@mutmutco/cli 4.1.1 → 4.1.3
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 +340 -60
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -2306,7 +2306,8 @@ __export(index_exports, {
|
|
|
2306
2306
|
positionalTargetForm: () => positionalTargetForm,
|
|
2307
2307
|
registryClientDeps: () => registryClientDeps,
|
|
2308
2308
|
repoSlug: () => repoSlug,
|
|
2309
|
-
suggestCommandPath: () => suggestCommandPath
|
|
2309
|
+
suggestCommandPath: () => suggestCommandPath,
|
|
2310
|
+
unknownCommandCandidates: () => unknownCommandCandidates
|
|
2310
2311
|
});
|
|
2311
2312
|
module.exports = __toCommonJS(index_exports);
|
|
2312
2313
|
|
|
@@ -12867,10 +12868,10 @@ var rollout_plan_default = {
|
|
|
12867
12868
|
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)."
|
|
12868
12869
|
},
|
|
12869
12870
|
baseline: {
|
|
12870
|
-
version: "4.1.
|
|
12871
|
-
tag: "v4.1.
|
|
12872
|
-
commit: "
|
|
12873
|
-
npm: "@mutmutco/cli@4.1.
|
|
12871
|
+
version: "4.1.3",
|
|
12872
|
+
tag: "v4.1.3",
|
|
12873
|
+
commit: "3164484f3f37",
|
|
12874
|
+
npm: "@mutmutco/cli@4.1.3"
|
|
12874
12875
|
},
|
|
12875
12876
|
exitCriterion: "fleet-n-of-n",
|
|
12876
12877
|
hubOnlyShortcut: "forbidden",
|
|
@@ -12887,14 +12888,14 @@ var rollout_plan_default = {
|
|
|
12887
12888
|
repo: "mutmutco/mmi-hub",
|
|
12888
12889
|
role: "canary",
|
|
12889
12890
|
schedule: "train",
|
|
12890
|
-
v3Target: "v4.1.
|
|
12891
|
+
v3Target: "v4.1.3"
|
|
12891
12892
|
}
|
|
12892
12893
|
],
|
|
12893
12894
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
12894
12895
|
rollback: {
|
|
12895
12896
|
independent: true,
|
|
12896
|
-
mechanism: "npm dist-tag latest -> 4.1.
|
|
12897
|
-
v3Target: "v4.1.
|
|
12897
|
+
mechanism: "npm dist-tag latest -> 4.1.3 and redeploy the Hub Lambda from tag v4.1.3 (3164484f3f37); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
12898
|
+
v3Target: "v4.1.3 (@mutmutco/cli@4.1.3, tag commit 3164484f3f37 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
12898
12899
|
}
|
|
12899
12900
|
},
|
|
12900
12901
|
{
|
|
@@ -19388,8 +19389,10 @@ init_client_version();
|
|
|
19388
19389
|
var BOARD_SNAPSHOT_TIMEOUT_MS = 25e3;
|
|
19389
19390
|
function isSnapshotShape(body) {
|
|
19390
19391
|
const b = body;
|
|
19392
|
+
const rate = b?.github?.rateLimit;
|
|
19393
|
+
const githubValid = b?.github === void 0 || b.github.credential === "app_installation" && Number.isFinite(rate?.limit) && Number.isFinite(rate?.remaining) && Number.isFinite(rate?.cost) && typeof rate?.resetAt === "string";
|
|
19391
19394
|
return Boolean(
|
|
19392
|
-
b && typeof b === "object" && typeof b.project?.id === "string" && typeof b.project?.title === "string" && typeof b.viewer === "string" && b.viewer.length > 0 && Array.isArray(b.nodes) && Array.isArray(b.writableRepos) && Array.isArray(b.unreadableRepos) && Array.isArray(b.pullRequests) && Array.isArray(b.warnings) && typeof b.partial === "boolean"
|
|
19395
|
+
b && typeof b === "object" && typeof b.project?.id === "string" && typeof b.project?.title === "string" && typeof b.viewer === "string" && b.viewer.length > 0 && Array.isArray(b.nodes) && Array.isArray(b.writableRepos) && Array.isArray(b.unreadableRepos) && Array.isArray(b.pullRequests) && Array.isArray(b.warnings) && typeof b.partial === "boolean" && githubValid
|
|
19393
19396
|
);
|
|
19394
19397
|
}
|
|
19395
19398
|
async function fetchHubBoardSnapshot(request, deps) {
|
|
@@ -20172,6 +20175,10 @@ function renderBoardItem(item) {
|
|
|
20172
20175
|
}
|
|
20173
20176
|
function renderBoardReport(report) {
|
|
20174
20177
|
const lines = [`Board \xB7 ${report.project.title} \xB7 @${report.viewer}`, renderBoardSource()];
|
|
20178
|
+
if (report.github) {
|
|
20179
|
+
const { limit, remaining, cost, resetAt } = report.github.rateLimit;
|
|
20180
|
+
lines.push(`github: app installation \xB7 GraphQL ${remaining}/${limit} remaining \xB7 cost ${cost} \xB7 resets ${resetAt}`);
|
|
20181
|
+
}
|
|
20175
20182
|
renderScope(lines, "PRIMARY", report.repo, report.primary, report.viewer);
|
|
20176
20183
|
renderScope(lines, "SECONDARY", "Other repos on this project", report.secondary, report.viewer);
|
|
20177
20184
|
if (report.warnings.length) {
|
|
@@ -20284,6 +20291,7 @@ async function readBoard(options, deps = {}) {
|
|
|
20284
20291
|
let collected;
|
|
20285
20292
|
let writable;
|
|
20286
20293
|
let pullRequests;
|
|
20294
|
+
let github;
|
|
20287
20295
|
let snapshotFallback;
|
|
20288
20296
|
const attempt = deps.snapshot ? await fetchHubBoardSnapshot(
|
|
20289
20297
|
{
|
|
@@ -20328,6 +20336,7 @@ async function readBoard(options, deps = {}) {
|
|
|
20328
20336
|
unknown: new Set(snapshot.unreadableRepos.map((entry) => entry.repo.toLowerCase()))
|
|
20329
20337
|
};
|
|
20330
20338
|
pullRequests = snapshot.pullRequests;
|
|
20339
|
+
github = snapshot.github;
|
|
20331
20340
|
} else {
|
|
20332
20341
|
if (attempt?.state === "unavailable") snapshotFallback = attempt.reason;
|
|
20333
20342
|
collected = await collectBoardItems(cfg, { repo: options.repo, allowPartial: options.allowPartial, activeOnly: true }, deps);
|
|
@@ -20348,7 +20357,8 @@ async function readBoard(options, deps = {}) {
|
|
|
20348
20357
|
warnings: collected.warnings,
|
|
20349
20358
|
partial: collected.partial,
|
|
20350
20359
|
source: "live",
|
|
20351
|
-
...pullRequests ? { pullRequests } : {}
|
|
20360
|
+
...pullRequests ? { pullRequests } : {},
|
|
20361
|
+
...github ? { github } : {}
|
|
20352
20362
|
};
|
|
20353
20363
|
if (options.includeBundleDetails || options.includeAllBodies) {
|
|
20354
20364
|
await attachBundleDetails(report, client, options.allowPartial ?? false, { all: options.includeAllBodies });
|
|
@@ -25322,6 +25332,7 @@ function repoIndexV4BucketDigests(repo, chunks, embeddings) {
|
|
|
25322
25332
|
|
|
25323
25333
|
// src/repo-index-cloud-client.ts
|
|
25324
25334
|
var RETRY_ATTEMPTS2 = 3;
|
|
25335
|
+
var REPO_INDEX_GC_TIMEOUT_MS = 12e4;
|
|
25325
25336
|
async function repoIndexSourceHostHeaders() {
|
|
25326
25337
|
const { detectSurface: detectSurface2 } = await Promise.resolve().then(() => (init_plugin_guard_io(), plugin_guard_io_exports));
|
|
25327
25338
|
return { [SOURCE_HOST_HEADER]: detectSurface2(process.env) };
|
|
@@ -25727,10 +25738,22 @@ async function statusRepoIndexCloud(repo, deps) {
|
|
|
25727
25738
|
return { ok: false, error: e.message, code: "network" };
|
|
25728
25739
|
}
|
|
25729
25740
|
}
|
|
25741
|
+
function normalizeGcV4Repos(raw) {
|
|
25742
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
25743
|
+
const out = {};
|
|
25744
|
+
for (const [repo, value] of Object.entries(raw)) {
|
|
25745
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
25746
|
+
const removed = Array.isArray(value.removed) ? value.removed.filter((k) => typeof k === "string") : [];
|
|
25747
|
+
const kept = Number(value.kept);
|
|
25748
|
+
out[repo] = { removed, kept: Number.isFinite(kept) ? kept : 0 };
|
|
25749
|
+
}
|
|
25750
|
+
return out;
|
|
25751
|
+
}
|
|
25730
25752
|
async function gcRepoIndexCloud(deps) {
|
|
25731
25753
|
if (!deps.baseUrl) return { ok: false, error: "Hub API URL not configured" };
|
|
25732
25754
|
const token = await deps.token();
|
|
25733
25755
|
if (!token) return { ok: false, error: "no Hub session token (run `gh auth login`)" };
|
|
25756
|
+
const timeoutMs = deps.timeoutMs ?? REPO_INDEX_GC_TIMEOUT_MS;
|
|
25734
25757
|
try {
|
|
25735
25758
|
const res = await fetchWithRetry(
|
|
25736
25759
|
deps.fetch ?? fetch,
|
|
@@ -25740,13 +25763,32 @@ async function gcRepoIndexCloud(deps) {
|
|
|
25740
25763
|
headers: { ...clientVersionHeaders(), Authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
25741
25764
|
body: "{}"
|
|
25742
25765
|
},
|
|
25743
|
-
|
|
25766
|
+
// Single attempt: GC tombstones authorities and deletes S3 objects. A timed-out POST may still
|
|
25767
|
+
// finish on Hub; retrying would re-issue a destructive sweep without an authoritative receipt.
|
|
25768
|
+
{ attempts: 1, timeoutMs, sleep: deps.retrySleep }
|
|
25744
25769
|
);
|
|
25745
25770
|
const body = await res.json().catch(() => ({}));
|
|
25746
25771
|
if (!res.ok) return { ok: false, error: body.error ?? `gc HTTP ${res.status}` };
|
|
25747
|
-
|
|
25772
|
+
const removed = Array.isArray(body.removed) ? body.removed.filter((repo) => typeof repo === "string") : [];
|
|
25773
|
+
const kept = Number(body.kept);
|
|
25774
|
+
return {
|
|
25775
|
+
ok: true,
|
|
25776
|
+
removed,
|
|
25777
|
+
kept: Number.isFinite(kept) ? kept : 0,
|
|
25778
|
+
v4: {
|
|
25779
|
+
dryRun: body.v4?.dryRun === true,
|
|
25780
|
+
repos: normalizeGcV4Repos(body.v4?.repos)
|
|
25781
|
+
}
|
|
25782
|
+
};
|
|
25748
25783
|
} catch (e) {
|
|
25749
|
-
|
|
25784
|
+
const msg = e.message || String(e);
|
|
25785
|
+
if (/abort|timeout/i.test(msg)) {
|
|
25786
|
+
return {
|
|
25787
|
+
ok: false,
|
|
25788
|
+
error: `repo-index gc timed out after ${timeoutMs}ms \u2014 Hub may still have completed the destructive sweep; run \`mmi-cli oracle repo-index status --cloud --json\` and verify before retrying`
|
|
25789
|
+
};
|
|
25790
|
+
}
|
|
25791
|
+
return { ok: false, error: msg };
|
|
25750
25792
|
}
|
|
25751
25793
|
}
|
|
25752
25794
|
|
|
@@ -25893,6 +25935,16 @@ function buildGraphEdges(cwd, repo, commit, rosterRepos2) {
|
|
|
25893
25935
|
}
|
|
25894
25936
|
|
|
25895
25937
|
// src/repo-index-sync.ts
|
|
25938
|
+
function execFileUtf8(file, args) {
|
|
25939
|
+
return new Promise((resolve5, reject) => {
|
|
25940
|
+
(0, import_node_child_process15.execFile)(file, args, { encoding: "utf8", windowsHide: true }, (error, stdout) => {
|
|
25941
|
+
if (error) reject(error);
|
|
25942
|
+
else resolve5(String(stdout ?? ""));
|
|
25943
|
+
});
|
|
25944
|
+
});
|
|
25945
|
+
}
|
|
25946
|
+
var ESTATE_CLASSIFY_CONCURRENCY = 8;
|
|
25947
|
+
var ESTATE_HEALTHY_CLASSIFY_BUDGET_MS = 5 * 601e3;
|
|
25896
25948
|
var COMMIT3 = /^[a-f0-9]{40}$/;
|
|
25897
25949
|
var SHA256 = /^[a-f0-9]{64}$/;
|
|
25898
25950
|
var UTC_MILLIS = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
@@ -25928,17 +25980,28 @@ function checkoutExactCommit(repo, dest, token, commit) {
|
|
|
25928
25980
|
const head = git3(["rev-parse", "HEAD"]).trim().toLowerCase();
|
|
25929
25981
|
if (head !== commit) throw new Error(`checkout of ${repo} resolved ${head}, not the requested commit ${commit}`);
|
|
25930
25982
|
}
|
|
25931
|
-
function remoteHead(repo, token) {
|
|
25983
|
+
async function remoteHead(repo, token) {
|
|
25932
25984
|
const basic = Buffer.from(`x-access-token:${token}`, "utf8").toString("base64");
|
|
25933
|
-
const
|
|
25985
|
+
const stdout = await execFileUtf8(
|
|
25934
25986
|
"git",
|
|
25935
|
-
["-c", `http.extraHeader=Authorization: Basic ${basic}`, "ls-remote", "--exit-code", `https://github.com/${repo}.git`, "HEAD"]
|
|
25936
|
-
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true }
|
|
25987
|
+
["-c", `http.extraHeader=Authorization: Basic ${basic}`, "ls-remote", "--exit-code", `https://github.com/${repo}.git`, "HEAD"]
|
|
25937
25988
|
);
|
|
25938
|
-
const match =
|
|
25989
|
+
const match = stdout.match(/^([a-f0-9]{40})\s+HEAD$/m);
|
|
25939
25990
|
if (!match) throw new Error(`could not resolve remote HEAD for ${repo}`);
|
|
25940
25991
|
return match[1];
|
|
25941
25992
|
}
|
|
25993
|
+
async function mapLimit(items, limit, fn) {
|
|
25994
|
+
const out = new Array(items.length);
|
|
25995
|
+
let next = 0;
|
|
25996
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
25997
|
+
while (next < items.length) {
|
|
25998
|
+
const i = next++;
|
|
25999
|
+
out[i] = await fn(items[i], i);
|
|
26000
|
+
}
|
|
26001
|
+
});
|
|
26002
|
+
await Promise.all(workers);
|
|
26003
|
+
return out;
|
|
26004
|
+
}
|
|
25942
26005
|
function verifiedReadyBase(statusValue, repo) {
|
|
25943
26006
|
if (!statusValue || typeof statusValue !== "object" || Array.isArray(statusValue)) return null;
|
|
25944
26007
|
const status = statusValue;
|
|
@@ -25946,8 +26009,9 @@ function verifiedReadyBase(statusValue, repo) {
|
|
|
25946
26009
|
if (!v4 || typeof v4 !== "object" || Array.isArray(v4)) return null;
|
|
25947
26010
|
const pointer = v4;
|
|
25948
26011
|
const artifactDigests = pointer.artifactDigests;
|
|
26012
|
+
const expectedArtifactDigests = pointer.materialLayout === 2 ? 1 : pointer.materialLayout === void 0 || pointer.materialLayout === 1 ? 2 : 0;
|
|
25949
26013
|
const counts = [pointer.chunkCount, pointer.embeddingCount, pointer.tombstoneCount];
|
|
25950
|
-
const structurallyVerified = status.repo === repo && pointer.repo === repo && pointer.state === "ready" && pointer.integrity === "verified" && typeof pointer.commit === "string" && COMMIT3.test(pointer.commit) && typeof pointer.digest === "string" && SHA256.test(pointer.digest) && Array.isArray(artifactDigests) && artifactDigests.length ===
|
|
26014
|
+
const structurallyVerified = status.repo === repo && pointer.repo === repo && pointer.state === "ready" && pointer.integrity === "verified" && typeof pointer.commit === "string" && COMMIT3.test(pointer.commit) && typeof pointer.digest === "string" && SHA256.test(pointer.digest) && Array.isArray(artifactDigests) && artifactDigests.length === expectedArtifactDigests && new Set(artifactDigests).size === artifactDigests.length && artifactDigests.every((digest) => typeof digest === "string" && SHA256.test(digest)) && counts.every((count) => Number.isInteger(count) && Number(count) >= 0) && pointer.embeddingCount === pointer.chunkCount && typeof pointer.activatedAt === "string" && UTC_MILLIS.test(pointer.activatedAt) && Number.isFinite(Date.parse(pointer.activatedAt)) && new Date(pointer.activatedAt).toISOString() === pointer.activatedAt;
|
|
25951
26015
|
return structurallyVerified && typeof pointer.commit === "string" && typeof pointer.digest === "string" ? { commit: pointer.commit, digest: pointer.digest } : null;
|
|
25952
26016
|
}
|
|
25953
26017
|
function activePointerDigest(statusValue) {
|
|
@@ -26039,11 +26103,18 @@ async function syncEstateRepoIndex(opts) {
|
|
|
26039
26103
|
const busy = new Set(
|
|
26040
26104
|
(opts.skipRepos ?? []).map((repo) => normalizeRepoIndexRepo(repo)).filter((repo) => repo !== null)
|
|
26041
26105
|
);
|
|
26042
|
-
|
|
26106
|
+
const emit = (progress) => {
|
|
26107
|
+
try {
|
|
26108
|
+
opts.onClassify?.(progress);
|
|
26109
|
+
} catch {
|
|
26110
|
+
}
|
|
26111
|
+
};
|
|
26112
|
+
const classified = await mapLimit(repos, ESTATE_CLASSIFY_CONCURRENCY, async (repo) => {
|
|
26043
26113
|
if (busy.has(repo)) {
|
|
26044
|
-
|
|
26045
|
-
|
|
26046
|
-
|
|
26114
|
+
const row2 = { repo, reason: "busy-elsewhere", action: "skip" };
|
|
26115
|
+
const warning = `${repo}: a per-repo reconcile run is already publishing it`;
|
|
26116
|
+
emit({ row: row2, warning });
|
|
26117
|
+
return { repo, row: row2, warning, base: null, expectedActiveDigest: void 0 };
|
|
26047
26118
|
}
|
|
26048
26119
|
let base = null;
|
|
26049
26120
|
let expectedActiveDigest;
|
|
@@ -26066,7 +26137,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
26066
26137
|
if (base && !forceFull) {
|
|
26067
26138
|
if (!targetCommit) {
|
|
26068
26139
|
try {
|
|
26069
|
-
targetCommit = remoteHead(repo, opts.githubToken);
|
|
26140
|
+
targetCommit = await remoteHead(repo, opts.githubToken);
|
|
26070
26141
|
} catch {
|
|
26071
26142
|
targetCommit = void 0;
|
|
26072
26143
|
}
|
|
@@ -26075,25 +26146,43 @@ async function syncEstateRepoIndex(opts) {
|
|
|
26075
26146
|
(error) => ({ ok: false, error: error.message })
|
|
26076
26147
|
);
|
|
26077
26148
|
if (provenance.ok && !provenance.deltaCompatible) {
|
|
26078
|
-
|
|
26079
|
-
|
|
26080
|
-
|
|
26081
|
-
|
|
26149
|
+
const row2 = {
|
|
26150
|
+
repo,
|
|
26151
|
+
reason: "incompatible-provenance",
|
|
26152
|
+
action: "needs-full-rebuild",
|
|
26153
|
+
activeCommit: base.commit,
|
|
26154
|
+
...targetCommit ? { targetCommit } : {}
|
|
26155
|
+
};
|
|
26156
|
+
const warning = `${repo}: DRIFT incompatible index provenance \u2014 the active authority at ${base.commit} was not built by ${CURRENT_REPO_INDEX_PROVENANCE_TOKEN}; migrate it explicitly with \`oracle repo-index sync-estate --repo ${repo} --full-rebuild ${CURRENT_REPO_INDEX_PROVENANCE_TOKEN}\``;
|
|
26157
|
+
emit({ row: row2, warning });
|
|
26158
|
+
return { repo, row: row2, warning, base, expectedActiveDigest };
|
|
26082
26159
|
}
|
|
26083
26160
|
if (targetCommit && targetCommit === base.commit) {
|
|
26084
|
-
|
|
26085
|
-
|
|
26086
|
-
|
|
26161
|
+
const row2 = { repo, reason: "healthy", action: "skip", activeCommit: base.commit, targetCommit };
|
|
26162
|
+
const warning = `${repo}: unchanged verified-ready authority at ${targetCommit}`;
|
|
26163
|
+
emit({ row: row2, warning });
|
|
26164
|
+
return { repo, row: row2, warning, base, expectedActiveDigest };
|
|
26087
26165
|
}
|
|
26088
26166
|
}
|
|
26089
|
-
|
|
26167
|
+
const row = {
|
|
26090
26168
|
repo,
|
|
26091
26169
|
reason,
|
|
26092
26170
|
action: "build",
|
|
26093
26171
|
...base ? { activeCommit: base.commit } : {},
|
|
26094
26172
|
...targetCommit ? { targetCommit } : {}
|
|
26095
|
-
}
|
|
26096
|
-
|
|
26173
|
+
};
|
|
26174
|
+
emit({ row });
|
|
26175
|
+
return { repo, row, base, expectedActiveDigest };
|
|
26176
|
+
});
|
|
26177
|
+
for (const entry of classified) {
|
|
26178
|
+
drift.push(entry.row);
|
|
26179
|
+
if (entry.warning) skipped.push(entry.warning);
|
|
26180
|
+
if (entry.row.action === "needs-full-rebuild") needsFullRebuild.push(entry.repo);
|
|
26181
|
+
}
|
|
26182
|
+
if (opts.plan) return answer();
|
|
26183
|
+
for (const entry of classified) {
|
|
26184
|
+
if (entry.row.action !== "build") continue;
|
|
26185
|
+
const { repo, base, expectedActiveDigest } = entry;
|
|
26097
26186
|
const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path25.join)((0, import_node_os13.tmpdir)(), "mmi-repo-index-"));
|
|
26098
26187
|
try {
|
|
26099
26188
|
shallowClone(repo, dir, opts.githubToken);
|
|
@@ -26534,6 +26623,79 @@ function runSpawnPolicy(root) {
|
|
|
26534
26623
|
var import_node_child_process17 = require("node:child_process");
|
|
26535
26624
|
var import_node_fs30 = require("node:fs");
|
|
26536
26625
|
var import_node_path27 = require("node:path");
|
|
26626
|
+
|
|
26627
|
+
// ../scripts/test-command-policy-core.mjs
|
|
26628
|
+
var TEST_COMMAND_CLASS = "test";
|
|
26629
|
+
function translateGlob(glob) {
|
|
26630
|
+
let out = "";
|
|
26631
|
+
for (let i = 0; i < glob.length; i += 1) {
|
|
26632
|
+
const char = glob[i];
|
|
26633
|
+
if (char === "*") {
|
|
26634
|
+
if (glob[i + 1] === "*") {
|
|
26635
|
+
if (glob[i + 2] === "/") {
|
|
26636
|
+
out += "(?:.*/)?";
|
|
26637
|
+
i += 2;
|
|
26638
|
+
} else {
|
|
26639
|
+
out += ".*";
|
|
26640
|
+
i += 1;
|
|
26641
|
+
}
|
|
26642
|
+
} else out += "[^/]*";
|
|
26643
|
+
} else if (char === "{") {
|
|
26644
|
+
const close = glob.indexOf("}", i);
|
|
26645
|
+
if (close === -1) out += "\\{";
|
|
26646
|
+
else {
|
|
26647
|
+
out += `(?:${glob.slice(i + 1, close).split(",").map(translateGlob).join("|")})`;
|
|
26648
|
+
i = close;
|
|
26649
|
+
}
|
|
26650
|
+
} else {
|
|
26651
|
+
out += /[.+?^${}()|[\]\\]/.test(char) ? `\\${char}` : char;
|
|
26652
|
+
}
|
|
26653
|
+
}
|
|
26654
|
+
return out;
|
|
26655
|
+
}
|
|
26656
|
+
function globToRegExp(glob) {
|
|
26657
|
+
return new RegExp(`^${translateGlob(glob)}$`);
|
|
26658
|
+
}
|
|
26659
|
+
function mandatoryGlobList(mandatory) {
|
|
26660
|
+
if (!Array.isArray(mandatory)) return [];
|
|
26661
|
+
return mandatory.map((entry) => typeof entry === "string" ? entry : entry?.glob).filter((glob) => typeof glob === "string");
|
|
26662
|
+
}
|
|
26663
|
+
function matchedMandatoryGlobs(paths, mandatory) {
|
|
26664
|
+
const globs = mandatoryGlobList(mandatory);
|
|
26665
|
+
const list = Array.isArray(paths) ? paths : [];
|
|
26666
|
+
return globs.filter((glob) => {
|
|
26667
|
+
const re = globToRegExp(glob);
|
|
26668
|
+
return list.some((path2) => re.test(path2));
|
|
26669
|
+
});
|
|
26670
|
+
}
|
|
26671
|
+
function evaluateTestCommandPolicy({ paths, mandatory, regulated = true } = {}) {
|
|
26672
|
+
const configuredMandatoryCount = mandatoryGlobList(mandatory).length;
|
|
26673
|
+
if (!regulated) {
|
|
26674
|
+
return {
|
|
26675
|
+
configuredMandatoryCount: 0,
|
|
26676
|
+
matchedMandatoryGlobs: [],
|
|
26677
|
+
matchedMandatoryCount: 0,
|
|
26678
|
+
testCommandsAllowed: true,
|
|
26679
|
+
reasonId: null,
|
|
26680
|
+
commandClasses: { allowed: [TEST_COMMAND_CLASS], refused: [] }
|
|
26681
|
+
};
|
|
26682
|
+
}
|
|
26683
|
+
const matched = matchedMandatoryGlobs(paths, mandatory);
|
|
26684
|
+
const testCommandsAllowed = matched.length > 0;
|
|
26685
|
+
return {
|
|
26686
|
+
configuredMandatoryCount,
|
|
26687
|
+
matchedMandatoryGlobs: matched,
|
|
26688
|
+
matchedMandatoryCount: matched.length,
|
|
26689
|
+
testCommandsAllowed,
|
|
26690
|
+
reasonId: testCommandsAllowed ? null : "test-command-outside-mandatory-zone",
|
|
26691
|
+
commandClasses: {
|
|
26692
|
+
allowed: testCommandsAllowed ? [TEST_COMMAND_CLASS] : [],
|
|
26693
|
+
refused: testCommandsAllowed ? [] : [TEST_COMMAND_CLASS]
|
|
26694
|
+
}
|
|
26695
|
+
};
|
|
26696
|
+
}
|
|
26697
|
+
|
|
26698
|
+
// src/test-policy-core.ts
|
|
26537
26699
|
var POLICY_FILE = "test-policy.json";
|
|
26538
26700
|
var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
26539
26701
|
var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
@@ -26579,7 +26741,7 @@ function translate(glob) {
|
|
|
26579
26741
|
}
|
|
26580
26742
|
return out;
|
|
26581
26743
|
}
|
|
26582
|
-
function
|
|
26744
|
+
function globToRegExp2(glob) {
|
|
26583
26745
|
return new RegExp(`^${translate(glob)}$`);
|
|
26584
26746
|
}
|
|
26585
26747
|
function isTestPath(path2) {
|
|
@@ -26813,7 +26975,7 @@ function isMeaningfulChange(path2, before, after) {
|
|
|
26813
26975
|
return !a.every((t, k) => t.text === b[k].text && t.nl === b[k].nl);
|
|
26814
26976
|
}
|
|
26815
26977
|
function annotateChangeMeaning(changed, policy, read) {
|
|
26816
|
-
const matchers = (policy.mandatory ?? []).map((m) =>
|
|
26978
|
+
const matchers = (policy.mandatory ?? []).map((m) => globToRegExp2(m.glob));
|
|
26817
26979
|
return changed.map((file) => {
|
|
26818
26980
|
if (file.status !== "M" || !SUPPORTED_SOURCE.test(file.path)) return file;
|
|
26819
26981
|
if (!matchers.some((re) => re.test(file.path)) && !isTestPath(file.path)) return file;
|
|
@@ -26851,7 +27013,7 @@ function removedPaths2(changed) {
|
|
|
26851
27013
|
);
|
|
26852
27014
|
}
|
|
26853
27015
|
function classify(changed, policy, present = () => false) {
|
|
26854
|
-
const matchers = (policy.mandatory ?? []).map((m) => ({ ...m, re:
|
|
27016
|
+
const matchers = (policy.mandatory ?? []).map((m) => ({ ...m, re: globToRegExp2(m.glob) }));
|
|
26855
27017
|
const mandatoryHits = changed.filter((f) => matchers.some((m) => m.re.test(f.path)));
|
|
26856
27018
|
const testChanges = changed.filter((f) => isTestPath(f.path));
|
|
26857
27019
|
const addedTests = testChanges.filter((f) => f.status === "A");
|
|
@@ -27101,7 +27263,23 @@ function runTestPolicy(root, deps = {}) {
|
|
|
27101
27263
|
};
|
|
27102
27264
|
const blocking = sift([...refusal ? [refusal] : [], ...lookup.refusals, ...staleFindings]);
|
|
27103
27265
|
const findings = blocking.length > 0 ? blocking : sift(evaluate(changed, policy, present));
|
|
27104
|
-
const
|
|
27266
|
+
const commandPolicy = evaluateTestCommandPolicy({
|
|
27267
|
+
paths: changed.map((f) => f.path),
|
|
27268
|
+
mandatory: policy.mandatory,
|
|
27269
|
+
regulated: policy.declared !== false
|
|
27270
|
+
});
|
|
27271
|
+
const result = {
|
|
27272
|
+
ok: findings.length === 0,
|
|
27273
|
+
findings,
|
|
27274
|
+
changedCount: changed.length,
|
|
27275
|
+
base,
|
|
27276
|
+
...counts,
|
|
27277
|
+
matchedMandatoryGlobs: commandPolicy.matchedMandatoryGlobs,
|
|
27278
|
+
matchedMandatoryCount: commandPolicy.matchedMandatoryCount,
|
|
27279
|
+
testCommandsAllowed: commandPolicy.testCommandsAllowed,
|
|
27280
|
+
testCommandReasonId: commandPolicy.reasonId,
|
|
27281
|
+
commandClasses: commandPolicy.commandClasses
|
|
27282
|
+
};
|
|
27105
27283
|
if (override) {
|
|
27106
27284
|
result.overriddenBy = override;
|
|
27107
27285
|
result.waived = waived;
|
|
@@ -34448,15 +34626,68 @@ function formatExplainLoop(playbook) {
|
|
|
34448
34626
|
}
|
|
34449
34627
|
return lines.join("\n");
|
|
34450
34628
|
}
|
|
34451
|
-
function
|
|
34452
|
-
|
|
34629
|
+
function catalogCommandPaths(manifest) {
|
|
34630
|
+
const acc = [];
|
|
34631
|
+
const walk2 = (command) => {
|
|
34632
|
+
if (command.path) acc.push(command.path);
|
|
34633
|
+
for (const child2 of command.subcommands) walk2(child2);
|
|
34634
|
+
};
|
|
34635
|
+
walk2(manifest.tree);
|
|
34636
|
+
return acc;
|
|
34637
|
+
}
|
|
34638
|
+
function nearestExplainTargets(query, paths, limit = 5) {
|
|
34639
|
+
const all = [...paths];
|
|
34640
|
+
const leafOf = (p) => p.slice(p.lastIndexOf(" ") + 1);
|
|
34641
|
+
const leaf = leafOf(query);
|
|
34642
|
+
const exactLeaf = all.filter((p) => p !== query && leafOf(p) === leaf).sort();
|
|
34643
|
+
if (exactLeaf.length) return exactLeaf.slice(0, limit);
|
|
34644
|
+
const out = [];
|
|
34645
|
+
const nearPath = didYouMean(query, all);
|
|
34646
|
+
if (nearPath) out.push(nearPath);
|
|
34647
|
+
const nearLeaf = didYouMean(leaf, new Set(all.map(leafOf)));
|
|
34648
|
+
if (nearLeaf) {
|
|
34649
|
+
for (const p of all.filter((candidate2) => leafOf(candidate2) === nearLeaf).sort()) {
|
|
34650
|
+
if (!out.includes(p)) out.push(p);
|
|
34651
|
+
if (out.length >= limit) break;
|
|
34652
|
+
}
|
|
34653
|
+
}
|
|
34654
|
+
return out.slice(0, limit);
|
|
34655
|
+
}
|
|
34656
|
+
function explainCommandManifest(manifest, command, opts = {}) {
|
|
34657
|
+
const base = {
|
|
34453
34658
|
schema_version: 1,
|
|
34454
34659
|
scope: "command",
|
|
34455
34660
|
name: manifest.name,
|
|
34456
|
-
...manifest.version ? { version: manifest.version } : {}
|
|
34661
|
+
...manifest.version ? { version: manifest.version } : {}
|
|
34662
|
+
};
|
|
34663
|
+
if (!command.subcommands.length) {
|
|
34664
|
+
return {
|
|
34665
|
+
...base,
|
|
34666
|
+
command: { ...command, subcommands: [] }
|
|
34667
|
+
};
|
|
34668
|
+
}
|
|
34669
|
+
if (opts.recursive) {
|
|
34670
|
+
return {
|
|
34671
|
+
...base,
|
|
34672
|
+
command: {
|
|
34673
|
+
...command,
|
|
34674
|
+
subcommands: command.subcommands.map((child2) => ({ ...child2, subcommands: [] }))
|
|
34675
|
+
}
|
|
34676
|
+
};
|
|
34677
|
+
}
|
|
34678
|
+
return {
|
|
34679
|
+
...base,
|
|
34457
34680
|
command: {
|
|
34458
34681
|
...command,
|
|
34459
|
-
subcommands:
|
|
34682
|
+
subcommands: []
|
|
34683
|
+
},
|
|
34684
|
+
children: command.subcommands.map((child2) => ({
|
|
34685
|
+
path: child2.path,
|
|
34686
|
+
...child2.description ? { summary: child2.description } : {},
|
|
34687
|
+
detail: `mmi-cli explain ${child2.path} --json`
|
|
34688
|
+
})),
|
|
34689
|
+
next: {
|
|
34690
|
+
recursive: `mmi-cli explain ${command.path} --json --recursive`
|
|
34460
34691
|
}
|
|
34461
34692
|
};
|
|
34462
34693
|
}
|
|
@@ -34472,7 +34703,7 @@ function findCommandInManifest(manifest, commandPath3) {
|
|
|
34472
34703
|
return visit(manifest.tree);
|
|
34473
34704
|
}
|
|
34474
34705
|
function registerExplainCommand(program3) {
|
|
34475
|
-
program3.command("explain").description("print a command's purpose, flags, and examples from the live schema \u2014 one grounding call replaces trial-and-error").argument("[command...]", 'the command path to explain (e.g. "issue create")').addOption(new Option("--loop <name>", "print the canonical command sequence: agent | start-work | ship-pr | hotfix").choices(Object.keys(LOOP_PLAYBOOKS))).option("--json", "machine-readable focused command, route, or loop detail").action((commandArgs, opts) => {
|
|
34706
|
+
program3.command("explain").description("print a command's purpose, flags, and examples from the live schema \u2014 one grounding call replaces trial-and-error").argument("[command...]", 'the command path to explain (e.g. "issue create")').addOption(new Option("--loop <name>", "print the canonical command sequence: agent | start-work | ship-pr | hotfix").choices(Object.keys(LOOP_PLAYBOOKS))).option("--json", "machine-readable focused command, route, or loop detail").option("--recursive", "include full schemas for immediate children (default: compact child index)").option("--full", "alias for --recursive").action((commandArgs, opts) => {
|
|
34476
34707
|
if (opts.loop) {
|
|
34477
34708
|
if (!LOOP_PLAYBOOKS[opts.loop]) {
|
|
34478
34709
|
const valid = Object.keys(LOOP_PLAYBOOKS).join(", ");
|
|
@@ -34490,10 +34721,19 @@ function registerExplainCommand(program3) {
|
|
|
34490
34721
|
const commandPath3 = commandArgs.join(" ");
|
|
34491
34722
|
const command = findCommandInManifest(manifest, commandPath3);
|
|
34492
34723
|
if (!command) {
|
|
34493
|
-
|
|
34724
|
+
const nearest = nearestExplainTargets(commandPath3, catalogCommandPaths(manifest));
|
|
34725
|
+
fail(`explain: unknown command "${commandPath3}"`, {
|
|
34726
|
+
code: ERROR_CODES.ERR_NOT_FOUND,
|
|
34727
|
+
...nearest.length ? {
|
|
34728
|
+
expected: nearest,
|
|
34729
|
+
did_you_mean: nearest[0],
|
|
34730
|
+
corrected_command: `mmi-cli explain ${nearest[0]} --json`
|
|
34731
|
+
} : {}
|
|
34732
|
+
});
|
|
34494
34733
|
return;
|
|
34495
34734
|
}
|
|
34496
|
-
|
|
34735
|
+
const recursive = Boolean(opts.recursive || opts.full);
|
|
34736
|
+
console.log(opts.json ? JSON.stringify(explainCommandManifest(manifest, command, { recursive }), null, 2) : command.subcommands.length ? formatExplainGroup(command, manifest.name) : formatExplainCommand(command, manifest.name));
|
|
34497
34737
|
});
|
|
34498
34738
|
}
|
|
34499
34739
|
|
|
@@ -35504,6 +35744,7 @@ var surfaces_default = {
|
|
|
35504
35744
|
targetPath: "packages/claude-plugin/scripts",
|
|
35505
35745
|
include: [
|
|
35506
35746
|
"pretooluse-shell-gates.mjs",
|
|
35747
|
+
"test-command-policy-core.mjs",
|
|
35507
35748
|
"vault-edit-gate.mjs",
|
|
35508
35749
|
"deny-gate-crash.mjs",
|
|
35509
35750
|
"secret-echo-lint.mjs",
|
|
@@ -35630,6 +35871,7 @@ var surfaces_default = {
|
|
|
35630
35871
|
targetPath: "packages/codex-plugin/scripts",
|
|
35631
35872
|
include: [
|
|
35632
35873
|
"pretooluse-shell-gates.mjs",
|
|
35874
|
+
"test-command-policy-core.mjs",
|
|
35633
35875
|
"vault-edit-gate.mjs",
|
|
35634
35876
|
"deny-gate-crash.mjs",
|
|
35635
35877
|
"secret-echo-lint.mjs",
|
|
@@ -35748,6 +35990,7 @@ var surfaces_default = {
|
|
|
35748
35990
|
targetPath: "packages/kimi-plugin/scripts",
|
|
35749
35991
|
include: [
|
|
35750
35992
|
"pretooluse-shell-gates.mjs",
|
|
35993
|
+
"test-command-policy-core.mjs",
|
|
35751
35994
|
"vault-edit-gate.mjs",
|
|
35752
35995
|
"deny-gate-crash.mjs",
|
|
35753
35996
|
"secret-echo-lint.mjs",
|
|
@@ -35874,6 +36117,7 @@ var surfaces_default = {
|
|
|
35874
36117
|
targetPath: "packages/cursor-plugin/scripts",
|
|
35875
36118
|
include: [
|
|
35876
36119
|
"pretooluse-shell-gates.mjs",
|
|
36120
|
+
"test-command-policy-core.mjs",
|
|
35877
36121
|
"vault-edit-gate.mjs",
|
|
35878
36122
|
"deny-gate-crash.mjs",
|
|
35879
36123
|
"secret-echo-lint.mjs",
|
|
@@ -35996,6 +36240,7 @@ var surfaces_default = {
|
|
|
35996
36240
|
targetPath: ".kilo-plugin/scripts",
|
|
35997
36241
|
include: [
|
|
35998
36242
|
"pretooluse-shell-gates.mjs",
|
|
36243
|
+
"test-command-policy-core.mjs",
|
|
35999
36244
|
"vault-edit-gate.mjs",
|
|
36000
36245
|
"deny-gate-crash.mjs",
|
|
36001
36246
|
"secret-echo-lint.mjs",
|
|
@@ -36105,6 +36350,7 @@ var surfaces_default = {
|
|
|
36105
36350
|
targetPath: ".pi-plugin/scripts",
|
|
36106
36351
|
include: [
|
|
36107
36352
|
"pretooluse-shell-gates.mjs",
|
|
36353
|
+
"test-command-policy-core.mjs",
|
|
36108
36354
|
"vault-edit-gate.mjs",
|
|
36109
36355
|
"deny-gate-crash.mjs",
|
|
36110
36356
|
"secret-echo-lint.mjs",
|
|
@@ -36204,6 +36450,7 @@ var surfaces_default = {
|
|
|
36204
36450
|
targetPath: "packages/hermes-plugin/scripts",
|
|
36205
36451
|
include: [
|
|
36206
36452
|
"pretooluse-shell-gates.mjs",
|
|
36453
|
+
"test-command-policy-core.mjs",
|
|
36207
36454
|
"vault-edit-gate.mjs",
|
|
36208
36455
|
"deny-gate-crash.mjs",
|
|
36209
36456
|
"secret-echo-lint.mjs",
|
|
@@ -38932,13 +39179,28 @@ function positionalTargetForm(cmd, opts = {}) {
|
|
|
38932
39179
|
if (!first) return void 0;
|
|
38933
39180
|
return formatPositionalTarget(canonicalPathFor(commandPath2(cmd)) ?? commandPath2(cmd), first.name(), opts);
|
|
38934
39181
|
}
|
|
39182
|
+
function unknownCommandCandidates(parent, allPaths) {
|
|
39183
|
+
if (!parent) return [...allPaths];
|
|
39184
|
+
const scoped = parent.commands.length ? parent.commands.filter((child2) => commandMetadata(child2)?.category !== "internal").map(commandPath2) : [];
|
|
39185
|
+
const house = houseForPath(commandPath2(parent));
|
|
39186
|
+
const sameHouse = house ? allPaths.filter((p) => houseForPath(p) === house) : [...allPaths];
|
|
39187
|
+
const seen = /* @__PURE__ */ new Set();
|
|
39188
|
+
const out = [];
|
|
39189
|
+
for (const p of [...scoped, ...sameHouse]) {
|
|
39190
|
+
if (seen.has(p)) continue;
|
|
39191
|
+
seen.add(p);
|
|
39192
|
+
out.push(p);
|
|
39193
|
+
}
|
|
39194
|
+
return out;
|
|
39195
|
+
}
|
|
38935
39196
|
function resolveParseHint() {
|
|
38936
39197
|
if (lastParseErrorKind === "unknown-command") {
|
|
38937
39198
|
const parent = resolveCommandFromArgv(program2, process.argv.slice(2));
|
|
38938
|
-
const candidates = parent
|
|
39199
|
+
const candidates = unknownCommandCandidates(parent, allCommandPaths());
|
|
38939
39200
|
const path3 = lastUnknownCommand ? suggestCommandPath(lastUnknownCommand, candidates) : void 0;
|
|
38940
39201
|
const canonical = path3 ? canonicalPathFor(path3) ?? path3 : void 0;
|
|
38941
|
-
|
|
39202
|
+
if (canonical) return `(did you mean \`mmi-cli ${canonical}\`? ${DISCOVERY_HINT})`;
|
|
39203
|
+
return parent ? `(${DISCOVERY_HINT})` : STALE_HINT;
|
|
38942
39204
|
}
|
|
38943
39205
|
if (lastParseErrorKind !== "bad-arguments") return STALE_HINT;
|
|
38944
39206
|
const cmd = resolveCommandFromArgv(program2, process.argv.slice(2));
|
|
@@ -39474,7 +39736,15 @@ repoIndex.command("gc").description("remove v4 cloud authority material for repo
|
|
|
39474
39736
|
consoleIo.log(JSON.stringify(res, null, 2));
|
|
39475
39737
|
return;
|
|
39476
39738
|
}
|
|
39477
|
-
|
|
39739
|
+
let artifactsRemoved = 0;
|
|
39740
|
+
let artifactsKept = 0;
|
|
39741
|
+
for (const receipt of Object.values(res.v4.repos)) {
|
|
39742
|
+
artifactsRemoved += receipt.removed.length;
|
|
39743
|
+
artifactsKept += receipt.kept;
|
|
39744
|
+
}
|
|
39745
|
+
console.log(
|
|
39746
|
+
`repo-index: gc tombstoned ${res.removed.length} orphan authorit${res.removed.length === 1 ? "y" : "ies"}, removed ${artifactsRemoved} artifact(s); kept ${res.kept} authorit${res.kept === 1 ? "y" : "ies"}, ${artifactsKept} artifact(s)`
|
|
39747
|
+
);
|
|
39478
39748
|
} catch (e) {
|
|
39479
39749
|
return await failGraceful(e.message);
|
|
39480
39750
|
}
|
|
@@ -39484,6 +39754,10 @@ repoIndex.command("sync-estate").description("Hub indexer: publish a pushed comm
|
|
|
39484
39754
|
const cfg = await loadConfig();
|
|
39485
39755
|
const gh = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || "";
|
|
39486
39756
|
if (!gh) await failGraceful("sync-estate needs GH_TOKEN or GITHUB_TOKEN with contents:read on target repos");
|
|
39757
|
+
if (!o.json) {
|
|
39758
|
+
console.log(`repo-index: pipeline provenance ${CURRENT_REPO_INDEX_PROVENANCE_TOKEN} \u2014 delta is the normal path${o.plan ? " (plan only: nothing was cloned, embedded or published)" : ""}`);
|
|
39759
|
+
}
|
|
39760
|
+
const streamedWarnings = /* @__PURE__ */ new Set();
|
|
39487
39761
|
const res = await syncEstateRepoIndex({
|
|
39488
39762
|
deps: registryClientDeps(cfg),
|
|
39489
39763
|
repo: o.repo,
|
|
@@ -39491,26 +39765,30 @@ repoIndex.command("sync-estate").description("Hub indexer: publish a pushed comm
|
|
|
39491
39765
|
fullRebuild: o.fullRebuild,
|
|
39492
39766
|
skipRepos: o.skipRepo,
|
|
39493
39767
|
plan: Boolean(o.plan),
|
|
39494
|
-
githubToken: gh
|
|
39768
|
+
githubToken: gh,
|
|
39769
|
+
onClassify: o.json ? void 0 : ({ row, warning }) => {
|
|
39770
|
+
const at = row.targetCommit ? ` target=${row.targetCommit.slice(0, 12)}` : "";
|
|
39771
|
+
const active = row.activeCommit ? ` active=${row.activeCommit.slice(0, 12)}` : "";
|
|
39772
|
+
console.log(`repo-index: ${row.repo} ${row.reason} \u2192 ${row.action}${active}${at}`);
|
|
39773
|
+
if (warning) {
|
|
39774
|
+
streamedWarnings.add(warning);
|
|
39775
|
+
console.error(`repo-index: WARN ${warning}`);
|
|
39776
|
+
}
|
|
39777
|
+
}
|
|
39495
39778
|
});
|
|
39496
39779
|
if (o.json) {
|
|
39497
39780
|
consoleIo.log(JSON.stringify(res, null, 2));
|
|
39498
39781
|
if (!res.ok) process.exitCode = 1;
|
|
39499
39782
|
return;
|
|
39500
39783
|
}
|
|
39501
|
-
console.log(`repo-index: pipeline provenance ${res.provenanceToken} \u2014 delta is the normal path${o.plan ? " (plan only: nothing was cloned, embedded or published)" : ""}`);
|
|
39502
|
-
for (const row of res.drift) {
|
|
39503
|
-
if (row.reason === "healthy") continue;
|
|
39504
|
-
const at = row.targetCommit ? ` target=${row.targetCommit.slice(0, 12)}` : "";
|
|
39505
|
-
const active = row.activeCommit ? ` active=${row.activeCommit.slice(0, 12)}` : "";
|
|
39506
|
-
console.log(`repo-index: ${row.repo} ${row.reason} \u2192 ${row.action}${active}${at}`);
|
|
39507
|
-
}
|
|
39508
39784
|
for (const p of res.published) {
|
|
39509
39785
|
const gap = p.embGap ?? Math.max(0, p.fileCount - (p.embCount ?? 0));
|
|
39510
39786
|
console.log(`repo-index: published v4 ${p.repo} \u2014 ${p.fileCount} chunks emb=${p.embCount ?? 0}/${p.fileCount} gap=${gap} graph=${p.graphEdges ?? "unavailable"}`);
|
|
39511
39787
|
if (p.metrics) console.log(`repo-index: ${formatV4BuildMetrics(p.repo, p.metrics)}`);
|
|
39512
39788
|
}
|
|
39513
|
-
for (const warning of res.skipped)
|
|
39789
|
+
for (const warning of res.skipped) {
|
|
39790
|
+
if (!streamedWarnings.has(warning)) console.error(`repo-index: WARN ${warning}`);
|
|
39791
|
+
}
|
|
39514
39792
|
if (res.needsFullRebuild.length) {
|
|
39515
39793
|
console.error(`repo-index: ${res.needsFullRebuild.length} repo(s) need an explicit tokened migration: ${res.needsFullRebuild.join(", ")}`);
|
|
39516
39794
|
}
|
|
@@ -39589,7 +39867,7 @@ spawnCmd.command("policy").description("enforce the windowsHide contract across
|
|
|
39589
39867
|
}
|
|
39590
39868
|
});
|
|
39591
39869
|
var tests = program2.command("tests").description("a repo's test-policy.json \u2014 the opt-in test contract and its enforcement");
|
|
39592
|
-
tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "machine-readable result: { ok, base, changedCount, findings[] }").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").action(async (o) => {
|
|
39870
|
+
tests.command("policy").description("enforce this repo's test-policy.json against the diff: a mandatory-zone change must carry a test, an unrequested new test file is refused, a `protected` test file may not be deleted or renamed away, and a `protected` entry naming a missing file is refused. Override any of them with a `Test-Policy-Override: <reason>` commit trailer (#3605)").option("--json", "machine-readable result: { ok, base, changedCount, mandatoryCount, matchedMandatoryCount, matchedMandatoryGlobs, testCommandsAllowed, commandClasses, findings[] }").option("--base <ref>", "comparison base (default: TEST_POLICY_BASE, then origin/development, then origin/main)").action(async (o) => {
|
|
39593
39871
|
try {
|
|
39594
39872
|
const root = await repoRoot();
|
|
39595
39873
|
const result = runTestPolicy(root, { base: o.base });
|
|
@@ -39605,8 +39883,9 @@ tests.command("policy").description("enforce this repo's test-policy.json agains
|
|
|
39605
39883
|
return;
|
|
39606
39884
|
}
|
|
39607
39885
|
if (result.ok) {
|
|
39886
|
+
const commandVerdict = result.testCommandsAllowed ? "test commands: allowed" : `test commands: refused [${result.testCommandReasonId}]`;
|
|
39608
39887
|
console.log(
|
|
39609
|
-
`tests policy: OK (${result.changedCount} changed file(s); ${result.mandatoryCount} mandatory glob(s), ${result.protectedCount} protected file(s)).`
|
|
39888
|
+
`tests policy: OK (${result.changedCount} changed file(s); ${result.matchedMandatoryCount} of ${result.mandatoryCount} mandatory glob(s) matched, ${result.protectedCount} protected file(s); ${commandVerdict}).`
|
|
39610
39889
|
);
|
|
39611
39890
|
return;
|
|
39612
39891
|
}
|
|
@@ -42085,5 +42364,6 @@ program2.parseAsync(process.argv).then(() => finishCliRun()).catch((e) => failGr
|
|
|
42085
42364
|
positionalTargetForm,
|
|
42086
42365
|
registryClientDeps,
|
|
42087
42366
|
repoSlug,
|
|
42088
|
-
suggestCommandPath
|
|
42367
|
+
suggestCommandPath,
|
|
42368
|
+
unknownCommandCandidates
|
|
42089
42369
|
});
|
package/package.json
CHANGED