@llblab/pi-kit 0.37.1 → 0.38.1
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/CHANGELOG.md +10 -0
- package/README.md +4 -4
- package/node_modules/@llblab/pi-claude-usage/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-claude-usage/README.md +3 -3
- package/node_modules/@llblab/pi-claude-usage/lib/status.ts +1 -1
- package/node_modules/@llblab/pi-claude-usage/lib/usage-store.ts +2 -2
- package/node_modules/@llblab/pi-claude-usage/package.json +1 -1
- package/node_modules/@llblab/pi-clean-room/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-clean-room/index.ts +39 -9
- package/node_modules/@llblab/pi-clean-room/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +7 -3
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +679 -2
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +17 -0
- package/node_modules/@llblab/pi-state-flow/README.md +30 -14
- package/node_modules/@llblab/pi-state-flow/api/modules.ts +11 -0
- package/node_modules/@llblab/pi-state-flow/dist/api/modules.d.ts +3 -0
- package/node_modules/@llblab/pi-state-flow/dist/api/modules.js +3 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.d.ts +7 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.js +77 -36
- package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.js +26 -27
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +3 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +13 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +27 -21
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +144 -46
- package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +14 -18
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +6 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +60 -50
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +1049 -310
- package/node_modules/@llblab/pi-state-flow/dist/lib/history.d.ts +4 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +15 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/json.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/json.js +2 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/memory.d.ts +3 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/memory.js +7 -7
- package/node_modules/@llblab/pi-state-flow/dist/lib/migration.d.ts +29 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/migration.js +186 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/model-interface.d.ts +17 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/model-interface.js +158 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/module-registry.d.ts +21 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/module-registry.js +108 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/operation.js +3 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.d.ts +4 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.js +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/planes.d.ts +29 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/planes.js +84 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +6 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +33 -16
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +21 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +53 -13
- package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +5 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/rehydration.d.ts +3 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/rehydration.js +10 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +84 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +570 -20
- package/node_modules/@llblab/pi-state-flow/dist/lib/selection.d.ts +10 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/selection.js +32 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/semantic-module.d.ts +79 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/semantic-module.js +187 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +98 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +398 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/skills.d.ts +7 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/skills.js +55 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +67 -14
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +129 -9
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +26 -14
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +61 -19
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +14 -9
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +59 -22
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +111 -10
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +728 -11
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +10 -7
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +50 -14
- package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.d.ts +40 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.js +247 -43
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.d.ts +41 -8
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +132 -39
- package/node_modules/@llblab/pi-state-flow/dist/package.json +6 -1
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +28 -16
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +12 -8
- package/node_modules/@llblab/pi-state-flow/docs/README.md +9 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +76 -43
- package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +9 -1
- package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +6 -0
- package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +23 -19
- package/node_modules/@llblab/pi-state-flow/docs/protocol-composition-decision.md +66 -0
- package/node_modules/@llblab/pi-state-flow/docs/public-module-contract.md +73 -0
- package/node_modules/@llblab/pi-state-flow/docs/scope-selection-contract.md +814 -0
- package/node_modules/@llblab/pi-state-flow/docs/semantic-compatibility-decision.md +212 -0
- package/node_modules/@llblab/pi-state-flow/docs/semantic-extensibility-decision.md +75 -0
- package/node_modules/@llblab/pi-state-flow/docs/semantic-handoff-contract.md +174 -0
- package/node_modules/@llblab/pi-state-flow/docs/semantic-memory-evaluation.md +166 -0
- package/node_modules/@llblab/pi-state-flow/docs/semantic-module-contract.md +84 -0
- package/node_modules/@llblab/pi-state-flow/docs/single-scope-interface-contract.md +201 -0
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +22 -1
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +32 -18
- package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +68 -31
- package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +21 -22
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +14 -1
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +142 -46
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +14 -17
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +53 -44
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +897 -297
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +16 -7
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +2 -1
- package/node_modules/@llblab/pi-state-flow/lib/memory.ts +10 -9
- package/node_modules/@llblab/pi-state-flow/lib/migration.ts +189 -0
- package/node_modules/@llblab/pi-state-flow/lib/model-interface.ts +136 -0
- package/node_modules/@llblab/pi-state-flow/lib/module-registry.ts +119 -0
- package/node_modules/@llblab/pi-state-flow/lib/operation.ts +3 -2
- package/node_modules/@llblab/pi-state-flow/lib/ownership.ts +6 -6
- package/node_modules/@llblab/pi-state-flow/lib/planes.ts +98 -0
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +37 -16
- package/node_modules/@llblab/pi-state-flow/lib/query.ts +59 -18
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +5 -2
- package/node_modules/@llblab/pi-state-flow/lib/rehydration.ts +10 -1
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +574 -21
- package/node_modules/@llblab/pi-state-flow/lib/selection.ts +39 -0
- package/node_modules/@llblab/pi-state-flow/lib/semantic-module.ts +239 -0
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +387 -3
- package/node_modules/@llblab/pi-state-flow/lib/skills.ts +45 -4
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +156 -16
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +69 -28
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +65 -31
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +770 -18
- package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +58 -20
- package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +267 -50
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +184 -52
- package/node_modules/@llblab/pi-state-flow/package.json +6 -1
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +28 -16
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +12 -8
- package/package.json +4 -4
|
@@ -1,5 +1,173 @@
|
|
|
1
|
-
import { parseRetainedPiCheckpoint, readCheckpointMode } from "./snapshot.js";
|
|
1
|
+
import { parseRetainedPiCheckpoint, prepareRetainedPolicyMigration, readCheckpointMode, isStateFlowMode } from "./snapshot.js";
|
|
2
|
+
import { captureScopeSelection, DEFAULT_SCOPE_SELECTION } from "./selection.js";
|
|
3
|
+
import { isJsonValue, isObject } from "./json.js";
|
|
4
|
+
import { isAbsolute, resolve } from "node:path";
|
|
5
|
+
import { RenewableLifetime } from "./operation.js";
|
|
2
6
|
export const SNAPSHOT_ENTRY_TYPE = "state-flow-snapshot";
|
|
7
|
+
function captureRequestPolicy(value) {
|
|
8
|
+
try {
|
|
9
|
+
if (!isObject(value) || Reflect.ownKeys(value).length !== 4
|
|
10
|
+
|| !["cwd", "owner", "mode", "scopes"].every(key => Object.hasOwn(value, key)))
|
|
11
|
+
throw new Error();
|
|
12
|
+
const { cwd, owner, mode, scopes } = value;
|
|
13
|
+
if (typeof cwd !== "string" || !isAbsolute(cwd) || typeof owner !== "string" || !owner.trim() || !isStateFlowMode(mode))
|
|
14
|
+
throw new Error();
|
|
15
|
+
return Object.freeze({ cwd: resolve(cwd), owner, mode, scopes: captureScopeSelection(scopes) });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new Error("Invalid State Flow selected request policy");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Owns policy-bound cancellation only; no storage, attachment, source acquisition or slot registry. */
|
|
22
|
+
export class SelectedPolicyLifetime {
|
|
23
|
+
#lifetime = new RenewableLifetime();
|
|
24
|
+
#policy;
|
|
25
|
+
#ended = false;
|
|
26
|
+
get policy() { return this.#policy; }
|
|
27
|
+
/** Cancellation only, including Off; unlike capture(), this grants no enabled memory receipt. */
|
|
28
|
+
get signal() { return this.#lifetime.signal; }
|
|
29
|
+
/** Same captured policy preserves independent owners; a real choice revokes all old requests. */
|
|
30
|
+
select(value) {
|
|
31
|
+
if (this.#ended)
|
|
32
|
+
throw new Error("State Flow selected policy lifetime has ended");
|
|
33
|
+
const next = captureRequestPolicy(value), previous = this.#policy;
|
|
34
|
+
if (previous && previous.cwd === next.cwd && previous.owner === next.owner && previous.mode === next.mode
|
|
35
|
+
&& previous.scopes.length === next.scopes.length && previous.scopes.every((scope, index) => scope === next.scopes[index]))
|
|
36
|
+
return;
|
|
37
|
+
this.#policy = next;
|
|
38
|
+
this.#lifetime.renew(new Error("State Flow selected native policy changed"));
|
|
39
|
+
}
|
|
40
|
+
/** Capture at admission, before any source acquisition, asynchronous wait or queued work. */
|
|
41
|
+
capture() {
|
|
42
|
+
const policy = this.#policy, signal = this.#lifetime.signal;
|
|
43
|
+
if (this.#ended || !policy || signal.aborted)
|
|
44
|
+
throw new Error("State Flow selected policy lifetime is unavailable");
|
|
45
|
+
if (policy.mode === "off")
|
|
46
|
+
throw new Error("Off cannot capture State Flow memory requests");
|
|
47
|
+
const revalidate = () => {
|
|
48
|
+
if (this.#ended || this.#policy !== policy || this.#lifetime.signal !== signal || signal.aborted)
|
|
49
|
+
throw new Error("State Flow selected policy request is no longer current");
|
|
50
|
+
};
|
|
51
|
+
return Object.freeze({ policy, signal, revalidate });
|
|
52
|
+
}
|
|
53
|
+
/** Same-policy branch movement/Abort may revoke requests without inventing a different selection. */
|
|
54
|
+
invalidate() {
|
|
55
|
+
if (!this.#ended)
|
|
56
|
+
this.#lifetime.renew(new Error("State Flow selected native request lifetime changed"));
|
|
57
|
+
}
|
|
58
|
+
/** Shutdown cannot be reopened by a late selection or abort listener. */
|
|
59
|
+
end() {
|
|
60
|
+
this.#ended = true;
|
|
61
|
+
this.#policy = undefined;
|
|
62
|
+
this.#lifetime.end(new Error("State Flow selected policy lifetime has ended"));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** One SDK turn and its finalized assistant batch; IDs are evidence only within this owned turn. */
|
|
66
|
+
export class NativeToolRequestCorrelation {
|
|
67
|
+
#turn;
|
|
68
|
+
#ambiguous = false;
|
|
69
|
+
#context;
|
|
70
|
+
#operation;
|
|
71
|
+
#calls = new Map();
|
|
72
|
+
begin(request, signal, currentIdentity, controlSignal) {
|
|
73
|
+
this.#operation = signal;
|
|
74
|
+
// An overlapping turn has no public request ID to disambiguate its later messages.
|
|
75
|
+
if (this.#turn || this.#ambiguous) {
|
|
76
|
+
this.end();
|
|
77
|
+
this.#ambiguous = true;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.#turn = { request, signal: controlSignal ? AbortSignal.any([controlSignal, ...(signal ? [signal] : [])]) : signal, currentIdentity, finalized: false, controller: new AbortController() };
|
|
81
|
+
}
|
|
82
|
+
/** Stable lease from turn_start through provider preparation, before assistant finalization. */
|
|
83
|
+
preparing() {
|
|
84
|
+
const turn = this.#turn;
|
|
85
|
+
const revalidate = () => {
|
|
86
|
+
if (this.#ambiguous || !turn || this.#turn !== turn || turn.finalized || turn.signal?.aborted || !turn.currentIdentity())
|
|
87
|
+
throw new Error("State Flow context has no current native request");
|
|
88
|
+
turn.request?.revalidate();
|
|
89
|
+
turn.prepared?.();
|
|
90
|
+
};
|
|
91
|
+
revalidate();
|
|
92
|
+
return this.#context ??= Object.freeze({
|
|
93
|
+
signal: AbortSignal.any([turn.controller.signal, ...(turn.signal ? [turn.signal] : []), ...(turn.request ? [turn.request.signal] : [])]),
|
|
94
|
+
revalidate,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** Provider-only revalidation of captured context data; callbacks must neither acquire nor recurse into this request. */
|
|
98
|
+
bindPreparedContext(check) {
|
|
99
|
+
this.preparing().revalidate();
|
|
100
|
+
const turn = this.#turn;
|
|
101
|
+
check();
|
|
102
|
+
if (this.#turn !== turn)
|
|
103
|
+
throw new Error("State Flow prepared context owner changed");
|
|
104
|
+
turn.prepared = check;
|
|
105
|
+
}
|
|
106
|
+
finalize(calls) {
|
|
107
|
+
if (!this.#turn || this.#ambiguous)
|
|
108
|
+
return;
|
|
109
|
+
if (this.#turn.finalized) {
|
|
110
|
+
this.end();
|
|
111
|
+
this.#ambiguous = true;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.#turn.finalized = true;
|
|
115
|
+
for (const { id, name } of calls) {
|
|
116
|
+
if (!id || !name || this.#calls.has(id)) {
|
|
117
|
+
this.end();
|
|
118
|
+
this.#ambiguous = true;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
this.#calls.set(id, { name, consumed: false });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
get active() { return this.#turn !== undefined || this.#ambiguous; }
|
|
125
|
+
/** Identify the ambient model owner; deciding which Abort cause to forward belongs to the native port. */
|
|
126
|
+
ownsOperation(signal) { return signal !== undefined && signal === this.#operation; }
|
|
127
|
+
has(id) { return this.#calls.has(id); }
|
|
128
|
+
current() {
|
|
129
|
+
const turn = this.#turn;
|
|
130
|
+
if (this.#ambiguous || !turn?.request || !turn.finalized || turn.signal?.aborted || !turn.currentIdentity())
|
|
131
|
+
throw new Error("State Flow tool batch has no current native request");
|
|
132
|
+
turn.request.revalidate();
|
|
133
|
+
return turn.request;
|
|
134
|
+
}
|
|
135
|
+
check(id, name) {
|
|
136
|
+
const request = this.current(), call = this.#calls.get(id);
|
|
137
|
+
if (!call || call.name !== name)
|
|
138
|
+
throw new Error("State Flow tool batch has no current native request");
|
|
139
|
+
return request;
|
|
140
|
+
}
|
|
141
|
+
/** Only explicit SDK parent evidence, never an ID prefix or branch-history guess. */
|
|
142
|
+
nested(id, name, parent) {
|
|
143
|
+
const call = this.#calls.get(parent), previous = this.#calls.get(id);
|
|
144
|
+
if (!id || !call || previous && (previous.name !== name || previous.parent !== parent))
|
|
145
|
+
throw new Error("State Flow nested tool has no current native parent");
|
|
146
|
+
this.check(parent, call.name);
|
|
147
|
+
if (!previous)
|
|
148
|
+
this.#calls.set(id, { name, consumed: false, parent });
|
|
149
|
+
}
|
|
150
|
+
take(id, name) {
|
|
151
|
+
const request = this.check(id, name), call = this.#calls.get(id);
|
|
152
|
+
if (call.consumed)
|
|
153
|
+
throw new Error("State Flow native tool admission was already consumed");
|
|
154
|
+
call.consumed = true;
|
|
155
|
+
const turn = this.#turn;
|
|
156
|
+
return Object.freeze({ policy: request.policy,
|
|
157
|
+
signal: AbortSignal.any([request.signal, turn.controller.signal, ...(turn.signal ? [turn.signal] : [])]),
|
|
158
|
+
revalidate: () => { if (this.#turn !== turn)
|
|
159
|
+
throw new Error("State Flow native request turn has ended"); this.check(id, name); },
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
end() {
|
|
163
|
+
const previous = this.#turn;
|
|
164
|
+
this.#turn = undefined;
|
|
165
|
+
this.#ambiguous = false;
|
|
166
|
+
this.#context = undefined;
|
|
167
|
+
this.#calls.clear();
|
|
168
|
+
previous?.controller.abort();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
3
171
|
/** Enumerate active-branch snapshots newest-first while containing hostile entries. */
|
|
4
172
|
export function discoverSnapshotData(branch) {
|
|
5
173
|
const candidates = [];
|
|
@@ -54,6 +222,226 @@ export function findBranchPolicy(branch, sessionId, stopEntryType, inactiveMode)
|
|
|
54
222
|
}
|
|
55
223
|
return undefined;
|
|
56
224
|
}
|
|
225
|
+
/** Checkpoint-only preflight: no Stop/fork precedence, installation or authority. Invalid owned data cannot fall back. */
|
|
226
|
+
export function prepareBranchCheckpointPolicy(branch, legacySelection, inactiveMode = "passive") {
|
|
227
|
+
for (let index = branch.length - 1; index >= 0; index--) {
|
|
228
|
+
let entry;
|
|
229
|
+
try {
|
|
230
|
+
entry = branch[index];
|
|
231
|
+
if (entry?.type !== "custom" || entry.customType !== SNAPSHOT_ENTRY_TYPE)
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Unclassifiable foreign entries grant no policy authority.
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
return prepareRetainedPolicyMigration(entry.data, legacySelection, inactiveMode);
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
function nativeMarkerVersion(value) {
|
|
243
|
+
let version;
|
|
244
|
+
try {
|
|
245
|
+
if (!Object.hasOwn(value, "version"))
|
|
246
|
+
return "legacy";
|
|
247
|
+
version = value.version;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
throw new Error("Unreadable State Flow native policy marker version");
|
|
251
|
+
}
|
|
252
|
+
if (version !== 2)
|
|
253
|
+
throw new Error("Unsupported State Flow native policy marker version");
|
|
254
|
+
return 2;
|
|
255
|
+
}
|
|
256
|
+
function parseNativeMarker(value) {
|
|
257
|
+
if (!isObject(value))
|
|
258
|
+
throw new Error("Invalid State Flow native policy marker");
|
|
259
|
+
const version = nativeMarkerVersion(value);
|
|
260
|
+
if (version === "legacy" && Object.hasOwn(value, "scopes"))
|
|
261
|
+
throw new Error("Target policy fields in legacy State Flow native marker");
|
|
262
|
+
const keys = ["version", "owner", "mode", "scopes", "reset", "forkPending", "at", "from", "preserveContext", "persistenceError", "memoryDeferred"];
|
|
263
|
+
if (Object.keys(value).some(key => !keys.includes(key)) || !isJsonValue(value))
|
|
264
|
+
throw new Error("Invalid State Flow native policy marker");
|
|
265
|
+
const { owner, mode, reset, forkPending, at, from: rawFrom, preserveContext, persistenceError, memoryDeferred } = value;
|
|
266
|
+
// Legacy Stop treated an invalid optional anchor as absent, retaining the valid cutoff.
|
|
267
|
+
const from = version === "legacy" && (!Number.isSafeInteger(rawFrom) || rawFrom < 0) ? undefined : rawFrom;
|
|
268
|
+
if ((owner !== undefined && (typeof owner !== "string" || !owner.trim()))
|
|
269
|
+
|| (mode !== undefined && !isStateFlowMode(mode))
|
|
270
|
+
|| (version === 2 && (typeof owner !== "string" || !isStateFlowMode(mode) || !Object.hasOwn(value, "scopes")))
|
|
271
|
+
|| [reset, forkPending, preserveContext, memoryDeferred].some(flag => flag !== undefined && flag !== true)
|
|
272
|
+
|| [at, from].some(time => time !== undefined && (!Number.isSafeInteger(time) || time < 0))
|
|
273
|
+
|| (persistenceError !== undefined && (typeof persistenceError !== "string" || !persistenceError.trim()))
|
|
274
|
+
|| ((from !== undefined || preserveContext !== undefined || persistenceError !== undefined || memoryDeferred !== undefined) && at === undefined)
|
|
275
|
+
|| (at !== undefined && mode === "active")
|
|
276
|
+
|| (memoryDeferred === true && (mode !== "off" || owner === undefined))
|
|
277
|
+
|| ((reset === true || forkPending === true) && owner === undefined)
|
|
278
|
+
|| (reset === true && (forkPending !== undefined || at !== undefined || from !== undefined || preserveContext !== undefined || persistenceError !== undefined || memoryDeferred !== undefined))
|
|
279
|
+
|| (version === "legacy" && at === undefined && reset !== true && forkPending !== true)
|
|
280
|
+
|| (version === "legacy" && reset === true && mode !== undefined))
|
|
281
|
+
throw new Error("Invalid State Flow native policy marker");
|
|
282
|
+
return {
|
|
283
|
+
version, ...(owner === undefined ? {} : { owner: owner }), ...(mode === undefined ? {} : { mode: mode }),
|
|
284
|
+
...(version === 2 ? { scopes: captureScopeSelection(value.scopes) } : {}),
|
|
285
|
+
...(reset === true ? { reset: true } : {}), ...(forkPending === true ? { forkPending: true } : {}),
|
|
286
|
+
...(at === undefined ? {} : { at: at }), ...(from === undefined ? {} : { from: from }),
|
|
287
|
+
...(preserveContext === true ? { preserveContext: true } : {}), ...(memoryDeferred === true ? { memoryDeferred: true } : {}),
|
|
288
|
+
...(persistenceError === undefined ? {} : { persistenceError: persistenceError }),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/** Closed v2 writer value. Legacy records are translated only in branch context, never given a fabricated owner. */
|
|
292
|
+
export function captureSelectedNativeMarker(value) {
|
|
293
|
+
const marker = parseNativeMarker(value);
|
|
294
|
+
if (marker.version !== 2)
|
|
295
|
+
throw new Error("Selected State Flow native marker requires version 2");
|
|
296
|
+
return marker;
|
|
297
|
+
}
|
|
298
|
+
/** Complete native branch admission only; never read canonical/parent files, attach policy or confer memory authority. */
|
|
299
|
+
export function prepareSelectedBranchPolicy(branch, options) {
|
|
300
|
+
const { owner, markerEntryType } = options;
|
|
301
|
+
const inactiveMode = options.inactiveMode ?? "passive";
|
|
302
|
+
const fallbackMode = options.defaults?.mode;
|
|
303
|
+
if (typeof owner !== "string" || !owner.trim() || typeof markerEntryType !== "string" || !markerEntryType.trim() || markerEntryType === SNAPSHOT_ENTRY_TYPE
|
|
304
|
+
|| !isStateFlowMode(fallbackMode) || (inactiveMode !== "passive" && inactiveMode !== "off")
|
|
305
|
+
|| (options.fork !== undefined && typeof options.fork !== "boolean"))
|
|
306
|
+
throw new Error("Invalid State Flow selected branch policy context");
|
|
307
|
+
let mode = fallbackMode, scopes = captureScopeSelection(options.defaults.scopes);
|
|
308
|
+
const classified = [];
|
|
309
|
+
for (let index = 0; index < branch.length; index++) {
|
|
310
|
+
try {
|
|
311
|
+
const entry = branch[index];
|
|
312
|
+
if (entry?.type !== "custom")
|
|
313
|
+
continue;
|
|
314
|
+
if (entry.customType === SNAPSHOT_ENTRY_TYPE)
|
|
315
|
+
classified.push({ type: "checkpoint", entry, index });
|
|
316
|
+
else if (entry.customType === markerEntryType)
|
|
317
|
+
classified.push({ type: "marker", entry, index });
|
|
318
|
+
}
|
|
319
|
+
catch { /* Unclassifiable foreign entries supply no policy. */ }
|
|
320
|
+
}
|
|
321
|
+
const data = new Map(), decoded = new Map();
|
|
322
|
+
const read = (record) => {
|
|
323
|
+
if (!data.has(record.index)) {
|
|
324
|
+
try {
|
|
325
|
+
data.set(record.index, record.entry.data);
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
throw new Error("Unreadable State Flow native policy data");
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return data.get(record.index);
|
|
332
|
+
};
|
|
333
|
+
const markerOwner = (value) => {
|
|
334
|
+
try {
|
|
335
|
+
return isObject(value) ? value.owner : undefined;
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
throw new Error("Unreadable State Flow native policy owner");
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
const marker = (record) => {
|
|
342
|
+
if (!decoded.has(record.index))
|
|
343
|
+
decoded.set(record.index, parseNativeMarker(read(record)));
|
|
344
|
+
return decoded.get(record.index);
|
|
345
|
+
};
|
|
346
|
+
let forkPending = options.fork === true;
|
|
347
|
+
// A later owned reset/pending record supersedes older fork evidence, not a checkpoint or mode-only choice.
|
|
348
|
+
for (const record of [...classified].reverse()) {
|
|
349
|
+
if (record.type !== "marker")
|
|
350
|
+
continue;
|
|
351
|
+
const value = read(record);
|
|
352
|
+
if (markerOwner(value) !== owner || !isObject(value))
|
|
353
|
+
continue;
|
|
354
|
+
nativeMarkerVersion(value);
|
|
355
|
+
if (!Object.hasOwn(value, "reset") && !Object.hasOwn(value, "forkPending"))
|
|
356
|
+
continue;
|
|
357
|
+
const selected = marker(record);
|
|
358
|
+
if (selected.reset) {
|
|
359
|
+
forkPending = false;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
if (selected.forkPending) {
|
|
363
|
+
forkPending = true;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const inherit = options.fork === true || forkPending;
|
|
368
|
+
let localSeen = false, policyError = false, requiresCapture = true;
|
|
369
|
+
let source = "default";
|
|
370
|
+
let checkpointMode;
|
|
371
|
+
let stop, persistenceError;
|
|
372
|
+
for (const record of classified) {
|
|
373
|
+
if (record.type === "checkpoint") {
|
|
374
|
+
try {
|
|
375
|
+
const selected = prepareRetainedPolicyMigration(read(record), scopes, inactiveMode);
|
|
376
|
+
mode = selected.checkpoint.mode;
|
|
377
|
+
scopes = selected.checkpoint.scopes;
|
|
378
|
+
checkpointMode = mode;
|
|
379
|
+
if (selected.sourceVersion === 2)
|
|
380
|
+
policyError = false;
|
|
381
|
+
requiresCapture = selected.requiresConversion || inherit;
|
|
382
|
+
source = "checkpoint";
|
|
383
|
+
if (Object.hasOwn(selected.checkpoint, "boundary"))
|
|
384
|
+
persistenceError = undefined;
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
policyError = true;
|
|
388
|
+
}
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
const raw = read(record), physicalOwner = markerOwner(raw);
|
|
392
|
+
const local = physicalOwner === owner;
|
|
393
|
+
const inherited = typeof physicalOwner === "string" && physicalOwner.trim() && inherit && !localSeen;
|
|
394
|
+
if (physicalOwner !== undefined && !local && !inherited)
|
|
395
|
+
continue;
|
|
396
|
+
try {
|
|
397
|
+
const selected = marker(record);
|
|
398
|
+
const policyOwner = local || inherited;
|
|
399
|
+
if (policyOwner) {
|
|
400
|
+
if (selected.version === 2) {
|
|
401
|
+
scopes = selected.scopes;
|
|
402
|
+
mode = selected.mode;
|
|
403
|
+
policyError = false;
|
|
404
|
+
source = "marker";
|
|
405
|
+
requiresCapture = !local;
|
|
406
|
+
}
|
|
407
|
+
else if (selected.reset) {
|
|
408
|
+
mode = checkpointMode ?? fallbackMode;
|
|
409
|
+
source = "marker";
|
|
410
|
+
requiresCapture = true;
|
|
411
|
+
}
|
|
412
|
+
else if (selected.memoryDeferred || selected.persistenceError) {
|
|
413
|
+
mode = selected.memoryDeferred ? "off" : selected.mode ?? inactiveMode;
|
|
414
|
+
source = "marker";
|
|
415
|
+
requiresCapture = true;
|
|
416
|
+
}
|
|
417
|
+
if (local)
|
|
418
|
+
localSeen = true;
|
|
419
|
+
}
|
|
420
|
+
if (local && selected.reset) {
|
|
421
|
+
stop = undefined;
|
|
422
|
+
persistenceError = undefined;
|
|
423
|
+
}
|
|
424
|
+
if ((local || physicalOwner === undefined) && selected.at !== undefined) {
|
|
425
|
+
stop = { at: selected.at, ...(selected.from === undefined ? {} : { from: selected.from }),
|
|
426
|
+
...(selected.preserveContext ? { preserveContext: true } : {}), ...(selected.mode === "passive" || selected.mode === "off" ? { mode: selected.mode } : {}),
|
|
427
|
+
...(selected.memoryDeferred ? { memoryDeferred: true } : {}) };
|
|
428
|
+
if (local && selected.persistenceError)
|
|
429
|
+
persistenceError = selected.persistenceError;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
if (local || inherited || isObject(raw) && Object.hasOwn(raw, "version"))
|
|
434
|
+
policyError = true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (policyError)
|
|
438
|
+
throw new Error("State Flow selected branch policy is invalid or unsupported");
|
|
439
|
+
scopes = captureScopeSelection(scopes);
|
|
440
|
+
const capture = captureSelectedNativeMarker({ version: 2, owner, mode, scopes, ...(forkPending ? { forkPending: true } : {}) });
|
|
441
|
+
return { mode, scopes, source, forkPending, requiresCapture, capture,
|
|
442
|
+
...(stop === undefined ? {} : { stop: { ...stop, ...(persistenceError === undefined ? {} : { persistenceError }) } }),
|
|
443
|
+
...(persistenceError === undefined ? {} : { persistenceError }) };
|
|
444
|
+
}
|
|
57
445
|
/** Native policy bookkeeping retains an unacquired fork across extension reloads. */
|
|
58
446
|
export function hasPendingFork(branch, sessionId, entryType) {
|
|
59
447
|
for (let index = branch.length - 1; index >= 0; index--) {
|
|
@@ -107,8 +495,15 @@ export function hasUncheckpointedConversation(branch) {
|
|
|
107
495
|
return true;
|
|
108
496
|
}
|
|
109
497
|
if (entry?.type === "custom" && entry.customType === SNAPSHOT_ENTRY_TYPE) {
|
|
110
|
-
|
|
111
|
-
|
|
498
|
+
if (isObject(entry.data) && Object.hasOwn(entry.data, "version")) {
|
|
499
|
+
const retained = prepareRetainedPolicyMigration(entry.data, DEFAULT_SCOPE_SELECTION).checkpoint;
|
|
500
|
+
if (Object.hasOwn(retained, "boundary"))
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
parseRetainedPiCheckpoint(entry.data);
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
112
507
|
}
|
|
113
508
|
}
|
|
114
509
|
catch {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ArtifactProvenance, type ArtifactRegistry } from "./artifact.ts";
|
|
2
|
-
import type
|
|
2
|
+
import { type ScopeSelection } from "./selection.ts";
|
|
3
|
+
import type { AtomicScopePatches, StateScope } from "./state.ts";
|
|
3
4
|
export declare const SKILL_ARTIFACT_COMPILER = "skill-artifact-v1";
|
|
4
5
|
export declare function hasCompiledSkillArtifact(artifacts: ArtifactRegistry, provenance: ArtifactProvenance | undefined, source: string, expectedHash?: string): boolean;
|
|
5
6
|
export type SkillSourceHasher = (source: string) => string;
|
|
@@ -29,7 +30,11 @@ export declare class SkillReadTracker {
|
|
|
29
30
|
readonly successful: Map<string, SuccessfulSkillRead>;
|
|
30
31
|
readonly hashSource: SkillSourceHasher;
|
|
31
32
|
readonly resolveRegistered: RegisteredSkillResolver;
|
|
32
|
-
constructor(hashSource?: SkillSourceHasher, resolveRegistered?: RegisteredSkillResolver);
|
|
33
|
+
constructor(hashSource?: SkillSourceHasher, resolveRegistered?: RegisteredSkillResolver, selection?: ScopeSelection);
|
|
34
|
+
/** Selection changes revoke correlated reads; a disabled Skill still retains ownership-only volatile evidence. */
|
|
35
|
+
select(selection: ScopeSelection): void;
|
|
36
|
+
/** Rehash only attempted selected compilations; this body acquisition must run outside canonical exclusion. */
|
|
37
|
+
validateCompilations(patches: AtomicScopePatches): void;
|
|
33
38
|
clear(): void;
|
|
34
39
|
recordStart(toolCallId: string, toolName: string, args: unknown): void;
|
|
35
40
|
recordCall(toolCallId: string, toolName: string, input: unknown): void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { hashArtifactSource, isArtifactHash, } from "./artifact.js";
|
|
4
4
|
import { isObject } from "./json.js";
|
|
5
|
+
import { captureScopeSelection, DEFAULT_SCOPE_SELECTION } from "./selection.js";
|
|
5
6
|
export const SKILL_ARTIFACT_COMPILER = "skill-artifact-v1";
|
|
6
7
|
function hasContent(value) {
|
|
7
8
|
if (typeof value === "string")
|
|
@@ -30,7 +31,26 @@ export function hasCompiledSkillArtifact(artifacts, provenance, source, expected
|
|
|
30
31
|
&& (expectedHash === undefined || sourceHash === expectedHash);
|
|
31
32
|
}
|
|
32
33
|
export function hashSkillSource(source) {
|
|
33
|
-
|
|
34
|
+
const expected = lstatSync(source, { bigint: true });
|
|
35
|
+
if (!expected.isFile() || expected.isSymbolicLink())
|
|
36
|
+
throw new Error("Skill source must be a regular non-symlink file");
|
|
37
|
+
const descriptor = openSync(source, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
38
|
+
try {
|
|
39
|
+
const before = fstatSync(descriptor, { bigint: true });
|
|
40
|
+
if (!before.isFile() || before.dev !== expected.dev || before.ino !== expected.ino)
|
|
41
|
+
throw new Error("Skill source changed before identity capture");
|
|
42
|
+
const bytes = readFileSync(descriptor);
|
|
43
|
+
const after = fstatSync(descriptor, { bigint: true });
|
|
44
|
+
const current = lstatSync(source, { bigint: true });
|
|
45
|
+
if (current.isSymbolicLink() || !current.isFile() || current.dev !== before.dev || current.ino !== before.ino
|
|
46
|
+
|| after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs
|
|
47
|
+
|| current.size !== after.size || current.mtimeNs !== after.mtimeNs || current.ctimeNs !== after.ctimeNs)
|
|
48
|
+
throw new Error("Skill source changed during identity capture");
|
|
49
|
+
return hashArtifactSource(bytes);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
closeSync(descriptor);
|
|
53
|
+
}
|
|
34
54
|
}
|
|
35
55
|
function readPath(toolName, args) {
|
|
36
56
|
if (toolName !== "read" || !isObject(args) || typeof args.path !== "string")
|
|
@@ -67,9 +87,36 @@ export class SkillReadTracker {
|
|
|
67
87
|
#pending = new Map();
|
|
68
88
|
hashSource;
|
|
69
89
|
resolveRegistered;
|
|
70
|
-
|
|
90
|
+
#selection;
|
|
91
|
+
constructor(hashSource = hashSkillSource, resolveRegistered = () => undefined, selection = DEFAULT_SCOPE_SELECTION) {
|
|
71
92
|
this.hashSource = hashSource;
|
|
72
93
|
this.resolveRegistered = resolveRegistered;
|
|
94
|
+
this.#selection = captureScopeSelection(selection);
|
|
95
|
+
}
|
|
96
|
+
/** Selection changes revoke correlated reads; a disabled Skill still retains ownership-only volatile evidence. */
|
|
97
|
+
select(selection) {
|
|
98
|
+
const wanted = captureScopeSelection(selection);
|
|
99
|
+
if (wanted.join(",") !== this.#selection.join(","))
|
|
100
|
+
this.clear();
|
|
101
|
+
this.#selection = wanted;
|
|
102
|
+
}
|
|
103
|
+
/** Rehash only attempted selected compilations; this body acquisition must run outside canonical exclusion. */
|
|
104
|
+
validateCompilations(patches) {
|
|
105
|
+
for (const scope of Object.keys(patches))
|
|
106
|
+
if (!this.#selection.includes(scope))
|
|
107
|
+
throw new Error(`State Flow ${scope} Skill compilation owner is excluded`);
|
|
108
|
+
for (const read of this.successful.values()) {
|
|
109
|
+
if (!this.#selection.includes(read.scope) || !Object.hasOwn(patches, read.scope))
|
|
110
|
+
continue;
|
|
111
|
+
const artifacts = patches[read.scope]?.artifacts;
|
|
112
|
+
if (!isObject(artifacts) || !Object.hasOwn(artifacts, read.path) || !isObject(artifacts[read.path]))
|
|
113
|
+
continue;
|
|
114
|
+
const registered = this.resolveRegistered(read.path);
|
|
115
|
+
if (!registered || registered.path !== read.path || registered.scope !== read.scope)
|
|
116
|
+
throw new Error(`Registered Skill ownership changed after acquisition: ${read.path}`);
|
|
117
|
+
if (!isArtifactHash(read.hash) || read.error !== undefined || this.hashSource(read.path) !== read.hash)
|
|
118
|
+
throw new Error(`Skill source changed after acquisition: ${read.path}`);
|
|
119
|
+
}
|
|
73
120
|
}
|
|
74
121
|
clear() {
|
|
75
122
|
this.successful.clear();
|
|
@@ -103,6 +150,11 @@ export class SkillReadTracker {
|
|
|
103
150
|
const registered = this.resolveRegistered(source);
|
|
104
151
|
if (!registered)
|
|
105
152
|
return undefined;
|
|
153
|
+
if (!this.#selection.includes(registered.scope)) {
|
|
154
|
+
const read = { path: registered.path, scope: registered.scope };
|
|
155
|
+
this.successful.set(registered.path, read);
|
|
156
|
+
return read;
|
|
157
|
+
}
|
|
106
158
|
let read;
|
|
107
159
|
try {
|
|
108
160
|
const hash = this.hashSource(registered.path);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ArtifactProvenanceRegistry } from "./artifact.ts";
|
|
2
2
|
import { type JsonObject } from "./json.ts";
|
|
3
|
-
import { type TransitionBoundary } from "./temporal.ts";
|
|
3
|
+
import { type ExcludedTransitionWitness, type TransitionBoundary } from "./temporal.ts";
|
|
4
|
+
import { type ScopeSelection } from "./selection.ts";
|
|
4
5
|
/** Missing operational capability is not evidence that a checkpoint target is invalid. */
|
|
5
6
|
export declare class RevisionUnavailableError extends Error {
|
|
6
7
|
}
|
|
@@ -35,24 +36,47 @@ export interface StateFlowSnapshot {
|
|
|
35
36
|
meta: SnapshotMeta;
|
|
36
37
|
}
|
|
37
38
|
export type Snapshot = StateFlowSnapshot;
|
|
39
|
+
/** Capture closed caller-owned run fields, omitting only undefined optional in-memory fields. */
|
|
40
|
+
export declare function captureLifecycleSnapshot(value: Snapshot): Snapshot;
|
|
38
41
|
/** Failed Active selection retains its policy and fences inference until explicit recovery or an inactive choice. */
|
|
39
42
|
export declare function isActiveRestorationBlocked(snapshot: Snapshot): boolean;
|
|
43
|
+
interface LifecycleMetadata extends SnapshotMeta {
|
|
44
|
+
identity: {
|
|
45
|
+
cwd: string;
|
|
46
|
+
sessionId: string;
|
|
47
|
+
};
|
|
48
|
+
lineage: TransitionBoundary[];
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
interface SessionRuntimeMetadata extends LifecycleMetadata {
|
|
52
|
+
/** Runtime-owned artifact compilation evidence; never projected as semantic state. */
|
|
53
|
+
artifacts?: ArtifactProvenanceRegistry;
|
|
54
|
+
temporal?: {
|
|
55
|
+
checkpoint: TransitionBoundary;
|
|
56
|
+
patches: TransitionBoundary[];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
40
59
|
export interface SessionRuntime {
|
|
41
60
|
config: SnapshotConfig;
|
|
42
|
-
meta:
|
|
61
|
+
meta: SessionRuntimeMetadata & {
|
|
43
62
|
version: 1;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export type PrivateAcquisition = "unacquired" | "deferred" | "acquired";
|
|
66
|
+
export interface PrivateCausalBasis {
|
|
67
|
+
lineage: TransitionBoundary[];
|
|
68
|
+
causalWitnesses: ExcludedTransitionWitness[];
|
|
69
|
+
}
|
|
70
|
+
/** Retained private identity proof, never private values or acquisition permission. */
|
|
71
|
+
export declare function capturePrivateCausalBasis(value: unknown): PrivateCausalBasis;
|
|
72
|
+
export interface SelectedSessionRuntime {
|
|
73
|
+
config: SnapshotConfig & {
|
|
74
|
+
scopes: ScopeSelection;
|
|
75
|
+
};
|
|
76
|
+
meta: LifecycleMetadata & {
|
|
77
|
+
version: 2;
|
|
78
|
+
privateAcquisition: PrivateAcquisition;
|
|
79
|
+
privateCausalBasis?: PrivateCausalBasis;
|
|
56
80
|
};
|
|
57
81
|
}
|
|
58
82
|
export declare function validateSessionRuntime(value: unknown, cwd: string, sessionId: string): asserts value is SessionRuntime;
|
|
@@ -63,6 +87,23 @@ export declare function serializeSessionRuntime(runtime: SessionRuntime, cwd: st
|
|
|
63
87
|
};
|
|
64
88
|
/** Legacy `enabled:false` decodes as non-active; native checkpoints, not this file, select branch policy. */
|
|
65
89
|
export declare function parseSessionRuntime(config: string | undefined, runtimeSource: string | undefined, cwd: string, sessionId: string): SessionRuntime | undefined;
|
|
90
|
+
export interface SessionPolicyMigrationCandidate {
|
|
91
|
+
sourceVersion: 1 | 2;
|
|
92
|
+
targetVersion: 2;
|
|
93
|
+
requiresConversion: boolean;
|
|
94
|
+
/** Original strings, not file observations or publication authority. */
|
|
95
|
+
source: {
|
|
96
|
+
config: string;
|
|
97
|
+
runtime: string;
|
|
98
|
+
};
|
|
99
|
+
runtime: SelectedSessionRuntime;
|
|
100
|
+
target: {
|
|
101
|
+
config: string;
|
|
102
|
+
runtime: string;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Detached lifecycle preflight only; current native readers/writers still admit version 1 exclusively. */
|
|
106
|
+
export declare function prepareSessionPolicyMigration(config: string | undefined, runtimeSource: string | undefined, cwd: string, sessionId: string, legacySelection: ScopeSelection): SessionPolicyMigrationCandidate | undefined;
|
|
66
107
|
export declare function emptySnapshot(mode?: StateFlowMode): Snapshot;
|
|
67
108
|
export type RetainedBoundaryCheckpoint = {
|
|
68
109
|
boundary: string;
|
|
@@ -84,5 +125,17 @@ export declare function retainedBoundaryCheckpoint(snapshot: Snapshot, boundary:
|
|
|
84
125
|
export declare function preRuntimeCheckpoint(mode: StateFlowMode): PreRuntimeCheckpoint;
|
|
85
126
|
/** Decode the retained-window checkpoint contract; legacy `enabled`/`{disabled:true}` markers map through `inactiveMode`. */
|
|
86
127
|
export declare function parseRetainedPiCheckpoint(value: unknown, inactiveMode?: InactiveMode): RetainedPiCheckpoint;
|
|
128
|
+
export type SelectedRetainedPiCheckpoint = RetainedPiCheckpoint & {
|
|
129
|
+
version: 2;
|
|
130
|
+
scopes: ScopeSelection;
|
|
131
|
+
};
|
|
132
|
+
export interface RetainedPolicyMigrationCandidate {
|
|
133
|
+
sourceVersion: "legacy" | 2;
|
|
134
|
+
targetVersion: 2;
|
|
135
|
+
requiresConversion: boolean;
|
|
136
|
+
checkpoint: SelectedRetainedPiCheckpoint;
|
|
137
|
+
}
|
|
138
|
+
/** Native policy value preflight; no retained boundary, fork or acquisition authority is created. */
|
|
139
|
+
export declare function prepareRetainedPolicyMigration(value: unknown, legacySelection: ScopeSelection, inactiveMode?: InactiveMode): RetainedPolicyMigrationCandidate;
|
|
87
140
|
export declare function migrationFailure(data: JsonObject, error: string, mode?: StateFlowMode): Snapshot;
|
|
88
141
|
export {};
|