@moda-ai/cli 1.55.28 → 1.55.30
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.
- package/dist/{agent-0w9rtdsw.js → agent-wjkgt137.js} +3 -3
- package/dist/{cli-ny48a8de.js → cli-2eqh3150.js} +2 -2
- package/dist/{cli-3n0gz4d0.js → cli-37r94bmk.js} +10238 -10127
- package/dist/{cli-yf39avhh.js → cli-5b4tz5vj.js} +1 -1
- package/dist/{cli-3retgh64.js → cli-6ycf2aj5.js} +5 -5
- package/dist/cli.js +366 -47
- package/dist/{doctor-k3ta6h2y.js → doctor-2hd9rq68.js} +2 -2
- package/dist/{harness-7azmzytc.js → harness-8rbsmg8y.js} +1 -1
- package/dist/{harness-github-actions-bv2qrnqb.js → harness-github-actions-jwfvzf5x.js} +1 -1
- package/dist/{index-d1z50dsq.js → index-ecsjv99z.js} +3 -3
- package/dist/{prompt-attribution-1nytc9wj.js → prompt-attribution-gypvn8z9.js} +1 -1
- package/dist/prompt-source-mcp.js +1 -1
- package/dist/{prompts-6y9wfq5z.js → prompts-3qr24vd6.js} +1 -1
- package/dist/{prompts-ab-ezrd63sk.js → prompts-ab-98pqf06s.js} +2 -2
- package/dist/{prompts-propose-2k3enm2q.js → prompts-propose-md1k1ax8.js} +2 -2
- package/dist/{registry-96aze5wp.js → registry-ctnn8e26.js} +20 -3
- package/dist/{sync-ew7yvy0e.js → sync-q9raqnk4.js} +2 -2
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
|
@@ -5725,9 +5725,9 @@ async function runPromptsCommand(input, legacyFlags, legacyProfileOptions) {
|
|
|
5725
5725
|
await promotePrompt(positionals, flags, profileOptions, context);
|
|
5726
5726
|
break;
|
|
5727
5727
|
case "ab":
|
|
5728
|
-
return (await import("./prompts-ab-
|
|
5728
|
+
return (await import("./prompts-ab-98pqf06s.js")).runPromptAb(flags, profileOptions, context);
|
|
5729
5729
|
case "propose":
|
|
5730
|
-
await (await import("./prompts-propose-
|
|
5730
|
+
await (await import("./prompts-propose-md1k1ax8.js")).runPromptPropose(positionals, flags, profileOptions, context);
|
|
5731
5731
|
break;
|
|
5732
5732
|
case "list":
|
|
5733
5733
|
case "show":
|
|
@@ -5830,7 +5830,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
5830
5830
|
const analyzedDefinitions = new Map;
|
|
5831
5831
|
if (flags["no-analyze"] !== "true") {
|
|
5832
5832
|
options.onProgress?.("Analyzing prompt sources before sync.");
|
|
5833
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
5833
|
+
const { analyzeHarnessPrompts } = await import("./harness-8rbsmg8y.js");
|
|
5834
5834
|
const result = await analyzeHarnessPrompts({
|
|
5835
5835
|
rootDir: process.cwd(),
|
|
5836
5836
|
existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
|
|
@@ -5858,7 +5858,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
5858
5858
|
const mergedSources = mergePromptSources(manifest.sources, extraSources);
|
|
5859
5859
|
const manifestUpdate = stableJson(mergedSources) === stableJson(mergePromptSources(manifest.sources, [])) ? undefined : $stringify({ version: 2, prompt_paths: manifest.promptPaths, sources: mergedSources });
|
|
5860
5860
|
const prompts = await discoverPrompts(extraSources);
|
|
5861
|
-
const { checkPromptAttribution } = await import("./prompt-attribution-
|
|
5861
|
+
const { checkPromptAttribution } = await import("./prompt-attribution-gypvn8z9.js");
|
|
5862
5862
|
const attribution = checkPromptAttribution(process.cwd(), prompts.map((prompt) => prompt.key));
|
|
5863
5863
|
const brokenAttribution = attribution.references.filter((reference) => reference.status === "missing");
|
|
5864
5864
|
if (brokenAttribution.length) {
|
|
@@ -6164,7 +6164,7 @@ async function migratePromptManifest(options = {}) {
|
|
|
6164
6164
|
let addedSources = [];
|
|
6165
6165
|
let pendingSources = [];
|
|
6166
6166
|
if (options.discover) {
|
|
6167
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
6167
|
+
const { analyzeHarnessPrompts } = await import("./harness-8rbsmg8y.js");
|
|
6168
6168
|
const result = await analyzeHarnessPrompts({
|
|
6169
6169
|
rootDir: root,
|
|
6170
6170
|
existing: manifest.sources,
|
package/dist/cli.js
CHANGED
|
@@ -91,6 +91,7 @@ import {
|
|
|
91
91
|
createCliOutput,
|
|
92
92
|
embeddedTenantIdFromApiKey,
|
|
93
93
|
errorToAgentError,
|
|
94
|
+
getActiveProfile,
|
|
94
95
|
getApiRequestCount,
|
|
95
96
|
getModaDir,
|
|
96
97
|
isPlatformApiKey,
|
|
@@ -128,7 +129,7 @@ import {
|
|
|
128
129
|
} from "./cli-0v6na3yp.js";
|
|
129
130
|
|
|
130
131
|
// src/cli.ts
|
|
131
|
-
import { randomUUID as
|
|
132
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
132
133
|
import { z } from "zod";
|
|
133
134
|
|
|
134
135
|
// src/replays.ts
|
|
@@ -387,10 +388,223 @@ function spawnDetachedNode(script, options = {}, spawnImpl = spawn) {
|
|
|
387
388
|
}
|
|
388
389
|
|
|
389
390
|
// src/telemetry.ts
|
|
390
|
-
import { randomUUID } from "node:crypto";
|
|
391
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
392
|
+
|
|
393
|
+
// src/telemetry-spool.ts
|
|
394
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
395
|
+
import {
|
|
396
|
+
closeSync,
|
|
397
|
+
constants as fsConstants,
|
|
398
|
+
fchmodSync,
|
|
399
|
+
mkdirSync,
|
|
400
|
+
openSync,
|
|
401
|
+
readFileSync,
|
|
402
|
+
renameSync,
|
|
403
|
+
rmSync,
|
|
404
|
+
statSync,
|
|
405
|
+
unlinkSync,
|
|
406
|
+
writeSync
|
|
407
|
+
} from "node:fs";
|
|
408
|
+
import { join } from "node:path";
|
|
409
|
+
var SPOOL_MAX_BYTES = 256 * 1024;
|
|
410
|
+
var FLUSH_MIN_EVENTS = 20;
|
|
411
|
+
var FLUSH_MAX_AGE_MS = 30000;
|
|
412
|
+
var SPOOL_MAX_EVENT_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
413
|
+
var FLUSH_LOCK_STALE_MS = 30000;
|
|
414
|
+
var MAX_BATCH_EVENTS = 50;
|
|
415
|
+
var SPOOL_LOCK_STALE_MS = 2000;
|
|
416
|
+
var SPOOL_LOCK_WAIT_MS = 200;
|
|
417
|
+
var SPOOL_FILE = "usage-spool.jsonl";
|
|
418
|
+
var LOCK_FILE = "flush.lock";
|
|
419
|
+
var SPOOL_LOCK_FILE = "spool.lock";
|
|
420
|
+
var O_NOFOLLOW = fsConstants.O_NOFOLLOW ?? 0;
|
|
421
|
+
function telemetrySpoolDir() {
|
|
422
|
+
return join(getModaDir(), "telemetry");
|
|
423
|
+
}
|
|
424
|
+
function keyFingerprint(apiKey) {
|
|
425
|
+
return createHash("sha256").update(`moda-cli-usage-spool\x00${apiKey}`).digest("hex").slice(0, 16);
|
|
426
|
+
}
|
|
427
|
+
function ensureDir(dir) {
|
|
428
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
429
|
+
}
|
|
430
|
+
function appendLines(path, text) {
|
|
431
|
+
const fd = openSync(path, fsConstants.O_WRONLY | fsConstants.O_APPEND | fsConstants.O_CREAT | O_NOFOLLOW, 384);
|
|
432
|
+
try {
|
|
433
|
+
try {
|
|
434
|
+
fchmodSync(fd, 384);
|
|
435
|
+
} catch {}
|
|
436
|
+
writeSync(fd, text);
|
|
437
|
+
} finally {
|
|
438
|
+
closeSync(fd);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function sleepSync(ms) {
|
|
442
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
443
|
+
}
|
|
444
|
+
function createLockFile(path, staleMs, now) {
|
|
445
|
+
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
446
|
+
try {
|
|
447
|
+
const fd = openSync(path, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL | O_NOFOLLOW, 384);
|
|
448
|
+
try {
|
|
449
|
+
writeSync(fd, String(process.pid));
|
|
450
|
+
} finally {
|
|
451
|
+
closeSync(fd);
|
|
452
|
+
}
|
|
453
|
+
return true;
|
|
454
|
+
} catch (error) {
|
|
455
|
+
if (error.code !== "EEXIST")
|
|
456
|
+
return false;
|
|
457
|
+
try {
|
|
458
|
+
if (now - statSync(path).mtimeMs < staleMs)
|
|
459
|
+
return false;
|
|
460
|
+
unlinkSync(path);
|
|
461
|
+
} catch {}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
function withSpoolLock(dir, fn) {
|
|
467
|
+
const path = join(dir, SPOOL_LOCK_FILE);
|
|
468
|
+
const deadline = Date.now() + SPOOL_LOCK_WAIT_MS;
|
|
469
|
+
while (!createLockFile(path, SPOOL_LOCK_STALE_MS, Date.now())) {
|
|
470
|
+
if (Date.now() >= deadline)
|
|
471
|
+
throw new Error("telemetry spool is locked");
|
|
472
|
+
sleepSync(5);
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
return fn();
|
|
476
|
+
} finally {
|
|
477
|
+
try {
|
|
478
|
+
unlinkSync(path);
|
|
479
|
+
} catch {}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function fileSize(path) {
|
|
483
|
+
try {
|
|
484
|
+
return statSync(path).size;
|
|
485
|
+
} catch {
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function parseEntries(text) {
|
|
490
|
+
const entries = [];
|
|
491
|
+
for (const line of text.split(`
|
|
492
|
+
`)) {
|
|
493
|
+
if (!line)
|
|
494
|
+
continue;
|
|
495
|
+
try {
|
|
496
|
+
const entry = JSON.parse(line);
|
|
497
|
+
if (entry && entry.v === 1 && typeof entry.url === "string" && typeof entry.profile === "string" && typeof entry.key === "string" && typeof entry.t === "number" && entry.event && typeof entry.event === "object") {
|
|
498
|
+
entries.push(entry);
|
|
499
|
+
}
|
|
500
|
+
} catch {}
|
|
501
|
+
}
|
|
502
|
+
return entries;
|
|
503
|
+
}
|
|
504
|
+
function sameGroup(a, b) {
|
|
505
|
+
return a.url === b.url && a.profile === b.profile && a.key === b.key;
|
|
506
|
+
}
|
|
507
|
+
function appendSpoolEntry(entry, dir = telemetrySpoolDir()) {
|
|
508
|
+
ensureDir(dir);
|
|
509
|
+
const path = join(dir, SPOOL_FILE);
|
|
510
|
+
const line = `${JSON.stringify(entry)}
|
|
511
|
+
`;
|
|
512
|
+
return withSpoolLock(dir, () => {
|
|
513
|
+
if (fileSize(path) + Buffer.byteLength(line) > SPOOL_MAX_BYTES)
|
|
514
|
+
return false;
|
|
515
|
+
appendLines(path, line);
|
|
516
|
+
return true;
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
function readSpool(dir = telemetrySpoolDir()) {
|
|
520
|
+
try {
|
|
521
|
+
return parseEntries(readFileSync(join(dir, SPOOL_FILE), "utf8"));
|
|
522
|
+
} catch {
|
|
523
|
+
return [];
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
function discardSpool(dir = telemetrySpoolDir()) {
|
|
527
|
+
try {
|
|
528
|
+
rmSync(join(dir, SPOOL_FILE), { force: true });
|
|
529
|
+
} catch {}
|
|
530
|
+
}
|
|
531
|
+
function flushDue(entries, group, now) {
|
|
532
|
+
let count = 0;
|
|
533
|
+
for (const entry of entries) {
|
|
534
|
+
if (!sameGroup(entry, group))
|
|
535
|
+
continue;
|
|
536
|
+
count += 1;
|
|
537
|
+
if (count >= FLUSH_MIN_EVENTS || now - entry.t >= FLUSH_MAX_AGE_MS)
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
function acquireFlushLock(dir = telemetrySpoolDir(), now = Date.now()) {
|
|
543
|
+
ensureDir(dir);
|
|
544
|
+
const path = join(dir, LOCK_FILE);
|
|
545
|
+
return createLockFile(path, FLUSH_LOCK_STALE_MS, now) ? path : undefined;
|
|
546
|
+
}
|
|
547
|
+
function releaseFlushLock(path) {
|
|
548
|
+
if (!path)
|
|
549
|
+
return;
|
|
550
|
+
try {
|
|
551
|
+
unlinkSync(path);
|
|
552
|
+
} catch {}
|
|
553
|
+
}
|
|
554
|
+
function claimSpoolGroup(group, dir = telemetrySpoolDir(), now = Date.now(), limit = Number.POSITIVE_INFINITY) {
|
|
555
|
+
try {
|
|
556
|
+
return withSpoolLock(dir, () => claimLocked(group, dir, now, limit));
|
|
557
|
+
} catch {
|
|
558
|
+
return [];
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function claimLocked(group, dir, now, limit) {
|
|
562
|
+
const path = join(dir, SPOOL_FILE);
|
|
563
|
+
const claim = join(dir, `${SPOOL_FILE}.${process.pid}.${randomUUID()}.claim`);
|
|
564
|
+
try {
|
|
565
|
+
renameSync(path, claim);
|
|
566
|
+
} catch {
|
|
567
|
+
return [];
|
|
568
|
+
}
|
|
569
|
+
let entries = [];
|
|
570
|
+
try {
|
|
571
|
+
entries = parseEntries(readFileSync(claim, "utf8"));
|
|
572
|
+
} catch {} finally {
|
|
573
|
+
rmSync(claim, { force: true });
|
|
574
|
+
}
|
|
575
|
+
const mine = [];
|
|
576
|
+
const others = [];
|
|
577
|
+
for (const entry of entries) {
|
|
578
|
+
const age = now - entry.t;
|
|
579
|
+
if (age > SPOOL_MAX_EVENT_AGE_MS || age < -FLUSH_LOCK_STALE_MS)
|
|
580
|
+
continue;
|
|
581
|
+
(sameGroup(entry, group) && mine.length < limit ? mine : others).push(entry);
|
|
582
|
+
}
|
|
583
|
+
if (others.length > 0) {
|
|
584
|
+
try {
|
|
585
|
+
const text = others.map((entry) => `${JSON.stringify(entry)}
|
|
586
|
+
`).join("");
|
|
587
|
+
if (fileSize(path) + Buffer.byteLength(text) <= SPOOL_MAX_BYTES)
|
|
588
|
+
appendLines(path, text);
|
|
589
|
+
} catch {}
|
|
590
|
+
}
|
|
591
|
+
return mine;
|
|
592
|
+
}
|
|
593
|
+
function batchBodies(entries, now = Date.now()) {
|
|
594
|
+
const bodies = [];
|
|
595
|
+
for (let start = 0;start < entries.length; start += MAX_BATCH_EVENTS) {
|
|
596
|
+
const events = entries.slice(start, start + MAX_BATCH_EVENTS).map((entry) => ({ ...entry.event, age_ms: Math.min(SPOOL_MAX_EVENT_AGE_MS, Math.max(0, Math.round(now - entry.t))) }));
|
|
597
|
+
bodies.push(JSON.stringify(events));
|
|
598
|
+
}
|
|
599
|
+
return bodies;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/telemetry.ts
|
|
391
603
|
var INLINE_TELEMETRY_TIMEOUT_MS = 500;
|
|
392
604
|
var DETACHED_TELEMETRY_TIMEOUT_MS = 5000;
|
|
393
|
-
var
|
|
605
|
+
var DETACHED_TELEMETRY_HARD_STOP_MS = 20000;
|
|
606
|
+
var MAX_FLUSH_BATCHES = Math.floor(DETACHED_TELEMETRY_HARD_STOP_MS / (2 * DETACHED_TELEMETRY_TIMEOUT_MS));
|
|
607
|
+
var INVOCATION_ID = randomUUID2();
|
|
394
608
|
var TELEMETRY_FLAG = "no-telemetry";
|
|
395
609
|
var TELEMETRY_TRANSPORT_ENV = "MODA_CLI_TELEMETRY_TRANSPORT";
|
|
396
610
|
var MAX_TELEMETRY_DURATION_MS = 86400000;
|
|
@@ -560,48 +774,103 @@ function safeCode(value) {
|
|
|
560
774
|
var TELEMETRY_SENDER_SCRIPT = [
|
|
561
775
|
"try {",
|
|
562
776
|
" let raw = '';",
|
|
563
|
-
|
|
564
|
-
" const
|
|
777
|
+
" let lock;",
|
|
778
|
+
" const release = () => { if (typeof lock === 'string') { try { require('node:fs').unlinkSync(lock); } catch {} lock = undefined; } };",
|
|
779
|
+
` const quit = setTimeout(() => { release(); process.exit(0); }, ${DETACHED_TELEMETRY_HARD_STOP_MS});`,
|
|
780
|
+
" const done = () => { release(); clearTimeout(quit); };",
|
|
781
|
+
" const post = (r, body) => new Promise((resolve) => {",
|
|
782
|
+
" try {",
|
|
783
|
+
" const u = new URL(r.url);",
|
|
784
|
+
" const lib = require(u.protocol === 'https:' ? 'node:https' : 'node:http');",
|
|
785
|
+
" const headers = Object.assign({}, r.headers, { 'Content-Length': Buffer.byteLength(body) });",
|
|
786
|
+
` const req = lib.request(u, { method: 'POST', headers, agent: false, timeout: ${DETACHED_TELEMETRY_TIMEOUT_MS} }, (res) => {`,
|
|
787
|
+
" res.on('error', () => resolve(0));",
|
|
788
|
+
" res.on('end', () => resolve(res.statusCode || 0));",
|
|
789
|
+
" res.resume();",
|
|
790
|
+
" });",
|
|
791
|
+
" req.on('timeout', () => req.destroy());",
|
|
792
|
+
" req.on('error', () => resolve(0));",
|
|
793
|
+
" req.end(body);",
|
|
794
|
+
" } catch { resolve(0); }",
|
|
795
|
+
" });",
|
|
796
|
+
" const run = async (requests) => {",
|
|
797
|
+
" for (const r of requests) {",
|
|
798
|
+
" if (!r || typeof r.url !== 'string' || typeof r.body !== 'string' || !r.headers || typeof r.headers !== 'object') continue;",
|
|
799
|
+
" const status = await post(r, r.body);",
|
|
800
|
+
" if (status !== 400 || r.body[0] !== '[') continue;",
|
|
801
|
+
" let events = [];",
|
|
802
|
+
" try { events = JSON.parse(r.body); } catch {}",
|
|
803
|
+
" await Promise.all((Array.isArray(events) ? events : []).map((event) => post(r, JSON.stringify(event))));",
|
|
804
|
+
" }",
|
|
805
|
+
" };",
|
|
565
806
|
" process.stdin.setEncoding('utf8');",
|
|
566
807
|
" process.stdin.on('error', () => {});",
|
|
567
808
|
" process.stdin.on('data', (chunk) => { raw += chunk; });",
|
|
568
809
|
" process.stdin.on('end', () => {",
|
|
569
|
-
"
|
|
570
|
-
"
|
|
571
|
-
"
|
|
572
|
-
"
|
|
573
|
-
"
|
|
574
|
-
|
|
575
|
-
" fetch(r.url, { method: 'POST', headers: r.headers, body: r.body, signal: c.signal })",
|
|
576
|
-
" .then((res) => (res.body && res.body.cancel ? res.body.cancel() : undefined))",
|
|
577
|
-
" .catch(() => {})",
|
|
578
|
-
" .finally(() => { clearTimeout(t); done(); });",
|
|
579
|
-
" } catch { done(); }",
|
|
810
|
+
" let job = null;",
|
|
811
|
+
" try { job = raw ? JSON.parse(raw) : null; } catch {}",
|
|
812
|
+
" raw = '';",
|
|
813
|
+
" if (job && typeof job.lock === 'string') lock = job.lock;",
|
|
814
|
+
" const requests = job && Array.isArray(job.requests) ? job.requests : [];",
|
|
815
|
+
" run(requests).catch(() => {}).finally(done);",
|
|
580
816
|
" });",
|
|
581
817
|
"} catch {}"
|
|
582
818
|
].join(`
|
|
583
819
|
`);
|
|
584
|
-
function spawnDetachedTelemetrySender(
|
|
585
|
-
return spawnDetachedNode(TELEMETRY_SENDER_SCRIPT, { stdin: JSON.stringify(
|
|
820
|
+
function spawnDetachedTelemetrySender(job, spawnImpl = spawn2) {
|
|
821
|
+
return spawnDetachedNode(TELEMETRY_SENDER_SCRIPT, { stdin: JSON.stringify(job), dropEnv: ["MODA_API_KEY"] }, spawnImpl);
|
|
822
|
+
}
|
|
823
|
+
async function sendTelemetryJobInline(job) {
|
|
824
|
+
try {
|
|
825
|
+
for (const pending of job.requests)
|
|
826
|
+
await sendInline(pending);
|
|
827
|
+
} finally {
|
|
828
|
+
releaseFlushLock(job.lock);
|
|
829
|
+
}
|
|
586
830
|
}
|
|
587
831
|
async function sendInline(request) {
|
|
832
|
+
const status = await postInline(request);
|
|
833
|
+
if (status !== 400 || !request.body.startsWith("["))
|
|
834
|
+
return;
|
|
835
|
+
let events = [];
|
|
836
|
+
try {
|
|
837
|
+
events = JSON.parse(request.body);
|
|
838
|
+
} catch {}
|
|
839
|
+
if (!Array.isArray(events))
|
|
840
|
+
return;
|
|
841
|
+
await Promise.all(events.map((event) => postInline({ ...request, body: JSON.stringify(event) })));
|
|
842
|
+
}
|
|
843
|
+
async function postInline(request) {
|
|
588
844
|
const controller = new AbortController;
|
|
589
845
|
const timeout = setTimeout(() => controller.abort(), INLINE_TELEMETRY_TIMEOUT_MS);
|
|
590
846
|
if (typeof timeout.unref === "function") {
|
|
591
847
|
timeout.unref();
|
|
592
848
|
}
|
|
593
849
|
try {
|
|
594
|
-
await fetch(request.url, {
|
|
850
|
+
const response = await fetch(request.url, {
|
|
595
851
|
method: "POST",
|
|
596
852
|
headers: request.headers,
|
|
597
853
|
body: request.body,
|
|
598
854
|
signal: controller.signal
|
|
599
855
|
});
|
|
600
|
-
|
|
856
|
+
return response.status;
|
|
857
|
+
} catch {
|
|
858
|
+
return 0;
|
|
859
|
+
} finally {
|
|
601
860
|
clearTimeout(timeout);
|
|
602
861
|
}
|
|
603
862
|
}
|
|
604
|
-
function
|
|
863
|
+
function usageRequest(baseUrl, apiKey, body) {
|
|
864
|
+
return {
|
|
865
|
+
url: `${baseUrl}/api/v1/data/cli-usage`,
|
|
866
|
+
headers: {
|
|
867
|
+
...apiKeyHeaders(apiKey),
|
|
868
|
+
"Content-Type": "application/json"
|
|
869
|
+
},
|
|
870
|
+
body
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
function buildCliUsageEvent(input) {
|
|
605
874
|
const baseUrl = resolveModaBaseUrlStrict(input.profile ? { profile: input.profile } : {});
|
|
606
875
|
if (!baseUrl)
|
|
607
876
|
return;
|
|
@@ -613,12 +882,8 @@ function buildCliUsageRequest(input) {
|
|
|
613
882
|
delete adoption[key];
|
|
614
883
|
}
|
|
615
884
|
return {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
...apiKeyHeaders(input.apiKey),
|
|
619
|
-
"Content-Type": "application/json"
|
|
620
|
-
},
|
|
621
|
-
body: JSON.stringify({
|
|
885
|
+
baseUrl,
|
|
886
|
+
event: {
|
|
622
887
|
invocation_id: INVOCATION_ID,
|
|
623
888
|
command: safeCode(input.command.slice(0, 64)) ?? "unknown",
|
|
624
889
|
status: input.status,
|
|
@@ -637,27 +902,79 @@ function buildCliUsageRequest(input) {
|
|
|
637
902
|
...((alias) => alias ? { legacy_alias: alias } : {})(safeCode(sanitizeReasonCode(input.legacyAlias?.replace(/ /g, ":"), 64)))
|
|
638
903
|
},
|
|
639
904
|
...adoption
|
|
640
|
-
}
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function telemetryProfileName(profile) {
|
|
909
|
+
try {
|
|
910
|
+
return getActiveProfile(profile ? { profile } : {}).name;
|
|
911
|
+
} catch {
|
|
912
|
+
return "";
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
function queueCliUsageEvent(request, group, event, now) {
|
|
916
|
+
const dir = telemetrySpoolDir();
|
|
917
|
+
const entry = { v: 1, ...group, t: now, event };
|
|
918
|
+
let unspooled = [];
|
|
919
|
+
try {
|
|
920
|
+
if (!appendSpoolEntry(entry, dir))
|
|
921
|
+
unspooled = [entry];
|
|
922
|
+
} catch {
|
|
923
|
+
return { requests: [request] };
|
|
924
|
+
}
|
|
925
|
+
const due = unspooled.length > 0 || envOptOutSet(process.env.CI) || flushDue(readSpool(dir), group, now);
|
|
926
|
+
if (!due)
|
|
927
|
+
return;
|
|
928
|
+
const lock = acquireFlushLock(dir, now);
|
|
929
|
+
if (!lock)
|
|
930
|
+
return unspooled.length > 0 ? { requests: [request] } : undefined;
|
|
931
|
+
const limit = MAX_FLUSH_BATCHES * MAX_BATCH_EVENTS - unspooled.length;
|
|
932
|
+
const entries = [...claimSpoolGroup(group, dir, now, limit), ...unspooled];
|
|
933
|
+
if (entries.length === 0) {
|
|
934
|
+
releaseFlushLock(lock);
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
return {
|
|
938
|
+
requests: batchBodies(entries, now).map((body) => ({ url: request.url, headers: request.headers, body })),
|
|
939
|
+
lock
|
|
641
940
|
};
|
|
642
941
|
}
|
|
942
|
+
function discardSpoolOnEnvOptOut() {
|
|
943
|
+
if (!isTelemetryDisabled({}))
|
|
944
|
+
return false;
|
|
945
|
+
discardSpool();
|
|
946
|
+
return true;
|
|
947
|
+
}
|
|
643
948
|
async function sendCliUsageTelemetry(input) {
|
|
644
949
|
try {
|
|
950
|
+
if (discardSpoolOnEnvOptOut())
|
|
951
|
+
return;
|
|
645
952
|
if (!input.apiKey || isTelemetryDisabled(input.flags)) {
|
|
646
953
|
return;
|
|
647
954
|
}
|
|
648
|
-
const
|
|
649
|
-
if (!
|
|
955
|
+
const built = buildCliUsageEvent(input);
|
|
956
|
+
if (!built)
|
|
650
957
|
return;
|
|
651
|
-
|
|
958
|
+
const request = usageRequest(built.baseUrl, input.apiKey, JSON.stringify(built.event));
|
|
959
|
+
if (process.env[TELEMETRY_TRANSPORT_ENV] === "inline") {
|
|
960
|
+
await sendInline(request);
|
|
652
961
|
return;
|
|
653
962
|
}
|
|
654
|
-
|
|
963
|
+
const group = {
|
|
964
|
+
url: built.baseUrl,
|
|
965
|
+
profile: telemetryProfileName(input.profile),
|
|
966
|
+
key: keyFingerprint(input.apiKey)
|
|
967
|
+
};
|
|
968
|
+
const job = queueCliUsageEvent(request, group, built.event, Date.now());
|
|
969
|
+
if (!job || spawnDetachedTelemetrySender(job))
|
|
970
|
+
return;
|
|
971
|
+
await sendTelemetryJobInline(job);
|
|
655
972
|
} catch {}
|
|
656
973
|
}
|
|
657
974
|
|
|
658
975
|
// src/update-check.ts
|
|
659
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
660
|
-
import { join } from "node:path";
|
|
976
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
977
|
+
import { join as join2 } from "node:path";
|
|
661
978
|
var UPDATE_CHECK_FLAG = "no-update-check";
|
|
662
979
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
663
980
|
var REGISTRY_TIMEOUT_MS = 1500;
|
|
@@ -670,11 +987,11 @@ function isUpdateCheckDisabled(flags, env = process.env) {
|
|
|
670
987
|
return optOutFlagSet(flags, UPDATE_CHECK_FLAG) || envSwitchedOff(env.MODA_CLI_UPDATE_CHECK) || envOptOutSet(env.DO_NOT_TRACK) || envOptOutSet(env.CI);
|
|
671
988
|
}
|
|
672
989
|
function cachePath(options = {}) {
|
|
673
|
-
return
|
|
990
|
+
return join2(getModaDir(options), "update-check.json");
|
|
674
991
|
}
|
|
675
992
|
function readCache(options = {}) {
|
|
676
993
|
try {
|
|
677
|
-
const parsed = JSON.parse(
|
|
994
|
+
const parsed = JSON.parse(readFileSync2(cachePath(options), "utf8"));
|
|
678
995
|
if (parsed && typeof parsed === "object" && typeof parsed.checked_at === "number" && typeof parsed.latest === "string") {
|
|
679
996
|
return parsed;
|
|
680
997
|
}
|
|
@@ -683,7 +1000,7 @@ function readCache(options = {}) {
|
|
|
683
1000
|
}
|
|
684
1001
|
function writeCache(cache, options = {}) {
|
|
685
1002
|
try {
|
|
686
|
-
|
|
1003
|
+
mkdirSync2(getModaDir(options), { recursive: true });
|
|
687
1004
|
writeFileSync(cachePath(options), `${JSON.stringify(cache, null, 2)}
|
|
688
1005
|
`, "utf8");
|
|
689
1006
|
} catch {}
|
|
@@ -2642,7 +2959,7 @@ function leafManifestFields(leaf, commands) {
|
|
|
2642
2959
|
import { fileURLToPath } from "url";
|
|
2643
2960
|
import { realpathSync } from "fs";
|
|
2644
2961
|
async function runPromptsCommand(...args) {
|
|
2645
|
-
return (await import("./prompts-
|
|
2962
|
+
return (await import("./prompts-3qr24vd6.js")).runPromptsCommand(...args);
|
|
2646
2963
|
}
|
|
2647
2964
|
async function runSkillsCommand(...args) {
|
|
2648
2965
|
return (await import("./skills-j8865009.js")).runSkillsCommand(...args);
|
|
@@ -2654,19 +2971,19 @@ async function runFixesCommand(...args) {
|
|
|
2654
2971
|
return (await import("./fix-w5z02wt4.js")).runFixesCommand(...args);
|
|
2655
2972
|
}
|
|
2656
2973
|
async function runHarnessCommand(...args) {
|
|
2657
|
-
return (await import("./harness-
|
|
2974
|
+
return (await import("./harness-8rbsmg8y.js")).runHarnessCommand(...args);
|
|
2658
2975
|
}
|
|
2659
2976
|
async function runSyncCommand(...args) {
|
|
2660
|
-
return (await import("./sync-
|
|
2977
|
+
return (await import("./sync-q9raqnk4.js")).runSyncCommand(...args);
|
|
2661
2978
|
}
|
|
2662
2979
|
async function runRegistryCommand(...args) {
|
|
2663
|
-
return (await import("./registry-
|
|
2980
|
+
return (await import("./registry-ctnn8e26.js")).runRegistryCommand(...args);
|
|
2664
2981
|
}
|
|
2665
2982
|
async function runDoctorCommand(...args) {
|
|
2666
|
-
return (await import("./doctor-
|
|
2983
|
+
return (await import("./doctor-2hd9rq68.js")).runDoctorCommand(...args);
|
|
2667
2984
|
}
|
|
2668
2985
|
async function runStatusCommand(...args) {
|
|
2669
|
-
return (await import("./doctor-
|
|
2986
|
+
return (await import("./doctor-2hd9rq68.js")).runStatusCommand(...args);
|
|
2670
2987
|
}
|
|
2671
2988
|
async function runAuthCommand(...args) {
|
|
2672
2989
|
return (await import("./profile-commands-h8evz9x0.js")).runAuthCommand(...args);
|
|
@@ -2678,7 +2995,7 @@ async function runProfilesCommand(...args) {
|
|
|
2678
2995
|
return (await import("./profile-commands-h8evz9x0.js")).runProfilesCommand(...args);
|
|
2679
2996
|
}
|
|
2680
2997
|
async function runAgentCommand(...args) {
|
|
2681
|
-
return (await import("./agent-
|
|
2998
|
+
return (await import("./agent-wjkgt137.js")).runAgentCommand(...args);
|
|
2682
2999
|
}
|
|
2683
3000
|
async function runProductionCommand(...args) {
|
|
2684
3001
|
return (await import("./production-intelligence-wvsgjxth.js")).runProductionCommand(...args);
|
|
@@ -5445,7 +5762,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
|
|
|
5445
5762
|
}
|
|
5446
5763
|
const data = await callDataAPI(reviewPath, {
|
|
5447
5764
|
method: "POST",
|
|
5448
|
-
body: JSON.stringify({ ...reviewBody, request_nonce:
|
|
5765
|
+
body: JSON.stringify({ ...reviewBody, request_nonce: randomUUID3() }),
|
|
5449
5766
|
headers: { "Content-Type": "application/json" }
|
|
5450
5767
|
});
|
|
5451
5768
|
context.output.writeData(data);
|
|
@@ -5538,7 +5855,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
|
|
|
5538
5855
|
});
|
|
5539
5856
|
break;
|
|
5540
5857
|
}
|
|
5541
|
-
const sentBody = request.body && request.nonce ? { ...request.body, request_nonce:
|
|
5858
|
+
const sentBody = request.body && request.nonce ? { ...request.body, request_nonce: randomUUID3() } : request.body;
|
|
5542
5859
|
const data = await callDataAPI(request.path, {
|
|
5543
5860
|
method: request.method,
|
|
5544
5861
|
...sentBody ? { body: JSON.stringify(sentBody), headers: { "Content-Type": "application/json" } } : {}
|
|
@@ -5826,7 +6143,7 @@ var commandRegistry = createCommandRegistry([
|
|
|
5826
6143
|
resetApiRequestCountBeforeRun: true,
|
|
5827
6144
|
telemetry: "result-and-error",
|
|
5828
6145
|
handler: async (context) => {
|
|
5829
|
-
const { runInit } = await import("./index-
|
|
6146
|
+
const { runInit } = await import("./index-ecsjv99z.js");
|
|
5830
6147
|
if (context.outputMode === "agent-stream") {
|
|
5831
6148
|
context.output.writeEvent({
|
|
5832
6149
|
event: "started",
|
|
@@ -7100,6 +7417,8 @@ async function dispatchParsedCommandInner(typedParsed, startedAt) {
|
|
|
7100
7417
|
const switchError = normalizeBooleanFlags(flags);
|
|
7101
7418
|
const typedFlags = stripUpdateCheckFlag(stripTelemetryFlag(flags));
|
|
7102
7419
|
const telemetryDisabled = isTelemetryDisabled(flags);
|
|
7420
|
+
if (telemetryDisabled)
|
|
7421
|
+
discardSpoolOnEnvOptOut();
|
|
7103
7422
|
const updateCheckDisabled = isUpdateCheckDisabled(flags);
|
|
7104
7423
|
if (command === "--version" || command === "-V" || flags.version === "true") {
|
|
7105
7424
|
console.log(`moda-cli ${VERSION}`);
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
promptsDiscoveredCheck,
|
|
4
4
|
runDoctorCommand,
|
|
5
5
|
runStatusCommand
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-2eqh3150.js";
|
|
7
7
|
import"./cli-9bgnvth2.js";
|
|
8
|
-
import"./cli-
|
|
8
|
+
import"./cli-6ycf2aj5.js";
|
|
9
9
|
import"./cli-mm48br00.js";
|
|
10
10
|
import"./cli-xq45etg1.js";
|
|
11
11
|
import"./cli-dr6x0zv7.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildDoctorReport
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-2eqh3150.js";
|
|
4
4
|
import {
|
|
5
5
|
selectTenantAndCreateKey
|
|
6
6
|
} from "./cli-9bgk5jeh.js";
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
initPrompts,
|
|
31
31
|
runPromptSync
|
|
32
|
-
} from "./cli-
|
|
32
|
+
} from "./cli-6ycf2aj5.js";
|
|
33
33
|
import"./cli-mm48br00.js";
|
|
34
34
|
import {
|
|
35
35
|
codingAgentDisplayName,
|
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
runCodingAgent,
|
|
44
44
|
runHarnessCommand,
|
|
45
45
|
startRemoteAnalyze
|
|
46
|
-
} from "./cli-
|
|
46
|
+
} from "./cli-37r94bmk.js";
|
|
47
47
|
import {
|
|
48
48
|
canonicalText,
|
|
49
49
|
renderInitBanner,
|