@akagilnc/pi-workflow-roles 0.1.3414 → 0.1.3439

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.
Files changed (61) hide show
  1. package/dist/archivist-record-entry.js +21 -12
  2. package/dist/archivist-record-topology.js +20 -0
  3. package/dist/auditor-dossier-tool.js +67 -76
  4. package/dist/canonical-json.js +66 -69
  5. package/dist/compliance-transport.js +99 -86
  6. package/dist/countersign-contracts.js +23 -25
  7. package/dist/doctor-contracts.js +169 -145
  8. package/dist/engine-detour-tool.js +83 -87
  9. package/dist/engine-detour.js +148 -183
  10. package/dist/evidence-child-executor.js +10 -1
  11. package/dist/exact-utf8.js +11 -10
  12. package/dist/git-object-id.js +10 -5
  13. package/dist/gleaner-left-contracts.js +33 -35
  14. package/dist/grok/production-host.js +229 -118
  15. package/dist/inspector-contracts.js +28 -31
  16. package/dist/institutional-resolution.js +101 -104
  17. package/dist/ledger-session-read.js +241 -0
  18. package/dist/merger-contracts.js +66 -56
  19. package/dist/notary-contracts.js +91 -100
  20. package/dist/open-tool-schema.js +32 -31
  21. package/dist/package-contracts/collector-output.js +56 -43
  22. package/dist/package-contracts/fixer-output.js +52 -50
  23. package/dist/package-contracts/fixer-packet.js +67 -64
  24. package/dist/package-contracts/gatekeeper-output.js +48 -56
  25. package/dist/package-contracts/judge-output.js +23 -20
  26. package/dist/package-contracts/navigator-output.js +35 -40
  27. package/dist/package-contracts/reviewer-output.js +94 -110
  28. package/dist/package-contracts/terminating-infrastructure.js +62 -90
  29. package/dist/package-contracts/worker-output.js +30 -11
  30. package/dist/package-resources/engine-material.js +58 -94
  31. package/dist/public-cli/config.js +420 -484
  32. package/dist/public-cli/main.js +1219 -524
  33. package/dist/public-cli/registry.js +107 -114
  34. package/dist/receipt-delivery-policy.js +74 -76
  35. package/dist/session-opening-materials.js +44 -47
  36. package/dist/sha256.js +5 -3
  37. package/dist/sitian-appender.js +204 -210
  38. package/dist/sitian-contracts.js +15 -19
  39. package/dist/sitian-facade.js +5 -10
  40. package/dist/sitian-reader.js +37 -46
  41. package/dist/stream-idle-guard.js +63 -71
  42. package/dist/ticket-seat-memory.js +244 -0
  43. package/package.json +1 -1
  44. package/scripts/build-package.mjs +41 -0
  45. package/src/analyst-gate-cycles-read.ts +152 -83
  46. package/src/analyst-ledger.ts +170 -43
  47. package/src/archivist-record-entry.ts +32 -11
  48. package/src/archivist-record-topology.ts +39 -0
  49. package/src/evidence-child-executor.ts +14 -1
  50. package/src/grok/production-host.ts +44 -9
  51. package/src/host-contracts.ts +18 -0
  52. package/src/host-transition-prior-native.ts +8 -1
  53. package/src/ledger-session-read.ts +56 -0
  54. package/src/pi/durable-principal.ts +6 -0
  55. package/src/public-cli/inspector-run.ts +21 -10
  56. package/src/public-cli/invocation.ts +4 -20
  57. package/src/public-cli/notary-run.ts +21 -4
  58. package/src/public-cli/post-admission.ts +333 -42
  59. package/src/public-cli/settlement.ts +266 -81
  60. package/src/session-opening-materials.ts +4 -2
  61. package/src/ticket-seat-memory.ts +454 -0
@@ -1,75 +1,67 @@
1
- /**
2
- * Stream idle backstop (#102 / #155 a): first-wait + between-event silence only.
3
- * Not a total wall-clock for long thinking turns.
4
- *
5
- * Default silence budget is owner-final 183s (#102 2026-08-04),
6
- * same numeric value as header timeoutMs but a distinct body-idle clock.
7
- */
8
- export const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 183_000;
9
- export const STREAM_IDLE_TIMEOUT_CODE = "AK_STREAM_IDLE_TIMEOUT";
10
- export class StreamIdleTimeoutError extends Error {
11
- code = STREAM_IDLE_TIMEOUT_CODE;
12
- idleTimeoutMs;
13
- constructor(idleTimeoutMs, options) {
14
- super(`stream idle timeout after ${idleTimeoutMs}ms`, options);
15
- this.name = "StreamIdleTimeoutError";
16
- this.idleTimeoutMs = idleTimeoutMs;
17
- }
1
+ const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 183e3;
2
+ const STREAM_IDLE_TIMEOUT_CODE = "AK_STREAM_IDLE_TIMEOUT";
3
+ class StreamIdleTimeoutError extends Error {
4
+ code = STREAM_IDLE_TIMEOUT_CODE;
5
+ idleTimeoutMs;
6
+ constructor(idleTimeoutMs, options) {
7
+ super(`stream idle timeout after ${idleTimeoutMs}ms`, options);
8
+ this.name = "StreamIdleTimeoutError";
9
+ this.idleTimeoutMs = idleTimeoutMs;
10
+ }
18
11
  }
19
- export function isStreamIdleTimeoutError(value) {
20
- return value instanceof StreamIdleTimeoutError
21
- || (typeof value === "object"
22
- && value !== null
23
- && value.name === "StreamIdleTimeoutError"
24
- && value.code === STREAM_IDLE_TIMEOUT_CODE);
12
+ function isStreamIdleTimeoutError(value) {
13
+ return value instanceof StreamIdleTimeoutError || typeof value === "object" && value !== null && value.name === "StreamIdleTimeoutError" && value.code === STREAM_IDLE_TIMEOUT_CODE;
25
14
  }
26
- export function createStreamIdleGuard(options = {}) {
27
- const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS;
28
- const parentSignal = options.parentSignal;
29
- const controller = new AbortController();
30
- let timer;
31
- let disposed = false;
32
- const clear = () => {
33
- if (timer !== undefined) {
34
- clearTimeout(timer);
35
- timer = undefined;
36
- }
37
- };
38
- const arm = () => {
39
- if (disposed || controller.signal.aborted || idleTimeoutMs <= 0)
40
- return;
41
- clear();
42
- timer = setTimeout(() => {
43
- timer = undefined;
44
- if (disposed || controller.signal.aborted)
45
- return;
46
- controller.abort(new StreamIdleTimeoutError(idleTimeoutMs));
47
- }, idleTimeoutMs);
48
- };
49
- const onParentAbort = () => {
50
- if (controller.signal.aborted)
51
- return;
52
- clear();
53
- controller.abort(parentSignal?.reason);
54
- };
55
- if (parentSignal !== undefined) {
56
- if (parentSignal.aborted) {
57
- controller.abort(parentSignal.reason);
58
- }
59
- else {
60
- parentSignal.addEventListener("abort", onParentAbort);
61
- }
15
+ function createStreamIdleGuard(options = {}) {
16
+ const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS;
17
+ const parentSignal = options.parentSignal;
18
+ const controller = new AbortController();
19
+ let timer;
20
+ let disposed = false;
21
+ const clear = () => {
22
+ if (timer !== void 0) {
23
+ clearTimeout(timer);
24
+ timer = void 0;
25
+ }
26
+ };
27
+ const arm = () => {
28
+ if (disposed || controller.signal.aborted || idleTimeoutMs <= 0) return;
29
+ clear();
30
+ timer = setTimeout(() => {
31
+ timer = void 0;
32
+ if (disposed || controller.signal.aborted) return;
33
+ controller.abort(new StreamIdleTimeoutError(idleTimeoutMs));
34
+ }, idleTimeoutMs);
35
+ };
36
+ const onParentAbort = () => {
37
+ if (controller.signal.aborted) return;
38
+ clear();
39
+ controller.abort(parentSignal?.reason);
40
+ };
41
+ if (parentSignal !== void 0) {
42
+ if (parentSignal.aborted) {
43
+ controller.abort(parentSignal.reason);
44
+ } else {
45
+ parentSignal.addEventListener("abort", onParentAbort);
46
+ }
47
+ }
48
+ arm();
49
+ return {
50
+ signal: controller.signal,
51
+ poke() {
52
+ arm();
53
+ },
54
+ dispose() {
55
+ disposed = true;
56
+ clear();
57
+ parentSignal?.removeEventListener("abort", onParentAbort);
62
58
  }
63
- arm();
64
- return {
65
- signal: controller.signal,
66
- poke() {
67
- arm();
68
- },
69
- dispose() {
70
- disposed = true;
71
- clear();
72
- parentSignal?.removeEventListener("abort", onParentAbort);
73
- },
74
- };
59
+ };
75
60
  }
61
+ export {
62
+ DEFAULT_STREAM_IDLE_TIMEOUT_MS,
63
+ STREAM_IDLE_TIMEOUT_CODE,
64
+ StreamIdleTimeoutError,
65
+ createStreamIdleGuard,
66
+ isStreamIdleTimeoutError
67
+ };
@@ -0,0 +1,244 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { homeFromRunDirectory } from "./activation-ledger-topology.js";
6
+ import { subjectKeyedRecordDirectory } from "./archivist-record-topology.js";
7
+ import { resolvePackageRootDir } from "./session-opening-materials.js";
8
+ const TICKET_SEAT_RUN_BINDING_ENTRY_TYPE = "ak_ticket_seat_run_binding";
9
+ function isTicketSeatRunBindingRow(row) {
10
+ return row.type === "custom" && row.customType === TICKET_SEAT_RUN_BINDING_ENTRY_TYPE;
11
+ }
12
+ function ticketSeatRunBindingRunId(row) {
13
+ if (!isTicketSeatRunBindingRow(row)) return void 0;
14
+ if (row.data === null || typeof row.data !== "object" || Array.isArray(row.data)) {
15
+ return void 0;
16
+ }
17
+ const runId = row.data.runId;
18
+ return typeof runId === "string" && runId.length > 0 ? runId : void 0;
19
+ }
20
+ async function loadCreateRecordSessionOpen() {
21
+ const packageRoot = resolvePackageRootDir(import.meta.url);
22
+ const built = join(packageRoot, "dist/archivist-record-entry.js");
23
+ const source = join(packageRoot, "src/archivist-record-entry.ts");
24
+ const target = existsSync(built) ? built : source;
25
+ const mod = await import(pathToFileURL(target).href);
26
+ return mod.createRecordSessionOpen;
27
+ }
28
+ const TICKET_SEAT_MEMORY_KIND = "auditor-roles";
29
+ const TICKET_SEAT_MEMORY_SEATS = ["inspector", "notary", "auditor"];
30
+ function isTicketSeatMemorySeat(value) {
31
+ return TICKET_SEAT_MEMORY_SEATS.includes(value);
32
+ }
33
+ function isTicketSeatMemoryBound(input) {
34
+ return isTicketSeatMemorySeat(input.role) && typeof input.ticketNumber === "number" && Number.isSafeInteger(input.ticketNumber) && input.ticketNumber >= 1;
35
+ }
36
+ function isEnoent(error) {
37
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
38
+ }
39
+ function ticketSeatMemorySubject(ticketNumber, seat) {
40
+ if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
41
+ throw new Error(
42
+ `ticket-seat memory subject requires a positive ticket number, got ${String(ticketNumber)}`
43
+ );
44
+ }
45
+ return `${ticketNumber}:${seat}`;
46
+ }
47
+ function ticketSeatMemorySessionDirectory(input) {
48
+ return subjectKeyedRecordDirectory({
49
+ cwd: input.cwd,
50
+ kind: TICKET_SEAT_MEMORY_KIND,
51
+ subject: ticketSeatMemorySubject(input.ticketNumber, input.seat),
52
+ ...input.parentSessionFile === void 0 ? {} : { parentSessionFile: input.parentSessionFile },
53
+ ...input.home === void 0 ? {} : { home: input.home }
54
+ });
55
+ }
56
+ async function readRunAdmittedPageFacts(runDirectory) {
57
+ try {
58
+ const raw = JSON.parse(
59
+ await readFile(join(runDirectory, "admitted-request.json"), "utf8")
60
+ );
61
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
62
+ return {};
63
+ }
64
+ const record = raw;
65
+ const ticketNumber = record.ticketNumber;
66
+ const projectRoot = record.projectRoot;
67
+ return {
68
+ ...typeof ticketNumber === "number" && Number.isSafeInteger(ticketNumber) && ticketNumber >= 1 ? { ticketNumber } : {},
69
+ ...typeof projectRoot === "string" ? { projectRoot } : {}
70
+ };
71
+ } catch (error) {
72
+ if (isEnoent(error)) return {};
73
+ throw error;
74
+ }
75
+ }
76
+ async function readInvocationTicketNumber(runDirectory) {
77
+ try {
78
+ const raw = JSON.parse(
79
+ await readFile(join(runDirectory, "invocation.json"), "utf8")
80
+ );
81
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
82
+ return void 0;
83
+ }
84
+ const ticketNumber = raw.ticketNumber;
85
+ if (typeof ticketNumber === "number" && Number.isSafeInteger(ticketNumber) && ticketNumber >= 1) {
86
+ return ticketNumber;
87
+ }
88
+ } catch (error) {
89
+ if (isEnoent(error)) return void 0;
90
+ throw error;
91
+ }
92
+ return void 0;
93
+ }
94
+ async function readRunTicketNumber(runDirectory) {
95
+ const admitted = await readRunAdmittedPageFacts(runDirectory);
96
+ if (admitted.ticketNumber !== void 0) return admitted.ticketNumber;
97
+ return readInvocationTicketNumber(runDirectory);
98
+ }
99
+ async function resolveTicketSeatMemoryNestDirectories(input) {
100
+ if (input.seats.length === 0) return [];
101
+ const admitted = await readRunAdmittedPageFacts(input.runDirectory);
102
+ const ticketNumber = admitted.ticketNumber ?? await readInvocationTicketNumber(input.runDirectory);
103
+ if (ticketNumber === void 0) return [];
104
+ let home;
105
+ try {
106
+ home = homeFromRunDirectory(input.runDirectory);
107
+ } catch {
108
+ return [];
109
+ }
110
+ const projectRoot = admitted.projectRoot;
111
+ if (projectRoot === void 0) return [];
112
+ return input.seats.map(
113
+ (seat) => ticketSeatMemorySessionDirectory({
114
+ ticketNumber,
115
+ seat,
116
+ cwd: projectRoot,
117
+ home
118
+ })
119
+ );
120
+ }
121
+ async function openTicketSeatMemoryCoordinates(input) {
122
+ const createRecordSessionOpen = await loadCreateRecordSessionOpen();
123
+ const opened = createRecordSessionOpen({
124
+ cwd: input.cwd,
125
+ kind: TICKET_SEAT_MEMORY_KIND,
126
+ subject: ticketSeatMemorySubject(input.ticketNumber, input.seat),
127
+ parent: {
128
+ getSessionFile: () => input.ledgerAnchorSessionFile
129
+ }
130
+ });
131
+ if (input.runId !== void 0) {
132
+ const data = { version: 1, runId: input.runId };
133
+ opened.session.appendCustomEntry(TICKET_SEAT_RUN_BINDING_ENTRY_TYPE, data);
134
+ }
135
+ const sessionFile = opened.session.getSessionFile();
136
+ const sessionDirectory = opened.session.getSessionDir();
137
+ if (typeof sessionFile !== "string" || sessionFile.length === 0) {
138
+ throw new Error(
139
+ `ticket-seat memory principal missing session file for ticket #${input.ticketNumber} seat ${input.seat}`
140
+ );
141
+ }
142
+ if (typeof sessionDirectory !== "string" || sessionDirectory.length === 0) {
143
+ throw new Error(
144
+ `ticket-seat memory principal missing session directory for ticket #${input.ticketNumber} seat ${input.seat}`
145
+ );
146
+ }
147
+ return { sessionDirectory, sessionFile, resumed: opened.resumed };
148
+ }
149
+ async function rebindAdmittedToTicketSeatMemory(input) {
150
+ const ticketNumber = input.admitted.ticketNumber;
151
+ if (ticketNumber === void 0) return void 0;
152
+ const anchor = input.principalAuthority.decode(input.admitted.principal);
153
+ const opened = await openTicketSeatMemoryCoordinates({
154
+ ticketNumber,
155
+ seat: input.seat,
156
+ cwd: input.admitted.projectRoot,
157
+ ledgerAnchorSessionFile: anchor.sessionFile,
158
+ // Analyst attributes frame/model/tool to this binding interval only (#636 D).
159
+ runId: input.admitted.runId
160
+ });
161
+ const coordinates = {
162
+ sessionDirectory: opened.sessionDirectory,
163
+ sessionFile: opened.sessionFile
164
+ };
165
+ const principal = input.principalAuthority.seal(coordinates);
166
+ input.principalAuthority.decode(principal);
167
+ input.admitted.principal = principal;
168
+ for (const page of ["admitted-request.json", "invocation.json"]) {
169
+ const path = join(input.admitted.runDirectory, page);
170
+ try {
171
+ const raw = JSON.parse(await readFile(path, "utf8"));
172
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) continue;
173
+ const next = {
174
+ ...raw,
175
+ sessionDirectory: coordinates.sessionDirectory,
176
+ sessionFile: coordinates.sessionFile
177
+ };
178
+ await writeFile(path, `${JSON.stringify(next, null, 2)}
179
+ `, "utf8");
180
+ } catch (error) {
181
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
182
+ continue;
183
+ }
184
+ throw error;
185
+ }
186
+ }
187
+ return { coordinates, resumed: opened.resumed };
188
+ }
189
+ const TICKET_SEAT_LAST_HOST_FILE = "last-host.json";
190
+ async function readTicketSeatMemoryLastHost(sessionDirectory) {
191
+ try {
192
+ const raw = JSON.parse(
193
+ await readFile(join(sessionDirectory, TICKET_SEAT_LAST_HOST_FILE), "utf8")
194
+ );
195
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw) || typeof raw.host !== "string" || raw.host.length === 0) {
196
+ throw new Error(
197
+ `ticket-seat memory last-host page is damaged under ${sessionDirectory}`
198
+ );
199
+ }
200
+ const host = raw.host;
201
+ const runDirectory = raw.runDirectory;
202
+ return {
203
+ host,
204
+ ...typeof runDirectory === "string" && runDirectory.length > 0 ? { runDirectory } : {}
205
+ };
206
+ } catch (error) {
207
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
208
+ return void 0;
209
+ }
210
+ throw error;
211
+ }
212
+ }
213
+ async function writeTicketSeatMemoryLastHost(sessionDirectory, host, runDirectory) {
214
+ if (host.trim() === "") {
215
+ throw new Error("ticket-seat memory last-host requires a non-empty host");
216
+ }
217
+ const body = {
218
+ host,
219
+ ...runDirectory !== void 0 && runDirectory.length > 0 ? { runDirectory } : {}
220
+ };
221
+ await writeFile(
222
+ join(sessionDirectory, TICKET_SEAT_LAST_HOST_FILE),
223
+ `${JSON.stringify(body, null, 2)}
224
+ `,
225
+ "utf8"
226
+ );
227
+ }
228
+ export {
229
+ TICKET_SEAT_MEMORY_KIND,
230
+ TICKET_SEAT_MEMORY_SEATS,
231
+ TICKET_SEAT_RUN_BINDING_ENTRY_TYPE,
232
+ isTicketSeatMemoryBound,
233
+ isTicketSeatMemorySeat,
234
+ isTicketSeatRunBindingRow,
235
+ openTicketSeatMemoryCoordinates,
236
+ readRunTicketNumber,
237
+ readTicketSeatMemoryLastHost,
238
+ rebindAdmittedToTicketSeatMemory,
239
+ resolveTicketSeatMemoryNestDirectories,
240
+ ticketSeatMemorySessionDirectory,
241
+ ticketSeatMemorySubject,
242
+ ticketSeatRunBindingRunId,
243
+ writeTicketSeatMemoryLastHost
244
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.3414",
3
+ "version": "0.1.3439",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -21,6 +21,47 @@ const entries = [
21
21
  "activation-ledger-topology",
22
22
  "activation-reconciliation",
23
23
  "archivist-record-entry",
24
+ // Pure subject nest topology — cold discovery without SessionManager (#636).
25
+ "archivist-record-topology",
26
+ // Officer ticket-seat pure read + deferred open (#636 public-bin cold graph).
27
+ "ticket-seat-memory",
28
+ // ticket-seat-memory → session-opening-materials (#636 non-bundle graph closure).
29
+ "session-opening-materials",
30
+ // Value-import closure of published non-bundle roots (build-package-only loadable).
31
+ "auditor-dossier-tool",
32
+ "canonical-json",
33
+ "compliance-transport",
34
+ "countersign-contracts",
35
+ "doctor-contracts",
36
+ "engine-detour",
37
+ "engine-detour-tool",
38
+ "exact-utf8",
39
+ "git-object-id",
40
+ "gleaner-left-contracts",
41
+ "inspector-contracts",
42
+ "institutional-resolution",
43
+ "merger-contracts",
44
+ "notary-contracts",
45
+ "open-tool-schema",
46
+ "package-contracts/collector-output",
47
+ "package-contracts/fixer-output",
48
+ "package-contracts/fixer-packet",
49
+ "package-contracts/gatekeeper-output",
50
+ "package-contracts/judge-output",
51
+ "package-contracts/navigator-output",
52
+ "package-contracts/reviewer-output",
53
+ "package-contracts/terminating-infrastructure",
54
+ "package-contracts/worker-output",
55
+ "package-resources/engine-material",
56
+ "public-cli/config",
57
+ "public-cli/registry",
58
+ "receipt-delivery-policy",
59
+ "sha256",
60
+ "sitian-appender",
61
+ "sitian-contracts",
62
+ "sitian-facade",
63
+ "sitian-reader",
64
+ "stream-idle-guard",
24
65
  "typed-provider-http",
25
66
  "upstream-error-testimony",
26
67
  ];