@unbrained/pm-cli 2026.8.11 → 2026.8.13
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 +74 -21
- package/dist/cli/commander-usage.js +37 -11
- package/dist/cli/error-guidance.d.ts +2 -0
- package/dist/cli/error-guidance.js +82 -19
- package/dist/cli/main.js +35 -19
- package/dist/cli/register-annotations.js +56 -3
- package/dist/cli/register-assurance.js +28 -17
- package/dist/cli/register-list-query.js +10 -7
- package/dist/cli/register-operations.js +16 -6
- package/dist/cli-bundle/bundle-manifest.json +163 -163
- package/dist/cli-bundle/chunks/chunk-3ZMOWAFM.js +2 -0
- package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +196 -0
- package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +13 -0
- package/dist/cli-bundle/chunks/chunk-F7FJYGK3.js +8 -0
- package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +5 -0
- package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-A2SJGHSI.js → chunk-Q47C67TQ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WMEZHCFI.js → chunk-QGTUPEU5.js} +62 -54
- package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +34 -0
- package/dist/cli-bundle/chunks/{chunk-ZU34C3LH.js → chunk-YLBAPY22.js} +50 -50
- package/dist/cli-bundle/chunks/register-list-query-4HIZ7EA3.js +10 -0
- package/dist/cli-bundle/chunks/register-mutation-W64FZ5HN.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-NOCOOWQY.js → register-setup-634MFRXU.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +31 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4H5IA6AV.js → chunk-2JP7W7GO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-2RI2FESN.js +4 -0
- package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2DL3MRTD.js → chunk-3DJSGWVB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +5 -0
- package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +155 -0
- package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TL5M2PAY.js → chunk-E3AVJ655.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-J5EKAIVD.js → chunk-HC2OL2H2.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-BKPIY34S.js → chunk-I75MANL7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-IIS2FRKL.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +17 -0
- package/dist/cli-bundle/focused-chunks/{chunk-UDAZWT25.js → chunk-OOYYKQWX.js} +4 -4
- package/dist/cli-bundle/focused-chunks/{chunk-23FTGO3W.js → chunk-PKPOZXLL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-55BIB6DV.js → chunk-TEZIXMTH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +18 -0
- 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 +42 -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 +1 -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/checkpoint/checkpoint-gc.js +7 -12
- package/dist/core/extensions/activation-summary-markdown.js +5 -4
- package/dist/core/extensions/activation-summary.d.ts +2 -0
- package/dist/core/extensions/activation-summary.js +6 -2
- package/dist/core/extensions/capability-usage.d.ts +1 -1
- package/dist/core/extensions/capability-usage.js +4 -3
- package/dist/core/extensions/contribution-inventory.d.ts +1 -0
- package/dist/core/extensions/contribution-inventory.js +6 -2
- package/dist/core/extensions/extension-registries.js +3 -2
- package/dist/core/extensions/extension-types.d.ts +83 -1
- package/dist/core/extensions/extension-types.js +3 -2
- package/dist/core/extensions/loader.d.ts +2 -8
- package/dist/core/extensions/loader.js +53 -144
- package/dist/core/extensions/registration-values.d.ts +43 -0
- package/dist/core/extensions/registration-values.js +210 -0
- package/dist/core/extensions/reserved-host-flags.js +3 -2
- package/dist/core/extensions/runtime-registrations.d.ts +3 -1
- package/dist/core/extensions/runtime-registrations.js +12 -2
- package/dist/core/fs/fs-utils.d.ts +2 -0
- package/dist/core/fs/fs-utils.js +7 -3
- package/dist/core/history/drift-cache.js +4 -3
- package/dist/core/history/drift-scan.js +16 -17
- package/dist/core/history/history.d.ts +8 -0
- package/dist/core/history/history.js +57 -7
- package/dist/core/history/replay.d.ts +9 -1
- package/dist/core/history/replay.js +48 -13
- package/dist/core/lock/lock-gc.js +8 -13
- package/dist/core/lock/lock.js +5 -4
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +46 -14
- package/dist/core/search/vector-stores.js +6 -11
- 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 +5 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/item-metadata-cache.d.ts +1 -1
- package/dist/core/store/item-metadata-cache.js +16 -9
- package/dist/core/telemetry/runtime.d.ts +6 -0
- package/dist/core/telemetry/runtime.js +101 -30
- package/dist/sdk/agent/command-recovery.d.ts +2 -0
- package/dist/sdk/agent/command-recovery.js +10 -2
- package/dist/sdk/annotations.js +4 -4
- package/dist/sdk/cli-bootstrap.d.ts +2 -0
- package/dist/sdk/cli-bootstrap.js +6 -2
- package/dist/sdk/cli-contracts/completeness.js +10 -3
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +9 -3
- package/dist/sdk/cli-contracts/registration-helpers.d.ts +20 -3
- package/dist/sdk/cli-contracts/registration-helpers.js +18 -12
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +40 -6
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +27 -3
- package/dist/sdk/cli-contracts/tool-option-contracts.js +3 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +55 -5
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +22 -4
- package/dist/sdk/cli-program.js +3 -2
- package/dist/sdk/comments.js +4 -3
- package/dist/sdk/compile-cache.js +4 -3
- package/dist/sdk/completion.js +16 -7
- package/dist/sdk/compose.d.ts +3 -1
- package/dist/sdk/compose.js +16 -2
- package/dist/sdk/context-intent-contracts.js +45 -4
- package/dist/sdk/context-signal-store.js +4 -3
- package/dist/sdk/core.d.ts +1 -0
- package/dist/sdk/core.js +3 -2
- package/dist/sdk/extension/install-runtime.js +4 -4
- package/dist/sdk/extension/managed-state.js +4 -3
- package/dist/sdk/extension-contracts.d.ts +1 -1
- package/dist/sdk/flag-invocation-contracts.js +5 -6
- package/dist/sdk/generated/generated-error-code-catalog-part-1.d.ts +8 -0
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1597 -0
- package/dist/sdk/generated/generated-error-code-catalog-part-2.d.ts +8 -0
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1608 -0
- package/dist/sdk/generated-error-code-catalog.js +6 -3140
- package/dist/sdk/governance/assurance-action.d.ts +27 -3
- package/dist/sdk/governance/assurance-action.js +117 -31
- package/dist/sdk/governance/assurance-mutation-error.d.ts +14 -0
- package/dist/sdk/governance/assurance-mutation-error.js +58 -0
- package/dist/sdk/governance/assurance-presets.d.ts +54 -0
- package/dist/sdk/governance/assurance-presets.js +136 -0
- package/dist/sdk/governance/assurance-runtime.d.ts +4 -0
- package/dist/sdk/governance/assurance-runtime.js +118 -14
- package/dist/sdk/governance/assurance.d.ts +51 -6
- package/dist/sdk/governance/assurance.js +321 -67
- package/dist/sdk/governance/gc.js +5 -11
- package/dist/sdk/governance/health.d.ts +3 -1
- package/dist/sdk/governance/health.js +24 -7
- package/dist/sdk/governance/validate-item-reader.js +3 -3
- package/dist/sdk/governance/validate.d.ts +2 -0
- package/dist/sdk/governance/validate.js +15 -5
- package/dist/sdk/graph/durable-cache.d.ts +1 -1
- package/dist/sdk/graph/durable-cache.js +156 -29
- package/dist/sdk/graph/governance-contracts.d.ts +12 -0
- package/dist/sdk/graph/governance-contracts.js +27 -0
- package/dist/sdk/graph/governance.d.ts +44 -2
- package/dist/sdk/graph/governance.js +156 -12
- package/dist/sdk/guide.js +4 -4
- package/dist/sdk/index.d.ts +3 -2
- package/dist/sdk/index.js +5 -4
- package/dist/sdk/lifecycle/claim.js +10 -3
- package/dist/sdk/linked-artifacts.d.ts +2 -0
- package/dist/sdk/linked-artifacts.js +29 -4
- package/dist/sdk/merge/driver.d.ts +2 -2
- package/dist/sdk/merge/driver.js +3 -3
- package/dist/sdk/merge/install.js +5 -4
- package/dist/sdk/merge/receipts.d.ts +6 -4
- package/dist/sdk/merge/receipts.js +7 -5
- package/dist/sdk/merge/three-way.d.ts +2 -2
- package/dist/sdk/merge/three-way.js +3 -3
- package/dist/sdk/output-projection.d.ts +9 -1
- package/dist/sdk/output-projection.js +45 -9
- package/dist/sdk/query/activity.d.ts +49 -2
- package/dist/sdk/query/activity.js +185 -38
- package/dist/sdk/query/get.js +19 -2
- package/dist/sdk/read-output-contracts.d.ts +5 -1
- package/dist/sdk/read-output-contracts.js +17 -2
- package/dist/sdk/read-output-session.d.ts +2 -0
- package/dist/sdk/read-output-session.js +12 -5
- package/dist/sdk/relationship-history.js +5 -5
- package/dist/sdk/runtime-primitives.d.ts +3 -3
- package/dist/sdk/runtime-primitives.js +5 -5
- package/dist/sdk/runtime-stats-options.js +3 -2
- package/dist/sdk/runtime.js +5 -9
- package/dist/sdk/schema-migration.js +4 -4
- package/dist/sdk/stats.d.ts +36 -3
- package/dist/sdk/stats.js +55 -15
- package/dist/sdk/test/execution.d.ts +4 -0
- package/dist/sdk/test/execution.js +88 -23
- package/dist/sdk/workspace-memory.js +4 -4
- package/dist/sdk/workspace-snapshot.js +8 -14
- package/dist/sdk/workspace-transaction-gc.js +4 -9
- package/dist/sdk/workspace-transaction.js +4 -4
- package/dist/sdk/workspace.js +4 -3
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -2
- package/docs/ASSURANCE.md +170 -14
- package/docs/COMMANDS.md +29 -8
- package/docs/CONFIGURATION.md +9 -0
- package/docs/DEPENDENCY_KIND_CONTRACT.md +10 -8
- package/docs/EXTENSIONS.md +11 -12
- package/docs/MERGE_SAFETY.md +3 -1
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +26 -13
- package/docs/README.md +2 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +17 -2
- package/docs/RELATIONSHIP_GRAPH.md +15 -0
- package/docs/SDK.md +17 -3
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +12 -1
- package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +53 -0
- package/docs/SDK_CONTEXT_INTEGRITY.md +28 -1
- package/docs/TESTING.md +24 -15
- package/docs/TRUSTWORTHY_CONTEXT_EVIDENCE.md +106 -0
- package/docs/performance/sdk-entrypoint-import-costs.md +6 -2
- package/marketplace.json +2 -2
- package/package.json +6 -6
- 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 +384 -83
- package/dist/cli-bundle/chunks/chunk-2OOU2AFH.js +0 -8
- package/dist/cli-bundle/chunks/chunk-2RA2YTHJ.js +0 -33
- package/dist/cli-bundle/chunks/chunk-DSKYD4LG.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HC3GM6YY.js +0 -194
- package/dist/cli-bundle/chunks/chunk-IUNRVDAI.js +0 -2
- package/dist/cli-bundle/chunks/chunk-W7CPZGSB.js +0 -2
- package/dist/cli-bundle/chunks/chunk-ZXOC6HG5.js +0 -5
- package/dist/cli-bundle/chunks/register-list-query-HAUXVUPY.js +0 -10
- package/dist/cli-bundle/chunks/register-mutation-7Y5U7ABT.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-EQX3DLAZ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3AYKXMYX.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4AHEC74N.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4SV3ZKG3.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-6JW6Z2P5.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-D4PIWE6D.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-DPO7TEFX.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-E3KCL7AY.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-ERAAFLPS.js +0 -153
- package/dist/cli-bundle/focused-chunks/chunk-F6E4JZKG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-FPSYO5ZG.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-KDH5OX3D.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-OJ3LVVIS.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-VABB4L5Y.js +0 -17
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/extensions/registration-values
|
|
3
|
+
*
|
|
4
|
+
* Preserves executable extension registrations while producing deterministic,
|
|
5
|
+
* serializable public inventory snapshots and validates assurance providers.
|
|
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]="7316b9ef-38e1-5ee0-9107-da15ec7804d4")}catch(e){}}();
|
|
9
|
+
import { KNOWN_EXTENSION_SERVICE_NAMES, } from "./extension-types.js";
|
|
10
|
+
import { asRegistrationRecord, assertOptionalBooleanField, assertOptionalStringField, } from "./registration-validation.js";
|
|
11
|
+
import { normalizeCommandName } from "./extension-runtime-helpers.js";
|
|
12
|
+
/** Narrow a string to a renderer format accepted by the extension host. */
|
|
13
|
+
export function isOutputRendererFormat(value) {
|
|
14
|
+
return value === "toon" || value === "json";
|
|
15
|
+
}
|
|
16
|
+
/** Narrow a string to a service name accepted by the extension host. */
|
|
17
|
+
export function isExtensionServiceName(value) {
|
|
18
|
+
return KNOWN_EXTENSION_SERVICE_NAMES.includes(value);
|
|
19
|
+
}
|
|
20
|
+
/** Require a callable lifecycle hook before registry mutation. */
|
|
21
|
+
export function assertHookHandler(hookName, hook) {
|
|
22
|
+
if (typeof hook !== "function") {
|
|
23
|
+
throw new TypeError(`api.hooks.${hookName} requires a function handler`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const EXTENSION_REGISTRATION_TRACE_SYMBOL = Symbol("extension_registration_trace");
|
|
27
|
+
/** Create a validation error carrying a hidden structured activation trace. */
|
|
28
|
+
export function createRegistrationValidationError(message, trace) {
|
|
29
|
+
const error = new TypeError(message);
|
|
30
|
+
Object.defineProperty(error, EXTENSION_REGISTRATION_TRACE_SYMBOL, {
|
|
31
|
+
value: trace,
|
|
32
|
+
enumerable: false,
|
|
33
|
+
configurable: false,
|
|
34
|
+
writable: false,
|
|
35
|
+
});
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
/** Recover a hidden structured activation trace from a validation error. */
|
|
39
|
+
export function extractRegistrationValidationTrace(error) {
|
|
40
|
+
return error instanceof Error
|
|
41
|
+
? error[EXTENSION_REGISTRATION_TRACE_SYMBOL]
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
44
|
+
/** Recursively project an arbitrary registration value into serializable data. */
|
|
45
|
+
export function sanitizeRegistrationValue(value) {
|
|
46
|
+
if (value === null)
|
|
47
|
+
return null;
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value.map((entry) => sanitizeRegistrationValue(entry));
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === "function")
|
|
52
|
+
return "[Function]";
|
|
53
|
+
if (typeof value === "bigint" || typeof value === "symbol") {
|
|
54
|
+
return value.toString();
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === "object") {
|
|
57
|
+
const record = value;
|
|
58
|
+
const normalized = {};
|
|
59
|
+
for (const key of Object.keys(record).sort((left, right) => left.localeCompare(right))) {
|
|
60
|
+
normalized[key] = sanitizeRegistrationValue(record[key]);
|
|
61
|
+
}
|
|
62
|
+
return normalized;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
/** Recursively clone registration containers while preserving function identities. */
|
|
67
|
+
export function cloneRuntimeRegistrationValue(value) {
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
return value.map((entry) => cloneRuntimeRegistrationValue(entry));
|
|
70
|
+
}
|
|
71
|
+
if (typeof value === "object" && value !== null) {
|
|
72
|
+
const record = value;
|
|
73
|
+
const cloned = {};
|
|
74
|
+
for (const key of Object.keys(record).sort((left, right) => left.localeCompare(right))) {
|
|
75
|
+
cloned[key] = cloneRuntimeRegistrationValue(record[key]);
|
|
76
|
+
}
|
|
77
|
+
return cloned;
|
|
78
|
+
}
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
/** Create a deterministic serializable registration snapshot with functions redacted. */
|
|
82
|
+
export function normalizeRegistrationRecord(name, value) {
|
|
83
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
84
|
+
throw new TypeError(`${name} requires an object definition`);
|
|
85
|
+
}
|
|
86
|
+
return sanitizeRegistrationValue(value);
|
|
87
|
+
}
|
|
88
|
+
/** Clone a registration record without stripping executable function values. */
|
|
89
|
+
export function normalizeRuntimeRegistrationRecord(name, value) {
|
|
90
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
91
|
+
throw new TypeError(`${name} requires an object definition`);
|
|
92
|
+
}
|
|
93
|
+
return cloneRuntimeRegistrationValue(value);
|
|
94
|
+
}
|
|
95
|
+
/** Implement the typed and untyped registration-array normalization overloads. */
|
|
96
|
+
export function normalizeRegistrationRecordList(name, value) {
|
|
97
|
+
if (!Array.isArray(value)) {
|
|
98
|
+
throw new TypeError(`${name} requires an array of object definitions`);
|
|
99
|
+
}
|
|
100
|
+
return value.map((entry) => normalizeRegistrationRecord(name, entry));
|
|
101
|
+
}
|
|
102
|
+
/** Require a trimmed non-empty string at an extension authoring boundary. */
|
|
103
|
+
export function assertNonEmptyRegistrationString(name, value) {
|
|
104
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
105
|
+
throw new TypeError(`${name} requires a non-empty string`);
|
|
106
|
+
}
|
|
107
|
+
return value.trim();
|
|
108
|
+
}
|
|
109
|
+
/** Require an executable handler at an extension authoring boundary. */
|
|
110
|
+
export function assertRegistrationFunction(name, value) {
|
|
111
|
+
if (typeof value !== "function") {
|
|
112
|
+
throw new TypeError(`${name} requires a function handler`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Canonicalize a user-facing registration name for stable routing. */
|
|
116
|
+
export function normalizeRegistrationName(name) {
|
|
117
|
+
return name
|
|
118
|
+
.trim()
|
|
119
|
+
.toLowerCase()
|
|
120
|
+
.split(/\s+/)
|
|
121
|
+
.filter((part) => part.length > 0)
|
|
122
|
+
.join(" ");
|
|
123
|
+
}
|
|
124
|
+
/** Build the canonical command path synthesized for an importer or exporter. */
|
|
125
|
+
export function toRegistrationCommandPath(name, action) {
|
|
126
|
+
return normalizeCommandName(`${name} ${action}`);
|
|
127
|
+
}
|
|
128
|
+
/** Attach an executable definition as hidden immutable runtime-only state. */
|
|
129
|
+
export function attachRuntimeDefinition(entry, runtimeDefinition) {
|
|
130
|
+
Object.defineProperty(entry, "runtime_definition", {
|
|
131
|
+
value: runtimeDefinition,
|
|
132
|
+
enumerable: false,
|
|
133
|
+
writable: false,
|
|
134
|
+
configurable: false,
|
|
135
|
+
});
|
|
136
|
+
return entry;
|
|
137
|
+
}
|
|
138
|
+
const ASSURANCE_PROVIDER_COST_CLASSES = new Set(["low", "medium", "high"]);
|
|
139
|
+
const ASSURANCE_PROVIDER_VALUE_TYPES = new Set(["number", "string_set"]);
|
|
140
|
+
const ASSURANCE_PROVIDER_PARAMETER_TYPES = new Set([
|
|
141
|
+
"string",
|
|
142
|
+
"number",
|
|
143
|
+
"boolean",
|
|
144
|
+
]);
|
|
145
|
+
function nonEmptyString(label, value) {
|
|
146
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
147
|
+
throw new TypeError(`${label} requires a non-empty string`);
|
|
148
|
+
}
|
|
149
|
+
return value.trim();
|
|
150
|
+
}
|
|
151
|
+
function validateAssuranceProviderKey(providerId, key, definition) {
|
|
152
|
+
const label = `registerAssuranceMeasurementProvider provider.keys.${key}`;
|
|
153
|
+
const record = asRegistrationRecord(label, definition);
|
|
154
|
+
if (!ASSURANCE_PROVIDER_VALUE_TYPES.has(String(record.value_type))) {
|
|
155
|
+
throw new TypeError(`${label}.value_type must be number or string_set`);
|
|
156
|
+
}
|
|
157
|
+
assertOptionalStringField(`${label}.description`, record.description);
|
|
158
|
+
if (record.parameters === undefined)
|
|
159
|
+
return;
|
|
160
|
+
const parameters = asRegistrationRecord(`${label}.parameters`, record.parameters);
|
|
161
|
+
for (const [parameter, rawDefinition] of Object.entries(parameters)) {
|
|
162
|
+
const parameterLabel = `${label}.parameters.${parameter}`;
|
|
163
|
+
nonEmptyString(`${parameterLabel}.name`, parameter);
|
|
164
|
+
const parameterDefinition = asRegistrationRecord(parameterLabel, rawDefinition);
|
|
165
|
+
if (!ASSURANCE_PROVIDER_PARAMETER_TYPES.has(String(parameterDefinition.type))) {
|
|
166
|
+
throw new TypeError(`${parameterLabel}.type must be string, number, or boolean`);
|
|
167
|
+
}
|
|
168
|
+
assertOptionalBooleanField(`${parameterLabel}.required`, parameterDefinition.required);
|
|
169
|
+
assertOptionalStringField(`${parameterLabel}.description`, parameterDefinition.description);
|
|
170
|
+
}
|
|
171
|
+
if (Object.keys(parameters).length > 50) {
|
|
172
|
+
throw new TypeError(`assurance provider ${providerId} key ${key} exceeds 50 parameters`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** Validate the closed provider schema before any activation registry mutation. */
|
|
176
|
+
export function validateAssuranceMeasurementProviderDefinition(provider) {
|
|
177
|
+
const record = asRegistrationRecord("registerAssuranceMeasurementProvider provider", provider);
|
|
178
|
+
const id = nonEmptyString("registerAssuranceMeasurementProvider provider.id", record.id);
|
|
179
|
+
if (!/^[a-z0-9][a-z0-9-]*$/u.test(id)) {
|
|
180
|
+
throw new TypeError("registerAssuranceMeasurementProvider provider.id must be a stable lowercase id");
|
|
181
|
+
}
|
|
182
|
+
if (!ASSURANCE_PROVIDER_COST_CLASSES.has(String(record.cost_class))) {
|
|
183
|
+
throw new TypeError("registerAssuranceMeasurementProvider provider.cost_class must be low, medium, or high");
|
|
184
|
+
}
|
|
185
|
+
if (typeof record.network !== "boolean") {
|
|
186
|
+
throw new TypeError("registerAssuranceMeasurementProvider provider.network must be boolean");
|
|
187
|
+
}
|
|
188
|
+
const keys = asRegistrationRecord("registerAssuranceMeasurementProvider provider.keys", record.keys);
|
|
189
|
+
if (Object.keys(keys).length === 0) {
|
|
190
|
+
throw new TypeError("registerAssuranceMeasurementProvider provider.keys requires at least one key");
|
|
191
|
+
}
|
|
192
|
+
for (const [key, definition] of Object.entries(keys)) {
|
|
193
|
+
if (!/^[a-z0-9][a-z0-9-]*$/u.test(key)) {
|
|
194
|
+
throw new TypeError(`registerAssuranceMeasurementProvider provider key ${key} must be a stable lowercase id`);
|
|
195
|
+
}
|
|
196
|
+
validateAssuranceProviderKey(id, key, definition);
|
|
197
|
+
}
|
|
198
|
+
if (record.timeout_ms !== undefined &&
|
|
199
|
+
(typeof record.timeout_ms !== "number" ||
|
|
200
|
+
!Number.isInteger(record.timeout_ms) ||
|
|
201
|
+
record.timeout_ms < 1 ||
|
|
202
|
+
record.timeout_ms > 300_000)) {
|
|
203
|
+
throw new TypeError("registerAssuranceMeasurementProvider provider.timeout_ms must be an integer from 1 through 300000");
|
|
204
|
+
}
|
|
205
|
+
if (typeof record.resolve !== "function") {
|
|
206
|
+
throw new TypeError("registerAssuranceMeasurementProvider provider.resolve requires a function handler");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=registration-values.js.map
|
|
210
|
+
//# debugId=7316b9ef-38e1-5ee0-9107-da15ec7804d4
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Host-owned flags inherited by every subcommand, including extension commands. */
|
|
7
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]="
|
|
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]="d4493313-8f07-585b-84c7-4141e1d0cba4")}catch(e){}}();
|
|
9
9
|
export const RESERVED_EXTENSION_HOST_FLAGS = Object.freeze([
|
|
10
10
|
{ flag: "--json" },
|
|
11
11
|
{ flag: "--lean" },
|
|
@@ -15,6 +15,7 @@ export const RESERVED_EXTENSION_HOST_FLAGS = Object.freeze([
|
|
|
15
15
|
{ flag: "--output-budget", value_name: "tokens" },
|
|
16
16
|
{ flag: "--output-format", value_name: "toon|json" },
|
|
17
17
|
{ flag: "--output-session", value_name: "state" },
|
|
18
|
+
{ flag: "--output-row-contract" },
|
|
18
19
|
{ flag: "--quiet" },
|
|
19
20
|
{ flag: "--no-changed-fields" },
|
|
20
21
|
{ flag: "--full-changed-fields" },
|
|
@@ -32,4 +33,4 @@ export const RESERVED_EXTENSION_HOST_FLAG_NAMES = new Set(RESERVED_EXTENSION_HOS
|
|
|
32
33
|
...(definition.aliases ?? []),
|
|
33
34
|
]));
|
|
34
35
|
//# sourceMappingURL=reserved-host-flags.js.map
|
|
35
|
-
//# debugId=
|
|
36
|
+
//# debugId=d4493313-8f07-585b-84c7-4141e1d0cba4
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Implements extension runtime contracts and governance for Runtime Registrations.
|
|
5
5
|
*/
|
|
6
|
-
import type { ExtensionRegistrationRegistry, RegisteredExtensionSchemaMigrationDefinition, RegisteredExtensionSearchProvider, RegisteredExtensionVectorStoreAdapter, SchemaFieldDefinition } from "./loader.js";
|
|
6
|
+
import type { ExtensionRegistrationRegistry, RegisteredExtensionSchemaMigrationDefinition, RegisteredExtensionSearchProvider, RegisteredExtensionVectorStoreAdapter, RegisteredExtensionAssuranceMeasurementProvider, SchemaFieldDefinition } from "./loader.js";
|
|
7
|
+
/** Resolve the last-activated assurance provider with the requested stable id. */
|
|
8
|
+
export declare function resolveRegisteredAssuranceMeasurementProvider(registrations: ExtensionRegistrationRegistry | null, providerId: string | undefined): RegisteredExtensionAssuranceMeasurementProvider | null;
|
|
7
9
|
/** Implements collect registered item fields for the public runtime surface of this module. */
|
|
8
10
|
export declare function collectRegisteredItemFields(registrations: ExtensionRegistrationRegistry | null): SchemaFieldDefinition[];
|
|
9
11
|
/** Implements resolve registered search provider for the public runtime surface of this module. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!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]="
|
|
2
|
+
!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]="ab276268-7a98-5f97-b3f5-300dfd1b5ed5")}catch(e){}}();
|
|
3
3
|
function normalizeRegistrationName(value) {
|
|
4
4
|
if (typeof value !== "string") {
|
|
5
5
|
return null;
|
|
@@ -7,6 +7,16 @@ function normalizeRegistrationName(value) {
|
|
|
7
7
|
const normalized = value.trim().toLowerCase();
|
|
8
8
|
return normalized.length > 0 ? normalized : null;
|
|
9
9
|
}
|
|
10
|
+
/** Resolve the last-activated assurance provider with the requested stable id. */
|
|
11
|
+
export function resolveRegisteredAssuranceMeasurementProvider(registrations, providerId) {
|
|
12
|
+
const normalizedId = normalizeRegistrationName(providerId);
|
|
13
|
+
if (!registrations || !normalizedId)
|
|
14
|
+
return null;
|
|
15
|
+
return ([...(registrations.assurance_providers ?? [])]
|
|
16
|
+
.reverse()
|
|
17
|
+
.find((registration) => normalizeRegistrationName(registration.definition.id) ===
|
|
18
|
+
normalizedId) ?? null);
|
|
19
|
+
}
|
|
10
20
|
/** Implements collect registered item fields for the public runtime surface of this module. */
|
|
11
21
|
export function collectRegisteredItemFields(registrations) {
|
|
12
22
|
if (!registrations) {
|
|
@@ -55,4 +65,4 @@ export function getMigrationRuntimeDefinition(migration) {
|
|
|
55
65
|
return migration.runtime_definition ?? migration.definition;
|
|
56
66
|
}
|
|
57
67
|
//# sourceMappingURL=runtime-registrations.js.map
|
|
58
|
-
//# debugId=
|
|
68
|
+
//# debugId=ab276268-7a98-5f97-b3f5-300dfd1b5ed5
|
|
@@ -12,6 +12,8 @@ export declare function pathExists(targetPath: string): Promise<boolean>;
|
|
|
12
12
|
* runtime fault instead of reaching the caller's own root validation.
|
|
13
13
|
*/
|
|
14
14
|
export declare function isFileAbsentError(error: unknown): boolean;
|
|
15
|
+
/** Report an exact missing-entry race while preserving ENOTDIR as structural corruption. */
|
|
16
|
+
export declare function isFileMissingError(error: unknown): boolean;
|
|
15
17
|
/** Implements read file if exists for the public runtime surface of this module. */
|
|
16
18
|
export declare function readFileIfExists(targetPath: string): Promise<string | null>;
|
|
17
19
|
/** Implements write file atomic for the public runtime surface of this module. */
|
package/dist/core/fs/fs-utils.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides filesystem helpers for Fs Utils.
|
|
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]="23fc5fcb-5c80-57ab-8d91-8d15ee35ab53")}catch(e){}}();
|
|
8
8
|
import * as fs from "node:fs/promises";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import crypto from "node:crypto";
|
|
@@ -33,7 +33,11 @@ export async function pathExists(targetPath) {
|
|
|
33
33
|
* runtime fault instead of reaching the caller's own root validation.
|
|
34
34
|
*/
|
|
35
35
|
export function isFileAbsentError(error) {
|
|
36
|
-
return
|
|
36
|
+
return isFileMissingError(error) || isErrno(error, "ENOTDIR");
|
|
37
|
+
}
|
|
38
|
+
/** Report an exact missing-entry race while preserving ENOTDIR as structural corruption. */
|
|
39
|
+
export function isFileMissingError(error) {
|
|
40
|
+
return isErrno(error, "ENOENT");
|
|
37
41
|
}
|
|
38
42
|
/** Implements read file if exists for the public runtime surface of this module. */
|
|
39
43
|
export async function readFileIfExists(targetPath) {
|
|
@@ -152,4 +156,4 @@ function isErrno(error, code) {
|
|
|
152
156
|
error.code === code);
|
|
153
157
|
}
|
|
154
158
|
//# sourceMappingURL=fs-utils.js.map
|
|
155
|
-
//# debugId=
|
|
159
|
+
//# debugId=23fc5fcb-5c80-57ab-8d91-8d15ee35ab53
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Invalidates derived history-chain verification state after committed writes.
|
|
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]="5121b339-6594-58ec-b479-11cbf7dafd27")}catch(e){}}();
|
|
8
|
+
import { isFileMissingError } from "../fs/fs-utils.js";
|
|
8
9
|
import fs from "node:fs/promises";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { writeStderr } from "../output/output.js";
|
|
@@ -49,7 +50,7 @@ export async function invalidateHistoryDriftCache(pmRoot) {
|
|
|
49
50
|
}
|
|
50
51
|
catch (error) {
|
|
51
52
|
const errorCode = getFilesystemErrorCode(error);
|
|
52
|
-
if (
|
|
53
|
+
if (isFileMissingError(error)) {
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
const code = errorCode === undefined
|
|
@@ -69,4 +70,4 @@ export async function invalidateHistoryDriftCacheForPath(historyPath) {
|
|
|
69
70
|
await invalidateHistoryDriftCache(path.dirname(historyDirectory));
|
|
70
71
|
}
|
|
71
72
|
//# sourceMappingURL=drift-cache.js.map
|
|
72
|
-
//# debugId=
|
|
73
|
+
//# debugId=5121b339-6594-58ec-b479-11cbf7dafd27
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
!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]="
|
|
2
|
+
!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]="a6714da6-6e2b-5647-bfde-607a54d7e4cd")}catch(e){}}();
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { getHistoryPath } from "../store/paths.js";
|
|
7
|
-
import { writeFileAtomic } from "../fs/fs-utils.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { isFileMissingError, writeFileAtomic } from "../fs/fs-utils.js";
|
|
8
|
+
import { CURRENT_HISTORY_ITEM_HASH_VERSION, hashDocumentForVersion, } from "./history.js";
|
|
9
|
+
import { verifyHistoryChainWithVersion } from "./replay.js";
|
|
10
10
|
import { getWorkspaceHistoryPath, WORKSPACE_HISTORY_ID, } from "./workspace-history.js";
|
|
11
|
-
const DRIFT_CACHE_VERSION =
|
|
11
|
+
const DRIFT_CACHE_VERSION = 4;
|
|
12
12
|
const DRIFT_CACHE_FILENAME = "history-drift-cache.json";
|
|
13
13
|
function getDriftCachePath(pmRoot) {
|
|
14
14
|
return path.join(pmRoot, "runtime", DRIFT_CACHE_FILENAME);
|
|
@@ -28,12 +28,6 @@ async function loadDriftCache(pmRoot) {
|
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
function isErrno(error, code) {
|
|
32
|
-
return (typeof error === "object" &&
|
|
33
|
-
error !== null &&
|
|
34
|
-
"code" in error &&
|
|
35
|
-
error.code === code);
|
|
36
|
-
}
|
|
37
31
|
async function scanWorkspaceHistory(pmRoot, previousEntries, nextEntries, verifyCacheHitByContent, accumulator) {
|
|
38
32
|
const historyPath = getWorkspaceHistoryPath(pmRoot);
|
|
39
33
|
let stat;
|
|
@@ -41,7 +35,7 @@ async function scanWorkspaceHistory(pmRoot, previousEntries, nextEntries, verify
|
|
|
41
35
|
stat = await fs.stat(historyPath);
|
|
42
36
|
}
|
|
43
37
|
catch (error) {
|
|
44
|
-
if (
|
|
38
|
+
if (isFileMissingError(error))
|
|
45
39
|
return false;
|
|
46
40
|
accumulator.unreadableStreams.push(WORKSPACE_HISTORY_ID);
|
|
47
41
|
return false;
|
|
@@ -69,6 +63,7 @@ async function scanWorkspaceHistory(pmRoot, previousEntries, nextEntries, verify
|
|
|
69
63
|
content_hash: resolved.verification.contentHash,
|
|
70
64
|
latest_after_hash: resolved.verification.latestAfterHash,
|
|
71
65
|
chain_ok: resolved.verification.chainOk,
|
|
66
|
+
item_hash_version: resolved.verification.itemHashVersion,
|
|
72
67
|
};
|
|
73
68
|
return resolved.cacheDirty;
|
|
74
69
|
}
|
|
@@ -106,10 +101,12 @@ async function verifyHistoryStream(historyPath) {
|
|
|
106
101
|
return null;
|
|
107
102
|
}
|
|
108
103
|
/* c8 ignore stop */
|
|
104
|
+
const verification = verifyHistoryChainWithVersion(entries);
|
|
109
105
|
return {
|
|
110
106
|
latestAfterHash,
|
|
111
|
-
chainOk:
|
|
107
|
+
chainOk: verification.ok,
|
|
112
108
|
contentHash,
|
|
109
|
+
itemHashVersion: verification.item_hash_version ?? CURRENT_HISTORY_ITEM_HASH_VERSION,
|
|
113
110
|
};
|
|
114
111
|
}
|
|
115
112
|
function cacheMetadataMatches(cached, stat) {
|
|
@@ -166,6 +163,7 @@ async function resolveStreamVerification(params) {
|
|
|
166
163
|
latestAfterHash: params.cached.latest_after_hash,
|
|
167
164
|
chainOk: params.cached.chain_ok,
|
|
168
165
|
contentHash: currentContentHash,
|
|
166
|
+
itemHashVersion: params.cached.item_hash_version ?? CURRENT_HISTORY_ITEM_HASH_VERSION,
|
|
169
167
|
},
|
|
170
168
|
cacheDirty: false,
|
|
171
169
|
};
|
|
@@ -206,7 +204,7 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
|
|
|
206
204
|
stat = await fs.stat(historyPath);
|
|
207
205
|
}
|
|
208
206
|
catch (error) {
|
|
209
|
-
if (
|
|
207
|
+
if (isFileMissingError(error)) {
|
|
210
208
|
accumulator.missingStreams.push(item.id);
|
|
211
209
|
}
|
|
212
210
|
else {
|
|
@@ -237,12 +235,13 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
|
|
|
237
235
|
content_hash: resolved.verification.contentHash,
|
|
238
236
|
latest_after_hash: resolved.verification.latestAfterHash,
|
|
239
237
|
chain_ok: resolved.verification.chainOk,
|
|
238
|
+
item_hash_version: resolved.verification.itemHashVersion,
|
|
240
239
|
};
|
|
241
240
|
const { body, ...itemMetadata } = item;
|
|
242
|
-
const currentHash =
|
|
241
|
+
const currentHash = hashDocumentForVersion({
|
|
243
242
|
metadata: itemMetadata,
|
|
244
243
|
body,
|
|
245
|
-
});
|
|
244
|
+
}, resolved.verification.itemHashVersion);
|
|
246
245
|
if (currentHash !== resolved.verification.latestAfterHash) {
|
|
247
246
|
accumulator.hashMismatches.push(item.id);
|
|
248
247
|
}
|
|
@@ -271,4 +270,4 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
|
|
|
271
270
|
return { ...accumulator, driftedItems };
|
|
272
271
|
}
|
|
273
272
|
//# sourceMappingURL=drift-scan.js.map
|
|
274
|
-
//# debugId=
|
|
273
|
+
//# debugId=a6714da6-6e2b-5647-bfde-607a54d7e4cd
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { type AuthorSource } from "../shared/author.js";
|
|
2
2
|
import type { HistoryEntry, ItemDocument } from "../../types/index.js";
|
|
3
|
+
/** Hash epoch that preserves linked-test insertion order in immutable history. */
|
|
4
|
+
export declare const CURRENT_HISTORY_ITEM_HASH_VERSION: 2;
|
|
5
|
+
/** Hash epochs understood by this runtime. */
|
|
6
|
+
export declare const SUPPORTED_HISTORY_ITEM_HASH_VERSIONS: readonly [1, 2];
|
|
7
|
+
/** Restricts item hash versions accepted by history replay. */
|
|
8
|
+
export type HistoryItemHashVersion = (typeof SUPPORTED_HISTORY_ITEM_HASH_VERSIONS)[number];
|
|
3
9
|
declare function decodeJsonPointer(path: string): string[];
|
|
4
10
|
declare function isDefinedPointerPath(document: unknown, path: string): boolean;
|
|
5
11
|
/** Implements hash document for the public runtime surface of this module. */
|
|
6
12
|
export declare function hashDocument(document: ItemDocument): string;
|
|
13
|
+
/** Hash an item with an explicit canonicalization epoch for replay compatibility. */
|
|
14
|
+
export declare function hashDocumentForVersion(document: ItemDocument, version: HistoryItemHashVersion): string;
|
|
7
15
|
/** Implements hash empty document for the public runtime surface of this module. */
|
|
8
16
|
export declare function hashEmptyDocument(): string;
|
|
9
17
|
/** Implements create history entry for the public runtime surface of this module. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements append-only history and replay behavior for History.
|
|
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]="2fc7f675-3500-5abb-8d5c-9ca9caa803b6")}catch(e){}}();
|
|
8
8
|
import jsonPatch from "fast-json-patch";
|
|
9
9
|
import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
10
10
|
import { runActiveServiceOverride } from "../extensions/index.js";
|
|
@@ -20,6 +20,42 @@ const EMPTY_LEGACY_HASH_DOCUMENT = {
|
|
|
20
20
|
front_matter: {},
|
|
21
21
|
body: "",
|
|
22
22
|
};
|
|
23
|
+
/** Hash epoch that preserves linked-test insertion order in immutable history. */
|
|
24
|
+
export const CURRENT_HISTORY_ITEM_HASH_VERSION = 2;
|
|
25
|
+
/** Hash epochs understood by this runtime. */
|
|
26
|
+
export const SUPPORTED_HISTORY_ITEM_HASH_VERSIONS = [1, 2];
|
|
27
|
+
function compareOptionalStrings(left, right) {
|
|
28
|
+
return (left ?? "").localeCompare(right ?? "");
|
|
29
|
+
}
|
|
30
|
+
function compareOptionalNumbers(left, right) {
|
|
31
|
+
return (left ?? 0) - (right ?? 0);
|
|
32
|
+
}
|
|
33
|
+
function compareJsonValues(left, right, fallback) {
|
|
34
|
+
// Preserve the original v1 comparator byte-for-byte: replacing JSON.stringify
|
|
35
|
+
// with stableStringify would invalidate immutable hashes from legacy streams.
|
|
36
|
+
return JSON.stringify(left ?? fallback).localeCompare(JSON.stringify(right ?? fallback));
|
|
37
|
+
}
|
|
38
|
+
function compareLegacyLinkedTests(left, right) {
|
|
39
|
+
const comparisons = [
|
|
40
|
+
left.scope.localeCompare(right.scope),
|
|
41
|
+
compareOptionalStrings(left.path, right.path),
|
|
42
|
+
compareOptionalStrings(left.command, right.command),
|
|
43
|
+
compareOptionalNumbers(left.timeout_seconds, right.timeout_seconds),
|
|
44
|
+
compareOptionalStrings(left.pm_context_mode, right.pm_context_mode),
|
|
45
|
+
Number(Boolean(left.shared_host_safe)) - Number(Boolean(right.shared_host_safe)),
|
|
46
|
+
compareJsonValues(left.env_clear, right.env_clear, []),
|
|
47
|
+
compareJsonValues(left.env_set, right.env_set, {}),
|
|
48
|
+
compareJsonValues(left.assert_stdout_contains, right.assert_stdout_contains, []),
|
|
49
|
+
compareJsonValues(left.assert_stdout_regex, right.assert_stdout_regex, []),
|
|
50
|
+
compareJsonValues(left.assert_stderr_contains, right.assert_stderr_contains, []),
|
|
51
|
+
compareJsonValues(left.assert_stderr_regex, right.assert_stderr_regex, []),
|
|
52
|
+
compareOptionalNumbers(left.assert_stdout_min_lines, right.assert_stdout_min_lines),
|
|
53
|
+
compareJsonValues(left.assert_json_field_equals, right.assert_json_field_equals, {}),
|
|
54
|
+
compareJsonValues(left.assert_json_field_gte, right.assert_json_field_gte, {}),
|
|
55
|
+
compareOptionalStrings(left.note, right.note),
|
|
56
|
+
];
|
|
57
|
+
return comparisons.find((comparison) => comparison !== 0) ?? 0;
|
|
58
|
+
}
|
|
23
59
|
function decodeJsonPointer(path) {
|
|
24
60
|
if (!path || path === "/") {
|
|
25
61
|
return [];
|
|
@@ -81,7 +117,7 @@ function normalizeHistoryPatchOps(beforeDocument, patch) {
|
|
|
81
117
|
}
|
|
82
118
|
return normalized;
|
|
83
119
|
}
|
|
84
|
-
function canonicalHashDocument(document) {
|
|
120
|
+
function canonicalHashDocument(document, version) {
|
|
85
121
|
const hasMetadata = document.metadata && Object.keys(document.metadata).length > 0;
|
|
86
122
|
if (!hasMetadata) {
|
|
87
123
|
return {
|
|
@@ -90,7 +126,13 @@ function canonicalHashDocument(document) {
|
|
|
90
126
|
};
|
|
91
127
|
}
|
|
92
128
|
const canonical = canonicalDocument(document);
|
|
93
|
-
const
|
|
129
|
+
const metadata = version === 1 && canonical.metadata.tests
|
|
130
|
+
? {
|
|
131
|
+
...canonical.metadata,
|
|
132
|
+
tests: [...canonical.metadata.tests].sort(compareLegacyLinkedTests),
|
|
133
|
+
}
|
|
134
|
+
: canonical.metadata;
|
|
135
|
+
const orderedMetadata = orderObject(toItemRecord(metadata), ITEM_METADATA_KEY_ORDER);
|
|
94
136
|
return {
|
|
95
137
|
front_matter: orderedMetadata,
|
|
96
138
|
body: canonical.body,
|
|
@@ -113,7 +155,14 @@ function canonicalPatchDocument(document) {
|
|
|
113
155
|
}
|
|
114
156
|
/** Implements hash document for the public runtime surface of this module. */
|
|
115
157
|
export function hashDocument(document) {
|
|
116
|
-
return
|
|
158
|
+
return hashDocumentForVersion(document, CURRENT_HISTORY_ITEM_HASH_VERSION);
|
|
159
|
+
}
|
|
160
|
+
/** Hash an item with an explicit canonicalization epoch for replay compatibility. */
|
|
161
|
+
export function hashDocumentForVersion(document, version) {
|
|
162
|
+
if (!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some((supportedVersion) => supportedVersion === version)) {
|
|
163
|
+
throw new TypeError(`unsupported_item_hash_version:${String(version)}`);
|
|
164
|
+
}
|
|
165
|
+
return sha256Hex(stableStringify(canonicalHashDocument(document, version)));
|
|
117
166
|
}
|
|
118
167
|
/** Implements hash empty document for the public runtime surface of this module. */
|
|
119
168
|
export function hashEmptyDocument() {
|
|
@@ -121,8 +170,8 @@ export function hashEmptyDocument() {
|
|
|
121
170
|
}
|
|
122
171
|
/** Implements create history entry for the public runtime surface of this module. */
|
|
123
172
|
export function createHistoryEntry(params) {
|
|
124
|
-
const beforeHashCanonical = canonicalHashDocument(params.before);
|
|
125
|
-
const afterHashCanonical = canonicalHashDocument(params.after);
|
|
173
|
+
const beforeHashCanonical = canonicalHashDocument(params.before, CURRENT_HISTORY_ITEM_HASH_VERSION);
|
|
174
|
+
const afterHashCanonical = canonicalHashDocument(params.after, CURRENT_HISTORY_ITEM_HASH_VERSION);
|
|
126
175
|
const beforePatchCanonical = canonicalPatchDocument(params.before);
|
|
127
176
|
const afterPatchCanonical = canonicalPatchDocument(params.after);
|
|
128
177
|
const rawPatch = jsonPatch.compare(beforePatchCanonical, afterPatchCanonical);
|
|
@@ -159,6 +208,7 @@ export function createHistoryEntry(params) {
|
|
|
159
208
|
patch,
|
|
160
209
|
before_hash: sha256Hex(stableStringify(beforeHashCanonical)),
|
|
161
210
|
after_hash: sha256Hex(stableStringify(afterHashCanonical)),
|
|
211
|
+
item_hash_version: CURRENT_HISTORY_ITEM_HASH_VERSION,
|
|
162
212
|
message: params.message === undefined ? undefined : params.message,
|
|
163
213
|
...(context === undefined ? {} : { context }),
|
|
164
214
|
};
|
|
@@ -242,4 +292,4 @@ export const _testOnly = {
|
|
|
242
292
|
isDefinedPointerPath,
|
|
243
293
|
};
|
|
244
294
|
//# sourceMappingURL=history.js.map
|
|
245
|
-
//# debugId=
|
|
295
|
+
//# debugId=2fc7f675-3500-5abb-8d5c-9ca9caa803b6
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { canonicalDocument } from "../item/item-format.js";
|
|
2
|
+
import { type HistoryItemHashVersion } from "./history.js";
|
|
2
3
|
import type { HistoryEntry, HistoryPatchOp, ItemDocument } from "../../types/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Shared history replay/patch mechanics single-sourced for the history, restore,
|
|
@@ -19,7 +20,7 @@ export declare const EMPTY_REPLAY_DOCUMENT: ReplayDocument;
|
|
|
19
20
|
/** Implements clone empty replay document for the public runtime surface of this module. */
|
|
20
21
|
export declare function cloneEmptyReplayDocument(): ReplayDocument;
|
|
21
22
|
/** Implements replay hash for the public runtime surface of this module. */
|
|
22
|
-
export declare function replayHash(document: ReplayDocument): string;
|
|
23
|
+
export declare function replayHash(document: ReplayDocument, version?: HistoryItemHashVersion): string;
|
|
23
24
|
/** Implements replay to item document for the public runtime surface of this module. */
|
|
24
25
|
export declare function replayToItemDocument(document: ReplayDocument): ItemDocument;
|
|
25
26
|
/** Converts a materialized replay document into a canonical item document. Use this when callers have already rejected the empty/deleted replay state and need restored metadata validated through the normal item-metadata rules. */
|
|
@@ -41,6 +42,13 @@ export type ReplayApplyResult = {
|
|
|
41
42
|
/** Strictly apply a history patch (front_matter->metadata normalized) to a replay document. Returns a result envelope rather than throwing so each caller can format its own error contract. */
|
|
42
43
|
export declare function tryApplyReplayPatch(current: ReplayDocument, patch: HistoryPatchOp[]): ReplayApplyResult;
|
|
43
44
|
/** Deterministically verify a history chain: each entry's before_hash must equal the prior replayed after_hash, the patch must strictly apply, and the recorded after_hash must equal the replayed result. */
|
|
45
|
+
/** Verify a chain and report the explicit or auto-detected item hash epoch. */
|
|
46
|
+
export declare function verifyHistoryChainWithVersion(entries: HistoryEntry[]): {
|
|
47
|
+
ok: boolean;
|
|
48
|
+
errors: string[];
|
|
49
|
+
item_hash_version?: HistoryItemHashVersion;
|
|
50
|
+
};
|
|
51
|
+
/** Deterministically verify a history chain while preserving the legacy result shape. */
|
|
44
52
|
export declare function verifyHistoryChain(entries: HistoryEntry[]): {
|
|
45
53
|
ok: boolean;
|
|
46
54
|
errors: string[];
|