@akagilnc/pi-workflow-roles 0.1.5478 → 0.1.5504
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/dist/acp-host/production-host.js +4945 -4980
- package/dist/analyst-gate-cycles-read.js +11 -29
- package/dist/analyst-ledger.js +10 -12
- package/dist/archivist-record-entry.js +4 -3
- package/dist/archivist-record-pointer.js +59 -32
- package/dist/atomic-write.js +2 -2
- package/dist/auditor-dossier-tool.js +8 -4
- package/dist/auditor-soul.js +2 -1
- package/dist/collector-config.js +6 -5
- package/dist/doctor-evidence.js +5 -1
- package/dist/engine-detour-usage.js +4 -10
- package/dist/headless-host/description.js +251 -0
- package/dist/headless-host/production-host.js +2787 -2658
- package/dist/ledger-session-read.js +5 -0
- package/dist/migrate-book-topology.js +129 -100
- package/dist/navigator-public-session.js +13 -17
- package/dist/notary-source-run.js +7 -15
- package/dist/packaged-role-registry.js +0 -12
- package/dist/pi/durable-principal.js +2 -3
- package/dist/pi/role-turn-host.js +27 -13
- package/dist/public-cli/instruction-seat-run.js +4 -4
- package/dist/public-cli/invocation.js +17 -45
- package/dist/public-cli/main.js +1074 -1085
- package/dist/public-cli/run-lifecycle.js +17 -47
- package/dist/public-cli/settlement.js +28 -128
- package/dist/public-cli/terminal.js +0 -12
- package/dist/role-run-placement.js +52 -5
- package/dist/role-run-relocation.js +39 -2
- package/dist/run-terminal-artifacts.js +2 -6
- package/dist/run-ticket-number.js +33 -4
- package/dist/session-assistant-usage.js +9 -18
- package/dist/session-identity.js +3 -4
- package/dist/sitian-appender.js +20 -6
- package/dist/submission-ledger.js +4 -4
- package/dist/ticket-provenance-contracts.js +2 -8
- package/dist/ticket-provenance.js +5 -4
- package/package.json +1 -1
- package/src/acp-host/role-turn-host.ts +2 -2
- package/src/analyst-gate-cycles-read.ts +11 -34
- package/src/analyst-ledger.ts +14 -14
- package/src/archivist-record-entry.ts +4 -3
- package/src/archivist-record-pointer.ts +70 -34
- package/src/atomic-write.ts +3 -1
- package/src/auditor-dossier-tool.ts +8 -4
- package/src/auditor-soul.ts +2 -1
- package/src/collector-config.ts +5 -3
- package/src/doctor-evidence.ts +5 -1
- package/src/engine-detour-usage.ts +10 -13
- package/src/factory-board.ts +16 -81
- package/src/headless-host/description.ts +248 -1
- package/src/headless-host/production-host.ts +1 -2
- package/src/headless-host/role-turn-host.ts +10 -9
- package/src/ledger-session-read.ts +6 -0
- package/src/navigator-public-session.ts +13 -18
- package/src/navigator-work-context.ts +3 -1
- package/src/notary-role.ts +2 -1
- package/src/notary-source-run.ts +7 -17
- package/src/packaged-role-registry.ts +0 -15
- package/src/pi/durable-principal.ts +2 -4
- package/src/pi/role-turn-host.ts +35 -12
- package/src/public-cli/instruction-seat-run.ts +4 -4
- package/src/public-cli/invocation.ts +29 -57
- package/src/public-cli/run-lifecycle.ts +20 -43
- package/src/public-cli/settlement.ts +30 -173
- package/src/public-cli/terminal.ts +0 -60
- package/src/role-envelope.ts +4 -2
- package/src/role-run-placement.ts +63 -4
- package/src/role-run-relocation.ts +39 -2
- package/src/role-runtime.ts +40 -59
- package/src/run-terminal-artifacts.ts +3 -5
- package/src/run-ticket-number.ts +41 -3
- package/src/session-assistant-usage.ts +8 -20
- package/src/session-identity.ts +3 -4
- package/src/sitian-appender.ts +20 -12
- package/src/submission-ledger.ts +4 -4
- package/src/ticket-provenance-contracts.ts +3 -6
- package/src/ticket-provenance.ts +5 -6
- package/src/ticket-snapshot.ts +3 -2
- package/src/ticket-trajectory.ts +85 -99
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sole nested-volume reader for gate-cycle facts under session/auditor-roles/.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* consume retained facts. Terminal settlement reuses this same pairing seam
|
|
7
|
-
* (no second auditor-roles scanner).
|
|
4
|
+
* Consumer: Analyst sole ledger scan (classifyScopedRun). Metric families must
|
|
5
|
+
* not open a second disk scan — they consume retained facts.
|
|
8
6
|
*
|
|
9
7
|
* Naming: records may carry pre-#440 menxia/jishizhong/fubaolang tool faces or
|
|
10
8
|
* the current gatekeeper/inspector/notary English face. Projection always uses
|
|
@@ -29,7 +27,10 @@ import { readdir } from "node:fs/promises";
|
|
|
29
27
|
import { join } from "node:path";
|
|
30
28
|
import { AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE, } from "./compliance-transport.js";
|
|
31
29
|
import { extractSessionTimestampSpan, intervalRowsAroundAnchor, readLedgerSessionJsonl, } from "./ledger-session-read.js";
|
|
32
|
-
import { isRecord,
|
|
30
|
+
import { isRecord, isEnoent } from "./unknown-value.js";
|
|
31
|
+
import { retainedRunPathsMatch } from "./role-run-relocation.js";
|
|
32
|
+
import { runDirectoryOfSessionFile } from "./role-run-placement.js";
|
|
33
|
+
import { resolveOfficerSessionFromPointerFile } from "./archivist-record-pointer.js";
|
|
33
34
|
const DISPATCH_TOOLS = new Set(["ak_menxia_output", "ak_gatekeeper_output"]);
|
|
34
35
|
/** Officer terminating tool → current English officer identity. */
|
|
35
36
|
const OFFICER_TOOL_TO_FACE = {
|
|
@@ -309,27 +310,6 @@ function pairGateRounds(volumes) {
|
|
|
309
310
|
.sort((a, b) => a.officerStartedAt.localeCompare(b.officerStartedAt))
|
|
310
311
|
.map((round, index) => ({ ...round, roundIndex: index + 1 }));
|
|
311
312
|
}
|
|
312
|
-
/** Resolve a direct-officer-run-pointer file to the officer session 正本 path. */
|
|
313
|
-
async function resolveOfficerSessionFromPointerFile(pointerPath) {
|
|
314
|
-
const { readFile } = await import("node:fs/promises");
|
|
315
|
-
let raw;
|
|
316
|
-
try {
|
|
317
|
-
raw = JSON.parse(await readFile(pointerPath, "utf8"));
|
|
318
|
-
}
|
|
319
|
-
catch (error) {
|
|
320
|
-
throw new Error(`direct officer run pointer unreadable in ${pointerPath}: ${errorText(error)}`, { cause: error });
|
|
321
|
-
}
|
|
322
|
-
if (!isRecord(raw) || raw.kind !== "direct-officer-run-pointer" || raw.version !== 1) {
|
|
323
|
-
throw new Error(`direct officer run pointer has unknown shape in ${pointerPath}`);
|
|
324
|
-
}
|
|
325
|
-
const sessionFile = raw.sessionFile;
|
|
326
|
-
if (typeof sessionFile !== "string" || sessionFile.trim() === "") {
|
|
327
|
-
throw new Error(`direct officer run pointer missing sessionFile in ${pointerPath}`);
|
|
328
|
-
}
|
|
329
|
-
const officer = raw.officer === "inspector" || raw.officer === "notary"
|
|
330
|
-
? raw.officer : undefined;
|
|
331
|
-
return { sessionFile, ...(officer === undefined ? {} : { officer }) };
|
|
332
|
-
}
|
|
333
313
|
/**
|
|
334
314
|
* Read and pair gate-cycle rounds from one or more auditor-roles directories.
|
|
335
315
|
* Accepts historical nested JSONL volumes and #675 direct-officer-run-pointer
|
|
@@ -346,7 +326,7 @@ export async function readAnalystGateCyclesFromAuditorRoles(auditorRolesDirector
|
|
|
346
326
|
const volumes = [];
|
|
347
327
|
// Same officer session pointed at N times (historical multi-mint pointers, or
|
|
348
328
|
// one parent booking many leaves) must classify once — else each accepted
|
|
349
|
-
// seal is counted ×N in
|
|
329
|
+
// seal is counted ×N in gate-cycle statistics (#753 acceptance A).
|
|
350
330
|
const classifiedOfficerSessions = new Set();
|
|
351
331
|
for (const directory of directories) {
|
|
352
332
|
let names;
|
|
@@ -375,11 +355,13 @@ export async function readAnalystGateCyclesFromAuditorRoles(auditorRolesDirector
|
|
|
375
355
|
continue;
|
|
376
356
|
classifiedOfficerSessions.add(sessionPath);
|
|
377
357
|
}
|
|
378
|
-
const
|
|
358
|
+
const officer = pointer?.officer === "inspector" || pointer?.officer === "notary"
|
|
359
|
+
? pointer.officer : undefined;
|
|
360
|
+
const classified = await classifyAuditorVolume(sessionPath, officer);
|
|
379
361
|
for (const volume of classified) {
|
|
380
362
|
if (options.parentSessionFile !== undefined &&
|
|
381
363
|
volume.parentSessionFile !== undefined &&
|
|
382
|
-
volume.parentSessionFile
|
|
364
|
+
!await retainedRunPathsMatch(volume.parentSessionFile, options.parentSessionFile, runDirectoryOfSessionFile(options.parentSessionFile))) {
|
|
383
365
|
continue;
|
|
384
366
|
}
|
|
385
367
|
volumes.push(volume);
|
package/dist/analyst-ledger.js
CHANGED
|
@@ -16,9 +16,11 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
16
16
|
import { basename, join } from "node:path";
|
|
17
17
|
import { isSyntheticAnalystBookKey, resolveAnalystBookKey } from "./analyst-book-key.js";
|
|
18
18
|
import { pathContainedIn, physicalPathIdentity, resolveActivationLedgerHome, } from "./activation-ledger-topology.js";
|
|
19
|
-
import { listBookRunDirectories } from "./role-run-placement.js";
|
|
19
|
+
import { listBookRunDirectories, parseRunLeaf, sessionFileOf, } from "./role-run-placement.js";
|
|
20
|
+
import { sitianRunVolumeDirectory } from "./sitian-appender.js";
|
|
20
21
|
import { autopsyWriterLock, readRoleRunIdentity } from "./public-cli/run-lifecycle.js";
|
|
21
22
|
import { readRunTicketNumber } from "./run-ticket-number.js";
|
|
23
|
+
import { rewriteRunDirectoryPathValue } from "./role-run-relocation.js";
|
|
22
24
|
import { extractSessionModelSequence, extractSessionTimestampSpan, extractSessionToolIntervals, LedgerSessionJsonlError, readLedgerSessionJsonl, } from "./ledger-session-read.js";
|
|
23
25
|
import { readRunTerminalArtifact, } from "./run-terminal-artifacts.js";
|
|
24
26
|
import { readAnalystGateCyclesFromAuditorRoles, } from "./analyst-gate-cycles-read.js";
|
|
@@ -65,12 +67,6 @@ async function classifyGhostCandidate(input) {
|
|
|
65
67
|
},
|
|
66
68
|
};
|
|
67
69
|
}
|
|
68
|
-
function parseRunDirectoryName(name) {
|
|
69
|
-
const at = name.lastIndexOf("@");
|
|
70
|
-
if (at <= 0 || at === name.length - 1)
|
|
71
|
-
return undefined;
|
|
72
|
-
return { runId: name.slice(0, at), role: name.slice(at + 1) };
|
|
73
|
-
}
|
|
74
70
|
async function listLedgerBookNames(booksRoot) {
|
|
75
71
|
try {
|
|
76
72
|
const entries = await readdir(booksRoot, { withFileTypes: true });
|
|
@@ -136,14 +132,16 @@ async function resolveSessionFile(runDirectory) {
|
|
|
136
132
|
if (isRecord(parsed)
|
|
137
133
|
&& typeof parsed.sessionFile === "string"
|
|
138
134
|
&& parsed.sessionFile.trim() !== "") {
|
|
139
|
-
return parsed.
|
|
135
|
+
return typeof parsed.runDirectory === "string"
|
|
136
|
+
? rewriteRunDirectoryPathValue(parsed.sessionFile, parsed.runDirectory, runDirectory)
|
|
137
|
+
: parsed.sessionFile;
|
|
140
138
|
}
|
|
141
139
|
}
|
|
142
140
|
catch (error) {
|
|
143
141
|
if (!isMissingPathError(error))
|
|
144
142
|
throw error;
|
|
145
143
|
}
|
|
146
|
-
return
|
|
144
|
+
return sessionFileOf(runDirectory);
|
|
147
145
|
}
|
|
148
146
|
/**
|
|
149
147
|
* Attribute session rows to one run.
|
|
@@ -394,8 +392,8 @@ async function classifyScopedRun(input) {
|
|
|
394
392
|
// nested JSONL is page-local unreadable — never silently under-count rounds.
|
|
395
393
|
let gateCycles;
|
|
396
394
|
try {
|
|
397
|
-
const parentSessionFile =
|
|
398
|
-
gateCycles = await readAnalystGateCyclesFromAuditorRoles(
|
|
395
|
+
const parentSessionFile = sessionFileOf(input.runDirectory);
|
|
396
|
+
gateCycles = await readAnalystGateCyclesFromAuditorRoles(sitianRunVolumeDirectory(input.runDirectory, "auditor-roles"), { parentSessionFile });
|
|
399
397
|
}
|
|
400
398
|
catch (error) {
|
|
401
399
|
return {
|
|
@@ -497,7 +495,7 @@ export async function scanAnalystIssueRuns(input) {
|
|
|
497
495
|
}
|
|
498
496
|
for (const runDirectory of runDirectories) {
|
|
499
497
|
const runName = basename(runDirectory);
|
|
500
|
-
const parsed =
|
|
498
|
+
const parsed = parseRunLeaf(runName);
|
|
501
499
|
if (parsed === undefined)
|
|
502
500
|
continue;
|
|
503
501
|
let scopeFields;
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
resolveNavigatorWorkSubjectPlacement
|
|
26
26
|
} from "./archivist-record-topology.js";
|
|
27
27
|
import { piRecordSessionHost } from "./pi/record-session-host.js";
|
|
28
|
+
import { sitianVolumeDirectory } from "./sitian-appender.js";
|
|
28
29
|
import {
|
|
29
30
|
DIRECT_OFFICER_RUN_POINTER_KIND,
|
|
30
31
|
bookDirectOfficerRunPointer
|
|
@@ -35,7 +36,7 @@ import {
|
|
|
35
36
|
} from "./archivist-record-topology.js";
|
|
36
37
|
const CURRENT_SESSION_LEDGER = "current-session.json";
|
|
37
38
|
function readCurrentSession(sessionDir) {
|
|
38
|
-
const ledger =
|
|
39
|
+
const ledger = currentSessionLedgerPath(sessionDir);
|
|
39
40
|
try {
|
|
40
41
|
const value = JSON.parse(readFileSync(ledger, "utf8"));
|
|
41
42
|
if (typeof value !== "object" || value === null || typeof value.sessionFile !== "string" || value.sessionFile.length === 0) {
|
|
@@ -50,7 +51,7 @@ function readCurrentSession(sessionDir) {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
function writeCurrentSession(sessionDir, sessionFile) {
|
|
53
|
-
const ledger =
|
|
54
|
+
const ledger = currentSessionLedgerPath(sessionDir);
|
|
54
55
|
try {
|
|
55
56
|
writeFileSync(ledger, `${JSON.stringify({ sessionFile })}
|
|
56
57
|
`, { flag: "wx" });
|
|
@@ -268,7 +269,7 @@ function createRecordSessionOpen(options, host = piRecordSessionHost) {
|
|
|
268
269
|
if (!physicallyContainedIn(ledgerHome, parentResolved)) {
|
|
269
270
|
throw new Error("Durable record ownership requires a parent session inside the ledger home");
|
|
270
271
|
}
|
|
271
|
-
sessionDir =
|
|
272
|
+
sessionDir = sitianVolumeDirectory(dirname(parentResolved), options.kind);
|
|
272
273
|
parentSession = parentFile;
|
|
273
274
|
mayResumeSameNest = options.kind === WORKER_SUBMISSION_GATE_KIND;
|
|
274
275
|
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { isRecord } from "./unknown-value.js";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
4
|
+
import { isRecord, errorText } from "./unknown-value.js";
|
|
5
|
+
import { homeFromRunDirectory } from "./activation-ledger-topology.js";
|
|
6
|
+
import { findRunDirectoryById, readRoleRunIdentity } from "./public-cli/run-lifecycle.js";
|
|
7
|
+
import { rewriteRunDirectoryPathValue } from "./role-run-relocation.js";
|
|
8
|
+
import { parseRunLeaf, runDirectoryOfSessionFile, runDirectoryFromSessionDirectory } from "./role-run-placement.js";
|
|
9
|
+
import { sitianVolumeDirectory } from "./sitian-appender.js";
|
|
5
10
|
/** Typed parent-side pointer to an independent officer run 正本 (ADR 0079 / #675). */
|
|
6
11
|
export const DIRECT_OFFICER_RUN_POINTER_KIND = "direct-officer-run-pointer";
|
|
12
|
+
function directOfficerRunPointerFile(parentSessionFile, officer) {
|
|
13
|
+
return join(sitianVolumeDirectory(dirname(parentSessionFile), "auditor-roles"), `${officer}.pointer.json`);
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
16
|
* Book a typed pointer under parent session/auditor-roles (same nest owner as
|
|
9
17
|
* createRecordSession). Never fabricates user/assistant/toolResult rows (#675).
|
|
@@ -11,11 +19,11 @@ export const DIRECT_OFFICER_RUN_POINTER_KIND = "direct-officer-run-pointer";
|
|
|
11
19
|
*
|
|
12
20
|
* Stable leaf per officer under one parent (#753 gate-round accounting):
|
|
13
21
|
* same-parent re-summons upsert the same pointer instead of minting N files that
|
|
14
|
-
* each re-scan the full officer session and multiply
|
|
22
|
+
* each re-scan the full officer session and multiply gate-cycle counts.
|
|
15
23
|
*/
|
|
16
24
|
export function bookDirectOfficerRunPointer(options) {
|
|
17
|
-
const
|
|
18
|
-
mkdirSync(
|
|
25
|
+
const pointerFile = directOfficerRunPointerFile(options.parentSessionFile, options.officer);
|
|
26
|
+
mkdirSync(dirname(pointerFile), { recursive: true });
|
|
19
27
|
const submissionToolCallId = options.submissionToolCallId?.trim() ?? "";
|
|
20
28
|
const pointer = {
|
|
21
29
|
version: 1,
|
|
@@ -27,38 +35,57 @@ export function bookDirectOfficerRunPointer(options) {
|
|
|
27
35
|
: {}),
|
|
28
36
|
...(submissionToolCallId === "" ? {} : { submissionToolCallId }),
|
|
29
37
|
};
|
|
30
|
-
writeFileSync(
|
|
38
|
+
writeFileSync(pointerFile, `${JSON.stringify(pointer)}\n`, "utf8");
|
|
31
39
|
return pointer;
|
|
32
40
|
}
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*/
|
|
37
|
-
export async function readDirectOfficerRunPointer(parentSessionFile, officer) {
|
|
41
|
+
/** Shared strict pointer IO; internal audit wraps unreadability as a re-summons. */
|
|
42
|
+
export async function resolveOfficerSessionFromPointerFile(pointerPath) {
|
|
43
|
+
let raw;
|
|
38
44
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
raw = JSON.parse(await readFile(pointerPath, "utf8"));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`direct officer run pointer unreadable in ${pointerPath}: ${errorText(error)}`, { cause: error });
|
|
49
|
+
}
|
|
50
|
+
if (!isRecord(raw) || raw.kind !== DIRECT_OFFICER_RUN_POINTER_KIND || raw.version !== 1) {
|
|
51
|
+
throw new Error(`direct officer run pointer has unknown shape in ${pointerPath}`);
|
|
52
|
+
}
|
|
53
|
+
if (typeof raw.sessionFile !== "string" || raw.sessionFile.trim() === "") {
|
|
54
|
+
throw new Error(`direct officer run pointer missing sessionFile in ${pointerPath}`);
|
|
55
|
+
}
|
|
56
|
+
const officer = raw.officer === "inspector" || raw.officer === "notary"
|
|
57
|
+
|| raw.officer === "auditor" || raw.officer === "countersign" ? raw.officer : undefined;
|
|
58
|
+
let runDirectory = typeof raw.runDirectory === "string" && raw.runDirectory.trim() !== ""
|
|
59
|
+
? raw.runDirectory : undefined;
|
|
60
|
+
let sessionFile = raw.sessionFile;
|
|
61
|
+
const recordedRunDirectory = runDirectory ?? runDirectoryOfSessionFile(sessionFile);
|
|
62
|
+
const leaf = parseRunLeaf(basename(recordedRunDirectory));
|
|
63
|
+
const parentRunDirectory = runDirectoryFromSessionDirectory(dirname(dirname(pointerPath)));
|
|
64
|
+
const parentIdentity = await readRoleRunIdentity(parentRunDirectory);
|
|
65
|
+
if (leaf !== undefined && parentIdentity !== undefined) {
|
|
66
|
+
const currentRunDirectory = await findRunDirectoryById(homeFromRunDirectory(parentRunDirectory), leaf.runId, parentIdentity.bookKey, leaf.role);
|
|
67
|
+
if (currentRunDirectory !== undefined) {
|
|
68
|
+
sessionFile = rewriteRunDirectoryPathValue(sessionFile, recordedRunDirectory, currentRunDirectory);
|
|
69
|
+
if (runDirectory !== undefined)
|
|
70
|
+
runDirectory = currentRunDirectory;
|
|
42
71
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
}
|
|
73
|
+
const submissionToolCallId = typeof raw.submissionToolCallId === "string"
|
|
74
|
+
&& raw.submissionToolCallId.trim() !== "" ? raw.submissionToolCallId : undefined;
|
|
75
|
+
return {
|
|
76
|
+
sessionFile,
|
|
77
|
+
...(officer === undefined ? {} : { officer }),
|
|
78
|
+
...(runDirectory === undefined ? {} : { runDirectory }),
|
|
79
|
+
...(submissionToolCallId === undefined ? {} : { submissionToolCallId }),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Missing or unreadable is not a pass: the internal audit caller re-runs the gate. */
|
|
83
|
+
export async function readDirectOfficerRunPointer(parentSessionFile, officer) {
|
|
84
|
+
try {
|
|
85
|
+
const pointer = await resolveOfficerSessionFromPointerFile(directOfficerRunPointerFile(parentSessionFile, officer));
|
|
86
|
+
if (pointer.officer !== officer)
|
|
46
87
|
return undefined;
|
|
47
|
-
|
|
48
|
-
? raw.runDirectory
|
|
49
|
-
: undefined;
|
|
50
|
-
const submissionToolCallId = typeof raw.submissionToolCallId === "string"
|
|
51
|
-
&& raw.submissionToolCallId.trim() !== ""
|
|
52
|
-
? raw.submissionToolCallId
|
|
53
|
-
: undefined;
|
|
54
|
-
return {
|
|
55
|
-
version: 1,
|
|
56
|
-
kind: DIRECT_OFFICER_RUN_POINTER_KIND,
|
|
57
|
-
officer,
|
|
58
|
-
sessionFile: raw.sessionFile,
|
|
59
|
-
...(runDirectory === undefined ? {} : { runDirectory }),
|
|
60
|
-
...(submissionToolCallId === undefined ? {} : { submissionToolCallId }),
|
|
61
|
-
};
|
|
88
|
+
return { ...pointer, officer, version: 1, kind: DIRECT_OFFICER_RUN_POINTER_KIND };
|
|
62
89
|
}
|
|
63
90
|
catch {
|
|
64
91
|
return undefined;
|
package/dist/atomic-write.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { rename, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
async function writeFileAtomically(destination, contents) {
|
|
4
|
+
async function writeFileAtomically(destination, contents, options) {
|
|
5
5
|
const parent = dirname(destination);
|
|
6
6
|
const temporary = join(parent, `.atomic-write-${randomUUID()}.tmp`);
|
|
7
7
|
try {
|
|
8
|
-
await writeFile(temporary, contents);
|
|
8
|
+
await writeFile(temporary, contents, options);
|
|
9
9
|
await rename(temporary, destination);
|
|
10
10
|
} catch (error) {
|
|
11
11
|
await rm(temporary, { force: true }).catch(() => void 0);
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
roleRunArtifactsDirectory,
|
|
4
|
+
runDirectoryOfSessionFile,
|
|
5
|
+
sessionFileOf
|
|
6
|
+
} from "./role-run-placement.js";
|
|
3
7
|
import { Type } from "typebox";
|
|
4
8
|
const AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
|
|
5
9
|
function auditorRunDirectory(context) {
|
|
6
10
|
const sessionFile = context.sessionManager?.getSessionFile?.();
|
|
7
11
|
if (sessionFile === void 0) return void 0;
|
|
8
|
-
return resolve(
|
|
12
|
+
return resolve(runDirectoryOfSessionFile(sessionFile));
|
|
9
13
|
}
|
|
10
14
|
function createAuditorDossierTool(runDirectory) {
|
|
11
15
|
return {
|
|
@@ -24,7 +28,7 @@ function createAuditorDossierTool(runDirectory) {
|
|
|
24
28
|
const details = {
|
|
25
29
|
runDirectory,
|
|
26
30
|
admittedRequest: join(runDirectory, "admitted-request.json"),
|
|
27
|
-
parentSessionCandidate:
|
|
31
|
+
parentSessionCandidate: sessionFileOf(runDirectory),
|
|
28
32
|
attachments: join(runDirectory, "attachments"),
|
|
29
33
|
artifacts: roleRunArtifactsDirectory(runDirectory)
|
|
30
34
|
};
|
package/dist/auditor-soul.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
|
+
import { parseRunLeaf } from "./role-run-placement.js";
|
|
3
4
|
import { isRecord } from "./unknown-value.js";
|
|
4
5
|
import { joinPackageMaterials, readPackageMaterial, } from "./session-opening-materials.js";
|
|
5
6
|
/**
|
|
@@ -84,7 +85,7 @@ export function loadAuditorReferenceMaterialsFromSubjectInput(raw) {
|
|
|
84
85
|
return loadAuditorReferenceMaterials(resolveAuditorSubject(raw));
|
|
85
86
|
}
|
|
86
87
|
function subjectFromSourceDirectory(sourceRunDirectory) {
|
|
87
|
-
const role = basename(sourceRunDirectory)
|
|
88
|
+
const role = parseRunLeaf(basename(sourceRunDirectory))?.role;
|
|
88
89
|
return isAuditorSoulRole(role) ? role : undefined;
|
|
89
90
|
}
|
|
90
91
|
/**
|
package/dist/collector-config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { sha256Hex } from "./sha256.js";
|
|
3
3
|
import { isRecord } from "./unknown-value.js";
|
|
4
|
+
import { isTicketNumberString, parseTicketNumber } from "./run-ticket-number.js";
|
|
4
5
|
export const COLLECTOR_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
|
|
5
6
|
export const COLLECTOR_REPO_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,98}[A-Za-z0-9])?$/;
|
|
6
7
|
function fail(message, cause) {
|
|
@@ -30,13 +31,13 @@ export function parseCollectorRepository(raw) {
|
|
|
30
31
|
return { display: raw, canonical: `${owner}/${repo}`, owner, repo };
|
|
31
32
|
}
|
|
32
33
|
export function parseCollectorPrNumber(raw) {
|
|
33
|
-
if (typeof raw === "string" && !/^[1-9][0-9]*$/.test(raw))
|
|
34
|
-
fail("Collector pull request number must be a positive safe integer string");
|
|
35
34
|
if (typeof raw !== "string" && typeof raw !== "number")
|
|
36
35
|
fail("Collector pull request number is required");
|
|
37
|
-
const value =
|
|
38
|
-
if (
|
|
39
|
-
fail(
|
|
36
|
+
const value = parseTicketNumber(raw);
|
|
37
|
+
if (value === undefined)
|
|
38
|
+
fail(typeof raw === "string" && !isTicketNumberString(raw)
|
|
39
|
+
? "Collector pull request number must be a positive safe integer string"
|
|
40
|
+
: "Collector pull request number must be a positive safe integer");
|
|
40
41
|
return value;
|
|
41
42
|
}
|
|
42
43
|
function canonicalManifest(requests) {
|
package/dist/doctor-evidence.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
2
2
|
import { dirname, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { sha256Hex } from "./sha256.js";
|
|
4
|
+
import { physicallyContainedIn } from "./activation-ledger-topology.js";
|
|
4
5
|
import { AcceptedDetailsContractError, acceptedFacts, isTerminatingToolName, validateAcceptedDetails } from "./package-contracts/terminating-tools.js";
|
|
5
6
|
import { isRecord, isMissingPathError } from "./unknown-value.js";
|
|
6
7
|
async function discoverCaseFiles(root) { const found = []; async function walk(dir, depth) { for (const item of await readdir(dir, { withFileTypes: true })) {
|
|
@@ -106,8 +107,11 @@ function deriveSession(content, id) {
|
|
|
106
107
|
return { session, turns, calls, tokens, statuses, commits };
|
|
107
108
|
}
|
|
108
109
|
/** Read Pi's retained session directory as the sole raw material for one case. */
|
|
109
|
-
export async function loadDoctorCase(runsPath) {
|
|
110
|
+
export async function loadDoctorCase(runsPath, projectRoot) {
|
|
110
111
|
const root = await realpath(runsPath);
|
|
112
|
+
if (projectRoot !== undefined && !physicallyContainedIn(projectRoot, root)) {
|
|
113
|
+
throw new Error("doctor --runs escapes the project root");
|
|
114
|
+
}
|
|
111
115
|
// Canonical <book>/<ticket>/runs; legacy issues/<n>/runs remains read-only compatible.
|
|
112
116
|
const match = root.split(sep).join("/").match(/\/\.ak-roles\/books\/[^/]+\/(?:issues\/)?([1-9]\d*)\/runs$/);
|
|
113
117
|
if (!match)
|
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { randomUUID } from "node:crypto";
|
|
19
19
|
import { readFileSync } from "node:fs";
|
|
20
|
-
import {
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
export { runDirectoryFromSessionDirectory, sessionFileIn as sessionFileFromSessionDirectory, } from "./role-run-placement.js";
|
|
21
22
|
import { ENGINE_DETOUR_TOOL_NAME } from "./engine-detour.js";
|
|
23
|
+
import { sitianRunVolumeDirectory, sitianVolumeRecordsFile } from "./sitian-appender.js";
|
|
22
24
|
import { readSitianRecords, resolveSitianRecordPath, sitianReport, } from "./sitian-facade.js";
|
|
23
25
|
import { isRecord } from "./unknown-value.js";
|
|
24
26
|
/** Sitian event kind for one detour-tool call (volume under session/). */
|
|
@@ -30,7 +32,7 @@ export const ENGINE_DETOUR_TOOL_USAGE_FACT_KEY = "engineDetourToolUsage";
|
|
|
30
32
|
* Openable once the run directory is known from the terminal's run id.
|
|
31
33
|
* Contains no runId bytes itself (#108 + #537).
|
|
32
34
|
*/
|
|
33
|
-
export const ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE =
|
|
35
|
+
export const ENGINE_DETOUR_CALL_RECORD_FILE_RELATIVE = sitianVolumeRecordsFile(sitianRunVolumeDirectory("", ENGINE_DETOUR_CALL_KIND));
|
|
34
36
|
/** stdout UTF-8 byte length (ticket-frozen metric; empty stdout is real 0). */
|
|
35
37
|
export function engineDetourStdoutByteLength(stdout) {
|
|
36
38
|
return Buffer.byteLength(stdout, "utf8");
|
|
@@ -212,14 +214,6 @@ export function withEngineDetourToolUsageFact(outcome, usage) {
|
|
|
212
214
|
},
|
|
213
215
|
};
|
|
214
216
|
}
|
|
215
|
-
/** runDirectory owning a session directory (.../runs/<id>@role/session). */
|
|
216
|
-
export function runDirectoryFromSessionDirectory(sessionDirectory) {
|
|
217
|
-
return dirname(sessionDirectory);
|
|
218
|
-
}
|
|
219
|
-
/** session.jsonl under a session directory. */
|
|
220
|
-
export function sessionFileFromSessionDirectory(sessionDirectory) {
|
|
221
|
-
return join(sessionDirectory, "session.jsonl");
|
|
222
|
-
}
|
|
223
217
|
/**
|
|
224
218
|
* Mint one public-invocation scope id.
|
|
225
219
|
* Call once at the public-entry boundary — never inside the auto-resume loop.
|