@akagilnc/pi-workflow-roles 0.1.4035 → 0.1.4193
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 +2368 -1155
- package/dist/archivist-record-entry.js +204 -20
- package/dist/archivist-record-topology.js +36 -16
- package/dist/auditor-dossier-tool.js +2 -1
- package/dist/diarist-contracts.js +96 -0
- package/dist/doctor-auditor.js +1 -1
- package/dist/doctor-evidence.js +3 -2
- package/dist/dossier-resolution.js +21 -8
- package/dist/gatekeeper-role.js +34 -27
- package/dist/headless-host/description.js +7 -8
- package/dist/headless-host/production-host.js +2375 -1149
- package/dist/host-contracts.js +16 -0
- package/dist/inspector-contracts.js +8 -0
- package/dist/migrate-book-topology.js +278917 -0
- package/dist/navigator-public-session.js +22 -25
- package/dist/notary-source-run.js +7 -4
- package/dist/packaged-role-registry.js +1 -1
- package/dist/pi/durable-principal.js +9 -6
- package/dist/pi/role-turn-host.js +43 -13
- package/dist/public-cli/auto-resume.js +2 -5
- package/dist/public-cli/case-dossier-delivery.js +60 -1
- package/dist/public-cli/diarist-run.js +27 -25
- package/dist/public-cli/inspector-run.js +17 -3
- package/dist/public-cli/instruction-seat-run.js +17 -17
- package/dist/public-cli/invocation.js +127 -63
- package/dist/public-cli/main.js +1685 -696
- package/dist/public-cli/notary-run.js +7 -4
- package/dist/public-cli/option-definitions.js +2 -2
- package/dist/public-cli/post-admission.js +113 -71
- package/dist/public-cli/run-lifecycle.js +209 -58
- package/dist/public-cli/seat-ticket-binding.js +3 -6
- package/dist/public-cli/settlement.js +29 -10
- package/dist/public-role-summons.js +8 -0
- package/dist/role-run-placement.js +84 -0
- package/dist/role-run-relocation.js +358 -0
- package/dist/run-terminal-artifacts.js +2 -1
- package/dist/run-ticket-number.js +51 -32
- package/dist/sitian-appender.js +11 -26
- package/dist/submission-ledger.js +106 -25
- package/dist/ticket-provenance.js +3 -1
- package/dist/user-dialogue-stdin.js +33 -0
- package/extensions/role-runtime.ts +1 -0
- package/package.json +3 -2
- package/resources/836-deleted-machine-instruction-inventory.md +1 -1
- package/scripts/build-package.mjs +34 -2
- package/souls/fixer.md +3 -2
- package/src/analyst-ledger.ts +14 -15
- package/src/archivist-record-entry.ts +285 -38
- package/src/archivist-record-topology.ts +43 -18
- package/src/auditor-dossier-tool.ts +2 -1
- package/src/book-topology-migration-placement.ts +493 -0
- package/src/book-topology-migration.ts +220 -0
- package/src/book-topology-migrators-t11.ts +856 -0
- package/src/book-topology-mixed-volume-migrators.ts +470 -0
- package/src/book-topology-partition-migrators.ts +25 -0
- package/src/book-topology-record-class-migrators.ts +779 -0
- package/src/book-topology-runs-migrator.ts +244 -0
- package/src/diarist-contracts.ts +116 -0
- package/src/diarist-role.ts +6 -0
- package/src/diarist.ts +2 -0
- package/src/doctor-auditor.ts +1 -1
- package/src/doctor-evidence.ts +4 -1
- package/src/doctor-role.ts +1 -1
- package/src/dossier-resolution.ts +26 -8
- package/src/external-host-turn-loop.ts +9 -0
- package/src/gatekeeper-pass-envelope.ts +6 -0
- package/src/gatekeeper-role.ts +47 -28
- package/src/headless-host/description.ts +8 -11
- package/src/headless-host/role-turn-host.ts +20 -5
- package/src/host-contracts.ts +22 -3
- package/src/inspector-contracts.ts +7 -0
- package/src/judge-role.ts +4 -0
- package/src/navigator-public-session.ts +33 -30
- package/src/navigator-work-context.ts +3 -4
- package/src/notary-role.ts +1 -0
- package/src/notary-source-run.ts +9 -4
- package/src/packaged-role-registry.ts +1 -1
- package/src/pi/adapter.ts +19 -4
- package/src/pi/durable-principal.ts +9 -13
- package/src/pi/role-turn-host.ts +48 -14
- package/src/public-cli/auto-resume.ts +2 -6
- package/src/public-cli/case-dossier-delivery.ts +86 -1
- package/src/public-cli/countersign-run.ts +182 -32
- package/src/public-cli/diarist-run.ts +34 -26
- package/src/public-cli/inspector-run.ts +26 -2
- package/src/public-cli/instruction-seat-run.ts +24 -20
- package/src/public-cli/invocation.ts +194 -58
- package/src/public-cli/notary-run.ts +13 -4
- package/src/public-cli/option-definitions.ts +2 -2
- package/src/public-cli/post-admission.ts +147 -78
- package/src/public-cli/run-lifecycle.ts +258 -65
- package/src/public-cli/seat-ticket-binding.ts +3 -6
- package/src/public-cli/settlement.ts +38 -10
- package/src/public-role-summons.ts +31 -7
- package/src/role-envelope.ts +9 -30
- package/src/role-run-placement.ts +128 -0
- package/src/role-run-relocation.ts +491 -0
- package/src/role-runtime-dependencies.ts +1 -0
- package/src/role-runtime.ts +106 -24
- package/src/run-terminal-artifacts.ts +3 -1
- package/src/run-ticket-number.ts +80 -20
- package/src/sitian-appender.ts +25 -28
- package/src/submission-ledger.ts +148 -30
- package/src/ticket-provenance.ts +4 -1
- package/src/ticket-trajectory.ts +22 -35
- package/src/user-dialogue-stdin.ts +37 -0
- package/src/worker-role.ts +8 -4
- package/src/worker-submission-gates.ts +6 -6
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import { resolveActivationLedgerHome, tryHomeFromAkRolesPath, } from "./activation-ledger-topology.js";
|
|
3
|
+
import { courtAttemptIdFromHostContext, runDirectoryFromHostContext, } from "./host-contracts.js";
|
|
2
4
|
import { isAuditEscalationProjection } from "./audit-escalation.js";
|
|
3
5
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.js";
|
|
4
6
|
import { readSitianRecords, resolveSitianRecordPathInLedger, sitianReport } from "./sitian-facade.js";
|
|
7
|
+
import { findRunDirectoryById } from "./public-cli/run-lifecycle.js";
|
|
5
8
|
import { isCorrectableExecuteError } from "./submission-correctable-error.js";
|
|
6
9
|
import { failOnInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.js";
|
|
7
10
|
/**
|
|
@@ -10,8 +13,8 @@ import { failOnInfrastructureFailureDeclaration } from "./package-contracts/term
|
|
|
10
13
|
* otherwise session header id. Never a shared "unbound" bucket.
|
|
11
14
|
*/
|
|
12
15
|
function runIdentity(context) {
|
|
13
|
-
const directory =
|
|
14
|
-
if (
|
|
16
|
+
const directory = runDirectoryFromHostContext(context);
|
|
17
|
+
if (directory !== undefined) {
|
|
15
18
|
const fromDir = runIdFromRunDirectory(directory);
|
|
16
19
|
if (fromDir !== undefined)
|
|
17
20
|
return fromDir;
|
|
@@ -27,26 +30,45 @@ function runIdentity(context) {
|
|
|
27
30
|
*/
|
|
28
31
|
export const COURT_ATTEMPT_ENV = "AK_ROLE_COURT_ATTEMPT";
|
|
29
32
|
function attemptIdentity(context, runId) {
|
|
30
|
-
const courtAttempt =
|
|
31
|
-
if (
|
|
33
|
+
const courtAttempt = courtAttemptIdFromHostContext(context);
|
|
34
|
+
if (courtAttempt !== undefined)
|
|
32
35
|
return courtAttempt;
|
|
33
36
|
return context.sessionManager.getHeader?.()?.id ?? context.sessionManager.getLeafId?.() ?? `${runId}:initial`;
|
|
34
37
|
}
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the submission-ledger record file for a run.
|
|
40
|
+
* Unknown run (no sessionParent and no discoverable directory) → undefined so
|
|
41
|
+
* read APIs return their empty set at the read boundary. Write paths always
|
|
42
|
+
* supply sessionParent and keep the ownership gate.
|
|
43
|
+
*/
|
|
44
|
+
async function submissionRecordFile(cwd, runId, scope) {
|
|
45
|
+
const ledgerHome = resolveActivationLedgerHome(scope.home);
|
|
46
|
+
let sessionParent = scope.sessionParent;
|
|
47
|
+
if (sessionParent === undefined) {
|
|
48
|
+
const discoveredRun = await findRunDirectoryById(scope.home, runId);
|
|
49
|
+
if (discoveredRun === undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
sessionParent = join(discoveredRun, "session", "session.jsonl");
|
|
52
|
+
}
|
|
37
53
|
return resolveSitianRecordPathInLedger({
|
|
38
54
|
level: "event",
|
|
39
55
|
kind: "candidate",
|
|
40
56
|
subject: { runId },
|
|
41
57
|
cwd,
|
|
58
|
+
sessionParent,
|
|
42
59
|
}, ledgerHome).recordFile;
|
|
43
60
|
}
|
|
44
|
-
async function readOwnedSubmissionRecords(cwd, runId,
|
|
45
|
-
const file = submissionRecordFile(cwd, runId,
|
|
61
|
+
async function readOwnedSubmissionRecords(cwd, runId, scope = {}) {
|
|
62
|
+
const file = await submissionRecordFile(cwd, runId, scope);
|
|
63
|
+
if (file === undefined) {
|
|
64
|
+
return { file: undefined, owned: [] };
|
|
65
|
+
}
|
|
46
66
|
const { records } = await readSitianRecords(file);
|
|
47
67
|
return {
|
|
48
68
|
file,
|
|
49
|
-
owned: records.filter((record) => typeof record.subject === "object"
|
|
69
|
+
owned: records.filter((record) => typeof record.subject === "object"
|
|
70
|
+
&& record.subject !== null
|
|
71
|
+
&& record.subject.runId === runId),
|
|
50
72
|
};
|
|
51
73
|
}
|
|
52
74
|
function resolveReadScope(homeOrScope) {
|
|
@@ -85,8 +107,8 @@ function recordAttemptId(record) {
|
|
|
85
107
|
* outranking the current attempt's own real host-turn failure signal
|
|
86
108
|
* (#637 original intent, restored narrowly).
|
|
87
109
|
*/
|
|
88
|
-
export async function hasFreshAttemptSubmission(cwd, runId, attemptId,
|
|
89
|
-
const { owned } = await readOwnedSubmissionRecords(cwd, runId,
|
|
110
|
+
export async function hasFreshAttemptSubmission(cwd, runId, attemptId, homeOrScope) {
|
|
111
|
+
const { owned } = await readOwnedSubmissionRecords(cwd, runId, resolveReadScope(homeOrScope));
|
|
90
112
|
return owned.some((record) => {
|
|
91
113
|
if (recordAttemptId(record) !== attemptId)
|
|
92
114
|
return false;
|
|
@@ -151,10 +173,8 @@ function rowFromPayload(kind, payload, accepted, roleFallback) {
|
|
|
151
173
|
* recorded attemptId + toolCallId so distinct court attempts stay distinct (#881).
|
|
152
174
|
* `accepted` is the original payload; never rebuilt from a status/facts envelope.
|
|
153
175
|
*/
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope.home);
|
|
157
|
-
const scoped = recordsForAttempt(owned, scope.attemptId);
|
|
176
|
+
function mapOwnedToSubmissionRows(owned) {
|
|
177
|
+
const scoped = owned;
|
|
158
178
|
const out = [];
|
|
159
179
|
const indexByCall = new Map();
|
|
160
180
|
// Recover seat identity for historical non-sealed rows that omitted role (#881).
|
|
@@ -238,6 +258,29 @@ export async function readRecordedSubmissionRows(cwd, runId, homeOrScope) {
|
|
|
238
258
|
}
|
|
239
259
|
return out;
|
|
240
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* All recorded role submissions in ledger order (#836 multi-submit).
|
|
263
|
+
* `accepted` is the original payload; never rebuilt from a status/facts envelope.
|
|
264
|
+
* Presentation stays run-scoped: attemptId on the read scope is a recording tag,
|
|
265
|
+
* not a visibility gate (#836).
|
|
266
|
+
*/
|
|
267
|
+
export async function readRecordedSubmissionRows(cwd, runId, homeOrScope) {
|
|
268
|
+
const scope = resolveReadScope(homeOrScope);
|
|
269
|
+
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope);
|
|
270
|
+
const scoped = recordsForAttempt(owned, scope.attemptId);
|
|
271
|
+
return mapOwnedToSubmissionRows(scoped);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Settlement-only this-court rows (#879 return path).
|
|
275
|
+
* Filters by attemptId for court-scoped roleOutcome; does not replace the
|
|
276
|
+
* run-scoped presentation API above (#836 visibility gate stays pass-through).
|
|
277
|
+
*/
|
|
278
|
+
export async function readAttemptScopedSubmissionRows(cwd, runId, attemptId, home) {
|
|
279
|
+
if (attemptId.length === 0)
|
|
280
|
+
return [];
|
|
281
|
+
const { owned } = await readOwnedSubmissionRecords(cwd, runId, home === undefined ? {} : { home });
|
|
282
|
+
return mapOwnedToSubmissionRows(owned.filter((record) => recordAttemptId(record) === attemptId));
|
|
283
|
+
}
|
|
241
284
|
/**
|
|
242
285
|
* All raw role payloads in ledger order (#836 multi-submit).
|
|
243
286
|
* Returns `accepted` bytes as stored — unknown, never re-wrapped.
|
|
@@ -252,7 +295,7 @@ export async function hasRecordedSubmission(cwd, runId, homeOrScope) {
|
|
|
252
295
|
/** Latest non-final outcome on the run ledger (settlement residual precedence). */
|
|
253
296
|
export async function readLatestSubmissionOutcome(cwd, runId, homeOrScope) {
|
|
254
297
|
const scope = resolveReadScope(homeOrScope);
|
|
255
|
-
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope
|
|
298
|
+
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope);
|
|
256
299
|
const scoped = recordsForAttempt(owned, scope.attemptId);
|
|
257
300
|
for (let index = scoped.length - 1; index >= 0; index -= 1) {
|
|
258
301
|
const record = scoped[index];
|
|
@@ -265,14 +308,33 @@ export async function readLatestSubmissionOutcome(cwd, runId, homeOrScope) {
|
|
|
265
308
|
}
|
|
266
309
|
return undefined;
|
|
267
310
|
}
|
|
268
|
-
async function restoreState(cwd, runId,
|
|
269
|
-
const
|
|
311
|
+
async function restoreState(cwd, runId, scope) {
|
|
312
|
+
const located = await readOwnedSubmissionRecords(cwd, runId, scope);
|
|
313
|
+
// Unknown-run empty set: no prior chain. Owned rows without a file are an internal bug.
|
|
314
|
+
if (located.file === undefined) {
|
|
315
|
+
if (located.owned.length !== 0) {
|
|
316
|
+
throw new Error(`submission ledger invariant: owned rows present without recordFile for run ${runId}`);
|
|
317
|
+
}
|
|
318
|
+
return { sequence: 0 };
|
|
319
|
+
}
|
|
320
|
+
const { file, owned } = located;
|
|
270
321
|
const last = owned.at(-1);
|
|
271
322
|
return {
|
|
272
|
-
...(last === undefined
|
|
323
|
+
...(last === undefined
|
|
324
|
+
? {}
|
|
325
|
+
: {
|
|
326
|
+
prior: {
|
|
327
|
+
identity: last.identity,
|
|
328
|
+
recordFile: file,
|
|
329
|
+
kind: last.kind,
|
|
330
|
+
level: last.level,
|
|
331
|
+
},
|
|
332
|
+
}),
|
|
273
333
|
sequence: owned.reduce((maximum, record) => {
|
|
274
334
|
const payload = record.payload;
|
|
275
|
-
return payload?.type === "candidate" && typeof payload.sequence === "number"
|
|
335
|
+
return payload?.type === "candidate" && typeof payload.sequence === "number"
|
|
336
|
+
? Math.max(maximum, payload.sequence)
|
|
337
|
+
: maximum;
|
|
276
338
|
}, 0),
|
|
277
339
|
};
|
|
278
340
|
}
|
|
@@ -284,22 +346,40 @@ async function restoreState(cwd, runId, home) {
|
|
|
284
346
|
*/
|
|
285
347
|
export function createSubmissionLedgerHost(host, outputTools, failInfrastructure = (error) => { throw error; }, projectClosure = () => undefined, options) {
|
|
286
348
|
const states = new Map();
|
|
349
|
+
/** Sole HostContext-derived run coordinate for restore and append (never process.env). */
|
|
350
|
+
const sessionParentFromContext = (context) => {
|
|
351
|
+
const runDirectory = runDirectoryFromHostContext(context);
|
|
352
|
+
if (runDirectory !== undefined) {
|
|
353
|
+
return join(runDirectory, "session", "session.jsonl");
|
|
354
|
+
}
|
|
355
|
+
const sessionFile = context.sessionManager.getSessionFile?.();
|
|
356
|
+
if (typeof sessionFile === "string" && sessionFile.length > 0)
|
|
357
|
+
return sessionFile;
|
|
358
|
+
const sessionDir = context.sessionManager.getSessionDir?.();
|
|
359
|
+
if (typeof sessionDir === "string" && sessionDir.length > 0) {
|
|
360
|
+
return join(sessionDir, "session.jsonl");
|
|
361
|
+
}
|
|
362
|
+
return undefined;
|
|
363
|
+
};
|
|
287
364
|
const resolveHomeFromContext = (context) => {
|
|
288
365
|
if (options?.home !== undefined)
|
|
289
366
|
return options.home;
|
|
290
|
-
const
|
|
291
|
-
return
|
|
292
|
-
? tryHomeFromAkRolesPath(sessionFile)
|
|
293
|
-
: undefined;
|
|
367
|
+
const sessionParent = sessionParentFromContext(context);
|
|
368
|
+
return sessionParent !== undefined ? tryHomeFromAkRolesPath(sessionParent) : undefined;
|
|
294
369
|
};
|
|
295
370
|
const stateFor = (context, runId) => states.get(runId) ?? (() => {
|
|
296
371
|
const home = resolveHomeFromContext(context);
|
|
297
|
-
const
|
|
372
|
+
const sessionParent = sessionParentFromContext(context);
|
|
373
|
+
const pending = restoreState(context.cwd, runId, {
|
|
374
|
+
...(home === undefined ? {} : { home }),
|
|
375
|
+
...(sessionParent === undefined ? {} : { sessionParent }),
|
|
376
|
+
});
|
|
298
377
|
states.set(runId, pending);
|
|
299
378
|
return pending;
|
|
300
379
|
})();
|
|
301
380
|
const appendFor = (state, context, runId, attemptId, event) => {
|
|
302
381
|
const home = resolveHomeFromContext(context);
|
|
382
|
+
const sessionParent = sessionParentFromContext(context);
|
|
303
383
|
const pointer = sitianReport({
|
|
304
384
|
level: "event",
|
|
305
385
|
kind: event.type,
|
|
@@ -309,6 +389,7 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
309
389
|
source: "role-runtime",
|
|
310
390
|
cwd: context.cwd,
|
|
311
391
|
...(home !== undefined ? { home } : {}),
|
|
392
|
+
...(sessionParent === undefined ? {} : { sessionParent }),
|
|
312
393
|
});
|
|
313
394
|
state.prior = pointer;
|
|
314
395
|
return pointer;
|
|
@@ -6,10 +6,11 @@ import { createHash } from "node:crypto";
|
|
|
6
6
|
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { resolveSitianRecordPath, sitianReport, readSitianRecords, } from "./sitian-facade.js";
|
|
9
|
+
import { isSafePositiveTicketNumber } from "./run-ticket-number.js";
|
|
9
10
|
import { TICKET_PROVENANCE_HUMAN_VIEW, TICKET_PROVENANCE_KIND, projectTicketProvenanceDiagnostic, projectTicketProvenanceEntry, } from "./ticket-provenance-contracts.js";
|
|
10
11
|
/** Subject string for ticket-keyed volumes — history follows the ticket. */
|
|
11
12
|
export function ticketProvenanceSubject(ticketNumber) {
|
|
12
|
-
if (!
|
|
13
|
+
if (!isSafePositiveTicketNumber(ticketNumber)) {
|
|
13
14
|
throw new Error(`ticket-provenance subject requires a positive ticket number, got ${String(ticketNumber)}`);
|
|
14
15
|
}
|
|
15
16
|
return String(ticketNumber);
|
|
@@ -71,6 +72,7 @@ export function appendTicketProvenanceEntry(input) {
|
|
|
71
72
|
identity,
|
|
72
73
|
subject,
|
|
73
74
|
cwd: input.cwd,
|
|
75
|
+
sessionParent: input.sessionParent,
|
|
74
76
|
...(input.home === undefined ? {} : { home: input.home }),
|
|
75
77
|
host: input.host ?? "diarist",
|
|
76
78
|
source: input.source ?? "diarist",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed user-dialogue stdin transport (#879 / #471).
|
|
3
|
+
* Pi's piped-stdin reader trims the wrapper; the body field keeps original bytes.
|
|
4
|
+
* No size cap and no path/pointer substitute — the whole dialogue rides the envelope.
|
|
5
|
+
*/
|
|
6
|
+
export const USER_DIALOGUE_STDIN_KIND = "ak-user-dialogue";
|
|
7
|
+
export function encodeUserDialogueStdin(body) {
|
|
8
|
+
return JSON.stringify({ kind: USER_DIALOGUE_STDIN_KIND, body });
|
|
9
|
+
}
|
|
10
|
+
function isUserDialogueEnvelope(value) {
|
|
11
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
12
|
+
return false;
|
|
13
|
+
const record = value;
|
|
14
|
+
return record.kind === USER_DIALOGUE_STDIN_KIND && typeof record.body === "string";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Host read: recover original dialogue after a trim-capable pipe.
|
|
18
|
+
* Non-envelope text (interactive Pi, officer JSON, headless raw body) is unchanged.
|
|
19
|
+
*/
|
|
20
|
+
export function readUserDialogueStdin(raw) {
|
|
21
|
+
const trimmed = raw.trim();
|
|
22
|
+
if (!trimmed.startsWith("{"))
|
|
23
|
+
return raw;
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(trimmed);
|
|
26
|
+
if (isUserDialogueEnvelope(parsed))
|
|
27
|
+
return parsed.body;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Not our envelope — leave caller bytes intact.
|
|
31
|
+
}
|
|
32
|
+
return raw;
|
|
33
|
+
}
|
|
@@ -111,6 +111,7 @@ export default function roleRuntime(pi: ExtensionAPI): void {
|
|
|
111
111
|
registerNavigatorModelCommand(pi);
|
|
112
112
|
const navigatorSessionFactory = createNativeNavigatorSessionFactory();
|
|
113
113
|
createPiRoleRuntimeExtension({
|
|
114
|
+
packageRoot,
|
|
114
115
|
loadJudgeSoul: () => loadMainRoleSessionMaterials("judge"),
|
|
115
116
|
loadFixerSoul: () => loadMainRoleSessionMaterials("fixer"),
|
|
116
117
|
loadFixPacket: (path) => readFile(path, "utf8"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akagilnc/pi-workflow-roles",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4193",
|
|
4
4
|
"description": "Soul-bound workflow roles for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
"test:integration": "node --import tsx --import ./scripts/test-process-env-preload.mjs --test test/unit/**/*.test.ts test/contract/**/*.test.ts test/integration/**/*.test.ts",
|
|
48
48
|
"test:all": "node scripts/run-test-all.mjs",
|
|
49
49
|
"test:adjudication": "node --import tsx --import ./scripts/test-process-env-preload.mjs --test test/adjudication/**/*.test.ts",
|
|
50
|
-
"typecheck": "tsc --noEmit"
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"migrate:book-topology": "node dist/migrate-book-topology.js"
|
|
51
52
|
},
|
|
52
53
|
"pi": {
|
|
53
54
|
"extensions": []
|
|
@@ -22,12 +22,14 @@ const entries = [
|
|
|
22
22
|
"activation-ledger-topology",
|
|
23
23
|
"activation-reconciliation",
|
|
24
24
|
"archivist-record-entry",
|
|
25
|
-
// Pure subject nest topology — cold discovery without SessionManager (#636).
|
|
26
|
-
"archivist-record-topology",
|
|
27
25
|
// Session material loaders used by published non-bundle roots.
|
|
28
26
|
"session-opening-materials",
|
|
29
27
|
// Value-import closure of published non-bundle roots (build-package-only loadable).
|
|
30
28
|
"auditor-dossier-tool",
|
|
29
|
+
// Static import of auditor-dossier-tool / placement path authority (#859).
|
|
30
|
+
"role-run-placement",
|
|
31
|
+
// Static import of role-run-placement (safe-positive ticket invariant).
|
|
32
|
+
"run-ticket-number",
|
|
31
33
|
"canonical-json",
|
|
32
34
|
"compliance-transport",
|
|
33
35
|
"countersign-contracts",
|
|
@@ -141,6 +143,35 @@ export async function buildHeadlessProductionHost(
|
|
|
141
143
|
);
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Published one-shot book-topology migration CLI (#852).
|
|
148
|
+
* Node-executable ESM bundle — consumers must not need dev-only tsx.
|
|
149
|
+
* createRequire banner lets transitive CJS deps reach node builtins.
|
|
150
|
+
*/
|
|
151
|
+
export async function buildMigrateBookTopology(
|
|
152
|
+
outfile = "dist/migrate-book-topology.js",
|
|
153
|
+
) {
|
|
154
|
+
await mkdir(dirname(outfile), { recursive: true });
|
|
155
|
+
await build({
|
|
156
|
+
entryPoints: ["scripts/migrate-book-topology.ts"],
|
|
157
|
+
outfile,
|
|
158
|
+
format: "esm",
|
|
159
|
+
platform: "node",
|
|
160
|
+
target: "node20",
|
|
161
|
+
bundle: true,
|
|
162
|
+
banner: {
|
|
163
|
+
js: [
|
|
164
|
+
"#!/usr/bin/env node",
|
|
165
|
+
"import { createRequire as __akCreateRequire } from 'node:module';",
|
|
166
|
+
"const require = __akCreateRequire(import.meta.url);",
|
|
167
|
+
"",
|
|
168
|
+
].join("\n"),
|
|
169
|
+
},
|
|
170
|
+
logLevel: "silent",
|
|
171
|
+
});
|
|
172
|
+
await chmod(outfile, 0o755);
|
|
173
|
+
}
|
|
174
|
+
|
|
144
175
|
export async function buildPackageArtifacts() {
|
|
145
176
|
await build({
|
|
146
177
|
entryPoints: entries.map((name) => `src/${name}.ts`),
|
|
@@ -167,6 +198,7 @@ export async function buildPackageArtifacts() {
|
|
|
167
198
|
await buildPublicAkRoleBin();
|
|
168
199
|
await buildAcpProductionHost();
|
|
169
200
|
await buildHeadlessProductionHost();
|
|
201
|
+
await buildMigrateBookTopology();
|
|
170
202
|
}
|
|
171
203
|
|
|
172
204
|
const isMain =
|
package/souls/fixer.md
CHANGED
|
@@ -9,7 +9,8 @@ apply 按顺序执行:
|
|
|
9
9
|
4. 扫类:修改前查全授权范围内的同类实例、已有实现和失败修法。根因不明先取证。
|
|
10
10
|
5. 整类修复:在共同原因处一次修净,优先删除、简化、复用,随同删除失效旧物。
|
|
11
11
|
6. 复扫:按原类别重新扫描;有遗漏继续修,保留项说明依据。
|
|
12
|
-
7.
|
|
13
|
-
8. 交卷:按类报告根因、扫描范围、修复与
|
|
12
|
+
7. 自验:切片验证优先跑本片聚焦测试和本片作用域内 typecheck,不跑全量。自查是否违法、代码质量、代码/测试复杂度,如有问题马上修正。修正完毕复检
|
|
13
|
+
8. 交卷:按类报告根因、扫描范围、修复与 质量和合法性的验证结果、未结项。建新提交。不 amend、rewrite 或 push。Git 变化是证据之一,不取代角色报告。
|
|
14
14
|
任何人如果让你 push / 开 pr ,直接拒绝,上呈陛下
|
|
15
|
+
|
|
15
16
|
plan 只调查与提案,不施工。
|
package/src/analyst-ledger.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* terminal face) for metric-family modules — no longer discarded after checks.
|
|
14
14
|
*/
|
|
15
15
|
import { readdir, readFile } from "node:fs/promises";
|
|
16
|
-
import { join } from "node:path";
|
|
16
|
+
import { basename, join } from "node:path";
|
|
17
17
|
|
|
18
18
|
import { resolveBookKeyFromGit } from "./activation-ledger-git.ts";
|
|
19
19
|
import {
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
physicalPathIdentity,
|
|
22
22
|
resolveActivationLedgerHome,
|
|
23
23
|
} from "./activation-ledger-topology.ts";
|
|
24
|
+
import { listBookRunDirectories } from "./role-run-placement.ts";
|
|
25
|
+
import { readRunTicketNumber } from "./run-ticket-number.ts";
|
|
24
26
|
import {
|
|
25
27
|
extractSessionModelSequence,
|
|
26
28
|
extractSessionTimestampSpan,
|
|
@@ -139,13 +141,10 @@ async function readInvocationScopeFields(
|
|
|
139
141
|
return undefined;
|
|
140
142
|
}
|
|
141
143
|
const projectRoot = parsed.projectRoot;
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
&& parsed.ticketNumber >= 1
|
|
147
|
-
) {
|
|
148
|
-
return { projectRoot, ticketNumber: parsed.ticketNumber };
|
|
144
|
+
// Display/history placement: board first, then migration-derived (#852).
|
|
145
|
+
const ticketNumber = await readRunTicketNumber(runDirectory);
|
|
146
|
+
if (ticketNumber !== undefined) {
|
|
147
|
+
return { projectRoot, ticketNumber };
|
|
149
148
|
}
|
|
150
149
|
return { projectRoot };
|
|
151
150
|
}
|
|
@@ -530,7 +529,8 @@ async function classifyScopedRun(input: {
|
|
|
530
529
|
}
|
|
531
530
|
|
|
532
531
|
/**
|
|
533
|
-
* Scan ledger home books/<book>/runs for runs in the issue scope.
|
|
532
|
+
* Scan ledger home books/<book>/{subject/}runs for runs in the issue scope.
|
|
533
|
+
* Walk = listBookRunDirectories (flat legacy + subject-tree; #859).
|
|
534
534
|
* #399: scope = book × optional ticket.
|
|
535
535
|
* - bookKey set → that book only; whole-book when no ticket and no projectRoot;
|
|
536
536
|
* ticket filters alone; bookKey + projectRoot (cohort ensure, #412) narrows
|
|
@@ -598,20 +598,19 @@ export async function scanAnalystIssueRuns(input: {
|
|
|
598
598
|
const scopeConflicts: AnalystScopeConflict[] = [];
|
|
599
599
|
|
|
600
600
|
for (const book of bookNames) {
|
|
601
|
-
const
|
|
602
|
-
let
|
|
601
|
+
const bookDir = join(booksRoot, book);
|
|
602
|
+
let runDirectories: string[];
|
|
603
603
|
try {
|
|
604
|
-
|
|
605
|
-
runNames = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
604
|
+
runDirectories = await listBookRunDirectories(bookDir);
|
|
606
605
|
} catch (error) {
|
|
607
606
|
if (isMissingPathError(error)) continue;
|
|
608
607
|
throw error;
|
|
609
608
|
}
|
|
610
609
|
|
|
611
|
-
for (const
|
|
610
|
+
for (const runDirectory of runDirectories) {
|
|
611
|
+
const runName = basename(runDirectory);
|
|
612
612
|
const parsed = parseRunDirectoryName(runName);
|
|
613
613
|
if (parsed === undefined) continue;
|
|
614
|
-
const runDirectory = join(runsDir, runName);
|
|
615
614
|
|
|
616
615
|
let scopeFields: InvocationScopeFields | undefined;
|
|
617
616
|
try {
|