nolo-cli 0.32.0 → 0.33.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/README.md +6 -12
  2. package/{_executeModel-LTMSIBS4.js → _executeModel-YXWAXPWQ.js} +77 -67
  3. package/{action-HI3VRQLP.js → action-OQWPNKAH.js} +17 -15
  4. package/{addContentAction-NCURJ6PK.js → addContentAction-YVINZQTF.js} +14 -13
  5. package/{addDialogAgentAction-RCY4ECF4.js → addDialogAgentAction-6IOCIEPI.js} +14 -13
  6. package/{agentDeleteCommand-D3MYZK6E.js → agentDeleteCommand-VGHWJN5T.js} +44 -60
  7. package/{agentEmailCommands-6BXS574I.js → agentEmailCommands-ZLRF35I3.js} +91 -81
  8. package/{agentGrantCommands-E7ZZFRHK.js → agentGrantCommands-2LEZDADN.js} +2 -2
  9. package/{agentListCommands-SF3HEUTT.js → agentListCommands-OHZJ7AFP.js} +75 -79
  10. package/{agentMachineCommands-YARVXRR6.js → agentMachineCommands-62PHPGTK.js} +43 -59
  11. package/{agentPullCommand-ARSIDNVC.js → agentPullCommand-TSWAJPS2.js} +5 -5
  12. package/agentRecordCommands-CW2JWERD.js +113 -0
  13. package/agentRunCommand-O4HV7YWA.js +131 -0
  14. package/{agentRuntimeLocal-ATGJY6WC.js → agentRuntimeLocal-4PSBNUOE.js} +37 -51
  15. package/{agentSlice-4XWW344Y.js → agentSlice-OUTQ5O72.js} +16 -14
  16. package/{appDeleteCommands-63JO7RXS.js → appDeleteCommands-VTDBVHYR.js} +40 -56
  17. package/{appDeployCommands-Y7EWYUGM.js → appDeployCommands-WOUP7MDA.js} +40 -56
  18. package/{appDeployStatusCommands-ZBEY3DWB.js → appDeployStatusCommands-N2NWZKEN.js} +40 -56
  19. package/{appGetCommands-QSSOSEYL.js → appGetCommands-GYKLWWCA.js} +40 -56
  20. package/{appListCommands-PH3XWNDX.js → appListCommands-RUWBSEJK.js} +40 -56
  21. package/{authCommand-BBDHMSO6.js → authCommand-YVXVH25I.js} +21 -20
  22. package/{authCommands-4UDEKRE6.js → authCommands-WTW6MEYS.js} +10 -10
  23. package/chatQueueReduxAdapter-2QJAD4KQ.js +181 -0
  24. package/{chunk-EEF23OOK.js → chunk-266VUBLK.js} +7 -7
  25. package/{chunk-TEYN42N3.js → chunk-2IVEXF7P.js} +11 -4
  26. package/{chunk-2HXKAPH7.js → chunk-2QLAVHVK.js} +6 -6
  27. package/{chunk-WTGCTVJG.js → chunk-2QTEYCR7.js} +3 -6
  28. package/{chunk-DOISARTV.js → chunk-2UECQ7RE.js} +1 -1
  29. package/{chunk-E3APEOIM.js → chunk-3GZXL6FM.js} +4 -19
  30. package/{chunk-KGEVMUMI.js → chunk-3RUW3ONU.js} +11 -11
  31. package/{chunk-RXVX5LFR.js → chunk-3UG2IIZ3.js} +1 -1
  32. package/{chunk-O5OMJPPF.js → chunk-3WXRAHCG.js} +6 -5
  33. package/{chunk-V54H24CQ.js → chunk-4F5M2MW5.js} +3 -3
  34. package/{chunk-2ZRP5RUG.js → chunk-4OV7DXFJ.js} +12 -11
  35. package/{chunk-W367V5CH.js → chunk-54BAYVCY.js} +404 -117
  36. package/{chunk-GAF5X6B7.js → chunk-5QW3O3ET.js} +284 -310
  37. package/{chunk-DLWCWUNW.js → chunk-64OVNZXE.js} +1197 -757
  38. package/{chunk-ODS2MVMU.js → chunk-66CWPJK2.js} +19 -303
  39. package/{chunk-PTHDLIRB.js → chunk-6KOS7ZBZ.js} +1 -1
  40. package/{chunk-MXFQHRSS.js → chunk-6XIE5ZGI.js} +1 -1
  41. package/{chunk-ATK5WJOA.js → chunk-6YXDOOSH.js} +4 -4
  42. package/{chunk-SWYMCHM7.js → chunk-75U775RZ.js} +69 -1
  43. package/{chunk-UDA3ZYLW.js → chunk-7YYHKBJP.js} +31 -72
  44. package/chunk-ADLYMQB6.js +642 -0
  45. package/{chunk-ZWJOGMKH.js → chunk-AETZ7AD6.js} +1 -1
  46. package/{chunk-43EPBPZ2.js → chunk-ASDXPOJH.js} +2 -2
  47. package/{chunk-44HACRCK.js → chunk-BANYWEYY.js} +4 -4
  48. package/chunk-BFPSVRCQ.js +1799 -0
  49. package/{chunk-TOW4E763.js → chunk-BJIRLHJR.js} +2 -0
  50. package/{chunk-ZJ2WITOO.js → chunk-BQXOGBFN.js} +2 -2
  51. package/{chunk-4PNU7W7K.js → chunk-C7H5GMXT.js} +107 -125
  52. package/chunk-CPYYM4RJ.js +98 -0
  53. package/{chunk-3GZT3L6F.js → chunk-DDVIBKIB.js} +326 -481
  54. package/{chunk-2K4NDPT5.js → chunk-DFUPZE6V.js} +20 -12
  55. package/{chunk-BGTUGS3T.js → chunk-DKMOY3QI.js} +4 -30
  56. package/chunk-EGRJC4ZN.js +91 -0
  57. package/{chunk-K6QEHQZ3.js → chunk-EKLRRZIN.js} +1 -1
  58. package/{chunk-6HYVJV7B.js → chunk-ESHYE7WU.js} +2 -1
  59. package/{chunk-XFG3BAKN.js → chunk-FMEVI5TG.js} +65 -0
  60. package/{chunk-U4TRT5V4.js → chunk-GEPHJJW4.js} +1 -1
  61. package/chunk-GJXRIOLS.js +241 -0
  62. package/{chunk-VP4WJWKW.js → chunk-GM6PU7B6.js} +431 -345
  63. package/chunk-HS7MLR74.js +38 -0
  64. package/{chunk-3AUWC6EM.js → chunk-HUCT7HID.js} +5 -84
  65. package/chunk-IDAU4UFS.js +437 -0
  66. package/{chunk-Q76I4SXI.js → chunk-IHEC7VBF.js} +1 -1
  67. package/{chunk-OWHNFZNW.js → chunk-IKWTTKWG.js} +4 -4
  68. package/{chunk-3LY4F7SV.js → chunk-INZZJSQF.js} +348 -331
  69. package/{chunk-ZJH3LKEW.js → chunk-IR6W62Q6.js} +102 -15
  70. package/{chunk-RH53LMEJ.js → chunk-J44TVX2O.js} +2 -4
  71. package/{chunk-CF2WZF4N.js → chunk-J6WH4PYZ.js} +0 -8
  72. package/chunk-KHCLMKZZ.js +3062 -0
  73. package/{chunk-WHLVPK32.js → chunk-KMSZPTM6.js} +27 -3
  74. package/{chunk-L3GCUVOH.js → chunk-KSRFVP36.js} +1 -1
  75. package/{chunk-XDHHF73Q.js → chunk-LUIHOUZC.js} +95 -95
  76. package/{chunk-UOJRKY5J.js → chunk-M2YMQOLC.js} +44 -53
  77. package/chunk-M3JEW6N6.js +193 -0
  78. package/{chunk-MITD7CON.js → chunk-MDIAECHA.js} +1461 -301
  79. package/{chunk-IXZX5CJK.js → chunk-MQRZ5QUH.js} +1 -1
  80. package/{chunk-3ASDTTEI.js → chunk-MRWGHF56.js} +2 -0
  81. package/{chunk-Q3CSL43H.js → chunk-N4XRDM26.js} +1 -1
  82. package/{chunk-D34RI6NI.js → chunk-NNWHHCVP.js} +75 -1
  83. package/{chunk-CAENRKNJ.js → chunk-OR2HNLVO.js} +126 -88
  84. package/chunk-OW765XBU.js +10 -0
  85. package/{chunk-VMWR7VNI.js → chunk-PRMMCFIN.js} +13 -9
  86. package/{chunk-JZPBVBIY.js → chunk-QTZD6HBK.js} +18 -8
  87. package/chunk-RCFIB45Q.js +28 -0
  88. package/{chunk-7S54ZGF6.js → chunk-RJKIB55Y.js} +256 -12
  89. package/chunk-RPRRIFXV.js +231 -0
  90. package/chunk-RQFO3CAF.js +300 -0
  91. package/chunk-RY57GLGW.js +188 -0
  92. package/{chunk-YHGHADBQ.js → chunk-SCUETSRP.js} +4 -4
  93. package/{chunk-TA6EA2A3.js → chunk-TFK3HUNQ.js} +182 -20
  94. package/{chunk-LAXMH7JY.js → chunk-UM4H3URE.js} +18 -15
  95. package/{chunk-6YABCOFU.js → chunk-UNHKVD2N.js} +1 -1
  96. package/{chunk-G5GVZAXF.js → chunk-UNOTBWZZ.js} +15 -19
  97. package/{chunk-GE6IWA5N.js → chunk-UNZDCI3O.js} +126 -1
  98. package/chunk-URMS4XY2.js +10 -0
  99. package/{chunk-SFWZUTCI.js → chunk-VBUQYOX7.js} +2 -2
  100. package/{chunk-FXFGNOT2.js → chunk-VFVCYIRQ.js} +1 -1
  101. package/chunk-VIDPVFP3.js +20 -0
  102. package/{chunk-5RDLGLAP.js → chunk-WJSW43QZ.js} +4 -7
  103. package/{chunk-CF7S2RYZ.js → chunk-WLH5BAKX.js} +6 -6
  104. package/{chunk-VVEH6XUE.js → chunk-X2DAEZ3X.js} +1 -1
  105. package/{chunk-2IJAKBK2.js → chunk-X664KVEV.js} +426 -246
  106. package/{chunk-3FCNXC2J.js → chunk-XRO5VGQ6.js} +3735 -1394
  107. package/chunk-Y5GCAMGP.js +9 -0
  108. package/{chunk-O3JR45Q2.js → chunk-YBMI5JAH.js} +44 -44
  109. package/{chunk-V42OE5HT.js → chunk-YDTYDA5W.js} +3 -3
  110. package/chunk-YYLHWIW6.js +48 -0
  111. package/{chunk-AOS5IN2I.js → chunk-ZHYK3N56.js} +1 -1
  112. package/{chunk-PJ2DDQQM.js → chunk-ZURFOV5J.js} +2 -2
  113. package/{chunk-3UGKATZQ.js → chunk-ZWS6DUHX.js} +26 -435
  114. package/chunk-ZZ2MH7LE.js +84 -0
  115. package/{cliExecutor-BBUVQU4L.js → cliExecutor-DW3PHGEL.js} +2 -2
  116. package/{clipboardy-BVE3LVEH.js → clipboardy-MMBYVRLF.js} +166 -372
  117. package/{codingSkills-V35TRR4Y.js → codingSkills-DY5MINPG.js} +5 -4
  118. package/{createAgentAutomationAction-WLRNE7C4.js → createAgentAutomationAction-H6ZRPXBR.js} +41 -31
  119. package/createDialogAction-UJ6LFJYM.js +61 -0
  120. package/{createPageAction-7YROVZ3W.js → createPageAction-KVPT3IRK.js} +57 -47
  121. package/{db-6DPSJ6WT.js → db-3H3JECGY.js} +45 -5
  122. package/{dbSlice-BBL3PEVW.js → dbSlice-UI2VCBLG.js} +13 -12
  123. package/{deleteFile-RJTEPOT4.js → deleteFile-XQXPBFFB.js} +7 -6
  124. package/dialogCommands-6ASXJP3H.js +82 -0
  125. package/{dialogSlice-N4HPG6HM.js → dialogSlice-B7KCGHMY.js} +37 -29
  126. package/{docCreateCommands-GRA5BHSA.js → docCreateCommands-S4E4MKVC.js} +42 -56
  127. package/{docDeleteCommands-ONIJM5MD.js → docDeleteCommands-M7XLKWRM.js} +44 -58
  128. package/{docReadCommands-H55VQ2US.js → docReadCommands-LSCMW2FR.js} +42 -56
  129. package/{docStore-B5AHDNW5.js → docStore-ZYWZWIRB.js} +40 -30
  130. package/{docUpdateCommands-ZQIQVGC2.js → docUpdateCommands-OMRBAFOB.js} +45 -59
  131. package/{fetchMessages-VPPQDDZ4.js → fetchMessages-7QRCCRYK.js} +3 -3
  132. package/{getPricing-QO5TYNCK.js → getPricing-L2ENXWHV.js} +7 -6
  133. package/{handleSendMessageAction-IN5XX5U7.js → handleSendMessageAction-Y2XKODRT.js} +39 -31
  134. package/index.js +74 -74
  135. package/{lib-FYYBQIXS.js → lib-2ZTNRXR4.js} +432 -183
  136. package/{localDialogRead-3DBXVYXS.js → localDialogRead-SLMPV5SK.js} +2 -2
  137. package/{localRuntimeAuthority-NDUA2D7Y.js → localRuntimeAuthority-S77B5QVB.js} +10 -4
  138. package/{localRuntimeDb-GKYRBWLQ.js → localRuntimeDb-N3H3HQ7G.js} +1 -1
  139. package/{machineCommands-H3UMKE76.js → machineCommands-62RUZVSW.js} +95 -85
  140. package/{machineInfo-M6KB6HZN.js → machineInfo-66ZFUMLE.js} +1 -1
  141. package/machineWsRunDispatch-L3HD3FSF.js +129 -0
  142. package/{models-WDUTTYFS.js → models-OX2S5C6Q.js} +2 -2
  143. package/{offlineMarxistsAgentCommand-E6LUG63A.js → offlineMarxistsAgentCommand-GEH6SNNA.js} +1 -1
  144. package/package.json +1 -4
  145. package/{read-64OQDO3I.js → read-2VHEHCAN.js} +8 -7
  146. package/{readDocTool-MXM3T6PE.js → readDocTool-CSWD6NPC.js} +1 -2
  147. package/{readlineWorkspace-XVJZDCSC.js → readlineWorkspace-3MOJWFM7.js} +3358 -3409
  148. package/{removeDialogAgentAction-NEKVAMSH.js → removeDialogAgentAction-2T7BPM3T.js} +19 -17
  149. package/{runAgentClientLoop-H7U53QB6.js → runAgentClientLoop-Y5UW544I.js} +73 -64
  150. package/{runtimeDoctorCommands-WI2YZUSJ.js → runtimeDoctorCommands-KHGQKT3B.js} +6 -6
  151. package/{setDialogExtraReferencesAction-WTOHQDIV.js → setDialogExtraReferencesAction-GPT37HTW.js} +15 -14
  152. package/{setPrimaryDialogAgentAction-LDJOYC4F.js → setPrimaryDialogAgentAction-3746P7IW.js} +19 -17
  153. package/{settingSlice-4M37TN7V.js → settingSlice-FIFOQ6OR.js} +16 -14
  154. package/{skillDiscovery-5U6RYAHN.js → skillDiscovery-KLLKXPUO.js} +4 -4
  155. package/{slateUtils-2M7MUTWX.js → slateUtils-VO2FU36K.js} +1 -1
  156. package/{spaceCommands-7VVKJBDV.js → spaceCommands-NKSBD5G3.js} +45 -241
  157. package/{spaceSlice-T6YK6D34.js → spaceSlice-L44CI2QR.js} +39 -61
  158. package/{streamAgentChatTurn-RQ63QFQ7.js → streamAgentChatTurn-7DU4Z2VJ.js} +1262 -150
  159. package/{switchDialogAgentAction-XVWGKR2Z.js → switchDialogAgentAction-MQTUTQHL.js} +14 -13
  160. package/syncMapping-RK2MANUX.js +43 -0
  161. package/{tableCommands-RJZ3V4TF.js → tableCommands-64FZBAI3.js} +9 -8
  162. package/{toolApiClient-ARGFDJAG.js → toolApiClient-B2MFXMEG.js} +3 -3
  163. package/tools-2JI52WJP.js +99 -0
  164. package/{tuiSummaryLlmCaller-SRZ4QQUP.js → tuiSummaryLlmCaller-EAWQ3IZX.js} +25 -21
  165. package/{updateCommands-AK2RDOFR.js → updateCommands-MNDUIKN7.js} +2 -2
  166. package/{updateDialogTitleAction-BBDSWHNG.js → updateDialogTitleAction-HW33OIJI.js} +49 -38
  167. package/agentRecordCommands-JFZRQJQ4.js +0 -103
  168. package/agentRunCommand-NOX5FLKO.js +0 -121
  169. package/chunk-AYMOSAHE.js +0 -3158
  170. package/chunk-D2BPX6DQ.js +0 -1707
  171. package/chunk-DCDL3GC4.js +0 -171
  172. package/chunk-F3MP7CP6.js +0 -73
  173. package/chunk-WZSRQNQG.js +0 -2587
  174. package/createDialogAction-Y6YV64QB.js +0 -52
  175. package/dialogCommands-XLO5CAHZ.js +0 -95
  176. package/machineWsRunDispatch-HONRUK3R.js +0 -119
  177. package/tools-KYZX3BGO.js +0 -90
  178. package/{chunk-Z5MXSEOJ.js → chunk-RQSOAMPJ.js} +2 -2
  179. package/{chunk-JDSUTNYY.js → chunk-SAQQLJZ5.js} +3 -3
@@ -1,17 +1,19 @@
1
1
  import {
2
2
  applyChatCompletionDelta,
3
+ applyResponsesToolEvent,
4
+ createResponsesToolAccumulator,
5
+ finalizeResponsesToolCalls,
3
6
  flushChatCompletionStream,
4
7
  providerHttpFailure,
5
8
  readSseFrames,
6
9
  throwIfChatCompletionStreamFailed
7
- } from "./chunk-7S54ZGF6.js";
10
+ } from "./chunk-RJKIB55Y.js";
8
11
  import {
9
12
  sanitizeForOutbound
10
13
  } from "./chunk-T27IEBNQ.js";
11
14
  import {
12
- parseToolArgumentsJson,
13
15
  resolveHistoricalToolContentCap
14
- } from "./chunk-AYMOSAHE.js";
16
+ } from "./chunk-BFPSVRCQ.js";
15
17
  import {
16
18
  createThinkParserState,
17
19
  createToolCallAccumulator,
@@ -22,24 +24,35 @@ import {
22
24
  import {
23
25
  requiresBareImageUrl,
24
26
  toBareImageUrlMessages
25
- } from "./chunk-3UGKATZQ.js";
27
+ } from "./chunk-ZWS6DUHX.js";
26
28
  import {
29
+ convertMessagesToResponsesInput,
30
+ extractReasoningFromResponseOutput,
31
+ extractTextFromResponseOutput,
32
+ extractToolCallsFromResponseOutput,
33
+ getUsageRequestOptions,
27
34
  shouldStripReasoningContentForOutbound,
28
- toOpenAiCompatibleMessages
29
- } from "./chunk-D34RI6NI.js";
35
+ toOpenAiCompatibleMessages,
36
+ toResponsesTools
37
+ } from "./chunk-NNWHHCVP.js";
30
38
  import {
31
39
  buildProviderAuthHeaders,
32
40
  buildProviderExecutionPlan
33
- } from "./chunk-UDA3ZYLW.js";
34
- import {
35
- buildDialogFallbackTitleFromUserInput
36
- } from "./chunk-2MBTWINN.js";
41
+ } from "./chunk-7YYHKBJP.js";
37
42
  import {
38
43
  NOLO_WORKSPACE_TOOL_NAMES,
39
44
  buildNoloWorkspaceCommandArgs,
45
+ noloPositiveIntegerString,
40
46
  noloStringArg,
41
- parseNoloWorkspaceToolArguments
42
- } from "./chunk-D2BPX6DQ.js";
47
+ parseNoloWorkspaceToolArguments,
48
+ resolveNoloDialogInput
49
+ } from "./chunk-ADLYMQB6.js";
50
+ import {
51
+ buildDialogFallbackTitleFromUserInput
52
+ } from "./chunk-2MBTWINN.js";
53
+ import {
54
+ canonicalizeToolName
55
+ } from "./chunk-ZZ2MH7LE.js";
43
56
  import {
44
57
  toErrorMessage
45
58
  } from "./chunk-HNMXYYJR.js";
@@ -47,17 +60,18 @@ import {
47
60
  asRecordOrEmpty
48
61
  } from "./chunk-KX6YBIHG.js";
49
62
  import {
50
- asTrimmedLowercaseString
51
- } from "./chunk-QSJ3HFEF.js";
52
- import {
53
- normalizeServerOrigin
54
- } from "./chunk-CF7PE763.js";
55
- import {
56
- dialogMessageKey
57
- } from "./chunk-WHLVPK32.js";
63
+ dialogMessageKey,
64
+ dialogMessageRange
65
+ } from "./chunk-KMSZPTM6.js";
58
66
  import {
59
67
  asOptionalFiniteNumber
60
68
  } from "./chunk-WWC7I6TA.js";
69
+ import {
70
+ asTrimmedNonEmptyStringArray
71
+ } from "./chunk-I42VC5KR.js";
72
+ import {
73
+ asTrimmedLowercaseString
74
+ } from "./chunk-QSJ3HFEF.js";
61
75
  import {
62
76
  asTrimmedString
63
77
  } from "./chunk-3EUW3WEO.js";
@@ -68,11 +82,8 @@ import {
68
82
  isRecord
69
83
  } from "./chunk-KUG52IAP.js";
70
84
  import {
71
- canonicalizeToolName
72
- } from "./chunk-3AUWC6EM.js";
73
- import {
74
- asTrimmedNonEmptyStringArray
75
- } from "./chunk-I42VC5KR.js";
85
+ normalizeServerOrigin
86
+ } from "./chunk-CF7PE763.js";
76
87
  import {
77
88
  asOptionalTrimmedString
78
89
  } from "./chunk-G3SUCT4W.js";
@@ -142,8 +153,173 @@ function parseSseDataLineObject(line) {
142
153
  return parsed && typeof parsed === "object" ? parsed : null;
143
154
  }
144
155
 
156
+ // packages/integrations/openai/responsesRequestBody.ts
157
+ function buildResponsesRequestBody(body, model) {
158
+ const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
159
+ const reasoningEffort = body.reasoning && typeof body.reasoning === "object" ? void 0 : typeof body.reasoning_effort === "string" && body.reasoning_effort.trim() ? body.reasoning_effort : void 0;
160
+ return {
161
+ ...body,
162
+ model,
163
+ input: Array.isArray(body.input) && body.input.length > 0 ? body.input : convertMessagesToResponsesInput(body.messages ?? []),
164
+ ...Array.isArray(body.tools) ? { tools: tools ?? void 0 } : {},
165
+ ...typeof body.max_tokens === "number" ? { max_output_tokens: body.max_tokens } : {},
166
+ ...reasoningEffort ? { reasoning: { effort: reasoningEffort } } : {},
167
+ messages: void 0,
168
+ max_tokens: void 0,
169
+ reasoning_effort: void 0,
170
+ tool_choice: void 0
171
+ };
172
+ }
173
+
174
+ // packages/agent-runtime/responsesSseStream.ts
175
+ function toResponsesStreamFailure(raw, fallbackPrefix = "Responses") {
176
+ if (!raw || typeof raw !== "object") return void 0;
177
+ const err = raw;
178
+ const reason = typeof err.reason === "string" ? err.reason : void 0;
179
+ const message = typeof err.message === "string" && err.message ? err.message : reason ? `${fallbackPrefix} upstream ended incomplete: ${reason}.` : "";
180
+ if (!message) return void 0;
181
+ const code = typeof err.code === "string" ? err.code : reason;
182
+ return {
183
+ ...code ? { code } : {},
184
+ ...typeof err.type === "string" ? { type: err.type } : {},
185
+ message
186
+ };
187
+ }
188
+ function responsesStreamFailureStatus(failure) {
189
+ const marker = `${failure.code ?? ""} ${failure.type ?? ""}`.toLowerCase();
190
+ if (marker.includes("overload") || marker.includes("service_unavailable")) return 503;
191
+ if (marker.includes("rate_limit") || marker.includes("usage_limit")) return 429;
192
+ return 502;
193
+ }
194
+ var codexStreamFailureStatus = responsesStreamFailureStatus;
195
+ function createResponsesStreamCollector(callbacks) {
196
+ let content = "";
197
+ let reasoning = "";
198
+ const toolCallsAcc = createResponsesToolAccumulator();
199
+ let usage;
200
+ let failure;
201
+ let completedResponse;
202
+ const processEvent = (ev) => {
203
+ const type = String(ev.type ?? "");
204
+ if (type === "error") {
205
+ failure = failure ?? toResponsesStreamFailure(ev.error, callbacks?.fallbackPrefix);
206
+ return;
207
+ }
208
+ if (type === "response.failed" || type === "response.incomplete") {
209
+ const response = ev.response;
210
+ failure = failure ?? toResponsesStreamFailure(response?.error, callbacks?.fallbackPrefix) ?? toResponsesStreamFailure(response?.incomplete_details, callbacks?.fallbackPrefix) ?? {
211
+ code: type === "response.incomplete" ? "response_incomplete" : "response_failed",
212
+ message: `${callbacks?.fallbackPrefix ?? "Responses"} upstream ended with ${type}.`
213
+ };
214
+ return;
215
+ }
216
+ if (type === "response.output_text.delta" && typeof ev.delta === "string") {
217
+ content += ev.delta;
218
+ callbacks?.onTextDelta?.(ev.delta);
219
+ return;
220
+ }
221
+ if ((type === "response.reasoning_text.delta" || type === "response.reasoning.delta") && typeof ev.delta === "string") {
222
+ reasoning += ev.delta;
223
+ callbacks?.onReasoningDelta?.(ev.delta);
224
+ return;
225
+ }
226
+ if (type === "response.output_item.added" || type === "response.output_item.done" || type === "response.function_call_arguments.delta" || type === "response.function_call_arguments.done") {
227
+ applyResponsesToolEvent(toolCallsAcc, ev);
228
+ return;
229
+ }
230
+ if (type === "response.completed") {
231
+ const response = ev.response;
232
+ if (response) {
233
+ completedResponse = response;
234
+ const u = response.usage;
235
+ if (u) {
236
+ const prompt = typeof u.input_tokens === "number" ? u.input_tokens : typeof u.prompt_tokens === "number" ? u.prompt_tokens : 0;
237
+ const completion = typeof u.output_tokens === "number" ? u.output_tokens : typeof u.completion_tokens === "number" ? u.completion_tokens : 0;
238
+ const total = typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion;
239
+ usage = {
240
+ prompt_tokens: prompt,
241
+ completion_tokens: completion,
242
+ total_tokens: total
243
+ };
244
+ }
245
+ }
246
+ }
247
+ };
248
+ const finalize = () => {
249
+ let finalToolCalls = finalizeResponsesToolCalls(toolCallsAcc);
250
+ if (finalToolCalls.length === 0 && completedResponse) {
251
+ finalToolCalls = extractToolCallsFromResponseOutput(completedResponse);
252
+ }
253
+ if (!content && completedResponse) {
254
+ content = extractTextFromResponseOutput(completedResponse);
255
+ }
256
+ if (!reasoning && completedResponse) {
257
+ reasoning = extractReasoningFromResponseOutput(completedResponse);
258
+ }
259
+ return {
260
+ content,
261
+ ...reasoning ? { reasoning_content: reasoning } : {},
262
+ ...finalToolCalls.length > 0 ? { tool_calls: finalToolCalls } : {},
263
+ ...usage ? { usage } : {},
264
+ finish_reason: finalToolCalls.length > 0 ? "tool_calls" : "stop",
265
+ stream_complete: true,
266
+ ...failure ? { failure } : {}
267
+ };
268
+ };
269
+ return {
270
+ processEvent,
271
+ finalize
272
+ };
273
+ }
274
+ function aggregateResponsesStream(events, options) {
275
+ const collector = createResponsesStreamCollector({ fallbackPrefix: options?.fallbackPrefix ?? "Codex" });
276
+ for (const ev of events) {
277
+ collector.processEvent(ev);
278
+ }
279
+ const finalized = collector.finalize();
280
+ return {
281
+ text: finalized.content,
282
+ toolCalls: finalized.tool_calls ?? [],
283
+ usage: finalized.usage,
284
+ failure: finalized.failure
285
+ };
286
+ }
287
+ async function readResponsesSseCompletion(args) {
288
+ const collector = createResponsesStreamCollector({
289
+ onTextDelta: args.onTextDelta,
290
+ onReasoningDelta: args.onReasoningDelta,
291
+ fallbackPrefix: args.fallbackPrefix ?? "Responses"
292
+ });
293
+ for await (const frame of readSseFrames(args.response)) {
294
+ for (const line of frame.split("\n")) {
295
+ const parsed = parseSseDataLineObject(line);
296
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
297
+ collector.processEvent(parsed);
298
+ }
299
+ }
300
+ }
301
+ const result = collector.finalize();
302
+ if (result.failure) {
303
+ const status = responsesStreamFailureStatus(result.failure);
304
+ const err = new Error(result.failure.message);
305
+ err.status = status;
306
+ err.code = result.failure.code;
307
+ err.type = result.failure.type;
308
+ throw err;
309
+ }
310
+ return result;
311
+ }
312
+
145
313
  // packages/agent-runtime/openAiCompatibleProvider.ts
314
+ function isOpenAiResponsesEndpoint(endpoint) {
315
+ return endpoint.includes("/responses");
316
+ }
317
+ function resolveOpenAiCompatibleWire(config) {
318
+ if (config.wire) return config.wire;
319
+ return isOpenAiResponsesEndpoint(config.endpoint) ? "responses" : "chat.completions";
320
+ }
146
321
  function buildOpenAiCompatibleChatCompletionRequest(args) {
322
+ const isResponses = resolveOpenAiCompatibleWire(args.providerConfig) === "responses";
147
323
  const shouldStripReasoning = shouldStripReasoningContentForOutbound(
148
324
  args.providerConfig.provider,
149
325
  args.providerConfig.model
@@ -152,7 +328,7 @@ function buildOpenAiCompatibleChatCompletionRequest(args) {
152
328
  const messages = toOpenAiCompatibleMessages(sanitizedMessages, {
153
329
  stripReasoningContent: shouldStripReasoning
154
330
  });
155
- const body = {
331
+ const rawBody = {
156
332
  model: args.providerConfig.model,
157
333
  messages: requiresBareImageUrl({
158
334
  endpoint: args.providerConfig.endpoint,
@@ -162,8 +338,9 @@ function buildOpenAiCompatibleChatCompletionRequest(args) {
162
338
  stream: args.stream ?? false,
163
339
  ...args.providerConfig.requestOptions,
164
340
  ...args.tools && args.tools.length > 0 ? { tools: args.tools } : {},
165
- ...args.stream ? { stream_options: { include_usage: true } } : {}
341
+ ...!isResponses && args.stream ? getUsageRequestOptions(args.providerConfig.provider, { api: "chat-completions" }) : {}
166
342
  };
343
+ const body = isResponses ? buildResponsesRequestBody(rawBody, args.providerConfig.model) : rawBody;
167
344
  const endpoint = args.providerConfig.endpoint;
168
345
  const headers = {
169
346
  "Content-Type": "application/json",
@@ -183,6 +360,28 @@ function buildOpenAiCompatibleChatCompletionRequest(args) {
183
360
  }
184
361
  };
185
362
  }
363
+ function parseOpenAiCompatibleResponsesResponse(args) {
364
+ const content = extractTextFromResponseOutput(args.data);
365
+ const reasoning = extractReasoningFromResponseOutput(args.data);
366
+ const tool_calls = extractToolCallsFromResponseOutput(args.data);
367
+ const u = args.data?.usage;
368
+ const usage = u && typeof u === "object" ? {
369
+ prompt_tokens: typeof u.input_tokens === "number" ? u.input_tokens : typeof u.prompt_tokens === "number" ? u.prompt_tokens : 0,
370
+ completion_tokens: typeof u.output_tokens === "number" ? u.output_tokens : typeof u.completion_tokens === "number" ? u.completion_tokens : 0,
371
+ total_tokens: typeof u.total_tokens === "number" ? u.total_tokens : (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
372
+ } : void 0;
373
+ return {
374
+ content,
375
+ model: args.providerConfig.model,
376
+ provider: args.providerConfig.provider,
377
+ ...tool_calls.length > 0 ? { tool_calls } : {},
378
+ ...reasoning ? { reasoning_content: reasoning } : {},
379
+ finish_reason: tool_calls.length > 0 ? "tool_calls" : "stop",
380
+ stream_complete: true,
381
+ ...usage ? { usage } : {},
382
+ trace: args.trace
383
+ };
384
+ }
186
385
  function parseOpenAiCompatibleChatCompletionResponse(args) {
187
386
  const choiceMessage = args.data?.choices?.[0]?.message ?? {};
188
387
  const rawContent = String(choiceMessage?.content ?? "");
@@ -236,6 +435,7 @@ async function readOpenAiCompatibleSseCompletion(args) {
236
435
  };
237
436
  }
238
437
  async function executeOpenAiCompatibleChatCompletion(args) {
438
+ const isResponses = resolveOpenAiCompatibleWire(args.providerConfig) === "responses";
239
439
  const send = async (apiKey2) => {
240
440
  const request = buildOpenAiCompatibleChatCompletionRequest({
241
441
  providerConfig: apiKey2 === args.providerConfig.apiKey ? args.providerConfig : { ...args.providerConfig, apiKey: apiKey2 },
@@ -272,6 +472,24 @@ async function executeOpenAiCompatibleChatCompletion(args) {
272
472
  const contentType = res.headers.get("content-type") ?? "";
273
473
  const isEventStream = contentType.includes("text/event-stream");
274
474
  if (isEventStream) {
475
+ if (isResponses) {
476
+ const streamed2 = await readResponsesSseCompletion({
477
+ response: res,
478
+ ...args.onTextDelta ? { onTextDelta: args.onTextDelta } : {},
479
+ ...args.onReasoningDelta ? { onReasoningDelta: args.onReasoningDelta } : {}
480
+ });
481
+ return {
482
+ content: streamed2.content,
483
+ model: args.providerConfig.model,
484
+ provider: args.providerConfig.provider,
485
+ ...streamed2.tool_calls ? { tool_calls: streamed2.tool_calls } : {},
486
+ ...streamed2.reasoning_content ? { reasoning_content: streamed2.reasoning_content } : {},
487
+ ...streamed2.usage ? { usage: streamed2.usage } : {},
488
+ ...streamed2.stream_complete ? { stream_complete: true } : {},
489
+ ...streamed2.finish_reason ? { finish_reason: streamed2.finish_reason } : {},
490
+ trace: args.messages
491
+ };
492
+ }
275
493
  const streamed = await readOpenAiCompatibleSseCompletion({
276
494
  response: res,
277
495
  ...args.onTextDelta ? { onTextDelta: args.onTextDelta } : {},
@@ -296,6 +514,13 @@ async function executeOpenAiCompatibleChatCompletion(args) {
296
514
  } catch {
297
515
  data = {};
298
516
  }
517
+ if (isResponses) {
518
+ return parseOpenAiCompatibleResponsesResponse({
519
+ providerConfig: args.providerConfig,
520
+ data,
521
+ trace: args.messages
522
+ });
523
+ }
299
524
  return parseOpenAiCompatibleChatCompletionResponse({
300
525
  providerConfig: args.providerConfig,
301
526
  data,
@@ -1020,6 +1245,80 @@ function evaluateShellCommandPolicy(args) {
1020
1245
  };
1021
1246
  }
1022
1247
 
1248
+ // packages/agent-runtime/capabilities/capabilityPolicy.ts
1249
+ function toDisplayCommand(command) {
1250
+ if (typeof command === "string") {
1251
+ const trimmed = command.trim();
1252
+ return trimmed ? trimmed : void 0;
1253
+ }
1254
+ if (Array.isArray(command)) {
1255
+ const joined = command.map((item) => typeof item === "string" ? item : String(item)).filter((item) => item.length > 0).join(" ").trim();
1256
+ return joined ? joined : void 0;
1257
+ }
1258
+ return void 0;
1259
+ }
1260
+ function buildDestructiveShellPermissionRequest(command) {
1261
+ return {
1262
+ id: "permission-shell-destructive-action",
1263
+ tool: "execShell",
1264
+ action: "destructive_shell_command",
1265
+ title: "\u786E\u8BA4\u6267\u884C\u7834\u574F\u6027 shell \u547D\u4EE4",
1266
+ body: "\u8BE5\u547D\u4EE4\u53EF\u80FD\u5220\u9664\u6216\u91CD\u7F6E\u7528\u6237\u5185\u5BB9\uFF0C\u9700\u8981\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u624D\u80FD\u6267\u884C\u3002",
1267
+ ...command ? { command } : {},
1268
+ suggestedRule: {
1269
+ scope: "once",
1270
+ pattern: { capability: "destructive_action", target: "shell_command" }
1271
+ }
1272
+ };
1273
+ }
1274
+ function buildDestructiveShellBlockedError(reason, request) {
1275
+ const error = new Error(reason);
1276
+ error.code = "destructive_action_requires_confirmation";
1277
+ error.policy = {
1278
+ capability: "destructive_action",
1279
+ target: "shell_command",
1280
+ detail: "execShell destructive command"
1281
+ };
1282
+ error.permissionRequest = request;
1283
+ return error;
1284
+ }
1285
+ async function evaluateExecShellDestructiveGuard(input, ctx) {
1286
+ const guardEnabled = ctx.enableDestructiveShellGuard !== false;
1287
+ if (!guardEnabled || ctx.confirmed) {
1288
+ return;
1289
+ }
1290
+ const rawCommand = resolveShellCommandArg(
1291
+ typeof input === "object" && input !== null ? input : { command: input }
1292
+ );
1293
+ const extraInput = typeof input === "object" && input !== null ? input.input : void 0;
1294
+ if (!isDestructiveShellCommand({ command: rawCommand, input: extraInput })) {
1295
+ return;
1296
+ }
1297
+ const displayCommand = toDisplayCommand(rawCommand);
1298
+ const request = buildDestructiveShellPermissionRequest(displayCommand);
1299
+ if (!ctx.confirmDestructiveAction) {
1300
+ if (ctx.blockDestructiveWithoutConfirmation) {
1301
+ throw buildDestructiveShellBlockedError(
1302
+ "destructive shell command blocked: no confirmation channel available",
1303
+ request
1304
+ );
1305
+ }
1306
+ return;
1307
+ }
1308
+ const confirmed = await ctx.confirmDestructiveAction(request);
1309
+ if (!confirmed) {
1310
+ throw buildDestructiveShellBlockedError(
1311
+ "destructive shell command blocked: user declined confirmation",
1312
+ request
1313
+ );
1314
+ }
1315
+ }
1316
+ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
1317
+ if (capability.name === "execShell") {
1318
+ await evaluateExecShellDestructiveGuard(normalizedInput, ctx);
1319
+ }
1320
+ }
1321
+
1023
1322
  // packages/agent-runtime/localToolPolicy.ts
1024
1323
  var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
1025
1324
  "deleteSpaces",
@@ -1064,20 +1363,6 @@ function normalizeLocalToolName(toolName) {
1064
1363
  String(toolName ?? "").replace(/^functions\./, "").trim()
1065
1364
  );
1066
1365
  }
1067
- function parseShellCommandPayload(rawArguments) {
1068
- return parseToolArgumentsJson(rawArguments);
1069
- }
1070
- function toDisplayCommand(command) {
1071
- if (typeof command === "string") {
1072
- const trimmed = command.trim();
1073
- return trimmed ? trimmed : void 0;
1074
- }
1075
- if (Array.isArray(command)) {
1076
- const joined = command.map((item) => typeof item === "string" ? item : String(item)).filter((item) => item.length > 0).join(" ").trim();
1077
- return joined ? joined : void 0;
1078
- }
1079
- return void 0;
1080
- }
1081
1366
  function isRestrictedLocalToolMode(env) {
1082
1367
  return env.NOLO_LOCAL_TOOL_MODE === "restricted";
1083
1368
  }
@@ -1127,7 +1412,6 @@ function resolveLocalToolPolicy(args) {
1127
1412
  reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
1128
1413
  };
1129
1414
  }
1130
- var ABORT_AWARE_LOCAL_TOOLS = /* @__PURE__ */ new Set(["execShell", "controlAgentRun"]);
1131
1415
  async function executeLocalToolWithPolicy(args) {
1132
1416
  const decision = resolveLocalToolPolicy({
1133
1417
  env: args.env,
@@ -1139,70 +1423,41 @@ async function executeLocalToolWithPolicy(args) {
1139
1423
  if (!executor) {
1140
1424
  throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
1141
1425
  }
1142
- const effectiveExecutor = args.abortSignal && ABORT_AWARE_LOCAL_TOOLS.has(decision.toolName) && args.executors ? (call) => executor(call, {
1143
- abortSignal: args.abortSignal,
1144
- detachMs: args.detachMs
1145
- }) : executor;
1146
- const guardEnabled = args.enableDestructiveShellGuard !== false;
1147
- if (decision.toolName === "execShell" && !args.confirmed && guardEnabled) {
1148
- const parsed = parseShellCommandPayload(args.call.arguments);
1149
- const rawCommand = resolveShellCommandArg(parsed);
1150
- if (isDestructiveShellCommand({ command: rawCommand, input: parsed.input })) {
1151
- const command = toDisplayCommand(rawCommand);
1152
- const request = {
1153
- id: "permission-shell-destructive-action",
1154
- tool: "execShell",
1155
- action: "destructive_shell_command",
1156
- title: "\u786E\u8BA4\u6267\u884C\u7834\u574F\u6027 shell \u547D\u4EE4",
1157
- body: "\u8BE5\u547D\u4EE4\u53EF\u80FD\u5220\u9664\u6216\u91CD\u7F6E\u7528\u6237\u5185\u5BB9\uFF0C\u9700\u8981\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u624D\u80FD\u6267\u884C\u3002",
1158
- ...command ? { command } : {},
1159
- suggestedRule: {
1160
- scope: "once",
1161
- pattern: { capability: "destructive_action", target: "shell_command" }
1162
- }
1163
- };
1164
- const buildBlockedError = (reason) => {
1165
- const error = new Error(reason);
1166
- error.code = "destructive_action_requires_confirmation";
1167
- error.policy = {
1168
- capability: "destructive_action",
1169
- target: "shell_command",
1170
- detail: "execShell destructive command"
1171
- };
1172
- error.permissionRequest = request;
1173
- return error;
1174
- };
1175
- if (!args.confirmDestructiveAction) {
1176
- if (args.blockDestructiveWithoutConfirmation) {
1177
- throw buildBlockedError(
1178
- "destructive shell command blocked: no confirmation channel available"
1179
- );
1180
- }
1181
- return effectiveExecutor({
1182
- ...args.call,
1183
- name: decision.toolName
1184
- });
1185
- }
1186
- const confirmed = await args.confirmDestructiveAction(request);
1187
- if (!confirmed) {
1188
- throw buildBlockedError(
1189
- "destructive shell command blocked: user declined confirmation"
1190
- );
1426
+ const opts = {
1427
+ ...args.abortSignal ? { abortSignal: args.abortSignal } : {},
1428
+ ...args.detachMs !== void 0 ? { detachMs: args.detachMs } : {},
1429
+ ...args.confirmed !== void 0 ? { confirmed: args.confirmed } : {},
1430
+ ...args.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args.enableDestructiveShellGuard } : {},
1431
+ ...args.confirmDestructiveAction ? { confirmDestructiveAction: args.confirmDestructiveAction } : {},
1432
+ ...args.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args.blockDestructiveWithoutConfirmation } : {}
1433
+ };
1434
+ if (decision.toolName === "execShell") {
1435
+ let parsedInput = args.call.arguments;
1436
+ if (typeof parsedInput === "string") {
1437
+ try {
1438
+ parsedInput = JSON.parse(parsedInput);
1439
+ } catch {
1440
+ parsedInput = { command: parsedInput };
1191
1441
  }
1192
1442
  }
1443
+ await evaluateExecShellDestructiveGuard(parsedInput, opts);
1444
+ opts.confirmed = true;
1193
1445
  }
1194
- return effectiveExecutor({
1195
- ...args.call,
1196
- name: decision.toolName
1197
- });
1446
+ return executor(
1447
+ {
1448
+ ...args.call,
1449
+ name: decision.toolName
1450
+ },
1451
+ opts
1452
+ );
1198
1453
  }
1199
1454
 
1200
1455
  // packages/agent-runtime/localWorkspaceTools.ts
1201
1456
  import { existsSync as existsSync2 } from "node:fs";
1202
1457
  import { createHash } from "node:crypto";
1203
1458
  import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
1204
- import { dirname, relative, resolve, sep } from "node:path";
1205
- import { spawnSync, spawn as spawnChildProcess } from "node:child_process";
1459
+ import { dirname, relative, resolve as resolve2, sep } from "node:path";
1460
+ import { spawnSync, spawn as spawnChildProcess2 } from "node:child_process";
1206
1461
 
1207
1462
  // packages/core/readRangeLedger.ts
1208
1463
  function filterRetainedLedgerRecords(records, retainedCap) {
@@ -1389,9 +1644,9 @@ function spawnToWebStreams(options) {
1389
1644
  env: options.env,
1390
1645
  stdio: ["ignore", "pipe", "pipe"]
1391
1646
  });
1392
- const exited = new Promise((resolve2) => {
1393
- child.on("exit", (code) => resolve2(code ?? 1));
1394
- child.on("error", () => resolve2(127));
1647
+ const exited = new Promise((resolve3) => {
1648
+ child.on("exit", (code) => resolve3(code ?? 1));
1649
+ child.on("error", () => resolve3(127));
1395
1650
  });
1396
1651
  const toWeb = (stream) => {
1397
1652
  if (!stream) return null;
@@ -1474,65 +1729,674 @@ function getProcessRegistry() {
1474
1729
  return registry;
1475
1730
  }
1476
1731
 
1477
- // packages/agent-runtime/localWorkspaceToolDefs.ts
1478
- var WORKSPACE_TOOL_NAMES = [
1479
- "listFiles",
1480
- "readFile",
1481
- "writeFile",
1482
- "editFile",
1483
- "globFiles",
1484
- "searchFiles",
1485
- "captureVisualState",
1486
- "execShell",
1487
- "launchProcess",
1488
- "listProcesses"
1489
- ];
1490
- var SHELL_TOOL_NAMES = ["execShell", "launchProcess", "listProcesses"];
1491
- var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
1492
- var REMOVED_WORKSPACE_TOOL_NAMES = /* @__PURE__ */ new Set([
1493
- "gitStatus",
1494
- "gitDiff",
1495
- "gitCreateBranch",
1496
- "gitAdd",
1497
- "gitCommit",
1498
- "commitWorkspace"
1499
- ]);
1500
- function tokenizeShellPrefix(command) {
1501
- const tokens = [];
1502
- const pattern = /"([^"]*)"|'([^']*)'|([^\s"'|;&<>]+)/g;
1503
- let match;
1504
- while (match = pattern.exec(command)) {
1505
- tokens.push(match[1] ?? match[2] ?? match[3] ?? "");
1506
- }
1507
- return tokens;
1732
+ // packages/agent-runtime/workspaceShell.ts
1733
+ import { resolve } from "node:path";
1734
+ import { spawn as spawnChildProcess } from "node:child_process";
1735
+ var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
1736
+ var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
1737
+ var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
1738
+ function readTrimmedString(value) {
1739
+ return asOptionalTrimmedString(value);
1508
1740
  }
1509
- function buildWorkspacePathProperty() {
1741
+ function extractActivityRefs(rawRefs) {
1742
+ if (!Array.isArray(rawRefs)) return void 0;
1743
+ const refs = rawRefs.flatMap((entry) => {
1744
+ if (typeof entry === "string" && entry.trim()) {
1745
+ return [{ type: "file", path: entry.trim() }];
1746
+ }
1747
+ if (!isRecord(entry)) return [];
1748
+ const path = readTrimmedString(entry.path);
1749
+ if (path) return [{ type: "file", path }];
1750
+ const terminalId = readTrimmedString(entry.id);
1751
+ const terminalLabel = readTrimmedString(entry.label);
1752
+ if (entry.type === "terminal" || terminalId || terminalLabel) {
1753
+ return [{
1754
+ type: "terminal",
1755
+ ...terminalId ? { id: terminalId } : {},
1756
+ ...terminalLabel ? { label: terminalLabel } : {}
1757
+ }];
1758
+ }
1759
+ if (entry.type === "url" || typeof entry.url === "string") {
1760
+ const url = readTrimmedString(entry.url);
1761
+ const label = readTrimmedString(entry.label);
1762
+ return url ? [{ type: "url", url, ...label ? { label } : {} }] : [];
1763
+ }
1764
+ return [];
1765
+ });
1766
+ return refs.length ? refs : void 0;
1767
+ }
1768
+ function extractActivityAction(rawAction) {
1769
+ if (!isRecord(rawAction)) return void 0;
1770
+ const title = readTrimmedString(rawAction.title);
1771
+ if (!title) return void 0;
1772
+ const kind = readTrimmedString(rawAction.kind);
1773
+ const detail = readTrimmedString(rawAction.detail);
1774
+ const refs = extractActivityRefs(rawAction.refs);
1510
1775
  return {
1511
- type: "string",
1512
- minLength: 1,
1513
- description: "Path relative to the workspace root. Defaults to workspace root when omitted."
1776
+ title,
1777
+ ...kind ? { kind } : {},
1778
+ ...detail ? { detail } : {},
1779
+ ...refs ? { refs } : {}
1514
1780
  };
1515
1781
  }
1516
- function buildListWorkspaceDescription(variant) {
1517
- if (variant === "brief") {
1518
- return "List files and directories inside a workspace directory.";
1519
- }
1520
- if (variant === "workflow") {
1521
- return "List directory overview inside workspace. Then use globFiles for path patterns, searchFiles for text discovery, and readFile for content.";
1522
- }
1523
- if (variant === "antiShell") {
1524
- return "List directory overview inside workspace. Prefer listFiles over shell ls/find commands.";
1525
- }
1526
- return "List files and directories inside a workspace folder. Defaults to shallow overview (depth 1).";
1527
- }
1528
- function buildListWorkspaceParameters(variant) {
1529
- const path = buildWorkspacePathProperty();
1530
- const maxDepth = {
1531
- type: "integer",
1532
- description: "Maximum directory depth to include. Defaults to 1 for the requested directory only."
1782
+ function extractActivityPhase(rawPhase) {
1783
+ if (!isRecord(rawPhase)) return void 0;
1784
+ const title = readTrimmedString(rawPhase.title);
1785
+ if (!title) return void 0;
1786
+ const id = readTrimmedString(rawPhase.id) || title.toLowerCase().replace(/\s+/g, "-");
1787
+ const index = asOptionalFiniteNumber(rawPhase.index);
1788
+ const total = asOptionalFiniteNumber(rawPhase.total);
1789
+ const status = rawPhase.status === "pending" || rawPhase.status === "running" || rawPhase.status === "success" || rawPhase.status === "failed" ? rawPhase.status : void 0;
1790
+ return {
1791
+ id,
1792
+ title,
1793
+ ...index !== void 0 ? { index } : {},
1794
+ ...total !== void 0 ? { total } : {},
1795
+ ...status ? { status } : {}
1533
1796
  };
1534
- const maxResults = {
1535
- type: "integer",
1797
+ }
1798
+ function extractActivityPlan(rawPlan) {
1799
+ if (!isRecord(rawPlan)) return void 0;
1800
+ if (!Array.isArray(rawPlan.phases)) return void 0;
1801
+ const phases = rawPlan.phases.flatMap((entry, index) => {
1802
+ const phase = extractActivityPhase(entry);
1803
+ if (!phase) return [];
1804
+ return [{
1805
+ id: phase.id,
1806
+ title: phase.title,
1807
+ index: phase.index ?? index + 1,
1808
+ ...phase.status ? { status: phase.status } : {}
1809
+ }];
1810
+ });
1811
+ if (phases.length === 0) return void 0;
1812
+ const title = readTrimmedString(rawPlan.title);
1813
+ return {
1814
+ ...title ? { title } : {},
1815
+ phases
1816
+ };
1817
+ }
1818
+ function extractActivity(parsed) {
1819
+ const raw = parsed._activity;
1820
+ if (!isRecord(raw)) return void 0;
1821
+ const nestedAction = extractActivityAction(raw.action);
1822
+ const legacyAction = extractActivityAction(raw);
1823
+ const action = nestedAction || legacyAction;
1824
+ const phase = extractActivityPhase(raw.phase);
1825
+ const plan = extractActivityPlan(raw.plan);
1826
+ if (!action && !plan) return void 0;
1827
+ return {
1828
+ ...action ? action : {},
1829
+ ...phase ? { phase } : {},
1830
+ ...nestedAction ? { action: nestedAction } : {},
1831
+ ...plan ? { plan } : {}
1832
+ };
1833
+ }
1834
+ function tokenizeShellPrefix(command) {
1835
+ const tokens = [];
1836
+ const pattern = /"([^"]*)"|'([^']*)'|([^\s"'|;&<>]+)/g;
1837
+ let match;
1838
+ while (match = pattern.exec(command)) {
1839
+ tokens.push(match[1] ?? match[2] ?? match[3] ?? "");
1840
+ }
1841
+ return tokens;
1842
+ }
1843
+ function wrapPowerShellCommand(command) {
1844
+ return [
1845
+ "[Console]::InputEncoding=[System.Text.Encoding]::UTF8",
1846
+ "[Console]::OutputEncoding=[System.Text.Encoding]::UTF8",
1847
+ "$OutputEncoding=[System.Text.Encoding]::UTF8",
1848
+ "$PSStyle.OutputRendering='PlainText'",
1849
+ command
1850
+ ].join("; ");
1851
+ }
1852
+ function findPowerShellExecutable() {
1853
+ return resolveExecutableOnPath("pwsh") || resolveExecutableOnPath("powershell.exe") || resolveExecutableOnPath("powershell");
1854
+ }
1855
+ function buildPowerShellCommand(command) {
1856
+ const executable = findPowerShellExecutable();
1857
+ if (!executable) throw new Error("PowerShell is not available on this machine.");
1858
+ return [
1859
+ executable,
1860
+ "-NoLogo",
1861
+ "-NoProfile",
1862
+ "-NonInteractive",
1863
+ "-ExecutionPolicy",
1864
+ "Bypass",
1865
+ "-Command",
1866
+ wrapPowerShellCommand(command)
1867
+ ];
1868
+ }
1869
+ function buildBashCommand(command) {
1870
+ const executable = resolveExecutableOnPath("bash") || resolveExecutableOnPath("sh");
1871
+ if (!executable) throw new Error("bash/sh is not available on this machine.");
1872
+ return [executable, "-lc", command];
1873
+ }
1874
+ function buildWorkspaceShellCommand(args) {
1875
+ if (args.shell === "powershell") return buildPowerShellCommand(args.command);
1876
+ if (args.shell === "bash") return buildBashCommand(args.command);
1877
+ return process.platform === "win32" ? buildPowerShellCommand(args.command) : buildBashCommand(args.command);
1878
+ }
1879
+ function findWorkspaceShellEscapeToken(command) {
1880
+ const tokens = tokenizeShellPrefix(command);
1881
+ for (const token of tokens) {
1882
+ if (token === ".." || token.startsWith("../") || token.startsWith("..\\") || token.includes("/../") || token.includes("\\..\\")) {
1883
+ return token;
1884
+ }
1885
+ if (token === "~" || token.startsWith("~/") || token.startsWith("~\\")) {
1886
+ return token;
1887
+ }
1888
+ if (token === "/" || token.startsWith("/") || /^[A-Za-z]:[\\/]/.test(token) || token.startsWith("\\\\")) {
1889
+ return token;
1890
+ }
1891
+ }
1892
+ return null;
1893
+ }
1894
+ function buildWorkspaceShellEscapeBlockedResult(args) {
1895
+ return {
1896
+ content: [
1897
+ "workspace_shell_escape_blocked",
1898
+ `blockedToken: ${args.token}`,
1899
+ `command: ${args.command}`,
1900
+ "Use paths relative to the authorized folder only.",
1901
+ "exitCode: 126"
1902
+ ].join("\n"),
1903
+ metadata: {
1904
+ exitCode: 126,
1905
+ workspaceShellEscapeBlocked: true,
1906
+ blockedToken: args.token
1907
+ }
1908
+ };
1909
+ }
1910
+ function extractInteractiveGhAuthCommand(command) {
1911
+ const tokens = tokenizeShellPrefix(command);
1912
+ if (tokens[0] !== "gh" || tokens[1] !== "auth") return null;
1913
+ const subcommand = tokens[2];
1914
+ if (subcommand !== "login" && subcommand !== "refresh") return null;
1915
+ if (tokens.includes("--help")) return null;
1916
+ const result = ["gh", "auth", subcommand];
1917
+ for (let index = 3; index < tokens.length; index += 1) {
1918
+ const token = tokens[index];
1919
+ if (!token) continue;
1920
+ if (token === "-h" || token === "--hostname" || token === "-s" || token === "--scopes" || token === "--remove-scopes" || token === "-r") {
1921
+ const value = tokens[index + 1];
1922
+ if (value) {
1923
+ result.push(token, value);
1924
+ index += 1;
1925
+ }
1926
+ continue;
1927
+ }
1928
+ if (token === "--clipboard" || token === "-c" || token === "--insecure-storage" || token === "--reset-scopes") {
1929
+ result.push(token);
1930
+ continue;
1931
+ }
1932
+ if (token.startsWith("--hostname=") || token.startsWith("--scopes=") || token.startsWith("--remove-scopes=")) {
1933
+ result.push(token);
1934
+ continue;
1935
+ }
1936
+ }
1937
+ return result.join(" ");
1938
+ }
1939
+ function buildInteractiveCommandBlockedResult(command) {
1940
+ const argv = tokenizeShellPrefix(command);
1941
+ return {
1942
+ content: [
1943
+ "action_gate: handoff",
1944
+ `command: ${command}`,
1945
+ "Run this in the current TUI terminal, then resume the agent turn.",
1946
+ "exitCode: 130"
1947
+ ].join("\n"),
1948
+ metadata: {
1949
+ exitCode: 130,
1950
+ timedOut: false,
1951
+ actionGate: {
1952
+ id: `gate-${Date.now().toString(36)}-terminal-handoff`,
1953
+ kind: "handoff",
1954
+ title: "This command requires an interactive terminal.",
1955
+ body: "Complete it in the terminal, then nolo will continue.",
1956
+ payload: {
1957
+ command: argv,
1958
+ displayCommand: command
1959
+ }
1960
+ },
1961
+ reason: "interactive-command-requires-terminal"
1962
+ }
1963
+ };
1964
+ }
1965
+ function resolveExecShellTimeoutMs(override) {
1966
+ const fromOverride = asOptionalPositiveFiniteNumber(override);
1967
+ if (fromOverride !== void 0) return fromOverride;
1968
+ const raw = process.env[EXEC_SHELL_TIMEOUT_ENV];
1969
+ if (raw === void 0) return void 0;
1970
+ return asOptionalPositiveFiniteNumber(Number(raw));
1971
+ }
1972
+ function resolveDetachMs(override) {
1973
+ if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
1974
+ return override;
1975
+ }
1976
+ const raw = process.env[EXEC_SHELL_DETACH_ENV];
1977
+ if (raw === void 0) return DEFAULT_EXEC_SHELL_DETACH_MS;
1978
+ const parsed = asOptionalPositiveFiniteNumber(Number(raw));
1979
+ return parsed === void 0 ? DEFAULT_EXEC_SHELL_DETACH_MS : parsed;
1980
+ }
1981
+ function truncateToolOutput(value, limit = 2e4) {
1982
+ if (value.length <= limit) return value;
1983
+ const approxMarkerLen = 40;
1984
+ if (limit <= approxMarkerLen) return value.slice(0, limit);
1985
+ const remaining = limit - approxMarkerLen;
1986
+ const headSize = Math.floor(remaining * 0.3);
1987
+ const tailSize = remaining - headSize;
1988
+ const head = value.slice(0, headSize);
1989
+ const tail = value.slice(-tailSize);
1990
+ const actualRemoved = value.length - headSize - tailSize;
1991
+ return `${head}
1992
+
1993
+ [... truncated ${actualRemoved} chars ...]
1994
+
1995
+ ${tail}`;
1996
+ }
1997
+ function readNodeStream(stream) {
1998
+ if (!stream) return Promise.resolve("");
1999
+ return new Promise((resolveStream, rejectStream) => {
2000
+ const chunks = [];
2001
+ stream.on("data", (chunk) => {
2002
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2003
+ });
2004
+ stream.on("error", rejectStream);
2005
+ stream.on("end", () => {
2006
+ resolveStream(Buffer.concat(chunks).toString("utf8"));
2007
+ });
2008
+ });
2009
+ }
2010
+ function waitForNodeProcessExit(proc) {
2011
+ return new Promise((resolveExit, rejectExit) => {
2012
+ proc.on("error", rejectExit);
2013
+ proc.on("close", (code) => {
2014
+ resolveExit(code ?? 0);
2015
+ });
2016
+ });
2017
+ }
2018
+ function deriveLabel(command) {
2019
+ const trimmed = command.trim();
2020
+ if (!trimmed) return "process";
2021
+ const tokens = trimmed.split(/\s+/);
2022
+ const lastToken = tokens[tokens.length - 1] ?? trimmed;
2023
+ const labelCandidate = lastToken.split(/[/\\]/).pop() || lastToken;
2024
+ return labelCandidate || trimmed;
2025
+ }
2026
+ function isSpawnFailureError(error) {
2027
+ if (!error || typeof error !== "object") return false;
2028
+ const err = error;
2029
+ if (err.code === "ENOENT") return true;
2030
+ const message = toErrorMessage(error).toLowerCase();
2031
+ return message.includes("enoent") || message.includes("executable not found") || message.includes("spawn") && message.includes("not found");
2032
+ }
2033
+ function spawnFailedCommandResult(error, outputLimit) {
2034
+ const stderr = `spawn failed: ${toErrorMessage(error)}
2035
+ `;
2036
+ return {
2037
+ stdout: "",
2038
+ stderr,
2039
+ exitCode: 127,
2040
+ timedOut: false,
2041
+ spawnFailed: true,
2042
+ content: truncateToolOutput(
2043
+ [`stderr:
2044
+ ${stderr.trim()}`, "exitCode: 127"].filter(Boolean).join("\n\n"),
2045
+ outputLimit
2046
+ )
2047
+ };
2048
+ }
2049
+ async function runWorkspaceCommand(args) {
2050
+ const timeoutMs = asOptionalPositiveFiniteNumber(args.timeoutMs);
2051
+ const detached = process.platform !== "win32";
2052
+ const command = [
2053
+ ...args.commandPrefix ?? [],
2054
+ ...args.command
2055
+ ];
2056
+ const proc = spawnChildProcess(command[0] ?? "", command.slice(1), {
2057
+ cwd: resolve(args.workspaceRoot),
2058
+ stdio: [
2059
+ args.stdin === void 0 ? "ignore" : "pipe",
2060
+ "pipe",
2061
+ "pipe"
2062
+ ],
2063
+ detached
2064
+ });
2065
+ if (args.stdin !== void 0 && proc.stdin) {
2066
+ proc.stdin.write(args.stdin);
2067
+ proc.stdin.end();
2068
+ }
2069
+ const exitPromise = waitForNodeProcessExit(proc);
2070
+ const cleanupChildOnHostSignal = (signal) => {
2071
+ if (typeof proc.pid === "number") {
2072
+ try {
2073
+ process.kill(-proc.pid, signal);
2074
+ } catch {
2075
+ }
2076
+ }
2077
+ };
2078
+ if (detached) {
2079
+ process.once("SIGHUP", cleanupChildOnHostSignal);
2080
+ process.once("SIGTERM", cleanupChildOnHostSignal);
2081
+ process.once("SIGINT", cleanupChildOnHostSignal);
2082
+ }
2083
+ const detachSignalCleanup = () => {
2084
+ if (!detached) return;
2085
+ process.removeListener("SIGHUP", cleanupChildOnHostSignal);
2086
+ process.removeListener("SIGTERM", cleanupChildOnHostSignal);
2087
+ process.removeListener("SIGINT", cleanupChildOnHostSignal);
2088
+ };
2089
+ exitPromise.then(detachSignalCleanup, detachSignalCleanup);
2090
+ const stdoutPromise = readNodeStream(proc.stdout);
2091
+ const stderrPromise = readNodeStream(proc.stderr);
2092
+ const killChild = (signal) => {
2093
+ if (detached && typeof proc.pid === "number") {
2094
+ try {
2095
+ process.kill(-proc.pid, signal);
2096
+ return;
2097
+ } catch {
2098
+ }
2099
+ }
2100
+ try {
2101
+ proc.kill(signal);
2102
+ } catch {
2103
+ }
2104
+ };
2105
+ let timeout;
2106
+ let detachTimer;
2107
+ const timeoutResult = Symbol("timeout");
2108
+ const abortResult = Symbol("abort");
2109
+ const detachResult = Symbol("detach");
2110
+ let abortListener;
2111
+ const abortPromise = args.abortSignal ? new Promise((resolveAbort) => {
2112
+ if (args.abortSignal.aborted) {
2113
+ resolveAbort(abortResult);
2114
+ return;
2115
+ }
2116
+ abortListener = () => resolveAbort(abortResult);
2117
+ args.abortSignal.addEventListener("abort", abortListener, { once: true });
2118
+ }) : null;
2119
+ const effectiveDetachMs = resolveDetachMs(args.detachMs);
2120
+ const detachPromise = new Promise((resolveDetach) => {
2121
+ detachTimer = setTimeout(() => resolveDetach(detachResult), effectiveDetachMs);
2122
+ });
2123
+ const exitOrTimeoutPromise = timeoutMs ? Promise.race([
2124
+ exitPromise,
2125
+ new Promise((resolveTimeout) => {
2126
+ timeout = setTimeout(() => resolveTimeout(timeoutResult), timeoutMs);
2127
+ })
2128
+ ]) : exitPromise;
2129
+ const raceCandidates = [
2130
+ exitOrTimeoutPromise,
2131
+ detachPromise
2132
+ ];
2133
+ if (abortPromise) {
2134
+ raceCandidates.push(abortPromise);
2135
+ }
2136
+ let raceWinner;
2137
+ try {
2138
+ raceWinner = await Promise.race(raceCandidates);
2139
+ } catch (error) {
2140
+ if (timeout) clearTimeout(timeout);
2141
+ if (detachTimer) clearTimeout(detachTimer);
2142
+ if (abortListener && args.abortSignal) {
2143
+ args.abortSignal.removeEventListener("abort", abortListener);
2144
+ }
2145
+ if (isSpawnFailureError(error)) {
2146
+ return spawnFailedCommandResult(error, args.outputLimit);
2147
+ }
2148
+ throw error;
2149
+ }
2150
+ if (timeout) clearTimeout(timeout);
2151
+ if (detachTimer) clearTimeout(detachTimer);
2152
+ if (abortListener && args.abortSignal) {
2153
+ args.abortSignal.removeEventListener("abort", abortListener);
2154
+ }
2155
+ const timedOut = raceWinner === timeoutResult;
2156
+ const aborted = raceWinner === abortResult;
2157
+ const detachedProcess = raceWinner === detachResult;
2158
+ if (timedOut || aborted) {
2159
+ killChild("SIGTERM");
2160
+ const forceKillTimer = setTimeout(() => {
2161
+ killChild("SIGKILL");
2162
+ }, 500);
2163
+ try {
2164
+ await exitPromise;
2165
+ } catch {
2166
+ } finally {
2167
+ clearTimeout(forceKillTimer);
2168
+ }
2169
+ }
2170
+ if (detachedProcess) {
2171
+ exitPromise.catch(() => {
2172
+ });
2173
+ const pid = typeof proc.pid === "number" ? proc.pid : 0;
2174
+ const label = deriveLabel(args.command.join(" "));
2175
+ const pgid = pid;
2176
+ const registry2 = getProcessRegistry();
2177
+ registry2.add({ pid, pgid, command: args.command.join(" "), label });
2178
+ proc.on("close", (code) => {
2179
+ detachSignalCleanup();
2180
+ registry2.markExited(pid, code ?? 1);
2181
+ });
2182
+ const immediate = effectiveDetachMs === 0;
2183
+ const reason = immediate ? `command looks long-running; moved to background immediately (pid=${pid}, label=${label})` : `command detached to background after ${effectiveDetachMs}ms (pid=${pid}, label=${label})`;
2184
+ return {
2185
+ stdout: "",
2186
+ stderr: `${reason}
2187
+ Use listProcesses to inspect or stop it.`,
2188
+ exitCode: 0,
2189
+ timedOut: false,
2190
+ detached: true,
2191
+ pid,
2192
+ label,
2193
+ content: JSON.stringify({
2194
+ detached: true,
2195
+ pid,
2196
+ label,
2197
+ status: "running",
2198
+ ...immediate ? { reason: "long-running-command" } : {}
2199
+ })
2200
+ };
2201
+ }
2202
+ const [stdout, rawStderr] = await Promise.all([
2203
+ stdoutPromise,
2204
+ stderrPromise
2205
+ ]);
2206
+ const exitCode = aborted ? 130 : timedOut ? 124 : Number(raceWinner);
2207
+ const stderr = aborted ? `${rawStderr.trim() ? `${rawStderr.trim()}
2208
+ ` : ""}command aborted by signal
2209
+ ` : timedOut ? `${rawStderr.trim() ? `${rawStderr.trim()}
2210
+ ` : ""}command timed out after ${timeoutMs ?? "unknown"}ms
2211
+ ` : rawStderr;
2212
+ return {
2213
+ stdout,
2214
+ stderr,
2215
+ exitCode,
2216
+ timedOut,
2217
+ aborted,
2218
+ content: truncateToolOutput([
2219
+ stdout.trim() ? `stdout:
2220
+ ${stdout.trim()}` : "",
2221
+ stderr.trim() ? `stderr:
2222
+ ${stderr.trim()}` : "",
2223
+ `exitCode: ${exitCode}`
2224
+ ].filter(Boolean).join("\n\n"), args.outputLimit)
2225
+ };
2226
+ }
2227
+
2228
+ // packages/agent-runtime/capabilities/execShellCapability.ts
2229
+ function buildExecShellToolDefinition(toolName = "execShell") {
2230
+ return {
2231
+ type: "function",
2232
+ function: {
2233
+ name: toolName,
2234
+ description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess.`,
2235
+ parameters: {
2236
+ type: "object",
2237
+ properties: {
2238
+ command: {
2239
+ type: "string",
2240
+ description: "Shell command to run (non-empty)."
2241
+ },
2242
+ cmd: {
2243
+ type: "string",
2244
+ description: "Compatibility alias for command."
2245
+ }
2246
+ }
2247
+ }
2248
+ }
2249
+ };
2250
+ }
2251
+ function normalizeExecShellInput(input) {
2252
+ if (input === null || input === void 0) {
2253
+ throw new Error("execShell requires a non-empty command.");
2254
+ }
2255
+ if (typeof input === "string") {
2256
+ const trimmed = input.trim();
2257
+ if (!trimmed) {
2258
+ throw new Error("execShell requires a non-empty command.");
2259
+ }
2260
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
2261
+ try {
2262
+ const parsed = JSON.parse(trimmed);
2263
+ if (parsed && typeof parsed === "object") {
2264
+ return normalizeExecShellInput(parsed);
2265
+ }
2266
+ } catch {
2267
+ }
2268
+ }
2269
+ return { command: trimmed };
2270
+ }
2271
+ if (typeof input === "object") {
2272
+ const record = input;
2273
+ let rawCommand = resolveShellCommandArg(record);
2274
+ if (typeof rawCommand !== "string" || !rawCommand.trim()) {
2275
+ const fallback = record.command ?? record.cmd;
2276
+ if (typeof fallback === "string" && fallback.trim()) {
2277
+ rawCommand = fallback;
2278
+ }
2279
+ }
2280
+ const command = typeof rawCommand === "string" ? rawCommand.trim() : "";
2281
+ if (!command) {
2282
+ throw new Error("execShell requires a non-empty command.");
2283
+ }
2284
+ const activity = extractActivity(record);
2285
+ return {
2286
+ command,
2287
+ ...record.shell !== void 0 ? { shell: record.shell } : {},
2288
+ ...activity ? { activity } : {},
2289
+ ...record.input !== void 0 ? { input: record.input } : {}
2290
+ };
2291
+ }
2292
+ throw new Error("execShell requires a non-empty command.");
2293
+ }
2294
+ var execShellCapability = {
2295
+ name: "execShell",
2296
+ getToolDefinition(toolName = "execShell") {
2297
+ return buildExecShellToolDefinition(toolName);
2298
+ },
2299
+ normalizeInput(input) {
2300
+ return normalizeExecShellInput(input);
2301
+ },
2302
+ async invoke(ctx, normalized) {
2303
+ const workspaceRoot = ctx.workspaceRoot || process.cwd();
2304
+ const command = normalized.command;
2305
+ if (ctx.restrictToWorkspace) {
2306
+ const escapeToken = findWorkspaceShellEscapeToken(command);
2307
+ if (escapeToken) {
2308
+ return buildWorkspaceShellEscapeBlockedResult({ command, token: escapeToken });
2309
+ }
2310
+ }
2311
+ const interactiveAuthCommand = extractInteractiveGhAuthCommand(command);
2312
+ if (interactiveAuthCommand) {
2313
+ const blocked = buildInteractiveCommandBlockedResult(interactiveAuthCommand);
2314
+ return {
2315
+ ...blocked,
2316
+ metadata: {
2317
+ ...blocked.metadata,
2318
+ ...normalized.activity ? { activity: normalized.activity } : {}
2319
+ }
2320
+ };
2321
+ }
2322
+ const result = await runWorkspaceCommand({
2323
+ workspaceRoot,
2324
+ command: buildWorkspaceShellCommand({
2325
+ toolName: "execShell",
2326
+ command,
2327
+ shell: normalized.shell
2328
+ }),
2329
+ timeoutMs: resolveExecShellTimeoutMs(ctx.commandTimeoutMs),
2330
+ outputLimit: ctx.commandOutputLimit,
2331
+ commandPrefix: ctx.commandPrefix,
2332
+ abortSignal: ctx.abortSignal,
2333
+ detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
2334
+ stdin: typeof normalized.input === "string" ? normalized.input : void 0
2335
+ });
2336
+ return {
2337
+ content: result.content,
2338
+ metadata: {
2339
+ command,
2340
+ exitCode: result.exitCode,
2341
+ timedOut: result.timedOut,
2342
+ ...result.aborted ? { aborted: true } : {},
2343
+ ...result.detached ? { detached: true, pid: result.pid, label: result.label, status: "running" } : {},
2344
+ ...normalized.activity ? { activity: normalized.activity } : {}
2345
+ }
2346
+ };
2347
+ }
2348
+ };
2349
+
2350
+ // packages/agent-runtime/localWorkspaceToolDefs.ts
2351
+ var WORKSPACE_TOOL_NAMES = [
2352
+ "listFiles",
2353
+ "readFile",
2354
+ "writeFile",
2355
+ "editFile",
2356
+ "globFiles",
2357
+ "searchFiles",
2358
+ "captureVisualState",
2359
+ "execShell",
2360
+ "launchProcess",
2361
+ "listProcesses"
2362
+ ];
2363
+ var SHELL_TOOL_NAMES = ["execShell", "launchProcess", "listProcesses"];
2364
+ var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
2365
+ var REMOVED_WORKSPACE_TOOL_NAMES = /* @__PURE__ */ new Set([
2366
+ "gitStatus",
2367
+ "gitDiff",
2368
+ "gitCreateBranch",
2369
+ "gitAdd",
2370
+ "gitCommit",
2371
+ "commitWorkspace"
2372
+ ]);
2373
+ function buildWorkspacePathProperty() {
2374
+ return {
2375
+ type: "string",
2376
+ minLength: 1,
2377
+ description: "Path relative to the workspace root. Defaults to workspace root when omitted."
2378
+ };
2379
+ }
2380
+ function buildListWorkspaceDescription(variant) {
2381
+ if (variant === "brief") {
2382
+ return "List files and directories inside a workspace directory.";
2383
+ }
2384
+ if (variant === "workflow") {
2385
+ return "List directory overview inside workspace. Then use globFiles for path patterns, searchFiles for text discovery, and readFile for content.";
2386
+ }
2387
+ if (variant === "antiShell") {
2388
+ return "List directory overview inside workspace. Prefer listFiles over shell ls/find commands.";
2389
+ }
2390
+ return "List files and directories inside a workspace folder. Defaults to shallow overview (depth 1).";
2391
+ }
2392
+ function buildListWorkspaceParameters(variant) {
2393
+ const path = buildWorkspacePathProperty();
2394
+ const maxDepth = {
2395
+ type: "integer",
2396
+ description: "Maximum directory depth to include. Defaults to 1 for the requested directory only."
2397
+ };
2398
+ const maxResults = {
2399
+ type: "integer",
1536
2400
  description: "Maximum number of entries to return. Use a small value for large directories."
1537
2401
  };
1538
2402
  const entryType = {
@@ -1879,26 +2743,7 @@ function buildCaptureVisualStateTool() {
1879
2743
  };
1880
2744
  }
1881
2745
  function buildExecShellTool(toolName) {
1882
- return {
1883
- type: "function",
1884
- function: {
1885
- name: toolName,
1886
- description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess.`,
1887
- parameters: {
1888
- type: "object",
1889
- properties: {
1890
- cmd: {
1891
- type: "string",
1892
- description: "Shell command to run (non-empty)."
1893
- },
1894
- command: {
1895
- type: "string",
1896
- description: "Compatibility alias for cmd."
1897
- }
1898
- }
1899
- }
1900
- }
1901
- };
2746
+ return buildExecShellToolDefinition(toolName);
1902
2747
  }
1903
2748
  function buildLaunchProcessTool() {
1904
2749
  return {
@@ -1922,88 +2767,21 @@ function buildLaunchProcessTool() {
1922
2767
  description: "Keep process alive after session/conversation closes. Defaults to false."
1923
2768
  }
1924
2769
  },
1925
- required: ["command"]
1926
- }
1927
- }
1928
- };
1929
- }
1930
- function buildListProcessesTool() {
1931
- return {
1932
- type: "function",
1933
- function: {
1934
- name: "listProcesses",
1935
- description: "List active background processes launched via launchProcess. Returns {pid, label, command, status, startedAt, persist}[].",
1936
- parameters: {
1937
- type: "object",
1938
- properties: {}
1939
- }
1940
- }
1941
- };
1942
- }
1943
- function wrapPowerShellCommand(command) {
1944
- return [
1945
- "[Console]::InputEncoding=[System.Text.Encoding]::UTF8",
1946
- "[Console]::OutputEncoding=[System.Text.Encoding]::UTF8",
1947
- "$OutputEncoding=[System.Text.Encoding]::UTF8",
1948
- "$PSStyle.OutputRendering='PlainText'",
1949
- command
1950
- ].join("; ");
1951
- }
1952
- function findPowerShellExecutable() {
1953
- return resolveExecutableOnPath("pwsh") || resolveExecutableOnPath("powershell.exe") || resolveExecutableOnPath("powershell");
1954
- }
1955
- function buildPowerShellCommand(command) {
1956
- const executable = findPowerShellExecutable();
1957
- if (!executable) throw new Error("PowerShell is not available on this machine.");
1958
- return [
1959
- executable,
1960
- "-NoLogo",
1961
- "-NoProfile",
1962
- "-NonInteractive",
1963
- "-ExecutionPolicy",
1964
- "Bypass",
1965
- "-Command",
1966
- wrapPowerShellCommand(command)
1967
- ];
1968
- }
1969
- function buildBashCommand(command) {
1970
- const executable = resolveExecutableOnPath("bash") || resolveExecutableOnPath("sh");
1971
- if (!executable) throw new Error("bash/sh is not available on this machine.");
1972
- return [executable, "-lc", command];
1973
- }
1974
- function buildWorkspaceShellCommand(args) {
1975
- if (args.shell === "powershell") return buildPowerShellCommand(args.command);
1976
- if (args.shell === "bash") return buildBashCommand(args.command);
1977
- return process.platform === "win32" ? buildPowerShellCommand(args.command) : buildBashCommand(args.command);
1978
- }
1979
- function findWorkspaceShellEscapeToken(command) {
1980
- const tokens = tokenizeShellPrefix(command);
1981
- for (const token of tokens) {
1982
- if (token === ".." || token.startsWith("../") || token.startsWith("..\\") || token.includes("/../") || token.includes("\\..\\")) {
1983
- return token;
1984
- }
1985
- if (token === "~" || token.startsWith("~/") || token.startsWith("~\\")) {
1986
- return token;
1987
- }
1988
- if (token === "/" || token.startsWith("/") || /^[A-Za-z]:[\\/]/.test(token) || token.startsWith("\\\\")) {
1989
- return token;
2770
+ required: ["command"]
2771
+ }
1990
2772
  }
1991
- }
1992
- return null;
2773
+ };
1993
2774
  }
1994
- function buildWorkspaceShellEscapeBlockedResult(args) {
2775
+ function buildListProcessesTool() {
1995
2776
  return {
1996
- content: [
1997
- "workspace_shell_escape_blocked",
1998
- `blockedToken: ${args.token}`,
1999
- `command: ${args.command}`,
2000
- "Use paths relative to the authorized folder only.",
2001
- "exitCode: 126"
2002
- ].join("\n"),
2003
- metadata: {
2004
- exitCode: 126,
2005
- workspaceShellEscapeBlocked: true,
2006
- blockedToken: args.token
2777
+ type: "function",
2778
+ function: {
2779
+ name: "listProcesses",
2780
+ description: "List active background processes launched via launchProcess. Returns {pid, label, command, status, startedAt, persist}[].",
2781
+ parameters: {
2782
+ type: "object",
2783
+ properties: {}
2784
+ }
2007
2785
  }
2008
2786
  };
2009
2787
  }
@@ -2050,10 +2828,24 @@ function filterDeclaredWorkspaceToolNames(args) {
2050
2828
  );
2051
2829
  }
2052
2830
 
2831
+ // packages/agent-runtime/capabilities/capabilitySdk.ts
2832
+ var BUILTIN_CAPABILITIES = [
2833
+ execShellCapability
2834
+ ];
2835
+ async function invokeCapability(capabilityOrName, input, ctx = {}) {
2836
+ const capability = typeof capabilityOrName === "string" ? BUILTIN_CAPABILITIES.find((c) => c.name === capabilityOrName) : capabilityOrName;
2837
+ if (!capability) {
2838
+ throw new Error(`Capability "${String(capabilityOrName)}" not found.`);
2839
+ }
2840
+ const normalizedInput = capability.normalizeInput(input);
2841
+ await evaluateCapabilityPolicy(capability, normalizedInput, ctx);
2842
+ if (ctx.onInvoke) {
2843
+ await ctx.onInvoke(capability.name, normalizedInput);
2844
+ }
2845
+ return capability.invoke(ctx, normalizedInput);
2846
+ }
2847
+
2053
2848
  // packages/agent-runtime/localWorkspaceTools.ts
2054
- var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
2055
- var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
2056
- var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
2057
2849
  var DEFAULT_LOCAL_API_ORIGIN = "http://127.0.0.1:38123";
2058
2850
  var ALWAYS_EXCLUDED_GLOBS = [
2059
2851
  "*.tsbuildinfo",
@@ -2073,7 +2865,7 @@ var ALWAYS_EXCLUDED_GLOBS = [
2073
2865
  ];
2074
2866
  var DEFAULT_SEARCH_MAX_RESULTS = 200;
2075
2867
  var SEARCH_OUTPUT_CHAR_LIMIT = 2e4;
2076
- function readTrimmedString(value) {
2868
+ function readTrimmedString2(value) {
2077
2869
  return asOptionalTrimmedString(value);
2078
2870
  }
2079
2871
  function readBoolean(parsed, key) {
@@ -2086,168 +2878,6 @@ function readBoolean(parsed, key) {
2086
2878
  }
2087
2879
  return void 0;
2088
2880
  }
2089
- function resolveExecShellTimeoutMs(override) {
2090
- const fromOverride = asOptionalPositiveFiniteNumber(override);
2091
- if (fromOverride !== void 0) return fromOverride;
2092
- const raw = process.env[EXEC_SHELL_TIMEOUT_ENV];
2093
- if (raw === void 0) return void 0;
2094
- return asOptionalPositiveFiniteNumber(Number(raw));
2095
- }
2096
- function resolveDetachMs(override) {
2097
- if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
2098
- return override;
2099
- }
2100
- const raw = process.env[EXEC_SHELL_DETACH_ENV];
2101
- if (raw === void 0) return DEFAULT_EXEC_SHELL_DETACH_MS;
2102
- const parsed = asOptionalPositiveFiniteNumber(Number(raw));
2103
- return parsed === void 0 ? DEFAULT_EXEC_SHELL_DETACH_MS : parsed;
2104
- }
2105
- function extractInteractiveGhAuthCommand(command) {
2106
- const tokens = tokenizeShellPrefix(command);
2107
- if (tokens[0] !== "gh" || tokens[1] !== "auth") return null;
2108
- const subcommand = tokens[2];
2109
- if (subcommand !== "login" && subcommand !== "refresh") return null;
2110
- if (tokens.includes("--help")) return null;
2111
- const result = ["gh", "auth", subcommand];
2112
- for (let index = 3; index < tokens.length; index += 1) {
2113
- const token = tokens[index];
2114
- if (!token) continue;
2115
- if (token === "-h" || token === "--hostname" || token === "-s" || token === "--scopes" || token === "--remove-scopes" || token === "-r") {
2116
- const value = tokens[index + 1];
2117
- if (value) {
2118
- result.push(token, value);
2119
- index += 1;
2120
- }
2121
- continue;
2122
- }
2123
- if (token === "--clipboard" || token === "-c" || token === "--insecure-storage" || token === "--reset-scopes") {
2124
- result.push(token);
2125
- continue;
2126
- }
2127
- if (token.startsWith("--hostname=") || token.startsWith("--scopes=") || token.startsWith("--remove-scopes=")) {
2128
- result.push(token);
2129
- continue;
2130
- }
2131
- }
2132
- return result.join(" ");
2133
- }
2134
- function splitShellWords(command) {
2135
- return tokenizeShellPrefix(command);
2136
- }
2137
- function buildInteractiveCommandBlockedResult(command) {
2138
- const argv = splitShellWords(command);
2139
- return {
2140
- content: [
2141
- "action_gate: handoff",
2142
- `command: ${command}`,
2143
- "Run this in the current TUI terminal, then resume the agent turn.",
2144
- "exitCode: 130"
2145
- ].join("\n"),
2146
- metadata: {
2147
- exitCode: 130,
2148
- timedOut: false,
2149
- actionGate: {
2150
- id: `gate-${Date.now().toString(36)}-terminal-handoff`,
2151
- kind: "handoff",
2152
- title: "This command requires an interactive terminal.",
2153
- body: "Complete it in the terminal, then nolo will continue.",
2154
- payload: {
2155
- command: argv,
2156
- displayCommand: command
2157
- }
2158
- },
2159
- reason: "interactive-command-requires-terminal"
2160
- }
2161
- };
2162
- }
2163
- function extractActivityRefs(rawRefs) {
2164
- if (!Array.isArray(rawRefs)) return void 0;
2165
- const refs = rawRefs.flatMap((entry) => {
2166
- if (!isRecord(entry)) return [];
2167
- if (entry.type === "file") {
2168
- const path = readTrimmedString(entry.path);
2169
- return path ? [{ type: "file", path }] : [];
2170
- }
2171
- if (entry.type === "terminal") {
2172
- const id = readTrimmedString(entry.id);
2173
- const label = readTrimmedString(entry.label);
2174
- return id || label ? [{ type: "terminal", ...id ? { id } : {}, ...label ? { label } : {} }] : [];
2175
- }
2176
- if (entry.type === "url") {
2177
- const url = readTrimmedString(entry.url);
2178
- const label = readTrimmedString(entry.label);
2179
- return url ? [{ type: "url", url, ...label ? { label } : {} }] : [];
2180
- }
2181
- return [];
2182
- });
2183
- return refs.length ? refs : void 0;
2184
- }
2185
- function extractActivityAction(rawAction) {
2186
- if (!isRecord(rawAction)) return void 0;
2187
- const title = readTrimmedString(rawAction.title);
2188
- if (!title) return void 0;
2189
- const kind = readTrimmedString(rawAction.kind);
2190
- const detail = readTrimmedString(rawAction.detail);
2191
- const refs = extractActivityRefs(rawAction.refs);
2192
- return {
2193
- title,
2194
- ...kind ? { kind } : {},
2195
- ...detail ? { detail } : {},
2196
- ...refs ? { refs } : {}
2197
- };
2198
- }
2199
- function extractActivityPhase(rawPhase) {
2200
- if (!isRecord(rawPhase)) return void 0;
2201
- const title = readTrimmedString(rawPhase.title);
2202
- if (!title) return void 0;
2203
- const id = readTrimmedString(rawPhase.id) || title.toLowerCase().replace(/\s+/g, "-");
2204
- const index = asOptionalFiniteNumber(rawPhase.index);
2205
- const total = asOptionalFiniteNumber(rawPhase.total);
2206
- const status = rawPhase.status === "pending" || rawPhase.status === "running" || rawPhase.status === "success" || rawPhase.status === "failed" ? rawPhase.status : void 0;
2207
- return {
2208
- id,
2209
- title,
2210
- ...index !== void 0 ? { index } : {},
2211
- ...total !== void 0 ? { total } : {},
2212
- ...status ? { status } : {}
2213
- };
2214
- }
2215
- function extractActivityPlan(rawPlan) {
2216
- if (!isRecord(rawPlan)) return void 0;
2217
- if (!Array.isArray(rawPlan.phases)) return void 0;
2218
- const phases = rawPlan.phases.flatMap((entry, index) => {
2219
- const phase = extractActivityPhase(entry);
2220
- if (!phase) return [];
2221
- return [{
2222
- id: phase.id,
2223
- title: phase.title,
2224
- index: phase.index ?? index + 1,
2225
- ...phase.status ? { status: phase.status } : {}
2226
- }];
2227
- });
2228
- if (phases.length === 0) return void 0;
2229
- const title = readTrimmedString(rawPlan.title);
2230
- return {
2231
- ...title ? { title } : {},
2232
- phases
2233
- };
2234
- }
2235
- function extractActivity(parsed) {
2236
- const raw = parsed._activity;
2237
- if (!isRecord(raw)) return void 0;
2238
- const nestedAction = extractActivityAction(raw.action);
2239
- const legacyAction = extractActivityAction(raw);
2240
- const action = nestedAction || legacyAction;
2241
- const phase = extractActivityPhase(raw.phase);
2242
- const plan = extractActivityPlan(raw.plan);
2243
- if (!action && !plan) return void 0;
2244
- return {
2245
- ...action ? action : {},
2246
- ...phase ? { phase } : {},
2247
- ...nestedAction ? { action: nestedAction } : {},
2248
- ...plan ? { plan } : {}
2249
- };
2250
- }
2251
2881
  function buildLocalWorkspaceToolset(args) {
2252
2882
  const exposeShellTools = args.exposeShellTools === true;
2253
2883
  if (args.useDeclaredToolNamesOnly) {
@@ -2650,7 +3280,7 @@ function readVisualStateCaptureArgs(args) {
2650
3280
  }
2651
3281
  async function readWorkspacePackageScripts(workspaceRoot) {
2652
3282
  try {
2653
- const raw = await readFile(resolve(workspaceRoot, "package.json"), "utf8");
3283
+ const raw = await readFile(resolve2(workspaceRoot, "package.json"), "utf8");
2654
3284
  const parsed = JSON.parse(raw);
2655
3285
  const scripts = parsed && typeof parsed === "object" && parsed.scripts && typeof parsed.scripts === "object" ? Object.keys(parsed.scripts).sort() : [];
2656
3286
  return { scripts };
@@ -2685,97 +3315,35 @@ async function runWorkspacePackageScript(args) {
2685
3315
  }
2686
3316
  };
2687
3317
  }
2688
- const result = await runWorkspaceCommand({
2689
- workspaceRoot: args.workspaceRoot,
2690
- command: ["bun", "run", script, ...extraArgs.length ? ["--", ...extraArgs] : []],
2691
- timeoutMs: args.commandTimeoutMs
2692
- });
2693
- return {
2694
- content: result.content,
2695
- metadata: {
2696
- script,
2697
- args: extraArgs,
2698
- exitCode: result.exitCode,
2699
- reason: result.exitCode === 0 ? "ok" : "script-failed",
2700
- timedOut: result.timedOut,
2701
- stdoutTail: result.stdout.trim().slice(-4e3),
2702
- stderrTail: result.stderr.trim().slice(-4e3)
2703
- }
2704
- };
2705
- }
2706
- function truncateToolOutput(value, limit = 2e4) {
2707
- if (value.length <= limit) return value;
2708
- const approxMarkerLen = 40;
2709
- if (limit <= approxMarkerLen) return value.slice(0, limit);
2710
- const remaining = limit - approxMarkerLen;
2711
- const headSize = Math.floor(remaining * 0.3);
2712
- const tailSize = remaining - headSize;
2713
- const head = value.slice(0, headSize);
2714
- const tail = value.slice(-tailSize);
2715
- const actualRemoved = value.length - headSize - tailSize;
2716
- return `${head}
2717
-
2718
- [... truncated ${actualRemoved} chars ...]
2719
-
2720
- ${tail}`;
2721
- }
2722
- function parseLastJsonObject(text) {
2723
- const trimmed = text.trim();
2724
- for (let index = trimmed.lastIndexOf("{"); index >= 0; index = trimmed.lastIndexOf("{", index - 1)) {
2725
- try {
2726
- const parsed = JSON.parse(trimmed.slice(index));
2727
- return parsed && typeof parsed === "object" ? parsed : null;
2728
- } catch {
2729
- }
2730
- }
2731
- return null;
2732
- }
2733
- function readNodeStream(stream) {
2734
- if (!stream) return Promise.resolve("");
2735
- return new Promise((resolveRead, rejectRead) => {
2736
- const chunks = [];
2737
- stream.on("data", (chunk) => {
2738
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
2739
- });
2740
- stream.on("error", rejectRead);
2741
- stream.on("end", () => resolveRead(Buffer.concat(chunks).toString("utf8")));
2742
- });
2743
- }
2744
- function waitForNodeProcessExit(proc) {
2745
- return new Promise((resolveExit, rejectExit) => {
2746
- proc.once("error", rejectExit);
2747
- proc.once("close", (code, signal) => {
2748
- if (typeof code === "number") {
2749
- resolveExit(code);
2750
- return;
2751
- }
2752
- resolveExit(signal ? 1 : 0);
2753
- });
2754
- });
2755
- }
2756
- function isSpawnFailureError(error) {
2757
- if (!error || typeof error !== "object") return false;
2758
- const err = error;
2759
- if (err.code === "ENOENT") return true;
2760
- const message = toErrorMessage(error).toLowerCase();
2761
- return message.includes("enoent") || message.includes("executable not found") || message.includes("spawn") && message.includes("not found");
2762
- }
2763
- function spawnFailedCommandResult(error, outputLimit) {
2764
- const stderr = `spawn failed: ${toErrorMessage(error)}
2765
- `;
3318
+ const result = await runWorkspaceCommand({
3319
+ workspaceRoot: args.workspaceRoot,
3320
+ command: ["bun", "run", script, ...extraArgs.length ? ["--", ...extraArgs] : []],
3321
+ timeoutMs: args.commandTimeoutMs
3322
+ });
2766
3323
  return {
2767
- stdout: "",
2768
- stderr,
2769
- exitCode: 127,
2770
- timedOut: false,
2771
- spawnFailed: true,
2772
- content: truncateToolOutput(
2773
- [`stderr:
2774
- ${stderr.trim()}`, "exitCode: 127"].filter(Boolean).join("\n\n"),
2775
- outputLimit
2776
- )
3324
+ content: result.content,
3325
+ metadata: {
3326
+ script,
3327
+ args: extraArgs,
3328
+ exitCode: result.exitCode,
3329
+ reason: result.exitCode === 0 ? "ok" : "script-failed",
3330
+ timedOut: result.timedOut,
3331
+ stdoutTail: result.stdout.trim().slice(-4e3),
3332
+ stderrTail: result.stderr.trim().slice(-4e3)
3333
+ }
2777
3334
  };
2778
3335
  }
3336
+ function parseLastJsonObject(text) {
3337
+ const trimmed = text.trim();
3338
+ for (let index = trimmed.lastIndexOf("{"); index >= 0; index = trimmed.lastIndexOf("{", index - 1)) {
3339
+ try {
3340
+ const parsed = JSON.parse(trimmed.slice(index));
3341
+ return parsed && typeof parsed === "object" ? parsed : null;
3342
+ } catch {
3343
+ }
3344
+ }
3345
+ return null;
3346
+ }
2779
3347
  function resolveRipgrepBinary(env = process.env) {
2780
3348
  const fromEnv = asOptionalTrimmedString(env.NOLO_BUNDLED_RG);
2781
3349
  if (fromEnv) {
@@ -2789,185 +3357,13 @@ function resolveRipgrepBinary(env = process.env) {
2789
3357
  function resolveGrepBinary() {
2790
3358
  return resolveExecutableOnPath("grep");
2791
3359
  }
2792
- async function runWorkspaceCommand(args) {
2793
- const timeoutMs = asOptionalPositiveFiniteNumber(args.timeoutMs);
2794
- const detached = process.platform !== "win32";
2795
- const command = [
2796
- ...args.commandPrefix ?? [],
2797
- ...args.command
2798
- ];
2799
- const proc = spawnChildProcess(command[0] ?? "", command.slice(1), {
2800
- cwd: resolve(args.workspaceRoot),
2801
- stdio: [
2802
- args.stdin === void 0 ? "ignore" : "pipe",
2803
- "pipe",
2804
- "pipe"
2805
- ],
2806
- detached
2807
- });
2808
- if (args.stdin !== void 0 && proc.stdin) {
2809
- proc.stdin.write(args.stdin);
2810
- proc.stdin.end();
2811
- }
2812
- const exitPromise = waitForNodeProcessExit(proc);
2813
- const cleanupChildOnHostSignal = (signal) => {
2814
- if (typeof proc.pid === "number") {
2815
- try {
2816
- process.kill(-proc.pid, signal);
2817
- } catch {
2818
- }
2819
- }
2820
- };
2821
- if (detached) {
2822
- process.once("SIGHUP", cleanupChildOnHostSignal);
2823
- process.once("SIGTERM", cleanupChildOnHostSignal);
2824
- process.once("SIGINT", cleanupChildOnHostSignal);
2825
- }
2826
- const detachSignalCleanup = () => {
2827
- if (!detached) return;
2828
- process.removeListener("SIGHUP", cleanupChildOnHostSignal);
2829
- process.removeListener("SIGTERM", cleanupChildOnHostSignal);
2830
- process.removeListener("SIGINT", cleanupChildOnHostSignal);
2831
- };
2832
- exitPromise.then(detachSignalCleanup, detachSignalCleanup);
2833
- const stdoutPromise = readNodeStream(proc.stdout);
2834
- const stderrPromise = readNodeStream(proc.stderr);
2835
- const killChild = (signal) => {
2836
- if (detached && typeof proc.pid === "number") {
2837
- try {
2838
- process.kill(-proc.pid, signal);
2839
- return;
2840
- } catch {
2841
- }
2842
- }
2843
- try {
2844
- proc.kill(signal);
2845
- } catch {
2846
- }
2847
- };
2848
- let timeout;
2849
- let detachTimer;
2850
- const timeoutResult = Symbol("timeout");
2851
- const abortResult = Symbol("abort");
2852
- const detachResult = Symbol("detach");
2853
- let abortListener;
2854
- const abortPromise = args.abortSignal ? new Promise((resolveAbort) => {
2855
- if (args.abortSignal.aborted) {
2856
- resolveAbort(abortResult);
2857
- return;
2858
- }
2859
- abortListener = () => resolveAbort(abortResult);
2860
- args.abortSignal.addEventListener("abort", abortListener, { once: true });
2861
- }) : null;
2862
- const effectiveDetachMs = resolveDetachMs(args.detachMs);
2863
- const detachPromise = new Promise((r) => {
2864
- detachTimer = setTimeout(() => r(detachResult), effectiveDetachMs);
2865
- });
2866
- const racers = [exitPromise];
2867
- if (timeoutMs) {
2868
- racers.push(
2869
- new Promise((resolveTimeout) => {
2870
- timeout = setTimeout(() => resolveTimeout(timeoutResult), timeoutMs);
2871
- })
2872
- );
2873
- }
2874
- if (abortPromise) racers.push(abortPromise);
2875
- racers.push(detachPromise);
2876
- let raceWinner;
2877
- try {
2878
- raceWinner = await Promise.race(racers);
2879
- } catch (error) {
2880
- if (timeout) clearTimeout(timeout);
2881
- if (detachTimer) clearTimeout(detachTimer);
2882
- if (abortListener && args.abortSignal) {
2883
- args.abortSignal.removeEventListener("abort", abortListener);
2884
- }
2885
- detachSignalCleanup();
2886
- if (isSpawnFailureError(error)) {
2887
- return spawnFailedCommandResult(error, args.outputLimit);
2888
- }
2889
- throw error;
2890
- }
2891
- if (timeout) clearTimeout(timeout);
2892
- if (detachTimer) clearTimeout(detachTimer);
2893
- if (abortListener && args.abortSignal) {
2894
- args.abortSignal.removeEventListener("abort", abortListener);
2895
- }
2896
- const timedOut = raceWinner === timeoutResult;
2897
- const aborted = raceWinner === abortResult;
2898
- const didDetach = raceWinner === detachResult;
2899
- if (timedOut || aborted) {
2900
- killChild("SIGTERM");
2901
- await Promise.race([
2902
- exitPromise.catch(() => 124),
2903
- new Promise((resolveKill) => setTimeout(resolveKill, 500))
2904
- ]);
2905
- killChild("SIGKILL");
2906
- }
2907
- if (didDetach) {
2908
- exitPromise.catch(() => {
2909
- });
2910
- const pid = typeof proc.pid === "number" ? proc.pid : 0;
2911
- const label = deriveLabel(args.command.join(" "));
2912
- const pgid = pid;
2913
- const registry2 = getProcessRegistry();
2914
- registry2.add({ pid, pgid, command: args.command.join(" "), label });
2915
- proc.on("close", (code) => {
2916
- detachSignalCleanup();
2917
- registry2.markExited(pid, code ?? 1);
2918
- });
2919
- const immediate = effectiveDetachMs === 0;
2920
- const reason = immediate ? `command looks long-running; moved to background immediately (pid=${pid}, label=${label})` : `command detached to background after ${effectiveDetachMs}ms (pid=${pid}, label=${label})`;
2921
- return {
2922
- stdout: "",
2923
- stderr: `${reason}
2924
- Use listProcesses to inspect or stop it.`,
2925
- exitCode: 0,
2926
- timedOut: false,
2927
- detached: true,
2928
- pid,
2929
- label,
2930
- content: JSON.stringify({
2931
- detached: true,
2932
- pid,
2933
- label,
2934
- status: "running",
2935
- ...immediate ? { reason: "long-running-command" } : {}
2936
- })
2937
- };
2938
- }
2939
- const [stdout, rawStderr] = await Promise.all([
2940
- stdoutPromise,
2941
- stderrPromise
2942
- ]);
2943
- const exitCode = aborted ? 130 : timedOut ? 124 : Number(raceWinner);
2944
- const stderr = aborted ? `${rawStderr.trim() ? `${rawStderr.trim()}
2945
- ` : ""}command aborted by signal
2946
- ` : timedOut ? `${rawStderr.trim() ? `${rawStderr.trim()}
2947
- ` : ""}command timed out after ${timeoutMs ?? "unknown"}ms
2948
- ` : rawStderr;
2949
- return {
2950
- stdout,
2951
- stderr,
2952
- exitCode,
2953
- timedOut,
2954
- aborted,
2955
- content: truncateToolOutput([
2956
- stdout.trim() ? `stdout:
2957
- ${stdout.trim()}` : "",
2958
- stderr.trim() ? `stderr:
2959
- ${stderr.trim()}` : "",
2960
- `exitCode: ${exitCode}`
2961
- ].filter(Boolean).join("\n\n"), args.outputLimit)
2962
- };
2963
- }
2964
3360
  async function runWorkspaceCommandLimitedLines(args) {
2965
3361
  const command = [
2966
3362
  ...args.commandPrefix ?? [],
2967
3363
  ...args.command
2968
3364
  ];
2969
- const proc = spawnChildProcess(command[0] ?? "", command.slice(1), {
2970
- cwd: resolve(args.workspaceRoot),
3365
+ const proc = spawnChildProcess2(command[0] ?? "", command.slice(1), {
3366
+ cwd: resolve2(args.workspaceRoot),
2971
3367
  stdio: ["ignore", "pipe", "pipe"],
2972
3368
  detached: false
2973
3369
  });
@@ -3058,8 +3454,8 @@ async function runWorkspaceCommandLimitedLines(args) {
3058
3454
  };
3059
3455
  }
3060
3456
  async function resolveLocalWorkspaceToolPath(args) {
3061
- const workspaceRoot = resolve(args.workspaceRoot);
3062
- const targetPath = resolve(workspaceRoot, args.requestedPath);
3457
+ const workspaceRoot = resolve2(args.workspaceRoot);
3458
+ const targetPath = resolve2(workspaceRoot, args.requestedPath);
3063
3459
  if (!isPathInsideWorkspace({ workspaceRoot, targetPath })) {
3064
3460
  if (args.confirmExternalFileAccess) {
3065
3461
  const request = {
@@ -3151,7 +3547,7 @@ async function readFileTool(args) {
3151
3547
  });
3152
3548
  const isTruncated = sliced.truncated || truncatedRead.truncatedByCharLimit;
3153
3549
  const relativePath = normalizeWorkspaceRelativePath({
3154
- workspaceRoot: resolve(args.workspaceRoot),
3550
+ workspaceRoot: resolve2(args.workspaceRoot),
3155
3551
  targetPath: absolutePath
3156
3552
  });
3157
3553
  const force = parsed.force === true;
@@ -3218,7 +3614,7 @@ async function writeFileTool(args) {
3218
3614
  await mkdir(dirname(absolutePath), { recursive: true });
3219
3615
  await writeFile(absolutePath, content, "utf8");
3220
3616
  const relativePath = normalizeWorkspaceRelativePath({
3221
- workspaceRoot: resolve(args.workspaceRoot),
3617
+ workspaceRoot: resolve2(args.workspaceRoot),
3222
3618
  targetPath: absolutePath
3223
3619
  });
3224
3620
  const activity = extractActivity(parsed);
@@ -3274,7 +3670,7 @@ async function editFileTool(args) {
3274
3670
  }
3275
3671
  await writeFile(absolutePath, nextContent, "utf8");
3276
3672
  const relativePath = normalizeWorkspaceRelativePath({
3277
- workspaceRoot: resolve(args.workspaceRoot),
3673
+ workspaceRoot: resolve2(args.workspaceRoot),
3278
3674
  targetPath: absolutePath
3279
3675
  });
3280
3676
  const activity = extractActivity(parsed);
@@ -3300,11 +3696,11 @@ async function listWorkspaceEntries(args) {
3300
3696
  const names = (await readdir(dirPath)).sort((left, right) => left.localeCompare(right));
3301
3697
  for (const name of names) {
3302
3698
  if (truncated) break;
3303
- const absolutePath = resolve(dirPath, name);
3699
+ const absolutePath = resolve2(dirPath, name);
3304
3700
  const info = await stat(absolutePath);
3305
3701
  visitedEntries += 1;
3306
3702
  const relativePath = normalizeWorkspaceRelativePath({
3307
- workspaceRoot: resolve(args.workspaceRoot),
3703
+ workspaceRoot: resolve2(args.workspaceRoot),
3308
3704
  targetPath: absolutePath
3309
3705
  });
3310
3706
  const isDirectory = info.isDirectory();
@@ -3383,7 +3779,7 @@ async function searchFilesTool(args) {
3383
3779
  ...args.confirmExternalFileAccess ? { confirmExternalFileAccess: args.confirmExternalFileAccess } : {}
3384
3780
  });
3385
3781
  const relativeSearchPath = normalizeWorkspaceRelativePath({
3386
- workspaceRoot: resolve(args.workspaceRoot),
3782
+ workspaceRoot: resolve2(args.workspaceRoot),
3387
3783
  targetPath: searchPath
3388
3784
  });
3389
3785
  const rgBinary = (args.resolveRipgrepBinary ?? resolveRipgrepBinary)();
@@ -3537,7 +3933,7 @@ async function searchFilesTool(args) {
3537
3933
  }
3538
3934
  async function hasRootGitignore(workspaceRoot) {
3539
3935
  try {
3540
- await stat(resolve(workspaceRoot, ".gitignore"));
3936
+ await stat(resolve2(workspaceRoot, ".gitignore"));
3541
3937
  return true;
3542
3938
  } catch {
3543
3939
  return false;
@@ -3545,7 +3941,7 @@ async function hasRootGitignore(workspaceRoot) {
3545
3941
  }
3546
3942
  async function readRootGitignorePatterns(workspaceRoot) {
3547
3943
  try {
3548
- const content = await readFile(resolve(workspaceRoot, ".gitignore"), "utf8");
3944
+ const content = await readFile(resolve2(workspaceRoot, ".gitignore"), "utf8");
3549
3945
  return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && !line.startsWith("!")).map((line) => {
3550
3946
  const unanchored = line.replace(/^\//, "");
3551
3947
  return unanchored.endsWith("/") ? `${unanchored}**` : unanchored;
@@ -3614,7 +4010,7 @@ async function scanWorkspaceTextMatches(args) {
3614
4010
  for (const file of files) {
3615
4011
  let content = "";
3616
4012
  try {
3617
- content = await readFile(resolve(args.workspaceRoot, file), "utf8");
4013
+ content = await readFile(resolve2(args.workspaceRoot, file), "utf8");
3618
4014
  } catch {
3619
4015
  continue;
3620
4016
  }
@@ -3659,7 +4055,7 @@ async function globFilesTool(args) {
3659
4055
  ...args.confirmExternalFileAccess ? { confirmExternalFileAccess: args.confirmExternalFileAccess } : {}
3660
4056
  });
3661
4057
  const relativeSearchPath = normalizeWorkspaceRelativePath({
3662
- workspaceRoot: resolve(args.workspaceRoot),
4058
+ workspaceRoot: resolve2(args.workspaceRoot),
3663
4059
  targetPath: searchPath
3664
4060
  });
3665
4061
  const pathPrefix = relativeSearchPath === "." ? "" : `${relativeSearchPath.replace(/\/+$/, "")}/`;
@@ -3819,63 +4215,24 @@ async function captureVisualStateTool(args) {
3819
4215
  };
3820
4216
  }
3821
4217
  async function execShellTool(args) {
3822
- const parsed = parseWorkspaceToolArguments(args.call.arguments);
3823
- const command = requireShellCommand(parsed, args.call.name);
3824
- if (args.restrictToWorkspace) {
3825
- const escapeToken = findWorkspaceShellEscapeToken(command);
3826
- if (escapeToken) {
3827
- return buildWorkspaceShellEscapeBlockedResult({ command, token: escapeToken });
3828
- }
3829
- }
3830
- const interactiveAuthCommand = extractInteractiveGhAuthCommand(command);
3831
- if (interactiveAuthCommand) {
3832
- const activity2 = extractActivity(parsed);
3833
- const blocked = buildInteractiveCommandBlockedResult(interactiveAuthCommand);
3834
- return {
3835
- ...blocked,
3836
- metadata: {
3837
- ...blocked.metadata,
3838
- ...activity2 ? { activity: activity2 } : {}
3839
- }
3840
- };
3841
- }
3842
- const result = await runWorkspaceCommand({
3843
- workspaceRoot: args.workspaceRoot,
3844
- command: buildWorkspaceShellCommand({
3845
- toolName: args.call.name,
3846
- command,
3847
- shell: parsed.shell
3848
- }),
3849
- timeoutMs: resolveExecShellTimeoutMs(args.commandTimeoutMs),
3850
- outputLimit: args.commandOutputLimit,
3851
- commandPrefix: args.commandPrefix,
3852
- abortSignal: args.abortSignal,
3853
- // Commands that clearly never exit (long sleeps, tail -f, watch, dev
3854
- // servers, infinite loops) are promoted to background immediately so the
3855
- // turn — and the user's conversation — keeps going. Everything else keeps
3856
- // the caller/env detach grace window.
3857
- detachMs: isImmediateDetachShellCommand({ command }) ? 0 : args.detachMs
3858
- });
3859
- const activity = extractActivity(parsed);
3860
- return {
3861
- content: result.content,
3862
- metadata: {
3863
- command,
3864
- exitCode: result.exitCode,
3865
- timedOut: result.timedOut,
3866
- ...result.aborted ? { aborted: true } : {},
3867
- ...result.detached ? { detached: true, pid: result.pid, label: result.label, status: "running" } : {},
3868
- ...activity ? { activity } : {}
4218
+ return invokeCapability(
4219
+ "execShell",
4220
+ args.call.arguments,
4221
+ {
4222
+ workspaceRoot: args.workspaceRoot,
4223
+ commandTimeoutMs: args.commandTimeoutMs,
4224
+ commandOutputLimit: args.commandOutputLimit,
4225
+ commandPrefix: args.commandPrefix,
4226
+ restrictToWorkspace: args.restrictToWorkspace,
4227
+ abortSignal: args.abortSignal,
4228
+ detachMs: args.detachMs,
4229
+ confirmed: args.confirmed,
4230
+ enableDestructiveShellGuard: args.enableDestructiveShellGuard,
4231
+ confirmDestructiveAction: args.confirmDestructiveAction,
4232
+ blockDestructiveWithoutConfirmation: args.blockDestructiveWithoutConfirmation,
4233
+ onInvoke: args.onInvoke
3869
4234
  }
3870
- };
3871
- }
3872
- function deriveLabel(command) {
3873
- const trimmed = command.trim();
3874
- if (!trimmed) return "process";
3875
- const tokens = trimmed.split(/\s+/);
3876
- const lastToken = tokens[tokens.length - 1] ?? trimmed;
3877
- const labelCandidate = lastToken.split(/[/\\]/).pop() || lastToken;
3878
- return labelCandidate || trimmed;
4235
+ );
3879
4236
  }
3880
4237
  async function launchProcessTool(args) {
3881
4238
  const parsed = parseWorkspaceToolArguments(args.call.arguments);
@@ -3886,7 +4243,7 @@ async function launchProcessTool(args) {
3886
4243
  return buildWorkspaceShellEscapeBlockedResult({ command, token: escapeToken });
3887
4244
  }
3888
4245
  }
3889
- const labelArg = readTrimmedString(parsed.label);
4246
+ const labelArg = readTrimmedString2(parsed.label);
3890
4247
  const label = labelArg || deriveLabel(command);
3891
4248
  const persist = readBoolean(parsed, "persist");
3892
4249
  const fullCommand = buildWorkspaceShellCommand({
@@ -3899,8 +4256,8 @@ async function launchProcessTool(args) {
3899
4256
  ...fullCommand
3900
4257
  ];
3901
4258
  const detached = process.platform !== "win32";
3902
- const proc = spawnChildProcess(cmdArgs[0] ?? "", cmdArgs.slice(1), {
3903
- cwd: resolve(args.workspaceRoot),
4259
+ const proc = spawnChildProcess2(cmdArgs[0] ?? "", cmdArgs.slice(1), {
4260
+ cwd: resolve2(args.workspaceRoot),
3904
4261
  stdio: ["ignore", "pipe", "pipe"],
3905
4262
  detached
3906
4263
  });
@@ -4015,7 +4372,12 @@ function createLocalWorkspaceToolExecutors(args) {
4015
4372
  commandPrefix: args.commandPrefix,
4016
4373
  restrictToWorkspace: args.restrictShellToWorkspace,
4017
4374
  abortSignal: opts?.abortSignal ?? args.abortSignal,
4018
- detachMs: opts?.detachMs ?? args.detachMs
4375
+ detachMs: opts?.detachMs ?? args.detachMs,
4376
+ confirmed: opts?.confirmed,
4377
+ enableDestructiveShellGuard: opts?.enableDestructiveShellGuard,
4378
+ confirmDestructiveAction: opts?.confirmDestructiveAction,
4379
+ blockDestructiveWithoutConfirmation: opts?.blockDestructiveWithoutConfirmation,
4380
+ onInvoke: opts?.onInvoke
4019
4381
  }),
4020
4382
  launchProcess: (call) => launchProcessTool({
4021
4383
  call,
@@ -4029,6 +4391,23 @@ function createLocalWorkspaceToolExecutors(args) {
4029
4391
  };
4030
4392
  }
4031
4393
 
4394
+ // packages/cli/client/localDialogRecords.ts
4395
+ var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
4396
+ function buildLocalDialogWritePlan(args) {
4397
+ return buildAgentRuntimeDialogWritePlan({
4398
+ input: args.input,
4399
+ userId: args.userId,
4400
+ now: args.now,
4401
+ createId: args.createId,
4402
+ existingDialog: args.existingDialog,
4403
+ runtimeHost: "cli",
4404
+ runtimeMetadata: {
4405
+ ...args.cwd ? { worktreePath: args.cwd } : {}
4406
+ },
4407
+ ...args.titleOverride ? { titleOverride: args.titleOverride } : {}
4408
+ });
4409
+ }
4410
+
4032
4411
  // packages/agent-runtime/noloWorkspaceTools.node.ts
4033
4412
  async function readNoloProcessStream(readable) {
4034
4413
  if (!readable) return "";
@@ -4065,10 +4444,67 @@ async function runNoloWorkspaceCliTool(call, args) {
4065
4444
  }
4066
4445
  };
4067
4446
  }
4447
+ async function readDialogInProcess(call, store, env) {
4448
+ const args = parseNoloWorkspaceToolArguments(call.arguments);
4449
+ const dialogInput = noloStringArg(args.dialog ?? args.dialogId ?? args.id);
4450
+ if (!dialogInput) throw new Error("readDialog requires dialog.");
4451
+ const mode = noloStringArg(args.mode);
4452
+ if (mode && mode !== "full" && mode !== "status") {
4453
+ throw new Error(`readDialog mode must be "full" or "status", got "${mode}".`);
4454
+ }
4455
+ const userId = noloStringArg(args.user ?? args.userId ?? args.owner) || env?.NOLO_LOCAL_USER_ID || env?.NOLO_USER_ID || "";
4456
+ const { dbKey: dialogKey, dialogId } = resolveNoloDialogInput(dialogInput, userId);
4457
+ const meta = await store.read(dialogKey, { remote: false });
4458
+ if (mode === "status") {
4459
+ const result2 = {
4460
+ dialogId,
4461
+ dialogKey,
4462
+ meta,
4463
+ status: meta?.status ?? null,
4464
+ runtimeCheckpoint: meta?.runtimeCheckpoint ?? null,
4465
+ source: "in-process"
4466
+ };
4467
+ return {
4468
+ content: JSON.stringify(result2, null, 2),
4469
+ metadata: { noloWorkspaceTool: true, readDialog: true, inProcess: true, mode: "status" }
4470
+ };
4471
+ }
4472
+ const limitNum = noloPositiveIntegerString(args.limit);
4473
+ const limit = limitNum ? Number(limitNum) : void 0;
4474
+ const rawMessages = [];
4475
+ if (store.iterator) {
4476
+ const { start, end } = dialogMessageRange(dialogId);
4477
+ for await (const [, value] of store.iterator({ gte: start, lte: end })) {
4478
+ const message = localDialogMessageRecordToRuntimeMessage(value);
4479
+ if (message) {
4480
+ rawMessages.push(message);
4481
+ } else if (value) {
4482
+ rawMessages.push(value);
4483
+ }
4484
+ }
4485
+ }
4486
+ const messages = limit !== void 0 && rawMessages.length > limit ? rawMessages.slice(rawMessages.length - limit) : rawMessages;
4487
+ const result = {
4488
+ dialogId,
4489
+ dialogKey,
4490
+ meta,
4491
+ messages,
4492
+ messagesCount: messages.length,
4493
+ source: "in-process"
4494
+ };
4495
+ return {
4496
+ content: JSON.stringify(result, null, 2),
4497
+ metadata: { noloWorkspaceTool: true, readDialog: true, inProcess: true }
4498
+ };
4499
+ }
4068
4500
  function buildNoloWorkspaceCliToolExecutors(args) {
4069
4501
  const executors = {};
4070
4502
  for (const toolName of NOLO_WORKSPACE_TOOL_NAMES) {
4071
4503
  if (toolName === "loadSkill") continue;
4504
+ if (toolName === "readDialog" && args.store) {
4505
+ executors[toolName] = (call) => readDialogInProcess(call, args.store, args.env);
4506
+ continue;
4507
+ }
4072
4508
  executors[toolName] = (call) => runNoloWorkspaceCliTool(call, args);
4073
4509
  }
4074
4510
  return executors;
@@ -4086,10 +4522,10 @@ function buildLoadSkillExecutor(args) {
4086
4522
  metadata: { loadSkill: true, resolved: false }
4087
4523
  };
4088
4524
  }
4089
- const { resolveSkillByName } = await import("./skillDiscovery-5U6RYAHN.js");
4525
+ const { resolveSkillByName } = await import("./skillDiscovery-KLLKXPUO.js");
4090
4526
  const resolved = resolveSkillByName(args.cwd, name);
4091
4527
  if (!resolved) {
4092
- const { resolveCodingBuiltinSlug, buildCodingSkillContentBySlug } = await import("./codingSkills-V35TRR4Y.js");
4528
+ const { resolveCodingBuiltinSlug, buildCodingSkillContentBySlug } = await import("./codingSkills-DY5MINPG.js");
4093
4529
  const builtinSlug = resolveCodingBuiltinSlug(name);
4094
4530
  if (builtinSlug) {
4095
4531
  const body = buildCodingSkillContentBySlug(builtinSlug);
@@ -4124,7 +4560,7 @@ ${body}`,
4124
4560
  };
4125
4561
  }
4126
4562
  async function formatUnknownSkillMessage(cwd, requestedName) {
4127
- const { discoverSkills } = await import("./skillDiscovery-5U6RYAHN.js");
4563
+ const { discoverSkills } = await import("./skillDiscovery-KLLKXPUO.js");
4128
4564
  let available = [];
4129
4565
  try {
4130
4566
  available = discoverSkills(cwd).map((s) => s.name);
@@ -4144,6 +4580,8 @@ export {
4144
4580
  isAgentCoolingDown,
4145
4581
  parseSseDataLineJson,
4146
4582
  parseSseDataLineObject,
4583
+ codexStreamFailureStatus,
4584
+ aggregateResponsesStream,
4147
4585
  buildOpenAiCompatibleChatCompletionRequest,
4148
4586
  parseOpenAiCompatibleChatCompletionResponse,
4149
4587
  readOpenAiCompatibleSseCompletion,
@@ -4165,6 +4603,8 @@ export {
4165
4603
  buildLocalWorkspacePolicyToolNames,
4166
4604
  buildLocalWorkspaceOpenAiTools,
4167
4605
  createLocalWorkspaceToolExecutors,
4606
+ localDialogMessageRecordToRuntimeMessage,
4607
+ buildLocalDialogWritePlan,
4168
4608
  buildNoloWorkspaceCliToolExecutors,
4169
4609
  buildLoadSkillExecutor
4170
4610
  };