nolo-cli 0.19.0 → 0.24.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -18
- package/{_executeModel-X5PCIZN6.js → _executeModel-ZPNYAEFW.js} +46 -44
- package/{action-LT7BRFLK.js → action-5MNAXR5B.js} +7 -6
- package/{addContentAction-PL3KKBDH.js → addContentAction-UNSYTVTB.js} +5 -5
- package/{addDialogAgentAction-FCMSKYAF.js → addDialogAgentAction-LJGNP2AO.js} +5 -5
- package/{agentDeleteCommand-2BZDQV36.js → agentDeleteCommand-5ZV4433K.js} +27 -26
- package/{agentEmailCommands-2QJDGRMB.js → agentEmailCommands-Z7KOYDVQ.js} +57 -55
- package/{agentListCommands-6VEPTKBI.js → agentListCommands-UQUXJYUN.js} +30 -26
- package/{agentMachineCommands-NVVHNWYI.js → agentMachineCommands-53O6P6L5.js} +25 -24
- package/{agentRecordCommands-4GGRDMD4.js → agentRecordCommands-ZRYNBSSS.js} +52 -50
- package/{agentRunCommand-XOLQNKBZ.js → agentRunCommand-B73MKVOG.js} +55 -54
- package/{agentRunControl-Y5AFH5PQ.js → agentRunControl-SNUKXN6J.js} +6 -2
- package/{agentRuntimeLocal-7WYWCGL4.js → agentRuntimeLocal-GVNERRKQ.js} +21 -18
- package/{agentSlice-EAXPGEYV.js → agentSlice-OJBHIL34.js} +5 -5
- package/{appDeleteCommands-77KR2RJ4.js → appDeleteCommands-23Z3Z6KE.js} +23 -22
- package/{appDeployCommands-K7CAHGBI.js → appDeployCommands-3MFAR4Z7.js} +23 -22
- package/{appDeployStatusCommands-4OEKLTBT.js → appDeployStatusCommands-JHU6GSN4.js} +23 -22
- package/{appGetCommands-VM2WDLAZ.js → appGetCommands-24J55H2Y.js} +23 -22
- package/{appListCommands-GX6BBA6U.js → appListCommands-HE5KP3PH.js} +23 -22
- package/{authCommand-DY6UUL6O.js → authCommand-KGRK6MNU.js} +12 -13
- package/{authCommands-XTBV7OFZ.js → authCommands-JSOG2H4E.js} +4 -5
- package/{chunk-OWOHNGCN.js → chunk-2MBTWINN.js} +42 -3
- package/{chunk-MVQ4TBSD.js → chunk-54VHTARN.js} +1 -1
- package/{chunk-RQN4SEKL.js → chunk-5DWZ46RJ.js} +1 -1
- package/{chunk-VYHDJEQD.js → chunk-5EDKWSQN.js} +136 -78
- package/{chunk-Z4NR32XR.js → chunk-5RGU3J7P.js} +13 -0
- package/{chunk-7BUYEZ6U.js → chunk-7H3UTGPM.js} +12 -72
- package/{chunk-3ZX7PERL.js → chunk-AAWJ5S3G.js} +20 -7
- package/{chunk-SCTYAHYK.js → chunk-ADE6577S.js} +237 -142
- package/{chunk-PJSV3IZ5.js → chunk-AOPOTHFK.js} +1 -1
- package/{chunk-3ND52WIL.js → chunk-ATWUOTJP.js} +180 -24
- package/{chunk-SWDPIPOY.js → chunk-AZW5AHMW.js} +1 -1
- package/chunk-CF7S2RYZ.js +376 -0
- package/{chunk-L4F3I4SR.js → chunk-CV6BM7LU.js} +4 -6
- package/{chunk-G5U6LDLG.js → chunk-CWTT2NZ6.js} +6 -6
- package/{chunk-MKA6QE5E.js → chunk-CZHE6LLV.js} +135 -55
- package/{chunk-KFEVY3ST.js → chunk-D34RI6NI.js} +18 -8
- package/{chunk-XRZJGPFI.js → chunk-FON47ACC.js} +4 -4
- package/{chunk-K6EUAOW3.js → chunk-FXFGNOT2.js} +67 -1
- package/{chunk-LLWKHDG4.js → chunk-G36SUBHA.js} +14 -6
- package/{chunk-REA4JLBH.js → chunk-GD23ZX7Z.js} +7 -6
- package/{chunk-ROWQEJRP.js → chunk-GE6IWA5N.js} +12 -4
- package/{chunk-EDV7EBOI.js → chunk-GGB6MPHD.js} +2155 -1503
- package/{chunk-IYEXFJPC.js → chunk-GNGOZMU2.js} +64 -57
- package/{chunk-4T5F7YZQ.js → chunk-I6RJGORZ.js} +1 -1
- package/{chunk-DFCFMCY6.js → chunk-J2WT5CEO.js} +2 -2
- package/{chunk-AHCY2S2I.js → chunk-JJ2WUBFN.js} +1 -1
- package/{chunk-UGUW3FHG.js → chunk-JMSCXQUG.js} +2 -2
- package/{chunk-VDXCXCXH.js → chunk-KURQBS7S.js} +1 -1
- package/{chunk-FQZZLA3C.js → chunk-KXKQO4Q6.js} +17 -0
- package/{chunk-3Q7WHGCB.js → chunk-L65QKSVJ.js} +1 -1
- package/{chunk-UAIVG4J6.js → chunk-LEHTC2FI.js} +1 -8
- package/{chunk-UBHAWFQ6.js → chunk-LLDGWLML.js} +42 -19
- package/{chunk-JLA4FXYC.js → chunk-MALVZUYL.js} +1 -1
- package/{chunk-N54HIJVJ.js → chunk-MCXQNEJ3.js} +101 -9
- package/{chunk-GFUIQ4RY.js → chunk-MXFQHRSS.js} +1 -1
- package/{chunk-LSFAWXKC.js → chunk-N7J63Q6C.js} +1 -0
- package/{chunk-6Y7A3OQQ.js → chunk-NRY4GCKJ.js} +2 -0
- package/{chunk-ELT65PZW.js → chunk-OXLLFZNF.js} +1 -1
- package/{chunk-YGW4G5W5.js → chunk-P3RZ6DHN.js} +133 -25
- package/{chunk-5MIDPSSK.js → chunk-PB7G5MAM.js} +3 -3
- package/{chunk-HEGV7BH3.js → chunk-PMCKFQYC.js} +1 -1
- package/{chunk-23FZYPLC.js → chunk-PTKI7TIN.js} +911 -1064
- package/{chunk-MHSGJW4Z.js → chunk-PXPISYEH.js} +44 -14
- package/{chunk-I2ZJKTG5.js → chunk-PY7VGC5M.js} +29 -10
- package/{chunk-PIZYJVHQ.js → chunk-RM464B7I.js} +4 -4
- package/{chunk-XHG22OEX.js → chunk-ROJI6DRT.js} +2 -2
- package/{chunk-VNAEBGDK.js → chunk-RZNYL4LW.js} +123 -26
- package/{chunk-RVOUXDFU.js → chunk-S6KVFOUG.js} +6 -34
- package/{chunk-BV4VEE3W.js → chunk-S7AV3NCK.js} +277 -357
- package/{chunk-R35XMF6F.js → chunk-SIUEKVK4.js} +484 -67
- package/{chunk-B5TOXZAK.js → chunk-SIZQB7BD.js} +1 -1
- package/{chunk-DFFIZ25G.js → chunk-SLOGKB7M.js} +4 -1
- package/{chunk-MPVYDS7I.js → chunk-TLYHUIWF.js} +3 -3
- package/{chunk-HWW2M4SN.js → chunk-TNM27YZ7.js} +5 -4
- package/{chunk-OK6YSWLH.js → chunk-TWA4L7J7.js} +1 -1
- package/chunk-UZ6XXCVR.js +50 -0
- package/{chunk-DKZFOK24.js → chunk-WCP5FDTF.js} +16 -304
- package/{chunk-TRT4I4UD.js → chunk-WSQLK2KR.js} +2 -2
- package/{chunk-FXUSIQC2.js → chunk-XNZJVYFS.js} +1 -1
- package/{chunk-V3ED5AWK.js → chunk-YJY7HODU.js} +27 -16
- package/chunk-YYLHWIW6.js +48 -0
- package/{chunk-CZ6NYQTV.js → chunk-ZFL3LTU7.js} +2 -2
- package/{chunk-34WPV75U.js → chunk-ZUXIXYJI.js} +1 -1
- package/{chunk-VC6OZXO5.js → chunk-ZWJOGMKH.js} +2 -26
- package/{cliExecutor-DNE7TCC4.js → cliExecutor-K3F7DMRO.js} +2 -2
- package/{codingSkills-36KN5NQT.js → codingSkills-EN6Z6G6U.js} +4 -4
- package/{createAgentAutomationAction-GNFF524X.js → createAgentAutomationAction-PO62NUR7.js} +19 -18
- package/{createDialogAction-RB55KCLO.js → createDialogAction-ORFRYI3C.js} +22 -20
- package/{createPageAction-Y7343GLU.js → createPageAction-XWVMNTYH.js} +20 -19
- package/{db-W3O47YGF.js → db-W5UHK4P3.js} +150 -0
- package/{dbSlice-CGSRFJN3.js → dbSlice-5BKDURDL.js} +4 -4
- package/{dialogCommands-IAZK6YHQ.js → dialogCommands-XTJHROXM.js} +24 -23
- package/{dialogSlice-UQAXF23P.js → dialogSlice-DJXC53YW.js} +24 -18
- package/{docCreateCommands-I2EWZGCI.js → docCreateCommands-T2XRVXYS.js} +24 -27
- package/{docDeleteCommands-IZ45UZKG.js → docDeleteCommands-L7RXFXY3.js} +25 -24
- package/{docReadCommands-R6Z4QJYU.js → docReadCommands-M5PYNADQ.js} +24 -23
- package/{docStore-5HOJ4D7D.js → docStore-6LKLLFDW.js} +20 -19
- package/{docUpdateCommands-2LRBKQPY.js → docUpdateCommands-OA5EGPLQ.js} +24 -27
- package/{fetchMessages-BMGVZVSE.js → fetchMessages-W4IKHPCS.js} +2 -3
- package/{getPricing-G7DLAST6.js → getPricing-6C3C47Y4.js} +3 -3
- package/{handleSendMessageAction-Q4HY35WX.js → handleSendMessageAction-ILFGZTN5.js} +23 -20
- package/index.js +74 -74
- package/{localDialogRead-4H3QJFLW.js → localDialogRead-JXTAHW2E.js} +2 -2
- package/{machineCommands-PKBPQKTY.js → machineCommands-AKAQGPAO.js} +59 -57
- package/{machineWsRunDispatch-UZAW4OXJ.js → machineWsRunDispatch-RSBERM64.js} +51 -49
- package/{models-DJFSJ7SW.js → models-ILWKIX2Y.js} +2 -2
- package/package.json +1 -1
- package/{read-3FMPZPER.js → read-F3L3T2WJ.js} +2 -1
- package/{readDocTool-VSYHKK3V.js → readDocTool-FOHWVA4R.js} +1 -1
- package/{readlineWorkspace-Y2RDOFZG.js → readlineWorkspace-TUH3SFHO.js} +937 -430
- package/{removeDialogAgentAction-OAGA2G3U.js → removeDialogAgentAction-QCFGIUIH.js} +8 -7
- package/{runAgentClientLoop-NBPIKJ6J.js → runAgentClientLoop-C3QB2EXV.js} +45 -38
- package/{setDialogExtraReferencesAction-JZEXA5SL.js → setDialogExtraReferencesAction-DK4CKERU.js} +5 -5
- package/{setPrimaryDialogAgentAction-4ZUQQKDG.js → setPrimaryDialogAgentAction-SJSO6N27.js} +8 -7
- package/{settingSlice-7MNKHZ6R.js → settingSlice-XNM5AFPU.js} +6 -5
- package/{spaceCommands-DHCZ7J5I.js → spaceCommands-SXYOFGUJ.js} +25 -24
- package/{spaceSlice-ZXLLG3CR.js → spaceSlice-6BHMRP5O.js} +21 -18
- package/{streamAgentChatTurn-L3YW6LSB.js → streamAgentChatTurn-GF5W5OIP.js} +140 -98
- package/switchDialogAgentAction-4OAC6QRN.js +61 -0
- package/{tableCommands-BEQAGE4I.js → tableCommands-QSZILI7I.js} +1 -1
- package/{toolApiClient-QI3YBNWB.js → toolApiClient-ISM4ZQX4.js} +2 -2
- package/{tools-ECGXR5QF.js → tools-KBCLJ43G.js} +36 -33
- package/{tuiSummaryLlmCaller-OMSCNHXA.js → tuiSummaryLlmCaller-ARIMGILF.js} +6 -6
- package/{updateCommands-XTW55TOT.js → updateCommands-AK2RDOFR.js} +8 -2
- package/{updateDialogTitleAction-HQ2EUDFT.js → updateDialogTitleAction-LMHZUY4Q.js} +28 -27
- package/chunk-DL6EPNIK.js +0 -50
- package/chunk-V5R4NZP2.js +0 -78
- package/chunk-X4Q4UZEY.js +0 -26
- package/queryRunOverlay-O4LOMMPO.js +0 -161
- package/runOverlayPresentation-ZO4VCWEU.js +0 -11
- package/types-ZSTJ7MPR.js +0 -7
- package/{chunk-X7W4TNB4.js → chunk-CMKUBIGW.js} +3 -3
- package/{runtimeDoctorCommands-E2OUORHK.js → runtimeDoctorCommands-HSU632DY.js} +3 -3
|
@@ -4,45 +4,50 @@ import {
|
|
|
4
4
|
providerHttpFailure,
|
|
5
5
|
readSseFrames,
|
|
6
6
|
throwIfChatCompletionStreamFailed
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MCXQNEJ3.js";
|
|
8
8
|
import {
|
|
9
9
|
parseToolArgumentsJson
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-P3RZ6DHN.js";
|
|
11
11
|
import {
|
|
12
12
|
createThinkParserState,
|
|
13
13
|
createToolCallAccumulator,
|
|
14
14
|
createToolCallTextParserState,
|
|
15
15
|
extractThinkContent,
|
|
16
16
|
finalizeAccumulatedToolCalls
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-N7J63Q6C.js";
|
|
18
18
|
import {
|
|
19
19
|
requiresBareImageUrl,
|
|
20
20
|
toBareImageUrlMessages
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-ZUXIXYJI.js";
|
|
22
22
|
import {
|
|
23
23
|
shouldStripReasoningContentForOutbound,
|
|
24
24
|
toOpenAiCompatibleMessages
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-D34RI6NI.js";
|
|
26
26
|
import {
|
|
27
27
|
buildProviderAuthHeaders,
|
|
28
28
|
buildProviderExecutionPlan
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-PXPISYEH.js";
|
|
30
30
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
NOLO_WORKSPACE_TOOL_NAMES,
|
|
32
|
+
buildNoloWorkspaceCommandArgs,
|
|
33
|
+
noloStringArg,
|
|
34
|
+
parseNoloWorkspaceToolArguments
|
|
35
|
+
} from "./chunk-WCP5FDTF.js";
|
|
34
36
|
import {
|
|
35
|
-
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
buildDialogFallbackTitleFromUserInput
|
|
38
|
+
} from "./chunk-2MBTWINN.js";
|
|
37
39
|
import {
|
|
38
40
|
canonicalizeToolName
|
|
39
41
|
} from "./chunk-ZZ2MH7LE.js";
|
|
42
|
+
import {
|
|
43
|
+
toErrorMessage
|
|
44
|
+
} from "./chunk-HNMXYYJR.js";
|
|
40
45
|
import {
|
|
41
46
|
asRecordOrEmpty
|
|
42
47
|
} from "./chunk-KX6YBIHG.js";
|
|
43
48
|
import {
|
|
44
49
|
dialogMessageKey
|
|
45
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-NRY4GCKJ.js";
|
|
46
51
|
import {
|
|
47
52
|
asOptionalFiniteNumber
|
|
48
53
|
} from "./chunk-WWC7I6TA.js";
|
|
@@ -68,6 +73,44 @@ import {
|
|
|
68
73
|
asOptionalTrimmedString
|
|
69
74
|
} from "./chunk-G3SUCT4W.js";
|
|
70
75
|
|
|
76
|
+
// packages/agent-runtime/agentAvailability.ts
|
|
77
|
+
var DEFAULT_PROVIDER_RETRY_MS = 5 * 60 * 1e3;
|
|
78
|
+
function parseResetText(value) {
|
|
79
|
+
const m = value.match(/(?:resets?\s+in|retry[- ]after)\s*(?:(\d+)\s*hr)?\s*(?:(\d+)\s*min)?\s*(?:(\d+)\s*sec)?/i);
|
|
80
|
+
if (!m) return void 0;
|
|
81
|
+
return (Number(m[1] ?? 0) * 3600 + Number(m[2] ?? 0) * 60 + Number(m[3] ?? 0)) * 1e3;
|
|
82
|
+
}
|
|
83
|
+
function resolveAgentNextAvailableAt(body, now = Date.now()) {
|
|
84
|
+
const root = body && typeof body === "object" ? body : {};
|
|
85
|
+
const error = root.error && typeof root.error === "object" ? root.error : root;
|
|
86
|
+
const details = error.details && typeof error.details === "object" ? error.details : void 0;
|
|
87
|
+
const retryRaw = error.retryAfter ?? error.retry_after ?? error["Retry-After"];
|
|
88
|
+
if (typeof retryRaw === "number" && Number.isFinite(retryRaw)) {
|
|
89
|
+
return retryRaw > 1e12 ? retryRaw : now + Math.max(0, retryRaw) * 1e3;
|
|
90
|
+
}
|
|
91
|
+
if (typeof retryRaw === "string") {
|
|
92
|
+
const numeric = Number(retryRaw.trim());
|
|
93
|
+
if (Number.isFinite(numeric)) return now + Math.max(0, numeric) * 1e3;
|
|
94
|
+
const date = Date.parse(retryRaw);
|
|
95
|
+
if (Number.isFinite(date) && date > now) return date;
|
|
96
|
+
}
|
|
97
|
+
const resetRaw = error.resets_at ?? error.resetsAt ?? details?.resets_at ?? details?.resetsAt;
|
|
98
|
+
if (typeof resetRaw === "number" && Number.isFinite(resetRaw)) {
|
|
99
|
+
const absolute = resetRaw > 1e12 ? resetRaw : resetRaw * 1e3;
|
|
100
|
+
if (absolute > now) return absolute;
|
|
101
|
+
}
|
|
102
|
+
if (typeof resetRaw === "string") {
|
|
103
|
+
const parsed = Date.parse(resetRaw);
|
|
104
|
+
if (Number.isFinite(parsed) && parsed > now) return parsed;
|
|
105
|
+
}
|
|
106
|
+
const text = typeof body === "string" ? body : JSON.stringify(body ?? "");
|
|
107
|
+
return now + (parseResetText(text) ?? DEFAULT_PROVIDER_RETRY_MS);
|
|
108
|
+
}
|
|
109
|
+
function isAgentCoolingDown(agent, now = Date.now()) {
|
|
110
|
+
const at = agent && typeof agent === "object" ? agent.nextAvailableAt : void 0;
|
|
111
|
+
return typeof at === "number" && Number.isFinite(at) && at > now;
|
|
112
|
+
}
|
|
113
|
+
|
|
71
114
|
// packages/agent-runtime/kimiUserAgent.ts
|
|
72
115
|
var KIMI_CODE_CLI_VERSION = "0.29.2";
|
|
73
116
|
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_CODE_CLI_VERSION} (nolo)`;
|
|
@@ -443,21 +486,37 @@ function extractLastUserText(messages) {
|
|
|
443
486
|
return "";
|
|
444
487
|
}
|
|
445
488
|
function resolveDialogTitle(args) {
|
|
446
|
-
|
|
447
|
-
|
|
489
|
+
const existing = args.existingDialog?.title;
|
|
490
|
+
if (typeof existing === "string" && existing.trim()) {
|
|
491
|
+
return existing.trim();
|
|
448
492
|
}
|
|
449
493
|
const lastUserText = extractLastUserText(args.messages).trim();
|
|
450
|
-
return lastUserText
|
|
494
|
+
return buildDialogFallbackTitleFromUserInput(lastUserText) || "Local agent run";
|
|
451
495
|
}
|
|
452
496
|
function pickDialogTitle(args) {
|
|
453
|
-
const
|
|
454
|
-
|
|
497
|
+
const existingSource = args.existingDialog?.titleSource;
|
|
498
|
+
const existingIsManual = existingSource === "manual";
|
|
455
499
|
const override = args.titleOverride?.trim();
|
|
456
|
-
if (override)
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
500
|
+
if (override && !existingIsManual) {
|
|
501
|
+
return { title: override, titleSource: "generated" };
|
|
502
|
+
}
|
|
503
|
+
const existing = args.existingDialog?.title;
|
|
504
|
+
if (typeof existing === "string" && existing.trim()) {
|
|
505
|
+
return {
|
|
506
|
+
title: existing.trim(),
|
|
507
|
+
titleSource: existingIsManual ? "manual" : "generated"
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
if (override) {
|
|
511
|
+
return { title: override, titleSource: "generated" };
|
|
512
|
+
}
|
|
513
|
+
return {
|
|
514
|
+
title: resolveDialogTitle({
|
|
515
|
+
existingDialog: args.existingDialog,
|
|
516
|
+
messages: args.messages
|
|
517
|
+
}),
|
|
518
|
+
titleSource: "generated"
|
|
519
|
+
};
|
|
461
520
|
}
|
|
462
521
|
function normalizeSubjectRef(ref) {
|
|
463
522
|
if (!ref || typeof ref !== "object") return null;
|
|
@@ -472,6 +531,15 @@ function normalizeSubjectRef(ref) {
|
|
|
472
531
|
...role ? { role } : {}
|
|
473
532
|
};
|
|
474
533
|
}
|
|
534
|
+
function parseTitleUpdatedAtMs(existingDialog) {
|
|
535
|
+
const raw = existingDialog?.titleUpdatedAt;
|
|
536
|
+
if (typeof raw === "number" && !Number.isNaN(raw)) return raw;
|
|
537
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
538
|
+
const parsed = Date.parse(raw);
|
|
539
|
+
if (!Number.isNaN(parsed)) return parsed;
|
|
540
|
+
}
|
|
541
|
+
return 0;
|
|
542
|
+
}
|
|
475
543
|
function mergeSubjectRefs(...groups) {
|
|
476
544
|
const refs = [];
|
|
477
545
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -550,6 +618,14 @@ function buildAgentRuntimeDialogWritePlan(args) {
|
|
|
550
618
|
cybots: [args.input.agentKey],
|
|
551
619
|
primaryAgentKey: args.input.agentKey
|
|
552
620
|
};
|
|
621
|
+
const pickedTitle = pickDialogTitle({
|
|
622
|
+
existingDialog: args.existingDialog,
|
|
623
|
+
titleOverride: args.titleOverride,
|
|
624
|
+
messages: args.input.messages
|
|
625
|
+
});
|
|
626
|
+
const existingTitleUpdatedAtMs = parseTitleUpdatedAtMs(args.existingDialog);
|
|
627
|
+
const titleChanged = typeof args.titleOverride === "string" && args.titleOverride.trim().length > 0;
|
|
628
|
+
const titleUpdatedAtIso = titleChanged ? nowIso : existingTitleUpdatedAtMs > 0 ? new Date(existingTitleUpdatedAtMs).toISOString() : args.existingDialog?.createdAt ?? nowIso;
|
|
553
629
|
const dialogRecord = {
|
|
554
630
|
...asRecordOrEmpty(args.existingDialog),
|
|
555
631
|
id: dialogId,
|
|
@@ -557,11 +633,9 @@ function buildAgentRuntimeDialogWritePlan(args) {
|
|
|
557
633
|
type: "dialog",
|
|
558
634
|
userId: args.userId,
|
|
559
635
|
...dialogAgentFields,
|
|
560
|
-
title:
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
messages: args.input.messages
|
|
564
|
-
}),
|
|
636
|
+
title: pickedTitle.title,
|
|
637
|
+
titleSource: pickedTitle.titleSource,
|
|
638
|
+
titleUpdatedAt: titleUpdatedAtIso,
|
|
565
639
|
status: args.input.result.error === true ? "failed" : "done",
|
|
566
640
|
triggerType: `${args.runtimeHost}-local`,
|
|
567
641
|
executionMode: args.existingDialog?.executionMode ?? "foreground",
|
|
@@ -687,6 +761,11 @@ function shouldCacheHybridRemoteRecord(remoteRecord, localRecord) {
|
|
|
687
761
|
if (!localRecord || typeof localRecord !== "object") return true;
|
|
688
762
|
return shouldReplaceWithHybridRecord(remoteRecord, localRecord);
|
|
689
763
|
}
|
|
764
|
+
function parseSyncServersEnv(env) {
|
|
765
|
+
const raw = env?.NOLO_SYNC_SERVERS?.trim();
|
|
766
|
+
if (!raw) return [];
|
|
767
|
+
return raw.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
768
|
+
}
|
|
690
769
|
function createHybridRecordStore(deps) {
|
|
691
770
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
692
771
|
return {
|
|
@@ -1124,11 +1203,185 @@ async function executeLocalToolWithPolicy(args) {
|
|
|
1124
1203
|
}
|
|
1125
1204
|
|
|
1126
1205
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
1127
|
-
import { existsSync } from "node:fs";
|
|
1206
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1128
1207
|
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
1129
1208
|
import { dirname, relative, resolve, sep } from "node:path";
|
|
1130
1209
|
import { spawnSync, spawn as spawnChildProcess } from "node:child_process";
|
|
1131
1210
|
|
|
1211
|
+
// packages/agent-runtime/runtimeCompat.ts
|
|
1212
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
1213
|
+
import { join } from "node:path";
|
|
1214
|
+
import { spawn } from "node:child_process";
|
|
1215
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
1216
|
+
function isExecutableFile(candidate) {
|
|
1217
|
+
if (!existsSync(candidate)) return false;
|
|
1218
|
+
try {
|
|
1219
|
+
return statSync(candidate).isFile();
|
|
1220
|
+
} catch {
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
function resolveExecutableOnPath(name) {
|
|
1225
|
+
if (IS_WINDOWS && !/\.[a-z]+$/i.test(name)) {
|
|
1226
|
+
const exts = (process.env.PATHEXT || ".EXE;.CMD;.BAT").split(";").filter(Boolean);
|
|
1227
|
+
for (const ext of exts) {
|
|
1228
|
+
const found = resolveExecutableOnPath(name + ext);
|
|
1229
|
+
if (found) return found;
|
|
1230
|
+
}
|
|
1231
|
+
return null;
|
|
1232
|
+
}
|
|
1233
|
+
const pathEnv = process.env.PATH ?? "";
|
|
1234
|
+
const sep2 = pathEnv.includes(";") && IS_WINDOWS ? ";" : ":";
|
|
1235
|
+
const pathDirs = pathEnv.split(sep2).filter(Boolean);
|
|
1236
|
+
const fallbackDirs = IS_WINDOWS ? [] : [
|
|
1237
|
+
"/opt/homebrew/bin",
|
|
1238
|
+
"/usr/local/bin",
|
|
1239
|
+
"/usr/bin",
|
|
1240
|
+
"/bin",
|
|
1241
|
+
`${process.env.HOME ?? ""}/.local/bin`
|
|
1242
|
+
].filter(Boolean);
|
|
1243
|
+
for (const dir of [...pathDirs, ...fallbackDirs]) {
|
|
1244
|
+
const candidate = join(dir, name);
|
|
1245
|
+
if (isExecutableFile(candidate)) return candidate;
|
|
1246
|
+
}
|
|
1247
|
+
return null;
|
|
1248
|
+
}
|
|
1249
|
+
function createGlob(pattern) {
|
|
1250
|
+
const regex = globToRegExp(pattern);
|
|
1251
|
+
return {
|
|
1252
|
+
match(path) {
|
|
1253
|
+
return regex.test(path);
|
|
1254
|
+
},
|
|
1255
|
+
scanSync(opts) {
|
|
1256
|
+
const dot = opts.dot ?? false;
|
|
1257
|
+
const results = [];
|
|
1258
|
+
walkDir(opts.cwd, "", dot, results);
|
|
1259
|
+
return results.filter((rel) => regex.test(rel));
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
function walkDir(dir, prefix, dot, out) {
|
|
1264
|
+
let entries;
|
|
1265
|
+
try {
|
|
1266
|
+
entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
|
|
1267
|
+
} catch {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
for (const entry of entries) {
|
|
1271
|
+
const name = String(entry.name);
|
|
1272
|
+
if (!dot && name.startsWith(".")) continue;
|
|
1273
|
+
const rel = prefix ? `${prefix}/${name}` : name;
|
|
1274
|
+
const full = join(dir, name);
|
|
1275
|
+
if (entry.isDirectory()) {
|
|
1276
|
+
walkDir(full, rel, dot, out);
|
|
1277
|
+
} else if (entry.isFile()) {
|
|
1278
|
+
out.push(rel);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
function globToRegExp(pattern) {
|
|
1283
|
+
const trailingDir = pattern.endsWith("/");
|
|
1284
|
+
const src = trailingDir ? pattern.slice(0, -1) : pattern;
|
|
1285
|
+
const anchored = src.startsWith("/");
|
|
1286
|
+
const body = anchored ? src.slice(1) : src;
|
|
1287
|
+
let regex = "^";
|
|
1288
|
+
if (!anchored) regex += "(?:.*/)?";
|
|
1289
|
+
regex += convertBody(body);
|
|
1290
|
+
if (trailingDir) {
|
|
1291
|
+
regex += "(?:/.*)?";
|
|
1292
|
+
}
|
|
1293
|
+
regex += "$";
|
|
1294
|
+
return new RegExp(regex);
|
|
1295
|
+
}
|
|
1296
|
+
function convertBody(p) {
|
|
1297
|
+
let out = "";
|
|
1298
|
+
let i = 0;
|
|
1299
|
+
while (i < p.length) {
|
|
1300
|
+
const c = p[i];
|
|
1301
|
+
if (c === "*") {
|
|
1302
|
+
if (p[i + 1] === "*") {
|
|
1303
|
+
i += 2;
|
|
1304
|
+
if (p[i] === "/") {
|
|
1305
|
+
out += "(?:.*/)?";
|
|
1306
|
+
i += 1;
|
|
1307
|
+
} else {
|
|
1308
|
+
out += ".*";
|
|
1309
|
+
}
|
|
1310
|
+
} else {
|
|
1311
|
+
out += "[^/]*";
|
|
1312
|
+
i += 1;
|
|
1313
|
+
}
|
|
1314
|
+
} else if (c === "?") {
|
|
1315
|
+
out += "[^/]";
|
|
1316
|
+
i += 1;
|
|
1317
|
+
} else if (c === "[") {
|
|
1318
|
+
out += "[";
|
|
1319
|
+
i += 1;
|
|
1320
|
+
if (p[i] === "!") {
|
|
1321
|
+
out += "^";
|
|
1322
|
+
i += 1;
|
|
1323
|
+
}
|
|
1324
|
+
while (i < p.length && p[i] !== "]") {
|
|
1325
|
+
out += p[i] === "\\" ? "\\\\" : p[i];
|
|
1326
|
+
i += 1;
|
|
1327
|
+
}
|
|
1328
|
+
if (p[i] === "]") {
|
|
1329
|
+
out += "]";
|
|
1330
|
+
i += 1;
|
|
1331
|
+
}
|
|
1332
|
+
} else if (c === "{") {
|
|
1333
|
+
let depth = 1;
|
|
1334
|
+
let j = i + 1;
|
|
1335
|
+
let bodyStr = "";
|
|
1336
|
+
while (j < p.length && depth > 0) {
|
|
1337
|
+
if (p[j] === "{") depth += 1;
|
|
1338
|
+
else if (p[j] === "}") depth -= 1;
|
|
1339
|
+
if (depth > 0) bodyStr += p[j];
|
|
1340
|
+
j += 1;
|
|
1341
|
+
}
|
|
1342
|
+
const alts = bodyStr.split(",").map((alt) => convertBody(alt));
|
|
1343
|
+
out += `(?:${alts.join("|")})`;
|
|
1344
|
+
i = j;
|
|
1345
|
+
} else {
|
|
1346
|
+
out += escapeRegexChar(c);
|
|
1347
|
+
i += 1;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
return out;
|
|
1351
|
+
}
|
|
1352
|
+
function escapeRegexChar(c) {
|
|
1353
|
+
if ("\\^$.|+()".includes(c)) {
|
|
1354
|
+
return `\\${c}`;
|
|
1355
|
+
}
|
|
1356
|
+
return c;
|
|
1357
|
+
}
|
|
1358
|
+
function spawnToWebStreams(options) {
|
|
1359
|
+
const [command, ...args] = options.cmd;
|
|
1360
|
+
const child = spawn(command, args, {
|
|
1361
|
+
env: options.env,
|
|
1362
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1363
|
+
});
|
|
1364
|
+
const exited = new Promise((resolve2) => {
|
|
1365
|
+
child.on("exit", (code) => resolve2(code ?? 1));
|
|
1366
|
+
child.on("error", () => resolve2(127));
|
|
1367
|
+
});
|
|
1368
|
+
const toWeb = (stream) => {
|
|
1369
|
+
if (!stream) return null;
|
|
1370
|
+
return stream.toWeb?.() ?? new ReadableStream({
|
|
1371
|
+
start(controller) {
|
|
1372
|
+
stream.on("data", (chunk) => controller.enqueue(new Uint8Array(chunk)));
|
|
1373
|
+
stream.on("end", () => controller.close());
|
|
1374
|
+
stream.on("error", (e) => controller.error(e));
|
|
1375
|
+
}
|
|
1376
|
+
});
|
|
1377
|
+
};
|
|
1378
|
+
return {
|
|
1379
|
+
stdout: toWeb(child.stdout),
|
|
1380
|
+
stderr: toWeb(child.stderr),
|
|
1381
|
+
exited
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1132
1385
|
// packages/agent-runtime/processRegistry.ts
|
|
1133
1386
|
var ProcessRegistry = class {
|
|
1134
1387
|
processes = /* @__PURE__ */ new Map();
|
|
@@ -1228,7 +1481,8 @@ function tokenizeShellPrefix(command) {
|
|
|
1228
1481
|
function buildWorkspacePathProperty() {
|
|
1229
1482
|
return {
|
|
1230
1483
|
type: "string",
|
|
1231
|
-
|
|
1484
|
+
minLength: 1,
|
|
1485
|
+
description: "Path relative to the workspace root. Required and must be non-empty for readFile/writeFile/editFile; for listFiles/searchFiles/globFiles it is optional and defaults to the workspace root when omitted."
|
|
1232
1486
|
};
|
|
1233
1487
|
}
|
|
1234
1488
|
function buildListWorkspaceDescription(variant) {
|
|
@@ -1236,12 +1490,12 @@ function buildListWorkspaceDescription(variant) {
|
|
|
1236
1490
|
return "List files and directories inside a workspace directory.";
|
|
1237
1491
|
}
|
|
1238
1492
|
if (variant === "workflow") {
|
|
1239
|
-
return "List
|
|
1493
|
+
return "List directory overview inside workspace. Then use globFiles for path patterns, searchFiles for text discovery, and readFile for content.";
|
|
1240
1494
|
}
|
|
1241
1495
|
if (variant === "antiShell") {
|
|
1242
|
-
return "List
|
|
1496
|
+
return "List directory overview inside workspace. Prefer listFiles over shell ls/find commands.";
|
|
1243
1497
|
}
|
|
1244
|
-
return "List
|
|
1498
|
+
return "List files and directories inside a workspace folder. Defaults to shallow overview (depth 1).";
|
|
1245
1499
|
}
|
|
1246
1500
|
function buildListWorkspaceParameters(variant) {
|
|
1247
1501
|
const path = buildWorkspacePathProperty();
|
|
@@ -1298,18 +1552,18 @@ function buildReadWorkspaceDescription(variant) {
|
|
|
1298
1552
|
return "Read a UTF-8 text file inside the workspace.";
|
|
1299
1553
|
}
|
|
1300
1554
|
if (variant === "workflow") {
|
|
1301
|
-
return 'Read a UTF-8 text file inside the workspace
|
|
1555
|
+
return 'Read a UTF-8 text file inside the workspace. Use lines with a range from searchFiles matches, or lines: "-50" for logs. Read the whole file only when the task needs all content.';
|
|
1302
1556
|
}
|
|
1303
1557
|
if (variant === "antiShell") {
|
|
1304
|
-
return "Read a UTF-8 text file inside the workspace.
|
|
1558
|
+
return "Read a UTF-8 text file inside the workspace. Prefer readFile over shell commands (cat/head/tail).";
|
|
1305
1559
|
}
|
|
1306
|
-
return "Read a UTF-8 text file inside the workspace.
|
|
1560
|
+
return "Read a UTF-8 text file inside the workspace. Use lines for focused range reads after searchFiles to save tokens.";
|
|
1307
1561
|
}
|
|
1308
1562
|
function buildReadWorkspaceParameters(variant) {
|
|
1309
1563
|
const path = buildWorkspacePathProperty();
|
|
1310
1564
|
const lines = {
|
|
1311
1565
|
type: "string",
|
|
1312
|
-
description: '
|
|
1566
|
+
description: 'Line slice: "40-120" (range, 1-based, inclusive), "120-" (from line to end), "-50" (tail N lines), "50" (head N lines). Omit to read full file.'
|
|
1313
1567
|
};
|
|
1314
1568
|
if (variant === "minimal") {
|
|
1315
1569
|
return {
|
|
@@ -1339,7 +1593,7 @@ function buildWriteWorkspaceFileTool() {
|
|
|
1339
1593
|
type: "function",
|
|
1340
1594
|
function: {
|
|
1341
1595
|
name: "writeFile",
|
|
1342
|
-
description: "Write full UTF-8 file content inside the workspace
|
|
1596
|
+
description: "Write full UTF-8 file content inside the workspace (new files or whole-file rewrites). Prefer editFile for targeted edits.",
|
|
1343
1597
|
parameters: {
|
|
1344
1598
|
type: "object",
|
|
1345
1599
|
properties: {
|
|
@@ -1359,7 +1613,7 @@ function buildReplaceWorkspaceTextTool() {
|
|
|
1359
1613
|
type: "function",
|
|
1360
1614
|
function: {
|
|
1361
1615
|
name: "editFile",
|
|
1362
|
-
description: "
|
|
1616
|
+
description: "Replace exact text occurrences in a workspace file. If expected replacement count fails, report the error instead of falling back to a whole-file rewrite.",
|
|
1363
1617
|
parameters: {
|
|
1364
1618
|
type: "object",
|
|
1365
1619
|
properties: {
|
|
@@ -1387,35 +1641,35 @@ function buildSearchWorkspaceDescription(variant) {
|
|
|
1387
1641
|
return "Search workspace file contents.";
|
|
1388
1642
|
}
|
|
1389
1643
|
if (variant === "workflow") {
|
|
1390
|
-
return "Search file contents inside
|
|
1644
|
+
return "Search file contents inside workspace. Returns line numbers; use readFile with line ranges for focused reading.";
|
|
1391
1645
|
}
|
|
1392
1646
|
if (variant === "antiShell") {
|
|
1393
|
-
return "Search text inside workspace files
|
|
1647
|
+
return "Search text inside workspace files using ripgrep. Prefer searchFiles over shell grep.";
|
|
1394
1648
|
}
|
|
1395
|
-
return "Search file contents inside the
|
|
1649
|
+
return "Search file contents inside the workspace using ripgrep. Returns matching lines and line numbers. Prefer globFiles when only finding file paths.";
|
|
1396
1650
|
}
|
|
1397
1651
|
function buildSearchWorkspaceParameters(variant) {
|
|
1398
1652
|
const query = {
|
|
1399
1653
|
type: "string",
|
|
1400
|
-
description: "Search query
|
|
1654
|
+
description: "Search query (regex or literal string)."
|
|
1401
1655
|
};
|
|
1402
1656
|
const path = buildWorkspacePathProperty();
|
|
1403
1657
|
const includeIgnored = {
|
|
1404
1658
|
type: "boolean",
|
|
1405
|
-
description: "When true, search files
|
|
1659
|
+
description: "When true, search gitignored files. Build artifacts (dist/, node_modules, .git) remain excluded."
|
|
1406
1660
|
};
|
|
1407
1661
|
const exclude = {
|
|
1408
1662
|
type: "array",
|
|
1409
1663
|
items: { type: "string" },
|
|
1410
|
-
description: "Glob patterns to exclude from content search
|
|
1664
|
+
description: "Glob patterns to exclude from content search (e.g. ['dist/**', '*.log'])."
|
|
1411
1665
|
};
|
|
1412
1666
|
const maxResults = {
|
|
1413
1667
|
type: "integer",
|
|
1414
|
-
description: "
|
|
1668
|
+
description: "Max matching output lines to return."
|
|
1415
1669
|
};
|
|
1416
1670
|
const literal = {
|
|
1417
1671
|
type: "boolean",
|
|
1418
|
-
description: "When true, search
|
|
1672
|
+
description: "When true, search query as literal text instead of regex."
|
|
1419
1673
|
};
|
|
1420
1674
|
const caseSensitive = {
|
|
1421
1675
|
type: "boolean",
|
|
@@ -1423,7 +1677,7 @@ function buildSearchWorkspaceParameters(variant) {
|
|
|
1423
1677
|
};
|
|
1424
1678
|
const contextLines = {
|
|
1425
1679
|
type: "integer",
|
|
1426
|
-
description: "Number of surrounding context lines
|
|
1680
|
+
description: "Number of surrounding context lines around each match. Defaults to 0."
|
|
1427
1681
|
};
|
|
1428
1682
|
if (variant === "minimal") {
|
|
1429
1683
|
return {
|
|
@@ -1474,31 +1728,31 @@ function buildGlobWorkspaceDescription(variant) {
|
|
|
1474
1728
|
return "Find workspace files by path glob without reading file contents.";
|
|
1475
1729
|
}
|
|
1476
1730
|
if (variant === "workflow") {
|
|
1477
|
-
return "Find files by glob pattern
|
|
1731
|
+
return "Find files by glob pattern. Use searchFiles for text inside candidates, and readFile for specific paths.";
|
|
1478
1732
|
}
|
|
1479
1733
|
if (variant === "antiShell") {
|
|
1480
|
-
return "Find workspace files by path glob
|
|
1734
|
+
return "Find workspace files by path glob. Prefer globFiles over shell find/ls commands.";
|
|
1481
1735
|
}
|
|
1482
|
-
return "Find
|
|
1736
|
+
return "Find file paths by glob pattern without reading file contents. Use brace groups (e.g. '**/*.{ts,tsx}') to match multiple patterns in one call.";
|
|
1483
1737
|
}
|
|
1484
1738
|
function buildGlobWorkspaceParameters(variant) {
|
|
1485
1739
|
const pattern = {
|
|
1486
1740
|
type: "string",
|
|
1487
|
-
description: "Glob pattern for files
|
|
1741
|
+
description: "Glob pattern for files (supports brace groups like '**/*.{ts,tsx}', '**/{package.json,tsconfig*.json}')."
|
|
1488
1742
|
};
|
|
1489
1743
|
const path = buildWorkspacePathProperty();
|
|
1490
1744
|
const includeIgnored = {
|
|
1491
1745
|
type: "boolean",
|
|
1492
|
-
description: "When true, include files
|
|
1746
|
+
description: "When true, include gitignored files (.git and node_modules remain excluded)."
|
|
1493
1747
|
};
|
|
1494
1748
|
const maxResults = {
|
|
1495
1749
|
type: "integer",
|
|
1496
|
-
description: "
|
|
1750
|
+
description: "Max file paths to return."
|
|
1497
1751
|
};
|
|
1498
1752
|
const exclude = {
|
|
1499
1753
|
type: "array",
|
|
1500
1754
|
items: { type: "string" },
|
|
1501
|
-
description: "Glob patterns to exclude from results
|
|
1755
|
+
description: "Glob patterns to exclude from results."
|
|
1502
1756
|
};
|
|
1503
1757
|
if (variant === "minimal") {
|
|
1504
1758
|
return {
|
|
@@ -1526,7 +1780,7 @@ function buildGlobWorkspaceParameters(variant) {
|
|
|
1526
1780
|
pattern,
|
|
1527
1781
|
glob: {
|
|
1528
1782
|
type: "string",
|
|
1529
|
-
description: "Alias for pattern, kept for compatibility
|
|
1783
|
+
description: "Alias for pattern, kept for compatibility."
|
|
1530
1784
|
},
|
|
1531
1785
|
path,
|
|
1532
1786
|
exclude,
|
|
@@ -1597,17 +1851,17 @@ function buildExecShellTool(toolName) {
|
|
|
1597
1851
|
type: "function",
|
|
1598
1852
|
function: {
|
|
1599
1853
|
name: toolName,
|
|
1600
|
-
description:
|
|
1854
|
+
description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification instead of multiple small roundtrips. Do not cd into guessed paths (e.g. /workspace, /repo, /home/user); commands already run from the workspace root. Use portable POSIX commands for macOS/BSD shells; do not use cat -A or brittle byte-offset tools such as xxd -s -32. For text-file content or trailing-newline checks, prefer readFile over shell byte inspection. After a successful command returned the needed status/commit info, do not run repeated git status/log/rev-parse checks; use one final verification command. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess.`,
|
|
1601
1855
|
parameters: {
|
|
1602
1856
|
type: "object",
|
|
1603
1857
|
properties: {
|
|
1604
1858
|
cmd: {
|
|
1605
1859
|
type: "string",
|
|
1606
|
-
description: "Shell command to run."
|
|
1860
|
+
description: "Shell command to run. Must be a non-empty command string \u2014 never pass an empty string, whitespace-only text, or null."
|
|
1607
1861
|
},
|
|
1608
1862
|
command: {
|
|
1609
1863
|
type: "string",
|
|
1610
|
-
description: "Shell command to run."
|
|
1864
|
+
description: "Shell command to run. Compatibility field for providers that model the command under this name; the executor reads cmd first, then falls back to command. Must also be non-empty when used."
|
|
1611
1865
|
}
|
|
1612
1866
|
}
|
|
1613
1867
|
}
|
|
@@ -1619,7 +1873,7 @@ function buildLaunchProcessTool() {
|
|
|
1619
1873
|
type: "function",
|
|
1620
1874
|
function: {
|
|
1621
1875
|
name: "launchProcess",
|
|
1622
|
-
description: "
|
|
1876
|
+
description: "Start a long-running background process (dev server, watcher, REPL) and return immediately with {pid, label, status}. Use listProcesses to inspect or stop it.",
|
|
1623
1877
|
parameters: {
|
|
1624
1878
|
type: "object",
|
|
1625
1879
|
properties: {
|
|
@@ -1633,7 +1887,7 @@ function buildLaunchProcessTool() {
|
|
|
1633
1887
|
},
|
|
1634
1888
|
persist: {
|
|
1635
1889
|
type: "boolean",
|
|
1636
|
-
description: "
|
|
1890
|
+
description: "Keep process alive after session/conversation closes. Defaults to false."
|
|
1637
1891
|
}
|
|
1638
1892
|
},
|
|
1639
1893
|
required: ["command"]
|
|
@@ -1646,7 +1900,7 @@ function buildListProcessesTool() {
|
|
|
1646
1900
|
type: "function",
|
|
1647
1901
|
function: {
|
|
1648
1902
|
name: "listProcesses",
|
|
1649
|
-
description: "List
|
|
1903
|
+
description: "List active background processes launched via launchProcess. Returns {pid, label, command, status, startedAt, persist}[].",
|
|
1650
1904
|
parameters: {
|
|
1651
1905
|
type: "object",
|
|
1652
1906
|
properties: {}
|
|
@@ -2037,7 +2291,7 @@ function isPathInsideWorkspace(args) {
|
|
|
2037
2291
|
const relativePath = relative(args.workspaceRoot, args.targetPath);
|
|
2038
2292
|
return relativePath === "" || !relativePath.startsWith("..") && !relativePath.includes(`..${sep}`);
|
|
2039
2293
|
}
|
|
2040
|
-
var PATH_FIELD_ALIASES = ["path", "file_path", "filePath", "filename", "file", "target_file", "targetFile", "file_to_read", "fileToRead"];
|
|
2294
|
+
var PATH_FIELD_ALIASES = ["path", "file_path", "filePath", "filename", "file", "target_file", "targetFile", "file_to_read", "fileToRead", "target_path", "read_path", "path_to_read", "pathToRead"];
|
|
2041
2295
|
var OLD_TEXT_FIELD_ALIASES = ["oldText", "old_string", "oldString", "search", "search_string", "find", "match"];
|
|
2042
2296
|
var NEW_TEXT_FIELD_ALIASES = ["newText", "new_string", "newString", "replacement", "replace"];
|
|
2043
2297
|
var SEARCH_QUERY_FIELD_ALIASES = ["query", "search_query", "searchQuery", "q", "pattern", "search"];
|
|
@@ -2494,7 +2748,7 @@ function resolveRipgrepBinary(env = process.env) {
|
|
|
2494
2748
|
const fromEnv = asOptionalTrimmedString(env.NOLO_BUNDLED_RG);
|
|
2495
2749
|
if (fromEnv) {
|
|
2496
2750
|
try {
|
|
2497
|
-
if (
|
|
2751
|
+
if (existsSync2(fromEnv)) return fromEnv;
|
|
2498
2752
|
} catch {
|
|
2499
2753
|
}
|
|
2500
2754
|
}
|
|
@@ -2801,6 +3055,48 @@ async function resolveLocalWorkspaceToolPath(args) {
|
|
|
2801
3055
|
}
|
|
2802
3056
|
return targetPath;
|
|
2803
3057
|
}
|
|
3058
|
+
var READ_FILE_MAX_CHAR_LIMIT = 32e3;
|
|
3059
|
+
function defensivelyTruncateReadFile(args) {
|
|
3060
|
+
const limit = args.limit ?? READ_FILE_MAX_CHAR_LIMIT;
|
|
3061
|
+
if (args.content.length <= limit) {
|
|
3062
|
+
return { content: args.content, truncatedByCharLimit: false };
|
|
3063
|
+
}
|
|
3064
|
+
const maxBudget = Math.floor(limit * 0.4);
|
|
3065
|
+
const lines = splitTextLines(args.content);
|
|
3066
|
+
if (lines.length <= 10) {
|
|
3067
|
+
const head2 = args.content.slice(0, maxBudget);
|
|
3068
|
+
const tail2 = args.content.slice(-maxBudget);
|
|
3069
|
+
const omitted = args.content.length - head2.length - tail2.length;
|
|
3070
|
+
return {
|
|
3071
|
+
content: `${head2}
|
|
3072
|
+
|
|
3073
|
+
[... ${omitted} characters omitted. Content exceeds limit (${args.content.length} chars). Use lines slice or searchFiles to inspect specific parts. ...]
|
|
3074
|
+
|
|
3075
|
+
${tail2}`,
|
|
3076
|
+
truncatedByCharLimit: true
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
const headLinesCount = Math.min(150, Math.floor(lines.length * 0.4));
|
|
3080
|
+
const tailLinesCount = Math.min(50, Math.floor(lines.length * 0.2));
|
|
3081
|
+
let head = lines.slice(0, headLinesCount).join("\n");
|
|
3082
|
+
let tail = lines.slice(-tailLinesCount).join("\n");
|
|
3083
|
+
if (head.length > maxBudget) {
|
|
3084
|
+
head = head.slice(0, maxBudget);
|
|
3085
|
+
}
|
|
3086
|
+
if (tail.length > maxBudget) {
|
|
3087
|
+
tail = tail.slice(-maxBudget);
|
|
3088
|
+
}
|
|
3089
|
+
const omittedLines = lines.length - headLinesCount - tailLinesCount;
|
|
3090
|
+
const omittedChars = args.content.length - head.length - tail.length;
|
|
3091
|
+
return {
|
|
3092
|
+
content: `${head}
|
|
3093
|
+
|
|
3094
|
+
[... Omitted ${Math.max(1, omittedLines)} lines (${omittedChars} chars). File exceeds safety limit (${args.content.length} chars, ${args.totalLines} lines). Use lines="start-end" (e.g. lines="151-300") or searchFiles to read specific sections. ...]
|
|
3095
|
+
|
|
3096
|
+
${tail}`,
|
|
3097
|
+
truncatedByCharLimit: true
|
|
3098
|
+
};
|
|
3099
|
+
}
|
|
2804
3100
|
async function readFileTool(args) {
|
|
2805
3101
|
const parsed = parseWorkspaceToolArguments(args.call.arguments);
|
|
2806
3102
|
const requestedPath = requireWorkspaceToolPath(parsed);
|
|
@@ -2816,19 +3112,25 @@ async function readFileTool(args) {
|
|
|
2816
3112
|
content,
|
|
2817
3113
|
...sliceArgs
|
|
2818
3114
|
});
|
|
2819
|
-
|
|
3115
|
+
const truncatedRead = defensivelyTruncateReadFile({
|
|
2820
3116
|
content: sliced.content,
|
|
3117
|
+
totalLines: sliced.totalLines
|
|
3118
|
+
});
|
|
3119
|
+
const isTruncated = sliced.truncated || truncatedRead.truncatedByCharLimit;
|
|
3120
|
+
return {
|
|
3121
|
+
content: truncatedRead.content,
|
|
2821
3122
|
metadata: {
|
|
2822
3123
|
path: normalizeWorkspaceRelativePath({
|
|
2823
3124
|
workspaceRoot: resolve(args.workspaceRoot),
|
|
2824
3125
|
targetPath: absolutePath
|
|
2825
3126
|
}),
|
|
2826
|
-
bytes: Buffer.byteLength(
|
|
3127
|
+
bytes: Buffer.byteLength(truncatedRead.content),
|
|
2827
3128
|
totalBytes: Buffer.byteLength(content),
|
|
2828
3129
|
startLine: sliced.startLine,
|
|
2829
3130
|
endLine: sliced.endLine,
|
|
2830
3131
|
totalLines: sliced.totalLines,
|
|
2831
|
-
truncated:
|
|
3132
|
+
truncated: isTruncated,
|
|
3133
|
+
...truncatedRead.truncatedByCharLimit ? { truncatedByByteLimit: true, truncatedByCharLimit: true } : {},
|
|
2832
3134
|
...sliceArgs.maxLines ? { maxLines: sliceArgs.maxLines } : {},
|
|
2833
3135
|
...sliceArgs.tailLines ? { tailLines: sliceArgs.tailLines } : {},
|
|
2834
3136
|
...warnings.length ? { warnings: [...warnings, buildReadFileSliceHint(sliced.totalLines)] } : {},
|
|
@@ -3656,7 +3958,119 @@ function createLocalWorkspaceToolExecutors(args) {
|
|
|
3656
3958
|
};
|
|
3657
3959
|
}
|
|
3658
3960
|
|
|
3961
|
+
// packages/agent-runtime/noloWorkspaceTools.node.ts
|
|
3962
|
+
async function readNoloProcessStream(readable) {
|
|
3963
|
+
if (!readable) return "";
|
|
3964
|
+
return new Response(readable).text();
|
|
3965
|
+
}
|
|
3966
|
+
async function runNoloWorkspaceCliTool(call, args) {
|
|
3967
|
+
const cliArgs = buildNoloWorkspaceCommandArgs(call);
|
|
3968
|
+
const bunSpawn = globalThis.Bun?.spawn;
|
|
3969
|
+
const spawn2 = args.spawn ?? (typeof bunSpawn === "function" ? bunSpawn : nodeSpawnFallback);
|
|
3970
|
+
const execPath = args.processExecPath ?? process.execPath;
|
|
3971
|
+
const entrypoint = args.cliEntrypoint;
|
|
3972
|
+
const cmd = entrypoint && entrypoint !== execPath ? [execPath, entrypoint, ...cliArgs] : [execPath, ...cliArgs];
|
|
3973
|
+
const proc = spawn2({
|
|
3974
|
+
cmd,
|
|
3975
|
+
stdout: "pipe",
|
|
3976
|
+
stderr: "pipe",
|
|
3977
|
+
env: args.env
|
|
3978
|
+
});
|
|
3979
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
3980
|
+
readNoloProcessStream(proc.stdout),
|
|
3981
|
+
readNoloProcessStream(proc.stderr),
|
|
3982
|
+
proc.exited
|
|
3983
|
+
]);
|
|
3984
|
+
const content = `${stdout}${stderr}`;
|
|
3985
|
+
if (exitCode !== 0) {
|
|
3986
|
+
throw new Error(content.trim() || `nolo ${cliArgs.join(" ")} exited ${exitCode}`);
|
|
3987
|
+
}
|
|
3988
|
+
return {
|
|
3989
|
+
content,
|
|
3990
|
+
metadata: {
|
|
3991
|
+
[args.metadataKind ?? "noloWorkspaceTool"]: true,
|
|
3992
|
+
command: ["nolo", ...cliArgs].join(" "),
|
|
3993
|
+
exitCode
|
|
3994
|
+
}
|
|
3995
|
+
};
|
|
3996
|
+
}
|
|
3997
|
+
function buildNoloWorkspaceCliToolExecutors(args) {
|
|
3998
|
+
const executors = {};
|
|
3999
|
+
for (const toolName of NOLO_WORKSPACE_TOOL_NAMES) {
|
|
4000
|
+
if (toolName === "loadSkill") continue;
|
|
4001
|
+
executors[toolName] = (call) => runNoloWorkspaceCliTool(call, args);
|
|
4002
|
+
}
|
|
4003
|
+
return executors;
|
|
4004
|
+
}
|
|
4005
|
+
var nodeSpawnFallback = (options) => {
|
|
4006
|
+
return spawnToWebStreams({ cmd: options.cmd, env: options.env });
|
|
4007
|
+
};
|
|
4008
|
+
function buildLoadSkillExecutor(args) {
|
|
4009
|
+
return async (call) => {
|
|
4010
|
+
const parsed = parseNoloWorkspaceToolArguments(call.arguments);
|
|
4011
|
+
const name = noloStringArg(parsed.name ?? parsed.skillName ?? parsed.skill);
|
|
4012
|
+
if (!name) {
|
|
4013
|
+
return {
|
|
4014
|
+
content: await formatUnknownSkillMessage(args.cwd, "(no name provided)"),
|
|
4015
|
+
metadata: { loadSkill: true, resolved: false }
|
|
4016
|
+
};
|
|
4017
|
+
}
|
|
4018
|
+
const { resolveSkillByName } = await import("./skillDiscovery-KJWT7JBU.js");
|
|
4019
|
+
const resolved = resolveSkillByName(args.cwd, name);
|
|
4020
|
+
if (!resolved) {
|
|
4021
|
+
const { resolveCodingBuiltinSlug, buildCodingSkillContentBySlug } = await import("./codingSkills-EN6Z6G6U.js");
|
|
4022
|
+
const builtinSlug = resolveCodingBuiltinSlug(name);
|
|
4023
|
+
if (builtinSlug) {
|
|
4024
|
+
const body = buildCodingSkillContentBySlug(builtinSlug);
|
|
4025
|
+
return {
|
|
4026
|
+
content: `Skill "${name}" loaded inline. Follow its instructions.
|
|
4027
|
+
|
|
4028
|
+
${body}`,
|
|
4029
|
+
metadata: { loadSkill: true, resolved: true, name, requestedName: name, builtin: true }
|
|
4030
|
+
};
|
|
4031
|
+
}
|
|
4032
|
+
return {
|
|
4033
|
+
content: await formatUnknownSkillMessage(args.cwd, name),
|
|
4034
|
+
metadata: { loadSkill: true, resolved: false, name, requestedName: name }
|
|
4035
|
+
};
|
|
4036
|
+
}
|
|
4037
|
+
try {
|
|
4038
|
+
const { readFileSync } = await import("node:fs");
|
|
4039
|
+
const body = readFileSync(resolved, "utf8");
|
|
4040
|
+
return {
|
|
4041
|
+
content: `Skill "${name}" loaded inline. Follow its instructions.
|
|
4042
|
+
|
|
4043
|
+
${body}`,
|
|
4044
|
+
metadata: { loadSkill: true, resolved: true, name, requestedName: name, path: resolved }
|
|
4045
|
+
};
|
|
4046
|
+
} catch (err) {
|
|
4047
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4048
|
+
return {
|
|
4049
|
+
content: `Skill "${name}" could not be read: ${message}`,
|
|
4050
|
+
metadata: { loadSkill: true, resolved: true, name, requestedName: name, path: resolved, readError: message }
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
};
|
|
4054
|
+
}
|
|
4055
|
+
async function formatUnknownSkillMessage(cwd, requestedName) {
|
|
4056
|
+
const { discoverSkills } = await import("./skillDiscovery-KJWT7JBU.js");
|
|
4057
|
+
let available = [];
|
|
4058
|
+
try {
|
|
4059
|
+
available = discoverSkills(cwd).map((s) => s.name);
|
|
4060
|
+
} catch {
|
|
4061
|
+
}
|
|
4062
|
+
const header = `Skill "${requestedName}" not found in this workspace's skill directory (.agents/skills/<name>/SKILL.md).`;
|
|
4063
|
+
if (available.length === 0) return `${header}
|
|
4064
|
+
|
|
4065
|
+
No skills were discovered in this workspace.`;
|
|
4066
|
+
return `${header}
|
|
4067
|
+
|
|
4068
|
+
Available skills: ${available.join(", ")}`;
|
|
4069
|
+
}
|
|
4070
|
+
|
|
3659
4071
|
export {
|
|
4072
|
+
resolveAgentNextAvailableAt,
|
|
4073
|
+
isAgentCoolingDown,
|
|
3660
4074
|
parseSseDataLineJson,
|
|
3661
4075
|
parseSseDataLineObject,
|
|
3662
4076
|
buildOpenAiCompatibleChatCompletionRequest,
|
|
@@ -3669,6 +4083,7 @@ export {
|
|
|
3669
4083
|
dialogMessageRecordToAgentRuntimeMessage,
|
|
3670
4084
|
buildAgentRuntimeDialogWritePlan,
|
|
3671
4085
|
shouldCacheHybridRemoteRecord,
|
|
4086
|
+
parseSyncServersEnv,
|
|
3672
4087
|
createHybridRecordStore,
|
|
3673
4088
|
isDestructiveShellCommand,
|
|
3674
4089
|
evaluateShellCommandPolicy,
|
|
@@ -3678,5 +4093,7 @@ export {
|
|
|
3678
4093
|
buildLocalWorkspaceToolset,
|
|
3679
4094
|
buildLocalWorkspacePolicyToolNames,
|
|
3680
4095
|
buildLocalWorkspaceOpenAiTools,
|
|
3681
|
-
createLocalWorkspaceToolExecutors
|
|
4096
|
+
createLocalWorkspaceToolExecutors,
|
|
4097
|
+
buildNoloWorkspaceCliToolExecutors,
|
|
4098
|
+
buildLoadSkillExecutor
|
|
3682
4099
|
};
|