issue-flow 0.18.0 → 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.
- package/README.md +43 -97
- package/dist/agent-4DHRKZ2Z.js +32 -0
- package/dist/{analyze-Q4ONIWRZ.js → analyze-UEJ2R3H5.js} +42 -41
- package/dist/analyze-UEJ2R3H5.js.map +1 -0
- package/dist/{apply-EEFPY2W4.js → apply-QDYNQMUX.js} +22 -24
- package/dist/apply-QDYNQMUX.js.map +1 -0
- package/dist/artifacts-AMJQJFFV.js +82 -0
- package/dist/artifacts-AMJQJFFV.js.map +1 -0
- package/dist/{bench-WWWXLTFH.js → bench-RNRXVEFK.js} +42 -42
- package/dist/{chunk-RYOUZ6EK.js → chunk-23VHVVKW.js} +3 -3
- package/dist/chunk-2EYLOS5I.js +99 -0
- package/dist/chunk-2EYLOS5I.js.map +1 -0
- package/dist/{chunk-C5TL7T4V.js → chunk-2YM2VH6R.js} +2 -2
- package/dist/{chunk-XUEMATVY.js → chunk-37O2FMAN.js} +28 -25
- package/dist/chunk-37O2FMAN.js.map +1 -0
- package/dist/chunk-44RF3VFG.js +717 -0
- package/dist/chunk-44RF3VFG.js.map +1 -0
- package/dist/chunk-6AOZCWN2.js +21 -0
- package/dist/chunk-6AOZCWN2.js.map +1 -0
- package/dist/chunk-7MJGYPHF.js +1571 -0
- package/dist/chunk-7MJGYPHF.js.map +1 -0
- package/dist/{chunk-SA6HXL4Y.js → chunk-7WBUEBD5.js} +9 -9
- package/dist/chunk-7WBUEBD5.js.map +1 -0
- package/dist/chunk-7ZZUSMBJ.js +35 -0
- package/dist/chunk-7ZZUSMBJ.js.map +1 -0
- package/dist/{chunk-QJ44VG5G.js → chunk-ADH6RJNX.js} +3 -3
- package/dist/{chunk-34OCSKOB.js → chunk-AKL5UPR6.js} +159 -114
- package/dist/chunk-AKL5UPR6.js.map +1 -0
- package/dist/{chunk-7F7LGMVO.js → chunk-BTBJ5UOO.js} +12 -12
- package/dist/{chunk-7F7LGMVO.js.map → chunk-BTBJ5UOO.js.map} +1 -1
- package/dist/{chunk-HOAHMERN.js → chunk-CLZ6RRZL.js} +21 -21
- package/dist/chunk-DBLXLKGU.js +1201 -0
- package/dist/chunk-DBLXLKGU.js.map +1 -0
- package/dist/{chunk-DUS5ZNKL.js → chunk-DIMDAYZS.js} +7 -6
- package/dist/chunk-DZ3DZ3EN.js +278 -0
- package/dist/chunk-DZ3DZ3EN.js.map +1 -0
- package/dist/{chunk-CRGIQFUQ.js → chunk-E2H3JV2E.js} +3 -1
- package/dist/chunk-E2H3JV2E.js.map +1 -0
- package/dist/{chunk-45WZ6GMI.js → chunk-EORDSKWZ.js} +17 -17
- package/dist/chunk-EORDSKWZ.js.map +1 -0
- package/dist/{chunk-LTH6XYZ3.js → chunk-EYKPWHT7.js} +40 -30
- package/dist/chunk-EYKPWHT7.js.map +1 -0
- package/dist/{chunk-OODXFCQV.js → chunk-FU2FQ4JE.js} +14 -16
- package/dist/{chunk-OODXFCQV.js.map → chunk-FU2FQ4JE.js.map} +1 -1
- package/dist/{chunk-V7QOIQYC.js → chunk-G442RDFX.js} +9 -23
- package/dist/{chunk-V7QOIQYC.js.map → chunk-G442RDFX.js.map} +1 -1
- package/dist/{chunk-QPGEFLMY.js → chunk-I64N6RL6.js} +7 -7
- package/dist/{chunk-KRAGAUKD.js → chunk-JBYXJOJJ.js} +201 -64
- package/dist/chunk-JBYXJOJJ.js.map +1 -0
- package/dist/{chunk-SOM4QA6C.js → chunk-JCR5C5A7.js} +93 -18
- package/dist/chunk-JCR5C5A7.js.map +1 -0
- package/dist/{chunk-RNFUVKC3.js → chunk-K5NM26NV.js} +30 -13
- package/dist/chunk-K5NM26NV.js.map +1 -0
- package/dist/{chunk-YVPZUN6X.js → chunk-KUA6KBBD.js} +335 -38
- package/dist/chunk-KUA6KBBD.js.map +1 -0
- package/dist/{chunk-KMCS76ZW.js → chunk-KUL64XUF.js} +44 -12
- package/dist/chunk-KUL64XUF.js.map +1 -0
- package/dist/{chunk-HAKDLR6N.js → chunk-MAJ6QDRL.js} +65 -78
- package/dist/chunk-MAJ6QDRL.js.map +1 -0
- package/dist/{chunk-DGRTJD5R.js → chunk-MML2G7IC.js} +7 -7
- package/dist/chunk-NP47HRX2.js +136 -0
- package/dist/chunk-NP47HRX2.js.map +1 -0
- package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
- package/dist/{chunk-ECU7YO7S.js → chunk-PM5YWJYO.js} +22 -6
- package/dist/chunk-PM5YWJYO.js.map +1 -0
- package/dist/{chunk-E4I6MMHD.js → chunk-PXPTIXJF.js} +154 -101
- package/dist/chunk-PXPTIXJF.js.map +1 -0
- package/dist/{chunk-CWSQVHVV.js → chunk-QJHZ3HYJ.js} +248 -102
- package/dist/chunk-QJHZ3HYJ.js.map +1 -0
- package/dist/{chunk-LI35PIIS.js → chunk-RDPK7LYK.js} +20 -117
- package/dist/chunk-RDPK7LYK.js.map +1 -0
- package/dist/{chunk-PMLE7KAQ.js → chunk-RMIBLFG3.js} +30 -14
- package/dist/chunk-RMIBLFG3.js.map +1 -0
- package/dist/{chunk-62GVVZQO.js → chunk-T736DSZI.js} +32 -316
- package/dist/chunk-T736DSZI.js.map +1 -0
- package/dist/{chunk-TZYINKCC.js → chunk-UDUUUFQF.js} +57 -29
- package/dist/chunk-UDUUUFQF.js.map +1 -0
- package/dist/{chunk-NEWNXZ65.js → chunk-V7GETODQ.js} +36 -28
- package/dist/{chunk-NEWNXZ65.js.map → chunk-V7GETODQ.js.map} +1 -1
- package/dist/{chunk-PPZ3K4YM.js → chunk-VHQMMY2D.js} +2 -2
- package/dist/{chunk-ZVZMWNCG.js → chunk-VJ3PF6B7.js} +50 -16
- package/dist/chunk-VJ3PF6B7.js.map +1 -0
- package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
- package/dist/{chunk-6K2LCFG6.js → chunk-WB4FA2EH.js} +70 -81
- package/dist/chunk-WB4FA2EH.js.map +1 -0
- package/dist/{chunk-LGHND47K.js → chunk-WQSGL5LX.js} +22 -16
- package/dist/chunk-WQSGL5LX.js.map +1 -0
- package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
- package/dist/chunk-XNK5UN2D.js.map +1 -0
- package/dist/{chunk-7UMMFOL2.js → chunk-Y2KOWABB.js} +39 -24
- package/dist/chunk-Y2KOWABB.js.map +1 -0
- package/dist/{chunk-QF7VEL3M.js → chunk-YC24E66P.js} +568 -158
- package/dist/chunk-YC24E66P.js.map +1 -0
- package/dist/{chunk-EG2MGDP5.js → chunk-Z6RCKCVB.js} +52 -46
- package/dist/chunk-Z6RCKCVB.js.map +1 -0
- package/dist/{chunk-YUNBOUQH.js → chunk-ZPGNVBWY.js} +8 -8
- package/dist/cli.js +132 -62
- package/dist/cli.js.map +1 -1
- package/dist/compat-OJG76J4I.js +24 -0
- package/dist/{config-LEBZZCJP.js → config-6YTWPDBK.js} +20 -17
- package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
- package/dist/{conventions-XOT6YW5L.js → conventions-5UPOTU42.js} +20 -16
- package/dist/{conventions-XOT6YW5L.js.map → conventions-5UPOTU42.js.map} +1 -1
- package/dist/db-QAZG4LQD.js +264 -0
- package/dist/db-QAZG4LQD.js.map +1 -0
- package/dist/diagnostics-YEFB42E5.js +25 -0
- package/dist/execute-QCT64D37.js +38 -0
- package/dist/{generate-JGW5JSKB.js → generate-QATMDKOK.js} +46 -43
- package/dist/generate-QATMDKOK.js.map +1 -0
- package/dist/{git-A2IP32PQ.js → git-XGOECXWG.js} +2 -3
- package/dist/history-NBPUZVGQ.js +101 -0
- package/dist/history-NBPUZVGQ.js.map +1 -0
- package/dist/init-4LB2YKWP.js +28 -0
- package/dist/{operations-O4FORFIH.js → operations-RUQP2Y2F.js} +78 -52
- package/dist/operations-RUQP2Y2F.js.map +1 -0
- package/dist/{permissions-G4XCAESF.js → permissions-QZPUUBSO.js} +5 -6
- package/dist/plan-2NMSHTMD.js +38 -0
- package/dist/{policy-U5NBFAO5.js → policy-RKKFF5A2.js} +17 -15
- package/dist/{policy-U5NBFAO5.js.map → policy-RKKFF5A2.js.map} +1 -1
- package/dist/pr-QKFO5HI3.js +42 -0
- package/dist/pr-review-H2BFD6F2.js +33 -0
- package/dist/prd-ET6XKYRS.js +37 -0
- package/dist/{ps-76L6ZAZL.js → ps-UIKSOUAQ.js} +26 -15
- package/dist/ps-UIKSOUAQ.js.map +1 -0
- package/dist/{recorder-2BAKPBRA.js → recorder-LOU3PTIE.js} +11 -7
- package/dist/registry-HV7M6MAH.js +17 -0
- package/dist/repository-RCRR6RDE.js +80 -0
- package/dist/resume-BWJZGBLZ.js +278 -0
- package/dist/resume-BWJZGBLZ.js.map +1 -0
- package/dist/review-2MTZLNSS.js +38 -0
- package/dist/routing-RM5ABHHD.js +35 -0
- package/dist/run-XMACQBRJ.js +61 -0
- package/dist/{session-publisher-KAJQRHNZ.js → session-publisher-Q5TNEZPX.js} +3 -3
- package/dist/session-publisher-Q5TNEZPX.js.map +1 -0
- package/dist/{state-manager-UPHO2EA2.js → state-manager-SRN4VJSX.js} +9 -4
- package/dist/state-manager-SRN4VJSX.js.map +1 -0
- package/dist/{usage-KTMYXAPF.js → usage-JOODVE5O.js} +69 -63
- package/dist/usage-JOODVE5O.js.map +1 -0
- package/dist/web-TLMWJ2BM.js +205 -0
- package/dist/web-TLMWJ2BM.js.map +1 -0
- package/package.json +22 -8
- package/prompts/analyze.md +16 -19
- package/prompts/execute.md +73 -144
- package/prompts/generate.md +23 -10
- package/prompts/plan.md +32 -60
- package/prompts/pr-review.md +58 -40
- package/prompts/pr.md +50 -16
- package/prompts/prd.md +26 -19
- package/prompts/review.md +41 -18
- package/web/public/app.js +111 -112
- package/dist/agent-HMZTXCRT.js +0 -30
- package/dist/analyze-Q4ONIWRZ.js.map +0 -1
- package/dist/apply-EEFPY2W4.js.map +0 -1
- package/dist/chunk-34OCSKOB.js.map +0 -1
- package/dist/chunk-45WZ6GMI.js.map +0 -1
- package/dist/chunk-62GVVZQO.js.map +0 -1
- package/dist/chunk-6K2LCFG6.js.map +0 -1
- package/dist/chunk-7UMMFOL2.js.map +0 -1
- package/dist/chunk-CRGIQFUQ.js.map +0 -1
- package/dist/chunk-CWSQVHVV.js.map +0 -1
- package/dist/chunk-E4I6MMHD.js.map +0 -1
- package/dist/chunk-ECU7YO7S.js.map +0 -1
- package/dist/chunk-EG2MGDP5.js.map +0 -1
- package/dist/chunk-HAKDLR6N.js.map +0 -1
- package/dist/chunk-ICM463EO.js.map +0 -1
- package/dist/chunk-KMCS76ZW.js.map +0 -1
- package/dist/chunk-KRAGAUKD.js.map +0 -1
- package/dist/chunk-LGHND47K.js.map +0 -1
- package/dist/chunk-LI35PIIS.js.map +0 -1
- package/dist/chunk-LTH6XYZ3.js.map +0 -1
- package/dist/chunk-PMLE7KAQ.js.map +0 -1
- package/dist/chunk-QF7VEL3M.js.map +0 -1
- package/dist/chunk-RNFUVKC3.js.map +0 -1
- package/dist/chunk-SA6HXL4Y.js.map +0 -1
- package/dist/chunk-SOM4QA6C.js.map +0 -1
- package/dist/chunk-TZYINKCC.js.map +0 -1
- package/dist/chunk-WCCZJL7W.js +0 -141
- package/dist/chunk-WCCZJL7W.js.map +0 -1
- package/dist/chunk-XEYH6ZZI.js +0 -289
- package/dist/chunk-XEYH6ZZI.js.map +0 -1
- package/dist/chunk-XUEMATVY.js.map +0 -1
- package/dist/chunk-XZUEFTUP.js +0 -243
- package/dist/chunk-XZUEFTUP.js.map +0 -1
- package/dist/chunk-YVPZUN6X.js.map +0 -1
- package/dist/chunk-ZVZMWNCG.js.map +0 -1
- package/dist/diagnostics-HTCWF7F4.js +0 -23
- package/dist/execute-LELOSR5T.js +0 -37
- package/dist/generate-JGW5JSKB.js.map +0 -1
- package/dist/init-TO6MUXO4.js +0 -26
- package/dist/operations-O4FORFIH.js.map +0 -1
- package/dist/plan-OXAT344Q.js +0 -34
- package/dist/pr-UZHNKKZC.js +0 -39
- package/dist/pr-review-Q4ACAWDM.js +0 -32
- package/dist/prd-6CYEMLDY.js +0 -33
- package/dist/ps-76L6ZAZL.js.map +0 -1
- package/dist/registry-XLHHYLTR.js +0 -15
- package/dist/resume-URCU6CIJ.js +0 -244
- package/dist/resume-URCU6CIJ.js.map +0 -1
- package/dist/review-LVZT2TMW.js +0 -35
- package/dist/routing-EK6RBZM4.js +0 -33
- package/dist/run-2RXJCJKT.js +0 -56
- package/dist/usage-KTMYXAPF.js.map +0 -1
- package/dist/web-B5UPHHR5.js +0 -172
- package/dist/web-B5UPHHR5.js.map +0 -1
- /package/dist/{agent-HMZTXCRT.js.map → agent-4DHRKZ2Z.js.map} +0 -0
- /package/dist/{bench-WWWXLTFH.js.map → bench-RNRXVEFK.js.map} +0 -0
- /package/dist/{chunk-RYOUZ6EK.js.map → chunk-23VHVVKW.js.map} +0 -0
- /package/dist/{chunk-C5TL7T4V.js.map → chunk-2YM2VH6R.js.map} +0 -0
- /package/dist/{chunk-QJ44VG5G.js.map → chunk-ADH6RJNX.js.map} +0 -0
- /package/dist/{chunk-HOAHMERN.js.map → chunk-CLZ6RRZL.js.map} +0 -0
- /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
- /package/dist/{chunk-QPGEFLMY.js.map → chunk-I64N6RL6.js.map} +0 -0
- /package/dist/{chunk-DGRTJD5R.js.map → chunk-MML2G7IC.js.map} +0 -0
- /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
- /package/dist/{chunk-PPZ3K4YM.js.map → chunk-VHQMMY2D.js.map} +0 -0
- /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
- /package/dist/{chunk-YUNBOUQH.js.map → chunk-ZPGNVBWY.js.map} +0 -0
- /package/dist/{config-LEBZZCJP.js.map → compat-OJG76J4I.js.map} +0 -0
- /package/dist/{contract-JH2WBIO6.js.map → config-6YTWPDBK.js.map} +0 -0
- /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
- /package/dist/{execute-LELOSR5T.js.map → diagnostics-YEFB42E5.js.map} +0 -0
- /package/dist/{git-A2IP32PQ.js.map → execute-QCT64D37.js.map} +0 -0
- /package/dist/{init-TO6MUXO4.js.map → git-XGOECXWG.js.map} +0 -0
- /package/dist/{permissions-G4XCAESF.js.map → init-4LB2YKWP.js.map} +0 -0
- /package/dist/{plan-OXAT344Q.js.map → permissions-QZPUUBSO.js.map} +0 -0
- /package/dist/{pr-UZHNKKZC.js.map → plan-2NMSHTMD.js.map} +0 -0
- /package/dist/{pr-review-Q4ACAWDM.js.map → pr-QKFO5HI3.js.map} +0 -0
- /package/dist/{prd-6CYEMLDY.js.map → pr-review-H2BFD6F2.js.map} +0 -0
- /package/dist/{recorder-2BAKPBRA.js.map → prd-ET6XKYRS.js.map} +0 -0
- /package/dist/{registry-XLHHYLTR.js.map → recorder-LOU3PTIE.js.map} +0 -0
- /package/dist/{review-LVZT2TMW.js.map → registry-HV7M6MAH.js.map} +0 -0
- /package/dist/{routing-EK6RBZM4.js.map → repository-RCRR6RDE.js.map} +0 -0
- /package/dist/{run-2RXJCJKT.js.map → review-2MTZLNSS.js.map} +0 -0
- /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-RM5ABHHD.js.map} +0 -0
- /package/dist/{state-manager-UPHO2EA2.js.map → run-XMACQBRJ.js.map} +0 -0
|
@@ -1,146 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
3
|
+
GLOBAL_CONFIG_FILENAME,
|
|
4
|
+
PROJECT_CONFIG_FILENAME,
|
|
6
5
|
formatDuration,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
RETRY_CONFIG_KEYS,
|
|
14
|
-
getProjectRoot,
|
|
15
|
-
run
|
|
16
|
-
} from "./chunk-YVPZUN6X.js";
|
|
6
|
+
loadGlobalConfig,
|
|
7
|
+
printWarning,
|
|
8
|
+
readProjectConfigFile,
|
|
9
|
+
resolveIssuePaths
|
|
10
|
+
} from "./chunk-DBLXLKGU.js";
|
|
17
11
|
import {
|
|
18
12
|
DEFAULT_TELEMETRY_CONFIG
|
|
19
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WB4FA2EH.js";
|
|
20
14
|
import {
|
|
21
15
|
parseCodexUsage,
|
|
22
16
|
parseUsage
|
|
23
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-JCR5C5A7.js";
|
|
24
18
|
import {
|
|
25
19
|
AGENT_PHASES,
|
|
20
|
+
AGENT_PROVIDER_IDS,
|
|
26
21
|
ANTIGRAVITY_CAPABILITIES,
|
|
27
22
|
CLAUDE_CAPABILITIES,
|
|
28
23
|
CODEX_CAPABILITIES,
|
|
29
24
|
CURSOR_CAPABILITIES,
|
|
25
|
+
OPENCODE_CAPABILITIES,
|
|
30
26
|
agentConfigInputSchema,
|
|
31
|
-
globalConfigSchema,
|
|
32
27
|
isAgentPhase,
|
|
33
28
|
isAgentProviderId,
|
|
34
|
-
issuesConfigSchema,
|
|
35
29
|
parsePhasesInput,
|
|
30
|
+
resilienceConfigSchema,
|
|
31
|
+
telemetryConfigInputSchema
|
|
32
|
+
} from "./chunk-44RF3VFG.js";
|
|
33
|
+
import {
|
|
34
|
+
issuesConfigSchema,
|
|
36
35
|
policyConfigInputSchema,
|
|
37
36
|
policyConfigSchema,
|
|
38
37
|
prReviewConfigSchema,
|
|
39
|
-
resilienceConfigSchema,
|
|
40
38
|
routingConfigInputSchema,
|
|
41
39
|
routingConfigSchema,
|
|
42
|
-
telemetryConfigInputSchema,
|
|
43
40
|
verifyConfigSchema,
|
|
44
41
|
webConfigSchema
|
|
45
|
-
} from "./chunk-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
var PROJECT_CONFIG_FILENAME = ".issue-flow.json";
|
|
52
|
-
function findProjectRootFromCwd(start = process.cwd()) {
|
|
53
|
-
let dir = start;
|
|
54
|
-
while (true) {
|
|
55
|
-
if (existsSync(join(dir, PROJECT_CONFIG_FILENAME)) || existsSync(join(dir, ".git"))) {
|
|
56
|
-
return dir;
|
|
57
|
-
}
|
|
58
|
-
const parent = dirname(dir);
|
|
59
|
-
if (parent === dir) return void 0;
|
|
60
|
-
dir = parent;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
async function readProjectConfigFile(projectRoot, warn) {
|
|
64
|
-
const root = projectRoot ?? findProjectRootFromCwd();
|
|
65
|
-
if (root === void 0) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
const filePath = join(root, PROJECT_CONFIG_FILENAME);
|
|
69
|
-
let raw;
|
|
70
|
-
try {
|
|
71
|
-
raw = await readFile(filePath, "utf-8");
|
|
72
|
-
} catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
let parsed;
|
|
76
|
-
try {
|
|
77
|
-
parsed = JSON.parse(raw);
|
|
78
|
-
} catch {
|
|
79
|
-
warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: invalid JSON.`);
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
83
|
-
warn(`Ignoring ${PROJECT_CONFIG_FILENAME}: expected a JSON object.`);
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
return parsed;
|
|
87
|
-
}
|
|
88
|
-
var GLOBAL_CONFIG_FILENAME = "config.json";
|
|
89
|
-
async function loadGlobalConfig(options = {}) {
|
|
90
|
-
const warn = options.warn ?? printWarning;
|
|
91
|
-
let root;
|
|
92
|
-
try {
|
|
93
|
-
root = options.globalRoot ?? getGlobalRoot({ env: options.env ?? process.env });
|
|
94
|
-
} catch (err) {
|
|
95
|
-
warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
|
|
96
|
-
return {};
|
|
97
|
-
}
|
|
98
|
-
const filePath = join(root, GLOBAL_CONFIG_FILENAME);
|
|
99
|
-
let raw;
|
|
100
|
-
try {
|
|
101
|
-
raw = await readFile(filePath, "utf-8");
|
|
102
|
-
} catch (err) {
|
|
103
|
-
if (err.code !== "ENOENT") {
|
|
104
|
-
warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: ${err.message}`);
|
|
105
|
-
}
|
|
106
|
-
return {};
|
|
107
|
-
}
|
|
108
|
-
let parsed;
|
|
109
|
-
try {
|
|
110
|
-
parsed = JSON.parse(raw);
|
|
111
|
-
} catch {
|
|
112
|
-
warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: invalid JSON.`);
|
|
113
|
-
return {};
|
|
114
|
-
}
|
|
115
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
116
|
-
warn(`Ignoring ${GLOBAL_CONFIG_FILENAME}: expected a JSON object.`);
|
|
117
|
-
return {};
|
|
118
|
-
}
|
|
119
|
-
const config = {};
|
|
120
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
121
|
-
const result = globalConfigSchema.safeParse({ [key]: value });
|
|
122
|
-
if (!result.success) {
|
|
123
|
-
warn(
|
|
124
|
-
`Ignoring "${key}" key of ${GLOBAL_CONFIG_FILENAME}: ${result.error.issues[0]?.message ?? "invalid value"}.`
|
|
125
|
-
);
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
Object.assign(config, result.data);
|
|
129
|
-
}
|
|
130
|
-
return config;
|
|
131
|
-
}
|
|
42
|
+
} from "./chunk-XNK5UN2D.js";
|
|
43
|
+
import {
|
|
44
|
+
RETRY_CONFIG_KEYS,
|
|
45
|
+
getProjectRoot,
|
|
46
|
+
run
|
|
47
|
+
} from "./chunk-KUA6KBBD.js";
|
|
132
48
|
|
|
133
49
|
// src/config/dependencies.ts
|
|
134
|
-
import { platform } from "os";
|
|
50
|
+
import { platform } from "node:os";
|
|
135
51
|
|
|
136
52
|
// src/agents/availability.ts
|
|
137
|
-
import { execa as
|
|
138
|
-
|
|
139
|
-
// src/agents/registry.ts
|
|
140
|
-
import { execa as execa5 } from "execa";
|
|
53
|
+
import { execa as execa7 } from "execa";
|
|
141
54
|
|
|
142
|
-
// src/agents/
|
|
143
|
-
import { execa as
|
|
55
|
+
// src/agents/opencode.ts
|
|
56
|
+
import { execa as execa3 } from "execa";
|
|
144
57
|
|
|
145
58
|
// src/core/shutdown.ts
|
|
146
59
|
var SHUTDOWN_GRACE_MS = 15e3;
|
|
@@ -336,11 +249,14 @@ function describeStall(silentMs, provider = "claude") {
|
|
|
336
249
|
return `${provider} produced no output for ${Math.round(silentMs / 1e3)}s and was stopped (stalled)`;
|
|
337
250
|
}
|
|
338
251
|
|
|
252
|
+
// src/agents/antigravity.ts
|
|
253
|
+
import { execa as execa2 } from "execa";
|
|
254
|
+
|
|
339
255
|
// src/agents/claude.ts
|
|
340
256
|
import { execa } from "execa";
|
|
341
257
|
|
|
342
258
|
// src/core/stream.ts
|
|
343
|
-
import { createInterface } from "readline";
|
|
259
|
+
import { createInterface } from "node:readline";
|
|
344
260
|
async function readClaudeStream(stdout, options = {}) {
|
|
345
261
|
const outcome = { result: "", isError: false, usage: null, events: 0, raw: "" };
|
|
346
262
|
const collected = [];
|
|
@@ -1064,11 +980,382 @@ ${stdout}`
|
|
|
1064
980
|
}
|
|
1065
981
|
};
|
|
1066
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
|
+
|
|
1067
1354
|
// src/agents/codex.ts
|
|
1068
|
-
import { mkdtemp, readFile
|
|
1069
|
-
import { tmpdir } from "os";
|
|
1070
|
-
import { join
|
|
1071
|
-
import { execa as
|
|
1355
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
1356
|
+
import { tmpdir } from "node:os";
|
|
1357
|
+
import { join } from "node:path";
|
|
1358
|
+
import { execa as execa4 } from "execa";
|
|
1072
1359
|
var BANNED_CODEX_FLAGS = [
|
|
1073
1360
|
"--dangerously-bypass-approvals-and-sandbox",
|
|
1074
1361
|
"--dangerously-bypass-hook-trust"
|
|
@@ -1221,15 +1508,15 @@ var CodexRunner = class {
|
|
|
1221
1508
|
return { command: "codex", args: ["login", "status"] };
|
|
1222
1509
|
}
|
|
1223
1510
|
async run(invocation, settings) {
|
|
1224
|
-
const tmp = await mkdtemp(
|
|
1225
|
-
const outputFile =
|
|
1511
|
+
const tmp = await mkdtemp(join(tmpdir(), "issue-flow-codex-"));
|
|
1512
|
+
const outputFile = join(tmp, "last-message.txt");
|
|
1226
1513
|
const args = buildCodexArgv(invocation, settings, outputFile);
|
|
1227
1514
|
const agent = { provider: this.id, model: settings.model };
|
|
1228
1515
|
const base = { agent, harnessVersion: peekHarnessVersion(this.id) };
|
|
1229
1516
|
const startTime = Date.now();
|
|
1230
1517
|
let cleanup = null;
|
|
1231
1518
|
try {
|
|
1232
|
-
const subprocess =
|
|
1519
|
+
const subprocess = execa4("codex", args, {
|
|
1233
1520
|
input: invocation.prompt,
|
|
1234
1521
|
reject: false,
|
|
1235
1522
|
timeout: invocation.timeout,
|
|
@@ -1259,7 +1546,7 @@ var CodexRunner = class {
|
|
|
1259
1546
|
};
|
|
1260
1547
|
const collected = [];
|
|
1261
1548
|
if (subprocess.stdout) {
|
|
1262
|
-
const { createInterface: createInterface2 } = await import("readline");
|
|
1549
|
+
const { createInterface: createInterface2 } = await import("node:readline");
|
|
1263
1550
|
const lines = createInterface2({ input: subprocess.stdout });
|
|
1264
1551
|
for await (const line of lines) {
|
|
1265
1552
|
watchdog.beat();
|
|
@@ -1279,7 +1566,7 @@ ${stderr}` : "");
|
|
|
1279
1566
|
const parsed = parseCodexStream(collected, invocation.onEvent);
|
|
1280
1567
|
let lastMessage = "";
|
|
1281
1568
|
try {
|
|
1282
|
-
lastMessage = (await
|
|
1569
|
+
lastMessage = (await readFile(outputFile, "utf-8")).trimEnd();
|
|
1283
1570
|
} catch {
|
|
1284
1571
|
lastMessage = "";
|
|
1285
1572
|
}
|
|
@@ -1352,17 +1639,17 @@ ${stderr}` : "");
|
|
|
1352
1639
|
};
|
|
1353
1640
|
|
|
1354
1641
|
// src/agents/cursor.ts
|
|
1355
|
-
import { execa as
|
|
1356
|
-
function
|
|
1642
|
+
import { execa as execa5 } from "execa";
|
|
1643
|
+
function isRecord3(value) {
|
|
1357
1644
|
return typeof value === "object" && value !== null;
|
|
1358
1645
|
}
|
|
1359
1646
|
function toolName(call) {
|
|
1360
|
-
if (
|
|
1361
|
-
const args =
|
|
1647
|
+
if (isRecord3(call.readToolCall)) {
|
|
1648
|
+
const args = isRecord3(call.readToolCall.args) ? call.readToolCall.args : {};
|
|
1362
1649
|
return { name: "Read", detail: typeof args.path === "string" ? args.path : "" };
|
|
1363
1650
|
}
|
|
1364
|
-
if (
|
|
1365
|
-
const args =
|
|
1651
|
+
if (isRecord3(call.writeToolCall)) {
|
|
1652
|
+
const args = isRecord3(call.writeToolCall.args) ? call.writeToolCall.args : {};
|
|
1366
1653
|
return { name: "Edit", detail: typeof args.path === "string" ? args.path : "" };
|
|
1367
1654
|
}
|
|
1368
1655
|
const key = Object.keys(call).find((name) => name.endsWith("ToolCall"));
|
|
@@ -1376,18 +1663,18 @@ function consumeCursorEvent(event, onEvent) {
|
|
|
1376
1663
|
};
|
|
1377
1664
|
}
|
|
1378
1665
|
if (event.type === "assistant") {
|
|
1379
|
-
const message =
|
|
1666
|
+
const message = isRecord3(event.message) ? event.message : {};
|
|
1380
1667
|
const content = Array.isArray(message.content) ? message.content : [];
|
|
1381
1668
|
const texts = [];
|
|
1382
1669
|
for (const block of content) {
|
|
1383
|
-
if (
|
|
1670
|
+
if (isRecord3(block) && typeof block.text === "string") texts.push(block.text);
|
|
1384
1671
|
}
|
|
1385
1672
|
const text = texts.join("");
|
|
1386
1673
|
if (text && onEvent) onEvent({ kind: "text", text });
|
|
1387
1674
|
return { text };
|
|
1388
1675
|
}
|
|
1389
1676
|
if (event.type === "tool_call" && event.subtype === "started") {
|
|
1390
|
-
const call =
|
|
1677
|
+
const call = isRecord3(event.tool_call) ? event.tool_call : {};
|
|
1391
1678
|
const { name, detail } = toolName(call);
|
|
1392
1679
|
onEvent?.({ kind: "tool", name, ...detail === "" ? {} : { detail } });
|
|
1393
1680
|
return {};
|
|
@@ -1412,7 +1699,7 @@ function parseCursorStream(raw, onEvent) {
|
|
|
1412
1699
|
if (trimmed === "") continue;
|
|
1413
1700
|
try {
|
|
1414
1701
|
const event = JSON.parse(trimmed);
|
|
1415
|
-
if (!
|
|
1702
|
+
if (!isRecord3(event)) continue;
|
|
1416
1703
|
const seen = consumeCursorEvent(event, onEvent);
|
|
1417
1704
|
if (seen.result !== void 0) result = seen.result;
|
|
1418
1705
|
if (seen.isError === true) isError = true;
|
|
@@ -1457,7 +1744,7 @@ var CursorRunner = class {
|
|
|
1457
1744
|
const agent = { provider: this.id, model: settings.model };
|
|
1458
1745
|
let cleanup = null;
|
|
1459
1746
|
try {
|
|
1460
|
-
const subprocess =
|
|
1747
|
+
const subprocess = execa5(command, args, {
|
|
1461
1748
|
reject: false,
|
|
1462
1749
|
timeout: invocation.timeout,
|
|
1463
1750
|
stripFinalNewline: false,
|
|
@@ -1575,6 +1862,7 @@ function ensureRunnersRegistered() {
|
|
|
1575
1862
|
if (!registered.has("codex")) registerRunner(new CodexRunner());
|
|
1576
1863
|
if (!registered.has("cursor")) registerRunner(new CursorRunner());
|
|
1577
1864
|
if (!registered.has("antigravity")) registerRunner(new AntigravityRunner());
|
|
1865
|
+
if (!registered.has("opencode")) registerRunner(new OpenCodeRunner());
|
|
1578
1866
|
}
|
|
1579
1867
|
function runnerFor(providerId) {
|
|
1580
1868
|
ensureRunnersRegistered();
|
|
@@ -1592,7 +1880,7 @@ async function ensureHarnessVersion(providerId) {
|
|
|
1592
1880
|
const runner = runnerFor(providerId);
|
|
1593
1881
|
const { command, args } = runner.versionCommand();
|
|
1594
1882
|
try {
|
|
1595
|
-
const proc = await
|
|
1883
|
+
const proc = await execa6(command, args, { reject: false, timeout: 1e4 });
|
|
1596
1884
|
const version = proc.exitCode === 0 ? proc.stdout?.toString().trim() ?? null : null;
|
|
1597
1885
|
cacheHarnessVersion(providerId, version);
|
|
1598
1886
|
return version;
|
|
@@ -1602,6 +1890,92 @@ async function ensureHarnessVersion(providerId) {
|
|
|
1602
1890
|
}
|
|
1603
1891
|
}
|
|
1604
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
|
+
|
|
1605
1979
|
// src/agents/origins.ts
|
|
1606
1980
|
var trackedOrigins = null;
|
|
1607
1981
|
function setTrackedOrigins(origins) {
|
|
@@ -1620,7 +1994,8 @@ function mergeAgentBlocks(base, overlay) {
|
|
|
1620
1994
|
claude: { ...base.claude, ...dropUndefined(overlay.claude ?? {}) },
|
|
1621
1995
|
codex: { ...base.codex, ...dropUndefined(overlay.codex ?? {}) },
|
|
1622
1996
|
cursor: { ...base.cursor, ...dropUndefined(overlay.cursor ?? {}) },
|
|
1623
|
-
antigravity: { ...base.antigravity, ...dropUndefined(overlay.antigravity ?? {}) }
|
|
1997
|
+
antigravity: { ...base.antigravity, ...dropUndefined(overlay.antigravity ?? {}) },
|
|
1998
|
+
opencode: { ...base.opencode, ...dropUndefined(overlay.opencode ?? {}) }
|
|
1624
1999
|
};
|
|
1625
2000
|
}
|
|
1626
2001
|
function dropUndefined(value) {
|
|
@@ -1631,7 +2006,7 @@ function dropUndefined(value) {
|
|
|
1631
2006
|
return result;
|
|
1632
2007
|
}
|
|
1633
2008
|
async function resolveAgentFor(phase, options = {}) {
|
|
1634
|
-
const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-
|
|
2009
|
+
const { getAgentCliOverrides: getAgentCliOverrides2, loadAgentConfig: loadAgentConfig2 } = await import("./config-6YTWPDBK.js");
|
|
1635
2010
|
const config = options.config ?? await loadAgentConfig2();
|
|
1636
2011
|
const cli = options.cli ?? getAgentCliOverrides2();
|
|
1637
2012
|
const defaultBlock = {
|
|
@@ -1640,7 +2015,8 @@ async function resolveAgentFor(phase, options = {}) {
|
|
|
1640
2015
|
claude: config.claude,
|
|
1641
2016
|
codex: config.codex,
|
|
1642
2017
|
cursor: config.cursor,
|
|
1643
|
-
antigravity: config.antigravity
|
|
2018
|
+
antigravity: config.antigravity,
|
|
2019
|
+
opencode: config.opencode
|
|
1644
2020
|
};
|
|
1645
2021
|
const phaseBlock = mergeAgentBlocks(config.phases[phase] ?? {}, cli.phases?.[phase]);
|
|
1646
2022
|
const merged = mergeAgentBlocks(defaultBlock, phaseBlock);
|
|
@@ -1657,6 +2033,9 @@ async function resolveAgentFor(phase, options = {}) {
|
|
|
1657
2033
|
model = cli.forceModel;
|
|
1658
2034
|
modelOrigin = "cli";
|
|
1659
2035
|
}
|
|
2036
|
+
if (provider === "opencode" && model === null) {
|
|
2037
|
+
model = resolveOpenCodeGoModel({ phase }).model;
|
|
2038
|
+
}
|
|
1660
2039
|
return {
|
|
1661
2040
|
provider,
|
|
1662
2041
|
model,
|
|
@@ -1664,6 +2043,7 @@ async function resolveAgentFor(phase, options = {}) {
|
|
|
1664
2043
|
codex: merged.codex ?? {},
|
|
1665
2044
|
cursor: merged.cursor ?? {},
|
|
1666
2045
|
antigravity: merged.antigravity ?? {},
|
|
2046
|
+
opencode: merged.opencode ?? {},
|
|
1667
2047
|
origin: { provider: providerOrigin, model: modelOrigin }
|
|
1668
2048
|
};
|
|
1669
2049
|
}
|
|
@@ -1706,7 +2086,7 @@ function parseAgentPhaseFlag(value) {
|
|
|
1706
2086
|
const [providerRaw, ...modelParts] = rest.split(":");
|
|
1707
2087
|
if (!providerRaw || !isAgentProviderId(providerRaw)) {
|
|
1708
2088
|
throw new Error(
|
|
1709
|
-
`Unknown agent provider "${providerRaw ?? ""}". Valid providers: claude, codex, cursor, antigravity.`
|
|
2089
|
+
`Unknown agent provider "${providerRaw ?? ""}". Valid providers: claude, codex, cursor, antigravity, opencode.`
|
|
1710
2090
|
);
|
|
1711
2091
|
}
|
|
1712
2092
|
const model = modelParts.length > 0 ? modelParts.join(":") : void 0;
|
|
@@ -1718,6 +2098,14 @@ function parseAgentPhaseFlag(value) {
|
|
|
1718
2098
|
}
|
|
1719
2099
|
};
|
|
1720
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
|
+
}
|
|
1721
2109
|
async function describeRunAgents(phases = AGENT_PHASES) {
|
|
1722
2110
|
const target = phases.length > 0 ? phases : AGENT_PHASES;
|
|
1723
2111
|
const byPhase = {};
|
|
@@ -1737,7 +2125,7 @@ async function describeRunAgents(phases = AGENT_PHASES) {
|
|
|
1737
2125
|
defaultModel = settings.model;
|
|
1738
2126
|
}
|
|
1739
2127
|
}
|
|
1740
|
-
const { loadAgentConfig: loadAgentConfig2 } = await import("./config-
|
|
2128
|
+
const { loadAgentConfig: loadAgentConfig2 } = await import("./config-6YTWPDBK.js");
|
|
1741
2129
|
const config = await loadAgentConfig2();
|
|
1742
2130
|
defaultProvider = config.provider;
|
|
1743
2131
|
defaultModel = config.model;
|
|
@@ -1775,9 +2163,10 @@ var PROVIDER_HARNESS = {
|
|
|
1775
2163
|
claude: "claude-code",
|
|
1776
2164
|
codex: "codex-cli",
|
|
1777
2165
|
cursor: "cursor-cli",
|
|
1778
|
-
antigravity: "antigravity-cli"
|
|
2166
|
+
antigravity: "antigravity-cli",
|
|
2167
|
+
opencode: "opencode-cli"
|
|
1779
2168
|
};
|
|
1780
|
-
var ALL_PROVIDERS =
|
|
2169
|
+
var ALL_PROVIDERS = AGENT_PROVIDER_IDS;
|
|
1781
2170
|
var probeCache = /* @__PURE__ */ new Map();
|
|
1782
2171
|
var inventoryCache = null;
|
|
1783
2172
|
function deriveState(installed2, authentication, cooldownUntil, nowMs) {
|
|
@@ -1821,7 +2210,7 @@ async function probeAgentUncached(id, options = {}) {
|
|
|
1821
2210
|
let installed2 = false;
|
|
1822
2211
|
try {
|
|
1823
2212
|
const { command, args } = runner.versionCommand();
|
|
1824
|
-
const proc = await
|
|
2213
|
+
const proc = await execa7(command, args, { reject: false, timeout: 1e4 });
|
|
1825
2214
|
installed2 = proc.exitCode === 0;
|
|
1826
2215
|
version = installed2 ? proc.stdout?.toString().trim() || "unknown" : null;
|
|
1827
2216
|
} catch {
|
|
@@ -1836,10 +2225,10 @@ async function probeAgentUncached(id, options = {}) {
|
|
|
1836
2225
|
} else if (runner.authCommand && runner.capabilities.authProbe !== "none") {
|
|
1837
2226
|
try {
|
|
1838
2227
|
const { command, args } = runner.authCommand();
|
|
1839
|
-
const auth = await
|
|
2228
|
+
const auth = await execa7(command, args, { reject: false, timeout: 1e4 });
|
|
1840
2229
|
const text = `${auth.stdout?.toString() ?? ""}
|
|
1841
2230
|
${auth.stderr?.toString() ?? ""}`;
|
|
1842
|
-
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;
|
|
1843
2232
|
authentication = ok ? "confirmed" : "failed";
|
|
1844
2233
|
detail = ok ? `${version} (authenticated)` : `${version} (not authenticated)`;
|
|
1845
2234
|
} catch {
|
|
@@ -1917,6 +2306,9 @@ function installHint(id) {
|
|
|
1917
2306
|
if (id === "antigravity") {
|
|
1918
2307
|
return "Install Antigravity CLI: https://antigravity.google/docs/cli/install/";
|
|
1919
2308
|
}
|
|
2309
|
+
if (id === "opencode") {
|
|
2310
|
+
return "Install OpenCode CLI: https://opencode.ai/docs";
|
|
2311
|
+
}
|
|
1920
2312
|
return "Install Claude Code: https://docs.anthropic.com/en/docs/claude-code";
|
|
1921
2313
|
}
|
|
1922
2314
|
|
|
@@ -1982,7 +2374,7 @@ function readAgentEnv(env, warn) {
|
|
|
1982
2374
|
layer.provider = env.ISSUE_FLOW_AGENT;
|
|
1983
2375
|
} else {
|
|
1984
2376
|
warn(
|
|
1985
|
-
`Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor or
|
|
2377
|
+
`Ignoring ISSUE_FLOW_AGENT="${env.ISSUE_FLOW_AGENT}": expected claude, codex, cursor, antigravity or opencode.`
|
|
1986
2378
|
);
|
|
1987
2379
|
}
|
|
1988
2380
|
}
|
|
@@ -2043,6 +2435,14 @@ function readAgentEnv(env, warn) {
|
|
|
2043
2435
|
antigravity.executeTimeout = env.ISSUE_FLOW_ANTIGRAVITY_EXECUTE_TIMEOUT;
|
|
2044
2436
|
}
|
|
2045
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;
|
|
2046
2446
|
return layer;
|
|
2047
2447
|
}
|
|
2048
2448
|
function readAgentKey(raw, label, warn) {
|
|
@@ -2065,6 +2465,7 @@ function readAgentKey(raw, label, warn) {
|
|
|
2065
2465
|
...parsed.data.codex !== void 0 ? { codex: parsed.data.codex } : {},
|
|
2066
2466
|
...parsed.data.cursor !== void 0 ? { cursor: parsed.data.cursor } : {},
|
|
2067
2467
|
...parsed.data.antigravity !== void 0 ? { antigravity: parsed.data.antigravity } : {},
|
|
2468
|
+
...parsed.data.opencode !== void 0 ? { opencode: parsed.data.opencode } : {},
|
|
2068
2469
|
...Object.keys(phases).length > 0 ? { phases } : {}
|
|
2069
2470
|
};
|
|
2070
2471
|
}
|
|
@@ -2087,7 +2488,8 @@ function mergeAgentBlockLayers(layers) {
|
|
|
2087
2488
|
claude: { ...merged.claude, ...layer.block.claude },
|
|
2088
2489
|
codex: { ...merged.codex, ...layer.block.codex },
|
|
2089
2490
|
cursor: { ...merged.cursor, ...layer.block.cursor },
|
|
2090
|
-
antigravity: { ...merged.antigravity, ...layer.block.antigravity }
|
|
2491
|
+
antigravity: { ...merged.antigravity, ...layer.block.antigravity },
|
|
2492
|
+
opencode: { ...merged.opencode, ...layer.block.opencode }
|
|
2091
2493
|
};
|
|
2092
2494
|
}
|
|
2093
2495
|
return any ? merged : void 0;
|
|
@@ -2100,6 +2502,7 @@ function dropUndefinedBlock(block) {
|
|
|
2100
2502
|
if (block.codex !== void 0) result.codex = block.codex;
|
|
2101
2503
|
if (block.cursor !== void 0) result.cursor = block.cursor;
|
|
2102
2504
|
if (block.antigravity !== void 0) result.antigravity = block.antigravity;
|
|
2505
|
+
if (block.opencode !== void 0) result.opencode = block.opencode;
|
|
2103
2506
|
return result;
|
|
2104
2507
|
}
|
|
2105
2508
|
async function loadAgentConfig(options = {}) {
|
|
@@ -2143,6 +2546,12 @@ async function loadAgentConfig(options = {}) {
|
|
|
2143
2546
|
env: envLayer.antigravity,
|
|
2144
2547
|
cli: cli.antigravity
|
|
2145
2548
|
});
|
|
2549
|
+
const opencode = mergeConfigLayers({
|
|
2550
|
+
global: globalLayer.opencode,
|
|
2551
|
+
project: projectLayer.opencode,
|
|
2552
|
+
env: envLayer.opencode,
|
|
2553
|
+
cli: cli.opencode
|
|
2554
|
+
});
|
|
2146
2555
|
const phases = {};
|
|
2147
2556
|
const phaseOrigins = {};
|
|
2148
2557
|
for (const phase of AGENT_PHASES) {
|
|
@@ -2187,7 +2596,7 @@ async function loadAgentConfig(options = {}) {
|
|
|
2187
2596
|
]),
|
|
2188
2597
|
phases: phaseOrigins
|
|
2189
2598
|
});
|
|
2190
|
-
const resolved = { provider, model, claude, codex, cursor, antigravity, phases };
|
|
2599
|
+
const resolved = { provider, model, claude, codex, cursor, antigravity, opencode, phases };
|
|
2191
2600
|
if (canCache) cachedAgentConfig = resolved;
|
|
2192
2601
|
return resolved;
|
|
2193
2602
|
}
|
|
@@ -2229,7 +2638,7 @@ async function validateDependencies() {
|
|
|
2229
2638
|
}
|
|
2230
2639
|
|
|
2231
2640
|
// src/config/engine.ts
|
|
2232
|
-
import { join as
|
|
2641
|
+
import { join as join2 } from "node:path";
|
|
2233
2642
|
var DEFAULTS = {
|
|
2234
2643
|
retryLimit: 10,
|
|
2235
2644
|
retryForever: false,
|
|
@@ -2239,6 +2648,7 @@ var DEFAULTS = {
|
|
|
2239
2648
|
function createConfig(options) {
|
|
2240
2649
|
return {
|
|
2241
2650
|
issueNumber: options.issueNumber,
|
|
2651
|
+
inPipeline: options.inPipeline,
|
|
2242
2652
|
maxIterations: options.maxIterations,
|
|
2243
2653
|
retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,
|
|
2244
2654
|
retryForever: options.retryForever ?? DEFAULTS.retryForever,
|
|
@@ -2264,13 +2674,13 @@ async function resolvePaths(config, scriptDir) {
|
|
|
2264
2674
|
}
|
|
2265
2675
|
const base = scriptDir ?? projectRoot;
|
|
2266
2676
|
const standalone = {
|
|
2267
|
-
prdFile:
|
|
2268
|
-
progressFile:
|
|
2269
|
-
archiveDir:
|
|
2270
|
-
lastBranchFile:
|
|
2677
|
+
prdFile: join2(base, "prd.json"),
|
|
2678
|
+
progressFile: join2(base, "progress.txt"),
|
|
2679
|
+
archiveDir: join2(base, "archive"),
|
|
2680
|
+
lastBranchFile: join2(base, ".last-branch"),
|
|
2271
2681
|
projectRoot
|
|
2272
2682
|
};
|
|
2273
|
-
const { bindTelemetry } = await import("./recorder-
|
|
2683
|
+
const { bindTelemetry } = await import("./recorder-LOU3PTIE.js");
|
|
2274
2684
|
bindTelemetry({ tasksPath: standalone.prdFile });
|
|
2275
2685
|
return standalone;
|
|
2276
2686
|
}
|
|
@@ -2828,9 +3238,8 @@ async function loadWebConfig(options = {}) {
|
|
|
2828
3238
|
var WEB_CONFIG_FILENAME = PROJECT_CONFIG_FILENAME;
|
|
2829
3239
|
|
|
2830
3240
|
export {
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
loadGlobalConfig,
|
|
3241
|
+
OPENCODE_GO_POLICY_VERSION,
|
|
3242
|
+
resolveOpenCodeGoModel,
|
|
2834
3243
|
getShutdownSignal,
|
|
2835
3244
|
onShutdown,
|
|
2836
3245
|
installShutdownHandlers,
|
|
@@ -2872,7 +3281,8 @@ export {
|
|
|
2872
3281
|
WEB_CONFIG_FILENAME,
|
|
2873
3282
|
resolveAgentFor,
|
|
2874
3283
|
parseAgentPhaseFlag,
|
|
3284
|
+
applyOpenCodeGoModel,
|
|
2875
3285
|
describeRunAgents,
|
|
2876
3286
|
hasExplicitAgentSelection
|
|
2877
3287
|
};
|
|
2878
|
-
//# sourceMappingURL=chunk-
|
|
3288
|
+
//# sourceMappingURL=chunk-YC24E66P.js.map
|