@mutmutco/cli 2.28.0 → 2.30.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.
- package/README.md +4 -2
- package/dist/index.cjs +16 -3
- package/dist/main.cjs +6961 -5636
- package/dist/saga.cjs +148 -76
- package/package.json +2 -2
package/dist/saga.cjs
CHANGED
|
@@ -3430,6 +3430,26 @@ function clientVersionHeaders() {
|
|
|
3430
3430
|
|
|
3431
3431
|
// src/saga-commands.ts
|
|
3432
3432
|
var import_node_crypto3 = require("node:crypto");
|
|
3433
|
+
var import_promises2 = require("node:fs/promises");
|
|
3434
|
+
|
|
3435
|
+
// src/issue-body.ts
|
|
3436
|
+
async function resolveTextArg(input, deps, labels) {
|
|
3437
|
+
const hasValue = input.value !== void 0;
|
|
3438
|
+
const hasFile = input.file !== void 0;
|
|
3439
|
+
if (hasValue && hasFile) {
|
|
3440
|
+
throw new Error(`pass only one of ${labels.value} or ${labels.file}`);
|
|
3441
|
+
}
|
|
3442
|
+
if (!hasValue && !hasFile) {
|
|
3443
|
+
throw new Error(`pass ${labels.value} or ${labels.file}`);
|
|
3444
|
+
}
|
|
3445
|
+
if (hasValue) return input.value ?? "";
|
|
3446
|
+
const source = input.file ?? "";
|
|
3447
|
+
const text = source === "-" ? await deps.readStdin() : await deps.readFile(source, "utf8");
|
|
3448
|
+
if (text.trim().length === 0) {
|
|
3449
|
+
throw new Error(`${labels.file} produced an empty ${labels.noun}`);
|
|
3450
|
+
}
|
|
3451
|
+
return text;
|
|
3452
|
+
}
|
|
3433
3453
|
|
|
3434
3454
|
// src/saga-capture.ts
|
|
3435
3455
|
function parseHookInput(stdin) {
|
|
@@ -3566,6 +3586,7 @@ async function runHeadEngine(prompt, timeoutMs = HEAD_ENGINE_TIMEOUT_MS) {
|
|
|
3566
3586
|
|
|
3567
3587
|
// src/saga-health.ts
|
|
3568
3588
|
var MEMORY_STALE_DAYS = 14;
|
|
3589
|
+
var SESSION_START_LIVENESS = { attempts: 1, timeoutMs: 3e3 };
|
|
3569
3590
|
function buildHealth(i) {
|
|
3570
3591
|
const problems = [];
|
|
3571
3592
|
if (!i.sagaApiUrl) problems.push("Hub API URL not configured");
|
|
@@ -3591,6 +3612,7 @@ function buildHealth(i) {
|
|
|
3591
3612
|
authorized: i.authorized,
|
|
3592
3613
|
sagaApiUrl: i.sagaApiUrl,
|
|
3593
3614
|
pendingNotes: i.pendingNotes ?? 0,
|
|
3615
|
+
honchoPending: i.honchoPending ?? 0,
|
|
3594
3616
|
key: i.key,
|
|
3595
3617
|
source: i.source,
|
|
3596
3618
|
problems,
|
|
@@ -3607,73 +3629,14 @@ function healthBanner(report) {
|
|
|
3607
3629
|
if (report.warnings.length) return `saga health: NOTE - ${report.warnings.join("; ")}`;
|
|
3608
3630
|
return null;
|
|
3609
3631
|
}
|
|
3610
|
-
function
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
|
|
3619
|
-
const sleep = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
3620
|
-
let lastErr;
|
|
3621
|
-
for (let i = 0; i < attempts; i++) {
|
|
3622
|
-
const isLast = i === attempts - 1;
|
|
3623
|
-
const attemptInit = opts.timeoutMs ? { ...init, signal: AbortSignal.timeout(opts.timeoutMs) } : init;
|
|
3624
|
-
try {
|
|
3625
|
-
const res = await fetchImpl(url, attemptInit);
|
|
3626
|
-
if (!isLast && retryOn(res)) {
|
|
3627
|
-
await sleep(baseDelayMs * 2 ** i);
|
|
3628
|
-
continue;
|
|
3629
|
-
}
|
|
3630
|
-
return res;
|
|
3631
|
-
} catch (e) {
|
|
3632
|
-
lastErr = e;
|
|
3633
|
-
if (isLast) throw e;
|
|
3634
|
-
await sleep(baseDelayMs * 2 ** i);
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3637
|
-
throw lastErr;
|
|
3638
|
-
}
|
|
3639
|
-
|
|
3640
|
-
// src/saga-note.ts
|
|
3641
|
-
var AGENT_SURFACE_TOKENS = ["claude", "codex", "cursor", "gemini"];
|
|
3642
|
-
var ROUTE_LEVEL_403 = "saga API route-level 403 from HubSessionAuthorizer/session policy";
|
|
3643
|
-
function agentSurface(env = process.env) {
|
|
3644
|
-
const surface = env.MMI_AGENT_SURFACE?.trim() || (env.CODEX_THREAD_ID?.trim() && !env.CLAUDE_SESSION_ID?.trim() ? "codex" : "claude");
|
|
3645
|
-
if (AGENT_SURFACE_TOKENS.includes(surface)) return surface;
|
|
3646
|
-
throw new Error(`MMI_AGENT_SURFACE must be one of: ${AGENT_SURFACE_TOKENS.join(", ")}`);
|
|
3647
|
-
}
|
|
3648
|
-
function buildNoteCapture(summary, o, id, evidence) {
|
|
3649
|
-
const queueOp = o.queueAdd ? { op: "add", text: o.queueAdd } : o.queueDone != null ? { op: "done", index: Number(o.queueDone) } : void 0;
|
|
3650
|
-
const state = o.diagnostic ? "diagnostic" : o.verified ? "verified" : "asserted";
|
|
3651
|
-
const source = o.diagnostic ? "probe" : "note";
|
|
3652
|
-
const ev = {};
|
|
3653
|
-
if (evidence.sha) ev.sha = evidence.sha;
|
|
3654
|
-
if (evidence.branch) ev.branch = evidence.branch;
|
|
3655
|
-
if (evidence.pr) ev.pr = evidence.pr;
|
|
3656
|
-
if (evidence.file) ev.file = evidence.file;
|
|
3657
|
-
const anchor = o.anchor ? { intent: o.anchor, setAt: (/* @__PURE__ */ new Date()).toISOString() } : void 0;
|
|
3658
|
-
return {
|
|
3659
|
-
event: "note",
|
|
3660
|
-
id,
|
|
3661
|
-
summary,
|
|
3662
|
-
next: o.next,
|
|
3663
|
-
decision: o.decision,
|
|
3664
|
-
queueOp,
|
|
3665
|
-
state,
|
|
3666
|
-
source,
|
|
3667
|
-
evidence: Object.keys(ev).length ? ev : void 0,
|
|
3668
|
-
surface: agentSurface(),
|
|
3669
|
-
supersedes: o.supersedes,
|
|
3670
|
-
anchor,
|
|
3671
|
-
anchorForce: o.anchorForce || void 0
|
|
3672
|
-
};
|
|
3673
|
-
}
|
|
3674
|
-
function formatCaptureFailure(status, message) {
|
|
3675
|
-
if (status === 403 && message === "Forbidden") return `saga: ${ROUTE_LEVEL_403} (HTTP 403)`;
|
|
3676
|
-
return `saga: HTTP ${status}`;
|
|
3632
|
+
function memorySyncBanner(report) {
|
|
3633
|
+
const saga = report.pendingNotes;
|
|
3634
|
+
const honcho = report.honchoPending;
|
|
3635
|
+
if (saga <= 0 && honcho <= 0) return null;
|
|
3636
|
+
const parts = [];
|
|
3637
|
+
if (saga > 0) parts.push(`${saga} saga`);
|
|
3638
|
+
if (honcho > 0) parts.push(`${honcho} honcho`);
|
|
3639
|
+
return `MEMORY SYNC \u2014 ${parts.join(" + ")} write(s) queued locally \u2014 run \`mmi-cli saga flush\` / \`honcho flush\` (this device only).`;
|
|
3677
3640
|
}
|
|
3678
3641
|
|
|
3679
3642
|
// src/saga-pending.ts
|
|
@@ -3852,6 +3815,81 @@ async function flushPending(post, dir = ".mmi") {
|
|
|
3852
3815
|
return { flushed, dropped, remaining: readPending(dir).length };
|
|
3853
3816
|
}
|
|
3854
3817
|
|
|
3818
|
+
// src/honcho-pending.ts
|
|
3819
|
+
var HONCHO_QUEUE_DIR = ".mmi/honcho";
|
|
3820
|
+
function readHonchoPending(dir = HONCHO_QUEUE_DIR) {
|
|
3821
|
+
return readPending(dir);
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
// src/fetch-retry.ts
|
|
3825
|
+
async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
|
|
3826
|
+
const attempts = opts.attempts ?? 3;
|
|
3827
|
+
const baseDelayMs = opts.baseDelayMs ?? 250;
|
|
3828
|
+
const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
|
|
3829
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
3830
|
+
let lastErr;
|
|
3831
|
+
for (let i = 0; i < attempts; i++) {
|
|
3832
|
+
const isLast = i === attempts - 1;
|
|
3833
|
+
const attemptInit = opts.timeoutMs ? { ...init, signal: AbortSignal.timeout(opts.timeoutMs) } : init;
|
|
3834
|
+
try {
|
|
3835
|
+
const res = await fetchImpl(url, attemptInit);
|
|
3836
|
+
if (!isLast && retryOn(res)) {
|
|
3837
|
+
await sleep(baseDelayMs * 2 ** i);
|
|
3838
|
+
continue;
|
|
3839
|
+
}
|
|
3840
|
+
return res;
|
|
3841
|
+
} catch (e) {
|
|
3842
|
+
lastErr = e;
|
|
3843
|
+
if (isLast) throw e;
|
|
3844
|
+
await sleep(baseDelayMs * 2 ** i);
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
throw lastErr;
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3850
|
+
// src/saga-note.ts
|
|
3851
|
+
var AGENT_SURFACE_TOKENS = ["claude", "codex", "cursor", "gemini"];
|
|
3852
|
+
var ROUTE_LEVEL_403 = "saga API route-level 403 from HubSessionAuthorizer/session policy";
|
|
3853
|
+
function agentSurface(env = process.env) {
|
|
3854
|
+
const surface = env.MMI_AGENT_SURFACE?.trim() || (env.CODEX_THREAD_ID?.trim() && !env.CLAUDE_SESSION_ID?.trim() ? "codex" : "claude");
|
|
3855
|
+
if (AGENT_SURFACE_TOKENS.includes(surface)) return surface;
|
|
3856
|
+
throw new Error(`MMI_AGENT_SURFACE must be one of: ${AGENT_SURFACE_TOKENS.join(", ")}`);
|
|
3857
|
+
}
|
|
3858
|
+
function buildNoteCapture(summary, o, id, evidence) {
|
|
3859
|
+
const queueOp = o.queueAdd ? { op: "add", text: o.queueAdd } : o.queueDone != null ? { op: "done", index: Number(o.queueDone) } : void 0;
|
|
3860
|
+
const state = o.diagnostic ? "diagnostic" : o.verified ? "verified" : "asserted";
|
|
3861
|
+
const source = o.diagnostic ? "probe" : "note";
|
|
3862
|
+
const ev = {};
|
|
3863
|
+
if (evidence.sha) ev.sha = evidence.sha;
|
|
3864
|
+
if (evidence.branch) ev.branch = evidence.branch;
|
|
3865
|
+
if (evidence.pr) ev.pr = evidence.pr;
|
|
3866
|
+
if (evidence.file) ev.file = evidence.file;
|
|
3867
|
+
const anchor = o.anchor ? {
|
|
3868
|
+
intent: o.anchor,
|
|
3869
|
+
...o.anchorSlug ? { slug: o.anchorSlug } : {},
|
|
3870
|
+
setAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3871
|
+
} : void 0;
|
|
3872
|
+
return {
|
|
3873
|
+
event: "note",
|
|
3874
|
+
id,
|
|
3875
|
+
summary,
|
|
3876
|
+
next: o.next,
|
|
3877
|
+
decision: o.decision,
|
|
3878
|
+
queueOp,
|
|
3879
|
+
state,
|
|
3880
|
+
source,
|
|
3881
|
+
evidence: Object.keys(ev).length ? ev : void 0,
|
|
3882
|
+
surface: agentSurface(),
|
|
3883
|
+
supersedes: o.supersedes,
|
|
3884
|
+
anchor,
|
|
3885
|
+
anchorForce: o.anchorForce || void 0
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3888
|
+
function formatCaptureFailure(status, message) {
|
|
3889
|
+
if (status === 403 && message === "Forbidden") return `saga: ${ROUTE_LEVEL_403} (HTTP 403)`;
|
|
3890
|
+
return `saga: HTTP ${status}`;
|
|
3891
|
+
}
|
|
3892
|
+
|
|
3855
3893
|
// src/hub-auth.ts
|
|
3856
3894
|
var import_node_crypto = require("node:crypto");
|
|
3857
3895
|
var import_node_fs5 = require("node:fs");
|
|
@@ -4147,6 +4185,13 @@ async function runNote(summary, o) {
|
|
|
4147
4185
|
const capture = buildNoteCapture(summary, o, (0, import_node_crypto3.randomUUID)(), { sha: sha || void 0, branch: key.branch });
|
|
4148
4186
|
await postCapture(capture);
|
|
4149
4187
|
}
|
|
4188
|
+
function resolveSummary(summary, o) {
|
|
4189
|
+
return resolveTextArg({ value: summary, file: o.messageFile }, { readFile: import_promises2.readFile, readStdin }, {
|
|
4190
|
+
value: "a summary argument",
|
|
4191
|
+
file: "--message-file",
|
|
4192
|
+
noun: "message"
|
|
4193
|
+
});
|
|
4194
|
+
}
|
|
4150
4195
|
async function runSagaFlush(o, io = consoleIo) {
|
|
4151
4196
|
if (o.run) {
|
|
4152
4197
|
try {
|
|
@@ -4181,7 +4226,6 @@ async function runSagaShow(opts, io = consoleIo) {
|
|
|
4181
4226
|
const qs = opts.latestAnywhere ? "scope=anywhere" : new URLSearchParams({ project: key.project, branch: key.branch }).toString();
|
|
4182
4227
|
const res = await fetchWithRetry(fetch, `${cfg.sagaApiUrl}/saga/head?${qs}`, { headers: await hubHeaders() }, { attempts: 2, timeoutMs: 3e3 });
|
|
4183
4228
|
if (res.ok) {
|
|
4184
|
-
io.log(resumeCue());
|
|
4185
4229
|
return io.log(await res.text());
|
|
4186
4230
|
}
|
|
4187
4231
|
if (!opts.quiet) io.log(`saga show failed: HTTP ${res.status}`);
|
|
@@ -4192,9 +4236,9 @@ async function runSagaShow(opts, io = consoleIo) {
|
|
|
4192
4236
|
}
|
|
4193
4237
|
}
|
|
4194
4238
|
}
|
|
4195
|
-
async function probeBackend(url) {
|
|
4239
|
+
async function probeBackend(url, opts = { attempts: 3, timeoutMs: 4e3 }) {
|
|
4196
4240
|
try {
|
|
4197
|
-
const res = await fetchWithRetry(fetch, `${url}/saga/head`, { headers: await hubHeaders() },
|
|
4241
|
+
const res = await fetchWithRetry(fetch, `${url}/saga/head`, { headers: await hubHeaders() }, opts);
|
|
4198
4242
|
let message = "";
|
|
4199
4243
|
try {
|
|
4200
4244
|
const body = await res.clone().json();
|
|
@@ -4233,12 +4277,13 @@ async function runSagaHealth(o, io = consoleIo) {
|
|
|
4233
4277
|
const session = resolveSessionId();
|
|
4234
4278
|
const key = await sagaKey(cfg, session);
|
|
4235
4279
|
const source = session.source;
|
|
4280
|
+
const livenessOpts = o.banner ? SESSION_START_LIVENESS : { attempts: 3, timeoutMs: 4e3 };
|
|
4236
4281
|
const [identity, liveness] = await Promise.all([
|
|
4237
4282
|
hubAuthSession({ baseUrl: cfg.sagaApiUrl ?? defaultHubUrl(), githubToken }).then((s) => s?.login),
|
|
4238
|
-
cfg.sagaApiUrl ? probeBackend(cfg.sagaApiUrl) : Promise.resolve({ reachable: false })
|
|
4283
|
+
cfg.sagaApiUrl ? probeBackend(cfg.sagaApiUrl, livenessOpts) : Promise.resolve({ reachable: false })
|
|
4239
4284
|
]);
|
|
4240
|
-
const authorized = cfg.sagaApiUrl && liveness.reachable ? await probeSagaAccess(cfg.sagaApiUrl, key) : void 0;
|
|
4241
|
-
const memoryAgeDays = cfg.sagaApiUrl && liveness.reachable ? await fetchMemoryAge(cfg.sagaApiUrl, key.project) : void 0;
|
|
4285
|
+
const authorized = o.banner ? void 0 : cfg.sagaApiUrl && liveness.reachable ? await probeSagaAccess(cfg.sagaApiUrl, key) : void 0;
|
|
4286
|
+
const memoryAgeDays = o.banner ? void 0 : cfg.sagaApiUrl && liveness.reachable ? await fetchMemoryAge(cfg.sagaApiUrl, key.project) : void 0;
|
|
4242
4287
|
const report = buildHealth({
|
|
4243
4288
|
key,
|
|
4244
4289
|
source,
|
|
@@ -4249,12 +4294,15 @@ async function runSagaHealth(o, io = consoleIo) {
|
|
|
4249
4294
|
authorized,
|
|
4250
4295
|
sagaApiUrl: cfg.sagaApiUrl,
|
|
4251
4296
|
pendingNotes: readPending().length,
|
|
4297
|
+
honchoPending: readHonchoPending().length,
|
|
4252
4298
|
memoryAgeDays
|
|
4253
4299
|
});
|
|
4254
4300
|
if (o.json) return io.log(JSON.stringify(report));
|
|
4255
4301
|
if (o.banner) {
|
|
4256
4302
|
const banner = healthBanner(report);
|
|
4257
4303
|
if (banner) io.log(banner);
|
|
4304
|
+
const sync = memorySyncBanner(report);
|
|
4305
|
+
if (sync) io.log(sync);
|
|
4258
4306
|
return;
|
|
4259
4307
|
}
|
|
4260
4308
|
if (o.quiet) return;
|
|
@@ -4265,8 +4313,24 @@ async function runSagaHealth(o, io = consoleIo) {
|
|
|
4265
4313
|
}
|
|
4266
4314
|
function registerSagaCommands(program2) {
|
|
4267
4315
|
const saga = program2.command("saga").description("per-session continuity");
|
|
4268
|
-
saga.command("note
|
|
4269
|
-
|
|
4316
|
+
saga.command("note [summary]").description("record a one-line structured note into your saga (the per-turn capture)").option("--next <text>", 'set "where I left off" (NEXT)').option("--decision <text>", "append a verbatim decision").option("--queue-add <text>", "add a worklist item").option("--queue-done <n>", "mark worklist item N done").option("--verified", "mark this claim as checked against source (state: verified, else asserted)").option("--diagnostic", "isolate a probe write (state: diagnostic, source: probe) \u2014 never resume/LAST 5").option("--supersedes <key>", "retire prior decisions matching an evidence key (pr:N | file:path)").option("--anchor <intent>", "set the sprint North-Star (write-protected; needs --anchor-force to change)").option("--anchor-slug <slug>", "bind the anchor to a North Star plan slug (SSOT at plans/.../<slug>.md)").option("--anchor-force", "overwrite an existing anchor").option("--message-file <path|->", "read the summary from a UTF-8 file, or from stdin with - (avoids cmd.exe quoting)").action(async (summary, o) => {
|
|
4317
|
+
let text;
|
|
4318
|
+
try {
|
|
4319
|
+
text = await resolveSummary(summary, o);
|
|
4320
|
+
} catch (e) {
|
|
4321
|
+
return fail(`saga note: ${e.message}`);
|
|
4322
|
+
}
|
|
4323
|
+
await runNote(text, o);
|
|
4324
|
+
});
|
|
4325
|
+
saga.command("probe [summary]").description("record a diagnostic probe note (alias for `saga note --diagnostic`)").option("--next <text>", 'set "where I left off" (NEXT)').option("--decision <text>", "append a verbatim decision").option("--queue-add <text>", "add a worklist item").option("--queue-done <n>", "mark worklist item N done").option("--message-file <path|->", "read the summary from a UTF-8 file, or from stdin with - (avoids cmd.exe quoting)").action(async (summary, o) => {
|
|
4326
|
+
let text;
|
|
4327
|
+
try {
|
|
4328
|
+
text = await resolveSummary(summary, o);
|
|
4329
|
+
} catch (e) {
|
|
4330
|
+
return fail(`saga probe: ${e.message}`);
|
|
4331
|
+
}
|
|
4332
|
+
await runNote(text, { ...o, diagnostic: true });
|
|
4333
|
+
});
|
|
4270
4334
|
saga.command("flush").option("--json", "machine-readable {flushed, dropped, remaining}").option("--run", "detached worker: drain the queue silently (spawned by note/capture)").description("roll the local pending-note queue forward (re-POST queued saga writes); reports what landed").action((o) => runSagaFlush(o));
|
|
4271
4335
|
saga.command("show").option("--quiet", "no-op silently when unconfigured/unreachable (SessionStart hook)").option("--latest-anywhere", "resume the newest saga across all repos (default: current repo)").description("print your resume block \u2014 current repo HEAD + project memory (where you left off)").action((opts) => runSagaShow(opts));
|
|
4272
4336
|
saga.command("capture").option("--quiet", "capture silently (for the Stop hook)").description("per-turn deterministic capture (Stop hook): turn boundary + current sha + gated HEAD-update").action(async (opts) => {
|
|
@@ -4380,8 +4444,16 @@ function socketPath(env = process.env, platform = process.platform, user) {
|
|
|
4380
4444
|
return platform === "win32" ? `\\\\.\\pipe\\mmi-cli-${hash}` : (0, import_node_path6.join)(daemonDir(env), `mmi-cli-${hash}.sock`);
|
|
4381
4445
|
}
|
|
4382
4446
|
var HOT_VERBS = /* @__PURE__ */ new Set(["note", "probe", "capture", "session", "head-update"]);
|
|
4447
|
+
function argvReadsStdin(args) {
|
|
4448
|
+
for (let i = 0; i < args.length; i++) {
|
|
4449
|
+
const a = args[i];
|
|
4450
|
+
if (a.endsWith("-file=-")) return true;
|
|
4451
|
+
if (a.endsWith("-file") && args[i + 1] === "-") return true;
|
|
4452
|
+
}
|
|
4453
|
+
return false;
|
|
4454
|
+
}
|
|
4383
4455
|
function daemonEligible(args) {
|
|
4384
|
-
return args[0] === "saga" && HOT_VERBS.has(args[1] ?? "") && !args.includes("--run") && !args.includes("--help") && !args.includes("-h");
|
|
4456
|
+
return args[0] === "saga" && HOT_VERBS.has(args[1] ?? "") && !args.includes("--run") && !args.includes("--help") && !args.includes("-h") && !argvReadsStdin(args);
|
|
4385
4457
|
}
|
|
4386
4458
|
function buildStamp(version, bundleMtimeMs) {
|
|
4387
4459
|
return `${version}#${Math.trunc(bundleMtimeMs)}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.30.0",
|
|
4
4
|
"description": "MMI Future CLI — delivers the org rules (whole-file), plus saga and KB access. The cross-IDE engine the plugin's SessionStart hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^22.0.0",
|
|
42
|
-
"esbuild": "^0.28.
|
|
42
|
+
"esbuild": "^0.28.1",
|
|
43
43
|
"typescript": "^5.7.0",
|
|
44
44
|
"vitest": "^4.1.0"
|
|
45
45
|
}
|