@straiffi/archon 1.11.5 → 1.11.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +8 -0
  2. package/dist/client/assets/{ActivityView-Dw7Bl18C.js → ActivityView-gwq90xuC.js} +1 -1
  3. package/dist/client/assets/{GitHubActionsDialog-9w5XtP5x.js → GitHubActionsDialog-CddU5mmQ.js} +1 -1
  4. package/dist/client/assets/{VerificationDialog-dOSv05QS.js → VerificationDialog-DZXmgf-Q.js} +1 -1
  5. package/dist/client/assets/{architectureDiagram-3BPJPVTR-BU-dnVWz.js → architectureDiagram-3BPJPVTR-B7h4gUId.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-GPEHLZMM-D1fhZ9K3.js → blockDiagram-GPEHLZMM-CKcqgkiW.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AAUBKEIU-C5cs67FJ.js → c4Diagram-AAUBKEIU-b0N8QAOw.js} +1 -1
  8. package/dist/client/assets/channel-DFqGOc-J.js +1 -0
  9. package/dist/client/assets/{chunk-2J33WTMH-BuofkrUv.js → chunk-2J33WTMH-DuMyezuW.js} +1 -1
  10. package/dist/client/assets/{chunk-3OPIFGDE-BSLbHStu.js → chunk-3OPIFGDE-Dgtz4ReD.js} +1 -1
  11. package/dist/client/assets/{chunk-5ZQYHXKU-CV_reqn5.js → chunk-5ZQYHXKU-By3w6rbd.js} +1 -1
  12. package/dist/client/assets/{chunk-727SXJPM-DuL4OL6p.js → chunk-727SXJPM-BHTPfHY2.js} +1 -1
  13. package/dist/client/assets/{chunk-AQP2D5EJ-B7ebIXsD.js → chunk-AQP2D5EJ-W2Rgle6H.js} +1 -1
  14. package/dist/client/assets/{chunk-CSCIHK7Q-CfvfKS81.js → chunk-CSCIHK7Q-C0zW-M44.js} +1 -1
  15. package/dist/client/assets/{chunk-KSCS5N6A-B8yAPh8_.js → chunk-KSCS5N6A-NLszOClX.js} +1 -1
  16. package/dist/client/assets/{chunk-L5ZTLDWV-CLAA9PrV.js → chunk-L5ZTLDWV-Djdu-TFq.js} +1 -1
  17. package/dist/client/assets/{chunk-LZXEDZCA-BWDUNHyY.js → chunk-LZXEDZCA-BBMjUaM6.js} +2 -2
  18. package/dist/client/assets/{chunk-ND2GUHAM-DDtkY0aA.js → chunk-ND2GUHAM-BMGxL6oq.js} +1 -1
  19. package/dist/client/assets/{chunk-NZK2D7GU-Cqw_WclD.js → chunk-NZK2D7GU-BmBtYVzv.js} +1 -1
  20. package/dist/client/assets/{chunk-O5CBEL6O-yk76d2Ne.js → chunk-O5CBEL6O-fNzTMe1t.js} +1 -1
  21. package/dist/client/assets/{chunk-WU5MYG2G-C9RL4ic0.js → chunk-WU5MYG2G-DtWDtH9D.js} +1 -1
  22. package/dist/client/assets/classDiagram-4FO5ZUOK-zJrDS8pp.js +1 -0
  23. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Bk6pmr_F.js +1 -0
  24. package/dist/client/assets/{dagre-BM42HDAG-D1R8Uoz3.js → dagre-BM42HDAG-zpl4bunJ.js} +1 -1
  25. package/dist/client/assets/{diagram-2AECGRRQ-CUwS3hk7.js → diagram-2AECGRRQ-XiIQ6yDZ.js} +1 -1
  26. package/dist/client/assets/{diagram-5GNKFQAL-BQGwWZ5M.js → diagram-5GNKFQAL-EwX79EhM.js} +1 -1
  27. package/dist/client/assets/{diagram-KO2AKTUF-C7ErzACC.js → diagram-KO2AKTUF-pTTl20VK.js} +1 -1
  28. package/dist/client/assets/{diagram-LMA3HP47-z4blMZQD.js → diagram-LMA3HP47-CAADMP3T.js} +1 -1
  29. package/dist/client/assets/{diagram-OG6HWLK6-DTdMXNXF.js → diagram-OG6HWLK6-DSw-z9AU.js} +1 -1
  30. package/dist/client/assets/{erDiagram-TEJ5UH35-Dzq40m7g.js → erDiagram-TEJ5UH35-CYVpzKnx.js} +1 -1
  31. package/dist/client/assets/{flowDiagram-I6XJVG4X-DZee4-lQ.js → flowDiagram-I6XJVG4X-YfUgs6Y9.js} +1 -1
  32. package/dist/client/assets/{ganttDiagram-6RSMTGT7-BrvahLDI.js → ganttDiagram-6RSMTGT7-CBZcM6fa.js} +1 -1
  33. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DFl7NFyp.js → gitGraphDiagram-PVQCEYII-B-cnyCdP.js} +1 -1
  34. package/dist/client/assets/index-CbYT3N3U.css +2 -0
  35. package/dist/client/assets/index-DXJSLf4W.js +287 -0
  36. package/dist/client/assets/{infoDiagram-5YYISTIA-DcbIRnzw.js → infoDiagram-5YYISTIA-hg-hixwz.js} +1 -1
  37. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CCLSDPWU.js → ishikawaDiagram-YF4QCWOH-CP30YmvW.js} +1 -1
  38. package/dist/client/assets/{journeyDiagram-JHISSGLW-DBybnxZb.js → journeyDiagram-JHISSGLW-MPwOtkOb.js} +1 -1
  39. package/dist/client/assets/{kanban-definition-UN3LZRKU-0vXnDc2p.js → kanban-definition-UN3LZRKU-dzx8hATQ.js} +1 -1
  40. package/dist/client/assets/{line-CmuG_mnn.js → line-C2wfs9Qd.js} +1 -1
  41. package/dist/client/assets/{mermaid-parser.core-2bcA4BZv.js → mermaid-parser.core-j3pT6MDr.js} +1 -1
  42. package/dist/client/assets/{mermaid.core-BtCKaSS-.js → mermaid.core-BwkWqkNy.js} +3 -3
  43. package/dist/client/assets/{mindmap-definition-RKZ34NQL-BS3GYH1w.js → mindmap-definition-RKZ34NQL-CZ3iES81.js} +1 -1
  44. package/dist/client/assets/{pieDiagram-4H26LBE5-DnSf3dLi.js → pieDiagram-4H26LBE5-DCY6gx4q.js} +1 -1
  45. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CvU26PT6.js → quadrantDiagram-W4KKPZXB-Bs-SuHD0.js} +1 -1
  46. package/dist/client/assets/{requirementDiagram-4Y6WPE33-9BKyfU_D.js → requirementDiagram-4Y6WPE33-DaHZPYWb.js} +1 -1
  47. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-9EYmPhr5.js → sankeyDiagram-5OEKKPKP-CAABGeQw.js} +1 -1
  48. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BcBk_wZZ.js → sequenceDiagram-3UESZ5HK-BiFFDmHd.js} +1 -1
  49. package/dist/client/assets/{stateDiagram-AJRCARHV-2m55Kpig.js → stateDiagram-AJRCARHV-DKXUKIex.js} +1 -1
  50. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DyEfP-lL.js +1 -0
  51. package/dist/client/assets/{timeline-definition-PNZ67QCA-J3NEOuRz.js → timeline-definition-PNZ67QCA-CNWuUe9M.js} +1 -1
  52. package/dist/client/assets/{vennDiagram-CIIHVFJN-D_3D_Pp4.js → vennDiagram-CIIHVFJN-Melay8l5.js} +1 -1
  53. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Wln2PbKU.js → wardleyDiagram-YWT4CUSO-pWa26XVf.js} +1 -1
  54. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DfvF03Zn.js → xychartDiagram-2RQKCTM6-BaAwLxVv.js} +1 -1
  55. package/dist/client/index.html +2 -2
  56. package/dist/server/db.js +71 -4
  57. package/dist/server/db.js.map +1 -1
  58. package/dist/server/index.js +29 -5
  59. package/dist/server/index.js.map +1 -1
  60. package/dist/server/lib/agent.js +277 -299
  61. package/dist/server/lib/agent.js.map +1 -1
  62. package/dist/server/lib/agentOutputLanguage.js +11 -0
  63. package/dist/server/lib/agentOutputLanguage.js.map +1 -0
  64. package/dist/server/lib/agentProvider.js.map +1 -1
  65. package/dist/server/lib/agentRuns.js +68 -4
  66. package/dist/server/lib/agentRuns.js.map +1 -1
  67. package/dist/server/lib/appLocale.js +19 -0
  68. package/dist/server/lib/appLocale.js.map +1 -0
  69. package/dist/server/lib/buildExecutionEnvironment.js +92 -1
  70. package/dist/server/lib/buildExecutionEnvironment.js.map +1 -1
  71. package/dist/server/lib/chatDraftTargets.js +81 -0
  72. package/dist/server/lib/chatDraftTargets.js.map +1 -0
  73. package/dist/server/lib/chatOperations.js +26 -3
  74. package/dist/server/lib/chatOperations.js.map +1 -1
  75. package/dist/server/lib/chatTargets.js +57 -2
  76. package/dist/server/lib/chatTargets.js.map +1 -1
  77. package/dist/server/lib/chats.js +10 -6
  78. package/dist/server/lib/chats.js.map +1 -1
  79. package/dist/server/lib/conversationResume.js +56 -3
  80. package/dist/server/lib/conversationResume.js.map +1 -1
  81. package/dist/server/lib/dockerSandboxOpencodeSessionOperations.js +81 -25
  82. package/dist/server/lib/dockerSandboxOpencodeSessionOperations.js.map +1 -1
  83. package/dist/server/lib/dockerSandboxReleaseProfiles.js +36 -7
  84. package/dist/server/lib/dockerSandboxReleaseProfiles.js.map +1 -1
  85. package/dist/server/lib/executionEnvironmentRoutes.js +71 -4
  86. package/dist/server/lib/executionEnvironmentRoutes.js.map +1 -1
  87. package/dist/server/lib/executionEnvironmentValidation.js +199 -19
  88. package/dist/server/lib/executionEnvironmentValidation.js.map +1 -1
  89. package/dist/server/lib/executionEnvironmentValidationEvidence.js +140 -0
  90. package/dist/server/lib/executionEnvironmentValidationEvidence.js.map +1 -0
  91. package/dist/server/lib/executionEnvironmentValidationOperations.js +13 -0
  92. package/dist/server/lib/executionEnvironmentValidationOperations.js.map +1 -1
  93. package/dist/server/lib/executionRetry.js.map +1 -1
  94. package/dist/server/lib/executionRetryContext.js +55 -11
  95. package/dist/server/lib/executionRetryContext.js.map +1 -1
  96. package/dist/server/lib/executionTargets.js +5 -2
  97. package/dist/server/lib/executionTargets.js.map +1 -1
  98. package/dist/server/lib/hostExecutionEnvironment.js +14 -2
  99. package/dist/server/lib/hostExecutionEnvironment.js.map +1 -1
  100. package/dist/server/lib/i18n/index.js +3 -2
  101. package/dist/server/lib/i18n/index.js.map +1 -1
  102. package/dist/server/lib/i18n/resources.js +0 -1
  103. package/dist/server/lib/i18n/resources.js.map +1 -1
  104. package/dist/server/lib/lightweightPrompt.js +4 -0
  105. package/dist/server/lib/lightweightPrompt.js.map +1 -1
  106. package/dist/server/lib/models.js +58 -18
  107. package/dist/server/lib/models.js.map +1 -1
  108. package/dist/server/lib/opencodeAgentProvider.js +54 -48
  109. package/dist/server/lib/opencodeAgentProvider.js.map +1 -1
  110. package/dist/server/lib/opencodeCli.js +244 -0
  111. package/dist/server/lib/opencodeCli.js.map +1 -0
  112. package/dist/server/lib/opencodePromptOutput.js +11 -65
  113. package/dist/server/lib/opencodePromptOutput.js.map +1 -1
  114. package/dist/server/lib/opencodeSessionOperations.js +44 -28
  115. package/dist/server/lib/opencodeSessionOperations.js.map +1 -1
  116. package/dist/server/lib/opencodeSessionProvenance.js +23 -0
  117. package/dist/server/lib/opencodeSessionProvenance.js.map +1 -0
  118. package/dist/server/lib/opencodeStream.js +263 -0
  119. package/dist/server/lib/opencodeStream.js.map +1 -0
  120. package/dist/server/lib/opencodeTaskSessions.js +3 -4
  121. package/dist/server/lib/opencodeTaskSessions.js.map +1 -1
  122. package/dist/server/lib/opencodeV2SessionOperations.js +453 -0
  123. package/dist/server/lib/opencodeV2SessionOperations.js.map +1 -0
  124. package/dist/server/lib/postBuildChecks.js +1 -1
  125. package/dist/server/lib/postBuildChecks.js.map +1 -1
  126. package/dist/server/lib/run.js +32 -41
  127. package/dist/server/lib/run.js.map +1 -1
  128. package/dist/server/lib/runProcessIdentity.js +10 -2
  129. package/dist/server/lib/runProcessIdentity.js.map +1 -1
  130. package/dist/server/lib/runProcesses.js +52 -19
  131. package/dist/server/lib/runProcesses.js.map +1 -1
  132. package/dist/server/lib/runServiceStop.js +62 -0
  133. package/dist/server/lib/runServiceStop.js.map +1 -0
  134. package/dist/server/lib/runServices.js +63 -4
  135. package/dist/server/lib/runServices.js.map +1 -1
  136. package/dist/server/lib/runSessionLifecycle.js +25 -0
  137. package/dist/server/lib/runSessionLifecycle.js.map +1 -1
  138. package/dist/server/lib/runtimePaths.js +7 -4
  139. package/dist/server/lib/runtimePaths.js.map +1 -1
  140. package/dist/server/lib/serviceRunLogs.js +180 -0
  141. package/dist/server/lib/serviceRunLogs.js.map +1 -0
  142. package/dist/server/lib/sessionTargets.js +35 -2
  143. package/dist/server/lib/sessionTargets.js.map +1 -1
  144. package/dist/server/lib/specOperations.js +7 -2
  145. package/dist/server/lib/specOperations.js.map +1 -1
  146. package/dist/server/lib/specReviewContext.js +3 -2
  147. package/dist/server/lib/specReviewContext.js.map +1 -1
  148. package/dist/server/lib/toolUpgrade.js +54 -5
  149. package/dist/server/lib/toolUpgrade.js.map +1 -1
  150. package/dist/server/lib/types.js.map +1 -1
  151. package/dist/server/workers/build.js +47 -9
  152. package/dist/server/workers/build.js.map +1 -1
  153. package/dist/server/workers/chat.js +89 -21
  154. package/dist/server/workers/chat.js.map +1 -1
  155. package/dist/server/workers/followUp.js +59 -22
  156. package/dist/server/workers/followUp.js.map +1 -1
  157. package/dist/server/workers/plan.js +109 -169
  158. package/dist/server/workers/plan.js.map +1 -1
  159. package/dist/server/workers/planFollowUp.js +27 -7
  160. package/dist/server/workers/planFollowUp.js.map +1 -1
  161. package/dist/server/workers/review.js +43 -10
  162. package/dist/server/workers/review.js.map +1 -1
  163. package/dist/server/workers/specReview.js +1 -0
  164. package/dist/server/workers/specReview.js.map +1 -1
  165. package/dist/server/workers/specSession.js +42 -5
  166. package/dist/server/workers/specSession.js.map +1 -1
  167. package/dist/shared/i18n/locales.js +12 -0
  168. package/dist/shared/i18n/locales.js.map +1 -0
  169. package/package.json +1 -1
  170. package/dist/client/assets/channel-DUX4Nl-Q.js +0 -1
  171. package/dist/client/assets/classDiagram-4FO5ZUOK-_vWY0Wm5.js +0 -1
  172. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Boom-t3w.js +0 -1
  173. package/dist/client/assets/index-D8_nS8Kw.js +0 -287
  174. package/dist/client/assets/index-RM0FaS4q.css +0 -2
  175. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DuYuP5AB.js +0 -1
@@ -10,9 +10,14 @@ import { resolveExistingWorktreePath } from '../lib/git.js';
10
10
  import { getModelProvider, normalizeModelId } from '../lib/models.js';
11
11
  import { getAgentModelProvider, normalizeAgentModelId, requireExecutableAgent } from '../lib/agentCatalog.js';
12
12
  import { codexAgentProvider } from '../lib/codexAgentProvider.js';
13
+ import { opencodeAgentProvider } from '../lib/opencodeAgentProvider.js';
13
14
  import { createOpencodeTaskSessionReader, parseOpencodeTaskEnvelope } from '../lib/opencodeTaskSessions.js';
15
+ import { parseOpencodeStreamLine } from '../lib/opencodeStream.js';
16
+ import { parseOpencodeError } from '../lib/opencodeErrors.js';
14
17
  import { hostOpencodeSessionOperations } from '../lib/opencodeSessionOperations.js';
18
+ import { getOpencodeCliCompatibility, inspectOpencodeRelease, requireSupportedOpencodeCompatibility } from '../lib/opencodeCli.js';
15
19
  import { markRetryableOpenCodeDatabaseLock, RetryableOpenCodeDatabaseLockError, retryOpenCodeDatabaseLocks } from '../lib/opencodeExecutionReliability.js';
20
+ import { appendAgentOutputLanguagePrompt } from '../lib/agentOutputLanguage.js';
16
21
  import { appendClaudeHeadlessPlanPrompt, appendPlanModeQuestionPromptRules, buildClaudeHeadlessPlanArgs } from '../lib/planModeQuestions.js';
17
22
  import { persistProjectMemorySuggestions } from '../lib/projectMemory.js';
18
23
  import { getProjectMemoryPromptBlock } from '../lib/projectMemoryPrompt.js';
@@ -27,7 +32,8 @@ import { createTicketMessage, upsertTicketDescriptionMessage } from '../lib/tick
27
32
  import { createAskQuestionMetadata, extractAskQuestionFromOutput, formatAskQuestionMessage } from '../lib/planQuestions.js';
28
33
  import { getTicket, resolveTicketBranch, resolveTicketTool, resolveTicketWorkerKey } from '../lib/tickets.js';
29
34
  import { createOpencodeSubagentMonitor, createSubagentRunTracker, formatAgentErrorForTranscript, getAgentErrorTranscriptRuns, readOpencodeSessionTranscript, storeTicketUsageSnapshot, storeTicketUsageSnapshotDirect, mergeUsageFromJsonLine, EMPTY_CHAT_USAGE_SNAPSHOT } from '../lib/agent.js';
30
- import { createAgentRun, emitAgentRunsUpdated, finalizeAgentRun, getAgentRun, getNextAgentRunIndex, terminalizeAgentRunsForExecutionRun, updateAgentRunSessionId } from '../lib/agentRuns.js';
35
+ import { createAgentRun, emitAgentRunsUpdated, finalizeAgentRun, getAgentRun, getNextAgentRunIndex, resolveHistoricalProviderSessionForParent, terminalizeAgentRunsForExecutionRun, updateAgentRunSessionId } from '../lib/agentRuns.js';
36
+ import { shouldStartFreshProviderSession } from '../lib/opencodeSessionProvenance.js';
31
37
  import { addExecutionRunLink, createExecutionRun, transitionExecutionRun } from '../lib/executionRuns.js';
32
38
  import { assertProviderSessionAuthorityMatches, createExecutionProfileSelectionMetadata } from '../lib/executionRunAuthority.js';
33
39
  import { classifyTicketExecutionTarget, resolveExecutionTarget, resolveProjectRootExecutionTarget } from '../lib/executionTargets.js';
@@ -50,6 +56,7 @@ const plannerExecutionOptions = (options) => ({
50
56
  executionTarget: options.executionTarget,
51
57
  executionLauncherEnvironment: options.executionLauncherEnvironment,
52
58
  executionRuntimeEnvironment: options.executionRuntimeEnvironment,
59
+ opencodeRuntimeIdentity: options.opencodeRuntimeIdentity,
53
60
  });
54
61
  const createPlanningInvocation = (options, label, role) => {
55
62
  const parentType = options.agentRunParent?.parentType ?? (options.ticketId ? 'ticket' : options.projectId ? 'planning' : null);
@@ -116,59 +123,6 @@ const createPlannerRecoveryTracker = () => {
116
123
  getRecoveredResponse: () => finalAnswerFragments.join('\n\n'),
117
124
  };
118
125
  };
119
- const extractLeadingJsonObject = (line) => {
120
- if (!line.startsWith('{')) {
121
- return null;
122
- }
123
- let depth = 0;
124
- let inString = false;
125
- let escaping = false;
126
- for (let index = 0; index < line.length; index += 1) {
127
- const char = line[index];
128
- if (inString) {
129
- if (escaping) {
130
- escaping = false;
131
- continue;
132
- }
133
- if (char === '\\') {
134
- escaping = true;
135
- continue;
136
- }
137
- if (char === '"') {
138
- inString = false;
139
- }
140
- continue;
141
- }
142
- if (char === '"') {
143
- inString = true;
144
- continue;
145
- }
146
- if (char === '{') {
147
- depth += 1;
148
- continue;
149
- }
150
- if (char === '}') {
151
- depth -= 1;
152
- if (depth === 0) {
153
- return line.slice(0, index + 1);
154
- }
155
- }
156
- }
157
- return null;
158
- };
159
- const extractLeadingJsonObjects = (line) => {
160
- const jsonObjects = [];
161
- let remainder = line.trim();
162
- while (remainder.startsWith('{')) {
163
- const jsonObject = extractLeadingJsonObject(remainder);
164
- if (!jsonObject) {
165
- break;
166
- }
167
- jsonObjects.push(jsonObject);
168
- remainder = remainder.slice(jsonObject.length).trim();
169
- }
170
- return { jsonObjects, remainder };
171
- };
172
126
  const normalizeToolName = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, '');
173
127
  const isPlannerSubagentTool = (name) => {
174
128
  const normalized = normalizeToolName(name);
@@ -384,61 +338,41 @@ const parseClaudePlannerStreamJsonLine = (line) => {
384
338
  }
385
339
  return emptyParsedPlannerStreamLine();
386
340
  };
387
- const formatPlannerOpencodeToolUse = (event, cwd) => {
388
- const toolName = event.part?.tool;
389
- if (!toolName) {
390
- return null;
391
- }
392
- return formatPlannerToolCall(toolName, event.part?.state?.input, cwd);
393
- };
394
- const formatPlannerStepTitle = (event) => {
395
- const title = event.part?.title?.trim();
396
- return title || null;
397
- };
398
341
  const parseOpencodePlannerJsonEvent = (event, cwd) => {
399
- const providerSessionId = event.sessionID?.trim()
400
- || event.sessionId?.trim()
401
- || event.part?.sessionID?.trim()
402
- || event.part?.sessionId?.trim()
403
- || null;
342
+ const providerSessionId = event.sessionId;
404
343
  if (event.type === 'subagent_snapshot') {
405
- const sessionId = typeof event.part?.state?.metadata?.sessionId === 'string'
406
- ? event.part.state.metadata.sessionId
407
- : null;
408
- const status = event.part?.state?.status;
344
+ const status = event.tool.status;
409
345
  return {
410
346
  ...emptyParsedPlannerStreamLine(),
411
347
  providerSessionId,
412
348
  subagentEvents: [{
413
349
  kind: 'snapshot',
414
- callId: event.part?.callID ?? null,
415
- label: event.part?.title?.trim() || 'Subagent',
416
- sessionId,
350
+ callId: event.tool.callId,
351
+ label: event.tool.title || 'Subagent',
352
+ sessionId: event.tool.childSessionId,
417
353
  status: status === 'error' || status === 'failed'
418
354
  ? 'error'
419
355
  : status === 'stopped' || status === 'interrupted' ? 'stopped' : status === 'running' ? 'running' : 'done',
420
- log: event.part?.state?.log ?? null,
421
- response: event.part?.state?.response ?? null,
356
+ log: event.tool.log,
357
+ response: event.tool.response,
422
358
  }],
423
359
  };
424
360
  }
425
- if (event.type === 'plan' && event.part?.type === 'text' && event.part.text) {
361
+ if (event.type === 'plan' && event.text) {
426
362
  return {
427
- logFragment: event.part.text,
363
+ logFragment: event.text,
428
364
  responseFragment: null,
429
365
  subagentEvents: [],
430
366
  providerSessionId,
431
- concatenateFragments: event.part.metadata?.codex?.delta === true,
432
- replaceFragment: event.part.metadata?.codex?.snapshot === true,
433
- fragmentGroup: event.part.metadata?.codex?.fragmentGroup
434
- ?? event.part.metadata?.codex?.itemId
435
- ?? null,
367
+ concatenateFragments: event.metadata.delta,
368
+ replaceFragment: event.metadata.snapshot,
369
+ fragmentGroup: event.metadata.fragmentGroup ?? event.metadata.itemId,
436
370
  };
437
371
  }
438
- if (event.type === 'text' && event.part?.type === 'text' && event.part.text) {
439
- const concatenateFragments = event.part.metadata?.codex?.delta === true;
440
- const text = concatenateFragments ? event.part.text : event.part.text.trim();
441
- const phase = event.part.metadata?.openai?.phase;
372
+ if (event.type === 'text' && event.text) {
373
+ const concatenateFragments = event.metadata.delta;
374
+ const text = concatenateFragments ? event.text : event.text.trim();
375
+ const phase = event.metadata.phase;
442
376
  return {
443
377
  logFragment: text || null,
444
378
  responseFragment: text && (!phase || phase === 'final_answer') ? text : null,
@@ -449,38 +383,32 @@ const parseOpencodePlannerJsonEvent = (event, cwd) => {
449
383
  ? [{ type: 'final_answer', text }]
450
384
  : [],
451
385
  concatenateFragments,
452
- fragmentGroup: event.part.metadata?.codex?.fragmentGroup
453
- ?? event.part.metadata?.codex?.itemId
454
- ?? null,
386
+ fragmentGroup: event.metadata.fragmentGroup ?? event.metadata.itemId,
455
387
  };
456
388
  }
457
- if (event.type === 'reasoning' && event.part?.type === 'reasoning') {
458
- const concatenateFragments = event.part.metadata?.codex?.delta === true;
459
- const text = concatenateFragments ? event.part.text ?? '' : event.part.text?.trim() ?? '';
389
+ if (event.type === 'reasoning') {
390
+ const concatenateFragments = event.metadata.delta;
391
+ const text = concatenateFragments ? event.text : event.text.trim();
460
392
  return {
461
393
  logFragment: text || null,
462
394
  responseFragment: null,
463
395
  subagentEvents: [],
464
396
  providerSessionId,
465
397
  concatenateFragments,
466
- fragmentGroup: event.part.metadata?.codex?.fragmentGroup
467
- ?? event.part.metadata?.codex?.itemId
468
- ?? null,
398
+ fragmentGroup: event.metadata.fragmentGroup ?? event.metadata.itemId,
469
399
  };
470
400
  }
471
- if (event.type === 'tool' || event.type === 'tool_use' || event.type === 'tool_result') {
472
- const isToolInvocation = event.type === 'tool' || event.type === 'tool_use';
473
- const toolName = event.part?.tool;
401
+ if (event.type === 'tool_use' || event.type === 'tool_result') {
402
+ const isToolInvocation = event.type === 'tool_use';
403
+ const toolName = event.tool.name;
474
404
  if (toolName && isPlannerSubagentTool(toolName)) {
475
- const description = getPlannerSubagentDescription(event.part?.state?.input, toolName);
476
- const rawOutput = event.part?.state?.output?.trim();
405
+ const description = getPlannerSubagentDescription(event.tool.input, toolName);
406
+ const rawOutput = event.tool.output?.trim();
477
407
  const envelope = parseOpencodeTaskEnvelope(rawOutput);
478
408
  const output = envelope?.result ?? rawOutput;
479
- const taskStatus = event.part?.state?.status?.toLowerCase() ?? envelope?.state?.toLowerCase();
409
+ const taskStatus = event.tool.status?.toLowerCase() ?? envelope?.state?.toLowerCase();
480
410
  const isTerminal = Boolean(taskStatus && taskStatus !== 'running' && taskStatus !== 'pending');
481
- const childSessionId = envelope?.childSessionId
482
- ?? (typeof event.part?.state?.metadata?.sessionID === 'string' ? event.part.state.metadata.sessionID : null)
483
- ?? (typeof event.part?.state?.metadata?.sessionId === 'string' ? event.part.state.metadata.sessionId : null);
411
+ const childSessionId = envelope?.childSessionId ?? event.tool.childSessionId;
484
412
  return {
485
413
  logFragment: isToolInvocation ? `Subagent: ${description}` : null,
486
414
  responseFragment: null,
@@ -488,7 +416,7 @@ const parseOpencodePlannerJsonEvent = (event, cwd) => {
488
416
  ...(isToolInvocation
489
417
  ? [{
490
418
  kind: 'start',
491
- callId: event.part?.callID ?? null,
419
+ callId: event.tool.callId,
492
420
  label: `Subagent: ${description}`,
493
421
  sessionId: childSessionId,
494
422
  }]
@@ -496,7 +424,7 @@ const parseOpencodePlannerJsonEvent = (event, cwd) => {
496
424
  ...(output || isTerminal
497
425
  ? [{
498
426
  kind: isTerminal ? 'complete' : 'fragment',
499
- callId: event.part?.callID ?? null,
427
+ callId: event.tool.callId,
500
428
  label: `Subagent: ${description}`,
501
429
  ...(output ? { text: output } : {}),
502
430
  sessionId: childSessionId,
@@ -513,7 +441,7 @@ const parseOpencodePlannerJsonEvent = (event, cwd) => {
513
441
  return { ...emptyParsedPlannerStreamLine(), providerSessionId };
514
442
  }
515
443
  return {
516
- logFragment: formatPlannerOpencodeToolUse(event, cwd),
444
+ logFragment: formatPlannerToolCall(toolName, event.tool.input, cwd),
517
445
  responseFragment: null,
518
446
  subagentEvents: [],
519
447
  providerSessionId,
@@ -521,19 +449,14 @@ const parseOpencodePlannerJsonEvent = (event, cwd) => {
521
449
  }
522
450
  if (event.type === 'step_start') {
523
451
  return {
524
- logFragment: formatPlannerStepTitle(event),
452
+ logFragment: event.title,
525
453
  responseFragment: null,
526
454
  subagentEvents: [],
527
455
  providerSessionId,
528
456
  };
529
457
  }
530
458
  if (event.type === 'error') {
531
- const errorText = typeof event.error === 'string'
532
- ? event.error.trim()
533
- : event.error?.data?.message?.trim()
534
- || event.error?.message?.trim()
535
- || (event.error ? JSON.stringify(event.error) : '');
536
- const text = event.part?.text?.trim() || errorText;
459
+ const text = parseOpencodeError(event.error, event.fallbackText ?? undefined)?.message ?? '';
537
460
  return {
538
461
  logFragment: text ? `**Error:** ${text}` : null,
539
462
  responseFragment: null,
@@ -549,8 +472,9 @@ const parseOpencodePlannerJsonLine = (line, cwd) => {
549
472
  if (!trimmedLine) {
550
473
  return emptyParsedPlannerStreamLine();
551
474
  }
552
- const { jsonObjects, remainder } = extractLeadingJsonObjects(trimmedLine);
553
- if (jsonObjects.length === 0) {
475
+ const normalizedLine = parseOpencodeStreamLine(trimmedLine);
476
+ const { events, remainder } = normalizedLine;
477
+ if (!normalizedLine.structured) {
554
478
  if (trimmedLine.startsWith('{')) {
555
479
  return emptyParsedPlannerStreamLine();
556
480
  }
@@ -578,14 +502,7 @@ const parseOpencodePlannerJsonLine = (line, cwd) => {
578
502
  let concatenateFragments;
579
503
  let replaceFragment;
580
504
  let fragmentGroup;
581
- for (const jsonObject of jsonObjects) {
582
- let event;
583
- try {
584
- event = JSON.parse(jsonObject);
585
- }
586
- catch {
587
- continue;
588
- }
505
+ for (const event of events) {
589
506
  const parsedEvent = parseOpencodePlannerJsonEvent(event, cwd);
590
507
  const eventRecoveryEvents = parsedEvent.recoveryEvents ?? [];
591
508
  if (eventRecoveryEvents.some(recoveryEvent => recoveryEvent.type === 'error')) {
@@ -601,7 +518,7 @@ const parseOpencodePlannerJsonLine = (line, cwd) => {
601
518
  recoveryEvents.push(...eventRecoveryEvents);
602
519
  providerSessionId = providerSessionId ?? parsedEvent.providerSessionId;
603
520
  hasFinalAnswer ||= parsedEvent.hasFinalAnswer === true;
604
- if (jsonObjects.length === 1) {
521
+ if (events.length === 1) {
605
522
  concatenateFragments = parsedEvent.concatenateFragments;
606
523
  replaceFragment = parsedEvent.replaceFragment;
607
524
  fragmentGroup = parsedEvent.fragmentGroup;
@@ -672,10 +589,6 @@ const MEMORY_SUGGESTION_RULES = [
672
589
  const getPlanningMemorySuggestionRules = (memoryEnabled) => {
673
590
  return memoryEnabled ? MEMORY_SUGGESTION_RULES : '';
674
591
  };
675
- const ENGLISH_OUTPUT_RULES = [
676
- '- Always write the output in English regardless of the language used in the source description, ticket, or linked materials.',
677
- '- Translate or restate non-English input into clear natural English for titles, summaries, descriptions, constraints, acceptance criteria, implementation steps, and open questions.',
678
- ].join('\n');
679
592
  const EXPANDED_TICKET_EXAMPLE = [
680
593
  '{',
681
594
  ' "key": "header-hello-world",',
@@ -810,7 +723,7 @@ Primary implementation scope:
810
723
  Linked project findings:
811
724
  ${researchBlocks}`;
812
725
  };
813
- const buildPlanPrompt = (title, description, linkedResearchContext = '') => `You are helping plan a software development ticket. Based on the title and brief description below, write a detailed ticket description that is specific enough for a separate AI agent to implement the feature end-to-end without needing any further context or clarification.
726
+ const buildPlanPrompt = (title, description, linkedResearchContext = '') => appendAgentOutputLanguagePrompt(`You are helping plan a software development ticket. Based on the title and brief description below, write a detailed ticket description that is specific enough for a separate AI agent to implement the feature end-to-end without needing any further context or clarification.
814
727
 
815
728
  Include:
816
729
  ${IMPLEMENTATION_READY_DESCRIPTION_REQUIREMENTS}
@@ -822,15 +735,13 @@ Brief description: ${description}
822
735
  ${linkedResearchContext}
823
736
 
824
737
  Additional rules:
825
- - Language rules:
826
- ${ENGLISH_OUTPUT_RULES}
827
738
  - The downstream build agent will only work in the active project repo.
828
739
  - If linked-project findings are relevant, embed the required external contract details directly in the ticket.
829
740
  - Do not instruct the implementer to inspect linked projects or linked files.
830
741
  - Preserve any user-provided URLs, Figma links, docs, tickets, or other external resources that are needed during implementation.
831
742
  - Include those resources verbatim in the final ticket description instead of replacing them with vague summaries.
832
743
 
833
- Write only the expanded description in markdown, formatted to be readable by both humans and agents. No preamble or meta-commentary.`;
744
+ Write only the expanded description in markdown, formatted to be readable by both humans and agents. No preamble or meta-commentary.`);
834
745
  const buildSingleTicketPrompt = (title, description, linkedResearchContext = '', projectMemoryBlock = '', memoryEnabled = false, interactiveQuestions = false) => {
835
746
  const prompt = `You are helping plan a single software development ticket.
836
747
 
@@ -858,8 +769,6 @@ Rules:
858
769
  - Use the key \`main-ticket\`.
859
770
  - Use the provided title exactly.
860
771
  - Return an empty dependencies array.
861
- - Language rules:
862
- ${ENGLISH_OUTPUT_RULES}
863
772
  - The description must be valid markdown and include:
864
773
  ${IMPLEMENTATION_READY_DESCRIPTION_REQUIREMENTS}
865
774
  ${INDENTED_IMPLEMENTATION_READY_DESCRIPTION_SECTION_TEMPLATE}
@@ -877,7 +786,6 @@ ${IMPLEMENTATION_BODY_DEDUPLICATION_RULES}
877
786
  ${PLANNING_QUESTIONS_RULES}
878
787
  - Memory suggestion rules:${getPlanningMemorySuggestionRules(memoryEnabled) ? `
879
788
  ${getPlanningMemorySuggestionRules(memoryEnabled)}` : ' Omit memory suggestions entirely when project memory is disabled.'}
880
- - Write the natural-language update in English.
881
789
  - Keep the natural-language update to 1-3 short sentences focused on what changed in the plan.
882
790
  - Wrap the JSON object in <archon-plan-output>...</archon-plan-output> tags after the natural-language update.
883
791
  - Do not wrap the JSON in markdown fences.
@@ -889,9 +797,10 @@ ${projectMemoryBlock ? `${projectMemoryBlock}
889
797
 
890
798
  ` : ''}
891
799
  ${linkedResearchContext}`;
892
- return interactiveQuestions ? appendPlanModeQuestionPromptRules(prompt) : prompt;
800
+ const languagePrompt = appendAgentOutputLanguagePrompt(prompt);
801
+ return interactiveQuestions ? appendPlanModeQuestionPromptRules(languagePrompt) : languagePrompt;
893
802
  };
894
- const buildPlanningAgentOutlinePrompt = (description, linkedResearchContext = '', projectMemoryBlock = '') => `You are helping break down a software development initiative into implementation tickets for a kanban board.
803
+ const buildPlanningAgentOutlinePrompt = (description, linkedResearchContext = '', projectMemoryBlock = '') => appendAgentOutputLanguagePrompt(`You are helping break down a software development initiative into implementation tickets for a kanban board.
895
804
 
896
805
  This is pass 1 of 2. Your job is to decide the best ticket split and dependency graph, not to fully expand implementation details yet.
897
806
 
@@ -928,8 +837,6 @@ Rules:
928
837
  - Each ticket should be independently actionable and belong in the plan column.
929
838
  - Prefer the smallest useful number of tickets that still separates major implementation concerns cleanly.
930
839
  - Do not write full implementation-ready descriptions yet.
931
- - Language rules:
932
- ${ENGLISH_OUTPUT_RULES}
933
840
  - For each ticket, include:
934
841
  ${OUTLINE_DETAIL_REQUIREMENTS}
935
842
  - Use stable unique keys in kebab-case.
@@ -948,8 +855,8 @@ ${description}
948
855
  ${projectMemoryBlock ? `${projectMemoryBlock}
949
856
 
950
857
  ` : ''}
951
- ${linkedResearchContext}`;
952
- const buildPlanningAgentExpansionPrompt = (description, outline, linkedResearchContext = '', projectMemoryBlock = '') => `You are helping expand a previously decomposed software development initiative into implementation-ready tickets for a kanban board.
858
+ ${linkedResearchContext}`);
859
+ const buildPlanningAgentExpansionPrompt = (description, outline, linkedResearchContext = '', projectMemoryBlock = '') => appendAgentOutputLanguagePrompt(`You are helping expand a previously decomposed software development initiative into implementation-ready tickets for a kanban board.
953
860
 
954
861
  Each generated ticket will later be implemented by a separate AI agent, so every ticket description must be self-contained and implementation-ready without needing any further context or clarification.
955
862
 
@@ -987,8 +894,6 @@ Rules:
987
894
  - Preserve every ticket key exactly as provided.
988
895
  - Preserve every ticket title exactly as provided.
989
896
  - Preserve the dependency list exactly as provided.
990
- - Language rules:
991
- ${ENGLISH_OUTPUT_RULES}
992
897
  - Each description must be valid markdown and include:
993
898
  ${IMPLEMENTATION_READY_DESCRIPTION_REQUIREMENTS}
994
899
  ${INDENTED_IMPLEMENTATION_READY_DESCRIPTION_SECTION_TEMPLATE}
@@ -1016,7 +921,7 @@ ${description}
1016
921
  ${linkedResearchContext}
1017
922
 
1018
923
  Outline to expand:
1019
- ${JSON.stringify(outline, null, 2)}`;
924
+ ${JSON.stringify(outline, null, 2)}`);
1020
925
  const resolvePlannerCwd = (project, branch) => {
1021
926
  if (!project) {
1022
927
  return undefined;
@@ -1098,9 +1003,23 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
1098
1003
  ? appendClaudeHeadlessPlanPrompt(prompt)
1099
1004
  : prompt;
1100
1005
  const sessionTracking = options.sessionTracking;
1006
+ const sessionDirectory = cwd ?? process.cwd();
1101
1007
  const opencodeSessionOperations = options.executionProvider
1102
1008
  ? options.executionProvider.sessionOperations.opencode
1103
1009
  : hostOpencodeSessionOperations;
1010
+ const resolvedOpencodeCompatibility = (() => {
1011
+ if (tool !== 'opencode') {
1012
+ return null;
1013
+ }
1014
+ if (options.executionProvider?.kind === 'docker_sandbox') {
1015
+ if (!options.opencodeRuntimeIdentity) {
1016
+ throw new Error('The selected OpenCode execution environment has no validated runtime compatibility.');
1017
+ }
1018
+ return requireSupportedOpencodeCompatibility(inspectOpencodeRelease(options.opencodeRuntimeIdentity.version));
1019
+ }
1020
+ return requireSupportedOpencodeCompatibility(getOpencodeCliCompatibility({ force: true }));
1021
+ })();
1022
+ const resolvedOpencodeRuntimeIdentity = resolvedOpencodeCompatibility?.runtimeIdentity ?? null;
1104
1023
  let sessionId = null;
1105
1024
  let spawnTimestamp = null;
1106
1025
  let sessionLookupTimer = null;
@@ -1140,21 +1059,21 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
1140
1059
  });
1141
1060
  return [invocation.command, [...invocation.args], invocation.stdio];
1142
1061
  })()
1143
- : [
1144
- 'opencode',
1145
- [
1146
- 'run',
1147
- '--agent',
1148
- 'plan',
1149
- '--format',
1150
- 'json',
1151
- ...(sessionTracking?.resumeSessionId ? ['--session', sessionTracking.resumeSessionId] : []),
1152
- ...(resolvedModel ? ['--model', resolvedModel] : []),
1153
- ...(variant ? ['--variant', variant] : []),
1154
- finalPrompt,
1155
- ],
1156
- ['ignore', 'pipe', 'pipe'],
1157
- ];
1062
+ : (() => {
1063
+ const invocation = opencodeAgentProvider.buildStreamingInvocation({
1064
+ cwd: cwd ?? process.cwd(),
1065
+ prompt: finalPrompt,
1066
+ model: resolvedModel || null,
1067
+ variant,
1068
+ skills: options.skills,
1069
+ mode: 'plan',
1070
+ resumeSessionId: sessionTracking?.resumeSessionId ?? null,
1071
+ sessionId: randomUUID(),
1072
+ opencodeRuntimeIdentity: resolvedOpencodeRuntimeIdentity,
1073
+ opencodeCompatibility: resolvedOpencodeCompatibility,
1074
+ });
1075
+ return [invocation.command, [...invocation.args], invocation.stdio];
1076
+ })();
1158
1077
  return new Promise((resolve, reject) => {
1159
1078
  let settled = false;
1160
1079
  let completionForced = false;
@@ -1169,6 +1088,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
1169
1088
  executionContext: options.executionContext,
1170
1089
  mainRun: options.mainRun,
1171
1090
  deferMainFinalization: Boolean(options.mainRun),
1091
+ opencodeRuntimeIdentity: resolvedOpencodeRuntimeIdentity,
1172
1092
  })
1173
1093
  : null;
1174
1094
  let opencodeSubagentMonitor = null;
@@ -1207,12 +1127,13 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
1207
1127
  if (!normalized) {
1208
1128
  return;
1209
1129
  }
1130
+ const sessionChanged = resolvedSessionId !== normalized;
1210
1131
  resolvedSessionId = normalized;
1211
1132
  opencodeSubagentMonitor?.setParentSessionId(normalized);
1212
1133
  if (options.mainRun) {
1213
- updateAgentRunSessionId(options.mainRun.id, normalized);
1134
+ updateAgentRunSessionId(options.mainRun.id, normalized, resolvedOpencodeRuntimeIdentity);
1214
1135
  }
1215
- if (sessionTracking && !hasResolvedSessionId) {
1136
+ if (sessionTracking && (!hasResolvedSessionId || sessionChanged)) {
1216
1137
  hasResolvedSessionId = true;
1217
1138
  updatePlanningSessionId(sessionTracking.ticketId, normalized, tool, sessionTracking.io, opencodeSessionOperations ?? undefined);
1218
1139
  }
@@ -1222,7 +1143,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
1222
1143
  return false;
1223
1144
  }
1224
1145
  try {
1225
- const session = await opencodeSessionOperations.findLatestSessionAfter(spawnTimestamp ?? 0, cwd);
1146
+ const session = await opencodeSessionOperations.findLatestSessionAfter(spawnTimestamp ?? 0, { directory: sessionDirectory });
1226
1147
  if (!hasResolvedSessionId && session?.id) {
1227
1148
  bindResolvedProviderSession(session.id);
1228
1149
  }
@@ -1330,7 +1251,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
1330
1251
  bindResolvedProviderSession(discoveredSessionId);
1331
1252
  },
1332
1253
  taskSessionReader: opencodeSessionOperations
1333
- ? createOpencodeTaskSessionReader(opencodeSessionOperations)
1254
+ ? createOpencodeTaskSessionReader(opencodeSessionOperations, { directory: sessionDirectory })
1334
1255
  : null,
1335
1256
  });
1336
1257
  opencodeSubagentMonitor.start();
@@ -2021,6 +1942,7 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
2021
1942
  executionTarget,
2022
1943
  executionLauncherEnvironment: childEnvironment.launcherEnvironment,
2023
1944
  executionRuntimeEnvironment: childEnvironment.runtimeEnvironment,
1945
+ opencodeRuntimeIdentity: childEnvironment.opencodeRuntimeIdentity ?? null,
2024
1946
  ...(invocation ? { mainRun: invocation } : {}),
2025
1947
  });
2026
1948
  const result = normalizeLinkedResearchResponse(extractFirstJsonObject(output), linkedProject, request);
@@ -2353,7 +2275,24 @@ export const startPlan = (ticket, io, options = {}) => {
2353
2275
  workload: 'plan',
2354
2276
  signal: cancellationState.abortController?.signal,
2355
2277
  });
2356
- const planningSessionId = options.providerContinuation === 'fresh' ? null : ticket.planning_session_id;
2278
+ let planningSessionId = options.providerContinuation === 'fresh' ? null : ticket.planning_session_id;
2279
+ const historicalProviderSession = planningSessionId
2280
+ ? resolveHistoricalProviderSessionForParent({
2281
+ projectId: project.id,
2282
+ currentExecutionRunId: executionContext.runId,
2283
+ parentType: 'ticket',
2284
+ parentId: ticket.id,
2285
+ sessionId: planningSessionId,
2286
+ })
2287
+ : null;
2288
+ if (shouldStartFreshProviderSession({
2289
+ tool: runTool,
2290
+ sessionId: planningSessionId,
2291
+ historicalRuntimeIdentity: historicalProviderSession?.runtimeIdentity ?? null,
2292
+ currentRuntimeIdentity: workloadEnvironment.opencodeRuntimeIdentity ?? null,
2293
+ })) {
2294
+ planningSessionId = null;
2295
+ }
2357
2296
  if (planningSessionId) {
2358
2297
  assertProviderSessionAuthorityMatches({
2359
2298
  projectId: project.id,
@@ -2383,6 +2322,7 @@ export const startPlan = (ticket, io, options = {}) => {
2383
2322
  executionTarget,
2384
2323
  executionLauncherEnvironment: workloadEnvironment.launcherEnvironment,
2385
2324
  executionRuntimeEnvironment: workloadEnvironment.runtimeEnvironment,
2325
+ opencodeRuntimeIdentity: workloadEnvironment.opencodeRuntimeIdentity ?? null,
2386
2326
  onProgress: progress => {
2387
2327
  updatePlanningProgress(ticket.id, progress.log, progress.response, io);
2388
2328
  },