@unbrained/pm-cli 2026.8.13 → 2026.8.15
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 +165 -113
- package/dist/cli/commander-usage.js +17 -4
- package/dist/cli/error-guidance.d.ts +2 -0
- package/dist/cli/error-guidance.js +52 -25
- package/dist/cli/main.js +40 -3
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +5 -5
- package/dist/cli-bundle/bundle-manifest.json +146 -178
- package/dist/cli-bundle/chunks/{chunk-F7FJYGK3.js → chunk-24GAV7XL.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +13 -0
- package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-Q47C67TQ.js → chunk-J42EGKDK.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-3ZMOWAFM.js → chunk-KLKYLSDX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-QGTUPEU5.js → chunk-LJHOAVGI.js} +59 -59
- package/dist/cli-bundle/chunks/chunk-MEM2ZS3O.js +5 -0
- package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-YLBAPY22.js → chunk-WLPDLNEZ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-4HIZ7EA3.js → register-list-query-CT3LFDDN.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-W64FZ5HN.js → register-mutation-NWEVA5YS.js} +3 -3
- package/dist/cli-bundle/chunks/register-operations-AHIAG5KM.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-634MFRXU.js → register-setup-ZJZFVAKE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-6XKF3PGV.js +18 -0
- package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-I75MANL7.js → chunk-EXZA4257.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-OOYYKQWX.js → chunk-KLVUMNXJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2RI2FESN.js → chunk-KT5XMYSX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-E3AVJ655.js → chunk-KTKH4IMG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3DJSGWVB.js → chunk-NSPYTG6G.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-IIS2FRKL.js → chunk-SLKC6QLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-WTSER4WJ.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2JP7W7GO.js → chunk-ZMFXQ7VF.js} +2 -2
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +41 -41
- 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 +110 -1
- 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 +2 -2
- package/dist/core/diagnostics/remediation.js +7 -2
- package/dist/core/extensions/reserved-host-flags.js +3 -2
- package/dist/core/history/drift-scan.d.ts +6 -0
- package/dist/core/history/drift-scan.js +74 -50
- package/dist/core/history/replay.d.ts +14 -1
- package/dist/core/history/replay.js +45 -8
- package/dist/core/history/workspace-history.d.ts +59 -0
- package/dist/core/history/workspace-history.js +197 -10
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +13 -4
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/command-types.js +2 -2
- package/dist/core/shared/errors.d.ts +12 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/mcp/tool-definitions.js +9 -5
- package/dist/sdk/agent/refusal-reachability.d.ts +61 -0
- package/dist/sdk/agent/refusal-reachability.js +91 -3
- package/dist/sdk/cli-bootstrap.d.ts +2 -0
- package/dist/sdk/cli-bootstrap.js +7 -2
- package/dist/sdk/cli-contracts/completeness.js +3 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
- package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +11 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +176 -65
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +15 -5
- package/dist/sdk/cli-contracts/tool-schema.js +10 -3
- package/dist/sdk/cli-program.js +4 -3
- package/dist/sdk/context-relevance.js +12 -4
- package/dist/sdk/core.d.ts +2 -2
- package/dist/sdk/core.js +3 -3
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +26 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -26
- package/dist/sdk/governance/assurance-action.d.ts +7 -1
- package/dist/sdk/governance/assurance-action.js +7 -6
- package/dist/sdk/governance/assurance-mutation-error.d.ts +42 -1
- package/dist/sdk/governance/assurance-mutation-error.js +27 -3
- package/dist/sdk/governance/assurance-runtime.js +12 -11
- package/dist/sdk/governance/assurance.d.ts +9 -0
- package/dist/sdk/governance/assurance.js +82 -16
- package/dist/sdk/governance/extension-host-version.d.ts +25 -0
- package/dist/sdk/governance/extension-host-version.js +105 -0
- package/dist/sdk/governance/health.d.ts +32 -1
- package/dist/sdk/governance/health.js +132 -28
- package/dist/sdk/governance/provenance-health.d.ts +27 -0
- package/dist/sdk/governance/provenance-health.js +95 -3
- package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
- package/dist/sdk/governance/validate-history-drift.js +68 -0
- package/dist/sdk/governance/validate.js +9 -52
- package/dist/sdk/governance.d.ts +6 -0
- package/dist/sdk/governance.js +8 -2
- package/dist/sdk/graph/assembly.d.ts +23 -0
- package/dist/sdk/graph/assembly.js +54 -2
- package/dist/sdk/graph/durable-cache.js +50 -20
- package/dist/sdk/graph/governance-contracts.d.ts +1 -1
- package/dist/sdk/graph/governance-contracts.js +4 -2
- package/dist/sdk/graph/governance.d.ts +21 -1
- package/dist/sdk/graph/governance.js +94 -32
- package/dist/sdk/graph/index.d.ts +2 -2
- package/dist/sdk/graph/index.js +4 -4
- package/dist/sdk/graph/mutation-advisory.js +15 -7
- package/dist/sdk/graph/remediation.js +12 -2
- package/dist/sdk/history-read.d.ts +8 -0
- package/dist/sdk/history-read.js +2 -2
- package/dist/sdk/history-repair.d.ts +13 -1
- package/dist/sdk/history-repair.js +62 -18
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/linked-artifacts.js +16 -5
- package/dist/sdk/pagination.d.ts +15 -0
- package/dist/sdk/pagination.js +9 -5
- package/dist/sdk/query/context.d.ts +5 -1
- package/dist/sdk/query/context.js +14 -5
- package/dist/sdk/query/history.js +20 -3
- package/dist/sdk/read-output/continuation.d.ts +11 -0
- package/dist/sdk/read-output/continuation.js +132 -0
- package/dist/sdk/read-output-budget.d.ts +3 -1
- package/dist/sdk/read-output-budget.js +24 -13
- package/dist/sdk/read-output-contracts.d.ts +127 -7
- package/dist/sdk/read-output-contracts.js +381 -35
- package/dist/sdk/read-output-rows.d.ts +13 -0
- package/dist/sdk/read-output-rows.js +60 -2
- package/dist/sdk/runtime-input.js +4 -2
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +5 -3
- package/docs/ASSURANCE.md +68 -2
- package/docs/COMMANDS.md +39 -4
- package/docs/READ_OUTPUT_CONTRACTS.md +85 -8
- package/docs/RELATIONSHIP_GRAPH.md +20 -5
- package/docs/RELEASING.md +42 -5
- package/docs/SDK.md +12 -5
- package/docs/SDK_CONTEXT_INTEGRITY.md +94 -1
- package/docs/TESTING.md +23 -1
- package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
- package/marketplace.json +2 -2
- package/package.json +7 -7
- package/packages/pm-beads/extensions/beads/index.ts +1 -0
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
- 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/extensions/linked-test-adapters/index.ts +6 -0
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/extensions/templates/index.ts +4 -0
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/extensions/todos/index.ts +2 -0
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
- 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/scripts/bundle-cli.mjs +17 -4
- package/sdk/public-surface.json +1283 -157
- package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +0 -196
- package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +0 -5
- package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +0 -2
- package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +0 -34
- package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-HC2OL2H2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +0 -17
- package/dist/cli-bundle/focused-chunks/chunk-PKPOZXLL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-TEZIXMTH.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +0 -18
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/governance/extension-host-version
|
|
3
|
+
*
|
|
4
|
+
* Discovers the pm-cli copy that each loaded extension resolves at runtime so
|
|
5
|
+
* package-manager layout skew is visible before SDK singleton state diverges.
|
|
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]="b55cafdc-9a3b-5386-bd85-cbd2311a5933")}catch(e){}}();
|
|
9
|
+
import fs from "node:fs/promises";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { resolvePmPackageRootFromModule } from "../../core/packages/root.js";
|
|
13
|
+
function displayPackagePath(packageJsonPath, workspaceRoot) {
|
|
14
|
+
const relative = path.relative(workspaceRoot, packageJsonPath);
|
|
15
|
+
if (relative.length > 0 &&
|
|
16
|
+
relative !== ".." &&
|
|
17
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
18
|
+
!path.isAbsolute(relative)) {
|
|
19
|
+
return relative.split(path.sep).join("/");
|
|
20
|
+
}
|
|
21
|
+
const externalPath = path.resolve(packageJsonPath);
|
|
22
|
+
let fingerprint = 0xcbf29ce484222325n;
|
|
23
|
+
for (let index = 0; index < externalPath.length; index += 1) {
|
|
24
|
+
fingerprint ^= BigInt(externalPath.charCodeAt(index));
|
|
25
|
+
fingerprint = BigInt.asUintN(64, fingerprint * 0x100000001b3n);
|
|
26
|
+
}
|
|
27
|
+
const installationId = fingerprint.toString(16).padStart(16, "0");
|
|
28
|
+
return `<external>/${installationId}/${path.basename(path.dirname(packageJsonPath))}/package.json`;
|
|
29
|
+
}
|
|
30
|
+
function dependencyLayout(packageJsonPath) {
|
|
31
|
+
if (packageJsonPath.includes(`${path.sep}.pnpm${path.sep}`))
|
|
32
|
+
return "pnpm";
|
|
33
|
+
if (packageJsonPath.includes(`${path.sep}node_modules${path.sep}`)) {
|
|
34
|
+
return "npm";
|
|
35
|
+
}
|
|
36
|
+
return "other";
|
|
37
|
+
}
|
|
38
|
+
async function readPackageVersion(packageJsonPath) {
|
|
39
|
+
try {
|
|
40
|
+
const parsed = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
|
|
41
|
+
return parsed.name === "@unbrained/pm-cli" &&
|
|
42
|
+
typeof parsed.version === "string" &&
|
|
43
|
+
parsed.version.trim().length > 0
|
|
44
|
+
? parsed.version.trim()
|
|
45
|
+
: undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Scan the host plus the nearest pm-cli package resolvable by every loaded extension. */
|
|
52
|
+
export async function scanExtensionHostVersions(loadedExtensions, workspaceRoot, hostPackageRoot = resolvePmPackageRootFromModule(import.meta.url, [
|
|
53
|
+
"../../..",
|
|
54
|
+
])) {
|
|
55
|
+
const hostPackageJson = path.join(hostPackageRoot, "package.json");
|
|
56
|
+
const hostVersion = await readPackageVersion(hostPackageJson);
|
|
57
|
+
const copies = new Map();
|
|
58
|
+
if (hostVersion !== undefined) {
|
|
59
|
+
copies.set(path.resolve(hostPackageJson), {
|
|
60
|
+
version: hostVersion,
|
|
61
|
+
path: displayPackagePath(hostPackageJson, workspaceRoot),
|
|
62
|
+
layout: "host",
|
|
63
|
+
consumers: ["pm-cli-host"],
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
for (const extension of loadedExtensions) {
|
|
67
|
+
try {
|
|
68
|
+
const resolved = createRequire(extension.entry_path).resolve("@unbrained/pm-cli/package.json");
|
|
69
|
+
const version = await readPackageVersion(resolved);
|
|
70
|
+
if (version === undefined)
|
|
71
|
+
continue;
|
|
72
|
+
const key = path.resolve(resolved);
|
|
73
|
+
const existing = copies.get(key);
|
|
74
|
+
if (existing) {
|
|
75
|
+
if (!existing.consumers.includes(extension.name)) {
|
|
76
|
+
existing.consumers.push(extension.name);
|
|
77
|
+
existing.consumers.sort((left, right) => left.localeCompare(right));
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
copies.set(key, {
|
|
82
|
+
version,
|
|
83
|
+
path: displayPackagePath(resolved, workspaceRoot),
|
|
84
|
+
layout: dependencyLayout(resolved),
|
|
85
|
+
consumers: [extension.name],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Extensions that do not resolve pm-cli use the host surface they were
|
|
90
|
+
// handed. Load/activation diagnostics own unrelated resolution failures.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const sortedCopies = [...copies.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
94
|
+
const mismatches = hostVersion === undefined
|
|
95
|
+
? []
|
|
96
|
+
: sortedCopies.filter((copy) => copy.version !== hostVersion);
|
|
97
|
+
return {
|
|
98
|
+
host_version: hostVersion ?? null,
|
|
99
|
+
copies: sortedCopies,
|
|
100
|
+
mismatches,
|
|
101
|
+
warnings: mismatches.map((copy) => `extension_host_pm_cli_version_skew:${hostVersion}:${copy.version}:${copy.consumers.join("+")}`),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=extension-host-version.js.map
|
|
105
|
+
//# debugId=b55cafdc-9a3b-5386-bd85-cbd2311a5933
|
|
@@ -20,6 +20,21 @@ export interface HealthCheck {
|
|
|
20
20
|
/** Value that configures or reports details for this contract. */
|
|
21
21
|
details: Record<string, unknown>;
|
|
22
22
|
}
|
|
23
|
+
/** One warning indexed to the check, severity, and safe next action that decide health. */
|
|
24
|
+
export interface HealthFinding {
|
|
25
|
+
/** Original stable warning token. */
|
|
26
|
+
warning: string;
|
|
27
|
+
/** Stable colon-delimited warning code. */
|
|
28
|
+
code: string;
|
|
29
|
+
/** Health check that owns the finding. */
|
|
30
|
+
check: HealthCheck["name"];
|
|
31
|
+
/** Whether the finding blocks the top-level health verdict. */
|
|
32
|
+
severity: "advisory" | "gate_failing";
|
|
33
|
+
/** Executable remediation when one is safe and fully specified. */
|
|
34
|
+
remediation?: string;
|
|
35
|
+
/** Explicit refusal when automatic remediation would require operator choices. */
|
|
36
|
+
disposition?: "no_safe_automatic_remediation";
|
|
37
|
+
}
|
|
23
38
|
/** Documents the health result payload exchanged by command, SDK, and package integrations. */
|
|
24
39
|
export interface HealthResult {
|
|
25
40
|
/** Whether the operation completed without a blocking failure. */
|
|
@@ -28,8 +43,16 @@ export interface HealthResult {
|
|
|
28
43
|
checks: HealthCheck[];
|
|
29
44
|
/** Number of warning entries represented by this result. */
|
|
30
45
|
warning_count?: number;
|
|
46
|
+
/** Maximum warning rows retained in every projection. */
|
|
47
|
+
warning_limit?: number;
|
|
48
|
+
/** Whether warning rows were omitted after the declared limit. */
|
|
49
|
+
warnings_truncated?: boolean;
|
|
31
50
|
/** Value that configures or reports warnings for this contract. */
|
|
32
51
|
warnings: string[];
|
|
52
|
+
/** Every retained warning indexed to its owning check and severity. */
|
|
53
|
+
findings: HealthFinding[];
|
|
54
|
+
/** Exact gate-failing warning tokens that make `ok` false. */
|
|
55
|
+
failed_because: string[];
|
|
33
56
|
/** Value that configures or reports projection for this contract. */
|
|
34
57
|
projection?: {
|
|
35
58
|
mode: "brief" | "summary" | "full";
|
|
@@ -115,7 +138,7 @@ interface ExtensionHealthTriageSummary {
|
|
|
115
138
|
top_warnings: string[];
|
|
116
139
|
remediation: string[];
|
|
117
140
|
}
|
|
118
|
-
/** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance
|
|
141
|
+
/** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance remains advisory until an operator explicitly applies the privacy-safe history normalizer. */
|
|
119
142
|
declare function isAdvisoryHealthWarning(warning: string, requireMergeDrivers?: boolean): boolean;
|
|
120
143
|
declare function warningCode(value: string): string;
|
|
121
144
|
declare function normalizeExtensionNameForMatch(value: string): string;
|
|
@@ -183,12 +206,20 @@ declare function buildStaleInProgressHealthSummary(scan: StaleInProgressScan): {
|
|
|
183
206
|
scan: StaleInProgressScan;
|
|
184
207
|
warnings: string[];
|
|
185
208
|
};
|
|
209
|
+
/** Index every warning to exactly one health check, severity, and safe next action. */
|
|
210
|
+
declare function buildHealthFindings(params: {
|
|
211
|
+
warnings: string[];
|
|
212
|
+
checks: HealthCheck[];
|
|
213
|
+
remediationSources: Record<HealthCheck["name"], string[]>;
|
|
214
|
+
requireMergeDrivers: boolean;
|
|
215
|
+
}): HealthFinding[];
|
|
186
216
|
declare function projectHealthResult(result: HealthResult, options: RunHealthOptions, summaryMode: boolean): HealthResult;
|
|
187
217
|
/** Implements run health for the public runtime surface of this module. */
|
|
188
218
|
export declare function runHealth(global: GlobalOptions, options?: RunHealthOptions): Promise<HealthResult>;
|
|
189
219
|
/** Public contract for test only health command, shared by SDK and presentation-layer consumers. */
|
|
190
220
|
export declare const _testOnlyHealthCommand: {
|
|
191
221
|
buildExtensionHealthTriageSummary: typeof buildExtensionHealthTriageSummary;
|
|
222
|
+
buildHealthFindings: typeof buildHealthFindings;
|
|
192
223
|
buildCapabilityContractMetadata: typeof buildCapabilityContractMetadata;
|
|
193
224
|
buildStaleInProgressHealthSummary: typeof buildStaleInProgressHealthSummary;
|
|
194
225
|
buildVectorizationProviderDetails: typeof buildVectorizationProviderDetails;
|
|
@@ -4,11 +4,11 @@
|
|
|
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]="e7be701e-085c-5903-96da-61149452c673")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
11
|
-
import { isFileMissingError, pathExists, readFileIfExists } from "../../core/fs/fs-utils.js";
|
|
11
|
+
import { isFileMissingError, pathExists, readFileIfExists, } from "../../core/fs/fs-utils.js";
|
|
12
12
|
import { activateExtensions, getActiveExtensionRegistrations, loadExtensions, runActiveOnReadHooks, } from "../../core/extensions/index.js";
|
|
13
13
|
import { collectRegisteredItemFieldNames } from "../../core/extensions/item-fields.js";
|
|
14
14
|
import { KNOWN_EXTENSION_CAPABILITIES, } from "../../core/extensions/loader.js";
|
|
@@ -30,9 +30,10 @@ import { parseItemDocument } from "../../core/item/item-format.js";
|
|
|
30
30
|
import { effectiveItemFormatVersion, scanItemFormatVersions, } from "../../core/item/item-format-version.js";
|
|
31
31
|
import { listAllItemMetadataLight, listAllItemMetadataWithBody, } from "../../core/store/item-store.js";
|
|
32
32
|
import { PM_TELEMETRY_SOURCE_CONTEXT_VALUES, TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS, TELEMETRY_SCHEMA_VERSION, } from "../../core/telemetry/runtime.js";
|
|
33
|
-
import { getItemFormatFromPath, getSettingsPath, ITEM_FILE_EXTENSIONS, resolveGlobalPmRoot, resolvePmRoot, } from "../../core/store/paths.js";
|
|
33
|
+
import { getItemFormatFromPath, getSettingsPath, ITEM_FILE_EXTENSIONS, resolveGlobalPmRoot, resolvePmRoot, resolveWorkspaceRoot, } from "../../core/store/paths.js";
|
|
34
34
|
import { readSettingsWithMetadata } from "../../core/store/settings.js";
|
|
35
|
-
import { buildRemediationMap } from "../../core/diagnostics/remediation.js";
|
|
35
|
+
import { buildRemediationMap, resolveRemediation, } from "../../core/diagnostics/remediation.js";
|
|
36
|
+
import { scanExtensionHostVersions } from "./extension-host-version.js";
|
|
36
37
|
import { scanHistoryAuthorAttribution, } from "../author-attribution.js";
|
|
37
38
|
import { readManagedExtensionState } from "../extension.js";
|
|
38
39
|
import { scanProvenanceResolverHealth } from "./provenance-health.js";
|
|
@@ -45,6 +46,7 @@ import { listMergeReceipts, partitionMergeReceipts, } from "../merge/receipts.js
|
|
|
45
46
|
const PM_TELEMETRY_SOURCE_CONTEXT_SET = new Set(PM_TELEMETRY_SOURCE_CONTEXT_VALUES);
|
|
46
47
|
const STALE_VECTORIZATION_SUMMARY_LIMIT = 25;
|
|
47
48
|
const BRIEF_HEALTH_DETAIL_LIMIT = 8;
|
|
49
|
+
const HEALTH_WARNING_LIMIT = 100;
|
|
48
50
|
const TELEMETRY_QUEUE_RELATIVE_PATH = path.join("runtime", "telemetry", "events.jsonl");
|
|
49
51
|
const TELEMETRY_STATE_RELATIVE_PATH = path.join("runtime", "telemetry", "state.json");
|
|
50
52
|
const TELEMETRY_ENDPOINT_PROBE_TIMEOUT_MS = 2_500;
|
|
@@ -54,7 +56,7 @@ const TELEMETRY_SERVER_MAX_SCHEMA_VERSION_HEADERS = [
|
|
|
54
56
|
"x-pm-telemetry-max-schema-version",
|
|
55
57
|
"x-pm-telemetry-max-version",
|
|
56
58
|
];
|
|
57
|
-
/** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance
|
|
59
|
+
/** Advisory warnings are surfaced for visibility but never flip overall health to not-ok. Telemetry is opt-out, non-critical observability: a queued/unreachable telemetry endpoint or corrupt local telemetry state is not a project-health failure and must not block agents that gate on `pm health` `ok`. History over-compaction-threshold warnings are likewise advisory maintenance hints — a deep stream is healthy, just a candidate for `pm history-compact`. Invalid legacy provenance remains advisory until an operator explicitly applies the privacy-safe history normalizer. */
|
|
58
60
|
function isAdvisoryHealthWarning(warning, requireMergeDrivers = false) {
|
|
59
61
|
return (warning.startsWith("telemetry_") ||
|
|
60
62
|
warning.startsWith("history_stream_over_compact_threshold:") ||
|
|
@@ -612,6 +614,7 @@ async function buildExtensionCheck(pmRoot, settings, noExtensionsFlag) {
|
|
|
612
614
|
noExtensions: noExtensionsFlag,
|
|
613
615
|
});
|
|
614
616
|
const loadedSummaries = loadResult.loaded.map((extension) => summarizeLoadedExtension(extension));
|
|
617
|
+
const hostVersionCensus = await scanExtensionHostVersions(loadResult.loaded, resolveWorkspaceRoot(pmRoot));
|
|
615
618
|
const activationResult = await activateExtensions({
|
|
616
619
|
...loadResult,
|
|
617
620
|
loaded: loadResult.loaded,
|
|
@@ -696,6 +699,7 @@ async function buildExtensionCheck(pmRoot, settings, noExtensionsFlag) {
|
|
|
696
699
|
...projectManagedState.warnings,
|
|
697
700
|
...globalManagedState.warnings,
|
|
698
701
|
...updateCoverageWarnings,
|
|
702
|
+
...hostVersionCensus.warnings,
|
|
699
703
|
];
|
|
700
704
|
const capabilityGuidance = collectUnknownCapabilityGuidance(extensionWarnings);
|
|
701
705
|
const capabilityContract = buildCapabilityContractMetadata();
|
|
@@ -721,6 +725,7 @@ async function buildExtensionCheck(pmRoot, settings, noExtensionsFlag) {
|
|
|
721
725
|
: {}),
|
|
722
726
|
capability_contract: capabilityContract,
|
|
723
727
|
capability_guidance: capabilityGuidance,
|
|
728
|
+
host_version_census: hostVersionCensus,
|
|
724
729
|
},
|
|
725
730
|
},
|
|
726
731
|
warnings: extensionWarnings,
|
|
@@ -858,6 +863,7 @@ const HEALTH_DETAIL_SUMMARIZERS = {
|
|
|
858
863
|
triage: details.triage,
|
|
859
864
|
capability_contract: details.capability_contract,
|
|
860
865
|
capability_guidance: summarizeRecordList(details.capability_guidance, limit),
|
|
866
|
+
host_version_census: details.host_version_census,
|
|
861
867
|
};
|
|
862
868
|
},
|
|
863
869
|
storage: (details, limit) => {
|
|
@@ -917,6 +923,9 @@ const HEALTH_DETAIL_SUMMARIZERS = {
|
|
|
917
923
|
unreadable_streams: summarizeStringList(details.unreadable_streams, limit),
|
|
918
924
|
hash_mismatches: summarizeStringList(details.hash_mismatches, limit),
|
|
919
925
|
chain_mismatches: summarizeStringList(details.chain_mismatches, limit),
|
|
926
|
+
workspace_state_mismatches: summarizeStringList(details.workspace_state_mismatches, limit),
|
|
927
|
+
workspace_state_missing: summarizeStringList(details.workspace_state_missing, limit),
|
|
928
|
+
workspace_state_unreadable: summarizeStringList(details.workspace_state_unreadable, limit),
|
|
920
929
|
skipped: details.skipped,
|
|
921
930
|
}),
|
|
922
931
|
vectorization: (details, limit) => ({
|
|
@@ -958,6 +967,9 @@ function applyBriefHealthProjection(result) {
|
|
|
958
967
|
details: summarizeHealthCheckDetails(check, BRIEF_HEALTH_DETAIL_LIMIT),
|
|
959
968
|
})),
|
|
960
969
|
warnings: warningsSummary.sample,
|
|
970
|
+
findings: result.findings.filter((finding) => warningsSummary.sample.includes(finding.warning) ||
|
|
971
|
+
result.failed_because.includes(finding.warning)),
|
|
972
|
+
failed_because: result.failed_because,
|
|
961
973
|
projection: {
|
|
962
974
|
mode: "brief",
|
|
963
975
|
warning_count: warningsSummary.count,
|
|
@@ -987,6 +999,9 @@ function applySummaryHealthProjection(result) {
|
|
|
987
999
|
})),
|
|
988
1000
|
warning_count: warningsSummary.count,
|
|
989
1001
|
warnings: warningsSummary.sample,
|
|
1002
|
+
findings: result.findings.filter((finding) => warningsSummary.sample.includes(finding.warning) ||
|
|
1003
|
+
result.failed_because.includes(finding.warning)),
|
|
1004
|
+
failed_because: result.failed_because,
|
|
990
1005
|
projection: {
|
|
991
1006
|
mode: "summary",
|
|
992
1007
|
warning_count: warningsSummary.count,
|
|
@@ -1351,12 +1366,15 @@ async function buildLocksCheck(pmRoot) {
|
|
|
1351
1366
|
}
|
|
1352
1367
|
async function buildHistoryDriftCheck(pmRoot, items) {
|
|
1353
1368
|
const cacheHitVerification = "metadata";
|
|
1354
|
-
const { missingStreams, unreadableStreams, hashMismatches, chainMismatches, driftedItems, } = await scanHistoryDrift(pmRoot, items, { cacheHitVerification });
|
|
1369
|
+
const { missingStreams, unreadableStreams, hashMismatches, chainMismatches, driftedItems, workspaceStateMismatches, workspaceStateMissing, workspaceStateUnreadable, } = await scanHistoryDrift(pmRoot, items, { cacheHitVerification });
|
|
1355
1370
|
const warnings = [
|
|
1356
1371
|
...missingStreams.map((id) => `history_drift_missing_stream:${id}`),
|
|
1357
1372
|
...unreadableStreams.map((id) => `history_drift_unreadable_stream:${id}`),
|
|
1358
1373
|
...hashMismatches.map((id) => `history_drift_hash_mismatch:${id}`),
|
|
1359
1374
|
...chainMismatches.map((id) => `history_drift_chain_mismatch:${id}`),
|
|
1375
|
+
...workspaceStateMismatches.map((documentPath) => `history_drift_workspace_state_mismatch:${documentPath}`),
|
|
1376
|
+
...workspaceStateMissing.map((documentPath) => `history_drift_workspace_state_missing:${documentPath}`),
|
|
1377
|
+
...workspaceStateUnreadable.map((documentPath) => `history_drift_workspace_state_unreadable:${documentPath}`),
|
|
1360
1378
|
];
|
|
1361
1379
|
return {
|
|
1362
1380
|
check: {
|
|
@@ -1373,11 +1391,17 @@ async function buildHistoryDriftCheck(pmRoot, items) {
|
|
|
1373
1391
|
unreadable_streams: unreadableStreams.length,
|
|
1374
1392
|
hash_mismatches: hashMismatches.length,
|
|
1375
1393
|
chain_mismatches: chainMismatches.length,
|
|
1394
|
+
workspace_state_mismatches: workspaceStateMismatches.length,
|
|
1395
|
+
workspace_state_missing: workspaceStateMissing.length,
|
|
1396
|
+
workspace_state_unreadable: workspaceStateUnreadable.length,
|
|
1376
1397
|
},
|
|
1377
1398
|
missing_streams: missingStreams,
|
|
1378
1399
|
unreadable_streams: unreadableStreams,
|
|
1379
1400
|
hash_mismatches: hashMismatches,
|
|
1380
1401
|
chain_mismatches: chainMismatches,
|
|
1402
|
+
workspace_state_mismatches: workspaceStateMismatches,
|
|
1403
|
+
workspace_state_missing: workspaceStateMissing,
|
|
1404
|
+
workspace_state_unreadable: workspaceStateUnreadable,
|
|
1381
1405
|
},
|
|
1382
1406
|
},
|
|
1383
1407
|
warnings,
|
|
@@ -1807,22 +1831,62 @@ function extractHistoryDriftedCount(historyDriftCheck) {
|
|
|
1807
1831
|
function buildHealthRemediationSources(params) {
|
|
1808
1832
|
return {
|
|
1809
1833
|
settings: params.normalizedSettingsReadWarnings,
|
|
1810
|
-
directories: params.directoryState.missingDirs.map((dir) => `missing_directory:${dir}`),
|
|
1834
|
+
directories: params.directoryState.missingDirs.map((dir) => `missing_directory:${dir}`).concat(params.directoryState.hookWarnings),
|
|
1811
1835
|
settings_values: params.settingWarnings,
|
|
1812
1836
|
telemetry: params.telemetryCheck.warnings,
|
|
1813
1837
|
extensions: params.extensionCheck.warnings,
|
|
1814
1838
|
storage: [
|
|
1839
|
+
...params.historyPolicyWarnings,
|
|
1815
1840
|
...params.historySummary.over_threshold.map((id) => `history_stream_over_compact_threshold:${id}`),
|
|
1816
1841
|
...params.authorAttributionWarnings,
|
|
1817
1842
|
...params.staleInProgressWarnings,
|
|
1818
1843
|
...params.provenanceWarnings,
|
|
1819
1844
|
],
|
|
1820
1845
|
locks: params.locksCheck.warnings,
|
|
1821
|
-
integrity:
|
|
1846
|
+
integrity: [
|
|
1847
|
+
...params.normalizedItemReadWarnings,
|
|
1848
|
+
...params.integrityCheck.warnings,
|
|
1849
|
+
],
|
|
1822
1850
|
history_drift: params.historyDriftCheck.warnings,
|
|
1823
1851
|
vectorization: params.vectorizationCheck.warnings,
|
|
1824
1852
|
};
|
|
1825
1853
|
}
|
|
1854
|
+
/** Index every warning to exactly one health check, severity, and safe next action. */
|
|
1855
|
+
function buildHealthFindings(params) {
|
|
1856
|
+
const owners = new Map();
|
|
1857
|
+
for (const [check, warnings] of Object.entries(params.remediationSources)) {
|
|
1858
|
+
for (const warning of warnings) {
|
|
1859
|
+
if (!owners.has(warning))
|
|
1860
|
+
owners.set(warning, check);
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
const checksByName = new Map(params.checks.map((check) => [check.name, check]));
|
|
1864
|
+
const findings = params.warnings.map((warning) => {
|
|
1865
|
+
const check = owners.get(warning) ?? "integrity";
|
|
1866
|
+
const code = resolveRemediation(warning)?.code ?? warningCode(warning);
|
|
1867
|
+
const details = checksByName.get(check)?.details;
|
|
1868
|
+
const remediationMap = typeof details?.remediation_map === "object" &&
|
|
1869
|
+
details.remediation_map !== null
|
|
1870
|
+
? details.remediation_map
|
|
1871
|
+
: {};
|
|
1872
|
+
const remediation = remediationMap[code];
|
|
1873
|
+
const severity = isAdvisoryHealthWarning(warning, params.requireMergeDrivers)
|
|
1874
|
+
? "advisory"
|
|
1875
|
+
: "gate_failing";
|
|
1876
|
+
return {
|
|
1877
|
+
warning,
|
|
1878
|
+
code,
|
|
1879
|
+
check,
|
|
1880
|
+
severity,
|
|
1881
|
+
...(typeof remediation === "string"
|
|
1882
|
+
? { remediation }
|
|
1883
|
+
: severity === "gate_failing"
|
|
1884
|
+
? { disposition: "no_safe_automatic_remediation" }
|
|
1885
|
+
: {}),
|
|
1886
|
+
};
|
|
1887
|
+
});
|
|
1888
|
+
return findings;
|
|
1889
|
+
}
|
|
1826
1890
|
function rewriteBulkHealthRemediation(params) {
|
|
1827
1891
|
if (params.check.name === "history_drift" && params.historyDriftedCount > 1) {
|
|
1828
1892
|
for (const code of Object.keys(params.remediationMap)) {
|
|
@@ -1850,10 +1914,38 @@ function attachHealthRemediationMaps(params) {
|
|
|
1850
1914
|
}
|
|
1851
1915
|
}
|
|
1852
1916
|
function projectHealthResult(result, options, summaryMode) {
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1917
|
+
const warningCount = result.warning_count ?? result.warnings.length;
|
|
1918
|
+
const boundedResult = {
|
|
1919
|
+
...result,
|
|
1920
|
+
warning_count: warningCount,
|
|
1921
|
+
warning_limit: HEALTH_WARNING_LIMIT,
|
|
1922
|
+
warnings_truncated: warningCount > HEALTH_WARNING_LIMIT,
|
|
1923
|
+
warnings: result.warnings.slice(0, HEALTH_WARNING_LIMIT),
|
|
1924
|
+
findings: (result.findings ?? []).filter((finding) => result.warnings
|
|
1925
|
+
.slice(0, HEALTH_WARNING_LIMIT)
|
|
1926
|
+
.includes(finding.warning) ||
|
|
1927
|
+
result.failed_because.includes(finding.warning)),
|
|
1928
|
+
};
|
|
1929
|
+
const projected = summaryMode
|
|
1930
|
+
? applySummaryHealthProjection(boundedResult)
|
|
1931
|
+
: options.brief === true
|
|
1932
|
+
? applyBriefHealthProjection(boundedResult)
|
|
1933
|
+
: boundedResult;
|
|
1934
|
+
return {
|
|
1935
|
+
...projected,
|
|
1936
|
+
warning_count: warningCount,
|
|
1937
|
+
warning_limit: HEALTH_WARNING_LIMIT,
|
|
1938
|
+
warnings_truncated: warningCount > projected.warnings.length,
|
|
1939
|
+
...(projected.projection
|
|
1940
|
+
? {
|
|
1941
|
+
projection: {
|
|
1942
|
+
...projected.projection,
|
|
1943
|
+
warning_count: warningCount,
|
|
1944
|
+
warnings_truncated: warningCount > projected.warnings.length,
|
|
1945
|
+
},
|
|
1946
|
+
}
|
|
1947
|
+
: {}),
|
|
1948
|
+
};
|
|
1857
1949
|
}
|
|
1858
1950
|
/** Implements run health for the public runtime surface of this module. */
|
|
1859
1951
|
export async function runHealth(global, options = {}) {
|
|
@@ -1945,23 +2037,26 @@ export async function runHealth(global, options = {}) {
|
|
|
1945
2037
|
historyDriftCheck,
|
|
1946
2038
|
vectorizationCheck,
|
|
1947
2039
|
});
|
|
2040
|
+
const remediationSources = buildHealthRemediationSources({
|
|
2041
|
+
directoryState,
|
|
2042
|
+
normalizedSettingsReadWarnings,
|
|
2043
|
+
settingWarnings,
|
|
2044
|
+
normalizedItemReadWarnings,
|
|
2045
|
+
telemetryCheck,
|
|
2046
|
+
extensionCheck,
|
|
2047
|
+
historyPolicyWarnings: historyPolicy.warnings,
|
|
2048
|
+
historySummary,
|
|
2049
|
+
authorAttributionWarnings,
|
|
2050
|
+
staleInProgressWarnings: staleInProgress.warnings,
|
|
2051
|
+
provenanceWarnings,
|
|
2052
|
+
locksCheck,
|
|
2053
|
+
integrityCheck,
|
|
2054
|
+
historyDriftCheck,
|
|
2055
|
+
vectorizationCheck,
|
|
2056
|
+
});
|
|
1948
2057
|
attachHealthRemediationMaps({
|
|
1949
2058
|
checks,
|
|
1950
|
-
remediationSources
|
|
1951
|
-
directoryState,
|
|
1952
|
-
normalizedSettingsReadWarnings,
|
|
1953
|
-
settingWarnings,
|
|
1954
|
-
telemetryCheck,
|
|
1955
|
-
extensionCheck,
|
|
1956
|
-
historySummary,
|
|
1957
|
-
authorAttributionWarnings,
|
|
1958
|
-
staleInProgressWarnings: staleInProgress.warnings,
|
|
1959
|
-
provenanceWarnings,
|
|
1960
|
-
locksCheck,
|
|
1961
|
-
integrityCheck,
|
|
1962
|
-
historyDriftCheck,
|
|
1963
|
-
vectorizationCheck,
|
|
1964
|
-
}),
|
|
2059
|
+
remediationSources,
|
|
1965
2060
|
historyDriftedCount: extractHistoryDriftedCount(historyDriftCheck),
|
|
1966
2061
|
overThresholdCount: historySummary.over_threshold.length,
|
|
1967
2062
|
});
|
|
@@ -1970,10 +2065,18 @@ export async function runHealth(global, options = {}) {
|
|
|
1970
2065
|
// it must never flip overall project health to not-ok. Such warnings are still
|
|
1971
2066
|
// surfaced in `warnings` and the telemetry check's own `warn` status.
|
|
1972
2067
|
const blockingWarnings = normalizedWarnings.filter((warning) => !isAdvisoryHealthWarning(warning, options.requireMergeDrivers === true));
|
|
2068
|
+
const findings = buildHealthFindings({
|
|
2069
|
+
warnings: normalizedWarnings,
|
|
2070
|
+
checks,
|
|
2071
|
+
remediationSources,
|
|
2072
|
+
requireMergeDrivers: options.requireMergeDrivers === true,
|
|
2073
|
+
});
|
|
1973
2074
|
const result = {
|
|
1974
2075
|
ok: blockingWarnings.length === 0,
|
|
1975
2076
|
checks,
|
|
1976
2077
|
warnings: normalizedWarnings,
|
|
2078
|
+
findings,
|
|
2079
|
+
failed_because: blockingWarnings,
|
|
1977
2080
|
generated_at: nowIso(),
|
|
1978
2081
|
};
|
|
1979
2082
|
return projectHealthResult(result, options, skipPolicy.summaryMode);
|
|
@@ -1981,6 +2084,7 @@ export async function runHealth(global, options = {}) {
|
|
|
1981
2084
|
/** Public contract for test only health command, shared by SDK and presentation-layer consumers. */
|
|
1982
2085
|
export const _testOnlyHealthCommand = {
|
|
1983
2086
|
buildExtensionHealthTriageSummary,
|
|
2087
|
+
buildHealthFindings,
|
|
1984
2088
|
buildCapabilityContractMetadata,
|
|
1985
2089
|
buildStaleInProgressHealthSummary,
|
|
1986
2090
|
buildVectorizationProviderDetails,
|
|
@@ -2007,4 +2111,4 @@ export const _testOnlyHealthCommand = {
|
|
|
2007
2111
|
warningCode,
|
|
2008
2112
|
};
|
|
2009
2113
|
//# sourceMappingURL=health.js.map
|
|
2010
|
-
//# debugId=
|
|
2114
|
+
//# debugId=e7be701e-085c-5903-96da-61149452c673
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HistoryEntry } from "../../types/index.js";
|
|
1
2
|
/** Aggregated resolver attempts for one harness provenance dimension. */
|
|
2
3
|
export interface ProvenanceResolverHealthOutcome {
|
|
3
4
|
/** Detected harness namespace. */
|
|
@@ -35,5 +36,31 @@ export interface ProvenanceResolverHealthScan {
|
|
|
35
36
|
/** Whether an event or byte ceiling omitted history input. */
|
|
36
37
|
truncated: boolean;
|
|
37
38
|
}
|
|
39
|
+
/** Privacy-safe receipt for an explicit provenance normalization pass. */
|
|
40
|
+
export interface ProvenanceNormalizationReceipt {
|
|
41
|
+
/** Whether at least one immutable event required normalization. */
|
|
42
|
+
changed: boolean;
|
|
43
|
+
/** Immutable events whose invalid provenance observations were removed. */
|
|
44
|
+
events_changed: number;
|
|
45
|
+
/** Total invalid observations removed without retaining their values. */
|
|
46
|
+
observations_removed: number;
|
|
47
|
+
/** Aggregate invalid-value classes removed by the pass. */
|
|
48
|
+
invalid_values: ProvenanceValueHealthFinding[];
|
|
49
|
+
}
|
|
50
|
+
/** Normalized entries plus the privacy-safe mutation receipt. */
|
|
51
|
+
export interface ProvenanceNormalizationResult {
|
|
52
|
+
/** History entries with invalid bounded observations removed. */
|
|
53
|
+
entries: HistoryEntry[];
|
|
54
|
+
/** Aggregate mutation receipt; never includes an observed value. */
|
|
55
|
+
receipt: ProvenanceNormalizationReceipt;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Remove only provenance observations whose values violate the bounded domain.
|
|
59
|
+
* History operations, patches, timestamps, authors, and hashes are retained;
|
|
60
|
+
* the receipt exposes aggregate classes and counts but never the removed value.
|
|
61
|
+
*/
|
|
62
|
+
export declare function normalizeInvalidHistoryProvenance(entries: HistoryEntry[]): ProvenanceNormalizationResult;
|
|
63
|
+
/** Find every history stream requiring provenance normalization without returning raw values. */
|
|
64
|
+
export declare function listInvalidProvenanceHistoryStreamIds(pmRoot: string): Promise<string[]>;
|
|
38
65
|
/** Scan immutable history without failing over malformed streams owned by integrity checks. */
|
|
39
66
|
export declare function scanProvenanceResolverHealth(pmRoot: string, eventLimit?: number): Promise<ProvenanceResolverHealthScan>;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Reads bounded, privacy-safe provenance resolver outcomes for health checks.
|
|
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]="6efed404-acd2-5c3a-a008-856df67c8b77")}catch(e){}}();
|
|
8
8
|
import fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
const DEFAULT_PROVENANCE_HISTORY_BYTE_LIMIT = 8_388_608;
|
|
@@ -27,6 +27,98 @@ const INVALID_PROVENANCE_VALUE_CLASSIFIERS = [
|
|
|
27
27
|
function isRecord(value) {
|
|
28
28
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29
29
|
}
|
|
30
|
+
function invalidProvenanceValueKind(value) {
|
|
31
|
+
return INVALID_PROVENANCE_VALUE_CLASSIFIERS.find((classifier) => classifier.matches(value))?.kind;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Remove only provenance observations whose values violate the bounded domain.
|
|
35
|
+
* History operations, patches, timestamps, authors, and hashes are retained;
|
|
36
|
+
* the receipt exposes aggregate classes and counts but never the removed value.
|
|
37
|
+
*/
|
|
38
|
+
export function normalizeInvalidHistoryProvenance(entries) {
|
|
39
|
+
const invalidValues = new Map();
|
|
40
|
+
let eventsChanged = 0;
|
|
41
|
+
let observationsRemoved = 0;
|
|
42
|
+
const normalized = entries.map((entry) => {
|
|
43
|
+
const provenance = isRecord(entry.agent_provenance)
|
|
44
|
+
? entry.agent_provenance
|
|
45
|
+
: undefined;
|
|
46
|
+
if (provenance === undefined)
|
|
47
|
+
return entry;
|
|
48
|
+
const retained = {};
|
|
49
|
+
let eventChanged = false;
|
|
50
|
+
for (const [dimension, observation] of Object.entries(provenance)) {
|
|
51
|
+
const kind = isRecord(observation)
|
|
52
|
+
? invalidProvenanceValueKind(observation.value)
|
|
53
|
+
: undefined;
|
|
54
|
+
if (kind === undefined) {
|
|
55
|
+
retained[dimension] = observation;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
eventChanged = true;
|
|
59
|
+
observationsRemoved += 1;
|
|
60
|
+
const harness = entry.agent_harness ?? "unknown";
|
|
61
|
+
const key = `${harness}\0${dimension}\0${kind}`;
|
|
62
|
+
const aggregate = invalidValues.get(key) ?? {
|
|
63
|
+
harness,
|
|
64
|
+
dimension,
|
|
65
|
+
kind,
|
|
66
|
+
count: 0,
|
|
67
|
+
};
|
|
68
|
+
aggregate.count += 1;
|
|
69
|
+
invalidValues.set(key, aggregate);
|
|
70
|
+
}
|
|
71
|
+
if (!eventChanged)
|
|
72
|
+
return entry;
|
|
73
|
+
eventsChanged += 1;
|
|
74
|
+
const next = { ...entry };
|
|
75
|
+
if (Object.keys(retained).length === 0) {
|
|
76
|
+
delete next.agent_provenance;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
next.agent_provenance = retained;
|
|
80
|
+
}
|
|
81
|
+
return next;
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
entries: normalized,
|
|
85
|
+
receipt: {
|
|
86
|
+
changed: eventsChanged > 0,
|
|
87
|
+
events_changed: eventsChanged,
|
|
88
|
+
observations_removed: observationsRemoved,
|
|
89
|
+
invalid_values: [...invalidValues.values()].sort((left, right) => left.harness.localeCompare(right.harness) ||
|
|
90
|
+
left.dimension.localeCompare(right.dimension) ||
|
|
91
|
+
left.kind.localeCompare(right.kind)),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** Find every history stream requiring provenance normalization without returning raw values. */
|
|
96
|
+
export async function listInvalidProvenanceHistoryStreamIds(pmRoot) {
|
|
97
|
+
const ids = [];
|
|
98
|
+
for (const file of await listHistoryFiles(pmRoot)) {
|
|
99
|
+
try {
|
|
100
|
+
const content = await fs.readFile(path.join(pmRoot, "history", file), "utf8");
|
|
101
|
+
for (const line of content.split("\n")) {
|
|
102
|
+
if (line.trim().length === 0)
|
|
103
|
+
continue;
|
|
104
|
+
const entry = parseHistoryEntry(line);
|
|
105
|
+
if (entry === null || !isRecord(entry.agent_provenance))
|
|
106
|
+
continue;
|
|
107
|
+
const invalid = Object.values(entry.agent_provenance).some((observation) => isRecord(observation) &&
|
|
108
|
+
invalidProvenanceValueKind(observation.value) !== undefined);
|
|
109
|
+
if (invalid) {
|
|
110
|
+
ids.push(file.slice(0, -".jsonl".length));
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Integrity diagnostics own unreadable or malformed streams. This census
|
|
117
|
+
// only selects safely parseable streams for the explicit normalizer.
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return ids;
|
|
121
|
+
}
|
|
30
122
|
async function listHistoryFiles(pmRoot) {
|
|
31
123
|
try {
|
|
32
124
|
return (await fs.readdir(path.join(pmRoot, "history")))
|
|
@@ -84,7 +176,7 @@ function collectResolverOutcomes(entry, aggregates, invalidValues) {
|
|
|
84
176
|
Object.entries(provenance).forEach(([dimension, observation]) => {
|
|
85
177
|
if (!isRecord(observation))
|
|
86
178
|
return;
|
|
87
|
-
const kind =
|
|
179
|
+
const kind = invalidProvenanceValueKind(observation.value);
|
|
88
180
|
if (!kind)
|
|
89
181
|
return;
|
|
90
182
|
const key = `${harness}\0${dimension}\0${kind}`;
|
|
@@ -182,4 +274,4 @@ export async function scanProvenanceResolverHealth(pmRoot, eventLimit = 10_000)
|
|
|
182
274
|
};
|
|
183
275
|
}
|
|
184
276
|
//# sourceMappingURL=provenance-health.js.map
|
|
185
|
-
//# debugId=
|
|
277
|
+
//# debugId=6efed404-acd2-5c3a-a008-856df67c8b77
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ValidateCheck } from "./validate.js";
|
|
2
|
+
import type { ValidateItem } from "./validate-item-reader.js";
|
|
3
|
+
/** Build the validation warning and bounded evidence projection for history drift. */
|
|
4
|
+
export declare function buildValidateHistoryDriftCheck(pmRoot: string, items: ValidateItem[], verboseDiagnostics: boolean): Promise<{
|
|
5
|
+
check: ValidateCheck;
|
|
6
|
+
warnings: string[];
|
|
7
|
+
}>;
|