nolo-cli 0.16.0-alpha.9 → 0.16.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 (74) hide show
  1. package/{_executeModel-ABTND4KZ.js → _executeModel-AVCA2NAV.js} +18 -19
  2. package/{agentDeleteCommand-ARMAV46L.js → agentDeleteCommand-QW5PUMDQ.js} +12 -13
  3. package/{agentEmailCommands-BKPZP4UP.js → agentEmailCommands-4ORVLGVQ.js} +23 -24
  4. package/{agentListCommands-5J7RRXUO.js → agentListCommands-YWBYRTYC.js} +14 -15
  5. package/{agentMachineCommands-VXWJXXPF.js → agentMachineCommands-JSQW4FOA.js} +12 -13
  6. package/{agentRecordCommands-INDJINPN.js → agentRecordCommands-AASIWOBT.js} +22 -23
  7. package/{agentRunCommand-KBN6HBY4.js → agentRunCommand-TB5BHXUH.js} +22 -23
  8. package/{agentRuntimeLocal-AH2RYWGP.js → agentRuntimeLocal-QNPNJRVH.js} +10 -11
  9. package/{agentSlice-R4PELU57.js → agentSlice-RUNXC62Y.js} +1 -1
  10. package/{authCommand-QU5BXRBH.js → authCommand-YFTR3347.js} +2 -8
  11. package/{chunk-ZVC2PCZN.js → chunk-33BJUVK4.js} +2 -2
  12. package/{chunk-BG7AP3Q7.js → chunk-3663CXZN.js} +11 -38
  13. package/{chunk-IFPY2BIE.js → chunk-3OIRVWXA.js} +10 -1
  14. package/{chunk-LSFAWXKC.js → chunk-3WGLLTK4.js} +3 -100
  15. package/{chunk-5Y5KEB7V.js → chunk-4FX6NVDW.js} +134 -1
  16. package/{chunk-QLWU2KOT.js → chunk-4IJYA27C.js} +1 -1
  17. package/{chunk-OELQ67TN.js → chunk-4L2OJPCU.js} +1 -1
  18. package/{chunk-HSLJ7QER.js → chunk-55NSNCFM.js} +1 -1
  19. package/{chunk-ZVDRAEZL.js → chunk-6EVITP2G.js} +250 -1
  20. package/{chunk-AFNJWHKL.js → chunk-7UKFVQ5W.js} +27 -84
  21. package/{chunk-VK2HVKAO.js → chunk-AUURUT6L.js} +193 -64
  22. package/{chunk-4N7QA72L.js → chunk-AVVZUXXC.js} +13 -34
  23. package/{chunk-2XA3QGOH.js → chunk-BEBNFWDU.js} +3 -3
  24. package/{chunk-4EME3YTO.js → chunk-DGEYDWEZ.js} +3 -3
  25. package/{chunk-XECKIDGJ.js → chunk-DPAB4FQ7.js} +126 -646
  26. package/{chunk-J3VQSU5W.js → chunk-EHLHSX7R.js} +2 -9
  27. package/{chunk-PEDT43JF.js → chunk-FRV6A633.js} +2 -2
  28. package/{chunk-VAT72PDP.js → chunk-FY233ZFU.js} +12 -13
  29. package/{chunk-LZYEWFPK.js → chunk-GSINCD4P.js} +4 -8
  30. package/{chunk-ZPPTWRPT.js → chunk-IGXREZW2.js} +1 -1
  31. package/{chunk-B4KT7RN2.js → chunk-JTMNCCWF.js} +2 -2
  32. package/{chunk-ASZ2C44S.js → chunk-LPEUV5RE.js} +2 -2
  33. package/{chunk-WVDAUR2S.js → chunk-M43KDE25.js} +1 -1
  34. package/{chunk-GWESD7AS.js → chunk-MR6ISAGB.js} +2 -2
  35. package/{chunk-LSHKV3S7.js → chunk-NSCHQQPU.js} +9 -9
  36. package/{chunk-F6JSVFHX.js → chunk-NVEWUJVX.js} +1 -1
  37. package/{chunk-R6ALN5F5.js → chunk-P3RIAYGG.js} +1 -1
  38. package/{chunk-FMYTM25W.js → chunk-PCTUYVUM.js} +1 -1
  39. package/{chunk-BHVBFI6B.js → chunk-S2LXHNHG.js} +3 -3
  40. package/{chunk-SGRDLYRZ.js → chunk-Z5JQNBNY.js} +1 -1
  41. package/{chunk-7HECYFOI.js → chunk-ZQBL7LIC.js} +22 -17
  42. package/{createAgentAutomationAction-3KKRAYGE.js → createAgentAutomationAction-FNHPSKKO.js} +4 -4
  43. package/{createDialogAction-S7NMQ4TZ.js → createDialogAction-TZCVQ3NU.js} +5 -5
  44. package/{createPageAction-2EFBT4LQ.js → createPageAction-EIGZ3BKT.js} +4 -4
  45. package/{dialogCommands-J7XFIQRD.js → dialogCommands-FO77J5DQ.js} +13 -14
  46. package/{dialogSlice-LNRRBUIC.js → dialogSlice-MM5U4KE2.js} +4 -4
  47. package/{docCreateCommands-MKO5WB34.js → docCreateCommands-I3BS3AZI.js} +15 -18
  48. package/{docDeleteCommands-RCBHRKUE.js → docDeleteCommands-Q2OPV52P.js} +14 -17
  49. package/{docReadCommands-66527P4G.js → docReadCommands-YOOFACYZ.js} +13 -16
  50. package/{docStore-67MYPX7P.js → docStore-NGYQ2JTR.js} +5 -5
  51. package/{docUpdateCommands-UT5HSLOJ.js → docUpdateCommands-2B32ITHN.js} +14 -17
  52. package/{handleSendMessageAction-VZ7226PB.js → handleSendMessageAction-JRZWWBKP.js} +4 -4
  53. package/index.js +43 -74
  54. package/{machineCommands-ATA7OSBJ.js → machineCommands-WRWF2ICZ.js} +21 -22
  55. package/{machineWsRunDispatch-ZDCZ645H.js → machineWsRunDispatch-ZX7Q3TWZ.js} +21 -22
  56. package/{models-5K5G2CZI.js → models-WQ5N4OJM.js} +1 -1
  57. package/package.json +1 -1
  58. package/{readlineWorkspace-UUNABTLB.js → readlineWorkspace-ZTGRGW46.js} +74 -75
  59. package/{runAgentClientLoop-2A577WBM.js → runAgentClientLoop-JZCOP7LG.js} +14 -15
  60. package/{spaceCommands-UNZVR2OS.js → spaceCommands-VV4GTPQK.js} +12 -13
  61. package/{spaceSlice-MC7FYPMZ.js → spaceSlice-DRWWZJP7.js} +4 -4
  62. package/{streamAgentChatTurn-IEKPNM33.js → streamAgentChatTurn-Y6WGATQR.js} +23 -21
  63. package/{tools-E6FHKTCF.js → tools-PUNBY3AH.js} +9 -9
  64. package/{tuiSummaryLlmCaller-QHPDD4WP.js → tuiSummaryLlmCaller-F64WLSAF.js} +3 -4
  65. package/{updateDialogTitleAction-SQJEEW2K.js → updateDialogTitleAction-YSR4TCMB.js} +4 -4
  66. package/appDeleteCommands-FRWMPQNS.js +0 -125
  67. package/appDeployCommands-IRF3T35Z.js +0 -164
  68. package/appDeployStatusCommands-ADFERYPU.js +0 -145
  69. package/appGetCommands-FTEOXWMS.js +0 -120
  70. package/appListCommands-WBY7UWYD.js +0 -123
  71. package/chunk-G63IH3ZK.js +0 -107
  72. package/chunk-GFUIQ4RY.js +0 -136
  73. package/chunk-KFEVY3ST.js +0 -255
  74. /package/{chunk-RK5NYQEL.js → chunk-XBS2WYJ2.js} +0 -0
@@ -7,6 +7,9 @@ import {
7
7
  import {
8
8
  asTrimmedString
9
9
  } from "./chunk-3EUW3WEO.js";
10
+ import {
11
+ isRecord
12
+ } from "./chunk-KUG52IAP.js";
10
13
  import {
11
14
  normalizeServerOrigin
12
15
  } from "./chunk-CF7PE763.js";
@@ -333,6 +336,242 @@ async function buildProviderExecutionPlan(args) {
333
336
  };
334
337
  }
335
338
 
339
+ // packages/agent-runtime/openAiCompatibleMessages.ts
340
+ function preserveAgentStateFields(source, target, options) {
341
+ const mutableTarget = target;
342
+ if (source.role === "assistant") {
343
+ if (!options?.stripReasoningContent && typeof source.reasoning_content === "string") {
344
+ mutableTarget.reasoning_content = source.reasoning_content;
345
+ }
346
+ if (Array.isArray(source.tool_calls)) {
347
+ mutableTarget.tool_calls = source.tool_calls;
348
+ }
349
+ }
350
+ if (source.role === "tool") {
351
+ const toolCallId = typeof source.tool_call_id === "string" ? source.tool_call_id.trim() : typeof source.toolCallId === "string" ? source.toolCallId.trim() : "";
352
+ if (toolCallId) mutableTarget.tool_call_id = toolCallId;
353
+ }
354
+ return target;
355
+ }
356
+ function toOpenAiCompatibleMessages(messages, options) {
357
+ return messages.map(
358
+ (message) => preserveAgentStateFields(message, {
359
+ role: message.role,
360
+ content: message.content ?? ""
361
+ }, options)
362
+ );
363
+ }
364
+ function shouldStripReasoningContentForOutbound(provider, model) {
365
+ const p = provider?.trim().toLowerCase();
366
+ const m = model?.trim().toLowerCase();
367
+ if (!p || !m) return false;
368
+ if (p === "deepseek" || p === "nolo") return m === "deepseek-v4-flash";
369
+ return false;
370
+ }
371
+
372
+ // packages/integrations/openai/responsesHelpers.ts
373
+ var RESPONSES_TOP_LEVEL_SCHEMA_KEYS = ["anyOf", "oneOf", "allOf", "enum", "not"];
374
+ var sanitizeResponsesParameters = (parameters) => {
375
+ if (!isRecord(parameters)) {
376
+ return parameters;
377
+ }
378
+ const next = { ...parameters };
379
+ for (const key of RESPONSES_TOP_LEVEL_SCHEMA_KEYS) {
380
+ delete next[key];
381
+ }
382
+ return next;
383
+ };
384
+ var appendTextPart = (parts, text, role) => {
385
+ if (!text) return;
386
+ const last = parts.at(-1);
387
+ const textType = role === "assistant" ? "output_text" : "input_text";
388
+ if (last?.type === textType) {
389
+ last.text += text;
390
+ return;
391
+ }
392
+ parts.push({ type: textType, text });
393
+ };
394
+ var normalizeMessageParts = (content, role) => {
395
+ if (typeof content === "string") {
396
+ if (!content) return [];
397
+ return [
398
+ {
399
+ type: role === "assistant" ? "output_text" : "input_text",
400
+ text: content
401
+ }
402
+ ];
403
+ }
404
+ const parts = [];
405
+ for (const part of content ?? []) {
406
+ const typedPart = part;
407
+ if (typedPart?.type === "text" && typeof typedPart.text === "string") {
408
+ appendTextPart(parts, typedPart.text, role);
409
+ continue;
410
+ }
411
+ if (typedPart?.type === "image_url" && typeof typedPart.image_url?.url === "string" && typedPart.image_url.url) {
412
+ if (role === "assistant") continue;
413
+ parts.push({
414
+ type: "input_image",
415
+ image_url: typedPart.image_url.url,
416
+ detail: typedPart.image_url.detail
417
+ });
418
+ }
419
+ }
420
+ return parts;
421
+ };
422
+ var normalizeToolOutput = (content) => {
423
+ if (typeof content === "string") return content;
424
+ return JSON.stringify(content ?? "");
425
+ };
426
+ var toResponsesTools = (tools) => {
427
+ if (!Array.isArray(tools) || tools.length === 0) return void 0;
428
+ return tools.map((tool) => {
429
+ const fn = tool?.function;
430
+ if (!fn?.name) return null;
431
+ return {
432
+ type: "function",
433
+ name: fn.name,
434
+ description: fn.description,
435
+ parameters: sanitizeResponsesParameters(fn.parameters),
436
+ strict: fn.strict
437
+ };
438
+ }).filter(Boolean);
439
+ };
440
+ var convertMessagesToResponsesInput = (messages, options) => {
441
+ const input = [];
442
+ for (const message of messages) {
443
+ if (!message?.role) continue;
444
+ if (message.role === "tool") {
445
+ if (!message.tool_call_id) continue;
446
+ input.push({
447
+ type: "function_call_output",
448
+ call_id: message.tool_call_id,
449
+ output: normalizeToolOutput(message.content)
450
+ });
451
+ continue;
452
+ }
453
+ const role = message.role;
454
+ if (role === "assistant" && !options?.stripReasoningContent && typeof message.reasoning_content === "string" && message.reasoning_content) {
455
+ input.push({ type: "reasoning", content: message.reasoning_content });
456
+ }
457
+ const contentParts = normalizeMessageParts(message.content, role);
458
+ if (contentParts.length > 0) {
459
+ input.push({
460
+ type: "message",
461
+ role,
462
+ content: contentParts
463
+ });
464
+ }
465
+ if (role === "assistant" && Array.isArray(message.content)) {
466
+ const replayImages = message.content.map((part) => part).filter(
467
+ (part) => part?.type === "image_url" && typeof part.image_url?.url === "string" && Boolean(part.image_url.url)
468
+ ).map((part) => ({
469
+ type: "input_image",
470
+ image_url: part.image_url.url,
471
+ detail: part.image_url.detail
472
+ }));
473
+ if (replayImages.length > 0) {
474
+ input.push({
475
+ type: "message",
476
+ role: "user",
477
+ content: replayImages
478
+ });
479
+ }
480
+ }
481
+ if (role === "assistant" && Array.isArray(message.tool_calls)) {
482
+ for (const toolCall of message.tool_calls) {
483
+ if (!toolCall?.id || !toolCall.function?.name) continue;
484
+ input.push({
485
+ type: "function_call",
486
+ call_id: toolCall.id,
487
+ name: toolCall.function.name,
488
+ arguments: typeof toolCall.function.arguments === "string" ? toolCall.function.arguments : JSON.stringify(toolCall.function.arguments ?? {})
489
+ });
490
+ }
491
+ }
492
+ }
493
+ return input;
494
+ };
495
+ var extractTextFromResponseOutput = (response) => {
496
+ const parts = [];
497
+ for (const item of response?.output ?? []) {
498
+ if (item?.type !== "message") continue;
499
+ for (const content of item.content ?? []) {
500
+ if (content?.type === "output_text" && typeof content.text === "string") {
501
+ parts.push(content.text);
502
+ }
503
+ }
504
+ }
505
+ return parts.join("");
506
+ };
507
+ var toDataUrl = (base64Data, mimeType) => {
508
+ const normalizedMimeType = asOptionalTrimmedString(mimeType) ?? "image/png";
509
+ return `data:${normalizedMimeType};base64,${base64Data}`;
510
+ };
511
+ var extractImagePartsFromResponseOutput = (response) => {
512
+ const images = [];
513
+ for (const item of response?.output ?? []) {
514
+ if (item?.type === "image_generation_call") {
515
+ const result = asOptionalTrimmedString(item.result);
516
+ if (result) {
517
+ const outputFormat = asOptionalTrimmedString(item.output_format);
518
+ images.push({
519
+ type: "image_url",
520
+ image_url: {
521
+ url: toDataUrl(
522
+ result,
523
+ outputFormat ? `image/${outputFormat}` : void 0
524
+ )
525
+ }
526
+ });
527
+ }
528
+ continue;
529
+ }
530
+ if (item?.type !== "message") continue;
531
+ for (const content of item.content ?? []) {
532
+ const result = asOptionalTrimmedString(content?.result);
533
+ if (content?.type === "output_image" && result) {
534
+ images.push({
535
+ type: "image_url",
536
+ image_url: {
537
+ url: toDataUrl(
538
+ result,
539
+ content.mime_type ?? content.mimeType ?? null
540
+ )
541
+ }
542
+ });
543
+ }
544
+ }
545
+ }
546
+ return images;
547
+ };
548
+ var extractToolCallsFromResponseOutput = (response) => {
549
+ const calls = [];
550
+ for (const item of response?.output ?? []) {
551
+ if (item?.type !== "function_call") continue;
552
+ if (!item.call_id || !item.name) continue;
553
+ calls.push({
554
+ id: item.call_id,
555
+ type: "function",
556
+ function: {
557
+ name: item.name,
558
+ arguments: typeof item.arguments === "string" ? item.arguments : JSON.stringify(item.arguments ?? {})
559
+ }
560
+ });
561
+ }
562
+ return calls;
563
+ };
564
+
565
+ // packages/core/chat/imageParts.ts
566
+ function isImageUrlPart(part) {
567
+ return isRecord(part) && part.type === "image_url";
568
+ }
569
+ function hasImageParts(messages) {
570
+ return messages.some(
571
+ (message) => Array.isArray(message.content) && message.content.some(isImageUrlPart)
572
+ );
573
+ }
574
+
336
575
  export {
337
576
  pickAgentRuntimeInferenceOptions,
338
577
  isOpenAiResponsesModel,
@@ -346,5 +585,15 @@ export {
346
585
  resolveAgentRuntimeLocation,
347
586
  resolveProviderTransportDecision,
348
587
  buildProviderAuthHeaders,
349
- buildProviderExecutionPlan
588
+ buildProviderExecutionPlan,
589
+ isImageUrlPart,
590
+ hasImageParts,
591
+ preserveAgentStateFields,
592
+ toOpenAiCompatibleMessages,
593
+ shouldStripReasoningContentForOutbound,
594
+ toResponsesTools,
595
+ convertMessagesToResponsesInput,
596
+ extractTextFromResponseOutput,
597
+ extractImagePartsFromResponseOutput,
598
+ extractToolCallsFromResponseOutput
350
599
  };
@@ -4,34 +4,31 @@ import {
4
4
  providerHttpFailure,
5
5
  readSseFrames,
6
6
  throwIfChatCompletionStreamFailed
7
- } from "./chunk-4N7QA72L.js";
7
+ } from "./chunk-AVVZUXXC.js";
8
8
  import {
9
9
  parseToolArgumentsJson
10
- } from "./chunk-LZYEWFPK.js";
10
+ } from "./chunk-GSINCD4P.js";
11
11
  import {
12
12
  createThinkParserState,
13
13
  createToolCallAccumulator,
14
- createToolCallTextParserState,
15
14
  extractThinkContent,
16
15
  finalizeAccumulatedToolCalls
17
- } from "./chunk-LSFAWXKC.js";
16
+ } from "./chunk-3WGLLTK4.js";
18
17
  import {
19
18
  requiresBareImageUrl,
20
19
  toBareImageUrlMessages
21
- } from "./chunk-ASZ2C44S.js";
20
+ } from "./chunk-LPEUV5RE.js";
22
21
  import {
22
+ buildProviderAuthHeaders,
23
+ buildProviderExecutionPlan,
23
24
  shouldStripReasoningContentForOutbound,
24
25
  toOpenAiCompatibleMessages
25
- } from "./chunk-KFEVY3ST.js";
26
- import {
27
- buildProviderAuthHeaders,
28
- buildProviderExecutionPlan
29
- } from "./chunk-ZVDRAEZL.js";
26
+ } from "./chunk-6EVITP2G.js";
30
27
  import {
31
28
  canonicalizeToolName,
32
29
  createGlob,
33
30
  resolveExecutableOnPath
34
- } from "./chunk-B4KT7RN2.js";
31
+ } from "./chunk-JTMNCCWF.js";
35
32
  import {
36
33
  toErrorMessage
37
34
  } from "./chunk-HNMXYYJR.js";
@@ -88,10 +85,6 @@ function parseSseDataLineJson(line) {
88
85
  return null;
89
86
  }
90
87
  }
91
- function parseSseDataLineObject(line) {
92
- const parsed = parseSseDataLineJson(line);
93
- return parsed && typeof parsed === "object" ? parsed : null;
94
- }
95
88
 
96
89
  // packages/agent-runtime/openAiCompatibleProvider.ts
97
90
  function buildOpenAiCompatibleChatCompletionRequest(args) {
@@ -167,7 +160,6 @@ async function readOpenAiCompatibleSseCompletion(args) {
167
160
  usage: void 0,
168
161
  accumulatedToolCalls: createToolCallAccumulator(),
169
162
  thinkState: createThinkParserState(),
170
- toolCallTextState: createToolCallTextParserState(),
171
163
  onTextDelta: args.onTextDelta,
172
164
  onReasoningDelta: args.onReasoningDelta
173
165
  };
@@ -841,16 +833,12 @@ var buildCombinedShellInput = (args) => {
841
833
  typeof args.input === "string" ? args.input : ""
842
834
  ].filter(Boolean).join("\n");
843
835
  };
844
- function resolveScannableShellInput(args) {
836
+ function isDestructiveShellCommand(args) {
845
837
  const combined = buildCombinedShellInput(args);
846
- if (!combined.trim()) return void 0;
847
- return SHELL_STRING_EXECUTION_PATTERNS.some(
838
+ if (!combined.trim()) return false;
839
+ const scannable = SHELL_STRING_EXECUTION_PATTERNS.some(
848
840
  (pattern) => pattern.test(combined)
849
841
  ) ? combined : stripQuotedSegments(combined);
850
- }
851
- function isDestructiveShellCommand(args) {
852
- const scannable = resolveScannableShellInput(args);
853
- if (scannable === void 0) return false;
854
842
  return SHELL_DESTRUCTIVE_PATTERNS.some((pattern) => pattern.test(scannable));
855
843
  }
856
844
  var LONG_RUNNING_COMMAND_PATTERNS = [
@@ -866,42 +854,13 @@ var LONG_RUNNING_COMMAND_PATTERNS = [
866
854
  /\bpm2\b.*\bstart\b/i
867
855
  ];
868
856
  function isLongRunningShellCommand(args) {
869
- const scannable = resolveScannableShellInput(args);
870
- if (scannable === void 0) return false;
857
+ const combined = buildCombinedShellInput(args);
858
+ if (!combined.trim()) return false;
859
+ const scannable = SHELL_STRING_EXECUTION_PATTERNS.some(
860
+ (pattern) => pattern.test(combined)
861
+ ) ? combined : stripQuotedSegments(combined);
871
862
  return LONG_RUNNING_COMMAND_PATTERNS.some((pattern) => pattern.test(scannable));
872
863
  }
873
- var IMMEDIATE_DETACH_COMMAND_PATTERNS = [
874
- /\btail\s+(?:-\S*[fF]\S*|--follow)\b/,
875
- /\bwatch\s+\S/,
876
- /\bwhile\s+(?:true|:|\[\s*true\s*\])\s*;\s*do\b/
877
- ];
878
- var IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS = 5;
879
- var SLEEP_PREFIX_PATTERN = /^(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:nohup\s+|time\s+)*sleep\s+(\S+)/;
880
- function parseSleepDurationSeconds(token) {
881
- const match = /^(\d+(?:\.\d+)?)(s|m|h|d)?$/i.exec(token);
882
- if (!match) return void 0;
883
- const value = Number(match[1]);
884
- if (!Number.isFinite(value)) return void 0;
885
- const unit = (match[2] ?? "s").toLowerCase();
886
- const factor = unit === "m" ? 60 : unit === "h" ? 3600 : unit === "d" ? 86400 : 1;
887
- return value * factor;
888
- }
889
- function isLongSleepCommand(scannable) {
890
- const match = SLEEP_PREFIX_PATTERN.exec(scannable.trim());
891
- if (!match) return false;
892
- const durationToken = match[1] ?? "";
893
- if (/^inf(inity)?$/i.test(durationToken)) return true;
894
- const seconds = parseSleepDurationSeconds(durationToken);
895
- if (seconds === void 0) return true;
896
- return seconds > IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS;
897
- }
898
- function isImmediateDetachShellCommand(args) {
899
- const scannable = resolveScannableShellInput(args);
900
- if (scannable === void 0) return false;
901
- return isLongSleepCommand(scannable) || LONG_RUNNING_COMMAND_PATTERNS.some((pattern) => pattern.test(scannable)) || IMMEDIATE_DETACH_COMMAND_PATTERNS.some(
902
- (pattern) => pattern.test(scannable)
903
- );
904
- }
905
864
  function evaluateShellCommandPolicy(args) {
906
865
  if (isDestructiveShellCommand(args) && !hasExplicitDestructivePermission(args.userInput)) {
907
866
  return {
@@ -1584,7 +1543,7 @@ function buildExecShellTool(toolName) {
1584
1543
  type: "function",
1585
1544
  function: {
1586
1545
  name: toolName,
1587
- description: "Run a shell command in the local workspace. Commands already execute from the workspace root; do not cd into guessed paths such as /workspace, /repo, /home/user, or /home/user/workspace. Prefer one command that performs a complete verification or related git operation instead of many tiny commands. For branch setup, prefer idempotent commands such as git switch -C <branch> when replacing or recreating a benchmark branch is acceptable. Use portable POSIX commands for macOS/BSD shells; avoid GNU-only flags such as cat -A. Do not use cat -A. Do not use brittle byte-offset commands such as xxd -s -32. For separator lines, use echo or printf '%s\\n'. For text-file content or trailing-newline checks, prefer readFile over shell byte inspection when that tool is available. Do not run repeated git status, git log, git rev-parse, or branch checks after a successful command already returned the needed clean status and commit information; use one final verification command. If a command fails, use the error output to adjust the next command rather than repeating the same shape. For long-running commands that should keep running in the background (dev servers, watchers, REPLs, `--watch`/`serve`/`dev` scripts), prefer launchProcess. Obviously long-running commands run via execShell (sleep over 5s, tail -f, watch, infinite loops, dev/serve/watch scripts) are moved to the background automatically and return {detached: true, pid, label} \u2014 use listProcesses to inspect or stop them, and tell the user the command is running in the background. Any other command blocks until it exits, so keep those short.",
1546
+ description: "Run a shell command in the local workspace. Commands already execute from the workspace root; do not cd into guessed paths such as /workspace, /repo, /home/user, or /home/user/workspace. Prefer one command that performs a complete verification or related git operation instead of many tiny commands. For branch setup, prefer idempotent commands such as git switch -C <branch> when replacing or recreating a benchmark branch is acceptable. Use portable POSIX commands for macOS/BSD shells; avoid GNU-only flags such as cat -A. Do not use cat -A. Do not use brittle byte-offset commands such as xxd -s -32. For separator lines, use echo or printf '%s\\n'. For text-file content or trailing-newline checks, prefer readFile over shell byte inspection when that tool is available. Do not run repeated git status, git log, git rev-parse, or branch checks after a successful command already returned the needed clean status and commit information; use one final verification command. If a command fails, use the error output to adjust the next command rather than repeating the same shape. For long-running commands that should keep running in the background (dev servers, watchers, REPLs, `--watch`/`serve`/`dev` scripts), use launchProcess instead \u2014 execShell blocks until the command exits and will freeze the conversation.",
1588
1547
  parameters: {
1589
1548
  type: "object",
1590
1549
  properties: {
@@ -1781,9 +1740,8 @@ function resolveExecShellTimeoutMs(override) {
1781
1740
  return asOptionalPositiveFiniteNumber(Number(raw));
1782
1741
  }
1783
1742
  function resolveDetachMs(override) {
1784
- if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
1785
- return override;
1786
- }
1743
+ const fromOverride = asOptionalPositiveFiniteNumber(override);
1744
+ if (fromOverride !== void 0) return fromOverride;
1787
1745
  const raw = process.env[EXEC_SHELL_DETACH_ENV];
1788
1746
  if (raw === void 0) return DEFAULT_EXEC_SHELL_DETACH_MS;
1789
1747
  const parsed = asOptionalPositiveFiniteNumber(Number(raw));
@@ -2547,9 +2505,9 @@ async function runWorkspaceCommand(args) {
2547
2505
  args.abortSignal.addEventListener("abort", abortListener, { once: true });
2548
2506
  }) : null;
2549
2507
  const effectiveDetachMs = resolveDetachMs(args.detachMs);
2550
- const detachPromise = new Promise((r) => {
2508
+ const detachPromise = effectiveDetachMs ? new Promise((r) => {
2551
2509
  detachTimer = setTimeout(() => r(detachResult), effectiveDetachMs);
2552
- });
2510
+ }) : null;
2553
2511
  const racers = [exitPromise];
2554
2512
  if (timeoutMs) {
2555
2513
  racers.push(
@@ -2559,7 +2517,7 @@ async function runWorkspaceCommand(args) {
2559
2517
  );
2560
2518
  }
2561
2519
  if (abortPromise) racers.push(abortPromise);
2562
- racers.push(detachPromise);
2520
+ if (detachPromise) racers.push(detachPromise);
2563
2521
  let raceWinner;
2564
2522
  try {
2565
2523
  raceWinner = await Promise.race(racers);
@@ -2592,35 +2550,25 @@ async function runWorkspaceCommand(args) {
2592
2550
  killChild("SIGKILL");
2593
2551
  }
2594
2552
  if (didDetach) {
2595
- exitPromise.catch(() => {
2596
- });
2553
+ detachSignalCleanup();
2597
2554
  const pid = typeof proc.pid === "number" ? proc.pid : 0;
2598
2555
  const label = deriveLabel(args.command.join(" "));
2599
2556
  const pgid = pid;
2600
2557
  const registry2 = getProcessRegistry();
2601
2558
  registry2.add({ pid, pgid, command: args.command.join(" "), label });
2602
2559
  proc.on("close", (code) => {
2603
- detachSignalCleanup();
2604
2560
  registry2.markExited(pid, code ?? 1);
2605
2561
  });
2606
- const immediate = effectiveDetachMs === 0;
2607
- 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})`;
2608
2562
  return {
2609
2563
  stdout: "",
2610
- stderr: `${reason}
2611
- Use listProcesses to inspect or stop it.`,
2564
+ stderr: `command detached to background after ${effectiveDetachMs}ms (pid=${pid}, label=${label})
2565
+ Use listProcesses / processRegistry to inspect.`,
2612
2566
  exitCode: 0,
2613
2567
  timedOut: false,
2614
2568
  detached: true,
2615
2569
  pid,
2616
2570
  label,
2617
- content: JSON.stringify({
2618
- detached: true,
2619
- pid,
2620
- label,
2621
- status: "running",
2622
- ...immediate ? { reason: "long-running-command" } : {}
2623
- })
2571
+ content: JSON.stringify({ detached: true, pid, label, status: "running" })
2624
2572
  };
2625
2573
  }
2626
2574
  const [stdout, rawStderr] = await Promise.all([
@@ -3452,11 +3400,7 @@ async function execShellTool(args) {
3452
3400
  outputLimit: args.commandOutputLimit,
3453
3401
  commandPrefix: args.commandPrefix,
3454
3402
  abortSignal: args.abortSignal,
3455
- // Commands that clearly never exit (long sleeps, tail -f, watch, dev
3456
- // servers, infinite loops) are promoted to background immediately so the
3457
- // turn — and the user's conversation — keeps going. Everything else keeps
3458
- // the caller/env detach grace window.
3459
- detachMs: isImmediateDetachShellCommand({ command }) ? 0 : args.detachMs
3403
+ detachMs: args.detachMs
3460
3404
  });
3461
3405
  const activity = extractActivity(parsed);
3462
3406
  return {
@@ -3630,7 +3574,6 @@ function createLocalWorkspaceToolExecutors(args) {
3630
3574
 
3631
3575
  export {
3632
3576
  parseSseDataLineJson,
3633
- parseSseDataLineObject,
3634
3577
  buildOpenAiCompatibleChatCompletionRequest,
3635
3578
  parseOpenAiCompatibleChatCompletionResponse,
3636
3579
  readOpenAiCompatibleSseCompletion,