@akagilnc/pi-workflow-roles 0.1.3932 → 0.1.3975

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.
Files changed (162) hide show
  1. package/CLAUDE.md +1 -1
  2. package/dist/acp-host/production-host.js +2389 -6018
  3. package/dist/analyst-gate-cycles-read.js +15 -19
  4. package/dist/audit-escalation.js +16 -46
  5. package/dist/auditor-dossier-tool.js +7 -62
  6. package/dist/collector-identity.js +0 -157
  7. package/dist/collector-ledger.js +2 -42
  8. package/dist/compliance-transport.js +40 -14
  9. package/dist/diarist-contracts.js +2 -40
  10. package/dist/doctor-contracts.js +39 -108
  11. package/dist/doctor-evidence.js +1 -5
  12. package/dist/engine-detour-tool.js +1 -1
  13. package/dist/gatekeeper-role.js +49 -38
  14. package/dist/headless-host/production-host.js +4814 -8450
  15. package/dist/host-contracts.js +0 -5
  16. package/dist/merger-contracts.js +4 -6
  17. package/dist/navigator-attendance.js +30 -52
  18. package/dist/navigator-invocation-identity.js +0 -1
  19. package/dist/navigator-public-session.js +2 -1
  20. package/dist/notary-contracts.js +4 -10
  21. package/dist/package-contracts/auditor-output.js +5 -23
  22. package/dist/package-contracts/fixer-output.js +25 -49
  23. package/dist/package-contracts/gatekeeper-output.js +3 -13
  24. package/dist/package-contracts/navigator-output.js +4 -7
  25. package/dist/package-contracts/reviewer-output.js +1 -95
  26. package/dist/package-contracts/terminating-tools.js +33 -144
  27. package/dist/package-contracts/worker-output.js +1 -3
  28. package/dist/public-cli/auto-resume.js +30 -68
  29. package/dist/public-cli/case-dossier-delivery.js +5 -17
  30. package/dist/public-cli/diarist-run.js +9 -4
  31. package/dist/public-cli/inspector-run.js +2 -8
  32. package/dist/public-cli/instruction-seat-run.js +3 -7
  33. package/dist/public-cli/invocation.js +5 -2
  34. package/dist/public-cli/main.js +6068 -6964
  35. package/dist/public-cli/notary-run.js +1 -8
  36. package/dist/public-cli/post-admission.js +314 -113
  37. package/dist/public-cli/run-lifecycle.js +14 -38
  38. package/dist/public-cli/settlement.js +209 -390
  39. package/dist/public-cli/terminal.js +51 -45
  40. package/dist/public-role-summons.js +1 -12
  41. package/dist/reviewer-dispatch.js +12 -258
  42. package/dist/submission-correctable-error.js +0 -12
  43. package/dist/submission-errors.js +6 -1
  44. package/dist/submission-ledger.js +125 -168
  45. package/dist/ticket-provenance-contracts.js +2 -49
  46. package/dist/ticket-provenance.js +82 -31
  47. package/extensions/role-runtime.ts +1 -6
  48. package/package.json +1 -1
  49. package/resources/836-deleted-machine-instruction-inventory.md +18 -0
  50. package/src/acp-host/role-turn-host.ts +8 -3
  51. package/src/analyst-gate-cycles-read.ts +17 -29
  52. package/src/audit-escalation.ts +20 -50
  53. package/src/auditor-dossier-tool.ts +5 -103
  54. package/src/canonical-skill-binding.ts +3 -2
  55. package/src/collector-identity.ts +0 -179
  56. package/src/collector-ledger.ts +3 -46
  57. package/src/collector-role.ts +32 -61
  58. package/src/collector-tool-schemas.ts +20 -14
  59. package/src/compliance-transport.ts +55 -17
  60. package/src/countersign-role.ts +17 -8
  61. package/src/diarist-contracts.ts +3 -36
  62. package/src/diarist-role.ts +13 -7
  63. package/src/diarist.ts +4 -16
  64. package/src/doctor-contracts.ts +73 -94
  65. package/src/doctor-evidence.ts +1 -1
  66. package/src/doctor-role.ts +3 -3
  67. package/src/engine-detour-tool.ts +4 -1
  68. package/src/external-host-turn-loop.ts +9 -3
  69. package/src/gatekeeper-pass-envelope.ts +7 -12
  70. package/src/gatekeeper-role.ts +56 -50
  71. package/src/gleaner-left-role.ts +4 -2
  72. package/src/headless-host/role-turn-host.ts +4 -5
  73. package/src/host-contracts.ts +3 -8
  74. package/src/judge-role.ts +19 -13
  75. package/src/merger-contracts.ts +10 -6
  76. package/src/merger-role.ts +1 -5
  77. package/src/navigator-attendance.ts +37 -74
  78. package/src/navigator-invocation-identity.ts +0 -6
  79. package/src/navigator-public-session.ts +2 -1
  80. package/src/notary-contracts.ts +7 -10
  81. package/src/package-contracts/auditor-output.ts +4 -21
  82. package/src/package-contracts/fixer-output.ts +34 -52
  83. package/src/package-contracts/gatekeeper-output.ts +5 -22
  84. package/src/package-contracts/navigator-output.ts +7 -7
  85. package/src/package-contracts/reviewer-output.ts +2 -150
  86. package/src/package-contracts/terminating-tools.ts +32 -147
  87. package/src/package-contracts/worker-output.ts +0 -1
  88. package/src/pi/adapter.ts +3 -8
  89. package/src/public-cli/auto-resume.ts +41 -94
  90. package/src/public-cli/case-dossier-delivery.ts +5 -15
  91. package/src/public-cli/countersign-run.ts +14 -6
  92. package/src/public-cli/diarist-run.ts +11 -9
  93. package/src/public-cli/inspector-run.ts +2 -18
  94. package/src/public-cli/instruction-seat-run.ts +3 -17
  95. package/src/public-cli/invocation.ts +5 -2
  96. package/src/public-cli/merger-run.ts +1 -1
  97. package/src/public-cli/notary-run.ts +1 -18
  98. package/src/public-cli/post-admission.ts +385 -115
  99. package/src/public-cli/run-lifecycle.ts +13 -44
  100. package/src/public-cli/settlement.ts +314 -562
  101. package/src/public-cli/terminal.ts +66 -72
  102. package/src/public-role-summons.ts +5 -30
  103. package/src/reviewer-dispatch.ts +29 -331
  104. package/src/reviewer-role.ts +16 -83
  105. package/src/role-envelope.ts +16 -24
  106. package/src/role-runtime-dependencies.ts +1 -6
  107. package/src/role-runtime.ts +65 -201
  108. package/src/submission-correctable-error.ts +0 -14
  109. package/src/submission-errors.ts +6 -1
  110. package/src/submission-ledger.ts +187 -187
  111. package/src/ticket-provenance-contracts.ts +4 -60
  112. package/src/ticket-provenance.ts +98 -32
  113. package/src/worker-role.ts +35 -36
  114. package/dist/activation-ledger-session.js +0 -105
  115. package/dist/activation-ledger.js +0 -139
  116. package/dist/activation-trace.js +0 -33
  117. package/dist/atomic-write.js +0 -23
  118. package/dist/auditor-role.js +0 -12
  119. package/dist/canonical-skill-binding.js +0 -61
  120. package/dist/collector-handbook.js +0 -142
  121. package/dist/collector-receipt.js +0 -107
  122. package/dist/collector-role.js +0 -566
  123. package/dist/collector-tool-schemas.js +0 -107
  124. package/dist/countersign-role.js +0 -28
  125. package/dist/diarist-role.js +0 -44
  126. package/dist/diarist.js +0 -66
  127. package/dist/doctor-role.js +0 -75
  128. package/dist/fixer-bash-seatbelt.js +0 -13
  129. package/dist/gatekeeper-pass-envelope.js +0 -77
  130. package/dist/gleaner-left-role.js +0 -26
  131. package/dist/inspector-role.js +0 -29
  132. package/dist/judge-role.js +0 -104
  133. package/dist/merger-role.js +0 -55
  134. package/dist/navigator-role.js +0 -12
  135. package/dist/notary-role.js +0 -134
  136. package/dist/oauth-keepalive.js +0 -158
  137. package/dist/pi/adapter.js +0 -223
  138. package/dist/reviewer-agent.js +0 -122
  139. package/dist/reviewer-child-executor.js +0 -194
  140. package/dist/reviewer-construction.js +0 -103
  141. package/dist/reviewer-execution-ledger.js +0 -166
  142. package/dist/reviewer-failure-diagnostic.js +0 -17
  143. package/dist/reviewer-role.js +0 -159
  144. package/dist/reviewer-scope-prompt.js +0 -21
  145. package/dist/reviewer-settlement.js +0 -66
  146. package/dist/reviewer-workspace.js +0 -132
  147. package/dist/role-runtime.js +0 -1604
  148. package/dist/stderr-jsonl.js +0 -26
  149. package/dist/tool-execution-observation.js +0 -141
  150. package/dist/worker-role.js +0 -345
  151. package/dist/worker-submission-gates.js +0 -305
  152. package/src/collector-receipt.ts +0 -140
  153. package/src/diagnostic-tail.ts +0 -18
  154. package/src/reviewer-agent.ts +0 -135
  155. package/src/reviewer-child-executor.ts +0 -252
  156. package/src/reviewer-construction.ts +0 -195
  157. package/src/reviewer-execution-ledger.ts +0 -212
  158. package/src/reviewer-failure-diagnostic.ts +0 -18
  159. package/src/reviewer-scope-prompt.ts +0 -24
  160. package/src/reviewer-settlement.ts +0 -74
  161. package/src/reviewer-workspace.ts +0 -105
  162. package/src/shape-unreadable-failure.ts +0 -49
@@ -1,26 +0,0 @@
1
- import { writeSync } from "node:fs";
2
- const STDERR_JSONL_WRITE_RETRY_LIMIT = 100;
3
- /**
4
- * Write one complete JSONL record to fd 2.
5
- * Retries EAGAIN/EINTR and short writes; never writes stdout.
6
- */
7
- export function writeStderrJsonlRecord(record, write = writeSync) {
8
- const bytes = Buffer.from(`${JSON.stringify(record)}\n`);
9
- let offset = 0;
10
- let retries = 0;
11
- while (offset < bytes.length) {
12
- try {
13
- const written = write(2, bytes, offset, bytes.length - offset);
14
- if (written <= 0)
15
- throw new Error("stderr JSONL write made no progress");
16
- offset += written;
17
- retries = 0;
18
- }
19
- catch (error) {
20
- const code = error.code;
21
- if ((code === "EAGAIN" || code === "EINTR") && retries++ < STDERR_JSONL_WRITE_RETRY_LIMIT)
22
- continue;
23
- throw error;
24
- }
25
- }
26
- }
@@ -1,141 +0,0 @@
1
- import { writeSync } from "node:fs";
2
- import { Type } from "typebox";
3
- import { Value } from "typebox/value";
4
- import { writeStderrJsonlRecord } from "./stderr-jsonl.js";
5
- /** Mandatory coalesce window for tool_execution_update heartbeats (stderr is bounded). */
6
- export const TOOL_EXECUTION_UPDATE_THROTTLE_MS = 30_000;
7
- /**
8
- * Heartbeat basis for downstream silence predicates.
9
- *
10
- * Production Pi `bash.js` calls `onUpdate` once with empty content at execute entry,
11
- * then schedules output-driven updates at ~100 ms. This face skips non-producing
12
- * (empty-content) updates so the first heartbeat is real child output, then
13
- * coalesces at {@link TOOL_EXECUTION_UPDATE_THROTTLE_MS}.
14
- *
15
- * If a future host path stopped delivering output-driven updates, change this to
16
- * `"duration-only"` and document that silence predicates degrade to pure duration.
17
- */
18
- export const TOOL_EXECUTION_UPDATE_HEARTBEAT = "output-driven";
19
- const observationBase = {
20
- role: Type.String({ minLength: 1 }),
21
- toolCallId: Type.String({ minLength: 1 }),
22
- toolName: Type.String({ minLength: 1 }),
23
- timestamp: Type.String({ format: "date-time" }),
24
- };
25
- export const toolExecutionObservationRecordSchema = Type.Union([
26
- Type.Object({
27
- ...observationBase,
28
- event: Type.Literal("tool_execution_start"),
29
- }, { additionalProperties: true }),
30
- Type.Object({
31
- ...observationBase,
32
- event: Type.Literal("tool_execution_update"),
33
- }, { additionalProperties: true }),
34
- Type.Object({
35
- ...observationBase,
36
- event: Type.Literal("tool_execution_end"),
37
- isError: Type.Boolean(),
38
- }, { additionalProperties: true }),
39
- ]);
40
- export function validateToolExecutionObservationRecord(record) {
41
- if (!Value.Check(toolExecutionObservationRecordSchema, record)) {
42
- throw new TypeError("Tool execution observation record does not match its contract");
43
- }
44
- return record;
45
- }
46
- export function writeToolExecutionObservationRecord(record, write = writeSync) {
47
- writeStderrJsonlRecord(validateToolExecutionObservationRecord(record), write);
48
- }
49
- /** True when a tool_execution_update partialResult carries producing content (not bash's empty entry callback). */
50
- export function isProducingToolUpdate(partialResult) {
51
- if (partialResult == null)
52
- return false;
53
- if (typeof partialResult !== "object")
54
- return true;
55
- const content = partialResult.content;
56
- if (!Array.isArray(content))
57
- return true;
58
- if (content.length === 0)
59
- return false;
60
- return content.some((part) => {
61
- if (typeof part !== "object" || part === null)
62
- return true;
63
- const text = part.text;
64
- if (typeof text === "string")
65
- return text.length > 0;
66
- return true;
67
- });
68
- }
69
- /**
70
- * Production throttle clock: genuinely monotonic milliseconds.
71
- * Wall-clock Date.now() is not safe — NTP/slew can compress two heartbeats under 30s.
72
- */
73
- export function systemToolExecutionObservationMonoNow() {
74
- return performance.now();
75
- }
76
- export function createToolExecutionObservationFace(options) {
77
- const states = new Map();
78
- async function emit(record) {
79
- await options.write(validateToolExecutionObservationRecord(record));
80
- }
81
- function activeRole() {
82
- if (!options.admitted())
83
- return undefined;
84
- const role = options.role();
85
- return role === undefined || role === "" ? undefined : role;
86
- }
87
- return {
88
- reset() {
89
- states.clear();
90
- },
91
- async onStart(event) {
92
- const role = activeRole();
93
- if (role === undefined)
94
- return;
95
- states.set(event.toolCallId, { lastUpdateEmitMonoMs: undefined });
96
- await emit({
97
- event: "tool_execution_start",
98
- role,
99
- toolCallId: event.toolCallId,
100
- toolName: event.toolName,
101
- timestamp: options.clock(),
102
- });
103
- },
104
- async onUpdate(event) {
105
- const role = activeRole();
106
- if (role === undefined)
107
- return;
108
- if (!isProducingToolUpdate(event.partialResult))
109
- return;
110
- const now = options.monoNow();
111
- const state = states.get(event.toolCallId) ?? { lastUpdateEmitMonoMs: undefined };
112
- if (state.lastUpdateEmitMonoMs !== undefined
113
- && now - state.lastUpdateEmitMonoMs < TOOL_EXECUTION_UPDATE_THROTTLE_MS) {
114
- return;
115
- }
116
- state.lastUpdateEmitMonoMs = now;
117
- states.set(event.toolCallId, state);
118
- await emit({
119
- event: "tool_execution_update",
120
- role,
121
- toolCallId: event.toolCallId,
122
- toolName: event.toolName,
123
- timestamp: options.clock(),
124
- });
125
- },
126
- async onEnd(event) {
127
- const role = activeRole();
128
- if (role === undefined)
129
- return;
130
- states.delete(event.toolCallId);
131
- await emit({
132
- event: "tool_execution_end",
133
- role,
134
- toolCallId: event.toolCallId,
135
- toolName: event.toolName,
136
- timestamp: options.clock(),
137
- isError: event.isError,
138
- });
139
- },
140
- };
141
- }
@@ -1,345 +0,0 @@
1
- import { stringEnum } from "./host-contracts.js";
2
- import { Type } from "typebox";
3
- import { openToolObjectFromUnion } from "./open-tool-schema.js";
4
- import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.js";
5
- import { CorrectableSubmissionError } from "./submission-correctable-error.js";
6
- import { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, validateAcceptedWorkerDetails, } from "./package-contracts/worker-output.js";
7
- import { fixerOutputSchema, validateFixerOutput, validateFixerOutputForPacket } from "./package-contracts/fixer-output.js";
8
- import { FixerPacketValidationError, parseFixerPrerequisites, } from "./package-contracts/fixer-packet.js";
9
- import { createWorkerSubmissionGate, WORKER_DONE_STATUSES, WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError, } from "./worker-submission-gates.js";
10
- import { fixerBashSeatbeltDenyReason, matchFixerBashForbiddenLiteral, } from "./fixer-bash-seatbelt.js";
11
- export { CODER_OUTPUT_TOOL_NAME, FIXER_OUTPUT_TOOL_NAME, validateAcceptedWorkerDetails, };
12
- const coderOutputVariants = Type.Union([
13
- Type.Object({
14
- status: stringEnum(["planned"], { description: "planned — 形状指引,非 schema 闸" }),
15
- report: Type.String({ minLength: 1, description: "如实结果报告" }),
16
- }, { additionalProperties: false }),
17
- Type.Object({
18
- status: stringEnum(["completed", "refused"], {
19
- description: "completed | refused — 形状指引,非 schema 闸;completed 回执含 TDD、同模式、引入回归、行为事实四项证据",
20
- }),
21
- report: Type.String({ minLength: 1, description: "如实结果报告" }),
22
- }, { additionalProperties: false }),
23
- Type.Object({
24
- status: stringEnum(["unfinished"], {
25
- description: "unfinished — 形状指引,非 schema 闸;缺前置或违宪约束致本局未完成时可用。缺待决 owner 决定或答复属缺前置。",
26
- }),
27
- report: Type.String({ minLength: 1, description: "如实结果报告" }),
28
- remainingScope: Type.String({ minLength: 1, description: "本局后剩余工作" }),
29
- reason: Type.Optional(Type.String({
30
- minLength: 1,
31
- description: "阻断原因:缺前置或违宪约束。缺待决 owner 决定或答复属缺前置。",
32
- })),
33
- }, { additionalProperties: false }),
34
- ]);
35
- export const coderOutputSchema = withInfrastructureFailureDeclaration(openToolObjectFromUnion(coderOutputVariants));
36
- export const FIXER_FLAG_DEFINITIONS = {
37
- packet: {
38
- name: "ak-fix-packet",
39
- definition: {
40
- description: "Path to opaque prose instructions for the Fixer",
41
- type: "string",
42
- },
43
- },
44
- prerequisites: {
45
- name: "ak-fixer-prerequisites",
46
- definition: {
47
- description: "Optional path to a JSON array of typed Fixer prerequisites",
48
- type: "string",
49
- },
50
- },
51
- phase: {
52
- name: "ak-fixer-phase",
53
- definition: {
54
- description: "Fixer phase: plan (inspect and propose a repair plan; no edits or commits) or apply (execute the approved plan, verify, and commit when repaired)",
55
- type: "string",
56
- },
57
- },
58
- };
59
- export const FIXER_PHASES = ["plan", "apply"];
60
- function isWorkerPhase(value) {
61
- return typeof value === "string" && FIXER_PHASES.includes(value);
62
- }
63
- /** Stable code for completed apply without host skill-expansion capability evidence (#525). */
64
- export const CODER_SKILL_EXPANSION_EVIDENCE_MISSING_CODE = "coder_skill_expansion_evidence_missing";
65
- /** Correct completed rejection — not infrastructure; projected via submission non-pass bridge. */
66
- export class CoderSkillExpansionEvidenceMissingError extends CorrectableSubmissionError {
67
- code = CODER_SKILL_EXPANSION_EVIDENCE_MISSING_CODE;
68
- result;
69
- constructor() {
70
- super("Coder completed requires host skill-expansion capability evidence");
71
- this.name = "CoderSkillExpansionEvidenceMissingError";
72
- this.result = Object.freeze({ code: CODER_SKILL_EXPANSION_EVIDENCE_MISSING_CODE });
73
- }
74
- }
75
- function isRecord(value) {
76
- return typeof value === "object" && value !== null && !Array.isArray(value);
77
- }
78
- function deepFreeze(value) {
79
- if (typeof value !== "object" || value === null || Object.isFrozen(value))
80
- return value;
81
- for (const child of Object.values(value))
82
- deepFreeze(child);
83
- return Object.freeze(value);
84
- }
85
- export function validateWorkerOutput(output, phase, roleLabel) {
86
- if (roleLabel === "Fixer")
87
- return validateFixerOutput(output, phase);
88
- return validateAcceptedWorkerDetails(output, "Coder");
89
- }
90
- /** Reminder bounces stay typed rejects; IO/infrastructure keep identity via host failInfrastructure. */
91
- function assertAcceptableThroughHost(submissionGate, status, details, hostActions, ctx, toolCallId) {
92
- try {
93
- submissionGate.assertAcceptable(status, details);
94
- }
95
- catch (error) {
96
- if (error instanceof WorkerCommitReminderError ||
97
- error instanceof WorkerPrefixReminderError ||
98
- error instanceof WorkerUnfinishedReasonReminderError) {
99
- throw error;
100
- }
101
- hostActions.failInfrastructure(error, ctx, toolCallId);
102
- }
103
- }
104
- export function createFixerRoleRuntime(pi, dependencies, hostActions) {
105
- let soul;
106
- let packet;
107
- let packetPath;
108
- let prerequisitesPath;
109
- let phase;
110
- let lifecycleRegistered = false;
111
- const submissionGate = createWorkerSubmissionGate();
112
- pi.registerFlag(FIXER_FLAG_DEFINITIONS.packet.name, FIXER_FLAG_DEFINITIONS.packet.definition);
113
- pi.registerFlag(FIXER_FLAG_DEFINITIONS.prerequisites.name, FIXER_FLAG_DEFINITIONS.prerequisites.definition);
114
- pi.registerFlag(FIXER_FLAG_DEFINITIONS.phase.name, FIXER_FLAG_DEFINITIONS.phase.definition);
115
- return {
116
- async activate() {
117
- soul = (await dependencies.loadSoul()).trim();
118
- if (soul.length === 0)
119
- throw new Error("Fixer soul is empty");
120
- const selectedPhase = pi.getFlag(FIXER_FLAG_DEFINITIONS.phase.name);
121
- if (!isWorkerPhase(selectedPhase)) {
122
- throw new Error("Fixer role requires --ak-fixer-phase plan|apply; no other phase is supported");
123
- }
124
- phase = selectedPhase;
125
- const resolvedPacketPath = pi.getFlag(FIXER_FLAG_DEFINITIONS.packet.name);
126
- if (typeof resolvedPacketPath !== "string" || resolvedPacketPath.trim().length === 0) {
127
- throw new Error("Fixer role requires --ak-fix-packet");
128
- }
129
- packetPath = resolvedPacketPath;
130
- const instructions = await dependencies.loadPacket(packetPath);
131
- if (instructions.trim().length === 0) {
132
- throw new FixerPacketValidationError(new Error("Fixer instructions must be nonblank"));
133
- }
134
- const resolvedPrerequisitesPath = pi.getFlag(FIXER_FLAG_DEFINITIONS.prerequisites.name);
135
- if (resolvedPrerequisitesPath !== undefined && (typeof resolvedPrerequisitesPath !== "string" || resolvedPrerequisitesPath.trim().length === 0)) {
136
- throw new Error("Fixer --ak-fixer-prerequisites path must be nonblank when supplied");
137
- }
138
- prerequisitesPath =
139
- typeof resolvedPrerequisitesPath === "string" ? resolvedPrerequisitesPath : undefined;
140
- const prerequisites = prerequisitesPath !== undefined
141
- ? parseFixerPrerequisites(await dependencies.loadPacket(prerequisitesPath))
142
- : Object.freeze([]);
143
- packet = Object.freeze({ instructions, prerequisites });
144
- if (!lifecycleRegistered) {
145
- lifecycleRegistered = true;
146
- pi.registerTool({
147
- name: FIXER_OUTPUT_TOOL_NAME,
148
- label: "修内司输出",
149
- description: "提交修内司终局回执;基础设施失败走 abort,不经本工具。",
150
- promptSnippet: "提交修内司终局回执",
151
- parameters: fixerOutputSchema,
152
- async execute(toolCallId, parameters, _signal, _onUpdate, ctx) {
153
- if (packet === undefined || phase === undefined) {
154
- throw new Error("修内司修理包与阶段未装载");
155
- }
156
- const output = deepFreeze(validateFixerOutputForPacket(parameters, phase, packet));
157
- assertAcceptableThroughHost(submissionGate, output.status, output, hostActions, ctx, toolCallId);
158
- if (WORKER_DONE_STATUSES.has(output.status)) {
159
- await pi.requireGatekeeperPass({
160
- context: ctx,
161
- subject: { kind: "worker_completion" },
162
- ...(_signal === undefined ? {} : { signal: _signal }),
163
- hostActions,
164
- toolCallId,
165
- });
166
- }
167
- const acceptedDetails = output;
168
- return {
169
- content: [{ type: "text", text: FIXER_ACCEPTED_TEXT }],
170
- details: acceptedDetails,
171
- terminate: true,
172
- };
173
- },
174
- });
175
- pi.on("tool_call", (event) => {
176
- if (event.toolName !== "bash")
177
- return;
178
- const command = event.input["command"];
179
- if (typeof command !== "string")
180
- return;
181
- const matched = matchFixerBashForbiddenLiteral(command);
182
- if (matched === undefined)
183
- return;
184
- return {
185
- block: true,
186
- reason: fixerBashSeatbeltDenyReason(matched),
187
- };
188
- });
189
- pi.on("before_agent_start", (event) => {
190
- if (soul === undefined)
191
- throw new Error("修内司职分未装载");
192
- if (packetPath === undefined)
193
- throw new Error("修内司修理包路径未装载");
194
- // Path delivery only — body is self-fetched; no inline duplicate of flag bytes (#632).
195
- const prerequisitesBlock = prerequisitesPath === undefined
196
- ? ""
197
- : `\n\n<fixer_prerequisites_path>\n${prerequisitesPath}\n</fixer_prerequisites_path>`;
198
- return {
199
- systemPrompt: `${event.systemPrompt}\n\n<fixer_soul>\n${soul}\n</fixer_soul>\n\n<fixer_phase>\n${phase ?? ""}\n</fixer_phase>\n\n<fix_packet_path>\n${packetPath}\n</fix_packet_path>${prerequisitesBlock}`,
200
- };
201
- });
202
- }
203
- },
204
- armSubmissionGate(cwd, parent) {
205
- submissionGate.arm(cwd, parent);
206
- },
207
- };
208
- }
209
- export function createCoderRoleRuntime(pi, dependencies, hostActions) {
210
- let soul;
211
- let task;
212
- let phase;
213
- let binding;
214
- let tddInvocationInjected = false;
215
- let originalRequest;
216
- let expansionPending = false;
217
- let expansionCaptured = false;
218
- let lifecycleRegistered = false;
219
- const submissionGate = createWorkerSubmissionGate();
220
- pi.registerFlag("ak-coder-task", {
221
- description: "Markdown task assigned to the coder role",
222
- type: "string",
223
- });
224
- pi.registerFlag("ak-coder-phase", {
225
- description: "Coder phase: plan (inspect and propose an implementation plan; no edits or commits) or apply (execute the approved plan and verify the first implementation)",
226
- type: "string",
227
- });
228
- return {
229
- async activate(ctx) {
230
- // Each activation owns its own Skill capture state; prior-session flags must
231
- // not authorize a later apply completed (same RoleHost, sequential activate).
232
- tddInvocationInjected = false;
233
- originalRequest = undefined;
234
- expansionPending = false;
235
- expansionCaptured = false;
236
- soul = (await dependencies.loadSoul()).trim();
237
- if (soul.length === 0)
238
- throw new Error("Coder soul is empty");
239
- const selectedPhase = pi.getFlag("ak-coder-phase");
240
- if (selectedPhase !== "plan" && selectedPhase !== "apply") {
241
- throw new Error("Coder role requires --ak-coder-phase plan|apply; no other phase is supported");
242
- }
243
- phase = selectedPhase;
244
- const taskPath = pi.getFlag("ak-coder-task");
245
- if (typeof taskPath !== "string" || taskPath.trim().length === 0) {
246
- throw new Error("Coder role requires --ak-coder-task");
247
- }
248
- task = (await dependencies.loadTask(taskPath)).trim();
249
- if (task.length === 0)
250
- throw new Error("Coder task is empty");
251
- binding = undefined;
252
- if (phase === "apply") {
253
- if (dependencies.loadCanonicalSkillBinding === undefined) {
254
- throw new Error("Coder canonical Skill binding loader is not configured");
255
- }
256
- try {
257
- const loaded = await dependencies.loadCanonicalSkillBinding("tdd");
258
- if (loaded.name !== "tdd") {
259
- throw new Error("Canonical Skill binding loader returned code-review for tdd");
260
- }
261
- binding = loaded;
262
- }
263
- catch (error) {
264
- if (ctx === undefined)
265
- throw error;
266
- hostActions.failInfrastructure(error, ctx);
267
- }
268
- }
269
- if (!lifecycleRegistered) {
270
- lifecycleRegistered = true;
271
- pi.registerTool({
272
- name: CODER_OUTPUT_TOOL_NAME,
273
- label: "将作监输出",
274
- description: "提交将作监终局回执;本工具无 escalate 通道。",
275
- promptSnippet: "提交将作监终局回执",
276
- parameters: coderOutputSchema,
277
- async execute(toolCallId, parameters, _signal, _onUpdate, ctx) {
278
- if (task === undefined || phase === undefined) {
279
- throw new Error("将作监任务与阶段未装载");
280
- }
281
- const output = validateWorkerOutput(parameters, phase, "Coder");
282
- if (phase === "apply" && output.status === "completed" &&
283
- !expansionCaptured) {
284
- const rejection = new CoderSkillExpansionEvidenceMissingError();
285
- hostActions.bindSubmissionNonPass(toolCallId, rejection.result);
286
- throw rejection;
287
- }
288
- assertAcceptableThroughHost(submissionGate, output.status, output, hostActions, ctx, toolCallId);
289
- if (WORKER_DONE_STATUSES.has(output.status)) {
290
- await pi.requireGatekeeperPass({
291
- context: ctx,
292
- subject: { kind: "worker_completion" },
293
- ...(_signal === undefined ? {} : { signal: _signal }),
294
- hostActions,
295
- toolCallId,
296
- });
297
- }
298
- const acceptedDetails = output;
299
- return {
300
- content: [{ type: "text", text: CODER_ACCEPTED_TEXT }],
301
- details: acceptedDetails,
302
- terminate: true,
303
- };
304
- },
305
- });
306
- pi.on("input", (event) => {
307
- if (phase !== "apply" || tddInvocationInjected) {
308
- return { action: "continue" };
309
- }
310
- tddInvocationInjected = true;
311
- expansionPending = true;
312
- // Original request via host capability when Pi argv already carries native form;
313
- // non-pi keeps plain original bytes (no consumer trim; #822 r3 / reviewer-aligned).
314
- // Role never emits or parses `/skill:` (ADR 0082).
315
- originalRequest = binding === undefined
316
- ? event.text
317
- : (pi.capabilities?.skillOriginalRequest?.(binding.name, event.text)
318
- ?? event.text);
319
- return { action: "continue" };
320
- });
321
- pi.on("before_agent_start", (event, ctx) => {
322
- if (soul === undefined)
323
- throw new Error("将作监职分未装载");
324
- if (phase === "apply") {
325
- if (binding === undefined) {
326
- hostActions.failInfrastructure(new Error("Coder canonical tdd Skill binding was not initialized"), ctx);
327
- }
328
- if (expansionPending) {
329
- expansionPending = false;
330
- if (originalRequest !== undefined) {
331
- expansionCaptured = binding.captureExpansion(pi.capabilities?.skillExpansion(event.prompt), originalRequest) !== undefined;
332
- }
333
- }
334
- }
335
- return {
336
- systemPrompt: `${event.systemPrompt}\n\n<coder_soul>\n${soul}\n</coder_soul>\n\n<coder_phase>\n${phase ?? ""}\n</coder_phase>\n\n<coder_task>\n${task ?? ""}\n</coder_task>`,
337
- };
338
- });
339
- }
340
- },
341
- armSubmissionGate(cwd, parent) {
342
- submissionGate.arm(cwd, parent);
343
- },
344
- };
345
- }