@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,94 @@
1
+ import { parseArgs } from 'node:util';
2
+ import path from 'node:path';
3
+ import { UserInputError } from '@laitszkin/tool-utils';
4
+ import type { InstallMode, ParsedArguments } from '../types.js';
5
+ import type { CommandParser, InstallCommand } from './types.js';
6
+ import { normalizeParseError } from './parser-utils.js';
7
+
8
+ /**
9
+ * Parser for the install (default) command mode.
10
+ *
11
+ * Recognises:
12
+ * - Positional args: install keyword, mode names (codex, openclaw, ...)
13
+ * - --help / -h
14
+ * - --home <path>
15
+ * - --symlink, --copy
16
+ */
17
+ export class InstallArgsParser implements CommandParser<InstallCommand> {
18
+ parse(argv: string[]): InstallCommand {
19
+ let showHelp = false;
20
+ let toolkitHome: string | null = null;
21
+ let linkMode: 'copy' | 'symlink' | null = null;
22
+ let explicitInstallCommand = false;
23
+ const modes: string[] = [];
24
+
25
+ try {
26
+ const { values, positionals } = parseArgs({
27
+ args: argv,
28
+ allowPositionals: true,
29
+ options: {
30
+ help: { type: 'boolean', short: 'h' },
31
+ home: { type: 'string' },
32
+ symlink: { type: 'boolean' },
33
+ copy: { type: 'boolean' },
34
+ },
35
+ });
36
+
37
+ showHelp = values.help ?? false;
38
+ if (values.home) {
39
+ toolkitHome = path.resolve(values.home);
40
+ }
41
+ if (values.symlink) {
42
+ linkMode = 'symlink';
43
+ }
44
+ if (values.copy) {
45
+ linkMode = 'copy';
46
+ }
47
+ if (values.symlink && values.copy) {
48
+ throw new UserInputError('Cannot use both --symlink and --copy');
49
+ }
50
+
51
+ for (const pos of positionals) {
52
+ if (pos === 'install') {
53
+ explicitInstallCommand = true;
54
+ } else {
55
+ modes.push(pos);
56
+ }
57
+ }
58
+ } catch (err) {
59
+ normalizeParseError(err);
60
+ }
61
+
62
+ const helpTopic: 'overview' | 'install' = showHelp
63
+ ? (explicitInstallCommand || modes.length > 0 || linkMode !== null || toolkitHome !== null)
64
+ ? 'install'
65
+ : 'overview'
66
+ : 'overview';
67
+
68
+ return {
69
+ command: 'install',
70
+ modes: modes as InstallMode[],
71
+ showHelp,
72
+ toolkitHome,
73
+ linkMode,
74
+ explicitInstallCommand,
75
+ helpTopic,
76
+ };
77
+ }
78
+
79
+ toParsedArguments(result: InstallCommand): ParsedArguments {
80
+ return {
81
+ command: 'install',
82
+ modes: result.modes,
83
+ showHelp: result.showHelp,
84
+ showToolsHelp: false,
85
+ toolkitHome: result.toolkitHome,
86
+ toolName: null,
87
+ toolArgs: [],
88
+ linkMode: result.linkMode,
89
+ assumeYes: false,
90
+ explicitInstallCommand: result.explicitInstallCommand,
91
+ helpTopic: result.helpTopic,
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,17 @@
1
+ import { UserInputError } from '@laitszkin/tool-utils';
2
+
3
+ /**
4
+ * Normalises common parseArgs errors into user-facing UserInputErrors.
5
+ *
6
+ * Currently handles:
7
+ * - --home without a value
8
+ *
9
+ * Call this inside a catch block to normalise the error before propagating it.
10
+ */
11
+ export function normalizeParseError(err: unknown): never {
12
+ const message = (err as Error).message;
13
+ if (message.includes('--home') && (message.includes('argument missing') || message.includes('value') || message.includes('ambiguous'))) {
14
+ throw new UserInputError('Missing value for --home');
15
+ }
16
+ throw err;
17
+ }
@@ -0,0 +1,65 @@
1
+ import type { ParsedArguments } from '../types.js';
2
+ import type { CommandParser, ToolCommand, ToolsHelpCommand } from './types.js';
3
+
4
+ /**
5
+ * Parser for tool-invocation modes.
6
+ *
7
+ * Two entry paths:
8
+ * 1. `tools` / `tool` prefix – argv[0] is 'tools' or 'tool'
9
+ * 2. Direct tool name – argv[0] is a known tool name (detected by caller)
10
+ *
11
+ * Returns a ToolsHelpCommand when no tool is named or --help is passed,
12
+ * otherwise returns a ToolCommand with the tool name and remaining args.
13
+ */
14
+ export class ToolArgsParser implements CommandParser<ToolCommand | ToolsHelpCommand> {
15
+ parse(argv: string[]): ToolCommand | ToolsHelpCommand {
16
+ const args = [...argv];
17
+
18
+ // Strip leading 'tools'/'tool' prefix if present
19
+ const hasToolsPrefix = args[0] === 'tools' || args[0] === 'tool';
20
+ if (hasToolsPrefix) {
21
+ args.shift();
22
+ }
23
+
24
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
25
+ return { command: 'tools-help', showToolsHelp: true };
26
+ }
27
+
28
+ return {
29
+ command: 'tool',
30
+ toolName: args.shift() ?? null,
31
+ toolArgs: args,
32
+ };
33
+ }
34
+
35
+ toParsedArguments(result: ToolCommand | ToolsHelpCommand): ParsedArguments {
36
+ if (result.command === 'tools-help') {
37
+ return {
38
+ command: 'tools-help',
39
+ modes: [],
40
+ showHelp: false,
41
+ showToolsHelp: true,
42
+ toolkitHome: null,
43
+ toolName: null,
44
+ toolArgs: [],
45
+ linkMode: null,
46
+ assumeYes: false,
47
+ explicitInstallCommand: false,
48
+ helpTopic: 'tools-help',
49
+ };
50
+ }
51
+ return {
52
+ command: 'tool',
53
+ modes: [],
54
+ showHelp: false,
55
+ showToolsHelp: false,
56
+ toolkitHome: null,
57
+ toolName: result.toolName,
58
+ toolArgs: result.toolArgs,
59
+ linkMode: null,
60
+ assumeYes: false,
61
+ explicitInstallCommand: false,
62
+ helpTopic: 'overview',
63
+ };
64
+ }
65
+ }
@@ -0,0 +1,56 @@
1
+ import type { InstallMode, ParsedArguments } from '../types.js';
2
+
3
+ /**
4
+ * Parsed result for the install (default) command mode.
5
+ */
6
+ export interface InstallCommand {
7
+ command: 'install';
8
+ modes: InstallMode[];
9
+ showHelp: boolean;
10
+ toolkitHome: string | null;
11
+ linkMode: 'copy' | 'symlink' | null;
12
+ explicitInstallCommand: boolean;
13
+ helpTopic: 'overview' | 'install';
14
+ }
15
+
16
+ /**
17
+ * Parsed result for the uninstall command mode.
18
+ */
19
+ export interface UninstallCommand {
20
+ command: 'uninstall';
21
+ modes: InstallMode[];
22
+ showHelp: boolean;
23
+ toolkitHome: string | null;
24
+ assumeYes: boolean;
25
+ helpTopic: 'uninstall';
26
+ }
27
+
28
+ /**
29
+ * Parsed result for a direct tool invocation.
30
+ */
31
+ export interface ToolCommand {
32
+ command: 'tool';
33
+ toolName: string | null;
34
+ toolArgs: string[];
35
+ }
36
+
37
+ /**
38
+ * Parsed result for the tools listing help screen.
39
+ */
40
+ export interface ToolsHelpCommand {
41
+ command: 'tools-help';
42
+ showToolsHelp: boolean;
43
+ }
44
+
45
+ /**
46
+ * Union of all parsed commands returned by the CLI arg parsers.
47
+ */
48
+ export type ParsedCommand = InstallCommand | UninstallCommand | ToolCommand | ToolsHelpCommand;
49
+
50
+ /**
51
+ * Parser interface for turning raw argv arrays into strongly-typed command objects.
52
+ */
53
+ export interface CommandParser<T> {
54
+ parse(argv: string[]): T;
55
+ toParsedArguments(result: T): ParsedArguments;
56
+ }
@@ -0,0 +1,75 @@
1
+ import { parseArgs } from 'node:util';
2
+ import path from 'node:path';
3
+ import { UserInputError } from '@laitszkin/tool-utils';
4
+ import type { InstallMode, ParsedArguments } from '../types.js';
5
+ import type { CommandParser, UninstallCommand } from './types.js';
6
+ import { normalizeParseError } from './parser-utils.js';
7
+
8
+ /**
9
+ * Parser for the uninstall command mode.
10
+ *
11
+ * Recognises:
12
+ * - Positional args: 'uninstall' keyword, mode names (codex, openclaw, ...)
13
+ * - --help / -h
14
+ * - --home <path>
15
+ * - --yes / -y
16
+ */
17
+ export class UninstallArgsParser implements CommandParser<UninstallCommand> {
18
+ parse(argv: string[]): UninstallCommand {
19
+ let showHelp = false;
20
+ let toolkitHome: string | null = null;
21
+ let assumeYes = false;
22
+ const modes: string[] = [];
23
+
24
+ try {
25
+ const { values, positionals } = parseArgs({
26
+ args: argv,
27
+ allowPositionals: true,
28
+ options: {
29
+ help: { type: 'boolean', short: 'h' },
30
+ home: { type: 'string' },
31
+ yes: { type: 'boolean', short: 'y' },
32
+ },
33
+ });
34
+
35
+ showHelp = values.help ?? false;
36
+ if (values.home) {
37
+ toolkitHome = path.resolve(values.home);
38
+ }
39
+ assumeYes = values.yes ?? false;
40
+
41
+ for (const pos of positionals) {
42
+ if (pos !== 'uninstall') {
43
+ modes.push(pos);
44
+ }
45
+ }
46
+ } catch (err) {
47
+ normalizeParseError(err);
48
+ }
49
+
50
+ return {
51
+ command: 'uninstall',
52
+ modes: modes as InstallMode[],
53
+ showHelp,
54
+ toolkitHome,
55
+ assumeYes,
56
+ helpTopic: 'uninstall',
57
+ };
58
+ }
59
+
60
+ toParsedArguments(result: UninstallCommand): ParsedArguments {
61
+ return {
62
+ command: 'uninstall',
63
+ modes: result.modes,
64
+ showHelp: result.showHelp,
65
+ showToolsHelp: false,
66
+ toolkitHome: result.toolkitHome,
67
+ toolName: null,
68
+ toolArgs: [],
69
+ linkMode: null,
70
+ assumeYes: result.assumeYes,
71
+ explicitInstallCommand: false,
72
+ helpTopic: result.helpTopic,
73
+ };
74
+ }
75
+ }
@@ -52,3 +52,6 @@ export async function registerAllTools(): Promise<void> {
52
52
  registerTool(mod.tool);
53
53
  }
54
54
  }
55
+
56
+ /** Tools excluded from CLI refactoring scope (SPEC.md L28) */
57
+ export const SCOPE_EXCLUDED_TOOLS = new Set(['eval']);
@@ -1,3 +1,5 @@
1
+ import type { StdioWriter } from '@laitszkin/tui';
2
+
1
3
  export type InstallMode = 'codex' | 'openclaw' | 'trae' | 'agents' | 'claude-code';
2
4
 
3
5
  export interface InstallTarget {
@@ -25,6 +27,8 @@ export interface SyncResult {
25
27
  previousSkillNames: string[];
26
28
  }
27
29
 
30
+ // ---- Active return type of parseArguments() / input contract for run() --------
31
+
28
32
  export interface ParsedArguments {
29
33
  command: 'install' | 'uninstall' | 'tool' | 'tools-help';
30
34
  modes: InstallMode[];
@@ -36,7 +40,7 @@ export interface ParsedArguments {
36
40
  linkMode: 'copy' | 'symlink' | null;
37
41
  assumeYes: boolean;
38
42
  explicitInstallCommand: boolean;
39
- helpTopic: string;
43
+ helpTopic: 'overview' | 'install' | 'uninstall' | 'tools-help';
40
44
  }
41
45
 
42
46
  export interface CliContext {
@@ -49,4 +53,5 @@ export interface CliContext {
49
53
  confirmUpdate?: Function;
50
54
  runTool?: Function;
51
55
  spawnCommand?: Function;
56
+ stdioWriter?: StdioWriter;
52
57
  }
@@ -1,6 +1,8 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import { EOL } from 'node:os';
2
3
  import { createInterface } from 'node:readline/promises';
3
4
  import { isInteractive } from '@laitszkin/tui';
5
+ import { createPlatformAdapter } from '@laitszkin/tool-utils';
4
6
 
5
7
  interface Version {
6
8
  parts: number[];
@@ -66,9 +68,13 @@ export function execCommand(command: string, args: string[], { env = process.env
66
68
  stderr?: NodeJS.WriteStream;
67
69
  } = {}): Promise<ExecResult> {
68
70
  return new Promise((resolve, reject) => {
69
- const child = spawn(command, args, {
71
+ // PlatformAdapter normalizes command names across OS (e.g., appending
72
+ // .cmd on Windows) so spawn works reliably on any platform.
73
+ const adapter = createPlatformAdapter();
74
+ const child = spawn(adapter.resolveCommand(command), args, {
70
75
  env,
71
76
  stdio: ['ignore', 'pipe', 'pipe'],
77
+ shell: true,
72
78
  });
73
79
 
74
80
  let capturedStdout = '';
@@ -150,17 +156,17 @@ export async function checkForPackageUpdate({ packageName, currentVersion, env =
150
156
  const approved = await confirmUpdate({ stdin, stdout, currentVersion, latestVersion, packageName });
151
157
 
152
158
  if (!approved) {
153
- stdout.write(`Continuing with ${packageName} ${currentVersion}.\n`);
159
+ stdout.write(`Continuing with ${packageName} ${currentVersion}.${EOL}`);
154
160
  return { checked: true, updated: false, latestVersion };
155
161
  }
156
162
 
157
- stdout.write(`Updating ${packageName} to ${latestVersion}...\n`);
163
+ stdout.write(`Updating ${packageName} to ${latestVersion}...${EOL}`);
158
164
  await exec('npm', ['install', '-g', `${packageName}@latest`], { env, stdout, stderr });
159
- stdout.write(`Update complete. Continuing with ${packageName} ${latestVersion}.\n`);
165
+ stdout.write(`Update complete. Continuing with ${packageName} ${latestVersion}.${EOL}`);
160
166
 
161
167
  return { checked: true, updated: true, latestVersion };
162
168
  } catch (error) {
163
- stderr.write(`Warning: unable to check or install package updates: ${(error as Error).message}\n`);
169
+ stderr.write(`Warning: unable to check or install package updates: ${(error as Error).message}${EOL}`);
164
170
  return { checked: false, updated: false, error: error as Error };
165
171
  }
166
172
  }
@@ -1,3 +1,4 @@
1
+ import { ToolNotFoundError, SystemError } from '../../tool-utils/dist/index.js';
1
2
  const TOOLS_BY_NAME = new Map();
2
3
  export function registerTool(tool) {
3
4
  TOOLS_BY_NAME.set(tool.name, tool);
@@ -18,14 +19,12 @@ export async function runTool(toolName, toolArgs, context = {}) {
18
19
  const stderr = context.stderr || process.stderr;
19
20
  const tool = getTool(toolName);
20
21
  if (!tool) {
21
- stderr.write(`Unknown tool: ${toolName}\n\nAvailable tools:\n${formatToolList()}\n`);
22
- return 1;
22
+ throw new ToolNotFoundError(`Unknown tool: ${toolName}`);
23
23
  }
24
24
  if (tool.handler) {
25
25
  return tool.handler(toolArgs, context);
26
26
  }
27
- stderr.write(`Tool not fully configured: ${toolName}\n`);
28
- return 1;
27
+ throw new SystemError(`Tool not fully configured: ${toolName}`);
29
28
  }
30
29
  export function formatExamples(examples = []) {
31
30
  return examples.map(({ command, result }) => (` ${command}\n Result: ${result}`)).join('\n');