nolo-cli 0.170.1 → 0.170.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/{chunk-TWJYVVUB.js → chunk-2AALYZZF.js} +26 -319
- package/{commandRegistry-3XBG7JHS.js → commandRegistry-OMHWU6IC.js} +5 -5
- package/index.js +3 -14
- package/package.json +1 -1
- package/{readlineWorkspace-OFBP6OA7.js → readlineWorkspace-XUUB3IXF.js} +3 -3
- package/{updateCommands-C56QMWHF.js → updateCommands-2IHLKRE2.js} +1 -1
|
@@ -28,40 +28,24 @@ import {
|
|
|
28
28
|
mkdirSync,
|
|
29
29
|
openSync,
|
|
30
30
|
readFileSync,
|
|
31
|
-
|
|
31
|
+
readdirSync,
|
|
32
32
|
rmSync,
|
|
33
|
-
statSync,
|
|
34
33
|
writeSync,
|
|
35
34
|
writeFileSync
|
|
36
35
|
} from "node:fs";
|
|
37
36
|
import { homedir, tmpdir } from "node:os";
|
|
38
37
|
import { dirname, isAbsolute, join, normalize } from "node:path";
|
|
39
38
|
import { randomUUID } from "node:crypto";
|
|
40
|
-
var UPDATE_STATE_FILE = "update-result.json";
|
|
41
|
-
var UPDATE_STALE_MS = 15 * 60 * 1e3;
|
|
42
|
-
var UPDATE_CORRUPT_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
43
39
|
var UPDATE_LOCK_FILE = "update.lock";
|
|
44
40
|
function resolveNoloHome(env, homeDir = homedir()) {
|
|
45
41
|
return env.NOLO_HOME?.trim() || join(homeDir, ".nolo");
|
|
46
42
|
}
|
|
47
|
-
function resolveWindowsUpdateStatePath(env = process.env, homeDir = homedir()) {
|
|
48
|
-
return join(resolveNoloHome(env, homeDir), "updates", UPDATE_STATE_FILE);
|
|
49
|
-
}
|
|
50
43
|
function resolveTrustedWindowsToolPaths(env, execPath, overrides) {
|
|
51
44
|
const nodePath = overrides.nodePath ?? execPath;
|
|
52
45
|
const npmCliPath = overrides.npmCliPath ?? join(dirname(nodePath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
53
|
-
const windowsRoot = env.SystemRoot?.trim() || env.WINDIR?.trim();
|
|
54
|
-
const powershellPath = overrides.powershellPath ?? (windowsRoot ? join(
|
|
55
|
-
windowsRoot,
|
|
56
|
-
"System32",
|
|
57
|
-
"WindowsPowerShell",
|
|
58
|
-
"v1.0",
|
|
59
|
-
"powershell.exe"
|
|
60
|
-
) : "");
|
|
61
46
|
for (const [label, path] of Object.entries({
|
|
62
47
|
nodePath,
|
|
63
|
-
npmCliPath
|
|
64
|
-
powershellPath
|
|
48
|
+
npmCliPath
|
|
65
49
|
})) {
|
|
66
50
|
if (!path || !isAbsolute(path) || !existsSync(path)) {
|
|
67
51
|
throw new Error(
|
|
@@ -69,7 +53,7 @@ function resolveTrustedWindowsToolPaths(env, execPath, overrides) {
|
|
|
69
53
|
);
|
|
70
54
|
}
|
|
71
55
|
}
|
|
72
|
-
return { nodePath, npmCliPath
|
|
56
|
+
return { nodePath, npmCliPath };
|
|
73
57
|
}
|
|
74
58
|
function removeOwnedLock(lockPath, updateId) {
|
|
75
59
|
try {
|
|
@@ -81,188 +65,20 @@ function removeOwnedLock(lockPath, updateId) {
|
|
|
81
65
|
} catch {
|
|
82
66
|
}
|
|
83
67
|
}
|
|
84
|
-
function
|
|
85
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
86
|
-
const tempPath = `${path}.${process.pid}.tmp`;
|
|
87
|
-
writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}
|
|
88
|
-
`, "utf8");
|
|
89
|
-
renameSync(tempPath, path);
|
|
90
|
-
}
|
|
91
|
-
function readWindowsUpdateState(env = process.env, homeDir = homedir()) {
|
|
92
|
-
const statePath = resolveWindowsUpdateStatePath(env, homeDir);
|
|
93
|
-
if (!existsSync(statePath)) return null;
|
|
94
|
-
try {
|
|
95
|
-
const parsed = JSON.parse(
|
|
96
|
-
readFileSync(statePath, "utf8")
|
|
97
|
-
);
|
|
98
|
-
if (!parsed || !["pending", "success", "failed"].includes(parsed.status)) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
return parsed;
|
|
102
|
-
} catch {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
function assessWindowsUpdatePending(state, now, statePath) {
|
|
107
|
-
const startedAtMs = Date.parse(state.startedAt);
|
|
108
|
-
const MAX_CLOCK_SKEW_MS = 5 * 60 * 1e3;
|
|
109
|
-
if (Number.isFinite(startedAtMs) && startedAtMs - now <= MAX_CLOCK_SKEW_MS) {
|
|
110
|
-
const ageMs = now - startedAtMs;
|
|
111
|
-
const stale = ageMs >= UPDATE_STALE_MS;
|
|
112
|
-
return {
|
|
113
|
-
classification: stale ? "stale" : "active",
|
|
114
|
-
ageMs,
|
|
115
|
-
startedAtUsable: true,
|
|
116
|
-
blocksStartup: !stale
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
let mtimeAge = Number.NaN;
|
|
120
|
-
try {
|
|
121
|
-
mtimeAge = now - statSync(statePath).mtimeMs;
|
|
122
|
-
} catch {
|
|
123
|
-
}
|
|
124
|
-
if (!Number.isFinite(mtimeAge) || mtimeAge < UPDATE_CORRUPT_MAX_AGE_MS) {
|
|
125
|
-
return {
|
|
126
|
-
classification: "corrupt-unageable",
|
|
127
|
-
ageMs: mtimeAge,
|
|
128
|
-
startedAtUsable: false,
|
|
129
|
-
blocksStartup: true
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
return {
|
|
133
|
-
classification: "stale",
|
|
134
|
-
ageMs: mtimeAge,
|
|
135
|
-
startedAtUsable: false,
|
|
136
|
-
blocksStartup: false
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
function consumeWindowsUpdateStartupNotice(env = process.env, options = {}) {
|
|
68
|
+
function getWindowsUpdateStatus(env = process.env, options = {}) {
|
|
140
69
|
const homeDir = options.homeDir ?? homedir();
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
if (state.status === "pending") {
|
|
145
|
-
if (options.ownerUpdateId && state.updateId && options.ownerUpdateId === state.updateId) {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
const now = options.now ?? Date.now();
|
|
149
|
-
const assessment = assessWindowsUpdatePending(state, now, statePath);
|
|
150
|
-
if (assessment.blocksStartup) {
|
|
151
|
-
return {
|
|
152
|
-
blocking: true,
|
|
153
|
-
text: `A Nolo update may still be in progress (${describeUpdatePhase(state)}). Run "nolo update status" for details, or retry shortly.
|
|
154
|
-
Log: ${state.logPath}`
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
if (state.lockPath && state.updateId) {
|
|
158
|
-
removeOwnedLock(state.lockPath, state.updateId);
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
blocking: false,
|
|
162
|
-
text: `The previous Nolo update helper stopped unexpectedly and its lock was released. Verify with "nolo -v" / "nolo update status"; a manual npm repair may be required.
|
|
163
|
-
Log: ${state.logPath}`
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
if (state.noticeAcknowledgedAt) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
const acknowledged = {
|
|
170
|
-
...state,
|
|
171
|
-
noticeAcknowledgedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
172
|
-
};
|
|
70
|
+
const installedVersion = options.currentVersion ?? "unknown";
|
|
71
|
+
const logDir = join(resolveNoloHome(env, homeDir), "updates");
|
|
72
|
+
let lastLogPath;
|
|
173
73
|
try {
|
|
174
|
-
|
|
74
|
+
const newest = readdirSync(logDir).filter((name) => name.startsWith("update-") && name.endsWith(".log")).sort().at(-1);
|
|
75
|
+
if (newest) lastLogPath = join(logDir, newest);
|
|
175
76
|
} catch {
|
|
176
77
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
Log: ${state.logPath}`
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
return {
|
|
185
|
-
blocking: false,
|
|
186
|
-
text: `Nolo update failed. Verify with "nolo -v"; npm may require a manual repair.${state.message ? `
|
|
187
|
-
${state.message}` : ""}
|
|
188
|
-
Log: ${state.logPath}`
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
function describeUpdatePhase(state) {
|
|
192
|
-
if (state.phase) {
|
|
193
|
-
return `phase: ${state.phase}`;
|
|
194
|
-
}
|
|
195
|
-
return "helper running";
|
|
196
|
-
}
|
|
197
|
-
function getWindowsUpdateStatus(env = process.env, options = {}) {
|
|
198
|
-
const homeDir = options.homeDir ?? homedir();
|
|
199
|
-
const state = readWindowsUpdateState(env, homeDir);
|
|
200
|
-
const now = options.now ?? Date.now();
|
|
201
|
-
const version = options.currentVersion ?? "unknown";
|
|
202
|
-
if (!state) {
|
|
203
|
-
return {
|
|
204
|
-
status: "none",
|
|
205
|
-
alive: false,
|
|
206
|
-
text: `No recorded Nolo update.
|
|
207
|
-
Installed version: ${version}`
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
const lines = [];
|
|
211
|
-
lines.push(`Update status: ${state.status}`);
|
|
212
|
-
lines.push(`Installed version: ${version}`);
|
|
213
|
-
lines.push(`Channel: ${state.channel}`);
|
|
214
|
-
lines.push(`From version: ${state.currentVersion}`);
|
|
215
|
-
if (state.targetVersion) lines.push(`Target version: ${state.targetVersion}`);
|
|
216
|
-
if (state.phase) lines.push(`Phase: ${state.phase}`);
|
|
217
|
-
lines.push(`Started: ${state.startedAt}`);
|
|
218
|
-
if (state.phaseStartedAt) lines.push(`Phase started: ${state.phaseStartedAt}`);
|
|
219
|
-
if (state.phaseDeadline) lines.push(`Phase deadline: ${state.phaseDeadline}`);
|
|
220
|
-
if (state.finishedAt) lines.push(`Finished: ${state.finishedAt}`);
|
|
221
|
-
if (state.helperPid) lines.push(`Helper pid: ${state.helperPid}`);
|
|
222
|
-
if (state.message) lines.push(`Message: ${state.message}`);
|
|
223
|
-
lines.push(`Log: ${state.logPath}`);
|
|
224
|
-
if (state.status === "pending") {
|
|
225
|
-
const statePath = resolveWindowsUpdateStatePath(env, homeDir);
|
|
226
|
-
const assessment = assessWindowsUpdatePending(state, now, statePath);
|
|
227
|
-
const deadline = state.phaseDeadline ? Date.parse(state.phaseDeadline) : NaN;
|
|
228
|
-
const pastDeadline = Number.isFinite(deadline) && now > deadline;
|
|
229
|
-
if (pastDeadline) {
|
|
230
|
-
lines.push(
|
|
231
|
-
`Phase deadline elapsed: the recorded phase has run past its soft ceiling. This can be a hung helper, but it can also be a slow install \u2014 the lock is NOT auto-released on this evidence alone.`
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
switch (assessment.classification) {
|
|
235
|
-
case "active":
|
|
236
|
-
lines.push(
|
|
237
|
-
`Diagnosis: update record is fresh (${describeUpdatePhase(state)}). The helper process has not been verified alive; the record simply has not outlived its bound, so startup is still blocked.`
|
|
238
|
-
);
|
|
239
|
-
break;
|
|
240
|
-
case "corrupt-unageable":
|
|
241
|
-
lines.push(
|
|
242
|
-
`Diagnosis: update record has an unreadable start time and cannot be aged reliably. Startup stays conservatively blocked until the record outlives its hard bound; inspect the log to tell a hung helper from a live one.`
|
|
243
|
-
);
|
|
244
|
-
break;
|
|
245
|
-
case "stale":
|
|
246
|
-
lines.push(
|
|
247
|
-
`Diagnosis: update record has outlived its bound; the helper is presumed stopped. The startup guard releases the stale lock on next start, then this record remains here for diagnosis.`
|
|
248
|
-
);
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
return {
|
|
252
|
-
status: "pending",
|
|
253
|
-
alive: assessment.blocksStartup,
|
|
254
|
-
pendingClassification: assessment.classification,
|
|
255
|
-
text: lines.join("\n")
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
if (state.status === "success") {
|
|
259
|
-
lines.push(
|
|
260
|
-
state.noticeAcknowledgedAt ? `Diagnosis: update applied and already acknowledged.` : `Diagnosis: update applied; notice pending on next start.`
|
|
261
|
-
);
|
|
262
|
-
} else {
|
|
263
|
-
lines.push(`Diagnosis: update failed; see the log above.`);
|
|
264
|
-
}
|
|
265
|
-
return { status: state.status, alive: false, text: lines.join("\n") };
|
|
78
|
+
const text = lastLogPath ? `Installed version: ${installedVersion}
|
|
79
|
+
Last update log: ${lastLogPath}` : `Installed version: ${installedVersion}
|
|
80
|
+
No recorded update log.`;
|
|
81
|
+
return { installedVersion, lastLogPath, text };
|
|
266
82
|
}
|
|
267
83
|
function defaultLaunchWindowsUpdateHelper(input) {
|
|
268
84
|
const child = spawn(input.execPath, [input.helperPath, input.payload], {
|
|
@@ -284,27 +100,7 @@ const { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, readdirS
|
|
|
284
100
|
const { dirname, isAbsolute, join, normalize, relative } = require("node:path");
|
|
285
101
|
|
|
286
102
|
const payload = JSON.parse(Buffer.from(process.argv[2], "base64url").toString("utf8"));
|
|
287
|
-
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
288
103
|
const log = (line) => appendFileSync(payload.logPath, "[" + new Date().toISOString() + "] " + line + "\n", "utf8");
|
|
289
|
-
const writeState = (next) => {
|
|
290
|
-
mkdirSync(dirname(payload.statePath), { recursive: true });
|
|
291
|
-
const temp = payload.statePath + "." + payload.updateId + ".tmp";
|
|
292
|
-
writeFileSync(temp, JSON.stringify(next, null, 2) + "\n", "utf8");
|
|
293
|
-
renameSync(temp, payload.statePath);
|
|
294
|
-
};
|
|
295
|
-
// Record the current helper step with a bounded wall-clock deadline so the
|
|
296
|
-
// startup guard can tell a live phase from a hung one. Deadline is a soft
|
|
297
|
-
// ceiling: a phase that overruns it is reported stale, not killed.
|
|
298
|
-
const setPhase = (base, phase, budgetMs) => {
|
|
299
|
-
const phaseStartedAt = new Date().toISOString();
|
|
300
|
-
const phaseDeadline = new Date(Date.now() + budgetMs).toISOString();
|
|
301
|
-
try {
|
|
302
|
-
writeState({ ...base, status: "pending", phase, phaseStartedAt, phaseDeadline });
|
|
303
|
-
} catch (error) {
|
|
304
|
-
log("Could not persist phase " + phase + ": " + (error && error.message ? error.message : String(error)));
|
|
305
|
-
}
|
|
306
|
-
return { ...base, status: "pending", phase, phaseStartedAt, phaseDeadline };
|
|
307
|
-
};
|
|
308
104
|
const runNpm = (args) => {
|
|
309
105
|
const command = [payload.nodePath, payload.npmCliPath, ...args].join(" ");
|
|
310
106
|
log("> " + command);
|
|
@@ -320,20 +116,6 @@ const runNpm = (args) => {
|
|
|
320
116
|
if (result.error) throw result.error;
|
|
321
117
|
return { code: result.status == null ? 1 : result.status, stdout: String(result.stdout || "").trim() };
|
|
322
118
|
};
|
|
323
|
-
const listOtherNoloPids = () => {
|
|
324
|
-
const script = "$selfPid=" + process.pid + "; Get-CimInstance Win32_Process | Where-Object { $_.ProcessId -ne $selfPid -and ($_.Name -ieq 'node.exe' -or $_.Name -ieq 'bun.exe') -and $_.CommandLine -and $_.CommandLine -match '\\\\node_modules\\\\nolo-cli\\\\index\\.js' } | ForEach-Object { $_.ProcessId }";
|
|
325
|
-
const result = spawnSync(payload.powershellPath, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
326
|
-
encoding: "utf8",
|
|
327
|
-
windowsHide: true,
|
|
328
|
-
env: process.env,
|
|
329
|
-
cwd: payload.updateDir,
|
|
330
|
-
timeout: 10 * 1000,
|
|
331
|
-
});
|
|
332
|
-
if (result.error || result.status !== 0) {
|
|
333
|
-
throw new Error("Could not verify that all other Nolo windows are closed");
|
|
334
|
-
}
|
|
335
|
-
return String(result.stdout || "").split(/\r?\n/).map((value) => value.trim()).filter(Boolean);
|
|
336
|
-
};
|
|
337
119
|
const parseVersion = (raw) => {
|
|
338
120
|
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(String(raw).trim());
|
|
339
121
|
return match ? { main: [Number(match[1]), Number(match[2]), Number(match[3])], pre: match[4] ? match[4].split(".") : [] } : null;
|
|
@@ -478,33 +260,11 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
478
260
|
updateId: payload.updateId,
|
|
479
261
|
lockPath: payload.lockPath,
|
|
480
262
|
};
|
|
481
|
-
let progress = base;
|
|
482
263
|
try {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
try { process.kill(payload.parentPid, 0); await delay(250); }
|
|
488
|
-
catch { parentExited = true; break; }
|
|
489
|
-
}
|
|
490
|
-
if (!parentExited) throw new Error("Timed out waiting for the current Nolo process to exit");
|
|
491
|
-
await delay(250);
|
|
492
|
-
|
|
493
|
-
progress = setPhase(progress, "wait-other-windows", 120 * 1000 + 30 * 1000);
|
|
494
|
-
const otherProcessDeadline = Date.now() + 120 * 1000;
|
|
495
|
-
let otherPids = listOtherNoloPids();
|
|
496
|
-
let checks = 0;
|
|
497
|
-
while (otherPids.length > 0 && Date.now() < otherProcessDeadline) {
|
|
498
|
-
if (checks === 0 || checks % 10 === 0) log("Waiting for other Nolo processes: " + otherPids.join(", "));
|
|
499
|
-
await delay(1000);
|
|
500
|
-
otherPids = listOtherNoloPids();
|
|
501
|
-
checks++;
|
|
502
|
-
}
|
|
503
|
-
if (otherPids.length > 0) {
|
|
504
|
-
throw new Error("Other Nolo processes are still running: " + otherPids.join(", "));
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
progress = setPhase(progress, "resolve-prefix", 30 * 1000);
|
|
264
|
+
// 2026-10-27 减法:不再等待父进程或其它 Nolo 窗口退出。
|
|
265
|
+
// 新版本写入独立版本目录、最后只切换入口,因此其它进程继续运行旧版本是安全的;
|
|
266
|
+
// 扫描 PID 也不构成真正的写入互斥(扫描结束后照样可以再启动一个进程)。
|
|
267
|
+
log("phase: resolve-prefix");
|
|
508
268
|
const prefixResult = runNpm(["prefix", "-g"]);
|
|
509
269
|
if (prefixResult.code !== 0 || !prefixResult.stdout) throw new Error("Could not resolve npm global prefix");
|
|
510
270
|
const prefix = prefixResult.stdout.split(/\r?\n/).at(-1).trim();
|
|
@@ -514,8 +274,7 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
514
274
|
if (!isWithin(expectedRoot, oldEntrypoint) && !isWithin(managedRoot, oldEntrypoint)) {
|
|
515
275
|
throw new Error("Refusing to update a different npm prefix. Current entrypoint: " + payload.entrypointPath + "; npm prefix: " + prefix);
|
|
516
276
|
}
|
|
517
|
-
|
|
518
|
-
progress = setPhase(progress, "resolve-target-version", 30 * 1000);
|
|
277
|
+
log("phase: resolve-target-version");
|
|
519
278
|
const targetResult = runNpm(["view", "nolo-cli@" + payload.channel, "version"]);
|
|
520
279
|
if (targetResult.code !== 0 || !parseVersion(targetResult.stdout)) {
|
|
521
280
|
throw new Error("Could not resolve nolo-cli@" + payload.channel + " target version");
|
|
@@ -526,7 +285,7 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
526
285
|
}
|
|
527
286
|
|
|
528
287
|
if (compare(targetVersion, payload.currentVersion) > 0) {
|
|
529
|
-
|
|
288
|
+
log("phase: install-target");
|
|
530
289
|
const versionPrefix = join(payload.managedRoot, targetVersion + "-" + payload.updateId);
|
|
531
290
|
uncommittedVersionPrefix = versionPrefix;
|
|
532
291
|
mkdirSync(versionPrefix, { recursive: true });
|
|
@@ -542,12 +301,12 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
542
301
|
const stagedEntrypoint = join(versionPrefix, "node_modules", "nolo-cli", "index.js");
|
|
543
302
|
if (!existsSync(stagedEntrypoint)) throw new Error("Staged nolo entrypoint is missing");
|
|
544
303
|
assertLockOwnership();
|
|
545
|
-
|
|
304
|
+
log("phase: switch-shims");
|
|
546
305
|
const switchedShims = switchWindowsShims(prefix, stagedEntrypoint);
|
|
547
306
|
const verify = spawnSync(payload.nodePath, [stagedEntrypoint, "-v"], {
|
|
548
307
|
encoding: "utf8",
|
|
549
308
|
windowsHide: true,
|
|
550
|
-
env:
|
|
309
|
+
env: process.env,
|
|
551
310
|
cwd: payload.updateDir,
|
|
552
311
|
timeout: 30 * 1000,
|
|
553
312
|
});
|
|
@@ -581,7 +340,6 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
581
340
|
} else {
|
|
582
341
|
log("Already current at " + targetVersion);
|
|
583
342
|
}
|
|
584
|
-
writeState({ ...progress, status: "success", phase: "done", targetVersion, finishedAt: new Date().toISOString() });
|
|
585
343
|
} catch (error) {
|
|
586
344
|
const message = error && error.message ? error.message : String(error);
|
|
587
345
|
log("ERROR: " + message);
|
|
@@ -592,11 +350,6 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
592
350
|
try { rmSync(uncommittedVersionPrefix, { recursive: true, force: true }); } catch {}
|
|
593
351
|
}
|
|
594
352
|
}
|
|
595
|
-
if (lockOwnershipLost) {
|
|
596
|
-
log("Not writing a failed status record: the update lock belongs to another updater");
|
|
597
|
-
} else {
|
|
598
|
-
writeState({ ...progress, status: "failed", finishedAt: new Date().toISOString(), message });
|
|
599
|
-
}
|
|
600
353
|
process.exitCode = 1;
|
|
601
354
|
} finally {
|
|
602
355
|
try {
|
|
@@ -613,8 +366,7 @@ const switchWindowsShims = (shimDir, entrypoint) => {
|
|
|
613
366
|
function scheduleWindowsSelfUpdate(options) {
|
|
614
367
|
const env = options.env ?? process.env;
|
|
615
368
|
const homeDir = options.homeDir ?? homedir();
|
|
616
|
-
const
|
|
617
|
-
const updateDir = dirname(statePath);
|
|
369
|
+
const updateDir = join(resolveNoloHome(env, homeDir), "updates");
|
|
618
370
|
const managedRoot = join(resolveNoloHome(env, homeDir), "cli", "versions");
|
|
619
371
|
const lockPath = join(updateDir, UPDATE_LOCK_FILE);
|
|
620
372
|
const updateId = randomUUID();
|
|
@@ -630,29 +382,14 @@ function scheduleWindowsSelfUpdate(options) {
|
|
|
630
382
|
try {
|
|
631
383
|
const lockFd = openSync(lockPath, "wx");
|
|
632
384
|
try {
|
|
633
|
-
writeSync(
|
|
634
|
-
lockFd,
|
|
635
|
-
JSON.stringify({ updateId, startedAt }),
|
|
636
|
-
void 0,
|
|
637
|
-
"utf8"
|
|
638
|
-
);
|
|
385
|
+
writeSync(lockFd, JSON.stringify({ updateId, startedAt }), void 0, "utf8");
|
|
639
386
|
} finally {
|
|
640
387
|
closeSync(lockFd);
|
|
641
388
|
}
|
|
642
389
|
} catch (error) {
|
|
643
|
-
if (!readWindowsUpdateState(env, homeDir)) {
|
|
644
|
-
try {
|
|
645
|
-
const lock = JSON.parse(readFileSync(lockPath, "utf8"));
|
|
646
|
-
const age = Date.now() - Date.parse(lock.startedAt ?? "");
|
|
647
|
-
if (Number.isFinite(age) && age >= UPDATE_STALE_MS) {
|
|
648
|
-
rmSync(lockPath, { force: true });
|
|
649
|
-
return scheduleWindowsSelfUpdate(options);
|
|
650
|
-
}
|
|
651
|
-
} catch {
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
390
|
throw new Error(
|
|
655
|
-
`Another Nolo update is already pending (${lockPath}): ${error instanceof Error ? error.message : String(error)}
|
|
391
|
+
`Another Nolo update is already pending (${lockPath}): ${error instanceof Error ? error.message : String(error)}
|
|
392
|
+
\u9501\u6587\u4EF6\u91CC\u8BB0\u5F55\u4E86\u6301\u6709\u8005\u7684 updateId \u4E0E\u5F00\u59CB\u65F6\u95F4\uFF1B\u66F4\u65B0\u65E5\u5FD7\u5728 ${updateDir} \u4E0B\uFF0C\u6309\u65F6\u95F4\u6392\u5E8F\u53D6\u6700\u65B0\u90A3\u4E2A\u3002\u786E\u8BA4\u6301\u6709\u5B83\u7684\u66F4\u65B0\u8FDB\u7A0B\u5DF2\u7ED3\u675F\u540E\uFF0C\u5220\u9664\u4E0A\u9762\u7684\u9501\u6587\u4EF6\u518D\u91CD\u8BD5\u3002`
|
|
656
393
|
);
|
|
657
394
|
}
|
|
658
395
|
const execPath = options.execPath ?? process.execPath;
|
|
@@ -663,20 +400,10 @@ function scheduleWindowsSelfUpdate(options) {
|
|
|
663
400
|
removeOwnedLock(lockPath, updateId);
|
|
664
401
|
throw error;
|
|
665
402
|
}
|
|
666
|
-
const pending = {
|
|
667
|
-
status: "pending",
|
|
668
|
-
currentVersion: options.currentVersion,
|
|
669
|
-
channel: options.channel,
|
|
670
|
-
startedAt,
|
|
671
|
-
logPath,
|
|
672
|
-
updateId,
|
|
673
|
-
lockPath
|
|
674
|
-
};
|
|
675
403
|
try {
|
|
676
404
|
writeFileSync(helperPath, buildWindowsUpdateHelperSource(), "utf8");
|
|
677
405
|
writeFileSync(logPath, `[${startedAt}] Windows update scheduled
|
|
678
406
|
`, "utf8");
|
|
679
|
-
writeJsonAtomic(statePath, pending);
|
|
680
407
|
} catch (error) {
|
|
681
408
|
removeOwnedLock(lockPath, updateId);
|
|
682
409
|
rmSync(helperPath, { force: true });
|
|
@@ -684,12 +411,10 @@ function scheduleWindowsSelfUpdate(options) {
|
|
|
684
411
|
}
|
|
685
412
|
const payload = Buffer.from(
|
|
686
413
|
JSON.stringify({
|
|
687
|
-
parentPid: options.parentPid ?? process.pid,
|
|
688
414
|
currentVersion: options.currentVersion,
|
|
689
415
|
channel: options.channel,
|
|
690
416
|
entrypointPath: normalize(options.entrypointPath),
|
|
691
417
|
startedAt,
|
|
692
|
-
statePath,
|
|
693
418
|
logPath,
|
|
694
419
|
updateDir,
|
|
695
420
|
updateId,
|
|
@@ -709,28 +434,11 @@ function scheduleWindowsSelfUpdate(options) {
|
|
|
709
434
|
env
|
|
710
435
|
});
|
|
711
436
|
} catch (error) {
|
|
712
|
-
const state = readWindowsUpdateState(env, homeDir);
|
|
713
|
-
if (state?.updateId === updateId) {
|
|
714
|
-
rmSync(statePath, { force: true });
|
|
715
|
-
}
|
|
716
437
|
removeOwnedLock(lockPath, updateId);
|
|
717
438
|
rmSync(helperPath, { force: true });
|
|
718
439
|
throw error;
|
|
719
440
|
}
|
|
720
|
-
|
|
721
|
-
writeJsonAtomic(statePath, { ...pending, helperPid });
|
|
722
|
-
} catch (error) {
|
|
723
|
-
try {
|
|
724
|
-
writeFileSync(
|
|
725
|
-
logPath,
|
|
726
|
-
`[${(/* @__PURE__ */ new Date()).toISOString()}] Could not persist helper pid: ${error instanceof Error ? error.message : String(error)}
|
|
727
|
-
`,
|
|
728
|
-
{ encoding: "utf8", flag: "a" }
|
|
729
|
-
);
|
|
730
|
-
} catch {
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
return { helperPid, statePath, logPath };
|
|
441
|
+
return { helperPid, logPath };
|
|
734
442
|
}
|
|
735
443
|
|
|
736
444
|
// packages/cli/updateCommands.ts
|
|
@@ -1277,7 +985,6 @@ async function runSelfUpdate(outputOrOptions) {
|
|
|
1277
985
|
}
|
|
1278
986
|
|
|
1279
987
|
export {
|
|
1280
|
-
consumeWindowsUpdateStartupNotice,
|
|
1281
988
|
getWindowsUpdateStatus,
|
|
1282
989
|
getCliInstallChannel,
|
|
1283
990
|
renderProgressBar,
|
|
@@ -546,7 +546,7 @@ function getSystemInternalCommandEntries(renderHelpText2) {
|
|
|
546
546
|
return runDoctorRuntimeCommand(args, deps);
|
|
547
547
|
}),
|
|
548
548
|
createContextCommand(["doctor"], "Show CLI doctor information", async (_args, ctx) => {
|
|
549
|
-
const { buildCliDoctorText, getCliInstallChannel, resolveSelfUpdateServerUrl } = await import("./updateCommands-
|
|
549
|
+
const { buildCliDoctorText, getCliInstallChannel, resolveSelfUpdateServerUrl } = await import("./updateCommands-2IHLKRE2.js");
|
|
550
550
|
const { isCompiledBinary } = await import("./cliEnvHelpers-BVYTMUPJ.js");
|
|
551
551
|
const serverUrl = resolveSelfUpdateServerUrl(ctx.env);
|
|
552
552
|
console.log(
|
|
@@ -563,7 +563,7 @@ function getSystemInternalCommandEntries(renderHelpText2) {
|
|
|
563
563
|
return 0;
|
|
564
564
|
}),
|
|
565
565
|
createContextCommand(["update"], "Update the CLI", async (_args, ctx) => {
|
|
566
|
-
const { resolveSelfUpdateServerUrl, runSelfUpdate } = await import("./updateCommands-
|
|
566
|
+
const { resolveSelfUpdateServerUrl, runSelfUpdate } = await import("./updateCommands-2IHLKRE2.js");
|
|
567
567
|
return runSelfUpdate({
|
|
568
568
|
entrypointPath: ctx.entrypointPath,
|
|
569
569
|
serverUrl: resolveSelfUpdateServerUrl(ctx.env),
|
|
@@ -576,17 +576,17 @@ function getSystemInternalCommandEntries(renderHelpText2) {
|
|
|
576
576
|
return process.exitCode ?? 0;
|
|
577
577
|
}),
|
|
578
578
|
createContextCommand(["version"], "Show CLI version", async (_args, ctx) => {
|
|
579
|
-
const { buildCliVersionText } = await import("./updateCommands-
|
|
579
|
+
const { buildCliVersionText } = await import("./updateCommands-2IHLKRE2.js");
|
|
580
580
|
console.log(buildCliVersionText(ctx.packageInfo));
|
|
581
581
|
return 0;
|
|
582
582
|
}),
|
|
583
583
|
createContextCommand(["--version"], "Show CLI version", async (_args, ctx) => {
|
|
584
|
-
const { buildCliVersionText } = await import("./updateCommands-
|
|
584
|
+
const { buildCliVersionText } = await import("./updateCommands-2IHLKRE2.js");
|
|
585
585
|
console.log(buildCliVersionText(ctx.packageInfo));
|
|
586
586
|
return 0;
|
|
587
587
|
}),
|
|
588
588
|
createContextCommand(["-v"], "Show CLI version", async (_args, ctx) => {
|
|
589
|
-
const { buildCliVersionText } = await import("./updateCommands-
|
|
589
|
+
const { buildCliVersionText } = await import("./updateCommands-2IHLKRE2.js");
|
|
590
590
|
console.log(buildCliVersionText(ctx.packageInfo));
|
|
591
591
|
return 0;
|
|
592
592
|
}),
|
package/index.js
CHANGED
|
@@ -4,10 +4,9 @@ import {
|
|
|
4
4
|
initializeDiagnostics
|
|
5
5
|
} from "./chunk-EYLGAEB4.js";
|
|
6
6
|
import {
|
|
7
|
-
consumeWindowsUpdateStartupNotice,
|
|
8
7
|
getWindowsUpdateStatus,
|
|
9
8
|
readPackageInfo
|
|
10
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-2AALYZZF.js";
|
|
11
10
|
import {
|
|
12
11
|
isCompiledBinary
|
|
13
12
|
} from "./chunk-WACI5I6V.js";
|
|
@@ -41,16 +40,6 @@ if (process.platform === "win32") {
|
|
|
41
40
|
`);
|
|
42
41
|
process.exit(0);
|
|
43
42
|
}
|
|
44
|
-
const updateNotice = consumeWindowsUpdateStartupNotice(process.env, {
|
|
45
|
-
ownerUpdateId: process.env.NOLO_UPDATE_OWNER_ID
|
|
46
|
-
});
|
|
47
|
-
if (updateNotice) {
|
|
48
|
-
process.stderr.write(`${updateNotice.text}
|
|
49
|
-
`);
|
|
50
|
-
if (updateNotice.blocking) {
|
|
51
|
-
process.exit(75);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
43
|
}
|
|
55
44
|
var SOURCE_CLI_DIR = dirname(fileURLToPath(import.meta.url));
|
|
56
45
|
var CLI_DIR = isCompiledBinary() ? dirname(process.execPath) : SOURCE_CLI_DIR;
|
|
@@ -71,7 +60,7 @@ async function runScript(script, forwardedArgs, env) {
|
|
|
71
60
|
return proc.exited;
|
|
72
61
|
}
|
|
73
62
|
async function launchTuiWorkspace(args2) {
|
|
74
|
-
const { startTuiWorkspace } = await import("./readlineWorkspace-
|
|
63
|
+
const { startTuiWorkspace } = await import("./readlineWorkspace-XUUB3IXF.js");
|
|
75
64
|
const { createTuiSummaryLlmCaller } = await import("./tuiSummaryLlmCaller-FQOEF4IE.js");
|
|
76
65
|
const { setCliAutoCompactionSummaryFallback } = await import("./localRuntimeAdapter-ZIAOTUBE.js");
|
|
77
66
|
setCliAutoCompactionSummaryFallback(
|
|
@@ -85,7 +74,7 @@ async function launchTuiWorkspace(args2) {
|
|
|
85
74
|
});
|
|
86
75
|
}
|
|
87
76
|
async function main() {
|
|
88
|
-
const { createCliRuntimeContext, looksLikeDaemonShortcut, renderHelpText, resolveCommand, runResolvedCommand } = await import("./commandRegistry-
|
|
77
|
+
const { createCliRuntimeContext, looksLikeDaemonShortcut, renderHelpText, resolveCommand, runResolvedCommand } = await import("./commandRegistry-OMHWU6IC.js");
|
|
89
78
|
const { buildCliRuntimeEnv, loadProfileConfig } = await import("./profileConfig-KN3N2BLF.js");
|
|
90
79
|
const { resolveTuiLaunchMode } = await import("./runtimeModeArgs-2Y7BALTO.js");
|
|
91
80
|
const runtimeEnv = {
|
package/package.json
CHANGED
|
@@ -348,7 +348,7 @@ import {
|
|
|
348
348
|
import {
|
|
349
349
|
checkForCliUpdate,
|
|
350
350
|
runSelfUpdateDetailed
|
|
351
|
-
} from "./chunk-
|
|
351
|
+
} from "./chunk-2AALYZZF.js";
|
|
352
352
|
import {
|
|
353
353
|
parseUserIdFromAuthToken,
|
|
354
354
|
resolveAuthToken,
|
|
@@ -497,7 +497,7 @@ function createSnapshotGuardedApproval(kind, getGrants, approve) {
|
|
|
497
497
|
import nacl from "tweetnacl";
|
|
498
498
|
|
|
499
499
|
// node_modules/js-base64/base64.mjs
|
|
500
|
-
var version = "3.9.
|
|
500
|
+
var version = "3.9.5";
|
|
501
501
|
var VERSION = version;
|
|
502
502
|
var _TD = typeof TextDecoder === "function" ? new TextDecoder("utf-8", { ignoreBOM: true }) : void 0;
|
|
503
503
|
var _TE = typeof TextEncoder === "function" ? new TextEncoder() : void 0;
|
|
@@ -525,7 +525,7 @@ var btoaPolyfill = (bin) => {
|
|
|
525
525
|
return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
|
|
526
526
|
};
|
|
527
527
|
var _btoa = typeof btoa === "function" ? (bin) => btoa(bin) : btoaPolyfill;
|
|
528
|
-
var _fromUint8Array = typeof Uint8Array.prototype.toBase64 === "function" ? (
|
|
528
|
+
var _fromUint8Array = typeof Uint8Array.prototype.toBase64 === "function" ? Function.prototype.call.bind(Uint8Array.prototype.toBase64) : (u8a) => {
|
|
529
529
|
const maxargs = 4096;
|
|
530
530
|
let strs = [];
|
|
531
531
|
for (let i = 0, l = u8a.length; i < l; i += maxargs) {
|