opencode-matrixx 2.4.0 → 2.6.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 (186) hide show
  1. package/README.md +181 -8
  2. package/dist/agents/builtin-agents/available-skills.d.ts +2 -2
  3. package/dist/agents/builtin-agents.d.ts +2 -2
  4. package/dist/agents/construct.d.ts +3 -3
  5. package/dist/agents/dynamic-agent-prompt-builder.d.ts +3 -0
  6. package/dist/agents/index.d.ts +3 -3
  7. package/dist/agents/operator.d.ts +3 -3
  8. package/dist/agents/oracle/identity-constraints.d.ts +1 -1
  9. package/dist/agents/oracle/system-prompt.d.ts +2 -2
  10. package/dist/agents/trinity.d.ts +3 -3
  11. package/dist/cli/doctor/checks/auth.d.ts +2 -0
  12. package/dist/cli/doctor/checks/config.d.ts +2 -0
  13. package/dist/cli/doctor/checks/index.d.ts +10 -0
  14. package/dist/cli/doctor/checks/mcp.d.ts +2 -0
  15. package/dist/cli/doctor/checks/optional.d.ts +2 -0
  16. package/dist/cli/doctor/checks/plugin.d.ts +2 -0
  17. package/dist/cli/doctor/checks/runtime.d.ts +2 -0
  18. package/dist/cli/doctor/format.d.ts +3 -0
  19. package/dist/cli/doctor/index.d.ts +9 -0
  20. package/dist/cli/doctor/types.d.ts +24 -0
  21. package/dist/cli/index.d.ts +13 -0
  22. package/dist/cli/install/index.d.ts +12 -0
  23. package/dist/cli.js +927 -0
  24. package/dist/config/index.d.ts +1 -1
  25. package/dist/config/schema/dcp.d.ts +231 -2
  26. package/dist/config/schema/evolution.d.ts +89 -0
  27. package/dist/config/schema/headroom.d.ts +23 -0
  28. package/dist/config/schema/hooks.d.ts +7 -1
  29. package/dist/config/schema/matrixx-config.d.ts +134 -9
  30. package/dist/config/schema.d.ts +3 -3
  31. package/dist/create-hooks.d.ts +8 -3
  32. package/dist/create-managers.d.ts +0 -2
  33. package/dist/create-tools.d.ts +3 -3
  34. package/dist/features/background-agent/error-helpers.d.ts +0 -2
  35. package/dist/features/builtin-commands/templates/dcp-profile.d.ts +1 -1
  36. package/dist/features/builtin-commands/templates/evolution.d.ts +1 -0
  37. package/dist/features/builtin-commands/types.d.ts +1 -1
  38. package/dist/features/builtin-skills/types.d.ts +10 -1
  39. package/dist/features/command-loader/index.d.ts +1 -1
  40. package/dist/features/evolution/compressor/index.d.ts +5 -0
  41. package/dist/features/evolution/compressor/interface.d.ts +5 -0
  42. package/dist/features/evolution/compressor/llm.d.ts +12 -0
  43. package/dist/features/evolution/evaluator.d.ts +11 -0
  44. package/dist/features/evolution/index.d.ts +7 -0
  45. package/dist/features/evolution/pipeline.d.ts +7 -0
  46. package/dist/features/evolution/store.d.ts +22 -0
  47. package/dist/features/evolution/types.d.ts +51 -0
  48. package/dist/features/evolution/writer.d.ts +20 -0
  49. package/dist/features/task-storage/types.d.ts +2 -2
  50. package/dist/features/task-toast-manager/types.d.ts +2 -2
  51. package/dist/hooks/anthropic-context-window-limit-recovery/message-builder.d.ts +0 -1
  52. package/dist/hooks/anthropic-context-window-limit-recovery/tool-part-types.d.ts +2 -1
  53. package/dist/hooks/auto-slash-command/executor.d.ts +5 -2
  54. package/dist/hooks/auto-slash-command/hook.d.ts +4 -2
  55. package/dist/hooks/evolution-compressor/index.d.ts +15 -0
  56. package/dist/hooks/evolution-hitl/index.d.ts +12 -0
  57. package/dist/hooks/evolution-quality-gate/index.d.ts +6 -0
  58. package/dist/hooks/evolution-watcher/index.d.ts +21 -0
  59. package/dist/hooks/evolution-watcher/utils.d.ts +5 -0
  60. package/dist/hooks/index.d.ts +7 -1
  61. package/dist/hooks/keyword-detector/analyze/default.d.ts +1 -1
  62. package/dist/hooks/keyword-detector/constants.d.ts +1 -1
  63. package/dist/hooks/keyword-detector/search/default.d.ts +1 -1
  64. package/dist/hooks/keyword-detector/ultrawork/deepseek.d.ts +16 -0
  65. package/dist/hooks/keyword-detector/ultrawork/default.d.ts +5 -2
  66. package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +12 -0
  67. package/dist/hooks/keyword-detector/ultrawork/glm.d.ts +11 -0
  68. package/dist/hooks/keyword-detector/ultrawork/gpt5.2.d.ts +4 -7
  69. package/dist/hooks/keyword-detector/ultrawork/index.d.ts +12 -4
  70. package/dist/hooks/keyword-detector/ultrawork/mimo.d.ts +16 -0
  71. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +18 -6
  72. package/dist/hooks/matrix-loop/with-timeout.d.ts +1 -1
  73. package/dist/hooks/mcp-startup-notification/index.d.ts +9 -0
  74. package/dist/hooks/{prometheus-md-only → oracle-md-only}/constants.d.ts +2 -2
  75. package/dist/hooks/session-recovery/types.d.ts +2 -1
  76. package/dist/hooks/task-todo-mirror/constants.d.ts +3 -0
  77. package/dist/hooks/task-todo-mirror/hook.d.ts +43 -0
  78. package/dist/hooks/task-todo-mirror/index.d.ts +2 -0
  79. package/dist/hooks/think-mode/types.d.ts +3 -0
  80. package/dist/index.js +85417 -96112
  81. package/dist/matrixx.schema.json +5412 -0
  82. package/dist/mcp/index.d.ts +10 -1
  83. package/dist/mcp/mcp-startup-state.d.ts +4 -0
  84. package/dist/mcp/mcp-validator.d.ts +13 -0
  85. package/dist/plugin/hooks/create-continuation-hooks.d.ts +3 -1
  86. package/dist/plugin/hooks/create-core-hooks.d.ts +4 -1
  87. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
  88. package/dist/plugin/hooks/create-skill-hooks.d.ts +2 -2
  89. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +3 -1
  90. package/dist/plugin/skill-context.d.ts +2 -2
  91. package/dist/plugin/tool-registry.d.ts +1 -1
  92. package/dist/plugin-handlers/agent-config-handler.d.ts +1 -0
  93. package/dist/plugin-handlers/index.d.ts +1 -1
  94. package/dist/plugin-handlers/plan-model-inheritance.d.ts +1 -1
  95. package/dist/shared/delay.d.ts +1 -0
  96. package/dist/shared/error-formatting.d.ts +1 -0
  97. package/dist/shared/format-bytes.d.ts +1 -0
  98. package/dist/shared/format-bytes.test.d.ts +1 -0
  99. package/dist/shared/index.d.ts +7 -9
  100. package/dist/shared/is-abort-error.test.d.ts +1 -0
  101. package/dist/shared/model-resolution-pipeline.d.ts +26 -1
  102. package/dist/shared/opencode-config-dir.d.ts +13 -2
  103. package/dist/shared/sentinels.d.ts +2 -0
  104. package/dist/shared/session-state.d.ts +15 -0
  105. package/dist/shared/status-types.d.ts +1 -0
  106. package/dist/shared/system-directive.d.ts +1 -1
  107. package/dist/shared/with-timeout.d.ts +1 -0
  108. package/dist/shared/with-timeout.test.d.ts +1 -0
  109. package/dist/tools/background-task/delay.d.ts +1 -1
  110. package/dist/tools/dcp-switch-profile/index.d.ts +1 -0
  111. package/dist/tools/dcp-switch-profile/tools.d.ts +8 -0
  112. package/dist/tools/delegate-agent/constants.d.ts +1 -1
  113. package/dist/tools/delegate-task/constants.d.ts +1 -1
  114. package/dist/tools/delegate-task/skill-resolver.d.ts +2 -2
  115. package/dist/tools/index.d.ts +2 -1
  116. package/dist/tools/pdf-extract-figures/index.d.ts +1 -0
  117. package/dist/tools/pdf-extract-figures/tools.d.ts +11 -0
  118. package/dist/tools/skill/types.d.ts +3 -7
  119. package/dist/tools/slashcommand/skill-command-converter.d.ts +2 -2
  120. package/dist/tools/slashcommand/types.d.ts +10 -3
  121. package/dist/tools/task/todo-sync.d.ts +1 -1
  122. package/dist/tools/task/types.d.ts +5 -5
  123. package/package.json +15 -4
  124. package/dist/config/schema/model-capabilities.d.ts +0 -8
  125. package/dist/features/agent-loader/index.d.ts +0 -2
  126. package/dist/features/agent-loader/loader.d.ts +0 -3
  127. package/dist/features/agent-loader/types.d.ts +0 -14
  128. package/dist/features/command-loader/loader.d.ts +0 -3
  129. package/dist/features/mcp-oauth/callback-server.d.ts +0 -11
  130. package/dist/features/mcp-oauth/dcr.d.ts +0 -28
  131. package/dist/features/mcp-oauth/discovery.d.ts +0 -8
  132. package/dist/features/mcp-oauth/oauth-authorization-flow.d.ts +0 -26
  133. package/dist/features/mcp-oauth/provider.d.ts +0 -29
  134. package/dist/features/mcp-oauth/step-up.d.ts +0 -9
  135. package/dist/features/mcp-oauth/storage.d.ts +0 -17
  136. package/dist/features/opencode-skill-loader/allowed-tools-parser.d.ts +0 -1
  137. package/dist/features/opencode-skill-loader/config-source-discovery.d.ts +0 -7
  138. package/dist/features/opencode-skill-loader/index.d.ts +0 -14
  139. package/dist/features/opencode-skill-loader/loaded-skill-from-path.d.ts +0 -9
  140. package/dist/features/opencode-skill-loader/loaded-skill-template-extractor.d.ts +0 -2
  141. package/dist/features/opencode-skill-loader/loader.d.ts +0 -17
  142. package/dist/features/opencode-skill-loader/merger/builtin-skill-converter.d.ts +0 -3
  143. package/dist/features/opencode-skill-loader/merger/config-skill-entry-loader.d.ts +0 -3
  144. package/dist/features/opencode-skill-loader/merger/scope-priority.d.ts +0 -2
  145. package/dist/features/opencode-skill-loader/merger/skill-definition-merger.d.ts +0 -3
  146. package/dist/features/opencode-skill-loader/merger/skills-config-normalizer.d.ts +0 -11
  147. package/dist/features/opencode-skill-loader/merger.d.ts +0 -8
  148. package/dist/features/opencode-skill-loader/skill-content.d.ts +0 -4
  149. package/dist/features/opencode-skill-loader/skill-deduplication.d.ts +0 -2
  150. package/dist/features/opencode-skill-loader/skill-definition-record.d.ts +0 -3
  151. package/dist/features/opencode-skill-loader/skill-directory-loader.d.ts +0 -8
  152. package/dist/features/opencode-skill-loader/skill-discovery.d.ts +0 -4
  153. package/dist/features/opencode-skill-loader/skill-mcp-config.d.ts +0 -3
  154. package/dist/features/opencode-skill-loader/skill-resolution-options.d.ts +0 -7
  155. package/dist/features/opencode-skill-loader/skill-template-resolver.d.ts +0 -11
  156. package/dist/features/opencode-skill-loader/types.d.ts +0 -34
  157. package/dist/features/skill-mcp-manager/cleanup.d.ts +0 -7
  158. package/dist/features/skill-mcp-manager/connection-type.d.ts +0 -6
  159. package/dist/features/skill-mcp-manager/connection.d.ts +0 -14
  160. package/dist/features/skill-mcp-manager/env-cleaner.d.ts +0 -2
  161. package/dist/features/skill-mcp-manager/env-expander.d.ts +0 -1
  162. package/dist/features/skill-mcp-manager/http-client.d.ts +0 -3
  163. package/dist/features/skill-mcp-manager/index.d.ts +0 -2
  164. package/dist/features/skill-mcp-manager/manager.d.ts +0 -20
  165. package/dist/features/skill-mcp-manager/oauth-handler.d.ts +0 -8
  166. package/dist/features/skill-mcp-manager/stdio-client.d.ts +0 -3
  167. package/dist/features/skill-mcp-manager/types.d.ts +0 -68
  168. package/dist/hooks/runtime-fallback/is-abort-error.d.ts +0 -1
  169. package/dist/shared/is-object.d.ts +0 -1
  170. package/dist/shared/model-resolution-types.d.ts +0 -27
  171. package/dist/shared/model-resolver.d.ts +0 -24
  172. package/dist/shared/opencode-config-dir-types.d.ts +0 -13
  173. package/dist/shared/session-model-state.d.ts +0 -6
  174. package/dist/shared/session-temperature-store.d.ts +0 -3
  175. package/dist/shared/session-tools-store.d.ts +0 -3
  176. package/dist/tools/skill-mcp/constants.d.ts +0 -1
  177. package/dist/tools/skill-mcp/index.d.ts +0 -3
  178. package/dist/tools/skill-mcp/tools.d.ts +0 -11
  179. package/dist/tools/skill-mcp/types.d.ts +0 -8
  180. /package/dist/hooks/{prometheus-md-only → oracle-md-only}/agent-matcher.d.ts +0 -0
  181. /package/dist/hooks/{prometheus-md-only → oracle-md-only}/agent-resolution.d.ts +0 -0
  182. /package/dist/hooks/{prometheus-md-only → oracle-md-only}/hook.d.ts +0 -0
  183. /package/dist/hooks/{prometheus-md-only → oracle-md-only}/index.d.ts +0 -0
  184. /package/dist/hooks/{prometheus-md-only → oracle-md-only}/path-policy.d.ts +0 -0
  185. /package/dist/plugin-handlers/{prometheus-agent-config-builder.d.ts → oracle-agent-config-builder.d.ts} +0 -0
  186. /package/dist/{hooks/architect → shared}/is-abort-error.d.ts +0 -0
package/dist/cli.js ADDED
@@ -0,0 +1,927 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // src/cli/index.ts
5
+ import { readFileSync as readFileSync5 } from "fs";
6
+ import { dirname, join as join5 } from "path";
7
+ import { fileURLToPath } from "url";
8
+
9
+ // src/cli/doctor/checks/auth.ts
10
+ import { existsSync, readFileSync } from "fs";
11
+ import { homedir } from "os";
12
+ import { join } from "path";
13
+ var OPENCODE_CONFIG_PATHS = [
14
+ join(homedir(), ".config", "opencode", "opencode.json"),
15
+ join(homedir(), ".config", "opencode", "opencode.jsonc")
16
+ ];
17
+ var AUTH_JSON_PATHS = [
18
+ join(homedir(), ".local", "share", "opencode", "auth.json"),
19
+ join(homedir(), ".config", "opencode", "auth.json")
20
+ ];
21
+ function stripJsonComments(text) {
22
+ return text.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
23
+ }
24
+ function collectConfigText() {
25
+ let combined = "";
26
+ for (const p of OPENCODE_CONFIG_PATHS) {
27
+ if (!existsSync(p))
28
+ continue;
29
+ try {
30
+ const raw = readFileSync(p, "utf-8");
31
+ combined += ` ${stripJsonComments(raw)}`;
32
+ } catch {}
33
+ }
34
+ return combined.toLowerCase();
35
+ }
36
+ function collectAuthText() {
37
+ let combined = "";
38
+ for (const p of AUTH_JSON_PATHS) {
39
+ if (!existsSync(p))
40
+ continue;
41
+ try {
42
+ const raw = readFileSync(p, "utf-8");
43
+ combined += ` ${raw}`;
44
+ } catch {}
45
+ }
46
+ try {
47
+ const result = Bun.spawnSync(["opencode", "auth", "list", "--json"], { stdout: "pipe", stderr: "pipe" });
48
+ if (result.exitCode === 0)
49
+ combined += ` ${result.stdout.toString()}`;
50
+ } catch {}
51
+ return combined.toLowerCase();
52
+ }
53
+ function hasProvider(haystack, keywords) {
54
+ return keywords.some((k) => haystack.includes(k));
55
+ }
56
+ function getProviderStatuses() {
57
+ const results = [
58
+ { provider: "Anthropic", configured: false },
59
+ { provider: "OpenAI", configured: false },
60
+ { provider: "Google", configured: false }
61
+ ];
62
+ const configText = collectConfigText();
63
+ const authText = collectAuthText();
64
+ const combinedAuthConfig = `${configText} ${authText}`;
65
+ const hasAnyConfigFile = OPENCODE_CONFIG_PATHS.some(existsSync) || AUTH_JSON_PATHS.some(existsSync);
66
+ if (!hasAnyConfigFile && !combinedAuthConfig.trim()) {
67
+ if (process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY) {} else {
68
+ return results.map((r) => ({ ...r, detail: "No opencode config or auth storage found \u2014 run `opencode auth login`" }));
69
+ }
70
+ }
71
+ const providerChecks = {
72
+ Anthropic: ["anthropic", "claude"],
73
+ OpenAI: ["openai"],
74
+ Google: ["google", "gemini", "vertex"]
75
+ };
76
+ for (const r of results) {
77
+ const keywords = providerChecks[r.provider] ?? [r.provider.toLowerCase()];
78
+ const inConfig = hasProvider(configText, keywords);
79
+ const inAuth = hasProvider(authText, keywords);
80
+ if (inConfig || inAuth) {
81
+ r.configured = true;
82
+ r.detail = inAuth ? "Provider found in auth storage" : "Provider found in opencode config";
83
+ } else {
84
+ r.detail = "Provider not configured \u2014 run `opencode auth login` or set env var";
85
+ }
86
+ }
87
+ if (process.env.ANTHROPIC_API_KEY) {
88
+ results[0].configured = true;
89
+ results[0].detail = "ANTHROPIC_API_KEY env var set";
90
+ }
91
+ if (process.env.OPENAI_API_KEY) {
92
+ results[1].configured = true;
93
+ results[1].detail = "OPENAI_API_KEY env var set";
94
+ }
95
+ if (process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY) {
96
+ results[2].configured = true;
97
+ results[2].detail = "Google/Gemini API key env var set";
98
+ }
99
+ return results;
100
+ }
101
+ var authCheck = {
102
+ name: "authentication",
103
+ category: "authentication",
104
+ check: () => {
105
+ const providers = getProviderStatuses();
106
+ const configured = providers.filter((p) => p.configured);
107
+ const unconfigured = providers.filter((p) => !p.configured);
108
+ if (configured.length === 0) {
109
+ return {
110
+ name: "authentication",
111
+ status: "fail",
112
+ message: "No API providers configured",
113
+ detail: providers.map((p) => ` ${p.provider}: ${p.detail ?? "not configured"}`).join(`
114
+ `)
115
+ };
116
+ }
117
+ const configuredList = configured.map((p) => p.provider).join(", ");
118
+ const warnings = unconfigured.map((p) => p.provider).join(", ");
119
+ if (unconfigured.length > 0) {
120
+ return {
121
+ name: "authentication",
122
+ status: "warn",
123
+ message: `Configured: ${configuredList}. Missing: ${warnings}`,
124
+ detail: `Missing providers:
125
+ ${unconfigured.map((p) => ` ${p.provider}: ${p.detail ?? "not configured"}`).join(`
126
+ `)}`
127
+ };
128
+ }
129
+ return {
130
+ name: "authentication",
131
+ status: "pass",
132
+ message: `All providers configured: ${configuredList}`
133
+ };
134
+ }
135
+ };
136
+
137
+ // src/cli/doctor/checks/config.ts
138
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
139
+ import { homedir as homedir2 } from "os";
140
+ import { join as join2 } from "path";
141
+ var MATRIX_CONFIG_PATHS = [
142
+ join2(process.cwd(), "matrixx.json"),
143
+ join2(process.cwd(), "matrixx.jsonc"),
144
+ join2(process.cwd(), ".opencode", "matrixx.json"),
145
+ join2(homedir2(), ".config", "opencode", "matrixx.json"),
146
+ join2(homedir2(), ".config", "opencode", "matrixx.jsonc")
147
+ ];
148
+ function findMatrixxConfig() {
149
+ for (const p of MATRIX_CONFIG_PATHS) {
150
+ if (existsSync2(p)) {
151
+ try {
152
+ const content = readFileSync2(p, "utf-8");
153
+ return { path: p, content };
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+ }
159
+ return null;
160
+ }
161
+ function tryParseJSON(text) {
162
+ try {
163
+ JSON.parse(text);
164
+ return { valid: true };
165
+ } catch (err) {
166
+ return { valid: false, error: String(err) };
167
+ }
168
+ }
169
+ var configValidationCheck = {
170
+ name: "config-validation",
171
+ category: "configuration",
172
+ check: () => {
173
+ const found = findMatrixxConfig();
174
+ if (!found) {
175
+ return {
176
+ name: "config-validation",
177
+ status: "warn",
178
+ message: "No matrixx configuration file found",
179
+ detail: "Create matrixx.jsonc in your project or ~/.config/opencode/"
180
+ };
181
+ }
182
+ const parseResult = tryParseJSON(found.content);
183
+ if (!parseResult.valid) {
184
+ const hasJsoncSigns = found.content.includes("//") || found.content.includes("/*") || found.content.includes(",,");
185
+ if (hasJsoncSigns) {
186
+ return {
187
+ name: "config-validation",
188
+ status: "warn",
189
+ message: `Config file has comments/trailing commas (JSONC), may need JSONC parser`,
190
+ detail: `Path: ${found.path}`
191
+ };
192
+ }
193
+ return {
194
+ name: "config-validation",
195
+ status: "fail",
196
+ message: `Invalid JSON in config: ${parseResult.error}`,
197
+ detail: `Path: ${found.path}`
198
+ };
199
+ }
200
+ return {
201
+ name: "config-validation",
202
+ status: "pass",
203
+ message: `Configuration file is valid at ${found.path}`
204
+ };
205
+ }
206
+ };
207
+
208
+ // src/cli/doctor/checks/mcp.ts
209
+ function checkUvxVersion() {
210
+ try {
211
+ const r = Bun.spawnSync(["uvx", "--version"], { stdout: "pipe", stderr: "pipe" });
212
+ if (r.exitCode === 0) {
213
+ return r.stdout.toString().trim().split(`
214
+ `)[0]?.replace(/^uvx\s+/i, "") || null;
215
+ }
216
+ } catch {}
217
+ return null;
218
+ }
219
+ var mcpPrerequisitesCheck = {
220
+ name: "mcp-prerequisites",
221
+ category: "dependencies",
222
+ check: () => {
223
+ const uvxVersion = checkUvxVersion();
224
+ if (!uvxVersion) {
225
+ return {
226
+ name: "mcp-prerequisites",
227
+ status: "fail",
228
+ message: "uvx (uv) not found \u2014 required for the document_reader MCP",
229
+ detail: `Install uv/uvx: curl -LsSf https://astral.sh/uv/install.sh | sh
230
+ ` + `Then run once to warm the markitdown-mcp cache:
231
+ ` + " uvx --from markitdown-mcp markitdown-mcp --help"
232
+ };
233
+ }
234
+ try {
235
+ const warm = Bun.spawnSync(["uvx", "--from", "markitdown-mcp", "markitdown-mcp", "--help"], { stdout: "pipe", stderr: "pipe", timeout: 120000 });
236
+ const output = `${warm.stdout.toString()}${warm.stderr.toString()}`;
237
+ if (warm.exitCode === 0 || output.includes("MarkItDown")) {
238
+ return {
239
+ name: "mcp-prerequisites",
240
+ status: "pass",
241
+ message: `uvx ${uvxVersion} found; markitdown-mcp cache warm`,
242
+ detail: output.trim() || undefined
243
+ };
244
+ }
245
+ return {
246
+ name: "mcp-prerequisites",
247
+ status: "warn",
248
+ message: `uvx ${uvxVersion} found but markitdown-mcp could not resolve`,
249
+ detail: output.trim() || undefined
250
+ };
251
+ } catch {
252
+ return {
253
+ name: "mcp-prerequisites",
254
+ status: "warn",
255
+ message: `uvx ${uvxVersion} found but warm-up timed out (network?)`,
256
+ detail: "Retry later: uvx --from markitdown-mcp markitdown-mcp --help"
257
+ };
258
+ }
259
+ }
260
+ };
261
+
262
+ // src/cli/doctor/checks/optional.ts
263
+ var BINARY_CHECKS = [
264
+ {
265
+ name: "ast-grep (sg)",
266
+ check: () => {
267
+ try {
268
+ const r = Bun.spawnSync(["sg", "--version"], { stdout: "pipe", stderr: "pipe" });
269
+ return { available: r.exitCode === 0, version: r.stdout.toString().trim() };
270
+ } catch {
271
+ return { available: false };
272
+ }
273
+ }
274
+ },
275
+ {
276
+ name: "Gitleaks",
277
+ check: () => {
278
+ try {
279
+ const r = Bun.spawnSync(["gitleaks", "--version"], { stdout: "pipe", stderr: "pipe" });
280
+ return { available: r.exitCode === 0, version: r.stdout.toString().trim() };
281
+ } catch {
282
+ return { available: false };
283
+ }
284
+ }
285
+ }
286
+ ];
287
+ var PYTHON_CHECKS = [
288
+ {
289
+ name: "PyMuPDF (fitz)",
290
+ check: () => {
291
+ try {
292
+ const r = Bun.spawnSync(["python3", "-c", "import fitz; print(fitz.__version__)"], {
293
+ stdout: "pipe",
294
+ stderr: "pipe"
295
+ });
296
+ return { available: r.exitCode === 0, version: r.stdout.toString().trim() };
297
+ } catch {
298
+ return { available: false };
299
+ }
300
+ }
301
+ },
302
+ {
303
+ name: "Playwright (CLI)",
304
+ check: () => {
305
+ try {
306
+ const r = Bun.spawnSync(["playwright", "--version"], { stdout: "pipe", stderr: "pipe" });
307
+ return { available: r.exitCode === 0, version: r.stdout.toString().trim() };
308
+ } catch {
309
+ return { available: false };
310
+ }
311
+ }
312
+ }
313
+ ];
314
+ var optionalToolsCheck = {
315
+ name: "optional-tools",
316
+ category: "tools",
317
+ check: () => {
318
+ const binaryResults = BINARY_CHECKS.map((t) => {
319
+ const result = t.check();
320
+ return { name: t.name, ...result };
321
+ });
322
+ let pythonResults = [];
323
+ try {
324
+ const pyCheck = Bun.spawnSync(["python3", "--version"], { stdout: "pipe", stderr: "pipe" });
325
+ if (pyCheck.exitCode === 0) {
326
+ pythonResults = PYTHON_CHECKS.map((t) => {
327
+ const result = t.check();
328
+ return { name: t.name, ...result };
329
+ });
330
+ } else {
331
+ pythonResults = PYTHON_CHECKS.map((t) => ({
332
+ name: t.name,
333
+ available: false,
334
+ version: undefined
335
+ }));
336
+ }
337
+ } catch {
338
+ pythonResults = PYTHON_CHECKS.map((t) => ({
339
+ name: t.name,
340
+ available: false,
341
+ version: undefined
342
+ }));
343
+ }
344
+ const allResults = [...binaryResults, ...pythonResults];
345
+ const available = allResults.filter((r) => r.available);
346
+ const missing = allResults.filter((r) => !r.available);
347
+ if (missing.length === 0) {
348
+ return {
349
+ name: "optional-tools",
350
+ status: "pass",
351
+ message: `All optional tools available: ${available.map((r) => r.name).join(", ")}`
352
+ };
353
+ }
354
+ const detailLines = allResults.map((r) => {
355
+ if (r.available) {
356
+ return ` \u2713 ${r.name}${r.version ? ` (${r.version})` : ""}`;
357
+ }
358
+ return ` \u2717 ${r.name} \u2014 not installed`;
359
+ });
360
+ const missingList = missing.map((r) => r.name).join(", ");
361
+ return {
362
+ name: "optional-tools",
363
+ status: "warn",
364
+ message: `Available: ${available.length}, Missing: ${missing.length} (${missingList})`,
365
+ detail: detailLines.join(`
366
+ `)
367
+ };
368
+ }
369
+ };
370
+
371
+ // src/cli/doctor/checks/plugin.ts
372
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
373
+ import { homedir as homedir3 } from "os";
374
+ import { join as join3 } from "path";
375
+ var OPECODE_CONFIG_PATHS = [
376
+ join3(homedir3(), ".config", "opencode", "opencode.json"),
377
+ join3(homedir3(), ".config", "opencode", "opencode.jsonc")
378
+ ];
379
+ function findOpenCodeConfig() {
380
+ for (const p of OPECODE_CONFIG_PATHS) {
381
+ if (existsSync3(p))
382
+ return p;
383
+ }
384
+ return null;
385
+ }
386
+ function checkOpenCodeVersion() {
387
+ try {
388
+ const result = Bun.spawnSync(["opencode", "--version"], {
389
+ stdout: "pipe",
390
+ stderr: "pipe"
391
+ });
392
+ if (result.exitCode === 0) {
393
+ return result.stdout.toString().trim();
394
+ }
395
+ } catch {}
396
+ return null;
397
+ }
398
+ var pluginInstallationCheck = {
399
+ name: "plugin-installation",
400
+ category: "installation",
401
+ check: () => {
402
+ const version = checkOpenCodeVersion();
403
+ if (!version) {
404
+ return {
405
+ name: "plugin-installation",
406
+ status: "fail",
407
+ message: "OpenCode CLI not found in PATH",
408
+ detail: "Install OpenCode first: https://opencode.ai/docs"
409
+ };
410
+ }
411
+ const semverMatch = version.match(/(\d+)\.(\d+)\.(\d+)/);
412
+ if (!semverMatch) {
413
+ return {
414
+ name: "plugin-installation",
415
+ status: "warn",
416
+ message: `OpenCode version: ${version} (unable to parse)`
417
+ };
418
+ }
419
+ const major = Number(semverMatch[1]);
420
+ const minor = Number(semverMatch[2]);
421
+ const meetsMinVersion = major >= 1 && minor >= 0;
422
+ const configPath = findOpenCodeConfig();
423
+ if (!configPath) {
424
+ return {
425
+ name: "plugin-installation",
426
+ status: "warn",
427
+ message: `OpenCode ${version} installed, but opencode.json not found`,
428
+ detail: "Run `opencode` once to generate the config file"
429
+ };
430
+ }
431
+ let configContent;
432
+ try {
433
+ configContent = readFileSync3(configPath, "utf-8");
434
+ } catch {
435
+ return {
436
+ name: "plugin-installation",
437
+ status: "fail",
438
+ message: `Cannot read config: ${configPath}`
439
+ };
440
+ }
441
+ const hasPlugin = configContent.includes("opencode-matrixx") || configContent.includes("@klpanagi/opencode-matrixx");
442
+ if (!meetsMinVersion) {
443
+ return {
444
+ name: "plugin-installation",
445
+ status: "fail",
446
+ message: `OpenCode ${version} is below minimum 1.0.150`,
447
+ detail: "Update OpenCode to use Matrixx plugin"
448
+ };
449
+ }
450
+ if (!hasPlugin) {
451
+ return {
452
+ name: "plugin-installation",
453
+ status: "warn",
454
+ message: `OpenCode ${version} installed, plugin not registered in ${configPath}`,
455
+ detail: "Run `bunx opencode-matrixx install` to register the plugin"
456
+ };
457
+ }
458
+ return {
459
+ name: "plugin-installation",
460
+ status: "pass",
461
+ message: `OpenCode ${version}, plugin registered in ${configPath}`
462
+ };
463
+ }
464
+ };
465
+
466
+ // src/cli/doctor/checks/runtime.ts
467
+ function checkCommand(cmd, arg = "--version") {
468
+ try {
469
+ const result = Bun.spawnSync([cmd, arg], {
470
+ stdout: "pipe",
471
+ stderr: "pipe"
472
+ });
473
+ if (result.exitCode === 0) {
474
+ return result.stdout.toString().trim().split(`
475
+ `)[0] || null;
476
+ }
477
+ } catch {}
478
+ return null;
479
+ }
480
+ function getRuntimeVersions() {
481
+ const runtimes = [
482
+ { name: "Bun", version: checkCommand("bun"), status: "fail" },
483
+ { name: "Node.js", version: checkCommand("node"), status: "fail" },
484
+ { name: "Git", version: checkCommand("git"), status: "fail" },
485
+ { name: "Python3", version: checkCommand("python3", "--version"), status: "fail" }
486
+ ];
487
+ for (const r of runtimes) {
488
+ if (r.version) {
489
+ r.status = "pass";
490
+ }
491
+ }
492
+ return runtimes;
493
+ }
494
+ var runtimeDepsCheck = {
495
+ name: "runtime-dependencies",
496
+ category: "dependencies",
497
+ check: () => {
498
+ const runtimes = getRuntimeVersions();
499
+ const passed = runtimes.filter((r) => r.status === "pass");
500
+ const failed = runtimes.filter((r) => r.status === "fail");
501
+ if (failed.length === 0) {
502
+ return {
503
+ name: "runtime-dependencies",
504
+ status: "pass",
505
+ message: `All runtimes found: ${passed.map((r) => `${r.name} ${r.version}`).join(", ")}`
506
+ };
507
+ }
508
+ const missingList = failed.map((r) => r.name).join(", ");
509
+ const detailLines = [];
510
+ for (const r of runtimes) {
511
+ const status = r.version ? `${r.version}` : "NOT FOUND";
512
+ detailLines.push(` ${r.name}: ${status}`);
513
+ }
514
+ if (failed.length <= passed.length) {
515
+ return {
516
+ name: "runtime-dependencies",
517
+ status: "warn",
518
+ message: `Found: ${passed.map((r) => r.name).join(", ")}. Missing: ${missingList}`,
519
+ detail: detailLines.join(`
520
+ `)
521
+ };
522
+ }
523
+ return {
524
+ name: "runtime-dependencies",
525
+ status: "fail",
526
+ message: `Critical runtimes missing: ${missingList}`,
527
+ detail: detailLines.join(`
528
+ `)
529
+ };
530
+ }
531
+ };
532
+
533
+ // src/cli/doctor/checks/index.ts
534
+ var ALL_CHECKS = [
535
+ pluginInstallationCheck,
536
+ configValidationCheck,
537
+ authCheck,
538
+ runtimeDepsCheck,
539
+ optionalToolsCheck,
540
+ mcpPrerequisitesCheck
541
+ ];
542
+ function getChecksByCategory(category) {
543
+ return ALL_CHECKS.filter((c) => c.category === category);
544
+ }
545
+
546
+ // src/cli/doctor/format.ts
547
+ var STATUS_ICONS = {
548
+ pass: "\u2713",
549
+ warn: "\u26A0",
550
+ fail: "\u2717"
551
+ };
552
+ function padRight(s, len) {
553
+ return s.length >= len ? s : s + " ".repeat(len - s.length);
554
+ }
555
+ function formatDoctorReport(report) {
556
+ const lines = [];
557
+ const boxWidth = 60;
558
+ lines.push("");
559
+ lines.push(`\u250C${"\u2500".repeat(boxWidth - 2)}\u2510`);
560
+ lines.push(`\u2502${padRight(" Matrixx Doctor", boxWidth - 1)}\u2502`);
561
+ lines.push(`\u2514${"\u2500".repeat(boxWidth - 2)}\u2518`);
562
+ lines.push("");
563
+ const grouped = new Map;
564
+ for (const check of report.checks) {
565
+ const cat = check.name.split("-")[0] || "other";
566
+ if (!grouped.has(cat))
567
+ grouped.set(cat, []);
568
+ grouped.get(cat)?.push(check);
569
+ }
570
+ for (const [category, checks] of grouped) {
571
+ lines.push(category.charAt(0).toUpperCase() + category.slice(1));
572
+ for (const c of checks) {
573
+ const icon = STATUS_ICONS[c.status] || "?";
574
+ const label = padRight(` ${icon} ${c.message}`, boxWidth - 4);
575
+ lines.push(label);
576
+ if (c.detail) {
577
+ const detailLines = c.detail.split(`
578
+ `);
579
+ for (const dl of detailLines) {
580
+ lines.push(` ${dl}`);
581
+ }
582
+ }
583
+ }
584
+ lines.push("");
585
+ }
586
+ const s = report.summary;
587
+ lines.push(`Summary: ${s.passed} passed, ${s.warnings} warning(s), ${s.failed} failed`);
588
+ lines.push("");
589
+ return lines.join(`
590
+ `);
591
+ }
592
+ function formatDoctorJson(report) {
593
+ return JSON.stringify(report, null, 2);
594
+ }
595
+
596
+ // src/cli/doctor/index.ts
597
+ async function runDoctor(options = {}) {
598
+ const checks = options.category ? getChecksByCategory(options.category) : ALL_CHECKS;
599
+ if (checks.length === 0) {
600
+ const _available = [...new Set(ALL_CHECKS.map((c) => c.category))];
601
+ return {
602
+ timestamp: new Date().toISOString(),
603
+ checks: [],
604
+ summary: { total: 0, passed: 0, warnings: 0, failed: 0 }
605
+ };
606
+ }
607
+ const results = [];
608
+ for (const check of checks) {
609
+ try {
610
+ const result = await Promise.resolve(check.check());
611
+ result.category = check.category;
612
+ results.push(result);
613
+ } catch (err) {
614
+ results.push({
615
+ name: check.name,
616
+ category: check.category,
617
+ status: "fail",
618
+ message: `Check threw an exception: ${err instanceof Error ? err.message : String(err)}`
619
+ });
620
+ }
621
+ }
622
+ const passed = results.filter((r) => r.status === "pass").length;
623
+ const warnings = results.filter((r) => r.status === "warn").length;
624
+ const failed = results.filter((r) => r.status === "fail").length;
625
+ return {
626
+ timestamp: new Date().toISOString(),
627
+ checks: results,
628
+ summary: { total: results.length, passed, warnings, failed }
629
+ };
630
+ }
631
+ async function executeDoctor(options = {}) {
632
+ const report = await runDoctor(options);
633
+ if (options.json) {
634
+ return formatDoctorJson(report);
635
+ }
636
+ return formatDoctorReport(report);
637
+ }
638
+
639
+ // src/cli/install/index.ts
640
+ import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
641
+ import { homedir as homedir4 } from "os";
642
+ import { join as join4 } from "path";
643
+ function getOpenCodeConfigPath() {
644
+ const configDir = join4(homedir4(), ".config", "opencode");
645
+ const jsonPath = join4(configDir, "opencode.json");
646
+ const jsoncPath = join4(configDir, "opencode.jsonc");
647
+ if (existsSync4(jsoncPath))
648
+ return jsoncPath;
649
+ return jsonPath;
650
+ }
651
+ function stripJsonComments2(text) {
652
+ return text.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
653
+ }
654
+ function parseOpenCodeConfig(content) {
655
+ try {
656
+ const stripped = stripJsonComments2(content);
657
+ return JSON.parse(stripped);
658
+ } catch {
659
+ return {};
660
+ }
661
+ }
662
+ function hasExistingPluginRegistration(configPath) {
663
+ if (!existsSync4(configPath))
664
+ return false;
665
+ try {
666
+ const content = readFileSync4(configPath, "utf-8");
667
+ return content.includes("opencode-matrixx");
668
+ } catch {
669
+ return false;
670
+ }
671
+ }
672
+ function isLocalRepoCheckout(dir) {
673
+ return existsSync4(join4(dir, "src", "index.ts")) && existsSync4(join4(dir, "package.json"));
674
+ }
675
+ function generatePluginEntry(absolutePath, forceLocal) {
676
+ const looksLocal = forceLocal || isLocalRepoCheckout(absolutePath);
677
+ if (looksLocal) {
678
+ const distEntry = join4(absolutePath, "dist", "index.js");
679
+ if (existsSync4(distEntry))
680
+ return `file://${distEntry}`;
681
+ if (existsSync4(absolutePath))
682
+ return `file://${absolutePath}`;
683
+ }
684
+ return "opencode-matrixx";
685
+ }
686
+ async function executeInstall(options) {
687
+ const configDir = join4(homedir4(), ".config", "opencode");
688
+ const configPath = getOpenCodeConfigPath();
689
+ if (!existsSync4(configDir)) {
690
+ mkdirSync(configDir, { recursive: true });
691
+ }
692
+ if (hasExistingPluginRegistration(configPath)) {
693
+ return `\u2713 Plugin already registered in ${configPath}`;
694
+ }
695
+ const cwd = process.cwd();
696
+ const pluginEntry = generatePluginEntry(cwd, options.local);
697
+ let config;
698
+ if (existsSync4(configPath)) {
699
+ try {
700
+ const content = readFileSync4(configPath, "utf-8");
701
+ config = parseOpenCodeConfig(content);
702
+ } catch {
703
+ config = {};
704
+ }
705
+ } else {
706
+ config = {};
707
+ }
708
+ if (!config.plugin) {
709
+ config.plugin = [];
710
+ }
711
+ if (!config.plugin.includes(pluginEntry)) {
712
+ config.plugin.push(pluginEntry);
713
+ }
714
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
715
+ `);
716
+ const flags = [];
717
+ if (options.claude)
718
+ flags.push(`Claude: ${options.claude}`);
719
+ if (options.openai)
720
+ flags.push(`OpenAI: ${options.openai}`);
721
+ if (options.gemini)
722
+ flags.push(`Gemini: ${options.gemini}`);
723
+ if (options.copilot)
724
+ flags.push(`Copilot: ${options.copilot}`);
725
+ if (options.opencodeZen)
726
+ flags.push(`OpenCode Zen: ${options.opencodeZen}`);
727
+ if (options.zaiCodingPlan)
728
+ flags.push(`Z.ai: ${options.zaiCodingPlan}`);
729
+ const parts = [
730
+ "",
731
+ "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
732
+ "\u2502 Matrixx Install Complete \u2502",
733
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
734
+ "",
735
+ `\u2713 Plugin registered in ${configPath}`,
736
+ ` Entry: ${pluginEntry}`,
737
+ ""
738
+ ];
739
+ if (flags.length > 0) {
740
+ parts.push(" Subscriptions:");
741
+ for (const f of flags) {
742
+ parts.push(` ${f}`);
743
+ }
744
+ parts.push("");
745
+ }
746
+ parts.push(" Next steps:");
747
+ parts.push(" 1. Configure authentication via `opencode auth login`");
748
+ parts.push(" 2. Verify with `bunx opencode-matrixx doctor`");
749
+ if (pluginEntry === "opencode-matrixx") {
750
+ parts.push(" 3. Restart OpenCode to load the plugin");
751
+ } else {
752
+ parts.push(" 3. Run `bun run build` in the repo, then restart OpenCode");
753
+ }
754
+ parts.push("");
755
+ return parts.join(`
756
+ `);
757
+ }
758
+
759
+ // src/cli/index.ts
760
+ function getVersion() {
761
+ try {
762
+ const thisDir = dirname(fileURLToPath(import.meta.url));
763
+ const candidates = [
764
+ join5(thisDir, "../../package.json"),
765
+ join5(thisDir, "../package.json"),
766
+ "package.json"
767
+ ];
768
+ for (const p of candidates) {
769
+ try {
770
+ const raw = readFileSync5(p, "utf-8");
771
+ const pkg = JSON.parse(raw);
772
+ if (pkg.version && typeof pkg.version === "string")
773
+ return pkg.version;
774
+ } catch {}
775
+ }
776
+ } catch {}
777
+ return "2.6.0";
778
+ }
779
+ var VERSION = getVersion();
780
+ function printHelp() {
781
+ console.log(`
782
+ Matrixx CLI v${VERSION}
783
+
784
+ Usage: bunx opencode-matrixx <command> [options]
785
+
786
+ Commands:
787
+ doctor Environment diagnostics and health checks
788
+ install Interactive setup wizard
789
+ version Display version information
790
+ help Display this help message
791
+
792
+ Options:
793
+ --help, -h Show help for any command
794
+ --json (doctor) Output results as JSON
795
+ --category (doctor) Check specific category only
796
+ --no-tui (install) Run in non-interactive mode (CI/CD)
797
+ --local (install) Use local repo file:// path (dev only)
798
+ --verbose (install) Display detailed logs
799
+
800
+ Doctor categories:
801
+ installation Plugin registration and OpenCode version
802
+ configuration Config file validation
803
+ authentication Provider API key status
804
+ dependencies Runtime dependencies (Bun, Node, Git, Python)
805
+ tools Optional tools (ast-grep, Gitleaks, PyMuPDF, Playwright)
806
+
807
+ Subscription flags (install --no-tui):
808
+ --claude=<yes|no|max20>
809
+ --openai=<yes|no>
810
+ --gemini=<yes|no>
811
+ --copilot=<yes|no>
812
+ --opencode-zen=<yes|no>
813
+ --zai-coding-plan=<yes|no>
814
+ `);
815
+ }
816
+ function parseArgs(argv) {
817
+ const result = {
818
+ command: "",
819
+ help: false,
820
+ json: false,
821
+ noTui: false,
822
+ verbose: false,
823
+ local: false,
824
+ extra: []
825
+ };
826
+ let args = argv.slice(2);
827
+ if (args.length === 0) {
828
+ result.help = true;
829
+ return result;
830
+ }
831
+ result.command = args[0];
832
+ args = args.slice(1);
833
+ for (let i = 0;i < args.length; i++) {
834
+ const a = args[i];
835
+ if (a === "--help" || a === "-h") {
836
+ result.help = true;
837
+ } else if (a === "--json") {
838
+ result.json = true;
839
+ } else if (a === "--no-tui") {
840
+ result.noTui = true;
841
+ } else if (a === "--local") {
842
+ result.local = true;
843
+ } else if (a === "--verbose") {
844
+ result.verbose = true;
845
+ } else if (a.startsWith("--category=")) {
846
+ result.category = a.slice("--category=".length);
847
+ } else if (a === "--category" && i + 1 < args.length) {
848
+ result.category = args[++i];
849
+ } else if (a.startsWith("--claude=")) {
850
+ const v = a.slice("--claude=".length);
851
+ if (["yes", "no", "max20"].includes(v))
852
+ result.claude = v;
853
+ } else if (a.startsWith("--openai=")) {
854
+ const v = a.slice("--openai=".length);
855
+ if (["yes", "no"].includes(v))
856
+ result.openai = v;
857
+ } else if (a.startsWith("--gemini=")) {
858
+ const v = a.slice("--gemini=".length);
859
+ if (["yes", "no"].includes(v))
860
+ result.gemini = v;
861
+ } else if (a.startsWith("--copilot=")) {
862
+ const v = a.slice("--copilot=".length);
863
+ if (["yes", "no"].includes(v))
864
+ result.copilot = v;
865
+ } else if (a.startsWith("--opencode-zen=")) {
866
+ const v = a.slice("--opencode-zen=".length);
867
+ if (["yes", "no"].includes(v))
868
+ result.opencodeZen = v;
869
+ } else if (a.startsWith("--zai-coding-plan=")) {
870
+ const v = a.slice("--zai-coding-plan=".length);
871
+ if (["yes", "no"].includes(v))
872
+ result.zaiCodingPlan = v;
873
+ } else {
874
+ result.extra.push(a);
875
+ }
876
+ }
877
+ return result;
878
+ }
879
+ async function main() {
880
+ const args = parseArgs(process.argv);
881
+ if (!args.command || args.command === "help" || args.help) {
882
+ printHelp();
883
+ return;
884
+ }
885
+ if (args.command === "version") {
886
+ console.log(VERSION);
887
+ return;
888
+ }
889
+ if (args.command === "doctor") {
890
+ const output = await executeDoctor({
891
+ category: args.category,
892
+ json: args.json
893
+ });
894
+ console.log(output);
895
+ return;
896
+ }
897
+ if (args.command === "install") {
898
+ const output = await executeInstall({
899
+ noTui: args.noTui,
900
+ verbose: args.verbose,
901
+ local: args.local,
902
+ claude: args.claude,
903
+ openai: args.openai,
904
+ gemini: args.gemini,
905
+ copilot: args.copilot,
906
+ opencodeZen: args.opencodeZen,
907
+ zaiCodingPlan: args.zaiCodingPlan
908
+ });
909
+ console.log(output);
910
+ return;
911
+ }
912
+ console.error(`Unknown command: ${args.command}
913
+ `);
914
+ printHelp();
915
+ process.exit(1);
916
+ }
917
+ var cli_default = main;
918
+ if (import.meta.main) {
919
+ main().catch((err) => {
920
+ console.error("Fatal error:", err);
921
+ process.exit(1);
922
+ });
923
+ }
924
+ export {
925
+ cli_default as default,
926
+ main
927
+ };