@unbrained/pm-cli 2026.9.5 → 2026.9.7
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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +39 -3
- package/dist/cli/main.js +10 -8
- package/dist/cli/register-operations.js +13 -8
- package/dist/cli-bundle/bundle-manifest.json +150 -158
- package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-WWAEGW4V.js → chunk-BAX2BYUW.js} +66 -66
- package/dist/cli-bundle/chunks/{chunk-IBYREGSP.js → chunk-CKOL5U7J.js} +51 -51
- package/dist/cli-bundle/chunks/{chunk-ZRAQS3UA.js → chunk-JT6XF6GE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-HUAQITVW.js → chunk-JX4DH4WC.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-QPZHQY2O.js → chunk-NPN5I67J.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-66VPKFP2.js → chunk-OF76PSDQ.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +232 -0
- package/dist/cli-bundle/chunks/{chunk-3HBDTJRK.js → chunk-RWWBOWJ5.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +40 -0
- package/dist/cli-bundle/chunks/{chunk-SF6SM6U5.js → chunk-WI2AYPA7.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-AYKGODWT.js → register-list-query-5JL52D33.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-YZYG53SQ.js → register-mutation-ZPG7KMVP.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-I5W3KMGB.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-UJCRVGBG.js → register-setup-H4SVAVX7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-QL66QNWG.js → chunk-3BZEOXLT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-WOCIPMW7.js → chunk-EZR3GHFE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +56 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3ASU6WGI.js → chunk-LIJIA4TY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-H5FOGAVD.js → chunk-M6PBRFSH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-B2TTQGFG.js → chunk-NTPY5GSO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +177 -0
- package/dist/cli-bundle/focused-chunks/{chunk-YEF5PQQ2.js → chunk-PEFABF7E.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-KWWCBWFO.js → chunk-QTVCLMSZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4OSHLNUE.js → chunk-QTZRBUYA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +10 -0
- package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +2 -0
- package/dist/cli-bundle/main.js +20 -20
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +37 -37
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +42 -42
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +9 -9
- package/dist/core/extensions/module-graph-snapshot.js +5 -4
- package/dist/core/fs/host-environment-errors.d.ts +27 -0
- package/dist/core/fs/host-environment-errors.js +142 -0
- package/dist/core/output/mutation-projection.js +12 -5
- package/dist/core/store/item-metadata-query-index.js +13 -10
- package/dist/core/store/item-metadata-read-work.d.ts +19 -0
- package/dist/core/store/item-metadata-read-work.js +44 -0
- package/dist/core/store/item-store.js +6 -2
- package/dist/core/validate/fix-planning.d.ts +1 -1
- package/dist/core/validate/fix-planning.js +2 -2
- package/dist/core/validate/missing-link-owners.d.ts +1 -1
- package/dist/core/validate/missing-link-owners.js +5 -3
- package/dist/core/validate/stale-file-classification.d.ts +6 -4
- package/dist/core/validate/stale-file-classification.js +20 -5
- package/dist/mcp/server.js +12 -5
- package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
- package/dist/sdk/cli-contracts/flag-contracts.js +7 -5
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +4 -3
- package/dist/sdk/cli-contracts/grammar-contracts.js +11 -2
- package/dist/sdk/cli-contracts/runtime-contracts.js +5 -2
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +254 -5
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +52 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +18 -6
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +17 -5
- package/dist/sdk/context/usage-ledger.d.ts +41 -0
- package/dist/sdk/context/usage-ledger.js +186 -0
- package/dist/sdk/context-usage.d.ts +18 -9
- package/dist/sdk/context-usage.js +37 -112
- package/dist/sdk/dependency-provenance.d.ts +7 -0
- package/dist/sdk/dependency-provenance.js +14 -4
- package/dist/sdk/duplicates.d.ts +2 -0
- package/dist/sdk/duplicates.js +3 -2
- package/dist/sdk/environment/host-environment-errors.d.ts +5 -27
- package/dist/sdk/environment/host-environment-errors.js +4 -137
- package/dist/sdk/extension/install-runtime.js +9 -6
- package/dist/sdk/extension/install-snapshot.js +7 -6
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +8 -8
- package/dist/sdk/governance/assurance-action.d.ts +3 -2
- package/dist/sdk/governance/assurance-action.js +23 -11
- package/dist/sdk/governance/assurance-runtime.d.ts +2 -0
- package/dist/sdk/governance/assurance-runtime.js +6 -3
- package/dist/sdk/governance/defect-recurrence-coverage.d.ts +93 -0
- package/dist/sdk/governance/defect-recurrence-coverage.js +189 -0
- package/dist/sdk/governance/defect-recurrence-graph.d.ts +33 -0
- package/dist/sdk/governance/defect-recurrence-graph.js +121 -0
- package/dist/sdk/governance/defect-recurrence.d.ts +8 -0
- package/dist/sdk/governance/defect-recurrence.js +118 -17
- package/dist/sdk/governance/health.d.ts +17 -2
- package/dist/sdk/governance/health.js +31 -10
- package/dist/sdk/governance/linked-file-report.d.ts +41 -0
- package/dist/sdk/governance/linked-file-report.js +72 -0
- package/dist/sdk/governance/validate.d.ts +5 -2
- package/dist/sdk/governance/validate.js +21 -37
- package/dist/sdk/governance.d.ts +2 -0
- package/dist/sdk/governance.js +4 -2
- package/dist/sdk/history-repair.d.ts +7 -0
- package/dist/sdk/history-repair.js +48 -13
- package/dist/sdk/lifecycle/close.d.ts +8 -0
- package/dist/sdk/lifecycle/close.js +16 -8
- package/dist/sdk/lifecycle/create.js +9 -12
- package/dist/sdk/lifecycle/update.js +12 -12
- package/dist/sdk/lifecycle-policy.d.ts +3 -0
- package/dist/sdk/lifecycle-policy.js +2 -2
- package/dist/sdk/merge/abandoned-receipts.d.ts +15 -0
- package/dist/sdk/merge/abandoned-receipts.js +47 -0
- package/dist/sdk/merge/driver.js +4 -2
- package/dist/sdk/merge/index.d.ts +1 -0
- package/dist/sdk/merge/index.js +2 -2
- package/dist/sdk/merge/receipt-operation.d.ts +15 -0
- package/dist/sdk/merge/receipt-operation.js +97 -0
- package/dist/sdk/merge/receipt-schema.d.ts +20 -0
- package/dist/sdk/merge/receipt-schema.js +398 -0
- package/dist/sdk/merge/receipts.d.ts +16 -7
- package/dist/sdk/merge/receipts.js +54 -340
- package/dist/sdk/merge/reconcile.d.ts +2 -0
- package/dist/sdk/merge/reconcile.js +11 -4
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/duplicate-candidates.d.ts +7 -0
- package/dist/sdk/query/duplicate-candidates.js +71 -0
- package/dist/sdk/query/get.js +7 -7
- package/dist/sdk/query.d.ts +2 -0
- package/dist/sdk/query.js +4 -2
- package/dist/sdk/read-output-session.js +5 -3
- package/dist/sdk/runtime.js +4 -2
- package/dist/sdk/similarity.d.ts +24 -3
- package/dist/sdk/similarity.js +50 -55
- package/docs/AGENT_GUIDE.md +23 -2
- package/docs/BOUNDED_CONTEXT_READS.md +185 -0
- package/docs/CLOSE_EVIDENCE_RECOVERY.md +35 -0
- package/docs/COMMANDS.md +30 -8
- package/docs/CONTEXT_RELEVANCE.md +16 -4
- package/docs/DEFECT_RECURRENCE.md +80 -6
- package/docs/EXTENSIONS.md +18 -19
- package/docs/MERGE_SAFETY.md +50 -0
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +66 -0
- package/docs/PR_REVIEW_LOOP.md +18 -3
- package/docs/README.md +18 -1
- package/docs/RELEASING.md +7 -2
- package/docs/SDK_LIFECYCLE.md +27 -0
- package/docs/SDK_RUNTIME_BOUNDARIES.md +11 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +1 -1
- package/marketplace.json +2 -2
- package/package.json +6 -3
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/README.md +10 -1
- package/packages/pm-governance-audit/extensions/governance-audit/dedupe-audit.ts +50 -65
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +2 -2
- package/packages/pm-governance-audit/extensions/governance-audit/sdk.ts +1 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/dist/cli-bundle/chunks/chunk-LUI4E32I.js +0 -231
- package/dist/cli-bundle/chunks/chunk-SVK5Y64D.js +0 -40
- package/dist/cli-bundle/chunks/chunk-V5GBD5KV.js +0 -9
- package/dist/cli-bundle/chunks/register-operations-KFSCC7QV.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-24IG6ONG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3ITLIBKS.js +0 -56
- package/dist/cli-bundle/focused-chunks/chunk-3NQD5YDG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-65N6JHAN.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-GUBM3RGY.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-JX3RCVCX.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-MV752SUC.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-PKIPMCFS.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-RJMR2JIF.js +0 -9
- package/dist/cli-bundle/focused-chunks/chunk-WIUPWIZR.js +0 -177
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm health command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cee8abad-51d2-5051-9cb8-81447bf2fd50")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { assertInitializedTracker } from "../environment/tracker-preflight.js";
|
|
@@ -1056,10 +1056,12 @@ function summarizeHealthCheckDetails(check, limit) {
|
|
|
1056
1056
|
return summarize ? summarize(check.details, limit) : check.details;
|
|
1057
1057
|
}
|
|
1058
1058
|
/* c8 ignore stop */
|
|
1059
|
+
/** Bound diagnostic detail and warnings while retaining every blocking cause and the authoritative verdict. */
|
|
1059
1060
|
function applyBriefHealthProjection(result) {
|
|
1060
1061
|
const warningsSummary = summarizeStringList(result.warnings, BRIEF_HEALTH_DETAIL_LIMIT);
|
|
1061
1062
|
return {
|
|
1062
1063
|
ok: result.ok,
|
|
1064
|
+
...(result.verdict ? { verdict: result.verdict } : {}),
|
|
1063
1065
|
checks: result.checks.map((check) => ({
|
|
1064
1066
|
name: check.name,
|
|
1065
1067
|
status: check.status,
|
|
@@ -1082,6 +1084,7 @@ function applyBriefHealthProjection(result) {
|
|
|
1082
1084
|
function isSkippedHealthCheck(check) {
|
|
1083
1085
|
return check.details.skipped === true;
|
|
1084
1086
|
}
|
|
1087
|
+
/** Emit verdicts for checks that ran, retain blocking causes, and name omitted checks for recovery. */
|
|
1085
1088
|
function applySummaryHealthProjection(result) {
|
|
1086
1089
|
const warningsSummary = summarizeStringList(result.warnings, BRIEF_HEALTH_DETAIL_LIMIT);
|
|
1087
1090
|
const omittedChecks = result.checks
|
|
@@ -1089,6 +1092,7 @@ function applySummaryHealthProjection(result) {
|
|
|
1089
1092
|
.map((check) => check.name);
|
|
1090
1093
|
return {
|
|
1091
1094
|
ok: result.ok,
|
|
1095
|
+
...(result.verdict ? { verdict: result.verdict } : {}),
|
|
1092
1096
|
checks: result.checks
|
|
1093
1097
|
.filter((check) => !isSkippedHealthCheck(check))
|
|
1094
1098
|
.map((check) => ({
|
|
@@ -1974,6 +1978,7 @@ function extractHistoryDriftedCount(historyDriftCheck) {
|
|
|
1974
1978
|
const counts = historyDriftCheck.check.details.counts;
|
|
1975
1979
|
return typeof counts?.drifted === "number" ? counts.drifted : 0;
|
|
1976
1980
|
}
|
|
1981
|
+
/** Associate warning producers with their owning checks so findings inherit the correct remediation and severity. */
|
|
1977
1982
|
function buildHealthRemediationSources(params) {
|
|
1978
1983
|
return {
|
|
1979
1984
|
settings: params.normalizedSettingsReadWarnings,
|
|
@@ -1985,7 +1990,7 @@ function buildHealthRemediationSources(params) {
|
|
|
1985
1990
|
extensions: params.extensionCheck.warnings,
|
|
1986
1991
|
storage: [
|
|
1987
1992
|
...params.historyPolicyWarnings,
|
|
1988
|
-
...params.historySummary.
|
|
1993
|
+
...params.historySummary.warnings,
|
|
1989
1994
|
...params.authorAttributionWarnings,
|
|
1990
1995
|
...params.staleInProgressWarnings,
|
|
1991
1996
|
...params.provenanceWarnings,
|
|
@@ -2064,6 +2069,7 @@ function attachHealthRemediationMaps(params) {
|
|
|
2064
2069
|
}
|
|
2065
2070
|
}
|
|
2066
2071
|
}
|
|
2072
|
+
/** Attribute drift to merge receipts only when read-only history repair proves their exact current snapshot. */
|
|
2067
2073
|
async function correlateMergeReceiptHistoryDriftItems(params) {
|
|
2068
2074
|
if (params.gitWorkspaceRoot === null ||
|
|
2069
2075
|
params.pendingMergeReceipts.length === 0) {
|
|
@@ -2094,15 +2100,15 @@ async function correlateMergeReceiptHistoryDriftItems(params) {
|
|
|
2094
2100
|
if (!receipts || receipts.length === 0)
|
|
2095
2101
|
continue;
|
|
2096
2102
|
try {
|
|
2097
|
-
|
|
2103
|
+
await runHistoryRepair(id, {
|
|
2098
2104
|
dryRun: true,
|
|
2099
2105
|
mergeReceiptProof: {
|
|
2100
2106
|
gitWorkspaceRoot: params.gitWorkspaceRoot,
|
|
2101
2107
|
receipts,
|
|
2102
2108
|
},
|
|
2103
2109
|
}, params.global);
|
|
2104
|
-
|
|
2105
|
-
|
|
2110
|
+
// An unforced proof-bearing preview rejects untrusted evidence before returning.
|
|
2111
|
+
attributed.push(id);
|
|
2106
2112
|
}
|
|
2107
2113
|
catch {
|
|
2108
2114
|
// Fail closed: generic history-repair guidance remains authoritative.
|
|
@@ -2168,6 +2174,8 @@ export async function runHealth(global, options = {}) {
|
|
|
2168
2174
|
const normalizedSettingsReadWarnings = [...new Set(settingsReadWarnings)];
|
|
2169
2175
|
const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
|
|
2170
2176
|
const strictDirectories = options.strictDirectories === true;
|
|
2177
|
+
const strictExit = options.strictExit === true || options.failOnWarn === true;
|
|
2178
|
+
const requireMergeDrivers = options.requireMergeDrivers === true || strictExit;
|
|
2171
2179
|
const refreshPolicy = resolveVectorRefreshPolicy(options);
|
|
2172
2180
|
const directoryState = await scanHealthDirectories(pmRoot, typeRegistry, strictDirectories);
|
|
2173
2181
|
const settingsValueWarnings = validateSettingsValues(settings);
|
|
@@ -2213,13 +2221,13 @@ export async function runHealth(global, options = {}) {
|
|
|
2213
2221
|
const provenanceInvalidValues = provenanceResolverHealth.invalid_values;
|
|
2214
2222
|
const provenanceWarnings = provenanceResolverHealth.warnings;
|
|
2215
2223
|
const locksCheck = await buildLocksCheck(pmRoot);
|
|
2216
|
-
const integrityCheck = skipPolicy.skipIntegrity
|
|
2224
|
+
const integrityCheck = skipPolicy.skipIntegrity && !requireMergeDrivers
|
|
2217
2225
|
? {
|
|
2218
2226
|
...buildSkippedHealthCheck("integrity"),
|
|
2219
2227
|
gitWorkspaceRoot: null,
|
|
2220
2228
|
pendingMergeReceipts: [],
|
|
2221
2229
|
}
|
|
2222
|
-
: await buildIntegrityCheck(pmRoot, typeRegistry.type_to_folder, settings.schema,
|
|
2230
|
+
: await buildIntegrityCheck(pmRoot, typeRegistry.type_to_folder, settings.schema, requireMergeDrivers, items);
|
|
2223
2231
|
const historyDriftCheck = skipPolicy.skipDrift
|
|
2224
2232
|
? buildSkippedHealthCheck("history_drift")
|
|
2225
2233
|
: await buildHistoryDriftCheck({
|
|
@@ -2296,15 +2304,28 @@ export async function runHealth(global, options = {}) {
|
|
|
2296
2304
|
// state (queue backlog, unreachable endpoint, corrupt local state) is advisory:
|
|
2297
2305
|
// it must never flip overall project health to not-ok. Such warnings are still
|
|
2298
2306
|
// surfaced in `warnings` and the telemetry check's own `warn` status.
|
|
2299
|
-
const blockingWarnings = normalizedWarnings.filter((warning) => !isAdvisoryHealthWarning(warning,
|
|
2307
|
+
const blockingWarnings = normalizedWarnings.filter((warning) => !isAdvisoryHealthWarning(warning, requireMergeDrivers));
|
|
2300
2308
|
const findings = buildHealthFindings({
|
|
2301
2309
|
warnings: normalizedWarnings,
|
|
2302
2310
|
checks,
|
|
2303
2311
|
remediationSources,
|
|
2304
|
-
requireMergeDrivers
|
|
2312
|
+
requireMergeDrivers,
|
|
2305
2313
|
});
|
|
2314
|
+
const failingChecks = new Set(findings.filter((finding) => finding.severity === "gate_failing").map((finding) => finding.check));
|
|
2315
|
+
const warningChecks = new Set(findings.map((finding) => finding.check));
|
|
2316
|
+
for (const check of checks) {
|
|
2317
|
+
check.ok = !failingChecks.has(check.name);
|
|
2318
|
+
if (warningChecks.has(check.name))
|
|
2319
|
+
check.status = "warn";
|
|
2320
|
+
}
|
|
2306
2321
|
const result = {
|
|
2307
2322
|
ok: blockingWarnings.length === 0,
|
|
2323
|
+
verdict: {
|
|
2324
|
+
authority: "ok",
|
|
2325
|
+
...(strictExit ? { strict_exit: true } : {}),
|
|
2326
|
+
...(requireMergeDrivers ? { require_merge_drivers: true } : {}),
|
|
2327
|
+
exit_code: strictExit && blockingWarnings.length > 0 ? EXIT_CODE.GENERIC_FAILURE : 0,
|
|
2328
|
+
},
|
|
2308
2329
|
checks,
|
|
2309
2330
|
warnings: normalizedWarnings,
|
|
2310
2331
|
findings,
|
|
@@ -2344,4 +2365,4 @@ export const _testOnlyHealthCommand = {
|
|
|
2344
2365
|
warningCode,
|
|
2345
2366
|
};
|
|
2346
2367
|
//# sourceMappingURL=health.js.map
|
|
2347
|
-
//# debugId=
|
|
2368
|
+
//# debugId=cee8abad-51d2-5051-9cb8-81447bf2fd50
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RuntimeStatusRegistry } from "../../core/schema/runtime-schema.js";
|
|
2
|
+
import { type MissingLinkedPathRow, type OwnerItemMetadata, type StaleLinkOwnerInput } from "../../core/validate/missing-link-owners.js";
|
|
3
|
+
import type { ClassifiedStaleLinkedPath } from "../../core/validate/stale-file-classification.js";
|
|
4
|
+
/** Repair evidence for one path; nested holders use the same ceiling as paths. */
|
|
5
|
+
export interface LinkedFileRepairRow extends MissingLinkedPathRow {
|
|
6
|
+
/** Same-basename possibilities, not verified relocation instructions. */
|
|
7
|
+
candidates: string[];
|
|
8
|
+
/** Whether the classifier withheld additional possible destinations. */
|
|
9
|
+
candidates_truncated: boolean;
|
|
10
|
+
/** Unique holder and field pairs referencing this path before projection. */
|
|
11
|
+
link_count: number;
|
|
12
|
+
/** Whether the bounded holder list omits any link. */
|
|
13
|
+
items_truncated: boolean;
|
|
14
|
+
/** Number of links on nonterminal holders for this path. */
|
|
15
|
+
active_link_count: number;
|
|
16
|
+
}
|
|
17
|
+
/** Full-population counters and a bounded, consistently structured worklist. */
|
|
18
|
+
export interface LinkedFileRepairReport {
|
|
19
|
+
/** Distinct stale path count, also the unprojected worklist row count. */
|
|
20
|
+
missing_linked_path_rows_count: number;
|
|
21
|
+
/** Paths with owners and candidates joined before either is truncated. */
|
|
22
|
+
missing_linked_path_rows: LinkedFileRepairRow[];
|
|
23
|
+
/** Whether any complete path row is omitted. */
|
|
24
|
+
missing_linked_path_rows_truncated: boolean;
|
|
25
|
+
/** Unique path, holder and field triples across every lifecycle state. */
|
|
26
|
+
missing_linked_links_count: number;
|
|
27
|
+
/** Missing links whose holders are actionable under the workspace registry. */
|
|
28
|
+
active_missing_linked_links_count: number;
|
|
29
|
+
/** Missing links on holders with the configured close status. */
|
|
30
|
+
legacy_closed_missing_linked_links_count: number;
|
|
31
|
+
/** Missing links on all terminal holders, including the closed subset. */
|
|
32
|
+
legacy_terminal_missing_linked_links_count: number;
|
|
33
|
+
/** Distinct paths referenced by at least one active holder. */
|
|
34
|
+
active_missing_linked_paths_count: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build an active-first repair worklist with deterministic path/holder sorting. Unknown
|
|
38
|
+
* statuses and absent holder metadata remain actionable. Infinity explicitly
|
|
39
|
+
* restores every path and holder; finite limits cap both dimensions equally.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildLinkedFileRepairReport(links: readonly StaleLinkOwnerInput[], classifications: readonly ClassifiedStaleLinkedPath[], lookup: (id: string) => OwnerItemMetadata | undefined, registry: RuntimeStatusRegistry, limit?: number): LinkedFileRepairReport;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/governance/linked-file-report
|
|
3
|
+
*
|
|
4
|
+
* Joins missing-file evidence with holder lifecycle before projecting a bounded
|
|
5
|
+
* repair worklist. Counts always describe the complete supplied evidence.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d62bc6ec-c345-5196-93b8-280b5484b18a")}catch(e){}}();
|
|
9
|
+
import { normalizeStatusInput } from "../../core/item/status.js";
|
|
10
|
+
import { buildMissingLinkedPathRows, } from "../../core/validate/missing-link-owners.js";
|
|
11
|
+
/**
|
|
12
|
+
* Build an active-first repair worklist with deterministic path/holder sorting. Unknown
|
|
13
|
+
* statuses and absent holder metadata remain actionable. Infinity explicitly
|
|
14
|
+
* restores every path and holder; finite limits cap both dimensions equally.
|
|
15
|
+
*/
|
|
16
|
+
export function buildLinkedFileRepairReport(links, classifications, lookup, registry, limit = 40) {
|
|
17
|
+
const ceiling = limit === Infinity
|
|
18
|
+
? Infinity
|
|
19
|
+
: Number.isFinite(limit)
|
|
20
|
+
? Math.max(0, Math.floor(limit))
|
|
21
|
+
: 40;
|
|
22
|
+
const byPath = new Map(classifications.map((entry) => [entry.path, entry]));
|
|
23
|
+
const report = {
|
|
24
|
+
missing_linked_path_rows_count: 0,
|
|
25
|
+
missing_linked_path_rows: [],
|
|
26
|
+
missing_linked_path_rows_truncated: false,
|
|
27
|
+
missing_linked_links_count: 0,
|
|
28
|
+
active_missing_linked_links_count: 0,
|
|
29
|
+
legacy_closed_missing_linked_links_count: 0,
|
|
30
|
+
legacy_terminal_missing_linked_links_count: 0,
|
|
31
|
+
active_missing_linked_paths_count: 0,
|
|
32
|
+
};
|
|
33
|
+
const rows = buildMissingLinkedPathRows(links, lookup).map((row) => {
|
|
34
|
+
const active = [];
|
|
35
|
+
const terminal = [];
|
|
36
|
+
for (const owner of row.items) {
|
|
37
|
+
const status = normalizeStatusInput(owner.status, registry) ?? owner.status;
|
|
38
|
+
if (registry.terminal_statuses.has(status)) {
|
|
39
|
+
terminal.push(owner);
|
|
40
|
+
if (status === registry.close_status)
|
|
41
|
+
report.legacy_closed_missing_linked_links_count += 1;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
active.push(owner);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
report.missing_linked_links_count += row.items.length;
|
|
48
|
+
report.active_missing_linked_links_count += active.length;
|
|
49
|
+
report.legacy_terminal_missing_linked_links_count += terminal.length;
|
|
50
|
+
if (active.length > 0)
|
|
51
|
+
report.active_missing_linked_paths_count += 1;
|
|
52
|
+
const classification = byPath.get(row.path);
|
|
53
|
+
return {
|
|
54
|
+
...row,
|
|
55
|
+
candidates: classification?.candidates ?? [],
|
|
56
|
+
candidates_truncated: classification?.candidates_truncated ?? false,
|
|
57
|
+
link_count: row.items.length,
|
|
58
|
+
active_link_count: active.length,
|
|
59
|
+
items: [...active, ...terminal].slice(0, ceiling),
|
|
60
|
+
items_truncated: row.items.length > ceiling,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
rows.sort((left, right) => Number(right.active_link_count > 0) -
|
|
64
|
+
Number(left.active_link_count > 0) ||
|
|
65
|
+
left.path.localeCompare(right.path));
|
|
66
|
+
report.missing_linked_path_rows_count = rows.length;
|
|
67
|
+
report.missing_linked_path_rows = rows.slice(0, ceiling);
|
|
68
|
+
report.missing_linked_path_rows_truncated = rows.length > ceiling;
|
|
69
|
+
return report;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=linked-file-report.js.map
|
|
72
|
+
//# debugId=d62bc6ec-c345-5196-93b8-280b5484b18a
|
|
@@ -151,7 +151,9 @@ export interface ValidateCountsResult extends Omit<ValidateResult, "fixes"> {
|
|
|
151
151
|
* Build the counts-only validate projection without mutating the full result.
|
|
152
152
|
* The check envelope and warning codes remain available for gates, while every
|
|
153
153
|
* per-item diagnostic/fix array is removed recursively and scalar counts,
|
|
154
|
-
* totals, statuses, and truncation markers are preserved.
|
|
154
|
+
* totals, statuses, and true truncation markers are preserved. False truncation
|
|
155
|
+
* markers are omitted; this sparse convention does not suppress other false or
|
|
156
|
+
* zero values, and the projection receipt still declares omitted diagnostic rows.
|
|
155
157
|
*/
|
|
156
158
|
export declare function projectValidateCounts(result: ValidateResult): ValidateCountsResult;
|
|
157
159
|
interface ValidateMetadataPolicy {
|
|
@@ -226,7 +228,8 @@ declare function buildLifecycleCheck(items: ItemWithBody[], includeStaleBlockers
|
|
|
226
228
|
warnings: string[];
|
|
227
229
|
terminalParentFixRows: TerminalParentFixRow[];
|
|
228
230
|
};
|
|
229
|
-
|
|
231
|
+
/** Join live filesystem evidence with holder lifecycle, retaining historical rows while warning only on active missing links. */
|
|
232
|
+
declare function buildFilesCheck(items: ItemWithBody[], workspaceRoot: string, pmRoot: string, fileScanMode: ValidateFileScanMode, includePmInternals: boolean, verboseFileLists: boolean, statusRegistry?: RuntimeStatusRegistry): Promise<{
|
|
230
233
|
check: ValidateCheck;
|
|
231
234
|
warnings: string[];
|
|
232
235
|
staleLinkPruneRows: StaleLinkPruneRow[];
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm validate command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="898c4c05-70ab-5ea4-851e-9e224a85afc4")}catch(e){}}();
|
|
8
8
|
import { assertInitializedTracker } from "../environment/tracker-preflight.js";
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import { realpathSync } from "node:fs";
|
|
@@ -18,7 +18,7 @@ import { isFileMissingError } from "../../core/fs/fs-utils.js";
|
|
|
18
18
|
import { normalizeStatusInput } from "../../core/item/status.js";
|
|
19
19
|
import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
20
20
|
import { resolveRuntimeStatusRegistry, } from "../../core/schema/runtime-schema.js";
|
|
21
|
-
import { DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS, DEFAULT_VALIDATE_STALE_BLOCKER_REASON_PATTERNS, EXIT_CODE, PM_DIRNAME, } from "../../core/shared/constants.js";
|
|
21
|
+
import { DEFAULT_VALIDATE_CLOSURE_LIKE_METADATA_FIELD_PATTERNS, DEFAULT_VALIDATE_STALE_BLOCKER_REASON_PATTERNS, EXIT_CODE, PM_DIRNAME, SETTINGS_DEFAULTS, } from "../../core/shared/constants.js";
|
|
22
22
|
import { PmCliError } from "../../core/shared/errors.js";
|
|
23
23
|
import { toNonEmptyStringOrUndefined } from "../../core/shared/primitives.js";
|
|
24
24
|
import { nowIso } from "../../core/shared/time.js";
|
|
@@ -30,11 +30,11 @@ import { findDuplicateIssueCodes, } from "../../core/governance/issue-codes.js";
|
|
|
30
30
|
import { buildMissingByTypeCounts, } from "../../core/validate/missing-by-type.js";
|
|
31
31
|
import { classifyStaleLinkedPaths, summarizeStaleLinkedPathClassifications, } from "../../core/validate/stale-file-classification.js";
|
|
32
32
|
import { isRemoteLinkedArtifactReference } from "../../core/validate/linked-artifact-reference.js";
|
|
33
|
-
import { buildMissingLinkedPathRows, summarizeMissingLinkedPathRows, } from "../../core/validate/missing-link-owners.js";
|
|
34
33
|
import { assertProjectionModeChoice, } from "../output-projection.js";
|
|
35
34
|
import { collectDanglingDependencyReferences } from "../graph/assembly.js";
|
|
36
35
|
import { auditMergeAttributeFence, auditMergeDriverConfiguration, findGitWorkspaceRoot, resolveProjectMergeTypeFolders, } from "../merge/install.js";
|
|
37
36
|
import { inspectMergeReceiptEvidence, partitionMergeReceipts, } from "../merge/receipts.js";
|
|
37
|
+
import { buildLinkedFileRepairReport } from "./linked-file-report.js";
|
|
38
38
|
import { scanStorageIntegrity } from "./storage-integrity.js";
|
|
39
39
|
import { scanTrackedRuntimeCache } from "./tracked-runtime-cache.js";
|
|
40
40
|
import { scanHistoryAuthorAttribution } from "../author-attribution.js";
|
|
@@ -166,10 +166,11 @@ const DIAGNOSTIC_LIST_SUMMARY_LIMIT = 5;
|
|
|
166
166
|
const LINKED_ARTIFACT_MAX_PATH_LENGTH = 4096;
|
|
167
167
|
const LINKED_ARTIFACT_MAX_SEGMENT_LENGTH = 255;
|
|
168
168
|
const execFileAsync = promisify(execFile);
|
|
169
|
+
/** Recursively omit diagnostic arrays and false truncation markers while preserving zero counts and ordinary false values. */
|
|
169
170
|
function projectValidateCountsRecord(record) {
|
|
170
171
|
const projected = {};
|
|
171
172
|
for (const [key, value] of Object.entries(record)) {
|
|
172
|
-
if (Array.isArray(value)) {
|
|
173
|
+
if (Array.isArray(value) || (value === false && key.endsWith("_truncated"))) {
|
|
173
174
|
continue;
|
|
174
175
|
}
|
|
175
176
|
projected[key] =
|
|
@@ -183,7 +184,9 @@ function projectValidateCountsRecord(record) {
|
|
|
183
184
|
* Build the counts-only validate projection without mutating the full result.
|
|
184
185
|
* The check envelope and warning codes remain available for gates, while every
|
|
185
186
|
* per-item diagnostic/fix array is removed recursively and scalar counts,
|
|
186
|
-
* totals, statuses, and truncation markers are preserved.
|
|
187
|
+
* totals, statuses, and true truncation markers are preserved. False truncation
|
|
188
|
+
* markers are omitted; this sparse convention does not suppress other false or
|
|
189
|
+
* zero values, and the projection receipt still declares omitted diagnostic rows.
|
|
187
190
|
*/
|
|
188
191
|
export function projectValidateCounts(result) {
|
|
189
192
|
return {
|
|
@@ -1573,7 +1576,8 @@ function buildLifecycleCheck(items, includeStaleBlockers, dependencyCycleSeverit
|
|
|
1573
1576
|
}
|
|
1574
1577
|
/* c8 ignore stop */
|
|
1575
1578
|
/* c8 ignore start -- files-check candidate filtering/classification permutations are covered by file-audit integration suites */
|
|
1576
|
-
|
|
1579
|
+
/** Join live filesystem evidence with holder lifecycle, retaining historical rows while warning only on active missing links. */
|
|
1580
|
+
async function buildFilesCheck(items, workspaceRoot, pmRoot, fileScanMode, includePmInternals, verboseFileLists, statusRegistry = resolveRuntimeStatusRegistry(SETTINGS_DEFAULTS.schema)) {
|
|
1577
1581
|
const linkedPathState = await collectLinkedPathScanState(items, workspaceRoot);
|
|
1578
1582
|
const itemsById = new Map(items.map((item) => [item.id, item]));
|
|
1579
1583
|
const uniqueMissingLinkedPaths = [
|
|
@@ -1601,9 +1605,6 @@ async function buildFilesCheck(items, workspaceRoot, pmRoot, fileScanMode, inclu
|
|
|
1601
1605
|
if (partition.strictModeForcesPmInternals) {
|
|
1602
1606
|
warnings.push("validate_files_tracked_all_strict_forces_pm_internals");
|
|
1603
1607
|
}
|
|
1604
|
-
if (uniqueMissingLinkedPaths.length > 0) {
|
|
1605
|
-
warnings.push(`validate_files_missing_linked_paths:${uniqueMissingLinkedPaths.length}`);
|
|
1606
|
-
}
|
|
1607
1608
|
if (orphanedFiles.length > 0) {
|
|
1608
1609
|
warnings.push(`validate_files_orphaned_paths:${orphanedFiles.length}`);
|
|
1609
1610
|
}
|
|
@@ -1617,29 +1618,11 @@ async function buildFilesCheck(items, workspaceRoot, pmRoot, fileScanMode, inclu
|
|
|
1617
1618
|
: summarizeFileList(summarizeOrphanedPathRows(orphanedPathRows), false)
|
|
1618
1619
|
.values;
|
|
1619
1620
|
const summarizedClassifications = summarizeFileList(summarizeStaleLinkedPathClassifications(classifiedStalePaths), verboseFileLists);
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
const missingLinkedPathRows = staleLinkPruneRows.map((row) => ({
|
|
1626
|
-
item_id: row.item_id,
|
|
1627
|
-
path: row.path,
|
|
1628
|
-
link_kind: row.link_kind,
|
|
1629
|
-
classification: row.classification,
|
|
1630
|
-
}));
|
|
1631
|
-
const ownerRows = buildMissingLinkedPathRows(missingLinkedPathRows, (id) => {
|
|
1632
|
-
const owner = itemsById.get(id);
|
|
1633
|
-
return owner
|
|
1634
|
-
? { type: owner.type, title: owner.title, status: owner.status }
|
|
1635
|
-
: undefined;
|
|
1636
|
-
});
|
|
1637
|
-
// Default to token-efficient compact one-liners; expose the full structured
|
|
1638
|
-
// rows (the GH-210 JSON shape) under --verbose-file-lists.
|
|
1639
|
-
const ownerRowDetail = verboseFileLists
|
|
1640
|
-
? ownerRows
|
|
1641
|
-
: summarizeFileList(summarizeMissingLinkedPathRows(ownerRows), false)
|
|
1642
|
-
.values;
|
|
1621
|
+
const missingLinkedPathRows = staleLinkPruneRows;
|
|
1622
|
+
const repairReport = buildLinkedFileRepairReport(missingLinkedPathRows, classifiedStalePaths, (id) => itemsById.get(id), statusRegistry, verboseFileLists ? Infinity : FILE_LIST_SUMMARY_LIMIT);
|
|
1623
|
+
if (repairReport.active_missing_linked_paths_count > 0) {
|
|
1624
|
+
warnings.push(`validate_files_missing_linked_paths:${repairReport.active_missing_linked_paths_count}`);
|
|
1625
|
+
}
|
|
1643
1626
|
return {
|
|
1644
1627
|
check: {
|
|
1645
1628
|
name: "files",
|
|
@@ -1678,11 +1661,11 @@ async function buildFilesCheck(items, workspaceRoot, pmRoot, fileScanMode, inclu
|
|
|
1678
1661
|
missing_linked_paths: summarizedMissing.values,
|
|
1679
1662
|
missing_linked_paths_truncated: summarizedMissing.truncated,
|
|
1680
1663
|
missing_linked_paths_moved_count: movedStalePathCount,
|
|
1681
|
-
missing_linked_paths_deleted_count:
|
|
1664
|
+
missing_linked_paths_deleted_count: classifiedStalePaths.filter((entry) => entry.classification === "deleted").length,
|
|
1665
|
+
missing_linked_paths_malformed_count: classifiedStalePaths.filter((entry) => entry.classification === "malformed").length,
|
|
1682
1666
|
missing_linked_path_classifications: summarizedClassifications.values,
|
|
1683
1667
|
missing_linked_path_classifications_truncated: summarizedClassifications.truncated,
|
|
1684
|
-
|
|
1685
|
-
missing_linked_path_rows: ownerRowDetail,
|
|
1668
|
+
...repairReport,
|
|
1686
1669
|
orphaned_paths_count: orphanedFiles.length,
|
|
1687
1670
|
orphaned_paths_total: summarizedOrphaned.total,
|
|
1688
1671
|
orphaned_paths: summarizedOrphaned.values,
|
|
@@ -2076,6 +2059,7 @@ function recordValidateCheck(state, built, fixHintsEnabled) {
|
|
|
2076
2059
|
state.checks.push(built.check);
|
|
2077
2060
|
state.warnings.push(...built.warnings);
|
|
2078
2061
|
}
|
|
2062
|
+
/** Run only selected checks against one resolved workspace context and collect their typed remediation evidence. */
|
|
2079
2063
|
async function executeRequestedValidateChecks(params) {
|
|
2080
2064
|
const state = {
|
|
2081
2065
|
checks: [],
|
|
@@ -2108,7 +2092,7 @@ async function executeRequestedValidateChecks(params) {
|
|
|
2108
2092
|
recordValidateCheck(state, buildDependencyReferencesCheck(params.items, fullDiagnostics, params.statusRegistry), fixHintsEnabled);
|
|
2109
2093
|
}
|
|
2110
2094
|
if (params.requestedChecks.has("files")) {
|
|
2111
|
-
const built = await buildFilesCheck(params.items, params.workspaceRoot, params.pmRoot, params.fileScanMode, Boolean(params.options.includePmInternals), Boolean(params.options.verboseFileLists));
|
|
2095
|
+
const built = await buildFilesCheck(params.items, params.workspaceRoot, params.pmRoot, params.fileScanMode, Boolean(params.options.includePmInternals), Boolean(params.options.verboseFileLists), params.statusRegistry);
|
|
2112
2096
|
state.staleLinkPruneRows = built.staleLinkPruneRows;
|
|
2113
2097
|
recordValidateCheck(state, built, fixHintsEnabled);
|
|
2114
2098
|
}
|
|
@@ -2275,4 +2259,4 @@ export async function runValidate(options, global, services = {}) {
|
|
|
2275
2259
|
}
|
|
2276
2260
|
/* c8 ignore stop */
|
|
2277
2261
|
//# sourceMappingURL=validate.js.map
|
|
2278
|
-
//# debugId=
|
|
2262
|
+
//# debugId=898c4c05-70ab-5ea4-851e-9e224a85afc4
|
package/dist/sdk/governance.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./governance/assurance-presets.js";
|
|
|
13
13
|
export * from "./governance/assurance-runtime.js";
|
|
14
14
|
export * from "./governance/boundary-fixtures.js";
|
|
15
15
|
export * from "./governance/defect-recurrence.js";
|
|
16
|
+
export * from "./governance/defect-recurrence-coverage.js";
|
|
16
17
|
export { runReindex, type ReindexOptions, type ReindexResult, } from "./governance/reindex.js";
|
|
17
18
|
export * from "./governance/stale-work.js";
|
|
18
19
|
export * from "./governance/storage-integrity.js";
|
|
@@ -20,6 +21,7 @@ export * from "./governance/status-role-diagnostics.js";
|
|
|
20
21
|
export * from "./governance/workspace-position.js";
|
|
21
22
|
export { runUpgrade, type UpgradeCliResult, type UpgradeCommandOptions, type UpgradeCommandRunner, type UpgradeCommandRunnerResult, type UpgradePackageResult, type UpgradeResult, } from "./governance/upgrade.js";
|
|
22
23
|
export * from "./governance/validate.js";
|
|
24
|
+
export * from "./governance/linked-file-report.js";
|
|
23
25
|
export * from "./author-attribution.js";
|
|
24
26
|
export * from "./mutation-guard.js";
|
|
25
27
|
export * from "./governance/provenance-health.js";
|
package/dist/sdk/governance.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides validation, health, integrity, and mutation-policy primitives.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5e2aaa83-a109-5e44-b9b3-316501ffadf4")}catch(e){}}();
|
|
8
8
|
export * from "./governance/gc.js";
|
|
9
9
|
export * from "./governance/health.js";
|
|
10
10
|
export * from "./governance/extension-host-version.js";
|
|
@@ -15,6 +15,7 @@ export * from "./governance/assurance-presets.js";
|
|
|
15
15
|
export * from "./governance/assurance-runtime.js";
|
|
16
16
|
export * from "./governance/boundary-fixtures.js";
|
|
17
17
|
export * from "./governance/defect-recurrence.js";
|
|
18
|
+
export * from "./governance/defect-recurrence-coverage.js";
|
|
18
19
|
export { runReindex, } from "./governance/reindex.js";
|
|
19
20
|
export * from "./governance/stale-work.js";
|
|
20
21
|
export * from "./governance/storage-integrity.js";
|
|
@@ -22,9 +23,10 @@ export * from "./governance/status-role-diagnostics.js";
|
|
|
22
23
|
export * from "./governance/workspace-position.js";
|
|
23
24
|
export { runUpgrade, } from "./governance/upgrade.js";
|
|
24
25
|
export * from "./governance/validate.js";
|
|
26
|
+
export * from "./governance/linked-file-report.js";
|
|
25
27
|
export * from "./author-attribution.js";
|
|
26
28
|
export * from "./mutation-guard.js";
|
|
27
29
|
export * from "./governance/provenance-health.js";
|
|
28
30
|
export * from "./similarity.js";
|
|
29
31
|
//# sourceMappingURL=governance.js.map
|
|
30
|
-
//# debugId=
|
|
32
|
+
//# debugId=5e2aaa83-a109-5e44-b9b3-316501ffadf4
|
|
@@ -36,6 +36,13 @@ export interface HistoryRepairCommandOptions {
|
|
|
36
36
|
gitWorkspaceRoot: string | null;
|
|
37
37
|
receipts: MergeDecisionReceipt[];
|
|
38
38
|
}>;
|
|
39
|
+
/** Restored-origin evidence checked against the same item snapshot protected by the rewrite transaction. */
|
|
40
|
+
mergeAbandonmentProof?: {
|
|
41
|
+
/** Git workspace containing the tracked item. */
|
|
42
|
+
gitWorkspaceRoot: string;
|
|
43
|
+
/** Authoritative receipt whose original rebase state must match. */
|
|
44
|
+
receipt: MergeDecisionReceipt;
|
|
45
|
+
};
|
|
39
46
|
}
|
|
40
47
|
/** Documents the history repair result payload exchanged by command, SDK, and package integrations. */
|
|
41
48
|
export interface HistoryRepairResult {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm history repair command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9f91f2ee-cebe-592c-92ee-717301fa96ca")}catch(e){}}();
|
|
8
8
|
import { assertInitializedTracker } from "./environment/tracker-preflight.js";
|
|
9
9
|
import { salvageHistoryTail } from "./history/salvage.js";
|
|
10
10
|
import { realpath } from "node:fs/promises";
|
|
@@ -30,6 +30,7 @@ import { listAllItemMetadataWithBody, readLocatedItem, } from "../core/store/ite
|
|
|
30
30
|
import { resolvePmRoot } from "../core/store/paths.js";
|
|
31
31
|
import { readSettings } from "../core/store/settings.js";
|
|
32
32
|
import { resolveHistorySubject } from "./history-redact.js";
|
|
33
|
+
import { isOriginalGitStateRestored } from "./merge/receipt-operation.js";
|
|
33
34
|
import { inspectMergeReceiptEvidence, summarizeMergeReceipt, } from "./merge/receipts.js";
|
|
34
35
|
import { encodeItemScalarDecisionValue, hashItemScalarDecisionValue, } from "./merge/three-way.js";
|
|
35
36
|
import { listInvalidProvenanceHistoryStreamIds, normalizeInvalidHistoryProvenance, } from "./governance/provenance-health.js";
|
|
@@ -229,6 +230,24 @@ async function verifyMergeReceiptProof(params) {
|
|
|
229
230
|
receipt_ids: [],
|
|
230
231
|
};
|
|
231
232
|
}
|
|
233
|
+
/** Refuse a restored-origin audit when its exact item snapshot or clean history has changed. */
|
|
234
|
+
async function assertHistoryRepairAbandonmentProof(proof, context, chainOk, reanchor) {
|
|
235
|
+
if (proof === undefined)
|
|
236
|
+
return;
|
|
237
|
+
const { receipt, gitWorkspaceRoot } = proof;
|
|
238
|
+
const canonicalPath = context.currentItemPath === null ? null
|
|
239
|
+
: path.relative(gitWorkspaceRoot, context.currentItemPath).split(path.sep).join("/");
|
|
240
|
+
if (!chainOk || reanchor.entriesRehashed !== 0 || reanchor.entriesPatchRepaired !== 0 || context.matchedChainBefore !== true ||
|
|
241
|
+
context.currentItemRawBeforeLock === null || canonicalPath !== receipt.item_path ||
|
|
242
|
+
receipt.operation === undefined ||
|
|
243
|
+
!await isOriginalGitStateRestored(gitWorkspaceRoot, receipt.item_path, receipt.operation, context.currentItemRawBeforeLock)) {
|
|
244
|
+
throw new PmCliError("Restored-origin receipt evidence no longer proves the exact clean item snapshot.", EXIT_CODE.CONFLICT, {
|
|
245
|
+
code: "merge_reconcile_receipt_evidence_untrusted",
|
|
246
|
+
recovery: { suggested_retry: "pm merge reconcile --dry-run" },
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** Resolve and verify receipt candidates against loaded item evidence, refusing untrusted preview and apply requests alike. */
|
|
232
251
|
async function resolveHistoryRepairMergeEvidence(params) {
|
|
233
252
|
const requestedReceiptIds = new Set(params.options.mergeReceiptProof?.receipts
|
|
234
253
|
.filter((receipt) => receipt.item_id === params.subjectId)
|
|
@@ -256,7 +275,6 @@ async function resolveHistoryRepairMergeEvidence(params) {
|
|
|
256
275
|
: undefined;
|
|
257
276
|
if (mergeReceiptProof &&
|
|
258
277
|
!mergeReceiptProof.trusted &&
|
|
259
|
-
params.options.dryRun !== true &&
|
|
260
278
|
params.options.force !== true) {
|
|
261
279
|
throw new PmCliError(`Merge receipt evidence for ${params.subjectId} does not prove the exact item snapshot (${mergeReceiptProof.reason}).`, EXIT_CODE.CONFLICT, {
|
|
262
280
|
code: "merge_reconcile_receipt_evidence_untrusted",
|
|
@@ -359,6 +377,7 @@ function collectHistoryRepairWarnings(changed, skippedOps, reconciliation) {
|
|
|
359
377
|
}
|
|
360
378
|
return warnings;
|
|
361
379
|
}
|
|
380
|
+
/** Revalidate item/history bytes and restored-origin Git proof under the rewrite lock before persisting. */
|
|
362
381
|
async function applyHistoryRepairRewrite(params) {
|
|
363
382
|
return executeHistoryRewrite({
|
|
364
383
|
pmRoot: params.pmRoot,
|
|
@@ -366,16 +385,19 @@ async function applyHistoryRepairRewrite(params) {
|
|
|
366
385
|
settings: params.settings,
|
|
367
386
|
typeRegistry: params.typeRegistry,
|
|
368
387
|
historyRawBeforeLock: params.historyRawBeforeLock,
|
|
369
|
-
currentItemRawBeforeLock: params.currentItemRawBeforeLock,
|
|
388
|
+
currentItemRawBeforeLock: params.itemReplayContext.currentItemRawBeforeLock,
|
|
370
389
|
operation: "history-repair",
|
|
371
390
|
author: params.author,
|
|
372
391
|
force: params.force,
|
|
373
|
-
itemDocument: params.loadedItem?.document ?? null,
|
|
374
|
-
applyRewrite: async ({ historyRawUnderLock }) =>
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
392
|
+
itemDocument: params.itemReplayContext.loadedItem?.document ?? null,
|
|
393
|
+
applyRewrite: async ({ historyRawUnderLock }) => {
|
|
394
|
+
await assertHistoryRepairAbandonmentProof(params.mergeAbandonmentProof, params.itemReplayContext, params.chainOk, params.reanchor);
|
|
395
|
+
await writeHistoryRawWithRollback({
|
|
396
|
+
historyPath: params.historyPath,
|
|
397
|
+
nextHistoryRaw: historyEntriesToRaw(params.rewrittenEntries),
|
|
398
|
+
historyRawUnderLock,
|
|
399
|
+
});
|
|
400
|
+
},
|
|
379
401
|
applyPostRewrite: async () => runActiveOnWriteHooks({
|
|
380
402
|
path: params.historyPath,
|
|
381
403
|
scope: "project",
|
|
@@ -395,6 +417,16 @@ export async function runHistoryRepair(id, options, global) {
|
|
|
395
417
|
}
|
|
396
418
|
return repairHistorySubject({ pmRoot, subject, settings, typeRegistry, options });
|
|
397
419
|
}
|
|
420
|
+
/** Preserve explicit audit requests while reusing exact restored-origin dispositions in verified history. */
|
|
421
|
+
function shouldAppendForcedHistoryAudit(options, historyEntries) {
|
|
422
|
+
// Receipt persistence can fail after the audited history transaction commits.
|
|
423
|
+
// Only an identical disposition satisfies a retry; unrelated audits do not.
|
|
424
|
+
const alreadyRecorded = options.mergeAbandonmentProof !== undefined &&
|
|
425
|
+
options.auditContext !== undefined &&
|
|
426
|
+
historyEntries.some((entry) => entry.op === "merge_reconcile" &&
|
|
427
|
+
stableStringify(entry.context) === stableStringify(options.auditContext));
|
|
428
|
+
return options.forceAuditEntry === true && !alreadyRecorded;
|
|
429
|
+
}
|
|
398
430
|
/** Reanchor or reconcile one resolved subject, separately from byte-preserving salvage. */
|
|
399
431
|
async function repairHistorySubject(params) {
|
|
400
432
|
const { pmRoot, subject, settings, typeRegistry, options } = params;
|
|
@@ -425,6 +457,7 @@ async function repairHistorySubject(params) {
|
|
|
425
457
|
.filter((version) => version !== undefined));
|
|
426
458
|
const reanchor = reanchorHistoryEntries(provenanceNormalization.entries, itemHashVersion);
|
|
427
459
|
const itemReplayContext = await loadHistoryRepairItemReplay(subject, settings, historyEntries, itemHashVersion);
|
|
460
|
+
await assertHistoryRepairAbandonmentProof(options.mergeAbandonmentProof, itemReplayContext, chainBefore.ok, reanchor);
|
|
428
461
|
const finalReplay = reanchor.finalDocument;
|
|
429
462
|
const finalReplayHashes = replayHashVerificationCandidates(finalReplay, itemHashVersion);
|
|
430
463
|
let reconcileNeeded = false;
|
|
@@ -449,7 +482,7 @@ async function repairHistorySubject(params) {
|
|
|
449
482
|
reanchor.entriesRehashed > 0,
|
|
450
483
|
reanchor.entriesPatchRepaired > 0,
|
|
451
484
|
reconcileNeeded,
|
|
452
|
-
options
|
|
485
|
+
shouldAppendForcedHistoryAudit(options, historyEntries),
|
|
453
486
|
provenanceNormalization.receipt.changed,
|
|
454
487
|
].some(Boolean);
|
|
455
488
|
const author = resolveAuthor(options.author, settings.author_default);
|
|
@@ -490,10 +523,12 @@ async function repairHistorySubject(params) {
|
|
|
490
523
|
settings,
|
|
491
524
|
typeRegistry,
|
|
492
525
|
historyRawBeforeLock,
|
|
493
|
-
|
|
526
|
+
itemReplayContext,
|
|
527
|
+
mergeAbandonmentProof: options.mergeAbandonmentProof,
|
|
528
|
+
chainOk: chainBefore.ok,
|
|
529
|
+
reanchor,
|
|
494
530
|
author,
|
|
495
531
|
force: options.force,
|
|
496
|
-
loadedItem: itemReplayContext.loadedItem,
|
|
497
532
|
historyPath: subject.historyPath,
|
|
498
533
|
rewrittenEntries,
|
|
499
534
|
})));
|
|
@@ -620,4 +655,4 @@ export async function runHistoryRepairAll(options, global) {
|
|
|
620
655
|
};
|
|
621
656
|
}
|
|
622
657
|
//# sourceMappingURL=history-repair.js.map
|
|
623
|
-
//# debugId=
|
|
658
|
+
//# debugId=9f91f2ee-cebe-592c-92ee-717301fa96ca
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/lifecycle/close
|
|
3
|
+
*
|
|
4
|
+
* Implements the pm close command surface and its agent-facing runtime behavior.
|
|
5
|
+
*/
|
|
6
|
+
import type { PmCliErrorRecoveryPayload } from "../../core/shared/errors.js";
|
|
1
7
|
import { type GlobalOptions } from "../runtime-primitives.js";
|
|
2
8
|
import { collectBlockedByIds } from "../actionability.js";
|
|
3
9
|
import { type CloseOperationOptions, type CloseOperationResult } from "../lifecycle-policy.js";
|
|
@@ -28,6 +34,8 @@ export interface CloseResult {
|
|
|
28
34
|
item: Record<string, unknown>;
|
|
29
35
|
/** Changed metadata fields. */
|
|
30
36
|
changed_fields: string[];
|
|
37
|
+
/** Evidence-only update guidance when acceptance fields are missing. */
|
|
38
|
+
recovery?: PmCliErrorRecoveryPayload;
|
|
31
39
|
/** Validation and lifecycle receipts. */
|
|
32
40
|
warnings: string[];
|
|
33
41
|
}
|