lightspec 0.1.1
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 +435 -0
- package/bin/lightspec.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +361 -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/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/core/archive.d.ts +11 -0
- package/dist/core/archive.js +280 -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 +16 -0
- package/dist/core/config.js +30 -0
- package/dist/core/configurators/agents.d.ts +8 -0
- package/dist/core/configurators/agents.js +15 -0
- package/dist/core/configurators/base.d.ts +7 -0
- package/dist/core/configurators/base.js +2 -0
- package/dist/core/configurators/claude.d.ts +8 -0
- package/dist/core/configurators/claude.js +15 -0
- package/dist/core/configurators/cline.d.ts +8 -0
- package/dist/core/configurators/cline.js +15 -0
- package/dist/core/configurators/codebuddy.d.ts +8 -0
- package/dist/core/configurators/codebuddy.js +15 -0
- package/dist/core/configurators/costrict.d.ts +8 -0
- package/dist/core/configurators/costrict.js +15 -0
- package/dist/core/configurators/iflow.d.ts +8 -0
- package/dist/core/configurators/iflow.js +15 -0
- package/dist/core/configurators/qoder.d.ts +30 -0
- package/dist/core/configurators/qoder.js +42 -0
- package/dist/core/configurators/qwen.d.ts +24 -0
- package/dist/core/configurators/qwen.js +37 -0
- package/dist/core/configurators/registry.d.ts +9 -0
- package/dist/core/configurators/registry.js +43 -0
- package/dist/core/configurators/slash/amazon-q.d.ts +9 -0
- package/dist/core/configurators/slash/amazon-q.js +46 -0
- package/dist/core/configurators/slash/antigravity.d.ts +9 -0
- package/dist/core/configurators/slash/antigravity.js +23 -0
- package/dist/core/configurators/slash/auggie.d.ts +9 -0
- package/dist/core/configurators/slash/auggie.js +31 -0
- package/dist/core/configurators/slash/base.d.ts +19 -0
- package/dist/core/configurators/slash/base.js +69 -0
- package/dist/core/configurators/slash/claude.d.ts +9 -0
- package/dist/core/configurators/slash/claude.js +37 -0
- package/dist/core/configurators/slash/cline.d.ts +9 -0
- package/dist/core/configurators/slash/cline.js +23 -0
- package/dist/core/configurators/slash/codebuddy.d.ts +9 -0
- package/dist/core/configurators/slash/codebuddy.js +34 -0
- package/dist/core/configurators/slash/codex.d.ts +14 -0
- package/dist/core/configurators/slash/codex.js +109 -0
- package/dist/core/configurators/slash/continue.d.ts +9 -0
- package/dist/core/configurators/slash/continue.js +46 -0
- package/dist/core/configurators/slash/costrict.d.ts +9 -0
- package/dist/core/configurators/slash/costrict.js +31 -0
- package/dist/core/configurators/slash/crush.d.ts +9 -0
- package/dist/core/configurators/slash/crush.js +37 -0
- package/dist/core/configurators/slash/cursor.d.ts +9 -0
- package/dist/core/configurators/slash/cursor.js +37 -0
- package/dist/core/configurators/slash/factory.d.ts +10 -0
- package/dist/core/configurators/slash/factory.js +35 -0
- package/dist/core/configurators/slash/gemini.d.ts +9 -0
- package/dist/core/configurators/slash/gemini.js +22 -0
- package/dist/core/configurators/slash/github-copilot.d.ts +9 -0
- package/dist/core/configurators/slash/github-copilot.js +34 -0
- package/dist/core/configurators/slash/iflow.d.ts +9 -0
- package/dist/core/configurators/slash/iflow.js +37 -0
- package/dist/core/configurators/slash/kilocode.d.ts +9 -0
- package/dist/core/configurators/slash/kilocode.js +17 -0
- package/dist/core/configurators/slash/opencode.d.ts +12 -0
- package/dist/core/configurators/slash/opencode.js +72 -0
- package/dist/core/configurators/slash/qoder.d.ts +35 -0
- package/dist/core/configurators/slash/qoder.js +76 -0
- package/dist/core/configurators/slash/qwen.d.ts +32 -0
- package/dist/core/configurators/slash/qwen.js +49 -0
- package/dist/core/configurators/slash/registry.d.ts +8 -0
- package/dist/core/configurators/slash/registry.js +78 -0
- package/dist/core/configurators/slash/roocode.d.ts +9 -0
- package/dist/core/configurators/slash/roocode.js +23 -0
- package/dist/core/configurators/slash/toml-base.d.ts +10 -0
- package/dist/core/configurators/slash/toml-base.js +53 -0
- package/dist/core/configurators/slash/windsurf.d.ts +9 -0
- package/dist/core/configurators/slash/windsurf.js +23 -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 +52 -0
- package/dist/core/init.js +644 -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/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/agents-root-stub.d.ts +2 -0
- package/dist/core/templates/agents-root-stub.js +17 -0
- package/dist/core/templates/agents-template.d.ts +2 -0
- package/dist/core/templates/agents-template.js +458 -0
- package/dist/core/templates/claude-template.d.ts +2 -0
- package/dist/core/templates/claude-template.js +2 -0
- package/dist/core/templates/cline-template.d.ts +2 -0
- package/dist/core/templates/cline-template.js +2 -0
- package/dist/core/templates/costrict-template.d.ts +2 -0
- package/dist/core/templates/costrict-template.js +2 -0
- package/dist/core/templates/index.d.ts +17 -0
- package/dist/core/templates/index.js +37 -0
- package/dist/core/templates/project-template.d.ts +8 -0
- package/dist/core/templates/project-template.js +32 -0
- package/dist/core/templates/slash-command-templates.d.ts +4 -0
- package/dist/core/templates/slash-command-templates.js +49 -0
- package/dist/core/update.d.ts +4 -0
- package/dist/core/update.js +88 -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/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 +103 -0
- package/dist/utils/file-system.d.ts +25 -0
- package/dist/utils/file-system.js +218 -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 +82 -0
- package/scripts/postinstall.js +147 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
interface GenerateOptions {
|
|
2
|
+
shell?: string;
|
|
3
|
+
}
|
|
4
|
+
interface InstallOptions {
|
|
5
|
+
shell?: string;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface UninstallOptions {
|
|
9
|
+
shell?: string;
|
|
10
|
+
yes?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface CompleteOptions {
|
|
13
|
+
type: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Command for managing shell completions for LightSpec CLI
|
|
17
|
+
*/
|
|
18
|
+
export declare class CompletionCommand {
|
|
19
|
+
private completionProvider;
|
|
20
|
+
constructor();
|
|
21
|
+
/**
|
|
22
|
+
* Resolve shell parameter or exit with error
|
|
23
|
+
*
|
|
24
|
+
* @param shell - The shell parameter (may be undefined)
|
|
25
|
+
* @param operationName - Name of the operation (for error messages)
|
|
26
|
+
* @returns Resolved shell or null if should exit
|
|
27
|
+
*/
|
|
28
|
+
private resolveShellOrExit;
|
|
29
|
+
/**
|
|
30
|
+
* Generate completion script and output to stdout
|
|
31
|
+
*
|
|
32
|
+
* @param options - Options for generation (shell type)
|
|
33
|
+
*/
|
|
34
|
+
generate(options?: GenerateOptions): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Install completion script to the appropriate location
|
|
37
|
+
*
|
|
38
|
+
* @param options - Options for installation (shell type, verbose output)
|
|
39
|
+
*/
|
|
40
|
+
install(options?: InstallOptions): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Uninstall completion script from the installation location
|
|
43
|
+
*
|
|
44
|
+
* @param options - Options for uninstallation (shell type, yes flag)
|
|
45
|
+
*/
|
|
46
|
+
uninstall(options?: UninstallOptions): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Generate completion script for a specific shell
|
|
49
|
+
*/
|
|
50
|
+
private generateForShell;
|
|
51
|
+
/**
|
|
52
|
+
* Install completion script for a specific shell
|
|
53
|
+
*/
|
|
54
|
+
private installForShell;
|
|
55
|
+
/**
|
|
56
|
+
* Uninstall completion script for a specific shell
|
|
57
|
+
*/
|
|
58
|
+
private uninstallForShell;
|
|
59
|
+
/**
|
|
60
|
+
* Output machine-readable completion data for shell consumption
|
|
61
|
+
* Format: tab-separated "id\tdescription" per line
|
|
62
|
+
*
|
|
63
|
+
* @param options - Options specifying completion type
|
|
64
|
+
*/
|
|
65
|
+
complete(options: CompleteOptions): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Normalize shell parameter to lowercase
|
|
68
|
+
*/
|
|
69
|
+
private normalizeShell;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=completion.d.ts.map
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import { CompletionFactory } from '../core/completions/factory.js';
|
|
3
|
+
import { COMMAND_REGISTRY } from '../core/completions/command-registry.js';
|
|
4
|
+
import { detectShell } from '../utils/shell-detection.js';
|
|
5
|
+
import { CompletionProvider } from '../core/completions/completion-provider.js';
|
|
6
|
+
import { getArchivedChangeIds } from '../utils/item-discovery.js';
|
|
7
|
+
/**
|
|
8
|
+
* Command for managing shell completions for LightSpec CLI
|
|
9
|
+
*/
|
|
10
|
+
export class CompletionCommand {
|
|
11
|
+
completionProvider;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.completionProvider = new CompletionProvider();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve shell parameter or exit with error
|
|
17
|
+
*
|
|
18
|
+
* @param shell - The shell parameter (may be undefined)
|
|
19
|
+
* @param operationName - Name of the operation (for error messages)
|
|
20
|
+
* @returns Resolved shell or null if should exit
|
|
21
|
+
*/
|
|
22
|
+
resolveShellOrExit(shell, operationName) {
|
|
23
|
+
const normalizedShell = this.normalizeShell(shell);
|
|
24
|
+
if (!normalizedShell) {
|
|
25
|
+
const detectionResult = detectShell();
|
|
26
|
+
if (detectionResult.shell && CompletionFactory.isSupported(detectionResult.shell)) {
|
|
27
|
+
return detectionResult.shell;
|
|
28
|
+
}
|
|
29
|
+
// Shell was detected but not supported
|
|
30
|
+
if (detectionResult.detected && !detectionResult.shell) {
|
|
31
|
+
console.error(`Error: Shell '${detectionResult.detected}' is not supported yet. Currently supported: ${CompletionFactory.getSupportedShells().join(', ')}`);
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
// No shell specified and cannot auto-detect
|
|
36
|
+
console.error('Error: Could not auto-detect shell. Please specify shell explicitly.');
|
|
37
|
+
console.error(`Usage: lightspec completion ${operationName} [shell]`);
|
|
38
|
+
console.error(`Currently supported: ${CompletionFactory.getSupportedShells().join(', ')}`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (!CompletionFactory.isSupported(normalizedShell)) {
|
|
43
|
+
console.error(`Error: Shell '${normalizedShell}' is not supported yet. Currently supported: ${CompletionFactory.getSupportedShells().join(', ')}`);
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return normalizedShell;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generate completion script and output to stdout
|
|
51
|
+
*
|
|
52
|
+
* @param options - Options for generation (shell type)
|
|
53
|
+
*/
|
|
54
|
+
async generate(options = {}) {
|
|
55
|
+
const shell = this.resolveShellOrExit(options.shell, 'generate');
|
|
56
|
+
if (!shell)
|
|
57
|
+
return;
|
|
58
|
+
await this.generateForShell(shell);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Install completion script to the appropriate location
|
|
62
|
+
*
|
|
63
|
+
* @param options - Options for installation (shell type, verbose output)
|
|
64
|
+
*/
|
|
65
|
+
async install(options = {}) {
|
|
66
|
+
const shell = this.resolveShellOrExit(options.shell, 'install');
|
|
67
|
+
if (!shell)
|
|
68
|
+
return;
|
|
69
|
+
await this.installForShell(shell, options.verbose || false);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Uninstall completion script from the installation location
|
|
73
|
+
*
|
|
74
|
+
* @param options - Options for uninstallation (shell type, yes flag)
|
|
75
|
+
*/
|
|
76
|
+
async uninstall(options = {}) {
|
|
77
|
+
const shell = this.resolveShellOrExit(options.shell, 'uninstall');
|
|
78
|
+
if (!shell)
|
|
79
|
+
return;
|
|
80
|
+
await this.uninstallForShell(shell, options.yes || false);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generate completion script for a specific shell
|
|
84
|
+
*/
|
|
85
|
+
async generateForShell(shell) {
|
|
86
|
+
const generator = CompletionFactory.createGenerator(shell);
|
|
87
|
+
const script = generator.generate(COMMAND_REGISTRY);
|
|
88
|
+
console.log(script);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Install completion script for a specific shell
|
|
92
|
+
*/
|
|
93
|
+
async installForShell(shell, verbose) {
|
|
94
|
+
const generator = CompletionFactory.createGenerator(shell);
|
|
95
|
+
const installer = CompletionFactory.createInstaller(shell);
|
|
96
|
+
const spinner = ora(`Installing ${shell} completion script...`).start();
|
|
97
|
+
try {
|
|
98
|
+
// Generate the completion script
|
|
99
|
+
const script = generator.generate(COMMAND_REGISTRY);
|
|
100
|
+
// Install it
|
|
101
|
+
const result = await installer.install(script);
|
|
102
|
+
spinner.stop();
|
|
103
|
+
if (result.success) {
|
|
104
|
+
console.log(`✓ ${result.message}`);
|
|
105
|
+
if (verbose && result.installedPath) {
|
|
106
|
+
console.log(` Installed to: ${result.installedPath}`);
|
|
107
|
+
if (result.backupPath) {
|
|
108
|
+
console.log(` Backup created: ${result.backupPath}`);
|
|
109
|
+
}
|
|
110
|
+
// Check if any shell config was updated
|
|
111
|
+
const configWasUpdated = result.zshrcConfigured || result.bashrcConfigured || result.profileConfigured;
|
|
112
|
+
if (configWasUpdated) {
|
|
113
|
+
const configPaths = {
|
|
114
|
+
zsh: '~/.zshrc',
|
|
115
|
+
bash: '~/.bashrc',
|
|
116
|
+
fish: '~/.config/fish/config.fish',
|
|
117
|
+
powershell: '$PROFILE',
|
|
118
|
+
};
|
|
119
|
+
const configPath = configPaths[shell] || 'config file';
|
|
120
|
+
console.log(` ${configPath} configured automatically`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Display warnings if present
|
|
124
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
125
|
+
console.log('');
|
|
126
|
+
for (const warning of result.warnings) {
|
|
127
|
+
console.log(warning);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Print instructions (only shown if .zshrc wasn't auto-configured)
|
|
131
|
+
if (result.instructions && result.instructions.length > 0) {
|
|
132
|
+
console.log('');
|
|
133
|
+
for (const instruction of result.instructions) {
|
|
134
|
+
console.log(instruction);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Check if any shell config was updated (InstallationResult has: zshrcConfigured, bashrcConfigured, profileConfigured)
|
|
139
|
+
const configWasUpdated = result.zshrcConfigured || result.bashrcConfigured || result.profileConfigured;
|
|
140
|
+
if (configWasUpdated) {
|
|
141
|
+
console.log('');
|
|
142
|
+
// Shell-specific reload instructions
|
|
143
|
+
const reloadCommands = {
|
|
144
|
+
zsh: 'exec zsh',
|
|
145
|
+
bash: 'exec bash',
|
|
146
|
+
fish: 'exec fish',
|
|
147
|
+
powershell: '. $PROFILE',
|
|
148
|
+
};
|
|
149
|
+
const reloadCmd = reloadCommands[shell] || `restart your ${shell} shell`;
|
|
150
|
+
console.log(`Restart your shell or run: ${reloadCmd}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.error(`✗ ${result.message}`);
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
spinner.stop();
|
|
161
|
+
console.error(`✗ Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`);
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Uninstall completion script for a specific shell
|
|
167
|
+
*/
|
|
168
|
+
async uninstallForShell(shell, skipConfirmation) {
|
|
169
|
+
const installer = CompletionFactory.createInstaller(shell);
|
|
170
|
+
// Prompt for confirmation unless --yes flag is provided
|
|
171
|
+
if (!skipConfirmation) {
|
|
172
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
173
|
+
// Get shell-specific config file path
|
|
174
|
+
const configPaths = {
|
|
175
|
+
zsh: '~/.zshrc',
|
|
176
|
+
bash: '~/.bashrc',
|
|
177
|
+
fish: 'Fish configuration', // Fish doesn't modify profile, just removes script file
|
|
178
|
+
powershell: '$PROFILE',
|
|
179
|
+
};
|
|
180
|
+
const configPath = configPaths[shell] || `${shell} configuration`;
|
|
181
|
+
const confirmed = await confirm({
|
|
182
|
+
message: `Remove LightSpec configuration from ${configPath}?`,
|
|
183
|
+
default: false,
|
|
184
|
+
});
|
|
185
|
+
if (!confirmed) {
|
|
186
|
+
console.log('Uninstall cancelled.');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const spinner = ora(`Uninstalling ${shell} completion script...`).start();
|
|
191
|
+
try {
|
|
192
|
+
const result = await installer.uninstall();
|
|
193
|
+
spinner.stop();
|
|
194
|
+
if (result.success) {
|
|
195
|
+
console.log(`✓ ${result.message}`);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
console.error(`✗ ${result.message}`);
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
spinner.stop();
|
|
204
|
+
console.error(`✗ Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`);
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Output machine-readable completion data for shell consumption
|
|
210
|
+
* Format: tab-separated "id\tdescription" per line
|
|
211
|
+
*
|
|
212
|
+
* @param options - Options specifying completion type
|
|
213
|
+
*/
|
|
214
|
+
async complete(options) {
|
|
215
|
+
const type = options.type.toLowerCase();
|
|
216
|
+
try {
|
|
217
|
+
switch (type) {
|
|
218
|
+
case 'changes': {
|
|
219
|
+
const changeIds = await this.completionProvider.getChangeIds();
|
|
220
|
+
for (const id of changeIds) {
|
|
221
|
+
console.log(`${id}\tactive change`);
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case 'specs': {
|
|
226
|
+
const specIds = await this.completionProvider.getSpecIds();
|
|
227
|
+
for (const id of specIds) {
|
|
228
|
+
console.log(`${id}\tspecification`);
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
case 'archived-changes': {
|
|
233
|
+
const archivedIds = await getArchivedChangeIds();
|
|
234
|
+
for (const id of archivedIds) {
|
|
235
|
+
console.log(`${id}\tarchived change`);
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
default:
|
|
240
|
+
// Invalid type - silently exit with no output for graceful shell completion failure
|
|
241
|
+
process.exitCode = 1;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Silently fail for graceful shell completion experience
|
|
247
|
+
process.exitCode = 1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Normalize shell parameter to lowercase
|
|
252
|
+
*/
|
|
253
|
+
normalizeShell(shell) {
|
|
254
|
+
return shell?.toLowerCase();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=completion.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Register the config command and all its subcommands.
|
|
4
|
+
*
|
|
5
|
+
* @param program - The Commander program instance
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerConfigCommand(program: Command): void;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { getGlobalConfigPath, getGlobalConfig, saveGlobalConfig, } from '../core/global-config.js';
|
|
4
|
+
import { getNestedValue, setNestedValue, deleteNestedValue, coerceValue, formatValueYaml, validateConfigKeyPath, validateConfig, DEFAULT_CONFIG, } from '../core/config-schema.js';
|
|
5
|
+
/**
|
|
6
|
+
* Register the config command and all its subcommands.
|
|
7
|
+
*
|
|
8
|
+
* @param program - The Commander program instance
|
|
9
|
+
*/
|
|
10
|
+
export function registerConfigCommand(program) {
|
|
11
|
+
const configCmd = program
|
|
12
|
+
.command('config')
|
|
13
|
+
.description('View and modify global LightSpec configuration')
|
|
14
|
+
.option('--scope <scope>', 'Config scope (only "global" supported currently)')
|
|
15
|
+
.hook('preAction', (thisCommand) => {
|
|
16
|
+
const opts = thisCommand.opts();
|
|
17
|
+
if (opts.scope && opts.scope !== 'global') {
|
|
18
|
+
console.error('Error: Project-local config is not yet implemented');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
// config path
|
|
23
|
+
configCmd
|
|
24
|
+
.command('path')
|
|
25
|
+
.description('Show config file location')
|
|
26
|
+
.action(() => {
|
|
27
|
+
console.log(getGlobalConfigPath());
|
|
28
|
+
});
|
|
29
|
+
// config list
|
|
30
|
+
configCmd
|
|
31
|
+
.command('list')
|
|
32
|
+
.description('Show all current settings')
|
|
33
|
+
.option('--json', 'Output as JSON')
|
|
34
|
+
.action((options) => {
|
|
35
|
+
const config = getGlobalConfig();
|
|
36
|
+
if (options.json) {
|
|
37
|
+
console.log(JSON.stringify(config, null, 2));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log(formatValueYaml(config));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// config get
|
|
44
|
+
configCmd
|
|
45
|
+
.command('get <key>')
|
|
46
|
+
.description('Get a specific value (raw, scriptable)')
|
|
47
|
+
.action((key) => {
|
|
48
|
+
const config = getGlobalConfig();
|
|
49
|
+
const value = getNestedValue(config, key);
|
|
50
|
+
if (value === undefined) {
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (typeof value === 'object' && value !== null) {
|
|
55
|
+
console.log(JSON.stringify(value));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.log(String(value));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// config set
|
|
62
|
+
configCmd
|
|
63
|
+
.command('set <key> <value>')
|
|
64
|
+
.description('Set a value (auto-coerce types)')
|
|
65
|
+
.option('--string', 'Force value to be stored as string')
|
|
66
|
+
.option('--allow-unknown', 'Allow setting unknown keys')
|
|
67
|
+
.action((key, value, options) => {
|
|
68
|
+
const allowUnknown = Boolean(options.allowUnknown);
|
|
69
|
+
const keyValidation = validateConfigKeyPath(key);
|
|
70
|
+
if (!keyValidation.valid && !allowUnknown) {
|
|
71
|
+
const reason = keyValidation.reason ? ` ${keyValidation.reason}.` : '';
|
|
72
|
+
console.error(`Error: Invalid configuration key "${key}".${reason}`);
|
|
73
|
+
console.error('Use "lightspec config list" to see available keys.');
|
|
74
|
+
console.error('Pass --allow-unknown to bypass this check.');
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const config = getGlobalConfig();
|
|
79
|
+
const coercedValue = coerceValue(value, options.string || false);
|
|
80
|
+
// Create a copy to validate before saving
|
|
81
|
+
const newConfig = JSON.parse(JSON.stringify(config));
|
|
82
|
+
setNestedValue(newConfig, key, coercedValue);
|
|
83
|
+
// Validate the new config
|
|
84
|
+
const validation = validateConfig(newConfig);
|
|
85
|
+
if (!validation.success) {
|
|
86
|
+
console.error(`Error: Invalid configuration - ${validation.error}`);
|
|
87
|
+
process.exitCode = 1;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Apply changes and save
|
|
91
|
+
setNestedValue(config, key, coercedValue);
|
|
92
|
+
saveGlobalConfig(config);
|
|
93
|
+
const displayValue = typeof coercedValue === 'string' ? `"${coercedValue}"` : String(coercedValue);
|
|
94
|
+
console.log(`Set ${key} = ${displayValue}`);
|
|
95
|
+
});
|
|
96
|
+
// config unset
|
|
97
|
+
configCmd
|
|
98
|
+
.command('unset <key>')
|
|
99
|
+
.description('Remove a key (revert to default)')
|
|
100
|
+
.action((key) => {
|
|
101
|
+
const config = getGlobalConfig();
|
|
102
|
+
const existed = deleteNestedValue(config, key);
|
|
103
|
+
if (existed) {
|
|
104
|
+
saveGlobalConfig(config);
|
|
105
|
+
console.log(`Unset ${key} (reverted to default)`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.log(`Key "${key}" was not set`);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// config reset
|
|
112
|
+
configCmd
|
|
113
|
+
.command('reset')
|
|
114
|
+
.description('Reset configuration to defaults')
|
|
115
|
+
.option('--all', 'Reset all configuration (required)')
|
|
116
|
+
.option('-y, --yes', 'Skip confirmation prompts')
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
if (!options.all) {
|
|
119
|
+
console.error('Error: --all flag is required for reset');
|
|
120
|
+
console.error('Usage: lightspec config reset --all [-y]');
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!options.yes) {
|
|
125
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
126
|
+
const confirmed = await confirm({
|
|
127
|
+
message: 'Reset all configuration to defaults?',
|
|
128
|
+
default: false,
|
|
129
|
+
});
|
|
130
|
+
if (!confirmed) {
|
|
131
|
+
console.log('Reset cancelled.');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
saveGlobalConfig({ ...DEFAULT_CONFIG });
|
|
136
|
+
console.log('Configuration reset to defaults');
|
|
137
|
+
});
|
|
138
|
+
// config edit
|
|
139
|
+
configCmd
|
|
140
|
+
.command('edit')
|
|
141
|
+
.description('Open config in $EDITOR')
|
|
142
|
+
.action(async () => {
|
|
143
|
+
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
144
|
+
if (!editor) {
|
|
145
|
+
console.error('Error: No editor configured');
|
|
146
|
+
console.error('Set the EDITOR or VISUAL environment variable to your preferred editor');
|
|
147
|
+
console.error('Example: export EDITOR=vim');
|
|
148
|
+
process.exitCode = 1;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const configPath = getGlobalConfigPath();
|
|
152
|
+
// Ensure config file exists with defaults
|
|
153
|
+
if (!fs.existsSync(configPath)) {
|
|
154
|
+
saveGlobalConfig({ ...DEFAULT_CONFIG });
|
|
155
|
+
}
|
|
156
|
+
// Spawn editor and wait for it to close
|
|
157
|
+
// Avoid shell parsing to correctly handle paths with spaces in both
|
|
158
|
+
// the editor path and config path
|
|
159
|
+
const child = spawn(editor, [configPath], {
|
|
160
|
+
stdio: 'inherit',
|
|
161
|
+
shell: false,
|
|
162
|
+
});
|
|
163
|
+
await new Promise((resolve, reject) => {
|
|
164
|
+
child.on('close', (code) => {
|
|
165
|
+
if (code === 0) {
|
|
166
|
+
resolve();
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
reject(new Error(`Editor exited with code ${code}`));
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
child.on('error', reject);
|
|
173
|
+
});
|
|
174
|
+
try {
|
|
175
|
+
const rawConfig = fs.readFileSync(configPath, 'utf-8');
|
|
176
|
+
const parsedConfig = JSON.parse(rawConfig);
|
|
177
|
+
const validation = validateConfig(parsedConfig);
|
|
178
|
+
if (!validation.success) {
|
|
179
|
+
console.error(`Error: Invalid configuration - ${validation.error}`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error.code === 'ENOENT') {
|
|
185
|
+
console.error(`Error: Config file not found at ${configPath}`);
|
|
186
|
+
}
|
|
187
|
+
else if (error instanceof SyntaxError) {
|
|
188
|
+
console.error(`Error: Invalid JSON in ${configPath}`);
|
|
189
|
+
console.error(error.message);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.error(`Error: Unable to validate configuration - ${error instanceof Error ? error.message : String(error)}`);
|
|
193
|
+
}
|
|
194
|
+
process.exitCode = 1;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=config.js.map
|