@akagilnc/pi-workflow-roles 0.1.1751
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/LICENSE +202 -0
- package/README.md +104 -0
- package/README.zh-CN.md +133 -0
- package/THIRD_PARTY_NOTICES.md +60 -0
- package/dist/activation-ledger-git.js +68 -0
- package/dist/activation-ledger-session.js +120 -0
- package/dist/activation-ledger-topology.js +239 -0
- package/dist/activation-reconciliation.js +61 -0
- package/dist/audit-escalation.js +108 -0
- package/dist/auditor-dossier-tool.js +35 -0
- package/dist/canonical-json.js +78 -0
- package/dist/compliance-transport.js +77 -0
- package/dist/doctor-contracts.js +172 -0
- package/dist/dossier-resolution.js +103 -0
- package/dist/evidence-child-executor.js +661 -0
- package/dist/exact-utf8.js +12 -0
- package/dist/git-object-id.js +7 -0
- package/dist/in-process-session.js +50 -0
- package/dist/merger-contracts.js +76 -0
- package/dist/navigator-attendance.js +995 -0
- package/dist/navigator-invocation-identity.js +220 -0
- package/dist/open-tool-schema.js +39 -0
- package/dist/package-contracts/collector-output.js +50 -0
- package/dist/package-contracts/fixer-output.js +72 -0
- package/dist/package-contracts/fixer-packet.js +77 -0
- package/dist/package-contracts/judge-output.js +17 -0
- package/dist/package-contracts/reviewer-output.js +82 -0
- package/dist/package-contracts/terminating-tools.js +173 -0
- package/dist/package-contracts/worker-output.js +13 -0
- package/dist/package-owned-tool-idle.js +104 -0
- package/dist/packaged-role-registry.js +34 -0
- package/dist/public-cli/main.js +23867 -0
- package/dist/public-command-renderer.js +20 -0
- package/dist/reviewer-agent.js +93 -0
- package/dist/reviewer-child-executor.js +23 -0
- package/dist/reviewer-construction.js +95 -0
- package/dist/reviewer-dispatch.js +77 -0
- package/dist/reviewer-execution-ledger.js +160 -0
- package/dist/reviewer-failure-diagnostic.js +17 -0
- package/dist/reviewer-git-snapshot.js +38 -0
- package/dist/reviewer-pinned-git.js +146 -0
- package/dist/reviewer-preflight-error.js +15 -0
- package/dist/reviewer-prompt-identity.js +10 -0
- package/dist/reviewer-scope-prompt.js +21 -0
- package/dist/reviewer-workspace.js +151 -0
- package/dist/sha256.js +5 -0
- package/dist/sitian-record-entry.js +33 -0
- package/dist/stderr-jsonl.js +26 -0
- package/dist/stream-idle-guard.js +75 -0
- package/dist/tool-execution-observation.js +141 -0
- package/dist/uuidv7.js +21 -0
- package/dist/work-subject-identity.js +53 -0
- package/extensions/role-runtime.ts +303 -0
- package/package.json +69 -0
- package/packets/fixer-prerequisites.json +6 -0
- package/packets/fixer-repair.md +5 -0
- package/packets/judge-apply.md +77 -0
- package/packets/judge-authority.md +64 -0
- package/packets/judge-plan.md +55 -0
- package/packets/judge-review.md +49 -0
- package/packets/judge-submission.md +34 -0
- package/resources/methods/code-review/SKILL.md +92 -0
- package/resources/methods/code-review/agents/openai.yaml +3 -0
- package/resources/methods/code-review/provenance.json +26 -0
- package/resources/methods/diagnosing-bugs/SKILL.md +134 -0
- package/resources/methods/diagnosing-bugs/agents/openai.yaml +3 -0
- package/resources/methods/diagnosing-bugs/provenance.json +31 -0
- package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/resources/methods/resolving-merge-conflicts/SKILL.md +14 -0
- package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +3 -0
- package/resources/methods/resolving-merge-conflicts/provenance.json +26 -0
- package/resources/methods/tdd/SKILL.md +38 -0
- package/resources/methods/tdd/agents/openai.yaml +3 -0
- package/resources/methods/tdd/mocking.md +59 -0
- package/resources/methods/tdd/provenance.json +36 -0
- package/resources/methods/tdd/tests.md +77 -0
- package/resources/navigator-route-playbook.md +32 -0
- package/schemas/tool-execution-observation.schema.json +107 -0
- package/scripts/build-package.mjs +65 -0
- package/scripts/generate-tool-execution-observation-schema.ts +7 -0
- package/souls/coder.md +10 -0
- package/souls/collector.md +11 -0
- package/souls/doctor-auditor.md +23 -0
- package/souls/doctor.md +8 -0
- package/souls/fixer-auditor.md +33 -0
- package/souls/fixer.md +13 -0
- package/souls/judge-auditor.md +33 -0
- package/souls/judge.md +74 -0
- package/souls/merger.md +5 -0
- package/souls/navigator.md +5 -0
- package/souls/reviewer-auditor.md +25 -0
- package/souls/reviewer.md +11 -0
- package/src/activation-ledger-git.ts +96 -0
- package/src/activation-ledger-session.ts +188 -0
- package/src/activation-ledger-topology.ts +301 -0
- package/src/activation-ledger.ts +240 -0
- package/src/activation-reconciliation.ts +163 -0
- package/src/activation-trace.ts +38 -0
- package/src/audit-escalation.ts +177 -0
- package/src/auditor-dossier-tool.ts +48 -0
- package/src/auditor-soul.ts +28 -0
- package/src/canonical-json.ts +74 -0
- package/src/canonical-skill-binding.ts +107 -0
- package/src/collector-config.ts +89 -0
- package/src/collector-evidence.ts +461 -0
- package/src/collector-github.ts +656 -0
- package/src/collector-identity.ts +161 -0
- package/src/collector-ledger.ts +827 -0
- package/src/collector-receipt.ts +87 -0
- package/src/collector-role.ts +592 -0
- package/src/collector-tool-schemas.ts +19 -0
- package/src/compliance-transport.ts +130 -0
- package/src/doctor-auditor.ts +53 -0
- package/src/doctor-contracts.ts +166 -0
- package/src/doctor-evidence.ts +47 -0
- package/src/doctor-role.ts +18 -0
- package/src/dossier-resolution.ts +137 -0
- package/src/evidence-child-executor.ts +775 -0
- package/src/exact-utf8.ts +9 -0
- package/src/factory-board.ts +1822 -0
- package/src/git-object-id.ts +11 -0
- package/src/human-format.ts +65 -0
- package/src/in-process-session.ts +78 -0
- package/src/judge-auditor.ts +55 -0
- package/src/judge-recording-anti-forge.ts +53 -0
- package/src/judge-role.ts +160 -0
- package/src/merger-contracts.ts +71 -0
- package/src/merger-git-state.ts +76 -0
- package/src/merger-role.ts +60 -0
- package/src/navigator-attendance.ts +1254 -0
- package/src/navigator-invocation-identity.ts +446 -0
- package/src/open-tool-schema.ts +46 -0
- package/src/package-contracts/collector-output.ts +109 -0
- package/src/package-contracts/fixer-output.ts +81 -0
- package/src/package-contracts/fixer-packet.ts +93 -0
- package/src/package-contracts/judge-output.ts +39 -0
- package/src/package-contracts/reviewer-output.ts +115 -0
- package/src/package-contracts/terminating-tools.ts +259 -0
- package/src/package-contracts/worker-output.ts +36 -0
- package/src/package-owned-tool-idle.ts +134 -0
- package/src/package-resources/method-skill-binding.ts +87 -0
- package/src/package-resources/method-skill.ts +358 -0
- package/src/packaged-role-registry.ts +36 -0
- package/src/public-cli/cli-errors.ts +11 -0
- package/src/public-cli/cli-io.ts +4 -0
- package/src/public-cli/cli.ts +912 -0
- package/src/public-cli/coder-run.ts +575 -0
- package/src/public-cli/collector-run.ts +375 -0
- package/src/public-cli/command-renderer.ts +8 -0
- package/src/public-cli/config.ts +346 -0
- package/src/public-cli/doctor-run.ts +355 -0
- package/src/public-cli/explicit-internal.ts +274 -0
- package/src/public-cli/fixer-run.ts +587 -0
- package/src/public-cli/host-pi-runtime.ts +112 -0
- package/src/public-cli/invocation.ts +1958 -0
- package/src/public-cli/judge-run.ts +507 -0
- package/src/public-cli/main.ts +15 -0
- package/src/public-cli/merger-run.ts +681 -0
- package/src/public-cli/public-run-credentials.ts +71 -0
- package/src/public-cli/registry.ts +153 -0
- package/src/public-cli/reviewer-run.ts +561 -0
- package/src/public-cli/run-lifecycle.ts +884 -0
- package/src/public-cli/settlement.ts +3765 -0
- package/src/public-cli/terminal.ts +325 -0
- package/src/public-command-renderer.ts +43 -0
- package/src/reviewer-agent.ts +94 -0
- package/src/reviewer-auditor.ts +53 -0
- package/src/reviewer-child-executor.ts +31 -0
- package/src/reviewer-construction.ts +137 -0
- package/src/reviewer-dispatch.ts +94 -0
- package/src/reviewer-execution-ledger.ts +206 -0
- package/src/reviewer-failure-diagnostic.ts +18 -0
- package/src/reviewer-git-snapshot.ts +53 -0
- package/src/reviewer-pinned-git.ts +144 -0
- package/src/reviewer-preflight-error.ts +14 -0
- package/src/reviewer-prompt-identity.ts +17 -0
- package/src/reviewer-role.ts +193 -0
- package/src/reviewer-scope-prompt.ts +24 -0
- package/src/reviewer-settlement.ts +63 -0
- package/src/reviewer-workspace.ts +111 -0
- package/src/role-runtime.ts +884 -0
- package/src/sha256.ts +6 -0
- package/src/sitian-record-entry.ts +57 -0
- package/src/stderr-jsonl.ts +28 -0
- package/src/stream-idle-guard.ts +98 -0
- package/src/ticket-snapshot.ts +662 -0
- package/src/ticket-trajectory.ts +1000 -0
- package/src/tool-execution-observation.ts +168 -0
- package/src/uuidv7.ts +1 -0
- package/src/work-subject-identity.ts +94 -0
- package/src/worker-role.ts +434 -0
- package/src/worker-submission-gates.ts +225 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal result: typed semantic regions for one admitted Role run (ADR 0052 / #106).
|
|
3
|
+
* Presentation may rearrange labels/order; only regions and typed facts are stable.
|
|
4
|
+
*
|
|
5
|
+
* Free-text cells are JSON-string encoded so legitimate newlines/tabs cannot forge
|
|
6
|
+
* extra rows or shift column boundaries (note / fix.summary / decision question / reason).
|
|
7
|
+
*/
|
|
8
|
+
import { renderPublicAkRoleCommand } from "./command-renderer.ts";
|
|
9
|
+
import type { ComplianceAuditIncomplete } from "../compliance-transport.ts";
|
|
10
|
+
import type { NavigatorPhase } from "../navigator-attendance.ts";
|
|
11
|
+
|
|
12
|
+
/** Encode one free-text Terminal cell. JSON string form cannot embed raw tab/newline. */
|
|
13
|
+
export function encodeTerminalField(value: string): string {
|
|
14
|
+
return JSON.stringify(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type TerminalArtifactRef = {
|
|
18
|
+
kind: "report" | "evidence" | "error";
|
|
19
|
+
/** Openable local reference (path). Layout is private; the ref value is the contract. */
|
|
20
|
+
path: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Controlled post-admission failure classes (ADR 0052 / #107). */
|
|
24
|
+
export type ControlledFailureCause =
|
|
25
|
+
| "activation"
|
|
26
|
+
| "provider"
|
|
27
|
+
| "session"
|
|
28
|
+
| "output"
|
|
29
|
+
| "timeout"
|
|
30
|
+
| "unrecognized";
|
|
31
|
+
|
|
32
|
+
/** Public callable roles that currently produce Terminal outcomes. */
|
|
33
|
+
export type TerminalRoleName =
|
|
34
|
+
| "judge"
|
|
35
|
+
| "coder"
|
|
36
|
+
| "fixer"
|
|
37
|
+
| "collector"
|
|
38
|
+
| "doctor"
|
|
39
|
+
| "reviewer"
|
|
40
|
+
| "merger";
|
|
41
|
+
|
|
42
|
+
export type ResidualIncompleteTerminalOutcome = {
|
|
43
|
+
kind: "incomplete";
|
|
44
|
+
role: "merger" | "collector";
|
|
45
|
+
status: "incomplete";
|
|
46
|
+
decision: "no-usable-result";
|
|
47
|
+
candidate: unknown;
|
|
48
|
+
diagnostic: string;
|
|
49
|
+
acceptedReceipt: false;
|
|
50
|
+
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type AuditIncompleteTerminalOutcome = {
|
|
54
|
+
kind: "audit_incomplete";
|
|
55
|
+
role: TerminalRoleName;
|
|
56
|
+
status: "audit-incomplete";
|
|
57
|
+
decision: "no-usable-decision";
|
|
58
|
+
/** The original role submission arguments, retained independently. */
|
|
59
|
+
roleCandidate: unknown;
|
|
60
|
+
/** The malformed auditor candidate and observation retained by compliance transport. */
|
|
61
|
+
audit: ComplianceAuditIncomplete;
|
|
62
|
+
acceptedReceipt: false;
|
|
63
|
+
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** JSON-safe public stand-in for an omitted tool-call `arguments` member. */
|
|
67
|
+
export const JSON_SAFE_UNDEFINED_ARGUMENT = Object.freeze({
|
|
68
|
+
kind: "json-safe-sentinel",
|
|
69
|
+
type: "undefined",
|
|
70
|
+
} as const);
|
|
71
|
+
|
|
72
|
+
export type AuditIncompleteResidual = {
|
|
73
|
+
readonly roleCandidate: unknown;
|
|
74
|
+
readonly audit: ComplianceAuditIncomplete;
|
|
75
|
+
readonly acceptedReceipt: false;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export function jsonSafeComplianceCandidate(value: unknown): unknown {
|
|
79
|
+
return value === undefined ? JSON_SAFE_UNDEFINED_ARGUMENT : value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type TerminalRoleOutcome =
|
|
83
|
+
| {
|
|
84
|
+
kind: "accepted";
|
|
85
|
+
role: TerminalRoleName;
|
|
86
|
+
status: string;
|
|
87
|
+
/** Few decisive facts drawn from the typed receipt. */
|
|
88
|
+
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
89
|
+
}
|
|
90
|
+
| {
|
|
91
|
+
kind: "audit_escalation";
|
|
92
|
+
role: TerminalRoleName;
|
|
93
|
+
status: "audit_escalation";
|
|
94
|
+
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
95
|
+
}
|
|
96
|
+
| AuditIncompleteTerminalOutcome
|
|
97
|
+
| ResidualIncompleteTerminalOutcome
|
|
98
|
+
| {
|
|
99
|
+
kind: "failure";
|
|
100
|
+
role: TerminalRoleName;
|
|
101
|
+
/** Typed cause class — never a fabricated role Receipt status. */
|
|
102
|
+
cause: ControlledFailureCause;
|
|
103
|
+
/** Original diagnostic identity retained for the caller. */
|
|
104
|
+
diagnostic: string;
|
|
105
|
+
decisiveFacts: Readonly<Record<string, unknown>>;
|
|
106
|
+
/** Retained audit residual when publication itself failed. */
|
|
107
|
+
auditResidual?: AuditIncompleteResidual;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** Lawful typed terminal results exit zero (including audit_escalation). */
|
|
111
|
+
export function isLawfulTypedTerminalOutcome(
|
|
112
|
+
outcome: TerminalRoleOutcome,
|
|
113
|
+
): boolean {
|
|
114
|
+
return outcome.kind === "accepted" || outcome.kind === "audit_escalation";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function exitCodeForTerminalOutcome(
|
|
118
|
+
outcome: TerminalRoleOutcome,
|
|
119
|
+
): number {
|
|
120
|
+
return isLawfulTypedTerminalOutcome(outcome) ? 0 : 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function buildResidualIncompleteTerminalOutcome(input: {
|
|
124
|
+
role: "merger" | "collector";
|
|
125
|
+
candidate: unknown;
|
|
126
|
+
diagnostic: string;
|
|
127
|
+
}): ResidualIncompleteTerminalOutcome {
|
|
128
|
+
return {
|
|
129
|
+
kind: "incomplete",
|
|
130
|
+
role: input.role,
|
|
131
|
+
status: "incomplete",
|
|
132
|
+
decision: "no-usable-result",
|
|
133
|
+
candidate: input.candidate,
|
|
134
|
+
diagnostic: input.diagnostic,
|
|
135
|
+
acceptedReceipt: false,
|
|
136
|
+
decisiveFacts: {
|
|
137
|
+
decision: "no-usable-result",
|
|
138
|
+
candidate: input.candidate,
|
|
139
|
+
diagnostic: input.diagnostic,
|
|
140
|
+
acceptedReceipt: false,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function buildAuditIncompleteTerminalOutcome(input: {
|
|
146
|
+
role: TerminalRoleName;
|
|
147
|
+
roleCandidate: unknown;
|
|
148
|
+
audit: ComplianceAuditIncomplete;
|
|
149
|
+
}): AuditIncompleteTerminalOutcome {
|
|
150
|
+
const roleCandidate = jsonSafeComplianceCandidate(input.roleCandidate);
|
|
151
|
+
const audit = {
|
|
152
|
+
...input.audit,
|
|
153
|
+
candidate: jsonSafeComplianceCandidate(input.audit.candidate),
|
|
154
|
+
};
|
|
155
|
+
return {
|
|
156
|
+
kind: "audit_incomplete",
|
|
157
|
+
role: input.role,
|
|
158
|
+
status: "audit-incomplete",
|
|
159
|
+
decision: "no-usable-decision",
|
|
160
|
+
roleCandidate,
|
|
161
|
+
audit,
|
|
162
|
+
acceptedReceipt: false,
|
|
163
|
+
decisiveFacts: {
|
|
164
|
+
decision: "no-usable-decision",
|
|
165
|
+
roleCandidate,
|
|
166
|
+
auditCandidate: audit.candidate,
|
|
167
|
+
auditObservation: audit.observation,
|
|
168
|
+
observationKind: audit.observation.kind,
|
|
169
|
+
observationType: audit.observation.kind === "non-object-arguments"
|
|
170
|
+
? audit.observation.type
|
|
171
|
+
: audit.observation.kind === "object-status-unreadable"
|
|
172
|
+
? audit.observation.status
|
|
173
|
+
: audit.observation.kind === "missing-subject"
|
|
174
|
+
? audit.observation.subject
|
|
175
|
+
: audit.observation.kind,
|
|
176
|
+
acceptedReceipt: false,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export type TerminalNavigatorFact =
|
|
182
|
+
| {
|
|
183
|
+
disposition: "recommendation";
|
|
184
|
+
next: { role: string; phase: NavigatorPhase };
|
|
185
|
+
reason: string;
|
|
186
|
+
/** Registry-rendered public command — never model prose. */
|
|
187
|
+
command: string;
|
|
188
|
+
route?: ReadonlyArray<{ role: string; phase: NavigatorPhase }>;
|
|
189
|
+
advisoryDiagnostic?: string;
|
|
190
|
+
}
|
|
191
|
+
| {
|
|
192
|
+
disposition: "no-advice";
|
|
193
|
+
advisoryDiagnostic?: string;
|
|
194
|
+
}
|
|
195
|
+
| {
|
|
196
|
+
disposition: "unavailable";
|
|
197
|
+
source: string;
|
|
198
|
+
reason: string;
|
|
199
|
+
advisoryDiagnostic?: string;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/** Present only when a controlled failure is v1-resumable (typed HTTP 429). */
|
|
203
|
+
export type TerminalResume = {
|
|
204
|
+
/** Complete public command; run ID is revealed only here. */
|
|
205
|
+
readonly command: string;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/** Public free-text stand-in when an exact Role run ID is stripped outside resume.command. */
|
|
209
|
+
export const REDACTED_RUN_ID_TOKEN = "[run-id]" as const;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Remove an exact Role run ID from untrusted free text at the public Terminal boundary.
|
|
213
|
+
* Private durable artifacts keep the original bytes; only resume.command may disclose it.
|
|
214
|
+
*/
|
|
215
|
+
export function redactExactRunId(text: string, runId: string): string {
|
|
216
|
+
if (runId.length === 0) return text;
|
|
217
|
+
if (!text.includes(runId)) return text;
|
|
218
|
+
return text.split(runId).join(REDACTED_RUN_ID_TOKEN);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* One admitted Role run's typed Terminal aggregate.
|
|
223
|
+
* Resumable failures carry `resume` and must not re-disclose the run ID via
|
|
224
|
+
* top-level `runId` or public artifact path components — only `resume.command`.
|
|
225
|
+
*/
|
|
226
|
+
export type TerminalResult = {
|
|
227
|
+
roleOutcome: TerminalRoleOutcome;
|
|
228
|
+
navigator: TerminalNavigatorFact;
|
|
229
|
+
artifacts: readonly TerminalArtifactRef[];
|
|
230
|
+
} & (
|
|
231
|
+
| {
|
|
232
|
+
/** Resumable failure: run ID appears only inside resume.command. */
|
|
233
|
+
resume: TerminalResume;
|
|
234
|
+
runId?: undefined;
|
|
235
|
+
}
|
|
236
|
+
| {
|
|
237
|
+
runId: string;
|
|
238
|
+
resume?: undefined;
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Build a recommendation navigator fact. Command is always registry-rendered;
|
|
244
|
+
* any model-authored command string is ignored.
|
|
245
|
+
*/
|
|
246
|
+
export function recommendationNavigatorFact(input: {
|
|
247
|
+
next: { role: string; phase: NavigatorPhase };
|
|
248
|
+
reason: string;
|
|
249
|
+
route?: ReadonlyArray<{ role: string; phase: NavigatorPhase }>;
|
|
250
|
+
advisoryDiagnostic?: string;
|
|
251
|
+
/** Ignored — retained only so callers can pass through raw attendance without using it. */
|
|
252
|
+
modelCommand?: string;
|
|
253
|
+
}): TerminalNavigatorFact {
|
|
254
|
+
void input.modelCommand;
|
|
255
|
+
const command = renderPublicAkRoleCommand(input.next);
|
|
256
|
+
if (command === undefined) {
|
|
257
|
+
return {
|
|
258
|
+
disposition: "unavailable",
|
|
259
|
+
source: "unknown",
|
|
260
|
+
reason: `recommended role is not a public callable seat: ${input.next.role}`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
disposition: "recommendation",
|
|
265
|
+
next: input.next,
|
|
266
|
+
reason: input.reason,
|
|
267
|
+
command,
|
|
268
|
+
...(input.route === undefined ? {} : { route: input.route }),
|
|
269
|
+
...(input.advisoryDiagnostic === undefined ? {} : { advisoryDiagnostic: input.advisoryDiagnostic }),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Present one Terminal result for humans. Labels, row order, wording, and layout
|
|
275
|
+
* are unfrozen (ADR 0052). Machine consumers and tests must read typed
|
|
276
|
+
* TerminalResult / settlement owners — never bite this presentation.
|
|
277
|
+
*/
|
|
278
|
+
export function formatTerminalResult(result: TerminalResult): string {
|
|
279
|
+
const lines: string[] = [];
|
|
280
|
+
lines.push("role\toutcome\tstatus");
|
|
281
|
+
const outcomeStatus =
|
|
282
|
+
result.roleOutcome.kind === "failure"
|
|
283
|
+
? result.roleOutcome.cause
|
|
284
|
+
: result.roleOutcome.status;
|
|
285
|
+
lines.push(
|
|
286
|
+
`${result.roleOutcome.role}\t${result.roleOutcome.kind}\t${encodeTerminalField(outcomeStatus)}`,
|
|
287
|
+
);
|
|
288
|
+
if (result.roleOutcome.kind === "failure") {
|
|
289
|
+
lines.push(
|
|
290
|
+
`diagnostic\t${encodeTerminalField(result.roleOutcome.diagnostic)}`,
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
const facts = result.roleOutcome.decisiveFacts;
|
|
294
|
+
for (const [key, value] of Object.entries(facts)) {
|
|
295
|
+
if (value === undefined) continue;
|
|
296
|
+
const rendered =
|
|
297
|
+
typeof value === "string" ? value : JSON.stringify(value);
|
|
298
|
+
lines.push(`fact\t${encodeTerminalField(key)}\t${encodeTerminalField(rendered)}`);
|
|
299
|
+
}
|
|
300
|
+
lines.push(`navigator\t${result.navigator.disposition}`);
|
|
301
|
+
if (result.navigator.advisoryDiagnostic !== undefined) {
|
|
302
|
+
lines.push(`navigator-advisory\t${encodeTerminalField(result.navigator.advisoryDiagnostic)}`);
|
|
303
|
+
}
|
|
304
|
+
if (result.navigator.disposition === "recommendation") {
|
|
305
|
+
lines.push(
|
|
306
|
+
`next\t${result.navigator.next.role}\t${result.navigator.next.phase ?? "none"}`,
|
|
307
|
+
);
|
|
308
|
+
lines.push(`reason\t${encodeTerminalField(result.navigator.reason)}`);
|
|
309
|
+
lines.push(`command\t${encodeTerminalField(result.navigator.command)}`);
|
|
310
|
+
} else if (result.navigator.disposition === "unavailable") {
|
|
311
|
+
lines.push(
|
|
312
|
+
`unavailable\t${result.navigator.source}\t${encodeTerminalField(result.navigator.reason)}`,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
for (const artifact of result.artifacts) {
|
|
316
|
+
lines.push(`artifact\t${artifact.kind}\t${encodeTerminalField(artifact.path)}`);
|
|
317
|
+
}
|
|
318
|
+
if (result.resume !== undefined) {
|
|
319
|
+
// Resumable failure: run ID is revealed only inside the complete resume command.
|
|
320
|
+
lines.push(`resume\t${encodeTerminalField(result.resume.command)}`);
|
|
321
|
+
} else if (result.runId !== undefined) {
|
|
322
|
+
lines.push(`run\t${encodeTerminalField(result.runId)}`);
|
|
323
|
+
}
|
|
324
|
+
return `${lines.join("\n")}\n`;
|
|
325
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry-owned public command renderer (ADR 0052 / #106).
|
|
3
|
+
* Typed role/phase facts → public `ak-role` command text.
|
|
4
|
+
* Model-authored command prose is never executable output.
|
|
5
|
+
*
|
|
6
|
+
* Low-level shared owner: Navigator attendance and the public CLI both import
|
|
7
|
+
* this module so dist/navigator-attendance.js keeps a complete dependency closure
|
|
8
|
+
* without duplicating renderer logic into the preparation graph or bin bundle.
|
|
9
|
+
*/
|
|
10
|
+
import {
|
|
11
|
+
PACKAGED_ROLE_REGISTRY,
|
|
12
|
+
type PackagedRole,
|
|
13
|
+
} from "./packaged-role-registry.ts";
|
|
14
|
+
|
|
15
|
+
export type PublicCommandPhase = "plan" | "apply" | null;
|
|
16
|
+
|
|
17
|
+
export type PublicCommandTarget = {
|
|
18
|
+
role: string;
|
|
19
|
+
phase: PublicCommandPhase;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const PUBLIC_CALLABLE_ROLES = new Set<string>(
|
|
23
|
+
PACKAGED_ROLE_REGISTRY.map((entry) => entry.role),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Render one public ak-role invocation from typed next-role facts.
|
|
28
|
+
* Returns undefined when the target is not a public callable role.
|
|
29
|
+
*/
|
|
30
|
+
export function renderPublicAkRoleCommand(
|
|
31
|
+
target: PublicCommandTarget,
|
|
32
|
+
): string | undefined {
|
|
33
|
+
if (!PUBLIC_CALLABLE_ROLES.has(target.role)) return undefined;
|
|
34
|
+
const role = target.role as PackagedRole;
|
|
35
|
+
if (target.phase === null || target.phase === undefined) {
|
|
36
|
+
return `ak-role ${role}`;
|
|
37
|
+
}
|
|
38
|
+
// Coder/Fixer expose plan|apply; other roles have no public phase selector.
|
|
39
|
+
if (role === "coder" || role === "fixer") {
|
|
40
|
+
return `ak-role ${role} ${target.phase}`;
|
|
41
|
+
}
|
|
42
|
+
return `ak-role ${role}`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { isReviewerPromptText, type ReviewerPromptText } from "./reviewer-prompt-identity.ts";
|
|
3
|
+
import type { AcceptedReviewerExecution } from "./reviewer-dispatch.ts";
|
|
4
|
+
import type { ReviewerTargetSnapshot, ReviewerWorkspaceDisposition, ReviewerFailureClassification, ReviewerUsage } from "./reviewer-execution-ledger.ts";
|
|
5
|
+
import { executeReviewerChild } from "./reviewer-child-executor.ts";
|
|
6
|
+
import { createReviewerWorkspaceOwner, type ReviewerWorkspaceFaultPoint } from "./reviewer-workspace.ts";
|
|
7
|
+
import { normalizeReviewerFailureDiagnostic } from "./reviewer-failure-diagnostic.ts";
|
|
8
|
+
|
|
9
|
+
type ReviewerLegRunResultCommon = Readonly<{ target: ReviewerTargetSnapshot; prompt: ReviewerPromptText; workspaceDisposition: ReviewerWorkspaceDisposition }>;
|
|
10
|
+
export type ReviewerSuccessfulLegRunResult = ReviewerLegRunResultCommon & Readonly<{ status: "successful"; report: string; usage: ReviewerUsage; failure?: never }>;
|
|
11
|
+
export type ReviewerFailedLegRunResult = ReviewerLegRunResultCommon & Readonly<{ status: "failed"; failure: ReviewerFailureClassification; diagnostic: string; cause?: unknown; report?: never; usage?: never }>;
|
|
12
|
+
export type ReviewerLegRunResult = ReviewerSuccessfulLegRunResult | ReviewerFailedLegRunResult;
|
|
13
|
+
type Envelope<L> = Readonly<{ identity: string; target: ReviewerTargetSnapshot; legs: Readonly<L> }>;
|
|
14
|
+
export type ReviewerDispatchRunResult = Envelope<{ standards: ReviewerLegRunResult; spec?: never }> | Envelope<{ standards: ReviewerLegRunResult; spec: ReviewerLegRunResult }>;
|
|
15
|
+
export type ReviewerSuccessfulDispatchRunResult = Envelope<{ standards: ReviewerSuccessfulLegRunResult; spec?: never }> | Envelope<{ standards: ReviewerSuccessfulLegRunResult; spec: ReviewerSuccessfulLegRunResult }>;
|
|
16
|
+
function reviewerDispatchFailureMessage(outcome: ReviewerDispatchRunResult): string {
|
|
17
|
+
const diagnostics = [...new Set(
|
|
18
|
+
Object.values(outcome.legs)
|
|
19
|
+
.filter((leg): leg is ReviewerFailedLegRunResult => leg?.status === "failed")
|
|
20
|
+
.map((leg) => leg.diagnostic.trim())
|
|
21
|
+
.filter((diagnostic) => diagnostic.length > 0),
|
|
22
|
+
)];
|
|
23
|
+
if (diagnostics.length === 0) return "Reviewer dispatch execution failed";
|
|
24
|
+
return diagnostics.length === 1 ? diagnostics[0]! : diagnostics.join("; ");
|
|
25
|
+
}
|
|
26
|
+
export class ReviewerDispatchExecutionError extends Error {
|
|
27
|
+
constructor(readonly outcome: ReviewerDispatchRunResult) {
|
|
28
|
+
super(reviewerDispatchFailureMessage(outcome));
|
|
29
|
+
this.name = "ReviewerDispatchExecutionError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export type ReviewerAgentRunner = { run(dispatch: AcceptedReviewerExecution, options: { context: ExtensionContext; signal?: AbortSignal }): Promise<ReviewerSuccessfulDispatchRunResult>; shutdown(): Promise<void> };
|
|
33
|
+
export type ReviewerAgentFaultPoint = ReviewerWorkspaceFaultPoint;
|
|
34
|
+
type Dependencies = Readonly<{
|
|
35
|
+
fault?(operation: ReviewerAgentFaultPoint): void;
|
|
36
|
+
/** When set, child credential/config scratch is created under this parent so cleanup proofs stay process-local. */
|
|
37
|
+
credentialScratchParent?: string;
|
|
38
|
+
}>;
|
|
39
|
+
function classify(error: unknown, signal?: AbortSignal): ReviewerFailureClassification { if (signal?.aborted) return "cancelled"; if (typeof error === "object" && error !== null && "reviewerFailure" in error) return (error as { reviewerFailure: ReviewerFailureClassification }).reviewerFailure; return "unknown"; }
|
|
40
|
+
function failed(error: unknown, target: ReviewerTargetSnapshot, prompt: ReviewerPromptText, signal?: AbortSignal, retained?: string): ReviewerFailedLegRunResult {
|
|
41
|
+
const attached = typeof error === "object" && error !== null ? error as { targetSnapshot?: ReviewerTargetSnapshot; workspaceDisposition?: ReviewerWorkspaceDisposition } : {};
|
|
42
|
+
const failure = classify(error, signal);
|
|
43
|
+
const diagnostic = normalizeReviewerFailureDiagnostic(error, failure);
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
status: "failed",
|
|
46
|
+
failure,
|
|
47
|
+
diagnostic,
|
|
48
|
+
cause: error,
|
|
49
|
+
target: attached.targetSnapshot ?? target,
|
|
50
|
+
prompt,
|
|
51
|
+
workspaceDisposition: retained === undefined ? attached.workspaceDisposition ?? "not-created" : { retained },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export function createReviewerAgentRunner(dependencies: Dependencies = {}): ReviewerAgentRunner {
|
|
55
|
+
const workspaceOwner = createReviewerWorkspaceOwner(dependencies.fault === undefined ? {} : { fault: dependencies.fault }); let accepted = false;
|
|
56
|
+
return {
|
|
57
|
+
async run(dispatch, options) {
|
|
58
|
+
if (dispatch.recipe !== "reviewer-common-bundle-v1" || dispatch.legs.length < 1 || dispatch.legs.length > 2 || dispatch.legs[0]?.axis !== "standards" || (dispatch.legs.length === 2 && dispatch.legs[1]?.axis !== "spec")) throw new Error("Invalid accepted Reviewer dispatch cardinality or axes");
|
|
59
|
+
if (accepted) throw new Error("Reviewer runner accepts exactly one dispatch"); accepted = true;
|
|
60
|
+
for (const leg of dispatch.legs) if (!isReviewerPromptText(leg.prompt)) throw new Error("Accepted Reviewer prompt evidence mismatch");
|
|
61
|
+
let batch;
|
|
62
|
+
try { batch = await workspaceOwner.prepare(dispatch.targetSnapshot, dispatch.legs.map(l => l.axis), options.signal); }
|
|
63
|
+
catch (error) {
|
|
64
|
+
const prepared = typeof error === "object" && error !== null && "preparedWorkspaces" in error ? (error as { preparedWorkspaces?: readonly { axis: string; path: string }[] }).preparedWorkspaces ?? [] : [];
|
|
65
|
+
const failedIndex = prepared.length;
|
|
66
|
+
const legs = Object.fromEntries(dispatch.legs.map((leg, index) => [leg.axis, failed(error, dispatch.targetSnapshot, leg.prompt, options.signal, index < failedIndex ? prepared[index]!.path : undefined)]));
|
|
67
|
+
// Siblings not yet attempted have no workspace; do not borrow the failed leg's retained path.
|
|
68
|
+
for (let index = failedIndex + 1; index < dispatch.legs.length; index += 1) { const axis = dispatch.legs[index]!.axis; legs[axis] = Object.freeze({ ...legs[axis]!, workspaceDisposition: "not-created" }); }
|
|
69
|
+
const target = Object.values(legs)[0]!.target; throw new ReviewerDispatchExecutionError(Object.freeze({ identity: dispatch.identity, target, legs: Object.freeze(legs) }) as ReviewerDispatchRunResult);
|
|
70
|
+
}
|
|
71
|
+
const settled = await Promise.allSettled(batch.workspaces.map(async workspace => {
|
|
72
|
+
const leg = dispatch.legs.find(candidate => candidate.axis === workspace.axis)!;
|
|
73
|
+
try {
|
|
74
|
+
const child = await executeReviewerChild(workspace.path, leg, options.context, {
|
|
75
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
76
|
+
...(dependencies.credentialScratchParent === undefined
|
|
77
|
+
? {}
|
|
78
|
+
: { credentialScratchParent: dependencies.credentialScratchParent }),
|
|
79
|
+
});
|
|
80
|
+
const disposition = await workspaceOwner.dispose(workspace);
|
|
81
|
+
return [leg.axis, Object.freeze({ status: "successful" as const, report: child.report, usage: child.usage, target: batch.target, prompt: child.prompt, workspaceDisposition: disposition })] as const;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
// Failed legs retain their workspace for the durable failure evidence and caller cleanup.
|
|
84
|
+
return [leg.axis, failed(error, batch.target, leg.prompt, options.signal, workspace.path)] as const;
|
|
85
|
+
}
|
|
86
|
+
}));
|
|
87
|
+
const pairs = settled.map(item => item.status === "fulfilled" ? item.value : (() => { throw item.reason; })());
|
|
88
|
+
const outcome = Object.freeze({ identity: dispatch.identity, target: batch.target, legs: Object.freeze(Object.fromEntries(pairs)) }) as ReviewerDispatchRunResult;
|
|
89
|
+
if (Object.values(outcome.legs).some(leg => leg?.status === "failed")) throw new ReviewerDispatchExecutionError(outcome);
|
|
90
|
+
return outcome as ReviewerSuccessfulDispatchRunResult;
|
|
91
|
+
},
|
|
92
|
+
shutdown: () => workspaceOwner.shutdown(),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
import { auditorRunDirectory } from "./auditor-dossier-tool.ts";
|
|
4
|
+
import { loadAuditorSoul } from "./auditor-soul.ts";
|
|
5
|
+
import {
|
|
6
|
+
createComplianceDecisionTool,
|
|
7
|
+
runComplianceAudit,
|
|
8
|
+
type ComplianceCompletion,
|
|
9
|
+
type ComplianceDecision,
|
|
10
|
+
} from "./compliance-transport.ts";
|
|
11
|
+
import {
|
|
12
|
+
readReviewerAuditSubjects,
|
|
13
|
+
resolveAuditDossier,
|
|
14
|
+
toAuditIncomplete,
|
|
15
|
+
} from "./dossier-resolution.ts";
|
|
16
|
+
|
|
17
|
+
export const REVIEWER_AUDIT_TOOL_NAME = "ak_reviewer_audit_decision";
|
|
18
|
+
|
|
19
|
+
export type ReviewerAuditOptions = {
|
|
20
|
+
context: ExtensionContext;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const reviewerDecisionTool = createComplianceDecisionTool(
|
|
25
|
+
REVIEWER_AUDIT_TOOL_NAME,
|
|
26
|
+
"Decide whether the Reviewer receipt demonstrably followed its method and boundaries from the dossier.",
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reviewer auditor: zero hand-delivered materials / no readiness projection.
|
|
31
|
+
* Candidate receipt must already be on the parent-session books.
|
|
32
|
+
*/
|
|
33
|
+
export function createPiReviewerAuditor(
|
|
34
|
+
runCompletion?: ComplianceCompletion,
|
|
35
|
+
): (options: ReviewerAuditOptions) => Promise<ComplianceDecision> {
|
|
36
|
+
return async (options) => {
|
|
37
|
+
const dossier = resolveAuditDossier();
|
|
38
|
+
if (dossier.status === "incomplete") return toAuditIncomplete(dossier.observation);
|
|
39
|
+
const subjects = readReviewerAuditSubjects(options.context);
|
|
40
|
+
if (subjects.status === "incomplete") return toAuditIncomplete(subjects.observation);
|
|
41
|
+
|
|
42
|
+
return runComplianceAudit({
|
|
43
|
+
tool: reviewerDecisionTool,
|
|
44
|
+
systemPrompt: await loadAuditorSoul("reviewer"),
|
|
45
|
+
roleLabel: "Reviewer compliance audit",
|
|
46
|
+
invalidDecisionLabel: "invalid reviewer audit decision",
|
|
47
|
+
...(runCompletion === undefined ? {} : { runCompletion }),
|
|
48
|
+
context: options.context,
|
|
49
|
+
...(auditorRunDirectory(options.context) === undefined ? {} : { runDirectory: auditorRunDirectory(options.context) }),
|
|
50
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { executeEvidenceChild } from "./evidence-child-executor.ts";
|
|
3
|
+
import type { AcceptedReviewerLeg } from "./reviewer-dispatch.ts";
|
|
4
|
+
|
|
5
|
+
export type ReviewerChildExecuteOptions = Readonly<{
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
credentialScratchParent?: string;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Single conversion at the Reviewer adapter boundary: shared child classifications
|
|
12
|
+
* become Reviewer failure classifications without a second error taxonomy.
|
|
13
|
+
*/
|
|
14
|
+
export function projectSharedChildFailure(error: unknown): unknown {
|
|
15
|
+
if (typeof error === "object" && error !== null && "evidenceChildFailure" in error) {
|
|
16
|
+
const classification = (error as { evidenceChildFailure?: unknown }).evidenceChildFailure;
|
|
17
|
+
if (classification === "provider" || classification === "child") {
|
|
18
|
+
Object.assign(error, { reviewerFailure: classification });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Reviewer policy adapter over the shared evidence-child lifecycle seam. */
|
|
25
|
+
export async function executeReviewerChild(workspace: string, leg: AcceptedReviewerLeg, context: ExtensionContext, options: ReviewerChildExecuteOptions = {}) {
|
|
26
|
+
try {
|
|
27
|
+
return await executeEvidenceChild(workspace, leg.prompt, context, options);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
throw projectSharedChildFailure(error);
|
|
30
|
+
}
|
|
31
|
+
}
|