nolo-cli 0.179.0-alpha.1 → 0.180.0-alpha.2
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-ZP6M2EWK.js → _executeModel-ACI2KGWO.js} +19 -19
- package/{accountResolver-OHS53Q75.js → accountResolver-HPVXZJYD.js} +1 -1
- package/{agentDeleteCommand-7TH3MY5U.js → agentDeleteCommand-LVSLONDD.js} +21 -21
- package/{agentEmailCommands-LVSCPVGC.js → agentEmailCommands-BKH3Q6I6.js} +22 -22
- package/{agentListCommands-67HVR7KB.js → agentListCommands-JPKRBHMP.js} +10 -10
- package/{agentMachineCommands-36IZWYUV.js → agentMachineCommands-HRORJN73.js} +8 -8
- package/{agentRecordCommands-4AIFNXVY.js → agentRecordCommands-OSZF2EHL.js} +21 -21
- package/{agentRunCommand-3B224VOA.js → agentRunCommand-FCGNSB4D.js} +22 -22
- package/{agentRuntimeLocal-I4J6XDO7.js → agentRuntimeLocal-SWG5ULIJ.js} +5 -5
- package/{agentSlice-XYVD7VDW.js → agentSlice-FCDRLXVA.js} +1 -1
- package/{appDeleteCommands-VBI7C4IO.js → appDeleteCommands-YH3BYQYK.js} +9 -9
- package/{appDeployCommands-FYUG5XWE.js → appDeployCommands-F44TNQJG.js} +9 -9
- package/{appDeployStatusCommands-TYHJOMUA.js → appDeployStatusCommands-BFTGFVQY.js} +9 -9
- package/{appGetCommands-HINYK5UT.js → appGetCommands-SFLFIXPW.js} +9 -9
- package/{appListCommands-NWDNQT4A.js → appListCommands-RUO5SEAJ.js} +9 -9
- package/{builtinSkillRegistry-V76JTNCJ.js → builtinSkillRegistry-MRI4FNCR.js} +4 -4
- package/{chromeCommands-VANHVOCE.js → chromeCommands-BGL6JZMB.js} +1 -1
- package/{chromeOpsCommands-RY776THN.js → chromeOpsCommands-IWKUA4C3.js} +37 -10
- package/{chunk-KPSNHLFI.js → chunk-2D3YKEAQ.js} +1 -1
- package/{chunk-BAXCQF6H.js → chunk-4FZUUCXQ.js} +1 -1
- package/{chunk-CUVJE3L5.js → chunk-4KDYRX3O.js} +2 -2
- package/{chunk-3LNVSFTH.js → chunk-5LZBJZLT.js} +2 -2
- package/{chunk-Y3BUTWUJ.js → chunk-6PHS6ADB.js} +2 -2
- package/{chunk-GPA3EA3Q.js → chunk-CGKN34IJ.js} +15 -15
- package/{chunk-UVPKOBVG.js → chunk-COXNBVP7.js} +4 -4
- package/{chunk-RPZNVBA5.js → chunk-CTEEJJVR.js} +1 -1
- package/{chunk-UTZF3X4Z.js → chunk-DTA4JVXW.js} +3 -3
- package/{chunk-LY4HX6OD.js → chunk-DVSXZC7F.js} +9 -9
- package/{chunk-RUKAOMXD.js → chunk-EAWOT7M6.js} +1 -1
- package/{chunk-IAOVXFL7.js → chunk-GCAOOTIS.js} +3 -3
- package/{chunk-L7PTHI3I.js → chunk-GHKEUJ6I.js} +2 -2
- package/{chunk-YUXSWHQC.js → chunk-GKKIZRJ6.js} +29 -3
- package/{chunk-ENIQIEAF.js → chunk-H63VHVFY.js} +1 -1
- package/{chunk-PP4TMS3T.js → chunk-HS7JBDUJ.js} +3 -3
- package/{chunk-YOXGSXOV.js → chunk-HTSXDJHA.js} +8 -8
- package/{chunk-QWNMFO5E.js → chunk-KUGOIFXV.js} +3 -3
- package/{chunk-NYYFIKHI.js → chunk-MMKP2XWK.js} +35 -6
- package/{chunk-FSTHTTI6.js → chunk-NJI5HZQA.js} +3 -3
- package/{chunk-EEEBL4MX.js → chunk-OBKPOFOB.js} +7 -7
- package/{chunk-P34IX26T.js → chunk-OXYSTN6B.js} +1 -1
- package/{chunk-M7ZURZLR.js → chunk-PD4KNHVU.js} +3 -3
- package/{chunk-ZEOR6XPJ.js → chunk-POYXVOYU.js} +2 -2
- package/{chunk-CIM3IW2X.js → chunk-PT6335JZ.js} +2 -2
- package/{chunk-LRXTGAZ4.js → chunk-QOKJFYJK.js} +7 -7
- package/{chunk-X7YSFSY3.js → chunk-QUCQVMYZ.js} +4 -4
- package/{chunk-LOCHKPC4.js → chunk-SGATEZV5.js} +14 -14
- package/{chunk-WXOKJP3W.js → chunk-SK2UMOZC.js} +1 -1
- package/{chunk-LM7VJUSD.js → chunk-TCCBECTT.js} +1 -1
- package/{chunk-NQKFBJD4.js → chunk-WQAOAJ5Q.js} +2 -2
- package/{chunk-5EBLANFT.js → chunk-XJBWPOIL.js} +1 -1
- package/{chunk-IU4FJDRU.js → chunk-YAN7XTXO.js} +5 -5
- package/{chunk-2GRXE3YJ.js → chunk-ZEQ6L6MZ.js} +1 -1
- package/{commandRegistry-OW2MIVIT.js → commandRegistry-UQ4GKJ5B.js} +48 -44
- package/{contentThunks-WNBEFSCD.js → contentThunks-GZUPF67H.js} +3 -3
- package/{createAgentAutomationAction-NTL5ST3J.js → createAgentAutomationAction-ZOFCBZRE.js} +3 -3
- package/{createDialogAction-JWGDTE6S.js → createDialogAction-G7QCYQT7.js} +6 -6
- package/{createPageAction-FPM5RD4C.js → createPageAction-Z6JQZYS5.js} +3 -3
- package/{dialogCommands-D4MNLDBH.js → dialogCommands-MITLWDBY.js} +9 -9
- package/{dialogSlice-QVQO4JCU.js → dialogSlice-PKFXK5WM.js} +2 -2
- package/{docCreateCommands-765YJTNP.js → docCreateCommands-G3S3LZMZ.js} +8 -8
- package/{docDeleteCommands-G5U77546.js → docDeleteCommands-MLRCMLVB.js} +9 -9
- package/{docReadCommands-5YU7WGGT.js → docReadCommands-6A6SBCOP.js} +8 -8
- package/{docStore-VN2HSHLZ.js → docStore-NAEY4CEK.js} +1 -1
- package/{docUpdateCommands-H2AHPZRW.js → docUpdateCommands-UZQC2NDO.js} +8 -8
- package/{handleSendMessageAction-DMXH4YLX.js → handleSendMessageAction-HUQLERJP.js} +11 -11
- package/index.js +3 -3
- package/{localRuntimeAdapter-CQH4RFZC.js → localRuntimeAdapter-4DJDFM7A.js} +19 -19
- package/{machineCommands-TVCJZ5K5.js → machineCommands-R2IP5OVT.js} +321 -112
- package/{machineWsRunDispatch-663CSUA3.js → machineWsRunDispatch-CIJDSHTA.js} +20 -20
- package/package.json +1 -1
- package/{readlineWorkspace-PSJS3ZS2.js → readlineWorkspace-YCNAWRDL.js} +25 -25
- package/{runAgentClientLoop-J3CTCBSI.js → runAgentClientLoop-K7WRMT27.js} +17 -17
- package/{spaceCommands-2ESFYAZG.js → spaceCommands-L537SH5I.js} +8 -8
- package/{streamAgentChatTurn-Z4DGKLGP.js → streamAgentChatTurn-HKUZ7OCA.js} +19 -19
- package/{tools-A2L3DK2Y.js → tools-NS37KPGT.js} +13 -13
- package/{updateDialogTitleAction-WM5YYYFZ.js → updateDialogTitleAction-UUZ5HDM2.js} +3 -3
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
buildMachinePermissionPromptBlock,
|
|
3
3
|
handleConnectorRunMessage,
|
|
4
4
|
resolveMachineRunPermissionPolicy
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QUCQVMYZ.js";
|
|
6
6
|
import {
|
|
7
7
|
MAX_CONNECTOR_TIMER_DELAY_MS,
|
|
8
8
|
clampConnectorTimerDelayMs,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
resolveConnectorProbeTimeoutMs,
|
|
12
12
|
resolveConnectorWebSocketTarget
|
|
13
13
|
} from "./chunk-BLVSFYQ3.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-SGATEZV5.js";
|
|
15
15
|
import "./chunk-D2J22QSE.js";
|
|
16
16
|
import "./chunk-R4BMKAR5.js";
|
|
17
17
|
import "./chunk-TDX2L4W2.js";
|
|
@@ -19,26 +19,27 @@ import {
|
|
|
19
19
|
parsePositiveFiniteNumberOrFallback
|
|
20
20
|
} from "./chunk-Y5GCAMGP.js";
|
|
21
21
|
import "./chunk-VP3BINY7.js";
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-CTEEJJVR.js";
|
|
23
23
|
import "./chunk-NBTY7YJF.js";
|
|
24
24
|
import "./chunk-VL5KOY2C.js";
|
|
25
25
|
import {
|
|
26
|
-
detectMachineInfo
|
|
26
|
+
detectMachineInfo,
|
|
27
|
+
resolveMachineId
|
|
27
28
|
} from "./chunk-S73EPYNC.js";
|
|
28
29
|
import "./chunk-ZEZC7IIM.js";
|
|
29
30
|
import "./chunk-VIWDGTDA.js";
|
|
30
31
|
import "./chunk-HGDKT2D6.js";
|
|
31
|
-
import "./chunk-
|
|
32
|
+
import "./chunk-GKKIZRJ6.js";
|
|
32
33
|
import "./chunk-W6E5IXIP.js";
|
|
33
34
|
import "./chunk-ATNTHIZI.js";
|
|
34
35
|
import "./chunk-INFHX73M.js";
|
|
35
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-GCAOOTIS.js";
|
|
36
37
|
import "./chunk-HS7MLR74.js";
|
|
37
|
-
import "./chunk-
|
|
38
|
-
import "./chunk-
|
|
38
|
+
import "./chunk-CGKN34IJ.js";
|
|
39
|
+
import "./chunk-2D3YKEAQ.js";
|
|
39
40
|
import "./chunk-KFHREHUQ.js";
|
|
40
41
|
import "./chunk-OXME3PEE.js";
|
|
41
|
-
import "./chunk-
|
|
42
|
+
import "./chunk-NJI5HZQA.js";
|
|
42
43
|
import "./chunk-NF64D32W.js";
|
|
43
44
|
import {
|
|
44
45
|
CORE_DRAIN_REASON
|
|
@@ -52,17 +53,17 @@ import "./chunk-KSTEXKL6.js";
|
|
|
52
53
|
import "./chunk-AGIM7IMJ.js";
|
|
53
54
|
import "./chunk-63W5N6P3.js";
|
|
54
55
|
import "./chunk-VF4K2QE6.js";
|
|
55
|
-
import "./chunk-
|
|
56
|
+
import "./chunk-4KDYRX3O.js";
|
|
56
57
|
import "./chunk-BAWAKW7X.js";
|
|
57
|
-
import "./chunk-
|
|
58
|
+
import "./chunk-PD4KNHVU.js";
|
|
58
59
|
import "./chunk-IF7V3CBU.js";
|
|
59
60
|
import "./chunk-YPG7TUQD.js";
|
|
60
|
-
import "./chunk-
|
|
61
|
-
import "./chunk-
|
|
61
|
+
import "./chunk-TCCBECTT.js";
|
|
62
|
+
import "./chunk-HTSXDJHA.js";
|
|
62
63
|
import "./chunk-OFFL4DCR.js";
|
|
63
64
|
import "./chunk-523DITKR.js";
|
|
64
65
|
import "./chunk-QYPE3TS3.js";
|
|
65
|
-
import "./chunk-
|
|
66
|
+
import "./chunk-HS7JBDUJ.js";
|
|
66
67
|
import "./chunk-4JH2UMJR.js";
|
|
67
68
|
import "./chunk-ZJ7UHBJS.js";
|
|
68
69
|
import "./chunk-BYXBJQAS.js";
|
|
@@ -88,8 +89,8 @@ import "./chunk-QQ56R7KS.js";
|
|
|
88
89
|
import "./chunk-OW765XBU.js";
|
|
89
90
|
import "./chunk-PXYBUFDB.js";
|
|
90
91
|
import "./chunk-D2MDMY2M.js";
|
|
91
|
-
import "./chunk-
|
|
92
|
-
import "./chunk-
|
|
92
|
+
import "./chunk-5LZBJZLT.js";
|
|
93
|
+
import "./chunk-SK2UMOZC.js";
|
|
93
94
|
import "./chunk-EUGTFFO6.js";
|
|
94
95
|
import "./chunk-AETZ7AD6.js";
|
|
95
96
|
import "./chunk-Y6ORVLSS.js";
|
|
@@ -99,7 +100,7 @@ import {
|
|
|
99
100
|
PATH_FIELD_ALIASES,
|
|
100
101
|
createLocalWorkspaceToolExecutors,
|
|
101
102
|
resolveRequestedWorkspacePath
|
|
102
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-COXNBVP7.js";
|
|
103
104
|
import "./chunk-KMSMIOOL.js";
|
|
104
105
|
import "./chunk-ZNFJWEN4.js";
|
|
105
106
|
import "./chunk-YO776XHS.js";
|
|
@@ -113,10 +114,10 @@ import "./chunk-P2BGRAW7.js";
|
|
|
113
114
|
import "./chunk-G6OOUQWJ.js";
|
|
114
115
|
import "./chunk-56GBUMO5.js";
|
|
115
116
|
import "./chunk-WJZOQR2J.js";
|
|
116
|
-
import "./chunk-
|
|
117
|
+
import "./chunk-POYXVOYU.js";
|
|
117
118
|
import "./chunk-JDCX5RWD.js";
|
|
118
119
|
import "./chunk-E2BESSAW.js";
|
|
119
|
-
import "./chunk-
|
|
120
|
+
import "./chunk-ZEQ6L6MZ.js";
|
|
120
121
|
import "./chunk-JLR5NWP2.js";
|
|
121
122
|
import "./chunk-XAFCJN32.js";
|
|
122
123
|
import "./chunk-2MBTWINN.js";
|
|
@@ -133,8 +134,8 @@ import "./chunk-7DPNBQSV.js";
|
|
|
133
134
|
import "./chunk-ZWQUWF6W.js";
|
|
134
135
|
import "./chunk-VEA7H5FG.js";
|
|
135
136
|
import "./chunk-4VJAC32I.js";
|
|
136
|
-
import "./chunk-
|
|
137
|
-
import "./chunk-
|
|
137
|
+
import "./chunk-XJBWPOIL.js";
|
|
138
|
+
import "./chunk-MMKP2XWK.js";
|
|
138
139
|
import "./chunk-LOEO7LRC.js";
|
|
139
140
|
import "./chunk-M2EJHDJP.js";
|
|
140
141
|
import "./chunk-5EMSBTQ6.js";
|
|
@@ -194,11 +195,169 @@ async function runHeartbeatLoop(options) {
|
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
197
|
|
|
198
|
+
// packages/cli/connectorInstanceLock.ts
|
|
199
|
+
import {
|
|
200
|
+
closeSync,
|
|
201
|
+
mkdirSync,
|
|
202
|
+
openSync,
|
|
203
|
+
readFileSync,
|
|
204
|
+
renameSync,
|
|
205
|
+
statSync,
|
|
206
|
+
unlinkSync,
|
|
207
|
+
writeFileSync
|
|
208
|
+
} from "node:fs";
|
|
209
|
+
import { homedir } from "node:os";
|
|
210
|
+
import { join } from "node:path";
|
|
211
|
+
function resolveConnectorStateDir(args = {}) {
|
|
212
|
+
const homeDir = args.homeDir?.trim();
|
|
213
|
+
if (homeDir) return join(homeDir, ".nolo", "connector");
|
|
214
|
+
const noloHome = args.noloHome?.trim() || process.env.NOLO_HOME?.trim();
|
|
215
|
+
if (noloHome) return join(noloHome, "connector");
|
|
216
|
+
return join(homedir(), ".nolo", "connector");
|
|
217
|
+
}
|
|
218
|
+
function sanitizeMachineId(machineId) {
|
|
219
|
+
const safe = String(machineId ?? "").replace(/[^A-Za-z0-9._-]/g, "_");
|
|
220
|
+
return safe || "unknown";
|
|
221
|
+
}
|
|
222
|
+
function connectorInstanceLockPath(args) {
|
|
223
|
+
return join(resolveConnectorStateDir(args), `${sanitizeMachineId(args.machineId)}.lock`);
|
|
224
|
+
}
|
|
225
|
+
function connectorAliveSignalPath(args) {
|
|
226
|
+
return join(resolveConnectorStateDir(args), `${sanitizeMachineId(args.machineId)}.alive`);
|
|
227
|
+
}
|
|
228
|
+
function isProcessAlive(pid) {
|
|
229
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
230
|
+
try {
|
|
231
|
+
process.kill(pid, 0);
|
|
232
|
+
return true;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
return error?.code === "EPERM";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function readLockPid(lockPath) {
|
|
238
|
+
let raw;
|
|
239
|
+
try {
|
|
240
|
+
raw = readFileSync(lockPath, "utf8");
|
|
241
|
+
} catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const parsed = JSON.parse(raw);
|
|
246
|
+
const pid = Number(parsed?.pid);
|
|
247
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
248
|
+
} catch {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function isEexist(error) {
|
|
253
|
+
return error?.code === "EEXIST";
|
|
254
|
+
}
|
|
255
|
+
var CONNECTOR_LOCK_CORRUPT_RECLAIM_SECONDS = 300;
|
|
256
|
+
function inspectCorruptLock(lockPath, now = Date.now()) {
|
|
257
|
+
try {
|
|
258
|
+
const stat2 = statSync(lockPath);
|
|
259
|
+
const ageMs = now - stat2.mtimeMs;
|
|
260
|
+
return ageMs > CONNECTOR_LOCK_CORRUPT_RECLAIM_SECONDS * 1e3 ? "expired" : "fresh";
|
|
261
|
+
} catch (error) {
|
|
262
|
+
const code = error?.code;
|
|
263
|
+
if (code === "ENOENT") return "gone";
|
|
264
|
+
return "fresh";
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function acquireConnectorInstanceLock(args) {
|
|
268
|
+
const lockPath = connectorInstanceLockPath(args);
|
|
269
|
+
mkdirSync(resolveConnectorStateDir(args), { recursive: true });
|
|
270
|
+
let reclaimed;
|
|
271
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
272
|
+
let fd = null;
|
|
273
|
+
try {
|
|
274
|
+
fd = openSync(lockPath, "wx");
|
|
275
|
+
} catch (error) {
|
|
276
|
+
if (!isEexist(error)) throw error;
|
|
277
|
+
const ownerPid2 = readLockPid(lockPath);
|
|
278
|
+
if (ownerPid2 !== null) {
|
|
279
|
+
if (isProcessAlive(ownerPid2)) {
|
|
280
|
+
return { ok: false, pid: ownerPid2 };
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
unlinkSync(lockPath);
|
|
284
|
+
} catch {
|
|
285
|
+
}
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
const state = inspectCorruptLock(lockPath);
|
|
289
|
+
if (state === "gone") {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
if (state === "fresh") {
|
|
293
|
+
return { ok: false, pid: 0 };
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
unlinkSync(lockPath);
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
299
|
+
reclaimed = "corrupt";
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
writeFileSync(fd, JSON.stringify({ pid: process.pid, startedAt: Date.now() }), "utf8");
|
|
304
|
+
} finally {
|
|
305
|
+
closeSync(fd);
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
ok: true,
|
|
309
|
+
release: () => releaseConnectorInstanceLock(lockPath),
|
|
310
|
+
...reclaimed ? { reclaimed } : {}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const ownerPid = readLockPid(lockPath);
|
|
314
|
+
return { ok: false, pid: ownerPid ?? 0 };
|
|
315
|
+
}
|
|
316
|
+
function releaseConnectorInstanceLock(lockPath) {
|
|
317
|
+
const ownerPid = readLockPid(lockPath);
|
|
318
|
+
if (ownerPid !== process.pid) return;
|
|
319
|
+
try {
|
|
320
|
+
unlinkSync(lockPath);
|
|
321
|
+
} catch {
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function markConnectorAlive(args) {
|
|
325
|
+
const path = connectorAliveSignalPath(args);
|
|
326
|
+
try {
|
|
327
|
+
mkdirSync(resolveConnectorStateDir(args), { recursive: true });
|
|
328
|
+
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
329
|
+
writeFileSync(tmpPath, String(Date.now()), "utf8");
|
|
330
|
+
try {
|
|
331
|
+
renameSync(tmpPath, path);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
try {
|
|
334
|
+
unlinkSync(tmpPath);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
} catch {
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function clearConnectorAlive(args) {
|
|
343
|
+
try {
|
|
344
|
+
unlinkSync(connectorAliveSignalPath(args));
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function withConnectorAliveSignal(sendHeartbeat, args) {
|
|
349
|
+
return async () => {
|
|
350
|
+
const result = await sendHeartbeat();
|
|
351
|
+
markConnectorAlive(args);
|
|
352
|
+
return result;
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
197
356
|
// packages/cli/machineDaemonCommands.ts
|
|
198
357
|
import { spawn } from "node:child_process";
|
|
199
|
-
import { existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
200
|
-
import { homedir } from "node:os";
|
|
201
|
-
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
358
|
+
import { existsSync, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync2, readdirSync, realpathSync } from "node:fs";
|
|
359
|
+
import { homedir as homedir2 } from "node:os";
|
|
360
|
+
import { dirname, isAbsolute, join as join2, relative, resolve } from "node:path";
|
|
202
361
|
import { fileURLToPath } from "node:url";
|
|
203
362
|
var CONNECTOR_RUNTIME_WORKSPACE_PACKAGES = /* @__PURE__ */ new Set([
|
|
204
363
|
"connector-experimental",
|
|
@@ -206,7 +365,7 @@ var CONNECTOR_RUNTIME_WORKSPACE_PACKAGES = /* @__PURE__ */ new Set([
|
|
|
206
365
|
]);
|
|
207
366
|
function readJsonFile(path) {
|
|
208
367
|
try {
|
|
209
|
-
return JSON.parse(
|
|
368
|
+
return JSON.parse(readFileSync2(path, "utf8"));
|
|
210
369
|
} catch {
|
|
211
370
|
return null;
|
|
212
371
|
}
|
|
@@ -226,7 +385,7 @@ function isInsideOrSame(path, parent) {
|
|
|
226
385
|
function findWorkspaceRoot(startPath) {
|
|
227
386
|
let current = resolve(startPath);
|
|
228
387
|
while (true) {
|
|
229
|
-
const packageJsonPath =
|
|
388
|
+
const packageJsonPath = join2(current, "package.json");
|
|
230
389
|
if (existsSync(packageJsonPath)) {
|
|
231
390
|
const packageJson = readJsonFile(packageJsonPath);
|
|
232
391
|
if (packageJson && getWorkspacePatterns(packageJson).length > 0) {
|
|
@@ -249,7 +408,7 @@ function listWorkspacePackageJsonFiles(workspaceParent) {
|
|
|
249
408
|
for (const entry of entries) {
|
|
250
409
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
251
410
|
const relativePath = `${entry.name}/package.json`;
|
|
252
|
-
if (existsSync(
|
|
411
|
+
if (existsSync(join2(workspaceParent, relativePath))) {
|
|
253
412
|
results.push(relativePath);
|
|
254
413
|
}
|
|
255
414
|
}
|
|
@@ -258,21 +417,21 @@ function listWorkspacePackageJsonFiles(workspaceParent) {
|
|
|
258
417
|
function validateConnectorWorkspaceLinks(cwd) {
|
|
259
418
|
const repoRoot = findWorkspaceRoot(cwd);
|
|
260
419
|
if (!repoRoot) return [];
|
|
261
|
-
const rootPackageJson = readJsonFile(
|
|
420
|
+
const rootPackageJson = readJsonFile(join2(repoRoot, "package.json"));
|
|
262
421
|
if (!rootPackageJson) return [];
|
|
263
422
|
const normalizedRepoRoot = normalizePath(realpathSync(repoRoot));
|
|
264
423
|
const errors = [];
|
|
265
424
|
for (const pattern of getWorkspacePatterns(rootPackageJson)) {
|
|
266
425
|
if (!pattern.endsWith("/*")) continue;
|
|
267
|
-
const workspaceParent =
|
|
426
|
+
const workspaceParent = join2(repoRoot, pattern.slice(0, -2));
|
|
268
427
|
if (!existsSync(workspaceParent)) continue;
|
|
269
428
|
for (const entry of listWorkspacePackageJsonFiles(workspaceParent)) {
|
|
270
|
-
const packageDir =
|
|
271
|
-
const packageJson = readJsonFile(
|
|
429
|
+
const packageDir = join2(workspaceParent, dirname(entry));
|
|
430
|
+
const packageJson = readJsonFile(join2(workspaceParent, entry));
|
|
272
431
|
if (!packageJson?.name || !CONNECTOR_RUNTIME_WORKSPACE_PACKAGES.has(packageJson.name)) {
|
|
273
432
|
continue;
|
|
274
433
|
}
|
|
275
|
-
const linkPath =
|
|
434
|
+
const linkPath = join2(repoRoot, "node_modules", ...packageJson.name.split("/"));
|
|
276
435
|
if (!existsSync(linkPath)) {
|
|
277
436
|
errors.push(`${linkPath} is missing. Run bun install in ${repoRoot}.`);
|
|
278
437
|
continue;
|
|
@@ -308,7 +467,7 @@ async function checkConnectorWorkspaceLinks(cwd, output, validateWorkspaceLinks)
|
|
|
308
467
|
return false;
|
|
309
468
|
}
|
|
310
469
|
function resolveDaemonLogPath(env) {
|
|
311
|
-
return env.NOLO_CONNECT_LOG ||
|
|
470
|
+
return env.NOLO_CONNECT_LOG || join2(homedir2(), ".nolo", "logs", "connector.log");
|
|
312
471
|
}
|
|
313
472
|
function buildDaemonCommand(cliEntrypointPath) {
|
|
314
473
|
const execPath = process.execPath;
|
|
@@ -319,8 +478,8 @@ function buildDaemonCommand(cliEntrypointPath) {
|
|
|
319
478
|
return [execPath, entrypoint, "connect", "--ws"];
|
|
320
479
|
}
|
|
321
480
|
function defaultSpawnDaemon(args) {
|
|
322
|
-
|
|
323
|
-
const out =
|
|
481
|
+
mkdirSync2(dirname(args.logPath), { recursive: true });
|
|
482
|
+
const out = openSync2(args.logPath, "a");
|
|
324
483
|
const env = Object.fromEntries(
|
|
325
484
|
Object.entries(args.env).filter((entry) => typeof entry[1] === "string")
|
|
326
485
|
);
|
|
@@ -340,6 +499,20 @@ async function runMachineDaemonCommand(deps = {}) {
|
|
|
340
499
|
if (!await checkConnectorWorkspaceLinks(process.cwd(), output, validateWorkspaceLinks)) {
|
|
341
500
|
return 1;
|
|
342
501
|
}
|
|
502
|
+
const probe = acquireConnectorInstanceLock({
|
|
503
|
+
machineId: deps.machineId ?? resolveMachineId(),
|
|
504
|
+
homeDir: deps.connectorHomeDir,
|
|
505
|
+
noloHome: env.NOLO_HOME,
|
|
506
|
+
kind: "daemon"
|
|
507
|
+
});
|
|
508
|
+
if (!probe.ok) {
|
|
509
|
+
output.write(
|
|
510
|
+
`[nolo] A connector for this machine is already running (pid=${probe.pid}). Do not start two connectors at the same time \u2014 stop the running one first (or check whether it is still healthy) before starting a new one.
|
|
511
|
+
`
|
|
512
|
+
);
|
|
513
|
+
return 3;
|
|
514
|
+
}
|
|
515
|
+
probe.release();
|
|
343
516
|
const logPath = resolveDaemonLogPath(env);
|
|
344
517
|
const result = (deps.spawnDaemon ?? defaultSpawnDaemon)({
|
|
345
518
|
cmd: buildDaemonCommand(deps.cliEntrypointPath),
|
|
@@ -400,8 +573,8 @@ async function runMachineWatchCommand(deps) {
|
|
|
400
573
|
|
|
401
574
|
// packages/cli/machineToolInvokeDispatch.ts
|
|
402
575
|
import { appendFile, lstat, mkdir, realpath, stat } from "node:fs/promises";
|
|
403
|
-
import { homedir as
|
|
404
|
-
import { dirname as dirname2, isAbsolute as isAbsolute2, join as
|
|
576
|
+
import { homedir as homedir3 } from "node:os";
|
|
577
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve as resolve2, sep } from "node:path";
|
|
405
578
|
|
|
406
579
|
// packages/agent-runtime/machineToolGrants.ts
|
|
407
580
|
function isRecord2(value) {
|
|
@@ -464,8 +637,8 @@ function isMachineToolGranted(grants, toolName, agentKey) {
|
|
|
464
637
|
}
|
|
465
638
|
function resolveMachineToolAuditLogPath() {
|
|
466
639
|
const noloHome = process.env.NOLO_HOME?.trim();
|
|
467
|
-
const base = noloHome ? noloHome :
|
|
468
|
-
return
|
|
640
|
+
const base = noloHome ? noloHome : join3(homedir3(), ".nolo");
|
|
641
|
+
return join3(base, "logs", "machine-tool-audit.jsonl");
|
|
469
642
|
}
|
|
470
643
|
function auditTargetFor(executorArgs) {
|
|
471
644
|
const target = extractMachineToolRequestPath(executorArgs) ?? "";
|
|
@@ -1261,11 +1434,13 @@ async function runMachineConnectCommand(args, deps = {}) {
|
|
|
1261
1434
|
output,
|
|
1262
1435
|
cliEntrypointPath: deps.cliEntrypointPath,
|
|
1263
1436
|
validateWorkspaceLinks: deps.validateWorkspaceLinks,
|
|
1264
|
-
spawnDaemon: deps.spawnDaemon
|
|
1437
|
+
spawnDaemon: deps.spawnDaemon,
|
|
1438
|
+
connectorHomeDir: deps.connectorHomeDir
|
|
1265
1439
|
});
|
|
1266
1440
|
}
|
|
1267
1441
|
const machine = (deps.machineInfo ?? detectLaunchableMachineInfo)();
|
|
1268
|
-
const
|
|
1442
|
+
const machineId = machine.machineId;
|
|
1443
|
+
const sendHeartbeatBase = () => postMachineHeartbeat({
|
|
1269
1444
|
fetchImpl,
|
|
1270
1445
|
serverUrl,
|
|
1271
1446
|
authToken,
|
|
@@ -1277,96 +1452,130 @@ async function runMachineConnectCommand(args, deps = {}) {
|
|
|
1277
1452
|
if (!await checkConnectorWorkspaceLinks(process.cwd(), output, validateWorkspaceLinks)) {
|
|
1278
1453
|
return 1;
|
|
1279
1454
|
}
|
|
1280
|
-
const
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
workspaceRoot: process.cwd(),
|
|
1286
|
-
// M2 修复:机器侧授权复核与握手上报共用同一来源——本次 `deps.env ??
|
|
1287
|
-
// process.env`。grants 快照与 WS URL 上报的那份逐字节相同;未配置时也
|
|
1288
|
-
// 显式传 env,工厂不再回落到 process.env(调用方经 deps.env 注入环境时
|
|
1289
|
-
// 两端曾不一致)。
|
|
1290
|
-
env,
|
|
1291
|
-
...toolGrants ? { grants: toolGrants } : {}
|
|
1455
|
+
const instanceLock = acquireConnectorInstanceLock({
|
|
1456
|
+
machineId,
|
|
1457
|
+
homeDir: deps.connectorHomeDir,
|
|
1458
|
+
noloHome: env.NOLO_HOME,
|
|
1459
|
+
kind: "ws"
|
|
1292
1460
|
});
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1461
|
+
if (!instanceLock.ok) {
|
|
1462
|
+
const owner = instanceLock.pid > 0 ? `pid=${instanceLock.pid}` : "owner pid unknown";
|
|
1463
|
+
output.write(
|
|
1464
|
+
`[nolo] A connector for this machine is already running (${owner}). Do not start two connectors at the same time \u2014 stop the running one first (or check whether it is still healthy) before starting a new one.
|
|
1465
|
+
`
|
|
1466
|
+
);
|
|
1467
|
+
return 3;
|
|
1468
|
+
}
|
|
1469
|
+
if (instanceLock.reclaimed === "corrupt") {
|
|
1470
|
+
output.write(
|
|
1471
|
+
`[nolo] Reclaimed a corrupt connector lock (no readable pid, older than ${CONNECTOR_LOCK_CORRUPT_RECLAIM_SECONDS}s) \u2014 a previous connector likely crashed while writing it.
|
|
1472
|
+
`
|
|
1473
|
+
);
|
|
1474
|
+
}
|
|
1475
|
+
const sendHeartbeat = withConnectorAliveSignal(sendHeartbeatBase, {
|
|
1476
|
+
machineId,
|
|
1477
|
+
homeDir: deps.connectorHomeDir,
|
|
1478
|
+
noloHome: env.NOLO_HOME
|
|
1479
|
+
});
|
|
1480
|
+
try {
|
|
1481
|
+
const maxAttempts = deps.maxConnectorAttempts ?? Infinity;
|
|
1482
|
+
const sleep = deps.sleep ?? defaultSleep2;
|
|
1483
|
+
const reconnectDelayMs = resolveConnectorReconnectDelayMs(env);
|
|
1484
|
+
const toolGrants = readMachineToolGrants(env);
|
|
1485
|
+
const toolInvokeHandlers = createMachineToolInvokeHandlers({
|
|
1486
|
+
workspaceRoot: process.cwd(),
|
|
1487
|
+
// M2 修复:机器侧授权复核与握手上报共用同一来源——本次 `deps.env ??
|
|
1488
|
+
// process.env`。grants 快照与 WS URL 上报的那份逐字节相同;未配置时也
|
|
1489
|
+
// 显式传 env,工厂不再回落到 process.env(调用方经 deps.env 注入环境时
|
|
1490
|
+
// 两端曾不一致)。
|
|
1299
1491
|
env,
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
serverUrl
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1492
|
+
...toolGrants ? { grants: toolGrants } : {}
|
|
1493
|
+
});
|
|
1494
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
1495
|
+
if (deps.signal?.aborted) {
|
|
1496
|
+
return 0;
|
|
1497
|
+
}
|
|
1498
|
+
const runtimeServerUrl = env.NOLO_CONNECT_RUNTIME_SERVER_URL || env.NOLO_RUNTIME_SERVER_URL || serverUrl;
|
|
1499
|
+
const sessionResult = await runMachineWsSession({
|
|
1500
|
+
env,
|
|
1501
|
+
output,
|
|
1502
|
+
signal: deps.signal,
|
|
1503
|
+
machine,
|
|
1504
|
+
sendHeartbeat,
|
|
1505
|
+
runHeartbeatLoop: deps.runHeartbeatLoop ?? runHeartbeatLoop,
|
|
1506
|
+
connectWebSocket: deps.connectWebSocket ?? defaultConnectWebSocket,
|
|
1507
|
+
serverUrl,
|
|
1508
|
+
authToken,
|
|
1509
|
+
resolveConnectorWebSocketTarget: async (options) => appendToolGrantsToWsUrl(
|
|
1510
|
+
await resolveConnectorWebSocketTarget({
|
|
1511
|
+
...options,
|
|
1512
|
+
fetchImpl
|
|
1513
|
+
}),
|
|
1514
|
+
toolGrants
|
|
1515
|
+
),
|
|
1516
|
+
onMessage: (message, send) => handleMachineWsMessageDemux(
|
|
1320
1517
|
message,
|
|
1321
1518
|
send,
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1519
|
+
{ toolInvoke: toolInvokeHandlers },
|
|
1520
|
+
() => handleConnectorRunMessage(
|
|
1521
|
+
message,
|
|
1522
|
+
send,
|
|
1523
|
+
deps.executeCli ?? defaultExecuteCli,
|
|
1524
|
+
{
|
|
1525
|
+
...env,
|
|
1526
|
+
NOLO_SERVER: runtimeServerUrl,
|
|
1527
|
+
NOLO_SERVER_URL: runtimeServerUrl,
|
|
1528
|
+
BASE_URL: runtimeServerUrl,
|
|
1529
|
+
AUTH_TOKEN: authToken,
|
|
1530
|
+
NOLO_MACHINE_API_KEY: authToken
|
|
1531
|
+
},
|
|
1532
|
+
fetchImpl,
|
|
1533
|
+
{
|
|
1534
|
+
buildConnectorCliPrompt
|
|
1535
|
+
}
|
|
1536
|
+
)
|
|
1335
1537
|
)
|
|
1336
|
-
)
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
`[nolo] Connector websocket disconnected${reconnectContext}. Reconnecting in ${retryDelayMs}ms.
|
|
1538
|
+
});
|
|
1539
|
+
const exitCode = sessionResult.exitCode;
|
|
1540
|
+
if (exitCode === 2) return 1;
|
|
1541
|
+
if (deps.signal?.aborted) {
|
|
1542
|
+
return 0;
|
|
1543
|
+
}
|
|
1544
|
+
if (attempt >= maxAttempts) return exitCode;
|
|
1545
|
+
const retryDelayMs = Math.min(
|
|
1546
|
+
sessionResult.retryAfterMs ?? reconnectDelayMs,
|
|
1547
|
+
MAX_CONNECTOR_TIMER_DELAY_MS
|
|
1548
|
+
);
|
|
1549
|
+
const reconnectContext = sessionResult.reconnectReason === CORE_DRAIN_REASON ? " during core draining" : "";
|
|
1550
|
+
output.write(
|
|
1551
|
+
`[nolo] Connector websocket disconnected${reconnectContext}. Reconnecting in ${retryDelayMs}ms.
|
|
1351
1552
|
`
|
|
1352
|
-
|
|
1353
|
-
|
|
1553
|
+
);
|
|
1554
|
+
await sleepWithAbort(retryDelayMs, sleep, deps.signal);
|
|
1555
|
+
}
|
|
1556
|
+
return 0;
|
|
1557
|
+
} finally {
|
|
1558
|
+
instanceLock.release();
|
|
1559
|
+
clearConnectorAlive({
|
|
1560
|
+
machineId,
|
|
1561
|
+
homeDir: deps.connectorHomeDir,
|
|
1562
|
+
noloHome: env.NOLO_HOME
|
|
1563
|
+
});
|
|
1354
1564
|
}
|
|
1355
|
-
return 0;
|
|
1356
1565
|
}
|
|
1357
1566
|
if (hasFlag(args, "--watch")) {
|
|
1358
1567
|
return runMachineWatchCommand({
|
|
1359
1568
|
env,
|
|
1360
1569
|
output,
|
|
1361
1570
|
machine,
|
|
1362
|
-
sendHeartbeat,
|
|
1571
|
+
sendHeartbeat: sendHeartbeatBase,
|
|
1363
1572
|
runHeartbeatLoop: deps.runHeartbeatLoop ?? runHeartbeatLoop
|
|
1364
1573
|
});
|
|
1365
1574
|
}
|
|
1366
1575
|
return runMachineHeartbeatConnectCommand({
|
|
1367
1576
|
output,
|
|
1368
1577
|
machine,
|
|
1369
|
-
sendHeartbeat
|
|
1578
|
+
sendHeartbeat: sendHeartbeatBase
|
|
1370
1579
|
});
|
|
1371
1580
|
}
|
|
1372
1581
|
export {
|