synarcx 0.1.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 +23 -0
- package/README.md +90 -0
- package/bin/synarcx.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +474 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +278 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +264 -0
- package/dist/commands/config.d.ts +36 -0
- package/dist/commands/config.js +552 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +170 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +870 -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 +226 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +295 -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 +327 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +45 -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 +57 -0
- package/dist/commands/workflow/shared.js +117 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +75 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +69 -0
- package/dist/commands/workspace/open.d.ts +29 -0
- package/dist/commands/workspace/open.js +84 -0
- package/dist/commands/workspace/operations.d.ts +18 -0
- package/dist/commands/workspace/operations.js +461 -0
- package/dist/commands/workspace/selection.d.ts +5 -0
- package/dist/commands/workspace/selection.js +90 -0
- package/dist/commands/workspace/types.d.ts +83 -0
- package/dist/commands/workspace/types.js +36 -0
- package/dist/commands/workspace.d.ts +3 -0
- package/dist/commands/workspace.js +635 -0
- package/dist/core/archive.d.ts +11 -0
- package/dist/core/archive.js +319 -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 +8 -0
- package/dist/core/artifact-graph/index.js +14 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
- package/dist/core/artifact-graph/instruction-loader.js +217 -0
- package/dist/core/artifact-graph/outputs.d.ts +14 -0
- package/dist/core/artifact-graph/outputs.js +39 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +258 -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 +31 -0
- package/dist/core/artifact-graph/types.d.ts +45 -0
- package/dist/core/artifact-graph/types.js +43 -0
- package/dist/core/available-tools.d.ts +17 -0
- package/dist/core/available-tools.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/bob.d.ts +14 -0
- package/dist/core/command-generation/adapters/bob.js +45 -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 +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -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 +32 -0
- package/dist/core/command-generation/adapters/index.js +32 -0
- package/dist/core/command-generation/adapters/junie.d.ts +13 -0
- package/dist/core/command-generation/adapters/junie.js +26 -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/kiro.d.ts +13 -0
- package/dist/core/command-generation/adapters/kiro.js +26 -0
- package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
- package/dist/core/command-generation/adapters/lingma.js +30 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +27 -0
- package/dist/core/command-generation/adapters/pi.d.ts +18 -0
- package/dist/core/command-generation/adapters/pi.js +55 -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 +98 -0
- package/dist/core/command-generation/types.d.ts +56 -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 +596 -0
- package/dist/core/completions/completion-provider.d.ts +71 -0
- package/dist/core/completions/completion-provider.js +129 -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 +35 -0
- package/dist/core/completions/generators/bash-generator.js +230 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +160 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
- package/dist/core/completions/generators/powershell-generator.js +266 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
- package/dist/core/completions/generators/zsh-generator.js +274 -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 +102 -0
- package/dist/core/completions/installers/powershell-installer.js +387 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
- package/dist/core/completions/installers/zsh-installer.js +421 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +30 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +45 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +34 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +45 -0
- package/dist/core/completions/types.d.ts +101 -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 +86 -0
- package/dist/core/config-schema.js +213 -0
- package/dist/core/config.d.ts +19 -0
- package/dist/core/config.js +38 -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 +49 -0
- package/dist/core/global-config.js +124 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +4 -0
- package/dist/core/init.d.ts +37 -0
- package/dist/core/init.js +585 -0
- package/dist/core/legacy-cleanup.d.ts +169 -0
- package/dist/core/legacy-cleanup.js +578 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +172 -0
- package/dist/core/migration.d.ts +23 -0
- package/dist/core/migration.js +108 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +197 -0
- package/dist/core/parsers/markdown-parser.d.ts +26 -0
- package/dist/core/parsers/markdown-parser.js +227 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/parsers/spec-structure.d.ts +9 -0
- package/dist/core/parsers/spec-structure.js +88 -0
- package/dist/core/profile-sync-drift.d.ts +38 -0
- package/dist/core/profile-sync-drift.js +197 -0
- package/dist/core/profiles.d.ts +26 -0
- package/dist/core/profiles.js +37 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +224 -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 +49 -0
- package/dist/core/shared/skill-generation.js +90 -0
- package/dist/core/shared/tool-detection.d.ts +71 -0
- package/dist/core/shared/tool-detection.js +152 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +393 -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 +15 -0
- package/dist/core/templates/skill-templates.js +14 -0
- package/dist/core/templates/types.d.ts +19 -0
- package/dist/core/templates/types.js +5 -0
- package/dist/core/templates/workflows/analyze.d.ts +4 -0
- package/dist/core/templates/workflows/analyze.js +101 -0
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +308 -0
- package/dist/core/templates/workflows/archive-change.d.ts +10 -0
- package/dist/core/templates/workflows/archive-change.js +271 -0
- package/dist/core/templates/workflows/clarify.d.ts +4 -0
- package/dist/core/templates/workflows/clarify.js +108 -0
- package/dist/core/templates/workflows/debug.d.ts +4 -0
- package/dist/core/templates/workflows/debug.js +117 -0
- package/dist/core/templates/workflows/explore.d.ts +10 -0
- package/dist/core/templates/workflows/explore.js +479 -0
- package/dist/core/templates/workflows/propose.d.ts +10 -0
- package/dist/core/templates/workflows/propose.js +216 -0
- package/dist/core/templates/workflows/sync.d.ts +4 -0
- package/dist/core/templates/workflows/sync.js +108 -0
- package/dist/core/update.d.ts +82 -0
- package/dist/core/update.js +555 -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 +418 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +169 -0
- package/dist/core/workspace/foundation.d.ts +79 -0
- package/dist/core/workspace/foundation.js +367 -0
- package/dist/core/workspace/index.d.ts +5 -0
- package/dist/core/workspace/index.js +5 -0
- package/dist/core/workspace/link-input.d.ts +9 -0
- package/dist/core/workspace/link-input.js +32 -0
- package/dist/core/workspace/open-surface.d.ts +24 -0
- package/dist/core/workspace/open-surface.js +137 -0
- package/dist/core/workspace/openers.d.ts +21 -0
- package/dist/core/workspace/openers.js +119 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +28 -0
- package/dist/prompts/searchable-multi-select.js +159 -0
- package/dist/ui/ascii-patterns.d.ts +25 -0
- package/dist/ui/ascii-patterns.js +140 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +144 -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 +122 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +41 -0
- package/dist/utils/file-system.js +301 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -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 +73 -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 +76 -0
- package/schemas/synarcx/schema.yaml +153 -0
- package/schemas/synarcx/templates/design.md +19 -0
- package/schemas/synarcx/templates/proposal.md +23 -0
- package/schemas/synarcx/templates/spec.md +8 -0
- package/schemas/synarcx/templates/tasks.md +9 -0
- package/scripts/postinstall.js +83 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { InstallationResult } from '../factory.js';
|
|
2
|
+
/**
|
|
3
|
+
* Installer for Fish completion scripts.
|
|
4
|
+
* Fish automatically loads completions from ~/.config/fish/completions/
|
|
5
|
+
*/
|
|
6
|
+
export declare class FishInstaller {
|
|
7
|
+
private readonly homeDir;
|
|
8
|
+
constructor(homeDir?: string);
|
|
9
|
+
/**
|
|
10
|
+
* Get the installation path for Fish completions
|
|
11
|
+
*
|
|
12
|
+
* @returns Installation path
|
|
13
|
+
*/
|
|
14
|
+
getInstallationPath(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Backup an existing completion file if it exists
|
|
17
|
+
*
|
|
18
|
+
* @param targetPath - Path to the file to backup
|
|
19
|
+
* @returns Path to the backup file, or undefined if no backup was needed
|
|
20
|
+
*/
|
|
21
|
+
backupExistingFile(targetPath: string): Promise<string | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Install the completion script
|
|
24
|
+
*
|
|
25
|
+
* @param completionScript - The completion script content to install
|
|
26
|
+
* @returns Installation result with status and instructions
|
|
27
|
+
*/
|
|
28
|
+
install(completionScript: string): Promise<InstallationResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Uninstall the completion script
|
|
31
|
+
*
|
|
32
|
+
* @param options - Optional uninstall options
|
|
33
|
+
* @param options.yes - Skip confirmation prompt (handled by command layer)
|
|
34
|
+
* @returns Uninstallation result
|
|
35
|
+
*/
|
|
36
|
+
uninstall(options?: {
|
|
37
|
+
yes?: boolean;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
success: boolean;
|
|
40
|
+
message: string;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=fish-installer.d.ts.map
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
/**
|
|
5
|
+
* Installer for Fish completion scripts.
|
|
6
|
+
* Fish automatically loads completions from ~/.config/fish/completions/
|
|
7
|
+
*/
|
|
8
|
+
export class FishInstaller {
|
|
9
|
+
homeDir;
|
|
10
|
+
constructor(homeDir = os.homedir()) {
|
|
11
|
+
this.homeDir = homeDir;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the installation path for Fish completions
|
|
15
|
+
*
|
|
16
|
+
* @returns Installation path
|
|
17
|
+
*/
|
|
18
|
+
getInstallationPath() {
|
|
19
|
+
return path.join(this.homeDir, '.config', 'fish', 'completions', 'synarcx.fish');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Backup an existing completion file if it exists
|
|
23
|
+
*
|
|
24
|
+
* @param targetPath - Path to the file to backup
|
|
25
|
+
* @returns Path to the backup file, or undefined if no backup was needed
|
|
26
|
+
*/
|
|
27
|
+
async backupExistingFile(targetPath) {
|
|
28
|
+
try {
|
|
29
|
+
await fs.access(targetPath);
|
|
30
|
+
// File exists, create a backup
|
|
31
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
32
|
+
const backupPath = `${targetPath}.backup-${timestamp}`;
|
|
33
|
+
await fs.copyFile(targetPath, backupPath);
|
|
34
|
+
return backupPath;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// File doesn't exist, no backup needed
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Install the completion script
|
|
43
|
+
*
|
|
44
|
+
* @param completionScript - The completion script content to install
|
|
45
|
+
* @returns Installation result with status and instructions
|
|
46
|
+
*/
|
|
47
|
+
async install(completionScript) {
|
|
48
|
+
try {
|
|
49
|
+
const targetPath = this.getInstallationPath();
|
|
50
|
+
// Check if already installed with same content
|
|
51
|
+
let isUpdate = false;
|
|
52
|
+
try {
|
|
53
|
+
const existingContent = await fs.readFile(targetPath, 'utf-8');
|
|
54
|
+
if (existingContent === completionScript) {
|
|
55
|
+
// Already installed and up to date
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
installedPath: targetPath,
|
|
59
|
+
message: 'Completion script is already installed (up to date)',
|
|
60
|
+
instructions: [
|
|
61
|
+
'The completion script is already installed and up to date.',
|
|
62
|
+
'Fish automatically loads completions - they should be available immediately.',
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// File exists but content is different - this is an update
|
|
67
|
+
isUpdate = true;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
// File doesn't exist or can't be read, proceed with installation
|
|
71
|
+
console.debug(`Unable to read existing completion file at ${targetPath}: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
// Ensure the directory exists
|
|
74
|
+
const targetDir = path.dirname(targetPath);
|
|
75
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
76
|
+
// Backup existing file if updating
|
|
77
|
+
const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
|
|
78
|
+
// Write the completion script
|
|
79
|
+
await fs.writeFile(targetPath, completionScript, 'utf-8');
|
|
80
|
+
// Determine appropriate message
|
|
81
|
+
let message;
|
|
82
|
+
if (isUpdate) {
|
|
83
|
+
message = backupPath
|
|
84
|
+
? 'Completion script updated successfully (previous version backed up)'
|
|
85
|
+
: 'Completion script updated successfully';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
message = 'Completion script installed successfully for Fish';
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
installedPath: targetPath,
|
|
93
|
+
backupPath,
|
|
94
|
+
message,
|
|
95
|
+
instructions: [
|
|
96
|
+
'Fish automatically loads completions from ~/.config/fish/completions/',
|
|
97
|
+
'Completions are available immediately - no shell restart needed.',
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
message: `Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Uninstall the completion script
|
|
110
|
+
*
|
|
111
|
+
* @param options - Optional uninstall options
|
|
112
|
+
* @param options.yes - Skip confirmation prompt (handled by command layer)
|
|
113
|
+
* @returns Uninstallation result
|
|
114
|
+
*/
|
|
115
|
+
async uninstall(options) {
|
|
116
|
+
try {
|
|
117
|
+
const targetPath = this.getInstallationPath();
|
|
118
|
+
// Check if installed
|
|
119
|
+
try {
|
|
120
|
+
await fs.access(targetPath);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
message: 'Completion script is not installed',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Remove the completion script
|
|
129
|
+
await fs.unlink(targetPath);
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
message: 'Completion script uninstalled successfully',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
return {
|
|
137
|
+
success: false,
|
|
138
|
+
message: `Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=fish-installer.js.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { InstallationResult } from '../factory.js';
|
|
2
|
+
/**
|
|
3
|
+
* Installer for PowerShell completion scripts.
|
|
4
|
+
* Works with both Windows PowerShell 5.1 and PowerShell Core 7+
|
|
5
|
+
*/
|
|
6
|
+
export declare class PowerShellInstaller {
|
|
7
|
+
private readonly homeDir;
|
|
8
|
+
/**
|
|
9
|
+
* Markers for PowerShell profile configuration management
|
|
10
|
+
*/
|
|
11
|
+
private readonly PROFILE_MARKERS;
|
|
12
|
+
constructor(homeDir?: string);
|
|
13
|
+
/**
|
|
14
|
+
* Detect the encoding of a file by inspecting its BOM (Byte Order Mark).
|
|
15
|
+
* Returns the Node.js BufferEncoding and the raw BOM bytes to preserve on write.
|
|
16
|
+
*/
|
|
17
|
+
private detectEncoding;
|
|
18
|
+
/**
|
|
19
|
+
* Read a profile file, preserving its encoding metadata for round-trip writes.
|
|
20
|
+
* Throws if the file uses UTF-16 BE (unsupported by Node).
|
|
21
|
+
*/
|
|
22
|
+
private readProfileFile;
|
|
23
|
+
/**
|
|
24
|
+
* Write a profile file, preserving the original BOM and encoding.
|
|
25
|
+
*/
|
|
26
|
+
private writeProfileFile;
|
|
27
|
+
/**
|
|
28
|
+
* Get PowerShell profile path
|
|
29
|
+
* Prefers $PROFILE environment variable, falls back to platform defaults
|
|
30
|
+
*
|
|
31
|
+
* @returns Profile path
|
|
32
|
+
*/
|
|
33
|
+
getProfilePath(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Get all PowerShell profile paths to configure.
|
|
36
|
+
* On Windows, returns both PowerShell Core and Windows PowerShell 5.1 paths.
|
|
37
|
+
* On Unix, returns PowerShell Core path only.
|
|
38
|
+
*/
|
|
39
|
+
private getAllProfilePaths;
|
|
40
|
+
/**
|
|
41
|
+
* Get the installation path for the completion script
|
|
42
|
+
*
|
|
43
|
+
* @returns Installation path
|
|
44
|
+
*/
|
|
45
|
+
getInstallationPath(): string;
|
|
46
|
+
/**
|
|
47
|
+
* Backup an existing completion file if it exists
|
|
48
|
+
*
|
|
49
|
+
* @param targetPath - Path to the file to backup
|
|
50
|
+
* @returns Path to the backup file, or undefined if no backup was needed
|
|
51
|
+
*/
|
|
52
|
+
backupExistingFile(targetPath: string): Promise<string | undefined>;
|
|
53
|
+
/**
|
|
54
|
+
* Generate PowerShell profile configuration content
|
|
55
|
+
*
|
|
56
|
+
* @param scriptPath - Path to the completion script
|
|
57
|
+
* @returns Configuration content
|
|
58
|
+
*/
|
|
59
|
+
private generateProfileConfig;
|
|
60
|
+
/**
|
|
61
|
+
* Configure PowerShell profile to source the completion script
|
|
62
|
+
*
|
|
63
|
+
* @param scriptPath - Path to the completion script
|
|
64
|
+
* @returns true if configured successfully, false otherwise
|
|
65
|
+
*/
|
|
66
|
+
configureProfile(scriptPath: string): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Remove PowerShell profile configuration
|
|
69
|
+
* Used during uninstallation
|
|
70
|
+
*
|
|
71
|
+
* @returns true if removed successfully, false otherwise
|
|
72
|
+
*/
|
|
73
|
+
removeProfileConfig(): Promise<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* Install the completion script
|
|
76
|
+
*
|
|
77
|
+
* @param completionScript - The completion script content to install
|
|
78
|
+
* @returns Installation result with status and instructions
|
|
79
|
+
*/
|
|
80
|
+
install(completionScript: string): Promise<InstallationResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Generate user instructions for enabling completions
|
|
83
|
+
*
|
|
84
|
+
* @param installedPath - Path where the script was installed
|
|
85
|
+
* @returns Array of instruction strings
|
|
86
|
+
*/
|
|
87
|
+
private generateInstructions;
|
|
88
|
+
/**
|
|
89
|
+
* Uninstall the completion script
|
|
90
|
+
*
|
|
91
|
+
* @param options - Optional uninstall options
|
|
92
|
+
* @param options.yes - Skip confirmation prompt (handled by command layer)
|
|
93
|
+
* @returns Uninstallation result
|
|
94
|
+
*/
|
|
95
|
+
uninstall(options?: {
|
|
96
|
+
yes?: boolean;
|
|
97
|
+
}): Promise<{
|
|
98
|
+
success: boolean;
|
|
99
|
+
message: string;
|
|
100
|
+
}>;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=powershell-installer.d.ts.map
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
/**
|
|
5
|
+
* Installer for PowerShell completion scripts.
|
|
6
|
+
* Works with both Windows PowerShell 5.1 and PowerShell Core 7+
|
|
7
|
+
*/
|
|
8
|
+
export class PowerShellInstaller {
|
|
9
|
+
homeDir;
|
|
10
|
+
/**
|
|
11
|
+
* Markers for PowerShell profile configuration management
|
|
12
|
+
*/
|
|
13
|
+
PROFILE_MARKERS = {
|
|
14
|
+
start: '# OPENSPEC:START',
|
|
15
|
+
end: '# OPENSPEC:END',
|
|
16
|
+
};
|
|
17
|
+
constructor(homeDir = os.homedir()) {
|
|
18
|
+
this.homeDir = homeDir;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Detect the encoding of a file by inspecting its BOM (Byte Order Mark).
|
|
22
|
+
* Returns the Node.js BufferEncoding and the raw BOM bytes to preserve on write.
|
|
23
|
+
*/
|
|
24
|
+
detectEncoding(buffer) {
|
|
25
|
+
// UTF-16 LE BOM: FF FE
|
|
26
|
+
if (buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xfe) {
|
|
27
|
+
return { encoding: 'utf16le', bom: Buffer.from([0xff, 0xfe]) };
|
|
28
|
+
}
|
|
29
|
+
// UTF-16 BE BOM: FE FF — not natively supported by Node
|
|
30
|
+
if (buffer.length >= 2 && buffer[0] === 0xfe && buffer[1] === 0xff) {
|
|
31
|
+
throw new Error('File is encoded as UTF-16 BE which is not supported. ' +
|
|
32
|
+
'Please re-save as UTF-8 or UTF-16 LE, then retry.');
|
|
33
|
+
}
|
|
34
|
+
// UTF-8 BOM: EF BB BF
|
|
35
|
+
if (buffer.length >= 3 && buffer[0] === 0xef && buffer[1] === 0xbb && buffer[2] === 0xbf) {
|
|
36
|
+
return { encoding: 'utf-8', bom: Buffer.from([0xef, 0xbb, 0xbf]) };
|
|
37
|
+
}
|
|
38
|
+
// No BOM → default UTF-8
|
|
39
|
+
return { encoding: 'utf-8', bom: Buffer.alloc(0) };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Read a profile file, preserving its encoding metadata for round-trip writes.
|
|
43
|
+
* Throws if the file uses UTF-16 BE (unsupported by Node).
|
|
44
|
+
*/
|
|
45
|
+
async readProfileFile(filePath) {
|
|
46
|
+
const raw = await fs.readFile(filePath);
|
|
47
|
+
const { encoding, bom } = this.detectEncoding(raw);
|
|
48
|
+
const content = raw.subarray(bom.length).toString(encoding);
|
|
49
|
+
return { content, encoding, bom };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Write a profile file, preserving the original BOM and encoding.
|
|
53
|
+
*/
|
|
54
|
+
async writeProfileFile(filePath, content, encoding, bom) {
|
|
55
|
+
const body = Buffer.from(content, encoding);
|
|
56
|
+
await fs.writeFile(filePath, Buffer.concat([bom, body]));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get PowerShell profile path
|
|
60
|
+
* Prefers $PROFILE environment variable, falls back to platform defaults
|
|
61
|
+
*
|
|
62
|
+
* @returns Profile path
|
|
63
|
+
*/
|
|
64
|
+
getProfilePath() {
|
|
65
|
+
// Check $PROFILE environment variable (set when running in PowerShell)
|
|
66
|
+
if (process.env.PROFILE) {
|
|
67
|
+
return process.env.PROFILE;
|
|
68
|
+
}
|
|
69
|
+
// Fall back to platform-specific defaults
|
|
70
|
+
if (process.platform === 'win32') {
|
|
71
|
+
// Windows: Documents/PowerShell/Microsoft.PowerShell_profile.ps1
|
|
72
|
+
return path.join(this.homeDir, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// macOS/Linux: .config/powershell/Microsoft.PowerShell_profile.ps1
|
|
76
|
+
return path.join(this.homeDir, '.config', 'powershell', 'Microsoft.PowerShell_profile.ps1');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get all PowerShell profile paths to configure.
|
|
81
|
+
* On Windows, returns both PowerShell Core and Windows PowerShell 5.1 paths.
|
|
82
|
+
* On Unix, returns PowerShell Core path only.
|
|
83
|
+
*/
|
|
84
|
+
getAllProfilePaths() {
|
|
85
|
+
// If PROFILE env var is set, use only that path
|
|
86
|
+
if (process.env.PROFILE) {
|
|
87
|
+
return [process.env.PROFILE];
|
|
88
|
+
}
|
|
89
|
+
if (process.platform === 'win32') {
|
|
90
|
+
return [
|
|
91
|
+
// PowerShell Core 6+ (cross-platform)
|
|
92
|
+
path.join(this.homeDir, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1'),
|
|
93
|
+
// Windows PowerShell 5.1 (Windows-only)
|
|
94
|
+
path.join(this.homeDir, 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1'),
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// Unix systems: PowerShell Core only
|
|
99
|
+
return [path.join(this.homeDir, '.config', 'powershell', 'Microsoft.PowerShell_profile.ps1')];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get the installation path for the completion script
|
|
104
|
+
*
|
|
105
|
+
* @returns Installation path
|
|
106
|
+
*/
|
|
107
|
+
getInstallationPath() {
|
|
108
|
+
const profilePath = this.getProfilePath();
|
|
109
|
+
const profileDir = path.dirname(profilePath);
|
|
110
|
+
return path.join(profileDir, 'OpenSpecCompletion.ps1');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Backup an existing completion file if it exists
|
|
114
|
+
*
|
|
115
|
+
* @param targetPath - Path to the file to backup
|
|
116
|
+
* @returns Path to the backup file, or undefined if no backup was needed
|
|
117
|
+
*/
|
|
118
|
+
async backupExistingFile(targetPath) {
|
|
119
|
+
try {
|
|
120
|
+
await fs.access(targetPath);
|
|
121
|
+
// File exists, create a backup
|
|
122
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
123
|
+
const backupPath = `${targetPath}.backup-${timestamp}`;
|
|
124
|
+
await fs.copyFile(targetPath, backupPath);
|
|
125
|
+
return backupPath;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// File doesn't exist, no backup needed
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generate PowerShell profile configuration content
|
|
134
|
+
*
|
|
135
|
+
* @param scriptPath - Path to the completion script
|
|
136
|
+
* @returns Configuration content
|
|
137
|
+
*/
|
|
138
|
+
generateProfileConfig(scriptPath) {
|
|
139
|
+
return [
|
|
140
|
+
'# synarcx shell completions configuration',
|
|
141
|
+
`if (Test-Path "${scriptPath}") {`,
|
|
142
|
+
` . "${scriptPath}"`,
|
|
143
|
+
'}',
|
|
144
|
+
].join('\n');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Configure PowerShell profile to source the completion script
|
|
148
|
+
*
|
|
149
|
+
* @param scriptPath - Path to the completion script
|
|
150
|
+
* @returns true if configured successfully, false otherwise
|
|
151
|
+
*/
|
|
152
|
+
async configureProfile(scriptPath) {
|
|
153
|
+
const profilePaths = this.getAllProfilePaths();
|
|
154
|
+
let anyConfigured = false;
|
|
155
|
+
for (const profilePath of profilePaths) {
|
|
156
|
+
try {
|
|
157
|
+
// Create profile file if it doesn't exist
|
|
158
|
+
const profileDir = path.dirname(profilePath);
|
|
159
|
+
await fs.mkdir(profileDir, { recursive: true });
|
|
160
|
+
let profileContent = '';
|
|
161
|
+
let fileEncoding = 'utf-8';
|
|
162
|
+
let fileBom = Buffer.alloc(0);
|
|
163
|
+
try {
|
|
164
|
+
const file = await this.readProfileFile(profilePath);
|
|
165
|
+
profileContent = file.content;
|
|
166
|
+
fileEncoding = file.encoding;
|
|
167
|
+
fileBom = file.bom;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
// If the file doesn't exist that's fine — we'll create it as UTF-8.
|
|
171
|
+
// Any other read error (permissions, unsupported encoding, etc.) → skip this profile.
|
|
172
|
+
if (err?.code === 'ENOENT') {
|
|
173
|
+
// keep defaults
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.warn(`Warning: Skipping ${profilePath}: ${err?.message ?? String(err)}`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Check if already configured
|
|
181
|
+
const scriptLine = `. "${scriptPath}"`;
|
|
182
|
+
if (profileContent.includes(scriptLine)) {
|
|
183
|
+
continue; // Already configured, skip
|
|
184
|
+
}
|
|
185
|
+
// Add OpenSpec completion configuration with markers
|
|
186
|
+
const openspecBlock = [
|
|
187
|
+
'',
|
|
188
|
+
'# OPENSPEC:START - synarcx completion (managed block, do not edit manually)',
|
|
189
|
+
scriptLine,
|
|
190
|
+
'# OPENSPEC:END',
|
|
191
|
+
'',
|
|
192
|
+
].join('\n');
|
|
193
|
+
const newContent = profileContent + openspecBlock;
|
|
194
|
+
await this.writeProfileFile(profilePath, newContent, fileEncoding, fileBom);
|
|
195
|
+
anyConfigured = true;
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
// Continue to next profile if this one fails
|
|
199
|
+
console.warn(`Warning: Could not configure ${profilePath}: ${error}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return anyConfigured;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Remove PowerShell profile configuration
|
|
206
|
+
* Used during uninstallation
|
|
207
|
+
*
|
|
208
|
+
* @returns true if removed successfully, false otherwise
|
|
209
|
+
*/
|
|
210
|
+
async removeProfileConfig() {
|
|
211
|
+
const profilePaths = this.getAllProfilePaths();
|
|
212
|
+
let anyRemoved = false;
|
|
213
|
+
for (const profilePath of profilePaths) {
|
|
214
|
+
try {
|
|
215
|
+
// Read profile content with encoding detection
|
|
216
|
+
let profileContent;
|
|
217
|
+
let fileEncoding = 'utf-8';
|
|
218
|
+
let fileBom = Buffer.alloc(0);
|
|
219
|
+
try {
|
|
220
|
+
const file = await this.readProfileFile(profilePath);
|
|
221
|
+
profileContent = file.content;
|
|
222
|
+
fileEncoding = file.encoding;
|
|
223
|
+
fileBom = file.bom;
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
if (err?.code === 'ENOENT') {
|
|
227
|
+
continue; // Profile doesn't exist, nothing to remove
|
|
228
|
+
}
|
|
229
|
+
console.warn(`Warning: Could not read ${profilePath}: ${err?.message ?? String(err)}`);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
// Remove OPENSPEC:START -> OPENSPEC:END block
|
|
233
|
+
const startMarker = '# OPENSPEC:START';
|
|
234
|
+
const endMarker = '# OPENSPEC:END';
|
|
235
|
+
const startIndex = profileContent.indexOf(startMarker);
|
|
236
|
+
if (startIndex === -1) {
|
|
237
|
+
continue; // No OpenSpec block found
|
|
238
|
+
}
|
|
239
|
+
const endIndex = profileContent.indexOf(endMarker, startIndex);
|
|
240
|
+
if (endIndex === -1) {
|
|
241
|
+
console.warn(`Warning: Found start marker but no end marker in ${profilePath}`);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
// Remove the block (including markers and surrounding newlines)
|
|
245
|
+
const beforeBlock = profileContent.substring(0, startIndex);
|
|
246
|
+
const afterBlock = profileContent.substring(endIndex + endMarker.length);
|
|
247
|
+
// Clean up extra newlines
|
|
248
|
+
const newContent = (beforeBlock.trimEnd() + '\n' + afterBlock.trimStart()).trim() + '\n';
|
|
249
|
+
await this.writeProfileFile(profilePath, newContent, fileEncoding, fileBom);
|
|
250
|
+
anyRemoved = true;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
console.warn(`Warning: Could not clean ${profilePath}: ${error}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return anyRemoved;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Install the completion script
|
|
260
|
+
*
|
|
261
|
+
* @param completionScript - The completion script content to install
|
|
262
|
+
* @returns Installation result with status and instructions
|
|
263
|
+
*/
|
|
264
|
+
async install(completionScript) {
|
|
265
|
+
try {
|
|
266
|
+
const targetPath = this.getInstallationPath();
|
|
267
|
+
// Check if already installed with same content
|
|
268
|
+
let isUpdate = false;
|
|
269
|
+
try {
|
|
270
|
+
const existingContent = await fs.readFile(targetPath, 'utf-8');
|
|
271
|
+
if (existingContent === completionScript) {
|
|
272
|
+
// Already installed and up to date
|
|
273
|
+
return {
|
|
274
|
+
success: true,
|
|
275
|
+
installedPath: targetPath,
|
|
276
|
+
message: 'Completion script is already installed (up to date)',
|
|
277
|
+
instructions: [
|
|
278
|
+
'The completion script is already installed and up to date.',
|
|
279
|
+
'If completions are not working, try restarting PowerShell or run: . $PROFILE',
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// File exists but content is different - this is an update
|
|
284
|
+
isUpdate = true;
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
// File doesn't exist or can't be read, proceed with installation
|
|
288
|
+
console.debug(`Unable to read existing completion file at ${targetPath}: ${error.message}`);
|
|
289
|
+
}
|
|
290
|
+
// Ensure the directory exists
|
|
291
|
+
const targetDir = path.dirname(targetPath);
|
|
292
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
293
|
+
// Backup existing file if updating
|
|
294
|
+
const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
|
|
295
|
+
// Write the completion script
|
|
296
|
+
await fs.writeFile(targetPath, completionScript, 'utf-8');
|
|
297
|
+
// Auto-configure PowerShell profile
|
|
298
|
+
const profileConfigured = await this.configureProfile(targetPath);
|
|
299
|
+
// Generate instructions if profile wasn't auto-configured
|
|
300
|
+
const instructions = profileConfigured ? undefined : this.generateInstructions(targetPath);
|
|
301
|
+
// Determine appropriate message
|
|
302
|
+
let message;
|
|
303
|
+
if (isUpdate) {
|
|
304
|
+
message = backupPath
|
|
305
|
+
? 'Completion script updated successfully (previous version backed up)'
|
|
306
|
+
: 'Completion script updated successfully';
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
message = profileConfigured
|
|
310
|
+
? 'Completion script installed and PowerShell profile configured successfully'
|
|
311
|
+
: 'Completion script installed successfully for PowerShell';
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
success: true,
|
|
315
|
+
installedPath: targetPath,
|
|
316
|
+
backupPath,
|
|
317
|
+
profileConfigured,
|
|
318
|
+
message,
|
|
319
|
+
instructions,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
return {
|
|
324
|
+
success: false,
|
|
325
|
+
message: `Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Generate user instructions for enabling completions
|
|
331
|
+
*
|
|
332
|
+
* @param installedPath - Path where the script was installed
|
|
333
|
+
* @returns Array of instruction strings
|
|
334
|
+
*/
|
|
335
|
+
generateInstructions(installedPath) {
|
|
336
|
+
const profilePath = this.getProfilePath();
|
|
337
|
+
return [
|
|
338
|
+
'Completion script installed successfully.',
|
|
339
|
+
'',
|
|
340
|
+
`To enable completions, add the following to your PowerShell profile (${profilePath}):`,
|
|
341
|
+
'',
|
|
342
|
+
' # Source synarcx completions',
|
|
343
|
+
` if (Test-Path "${installedPath}") {`,
|
|
344
|
+
` . "${installedPath}"`,
|
|
345
|
+
' }',
|
|
346
|
+
'',
|
|
347
|
+
'Then restart PowerShell or run: . $PROFILE',
|
|
348
|
+
];
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Uninstall the completion script
|
|
352
|
+
*
|
|
353
|
+
* @param options - Optional uninstall options
|
|
354
|
+
* @param options.yes - Skip confirmation prompt (handled by command layer)
|
|
355
|
+
* @returns Uninstallation result
|
|
356
|
+
*/
|
|
357
|
+
async uninstall(options) {
|
|
358
|
+
try {
|
|
359
|
+
const targetPath = this.getInstallationPath();
|
|
360
|
+
// Check if installed
|
|
361
|
+
try {
|
|
362
|
+
await fs.access(targetPath);
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return {
|
|
366
|
+
success: false,
|
|
367
|
+
message: 'Completion script is not installed',
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
// Remove the completion script
|
|
371
|
+
await fs.unlink(targetPath);
|
|
372
|
+
// Remove profile configuration
|
|
373
|
+
await this.removeProfileConfig();
|
|
374
|
+
return {
|
|
375
|
+
success: true,
|
|
376
|
+
message: 'Completion script uninstalled successfully',
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
return {
|
|
381
|
+
success: false,
|
|
382
|
+
message: `Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=powershell-installer.js.map
|