issue-flow 0.19.1 → 0.20.0

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 (156) hide show
  1. package/README.md +12 -0
  2. package/dist/{agent-EWKA7357.js → agent-4DHRKZ2Z.js} +11 -11
  3. package/dist/{analyze-Z7ODC27F.js → analyze-UEJ2R3H5.js} +19 -19
  4. package/dist/{apply-VNSWQS6O.js → apply-QDYNQMUX.js} +11 -11
  5. package/dist/{bench-ZJEIACUK.js → bench-RNRXVEFK.js} +16 -16
  6. package/dist/{chunk-2EZW4X57.js → chunk-37O2FMAN.js} +8 -8
  7. package/dist/{chunk-IMB6FA2F.js → chunk-44RF3VFG.js} +48 -4
  8. package/dist/chunk-44RF3VFG.js.map +1 -0
  9. package/dist/{chunk-WPHC6JBR.js → chunk-7WBUEBD5.js} +4 -4
  10. package/dist/{chunk-KDQRNVBZ.js → chunk-ADH6RJNX.js} +3 -3
  11. package/dist/{chunk-HHXWAWU6.js → chunk-AKL5UPR6.js} +11 -11
  12. package/dist/{chunk-XKR3VD2Z.js → chunk-BTBJ5UOO.js} +3 -3
  13. package/dist/{chunk-UDRAD7MF.js → chunk-CLZ6RRZL.js} +7 -7
  14. package/dist/{chunk-J6VJ5M2U.js → chunk-DBLXLKGU.js} +7 -7
  15. package/dist/{chunk-3JD25HHJ.js → chunk-DZ3DZ3EN.js} +5 -5
  16. package/dist/{chunk-P7ZYOC23.js → chunk-EORDSKWZ.js} +7 -7
  17. package/dist/chunk-EORDSKWZ.js.map +1 -0
  18. package/dist/{chunk-XQLNZW7I.js → chunk-EYKPWHT7.js} +9 -9
  19. package/dist/{chunk-2YYP7AE6.js → chunk-FU2FQ4JE.js} +10 -10
  20. package/dist/{chunk-RGFMQFX7.js → chunk-G442RDFX.js} +5 -5
  21. package/dist/{chunk-7CMVL4X6.js → chunk-I64N6RL6.js} +2 -2
  22. package/dist/{chunk-XHCP6ZNO.js → chunk-JBYXJOJJ.js} +11 -11
  23. package/dist/{chunk-GD7JZMSJ.js → chunk-JCR5C5A7.js} +2 -2
  24. package/dist/{chunk-UPAAZU4W.js → chunk-K5NM26NV.js} +2 -2
  25. package/dist/{chunk-TJVX42KY.js → chunk-KUA6KBBD.js} +2 -2
  26. package/dist/{chunk-WB2FVIUS.js → chunk-KUL64XUF.js} +5 -5
  27. package/dist/{chunk-DXH4TQRB.js → chunk-MML2G7IC.js} +2 -2
  28. package/dist/{chunk-IQYXXFRC.js → chunk-PM5YWJYO.js} +5 -5
  29. package/dist/chunk-PM5YWJYO.js.map +1 -0
  30. package/dist/{chunk-HWWB22HC.js → chunk-PXPTIXJF.js} +9 -8
  31. package/dist/chunk-PXPTIXJF.js.map +1 -0
  32. package/dist/{chunk-MHA7Q3KU.js → chunk-QJHZ3HYJ.js} +24 -24
  33. package/dist/{chunk-LYC57OXF.js → chunk-RDPK7LYK.js} +4 -4
  34. package/dist/{chunk-46S7APLQ.js → chunk-RMIBLFG3.js} +9 -9
  35. package/dist/{chunk-ZAYATXJD.js → chunk-T736DSZI.js} +5 -5
  36. package/dist/{chunk-MQTVMB7W.js → chunk-UDUUUFQF.js} +35 -12
  37. package/dist/chunk-UDUUUFQF.js.map +1 -0
  38. package/dist/{chunk-PHPAK2L6.js → chunk-V7GETODQ.js} +18 -12
  39. package/dist/{chunk-PHPAK2L6.js.map → chunk-V7GETODQ.js.map} +1 -1
  40. package/dist/{chunk-PRGPSNGA.js → chunk-VHQMMY2D.js} +2 -2
  41. package/dist/{chunk-F2NFJ27Z.js → chunk-VJ3PF6B7.js} +50 -16
  42. package/dist/chunk-VJ3PF6B7.js.map +1 -0
  43. package/dist/{chunk-HEHHQU4G.js → chunk-WB4FA2EH.js} +6 -6
  44. package/dist/{chunk-2Q6PG3MT.js → chunk-WQSGL5LX.js} +11 -5
  45. package/dist/chunk-WQSGL5LX.js.map +1 -0
  46. package/dist/{chunk-LRWIP7QS.js → chunk-Y2KOWABB.js} +3 -3
  47. package/dist/{chunk-UHDXXLYH.js → chunk-YC24E66P.js} +538 -40
  48. package/dist/chunk-YC24E66P.js.map +1 -0
  49. package/dist/{chunk-NYDAHE3Y.js → chunk-Z6RCKCVB.js} +8 -8
  50. package/dist/{chunk-ERAG5IQB.js → chunk-ZPGNVBWY.js} +3 -3
  51. package/dist/cli.js +55 -53
  52. package/dist/cli.js.map +1 -1
  53. package/dist/{compat-YPDZB34U.js → compat-OJG76J4I.js} +5 -5
  54. package/dist/{config-56B4OHZE.js → config-6YTWPDBK.js} +10 -10
  55. package/dist/{conventions-DW2CM5I3.js → conventions-5UPOTU42.js} +13 -13
  56. package/dist/{db-5NU77PJA.js → db-QAZG4LQD.js} +9 -9
  57. package/dist/{diagnostics-UCTS2VUF.js → diagnostics-YEFB42E5.js} +6 -6
  58. package/dist/execute-QCT64D37.js +38 -0
  59. package/dist/{generate-O7GUXLN4.js → generate-QATMDKOK.js} +17 -17
  60. package/dist/{git-LCG45YXD.js → git-XGOECXWG.js} +2 -2
  61. package/dist/{history-6GSURU3H.js → history-NBPUZVGQ.js} +9 -9
  62. package/dist/{init-DD6DBRC5.js → init-4LB2YKWP.js} +11 -11
  63. package/dist/{operations-HU5ZFEBA.js → operations-RUQP2Y2F.js} +11 -11
  64. package/dist/{permissions-NNNSRC4P.js → permissions-QZPUUBSO.js} +3 -3
  65. package/dist/plan-2NMSHTMD.js +38 -0
  66. package/dist/{policy-RFJOJQL6.js → policy-RKKFF5A2.js} +11 -11
  67. package/dist/pr-QKFO5HI3.js +42 -0
  68. package/dist/pr-review-H2BFD6F2.js +33 -0
  69. package/dist/prd-ET6XKYRS.js +37 -0
  70. package/dist/{ps-AKRHGPSR.js → ps-UIKSOUAQ.js} +10 -10
  71. package/dist/{recorder-T7426CKV.js → recorder-LOU3PTIE.js} +6 -6
  72. package/dist/{registry-DWRKD65A.js → registry-HV7M6MAH.js} +4 -4
  73. package/dist/{repository-TABBRW2C.js → repository-RCRR6RDE.js} +2 -2
  74. package/dist/{resume-GDXKK5XP.js → resume-BWJZGBLZ.js} +36 -36
  75. package/dist/review-2MTZLNSS.js +38 -0
  76. package/dist/{routing-FPNUVE7T.js → routing-RM5ABHHD.js} +12 -12
  77. package/dist/run-XMACQBRJ.js +61 -0
  78. package/dist/{state-manager-IGNTD4AB.js → state-manager-SRN4VJSX.js} +4 -4
  79. package/dist/{usage-XW27AL5K.js → usage-JOODVE5O.js} +9 -9
  80. package/dist/{web-NCDBVZ5Y.js → web-TLMWJ2BM.js} +15 -15
  81. package/package.json +3 -2
  82. package/web/public/app.js +2 -2
  83. package/dist/chunk-2Q6PG3MT.js.map +0 -1
  84. package/dist/chunk-F2NFJ27Z.js.map +0 -1
  85. package/dist/chunk-HWWB22HC.js.map +0 -1
  86. package/dist/chunk-IMB6FA2F.js.map +0 -1
  87. package/dist/chunk-IQYXXFRC.js.map +0 -1
  88. package/dist/chunk-MQTVMB7W.js.map +0 -1
  89. package/dist/chunk-P7ZYOC23.js.map +0 -1
  90. package/dist/chunk-UHDXXLYH.js.map +0 -1
  91. package/dist/execute-R7AVOLNG.js +0 -38
  92. package/dist/plan-XR6B7EM3.js +0 -38
  93. package/dist/pr-OSCNJCOO.js +0 -42
  94. package/dist/pr-review-IKIYHFBO.js +0 -33
  95. package/dist/prd-HFDZJJQR.js +0 -37
  96. package/dist/review-JJHMQA2O.js +0 -38
  97. package/dist/run-RLCURLLL.js +0 -61
  98. /package/dist/{agent-EWKA7357.js.map → agent-4DHRKZ2Z.js.map} +0 -0
  99. /package/dist/{analyze-Z7ODC27F.js.map → analyze-UEJ2R3H5.js.map} +0 -0
  100. /package/dist/{apply-VNSWQS6O.js.map → apply-QDYNQMUX.js.map} +0 -0
  101. /package/dist/{bench-ZJEIACUK.js.map → bench-RNRXVEFK.js.map} +0 -0
  102. /package/dist/{chunk-2EZW4X57.js.map → chunk-37O2FMAN.js.map} +0 -0
  103. /package/dist/{chunk-WPHC6JBR.js.map → chunk-7WBUEBD5.js.map} +0 -0
  104. /package/dist/{chunk-KDQRNVBZ.js.map → chunk-ADH6RJNX.js.map} +0 -0
  105. /package/dist/{chunk-HHXWAWU6.js.map → chunk-AKL5UPR6.js.map} +0 -0
  106. /package/dist/{chunk-XKR3VD2Z.js.map → chunk-BTBJ5UOO.js.map} +0 -0
  107. /package/dist/{chunk-UDRAD7MF.js.map → chunk-CLZ6RRZL.js.map} +0 -0
  108. /package/dist/{chunk-J6VJ5M2U.js.map → chunk-DBLXLKGU.js.map} +0 -0
  109. /package/dist/{chunk-3JD25HHJ.js.map → chunk-DZ3DZ3EN.js.map} +0 -0
  110. /package/dist/{chunk-XQLNZW7I.js.map → chunk-EYKPWHT7.js.map} +0 -0
  111. /package/dist/{chunk-2YYP7AE6.js.map → chunk-FU2FQ4JE.js.map} +0 -0
  112. /package/dist/{chunk-RGFMQFX7.js.map → chunk-G442RDFX.js.map} +0 -0
  113. /package/dist/{chunk-7CMVL4X6.js.map → chunk-I64N6RL6.js.map} +0 -0
  114. /package/dist/{chunk-XHCP6ZNO.js.map → chunk-JBYXJOJJ.js.map} +0 -0
  115. /package/dist/{chunk-GD7JZMSJ.js.map → chunk-JCR5C5A7.js.map} +0 -0
  116. /package/dist/{chunk-UPAAZU4W.js.map → chunk-K5NM26NV.js.map} +0 -0
  117. /package/dist/{chunk-TJVX42KY.js.map → chunk-KUA6KBBD.js.map} +0 -0
  118. /package/dist/{chunk-WB2FVIUS.js.map → chunk-KUL64XUF.js.map} +0 -0
  119. /package/dist/{chunk-DXH4TQRB.js.map → chunk-MML2G7IC.js.map} +0 -0
  120. /package/dist/{chunk-MHA7Q3KU.js.map → chunk-QJHZ3HYJ.js.map} +0 -0
  121. /package/dist/{chunk-LYC57OXF.js.map → chunk-RDPK7LYK.js.map} +0 -0
  122. /package/dist/{chunk-46S7APLQ.js.map → chunk-RMIBLFG3.js.map} +0 -0
  123. /package/dist/{chunk-ZAYATXJD.js.map → chunk-T736DSZI.js.map} +0 -0
  124. /package/dist/{chunk-PRGPSNGA.js.map → chunk-VHQMMY2D.js.map} +0 -0
  125. /package/dist/{chunk-HEHHQU4G.js.map → chunk-WB4FA2EH.js.map} +0 -0
  126. /package/dist/{chunk-LRWIP7QS.js.map → chunk-Y2KOWABB.js.map} +0 -0
  127. /package/dist/{chunk-NYDAHE3Y.js.map → chunk-Z6RCKCVB.js.map} +0 -0
  128. /package/dist/{chunk-ERAG5IQB.js.map → chunk-ZPGNVBWY.js.map} +0 -0
  129. /package/dist/{compat-YPDZB34U.js.map → compat-OJG76J4I.js.map} +0 -0
  130. /package/dist/{config-56B4OHZE.js.map → config-6YTWPDBK.js.map} +0 -0
  131. /package/dist/{conventions-DW2CM5I3.js.map → conventions-5UPOTU42.js.map} +0 -0
  132. /package/dist/{db-5NU77PJA.js.map → db-QAZG4LQD.js.map} +0 -0
  133. /package/dist/{diagnostics-UCTS2VUF.js.map → diagnostics-YEFB42E5.js.map} +0 -0
  134. /package/dist/{execute-R7AVOLNG.js.map → execute-QCT64D37.js.map} +0 -0
  135. /package/dist/{generate-O7GUXLN4.js.map → generate-QATMDKOK.js.map} +0 -0
  136. /package/dist/{git-LCG45YXD.js.map → git-XGOECXWG.js.map} +0 -0
  137. /package/dist/{history-6GSURU3H.js.map → history-NBPUZVGQ.js.map} +0 -0
  138. /package/dist/{init-DD6DBRC5.js.map → init-4LB2YKWP.js.map} +0 -0
  139. /package/dist/{operations-HU5ZFEBA.js.map → operations-RUQP2Y2F.js.map} +0 -0
  140. /package/dist/{permissions-NNNSRC4P.js.map → permissions-QZPUUBSO.js.map} +0 -0
  141. /package/dist/{plan-XR6B7EM3.js.map → plan-2NMSHTMD.js.map} +0 -0
  142. /package/dist/{policy-RFJOJQL6.js.map → policy-RKKFF5A2.js.map} +0 -0
  143. /package/dist/{pr-OSCNJCOO.js.map → pr-QKFO5HI3.js.map} +0 -0
  144. /package/dist/{pr-review-IKIYHFBO.js.map → pr-review-H2BFD6F2.js.map} +0 -0
  145. /package/dist/{prd-HFDZJJQR.js.map → prd-ET6XKYRS.js.map} +0 -0
  146. /package/dist/{ps-AKRHGPSR.js.map → ps-UIKSOUAQ.js.map} +0 -0
  147. /package/dist/{recorder-T7426CKV.js.map → recorder-LOU3PTIE.js.map} +0 -0
  148. /package/dist/{registry-DWRKD65A.js.map → registry-HV7M6MAH.js.map} +0 -0
  149. /package/dist/{repository-TABBRW2C.js.map → repository-RCRR6RDE.js.map} +0 -0
  150. /package/dist/{resume-GDXKK5XP.js.map → resume-BWJZGBLZ.js.map} +0 -0
  151. /package/dist/{review-JJHMQA2O.js.map → review-2MTZLNSS.js.map} +0 -0
  152. /package/dist/{routing-FPNUVE7T.js.map → routing-RM5ABHHD.js.map} +0 -0
  153. /package/dist/{run-RLCURLLL.js.map → run-XMACQBRJ.js.map} +0 -0
  154. /package/dist/{state-manager-IGNTD4AB.js.map → state-manager-SRN4VJSX.js.map} +0 -0
  155. /package/dist/{usage-XW27AL5K.js.map → usage-JOODVE5O.js.map} +0 -0
  156. /package/dist/{web-NCDBVZ5Y.js.map → web-TLMWJ2BM.js.map} +0 -0
@@ -7,27 +7,29 @@ import {
7
7
  printWarning,
8
8
  readProjectConfigFile,
9
9
  resolveIssuePaths
10
- } from "./chunk-J6VJ5M2U.js";
10
+ } from "./chunk-DBLXLKGU.js";
11
11
  import {
12
12
  DEFAULT_TELEMETRY_CONFIG
13
- } from "./chunk-HEHHQU4G.js";
13
+ } from "./chunk-WB4FA2EH.js";
14
14
  import {
15
15
  parseCodexUsage,
16
16
  parseUsage
17
- } from "./chunk-GD7JZMSJ.js";
17
+ } from "./chunk-JCR5C5A7.js";
18
18
  import {
19
19
  AGENT_PHASES,
20
+ AGENT_PROVIDER_IDS,
20
21
  ANTIGRAVITY_CAPABILITIES,
21
22
  CLAUDE_CAPABILITIES,
22
23
  CODEX_CAPABILITIES,
23
24
  CURSOR_CAPABILITIES,
25
+ OPENCODE_CAPABILITIES,
24
26
  agentConfigInputSchema,
25
27
  isAgentPhase,
26
28
  isAgentProviderId,
27
29
  parsePhasesInput,
28
30
  resilienceConfigSchema,
29
31
  telemetryConfigInputSchema
30
- } from "./chunk-IMB6FA2F.js";
32
+ } from "./chunk-44RF3VFG.js";
31
33
  import {
32
34
  issuesConfigSchema,
33
35
  policyConfigInputSchema,
@@ -42,19 +44,16 @@ import {
42
44
  RETRY_CONFIG_KEYS,
43
45
  getProjectRoot,
44
46
  run
45
- } from "./chunk-TJVX42KY.js";
47
+ } from "./chunk-KUA6KBBD.js";
46
48
 
47
49
  // src/config/dependencies.ts
48
50
  import { platform } from "node:os";
49
51
 
50
52
  // src/agents/availability.ts
51
- import { execa as execa6 } from "execa";
53
+ import { execa as execa7 } from "execa";
52
54
 
53
- // src/agents/registry.ts
54
- import { execa as execa5 } from "execa";
55
-
56
- // src/agents/antigravity.ts
57
- import { execa as execa2 } from "execa";
55
+ // src/agents/opencode.ts
56
+ import { execa as execa3 } from "execa";
58
57
 
59
58
  // src/core/shutdown.ts
60
59
  var SHUTDOWN_GRACE_MS = 15e3;
@@ -250,6 +249,9 @@ function describeStall(silentMs, provider = "claude") {
250
249
  return `${provider} produced no output for ${Math.round(silentMs / 1e3)}s and was stopped (stalled)`;
251
250
  }
252
251
 
252
+ // src/agents/antigravity.ts
253
+ import { execa as execa2 } from "execa";
254
+
253
255
  // src/agents/claude.ts
254
256
  import { execa } from "execa";
255
257
 
@@ -978,11 +980,382 @@ ${stdout}`
978
980
  }
979
981
  };
980
982
 
983
+ // src/agents/opencode.ts
984
+ var OPENCODE_MIN_VERSION = "1.15.0";
985
+ var DEFAULT_MAX_PROMPT_BYTES2 = 1e5;
986
+ var OPENCODE_INSTALL_URL = "https://opencode.ai/docs";
987
+ var MUTATING_BASH = [
988
+ "rm *",
989
+ "rmdir *",
990
+ "mv *",
991
+ "cp *",
992
+ "chmod *",
993
+ "chown *",
994
+ "mkdir *",
995
+ "touch *",
996
+ "tee *",
997
+ "git add *",
998
+ "git commit *",
999
+ "git push *",
1000
+ "git checkout *",
1001
+ "git reset *",
1002
+ "git rebase *",
1003
+ "npm install *",
1004
+ "npm ci *",
1005
+ "pnpm install *",
1006
+ "yarn add *"
1007
+ ];
1008
+ function isRecord2(value) {
1009
+ return typeof value === "object" && value !== null;
1010
+ }
1011
+ function maxPromptBytesOf2(settings) {
1012
+ return settings.maxPromptBytes ?? DEFAULT_MAX_PROMPT_BYTES2;
1013
+ }
1014
+ function interpretOpenCodeAuth(text) {
1015
+ const cleaned = text.replaceAll(`${String.fromCharCode(27)}[`, "[").trim();
1016
+ if (cleaned === "") return false;
1017
+ if (/no credentials|not logged|not authenticated|no providers/i.test(cleaned)) return false;
1018
+ return /[a-z0-9][a-z0-9._-]*/i.test(cleaned);
1019
+ }
1020
+ function parseOpenCodeUsage(tokens) {
1021
+ if (!isRecord2(tokens)) return null;
1022
+ const result = {};
1023
+ if (typeof tokens.input === "number" && Number.isFinite(tokens.input)) {
1024
+ result.inputTokens = tokens.input;
1025
+ }
1026
+ if (typeof tokens.output === "number" && Number.isFinite(tokens.output)) {
1027
+ result.outputTokens = tokens.output;
1028
+ }
1029
+ const cache = isRecord2(tokens.cache) ? tokens.cache : {};
1030
+ if (typeof cache.read === "number" && Number.isFinite(cache.read)) {
1031
+ result.cacheReadTokens = cache.read;
1032
+ }
1033
+ if (typeof cache.write === "number" && Number.isFinite(cache.write)) {
1034
+ result.cacheCreationTokens = cache.write;
1035
+ }
1036
+ return Object.keys(result).length === 0 ? null : result;
1037
+ }
1038
+ function isPermissionDenial2(message) {
1039
+ return /permission|denied|not allowed|external_directory/i.test(message);
1040
+ }
1041
+ function toolDetail(name, input) {
1042
+ const key = name === "bash" || name === "read" || name === "edit" || name === "write" ? ["command", "path", "filePath", "file"] : ["path", "pattern", "query", "url", "command"];
1043
+ for (const field of key) {
1044
+ const value = input[field];
1045
+ if (typeof value === "string" && value !== "") {
1046
+ return value.length > 80 ? `${value.slice(0, 77)}...` : value;
1047
+ }
1048
+ }
1049
+ return "";
1050
+ }
1051
+ function extractError(event) {
1052
+ if (typeof event.error === "string" && event.error !== "") return event.error;
1053
+ const error = isRecord2(event.error) ? event.error : {};
1054
+ const data = isRecord2(error.data) ? error.data : {};
1055
+ if (typeof data.message === "string" && data.message !== "") return data.message;
1056
+ if (typeof error.message === "string" && error.message !== "") return error.message;
1057
+ if (typeof error.name === "string" && error.name !== "") return error.name;
1058
+ return "OpenCode reported an error";
1059
+ }
1060
+ function consumeOpenCodeEvent(event, onEvent, acc) {
1061
+ if (typeof event.sessionID === "string" && event.sessionID !== "") {
1062
+ acc.sessionId = event.sessionID;
1063
+ }
1064
+ if (event.type === "text") {
1065
+ const part = isRecord2(event.part) ? event.part : {};
1066
+ if (typeof part.text === "string" && part.text !== "") {
1067
+ acc.result += part.text;
1068
+ onEvent?.({ kind: "text", text: part.text });
1069
+ }
1070
+ return;
1071
+ }
1072
+ if (event.type === "tool_use") {
1073
+ const part = isRecord2(event.part) ? event.part : {};
1074
+ const name = typeof part.tool === "string" ? part.tool : "tool";
1075
+ const state = isRecord2(part.state) ? part.state : {};
1076
+ const input = isRecord2(state.input) ? state.input : {};
1077
+ const detail = toolDetail(name, input);
1078
+ onEvent?.({ kind: "tool", name, ...detail === "" ? {} : { detail } });
1079
+ const error = isRecord2(state.error) ? state.error : {};
1080
+ const message = typeof error.message === "string" ? error.message : typeof state.status === "string" && state.status === "error" ? `${name} failed` : "";
1081
+ if (message !== "" && isPermissionDenial2(message)) {
1082
+ acc.permissionDenied = { tool: name, message };
1083
+ }
1084
+ return;
1085
+ }
1086
+ if (event.type === "step_finish") {
1087
+ const part = isRecord2(event.part) ? event.part : {};
1088
+ if (part.reason === "stop") acc.seenTerminal = true;
1089
+ const usage = parseOpenCodeUsage(part.tokens);
1090
+ if (usage) acc.usage = usage;
1091
+ return;
1092
+ }
1093
+ if (event.type === "error") {
1094
+ acc.error = extractError(event);
1095
+ acc.seenTerminal = true;
1096
+ }
1097
+ }
1098
+ function parseOpenCodeStream(raw, onEvent) {
1099
+ const acc = {
1100
+ result: "",
1101
+ sessionId: null,
1102
+ model: null,
1103
+ usage: null,
1104
+ seenTerminal: false,
1105
+ error: null,
1106
+ permissionDenied: null
1107
+ };
1108
+ for (const line of raw.split("\n")) {
1109
+ const trimmed = line.trim();
1110
+ if (trimmed === "") continue;
1111
+ try {
1112
+ const event = JSON.parse(trimmed);
1113
+ if (!isRecord2(event)) continue;
1114
+ consumeOpenCodeEvent(event, onEvent, acc);
1115
+ } catch {
1116
+ }
1117
+ }
1118
+ return acc;
1119
+ }
1120
+ function buildOpenCodePermission(permission, addDirs = []) {
1121
+ const external = { "*": "deny" };
1122
+ for (const dir of addDirs) {
1123
+ const normalized = dir.replace(/\\/g, "/").replace(/\/$/, "");
1124
+ if (normalized === "") continue;
1125
+ external[normalized] = "allow";
1126
+ external[`${normalized}/**`] = "allow";
1127
+ }
1128
+ const bash = permission === "read-only" ? Object.fromEntries([["*", "allow"], ...MUTATING_BASH.map((rule) => [rule, "deny"])]) : "allow";
1129
+ return {
1130
+ edit: permission === "read-only" ? "deny" : "allow",
1131
+ bash,
1132
+ question: "deny",
1133
+ external_directory: external
1134
+ };
1135
+ }
1136
+ function buildOpenCodeArgv(invocation, settings) {
1137
+ if (settings.model && !settings.model.includes("/")) {
1138
+ return {
1139
+ error: "configuration: OpenCode model must be provider/model (for example opencode-go/qwen3.8-flash)."
1140
+ };
1141
+ }
1142
+ const promptBytes = Buffer.byteLength(invocation.prompt, "utf8");
1143
+ const limit = maxPromptBytesOf2(settings.opencode);
1144
+ if (promptBytes > limit) {
1145
+ return {
1146
+ error: `configuration: prompt exceeds OpenCode argv limit (${promptBytes} bytes > ${limit} maxPromptBytes). The promptChannel is argv; shorten the prompt or raise agent.opencode.maxPromptBytes.`
1147
+ };
1148
+ }
1149
+ const workspace = invocation.workingDirectory ?? process.cwd();
1150
+ const args = ["run", "--format", "json", "--dir", workspace, "--auto"];
1151
+ if (settings.model) args.push("--model", settings.model);
1152
+ if (settings.opencode.variant) args.push("--variant", settings.opencode.variant);
1153
+ args.push(invocation.prompt);
1154
+ return {
1155
+ command: "opencode",
1156
+ args,
1157
+ env: {
1158
+ ...process.env,
1159
+ OPENCODE_PERMISSION: JSON.stringify(
1160
+ buildOpenCodePermission(invocation.permission, invocation.addDirs ?? [])
1161
+ )
1162
+ }
1163
+ };
1164
+ }
1165
+ function opencodeRunVerdict(input) {
1166
+ if (input.parsed.permissionDenied) {
1167
+ return {
1168
+ success: false,
1169
+ error: `configuration: permission denied for ${input.parsed.permissionDenied.tool}. ${input.parsed.permissionDenied.message}`
1170
+ };
1171
+ }
1172
+ if (input.parsed.error) {
1173
+ return { success: false, error: input.parsed.error };
1174
+ }
1175
+ const hasTerminalEvidence = input.parsed.seenTerminal || input.parsed.result.trim() !== "" || input.parsed.error !== null;
1176
+ if (!hasTerminalEvidence) {
1177
+ return {
1178
+ success: false,
1179
+ error: "configuration: OpenCode finished without a terminal event in the stream."
1180
+ };
1181
+ }
1182
+ if (input.exitCode !== 0 || input.timedOut) {
1183
+ return {
1184
+ success: false,
1185
+ error: input.parsed.error ?? `opencode exited with code ${input.exitCode}`
1186
+ };
1187
+ }
1188
+ return { success: true, error: null };
1189
+ }
1190
+ function configurationFailure2(agent, message, rawOutput = message) {
1191
+ return {
1192
+ success: false,
1193
+ result: "",
1194
+ rawOutput,
1195
+ exitCode: 1,
1196
+ usage: null,
1197
+ error: message,
1198
+ agent,
1199
+ harnessVersion: peekHarnessVersion("opencode")
1200
+ };
1201
+ }
1202
+ var OpenCodeRunner = class {
1203
+ id = "opencode";
1204
+ capabilities = OPENCODE_CAPABILITIES;
1205
+ versionCommand() {
1206
+ return { command: "opencode", args: ["--version"] };
1207
+ }
1208
+ authCommand() {
1209
+ return { command: "opencode", args: ["auth", "list"] };
1210
+ }
1211
+ async run(invocation, settings) {
1212
+ const agent = { provider: this.id, model: settings.model };
1213
+ const built = buildOpenCodeArgv(invocation, settings);
1214
+ if ("error" in built) return configurationFailure2(agent, built.error);
1215
+ const minimum = settings.opencode.minVersion ?? OPENCODE_MIN_VERSION;
1216
+ const installed2 = peekHarnessVersion(this.id);
1217
+ if (typeof installed2 === "string" && compareVersions(installed2, minimum) < 0) {
1218
+ return configurationFailure2(
1219
+ agent,
1220
+ `configuration: opencode ${installed2} is below the minimum ${minimum}. Update OpenCode CLI.`
1221
+ );
1222
+ }
1223
+ const { command, args, env } = built;
1224
+ const startTime = Date.now();
1225
+ const timeoutMs = invocation.timeout;
1226
+ let cleanup = null;
1227
+ try {
1228
+ const subprocess = execa3(command, args, {
1229
+ reject: false,
1230
+ timeout: timeoutMs > 0 ? timeoutMs : void 0,
1231
+ stripFinalNewline: false,
1232
+ stdin: "ignore",
1233
+ env,
1234
+ ...invocation.workingDirectory ? { cwd: invocation.workingDirectory } : {}
1235
+ });
1236
+ const unregister = registerChild({
1237
+ kill: (signal) => subprocess.kill(signal),
1238
+ done: subprocess.then(
1239
+ () => void 0,
1240
+ () => void 0
1241
+ )
1242
+ });
1243
+ const watchdog = createWatchdog({
1244
+ ...invocation.inactivityTimeoutMs === void 0 ? {} : { inactivityTimeoutMs: invocation.inactivityTimeoutMs },
1245
+ child: {
1246
+ kill: (signal) => subprocess.kill(signal),
1247
+ done: subprocess.then(
1248
+ () => void 0,
1249
+ () => void 0
1250
+ )
1251
+ }
1252
+ });
1253
+ cleanup = () => {
1254
+ watchdog.stop();
1255
+ unregister();
1256
+ };
1257
+ const chunks = [];
1258
+ if (subprocess.stdout) {
1259
+ subprocess.stdout.on("data", (chunk) => {
1260
+ watchdog.beat();
1261
+ const text = chunk.toString();
1262
+ chunks.push(text);
1263
+ invocation.onLine?.(text);
1264
+ });
1265
+ }
1266
+ if (subprocess.stderr) {
1267
+ subprocess.stderr.on("data", () => {
1268
+ watchdog.beat();
1269
+ });
1270
+ }
1271
+ const proc = await subprocess;
1272
+ watchdog.stop();
1273
+ unregister();
1274
+ const stdout = chunks.join("") || proc.stdout?.toString() || "";
1275
+ const stderr = proc.stderr?.toString() ?? "";
1276
+ const parsed = parseOpenCodeStream(stdout, invocation.onEvent);
1277
+ const rawOutput = stdout + (stderr ? `
1278
+ ${stderr}` : "");
1279
+ const exitCode = proc.exitCode ?? 1;
1280
+ const elapsedMs = Date.now() - startTime;
1281
+ const timedOut = wasTimedOut(proc, timeoutMs, elapsedMs);
1282
+ const stalled = watchdog.stalled;
1283
+ const authFailed = /not authenticated|unauthorized|no api key|auth required|login required/i.test(
1284
+ `${stderr}
1285
+ ${stdout}`
1286
+ );
1287
+ if (stalled) {
1288
+ return {
1289
+ success: false,
1290
+ result: "",
1291
+ rawOutput: describeStall(watchdog.silentMs, "opencode"),
1292
+ exitCode: 1,
1293
+ usage: parsed.usage,
1294
+ error: describeStall(watchdog.silentMs, "opencode"),
1295
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
1296
+ sessionId: parsed.sessionId ?? void 0,
1297
+ harnessVersion: peekHarnessVersion(this.id)
1298
+ };
1299
+ }
1300
+ if (authFailed) {
1301
+ return {
1302
+ success: false,
1303
+ result: parsed.result,
1304
+ rawOutput,
1305
+ exitCode: timedOut ? 1 : exitCode,
1306
+ usage: parsed.usage,
1307
+ error: stderr.trim() || "OpenCode is not authenticated.",
1308
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
1309
+ sessionId: parsed.sessionId ?? void 0,
1310
+ harnessVersion: peekHarnessVersion(this.id)
1311
+ };
1312
+ }
1313
+ const verdict = opencodeRunVerdict({ exitCode, parsed, timedOut });
1314
+ if (!verdict.success) {
1315
+ return {
1316
+ success: false,
1317
+ result: parsed.result,
1318
+ rawOutput,
1319
+ exitCode: timedOut || exitCode === 0 && verdict.error?.startsWith("configuration:") === true ? 1 : exitCode,
1320
+ usage: parsed.usage,
1321
+ error: timedOut ? describeAgentFailure(proc, stderr || rawOutput, timeoutMs, elapsedMs, command) : verdict.error ?? parsed.error ?? (stderr.trim() || rawOutput),
1322
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
1323
+ sessionId: parsed.sessionId ?? void 0,
1324
+ harnessVersion: peekHarnessVersion(this.id)
1325
+ };
1326
+ }
1327
+ return {
1328
+ success: true,
1329
+ result: parsed.result,
1330
+ rawOutput,
1331
+ exitCode,
1332
+ usage: parsed.usage,
1333
+ error: null,
1334
+ agent: { provider: this.id, model: parsed.model ?? settings.model },
1335
+ sessionId: parsed.sessionId ?? void 0,
1336
+ harnessVersion: peekHarnessVersion(this.id)
1337
+ };
1338
+ } catch (err) {
1339
+ const message = err instanceof Error ? err.message : String(err);
1340
+ const missing = /ENOENT|not found|command not found/i.test(message);
1341
+ return configurationFailure2(
1342
+ agent,
1343
+ missing ? `configuration: opencode is not installed. Install OpenCode CLI: ${OPENCODE_INSTALL_URL}` : message
1344
+ );
1345
+ } finally {
1346
+ cleanup?.();
1347
+ }
1348
+ }
1349
+ };
1350
+
1351
+ // src/agents/registry.ts
1352
+ import { execa as execa6 } from "execa";
1353
+
981
1354
  // src/agents/codex.ts
982
1355
  import { mkdtemp, readFile, rm } from "node:fs/promises";
983
1356
  import { tmpdir } from "node:os";
984
1357
  import { join } from "node:path";
985
- import { execa as execa3 } from "execa";
1358
+ import { execa as execa4 } from "execa";
986
1359
  var BANNED_CODEX_FLAGS = [
987
1360
  "--dangerously-bypass-approvals-and-sandbox",
988
1361
  "--dangerously-bypass-hook-trust"
@@ -1143,7 +1516,7 @@ var CodexRunner = class {
1143
1516
  const startTime = Date.now();
1144
1517
  let cleanup = null;
1145
1518
  try {
1146
- const subprocess = execa3("codex", args, {
1519
+ const subprocess = execa4("codex", args, {
1147
1520
  input: invocation.prompt,
1148
1521
  reject: false,
1149
1522
  timeout: invocation.timeout,
@@ -1266,17 +1639,17 @@ ${stderr}` : "");
1266
1639
  };
1267
1640
 
1268
1641
  // src/agents/cursor.ts
1269
- import { execa as execa4 } from "execa";
1270
- function isRecord2(value) {
1642
+ import { execa as execa5 } from "execa";
1643
+ function isRecord3(value) {
1271
1644
  return typeof value === "object" && value !== null;
1272
1645
  }
1273
1646
  function toolName(call) {
1274
- if (isRecord2(call.readToolCall)) {
1275
- const args = isRecord2(call.readToolCall.args) ? call.readToolCall.args : {};
1647
+ if (isRecord3(call.readToolCall)) {
1648
+ const args = isRecord3(call.readToolCall.args) ? call.readToolCall.args : {};
1276
1649
  return { name: "Read", detail: typeof args.path === "string" ? args.path : "" };
1277
1650
  }
1278
- if (isRecord2(call.writeToolCall)) {
1279
- const args = isRecord2(call.writeToolCall.args) ? call.writeToolCall.args : {};
1651
+ if (isRecord3(call.writeToolCall)) {
1652
+ const args = isRecord3(call.writeToolCall.args) ? call.writeToolCall.args : {};
1280
1653
  return { name: "Edit", detail: typeof args.path === "string" ? args.path : "" };
1281
1654
  }
1282
1655
  const key = Object.keys(call).find((name) => name.endsWith("ToolCall"));
@@ -1290,18 +1663,18 @@ function consumeCursorEvent(event, onEvent) {
1290
1663
  };
1291
1664
  }
1292
1665
  if (event.type === "assistant") {
1293
- const message = isRecord2(event.message) ? event.message : {};
1666
+ const message = isRecord3(event.message) ? event.message : {};
1294
1667
  const content = Array.isArray(message.content) ? message.content : [];
1295
1668
  const texts = [];
1296
1669
  for (const block of content) {
1297
- if (isRecord2(block) && typeof block.text === "string") texts.push(block.text);
1670
+ if (isRecord3(block) && typeof block.text === "string") texts.push(block.text);
1298
1671
  }
1299
1672
  const text = texts.join("");
1300
1673
  if (text && onEvent) onEvent({ kind: "text", text });
1301
1674
  return { text };
1302
1675
  }
1303
1676
  if (event.type === "tool_call" && event.subtype === "started") {
1304
- const call = isRecord2(event.tool_call) ? event.tool_call : {};
1677
+ const call = isRecord3(event.tool_call) ? event.tool_call : {};
1305
1678
  const { name, detail } = toolName(call);
1306
1679
  onEvent?.({ kind: "tool", name, ...detail === "" ? {} : { detail } });
1307
1680
  return {};
@@ -1326,7 +1699,7 @@ function parseCursorStream(raw, onEvent) {
1326
1699
  if (trimmed === "") continue;
1327
1700
  try {
1328
1701
  const event = JSON.parse(trimmed);
1329
- if (!isRecord2(event)) continue;
1702
+ if (!isRecord3(event)) continue;
1330
1703
  const seen = consumeCursorEvent(event, onEvent);
1331
1704
  if (seen.result !== void 0) result = seen.result;
1332
1705
  if (seen.isError === true) isError = true;
@@ -1371,7 +1744,7 @@ var CursorRunner = class {
1371
1744
  const agent = { provider: this.id, model: settings.model };
1372
1745
  let cleanup = null;
1373
1746
  try {
1374
- const subprocess = execa4(command, args, {
1747
+ const subprocess = execa5(command, args, {
1375
1748
  reject: false,
1376
1749
  timeout: invocation.timeout,
1377
1750
  stripFinalNewline: false,
@@ -1489,6 +1862,7 @@ function ensureRunnersRegistered() {
1489
1862
  if (!registered.has("codex")) registerRunner(new CodexRunner());
1490
1863
  if (!registered.has("cursor")) registerRunner(new CursorRunner());
1491
1864
  if (!registered.has("antigravity")) registerRunner(new AntigravityRunner());
1865
+ if (!registered.has("opencode")) registerRunner(new OpenCodeRunner());
1492
1866
  }
1493
1867
  function runnerFor(providerId) {
1494
1868
  ensureRunnersRegistered();
@@ -1506,7 +1880,7 @@ async function ensureHarnessVersion(providerId) {
1506
1880
  const runner = runnerFor(providerId);
1507
1881
  const { command, args } = runner.versionCommand();
1508
1882
  try {
1509
- const proc = await execa5(command, args, { reject: false, timeout: 1e4 });
1883
+ const proc = await execa6(command, args, { reject: false, timeout: 1e4 });
1510
1884
  const version = proc.exitCode === 0 ? proc.stdout?.toString().trim() ?? null : null;
1511
1885
  cacheHarnessVersion(providerId, version);
1512
1886
  return version;
@@ -1516,6 +1890,92 @@ async function ensureHarnessVersion(providerId) {
1516
1890
  }
1517
1891
  }
1518
1892
 
1893
+ // src/routing/opencode-go.ts
1894
+ var OPENCODE_GO_POLICY_VERSION = "1";
1895
+ var OPENCODE_GO_MODELS = {
1896
+ cheap: "opencode-go/mimo-v2.5",
1897
+ default: "opencode-go/qwen3.8-flash",
1898
+ codingCheap: "opencode-go/deepseek-v4-flash",
1899
+ escalate: "opencode-go/gpt-5.6-luna",
1900
+ specialist: "opencode-go/kimi-k2.7-code"
1901
+ };
1902
+ var OPENCODE_GO_LADDER = [
1903
+ OPENCODE_GO_MODELS.cheap,
1904
+ OPENCODE_GO_MODELS.default,
1905
+ OPENCODE_GO_MODELS.escalate,
1906
+ OPENCODE_GO_MODELS.specialist
1907
+ ];
1908
+ var ROLE_BY_MODEL = {
1909
+ [OPENCODE_GO_MODELS.cheap]: "cheap",
1910
+ [OPENCODE_GO_MODELS.default]: "default",
1911
+ [OPENCODE_GO_MODELS.codingCheap]: "coding-cheap",
1912
+ [OPENCODE_GO_MODELS.escalate]: "escalate",
1913
+ [OPENCODE_GO_MODELS.specialist]: "specialist"
1914
+ };
1915
+ function choice(role, reasonCodes) {
1916
+ return {
1917
+ model: OPENCODE_GO_MODELS[role === "coding-cheap" ? "codingCheap" : role],
1918
+ role,
1919
+ reasonCodes
1920
+ };
1921
+ }
1922
+ function phaseDefault(phase) {
1923
+ if (phase === "analyze") return "cheap";
1924
+ if (phase === "pr-review") return "escalate";
1925
+ return "default";
1926
+ }
1927
+ function correctionRole(cycle) {
1928
+ if (cycle <= 1) return "coding-cheap";
1929
+ if (cycle === 2) return "default";
1930
+ if (cycle === 3) return "escalate";
1931
+ return "specialist";
1932
+ }
1933
+ function resolveOpenCodeGoModel(input) {
1934
+ const reasons = ["OPENCODE_GO_POLICY"];
1935
+ if ((input.correctionCycle ?? 0) >= 1 && input.phase === "execute") {
1936
+ const role2 = correctionRole(input.correctionCycle ?? 1);
1937
+ if (role2 === "specialist") reasons.push("OPENCODE_GO_SPECIALIST");
1938
+ else if (role2 === "escalate") reasons.push("OPENCODE_GO_ESCALATE");
1939
+ else if (role2 === "coding-cheap") reasons.push("OPENCODE_GO_CODING_CHEAP");
1940
+ return choice(role2, reasons);
1941
+ }
1942
+ const taskClass = input.taskClass ?? "feature";
1943
+ const risk = input.risk ?? "low";
1944
+ let role = phaseDefault(input.phase);
1945
+ if (input.phase === "analyze" && risk === "high") {
1946
+ role = "default";
1947
+ } else if (input.phase === "generate" && taskClass === "docs") {
1948
+ role = "cheap";
1949
+ reasons.push("OPENCODE_GO_CHEAP");
1950
+ } else if (input.phase === "prd" && (risk === "high" || taskClass === "infra")) {
1951
+ role = "escalate";
1952
+ reasons.push("OPENCODE_GO_ESCALATE");
1953
+ } else if (input.phase === "plan" && risk === "high") {
1954
+ role = "escalate";
1955
+ reasons.push("OPENCODE_GO_ESCALATE");
1956
+ } else if (input.phase === "plan" && input.profile === "economy" && risk === "low") {
1957
+ role = "cheap";
1958
+ reasons.push("OPENCODE_GO_CHEAP");
1959
+ } else if (input.phase === "execute") {
1960
+ if (risk === "high" || taskClass === "infra" || taskClass === "refactor" && risk !== "low") {
1961
+ role = "escalate";
1962
+ reasons.push("OPENCODE_GO_ESCALATE");
1963
+ } else if ((taskClass === "bugfix" || taskClass === "test") && risk === "low") {
1964
+ role = "coding-cheap";
1965
+ reasons.push("OPENCODE_GO_CODING_CHEAP");
1966
+ }
1967
+ } else if (input.phase === "review" && risk === "high") {
1968
+ role = "escalate";
1969
+ reasons.push("OPENCODE_GO_ESCALATE");
1970
+ } else if (input.phase === "pr" && taskClass === "bugfix" && risk === "low") {
1971
+ role = "coding-cheap";
1972
+ reasons.push("OPENCODE_GO_CODING_CHEAP");
1973
+ } else if (input.phase === "pr-review" && risk === "low" && taskClass === "docs") {
1974
+ role = "default";
1975
+ }
1976
+ return choice(role, reasons);
1977
+ }
1978
+
1519
1979
  // src/agents/origins.ts
1520
1980
  var trackedOrigins = null;
1521
1981
  function setTrackedOrigins(origins) {
@@ -1534,7 +1994,8 @@ function mergeAgentBlocks(base, overlay) {
1534
1994
  claude: { ...base.claude, ...dropUndefined(overlay.claude ?? {}) },
1535
1995
  codex: { ...base.codex, ...dropUndefined(overlay.codex ?? {}) },
1536
1996
  cursor: { ...base.cursor, ...dropUndefined(overlay.cursor ?? {}) },
1537
- antigravity: { ...base.antigravity, ...dropUndefined(overlay.antigravity ?? {}) }
1997
+ antigravity: { ...base.antigravity, ...dropUndefined(overlay.antigravity ?? {}) },
1998
+ opencode: { ...base.opencode, ...dropUndefined(overlay.opencode ?? {}) }
1538
1999
  };
1539
2000
  }
1540
2001
  function dropUndefined(value) {
@@ -1545,7 +2006,7 @@ function dropUndefined(value) {
1545
2006
  return result;
1546
2007
  }
1547
2008
  async function resolveAgentFor(phase, options = {}) {
1548
- const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-56B4OHZE.js");
2009
+ const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-6YTWPDBK.js");
1549
2010
  const config = options.config ?? await loadAgentConfig2();
1550
2011
  const cli = options.cli ?? getAgentCliOverrides2();
1551
2012
  const defaultBlock = {
@@ -1554,7 +2015,8 @@ async function resolveAgentFor(phase, options = {}) {
1554
2015
  claude: config.claude,
1555
2016
  codex: config.codex,
1556
2017
  cursor: config.cursor,
1557
- antigravity: config.antigravity
2018
+ antigravity: config.antigravity,
2019
+ opencode: config.opencode
1558
2020
  };
1559
2021
  const phaseBlock = mergeAgentBlocks(config.phases[phase] ?? {}, cli.phases?.[phase]);
1560
2022
  const merged = mergeAgentBlocks(defaultBlock, phaseBlock);
@@ -1571,6 +2033,9 @@ async function resolveAgentFor(phase, options = {}) {
1571
2033
  model = cli.forceModel;
1572
2034
  modelOrigin = "cli";
1573
2035
  }
2036
+ if (provider === "opencode" && model === null) {
2037
+ model = resolveOpenCodeGoModel({ phase }).model;
2038
+ }
1574
2039
  return {
1575
2040
  provider,
1576
2041
  model,
@@ -1578,6 +2043,7 @@ async function resolveAgentFor(phase, options = {}) {
1578
2043
  codex: merged.codex ?? {},
1579
2044
  cursor: merged.cursor ?? {},
1580
2045
  antigravity: merged.antigravity ?? {},
2046
+ opencode: merged.opencode ?? {},
1581
2047
  origin: { provider: providerOrigin, model: modelOrigin }
1582
2048
  };
1583
2049
  }
@@ -1620,7 +2086,7 @@ function parseAgentPhaseFlag(value) {
1620
2086
  const [providerRaw, ...modelParts] = rest.split(":");
1621
2087
  if (!providerRaw || !isAgentProviderId(providerRaw)) {
1622
2088
  throw new Error(
1623
- `Unknown agent provider "${providerRaw ?? ""}". Valid providers: claude, codex, cursor, antigravity.`
2089
+ `Unknown agent provider "${providerRaw ?? ""}". Valid providers: claude, codex, cursor, antigravity, opencode.`
1624
2090
  );
1625
2091
  }
1626
2092
  const model = modelParts.length > 0 ? modelParts.join(":") : void 0;
@@ -1632,6 +2098,14 @@ function parseAgentPhaseFlag(value) {
1632
2098
  }
1633
2099
  };
1634
2100
  }
2101
+ function applyOpenCodeGoModel(settings, input) {
2102
+ if (settings.provider !== "opencode" || settings.origin.model !== "default") {
2103
+ return settings;
2104
+ }
2105
+ const model = resolveOpenCodeGoModel(input).model;
2106
+ if (model === settings.model) return settings;
2107
+ return { ...settings, model };
2108
+ }
1635
2109
  async function describeRunAgents(phases = AGENT_PHASES) {
1636
2110
  const target = phases.length > 0 ? phases : AGENT_PHASES;
1637
2111
  const byPhase = {};
@@ -1651,7 +2125,7 @@ async function describeRunAgents(phases = AGENT_PHASES) {
1651
2125
  defaultModel = settings.model;
1652
2126
  }
1653
2127
  }
1654
- const { loadAgentConfig: loadAgentConfig2 } = await import("./config-56B4OHZE.js");
2128
+ const { loadAgentConfig: loadAgentConfig2 } = await import("./config-6YTWPDBK.js");
1655
2129
  const config = await loadAgentConfig2();
1656
2130
  defaultProvider = config.provider;
1657
2131
  defaultModel = config.model;
@@ -1689,9 +2163,10 @@ var PROVIDER_HARNESS = {
1689
2163
  claude: "claude-code",
1690
2164
  codex: "codex-cli",
1691
2165
  cursor: "cursor-cli",
1692
- antigravity: "antigravity-cli"
2166
+ antigravity: "antigravity-cli",
2167
+ opencode: "opencode-cli"
1693
2168
  };
1694
- var ALL_PROVIDERS = ["claude", "codex", "cursor", "antigravity"];
2169
+ var ALL_PROVIDERS = AGENT_PROVIDER_IDS;
1695
2170
  var probeCache = /* @__PURE__ */ new Map();
1696
2171
  var inventoryCache = null;
1697
2172
  function deriveState(installed2, authentication, cooldownUntil, nowMs) {
@@ -1735,7 +2210,7 @@ async function probeAgentUncached(id, options = {}) {
1735
2210
  let installed2 = false;
1736
2211
  try {
1737
2212
  const { command, args } = runner.versionCommand();
1738
- const proc = await execa6(command, args, { reject: false, timeout: 1e4 });
2213
+ const proc = await execa7(command, args, { reject: false, timeout: 1e4 });
1739
2214
  installed2 = proc.exitCode === 0;
1740
2215
  version = installed2 ? proc.stdout?.toString().trim() || "unknown" : null;
1741
2216
  } catch {
@@ -1750,10 +2225,10 @@ async function probeAgentUncached(id, options = {}) {
1750
2225
  } else if (runner.authCommand && runner.capabilities.authProbe !== "none") {
1751
2226
  try {
1752
2227
  const { command, args } = runner.authCommand();
1753
- const auth = await execa6(command, args, { reject: false, timeout: 1e4 });
2228
+ const auth = await execa7(command, args, { reject: false, timeout: 1e4 });
1754
2229
  const text = `${auth.stdout?.toString() ?? ""}
1755
2230
  ${auth.stderr?.toString() ?? ""}`;
1756
- const ok = runner.capabilities.authProbe === "text" ? !/not logged in|not authenticated|no models available/i.test(text) : auth.exitCode === 0;
2231
+ const ok = runner.capabilities.authProbe === "text" ? id === "opencode" ? interpretOpenCodeAuth(text) : !/not logged in|not authenticated|no models available/i.test(text) : auth.exitCode === 0;
1757
2232
  authentication = ok ? "confirmed" : "failed";
1758
2233
  detail = ok ? `${version} (authenticated)` : `${version} (not authenticated)`;
1759
2234
  } catch {
@@ -1831,6 +2306,9 @@ function installHint(id) {
1831
2306
  if (id === "antigravity") {
1832
2307
  return "Install Antigravity CLI: https://antigravity.google/docs/cli/install/";
1833
2308
  }
2309
+ if (id === "opencode") {
2310
+ return "Install OpenCode CLI: https://opencode.ai/docs";
2311
+ }
1834
2312
  return "Install Claude Code: https://docs.anthropic.com/en/docs/claude-code";
1835
2313
  }
1836
2314
 
@@ -1896,7 +2374,7 @@ function readAgentEnv(env, warn) {
1896
2374
  layer.provider = env.ISSUE_FLOW_AGENT;
1897
2375
  } else {
1898
2376
  warn(
1899
- `Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor or antigravity.`
2377
+ `Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor, antigravity or opencode.`
1900
2378
  );
1901
2379
  }
1902
2380
  }
@@ -1957,6 +2435,14 @@ function readAgentEnv(env, warn) {
1957
2435
  antigravity.executeTimeout = env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT;
1958
2436
  }
1959
2437
  if (Object.keys(antigravity).length > 0) layer.antigravity = antigravity;
2438
+ const opencode = {};
2439
+ if (env.ISSUE_FLOW_OPENCODE_VARIANT !== void 0 && env.ISSUE_FLOW_OPENCODE_VARIANT !== "") {
2440
+ opencode.variant = env.ISSUE_FLOW_OPENCODE_VARIANT;
2441
+ }
2442
+ if (env.ISSUE_FLOW_OPENCODE_MIN_VERSION !== void 0 && env.ISSUE_FLOW_OPENCODE_MIN_VERSION !== "") {
2443
+ opencode.minVersion = env.ISSUE_FLOW_OPENCODE_MIN_VERSION;
2444
+ }
2445
+ if (Object.keys(opencode).length > 0) layer.opencode = opencode;
1960
2446
  return layer;
1961
2447
  }
1962
2448
  function readAgentKey(raw, label, warn) {
@@ -1979,6 +2465,7 @@ function readAgentKey(raw, label, warn) {
1979
2465
  ...parsed.data.codex !== void 0 ? { codex: parsed.data.codex } : {},
1980
2466
  ...parsed.data.cursor !== void 0 ? { cursor: parsed.data.cursor } : {},
1981
2467
  ...parsed.data.antigravity !== void 0 ? { antigravity: parsed.data.antigravity } : {},
2468
+ ...parsed.data.opencode !== void 0 ? { opencode: parsed.data.opencode } : {},
1982
2469
  ...Object.keys(phases).length > 0 ? { phases } : {}
1983
2470
  };
1984
2471
  }
@@ -2001,7 +2488,8 @@ function mergeAgentBlockLayers(layers) {
2001
2488
  claude: { ...merged.claude, ...layer.block.claude },
2002
2489
  codex: { ...merged.codex, ...layer.block.codex },
2003
2490
  cursor: { ...merged.cursor, ...layer.block.cursor },
2004
- antigravity: { ...merged.antigravity, ...layer.block.antigravity }
2491
+ antigravity: { ...merged.antigravity, ...layer.block.antigravity },
2492
+ opencode: { ...merged.opencode, ...layer.block.opencode }
2005
2493
  };
2006
2494
  }
2007
2495
  return any ? merged : void 0;
@@ -2014,6 +2502,7 @@ function dropUndefinedBlock(block) {
2014
2502
  if (block.codex !== void 0) result.codex = block.codex;
2015
2503
  if (block.cursor !== void 0) result.cursor = block.cursor;
2016
2504
  if (block.antigravity !== void 0) result.antigravity = block.antigravity;
2505
+ if (block.opencode !== void 0) result.opencode = block.opencode;
2017
2506
  return result;
2018
2507
  }
2019
2508
  async function loadAgentConfig(options = {}) {
@@ -2057,6 +2546,12 @@ async function loadAgentConfig(options = {}) {
2057
2546
  env: envLayer.antigravity,
2058
2547
  cli: cli.antigravity
2059
2548
  });
2549
+ const opencode = mergeConfigLayers({
2550
+ global: globalLayer.opencode,
2551
+ project: projectLayer.opencode,
2552
+ env: envLayer.opencode,
2553
+ cli: cli.opencode
2554
+ });
2060
2555
  const phases = {};
2061
2556
  const phaseOrigins = {};
2062
2557
  for (const phase of AGENT_PHASES) {
@@ -2101,7 +2596,7 @@ async function loadAgentConfig(options = {}) {
2101
2596
  ]),
2102
2597
  phases: phaseOrigins
2103
2598
  });
2104
- const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
2599
+ const resolved = { provider, model, claude, codex, cursor, antigravity, opencode, phases };
2105
2600
  if (canCache) cachedAgentConfig = resolved;
2106
2601
  return resolved;
2107
2602
  }
@@ -2185,7 +2680,7 @@ async function resolvePaths(config, scriptDir) {
2185
2680
  lastBranchFile: join2(base, ".last-branch"),
2186
2681
  projectRoot
2187
2682
  };
2188
- const { bindTelemetry } = await import("./recorder-T7426CKV.js");
2683
+ const { bindTelemetry } = await import("./recorder-LOU3PTIE.js");
2189
2684
  bindTelemetry({ tasksPath: standalone.prdFile });
2190
2685
  return standalone;
2191
2686
  }
@@ -2743,6 +3238,8 @@ async function loadWebConfig(options = {}) {
2743
3238
  var WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;
2744
3239
 
2745
3240
  export {
3241
+ OPENCODE_GO_POLICY_VERSION,
3242
+ resolveOpenCodeGoModel,
2746
3243
  getShutdownSignal,
2747
3244
  onShutdown,
2748
3245
  installShutdownHandlers,
@@ -2784,7 +3281,8 @@ export {
2784
3281
  WEB_CONFIG_FILENAME,
2785
3282
  resolveAgentFor,
2786
3283
  parseAgentPhaseFlag,
3284
+ applyOpenCodeGoModel,
2787
3285
  describeRunAgents,
2788
3286
  hasExplicitAgentSelection
2789
3287
  };
2790
- //# sourceMappingURL=chunk-UHDXXLYH.js.map
3288
+ //# sourceMappingURL=chunk-YC24E66P.js.map