@akagilnc/pi-workflow-roles 0.1.3280 → 0.1.3353
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 +5 -5
- package/README.zh-CN.md +5 -5
- package/dist/audit-escalation.js +31 -4
- package/dist/gatekeeper-role.js +25 -4
- package/dist/grok/production-host.js +1167 -862
- package/dist/inspector-contracts.js +5 -2
- package/dist/notary-contracts.js +16 -5
- package/dist/packaged-role-registry.js +0 -7
- package/dist/public-cli/main.js +867 -757
- package/package.json +1 -1
- package/src/audit-escalation.ts +52 -8
- package/src/collector-ledger.ts +309 -74
- package/src/collector-receipt.ts +0 -1
- package/src/collector-role.ts +21 -14
- package/src/diarist-mechanical.ts +16 -5
- package/src/gatekeeper-role.ts +33 -4
- package/src/grok/role-envelope.ts +68 -52
- package/src/inspector-contracts.ts +6 -3
- package/src/inspector-role.ts +5 -2
- package/src/notary-contracts.ts +20 -5
- package/src/notary-role.ts +2 -2
- package/src/packaged-role-registry.ts +0 -12
- package/src/public-cli/cli.ts +50 -125
- package/src/public-cli/coder-run.ts +5 -19
- package/src/public-cli/collector-run.ts +65 -21
- package/src/public-cli/countersign-run.ts +14 -40
- package/src/public-cli/doctor-run.ts +50 -6
- package/src/public-cli/fixer-run.ts +5 -19
- package/src/public-cli/gleaner-left-run.ts +14 -40
- package/src/public-cli/inspector-run.ts +51 -7
- package/src/public-cli/instruction-seat-run.ts +27 -0
- package/src/public-cli/judge-run.ts +11 -36
- package/src/public-cli/merger-run.ts +5 -19
- package/src/public-cli/notary-run.ts +54 -5
- package/src/public-cli/option-definitions.ts +3 -3
- package/src/public-cli/post-admission.ts +76 -0
- package/src/public-cli/reviewer-run.ts +5 -19
- package/src/public-cli/run-lifecycle.ts +342 -107
- package/src/public-cli/settlement.ts +134 -71
- package/src/role-runtime.ts +18 -1
- package/src/submission-ledger.ts +55 -5
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ ak-role judge --attach ./plan.md "Review this plan." > result.txt
|
|
|
38
38
|
|
|
39
39
|
Exit status reports lifecycle honesty, not business success: every lawful typed result (including `audit_escalation`) exits zero; a failure without a lawful result exits nonzero, and its Terminal carries the Error Artifact ref and original cause instead of a fabricated receipt.
|
|
40
40
|
|
|
41
|
-
`ak-role resume <runId> [message]` reopens that run under the **current seat table** for model / host / engine — the same resolution as starting a new leg (`--flag` → persistent seat → package default). Standard chain after a role `escalate`s: take the owner ruling and feed it back with `ak-role resume <runId> "<ruling>"` so the same run continues to a terminal.
|
|
41
|
+
`ak-role resume <runId> [message]` reopens that run under the **current seat table** for model / host / engine — the same resolution as starting a new leg (`--flag` → persistent seat → package default). Standard chain after a role `escalate`s: take the owner ruling and feed it back with `ak-role resume <runId> "<ruling>"` so the same run continues to a terminal. `[message]` applies only to seats that accept caller instruction: for those seats the optional `message` after `runId` is passed through unchanged as the continuation prompt (opaque: not parsed as flags); omit it to use the package resume envelope. Notary/符宝郎 must omit `message` and derives evidence from the existing source-run/dossier binding. Global `--model` / `--host` / `--engine` override the table for that resume only. On a real host switch (live seat host differs from the previous invocation host), prior native records of the previous host are delivered once as context to the target host; same-host resume does not re-inject. Each host writes only its native volume (Pi: `session/session.jsonl`, Grok: `runDirectory/grok-home`), with unified ledger entries recorded in 司天台 (Sitian). Whether to resume is the caller's decision: the command does not require a typed HTTP 429 or a `resumable` state. Unknown run IDs and missing session principals are rejected. Every callable role accepts manual resume; Countersign and Gleaner-Left gained it in #599, Collector, Doctor, Notary, and Inspector in #633.
|
|
42
42
|
|
|
43
43
|
Judge, coder, fixer, reviewer, and merger also retry a non-lawful LLM call in place (same `runId` and session) up to `autoResumeLimit` times. Unset defaults to 2; `ak-role config set-auto-resume-limit <N>` writes the ceiling (`0` disables). Lawful typed terminals (`accepted`, `audit_escalation`, `no_receipt`) stop immediately. Manual `ak-role resume` stays available.
|
|
44
44
|
|
|
@@ -90,23 +90,23 @@ ak-role coder apply --attach ./plan.md "Implement the approved slice."
|
|
|
90
90
|
# reviewer — fixed-target two-axis review; completed ≠ approved, read the findings
|
|
91
91
|
ak-role reviewer --base main "Review the branch."
|
|
92
92
|
|
|
93
|
-
# collector — GitHub PR review evidence
|
|
93
|
+
# collector — GitHub PR review evidence
|
|
94
94
|
ak-role collector --pr 42 --repo owner/repository
|
|
95
95
|
|
|
96
96
|
# fixer — repair the assigned findings
|
|
97
97
|
ak-role fixer --attach ./findings.md --prerequisites ./prereqs.json "Repair the findings."
|
|
98
98
|
|
|
99
|
-
# doctor — diagnose one retained case
|
|
99
|
+
# doctor — diagnose one retained case
|
|
100
100
|
ak-role doctor --issue 115 "Diagnose this retained case."
|
|
101
101
|
|
|
102
102
|
# merger — resolve one merge already in conflict (start it with Git's ort first)
|
|
103
103
|
ak-role merger --project /path/to/worktree "Reconcile the active merge."
|
|
104
104
|
|
|
105
|
-
# notary — document-fidelity check on one retained source run;
|
|
105
|
+
# notary — document-fidelity check on one retained source run; optional --ticket for court diary
|
|
106
106
|
ak-role notary --source-run <runId@role|path>
|
|
107
107
|
ak-role notary --source-run <runId@role|path> --ticket 582
|
|
108
108
|
|
|
109
|
-
# inspector — direct complexity and test-quality check
|
|
109
|
+
# inspector — direct complexity and test-quality check
|
|
110
110
|
ak-role inspector --attach ./change.patch "Review this material."
|
|
111
111
|
|
|
112
112
|
# gatekeeper — direct Gate province review; dispatch an officer or pass
|
package/README.zh-CN.md
CHANGED
|
@@ -38,7 +38,7 @@ ak-role judge --attach ./plan.md "Review this plan." > result.txt
|
|
|
38
38
|
|
|
39
39
|
退出码报的是生命周期诚实,不是业务成败:一切合法 typed 终态(含 `audit_escalation`)退出零;无合法终态的失败退出非零,其 Terminal 携带 Error Artifact 引用与原始原因,不伪造回执。
|
|
40
40
|
|
|
41
|
-
`ak-role resume <runId> [message]` 按**现行席位表**的 model / host / engine 续跑该次运行——与新起角色腿同一解析(调用旗 → 席位持久 → 包默认)。角色 `escalate`(直通御前)后拿到 owner 裁定,标准续跑是 `ak-role resume <runId> "<裁定>"`——把裁定喂回同一 run,角色继续走到终局。`runId` 后可选的 `message` 原样作为续跑 prompt(opaque:不进全局旗标语法);省略则用包自带 resume envelope
|
|
41
|
+
`ak-role resume <runId> [message]` 按**现行席位表**的 model / host / engine 续跑该次运行——与新起角色腿同一解析(调用旗 → 席位持久 → 包默认)。角色 `escalate`(直通御前)后拿到 owner 裁定,标准续跑是 `ak-role resume <runId> "<裁定>"`——把裁定喂回同一 run,角色继续走到终局。`[message]` 只适用于接收 caller instruction 的席位:对这些席位,`runId` 后可选的 `message` 原样作为续跑 prompt(opaque:不进全局旗标语法);省略则用包自带 resume envelope。Notary/符宝郎必须省略 `message`,仅从既有 source-run/案卷绑定自取证。全局 `--model` / `--host` / `--engine` 仅覆盖本次 resume。真实换宿主时(现行席位 host 与上一次 invocation host 不同),将前序宿主原生卷宗一次性作为 context 交付目标宿主;同宿主续跑不重复注入。各宿主仅直写自身原生卷宗(Pi:`session/session.jsonl`,Grok:`runDirectory/grok-home`),统一账目归入司天台。要不要续跑由调用者决定:不再要求 typed HTTP 429,也不要求 `resumable` 状态。未知 run ID、session 主体不在则拒绝。所有可调用角色均可手动 resume:给事中、左拾遗始于 #599,通进司、太医署、符宝郎、察院始于 #633。
|
|
42
42
|
|
|
43
43
|
大理寺、将作监、修内司、御史台、校书郎在单次调用内对非 lawful LLM 终态原地续跑(同一 `runId` 与 session),次数上限为 `autoResumeLimit`。缺键默认 2;`ak-role config set-auto-resume-limit <N>` 写入(`0` 关闭自动续)。lawful typed 终态(`accepted` / `audit_escalation` / `no_receipt`)立即停止。手动 `ak-role resume` 仍可用。
|
|
44
44
|
|
|
@@ -84,23 +84,23 @@ ak-role coder apply --attach ./plan.md "Implement the approved slice."
|
|
|
84
84
|
# 御史台——固定目标双轴察举;completed ≠ 准行,findings 在 Terminal 里
|
|
85
85
|
ak-role reviewer --base main "Review the branch."
|
|
86
86
|
|
|
87
|
-
# 通进司——GitHub PR
|
|
87
|
+
# 通进司——GitHub PR 收证
|
|
88
88
|
ak-role collector --pr 42 --repo owner/repository
|
|
89
89
|
|
|
90
90
|
# 修内司——缮修所指 findings
|
|
91
91
|
ak-role fixer --attach ./findings.md --prerequisites ./prereqs.json "Repair the findings."
|
|
92
92
|
|
|
93
|
-
#
|
|
93
|
+
# 太医署——单案诊断
|
|
94
94
|
ak-role doctor --issue 115 "Diagnose this retained case."
|
|
95
95
|
|
|
96
96
|
# 校书郎——调和已在冲突的 merge(先用 Git ort 起动)
|
|
97
97
|
ak-role merger --project /path/to/worktree "Reconcile the active merge."
|
|
98
98
|
|
|
99
|
-
# 符宝郎——文书核验一份留存 source run
|
|
99
|
+
# 符宝郎——文书核验一份留存 source run;可选 --ticket 调起居录
|
|
100
100
|
ak-role notary --source-run <runId@role|path>
|
|
101
101
|
ak-role notary --source-run <runId@role|path> --ticket 582
|
|
102
102
|
|
|
103
|
-
#
|
|
103
|
+
# 察院——直调复杂度与测试质量两轴
|
|
104
104
|
ak-role inspector --attach ./change.patch "Review this material."
|
|
105
105
|
|
|
106
106
|
# 门下省——直调省审:派官或放行
|
package/dist/audit-escalation.js
CHANGED
|
@@ -22,15 +22,29 @@ export function buildAuditEscalationResult(decision, deliveredOutput) {
|
|
|
22
22
|
if (Object.hasOwn(decision, "decisionGate")) {
|
|
23
23
|
auditOwned.auditDecisionGate = decision.decisionGate;
|
|
24
24
|
}
|
|
25
|
+
if (Object.hasOwn(decision, "reason") && decision.reason !== undefined) {
|
|
26
|
+
auditOwned.reason = decision.reason;
|
|
27
|
+
}
|
|
28
|
+
if (Object.hasOwn(decision, "officer") && decision.officer !== undefined) {
|
|
29
|
+
auditOwned.officer = decision.officer;
|
|
30
|
+
}
|
|
31
|
+
if (Object.hasOwn(decision, "findings") && decision.findings !== undefined) {
|
|
32
|
+
auditOwned.findings = decision.findings;
|
|
33
|
+
}
|
|
25
34
|
const deliveredFields = deliveredOutput !== undefined &&
|
|
26
35
|
deliveredOutput !== null &&
|
|
27
36
|
typeof deliveredOutput === "object" &&
|
|
28
37
|
!Array.isArray(deliveredOutput)
|
|
29
38
|
? { ...deliveredOutput }
|
|
30
39
|
: {};
|
|
31
|
-
// Role output cannot fill an absent audit-owned field.
|
|
40
|
+
// Role output cannot fill an absent audit/officer-owned field.
|
|
32
41
|
delete deliveredFields.conflicts;
|
|
33
42
|
delete deliveredFields.auditDecisionGate;
|
|
43
|
+
if (Object.hasOwn(decision, "officer")) {
|
|
44
|
+
delete deliveredFields.reason;
|
|
45
|
+
delete deliveredFields.officer;
|
|
46
|
+
delete deliveredFields.findings;
|
|
47
|
+
}
|
|
34
48
|
const result = {
|
|
35
49
|
...deliveredFields,
|
|
36
50
|
...auditOwned,
|
|
@@ -44,11 +58,24 @@ export function isAuditEscalationProjection(value) {
|
|
|
44
58
|
return false;
|
|
45
59
|
return AUDIT_ESCALATION_LIVE_REGISTRY.has(value);
|
|
46
60
|
}
|
|
47
|
-
function humanDecisionText(result) {
|
|
48
|
-
const
|
|
61
|
+
function humanDecisionText(decision, result) {
|
|
62
|
+
const officer = Object.hasOwn(decision, "officer")
|
|
63
|
+
? decision.officer
|
|
64
|
+
: undefined;
|
|
65
|
+
const lines = [
|
|
66
|
+
officer === undefined
|
|
67
|
+
? "Human decision required: compliance audit escalation."
|
|
68
|
+
: `Human decision required: ${officer} escalation.`,
|
|
69
|
+
];
|
|
70
|
+
if (officer !== undefined && typeof result.reason === "string") {
|
|
71
|
+
lines.push(`Reason: ${result.reason}`);
|
|
72
|
+
}
|
|
49
73
|
if (Array.isArray(result.conflicts)) {
|
|
50
74
|
lines.push("Conflicts:", ...result.conflicts.map((conflict) => `- ${conflict}`));
|
|
51
75
|
}
|
|
76
|
+
if (officer !== undefined && Array.isArray(result.findings) && result.findings.length > 0) {
|
|
77
|
+
lines.push("Findings:", ...result.findings.map((finding) => `- ${finding}`));
|
|
78
|
+
}
|
|
52
79
|
const gate = result.auditDecisionGate;
|
|
53
80
|
if (gate !== null && typeof gate === "object" && !Array.isArray(gate)) {
|
|
54
81
|
const record = gate;
|
|
@@ -63,7 +90,7 @@ function humanDecisionText(result) {
|
|
|
63
90
|
export function projectAuditEscalation(decision, deliveredOutput) {
|
|
64
91
|
const details = buildAuditEscalationResult(decision, deliveredOutput);
|
|
65
92
|
return {
|
|
66
|
-
content: [{ type: "text", text: humanDecisionText(details) }],
|
|
93
|
+
content: [{ type: "text", text: humanDecisionText(decision, details) }],
|
|
67
94
|
details,
|
|
68
95
|
terminate: true,
|
|
69
96
|
...(decision.usage === undefined ? {} : { usage: decision.usage }),
|
package/dist/gatekeeper-role.js
CHANGED
|
@@ -19,11 +19,20 @@ function gateSeatLabel(stage) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
export { GatekeeperDecisionError } from "./submission-errors.js";
|
|
22
|
+
export class GatekeeperEscalationError extends Error {
|
|
23
|
+
gatekeeper;
|
|
24
|
+
constructor(gatekeeper) {
|
|
25
|
+
super(`门下省${gateSeatLabel(gatekeeper.officer)}上呈`);
|
|
26
|
+
this.name = "GatekeeperEscalationError";
|
|
27
|
+
this.gatekeeper = gatekeeper;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
22
30
|
// Unknown fields so wrong types/spellings still reach projection (ADR 0055/0057; 仓第 0 条).
|
|
23
31
|
// Opening goes through the sole openToolObject owner — no parallel transport helper.
|
|
24
32
|
const officerDecisionSchema = openToolObject(Type.Object({
|
|
25
|
-
status: Type.Unknown({ description: "pass | bounce — 形状指引,非 schema 闸" }),
|
|
26
|
-
|
|
33
|
+
status: Type.Unknown({ description: "pass | bounce | escalate — 形状指引,非 schema 闸" }),
|
|
34
|
+
reason: Type.Optional(Type.Unknown({ description: "status 为 escalate 时的理由" })),
|
|
35
|
+
findings: Type.Unknown({ description: "string[] findings,随 pass、bounce 或 escalate 留存" }),
|
|
27
36
|
}));
|
|
28
37
|
/**
|
|
29
38
|
* Direct-seat decision tool spec (#639). Lifecycle assembly stays on the
|
|
@@ -52,7 +61,7 @@ function subjectTool(subject) {
|
|
|
52
61
|
export function createOfficerDecisionTool(name) {
|
|
53
62
|
return {
|
|
54
63
|
name,
|
|
55
|
-
description: "提交一份 typed pass/bounce 决议。",
|
|
64
|
+
description: "提交一份 typed pass/bounce/escalate 决议。",
|
|
56
65
|
parameters: officerDecisionSchema,
|
|
57
66
|
async execute(_id, args) { return result(`已收 ${String(args?.status)}`, args); },
|
|
58
67
|
};
|
|
@@ -101,7 +110,7 @@ function noUsableReleaseFailure(stage, decision) {
|
|
|
101
110
|
return {
|
|
102
111
|
status: "transport_failure",
|
|
103
112
|
stage,
|
|
104
|
-
reason: stage === "gatekeeper" ? "decision 无显式 dispatch" : "decision 无显式 pass/bounce",
|
|
113
|
+
reason: stage === "gatekeeper" ? "decision 无显式 dispatch" : "decision 无显式 pass/bounce/escalate",
|
|
105
114
|
submission: retainedSubmission(decision),
|
|
106
115
|
};
|
|
107
116
|
}
|
|
@@ -143,6 +152,15 @@ function projectOfficerDecision(officer, decision) {
|
|
|
143
152
|
findings: asStringArray(record.findings),
|
|
144
153
|
};
|
|
145
154
|
}
|
|
155
|
+
if (record.status === "escalate") {
|
|
156
|
+
return {
|
|
157
|
+
status: "escalate",
|
|
158
|
+
officer,
|
|
159
|
+
...(Object.hasOwn(record, "reason") ? { reason: record.reason } : {}),
|
|
160
|
+
findings: record.findings,
|
|
161
|
+
submission: retainedSubmission(decision),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
146
164
|
return noUsableReleaseFailure(officer, decision);
|
|
147
165
|
}
|
|
148
166
|
export async function runGatekeeper(options) {
|
|
@@ -212,6 +230,9 @@ export async function requireGatekeeperPass(options) {
|
|
|
212
230
|
error.submission = gatekeeper.submission;
|
|
213
231
|
options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
|
|
214
232
|
}
|
|
233
|
+
if (gatekeeper.status === "escalate") {
|
|
234
|
+
throw new GatekeeperEscalationError(gatekeeper);
|
|
235
|
+
}
|
|
215
236
|
// Envelope owns the execute→tool_result bridge; this module only projects + throws.
|
|
216
237
|
options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
|
|
217
238
|
throw new GatekeeperDecisionError(gatekeeper);
|