@akagilnc/pi-workflow-roles 0.1.5864 → 0.1.5877
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 +79 -11
- package/dist/audited-run-identity.js +4 -3
- package/dist/auditor-soul.js +3 -1
- package/dist/diarist-contracts.js +4 -3
- package/dist/headless-host/production-host.js +79 -11
- package/dist/migrate-book-topology.js +16 -5
- package/dist/notary-role.js +10 -2
- package/dist/packaged-role-registry.js +3 -1
- package/dist/public-cli/cli.js +7 -0
- package/dist/public-cli/dialogue-command.js +37 -0
- package/dist/public-cli/main.js +209 -6
- package/dist/public-cli/option-definitions.js +8 -0
- package/dist/public-cli/registry.js +2 -1
- package/dist/role-runtime.js +5 -2
- package/dist/role-submission-declarations.js +1 -1
- package/dist/ticket-provenance.js +1 -1
- package/package.json +1 -1
- package/resources/collector-bot-handbook.md +1 -1
- package/resources/diarist-collect.md +4 -3
- package/src/audited-run-identity.ts +5 -4
- package/src/auditor-soul.ts +3 -1
- package/src/diarist-contracts.ts +7 -4
- package/src/notary-role.ts +14 -2
- package/src/packaged-role-registry.ts +3 -1
- package/src/public-cli/cli.ts +7 -0
- package/src/public-cli/dialogue-command.ts +53 -0
- package/src/public-cli/option-definitions.ts +9 -0
- package/src/public-cli/registry.ts +1 -0
- package/src/role-runtime.ts +5 -1
- package/src/role-submission-declarations.ts +1 -1
- package/src/ticket-provenance.ts +1 -1
package/src/diarist-contracts.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public 起居郎 (diarist) terminating receipt contracts — ADR 0075 `diarist-is-role` / #901.
|
|
3
|
-
* Lawful explicit releases: completed (入录) | escalate (
|
|
3
|
+
* Lawful explicit releases: completed (入录) | escalate (无法正常署时上呈,见 Soul).
|
|
4
4
|
* Machine facts about the volume come from the mechanical reproject seam, never
|
|
5
5
|
* from model self-report (锚定宪法); this module owns the receipt shape only.
|
|
6
6
|
*
|
|
@@ -42,7 +42,7 @@ export type DiaristOutput =
|
|
|
42
42
|
}[];
|
|
43
43
|
}
|
|
44
44
|
| {
|
|
45
|
-
/** LLM cannot
|
|
45
|
+
/** LLM cannot sign this round normally (Soul) — escalate, never wash into 无录. */
|
|
46
46
|
readonly status: "escalate";
|
|
47
47
|
readonly reason: string;
|
|
48
48
|
};
|
|
@@ -100,8 +100,11 @@ export function projectDiaristTicketSessions(
|
|
|
100
100
|
* sessions / ticketSessions 是投影所读的边界:卷路径或端点读不出时走既有 reask,不中止本轮。
|
|
101
101
|
* 声明只留字段名和语义说明,不留类型、嵌套、长度、必填。
|
|
102
102
|
*/
|
|
103
|
+
export const DIARIST_BOUND_ENDPOINTS =
|
|
104
|
+
"起点与终点各写 id 或 line,二选一:id=会话卷里那一行 JSON 的 uuid 字段值(没有 uuid 取 id;顶层都没有再取 message 或 payload 里的 uuid / id),同一 id 出现多次时取第一次出现的那一行;line=那一行在文件里从 1 数起的行号。两端都含在区间内。" as const;
|
|
105
|
+
|
|
103
106
|
const DIARIST_SESSIONS_DESCRIPTION =
|
|
104
|
-
|
|
107
|
+
`对话边界。每卷含 path(会话卷绝对或可读路径)与 ranges(本卷本轮各区间)。每段区间含 from / to;${DIARIST_BOUND_ENDPOINTS}区间里只有说话人的原文进录:用户与助手消息里的文本、真人经队列的插话;思考、工具调用、工具结果和机器通知不进录,区间可以直接跨过它们,不必拆段。每次交卷的边界照投影追加进本票起居录,不去重,也不改已有的录。空列表=本轮无对话可划。端点无法指名时走 reask,不中止。` as const;
|
|
105
108
|
|
|
106
109
|
export const diaristOutputSchema = withTerminatingOutputDeclarations(
|
|
107
110
|
openToolObject(
|
|
@@ -116,7 +119,7 @@ export const diaristOutputSchema = withTerminatingOutputDeclarations(
|
|
|
116
119
|
}),
|
|
117
120
|
),
|
|
118
121
|
reason: Type.Unknown({
|
|
119
|
-
description: "status 为 escalate
|
|
122
|
+
description: "status 为 escalate 时:上呈的原因",
|
|
120
123
|
}),
|
|
121
124
|
sessions: Type.Optional(Type.Unknown({ description: DIARIST_SESSIONS_DESCRIPTION })),
|
|
122
125
|
ticketSessions: Type.Unknown({
|
package/src/notary-role.ts
CHANGED
|
@@ -29,6 +29,8 @@ export {
|
|
|
29
29
|
export type NotaryRoleDependencies = {
|
|
30
30
|
loadSoul(): Promise<string>;
|
|
31
31
|
loadSourceRunLocator(path: string): Promise<NotarySourceRunLocator>;
|
|
32
|
+
/** Soul of the audited seat (the verdict under review cites it); undefined when the package has none. */
|
|
33
|
+
loadAuditedSoul(role: string): Promise<string | undefined>;
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
export type NotaryRoleHostActions = {
|
|
@@ -95,14 +97,18 @@ export function projectNotaryBoundFromFlags(
|
|
|
95
97
|
};
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
/** Assemble systemPrompt body from base + soul
|
|
100
|
+
/** Assemble systemPrompt body from base + soul + the audited seat's Soul (NO embedded bound JSON).
|
|
99
101
|
* Audited-run identity travels separately as `readingMaterial`; adapters fold
|
|
100
102
|
* it into the provider-visible prompt at the send boundary. */
|
|
101
103
|
export function assembleNotaryAgentStartPrompt(input: {
|
|
102
104
|
readonly baseSystemPrompt: string;
|
|
103
105
|
readonly soul: string;
|
|
106
|
+
readonly audited?: { readonly seat: string; readonly soul: string };
|
|
104
107
|
}): string {
|
|
105
|
-
|
|
108
|
+
const audited = input.audited === undefined
|
|
109
|
+
? ""
|
|
110
|
+
: `\n\n<audited_seat_soul seat="${input.audited.seat}">\n${input.audited.soul}\n</audited_seat_soul>`;
|
|
111
|
+
return `${input.baseSystemPrompt}\n\n<notary_soul>\n${input.soul}\n</notary_soul>${audited}`;
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
/** Envelope-admitted ticket binding (flag read owned by shared envelope). */
|
|
@@ -119,6 +125,7 @@ export function createNotaryRoleRuntime(
|
|
|
119
125
|
| {
|
|
120
126
|
soul: string;
|
|
121
127
|
sourceRun: NotarySourceRunLocator;
|
|
128
|
+
auditedSoul?: string;
|
|
122
129
|
ticketNumber?: number;
|
|
123
130
|
}
|
|
124
131
|
| undefined;
|
|
@@ -142,9 +149,11 @@ export function createNotaryRoleRuntime(
|
|
|
142
149
|
const soul = (await dependencies.loadSoul()).trim();
|
|
143
150
|
if (soul.length === 0) throw new Error("Notary soul is empty");
|
|
144
151
|
const sourceRun = await dependencies.loadSourceRunLocator(path);
|
|
152
|
+
const auditedSoul = (await dependencies.loadAuditedSoul(sourceRun.role))?.trim();
|
|
145
153
|
activation = {
|
|
146
154
|
soul,
|
|
147
155
|
sourceRun,
|
|
156
|
+
...(auditedSoul === undefined || auditedSoul === "" ? {} : { auditedSoul }),
|
|
148
157
|
...(admitted?.ticketNumber === undefined
|
|
149
158
|
? {}
|
|
150
159
|
: { ticketNumber: admitted.ticketNumber }),
|
|
@@ -165,6 +174,9 @@ export function createNotaryRoleRuntime(
|
|
|
165
174
|
systemPrompt: assembleNotaryAgentStartPrompt({
|
|
166
175
|
baseSystemPrompt: event.systemPrompt,
|
|
167
176
|
soul: activation.soul,
|
|
177
|
+
...(activation.auditedSoul === undefined
|
|
178
|
+
? {}
|
|
179
|
+
: { audited: { seat: activation.sourceRun.role, soul: activation.auditedSoul } }),
|
|
168
180
|
}),
|
|
169
181
|
readingMaterial: projectNotaryAuditedRunIdentity({
|
|
170
182
|
sourceRun: activation.sourceRun,
|
|
@@ -37,6 +37,7 @@ export const NOTARY_SESSION_MATERIALS = [
|
|
|
37
37
|
"souls/notary.md",
|
|
38
38
|
"souls/audit-law.md",
|
|
39
39
|
"souls/ticket-law.md",
|
|
40
|
+
"souls/quality-law.md",
|
|
40
41
|
"souls/gate-output-guide.md",
|
|
41
42
|
"docs/adr/0057-schema-narrowing-cuts-the-required-set-not-the-declared-set.md",
|
|
42
43
|
] as const;
|
|
@@ -61,6 +62,7 @@ export const AUDITOR_PUBLIC_SESSION_MATERIALS = [
|
|
|
61
62
|
"CLAUDE.md",
|
|
62
63
|
"souls/judge-auditor.md",
|
|
63
64
|
"souls/doctor-auditor.md",
|
|
65
|
+
"souls/judge.md",
|
|
64
66
|
"souls/audit-law.md",
|
|
65
67
|
"souls/quality-law.md",
|
|
66
68
|
"docs/adr/0057-schema-narrowing-cuts-the-required-set-not-the-declared-set.md",
|
|
@@ -319,7 +321,7 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
319
321
|
activationStage: "load-and-install",
|
|
320
322
|
receiptStatusKey: "status",
|
|
321
323
|
// #924: 公用《票面法》三席同装
|
|
322
|
-
sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md", "resources/countersign-ticket-issue.md", "docs/adr/0057-schema-narrowing-cuts-the-required-set-not-the-declared-set.md"],
|
|
324
|
+
sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md", "souls/audit-law.md", "souls/quality-law.md", "resources/countersign-ticket-issue.md", "docs/adr/0057-schema-narrowing-cuts-the-required-set-not-the-declared-set.md"],
|
|
323
325
|
},
|
|
324
326
|
{
|
|
325
327
|
role: "secretariat",
|
package/src/public-cli/cli.ts
CHANGED
|
@@ -79,6 +79,7 @@ import {
|
|
|
79
79
|
type TypedOptionConsumer,
|
|
80
80
|
} from "./option-definitions.ts";
|
|
81
81
|
import { TurnDispatchedFailure } from "./auto-resume.ts";
|
|
82
|
+
import { readSessionDialogue, renderSessionDialogue } from "./dialogue-command.ts";
|
|
82
83
|
import {
|
|
83
84
|
continueParentAfterChild,
|
|
84
85
|
presentAuditedOriginalOfUnsettledOfficer,
|
|
@@ -1157,6 +1158,12 @@ export async function runAkRole(
|
|
|
1157
1158
|
// and settle through the outer catch — no $HOME fallback (#604).
|
|
1158
1159
|
const home = resolveHome(env);
|
|
1159
1160
|
|
|
1161
|
+
if (parsed.command === "dialogue") {
|
|
1162
|
+
if (parsed.args.length !== 1) throw new CliUsageError("usage: ak-role dialogue <session.jsonl>");
|
|
1163
|
+
io.stdout(renderSessionDialogue(await readSessionDialogue(parsed.args[0]!, home)));
|
|
1164
|
+
return { exitCode: 0 };
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1160
1167
|
if (parsed.command === "roles") {
|
|
1161
1168
|
if (parsed.args.length > 0) {
|
|
1162
1169
|
throw new CliUsageError("roles takes no arguments");
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ak-role dialogue <session>`: the speaker lines a diary range would project,
|
|
3
|
+
* one JSON object per line, so the diarist searches the dialogue instead of
|
|
4
|
+
* re-deriving the session format (owner 2026-10-21). Same read and adapter as
|
|
5
|
+
* the ticket-provenance projection — no second speaker rule.
|
|
6
|
+
*/
|
|
7
|
+
import { readLedgerSessionJsonlLines } from "../ledger-session-read.ts";
|
|
8
|
+
import { adaptSessionDialogue, type DialogueSpeaker } from "../session-dialogue.ts";
|
|
9
|
+
import { assertDialogueSessionSourcePath } from "../ticket-provenance.ts";
|
|
10
|
+
|
|
11
|
+
export type SessionDialogueLine =
|
|
12
|
+
| {
|
|
13
|
+
/** 1-based file line, the same `line` a diary range endpoint names. */
|
|
14
|
+
readonly line: number;
|
|
15
|
+
/** Native id a range endpoint can name; only on its first line, since an id resolves there. */
|
|
16
|
+
readonly id?: string;
|
|
17
|
+
readonly speaker: DialogueSpeaker;
|
|
18
|
+
readonly text: string;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
/** Unparsable source line; a range covering it keeps these bytes in the record. */
|
|
22
|
+
readonly line: number;
|
|
23
|
+
readonly raw: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function readSessionDialogue(path: string, home?: string): Promise<SessionDialogueLine[]> {
|
|
27
|
+
assertDialogueSessionSourcePath(path, home);
|
|
28
|
+
const sessionLines = await readLedgerSessionJsonlLines(path);
|
|
29
|
+
const dialogue = adaptSessionDialogue(sessionLines.map((entry) => entry.row));
|
|
30
|
+
const seenIds = new Set<string>();
|
|
31
|
+
const out: SessionDialogueLine[] = [];
|
|
32
|
+
sessionLines.forEach((entry, index) => {
|
|
33
|
+
if (entry.row === undefined) {
|
|
34
|
+
out.push({ line: entry.line, raw: entry.raw });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const event of dialogue[index] ?? []) {
|
|
38
|
+
const firstId = event.id !== undefined && !seenIds.has(event.id);
|
|
39
|
+
if (event.id !== undefined) seenIds.add(event.id);
|
|
40
|
+
out.push({
|
|
41
|
+
line: entry.line,
|
|
42
|
+
...(firstId ? { id: event.id } : {}),
|
|
43
|
+
speaker: event.speaker,
|
|
44
|
+
text: event.text,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function renderSessionDialogue(lines: readonly SessionDialogueLine[]): string {
|
|
52
|
+
return lines.map((line) => `${JSON.stringify(line)}\n`).join("");
|
|
53
|
+
}
|
|
@@ -1362,6 +1362,15 @@ const SUPPORT_COMMAND_HELP = {
|
|
|
1362
1362
|
"ak-role --host grok-build new inspector --attach ./change.patch",
|
|
1363
1363
|
],
|
|
1364
1364
|
},
|
|
1365
|
+
dialogue: {
|
|
1366
|
+
command: "dialogue",
|
|
1367
|
+
summary:
|
|
1368
|
+
"Print what a diary range projects from a session volume, one JSON object per line: speaker lines {line, id, speaker: owner|runner, text} and unparsable lines {line, raw}. line and id are what a range endpoint names; a repeated id is shown on its first line only, where it resolves. Same authorized session roots as the projection.",
|
|
1369
|
+
usage: ["ak-role dialogue <session.jsonl>"],
|
|
1370
|
+
examples: [
|
|
1371
|
+
"ak-role dialogue ~/.claude/projects/-Users-me-repo/0b1c….jsonl > /tmp/dialogue.jsonl",
|
|
1372
|
+
],
|
|
1373
|
+
},
|
|
1365
1374
|
} as const satisfies Record<string, PublicCommandHelpFacts>;
|
|
1366
1375
|
|
|
1367
1376
|
/**
|
package/src/role-runtime.ts
CHANGED
|
@@ -96,6 +96,7 @@ import {
|
|
|
96
96
|
} from "./secretariat-role.ts";
|
|
97
97
|
import { SECRETARIAT_OUTPUT_TOOL_NAME } from "./secretariat-contracts.ts";
|
|
98
98
|
import {
|
|
99
|
+
DIARIST_BOUND_ENDPOINTS,
|
|
99
100
|
projectDiaristSessions,
|
|
100
101
|
projectDiaristTicketSessions,
|
|
101
102
|
} from "./diarist-contracts.ts";
|
|
@@ -785,7 +786,7 @@ function readDiaristRunCoordinates(ctx: HostContext): {
|
|
|
785
786
|
|
|
786
787
|
/** Plain-language re-ask when diarist bounds cannot be used (#901 / reask-not-explode). */
|
|
787
788
|
const DIARIST_BOUNDS_REASK =
|
|
788
|
-
|
|
789
|
+
`边界无法使用。多票请逐票重交 ticketSessions,单票重交 sessions;每卷 path + ranges。${DIARIST_BOUND_ENDPOINTS}` as const;
|
|
789
790
|
/**
|
|
790
791
|
* #708 / #779 / #901: 起居郎 public seat on the shared filed-officer envelope.
|
|
791
792
|
* LLM judges ticket + dialogue bounds; mechanical layer reprojects the unique
|
|
@@ -1383,6 +1384,9 @@ export function createRoleRuntimeExtension(
|
|
|
1383
1384
|
if (!dependencies.loadNotarySourceRun) throw new Error("Notary runtime dependencies are not configured");
|
|
1384
1385
|
return dependencies.loadNotarySourceRun(path);
|
|
1385
1386
|
},
|
|
1387
|
+
async loadAuditedSoul(role) {
|
|
1388
|
+
return packagedRoleMetadata(role) === undefined ? undefined : requireRoleSoul(role as PackagedRole);
|
|
1389
|
+
},
|
|
1386
1390
|
}, hostActions);
|
|
1387
1391
|
const countersign = createCountersignRoleRuntime(roleHost, {
|
|
1388
1392
|
loadSoul: () => requireRoleSoul("countersign"),
|
|
@@ -121,7 +121,7 @@ const SUBMISSION_FACE = {
|
|
|
121
121
|
},
|
|
122
122
|
diarist: {
|
|
123
123
|
label: "起居郎输出",
|
|
124
|
-
description: "起居郎交单票 sessions 或多票逐票 ticketSessions
|
|
124
|
+
description: "起居郎交单票 sessions 或多票逐票 ticketSessions 边界,或 escalate。",
|
|
125
125
|
promptSnippet: "起居郎交边界",
|
|
126
126
|
parameters: diaristOutputSchema,
|
|
127
127
|
},
|
package/src/ticket-provenance.ts
CHANGED
|
@@ -83,7 +83,7 @@ function isLedgerRoleSessionFile(absolute: string, home?: string): boolean {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/** Real I/O seam gate: only host session stores or sitian role-run session.jsonl. */
|
|
86
|
-
function assertDialogueSessionSourcePath(path: string, home?: string): void {
|
|
86
|
+
export function assertDialogueSessionSourcePath(path: string, home?: string): void {
|
|
87
87
|
const absolute = resolve(path);
|
|
88
88
|
for (const root of dialogueSessionSourceRoots(home)) {
|
|
89
89
|
if (physicallyContainedIn(root, absolute)) return;
|