nolo-cli 0.213.0 → 0.222.0-alpha.2
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 +3 -2
- package/{_executeModel-CUJLCFWR.js → _executeModel-4GGQQHOB.js} +111 -82
- package/{accountResolver-4LKIHEKL.js → accountResolver-EK2S4PWF.js} +6 -6
- package/{action-DF5UYSJF.js → action-CK64LS6S.js} +12 -11
- package/{addContentAction-WERAONNY.js → addContentAction-GDHDOF4U.js} +18 -17
- package/{addDialogAgentAction-7VI7YRML.js → addDialogAgentAction-CAKRU3ZT.js} +21 -20
- package/{agentDeleteCommand-XJORXPGU.js → agentDeleteCommand-BPV2XZL7.js} +128 -119
- package/{agentEmailCommands-XTYYFR6Z.js → agentEmailCommands-EJOS75YL.js} +132 -124
- package/{agentFavoriteCommands-EDK743YA.js → agentFavoriteCommands-2LKGKSUD.js} +7 -8
- package/{agentGrantCommands-RQWK2TEV.js → agentGrantCommands-QQV4N4JW.js} +5 -5
- package/{agentListCommands-OBLRBLHS.js → agentListCommands-HIZODBF3.js} +155 -92
- package/{agentMachineCommands-5FMT3OT5.js → agentMachineCommands-ZMQ2CY7Y.js} +62 -54
- package/{agentProviderCommands-Q5O33MED.js → agentProviderCommands-WKJOAWBP.js} +5 -5
- package/{agentPullCommand-6EM3URVK.js → agentPullCommand-XN6ZPBUW.js} +7 -7
- package/agentRecordCommands-OMXVDLDX.js +176 -0
- package/agentRunCommand-CB34YWMV.js +206 -0
- package/{agentRunControl-TAMHJQSR.js → agentRunControl-JNONH3RP.js} +30 -15
- package/{agentRuntimeLocal-SOO2OPJG.js → agentRuntimeLocal-QZPFWMLG.js} +52 -45
- package/{agentSlice-CHR6KOZN.js → agentSlice-RD2CDU7T.js} +20 -19
- package/{appDeleteCommands-GUP6P5YE.js → appDeleteCommands-QCCFDIEQ.js} +61 -53
- package/{appDeployCommands-MH2FX4O5.js → appDeployCommands-V2T7TNMQ.js} +61 -53
- package/{appDeployStatusCommands-SUHN3HPJ.js → appDeployStatusCommands-6PGH7ZCG.js} +61 -53
- package/{appGetCommands-YWDEX6Z4.js → appGetCommands-3L7WWJA6.js} +61 -53
- package/{appListCommands-ZQVMLPAY.js → appListCommands-ENJCK4PO.js} +61 -53
- package/{authCommand-PWX2ZNUP.js → authCommand-6V47SYGK.js} +29 -28
- package/{authCommands-HV3EAU3V.js → authCommands-GAJ3NIXO.js} +14 -13
- package/{builtinSkillRegistry-2QETTQPM.js → builtinSkillRegistry-2ECA42FC.js} +11 -13
- package/{chromeCommands-REEAH4SX.js → chromeCommands-G5UDKVSV.js} +3 -3
- package/{chromeOpsCommands-DIVM2K3T.js → chromeOpsCommands-YKX2QX3A.js} +20 -10
- package/{chunk-CRHOO2ZR.js → chunk-27PCUMJI.js} +2 -2
- package/chunk-2CI3ZFWD.js +97 -0
- package/{chunk-NSAPDIN2.js → chunk-2GJKRKI6.js} +541 -31
- package/{chunk-SM3NSZJV.js → chunk-2UCBGYO4.js} +20 -1
- package/{chunk-PYRUW7XN.js → chunk-2VUZSVAS.js} +136 -54
- package/{chunk-YB3YZK56.js → chunk-2WZXXAQD.js} +1 -67
- package/chunk-2YGBI2XB.js +30 -0
- package/chunk-2ZKFCIJJ.js +13 -0
- package/{chunk-QG4AOSON.js → chunk-34J5K2YA.js} +13 -32
- package/{chunk-LOEO7LRC.js → chunk-3IK6ILVW.js} +4 -1
- package/{chunk-CTPXME7U.js → chunk-3LMUPOHG.js} +29 -6
- package/chunk-44X52WOJ.js +1621 -0
- package/{chunk-6VLJ6YA7.js → chunk-4DESLZTK.js} +9 -9
- package/{chunk-MYOH447Z.js → chunk-4JVNURX4.js} +1 -1
- package/chunk-5CHGAKRT.js +364 -0
- package/{chunk-YDH3FDFQ.js → chunk-5FUN7EG4.js} +1 -1
- package/{chunk-INUFILG6.js → chunk-5RKUPJYL.js} +1 -1
- package/{chunk-ZC3CMUKU.js → chunk-6OVNSQHN.js} +84 -2
- package/{chunk-MOIJOHA5.js → chunk-6WU5572L.js} +36 -25
- package/{chunk-IXNGOHV5.js → chunk-7EEZJ6BS.js} +11 -152
- package/{chunk-Y6ORVLSS.js → chunk-7ET2U67U.js} +1 -1
- package/{chunk-G7MLNNEX.js → chunk-7JLY4WYF.js} +5 -5
- package/{chunk-P5L7CXOC.js → chunk-7Z6EW7AH.js} +3 -2
- package/{chunk-NJLL224W.js → chunk-AD5EWDFD.js} +2 -2
- package/{chunk-J2NHJ7WX.js → chunk-AIHYNKGV.js} +4 -4
- package/{chunk-HPFCI4SK.js → chunk-AK5O76CC.js} +3 -3
- package/{chunk-Y63ZSOR6.js → chunk-AL3TYDIF.js} +1 -1
- package/{chunk-ALQ3657A.js → chunk-AMEOV5VZ.js} +32 -12
- package/chunk-AN74ON4G.js +675 -0
- package/{chunk-HRMJUN5J.js → chunk-AQZ6BMRK.js} +1 -1
- package/{chunk-XHQC4PXX.js → chunk-B4GOW4MT.js} +424 -194
- package/{chunk-4KB6WQUL.js → chunk-BGP2EDFG.js} +1 -1
- package/{chunk-NBTY7YJF.js → chunk-BR3GT6MR.js} +1 -0
- package/{chunk-7RFNTILS.js → chunk-BUDVRYES.js} +2 -2
- package/{chunk-SVYO6AO7.js → chunk-BV3FLP2L.js} +41 -1
- package/{chunk-RZOV7OMV.js → chunk-C4VAR65S.js} +83 -141
- package/{chunk-COFEN36Z.js → chunk-C4WTX5TU.js} +2 -2
- package/{chunk-ZL5RAEEB.js → chunk-CIRB724Q.js} +1 -1
- package/{chunk-F6UUQOG6.js → chunk-CKT6QUE2.js} +4 -4
- package/{chunk-X7SDOJUM.js → chunk-CMZ3Z5PT.js} +14 -14
- package/{secretCommands-LXDWOLZ6.js → chunk-D726I5AZ.js} +191 -16
- package/{chunk-TAKB25RM.js → chunk-DNKTQ3IN.js} +4 -4
- package/chunk-DVQH4BTR.js +1137 -0
- package/{chunk-WYDI6TGM.js → chunk-DWX2HEVC.js} +91 -132
- package/{chunk-5MQRBSMW.js → chunk-EIAI3PPH.js} +111 -113
- package/chunk-EUCFKKDM.js +247 -0
- package/chunk-EWQ3HGNZ.js +90 -0
- package/{chunk-RPQXPZZF.js → chunk-F3GRJO4Z.js} +908 -13
- package/{chunk-YTF4WH7J.js → chunk-FIYSMXHY.js} +1 -1
- package/{chunk-75XIDFBW.js → chunk-FJ23FZXF.js} +72 -28
- package/{chunk-INN4LTAJ.js → chunk-FJK526XH.js} +2 -2
- package/chunk-FS2XP5D7.js +142 -0
- package/{chunk-FUGMREBO.js → chunk-FYF2TONJ.js} +5 -5
- package/{chunk-PCLE46CE.js → chunk-GBWGPTA7.js} +2 -1
- package/{chunk-TX5EYMGT.js → chunk-GYVCJABP.js} +30 -254
- package/{chunk-3UKL3HPD.js → chunk-HOCHUZQ7.js} +8 -78
- package/{chunk-EHSZD5OI.js → chunk-HXER7YJF.js} +4 -4
- package/chunk-HYIETXA6.js +99 -0
- package/{chunk-H2TJUNCH.js → chunk-I4EADJ4P.js} +6 -6
- package/{chunk-TCZHTTUU.js → chunk-I7WBYGBP.js} +8 -8
- package/{chunk-6DWMYIUY.js → chunk-IILMY4W4.js} +14 -9
- package/chunk-JA3ICVJY.js +271 -0
- package/{chunk-ZRSNONOB.js → chunk-JWXITTQB.js} +8 -3
- package/{chunk-H4UOTUOX.js → chunk-KEN3N2TN.js} +148 -18
- package/{chunk-LEC5ALIN.js → chunk-KEPOVMF4.js} +1 -1
- package/{chunk-UHJGXRJ4.js → chunk-KQSYAIZR.js} +3 -3
- package/{chunk-4VJAC32I.js → chunk-L5I543VB.js} +3 -2
- package/chunk-LKA64WH4.js +227 -0
- package/{chunk-QHPRUL4O.js → chunk-LVL6GFCM.js} +4 -4
- package/{chunk-H5HF7TJA.js → chunk-MAIITKBT.js} +2 -2
- package/chunk-MBG66ZBH.js +226 -0
- package/{chunk-YUA6OAH5.js → chunk-MDLS23JK.js} +2 -2
- package/{chunk-VL5KOY2C.js → chunk-MK2Q7ZJD.js} +67 -5
- package/{chunk-MDB67IWP.js → chunk-MS4NZNKI.js} +10 -10
- package/{chunk-VO4WSAVP.js → chunk-MYHNBEXD.js} +3 -3
- package/{chunk-ZXOUUDCG.js → chunk-MZLE5HQ3.js} +3654 -231
- package/{chunk-AZMYUSVF.js → chunk-N5Z2V73W.js} +1 -1
- package/{chunk-V5Y3R6BT.js → chunk-NIZ2BXFD.js} +213 -210
- package/{chunk-KFLT5KAD.js → chunk-NWP2OYOX.js} +20 -20
- package/{chunk-G2BQWAVT.js → chunk-O6J3OTOP.js} +4 -4
- package/{chunk-VNYYOX3V.js → chunk-OB6DVWPF.js} +141 -48
- package/{chunk-YWSEPJ7C.js → chunk-OBWT45ZU.js} +3 -3
- package/{chunk-ZNWI6OVT.js → chunk-ODJ7BVSI.js} +80 -11
- package/{chunk-XJWWBO34.js → chunk-OJKUU3LP.js} +5 -7
- package/{chunk-HUBHAQK2.js → chunk-ON37YXGX.js} +29 -29
- package/{chunk-UYD5HQ6T.js → chunk-P5ZJRTCH.js} +5429 -1752
- package/{chunk-6XIE5ZGI.js → chunk-PDCV7P5W.js} +1 -1
- package/{chunk-WRYQ35LQ.js → chunk-PJCIP64Z.js} +859 -57
- package/{chunk-7QTZCMKL.js → chunk-PJVKMGPZ.js} +1089 -1639
- package/{chunk-A7TFUNZO.js → chunk-PPJYZRSQ.js} +6 -2
- package/chunk-QHEN7NZ7.js +46 -0
- package/{chunk-OQPKUBPB.js → chunk-QNWG52I4.js} +19 -7
- package/{chunk-YGILMZ7N.js → chunk-QVBXJNZ2.js} +1 -1
- package/{chunk-7BT37FK3.js → chunk-RDH5CQ4T.js} +648 -131
- package/{chunk-C6KNNXWU.js → chunk-RGQ4UUWZ.js} +25 -2
- package/{chunk-OWYYDMGJ.js → chunk-S2NTVGA2.js} +4 -2
- package/{chunk-KC4XDTT3.js → chunk-SOF4OWDM.js} +6 -4
- package/{chunk-RLBNLZVC.js → chunk-SQYIK6HO.js} +1 -1
- package/{chunk-YJAFKXMU.js → chunk-SVT62ULE.js} +50 -48
- package/{chunk-KIM6CLW5.js → chunk-SY3C4SQ7.js} +42 -15
- package/{chunk-JY5NGFFH.js → chunk-SYTHYBMI.js} +5 -5
- package/{chunk-WMTBPBMP.js → chunk-T6DXNI6Z.js} +52 -50
- package/chunk-TLE77UJ5.js +230 -0
- package/{chunk-4VNS5WPM.js → chunk-U67V476Y.js} +1 -8
- package/{chunk-F7CI2ZC5.js → chunk-UAIHKQIA.js} +2 -1
- package/{chunk-R5O4QAWG.js → chunk-UB3D4TRQ.js} +11 -77
- package/{chunk-WPORQFYN.js → chunk-UVLYNWIE.js} +2 -2
- package/{chunk-NOKUNJON.js → chunk-UYOICCYG.js} +29 -19
- package/{chunk-4I7ERB7F.js → chunk-VREDDN25.js} +1 -1
- package/{chunk-O2TZF4AI.js → chunk-WAE3GFCJ.js} +3 -3
- package/{chunk-H7PPIYWP.js → chunk-WI67URFP.js} +20 -20
- package/{chunk-7OCO4TDT.js → chunk-WJVYAO6P.js} +1 -1
- package/{chunk-T43B7LB2.js → chunk-WKGQSYTB.js} +1 -1
- package/{chunk-BBJ22CLB.js → chunk-WUUH4LWZ.js} +60 -30
- package/{chunk-4T2WNOY7.js → chunk-X7UF53VA.js} +33 -22
- package/{chunk-TY3TIUJK.js → chunk-XI2BWJM5.js} +65 -0
- package/{chunk-LLRPJECG.js → chunk-XWVCYUUU.js} +16 -159
- package/{chunk-J5JTMQIA.js → chunk-YFLVRVYK.js} +1 -1
- package/{chunk-EYLGAEB4.js → chunk-YGMBIXCF.js} +132 -0
- package/chunk-YL3EFYL3.js +199 -0
- package/{chunk-MMA3LZ3W.js → chunk-YNIYE47Z.js} +1 -1
- package/{chunk-W4S457LU.js → chunk-YU4ZPWVF.js} +41 -5
- package/{chunk-7Y4YTDQF.js → chunk-YWWDC3O7.js} +281 -159
- package/chunk-YZMNK53S.js +68 -0
- package/{chunk-RSHTSUEG.js → chunk-Z2PITYZN.js} +2060 -602
- package/{chunk-FY7F4Q6X.js → chunk-Z4PCXPUE.js} +2 -2
- package/{cliAgentConfigHelpers-WJBZQTLW.js → cliAgentConfigHelpers-TKYL43MT.js} +15 -16
- package/{cliAuthorityBrokerClient-PM3U6Q6J.js → cliAuthorityBrokerClient-XHH7MH2P.js} +1 -1
- package/{cliAuthorityStoreDriver-TKLXNNTG.js → cliAuthorityStoreDriver-6FE3BJNB.js} +1 -1
- package/{cliEnvHelpers-BVYTMUPJ.js → cliEnvHelpers-VPSJ4XWC.js} +3 -3
- package/{cliExecutor-BWBF2MTI.js → cliExecutor-4MAX3PZL.js} +2 -2
- package/cliLocalAgentRecordReader-MHHD4T7R.js +90 -0
- package/{commandRegistry-W63CYRZJ.js → commandRegistry-5DA5UP7S.js} +105 -97
- package/{contentThunks-U7PL5MQD.js → contentThunks-5GUQ7FWJ.js} +47 -43
- package/{cooldownCommands-TIGUHXTD.js → cooldownCommands-X7P5M2V5.js} +5 -4
- package/{createAgentAutomationAction-OLBQDD6R.js → createAgentAutomationAction-UCLTHQRI.js} +51 -49
- package/{createDialogAction-SVH6B3SB.js → createDialogAction-UPN774AF.js} +46 -48
- package/{createPageAction-F4DIWZ2Z.js → createPageAction-JRQ2TA4O.js} +50 -48
- package/{cursorProvider-YGGNMVWX.js → cursorProvider-2RACMEMF.js} +1 -1
- package/{db-HUCI5R4G.js → db-CS4ZJQKV.js} +1 -1
- package/{dbSlice-BVH2YZPQ.js → dbSlice-WNON7TOL.js} +17 -16
- package/{deleteFile-5YOEKV4U.js → deleteFile-Q3YDB4ML.js} +9 -9
- package/{desktopFolderProjects-SFY5EZS3.js → desktopFolderProjects-4POAMVJN.js} +2 -2
- package/{dialogCommands-KHIEPY3M.js → dialogCommands-VRI7VCXH.js} +64 -57
- package/dialogNotifyCommand-6TMCX4D2.js +36 -0
- package/{dialogSlice-ZCTDV2PZ.js → dialogSlice-LFNVUSAN.js} +42 -40
- package/{dialogUsageCommand-7KCPYGHG.js → dialogUsageCommand-HTVPR2CX.js} +11 -10
- package/{docCreateCommands-DPMZI7G5.js → docCreateCommands-AMPXMOX3.js} +61 -55
- package/{docDeleteCommands-IRQQLUBT.js → docDeleteCommands-I5WFAEHP.js} +63 -57
- package/{docReadCommands-LK37XH6L.js → docReadCommands-X53ELNIE.js} +61 -55
- package/{docStore-V2KECILA.js → docStore-2VAWVLWH.js} +21 -20
- package/{docUpdateCommands-O6T3HJHH.js → docUpdateCommands-6QPNDC7M.js} +64 -58
- package/{fetchMessages-NR4KNQLO.js → fetchMessages-TQEUZD7H.js} +8 -7
- package/{getPricing-2MNMXEVG.js → getPricing-MB2GBXOK.js} +6 -6
- package/{handleSendMessageAction-2PE25WM3.js → handleSendMessageAction-AAJOHXOB.js} +194 -302
- package/{hostCredentialCreate-S233UMAP.js → hostCredentialCreate-GLMJ22M6.js} +123 -114
- package/index.js +29 -29
- package/{keys-BEGDOTRL.js → keys-RWF7UCB4.js} +5 -4
- package/legacyMigration-TF4SYJCZ.js +19 -0
- package/{lib-5KKIBFIT.js → lib-OT5OTXRU.js} +7087 -6664
- package/{localDialogRead-7NNDVVF7.js → localDialogRead-SVTPA5GY.js} +3 -3
- package/{localFirstLog-DHNOY2NA.js → localFirstLog-OIETGK66.js} +1 -1
- package/localRecall-2J6QPOK2.js +15 -0
- package/{localRuntimeAdapter-KY6WXNBR.js → localRuntimeAdapter-BMP57P42.js} +119 -110
- package/{localRuntimeAuthority-OYH4AE4G.js → localRuntimeAuthority-IBJAT62G.js} +1 -1
- package/{localRuntimeDb-VBIMCWUC.js → localRuntimeDb-N7KHDXS2.js} +2 -2
- package/{machineCommands-Q6HA3IXF.js → machineCommands-3MLIAK5Q.js} +128 -119
- package/{machineInfo-UKPTZO5Y.js → machineInfo-LWHTEBHJ.js} +1 -1
- package/machineWsRunDispatch-FKIGROQF.js +191 -0
- package/{memberThunks-7EDJADWU.js → memberThunks-ZGLZ36PK.js} +29 -28
- package/{memoryCommands-ASCE5STX.js → memoryCommands-5WC3T66U.js} +4 -4
- package/models-ULVWLSQ6.js +9 -0
- package/{oauthTokenStore-OEERZFUC.js → oauthTokenStore-RUYNYALS.js} +1 -1
- package/{offlineMarxistsAgentCommand-2QTHJCHV.js → offlineMarxistsAgentCommand-4IC3Y4C6.js} +4 -4
- package/overlay-THLKYIWY.js +11 -0
- package/package.json +2 -2
- package/{pdf-U6KSUEZZ.js → pdf-KE3QI2V7.js} +1 -1
- package/{processSpawn-ZU5QFM43.js → processSpawn-6GEO77KV.js} +1 -1
- package/{profileConfig-KN3N2BLF.js → profileConfig-KOWK4HOG.js} +1 -1
- package/{projectArchive-DRTDIMEV.js → projectArchive-HK63GMF4.js} +52 -50
- package/{providerPresetApply-YXGV6NXB.js → providerPresetApply-OIFQ73LH.js} +19 -12
- package/{providerRegistry-S6UL6UNA.js → providerRegistry-KZ3SDZ3D.js} +10 -10
- package/{read-4V2RMG7N.js → read-MRQHJMJ2.js} +10 -10
- package/{readDocTool-BH6ATGQO.js → readDocTool-4BGTXTXA.js} +2 -2
- package/{readlineWorkspace-2W4WRCOU.js → readlineWorkspace-AKAHSCNY.js} +7982 -6274
- package/{removeDialogAgentAction-LYAZGNKW.js → removeDialogAgentAction-B6H7DXFM.js} +23 -22
- package/{runAgentClientLoop-J2VQBS2Z.js → runAgentClientLoop-UVAWGEON.js} +81 -79
- package/{runtimeDoctorCommands-QAI3MBKQ.js → runtimeDoctorCommands-FW6XKDUG.js} +12 -12
- package/{runtimeModeArgs-2Y7BALTO.js → runtimeModeArgs-X7DL7PUN.js} +1 -1
- package/secretCommands-LJXOOYA7.js +24 -0
- package/{setDialogExtraReferencesAction-OCRPGPYH.js → setDialogExtraReferencesAction-EVCY3TRW.js} +22 -21
- package/{setPrimaryDialogAgentAction-HFJDQIBU.js → setPrimaryDialogAgentAction-KPFVPHCJ.js} +23 -22
- package/{settingThunks-RAMHMTGM.js → settingThunks-ENOAK2WV.js} +97 -88
- package/{skillDiscovery-XKHROSH2.js → skillDiscovery-B5V23AXP.js} +4 -4
- package/{skillSummaryMarker-42HKSXYY.js → skillSummaryMarker-62UW7HI7.js} +1 -1
- package/{slateToRenderMarkdown-Y5IYN73U.js → slateToRenderMarkdown-R3X74MCX.js} +1 -1
- package/{slateUtils-NGV2NMKM.js → slateUtils-ESQAJ6RN.js} +1 -1
- package/{spaceCommands-KVJZVKVO.js → spaceCommands-DTTNAS2L.js} +61 -53
- package/store-JRVN62NM.js +46 -0
- package/{streamAgentChatTurn-GHBMJJ6S.js → streamAgentChatTurn-R5UY25VB.js} +875 -618
- package/{switchDialogAgentAction-EBRMW3RA.js → switchDialogAgentAction-SZ44XDRY.js} +21 -20
- package/{tableCommands-MP6VFSVT.js → tableCommands-HITDSLHS.js} +10 -10
- package/tombstones-FQQMEDOW.js +32 -0
- package/{toolApiClient-HGNO53TC.js → toolApiClient-OGQEBQVX.js} +4 -4
- package/{tools-EWKCPKMS.js → tools-HWFG6GMJ.js} +75 -74
- package/tuiSummaryLlmCaller-HQQZAMYF.js +44 -0
- package/{updateCommands-ZQYU6SCI.js → updateCommands-RJVCRSBP.js} +10 -8
- package/{updateDialogTitleAction-5GGMBTDF.js → updateDialogTitleAction-KNPOAMVS.js} +48 -46
- package/{usageCommand-F4IPVMIZ.js → usageCommand-FWZCB7AM.js} +11 -10
- package/{usageRebuildCommand-HAW2AD5N.js → usageRebuildCommand-SP2BLNJU.js} +12 -11
- package/userDataMerge-HT2ZVHBJ.js +13 -0
- package/{windowsSelfUpdate-257DV2T6.js → windowsSelfUpdate-KERHIAB4.js} +3 -3
- package/{workloadLifecycle-4C42SVBD.js → workloadLifecycle-DYNEYHV5.js} +6 -6
- package/agentRecordCommands-ZQ7SVYGG.js +0 -167
- package/agentRunCommand-WS7IGO2W.js +0 -196
- package/chunk-3CGG2PAL.js +0 -594
- package/chunk-5XBUWM6I.js +0 -89
- package/chunk-CJEIOP3E.js +0 -0
- package/chunk-EHGEOAHI.js +0 -636
- package/chunk-FW6YHHLI.js +0 -842
- package/chunk-GPVRUGGY.js +0 -115
- package/chunk-HSVBJRF4.js +0 -339
- package/chunk-WJZOQR2J.js +0 -151
- package/chunk-ZCWRMUWT.js +0 -89
- package/dist-M676ULYG.js +0 -7314
- package/machineWsRunDispatch-WWJQ6WR3.js +0 -182
- package/models-PJBE6JDV.js +0 -9
- package/tuiSummaryLlmCaller-ALQYUUWB.js +0 -189
- package/{chunk-WACI5I6V.js → chunk-2THCNKE4.js} +3 -3
- package/{chunk-2QHFH3DR.js → chunk-47ITIXO7.js} +6 -6
- package/{chunk-GOO6G4PY.js → chunk-CKG3PRZ7.js} +0 -0
- package/{chunk-OQHIVPG4.js → chunk-SNBZZPYH.js} +3 -3
- package/{chunk-AETZ7AD6.js → chunk-W6RFEDN4.js} +3 -3
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveRuntimeAuthToken,
|
|
3
3
|
resolveRuntimeServerUrl
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AQZ6BMRK.js";
|
|
5
5
|
import {
|
|
6
6
|
isAgentRunTerminalStatus,
|
|
7
|
-
normalizeRunTitle
|
|
8
|
-
|
|
7
|
+
normalizeRunTitle,
|
|
8
|
+
shortAgentKey
|
|
9
|
+
} from "./chunk-AMEOV5VZ.js";
|
|
9
10
|
import {
|
|
10
11
|
findPowerShellExecutable
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KEN3N2TN.js";
|
|
13
|
+
import {
|
|
14
|
+
AUTH_ERROR_PATTERNS
|
|
15
|
+
} from "./chunk-EWQ3HGNZ.js";
|
|
12
16
|
import {
|
|
13
17
|
isRecord
|
|
14
18
|
} from "./chunk-KUG52IAP.js";
|
|
15
19
|
import {
|
|
16
20
|
isCompiledBinary,
|
|
17
21
|
resolveCliEntrypointPath
|
|
18
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2THCNKE4.js";
|
|
19
23
|
|
|
20
24
|
// packages/cli/client/originShellApprovalTransport.ts
|
|
21
25
|
import { realpathSync } from "node:fs";
|
|
@@ -444,9 +448,10 @@ function redactLogLines(lines, options = {}) {
|
|
|
444
448
|
}
|
|
445
449
|
|
|
446
450
|
// packages/cli/agentRunControl.ts
|
|
447
|
-
import { homedir as nodeHomedir } from "node:os";
|
|
451
|
+
import { hostname as nodeHostname, homedir as nodeHomedir } from "node:os";
|
|
448
452
|
import { dirname, isAbsolute as isAbsolute2, join as join2, resolve } from "node:path";
|
|
449
453
|
import * as nodeFs2 from "node:fs";
|
|
454
|
+
import { randomUUID as randomUUID2, createHash } from "node:crypto";
|
|
450
455
|
import { execFileSync as nodeExecFileSync, spawn as nodeSpawn } from "node:child_process";
|
|
451
456
|
|
|
452
457
|
// packages/cli/client/hostMemory.ts
|
|
@@ -1090,6 +1095,7 @@ function resolveResultServerMeta(input) {
|
|
|
1090
1095
|
var resultHeaderMeta = /* @__PURE__ */ new WeakMap();
|
|
1091
1096
|
function recordRunResultHeaderMeta(result, meta) {
|
|
1092
1097
|
const clean = {};
|
|
1098
|
+
if (meta.commandObservations?.length) clean.commandObservations = meta.commandObservations;
|
|
1093
1099
|
if (meta.model) clean.model = meta.model;
|
|
1094
1100
|
if (meta.dialogServer) clean.dialogServer = meta.dialogServer;
|
|
1095
1101
|
if (meta.serverSync) clean.serverSync = meta.serverSync;
|
|
@@ -1134,7 +1140,8 @@ function buildResultFrontMatter(input) {
|
|
|
1134
1140
|
["server", input.server],
|
|
1135
1141
|
["serverSync", input.serverSync],
|
|
1136
1142
|
["cwd", input.cwd],
|
|
1137
|
-
["continuedFrom", input.continuedFrom]
|
|
1143
|
+
["continuedFrom", input.continuedFrom],
|
|
1144
|
+
["acceptance", input.acceptance ? JSON.stringify(input.acceptance) : void 0]
|
|
1138
1145
|
];
|
|
1139
1146
|
const lines = entries.filter(([, v]) => v !== void 0 && v !== "").map(([k, v]) => `${k}: ${yamlScalar(v)}`);
|
|
1140
1147
|
return `---
|
|
@@ -1145,9 +1152,18 @@ ${lines.join("\n")}
|
|
|
1145
1152
|
function buildResultFileContent(input, body) {
|
|
1146
1153
|
return `${buildResultFrontMatter(input)}${body}`;
|
|
1147
1154
|
}
|
|
1155
|
+
var RESULT_FRONT_MATTER_RE = /^---\nrunId: [^\n]*\n(?:[^\n]*\n)*?---\n/;
|
|
1156
|
+
function stripResultFrontMatter(text) {
|
|
1157
|
+
const match = RESULT_FRONT_MATTER_RE.exec(text);
|
|
1158
|
+
return match ? text.slice(match[0].length) : text;
|
|
1159
|
+
}
|
|
1148
1160
|
|
|
1149
1161
|
// packages/ai/tools/agent/runFailureClass.ts
|
|
1150
|
-
|
|
1162
|
+
function isHistoryIntegrityFailure(message) {
|
|
1163
|
+
return /^Strict continuation history load failed for [^\r\n]+:/i.test(message.trim());
|
|
1164
|
+
}
|
|
1165
|
+
var BALANCE_PATTERN = /\bUPSTREAM_402\b|\b402\b|insufficient[_\s-]+balance|余额不足|wallet\s+balance\s+is\s+insufficient|top\s+up\s+your\s+wallet|payment[_ ]required/i;
|
|
1166
|
+
var RATE_LIMIT_PATTERN = /429|rate.?limit|quota|cooling|冷却/i;
|
|
1151
1167
|
var PROVIDER_ERROR_PATTERN = /provider|upstream|5\d\d|bad.?gateway|service.?unavailable|overloaded/i;
|
|
1152
1168
|
var MALFORMED_PATTERN = /MALFORMED_FUNCTION_CALL|malformed|invalid.?function.?call|invalid.?tool.?call/i;
|
|
1153
1169
|
var STALLED_PATTERN = /stall|no.?progress|repetition|stagnant|无进展|卡死/i;
|
|
@@ -1159,6 +1175,20 @@ function classifyRunFailure(input) {
|
|
|
1159
1175
|
}
|
|
1160
1176
|
const reason = typeof input.failureReason === "string" ? input.failureReason : "";
|
|
1161
1177
|
const message = typeof input.errorMessage === "string" ? input.errorMessage : "";
|
|
1178
|
+
if (reason === "history_integrity" || isHistoryIntegrityFailure(message)) {
|
|
1179
|
+
return { failureClass: "history_integrity", retryable: false };
|
|
1180
|
+
}
|
|
1181
|
+
if (!reason || reason === "provider_rate_limited" || reason === "provider_error") {
|
|
1182
|
+
if (BALANCE_PATTERN.test(message)) {
|
|
1183
|
+
return { failureClass: "balance_exhausted", retryable: false };
|
|
1184
|
+
}
|
|
1185
|
+
if (AUTH_ERROR_PATTERNS.some((pattern) => pattern.test(message))) {
|
|
1186
|
+
return { failureClass: "auth", retryable: false };
|
|
1187
|
+
}
|
|
1188
|
+
if (reason === "provider_error" && RATE_LIMIT_PATTERN.test(message)) {
|
|
1189
|
+
return { failureClass: "rate_limited", retryable: true };
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1162
1192
|
switch (reason) {
|
|
1163
1193
|
case "provider_rate_limited":
|
|
1164
1194
|
return { failureClass: "rate_limited", retryable: true };
|
|
@@ -1552,7 +1582,9 @@ function withRunRecordLock(runId, deps, fn, opts = {}) {
|
|
|
1552
1582
|
try {
|
|
1553
1583
|
const stat = fs.statSync?.(lockPath);
|
|
1554
1584
|
const ageMs = stat ? now().getTime() - stat.mtimeMs : Number.POSITIVE_INFINITY;
|
|
1555
|
-
|
|
1585
|
+
const ownerPid = opts.requireDeadOwner ? Number(String(fs.readFileSync(lockPath, "utf8"))) : void 0;
|
|
1586
|
+
const ownerGone = !opts.requireDeadOwner || Number.isSafeInteger(ownerPid) && ownerPid > 0 && isPidGone(ownerPid, deps);
|
|
1587
|
+
if (ageMs > LOCK_STALE_MS && ownerGone) {
|
|
1556
1588
|
fs.unlinkSync(lockPath);
|
|
1557
1589
|
fs.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
1558
1590
|
held = true;
|
|
@@ -1582,13 +1614,15 @@ function writeRunRecord(record, deps = {}) {
|
|
|
1582
1614
|
fs.writeFileSync(tmp, payload);
|
|
1583
1615
|
fs.renameSync(tmp, path);
|
|
1584
1616
|
return;
|
|
1585
|
-
} catch {
|
|
1617
|
+
} catch (error) {
|
|
1586
1618
|
try {
|
|
1587
1619
|
fs.unlinkSync(tmp);
|
|
1588
1620
|
} catch {
|
|
1589
1621
|
}
|
|
1622
|
+
if (record.writerLaunch) throw error;
|
|
1590
1623
|
}
|
|
1591
1624
|
}
|
|
1625
|
+
if (record.writerLaunch) throw new Error("[local-writer-resource] fenced launch requires atomic rename");
|
|
1592
1626
|
fs.writeFileSync(path, payload);
|
|
1593
1627
|
}
|
|
1594
1628
|
function reportRunProcessIdentity(runId, deps = {}) {
|
|
@@ -2054,9 +2088,18 @@ async function gcRunRecords(deps = {}, options = {}) {
|
|
|
2054
2088
|
const failedIds = [];
|
|
2055
2089
|
for (const record of records) {
|
|
2056
2090
|
if (!isRunTerminalStatus(record.status)) continue;
|
|
2091
|
+
if (localWriterStillOwns(record, deps)) continue;
|
|
2092
|
+
if (!/^[A-Za-z0-9._-]{1,128}$/.test(record.runId) || record.runId === "." || record.runId === "..") {
|
|
2093
|
+
failedIds.push(record.runId);
|
|
2094
|
+
continue;
|
|
2095
|
+
}
|
|
2057
2096
|
const ts = record.reconciledAt ?? record.endedAt ?? record.startedAt;
|
|
2058
2097
|
const ageMs = nowMs - new Date(ts).getTime();
|
|
2059
2098
|
if (!Number.isFinite(ageMs) || ageMs < retentionMs) continue;
|
|
2099
|
+
if (fs.existsSync(`${resolveRunRecordPath(record.runId, deps.env, deps.homedir)}.lock`)) {
|
|
2100
|
+
failedIds.push(record.runId);
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2060
2103
|
const jsonPath = resolveRunRecordPath(record.runId, deps.env, deps.homedir);
|
|
2061
2104
|
const logPath = resolveRunLogPath(record.runId, deps.env, deps.homedir);
|
|
2062
2105
|
const queuePath = record.queuePath ?? resolveRunQueuePath(record.runId, deps.env, deps.homedir);
|
|
@@ -2076,8 +2119,30 @@ async function gcRunRecords(deps = {}, options = {}) {
|
|
|
2076
2119
|
const runsDirForLegacy = resolveRunsDir(deps.env, deps.homedir);
|
|
2077
2120
|
tryUnlinkFile(fs, join2(runsDirForLegacy, `${record.runId}.report.md`));
|
|
2078
2121
|
tryUnlinkFile(fs, join2(runsDirForLegacy, `${record.runId}.report.json`));
|
|
2079
|
-
|
|
2080
|
-
|
|
2122
|
+
let resultOk = false;
|
|
2123
|
+
let artifactsOk = true;
|
|
2124
|
+
const artifactSweep = withRunRecordLock(record.runId, deps, () => {
|
|
2125
|
+
resultOk = tryUnlinkFile(fs, join2(runsDirForLegacy, `${record.runId}.result.md`));
|
|
2126
|
+
for (const artifact of record.resultArtifacts ?? []) {
|
|
2127
|
+
try {
|
|
2128
|
+
const prefix = `${record.runId}.result.md.`;
|
|
2129
|
+
const name = artifact.path.slice(join2(runsDirForLegacy, prefix).length);
|
|
2130
|
+
const uuid = "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}";
|
|
2131
|
+
if (artifact.publisher !== "run-result-v1" || !/^[A-Za-z0-9._-]+$/.test(record.runId) || !["pending", "bak"].includes(artifact.kind) || !new RegExp(`^${uuid}\\.${artifact.kind}$`).test(name) || artifact.path !== join2(runsDirForLegacy, prefix + name)) throw new Error("unsafe artifact ownership");
|
|
2132
|
+
if (!fs.existsSync(artifact.path)) continue;
|
|
2133
|
+
const stat = fs.lstatSync?.(artifact.path);
|
|
2134
|
+
if (!stat || !stat.isFile() || stat.isSymbolicLink() || fs.realpathSync?.(artifact.path) !== resolve(artifact.path) || String(stat.dev) !== artifact.dev || String(stat.ino) !== artifact.ino || createHash("sha256").update(fs.readFileSync(artifact.path)).digest("hex") !== artifact.sha256) {
|
|
2135
|
+
throw new Error("artifact identity changed");
|
|
2136
|
+
}
|
|
2137
|
+
if (!tryUnlinkFile(fs, artifact.path)) artifactsOk = false;
|
|
2138
|
+
} catch {
|
|
2139
|
+
artifactsOk = false;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return true;
|
|
2143
|
+
}, { strict: true });
|
|
2144
|
+
if (!artifactSweep) artifactsOk = false;
|
|
2145
|
+
if (!logOk || !msgOk || !queueOk || !resultOk || !artifactsOk) {
|
|
2081
2146
|
failedIds.push(record.runId);
|
|
2082
2147
|
continue;
|
|
2083
2148
|
}
|
|
@@ -2090,12 +2155,12 @@ async function gcRunRecords(deps = {}, options = {}) {
|
|
|
2090
2155
|
}
|
|
2091
2156
|
try {
|
|
2092
2157
|
const dir = resolveRunsDir(deps.env, deps.homedir);
|
|
2093
|
-
const
|
|
2158
|
+
const statSync2 = fs.statSync;
|
|
2094
2159
|
for (const entry of fs.readdirSync(dir)) {
|
|
2095
2160
|
if (typeof entry !== "string" || !entry.endsWith(".tmp")) continue;
|
|
2096
2161
|
const tmpPath = join2(dir, entry);
|
|
2097
2162
|
try {
|
|
2098
|
-
const stat =
|
|
2163
|
+
const stat = statSync2?.(tmpPath);
|
|
2099
2164
|
if (stat && nowMs - stat.mtimeMs <= TMP_STALE_MS) continue;
|
|
2100
2165
|
} catch {
|
|
2101
2166
|
continue;
|
|
@@ -2210,6 +2275,270 @@ function emitHostMemoryNotice(mem, output) {
|
|
|
2210
2275
|
}
|
|
2211
2276
|
return notice;
|
|
2212
2277
|
}
|
|
2278
|
+
function trustedLocalWorktree(cwd, deps) {
|
|
2279
|
+
const fs = deps.fs ?? nodeFs2;
|
|
2280
|
+
try {
|
|
2281
|
+
const env = { ...process.env, ...deps.env };
|
|
2282
|
+
for (const key of Object.keys(env)) if (key.startsWith("GIT_")) delete env[key];
|
|
2283
|
+
const exec = deps.execFileSync ?? nodeExecFileSync;
|
|
2284
|
+
const git = (args) => exec("git", args, {
|
|
2285
|
+
cwd,
|
|
2286
|
+
env,
|
|
2287
|
+
encoding: "utf8",
|
|
2288
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2289
|
+
timeout: 3e3
|
|
2290
|
+
}).trim();
|
|
2291
|
+
const real = (path) => String((fs.realpathSync ?? nodeFs2.realpathSync)(path));
|
|
2292
|
+
const [dir, top, common] = git(["rev-parse", "--path-format=absolute", "--git-dir", "--show-toplevel", "--git-common-dir"]).split("\n");
|
|
2293
|
+
if (!dir || !top || !common || ![dir, top, common].every(isAbsolute2)) return;
|
|
2294
|
+
const root = real(top), gitDir = real(dir), commonDir = real(common);
|
|
2295
|
+
const marker = join2(root, ".git");
|
|
2296
|
+
const stat = (path) => (fs.lstatSync ?? nodeFs2.lstatSync)(path);
|
|
2297
|
+
if (stat(marker).isSymbolicLink() || stat(commonDir).isSymbolicLink()) return;
|
|
2298
|
+
if (gitDir === commonDir) {
|
|
2299
|
+
if (!stat(marker).isDirectory() || real(marker) !== commonDir) return;
|
|
2300
|
+
} else {
|
|
2301
|
+
const registry = join2(commonDir, "worktrees");
|
|
2302
|
+
if (stat(registry).isSymbolicLink() || dirname(gitDir) !== real(registry) || !stat(gitDir).isDirectory() || stat(gitDir).isSymbolicLink() || !stat(marker).isFile()) return;
|
|
2303
|
+
const text = String(fs.readFileSync(marker, "utf8")).trim();
|
|
2304
|
+
if (!text.startsWith("gitdir: ") || real(resolve(root, text.slice(8))) !== gitDir) return;
|
|
2305
|
+
const back = String(fs.readFileSync(join2(gitDir, "gitdir"), "utf8")).trim();
|
|
2306
|
+
const commonBack = String(fs.readFileSync(join2(gitDir, "commondir"), "utf8")).trim();
|
|
2307
|
+
if (real(resolve(gitDir, back)) !== real(marker) || real(resolve(gitDir, commonBack)) !== commonDir) return;
|
|
2308
|
+
}
|
|
2309
|
+
const registered = git(["worktree", "list", "--porcelain"]).split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.slice(9));
|
|
2310
|
+
if (!registered.some((path) => real(path) === root)) return;
|
|
2311
|
+
const mainMarker = registered[0] && join2(registered[0], ".git");
|
|
2312
|
+
if (!mainMarker || stat(mainMarker).isSymbolicLink() || !stat(mainMarker).isDirectory() || real(mainMarker) !== commonDir) return;
|
|
2313
|
+
return { root, gitDir, commonDir };
|
|
2314
|
+
} catch {
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
function localWriterRecovery(record) {
|
|
2319
|
+
if (record.localWriterClaim?.state !== "held" || typeof record.pid === "number" && record.pid > 0) return;
|
|
2320
|
+
return {
|
|
2321
|
+
state: "required",
|
|
2322
|
+
reason: "owner-unpublished",
|
|
2323
|
+
automaticReleaseAllowed: false,
|
|
2324
|
+
runId: record.runId,
|
|
2325
|
+
canonicalCwd: record.localWriterClaim.cwd,
|
|
2326
|
+
requiredEvidence: "native launch receipt proving no live child; parent death/timeouts/process-name search are insufficient"
|
|
2327
|
+
};
|
|
2328
|
+
}
|
|
2329
|
+
function revokePreparedWriterLaunch(runId, attemptId, deps = {}) {
|
|
2330
|
+
if (!/^[A-Za-z0-9_-]+$/.test(runId) || !attemptId) return "blocked";
|
|
2331
|
+
return withRunRecordLock("local-writer-admission", deps, () => {
|
|
2332
|
+
const snapshot = readRunRecord(runId, deps);
|
|
2333
|
+
if (!snapshot) return "blocked";
|
|
2334
|
+
return withRunRecordLock(runId, deps, () => {
|
|
2335
|
+
const latest = readRunRecord(runId, deps);
|
|
2336
|
+
if (!latest || JSON.stringify(latest) !== JSON.stringify(snapshot)) return "blocked";
|
|
2337
|
+
const launch = latest.writerLaunch;
|
|
2338
|
+
if (launch?.protocol !== "fenced-launch-v1" || launch.attemptId !== attemptId) return "blocked";
|
|
2339
|
+
if (launch.phase === "revoked") return latest.localWriterClaim?.state === "released" ? "already-revoked" : "blocked";
|
|
2340
|
+
if (launch.phase !== "prepared" || latest.localWriterClaim?.state !== "held" || latest.execution?.state !== "known" || latest.execution.owner.state !== "unknown" || latest.execution.canonicalCwd !== latest.localWriterClaim.cwd || latest.pid !== void 0 || latest.cwd !== latest.localWriterClaim.cwd || latest.execution.kind !== "host-local" || latest.execution.permissions.readOnly || !latest.execution.permissions.hostWritesAuthorized) return "blocked";
|
|
2341
|
+
launch.phase = "revoked";
|
|
2342
|
+
latest.localWriterClaim.state = "released";
|
|
2343
|
+
writeRunRecord(latest, deps);
|
|
2344
|
+
return "revoked";
|
|
2345
|
+
}, { strict: true, requireDeadOwner: true }) ?? "blocked";
|
|
2346
|
+
}, { strict: true, requireDeadOwner: true }) ?? "blocked";
|
|
2347
|
+
}
|
|
2348
|
+
function localWriterStillOwns(record, deps) {
|
|
2349
|
+
if (record.localWriterClaim?.state !== "held") return false;
|
|
2350
|
+
if (typeof record.pid !== "number" || record.pid <= 0) return true;
|
|
2351
|
+
const e = record.execution;
|
|
2352
|
+
const observed = e?.state === "known" && e.owner.state === "verified" ? nativeOwner(record.pid, deps) : void 0;
|
|
2353
|
+
const reused = observed?.state === "verified" && e?.state === "known" && e.owner.state === "verified" && (observed.startedAt !== e.owner.startedAt || (observed.linux?.bootId !== e.owner.linux?.bootId || observed.linux?.startTicks !== e.owner.linux?.startTicks));
|
|
2354
|
+
if (!isPidGone(record.pid, deps) && !reused) return true;
|
|
2355
|
+
const snapshot = JSON.stringify(record);
|
|
2356
|
+
const released = withRunRecordLock(record.runId, deps, () => {
|
|
2357
|
+
const latest = readRunRecord(record.runId, deps);
|
|
2358
|
+
if (!latest || JSON.stringify(latest) !== snapshot) return false;
|
|
2359
|
+
latest.localWriterClaim.state = "released";
|
|
2360
|
+
writeRunRecord(latest, deps);
|
|
2361
|
+
return true;
|
|
2362
|
+
}, { strict: true });
|
|
2363
|
+
return released !== true;
|
|
2364
|
+
}
|
|
2365
|
+
function acquireLocalWriterClaim(runId, cwd, deps) {
|
|
2366
|
+
const fs = deps.fs ?? nodeFs2;
|
|
2367
|
+
const canonical = String((fs.realpathSync ?? nodeFs2.realpathSync)(cwd));
|
|
2368
|
+
const worktree = trustedLocalWorktree(canonical, deps);
|
|
2369
|
+
const acquired = withRunRecordLock("local-writer-admission", deps, () => {
|
|
2370
|
+
const updated = withRunRecordLock(runId, deps, () => {
|
|
2371
|
+
const record = readRunRecord(runId, deps);
|
|
2372
|
+
if (!record) throw new Error(`[local-writer-resource] missing run ${runId}`);
|
|
2373
|
+
if (record.writerLaunch?.phase === "revoked") throw new Error("[local-writer-resource] claim attempt revoked");
|
|
2374
|
+
record.localWriterClaim = { cwd: canonical, ...worktree ? { worktree } : {}, state: "held" };
|
|
2375
|
+
if (record.writerLaunch && record.execution?.state === "known" && record.execution.owner.state === "verified" && record.pid === process.pid) {
|
|
2376
|
+
record.writerLaunch.phase = "granted";
|
|
2377
|
+
}
|
|
2378
|
+
writeRunRecord(record, deps);
|
|
2379
|
+
return true;
|
|
2380
|
+
}, { strict: true });
|
|
2381
|
+
if (!updated) throw new Error(`[local-writer-resource] run lock busy: ${runId}`);
|
|
2382
|
+
return true;
|
|
2383
|
+
}, { strict: true, requireDeadOwner: true });
|
|
2384
|
+
if (!acquired) throw new Error("[local-writer-resource] admission lock busy; no child spawned");
|
|
2385
|
+
return canonical;
|
|
2386
|
+
}
|
|
2387
|
+
function nativeOwner(pid, deps) {
|
|
2388
|
+
const first = probeProcessStartTime(pid, deps);
|
|
2389
|
+
let linux;
|
|
2390
|
+
if ((deps.platform ?? process.platform) === "linux") {
|
|
2391
|
+
try {
|
|
2392
|
+
const stat = nodeFs2.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
2393
|
+
const startTicks = stat.slice(stat.lastIndexOf(")") + 2).split(/\s+/)[19];
|
|
2394
|
+
const bootId = nodeFs2.readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
|
|
2395
|
+
if (/^\d+$/.test(startTicks) && bootId) linux = { startTicks, bootId };
|
|
2396
|
+
} catch {
|
|
2397
|
+
return { state: "unknown" };
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
const second = probeProcessStartTime(pid, deps);
|
|
2401
|
+
if (!first || !second || first.getTime() !== second.getTime() || isPidGone(pid, deps) || (deps.platform ?? process.platform) === "linux" && !linux) return { state: "unknown" };
|
|
2402
|
+
return { state: "verified", pid, startedAt: first.toISOString(), source: "parent-native", ...linux ? { linux } : {} };
|
|
2403
|
+
}
|
|
2404
|
+
function validateLocalWriterChild(runId, cwd, policy, deps = {}) {
|
|
2405
|
+
const fail = (reason = "facts") => {
|
|
2406
|
+
throw new Error(`[local-writer-resource] child binding unknown or mismatched: ${reason}`);
|
|
2407
|
+
};
|
|
2408
|
+
if (!/^[A-Za-z0-9_-]+$/.test(runId)) fail();
|
|
2409
|
+
const validated = withRunRecordLock(runId, deps, () => {
|
|
2410
|
+
const r = readRunRecord(runId, deps), e = r?.execution;
|
|
2411
|
+
const launch = r?.writerLaunch;
|
|
2412
|
+
if (launch && (launch.protocol !== "fenced-launch-v1" || launch.phase !== "granted" || launch.attemptId !== deps.env?.NOLO_WRITER_LAUNCH_ATTEMPT)) fail("launch grant missing/revoked");
|
|
2413
|
+
const native = nativeOwner(process.pid, deps);
|
|
2414
|
+
const real = String((deps.fs?.realpathSync ?? nodeFs2.realpathSync)(cwd));
|
|
2415
|
+
if (!r || r.runId !== runId || r.pid !== process.pid || r.status !== "running" || e?.state !== "known" || e.kind !== "host-local" || e.runtimeKey !== "local" || e.device.kind !== "localhost" || e.device.hostname !== nodeHostname() || e.device.platform !== process.platform || !["cli-command-authorized", "cli-tool-dispatch-authorized"].includes(e.provenance) || e.owner.state !== "verified" || native.state !== "verified" || e.owner.pid !== process.pid || e.owner.startedAt !== native.startedAt || (e.owner.linux?.bootId !== native.linux?.bootId || e.owner.linux?.startTicks !== native.linux?.startTicks) || r.processIdentity !== "verified" || r.processStartedAt !== e.owner.startedAt || e.canonicalCwd !== real || r.cwd !== real || e.permissions.hostWritesAuthorized !== policy.hostWritesAuthorized || e.permissions.readOnly !== policy.readOnly) fail("native identity/authorization");
|
|
2416
|
+
if (e?.state !== "known") return fail();
|
|
2417
|
+
const set = (v) => JSON.stringify(v === void 0 ? null : [...new Set(v)].sort());
|
|
2418
|
+
if (set(e.permissions.allowedToolNames) !== set(policy.allowedToolNames) || set(e.permissions.blockedToolNames) !== set(policy.blockedToolNames) || JSON.stringify(e.worktree) !== JSON.stringify(trustedLocalWorktree(real, deps))) fail("scope/worktree");
|
|
2419
|
+
if (!policy.readOnly && (!policy.hostWritesAuthorized || r?.localWriterClaim?.state !== "held" || r.localWriterClaim.cwd !== real || e.worktree && (r.localWriterClaim.worktree?.root !== e.worktree.root || r.localWriterClaim.worktree.gitDir !== e.worktree.gitDir))) fail();
|
|
2420
|
+
return true;
|
|
2421
|
+
}, { strict: true, requireDeadOwner: true });
|
|
2422
|
+
if (!validated) fail("registry lock busy");
|
|
2423
|
+
}
|
|
2424
|
+
async function awaitLocalWriterChild(runId, cwd, policy, deps = {}) {
|
|
2425
|
+
if (!/^[A-Za-z0-9_-]+$/.test(runId)) throw new Error("[local-writer-resource] child binding invalid id");
|
|
2426
|
+
const deadline = Date.now() + 2e3;
|
|
2427
|
+
for (; ; ) {
|
|
2428
|
+
const r = readRunRecord(runId, deps);
|
|
2429
|
+
const publication = r?.ownerPublication;
|
|
2430
|
+
if (r?.writerLaunch && (r.writerLaunch.phase === "revoked" || r.writerLaunch.attemptId !== deps.env?.NOLO_WRITER_LAUNCH_ATTEMPT)) {
|
|
2431
|
+
throw new Error("[local-writer-resource] child binding launch revoked/mismatched");
|
|
2432
|
+
}
|
|
2433
|
+
const native = publication ? nativeOwner(publication.parent.pid, deps) : { state: "unknown" };
|
|
2434
|
+
const parentLive = publication && native.state === "verified" && publication.parent.startedAt === native.startedAt && publication.parent.linux?.bootId === native.linux?.bootId && publication.parent.linux?.startTicks === native.linux?.startTicks;
|
|
2435
|
+
try {
|
|
2436
|
+
validateLocalWriterChild(runId, cwd, policy, deps);
|
|
2437
|
+
return;
|
|
2438
|
+
} catch (error) {
|
|
2439
|
+
const lockBusy = String(error).includes("registry lock busy");
|
|
2440
|
+
const pending = publication?.state === "pending" && r?.execution?.state === "known" && r.execution.owner.state === "unknown";
|
|
2441
|
+
if (!parentLive || !pending && !lockBusy || Date.now() >= deadline) throw error;
|
|
2442
|
+
await new Promise((resolve2) => setTimeout(resolve2, 20));
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
function resolveLocalContinuation(record, deps = {}) {
|
|
2447
|
+
const fail = (why) => {
|
|
2448
|
+
throw new Error(`[local-continuation] ${why}; dispatch a fresh explicitly authorized run`);
|
|
2449
|
+
};
|
|
2450
|
+
const e = record.execution;
|
|
2451
|
+
if (e?.state !== "known" || e.kind !== "host-local" || e.runtimeKey !== "local" || e.device?.kind !== "localhost" || e.device.hostname !== nodeHostname() || e.device.platform !== process.platform || !["cli-command-authorized", "cli-tool-dispatch-authorized"].includes(e.provenance) || typeof e.permissions?.readOnly !== "boolean" || typeof e.permissions.hostWritesAuthorized !== "boolean" || !e.permissions.readOnly && !e.permissions.hostWritesAuthorized) return fail("execution unknown or unsupported");
|
|
2452
|
+
const lists = [e.permissions.allowedToolNames, e.permissions.blockedToolNames];
|
|
2453
|
+
if (lists.some((v) => v !== void 0 && (!Array.isArray(v) || v.some((t) => typeof t !== "string" || !t || t.startsWith("--"))))) return fail("tool scope invalid");
|
|
2454
|
+
let cwd;
|
|
2455
|
+
try {
|
|
2456
|
+
if (!e.canonicalCwd || !isAbsolute2(e.canonicalCwd) || record.cwd !== e.canonicalCwd) return fail("cwd identity missing");
|
|
2457
|
+
const fs = deps.fs ?? nodeFs2;
|
|
2458
|
+
cwd = String((fs.realpathSync ?? nodeFs2.realpathSync)(e.canonicalCwd));
|
|
2459
|
+
if (cwd !== e.canonicalCwd || !(fs.statSync ?? nodeFs2.statSync)(cwd).isDirectory()) return fail("cwd drift");
|
|
2460
|
+
if (JSON.stringify(e.worktree) !== JSON.stringify(trustedLocalWorktree(cwd, deps))) return fail("cwd worktree changed");
|
|
2461
|
+
} catch {
|
|
2462
|
+
return fail("cwd missing or moved");
|
|
2463
|
+
}
|
|
2464
|
+
const death = record.ownerDeath;
|
|
2465
|
+
const hasDeath = !record.pid && death && death.pid > 0 && JSON.stringify(death.executionOwner) === JSON.stringify(e.owner) && (!record.localWriterClaim || record.localWriterClaim.state === "released");
|
|
2466
|
+
if (!hasDeath && (typeof record.pid !== "number" || record.pid <= 0)) return fail("old owner unknown");
|
|
2467
|
+
const current = hasDeath ? { state: "unknown" } : nativeOwner(record.pid, deps);
|
|
2468
|
+
const old = e.owner;
|
|
2469
|
+
const reused = old?.state === "verified" && current.state === "verified" && (old.pid !== current.pid || old.startedAt !== current.startedAt || old.linux?.bootId !== current.linux?.bootId || old.linux?.startTicks !== current.linux?.startTicks);
|
|
2470
|
+
if (!hasDeath && !isPidGone(record.pid, deps) && !reused) return fail("old owner live or unknown");
|
|
2471
|
+
if (!e.permissions.readOnly && (record.localWriterClaim?.cwd !== cwd || !["held", "released"].includes(record.localWriterClaim.state))) return fail("writer claim unknown");
|
|
2472
|
+
const policy = { runtimeKey: "local", ...e.permissions, provenance: "cli-tool-dispatch-authorized" };
|
|
2473
|
+
const rawArgs = [
|
|
2474
|
+
"--runtime-key",
|
|
2475
|
+
"local",
|
|
2476
|
+
...policy.hostWritesAuthorized ? ["--allow-host-writes"] : [],
|
|
2477
|
+
...policy.readOnly ? ["--read-only"] : [],
|
|
2478
|
+
...(policy.allowedToolNames ?? []).flatMap((t) => ["--allowed-tool", t]),
|
|
2479
|
+
...(policy.blockedToolNames ?? []).flatMap((t) => ["--blocked-tool", t])
|
|
2480
|
+
];
|
|
2481
|
+
return { cwd, policy, rawArgs };
|
|
2482
|
+
}
|
|
2483
|
+
function registerLocalForegroundWriter(cwd, policy, agentKey, deps = {}) {
|
|
2484
|
+
const fs = deps.fs ?? nodeFs2;
|
|
2485
|
+
const canonical = String((fs.realpathSync ?? nodeFs2.realpathSync)(cwd));
|
|
2486
|
+
const owner = nativeOwner(process.pid, deps);
|
|
2487
|
+
if (owner.state !== "verified" || policy.readOnly || !policy.hostWritesAuthorized) {
|
|
2488
|
+
throw new Error("[local-writer-resource] foreground native identity/authorization unknown");
|
|
2489
|
+
}
|
|
2490
|
+
const runId = defaultGenerateRunId();
|
|
2491
|
+
fs.mkdirSync(resolveRunsDir(deps.env, deps.homedir), { recursive: true });
|
|
2492
|
+
const worktree = trustedLocalWorktree(canonical, deps);
|
|
2493
|
+
const record = {
|
|
2494
|
+
runId,
|
|
2495
|
+
agentKey,
|
|
2496
|
+
writerLaunch: { protocol: "fenced-launch-v1", attemptId: randomUUID2(), phase: "prepared" },
|
|
2497
|
+
cwd: canonical,
|
|
2498
|
+
startedAt: (deps.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
2499
|
+
status: "running",
|
|
2500
|
+
logPath: resolveRunLogPath(runId, deps.env, deps.homedir),
|
|
2501
|
+
pid: process.pid,
|
|
2502
|
+
processStartedAt: owner.startedAt,
|
|
2503
|
+
processIdentity: "verified",
|
|
2504
|
+
execution: {
|
|
2505
|
+
state: "known",
|
|
2506
|
+
kind: "host-local",
|
|
2507
|
+
runtimeKey: "local",
|
|
2508
|
+
canonicalCwd: canonical,
|
|
2509
|
+
device: { kind: "localhost", hostname: nodeHostname(), platform: process.platform },
|
|
2510
|
+
...worktree ? { worktree } : {},
|
|
2511
|
+
permissions: {
|
|
2512
|
+
hostWritesAuthorized: policy.hostWritesAuthorized,
|
|
2513
|
+
readOnly: policy.readOnly,
|
|
2514
|
+
...policy.allowedToolNames ? { allowedToolNames: [...policy.allowedToolNames] } : {},
|
|
2515
|
+
...policy.blockedToolNames ? { blockedToolNames: [...policy.blockedToolNames] } : {}
|
|
2516
|
+
},
|
|
2517
|
+
provenance: policy.provenance,
|
|
2518
|
+
owner
|
|
2519
|
+
}
|
|
2520
|
+
};
|
|
2521
|
+
writeRunRecord(record, deps);
|
|
2522
|
+
try {
|
|
2523
|
+
acquireLocalWriterClaim(runId, canonical, deps);
|
|
2524
|
+
} catch (error) {
|
|
2525
|
+
finalizeRunRecord(runId, { status: "failed", exitCode: 1, note: String(error) }, deps);
|
|
2526
|
+
throw error;
|
|
2527
|
+
}
|
|
2528
|
+
return runId;
|
|
2529
|
+
}
|
|
2530
|
+
function releaseUnspawnedLocalWriterClaim(runId, deps) {
|
|
2531
|
+
const released = withRunRecordLock(runId, deps, () => {
|
|
2532
|
+
const record = readRunRecord(runId, deps);
|
|
2533
|
+
if (record?.localWriterClaim) {
|
|
2534
|
+
if (record.writerLaunch?.phase === "prepared") record.writerLaunch.phase = "revoked";
|
|
2535
|
+
record.localWriterClaim.state = "released";
|
|
2536
|
+
writeRunRecord(record, deps);
|
|
2537
|
+
}
|
|
2538
|
+
return true;
|
|
2539
|
+
}, { strict: true });
|
|
2540
|
+
if (!released) throw new Error(`[local-writer-resource] release lock busy: ${runId}`);
|
|
2541
|
+
}
|
|
2213
2542
|
async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
2214
2543
|
const homedir = deps.homedir ?? nodeHomedir;
|
|
2215
2544
|
const env = deps.env ?? (deps.homedir ? { ...process.env, NOLO_HOME: join2(homedir(), ".nolo") } : process.env);
|
|
@@ -2255,13 +2584,43 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2255
2584
|
}
|
|
2256
2585
|
} catch {
|
|
2257
2586
|
}
|
|
2587
|
+
const executionRequest = input.localExecution;
|
|
2588
|
+
if (executionRequest && (executionRequest.runtimeKey !== "local" || typeof executionRequest.readOnly !== "boolean" || typeof executionRequest.hostWritesAuthorized !== "boolean" || !executionRequest.readOnly && !executionRequest.hostWritesAuthorized)) {
|
|
2589
|
+
throw new Error("Invalid authorized local execution facts");
|
|
2590
|
+
}
|
|
2591
|
+
const canonicalCwd = executionRequest ? String((fs.realpathSync ?? nodeFs2.realpathSync)(targetCwd)) : void 0;
|
|
2592
|
+
const executionWorktree = canonicalCwd ? trustedLocalWorktree(canonicalCwd, resolvedDeps) : void 0;
|
|
2593
|
+
const execution = executionRequest ? {
|
|
2594
|
+
state: "known",
|
|
2595
|
+
kind: "host-local",
|
|
2596
|
+
runtimeKey: "local",
|
|
2597
|
+
device: { kind: "localhost", hostname: nodeHostname(), platform: deps.platform ?? process.platform },
|
|
2598
|
+
canonicalCwd,
|
|
2599
|
+
...executionWorktree ? { worktree: executionWorktree } : {},
|
|
2600
|
+
permissions: {
|
|
2601
|
+
hostWritesAuthorized: executionRequest.hostWritesAuthorized,
|
|
2602
|
+
readOnly: executionRequest.readOnly,
|
|
2603
|
+
...executionRequest.allowedToolNames ? { allowedToolNames: [...executionRequest.allowedToolNames] } : {},
|
|
2604
|
+
...executionRequest.blockedToolNames ? { blockedToolNames: [...executionRequest.blockedToolNames] } : {}
|
|
2605
|
+
},
|
|
2606
|
+
provenance: executionRequest.provenance,
|
|
2607
|
+
owner: { state: "unknown" }
|
|
2608
|
+
} : { state: "unknown", reason: "missing-host-facts" };
|
|
2258
2609
|
const title = normalizeRunTitle(input.title);
|
|
2259
2610
|
const record = {
|
|
2611
|
+
...input.evidenceScope ? { evidenceScope: input.evidenceScope } : {},
|
|
2612
|
+
...input.dispatchSpeedProvenance ? { dispatchSpeedProvenance: input.dispatchSpeedProvenance } : {},
|
|
2260
2613
|
runId,
|
|
2261
2614
|
agentKey: input.agentKey,
|
|
2262
|
-
|
|
2615
|
+
agentName: input.agentName?.trim() || shortAgentKey(input.agentKey),
|
|
2263
2616
|
...title ? { title } : {},
|
|
2264
|
-
cwd: input.cwd,
|
|
2617
|
+
cwd: canonicalCwd ?? input.cwd,
|
|
2618
|
+
execution,
|
|
2619
|
+
...executionRequest ? { writerLaunch: { protocol: "fenced-launch-v1", attemptId: randomUUID2(), phase: "prepared" } } : {},
|
|
2620
|
+
...executionRequest ? (() => {
|
|
2621
|
+
const parent = nativeOwner(process.pid, resolvedDeps);
|
|
2622
|
+
return parent.state === "verified" ? { ownerPublication: { state: "pending", parent } } : {};
|
|
2623
|
+
})() : {},
|
|
2265
2624
|
...messagePath ? { msgFile: messagePath } : input.msgFile ? { msgFile: input.msgFile } : {},
|
|
2266
2625
|
startedAt: now().toISOString(),
|
|
2267
2626
|
...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
|
|
@@ -2269,6 +2628,7 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2269
2628
|
logPath,
|
|
2270
2629
|
queuePath,
|
|
2271
2630
|
batchId,
|
|
2631
|
+
...input.selectionCheck ? { selectionCheck: input.selectionCheck } : {},
|
|
2272
2632
|
...typeof input.credentialGroup === "string" && input.credentialGroup.trim() ? { credentialGroup: input.credentialGroup.trim() } : {},
|
|
2273
2633
|
...typeof input.parentDialogId === "string" && input.parentDialogId.trim() ? { parentDialogId: input.parentDialogId.trim() } : {},
|
|
2274
2634
|
...typeof input.dialogId === "string" && input.dialogId.trim() ? { dialogId: input.dialogId.trim() } : {},
|
|
@@ -2294,11 +2654,11 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2294
2654
|
...env,
|
|
2295
2655
|
NOLO_AGENT_RUN_CHILD: "1",
|
|
2296
2656
|
NOLO_AGENT_RUN_ID: runId,
|
|
2297
|
-
...
|
|
2298
|
-
NOLO_SUBTASK_MAX_TOOL_CALLS: String(input.subtaskBudgetLimits.maxToolCalls),
|
|
2299
|
-
NOLO_SUBTASK_MAX_WALL_CLOCK_MS: String(input.subtaskBudgetLimits.maxWallClockMs)
|
|
2300
|
-
} : {}
|
|
2657
|
+
...record.writerLaunch ? { NOLO_WRITER_LAUNCH_ATTEMPT: record.writerLaunch.attemptId } : {}
|
|
2301
2658
|
};
|
|
2659
|
+
if (!record.writerLaunch) delete childEnv.NOLO_WRITER_LAUNCH_ATTEMPT;
|
|
2660
|
+
delete childEnv.NOLO_SUBTASK_MAX_TOOL_CALLS;
|
|
2661
|
+
delete childEnv.NOLO_SUBTASK_MAX_WALL_CLOCK_MS;
|
|
2302
2662
|
let hostMemory = null;
|
|
2303
2663
|
let reservation;
|
|
2304
2664
|
const logFd = fs.openSync(logPath, "a");
|
|
@@ -2312,6 +2672,8 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2312
2672
|
...fs.statSync ? { statSync: (path) => ({ mtimeMs: fs.statSync(path).mtimeMs }) } : {}
|
|
2313
2673
|
};
|
|
2314
2674
|
let proc;
|
|
2675
|
+
let preparedScope;
|
|
2676
|
+
const launchScope = (r) => JSON.stringify({ cwd: r.cwd, execution: r.execution, claim: r.localWriterClaim, publication: r.ownerPublication });
|
|
2315
2677
|
try {
|
|
2316
2678
|
reservation = reserveHostMemory({
|
|
2317
2679
|
runsDir,
|
|
@@ -2323,8 +2685,14 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2323
2685
|
getProcessStartTime: () => null,
|
|
2324
2686
|
withLock: (id, fn, opts) => withRunRecordLock(id, resolvedDeps, fn, opts)
|
|
2325
2687
|
});
|
|
2688
|
+
const spawnCwd = input.claimLocalWrites ? acquireLocalWriterClaim(runId, input.cwd ?? process.cwd(), resolvedDeps) : canonicalCwd ?? input.cwd;
|
|
2689
|
+
if (record.writerLaunch) {
|
|
2690
|
+
const prepared = readRunRecord(runId, resolvedDeps);
|
|
2691
|
+
if (!prepared || prepared.writerLaunch?.phase !== "prepared" || prepared.writerLaunch.attemptId !== record.writerLaunch.attemptId) throw new Error("[local-writer-resource] launch attempt revoked before spawn");
|
|
2692
|
+
preparedScope = launchScope(prepared);
|
|
2693
|
+
}
|
|
2326
2694
|
proc = spawn(execPath, childArgs, {
|
|
2327
|
-
cwd:
|
|
2695
|
+
cwd: spawnCwd,
|
|
2328
2696
|
env: childEnv,
|
|
2329
2697
|
detached: true,
|
|
2330
2698
|
// Detached on Windows means no console; hide the one its children would create.
|
|
@@ -2334,6 +2702,7 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2334
2702
|
} catch (error) {
|
|
2335
2703
|
try {
|
|
2336
2704
|
reservation?.release("spawn_sync_failed");
|
|
2705
|
+
if (input.claimLocalWrites) releaseUnspawnedLocalWriterClaim(runId, resolvedDeps);
|
|
2337
2706
|
} finally {
|
|
2338
2707
|
finalizeRunRecord(runId, { status: "failed", exitCode: 1, note: String(error) }, resolvedDeps);
|
|
2339
2708
|
}
|
|
@@ -2356,13 +2725,56 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2356
2725
|
});
|
|
2357
2726
|
const hostMemoryNotice = emitHostMemoryNotice(hostMemory, input.output);
|
|
2358
2727
|
if (typeof proc.pid === "number") {
|
|
2359
|
-
|
|
2360
|
-
|
|
2728
|
+
const nativeStartedAt = executionRequest ? probeProcessStartTime(proc.pid, resolvedDeps) : null;
|
|
2729
|
+
let linuxIdentity;
|
|
2730
|
+
if (executionRequest && (deps.platform ?? process.platform) === "linux") {
|
|
2731
|
+
try {
|
|
2732
|
+
const stat = String(nodeFs2.readFileSync(`/proc/${proc.pid}/stat`, "utf8"));
|
|
2733
|
+
const startTicks = stat.slice(stat.lastIndexOf(")") + 2).split(/\s+/)[19];
|
|
2734
|
+
const bootId = nodeFs2.readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
|
|
2735
|
+
if (/^\d+$/.test(startTicks) && bootId) linuxIdentity = { bootId, startTicks };
|
|
2736
|
+
} catch {
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
const confirmedStart = executionRequest ? probeProcessStartTime(proc.pid, resolvedDeps) : null;
|
|
2740
|
+
const stableNativeIdentity = nativeStartedAt && confirmedStart && nativeStartedAt.getTime() === confirmedStart.getTime() && !isPidGone(proc.pid, resolvedDeps);
|
|
2741
|
+
const publishOwner = () => withRunRecordLock(runId, resolvedDeps, () => {
|
|
2742
|
+
const latest = readRunRecord(runId, resolvedDeps);
|
|
2743
|
+
if (!latest) throw new Error("[local-writer-resource] publication record missing");
|
|
2744
|
+
if (record.writerLaunch) {
|
|
2745
|
+
const launch = latest.writerLaunch;
|
|
2746
|
+
if (launch?.protocol !== "fenced-launch-v1" || launch.attemptId !== record.writerLaunch.attemptId || launch.phase !== "prepared") {
|
|
2747
|
+
throw new Error("[local-writer-resource] publication attempt revoked/mismatched");
|
|
2748
|
+
}
|
|
2749
|
+
if (launchScope(latest) !== preparedScope) throw new Error("[local-writer-resource] publication scope changed");
|
|
2750
|
+
}
|
|
2361
2751
|
latest.pid = proc.pid;
|
|
2362
|
-
latest.
|
|
2752
|
+
if (latest.execution?.state === "known") {
|
|
2753
|
+
const verified = stableNativeIdentity && ((deps.platform ?? process.platform) !== "linux" || linuxIdentity);
|
|
2754
|
+
latest.execution.owner = verified ? {
|
|
2755
|
+
state: "verified",
|
|
2756
|
+
pid: proc.pid,
|
|
2757
|
+
startedAt: nativeStartedAt.toISOString(),
|
|
2758
|
+
source: "parent-native",
|
|
2759
|
+
...linuxIdentity ? { linux: linuxIdentity } : {}
|
|
2760
|
+
} : { state: "unknown" };
|
|
2761
|
+
latest.processIdentity = verified ? "verified" : "unverified";
|
|
2762
|
+
latest.processStartedAt = verified ? nativeStartedAt.toISOString() : void 0;
|
|
2763
|
+
} else {
|
|
2764
|
+
latest.processIdentity ??= "unverified";
|
|
2765
|
+
}
|
|
2766
|
+
if (latest.writerLaunch && latest.execution?.state === "known" && latest.execution.owner.state === "verified") {
|
|
2767
|
+
latest.writerLaunch.phase = "granted";
|
|
2768
|
+
}
|
|
2769
|
+
if (latest.ownerPublication) latest.ownerPublication.state = "complete";
|
|
2363
2770
|
writeRunRecord(latest, resolvedDeps);
|
|
2364
2771
|
return true;
|
|
2365
|
-
}, { strict: true });
|
|
2772
|
+
}, { strict: true, requireDeadOwner: true });
|
|
2773
|
+
const publicationDeadline = Date.now() + 2e3;
|
|
2774
|
+
while (!publishOwner()) {
|
|
2775
|
+
if (Date.now() >= publicationDeadline) throw new Error("[local-writer-resource] parent owner publication lock busy");
|
|
2776
|
+
await new Promise((resolve2) => setTimeout(resolve2, 20));
|
|
2777
|
+
}
|
|
2366
2778
|
try {
|
|
2367
2779
|
const persisted = readRunRecord(runId, resolvedDeps);
|
|
2368
2780
|
reservation.associate({ runId, pid: proc.pid, processStartedAt: persisted?.processStartedAt });
|
|
@@ -2387,6 +2799,8 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2387
2799
|
logPath,
|
|
2388
2800
|
queuePath,
|
|
2389
2801
|
batchId,
|
|
2802
|
+
agentName: record.agentName ?? shortAgentKey(input.agentKey),
|
|
2803
|
+
...input.selectionCheck ? { selectionCheck: input.selectionCheck } : {},
|
|
2390
2804
|
...hostMemoryNotice ? { hostMemoryNotice } : {}
|
|
2391
2805
|
};
|
|
2392
2806
|
}
|
|
@@ -2495,8 +2909,31 @@ function transitionRunToTerminal(runId, update, deps = {}, options = {}) {
|
|
|
2495
2909
|
if (typeof update.lastAssistantText === "string" && update.lastAssistantText) {
|
|
2496
2910
|
record2.lastAssistantText = update.lastAssistantText.slice(0, 2e3);
|
|
2497
2911
|
}
|
|
2912
|
+
if (update.cacheUsage) {
|
|
2913
|
+
record2.cacheHitRatio = update.cacheUsage.cache_hit_ratio;
|
|
2914
|
+
record2.cacheCachedTokens = update.cacheUsage.cached_tokens;
|
|
2915
|
+
}
|
|
2498
2916
|
record2.endedAt = now().toISOString();
|
|
2499
|
-
|
|
2917
|
+
let resultWriteFailed = false;
|
|
2918
|
+
let pendingResultFile;
|
|
2919
|
+
let stagingComplete = false;
|
|
2920
|
+
let backupFile;
|
|
2921
|
+
let backupVerified = false;
|
|
2922
|
+
const registerArtifact = (path, kind) => {
|
|
2923
|
+
const fs = deps.fs ?? nodeFs2;
|
|
2924
|
+
const stat = fs.lstatSync?.(path);
|
|
2925
|
+
if (!stat || !stat.isFile() || stat.isSymbolicLink()) return;
|
|
2926
|
+
const artifact = {
|
|
2927
|
+
publisher: "run-result-v1",
|
|
2928
|
+
path,
|
|
2929
|
+
kind,
|
|
2930
|
+
dev: String(stat.dev),
|
|
2931
|
+
ino: String(stat.ino),
|
|
2932
|
+
sha256: createHash("sha256").update(fs.readFileSync(path)).digest("hex")
|
|
2933
|
+
};
|
|
2934
|
+
record2.resultArtifacts = [...(record2.resultArtifacts ?? []).filter((a) => a.path !== path), artifact];
|
|
2935
|
+
};
|
|
2936
|
+
if (typeof update.lastAssistantText === "string" && update.lastAssistantText || update.acceptance?.checks.observations?.length) {
|
|
2500
2937
|
try {
|
|
2501
2938
|
const fs = deps.fs ?? nodeFs2;
|
|
2502
2939
|
const resultFile = join2(resolveRunsDir(deps.env, deps.homedir), `${runId}.result.md`);
|
|
@@ -2505,6 +2942,7 @@ function transitionRunToTerminal(runId, update, deps = {}, options = {}) {
|
|
|
2505
2942
|
const content = buildResultFileContent(
|
|
2506
2943
|
{
|
|
2507
2944
|
runId,
|
|
2945
|
+
acceptance: update.acceptance,
|
|
2508
2946
|
status: record2.status,
|
|
2509
2947
|
agentName: record2.agentName,
|
|
2510
2948
|
model: update.model,
|
|
@@ -2519,16 +2957,54 @@ function transitionRunToTerminal(runId, update, deps = {}, options = {}) {
|
|
|
2519
2957
|
continuedFrom: record2.continuedFrom,
|
|
2520
2958
|
...update.cacheUsage ? { cacheUsage: update.cacheUsage } : {}
|
|
2521
2959
|
},
|
|
2522
|
-
update.lastAssistantText
|
|
2960
|
+
update.lastAssistantText ?? ""
|
|
2523
2961
|
);
|
|
2524
|
-
fs.
|
|
2962
|
+
if (typeof fs.renameSync !== "function") throw new Error("atomic result publication requires renameSync");
|
|
2963
|
+
pendingResultFile = `${resultFile}.${randomUUID2()}.pending`;
|
|
2964
|
+
try {
|
|
2965
|
+
fs.writeFileSync(pendingResultFile, content, { encoding: "utf8", flag: "wx" });
|
|
2966
|
+
stagingComplete = true;
|
|
2967
|
+
} finally {
|
|
2968
|
+
if (fs.existsSync(pendingResultFile)) registerArtifact(pendingResultFile, "pending");
|
|
2969
|
+
}
|
|
2970
|
+
if (fs.existsSync(resultFile)) {
|
|
2971
|
+
const previous = fs.readFileSync(resultFile);
|
|
2972
|
+
const backup = `${resultFile}.${randomUUID2()}.bak`;
|
|
2973
|
+
backupFile = backup;
|
|
2974
|
+
try {
|
|
2975
|
+
fs.writeFileSync(backup, previous, { flag: "wx" });
|
|
2976
|
+
} finally {
|
|
2977
|
+
if (fs.existsSync(backup)) registerArtifact(backup, "bak");
|
|
2978
|
+
}
|
|
2979
|
+
const sameBytes = (a, b) => Buffer.from(a).equals(Buffer.from(b));
|
|
2980
|
+
if (!sameBytes(previous, fs.readFileSync(backup)) || !sameBytes(previous, fs.readFileSync(resultFile))) {
|
|
2981
|
+
throw new Error("previous result backup verification failed");
|
|
2982
|
+
}
|
|
2983
|
+
backupVerified = true;
|
|
2984
|
+
}
|
|
2985
|
+
fs.renameSync(pendingResultFile, resultFile);
|
|
2986
|
+
record2.resultArtifacts = record2.resultArtifacts?.filter((a) => a.path !== pendingResultFile);
|
|
2987
|
+
pendingResultFile = void 0;
|
|
2525
2988
|
record2.resultFile = resultFile;
|
|
2526
2989
|
} catch {
|
|
2990
|
+
resultWriteFailed = true;
|
|
2991
|
+
delete record2.resultFile;
|
|
2992
|
+
if (record2.status === "done") {
|
|
2993
|
+
record2.status = "failed";
|
|
2994
|
+
record2.exitCode = 1;
|
|
2995
|
+
}
|
|
2527
2996
|
}
|
|
2528
2997
|
}
|
|
2529
2998
|
if (typeof update.note === "string" && update.note.trim()) {
|
|
2530
2999
|
record2.note = update.note.trim();
|
|
2531
3000
|
}
|
|
3001
|
+
if (resultWriteFailed) {
|
|
3002
|
+
if (record2.note?.startsWith("orphaned:")) record2.note = void 0;
|
|
3003
|
+
const fs = deps.fs ?? nodeFs2;
|
|
3004
|
+
const stagingNote = pendingResultFile ? fs.existsSync(pendingResultFile) ? `${stagingComplete ? "complete staging copy" : "incomplete staging fragment"}: ${pendingResultFile}` : `staging not created: ${pendingResultFile}` : "staging not created";
|
|
3005
|
+
const backupNote = backupFile ? `${fs.existsSync(backupFile) ? backupVerified ? "full verified backup" : "partial backup" : "backup not created"}: ${backupFile}` : "backup not created";
|
|
3006
|
+
record2.note = [record2.note, `result file write failed; complete final report was not saved; ${stagingNote}; ${backupNote}`].filter(Boolean).join("; ");
|
|
3007
|
+
}
|
|
2532
3008
|
if (record2.note?.startsWith("orphaned:")) record2.note = void 0;
|
|
2533
3009
|
writeRunRecord(record2, deps);
|
|
2534
3010
|
return { kind: "transitioned", record: record2 };
|
|
@@ -2604,10 +3080,10 @@ function defaultGetProcessStartTime(pid, deps = {}) {
|
|
|
2604
3080
|
// 这会让 isPidReused 的结论依赖调用者环境:同一条 run 记录在英文
|
|
2605
3081
|
// locale 下被判 pid reused → orphaned,中文 locale 下不判。强制 C
|
|
2606
3082
|
// locale 让输出恒为可解析的英文格式,结果与 locale 无关。
|
|
2607
|
-
env: { ...process.env, LC_ALL: "C", LANG: "C" }
|
|
3083
|
+
env: { ...process.env, LC_ALL: "C", LANG: "C", TZ: "UTC" }
|
|
2608
3084
|
}).trim();
|
|
2609
3085
|
if (!output) return null;
|
|
2610
|
-
const d = new Date(output);
|
|
3086
|
+
const d = new Date(output.endsWith("Z") || /[+-]\d\d:\d\d$/.test(output) ? output : `${output} UTC`);
|
|
2611
3087
|
return isNaN(d.getTime()) ? null : d;
|
|
2612
3088
|
} catch {
|
|
2613
3089
|
return null;
|
|
@@ -2659,6 +3135,7 @@ function checkStaleRun(runId, deps = {}) {
|
|
|
2659
3135
|
const latest = readRunRecord(runId, deps);
|
|
2660
3136
|
if (!latest) return record;
|
|
2661
3137
|
if (latest.status !== "running") return latest;
|
|
3138
|
+
if (latest.pid !== record.pid || latest.processStartedAt !== record.processStartedAt || latest.processIdentity !== record.processIdentity) return latest;
|
|
2662
3139
|
if (latest.activity?.updatedAt !== record.activity?.updatedAt) return latest;
|
|
2663
3140
|
const at = now().toISOString();
|
|
2664
3141
|
latest.status = "orphaned";
|
|
@@ -2674,6 +3151,16 @@ function checkStaleRun(runId, deps = {}) {
|
|
|
2674
3151
|
}
|
|
2675
3152
|
latest.endedAt = at;
|
|
2676
3153
|
latest.reconciledAt = at;
|
|
3154
|
+
if ((pidGone || pidReused) && latest.localWriterClaim?.state === "held") {
|
|
3155
|
+
latest.localWriterClaim.state = "released";
|
|
3156
|
+
}
|
|
3157
|
+
latest.ownerDeath = {
|
|
3158
|
+
pid: latest.pid,
|
|
3159
|
+
processStartedAt: latest.processStartedAt,
|
|
3160
|
+
processIdentity: latest.processIdentity,
|
|
3161
|
+
...latest.execution?.state === "known" ? { executionOwner: latest.execution.owner } : {},
|
|
3162
|
+
confirmedAt: at
|
|
3163
|
+
};
|
|
2677
3164
|
latest.pid = void 0;
|
|
2678
3165
|
writeRunRecord(latest, deps);
|
|
2679
3166
|
return latest;
|
|
@@ -2844,6 +3331,7 @@ async function runAgentStatusCommand(args, deps) {
|
|
|
2844
3331
|
const { partialCheckpoint, ...summary } = record;
|
|
2845
3332
|
deps.output.write(JSON.stringify({
|
|
2846
3333
|
...summary,
|
|
3334
|
+
...localWriterRecovery(record) ? { writerRecovery: localWriterRecovery(record) } : {},
|
|
2847
3335
|
...includeCheckpoint ? { checkpoint: partialCheckpoint ? { ...partialCheckpoint, available: true } : { available: false, final: false, reason: "checkpoint_missing" } } : {}
|
|
2848
3336
|
}) + "\n");
|
|
2849
3337
|
return 0;
|
|
@@ -2878,6 +3366,9 @@ function printStatusOnce(record, deps) {
|
|
|
2878
3366
|
deps.output.write(`status: ${record.status}
|
|
2879
3367
|
`);
|
|
2880
3368
|
deps.output.write(`pid: ${record.pid ?? "-"}
|
|
3369
|
+
`);
|
|
3370
|
+
const recovery = localWriterRecovery(record);
|
|
3371
|
+
if (recovery) deps.output.write(`writerRecovery: required (${recovery.reason}); automatic release forbidden; native launch evidence required
|
|
2881
3372
|
`);
|
|
2882
3373
|
deps.output.write(`agent: ${record.agentKey}
|
|
2883
3374
|
`);
|
|
@@ -3135,6 +3626,16 @@ async function runAgentStopCommand(args, deps) {
|
|
|
3135
3626
|
async function runAgentKillCommand(args, deps) {
|
|
3136
3627
|
return runSignalCommand(args, "SIGKILL", "kill", deps);
|
|
3137
3628
|
}
|
|
3629
|
+
async function runAgentRecoverPreparedWriterCommand(args, deps) {
|
|
3630
|
+
if (args.length !== 3 || args[1] !== "--attempt-id" || !/^[A-Za-z0-9_-]+$/.test(args[0] ?? "") || !args[2] || args[2].startsWith("-")) {
|
|
3631
|
+
deps.output.write("Usage: nolo agent recover-prepared-writer <runId> --attempt-id <attemptId>\n");
|
|
3632
|
+
return 1;
|
|
3633
|
+
}
|
|
3634
|
+
const [runId, , attemptId] = args;
|
|
3635
|
+
const outcome = revokePreparedWriterLaunch(runId, attemptId, deps);
|
|
3636
|
+
deps.output.write(JSON.stringify({ action: "recoverPreparedWriter", runId, attemptId, outcome }) + "\n");
|
|
3637
|
+
return outcome === "blocked" ? 1 : 0;
|
|
3638
|
+
}
|
|
3138
3639
|
|
|
3139
3640
|
export {
|
|
3140
3641
|
createShellApprovalChild,
|
|
@@ -3145,6 +3646,8 @@ export {
|
|
|
3145
3646
|
recordRunResultHeaderMeta,
|
|
3146
3647
|
getRunResultHeaderMeta,
|
|
3147
3648
|
serverOriginForDialog,
|
|
3649
|
+
stripResultFrontMatter,
|
|
3650
|
+
isHistoryIntegrityFailure,
|
|
3148
3651
|
RUN_TERMINAL_STATUSES,
|
|
3149
3652
|
isRunTerminalStatus,
|
|
3150
3653
|
resolveNoloHome,
|
|
@@ -3192,6 +3695,12 @@ export {
|
|
|
3192
3695
|
absolutizeSkillArgs,
|
|
3193
3696
|
rewriteMsgFileArg,
|
|
3194
3697
|
buildAgentRunChildCommand,
|
|
3698
|
+
localWriterRecovery,
|
|
3699
|
+
revokePreparedWriterLaunch,
|
|
3700
|
+
validateLocalWriterChild,
|
|
3701
|
+
awaitLocalWriterChild,
|
|
3702
|
+
resolveLocalContinuation,
|
|
3703
|
+
registerLocalForegroundWriter,
|
|
3195
3704
|
spawnLocalBackgroundRun,
|
|
3196
3705
|
ackRunRecord,
|
|
3197
3706
|
DEFAULT_ACK_LEASE_TTL_MS,
|
|
@@ -3219,5 +3728,6 @@ export {
|
|
|
3219
3728
|
TERMINATE_KILL_GRACE_MS,
|
|
3220
3729
|
terminateRunProcess,
|
|
3221
3730
|
runAgentStopCommand,
|
|
3222
|
-
runAgentKillCommand
|
|
3731
|
+
runAgentKillCommand,
|
|
3732
|
+
runAgentRecoverPreparedWriterCommand
|
|
3223
3733
|
};
|