@akagilnc/pi-workflow-roles 0.1.4321 → 0.1.4387
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/README.md +4 -1
- package/README.zh-CN.md +5 -1
- package/dist/acp-host/production-host.js +1308 -587
- package/dist/doctor-contracts.js +2 -2
- package/dist/engine-detour-tool.js +2 -8
- package/dist/gatekeeper-role.js +4 -19
- package/dist/headless-host/production-host.js +2613 -1892
- package/dist/merger-contracts.js +2 -2
- package/dist/migrate-book-topology.js +34 -9
- package/dist/notary-contracts.js +2 -2
- package/dist/package-contracts/auditor-output.js +2 -2
- package/dist/package-contracts/fixer-output.js +2 -2
- package/dist/package-contracts/gatekeeper-output.js +2 -2
- package/dist/package-contracts/navigator-output.js +2 -2
- package/dist/package-contracts/terminating-infrastructure.js +7 -2
- package/dist/package-contracts/terminating-tools.js +6 -0
- package/dist/packaged-role-registry.js +20 -1
- package/dist/public-cli/case-dossier-delivery.js +45 -28
- package/dist/public-cli/countersign-run.js +439 -0
- package/dist/public-cli/invocation.js +10 -0
- package/dist/public-cli/main.js +388 -101
- package/dist/public-cli/option-definitions.js +14 -0
- package/dist/public-cli/post-admission.js +44 -49
- package/dist/public-cli/run-lifecycle.js +13 -1
- package/dist/public-cli/settlement.js +14 -53
- package/dist/public-role-summons.js +14 -0
- package/dist/secretariat-contracts.js +8 -0
- package/dist/sitian-appender.js +21 -4
- package/extensions/role-runtime.ts +1 -0
- package/package.json +1 -1
- package/scripts/build-package.mjs +1 -0
- package/souls/secretariat.md +26 -0
- package/souls/ticket-law.md +9 -0
- package/src/collector-tool-schemas.ts +2 -2
- package/src/countersign-role.ts +2 -2
- package/src/diarist-role.ts +2 -2
- package/src/doctor-contracts.ts +2 -2
- package/src/engine-detour-tool.ts +3 -9
- package/src/gatekeeper-pass-envelope.ts +35 -2
- package/src/gatekeeper-role.ts +8 -31
- package/src/gleaner-left-role.ts +2 -2
- package/src/host-contracts.ts +2 -1
- package/src/inspector-role.ts +2 -2
- package/src/judge-role.ts +2 -2
- package/src/merger-contracts.ts +2 -2
- package/src/notary-contracts.ts +2 -2
- package/src/package-contracts/auditor-output.ts +2 -2
- package/src/package-contracts/fixer-output.ts +2 -2
- package/src/package-contracts/gatekeeper-output.ts +2 -2
- package/src/package-contracts/navigator-output.ts +2 -2
- package/src/package-contracts/terminating-infrastructure.ts +13 -3
- package/src/package-contracts/terminating-tools.ts +9 -1
- package/src/packaged-role-registry.ts +20 -1
- package/src/public-cli/case-dossier-delivery.ts +48 -29
- package/src/public-cli/cli.ts +10 -0
- package/src/public-cli/countersign-run.ts +29 -5
- package/src/public-cli/invocation.ts +28 -2
- package/src/public-cli/option-definitions.ts +17 -0
- package/src/public-cli/post-admission.ts +45 -58
- package/src/public-cli/run-lifecycle.ts +29 -2
- package/src/public-cli/secretariat-run.ts +266 -0
- package/src/public-cli/settlement.ts +31 -55
- package/src/public-cli/terminal.ts +2 -1
- package/src/public-role-summons.ts +23 -1
- package/src/reviewer-role.ts +2 -2
- package/src/role-runtime-dependencies.ts +1 -0
- package/src/role-runtime.ts +203 -18
- package/src/secretariat-contracts.ts +27 -0
- package/src/secretariat-role.ts +210 -0
- package/src/sitian-appender.ts +36 -3
- package/src/worker-role.ts +2 -2
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import { bookDirectOfficerRunPointer } from "./archivist-record-entry.ts";
|
|
17
|
-
import type { HostContext } from "./host-contracts.ts";
|
|
17
|
+
import type { HostContext, RoleTurnHost } from "./host-contracts.ts";
|
|
18
18
|
import {
|
|
19
19
|
GatekeeperDecisionError,
|
|
20
20
|
OFFICER_CONCLUSION_REASK,
|
|
@@ -28,6 +28,34 @@ import {
|
|
|
28
28
|
import type { PublicSummonResult } from "./public-role-summons.ts";
|
|
29
29
|
import { sessionFileFromPublicSummon } from "./session-assistant-usage.ts";
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Shared-envelope default officer summon (ADR 0018).
|
|
33
|
+
* Role modules must not own this drive seam — only project results.
|
|
34
|
+
*/
|
|
35
|
+
export function createDefaultGateOfficerSummon(options: {
|
|
36
|
+
readonly cwd: string;
|
|
37
|
+
readonly home?: string;
|
|
38
|
+
readonly packageRoot?: string;
|
|
39
|
+
readonly roleTurnHost?: RoleTurnHost;
|
|
40
|
+
readonly createRunId?: () => string;
|
|
41
|
+
}): GateOfficerSummon {
|
|
42
|
+
return async (officer, sourceRunDirectory, signal, reask, submission) => {
|
|
43
|
+
const { summonGateOfficer } = await import("./public-role-summons.ts");
|
|
44
|
+
return summonGateOfficer({
|
|
45
|
+
officer,
|
|
46
|
+
sourceRunDirectory,
|
|
47
|
+
cwd: options.cwd,
|
|
48
|
+
...(signal === undefined ? {} : { signal }),
|
|
49
|
+
...(reask === undefined ? {} : { reask }),
|
|
50
|
+
...(submission === undefined ? {} : { submission }),
|
|
51
|
+
...(options.home === undefined ? {} : { home: options.home }),
|
|
52
|
+
...(options.packageRoot === undefined ? {} : { packageRoot: options.packageRoot }),
|
|
53
|
+
...(options.roleTurnHost === undefined ? {} : { roleTurnHost: options.roleTurnHost }),
|
|
54
|
+
...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
31
59
|
/**
|
|
32
60
|
* Book a typed pointer under parent session/auditor-roles (archivist-owned write).
|
|
33
61
|
* Offline mocks without a real session leave no nested volume (lawful zero).
|
|
@@ -84,12 +112,17 @@ export async function requireGatekeeperPass(options: {
|
|
|
84
112
|
}): Promise<void> {
|
|
85
113
|
let reask: string | undefined;
|
|
86
114
|
// No round cap — end only on pass, bounce/escalate-to-parent, or real failure.
|
|
115
|
+
const summonOfficer =
|
|
116
|
+
options.summonOfficer ??
|
|
117
|
+
createDefaultGateOfficerSummon({
|
|
118
|
+
cwd: options.context.cwd ?? process.cwd(),
|
|
119
|
+
});
|
|
87
120
|
for (;;) {
|
|
88
121
|
const projected = await projectGatekeeperRun({
|
|
89
122
|
context: options.context,
|
|
90
123
|
subject: options.subject,
|
|
124
|
+
summonOfficer,
|
|
91
125
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
92
|
-
...(options.summonOfficer === undefined ? {} : { summonOfficer: options.summonOfficer }),
|
|
93
126
|
...(options.submission === undefined ? {} : { submission: options.submission }),
|
|
94
127
|
...(reask === undefined ? {} : { reask }),
|
|
95
128
|
});
|
package/src/gatekeeper-role.ts
CHANGED
|
@@ -111,18 +111,11 @@ export type RunGatekeeperOptions = {
|
|
|
111
111
|
*/
|
|
112
112
|
readonly submission?: unknown;
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
114
|
+
* Officer summon seam. Production default lives on the shared envelope
|
|
115
|
+
* (`createDefaultGateOfficerSummon` / requireGatekeeperPass — ADR 0018).
|
|
116
|
+
* Role module only projects; callers must supply the summon.
|
|
116
117
|
*/
|
|
117
|
-
readonly summonOfficer
|
|
118
|
-
/**
|
|
119
|
-
* Offline test injects forwarded through the production default summonGateOfficer
|
|
120
|
-
* path (same faces as public CLI). Production leaves these unset.
|
|
121
|
-
*/
|
|
122
|
-
readonly home?: string;
|
|
123
|
-
readonly packageRoot?: string;
|
|
124
|
-
readonly roleTurnHost?: import("./host-contracts.ts").RoleTurnHost;
|
|
125
|
-
readonly createRunId?: () => string;
|
|
118
|
+
readonly summonOfficer: GateOfficerSummon;
|
|
126
119
|
};
|
|
127
120
|
|
|
128
121
|
export type GatekeeperPassHostActions = {
|
|
@@ -323,8 +316,9 @@ export const OFFICER_CONCLUSION_REASK =
|
|
|
323
316
|
"上次交卷的结论不是 pass、bounce、escalate 三态之一。请重新输出,结论字段写明其一;打回或上呈的话就是给对方看的原文。" as const;
|
|
324
317
|
|
|
325
318
|
/**
|
|
326
|
-
* Summon + project
|
|
327
|
-
*
|
|
319
|
+
* Summon (via injected seam) + project. Default summonGateOfficer drive lives
|
|
320
|
+
* on the shared envelope (`gatekeeper-pass-envelope.ts`, ADR 0018 / #675) —
|
|
321
|
+
* role module keeps projection only.
|
|
328
322
|
*/
|
|
329
323
|
export async function projectGatekeeperRun(
|
|
330
324
|
options: RunGatekeeperOptions,
|
|
@@ -345,24 +339,7 @@ export async function projectGatekeeperRun(
|
|
|
345
339
|
// typed payload passed explicitly (never latest-toolCall recovery, A7.1–A7.3).
|
|
346
340
|
let summoned: PublicSummonResult;
|
|
347
341
|
try {
|
|
348
|
-
|
|
349
|
-
options.summonOfficer
|
|
350
|
-
?? (async (nextOfficer, sourceRunDirectory, officerSignal, reask, nextSubmission) => {
|
|
351
|
-
const { summonGateOfficer } = await import("./public-role-summons.ts");
|
|
352
|
-
return summonGateOfficer({
|
|
353
|
-
officer: nextOfficer,
|
|
354
|
-
sourceRunDirectory,
|
|
355
|
-
cwd: options.context.cwd ?? process.cwd(),
|
|
356
|
-
...(officerSignal === undefined ? {} : { signal: officerSignal }),
|
|
357
|
-
...(reask === undefined ? {} : { reask }),
|
|
358
|
-
...(nextSubmission === undefined ? {} : { submission: nextSubmission }),
|
|
359
|
-
...(options.home === undefined ? {} : { home: options.home }),
|
|
360
|
-
...(options.packageRoot === undefined ? {} : { packageRoot: options.packageRoot }),
|
|
361
|
-
...(options.roleTurnHost === undefined ? {} : { roleTurnHost: options.roleTurnHost }),
|
|
362
|
-
...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
summoned = await summon(
|
|
342
|
+
summoned = await options.summonOfficer(
|
|
366
343
|
officer,
|
|
367
344
|
runDirectory,
|
|
368
345
|
options.signal,
|
package/src/gleaner-left-role.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Static } from "typebox";
|
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
|
|
4
4
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
5
|
-
import {
|
|
5
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
6
6
|
import {
|
|
7
7
|
GLEANER_LEFT_OUTPUT_TOOL_NAME,
|
|
8
8
|
validateRecordedGleanerLeftOutput,
|
|
@@ -19,7 +19,7 @@ export { validateRecordedGleanerLeftOutput };
|
|
|
19
19
|
// #836 r16 class 1: pointer/statement are LLM/human-read narrative content — no
|
|
20
20
|
// code branches on their presence.
|
|
21
21
|
/** 左拾遗弹章交卷形状;形状指引,非 schema 闸。 */
|
|
22
|
-
export const gleanerLeftOutputSchema =
|
|
22
|
+
export const gleanerLeftOutputSchema = withTerminatingOutputDeclarations(
|
|
23
23
|
openToolObject(
|
|
24
24
|
Type.Object({
|
|
25
25
|
status: Type.Unknown({
|
package/src/host-contracts.ts
CHANGED
|
@@ -134,7 +134,8 @@ export type RoleTurnActivation =
|
|
|
134
134
|
| { readonly role: "gatekeeper" }
|
|
135
135
|
| { readonly role: "navigator" }
|
|
136
136
|
| { readonly role: "auditor" }
|
|
137
|
-
| { readonly role: "diarist" }
|
|
137
|
+
| { readonly role: "diarist" }
|
|
138
|
+
| { readonly role: "secretariat" };
|
|
138
139
|
|
|
139
140
|
export type RoleTurnContinuation =
|
|
140
141
|
| { readonly kind: "initial"; readonly prompt: string }
|
package/src/inspector-role.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Static } from "typebox";
|
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
|
|
4
4
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
5
|
-
import {
|
|
5
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
6
6
|
import {
|
|
7
7
|
INSPECTOR_ACCEPTED_TEXT,
|
|
8
8
|
INSPECTOR_OUTPUT_TOOL_NAME,
|
|
@@ -19,7 +19,7 @@ export type { InspectorOutput };
|
|
|
19
19
|
export { validateRecordedInspectorOutput };
|
|
20
20
|
|
|
21
21
|
/** 台院事后察举交卷形状;形状指引,非 schema 闸。 */
|
|
22
|
-
export const inspectorOutputSchema =
|
|
22
|
+
export const inspectorOutputSchema = withTerminatingOutputDeclarations(
|
|
23
23
|
openToolObject(
|
|
24
24
|
Type.Object({
|
|
25
25
|
status: Type.Unknown({
|
package/src/judge-role.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RoleHost, HostContext, HostToolResult, HostGatekeeperActions } from "./host-contracts.ts";
|
|
2
2
|
import { Type, type Static } from "typebox";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
5
5
|
import { ParentQueueReaskError } from "./submission-errors.ts";
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -25,7 +25,7 @@ export type { JudgeVerdict };
|
|
|
25
25
|
// #836 (ADR 0003 Amendment): judgeStatus kept open like countersignStatus
|
|
26
26
|
// (src/countersign-role.ts) — a closed domain here would reject an unknown
|
|
27
27
|
// value before the rawStatus/ParentQueueReaskError check below ever runs.
|
|
28
|
-
export const judgeVerdictSchema =
|
|
28
|
+
export const judgeVerdictSchema = withTerminatingOutputDeclarations(
|
|
29
29
|
Type.Object(
|
|
30
30
|
{
|
|
31
31
|
judgeStatus: Type.Unknown({ description: "converged | continue | escalate — 形状指引,非 schema 闸" }),
|
package/src/merger-contracts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { exactUtf8 } from "./exact-utf8.ts";
|
|
3
3
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
5
5
|
|
|
6
6
|
const materialSchema = Type.Object({ bytesBase64: Type.String(), sha256: Type.String() }, { additionalProperties: false });
|
|
7
7
|
const checkSchema = Type.Object({ name: Type.String({ minLength: 1 }), argv: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }) }, { additionalProperties: false });
|
|
@@ -25,7 +25,7 @@ const mergerOutputVariants = Type.Union([
|
|
|
25
25
|
Type.Object({ status: Type.Unknown({ description: MERGER_STATUS_DESCRIPTION }), attemptId: Type.String({ description: "已受理合并 attempt 身份" }), report: Type.String({ description: "如实结果报告" }), mergeCommitId: Type.String({ description: "完成合并 commit object ID" }) }, { additionalProperties: false }),
|
|
26
26
|
Type.Object({ status: Type.Unknown({ description: MERGER_STATUS_DESCRIPTION }), attemptId: Type.String({ description: "已受理合并 attempt 身份" }), diagnosis: Type.String({ description: "合并无法或不应由本席完成的原因(含无进行中合并、无活可干、需新的产品/权力决定)" }), report: Type.String({ description: "如实结果报告" }) }, { additionalProperties: false }),
|
|
27
27
|
]);
|
|
28
|
-
export const mergerOutputSchema =
|
|
28
|
+
export const mergerOutputSchema = withTerminatingOutputDeclarations(openToolObjectFromUnion(mergerOutputVariants));
|
|
29
29
|
|
|
30
30
|
export type DeepReadonly<T> = T extends (...args: never[]) => unknown ? T : T extends readonly (infer U)[] ? readonly DeepReadonly<U>[] : T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]> } : T;
|
|
31
31
|
export type MergerMaterial = DeepReadonly<Static<typeof materialSchema>>;
|
package/src/notary-contracts.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { Type } from "typebox";
|
|
7
7
|
|
|
8
8
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
9
|
-
import {
|
|
9
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
10
10
|
|
|
11
11
|
export const NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
|
|
12
12
|
export const NOTARY_ACCEPTED_TEXT = "符宝郎回执已接受";
|
|
@@ -31,7 +31,7 @@ export const NOTARY_TICKET_FLAG = {
|
|
|
31
31
|
export const NOTARY_FIXED_KICKOFF =
|
|
32
32
|
"符宝郎案卷已受理;来源 run 定位见会话材料。";
|
|
33
33
|
|
|
34
|
-
export const notaryOutputSchema =
|
|
34
|
+
export const notaryOutputSchema = withTerminatingOutputDeclarations(
|
|
35
35
|
openToolObject(
|
|
36
36
|
Type.Object({
|
|
37
37
|
status: Type.Unknown({
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
|
|
7
7
|
import { openToolObject } from "../open-tool-schema.ts";
|
|
8
|
-
import {
|
|
8
|
+
import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
|
|
9
9
|
|
|
10
10
|
export const AUDITOR_OUTPUT_TOOL_NAME = "ak_auditor_output" as const;
|
|
11
11
|
export const AUDITOR_ACCEPTED_TEXT = "审刑院回执已接受";
|
|
12
12
|
|
|
13
|
-
export const auditorOutputSchema =
|
|
13
|
+
export const auditorOutputSchema = withTerminatingOutputDeclarations(
|
|
14
14
|
openToolObject(
|
|
15
15
|
Type.Object({
|
|
16
16
|
status: Type.Unknown({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { openToolObjectFromUnion } from "../open-tool-schema.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
|
|
4
4
|
|
|
5
5
|
export const FIXER_OUTPUT_TOOL_NAME = "ak_fixer_output";
|
|
6
6
|
export const FIXER_ACCEPTED_TEXT = "修内司回执已接受";
|
|
@@ -51,7 +51,7 @@ const fixerOutputVariants = Type.Union([
|
|
|
51
51
|
Type.Object({ status: Type.Unknown({ description: FIXER_STATUS_DESCRIPTION }), report: Type.String({ description: "如实结果报告" }), classResults: Type.Array(classResultSchema, { description: "各类拒绝结算" }) }),
|
|
52
52
|
Type.Object({ status: Type.Unknown({ description: FIXER_STATUS_DESCRIPTION }), report: Type.String({ description: "如实结果报告" }), classResults: Type.Array(classResultSchema, { description: "各类完成或拒绝结算" }), testEvidence: Type.Optional(testEvidenceSchema) }),
|
|
53
53
|
]);
|
|
54
|
-
export const fixerOutputSchema =
|
|
54
|
+
export const fixerOutputSchema = withTerminatingOutputDeclarations(
|
|
55
55
|
openToolObjectFromUnion(fixerOutputVariants),
|
|
56
56
|
);
|
|
57
57
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { Type } from "typebox";
|
|
7
7
|
|
|
8
8
|
import { openToolObject } from "../open-tool-schema.ts";
|
|
9
|
-
import {
|
|
9
|
+
import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
|
|
10
10
|
|
|
11
11
|
export const GATEKEEPER_OUTPUT_TOOL_NAME = "ak_gatekeeper_output";
|
|
12
12
|
export const GATEKEEPER_ACCEPTED_TEXT = "门下省决议已受理";
|
|
@@ -26,7 +26,7 @@ export const gatekeeperDecisionSchema = openToolObject(
|
|
|
26
26
|
}),
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
-
export const gatekeeperOutputSchema =
|
|
29
|
+
export const gatekeeperOutputSchema = withTerminatingOutputDeclarations(
|
|
30
30
|
gatekeeperDecisionSchema,
|
|
31
31
|
);
|
|
32
32
|
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
import { Type } from "typebox";
|
|
8
8
|
|
|
9
9
|
import { openToolObject } from "../open-tool-schema.ts";
|
|
10
|
-
import {
|
|
10
|
+
import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
|
|
11
11
|
|
|
12
12
|
export const NAVIGATOR_OUTPUT_TOOL_NAME = "ak_navigator_output";
|
|
13
13
|
export const NAVIGATOR_ACCEPTED_TEXT = "游奕使建议已受理";
|
|
14
14
|
|
|
15
|
-
export const navigatorOutputSchema =
|
|
15
|
+
export const navigatorOutputSchema = withTerminatingOutputDeclarations(
|
|
16
16
|
openToolObject(
|
|
17
17
|
Type.Object({
|
|
18
18
|
status: Type.Unknown({
|
|
@@ -49,19 +49,29 @@ const infrastructureFailureDeclarationSchema = Type.Object(
|
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* Compose
|
|
53
|
-
*
|
|
52
|
+
* Compose declarations shared by terminating output tools: infrastructure failure
|
|
53
|
+
* and the optional role-asserted ticket identity. Returns an open object (additionalProperties: true,
|
|
54
54
|
* required: []) with the base schema's properties plus the shared declaration.
|
|
55
55
|
* Static typing is preserved on the base (`as S`), so existing
|
|
56
56
|
* `Static<typeof ...>` derived parameter types are unchanged.
|
|
57
57
|
*/
|
|
58
|
-
export function
|
|
58
|
+
export function withTerminatingOutputDeclarations<
|
|
59
59
|
S extends TSchema & { properties?: Record<string, TSchema> },
|
|
60
60
|
>(schema: S): S {
|
|
61
61
|
const baseProperties = (schema as { properties?: Record<string, TSchema> })
|
|
62
62
|
.properties;
|
|
63
63
|
const properties: Record<string, TSchema> = {
|
|
64
64
|
...(baseProperties ?? {}),
|
|
65
|
+
...(
|
|
66
|
+
baseProperties?.ticketNumber === undefined
|
|
67
|
+
? {
|
|
68
|
+
ticketNumber: Type.Unknown({
|
|
69
|
+
description:
|
|
70
|
+
"可选本票号:尚未绑定时由角色在既有回执中申报;机械层只记录合法正整数,不从散文推导、不验真。缺失或错形不拒收。",
|
|
71
|
+
}),
|
|
72
|
+
}
|
|
73
|
+
: {}
|
|
74
|
+
),
|
|
65
75
|
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]:
|
|
66
76
|
infrastructureFailureDeclarationSchema.properties[
|
|
67
77
|
INFRASTRUCTURE_FAILURE_DECLARATION_KEY
|
|
@@ -32,6 +32,7 @@ import { COUNTERSIGN_ACCEPTED_TEXT, COUNTERSIGN_OUTPUT_TOOL_NAME, validateRecord
|
|
|
32
32
|
import { GLEANER_LEFT_ACCEPTED_TEXT, GLEANER_LEFT_OUTPUT_TOOL_NAME, validateRecordedGleanerLeftOutput, type GleanerLeftOutput } from "../gleaner-left-contracts.ts";
|
|
33
33
|
import { INSPECTOR_ACCEPTED_TEXT, INSPECTOR_OUTPUT_TOOL_NAME, validateRecordedInspectorOutput, type InspectorOutput } from "../inspector-contracts.ts";
|
|
34
34
|
import { DIARIST_ACCEPTED_TEXT, DIARIST_OUTPUT_TOOL_NAME, validateRecordedDiaristOutput, type DiaristOutput } from "../diarist-contracts.ts";
|
|
35
|
+
import { SECRETARIAT_ACCEPTED_TEXT, SECRETARIAT_OUTPUT_TOOL_NAME, type SecretariatVerdict } from "../secretariat-contracts.ts";
|
|
35
36
|
import {
|
|
36
37
|
CODER_ACCEPTED_TEXT,
|
|
37
38
|
CODER_OUTPUT_TOOL_NAME,
|
|
@@ -86,6 +87,7 @@ export type {
|
|
|
86
87
|
NavigatorAdvice,
|
|
87
88
|
AuditorOutput,
|
|
88
89
|
DiaristOutput,
|
|
90
|
+
SecretariatVerdict,
|
|
89
91
|
};
|
|
90
92
|
|
|
91
93
|
export const TERMINATING_TOOL_NAMES = [
|
|
@@ -104,6 +106,7 @@ export const TERMINATING_TOOL_NAMES = [
|
|
|
104
106
|
NAVIGATOR_OUTPUT_TOOL_NAME,
|
|
105
107
|
AUDITOR_OUTPUT_TOOL_NAME,
|
|
106
108
|
DIARIST_OUTPUT_TOOL_NAME,
|
|
109
|
+
SECRETARIAT_OUTPUT_TOOL_NAME,
|
|
107
110
|
] as const;
|
|
108
111
|
|
|
109
112
|
export type TerminatingToolName = (typeof TERMINATING_TOOL_NAMES)[number];
|
|
@@ -122,7 +125,8 @@ export type AcceptedDetails =
|
|
|
122
125
|
| GatekeeperDirectOutput
|
|
123
126
|
| NavigatorAdvice
|
|
124
127
|
| AuditorOutput
|
|
125
|
-
| DiaristOutput
|
|
128
|
+
| DiaristOutput
|
|
129
|
+
| SecretariatVerdict;
|
|
126
130
|
|
|
127
131
|
export function isTerminatingToolName(
|
|
128
132
|
name: string,
|
|
@@ -162,6 +166,8 @@ export function acceptedTextFor(toolName: TerminatingToolName): string {
|
|
|
162
166
|
return AUDITOR_ACCEPTED_TEXT;
|
|
163
167
|
case DIARIST_OUTPUT_TOOL_NAME:
|
|
164
168
|
return DIARIST_ACCEPTED_TEXT;
|
|
169
|
+
case SECRETARIAT_OUTPUT_TOOL_NAME:
|
|
170
|
+
return SECRETARIAT_ACCEPTED_TEXT;
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
173
|
|
|
@@ -214,6 +220,8 @@ export function acceptedFacts(toolName: TerminatingToolName, details: AcceptedDe
|
|
|
214
220
|
return typeof record.judgeStatus === "string" ? { status: record.judgeStatus } : {};
|
|
215
221
|
case COUNTERSIGN_OUTPUT_TOOL_NAME:
|
|
216
222
|
return typeof record.countersignStatus === "string" ? { status: record.countersignStatus } : {};
|
|
223
|
+
case SECRETARIAT_OUTPUT_TOOL_NAME:
|
|
224
|
+
return typeof record.secretariatStatus === "string" ? { status: record.secretariatStatus } : {};
|
|
217
225
|
case MERGER_OUTPUT_TOOL_NAME: {
|
|
218
226
|
const status = typeof record.status === "string" ? record.status : undefined;
|
|
219
227
|
return {
|
|
@@ -13,12 +13,14 @@ import { GLEANER_LEFT_OUTPUT_TOOL_NAME } from "./gleaner-left-contracts.ts";
|
|
|
13
13
|
import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.ts";
|
|
14
14
|
import { AUDITOR_OUTPUT_TOOL_NAME } from "./package-contracts/auditor-output.ts";
|
|
15
15
|
import { DIARIST_OUTPUT_TOOL_NAME } from "./diarist-contracts.ts";
|
|
16
|
+
import { SECRETARIAT_OUTPUT_TOOL_NAME } from "./secretariat-contracts.ts";
|
|
16
17
|
|
|
17
18
|
/** Shared by public notary and gatekeeper-province notary. */
|
|
18
19
|
export const NOTARY_SESSION_MATERIALS = [
|
|
19
20
|
"CLAUDE.md",
|
|
20
21
|
"souls/notary.md",
|
|
21
22
|
"souls/audit-law.md",
|
|
23
|
+
"souls/ticket-law.md",
|
|
22
24
|
"souls/gate-output-guide.md",
|
|
23
25
|
] as const;
|
|
24
26
|
|
|
@@ -154,7 +156,24 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
154
156
|
inputFlag: undefined,
|
|
155
157
|
phaseFlag: undefined,
|
|
156
158
|
activationStage: "load-and-install",
|
|
157
|
-
|
|
159
|
+
// #924: 公用《票面法》三席同装
|
|
160
|
+
sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md"],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
role: "secretariat",
|
|
164
|
+
phases: [null],
|
|
165
|
+
outputTool: SECRETARIAT_OUTPUT_TOOL_NAME,
|
|
166
|
+
inputFlag: undefined,
|
|
167
|
+
phaseFlag: undefined,
|
|
168
|
+
activationStage: "load-and-install",
|
|
169
|
+
// #924: owner-finalized Soul + 票面法 + 给事中/符宝郎行为指南
|
|
170
|
+
sessionMaterials: [
|
|
171
|
+
"CLAUDE.md",
|
|
172
|
+
"souls/secretariat.md",
|
|
173
|
+
"souls/ticket-law.md",
|
|
174
|
+
"souls/countersign.md",
|
|
175
|
+
"souls/notary.md",
|
|
176
|
+
],
|
|
158
177
|
},
|
|
159
178
|
{
|
|
160
179
|
role: "gleaner-left",
|
|
@@ -1,52 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* #709 公共入口通用递送与 #742
|
|
4
|
-
* 指针输入沿 ADR 0079
|
|
5
|
-
*
|
|
2
|
+
* 系统随案递送起居录路径的中立指针段(ADR 0081:公共入口直接挂案卷,Soul 只说明用途不负责派送;
|
|
3
|
+
* #709 公共入口通用递送与 #742 给事中受理链路同源;#858 告诉 LLM 路径,不另建取号/lookup)。
|
|
4
|
+
* 指针输入沿 ADR 0079(指针是绑定材料由代码精准递送),不把卷宗正文塞进提示词。
|
|
5
|
+
* 只告诉路径:不刷新、不生成、不校验内容、不新增拒收或停工条件、不从 instruction 抽票号。
|
|
6
6
|
* 机器文本仅中立标识材料(ADR 0073),用途说明归角色材料所有。
|
|
7
7
|
*
|
|
8
8
|
* 递送挂载点唯一:`post-admission` 在 beforeDispatch 之后为每个公共入口挂载。
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* systemPrompt.materials fold(#879:对话 instruction
|
|
12
|
-
*
|
|
9
|
+
* 全部公共入口(ordinary 已绑定/未绑定与 station-child)统一走 attachments 冻结 +
|
|
10
|
+
* role-runtime `loadCaseDossierReadingMaterial` → readingMaterial →
|
|
11
|
+
* systemPrompt.materials fold(#879 / #858:对话 instruction、空请求、resume
|
|
12
|
+
* message 保持调用者原文;起居录作独立附件面,不新造 RoleTurnRequest.materials,
|
|
13
|
+
* 不拼进 user-dialogue continuation)。
|
|
14
|
+
*
|
|
15
|
+
* #858: deliver returns typed FrozenAttachment[]; load currently re-derives the
|
|
16
|
+
* freeze leaf under runDirectory because agent-start only has HostContext.runDirectory.
|
|
17
|
+
* Consuming the typed frozenPath across that process boundary needs a design
|
|
18
|
+
* revision of the existing envelope/persistence seam — not a local replica of
|
|
19
|
+
* freezeAttachments' `00-` naming, not a drift throw, not readdir guessing.
|
|
13
20
|
*/
|
|
14
21
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
15
22
|
import { tmpdir } from "node:os";
|
|
16
23
|
import { join } from "node:path";
|
|
17
24
|
|
|
25
|
+
import { projectTicketRecordsPathShape } from "../sitian-facade.ts";
|
|
18
26
|
import { resolveTicketProvenanceVolume } from "../ticket-provenance.ts";
|
|
19
27
|
import {
|
|
20
28
|
freezeAttachmentsIntoRun,
|
|
21
29
|
type FrozenAttachment,
|
|
22
30
|
} from "./invocation.ts";
|
|
23
31
|
|
|
24
|
-
/**
|
|
32
|
+
/** Bound-ticket section heading (presentation only). */
|
|
25
33
|
const CASE_DOSSIER_SECTION_HEADING = "## 本票起居录(系统随案提供)" as const;
|
|
26
34
|
|
|
35
|
+
/** Unbound path-only heading — no 本票 claim when no typed ticket is on the run. */
|
|
36
|
+
const UNBOUND_DOSSIER_PATH_HEADING = "## 起居录路径(系统随案提供)" as const;
|
|
37
|
+
|
|
27
38
|
/** Stable freeze key under run/attachments/ for station-child 0081 delivery. */
|
|
28
39
|
const CASE_DOSSIER_ATTACH_KEY = "case-dossier" as const;
|
|
29
40
|
|
|
30
41
|
/** Leaf name of the frozen pointer section (content = purpose + paths). */
|
|
31
42
|
const CASE_DOSSIER_ATTACH_FILE = "case-dossier-pointer.md" as const;
|
|
32
43
|
|
|
33
|
-
/** Pointer only — presence/absence is for the role to observe at the path. */
|
|
34
|
-
function describeDossierFile(path: string): string {
|
|
35
|
-
return path;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
44
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* the
|
|
45
|
+
* Neutral 起居录 path pointer for every public entry (ADR 0081 delivery seam).
|
|
46
|
+
* Always tells the canonical path shape so the seat LLM can read the diary
|
|
47
|
+
* itself (陛下 2026-09-15: 只需要告诉llm这个路径). When a typed ticket identity is
|
|
48
|
+
* already on the run, also project the concrete resolved file. Never claims a
|
|
49
|
+
* volume or「本票」exists when unbound; never extracts a ticket from instruction.
|
|
50
|
+
* Under-book shape comes only from sitian writer joins — no local replica.
|
|
43
51
|
*/
|
|
44
52
|
export async function projectCaseDossierPointerSection(input: {
|
|
45
53
|
readonly ticketNumber: number | undefined;
|
|
46
54
|
readonly projectRoot: string;
|
|
47
55
|
readonly home: string;
|
|
48
|
-
}): Promise<string
|
|
49
|
-
if (input.ticketNumber === undefined)
|
|
56
|
+
}): Promise<string> {
|
|
57
|
+
if (input.ticketNumber === undefined) {
|
|
58
|
+
return [
|
|
59
|
+
UNBOUND_DOSSIER_PATH_HEADING,
|
|
60
|
+
"",
|
|
61
|
+
`记录卷宗:${projectTicketRecordsPathShape()}`,
|
|
62
|
+
].join("\n");
|
|
63
|
+
}
|
|
50
64
|
const volume = resolveTicketProvenanceVolume(
|
|
51
65
|
input.ticketNumber,
|
|
52
66
|
input.projectRoot,
|
|
@@ -56,30 +70,30 @@ export async function projectCaseDossierPointerSection(input: {
|
|
|
56
70
|
CASE_DOSSIER_SECTION_HEADING,
|
|
57
71
|
"",
|
|
58
72
|
`票号:#${input.ticketNumber}`,
|
|
59
|
-
`记录卷宗:${
|
|
73
|
+
`记录卷宗:${volume.recordFile}`,
|
|
60
74
|
].join("\n");
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
/**
|
|
64
|
-
* ADR 0081 delivery for
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
78
|
+
* ADR 0081 delivery for every public entry (#879 / #858): freeze the pointer
|
|
79
|
+
* section through the existing attachments seam. Role-runtime loads that freeze
|
|
80
|
+
* via loadCaseDossierReadingMaterial onto readingMaterial; the envelope then
|
|
81
|
+
* folds it into systemPrompt.materials. Caller / peer dialogue instruction stays
|
|
82
|
+
* opaque; never RoleTurnRequest.materials, never user-dialogue continuation.
|
|
83
|
+
* Always freezes the path pointer (canonical shape, or concrete file when a
|
|
84
|
+
* typed ticket is already bound).
|
|
70
85
|
*/
|
|
71
86
|
export async function deliverCaseDossierAsAttachment(input: {
|
|
72
87
|
readonly ticketNumber: number | undefined;
|
|
73
88
|
readonly projectRoot: string;
|
|
74
89
|
readonly home: string;
|
|
75
90
|
readonly runDirectory: string;
|
|
76
|
-
}): Promise<readonly FrozenAttachment[]
|
|
91
|
+
}): Promise<readonly FrozenAttachment[]> {
|
|
77
92
|
const section = await projectCaseDossierPointerSection({
|
|
78
93
|
ticketNumber: input.ticketNumber,
|
|
79
94
|
projectRoot: input.projectRoot,
|
|
80
95
|
home: input.home,
|
|
81
96
|
});
|
|
82
|
-
if (section === undefined) return undefined;
|
|
83
97
|
// Stage in OS temp only — never leave a run-local .case-dossier-stage copy.
|
|
84
98
|
const stagingDir = await mkdtemp(join(tmpdir(), "ak-case-dossier-"));
|
|
85
99
|
try {
|
|
@@ -106,6 +120,11 @@ export type CaseDossierReadingMaterial = {
|
|
|
106
120
|
* Load a previously frozen case-dossier attachment as reading material
|
|
107
121
|
* (existing agent-start / systemPrompt.materials fold — not dialogue prompt,
|
|
108
122
|
* not RoleTurnRequest.materials). Undefined when the run has no such freeze.
|
|
123
|
+
*
|
|
124
|
+
* #858: this join re-derives freezeAttachments' leaf naming because the
|
|
125
|
+
* agent-start handler only receives runDirectory. Replacing it requires
|
|
126
|
+
* threading deliver's typed frozenPath across the existing envelope seam
|
|
127
|
+
* (design revision) — do not copy freeze's `00-` algorithm here again.
|
|
109
128
|
*/
|
|
110
129
|
export async function loadCaseDossierReadingMaterial(
|
|
111
130
|
runDirectory: string,
|
package/src/public-cli/cli.ts
CHANGED
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
parseCollectorArgv,
|
|
65
65
|
parseCountersignArgv,
|
|
66
66
|
parseDiaristArgv,
|
|
67
|
+
parseSecretariatArgv,
|
|
67
68
|
parseGleanerLeftArgv,
|
|
68
69
|
parseDoctorArgv,
|
|
69
70
|
parseFixerArgv,
|
|
@@ -91,6 +92,7 @@ import { runPublicInstructionSeat, runPublicInstructionSeatResume } from "./inst
|
|
|
91
92
|
import { runPublicCollector, runPublicCollectorResume } from "./collector-run.ts";
|
|
92
93
|
import { runPublicCountersign, runPublicCountersignResume } from "./countersign-run.ts";
|
|
93
94
|
import { runPublicDiarist, runPublicDiaristResume } from "./diarist-run.ts";
|
|
95
|
+
import { runPublicSecretariat, runPublicSecretariatResume } from "./secretariat-run.ts";
|
|
94
96
|
import { runPublicGleanerLeft, runPublicGleanerLeftResume } from "./gleaner-left-run.ts";
|
|
95
97
|
import { runPublicDoctor, runPublicDoctorResume } from "./doctor-run.ts";
|
|
96
98
|
import { runPublicFixer, runPublicFixerResume } from "./fixer-run.ts";
|
|
@@ -141,6 +143,7 @@ const RESUME_SEAT_DISPATCH: Record<
|
|
|
141
143
|
navigator: { seat: "navigator", run: runPublicInstructionSeatResume },
|
|
142
144
|
auditor: { seat: "auditor", run: runPublicInstructionSeatResume },
|
|
143
145
|
diarist: { seat: "diarist", run: runPublicDiaristResume },
|
|
146
|
+
secretariat: { seat: "secretariat", run: runPublicSecretariatResume },
|
|
144
147
|
};
|
|
145
148
|
import {
|
|
146
149
|
INTERNAL_ROLE_ENTRYPOINT_RELATIVE,
|
|
@@ -186,6 +189,7 @@ export const PUBLIC_ROLE_ARGV = {
|
|
|
186
189
|
navigator: { parse: parseNavigatorArgv, options: optionsForOwner("navigator") },
|
|
187
190
|
auditor: { parse: parseAuditorArgv, options: optionsForOwner("auditor") },
|
|
188
191
|
diarist: { parse: parseDiaristArgv, options: optionsForOwner("diarist") },
|
|
192
|
+
secretariat: { parse: parseSecretariatArgv, options: optionsForOwner("secretariat") },
|
|
189
193
|
/** Deterministic analysis seat (#336) — argv parse only; no LLM admission. */
|
|
190
194
|
analyst: { parse: parseAnalystArgv, options: optionsForOwner("analyst") },
|
|
191
195
|
} as const;
|
|
@@ -1349,6 +1353,12 @@ export async function runAkRole(
|
|
|
1349
1353
|
(args, roleEnv, once) => runPublicDiarist(args, roleEnv, io, once),
|
|
1350
1354
|
);
|
|
1351
1355
|
}
|
|
1356
|
+
if (parsed.command === "secretariat") {
|
|
1357
|
+
return await dispatchPublicRoleCommand(
|
|
1358
|
+
env, home, io, parsed, "secretariat", PUBLIC_ROLE_ARGV.secretariat.parse,
|
|
1359
|
+
(args, roleEnv, once) => runPublicSecretariat(args, roleEnv, io, once),
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1352
1362
|
if (parsed.command === "coder") {
|
|
1353
1363
|
return await dispatchPublicRoleCommand(
|
|
1354
1364
|
env, home, io, parsed, "coder", PUBLIC_ROLE_ARGV.coder.parse,
|