@mutmutco/cli 3.139.2 → 3.139.4

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/main.cjs CHANGED
@@ -10746,10 +10746,10 @@ var rollout_plan_default = {
10746
10746
  note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
10747
10747
  },
10748
10748
  baseline: {
10749
- version: "3.139.2",
10750
- tag: "v3.139.2",
10751
- commit: "1e69c6815490",
10752
- npm: "@mutmutco/cli@3.139.2"
10749
+ version: "3.139.4",
10750
+ tag: "v3.139.4",
10751
+ commit: "ec2807c7a293",
10752
+ npm: "@mutmutco/cli@3.139.4"
10753
10753
  },
10754
10754
  exitCriterion: "fleet-n-of-n",
10755
10755
  hubOnlyShortcut: "forbidden",
@@ -10766,14 +10766,14 @@ var rollout_plan_default = {
10766
10766
  repo: "mutmutco/mmi-hub",
10767
10767
  role: "canary",
10768
10768
  schedule: "train",
10769
- v3Target: "v3.139.2"
10769
+ v3Target: "v3.139.4"
10770
10770
  }
10771
10771
  ],
10772
10772
  rollbackTrigger: "Any red inside the post-cut soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a v3 client refused while the compat window must still admit it (SUPPORTED_MINOR_WINDOW=2, MIN_CLIENT_VERSION 0.0.0 \u2014 D6a), or npm consumer install/doctor failure on the v4 dist.",
10773
10773
  rollback: {
10774
10774
  independent: true,
10775
- mechanism: "npm dist-tag latest -> 3.139.2 and redeploy the Hub Lambda from tag v3.139.2 (1e69c6815490); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
10776
- v3Target: "v3.139.2 (@mutmutco/cli@3.139.2, tag commit 1e69c6815490 \u2014 the preserved latest-v3 distribution, D6b)"
10775
+ mechanism: "npm dist-tag latest -> 3.139.4 and redeploy the Hub Lambda from tag v3.139.4 (ec2807c7a293); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
10776
+ v3Target: "v3.139.4 (@mutmutco/cli@3.139.4, tag commit ec2807c7a293 \u2014 the preserved latest-v3 distribution, D6b)"
10777
10777
  }
10778
10778
  },
10779
10779
  {
@@ -23042,8 +23042,12 @@ var import_node_path22 = require("node:path");
23042
23042
  // src/repo-index-v4/language.ts
23043
23043
  var LANGUAGE_BY_EXTENSION = {
23044
23044
  ".ts": { name: "typescript", parserName: "typescript" },
23045
+ ".mts": { name: "typescript", parserName: "typescript" },
23046
+ ".cts": { name: "typescript", parserName: "typescript" },
23045
23047
  ".tsx": { name: "tsx", parserName: "tsx" },
23046
23048
  ".js": { name: "javascript", parserName: "javascript" },
23049
+ ".mjs": { name: "javascript", parserName: "javascript" },
23050
+ ".cjs": { name: "javascript", parserName: "javascript" },
23047
23051
  ".jsx": { name: "jsx", parserName: "javascript" },
23048
23052
  ".py": { name: "python", parserName: "python" },
23049
23053
  ".go": { name: "go", parserName: "go" },
@@ -23209,6 +23213,7 @@ async function buildStructuralChunks(cwd, repo, commit) {
23209
23213
  var V4_MAX_CHUNKS = 1e4;
23210
23214
  var V4_MAX_ARTIFACT_BYTES = 64 * 1024 * 1024;
23211
23215
  var V4_EMBED_BATCH = 32;
23216
+ var V4_VECTOR_DECIMAL_PLACES = 6;
23212
23217
  var COMMIT = /^[a-f0-9]{40}$/;
23213
23218
  function canonicalJson(value) {
23214
23219
  if (value === null || typeof value !== "object") return JSON.stringify(value);
@@ -23219,6 +23224,9 @@ function canonicalJson(value) {
23219
23224
  function sha2562(value) {
23220
23225
  return (0, import_node_crypto7.createHash)("sha256").update(canonicalJson(value)).digest("hex");
23221
23226
  }
23227
+ function quantizeV4Vector(vector) {
23228
+ return vector.map((value) => Number(value.toFixed(V4_VECTOR_DECIMAL_PLACES)));
23229
+ }
23222
23230
  function statePath(cwd) {
23223
23231
  return repoRuntimeStatePath(cwd, "repo-index", "v4.json");
23224
23232
  }
@@ -23268,16 +23276,20 @@ ${chunk.symbol ?? ""}
23268
23276
  ${chunk.blurb ?? ""}`;
23269
23277
  }
23270
23278
  }
23279
+ var V4_EMBED_TIMEOUT_MS = 15 * 6e4;
23271
23280
  function runEmbedder(cwd, chunks, modelDirectory, createdAt) {
23272
23281
  if (!chunks.length) return { embeddings: [] };
23273
- const runner = (0, import_node_path23.join)(cwd, "repo-indexer", "src", "batch.mjs");
23274
- const fallback = (0, import_node_path23.join)(process.cwd(), "repo-indexer", "src", "batch.mjs");
23275
- const file = (0, import_node_fs25.existsSync)(runner) ? runner : fallback;
23282
+ const orchestratorRunner = (0, import_node_path23.join)(process.cwd(), "repo-indexer", "src", "batch.mjs");
23283
+ const targetRunner = (0, import_node_path23.join)(cwd, "repo-indexer", "src", "batch.mjs");
23284
+ const file = (0, import_node_fs25.existsSync)(orchestratorRunner) ? orchestratorRunner : targetRunner;
23276
23285
  if (!(0, import_node_fs25.existsSync)(file)) return { embeddings: [], reason: "embeddings-unavailable" };
23277
23286
  const request = { texts: chunks.map((chunk) => ({ id: chunk.id, text: embeddingInput(cwd, chunk) })), maxBatch: V4_EMBED_BATCH };
23278
23287
  const env = { ...process.env, ...modelDirectory ? { MMI_REPO_INDEXER_MODEL_DIR: modelDirectory } : {} };
23279
- const result = (0, import_node_child_process13.spawnSync)(process.execPath, [file], { input: JSON.stringify(request), encoding: "utf8", windowsHide: true, timeout: 3e5, maxBuffer: V4_MAX_ARTIFACT_BYTES, env });
23280
- if (result.error || result.status !== 0) return { embeddings: [], reason: "embeddings-unavailable" };
23288
+ const result = (0, import_node_child_process13.spawnSync)(process.execPath, [file], { input: JSON.stringify(request), encoding: "utf8", windowsHide: true, timeout: V4_EMBED_TIMEOUT_MS, maxBuffer: V4_MAX_ARTIFACT_BYTES, env });
23289
+ if (result.error || result.status !== 0) {
23290
+ const detail = result.error?.message ?? result.signal ?? `exit status ${result.status ?? "unknown"}`;
23291
+ throw new Error(`repo-index v4 embedding runner failed: ${detail}`);
23292
+ }
23281
23293
  try {
23282
23294
  const response = JSON.parse(result.stdout);
23283
23295
  if (!response.ok || !response.provenance || !Array.isArray(response.embeddings)) return { embeddings: [], reason: "embeddings-unavailable" };
@@ -23320,7 +23332,7 @@ async function buildRepoIndexV4(cwd, repo, opts = {}) {
23320
23332
  const reusableIds = new Set(reusable.map((e) => e.chunkId));
23321
23333
  const missing = chunks.filter((chunk) => !reusableIds.has(chunk.id));
23322
23334
  const generated = missing.length === 0 ? { embeddings: [] } : opts.embed === false ? { embeddings: [], reason: "embeddings-unavailable" } : runEmbedder(cwd, missing, opts.modelDirectory, createdAt);
23323
- const embeddings = [...reusable, ...generated.embeddings].sort((a, b) => a.chunkId.localeCompare(b.chunkId));
23335
+ const embeddings = [...reusable, ...generated.embeddings].map((embedding) => ({ ...embedding, vector: quantizeV4Vector(embedding.vector) })).sort((a, b) => a.chunkId.localeCompare(b.chunkId));
23324
23336
  const chunksDigest = sha2562(chunks);
23325
23337
  const embeddingsDigest = sha2562(embeddings);
23326
23338
  const artifact = (kind, digest) => {
@@ -23350,6 +23362,9 @@ async function buildRepoIndexV4(cwd, repo, opts = {}) {
23350
23362
  `, "utf8");
23351
23363
  return envelope;
23352
23364
  }
23365
+ function repoIndexV4StorePath(cwd) {
23366
+ return statePath(cwd);
23367
+ }
23353
23368
 
23354
23369
  // src/repo-index-v4/shards.ts
23355
23370
  var V4_STAGE_MAX_BODY_BYTES = 750 * 1024;
@@ -23645,6 +23660,41 @@ var import_node_os12 = require("node:os");
23645
23660
  var import_node_path25 = require("node:path");
23646
23661
  var import_node_child_process14 = require("node:child_process");
23647
23662
 
23663
+ // ../infra/src/repo-index-roster.ts
23664
+ var ORG2 = "mutmutco";
23665
+ function normalizeRepoIndexRepo(raw) {
23666
+ if (typeof raw !== "string") return null;
23667
+ const value = raw.trim().replace(/\.git$/, "");
23668
+ if (!value) return null;
23669
+ if (value.includes("/")) {
23670
+ const [owner, name, ...rest] = value.split("/");
23671
+ if (!owner || !name || rest.length) return null;
23672
+ return `${owner.toLowerCase()}/${name.toLowerCase()}`;
23673
+ }
23674
+ if (!/^[A-Za-z0-9._-]+$/.test(value)) return null;
23675
+ return `${ORG2}/${value.toLowerCase()}`;
23676
+ }
23677
+ function repoIndexRepoIsEligible(project2, repo) {
23678
+ const normalized = normalizeRepoIndexRepo(repo);
23679
+ if (!normalized || project2.class === "content") return false;
23680
+ return !(project2.repoIndexExcludedRepos ?? []).some(
23681
+ (excluded) => normalizeRepoIndexRepo(excluded) === normalized
23682
+ );
23683
+ }
23684
+ function repoIndexRoster(projects) {
23685
+ const excluded = new Set(
23686
+ projects.flatMap((project2) => project2.repoIndexExcludedRepos ?? []).map(normalizeRepoIndexRepo).filter((repo) => repo !== null)
23687
+ );
23688
+ const roster = /* @__PURE__ */ new Set();
23689
+ for (const project2 of projects) {
23690
+ for (const repo of project2.repos ?? []) {
23691
+ const normalized = normalizeRepoIndexRepo(repo);
23692
+ if (normalized && repoIndexRepoIsEligible(project2, normalized) && !excluded.has(normalized)) roster.add(normalized);
23693
+ }
23694
+ }
23695
+ return roster;
23696
+ }
23697
+
23648
23698
  // src/repo-index-v4/edges.ts
23649
23699
  var import_node_fs26 = require("node:fs");
23650
23700
  var import_node_path24 = require("node:path");
@@ -23749,20 +23799,12 @@ function buildGraphEdges(cwd, repo, commit, rosterRepos2) {
23749
23799
  // src/repo-index-sync.ts
23750
23800
  var MAX_EMBED_BACKFILL_ROUNDS = 40;
23751
23801
  function normalizeRepo(raw) {
23752
- const t = raw.trim().replace(/\.git$/, "");
23753
- if (t.includes("/")) {
23754
- const [owner, name] = t.split("/");
23755
- return `${(owner || "").toLowerCase()}/${(name || "").toLowerCase()}`;
23756
- }
23757
- return `mutmutco/${t.toLowerCase()}`;
23802
+ const normalized = normalizeRepoIndexRepo(raw);
23803
+ if (!normalized) throw new Error(`invalid repository: ${raw}`);
23804
+ return normalized;
23758
23805
  }
23759
23806
  function rosterRepos(projects) {
23760
- const set = /* @__PURE__ */ new Set();
23761
- for (const p of projects) {
23762
- if (p.class === "content") continue;
23763
- for (const r of p.repos ?? []) set.add(normalizeRepo(r));
23764
- }
23765
- return [...set].sort((a, b) => a.localeCompare(b));
23807
+ return [...repoIndexRoster(projects)].sort((a, b) => a.localeCompare(b));
23766
23808
  }
23767
23809
  function shallowClone(repo, dest, token) {
23768
23810
  const basic = Buffer.from(`x-access-token:${token}`, "utf8").toString("base64");
@@ -24595,7 +24637,7 @@ async function syncProjectInfo(plan, client, apply) {
24595
24637
  }
24596
24638
 
24597
24639
  // src/project-set.ts
24598
- var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "tenantTasks", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "ciExemptReason", "gate", "seedCanary"];
24640
+ var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "tenantTasks", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "ciExemptReason", "gate", "seedCanary", "repoIndexExcludedRepos"];
24599
24641
  var UNSET_KEY_SET = new Set(UNSET_KEYS);
24600
24642
  var RUNTIME_SECRET_STAGES = ["dev", "rc", "main"];
24601
24643
  var SECRET_CONSUMERS = ["runtime", "build", "lambda", "actions", "agent", "box"];
@@ -24966,6 +25008,7 @@ var SETTABLE_VAR_KEYS = [
24966
25008
  "branch",
24967
25009
  "vaultPath",
24968
25010
  "repos",
25011
+ "repoIndexExcludedRepos",
24969
25012
  "oauth",
24970
25013
  "publishRequired",
24971
25014
  "publishDir",
@@ -25001,6 +25044,7 @@ var SETTABLE_VAR_HINTS = {
25001
25044
  runtimeVaultOnly: "true|false",
25002
25045
  seedCanary: "true|false",
25003
25046
  repos: 'JSON array, e.g. ["mutmutco/mm-foo"]',
25047
+ repoIndexExcludedRepos: "JSON array; excludes only these registered repos from repo-index",
25004
25048
  oauth: "JSON {subdomains,domains,callbackPath,fofuSubdomain}",
25005
25049
  requiredGcpApis: "comma-string",
25006
25050
  requiredRuntimeSecrets: 'JSON stage map, e.g. {"dev":["KEY"],"rc":["KEY"],"main":["KEY"]}',
@@ -25092,7 +25136,7 @@ function buildProjectSetPatch(input) {
25092
25136
  patch[key] = parsePortRangeVar(raw);
25093
25137
  } else if (key === "oauth") {
25094
25138
  patch[key] = parseOauthVar(raw);
25095
- } else if (key === "repos") {
25139
+ } else if (key === "repos" || key === "repoIndexExcludedRepos") {
25096
25140
  patch[key] = parseReposVar(raw);
25097
25141
  } else if (key === "publishRequired") {
25098
25142
  patch[key] = parsePublishRequiredVar(raw);
@@ -32424,7 +32468,7 @@ var surfaces_default = {
32424
32468
  ownership: {
32425
32469
  trust: "host",
32426
32470
  cache: "host",
32427
- repair: "mmi-cli"
32471
+ repair: "mmi-hub"
32428
32472
  },
32429
32473
  certification: {
32430
32474
  hostCommand: "claude",
@@ -32559,7 +32603,7 @@ var surfaces_default = {
32559
32603
  ownership: {
32560
32604
  trust: "operator",
32561
32605
  cache: "host",
32562
- repair: "mmi-cli"
32606
+ repair: "mmi-hub"
32563
32607
  },
32564
32608
  certification: {
32565
32609
  hostCommand: "codex",
@@ -32820,8 +32864,8 @@ var surfaces_default = {
32820
32864
  },
32821
32865
  ownership: {
32822
32866
  trust: "host",
32823
- cache: "mmi-cli",
32824
- repair: "mmi-cli"
32867
+ cache: "mmi-hub",
32868
+ repair: "mmi-hub"
32825
32869
  },
32826
32870
  certification: {
32827
32871
  hostCommand: "cursor-agent",
@@ -32932,7 +32976,7 @@ var surfaces_default = {
32932
32976
  ownership: {
32933
32977
  trust: "host",
32934
32978
  cache: "host",
32935
- repair: "mmi-cli"
32979
+ repair: "mmi-hub"
32936
32980
  },
32937
32981
  certification: {
32938
32982
  hostCommand: "kilo",
@@ -33050,7 +33094,7 @@ var surfaces_default = {
33050
33094
  ownership: {
33051
33095
  trust: "host",
33052
33096
  cache: "host",
33053
- repair: "mmi-cli"
33097
+ repair: "mmi-hub"
33054
33098
  },
33055
33099
  certification: {
33056
33100
  hostCommand: "jervcode",
@@ -34178,19 +34222,14 @@ function checkPluginCache(input) {
34178
34222
  parts.push(`${input.staging.length} orphaned staging dir(s)${size}`);
34179
34223
  }
34180
34224
  return {
34181
- ok: false,
34225
+ ok: true,
34226
+ warn: true,
34182
34227
  id: "plugin-cache",
34183
34228
  label: "plugin cache",
34184
- // #3485: deliberately NOT `reportOnly`, and not in the closed set docs/doctor-contract.md enumerates.
34185
- // A checker argued it qualifies because no `doctor --apply` clears it; I tagged it, then reverted.
34186
- // `mmi-cli plugin prune --apply` clears it in one command and a re-run goes green, so this is an
34187
- // ordinary red the operator is expected to act on. "The doctor cannot heal it automatically" was never
34188
- // the bar — see the contract for why report-only is a per-row ruling rather than a rule you can apply
34189
- // from here.
34190
- // Lead with the versioned-cache framing when there are stale versions; otherwise report the staging litter
34191
- // on its own so a cache with zero versioned dirs still gets an honest ✗.
34229
+ // Installed-surface convergence belongs to mmi-hub; the host owns its cache lifecycle. Doctor
34230
+ // reports old generations but never races either writer by deleting them.
34192
34231
  detail: input.stale.length ? `${input.cached} versions cached (${parts.join("; ")})` : parts.join("; "),
34193
- fix: "run `mmi-cli plugin prune` to review, then `mmi-cli plugin prune --apply` to delete",
34232
+ fix: "run `mmi-hub status` and `mmi-hub update`; if only superseded cache remains, let the host retire it after all older sessions close",
34194
34233
  verbose: evidence
34195
34234
  };
34196
34235
  }
@@ -34295,24 +34334,34 @@ function checkRepoIndexCloud(probe) {
34295
34334
  probe.builtAt ? `builtAt: ${probe.builtAt}` : "builtAt: n/a",
34296
34335
  typeof probe.fileCount === "number" ? `fileCount: ${probe.fileCount}` : "fileCount: n/a",
34297
34336
  typeof probe.embCount === "number" ? `embCount: ${probe.embCount}` : "embCount: n/a",
34298
- typeof probe.localPresent === "boolean" ? `local cache: ${probe.localPresent ? "present" : "absent"}` : "local cache: n/a"
34337
+ typeof probe.localPresent === "boolean" ? `local v3 cache: ${probe.localPresent ? "present" : "absent"}` : "local v3 cache: n/a",
34338
+ `local v4: ${probe.localV4State ?? "unknown"}${probe.localV4Commit ? ` @ ${probe.localV4Commit.slice(0, 12)}` : ""}${typeof probe.localV4EmbeddingCoverage === "number" ? ` (${Math.round(probe.localV4EmbeddingCoverage * 100)}% embeddings)` : ""}`,
34339
+ `cloud v4: ${probe.cloudV4State ?? "unknown"}${probe.cloudV4Commit ? ` @ ${probe.cloudV4Commit.slice(0, 12)}` : ""}`,
34340
+ `v4 cohort: ${probe.v4ReadPercent ?? 0}%`,
34341
+ `v4 shadows: ${probe.v4ShadowComparisons ?? 0}/${probe.v4ShadowMinimum ?? 50} \u2014 ${probe.v4ShadowCutoverReady ? "cutover-ready" : "not ready"}`,
34342
+ ...Object.entries(probe.v4ShadowErrors ?? {}).map(([kind, count]) => `v4 shadow error ${kind}: ${count}`)
34299
34343
  ];
34300
34344
  switch (probe.kind) {
34301
- case "healthy":
34345
+ case "healthy": {
34346
+ const v4Unready = probe.cloudV4State === "invalid" || probe.cloudV4State === "tombstoned" || probe.cloudV4State === "degraded" && (probe.localV4EmbeddingCoverage ?? 1) < 0.95;
34347
+ const detail = probe.detail ?? `cloud v3 ok${typeof probe.fileCount === "number" ? ` \u2014 ${probe.fileCount} files` : ""}; v4 ${probe.cloudV4State ?? "absent"}, cohort ${probe.v4ReadPercent ?? 0}%`;
34302
34348
  return {
34303
- ok: true,
34349
+ ok: !v4Unready || (probe.v4ReadPercent ?? 0) === 0,
34350
+ ...v4Unready && (probe.v4ReadPercent ?? 0) === 0 ? { warn: true, verified: false } : {},
34304
34351
  id: "repo-index",
34305
34352
  label: "repo-index",
34306
- detail: probe.detail ?? `cloud ok${typeof probe.fileCount === "number" ? ` \u2014 ${probe.fileCount} files` : ""}`,
34353
+ detail,
34354
+ ...v4Unready ? { fix: "run `mmi-hub update`, then dispatch `mmi-cli harbour org schedules run MMI-Hub/repo-index-reconcile`; keep the v4 cohort at 0 until shadows pass" } : {},
34307
34355
  verbose: evidence
34308
34356
  };
34357
+ }
34309
34358
  case "command-absent":
34310
34359
  return {
34311
34360
  ok: false,
34312
34361
  id: "repo-index",
34313
34362
  label: "repo-index",
34314
34363
  detail: "this mmi-cli build has no repo-index command",
34315
- fix: "run `mmi-cli doctor` to heal the global CLI, or `npm install -g @mutmutco/cli`",
34364
+ fix: "run `mmi-hub status`, then `mmi-hub update` to converge the CLI and installed host surfaces",
34316
34365
  verbose: evidence
34317
34366
  };
34318
34367
  case "deploy-lag":
@@ -34331,7 +34380,7 @@ function checkRepoIndexCloud(probe) {
34331
34380
  id: "repo-index",
34332
34381
  label: "repo-index",
34333
34382
  detail: probe.detail ?? "no cloud projection for this repo",
34334
- fix: "run harbour repo-index-reconcile or `mmi-cli oracle repo-index sync-estate --repo <owner/name>`",
34383
+ fix: "dispatch `mmi-cli harbour org schedules run MMI-Hub/repo-index-reconcile` or run the authenticated per-repo sync",
34335
34384
  verbose: evidence
34336
34385
  };
34337
34386
  case "stale":
@@ -34340,7 +34389,7 @@ function checkRepoIndexCloud(probe) {
34340
34389
  id: "repo-index",
34341
34390
  label: "repo-index",
34342
34391
  detail: probe.detail ?? "cloud projection looks stale vs recent pushes",
34343
- fix: "trigger `repo-index-reconcile` (workflow_dispatch) or wait for the 6h harbour tick",
34392
+ fix: "dispatch `mmi-cli harbour org schedules run MMI-Hub/repo-index-reconcile` or wait for the registered 6h schedule",
34344
34393
  verbose: evidence
34345
34394
  };
34346
34395
  case "auth":
@@ -34358,7 +34407,7 @@ function checkRepoIndexCloud(probe) {
34358
34407
  id: "repo-index",
34359
34408
  label: "repo-index",
34360
34409
  detail: probe.detail ?? "Hub API URL not configured",
34361
- fix: "run `mmi-cli doctor` to repair Hub wiring",
34410
+ fix: "run `mmi-hub status` and `mmi-hub update`; Hub URL wiring is installer-owned",
34362
34411
  verbose: evidence
34363
34412
  };
34364
34413
  case "network":
@@ -34578,42 +34627,6 @@ async function runDoctorClean(opts, io, deps) {
34578
34627
  }
34579
34628
  }
34580
34629
  async function runPluginCacheRow() {
34581
- if (applyEnv && deps.prunePluginCache && spendOnce("cache-prune")) {
34582
- const cache = deps.pluginCache();
34583
- if (cache.stale.length === 0 && cache.staging.length === 0) {
34584
- emitNow(checkPluginCache(cache));
34585
- return;
34586
- }
34587
- healIntent(`plugin cache \u2014 pruning ${cache.stale.length} superseded version(s) (guarded)`);
34588
- traceHeal("cache-prune");
34589
- const outcome = deps.prunePluginCache();
34590
- if (outcome.removed.length) markHealChanged();
34591
- const evidence = [
34592
- ...outcome.removed.map((v) => `pruned: ${v}`),
34593
- ...outcome.held.map((h) => `still held: ${h.version} (${h.error}) \u2014 never forced`),
34594
- ...outcome.kept.map((k) => `kept: ${k.version} \u2014 ${k.reason}`)
34595
- ];
34596
- if (outcome.held.length === 0) {
34597
- emitNow({
34598
- id: "plugin-cache",
34599
- ok: true,
34600
- label: "plugin cache",
34601
- detail: outcome.removed.length ? `pruned ${outcome.removed.length} superseded version(s)` : "nothing provably superseded (guards kept every candidate)",
34602
- verbose: evidence
34603
- });
34604
- } else {
34605
- emitNow({
34606
- id: "plugin-cache",
34607
- ok: false,
34608
- reportOnly: true,
34609
- label: "plugin cache",
34610
- detail: `${outcome.removed.length} pruned; ${outcome.held.length} still held by a live session`,
34611
- fix: "close the session holding it and re-run `mmi-cli doctor`",
34612
- verbose: evidence
34613
- });
34614
- }
34615
- return;
34616
- }
34617
34630
  emitNow(checkPluginCache(deps.pluginCache()));
34618
34631
  }
34619
34632
  async function runClaudeBinaryRow() {
@@ -35627,6 +35640,21 @@ function mmiDoctorDeps(opts = {}) {
35627
35640
  // #4156: short-timeout Hub status for the current repo. Fail-soft — never throws to doctor.
35628
35641
  repoIndexCloudState: async (root) => {
35629
35642
  const local = repoIndexStatus(root);
35643
+ let localV4 = { state: "absent" };
35644
+ try {
35645
+ const parsed = JSON.parse((0, import_node_fs42.readFileSync)(repoIndexV4StorePath(root), "utf8"));
35646
+ const state = parsed.status?.state;
35647
+ if (parsed.schemaVersion === 4 && (state === "ready" || state === "degraded")) {
35648
+ const chunks = parsed.manifest?.chunks?.length ?? 0;
35649
+ localV4 = {
35650
+ state,
35651
+ ...typeof parsed.manifest?.commit === "string" ? { commit: parsed.manifest.commit } : {},
35652
+ embeddingCoverage: chunks ? (parsed.manifest?.embeddings?.length ?? 0) / chunks : 1
35653
+ };
35654
+ } else localV4 = { state: "invalid" };
35655
+ } catch {
35656
+ }
35657
+ const localFields = { localPresent: local.present, localV4State: localV4.state, localV4Commit: localV4.commit, localV4EmbeddingCoverage: localV4.embeddingCoverage };
35630
35658
  try {
35631
35659
  const cfg = await loadConfig();
35632
35660
  const repo = inferRepoSlug(root);
@@ -35635,17 +35663,32 @@ function mmiDoctorDeps(opts = {}) {
35635
35663
  timeoutMs: 4e3
35636
35664
  });
35637
35665
  if (isRepoIndexStatusError(st)) {
35638
- if (st.code === "deploy-lag") return { kind: "deploy-lag", repo, localPresent: local.present };
35639
- if (st.code === "auth") return { kind: "auth", repo, localPresent: local.present };
35640
- if (st.code === "config") return { kind: "config", repo, detail: st.error, localPresent: local.present };
35641
- return { kind: "network", repo, detail: st.error, localPresent: local.present };
35666
+ if (st.code === "deploy-lag") return { kind: "deploy-lag", repo, ...localFields };
35667
+ if (st.code === "auth") return { kind: "auth", repo, ...localFields };
35668
+ if (st.code === "config") return { kind: "config", repo, detail: st.error, ...localFields };
35669
+ return { kind: "network", repo, detail: st.error, ...localFields };
35642
35670
  }
35643
35671
  const present = st.present;
35644
35672
  const builtAt = typeof st.builtAt === "string" ? st.builtAt : void 0;
35645
35673
  const fileCount = typeof st.fileCount === "number" ? st.fileCount : void 0;
35646
35674
  const embCount = typeof st.embCount === "number" ? st.embCount : void 0;
35675
+ const v4 = st.v4;
35676
+ const migration = st.v4Migration;
35677
+ const shadow = st.v4Shadow;
35678
+ const shadowThresholds = shadow?.thresholds;
35679
+ const cloudV4State = typeof v4?.state === "string" && ["ready", "degraded", "invalid", "tombstoned"].includes(v4.state) ? v4.state : "absent";
35680
+ const v4Fields = {
35681
+ ...localFields,
35682
+ cloudV4State,
35683
+ ...typeof v4?.commit === "string" ? { cloudV4Commit: v4.commit } : {},
35684
+ v4ReadPercent: typeof migration?.readPercent === "number" ? migration.readPercent : 0,
35685
+ v4ShadowComparisons: typeof shadow?.comparisonCount === "number" ? shadow.comparisonCount : 0,
35686
+ v4ShadowMinimum: typeof shadowThresholds?.minimumComparisons === "number" ? shadowThresholds.minimumComparisons : 50,
35687
+ v4ShadowCutoverReady: shadow?.cutoverReady === true,
35688
+ v4ShadowErrors: shadow?.errors && typeof shadow.errors === "object" ? shadow.errors : {}
35689
+ };
35647
35690
  if (present === false) {
35648
- return { kind: "missing-projection", repo, localPresent: local.present, fileCount: 0, embCount: 0 };
35691
+ return { kind: "missing-projection", repo, ...v4Fields, fileCount: 0, embCount: 0 };
35649
35692
  }
35650
35693
  if (builtAt) {
35651
35694
  const ageMs = Date.now() - Date.parse(builtAt);
@@ -35656,7 +35699,7 @@ function mmiDoctorDeps(opts = {}) {
35656
35699
  builtAt,
35657
35700
  fileCount,
35658
35701
  embCount,
35659
- localPresent: local.present,
35702
+ ...v4Fields,
35660
35703
  detail: `projection builtAt ${builtAt} (>48h old)`
35661
35704
  };
35662
35705
  }
@@ -35667,13 +35710,13 @@ function mmiDoctorDeps(opts = {}) {
35667
35710
  builtAt,
35668
35711
  fileCount,
35669
35712
  embCount,
35670
- localPresent: local.present
35713
+ ...v4Fields
35671
35714
  };
35672
35715
  } catch (e) {
35673
35716
  return {
35674
35717
  kind: "network",
35675
35718
  detail: e instanceof Error ? e.message : String(e),
35676
- localPresent: local.present
35719
+ ...localFields
35677
35720
  };
35678
35721
  }
35679
35722
  }
@@ -197,8 +197,12 @@ function listCandidatePaths(cwd, exec = import_node_child_process2.execFileSync)
197
197
  // src/repo-index-v4/language.ts
198
198
  var LANGUAGE_BY_EXTENSION = {
199
199
  ".ts": { name: "typescript", parserName: "typescript" },
200
+ ".mts": { name: "typescript", parserName: "typescript" },
201
+ ".cts": { name: "typescript", parserName: "typescript" },
200
202
  ".tsx": { name: "tsx", parserName: "tsx" },
201
203
  ".js": { name: "javascript", parserName: "javascript" },
204
+ ".mjs": { name: "javascript", parserName: "javascript" },
205
+ ".cjs": { name: "javascript", parserName: "javascript" },
202
206
  ".jsx": { name: "jsx", parserName: "javascript" },
203
207
  ".py": { name: "python", parserName: "python" },
204
208
  ".go": { name: "go", parserName: "go" },
@@ -371,6 +375,7 @@ var import_node_path4 = require("node:path");
371
375
  var V4_MAX_CHUNKS = 1e4;
372
376
  var V4_MAX_ARTIFACT_BYTES = 64 * 1024 * 1024;
373
377
  var V4_EMBED_BATCH = 32;
378
+ var V4_VECTOR_DECIMAL_PLACES = 6;
374
379
  var COMMIT = /^[a-f0-9]{40}$/;
375
380
  function canonicalJson(value) {
376
381
  if (value === null || typeof value !== "object") return JSON.stringify(value);
@@ -381,6 +386,9 @@ function canonicalJson(value) {
381
386
  function sha2562(value) {
382
387
  return (0, import_node_crypto3.createHash)("sha256").update(canonicalJson(value)).digest("hex");
383
388
  }
389
+ function quantizeV4Vector(vector) {
390
+ return vector.map((value) => Number(value.toFixed(V4_VECTOR_DECIMAL_PLACES)));
391
+ }
384
392
  function statePath(cwd) {
385
393
  return repoRuntimeStatePath(cwd, "repo-index", "v4.json");
386
394
  }
@@ -430,16 +438,20 @@ ${chunk.symbol ?? ""}
430
438
  ${chunk.blurb ?? ""}`;
431
439
  }
432
440
  }
441
+ var V4_EMBED_TIMEOUT_MS = 15 * 6e4;
433
442
  function runEmbedder(cwd, chunks, modelDirectory, createdAt) {
434
443
  if (!chunks.length) return { embeddings: [] };
435
- const runner = (0, import_node_path4.join)(cwd, "repo-indexer", "src", "batch.mjs");
436
- const fallback = (0, import_node_path4.join)(process.cwd(), "repo-indexer", "src", "batch.mjs");
437
- const file = (0, import_node_fs3.existsSync)(runner) ? runner : fallback;
444
+ const orchestratorRunner = (0, import_node_path4.join)(process.cwd(), "repo-indexer", "src", "batch.mjs");
445
+ const targetRunner = (0, import_node_path4.join)(cwd, "repo-indexer", "src", "batch.mjs");
446
+ const file = (0, import_node_fs3.existsSync)(orchestratorRunner) ? orchestratorRunner : targetRunner;
438
447
  if (!(0, import_node_fs3.existsSync)(file)) return { embeddings: [], reason: "embeddings-unavailable" };
439
448
  const request = { texts: chunks.map((chunk) => ({ id: chunk.id, text: embeddingInput(cwd, chunk) })), maxBatch: V4_EMBED_BATCH };
440
449
  const env = { ...process.env, ...modelDirectory ? { MMI_REPO_INDEXER_MODEL_DIR: modelDirectory } : {} };
441
- const result = (0, import_node_child_process3.spawnSync)(process.execPath, [file], { input: JSON.stringify(request), encoding: "utf8", windowsHide: true, timeout: 3e5, maxBuffer: V4_MAX_ARTIFACT_BYTES, env });
442
- if (result.error || result.status !== 0) return { embeddings: [], reason: "embeddings-unavailable" };
450
+ const result = (0, import_node_child_process3.spawnSync)(process.execPath, [file], { input: JSON.stringify(request), encoding: "utf8", windowsHide: true, timeout: V4_EMBED_TIMEOUT_MS, maxBuffer: V4_MAX_ARTIFACT_BYTES, env });
451
+ if (result.error || result.status !== 0) {
452
+ const detail = result.error?.message ?? result.signal ?? `exit status ${result.status ?? "unknown"}`;
453
+ throw new Error(`repo-index v4 embedding runner failed: ${detail}`);
454
+ }
443
455
  try {
444
456
  const response = JSON.parse(result.stdout);
445
457
  if (!response.ok || !response.provenance || !Array.isArray(response.embeddings)) return { embeddings: [], reason: "embeddings-unavailable" };
@@ -482,7 +494,7 @@ async function buildRepoIndexV4(cwd, repo, opts = {}) {
482
494
  const reusableIds = new Set(reusable.map((e) => e.chunkId));
483
495
  const missing = chunks.filter((chunk) => !reusableIds.has(chunk.id));
484
496
  const generated = missing.length === 0 ? { embeddings: [] } : opts.embed === false ? { embeddings: [], reason: "embeddings-unavailable" } : runEmbedder(cwd, missing, opts.modelDirectory, createdAt);
485
- const embeddings = [...reusable, ...generated.embeddings].sort((a, b) => a.chunkId.localeCompare(b.chunkId));
497
+ const embeddings = [...reusable, ...generated.embeddings].map((embedding) => ({ ...embedding, vector: quantizeV4Vector(embedding.vector) })).sort((a, b) => a.chunkId.localeCompare(b.chunkId));
486
498
  const chunksDigest = sha2562(chunks);
487
499
  const embeddingsDigest = sha2562(embeddings);
488
500
  const artifact = (kind, digest) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.139.2",
3
+ "version": "3.139.4",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",