nolo-cli 0.16.0 → 0.18.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 (134) hide show
  1. package/{_executeModel-AVCA2NAV.js → _executeModel-X5PCIZN6.js} +50 -44
  2. package/{action-F5JACQBG.js → action-LT7BRFLK.js} +10 -9
  3. package/{addContentAction-AQXEYRBE.js → addContentAction-PL3KKBDH.js} +9 -8
  4. package/{addDialogAgentAction-EJHHJZWW.js → addDialogAgentAction-FCMSKYAF.js} +8 -7
  5. package/{agentDeleteCommand-QW5PUMDQ.js → agentDeleteCommand-2BZDQV36.js} +32 -29
  6. package/{agentEmailCommands-4ORVLGVQ.js → agentEmailCommands-2QJDGRMB.js} +62 -56
  7. package/{agentListCommands-YWBYRTYC.js → agentListCommands-6VEPTKBI.js} +31 -28
  8. package/{agentMachineCommands-JSQW4FOA.js → agentMachineCommands-NVVHNWYI.js} +30 -27
  9. package/{agentPullCommand-6HWUT3SW.js → agentPullCommand-ZZGU5KOY.js} +4 -4
  10. package/{agentRecordCommands-AASIWOBT.js → agentRecordCommands-4GGRDMD4.js} +57 -51
  11. package/{agentRunCommand-TB5BHXUH.js → agentRunCommand-XOLQNKBZ.js} +63 -54
  12. package/{agentRunControl-6ADXVYMR.js → agentRunControl-Y5AFH5PQ.js} +24 -1
  13. package/{agentRuntimeLocal-QNPNJRVH.js → agentRuntimeLocal-7WYWCGL4.js} +25 -22
  14. package/{agentSlice-RUNXC62Y.js → agentSlice-EAXPGEYV.js} +9 -8
  15. package/appDeleteCommands-77KR2RJ4.js +127 -0
  16. package/appDeployCommands-K7CAHGBI.js +166 -0
  17. package/appDeployStatusCommands-4OEKLTBT.js +147 -0
  18. package/appGetCommands-VM2WDLAZ.js +122 -0
  19. package/appListCommands-GX6BBA6U.js +125 -0
  20. package/{authCommand-YFTR3347.js → authCommand-DY6UUL6O.js} +16 -9
  21. package/{authCommands-YXGOXNBZ.js → authCommands-XTBV7OFZ.js} +6 -5
  22. package/{chunk-DPAB4FQ7.js → chunk-23FZYPLC.js} +1608 -212
  23. package/{chunk-LPEUV5RE.js → chunk-34WPV75U.js} +23 -2
  24. package/{chunk-XPC5C7BK.js → chunk-3ND52WIL.js} +2 -2
  25. package/{chunk-SOTZ6RDN.js → chunk-3Q7WHGCB.js} +1 -1
  26. package/{chunk-3OIRVWXA.js → chunk-3ZX7PERL.js} +10 -1
  27. package/{chunk-KKY4B2Q2.js → chunk-4PWB7JRR.js} +4 -1
  28. package/{chunk-6N4KODMN.js → chunk-4T5F7YZQ.js} +1 -1
  29. package/chunk-7BUYEZ6U.js +671 -0
  30. package/{chunk-AS3ZQ3O2.js → chunk-7OBMZCRD.js} +1 -1
  31. package/{chunk-IGXREZW2.js → chunk-AHCY2S2I.js} +1 -1
  32. package/{chunk-QLUFR47U.js → chunk-AL2V7U3E.js} +1 -1
  33. package/{chunk-MTU75CZ2.js → chunk-B5TOXZAK.js} +1 -1
  34. package/{chunk-AUURUT6L.js → chunk-BV4VEE3W.js} +264 -424
  35. package/{chunk-FRV6A633.js → chunk-CZ6NYQTV.js} +13 -4
  36. package/{chunk-PCTUYVUM.js → chunk-DFCFMCY6.js} +10 -3
  37. package/{chunk-JTMNCCWF.js → chunk-DKZFOK24.js} +16 -87
  38. package/chunk-DL6EPNIK.js +50 -0
  39. package/{chunk-ZQBL7LIC.js → chunk-EDV7EBOI.js} +317 -216
  40. package/{chunk-IWLUTMYX.js → chunk-ELT65PZW.js} +2 -2
  41. package/chunk-FQZZLA3C.js +223 -0
  42. package/{chunk-55NSNCFM.js → chunk-FXUSIQC2.js} +1 -1
  43. package/{chunk-MR6ISAGB.js → chunk-G5U6LDLG.js} +6 -6
  44. package/chunk-GFUIQ4RY.js +136 -0
  45. package/{chunk-NVEWUJVX.js → chunk-HEGV7BH3.js} +1 -1
  46. package/{chunk-BEBNFWDU.js → chunk-HWW2M4SN.js} +3 -3
  47. package/{chunk-4L2OJPCU.js → chunk-I2ZJKTG5.js} +58 -8
  48. package/{chunk-Z5JQNBNY.js → chunk-IYEXFJPC.js} +34 -15
  49. package/{setDialogExtraReferencesAction-LR6MSIXO.js → chunk-JLA4FXYC.js} +2 -17
  50. package/chunk-KFEVY3ST.js +255 -0
  51. package/{chunk-4FX6NVDW.js → chunk-L4F3I4SR.js} +3 -136
  52. package/{chunk-XBS2WYJ2.js → chunk-LLWKHDG4.js} +1 -1
  53. package/{chunk-3WGLLTK4.js → chunk-LSFAWXKC.js} +100 -3
  54. package/{chunk-6EVITP2G.js → chunk-MHSGJW4Z.js} +2 -251
  55. package/{chunk-O6W2O2DA.js → chunk-MKA6QE5E.js} +6 -2
  56. package/{chunk-DGEYDWEZ.js → chunk-MPVYDS7I.js} +3 -3
  57. package/{chunk-KFHN5NGJ.js → chunk-MVQ4TBSD.js} +1 -1
  58. package/{chunk-AVVZUXXC.js → chunk-N54HIJVJ.js} +34 -13
  59. package/{chunk-EHLHSX7R.js → chunk-OK6YSWLH.js} +9 -2
  60. package/{chunk-33BJUVK4.js → chunk-PIZYJVHQ.js} +5 -5
  61. package/{chunk-RLCXU7A5.js → chunk-PJSV3IZ5.js} +1 -1
  62. package/{chunk-7UKFVQ5W.js → chunk-R35XMF6F.js} +126 -41
  63. package/{chunk-OOSFSFMA.js → chunk-R5V5G73M.js} +2 -0
  64. package/{chunk-S2LXHNHG.js → chunk-REA4JLBH.js} +6 -6
  65. package/chunk-RQN4SEKL.js +107 -0
  66. package/{chunk-EABWT43X.js → chunk-RVOUXDFU.js} +5 -5
  67. package/{chunk-NSCHQQPU.js → chunk-SCTYAHYK.js} +470 -325
  68. package/{chunk-JTINRTBT.js → chunk-SKDNBYZK.js} +2 -2
  69. package/{chunk-M43KDE25.js → chunk-SWDPIPOY.js} +2 -8
  70. package/{chunk-KMQPSTMJ.js → chunk-TRT4I4UD.js} +2 -2
  71. package/{chunk-66X4VSRC.js → chunk-UAIVG4J6.js} +42 -2
  72. package/{chunk-3663CXZN.js → chunk-UBHAWFQ6.js} +143 -31
  73. package/{chunk-YJKXGHJ6.js → chunk-UGUW3FHG.js} +4 -4
  74. package/{chunk-P3RIAYGG.js → chunk-V3ED5AWK.js} +3 -3
  75. package/chunk-V5R4NZP2.js +78 -0
  76. package/{chunk-4IJYA27C.js → chunk-VDXCXCXH.js} +1 -1
  77. package/{chunk-MYMMNKYL.js → chunk-VNAEBGDK.js} +156 -6
  78. package/{chunk-FY233ZFU.js → chunk-VYHDJEQD.js} +110 -192
  79. package/{chunk-W4NVOSFF.js → chunk-WFHXMLHZ.js} +1 -1
  80. package/{chunk-H33743XH.js → chunk-WJRJDX2W.js} +1 -1
  81. package/chunk-X4Q4UZEY.js +26 -0
  82. package/{chunk-RPDGJO4D.js → chunk-XHG22OEX.js} +4 -4
  83. package/{chunk-DVRHHFEA.js → chunk-XMLRJUU5.js} +1 -1
  84. package/{chunk-3S2VOMIF.js → chunk-XRZJGPFI.js} +7 -7
  85. package/{chunk-GSINCD4P.js → chunk-YGW4G5W5.js} +25 -12
  86. package/chunk-ZZ2MH7LE.js +84 -0
  87. package/{cliExecutor-K3F7DMRO.js → cliExecutor-DNE7TCC4.js} +2 -2
  88. package/codingSkills-36KN5NQT.js +48 -0
  89. package/{createAgentAutomationAction-FNHPSKKO.js → createAgentAutomationAction-GNFF524X.js} +20 -19
  90. package/{createDialogAction-TZCVQ3NU.js → createDialogAction-RB55KCLO.js} +22 -21
  91. package/{createPageAction-EIGZ3BKT.js → createPageAction-Y7343GLU.js} +26 -25
  92. package/{db-HCJ5PRB5.js → db-W3O47YGF.js} +38 -12
  93. package/{dbSlice-7KQH6GOU.js → dbSlice-CGSRFJN3.js} +8 -7
  94. package/{deleteFile-WPWVZE4B.js → deleteFile-WDZ3VM7B.js} +3 -3
  95. package/{dialogCommands-FO77J5DQ.js → dialogCommands-IAZK6YHQ.js} +30 -27
  96. package/{dialogSlice-MM5U4KE2.js → dialogSlice-UQAXF23P.js} +20 -19
  97. package/{docCreateCommands-I3BS3AZI.js → docCreateCommands-I2EWZGCI.js} +33 -28
  98. package/{docDeleteCommands-Q2OPV52P.js → docDeleteCommands-IZ45UZKG.js} +32 -27
  99. package/{docReadCommands-YOOFACYZ.js → docReadCommands-R6Z4QJYU.js} +31 -26
  100. package/{docStore-NGYQ2JTR.js → docStore-5HOJ4D7D.js} +21 -20
  101. package/{docUpdateCommands-2B32ITHN.js → docUpdateCommands-2LRBKQPY.js} +32 -27
  102. package/{fetchMessages-KTNM7QAR.js → fetchMessages-BMGVZVSE.js} +4 -3
  103. package/{getPricing-P4XRJRZB.js → getPricing-G7DLAST6.js} +3 -3
  104. package/{handleSendMessageAction-JRZWWBKP.js → handleSendMessageAction-Q4HY35WX.js} +21 -20
  105. package/index.js +95 -64
  106. package/{localDialogRead-2VRI24F4.js → localDialogRead-4H3QJFLW.js} +2 -2
  107. package/{localRuntimeDb-LGDF6FQP.js → localRuntimeDb-THJZGAOJ.js} +1 -1
  108. package/{machineCommands-WRWF2ICZ.js → machineCommands-PKBPQKTY.js} +63 -57
  109. package/{machineWsRunDispatch-ZX7Q3TWZ.js → machineWsRunDispatch-UZAW4OXJ.js} +55 -49
  110. package/{models-WQ5N4OJM.js → models-DJFSJ7SW.js} +2 -2
  111. package/package.json +1 -1
  112. package/queryRunOverlay-O4LOMMPO.js +161 -0
  113. package/{read-CN3TNXIP.js → read-3FMPZPER.js} +3 -3
  114. package/{readDocTool-WF3675ED.js → readDocTool-VSYHKK3V.js} +1 -1
  115. package/{readlineWorkspace-ZTGRGW46.js → readlineWorkspace-Y2RDOFZG.js} +762 -218
  116. package/{removeDialogAgentAction-YDHBFEGI.js → removeDialogAgentAction-OAGA2G3U.js} +10 -9
  117. package/{runAgentClientLoop-JZCOP7LG.js → runAgentClientLoop-NBPIKJ6J.js} +44 -38
  118. package/runOverlayPresentation-ZO4VCWEU.js +11 -0
  119. package/{runtimeDoctorCommands-THIHX2SY.js → runtimeDoctorCommands-E2OUORHK.js} +6 -6
  120. package/setDialogExtraReferencesAction-JZEXA5SL.js +27 -0
  121. package/{setPrimaryDialogAgentAction-IIVDCY5C.js → setPrimaryDialogAgentAction-4ZUQQKDG.js} +26 -17
  122. package/{settingSlice-O23YDK2O.js → settingSlice-7MNKHZ6R.js} +9 -8
  123. package/{skillDiscovery-6M2BZUFN.js → skillDiscovery-KJWT7JBU.js} +3 -3
  124. package/{spaceCommands-VV4GTPQK.js → spaceCommands-DHCZ7J5I.js} +31 -28
  125. package/{spaceSlice-DRWWZJP7.js → spaceSlice-ZXLLG3CR.js} +20 -19
  126. package/{streamAgentChatTurn-Y6WGATQR.js → streamAgentChatTurn-L3YW6LSB.js} +98 -57
  127. package/{tableCommands-3P7MJ3PF.js → tableCommands-BEQAGE4I.js} +1 -1
  128. package/{tools-PUNBY3AH.js → tools-ECGXR5QF.js} +33 -28
  129. package/{tuiSummaryLlmCaller-F64WLSAF.js → tuiSummaryLlmCaller-OMSCNHXA.js} +6 -5
  130. package/types-ZSTJ7MPR.js +7 -0
  131. package/{updateDialogTitleAction-YSR4TCMB.js → updateDialogTitleAction-HQ2EUDFT.js} +23 -22
  132. package/{chunk-O4BU24WZ.js → chunk-6Y7A3OQQ.js} +3 -3
  133. package/{chunk-CMKUBIGW.js → chunk-X7W4TNB4.js} +3 -3
  134. package/{localRuntimeAuthority-TEGCOWX4.js → localRuntimeAuthority-4IXJCHZ7.js} +3 -3
@@ -4,46 +4,51 @@ import {
4
4
  providerHttpFailure,
5
5
  readSseFrames,
6
6
  throwIfChatCompletionStreamFailed
7
- } from "./chunk-AVVZUXXC.js";
7
+ } from "./chunk-N54HIJVJ.js";
8
8
  import {
9
9
  parseToolArgumentsJson
10
- } from "./chunk-GSINCD4P.js";
10
+ } from "./chunk-YGW4G5W5.js";
11
11
  import {
12
12
  createThinkParserState,
13
13
  createToolCallAccumulator,
14
+ createToolCallTextParserState,
14
15
  extractThinkContent,
15
16
  finalizeAccumulatedToolCalls
16
- } from "./chunk-3WGLLTK4.js";
17
+ } from "./chunk-LSFAWXKC.js";
17
18
  import {
18
19
  requiresBareImageUrl,
19
20
  toBareImageUrlMessages
20
- } from "./chunk-LPEUV5RE.js";
21
+ } from "./chunk-34WPV75U.js";
21
22
  import {
22
- buildProviderAuthHeaders,
23
- buildProviderExecutionPlan,
24
23
  shouldStripReasoningContentForOutbound,
25
24
  toOpenAiCompatibleMessages
26
- } from "./chunk-6EVITP2G.js";
25
+ } from "./chunk-KFEVY3ST.js";
26
+ import {
27
+ buildProviderAuthHeaders,
28
+ buildProviderExecutionPlan
29
+ } from "./chunk-MHSGJW4Z.js";
27
30
  import {
28
- canonicalizeToolName,
29
31
  createGlob,
30
32
  resolveExecutableOnPath
31
- } from "./chunk-JTMNCCWF.js";
33
+ } from "./chunk-DKZFOK24.js";
32
34
  import {
33
35
  toErrorMessage
34
36
  } from "./chunk-HNMXYYJR.js";
37
+ import {
38
+ canonicalizeToolName
39
+ } from "./chunk-ZZ2MH7LE.js";
35
40
  import {
36
41
  asRecordOrEmpty
37
42
  } from "./chunk-KX6YBIHG.js";
38
43
  import {
39
44
  dialogMessageKey
40
- } from "./chunk-O4BU24WZ.js";
41
- import {
42
- asTrimmedNonEmptyStringArray
43
- } from "./chunk-I42VC5KR.js";
45
+ } from "./chunk-6Y7A3OQQ.js";
44
46
  import {
45
47
  asOptionalFiniteNumber
46
48
  } from "./chunk-WWC7I6TA.js";
49
+ import {
50
+ asTrimmedNonEmptyStringArray
51
+ } from "./chunk-I42VC5KR.js";
47
52
  import {
48
53
  asTrimmedLowercaseString
49
54
  } from "./chunk-QSJ3HFEF.js";
@@ -85,6 +90,10 @@ function parseSseDataLineJson(line) {
85
90
  return null;
86
91
  }
87
92
  }
93
+ function parseSseDataLineObject(line) {
94
+ const parsed = parseSseDataLineJson(line);
95
+ return parsed && typeof parsed === "object" ? parsed : null;
96
+ }
88
97
 
89
98
  // packages/agent-runtime/openAiCompatibleProvider.ts
90
99
  function buildOpenAiCompatibleChatCompletionRequest(args) {
@@ -160,6 +169,7 @@ async function readOpenAiCompatibleSseCompletion(args) {
160
169
  usage: void 0,
161
170
  accumulatedToolCalls: createToolCallAccumulator(),
162
171
  thinkState: createThinkParserState(),
172
+ toolCallTextState: createToolCallTextParserState(),
163
173
  onTextDelta: args.onTextDelta,
164
174
  onReasoningDelta: args.onReasoningDelta
165
175
  };
@@ -529,14 +539,24 @@ function buildAgentRuntimeDialogWritePlan(args) {
529
539
  const nowIso = new Date(args.now).toISOString();
530
540
  const dialogKey = `dialog-${args.userId}-${dialogId}`;
531
541
  const subjectRefs = buildRuntimeSubjectRefs(args.input.runtimeContext);
542
+ const requestedAgentMode = args.input.runtimeContext?.dialogAgentMode === "auto" || args.input.runtimeContext?.dialogAgentMode === "fixed" ? args.input.runtimeContext.dialogAgentMode : void 0;
543
+ const agentMode = requestedAgentMode ?? (args.existingDialog?.agentMode === "auto" ? "auto" : "fixed");
544
+ const dialogAgentFields = agentMode === "auto" ? {
545
+ agentMode: "auto",
546
+ cybots: [],
547
+ primaryAgentKey: void 0
548
+ } : {
549
+ agentMode: "fixed",
550
+ cybots: [args.input.agentKey],
551
+ primaryAgentKey: args.input.agentKey
552
+ };
532
553
  const dialogRecord = {
533
554
  ...asRecordOrEmpty(args.existingDialog),
534
555
  id: dialogId,
535
556
  dbKey: dialogKey,
536
557
  type: "dialog",
537
558
  userId: args.userId,
538
- cybots: [args.input.agentKey],
539
- primaryAgentKey: args.input.agentKey,
559
+ ...dialogAgentFields,
540
560
  title: pickDialogTitle({
541
561
  existingDialog: args.existingDialog,
542
562
  titleOverride: args.titleOverride,
@@ -833,12 +853,16 @@ var buildCombinedShellInput = (args) => {
833
853
  typeof args.input === "string" ? args.input : ""
834
854
  ].filter(Boolean).join("\n");
835
855
  };
836
- function isDestructiveShellCommand(args) {
856
+ function resolveScannableShellInput(args) {
837
857
  const combined = buildCombinedShellInput(args);
838
- if (!combined.trim()) return false;
839
- const scannable = SHELL_STRING_EXECUTION_PATTERNS.some(
858
+ if (!combined.trim()) return void 0;
859
+ return SHELL_STRING_EXECUTION_PATTERNS.some(
840
860
  (pattern) => pattern.test(combined)
841
861
  ) ? combined : stripQuotedSegments(combined);
862
+ }
863
+ function isDestructiveShellCommand(args) {
864
+ const scannable = resolveScannableShellInput(args);
865
+ if (scannable === void 0) return false;
842
866
  return SHELL_DESTRUCTIVE_PATTERNS.some((pattern) => pattern.test(scannable));
843
867
  }
844
868
  var LONG_RUNNING_COMMAND_PATTERNS = [
@@ -854,13 +878,42 @@ var LONG_RUNNING_COMMAND_PATTERNS = [
854
878
  /\bpm2\b.*\bstart\b/i
855
879
  ];
856
880
  function isLongRunningShellCommand(args) {
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);
881
+ const scannable = resolveScannableShellInput(args);
882
+ if (scannable === void 0) return false;
862
883
  return LONG_RUNNING_COMMAND_PATTERNS.some((pattern) => pattern.test(scannable));
863
884
  }
885
+ var IMMEDIATE_DETACH_COMMAND_PATTERNS = [
886
+ /\btail\s+(?:-\S*[fF]\S*|--follow)\b/,
887
+ /\bwatch\s+\S/,
888
+ /\bwhile\s+(?:true|:|\[\s*true\s*\])\s*;\s*do\b/
889
+ ];
890
+ var IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS = 5;
891
+ var SLEEP_PREFIX_PATTERN = /^(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:nohup\s+|time\s+)*sleep\s+(\S+)/;
892
+ function parseSleepDurationSeconds(token) {
893
+ const match = /^(\d+(?:\.\d+)?)(s|m|h|d)?$/i.exec(token);
894
+ if (!match) return void 0;
895
+ const value = Number(match[1]);
896
+ if (!Number.isFinite(value)) return void 0;
897
+ const unit = (match[2] ?? "s").toLowerCase();
898
+ const factor = unit === "m" ? 60 : unit === "h" ? 3600 : unit === "d" ? 86400 : 1;
899
+ return value * factor;
900
+ }
901
+ function isLongSleepCommand(scannable) {
902
+ const match = SLEEP_PREFIX_PATTERN.exec(scannable.trim());
903
+ if (!match) return false;
904
+ const durationToken = match[1] ?? "";
905
+ if (/^inf(inity)?$/i.test(durationToken)) return true;
906
+ const seconds = parseSleepDurationSeconds(durationToken);
907
+ if (seconds === void 0) return true;
908
+ return seconds > IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS;
909
+ }
910
+ function isImmediateDetachShellCommand(args) {
911
+ const scannable = resolveScannableShellInput(args);
912
+ if (scannable === void 0) return false;
913
+ return isLongSleepCommand(scannable) || LONG_RUNNING_COMMAND_PATTERNS.some((pattern) => pattern.test(scannable)) || IMMEDIATE_DETACH_COMMAND_PATTERNS.some(
914
+ (pattern) => pattern.test(scannable)
915
+ );
916
+ }
864
917
  function evaluateShellCommandPolicy(args) {
865
918
  if (isDestructiveShellCommand(args) && !hasExplicitDestructivePermission(args.userInput)) {
866
919
  return {
@@ -1086,7 +1139,8 @@ var ProcessRegistry = class {
1086
1139
  command: proc.command,
1087
1140
  label: proc.label,
1088
1141
  startedAt: Date.now(),
1089
- status: "running"
1142
+ status: "running",
1143
+ persist: proc.persist ?? false
1090
1144
  });
1091
1145
  }
1092
1146
  list() {
@@ -1109,9 +1163,9 @@ var ProcessRegistry = class {
1109
1163
  }
1110
1164
  return false;
1111
1165
  }
1112
- stopAll(signal = "SIGTERM") {
1166
+ stopAll(signal = "SIGTERM", opts) {
1113
1167
  for (const item of this.processes.values()) {
1114
- if (item.status === "running") {
1168
+ if (item.status === "running" && (opts?.includePersist || !item.persist)) {
1115
1169
  try {
1116
1170
  process.kill(-item.pgid, signal);
1117
1171
  } catch {
@@ -1543,7 +1597,7 @@ function buildExecShellTool(toolName) {
1543
1597
  type: "function",
1544
1598
  function: {
1545
1599
  name: toolName,
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.",
1600
+ 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.",
1547
1601
  parameters: {
1548
1602
  type: "object",
1549
1603
  properties: {
@@ -1576,6 +1630,10 @@ function buildLaunchProcessTool() {
1576
1630
  label: {
1577
1631
  type: "string",
1578
1632
  description: "Optional friendly label for the process."
1633
+ },
1634
+ persist: {
1635
+ type: "boolean",
1636
+ description: "Mark the process as persistent so it survives the current TUI/session exit (kept running in the background when the conversation closes). Defaults to false. Use for long-lived services (e.g. a desktop dev server) you want to keep alive after the session ends."
1579
1637
  }
1580
1638
  },
1581
1639
  required: ["command"]
@@ -1588,7 +1646,7 @@ function buildListProcessesTool() {
1588
1646
  type: "function",
1589
1647
  function: {
1590
1648
  name: "listProcesses",
1591
- description: "List currently registered background processes launched via launchProcess. Returns array of {pid, label, command, status, startedAt}.",
1649
+ description: "List currently registered background processes launched via launchProcess. Returns array of {pid, label, command, status, startedAt, persist}.",
1592
1650
  parameters: {
1593
1651
  type: "object",
1594
1652
  properties: {}
@@ -1732,6 +1790,16 @@ var SEARCH_OUTPUT_CHAR_LIMIT = 2e4;
1732
1790
  function readTrimmedString(value) {
1733
1791
  return asOptionalTrimmedString(value);
1734
1792
  }
1793
+ function readBoolean(parsed, key) {
1794
+ const val = parsed[key];
1795
+ if (typeof val === "boolean") return val;
1796
+ if (typeof val === "string") {
1797
+ const lower = val.trim().toLowerCase();
1798
+ if (lower === "true") return true;
1799
+ if (lower === "false") return false;
1800
+ }
1801
+ return void 0;
1802
+ }
1735
1803
  function resolveExecShellTimeoutMs(override) {
1736
1804
  const fromOverride = asOptionalPositiveFiniteNumber(override);
1737
1805
  if (fromOverride !== void 0) return fromOverride;
@@ -1740,8 +1808,9 @@ function resolveExecShellTimeoutMs(override) {
1740
1808
  return asOptionalPositiveFiniteNumber(Number(raw));
1741
1809
  }
1742
1810
  function resolveDetachMs(override) {
1743
- const fromOverride = asOptionalPositiveFiniteNumber(override);
1744
- if (fromOverride !== void 0) return fromOverride;
1811
+ if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
1812
+ return override;
1813
+ }
1745
1814
  const raw = process.env[EXEC_SHELL_DETACH_ENV];
1746
1815
  if (raw === void 0) return DEFAULT_EXEC_SHELL_DETACH_MS;
1747
1816
  const parsed = asOptionalPositiveFiniteNumber(Number(raw));
@@ -2505,9 +2574,9 @@ async function runWorkspaceCommand(args) {
2505
2574
  args.abortSignal.addEventListener("abort", abortListener, { once: true });
2506
2575
  }) : null;
2507
2576
  const effectiveDetachMs = resolveDetachMs(args.detachMs);
2508
- const detachPromise = effectiveDetachMs ? new Promise((r) => {
2577
+ const detachPromise = new Promise((r) => {
2509
2578
  detachTimer = setTimeout(() => r(detachResult), effectiveDetachMs);
2510
- }) : null;
2579
+ });
2511
2580
  const racers = [exitPromise];
2512
2581
  if (timeoutMs) {
2513
2582
  racers.push(
@@ -2517,7 +2586,7 @@ async function runWorkspaceCommand(args) {
2517
2586
  );
2518
2587
  }
2519
2588
  if (abortPromise) racers.push(abortPromise);
2520
- if (detachPromise) racers.push(detachPromise);
2589
+ racers.push(detachPromise);
2521
2590
  let raceWinner;
2522
2591
  try {
2523
2592
  raceWinner = await Promise.race(racers);
@@ -2550,25 +2619,35 @@ async function runWorkspaceCommand(args) {
2550
2619
  killChild("SIGKILL");
2551
2620
  }
2552
2621
  if (didDetach) {
2553
- detachSignalCleanup();
2622
+ exitPromise.catch(() => {
2623
+ });
2554
2624
  const pid = typeof proc.pid === "number" ? proc.pid : 0;
2555
2625
  const label = deriveLabel(args.command.join(" "));
2556
2626
  const pgid = pid;
2557
2627
  const registry2 = getProcessRegistry();
2558
2628
  registry2.add({ pid, pgid, command: args.command.join(" "), label });
2559
2629
  proc.on("close", (code) => {
2630
+ detachSignalCleanup();
2560
2631
  registry2.markExited(pid, code ?? 1);
2561
2632
  });
2633
+ const immediate = effectiveDetachMs === 0;
2634
+ 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})`;
2562
2635
  return {
2563
2636
  stdout: "",
2564
- stderr: `command detached to background after ${effectiveDetachMs}ms (pid=${pid}, label=${label})
2565
- Use listProcesses / processRegistry to inspect.`,
2637
+ stderr: `${reason}
2638
+ Use listProcesses to inspect or stop it.`,
2566
2639
  exitCode: 0,
2567
2640
  timedOut: false,
2568
2641
  detached: true,
2569
2642
  pid,
2570
2643
  label,
2571
- content: JSON.stringify({ detached: true, pid, label, status: "running" })
2644
+ content: JSON.stringify({
2645
+ detached: true,
2646
+ pid,
2647
+ label,
2648
+ status: "running",
2649
+ ...immediate ? { reason: "long-running-command" } : {}
2650
+ })
2572
2651
  };
2573
2652
  }
2574
2653
  const [stdout, rawStderr] = await Promise.all([
@@ -2926,7 +3005,7 @@ async function searchFilesTool(args) {
2926
3005
  const literal = parsed.literal === true;
2927
3006
  const caseSensitive = parsed.caseSensitive === false ? false : true;
2928
3007
  const requestedPath = pickFirstAlias(parsed, PATH_FIELD_ALIASES) ?? ".";
2929
- const includeIgnored = parsed.includeIgnored === true;
3008
+ const includeIgnored = parsed.includeIgnored === true || args.workspaceRoot.includes(".worktrees");
2930
3009
  const searchPath = await resolveLocalWorkspaceToolPath({
2931
3010
  workspaceRoot: args.workspaceRoot,
2932
3011
  requestedPath,
@@ -3202,7 +3281,7 @@ async function globFilesTool(args) {
3202
3281
  const exclude = readWorkspaceExcludeGlobs(parsed);
3203
3282
  const maxResults = readWorkspaceMaxResults(parsed, warnings);
3204
3283
  const requestedPath = pickFirstAlias(parsed, PATH_FIELD_ALIASES) ?? ".";
3205
- const includeIgnored = parsed.includeIgnored === true;
3284
+ const includeIgnored = parsed.includeIgnored === true || args.workspaceRoot.includes(".worktrees");
3206
3285
  const searchPath = await resolveLocalWorkspaceToolPath({
3207
3286
  workspaceRoot: args.workspaceRoot,
3208
3287
  requestedPath,
@@ -3400,7 +3479,11 @@ async function execShellTool(args) {
3400
3479
  outputLimit: args.commandOutputLimit,
3401
3480
  commandPrefix: args.commandPrefix,
3402
3481
  abortSignal: args.abortSignal,
3403
- detachMs: args.detachMs
3482
+ // Commands that clearly never exit (long sleeps, tail -f, watch, dev
3483
+ // servers, infinite loops) are promoted to background immediately so the
3484
+ // turn — and the user's conversation — keeps going. Everything else keeps
3485
+ // the caller/env detach grace window.
3486
+ detachMs: isImmediateDetachShellCommand({ command }) ? 0 : args.detachMs
3404
3487
  });
3405
3488
  const activity = extractActivity(parsed);
3406
3489
  return {
@@ -3434,6 +3517,7 @@ async function launchProcessTool(args) {
3434
3517
  }
3435
3518
  const labelArg = readTrimmedString(parsed.label);
3436
3519
  const label = labelArg || deriveLabel(command);
3520
+ const persist = readBoolean(parsed, "persist");
3437
3521
  const fullCommand = buildWorkspaceShellCommand({
3438
3522
  toolName: args.call.name,
3439
3523
  command,
@@ -3458,7 +3542,7 @@ async function launchProcessTool(args) {
3458
3542
  }
3459
3543
  const pgid = detached ? pid : pid;
3460
3544
  const registry2 = getProcessRegistry();
3461
- registry2.add({ pid, pgid, command, label });
3545
+ registry2.add({ pid, pgid, command, label, persist });
3462
3546
  const cleanupChildOnHostSignal = (signal) => {
3463
3547
  try {
3464
3548
  if (detached) {
@@ -3574,6 +3658,7 @@ function createLocalWorkspaceToolExecutors(args) {
3574
3658
 
3575
3659
  export {
3576
3660
  parseSseDataLineJson,
3661
+ parseSseDataLineObject,
3577
3662
  buildOpenAiCompatibleChatCompletionRequest,
3578
3663
  parseOpenAiCompatibleChatCompletionResponse,
3579
3664
  readOpenAiCompatibleSseCompletion,
@@ -13,6 +13,7 @@ import {
13
13
  var processEnv = typeof process !== "undefined" ? process.env : void 0;
14
14
  var reactNativeDev = typeof globalThis !== "undefined" && "__DEV__" in globalThis ? globalThis.__DEV__ : void 0;
15
15
  var isProduction = processEnv?.NOLO_FORCE_PRODUCTION === "1" || processEnv?.NODE_ENV === "production" || reactNativeDev === false;
16
+ var isDevelopment = !isProduction;
16
17
  var getIsDesktopApp = () => (typeof process !== "undefined" ? process.env?.NOLO_DESKTOP : processEnv?.NOLO_DESKTOP) === "1" || typeof window !== "undefined" && window.__NOLO_DESKTOP__ === true;
17
18
  var isDesktopApp = getIsDesktopApp();
18
19
 
@@ -258,6 +259,7 @@ var normalizeTimeFields = (data) => ({
258
259
 
259
260
  export {
260
261
  isProduction,
262
+ isDevelopment,
261
263
  getIsDesktopApp,
262
264
  createClientLogger,
263
265
  isAbortError,
@@ -11,16 +11,16 @@ import {
11
11
  patch,
12
12
  remove,
13
13
  write
14
- } from "./chunk-3S2VOMIF.js";
14
+ } from "./chunk-XRZJGPFI.js";
15
15
  import {
16
16
  createAgentKey,
17
17
  toTrimmedString
18
- } from "./chunk-O4BU24WZ.js";
18
+ } from "./chunk-6Y7A3OQQ.js";
19
19
  import {
20
20
  asyncThunkCreator,
21
21
  buildCreateSlice,
22
22
  getRuntimeServerContext
23
- } from "./chunk-DVRHHFEA.js";
23
+ } from "./chunk-XMLRJUU5.js";
24
24
  import {
25
25
  asTrimmedString
26
26
  } from "./chunk-3EUW3WEO.js";
@@ -300,7 +300,7 @@ var slice = createSliceWithThunks({
300
300
  const overrides = {};
301
301
  if (args.systemPromptOverride !== void 0) overrides.prompt = args.systemPromptOverride;
302
302
  if (args.toolsOverride !== void 0) overrides.tools = args.toolsOverride;
303
- const { _executeModel } = await import("./_executeModel-AVCA2NAV.js");
303
+ const { _executeModel } = await import("./_executeModel-X5PCIZN6.js");
304
304
  return _executeModel(
305
305
  {
306
306
  isStreaming: args.isStreaming ?? false,
@@ -321,7 +321,7 @@ var slice = createSliceWithThunks({
321
321
  * - 循环直到无工具调用或触发其他运行时停止条件
322
322
  */
323
323
  runAgent: create.asyncThunk(async (args, thunkApi) => {
324
- const { runAgentClientLoop } = await import("./runAgentClientLoop-JZCOP7LG.js");
324
+ const { runAgentClientLoop } = await import("./runAgentClientLoop-NBPIKJ6J.js");
325
325
  const { content: loopContent, toolCallCount } = await runAgentClientLoop(
326
326
  {
327
327
  agentKey: args.agentKey,
@@ -337,7 +337,7 @@ var slice = createSliceWithThunks({
337
337
  * 聊天轮次流式 Agent 调用
338
338
  */
339
339
  streamAgentChatTurn: create.asyncThunk(async (args, thunkApi) => {
340
- const { streamAgentChatTurnHandler } = await import("./streamAgentChatTurn-Y6WGATQR.js");
340
+ const { streamAgentChatTurnHandler } = await import("./streamAgentChatTurn-L3YW6LSB.js");
341
341
  return streamAgentChatTurnHandler(args, thunkApi);
342
342
  }),
343
343
  /**
@@ -0,0 +1,107 @@
1
+ import {
2
+ requireTokenUser
3
+ } from "./chunk-L4F3I4SR.js";
4
+ import {
5
+ resolveServerUrl
6
+ } from "./chunk-A7GB5UGH.js";
7
+
8
+ // packages/cli/cliApiClient.ts
9
+ var CliApiError = class extends Error {
10
+ code;
11
+ status;
12
+ constructor(message, code, status) {
13
+ super(message);
14
+ this.code = code;
15
+ this.status = status;
16
+ }
17
+ };
18
+ async function cliApiRequest(args) {
19
+ const method = args.method ?? "POST";
20
+ let url = `${args.serverUrl.replace(/\/$/, "")}${args.path}`;
21
+ if (args.query) {
22
+ const params = new URLSearchParams(args.query);
23
+ url += `?${params.toString()}`;
24
+ }
25
+ const headers = {
26
+ "Content-Type": "application/json",
27
+ Authorization: `Bearer ${args.authToken}`
28
+ };
29
+ const init = { method, headers };
30
+ if (args.body !== void 0 && args.body !== null && method !== "GET") {
31
+ init.body = JSON.stringify(args.body);
32
+ }
33
+ let response;
34
+ try {
35
+ response = await fetch(url, init);
36
+ } catch (error) {
37
+ throw new CliApiError(`\u8BF7\u6C42\u5931\u8D25: ${error.message}`, "NETWORK_ERROR", 0);
38
+ }
39
+ let data;
40
+ try {
41
+ data = await response.json();
42
+ } catch {
43
+ throw new CliApiError(
44
+ `\u670D\u52A1\u7AEF\u8FD4\u56DE\u975E JSON \u54CD\u5E94 (HTTP ${response.status})`,
45
+ "INVALID_RESPONSE",
46
+ response.status
47
+ );
48
+ }
49
+ if (!response.ok || data.success !== true) {
50
+ const errorObj = data.error ?? {};
51
+ const message = errorObj.message || data.message || `\u8BF7\u6C42\u5931\u8D25 (HTTP ${response.status})`;
52
+ const code = errorObj.code || `HTTP_${response.status}`;
53
+ throw new CliApiError(message, code, response.status);
54
+ }
55
+ return data;
56
+ }
57
+ function printCliError(error) {
58
+ if (error instanceof CliApiError) {
59
+ process.stderr.write(`\u9519\u8BEF [${error.code}]: ${error.message}
60
+ `);
61
+ } else if (error instanceof Error) {
62
+ process.stderr.write(`\u9519\u8BEF: ${error.message}
63
+ `);
64
+ } else {
65
+ process.stderr.write(`\u9519\u8BEF: ${String(error)}
66
+ `);
67
+ }
68
+ }
69
+ function resolveCliContext(args, env) {
70
+ const serverUrl = resolveServerUrl(args, env);
71
+ const { authToken, userId } = requireTokenUser(args, env, false);
72
+ return { serverUrl, authToken, userId };
73
+ }
74
+
75
+ // packages/cli/cliOutputHelpers.ts
76
+ function pickDefined(obj) {
77
+ const result = {};
78
+ for (const [key, value] of Object.entries(obj)) {
79
+ if (value !== void 0 && value !== null) result[key] = value;
80
+ }
81
+ return result;
82
+ }
83
+ function formatFields(fields, indent = "") {
84
+ const maxKeyLen = fields.reduce((max, [k]) => Math.max(max, k.length), 0);
85
+ const lines = fields.map(([key, value]) => {
86
+ const display = value === void 0 || value === null ? "-" : String(value);
87
+ return `${indent}${key.padEnd(maxKeyLen)}: ${display}`;
88
+ });
89
+ return lines.join("\n");
90
+ }
91
+ function outputResult(data, shouldOutputJson, formatter, output = process.stdout) {
92
+ if (shouldOutputJson) {
93
+ output.write(`${JSON.stringify(data, null, 2)}
94
+ `);
95
+ } else {
96
+ formatter();
97
+ }
98
+ }
99
+
100
+ export {
101
+ cliApiRequest,
102
+ printCliError,
103
+ resolveCliContext,
104
+ pickDefined,
105
+ formatFields,
106
+ outputResult
107
+ };
@@ -10,18 +10,18 @@ import {
10
10
  toTimestampMs,
11
11
  upsert,
12
12
  write
13
- } from "./chunk-3S2VOMIF.js";
13
+ } from "./chunk-XRZJGPFI.js";
14
14
  import {
15
15
  createUserKey,
16
16
  createUserPreferenceKey,
17
17
  ulid
18
- } from "./chunk-O4BU24WZ.js";
18
+ } from "./chunk-6Y7A3OQQ.js";
19
19
  import {
20
20
  asTrimmedLowercaseString
21
21
  } from "./chunk-QSJ3HFEF.js";
22
22
  import {
23
23
  BUILTIN_NOLO_AGENT_KEY
24
- } from "./chunk-XPC5C7BK.js";
24
+ } from "./chunk-3ND52WIL.js";
25
25
  import {
26
26
  asyncThunkCreator,
27
27
  buildCreateSlice,
@@ -29,12 +29,12 @@ import {
29
29
  createAsyncThunk,
30
30
  createSelector,
31
31
  selectIdentityUserId
32
- } from "./chunk-DVRHHFEA.js";
32
+ } from "./chunk-XMLRJUU5.js";
33
33
  import {
34
34
  getAllServers,
35
35
  getIsDesktopApp,
36
36
  isProduction
37
- } from "./chunk-OOSFSFMA.js";
37
+ } from "./chunk-R5V5G73M.js";
38
38
  import {
39
39
  SERVERS
40
40
  } from "./chunk-LCBAMY2M.js";