nolo-cli 0.33.0-alpha.2 → 0.33.0-alpha.21
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/{_executeModel-RWPVI3YV.js → _executeModel-XKWVTZAY.js} +35 -34
- package/{action-SMLG6OTB.js → action-Q4KO7DDW.js} +4 -4
- package/{addContentAction-SFO244QN.js → addContentAction-FRXDZKSI.js} +3 -3
- package/{addDialogAgentAction-W44ZCEHB.js → addDialogAgentAction-XL5G3LPR.js} +2 -2
- package/{agentDeleteCommand-KU2RXQPP.js → agentDeleteCommand-ZU4H6F6M.js} +19 -18
- package/{agentEmailCommands-MPCMDENS.js → agentEmailCommands-6ULFXW4A.js} +41 -40
- package/{agentListCommands-EPD4N6FX.js → agentListCommands-VN7WCW7Z.js} +21 -20
- package/{agentMachineCommands-AF7C3YRT.js → agentMachineCommands-5PALVQBD.js} +21 -20
- package/{agentPullCommand-YH5GEBK4.js → agentPullCommand-TSWAJPS2.js} +1 -1
- package/{agentRecordCommands-EYE6MZZG.js → agentRecordCommands-XEB66KRX.js} +40 -39
- package/{agentRunCommand-LL22SGTN.js → agentRunCommand-OJX27NII.js} +42 -41
- package/{agentRuntimeLocal-JX34G47Z.js → agentRuntimeLocal-UWDOE55A.js} +20 -19
- package/{agentSlice-TNMFQQOV.js → agentSlice-SZRRJ3ZX.js} +5 -5
- package/{appDeleteCommands-43K5VXQB.js → appDeleteCommands-R63PZAY7.js} +20 -19
- package/{appDeployCommands-FEEJSVDZ.js → appDeployCommands-VNRT54YO.js} +20 -19
- package/{appDeployStatusCommands-H76CG45R.js → appDeployStatusCommands-6IPTKLEM.js} +20 -19
- package/{appGetCommands-MDZYFTYZ.js → appGetCommands-JPFVMVAI.js} +20 -19
- package/{appListCommands-TUJJXPWG.js → appListCommands-B3SLTPII.js} +20 -19
- package/{authCommand-T7UK4CWS.js → authCommand-EX5G5PF4.js} +12 -11
- package/{authCommands-EAPFGNHN.js → authCommands-VR6Q6GU2.js} +4 -4
- package/{chatQueueReduxAdapter-LVQXC4ZY.js → chatQueueReduxAdapter-IEX32ZVP.js} +15 -14
- package/{chunk-2H3XIBY4.js → chunk-2CNX3CJE.js} +4 -82
- package/{chunk-MPZJVZDC.js → chunk-2UDMTJOM.js} +9 -9
- package/{chunk-WHD6BG7M.js → chunk-37LDAHQN.js} +20 -18
- package/{chunk-2UECQ7RE.js → chunk-3AOLVADY.js} +1 -1
- package/{chunk-HUCT7HID.js → chunk-42IF53CR.js} +1 -1
- package/{chunk-AAGCMVFT.js → chunk-46JSKTPF.js} +189 -38
- package/{chunk-3WXRAHCG.js → chunk-6MSSX7FI.js} +1 -1
- package/{chunk-57QJXIB6.js → chunk-6YH4UR3E.js} +3 -3
- package/{chunk-HDKRSRYU.js → chunk-7BNPRRDS.js} +150 -29
- package/{chunk-FMEVI5TG.js → chunk-7CH6U3FL.js} +1 -1
- package/{chunk-OR2HNLVO.js → chunk-7EPNNOL4.js} +6 -6
- package/{chunk-PREQU5QV.js → chunk-7OGIWPNK.js} +1 -1
- package/{chunk-DFUPZE6V.js → chunk-7SLMYTSF.js} +1 -1
- package/{chunk-3GZXL6FM.js → chunk-AOWETAXX.js} +1 -1
- package/{chunk-2IVEXF7P.js → chunk-BHILFABL.js} +1 -1
- package/{chunk-TFPUAELY.js → chunk-DDET6246.js} +1 -1
- package/{chunk-ZURFOV5J.js → chunk-DMT4NJXR.js} +1 -1
- package/{chunk-RAZOLMJR.js → chunk-EQ6HOWEJ.js} +2 -2
- package/{chunk-6HYVJV7B.js → chunk-ESHYE7WU.js} +2 -1
- package/{chunk-JZ5AMMXU.js → chunk-FH7VUJN5.js} +2 -2
- package/{chunk-I6N2UVVY.js → chunk-FV63ICZC.js} +1 -1
- package/{chunk-U4TRT5V4.js → chunk-GEPHJJW4.js} +1 -1
- package/{chunk-VH2F7ZB6.js → chunk-GTEHJWXU.js} +1 -1
- package/{chunk-AOXVOC6D.js → chunk-HCOIKLSH.js} +2 -2
- package/{chunk-GTYM4HKV.js → chunk-IEHZHWN7.js} +2 -2
- package/{chunk-2QTEYCR7.js → chunk-JFUW3UTO.js} +1 -1
- package/{chunk-73GINUCW.js → chunk-JL2PUYVS.js} +102 -23
- package/{chunk-37V5LNEQ.js → chunk-KIL7V27H.js} +1 -1
- package/{chunk-JTSGWTYZ.js → chunk-KMMQFY5O.js} +1 -1
- package/{chunk-UK5JGQVU.js → chunk-KZB5SNYH.js} +9 -14
- package/{chunk-XCCGU6QB.js → chunk-L5XKDBSH.js} +1 -1
- package/{chunk-DPMBNHOJ.js → chunk-LAZTMWIU.js} +1 -1
- package/{chunk-M4NC7NF6.js → chunk-LJGEEYGC.js} +2 -2
- package/{chunk-B2BSG6QQ.js → chunk-LLKHGZME.js} +4 -4
- package/{chunk-7E72JMBB.js → chunk-N2WDGMD5.js} +45 -4
- package/{chunk-Q5ITEGIN.js → chunk-N4XRDM26.js} +1 -1
- package/{chunk-AFV4FOT2.js → chunk-OQVRTSZ5.js} +4 -91
- package/{chunk-3VAQHAXT.js → chunk-PU47HKTF.js} +11 -11
- package/{chunk-CLP2K7U4.js → chunk-QKCMP3LU.js} +2 -2
- package/{chunk-JZPBVBIY.js → chunk-QTZD6HBK.js} +18 -8
- package/{chunk-LOD75GOS.js → chunk-REOW4YJX.js} +80 -1099
- package/{chunk-6SXC35F4.js → chunk-RO3AEN3L.js} +5 -5
- package/{chunk-5CS33IBL.js → chunk-RQFO3CAF.js} +8 -9
- package/{chunk-GMXWYXAF.js → chunk-SBPGB6TF.js} +3 -3
- package/{chunk-FSSX3XRY.js → chunk-U2FRXKC7.js} +1 -1
- package/{chunk-NUO3QFWD.js → chunk-UNHKVD2N.js} +1 -1
- package/{chunk-GE6IWA5N.js → chunk-UNZDCI3O.js} +126 -1
- package/{chunk-JMPYDFHY.js → chunk-V44VE7R4.js} +2 -2
- package/{chunk-IL545V3E.js → chunk-V4MT7AEN.js} +1 -1
- package/{chunk-FXFGNOT2.js → chunk-VFVCYIRQ.js} +1 -1
- package/chunk-VIRTYWWE.js +97 -0
- package/{chunk-ZJMME4DS.js → chunk-XS543SNR.js} +5 -5
- package/{chunk-O6GEBMIY.js → chunk-XTSVOICC.js} +195 -47
- package/{chunk-6PO2SYCS.js → chunk-YH3FPBG6.js} +1569 -204
- package/{chunk-WLH5BAKX.js → chunk-YYTTDOWA.js} +2 -2
- package/{chunk-5SBK2MTI.js → chunk-ZKUATCEY.js} +20 -69
- package/{codingSkills-DY5MINPG.js → codingSkills-5VOV3JVB.js} +2 -2
- package/{createAgentAutomationAction-INQT23LX.js → createAgentAutomationAction-72NNXELT.js} +16 -15
- package/{createDialogAction-LDCPDI73.js → createDialogAction-3CJ2GXNO.js} +18 -17
- package/{createPageAction-5YXOG2M4.js → createPageAction-HZHQGQO6.js} +16 -15
- package/{dbSlice-3SD5L5H2.js → dbSlice-2YD2PZER.js} +2 -2
- package/{dialogCommands-CHJO47AX.js → dialogCommands-2BF4ZSWH.js} +18 -17
- package/{dialogSlice-DOWKOILN.js → dialogSlice-5R4O4377.js} +15 -14
- package/{docCreateCommands-OVZARUFX.js → docCreateCommands-HMZUBFGL.js} +19 -18
- package/{docDeleteCommands-E2XJ62LD.js → docDeleteCommands-DFR7GCOR.js} +19 -18
- package/{docReadCommands-I7OSREPJ.js → docReadCommands-YM7RDUAZ.js} +19 -18
- package/{docStore-UAWSKZ2Y.js → docStore-A4SRW2DJ.js} +17 -16
- package/{docUpdateCommands-X4Z26VJM.js → docUpdateCommands-TTQBD7IU.js} +19 -18
- package/{getPricing-L2ENXWHV.js → getPricing-J4VXWR5B.js} +3 -3
- package/{handleSendMessageAction-C3TSDWKH.js → handleSendMessageAction-CIFBZCI2.js} +15 -14
- package/index.js +70 -70
- package/{localRuntimeAuthority-E3R24J4T.js → localRuntimeAuthority-S77B5QVB.js} +6 -2
- package/{localRuntimeDb-DDZCJFQZ.js → localRuntimeDb-N3H3HQ7G.js} +1 -1
- package/{machineCommands-BUOIYJAD.js → machineCommands-QSW4JKR2.js} +40 -39
- package/{machineInfo-M6KB6HZN.js → machineInfo-66ZFUMLE.js} +1 -1
- package/{machineWsRunDispatch-7CRWAA6O.js → machineWsRunDispatch-X3ZC7DZJ.js} +39 -38
- package/{models-OX2S5C6Q.js → models-SQFOI4FI.js} +2 -2
- package/package.json +1 -1
- package/{read-6G73BMEY.js → read-526GJR3R.js} +1 -1
- package/{readDocTool-DK4EI2GA.js → readDocTool-JNEZUOSM.js} +1 -1
- package/{readlineWorkspace-ZDWEASJV.js → readlineWorkspace-J2ARMEUC.js} +2701 -2083
- package/{removeDialogAgentAction-E7H557UO.js → removeDialogAgentAction-NPMEFEJW.js} +4 -4
- package/{runAgentClientLoop-U7HYA3O5.js → runAgentClientLoop-5I2R74NR.js} +31 -30
- package/{runtimeDoctorCommands-KIKM6BIO.js → runtimeDoctorCommands-KHGQKT3B.js} +3 -3
- package/{setDialogExtraReferencesAction-RMMGBR5F.js → setDialogExtraReferencesAction-ZZ6QWAG2.js} +3 -3
- package/{setPrimaryDialogAgentAction-FWBKKLVA.js → setPrimaryDialogAgentAction-BG72QA6S.js} +4 -4
- package/{settingSlice-73PV4KG4.js → settingSlice-JCCLCXZB.js} +3 -3
- package/{skillDiscovery-KLLKXPUO.js → skillDiscovery-AYBKAG6X.js} +3 -3
- package/{spaceCommands-GEWZXGHM.js → spaceCommands-EZYMMJJH.js} +18 -17
- package/{spaceSlice-B6MOVY4N.js → spaceSlice-TL2FR4AF.js} +16 -15
- package/{streamAgentChatTurn-T527EQTT.js → streamAgentChatTurn-UDYSE2ES.js} +45 -54
- package/{switchDialogAgentAction-US6QNL3N.js → switchDialogAgentAction-YPGPM2LL.js} +2 -2
- package/{tableCommands-QE47K72R.js → tableCommands-64FZBAI3.js} +1 -1
- package/{tools-XMWCVMPM.js → tools-KWYWDJ77.js} +25 -24
- package/{tuiSummaryLlmCaller-NCAJSVSD.js → tuiSummaryLlmCaller-WUVAOIYU.js} +9 -8
- package/{updateCommands-AK2RDOFR.js → updateCommands-MNDUIKN7.js} +2 -2
- package/{updateDialogTitleAction-XPJZRJEL.js → updateDialogTitleAction-NQCOEOLF.js} +16 -15
|
@@ -7,14 +7,30 @@ import {
|
|
|
7
7
|
providerHttpFailure,
|
|
8
8
|
readSseFrames,
|
|
9
9
|
throwIfChatCompletionStreamFailed
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EQ6HOWEJ.js";
|
|
11
11
|
import {
|
|
12
12
|
sanitizeForOutbound
|
|
13
13
|
} from "./chunk-T27IEBNQ.js";
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
buildExecShellToolDefinition,
|
|
16
|
+
buildWorkspaceShellCommand,
|
|
17
|
+
buildWorkspaceShellEscapeBlockedResult,
|
|
18
|
+
createGlob,
|
|
19
|
+
deriveLabel,
|
|
20
|
+
evaluateExecShellDestructiveGuard,
|
|
21
|
+
extractActivity,
|
|
22
|
+
findWorkspaceShellEscapeToken,
|
|
23
|
+
getProcessRegistry,
|
|
24
|
+
invokeCapability,
|
|
25
|
+
isSpawnFailureError,
|
|
26
|
+
readNodeStream,
|
|
27
|
+
resolveExecutableOnPath,
|
|
28
|
+
resolveHistoricalToolContentCap,
|
|
29
|
+
runWorkspaceCommand,
|
|
30
|
+
spawnToWebStreams,
|
|
31
|
+
truncateToolOutput,
|
|
32
|
+
waitForNodeProcessExit
|
|
33
|
+
} from "./chunk-YH3FPBG6.js";
|
|
18
34
|
import {
|
|
19
35
|
createThinkParserState,
|
|
20
36
|
createToolCallAccumulator,
|
|
@@ -25,7 +41,7 @@ import {
|
|
|
25
41
|
import {
|
|
26
42
|
requiresBareImageUrl,
|
|
27
43
|
toBareImageUrlMessages
|
|
28
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-ZKUATCEY.js";
|
|
29
45
|
import {
|
|
30
46
|
convertMessagesToResponsesInput,
|
|
31
47
|
extractReasoningFromResponseOutput,
|
|
@@ -39,7 +55,7 @@ import {
|
|
|
39
55
|
import {
|
|
40
56
|
buildProviderAuthHeaders,
|
|
41
57
|
buildProviderExecutionPlan
|
|
42
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-OQVRTSZ5.js";
|
|
43
59
|
import {
|
|
44
60
|
NOLO_WORKSPACE_TOOL_NAMES,
|
|
45
61
|
buildNoloWorkspaceCommandArgs,
|
|
@@ -64,24 +80,15 @@ import {
|
|
|
64
80
|
dialogMessageKey,
|
|
65
81
|
dialogMessageRange
|
|
66
82
|
} from "./chunk-KMSZPTM6.js";
|
|
67
|
-
import {
|
|
68
|
-
asOptionalFiniteNumber
|
|
69
|
-
} from "./chunk-WWC7I6TA.js";
|
|
70
83
|
import {
|
|
71
84
|
asTrimmedNonEmptyStringArray
|
|
72
85
|
} from "./chunk-I42VC5KR.js";
|
|
73
|
-
import {
|
|
74
|
-
asTrimmedLowercaseString
|
|
75
|
-
} from "./chunk-QSJ3HFEF.js";
|
|
76
86
|
import {
|
|
77
87
|
asTrimmedString
|
|
78
88
|
} from "./chunk-3EUW3WEO.js";
|
|
79
89
|
import {
|
|
80
90
|
asOptionalPositiveFiniteNumber
|
|
81
91
|
} from "./chunk-U6VC4MU4.js";
|
|
82
|
-
import {
|
|
83
|
-
isRecord
|
|
84
|
-
} from "./chunk-KUG52IAP.js";
|
|
85
92
|
import {
|
|
86
93
|
normalizeServerOrigin
|
|
87
94
|
} from "./chunk-CF7PE763.js";
|
|
@@ -1033,219 +1040,6 @@ function createHybridRecordStore(deps) {
|
|
|
1033
1040
|
};
|
|
1034
1041
|
}
|
|
1035
1042
|
|
|
1036
|
-
// packages/agent-runtime/shellCommandPolicy.ts
|
|
1037
|
-
var DESTRUCTIVE_NEGATION_PATTERNS = [
|
|
1038
|
-
"\u522B\u5220",
|
|
1039
|
-
"\u522B\u5220\u9664",
|
|
1040
|
-
"\u4E0D\u8981\u5220",
|
|
1041
|
-
"\u4E0D\u8981\u5220\u9664",
|
|
1042
|
-
"\u522B\u4E71\u5220",
|
|
1043
|
-
"\u522B\u52A8",
|
|
1044
|
-
"\u4E0D\u8981\u52A8",
|
|
1045
|
-
"\u4E0D\u8981\u6E05\u7406",
|
|
1046
|
-
"\u4E0D\u8981\u6E05\u7A7A",
|
|
1047
|
-
"\u4E0D\u8981\u91CD\u7F6E",
|
|
1048
|
-
"don't delete",
|
|
1049
|
-
"do not delete",
|
|
1050
|
-
"don't remove",
|
|
1051
|
-
"do not remove",
|
|
1052
|
-
"without deleting"
|
|
1053
|
-
];
|
|
1054
|
-
var EXPLICIT_DESTRUCTIVE_REQUEST_PATTERNS = [
|
|
1055
|
-
"\u5220\u9664",
|
|
1056
|
-
"\u5220\u6389",
|
|
1057
|
-
"\u79FB\u9664",
|
|
1058
|
-
"\u6E05\u7406",
|
|
1059
|
-
"\u6E05\u7A7A",
|
|
1060
|
-
"\u91CD\u7F6E",
|
|
1061
|
-
"drop",
|
|
1062
|
-
"delete",
|
|
1063
|
-
"remove",
|
|
1064
|
-
"erase",
|
|
1065
|
-
"clean up",
|
|
1066
|
-
"reset"
|
|
1067
|
-
];
|
|
1068
|
-
var SHELL_DESTRUCTIVE_PATTERNS = [
|
|
1069
|
-
/\brm\s+(-[^\n\r]*\s+)?/i,
|
|
1070
|
-
/\bremove-item\b/i,
|
|
1071
|
-
/\bdel\s+\/?[a-z]*\s+/i,
|
|
1072
|
-
/\berase\s+/i,
|
|
1073
|
-
/\brmdir\s+/i,
|
|
1074
|
-
/\brd\s+\/s\b/i,
|
|
1075
|
-
/\bgit\s+reset\s+(--hard\b|--merge\b|--keep\b)/i,
|
|
1076
|
-
/\bgit\s+clean\s+-[^\n\r]*f/i,
|
|
1077
|
-
/\bgit\s+checkout\s+--\b/i,
|
|
1078
|
-
/\bgit\s+restore\s+--source=/i
|
|
1079
|
-
];
|
|
1080
|
-
var SHELL_STRING_EXECUTION_PATTERNS = [
|
|
1081
|
-
/\b(?:ba|da|z|k)?sh\b/i,
|
|
1082
|
-
/\beval\b/i,
|
|
1083
|
-
/\bexec\b/i,
|
|
1084
|
-
/\bxargs\b/i,
|
|
1085
|
-
/\bsource\s/i,
|
|
1086
|
-
/\b(?:node|deno|bun)\s+(?:-\S+\s+)*(?:-e|--eval)\b/i,
|
|
1087
|
-
/\bpython[\d.]*\s+(?:-\S+\s+)*-c\b/i,
|
|
1088
|
-
/\b(?:perl|ruby)\s+(?:-\S+\s+)*-e\b/i
|
|
1089
|
-
];
|
|
1090
|
-
var stripQuotedSegments = (text) => {
|
|
1091
|
-
let out = "";
|
|
1092
|
-
let i = 0;
|
|
1093
|
-
while (i < text.length) {
|
|
1094
|
-
const ch = text[i];
|
|
1095
|
-
if (ch === "\\") {
|
|
1096
|
-
out += text.slice(i, i + 2);
|
|
1097
|
-
i += 2;
|
|
1098
|
-
} else if (ch === "'") {
|
|
1099
|
-
const end = text.indexOf("'", i + 1);
|
|
1100
|
-
if (end === -1) return out + text.slice(i);
|
|
1101
|
-
out += "''";
|
|
1102
|
-
i = end + 1;
|
|
1103
|
-
} else if (ch === '"') {
|
|
1104
|
-
let j = i + 1;
|
|
1105
|
-
while (j < text.length && text[j] !== '"') {
|
|
1106
|
-
j += text[j] === "\\" ? 2 : 1;
|
|
1107
|
-
}
|
|
1108
|
-
if (j >= text.length) return out + text.slice(i);
|
|
1109
|
-
out += '""';
|
|
1110
|
-
i = j + 1;
|
|
1111
|
-
} else {
|
|
1112
|
-
out += ch;
|
|
1113
|
-
i += 1;
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
return out;
|
|
1117
|
-
};
|
|
1118
|
-
var normalizeUserInput = (value) => asTrimmedLowercaseString(value);
|
|
1119
|
-
var containsAny = (text, patterns) => patterns.some((pattern) => text.includes(pattern));
|
|
1120
|
-
var hasExplicitDestructivePermission = (userInput) => {
|
|
1121
|
-
const normalized = normalizeUserInput(userInput);
|
|
1122
|
-
if (!normalized) return false;
|
|
1123
|
-
if (containsAny(normalized, DESTRUCTIVE_NEGATION_PATTERNS)) return false;
|
|
1124
|
-
return containsAny(normalized, EXPLICIT_DESTRUCTIVE_REQUEST_PATTERNS);
|
|
1125
|
-
};
|
|
1126
|
-
var SHELL_COMMAND_ARG_ALIASES = [
|
|
1127
|
-
"command",
|
|
1128
|
-
"runCommand",
|
|
1129
|
-
"run_command",
|
|
1130
|
-
"terminalCommand",
|
|
1131
|
-
"terminal_command",
|
|
1132
|
-
"runInBash",
|
|
1133
|
-
"run_in_bash",
|
|
1134
|
-
"executeCommand",
|
|
1135
|
-
"execute_command",
|
|
1136
|
-
"execShell",
|
|
1137
|
-
"bash",
|
|
1138
|
-
"cmd"
|
|
1139
|
-
];
|
|
1140
|
-
var resolveShellCommandArg = (args) => {
|
|
1141
|
-
if (!args) return void 0;
|
|
1142
|
-
for (const key of SHELL_COMMAND_ARG_ALIASES) {
|
|
1143
|
-
const value = args[key];
|
|
1144
|
-
if (value != null) return value;
|
|
1145
|
-
}
|
|
1146
|
-
return void 0;
|
|
1147
|
-
};
|
|
1148
|
-
var buildCombinedShellInput = (args) => {
|
|
1149
|
-
const command = resolveShellCommandArg(args);
|
|
1150
|
-
return [
|
|
1151
|
-
typeof command === "string" ? command : "",
|
|
1152
|
-
typeof args.input === "string" ? args.input : ""
|
|
1153
|
-
].filter(Boolean).join("\n");
|
|
1154
|
-
};
|
|
1155
|
-
function resolveScannableShellInput(args) {
|
|
1156
|
-
const combined = buildCombinedShellInput(args);
|
|
1157
|
-
if (!combined.trim()) return void 0;
|
|
1158
|
-
return SHELL_STRING_EXECUTION_PATTERNS.some(
|
|
1159
|
-
(pattern) => pattern.test(combined)
|
|
1160
|
-
) ? combined : stripQuotedSegments(combined);
|
|
1161
|
-
}
|
|
1162
|
-
function isDestructiveShellCommand(args) {
|
|
1163
|
-
const scannable = resolveScannableShellInput(args);
|
|
1164
|
-
if (scannable === void 0) return false;
|
|
1165
|
-
return SHELL_DESTRUCTIVE_PATTERNS.some((pattern) => pattern.test(scannable));
|
|
1166
|
-
}
|
|
1167
|
-
var LONG_RUNNING_COMMAND_PATTERNS = [
|
|
1168
|
-
/\b(run|npm|yarn|pnpm|bun|npx)\s+(run\s+)?(dev|serve|start|watch)\b/i,
|
|
1169
|
-
/(^|[\s=&|;])--watch\b/i,
|
|
1170
|
-
/\bvite\b.*\b(dev|serve)\b/i,
|
|
1171
|
-
/\bwebpack\b.*(?:--watch|serve)\b/i,
|
|
1172
|
-
/\bnodemon\b/i,
|
|
1173
|
-
/\bgatsby\b.*\b(develop|serve)\b/i,
|
|
1174
|
-
/\bnext\b.*\b(dev|start)\b/i,
|
|
1175
|
-
/\belectron\b.*\bdev\b/i,
|
|
1176
|
-
/\bforever\b/i,
|
|
1177
|
-
/\bpm2\b.*\bstart\b/i
|
|
1178
|
-
];
|
|
1179
|
-
function isLongRunningShellCommand(args) {
|
|
1180
|
-
const scannable = resolveScannableShellInput(args);
|
|
1181
|
-
if (scannable === void 0) return false;
|
|
1182
|
-
return LONG_RUNNING_COMMAND_PATTERNS.some((pattern) => pattern.test(scannable));
|
|
1183
|
-
}
|
|
1184
|
-
var IMMEDIATE_DETACH_COMMAND_PATTERNS = [
|
|
1185
|
-
/\btail\s+(?:-\S*[fF]\S*|--follow)\b/,
|
|
1186
|
-
/\bwatch\s+\S/,
|
|
1187
|
-
/\bwhile\s+(?:true|:|\[\s*true\s*\])\s*;\s*do\b/
|
|
1188
|
-
];
|
|
1189
|
-
var IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS = 5;
|
|
1190
|
-
var SLEEP_PREFIX_PATTERN = /^(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:nohup\s+|time\s+)*sleep\s+(\S+)/;
|
|
1191
|
-
function parseSleepDurationSeconds(token) {
|
|
1192
|
-
const match = /^(\d+(?:\.\d+)?)(s|m|h|d)?$/i.exec(token);
|
|
1193
|
-
if (!match) return void 0;
|
|
1194
|
-
const value = Number(match[1]);
|
|
1195
|
-
if (!Number.isFinite(value)) return void 0;
|
|
1196
|
-
const unit = (match[2] ?? "s").toLowerCase();
|
|
1197
|
-
const factor = unit === "m" ? 60 : unit === "h" ? 3600 : unit === "d" ? 86400 : 1;
|
|
1198
|
-
return value * factor;
|
|
1199
|
-
}
|
|
1200
|
-
function isLongSleepCommand(scannable) {
|
|
1201
|
-
const match = SLEEP_PREFIX_PATTERN.exec(scannable.trim());
|
|
1202
|
-
if (!match) return false;
|
|
1203
|
-
const durationToken = match[1] ?? "";
|
|
1204
|
-
if (/^inf(inity)?$/i.test(durationToken)) return true;
|
|
1205
|
-
const seconds = parseSleepDurationSeconds(durationToken);
|
|
1206
|
-
if (seconds === void 0) return true;
|
|
1207
|
-
return seconds > IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS;
|
|
1208
|
-
}
|
|
1209
|
-
function isImmediateDetachShellCommand(args) {
|
|
1210
|
-
const scannable = resolveScannableShellInput(args);
|
|
1211
|
-
if (scannable === void 0) return false;
|
|
1212
|
-
return isLongSleepCommand(scannable) || LONG_RUNNING_COMMAND_PATTERNS.some((pattern) => pattern.test(scannable)) || IMMEDIATE_DETACH_COMMAND_PATTERNS.some(
|
|
1213
|
-
(pattern) => pattern.test(scannable)
|
|
1214
|
-
);
|
|
1215
|
-
}
|
|
1216
|
-
function evaluateShellCommandPolicy(args) {
|
|
1217
|
-
if (isDestructiveShellCommand(args) && !hasExplicitDestructivePermission(args.userInput)) {
|
|
1218
|
-
return {
|
|
1219
|
-
verdict: "forbidden",
|
|
1220
|
-
permissionDecision: "ask",
|
|
1221
|
-
code: "destructive_action_requires_confirmation",
|
|
1222
|
-
reason: "\u5F53\u524D\u8FD0\u884C\u9ED8\u8BA4\u7981\u6B62\u81EA\u52A8\u6267\u884C\u53EF\u80FD\u5220\u9664\u7528\u6237\u5185\u5BB9\u7684 shell \u547D\u4EE4\u3002\u53EA\u6709\u5F53\u7528\u6237\u5728\u5F53\u524D\u8BF7\u6C42\u91CC\u660E\u786E\u8981\u6C42\u5220\u9664/\u6E05\u7406\u65F6\uFF0C\u624D\u80FD\u7EE7\u7EED\uFF1B\u5426\u5219\u8BF7\u505C\u6B62\u5E76\u5148\u8BF4\u660E\u9650\u5236\u3002",
|
|
1223
|
-
permissionRequest: {
|
|
1224
|
-
id: "permission-shell-destructive-action",
|
|
1225
|
-
tool: "execShell",
|
|
1226
|
-
action: "destructive_shell_command",
|
|
1227
|
-
title: "\u786E\u8BA4\u6267\u884C\u7834\u574F\u6027 shell \u547D\u4EE4",
|
|
1228
|
-
body: "\u8BE5\u547D\u4EE4\u53EF\u80FD\u5220\u9664\u6216\u91CD\u7F6E\u7528\u6237\u5185\u5BB9\uFF0C\u9700\u8981\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u624D\u80FD\u6267\u884C\u3002",
|
|
1229
|
-
suggestedRule: {
|
|
1230
|
-
scope: "once",
|
|
1231
|
-
pattern: { capability: "destructive_action", target: "shell_command" }
|
|
1232
|
-
}
|
|
1233
|
-
},
|
|
1234
|
-
policy: {
|
|
1235
|
-
capability: "destructive_action",
|
|
1236
|
-
target: "shell_command",
|
|
1237
|
-
detail: "execShell destructive command"
|
|
1238
|
-
}
|
|
1239
|
-
};
|
|
1240
|
-
}
|
|
1241
|
-
const longRunningHint = isLongRunningShellCommand(args);
|
|
1242
|
-
return {
|
|
1243
|
-
verdict: "allowed",
|
|
1244
|
-
permissionDecision: "allow",
|
|
1245
|
-
...longRunningHint ? { longRunningHint: true } : {}
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
1043
|
// packages/agent-runtime/localToolPolicy.ts
|
|
1250
1044
|
var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
|
|
1251
1045
|
"deleteSpaces",
|
|
@@ -1290,20 +1084,6 @@ function normalizeLocalToolName(toolName) {
|
|
|
1290
1084
|
String(toolName ?? "").replace(/^functions\./, "").trim()
|
|
1291
1085
|
);
|
|
1292
1086
|
}
|
|
1293
|
-
function parseShellCommandPayload(rawArguments) {
|
|
1294
|
-
return parseToolArgumentsJson(rawArguments);
|
|
1295
|
-
}
|
|
1296
|
-
function toDisplayCommand(command) {
|
|
1297
|
-
if (typeof command === "string") {
|
|
1298
|
-
const trimmed = command.trim();
|
|
1299
|
-
return trimmed ? trimmed : void 0;
|
|
1300
|
-
}
|
|
1301
|
-
if (Array.isArray(command)) {
|
|
1302
|
-
const joined = command.map((item) => typeof item === "string" ? item : String(item)).filter((item) => item.length > 0).join(" ").trim();
|
|
1303
|
-
return joined ? joined : void 0;
|
|
1304
|
-
}
|
|
1305
|
-
return void 0;
|
|
1306
|
-
}
|
|
1307
1087
|
function isRestrictedLocalToolMode(env) {
|
|
1308
1088
|
return env.NOLO_LOCAL_TOOL_MODE === "restricted";
|
|
1309
1089
|
}
|
|
@@ -1353,7 +1133,6 @@ function resolveLocalToolPolicy(args) {
|
|
|
1353
1133
|
reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
|
|
1354
1134
|
};
|
|
1355
1135
|
}
|
|
1356
|
-
var ABORT_AWARE_LOCAL_TOOLS = /* @__PURE__ */ new Set(["execShell", "controlAgentRun"]);
|
|
1357
1136
|
async function executeLocalToolWithPolicy(args) {
|
|
1358
1137
|
const decision = resolveLocalToolPolicy({
|
|
1359
1138
|
env: args.env,
|
|
@@ -1365,66 +1144,37 @@ async function executeLocalToolWithPolicy(args) {
|
|
|
1365
1144
|
if (!executor) {
|
|
1366
1145
|
throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
|
|
1367
1146
|
}
|
|
1368
|
-
const
|
|
1369
|
-
abortSignal: args.abortSignal,
|
|
1370
|
-
detachMs: args.detachMs
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
body: "\u8BE5\u547D\u4EE4\u53EF\u80FD\u5220\u9664\u6216\u91CD\u7F6E\u7528\u6237\u5185\u5BB9\uFF0C\u9700\u8981\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u624D\u80FD\u6267\u884C\u3002",
|
|
1384
|
-
...command ? { command } : {},
|
|
1385
|
-
suggestedRule: {
|
|
1386
|
-
scope: "once",
|
|
1387
|
-
pattern: { capability: "destructive_action", target: "shell_command" }
|
|
1388
|
-
}
|
|
1389
|
-
};
|
|
1390
|
-
const buildBlockedError = (reason) => {
|
|
1391
|
-
const error = new Error(reason);
|
|
1392
|
-
error.code = "destructive_action_requires_confirmation";
|
|
1393
|
-
error.policy = {
|
|
1394
|
-
capability: "destructive_action",
|
|
1395
|
-
target: "shell_command",
|
|
1396
|
-
detail: "execShell destructive command"
|
|
1397
|
-
};
|
|
1398
|
-
error.permissionRequest = request;
|
|
1399
|
-
return error;
|
|
1400
|
-
};
|
|
1401
|
-
if (!args.confirmDestructiveAction) {
|
|
1402
|
-
if (args.blockDestructiveWithoutConfirmation) {
|
|
1403
|
-
throw buildBlockedError(
|
|
1404
|
-
"destructive shell command blocked: no confirmation channel available"
|
|
1405
|
-
);
|
|
1406
|
-
}
|
|
1407
|
-
return effectiveExecutor({
|
|
1408
|
-
...args.call,
|
|
1409
|
-
name: decision.toolName
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
const confirmed = await args.confirmDestructiveAction(request);
|
|
1413
|
-
if (!confirmed) {
|
|
1414
|
-
throw buildBlockedError(
|
|
1415
|
-
"destructive shell command blocked: user declined confirmation"
|
|
1416
|
-
);
|
|
1147
|
+
const opts = {
|
|
1148
|
+
...args.abortSignal ? { abortSignal: args.abortSignal } : {},
|
|
1149
|
+
...args.detachMs !== void 0 ? { detachMs: args.detachMs } : {},
|
|
1150
|
+
...args.confirmed !== void 0 ? { confirmed: args.confirmed } : {},
|
|
1151
|
+
...args.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args.enableDestructiveShellGuard } : {},
|
|
1152
|
+
...args.confirmDestructiveAction ? { confirmDestructiveAction: args.confirmDestructiveAction } : {},
|
|
1153
|
+
...args.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args.blockDestructiveWithoutConfirmation } : {}
|
|
1154
|
+
};
|
|
1155
|
+
if (decision.toolName === "execShell") {
|
|
1156
|
+
let parsedInput = args.call.arguments;
|
|
1157
|
+
if (typeof parsedInput === "string") {
|
|
1158
|
+
try {
|
|
1159
|
+
parsedInput = JSON.parse(parsedInput);
|
|
1160
|
+
} catch {
|
|
1161
|
+
parsedInput = { command: parsedInput };
|
|
1417
1162
|
}
|
|
1418
1163
|
}
|
|
1164
|
+
await evaluateExecShellDestructiveGuard(parsedInput, opts);
|
|
1165
|
+
opts.confirmed = true;
|
|
1419
1166
|
}
|
|
1420
|
-
return
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1167
|
+
return executor(
|
|
1168
|
+
{
|
|
1169
|
+
...args.call,
|
|
1170
|
+
name: decision.toolName
|
|
1171
|
+
},
|
|
1172
|
+
opts
|
|
1173
|
+
);
|
|
1424
1174
|
}
|
|
1425
1175
|
|
|
1426
1176
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
1427
|
-
import { existsSync
|
|
1177
|
+
import { existsSync } from "node:fs";
|
|
1428
1178
|
import { createHash } from "node:crypto";
|
|
1429
1179
|
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
1430
1180
|
import { dirname, relative, resolve, sep } from "node:path";
|
|
@@ -1462,244 +1212,6 @@ function isLineRangeCovered(request, covered) {
|
|
|
1462
1212
|
return open > request.endLine;
|
|
1463
1213
|
}
|
|
1464
1214
|
|
|
1465
|
-
// packages/agent-runtime/runtimeCompat.ts
|
|
1466
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
1467
|
-
import { join } from "node:path";
|
|
1468
|
-
import { spawn } from "node:child_process";
|
|
1469
|
-
var IS_WINDOWS = process.platform === "win32";
|
|
1470
|
-
function isExecutableFile(candidate) {
|
|
1471
|
-
if (!existsSync(candidate)) return false;
|
|
1472
|
-
try {
|
|
1473
|
-
return statSync(candidate).isFile();
|
|
1474
|
-
} catch {
|
|
1475
|
-
return false;
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
function resolveExecutableOnPath(name) {
|
|
1479
|
-
if (IS_WINDOWS && !/\.[a-z]+$/i.test(name)) {
|
|
1480
|
-
const exts = (process.env.PATHEXT || ".EXE;.CMD;.BAT").split(";").filter(Boolean);
|
|
1481
|
-
for (const ext of exts) {
|
|
1482
|
-
const found = resolveExecutableOnPath(name + ext);
|
|
1483
|
-
if (found) return found;
|
|
1484
|
-
}
|
|
1485
|
-
return null;
|
|
1486
|
-
}
|
|
1487
|
-
const pathEnv = process.env.PATH ?? "";
|
|
1488
|
-
const sep2 = pathEnv.includes(";") && IS_WINDOWS ? ";" : ":";
|
|
1489
|
-
const pathDirs = pathEnv.split(sep2).filter(Boolean);
|
|
1490
|
-
const fallbackDirs = IS_WINDOWS ? [] : [
|
|
1491
|
-
"/opt/homebrew/bin",
|
|
1492
|
-
"/usr/local/bin",
|
|
1493
|
-
"/usr/bin",
|
|
1494
|
-
"/bin",
|
|
1495
|
-
`${process.env.HOME ?? ""}/.local/bin`
|
|
1496
|
-
].filter(Boolean);
|
|
1497
|
-
for (const dir of [...pathDirs, ...fallbackDirs]) {
|
|
1498
|
-
const candidate = join(dir, name);
|
|
1499
|
-
if (isExecutableFile(candidate)) return candidate;
|
|
1500
|
-
}
|
|
1501
|
-
return null;
|
|
1502
|
-
}
|
|
1503
|
-
function createGlob(pattern) {
|
|
1504
|
-
const regex = globToRegExp(pattern);
|
|
1505
|
-
return {
|
|
1506
|
-
match(path) {
|
|
1507
|
-
return regex.test(path);
|
|
1508
|
-
},
|
|
1509
|
-
scanSync(opts) {
|
|
1510
|
-
const dot = opts.dot ?? false;
|
|
1511
|
-
const results = [];
|
|
1512
|
-
walkDir(opts.cwd, "", dot, results);
|
|
1513
|
-
return results.filter((rel) => regex.test(rel));
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
}
|
|
1517
|
-
function walkDir(dir, prefix, dot, out) {
|
|
1518
|
-
let entries;
|
|
1519
|
-
try {
|
|
1520
|
-
entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
|
|
1521
|
-
} catch {
|
|
1522
|
-
return;
|
|
1523
|
-
}
|
|
1524
|
-
for (const entry of entries) {
|
|
1525
|
-
const name = String(entry.name);
|
|
1526
|
-
if (!dot && name.startsWith(".")) continue;
|
|
1527
|
-
const rel = prefix ? `${prefix}/${name}` : name;
|
|
1528
|
-
const full = join(dir, name);
|
|
1529
|
-
if (entry.isDirectory()) {
|
|
1530
|
-
walkDir(full, rel, dot, out);
|
|
1531
|
-
} else if (entry.isFile()) {
|
|
1532
|
-
out.push(rel);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
function globToRegExp(pattern) {
|
|
1537
|
-
const trailingDir = pattern.endsWith("/");
|
|
1538
|
-
const src = trailingDir ? pattern.slice(0, -1) : pattern;
|
|
1539
|
-
const anchored = src.startsWith("/");
|
|
1540
|
-
const body = anchored ? src.slice(1) : src;
|
|
1541
|
-
let regex = "^";
|
|
1542
|
-
if (!anchored) regex += "(?:.*/)?";
|
|
1543
|
-
regex += convertBody(body);
|
|
1544
|
-
if (trailingDir) {
|
|
1545
|
-
regex += "(?:/.*)?";
|
|
1546
|
-
}
|
|
1547
|
-
regex += "$";
|
|
1548
|
-
return new RegExp(regex);
|
|
1549
|
-
}
|
|
1550
|
-
function convertBody(p) {
|
|
1551
|
-
let out = "";
|
|
1552
|
-
let i = 0;
|
|
1553
|
-
while (i < p.length) {
|
|
1554
|
-
const c = p[i];
|
|
1555
|
-
if (c === "*") {
|
|
1556
|
-
if (p[i + 1] === "*") {
|
|
1557
|
-
i += 2;
|
|
1558
|
-
if (p[i] === "/") {
|
|
1559
|
-
out += "(?:.*/)?";
|
|
1560
|
-
i += 1;
|
|
1561
|
-
} else {
|
|
1562
|
-
out += ".*";
|
|
1563
|
-
}
|
|
1564
|
-
} else {
|
|
1565
|
-
out += "[^/]*";
|
|
1566
|
-
i += 1;
|
|
1567
|
-
}
|
|
1568
|
-
} else if (c === "?") {
|
|
1569
|
-
out += "[^/]";
|
|
1570
|
-
i += 1;
|
|
1571
|
-
} else if (c === "[") {
|
|
1572
|
-
out += "[";
|
|
1573
|
-
i += 1;
|
|
1574
|
-
if (p[i] === "!") {
|
|
1575
|
-
out += "^";
|
|
1576
|
-
i += 1;
|
|
1577
|
-
}
|
|
1578
|
-
while (i < p.length && p[i] !== "]") {
|
|
1579
|
-
out += p[i] === "\\" ? "\\\\" : p[i];
|
|
1580
|
-
i += 1;
|
|
1581
|
-
}
|
|
1582
|
-
if (p[i] === "]") {
|
|
1583
|
-
out += "]";
|
|
1584
|
-
i += 1;
|
|
1585
|
-
}
|
|
1586
|
-
} else if (c === "{") {
|
|
1587
|
-
let depth = 1;
|
|
1588
|
-
let j = i + 1;
|
|
1589
|
-
let bodyStr = "";
|
|
1590
|
-
while (j < p.length && depth > 0) {
|
|
1591
|
-
if (p[j] === "{") depth += 1;
|
|
1592
|
-
else if (p[j] === "}") depth -= 1;
|
|
1593
|
-
if (depth > 0) bodyStr += p[j];
|
|
1594
|
-
j += 1;
|
|
1595
|
-
}
|
|
1596
|
-
const alts = bodyStr.split(",").map((alt) => convertBody(alt));
|
|
1597
|
-
out += `(?:${alts.join("|")})`;
|
|
1598
|
-
i = j;
|
|
1599
|
-
} else {
|
|
1600
|
-
out += escapeRegexChar(c);
|
|
1601
|
-
i += 1;
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
return out;
|
|
1605
|
-
}
|
|
1606
|
-
function escapeRegexChar(c) {
|
|
1607
|
-
if ("\\^$.|+()".includes(c)) {
|
|
1608
|
-
return `\\${c}`;
|
|
1609
|
-
}
|
|
1610
|
-
return c;
|
|
1611
|
-
}
|
|
1612
|
-
function spawnToWebStreams(options) {
|
|
1613
|
-
const [command, ...args] = options.cmd;
|
|
1614
|
-
const child = spawn(command, args, {
|
|
1615
|
-
env: options.env,
|
|
1616
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
1617
|
-
});
|
|
1618
|
-
const exited = new Promise((resolve2) => {
|
|
1619
|
-
child.on("exit", (code) => resolve2(code ?? 1));
|
|
1620
|
-
child.on("error", () => resolve2(127));
|
|
1621
|
-
});
|
|
1622
|
-
const toWeb = (stream) => {
|
|
1623
|
-
if (!stream) return null;
|
|
1624
|
-
return stream.toWeb?.() ?? new ReadableStream({
|
|
1625
|
-
start(controller) {
|
|
1626
|
-
stream.on("data", (chunk) => controller.enqueue(new Uint8Array(chunk)));
|
|
1627
|
-
stream.on("end", () => controller.close());
|
|
1628
|
-
stream.on("error", (e) => controller.error(e));
|
|
1629
|
-
}
|
|
1630
|
-
});
|
|
1631
|
-
};
|
|
1632
|
-
return {
|
|
1633
|
-
stdout: toWeb(child.stdout),
|
|
1634
|
-
stderr: toWeb(child.stderr),
|
|
1635
|
-
exited
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
// packages/agent-runtime/processRegistry.ts
|
|
1640
|
-
var ProcessRegistry = class {
|
|
1641
|
-
processes = /* @__PURE__ */ new Map();
|
|
1642
|
-
add(proc) {
|
|
1643
|
-
this.processes.set(proc.pid, {
|
|
1644
|
-
pid: proc.pid,
|
|
1645
|
-
pgid: proc.pgid,
|
|
1646
|
-
command: proc.command,
|
|
1647
|
-
label: proc.label,
|
|
1648
|
-
startedAt: Date.now(),
|
|
1649
|
-
status: "running",
|
|
1650
|
-
persist: proc.persist ?? false
|
|
1651
|
-
});
|
|
1652
|
-
}
|
|
1653
|
-
list() {
|
|
1654
|
-
return Array.from(this.processes.values()).map((proc) => ({ ...proc }));
|
|
1655
|
-
}
|
|
1656
|
-
get(pid) {
|
|
1657
|
-
const item = this.processes.get(pid);
|
|
1658
|
-
return item ? { ...item } : void 0;
|
|
1659
|
-
}
|
|
1660
|
-
kill(pid, signal = "SIGTERM") {
|
|
1661
|
-
const item = this.processes.get(pid);
|
|
1662
|
-
if (!item) return false;
|
|
1663
|
-
if (item.status === "running") {
|
|
1664
|
-
try {
|
|
1665
|
-
process.kill(-item.pgid, signal);
|
|
1666
|
-
} catch {
|
|
1667
|
-
}
|
|
1668
|
-
item.status = "stopped";
|
|
1669
|
-
return true;
|
|
1670
|
-
}
|
|
1671
|
-
return false;
|
|
1672
|
-
}
|
|
1673
|
-
stopAll(signal = "SIGTERM", opts) {
|
|
1674
|
-
for (const item of this.processes.values()) {
|
|
1675
|
-
if (item.status === "running" && (opts?.includePersist || !item.persist)) {
|
|
1676
|
-
try {
|
|
1677
|
-
process.kill(-item.pgid, signal);
|
|
1678
|
-
} catch {
|
|
1679
|
-
}
|
|
1680
|
-
item.status = "stopped";
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
markExited(pid, exitCode) {
|
|
1685
|
-
const item = this.processes.get(pid);
|
|
1686
|
-
if (item && item.status === "running") {
|
|
1687
|
-
item.exitCode = exitCode;
|
|
1688
|
-
item.status = exitCode === 0 ? "exited" : "failed";
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
clear() {
|
|
1692
|
-
this.processes.clear();
|
|
1693
|
-
}
|
|
1694
|
-
};
|
|
1695
|
-
var registry = null;
|
|
1696
|
-
function getProcessRegistry() {
|
|
1697
|
-
if (!registry) {
|
|
1698
|
-
registry = new ProcessRegistry();
|
|
1699
|
-
}
|
|
1700
|
-
return registry;
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
1215
|
// packages/agent-runtime/localWorkspaceToolDefs.ts
|
|
1704
1216
|
var WORKSPACE_TOOL_NAMES = [
|
|
1705
1217
|
"listFiles",
|
|
@@ -1723,15 +1235,6 @@ var REMOVED_WORKSPACE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
1723
1235
|
"gitCommit",
|
|
1724
1236
|
"commitWorkspace"
|
|
1725
1237
|
]);
|
|
1726
|
-
function tokenizeShellPrefix(command) {
|
|
1727
|
-
const tokens = [];
|
|
1728
|
-
const pattern = /"([^"]*)"|'([^']*)'|([^\s"'|;&<>]+)/g;
|
|
1729
|
-
let match;
|
|
1730
|
-
while (match = pattern.exec(command)) {
|
|
1731
|
-
tokens.push(match[1] ?? match[2] ?? match[3] ?? "");
|
|
1732
|
-
}
|
|
1733
|
-
return tokens;
|
|
1734
|
-
}
|
|
1735
1238
|
function buildWorkspacePathProperty() {
|
|
1736
1239
|
return {
|
|
1737
1240
|
type: "string",
|
|
@@ -2105,26 +1608,7 @@ function buildCaptureVisualStateTool() {
|
|
|
2105
1608
|
};
|
|
2106
1609
|
}
|
|
2107
1610
|
function buildExecShellTool(toolName) {
|
|
2108
|
-
return
|
|
2109
|
-
type: "function",
|
|
2110
|
-
function: {
|
|
2111
|
-
name: toolName,
|
|
2112
|
-
description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess.`,
|
|
2113
|
-
parameters: {
|
|
2114
|
-
type: "object",
|
|
2115
|
-
properties: {
|
|
2116
|
-
command: {
|
|
2117
|
-
type: "string",
|
|
2118
|
-
description: "Shell command to run (non-empty)."
|
|
2119
|
-
},
|
|
2120
|
-
cmd: {
|
|
2121
|
-
type: "string",
|
|
2122
|
-
description: "Compatibility alias for command."
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
};
|
|
1611
|
+
return buildExecShellToolDefinition(toolName);
|
|
2128
1612
|
}
|
|
2129
1613
|
function buildLaunchProcessTool() {
|
|
2130
1614
|
return {
|
|
@@ -2166,73 +1650,6 @@ function buildListProcessesTool() {
|
|
|
2166
1650
|
}
|
|
2167
1651
|
};
|
|
2168
1652
|
}
|
|
2169
|
-
function wrapPowerShellCommand(command) {
|
|
2170
|
-
return [
|
|
2171
|
-
"[Console]::InputEncoding=[System.Text.Encoding]::UTF8",
|
|
2172
|
-
"[Console]::OutputEncoding=[System.Text.Encoding]::UTF8",
|
|
2173
|
-
"$OutputEncoding=[System.Text.Encoding]::UTF8",
|
|
2174
|
-
"$PSStyle.OutputRendering='PlainText'",
|
|
2175
|
-
command
|
|
2176
|
-
].join("; ");
|
|
2177
|
-
}
|
|
2178
|
-
function findPowerShellExecutable() {
|
|
2179
|
-
return resolveExecutableOnPath("pwsh") || resolveExecutableOnPath("powershell.exe") || resolveExecutableOnPath("powershell");
|
|
2180
|
-
}
|
|
2181
|
-
function buildPowerShellCommand(command) {
|
|
2182
|
-
const executable = findPowerShellExecutable();
|
|
2183
|
-
if (!executable) throw new Error("PowerShell is not available on this machine.");
|
|
2184
|
-
return [
|
|
2185
|
-
executable,
|
|
2186
|
-
"-NoLogo",
|
|
2187
|
-
"-NoProfile",
|
|
2188
|
-
"-NonInteractive",
|
|
2189
|
-
"-ExecutionPolicy",
|
|
2190
|
-
"Bypass",
|
|
2191
|
-
"-Command",
|
|
2192
|
-
wrapPowerShellCommand(command)
|
|
2193
|
-
];
|
|
2194
|
-
}
|
|
2195
|
-
function buildBashCommand(command) {
|
|
2196
|
-
const executable = resolveExecutableOnPath("bash") || resolveExecutableOnPath("sh");
|
|
2197
|
-
if (!executable) throw new Error("bash/sh is not available on this machine.");
|
|
2198
|
-
return [executable, "-lc", command];
|
|
2199
|
-
}
|
|
2200
|
-
function buildWorkspaceShellCommand(args) {
|
|
2201
|
-
if (args.shell === "powershell") return buildPowerShellCommand(args.command);
|
|
2202
|
-
if (args.shell === "bash") return buildBashCommand(args.command);
|
|
2203
|
-
return process.platform === "win32" ? buildPowerShellCommand(args.command) : buildBashCommand(args.command);
|
|
2204
|
-
}
|
|
2205
|
-
function findWorkspaceShellEscapeToken(command) {
|
|
2206
|
-
const tokens = tokenizeShellPrefix(command);
|
|
2207
|
-
for (const token of tokens) {
|
|
2208
|
-
if (token === ".." || token.startsWith("../") || token.startsWith("..\\") || token.includes("/../") || token.includes("\\..\\")) {
|
|
2209
|
-
return token;
|
|
2210
|
-
}
|
|
2211
|
-
if (token === "~" || token.startsWith("~/") || token.startsWith("~\\")) {
|
|
2212
|
-
return token;
|
|
2213
|
-
}
|
|
2214
|
-
if (token === "/" || token.startsWith("/") || /^[A-Za-z]:[\\/]/.test(token) || token.startsWith("\\\\")) {
|
|
2215
|
-
return token;
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
return null;
|
|
2219
|
-
}
|
|
2220
|
-
function buildWorkspaceShellEscapeBlockedResult(args) {
|
|
2221
|
-
return {
|
|
2222
|
-
content: [
|
|
2223
|
-
"workspace_shell_escape_blocked",
|
|
2224
|
-
`blockedToken: ${args.token}`,
|
|
2225
|
-
`command: ${args.command}`,
|
|
2226
|
-
"Use paths relative to the authorized folder only.",
|
|
2227
|
-
"exitCode: 126"
|
|
2228
|
-
].join("\n"),
|
|
2229
|
-
metadata: {
|
|
2230
|
-
exitCode: 126,
|
|
2231
|
-
workspaceShellEscapeBlocked: true,
|
|
2232
|
-
blockedToken: args.token
|
|
2233
|
-
}
|
|
2234
|
-
};
|
|
2235
|
-
}
|
|
2236
1653
|
function buildWorkspaceToolDefinition(toolName, args) {
|
|
2237
1654
|
if (toolName === "listFiles") {
|
|
2238
1655
|
return buildListWorkspaceFilesTool({
|
|
@@ -2277,9 +1694,6 @@ function filterDeclaredWorkspaceToolNames(args) {
|
|
|
2277
1694
|
}
|
|
2278
1695
|
|
|
2279
1696
|
// packages/agent-runtime/localWorkspaceTools.ts
|
|
2280
|
-
var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
|
|
2281
|
-
var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
|
|
2282
|
-
var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
|
|
2283
1697
|
var DEFAULT_LOCAL_API_ORIGIN = "http://127.0.0.1:38123";
|
|
2284
1698
|
var ALWAYS_EXCLUDED_GLOBS = [
|
|
2285
1699
|
"*.tsbuildinfo",
|
|
@@ -2312,168 +1726,6 @@ function readBoolean(parsed, key) {
|
|
|
2312
1726
|
}
|
|
2313
1727
|
return void 0;
|
|
2314
1728
|
}
|
|
2315
|
-
function resolveExecShellTimeoutMs(override) {
|
|
2316
|
-
const fromOverride = asOptionalPositiveFiniteNumber(override);
|
|
2317
|
-
if (fromOverride !== void 0) return fromOverride;
|
|
2318
|
-
const raw = process.env[EXEC_SHELL_TIMEOUT_ENV];
|
|
2319
|
-
if (raw === void 0) return void 0;
|
|
2320
|
-
return asOptionalPositiveFiniteNumber(Number(raw));
|
|
2321
|
-
}
|
|
2322
|
-
function resolveDetachMs(override) {
|
|
2323
|
-
if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
|
|
2324
|
-
return override;
|
|
2325
|
-
}
|
|
2326
|
-
const raw = process.env[EXEC_SHELL_DETACH_ENV];
|
|
2327
|
-
if (raw === void 0) return DEFAULT_EXEC_SHELL_DETACH_MS;
|
|
2328
|
-
const parsed = asOptionalPositiveFiniteNumber(Number(raw));
|
|
2329
|
-
return parsed === void 0 ? DEFAULT_EXEC_SHELL_DETACH_MS : parsed;
|
|
2330
|
-
}
|
|
2331
|
-
function extractInteractiveGhAuthCommand(command) {
|
|
2332
|
-
const tokens = tokenizeShellPrefix(command);
|
|
2333
|
-
if (tokens[0] !== "gh" || tokens[1] !== "auth") return null;
|
|
2334
|
-
const subcommand = tokens[2];
|
|
2335
|
-
if (subcommand !== "login" && subcommand !== "refresh") return null;
|
|
2336
|
-
if (tokens.includes("--help")) return null;
|
|
2337
|
-
const result = ["gh", "auth", subcommand];
|
|
2338
|
-
for (let index = 3; index < tokens.length; index += 1) {
|
|
2339
|
-
const token = tokens[index];
|
|
2340
|
-
if (!token) continue;
|
|
2341
|
-
if (token === "-h" || token === "--hostname" || token === "-s" || token === "--scopes" || token === "--remove-scopes" || token === "-r") {
|
|
2342
|
-
const value = tokens[index + 1];
|
|
2343
|
-
if (value) {
|
|
2344
|
-
result.push(token, value);
|
|
2345
|
-
index += 1;
|
|
2346
|
-
}
|
|
2347
|
-
continue;
|
|
2348
|
-
}
|
|
2349
|
-
if (token === "--clipboard" || token === "-c" || token === "--insecure-storage" || token === "--reset-scopes") {
|
|
2350
|
-
result.push(token);
|
|
2351
|
-
continue;
|
|
2352
|
-
}
|
|
2353
|
-
if (token.startsWith("--hostname=") || token.startsWith("--scopes=") || token.startsWith("--remove-scopes=")) {
|
|
2354
|
-
result.push(token);
|
|
2355
|
-
continue;
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
return result.join(" ");
|
|
2359
|
-
}
|
|
2360
|
-
function splitShellWords(command) {
|
|
2361
|
-
return tokenizeShellPrefix(command);
|
|
2362
|
-
}
|
|
2363
|
-
function buildInteractiveCommandBlockedResult(command) {
|
|
2364
|
-
const argv = splitShellWords(command);
|
|
2365
|
-
return {
|
|
2366
|
-
content: [
|
|
2367
|
-
"action_gate: handoff",
|
|
2368
|
-
`command: ${command}`,
|
|
2369
|
-
"Run this in the current TUI terminal, then resume the agent turn.",
|
|
2370
|
-
"exitCode: 130"
|
|
2371
|
-
].join("\n"),
|
|
2372
|
-
metadata: {
|
|
2373
|
-
exitCode: 130,
|
|
2374
|
-
timedOut: false,
|
|
2375
|
-
actionGate: {
|
|
2376
|
-
id: `gate-${Date.now().toString(36)}-terminal-handoff`,
|
|
2377
|
-
kind: "handoff",
|
|
2378
|
-
title: "This command requires an interactive terminal.",
|
|
2379
|
-
body: "Complete it in the terminal, then nolo will continue.",
|
|
2380
|
-
payload: {
|
|
2381
|
-
command: argv,
|
|
2382
|
-
displayCommand: command
|
|
2383
|
-
}
|
|
2384
|
-
},
|
|
2385
|
-
reason: "interactive-command-requires-terminal"
|
|
2386
|
-
}
|
|
2387
|
-
};
|
|
2388
|
-
}
|
|
2389
|
-
function extractActivityRefs(rawRefs) {
|
|
2390
|
-
if (!Array.isArray(rawRefs)) return void 0;
|
|
2391
|
-
const refs = rawRefs.flatMap((entry) => {
|
|
2392
|
-
if (!isRecord(entry)) return [];
|
|
2393
|
-
if (entry.type === "file") {
|
|
2394
|
-
const path = readTrimmedString(entry.path);
|
|
2395
|
-
return path ? [{ type: "file", path }] : [];
|
|
2396
|
-
}
|
|
2397
|
-
if (entry.type === "terminal") {
|
|
2398
|
-
const id = readTrimmedString(entry.id);
|
|
2399
|
-
const label = readTrimmedString(entry.label);
|
|
2400
|
-
return id || label ? [{ type: "terminal", ...id ? { id } : {}, ...label ? { label } : {} }] : [];
|
|
2401
|
-
}
|
|
2402
|
-
if (entry.type === "url") {
|
|
2403
|
-
const url = readTrimmedString(entry.url);
|
|
2404
|
-
const label = readTrimmedString(entry.label);
|
|
2405
|
-
return url ? [{ type: "url", url, ...label ? { label } : {} }] : [];
|
|
2406
|
-
}
|
|
2407
|
-
return [];
|
|
2408
|
-
});
|
|
2409
|
-
return refs.length ? refs : void 0;
|
|
2410
|
-
}
|
|
2411
|
-
function extractActivityAction(rawAction) {
|
|
2412
|
-
if (!isRecord(rawAction)) return void 0;
|
|
2413
|
-
const title = readTrimmedString(rawAction.title);
|
|
2414
|
-
if (!title) return void 0;
|
|
2415
|
-
const kind = readTrimmedString(rawAction.kind);
|
|
2416
|
-
const detail = readTrimmedString(rawAction.detail);
|
|
2417
|
-
const refs = extractActivityRefs(rawAction.refs);
|
|
2418
|
-
return {
|
|
2419
|
-
title,
|
|
2420
|
-
...kind ? { kind } : {},
|
|
2421
|
-
...detail ? { detail } : {},
|
|
2422
|
-
...refs ? { refs } : {}
|
|
2423
|
-
};
|
|
2424
|
-
}
|
|
2425
|
-
function extractActivityPhase(rawPhase) {
|
|
2426
|
-
if (!isRecord(rawPhase)) return void 0;
|
|
2427
|
-
const title = readTrimmedString(rawPhase.title);
|
|
2428
|
-
if (!title) return void 0;
|
|
2429
|
-
const id = readTrimmedString(rawPhase.id) || title.toLowerCase().replace(/\s+/g, "-");
|
|
2430
|
-
const index = asOptionalFiniteNumber(rawPhase.index);
|
|
2431
|
-
const total = asOptionalFiniteNumber(rawPhase.total);
|
|
2432
|
-
const status = rawPhase.status === "pending" || rawPhase.status === "running" || rawPhase.status === "success" || rawPhase.status === "failed" ? rawPhase.status : void 0;
|
|
2433
|
-
return {
|
|
2434
|
-
id,
|
|
2435
|
-
title,
|
|
2436
|
-
...index !== void 0 ? { index } : {},
|
|
2437
|
-
...total !== void 0 ? { total } : {},
|
|
2438
|
-
...status ? { status } : {}
|
|
2439
|
-
};
|
|
2440
|
-
}
|
|
2441
|
-
function extractActivityPlan(rawPlan) {
|
|
2442
|
-
if (!isRecord(rawPlan)) return void 0;
|
|
2443
|
-
if (!Array.isArray(rawPlan.phases)) return void 0;
|
|
2444
|
-
const phases = rawPlan.phases.flatMap((entry, index) => {
|
|
2445
|
-
const phase = extractActivityPhase(entry);
|
|
2446
|
-
if (!phase) return [];
|
|
2447
|
-
return [{
|
|
2448
|
-
id: phase.id,
|
|
2449
|
-
title: phase.title,
|
|
2450
|
-
index: phase.index ?? index + 1,
|
|
2451
|
-
...phase.status ? { status: phase.status } : {}
|
|
2452
|
-
}];
|
|
2453
|
-
});
|
|
2454
|
-
if (phases.length === 0) return void 0;
|
|
2455
|
-
const title = readTrimmedString(rawPlan.title);
|
|
2456
|
-
return {
|
|
2457
|
-
...title ? { title } : {},
|
|
2458
|
-
phases
|
|
2459
|
-
};
|
|
2460
|
-
}
|
|
2461
|
-
function extractActivity(parsed) {
|
|
2462
|
-
const raw = parsed._activity;
|
|
2463
|
-
if (!isRecord(raw)) return void 0;
|
|
2464
|
-
const nestedAction = extractActivityAction(raw.action);
|
|
2465
|
-
const legacyAction = extractActivityAction(raw);
|
|
2466
|
-
const action = nestedAction || legacyAction;
|
|
2467
|
-
const phase = extractActivityPhase(raw.phase);
|
|
2468
|
-
const plan = extractActivityPlan(raw.plan);
|
|
2469
|
-
if (!action && !plan) return void 0;
|
|
2470
|
-
return {
|
|
2471
|
-
...action ? action : {},
|
|
2472
|
-
...phase ? { phase } : {},
|
|
2473
|
-
...nestedAction ? { action: nestedAction } : {},
|
|
2474
|
-
...plan ? { plan } : {}
|
|
2475
|
-
};
|
|
2476
|
-
}
|
|
2477
1729
|
function buildLocalWorkspaceToolset(args) {
|
|
2478
1730
|
const exposeShellTools = args.exposeShellTools === true;
|
|
2479
1731
|
if (args.useDeclaredToolNamesOnly) {
|
|
@@ -2929,22 +2181,6 @@ async function runWorkspacePackageScript(args) {
|
|
|
2929
2181
|
}
|
|
2930
2182
|
};
|
|
2931
2183
|
}
|
|
2932
|
-
function truncateToolOutput(value, limit = 2e4) {
|
|
2933
|
-
if (value.length <= limit) return value;
|
|
2934
|
-
const approxMarkerLen = 40;
|
|
2935
|
-
if (limit <= approxMarkerLen) return value.slice(0, limit);
|
|
2936
|
-
const remaining = limit - approxMarkerLen;
|
|
2937
|
-
const headSize = Math.floor(remaining * 0.3);
|
|
2938
|
-
const tailSize = remaining - headSize;
|
|
2939
|
-
const head = value.slice(0, headSize);
|
|
2940
|
-
const tail = value.slice(-tailSize);
|
|
2941
|
-
const actualRemoved = value.length - headSize - tailSize;
|
|
2942
|
-
return `${head}
|
|
2943
|
-
|
|
2944
|
-
[... truncated ${actualRemoved} chars ...]
|
|
2945
|
-
|
|
2946
|
-
${tail}`;
|
|
2947
|
-
}
|
|
2948
2184
|
function parseLastJsonObject(text) {
|
|
2949
2185
|
const trimmed = text.trim();
|
|
2950
2186
|
for (let index = trimmed.lastIndexOf("{"); index >= 0; index = trimmed.lastIndexOf("{", index - 1)) {
|
|
@@ -2956,57 +2192,11 @@ function parseLastJsonObject(text) {
|
|
|
2956
2192
|
}
|
|
2957
2193
|
return null;
|
|
2958
2194
|
}
|
|
2959
|
-
function readNodeStream(stream) {
|
|
2960
|
-
if (!stream) return Promise.resolve("");
|
|
2961
|
-
return new Promise((resolveRead, rejectRead) => {
|
|
2962
|
-
const chunks = [];
|
|
2963
|
-
stream.on("data", (chunk) => {
|
|
2964
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
2965
|
-
});
|
|
2966
|
-
stream.on("error", rejectRead);
|
|
2967
|
-
stream.on("end", () => resolveRead(Buffer.concat(chunks).toString("utf8")));
|
|
2968
|
-
});
|
|
2969
|
-
}
|
|
2970
|
-
function waitForNodeProcessExit(proc) {
|
|
2971
|
-
return new Promise((resolveExit, rejectExit) => {
|
|
2972
|
-
proc.once("error", rejectExit);
|
|
2973
|
-
proc.once("close", (code, signal) => {
|
|
2974
|
-
if (typeof code === "number") {
|
|
2975
|
-
resolveExit(code);
|
|
2976
|
-
return;
|
|
2977
|
-
}
|
|
2978
|
-
resolveExit(signal ? 1 : 0);
|
|
2979
|
-
});
|
|
2980
|
-
});
|
|
2981
|
-
}
|
|
2982
|
-
function isSpawnFailureError(error) {
|
|
2983
|
-
if (!error || typeof error !== "object") return false;
|
|
2984
|
-
const err = error;
|
|
2985
|
-
if (err.code === "ENOENT") return true;
|
|
2986
|
-
const message = toErrorMessage(error).toLowerCase();
|
|
2987
|
-
return message.includes("enoent") || message.includes("executable not found") || message.includes("spawn") && message.includes("not found");
|
|
2988
|
-
}
|
|
2989
|
-
function spawnFailedCommandResult(error, outputLimit) {
|
|
2990
|
-
const stderr = `spawn failed: ${toErrorMessage(error)}
|
|
2991
|
-
`;
|
|
2992
|
-
return {
|
|
2993
|
-
stdout: "",
|
|
2994
|
-
stderr,
|
|
2995
|
-
exitCode: 127,
|
|
2996
|
-
timedOut: false,
|
|
2997
|
-
spawnFailed: true,
|
|
2998
|
-
content: truncateToolOutput(
|
|
2999
|
-
[`stderr:
|
|
3000
|
-
${stderr.trim()}`, "exitCode: 127"].filter(Boolean).join("\n\n"),
|
|
3001
|
-
outputLimit
|
|
3002
|
-
)
|
|
3003
|
-
};
|
|
3004
|
-
}
|
|
3005
2195
|
function resolveRipgrepBinary(env = process.env) {
|
|
3006
2196
|
const fromEnv = asOptionalTrimmedString(env.NOLO_BUNDLED_RG);
|
|
3007
2197
|
if (fromEnv) {
|
|
3008
2198
|
try {
|
|
3009
|
-
if (
|
|
2199
|
+
if (existsSync(fromEnv)) return fromEnv;
|
|
3010
2200
|
} catch {
|
|
3011
2201
|
}
|
|
3012
2202
|
}
|
|
@@ -3015,178 +2205,6 @@ function resolveRipgrepBinary(env = process.env) {
|
|
|
3015
2205
|
function resolveGrepBinary() {
|
|
3016
2206
|
return resolveExecutableOnPath("grep");
|
|
3017
2207
|
}
|
|
3018
|
-
async function runWorkspaceCommand(args) {
|
|
3019
|
-
const timeoutMs = asOptionalPositiveFiniteNumber(args.timeoutMs);
|
|
3020
|
-
const detached = process.platform !== "win32";
|
|
3021
|
-
const command = [
|
|
3022
|
-
...args.commandPrefix ?? [],
|
|
3023
|
-
...args.command
|
|
3024
|
-
];
|
|
3025
|
-
const proc = spawnChildProcess(command[0] ?? "", command.slice(1), {
|
|
3026
|
-
cwd: resolve(args.workspaceRoot),
|
|
3027
|
-
stdio: [
|
|
3028
|
-
args.stdin === void 0 ? "ignore" : "pipe",
|
|
3029
|
-
"pipe",
|
|
3030
|
-
"pipe"
|
|
3031
|
-
],
|
|
3032
|
-
detached
|
|
3033
|
-
});
|
|
3034
|
-
if (args.stdin !== void 0 && proc.stdin) {
|
|
3035
|
-
proc.stdin.write(args.stdin);
|
|
3036
|
-
proc.stdin.end();
|
|
3037
|
-
}
|
|
3038
|
-
const exitPromise = waitForNodeProcessExit(proc);
|
|
3039
|
-
const cleanupChildOnHostSignal = (signal) => {
|
|
3040
|
-
if (typeof proc.pid === "number") {
|
|
3041
|
-
try {
|
|
3042
|
-
process.kill(-proc.pid, signal);
|
|
3043
|
-
} catch {
|
|
3044
|
-
}
|
|
3045
|
-
}
|
|
3046
|
-
};
|
|
3047
|
-
if (detached) {
|
|
3048
|
-
process.once("SIGHUP", cleanupChildOnHostSignal);
|
|
3049
|
-
process.once("SIGTERM", cleanupChildOnHostSignal);
|
|
3050
|
-
process.once("SIGINT", cleanupChildOnHostSignal);
|
|
3051
|
-
}
|
|
3052
|
-
const detachSignalCleanup = () => {
|
|
3053
|
-
if (!detached) return;
|
|
3054
|
-
process.removeListener("SIGHUP", cleanupChildOnHostSignal);
|
|
3055
|
-
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
3056
|
-
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
3057
|
-
};
|
|
3058
|
-
exitPromise.then(detachSignalCleanup, detachSignalCleanup);
|
|
3059
|
-
const stdoutPromise = readNodeStream(proc.stdout);
|
|
3060
|
-
const stderrPromise = readNodeStream(proc.stderr);
|
|
3061
|
-
const killChild = (signal) => {
|
|
3062
|
-
if (detached && typeof proc.pid === "number") {
|
|
3063
|
-
try {
|
|
3064
|
-
process.kill(-proc.pid, signal);
|
|
3065
|
-
return;
|
|
3066
|
-
} catch {
|
|
3067
|
-
}
|
|
3068
|
-
}
|
|
3069
|
-
try {
|
|
3070
|
-
proc.kill(signal);
|
|
3071
|
-
} catch {
|
|
3072
|
-
}
|
|
3073
|
-
};
|
|
3074
|
-
let timeout;
|
|
3075
|
-
let detachTimer;
|
|
3076
|
-
const timeoutResult = Symbol("timeout");
|
|
3077
|
-
const abortResult = Symbol("abort");
|
|
3078
|
-
const detachResult = Symbol("detach");
|
|
3079
|
-
let abortListener;
|
|
3080
|
-
const abortPromise = args.abortSignal ? new Promise((resolveAbort) => {
|
|
3081
|
-
if (args.abortSignal.aborted) {
|
|
3082
|
-
resolveAbort(abortResult);
|
|
3083
|
-
return;
|
|
3084
|
-
}
|
|
3085
|
-
abortListener = () => resolveAbort(abortResult);
|
|
3086
|
-
args.abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
3087
|
-
}) : null;
|
|
3088
|
-
const effectiveDetachMs = resolveDetachMs(args.detachMs);
|
|
3089
|
-
const detachPromise = new Promise((r) => {
|
|
3090
|
-
detachTimer = setTimeout(() => r(detachResult), effectiveDetachMs);
|
|
3091
|
-
});
|
|
3092
|
-
const racers = [exitPromise];
|
|
3093
|
-
if (timeoutMs) {
|
|
3094
|
-
racers.push(
|
|
3095
|
-
new Promise((resolveTimeout) => {
|
|
3096
|
-
timeout = setTimeout(() => resolveTimeout(timeoutResult), timeoutMs);
|
|
3097
|
-
})
|
|
3098
|
-
);
|
|
3099
|
-
}
|
|
3100
|
-
if (abortPromise) racers.push(abortPromise);
|
|
3101
|
-
racers.push(detachPromise);
|
|
3102
|
-
let raceWinner;
|
|
3103
|
-
try {
|
|
3104
|
-
raceWinner = await Promise.race(racers);
|
|
3105
|
-
} catch (error) {
|
|
3106
|
-
if (timeout) clearTimeout(timeout);
|
|
3107
|
-
if (detachTimer) clearTimeout(detachTimer);
|
|
3108
|
-
if (abortListener && args.abortSignal) {
|
|
3109
|
-
args.abortSignal.removeEventListener("abort", abortListener);
|
|
3110
|
-
}
|
|
3111
|
-
detachSignalCleanup();
|
|
3112
|
-
if (isSpawnFailureError(error)) {
|
|
3113
|
-
return spawnFailedCommandResult(error, args.outputLimit);
|
|
3114
|
-
}
|
|
3115
|
-
throw error;
|
|
3116
|
-
}
|
|
3117
|
-
if (timeout) clearTimeout(timeout);
|
|
3118
|
-
if (detachTimer) clearTimeout(detachTimer);
|
|
3119
|
-
if (abortListener && args.abortSignal) {
|
|
3120
|
-
args.abortSignal.removeEventListener("abort", abortListener);
|
|
3121
|
-
}
|
|
3122
|
-
const timedOut = raceWinner === timeoutResult;
|
|
3123
|
-
const aborted = raceWinner === abortResult;
|
|
3124
|
-
const didDetach = raceWinner === detachResult;
|
|
3125
|
-
if (timedOut || aborted) {
|
|
3126
|
-
killChild("SIGTERM");
|
|
3127
|
-
await Promise.race([
|
|
3128
|
-
exitPromise.catch(() => 124),
|
|
3129
|
-
new Promise((resolveKill) => setTimeout(resolveKill, 500))
|
|
3130
|
-
]);
|
|
3131
|
-
killChild("SIGKILL");
|
|
3132
|
-
}
|
|
3133
|
-
if (didDetach) {
|
|
3134
|
-
exitPromise.catch(() => {
|
|
3135
|
-
});
|
|
3136
|
-
const pid = typeof proc.pid === "number" ? proc.pid : 0;
|
|
3137
|
-
const label = deriveLabel(args.command.join(" "));
|
|
3138
|
-
const pgid = pid;
|
|
3139
|
-
const registry2 = getProcessRegistry();
|
|
3140
|
-
registry2.add({ pid, pgid, command: args.command.join(" "), label });
|
|
3141
|
-
proc.on("close", (code) => {
|
|
3142
|
-
detachSignalCleanup();
|
|
3143
|
-
registry2.markExited(pid, code ?? 1);
|
|
3144
|
-
});
|
|
3145
|
-
const immediate = effectiveDetachMs === 0;
|
|
3146
|
-
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})`;
|
|
3147
|
-
return {
|
|
3148
|
-
stdout: "",
|
|
3149
|
-
stderr: `${reason}
|
|
3150
|
-
Use listProcesses to inspect or stop it.`,
|
|
3151
|
-
exitCode: 0,
|
|
3152
|
-
timedOut: false,
|
|
3153
|
-
detached: true,
|
|
3154
|
-
pid,
|
|
3155
|
-
label,
|
|
3156
|
-
content: JSON.stringify({
|
|
3157
|
-
detached: true,
|
|
3158
|
-
pid,
|
|
3159
|
-
label,
|
|
3160
|
-
status: "running",
|
|
3161
|
-
...immediate ? { reason: "long-running-command" } : {}
|
|
3162
|
-
})
|
|
3163
|
-
};
|
|
3164
|
-
}
|
|
3165
|
-
const [stdout, rawStderr] = await Promise.all([
|
|
3166
|
-
stdoutPromise,
|
|
3167
|
-
stderrPromise
|
|
3168
|
-
]);
|
|
3169
|
-
const exitCode = aborted ? 130 : timedOut ? 124 : Number(raceWinner);
|
|
3170
|
-
const stderr = aborted ? `${rawStderr.trim() ? `${rawStderr.trim()}
|
|
3171
|
-
` : ""}command aborted by signal
|
|
3172
|
-
` : timedOut ? `${rawStderr.trim() ? `${rawStderr.trim()}
|
|
3173
|
-
` : ""}command timed out after ${timeoutMs ?? "unknown"}ms
|
|
3174
|
-
` : rawStderr;
|
|
3175
|
-
return {
|
|
3176
|
-
stdout,
|
|
3177
|
-
stderr,
|
|
3178
|
-
exitCode,
|
|
3179
|
-
timedOut,
|
|
3180
|
-
aborted,
|
|
3181
|
-
content: truncateToolOutput([
|
|
3182
|
-
stdout.trim() ? `stdout:
|
|
3183
|
-
${stdout.trim()}` : "",
|
|
3184
|
-
stderr.trim() ? `stderr:
|
|
3185
|
-
${stderr.trim()}` : "",
|
|
3186
|
-
`exitCode: ${exitCode}`
|
|
3187
|
-
].filter(Boolean).join("\n\n"), args.outputLimit)
|
|
3188
|
-
};
|
|
3189
|
-
}
|
|
3190
2208
|
async function runWorkspaceCommandLimitedLines(args) {
|
|
3191
2209
|
const command = [
|
|
3192
2210
|
...args.commandPrefix ?? [],
|
|
@@ -4045,63 +3063,24 @@ async function captureVisualStateTool(args) {
|
|
|
4045
3063
|
};
|
|
4046
3064
|
}
|
|
4047
3065
|
async function execShellTool(args) {
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
...activity2 ? { activity: activity2 } : {}
|
|
4065
|
-
}
|
|
4066
|
-
};
|
|
4067
|
-
}
|
|
4068
|
-
const result = await runWorkspaceCommand({
|
|
4069
|
-
workspaceRoot: args.workspaceRoot,
|
|
4070
|
-
command: buildWorkspaceShellCommand({
|
|
4071
|
-
toolName: args.call.name,
|
|
4072
|
-
command,
|
|
4073
|
-
shell: parsed.shell
|
|
4074
|
-
}),
|
|
4075
|
-
timeoutMs: resolveExecShellTimeoutMs(args.commandTimeoutMs),
|
|
4076
|
-
outputLimit: args.commandOutputLimit,
|
|
4077
|
-
commandPrefix: args.commandPrefix,
|
|
4078
|
-
abortSignal: args.abortSignal,
|
|
4079
|
-
// Commands that clearly never exit (long sleeps, tail -f, watch, dev
|
|
4080
|
-
// servers, infinite loops) are promoted to background immediately so the
|
|
4081
|
-
// turn — and the user's conversation — keeps going. Everything else keeps
|
|
4082
|
-
// the caller/env detach grace window.
|
|
4083
|
-
detachMs: isImmediateDetachShellCommand({ command }) ? 0 : args.detachMs
|
|
4084
|
-
});
|
|
4085
|
-
const activity = extractActivity(parsed);
|
|
4086
|
-
return {
|
|
4087
|
-
content: result.content,
|
|
4088
|
-
metadata: {
|
|
4089
|
-
command,
|
|
4090
|
-
exitCode: result.exitCode,
|
|
4091
|
-
timedOut: result.timedOut,
|
|
4092
|
-
...result.aborted ? { aborted: true } : {},
|
|
4093
|
-
...result.detached ? { detached: true, pid: result.pid, label: result.label, status: "running" } : {},
|
|
4094
|
-
...activity ? { activity } : {}
|
|
3066
|
+
return invokeCapability(
|
|
3067
|
+
"execShell",
|
|
3068
|
+
args.call.arguments,
|
|
3069
|
+
{
|
|
3070
|
+
workspaceRoot: args.workspaceRoot,
|
|
3071
|
+
commandTimeoutMs: args.commandTimeoutMs,
|
|
3072
|
+
commandOutputLimit: args.commandOutputLimit,
|
|
3073
|
+
commandPrefix: args.commandPrefix,
|
|
3074
|
+
restrictToWorkspace: args.restrictToWorkspace,
|
|
3075
|
+
abortSignal: args.abortSignal,
|
|
3076
|
+
detachMs: args.detachMs,
|
|
3077
|
+
confirmed: args.confirmed,
|
|
3078
|
+
enableDestructiveShellGuard: args.enableDestructiveShellGuard,
|
|
3079
|
+
confirmDestructiveAction: args.confirmDestructiveAction,
|
|
3080
|
+
blockDestructiveWithoutConfirmation: args.blockDestructiveWithoutConfirmation,
|
|
3081
|
+
onInvoke: args.onInvoke
|
|
4095
3082
|
}
|
|
4096
|
-
|
|
4097
|
-
}
|
|
4098
|
-
function deriveLabel(command) {
|
|
4099
|
-
const trimmed = command.trim();
|
|
4100
|
-
if (!trimmed) return "process";
|
|
4101
|
-
const tokens = trimmed.split(/\s+/);
|
|
4102
|
-
const lastToken = tokens[tokens.length - 1] ?? trimmed;
|
|
4103
|
-
const labelCandidate = lastToken.split(/[/\\]/).pop() || lastToken;
|
|
4104
|
-
return labelCandidate || trimmed;
|
|
3083
|
+
);
|
|
4105
3084
|
}
|
|
4106
3085
|
async function launchProcessTool(args) {
|
|
4107
3086
|
const parsed = parseWorkspaceToolArguments(args.call.arguments);
|
|
@@ -4138,8 +3117,8 @@ async function launchProcessTool(args) {
|
|
|
4138
3117
|
};
|
|
4139
3118
|
}
|
|
4140
3119
|
const pgid = detached ? pid : pid;
|
|
4141
|
-
const
|
|
4142
|
-
|
|
3120
|
+
const registry = getProcessRegistry();
|
|
3121
|
+
registry.add({ pid, pgid, command, label, persist });
|
|
4143
3122
|
const cleanupChildOnHostSignal = (signal) => {
|
|
4144
3123
|
try {
|
|
4145
3124
|
if (detached) {
|
|
@@ -4161,7 +3140,7 @@ async function launchProcessTool(args) {
|
|
|
4161
3140
|
process.removeListener("SIGTERM", cleanupChildOnHostSignal);
|
|
4162
3141
|
process.removeListener("SIGINT", cleanupChildOnHostSignal);
|
|
4163
3142
|
}
|
|
4164
|
-
|
|
3143
|
+
registry.markExited(pid, code ?? 1);
|
|
4165
3144
|
});
|
|
4166
3145
|
const activity = extractActivity(parsed);
|
|
4167
3146
|
const resultData = { pid, label, status: "running" };
|
|
@@ -4241,7 +3220,12 @@ function createLocalWorkspaceToolExecutors(args) {
|
|
|
4241
3220
|
commandPrefix: args.commandPrefix,
|
|
4242
3221
|
restrictToWorkspace: args.restrictShellToWorkspace,
|
|
4243
3222
|
abortSignal: opts?.abortSignal ?? args.abortSignal,
|
|
4244
|
-
detachMs: opts?.detachMs ?? args.detachMs
|
|
3223
|
+
detachMs: opts?.detachMs ?? args.detachMs,
|
|
3224
|
+
confirmed: opts?.confirmed,
|
|
3225
|
+
enableDestructiveShellGuard: opts?.enableDestructiveShellGuard,
|
|
3226
|
+
confirmDestructiveAction: opts?.confirmDestructiveAction,
|
|
3227
|
+
blockDestructiveWithoutConfirmation: opts?.blockDestructiveWithoutConfirmation,
|
|
3228
|
+
onInvoke: opts?.onInvoke
|
|
4245
3229
|
}),
|
|
4246
3230
|
launchProcess: (call) => launchProcessTool({
|
|
4247
3231
|
call,
|
|
@@ -4280,11 +3264,11 @@ async function readNoloProcessStream(readable) {
|
|
|
4280
3264
|
async function runNoloWorkspaceCliTool(call, args) {
|
|
4281
3265
|
const cliArgs = buildNoloWorkspaceCommandArgs(call);
|
|
4282
3266
|
const bunSpawn = globalThis.Bun?.spawn;
|
|
4283
|
-
const
|
|
3267
|
+
const spawn = args.spawn ?? (typeof bunSpawn === "function" ? bunSpawn : nodeSpawnFallback);
|
|
4284
3268
|
const execPath = args.processExecPath ?? process.execPath;
|
|
4285
3269
|
const entrypoint = args.cliEntrypoint;
|
|
4286
3270
|
const cmd = entrypoint && entrypoint !== execPath ? [execPath, entrypoint, ...cliArgs] : [execPath, ...cliArgs];
|
|
4287
|
-
const proc =
|
|
3271
|
+
const proc = spawn({
|
|
4288
3272
|
cmd,
|
|
4289
3273
|
stdout: "pipe",
|
|
4290
3274
|
stderr: "pipe",
|
|
@@ -4386,10 +3370,10 @@ function buildLoadSkillExecutor(args) {
|
|
|
4386
3370
|
metadata: { loadSkill: true, resolved: false }
|
|
4387
3371
|
};
|
|
4388
3372
|
}
|
|
4389
|
-
const { resolveSkillByName } = await import("./skillDiscovery-
|
|
3373
|
+
const { resolveSkillByName } = await import("./skillDiscovery-AYBKAG6X.js");
|
|
4390
3374
|
const resolved = resolveSkillByName(args.cwd, name);
|
|
4391
3375
|
if (!resolved) {
|
|
4392
|
-
const { resolveCodingBuiltinSlug, buildCodingSkillContentBySlug } = await import("./codingSkills-
|
|
3376
|
+
const { resolveCodingBuiltinSlug, buildCodingSkillContentBySlug } = await import("./codingSkills-5VOV3JVB.js");
|
|
4393
3377
|
const builtinSlug = resolveCodingBuiltinSlug(name);
|
|
4394
3378
|
if (builtinSlug) {
|
|
4395
3379
|
const body = buildCodingSkillContentBySlug(builtinSlug);
|
|
@@ -4424,7 +3408,7 @@ ${body}`,
|
|
|
4424
3408
|
};
|
|
4425
3409
|
}
|
|
4426
3410
|
async function formatUnknownSkillMessage(cwd, requestedName) {
|
|
4427
|
-
const { discoverSkills } = await import("./skillDiscovery-
|
|
3411
|
+
const { discoverSkills } = await import("./skillDiscovery-AYBKAG6X.js");
|
|
4428
3412
|
let available = [];
|
|
4429
3413
|
try {
|
|
4430
3414
|
available = discoverSkills(cwd).map((s) => s.name);
|
|
@@ -4456,13 +3440,10 @@ export {
|
|
|
4456
3440
|
shouldCacheHybridRemoteRecord,
|
|
4457
3441
|
parseSyncServersEnv,
|
|
4458
3442
|
createHybridRecordStore,
|
|
4459
|
-
isDestructiveShellCommand,
|
|
4460
|
-
evaluateShellCommandPolicy,
|
|
4461
3443
|
resolveLocalToolPolicy,
|
|
4462
3444
|
executeLocalToolWithPolicy,
|
|
4463
3445
|
filterRetainedLedgerRecords,
|
|
4464
3446
|
isLineRangeCovered,
|
|
4465
|
-
getProcessRegistry,
|
|
4466
3447
|
buildLocalWorkspaceToolset,
|
|
4467
3448
|
buildLocalWorkspacePolicyToolNames,
|
|
4468
3449
|
buildLocalWorkspaceOpenAiTools,
|