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.
Files changed (288) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +90 -0
  3. package/bin/synarcx.js +3 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +474 -0
  6. package/dist/commands/change.d.ts +35 -0
  7. package/dist/commands/change.js +278 -0
  8. package/dist/commands/completion.d.ts +72 -0
  9. package/dist/commands/completion.js +264 -0
  10. package/dist/commands/config.d.ts +36 -0
  11. package/dist/commands/config.js +552 -0
  12. package/dist/commands/feedback.d.ts +9 -0
  13. package/dist/commands/feedback.js +170 -0
  14. package/dist/commands/schema.d.ts +6 -0
  15. package/dist/commands/schema.js +870 -0
  16. package/dist/commands/show.d.ts +14 -0
  17. package/dist/commands/show.js +132 -0
  18. package/dist/commands/spec.d.ts +15 -0
  19. package/dist/commands/spec.js +226 -0
  20. package/dist/commands/validate.d.ts +24 -0
  21. package/dist/commands/validate.js +295 -0
  22. package/dist/commands/workflow/index.d.ts +17 -0
  23. package/dist/commands/workflow/index.js +12 -0
  24. package/dist/commands/workflow/instructions.d.ts +29 -0
  25. package/dist/commands/workflow/instructions.js +327 -0
  26. package/dist/commands/workflow/new-change.d.ts +11 -0
  27. package/dist/commands/workflow/new-change.js +45 -0
  28. package/dist/commands/workflow/schemas.d.ts +10 -0
  29. package/dist/commands/workflow/schemas.js +34 -0
  30. package/dist/commands/workflow/shared.d.ts +57 -0
  31. package/dist/commands/workflow/shared.js +117 -0
  32. package/dist/commands/workflow/status.d.ts +14 -0
  33. package/dist/commands/workflow/status.js +75 -0
  34. package/dist/commands/workflow/templates.d.ts +16 -0
  35. package/dist/commands/workflow/templates.js +69 -0
  36. package/dist/commands/workspace/open.d.ts +29 -0
  37. package/dist/commands/workspace/open.js +84 -0
  38. package/dist/commands/workspace/operations.d.ts +18 -0
  39. package/dist/commands/workspace/operations.js +461 -0
  40. package/dist/commands/workspace/selection.d.ts +5 -0
  41. package/dist/commands/workspace/selection.js +90 -0
  42. package/dist/commands/workspace/types.d.ts +83 -0
  43. package/dist/commands/workspace/types.js +36 -0
  44. package/dist/commands/workspace.d.ts +3 -0
  45. package/dist/commands/workspace.js +635 -0
  46. package/dist/core/archive.d.ts +11 -0
  47. package/dist/core/archive.js +319 -0
  48. package/dist/core/artifact-graph/graph.d.ts +56 -0
  49. package/dist/core/artifact-graph/graph.js +141 -0
  50. package/dist/core/artifact-graph/index.d.ts +8 -0
  51. package/dist/core/artifact-graph/index.js +14 -0
  52. package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
  53. package/dist/core/artifact-graph/instruction-loader.js +217 -0
  54. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  55. package/dist/core/artifact-graph/outputs.js +39 -0
  56. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  57. package/dist/core/artifact-graph/resolver.js +258 -0
  58. package/dist/core/artifact-graph/schema.d.ts +13 -0
  59. package/dist/core/artifact-graph/schema.js +108 -0
  60. package/dist/core/artifact-graph/state.d.ts +12 -0
  61. package/dist/core/artifact-graph/state.js +31 -0
  62. package/dist/core/artifact-graph/types.d.ts +45 -0
  63. package/dist/core/artifact-graph/types.js +43 -0
  64. package/dist/core/available-tools.d.ts +17 -0
  65. package/dist/core/available-tools.js +43 -0
  66. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  67. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  68. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  69. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  70. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  71. package/dist/core/command-generation/adapters/auggie.js +27 -0
  72. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  73. package/dist/core/command-generation/adapters/bob.js +45 -0
  74. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  75. package/dist/core/command-generation/adapters/claude.js +50 -0
  76. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  77. package/dist/core/command-generation/adapters/cline.js +27 -0
  78. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  79. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  80. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  81. package/dist/core/command-generation/adapters/codex.js +39 -0
  82. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  83. package/dist/core/command-generation/adapters/continue.js +28 -0
  84. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  85. package/dist/core/command-generation/adapters/costrict.js +27 -0
  86. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/crush.js +30 -0
  88. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  89. package/dist/core/command-generation/adapters/cursor.js +44 -0
  90. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  91. package/dist/core/command-generation/adapters/factory.js +27 -0
  92. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  93. package/dist/core/command-generation/adapters/gemini.js +26 -0
  94. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  95. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  96. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  97. package/dist/core/command-generation/adapters/iflow.js +29 -0
  98. package/dist/core/command-generation/adapters/index.d.ts +32 -0
  99. package/dist/core/command-generation/adapters/index.js +32 -0
  100. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  101. package/dist/core/command-generation/adapters/junie.js +26 -0
  102. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  103. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  104. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  105. package/dist/core/command-generation/adapters/kiro.js +26 -0
  106. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  107. package/dist/core/command-generation/adapters/lingma.js +30 -0
  108. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  109. package/dist/core/command-generation/adapters/opencode.js +27 -0
  110. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  111. package/dist/core/command-generation/adapters/pi.js +55 -0
  112. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/qoder.js +30 -0
  114. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  115. package/dist/core/command-generation/adapters/qwen.js +26 -0
  116. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  117. package/dist/core/command-generation/adapters/roocode.js +27 -0
  118. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  119. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  120. package/dist/core/command-generation/generator.d.ts +21 -0
  121. package/dist/core/command-generation/generator.js +27 -0
  122. package/dist/core/command-generation/index.d.ts +22 -0
  123. package/dist/core/command-generation/index.js +24 -0
  124. package/dist/core/command-generation/registry.d.ts +36 -0
  125. package/dist/core/command-generation/registry.js +98 -0
  126. package/dist/core/command-generation/types.d.ts +56 -0
  127. package/dist/core/command-generation/types.js +8 -0
  128. package/dist/core/completions/command-registry.d.ts +7 -0
  129. package/dist/core/completions/command-registry.js +596 -0
  130. package/dist/core/completions/completion-provider.d.ts +71 -0
  131. package/dist/core/completions/completion-provider.js +129 -0
  132. package/dist/core/completions/factory.d.ts +64 -0
  133. package/dist/core/completions/factory.js +75 -0
  134. package/dist/core/completions/generators/bash-generator.d.ts +35 -0
  135. package/dist/core/completions/generators/bash-generator.js +230 -0
  136. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  137. package/dist/core/completions/generators/fish-generator.js +160 -0
  138. package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
  139. package/dist/core/completions/generators/powershell-generator.js +266 -0
  140. package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
  141. package/dist/core/completions/generators/zsh-generator.js +274 -0
  142. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  143. package/dist/core/completions/installers/bash-installer.js +318 -0
  144. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  145. package/dist/core/completions/installers/fish-installer.js +143 -0
  146. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  147. package/dist/core/completions/installers/powershell-installer.js +387 -0
  148. package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
  149. package/dist/core/completions/installers/zsh-installer.js +421 -0
  150. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  151. package/dist/core/completions/templates/bash-templates.js +30 -0
  152. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  153. package/dist/core/completions/templates/fish-templates.js +45 -0
  154. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  155. package/dist/core/completions/templates/powershell-templates.js +34 -0
  156. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  157. package/dist/core/completions/templates/zsh-templates.js +45 -0
  158. package/dist/core/completions/types.d.ts +101 -0
  159. package/dist/core/completions/types.js +2 -0
  160. package/dist/core/config-prompts.d.ts +9 -0
  161. package/dist/core/config-prompts.js +34 -0
  162. package/dist/core/config-schema.d.ts +86 -0
  163. package/dist/core/config-schema.js +213 -0
  164. package/dist/core/config.d.ts +19 -0
  165. package/dist/core/config.js +38 -0
  166. package/dist/core/converters/json-converter.d.ts +6 -0
  167. package/dist/core/converters/json-converter.js +51 -0
  168. package/dist/core/global-config.d.ts +49 -0
  169. package/dist/core/global-config.js +124 -0
  170. package/dist/core/index.d.ts +3 -0
  171. package/dist/core/index.js +4 -0
  172. package/dist/core/init.d.ts +37 -0
  173. package/dist/core/init.js +585 -0
  174. package/dist/core/legacy-cleanup.d.ts +169 -0
  175. package/dist/core/legacy-cleanup.js +578 -0
  176. package/dist/core/list.d.ts +9 -0
  177. package/dist/core/list.js +172 -0
  178. package/dist/core/migration.d.ts +23 -0
  179. package/dist/core/migration.js +108 -0
  180. package/dist/core/parsers/change-parser.d.ts +13 -0
  181. package/dist/core/parsers/change-parser.js +197 -0
  182. package/dist/core/parsers/markdown-parser.d.ts +26 -0
  183. package/dist/core/parsers/markdown-parser.js +227 -0
  184. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  185. package/dist/core/parsers/requirement-blocks.js +201 -0
  186. package/dist/core/parsers/spec-structure.d.ts +9 -0
  187. package/dist/core/parsers/spec-structure.js +88 -0
  188. package/dist/core/profile-sync-drift.d.ts +38 -0
  189. package/dist/core/profile-sync-drift.js +197 -0
  190. package/dist/core/profiles.d.ts +26 -0
  191. package/dist/core/profiles.js +37 -0
  192. package/dist/core/project-config.d.ts +64 -0
  193. package/dist/core/project-config.js +224 -0
  194. package/dist/core/schemas/base.schema.d.ts +13 -0
  195. package/dist/core/schemas/base.schema.js +13 -0
  196. package/dist/core/schemas/change.schema.d.ts +73 -0
  197. package/dist/core/schemas/change.schema.js +31 -0
  198. package/dist/core/schemas/index.d.ts +4 -0
  199. package/dist/core/schemas/index.js +4 -0
  200. package/dist/core/schemas/spec.schema.d.ts +18 -0
  201. package/dist/core/schemas/spec.schema.js +15 -0
  202. package/dist/core/shared/index.d.ts +8 -0
  203. package/dist/core/shared/index.js +8 -0
  204. package/dist/core/shared/skill-generation.d.ts +49 -0
  205. package/dist/core/shared/skill-generation.js +90 -0
  206. package/dist/core/shared/tool-detection.d.ts +71 -0
  207. package/dist/core/shared/tool-detection.js +152 -0
  208. package/dist/core/specs-apply.d.ts +73 -0
  209. package/dist/core/specs-apply.js +393 -0
  210. package/dist/core/styles/palette.d.ts +7 -0
  211. package/dist/core/styles/palette.js +8 -0
  212. package/dist/core/templates/index.d.ts +8 -0
  213. package/dist/core/templates/index.js +9 -0
  214. package/dist/core/templates/skill-templates.d.ts +15 -0
  215. package/dist/core/templates/skill-templates.js +14 -0
  216. package/dist/core/templates/types.d.ts +19 -0
  217. package/dist/core/templates/types.js +5 -0
  218. package/dist/core/templates/workflows/analyze.d.ts +4 -0
  219. package/dist/core/templates/workflows/analyze.js +101 -0
  220. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  221. package/dist/core/templates/workflows/apply-change.js +308 -0
  222. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  223. package/dist/core/templates/workflows/archive-change.js +271 -0
  224. package/dist/core/templates/workflows/clarify.d.ts +4 -0
  225. package/dist/core/templates/workflows/clarify.js +108 -0
  226. package/dist/core/templates/workflows/debug.d.ts +4 -0
  227. package/dist/core/templates/workflows/debug.js +117 -0
  228. package/dist/core/templates/workflows/explore.d.ts +10 -0
  229. package/dist/core/templates/workflows/explore.js +479 -0
  230. package/dist/core/templates/workflows/propose.d.ts +10 -0
  231. package/dist/core/templates/workflows/propose.js +216 -0
  232. package/dist/core/templates/workflows/sync.d.ts +4 -0
  233. package/dist/core/templates/workflows/sync.js +108 -0
  234. package/dist/core/update.d.ts +82 -0
  235. package/dist/core/update.js +555 -0
  236. package/dist/core/validation/constants.d.ts +34 -0
  237. package/dist/core/validation/constants.js +40 -0
  238. package/dist/core/validation/types.d.ts +18 -0
  239. package/dist/core/validation/types.js +2 -0
  240. package/dist/core/validation/validator.d.ts +33 -0
  241. package/dist/core/validation/validator.js +418 -0
  242. package/dist/core/view.d.ts +8 -0
  243. package/dist/core/view.js +169 -0
  244. package/dist/core/workspace/foundation.d.ts +79 -0
  245. package/dist/core/workspace/foundation.js +367 -0
  246. package/dist/core/workspace/index.d.ts +5 -0
  247. package/dist/core/workspace/index.js +5 -0
  248. package/dist/core/workspace/link-input.d.ts +9 -0
  249. package/dist/core/workspace/link-input.js +32 -0
  250. package/dist/core/workspace/open-surface.d.ts +24 -0
  251. package/dist/core/workspace/open-surface.js +137 -0
  252. package/dist/core/workspace/openers.d.ts +21 -0
  253. package/dist/core/workspace/openers.js +119 -0
  254. package/dist/index.d.ts +3 -0
  255. package/dist/index.js +3 -0
  256. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  257. package/dist/prompts/searchable-multi-select.js +159 -0
  258. package/dist/ui/ascii-patterns.d.ts +25 -0
  259. package/dist/ui/ascii-patterns.js +140 -0
  260. package/dist/ui/welcome-screen.d.ts +10 -0
  261. package/dist/ui/welcome-screen.js +144 -0
  262. package/dist/utils/change-metadata.d.ts +51 -0
  263. package/dist/utils/change-metadata.js +147 -0
  264. package/dist/utils/change-utils.d.ts +62 -0
  265. package/dist/utils/change-utils.js +122 -0
  266. package/dist/utils/command-references.d.ts +18 -0
  267. package/dist/utils/command-references.js +20 -0
  268. package/dist/utils/file-system.d.ts +41 -0
  269. package/dist/utils/file-system.js +301 -0
  270. package/dist/utils/index.d.ts +6 -0
  271. package/dist/utils/index.js +9 -0
  272. package/dist/utils/interactive.d.ts +18 -0
  273. package/dist/utils/interactive.js +21 -0
  274. package/dist/utils/item-discovery.d.ts +4 -0
  275. package/dist/utils/item-discovery.js +73 -0
  276. package/dist/utils/match.d.ts +3 -0
  277. package/dist/utils/match.js +22 -0
  278. package/dist/utils/shell-detection.d.ts +20 -0
  279. package/dist/utils/shell-detection.js +41 -0
  280. package/dist/utils/task-progress.d.ts +8 -0
  281. package/dist/utils/task-progress.js +36 -0
  282. package/package.json +76 -0
  283. package/schemas/synarcx/schema.yaml +153 -0
  284. package/schemas/synarcx/templates/design.md +19 -0
  285. package/schemas/synarcx/templates/proposal.md +23 -0
  286. package/schemas/synarcx/templates/spec.md +8 -0
  287. package/schemas/synarcx/templates/tasks.md +9 -0
  288. 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