@unbrained/pm-cli 2026.8.14 → 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 +25 -2
- 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 +3 -2
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +5 -5
- package/dist/cli-bundle/bundle-manifest.json +150 -150
- package/dist/cli-bundle/chunks/{chunk-TXMEUUUY.js → chunk-24GAV7XL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-TMJ7URWS.js → chunk-AIM6VT2N.js} +9 -9
- package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-FIW4P64F.js → chunk-J42EGKDK.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-SBRKH6OR.js → chunk-KLKYLSDX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-G5JUB66K.js → chunk-LJHOAVGI.js} +59 -59
- package/dist/cli-bundle/chunks/{chunk-BFALV3YP.js → chunk-MEM2ZS3O.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-XAVMOK6B.js → chunk-WLPDLNEZ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-T3EHHNNV.js → register-list-query-CT3LFDDN.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-E27WCLSZ.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-3YXZ444E.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-XDNAW5OI.js → chunk-6XKF3PGV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-WCVE2NIG.js → chunk-EXZA4257.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4DQ2YERC.js → chunk-KLVUMNXJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-K7RWWOAG.js → chunk-KT5XMYSX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-PPFGQDSI.js → chunk-KTKH4IMG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KSEDUWVZ.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-LZ4MV3RH.js → chunk-SLKC6QLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KFSZ3BP6.js → chunk-WTSER4WJ.js} +6 -6
- package/dist/cli-bundle/focused-chunks/{chunk-YOOI3UZX.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 +32 -35
- 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 +32 -31
- 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/replay.d.ts +14 -1
- package/dist/core/history/replay.js +45 -8
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +3 -2
- 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 +5 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +23 -7
- 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 +3 -2
- 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 +80 -14
- 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 +119 -27
- package/dist/sdk/governance/provenance-health.d.ts +27 -0
- package/dist/sdk/governance/provenance-health.js +95 -3
- package/dist/sdk/governance/validate.js +7 -8
- package/dist/sdk/governance.d.ts +6 -0
- package/dist/sdk/governance.js +8 -2
- package/dist/sdk/history-repair.d.ts +13 -1
- package/dist/sdk/history-repair.js +62 -18
- 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/read-output/continuation.d.ts +11 -0
- package/dist/sdk/read-output/continuation.js +132 -0
- package/dist/sdk/read-output-budget.d.ts +1 -1
- package/dist/sdk/read-output-budget.js +14 -10
- package/dist/sdk/read-output-contracts.d.ts +66 -2
- package/dist/sdk/read-output-contracts.js +183 -19
- package/dist/sdk/read-output-rows.d.ts +2 -0
- package/dist/sdk/read-output-rows.js +15 -2
- package/dist/sdk/runtime-input.js +4 -2
- package/docs/ASSURANCE.md +59 -2
- package/docs/COMMANDS.md +8 -2
- package/docs/READ_OUTPUT_CONTRACTS.md +49 -8
- package/docs/RELEASING.md +42 -5
- package/docs/SDK_CONTEXT_INTEGRITY.md +64 -2
- package/marketplace.json +2 -2
- package/package.json +3 -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/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/sdk/public-surface.json +1133 -187
- package/dist/cli-bundle/chunks/chunk-BBOFSVAK.js +0 -197
- package/dist/cli-bundle/chunks/chunk-YAMTJL6Y.js +0 -34
- package/dist/cli-bundle/chunks/chunk-YSVSMJ2B.js +0 -2
- package/dist/cli-bundle/chunks/register-operations-4R6I7CPY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-F43TT2QQ.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-KYUQGTSB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PGXJQLCT.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-Q4YY3XNF.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QK753U3U.js +0 -46
- package/dist/cli-bundle/focused-chunks/chunk-QUMB2J27.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-SM7MTG27.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZM6TZVHC.js +0 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* one deterministic SDK path.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!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]="
|
|
10
|
+
!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]="2bf52d6d-7e4f-5ec5-86bd-3e817ef521bb")}catch(e){}}();
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
@@ -15,7 +15,7 @@ import { PmCliError } from "../../core/shared/errors.js";
|
|
|
15
15
|
import { appendWorkspaceAuditEvent, mutateWorkspaceJsonWithHistory, readFileIfExists, readHistoryEntries, readSettings, resolveAuthor, stableStringify, WORKSPACE_HISTORY_ID, getWorkspaceHistoryPath, } from "../runtime-primitives.js";
|
|
16
16
|
import { resolveCanonicalRelationshipKind } from "../relationships.js";
|
|
17
17
|
import { MAX_ASSURANCE_VERDICT_LIMIT } from "./assurance-limits.js";
|
|
18
|
-
import { AssuranceEvaluationRefusalError, AssuranceMutationRefusalError, } from "./assurance-mutation-error.js";
|
|
18
|
+
import { AssuranceEvaluationRefusalError, AssuranceMutationRefusalError, AssuranceSourceResolutionError, } from "./assurance-mutation-error.js";
|
|
19
19
|
/** Current serialized assurance registry format. */
|
|
20
20
|
export const ASSURANCE_DOCUMENT_VERSION = 1;
|
|
21
21
|
/** Supported lifecycle points that can evaluate a gate. */
|
|
@@ -30,6 +30,18 @@ export const ASSURANCE_GATE_TRIGGERS = [
|
|
|
30
30
|
"on-claim",
|
|
31
31
|
"on-close",
|
|
32
32
|
];
|
|
33
|
+
/** Supported discriminants for built-in, delegated, and derived measurements. */
|
|
34
|
+
export const ASSURANCE_MEASUREMENT_SOURCE_KINDS = [
|
|
35
|
+
"items",
|
|
36
|
+
"dependency_kind",
|
|
37
|
+
"graph",
|
|
38
|
+
"validate",
|
|
39
|
+
"health",
|
|
40
|
+
"history",
|
|
41
|
+
"links",
|
|
42
|
+
"provider",
|
|
43
|
+
"derived",
|
|
44
|
+
];
|
|
33
45
|
const POLARITY_KEYS = [
|
|
34
46
|
"ceiling",
|
|
35
47
|
"floor",
|
|
@@ -161,7 +173,15 @@ export function validateMeasurementDefinition(definition) {
|
|
|
161
173
|
if (definition.max_cost !== undefined) {
|
|
162
174
|
requireFiniteNonNegative(definition.max_cost, "measurement.max_cost");
|
|
163
175
|
}
|
|
164
|
-
const
|
|
176
|
+
const candidateSource = definition.source;
|
|
177
|
+
if (Object.prototype.toString.call(candidateSource) !== "[object Object]") {
|
|
178
|
+
throw new AssuranceMutationRefusalError(`measurement.source.kind must be one of ${ASSURANCE_MEASUREMENT_SOURCE_KINDS.join(", ")}`);
|
|
179
|
+
}
|
|
180
|
+
const sourceKind = Reflect.get(candidateSource, "kind");
|
|
181
|
+
if (!ASSURANCE_MEASUREMENT_SOURCE_KINDS.includes(sourceKind)) {
|
|
182
|
+
throw new AssuranceMutationRefusalError(`measurement.source.kind must be one of ${ASSURANCE_MEASUREMENT_SOURCE_KINDS.join(", ")}`);
|
|
183
|
+
}
|
|
184
|
+
const source = candidateSource;
|
|
165
185
|
if (source.kind === "items") {
|
|
166
186
|
validateItemsMeasurementSource(source);
|
|
167
187
|
}
|
|
@@ -240,14 +260,25 @@ function validateGateProviderPolicy(policy) {
|
|
|
240
260
|
/** Validate and return one gate declaration. */
|
|
241
261
|
export function validateGateDefinition(definition) {
|
|
242
262
|
requireStableId(definition.id, "gate.id");
|
|
263
|
+
if (!Array.isArray(definition.assertion_ids)) {
|
|
264
|
+
throw new AssuranceMutationRefusalError("gate.assertion_ids is required and must be an array");
|
|
265
|
+
}
|
|
243
266
|
if (definition.assertion_ids.length === 0) {
|
|
244
267
|
throw new AssuranceMutationRefusalError("gate requires at least one assertion");
|
|
245
268
|
}
|
|
246
269
|
for (const id of definition.assertion_ids)
|
|
247
270
|
requireStableId(id, "gate.assertion_id");
|
|
271
|
+
if (!Array.isArray(definition.triggers)) {
|
|
272
|
+
throw new AssuranceMutationRefusalError(`gate.triggers is required and must be an array of ${ASSURANCE_GATE_TRIGGERS.join(", ")}`);
|
|
273
|
+
}
|
|
248
274
|
if (definition.triggers.length === 0) {
|
|
249
275
|
throw new AssuranceMutationRefusalError("gate requires at least one trigger");
|
|
250
276
|
}
|
|
277
|
+
for (const trigger of definition.triggers) {
|
|
278
|
+
if (!ASSURANCE_GATE_TRIGGERS.includes(trigger)) {
|
|
279
|
+
throw new AssuranceMutationRefusalError(`gate trigger must be one of ${ASSURANCE_GATE_TRIGGERS.join(", ")}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
251
282
|
if (definition.provider_policy) {
|
|
252
283
|
validateGateProviderPolicy(definition.provider_policy);
|
|
253
284
|
}
|
|
@@ -543,16 +574,10 @@ async function evaluateMeasurementInternal(definition, context, definitions, sta
|
|
|
543
574
|
if (builtin !== null) {
|
|
544
575
|
result = builtin;
|
|
545
576
|
}
|
|
546
|
-
else
|
|
547
|
-
definition.source.kind === "validate" ||
|
|
548
|
-
definition.source.kind === "health" ||
|
|
549
|
-
definition.source.kind === "provider") {
|
|
577
|
+
else {
|
|
550
578
|
result = await context.external(definition.source);
|
|
551
579
|
providerCalls = 1;
|
|
552
580
|
}
|
|
553
|
-
else {
|
|
554
|
-
throw new TypeError(`unsupported assurance source ${definition.source.kind}`);
|
|
555
|
-
}
|
|
556
581
|
}
|
|
557
582
|
const ownCost = {
|
|
558
583
|
units: result.cost,
|
|
@@ -587,7 +612,21 @@ function evaluateMeasurementCached(definition, context, definitions, stack, stat
|
|
|
587
612
|
const cached = state.cache.get(definition.id);
|
|
588
613
|
if (cached)
|
|
589
614
|
return cached;
|
|
590
|
-
const evaluation = evaluateMeasurementInternal(definition, context, definitions, stack, state)
|
|
615
|
+
const evaluation = evaluateMeasurementInternal(definition, context, definitions, stack, state).catch((error) => {
|
|
616
|
+
if (error instanceof AssuranceSourceResolutionError &&
|
|
617
|
+
error.measurement_id === undefined) {
|
|
618
|
+
const sourceContext = {
|
|
619
|
+
measurement_id: definition.id,
|
|
620
|
+
source_kind: error.source_kind,
|
|
621
|
+
field: error.field,
|
|
622
|
+
...(error.check ? { check: error.check } : {}),
|
|
623
|
+
};
|
|
624
|
+
const sourceError = new AssuranceSourceResolutionError(error.message, sourceContext);
|
|
625
|
+
sourceError.cause = error;
|
|
626
|
+
throw sourceError;
|
|
627
|
+
}
|
|
628
|
+
throw error;
|
|
629
|
+
});
|
|
591
630
|
state.cache.set(definition.id, evaluation);
|
|
592
631
|
return evaluation;
|
|
593
632
|
}
|
|
@@ -664,6 +703,28 @@ function enforceGateProviderPolicy(gate, document, context, trigger) {
|
|
|
664
703
|
}
|
|
665
704
|
}
|
|
666
705
|
}
|
|
706
|
+
async function evaluateGateMeasurement(gateId, assertionId, definition, context, definitions) {
|
|
707
|
+
try {
|
|
708
|
+
return await evaluateMeasurement(definition, context, definitions);
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
if (error instanceof AssuranceSourceResolutionError) {
|
|
712
|
+
const checkLocation = error.check ? ` check ${error.check}` : "";
|
|
713
|
+
const measurementId = error.measurement_id ?? definition.id;
|
|
714
|
+
const refusal = new AssuranceEvaluationRefusalError(`assurance gate ${gateId} assertion ${assertionId} measurement ${measurementId} source ${error.source_kind}${checkLocation} field ${error.field} could not resolve: ${error.message}`, {
|
|
715
|
+
gate_id: gateId,
|
|
716
|
+
assertion_id: assertionId,
|
|
717
|
+
measurement_id: measurementId,
|
|
718
|
+
source_kind: error.source_kind,
|
|
719
|
+
field: error.field,
|
|
720
|
+
...(error.check ? { check: error.check } : {}),
|
|
721
|
+
});
|
|
722
|
+
refusal.cause = error;
|
|
723
|
+
throw refusal;
|
|
724
|
+
}
|
|
725
|
+
throw error;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
667
728
|
/** Evaluate a named gate into one presentation-independent verdict document. */
|
|
668
729
|
export async function evaluateAssuranceGate(gateId, document, context, options) {
|
|
669
730
|
validateAssuranceDocument(document);
|
|
@@ -688,7 +749,7 @@ export async function evaluateAssuranceGate(gateId, document, context, options)
|
|
|
688
749
|
else if (assertionDefinition.scope.kind === "filter") {
|
|
689
750
|
const scopeMeasurementId = assertionDefinition.scope.measurement_id;
|
|
690
751
|
const scopeDefinition = document.measurements.find((entry) => entry.id === scopeMeasurementId);
|
|
691
|
-
const scope = await
|
|
752
|
+
const scope = await evaluateGateMeasurement(gateDefinition.id, assertionDefinition.id, scopeDefinition, context, document.measurements);
|
|
692
753
|
const contributorIds = new Set(scope.contributors);
|
|
693
754
|
scopedContext = {
|
|
694
755
|
...context,
|
|
@@ -698,7 +759,7 @@ export async function evaluateAssuranceGate(gateId, document, context, options)
|
|
|
698
759
|
const owner = context.items.find((item) => item.id === assertionDefinition.owner_item_id);
|
|
699
760
|
const ownerTerminal = owner !== undefined &&
|
|
700
761
|
new Set(context.terminal_statuses ?? ["closed", "canceled"]).has(owner.status);
|
|
701
|
-
return evaluateAssuranceAssertion(assertionDefinition, await
|
|
762
|
+
return evaluateAssuranceAssertion(assertionDefinition, await evaluateGateMeasurement(gateDefinition.id, assertionDefinition.id, measurementDefinition, scopedContext, document.measurements), { owner_terminal: ownerTerminal });
|
|
702
763
|
});
|
|
703
764
|
const blocking = assertions.some((entry) => entry.verdict === "fail" && entry.enforcement === "block");
|
|
704
765
|
const warning = assertions.some((entry) => entry.verdict === "fail" && entry.enforcement === "warn");
|
|
@@ -711,6 +772,11 @@ export async function evaluateAssuranceGate(gateId, document, context, options)
|
|
|
711
772
|
verdict: blocking ? "block" : warning ? "warn" : "pass",
|
|
712
773
|
exit_code: blocking ? 1 : 0,
|
|
713
774
|
assertions,
|
|
775
|
+
assertions_total: assertions.length,
|
|
776
|
+
row_contract: {
|
|
777
|
+
row_keys: ["assertions"],
|
|
778
|
+
jq_selector: ".assertions[]",
|
|
779
|
+
},
|
|
714
780
|
cost: sumCosts(assertions.map((entry) => entry.cost), Math.max(0, ...assertions.map((entry) => entry.cost.duration_ms))),
|
|
715
781
|
};
|
|
716
782
|
}
|
|
@@ -940,4 +1006,4 @@ export async function listAssuranceVerdicts(pmRoot, options = {}) {
|
|
|
940
1006
|
.slice(0, limit);
|
|
941
1007
|
}
|
|
942
1008
|
//# sourceMappingURL=assurance.js.map
|
|
943
|
-
//# debugId=
|
|
1009
|
+
//# debugId=2bf52d6d-7e4f-5ec5-86bd-3e817ef521bb
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { LoadedExtension } from "../../core/extensions/loader.js";
|
|
2
|
+
/** One distinct resolvable pm-cli installation and its extension consumers. */
|
|
3
|
+
export interface ExtensionHostVersionCopy {
|
|
4
|
+
/** Installed pm-cli version. */
|
|
5
|
+
version: string;
|
|
6
|
+
/** Privacy-safe workspace-relative package manifest location. */
|
|
7
|
+
path: string;
|
|
8
|
+
/** Dependency layout that exposed this copy. */
|
|
9
|
+
layout: "host" | "npm" | "pnpm" | "other";
|
|
10
|
+
/** Loaded extensions resolving this copy. */
|
|
11
|
+
consumers: string[];
|
|
12
|
+
}
|
|
13
|
+
/** Extension/host version census returned by the health SDK. */
|
|
14
|
+
export interface ExtensionHostVersionCensus {
|
|
15
|
+
/** Version of the process-hosting pm-cli package. */
|
|
16
|
+
host_version: string | null;
|
|
17
|
+
/** Every distinct relevant copy resolved by the host or an extension. */
|
|
18
|
+
copies: ExtensionHostVersionCopy[];
|
|
19
|
+
/** Copies whose version differs from the process host. */
|
|
20
|
+
mismatches: ExtensionHostVersionCopy[];
|
|
21
|
+
/** Stable health warning tokens for mismatched copies. */
|
|
22
|
+
warnings: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Scan the host plus the nearest pm-cli package resolvable by every loaded extension. */
|
|
25
|
+
export declare function scanExtensionHostVersions(loadedExtensions: readonly LoadedExtension[], workspaceRoot: string, hostPackageRoot?: string): Promise<ExtensionHostVersionCensus>;
|
|
@@ -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) => {
|
|
@@ -961,6 +967,9 @@ function applyBriefHealthProjection(result) {
|
|
|
961
967
|
details: summarizeHealthCheckDetails(check, BRIEF_HEALTH_DETAIL_LIMIT),
|
|
962
968
|
})),
|
|
963
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,
|
|
964
973
|
projection: {
|
|
965
974
|
mode: "brief",
|
|
966
975
|
warning_count: warningsSummary.count,
|
|
@@ -990,6 +999,9 @@ function applySummaryHealthProjection(result) {
|
|
|
990
999
|
})),
|
|
991
1000
|
warning_count: warningsSummary.count,
|
|
992
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,
|
|
993
1005
|
projection: {
|
|
994
1006
|
mode: "summary",
|
|
995
1007
|
warning_count: warningsSummary.count,
|
|
@@ -1819,22 +1831,62 @@ function extractHistoryDriftedCount(historyDriftCheck) {
|
|
|
1819
1831
|
function buildHealthRemediationSources(params) {
|
|
1820
1832
|
return {
|
|
1821
1833
|
settings: params.normalizedSettingsReadWarnings,
|
|
1822
|
-
directories: params.directoryState.missingDirs.map((dir) => `missing_directory:${dir}`),
|
|
1834
|
+
directories: params.directoryState.missingDirs.map((dir) => `missing_directory:${dir}`).concat(params.directoryState.hookWarnings),
|
|
1823
1835
|
settings_values: params.settingWarnings,
|
|
1824
1836
|
telemetry: params.telemetryCheck.warnings,
|
|
1825
1837
|
extensions: params.extensionCheck.warnings,
|
|
1826
1838
|
storage: [
|
|
1839
|
+
...params.historyPolicyWarnings,
|
|
1827
1840
|
...params.historySummary.over_threshold.map((id) => `history_stream_over_compact_threshold:${id}`),
|
|
1828
1841
|
...params.authorAttributionWarnings,
|
|
1829
1842
|
...params.staleInProgressWarnings,
|
|
1830
1843
|
...params.provenanceWarnings,
|
|
1831
1844
|
],
|
|
1832
1845
|
locks: params.locksCheck.warnings,
|
|
1833
|
-
integrity:
|
|
1846
|
+
integrity: [
|
|
1847
|
+
...params.normalizedItemReadWarnings,
|
|
1848
|
+
...params.integrityCheck.warnings,
|
|
1849
|
+
],
|
|
1834
1850
|
history_drift: params.historyDriftCheck.warnings,
|
|
1835
1851
|
vectorization: params.vectorizationCheck.warnings,
|
|
1836
1852
|
};
|
|
1837
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
|
+
}
|
|
1838
1890
|
function rewriteBulkHealthRemediation(params) {
|
|
1839
1891
|
if (params.check.name === "history_drift" && params.historyDriftedCount > 1) {
|
|
1840
1892
|
for (const code of Object.keys(params.remediationMap)) {
|
|
@@ -1862,10 +1914,38 @@ function attachHealthRemediationMaps(params) {
|
|
|
1862
1914
|
}
|
|
1863
1915
|
}
|
|
1864
1916
|
function projectHealthResult(result, options, summaryMode) {
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
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
|
+
};
|
|
1869
1949
|
}
|
|
1870
1950
|
/** Implements run health for the public runtime surface of this module. */
|
|
1871
1951
|
export async function runHealth(global, options = {}) {
|
|
@@ -1957,23 +2037,26 @@ export async function runHealth(global, options = {}) {
|
|
|
1957
2037
|
historyDriftCheck,
|
|
1958
2038
|
vectorizationCheck,
|
|
1959
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
|
+
});
|
|
1960
2057
|
attachHealthRemediationMaps({
|
|
1961
2058
|
checks,
|
|
1962
|
-
remediationSources
|
|
1963
|
-
directoryState,
|
|
1964
|
-
normalizedSettingsReadWarnings,
|
|
1965
|
-
settingWarnings,
|
|
1966
|
-
telemetryCheck,
|
|
1967
|
-
extensionCheck,
|
|
1968
|
-
historySummary,
|
|
1969
|
-
authorAttributionWarnings,
|
|
1970
|
-
staleInProgressWarnings: staleInProgress.warnings,
|
|
1971
|
-
provenanceWarnings,
|
|
1972
|
-
locksCheck,
|
|
1973
|
-
integrityCheck,
|
|
1974
|
-
historyDriftCheck,
|
|
1975
|
-
vectorizationCheck,
|
|
1976
|
-
}),
|
|
2059
|
+
remediationSources,
|
|
1977
2060
|
historyDriftedCount: extractHistoryDriftedCount(historyDriftCheck),
|
|
1978
2061
|
overThresholdCount: historySummary.over_threshold.length,
|
|
1979
2062
|
});
|
|
@@ -1982,10 +2065,18 @@ export async function runHealth(global, options = {}) {
|
|
|
1982
2065
|
// it must never flip overall project health to not-ok. Such warnings are still
|
|
1983
2066
|
// surfaced in `warnings` and the telemetry check's own `warn` status.
|
|
1984
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
|
+
});
|
|
1985
2074
|
const result = {
|
|
1986
2075
|
ok: blockingWarnings.length === 0,
|
|
1987
2076
|
checks,
|
|
1988
2077
|
warnings: normalizedWarnings,
|
|
2078
|
+
findings,
|
|
2079
|
+
failed_because: blockingWarnings,
|
|
1989
2080
|
generated_at: nowIso(),
|
|
1990
2081
|
};
|
|
1991
2082
|
return projectHealthResult(result, options, skipPolicy.summaryMode);
|
|
@@ -1993,6 +2084,7 @@ export async function runHealth(global, options = {}) {
|
|
|
1993
2084
|
/** Public contract for test only health command, shared by SDK and presentation-layer consumers. */
|
|
1994
2085
|
export const _testOnlyHealthCommand = {
|
|
1995
2086
|
buildExtensionHealthTriageSummary,
|
|
2087
|
+
buildHealthFindings,
|
|
1996
2088
|
buildCapabilityContractMetadata,
|
|
1997
2089
|
buildStaleInProgressHealthSummary,
|
|
1998
2090
|
buildVectorizationProviderDetails,
|
|
@@ -2019,4 +2111,4 @@ export const _testOnlyHealthCommand = {
|
|
|
2019
2111
|
warningCode,
|
|
2020
2112
|
};
|
|
2021
2113
|
//# sourceMappingURL=health.js.map
|
|
2022
|
-
//# debugId=
|
|
2114
|
+
//# debugId=e7be701e-085c-5903-96da-61149452c673
|