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,274 @@
1
+ import { ZSH_DYNAMIC_HELPERS } from '../templates/zsh-templates.js';
2
+ /**
3
+ * Generates Zsh completion scripts for the synarcx CLI.
4
+ * Follows Zsh completion system conventions using the _synarcx function.
5
+ */
6
+ export class ZshGenerator {
7
+ shell = 'zsh';
8
+ /**
9
+ * Generate a Zsh completion script
10
+ *
11
+ * @param commands - Command definitions to generate completions for
12
+ * @returns Zsh completion script as a string
13
+ */
14
+ generate(commands) {
15
+ // Build command list using push() for loop clarity
16
+ const commandLines = [];
17
+ for (const cmd of commands) {
18
+ const escapedDesc = this.escapeDescription(cmd.description);
19
+ commandLines.push(` '${cmd.name}:${escapedDesc}'`);
20
+ }
21
+ const commandList = commandLines.join('\n');
22
+ // Build command cases using push() for loop clarity
23
+ const commandCaseLines = [];
24
+ for (const cmd of commands) {
25
+ commandCaseLines.push(` ${cmd.name})`);
26
+ commandCaseLines.push(` _synarcx_${this.sanitizeFunctionName(cmd.name)}`);
27
+ commandCaseLines.push(' ;;');
28
+ }
29
+ const commandCases = commandCaseLines.join('\n');
30
+ // Build command functions using push() for loop clarity
31
+ const commandFunctionLines = [];
32
+ for (const cmd of commands) {
33
+ commandFunctionLines.push(...this.generateCommandFunction(cmd));
34
+ commandFunctionLines.push('');
35
+ }
36
+ const commandFunctions = commandFunctionLines.join('\n');
37
+ // Dynamic completion helpers from template
38
+ const helpers = ZSH_DYNAMIC_HELPERS;
39
+ // Assemble final script with template literal
40
+ return `#compdef synarcx
41
+
42
+ # Zsh completion script for synarcx CLI
43
+ # Auto-generated - do not edit manually
44
+
45
+ _synarcx() {
46
+ local context state line
47
+ typeset -A opt_args
48
+
49
+ local -a commands
50
+ commands=(
51
+ ${commandList}
52
+ )
53
+
54
+ _arguments -C \\
55
+ "1: :->command" \\
56
+ "*::arg:->args"
57
+
58
+ case $state in
59
+ command)
60
+ _describe "synarcx command" commands
61
+ ;;
62
+ args)
63
+ case $words[1] in
64
+ ${commandCases}
65
+ esac
66
+ ;;
67
+ esac
68
+ }
69
+
70
+ ${commandFunctions}
71
+ ${helpers}
72
+ compdef _synarcx synarcx
73
+ `;
74
+ }
75
+ /**
76
+ * Generate completion function for a specific command
77
+ */
78
+ generateCommandFunction(cmd) {
79
+ const funcName = `_synarcx_${this.sanitizeFunctionName(cmd.name)}`;
80
+ const lines = [];
81
+ lines.push(`${funcName}() {`);
82
+ // If command has subcommands, handle them
83
+ if (cmd.subcommands && cmd.subcommands.length > 0) {
84
+ lines.push(' local context state line');
85
+ lines.push(' typeset -A opt_args');
86
+ lines.push('');
87
+ lines.push(' local -a subcommands');
88
+ lines.push(' subcommands=(');
89
+ for (const subcmd of cmd.subcommands) {
90
+ const escapedDesc = this.escapeDescription(subcmd.description);
91
+ lines.push(` '${subcmd.name}:${escapedDesc}'`);
92
+ }
93
+ lines.push(' )');
94
+ lines.push('');
95
+ lines.push(' _arguments -C \\');
96
+ // Add command flags
97
+ for (const flag of cmd.flags) {
98
+ lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
99
+ }
100
+ lines.push(' "1: :->subcommand" \\');
101
+ lines.push(' "*::arg:->args"');
102
+ lines.push('');
103
+ lines.push(' case $state in');
104
+ lines.push(' subcommand)');
105
+ lines.push(' _describe "subcommand" subcommands');
106
+ lines.push(' ;;');
107
+ lines.push(' args)');
108
+ lines.push(' case $words[1] in');
109
+ for (const subcmd of cmd.subcommands) {
110
+ lines.push(` ${subcmd.name})`);
111
+ lines.push(` _synarcx_${this.sanitizeFunctionName(cmd.name)}_${this.sanitizeFunctionName(subcmd.name)}`);
112
+ lines.push(' ;;');
113
+ }
114
+ lines.push(' esac');
115
+ lines.push(' ;;');
116
+ lines.push(' esac');
117
+ }
118
+ else {
119
+ // Command without subcommands
120
+ lines.push(' _arguments \\');
121
+ // Add flags
122
+ for (const flag of cmd.flags) {
123
+ lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
124
+ }
125
+ this.appendPositionalSpecs(lines, cmd);
126
+ }
127
+ lines.push('}');
128
+ // Generate subcommand functions if they exist
129
+ if (cmd.subcommands) {
130
+ for (const subcmd of cmd.subcommands) {
131
+ lines.push('');
132
+ lines.push(...this.generateSubcommandFunction(cmd.name, subcmd));
133
+ }
134
+ }
135
+ return lines;
136
+ }
137
+ /**
138
+ * Generate completion function for a subcommand
139
+ */
140
+ generateSubcommandFunction(parentName, subcmd) {
141
+ const funcName = `_synarcx_${this.sanitizeFunctionName(parentName)}_${this.sanitizeFunctionName(subcmd.name)}`;
142
+ const lines = [];
143
+ lines.push(`${funcName}() {`);
144
+ lines.push(' _arguments \\');
145
+ // Add flags
146
+ for (const flag of subcmd.flags) {
147
+ lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
148
+ }
149
+ this.appendPositionalSpecs(lines, subcmd);
150
+ lines.push('}');
151
+ return lines;
152
+ }
153
+ /**
154
+ * Generate flag specification for _arguments
155
+ */
156
+ generateFlagSpec(flag) {
157
+ const parts = [];
158
+ // Handle mutually exclusive short and long forms
159
+ if (flag.short) {
160
+ parts.push(`'(-${flag.short} --${flag.name})'{-${flag.short},--${flag.name}}'`);
161
+ }
162
+ else {
163
+ parts.push(`'--${flag.name}`);
164
+ }
165
+ // Add description
166
+ const escapedDesc = this.escapeDescription(flag.description);
167
+ parts.push(`[${escapedDesc}]`);
168
+ // Add value completion if flag takes a value
169
+ if (flag.takesValue) {
170
+ if (flag.values && flag.values.length > 0) {
171
+ // Provide specific value completions
172
+ const valueList = flag.values.map(v => this.escapeValue(v)).join(' ');
173
+ parts.push(`:value:(${valueList})`);
174
+ }
175
+ else {
176
+ // Generic value placeholder
177
+ parts.push(':value:');
178
+ }
179
+ }
180
+ // Close the quote (needed for both short and long forms)
181
+ parts.push("'");
182
+ return parts.join('');
183
+ }
184
+ /**
185
+ * Generate positional argument specification
186
+ */
187
+ generatePositionalSpec(positionalType) {
188
+ switch (positionalType) {
189
+ case 'change-id':
190
+ return "'*: :_synarcx_complete_changes'";
191
+ case 'spec-id':
192
+ return "'*: :_synarcx_complete_specs'";
193
+ case 'change-or-spec-id':
194
+ return "'*: :_synarcx_complete_items'";
195
+ case 'schema-name':
196
+ return "'*: :_synarcx_complete_schemas'";
197
+ case 'path':
198
+ return "'*:path:_files'";
199
+ case 'shell':
200
+ return "'*:shell:(zsh bash fish powershell)'";
201
+ default:
202
+ return "'*: :_default'";
203
+ }
204
+ }
205
+ appendPositionalSpecs(lines, cmd) {
206
+ const positionalSpecs = this.generatePositionalSpecs(cmd);
207
+ if (positionalSpecs.length === 0) {
208
+ if (lines[lines.length - 1].endsWith(' \\')) {
209
+ lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
210
+ }
211
+ return;
212
+ }
213
+ for (const [index, spec] of positionalSpecs.entries()) {
214
+ const suffix = index === positionalSpecs.length - 1 ? '' : ' \\';
215
+ lines.push(' ' + spec + suffix);
216
+ }
217
+ }
218
+ generatePositionalSpecs(cmd) {
219
+ if (cmd.positionals && cmd.positionals.length > 0) {
220
+ return cmd.positionals.map((positional, index) => this.generateIndexedPositionalSpec(positional, index + 1));
221
+ }
222
+ if (cmd.acceptsPositional) {
223
+ return [this.generatePositionalSpec(cmd.positionalType)];
224
+ }
225
+ return [];
226
+ }
227
+ generateIndexedPositionalSpec(positional, index) {
228
+ const name = this.escapeDescription(positional.name);
229
+ const separator = positional.optional ? '::' : ':';
230
+ switch (positional.type) {
231
+ case 'change-id':
232
+ return `'${index}${separator}${name}:_synarcx_complete_changes'`;
233
+ case 'spec-id':
234
+ return `'${index}${separator}${name}:_synarcx_complete_specs'`;
235
+ case 'change-or-spec-id':
236
+ return `'${index}${separator}${name}:_synarcx_complete_items'`;
237
+ case 'schema-name':
238
+ return `'${index}${separator}${name}:_synarcx_complete_schemas'`;
239
+ case 'path':
240
+ return `'${index}${separator}${name}:_files'`;
241
+ case 'shell':
242
+ return `'${index}${separator}${name}:(zsh bash fish powershell)'`;
243
+ default:
244
+ return `'${index}${separator}${name}:'`;
245
+ }
246
+ }
247
+ /**
248
+ * Escape special characters in descriptions
249
+ */
250
+ escapeDescription(desc) {
251
+ return desc
252
+ .replace(/\\/g, '\\\\')
253
+ .replace(/'/g, "\\'")
254
+ .replace(/\[/g, '\\[')
255
+ .replace(/]/g, '\\]')
256
+ .replace(/:/g, '\\:');
257
+ }
258
+ /**
259
+ * Escape special characters in values
260
+ */
261
+ escapeValue(value) {
262
+ return value
263
+ .replace(/\\/g, '\\\\')
264
+ .replace(/'/g, "\\'")
265
+ .replace(/ /g, '\\ ');
266
+ }
267
+ /**
268
+ * Sanitize command names for use in function names
269
+ */
270
+ sanitizeFunctionName(name) {
271
+ return name.replace(/-/g, '_');
272
+ }
273
+ }
274
+ //# sourceMappingURL=zsh-generator.js.map
@@ -0,0 +1,87 @@
1
+ import { InstallationResult } from '../factory.js';
2
+ /**
3
+ * Installer for Bash completion scripts.
4
+ * Supports bash-completion package and standalone installations.
5
+ */
6
+ export declare class BashInstaller {
7
+ private readonly homeDir;
8
+ /**
9
+ * Markers for .bashrc configuration management
10
+ */
11
+ private readonly BASHRC_MARKERS;
12
+ constructor(homeDir?: string);
13
+ /**
14
+ * Check if bash-completion is installed
15
+ *
16
+ * @returns true if bash-completion directories exist
17
+ */
18
+ isBashCompletionInstalled(): Promise<boolean>;
19
+ /**
20
+ * Get the appropriate installation path for the completion script
21
+ *
22
+ * @returns Installation path
23
+ */
24
+ getInstallationPath(): Promise<string>;
25
+ /**
26
+ * Backup an existing completion file if it exists
27
+ *
28
+ * @param targetPath - Path to the file to backup
29
+ * @returns Path to the backup file, or undefined if no backup was needed
30
+ */
31
+ backupExistingFile(targetPath: string): Promise<string | undefined>;
32
+ /**
33
+ * Get the path to .bashrc file
34
+ *
35
+ * @returns Path to .bashrc
36
+ */
37
+ private getBashrcPath;
38
+ /**
39
+ * Generate .bashrc configuration content
40
+ *
41
+ * @param completionsDir - Directory containing completion scripts
42
+ * @returns Configuration content
43
+ */
44
+ private generateBashrcConfig;
45
+ /**
46
+ * Configure .bashrc to enable completions
47
+ *
48
+ * @param completionsDir - Directory containing completion scripts
49
+ * @returns true if configured successfully, false otherwise
50
+ */
51
+ configureBashrc(completionsDir: string): Promise<boolean>;
52
+ /**
53
+ * Remove .bashrc configuration
54
+ * Used during uninstallation
55
+ *
56
+ * @returns true if removed successfully, false otherwise
57
+ */
58
+ removeBashrcConfig(): Promise<boolean>;
59
+ /**
60
+ * Install the completion script
61
+ *
62
+ * @param completionScript - The completion script content to install
63
+ * @returns Installation result with status and instructions
64
+ */
65
+ install(completionScript: string): Promise<InstallationResult>;
66
+ /**
67
+ * Generate user instructions for enabling completions
68
+ *
69
+ * @param installedPath - Path where the script was installed
70
+ * @returns Array of instruction strings
71
+ */
72
+ private generateInstructions;
73
+ /**
74
+ * Uninstall the completion script
75
+ *
76
+ * @param options - Optional uninstall options
77
+ * @param options.yes - Skip confirmation prompt (handled by command layer)
78
+ * @returns Uninstallation result
79
+ */
80
+ uninstall(options?: {
81
+ yes?: boolean;
82
+ }): Promise<{
83
+ success: boolean;
84
+ message: string;
85
+ }>;
86
+ }
87
+ //# sourceMappingURL=bash-installer.d.ts.map
@@ -0,0 +1,318 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { FileSystemUtils } from '../../../utils/file-system.js';
5
+ /**
6
+ * Installer for Bash completion scripts.
7
+ * Supports bash-completion package and standalone installations.
8
+ */
9
+ export class BashInstaller {
10
+ homeDir;
11
+ /**
12
+ * Markers for .bashrc configuration management
13
+ */
14
+ BASHRC_MARKERS = {
15
+ start: '# OPENSPEC:START',
16
+ end: '# OPENSPEC:END',
17
+ };
18
+ constructor(homeDir = os.homedir()) {
19
+ this.homeDir = homeDir;
20
+ }
21
+ /**
22
+ * Check if bash-completion is installed
23
+ *
24
+ * @returns true if bash-completion directories exist
25
+ */
26
+ async isBashCompletionInstalled() {
27
+ const paths = [
28
+ '/usr/share/bash-completion', // Linux system-wide
29
+ '/usr/local/share/bash-completion', // Homebrew Intel (main)
30
+ '/opt/homebrew/etc/bash_completion.d', // Homebrew Apple Silicon
31
+ '/usr/local/etc/bash_completion.d', // Homebrew Intel (alt path)
32
+ '/etc/bash_completion.d', // Legacy fallback
33
+ ];
34
+ for (const p of paths) {
35
+ try {
36
+ const stat = await fs.stat(p);
37
+ if (stat.isDirectory()) {
38
+ return true;
39
+ }
40
+ }
41
+ catch {
42
+ // Continue checking other paths
43
+ }
44
+ }
45
+ return false;
46
+ }
47
+ /**
48
+ * Get the appropriate installation path for the completion script
49
+ *
50
+ * @returns Installation path
51
+ */
52
+ async getInstallationPath() {
53
+ // Try user-local bash-completion directory first
54
+ const localCompletionDir = path.join(this.homeDir, '.local', 'share', 'bash-completion', 'completions');
55
+ // For user installation, use local directory
56
+ return path.join(localCompletionDir, 'synarcx');
57
+ }
58
+ /**
59
+ * Backup an existing completion file if it exists
60
+ *
61
+ * @param targetPath - Path to the file to backup
62
+ * @returns Path to the backup file, or undefined if no backup was needed
63
+ */
64
+ async backupExistingFile(targetPath) {
65
+ try {
66
+ await fs.access(targetPath);
67
+ // File exists, create a backup
68
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
69
+ const backupPath = `${targetPath}.backup-${timestamp}`;
70
+ await fs.copyFile(targetPath, backupPath);
71
+ return backupPath;
72
+ }
73
+ catch {
74
+ // File doesn't exist, no backup needed
75
+ return undefined;
76
+ }
77
+ }
78
+ /**
79
+ * Get the path to .bashrc file
80
+ *
81
+ * @returns Path to .bashrc
82
+ */
83
+ getBashrcPath() {
84
+ return path.join(this.homeDir, '.bashrc');
85
+ }
86
+ /**
87
+ * Generate .bashrc configuration content
88
+ *
89
+ * @param completionsDir - Directory containing completion scripts
90
+ * @returns Configuration content
91
+ */
92
+ generateBashrcConfig(completionsDir) {
93
+ return [
94
+ '# synarcx shell completions configuration',
95
+ `if [ -d "${completionsDir}" ]; then`,
96
+ ` for f in "${completionsDir}"/*; do`,
97
+ ' [ -f "$f" ] && . "$f"',
98
+ ' done',
99
+ 'fi',
100
+ ].join('\n');
101
+ }
102
+ /**
103
+ * Configure .bashrc to enable completions
104
+ *
105
+ * @param completionsDir - Directory containing completion scripts
106
+ * @returns true if configured successfully, false otherwise
107
+ */
108
+ async configureBashrc(completionsDir) {
109
+ // Check if auto-configuration is disabled
110
+ if (process.env.OPENSPEC_NO_AUTO_CONFIG === '1') {
111
+ return false;
112
+ }
113
+ try {
114
+ const bashrcPath = this.getBashrcPath();
115
+ const config = this.generateBashrcConfig(completionsDir);
116
+ // Check write permissions
117
+ const canWrite = await FileSystemUtils.canWriteFile(bashrcPath);
118
+ if (!canWrite) {
119
+ return false;
120
+ }
121
+ // Use marker-based update
122
+ await FileSystemUtils.updateFileWithMarkers(bashrcPath, config, this.BASHRC_MARKERS.start, this.BASHRC_MARKERS.end);
123
+ return true;
124
+ }
125
+ catch (error) {
126
+ // Fail gracefully - don't break installation
127
+ console.debug(`Unable to configure .bashrc for completions: ${error.message}`);
128
+ return false;
129
+ }
130
+ }
131
+ /**
132
+ * Remove .bashrc configuration
133
+ * Used during uninstallation
134
+ *
135
+ * @returns true if removed successfully, false otherwise
136
+ */
137
+ async removeBashrcConfig() {
138
+ try {
139
+ const bashrcPath = this.getBashrcPath();
140
+ // Check if file exists
141
+ try {
142
+ await fs.access(bashrcPath);
143
+ }
144
+ catch {
145
+ // File doesn't exist, nothing to remove
146
+ return true;
147
+ }
148
+ // Read file content
149
+ const content = await fs.readFile(bashrcPath, 'utf-8');
150
+ // Check if markers exist
151
+ if (!content.includes(this.BASHRC_MARKERS.start) || !content.includes(this.BASHRC_MARKERS.end)) {
152
+ // Markers don't exist, nothing to remove
153
+ return true;
154
+ }
155
+ // Remove content between markers (including markers)
156
+ const lines = content.split('\n');
157
+ const startIndex = lines.findIndex((line) => line.trim() === this.BASHRC_MARKERS.start);
158
+ const endIndex = lines.findIndex((line) => line.trim() === this.BASHRC_MARKERS.end);
159
+ if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
160
+ // Invalid marker placement
161
+ return false;
162
+ }
163
+ // Remove lines between markers (inclusive)
164
+ lines.splice(startIndex, endIndex - startIndex + 1);
165
+ // Remove trailing empty lines
166
+ while (lines.length > 0 && lines[lines.length - 1].trim() === '') {
167
+ lines.pop();
168
+ }
169
+ // Write back
170
+ await fs.writeFile(bashrcPath, lines.join('\n'), 'utf-8');
171
+ return true;
172
+ }
173
+ catch (error) {
174
+ // Fail gracefully
175
+ console.debug(`Unable to remove .bashrc configuration: ${error.message}`);
176
+ return false;
177
+ }
178
+ }
179
+ /**
180
+ * Install the completion script
181
+ *
182
+ * @param completionScript - The completion script content to install
183
+ * @returns Installation result with status and instructions
184
+ */
185
+ async install(completionScript) {
186
+ try {
187
+ const targetPath = await this.getInstallationPath();
188
+ // Check for bash-completion package
189
+ const hasBashCompletion = await this.isBashCompletionInstalled();
190
+ // Check if already installed with same content
191
+ let isUpdate = false;
192
+ try {
193
+ const existingContent = await fs.readFile(targetPath, 'utf-8');
194
+ if (existingContent === completionScript) {
195
+ // Already installed and up to date
196
+ return {
197
+ success: true,
198
+ installedPath: targetPath,
199
+ message: 'Completion script is already installed (up to date)',
200
+ instructions: [
201
+ 'The completion script is already installed and up to date.',
202
+ 'If completions are not working, try: exec bash',
203
+ ],
204
+ };
205
+ }
206
+ // File exists but content is different - this is an update
207
+ isUpdate = true;
208
+ }
209
+ catch (error) {
210
+ // File doesn't exist or can't be read, proceed with installation
211
+ console.debug(`Unable to read existing completion file at ${targetPath}: ${error.message}`);
212
+ }
213
+ // Ensure the directory exists
214
+ const targetDir = path.dirname(targetPath);
215
+ await fs.mkdir(targetDir, { recursive: true });
216
+ // Backup existing file if updating
217
+ const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
218
+ // Write the completion script
219
+ await fs.writeFile(targetPath, completionScript, 'utf-8');
220
+ // Auto-configure .bashrc
221
+ const bashrcConfigured = await this.configureBashrc(targetDir);
222
+ // Generate instructions if .bashrc wasn't auto-configured
223
+ const instructions = bashrcConfigured ? undefined : this.generateInstructions(targetPath);
224
+ // Collect warnings
225
+ const warnings = [];
226
+ if (!hasBashCompletion) {
227
+ warnings.push('⚠️ Warning: bash-completion package not detected', '', 'The completion script requires bash-completion to function.', 'Install it with:', ' brew install bash-completion@2', '', 'Then add to your ~/.bash_profile:', ' [[ -r "/opt/homebrew/etc/profile.d/bash_completion.sh" ]] && . "/opt/homebrew/etc/profile.d/bash_completion.sh"');
228
+ }
229
+ // Determine appropriate message
230
+ let message;
231
+ if (isUpdate) {
232
+ message = backupPath
233
+ ? 'Completion script updated successfully (previous version backed up)'
234
+ : 'Completion script updated successfully';
235
+ }
236
+ else {
237
+ message = bashrcConfigured
238
+ ? 'Completion script installed and .bashrc configured successfully'
239
+ : 'Completion script installed successfully for Bash';
240
+ }
241
+ return {
242
+ success: true,
243
+ installedPath: targetPath,
244
+ backupPath,
245
+ bashrcConfigured,
246
+ message,
247
+ instructions,
248
+ warnings: warnings.length > 0 ? warnings : undefined,
249
+ };
250
+ }
251
+ catch (error) {
252
+ return {
253
+ success: false,
254
+ message: `Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`,
255
+ };
256
+ }
257
+ }
258
+ /**
259
+ * Generate user instructions for enabling completions
260
+ *
261
+ * @param installedPath - Path where the script was installed
262
+ * @returns Array of instruction strings
263
+ */
264
+ generateInstructions(installedPath) {
265
+ const completionsDir = path.dirname(installedPath);
266
+ return [
267
+ 'Completion script installed successfully.',
268
+ '',
269
+ 'To enable completions, add the following to your ~/.bashrc file:',
270
+ '',
271
+ ` # Source synarcx completions`,
272
+ ` if [ -d "${completionsDir}" ]; then`,
273
+ ` for f in "${completionsDir}"/*; do`,
274
+ ' [ -f "$f" ] && . "$f"',
275
+ ' done',
276
+ ' fi',
277
+ '',
278
+ 'Then restart your shell or run: exec bash',
279
+ ];
280
+ }
281
+ /**
282
+ * Uninstall the completion script
283
+ *
284
+ * @param options - Optional uninstall options
285
+ * @param options.yes - Skip confirmation prompt (handled by command layer)
286
+ * @returns Uninstallation result
287
+ */
288
+ async uninstall(options) {
289
+ try {
290
+ const targetPath = await this.getInstallationPath();
291
+ // Check if installed
292
+ try {
293
+ await fs.access(targetPath);
294
+ }
295
+ catch {
296
+ return {
297
+ success: false,
298
+ message: 'Completion script is not installed',
299
+ };
300
+ }
301
+ // Remove the completion script
302
+ await fs.unlink(targetPath);
303
+ // Remove .bashrc configuration
304
+ await this.removeBashrcConfig();
305
+ return {
306
+ success: true,
307
+ message: 'Completion script uninstalled successfully',
308
+ };
309
+ }
310
+ catch (error) {
311
+ return {
312
+ success: false,
313
+ message: `Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`,
314
+ };
315
+ }
316
+ }
317
+ }
318
+ //# sourceMappingURL=bash-installer.js.map