nolo-cli 0.212.0-alpha.1 → 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-KE6MBNUJ.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-N2YC5IL3.js → addContentAction-GDHDOF4U.js} +18 -17
- package/{addDialogAgentAction-3NKVQCEC.js → addDialogAgentAction-CAKRU3ZT.js} +21 -20
- package/{agentDeleteCommand-NWK7VU4N.js → agentDeleteCommand-BPV2XZL7.js} +128 -119
- package/{agentEmailCommands-UZ4DHEX2.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-HE7L2A6L.js → agentListCommands-HIZODBF3.js} +196 -124
- package/{agentMachineCommands-6TE4MBMP.js → agentMachineCommands-ZMQ2CY7Y.js} +62 -53
- 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-OI3LOENH.js → agentRunControl-JNONH3RP.js} +30 -15
- package/{agentRuntimeLocal-HL526DNQ.js → agentRuntimeLocal-QZPFWMLG.js} +52 -45
- package/{agentSlice-TMYP2UEA.js → agentSlice-RD2CDU7T.js} +20 -19
- package/{appDeleteCommands-ZERW4AXY.js → appDeleteCommands-QCCFDIEQ.js} +61 -52
- package/{appDeployCommands-DUWSMYHL.js → appDeployCommands-V2T7TNMQ.js} +61 -52
- package/{appDeployStatusCommands-N2KIE4BF.js → appDeployStatusCommands-6PGH7ZCG.js} +61 -52
- package/{appGetCommands-YVR4NPVY.js → appGetCommands-3L7WWJA6.js} +61 -52
- package/{appListCommands-JS6HOHZS.js → appListCommands-ENJCK4PO.js} +61 -52
- package/{authCommand-FE2C3ZUM.js → authCommand-6V47SYGK.js} +29 -28
- package/{authCommands-HV3EAU3V.js → authCommands-GAJ3NIXO.js} +14 -13
- package/{builtinSkillRegistry-3YOIGEF6.js → builtinSkillRegistry-2ECA42FC.js} +11 -13
- package/{chromeCommands-REEAH4SX.js → chromeCommands-G5UDKVSV.js} +3 -3
- package/{chromeOpsCommands-HEN5AX2J.js → chromeOpsCommands-YKX2QX3A.js} +20 -10
- package/{chunk-DM6UMOEL.js → chunk-27PCUMJI.js} +2 -2
- package/chunk-2CI3ZFWD.js +97 -0
- package/{chunk-HIRC32DV.js → chunk-2GJKRKI6.js} +543 -29
- package/{chunk-SM3NSZJV.js → chunk-2UCBGYO4.js} +20 -1
- package/{chunk-PYRUW7XN.js → chunk-2VUZSVAS.js} +136 -54
- package/chunk-2YGBI2XB.js +30 -0
- package/chunk-2ZKFCIJJ.js +13 -0
- package/{chunk-CJRONOYL.js → chunk-34J5K2YA.js} +19 -75
- 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-LKDF3ATR.js → chunk-5RKUPJYL.js} +1 -1
- package/{chunk-ZC3CMUKU.js → chunk-6OVNSQHN.js} +84 -2
- package/{chunk-IF45XG7K.js → chunk-6WU5572L.js} +40 -24
- package/{chunk-OHNELDTO.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-IIQ6JGRI.js → chunk-AD5EWDFD.js} +2 -2
- package/{chunk-WXYLV624.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-PJNFNEJE.js → chunk-AMEOV5VZ.js} +59 -13
- package/chunk-AN74ON4G.js +675 -0
- package/{chunk-HRMJUN5J.js → chunk-AQZ6BMRK.js} +1 -1
- package/{chunk-CQ46IRNN.js → chunk-B4GOW4MT.js} +445 -201
- 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-D2MDMY2M.js → chunk-BV3FLP2L.js} +47 -1
- package/{chunk-25JZEIXN.js → chunk-C4VAR65S.js} +92 -150
- package/{chunk-AVTVGMDY.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-M6RL5JCD.js → chunk-CMZ3Z5PT.js} +14 -14
- package/{secretCommands-4QS3HCA2.js → chunk-D726I5AZ.js} +191 -16
- package/{chunk-INSBKSBB.js → chunk-DNKTQ3IN.js} +4 -4
- package/chunk-DVQH4BTR.js +1137 -0
- package/{chunk-SOHTHFV2.js → chunk-DWX2HEVC.js} +91 -132
- package/{chunk-NOMIGOST.js → chunk-EIAI3PPH.js} +116 -124
- package/chunk-EUCFKKDM.js +247 -0
- package/chunk-EWQ3HGNZ.js +90 -0
- package/{chunk-RPQXPZZF.js → chunk-F3GRJO4Z.js} +908 -13
- package/{chunk-GSQNH63I.js → chunk-FIYSMXHY.js} +3 -19
- package/{chunk-KSTEXKL6.js → chunk-FJ23FZXF.js} +76 -31
- package/{chunk-INN4LTAJ.js → chunk-FJK526XH.js} +2 -2
- package/chunk-FS2XP5D7.js +142 -0
- package/{chunk-QT6PKHYJ.js → chunk-FYF2TONJ.js} +5 -5
- package/{chunk-OXME3PEE.js → chunk-GBWGPTA7.js} +2 -1
- package/{chunk-RU4SD66C.js → chunk-GYVCJABP.js} +30 -254
- package/{chunk-YUXQAVRD.js → chunk-HOCHUZQ7.js} +257 -90
- package/{chunk-Y2WUYX4I.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-5RYBGBQH.js → chunk-IILMY4W4.js} +14 -9
- package/chunk-JA3ICVJY.js +271 -0
- package/{chunk-ZRSNONOB.js → chunk-JWXITTQB.js} +8 -3
- package/{chunk-JNKSDZFS.js → chunk-KEN3N2TN.js} +310 -66
- 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-6OQUPIQF.js → chunk-LVL6GFCM.js} +4 -4
- package/{chunk-UTV2AYEG.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-B7NJ3T4A.js → chunk-MS4NZNKI.js} +10 -10
- package/{chunk-3AKFVZ2I.js → chunk-MYHNBEXD.js} +3 -3
- package/{chunk-VZKUKCA6.js → chunk-MZLE5HQ3.js} +3673 -241
- package/{chunk-AZMYUSVF.js → chunk-N5Z2V73W.js} +1 -1
- package/chunk-NIZ2BXFD.js +526 -0
- package/{chunk-YPD3VJZW.js → chunk-NWP2OYOX.js} +20 -20
- package/{chunk-3FOQHGHN.js → chunk-O6J3OTOP.js} +4 -4
- package/{chunk-3RQVYR4B.js → chunk-OB6DVWPF.js} +197 -65
- package/{chunk-YWSEPJ7C.js → chunk-OBWT45ZU.js} +3 -3
- package/{chunk-5AQR3DGV.js → chunk-ODJ7BVSI.js} +80 -11
- package/{chunk-XJWWBO34.js → chunk-OJKUU3LP.js} +5 -7
- package/{chunk-GNDJKC4B.js → chunk-ON37YXGX.js} +29 -29
- package/{chunk-D5RCRX4A.js → chunk-P5ZJRTCH.js} +9415 -5169
- package/{chunk-6XIE5ZGI.js → chunk-PDCV7P5W.js} +1 -1
- package/{chunk-EZFQ6XRV.js → chunk-PJCIP64Z.js} +861 -59
- package/{chunk-GPO7FCEZ.js → chunk-PJVKMGPZ.js} +1222 -1719
- package/{chunk-CKAHAVMK.js → chunk-PPJYZRSQ.js} +40 -26
- package/chunk-QHEN7NZ7.js +46 -0
- package/{chunk-4KH4J3G5.js → chunk-QNWG52I4.js} +19 -7
- package/{chunk-YGILMZ7N.js → chunk-QVBXJNZ2.js} +1 -1
- package/chunk-RDH5CQ4T.js +1382 -0
- 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-IAPCBNEE.js → chunk-SQYIK6HO.js} +1 -1
- package/{chunk-22CIEBYO.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-6NSSLV67.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-MMNYUVLW.js → chunk-UB3D4TRQ.js} +11 -77
- package/{chunk-WPORQFYN.js → chunk-UVLYNWIE.js} +2 -2
- package/{chunk-YOIW77S2.js → chunk-UYOICCYG.js} +29 -19
- package/{chunk-4I7ERB7F.js → chunk-VREDDN25.js} +1 -1
- package/{chunk-JIT6FSXJ.js → chunk-WAE3GFCJ.js} +3 -3
- package/{chunk-IJXYFTV7.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-YJMRHHGY.js → chunk-WUUH4LWZ.js} +60 -30
- package/{chunk-PDGKOTO7.js → chunk-X7UF53VA.js} +33 -22
- package/{chunk-TY3TIUJK.js → chunk-XI2BWJM5.js} +65 -0
- package/{chunk-OOF4UPC5.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-NJR3WKVP.js → chunk-YWWDC3O7.js} +281 -159
- package/chunk-YZMNK53S.js +68 -0
- package/{chunk-FHU44LN3.js → chunk-Z2PITYZN.js} +2179 -552
- 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-VVMTPFAX.js → commandRegistry-5DA5UP7S.js} +106 -98
- package/{contentThunks-N52O67MI.js → contentThunks-5GUQ7FWJ.js} +47 -43
- package/{cooldownCommands-YXLWOXWR.js → cooldownCommands-X7P5M2V5.js} +5 -4
- package/{createAgentAutomationAction-ZC57YRSV.js → createAgentAutomationAction-UCLTHQRI.js} +51 -49
- package/{createDialogAction-VQW5WDYX.js → createDialogAction-UPN774AF.js} +46 -48
- package/{createPageAction-M5VDA7SC.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-HP7G4LX3.js → dbSlice-WNON7TOL.js} +17 -16
- package/{deleteFile-7VQGLK2V.js → deleteFile-Q3YDB4ML.js} +9 -9
- package/{desktopFolderProjects-SFY5EZS3.js → desktopFolderProjects-4POAMVJN.js} +2 -2
- package/{dialogCommands-JHMR2N2Y.js → dialogCommands-VRI7VCXH.js} +64 -57
- package/dialogNotifyCommand-6TMCX4D2.js +36 -0
- package/{dialogSlice-GRSVGDTF.js → dialogSlice-LFNVUSAN.js} +42 -40
- package/{dialogUsageCommand-7KCPYGHG.js → dialogUsageCommand-HTVPR2CX.js} +11 -10
- package/{docCreateCommands-F2K3UPSQ.js → docCreateCommands-AMPXMOX3.js} +61 -54
- package/{docDeleteCommands-XGXB5RFT.js → docDeleteCommands-I5WFAEHP.js} +63 -57
- package/{docReadCommands-7HWZZV6J.js → docReadCommands-X53ELNIE.js} +61 -54
- package/{docStore-KNZK6Y2G.js → docStore-2VAWVLWH.js} +21 -20
- package/{docUpdateCommands-OZZ7NQII.js → docUpdateCommands-6QPNDC7M.js} +64 -57
- package/{fetchMessages-M3QU7ZCQ.js → fetchMessages-TQEUZD7H.js} +8 -7
- package/{getPricing-2MNMXEVG.js → getPricing-MB2GBXOK.js} +6 -6
- package/{handleSendMessageAction-SHIH74GJ.js → handleSendMessageAction-AAJOHXOB.js} +193 -301
- package/{hostCredentialCreate-X64WK4JD.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-XRLAH4CZ.js → localDialogRead-SVTPA5GY.js} +3 -3
- package/{localFirstLog-DHNOY2NA.js → localFirstLog-OIETGK66.js} +1 -1
- package/localRecall-2J6QPOK2.js +15 -0
- package/{localRuntimeAdapter-A7K3ABA6.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-DE3MR7CJ.js → machineCommands-3MLIAK5Q.js} +128 -119
- package/{machineInfo-UKPTZO5Y.js → machineInfo-LWHTEBHJ.js} +1 -1
- package/machineWsRunDispatch-FKIGROQF.js +191 -0
- package/{memberThunks-7WJAY5V6.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-GGL5HLMD.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-4VZQODSN.js → read-MRQHJMJ2.js} +10 -10
- package/{readDocTool-AVD32RUJ.js → readDocTool-4BGTXTXA.js} +2 -2
- package/{readlineWorkspace-XKYKNL2I.js → readlineWorkspace-AKAHSCNY.js} +6505 -4634
- package/{removeDialogAgentAction-FKL4BYMR.js → removeDialogAgentAction-B6H7DXFM.js} +23 -22
- package/{runAgentClientLoop-V7E2WBVM.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-TLIOLWWI.js → setDialogExtraReferencesAction-EVCY3TRW.js} +22 -21
- package/{setPrimaryDialogAgentAction-2OLWRFYR.js → setPrimaryDialogAgentAction-KPFVPHCJ.js} +23 -22
- package/{settingThunks-UGBPCNYF.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-4KSLKVNF.js → spaceCommands-DTTNAS2L.js} +61 -53
- package/store-JRVN62NM.js +46 -0
- package/{streamAgentChatTurn-7FR7X2NU.js → streamAgentChatTurn-R5UY25VB.js} +875 -618
- package/{switchDialogAgentAction-UZSAG2N5.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-ZLKCC25W.js → tools-HWFG6GMJ.js} +75 -74
- package/tuiSummaryLlmCaller-HQQZAMYF.js +44 -0
- package/{updateCommands-4744PL3P.js → updateCommands-RJVCRSBP.js} +10 -8
- package/{updateDialogTitleAction-U53ZT7PJ.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-XSQVF2GK.js → windowsSelfUpdate-KERHIAB4.js} +3 -3
- package/{workloadLifecycle-4BEQHMSD.js → workloadLifecycle-DYNEYHV5.js} +7 -6
- package/agentRecordCommands-L3QQ7HZ4.js +0 -167
- package/agentRunCommand-2IFGQHCO.js +0 -196
- package/chunk-3CGG2PAL.js +0 -594
- package/chunk-5XBUWM6I.js +0 -89
- package/chunk-BFM34N54.js +0 -842
- package/chunk-CJEIOP3E.js +0 -0
- package/chunk-CZM5YTZ7.js +0 -977
- package/chunk-EYUBHHFB.js +0 -636
- package/chunk-JTDORD5P.js +0 -415
- package/chunk-NRFKLKRU.js +0 -339
- package/chunk-VPAZOH2D.js +0 -115
- package/chunk-WJZOQR2J.js +0 -151
- package/chunk-ZCWRMUWT.js +0 -89
- package/dist-M676ULYG.js +0 -7314
- package/machineWsRunDispatch-R26P5V36.js +0 -182
- package/models-PJBE6JDV.js +0 -9
- package/tuiSummaryLlmCaller-WC54MVGP.js +0 -160
- 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() } : {},
|
|
@@ -2293,8 +2653,12 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2293
2653
|
const childEnv = {
|
|
2294
2654
|
...env,
|
|
2295
2655
|
NOLO_AGENT_RUN_CHILD: "1",
|
|
2296
|
-
NOLO_AGENT_RUN_ID: runId
|
|
2656
|
+
NOLO_AGENT_RUN_ID: runId,
|
|
2657
|
+
...record.writerLaunch ? { NOLO_WRITER_LAUNCH_ATTEMPT: record.writerLaunch.attemptId } : {}
|
|
2297
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;
|
|
2298
2662
|
let hostMemory = null;
|
|
2299
2663
|
let reservation;
|
|
2300
2664
|
const logFd = fs.openSync(logPath, "a");
|
|
@@ -2308,6 +2672,8 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2308
2672
|
...fs.statSync ? { statSync: (path) => ({ mtimeMs: fs.statSync(path).mtimeMs }) } : {}
|
|
2309
2673
|
};
|
|
2310
2674
|
let proc;
|
|
2675
|
+
let preparedScope;
|
|
2676
|
+
const launchScope = (r) => JSON.stringify({ cwd: r.cwd, execution: r.execution, claim: r.localWriterClaim, publication: r.ownerPublication });
|
|
2311
2677
|
try {
|
|
2312
2678
|
reservation = reserveHostMemory({
|
|
2313
2679
|
runsDir,
|
|
@@ -2319,8 +2685,14 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2319
2685
|
getProcessStartTime: () => null,
|
|
2320
2686
|
withLock: (id, fn, opts) => withRunRecordLock(id, resolvedDeps, fn, opts)
|
|
2321
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
|
+
}
|
|
2322
2694
|
proc = spawn(execPath, childArgs, {
|
|
2323
|
-
cwd:
|
|
2695
|
+
cwd: spawnCwd,
|
|
2324
2696
|
env: childEnv,
|
|
2325
2697
|
detached: true,
|
|
2326
2698
|
// Detached on Windows means no console; hide the one its children would create.
|
|
@@ -2330,6 +2702,7 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2330
2702
|
} catch (error) {
|
|
2331
2703
|
try {
|
|
2332
2704
|
reservation?.release("spawn_sync_failed");
|
|
2705
|
+
if (input.claimLocalWrites) releaseUnspawnedLocalWriterClaim(runId, resolvedDeps);
|
|
2333
2706
|
} finally {
|
|
2334
2707
|
finalizeRunRecord(runId, { status: "failed", exitCode: 1, note: String(error) }, resolvedDeps);
|
|
2335
2708
|
}
|
|
@@ -2352,13 +2725,56 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2352
2725
|
});
|
|
2353
2726
|
const hostMemoryNotice = emitHostMemoryNotice(hostMemory, input.output);
|
|
2354
2727
|
if (typeof proc.pid === "number") {
|
|
2355
|
-
|
|
2356
|
-
|
|
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
|
+
}
|
|
2357
2751
|
latest.pid = proc.pid;
|
|
2358
|
-
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";
|
|
2359
2770
|
writeRunRecord(latest, resolvedDeps);
|
|
2360
2771
|
return true;
|
|
2361
|
-
}, { 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
|
+
}
|
|
2362
2778
|
try {
|
|
2363
2779
|
const persisted = readRunRecord(runId, resolvedDeps);
|
|
2364
2780
|
reservation.associate({ runId, pid: proc.pid, processStartedAt: persisted?.processStartedAt });
|
|
@@ -2383,6 +2799,8 @@ async function spawnLocalBackgroundRun(input, deps = {}) {
|
|
|
2383
2799
|
logPath,
|
|
2384
2800
|
queuePath,
|
|
2385
2801
|
batchId,
|
|
2802
|
+
agentName: record.agentName ?? shortAgentKey(input.agentKey),
|
|
2803
|
+
...input.selectionCheck ? { selectionCheck: input.selectionCheck } : {},
|
|
2386
2804
|
...hostMemoryNotice ? { hostMemoryNotice } : {}
|
|
2387
2805
|
};
|
|
2388
2806
|
}
|
|
@@ -2491,8 +2909,31 @@ function transitionRunToTerminal(runId, update, deps = {}, options = {}) {
|
|
|
2491
2909
|
if (typeof update.lastAssistantText === "string" && update.lastAssistantText) {
|
|
2492
2910
|
record2.lastAssistantText = update.lastAssistantText.slice(0, 2e3);
|
|
2493
2911
|
}
|
|
2912
|
+
if (update.cacheUsage) {
|
|
2913
|
+
record2.cacheHitRatio = update.cacheUsage.cache_hit_ratio;
|
|
2914
|
+
record2.cacheCachedTokens = update.cacheUsage.cached_tokens;
|
|
2915
|
+
}
|
|
2494
2916
|
record2.endedAt = now().toISOString();
|
|
2495
|
-
|
|
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) {
|
|
2496
2937
|
try {
|
|
2497
2938
|
const fs = deps.fs ?? nodeFs2;
|
|
2498
2939
|
const resultFile = join2(resolveRunsDir(deps.env, deps.homedir), `${runId}.result.md`);
|
|
@@ -2501,6 +2942,7 @@ function transitionRunToTerminal(runId, update, deps = {}, options = {}) {
|
|
|
2501
2942
|
const content = buildResultFileContent(
|
|
2502
2943
|
{
|
|
2503
2944
|
runId,
|
|
2945
|
+
acceptance: update.acceptance,
|
|
2504
2946
|
status: record2.status,
|
|
2505
2947
|
agentName: record2.agentName,
|
|
2506
2948
|
model: update.model,
|
|
@@ -2515,16 +2957,54 @@ function transitionRunToTerminal(runId, update, deps = {}, options = {}) {
|
|
|
2515
2957
|
continuedFrom: record2.continuedFrom,
|
|
2516
2958
|
...update.cacheUsage ? { cacheUsage: update.cacheUsage } : {}
|
|
2517
2959
|
},
|
|
2518
|
-
update.lastAssistantText
|
|
2960
|
+
update.lastAssistantText ?? ""
|
|
2519
2961
|
);
|
|
2520
|
-
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;
|
|
2521
2988
|
record2.resultFile = resultFile;
|
|
2522
2989
|
} catch {
|
|
2990
|
+
resultWriteFailed = true;
|
|
2991
|
+
delete record2.resultFile;
|
|
2992
|
+
if (record2.status === "done") {
|
|
2993
|
+
record2.status = "failed";
|
|
2994
|
+
record2.exitCode = 1;
|
|
2995
|
+
}
|
|
2523
2996
|
}
|
|
2524
2997
|
}
|
|
2525
2998
|
if (typeof update.note === "string" && update.note.trim()) {
|
|
2526
2999
|
record2.note = update.note.trim();
|
|
2527
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
|
+
}
|
|
2528
3008
|
if (record2.note?.startsWith("orphaned:")) record2.note = void 0;
|
|
2529
3009
|
writeRunRecord(record2, deps);
|
|
2530
3010
|
return { kind: "transitioned", record: record2 };
|
|
@@ -2600,10 +3080,10 @@ function defaultGetProcessStartTime(pid, deps = {}) {
|
|
|
2600
3080
|
// 这会让 isPidReused 的结论依赖调用者环境:同一条 run 记录在英文
|
|
2601
3081
|
// locale 下被判 pid reused → orphaned,中文 locale 下不判。强制 C
|
|
2602
3082
|
// locale 让输出恒为可解析的英文格式,结果与 locale 无关。
|
|
2603
|
-
env: { ...process.env, LC_ALL: "C", LANG: "C" }
|
|
3083
|
+
env: { ...process.env, LC_ALL: "C", LANG: "C", TZ: "UTC" }
|
|
2604
3084
|
}).trim();
|
|
2605
3085
|
if (!output) return null;
|
|
2606
|
-
const d = new Date(output);
|
|
3086
|
+
const d = new Date(output.endsWith("Z") || /[+-]\d\d:\d\d$/.test(output) ? output : `${output} UTC`);
|
|
2607
3087
|
return isNaN(d.getTime()) ? null : d;
|
|
2608
3088
|
} catch {
|
|
2609
3089
|
return null;
|
|
@@ -2655,6 +3135,7 @@ function checkStaleRun(runId, deps = {}) {
|
|
|
2655
3135
|
const latest = readRunRecord(runId, deps);
|
|
2656
3136
|
if (!latest) return record;
|
|
2657
3137
|
if (latest.status !== "running") return latest;
|
|
3138
|
+
if (latest.pid !== record.pid || latest.processStartedAt !== record.processStartedAt || latest.processIdentity !== record.processIdentity) return latest;
|
|
2658
3139
|
if (latest.activity?.updatedAt !== record.activity?.updatedAt) return latest;
|
|
2659
3140
|
const at = now().toISOString();
|
|
2660
3141
|
latest.status = "orphaned";
|
|
@@ -2670,6 +3151,16 @@ function checkStaleRun(runId, deps = {}) {
|
|
|
2670
3151
|
}
|
|
2671
3152
|
latest.endedAt = at;
|
|
2672
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
|
+
};
|
|
2673
3164
|
latest.pid = void 0;
|
|
2674
3165
|
writeRunRecord(latest, deps);
|
|
2675
3166
|
return latest;
|
|
@@ -2840,6 +3331,7 @@ async function runAgentStatusCommand(args, deps) {
|
|
|
2840
3331
|
const { partialCheckpoint, ...summary } = record;
|
|
2841
3332
|
deps.output.write(JSON.stringify({
|
|
2842
3333
|
...summary,
|
|
3334
|
+
...localWriterRecovery(record) ? { writerRecovery: localWriterRecovery(record) } : {},
|
|
2843
3335
|
...includeCheckpoint ? { checkpoint: partialCheckpoint ? { ...partialCheckpoint, available: true } : { available: false, final: false, reason: "checkpoint_missing" } } : {}
|
|
2844
3336
|
}) + "\n");
|
|
2845
3337
|
return 0;
|
|
@@ -2874,6 +3366,9 @@ function printStatusOnce(record, deps) {
|
|
|
2874
3366
|
deps.output.write(`status: ${record.status}
|
|
2875
3367
|
`);
|
|
2876
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
|
|
2877
3372
|
`);
|
|
2878
3373
|
deps.output.write(`agent: ${record.agentKey}
|
|
2879
3374
|
`);
|
|
@@ -3131,16 +3626,28 @@ async function runAgentStopCommand(args, deps) {
|
|
|
3131
3626
|
async function runAgentKillCommand(args, deps) {
|
|
3132
3627
|
return runSignalCommand(args, "SIGKILL", "kill", deps);
|
|
3133
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
|
+
}
|
|
3134
3639
|
|
|
3135
3640
|
export {
|
|
3136
|
-
TAIL_LINES_MAX,
|
|
3137
3641
|
createShellApprovalChild,
|
|
3642
|
+
TAIL_LINES_MAX,
|
|
3138
3643
|
readHostMemory,
|
|
3139
3644
|
assertHostMemoryAdmission,
|
|
3140
3645
|
resolveResultServerMeta,
|
|
3141
3646
|
recordRunResultHeaderMeta,
|
|
3142
3647
|
getRunResultHeaderMeta,
|
|
3143
3648
|
serverOriginForDialog,
|
|
3649
|
+
stripResultFrontMatter,
|
|
3650
|
+
isHistoryIntegrityFailure,
|
|
3144
3651
|
RUN_TERMINAL_STATUSES,
|
|
3145
3652
|
isRunTerminalStatus,
|
|
3146
3653
|
resolveNoloHome,
|
|
@@ -3188,6 +3695,12 @@ export {
|
|
|
3188
3695
|
absolutizeSkillArgs,
|
|
3189
3696
|
rewriteMsgFileArg,
|
|
3190
3697
|
buildAgentRunChildCommand,
|
|
3698
|
+
localWriterRecovery,
|
|
3699
|
+
revokePreparedWriterLaunch,
|
|
3700
|
+
validateLocalWriterChild,
|
|
3701
|
+
awaitLocalWriterChild,
|
|
3702
|
+
resolveLocalContinuation,
|
|
3703
|
+
registerLocalForegroundWriter,
|
|
3191
3704
|
spawnLocalBackgroundRun,
|
|
3192
3705
|
ackRunRecord,
|
|
3193
3706
|
DEFAULT_ACK_LEASE_TTL_MS,
|
|
@@ -3215,5 +3728,6 @@ export {
|
|
|
3215
3728
|
TERMINATE_KILL_GRACE_MS,
|
|
3216
3729
|
terminateRunProcess,
|
|
3217
3730
|
runAgentStopCommand,
|
|
3218
|
-
runAgentKillCommand
|
|
3731
|
+
runAgentKillCommand,
|
|
3732
|
+
runAgentRecoverPreparedWriterCommand
|
|
3219
3733
|
};
|