nolo-cli 0.212.0-alpha.1 → 0.213.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/{_executeModel-KE6MBNUJ.js → _executeModel-CUJLCFWR.js} +35 -35
  2. package/{addContentAction-N2YC5IL3.js → addContentAction-WERAONNY.js} +5 -5
  3. package/{addDialogAgentAction-3NKVQCEC.js → addDialogAgentAction-7VI7YRML.js} +4 -4
  4. package/{agentDeleteCommand-NWK7VU4N.js → agentDeleteCommand-XJORXPGU.js} +42 -42
  5. package/{agentEmailCommands-UZ4DHEX2.js → agentEmailCommands-XTYYFR6Z.js} +43 -43
  6. package/{agentListCommands-HE7L2A6L.js → agentListCommands-OBLRBLHS.js} +60 -51
  7. package/{agentMachineCommands-6TE4MBMP.js → agentMachineCommands-5FMT3OT5.js} +13 -12
  8. package/{agentRecordCommands-L3QQ7HZ4.js → agentRecordCommands-ZQ7SVYGG.js} +42 -42
  9. package/{agentRunCommand-2IFGQHCO.js → agentRunCommand-WS7IGO2W.js} +43 -43
  10. package/{agentRunControl-OI3LOENH.js → agentRunControl-TAMHJQSR.js} +3 -3
  11. package/{agentRuntimeLocal-HL526DNQ.js → agentRuntimeLocal-SOO2OPJG.js} +10 -10
  12. package/{agentSlice-TMYP2UEA.js → agentSlice-CHR6KOZN.js} +5 -5
  13. package/{appDeleteCommands-ZERW4AXY.js → appDeleteCommands-GUP6P5YE.js} +15 -14
  14. package/{appDeployCommands-DUWSMYHL.js → appDeployCommands-MH2FX4O5.js} +15 -14
  15. package/{appDeployStatusCommands-N2KIE4BF.js → appDeployStatusCommands-SUHN3HPJ.js} +15 -14
  16. package/{appGetCommands-YVR4NPVY.js → appGetCommands-YWDEX6Z4.js} +15 -14
  17. package/{appListCommands-JS6HOHZS.js → appListCommands-ZQVMLPAY.js} +15 -14
  18. package/{authCommand-FE2C3ZUM.js → authCommand-PWX2ZNUP.js} +2 -2
  19. package/{builtinSkillRegistry-3YOIGEF6.js → builtinSkillRegistry-2QETTQPM.js} +2 -2
  20. package/{chromeOpsCommands-HEN5AX2J.js → chromeOpsCommands-DIVM2K3T.js} +1 -1
  21. package/{chunk-YUXQAVRD.js → chunk-3UKL3HPD.js} +251 -14
  22. package/{chunk-PDGKOTO7.js → chunk-4T2WNOY7.js} +4 -4
  23. package/{chunk-NOMIGOST.js → chunk-5MQRBSMW.js} +35 -41
  24. package/{chunk-5RYBGBQH.js → chunk-6DWMYIUY.js} +3 -3
  25. package/{chunk-KSTEXKL6.js → chunk-75XIDFBW.js} +4 -3
  26. package/{chunk-CZM5YTZ7.js → chunk-7BT37FK3.js} +193 -305
  27. package/{chunk-GPO7FCEZ.js → chunk-7QTZCMKL.js} +159 -106
  28. package/{chunk-NJR3WKVP.js → chunk-7Y4YTDQF.js} +6 -6
  29. package/{chunk-CKAHAVMK.js → chunk-A7TFUNZO.js} +35 -25
  30. package/{chunk-PJNFNEJE.js → chunk-ALQ3657A.js} +28 -2
  31. package/{chunk-YJMRHHGY.js → chunk-BBJ22CLB.js} +5 -5
  32. package/{chunk-AVTVGMDY.js → chunk-COFEN36Z.js} +1 -1
  33. package/{chunk-DM6UMOEL.js → chunk-CRHOO2ZR.js} +1 -1
  34. package/{chunk-EYUBHHFB.js → chunk-EHGEOAHI.js} +2 -2
  35. package/{chunk-Y2WUYX4I.js → chunk-EHSZD5OI.js} +1 -1
  36. package/{chunk-QT6PKHYJ.js → chunk-FUGMREBO.js} +2 -2
  37. package/{chunk-BFM34N54.js → chunk-FW6YHHLI.js} +4 -4
  38. package/{chunk-3FOQHGHN.js → chunk-G2BQWAVT.js} +2 -2
  39. package/{chunk-VPAZOH2D.js → chunk-GPVRUGGY.js} +1 -1
  40. package/{chunk-JNKSDZFS.js → chunk-H4UOTUOX.js} +162 -48
  41. package/{chunk-UTV2AYEG.js → chunk-H5HF7TJA.js} +1 -1
  42. package/{chunk-IJXYFTV7.js → chunk-H7PPIYWP.js} +1 -1
  43. package/{chunk-NRFKLKRU.js → chunk-HSVBJRF4.js} +1 -1
  44. package/{chunk-GNDJKC4B.js → chunk-HUBHAQK2.js} +8 -8
  45. package/{chunk-LKDF3ATR.js → chunk-INUFILG6.js} +1 -1
  46. package/{chunk-OHNELDTO.js → chunk-IXNGOHV5.js} +2 -2
  47. package/{chunk-WXYLV624.js → chunk-J2NHJ7WX.js} +4 -4
  48. package/{chunk-YPD3VJZW.js → chunk-KFLT5KAD.js} +4 -4
  49. package/{chunk-OOF4UPC5.js → chunk-LLRPJECG.js} +4 -4
  50. package/{chunk-B7NJ3T4A.js → chunk-MDB67IWP.js} +4 -4
  51. package/{chunk-IF45XG7K.js → chunk-MOIJOHA5.js} +9 -4
  52. package/{chunk-IIQ6JGRI.js → chunk-NJLL224W.js} +1 -1
  53. package/{chunk-YOIW77S2.js → chunk-NOKUNJON.js} +2 -2
  54. package/{chunk-HIRC32DV.js → chunk-NSAPDIN2.js} +8 -4
  55. package/{chunk-JIT6FSXJ.js → chunk-O2TZF4AI.js} +1 -1
  56. package/{chunk-4KH4J3G5.js → chunk-OQPKUBPB.js} +1 -1
  57. package/{chunk-OXME3PEE.js → chunk-PCLE46CE.js} +1 -1
  58. package/{chunk-CJRONOYL.js → chunk-QG4AOSON.js} +8 -45
  59. package/{chunk-6OQUPIQF.js → chunk-QHPRUL4O.js} +3 -3
  60. package/{chunk-MMNYUVLW.js → chunk-R5O4QAWG.js} +1 -1
  61. package/{chunk-IAPCBNEE.js → chunk-RLBNLZVC.js} +1 -1
  62. package/{chunk-FHU44LN3.js → chunk-RSHTSUEG.js} +246 -77
  63. package/{chunk-25JZEIXN.js → chunk-RZOV7OMV.js} +11 -11
  64. package/{chunk-D2MDMY2M.js → chunk-SVYO6AO7.js} +7 -1
  65. package/{chunk-INSBKSBB.js → chunk-TAKB25RM.js} +1 -1
  66. package/{chunk-RU4SD66C.js → chunk-TX5EYMGT.js} +5 -5
  67. package/{chunk-D5RCRX4A.js → chunk-UYD5HQ6T.js} +746 -177
  68. package/{chunk-JTDORD5P.js → chunk-V5Y3R6BT.js} +110 -2
  69. package/{chunk-3RQVYR4B.js → chunk-VNYYOX3V.js} +59 -20
  70. package/{chunk-3AKFVZ2I.js → chunk-VO4WSAVP.js} +3 -3
  71. package/{chunk-6NSSLV67.js → chunk-WMTBPBMP.js} +6 -6
  72. package/{chunk-EZFQ6XRV.js → chunk-WRYQ35LQ.js} +4 -4
  73. package/{chunk-SOHTHFV2.js → chunk-WYDI6TGM.js} +14 -14
  74. package/{chunk-M6RL5JCD.js → chunk-X7SDOJUM.js} +3 -3
  75. package/{chunk-CQ46IRNN.js → chunk-XHQC4PXX.js} +48 -34
  76. package/{chunk-2WZXXAQD.js → chunk-YB3YZK56.js} +67 -1
  77. package/{chunk-22CIEBYO.js → chunk-YJAFKXMU.js} +11 -11
  78. package/{chunk-GSQNH63I.js → chunk-YTF4WH7J.js} +3 -19
  79. package/{chunk-5AQR3DGV.js → chunk-ZNWI6OVT.js} +2 -2
  80. package/{chunk-VZKUKCA6.js → chunk-ZXOUUDCG.js} +49 -40
  81. package/{commandRegistry-VVMTPFAX.js → commandRegistry-W63CYRZJ.js} +64 -64
  82. package/{contentThunks-N52O67MI.js → contentThunks-U7PL5MQD.js} +12 -12
  83. package/{cooldownCommands-YXLWOXWR.js → cooldownCommands-TIGUHXTD.js} +3 -3
  84. package/{createAgentAutomationAction-ZC57YRSV.js → createAgentAutomationAction-OLBQDD6R.js} +12 -12
  85. package/{createDialogAction-VQW5WDYX.js → createDialogAction-SVH6B3SB.js} +14 -14
  86. package/{createPageAction-M5VDA7SC.js → createPageAction-F4DIWZ2Z.js} +14 -14
  87. package/{dbSlice-HP7G4LX3.js → dbSlice-BVH2YZPQ.js} +4 -4
  88. package/{deleteFile-7VQGLK2V.js → deleteFile-5YOEKV4U.js} +2 -2
  89. package/{dialogCommands-JHMR2N2Y.js → dialogCommands-KHIEPY3M.js} +18 -18
  90. package/{dialogSlice-GRSVGDTF.js → dialogSlice-ZCTDV2PZ.js} +11 -11
  91. package/{docCreateCommands-F2K3UPSQ.js → docCreateCommands-DPMZI7G5.js} +14 -13
  92. package/{docDeleteCommands-XGXB5RFT.js → docDeleteCommands-IRQQLUBT.js} +16 -16
  93. package/{docReadCommands-7HWZZV6J.js → docReadCommands-LK37XH6L.js} +14 -13
  94. package/{docStore-KNZK6Y2G.js → docStore-V2KECILA.js} +5 -5
  95. package/{docUpdateCommands-OZZ7NQII.js → docUpdateCommands-O6T3HJHH.js} +14 -13
  96. package/{fetchMessages-M3QU7ZCQ.js → fetchMessages-NR4KNQLO.js} +2 -2
  97. package/{handleSendMessageAction-SHIH74GJ.js → handleSendMessageAction-2PE25WM3.js} +25 -25
  98. package/{hostCredentialCreate-X64WK4JD.js → hostCredentialCreate-S233UMAP.js} +42 -42
  99. package/index.js +7 -7
  100. package/{localDialogRead-XRLAH4CZ.js → localDialogRead-7NNDVVF7.js} +1 -1
  101. package/{localRuntimeAdapter-A7K3ABA6.js → localRuntimeAdapter-KY6WXNBR.js} +41 -41
  102. package/{machineCommands-DE3MR7CJ.js → machineCommands-Q6HA3IXF.js} +42 -42
  103. package/{machineWsRunDispatch-R26P5V36.js → machineWsRunDispatch-WWJQ6WR3.js} +42 -42
  104. package/{memberThunks-7WJAY5V6.js → memberThunks-7EDJADWU.js} +5 -5
  105. package/package.json +1 -1
  106. package/{projectArchive-GGL5HLMD.js → projectArchive-DRTDIMEV.js} +14 -14
  107. package/{read-4VZQODSN.js → read-4V2RMG7N.js} +2 -2
  108. package/{readDocTool-AVD32RUJ.js → readDocTool-BH6ATGQO.js} +1 -1
  109. package/{readlineWorkspace-XKYKNL2I.js → readlineWorkspace-2W4WRCOU.js} +322 -159
  110. package/{removeDialogAgentAction-FKL4BYMR.js → removeDialogAgentAction-LYAZGNKW.js} +5 -5
  111. package/{runAgentClientLoop-V7E2WBVM.js → runAgentClientLoop-J2VQBS2Z.js} +33 -33
  112. package/{secretCommands-4QS3HCA2.js → secretCommands-LXDWOLZ6.js} +1 -1
  113. package/{setDialogExtraReferencesAction-TLIOLWWI.js → setDialogExtraReferencesAction-OCRPGPYH.js} +5 -5
  114. package/{setPrimaryDialogAgentAction-2OLWRFYR.js → setPrimaryDialogAgentAction-HFJDQIBU.js} +5 -5
  115. package/{settingThunks-UGBPCNYF.js → settingThunks-RAMHMTGM.js} +7 -7
  116. package/{spaceCommands-4KSLKVNF.js → spaceCommands-KVJZVKVO.js} +14 -14
  117. package/{streamAgentChatTurn-7FR7X2NU.js → streamAgentChatTurn-GHBMJJ6S.js} +37 -37
  118. package/{switchDialogAgentAction-UZSAG2N5.js → switchDialogAgentAction-EBRMW3RA.js} +4 -4
  119. package/{tools-ZLKCC25W.js → tools-EWKCPKMS.js} +28 -28
  120. package/{tuiSummaryLlmCaller-WC54MVGP.js → tuiSummaryLlmCaller-ALQYUUWB.js} +41 -12
  121. package/{updateCommands-4744PL3P.js → updateCommands-ZQYU6SCI.js} +3 -3
  122. package/{updateDialogTitleAction-U53ZT7PJ.js → updateDialogTitleAction-5GGMBTDF.js} +12 -12
  123. package/{windowsSelfUpdate-XSQVF2GK.js → windowsSelfUpdate-257DV2T6.js} +2 -2
  124. package/{workloadLifecycle-4BEQHMSD.js → workloadLifecycle-4C42SVBD.js} +1 -0
@@ -12,7 +12,7 @@ import {
12
12
  resolveRawAgentInput,
13
13
  resolveServerUrl,
14
14
  writeUsage
15
- } from "./chunk-NRFKLKRU.js";
15
+ } from "./chunk-HSVBJRF4.js";
16
16
  import {
17
17
  getReadableCliDb
18
18
  } from "./chunk-J5JTMQIA.js";
@@ -49,16 +49,15 @@ import {
49
49
  resolveBoundMachineId,
50
50
  resolveFileWriteGateEnabled,
51
51
  validateInstaboxWorkspaceSelection
52
- } from "./chunk-D5RCRX4A.js";
52
+ } from "./chunk-UYD5HQ6T.js";
53
53
  import {
54
54
  clearCredentialAvailability,
55
- readEffectiveCredentialEntry,
56
- recordCredentialProbe
57
- } from "./chunk-GSQNH63I.js";
55
+ readEffectiveCredentialEntry
56
+ } from "./chunk-YTF4WH7J.js";
58
57
  import {
59
58
  readDbRecord,
60
59
  resolveAgentRecordFromHybridStore
61
- } from "./chunk-IF45XG7K.js";
60
+ } from "./chunk-MOIJOHA5.js";
62
61
  import {
63
62
  isBuiltinNoloAgentRef,
64
63
  resolveLocalUserId
@@ -71,7 +70,7 @@ import {
71
70
  } from "./chunk-VL5KOY2C.js";
72
71
  import {
73
72
  resolveCliLocalRuntimeKeyCapability
74
- } from "./chunk-CQ46IRNN.js";
73
+ } from "./chunk-XHQC4PXX.js";
75
74
  import {
76
75
  isTransientFetchError
77
76
  } from "./chunk-KFHREHUQ.js";
@@ -81,7 +80,7 @@ import {
81
80
  import {
82
81
  parseUiCard,
83
82
  uiCardFallback
84
- } from "./chunk-GNDJKC4B.js";
83
+ } from "./chunk-HUBHAQK2.js";
85
84
  import {
86
85
  isGatewayHttpStatus
87
86
  } from "./chunk-NF64D32W.js";
@@ -90,7 +89,7 @@ import {
90
89
  chooseMemoryOwners,
91
90
  loadMemoryCandidatesFromDb,
92
91
  resolveAgentMemoryPolicy
93
- } from "./chunk-OOF4UPC5.js";
92
+ } from "./chunk-LLRPJECG.js";
94
93
  import {
95
94
  API_REPORTED_COST_MULTIPLIER,
96
95
  estimateMessagesTokens,
@@ -98,7 +97,7 @@ import {
98
97
  resolveAgentContextWindow,
99
98
  resolveOccupancy,
100
99
  resolveOccupancyWindow
101
- } from "./chunk-VZKUKCA6.js";
100
+ } from "./chunk-ZXOUUDCG.js";
102
101
  import {
103
102
  isCliAuthorityBrokerProtocolError,
104
103
  isCliAuthorityBrokerTimeoutError,
@@ -118,7 +117,7 @@ import {
118
117
  LOCAL_AGENT_CONFIG_MISSING_CODE,
119
118
  LOCAL_TURN_ABORTED_CODE,
120
119
  readActionGate
121
- } from "./chunk-FHU44LN3.js";
120
+ } from "./chunk-RSHTSUEG.js";
122
121
  import {
123
122
  resolveAgentRuntimeConfigFromRecord
124
123
  } from "./chunk-W4S457LU.js";
@@ -128,16 +127,17 @@ import {
128
127
  processThinkChunk
129
128
  } from "./chunk-56GBUMO5.js";
130
129
  import {
131
- PROBE_INTERVAL_MS,
130
+ resolveSubtaskBudgetLimits
131
+ } from "./chunk-RZOV7OMV.js";
132
+ import {
132
133
  QUOTA_ERROR_PATTERNS,
133
134
  classifyFailureSubclass,
134
135
  isCapacitySaturatedRateLimit,
135
136
  isQuotaExhaustedError,
136
137
  isQuotaExhaustedText,
137
- mergeAvailabilityDeadline,
138
- resolveCooldownGate,
138
+ resolveAvailabilityAction,
139
139
  resolveCredentialKeyWithFallback
140
- } from "./chunk-YUXQAVRD.js";
140
+ } from "./chunk-3UKL3HPD.js";
141
141
  import {
142
142
  ATTACHMENT_PART_TYPE,
143
143
  ATTACHMENT_PART_VERSION,
@@ -147,7 +147,10 @@ import {
147
147
  import {
148
148
  normalizeUsage,
149
149
  readCacheReadInputTokensOrNull
150
- } from "./chunk-JTDORD5P.js";
150
+ } from "./chunk-V5Y3R6BT.js";
151
+ import {
152
+ findCodexOAuthPinnedContextWindow
153
+ } from "./chunk-7BT37FK3.js";
151
154
  import {
152
155
  isOAuthApiKeyRef
153
156
  } from "./chunk-UKZX3NHN.js";
@@ -195,17 +198,18 @@ import {
195
198
  serverOriginForDialog,
196
199
  settleRunTerminalAuthoritatively,
197
200
  spawnLocalBackgroundRun
198
- } from "./chunk-HIRC32DV.js";
201
+ } from "./chunk-NSAPDIN2.js";
199
202
  import {
200
203
  formatAgentListCard,
201
204
  formatFinishedRunCard,
205
+ formatIdentityRow,
202
206
  formatListRunsCard,
203
207
  formatNotFoundRunCard,
204
- formatStartRunCard,
205
208
  formatStatusRunCard,
206
209
  formatStopRunCard,
210
+ getAgentRunStatusIcon,
207
211
  isAgentRunTerminalStatus
208
- } from "./chunk-PJNFNEJE.js";
212
+ } from "./chunk-ALQ3657A.js";
209
213
  import {
210
214
  resolveClientVersion
211
215
  } from "./chunk-TCZHTTUU.js";
@@ -240,7 +244,7 @@ import {
240
244
  t,
241
245
  toolLabel,
242
246
  toolLabelVariants
243
- } from "./chunk-3RQVYR4B.js";
247
+ } from "./chunk-VNYYOX3V.js";
244
248
  import {
245
249
  createMemoryKey
246
250
  } from "./chunk-JY5NGFFH.js";
@@ -644,6 +648,8 @@ function parseUsageRecord(usage) {
644
648
  function resolveContextWindow(model) {
645
649
  const raw = model?.trim();
646
650
  if (!raw) return void 0;
651
+ const oauthPinned = findCodexOAuthPinnedContextWindow(raw);
652
+ if (oauthPinned !== void 0) return oauthPinned;
647
653
  for (const provider of PROVIDER_LOOKUP_ORDER) {
648
654
  const config = findModelConfig(provider, raw);
649
655
  if (config?.contextWindow) return config.contextWindow;
@@ -9675,7 +9681,7 @@ function clip(value, max = 72) {
9675
9681
  return clipCompactText(value, max, "\u2026");
9676
9682
  }
9677
9683
  function formatConservativeActiveToolLabel(event) {
9678
- return toolLabel(event.toolName || "tool");
9684
+ return event.toolName === "startAgentRun" ? t("agentStartingLabel") : toolLabel(event.toolName || "tool");
9679
9685
  }
9680
9686
  function isRunToolName(name) {
9681
9687
  return name === "execShell" || name === "runCommand" || name === "launchProcess";
@@ -9925,8 +9931,9 @@ function recoverOrchestrationCard(event, toolName, opts) {
9925
9931
  if (toolName === "listAgents") {
9926
9932
  try {
9927
9933
  const parsed = JSON.parse(trimmed);
9928
- const agents = Array.isArray(parsed.agents) ? parsed.agents : [];
9929
- const card = formatAgentListCard(agents);
9934
+ if (parsed.success === false || !Array.isArray(parsed.agents)) return null;
9935
+ const agents = parsed.agents;
9936
+ const card = formatAgentListCard(agents, 8, /* @__PURE__ */ new Date(), !safe);
9930
9937
  const lines = card.split("\n");
9931
9938
  lines[0] = t("agentsListLabel", String(agents.length));
9932
9939
  return lines.join("\n");
@@ -9954,12 +9961,18 @@ function recoverOrchestrationCard(event, toolName, opts) {
9954
9961
  const name = safe ? cleanUserText(snapshot.agentName ?? "agent") : snapshot.agentName ?? "agent";
9955
9962
  const task = snapshot.taskPreview ? safe ? cleanUserText(snapshot.taskPreview) : snapshot.taskPreview : snapshot.taskPreview;
9956
9963
  const title = snapshot.title ? safe ? cleanUserText(snapshot.title) : snapshot.title : snapshot.title;
9957
- return formatStartRunCard(name, snapshot.status, {
9958
- task,
9959
- runId: snapshot.runId,
9960
- ...title ? { title } : {},
9961
- labels
9964
+ const identity = formatIdentityRow(name, snapshot.runId, {
9965
+ title,
9966
+ unnamedAgent: labels.unnamedAgent
9962
9967
  });
9968
+ const status = `${getAgentRunStatusIcon(snapshot.status)} ${labels.statusWord(snapshot.status)}`;
9969
+ const oneLine = identity ? `${identity} \xB7 ${status}` : status;
9970
+ const columns = process.stdout.columns || 80;
9971
+ const secondary = formatIdentityRow(name, snapshot.runId, { title, titleOnOwnLine: true, unnamedAgent: labels.unnamedAgent });
9972
+ const rows = identity && title && displayWidth(` ${oneLine}`) > columns ? [title, ` ${secondary ? `${secondary} \xB7 ` : ""}${status}`] : [oneLine];
9973
+ if (task && !title) rows.push(` ${labels.rows.task}${task}`);
9974
+ if (snapshot.errorMessage) rows.push(` ${labels.rows.error}${redactSecrets(cleanUserText(snapshot.errorMessage.split("\n")[0]))}`);
9975
+ return rows.join("\n");
9963
9976
  }
9964
9977
  if (kind === "gone") return formatNotFoundRunCard(labels);
9965
9978
  if (kind === "stop") return formatStopRunCard(snapshot.status, labels);
@@ -9969,10 +9982,20 @@ function formatOrchestrationCardBlock(event, toolName, colorEnabled, opts) {
9969
9982
  const safe = opts?.safe === true;
9970
9983
  const rawLabel = toolLabel(toolName);
9971
9984
  const bakedCard = typeof event.metadata?.displayData === "string" && event.metadata.displayData.trim() ? event.metadata.displayData : "";
9972
- const rawDataStr = recoverOrchestrationCard(event, toolName, { safe }) || bakedCard || (typeof event.content === "string" ? event.content : "");
9973
- const failed = event.type === "tool-error" || isFailedToolResult(event) || Boolean(event.metadata?.failed) || /^Error:/i.test(rawDataStr.trim());
9985
+ let listPayload;
9986
+ if (toolName === "listAgents" && typeof event.content === "string") {
9987
+ try {
9988
+ const value = JSON.parse(event.content);
9989
+ if (value && typeof value === "object" && !Array.isArray(value)) listPayload = value;
9990
+ } catch {
9991
+ }
9992
+ }
9993
+ const listFailed = listPayload?.success === false;
9994
+ const rawDataStr = listFailed ? typeof listPayload?.error === "string" ? listPayload.error : event.content || bakedCard : recoverOrchestrationCard(event, toolName, { safe }) || bakedCard || (typeof event.content === "string" ? event.content : "");
9995
+ const failed = event.type === "tool-error" || isFailedToolResult(event) || Boolean(event.metadata?.failed) || listFailed || /^Error:/i.test(rawDataStr.trim());
9974
9996
  if (failed) {
9975
- const firstLine = stripAnsi2(rawDataStr.trim().split("\n")[0] || event.summary || event.message || t("toolFailed"));
9997
+ const failureSnapshot = toolName === "startAgentRun" ? parseAgentRunEvent(event)?.snapshot : void 0;
9998
+ const firstLine = stripAnsi2(failureSnapshot?.errorMessage || rawDataStr.trim().split("\n")[0] || event.summary || event.message || t("toolFailed"));
9976
9999
  const message = clip(redactSecrets(firstLine), 96);
9977
10000
  if (!colorEnabled) {
9978
10001
  return `\u2717 ${rawLabel} ${message}
@@ -9984,11 +10007,37 @@ function formatOrchestrationCardBlock(event, toolName, colorEnabled, opts) {
9984
10007
  return `${cross} ${labelPart2} ${msgPart}
9985
10008
  `;
9986
10009
  }
10010
+ const parsedStart = toolName === "startAgentRun" ? parseAgentRunEvent(event) : null;
10011
+ const startFailed = parsedStart && ["failed", "timeout", "orphaned", "cancelled", "killed"].includes(parsedStart.snapshot.status);
10012
+ let heading = parsedStart ? t(startFailed ? "agentStartFailedLabel" : "agentStartedLabel") : rawLabel;
9987
10013
  const displayData = rawDataStr.trim();
9988
10014
  const lines = displayData ? displayData.split("\n") : [];
9989
- const projected = safe ? sanitizeRunCardForNormal(lines) : lines;
10015
+ if (toolName === "startAgentRun" && ["Run started", "\u8FD0\u884C\u5DF2\u542F\u52A8"].includes(lines[0]?.trim())) lines.shift();
10016
+ let projected = safe ? sanitizeRunCardForNormal(lines) : lines;
10017
+ if (safe && toolName === "listAgents") {
10018
+ if (Array.isArray(listPayload?.agents)) {
10019
+ const count = listPayload.agents.length;
10020
+ const total = typeof listPayload.total === "number" && Number.isSafeInteger(listPayload.total) && listPayload.total >= count ? listPayload.total : count;
10021
+ heading = t("agentsCompactCount", String(total));
10022
+ if (total !== count) heading += ` \xB7 ${t("agentsPageCount", String(count))}`;
10023
+ if (listPayload.truncated === true) heading += ` \xB7 ${t("agentsTruncated")}`;
10024
+ if (/^(?:Agents|智能体)\s*\(\d+\)$/.test(projected[0]?.trim() ?? "")) {
10025
+ projected = projected.slice(1);
10026
+ }
10027
+ }
10028
+ projected = projected.map((line) => line.replace(/\s{2,}(?:agent-pub-[a-z0-9]+|agent-system-[a-z0-9]+|agent-[0-9a-f]{6,}-[a-z0-9-]+|\(agentKey unavailable\))\s*$/i, ""));
10029
+ }
10030
+ if (safe && toolName === "controlAgentRun" && projected.length > 0) {
10031
+ const first = projected[0].trim();
10032
+ const recognized = ["Run status", "\u8FD0\u884C\u72B6\u6001", "Run finished", "\u8FD0\u884C\u5DF2\u7ED3\u675F", "Run stopped", "\u8FD0\u884C\u5DF2\u505C\u6B62"];
10033
+ const merged = `${heading} \xB7 ${first}`;
10034
+ if (recognized.includes(first) && displayWidth(`\u25CF ${merged}`) <= (process.stdout.columns || 80)) {
10035
+ heading = merged;
10036
+ projected = projected.slice(1);
10037
+ }
10038
+ }
9990
10039
  if (!colorEnabled) {
9991
- let out2 = `\u25CF ${rawLabel}
10040
+ let out2 = `\u25CF ${heading}
9992
10041
  `;
9993
10042
  for (const line of projected) {
9994
10043
  out2 += ` ${line}
@@ -9997,7 +10046,7 @@ function formatOrchestrationCardBlock(event, toolName, colorEnabled, opts) {
9997
10046
  return out2;
9998
10047
  }
9999
10048
  const bullet = themeText("\u25CF", "success", true);
10000
- const labelPart = themeText(rawLabel, "muted", true);
10049
+ const labelPart = themeText(heading, "muted", true);
10001
10050
  let out = `${bullet} ${labelPart}
10002
10051
  `;
10003
10052
  for (const line of projected) {
@@ -10259,7 +10308,7 @@ function formatNormalToolLine(event, pending, colorEnabled) {
10259
10308
  return formatOrchestrationCardBlock(event, toolName, colorEnabled, { safe: true });
10260
10309
  }
10261
10310
  if (event.type === "tool-result" && toolName === "loadSkill") {
10262
- return formatLoadSkillBlock(event, colorEnabled, { safe: true }) ?? "";
10311
+ return formatLoadSkillBlock({ ...event, argumentsPreview: event.argumentsPreview || pending?.argumentsPreview }, colorEnabled, { safe: true }) ?? "";
10263
10312
  }
10264
10313
  if (event.type === "tool-result" && toolName === "show_interaction") {
10265
10314
  return formatShowInteractionBlock(event, colorEnabled);
@@ -10307,21 +10356,53 @@ function toolFailureReason(event) {
10307
10356
  return reasonLine ? clip(redactSecrets(stripAnsi2(reasonLine)), 96) : "";
10308
10357
  }
10309
10358
  function resolveLoadSkillName(event) {
10310
- const metaName = typeof event.metadata?.name === "string" ? event.metadata.name : void 0;
10311
- if (metaName) return metaName;
10312
- const argName = event.argumentsPreview?.trim();
10313
- if (argName && !argName.startsWith("{")) return argName;
10314
10359
  const content = typeof event.content === "string" ? event.content : "";
10315
- const match = content.match(/Skill "([^"]+)" loaded inline/);
10316
- if (match?.[1]) return match[1];
10317
- return argName || "skill";
10360
+ let result;
10361
+ try {
10362
+ const value = JSON.parse(content);
10363
+ if (value && typeof value === "object" && !Array.isArray(value)) result = value;
10364
+ } catch {
10365
+ }
10366
+ const preview = event.argumentsPreview?.trim() ?? "";
10367
+ let args = {};
10368
+ if (preview.startsWith("{")) {
10369
+ try {
10370
+ const value = JSON.parse(preview);
10371
+ if (value && typeof value === "object" && !Array.isArray(value)) args = value;
10372
+ } catch {
10373
+ }
10374
+ } else if (/^(?:name|source|slug|dbKey|projectBinding|relativePath)=/.test(preview)) {
10375
+ for (const match of preview.matchAll(/(?:^|\s)(name|source|slug|dbKey|projectBinding|relativePath)=([^\s]+)/g)) args[match[1]] = match[2];
10376
+ } else if (preview) {
10377
+ args.name = preview;
10378
+ }
10379
+ const textName = content.match(/^Skill "([^"\n]+)" loaded inline\./)?.[1];
10380
+ const name = result?.name ?? textName ?? event.metadata?.name ?? args.name;
10381
+ const source = result?.source ?? event.metadata?.source ?? args.source;
10382
+ const slug = result?.slug ?? event.metadata?.slug ?? args.slug;
10383
+ const dbKey = result?.dbKey ?? event.metadata?.dbKey ?? args.dbKey;
10384
+ const relativePath2 = result?.relativePath ?? event.metadata?.relativePath ?? args.relativePath;
10385
+ const shortReference = (value) => {
10386
+ if (typeof value !== "string" || !value.trim()) return void 0;
10387
+ const normalized = value.trim().replace(/\\/g, "/");
10388
+ const parts = normalized.split("/").filter(Boolean);
10389
+ return parts.at(-1) === "SKILL.md" && parts.length > 1 ? parts.at(-2) : parts.at(-1);
10390
+ };
10391
+ const candidate = shortReference(name) ?? shortReference(slug) ?? shortReference(dbKey) ?? shortReference(relativePath2) ?? shortReference(source) ?? t("unnamedSkillReference");
10392
+ return clip(redactSecrets(cleanUserText(candidate)), 80);
10318
10393
  }
10319
10394
  function formatLoadSkillBlock(event, colorEnabled, opts) {
10320
10395
  if (event.type !== "tool-result" || event.toolName !== "loadSkill") return null;
10321
10396
  const skillName = resolveLoadSkillName(event);
10322
10397
  const content = typeof event.content === "string" ? event.content : "";
10323
- const failed = /^Skill\s+"[^"]*"\s+not found/.test(content) || isFailedToolResult(event);
10324
- const labelText = t("usedSkillLabel");
10398
+ let result;
10399
+ try {
10400
+ const value = JSON.parse(content);
10401
+ if (value && typeof value === "object" && !Array.isArray(value)) result = value;
10402
+ } catch {
10403
+ }
10404
+ const failed = /^Skill\s+"[^"]*"\s+not found/i.test(content) || /^Skill reference rejected:/i.test(content) || event.metadata?.resolved === false || Boolean(event.metadata?.failed) || result?.success === false || isFailedToolResult(event);
10405
+ const labelText = t(failed ? "loadSkillLabel" : "usedSkillLabel");
10325
10406
  if (failed) {
10326
10407
  const message = opts?.safe === true ? t("toolFailed") : clip(content.split("\n")[0] || t("toolFailed"), 96);
10327
10408
  return formatToolTraceLine(`\u25B8 ${labelText} (${skillName}) \u2717 ${message}`, colorEnabled, "error");
@@ -11414,7 +11495,7 @@ function isBalanceExhaustedError(error) {
11414
11495
 
11415
11496
  // packages/cli/client/agentRun.ts
11416
11497
  async function loadRunLocalAgentTurn() {
11417
- const { runLocalAgentTurn } = await import("./agentRuntimeLocal-HL526DNQ.js");
11498
+ const { runLocalAgentTurn } = await import("./agentRuntimeLocal-SOO2OPJG.js");
11418
11499
  return runLocalAgentTurn;
11419
11500
  }
11420
11501
  var stripDebugNoise = (s) => s.replace(/\s*raw="[\s\S]*"/g, "").replace(/\s*raw=\S+/g, "").replace(/\s*headers=\[[^\]]*\]/g, "").replace(/\s*headers=\S+/g, "").trim();
@@ -11982,8 +12063,7 @@ function buildRateLimitFailure(ctx) {
11982
12063
  t(
11983
12064
  "localRunRateLimitCooldown",
11984
12065
  formatCooldownUntilLocal(cooldownUntil),
11985
- resetValue ? t("localRunRateLimitResetNote", resetValue) : "",
11986
- String(Math.round(PROBE_INTERVAL_MS / 6e4))
12066
+ resetValue ? t("localRunRateLimitResetNote", resetValue) : ""
11987
12067
  )
11988
12068
  );
11989
12069
  }
@@ -12344,7 +12424,7 @@ async function runHttpAgentTurn(options, authToken) {
12344
12424
  const contentType = res.headers.get("content-type") || "";
12345
12425
  if (contentType.includes("text/event-stream") && res.body) {
12346
12426
  const result = await readStreamingAgentRun(options, res, spinner);
12347
- return result;
12427
+ return { ...result, httpOutcome: { status: res.status } };
12348
12428
  }
12349
12429
  spinner.stop();
12350
12430
  let data = {};
@@ -12431,7 +12511,7 @@ ${options.agentName} > (no text response)
12431
12511
  model: typeof data?.model === "string" ? data.model : void 0,
12432
12512
  dialogServer: serverOriginForDialog(options.serverUrl)
12433
12513
  });
12434
- return serverResult;
12514
+ return { ...serverResult, httpOutcome: { status: res.status, body: data } };
12435
12515
  }
12436
12516
  async function runInjectedLocalAgentTurn(options) {
12437
12517
  return runLocalAgentTurnForCli(options, { reportFailure: true });
@@ -12531,7 +12611,8 @@ async function executeLocalAgentTurnForCliWithAdapter(options, settings, resolve
12531
12611
  const runtimeContextWithOwnership = {
12532
12612
  ...runtimeContext ?? {},
12533
12613
  dialogId: currentDialogId,
12534
- turnId
12614
+ turnId,
12615
+ getProcessCausalDepth: options.getProcessCausalDepth
12535
12616
  };
12536
12617
  const adapter = baseAdapter;
12537
12618
  const expandedMessage = options.pastedTextStore?.items.size ? expandCollapsedPastes(options.message, options.pastedTextStore) : options.message;
@@ -12588,6 +12669,7 @@ async function executeLocalAgentTurnForCliWithAdapter(options, settings, resolve
12588
12669
  parentDialogId: options.parentDialogId,
12589
12670
  runtimeContext: runtimeContextWithOwnership,
12590
12671
  runKind: options.env.NOLO_AGENT_RUN_CHILD === "1" ? "subtask" : "interactive",
12672
+ ...options.env.NOLO_AGENT_RUN_CHILD === "1" ? { subtaskBudgetLimits: resolveSubtaskBudgetLimits({ env: options.env }) } : {},
12591
12673
  // 展示能力由宿主声明(TUI=narrow),非交互 CLI/后台留空 → unknown;
12592
12674
  // 排版段只在能力已知时由 localLoop 注入,server 线不读该字段。
12593
12675
  ...options.responseViewport ? { responseViewport: options.responseViewport } : {},
@@ -12718,7 +12800,7 @@ async function executeLocalAgentTurnForCliWithAdapter(options, settings, resolve
12718
12800
  };
12719
12801
  }
12720
12802
  }
12721
- async function checkLocalAvailabilityBeforeHttpDispatch(options) {
12803
+ async function resolveLocalCredentialKeysForDispatch(options) {
12722
12804
  if (options.runtimeKey && !isDockerRuntimeKey(options.runtimeKey)) return null;
12723
12805
  const adapter = resolveLocalRuntimeAdapter(options);
12724
12806
  if (!adapter || typeof adapter.loadAgentConfig !== "function") return null;
@@ -12737,50 +12819,19 @@ async function checkLocalAvailabilityBeforeHttpDispatch(options) {
12737
12819
  config,
12738
12820
  options
12739
12821
  )) {
12740
- credentialKey = void 0;
12741
- }
12742
- const agentLevelAt = baseRecord.nextAvailableAt;
12743
- const agentLevelNextAvailableAt = typeof agentLevelAt === "number" && Number.isFinite(agentLevelAt) ? agentLevelAt : void 0;
12744
- if (!credentialKey && agentLevelNextAvailableAt === void 0) {
12745
- return { credentialKey };
12822
+ return null;
12746
12823
  }
12747
12824
  const env = options.env;
12748
12825
  const now = Date.now();
12749
- let entry;
12750
- let matchedKey;
12751
- if (credentialKey) {
12752
- const effective = await readEffectiveCredentialEntry(credentialKey, env, now).catch(() => void 0);
12753
- if (effective) {
12754
- entry = effective;
12755
- matchedKey = effective.matchedKey;
12756
- }
12757
- }
12758
- const entryAt = entry?.nextAvailableAt;
12759
- const effectiveNextAvailableAt = typeof entryAt === "number" ? mergeAvailabilityDeadline(agentLevelNextAvailableAt, entryAt) : agentLevelNextAvailableAt;
12760
- const activeKey = matchedKey || credentialKey;
12761
- if (typeof effectiveNextAvailableAt !== "number") {
12762
- return { credentialKey: credentialKey || activeKey, matchedKey };
12763
- }
12764
- const gateDecision = resolveCooldownGate(
12765
- { nextAvailableAt: effectiveNextAvailableAt, lastProbeAt: entry?.lastProbeAt },
12766
- now
12767
- );
12768
- if (gateDecision === "probe" && activeKey) {
12769
- await recordCredentialProbe(activeKey, env, now).catch(() => void 0);
12770
- return { credentialKey: credentialKey || activeKey, matchedKey };
12771
- }
12772
- if (gateDecision !== "blocked") return { credentialKey: credentialKey || activeKey, matchedKey };
12773
- options.output.write(
12774
- `${t(
12775
- "agentCooldownBlocked",
12776
- options.agentName || options.agentKey,
12777
- formatCooldownUntilLocal(
12778
- new Date(Number(effectiveNextAvailableAt)).toISOString()
12779
- )
12780
- )}
12781
- `
12782
- );
12783
- return { exitCode: 1, failureSubclass: "rate_limit" };
12826
+ const entry = credentialKey ? await readEffectiveCredentialEntry(credentialKey, env, now).catch(() => void 0) : void 0;
12827
+ const recorder = adapter;
12828
+ return {
12829
+ credentialKey,
12830
+ matchedKey: entry?.matchedKey,
12831
+ // 真实 status/body 由调用方透传(不再固定 200 无 body):HTTP 2xx 的 body 里
12832
+ // 也可能带配额错误码,固定成功的判定会把这类响应当成恢复而清掉冷却。
12833
+ recordSuccess: recorder.recordStartupAvailabilityForAgent ? (status, body) => recorder.recordStartupAvailabilityForAgent(options.agentKey, status, body) : void 0
12834
+ };
12784
12835
  }
12785
12836
  function foldLocalResultForTui(localResult) {
12786
12837
  const folded = {
@@ -12907,20 +12958,22 @@ async function runAgentTurn(options) {
12907
12958
  );
12908
12959
  return { exitCode: 1 };
12909
12960
  }
12910
- const localAvailability = await checkLocalAvailabilityBeforeHttpDispatch(options);
12911
- if (localAvailability?.exitCode) {
12912
- return {
12913
- exitCode: localAvailability.exitCode,
12914
- failureSubclass: localAvailability.failureSubclass ?? "rate_limit"
12915
- };
12916
- }
12917
- const httpResult = await runHttpAgentTurn(options, authToken);
12918
- if (httpResult.exitCode === 0 && !httpResult.streamInterrupted && (localAvailability?.credentialKey || localAvailability?.matchedKey)) {
12919
- const keyToClear = localAvailability.credentialKey || localAvailability.matchedKey;
12920
- await clearCredentialAvailability(
12921
- keyToClear,
12922
- options.env
12923
- ).catch(() => void 0);
12961
+ const localAvailability = await resolveLocalCredentialKeysForDispatch(options);
12962
+ const { httpOutcome, ...httpResult } = await runHttpAgentTurn(options, authToken);
12963
+ if (httpResult.exitCode === 0 && !httpResult.streamInterrupted && localAvailability) {
12964
+ const action = httpOutcome ? resolveAvailabilityAction(httpOutcome.status, httpOutcome.body, Date.now()) : void 0;
12965
+ if (action?.kind === "clear") {
12966
+ const keyToClear = localAvailability.credentialKey || localAvailability.matchedKey;
12967
+ if (keyToClear) {
12968
+ await clearCredentialAvailability(
12969
+ keyToClear,
12970
+ options.env
12971
+ ).catch(() => void 0);
12972
+ }
12973
+ }
12974
+ if (httpOutcome) {
12975
+ await localAvailability.recordSuccess?.(httpOutcome.status, httpOutcome.body).catch(() => void 0);
12976
+ }
12924
12977
  }
12925
12978
  return httpResult;
12926
12979
  }
@@ -2,7 +2,7 @@ import {
2
2
  deleteDialog,
3
3
  runtime_default,
4
4
  toast
5
- } from "./chunk-VZKUKCA6.js";
5
+ } from "./chunk-ZXOUUDCG.js";
6
6
  import {
7
7
  getCurrentSpaceId,
8
8
  getCurrentSpaceIdRaw,
@@ -13,7 +13,7 @@ import {
13
13
  addContentAction,
14
14
  checkSpaceMembership,
15
15
  localSpaceAuthorityPatchStamp
16
- } from "./chunk-VPAZOH2D.js";
16
+ } from "./chunk-GPVRUGGY.js";
17
17
  import {
18
18
  createSpaceKey,
19
19
  normalizeSpaceId
@@ -32,7 +32,7 @@ import {
32
32
  uploadFileAction,
33
33
  upsertSSREntity,
34
34
  write
35
- } from "./chunk-BFM34N54.js";
35
+ } from "./chunk-FW6YHHLI.js";
36
36
  import {
37
37
  resolveFileCategory
38
38
  } from "./chunk-3PVYUPXK.js";
@@ -58,7 +58,7 @@ import {
58
58
  } from "./chunk-PXYBUFDB.js";
59
59
  import {
60
60
  buildTombstoneRecord
61
- } from "./chunk-D2MDMY2M.js";
61
+ } from "./chunk-SVYO6AO7.js";
62
62
  import {
63
63
  isSystemAdmin
64
64
  } from "./chunk-Y6ORVLSS.js";
@@ -1506,11 +1506,11 @@ var ENTITY_DELETE_STRATEGIES = {
1506
1506
  await dispatch(deleteTable({ dbKey: key })).unwrap();
1507
1507
  },
1508
1508
  file: async (key, { thunkAPI }) => {
1509
- const { deleteFileAction } = await import("./deleteFile-7VQGLK2V.js");
1509
+ const { deleteFileAction } = await import("./deleteFile-5YOEKV4U.js");
1510
1510
  await deleteFileAction(key, thunkAPI);
1511
1511
  },
1512
1512
  image: async (key, { thunkAPI }) => {
1513
- const { deleteFileAction } = await import("./deleteFile-7VQGLK2V.js");
1513
+ const { deleteFileAction } = await import("./deleteFile-5YOEKV4U.js");
1514
1514
  await deleteFileAction(key, thunkAPI);
1515
1515
  },
1516
1516
  agent: async (key, { dispatch, userId, sourceServerOrigin }) => {
@@ -2,17 +2,23 @@
2
2
  import { execFile } from "node:child_process";
3
3
  var DEFAULT_SSH_HOST = "nolotus@136.67.147.177";
4
4
  var DEFAULT_CI_PORT = "3900";
5
- function resolveSshTarget() {
6
- const override = process.env.NOLO_CI_SSH_HOST?.trim();
5
+ function resolveCiSshTarget(env = process.env) {
6
+ const override = env.NOLO_CI_SSH_HOST?.trim();
7
7
  if (override) return override;
8
- const raw = process.env.NOLO_CI_RAW_HOST?.trim() ?? process.env.NOLO_ALPHA_RAW_HOST?.trim();
9
- if (raw) {
10
- const user = process.env.NOLO_CI_SSH_USER?.trim() ?? process.env.NOLO_ALPHA_SSH_USER?.trim() ?? "nolotus";
11
- return `${user}@${raw}`;
12
- }
13
- const legacyAlias = process.env.NOLO_ALPHA_SSH_CONFIG_HOST?.trim();
14
- if (legacyAlias) return legacyAlias;
15
- return DEFAULT_SSH_HOST;
8
+ const raw = env.NOLO_CI_RAW_HOST?.trim() ?? env.NOLO_ALPHA_RAW_HOST?.trim();
9
+ if (raw) return `${env.NOLO_CI_SSH_USER?.trim() ?? env.NOLO_ALPHA_SSH_USER?.trim() ?? "nolotus"}@${raw}`;
10
+ return env.NOLO_ALPHA_SSH_CONFIG_HOST?.trim() || DEFAULT_SSH_HOST;
11
+ }
12
+ function resolveCiPort(env = process.env) {
13
+ const raw = env.NOLO_CI_PORT?.trim() ?? "";
14
+ return /^\d{1,5}$/.test(raw) && Number(raw) > 0 && Number(raw) <= 65535 ? raw : DEFAULT_CI_PORT;
15
+ }
16
+ function buildCiStatusCommand(limit, env = process.env) {
17
+ const safeLimit = Math.max(1, Math.min(20, Math.trunc(limit) || 5));
18
+ return `curl -s -m 3 "http://127.0.0.1:${resolveCiPort(env)}/status?limit=${safeLimit}"`;
19
+ }
20
+ function resolveSshTarget() {
21
+ return resolveCiSshTarget();
16
22
  }
17
23
  function asRecord(value) {
18
24
  return typeof value === "object" && value !== null ? value : void 0;
@@ -64,19 +70,13 @@ function parseCiStatusPayload(raw) {
64
70
  const single = toCiJob(parsed);
65
71
  return single ? [single] : void 0;
66
72
  }
67
- function resolveCiPort() {
68
- const rawPort = process.env.NOLO_CI_PORT?.trim() ?? "";
69
- return /^\d{1,5}$/.test(rawPort) && Number(rawPort) > 0 && Number(rawPort) <= 65535 ? rawPort : DEFAULT_CI_PORT;
70
- }
71
73
  function buildRemoteCommand(limit) {
72
- const port = resolveCiPort();
73
- const safeLimit = Math.max(1, Math.min(20, Math.trunc(limit) || 5));
74
- return `curl -s -m 3 "http://127.0.0.1:${port}/status?limit=${safeLimit}"`;
74
+ return buildCiStatusCommand(limit);
75
75
  }
76
- function fetchCiStatus(limit = 5, timeoutMs = 4e3) {
77
- return fetchCiPayload(buildRemoteCommand(limit), parseCiStatusPayload, timeoutMs);
76
+ function fetchCiStatus(limit = 5, timeoutMs = 4e3, signal) {
77
+ return fetchCiPayload(buildRemoteCommand(limit), parseCiStatusPayload, timeoutMs, resolveSshTarget(), signal);
78
78
  }
79
- function fetchCiPayload(command, parse, timeoutMs) {
79
+ function fetchCiPayload(command, parse, timeoutMs, sshTarget, signal, execFileImpl = execFile) {
80
80
  return new Promise((resolve) => {
81
81
  let settled = false;
82
82
  let guard;
@@ -84,15 +84,22 @@ function fetchCiPayload(command, parse, timeoutMs) {
84
84
  if (settled) return;
85
85
  settled = true;
86
86
  if (guard) clearTimeout(guard);
87
+ signal?.removeEventListener("abort", onAbort);
87
88
  resolve(value);
88
89
  };
90
+ const onAbort = () => finish(void 0);
91
+ if (signal?.aborted) {
92
+ finish(void 0);
93
+ return;
94
+ }
95
+ signal?.addEventListener("abort", onAbort, { once: true });
89
96
  guard = setTimeout(() => finish(void 0), timeoutMs + 500);
90
97
  guard.unref?.();
91
98
  try {
92
- execFile(
99
+ execFileImpl(
93
100
  "ssh",
94
- ["-o", "BatchMode=yes", "-o", `ConnectTimeout=3`, resolveSshTarget(), command],
95
- { timeout: timeoutMs, encoding: "utf8", maxBuffer: 1024 * 1024 },
101
+ ["-o", "BatchMode=yes", "-o", `ConnectTimeout=3`, sshTarget, command],
102
+ { timeout: timeoutMs, signal, encoding: "utf8", maxBuffer: 1024 * 1024 },
96
103
  (error, stdout) => {
97
104
  if (error) {
98
105
  finish(void 0);
@@ -128,14 +135,17 @@ function buildCancelCommand(jobId) {
128
135
  const tokenRef = `$(grep -m1 '^NOLO_CI_ADMIN_TOKEN=' "$HOME/.config/nolo-ci.env" 2>/dev/null | cut -d= -f2-)`;
129
136
  return `curl -s -m 110 -H "Authorization: Bearer ${tokenRef}" -H 'Content-Type: application/json' -X POST --data '${body}' "${endpoint}"`;
130
137
  }
131
- function fetchCiCancel(jobId, timeoutMs = 12e4) {
138
+ function fetchCiCancel(jobId, timeoutMs = 12e4, execFileImpl = execFile) {
132
139
  return fetchCiPayload(
133
140
  buildCancelCommand(jobId),
134
141
  (stdout) => {
135
142
  const response = JSON.parse(stdout);
136
143
  return response?.ok === true && response?.cancelled === true && response?.jobId === jobId ? true : false;
137
144
  },
138
- timeoutMs
145
+ timeoutMs,
146
+ resolveSshTarget(),
147
+ void 0,
148
+ execFileImpl
139
149
  );
140
150
  }
141
151