@unbrained/pm-cli 2026.9.4 → 2026.9.5
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/.agents/skills/HARNESS_COMPATIBILITY.md +1 -1
- package/.agents/skills/README.md +2 -2
- package/.agents/skills/pm-developer/SKILL.md +4 -1
- package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +10 -0
- package/.agents/skills/pm-developer/references/GRAPH_AND_RELATIONSHIPS.md +3 -1
- package/.agents/skills/pm-extensions/SKILL.md +2 -2
- package/.agents/skills/pm-extensions/references/LIFECYCLE.md +3 -3
- package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +3 -3
- package/.agents/skills/pm-user/SKILL.md +2 -0
- package/.agents/skills/pm-user/references/BACKLOG_SHAPING.md +5 -0
- package/.agents/skills/pm-user/references/WORKFLOWS.md +20 -5
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +26 -1
- package/dist/cli/commander-usage.d.ts +2 -0
- package/dist/cli/commander-usage.js +15 -12
- package/dist/cli/help-json-payload.js +12 -7
- package/dist/cli/main.js +15 -6
- package/dist/cli/register-list-query.js +4 -2
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +6 -2
- package/dist/cli-bundle/bundle-manifest.json +153 -153
- package/dist/cli-bundle/chunks/{chunk-RI4XNOYS.js → chunk-3HBDTJRK.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-66VPKFP2.js +5 -0
- package/dist/cli-bundle/chunks/{chunk-I2AS367G.js → chunk-HUAQITVW.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-HI6BHPCU.js → chunk-IBYREGSP.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-LUI4E32I.js +231 -0
- package/dist/cli-bundle/chunks/{chunk-YW4QK2G7.js → chunk-QPZHQY2O.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-X6CMGV6L.js → chunk-SF6SM6U5.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-SVK5Y64D.js +40 -0
- package/dist/cli-bundle/chunks/chunk-V5GBD5KV.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-V72UV7QS.js → chunk-WWAEGW4V.js} +57 -57
- package/dist/cli-bundle/chunks/{chunk-A24WAVE6.js → chunk-ZRAQS3UA.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-Z5YYSJJG.js → register-list-query-AYKGODWT.js} +3 -3
- package/dist/cli-bundle/chunks/{register-mutation-ELSP6I4I.js → register-mutation-YZYG53SQ.js} +4 -4
- package/dist/cli-bundle/chunks/register-operations-KFSCC7QV.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-E2AE72QG.js → register-setup-UJCRVGBG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-24IG6ONG.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-53IHPICX.js → chunk-3ASU6WGI.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-3ITLIBKS.js +56 -0
- package/dist/cli-bundle/focused-chunks/chunk-3NQD5YDG.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-7N2TV7WZ.js → chunk-4OSHLNUE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-65N6JHAN.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-AJR3OP2E.js → chunk-B2TTQGFG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-GUBM3RGY.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-25UJBH4M.js → chunk-H5FOGAVD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-JX3RCVCX.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-6PWPQKDN.js → chunk-KWWCBWFO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-MV752SUC.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-PKIPMCFS.js +6 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3646BZ4W.js → chunk-QL66QNWG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-RJMR2JIF.js +9 -0
- package/dist/cli-bundle/focused-chunks/chunk-WIUPWIZR.js +177 -0
- package/dist/cli-bundle/focused-chunks/{chunk-NBMJD6MK.js → chunk-WOCIPMW7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-MHKUIPJW.js → chunk-YEF5PQQ2.js} +2 -2
- package/dist/cli-bundle/main.js +22 -15
- 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 +29 -29
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +42 -39
- 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 +8 -8
- package/dist/core/extensions/extension-types.d.ts +2 -0
- package/dist/core/extensions/extension-types.js +2 -2
- package/dist/core/history/drift-scan.d.ts +5 -0
- package/dist/core/history/drift-scan.js +16 -6
- package/dist/core/history/event-classification.d.ts +1 -1
- package/dist/core/history/event-classification.js +3 -2
- package/dist/core/history/history.js +37 -5
- package/dist/core/history/identity.d.ts +15 -0
- package/dist/core/history/identity.js +31 -0
- package/dist/core/history/projection.js +50 -17
- package/dist/core/history/read.js +6 -3
- package/dist/core/history/replay.d.ts +1 -2
- package/dist/core/history/replay.js +4 -4
- package/dist/core/history/version-address.d.ts +13 -0
- package/dist/core/history/version-address.js +33 -0
- package/dist/core/item/actionability.d.ts +21 -1
- package/dist/core/item/actionability.js +45 -10
- package/dist/core/item/id.js +8 -4
- package/dist/core/item/item-type-definition.d.ts +2 -0
- package/dist/core/item/item-type-definition.js +9 -2
- package/dist/core/item/type-registry.d.ts +5 -1
- package/dist/core/item/type-registry.js +9 -4
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/item-store.d.ts +14 -0
- package/dist/core/store/item-store.js +48 -10
- package/dist/core/store/settings-validator.js +3 -2
- package/dist/sdk/actionability.d.ts +1 -1
- package/dist/sdk/actionability.js +3 -3
- package/dist/sdk/cli-contracts/command-aliases.js +11 -2
- package/dist/sdk/cli-contracts/completeness.js +4 -3
- package/dist/sdk/cli-contracts/flag-contracts.js +29 -5
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +19 -12
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +14 -2
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +19 -6
- package/dist/sdk/context-intent-contracts.js +3 -3
- package/dist/sdk/context-usage.js +9 -11
- package/dist/sdk/define.d.ts +1 -1
- package/dist/sdk/define.js +2 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +98 -50
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
- package/dist/sdk/governance/validate-history-drift.js +16 -5
- package/dist/sdk/guide-topics.js +116 -2
- package/dist/sdk/history/salvage.d.ts +35 -0
- package/dist/sdk/history/salvage.js +248 -0
- package/dist/sdk/history-compact.js +32 -37
- package/dist/sdk/history-read.d.ts +3 -2
- package/dist/sdk/history-read.js +6 -3
- package/dist/sdk/history-repair.d.ts +5 -0
- package/dist/sdk/history-repair.js +14 -2
- package/dist/sdk/lifecycle/claim.d.ts +4 -0
- package/dist/sdk/lifecycle/claim.js +9 -3
- package/dist/sdk/lifecycle/restore.d.ts +1 -0
- package/dist/sdk/lifecycle/restore.js +19 -7
- package/dist/sdk/output-projection.d.ts +3 -1
- package/dist/sdk/output-projection.js +11 -3
- package/dist/sdk/public-surface.json +1 -0
- package/dist/sdk/query/context.d.ts +9 -0
- package/dist/sdk/query/context.js +33 -21
- package/dist/sdk/query/get.d.ts +2 -2
- package/dist/sdk/query/get.js +4 -3
- package/dist/sdk/query/history.d.ts +11 -0
- package/dist/sdk/query/history.js +34 -10
- package/dist/sdk/query/next.d.ts +15 -1
- package/dist/sdk/query/next.js +43 -20
- package/dist/sdk/query.d.ts +1 -0
- package/dist/sdk/query.js +3 -2
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_GUIDE.md +36 -0
- package/docs/HISTORY_RECOVERY.md +146 -0
- package/docs/README.md +1 -0
- package/docs/RELEASING.md +25 -11
- package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +24 -1
- package/docs/SDK_EXECUTION_CONTRACTS.md +105 -0
- package/docs/TESTING.md +5 -0
- package/docs/agent-task-token-baseline.json +17 -17
- package/docs/agent-task-transcripts.json +2 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +10 -10
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +11 -3
- package/marketplace.json +2 -2
- package/package.json +4 -5
- 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-claude/skills/pm-audit/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-developer/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-planner/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-release/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-workflow/SKILL.md +3 -3
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/skills/pm-auditor/SKILL.md +2 -2
- package/plugins/pm-codex/skills/pm-native/SKILL.md +3 -4
- package/plugins/pm-codex/skills/pm-release/SKILL.md +2 -2
- package/scripts/finalize-build.mjs +13 -1
- package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +0 -230
- package/dist/cli-bundle/chunks/chunk-OGBVU67G.js +0 -5
- package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +0 -38
- package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +0 -9
- package/dist/cli-bundle/chunks/register-operations-OH7R3ZT4.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +0 -176
- package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +0 -54
- package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +0 -9
- package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-P2GOAOQN.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +0 -2
- package/sdk/public-surface.json +0 -33034
|
@@ -839,6 +839,8 @@ export interface SchemaItemTypeDefinition {
|
|
|
839
839
|
description?: string;
|
|
840
840
|
/** Initial status assigned when the contributed item type is created. */
|
|
841
841
|
default_status?: string;
|
|
842
|
+
/** Dispatch role inherited by next, context, and automatic claims. Gates track outcomes; human roles require decisions. */
|
|
843
|
+
execution_role?: "agent" | "human" | "gate";
|
|
842
844
|
/** Value that configures or reports required create fields for this contract. */
|
|
843
845
|
required_create_fields?: string[];
|
|
844
846
|
/** Value that configures or reports required create repeatables for this contract. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Public contract for known extension capabilities, shared by SDK and presentation-layer consumers. */
|
|
2
2
|
|
|
3
|
-
!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]="
|
|
3
|
+
!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]="a2f05fd9-1331-5e75-b8c1-42ad6deb425e")}catch(e){}}();
|
|
4
4
|
export const KNOWN_EXTENSION_CAPABILITIES = [
|
|
5
5
|
"commands",
|
|
6
6
|
"renderers",
|
|
@@ -100,4 +100,4 @@ export function createDefaultExtensionGovernancePolicy() {
|
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
//# sourceMappingURL=extension-types.js.map
|
|
103
|
-
//# debugId=
|
|
103
|
+
//# debugId=a2f05fd9-1331-5e75-b8c1-42ad6deb425e
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { type HistoryIdentityDiscontinuity } from "./identity.js";
|
|
1
2
|
import type { ItemMetadata } from "../../types/index.js";
|
|
2
3
|
/** Documents the drift scan result payload exchanged by command, SDK, and package integrations. */
|
|
3
4
|
export interface DriftScanResult {
|
|
5
|
+
/** Repeated genesis ordinals and observed sequence, keyed by affected item. */
|
|
6
|
+
identityDiscontinuities?: Array<HistoryIdentityDiscontinuity & {
|
|
7
|
+
item_id: string;
|
|
8
|
+
}>;
|
|
4
9
|
/** Value that configures or reports missing streams for this contract. */
|
|
5
10
|
missingStreams: string[];
|
|
6
11
|
/** Value that configures or reports unreadable streams for this contract. */
|
|
@@ -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]="80648bfe-2436-5b5a-8a16-b9c2875f95fd")}catch(e){}}();
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import path from "node:path";
|
|
@@ -7,12 +7,14 @@ import { getHistoryPath } from "../store/paths.js";
|
|
|
7
7
|
import { isFileMissingError, writeFileAtomic } from "../fs/fs-utils.js";
|
|
8
8
|
import { CURRENT_HISTORY_ITEM_HASH_VERSION, SUPPORTED_HISTORY_ITEM_HASH_VERSIONS, hashDocumentVerificationCandidates, } from "./history.js";
|
|
9
9
|
import { verifyHistoryChainWithVersion } from "./replay.js";
|
|
10
|
+
import { findHistoryIdentityDiscontinuities, } from "./identity.js";
|
|
10
11
|
import { getWorkspaceHistoryPath, inspectWorkspaceHistoryState, WORKSPACE_HISTORY_ID, } from "./workspace-history.js";
|
|
11
|
-
const DRIFT_CACHE_VERSION =
|
|
12
|
+
const DRIFT_CACHE_VERSION = 10;
|
|
12
13
|
const DRIFT_CACHE_FILENAME = "history-drift-cache.json";
|
|
13
14
|
function getDriftCachePath(pmRoot) {
|
|
14
15
|
return path.join(pmRoot, "runtime", DRIFT_CACHE_FILENAME);
|
|
15
16
|
}
|
|
17
|
+
/** Discard unreadable or stale cache envelopes, including prior verification semantics. */
|
|
16
18
|
async function loadDriftCache(pmRoot) {
|
|
17
19
|
try {
|
|
18
20
|
const raw = await fs.readFile(getDriftCachePath(pmRoot), "utf8");
|
|
@@ -123,6 +125,7 @@ async function verifyHistoryStream(historyPath) {
|
|
|
123
125
|
: verification.item_hash_version;
|
|
124
126
|
return {
|
|
125
127
|
latestAfterHash,
|
|
128
|
+
identityDiscontinuities: findHistoryIdentityDiscontinuities(entries),
|
|
126
129
|
chainOk: verification.ok,
|
|
127
130
|
versionSkew,
|
|
128
131
|
latestHashComparable: latestHashVersion !== undefined &&
|
|
@@ -153,15 +156,15 @@ async function loadFreshStreamVerification(itemId, historyPath, accumulator) {
|
|
|
153
156
|
return null;
|
|
154
157
|
}
|
|
155
158
|
}
|
|
159
|
+
/** Reverify invalid streams and content-sensitive cache hits; reuse only compatible healthy evidence. */
|
|
156
160
|
async function resolveStreamVerification(params) {
|
|
157
161
|
const cachedContentHash = typeof params.cached?.content_hash === "string" &&
|
|
158
162
|
params.cached.content_hash.length > 0
|
|
159
163
|
? params.cached.content_hash
|
|
160
164
|
: undefined;
|
|
161
165
|
const canUseCache = cacheMetadataMatches(params.cached, params.stat) &&
|
|
162
|
-
cachedContentHash !== undefined
|
|
163
|
-
|
|
164
|
-
if (!canUseCache || !params.cached) {
|
|
166
|
+
cachedContentHash !== undefined;
|
|
167
|
+
if (!canUseCache || !params.cached || !params.cached.chain_ok) {
|
|
165
168
|
return {
|
|
166
169
|
verification: await loadFreshStreamVerification(params.itemId, params.historyPath, params.accumulator),
|
|
167
170
|
cacheDirty: true,
|
|
@@ -183,6 +186,7 @@ async function resolveStreamVerification(params) {
|
|
|
183
186
|
}
|
|
184
187
|
return {
|
|
185
188
|
verification: {
|
|
189
|
+
identityDiscontinuities: [],
|
|
186
190
|
latestAfterHash: params.cached.latest_after_hash,
|
|
187
191
|
chainOk: params.cached.chain_ok,
|
|
188
192
|
versionSkew: params.cached.version_skew === true,
|
|
@@ -217,6 +221,12 @@ async function scanItemHistory(pmRoot, item, cache, accumulator) {
|
|
|
217
221
|
});
|
|
218
222
|
if (!resolved.verification)
|
|
219
223
|
return resolved.cacheDirty;
|
|
224
|
+
if (resolved.verification.identityDiscontinuities.length > 0) {
|
|
225
|
+
(accumulator.identityDiscontinuities ??= []).push(...resolved.verification.identityDiscontinuities.map((finding) => ({
|
|
226
|
+
...finding,
|
|
227
|
+
item_id: item.id,
|
|
228
|
+
})));
|
|
229
|
+
}
|
|
220
230
|
if (resolved.verification.versionSkew) {
|
|
221
231
|
accumulator.versionSkews.push(item.id);
|
|
222
232
|
}
|
|
@@ -330,4 +340,4 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
|
|
|
330
340
|
return { ...accumulator, driftedItems };
|
|
331
341
|
}
|
|
332
342
|
//# sourceMappingURL=drift-scan.js.map
|
|
333
|
-
//# debugId=
|
|
343
|
+
//# debugId=80648bfe-2436-5b5a-8a16-b9c2875f95fd
|
|
@@ -10,7 +10,7 @@ export declare const HISTORY_EVENT_CLASSIFICATION_VERSION: 1;
|
|
|
10
10
|
/** Semantic effect of an immutable history event on project recency. */
|
|
11
11
|
export type HistoryEventClass = "substantive" | "maintenance";
|
|
12
12
|
/** Operations whose meaning is always governance or storage maintenance. */
|
|
13
|
-
export declare const MAINTENANCE_HISTORY_OPERATIONS: readonly ["docs_add", "files_add", "history:author-acknowledge", "history_author_acknowledge", "history_compact", "history_compact_baseline", "history_redact", "history_repair", "normalize", "release", "test_run_track", "tests_add", "tests_remove", "update_audit", "update_ownership_bypass"];
|
|
13
|
+
export declare const MAINTENANCE_HISTORY_OPERATIONS: readonly ["docs_add", "files_add", "history:author-acknowledge", "history_author_acknowledge", "history_compact", "history_compact_baseline", "history_redact", "history_repair", "history_salvage", "normalize", "release", "test_run_track", "tests_add", "tests_remove", "update_audit", "update_ownership_bypass"];
|
|
14
14
|
/** Operations whose meaning always advances lifecycle or working context. */
|
|
15
15
|
export declare const SUBSTANTIVE_HISTORY_OPERATIONS: readonly ["append", "cancel", "claim", "close", "comment_add", "create", "learning_add", "note_add", "reopen"];
|
|
16
16
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Current version of the public history-event classification policy. */
|
|
2
2
|
|
|
3
|
-
!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]="
|
|
3
|
+
!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]="9ad6614e-44bc-549c-915c-6177c3a43c1f")}catch(e){}}();
|
|
4
4
|
export const HISTORY_EVENT_CLASSIFICATION_VERSION = 1;
|
|
5
5
|
/** Operations whose meaning is always governance or storage maintenance. */
|
|
6
6
|
export const MAINTENANCE_HISTORY_OPERATIONS = [
|
|
@@ -12,6 +12,7 @@ export const MAINTENANCE_HISTORY_OPERATIONS = [
|
|
|
12
12
|
"history_compact_baseline",
|
|
13
13
|
"history_redact",
|
|
14
14
|
"history_repair",
|
|
15
|
+
"history_salvage",
|
|
15
16
|
"normalize",
|
|
16
17
|
"release",
|
|
17
18
|
"test_run_track",
|
|
@@ -106,4 +107,4 @@ export function classifyHistoryEvent(entry) {
|
|
|
106
107
|
: "substantive";
|
|
107
108
|
}
|
|
108
109
|
//# sourceMappingURL=event-classification.js.map
|
|
109
|
-
//# debugId=
|
|
110
|
+
//# debugId=9ad6614e-44bc-549c-915c-6177c3a43c1f
|
|
@@ -4,8 +4,10 @@
|
|
|
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]="a5449fec-c5b4-5cf4-9a7f-b7c5dc7161c2")}catch(e){}}();
|
|
8
8
|
import jsonPatch from "fast-json-patch";
|
|
9
|
+
import fs from "node:fs/promises";
|
|
10
|
+
import path from "node:path";
|
|
9
11
|
import { EXIT_CODE, ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
10
12
|
import { runActiveServiceOverride } from "../extensions/index.js";
|
|
11
13
|
import { appendLineAtomic } from "../fs/fs-utils.js";
|
|
@@ -539,7 +541,8 @@ async function applyHistoryAppendOverride(historyPath, entry, result) {
|
|
|
539
541
|
if (result === false)
|
|
540
542
|
return true;
|
|
541
543
|
if (typeof result === "string") {
|
|
542
|
-
|
|
544
|
+
const line = serializeHistoryLine(result, entry);
|
|
545
|
+
await appendHistoryLineWithIdentityReservation(historyPath, line);
|
|
543
546
|
await invalidateHistoryDriftCacheForPath(historyPath);
|
|
544
547
|
await removeHistoryEventIndexForHistoryPath(historyPath);
|
|
545
548
|
return true;
|
|
@@ -550,11 +553,40 @@ async function applyHistoryAppendOverride(historyPath, entry, result) {
|
|
|
550
553
|
if (record.skip === true)
|
|
551
554
|
return true;
|
|
552
555
|
const nextHistoryPath = typeof record.history_path === "string" ? record.history_path : historyPath;
|
|
553
|
-
|
|
556
|
+
const line = serializeHistoryLine(typeof record.line === "string" ? record.line : (record.entry ?? entry), entry);
|
|
557
|
+
await appendHistoryLineWithIdentityReservation(nextHistoryPath, line);
|
|
554
558
|
await invalidateHistoryDriftCacheForPath(nextHistoryPath);
|
|
555
559
|
await removeHistoryEventIndexForHistoryPath(nextHistoryPath);
|
|
556
560
|
return true;
|
|
557
561
|
}
|
|
562
|
+
/** Exclusively create genesis streams at their effective destination; never remove a failed partial reservation. */
|
|
563
|
+
async function appendHistoryLineWithIdentityReservation(historyPath, line) {
|
|
564
|
+
let record;
|
|
565
|
+
try {
|
|
566
|
+
record = JSON.parse(line);
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
// Legacy service overrides may provide non-JSON lines; verification diagnoses them.
|
|
570
|
+
record = null;
|
|
571
|
+
}
|
|
572
|
+
if (!isRecord(record) || record.op !== "create") {
|
|
573
|
+
await appendLineAtomic(historyPath, line);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
await fs.mkdir(path.dirname(historyPath), { recursive: true });
|
|
577
|
+
try {
|
|
578
|
+
await fs.writeFile(historyPath, `${line}\n`, { encoding: "utf8", flag: "wx" });
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
if (error.code !== "EEXIST")
|
|
582
|
+
throw error;
|
|
583
|
+
throw new PmCliError("This item identity is reserved by an existing history stream.", EXIT_CODE.CONFLICT, {
|
|
584
|
+
code: "item_identity_reserved",
|
|
585
|
+
required: "Choose a new item ID or restore the original item from its history.",
|
|
586
|
+
nextSteps: ["Run pm history <id> --full, then pm restore <id> <version> to recover the original item."],
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
558
590
|
/** Implements append history entry for the public runtime surface of this module. */
|
|
559
591
|
export async function appendHistoryEntry(historyPath, entry) {
|
|
560
592
|
const override = await runActiveServiceOverride("history_append", {
|
|
@@ -573,7 +605,7 @@ export async function appendHistoryEntry(historyPath, entry) {
|
|
|
573
605
|
event_class: classifyHistoryEvent(timestampedEntry),
|
|
574
606
|
});
|
|
575
607
|
await appendHistoryEntryWithEventIndex(historyPath, normalizedEntry, async () => {
|
|
576
|
-
await
|
|
608
|
+
await appendHistoryLineWithIdentityReservation(historyPath, serializeHistoryLine(normalizedEntry, normalizedEntry));
|
|
577
609
|
});
|
|
578
610
|
await invalidateHistoryDriftCacheForPath(historyPath);
|
|
579
611
|
}
|
|
@@ -583,4 +615,4 @@ export const _testOnly = {
|
|
|
583
615
|
isDefinedPointerPath,
|
|
584
616
|
};
|
|
585
617
|
//# sourceMappingURL=history.js.map
|
|
586
|
-
//# debugId=
|
|
618
|
+
//# debugId=a5449fec-c5b4-5cf4-9a7f-b7c5dc7161c2
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** @module core/history/identity
|
|
2
|
+
* Identifies multiple genesis records without inferring an unrecorded writer.
|
|
3
|
+
*/
|
|
4
|
+
import type { HistoryEntry } from "../../types/index.js";
|
|
5
|
+
/** Evidence of a second subject occupying one append-only identity stream. */
|
|
6
|
+
export interface HistoryIdentityDiscontinuity {
|
|
7
|
+
/** One-based physical ordinal of the original create or retained baseline. */
|
|
8
|
+
prior_genesis_index: number;
|
|
9
|
+
/** One-based physical ordinal of the later create record. */
|
|
10
|
+
repeated_create_index: number;
|
|
11
|
+
/** Observed record sequence, not an assertion about branch or writer origin. */
|
|
12
|
+
sequence: "delete_then_create" | "multiple_creates" | "checkpoint_then_create";
|
|
13
|
+
}
|
|
14
|
+
/** Find every repeated genesis, including histories that start at a checkpoint. */
|
|
15
|
+
export declare function findHistoryIdentityDiscontinuities(entries: readonly HistoryEntry[]): HistoryIdentityDiscontinuity[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Find every repeated genesis, including histories that start at a checkpoint. */
|
|
2
|
+
|
|
3
|
+
!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]="ffaea7bd-daa4-5ff5-8cd5-82ad04e2256e")}catch(e){}}();
|
|
4
|
+
export function findHistoryIdentityDiscontinuities(entries) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
const checkpoint = entries[0]?.op === "history_compact_baseline";
|
|
7
|
+
let genesis = checkpoint ? 1 : undefined;
|
|
8
|
+
let deleted = false;
|
|
9
|
+
for (const [index, entry] of entries.entries()) {
|
|
10
|
+
if (entry.op === "delete")
|
|
11
|
+
deleted = true;
|
|
12
|
+
if (entry.op !== "create")
|
|
13
|
+
continue;
|
|
14
|
+
if (genesis !== undefined) {
|
|
15
|
+
findings.push({
|
|
16
|
+
prior_genesis_index: genesis,
|
|
17
|
+
repeated_create_index: index + 1,
|
|
18
|
+
sequence: deleted
|
|
19
|
+
? "delete_then_create"
|
|
20
|
+
: checkpoint
|
|
21
|
+
? "checkpoint_then_create"
|
|
22
|
+
: "multiple_creates",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
genesis ??= index + 1;
|
|
26
|
+
deleted = false;
|
|
27
|
+
}
|
|
28
|
+
return findings;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=identity.js.map
|
|
31
|
+
//# debugId=ffaea7bd-daa4-5ff5-8cd5-82ad04e2256e
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* replay kernel so read and write paths cannot disagree about a version.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
!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]="
|
|
9
|
+
!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]="2efbffc1-722c-5f3a-9ca5-e4e7a4f97729")}catch(e){}}();
|
|
10
10
|
import { EXIT_CODE } from "../shared/constants.js";
|
|
11
11
|
import { PmCliError } from "../shared/errors.js";
|
|
12
|
-
import {
|
|
12
|
+
import { historyVersionOffset } from "./version-address.js";
|
|
13
|
+
import { EMPTY_REPLAY_DOCUMENT, verifyHistoryChain, tryApplyReplayPatch, } from "./replay.js";
|
|
13
14
|
/** Find the final history entry recorded at or before a parsed timestamp. */
|
|
14
15
|
function findHistoryIndexAtTimestamp(history, parsedTarget) {
|
|
15
16
|
let historyIndex = -1;
|
|
@@ -25,7 +26,7 @@ function findHistoryIndexAtTimestamp(history, parsedTarget) {
|
|
|
25
26
|
return historyIndex;
|
|
26
27
|
}
|
|
27
28
|
/** Build structured target-range guidance once for every resolver error path. */
|
|
28
|
-
function buildHistoryTargetGuidance(history) {
|
|
29
|
+
function buildHistoryTargetGuidance(history, offset) {
|
|
29
30
|
const firstTimestamp = history[0]?.ts ?? null;
|
|
30
31
|
const lastTimestamp = history.at(-1)?.ts ?? null;
|
|
31
32
|
const guidance = {
|
|
@@ -44,9 +45,12 @@ function buildHistoryTargetGuidance(history) {
|
|
|
44
45
|
},
|
|
45
46
|
};
|
|
46
47
|
if (lastTimestamp !== null) {
|
|
47
|
-
guidance.examples = [
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
guidance.examples = [lastTimestamp];
|
|
49
|
+
if (offset !== null) {
|
|
50
|
+
guidance.examples.unshift(String(offset + 1), String(offset + history.length));
|
|
51
|
+
guidance.valid_range.first_version = offset + 1;
|
|
52
|
+
guidance.valid_range.last_version = offset + history.length;
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
55
|
return { guidance, lastTimestamp };
|
|
52
56
|
}
|
|
@@ -90,18 +94,25 @@ export function resolveHistoryTarget(target, history, options = {}) {
|
|
|
90
94
|
const trimmed = target.trim();
|
|
91
95
|
const errorSubject = options.errorSubject ?? "history";
|
|
92
96
|
const errorSubjectTitle = errorSubject === "restore" ? "Restore" : "History";
|
|
93
|
-
const { guidance, lastTimestamp } = buildHistoryTargetGuidance(history);
|
|
97
|
+
const { guidance, lastTimestamp } = buildHistoryTargetGuidance(history, historyVersionOffset(history, true));
|
|
94
98
|
if (!trimmed) {
|
|
95
99
|
throw new PmCliError(`Missing ${errorSubject} target. Use a timestamp or version number.`, EXIT_CODE.USAGE, guidance);
|
|
96
100
|
}
|
|
97
101
|
if (/^\d+$/.test(trimmed)) {
|
|
102
|
+
const offset = historyVersionOffset(history);
|
|
98
103
|
const version = Number(trimmed);
|
|
104
|
+
if (version >= 1 && version <= offset) {
|
|
105
|
+
throw new PmCliError(`History version ${version} was pruned by compaction.`, EXIT_CODE.USAGE, {
|
|
106
|
+
...guidance,
|
|
107
|
+
code: "history_version_pruned",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
99
110
|
if (!Number.isSafeInteger(version) ||
|
|
100
111
|
version < 1 ||
|
|
101
|
-
version > history.length) {
|
|
102
|
-
throw new PmCliError(`${errorSubjectTitle} version must be between 1 and ${history.length} for this item.`, EXIT_CODE.USAGE, guidance);
|
|
112
|
+
version > offset + history.length) {
|
|
113
|
+
throw new PmCliError(`${errorSubjectTitle} version must be between ${offset + 1} and ${offset + history.length} for this item.`, EXIT_CODE.USAGE, guidance);
|
|
103
114
|
}
|
|
104
|
-
return { kind: "version", raw: trimmed, historyIndex: version - 1 };
|
|
115
|
+
return { kind: "version", raw: trimmed, historyIndex: version - offset - 1 };
|
|
105
116
|
}
|
|
106
117
|
const parsedTarget = Date.parse(trimmed);
|
|
107
118
|
if (!Number.isFinite(parsedTarget)) {
|
|
@@ -137,28 +148,50 @@ export function applyHistoryPatch(current, patch, entryNumber, entryOp) {
|
|
|
137
148
|
}
|
|
138
149
|
/** Replay and hash-verify a history stream through a zero-based target entry. */
|
|
139
150
|
export function replayHistoryToTarget(history, targetIndex) {
|
|
151
|
+
const first = history[0];
|
|
152
|
+
if (first && first.op !== "create" && first.op !== "history_compact_baseline") {
|
|
153
|
+
const baseline = tryApplyReplayPatch(EMPTY_REPLAY_DOCUMENT, first.patch);
|
|
154
|
+
if (!baseline.ok || typeof baseline.document.metadata.id !== "string") {
|
|
155
|
+
throw new PmCliError("History starts without a reconstructable item baseline.", EXIT_CODE.GENERIC_FAILURE, {
|
|
156
|
+
code: "history_baseline_unavailable",
|
|
157
|
+
required: "Recover the original create entry or a complete checkpoint from version control.",
|
|
158
|
+
nextSteps: ["Run pm history <id> --full to inspect the missing baseline."],
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const selected = history.slice(0, targetIndex + 1);
|
|
163
|
+
const verification = verifyHistoryChain([...selected]);
|
|
140
164
|
let document = structuredClone(EMPTY_REPLAY_DOCUMENT);
|
|
141
165
|
for (let index = 0; index <= targetIndex; index += 1) {
|
|
142
166
|
const entry = history[index];
|
|
143
167
|
if (!entry) {
|
|
144
168
|
throw new PmCliError(`History target entry ${index + 1} does not exist.`, EXIT_CODE.USAGE);
|
|
145
169
|
}
|
|
146
|
-
if (replayHash(document) !== entry.before_hash) {
|
|
147
|
-
throw new PmCliError(`History hash mismatch before replay at entry ${index + 1}.`, EXIT_CODE.GENERIC_FAILURE);
|
|
148
|
-
}
|
|
149
170
|
document = applyHistoryPatch(document, entry.patch, index + 1, entry.op);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
171
|
+
}
|
|
172
|
+
if (!verification.ok) {
|
|
173
|
+
throw new PmCliError(`History cannot be replayed: ${verification.errors.join(", ")}.`, EXIT_CODE.GENERIC_FAILURE, {
|
|
174
|
+
code: "history_replay_invalid",
|
|
175
|
+
verification_errors: verification.errors,
|
|
176
|
+
required: "Inspect the history integrity findings before attempting recovery.",
|
|
177
|
+
nextSteps: ["Run pm history <id> --verify --full."],
|
|
178
|
+
});
|
|
153
179
|
}
|
|
154
180
|
return document;
|
|
155
181
|
}
|
|
156
182
|
/** Reject a version whose reconstructed state represents a deleted item. */
|
|
157
183
|
export function ensureMaterializedHistoryTarget(replayDocument, target) {
|
|
158
184
|
if (Object.keys(replayDocument.metadata).length > 0) {
|
|
185
|
+
if (typeof replayDocument.metadata.id !== "string" || !Array.isArray(replayDocument.metadata.tags)) {
|
|
186
|
+
throw new PmCliError("History has no complete item baseline for this target.", EXIT_CODE.GENERIC_FAILURE, {
|
|
187
|
+
code: "history_baseline_unavailable",
|
|
188
|
+
required: "Recover the original create entry or a complete checkpoint from version control.",
|
|
189
|
+
nextSteps: ["Run pm history <id> --full to inspect the first recorded state."],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
159
192
|
return replayDocument;
|
|
160
193
|
}
|
|
161
194
|
throw new PmCliError(`History target ${target.raw} resolves to a deleted state; choose a version or timestamp where the item exists.`, EXIT_CODE.USAGE);
|
|
162
195
|
}
|
|
163
196
|
//# sourceMappingURL=projection.js.map
|
|
164
|
-
//# debugId=
|
|
197
|
+
//# debugId=2efbffc1-722c-5f3a-9ca5-e4e7a4f97729
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* maintenance APIs from depending on presentation-layer modules.
|
|
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]="999c126a-112a-50f6-b53e-bd36dbc5b885")}catch(e){}}();
|
|
11
11
|
import { readFileIfExists } from "../fs/fs-utils.js";
|
|
12
12
|
import { runActiveOnReadHooks } from "../extensions/index.js";
|
|
13
13
|
import { EXIT_CODE } from "../shared/constants.js";
|
|
@@ -46,10 +46,13 @@ export async function readHistoryEntries(historyPath, itemId) {
|
|
|
46
46
|
entries.push(JSON.parse(line));
|
|
47
47
|
}
|
|
48
48
|
catch {
|
|
49
|
-
throw new PmCliError(`History for ${itemId} contains invalid JSON at line ${index + 1}. Repair or restore the history stream and retry.`, EXIT_CODE.GENERIC_FAILURE
|
|
49
|
+
throw new PmCliError(`History for ${itemId} contains invalid JSON at line ${index + 1}. Repair or restore the history stream and retry.`, EXIT_CODE.GENERIC_FAILURE, {
|
|
50
|
+
code: "history_json_invalid",
|
|
51
|
+
nextSteps: [`Run pm history-repair ${itemId} --salvage-tail --dry-run to check whether only an invalid suffix is damaged.`],
|
|
52
|
+
});
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
return entries;
|
|
53
56
|
}
|
|
54
57
|
//# sourceMappingURL=read.js.map
|
|
55
|
-
//# debugId=
|
|
58
|
+
//# debugId=999c126a-112a-50f6-b53e-bd36dbc5b885
|
|
@@ -47,7 +47,6 @@ export type ReplayApplyResult = {
|
|
|
47
47
|
};
|
|
48
48
|
/** 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. */
|
|
49
49
|
export declare function tryApplyReplayPatch(current: ReplayDocument, patch: HistoryPatchOp[]): ReplayApplyResult;
|
|
50
|
-
/** 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. */
|
|
51
50
|
/** Verify a chain and report the explicit or auto-detected item hash epoch. */
|
|
52
51
|
export declare function verifyHistoryChainWithVersion(entries: HistoryEntry[]): {
|
|
53
52
|
ok: boolean;
|
|
@@ -119,6 +118,6 @@ export interface ReanchorHistoryOptions {
|
|
|
119
118
|
*/
|
|
120
119
|
export declare function resolveHistoryRepairItemHashVersion(entries: HistoryEntry[]): HistoryItemHashVersion;
|
|
121
120
|
/** Re-anchor a drifted history chain: replay every entry from empty, recompute the before/after hashes, and only rewrite a patch when the original op set no longer strictly applies (legacy drift). Clean entries keep their patch verbatim so the on-disk diff stays minimal. The returned chain verifies via verifyHistoryChain. */
|
|
122
|
-
export declare function reanchorHistoryEntries(entries: HistoryEntry[], itemHashVersion?:
|
|
121
|
+
export declare function reanchorHistoryEntries(entries: HistoryEntry[], itemHashVersion?: HistoryItemHashVersion, options?: ReanchorHistoryOptions): ReanchorResult;
|
|
123
122
|
/** Implements history entries to raw for the public runtime surface of this module. */
|
|
124
123
|
export declare function historyEntriesToRaw(entries: HistoryEntry[]): string;
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Implements append-only history and replay behavior for Replay.
|
|
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]="b0230e20-93c4-531c-9cc1-85f85c1def7a")}catch(e){}}();
|
|
8
8
|
import jsonPatch from "fast-json-patch";
|
|
9
|
+
import { findHistoryIdentityDiscontinuities } from "./identity.js";
|
|
9
10
|
import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
10
11
|
import { canonicalDocument } from "../item/item-format.js";
|
|
11
12
|
import { toItemRecord } from "../item/item-record.js";
|
|
@@ -190,13 +191,12 @@ function assertHistoryEntryIntegrity(entry, index) {
|
|
|
190
191
|
throw new TypeError(`${integrityError}:entry_${index + 1}`);
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
|
-
/** 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. */
|
|
194
194
|
/** Verify a chain and report the explicit or auto-detected item hash epoch. */
|
|
195
195
|
export function verifyHistoryChainWithVersion(entries) {
|
|
196
196
|
let replay = cloneEmptyReplayDocument();
|
|
197
197
|
let detectedVersion;
|
|
198
198
|
let authoritativeExplicitVersion;
|
|
199
|
-
const errors =
|
|
199
|
+
const errors = findHistoryIdentityDiscontinuities(entries).map((finding) => `verify_failed:duplicate_create:entry_${finding.repeated_create_index}:prior_${finding.prior_genesis_index}`);
|
|
200
200
|
for (let index = 0; index < entries.length; index += 1) {
|
|
201
201
|
const entry = entries[index];
|
|
202
202
|
const explicitVersion = entry.item_hash_version;
|
|
@@ -437,4 +437,4 @@ export function historyEntriesToRaw(entries) {
|
|
|
437
437
|
return `${entries.map((entry) => JSON.stringify(entry)).join("\n")}\n`;
|
|
438
438
|
}
|
|
439
439
|
//# sourceMappingURL=replay.js.map
|
|
440
|
-
//# debugId=
|
|
440
|
+
//# debugId=b0230e20-93c4-531c-9cc1-85f85c1def7a
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/history/version-address
|
|
3
|
+
* Stable ordinal addressing for streams whose retained prefix is a checkpoint.
|
|
4
|
+
*/
|
|
5
|
+
import type { HistoryEntry } from "../../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Return the number added to physical one-based positions to obtain durable
|
|
8
|
+
* version addresses. Legacy checkpoints cannot prove their original ordinal;
|
|
9
|
+
* refusing them prevents silently selecting a different historical state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function historyVersionOffset(history: readonly HistoryEntry[], allowUnknown: true): number | null;
|
|
12
|
+
/** Resolve a required durable offset, refusing ambiguous legacy checkpoints. */
|
|
13
|
+
export declare function historyVersionOffset(history: readonly HistoryEntry[], allowUnknown?: false): number;
|
|
@@ -0,0 +1,33 @@
|
|
|
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]="7ad4e6c0-7545-51cb-9af7-4ba1ad4c4758")}catch(e){}}();
|
|
3
|
+
import { EXIT_CODE } from "../shared/constants.js";
|
|
4
|
+
import { PmCliError } from "../shared/errors.js";
|
|
5
|
+
/** Resolve the checkpoint offset with an explicit opt-in for unknown legacy addresses. */
|
|
6
|
+
export function historyVersionOffset(history, allowUnknown = false) {
|
|
7
|
+
const first = history[0];
|
|
8
|
+
if (first?.op !== "history_compact_baseline")
|
|
9
|
+
return 0;
|
|
10
|
+
const receipt = first.context?.history_compaction;
|
|
11
|
+
const offset = typeof receipt === "object" &&
|
|
12
|
+
receipt !== null &&
|
|
13
|
+
"version_offset" in receipt
|
|
14
|
+
? receipt.version_offset
|
|
15
|
+
: undefined;
|
|
16
|
+
if (typeof offset === "number" &&
|
|
17
|
+
Number.isSafeInteger(offset) &&
|
|
18
|
+
offset >= 0 &&
|
|
19
|
+
Number.isSafeInteger(offset + history.length)) {
|
|
20
|
+
return offset;
|
|
21
|
+
}
|
|
22
|
+
if (allowUnknown)
|
|
23
|
+
return null;
|
|
24
|
+
throw new PmCliError("This compacted stream has no trustworthy version offset; numeric history addresses are unavailable.", EXIT_CODE.USAGE, {
|
|
25
|
+
code: "history_version_mapping_unavailable",
|
|
26
|
+
required: "Use a retained timestamp or recover the pre-compaction stream from version control.",
|
|
27
|
+
nextSteps: [
|
|
28
|
+
"Run pm history <id> --full to inspect the retained timestamps and checkpoint evidence.",
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=version-address.js.map
|
|
33
|
+
//# debugId=7ad4e6c0-7545-51cb-9af7-4ba1ad4c4758
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { RuntimeStatusRegistry } from "../schema/runtime-schema.js";
|
|
2
2
|
import type { ItemMetadata, ItemStatus } from "../../types/index.js";
|
|
3
|
+
import { type ItemTypeRegistry } from "./type-registry.js";
|
|
4
|
+
/** Resolve dispatch semantics once for SDK callers, honoring custom and extension type aliases before built-in defaults. */
|
|
5
|
+
export declare function resolveItemExecutionRole(type: string, registry?: ItemTypeRegistry): "agent" | "human" | "gate";
|
|
3
6
|
/** Built-in ordering kinds that must remain reachable by blocker resolution. */
|
|
4
7
|
export declare const ACTIONABILITY_ORDERING_KINDS: readonly string[];
|
|
5
8
|
/** Collects the blocker item ids declared by an item: the legacy scalar `blocked_by` field plus every `blocked_by` dependency edge. Ids are trimmed, de-duplicated, and returned in stable lexicographic order. This is the single source of truth for "what must close before this item can proceed", shared by `pm next` readiness classification and the close-time auto-unblock sweep. */
|
|
@@ -54,11 +57,28 @@ export interface ActionabilityReport {
|
|
|
54
57
|
ready: ActionableEntry[];
|
|
55
58
|
/** Active leaves with at least one open blocker — waiting to become ready. */
|
|
56
59
|
blocked: ActionableEntry[];
|
|
60
|
+
/** Active containers with unresolved descendants, including their blocker evidence. */
|
|
61
|
+
containers: ActionableEntry[];
|
|
62
|
+
/** Unblocked leaf work that requires a human decision. */
|
|
63
|
+
decisions: ActionableEntry[];
|
|
64
|
+
/** Unblocked leaf outcome gates held out of automatic dispatch. */
|
|
65
|
+
gates: ActionableEntry[];
|
|
57
66
|
/** Active candidates considered before the leaf/blocker split. */
|
|
58
67
|
active_count: number;
|
|
59
68
|
/** Active candidates skipped because they still have open descendants. */
|
|
60
69
|
container_count: number;
|
|
61
70
|
}
|
|
71
|
+
/** Explicit dispatch opt-ins; dependency and lifecycle blocking always remain enforced. */
|
|
72
|
+
export interface ActionabilitySelectionOptions {
|
|
73
|
+
/** Include human decision work in the executable selection. */
|
|
74
|
+
includeDecisions?: boolean;
|
|
75
|
+
/** Include outcome gates in the executable selection. */
|
|
76
|
+
includeGates?: boolean;
|
|
77
|
+
/** Include containers whose descendants are still unfinished. */
|
|
78
|
+
includeContainers?: boolean;
|
|
79
|
+
}
|
|
80
|
+
/** Select dispatch candidates from a classified report while retaining held-out worklists. Ownership and ranking remain caller responsibilities. */
|
|
81
|
+
export declare function selectActionableEntries(report: ActionabilityReport, statusRegistry: RuntimeStatusRegistry, options?: ActionabilitySelectionOptions, typeRegistry?: ItemTypeRegistry): Pick<ActionabilityReport, "ready" | "decisions" | "gates">;
|
|
62
82
|
/**
|
|
63
83
|
* Partitions a candidate set into ready vs blocked leaf work using the corpus to
|
|
64
84
|
* resolve blockers, descendants, and downstream dependents.
|
|
@@ -70,4 +90,4 @@ export interface ActionabilityReport {
|
|
|
70
90
|
* blockers and the non-terminal items it would unblock. Returned lists preserve
|
|
71
91
|
* the candidate order so the caller can apply its own ranking.
|
|
72
92
|
*/
|
|
73
|
-
export declare function computeActionabilityReport(candidates: ItemMetadata[], corpus: ItemMetadata[], statusRegistry: RuntimeStatusRegistry): ActionabilityReport;
|
|
93
|
+
export declare function computeActionabilityReport(candidates: ItemMetadata[], corpus: ItemMetadata[], statusRegistry: RuntimeStatusRegistry, typeRegistry?: ItemTypeRegistry): ActionabilityReport;
|