@zhixuan92/multi-model-agent 3.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 (169) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +217 -0
  3. package/dist/cli/index.d.ts +61 -0
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +252 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/install-skill.d.ts +158 -0
  8. package/dist/cli/install-skill.d.ts.map +1 -0
  9. package/dist/cli/install-skill.js +425 -0
  10. package/dist/cli/install-skill.js.map +1 -0
  11. package/dist/cli/print-token.d.ts +18 -0
  12. package/dist/cli/print-token.d.ts.map +1 -0
  13. package/dist/cli/print-token.js +60 -0
  14. package/dist/cli/print-token.js.map +1 -0
  15. package/dist/cli/serve.d.ts +44 -0
  16. package/dist/cli/serve.d.ts.map +1 -0
  17. package/dist/cli/serve.js +61 -0
  18. package/dist/cli/serve.js.map +1 -0
  19. package/dist/cli/status.d.ts +49 -0
  20. package/dist/cli/status.d.ts.map +1 -0
  21. package/dist/cli/status.js +155 -0
  22. package/dist/cli/status.js.map +1 -0
  23. package/dist/http/async-dispatch.d.ts +32 -0
  24. package/dist/http/async-dispatch.d.ts.map +1 -0
  25. package/dist/http/async-dispatch.js +53 -0
  26. package/dist/http/async-dispatch.js.map +1 -0
  27. package/dist/http/auth.d.ts +26 -0
  28. package/dist/http/auth.d.ts.map +1 -0
  29. package/dist/http/auth.js +64 -0
  30. package/dist/http/auth.js.map +1 -0
  31. package/dist/http/cwd-validator.d.ts +11 -0
  32. package/dist/http/cwd-validator.d.ts.map +1 -0
  33. package/dist/http/cwd-validator.js +115 -0
  34. package/dist/http/cwd-validator.js.map +1 -0
  35. package/dist/http/errors.d.ts +4 -0
  36. package/dist/http/errors.d.ts.map +1 -0
  37. package/dist/http/errors.js +9 -0
  38. package/dist/http/errors.js.map +1 -0
  39. package/dist/http/execution-context.d.ts +15 -0
  40. package/dist/http/execution-context.d.ts.map +1 -0
  41. package/dist/http/execution-context.js +35 -0
  42. package/dist/http/execution-context.js.map +1 -0
  43. package/dist/http/handler-deps.d.ts +16 -0
  44. package/dist/http/handler-deps.d.ts.map +1 -0
  45. package/dist/http/handler-deps.js +2 -0
  46. package/dist/http/handler-deps.js.map +1 -0
  47. package/dist/http/handlers/control/batch.d.ts +24 -0
  48. package/dist/http/handlers/control/batch.d.ts.map +1 -0
  49. package/dist/http/handlers/control/batch.js +81 -0
  50. package/dist/http/handlers/control/batch.js.map +1 -0
  51. package/dist/http/handlers/control/clarifications.d.ts +19 -0
  52. package/dist/http/handlers/control/clarifications.d.ts.map +1 -0
  53. package/dist/http/handlers/control/clarifications.js +58 -0
  54. package/dist/http/handlers/control/clarifications.js.map +1 -0
  55. package/dist/http/handlers/control/context-blocks.d.ts +22 -0
  56. package/dist/http/handlers/control/context-blocks.d.ts.map +1 -0
  57. package/dist/http/handlers/control/context-blocks.js +88 -0
  58. package/dist/http/handlers/control/context-blocks.js.map +1 -0
  59. package/dist/http/handlers/introspection/health.d.ts +13 -0
  60. package/dist/http/handlers/introspection/health.d.ts.map +1 -0
  61. package/dist/http/handlers/introspection/health.js +17 -0
  62. package/dist/http/handlers/introspection/health.js.map +1 -0
  63. package/dist/http/handlers/introspection/status.d.ts +26 -0
  64. package/dist/http/handlers/introspection/status.d.ts.map +1 -0
  65. package/dist/http/handlers/introspection/status.js +136 -0
  66. package/dist/http/handlers/introspection/status.js.map +1 -0
  67. package/dist/http/handlers/introspection/tools-list.d.ts +9 -0
  68. package/dist/http/handlers/introspection/tools-list.d.ts.map +1 -0
  69. package/dist/http/handlers/introspection/tools-list.js +28 -0
  70. package/dist/http/handlers/introspection/tools-list.js.map +1 -0
  71. package/dist/http/handlers/tools/audit.d.ts +4 -0
  72. package/dist/http/handlers/tools/audit.d.ts.map +1 -0
  73. package/dist/http/handlers/tools/audit.js +39 -0
  74. package/dist/http/handlers/tools/audit.js.map +1 -0
  75. package/dist/http/handlers/tools/debug.d.ts +4 -0
  76. package/dist/http/handlers/tools/debug.d.ts.map +1 -0
  77. package/dist/http/handlers/tools/debug.js +39 -0
  78. package/dist/http/handlers/tools/debug.js.map +1 -0
  79. package/dist/http/handlers/tools/delegate.d.ts +4 -0
  80. package/dist/http/handlers/tools/delegate.d.ts.map +1 -0
  81. package/dist/http/handlers/tools/delegate.js +57 -0
  82. package/dist/http/handlers/tools/delegate.js.map +1 -0
  83. package/dist/http/handlers/tools/execute-plan.d.ts +4 -0
  84. package/dist/http/handlers/tools/execute-plan.d.ts.map +1 -0
  85. package/dist/http/handlers/tools/execute-plan.js +39 -0
  86. package/dist/http/handlers/tools/execute-plan.js.map +1 -0
  87. package/dist/http/handlers/tools/retry.d.ts +4 -0
  88. package/dist/http/handlers/tools/retry.d.ts.map +1 -0
  89. package/dist/http/handlers/tools/retry.js +52 -0
  90. package/dist/http/handlers/tools/retry.js.map +1 -0
  91. package/dist/http/handlers/tools/review.d.ts +4 -0
  92. package/dist/http/handlers/tools/review.d.ts.map +1 -0
  93. package/dist/http/handlers/tools/review.js +39 -0
  94. package/dist/http/handlers/tools/review.js.map +1 -0
  95. package/dist/http/handlers/tools/verify.d.ts +4 -0
  96. package/dist/http/handlers/tools/verify.d.ts.map +1 -0
  97. package/dist/http/handlers/tools/verify.js +39 -0
  98. package/dist/http/handlers/tools/verify.js.map +1 -0
  99. package/dist/http/loopback.d.ts +17 -0
  100. package/dist/http/loopback.d.ts.map +1 -0
  101. package/dist/http/loopback.js +43 -0
  102. package/dist/http/loopback.js.map +1 -0
  103. package/dist/http/middleware/body-reader.d.ts +16 -0
  104. package/dist/http/middleware/body-reader.d.ts.map +1 -0
  105. package/dist/http/middleware/body-reader.js +44 -0
  106. package/dist/http/middleware/body-reader.js.map +1 -0
  107. package/dist/http/project-registry.d.ts +54 -0
  108. package/dist/http/project-registry.d.ts.map +1 -0
  109. package/dist/http/project-registry.js +132 -0
  110. package/dist/http/project-registry.js.map +1 -0
  111. package/dist/http/router.d.ts +14 -0
  112. package/dist/http/router.d.ts.map +1 -0
  113. package/dist/http/router.js +41 -0
  114. package/dist/http/router.js.map +1 -0
  115. package/dist/http/server.d.ts +16 -0
  116. package/dist/http/server.d.ts.map +1 -0
  117. package/dist/http/server.js +235 -0
  118. package/dist/http/server.js.map +1 -0
  119. package/dist/http/types.d.ts +9 -0
  120. package/dist/http/types.d.ts.map +1 -0
  121. package/dist/http/types.js +2 -0
  122. package/dist/http/types.js.map +1 -0
  123. package/dist/index.d.ts +2 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +2 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/install/claude-code.d.ts +43 -0
  128. package/dist/install/claude-code.d.ts.map +1 -0
  129. package/dist/install/claude-code.js +65 -0
  130. package/dist/install/claude-code.js.map +1 -0
  131. package/dist/install/codex-cli.d.ts +39 -0
  132. package/dist/install/codex-cli.d.ts.map +1 -0
  133. package/dist/install/codex-cli.js +318 -0
  134. package/dist/install/codex-cli.js.map +1 -0
  135. package/dist/install/cursor.d.ts +72 -0
  136. package/dist/install/cursor.d.ts.map +1 -0
  137. package/dist/install/cursor.js +81 -0
  138. package/dist/install/cursor.js.map +1 -0
  139. package/dist/install/gemini-cli.d.ts +66 -0
  140. package/dist/install/gemini-cli.d.ts.map +1 -0
  141. package/dist/install/gemini-cli.js +111 -0
  142. package/dist/install/gemini-cli.js.map +1 -0
  143. package/dist/install/include-utils.d.ts +27 -0
  144. package/dist/install/include-utils.d.ts.map +1 -0
  145. package/dist/install/include-utils.js +90 -0
  146. package/dist/install/include-utils.js.map +1 -0
  147. package/dist/install/manifest.d.ts +90 -0
  148. package/dist/install/manifest.d.ts.map +1 -0
  149. package/dist/install/manifest.js +200 -0
  150. package/dist/install/manifest.js.map +1 -0
  151. package/dist/openapi.d.ts +15 -0
  152. package/dist/openapi.d.ts.map +1 -0
  153. package/dist/openapi.js +314 -0
  154. package/dist/openapi.js.map +1 -0
  155. package/dist/skills/_shared/auth.md +32 -0
  156. package/dist/skills/_shared/error-handling.md +31 -0
  157. package/dist/skills/_shared/polling.md +40 -0
  158. package/dist/skills/_shared/response-shape.md +46 -0
  159. package/dist/skills/mma-audit/SKILL.md +55 -0
  160. package/dist/skills/mma-clarifications/SKILL.md +68 -0
  161. package/dist/skills/mma-context-blocks/SKILL.md +69 -0
  162. package/dist/skills/mma-debug/SKILL.md +59 -0
  163. package/dist/skills/mma-delegate/SKILL.md +63 -0
  164. package/dist/skills/mma-execute-plan/SKILL.md +63 -0
  165. package/dist/skills/mma-retry/SKILL.md +54 -0
  166. package/dist/skills/mma-review/SKILL.md +55 -0
  167. package/dist/skills/mma-verify/SKILL.md +57 -0
  168. package/dist/skills/multi-model-agent/SKILL.md +55 -0
  169. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zhang Zhixuan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,217 @@
1
+ # @zhixuan92/multi-model-agent-mcp
2
+
3
+ **MCP server for multi-model-agent.** Your AI assistant gets 10 tools for delegating work to cheaper agents — parallel execution, cross-agent review, 90% cost savings.
4
+
5
+ Works with Claude Code, Codex CLI, Cursor, Gemini CLI, and Claude Desktop.
6
+
7
+ ## Install
8
+
9
+ Requires Node >= 22 and a config file at `~/.multi-model/config.json`.
10
+
11
+ **1. Create config** — define your two agent slots. Three agent types are supported:
12
+
13
+ | Type | Auth | API key needed? |
14
+ |---|---|---|
15
+ | `claude` | Your existing Claude Code / Claude subscription | No — uses local OAuth |
16
+ | `codex` | Your existing Codex subscription (`codex login`) | No — reads `~/.codex/auth.json` |
17
+ | `openai-compatible` | Any OpenAI-compatible API (GPT, MiniMax, DeepSeek, Groq, local vLLM) | Yes — `apiKeyEnv` or `apiKey` |
18
+
19
+ **Example — Claude + Codex (no API keys):**
20
+
21
+ ```bash
22
+ mkdir -p ~/.multi-model && cat > ~/.multi-model/config.json << 'EOF'
23
+ {
24
+ "agents": {
25
+ "standard": { "type": "codex", "model": "codex-mini-latest" },
26
+ "complex": { "type": "claude", "model": "claude-sonnet-4-20250514" }
27
+ },
28
+ "defaults": { "timeoutMs": 1800000, "maxCostUSD": 10, "tools": "full" }
29
+ }
30
+ EOF
31
+ ```
32
+
33
+ **Example — OpenAI-compatible endpoints (API keys required):**
34
+
35
+ ```bash
36
+ mkdir -p ~/.multi-model && cat > ~/.multi-model/config.json << 'EOF'
37
+ {
38
+ "agents": {
39
+ "standard": {
40
+ "type": "openai-compatible",
41
+ "model": "MiniMax-M2",
42
+ "baseUrl": "https://api.minimax.io/v1",
43
+ "apiKeyEnv": "MINIMAX_API_KEY"
44
+ },
45
+ "complex": {
46
+ "type": "openai-compatible",
47
+ "model": "gpt-5",
48
+ "baseUrl": "https://api.openai.com/v1",
49
+ "apiKeyEnv": "OPENAI_API_KEY"
50
+ }
51
+ },
52
+ "defaults": { "timeoutMs": 1800000, "maxCostUSD": 10, "tools": "full", "parentModel": "claude-opus-4-6" }
53
+ }
54
+ EOF
55
+ ```
56
+
57
+ > **`parentModel`** (optional): When set, headlines show `$Y saved vs model (Zx ROI)`. When omitted, headlines show `$X actual`.
58
+
59
+ Mix and match freely — e.g., `claude` for complex + `openai-compatible` for standard.
60
+
61
+ **2. Register the MCP server:**
62
+
63
+ ```bash
64
+ # Claude/Codex agents (no env vars needed):
65
+ claude mcp add multi-model-agent -s user \
66
+ -- npx -y @zhixuan92/multi-model-agent-mcp serve
67
+
68
+ # OpenAI-compatible agents (pass API keys):
69
+ claude mcp add multi-model-agent -s user \
70
+ -e MINIMAX_API_KEY=... -e OPENAI_API_KEY=... \
71
+ -- npx -y @zhixuan92/multi-model-agent-mcp serve
72
+ ```
73
+
74
+ No install step, no long-running process. Your MCP client spawns it on demand via `npx`.
75
+
76
+ For Codex CLI, Claude Desktop, and Cursor setup, see the [full guide](https://github.com/zhixuan312/multi-model-agent#quick-start).
77
+
78
+ ## What you get
79
+
80
+ | Tool | What it does |
81
+ |---|---|
82
+ | `delegate_tasks` | Dispatch tasks in parallel with minimal input: `prompt` plus optional `agentType`, `filePaths`, `done`, and `contextBlockIds`. The MCP interprets your request and infers missing details — if confused, it returns a proposed interpretation for confirmation. |
83
+ | `audit_document` | Audit docs/files for issues — parallel per file. Accepts `contextBlockIds` for delta audits (round 2+). |
84
+ | `review_code` | Code review with spec + quality pipeline — parallel per file. Accepts `contextBlockIds` for diff-scoped/delta reviews. |
85
+ | `verify_work` | Verify work against a checklist — parallel per file. Accepts `contextBlockIds` for shared context. |
86
+ | `debug_task` | Hypothesis-driven debugging with file context. Accepts `contextBlockIds` for shared context. |
87
+ | `execute_plan` | Execute tasks from a plan document — worker reads plan files, finds matching task by descriptor, implements it. Multiple tasks run in parallel. |
88
+ | `register_context_block` | Store reusable context for later tasks |
89
+ | `retry_tasks` | Re-run specific tasks from a previous batch |
90
+ | `get_batch_slice` | Fetch output or telemetry from a previous batch |
91
+ | `confirm_clarifications` | Resume a clarification set by confirming or editing proposed interpretations |
92
+
93
+ ## Diagnostic logging
94
+
95
+ Diagnostic logging is OFF by default.
96
+
97
+ It stays disabled when the `diagnostics` block is absent or when `diagnostics.log` is `false` in `~/.multi-model/config.json`.
98
+
99
+ To capture a crash/disconnect log to send us, add a `diagnostics` block to your config.
100
+
101
+ Minimal example:
102
+
103
+ ```json
104
+ {
105
+ "diagnostics": { "log": true }
106
+ }
107
+ ```
108
+
109
+ Full config shape example:
110
+
111
+ ```json
112
+ {
113
+ "agents": {
114
+ "standard": { "type": "codex", "model": "codex-mini-latest" },
115
+ "complex": { "type": "claude", "model": "claude-sonnet-4-20250514" }
116
+ },
117
+ "defaults": {
118
+ "timeoutMs": 1800000,
119
+ "maxCostUSD": 10,
120
+ "tools": "full"
121
+ },
122
+ "diagnostics": {
123
+ "log": true,
124
+ "logDir": "/some/path"
125
+ }
126
+ }
127
+ ```
128
+
129
+ `diagnostics.logDir` is optional; when omitted, logs default to `~/.multi-model/logs/`.
130
+
131
+ When enabled, the server appends JSONL records to `mcp-YYYY-MM-DD.jsonl` in append mode.
132
+
133
+ Only crash/disconnect diagnostic events are logged: `startup`, `request_start`, `request_complete`, `shutdown`, and `error`. This is a crash-diagnosis log, not a progress feed.
134
+
135
+ ## Setup & Configuration
136
+
137
+ See the full setup guide with config examples, client-specific instructions, and auth details:
138
+
139
+ → **[github.com/zhixuan312/multi-model-agent](https://github.com/zhixuan312/multi-model-agent#quick-start)**
140
+
141
+ ## Running as an HTTP daemon
142
+
143
+ The default transport is stdio — Claude Code spawns one `mmagent` process per session. When the Claude Code session ends (compaction, `/clear`, exit), the process dies; the next tool call has to start a fresh one.
144
+
145
+ To survive Claude Code lifecycle events, run `mmagent` as a long-running HTTP daemon. Multiple Claude Code sessions can connect to the same daemon (each pointing at its own project directory), and a client reconnect reuses the project's in-memory stores.
146
+
147
+ ### Start the daemon
148
+
149
+ Foreground (quickest way to try):
150
+
151
+ ```bash
152
+ mmagent serve --http
153
+ # → http://127.0.0.1:7312
154
+ ```
155
+
156
+ Background (macOS launchd / Linux systemd): see `scripts/README.md`.
157
+
158
+ ### Point Claude Code at the daemon
159
+
160
+ In each project's `.mcp.json`:
161
+
162
+ ```jsonc
163
+ {
164
+ "mcpServers": {
165
+ "multi-model-agent": {
166
+ "url": "http://127.0.0.1:7312/?cwd=/absolute/path/to/project"
167
+ }
168
+ }
169
+ }
170
+ ```
171
+
172
+ Two projects = two `.mcp.json` files, each with a different `?cwd=`.
173
+
174
+ ### Auth (optional)
175
+
176
+ For shared development machines:
177
+
178
+ ```jsonc
179
+ // ~/.multi-model/config.json
180
+ {
181
+ "transport": {
182
+ "mode": "http",
183
+ "http": { "auth": { "enabled": true } }
184
+ }
185
+ }
186
+ ```
187
+
188
+ On startup, `mmagent` generates a random token at `~/.multi-model/runtime/token` (mode 600). Paste it into `.mcp.json`:
189
+
190
+ ```jsonc
191
+ {
192
+ "url": "http://127.0.0.1:7312/?cwd=...",
193
+ "headers": { "Authorization": "Bearer <token-from-that-file>" }
194
+ }
195
+ ```
196
+
197
+ ### Check daemon status
198
+
199
+ ```bash
200
+ mmagent status
201
+ # mmagent 2.8.0 · pid 6821 · uptime 3h 24m · http://127.0.0.1:7312
202
+ # Projects (2):
203
+ # /Users/me/project-X 1 sess 7 batches last seen 8s ago
204
+ # /Users/me/project-Y 1 sess 2 batches last seen 4m ago
205
+ ```
206
+
207
+ ### Upgrades
208
+
209
+ `npm i -g @zhixuan92/multi-model-agent-mcp@latest` writes the new binary but does not restart the running daemon. Restart manually:
210
+
211
+ - **launchd**: `launchctl kickstart -k gui/$(id -u)/com.zhixuan92.mmagent`
212
+ - **systemd**: `systemctl --user restart mmagent`
213
+ - **foreground**: `Ctrl-C` and run `mmagent serve --http` again.
214
+
215
+ ## License
216
+
217
+ [MIT](./LICENSE) — Copyright (c) 2026 Zhang Zhixuan
@@ -0,0 +1,61 @@
1
+ import { type ParsedArgs } from 'minimist';
2
+ import { type MultiModelConfig } from '@zhixuan92/multi-model-agent-core';
3
+ /**
4
+ * Minimal I/O dependencies — allows tests to intercept stdout/stderr and
5
+ * override process.argv / process.exit.
6
+ */
7
+ export interface CliDeps {
8
+ /**
9
+ * argv[0..] (not including node path or script path) passed to minimist.
10
+ * Defaults to process.argv.slice(2).
11
+ */
12
+ argv?: () => string[];
13
+ /**
14
+ * Current working directory. Defaults to process.cwd().
15
+ * Used only for resolving the CWD/.multi-model-agent.json discovery path.
16
+ */
17
+ cwd?: () => string;
18
+ /**
19
+ * Home directory. Defaults to os.homedir().
20
+ * Used only for resolving the ~/.multi-model/config.json discovery path.
21
+ */
22
+ homeDir?: () => string;
23
+ /**
24
+ * Environment variable accessor. Defaults to process.env.
25
+ */
26
+ env?: () => Record<string, string | undefined>;
27
+ /** Write to stdout. Defaults to process.stdout.write.bind(process.stdout). */
28
+ stdout?: (s: string) => boolean;
29
+ /** Write to stderr. Defaults to process.stderr.write.bind(process.stderr). */
30
+ stderr?: (s: string) => boolean;
31
+ /** Exit the process. Defaults to process.exit. */
32
+ exit?: (code: number) => never;
33
+ }
34
+ /** Parse minimist args from an argv array. */
35
+ export declare function parseArgs(argv: string[]): ParsedArgs;
36
+ /**
37
+ * Resolve the config file path using the discovery order:
38
+ * 1. --config <path> (explicit flag)
39
+ * 2. $MMAGENT_CONFIG (env var)
40
+ * 3. CWD/.multi-model-agent.json
41
+ * 4. ~/.multi-model/config.json
42
+ *
43
+ * Returns the first path that exists, or undefined if none exist.
44
+ * Does NOT validate or parse the file — caller uses loadConfigFromFile().
45
+ */
46
+ export declare function resolveConfigPath(explicit: string | undefined, env: Record<string, string | undefined>, cwd: string, home: string): string | undefined;
47
+ /**
48
+ * Load config using the discovery order.
49
+ * Tries each candidate in priority order and returns the first successfully
50
+ * loaded config. Returns an error listing all attempted paths if none are found
51
+ * or every found file is unreadable/invalid.
52
+ */
53
+ export declare function loadConfig(explicitPath: string | undefined, deps: Pick<CliDeps, 'cwd' | 'homeDir' | 'env'>): Promise<MultiModelConfig>;
54
+ /**
55
+ * Main entry point — exported so it can be unit-tested without subprocess spawning.
56
+ *
57
+ * @param deps I/O dependencies (defaults to real process globals).
58
+ */
59
+ export declare function main(deps?: CliDeps): Promise<void>;
60
+ export type { MultiModelConfig };
61
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAyBA,OAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAM3C;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IACvB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,8EAA8E;IAC9E,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,kDAAkD;IAClD,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;CAChC;AAED,8CAA8C;AAC9C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CASpD;AA4BD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAKpB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC,GAC7C,OAAO,CAAC,gBAAgB,CAAC,CA0B3B;AAkCD;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,IAAI,GAAE,OAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsF5D;AA8BD,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,252 @@
1
+ /**
2
+ * CLI entry point for `mmagent` / `multi-model-agent`.
3
+ *
4
+ * Usage:
5
+ * mmagent serve [--config <path>]
6
+ * mmagent --help
7
+ * mmagent --version
8
+ *
9
+ * Config discovery order (highest priority → lowest):
10
+ * 1. --config <path> (explicit flag)
11
+ * 2. $MMAGENT_CONFIG env var
12
+ * 3. CWD/.multi-model-agent.json
13
+ * 4. ~/.multi-model/config.json
14
+ *
15
+ * All side effects (process.exit, stdout/stderr writes) are contained in the
16
+ * bootstrap at the bottom of this file. The internal `main()` function is
17
+ * exported so it can be unit-tested without spawning subprocesses.
18
+ *
19
+ * Signal lifecycle is owned by `serve.ts` — this module delegates to
20
+ * `startServe()` which registers SIGTERM/SIGINT handlers and manages process.exit.
21
+ */
22
+ import * as path from 'node:path';
23
+ import * as fs from 'node:fs';
24
+ import * as os from 'node:os';
25
+ import { fileURLToPath } from 'node:url';
26
+ import minimist from 'minimist';
27
+ import { loadConfigFromFile, } from '@zhixuan92/multi-model-agent-core';
28
+ import { startServe } from './serve.js';
29
+ import { printToken } from './print-token.js';
30
+ import { runStatus, buildServerUrl } from './status.js';
31
+ import { main as installSkillMain } from './install-skill.js';
32
+ /** Parse minimist args from an argv array. */
33
+ export function parseArgs(argv) {
34
+ return minimist(argv, {
35
+ string: ['config'],
36
+ boolean: ['help', 'version', 'json'],
37
+ alias: { config: 'c', help: 'h', version: 'v', json: 'j' },
38
+ // Note: stopEarly is NOT set. With stopEarly:true, options after the first
39
+ // positional argument (the subcommand) would be silently dropped. E.g.
40
+ // `mmagent serve --config ./config.json` would lose --config.
41
+ });
42
+ }
43
+ /**
44
+ * Build the ordered list of config-file candidates from discovery sources.
45
+ * Returns an array of resolved paths; callers filter for existence and
46
+ * iterate in priority order. This single builder ensures that
47
+ * resolveConfigPath() and loadConfig() cannot drift apart.
48
+ */
49
+ function buildCandidatePaths(explicit, env, cwd, home) {
50
+ const paths = [];
51
+ if (explicit)
52
+ paths.push(explicit);
53
+ const envVal = (env['MMAGENT_CONFIG'] ?? '').trim();
54
+ if (envVal)
55
+ paths.push(envVal);
56
+ paths.push(path.join(cwd, '.multi-model-agent.json'));
57
+ paths.push(path.join(home, '.multi-model', 'config.json'));
58
+ return paths;
59
+ }
60
+ /**
61
+ * Resolve the config file path using the discovery order:
62
+ * 1. --config <path> (explicit flag)
63
+ * 2. $MMAGENT_CONFIG (env var)
64
+ * 3. CWD/.multi-model-agent.json
65
+ * 4. ~/.multi-model/config.json
66
+ *
67
+ * Returns the first path that exists, or undefined if none exist.
68
+ * Does NOT validate or parse the file — caller uses loadConfigFromFile().
69
+ */
70
+ export function resolveConfigPath(explicit, env, cwd, home) {
71
+ for (const p of buildCandidatePaths(explicit, env, cwd, home)) {
72
+ if (p && fs.existsSync(p))
73
+ return p;
74
+ }
75
+ return undefined;
76
+ }
77
+ /**
78
+ * Load config using the discovery order.
79
+ * Tries each candidate in priority order and returns the first successfully
80
+ * loaded config. Returns an error listing all attempted paths if none are found
81
+ * or every found file is unreadable/invalid.
82
+ */
83
+ export async function loadConfig(explicitPath, deps) {
84
+ const cwd = deps.cwd?.() ?? process.cwd();
85
+ const home = deps.homeDir?.() ?? os.homedir();
86
+ const env = deps.env?.() ?? process.env;
87
+ const attempted = [];
88
+ for (const p of buildCandidatePaths(explicitPath, env, cwd, home)) {
89
+ if (!p) {
90
+ attempted.push('<source: not set>');
91
+ continue;
92
+ }
93
+ attempted.push(p);
94
+ if (!fs.existsSync(p))
95
+ continue;
96
+ try {
97
+ return await loadConfigFromFile(p);
98
+ }
99
+ catch (err) {
100
+ const msg = err instanceof Error ? err.message : String(err);
101
+ throw new Error(`Config error (${p}): ${msg}`);
102
+ }
103
+ }
104
+ throw new Error(`No config file found. Tried:\n${attempted.join('\n')}\n` +
105
+ `Set one via --config, $MMAGENT_CONFIG, or place it at a default location above.`);
106
+ }
107
+ const HELP_TEXT = `\
108
+ mmagent — multi-model-agent HTTP server
109
+
110
+ Usage:
111
+ mmagent [command] [options]
112
+
113
+ Commands:
114
+ serve Start the HTTP server (default)
115
+ print-token Print the bearer auth token to stdout
116
+ status Show server status (requires a running server)
117
+ install-skill Install or uninstall a skill for an AI client
118
+
119
+ Global options:
120
+ --config, -c <path> Path to config file
121
+ --help, -h Show this help
122
+ --version, -v Show version
123
+ `;
124
+ /**
125
+ * Read the server package version from package.json, walking up from this file.
126
+ */
127
+ function readServerVersion() {
128
+ try {
129
+ const thisDir = path.dirname(fileURLToPath(import.meta.url));
130
+ const pkgPath = path.join(thisDir, '..', '..', 'package.json');
131
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
132
+ return pkg.version ?? '0.0.0';
133
+ }
134
+ catch {
135
+ return '0.0.0';
136
+ }
137
+ }
138
+ /**
139
+ * Main entry point — exported so it can be unit-tested without subprocess spawning.
140
+ *
141
+ * @param deps I/O dependencies (defaults to real process globals).
142
+ */
143
+ export async function main(deps = {}) {
144
+ const argv = deps.argv?.() ?? process.argv.slice(2);
145
+ const stdout = deps.stdout ?? process.stdout.write.bind(process.stdout);
146
+ const stderr = deps.stderr ?? process.stderr.write.bind(process.stderr);
147
+ const exit = deps.exit ?? process.exit.bind(process);
148
+ const opts = parseArgs(argv);
149
+ const positional = opts._;
150
+ const subcommand = positional[0] ?? 'serve';
151
+ const configArg = typeof opts['config'] === 'string' ? opts['config'] : undefined;
152
+ if (opts['help']) {
153
+ stdout(HELP_TEXT);
154
+ return;
155
+ }
156
+ if (opts['version']) {
157
+ stdout(readServerVersion() + '\n');
158
+ return;
159
+ }
160
+ switch (subcommand) {
161
+ case 'serve': {
162
+ const config = await loadConfig(configArg, deps);
163
+ // startServe() blocks until a signal arrives and exits the process.
164
+ await startServe(config, exit);
165
+ break;
166
+ }
167
+ case 'print-token': {
168
+ const config = await loadConfig(configArg, deps).catch(() => null);
169
+ const tokenFile = config
170
+ ? config.server.auth.tokenFile
171
+ : path.join(deps.homeDir?.() ?? os.homedir(), '.multi-model', 'auth-token');
172
+ const code = printToken({
173
+ homeDir: deps.homeDir?.() ?? os.homedir(),
174
+ tokenFile,
175
+ env: deps.env?.() ?? process.env,
176
+ stdout: deps.stdout,
177
+ stderr: deps.stderr,
178
+ });
179
+ exit(code);
180
+ break;
181
+ }
182
+ case 'status': {
183
+ const jsonFlag = opts['json'] === true;
184
+ const config = await loadConfig(configArg, deps).catch(() => null);
185
+ const home = deps.homeDir?.() ?? os.homedir();
186
+ const tokenFile = config
187
+ ? config.server.auth.tokenFile
188
+ : path.join(home, '.multi-model', 'auth-token');
189
+ const serverUrl = config
190
+ ? buildServerUrl(config.server.bind, config.server.port)
191
+ : buildServerUrl('127.0.0.1', 7337);
192
+ const code = await runStatus({
193
+ serverUrl,
194
+ tokenFile,
195
+ json: jsonFlag,
196
+ env: deps.env?.() ?? process.env,
197
+ homeDir: home,
198
+ stdout: deps.stdout,
199
+ stderr: deps.stderr,
200
+ });
201
+ exit(code);
202
+ break;
203
+ }
204
+ case 'install-skill': {
205
+ // Forward all argv tokens that come after the subcommand name.
206
+ // minimist with stopEarly:true would have captured them in opts._, but
207
+ // since we don't use stopEarly we need to find the subcommand boundary
208
+ // in the raw argv array and pass everything after it.
209
+ const subCmdIdx = argv.indexOf('install-skill');
210
+ const subArgv = subCmdIdx >= 0 ? argv.slice(subCmdIdx + 1) : positional.slice(1);
211
+ const code = await installSkillMain({
212
+ argv: subArgv,
213
+ homeDir: deps.homeDir?.() ?? os.homedir(),
214
+ stdout: deps.stdout,
215
+ stderr: deps.stderr,
216
+ });
217
+ exit(code);
218
+ break;
219
+ }
220
+ default: {
221
+ stderr(`Unknown command: ${subcommand}\nRun 'mmagent --help' for usage.\n`);
222
+ exit(1);
223
+ }
224
+ }
225
+ }
226
+ // ── Bootstrap ──────────────────────────────────────────────────────────────
227
+ // Only run main() when this module is executed as the CLI entry point.
228
+ // Tests import main() directly and pass CliDeps.
229
+ function isMain() {
230
+ try {
231
+ const argv1 = process.argv[1];
232
+ if (!argv1)
233
+ return false;
234
+ // Resolve to absolute path to handle relative argv[1], symlinks, and
235
+ // platform-specific path normalization consistently.
236
+ const entryPath = import.meta.url.startsWith('file://')
237
+ ? fileURLToPath(import.meta.url)
238
+ : path.resolve(argv1);
239
+ return path.resolve(argv1) === entryPath;
240
+ }
241
+ catch {
242
+ return false;
243
+ }
244
+ }
245
+ if (isMain()) {
246
+ void main().catch((err) => {
247
+ const msg = err instanceof Error ? err.message : String(err);
248
+ process.stderr.write(`mmagent: ${msg}\n`);
249
+ process.exit(1);
250
+ });
251
+ }
252
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}