@zhixuan92/multi-model-agent 5.0.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/README.md +14 -23
  2. package/dist/cli/index.d.ts +62 -0
  3. package/dist/cli/index.d.ts.map +1 -0
  4. package/dist/cli/index.js +345 -0
  5. package/dist/cli/index.js.map +1 -0
  6. package/dist/cli/info.d.ts +22 -0
  7. package/dist/cli/info.d.ts.map +1 -0
  8. package/dist/cli/info.js +100 -0
  9. package/dist/cli/info.js.map +1 -0
  10. package/dist/cli/logs.d.ts +15 -0
  11. package/dist/cli/logs.d.ts.map +1 -0
  12. package/dist/cli/logs.js +102 -0
  13. package/dist/cli/logs.js.map +1 -0
  14. package/dist/cli/print-token.d.ts +18 -0
  15. package/dist/cli/print-token.d.ts.map +1 -0
  16. package/dist/cli/print-token.js +60 -0
  17. package/dist/cli/print-token.js.map +1 -0
  18. package/dist/cli/serve.d.ts +28 -0
  19. package/dist/cli/serve.d.ts.map +1 -0
  20. package/dist/cli/serve.js +405 -0
  21. package/dist/cli/serve.js.map +1 -0
  22. package/dist/cli/status.d.ts +49 -0
  23. package/dist/cli/status.d.ts.map +1 -0
  24. package/dist/cli/status.js +155 -0
  25. package/dist/cli/status.js.map +1 -0
  26. package/dist/cli/sync-skills.d.ts +58 -0
  27. package/dist/cli/sync-skills.d.ts.map +1 -0
  28. package/dist/cli/sync-skills.js +266 -0
  29. package/dist/cli/sync-skills.js.map +1 -0
  30. package/dist/cli/telemetry.d.ts +10 -0
  31. package/dist/cli/telemetry.d.ts.map +1 -0
  32. package/dist/cli/telemetry.js +161 -0
  33. package/dist/cli/telemetry.js.map +1 -0
  34. package/dist/cli/toggle.d.ts +26 -0
  35. package/dist/cli/toggle.d.ts.map +1 -0
  36. package/dist/cli/toggle.js +185 -0
  37. package/dist/cli/toggle.js.map +1 -0
  38. package/dist/http/async-dispatch.d.ts +44 -0
  39. package/dist/http/async-dispatch.d.ts.map +1 -0
  40. package/dist/http/async-dispatch.js +175 -0
  41. package/dist/http/async-dispatch.js.map +1 -0
  42. package/dist/http/auth.d.ts +20 -0
  43. package/dist/http/auth.d.ts.map +1 -0
  44. package/dist/http/auth.js +56 -0
  45. package/dist/http/auth.js.map +1 -0
  46. package/dist/http/canonicalize-file-paths.d.ts +8 -0
  47. package/dist/http/canonicalize-file-paths.d.ts.map +1 -0
  48. package/dist/http/canonicalize-file-paths.js +43 -0
  49. package/dist/http/canonicalize-file-paths.js.map +1 -0
  50. package/dist/http/cwd-validator.d.ts +11 -0
  51. package/dist/http/cwd-validator.d.ts.map +1 -0
  52. package/dist/http/cwd-validator.js +130 -0
  53. package/dist/http/cwd-validator.js.map +1 -0
  54. package/dist/http/errors.d.ts +4 -0
  55. package/dist/http/errors.d.ts.map +1 -0
  56. package/dist/http/errors.js +9 -0
  57. package/dist/http/errors.js.map +1 -0
  58. package/dist/http/execution-context.d.ts +18 -0
  59. package/dist/http/execution-context.d.ts.map +1 -0
  60. package/dist/http/execution-context.js +61 -0
  61. package/dist/http/execution-context.js.map +1 -0
  62. package/dist/http/handler-deps.d.ts +19 -0
  63. package/dist/http/handler-deps.d.ts.map +1 -0
  64. package/dist/http/handler-deps.js +2 -0
  65. package/dist/http/handler-deps.js.map +1 -0
  66. package/dist/http/handlers/control/batch-slice.d.ts +4 -0
  67. package/dist/http/handlers/control/batch-slice.d.ts.map +1 -0
  68. package/dist/http/handlers/control/batch-slice.js +40 -0
  69. package/dist/http/handlers/control/batch-slice.js.map +1 -0
  70. package/dist/http/handlers/control/batch.d.ts +23 -0
  71. package/dist/http/handlers/control/batch.d.ts.map +1 -0
  72. package/dist/http/handlers/control/batch.js +332 -0
  73. package/dist/http/handlers/control/batch.js.map +1 -0
  74. package/dist/http/handlers/control/context-blocks.d.ts +22 -0
  75. package/dist/http/handlers/control/context-blocks.d.ts.map +1 -0
  76. package/dist/http/handlers/control/context-blocks.js +111 -0
  77. package/dist/http/handlers/control/context-blocks.js.map +1 -0
  78. package/dist/http/handlers/introspection/health.d.ts +20 -0
  79. package/dist/http/handlers/introspection/health.d.ts.map +1 -0
  80. package/dist/http/handlers/introspection/health.js +18 -0
  81. package/dist/http/handlers/introspection/health.js.map +1 -0
  82. package/dist/http/handlers/introspection/status.d.ts +26 -0
  83. package/dist/http/handlers/introspection/status.d.ts.map +1 -0
  84. package/dist/http/handlers/introspection/status.js +136 -0
  85. package/dist/http/handlers/introspection/status.js.map +1 -0
  86. package/dist/http/handlers/tools/audit.d.ts +4 -0
  87. package/dist/http/handlers/tools/audit.d.ts.map +1 -0
  88. package/dist/http/handlers/tools/audit.js +43 -0
  89. package/dist/http/handlers/tools/audit.js.map +1 -0
  90. package/dist/http/handlers/tools/debug.d.ts +4 -0
  91. package/dist/http/handlers/tools/debug.d.ts.map +1 -0
  92. package/dist/http/handlers/tools/debug.js +43 -0
  93. package/dist/http/handlers/tools/debug.js.map +1 -0
  94. package/dist/http/handlers/tools/delegate.d.ts +4 -0
  95. package/dist/http/handlers/tools/delegate.d.ts.map +1 -0
  96. package/dist/http/handlers/tools/delegate.js +43 -0
  97. package/dist/http/handlers/tools/delegate.js.map +1 -0
  98. package/dist/http/handlers/tools/execute-plan.d.ts +4 -0
  99. package/dist/http/handlers/tools/execute-plan.d.ts.map +1 -0
  100. package/dist/http/handlers/tools/execute-plan.js +45 -0
  101. package/dist/http/handlers/tools/execute-plan.js.map +1 -0
  102. package/dist/http/handlers/tools/investigate.d.ts +4 -0
  103. package/dist/http/handlers/tools/investigate.d.ts.map +1 -0
  104. package/dist/http/handlers/tools/investigate.js +64 -0
  105. package/dist/http/handlers/tools/investigate.js.map +1 -0
  106. package/dist/http/handlers/tools/journal-recall.d.ts +4 -0
  107. package/dist/http/handlers/tools/journal-recall.d.ts.map +1 -0
  108. package/dist/http/handlers/tools/journal-recall.js +40 -0
  109. package/dist/http/handlers/tools/journal-recall.js.map +1 -0
  110. package/dist/http/handlers/tools/journal-record.d.ts +12 -0
  111. package/dist/http/handlers/tools/journal-record.d.ts.map +1 -0
  112. package/dist/http/handlers/tools/journal-record.js +43 -0
  113. package/dist/http/handlers/tools/journal-record.js.map +1 -0
  114. package/dist/http/handlers/tools/research.d.ts +4 -0
  115. package/dist/http/handlers/tools/research.d.ts.map +1 -0
  116. package/dist/http/handlers/tools/research.js +64 -0
  117. package/dist/http/handlers/tools/research.js.map +1 -0
  118. package/dist/http/handlers/tools/retry.d.ts +4 -0
  119. package/dist/http/handlers/tools/retry.d.ts.map +1 -0
  120. package/dist/http/handlers/tools/retry.js +49 -0
  121. package/dist/http/handlers/tools/retry.js.map +1 -0
  122. package/dist/http/handlers/tools/review.d.ts +4 -0
  123. package/dist/http/handlers/tools/review.d.ts.map +1 -0
  124. package/dist/http/handlers/tools/review.js +43 -0
  125. package/dist/http/handlers/tools/review.js.map +1 -0
  126. package/dist/http/middleware/body-reader.d.ts +16 -0
  127. package/dist/http/middleware/body-reader.d.ts.map +1 -0
  128. package/dist/http/middleware/body-reader.js +44 -0
  129. package/dist/http/middleware/body-reader.js.map +1 -0
  130. package/dist/http/middleware/caller-identity.d.ts +16 -0
  131. package/dist/http/middleware/caller-identity.d.ts.map +1 -0
  132. package/dist/http/middleware/caller-identity.js +16 -0
  133. package/dist/http/middleware/caller-identity.js.map +1 -0
  134. package/dist/http/middleware/decompress.d.ts +14 -0
  135. package/dist/http/middleware/decompress.d.ts.map +1 -0
  136. package/dist/http/middleware/decompress.js +51 -0
  137. package/dist/http/middleware/decompress.js.map +1 -0
  138. package/dist/http/project-registry.d.ts +54 -0
  139. package/dist/http/project-registry.d.ts.map +1 -0
  140. package/dist/http/project-registry.js +130 -0
  141. package/dist/http/project-registry.js.map +1 -0
  142. package/dist/http/request-observability.d.ts +8 -0
  143. package/dist/http/request-observability.d.ts.map +1 -0
  144. package/dist/http/request-observability.js +20 -0
  145. package/dist/http/request-observability.js.map +1 -0
  146. package/dist/http/request-pipeline.d.ts +16 -0
  147. package/dist/http/request-pipeline.d.ts.map +1 -0
  148. package/dist/http/request-pipeline.js +144 -0
  149. package/dist/http/request-pipeline.js.map +1 -0
  150. package/dist/http/server.d.ts +17 -0
  151. package/dist/http/server.d.ts.map +1 -0
  152. package/dist/http/server.js +300 -0
  153. package/dist/http/server.js.map +1 -0
  154. package/dist/http/types.d.ts +20 -0
  155. package/dist/http/types.d.ts.map +1 -0
  156. package/dist/http/types.js +2 -0
  157. package/dist/http/types.js.map +1 -0
  158. package/dist/skill-install/disabled-state.d.ts +35 -0
  159. package/dist/skill-install/disabled-state.d.ts.map +1 -0
  160. package/dist/skill-install/disabled-state.js +96 -0
  161. package/dist/skill-install/disabled-state.js.map +1 -0
  162. package/dist/skill-install/discover.d.ts +29 -0
  163. package/dist/skill-install/discover.d.ts.map +1 -0
  164. package/dist/skill-install/discover.js +104 -0
  165. package/dist/skill-install/discover.js.map +1 -0
  166. package/dist/skill-install/include-utils.d.ts +27 -0
  167. package/dist/skill-install/include-utils.d.ts.map +1 -0
  168. package/dist/skill-install/include-utils.js +90 -0
  169. package/dist/skill-install/include-utils.js.map +1 -0
  170. package/dist/skill-install/manifest.d.ts +82 -0
  171. package/dist/skill-install/manifest.d.ts.map +1 -0
  172. package/dist/skill-install/manifest.js +215 -0
  173. package/dist/skill-install/manifest.js.map +1 -0
  174. package/dist/skill-install/skill-installer-common.d.ts +26 -0
  175. package/dist/skill-install/skill-installer-common.d.ts.map +1 -0
  176. package/dist/skill-install/skill-installer-common.js +139 -0
  177. package/dist/skill-install/skill-installer-common.js.map +1 -0
  178. package/dist/skill-install/skill-installers/claude-code.d.ts +43 -0
  179. package/dist/skill-install/skill-installers/claude-code.d.ts.map +1 -0
  180. package/dist/skill-install/skill-installers/claude-code.js +65 -0
  181. package/dist/skill-install/skill-installers/claude-code.js.map +1 -0
  182. package/dist/skill-install/skill-installers/codex-cli.d.ts +27 -0
  183. package/dist/skill-install/skill-installers/codex-cli.d.ts.map +1 -0
  184. package/dist/skill-install/skill-installers/codex-cli.js +84 -0
  185. package/dist/skill-install/skill-installers/codex-cli.js.map +1 -0
  186. package/dist/skill-install/skill-installers/cursor.d.ts +72 -0
  187. package/dist/skill-install/skill-installers/cursor.d.ts.map +1 -0
  188. package/dist/skill-install/skill-installers/cursor.js +81 -0
  189. package/dist/skill-install/skill-installers/cursor.js.map +1 -0
  190. package/dist/skill-install/skill-installers/gemini-cli.d.ts +50 -0
  191. package/dist/skill-install/skill-installers/gemini-cli.d.ts.map +1 -0
  192. package/dist/skill-install/skill-installers/gemini-cli.js +72 -0
  193. package/dist/skill-install/skill-installers/gemini-cli.js.map +1 -0
  194. package/dist/skill-install/skill-manifest-sync.d.ts +11 -0
  195. package/dist/skill-install/skill-manifest-sync.d.ts.map +1 -0
  196. package/dist/skill-install/skill-manifest-sync.js +65 -0
  197. package/dist/skill-install/skill-manifest-sync.js.map +1 -0
  198. package/dist/skills/_shared/auth.md +41 -0
  199. package/dist/skills/_shared/error-handling.md +31 -0
  200. package/dist/skills/_shared/polling.md +88 -0
  201. package/dist/skills/_shared/response-shape.md +55 -0
  202. package/dist/skills/_shared/review-policy.md +15 -0
  203. package/dist/skills/mma-audit/SKILL.md +270 -0
  204. package/dist/skills/mma-context-blocks/SKILL.md +148 -0
  205. package/dist/skills/mma-debug/SKILL.md +208 -0
  206. package/dist/skills/mma-delegate/SKILL.md +216 -0
  207. package/dist/skills/mma-execute-plan/SKILL.md +214 -0
  208. package/dist/skills/mma-explore/SKILL.md +190 -0
  209. package/dist/skills/mma-investigate/SKILL.md +258 -0
  210. package/dist/skills/mma-journal-recall/SKILL.md +242 -0
  211. package/dist/skills/mma-journal-record/SKILL.md +202 -0
  212. package/dist/skills/mma-research/SKILL.md +223 -0
  213. package/dist/skills/mma-retry/SKILL.md +221 -0
  214. package/dist/skills/mma-review/SKILL.md +209 -0
  215. package/dist/skills/multi-model-agent/SKILL.md +206 -0
  216. package/dist/telemetry/consent.d.ts +4 -0
  217. package/dist/telemetry/consent.d.ts.map +1 -0
  218. package/dist/telemetry/consent.js +40 -0
  219. package/dist/telemetry/consent.js.map +1 -0
  220. package/dist/telemetry/flusher.d.ts +19 -0
  221. package/dist/telemetry/flusher.d.ts.map +1 -0
  222. package/dist/telemetry/flusher.js +277 -0
  223. package/dist/telemetry/flusher.js.map +1 -0
  224. package/dist/telemetry/generation.d.ts +9 -0
  225. package/dist/telemetry/generation.d.ts.map +1 -0
  226. package/dist/telemetry/generation.js +33 -0
  227. package/dist/telemetry/generation.js.map +1 -0
  228. package/dist/telemetry/identity.d.ts +9 -0
  229. package/dist/telemetry/identity.d.ts.map +1 -0
  230. package/dist/telemetry/identity.js +35 -0
  231. package/dist/telemetry/identity.js.map +1 -0
  232. package/dist/telemetry/install-id.d.ts +13 -0
  233. package/dist/telemetry/install-id.d.ts.map +1 -0
  234. package/dist/telemetry/install-id.js +49 -0
  235. package/dist/telemetry/install-id.js.map +1 -0
  236. package/dist/telemetry/install-meta.d.ts +10 -0
  237. package/dist/telemetry/install-meta.d.ts.map +1 -0
  238. package/dist/telemetry/install-meta.js +15 -0
  239. package/dist/telemetry/install-meta.js.map +1 -0
  240. package/dist/telemetry/queue.d.ts +35 -0
  241. package/dist/telemetry/queue.d.ts.map +1 -0
  242. package/dist/telemetry/queue.js +287 -0
  243. package/dist/telemetry/queue.js.map +1 -0
  244. package/dist/telemetry/recorder.d.ts +39 -0
  245. package/dist/telemetry/recorder.d.ts.map +1 -0
  246. package/dist/telemetry/recorder.js +173 -0
  247. package/dist/telemetry/recorder.js.map +1 -0
  248. package/package.json +43 -24
  249. package/scripts/postinstall.js +36 -0
  250. package/bin/mmagent.mjs +0 -47
  251. package/postinstall.mjs +0 -8
@@ -0,0 +1,405 @@
1
+ /**
2
+ * serve.ts — starts the HTTP server and manages its signal lifecycle.
3
+ *
4
+ * This module owns the complete serve lifecycle: starting the HTTP server,
5
+ * registering SIGTERM/SIGINT handlers, draining in-flight requests, and
6
+ * cleanly exiting the process. The CLI entry point (cli/index.ts) delegates
7
+ * to this module and does not manage signals directly.
8
+ *
9
+ * Usage (library):
10
+ * const handle = await startServe(config);
11
+ * // server is running on handle.port
12
+ * await handle.stop(); // graceful shutdown; no process.exit
13
+ *
14
+ * Usage (CLI):
15
+ * mmagent serve [--config <path>]
16
+ * // this module owns signal handling and process.exit
17
+ */
18
+ import { createHash, randomUUID } from 'node:crypto';
19
+ import * as path from 'node:path';
20
+ import * as fs from 'node:fs';
21
+ import * as os from 'node:os';
22
+ import { fileURLToPath } from 'node:url';
23
+ import { collectInlineApiKeyOffenders, loadAuthToken } from '@zhixuan92/multi-model-agent-core';
24
+ import { startServer } from '../http/server.js';
25
+ import { setDraining } from '../http/request-pipeline.js';
26
+ import { createRecorder } from '../telemetry/recorder.js';
27
+ import { Flusher } from '../telemetry/flusher.js';
28
+ import { Queue } from '../telemetry/queue.js';
29
+ import { runSyncSkills } from './sync-skills.js';
30
+ import { listEntries, FutureManifestError } from '../skill-install/manifest.js';
31
+ import { readSkillContent, SUPPORTED_SKILLS } from '../skill-install/discover.js';
32
+ import { findMissingSkills } from '../skill-install/skill-installer-common.js';
33
+ import matter from 'gray-matter';
34
+ function isSkillBehind(entryName, entrySkillVersion) {
35
+ const src = readSkillContent(entryName);
36
+ if (src === null)
37
+ return false; // skill removed from bundle — sync-skills will drop it
38
+ try {
39
+ const parsed = matter(src);
40
+ const v = parsed.data['version'];
41
+ return typeof v === 'string' && v !== entrySkillVersion;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ export async function maybeAutoUpdateSkills(config, stderr) {
48
+ let entries;
49
+ try {
50
+ entries = listEntries();
51
+ }
52
+ catch (err) {
53
+ if (err instanceof FutureManifestError) {
54
+ stderr(`[mmagent] warning: ${err.message}; skipping skill auto-sync\n`);
55
+ return;
56
+ }
57
+ return; // best-effort — never let manifest IO issues block serve
58
+ }
59
+ const behind = entries.filter((e) => isSkillBehind(e.name, e.skillVersion));
60
+ const missing = findMissingSkills(entries, SUPPORTED_SKILLS);
61
+ if (behind.length === 0 && missing.length === 0)
62
+ return;
63
+ if (!config.server.autoUpdateSkills) {
64
+ const drift = [];
65
+ if (behind.length > 0)
66
+ drift.push(`${behind.length} out of date (${behind.map((e) => e.name).join(', ')})`);
67
+ if (missing.length > 0)
68
+ drift.push(`${missing.length} new (${missing.map((m) => m.name).join(', ')})`);
69
+ stderr(`[mmagent] skill drift: ${drift.join('; ')}. ` +
70
+ `Run 'mmagent sync-skills' to reconcile (or set server.autoUpdateSkills=true in config).\n`);
71
+ return;
72
+ }
73
+ const deadlineMs = 5000;
74
+ try {
75
+ await Promise.race([
76
+ runSyncSkills({ silent: true, bestEffort: true, ifExists: true }),
77
+ new Promise((resolve) => setTimeout(() => resolve(), deadlineMs)),
78
+ ]);
79
+ if (behind.length > 0)
80
+ process.stdout.write(`[mmagent] auto-synced ${behind.length} updated skill(s)\n`);
81
+ if (missing.length > 0)
82
+ process.stdout.write(`[mmagent] auto-synced ${missing.length} new skill(s): ${missing.map((m) => m.name).join(', ')}\n`);
83
+ }
84
+ catch {
85
+ // bestEffort swallows inside; extra safety here.
86
+ }
87
+ }
88
+ function readServerVersion() {
89
+ try {
90
+ const thisDir = path.dirname(fileURLToPath(import.meta.url));
91
+ const pkgPath = path.join(thisDir, '..', '..', 'package.json');
92
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
93
+ return pkg.version ?? '0.0.0';
94
+ }
95
+ catch {
96
+ return '0.0.0';
97
+ }
98
+ }
99
+ function envVarHint(agentName) {
100
+ return `${agentName.toUpperCase().replace(/[^A-Z0-9]/g, '_')}_API_KEY`;
101
+ }
102
+ /**
103
+ * Shared signal-state used to deduplicate shutdown if two signals arrive
104
+ * before stop() resolves.
105
+ */
106
+ let stopInFlight = false;
107
+ // Stored so they can be removed when stop() is called programmatically
108
+ let onSigterm;
109
+ let onSigint;
110
+ let onStdoutErrorRef;
111
+ let onStderrErrorRef;
112
+ let onUncaughtRef;
113
+ let onUnhandledRejectionRef;
114
+ /**
115
+ * Start the HTTP server with the given config.
116
+ *
117
+ * Registers SIGTERM and SIGINT handlers that drain in-flight requests and
118
+ * exit the process cleanly. If config includes `server.limits.shutdownDrainMs`,
119
+ * the server will wait up to that duration for in-flight requests to finish.
120
+ *
121
+ * @param config Full MultiModelConfig (includes agents.*, defaults, diagnostics,
122
+ * and server block). startServer() inspects the agents.* field
123
+ * and enables real tool handlers when present.
124
+ * @param exit Process exit function — defaults to process.exit.
125
+ * Exposed so tests can suppress actual exits.
126
+ */
127
+ export async function startServe(config, exit = process.exit.bind(process)) {
128
+ const stderr = process.stderr.write.bind(process.stderr);
129
+ // Auto-update installed skills before bind (bounded 5s; never blocks indefinitely).
130
+ await maybeAutoUpdateSkills(config, stderr);
131
+ // Drift check — warn if installed skills don't match the canonical manifest.
132
+ try {
133
+ const { makeSkillManifestSync } = await import('../skill-install/skill-manifest-sync.js');
134
+ const { discoverPerClientInstallDirs } = await import('../skill-install/discover.js');
135
+ const sync = makeSkillManifestSync(discoverPerClientInstallDirs());
136
+ const drift = sync.driftReport();
137
+ if (drift.length > 0) {
138
+ const summary = drift.map(d => `${d.client}/${d.skill}=${d.issue}`).join(', ');
139
+ stderr(`[mmagent] WARN: skill manifest drift detected: ${summary}. Re-run 'mmagent sync-skills' to reconcile.\n`);
140
+ }
141
+ }
142
+ catch {
143
+ // best-effort — never let drift check block serve
144
+ }
145
+ // Create the telemetry recorder BEFORE startServer. The server's bus
146
+ // subscriber (TelemetryUploader) calls getRecorder() during startServer →
147
+ // if recorder is null at that moment, the uploader is wired with
148
+ // recorder=null and silently drops every event for the daemon's lifetime.
149
+ const homeDir = path.join(os.homedir(), '.multi-model');
150
+ const mmagentVersion = readServerVersion();
151
+ createRecorder({ homeDir, mmagentVersion });
152
+ // Pass the full MultiModelConfig (not just the server block) so
153
+ // registerToolHandlers sees `agents` and registers real tool endpoints.
154
+ // Stripping to { server } here caused a 3.1.0 regression where tool
155
+ // endpoints returned 503 'no_agent_config' even when agents were set.
156
+ const running = await startServer(config);
157
+ // ── stdout/stderr error + uncaught/unhandled rejection guards ────────
158
+ const logShutdown = (_cause) => {
159
+ // Option A: no diagnostics surface today. Cause name routed via stderr only.
160
+ // Option B (follow-up): wire running.diagnostics?.shutdown(_cause) here.
161
+ };
162
+ const onStdoutError = (err) => {
163
+ if (err.code === 'EPIPE') {
164
+ logShutdown('stdout_epipe');
165
+ exit(0);
166
+ }
167
+ logShutdown('stdout_other_error');
168
+ try {
169
+ process.stderr.write(`[mmagent] stdout error: ${err.message}\n`);
170
+ }
171
+ catch { /* stderr may also be dead */ }
172
+ exit(1);
173
+ };
174
+ const onStderrError = (err) => {
175
+ if (err.code === 'EPIPE') {
176
+ logShutdown('stdout_epipe');
177
+ exit(0);
178
+ }
179
+ logShutdown('stdout_other_error');
180
+ exit(1);
181
+ };
182
+ const onUncaught = (err) => {
183
+ const errno = err?.code;
184
+ if (errno === 'EPIPE') {
185
+ logShutdown('stdout_epipe');
186
+ exit(0);
187
+ }
188
+ logShutdown('uncaughtException');
189
+ try {
190
+ const msg = err instanceof Error ? (err.stack ?? err.message) : String(err);
191
+ process.stderr.write(`[mmagent] uncaught exception: ${msg}\n`);
192
+ }
193
+ catch { /* best-effort */ }
194
+ exit(1);
195
+ };
196
+ const onUnhandledRejection = (reason) => {
197
+ const errno = reason?.code;
198
+ if (errno === 'EPIPE') {
199
+ logShutdown('stdout_epipe');
200
+ exit(0);
201
+ }
202
+ logShutdown('unhandledRejection');
203
+ try {
204
+ const msg = reason instanceof Error ? (reason.stack ?? reason.message) : String(reason);
205
+ process.stderr.write(`[mmagent] unhandled rejection: ${msg}\n`);
206
+ }
207
+ catch { /* best-effort */ }
208
+ exit(1);
209
+ };
210
+ process.stdout.on('error', onStdoutError);
211
+ process.stderr.on('error', onStderrError);
212
+ process.on('uncaughtException', onUncaught);
213
+ process.on('unhandledRejection', onUnhandledRejection);
214
+ onStdoutErrorRef = onStdoutError;
215
+ onStderrErrorRef = onStderrError;
216
+ onUncaughtRef = onUncaught;
217
+ onUnhandledRejectionRef = onUnhandledRejection;
218
+ // Recorder was created above (BEFORE startServer). homeDir + mmagentVersion
219
+ // are computed there and reused here for the version-pin file + Flusher.
220
+ const lastVersionPath = path.join(homeDir, 'last-version');
221
+ let lastVersion = null;
222
+ try {
223
+ lastVersion = fs.readFileSync(lastVersionPath, 'utf8').trim();
224
+ }
225
+ catch {
226
+ // first run — no last-version file yet
227
+ }
228
+ if (lastVersion !== mmagentVersion) {
229
+ try {
230
+ fs.mkdirSync(homeDir, { recursive: true });
231
+ fs.writeFileSync(lastVersionPath, mmagentVersion + '\n', { mode: 0o600 });
232
+ }
233
+ catch (err) {
234
+ stderr(`[mmagent] warning: failed to write last-version at ${lastVersionPath}: ${err instanceof Error ? err.message : String(err)}\n`);
235
+ }
236
+ }
237
+ // Telemetry uploader. Default endpoint ships to the project's hosted
238
+ // dashboard. MMAGENT_TELEMETRY_ENDPOINT overrides for self-hosted backends;
239
+ // setting it to an empty string disables shipping entirely (events stay in
240
+ // ~/.multi-model/telemetry-queue.ndjson). The real off-switch for telemetry
241
+ // is the consent flag (MMAGENT_TELEMETRY=0 / config.telemetry.enabled =
242
+ // false) — when consent is off the recorder enqueues nothing, so the
243
+ // flusher's tick is a no-op even with the default endpoint set.
244
+ const DEFAULT_TELEMETRY_ENDPOINT = 'https://mma-telemetry-frontend.x1.lucazhang.work/v1/events';
245
+ const envEndpoint = process.env.MMAGENT_TELEMETRY_ENDPOINT;
246
+ const telemetryEndpoint = envEndpoint === undefined
247
+ ? DEFAULT_TELEMETRY_ENDPOINT
248
+ : envEndpoint.trim();
249
+ let flusher = null;
250
+ if (telemetryEndpoint) {
251
+ flusher = new Flusher({
252
+ queue: new Queue(homeDir),
253
+ dir: homeDir,
254
+ endpoint: telemetryEndpoint,
255
+ });
256
+ flusher.start();
257
+ }
258
+ // Fire once at serve startup. Lives here (not in loadConfigFromFile) so
259
+ // print-token / info / status don't re-emit the same warning repeatedly.
260
+ const inlineOffenders = collectInlineApiKeyOffenders(config);
261
+ if (inlineOffenders.length > 0) {
262
+ const firstHint = envVarHint(inlineOffenders[0]);
263
+ stderr(`[mmagent] WARNING: inline apiKey in config for agent(s): ${inlineOffenders.join(', ')}.\n` +
264
+ ` Fix:\n` +
265
+ ` export ${firstHint}='<your-key>'\n` +
266
+ ` # then in config.json, replace\n` +
267
+ ` # "apiKey": "..."\n` +
268
+ ` # with\n` +
269
+ ` # "apiKeyEnv": "${firstHint}"\n`);
270
+ }
271
+ const cleanupSignal = (sig) => {
272
+ if (stopInFlight)
273
+ return;
274
+ stopInFlight = true;
275
+ stderr(`[mmagent] received ${sig}, shutting down gracefully\u2026\n`);
276
+ // 1) Refuse new dispatches immediately so they don't compound the drain.
277
+ setDraining(true);
278
+ // 2) Walk BatchRegistry: close every in-flight task's sessions in parallel
279
+ // with a 5-second wall clock. After the grace window, SIGKILL any
280
+ // subprocess still alive whose session exposes a pid. Without this,
281
+ // SIGTERM-killed daemons leaked codex children as orphans (see 2026-05-16
282
+ // OOM post-mortem).
283
+ const SHUTDOWN_GRACE_MS = 5000;
284
+ const inflight = running.batchRegistry?.allInFlight?.() ?? [];
285
+ const closeAll = Promise.allSettled(inflight.flatMap((entry) => {
286
+ const ctxs = entry.executionContexts ? Array.from(entry.executionContexts.values()) : [];
287
+ return ctxs.map(async (ec) => {
288
+ try {
289
+ await ec.closeSessions();
290
+ }
291
+ catch { /* swallow */ }
292
+ });
293
+ }));
294
+ const drainSessions = Promise.race([
295
+ closeAll,
296
+ new Promise((resolve) => setTimeout(resolve, SHUTDOWN_GRACE_MS).unref()),
297
+ ]).then(() => {
298
+ // Belt-and-suspenders: SIGKILL anything still alive whose pid we know.
299
+ for (const entry of inflight) {
300
+ const ctxs = entry.executionContexts ? Array.from(entry.executionContexts.values()) : [];
301
+ for (const ec of ctxs) {
302
+ for (const pid of ec.getActivePids?.() ?? []) {
303
+ try {
304
+ process.kill(pid, 'SIGKILL');
305
+ }
306
+ catch { /* already dead */ }
307
+ }
308
+ }
309
+ }
310
+ });
311
+ const drainTelemetry = flusher ? flusher.drain() : Promise.resolve();
312
+ drainSessions
313
+ .catch(() => { })
314
+ .then(() => drainTelemetry)
315
+ .catch(() => { })
316
+ .then(() => running.stop())
317
+ .then(() => exit(0))
318
+ .catch((err) => {
319
+ const msg = err instanceof Error ? err.message : String(err);
320
+ stderr(`[mmagent] shutdown failed: ${msg}\n`);
321
+ exit(1);
322
+ });
323
+ };
324
+ // Register handlers using named references so they can be removed correctly.
325
+ // Using anonymous wrappers (e.g. `process.once('SIGTERM', () => fn(sig))`)
326
+ // would make process.off(sig, fn) unable to find and remove the listener.
327
+ onSigterm = () => cleanupSignal('SIGTERM');
328
+ onSigint = () => cleanupSignal('SIGINT');
329
+ process.once('SIGTERM', onSigterm);
330
+ process.once('SIGINT', onSigint);
331
+ // Print the actual bound address so operators see what the kernel assigned
332
+ // (useful when port=0 selects an ephemeral port).
333
+ const host = running.serverAddress ?? config.server.bind;
334
+ // Emit a single structured startup line before the "listening" line.
335
+ // Fingerprint the auth token (first 8 hex of sha256) so operators can verify
336
+ // the running instance matches what their clients are using, without ever
337
+ // revealing the token. bootId discriminates successive startups from the same pid.
338
+ try {
339
+ const token = loadAuthToken({ tokenFile: config.server.auth.tokenFile });
340
+ const fp = createHash('sha256').update(token).digest('hex').slice(0, 8);
341
+ const bootId = randomUUID();
342
+ const version = readServerVersion();
343
+ process.stdout.write(`[mmagent] started | version=${version} | bind=${host}:${running.port} | pid=${process.pid} | token=${fp} | boot=${bootId}\n`);
344
+ }
345
+ catch {
346
+ // Token load shouldn't fail here (startServer already validated it), but
347
+ // if it does, skip the startup line rather than crash the server.
348
+ }
349
+ // Per-tier model lines so operators can see which provider is wired to
350
+ // each agent slot. The complex tier handles read-only sub-workers + most
351
+ // implementer work; the standard tier handles annotator/reviewer + the
352
+ // explore route's internal half. When a tier is unconfigured, log it as
353
+ // "(not configured)" so a misconfigured slot is visible at boot time.
354
+ const fmtTier = (slot) => {
355
+ const cfg = config.agents[slot];
356
+ if (!cfg || !cfg.model)
357
+ return '(not configured)';
358
+ return `${cfg.model} [${cfg.type ?? 'unknown'}]`;
359
+ };
360
+ process.stdout.write(`[mmagent] tiers | complex=${fmtTier('complex')} | standard=${fmtTier('standard')}\n`);
361
+ // A4a.4 (4.2.2+): warn when stale Claude Code project siblings exist
362
+ // under /tmp/claude/G--*. These come from prior Claude Code test runs
363
+ // and confuse worker cwd resolution if a caller passes one as ?cwd=.
364
+ // The validator already rejects them at request time (A4a.1); this
365
+ // startup scan surfaces the contamination so operators clean it up.
366
+ // Pure log behavior — does NOT block startup.
367
+ for (const root of ['/tmp/claude', '/private/tmp/claude']) {
368
+ try {
369
+ if (!fs.existsSync(root))
370
+ continue;
371
+ const stale = fs.readdirSync(root).filter(e => e.startsWith('G--'));
372
+ if (stale.length > 0) {
373
+ process.stdout.write(`[mmagent] WARNING: ${stale.length} stale Claude Code project sibling(s) under ${root}/G--*. ` +
374
+ `These can confuse cwd resolution; clean up with: rm -rf ${root}/G--*\n`);
375
+ }
376
+ }
377
+ catch { /* swallow — log-only */ }
378
+ }
379
+ process.stdout.write(`[mmagent] listening on ${host}:${running.port}\n`);
380
+ return {
381
+ port: running.port,
382
+ stop: async () => {
383
+ // Clean up signal listeners to prevent leaks when stop() is called
384
+ // programmatically (i.e. not via a signal).
385
+ if (onSigterm)
386
+ process.off('SIGTERM', onSigterm);
387
+ if (onSigint)
388
+ process.off('SIGINT', onSigint);
389
+ if (onStdoutErrorRef)
390
+ process.stdout.off('error', onStdoutErrorRef);
391
+ if (onStderrErrorRef)
392
+ process.stderr.off('error', onStderrErrorRef);
393
+ if (onUncaughtRef)
394
+ process.off('uncaughtException', onUncaughtRef);
395
+ if (onUnhandledRejectionRef)
396
+ process.off('unhandledRejection', onUnhandledRejectionRef);
397
+ onStdoutErrorRef = onStderrErrorRef = onUncaughtRef = onUnhandledRejectionRef = undefined;
398
+ if (flusher) {
399
+ await flusher.drain().catch(() => { });
400
+ }
401
+ await running.stop();
402
+ },
403
+ };
404
+ }
405
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/cli/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ export interface StatusDeps {
2
+ /** Server URL (e.g. 'http://127.0.0.1:7337'). */
3
+ serverUrl: string;
4
+ /** Bearer auth token. */
5
+ token: string;
6
+ /** Output as raw JSON instead of pretty-printed summary. */
7
+ json?: boolean;
8
+ /** Write to stdout. */
9
+ stdout?: (s: string) => boolean;
10
+ /** Write to stderr. */
11
+ stderr?: (s: string) => boolean;
12
+ /** Inject fetch for testability. Defaults to global fetch. */
13
+ fetch?: typeof fetch;
14
+ }
15
+ /**
16
+ * Fetch GET /status and print a summary (or raw JSON).
17
+ * Returns an exit code: 0 on success, 1 on error.
18
+ */
19
+ export declare function fetchStatus(deps: StatusDeps): Promise<number>;
20
+ /**
21
+ * Build the server URL from a bind address and port.
22
+ * Handles '0.0.0.0' / '::' by converting to '127.0.0.1' since /status
23
+ * is loopback-only.
24
+ */
25
+ export declare function buildServerUrl(bind: string, port: number): string;
26
+ export interface RunStatusDeps {
27
+ /** Config with server.bind + server.port. */
28
+ serverUrl: string;
29
+ /** Token file path (already resolved). */
30
+ tokenFile: string;
31
+ /** Whether to output raw JSON. */
32
+ json?: boolean;
33
+ /** Environment variable accessor (for MMAGENT_AUTH_TOKEN override). */
34
+ env?: Record<string, string | undefined>;
35
+ /** Write to stdout. */
36
+ stdout?: (s: string) => boolean;
37
+ /** Write to stderr. */
38
+ stderr?: (s: string) => boolean;
39
+ /** Inject fetch for testability. */
40
+ fetch?: typeof fetch;
41
+ /** Home directory (used to expand token file paths). */
42
+ homeDir?: string;
43
+ }
44
+ /**
45
+ * Read the token and then call fetchStatus.
46
+ * Returns exit code.
47
+ */
48
+ export declare function runStatus(deps: RunStatusDeps): Promise<number>;
49
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAiBD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAuEnE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCpE"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * status.ts — `mmagent status` subcommand.
3
+ *
4
+ * Fetches GET /status from a running server and pretty-prints a summary.
5
+ * Supports --json to dump the raw JSON response.
6
+ * Exits 1 if the server is unreachable or returns an error status.
7
+ *
8
+ * Usage:
9
+ * mmagent status [--config <path>] [--json]
10
+ */
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ /**
14
+ * Format uptime in ms as a human-readable string.
15
+ */
16
+ function formatUptime(ms) {
17
+ const seconds = Math.floor(ms / 1000);
18
+ const minutes = Math.floor(seconds / 60);
19
+ const hours = Math.floor(minutes / 60);
20
+ const days = Math.floor(hours / 24);
21
+ if (days > 0)
22
+ return `${days}d ${hours % 24}h ${minutes % 60}m`;
23
+ if (hours > 0)
24
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
25
+ if (minutes > 0)
26
+ return `${minutes}m ${seconds % 60}s`;
27
+ return `${seconds}s`;
28
+ }
29
+ /**
30
+ * Fetch GET /status and print a summary (or raw JSON).
31
+ * Returns an exit code: 0 on success, 1 on error.
32
+ */
33
+ export async function fetchStatus(deps) {
34
+ const { serverUrl, token, json = false } = deps;
35
+ const stdout = deps.stdout ?? process.stdout.write.bind(process.stdout);
36
+ const stderr = deps.stderr ?? process.stderr.write.bind(process.stderr);
37
+ const fetcher = deps.fetch ?? fetch;
38
+ const url = `${serverUrl.replace(/\/$/, '')}/status`;
39
+ let res;
40
+ try {
41
+ res = await fetcher(url, {
42
+ method: 'GET',
43
+ headers: {
44
+ Authorization: `Bearer ${token}`,
45
+ Accept: 'application/json',
46
+ },
47
+ });
48
+ }
49
+ catch (err) {
50
+ const msg = err instanceof Error ? err.message : String(err);
51
+ stderr(`mmagent status: cannot reach server at ${serverUrl}: ${msg}\n`);
52
+ stderr(`Is the server running? Start it with 'mmagent serve'.\n`);
53
+ return 1;
54
+ }
55
+ if (!res.ok) {
56
+ stderr(`mmagent status: server returned HTTP ${res.status} ${res.statusText}\n`);
57
+ return 1;
58
+ }
59
+ let body;
60
+ try {
61
+ body = (await res.json());
62
+ }
63
+ catch (err) {
64
+ stderr(`mmagent status: invalid JSON response from server\n`);
65
+ return 1;
66
+ }
67
+ if (json) {
68
+ stdout(JSON.stringify(body, null, 2) + '\n');
69
+ return 0;
70
+ }
71
+ // Pretty-print summary
72
+ const lines = [];
73
+ lines.push(`mmagent server status`);
74
+ lines.push(`─────────────────────────────`);
75
+ if (body.version)
76
+ lines.push(` version: ${body.version}`);
77
+ if (body.pid !== undefined)
78
+ lines.push(` pid: ${body.pid}`);
79
+ if (body.bind)
80
+ lines.push(` bind: ${body.bind}`);
81
+ if (body.uptimeMs !== undefined)
82
+ lines.push(` uptime: ${formatUptime(body.uptimeMs)}`);
83
+ const c = body.counters;
84
+ if (c) {
85
+ lines.push(` projects: ${c.projectCount ?? 0}`);
86
+ lines.push(` active batches: ${c.activeBatches ?? 0}`);
87
+ lines.push(` active reqs: ${c.activeRequests ?? 0}`);
88
+ }
89
+ const inflightCount = Array.isArray(body.inflight) ? body.inflight.length : 0;
90
+ lines.push(` in-flight: ${inflightCount}`);
91
+ if (body.skillVersion !== undefined) {
92
+ const sv = body.skillVersion ?? 'none';
93
+ const compat = body.skillCompatible === true ? ' (compatible)'
94
+ : body.skillCompatible === false ? ' (incompatible — run mmagent sync-skills to reconcile)'
95
+ : '';
96
+ lines.push(` skill version: ${sv}${compat}`);
97
+ }
98
+ stdout(lines.join('\n') + '\n');
99
+ return 0;
100
+ }
101
+ /**
102
+ * Build the server URL from a bind address and port.
103
+ * Handles '0.0.0.0' / '::' by converting to '127.0.0.1' since /status
104
+ * is loopback-only.
105
+ */
106
+ export function buildServerUrl(bind, port) {
107
+ const host = (bind === '0.0.0.0' || bind === '::') ? '127.0.0.1' : bind;
108
+ return `http://${host}:${port}`;
109
+ }
110
+ /**
111
+ * Read the token and then call fetchStatus.
112
+ * Returns exit code.
113
+ */
114
+ export async function runStatus(deps) {
115
+ const { serverUrl, tokenFile, json = false } = deps;
116
+ const env = deps.env ?? process.env;
117
+ const stderr = deps.stderr ?? process.stderr.write.bind(process.stderr);
118
+ const homeDir = deps.homeDir ?? os.homedir();
119
+ // Read the token (env wins)
120
+ let token;
121
+ const envToken = (env['MMAGENT_AUTH_TOKEN'] ?? '').trim();
122
+ if (envToken.length > 0) {
123
+ token = envToken;
124
+ }
125
+ else {
126
+ const { readFileSync } = await import('node:fs');
127
+ const resolvedTokenFile = tokenFile.startsWith('~/')
128
+ ? path.join(homeDir, tokenFile.slice(2))
129
+ : tokenFile;
130
+ try {
131
+ token = readFileSync(resolvedTokenFile, 'utf-8').trim();
132
+ }
133
+ catch (err) {
134
+ const code = err.code;
135
+ if (code === 'ENOENT') {
136
+ stderr(`mmagent status: token file not found: ${resolvedTokenFile}\n`);
137
+ stderr(`Run 'mmagent print-token' or set MMAGENT_AUTH_TOKEN.\n`);
138
+ }
139
+ else {
140
+ const msg = err instanceof Error ? err.message : String(err);
141
+ stderr(`mmagent status: cannot read token file: ${msg}\n`);
142
+ }
143
+ return 1;
144
+ }
145
+ }
146
+ return fetchStatus({
147
+ serverUrl,
148
+ token,
149
+ json,
150
+ stdout: deps.stdout,
151
+ stderr: deps.stderr,
152
+ fetch: deps.fetch,
153
+ });
154
+ }
155
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"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"}