@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.
- package/CLAUDE.md +1 -1
- package/dist/acp-host/production-host.js +2389 -6018
- package/dist/analyst-gate-cycles-read.js +15 -19
- package/dist/audit-escalation.js +16 -46
- package/dist/auditor-dossier-tool.js +7 -62
- package/dist/collector-identity.js +0 -157
- package/dist/collector-ledger.js +2 -42
- package/dist/compliance-transport.js +40 -14
- package/dist/diarist-contracts.js +2 -40
- package/dist/doctor-contracts.js +39 -108
- package/dist/doctor-evidence.js +1 -5
- package/dist/engine-detour-tool.js +1 -1
- package/dist/gatekeeper-role.js +49 -38
- package/dist/headless-host/production-host.js +4814 -8450
- package/dist/host-contracts.js +0 -5
- package/dist/merger-contracts.js +4 -6
- package/dist/navigator-attendance.js +30 -52
- package/dist/navigator-invocation-identity.js +0 -1
- package/dist/navigator-public-session.js +2 -1
- package/dist/notary-contracts.js +4 -10
- package/dist/package-contracts/auditor-output.js +5 -23
- package/dist/package-contracts/fixer-output.js +25 -49
- package/dist/package-contracts/gatekeeper-output.js +3 -13
- package/dist/package-contracts/navigator-output.js +4 -7
- package/dist/package-contracts/reviewer-output.js +1 -95
- package/dist/package-contracts/terminating-tools.js +33 -144
- package/dist/package-contracts/worker-output.js +1 -3
- package/dist/public-cli/auto-resume.js +30 -68
- package/dist/public-cli/case-dossier-delivery.js +5 -17
- package/dist/public-cli/diarist-run.js +9 -4
- package/dist/public-cli/inspector-run.js +2 -8
- package/dist/public-cli/instruction-seat-run.js +3 -7
- package/dist/public-cli/invocation.js +5 -2
- package/dist/public-cli/main.js +6068 -6964
- package/dist/public-cli/notary-run.js +1 -8
- package/dist/public-cli/post-admission.js +314 -113
- package/dist/public-cli/run-lifecycle.js +14 -38
- package/dist/public-cli/settlement.js +209 -390
- package/dist/public-cli/terminal.js +51 -45
- package/dist/public-role-summons.js +1 -12
- package/dist/reviewer-dispatch.js +12 -258
- package/dist/submission-correctable-error.js +0 -12
- package/dist/submission-errors.js +6 -1
- package/dist/submission-ledger.js +125 -168
- package/dist/ticket-provenance-contracts.js +2 -49
- package/dist/ticket-provenance.js +82 -31
- package/extensions/role-runtime.ts +1 -6
- package/package.json +1 -1
- package/resources/836-deleted-machine-instruction-inventory.md +18 -0
- package/src/acp-host/role-turn-host.ts +8 -3
- package/src/analyst-gate-cycles-read.ts +17 -29
- package/src/audit-escalation.ts +20 -50
- package/src/auditor-dossier-tool.ts +5 -103
- package/src/canonical-skill-binding.ts +3 -2
- package/src/collector-identity.ts +0 -179
- package/src/collector-ledger.ts +3 -46
- package/src/collector-role.ts +32 -61
- package/src/collector-tool-schemas.ts +20 -14
- package/src/compliance-transport.ts +55 -17
- package/src/countersign-role.ts +17 -8
- package/src/diarist-contracts.ts +3 -36
- package/src/diarist-role.ts +13 -7
- package/src/diarist.ts +4 -16
- package/src/doctor-contracts.ts +73 -94
- package/src/doctor-evidence.ts +1 -1
- package/src/doctor-role.ts +3 -3
- package/src/engine-detour-tool.ts +4 -1
- package/src/external-host-turn-loop.ts +9 -3
- package/src/gatekeeper-pass-envelope.ts +7 -12
- package/src/gatekeeper-role.ts +56 -50
- package/src/gleaner-left-role.ts +4 -2
- package/src/headless-host/role-turn-host.ts +4 -5
- package/src/host-contracts.ts +3 -8
- package/src/judge-role.ts +19 -13
- package/src/merger-contracts.ts +10 -6
- package/src/merger-role.ts +1 -5
- package/src/navigator-attendance.ts +37 -74
- package/src/navigator-invocation-identity.ts +0 -6
- package/src/navigator-public-session.ts +2 -1
- package/src/notary-contracts.ts +7 -10
- package/src/package-contracts/auditor-output.ts +4 -21
- package/src/package-contracts/fixer-output.ts +34 -52
- package/src/package-contracts/gatekeeper-output.ts +5 -22
- package/src/package-contracts/navigator-output.ts +7 -7
- package/src/package-contracts/reviewer-output.ts +2 -150
- package/src/package-contracts/terminating-tools.ts +32 -147
- package/src/package-contracts/worker-output.ts +0 -1
- package/src/pi/adapter.ts +3 -8
- package/src/public-cli/auto-resume.ts +41 -94
- package/src/public-cli/case-dossier-delivery.ts +5 -15
- package/src/public-cli/countersign-run.ts +14 -6
- package/src/public-cli/diarist-run.ts +11 -9
- package/src/public-cli/inspector-run.ts +2 -18
- package/src/public-cli/instruction-seat-run.ts +3 -17
- package/src/public-cli/invocation.ts +5 -2
- package/src/public-cli/merger-run.ts +1 -1
- package/src/public-cli/notary-run.ts +1 -18
- package/src/public-cli/post-admission.ts +385 -115
- package/src/public-cli/run-lifecycle.ts +13 -44
- package/src/public-cli/settlement.ts +314 -562
- package/src/public-cli/terminal.ts +66 -72
- package/src/public-role-summons.ts +5 -30
- package/src/reviewer-dispatch.ts +29 -331
- package/src/reviewer-role.ts +16 -83
- package/src/role-envelope.ts +16 -24
- package/src/role-runtime-dependencies.ts +1 -6
- package/src/role-runtime.ts +65 -201
- package/src/submission-correctable-error.ts +0 -14
- package/src/submission-errors.ts +6 -1
- package/src/submission-ledger.ts +187 -187
- package/src/ticket-provenance-contracts.ts +4 -60
- package/src/ticket-provenance.ts +98 -32
- package/src/worker-role.ts +35 -36
- package/dist/activation-ledger-session.js +0 -105
- package/dist/activation-ledger.js +0 -139
- package/dist/activation-trace.js +0 -33
- package/dist/atomic-write.js +0 -23
- package/dist/auditor-role.js +0 -12
- package/dist/canonical-skill-binding.js +0 -61
- package/dist/collector-handbook.js +0 -142
- package/dist/collector-receipt.js +0 -107
- package/dist/collector-role.js +0 -566
- package/dist/collector-tool-schemas.js +0 -107
- package/dist/countersign-role.js +0 -28
- package/dist/diarist-role.js +0 -44
- package/dist/diarist.js +0 -66
- package/dist/doctor-role.js +0 -75
- package/dist/fixer-bash-seatbelt.js +0 -13
- package/dist/gatekeeper-pass-envelope.js +0 -77
- package/dist/gleaner-left-role.js +0 -26
- package/dist/inspector-role.js +0 -29
- package/dist/judge-role.js +0 -104
- package/dist/merger-role.js +0 -55
- package/dist/navigator-role.js +0 -12
- package/dist/notary-role.js +0 -134
- package/dist/oauth-keepalive.js +0 -158
- package/dist/pi/adapter.js +0 -223
- package/dist/reviewer-agent.js +0 -122
- package/dist/reviewer-child-executor.js +0 -194
- package/dist/reviewer-construction.js +0 -103
- package/dist/reviewer-execution-ledger.js +0 -166
- package/dist/reviewer-failure-diagnostic.js +0 -17
- package/dist/reviewer-role.js +0 -159
- package/dist/reviewer-scope-prompt.js +0 -21
- package/dist/reviewer-settlement.js +0 -66
- package/dist/reviewer-workspace.js +0 -132
- package/dist/role-runtime.js +0 -1604
- package/dist/stderr-jsonl.js +0 -26
- package/dist/tool-execution-observation.js +0 -141
- package/dist/worker-role.js +0 -345
- package/dist/worker-submission-gates.js +0 -305
- package/src/collector-receipt.ts +0 -140
- package/src/diagnostic-tail.ts +0 -18
- package/src/reviewer-agent.ts +0 -135
- package/src/reviewer-child-executor.ts +0 -252
- package/src/reviewer-construction.ts +0 -195
- package/src/reviewer-execution-ledger.ts +0 -212
- package/src/reviewer-failure-diagnostic.ts +0 -18
- package/src/reviewer-scope-prompt.ts +0 -24
- package/src/reviewer-settlement.ts +0 -74
- package/src/reviewer-workspace.ts +0 -105
- package/src/shape-unreadable-failure.ts +0 -49
package/dist/stderr-jsonl.js
DELETED
|
@@ -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
|
-
}
|
package/dist/worker-role.js
DELETED
|
@@ -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
|
-
}
|