@zhixuan92/multi-model-agent 3.5.2 → 3.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 (93) hide show
  1. package/dist/cli/index.d.ts.map +1 -1
  2. package/dist/cli/index.js +20 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/serve.d.ts.map +1 -1
  5. package/dist/cli/serve.js +59 -0
  6. package/dist/cli/serve.js.map +1 -1
  7. package/dist/cli/telemetry.d.ts +10 -0
  8. package/dist/cli/telemetry.d.ts.map +1 -0
  9. package/dist/cli/telemetry.js +160 -0
  10. package/dist/cli/telemetry.js.map +1 -0
  11. package/dist/http/async-dispatch.js +1 -1
  12. package/dist/http/async-dispatch.js.map +1 -1
  13. package/dist/http/execution-context.d.ts +1 -1
  14. package/dist/http/execution-context.d.ts.map +1 -1
  15. package/dist/http/execution-context.js +15 -8
  16. package/dist/http/execution-context.js.map +1 -1
  17. package/dist/http/middleware/body-size.d.ts +7 -0
  18. package/dist/http/middleware/body-size.d.ts.map +1 -0
  19. package/dist/http/middleware/body-size.js +7 -0
  20. package/dist/http/middleware/body-size.js.map +1 -0
  21. package/dist/http/middleware/caller-identity.d.ts +11 -0
  22. package/dist/http/middleware/caller-identity.d.ts.map +1 -0
  23. package/dist/http/middleware/caller-identity.js +27 -0
  24. package/dist/http/middleware/caller-identity.js.map +1 -0
  25. package/dist/http/middleware/decompress.d.ts +14 -0
  26. package/dist/http/middleware/decompress.d.ts.map +1 -0
  27. package/dist/http/middleware/decompress.js +51 -0
  28. package/dist/http/middleware/decompress.js.map +1 -0
  29. package/dist/http/request-pipeline.d.ts.map +1 -1
  30. package/dist/http/request-pipeline.js +23 -3
  31. package/dist/http/request-pipeline.js.map +1 -1
  32. package/dist/http/server.d.ts +1 -0
  33. package/dist/http/server.d.ts.map +1 -1
  34. package/dist/http/server.js +1 -1
  35. package/dist/http/server.js.map +1 -1
  36. package/dist/http/types.d.ts +3 -0
  37. package/dist/http/types.d.ts.map +1 -1
  38. package/dist/install/headers.d.ts +17 -0
  39. package/dist/install/headers.d.ts.map +1 -0
  40. package/dist/install/headers.js +22 -0
  41. package/dist/install/headers.js.map +1 -0
  42. package/dist/install/manifest-resolve.d.ts.map +1 -1
  43. package/dist/install/manifest-resolve.js +5 -0
  44. package/dist/install/manifest-resolve.js.map +1 -1
  45. package/dist/install/manifest.d.ts +2 -2
  46. package/dist/install/notify.d.ts +6 -0
  47. package/dist/install/notify.d.ts.map +1 -0
  48. package/dist/install/notify.js +16 -0
  49. package/dist/install/notify.js.map +1 -0
  50. package/dist/skills/mma-audit/SKILL.md +1 -1
  51. package/dist/skills/mma-clarifications/SKILL.md +1 -1
  52. package/dist/skills/mma-context-blocks/SKILL.md +1 -1
  53. package/dist/skills/mma-debug/SKILL.md +1 -1
  54. package/dist/skills/mma-delegate/SKILL.md +1 -1
  55. package/dist/skills/mma-execute-plan/SKILL.md +1 -1
  56. package/dist/skills/mma-investigate/SKILL.md +1 -1
  57. package/dist/skills/mma-retry/SKILL.md +1 -1
  58. package/dist/skills/mma-review/SKILL.md +1 -1
  59. package/dist/skills/mma-verify/SKILL.md +1 -1
  60. package/dist/skills/multi-model-agent/SKILL.md +1 -1
  61. package/dist/telemetry/consent.d.ts +4 -0
  62. package/dist/telemetry/consent.d.ts.map +1 -0
  63. package/dist/telemetry/consent.js +40 -0
  64. package/dist/telemetry/consent.js.map +1 -0
  65. package/dist/telemetry/flusher.d.ts +19 -0
  66. package/dist/telemetry/flusher.d.ts.map +1 -0
  67. package/dist/telemetry/flusher.js +231 -0
  68. package/dist/telemetry/flusher.js.map +1 -0
  69. package/dist/telemetry/generation.d.ts +9 -0
  70. package/dist/telemetry/generation.d.ts.map +1 -0
  71. package/dist/telemetry/generation.js +33 -0
  72. package/dist/telemetry/generation.js.map +1 -0
  73. package/dist/telemetry/install-id.d.ts +13 -0
  74. package/dist/telemetry/install-id.d.ts.map +1 -0
  75. package/dist/telemetry/install-id.js +49 -0
  76. package/dist/telemetry/install-id.js.map +1 -0
  77. package/dist/telemetry/install-meta.d.ts +6 -0
  78. package/dist/telemetry/install-meta.d.ts.map +1 -0
  79. package/dist/telemetry/install-meta.js +38 -0
  80. package/dist/telemetry/install-meta.js.map +1 -0
  81. package/dist/telemetry/notice.d.ts +9 -0
  82. package/dist/telemetry/notice.d.ts.map +1 -0
  83. package/dist/telemetry/notice.js +91 -0
  84. package/dist/telemetry/notice.js.map +1 -0
  85. package/dist/telemetry/queue.d.ts +34 -0
  86. package/dist/telemetry/queue.d.ts.map +1 -0
  87. package/dist/telemetry/queue.js +239 -0
  88. package/dist/telemetry/queue.js.map +1 -0
  89. package/dist/telemetry/recorder.d.ts +18 -0
  90. package/dist/telemetry/recorder.d.ts.map +1 -0
  91. package/dist/telemetry/recorder.js +123 -0
  92. package/dist/telemetry/recorder.js.map +1 -0
  93. package/package.json +5 -3
@@ -0,0 +1,239 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { writeFile, readFile, rename, stat, open } from 'node:fs/promises';
3
+ import { existsSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import lockfile from 'proper-lockfile';
6
+ const QUEUE_FILE = 'telemetry-queue.ndjson';
7
+ const MAX_SIZE_BYTES = 10 * 1024 * 1024; // 10 MiB
8
+ const MAX_RECORDS = 10_000;
9
+ const CAP_TRUNCATE_COUNT = 1_000;
10
+ const MAX_BATCH_READ = 500;
11
+ const LOCK_OPTIONS = {
12
+ retries: { retries: 10, minTimeout: 50, maxTimeout: 150, factor: 1.3 },
13
+ };
14
+ let capWarned = false;
15
+ function resetCapWarning() {
16
+ capWarned = false;
17
+ }
18
+ function deepSort(obj) {
19
+ if (Array.isArray(obj))
20
+ return obj.map(deepSort);
21
+ if (obj !== null && typeof obj === 'object') {
22
+ const sorted = {};
23
+ for (const key of Object.keys(obj).sort()) {
24
+ sorted[key] = deepSort(obj[key]);
25
+ }
26
+ return sorted;
27
+ }
28
+ return obj;
29
+ }
30
+ function canonicalSerialize(record) {
31
+ return JSON.stringify(deepSort(record)) + '\n';
32
+ }
33
+ function hashLine(line) {
34
+ return createHash('sha256').update(line).digest('hex');
35
+ }
36
+ async function ensureFile(p) {
37
+ if (!existsSync(p)) {
38
+ try {
39
+ await writeFile(p, '', { mode: 0o600, flag: 'wx' });
40
+ }
41
+ catch {
42
+ // race: another process created it between our check and write
43
+ }
44
+ }
45
+ }
46
+ export class Queue {
47
+ #dir;
48
+ #queuePath;
49
+ #approxCount = 0;
50
+ #appendsSinceCapCheck = 0;
51
+ constructor(dir) {
52
+ this.#dir = dir;
53
+ this.#queuePath = join(dir, QUEUE_FILE);
54
+ }
55
+ get queuePath() {
56
+ return this.#queuePath;
57
+ }
58
+ async append(record) {
59
+ // Ensure file exists before locking (proper-lockfile requires it)
60
+ await ensureFile(this.#queuePath);
61
+ let release = null;
62
+ try {
63
+ release = await lockfile.lock(this.#queuePath, LOCK_OPTIONS);
64
+ }
65
+ catch {
66
+ return; // lock timeout — silently skip
67
+ }
68
+ try {
69
+ await this.#enforceCap();
70
+ const line = canonicalSerialize(record);
71
+ const fd = await open(this.#queuePath, 'a', 0o600);
72
+ try {
73
+ await fd.write(line);
74
+ }
75
+ finally {
76
+ await fd.close();
77
+ }
78
+ // fsync skipped here — best-effort, adds significant per-append latency.
79
+ // OS buffers are flushed on process exit; crash recovery is handled by
80
+ // the corruption-rotation path on next readBatch.
81
+ }
82
+ finally {
83
+ if (release)
84
+ await release();
85
+ }
86
+ }
87
+ async readBatch(maxRecords = MAX_BATCH_READ) {
88
+ const records = [];
89
+ const meta = [];
90
+ // Don't create if missing; just return empty
91
+ if (!existsSync(this.#queuePath))
92
+ return { records, meta };
93
+ let release = null;
94
+ try {
95
+ release = await lockfile.lock(this.#queuePath, LOCK_OPTIONS);
96
+ }
97
+ catch {
98
+ return { records, meta };
99
+ }
100
+ try {
101
+ if (!existsSync(this.#queuePath))
102
+ return { records, meta };
103
+ const content = await readFile(this.#queuePath, 'utf8');
104
+ if (!content.trim())
105
+ return { records, meta };
106
+ const lines = content.split('\n');
107
+ let byteOffset = 0;
108
+ for (const line of lines) {
109
+ if (records.length >= maxRecords)
110
+ break;
111
+ if (!line.trim()) {
112
+ byteOffset += line.length + 1;
113
+ continue;
114
+ }
115
+ const lineBytes = line + '\n';
116
+ try {
117
+ const record = JSON.parse(line);
118
+ records.push(record);
119
+ meta.push({
120
+ byteOffset,
121
+ byteLength: Buffer.byteLength(lineBytes),
122
+ sha256: hashLine(lineBytes),
123
+ });
124
+ }
125
+ catch {
126
+ // Corrupted line: rotate entire file and stop reading
127
+ await this.#rotateCorrupted();
128
+ return { records, meta: [] };
129
+ }
130
+ byteOffset += Buffer.byteLength(lineBytes);
131
+ }
132
+ }
133
+ finally {
134
+ if (release)
135
+ await release();
136
+ }
137
+ return { records, meta };
138
+ }
139
+ async truncate(expectedMeta) {
140
+ if (expectedMeta.length === 0)
141
+ return;
142
+ if (!existsSync(this.#queuePath))
143
+ return;
144
+ let release = null;
145
+ try {
146
+ release = await lockfile.lock(this.#queuePath, LOCK_OPTIONS);
147
+ }
148
+ catch {
149
+ return;
150
+ }
151
+ try {
152
+ if (!existsSync(this.#queuePath))
153
+ return;
154
+ const content = await readFile(this.#queuePath, 'utf8');
155
+ const lines = content.split('\n');
156
+ // Verify SHA-256 of the first expectedMeta.length records
157
+ let byteOffset = 0;
158
+ let verified = 0;
159
+ for (const line of lines) {
160
+ if (verified >= expectedMeta.length)
161
+ break;
162
+ if (!line.trim()) {
163
+ byteOffset += line.length + 1;
164
+ continue;
165
+ }
166
+ const lineBytes = line + '\n';
167
+ const actualHash = hashLine(lineBytes);
168
+ if (actualHash !== expectedMeta[verified].sha256 ||
169
+ byteOffset !== expectedMeta[verified].byteOffset) {
170
+ return; // hash mismatch — don't truncate
171
+ }
172
+ byteOffset += Buffer.byteLength(lineBytes);
173
+ verified++;
174
+ }
175
+ if (verified === 0)
176
+ return;
177
+ // Atomically truncate: write remainder to temp file + rename
178
+ const remainder = content.slice(byteOffset);
179
+ const tmpPath = this.#queuePath + '.tmp.' + Date.now();
180
+ await writeFile(tmpPath, remainder, { mode: 0o600 });
181
+ await rename(tmpPath, this.#queuePath);
182
+ }
183
+ finally {
184
+ if (release)
185
+ await release();
186
+ }
187
+ }
188
+ async #enforceCap() {
189
+ this.#approxCount++;
190
+ this.#appendsSinceCapCheck++;
191
+ // Only check periodically to avoid reading the file on every append
192
+ if (this.#appendsSinceCapCheck < 100 && this.#approxCount < MAX_RECORDS)
193
+ return;
194
+ this.#appendsSinceCapCheck = 0;
195
+ // Quick size check first
196
+ const st = await stat(this.#queuePath);
197
+ if (st.size <= MAX_SIZE_BYTES && this.#approxCount <= MAX_RECORDS)
198
+ return;
199
+ // Full check: read the file to get exact record count
200
+ const content = await readFile(this.#queuePath, 'utf8');
201
+ const lines = content.split('\n').filter(l => l.trim());
202
+ const recordCount = lines.length;
203
+ if (st.size <= MAX_SIZE_BYTES && recordCount <= MAX_RECORDS) {
204
+ this.#approxCount = recordCount;
205
+ return;
206
+ }
207
+ if (!capWarned) {
208
+ console.warn('mma-telemetry: queue capped (10 MiB or 10,000 events), dropping oldest 1,000');
209
+ capWarned = true;
210
+ }
211
+ // Compute byte offset to drop exactly CAP_TRUNCATE_COUNT records
212
+ let dropped = 0;
213
+ let cutOffset = 0;
214
+ for (const line of content.split('\n')) {
215
+ if (dropped >= CAP_TRUNCATE_COUNT)
216
+ break;
217
+ if (!line.trim()) {
218
+ cutOffset += line.length + 1;
219
+ continue;
220
+ }
221
+ cutOffset += Buffer.byteLength(line + '\n');
222
+ dropped++;
223
+ }
224
+ const remainder = content.slice(cutOffset);
225
+ const tmpPath = this.#queuePath + '.cap.' + Date.now();
226
+ await writeFile(tmpPath, remainder, { mode: 0o600 });
227
+ await rename(tmpPath, this.#queuePath);
228
+ // Reset approximate counter after truncation
229
+ this.#approxCount = Math.max(0, recordCount - CAP_TRUNCATE_COUNT);
230
+ }
231
+ async #rotateCorrupted() {
232
+ const ts = Date.now();
233
+ const corruptedPath = this.#queuePath.replace('.ndjson', `.corrupted-${ts}.ndjson`);
234
+ await rename(this.#queuePath, corruptedPath);
235
+ await writeFile(this.#queuePath, '', { mode: 0o600 });
236
+ }
237
+ }
238
+ export { resetCapWarning };
239
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/telemetry/queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type BuildContext, type SessionSnapshot } from '@zhixuan92/multi-model-agent-core/telemetry/event-builder';
2
+ export interface Recorder {
3
+ readonly signal: AbortSignal;
4
+ recordTaskCompleted(ctx: BuildContext): void;
5
+ recordSessionStarted(snap: SessionSnapshot): void;
6
+ recordInstallChanged(from: string | null, to: string, trigger: string): void;
7
+ recordSkillInstalled(skillId: string, client: string): void;
8
+ revokeIdentity(options?: {
9
+ deleteInstallId?: boolean;
10
+ }): Promise<void>;
11
+ }
12
+ export declare function getRecorder(): Recorder;
13
+ export declare function setRecorderForTest(r: Recorder): void;
14
+ export declare function createRecorder(opts: {
15
+ homeDir: string;
16
+ mmagentVersion: string;
17
+ }): Recorder;
18
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/telemetry/recorder.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,2DAA2D,CAAC;AAEnE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7C,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAClD,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7E,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5D,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAID,wBAAgB,WAAW,IAAI,QAAQ,CAKtC;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAEpD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,CAI1F"}
@@ -0,0 +1,123 @@
1
+ import { existsSync, unlinkSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { decide } from './consent.js';
4
+ import { getOrCreateInstallId, deleteInstallId } from './install-id.js';
5
+ import { buildInstallMeta } from './install-meta.js';
6
+ import { Queue } from './queue.js';
7
+ import { readGeneration, bumpGeneration } from './generation.js';
8
+ import { SCHEMA_VERSION } from '@zhixuan92/multi-model-agent-core/telemetry/types';
9
+ import { buildTaskCompletedEvent, buildSessionStartedEvent, buildInstallChangedEvent, buildSkillInstalledEvent, } from '@zhixuan92/multi-model-agent-core/telemetry/event-builder';
10
+ let _recorder = null;
11
+ export function getRecorder() {
12
+ if (!_recorder) {
13
+ throw new Error('Recorder not initialized — call createRecorder first');
14
+ }
15
+ return _recorder;
16
+ }
17
+ export function setRecorderForTest(r) {
18
+ _recorder = r;
19
+ }
20
+ export function createRecorder(opts) {
21
+ const recorder = _buildRecorder(opts);
22
+ _recorder = recorder;
23
+ return recorder;
24
+ }
25
+ function _buildRecorder(opts) {
26
+ const { homeDir, mmagentVersion } = opts;
27
+ const queue = new Queue(homeDir);
28
+ const controller = new AbortController();
29
+ let _installId = null;
30
+ let dropped = 0;
31
+ const resolveInstallId = () => {
32
+ if (!_installId) {
33
+ _installId = getOrCreateInstallId(homeDir);
34
+ }
35
+ return _installId;
36
+ };
37
+ const enqueue = (event) => {
38
+ try {
39
+ const id = resolveInstallId();
40
+ const meta = buildInstallMeta({ installId: id, mmagentVersion });
41
+ const gen = readGeneration(homeDir);
42
+ queue.append({
43
+ schemaVersion: SCHEMA_VERSION,
44
+ install: {
45
+ installId: meta.installId,
46
+ mmagentVersion: meta.mmagentVersion,
47
+ os: meta.os,
48
+ nodeMajor: meta.nodeMajor,
49
+ language: meta.language,
50
+ tzOffsetBucket: meta.tzOffsetBucket,
51
+ },
52
+ generation: gen,
53
+ event,
54
+ }).catch(() => {
55
+ dropped++;
56
+ });
57
+ }
58
+ catch {
59
+ dropped++;
60
+ }
61
+ };
62
+ return {
63
+ get signal() {
64
+ return controller.signal;
65
+ },
66
+ recordTaskCompleted(ctx) {
67
+ try {
68
+ const d = decide(homeDir);
69
+ if (!d.enabled)
70
+ return;
71
+ enqueue(buildTaskCompletedEvent(ctx));
72
+ }
73
+ catch {
74
+ dropped++;
75
+ }
76
+ },
77
+ recordSessionStarted(snap) {
78
+ try {
79
+ const d = decide(homeDir);
80
+ if (!d.enabled)
81
+ return;
82
+ enqueue(buildSessionStartedEvent(snap));
83
+ }
84
+ catch {
85
+ dropped++;
86
+ }
87
+ },
88
+ recordInstallChanged(from, to, trigger) {
89
+ try {
90
+ const d = decide(homeDir);
91
+ if (!d.enabled)
92
+ return;
93
+ enqueue(buildInstallChangedEvent(from, to, trigger));
94
+ }
95
+ catch {
96
+ dropped++;
97
+ }
98
+ },
99
+ recordSkillInstalled(skillId, client) {
100
+ try {
101
+ const d = decide(homeDir);
102
+ if (!d.enabled)
103
+ return;
104
+ enqueue(buildSkillInstalledEvent(skillId, client));
105
+ }
106
+ catch {
107
+ dropped++;
108
+ }
109
+ },
110
+ async revokeIdentity(options) {
111
+ await bumpGeneration(homeDir);
112
+ controller.abort();
113
+ const queuePath = join(homeDir, 'telemetry-queue.ndjson');
114
+ if (existsSync(queuePath))
115
+ unlinkSync(queuePath);
116
+ _installId = null;
117
+ if (options?.deleteInstallId) {
118
+ deleteInstallId(homeDir);
119
+ }
120
+ },
121
+ };
122
+ }
123
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/telemetry/recorder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhixuan92/multi-model-agent",
3
- "version": "3.5.2",
3
+ "version": "3.6.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Standalone HTTP server for multi-model-agent. Routes tool-invocation work to Claude, Codex, or OpenAI-compatible sub-agents with async-polling REST dispatch and installable skills for Claude Code, Gemini CLI, Codex CLI, and Cursor.",
@@ -52,12 +52,14 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@asteasolutions/zod-to-openapi": "^8.5.0",
55
- "@zhixuan92/multi-model-agent-core": "^3.5.2",
55
+ "@zhixuan92/multi-model-agent-core": "^3.6.0",
56
56
  "gray-matter": "^4.0.3",
57
57
  "minimist": "^1.2.8",
58
+ "proper-lockfile": "^4.1.2",
58
59
  "zod": "^4.0.0"
59
60
  },
60
61
  "devDependencies": {
61
- "@types/minimist": "^1.2.5"
62
+ "@types/minimist": "^1.2.5",
63
+ "@types/proper-lockfile": "^4.1.4"
62
64
  }
63
65
  }