openspec-cn 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +153 -0
- package/bin/openspec.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +480 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +277 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +257 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +198 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +869 -0
- package/dist/commands/show.d.ts +14 -0
- package/dist/commands/show.js +132 -0
- package/dist/commands/spec.d.ts +15 -0
- package/dist/commands/spec.js +225 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +294 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +381 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +44 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +52 -0
- package/dist/commands/workflow/shared.js +111 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +58 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +68 -0
- package/dist/core/archive.d.ts +11 -0
- package/dist/core/archive.js +280 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/index.d.ts +7 -0
- package/dist/core/artifact-graph/index.js +13 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
- package/dist/core/artifact-graph/instruction-loader.js +214 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +257 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +54 -0
- package/dist/core/artifact-graph/types.d.ts +45 -0
- package/dist/core/artifact-graph/types.js +43 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +13 -0
- package/dist/core/command-generation/adapters/codex.js +27 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +27 -0
- package/dist/core/command-generation/adapters/index.js +27 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +26 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +88 -0
- package/dist/core/command-generation/types.d.ts +55 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/completions/command-registry.d.ts +7 -0
- package/dist/core/completions/command-registry.js +456 -0
- package/dist/core/completions/completion-provider.d.ts +60 -0
- package/dist/core/completions/completion-provider.js +102 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +32 -0
- package/dist/core/completions/generators/bash-generator.js +174 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +157 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
- package/dist/core/completions/generators/powershell-generator.js +207 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
- package/dist/core/completions/generators/zsh-generator.js +250 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +318 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +143 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
- package/dist/core/completions/installers/powershell-installer.js +327 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
- package/dist/core/completions/installers/zsh-installer.js +449 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +24 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +39 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +25 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +36 -0
- package/dist/core/completions/types.d.ts +79 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +76 -0
- package/dist/core/config-schema.js +200 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +30 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/global-config.d.ts +39 -0
- package/dist/core/global-config.js +115 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +3 -0
- package/dist/core/init.d.ts +32 -0
- package/dist/core/init.js +433 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +501 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +171 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +193 -0
- package/dist/core/parsers/markdown-parser.d.ts +22 -0
- package/dist/core/parsers/markdown-parser.js +187 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +223 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +13 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +41 -0
- package/dist/core/shared/skill-generation.js +74 -0
- package/dist/core/shared/tool-detection.d.ts +66 -0
- package/dist/core/shared/tool-detection.js +140 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +384 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +112 -0
- package/dist/core/templates/skill-templates.js +2893 -0
- package/dist/core/update.d.ts +42 -0
- package/dist/core/update.js +306 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +33 -0
- package/dist/core/validation/validator.js +409 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +168 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +27 -0
- package/dist/prompts/searchable-multi-select.js +149 -0
- package/dist/telemetry/config.d.ts +32 -0
- package/dist/telemetry/config.js +68 -0
- package/dist/telemetry/index.d.ts +31 -0
- package/dist/telemetry/index.js +145 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/change-metadata.d.ts +51 -0
- package/dist/utils/change-metadata.js +147 -0
- package/dist/utils/change-utils.d.ts +62 -0
- package/dist/utils/change-utils.js +121 -0
- package/dist/utils/file-system.d.ts +36 -0
- package/dist/utils/file-system.js +281 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +72 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +84 -0
- package/schemas/spec-driven/schema.yaml +148 -0
- package/schemas/spec-driven/templates/design.md +19 -0
- package/schemas/spec-driven/templates/proposal.md +23 -0
- package/schemas/spec-driven/templates/spec.md +8 -0
- package/schemas/spec-driven/templates/tasks.md +9 -0
- package/schemas/tdd/schema.yaml +213 -0
- package/schemas/tdd/templates/docs.md +15 -0
- package/schemas/tdd/templates/implementation.md +11 -0
- package/schemas/tdd/templates/spec.md +11 -0
- package/schemas/tdd/templates/test.md +11 -0
- package/scripts/postinstall.js +147 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { POWERSHELL_DYNAMIC_HELPERS } from '../templates/powershell-templates.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates PowerShell completion scripts for the OpenSpec CLI.
|
|
4
|
+
* Uses Register-ArgumentCompleter for command completion.
|
|
5
|
+
*/
|
|
6
|
+
export class PowerShellGenerator {
|
|
7
|
+
shell = 'powershell';
|
|
8
|
+
stripTrailingCommaFromLastLine(lines) {
|
|
9
|
+
if (lines.length === 0)
|
|
10
|
+
return;
|
|
11
|
+
lines[lines.length - 1] = lines[lines.length - 1].replace(/,\s*$/, '');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate a PowerShell completion script
|
|
15
|
+
*
|
|
16
|
+
* @param commands - Command definitions to generate completions for
|
|
17
|
+
* @returns PowerShell completion script as a string
|
|
18
|
+
*/
|
|
19
|
+
generate(commands) {
|
|
20
|
+
// Build top-level commands using push() for loop clarity
|
|
21
|
+
const commandLines = [];
|
|
22
|
+
for (const cmd of commands) {
|
|
23
|
+
commandLines.push(` @{Name="${cmd.name}"; Description="${this.escapeDescription(cmd.description)}"},`);
|
|
24
|
+
}
|
|
25
|
+
this.stripTrailingCommaFromLastLine(commandLines);
|
|
26
|
+
const topLevelCommands = commandLines.join('\n');
|
|
27
|
+
// Build command cases using push() for loop clarity
|
|
28
|
+
const commandCaseLines = [];
|
|
29
|
+
for (const cmd of commands) {
|
|
30
|
+
commandCaseLines.push(` "${cmd.name}" {`);
|
|
31
|
+
commandCaseLines.push(...this.generateCommandCase(cmd, ' '));
|
|
32
|
+
commandCaseLines.push(' }');
|
|
33
|
+
}
|
|
34
|
+
const commandCases = commandCaseLines.join('\n');
|
|
35
|
+
// Dynamic completion helpers from template
|
|
36
|
+
const helpers = POWERSHELL_DYNAMIC_HELPERS;
|
|
37
|
+
// Assemble final script with template literal
|
|
38
|
+
return `# PowerShell completion script for OpenSpec CLI
|
|
39
|
+
# Auto-generated - do not edit manually
|
|
40
|
+
|
|
41
|
+
${helpers}
|
|
42
|
+
$openspecCompleter = {
|
|
43
|
+
param($wordToComplete, $commandAst, $cursorPosition)
|
|
44
|
+
|
|
45
|
+
$tokens = $commandAst.ToString() -split "\\s+"
|
|
46
|
+
$commandCount = ($tokens | Measure-Object).Count
|
|
47
|
+
|
|
48
|
+
# Top-level commands
|
|
49
|
+
if ($commandCount -eq 1 -or ($commandCount -eq 2 -and $wordToComplete)) {
|
|
50
|
+
$commands = @(
|
|
51
|
+
${topLevelCommands}
|
|
52
|
+
)
|
|
53
|
+
$commands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
|
|
54
|
+
[System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, "ParameterValue", $_.Description)
|
|
55
|
+
}
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
$command = $tokens[1]
|
|
60
|
+
|
|
61
|
+
switch ($command) {
|
|
62
|
+
${commandCases}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate completion case for a command
|
|
71
|
+
*/
|
|
72
|
+
generateCommandCase(cmd, indent) {
|
|
73
|
+
const lines = [];
|
|
74
|
+
if (cmd.subcommands && cmd.subcommands.length > 0) {
|
|
75
|
+
// First, check if user is typing a flag for the parent command
|
|
76
|
+
if (cmd.flags.length > 0) {
|
|
77
|
+
lines.push(`${indent}if ($wordToComplete -like "-*") {`);
|
|
78
|
+
lines.push(`${indent} $flags = @(`);
|
|
79
|
+
for (const flag of cmd.flags) {
|
|
80
|
+
const longFlag = `--${flag.name}`;
|
|
81
|
+
const shortFlag = flag.short ? `-${flag.short}` : undefined;
|
|
82
|
+
if (shortFlag) {
|
|
83
|
+
lines.push(`${indent} @{Name="${longFlag}"; Description="${this.escapeDescription(flag.description)}"},`);
|
|
84
|
+
lines.push(`${indent} @{Name="${shortFlag}"; Description="${this.escapeDescription(flag.description)}"},`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
lines.push(`${indent} @{Name="${longFlag}"; Description="${this.escapeDescription(flag.description)}"},`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.stripTrailingCommaFromLastLine(lines);
|
|
91
|
+
lines.push(`${indent} )`);
|
|
92
|
+
lines.push(`${indent} $flags | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {`);
|
|
93
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, "ParameterName", $_.Description)`);
|
|
94
|
+
lines.push(`${indent} }`);
|
|
95
|
+
lines.push(`${indent} return`);
|
|
96
|
+
lines.push(`${indent}}`);
|
|
97
|
+
lines.push('');
|
|
98
|
+
}
|
|
99
|
+
// Handle subcommands
|
|
100
|
+
lines.push(`${indent}if ($commandCount -eq 2 -or ($commandCount -eq 3 -and $wordToComplete)) {`);
|
|
101
|
+
lines.push(`${indent} $subcommands = @(`);
|
|
102
|
+
for (const subcmd of cmd.subcommands) {
|
|
103
|
+
lines.push(`${indent} @{Name="${subcmd.name}"; Description="${this.escapeDescription(subcmd.description)}"},`);
|
|
104
|
+
}
|
|
105
|
+
this.stripTrailingCommaFromLastLine(lines);
|
|
106
|
+
lines.push(`${indent} )`);
|
|
107
|
+
lines.push(`${indent} $subcommands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {`);
|
|
108
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, "ParameterValue", $_.Description)`);
|
|
109
|
+
lines.push(`${indent} }`);
|
|
110
|
+
lines.push(`${indent} return`);
|
|
111
|
+
lines.push(`${indent}}`);
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push(`${indent}$subcommand = if ($commandCount -gt 2) { $tokens[2] } else { "" }`);
|
|
114
|
+
lines.push(`${indent}switch ($subcommand) {`);
|
|
115
|
+
for (const subcmd of cmd.subcommands) {
|
|
116
|
+
lines.push(`${indent} "${subcmd.name}" {`);
|
|
117
|
+
lines.push(...this.generateArgumentCompletion(subcmd, indent + ' '));
|
|
118
|
+
lines.push(`${indent} }`);
|
|
119
|
+
}
|
|
120
|
+
lines.push(`${indent}}`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// No subcommands
|
|
124
|
+
lines.push(...this.generateArgumentCompletion(cmd, indent));
|
|
125
|
+
}
|
|
126
|
+
return lines;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Generate argument completion (flags and positional)
|
|
130
|
+
*/
|
|
131
|
+
generateArgumentCompletion(cmd, indent) {
|
|
132
|
+
const lines = [];
|
|
133
|
+
// Flag completion
|
|
134
|
+
if (cmd.flags.length > 0) {
|
|
135
|
+
lines.push(`${indent}if ($wordToComplete -like "-*") {`);
|
|
136
|
+
lines.push(`${indent} $flags = @(`);
|
|
137
|
+
for (const flag of cmd.flags) {
|
|
138
|
+
const longFlag = `--${flag.name}`;
|
|
139
|
+
const shortFlag = flag.short ? `-${flag.short}` : undefined;
|
|
140
|
+
if (shortFlag) {
|
|
141
|
+
lines.push(`${indent} @{Name="${longFlag}"; Description="${this.escapeDescription(flag.description)}"},`);
|
|
142
|
+
lines.push(`${indent} @{Name="${shortFlag}"; Description="${this.escapeDescription(flag.description)}"},`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
lines.push(`${indent} @{Name="${longFlag}"; Description="${this.escapeDescription(flag.description)}"},`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.stripTrailingCommaFromLastLine(lines);
|
|
149
|
+
lines.push(`${indent} )`);
|
|
150
|
+
lines.push(`${indent} $flags | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {`);
|
|
151
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, "ParameterName", $_.Description)`);
|
|
152
|
+
lines.push(`${indent} }`);
|
|
153
|
+
lines.push(`${indent} return`);
|
|
154
|
+
lines.push(`${indent}}`);
|
|
155
|
+
lines.push('');
|
|
156
|
+
}
|
|
157
|
+
// Positional completion
|
|
158
|
+
if (cmd.acceptsPositional) {
|
|
159
|
+
lines.push(...this.generatePositionalCompletion(cmd.positionalType, indent));
|
|
160
|
+
}
|
|
161
|
+
return lines;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Generate positional argument completion
|
|
165
|
+
*/
|
|
166
|
+
generatePositionalCompletion(positionalType, indent) {
|
|
167
|
+
const lines = [];
|
|
168
|
+
switch (positionalType) {
|
|
169
|
+
case 'change-id':
|
|
170
|
+
lines.push(`${indent}Get-OpenSpecChanges | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
|
|
171
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", "Change: $_")`);
|
|
172
|
+
lines.push(`${indent}}`);
|
|
173
|
+
break;
|
|
174
|
+
case 'spec-id':
|
|
175
|
+
lines.push(`${indent}Get-OpenSpecSpecs | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
|
|
176
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", "Spec: $_")`);
|
|
177
|
+
lines.push(`${indent}}`);
|
|
178
|
+
break;
|
|
179
|
+
case 'change-or-spec-id':
|
|
180
|
+
lines.push(`${indent}$items = @(Get-OpenSpecChanges) + @(Get-OpenSpecSpecs)`);
|
|
181
|
+
lines.push(`${indent}$items | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
|
|
182
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)`);
|
|
183
|
+
lines.push(`${indent}}`);
|
|
184
|
+
break;
|
|
185
|
+
case 'shell':
|
|
186
|
+
lines.push(`${indent}$shells = @("zsh", "bash", "fish", "powershell")`);
|
|
187
|
+
lines.push(`${indent}$shells | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
|
|
188
|
+
lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", "Shell: $_")`);
|
|
189
|
+
lines.push(`${indent}}`);
|
|
190
|
+
break;
|
|
191
|
+
case 'path':
|
|
192
|
+
// PowerShell handles file path completion automatically
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
return lines;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Escape description text for PowerShell
|
|
199
|
+
*/
|
|
200
|
+
escapeDescription(description) {
|
|
201
|
+
return description
|
|
202
|
+
.replace(/`/g, '``') // Backticks (escape sequences)
|
|
203
|
+
.replace(/\$/g, '`$') // Dollar signs (prevents $())
|
|
204
|
+
.replace(/"/g, '""'); // Double quotes
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=powershell-generator.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { CompletionGenerator, CommandDefinition } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates Zsh completion scripts for the OpenSpec CLI.
|
|
4
|
+
* Follows Zsh completion system conventions using the _openspec function.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ZshGenerator implements CompletionGenerator {
|
|
7
|
+
readonly shell: "zsh";
|
|
8
|
+
/**
|
|
9
|
+
* Generate a Zsh completion script
|
|
10
|
+
*
|
|
11
|
+
* @param commands - Command definitions to generate completions for
|
|
12
|
+
* @returns Zsh completion script as a string
|
|
13
|
+
*/
|
|
14
|
+
generate(commands: CommandDefinition[]): string;
|
|
15
|
+
/**
|
|
16
|
+
* Generate completion function for a specific command
|
|
17
|
+
*/
|
|
18
|
+
private generateCommandFunction;
|
|
19
|
+
/**
|
|
20
|
+
* Generate completion function for a subcommand
|
|
21
|
+
*/
|
|
22
|
+
private generateSubcommandFunction;
|
|
23
|
+
/**
|
|
24
|
+
* Generate flag specification for _arguments
|
|
25
|
+
*/
|
|
26
|
+
private generateFlagSpec;
|
|
27
|
+
/**
|
|
28
|
+
* Generate positional argument specification
|
|
29
|
+
*/
|
|
30
|
+
private generatePositionalSpec;
|
|
31
|
+
/**
|
|
32
|
+
* Escape special characters in descriptions
|
|
33
|
+
*/
|
|
34
|
+
private escapeDescription;
|
|
35
|
+
/**
|
|
36
|
+
* Escape special characters in values
|
|
37
|
+
*/
|
|
38
|
+
private escapeValue;
|
|
39
|
+
/**
|
|
40
|
+
* Sanitize command names for use in function names
|
|
41
|
+
*/
|
|
42
|
+
private sanitizeFunctionName;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=zsh-generator.d.ts.map
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { ZSH_DYNAMIC_HELPERS } from '../templates/zsh-templates.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates Zsh completion scripts for the OpenSpec CLI.
|
|
4
|
+
* Follows Zsh completion system conventions using the _openspec function.
|
|
5
|
+
*/
|
|
6
|
+
export class ZshGenerator {
|
|
7
|
+
shell = 'zsh';
|
|
8
|
+
/**
|
|
9
|
+
* Generate a Zsh completion script
|
|
10
|
+
*
|
|
11
|
+
* @param commands - Command definitions to generate completions for
|
|
12
|
+
* @returns Zsh completion script as a string
|
|
13
|
+
*/
|
|
14
|
+
generate(commands) {
|
|
15
|
+
// Build command list using push() for loop clarity
|
|
16
|
+
const commandLines = [];
|
|
17
|
+
for (const cmd of commands) {
|
|
18
|
+
const escapedDesc = this.escapeDescription(cmd.description);
|
|
19
|
+
commandLines.push(` '${cmd.name}:${escapedDesc}'`);
|
|
20
|
+
}
|
|
21
|
+
const commandList = commandLines.join('\n');
|
|
22
|
+
// Build command cases using push() for loop clarity
|
|
23
|
+
const commandCaseLines = [];
|
|
24
|
+
for (const cmd of commands) {
|
|
25
|
+
commandCaseLines.push(` ${cmd.name})`);
|
|
26
|
+
commandCaseLines.push(` _openspec_${this.sanitizeFunctionName(cmd.name)}`);
|
|
27
|
+
commandCaseLines.push(' ;;');
|
|
28
|
+
}
|
|
29
|
+
const commandCases = commandCaseLines.join('\n');
|
|
30
|
+
// Build command functions using push() for loop clarity
|
|
31
|
+
const commandFunctionLines = [];
|
|
32
|
+
for (const cmd of commands) {
|
|
33
|
+
commandFunctionLines.push(...this.generateCommandFunction(cmd));
|
|
34
|
+
commandFunctionLines.push('');
|
|
35
|
+
}
|
|
36
|
+
const commandFunctions = commandFunctionLines.join('\n');
|
|
37
|
+
// Dynamic completion helpers from template
|
|
38
|
+
const helpers = ZSH_DYNAMIC_HELPERS;
|
|
39
|
+
// Assemble final script with template literal
|
|
40
|
+
return `#compdef openspec
|
|
41
|
+
|
|
42
|
+
# Zsh completion script for OpenSpec CLI
|
|
43
|
+
# Auto-generated - do not edit manually
|
|
44
|
+
|
|
45
|
+
_openspec() {
|
|
46
|
+
local context state line
|
|
47
|
+
typeset -A opt_args
|
|
48
|
+
|
|
49
|
+
local -a commands
|
|
50
|
+
commands=(
|
|
51
|
+
${commandList}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
_arguments -C \\
|
|
55
|
+
"1: :->command" \\
|
|
56
|
+
"*::arg:->args"
|
|
57
|
+
|
|
58
|
+
case $state in
|
|
59
|
+
command)
|
|
60
|
+
_describe "openspec command" commands
|
|
61
|
+
;;
|
|
62
|
+
args)
|
|
63
|
+
case $words[1] in
|
|
64
|
+
${commandCases}
|
|
65
|
+
esac
|
|
66
|
+
;;
|
|
67
|
+
esac
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
${commandFunctions}
|
|
71
|
+
${helpers}
|
|
72
|
+
compdef _openspec openspec
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Generate completion function for a specific command
|
|
77
|
+
*/
|
|
78
|
+
generateCommandFunction(cmd) {
|
|
79
|
+
const funcName = `_openspec_${this.sanitizeFunctionName(cmd.name)}`;
|
|
80
|
+
const lines = [];
|
|
81
|
+
lines.push(`${funcName}() {`);
|
|
82
|
+
// If command has subcommands, handle them
|
|
83
|
+
if (cmd.subcommands && cmd.subcommands.length > 0) {
|
|
84
|
+
lines.push(' local context state line');
|
|
85
|
+
lines.push(' typeset -A opt_args');
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(' local -a subcommands');
|
|
88
|
+
lines.push(' subcommands=(');
|
|
89
|
+
for (const subcmd of cmd.subcommands) {
|
|
90
|
+
const escapedDesc = this.escapeDescription(subcmd.description);
|
|
91
|
+
lines.push(` '${subcmd.name}:${escapedDesc}'`);
|
|
92
|
+
}
|
|
93
|
+
lines.push(' )');
|
|
94
|
+
lines.push('');
|
|
95
|
+
lines.push(' _arguments -C \\');
|
|
96
|
+
// Add command flags
|
|
97
|
+
for (const flag of cmd.flags) {
|
|
98
|
+
lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
|
|
99
|
+
}
|
|
100
|
+
lines.push(' "1: :->subcommand" \\');
|
|
101
|
+
lines.push(' "*::arg:->args"');
|
|
102
|
+
lines.push('');
|
|
103
|
+
lines.push(' case $state in');
|
|
104
|
+
lines.push(' subcommand)');
|
|
105
|
+
lines.push(' _describe "subcommand" subcommands');
|
|
106
|
+
lines.push(' ;;');
|
|
107
|
+
lines.push(' args)');
|
|
108
|
+
lines.push(' case $words[1] in');
|
|
109
|
+
for (const subcmd of cmd.subcommands) {
|
|
110
|
+
lines.push(` ${subcmd.name})`);
|
|
111
|
+
lines.push(` _openspec_${this.sanitizeFunctionName(cmd.name)}_${this.sanitizeFunctionName(subcmd.name)}`);
|
|
112
|
+
lines.push(' ;;');
|
|
113
|
+
}
|
|
114
|
+
lines.push(' esac');
|
|
115
|
+
lines.push(' ;;');
|
|
116
|
+
lines.push(' esac');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// Command without subcommands
|
|
120
|
+
lines.push(' _arguments \\');
|
|
121
|
+
// Add flags
|
|
122
|
+
for (const flag of cmd.flags) {
|
|
123
|
+
lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
|
|
124
|
+
}
|
|
125
|
+
// Add positional argument completion
|
|
126
|
+
if (cmd.acceptsPositional) {
|
|
127
|
+
const positionalSpec = this.generatePositionalSpec(cmd.positionalType);
|
|
128
|
+
lines.push(' ' + positionalSpec);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// Remove trailing backslash from last flag
|
|
132
|
+
if (lines[lines.length - 1].endsWith(' \\')) {
|
|
133
|
+
lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
lines.push('}');
|
|
138
|
+
// Generate subcommand functions if they exist
|
|
139
|
+
if (cmd.subcommands) {
|
|
140
|
+
for (const subcmd of cmd.subcommands) {
|
|
141
|
+
lines.push('');
|
|
142
|
+
lines.push(...this.generateSubcommandFunction(cmd.name, subcmd));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return lines;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Generate completion function for a subcommand
|
|
149
|
+
*/
|
|
150
|
+
generateSubcommandFunction(parentName, subcmd) {
|
|
151
|
+
const funcName = `_openspec_${this.sanitizeFunctionName(parentName)}_${this.sanitizeFunctionName(subcmd.name)}`;
|
|
152
|
+
const lines = [];
|
|
153
|
+
lines.push(`${funcName}() {`);
|
|
154
|
+
lines.push(' _arguments \\');
|
|
155
|
+
// Add flags
|
|
156
|
+
for (const flag of subcmd.flags) {
|
|
157
|
+
lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
|
|
158
|
+
}
|
|
159
|
+
// Add positional argument completion
|
|
160
|
+
if (subcmd.acceptsPositional) {
|
|
161
|
+
const positionalSpec = this.generatePositionalSpec(subcmd.positionalType);
|
|
162
|
+
lines.push(' ' + positionalSpec);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// Remove trailing backslash from last flag
|
|
166
|
+
if (lines[lines.length - 1].endsWith(' \\')) {
|
|
167
|
+
lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
lines.push('}');
|
|
171
|
+
return lines;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Generate flag specification for _arguments
|
|
175
|
+
*/
|
|
176
|
+
generateFlagSpec(flag) {
|
|
177
|
+
const parts = [];
|
|
178
|
+
// Handle mutually exclusive short and long forms
|
|
179
|
+
if (flag.short) {
|
|
180
|
+
parts.push(`'(-${flag.short} --${flag.name})'{-${flag.short},--${flag.name}}'`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
parts.push(`'--${flag.name}`);
|
|
184
|
+
}
|
|
185
|
+
// Add description
|
|
186
|
+
const escapedDesc = this.escapeDescription(flag.description);
|
|
187
|
+
parts.push(`[${escapedDesc}]`);
|
|
188
|
+
// Add value completion if flag takes a value
|
|
189
|
+
if (flag.takesValue) {
|
|
190
|
+
if (flag.values && flag.values.length > 0) {
|
|
191
|
+
// Provide specific value completions
|
|
192
|
+
const valueList = flag.values.map(v => this.escapeValue(v)).join(' ');
|
|
193
|
+
parts.push(`:value:(${valueList})`);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Generic value placeholder
|
|
197
|
+
parts.push(':value:');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Close the quote (needed for both short and long forms)
|
|
201
|
+
parts.push("'");
|
|
202
|
+
return parts.join('');
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Generate positional argument specification
|
|
206
|
+
*/
|
|
207
|
+
generatePositionalSpec(positionalType) {
|
|
208
|
+
switch (positionalType) {
|
|
209
|
+
case 'change-id':
|
|
210
|
+
return "'*: :_openspec_complete_changes'";
|
|
211
|
+
case 'spec-id':
|
|
212
|
+
return "'*: :_openspec_complete_specs'";
|
|
213
|
+
case 'change-or-spec-id':
|
|
214
|
+
return "'*: :_openspec_complete_items'";
|
|
215
|
+
case 'path':
|
|
216
|
+
return "'*:path:_files'";
|
|
217
|
+
case 'shell':
|
|
218
|
+
return "'*:shell:(zsh bash fish powershell)'";
|
|
219
|
+
default:
|
|
220
|
+
return "'*: :_default'";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Escape special characters in descriptions
|
|
225
|
+
*/
|
|
226
|
+
escapeDescription(desc) {
|
|
227
|
+
return desc
|
|
228
|
+
.replace(/\\/g, '\\\\')
|
|
229
|
+
.replace(/'/g, "\\'")
|
|
230
|
+
.replace(/\[/g, '\\[')
|
|
231
|
+
.replace(/]/g, '\\]')
|
|
232
|
+
.replace(/:/g, '\\:');
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Escape special characters in values
|
|
236
|
+
*/
|
|
237
|
+
escapeValue(value) {
|
|
238
|
+
return value
|
|
239
|
+
.replace(/\\/g, '\\\\')
|
|
240
|
+
.replace(/'/g, "\\'")
|
|
241
|
+
.replace(/ /g, '\\ ');
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Sanitize command names for use in function names
|
|
245
|
+
*/
|
|
246
|
+
sanitizeFunctionName(name) {
|
|
247
|
+
return name.replace(/-/g, '_');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=zsh-generator.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { InstallationResult } from '../factory.js';
|
|
2
|
+
/**
|
|
3
|
+
* Installer for Bash completion scripts.
|
|
4
|
+
* Supports bash-completion package and standalone installations.
|
|
5
|
+
*/
|
|
6
|
+
export declare class BashInstaller {
|
|
7
|
+
private readonly homeDir;
|
|
8
|
+
/**
|
|
9
|
+
* Markers for .bashrc configuration management
|
|
10
|
+
*/
|
|
11
|
+
private readonly BASHRC_MARKERS;
|
|
12
|
+
constructor(homeDir?: string);
|
|
13
|
+
/**
|
|
14
|
+
* Check if bash-completion is installed
|
|
15
|
+
*
|
|
16
|
+
* @returns true if bash-completion directories exist
|
|
17
|
+
*/
|
|
18
|
+
isBashCompletionInstalled(): Promise<boolean>;
|
|
19
|
+
/**
|
|
20
|
+
* Get the appropriate installation path for the completion script
|
|
21
|
+
*
|
|
22
|
+
* @returns Installation path
|
|
23
|
+
*/
|
|
24
|
+
getInstallationPath(): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Backup an existing completion file if it exists
|
|
27
|
+
*
|
|
28
|
+
* @param targetPath - Path to the file to backup
|
|
29
|
+
* @returns Path to the backup file, or undefined if no backup was needed
|
|
30
|
+
*/
|
|
31
|
+
backupExistingFile(targetPath: string): Promise<string | undefined>;
|
|
32
|
+
/**
|
|
33
|
+
* Get the path to .bashrc file
|
|
34
|
+
*
|
|
35
|
+
* @returns Path to .bashrc
|
|
36
|
+
*/
|
|
37
|
+
private getBashrcPath;
|
|
38
|
+
/**
|
|
39
|
+
* Generate .bashrc configuration content
|
|
40
|
+
*
|
|
41
|
+
* @param completionsDir - Directory containing completion scripts
|
|
42
|
+
* @returns Configuration content
|
|
43
|
+
*/
|
|
44
|
+
private generateBashrcConfig;
|
|
45
|
+
/**
|
|
46
|
+
* Configure .bashrc to enable completions
|
|
47
|
+
*
|
|
48
|
+
* @param completionsDir - Directory containing completion scripts
|
|
49
|
+
* @returns true if configured successfully, false otherwise
|
|
50
|
+
*/
|
|
51
|
+
configureBashrc(completionsDir: string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Remove .bashrc configuration
|
|
54
|
+
* Used during uninstallation
|
|
55
|
+
*
|
|
56
|
+
* @returns true if removed successfully, false otherwise
|
|
57
|
+
*/
|
|
58
|
+
removeBashrcConfig(): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Install the completion script
|
|
61
|
+
*
|
|
62
|
+
* @param completionScript - The completion script content to install
|
|
63
|
+
* @returns Installation result with status and instructions
|
|
64
|
+
*/
|
|
65
|
+
install(completionScript: string): Promise<InstallationResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Generate user instructions for enabling completions
|
|
68
|
+
*
|
|
69
|
+
* @param installedPath - Path where the script was installed
|
|
70
|
+
* @returns Array of instruction strings
|
|
71
|
+
*/
|
|
72
|
+
private generateInstructions;
|
|
73
|
+
/**
|
|
74
|
+
* Uninstall the completion script
|
|
75
|
+
*
|
|
76
|
+
* @param options - Optional uninstall options
|
|
77
|
+
* @param options.yes - Skip confirmation prompt (handled by command layer)
|
|
78
|
+
* @returns Uninstallation result
|
|
79
|
+
*/
|
|
80
|
+
uninstall(options?: {
|
|
81
|
+
yes?: boolean;
|
|
82
|
+
}): Promise<{
|
|
83
|
+
success: boolean;
|
|
84
|
+
message: string;
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=bash-installer.d.ts.map
|