@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
|
@@ -355,6 +355,10 @@ const DIARIST_OPTIONS = [
|
|
|
355
355
|
bindOwner("diarist", SHARED_PROJECT_SEMANTICS),
|
|
356
356
|
bindOwner("diarist", SHARED_ATTACH_SEMANTICS),
|
|
357
357
|
];
|
|
358
|
+
const SECRETARIAT_OPTIONS = [
|
|
359
|
+
bindOwner("secretariat", SHARED_PROJECT_SEMANTICS),
|
|
360
|
+
bindOwner("secretariat", SHARED_ATTACH_SEMANTICS),
|
|
361
|
+
];
|
|
358
362
|
const CODER_OPTIONS = [
|
|
359
363
|
{
|
|
360
364
|
id: "phase",
|
|
@@ -721,6 +725,7 @@ export const PUBLIC_OPTION_TABLE = {
|
|
|
721
725
|
navigator: NAVIGATOR_OPTIONS,
|
|
722
726
|
auditor: AUDITOR_OPTIONS,
|
|
723
727
|
diarist: DIARIST_OPTIONS,
|
|
728
|
+
secretariat: SECRETARIAT_OPTIONS,
|
|
724
729
|
analyst: ANALYST_OPTIONS,
|
|
725
730
|
};
|
|
726
731
|
/** Role/deterministic owners that appear on PUBLIC_ROLE_ARGV. */
|
|
@@ -740,6 +745,7 @@ export const PUBLIC_ROLE_OPTION_OWNERS = [
|
|
|
740
745
|
"navigator",
|
|
741
746
|
"auditor",
|
|
742
747
|
"diarist",
|
|
748
|
+
"secretariat",
|
|
743
749
|
"analyst",
|
|
744
750
|
];
|
|
745
751
|
export function optionsForOwner(owner) {
|
|
@@ -1051,6 +1057,14 @@ const ROLE_COMMAND_HELP = {
|
|
|
1051
1057
|
'ak-role diarist --attach ./design.md "补录本轮设计修订。"',
|
|
1052
1058
|
],
|
|
1053
1059
|
},
|
|
1060
|
+
secretariat: {
|
|
1061
|
+
command: "secretariat",
|
|
1062
|
+
summary: "Secretariat (中书省): rewrite ticket per 票面法 and drive countersign to converged or escalate.",
|
|
1063
|
+
usage: ["ak-role secretariat [options] [instruction]"],
|
|
1064
|
+
examples: [
|
|
1065
|
+
'ak-role secretariat "整理 #924 票面并送庭。"',
|
|
1066
|
+
],
|
|
1067
|
+
},
|
|
1054
1068
|
notary: {
|
|
1055
1069
|
command: "notary",
|
|
1056
1070
|
summary: "Direct Notary document check (quote fidelity + ticket alignment); zero prompt/attachment.",
|
|
@@ -10,12 +10,13 @@ import { writeFile } from "node:fs/promises";
|
|
|
10
10
|
import { isAbsolute, join, resolve } from "node:path";
|
|
11
11
|
import { buildResumeContinuationPrompt, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
|
|
12
12
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
|
-
import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
|
|
13
|
+
import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
|
|
14
|
+
import { readRecordedSubmissionRows } from "../submission-ledger.js";
|
|
14
15
|
import { pathContainedIn } from "../activation-ledger-topology.js";
|
|
15
16
|
import { pickEngineAxis } from "../package-resources/engine-material.js";
|
|
16
17
|
import { resolveHostAwareSessionAvailability } from "../session-identity.js";
|
|
17
18
|
import { isOfficerReviewSeat } from "../host-contracts.js";
|
|
18
|
-
import { deliverCaseDossierAsAttachment
|
|
19
|
+
import { deliverCaseDossierAsAttachment } from "./case-dossier-delivery.js";
|
|
19
20
|
/** Original error bytes, never relabeled — a secondary fact riding beside a classified cause. */
|
|
20
21
|
function describeCaughtError(error) {
|
|
21
22
|
if (error instanceof Error) {
|
|
@@ -24,13 +25,6 @@ function describeCaughtError(error) {
|
|
|
24
25
|
}
|
|
25
26
|
return { message: String(error) };
|
|
26
27
|
}
|
|
27
|
-
/** Append one system section to a continuation prompt, keeping its kind. */
|
|
28
|
-
function appendContinuationSection(continuation, section) {
|
|
29
|
-
const prompt = `${continuation.prompt}\n\n${section}`;
|
|
30
|
-
return continuation.kind === "initial"
|
|
31
|
-
? { kind: "initial", prompt }
|
|
32
|
-
: { kind: "resume", prompt };
|
|
33
|
-
}
|
|
34
28
|
/**
|
|
35
29
|
* Nested gate summons (station child) on an officer seat: dialogue content is
|
|
36
30
|
* peer words only (#879). ADR 0081 case dossier still hangs via the existing
|
|
@@ -262,11 +256,32 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
262
256
|
*/
|
|
263
257
|
let afterDispatchApplied = false;
|
|
264
258
|
const finishAfterTurn = async (result) => {
|
|
265
|
-
if (
|
|
259
|
+
if (afterDispatchApplied)
|
|
266
260
|
return result;
|
|
267
261
|
afterDispatchApplied = true;
|
|
268
262
|
try {
|
|
269
|
-
|
|
263
|
+
// #858: an unbound seat may assert its ticket on the existing receipt.
|
|
264
|
+
// Read the original accepted payload; do not rewrite it, infer from prose,
|
|
265
|
+
// or reject missing/malformed declarations. An existing binding wins.
|
|
266
|
+
if (admitted.ticketNumber === undefined) {
|
|
267
|
+
const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, { home: homeFromRunDirectory(admitted.runDirectory), sessionParent: join(admitted.runDirectory, "session", "session.jsonl") });
|
|
268
|
+
const asserted = rows
|
|
269
|
+
.filter((row) => row.kind === "accepted" && row.role === admitted.role)
|
|
270
|
+
.map((row) => row.accepted)
|
|
271
|
+
.find((payload) => {
|
|
272
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload))
|
|
273
|
+
return false;
|
|
274
|
+
const value = payload.ticketNumber;
|
|
275
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
276
|
+
});
|
|
277
|
+
const ticketNumber = asserted === undefined
|
|
278
|
+
? undefined
|
|
279
|
+
: asserted.ticketNumber;
|
|
280
|
+
if (ticketNumber !== undefined)
|
|
281
|
+
await bindAdmittedTicketNumber(admitted, ticketNumber);
|
|
282
|
+
}
|
|
283
|
+
if (adapters.afterDispatch !== undefined)
|
|
284
|
+
await adapters.afterDispatch(admitted, lease);
|
|
270
285
|
return result;
|
|
271
286
|
}
|
|
272
287
|
catch (error) {
|
|
@@ -362,10 +377,11 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
362
377
|
}
|
|
363
378
|
// Turn request is assembled after beforeDispatch so this turn sees whatever it
|
|
364
379
|
// settled — the seat's ticket bind re-projection and any court diarist station
|
|
365
|
-
// writes (#742). Case dossier delivery (ADR 0081 / #709) rides here once
|
|
366
|
-
// every public entry
|
|
367
|
-
//
|
|
368
|
-
//
|
|
380
|
+
// writes (#742). Case dossier delivery (ADR 0081 / #709 / #858) rides here once
|
|
381
|
+
// for every public entry on the existing attachments → readingMaterial face
|
|
382
|
+
// (station-child and ordinary share one seam). Dialogue continuation stays
|
|
383
|
+
// caller/peer opaque — never splice system path sections into user dialogue.
|
|
384
|
+
// No package-resume parallel face or typed resume identity.
|
|
369
385
|
let turnRequest = env.signal === undefined ? request : { ...request, signal: env.signal };
|
|
370
386
|
if (env.stationChild !== undefined) {
|
|
371
387
|
turnRequest = { ...turnRequest, stationChild: env.stationChild };
|
|
@@ -378,32 +394,16 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
378
394
|
if (typeof liveHost === "string" && liveHost.trim() !== "") {
|
|
379
395
|
turnRequest = { ...turnRequest, host: liveHost.trim() };
|
|
380
396
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
runDirectory: admitted.runDirectory,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
const dossierSection = await projectCaseDossierPointerSection({
|
|
396
|
-
ticketNumber: admitted.ticketNumber,
|
|
397
|
-
projectRoot: admitted.projectRoot,
|
|
398
|
-
home: env.home,
|
|
399
|
-
});
|
|
400
|
-
if (dossierSection !== undefined) {
|
|
401
|
-
turnRequest = {
|
|
402
|
-
...turnRequest,
|
|
403
|
-
continuation: appendContinuationSection(turnRequest.continuation, dossierSection),
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
}
|
|
397
|
+
// 0081 non-dialogue face: freeze pointer section under run/attachments/.
|
|
398
|
+
// Seat consumes via loadCaseDossierReadingMaterial → existing agent-start
|
|
399
|
+
// readingMaterial / systemPrompt.materials fold. Caller instruction, empty
|
|
400
|
+
// request, and resume --message stay verbatim.
|
|
401
|
+
await deliverCaseDossierAsAttachment({
|
|
402
|
+
ticketNumber: admitted.ticketNumber,
|
|
403
|
+
projectRoot: admitted.projectRoot,
|
|
404
|
+
home: env.home,
|
|
405
|
+
runDirectory: admitted.runDirectory,
|
|
406
|
+
});
|
|
407
407
|
// Authoritative host write happens here, at the real dispatch boundary —
|
|
408
408
|
// immediately before the turn actually starts, after every retryable
|
|
409
409
|
// pre-turn step above has succeeded on this attempt (#840 r9 判词 class 2).
|
|
@@ -784,9 +784,9 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
784
784
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
785
785
|
...pickEngineAxis(env),
|
|
786
786
|
...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
|
|
787
|
-
...(
|
|
787
|
+
...(env.correlationId === undefined && admitted.correlationId === undefined
|
|
788
788
|
? {}
|
|
789
|
-
: { correlationId:
|
|
789
|
+
: { correlationId: env.correlationId ?? admitted.correlationId }),
|
|
790
790
|
continuation: {
|
|
791
791
|
kind: "resume",
|
|
792
792
|
prompt,
|
|
@@ -999,12 +999,7 @@ export async function runPostAdmissionSeatResume(input) {
|
|
|
999
999
|
dispatch: async (turnRequest) => {
|
|
1000
1000
|
const result = await dispatchPostAdmissionTurn({
|
|
1001
1001
|
admitted: loaded.admitted,
|
|
1002
|
-
env:
|
|
1003
|
-
...input.env,
|
|
1004
|
-
...(loaded.admitted.correlationId === undefined
|
|
1005
|
-
? {}
|
|
1006
|
-
: { correlationId: loaded.admitted.correlationId }),
|
|
1007
|
-
},
|
|
1002
|
+
env: input.env,
|
|
1008
1003
|
io: attemptIo,
|
|
1009
1004
|
request: turnRequest,
|
|
1010
1005
|
lease,
|
|
@@ -169,7 +169,8 @@ async function readRoleRunStateDisk(runDirectory) {
|
|
|
169
169
|
record.role !== "gatekeeper" &&
|
|
170
170
|
record.role !== "navigator" &&
|
|
171
171
|
record.role !== "auditor" &&
|
|
172
|
-
record.role !== "diarist"
|
|
172
|
+
record.role !== "diarist" &&
|
|
173
|
+
record.role !== "secretariat") {
|
|
173
174
|
return undefined;
|
|
174
175
|
}
|
|
175
176
|
if (record.state !== "admitted" &&
|
|
@@ -1411,6 +1412,17 @@ export async function loadResumableDiaristRun(home, runId, authority) {
|
|
|
1411
1412
|
};
|
|
1412
1413
|
return seatLoadedResult(loaded, admitted);
|
|
1413
1414
|
}
|
|
1415
|
+
export async function loadResumableSecretariatRun(home, runId, authority) {
|
|
1416
|
+
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1417
|
+
if (loaded.run.role !== "secretariat") {
|
|
1418
|
+
throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not secretariat`);
|
|
1419
|
+
}
|
|
1420
|
+
const admitted = {
|
|
1421
|
+
role: "secretariat",
|
|
1422
|
+
...resumedBaseAdmitted(loaded),
|
|
1423
|
+
};
|
|
1424
|
+
return seatLoadedResult(loaded, admitted);
|
|
1425
|
+
}
|
|
1414
1426
|
/**
|
|
1415
1427
|
* Load a resumable Merger run for resume. Derived envelope + internal input path
|
|
1416
1428
|
* are restored from the admitted request (#114).
|
|
@@ -33,6 +33,7 @@ import { NOTARY_OUTPUT_TOOL_NAME, } from "../notary-contracts.js";
|
|
|
33
33
|
import { COUNTERSIGN_OUTPUT_TOOL_NAME, } from "../countersign-contracts.js";
|
|
34
34
|
import { GLEANER_LEFT_OUTPUT_TOOL_NAME, } from "../gleaner-left-contracts.js";
|
|
35
35
|
import { DIARIST_OUTPUT_TOOL_NAME, } from "../diarist-contracts.js";
|
|
36
|
+
import { SECRETARIAT_OUTPUT_TOOL_NAME, } from "../secretariat-contracts.js";
|
|
36
37
|
import { INSPECTOR_OUTPUT_TOOL_NAME, } from "../inspector-contracts.js";
|
|
37
38
|
import { GATEKEEPER_OUTPUT_TOOL_NAME, } from "../package-contracts/gatekeeper-output.js";
|
|
38
39
|
import { NAVIGATOR_OUTPUT_TOOL_NAME, } from "../package-contracts/navigator-output.js";
|
|
@@ -672,44 +673,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
|
|
|
672
673
|
const parentId = parentEntries.find((entry) => entry.type === "session")?.id;
|
|
673
674
|
if (parentId === undefined)
|
|
674
675
|
return undefined;
|
|
675
|
-
const isResumeEnvelopeBytes = (value) => {
|
|
676
|
-
if (typeof value !== "string")
|
|
677
|
-
return false;
|
|
678
|
-
if (value.length === 0)
|
|
679
|
-
return true;
|
|
680
|
-
const nl = value.indexOf("\n");
|
|
681
|
-
const firstLine = nl === -1 ? value : value.slice(0, nl);
|
|
682
|
-
const body = firstLine === "" && nl !== -1 ? value.slice(nl + 1) : value;
|
|
683
|
-
return body.startsWith("本次配置的劳务引擎及其手册:") || body.startsWith("- engine:");
|
|
684
|
-
};
|
|
685
|
-
const isResumeEnvelope = (msg) => {
|
|
686
|
-
if (!isRecord(msg) || msg.role !== "user")
|
|
687
|
-
return false;
|
|
688
|
-
const text = typeof msg.text === "string" ? msg.text : typeof msg.content === "string" ? msg.content : undefined;
|
|
689
|
-
if (isResumeEnvelopeBytes(text))
|
|
690
|
-
return true;
|
|
691
|
-
const content = msg.content;
|
|
692
|
-
if (Array.isArray(content)) {
|
|
693
|
-
return content.some((p) => isRecord(p) && (isResumeEnvelopeBytes(p.text) || isResumeEnvelopeBytes(p.content)));
|
|
694
|
-
}
|
|
695
|
-
return false;
|
|
696
|
-
};
|
|
697
|
-
let latestParentUserIndex = -1;
|
|
698
|
-
for (let i = parentEntries.length - 1; i >= 0; i -= 1) {
|
|
699
|
-
const entry = parentEntries[i];
|
|
700
|
-
if (entry?.type !== "message" || entry.message?.role !== "user")
|
|
701
|
-
continue;
|
|
702
|
-
if (isResumeEnvelope(entry.message))
|
|
703
|
-
continue;
|
|
704
|
-
latestParentUserIndex = i;
|
|
705
|
-
break;
|
|
706
|
-
}
|
|
707
676
|
const childDirectories = [join(dirname(sessionFile), "auditor-roles")];
|
|
708
|
-
// Auto-resume seam (owner A): stale check must ignore resume envelope and
|
|
709
|
-
// prioritize retention. Previous `attemptEntryIndex < latest` discarded the
|
|
710
|
-
// first attempt's child after resume advanced latest, losing retentionFailure
|
|
711
|
-
// when retry had no compliance entry. Fix: ignore envelope for staleness and
|
|
712
|
-
// prefer any valid compliance failure before falling back to primary.
|
|
713
677
|
const valid = [];
|
|
714
678
|
let sawAnyDirectory = false;
|
|
715
679
|
for (const childDirectory of childDirectories) {
|
|
@@ -759,9 +723,6 @@ async function loadBoundAuditorVolumes(sessionFile) {
|
|
|
759
723
|
const attemptEntryId = typeof bindingParent?.attemptEntryId === "string"
|
|
760
724
|
? bindingParent.attemptEntryId
|
|
761
725
|
: undefined;
|
|
762
|
-
const attemptEntryIndex = attemptEntryId === undefined
|
|
763
|
-
? -1
|
|
764
|
-
: parentEntries.findIndex((entry) => entry.id === attemptEntryId);
|
|
765
726
|
const boundSessionFile = typeof bindingParent?.sessionFile === "string"
|
|
766
727
|
? bindingParent.sessionFile
|
|
767
728
|
: typeof header.parentSession === "string"
|
|
@@ -769,10 +730,8 @@ async function loadBoundAuditorVolumes(sessionFile) {
|
|
|
769
730
|
: undefined;
|
|
770
731
|
if (boundSessionFile !== sessionFile)
|
|
771
732
|
continue;
|
|
772
|
-
if (bindingParent !== undefined &&
|
|
773
|
-
(bindingParent.sessionId !== parentId || attemptEntryIndex < latestParentUserIndex)) {
|
|
733
|
+
if (bindingParent !== undefined && bindingParent.sessionId !== parentId)
|
|
774
734
|
continue;
|
|
775
|
-
}
|
|
776
735
|
if (bindingParent === undefined && header.parentSession !== sessionFile)
|
|
777
736
|
continue;
|
|
778
737
|
valid.push({
|
|
@@ -781,8 +740,8 @@ async function loadBoundAuditorVolumes(sessionFile) {
|
|
|
781
740
|
sessionFile,
|
|
782
741
|
...(attemptEntryId === undefined ? {} : { attemptEntryId }),
|
|
783
742
|
});
|
|
784
|
-
// Keep every
|
|
785
|
-
//
|
|
743
|
+
// Keep every interval bound to this parent. Auditor payload is relayed as
|
|
744
|
+
// recorded; code does not expire it from later user-message shape (#858).
|
|
786
745
|
}
|
|
787
746
|
}
|
|
788
747
|
}
|
|
@@ -843,14 +802,6 @@ function providerStopFallbackFromAuditorVolumes(volumes) {
|
|
|
843
802
|
}
|
|
844
803
|
return undefined;
|
|
845
804
|
}
|
|
846
|
-
/** Recover a provider stop from the auditor child bound to the current parent attempt. */
|
|
847
|
-
export async function readBoundAuditorKnownFailure(sessionFile) {
|
|
848
|
-
const volumes = await loadBoundAuditorVolumes(sessionFile);
|
|
849
|
-
if (volumes === undefined)
|
|
850
|
-
return undefined;
|
|
851
|
-
return complianceFailureFromAuditorVolumes(volumes)
|
|
852
|
-
?? providerStopFallbackFromAuditorVolumes(volumes);
|
|
853
|
-
}
|
|
854
805
|
/** Strong auditor tier only — retained compliance-failure entries, no provider-stop fallback. */
|
|
855
806
|
async function readBoundAuditorComplianceFailure(sessionFile) {
|
|
856
807
|
const volumes = await loadBoundAuditorVolumes(sessionFile);
|
|
@@ -2361,6 +2312,16 @@ async function settleLawfulDiaristTerminalResult(admitted, authority, scope) {
|
|
|
2361
2312
|
export async function trySettleDiaristTerminalResult(admitted, authority, scope) {
|
|
2362
2313
|
return settleLawfulDiaristTerminalResult(admitted, authority, scope);
|
|
2363
2314
|
}
|
|
2315
|
+
async function settleLawfulSecretariatTerminalResult(admitted, authority, scope) {
|
|
2316
|
+
return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
|
|
2317
|
+
role: "secretariat",
|
|
2318
|
+
toolName: SECRETARIAT_OUTPUT_TOOL_NAME,
|
|
2319
|
+
}, scope);
|
|
2320
|
+
}
|
|
2321
|
+
/** Try to settle a lawful Secretariat Terminal; undefined only for genuine absence. */
|
|
2322
|
+
export async function trySettleSecretariatTerminalResult(admitted, authority, scope) {
|
|
2323
|
+
return settleLawfulSecretariatTerminalResult(admitted, authority, scope);
|
|
2324
|
+
}
|
|
2364
2325
|
async function settleLawfulInspectorTerminalResult(admitted, authority, scope) {
|
|
2365
2326
|
return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
|
|
2366
2327
|
role: "inspector",
|
|
@@ -169,11 +169,15 @@ async function summonPublicRole(options) {
|
|
|
169
169
|
env: {
|
|
170
170
|
...built.env,
|
|
171
171
|
stationChild: true,
|
|
172
|
+
// Forward composition-root adapters so nested court stations (e.g.
|
|
173
|
+
// countersign → diarist) select the same faux/production table (#924).
|
|
174
|
+
...options.hostAdapters === void 0 ? {} : { hostAdapters: options.hostAdapters },
|
|
172
175
|
...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit },
|
|
173
176
|
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
174
177
|
...options.reviewReask === void 0 ? {} : { reviewReask: options.reviewReask },
|
|
175
178
|
...options.gateReviewInstruction === void 0 ? {} : { gateReviewInstruction: options.gateReviewInstruction },
|
|
176
179
|
...options.boundTicketNumber === void 0 ? {} : { boundTicketNumber: options.boundTicketNumber },
|
|
180
|
+
...options.correlationId === void 0 || options.correlationId.trim() === "" ? {} : { correlationId: options.correlationId },
|
|
177
181
|
...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
|
|
178
182
|
}
|
|
179
183
|
};
|
|
@@ -276,6 +280,16 @@ async function summonPublicRole(options) {
|
|
|
276
280
|
result = stepped.ok;
|
|
277
281
|
break;
|
|
278
282
|
}
|
|
283
|
+
case "countersign": {
|
|
284
|
+
const [{ runPublicCountersign }, { parseCountersignArgv }] = await Promise.all([
|
|
285
|
+
import("./public-cli/countersign-run.js"),
|
|
286
|
+
import("./public-cli/invocation.js")
|
|
287
|
+
]);
|
|
288
|
+
const stepped = await runPrepared(parseCountersignArgv, (env, once) => runPublicCountersign(options.argv, env, io, once));
|
|
289
|
+
if ("fail" in stepped) return stepped.fail;
|
|
290
|
+
result = stepped.ok;
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
279
293
|
}
|
|
280
294
|
const stderr = captured?.stderrText();
|
|
281
295
|
const runDirectory = result.admitted?.runDirectory;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const SECRETARIAT_OUTPUT_TOOL_NAME = "ak_secretariat_output";
|
|
2
|
+
const SECRETARIAT_SUMMON_COUNTERSIGN_TOOL_NAME = "ak_secretariat_summon_countersign";
|
|
3
|
+
const SECRETARIAT_ACCEPTED_TEXT = "\u4E2D\u4E66\u7701\u56DE\u6267\u5DF2\u63A5\u53D7";
|
|
4
|
+
export {
|
|
5
|
+
SECRETARIAT_ACCEPTED_TEXT,
|
|
6
|
+
SECRETARIAT_OUTPUT_TOOL_NAME,
|
|
7
|
+
SECRETARIAT_SUMMON_COUNTERSIGN_TOOL_NAME
|
|
8
|
+
};
|
package/dist/sitian-appender.js
CHANGED
|
@@ -152,25 +152,41 @@ function resolveSitianVolumeCategory(kind) {
|
|
|
152
152
|
}
|
|
153
153
|
return kind;
|
|
154
154
|
}
|
|
155
|
+
const SITIAN_RECORDS_LEAF = "records.jsonl";
|
|
156
|
+
function ticketProvenanceUnderBookPaths(ledgerHome, bookKey, ticketId) {
|
|
157
|
+
const sessionDir = join(activationBookDirectory(ledgerHome, bookKey), ticketId);
|
|
158
|
+
return { sessionDir, recordFile: join(sessionDir, SITIAN_RECORDS_LEAF) };
|
|
159
|
+
}
|
|
155
160
|
function resolveSitianRecordPathInLedger(input, ledgerHome) {
|
|
156
161
|
const category = resolveSitianVolumeCategory(input.kind);
|
|
157
162
|
const ticketNumber = category === "ticket-provenance" ? typeof input.subject === "string" && /^[1-9][0-9]*$/.test(input.subject) ? input.subject : typeof input.subject === "object" && typeof input.subject.ticketNumber === "number" && Number.isSafeInteger(input.subject.ticketNumber) && input.subject.ticketNumber > 0 ? String(input.subject.ticketNumber) : void 0 : void 0;
|
|
158
163
|
let sessionDir;
|
|
164
|
+
let recordFile;
|
|
159
165
|
if (ticketNumber !== void 0) {
|
|
160
|
-
const
|
|
166
|
+
const paths = ticketProvenanceUnderBookPaths(
|
|
161
167
|
ledgerHome,
|
|
162
|
-
resolveBookKeyFromGit(input.cwd ?? process.cwd())
|
|
168
|
+
resolveBookKeyFromGit(input.cwd ?? process.cwd()),
|
|
169
|
+
ticketNumber
|
|
163
170
|
);
|
|
164
|
-
sessionDir =
|
|
171
|
+
sessionDir = paths.sessionDir;
|
|
172
|
+
recordFile = paths.recordFile;
|
|
165
173
|
} else {
|
|
166
174
|
if (input.sessionParent === void 0 || input.sessionParent.length === 0 || !physicallyContainedIn(ledgerHome, input.sessionParent)) {
|
|
167
175
|
throw new Error("Sitian record ownership requires a parent session inside the ledger home");
|
|
168
176
|
}
|
|
169
177
|
sessionDir = join(dirname(input.sessionParent), category);
|
|
178
|
+
recordFile = join(sessionDir, SITIAN_RECORDS_LEAF);
|
|
170
179
|
}
|
|
171
|
-
const recordFile = join(sessionDir, "records.jsonl");
|
|
172
180
|
return { sessionDir, recordFile, ledgerHome };
|
|
173
181
|
}
|
|
182
|
+
function projectTicketRecordsPathShape() {
|
|
183
|
+
const { recordFile } = ticketProvenanceUnderBookPaths(
|
|
184
|
+
join("~", ".ak-roles"),
|
|
185
|
+
"<\u7C3F>",
|
|
186
|
+
"<\u7968\u53F7>"
|
|
187
|
+
);
|
|
188
|
+
return recordFile.replace(/\\/g, "/");
|
|
189
|
+
}
|
|
174
190
|
function resolveSitianRecordPath(input) {
|
|
175
191
|
const ledgerHome = input.home !== void 0 && input.home.length > 0 ? resolveActivationLedgerHome(input.home) : resolveActivationLedgerHomeForPath(input.sessionParent);
|
|
176
192
|
return resolveSitianRecordPathInLedger(input, ledgerHome);
|
|
@@ -210,6 +226,7 @@ function appendSitianRecord(input) {
|
|
|
210
226
|
export {
|
|
211
227
|
S4_SUBMISSION_LEDGER_KINDS,
|
|
212
228
|
appendSitianRecord,
|
|
229
|
+
projectTicketRecordsPathShape,
|
|
213
230
|
resolveSitianRecordPath,
|
|
214
231
|
resolveSitianRecordPathInLedger,
|
|
215
232
|
resolveSitianVolumeCategory
|
|
@@ -130,6 +130,7 @@ export default function roleRuntime(pi: ExtensionAPI): void {
|
|
|
130
130
|
loadCountersignSoul: () => loadMainRoleSessionMaterials("countersign"),
|
|
131
131
|
loadGleanerLeftSoul: () => loadMainRoleSessionMaterials("gleaner-left"),
|
|
132
132
|
loadDiaristSoul: () => loadMainRoleSessionMaterials("diarist"),
|
|
133
|
+
loadSecretariatSoul: () => loadMainRoleSessionMaterials("secretariat"),
|
|
133
134
|
loadInspectorSoul: () => loadMainRoleSessionMaterials("inspector"),
|
|
134
135
|
loadGatekeeperSoul: () => loadGatekeeperSessionMaterials("gatekeeper"),
|
|
135
136
|
loadNavigatorSoul: () => loadMainRoleSessionMaterials("navigator"),
|
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
中书省 Soul
|
|
2
|
+
你是中书省,出令省。调用者给你票,你交出可送庭的票面:送庭,封驳则改,改则再送,直到署或上呈。
|
|
3
|
+
立法与材料
|
|
4
|
+
|
|
5
|
+
* 第一法源:全局宪法、本仓宪法、本票起居录。
|
|
6
|
+
* 第二法源:适用 ADR,按票面触及的席位、接缝、术语自行查全,草稿引没引都算,逐条列决定;CONTEXT.md。
|
|
7
|
+
* 审查对象:派单文,票面、父票与相关票。
|
|
8
|
+
* 输出参考:《票面法》《质量法》、给事中与符宝郎 Soul。票面最终要过他们的审。
|
|
9
|
+
* 第二法源合法性:第二法源是否合法,违背第一法源,又没有陛下原话的;直接封驳,拿不准的,上呈,不准署
|
|
10
|
+
|
|
11
|
+
合法性检查
|
|
12
|
+
|
|
13
|
+
* 审查派单文、票面、父票与相关票。逐项对第一、第二法源:不得违法源,不得拿局部原话替整段意思,不得以第二法源反压第一法源。违法则封驳;拿不准且关系裁量的,上呈。
|
|
14
|
+
|
|
15
|
+
审票
|
|
16
|
+
|
|
17
|
+
* 该有的都有,不该有的都没有。法源要求的决定、边界、行为、验收均须落到票面,或明确由谁承接;无依据的设计、推演、夹带、越权内容不得写进票面。每一句只能是原话、可见行为、可跑验收或法源路径。
|
|
18
|
+
* 票面写下来的事,必须就是陛下要办的那件事。原话读整段,结合起居录、上下文与相关票判断真实意图;不得断章取义,也不得因“有一句话能对应”就视为正确。逐项检查目标、偏差、结果、边界与验收是否写对、有没有写偏、漏掉或扩大。能改则改票重送,不能自行裁定则上呈。
|
|
19
|
+
|
|
20
|
+
每次重交整张票重审,不沿用上庭结论。
|
|
21
|
+
判词
|
|
22
|
+
事实与处方分开对宪:裁决落法度与事实;施工设计与实现细节过早堆上票面即为失职。
|
|
23
|
+
|
|
24
|
+
* 署(converged)——自检无误,可以送下一个衙门;
|
|
25
|
+
* 封驳(continue)——存在必须退回重议的问题;写明缺什么、属哪一步;
|
|
26
|
+
* 上呈(escalate)——无法正常署/封驳时。上呈求助
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Type, type Static } from "typebox";
|
|
2
2
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
4
4
|
|
|
5
5
|
// #836 r16 class 3: execute() reads no params for this tool
|
|
6
6
|
// (src/collector-role.ts:431-459) — a closed root only rejects the role for
|
|
@@ -124,7 +124,7 @@ export const collectorOutputBaseSchema = openToolObject(
|
|
|
124
124
|
);
|
|
125
125
|
|
|
126
126
|
/** Runtime owns the observed evidence; the model submits findings and signals sole-final submission. */
|
|
127
|
-
export const collectorOutputArgsSchema =
|
|
127
|
+
export const collectorOutputArgsSchema = withTerminatingOutputDeclarations(
|
|
128
128
|
collectorOutputBaseSchema,
|
|
129
129
|
);
|
|
130
130
|
|
package/src/countersign-role.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Static } from "typebox";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
|
|
5
5
|
import {
|
|
6
6
|
COUNTERSIGN_OUTPUT_TOOL_NAME,
|
|
7
7
|
validateRecordedCountersignOutput,
|
|
@@ -22,7 +22,7 @@ export type { CountersignVerdict };
|
|
|
22
22
|
// classifies the recorded value and reasks the countersign itself when it
|
|
23
23
|
// isn't one of the three states — code, not the transport, does that work.
|
|
24
24
|
/** 给事中票庭审读五问的交卷形状(ADR 0074);形状指引,非 schema 闸。 */
|
|
25
|
-
export const countersignVerdictSchema =
|
|
25
|
+
export const countersignVerdictSchema = withTerminatingOutputDeclarations(
|
|
26
26
|
Type.Object(
|
|
27
27
|
{
|
|
28
28
|
countersignStatus: Type.Unknown({ description: "converged | continue | escalate。非三态时请重读后重交,勿改标。" }),
|
package/src/diarist-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
|
DIARIST_OUTPUT_TOOL_NAME,
|
|
8
8
|
validateRecordedDiaristOutput,
|
|
@@ -20,7 +20,7 @@ export { validateRecordedDiaristOutput };
|
|
|
20
20
|
* 起居郎交卷形状;形状指引,非 schema 闸。
|
|
21
21
|
* #901:交边界(sessions)+ 可选坏行补写(amendments);正文由机械投影。
|
|
22
22
|
*/
|
|
23
|
-
export const diaristOutputSchema =
|
|
23
|
+
export const diaristOutputSchema = withTerminatingOutputDeclarations(
|
|
24
24
|
openToolObject(
|
|
25
25
|
Type.Object({
|
|
26
26
|
status: Type.Unknown({
|
package/src/doctor-contracts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { canonicalJson } from "./canonical-json.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
|
export const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
|
|
7
7
|
export const DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
@@ -87,7 +87,7 @@ const doctorSubmissionVariants = Type.Union([
|
|
|
87
87
|
missingEvidence: Type.Array(Type.Object({ need: nonblank, targetKeys: evidenceIds }, { additionalProperties: true }), { description: "如实证词所需而尚缺的证据" }),
|
|
88
88
|
}, { additionalProperties: false, description: "证据不足以支撑如实案证词" }),
|
|
89
89
|
]);
|
|
90
|
-
export const doctorSubmissionSchema =
|
|
90
|
+
export const doctorSubmissionSchema = withTerminatingOutputDeclarations(
|
|
91
91
|
openToolObjectFromUnion(doctorSubmissionVariants),
|
|
92
92
|
);
|
|
93
93
|
// #836 r16 class 3: action tool — code reads evidenceId to look up the Map entry
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Engine process failures stop through the host infrastructure-failure seam.
|
|
6
6
|
* Caller AbortSignal cancellation propagates unchanged.
|
|
7
7
|
*/
|
|
8
|
-
import { basename } from "node:path";
|
|
9
8
|
import { Type, type Static } from "typebox";
|
|
10
9
|
import type { HostContext, HostToolDefinition, HostToolResult, RoleHost } from "./host-contracts.ts";
|
|
11
10
|
|
|
@@ -21,14 +20,9 @@ import {
|
|
|
21
20
|
engineDetourStdoutByteLength,
|
|
22
21
|
reportEngineDetourCall,
|
|
23
22
|
} from "./engine-detour-usage.ts";
|
|
23
|
+
import { runIdFromRunDirectory } from "./run-terminal-artifacts.ts";
|
|
24
|
+
|
|
24
25
|
|
|
25
|
-
/** runDirectory leaf is `<runId>@<role>`; subject is optional. */
|
|
26
|
-
function basenameRunId(runDirectory: string): string | undefined {
|
|
27
|
-
const leaf = basename(runDirectory);
|
|
28
|
-
const at = leaf.indexOf("@");
|
|
29
|
-
if (at <= 0) return undefined;
|
|
30
|
-
return leaf.slice(0, at);
|
|
31
|
-
}
|
|
32
26
|
|
|
33
27
|
// #836 r16 class 3: argv required/minItems/element-minLength stay — execute()
|
|
34
28
|
// must obtain the first item as the executable and spawn it (below; #82-98).
|
|
@@ -131,7 +125,7 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
131
125
|
const runDirectory = typeof ctx.runDirectory === "string" && ctx.runDirectory.length > 0
|
|
132
126
|
? ctx.runDirectory
|
|
133
127
|
: undefined;
|
|
134
|
-
const runId = runDirectory === undefined ? undefined :
|
|
128
|
+
const runId = runDirectory === undefined ? undefined : runIdFromRunDirectory(runDirectory);
|
|
135
129
|
// Public-invocation scope + selected host from Host envelope only — never
|
|
136
130
|
// courtAttemptId, never sidecar file, never pre-spawn invocation.json I/O.
|
|
137
131
|
const invocationScopeId =
|