@laitszkin/apollo-toolkit 4.1.3 → 5.0.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 (205) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/bin/apollo-toolkit.ts +4 -0
  3. package/dist/bin/apollo-toolkit.js +4 -0
  4. package/package.json +7 -2
  5. package/packages/cli/dist/help-text-builder.d.ts +23 -0
  6. package/packages/cli/dist/help-text-builder.js +166 -0
  7. package/packages/cli/dist/index.d.ts +6 -17
  8. package/packages/cli/dist/index.js +52 -246
  9. package/packages/cli/dist/installer.d.ts +1 -0
  10. package/packages/cli/dist/installer.js +20 -7
  11. package/packages/cli/dist/parsers/install-parser.d.ts +15 -0
  12. package/packages/cli/dist/parsers/install-parser.js +87 -0
  13. package/packages/cli/dist/parsers/parser-utils.d.ts +9 -0
  14. package/packages/cli/dist/parsers/parser-utils.js +16 -0
  15. package/packages/cli/dist/parsers/tool-parser.d.ts +16 -0
  16. package/packages/cli/dist/parsers/tool-parser.js +58 -0
  17. package/packages/cli/dist/parsers/types.d.ts +50 -0
  18. package/packages/cli/dist/parsers/types.js +1 -0
  19. package/packages/cli/dist/parsers/uninstall-parser.d.ts +15 -0
  20. package/packages/cli/dist/parsers/uninstall-parser.js +67 -0
  21. package/packages/cli/dist/tool-registration.d.ts +2 -0
  22. package/packages/cli/dist/tool-registration.js +2 -0
  23. package/packages/cli/dist/tsconfig.tsbuildinfo +1 -1
  24. package/packages/cli/dist/types.d.ts +3 -1
  25. package/packages/cli/dist/updater.js +11 -5
  26. package/packages/cli/help-text-builder.ts +180 -0
  27. package/packages/cli/index.ts +59 -251
  28. package/packages/cli/installer.ts +19 -7
  29. package/packages/cli/package.json +6 -3
  30. package/packages/cli/parsers/install-parser.ts +94 -0
  31. package/packages/cli/parsers/parser-utils.ts +17 -0
  32. package/packages/cli/parsers/tool-parser.ts +65 -0
  33. package/packages/cli/parsers/types.ts +56 -0
  34. package/packages/cli/parsers/uninstall-parser.ts +75 -0
  35. package/packages/cli/tool-registration.ts +3 -0
  36. package/packages/cli/types.ts +6 -1
  37. package/packages/cli/updater.ts +11 -5
  38. package/packages/tool-registry/dist/registry.js +3 -4
  39. package/packages/tool-registry/dist/tsconfig.tsbuildinfo +1 -1
  40. package/packages/tool-registry/dist/types.d.ts +2 -9
  41. package/packages/tool-registry/package.json +3 -3
  42. package/packages/tool-registry/registry.ts +3 -4
  43. package/packages/tool-registry/tsconfig.json +6 -2
  44. package/packages/tool-registry/types.ts +3 -9
  45. package/packages/tool-utils/app-error.ts +97 -0
  46. package/packages/tool-utils/dist/app-error.d.ts +49 -0
  47. package/packages/tool-utils/dist/app-error.js +80 -0
  48. package/packages/tool-utils/dist/index.d.ts +5 -0
  49. package/packages/tool-utils/dist/index.js +3 -0
  50. package/packages/tool-utils/dist/platform-adapter.d.ts +48 -0
  51. package/packages/tool-utils/dist/platform-adapter.js +73 -0
  52. package/packages/tool-utils/dist/schema.d.ts +68 -0
  53. package/packages/tool-utils/dist/schema.js +67 -0
  54. package/packages/tool-utils/dist/tsconfig.tsbuildinfo +1 -1
  55. package/packages/tool-utils/index.ts +12 -0
  56. package/packages/tool-utils/package.json +3 -3
  57. package/packages/tool-utils/platform-adapter.ts +112 -0
  58. package/packages/tool-utils/schema.ts +122 -0
  59. package/packages/tools/architecture/dist/index.d.ts +13 -0
  60. package/packages/tools/architecture/dist/index.js +55 -57
  61. package/packages/tools/architecture/dist/index.test.js +17 -4
  62. package/packages/tools/architecture/dist/tsconfig.tsbuildinfo +1 -1
  63. package/packages/tools/architecture/index.test.ts +27 -14
  64. package/packages/tools/architecture/index.ts +85 -88
  65. package/packages/tools/architecture/package.json +3 -3
  66. package/packages/tools/codegraph/dist/index.js +21 -17
  67. package/packages/tools/codegraph/dist/tsconfig.tsbuildinfo +1 -1
  68. package/packages/tools/codegraph/index.ts +21 -17
  69. package/packages/tools/codegraph/package.json +3 -3
  70. package/packages/tools/create-review-report/dist/index.d.ts +1 -2
  71. package/packages/tools/create-review-report/dist/index.js +46 -77
  72. package/packages/tools/create-review-report/dist/tsconfig.tsbuildinfo +1 -1
  73. package/packages/tools/create-review-report/index.ts +52 -81
  74. package/packages/tools/create-review-report/package.json +3 -3
  75. package/packages/tools/create-specs/dist/index.d.ts +1 -2
  76. package/packages/tools/create-specs/dist/index.js +70 -123
  77. package/packages/tools/create-specs/dist/tsconfig.tsbuildinfo +1 -1
  78. package/packages/tools/create-specs/index.ts +82 -128
  79. package/packages/tools/create-specs/package.json +3 -3
  80. package/packages/tools/docs-to-voice/dist/index.d.ts +1 -2
  81. package/packages/tools/docs-to-voice/dist/index.js +116 -219
  82. package/packages/tools/docs-to-voice/dist/tsconfig.tsbuildinfo +1 -1
  83. package/packages/tools/docs-to-voice/index.ts +265 -385
  84. package/packages/tools/docs-to-voice/package.json +3 -3
  85. package/packages/tools/enforce-video-aspect-ratio/dist/index.d.ts +1 -2
  86. package/packages/tools/enforce-video-aspect-ratio/dist/index.js +77 -154
  87. package/packages/tools/enforce-video-aspect-ratio/dist/tsconfig.tsbuildinfo +1 -1
  88. package/packages/tools/enforce-video-aspect-ratio/index.ts +87 -172
  89. package/packages/tools/enforce-video-aspect-ratio/package.json +3 -3
  90. package/packages/tools/eval/dist/index.js +7 -0
  91. package/packages/tools/eval/dist/tsconfig.tsbuildinfo +1 -1
  92. package/packages/tools/eval/index.ts +8 -0
  93. package/packages/tools/eval/package.json +3 -3
  94. package/packages/tools/extract-conversations/dist/index.d.ts +1 -2
  95. package/packages/tools/extract-conversations/dist/index.js +31 -29
  96. package/packages/tools/extract-conversations/dist/tsconfig.tsbuildinfo +1 -1
  97. package/packages/tools/extract-conversations/index.ts +37 -30
  98. package/packages/tools/extract-conversations/package.json +3 -3
  99. package/packages/tools/extract-pdf-text/dist/index.d.ts +1 -2
  100. package/packages/tools/extract-pdf-text/dist/index.js +44 -65
  101. package/packages/tools/extract-pdf-text/dist/tsconfig.tsbuildinfo +1 -1
  102. package/packages/tools/extract-pdf-text/index.ts +55 -74
  103. package/packages/tools/extract-pdf-text/package.json +3 -3
  104. package/packages/tools/filter-logs/dist/index.js +60 -84
  105. package/packages/tools/filter-logs/dist/tsconfig.tsbuildinfo +1 -1
  106. package/packages/tools/filter-logs/index.ts +67 -97
  107. package/packages/tools/filter-logs/package.json +3 -3
  108. package/packages/tools/find-github-issues/dist/index.d.ts +10 -0
  109. package/packages/tools/find-github-issues/dist/index.js +34 -5
  110. package/packages/tools/find-github-issues/dist/tsconfig.tsbuildinfo +1 -1
  111. package/packages/tools/find-github-issues/index.ts +37 -5
  112. package/packages/tools/find-github-issues/package.json +3 -3
  113. package/packages/tools/generate-storyboard-images/dist/index.d.ts +1 -2
  114. package/packages/tools/generate-storyboard-images/dist/index.js +98 -173
  115. package/packages/tools/generate-storyboard-images/dist/tsconfig.tsbuildinfo +1 -1
  116. package/packages/tools/generate-storyboard-images/index.ts +100 -188
  117. package/packages/tools/generate-storyboard-images/package.json +3 -3
  118. package/packages/tools/open-github-issue/dist/index.d.ts +13 -0
  119. package/packages/tools/open-github-issue/dist/index.js +67 -68
  120. package/packages/tools/open-github-issue/dist/tsconfig.tsbuildinfo +1 -1
  121. package/packages/tools/open-github-issue/index.ts +71 -72
  122. package/packages/tools/open-github-issue/package.json +3 -3
  123. package/packages/tools/read-github-issue/dist/index.d.ts +16 -1
  124. package/packages/tools/read-github-issue/dist/index.js +32 -40
  125. package/packages/tools/read-github-issue/dist/tsconfig.tsbuildinfo +1 -1
  126. package/packages/tools/read-github-issue/index.ts +32 -45
  127. package/packages/tools/read-github-issue/package.json +3 -3
  128. package/packages/tools/render-error-book/dist/index.d.ts +1 -2
  129. package/packages/tools/render-error-book/dist/index.js +74 -95
  130. package/packages/tools/render-error-book/dist/tsconfig.tsbuildinfo +1 -1
  131. package/packages/tools/render-error-book/index.ts +88 -103
  132. package/packages/tools/render-error-book/package.json +3 -3
  133. package/packages/tools/render-katex/dist/index.d.ts +1 -2
  134. package/packages/tools/render-katex/dist/index.js +70 -157
  135. package/packages/tools/render-katex/dist/tsconfig.tsbuildinfo +1 -1
  136. package/packages/tools/render-katex/index.ts +138 -222
  137. package/packages/tools/render-katex/package.json +3 -3
  138. package/packages/tools/review-threads/dist/index.d.ts +12 -0
  139. package/packages/tools/review-threads/dist/index.js +83 -86
  140. package/packages/tools/review-threads/dist/tsconfig.tsbuildinfo +1 -1
  141. package/packages/tools/review-threads/index.ts +90 -84
  142. package/packages/tools/review-threads/package.json +3 -3
  143. package/packages/tools/search-logs/dist/index.js +100 -136
  144. package/packages/tools/search-logs/dist/tsconfig.tsbuildinfo +1 -1
  145. package/packages/tools/search-logs/index.ts +113 -145
  146. package/packages/tools/search-logs/package.json +3 -3
  147. package/packages/tools/sync-memory-index/dist/index.js +34 -28
  148. package/packages/tools/sync-memory-index/dist/tsconfig.tsbuildinfo +1 -1
  149. package/packages/tools/sync-memory-index/index.ts +37 -28
  150. package/packages/tools/sync-memory-index/package.json +3 -3
  151. package/packages/tools/validate-openai-agent-config/dist/index.js +13 -7
  152. package/packages/tools/validate-openai-agent-config/dist/tsconfig.tsbuildinfo +1 -1
  153. package/packages/tools/validate-openai-agent-config/index.ts +13 -7
  154. package/packages/tools/validate-openai-agent-config/package.json +3 -3
  155. package/packages/tools/validate-skill-frontmatter/dist/index.js +12 -6
  156. package/packages/tools/validate-skill-frontmatter/dist/tsconfig.tsbuildinfo +1 -1
  157. package/packages/tools/validate-skill-frontmatter/index.ts +12 -6
  158. package/packages/tools/validate-skill-frontmatter/package.json +3 -3
  159. package/packages/tui/dist/index.d.ts +2 -1
  160. package/packages/tui/dist/index.js +1 -0
  161. package/packages/tui/dist/stdio-adapter.d.ts +36 -0
  162. package/packages/tui/dist/stdio-adapter.js +69 -0
  163. package/packages/tui/dist/terminal.js +3 -1
  164. package/packages/tui/dist/tsconfig.tsbuildinfo +1 -1
  165. package/packages/tui/dist/types.d.ts +17 -0
  166. package/packages/tui/index.ts +2 -1
  167. package/packages/tui/package.json +6 -5
  168. package/packages/tui/stdio-adapter.ts +85 -0
  169. package/packages/tui/terminal.ts +3 -1
  170. package/packages/tui/tsconfig.json +5 -2
  171. package/packages/tui/types.ts +19 -0
  172. package/resources/project-architecture/assets/architecture.css +2 -1
  173. package/resources/project-architecture/atlas/atlas.history.log +1 -0
  174. package/resources/project-architecture/atlas/atlas.history.undo.json +13 -2
  175. package/resources/project-architecture/atlas/atlas.history.undo.stack.json +610 -0
  176. package/resources/project-architecture/atlas/atlas.index.yaml +81 -5
  177. package/resources/project-architecture/atlas/features/cli-dispatch.yaml +43 -0
  178. package/resources/project-architecture/atlas/features/terminal-ui.yaml +29 -0
  179. package/resources/project-architecture/atlas/features/tool-registry.yaml +22 -0
  180. package/resources/project-architecture/atlas/features/tool-utils.yaml +22 -0
  181. package/resources/project-architecture/features/cli-dispatch/arg-parser.html +40 -0
  182. package/resources/project-architecture/features/cli-dispatch/help-builder.html +40 -0
  183. package/resources/project-architecture/features/cli-dispatch/index.html +64 -0
  184. package/resources/project-architecture/features/cli-dispatch/installer-core.html +40 -0
  185. package/resources/project-architecture/features/cli-dispatch/tool-discovery.html +40 -0
  186. package/resources/project-architecture/features/cli-dispatch/update-checker.html +40 -0
  187. package/resources/project-architecture/features/terminal-ui/banner-display.html +40 -0
  188. package/resources/project-architecture/features/terminal-ui/index.html +50 -0
  189. package/resources/project-architecture/features/terminal-ui/interactive-prompts.html +40 -0
  190. package/resources/project-architecture/features/terminal-ui/terminal-detection.html +40 -0
  191. package/resources/project-architecture/features/tool-registry/formatter.html +40 -0
  192. package/resources/project-architecture/features/tool-registry/index.html +43 -0
  193. package/resources/project-architecture/features/tool-registry/registry-core.html +40 -0
  194. package/resources/project-architecture/features/tool-utils/index.html +43 -0
  195. package/resources/project-architecture/features/tool-utils/log-utils.html +40 -0
  196. package/resources/project-architecture/features/tool-utils/skill-discovery.html +40 -0
  197. package/resources/project-architecture/index.html +365 -121
  198. package/scripts/rewrite-imports.mjs +2 -2
  199. package/scripts/test.sh +144 -8
  200. package/skills/design/SKILL.md +57 -64
  201. package/skills/design/assets/templates/DESIGN.md +12 -0
  202. package/skills/design/references/code-smells.md +94 -0
  203. package/skills/design/references/module-boundary-adjustment.md +126 -0
  204. package/skills/design/references/module-internal-restructuring.md +132 -0
  205. package/skills/design/references/module-internal-simplification.md +164 -0
@@ -0,0 +1,180 @@
1
+ import { buildBanner, buildSupportedTargetLines } from '@laitszkin/tui';
2
+ import { formatToolList, buildToolDiscoveryHelp, formatExamples } from '@laitszkin/tool-registry';
3
+ import { TARGET_DEFINITIONS, VALID_MODES } from './installer.js';
4
+
5
+ /**
6
+ * Produces the four help text sections previously generated by standalone
7
+ * functions. Each method returns text identical to the original builder so
8
+ * that observable CLI output is unchanged.
9
+ */
10
+ export class HelpTextBuilder {
11
+ private version: string;
12
+ private colorEnabled: boolean;
13
+
14
+ constructor({ version, colorEnabled }: { version: string; colorEnabled: boolean }) {
15
+ this.version = version;
16
+ this.colorEnabled = colorEnabled;
17
+ }
18
+
19
+ // ---- shared helpers -------------------------------------------------------
20
+
21
+ private modeUsagePattern(): string {
22
+ return `${VALID_MODES.join('|')}|all`;
23
+ }
24
+
25
+ private joinLines(lines: (string | undefined | null | false)[]): string {
26
+ return lines.filter(Boolean).join('\n');
27
+ }
28
+
29
+ // ---- public methods -------------------------------------------------------
30
+
31
+ /** Replaces buildHelpText – top-level overview help. */
32
+ overview(): string {
33
+ const examples = [
34
+ { command: 'apltk --help', result: 'Shows the top-level Apollo Toolkit guide, including install modes and bundled task-tool discovery.' },
35
+ { command: 'apltk tools --help', result: 'Lists bundled tools by task so you can decide which CLI helper to inspect next.' },
36
+ { command: 'apltk architecture --help', result: 'Shows the architecture atlas command tree, task guidance, and action-specific follow-up help paths.' },
37
+ { command: 'apltk tools architecture --help', result: 'Shows what the architecture atlas tool is for, then prints its native command tree and examples.' },
38
+ { command: 'apltk filter-logs app.log --start 2026-03-24T10:00:00Z', result: 'Prints only the log lines whose timestamps fall within the requested time window.' },
39
+ ];
40
+
41
+ return this.joinLines([
42
+ buildBanner({ version: this.version, colorEnabled: this.colorEnabled }),
43
+ '',
44
+ 'Usage:',
45
+ ` apltk [install] [${this.modeUsagePattern()}]...`,
46
+ ` apollo-toolkit [install] [${this.modeUsagePattern()}]...`,
47
+ ` apltk uninstall [${this.modeUsagePattern()}]... [--yes]`,
48
+ ' apltk tools',
49
+ ' apltk <tool> [...args]',
50
+ ' apltk tools <tool> [...args]',
51
+ ' apltk --help',
52
+ ' apollo-toolkit --help',
53
+ '',
54
+ 'Common goals:',
55
+ ' - Install or refresh skills in one or more agent targets: `apltk install --help`',
56
+ ' - Remove manifest-tracked installs from selected targets: `apltk uninstall --help`',
57
+ ' - Discover which bundled helper tool matches a task: `apltk tools --help`',
58
+ ' - Inspect one tool deeply before running it: `apltk tools <tool> --help`',
59
+ '',
60
+ 'Bundled tools:',
61
+ formatToolList(),
62
+ '',
63
+ buildToolDiscoveryHelp(),
64
+ '',
65
+ 'Options:',
66
+ ' --home <path> Override Apollo Toolkit home directory',
67
+ ' --symlink Install skills as symlinks instead of copied directories',
68
+ ' --copy Install skills as copied directories instead of symlinks',
69
+ ' --yes, -y Skip uninstall confirmation',
70
+ ' --help Show this help text',
71
+ '',
72
+ 'Examples:',
73
+ formatExamples(examples),
74
+ ]);
75
+ }
76
+
77
+ /** Replaces buildInstallHelpText – install-specific help. */
78
+ install(): string {
79
+ const examples = [
80
+ { command: 'apltk', result: 'Launches the interactive installer, opens the target selector, and then walks through link-mode confirmation.' },
81
+ { command: 'apltk codex openclaw --symlink', result: 'Performs a non-interactive install into `codex` and `openclaw` targets using symlinks.' },
82
+ { command: 'npx @laitszkin/apollo-toolkit all --copy', result: 'Installs a copied snapshot into every supported target instead of symlinking.' },
83
+ ];
84
+
85
+ return this.joinLines([
86
+ buildBanner({ version: this.version, colorEnabled: this.colorEnabled }),
87
+ '',
88
+ 'Usage:',
89
+ ` apltk [install] [${this.modeUsagePattern()}]...`,
90
+ ` apollo-toolkit [install] [${this.modeUsagePattern()}]...`,
91
+ '',
92
+ 'Use this when:',
93
+ ' - You want to install or refresh Apollo Toolkit skills in one or more agent targets.',
94
+ ' - You need to choose between symlink mode (auto-updating) and copy mode (stable snapshot).',
95
+ '',
96
+ 'Supported targets:',
97
+ buildSupportedTargetLines({ targets: [...TARGET_DEFINITIONS], colorEnabled: this.colorEnabled }),
98
+ '',
99
+ 'Behavior notes:',
100
+ ' - Running `apltk` with no targets opens the interactive installer and target selector.',
101
+ ' - `--symlink` keeps installed skills connected to the managed toolkit checkout in `~/.apollo-toolkit`.',
102
+ ' - `--copy` installs a snapshot that only changes when you run the installer again.',
103
+ ' - The installer can optionally include codex-exclusive skills in non-codex targets after prompting.',
104
+ '',
105
+ 'Options:',
106
+ ' --home <path> Override Apollo Toolkit home directory',
107
+ ' --symlink Install skills as symlinks (recommended)',
108
+ ' --copy Install skills as copied directories',
109
+ ' --help Show this install help',
110
+ '',
111
+ 'Examples:',
112
+ formatExamples(examples),
113
+ ]);
114
+ }
115
+
116
+ /** Replaces buildUninstallHelpText – uninstall-specific help. */
117
+ uninstall(): string {
118
+ const examples = [
119
+ { command: 'apltk uninstall', result: 'Opens the interactive uninstall selector when running in a TTY and then asks for confirmation before removal.' },
120
+ { command: 'apltk uninstall codex agents --yes', result: 'Removes Apollo Toolkit-managed installs from `codex` and `agents` without another confirmation prompt.' },
121
+ { command: 'apltk uninstall codex --home /tmp/custom-home', result: 'Uses the custom managed toolkit home while removing manifest-tracked installs from the selected target.' },
122
+ ];
123
+
124
+ return this.joinLines([
125
+ buildBanner({ version: this.version, colorEnabled: this.colorEnabled }),
126
+ '',
127
+ 'Usage:',
128
+ ` apltk uninstall [${this.modeUsagePattern()}]... [--yes]`,
129
+ '',
130
+ 'Use this when:',
131
+ ' - You want to remove Apollo Toolkit-managed skills from one or more agent targets.',
132
+ ' - You need to clean up manifest-tracked historical installs as well as the current installed skills.',
133
+ '',
134
+ 'Supported targets:',
135
+ buildSupportedTargetLines({ targets: [...TARGET_DEFINITIONS], colorEnabled: this.colorEnabled }),
136
+ '',
137
+ 'Behavior notes:',
138
+ ' - With no explicit targets, uninstall opens the interactive selector in a TTY and otherwise falls back to all targets.',
139
+ ' - Uninstall removes manifest-tracked current and historical Apollo Toolkit skill directories.',
140
+ ' - `--yes` skips the confirmation prompt after the target list is resolved.',
141
+ '',
142
+ 'Options:',
143
+ ' --home <path> Override Apollo Toolkit home directory',
144
+ ' --yes, -y Skip uninstall confirmation',
145
+ ' --help Show this uninstall help',
146
+ '',
147
+ 'Examples:',
148
+ formatExamples(examples),
149
+ ]);
150
+ }
151
+
152
+ /** Replaces buildToolsHelp – tools listing help screen. */
153
+ toolsHelp(): string {
154
+ const examples = [
155
+ { command: 'apltk tools', result: 'Lists all bundled tools plus the task-oriented discovery guide.' },
156
+ { command: 'apltk tools open-github-issue --help', result: 'Shows when to use the GitHub issue publisher, then prints its exact script flags and examples.' },
157
+ { command: 'apltk tools architecture --help', result: 'Shows when to use the architecture atlas CLI, then prints its native command tree.' },
158
+ ];
159
+
160
+ return this.joinLines([
161
+ buildBanner({ version: this.version, colorEnabled: this.colorEnabled }),
162
+ '',
163
+ 'Usage:',
164
+ ' apltk tools',
165
+ ' apltk <tool> [...args]',
166
+ ' apltk tools <tool> [...args]',
167
+ '',
168
+ buildToolDiscoveryHelp(),
169
+ '',
170
+ 'Bundled tools:',
171
+ formatToolList(),
172
+ '',
173
+ 'Tip:',
174
+ ' Pass `--help` after a tool name to view task guidance, native script flags, and concrete examples.',
175
+ '',
176
+ 'Examples:',
177
+ formatExamples(examples),
178
+ ]);
179
+ }
180
+ }
@@ -1,10 +1,9 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
- import { color, supportsColor, supportsAnimation, buildBanner, buildWordmark, buildWelcomeScreen, buildSupportedTargetLines, renderSelectionScreen, animateWelcomeScreen, promptYesNo, promptForModes, isInteractive } from '@laitszkin/tui';
5
- import type { TargetDefinition } from '@laitszkin/tui';
6
- import { formatToolList, buildToolDiscoveryHelp, runTool, getTool as getToolCommand } from '@laitszkin/tool-registry';
7
- import { formatExamples } from '@laitszkin/tool-registry';
4
+ import { color, supportsColor, supportsAnimation, buildBanner, buildWordmark, buildWelcomeScreen, buildSupportedTargetLines, renderSelectionScreen, animateWelcomeScreen, promptYesNo, promptForModes, isInteractive, createStdioWriter } from '@laitszkin/tui';
5
+ import type { TargetDefinition, StdioWriter } from '@laitszkin/tui';
6
+ import { runTool } from '@laitszkin/tool-registry';
8
7
  import {
9
8
  TARGET_DEFINITIONS,
10
9
  VALID_MODES,
@@ -49,257 +48,52 @@ export {
49
48
  execCommand,
50
49
  };
51
50
  import type { CliContext, InstallMode, ParsedArguments } from './types.js';
52
-
53
- function buildModeUsagePattern(): string {
54
- return `${VALID_MODES.join('|')}|all`;
55
- }
56
-
57
- function buildInteractiveModeHint(): string {
58
- const quotedModes = [...VALID_MODES, 'all'].map((mode) => `\`${mode}\``);
59
- return `${quotedModes.slice(0, -1).join(', ')}, or ${quotedModes.at(-1)}`;
60
- }
61
-
62
- function buildHelpText({ version, colorEnabled }: { version: string; colorEnabled: boolean }): string {
63
- const examples = [
64
- { command: 'apltk --help', result: 'Shows the top-level Apollo Toolkit guide, including install modes and bundled task-tool discovery.' },
65
- { command: 'apltk tools --help', result: 'Lists bundled tools by task so you can decide which CLI helper to inspect next.' },
66
- { command: 'apltk architecture --help', result: 'Shows the architecture atlas command tree, task guidance, and action-specific follow-up help paths.' },
67
- { command: 'apltk tools architecture --help', result: 'Shows what the architecture atlas tool is for, then prints its native command tree and examples.' },
68
- { command: 'apltk filter-logs app.log --start 2026-03-24T10:00:00Z', result: 'Prints only the log lines whose timestamps fall within the requested time window.' },
69
- ];
70
- return [
71
- buildBanner({ version, colorEnabled }),
72
- '',
73
- 'Usage:',
74
- ` apltk [install] [${buildModeUsagePattern()}]...`,
75
- ` apollo-toolkit [install] [${buildModeUsagePattern()}]...`,
76
- ` apltk uninstall [${buildModeUsagePattern()}]... [--yes]`,
77
- ' apltk tools',
78
- ' apltk <tool> [...args]',
79
- ' apltk tools <tool> [...args]',
80
- ' apltk --help',
81
- ' apollo-toolkit --help',
82
- '',
83
- 'Common goals:',
84
- ' - Install or refresh skills in one or more agent targets: `apltk install --help`',
85
- ' - Remove manifest-tracked installs from selected targets: `apltk uninstall --help`',
86
- ' - Discover which bundled helper tool matches a task: `apltk tools --help`',
87
- ' - Inspect one tool deeply before running it: `apltk tools <tool> --help`',
88
- '',
89
- 'Bundled tools:',
90
- formatToolList(),
91
- '',
92
- buildToolDiscoveryHelp(),
93
- '',
94
- 'Options:',
95
- ' --home <path> Override Apollo Toolkit home directory',
96
- ' --symlink Install skills as symlinks instead of copied directories',
97
- ' --copy Install skills as copied directories instead of symlinks',
98
- ' --yes, -y Skip uninstall confirmation',
99
- ' --help Show this help text',
100
- '',
101
- 'Examples:',
102
- formatExamples(examples),
103
- ].join('\n');
104
- }
105
-
106
- function buildToolsHelp({ version, colorEnabled }: { version: string; colorEnabled: boolean }): string {
107
- const examples = [
108
- { command: 'apltk tools', result: 'Lists all bundled tools plus the task-oriented discovery guide.' },
109
- { command: 'apltk tools open-github-issue --help', result: 'Shows when to use the GitHub issue publisher, then prints its exact script flags and examples.' },
110
- { command: 'apltk tools architecture --help', result: 'Shows when to use the architecture atlas CLI, then prints its native command tree.' },
111
- ];
112
- return [
113
- buildBanner({ version, colorEnabled }),
114
- '',
115
- 'Usage:',
116
- ' apltk tools',
117
- ' apltk <tool> [...args]',
118
- ' apltk tools <tool> [...args]',
119
- '',
120
- buildToolDiscoveryHelp(),
121
- '',
122
- 'Bundled tools:',
123
- formatToolList(),
124
- '',
125
- 'Tip:',
126
- ' Pass `--help` after a tool name to view task guidance, native script flags, and concrete examples.',
127
- '',
128
- 'Examples:',
129
- formatExamples(examples),
130
- ].join('\n');
131
- }
132
-
133
- function buildInstallHelpText({ version, colorEnabled }: { version: string; colorEnabled: boolean }): string {
134
- const examples = [
135
- { command: 'apltk', result: 'Launches the interactive installer, opens the target selector, and then walks through link-mode confirmation.' },
136
- { command: 'apltk codex openclaw --symlink', result: 'Performs a non-interactive install into `codex` and `openclaw` targets using symlinks.' },
137
- { command: 'npx @laitszkin/apollo-toolkit all --copy', result: 'Installs a copied snapshot into every supported target instead of symlinking.' },
138
- ];
139
- return [
140
- buildBanner({ version, colorEnabled }),
141
- '',
142
- 'Usage:',
143
- ` apltk [install] [${buildModeUsagePattern()}]...`,
144
- ` apollo-toolkit [install] [${buildModeUsagePattern()}]...`,
145
- '',
146
- 'Use this when:',
147
- ' - You want to install or refresh Apollo Toolkit skills in one or more agent targets.',
148
- ' - You need to choose between symlink mode (auto-updating) and copy mode (stable snapshot).',
149
- '',
150
- 'Supported targets:',
151
- buildSupportedTargetLines({ targets: [...TARGET_DEFINITIONS], colorEnabled }),
152
- '',
153
- 'Behavior notes:',
154
- ' - Running `apltk` with no targets opens the interactive installer and target selector.',
155
- ' - `--symlink` keeps installed skills connected to the managed toolkit checkout in `~/.apollo-toolkit`.',
156
- ' - `--copy` installs a snapshot that only changes when you run the installer again.',
157
- ' - The installer can optionally include codex-exclusive skills in non-codex targets after prompting.',
158
- '',
159
- 'Options:',
160
- ' --home <path> Override Apollo Toolkit home directory',
161
- ' --symlink Install skills as symlinks (recommended)',
162
- ' --copy Install skills as copied directories',
163
- ' --help Show this install help',
164
- '',
165
- 'Examples:',
166
- formatExamples(examples),
167
- ].join('\n');
168
- }
169
-
170
- function buildUninstallHelpText({ version, colorEnabled }: { version: string; colorEnabled: boolean }): string {
171
- const examples = [
172
- { command: 'apltk uninstall', result: 'Opens the interactive uninstall selector when running in a TTY and then asks for confirmation before removal.' },
173
- { command: 'apltk uninstall codex agents --yes', result: 'Removes Apollo Toolkit-managed installs from `codex` and `agents` without another confirmation prompt.' },
174
- { command: 'apltk uninstall codex --home /tmp/custom-home', result: 'Uses the custom managed toolkit home while removing manifest-tracked installs from the selected target.' },
175
- ];
176
- return [
177
- buildBanner({ version, colorEnabled }),
178
- '',
179
- 'Usage:',
180
- ` apltk uninstall [${buildModeUsagePattern()}]... [--yes]`,
181
- '',
182
- 'Use this when:',
183
- ' - You want to remove Apollo Toolkit-managed skills from one or more agent targets.',
184
- ' - You need to clean up manifest-tracked historical installs as well as the current installed skills.',
185
- '',
186
- 'Supported targets:',
187
- buildSupportedTargetLines({ targets: [...TARGET_DEFINITIONS], colorEnabled }),
188
- '',
189
- 'Behavior notes:',
190
- ' - With no explicit targets, uninstall opens the interactive selector in a TTY and otherwise falls back to all targets.',
191
- ' - Uninstall removes manifest-tracked current and historical Apollo Toolkit skill directories.',
192
- ' - `--yes` skips the confirmation prompt after the target list is resolved.',
193
- '',
194
- 'Options:',
195
- ' --home <path> Override Apollo Toolkit home directory',
196
- ' --yes, -y Skip uninstall confirmation',
197
- ' --help Show this uninstall help',
198
- '',
199
- 'Examples:',
200
- formatExamples(examples),
201
- ].join('\n');
202
- }
51
+ import type { CommandParser } from './parsers/types.js';
52
+ import { formatAppError } from '@laitszkin/tool-utils';
53
+ import { InstallArgsParser } from './parsers/install-parser.js';
54
+ import { UninstallArgsParser } from './parsers/uninstall-parser.js';
55
+ import { ToolArgsParser } from './parsers/tool-parser.js';
56
+ import { HelpTextBuilder } from './help-text-builder.js';
203
57
 
204
58
  function readPackageJson(sourceRoot: string): { version: string; name: string } {
205
59
  return JSON.parse(fs.readFileSync(path.join(sourceRoot, 'package.json'), 'utf8'));
206
60
  }
207
61
 
208
62
  function parseArguments(argv: string[]): ParsedArguments {
209
- const args = [...argv];
210
- const result: ParsedArguments = {
211
- command: 'install',
212
- modes: [],
213
- showHelp: false,
214
- showToolsHelp: false,
215
- toolkitHome: null,
216
- toolName: null,
217
- toolArgs: [],
218
- linkMode: null,
219
- assumeYes: false,
220
- explicitInstallCommand: false,
221
- helpTopic: 'overview',
222
- };
223
-
224
- if (args[0] === 'uninstall') {
225
- result.command = 'uninstall';
226
- args.shift();
227
- while (args.length > 0) {
228
- const arg = args.shift()!;
229
- if (arg === '--help' || arg === '-h') {
230
- result.showHelp = true;
231
- } else if (arg === '--yes' || arg === '-y') {
232
- result.assumeYes = true;
233
- } else if (arg === '--home') {
234
- const toolkitHome = args.shift();
235
- if (!toolkitHome) throw new Error('Missing value for --home');
236
- result.toolkitHome = path.resolve(toolkitHome);
237
- } else {
238
- result.modes.push(arg as InstallMode);
239
- }
240
- }
241
- if (result.showHelp) result.helpTopic = 'uninstall';
242
- return result;
243
- }
244
-
245
- if (args[0] === 'tools' || args[0] === 'tool') {
246
- args.shift();
247
- const nextArg: string | undefined = args[0];
248
- if (args.length === 0 || nextArg === '--help' || nextArg === '-h') {
249
- result.command = 'tools-help';
250
- result.showToolsHelp = true;
251
- return result;
63
+ const firstArg = argv[0];
64
+
65
+ // Shared parser instances (eliminates double instantiation)
66
+ const installParser = new InstallArgsParser();
67
+ const toolParser = new ToolArgsParser();
68
+
69
+ // Dispatch table for all known command types
70
+ // ==== Collision zone (FIX-09) ====
71
+ // L55-190 and L349-360 are high-collision regions touched by dispatch,
72
+ // parser, and error-boundary changes. Modify with care.
73
+ // =================================
74
+
75
+ const commandParsers = new Map<string, CommandParser<any>>([
76
+ ['install', installParser],
77
+ ['uninstall', new UninstallArgsParser()],
78
+ ['tools', toolParser],
79
+ ['tool', toolParser],
80
+ ]);
81
+
82
+ // Command dispatch: iterate parsers, first match wins
83
+ for (const [name, parser] of commandParsers) {
84
+ if (firstArg === name) {
85
+ const result = parser.parse(argv);
86
+ return parser.toParsedArguments(result);
252
87
  }
253
- result.command = 'tool';
254
- result.toolName = args.shift() || null;
255
- result.toolArgs = args;
256
- return result;
257
88
  }
258
89
 
259
- const firstArg = args[0];
90
+ // Direct tool name (no "tools" prefix) — route through the 'tool' dispatch table entry
260
91
  if (firstArg && isKnownToolName(firstArg)) {
261
- result.command = 'tool';
262
- result.toolName = args.shift() || null;
263
- result.toolArgs = args;
264
- return result;
265
- }
266
-
267
- while (args.length > 0) {
268
- const arg = args.shift()!;
269
- if (arg === '--help' || arg === '-h') {
270
- result.showHelp = true;
271
- continue;
272
- }
273
- if (arg === '--home') {
274
- const toolkitHome = args.shift();
275
- if (!toolkitHome) throw new Error('Missing value for --home');
276
- result.toolkitHome = path.resolve(toolkitHome);
277
- continue;
278
- }
279
- if (arg === '--symlink') {
280
- result.linkMode = 'symlink';
281
- continue;
282
- }
283
- if (arg === '--copy') {
284
- result.linkMode = 'copy';
285
- continue;
286
- }
287
- if (arg === 'install') {
288
- result.explicitInstallCommand = true;
289
- continue;
290
- }
291
- result.modes.push(arg as InstallMode);
92
+ return toolParser.toParsedArguments(toolParser.parse(argv));
292
93
  }
293
94
 
294
- if (result.showHelp) {
295
- const installContextRequested = result.explicitInstallCommand
296
- || result.modes.length > 0
297
- || result.linkMode !== null
298
- || result.toolkitHome !== null;
299
- result.helpTopic = installContextRequested ? 'install' : 'overview';
300
- }
301
-
302
- return result;
95
+ // Default: install (handles bare arguments like "codex", "--help", or empty argv)
96
+ return installParser.toParsedArguments(installParser.parse(argv));
303
97
  }
304
98
 
305
99
  function buildSymlinkInfo({ colorEnabled }: { colorEnabled: boolean }): string {
@@ -418,7 +212,13 @@ function printUninstallSummary({ stdout, uninstallResult, env }: {
418
212
  }
419
213
  }
420
214
 
421
- export { parseArguments, buildHelpText, buildInstallHelpText, buildUninstallHelpText, buildToolsHelp, buildBanner, buildWelcomeScreen, registerAllTools };
215
+ export { InstallArgsParser } from './parsers/install-parser.js';
216
+ export { UninstallArgsParser } from './parsers/uninstall-parser.js';
217
+ export { ToolArgsParser } from './parsers/tool-parser.js';
218
+ export { HelpTextBuilder } from './help-text-builder.js';
219
+ export { normalizeParseError } from './parsers/parser-utils.js';
220
+
221
+ export { parseArguments, buildBanner, buildWelcomeScreen, registerAllTools };
422
222
 
423
223
  export async function run(argv: string[], context: CliContext = {}): Promise<number> {
424
224
  const __filename = fileURLToPath(import.meta.url);
@@ -428,6 +228,7 @@ export async function run(argv: string[], context: CliContext = {}): Promise<num
428
228
  const stderr = context.stderr || process.stderr;
429
229
  const stdin = context.stdin || process.stdin;
430
230
  const env = context.env || process.env;
231
+ const stdioWriter: StdioWriter = createStdioWriter({ stdout, stderr, env });
431
232
  let packageJson = readPackageJson(sourceRoot);
432
233
 
433
234
  try {
@@ -436,25 +237,32 @@ export async function run(argv: string[], context: CliContext = {}): Promise<num
436
237
  if (parsed.showHelp) {
437
238
  const colorEnabled = supportsColor(stdout, env);
438
239
  if (parsed.helpTopic === 'overview') await registerAllTools();
240
+ const builder = new HelpTextBuilder({ version: packageJson.version, colorEnabled });
439
241
  const helpText = parsed.helpTopic === 'install'
440
- ? buildInstallHelpText({ version: packageJson.version, colorEnabled })
242
+ ? builder.install()
441
243
  : parsed.helpTopic === 'uninstall'
442
- ? buildUninstallHelpText({ version: packageJson.version, colorEnabled })
443
- : buildHelpText({ version: packageJson.version, colorEnabled });
244
+ ? builder.uninstall()
245
+ : builder.overview();
444
246
  stdout.write(`${helpText}\n`);
445
247
  return 0;
446
248
  }
447
249
 
448
250
  if (parsed.showToolsHelp) {
449
251
  await registerAllTools();
450
- stdout.write(`${buildToolsHelp({ version: packageJson.version, colorEnabled: supportsColor(stdout, env) })}\n`);
252
+ stdout.write(`${new HelpTextBuilder({ version: packageJson.version, colorEnabled: supportsColor(stdout, env) }).toolsHelp()}\n`);
451
253
  return 0;
452
254
  }
453
255
 
256
+ // Tool dispatch error patterns (FIX-10):
257
+ // Pattern A (createToolRunner tools): handler throws -> caught internally ->
258
+ // formatAppError + return 1
259
+ // Pattern B (carryover tools): handler throws -> propagates through runTool ->
260
+ // CLI boundary catch -> formatAppError + return 1
261
+ // Both patterns converge on the same formatting at the boundary.
454
262
  if (parsed.command === 'tool') {
455
263
  await registerAllTools();
456
- return (context.runTool || runTool)(parsed.toolName!, parsed.toolArgs, {
457
- sourceRoot, stdout, stderr, env, spawnCommand: context.spawnCommand,
264
+ return await (context.runTool || runTool)(parsed.toolName!, parsed.toolArgs, {
265
+ sourceRoot, stdout, stderr, env, spawnCommand: context.spawnCommand, stdioWriter,
458
266
  });
459
267
  }
460
268
 
@@ -580,7 +388,7 @@ export async function run(argv: string[], context: CliContext = {}): Promise<num
580
388
  printSummary({ stdout, version: packageJson.version, toolkitHome, modes, installResult, env });
581
389
  return 0;
582
390
  } catch (error) {
583
- stderr.write(`Error: ${(error as Error).message}\n`);
391
+ formatAppError(stderr, error);
584
392
  return 1;
585
393
  }
586
394
  }
@@ -1,9 +1,11 @@
1
1
  import fs from 'node:fs';
2
2
  import fsp from 'node:fs/promises';
3
- import os from 'node:os';
4
3
  import path from 'node:path';
4
+ import { createPlatformAdapter } from '@laitszkin/tool-utils';
5
5
  import type { InstallMode, InstallTarget, ManifestData, SyncResult } from './types.js';
6
6
 
7
+ const platformAdapter = createPlatformAdapter();
8
+
7
9
  export interface TargetDefinition {
8
10
  id: InstallMode;
9
11
  label: string;
@@ -24,7 +26,7 @@ const SKILLS_DIRNAME = 'skills';
24
26
  export const MANIFEST_FILENAME = '.apollo-toolkit-manifest.json';
25
27
 
26
28
  export function resolveHomeDirectory(env: NodeJS.ProcessEnv = process.env): string {
27
- return env.HOME || env.USERPROFILE || os.homedir();
29
+ return createPlatformAdapter().homeDir(env);
28
30
  }
29
31
 
30
32
  export function expandUserPath(inputPath: string, env: NodeJS.ProcessEnv = process.env): string {
@@ -115,12 +117,12 @@ export async function readManifest(targetRoot: string): Promise<ManifestData | n
115
117
  }
116
118
  }
117
119
 
118
- function isSafeSkillName(skillName: string): boolean {
120
+ export function isSafeSkillName(skillName: string): boolean {
119
121
  return typeof skillName === 'string'
120
122
  && skillName.length > 0
121
123
  && !skillName.includes('\0')
122
124
  && !skillName.includes('/')
123
- && !skillName.includes('\\')
125
+ && !(skillName.includes('\\') && createPlatformAdapter().isWindows())
124
126
  && !path.isAbsolute(skillName)
125
127
  && skillName !== '.'
126
128
  && skillName !== '..';
@@ -148,7 +150,7 @@ export async function writeManifest(
148
150
  await fsp.mkdir(targetRoot, { recursive: true });
149
151
  await fsp.writeFile(
150
152
  path.join(targetRoot, MANIFEST_FILENAME),
151
- `${JSON.stringify(manifest, null, 2)}\n`,
153
+ `${JSON.stringify(manifest, null, 2)}${platformAdapter.EOL}`,
152
154
  'utf8',
153
155
  );
154
156
  }
@@ -229,7 +231,7 @@ async function stageToolkitContents({ sourceRoot, destinationRoot, version, mode
229
231
  const metadata = { version, installedAt: new Date().toISOString(), source: 'npm-package' };
230
232
  await fsp.writeFile(
231
233
  path.join(destinationRoot, '.apollo-toolkit-install.json'),
232
- `${JSON.stringify(metadata, null, 2)}\n`,
234
+ `${JSON.stringify(metadata, null, 2)}${platformAdapter.EOL}`,
233
235
  'utf8',
234
236
  );
235
237
  return copiedEntries.sort();
@@ -357,9 +359,19 @@ async function replaceWithCopy(sourcePath: string, targetPath: string): Promise<
357
359
  }
358
360
 
359
361
  async function replaceWithSymlink(sourcePath: string, targetPath: string): Promise<void> {
362
+ const adapter = createPlatformAdapter();
360
363
  await fsp.rm(targetPath, { recursive: true, force: true });
361
364
  await ensureDirectory(path.dirname(targetPath));
362
- await fsp.symlink(sourcePath, targetPath, process.platform === 'win32' ? 'junction' : 'dir');
365
+ try {
366
+ await fsp.symlink(sourcePath, targetPath, adapter.symlinkType());
367
+ } catch (err: unknown) {
368
+ if ((err as NodeJS.ErrnoException).code === 'EPERM') {
369
+ process.stderr.write(`Warning: Symlink not supported (EPERM). Falling back to copy mode.${adapter.EOL}`);
370
+ await replaceWithCopy(sourcePath, targetPath);
371
+ } else {
372
+ throw err;
373
+ }
374
+ }
363
375
  }
364
376
 
365
377
  export async function installLinks({ toolkitHome, modes, env = process.env, previousSkillNames = [], linkMode = 'copy', includeExclusiveSkills = false }: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@laitszkin/cli",
3
- "version": "4.0.8",
4
- "description": "Apollo Toolkit CLI command management (install, uninstall, tool routing)",
3
+ "version": "5.0.0",
4
+ "description": "Apollo Toolkit \u2014 CLI command management (install, uninstall, tool routing)",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -19,6 +19,7 @@
19
19
  "dependencies": {
20
20
  "@laitszkin/tui": "*",
21
21
  "@laitszkin/tool-registry": "*",
22
+ "@laitszkin/tool-utils": "*",
22
23
  "@laitszkin/tool-filter-logs": "*",
23
24
  "@laitszkin/tool-search-logs": "*",
24
25
  "@laitszkin/tool-validate-skill-frontmatter": "*",
@@ -35,8 +36,10 @@
35
36
  "@laitszkin/tool-generate-storyboard-images": "*",
36
37
  "@laitszkin/tool-enforce-video-aspect-ratio": "*",
37
38
  "@laitszkin/tool-architecture": "*",
39
+ "@laitszkin/tool-codegraph": "*",
38
40
  "@laitszkin/tool-create-specs": "*",
39
41
  "@laitszkin/tool-create-review-report": "*",
42
+ "@laitszkin/tool-eval": "*",
40
43
  "@laitszkin/tool-extract-pdf-text": "*"
41
44
  }
42
- }
45
+ }