diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml new file mode 100644 index 0000000..a115f1f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -0,0 +1,62 @@ +name: "bug report🕷" +description: help us improve +title: a bug +labels: bug +assignees: steve02081504 +body: + - type: checkboxes + attributes: + label: 检查清单 Prerequisites + options: + - label: "请确保你是在最新版本中遇见此问题\nMake sure you have this bug in the latest release" + id: latest-release + required: true + - label: "请确保你已经检索了已关闭的问题,以确保你的问题没有被重复提交\nMake sure you have retrieved closed issues to make sure your issue has not been submitted repeatedly" + id: closed-issues + required: true + + - type: textarea + id: bug-description + attributes: + label: "描述错误\nDescribe the bug" + description: | + 对错误的清晰简明的描述于此 + A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + id: fount-pwsh-usage + attributes: + label: "复现\nTo Reproduce" + description: | + 你如何使用fount-pwsh + How do you use fount-pwsh. + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: "预期行为\nExpected behavior" + description: | + 对你期望发生的事的清晰而简明的描述 + A clear and concise description of what you expected to happen. + validations: + required: true + + - type: textarea + id: screenshorts + attributes: + label: "截图\nScreenshots" + description: | + 如果可以,请添加截图以帮助解释你的问题 + If applicable, add screenshots to help explain your problem. + + - type: textarea + id: additional-context + attributes: + label: "附加上下文\nAdditional context" + description: | + 在此处添加有关该问题的任何其他上下文 + Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yaml b/.github/ISSUE_TEMPLATE/feature-request.yaml new file mode 100644 index 0000000..d3469fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yaml @@ -0,0 +1,68 @@ +name: "feature request🎨" +description: Suggest idea +title: a feature request +labels: enhancement +assignees: + - steve02081504 +body: + - type: checkboxes + attributes: + label: 检查清单 Prerequisites + options: + - label: "请确保你已经检索了已关闭的问题,以确保你的问题没有被重复提交\nMake sure you have retrieved closed issues to make sure your issue has not been submitted repeatedly" + id: closed-issues + required: true + + - type: textarea + id: problem + attributes: + label: "问题描述\nProblem description" + description: | + 你的建议是否与什么问题有关?请描述一下。 + Is your feature request related to a problem? Please describe. + placeholder: | + 对你遇见的问题的清晰简明的描述于此 + A clear and concise description of what the problem is. + 例:我总是感到沮丧当 [...] + Ex. I'm always frustrated when [...] + validations: + required: true + + - type: textarea + id: solution + attributes: + label: "解决方案描述\nSolution description" + description: | + 描述你想要的解决方案 + Describe the solution you'd like + placeholder: | + 对你想要的解决方案的清晰简明的描述于此 + A clear and concise description of what you want to happen. + 例:我希望能够 [...] + Ex. I'd like to see [...] + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: "替代方案描述\nAlternative description" + description: | + 描述你考虑过的替代方案 + Describe alternatives you've considered + placeholder: | + 对你考虑过的任何替代方案或功能的清晰简明的描述 + A clear and concise description of any alternative solutions or features you've considered. + 例:一种替代性的方案,可以 [...] + Ex. One alternative solution could be [...] + + - type: textarea + id: context + attributes: + label: "附加内容\nAdditional context" + description: | + 附加内容 + Additional context + placeholder: | + 在此处添加有关功能请求的任何其他上下文或屏幕截图 + Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md new file mode 100644 index 0000000..cc77570 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.md @@ -0,0 +1,10 @@ +--- +name: "other🔮" +about: nothing +title: a issue +labels: '' +assignees: steve02081504 + +--- + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..cea7f38 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +--- +name: "default" +about: default pull request template +title: change name +assignees: steve02081504 + +--- +**感谢你对fount-pwsh做出的贡献** +**Thank you for your contribution to fount-pwsh** + +如果你自信其他人能通过观察你对项目的修改得知你的意图,这里可以什么都不填。如果不能,请描述你的修改直至你认为其他人可以看懂修改的缘由 +If you are confident that others will know your intentions by observing your modifications to the project, you can fill in nothing here. If not, please describe your change until you think others can understand the reason for the modification. diff --git a/.github/workflows/PSObjectToString.ps1 b/.github/workflows/PSObjectToString.ps1 new file mode 100644 index 0000000..9619d95 --- /dev/null +++ b/.github/workflows/PSObjectToString.ps1 @@ -0,0 +1,43 @@ +$script:tabnum = 0 +function PSObjectToString($obj, [Switch]$OneLine = $false) { + if ($obj -is [System.Collections.IDictionary]) { + $script:tabnum += 1 + $str = '' + if ($obj -is [System.Collections.Specialized.OrderedDictionary]) { + $str = '[ordered]' + } + $str += '@{' + if (-not $OneLine) { + $str += "`n" + } + $str += (($obj.GetEnumerator() | ForEach-Object { + if (-not $OneLine) { + "`t" * $script:tabnum + } + $_.Key + ' = ' + $(PSObjectToString $_.Value $OneLine) + if (-not $OneLine) { "`n" } + else { ';' } + }) -join '') + if (-not $OneLine) { + $str += "`t" * ($script:tabnum - 1) + } + $str += '}' + $str + $script:tabnum -= 1 + } + elseif ($obj -is [System.Collections.ICollection]) { + '@(' + (($obj | ForEach-Object { + PSObjectToString $_ $OneLine + ', ' + } | Select-Object -SkipLast 1) -join '') + ')' + } + elseif ($obj -is [string]) { + "'" + $obj.Replace("'", "''") + "'" + } + elseif ($obj -is [int]) { $obj } + elseif ($obj -is [bool] -or $obj -is [switch]) { "`$$obj" } + else { "$obj" } +} +function Get-ArgsString([hashtable]$Params) { + $Params.GetEnumerator() | ForEach-Object { "-$($_.Key):$(PSObjectToString $_.Value -OneLine)" } +} diff --git a/.github/workflows/Publish.ps1 b/.github/workflows/Publish.ps1 new file mode 100644 index 0000000..c88eaee --- /dev/null +++ b/.github/workflows/Publish.ps1 @@ -0,0 +1,57 @@ +# pwsh ./.github/workflows/publish.ps1 -version ${{ github.ref_name }} -ApiKey ${{ secrets.NUGET_API_KEY }} + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string]$version, + [Parameter(Mandatory = $true)] + [string]$ApiKey +) +if ($version -match '^v(\d+\.\d+\.\d+)$') { + $version = $Matches[1] +} +else { + throw "invalid version: $version" +} + +$repoPath = "$PSScriptRoot/../.." +. $PSScriptRoot/PSObjectToString.ps1 +$error.clear() + +try { + # read psd1 + $packData = Import-PowerShellDataFile "$repoPath/fount-pwsh.psd1" + # update version + $packData.ModuleVersion = $version + # update psd1 + Set-Content -Path "$repoPath/fount-pwsh.psd1" -Value $(PSObjectToString($packData)) -NoNewline -Encoding UTF8 -Force + # 遍历文件列表,移除.开头的文件和文件夹 + Get-ChildItem -Path $repoPath -Recurse | Where-Object { $_.Name -match '^\.' } | ForEach-Object { Remove-Item -Path $_.FullName -Force -Recurse } + # 打包发布 + Install-Module -Name 'PowerShellGet' -Force -Scope CurrentUser | Out-Null + $errnum = $Error.Count + Publish-Module -Path $repoPath -NuGetApiKey $ApiKey -ErrorAction Stop + while ($Error.Count -gt $errnum) { + $Error.RemoveAt(0) + } +} +catch {} + +if ($error) { + Write-Output "::group::PSVersion" + Write-Output $PSVersionTable + Write-Output "::endgroup::" + + $error | ForEach-Object { + Write-Output "::error file=$($_.InvocationInfo.ScriptName),line=$($_.InvocationInfo.ScriptLineNumber),col=$($_.InvocationInfo.OffsetInLine),endColumn=$($_.InvocationInfo.OffsetInLine),tittle=error::$_" + Write-Output "::group::script stack trace" + Write-Output $_.ScriptStackTrace + Write-Output "::endgroup::" + Write-Output "::group::error details" + Write-Output $_ + Write-Output "::endgroup::" + } + exit 1 +} + +Write-Output "Nice CI!" diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml new file mode 100644 index 0000000..ab1683b --- /dev/null +++ b/.github/workflows/Publish.yml @@ -0,0 +1,21 @@ +name: Publish Release to PowerShell Gallery + +on: + push: + tags: + - v* + workflow_dispatch: + inputs: + version: + description: 'Version to publish' + required: true + default: 'v0.0.0' + +jobs: + test: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - name: Run a one-line script + shell: pwsh + run: ./.github/workflows/publish.ps1 -version ${{ github.event.inputs.version || github.ref_name }} -ApiKey ${{ secrets.NUGET_API_KEY }} diff --git a/argument_completer.ps1 b/argument_completer.ps1 new file mode 100644 index 0000000..0d57cac --- /dev/null +++ b/argument_completer.ps1 @@ -0,0 +1,186 @@ +# 获取具有补全脚本的 Shell 列表。 +function Get-FountShellListWithCompleter { + param([string]$Username) + # 获取指定用户或所有用户的可用 Shell 列表。 + Get-FountPartList -parttype shells -Username $Username | + # 筛选出存在 argument_completer.ps1 脚本的 Shell。 + Where-Object { + $shellDir = Get-FountPartDirectory -Username $Username -parttype shells -partname $_ + Test-Path (Join-Path -Path $shellDir -ChildPath "argument_completer.ps1") -PathType Leaf + } +} + +# 移除哈希表中的指定键及其子键(递归)。 +function Remove-ArgumentNode { + param([hashtable]$Node, [string]$Key) + # 如果哈希表中存在指定的键,则移除该键。 + if ($Node.ContainsKey($Key)) { $Node.Remove($Key) } + # 遍历哈希表中的所有键。 + foreach ($mapperkey in $Node.Keys) { + # 如果当前键对应的值是哈希表,则递归调用 Remove-ArgumentNode 函数。 + if ($Node[$mapperkey] -is [hashtable]) { Remove-ArgumentNode -Node $Node[$mapperkey] -Key $Key } + } +} + +# 处理 'runshell' 子命令的参数补全。 +function Invoke-RunshellCompletion { + param( + [string]$WordToComplete, + [System.Management.Automation.Language.CommandAst]$CommandAst, + [int]$CursorPosition, + [int]$runshellIndex, # 'runshell' 命令在 CommandAst 中的索引。 + [int]$Argindex # 当前参数在 CommandAst 中的索引。 + ) + + # 提取用户名和 shellname,处理它们可能还不存在的情况。 + # $runshellIndex + 1 是用户名的可能位置。 + # $runshellIndex + 2 是 shellname 的可能位置。 + # 如果索引在 CommandAst 的范围内,并且元素是字符串常量,则提取其值。 + $username = if ($runshellIndex + 1 -lt $CommandAst.CommandElements.Count -and $CommandAst.CommandElements[$runshellIndex + 1] -is [System.Management.Automation.Language.StringConstantExpressionAst]) { + $CommandAst.CommandElements[$runshellIndex + 1].Value + } + $shellname = if ($runshellIndex + 2 -lt $CommandAst.CommandElements.Count -and $CommandAst.CommandElements[$runshellIndex + 2] -is [System.Management.Automation.Language.StringConstantExpressionAst]) { + $CommandAst.CommandElements[$runshellIndex + 2].Value + } + + # 补全用户名。 + # 如果当前参数是 'runshell' 之后的第一个参数,则补全用户名。 + if (($ArgIndex - $runshellIndex) -eq 1) { + return Get-FountUserList | Where-Object { $_.StartsWith($WordToComplete) } + } + + # 补全 shellname。 + # 如果当前参数是 'runshell' 之后的第二个参数,则补全 shellname。 + if (($ArgIndex - $runshellIndex) -eq 2) { + return Get-FountShellListWithCompleter $username | Where-Object { $_.StartsWith($WordToComplete) } + } + + # 委托给 shell 的 argument_completer.ps1 脚本处理后续参数。 + # 获取 shell 目录的路径。 + $shellDir = Get-FountPartDirectory -Username $username -parttype shells -partname $shellname + # 如果 shell 目录存在,并且包含 argument_completer.ps1 脚本(-PathType Leaf 检查是否为文件),则执行该脚本。 + if (Test-Path (Join-Path -Path $shellDir -ChildPath "argument_completer.ps1") -PathType Leaf) { + # 使用 '&' 调用操作符执行脚本,并传递必要的参数。 + & (Join-Path -Path $shellDir -ChildPath "argument_completer.ps1") $username $WordToComplete $CommandAst $CursorPosition $runshellIndex $Argindex + } +} + +# 定义 Fount 工具的参数结构。 +$ArgumentStructure = @{ + Root = @{ + # 根节点包含的参数。 + Parameters = 'background', 'geneexe', 'init', 'keepalive', 'runshell', 'shutdown' + # 'background' 参数的子参数。 + background = @{ + Parameters = 'geneexe', 'init', 'keepalive', 'runshell', 'shutdown' + # 'geneexe' 参数的处理程序(仅限 Windows)。 + geneexe = { if ($IsWindows) { Get-ChildItem -Path "$($WordToComplete)*" -File | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_.FullName, $_.Name, 'File', $_.FullName) } } } + init = $null # 没有补全逻辑。 + # 'keepalive' 参数的子参数和处理程序。 + keepalive = @{ Parameters = 'debug', 'runshell'; debug = @{ Parameters = 'runshell'; runshell = ${function:Invoke-RunshellCompletion} }; runshell = ${function:Invoke-RunshellCompletion} } + # 'runshell' 参数的处理程序。 + runshell = ${function:Invoke-RunshellCompletion} + shutdown = $null + } + geneexe = { if ($IsWindows) { Get-ChildItem -Path "$($WordToComplete)*" -File | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_.FullName, $_.Name, 'File', $_.FullName) } } } + init = $null + keepalive = @{ Parameters = 'debug', 'runshell'; debug = @{ Parameters = 'runshell'; runshell = ${function:Invoke-RunshellCompletion} }; runshell = ${function:Invoke-RunshellCompletion} } + debug = @{ Parameters = 'runshell'; runshell = ${function:Invoke-RunshellCompletion} } + runshell = ${function:Invoke-RunshellCompletion} + shutdown = $null + } +} + +# 如果不是 Windows 系统,则移除 'geneexe' 参数。 +if (-not $IsWindows) { + Remove-ArgumentNode -Node $ArgumentStructure.Root -Key 'geneexe' +} + +# Fount 工具的主参数补全函数。 +function Get-FountArgumentCompletion { + param( + [string]$WordToComplete, + [System.Management.Automation.Language.CommandAst]$CommandAst, + [int]$CursorPosition + ) + + try { + # 改进的提取 $realWordToComplete 的逻辑。 这段代码尝试更准确地确定用户正在输入的单词。 + $WordToComplete = "$CommandAst" # 首先将整个命令字符串赋值给 $WordToComplete。 + # 循环添加空格,直到 $WordToComplete 的长度大于等于光标位置。这确保了后续的字符串分割可以正确工作,即使光标后面有空格。 + while ($CursorPosition -gt $WordToComplete.Length) { + $WordToComplete += ' ' + } + # 将 $WordToComplete 截取到光标位置,然后按空格分割,得到一个单词数组。 + $CommandWords = $WordToComplete.Substring(0, [Math]::Min($WordToComplete.Length, $CursorPosition)) -split '\s+' + # $Argindex 是当前参数的索引。 + $Argindex = $CommandWords.Count - 1 + # $WordToComplete 现在是用户正在输入的单词。 + $WordToComplete = $CommandWords[-1] + + # 从参数结构的根节点开始。 + $currentLevel = $ArgumentStructure.Root + + # 跳过命令名称(例如 'fount')。 + $ArgCommandElements = $CommandAst.CommandElements | Select-Object -Skip 1 + + $rootIndex = 0 # 用于跟踪runshel​​l参数的索引 + + # 遍历命令参数。 + foreach ($element in $ArgCommandElements) { + # 如果元素是字符串常量。 + if ($element -is [System.Management.Automation.Language.StringConstantExpressionAst]) { + $argValue = $element.Value + + # 如果当前级别是哈希表,并且包含该参数值。 + if ($currentLevel -is [hashtable] -and $currentLevel.ContainsKey($argValue)) { + # 移动到下一级。 + $currentLevel = $currentLevel[$argValue] + $rootIndex += 1 + } + # 否则,如果当前级别是哈希表,并且包含 "Parameters" 键,并且 "Parameters" 包含该参数值, 则不做任何事情,因为我们已经处理了有效的参数。 + elseif ($currentLevel -is [hashtable] -and $currentLevel.ContainsKey("Parameters") -and ($currentLevel.Parameters -contains $argValue)) { + } + # 否则,参数无效,退出循环。 + else { + break + } + } + # 否则,参数不是字符串常量,退出循环。 + else { + break + } + } + + # 如果当前级别是哈希表。 + if ($currentLevel -is [hashtable]) { + # 如果包含 "Parameters" 键。 + if ($currentLevel.ContainsKey("Parameters")) { + # 获取匹配的参数。 + $parameters = $currentLevel.Parameters + $matchingParameters = $parameters | Where-Object { $_.StartsWith($WordToComplete) } + # 返回匹配的参数。 + $matchingParameters + return + } + return + } + # 否则,如果当前级别是脚本块。 + elseif ($currentLevel -is [scriptblock]) { + # 执行脚本块,并传递必要的参数。 + & $currentLevel $WordToComplete $CommandAst $CursorPosition $rootIndex $Argindex | ForEach-Object { $_ } + return + } + } + catch { + # 捕获并显示错误信息。 + Write-Host "Error in Get-FountArgumentCompletion: $_" -ForegroundColor Red + } +} + +# 注册参数补全函数。 +# 为 'fount'、'fount.ps1'、'fount.cmd' 和 'fount.exe' 命令注册 Get-FountArgumentCompletion 函数。 +Register-ArgumentCompleter -CommandName fount -ScriptBlock ${function:Get-FountArgumentCompletion} -Native +Register-ArgumentCompleter -CommandName fount.ps1 -ScriptBlock ${function:Get-FountArgumentCompletion} -Native +Register-ArgumentCompleter -CommandName fount.cmd -ScriptBlock ${function:Get-FountArgumentCompletion} -Native +Register-ArgumentCompleter -CommandName fount.exe -ScriptBlock ${function:Get-FountArgumentCompletion} -Native diff --git a/data.ps1 b/data.ps1 new file mode 100644 index 0000000..c0799dc --- /dev/null +++ b/data.ps1 @@ -0,0 +1,68 @@ +# 获取 Fount 工具的根目录。 +function Get-FountDirectory { + # Get-Command fount.ps1 获取 fount.ps1 脚本的信息。 + # .Path 获取脚本的完整路径。 + # Split-Path -Parent 两次,获取脚本所在目录的父目录,即 Fount 工具的根目录。 + (Get-Command fount.ps1).Path | Split-Path -Parent | Split-Path -Parent +} + +# 获取所有 Fount 用户的用户名列表。 +function Get-FountUserList { + # $(Get-FountDirectory)/data/users 构造用户数据目录的路径。 + # Get-ChildItem -Directory 获取该目录下的所有子目录(即用户名)。 + # ForEach-Object Name 提取每个子目录的名称(即用户名)。 + Get-ChildItem -Path "$(Get-FountDirectory)/data/users" -Directory | ForEach-Object Name +} + +function Get-FountParts { + @( + 'shells', 'chars', 'personas', 'worlds', 'AIsources', 'AIsourceGenerators', 'ImportHanlders' + ) +} + +function Get-FountPartList { + param([string]$parttype, [string]$Username) + $fountDir = Get-FountDirectory + $isFile = $parttype -eq 'AIsources' + # 如果提供了用户名: + $userParts = if ($Username) { + Get-ChildItem -Path "$fountDir/data/users/$Username/$parttype" -Directory:$(!$isFile) -File:$isFile -ErrorAction SilentlyContinue + } + $publicParts = Get-ChildItem -Path "$fountDir/src/public/$parttype" -Directory:$(!$isFile) -File:$isFile -ErrorAction SilentlyContinue + .{ $userParts; $publicParts } | Where-Object { + if ($isFile) { $_ } + else { + Test-Path $(Join-Path -Path $_.FullName -ChildPath "main.mjs") -PathType Leaf + } + } | ForEach-Object { + if($isFile) { $_.BaseName } + else { $_.Name } + } | Sort-Object -Unique +} + +function Get-FountPartDirectory { + param([string]$Username, [string]$parttype, [string]$partname) + $fountDir = Get-FountDirectory + $isFile = $parttype -eq 'AIsources' + # 构造用户特定的 Shell 目录路径。 + $userPath = "$fountDir/data/users/$Username/$parttype/$partname" + # 构造公共 Shell 目录路径。 + $publicPath = "$fountDir/src/public/$parttype/$partname" + # 优先返回用户特定的 Shell 目录路径(如果存在)。 + if ($isFile) { + function Test-PartExist($path) { + Test-Path $path -PathType Leaf + } + } + else { + function Test-PartExist($path) { + Test-Path "$path/main.mjs" -PathType Leaf + } + } + if (Test-PartExist $userPath) { + $userPath + } + elseif (Test-PartExist $publicPath) { + $publicPath + } +} diff --git a/fount-pwsh.psd1 b/fount-pwsh.psd1 index 0b1b3f2..7d1739f 100644 --- a/fount-pwsh.psd1 +++ b/fount-pwsh.psd1 @@ -12,7 +12,7 @@ RootModule = 'fount-pwsh.psm1' # Version number of this module. - ModuleVersion = '0.0.5' + ModuleVersion = '0.0.0' # ID used to uniquely identify this module GUID = '2a16dae2-91d8-4743-952c-94acd1ed7e5a' @@ -71,17 +71,25 @@ Allows you: # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. FunctionsToExport = @( - "Set-FountAssist", - "Install-FountAssist", - "Set-FountClient", - "Close-FountClient", - "Test-FountRunning", - "Invoke-FountIPC", - "Start-FountShell", - "Invoke-FountShell", - "Start-Fount", - "Stop-Fount", + "Set-FountAssist" + "Install-FountAssist" + + "Set-FountClient" + "Close-FountClient" + "Test-FountRunning" + "Invoke-FountIPC" + "Start-FountShell" + "Invoke-FountShell" + + "Start-Fount" + "Stop-Fount" "Install-Fount" + + "Get-FountDirectory" + "Get-FountUserList" + "Get-FountParts" + "Get-FountPartList" + "Get-FountPartDirectory" ) # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. diff --git a/fount-pwsh.psm1 b/fount-pwsh.psm1 index 5010aaf..7acbd55 100644 --- a/fount-pwsh.psm1 +++ b/fount-pwsh.psm1 @@ -1,19 +1,29 @@ . $PSScriptRoot/base.ps1 . $PSScriptRoot/predicate.ps1 . $PSScriptRoot/assists/main.ps1 +. $PSScriptRoot/data.ps1 +. $PSScriptRoot/argument_completer.ps1 Export-ModuleMember -Function @( - "Set-FountAssist", - "Install-FountAssist", - "Set-FountClient", - "Close-FountClient", - "Test-FountRunning", - "Invoke-FountIPC", - "Start-FountShell", - "Invoke-FountShell", - "Start-Fount", - "Stop-Fount", + "Set-FountAssist" + "Install-FountAssist" + + "Set-FountClient" + "Close-FountClient" + "Test-FountRunning" + "Invoke-FountIPC" + "Start-FountShell" + "Invoke-FountShell" + + "Start-Fount" + "Stop-Fount" "Install-Fount" + + "Get-FountDirectory" + "Get-FountUserList" + "Get-FountParts" + "Get-FountPartList" + "Get-FountPartDirectory" ) -Variable @( "FountAssist" )