@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,884 @@
|
|
|
1
|
+
import { writeSync } from "node:fs";
|
|
2
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { Value } from "typebox/value";
|
|
4
|
+
|
|
5
|
+
import { activationTraceRecordSchema, namedActivationCause, type ActivationTraceRecord, type ActivationTraceWriter } from "./activation-trace.ts";
|
|
6
|
+
import {
|
|
7
|
+
appendAcceptedActivationToBook,
|
|
8
|
+
buildAcceptedActivationFact,
|
|
9
|
+
correlationIdentityFromEnv,
|
|
10
|
+
durableSessionPointer,
|
|
11
|
+
resolveActivationLedgerHome,
|
|
12
|
+
resolveBookKeyFromGit,
|
|
13
|
+
type AcceptedActivationFact,
|
|
14
|
+
type ActivationCorrelationIdentity,
|
|
15
|
+
type ActivationSessionPointer,
|
|
16
|
+
} from "./activation-ledger.ts";
|
|
17
|
+
import { writeStderrJsonlRecord } from "./stderr-jsonl.ts";
|
|
18
|
+
import {
|
|
19
|
+
createToolExecutionObservationFace,
|
|
20
|
+
systemToolExecutionObservationMonoNow,
|
|
21
|
+
writeToolExecutionObservationRecord,
|
|
22
|
+
type ToolExecutionObservationWriter,
|
|
23
|
+
} from "./tool-execution-observation.ts";
|
|
24
|
+
import { installPackageOwnedToolRegistration } from "./package-owned-tool-idle.ts";
|
|
25
|
+
import { installWorkerGitHooks } from "./worker-submission-gates.ts";
|
|
26
|
+
|
|
27
|
+
import type { AnyCanonicalSkillBinding } from "./canonical-skill-binding.ts";
|
|
28
|
+
import type { CollectorClock } from "./collector-evidence.ts";
|
|
29
|
+
import type { CollectorGitHubTransport } from "./collector-github.ts";
|
|
30
|
+
import {
|
|
31
|
+
COLLECTOR_OBSERVE_TOOL,
|
|
32
|
+
COLLECTOR_OUTPUT_TOOL,
|
|
33
|
+
COLLECTOR_REQUEST_TOOL,
|
|
34
|
+
COLLECTOR_WAIT_TOOL,
|
|
35
|
+
createCollectorRoleRuntime,
|
|
36
|
+
} from "./collector-role.ts";
|
|
37
|
+
import type { ComplianceDecision } from "./compliance-transport.ts";
|
|
38
|
+
import { createDoctorRoleRuntime } from "./doctor-role.ts";
|
|
39
|
+
import { decorateSettlementWithNavigation, formatNavigatorReport, NAVIGATOR_EVENT_TYPE, navigatorSubjectKey, navigatorUnavailableError, subjectPath, type NavigatorAttendance, type NavigatorEvent, type NavigatorPhase, type NavigatorReport, type NavigatorSettlement, type NavigatorSubjectProvenance, type NavigatorWorkContext } from "./navigator-attendance.ts";
|
|
40
|
+
import {
|
|
41
|
+
buildNavigatorInfrastructureFailureFact,
|
|
42
|
+
classifyPackagedRoleTerminalResult,
|
|
43
|
+
NAVIGATOR_INVOCATION_ENTRY,
|
|
44
|
+
resolveLifecycleInvocationPrincipal,
|
|
45
|
+
} from "./navigator-invocation-identity.ts";
|
|
46
|
+
import { recordTypedProviderHttpStatus } from "./public-cli/run-lifecycle.ts";
|
|
47
|
+
import { NAVIGATOR_POST_ROLE_GRACE_MS, raceNavigatorGrace } from "./public-cli/settlement.ts";
|
|
48
|
+
import { PACKAGED_ROLE_REGISTRY, packagedRoleMetadata, packagedRoleOutputTool, packagedRolePhaseFlag, type PackagedRole } from "./packaged-role-registry.ts";
|
|
49
|
+
import { isAuditEscalationProjection } from "./audit-escalation.ts";
|
|
50
|
+
import {
|
|
51
|
+
createJudgeRoleRuntime,
|
|
52
|
+
type SoulAuditResult,
|
|
53
|
+
} from "./judge-role.ts";
|
|
54
|
+
import {
|
|
55
|
+
createReviewerRoleRuntime,
|
|
56
|
+
type ReviewerActivation,
|
|
57
|
+
} from "./reviewer-role.ts";
|
|
58
|
+
import type { AcceptedReviewerExecution, ReviewerPinnedGitReader } from "./reviewer-dispatch.ts";
|
|
59
|
+
import type { ReviewerDispatchRunResult } from "./reviewer-agent.ts";
|
|
60
|
+
import {
|
|
61
|
+
CODER_OUTPUT_TOOL_NAME,
|
|
62
|
+
createCoderRoleRuntime,
|
|
63
|
+
createFixerRoleRuntime,
|
|
64
|
+
FIXER_FLAG_DEFINITIONS,
|
|
65
|
+
FIXER_OUTPUT_TOOL_NAME,
|
|
66
|
+
FIXER_PHASES,
|
|
67
|
+
} from "./worker-role.ts";
|
|
68
|
+
import { JUDGE_OUTPUT_TOOL_NAME } from "./package-contracts/judge-output.ts";
|
|
69
|
+
import { REVIEWER_OUTPUT_TOOL_NAME } from "./package-contracts/reviewer-output.ts";
|
|
70
|
+
import { DOCTOR_OUTPUT_TOOL_NAME } from "./doctor-contracts.ts";
|
|
71
|
+
import { MERGER_OUTPUT_TOOL_NAME } from "./merger-contracts.ts";
|
|
72
|
+
import { createMergerRoleRuntime, type MergerRoleDependencies } from "./merger-role.ts";
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
buildNavigatorInfrastructureFailureFact,
|
|
76
|
+
classifyPackagedRoleTerminalResult,
|
|
77
|
+
isAcceptedPackagedRoleTerminalResult,
|
|
78
|
+
isDurablePackagedRoleTerminalResult,
|
|
79
|
+
isNavigatorInfrastructureFailureFact,
|
|
80
|
+
NAVIGATOR_INFRASTRUCTURE_FAILURE_KIND,
|
|
81
|
+
type NavigatorInfrastructureFailureFact,
|
|
82
|
+
type PackagedRoleTerminalClassification,
|
|
83
|
+
} from "./navigator-invocation-identity.ts";
|
|
84
|
+
export { activationTraceRecordSchema, namedActivationCause } from "./activation-trace.ts";
|
|
85
|
+
export type { ActivationTraceRecord, ActivationTraceWriter } from "./activation-trace.ts";
|
|
86
|
+
export {
|
|
87
|
+
ACCEPTED_ACTIVATION_EVENT,
|
|
88
|
+
ACCEPTED_ACTIVATION_FACT_KEYS,
|
|
89
|
+
ActivationGitRepositoryRequiredError,
|
|
90
|
+
ActivationLedgerError,
|
|
91
|
+
ActivationSessionFileMissingError,
|
|
92
|
+
activationBookDirectory,
|
|
93
|
+
activationWaitingLedgerPath,
|
|
94
|
+
appendAcceptedActivationFact,
|
|
95
|
+
appendAcceptedActivationToBook,
|
|
96
|
+
buildAcceptedActivationFact,
|
|
97
|
+
correlationIdentityFromEnv,
|
|
98
|
+
durableSessionPointer,
|
|
99
|
+
resolveActivationLedgerHome,
|
|
100
|
+
resolveBookKeyFromGit,
|
|
101
|
+
serializeAcceptedActivationFact,
|
|
102
|
+
} from "./activation-ledger.ts";
|
|
103
|
+
export type {
|
|
104
|
+
AcceptedActivationFact,
|
|
105
|
+
AcceptedActivationFactInput,
|
|
106
|
+
AcceptedActivationFactKey,
|
|
107
|
+
ActivationCorrelationIdentity,
|
|
108
|
+
ActivationSessionManager,
|
|
109
|
+
ActivationSessionPointer,
|
|
110
|
+
} from "./activation-ledger.ts";
|
|
111
|
+
export {
|
|
112
|
+
DISPATCH_STUB_EVENT,
|
|
113
|
+
buildDispatchStubFact,
|
|
114
|
+
reconcileInvocation,
|
|
115
|
+
} from "./activation-reconciliation.ts";
|
|
116
|
+
export type {
|
|
117
|
+
DispatchPointer,
|
|
118
|
+
DispatchStubFact,
|
|
119
|
+
DispatchStubFactInput,
|
|
120
|
+
ProcessLivenessFact,
|
|
121
|
+
ReconciliationOutcome,
|
|
122
|
+
ReconciliationSubject,
|
|
123
|
+
} from "./activation-reconciliation.ts";
|
|
124
|
+
export {
|
|
125
|
+
TOOL_EXECUTION_UPDATE_HEARTBEAT,
|
|
126
|
+
TOOL_EXECUTION_UPDATE_THROTTLE_MS,
|
|
127
|
+
createToolExecutionObservationFace,
|
|
128
|
+
isProducingToolUpdate,
|
|
129
|
+
systemToolExecutionObservationMonoNow,
|
|
130
|
+
toolExecutionObservationRecordSchema,
|
|
131
|
+
validateToolExecutionObservationRecord,
|
|
132
|
+
writeToolExecutionObservationRecord,
|
|
133
|
+
} from "./tool-execution-observation.ts";
|
|
134
|
+
export type { ToolExecutionObservationRecord, ToolExecutionObservationWriter } from "./tool-execution-observation.ts";
|
|
135
|
+
export { executeAuditorChild } from "./evidence-child-executor.ts";
|
|
136
|
+
export type { AuditorCompletion, AuditorDecisionTool } from "./evidence-child-executor.ts";
|
|
137
|
+
|
|
138
|
+
export {
|
|
139
|
+
DOCTOR_EVIDENCE_TOOL_NAME,
|
|
140
|
+
DOCTOR_OUTPUT_TOOL_NAME,
|
|
141
|
+
} from "./doctor-role.ts";
|
|
142
|
+
export type { DoctorCase, DoctorCaseCost, DoctorSubmission, DoctorOutput, DoctorFinding } from "./doctor-contracts.ts";
|
|
143
|
+
export { validateDoctorSubmissionShape, validateDoctorOutput, DoctorEvidenceStore } from "./doctor-contracts.ts";
|
|
144
|
+
export { loadDoctorCase } from "./doctor-evidence.ts";
|
|
145
|
+
export {
|
|
146
|
+
JUDGE_OUTPUT_TOOL_NAME,
|
|
147
|
+
type JudgeVerdict,
|
|
148
|
+
type SoulAuditResult,
|
|
149
|
+
} from "./judge-role.ts";
|
|
150
|
+
export {
|
|
151
|
+
AGENT_TOOL_NAME,
|
|
152
|
+
REVIEWER_OUTPUT_TOOL_NAME,
|
|
153
|
+
type ReviewerIntent,
|
|
154
|
+
} from "./reviewer-role.ts";
|
|
155
|
+
export {
|
|
156
|
+
CODER_OUTPUT_TOOL_NAME,
|
|
157
|
+
FIXER_FLAG_DEFINITIONS,
|
|
158
|
+
FIXER_OUTPUT_TOOL_NAME,
|
|
159
|
+
FIXER_PHASES,
|
|
160
|
+
type CoderOutput,
|
|
161
|
+
type FixerOutput,
|
|
162
|
+
type WorkerOutput,
|
|
163
|
+
} from "./worker-role.ts";
|
|
164
|
+
export { fixerOutputSchema, validateFixerOutput, validateFixerOutputForPacket } from "./package-contracts/fixer-output.ts";
|
|
165
|
+
export type { FixerBlocker, FixerClassResult, FixerPhase, FixerTestEvidence } from "./package-contracts/fixer-output.ts";
|
|
166
|
+
export { fixerPrerequisiteSchema, fixerPrerequisitesSchema, parseFixerPrerequisites, validateFixerPrerequisites } from "./package-contracts/fixer-packet.ts";
|
|
167
|
+
export type { FixerInvocationInput, FixerPrerequisite } from "./package-contracts/fixer-packet.ts";
|
|
168
|
+
export { AUDIT_ESCALATION_KIND, buildAuditEscalationResult, disposeComplianceDecision, isAuditEscalationResult, projectAuditEscalation } from "./audit-escalation.ts";
|
|
169
|
+
export type { AuditEscalationResult, AuditEscalationToolResult, ComplianceDecisionHandlers } from "./audit-escalation.ts";
|
|
170
|
+
export { AUDITOR_SOUL_ROLES, loadAuditorSoul } from "./auditor-soul.ts";
|
|
171
|
+
export type { AuditorSoulRole } from "./auditor-soul.ts";
|
|
172
|
+
export { JUDGE_AUDIT_TOOL_NAME, SOUL_AUDIT_TOOL_NAME, createPiJudgeAuditor } from "./judge-auditor.ts";
|
|
173
|
+
export { REVIEWER_AUDIT_TOOL_NAME, createPiReviewerAuditor } from "./reviewer-auditor.ts";
|
|
174
|
+
export { DOCTOR_AUDIT_TOOL_NAME, createPiDoctorAuditor } from "./doctor-auditor.ts";
|
|
175
|
+
export type { ComplianceDecision } from "./compliance-transport.ts";
|
|
176
|
+
export {
|
|
177
|
+
COLLECTOR_OBSERVE_TOOL,
|
|
178
|
+
COLLECTOR_OUTPUT_TOOL,
|
|
179
|
+
COLLECTOR_REQUEST_TOOL,
|
|
180
|
+
COLLECTOR_WAIT_TOOL,
|
|
181
|
+
} from "./collector-role.ts";
|
|
182
|
+
export type {
|
|
183
|
+
ReviewerExecutionRecord,
|
|
184
|
+
ReviewerTargetSnapshot,
|
|
185
|
+
ReviewerUsage,
|
|
186
|
+
ReviewerWorkspaceDisposition,
|
|
187
|
+
} from "./reviewer-execution-ledger.ts";
|
|
188
|
+
export type { AcceptedReviewerDispatch, AcceptedReviewerExecution, ReviewerPinnedGitReader } from "./reviewer-dispatch.ts";
|
|
189
|
+
export type { ReviewerDispatchRunResult } from "./reviewer-agent.ts";
|
|
190
|
+
export type { CollectorReceipt } from "./collector-receipt.ts";
|
|
191
|
+
export type { CollectorGitHubTransport } from "./collector-github.ts";
|
|
192
|
+
export type { CollectorClock } from "./collector-evidence.ts";
|
|
193
|
+
export * from "./navigator-attendance.ts";
|
|
194
|
+
export { MERGER_INPUT_FLAG, MERGER_ACTIVE_TOOLS, createMergerRoleRuntime } from "./merger-role.ts";
|
|
195
|
+
export { MERGER_OUTPUT_TOOL_NAME, mergerInputSchema, mergerOutputSchema, validateMergerInput, validateMergerOutput } from "./merger-contracts.ts";
|
|
196
|
+
export type { MergerInput, MergerMaterial, MergerOutput } from "./merger-contracts.ts";
|
|
197
|
+
export { createProductionMergerGitState } from "./merger-git-state.ts";
|
|
198
|
+
export type { MergerGitState, ActiveMergerGitState, CompletedMergerGitState } from "./merger-git-state.ts";
|
|
199
|
+
export type { MergerRoleDependencies } from "./merger-role.ts";
|
|
200
|
+
|
|
201
|
+
type WorkerArmable = {
|
|
202
|
+
activate(context?: ExtensionContext): Promise<void>;
|
|
203
|
+
armSubmissionGate(cwd: string, parent?: { getSessionFile(): string | undefined }): void;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
type ActivationRuntime = {
|
|
207
|
+
event: { reason: string };
|
|
208
|
+
context: ExtensionContext;
|
|
209
|
+
judge: { activate(): Promise<void> };
|
|
210
|
+
fixer: WorkerArmable;
|
|
211
|
+
coder: WorkerArmable;
|
|
212
|
+
reviewer: { activate(context: ExtensionContext): Promise<ReviewerActivation> };
|
|
213
|
+
collector: { activate(context: ExtensionContext, event: { reason: string }): Promise<void> };
|
|
214
|
+
doctor: { activate(): Promise<void> };
|
|
215
|
+
merger(): Promise<void>;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
function activationStage(role: PackagedRole, runtime: ActivationRuntime): { id: string; run(): Promise<void> } {
|
|
219
|
+
switch (role) {
|
|
220
|
+
case "judge": return { id: "load-and-install", run: async () => runtime.judge.activate() };
|
|
221
|
+
case "fixer": return { id: "load-and-install", run: async () => runtime.fixer.activate() };
|
|
222
|
+
case "coder": return { id: "load-and-install", run: async () => runtime.coder.activate(runtime.context) };
|
|
223
|
+
case "reviewer": return { id: "load-install-and-dispatch", run: async () => {
|
|
224
|
+
const activation = await runtime.reviewer.activate(runtime.context);
|
|
225
|
+
const result = await activation.dispatcher.dispatch(activation.fixedBaseRevision, { context: runtime.context });
|
|
226
|
+
if (result.status !== "accepted") throw new Error(`Fixed Reviewer dispatch was not accepted: ${result.status}`);
|
|
227
|
+
} };
|
|
228
|
+
case "collector": return { id: "load-and-install", run: async () => runtime.collector.activate(runtime.context, runtime.event) };
|
|
229
|
+
case "doctor": return { id: "load-and-install", run: async () => runtime.doctor.activate() };
|
|
230
|
+
case "merger": return { id: "prepare-git-and-install", run: async () => runtime.merger() };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function validateActivationTraceRecord(record: unknown): ActivationTraceRecord {
|
|
235
|
+
if (!Value.Check(activationTraceRecordSchema, record)) {
|
|
236
|
+
throw new TypeError("Activation trace record does not match its closed contract");
|
|
237
|
+
}
|
|
238
|
+
return record as ActivationTraceRecord;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function emitActivationTrace(
|
|
242
|
+
writeTrace: (record: ActivationTraceRecord) => void | Promise<void>,
|
|
243
|
+
record: unknown,
|
|
244
|
+
): Promise<void> {
|
|
245
|
+
await writeTrace(validateActivationTraceRecord(record));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function executeActivationStage(
|
|
249
|
+
role: string,
|
|
250
|
+
stage: { id: string; run(): Promise<void> },
|
|
251
|
+
infrastructure: { clock(): string; writeTrace(record: ActivationTraceRecord): void | Promise<void> },
|
|
252
|
+
): Promise<void> {
|
|
253
|
+
try {
|
|
254
|
+
await stage.run();
|
|
255
|
+
} catch (activationError) {
|
|
256
|
+
try {
|
|
257
|
+
await emitActivationTrace(infrastructure.writeTrace, {
|
|
258
|
+
role,
|
|
259
|
+
stageId: stage.id,
|
|
260
|
+
status: "failed",
|
|
261
|
+
timestamp: infrastructure.clock(),
|
|
262
|
+
cause: namedActivationCause(activationError),
|
|
263
|
+
});
|
|
264
|
+
} catch (traceError) {
|
|
265
|
+
throw new AggregateError([activationError, traceError], `Activation stage ${stage.id} failed and its failure trace could not be emitted`);
|
|
266
|
+
}
|
|
267
|
+
throw activationError;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function writeActivationTraceRecord(
|
|
272
|
+
record: ActivationTraceRecord,
|
|
273
|
+
write: typeof writeSync = writeSync,
|
|
274
|
+
): void {
|
|
275
|
+
writeStderrJsonlRecord(record, write);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export class ActivationBarrierError extends Error {
|
|
279
|
+
readonly code = "AK_ACTIVATION_NOT_ADMITTED";
|
|
280
|
+
constructor(role: unknown) {
|
|
281
|
+
super(`Workflow role ${String(role)} activation did not complete`);
|
|
282
|
+
this.name = "ActivationBarrierError";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export const WORKFLOW_ROLES = PACKAGED_ROLE_REGISTRY.map(({ role }) => role) as Array<(typeof PACKAGED_ROLE_REGISTRY)[number]["role"]>;
|
|
287
|
+
export const ROLE_FLAG = {
|
|
288
|
+
name: "ak-role",
|
|
289
|
+
definition: {
|
|
290
|
+
description: `Activate a packaged workflow role: ${WORKFLOW_ROLES.slice(0, -1).join(", ")}, or ${WORKFLOW_ROLES.at(-1)}`,
|
|
291
|
+
type: "string" as const,
|
|
292
|
+
},
|
|
293
|
+
} as const;
|
|
294
|
+
|
|
295
|
+
type NavigatorAttendanceDependency = Omit<NavigatorAttendance, "knownRoutePlaybookReadFailure"> &
|
|
296
|
+
Partial<Pick<NavigatorAttendance, "knownRoutePlaybookReadFailure">>;
|
|
297
|
+
|
|
298
|
+
export type RoleRuntimeDependencies = {
|
|
299
|
+
loadJudgeSoul(): Promise<string>;
|
|
300
|
+
loadFixerSoul?(): Promise<string>;
|
|
301
|
+
loadFixPacket?(path: string): Promise<string>;
|
|
302
|
+
loadCoderSoul?(): Promise<string>;
|
|
303
|
+
loadCoderTask?(path: string): Promise<string>;
|
|
304
|
+
loadReviewerSoul?(): Promise<string>;
|
|
305
|
+
createReviewerPinnedGitReader?(): Promise<ReviewerPinnedGitReader>;
|
|
306
|
+
loadCollectorSoul?(): Promise<string>;
|
|
307
|
+
createCollectorTransport?(): CollectorGitHubTransport;
|
|
308
|
+
loadDoctorSoul?(): Promise<string>;
|
|
309
|
+
loadDoctorCase?(path: string): Promise<import("./doctor-contracts.ts").DoctorCase>;
|
|
310
|
+
loadMergerSoul?(): Promise<string>;
|
|
311
|
+
loadMergerInput?(path: string): Promise<unknown>;
|
|
312
|
+
mergerGitState?: MergerRoleDependencies["gitState"];
|
|
313
|
+
createMergerGitState?(repositoryRoot: string): MergerRoleDependencies["gitState"];
|
|
314
|
+
auditDoctorCompliance?(options: { context: ExtensionContext; signal?: AbortSignal }): Promise<ComplianceDecision>;
|
|
315
|
+
createCollectorClock?(): CollectorClock;
|
|
316
|
+
collectorPackageExtensionPath?: string;
|
|
317
|
+
createNavigatorAttendance?(options: { context: ExtensionContext; role: string; phase: NavigatorPhase; subjectKey: string; subject: string; authority: string; contextError?: unknown; sessionDirectory?: (subjectKey: string) => string; invocationId: string; onEvent: (event: import("./navigator-attendance.ts").NavigatorEvent, report: import("./navigator-attendance.ts").NavigatorReport) => void | Promise<void> }): NavigatorAttendanceDependency | Promise<NavigatorAttendanceDependency>;
|
|
318
|
+
loadNavigatorWorkContext?(options: { context: ExtensionContext; role: string; phase: NavigatorPhase }): Promise<NavigatorWorkContext>;
|
|
319
|
+
loadCanonicalSkillBinding?(
|
|
320
|
+
name: "tdd" | "code-review",
|
|
321
|
+
): Promise<AnyCanonicalSkillBinding>;
|
|
322
|
+
runReviewerDispatch?(
|
|
323
|
+
dispatch: AcceptedReviewerExecution,
|
|
324
|
+
options: { context: ExtensionContext; signal?: AbortSignal },
|
|
325
|
+
): Promise<ReviewerDispatchRunResult>;
|
|
326
|
+
shutdownReviewerAgent?(): Promise<void>;
|
|
327
|
+
transcriptFromContext(ctx: ExtensionContext): string;
|
|
328
|
+
auditSoulCompliance(
|
|
329
|
+
options: { context: ExtensionContext; signal?: AbortSignal },
|
|
330
|
+
): Promise<SoulAuditResult>;
|
|
331
|
+
auditReviewerCompliance?(
|
|
332
|
+
options: { context: ExtensionContext; signal?: AbortSignal },
|
|
333
|
+
): Promise<ComplianceDecision>;
|
|
334
|
+
activationClock?(): string;
|
|
335
|
+
activationTraceWriter?: (record: ActivationTraceRecord) => void | Promise<void>;
|
|
336
|
+
/** Wall-clock ISO timestamps for tool-execution observation records; defaults to activationClock/Date. */
|
|
337
|
+
toolExecutionObservationClock?(): string;
|
|
338
|
+
/** Monotonic ms clock for update throttling; defaults to performance.now (not Date.now). */
|
|
339
|
+
toolExecutionObservationMonoNow?(): number;
|
|
340
|
+
toolExecutionObservationWriter?: ToolExecutionObservationWriter;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
function abortContext(ctx: ExtensionContext): void {
|
|
344
|
+
const abort = (ctx as ExtensionContext & { abort?: () => void }).abort;
|
|
345
|
+
if (typeof abort === "function") abort.call(ctx);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function failInfrastructure(error: unknown, ctx: ExtensionContext): never {
|
|
349
|
+
abortContext(ctx);
|
|
350
|
+
if (ctx.mode === "print" || ctx.mode === "json") process.exitCode = 1;
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function navigatorPhase(pi: ExtensionAPI, role: string): NavigatorPhase {
|
|
355
|
+
const metadata = packagedRoleMetadata(role);
|
|
356
|
+
if (metadata === undefined || metadata.phases[0] === null) return null;
|
|
357
|
+
const phaseFlag = packagedRolePhaseFlag(role);
|
|
358
|
+
const requested = phaseFlag === undefined ? undefined : pi.getFlag(phaseFlag);
|
|
359
|
+
return requested === "apply" ? "apply" : "plan";
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function navigatorOutputTool(role: string): string | undefined {
|
|
363
|
+
return packagedRoleOutputTool(role);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function publicNavigatorSettlement(role: string, phase: NavigatorPhase, event: { toolName: string; isError?: unknown; details: unknown }): NavigatorSettlement | undefined {
|
|
367
|
+
// One shared classifier owns terminal discriminant (lifecycle + settlement + extractors).
|
|
368
|
+
if (event.toolName !== navigatorOutputTool(role)) return undefined;
|
|
369
|
+
const classification = classifyPackagedRoleTerminalResult(event);
|
|
370
|
+
if (classification.kind === "nonterminal") return undefined;
|
|
371
|
+
if (classification.kind === "infrastructure") {
|
|
372
|
+
return { kind: "role_infrastructure_failure", role, phase };
|
|
373
|
+
}
|
|
374
|
+
// accepted/human — project role/phase status; classifier already rejected infra/contradiction.
|
|
375
|
+
const details = typeof event.details === "object" && event.details !== null && !Array.isArray(event.details)
|
|
376
|
+
? event.details as Record<string, unknown>
|
|
377
|
+
: {};
|
|
378
|
+
// Live Navigator consumes only the audit-owned projection; persisted/replayed
|
|
379
|
+
// records are re-authenticated by settlement against retained audit evidence.
|
|
380
|
+
if (isAuditEscalationProjection(event.details)) {
|
|
381
|
+
return { kind: "human_decision", role, phase, status: "audit_escalation" };
|
|
382
|
+
}
|
|
383
|
+
const status = typeof details.status === "string"
|
|
384
|
+
? details.status
|
|
385
|
+
: typeof details.judgeStatus === "string" ? details.judgeStatus : undefined;
|
|
386
|
+
if (status === "escalate") {
|
|
387
|
+
return { kind: "human_decision", role, phase, status };
|
|
388
|
+
}
|
|
389
|
+
return { kind: "accepted", role, phase, ...(status === undefined ? {} : { status }) };
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function createRoleRuntimeExtension(
|
|
393
|
+
dependencies: RoleRuntimeDependencies,
|
|
394
|
+
): (pi: ExtensionAPI) => void {
|
|
395
|
+
return (pi) => {
|
|
396
|
+
// #102: one shared package-owned tool registration surface for all role runtimes.
|
|
397
|
+
installPackageOwnedToolRegistration(pi);
|
|
398
|
+
pi.registerFlag(ROLE_FLAG.name, ROLE_FLAG.definition);
|
|
399
|
+
|
|
400
|
+
let admitted = false;
|
|
401
|
+
let selectedRole: string | undefined;
|
|
402
|
+
let navigatorAttendance: NavigatorAttendanceDependency | undefined;
|
|
403
|
+
let pendingNavigatorPresentation: { event: import("./navigator-attendance.ts").NavigatorEvent; report: import("./navigator-attendance.ts").NavigatorReport } | undefined;
|
|
404
|
+
let pendingNavigatorSettlement: Promise<void> | undefined;
|
|
405
|
+
let navigatorWorkContext: NavigatorWorkContext | undefined;
|
|
406
|
+
const pendingInfrastructureToolCallIds = new Set<string>();
|
|
407
|
+
pi.on("input", () => {
|
|
408
|
+
const role = pi.getFlag(ROLE_FLAG.name);
|
|
409
|
+
if (role !== undefined && !admitted) return { action: "handled" as const };
|
|
410
|
+
return { action: "continue" as const };
|
|
411
|
+
});
|
|
412
|
+
pi.on("before_agent_start", (event, ctx) => {
|
|
413
|
+
const role = pi.getFlag(ROLE_FLAG.name);
|
|
414
|
+
if (role === undefined) return;
|
|
415
|
+
if (!admitted || selectedRole !== role) {
|
|
416
|
+
failInfrastructure(new ActivationBarrierError(role), ctx);
|
|
417
|
+
}
|
|
418
|
+
if (navigatorAttendance !== undefined && navigatorWorkContext !== undefined && navigatorWorkContext.contextError === undefined) {
|
|
419
|
+
// Flagged roles already have a concrete packet/task/case/review input.
|
|
420
|
+
// A bare Judge (and other bare packaged entrypoint) gets its concrete
|
|
421
|
+
// user task at this seam; do not copy the assembled system prompt.
|
|
422
|
+
// Replacement is keyed by typed subject provenance, never prose prefixes.
|
|
423
|
+
// Soft session_start placeholders (no materials yet) recover here; hard
|
|
424
|
+
// contextError from true loader failures stays poisoned and honest.
|
|
425
|
+
if (navigatorWorkContext.subjectProvenance === "placeholder") {
|
|
426
|
+
const subject = event.prompt.trim();
|
|
427
|
+
if (subject !== "") {
|
|
428
|
+
const root = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
429
|
+
const subjectProvenance = "user_prompt" satisfies NavigatorSubjectProvenance;
|
|
430
|
+
const priorAuthority = navigatorWorkContext.authority;
|
|
431
|
+
const authority = typeof priorAuthority === "string" && priorAuthority.trim() !== ""
|
|
432
|
+
? priorAuthority
|
|
433
|
+
: subject;
|
|
434
|
+
navigatorWorkContext = {
|
|
435
|
+
subjectKey: navigatorSubjectKey(root, subject, subjectProvenance),
|
|
436
|
+
subject,
|
|
437
|
+
authority,
|
|
438
|
+
subjectProvenance,
|
|
439
|
+
};
|
|
440
|
+
navigatorAttendance.setWorkContext(navigatorWorkContext);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
navigatorAttendance?.prepare();
|
|
445
|
+
});
|
|
446
|
+
pi.on("tool_result", async (event) => {
|
|
447
|
+
const role = selectedRole;
|
|
448
|
+
if (role === undefined || navigatorAttendance === undefined) return;
|
|
449
|
+
const isRoleInfrastructureFailure = pendingInfrastructureToolCallIds.delete(event.toolCallId);
|
|
450
|
+
// Overlay typed infra fact so live settlement and durable session entry agree.
|
|
451
|
+
const infrastructureDetails = isRoleInfrastructureFailure
|
|
452
|
+
? buildNavigatorInfrastructureFailureFact()
|
|
453
|
+
: undefined;
|
|
454
|
+
const classified = infrastructureDetails === undefined
|
|
455
|
+
? event
|
|
456
|
+
: { ...event, details: infrastructureDetails };
|
|
457
|
+
const settlement = publicNavigatorSettlement(
|
|
458
|
+
role,
|
|
459
|
+
navigatorPhase(pi, role),
|
|
460
|
+
classified,
|
|
461
|
+
);
|
|
462
|
+
if (settlement !== undefined) {
|
|
463
|
+
const attendance = navigatorAttendance;
|
|
464
|
+
const workContext = navigatorWorkContext;
|
|
465
|
+
const pending = (async () => {
|
|
466
|
+
// Accepted role terminal starts the post-role Navigator grace (#101/#106).
|
|
467
|
+
if (settlement.kind !== "accepted") {
|
|
468
|
+
await attendance.settle(settlement);
|
|
469
|
+
// Emission stays on agent_settled (normal completion) or session_shutdown
|
|
470
|
+
// flush (abort/infrastructure teardown that skips agent_settled).
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const settlePromise = attendance.settle(settlement);
|
|
474
|
+
const raced = await raceNavigatorGrace(settlePromise, NAVIGATOR_POST_ROLE_GRACE_MS);
|
|
475
|
+
if (raced.status === "timeout") {
|
|
476
|
+
if (pendingNavigatorPresentation === undefined) {
|
|
477
|
+
const routePlaybookReadFailure = attendance.knownRoutePlaybookReadFailure?.();
|
|
478
|
+
const report: NavigatorReport = {
|
|
479
|
+
disposition: "unavailable",
|
|
480
|
+
unavailableReason: "Navigator exceeded post-role delivery grace",
|
|
481
|
+
unavailableSource: "unknown",
|
|
482
|
+
unavailableCause: "unknown",
|
|
483
|
+
...(routePlaybookReadFailure === undefined ? {} : { routePlaybookReadFailure }),
|
|
484
|
+
};
|
|
485
|
+
const navigatorEvent: NavigatorEvent = {
|
|
486
|
+
version: 1,
|
|
487
|
+
disposition: "unavailable",
|
|
488
|
+
invocationId: "post-role-grace-timeout",
|
|
489
|
+
role,
|
|
490
|
+
phase: navigatorPhase(pi, role),
|
|
491
|
+
subjectKey: workContext?.subjectKey ?? "",
|
|
492
|
+
unavailableReason: "Navigator exceeded post-role delivery grace",
|
|
493
|
+
unavailableSource: "unknown",
|
|
494
|
+
unavailableCause: "unknown",
|
|
495
|
+
...(routePlaybookReadFailure === undefined ? {} : { routePlaybookReadFailure }),
|
|
496
|
+
};
|
|
497
|
+
pendingNavigatorPresentation = { event: navigatorEvent, report };
|
|
498
|
+
}
|
|
499
|
+
attendance.dispose();
|
|
500
|
+
void settlePromise.catch(() => undefined);
|
|
501
|
+
}
|
|
502
|
+
})();
|
|
503
|
+
pendingNavigatorSettlement = pending;
|
|
504
|
+
await pending;
|
|
505
|
+
}
|
|
506
|
+
// Persist typed infrastructure-failure fact onto the role session toolResult so
|
|
507
|
+
// exact-session restart shares the same durable completion classification.
|
|
508
|
+
if (infrastructureDetails !== undefined) {
|
|
509
|
+
return { details: infrastructureDetails, isError: true };
|
|
510
|
+
}
|
|
511
|
+
// Recommendation rides the accepted settlement record's content so the one
|
|
512
|
+
// mandatory last-ak_*_output extraction surfaces route/next/reason without
|
|
513
|
+
// a second file, grep, or nesting step. Receipt details stay contract-pure;
|
|
514
|
+
// unavailable/no-advice leave the settlement untouched.
|
|
515
|
+
if (event.isError) return;
|
|
516
|
+
const decorated = decorateSettlementWithNavigation(event, pendingNavigatorPresentation);
|
|
517
|
+
if (decorated === undefined) return;
|
|
518
|
+
return {
|
|
519
|
+
content: decorated.content as typeof event.content,
|
|
520
|
+
};
|
|
521
|
+
});
|
|
522
|
+
pi.on("agent_settled", async () => {
|
|
523
|
+
if (pendingNavigatorSettlement !== undefined) {
|
|
524
|
+
await pendingNavigatorSettlement;
|
|
525
|
+
}
|
|
526
|
+
// Do not auto-drain Navigator on ordinary mid-turn agent_settled.
|
|
527
|
+
// Multi-turn roles (#162 coder) fire agent_settled after every tool turn;
|
|
528
|
+
// discarding a healthy/in-flight prepare there forces a cold prepare on the
|
|
529
|
+
// final accepted terminal and races the post-role grace. Keep preparation
|
|
530
|
+
// until an accepted/human/infrastructure tool_result settlement (or dispose).
|
|
531
|
+
// Provider death without any role tool_result leaves preparation held; the
|
|
532
|
+
// next explicit settlement or session end owns it — not mid-turn churn.
|
|
533
|
+
pendingNavigatorSettlement = undefined;
|
|
534
|
+
const presentation = pendingNavigatorPresentation;
|
|
535
|
+
pendingNavigatorPresentation = undefined;
|
|
536
|
+
if (presentation === undefined) return;
|
|
537
|
+
await pi.sendMessage({
|
|
538
|
+
customType: NAVIGATOR_EVENT_TYPE,
|
|
539
|
+
content: formatNavigatorReport(presentation.report),
|
|
540
|
+
display: true,
|
|
541
|
+
details: presentation.event,
|
|
542
|
+
}, { triggerTurn: false });
|
|
543
|
+
});
|
|
544
|
+
pi.on("session_shutdown", async () => {
|
|
545
|
+
// Flush any still-pending affirmative attendance before teardown. Accepted
|
|
546
|
+
// grace-timeout paths normally emit on agent_settled; abort can skip that hook.
|
|
547
|
+
const presentation = pendingNavigatorPresentation;
|
|
548
|
+
pendingNavigatorPresentation = undefined;
|
|
549
|
+
if (presentation !== undefined) {
|
|
550
|
+
try {
|
|
551
|
+
await pi.sendMessage({
|
|
552
|
+
customType: NAVIGATOR_EVENT_TYPE,
|
|
553
|
+
content: formatNavigatorReport(presentation.report),
|
|
554
|
+
display: true,
|
|
555
|
+
details: presentation.event,
|
|
556
|
+
}, { triggerTurn: false });
|
|
557
|
+
} catch {
|
|
558
|
+
// Teardown must not mask the original role failure cause.
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
navigatorAttendance?.dispose();
|
|
562
|
+
navigatorAttendance = undefined;
|
|
563
|
+
pendingNavigatorSettlement = undefined;
|
|
564
|
+
pendingInfrastructureToolCallIds.clear();
|
|
565
|
+
observationFace.reset();
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
const hostActions = {
|
|
569
|
+
failInfrastructure(error: unknown, ctx: ExtensionContext, toolCallId?: string): never {
|
|
570
|
+
if (toolCallId !== undefined) {
|
|
571
|
+
pendingInfrastructureToolCallIds.add(toolCallId);
|
|
572
|
+
}
|
|
573
|
+
failInfrastructure(error, ctx);
|
|
574
|
+
},
|
|
575
|
+
};
|
|
576
|
+
const judge = createJudgeRoleRuntime(
|
|
577
|
+
pi,
|
|
578
|
+
{
|
|
579
|
+
loadSoul: dependencies.loadJudgeSoul,
|
|
580
|
+
auditSoulCompliance: dependencies.auditSoulCompliance,
|
|
581
|
+
},
|
|
582
|
+
hostActions,
|
|
583
|
+
);
|
|
584
|
+
const fixer = createFixerRoleRuntime(
|
|
585
|
+
pi,
|
|
586
|
+
{
|
|
587
|
+
async loadSoul() {
|
|
588
|
+
if (dependencies.loadFixerSoul === undefined) {
|
|
589
|
+
throw new Error("fixer soul loader is not configured");
|
|
590
|
+
}
|
|
591
|
+
return dependencies.loadFixerSoul();
|
|
592
|
+
},
|
|
593
|
+
async loadPacket(path) {
|
|
594
|
+
if (dependencies.loadFixPacket === undefined) {
|
|
595
|
+
throw new Error("Fixer packet loader is not configured");
|
|
596
|
+
}
|
|
597
|
+
return dependencies.loadFixPacket(path);
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
);
|
|
601
|
+
const coder = createCoderRoleRuntime(
|
|
602
|
+
pi,
|
|
603
|
+
{
|
|
604
|
+
async loadSoul() {
|
|
605
|
+
if (dependencies.loadCoderSoul === undefined) {
|
|
606
|
+
throw new Error("coder soul loader is not configured");
|
|
607
|
+
}
|
|
608
|
+
return dependencies.loadCoderSoul();
|
|
609
|
+
},
|
|
610
|
+
async loadTask(path) {
|
|
611
|
+
if (dependencies.loadCoderTask === undefined) {
|
|
612
|
+
throw new Error("Coder task loader is not configured");
|
|
613
|
+
}
|
|
614
|
+
return dependencies.loadCoderTask(path);
|
|
615
|
+
},
|
|
616
|
+
...(dependencies.loadCanonicalSkillBinding === undefined
|
|
617
|
+
? {}
|
|
618
|
+
: {
|
|
619
|
+
loadCanonicalSkillBinding: (name: "tdd") =>
|
|
620
|
+
dependencies.loadCanonicalSkillBinding!(name),
|
|
621
|
+
}),
|
|
622
|
+
},
|
|
623
|
+
hostActions,
|
|
624
|
+
);
|
|
625
|
+
const reviewer = createReviewerRoleRuntime(
|
|
626
|
+
pi,
|
|
627
|
+
{
|
|
628
|
+
async loadSoul() {
|
|
629
|
+
if (dependencies.loadReviewerSoul === undefined) {
|
|
630
|
+
throw new Error("reviewer soul loader is not configured");
|
|
631
|
+
}
|
|
632
|
+
return dependencies.loadReviewerSoul();
|
|
633
|
+
},
|
|
634
|
+
async createPinnedGitReader() {
|
|
635
|
+
if (dependencies.createReviewerPinnedGitReader === undefined) throw new Error("Reviewer runtime dependencies are not configured");
|
|
636
|
+
return dependencies.createReviewerPinnedGitReader();
|
|
637
|
+
},
|
|
638
|
+
async loadCanonicalSkillBinding(name) {
|
|
639
|
+
if (dependencies.loadCanonicalSkillBinding === undefined) {
|
|
640
|
+
throw new Error("Reviewer runtime dependencies are not configured");
|
|
641
|
+
}
|
|
642
|
+
return dependencies.loadCanonicalSkillBinding(name);
|
|
643
|
+
},
|
|
644
|
+
async runDispatch(dispatch, options) {
|
|
645
|
+
if (dependencies.runReviewerDispatch === undefined) throw new Error("Reviewer runtime dependencies are not configured");
|
|
646
|
+
return dependencies.runReviewerDispatch(dispatch, options);
|
|
647
|
+
},
|
|
648
|
+
...(dependencies.shutdownReviewerAgent === undefined
|
|
649
|
+
? {}
|
|
650
|
+
: { shutdownAgent: dependencies.shutdownReviewerAgent }),
|
|
651
|
+
async auditCompliance(options) {
|
|
652
|
+
if (dependencies.auditReviewerCompliance === undefined) {
|
|
653
|
+
throw new Error("Reviewer runtime dependencies are not configured");
|
|
654
|
+
}
|
|
655
|
+
return dependencies.auditReviewerCompliance(options);
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
hostActions,
|
|
659
|
+
);
|
|
660
|
+
const doctor = createDoctorRoleRuntime(pi, {
|
|
661
|
+
async loadSoul() { if (!dependencies.loadDoctorSoul) throw new Error("Doctor runtime dependencies are not configured"); return dependencies.loadDoctorSoul(); },
|
|
662
|
+
async loadCase(path) { if (!dependencies.loadDoctorCase) throw new Error("Doctor runtime dependencies are not configured"); return dependencies.loadDoctorCase(path); },
|
|
663
|
+
async auditCompliance(options) { if (!dependencies.auditDoctorCompliance) throw new Error("Doctor runtime dependencies are not configured"); return dependencies.auditDoctorCompliance(options); },
|
|
664
|
+
}, hostActions);
|
|
665
|
+
let sessionMergerGitState = dependencies.mergerGitState;
|
|
666
|
+
const merger = createMergerRoleRuntime(pi, {
|
|
667
|
+
async loadSoul() { if (!dependencies.loadMergerSoul) throw new Error("Merger runtime dependencies are not configured"); return dependencies.loadMergerSoul(); },
|
|
668
|
+
async loadInput(path) { if (!dependencies.loadMergerInput) throw new Error("Merger runtime dependencies are not configured"); return dependencies.loadMergerInput(path); },
|
|
669
|
+
gitState: {
|
|
670
|
+
activeMerge() { if (!sessionMergerGitState) throw new Error("Merger runtime dependencies are not configured"); return sessionMergerGitState.activeMerge(); },
|
|
671
|
+
completedMerge(mergeCommitId, automaticMergeTreeId) { if (!sessionMergerGitState) throw new Error("Merger runtime dependencies are not configured"); return sessionMergerGitState.completedMerge(mergeCommitId, automaticMergeTreeId); },
|
|
672
|
+
},
|
|
673
|
+
}, hostActions);
|
|
674
|
+
const collector = createCollectorRoleRuntime(
|
|
675
|
+
pi,
|
|
676
|
+
{
|
|
677
|
+
async loadSoul() {
|
|
678
|
+
if (dependencies.loadCollectorSoul === undefined) {
|
|
679
|
+
throw new Error("collector soul loader is not configured");
|
|
680
|
+
}
|
|
681
|
+
return dependencies.loadCollectorSoul();
|
|
682
|
+
},
|
|
683
|
+
createTransport() {
|
|
684
|
+
if (dependencies.createCollectorTransport === undefined) {
|
|
685
|
+
throw new Error("Collector GitHub transport is not configured");
|
|
686
|
+
}
|
|
687
|
+
return dependencies.createCollectorTransport();
|
|
688
|
+
},
|
|
689
|
+
...(dependencies.createCollectorClock === undefined
|
|
690
|
+
? {}
|
|
691
|
+
: { createClock: dependencies.createCollectorClock }),
|
|
692
|
+
...(dependencies.collectorPackageExtensionPath === undefined
|
|
693
|
+
? {}
|
|
694
|
+
: {
|
|
695
|
+
packageExtensionPath: dependencies.collectorPackageExtensionPath,
|
|
696
|
+
}),
|
|
697
|
+
},
|
|
698
|
+
hostActions,
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
const clock = dependencies.activationClock ?? (() => new Date().toISOString());
|
|
702
|
+
const writeTrace = dependencies.activationTraceWriter ?? writeActivationTraceRecord;
|
|
703
|
+
const observationFace = createToolExecutionObservationFace({
|
|
704
|
+
role: () => selectedRole,
|
|
705
|
+
admitted: () => admitted,
|
|
706
|
+
clock: dependencies.toolExecutionObservationClock ?? clock,
|
|
707
|
+
monoNow: dependencies.toolExecutionObservationMonoNow ?? systemToolExecutionObservationMonoNow,
|
|
708
|
+
write: dependencies.toolExecutionObservationWriter ?? writeToolExecutionObservationRecord,
|
|
709
|
+
});
|
|
710
|
+
// ExtensionRunner.emit catches ordinary handler throws, emits extension error, and continues.
|
|
711
|
+
// Observation plane failures must still hit the shared infrastructure termination path
|
|
712
|
+
// (abort + nonzero print/json exit) with the original cause before that swallow.
|
|
713
|
+
const observe = async (
|
|
714
|
+
run: () => void | Promise<void>,
|
|
715
|
+
ctx: ExtensionContext,
|
|
716
|
+
): Promise<void> => {
|
|
717
|
+
try {
|
|
718
|
+
await run();
|
|
719
|
+
} catch (error) {
|
|
720
|
+
failInfrastructure(error, ctx);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
pi.on("tool_execution_start", async (event, ctx) => {
|
|
724
|
+
await observe(() => observationFace.onStart(event), ctx);
|
|
725
|
+
});
|
|
726
|
+
pi.on("tool_execution_update", async (event, ctx) => {
|
|
727
|
+
await observe(() => observationFace.onUpdate(event), ctx);
|
|
728
|
+
});
|
|
729
|
+
pi.on("tool_execution_end", async (event, ctx) => {
|
|
730
|
+
await observe(() => observationFace.onEnd(event), ctx);
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
// Public Role run: record typed provider HTTP status for v1 resume (#108).
|
|
734
|
+
// Latest typed response is authoritative; only a current Codex/xAI 429 is
|
|
735
|
+
// retained — never prose classification or an earlier within-attempt 429.
|
|
736
|
+
pi.on("after_provider_response", async (event, ctx) => {
|
|
737
|
+
const runDir = process.env.AK_ROLE_RUN_DIR;
|
|
738
|
+
if (typeof runDir !== "string" || runDir.trim() === "") return;
|
|
739
|
+
const provider = ctx.model?.provider;
|
|
740
|
+
if (typeof provider !== "string" || provider.trim() === "") return;
|
|
741
|
+
try {
|
|
742
|
+
await recordTypedProviderHttpStatus(runDir, {
|
|
743
|
+
httpStatus: event.status,
|
|
744
|
+
provider,
|
|
745
|
+
});
|
|
746
|
+
} catch {
|
|
747
|
+
// Observation is best-effort relative to the live provider stream;
|
|
748
|
+
// settlement still owns failure presentation.
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
pi.on("session_start", async (event, ctx) => {
|
|
753
|
+
admitted = false;
|
|
754
|
+
selectedRole = undefined;
|
|
755
|
+
observationFace.reset();
|
|
756
|
+
pendingNavigatorPresentation = undefined;
|
|
757
|
+
pendingNavigatorSettlement = undefined;
|
|
758
|
+
pendingInfrastructureToolCallIds.clear();
|
|
759
|
+
navigatorWorkContext = undefined;
|
|
760
|
+
const rawRole = pi.getFlag(ROLE_FLAG.name);
|
|
761
|
+
if (rawRole === undefined) return;
|
|
762
|
+
const entry = PACKAGED_ROLE_REGISTRY.find(({ role }) => role === rawRole);
|
|
763
|
+
if (entry === undefined) {
|
|
764
|
+
failInfrastructure(new Error(`Unsupported workflow role: ${String(rawRole)}`), ctx);
|
|
765
|
+
}
|
|
766
|
+
selectedRole = entry.role;
|
|
767
|
+
navigatorAttendance?.dispose();
|
|
768
|
+
navigatorAttendance = undefined;
|
|
769
|
+
const runtime: ActivationRuntime = {
|
|
770
|
+
event,
|
|
771
|
+
context: ctx,
|
|
772
|
+
judge,
|
|
773
|
+
fixer,
|
|
774
|
+
coder,
|
|
775
|
+
reviewer,
|
|
776
|
+
collector,
|
|
777
|
+
doctor,
|
|
778
|
+
merger: async () => {
|
|
779
|
+
if (dependencies.mergerGitState === undefined) {
|
|
780
|
+
sessionMergerGitState = dependencies.createMergerGitState?.(ctx.cwd);
|
|
781
|
+
}
|
|
782
|
+
if (sessionMergerGitState === undefined) throw new Error("Merger runtime dependencies are not configured");
|
|
783
|
+
await merger.activate();
|
|
784
|
+
},
|
|
785
|
+
};
|
|
786
|
+
try {
|
|
787
|
+
// Production topology only (ADR 0048/0049): no test-only ledger hooks.
|
|
788
|
+
// Admit durable session file first so lifecycle getEntries/appendEntry are truthful:
|
|
789
|
+
// deferred SM materialization must not wipe an in-memory principal marker.
|
|
790
|
+
const bookKey = resolveBookKeyFromGit(ctx.cwd);
|
|
791
|
+
const correlation = correlationIdentityFromEnv();
|
|
792
|
+
const ledgerHome = resolveActivationLedgerHome();
|
|
793
|
+
const session = durableSessionPointer(ctx.sessionManager, { ledgerHome, bookKey });
|
|
794
|
+
|
|
795
|
+
if (dependencies.createNavigatorAttendance !== undefined) {
|
|
796
|
+
let work: NavigatorWorkContext;
|
|
797
|
+
let contextError: unknown;
|
|
798
|
+
if (dependencies.loadNavigatorWorkContext === undefined) {
|
|
799
|
+
const fallbackSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
800
|
+
contextError = new Error("Navigator work context loader is not configured");
|
|
801
|
+
work = { subjectKey: fallbackSubjectKey, subject: `work subject: ${fallbackSubjectKey}`, authority: "", subjectProvenance: "placeholder" };
|
|
802
|
+
} else {
|
|
803
|
+
try {
|
|
804
|
+
work = await dependencies.loadNavigatorWorkContext({ context: ctx, role: entry.role, phase: navigatorPhase(pi, entry.role) });
|
|
805
|
+
contextError = work.contextError;
|
|
806
|
+
} catch (error) {
|
|
807
|
+
// Contract: README.md#Navigator-attendance — a failed context load continues with a typed placeholder work context; the original cause is retained in contextError for the typed unavailable report.
|
|
808
|
+
contextError = navigatorUnavailableError("context", error);
|
|
809
|
+
const fallbackSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
810
|
+
work = { subjectKey: fallbackSubjectKey, subject: `work subject: ${fallbackSubjectKey}`, authority: "", subjectProvenance: "placeholder" };
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
navigatorWorkContext = { ...work, ...(contextError === undefined ? {} : { contextError }) };
|
|
814
|
+
// Shared envelope owns exact invocation principal from admitted session lifecycle.
|
|
815
|
+
// session_start is process activation: resume unfinished principal only when marker
|
|
816
|
+
// role/phase/subjectKey still match; mint for contradictory marker, malformed nearest,
|
|
817
|
+
// missing marker, or terminal already completed.
|
|
818
|
+
const sessionEntries = ctx.sessionManager.getEntries();
|
|
819
|
+
const invocationPhase = navigatorPhase(pi, entry.role);
|
|
820
|
+
const lifecyclePrincipal = resolveLifecycleInvocationPrincipal(sessionEntries, {
|
|
821
|
+
role: entry.role,
|
|
822
|
+
phase: invocationPhase,
|
|
823
|
+
subjectKey: work.subjectKey,
|
|
824
|
+
});
|
|
825
|
+
const invocationId = lifecyclePrincipal.invocationId;
|
|
826
|
+
if (!lifecyclePrincipal.resume) {
|
|
827
|
+
pi.appendEntry(NAVIGATOR_INVOCATION_ENTRY, {
|
|
828
|
+
invocationId,
|
|
829
|
+
role: entry.role,
|
|
830
|
+
phase: invocationPhase,
|
|
831
|
+
subjectKey: work.subjectKey,
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
navigatorAttendance = await dependencies.createNavigatorAttendance({
|
|
835
|
+
context: ctx,
|
|
836
|
+
role: entry.role,
|
|
837
|
+
phase: invocationPhase,
|
|
838
|
+
subjectKey: work.subjectKey,
|
|
839
|
+
subject: work.subject,
|
|
840
|
+
authority: work.authority,
|
|
841
|
+
invocationId,
|
|
842
|
+
...(contextError === undefined ? {} : { contextError }),
|
|
843
|
+
onEvent: (navigatorEvent, report) => {
|
|
844
|
+
pendingNavigatorPresentation = { event: navigatorEvent, report };
|
|
845
|
+
},
|
|
846
|
+
});
|
|
847
|
+
// Warm live help during activation so prepare is not help-bound under load.
|
|
848
|
+
// Concrete work context also starts full preparation so session create
|
|
849
|
+
// overlaps the role run. Placeholder subjects wait for before_agent_start
|
|
850
|
+
// (user prompt may replace the subject key) but still inherit warm help.
|
|
851
|
+
navigatorAttendance.warmHelp?.();
|
|
852
|
+
if (
|
|
853
|
+
navigatorWorkContext.contextError === undefined &&
|
|
854
|
+
navigatorWorkContext.subjectProvenance !== "placeholder"
|
|
855
|
+
) {
|
|
856
|
+
navigatorAttendance.prepare();
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
|
|
861
|
+
// Worker gates ②④ + ① baseline: envelope arms the worktree after role install.
|
|
862
|
+
// Parent session feeds #216 createRecordSession so baseline/bounce survive resume.
|
|
863
|
+
if (entry.role === "coder" || entry.role === "fixer") {
|
|
864
|
+
installWorkerGitHooks(ctx.cwd);
|
|
865
|
+
if (entry.role === "coder") coder.armSubmissionGate(ctx.cwd, ctx.sessionManager);
|
|
866
|
+
else fixer.armSubmissionGate(ctx.cwd, ctx.sessionManager);
|
|
867
|
+
}
|
|
868
|
+
appendAcceptedActivationToBook({
|
|
869
|
+
ledgerHome,
|
|
870
|
+
fact: buildAcceptedActivationFact({
|
|
871
|
+
role: entry.role,
|
|
872
|
+
observedAt: clock(),
|
|
873
|
+
bookKey,
|
|
874
|
+
session,
|
|
875
|
+
correlation,
|
|
876
|
+
}),
|
|
877
|
+
});
|
|
878
|
+
admitted = true;
|
|
879
|
+
} catch (error) {
|
|
880
|
+
failInfrastructure(error, ctx);
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
};
|
|
884
|
+
}
|