@maycombhq/atticus 2.0.0-beta.12.2 → 2.0.0-beta.14
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/dist/bin.js +3 -3
- package/dist/{chunk-ACW2C7CY.js → chunk-24EUDX5K.js} +5 -5
- package/dist/{chunk-3BZR2M2H.js → chunk-25TTISZF.js} +149 -104
- package/dist/chunk-2QF33M4X.js +43 -0
- package/dist/{chunk-BLEZRUU5.js → chunk-35LPWM32.js} +18 -18
- package/dist/{chunk-73QQ3KWY.js → chunk-3F4OM72R.js} +11 -11
- package/dist/{chunk-JFCTPPRA.js → chunk-3FBY2UAO.js} +102 -102
- package/dist/chunk-3GAX4GT2.js +41 -0
- package/dist/{chunk-767WN7BP.js → chunk-3RQ5AZA4.js} +3 -3
- package/dist/chunk-3UOFXHXE.js +48 -0
- package/dist/{chunk-KDKLT22F.js → chunk-45U5EYEE.js} +2 -2
- package/dist/{chunk-IRA6XAXY.js → chunk-4AK3G3SO.js} +11 -11
- package/dist/{chunk-U24UW3SV.js → chunk-4JCNTKRO.js} +11 -11
- package/dist/{chunk-35FTAQDX.js → chunk-4MDSW4HD.js} +4 -4
- package/dist/{chunk-PPP75X5G.js → chunk-4SPIDCGQ.js} +11 -11
- package/dist/{chunk-FR6J2NW5.js → chunk-4XUMHUAJ.js} +3 -3
- package/dist/{chunk-4Q6HX5GQ.js → chunk-5ABRLEKA.js} +1 -1
- package/dist/{chunk-PR5X4SIJ.js → chunk-5DJOPXIV.js} +4 -4
- package/dist/{chunk-CLDB6K2T.js → chunk-5IA6AEPF.js} +13 -13
- package/dist/chunk-5J5BWVSI.js +34 -0
- package/dist/{chunk-LQ5CEQFQ.js → chunk-5MHJDI4Q.js} +3 -3
- package/dist/{chunk-RA3TVBWK.js → chunk-5NADL2NL.js} +1 -1
- package/dist/{chunk-CV2Y7JQU.js → chunk-5SMTR7OH.js} +5 -5
- package/dist/{chunk-RSAJ33C6.js → chunk-5TK6HWPJ.js} +15 -15
- package/dist/{chunk-4CPOXPS4.js → chunk-5ZTOGSMC.js} +3 -3
- package/dist/{chunk-ZJDOYEW4.js → chunk-5ZXQDKGA.js} +6 -6
- package/dist/{chunk-X3HFDWKA.js → chunk-62FNRMFS.js} +1 -1
- package/dist/{chunk-AAIAS55Y.js → chunk-6BOG3VWS.js} +21 -21
- package/dist/{chunk-KTHFVH6T.js → chunk-6FTUMJDB.js} +9 -9
- package/dist/{chunk-66VD3EHO.js → chunk-6GT2F5N5.js} +10 -10
- package/dist/{chunk-THZXSH5O.js → chunk-6QDXNWK4.js} +11 -11
- package/dist/{chunk-CW4OVNJF.js → chunk-6R4S5AQ2.js} +10 -10
- package/dist/{chunk-LO3NRDCE.js → chunk-6T6JOLI7.js} +1 -1
- package/dist/{chunk-ZS2EZYOR.js → chunk-744GKTHJ.js} +4 -4
- package/dist/{chunk-ZNXTVNPY.js → chunk-74VWL26C.js} +19 -19
- package/dist/{chunk-WPBQT6VF.js → chunk-7ROVJ63F.js} +4 -4
- package/dist/{chunk-ZT6WXY3J.js → chunk-7TKV7LPE.js} +23 -23
- package/dist/{chunk-7CJ2TNZZ.js → chunk-7USOANHY.js} +16 -16
- package/dist/{chunk-PPCCFZG7.js → chunk-7WBYR3EO.js} +2 -2
- package/dist/{chunk-VOZI4AFV.js → chunk-A2ZDCL7B.js} +14 -14
- package/dist/{chunk-G3CY3PFO.js → chunk-AG7GZIP2.js} +2 -2
- package/dist/{chunk-6ZQOYNTT.js → chunk-AJQL5YGT.js} +46 -2
- package/dist/chunk-ANYED2TJ.js +54 -0
- package/dist/{chunk-CXDUMI7E.js → chunk-ASMKMBEQ.js} +3 -3
- package/dist/{chunk-S6IJNQFM.js → chunk-B3KDZGGW.js} +19 -19
- package/dist/{chunk-IUWOOFPR.js → chunk-B6UDXL46.js} +2 -2
- package/dist/{chunk-RICWZRBR.js → chunk-BDPECBQC.js} +4 -4
- package/dist/{chunk-OG42OLZK.js → chunk-BKJBWKAM.js} +24 -24
- package/dist/{chunk-YYV55774.js → chunk-BMQD24X2.js} +1 -1
- package/dist/{chunk-E52MNV5B.js → chunk-BYR5KVSS.js} +1090 -40
- package/dist/{chunk-C43X7Y7O.js → chunk-BYZER6EW.js} +4 -4
- package/dist/{chunk-DRA2V4R4.js → chunk-C4GYAMEL.js} +15 -15
- package/dist/{chunk-24ARIOB7.js → chunk-CBVRGUGK.js} +1 -1
- package/dist/{chunk-AV2DVINC.js → chunk-CSRNVT6P.js} +10 -10
- package/dist/{chunk-XKARSCXA.js → chunk-CT4ADBQQ.js} +14 -14
- package/dist/{chunk-IVBSAKVG.js → chunk-CTSB37J2.js} +15 -15
- package/dist/{chunk-2Y4EWUDF.js → chunk-CYVG7DD3.js} +4 -4
- package/dist/{chunk-ZPNRTY73.js → chunk-D6VVLYMV.js} +4 -4
- package/dist/{chunk-NAFPFQMJ.js → chunk-D7UBUQEY.js} +4 -4
- package/dist/chunk-DJHPM4TX.js +45 -0
- package/dist/{chunk-5VZJX75P.js → chunk-DLYLON5W.js} +11 -11
- package/dist/{chunk-DLSPFAC5.js → chunk-DRI5IK3M.js} +9 -3
- package/dist/{chunk-DDCK4CFE.js → chunk-DRSJ57DP.js} +2 -2
- package/dist/{chunk-AODGV7YL.js → chunk-DSW6E4OR.js} +23 -23
- package/dist/{chunk-N3Z5NFM4.js → chunk-DZYM6AN6.js} +4 -4
- package/dist/{chunk-PG5FIVP3.js → chunk-ELQCSMJM.js} +16 -16
- package/dist/chunk-ERIZ3X7P.js +38 -0
- package/dist/{chunk-X2SHYKUY.js → chunk-FHJ3NAIF.js} +6 -6
- package/dist/{chunk-JTI3FKGI.js → chunk-FJOFX7VK.js} +4 -4
- package/dist/{chunk-LZABEKI6.js → chunk-FVI44U5N.js} +189 -17
- package/dist/{chunk-T34ITVSM.js → chunk-GBFDKOY5.js} +4 -4
- package/dist/{chunk-2IFPJYBT.js → chunk-GBFPEELX.js} +19 -19
- package/dist/{chunk-IPB6EKUH.js → chunk-GN6OYMZS.js} +4 -4
- package/dist/{chunk-P4L435FY.js → chunk-GOG2YLKM.js} +12 -12
- package/dist/{chunk-AQPK22BH.js → chunk-GQC45MWG.js} +1 -1
- package/dist/{chunk-JQHNT45I.js → chunk-GSPYXZF4.js} +17 -17
- package/dist/{chunk-3RQK5AWY.js → chunk-HBYNSHIE.js} +4 -4
- package/dist/{chunk-K2WOVID6.js → chunk-HITV6XB7.js} +31 -31
- package/dist/{chunk-OKLXZ35H.js → chunk-HZWH4QQ4.js} +4 -4
- package/dist/{chunk-THLOT563.js → chunk-I3PFGDPR.js} +22 -22
- package/dist/{chunk-GFMOU6YM.js → chunk-IBKDZFNF.js} +17 -17
- package/dist/{chunk-4M3OQM5V.js → chunk-IEYY25SU.js} +10 -10
- package/dist/{chunk-FT2E2DHW.js → chunk-IHTZPVE6.js} +1 -1
- package/dist/{chunk-3DMXBIDW.js → chunk-IHZ2JO63.js} +3 -3
- package/dist/{chunk-UELYGLNG.js → chunk-IIFZJ52W.js} +14 -14
- package/dist/{chunk-7XYCCKGI.js → chunk-IOQDUPUK.js} +12 -12
- package/dist/{chunk-YU63ND72.js → chunk-IW4KD2KO.js} +9 -9
- package/dist/{chunk-2DFYLFBL.js → chunk-IWD2ZNSK.js} +17 -17
- package/dist/{chunk-X4VLWQR2.js → chunk-IWH3CE3N.js} +11 -11
- package/dist/{chunk-LIRPXFA4.js → chunk-J2U5CZVH.js} +17 -17
- package/dist/{chunk-AOPL3VT7.js → chunk-J6SJR2P2.js} +18 -15
- package/dist/{chunk-5BDBPV6V.js → chunk-JCQINQNG.js} +28 -28
- package/dist/{chunk-OOQPEISI.js → chunk-JDLYCWEW.js} +3 -3
- package/dist/chunk-JDWBTBDL.js +54 -0
- package/dist/{chunk-OV3WHHRI.js → chunk-JGPNL65L.js} +1 -1
- package/dist/{chunk-OQTSTW2G.js → chunk-JLQIWN7I.js} +6 -6
- package/dist/{chunk-S6JXYEG4.js → chunk-JMSK3SKS.js} +5 -5
- package/dist/{chunk-VZM535M5.js → chunk-JUWLAORV.js} +6 -6
- package/dist/{chunk-MPC5BQ6O.js → chunk-JWUAT3GG.js} +16 -16
- package/dist/{chunk-OYGY4DI2.js → chunk-K5DS7HYU.js} +25 -8
- package/dist/{chunk-P44WNZXO.js → chunk-K6JTUIBO.js} +15 -15
- package/dist/{chunk-OQPFFBPQ.js → chunk-K7OAIHJH.js} +17 -17
- package/dist/{chunk-EHLZJPGF.js → chunk-KBLI2YTN.js} +24 -24
- package/dist/{chunk-PWUVIOMW.js → chunk-KOLSYPTV.js} +17 -17
- package/dist/{chunk-WKVNT6DL.js → chunk-KTV3LDZA.js} +14 -14
- package/dist/{chunk-S4EGGQZB.js → chunk-KXNVR3SY.js} +14 -14
- package/dist/{chunk-5WIH5VUB.js → chunk-L7JGHU7B.js} +4 -4
- package/dist/{chunk-5BVNNYU7.js → chunk-LI4LPS3I.js} +1 -1
- package/dist/{chunk-J6FWM4VI.js → chunk-LNWKWUAA.js} +9 -9
- package/dist/{chunk-JW3ENKRI.js → chunk-LXEBD6WZ.js} +20 -20
- package/dist/{chunk-2L5XV7QK.js → chunk-M5MDJYXB.js} +10 -10
- package/dist/{chunk-QBUHJ77Q.js → chunk-M6SGY5AT.js} +18 -18
- package/dist/{chunk-7OHYHBEQ.js → chunk-MFDCFFFN.js} +1 -1
- package/dist/{chunk-PI6KNUBW.js → chunk-MG4LO2LM.js} +5 -5
- package/dist/{chunk-IUKKHYEK.js → chunk-MOYSMFCU.js} +6 -6
- package/dist/{chunk-TLTKLVZZ.js → chunk-MPTSUQHD.js} +1 -1
- package/dist/{chunk-J347EH7F.js → chunk-MYD3JJDW.js} +5 -5
- package/dist/chunk-MZBOXOT7.js +37 -0
- package/dist/{chunk-AVEKRWDF.js → chunk-MZHH5S22.js} +4 -4
- package/dist/{chunk-QXI64SJ4.js → chunk-N734S36H.js} +1 -1
- package/dist/{chunk-YIO2LEBW.js → chunk-NEOXUR77.js} +23 -23
- package/dist/{chunk-YDBWECPT.js → chunk-NHA3IIG5.js} +8 -8
- package/dist/{chunk-PQVZO25F.js → chunk-NJZEWNUL.js} +3 -3
- package/dist/{chunk-LNPS5GQ3.js → chunk-NNCSRRZU.js} +9 -9
- package/dist/{chunk-ZUCJCBS5.js → chunk-NONCVSYA.js} +4 -4
- package/dist/{chunk-7JA7XGWC.js → chunk-NRMD72XA.js} +24 -24
- package/dist/{chunk-ZTF2NSQD.js → chunk-NU6I7ERX.js} +5 -5
- package/dist/{chunk-M63Z7PIB.js → chunk-O7DIP5QU.js} +7 -7
- package/dist/{chunk-7V3IIWMG.js → chunk-OBGUJGXV.js} +23 -23
- package/dist/{chunk-EPTCDW3U.js → chunk-OF4A7CHX.js} +11 -11
- package/dist/{chunk-HFMLZFY4.js → chunk-OHSXSOVP.js} +6 -6
- package/dist/{chunk-M2U3IZ54.js → chunk-OKBFXKWJ.js} +5 -5
- package/dist/{chunk-ASCZ47XX.js → chunk-OMD7ZFUV.js} +2 -2
- package/dist/{chunk-K7ICVNZ6.js → chunk-OMTVSFHU.js} +22 -22
- package/dist/{chunk-WOWEF5DL.js → chunk-OPXFMH7V.js} +13 -13
- package/dist/{chunk-34COONQ2.js → chunk-PDXYFEDF.js} +7 -7
- package/dist/{chunk-QQLWNMLX.js → chunk-PLHLCTZC.js} +10 -10
- package/dist/{chunk-5WJCV6ED.js → chunk-PTVCIZRD.js} +1 -1
- package/dist/chunk-PWAZEGMY.js +43 -0
- package/dist/{chunk-OHBNRL75.js → chunk-QKZ4QEQE.js} +1 -1
- package/dist/{chunk-WMWYW4WB.js → chunk-QLP7SR7A.js} +1 -1
- package/dist/{chunk-UA4DLNV7.js → chunk-QO3IGQAV.js} +2 -2
- package/dist/{chunk-RNUHS433.js → chunk-QR7GE4R7.js} +5 -5
- package/dist/{chunk-V3P5ZJSO.js → chunk-R6KFSIIX.js} +31 -8
- package/dist/{chunk-EL4VOLGT.js → chunk-R6NE7KMO.js} +22 -22
- package/dist/{chunk-WMCKOZFT.js → chunk-RMQKKQIR.js} +5 -5
- package/dist/{chunk-JEZM3NRF.js → chunk-RWISSEVH.js} +2 -2
- package/dist/{chunk-EWJ32DKS.js → chunk-S5J2U5WU.js} +6 -6
- package/dist/{chunk-TDQNBA2N.js → chunk-S5U63AKM.js} +20 -20
- package/dist/{chunk-QUHSKUDF.js → chunk-SB7TN363.js} +27 -27
- package/dist/{chunk-KMU7XNK3.js → chunk-SCFQIVTI.js} +2 -2
- package/dist/{chunk-4DRSRU4U.js → chunk-SEIHA4IV.js} +22 -22
- package/dist/{chunk-TDKSKJU3.js → chunk-SFCXIHSS.js} +8 -8
- package/dist/{chunk-6J2BWOLO.js → chunk-SIXUVC4U.js} +11 -11
- package/dist/{chunk-6IFOKO2R.js → chunk-SXG7MWJR.js} +17 -17
- package/dist/{chunk-BGASQ4UD.js → chunk-SYSJGL5J.js} +11 -11
- package/dist/{chunk-CAH7L2QH.js → chunk-TFWVZXDL.js} +7 -7
- package/dist/{chunk-O775JVDM.js → chunk-TRHXX6TK.js} +15 -15
- package/dist/{chunk-MA43MHVR.js → chunk-TRQES4AU.js} +3 -3
- package/dist/{chunk-QJWE44D4.js → chunk-TTCFBLQN.js} +3 -3
- package/dist/{chunk-JARVXMUW.js → chunk-TWH4CWSQ.js} +2 -2
- package/dist/{chunk-OAXCNACK.js → chunk-TZBFR7FC.js} +3 -3
- package/dist/{chunk-R2A6DAPC.js → chunk-U5IVUP6J.js} +552 -539
- package/dist/chunk-UALSP7GQ.js +34 -0
- package/dist/chunk-UGLLLLP3.js +151 -0
- package/dist/{chunk-LURMCWUG.js → chunk-UXLYDGTH.js} +2 -2
- package/dist/{chunk-HSLT4NZA.js → chunk-V7EUAYRF.js} +19 -19
- package/dist/{chunk-D6CUQIU3.js → chunk-VFLKU5W2.js} +20 -20
- package/dist/{chunk-HZGTUG23.js → chunk-VHHVMIZ2.js} +1 -1
- package/dist/{chunk-GP3NGMWY.js → chunk-VKSZ4QRQ.js} +3 -3
- package/dist/{chunk-QLJ7KLO3.js → chunk-VPO7QBCI.js} +5 -5
- package/dist/{chunk-EUK4IONY.js → chunk-VR3CCWV4.js} +7 -7
- package/dist/chunk-VR7NZQTB.js +41 -0
- package/dist/{chunk-GGBEM27J.js → chunk-VSVRRZYG.js} +3 -3
- package/dist/{chunk-5P766RED.js → chunk-VU2SU7YM.js} +15 -1
- package/dist/{chunk-QZIAPAUG.js → chunk-VUH22CD2.js} +136 -35
- package/dist/{chunk-REFOPAZF.js → chunk-VUWEGLE5.js} +24 -24
- package/dist/{chunk-FM56YGBC.js → chunk-VZXFVGF4.js} +7 -7
- package/dist/{chunk-VK22DOCQ.js → chunk-WCI34RMN.js} +22 -22
- package/dist/{chunk-6FYKGYAO.js → chunk-WCM5NQQN.js} +6 -6
- package/dist/{chunk-U7RMOCQQ.js → chunk-WD4FEXU2.js} +7 -7
- package/dist/{chunk-R5DGXWOX.js → chunk-WE7XQEU3.js} +5 -5
- package/dist/{chunk-3ENG33LV.js → chunk-WF4MREFF.js} +3 -3
- package/dist/{chunk-7YZ6JPFR.js → chunk-WJCQ5LIS.js} +2 -2
- package/dist/{chunk-2UPMPTNJ.js → chunk-WLRBN5WZ.js} +4 -4
- package/dist/{chunk-KLROTB6N.js → chunk-WMIVXJZI.js} +2 -2
- package/dist/{chunk-5CIFSHTS.js → chunk-WTASJAJP.js} +17 -17
- package/dist/{chunk-ZIVRZ3WV.js → chunk-WZUHRZEU.js} +21 -21
- package/dist/{chunk-PURVXI7L.js → chunk-X2FQF2OU.js} +4 -4
- package/dist/{chunk-UOW37F7C.js → chunk-X3GQJ7NF.js} +3 -3
- package/dist/{chunk-X5IKLUFM.js → chunk-XFFJC3CG.js} +3 -3
- package/dist/{chunk-U55GKPUB.js → chunk-XHOLEYC2.js} +14 -14
- package/dist/{chunk-FAAOOT34.js → chunk-XPKSNF34.js} +4 -4
- package/dist/{chunk-E53MN24E.js → chunk-XR43R3R7.js} +29 -10
- package/dist/{chunk-NTUHEHC6.js → chunk-XWWTLE3A.js} +13 -13
- package/dist/{chunk-JLZPUCEC.js → chunk-XXFSFT3Y.js} +6 -6
- package/dist/{chunk-JLF4JIZ6.js → chunk-Y7PPHHAL.js} +10 -10
- package/dist/{chunk-KZSIKS64.js → chunk-YBMXI4JK.js} +10 -10
- package/dist/{chunk-3LWQYHID.js → chunk-YHCTZC6K.js} +7 -7
- package/dist/{chunk-UGMJ3Z35.js → chunk-YSLIXVBW.js} +2 -2
- package/dist/{chunk-WQKMAOD7.js → chunk-Z3GCR344.js} +4 -4
- package/dist/{chunk-LUBKMCTR.js → chunk-Z3ZL3UHQ.js} +2 -2
- package/dist/{chunk-64BU3UUE.js → chunk-Z5TS4KDL.js} +16 -16
- package/dist/{chunk-MT6GHEH5.js → chunk-ZDJ7LQNW.js} +4 -4
- package/dist/{chunk-V5UZVS74.js → chunk-ZJRLEEL4.js} +11 -11
- package/dist/{chunk-SOLKTI2T.js → chunk-ZOC5JCIY.js} +4 -4
- package/dist/files.json +455 -447
- package/dist/packages/sdk/npm/index.js +59 -9
- package/dist/packages/ui/dist/assets/{elk-api-GNftut9z.js → elk-api-BuFBvNyV.js} +2 -2
- package/dist/packages/ui/dist/assets/{index-C0JEkXyN.css → index-C5QnK82A.css} +1 -1
- package/dist/packages/ui/dist/assets/{index-C2evnHpj.js → index-CQ0a1cBg.js} +12 -12
- package/dist/packages/ui/dist/index.html +2 -2
- package/package.json +4 -4
- package/dist/chunk-6VIQB6XT.js +0 -37
- package/dist/chunk-BUJJLQ7C.js +0 -41
- package/dist/chunk-FML6GOUB.js +0 -45
- package/dist/chunk-HEQ2YUFK.js +0 -43
- package/dist/chunk-JHISKJFN.js +0 -48
- package/dist/chunk-KLFPFMXV.js +0 -38
- package/dist/chunk-KSAKVVOA.js +0 -34
- package/dist/chunk-M5NKIQKM.js +0 -34
- package/dist/chunk-O23JP5EA.js +0 -54
- package/dist/chunk-WZEUA4PU.js +0 -54
- package/dist/chunk-XMRFYVBB.js +0 -41
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
STEP_CLASSES,
|
|
14
14
|
changesDirOf,
|
|
15
15
|
changesRelOf,
|
|
16
|
+
copilotAcpOf,
|
|
16
17
|
currentSignal,
|
|
17
18
|
differentThings,
|
|
18
19
|
identifierWords,
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
runsRelOf,
|
|
28
29
|
stateDirOf,
|
|
29
30
|
stepModelsOf
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-FVI44U5N.js";
|
|
31
32
|
import {
|
|
32
33
|
writeFileAtomic
|
|
33
34
|
} from "./chunk-MMB2OHUY.js";
|
|
@@ -1111,8 +1112,8 @@ function checkAllowed(kind, agent) {
|
|
|
1111
1112
|
}
|
|
1112
1113
|
function makeRunId(now, seq) {
|
|
1113
1114
|
const stamp = now.toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
|
|
1114
|
-
const
|
|
1115
|
-
return `run-${stamp}-${
|
|
1115
|
+
const tail2 = seq !== void 0 ? String(seq).padStart(4, "0") : Math.random().toString(36).slice(2, 8);
|
|
1116
|
+
return `run-${stamp}-${tail2}`;
|
|
1116
1117
|
}
|
|
1117
1118
|
function toRunSummary(run) {
|
|
1118
1119
|
return {
|
|
@@ -1132,7 +1133,8 @@ function toRunSummary(run) {
|
|
|
1132
1133
|
...run.tools ? { tools: run.tools } : {},
|
|
1133
1134
|
...run.request.retrieval ? { retrieval: run.request.retrieval } : {},
|
|
1134
1135
|
stepClass: run.stepClass ?? stepClassOf(run.request),
|
|
1135
|
-
...run.model ? { model: run.model } : {}
|
|
1136
|
+
...run.model ? { model: run.model } : {},
|
|
1137
|
+
...run.assistant ? { assistant: run.assistant } : {}
|
|
1136
1138
|
};
|
|
1137
1139
|
}
|
|
1138
1140
|
var OneShotRuntime = class {
|
|
@@ -1149,11 +1151,15 @@ var OneShotRuntime = class {
|
|
|
1149
1151
|
modelFor(_request) {
|
|
1150
1152
|
return void 0;
|
|
1151
1153
|
}
|
|
1154
|
+
/** The kind an agent's allowedRuntimes must name for this runtime (copilot-acp: hand-off too). */
|
|
1155
|
+
allowedAs(_agent) {
|
|
1156
|
+
return this.kind;
|
|
1157
|
+
}
|
|
1152
1158
|
/** Keep a finished run where Model runs reads it (the model runtime, given a root). */
|
|
1153
1159
|
async keep(_run) {
|
|
1154
1160
|
}
|
|
1155
1161
|
async prepare(request) {
|
|
1156
|
-
checkAllowed(this.
|
|
1162
|
+
checkAllowed(this.allowedAs(request.agent), request.agent);
|
|
1157
1163
|
if (request.pack.manifest.totalTokens > request.agent.tokenBudget) {
|
|
1158
1164
|
throw new RuntimeError(`context pack (${request.pack.manifest.totalTokens} tokens) is over agent ${request.agent.id}'s budget of ${request.agent.tokenBudget}`);
|
|
1159
1165
|
}
|
|
@@ -1181,8 +1187,14 @@ var OneShotRuntime = class {
|
|
|
1181
1187
|
return run;
|
|
1182
1188
|
}
|
|
1183
1189
|
try {
|
|
1184
|
-
const { output, usage, tools } = await this.produce(run, signal);
|
|
1185
|
-
run = transition(run, "produced", this.now(), {
|
|
1190
|
+
const { output, usage, tools, model, assistant } = await this.produce(run, signal);
|
|
1191
|
+
run = transition(run, "produced", this.now(), {
|
|
1192
|
+
output,
|
|
1193
|
+
usage,
|
|
1194
|
+
...tools ? { tools } : {},
|
|
1195
|
+
...model ? { model } : {},
|
|
1196
|
+
...assistant ? { assistant } : {}
|
|
1197
|
+
});
|
|
1186
1198
|
const problems = await this.opts.validate?.(output, run.request) ?? [];
|
|
1187
1199
|
run = problems.length === 0 ? transition(run, "validated", this.now()) : transition(run, "failed", this.now(), { errors: problems });
|
|
1188
1200
|
} catch (e) {
|
|
@@ -1699,12 +1711,1005 @@ async function pruneRuns(root, days, now = /* @__PURE__ */ new Date(), only) {
|
|
|
1699
1711
|
}
|
|
1700
1712
|
|
|
1701
1713
|
// packages/ai/dist/factory.js
|
|
1702
|
-
import { spawn } from "node:child_process";
|
|
1703
|
-
import { mkdir as
|
|
1714
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1715
|
+
import { mkdir as mkdir5, mkdtemp, readFile as readFile5, rm as rm2, stat as stat3, writeFile as writeFile5 } from "node:fs/promises";
|
|
1704
1716
|
import { tmpdir } from "node:os";
|
|
1705
|
-
import { dirname, join as
|
|
1717
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
1718
|
+
|
|
1719
|
+
// packages/ai/dist/copilot-acp.js
|
|
1720
|
+
import { spawn } from "node:child_process";
|
|
1721
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
1722
|
+
import { mkdir as mkdir4, readFile as readFile4, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
|
|
1723
|
+
import { basename, dirname, isAbsolute, join as join4, relative, resolve, sep } from "node:path";
|
|
1724
|
+
import { createInterface } from "node:readline";
|
|
1725
|
+
|
|
1726
|
+
// packages/ai/dist/acp.js
|
|
1727
|
+
var ACP_PROTOCOL_VERSION = 1;
|
|
1728
|
+
var ACP_METHODS = {
|
|
1729
|
+
initialize: "initialize",
|
|
1730
|
+
authenticate: "authenticate",
|
|
1731
|
+
sessionNew: "session/new",
|
|
1732
|
+
sessionSetModel: "session/set_model",
|
|
1733
|
+
sessionPrompt: "session/prompt",
|
|
1734
|
+
sessionCancel: "session/cancel",
|
|
1735
|
+
sessionUpdate: "session/update",
|
|
1736
|
+
requestPermission: "session/request_permission",
|
|
1737
|
+
readTextFile: "fs/read_text_file",
|
|
1738
|
+
writeTextFile: "fs/write_text_file",
|
|
1739
|
+
terminalCreate: "terminal/create",
|
|
1740
|
+
terminalOutput: "terminal/output",
|
|
1741
|
+
terminalWaitForExit: "terminal/wait_for_exit",
|
|
1742
|
+
terminalKill: "terminal/kill",
|
|
1743
|
+
terminalRelease: "terminal/release"
|
|
1744
|
+
};
|
|
1745
|
+
var ACP_ERRORS = {
|
|
1746
|
+
invalidParams: -32602,
|
|
1747
|
+
methodNotFound: -32601,
|
|
1748
|
+
internal: -32603,
|
|
1749
|
+
authRequired: -32e3
|
|
1750
|
+
};
|
|
1751
|
+
var AcpRpcError = class extends Error {
|
|
1752
|
+
code;
|
|
1753
|
+
data;
|
|
1754
|
+
constructor(code, message, data) {
|
|
1755
|
+
super(message);
|
|
1756
|
+
this.code = code;
|
|
1757
|
+
this.data = data;
|
|
1758
|
+
this.name = "AcpRpcError";
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
var AcpClient = class {
|
|
1762
|
+
t;
|
|
1763
|
+
h;
|
|
1764
|
+
tap;
|
|
1765
|
+
next = 1;
|
|
1766
|
+
pending = /* @__PURE__ */ new Map();
|
|
1767
|
+
closed;
|
|
1768
|
+
constructor(t, h, tap = () => {
|
|
1769
|
+
}) {
|
|
1770
|
+
this.t = t;
|
|
1771
|
+
this.h = h;
|
|
1772
|
+
this.tap = tap;
|
|
1773
|
+
t.onLine((line) => this.receive(line));
|
|
1774
|
+
t.onClose((why) => {
|
|
1775
|
+
this.closed = why;
|
|
1776
|
+
for (const p of this.pending.values())
|
|
1777
|
+
p.reject(new AcpRpcError(ACP_ERRORS.internal, why));
|
|
1778
|
+
this.pending.clear();
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
out(message) {
|
|
1782
|
+
const m = { jsonrpc: "2.0", ...message };
|
|
1783
|
+
this.tap("out", m);
|
|
1784
|
+
this.t.send(JSON.stringify(m));
|
|
1785
|
+
}
|
|
1786
|
+
request(method, params) {
|
|
1787
|
+
if (this.closed)
|
|
1788
|
+
return Promise.reject(new AcpRpcError(ACP_ERRORS.internal, this.closed));
|
|
1789
|
+
const id = this.next++;
|
|
1790
|
+
return new Promise((resolve2, reject) => {
|
|
1791
|
+
this.pending.set(id, { resolve: resolve2, reject });
|
|
1792
|
+
this.out({ id, method, params });
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
notify(method, params) {
|
|
1796
|
+
if (!this.closed)
|
|
1797
|
+
this.out({ method, params });
|
|
1798
|
+
}
|
|
1799
|
+
receive(line) {
|
|
1800
|
+
if (!line.trim())
|
|
1801
|
+
return;
|
|
1802
|
+
let m;
|
|
1803
|
+
try {
|
|
1804
|
+
m = JSON.parse(line);
|
|
1805
|
+
} catch {
|
|
1806
|
+
this.tap("in", { notJson: line.slice(0, 500) });
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
this.tap("in", m);
|
|
1810
|
+
if (m.method === void 0 && m.id !== void 0) {
|
|
1811
|
+
const p = this.pending.get(Number(m.id));
|
|
1812
|
+
if (!p)
|
|
1813
|
+
return;
|
|
1814
|
+
this.pending.delete(Number(m.id));
|
|
1815
|
+
if (m.error)
|
|
1816
|
+
p.reject(new AcpRpcError(m.error.code, m.error.message, m.error.data));
|
|
1817
|
+
else
|
|
1818
|
+
p.resolve(m.result ?? null);
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
if (m.method === ACP_METHODS.sessionUpdate) {
|
|
1822
|
+
const u = m.params?.update;
|
|
1823
|
+
if (u && typeof u === "object")
|
|
1824
|
+
this.h.update(u);
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (m.id === void 0)
|
|
1828
|
+
return;
|
|
1829
|
+
const id = m.id;
|
|
1830
|
+
void this.answer(m.method ?? "", m.params ?? {}).then((result) => this.out({ id, result }), (e) => this.out({
|
|
1831
|
+
id,
|
|
1832
|
+
error: {
|
|
1833
|
+
code: e instanceof AcpRpcError ? e.code : ACP_ERRORS.invalidParams,
|
|
1834
|
+
message: e.message
|
|
1835
|
+
}
|
|
1836
|
+
}));
|
|
1837
|
+
}
|
|
1838
|
+
answer(method, p) {
|
|
1839
|
+
const s = (k) => typeof p[k] === "string" ? p[k] : "";
|
|
1840
|
+
switch (method) {
|
|
1841
|
+
case ACP_METHODS.readTextFile:
|
|
1842
|
+
return this.h.readTextFile({
|
|
1843
|
+
path: s("path"),
|
|
1844
|
+
...typeof p.line === "number" ? { line: p.line } : {},
|
|
1845
|
+
...typeof p.limit === "number" ? { limit: p.limit } : {}
|
|
1846
|
+
});
|
|
1847
|
+
case ACP_METHODS.writeTextFile:
|
|
1848
|
+
return this.h.writeTextFile({ path: s("path"), content: s("content") });
|
|
1849
|
+
case ACP_METHODS.requestPermission:
|
|
1850
|
+
return this.h.requestPermission({
|
|
1851
|
+
toolCall: p.toolCall ?? {},
|
|
1852
|
+
options: Array.isArray(p.options) ? p.options : []
|
|
1853
|
+
});
|
|
1854
|
+
case ACP_METHODS.terminalCreate:
|
|
1855
|
+
return this.h.terminalCreate({
|
|
1856
|
+
command: s("command"),
|
|
1857
|
+
...Array.isArray(p.args) ? { args: p.args.map(String) } : {},
|
|
1858
|
+
...typeof p.cwd === "string" ? { cwd: p.cwd } : {},
|
|
1859
|
+
...Array.isArray(p.env) ? { env: p.env } : {},
|
|
1860
|
+
...typeof p.outputByteLimit === "number" ? { outputByteLimit: p.outputByteLimit } : {}
|
|
1861
|
+
});
|
|
1862
|
+
case ACP_METHODS.terminalOutput:
|
|
1863
|
+
return this.h.terminalOutput({ terminalId: s("terminalId") });
|
|
1864
|
+
case ACP_METHODS.terminalWaitForExit:
|
|
1865
|
+
return this.h.terminalWaitForExit({ terminalId: s("terminalId") });
|
|
1866
|
+
case ACP_METHODS.terminalKill:
|
|
1867
|
+
return this.h.terminalKill({ terminalId: s("terminalId") });
|
|
1868
|
+
case ACP_METHODS.terminalRelease:
|
|
1869
|
+
return this.h.terminalRelease({ terminalId: s("terminalId") });
|
|
1870
|
+
default:
|
|
1871
|
+
return Promise.reject(new AcpRpcError(ACP_ERRORS.methodNotFound, `Atticus doesn't offer ${method}`));
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
// ------------------------------------------------------------ the agent's methods
|
|
1875
|
+
initialize(clientInfo) {
|
|
1876
|
+
return this.request(ACP_METHODS.initialize, {
|
|
1877
|
+
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
1878
|
+
clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: true },
|
|
1879
|
+
clientInfo
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
newSession(cwd) {
|
|
1883
|
+
return this.request(ACP_METHODS.sessionNew, { cwd, mcpServers: [] });
|
|
1884
|
+
}
|
|
1885
|
+
setModel(sessionId, modelId) {
|
|
1886
|
+
return this.request(ACP_METHODS.sessionSetModel, { sessionId, modelId });
|
|
1887
|
+
}
|
|
1888
|
+
prompt(sessionId, text) {
|
|
1889
|
+
return this.request(ACP_METHODS.sessionPrompt, {
|
|
1890
|
+
sessionId,
|
|
1891
|
+
prompt: [{ type: "text", text }]
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
cancel(sessionId) {
|
|
1895
|
+
this.notify(ACP_METHODS.sessionCancel, { sessionId });
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1898
|
+
function chunkText(u) {
|
|
1899
|
+
const c = u.content;
|
|
1900
|
+
return c?.type === "text" && typeof c.text === "string" ? c.text : void 0;
|
|
1901
|
+
}
|
|
1902
|
+
var UPDATE = {
|
|
1903
|
+
message: "agent_message_chunk",
|
|
1904
|
+
thought: "agent_thought_chunk",
|
|
1905
|
+
toolCall: "tool_call",
|
|
1906
|
+
toolCallUpdate: "tool_call_update",
|
|
1907
|
+
plan: "plan"
|
|
1908
|
+
};
|
|
1909
|
+
function usageOf(u) {
|
|
1910
|
+
if (!u)
|
|
1911
|
+
return void 0;
|
|
1912
|
+
const n = (...ks) => {
|
|
1913
|
+
for (const k of ks)
|
|
1914
|
+
if (typeof u[k] === "number")
|
|
1915
|
+
return u[k];
|
|
1916
|
+
return void 0;
|
|
1917
|
+
};
|
|
1918
|
+
const i = n("inputTokens", "input_tokens", "promptTokens");
|
|
1919
|
+
const o = n("outputTokens", "output_tokens", "completionTokens");
|
|
1920
|
+
return i === void 0 && o === void 0 ? void 0 : {
|
|
1921
|
+
inputTokens: Math.max(0, Math.round(i ?? 0)),
|
|
1922
|
+
outputTokens: Math.max(0, Math.round(o ?? 0))
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
var isAuthRequired = (e) => e instanceof AcpRpcError && (e.code === ACP_ERRORS.authRequired || /auth|sign.?in|log.?in/i.test(e.message));
|
|
1926
|
+
|
|
1927
|
+
// packages/ai/dist/copilot-acp.js
|
|
1928
|
+
function words(line) {
|
|
1929
|
+
const out = [];
|
|
1930
|
+
let cur = "";
|
|
1931
|
+
let quote;
|
|
1932
|
+
let any = false;
|
|
1933
|
+
let meta = false;
|
|
1934
|
+
for (const ch of line) {
|
|
1935
|
+
if (quote) {
|
|
1936
|
+
if (ch === quote)
|
|
1937
|
+
quote = void 0;
|
|
1938
|
+
else
|
|
1939
|
+
cur += ch;
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
if (ch === '"' || ch === "'") {
|
|
1943
|
+
quote = ch;
|
|
1944
|
+
any = true;
|
|
1945
|
+
continue;
|
|
1946
|
+
}
|
|
1947
|
+
if (/\s/.test(ch)) {
|
|
1948
|
+
if (cur || any)
|
|
1949
|
+
out.push(cur);
|
|
1950
|
+
cur = "";
|
|
1951
|
+
any = false;
|
|
1952
|
+
continue;
|
|
1953
|
+
}
|
|
1954
|
+
if ("|&;<>`$(){}\n".includes(ch))
|
|
1955
|
+
meta = true;
|
|
1956
|
+
cur += ch;
|
|
1957
|
+
}
|
|
1958
|
+
if (cur || any)
|
|
1959
|
+
out.push(cur);
|
|
1960
|
+
return { words: out, meta: meta || quote !== void 0 };
|
|
1961
|
+
}
|
|
1962
|
+
function commandLineOf(line) {
|
|
1963
|
+
const w = words(line.trim()).words;
|
|
1964
|
+
if (!w.length)
|
|
1965
|
+
throw new RuntimeConfigLikeError("copilotAcp.command is empty");
|
|
1966
|
+
const args = w.slice(1);
|
|
1967
|
+
return { command: w[0], args: args.includes("--acp") ? args : [...args, "--acp"] };
|
|
1968
|
+
}
|
|
1969
|
+
var RuntimeConfigLikeError = class extends RuntimeError {
|
|
1970
|
+
};
|
|
1971
|
+
var PERSONS = [
|
|
1972
|
+
{
|
|
1973
|
+
test: (a) => a[0] === "questions" && a[1] === "answer",
|
|
1974
|
+
why: "a person answers questions (atticus questions answer is theirs to run)"
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
test: (a) => a.includes("--approve"),
|
|
1978
|
+
why: "--approve is a person's: a human approves every write to shared systems"
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
test: (a) => a.includes("--accept") || a.includes("--accept-proposal"),
|
|
1982
|
+
why: "a person accepts what is proposed (--accept is theirs)"
|
|
1983
|
+
},
|
|
1984
|
+
{
|
|
1985
|
+
test: (a) => a[0] === "map" && a.includes("--all"),
|
|
1986
|
+
why: "this session is one step of atticus map --all; Atticus runs the loop, not the session"
|
|
1987
|
+
},
|
|
1988
|
+
{
|
|
1989
|
+
test: (a) => ["ui", "serve", "mcp"].includes(a[0] ?? ""),
|
|
1990
|
+
why: "a server that keeps running isn't a step's command"
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
test: (a) => a.some((x) => x === "--root" || x.startsWith("--root=")),
|
|
1994
|
+
why: "the session works in this metarepo; --root points elsewhere"
|
|
1995
|
+
}
|
|
1996
|
+
];
|
|
1997
|
+
var ATTICUS_NAMES = /* @__PURE__ */ new Set(["atticus", "atticus.cmd", "atticus.exe"]);
|
|
1998
|
+
function atticusArgvOf(command, args = []) {
|
|
1999
|
+
const head = words(command.trim());
|
|
2000
|
+
if (head.meta)
|
|
2001
|
+
return {
|
|
2002
|
+
refused: `Atticus runs no shell here, so a command line with | & ; < > $ or backquotes is refused: ${short(command)}. Run one atticus command at a time.`
|
|
2003
|
+
};
|
|
2004
|
+
const all = [...head.words, ...args];
|
|
2005
|
+
const program = all[0] ?? "";
|
|
2006
|
+
if (!ATTICUS_NAMES.has(program.toLowerCase()))
|
|
2007
|
+
return {
|
|
2008
|
+
refused: `Atticus runs only atticus commands in this session (atticus <command> <arguments>); ${short([program, ...all.slice(1)].join(" "))} is refused. Read files with your file tools; write only under facts/ or the step's result file.`
|
|
2009
|
+
};
|
|
2010
|
+
const argv = all.slice(1);
|
|
2011
|
+
if (!argv.length)
|
|
2012
|
+
return { refused: "atticus needs a command (atticus next, atticus verify <repo>, ...)" };
|
|
2013
|
+
for (const p of PERSONS)
|
|
2014
|
+
if (p.test(argv))
|
|
2015
|
+
return { refused: `Refused: ${p.why}.` };
|
|
2016
|
+
return { argv };
|
|
2017
|
+
}
|
|
2018
|
+
var short = (s, n = 120) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
|
|
2019
|
+
function real(p) {
|
|
2020
|
+
let cur = resolve(p);
|
|
2021
|
+
const rest = [];
|
|
2022
|
+
for (; ; ) {
|
|
2023
|
+
try {
|
|
2024
|
+
return join4(realpathSync.native(cur), ...rest.reverse());
|
|
2025
|
+
} catch {
|
|
2026
|
+
const up = dirname(cur);
|
|
2027
|
+
if (up === cur)
|
|
2028
|
+
return resolve(p);
|
|
2029
|
+
rest.push(basename(cur));
|
|
2030
|
+
cur = up;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
var sameOrUnder = (root, p) => {
|
|
2035
|
+
const r = relative(root, p);
|
|
2036
|
+
return r === "" || !r.startsWith("..") && !isAbsolute(r);
|
|
2037
|
+
};
|
|
2038
|
+
var caseOf = (p) => process.platform === "win32" ? p.toLowerCase() : p;
|
|
2039
|
+
var Paths = class {
|
|
2040
|
+
p;
|
|
2041
|
+
reads;
|
|
2042
|
+
writeDirs;
|
|
2043
|
+
files;
|
|
2044
|
+
constructor(p) {
|
|
2045
|
+
this.p = p;
|
|
2046
|
+
this.reads = p.readRoots.map((r) => caseOf(real(r)));
|
|
2047
|
+
this.writeDirs = p.writeRoots.map((r) => caseOf(real(r)));
|
|
2048
|
+
this.files = (p.writeFiles ?? []).map((f) => caseOf(real(f)));
|
|
2049
|
+
}
|
|
2050
|
+
readable(path) {
|
|
2051
|
+
if (!path || !isAbsolute(path))
|
|
2052
|
+
return `the path must be absolute (got ${short(path)})`;
|
|
2053
|
+
const r = caseOf(real(path));
|
|
2054
|
+
return this.reads.some((x) => sameOrUnder(x, r)) ? void 0 : `Atticus lets this session read only under the metarepo and its clones; ${short(path)} is outside`;
|
|
2055
|
+
}
|
|
2056
|
+
writable(path) {
|
|
2057
|
+
if (!path || !isAbsolute(path))
|
|
2058
|
+
return `the path must be absolute (got ${short(path)})`;
|
|
2059
|
+
const r = caseOf(real(path));
|
|
2060
|
+
if (r.split(sep).includes(".git"))
|
|
2061
|
+
return `Atticus never lets a session write in .git (${short(path)})`;
|
|
2062
|
+
if (this.files.includes(r) || this.writeDirs.some((x) => sameOrUnder(x, r)))
|
|
2063
|
+
return void 0;
|
|
2064
|
+
const base = this.p.readRoots[0] ?? "";
|
|
2065
|
+
const rel = (x) => {
|
|
2066
|
+
const r2 = relative(base, x);
|
|
2067
|
+
return r2 && !r2.startsWith("..") && !isAbsolute(r2) ? r2.split(sep).join("/") : x;
|
|
2068
|
+
};
|
|
2069
|
+
const where = [
|
|
2070
|
+
...this.p.writeRoots.map((d) => `${rel(d)}/`),
|
|
2071
|
+
...(this.p.writeFiles ?? []).map(rel)
|
|
2072
|
+
].join(", ");
|
|
2073
|
+
return `Atticus lets this session write only its step's result: it writes only under ${where || "nothing"}; ${short(path)} is refused`;
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
var factsOnly = (root, factsDir) => ({
|
|
2077
|
+
readRoots: readRootsOf(root),
|
|
2078
|
+
writeRoots: [factsDir]
|
|
2079
|
+
});
|
|
2080
|
+
function readRootsOf(root) {
|
|
2081
|
+
const out = [root];
|
|
2082
|
+
const state = join4(stateDirOf(root), "workspace");
|
|
2083
|
+
if (!sameOrUnder(resolve(root), resolve(state)))
|
|
2084
|
+
out.push(state);
|
|
2085
|
+
return out;
|
|
2086
|
+
}
|
|
2087
|
+
var needsShell = (command) => process.platform === "win32" && !/\.(exe|com)$/i.test(command);
|
|
2088
|
+
var quoteForCmd = (a) => /[\s"]/.test(a) ? `"${a.replace(/"/g, '""')}"` : a;
|
|
2089
|
+
var spawnAcpServer = (o) => {
|
|
2090
|
+
const shell = needsShell(o.command);
|
|
2091
|
+
let child;
|
|
2092
|
+
let err = "";
|
|
2093
|
+
let failed = () => {
|
|
2094
|
+
};
|
|
2095
|
+
let ok = () => {
|
|
2096
|
+
};
|
|
2097
|
+
const started = new Promise((res, rej) => {
|
|
2098
|
+
ok = res;
|
|
2099
|
+
failed = rej;
|
|
2100
|
+
});
|
|
2101
|
+
started.catch(() => void 0);
|
|
2102
|
+
try {
|
|
2103
|
+
child = spawn(shell ? quoteForCmd(o.command) : o.command, shell ? o.args.map(quoteForCmd) : o.args, { cwd: o.cwd, env: o.env, stdio: ["pipe", "pipe", "pipe"], windowsHide: true, shell });
|
|
2104
|
+
} catch (e) {
|
|
2105
|
+
failed(e);
|
|
2106
|
+
const dead = { send: () => {
|
|
2107
|
+
}, onLine: () => {
|
|
2108
|
+
}, onClose: (fn) => fn(String(e)) };
|
|
2109
|
+
return { transport: dead, stderr: () => "", close: async () => {
|
|
2110
|
+
}, started };
|
|
2111
|
+
}
|
|
2112
|
+
const lines = [];
|
|
2113
|
+
const closes = [];
|
|
2114
|
+
let closed;
|
|
2115
|
+
const close = (why) => {
|
|
2116
|
+
if (closed)
|
|
2117
|
+
return;
|
|
2118
|
+
closed = why;
|
|
2119
|
+
for (const f of closes)
|
|
2120
|
+
f(why);
|
|
2121
|
+
};
|
|
2122
|
+
child.on("spawn", () => ok());
|
|
2123
|
+
child.on("error", (e) => {
|
|
2124
|
+
failed(e);
|
|
2125
|
+
close(`the Copilot language server couldn't be run: ${e.message}`);
|
|
2126
|
+
});
|
|
2127
|
+
child.on("exit", (code, signal) => close(`the Copilot language server ended (${code ?? signal ?? "no code"})`));
|
|
2128
|
+
for (const s of [child.stdin, child.stdout, child.stderr])
|
|
2129
|
+
s?.on("error", () => void 0);
|
|
2130
|
+
child.stderr?.setEncoding("utf8").on("data", (d) => {
|
|
2131
|
+
err = (err + d).slice(-64e3);
|
|
2132
|
+
});
|
|
2133
|
+
createInterface({ input: child.stdout }).on("line", (l) => {
|
|
2134
|
+
for (const f of lines)
|
|
2135
|
+
f(l);
|
|
2136
|
+
});
|
|
2137
|
+
return {
|
|
2138
|
+
started,
|
|
2139
|
+
stderr: () => err,
|
|
2140
|
+
transport: {
|
|
2141
|
+
send: (t) => {
|
|
2142
|
+
if (!closed)
|
|
2143
|
+
child.stdin?.write(`${t}
|
|
2144
|
+
`);
|
|
2145
|
+
},
|
|
2146
|
+
onLine: (f) => lines.push(f),
|
|
2147
|
+
onClose: (f) => closed ? f(closed) : closes.push(f)
|
|
2148
|
+
},
|
|
2149
|
+
close: async () => {
|
|
2150
|
+
if (closed)
|
|
2151
|
+
return;
|
|
2152
|
+
child.stdin?.end();
|
|
2153
|
+
await new Promise((res) => {
|
|
2154
|
+
const t = setTimeout(() => {
|
|
2155
|
+
child.kill();
|
|
2156
|
+
res();
|
|
2157
|
+
}, 2e3);
|
|
2158
|
+
closes.push(() => {
|
|
2159
|
+
clearTimeout(t);
|
|
2160
|
+
res();
|
|
2161
|
+
});
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
};
|
|
2165
|
+
};
|
|
2166
|
+
function atticusExec(entry, node = process.execPath) {
|
|
2167
|
+
return (argv, o) => new Promise((res) => {
|
|
2168
|
+
let output = "";
|
|
2169
|
+
const child = spawn(node, [entry, ...argv], {
|
|
2170
|
+
cwd: o.cwd,
|
|
2171
|
+
env: { ...process.env, ATTICUS_ACP_SESSION: "1" },
|
|
2172
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2173
|
+
windowsHide: true,
|
|
2174
|
+
signal: o.signal
|
|
2175
|
+
});
|
|
2176
|
+
const take = (d) => {
|
|
2177
|
+
const t = d.toString("utf8");
|
|
2178
|
+
output = (output + t).slice(-1e6);
|
|
2179
|
+
o.onOutput?.(t);
|
|
2180
|
+
};
|
|
2181
|
+
child.stdout.on("data", take);
|
|
2182
|
+
child.stderr.on("data", take);
|
|
2183
|
+
child.on("error", (e) => res({ exitCode: 1, output: `${output}${e.message}
|
|
2184
|
+
` }));
|
|
2185
|
+
child.on("close", (code, signal) => res({ exitCode: code, output, signal }));
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
var AcpSignInError = class extends RuntimeError {
|
|
2189
|
+
constructor(message) {
|
|
2190
|
+
super(message);
|
|
2191
|
+
this.name = "AcpSignInError";
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2194
|
+
var ACP_OFFERED = [
|
|
2195
|
+
"fs/read_text_file",
|
|
2196
|
+
"fs/write_text_file",
|
|
2197
|
+
"terminal/create (atticus only)",
|
|
2198
|
+
"session/request_permission"
|
|
2199
|
+
];
|
|
2200
|
+
var withTimeout = (p, ms, what) => new Promise((res, rej) => {
|
|
2201
|
+
const t = setTimeout(() => rej(new RuntimeError(`${what} took over ${Math.round(ms / 1e3)}s`)), ms);
|
|
2202
|
+
p.then((v) => {
|
|
2203
|
+
clearTimeout(t);
|
|
2204
|
+
res(v);
|
|
2205
|
+
}, (e) => {
|
|
2206
|
+
clearTimeout(t);
|
|
2207
|
+
rej(e);
|
|
2208
|
+
});
|
|
2209
|
+
});
|
|
2210
|
+
var oneLine = (s, n = 150) => short(s.replace(/\s+/g, " ").trim(), n);
|
|
2211
|
+
var signInLines = (stderr) => stderr.split(/\r?\n/).map((l) => l.trim()).filter((l) => /https?:\/\/|code|sign|log.?in|auth/i.test(l)).slice(-5);
|
|
2212
|
+
async function runAcpSession(o) {
|
|
2213
|
+
const { command, args } = commandLineOf(o.command);
|
|
2214
|
+
const server = (o.spawn ?? spawnAcpServer)({
|
|
2215
|
+
command,
|
|
2216
|
+
args,
|
|
2217
|
+
cwd: o.cwd,
|
|
2218
|
+
env: { ...process.env, ...o.env ?? {} }
|
|
2219
|
+
});
|
|
2220
|
+
const transcript = [];
|
|
2221
|
+
const paths = new Paths(o.policy);
|
|
2222
|
+
const calls = [];
|
|
2223
|
+
const refused = [];
|
|
2224
|
+
const say = (l) => o.onProgress?.(short(l, 160));
|
|
2225
|
+
let text = "";
|
|
2226
|
+
let pendingText = "";
|
|
2227
|
+
let agentCalls = 0;
|
|
2228
|
+
let cancelWhy;
|
|
2229
|
+
let sessionId;
|
|
2230
|
+
const abort = new AbortController();
|
|
2231
|
+
const flush = () => {
|
|
2232
|
+
if (pendingText.trim())
|
|
2233
|
+
say(` Copilot: ${oneLine(pendingText)}`);
|
|
2234
|
+
pendingText = "";
|
|
2235
|
+
};
|
|
2236
|
+
const record = (name, input, output, error) => {
|
|
2237
|
+
calls.push({
|
|
2238
|
+
round: 1,
|
|
2239
|
+
name,
|
|
2240
|
+
input,
|
|
2241
|
+
output: short(output, 2e3),
|
|
2242
|
+
tokens: estimateTokens(output),
|
|
2243
|
+
...error ? { error: true } : {}
|
|
2244
|
+
});
|
|
2245
|
+
if (error) {
|
|
2246
|
+
refused.push(output);
|
|
2247
|
+
flush();
|
|
2248
|
+
say(` Refused: ${oneLine(output, 140)}`);
|
|
2249
|
+
}
|
|
2250
|
+
};
|
|
2251
|
+
const refuse = (name, input, why) => {
|
|
2252
|
+
record(name, input, why, true);
|
|
2253
|
+
throw new AcpRpcError(ACP_ERRORS.invalidParams, why);
|
|
2254
|
+
};
|
|
2255
|
+
const terminals = /* @__PURE__ */ new Map();
|
|
2256
|
+
let tn = 0;
|
|
2257
|
+
const box = {};
|
|
2258
|
+
const cancel = (why) => {
|
|
2259
|
+
if (cancelWhy)
|
|
2260
|
+
return;
|
|
2261
|
+
cancelWhy = why;
|
|
2262
|
+
flush();
|
|
2263
|
+
say(` Stopping the session: ${why}.`);
|
|
2264
|
+
if (sessionId)
|
|
2265
|
+
box.client?.cancel(sessionId);
|
|
2266
|
+
for (const t of terminals.values())
|
|
2267
|
+
t.kill.abort();
|
|
2268
|
+
};
|
|
2269
|
+
const handlers = {
|
|
2270
|
+
async readTextFile(p) {
|
|
2271
|
+
const why = paths.readable(p.path);
|
|
2272
|
+
if (why)
|
|
2273
|
+
return refuse("fs/read_text_file", { path: p.path }, why);
|
|
2274
|
+
const all = await readFile4(p.path, "utf8").catch((e) => {
|
|
2275
|
+
throw new AcpRpcError(ACP_ERRORS.invalidParams, `${p.path} can't be read: ${e.code ?? e.message}`);
|
|
2276
|
+
});
|
|
2277
|
+
let content = all;
|
|
2278
|
+
if (p.line !== void 0 || p.limit !== void 0) {
|
|
2279
|
+
const lines = all.split("\n");
|
|
2280
|
+
const from = Math.max(0, (p.line ?? 1) - 1);
|
|
2281
|
+
content = lines.slice(from, p.limit !== void 0 ? from + p.limit : void 0).join("\n");
|
|
2282
|
+
}
|
|
2283
|
+
record("fs/read_text_file", { path: p.path }, `${content.length} characters`);
|
|
2284
|
+
return { content };
|
|
2285
|
+
},
|
|
2286
|
+
async writeTextFile(p) {
|
|
2287
|
+
const why = paths.writable(p.path);
|
|
2288
|
+
if (why)
|
|
2289
|
+
return refuse("fs/write_text_file", { path: p.path }, why);
|
|
2290
|
+
await mkdir4(dirname(p.path), { recursive: true });
|
|
2291
|
+
await writeFile4(p.path, p.content, "utf8");
|
|
2292
|
+
record("fs/write_text_file", { path: p.path }, `${p.content.length} characters written`);
|
|
2293
|
+
return null;
|
|
2294
|
+
},
|
|
2295
|
+
async requestPermission(p) {
|
|
2296
|
+
const tc = p.toolCall;
|
|
2297
|
+
const why = permissionRefused(tc, paths);
|
|
2298
|
+
const pick = (kinds) => kinds.map((k) => p.options.find((x) => x.kind === k)).find(Boolean);
|
|
2299
|
+
const allow = why ? void 0 : pick(["allow_once"]);
|
|
2300
|
+
const input = {
|
|
2301
|
+
kind: tc.kind ?? "",
|
|
2302
|
+
title: tc.title ?? "",
|
|
2303
|
+
...tc.locations?.length ? { locations: tc.locations.map((l) => l.path) } : {}
|
|
2304
|
+
};
|
|
2305
|
+
if (allow) {
|
|
2306
|
+
record(`permission:${tc.kind ?? "other"}`, input, `allowed once: ${tc.title ?? ""}`);
|
|
2307
|
+
return { outcome: { outcome: "selected", optionId: allow.optionId } };
|
|
2308
|
+
}
|
|
2309
|
+
record(`permission:${tc.kind ?? "other"}`, input, why ?? "Refused: the server offered only to allow it always; Atticus allows once at a time", true);
|
|
2310
|
+
const reject = pick(["reject_once", "reject_always"]);
|
|
2311
|
+
return reject ? { outcome: { outcome: "selected", optionId: reject.optionId } } : { outcome: { outcome: "cancelled" } };
|
|
2312
|
+
},
|
|
2313
|
+
async terminalCreate(p) {
|
|
2314
|
+
const a = atticusArgvOf(p.command, p.args ?? []);
|
|
2315
|
+
const input = { command: p.command, args: p.args ?? [] };
|
|
2316
|
+
if (a.refused !== void 0)
|
|
2317
|
+
return refuse("terminal/create", input, a.refused);
|
|
2318
|
+
const cwd = p.cwd ?? o.cwd;
|
|
2319
|
+
const out = paths.readable(cwd);
|
|
2320
|
+
if (out)
|
|
2321
|
+
return refuse("terminal/create", input, `the command runs in the metarepo: ${out}`);
|
|
2322
|
+
const id = `atticus-${++tn}`;
|
|
2323
|
+
const kill = new AbortController();
|
|
2324
|
+
flush();
|
|
2325
|
+
say(` atticus ${oneLine(a.argv.join(" "), 140)}`);
|
|
2326
|
+
const t = {
|
|
2327
|
+
output: "",
|
|
2328
|
+
kill,
|
|
2329
|
+
...p.outputByteLimit ? { limit: p.outputByteLimit } : {}
|
|
2330
|
+
};
|
|
2331
|
+
t.done = o.exec(a.argv, {
|
|
2332
|
+
cwd,
|
|
2333
|
+
signal: kill.signal,
|
|
2334
|
+
onOutput: (s) => {
|
|
2335
|
+
t.output += s;
|
|
2336
|
+
if (t.limit && Buffer.byteLength(t.output) > t.limit)
|
|
2337
|
+
t.output = t.output.slice(-t.limit);
|
|
2338
|
+
}
|
|
2339
|
+
}).then((r) => {
|
|
2340
|
+
if (!t.output && r.output)
|
|
2341
|
+
t.output = r.output;
|
|
2342
|
+
t.exit = { exitCode: r.exitCode, signal: r.signal ?? null };
|
|
2343
|
+
record("terminal/create", input, `exit ${r.exitCode ?? "none"}: ${short(t.output, 1500)}`);
|
|
2344
|
+
return t.exit;
|
|
2345
|
+
});
|
|
2346
|
+
terminals.set(id, t);
|
|
2347
|
+
return { terminalId: id };
|
|
2348
|
+
},
|
|
2349
|
+
async terminalOutput(p) {
|
|
2350
|
+
const t = terminals.get(p.terminalId);
|
|
2351
|
+
if (!t)
|
|
2352
|
+
throw new AcpRpcError(ACP_ERRORS.invalidParams, `no terminal ${p.terminalId}`);
|
|
2353
|
+
return { output: t.output, truncated: false, ...t.exit ? { exitStatus: t.exit } : {} };
|
|
2354
|
+
},
|
|
2355
|
+
async terminalWaitForExit(p) {
|
|
2356
|
+
const t = terminals.get(p.terminalId);
|
|
2357
|
+
if (!t)
|
|
2358
|
+
throw new AcpRpcError(ACP_ERRORS.invalidParams, `no terminal ${p.terminalId}`);
|
|
2359
|
+
return t.done;
|
|
2360
|
+
},
|
|
2361
|
+
async terminalKill(p) {
|
|
2362
|
+
terminals.get(p.terminalId)?.kill.abort();
|
|
2363
|
+
return null;
|
|
2364
|
+
},
|
|
2365
|
+
async terminalRelease(p) {
|
|
2366
|
+
const t = terminals.get(p.terminalId);
|
|
2367
|
+
t?.kill.abort();
|
|
2368
|
+
terminals.delete(p.terminalId);
|
|
2369
|
+
return null;
|
|
2370
|
+
},
|
|
2371
|
+
update(u) {
|
|
2372
|
+
const kind = u.sessionUpdate;
|
|
2373
|
+
if (kind === UPDATE.message) {
|
|
2374
|
+
const t = chunkText(u);
|
|
2375
|
+
if (t) {
|
|
2376
|
+
text += t;
|
|
2377
|
+
pendingText += t;
|
|
2378
|
+
}
|
|
2379
|
+
} else if (kind === UPDATE.toolCall) {
|
|
2380
|
+
agentCalls++;
|
|
2381
|
+
flush();
|
|
2382
|
+
say(` \xB7 ${oneLine(String(u.title ?? u.kind ?? "a tool"), 140)}`);
|
|
2383
|
+
if (o.maxTurns !== void 0 && agentCalls > o.maxTurns)
|
|
2384
|
+
cancel(`maxTurns ${o.maxTurns}`);
|
|
2385
|
+
} else if (kind === UPDATE.plan) {
|
|
2386
|
+
const n = Array.isArray(u.entries) ? u.entries.length : 0;
|
|
2387
|
+
if (n)
|
|
2388
|
+
say(` Plan: ${n} steps`);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
};
|
|
2392
|
+
const client = new AcpClient(server.transport, handlers, (dir, m) => transcript.push(JSON.stringify({ dir, m })));
|
|
2393
|
+
box.client = client;
|
|
2394
|
+
const onAbort = () => cancel("stopped (Ctrl+C)");
|
|
2395
|
+
o.signal?.addEventListener("abort", onAbort, { once: true });
|
|
2396
|
+
let timer;
|
|
2397
|
+
try {
|
|
2398
|
+
let init;
|
|
2399
|
+
try {
|
|
2400
|
+
await server.started;
|
|
2401
|
+
init = await withTimeout(client.initialize({ name: "atticus", version: o.clientVersion ?? "2" }), 6e4, "The Copilot language server's initialize");
|
|
2402
|
+
} catch (e) {
|
|
2403
|
+
throw new RuntimeError(`Atticus couldn't start the Copilot language server (${o.command}): ${firstLine(e)}${tail(server.stderr())}. Check copilotAcp.command in runtime.yaml, and that ${command} --help lists --acp.`);
|
|
2404
|
+
}
|
|
2405
|
+
const assistant = {
|
|
2406
|
+
name: init.agentInfo?.name ?? basename(command).replace(/\.(cmd|exe)$/i, ""),
|
|
2407
|
+
...init.agentInfo?.version ? { version: init.agentInfo.version } : {},
|
|
2408
|
+
...typeof init.protocolVersion === "number" ? { protocolVersion: init.protocolVersion } : {}
|
|
2409
|
+
};
|
|
2410
|
+
let ns;
|
|
2411
|
+
try {
|
|
2412
|
+
ns = await withTimeout(client.newSession(o.cwd), 12e4, "Opening a Copilot session");
|
|
2413
|
+
} catch (e) {
|
|
2414
|
+
if (isAuthRequired(e)) {
|
|
2415
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
2416
|
+
throw signInError(e, init, server.stderr());
|
|
2417
|
+
}
|
|
2418
|
+
throw new RuntimeError(`The Copilot language server didn't open a session: ${firstLine(e)}`);
|
|
2419
|
+
}
|
|
2420
|
+
sessionId = ns.sessionId;
|
|
2421
|
+
let model = ns.models?.currentModelId;
|
|
2422
|
+
if (o.model && o.model !== model) {
|
|
2423
|
+
const offered = (ns.models?.availableModels ?? []).map((m) => m.modelId);
|
|
2424
|
+
if (!offered.includes(o.model))
|
|
2425
|
+
throw new RuntimeError(`The Copilot language server doesn't offer the model ${o.model} (it offers ${offered.join(", ") || "no list"}): change copilotAcp.model in runtime.yaml, or leave it out for Copilot's own.`);
|
|
2426
|
+
await client.setModel(sessionId, o.model);
|
|
2427
|
+
model = o.model;
|
|
2428
|
+
}
|
|
2429
|
+
say(` Copilot session open (${assistant.name}${assistant.version ? ` ${assistant.version}` : ""}${model ? `, ${model}` : ""}).`);
|
|
2430
|
+
if (o.signal?.aborted)
|
|
2431
|
+
cancel("stopped (Ctrl+C)");
|
|
2432
|
+
const asked = client.prompt(sessionId, o.prompt);
|
|
2433
|
+
timer = setTimeout(() => cancel("timeout"), o.timeoutMs ?? 30 * 6e4);
|
|
2434
|
+
let answer;
|
|
2435
|
+
try {
|
|
2436
|
+
answer = await new Promise((res, rej) => {
|
|
2437
|
+
asked.then(res, rej);
|
|
2438
|
+
const watch = setInterval(() => {
|
|
2439
|
+
if (!cancelWhy)
|
|
2440
|
+
return;
|
|
2441
|
+
clearInterval(watch);
|
|
2442
|
+
setTimeout(() => res({ stopReason: "cancelled" }), 1e4);
|
|
2443
|
+
}, 50);
|
|
2444
|
+
asked.finally(() => clearInterval(watch)).catch(() => void 0);
|
|
2445
|
+
});
|
|
2446
|
+
} catch (e) {
|
|
2447
|
+
if (isAuthRequired(e))
|
|
2448
|
+
throw signInError(e, init, server.stderr());
|
|
2449
|
+
throw new RuntimeError(`The Copilot session failed: ${firstLine(e)}${tail(server.stderr())}`);
|
|
2450
|
+
}
|
|
2451
|
+
flush();
|
|
2452
|
+
const usage = usageOf(answer.usage);
|
|
2453
|
+
return {
|
|
2454
|
+
stopReason: cancelWhy ? "cancelled" : answer.stopReason,
|
|
2455
|
+
...cancelWhy ? { stopped: cancelWhy } : {},
|
|
2456
|
+
...model ? { model } : {},
|
|
2457
|
+
assistant,
|
|
2458
|
+
...usage ? { usage } : {},
|
|
2459
|
+
text,
|
|
2460
|
+
toolCalls: calls,
|
|
2461
|
+
refused,
|
|
2462
|
+
agentToolCalls: agentCalls
|
|
2463
|
+
};
|
|
2464
|
+
} finally {
|
|
2465
|
+
clearTimeout(timer);
|
|
2466
|
+
o.signal?.removeEventListener("abort", onAbort);
|
|
2467
|
+
abort.abort();
|
|
2468
|
+
for (const t of terminals.values())
|
|
2469
|
+
t.kill.abort();
|
|
2470
|
+
await server.close().catch(() => void 0);
|
|
2471
|
+
if (o.transcript) {
|
|
2472
|
+
await mkdir4(dirname(o.transcript), { recursive: true });
|
|
2473
|
+
await writeFile4(o.transcript, transcript.join("\n") + (transcript.length ? "\n" : ""), "utf8");
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
var firstLine = (e) => String(e?.message ?? e).split("\n")[0];
|
|
2478
|
+
var tail = (stderr) => {
|
|
2479
|
+
const l = stderr.trim().split(/\r?\n/).slice(-2).join(" ").trim();
|
|
2480
|
+
return l ? ` (it said: ${short(l, 300)})` : "";
|
|
2481
|
+
};
|
|
2482
|
+
function signInError(e, init, stderr) {
|
|
2483
|
+
const how = (init.authMethods ?? []).map((m) => m.description || m.name).filter(Boolean).join("; ");
|
|
2484
|
+
const lines = signInLines(stderr);
|
|
2485
|
+
return new AcpSignInError([
|
|
2486
|
+
`GitHub Copilot isn't signed in here, so the run stopped. The Copilot language server said: ${firstLine(e)}`,
|
|
2487
|
+
...lines.length ? [`It also said: ${lines.join(" ")}`] : [],
|
|
2488
|
+
...how ? [`Its ways to sign in: ${how}.`] : [],
|
|
2489
|
+
"Sign in yourself (Copilot's sign-in in your editor, or the link and code above), then run the command again. Atticus never enters or keeps your credentials."
|
|
2490
|
+
].join("\n"));
|
|
2491
|
+
}
|
|
2492
|
+
function permissionRefused(tc, paths) {
|
|
2493
|
+
const locs = (tc.locations ?? []).map((l) => l.path);
|
|
2494
|
+
switch (tc.kind) {
|
|
2495
|
+
case "think":
|
|
2496
|
+
return void 0;
|
|
2497
|
+
case "read":
|
|
2498
|
+
case "search": {
|
|
2499
|
+
if (!locs.length)
|
|
2500
|
+
return tc.kind === "search" ? void 0 : "Refused: a read must say which file (use fs/read_text_file)";
|
|
2501
|
+
for (const l of locs) {
|
|
2502
|
+
const why = paths.readable(l);
|
|
2503
|
+
if (why)
|
|
2504
|
+
return why;
|
|
2505
|
+
}
|
|
2506
|
+
return void 0;
|
|
2507
|
+
}
|
|
2508
|
+
case "edit": {
|
|
2509
|
+
if (!locs.length)
|
|
2510
|
+
return "Refused: an edit must say which file it changes";
|
|
2511
|
+
for (const l of locs) {
|
|
2512
|
+
const why = paths.writable(l);
|
|
2513
|
+
if (why)
|
|
2514
|
+
return why;
|
|
2515
|
+
}
|
|
2516
|
+
return void 0;
|
|
2517
|
+
}
|
|
2518
|
+
case "execute": {
|
|
2519
|
+
const raw = tc.rawInput ?? {};
|
|
2520
|
+
const cmd = typeof raw.command === "string" ? raw.command : typeof raw.commandLine === "string" ? raw.commandLine : tc.title ?? "";
|
|
2521
|
+
const args = Array.isArray(raw.args) ? raw.args.map(String) : [];
|
|
2522
|
+
const a = atticusArgvOf(cmd, args);
|
|
2523
|
+
return a.refused;
|
|
2524
|
+
}
|
|
2525
|
+
default:
|
|
2526
|
+
return `Refused: Atticus doesn't let this session ${tc.kind ?? "do"} ${short(tc.title ?? "that")} (it may read the metarepo, write its step's result and run atticus commands)`;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
async function copilotAcpProbe(o) {
|
|
2530
|
+
const { command, args } = commandLineOf(o.command);
|
|
2531
|
+
const plain = args.filter((a) => a !== "--acp");
|
|
2532
|
+
const env = { ...process.env, ...o.env ?? {} };
|
|
2533
|
+
const version = await new Promise((res) => {
|
|
2534
|
+
const shell = needsShell(command);
|
|
2535
|
+
let out = "";
|
|
2536
|
+
let child;
|
|
2537
|
+
try {
|
|
2538
|
+
child = spawn(shell ? quoteForCmd(command) : command, [...shell ? plain.map(quoteForCmd) : plain, "--version"], {
|
|
2539
|
+
cwd: o.cwd,
|
|
2540
|
+
env,
|
|
2541
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2542
|
+
windowsHide: true,
|
|
2543
|
+
shell
|
|
2544
|
+
});
|
|
2545
|
+
} catch (e) {
|
|
2546
|
+
res({ ok: false, text: e.message });
|
|
2547
|
+
return;
|
|
2548
|
+
}
|
|
2549
|
+
const t = setTimeout(() => child.kill(), o.timeoutMs ?? 6e4);
|
|
2550
|
+
child.stdout?.on("data", (d) => out += d.toString("utf8"));
|
|
2551
|
+
child.stderr?.on("data", (d) => out += d.toString("utf8"));
|
|
2552
|
+
child.on("error", (e) => {
|
|
2553
|
+
clearTimeout(t);
|
|
2554
|
+
res({ ok: false, text: e.message });
|
|
2555
|
+
});
|
|
2556
|
+
child.on("close", (code) => {
|
|
2557
|
+
clearTimeout(t);
|
|
2558
|
+
res({ ok: code === 0, text: out.trim() });
|
|
2559
|
+
});
|
|
2560
|
+
});
|
|
2561
|
+
if (!version.ok)
|
|
2562
|
+
return { found: false, said: oneLine(version.text, 200) };
|
|
2563
|
+
const v = version.text.split(/\r?\n/).find((l) => l.trim())?.trim();
|
|
2564
|
+
const server = (o.spawn ?? spawnAcpServer)({ command, args, cwd: o.cwd, env });
|
|
2565
|
+
const client = new AcpClient(server.transport, {
|
|
2566
|
+
readTextFile: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor reads nothing")),
|
|
2567
|
+
writeTextFile: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor writes nothing")),
|
|
2568
|
+
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
|
2569
|
+
terminalCreate: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "doctor runs nothing")),
|
|
2570
|
+
terminalOutput: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "no terminal")),
|
|
2571
|
+
terminalWaitForExit: () => Promise.reject(new AcpRpcError(ACP_ERRORS.invalidParams, "no terminal")),
|
|
2572
|
+
terminalKill: async () => null,
|
|
2573
|
+
terminalRelease: async () => null,
|
|
2574
|
+
update: () => {
|
|
2575
|
+
}
|
|
2576
|
+
});
|
|
2577
|
+
const base = { found: true, ...v ? { version: v } : {} };
|
|
2578
|
+
try {
|
|
2579
|
+
await server.started;
|
|
2580
|
+
await withTimeout(client.initialize({ name: "atticus-doctor", version: "2" }), o.timeoutMs ?? 6e4, "initialize");
|
|
2581
|
+
try {
|
|
2582
|
+
await withTimeout(client.newSession(o.cwd), o.timeoutMs ?? 6e4, "a new session");
|
|
2583
|
+
return { ...base, signedIn: true };
|
|
2584
|
+
} catch (e) {
|
|
2585
|
+
if (isAuthRequired(e)) {
|
|
2586
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
2587
|
+
const lines = signInLines(server.stderr());
|
|
2588
|
+
return { ...base, signedIn: false, said: [firstLine(e), ...lines].join(" ") };
|
|
2589
|
+
}
|
|
2590
|
+
return { ...base, said: firstLine(e) };
|
|
2591
|
+
}
|
|
2592
|
+
} catch (e) {
|
|
2593
|
+
return { ...base, said: `the --acp handshake failed: ${firstLine(e)}` };
|
|
2594
|
+
} finally {
|
|
2595
|
+
await server.close().catch(() => void 0);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
var CopilotAcpRuntime = class extends OneShotRuntime {
|
|
2599
|
+
c;
|
|
2600
|
+
kind = "copilot-acp";
|
|
2601
|
+
constructor(c) {
|
|
2602
|
+
super({ ...c.now ? { now: c.now } : {}, ...c.validate ? { validate: c.validate } : {} });
|
|
2603
|
+
this.c = c;
|
|
2604
|
+
}
|
|
2605
|
+
allowedAs(agent) {
|
|
2606
|
+
return agent.allowedRuntimes.includes("copilot-acp") ? "copilot-acp" : "hand-off";
|
|
2607
|
+
}
|
|
2608
|
+
modelFor() {
|
|
2609
|
+
return this.c.model;
|
|
2610
|
+
}
|
|
2611
|
+
async produce(run, signal) {
|
|
2612
|
+
const { request } = run;
|
|
2613
|
+
const root = this.c.root;
|
|
2614
|
+
const dir = join4(runsDirOf(root), request.change, run.runId);
|
|
2615
|
+
await mkdir4(dir, { recursive: true });
|
|
2616
|
+
const outRel = HandoffRuntime.outputRel(run, changesRelOf(root), runsRelOf(root));
|
|
2617
|
+
const prompt = HandoffRuntime.promptFor(run, changesRelOf(root), runsRelOf(root)).replace(/\nWhen the file is complete.*\n$/s, "\n") + (request.selfCheck ? `
|
|
2618
|
+
Before you finish, check the file: run ${request.selfCheck.command} ${outRel}. Fix each problem it lists and run it again, until it says the file is clean (at most ${request.selfCheck.limit} times).
|
|
2619
|
+
` : "") + `
|
|
2620
|
+
${DATA_RULE}
|
|
2621
|
+
`;
|
|
2622
|
+
await writeFile4(join4(dir, "prompt.md"), prompt, "utf8");
|
|
2623
|
+
await writeFile4(join4(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
|
|
2624
|
+
const outputFile = request.outputIn === "run" ? join4(dir, request.outputPath) : join4(changesDirOf(root), request.change, request.outputPath);
|
|
2625
|
+
const before = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
|
|
2626
|
+
const r = await runAcpSession({
|
|
2627
|
+
command: this.c.command,
|
|
2628
|
+
cwd: root,
|
|
2629
|
+
prompt,
|
|
2630
|
+
policy: { readRoots: readRootsOf(root), writeRoots: [], writeFiles: [outputFile] },
|
|
2631
|
+
exec: this.c.exec ?? noExec,
|
|
2632
|
+
...this.c.model ? { model: this.c.model } : {},
|
|
2633
|
+
...this.c.maxTurns ? { maxTurns: this.c.maxTurns } : {},
|
|
2634
|
+
...this.c.timeoutMs ? { timeoutMs: this.c.timeoutMs } : {},
|
|
2635
|
+
...signal ? { signal } : {},
|
|
2636
|
+
...this.c.onProgress ? { onProgress: this.c.onProgress } : {},
|
|
2637
|
+
...this.c.env ? { env: this.c.env } : {},
|
|
2638
|
+
...this.c.spawn ? { spawn: this.c.spawn } : {},
|
|
2639
|
+
...this.c.clientVersion ? { clientVersion: this.c.clientVersion } : {},
|
|
2640
|
+
transcript: join4(dir, "transcript.jsonl")
|
|
2641
|
+
});
|
|
2642
|
+
const after = (await stat2(outputFile).catch(() => void 0))?.mtimeMs;
|
|
2643
|
+
const written = after !== void 0 && after !== before ? await readFile4(outputFile, "utf8") : void 0;
|
|
2644
|
+
const tools = {
|
|
2645
|
+
offered: ACP_OFFERED,
|
|
2646
|
+
calls: r.toolCalls,
|
|
2647
|
+
...r.stopped ? { stopped: r.stopped } : {}
|
|
2648
|
+
};
|
|
2649
|
+
if (written === void 0 && r.stopReason !== "end_turn")
|
|
2650
|
+
throw Object.assign(new RuntimeError(`The Copilot session ended (${r.stopped ?? r.stopReason}) without writing ${outRel}.`), { tools });
|
|
2651
|
+
return {
|
|
2652
|
+
output: written ?? r.text,
|
|
2653
|
+
usage: r.usage ?? {
|
|
2654
|
+
inputTokens: request.pack.manifest.totalTokens,
|
|
2655
|
+
outputTokens: estimateTokens(r.text)
|
|
2656
|
+
},
|
|
2657
|
+
tools,
|
|
2658
|
+
...r.model ? { model: r.model } : {},
|
|
2659
|
+
assistant: r.assistant
|
|
2660
|
+
};
|
|
2661
|
+
}
|
|
2662
|
+
/** Kept as a hand-off run is: run.json beside the prompt, so Model runs shows it. */
|
|
2663
|
+
async keep(run) {
|
|
2664
|
+
const dir = join4(runsDirOf(this.c.root), run.request.change, run.runId);
|
|
2665
|
+
await mkdir4(dir, { recursive: true });
|
|
2666
|
+
await writeFile4(join4(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
|
|
2667
|
+
}
|
|
2668
|
+
};
|
|
2669
|
+
var noExec = async (argv) => ({
|
|
2670
|
+
exitCode: 127,
|
|
2671
|
+
output: `atticus ${argv.join(" ")}: this program can't run atticus commands for the session; run the step with the atticus command line.
|
|
2672
|
+
`
|
|
2673
|
+
});
|
|
2674
|
+
async function keepAcpRun(o) {
|
|
2675
|
+
const dir = join4(runsDirOf(o.root), o.change, o.runId);
|
|
2676
|
+
await mkdir4(dir, { recursive: true });
|
|
2677
|
+
if (!existsSync(join4(dir, "prompt.md")))
|
|
2678
|
+
await writeFile4(join4(dir, "prompt.md"), o.prompt, "utf8");
|
|
2679
|
+
const r = o.result;
|
|
2680
|
+
const run = {
|
|
2681
|
+
runId: o.runId,
|
|
2682
|
+
request: { change: o.change, agent: o.agent, outputPath: o.outputPath },
|
|
2683
|
+
runtime: "copilot-acp",
|
|
2684
|
+
state: o.state,
|
|
2685
|
+
attempt: 1,
|
|
2686
|
+
startedAt: o.startedAt,
|
|
2687
|
+
finishedAt: o.finishedAt,
|
|
2688
|
+
errors: o.errors,
|
|
2689
|
+
...r?.usage ? { usage: r.usage } : {},
|
|
2690
|
+
...r ? {
|
|
2691
|
+
tools: {
|
|
2692
|
+
offered: ACP_OFFERED,
|
|
2693
|
+
calls: r.toolCalls,
|
|
2694
|
+
...r.stopped ? { stopped: r.stopped } : {}
|
|
2695
|
+
}
|
|
2696
|
+
} : {},
|
|
2697
|
+
stepClass: o.stepClass ?? stepClassOf({ agent: o.agent }),
|
|
2698
|
+
...r?.model ? { model: r.model } : {},
|
|
2699
|
+
...r ? { assistant: r.assistant } : {}
|
|
2700
|
+
};
|
|
2701
|
+
await writeFile4(join4(dir, "run.json"), JSON.stringify(run, null, 2) + "\n", "utf8");
|
|
2702
|
+
return dir;
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
// packages/ai/dist/factory.js
|
|
1706
2706
|
var RUNTIME_MODES = RuntimeKind.options;
|
|
1707
|
-
var CONFIGURED = [
|
|
2707
|
+
var CONFIGURED = [
|
|
2708
|
+
"hand-off",
|
|
2709
|
+
"model",
|
|
2710
|
+
"headless-claude-code",
|
|
2711
|
+
"copilot-acp"
|
|
2712
|
+
];
|
|
1708
2713
|
var RuntimeConfigError = class extends RuntimeError {
|
|
1709
2714
|
constructor(message) {
|
|
1710
2715
|
super(message);
|
|
@@ -1717,7 +2722,7 @@ var AiOffError = class extends RuntimeConfigError {
|
|
|
1717
2722
|
}
|
|
1718
2723
|
};
|
|
1719
2724
|
function claudeCodeCliRunner(o = {}) {
|
|
1720
|
-
return (i) => collectChild(() =>
|
|
2725
|
+
return (i) => collectChild(() => spawn2(o.command ?? "claude", i.args, {
|
|
1721
2726
|
cwd: i.cwd,
|
|
1722
2727
|
env: { ...process.env, ...i.env },
|
|
1723
2728
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -1726,7 +2731,7 @@ function claudeCodeCliRunner(o = {}) {
|
|
|
1726
2731
|
}), i.prompt, i.timeoutMs, i.cwd);
|
|
1727
2732
|
}
|
|
1728
2733
|
function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform) {
|
|
1729
|
-
return new Promise((
|
|
2734
|
+
return new Promise((resolve2, reject) => {
|
|
1730
2735
|
let done = false;
|
|
1731
2736
|
const timer = {};
|
|
1732
2737
|
const fail = (e) => {
|
|
@@ -1758,16 +2763,16 @@ function collectChild(start, prompt, timeoutMs, cwd, platform = process.platform
|
|
|
1758
2763
|
return;
|
|
1759
2764
|
done = true;
|
|
1760
2765
|
clearTimeout(timer.id);
|
|
1761
|
-
|
|
2766
|
+
resolve2({ exitCode: code, stdout, stderr });
|
|
1762
2767
|
});
|
|
1763
2768
|
child.stdin.end(prompt, "utf8");
|
|
1764
2769
|
});
|
|
1765
2770
|
}
|
|
1766
|
-
var cloneDirs = (root) => [
|
|
2771
|
+
var cloneDirs = (root) => [join5(root, "workspace"), join5(stateDirOf(root), "workspace")];
|
|
1767
2772
|
async function existingDirs(dirs) {
|
|
1768
2773
|
const out = [];
|
|
1769
2774
|
for (const d of [...new Set(dirs)])
|
|
1770
|
-
if ((await
|
|
2775
|
+
if ((await stat3(d).catch(() => void 0))?.isDirectory())
|
|
1771
2776
|
out.push(d);
|
|
1772
2777
|
return out;
|
|
1773
2778
|
}
|
|
@@ -1804,9 +2809,9 @@ var HeadlessClaudeCodeRuntime = class _HeadlessClaudeCodeRuntime extends OneShot
|
|
|
1804
2809
|
}
|
|
1805
2810
|
async produce(run, signal) {
|
|
1806
2811
|
const { request } = run;
|
|
1807
|
-
const dir =
|
|
2812
|
+
const dir = join5(runsDirOf(this.h.root), request.change, run.runId);
|
|
1808
2813
|
const reviewer = request.agent.outputArtifact === "findings" && request.outputIn === "run";
|
|
1809
|
-
const work = reviewer ? await mkdtemp(
|
|
2814
|
+
const work = reviewer ? await mkdtemp(join5(tmpdir(), "atticus-review-")) : void 0;
|
|
1810
2815
|
const clones = work ? await existingDirs(cloneDirs(this.h.root)) : [];
|
|
1811
2816
|
const base = work ? {
|
|
1812
2817
|
cwd: work,
|
|
@@ -1820,27 +2825,27 @@ var HeadlessClaudeCodeRuntime = class _HeadlessClaudeCodeRuntime extends OneShot
|
|
|
1820
2825
|
`Bash(${request.selfCheck.command}:*)`
|
|
1821
2826
|
]
|
|
1822
2827
|
} : base;
|
|
1823
|
-
await
|
|
1824
|
-
const promptFile =
|
|
2828
|
+
await mkdir5(dir, { recursive: true });
|
|
2829
|
+
const promptFile = join5(dir, "prompt.md");
|
|
1825
2830
|
const self = reviewer ? void 0 : request.selfCheck;
|
|
1826
2831
|
const handoff = HandoffRuntime.promptFor(run, changesRelOf(this.h.root), runsRelOf(this.h.root)).replace(/\nWhen the file is complete.*\n$/s, "\n") + // W3a: the drafter checks its own file with the stage's checks before it finishes.
|
|
1827
2832
|
(self ? `
|
|
1828
2833
|
Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRel(run, changesRelOf(this.h.root), runsRelOf(this.h.root))}. Fix each problem it lists and run it again, until it says the file is clean (at most ${self.limit} times).
|
|
1829
2834
|
` : "");
|
|
1830
2835
|
const prompt = reviewer ? handoff.replace(`Write the result to ${HandoffRuntime.outputRel(run, changesRelOf(this.h.root), runsRelOf(this.h.root))}.`, `Write the result to ${request.outputPath}.${clones.length ? ` The metarepo is at ${this.h.root}: a folder named relative to the metarepo (the repos' clones under workspace/) is there, to read, never to edit.` : ""}`) : handoff;
|
|
1831
|
-
await
|
|
1832
|
-
await
|
|
1833
|
-
if (!await
|
|
2836
|
+
await writeFile5(promptFile, prompt, "utf8");
|
|
2837
|
+
await writeFile5(join5(dir, "context-manifest.json"), JSON.stringify(request.pack.manifest, null, 2) + "\n", "utf8");
|
|
2838
|
+
if (!await stat3(inv.cwd).catch(() => void 0))
|
|
1834
2839
|
throw new RuntimeError(`the worktree ${inv.cwd} doesn't exist`);
|
|
1835
|
-
const outputFile = work ?
|
|
2840
|
+
const outputFile = work ? join5(work, request.outputPath) : request.outputIn === "run" ? join5(dir, request.outputPath) : join5(changesDirOf(this.h.root), request.change, request.outputPath);
|
|
1836
2841
|
try {
|
|
1837
2842
|
return await this.runIn(run, dir, inv, prompt, promptFile, outputFile, signal);
|
|
1838
2843
|
} finally {
|
|
1839
2844
|
if (work) {
|
|
1840
|
-
const kept = await
|
|
2845
|
+
const kept = await readFile5(outputFile, "utf8").catch(() => void 0);
|
|
1841
2846
|
if (kept !== void 0) {
|
|
1842
|
-
await
|
|
1843
|
-
await
|
|
2847
|
+
await mkdir5(dirname2(join5(dir, request.outputPath)), { recursive: true });
|
|
2848
|
+
await writeFile5(join5(dir, request.outputPath), kept, "utf8");
|
|
1844
2849
|
}
|
|
1845
2850
|
await rm2(work, { recursive: true, force: true, maxRetries: 5 }).catch(() => void 0);
|
|
1846
2851
|
}
|
|
@@ -1848,7 +2853,7 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
|
|
|
1848
2853
|
}
|
|
1849
2854
|
async runIn(run, dir, inv, prompt, promptFile, outputFile, signal) {
|
|
1850
2855
|
const { request } = run;
|
|
1851
|
-
const before = (await
|
|
2856
|
+
const before = (await stat3(outputFile).catch(() => void 0))?.mtimeMs;
|
|
1852
2857
|
const res = await this.runner({
|
|
1853
2858
|
cwd: inv.cwd,
|
|
1854
2859
|
prompt,
|
|
@@ -1864,7 +2869,7 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
|
|
|
1864
2869
|
timeoutMs: this.h.timeoutMs ?? 30 * 6e4,
|
|
1865
2870
|
...signal ? { signal } : {}
|
|
1866
2871
|
});
|
|
1867
|
-
await
|
|
2872
|
+
await writeFile5(join5(dir, "claude-output.json"), res.stdout, "utf8");
|
|
1868
2873
|
let parsed;
|
|
1869
2874
|
try {
|
|
1870
2875
|
parsed = JSON.parse(res.stdout);
|
|
@@ -1874,8 +2879,8 @@ Before you finish, check the file: run ${self.command} ${HandoffRuntime.outputRe
|
|
|
1874
2879
|
const text = typeof parsed.result === "string" ? parsed.result : "";
|
|
1875
2880
|
if (res.exitCode !== 0 || parsed.is_error === true)
|
|
1876
2881
|
throw new RuntimeError(`Claude Code reported a failure: ${text || res.stderr.trim()}`);
|
|
1877
|
-
const after = (await
|
|
1878
|
-
const written = after !== void 0 && after !== before ? await
|
|
2882
|
+
const after = (await stat3(outputFile).catch(() => void 0))?.mtimeMs;
|
|
2883
|
+
const written = after !== void 0 && after !== before ? await readFile5(outputFile, "utf8") : void 0;
|
|
1879
2884
|
return {
|
|
1880
2885
|
output: written ?? text,
|
|
1881
2886
|
usage: {
|
|
@@ -1920,6 +2925,10 @@ var toolSource;
|
|
|
1920
2925
|
function registerToolSource(source) {
|
|
1921
2926
|
toolSource = source;
|
|
1922
2927
|
}
|
|
2928
|
+
var acpRunner;
|
|
2929
|
+
function registerCopilotAcp(o) {
|
|
2930
|
+
acpRunner = o;
|
|
2931
|
+
}
|
|
1923
2932
|
function classModels(rt, o) {
|
|
1924
2933
|
const by = modelsByClass(rt, o.env ?? {});
|
|
1925
2934
|
const out = {};
|
|
@@ -1941,17 +2950,19 @@ function classModels(rt, o) {
|
|
|
1941
2950
|
}
|
|
1942
2951
|
var told = /* @__PURE__ */ new WeakMap();
|
|
1943
2952
|
var nonEmpty = async (file, request) => {
|
|
1944
|
-
const text = await
|
|
2953
|
+
const text = await readFile5(file, "utf8").catch(() => "");
|
|
1945
2954
|
return text.trim() ? [] : [`${request.outputPath} is empty`];
|
|
1946
2955
|
};
|
|
1947
2956
|
async function createRuntime(orgPack, o) {
|
|
1948
2957
|
const rt = orgPack.runtime;
|
|
1949
|
-
const
|
|
2958
|
+
const asked = o.mode ?? rt.modes.default;
|
|
2959
|
+
const inSession = !!(o.env ?? process.env).ATTICUS_ACP_SESSION;
|
|
2960
|
+
const mode = asked === "copilot-acp" && inSession ? "hand-off" : asked;
|
|
1950
2961
|
if (!RUNTIME_MODES.includes(mode))
|
|
1951
2962
|
throw new RuntimeConfigError(`There is no AI mode called ${String(mode)}. Use one of: ${RUNTIME_MODES.join(", ")}.`);
|
|
1952
2963
|
if (rt.ai === "off" && CONFIGURED.includes(mode))
|
|
1953
2964
|
throw new AiOffError();
|
|
1954
|
-
if (CONFIGURED.includes(mode) && !rt.modes.allowed.includes(mode))
|
|
2965
|
+
if (CONFIGURED.includes(mode) && !rt.modes.allowed.includes(mode) && !(inSession && asked === "copilot-acp"))
|
|
1955
2966
|
throw new RuntimeConfigError(`runtime.yaml doesn't allow ${mode} mode (allowed: ${rt.modes.allowed.join(", ")}). Change modes.allowed in a pull request, or pick an allowed mode.`);
|
|
1956
2967
|
const one = { ...o.now ? { now: o.now } : {}, ...o.validate ? { validate: o.validate } : {} };
|
|
1957
2968
|
switch (mode) {
|
|
@@ -1999,6 +3010,22 @@ async function createRuntime(orgPack, o) {
|
|
|
1999
3010
|
...o.validate ? { validate: o.validate } : {}
|
|
2000
3011
|
});
|
|
2001
3012
|
}
|
|
3013
|
+
case "copilot-acp": {
|
|
3014
|
+
if (!rt.assistants.allowed.includes("copilot"))
|
|
3015
|
+
throw new RuntimeConfigError("copilot-acp drives GitHub Copilot, which runtime.yaml doesn't list under assistants.allowed.");
|
|
3016
|
+
const c = copilotAcpOf(rt);
|
|
3017
|
+
return new CopilotAcpRuntime({
|
|
3018
|
+
root: o.root,
|
|
3019
|
+
command: c.command,
|
|
3020
|
+
...c.model ? { model: c.model } : {},
|
|
3021
|
+
maxTurns: c.maxTurns,
|
|
3022
|
+
timeoutMs: c.timeoutMs,
|
|
3023
|
+
...acpRunner,
|
|
3024
|
+
...o.copilotAcp,
|
|
3025
|
+
...o.now ? { now: o.now } : {},
|
|
3026
|
+
...o.validate ? { validate: o.validate } : {}
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
2002
3029
|
case "replay":
|
|
2003
3030
|
if (o.recordings)
|
|
2004
3031
|
return new ReplayRuntime(o.recordings, one);
|
|
@@ -2015,13 +3042,13 @@ var sayOnce = (line) => process.stderr.write(`${line}
|
|
|
2015
3042
|
`);
|
|
2016
3043
|
async function runtimeForCli(root, o = {}) {
|
|
2017
3044
|
const env = o.env ?? process.env;
|
|
2018
|
-
const op = await loadOrgPack(
|
|
3045
|
+
const op = await loadOrgPack(join5(orgPackDirOf(root)));
|
|
2019
3046
|
const bad = op.problems.filter((p) => p.file === "runtime.yaml");
|
|
2020
3047
|
if (bad.length)
|
|
2021
3048
|
throw new RuntimeConfigError(`org-pack/runtime.yaml has problems: ${bad.map((p) => `${p.path ? `${p.path}: ` : ""}${p.message}`).join("; ")}`);
|
|
2022
3049
|
const asked = o.mode ?? env.ATTICUS_RUNTIME ?? op.runtime.modes.default;
|
|
2023
3050
|
if (asked === "mock")
|
|
2024
|
-
throw new RuntimeConfigError("Mock mode is for tests; use hand-off, model, headless-claude-code or replay.");
|
|
3051
|
+
throw new RuntimeConfigError("Mock mode is for tests; use hand-off, model, headless-claude-code, copilot-acp or replay.");
|
|
2025
3052
|
const mode = asked;
|
|
2026
3053
|
const runtime = await createRuntime(op, {
|
|
2027
3054
|
root,
|
|
@@ -2029,13 +3056,14 @@ async function runtimeForCli(root, o = {}) {
|
|
|
2029
3056
|
...env.ATTICUS_REPLAY_DIR ? { replayDir: env.ATTICUS_REPLAY_DIR } : {},
|
|
2030
3057
|
...o.providers ? { providers: o.providers } : {},
|
|
2031
3058
|
...o.headless ? { headless: o.headless } : {},
|
|
3059
|
+
...o.copilotAcp ? { copilotAcp: o.copilotAcp } : {},
|
|
2032
3060
|
...o.handoffValidate ? { handoffValidate: o.handoffValidate } : {},
|
|
2033
3061
|
// ADR 0121 addendum: the person's model per kind of step, and a model passed over said once.
|
|
2034
3062
|
env,
|
|
2035
3063
|
onNote: o.onNote ?? sayOnce
|
|
2036
3064
|
});
|
|
2037
|
-
const describe =
|
|
2038
|
-
return { runtime, mode, describe };
|
|
3065
|
+
const describe = runtime.kind === "hand-off" ? "AI steps are handed to your assistant: Atticus writes the prompt and waits for atticus handoff done." : mode === "model" ? `AI steps call the ${op.runtime.adapters.model?.type ?? "configured"} model directly.` : mode === "headless-claude-code" ? "AI steps run in headless Claude Code." : mode === "copilot-acp" ? "AI steps run in GitHub Copilot, unattended, one new session each (copilot-acp)." : "AI steps replay recorded answers.";
|
|
3066
|
+
return { runtime, mode: runtime.kind === "hand-off" ? "hand-off" : mode, describe };
|
|
2039
3067
|
}
|
|
2040
3068
|
|
|
2041
3069
|
// packages/ai/dist/attempts.js
|
|
@@ -2131,8 +3159,8 @@ var HashEmbedder = class {
|
|
|
2131
3159
|
return { i: h.readUInt32BE(0) % this.dim, sign: h[4] & 1 ? 1 : -1 };
|
|
2132
3160
|
};
|
|
2133
3161
|
for (const m of text.matchAll(/[A-Za-z0-9]+/g)) {
|
|
2134
|
-
const
|
|
2135
|
-
for (const w of new Set(
|
|
3162
|
+
const words2 = [m[0].toLowerCase(), ...identifierWords(m[0])];
|
|
3163
|
+
for (const w of new Set(words2)) {
|
|
2136
3164
|
if (w.length < 3)
|
|
2137
3165
|
continue;
|
|
2138
3166
|
const b = bucket(`w:${w}`);
|
|
@@ -2689,6 +3717,27 @@ export {
|
|
|
2689
3717
|
ModelRuntime,
|
|
2690
3718
|
HandoffRuntime,
|
|
2691
3719
|
pruneRuns,
|
|
3720
|
+
ACP_PROTOCOL_VERSION,
|
|
3721
|
+
ACP_METHODS,
|
|
3722
|
+
ACP_ERRORS,
|
|
3723
|
+
AcpRpcError,
|
|
3724
|
+
AcpClient,
|
|
3725
|
+
chunkText,
|
|
3726
|
+
UPDATE,
|
|
3727
|
+
usageOf,
|
|
3728
|
+
isAuthRequired,
|
|
3729
|
+
commandLineOf,
|
|
3730
|
+
atticusArgvOf,
|
|
3731
|
+
factsOnly,
|
|
3732
|
+
readRootsOf,
|
|
3733
|
+
spawnAcpServer,
|
|
3734
|
+
atticusExec,
|
|
3735
|
+
AcpSignInError,
|
|
3736
|
+
ACP_OFFERED,
|
|
3737
|
+
runAcpSession,
|
|
3738
|
+
copilotAcpProbe,
|
|
3739
|
+
CopilotAcpRuntime,
|
|
3740
|
+
keepAcpRun,
|
|
2692
3741
|
RUNTIME_MODES,
|
|
2693
3742
|
RuntimeConfigError,
|
|
2694
3743
|
AiOffError,
|
|
@@ -2703,6 +3752,7 @@ export {
|
|
|
2703
3752
|
registeredModelProviders,
|
|
2704
3753
|
clearModelProviders,
|
|
2705
3754
|
registerToolSource,
|
|
3755
|
+
registerCopilotAcp,
|
|
2706
3756
|
createRuntime,
|
|
2707
3757
|
runtimeForCli,
|
|
2708
3758
|
resumedAttempt,
|