open-agents-ai 0.187.459 → 0.187.461
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/dist/index.js +92 -13
- package/dist/launcher.cjs +67 -420
- package/dist/postinstall-daemon.cjs +162 -0
- package/dist/preinstall.cjs +2 -506
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -542151,7 +542151,10 @@ async function readExpandedVariantState(backendUrl, modelName) {
|
|
|
542151
542151
|
const showData = await showRes.json();
|
|
542152
542152
|
const currentNumCtx = parseShowNumCtx2(showData);
|
|
542153
542153
|
const fromMatch = showData.modelfile?.match(/^FROM\s+(.+)$/m);
|
|
542154
|
-
|
|
542154
|
+
let baseModel = fromMatch?.[1]?.trim() ?? null;
|
|
542155
|
+
if (baseModel && (baseModel.startsWith("/") || /blobs\/sha256[-:]/.test(baseModel))) {
|
|
542156
|
+
baseModel = null;
|
|
542157
|
+
}
|
|
542155
542158
|
return { currentNumCtx, baseModel };
|
|
542156
542159
|
} catch {
|
|
542157
542160
|
return null;
|
|
@@ -542161,6 +542164,11 @@ function stripVariantTag(modelName) {
|
|
|
542161
542164
|
return modelName.replace(/:latest$/i, "");
|
|
542162
542165
|
}
|
|
542163
542166
|
function createExpandedVariantContent(baseModel, numCtx) {
|
|
542167
|
+
if (baseModel.startsWith("/") || /blobs\/sha256[-:]/.test(baseModel)) {
|
|
542168
|
+
throw new Error(
|
|
542169
|
+
`createExpandedVariantContent: refusing to use blob-path base "${baseModel}". Pass the user-facing model name (e.g. "qwen3.6:latest") instead.`
|
|
542170
|
+
);
|
|
542171
|
+
}
|
|
542164
542172
|
const numPredict = Math.min(16384, Math.max(2048, Math.floor(numCtx * 0.25)));
|
|
542165
542173
|
return [
|
|
542166
542174
|
`FROM ${baseModel}`,
|
|
@@ -542284,6 +542292,23 @@ async function ensureExpandedContext(modelName, backendUrl) {
|
|
|
542284
542292
|
return { model: modelName, created: false, contextLabel: "", numCtx: 0 };
|
|
542285
542293
|
}
|
|
542286
542294
|
if (typeof existing === "string") {
|
|
542295
|
+
const lostTools = await wrapperLacksToolsCapability(backendUrl, existing).catch(() => false);
|
|
542296
|
+
if (lostTools) {
|
|
542297
|
+
try {
|
|
542298
|
+
const rebuilt = await createExpandedVariantNamedAsync(
|
|
542299
|
+
stripVariantTag(existing),
|
|
542300
|
+
modelName,
|
|
542301
|
+
specs,
|
|
542302
|
+
sizeGB,
|
|
542303
|
+
kvInfo?.kvBytesPerToken,
|
|
542304
|
+
kvInfo?.archMax
|
|
542305
|
+
);
|
|
542306
|
+
if (rebuilt) {
|
|
542307
|
+
return { model: rebuilt, created: true, contextLabel: ctx3.label, numCtx: ctx3.numCtx };
|
|
542308
|
+
}
|
|
542309
|
+
} catch {
|
|
542310
|
+
}
|
|
542311
|
+
}
|
|
542287
542312
|
const repair = await repairExpandedVariantIfStale(
|
|
542288
542313
|
existing,
|
|
542289
542314
|
modelName,
|
|
@@ -542302,6 +542327,38 @@ async function ensureExpandedContext(modelName, backendUrl) {
|
|
|
542302
542327
|
}
|
|
542303
542328
|
return { model: modelName, created: false, contextLabel: ctx3.label, numCtx: ctx3.numCtx };
|
|
542304
542329
|
}
|
|
542330
|
+
function guessBaseFromVariant(variantName, models) {
|
|
542331
|
+
const stripped = stripVariantTag(variantName);
|
|
542332
|
+
for (const m2 of models) {
|
|
542333
|
+
if (/^open-agents-/i.test(m2.name)) continue;
|
|
542334
|
+
const candidates = expandedModelCandidates(stripVariantTag(m2.name));
|
|
542335
|
+
if (candidates.includes(stripped)) {
|
|
542336
|
+
return m2.name;
|
|
542337
|
+
}
|
|
542338
|
+
}
|
|
542339
|
+
return null;
|
|
542340
|
+
}
|
|
542341
|
+
async function wrapperLacksToolsCapability(backendUrl, modelName) {
|
|
542342
|
+
try {
|
|
542343
|
+
const normalized = backendUrl.replace(/\/+$/, "");
|
|
542344
|
+
const showRes = await fetch(`${normalized}/api/show`, {
|
|
542345
|
+
method: "POST",
|
|
542346
|
+
headers: { "Content-Type": "application/json" },
|
|
542347
|
+
body: JSON.stringify({ name: modelName }),
|
|
542348
|
+
signal: AbortSignal.timeout(5e3)
|
|
542349
|
+
});
|
|
542350
|
+
if (!showRes.ok) return false;
|
|
542351
|
+
const showData = await showRes.json();
|
|
542352
|
+
const caps = Array.isArray(showData.capabilities) ? showData.capabilities : [];
|
|
542353
|
+
const hasTools = caps.some((c9) => /^tools?$/i.test(c9));
|
|
542354
|
+
if (hasTools) return false;
|
|
542355
|
+
const fromMatch = showData.modelfile?.match(/^FROM\s+(.+)$/m);
|
|
542356
|
+
const fromVal = fromMatch?.[1]?.trim() ?? "";
|
|
542357
|
+
return fromVal.startsWith("/") || /blobs\/sha256[-:]/.test(fromVal);
|
|
542358
|
+
} catch {
|
|
542359
|
+
return false;
|
|
542360
|
+
}
|
|
542361
|
+
}
|
|
542305
542362
|
async function repairAllExpandedVariants(backendUrl) {
|
|
542306
542363
|
const specs = await detectSystemSpecsAsync();
|
|
542307
542364
|
const models = await fetchOllamaModels(backendUrl);
|
|
@@ -542319,25 +542376,47 @@ async function repairAllExpandedVariants(backendUrl) {
|
|
|
542319
542376
|
summary.failed.push({ model: variant.name, reason: "missing-state" });
|
|
542320
542377
|
continue;
|
|
542321
542378
|
}
|
|
542322
|
-
|
|
542379
|
+
let baseModel = state.baseModel && !state.baseModel.startsWith("open-agents-") ? state.baseModel : null;
|
|
542380
|
+
if (!baseModel) {
|
|
542381
|
+
baseModel = guessBaseFromVariant(variant.name, models);
|
|
542382
|
+
}
|
|
542323
542383
|
if (!baseModel) {
|
|
542324
542384
|
summary.failed.push({ model: variant.name, reason: "missing-base-model" });
|
|
542325
542385
|
continue;
|
|
542326
542386
|
}
|
|
542327
|
-
const sizeGB = modelSizeGB(models, baseModel
|
|
542387
|
+
const sizeGB = modelSizeGB(models, baseModel);
|
|
542328
542388
|
const kvInfo = await queryModelKVInfo(backendUrl, baseModel);
|
|
542329
542389
|
const target = calculateExpandedVariantContextWindow(specs, sizeGB, kvInfo?.kvBytesPerToken, kvInfo?.archMax);
|
|
542390
|
+
const lostTools = await wrapperLacksToolsCapability(backendUrl, variant.name);
|
|
542330
542391
|
try {
|
|
542331
|
-
|
|
542332
|
-
|
|
542333
|
-
|
|
542334
|
-
|
|
542335
|
-
|
|
542336
|
-
|
|
542337
|
-
|
|
542338
|
-
|
|
542339
|
-
|
|
542340
|
-
|
|
542392
|
+
let result;
|
|
542393
|
+
if (lostTools) {
|
|
542394
|
+
const created = await createExpandedVariantNamedAsync(
|
|
542395
|
+
stripVariantTag(variant.name),
|
|
542396
|
+
baseModel,
|
|
542397
|
+
specs,
|
|
542398
|
+
sizeGB,
|
|
542399
|
+
kvInfo?.kvBytesPerToken,
|
|
542400
|
+
kvInfo?.archMax
|
|
542401
|
+
);
|
|
542402
|
+
result = {
|
|
542403
|
+
repaired: !!created,
|
|
542404
|
+
currentNumCtx: state.currentNumCtx,
|
|
542405
|
+
baseModel,
|
|
542406
|
+
resolvedModel: created ?? variant.name
|
|
542407
|
+
};
|
|
542408
|
+
} else {
|
|
542409
|
+
result = await repairExpandedVariantIfStale(
|
|
542410
|
+
variant.name,
|
|
542411
|
+
baseModel,
|
|
542412
|
+
backendUrl,
|
|
542413
|
+
specs,
|
|
542414
|
+
sizeGB,
|
|
542415
|
+
target.numCtx,
|
|
542416
|
+
kvInfo?.kvBytesPerToken,
|
|
542417
|
+
kvInfo?.archMax
|
|
542418
|
+
);
|
|
542419
|
+
}
|
|
542341
542420
|
if (result.repaired) {
|
|
542342
542421
|
summary.repaired.push({
|
|
542343
542422
|
model: result.resolvedModel,
|
package/dist/launcher.cjs
CHANGED
|
@@ -1,431 +1,78 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.log(" Platform: " + platform + "/" + arch);
|
|
31
|
-
console.log("");
|
|
32
|
-
|
|
33
|
-
// Detect if nvm is already installed
|
|
34
|
-
var nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
|
|
35
|
-
var hasNvm = false;
|
|
36
|
-
try { fs.statSync(path.join(nvmDir, "nvm.sh")); hasNvm = true; } catch (e) {}
|
|
37
|
-
|
|
38
|
-
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
39
|
-
|
|
40
|
-
function ask(question, cb) {
|
|
41
|
-
rl.question(question, function(answer) {
|
|
42
|
-
cb(answer.trim().toLowerCase());
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function hasCmd(cmd) {
|
|
47
|
-
try {
|
|
48
|
-
childProcess.execSync("which " + cmd, { stdio: "pipe", timeout: 3000 });
|
|
49
|
-
return true;
|
|
50
|
-
} catch (e) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function run(cmd) {
|
|
56
|
-
console.log(" $ " + cmd);
|
|
57
|
-
try {
|
|
58
|
-
childProcess.execSync(cmd, { stdio: "inherit" });
|
|
59
|
-
return true;
|
|
60
|
-
} catch (e) {
|
|
61
|
-
console.error(" Command failed: " + (e.message || e));
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function bail(msg) {
|
|
67
|
-
console.log(msg);
|
|
68
|
-
rl.close();
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Returns "curl -o-" or "wget -qO-" or null
|
|
73
|
-
function getDownloader() {
|
|
74
|
-
if (hasCmd("curl")) return "curl -o-";
|
|
75
|
-
if (hasCmd("wget")) return "wget -qO-";
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Try to install curl if neither curl nor wget is available
|
|
80
|
-
function ensureDownloader(next) {
|
|
81
|
-
var dl = getDownloader();
|
|
82
|
-
if (dl) { next(dl); return; }
|
|
83
|
-
|
|
84
|
-
console.log(" Neither curl nor wget found.");
|
|
85
|
-
console.log("");
|
|
86
|
-
|
|
87
|
-
ask(" Install curl now? [Y/n] ", function(a) {
|
|
88
|
-
if (a === "n" || a === "no") {
|
|
89
|
-
bail(
|
|
90
|
-
"\n Install manually:\n" +
|
|
91
|
-
" sudo apt install curl (Debian/Ubuntu)\n" +
|
|
92
|
-
" sudo dnf install curl (Fedora)\n" +
|
|
93
|
-
" sudo pacman -S curl (Arch)\n"
|
|
94
|
-
);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
console.log("");
|
|
98
|
-
var ok = false;
|
|
99
|
-
if (hasCmd("apt-get")) {
|
|
100
|
-
ok = run("sudo -n apt-get install -y curl 2>/dev/null || sudo apt-get install -y curl");
|
|
101
|
-
} else if (hasCmd("dnf")) {
|
|
102
|
-
ok = run("sudo -n dnf install -y curl 2>/dev/null || sudo dnf install -y curl");
|
|
103
|
-
} else if (hasCmd("pacman")) {
|
|
104
|
-
ok = run("sudo -n pacman -S --noconfirm curl 2>/dev/null || sudo pacman -S --noconfirm curl");
|
|
105
|
-
} else if (hasCmd("apk")) {
|
|
106
|
-
ok = run("apk add curl");
|
|
107
|
-
} else {
|
|
108
|
-
console.log(" No supported package manager found (tried apt, dnf, pacman, apk).");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (ok && hasCmd("curl")) {
|
|
112
|
-
console.log("");
|
|
113
|
-
next("curl -o-");
|
|
114
|
-
} else {
|
|
115
|
-
bail(
|
|
116
|
-
"\n Could not install curl. Install it manually, then re-run:\n" +
|
|
117
|
-
" npm i -g open-agents-ai\n"
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function doInstallNvm(dl, next) {
|
|
124
|
-
if (hasNvm) {
|
|
125
|
-
console.log(" nvm found at " + nvmDir);
|
|
126
|
-
console.log("");
|
|
127
|
-
next();
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
ask(" nvm is not installed. Install nvm now? [Y/n] ", function(a) {
|
|
131
|
-
if (a === "n" || a === "no") {
|
|
132
|
-
bail(
|
|
133
|
-
"\n Install nvm manually:\n" +
|
|
134
|
-
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
|
|
135
|
-
" # or: wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
|
|
136
|
-
" source ~/.bashrc\n" +
|
|
137
|
-
" nvm install 22\n" +
|
|
138
|
-
" npm i -g open-agents-ai\n"
|
|
139
|
-
);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
console.log("");
|
|
143
|
-
var ok = run(dl + " https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash");
|
|
144
|
-
if (!ok) {
|
|
145
|
-
bail("\n nvm install failed. See https://github.com/nvm-sh/nvm#installing-and-updating\n");
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
|
|
149
|
-
hasNvm = true;
|
|
150
|
-
console.log("");
|
|
151
|
-
next();
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function doInstallNode(next) {
|
|
156
|
-
ask(" Install Node.js 22 via nvm? [Y/n] ", function(a) {
|
|
157
|
-
if (a === "n" || a === "no") {
|
|
158
|
-
bail(
|
|
159
|
-
"\n Install manually:\n" +
|
|
160
|
-
" nvm install 22 && nvm alias default 22\n" +
|
|
161
|
-
" npm i -g open-agents-ai\n"
|
|
162
|
-
);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
console.log("");
|
|
166
|
-
var shell = process.env.SHELL || "/bin/bash";
|
|
167
|
-
var cmd = 'export NVM_DIR="' + nvmDir + '" && ' +
|
|
168
|
-
'[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ' +
|
|
169
|
-
"nvm install 22 && nvm use 22 && nvm alias default 22";
|
|
170
|
-
var ok = run(shell + " -c '" + cmd + "'");
|
|
171
|
-
if (!ok) {
|
|
172
|
-
bail("\n Node 22 install failed.\n");
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
console.log("");
|
|
176
|
-
next();
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Find the Node 22 binary installed by nvm
|
|
181
|
-
function findNode22Bin() {
|
|
182
|
-
// Check nvm versions directory for a v22.x binary
|
|
183
|
-
var versionsDir = path.join(nvmDir, "versions", "node");
|
|
184
|
-
try {
|
|
185
|
-
var versions = fs.readdirSync(versionsDir).filter(function(v) {
|
|
186
|
-
return v.startsWith("v22");
|
|
187
|
-
}).sort().reverse();
|
|
188
|
-
if (versions.length > 0) {
|
|
189
|
-
var bin = path.join(versionsDir, versions[0], "bin", "node");
|
|
190
|
-
try { fs.statSync(bin); return bin; } catch (e) {}
|
|
191
|
-
}
|
|
192
|
-
} catch (e) {}
|
|
193
|
-
// Fallback: ask nvm which node 22 is
|
|
194
|
-
try {
|
|
195
|
-
var shell = process.env.SHELL || "/bin/bash";
|
|
196
|
-
var result = childProcess.execSync(
|
|
197
|
-
shell + ' -c \'export NVM_DIR="' + nvmDir + '" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && nvm which 22\'',
|
|
198
|
-
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 10000 }
|
|
199
|
-
).trim();
|
|
200
|
-
if (result && fs.existsSync(result)) return result;
|
|
201
|
-
} catch (e) {}
|
|
202
|
-
return null;
|
|
2
|
+
// Robust launcher for open-agents CLI.
|
|
3
|
+
// - Runs the ESM entry as a child process
|
|
4
|
+
// - On exit code 120 (update), resets terminal and restarts child
|
|
5
|
+
// - Prevents raw-mode/mouse-tracking bleedthrough on restart or crash
|
|
6
|
+
|
|
7
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
8
|
+
const { resolve } = require('node:path');
|
|
9
|
+
|
|
10
|
+
function resetTerminal() {
|
|
11
|
+
try { if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') process.stdin.setRawMode(false); } catch {}
|
|
12
|
+
// Disable mouse tracking, bracketed paste, show cursor, reset attrs, exit alt screen if active
|
|
13
|
+
const ESC = '\x1B';
|
|
14
|
+
try {
|
|
15
|
+
process.stdout.write(
|
|
16
|
+
ESC + '[?25h' + // show cursor
|
|
17
|
+
ESC + '[?1000l' + // X10 mouse off
|
|
18
|
+
ESC + '[?1002l' + // button-event mouse off
|
|
19
|
+
ESC + '[?1003l' + // any-event mouse off
|
|
20
|
+
ESC + '[?1006l' + // SGR mouse off
|
|
21
|
+
ESC + '[?1015l' + // urxvt mouse off
|
|
22
|
+
ESC + '[?2004l' + // bracketed paste off
|
|
23
|
+
ESC + '[?1049l' + // exit alt screen
|
|
24
|
+
ESC + '[0m' // reset attributes
|
|
25
|
+
);
|
|
26
|
+
} catch {}
|
|
27
|
+
// stty sane (POSIX)
|
|
28
|
+
if (process.platform !== 'win32' && process.stdin.isTTY) {
|
|
29
|
+
try { spawnSync('stty', ['sane'], { stdio: 'inherit' }); } catch {}
|
|
203
30
|
}
|
|
31
|
+
}
|
|
204
32
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
try { fs.statSync(candidates[i]); return candidates[i]; } catch (e) {}
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
33
|
+
function runChild() {
|
|
34
|
+
const entry = resolve(__dirname, 'index.js');
|
|
35
|
+
const args = [entry, ...process.argv.slice(2)];
|
|
36
|
+
const child = spawn(process.execPath, args, {
|
|
37
|
+
stdio: 'inherit',
|
|
38
|
+
env: process.env,
|
|
39
|
+
});
|
|
40
|
+
return child;
|
|
41
|
+
}
|
|
218
42
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
43
|
+
(async () => {
|
|
44
|
+
let restarts = 0;
|
|
45
|
+
const MAX_RESTARTS = 3;
|
|
46
|
+
let child = runChild();
|
|
47
|
+
|
|
48
|
+
const forward = (sig) => {
|
|
49
|
+
try { child && child.kill(sig); } catch {}
|
|
50
|
+
};
|
|
51
|
+
process.on('SIGINT', () => forward('SIGINT'));
|
|
52
|
+
process.on('SIGTERM', () => forward('SIGTERM'));
|
|
53
|
+
|
|
54
|
+
function attach(childProc) {
|
|
55
|
+
childProc.on('exit', (code, signal) => {
|
|
56
|
+
if (signal) {
|
|
57
|
+
resetTerminal();
|
|
58
|
+
process.kill(process.pid, signal);
|
|
228
59
|
return;
|
|
229
60
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
"\n Reinstall failed. Open a new terminal, then run:\n" +
|
|
239
|
-
" npm i -g open-agents-ai\n"
|
|
240
|
-
);
|
|
241
|
-
rl.close();
|
|
242
|
-
process.exit(1);
|
|
61
|
+
if (code === 120 && restarts < MAX_RESTARTS) {
|
|
62
|
+
// Update-triggered restart
|
|
63
|
+
resetTerminal();
|
|
64
|
+
restarts += 1;
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
child = runChild();
|
|
67
|
+
attach(child);
|
|
68
|
+
}, 300);
|
|
243
69
|
return;
|
|
244
70
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
// Try to auto-relaunch under Node 22 — no new terminal needed
|
|
249
|
-
var node22 = findNode22Bin();
|
|
250
|
-
if (node22) {
|
|
251
|
-
var oaBin = findOaBin(node22);
|
|
252
|
-
if (oaBin) {
|
|
253
|
-
console.log(" ┌─────────────────────────────────────────────────┐");
|
|
254
|
-
console.log(" │ Done! Launching open-agents with Node 22... │");
|
|
255
|
-
console.log(" └─────────────────────────────────────────────────┘");
|
|
256
|
-
console.log("");
|
|
257
|
-
// Replace this process with Node 22 running the new oa launcher
|
|
258
|
-
try {
|
|
259
|
-
childProcess.execFileSync(node22, [oaBin], {
|
|
260
|
-
stdio: "inherit",
|
|
261
|
-
env: process.env,
|
|
262
|
-
});
|
|
263
|
-
} catch (e) {
|
|
264
|
-
// execFileSync throws when the child exits — that's normal
|
|
265
|
-
}
|
|
266
|
-
process.exit(0);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Fallback if we can't find Node 22 binary or oa script
|
|
271
|
-
console.log(" ┌─────────────────────────────────────────────────┐");
|
|
272
|
-
console.log(" │ Done! Open a new terminal and run: oa │");
|
|
273
|
-
console.log(" └─────────────────────────────────────────────────┘");
|
|
274
|
-
console.log("");
|
|
275
|
-
process.exit(0);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Walk through the steps
|
|
280
|
-
ask(" Upgrade to Node.js 22 now? [Y/n] ", function(a) {
|
|
281
|
-
if (a === "n" || a === "no") {
|
|
282
|
-
bail(
|
|
283
|
-
"\n To install manually:\n" +
|
|
284
|
-
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
|
|
285
|
-
" # or: wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
|
|
286
|
-
" source ~/.bashrc\n" +
|
|
287
|
-
" nvm install 22\n" +
|
|
288
|
-
" nvm alias default 22\n" +
|
|
289
|
-
" npm i -g open-agents-ai\n"
|
|
290
|
-
);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
console.log("");
|
|
294
|
-
// Ensure curl or wget is available first
|
|
295
|
-
ensureDownloader(function(dl) {
|
|
296
|
-
doInstallNvm(dl, function() {
|
|
297
|
-
doInstallNode(function() {
|
|
298
|
-
doReinstall();
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
} else {
|
|
304
|
-
// Node >= 22 — check sub-dependencies before loading the ESM bundle
|
|
305
|
-
var _path = require("path");
|
|
306
|
-
var _fs = require("fs");
|
|
307
|
-
var _cp = require("child_process");
|
|
308
|
-
|
|
309
|
-
// Resolve the package root (where package.json lives)
|
|
310
|
-
var _pkgDir = _path.dirname(__dirname.endsWith("dist") ? _path.dirname(__dirname) : __dirname);
|
|
311
|
-
// If we're in .../lib/node_modules/open-agents-ai/dist/, go up to the package root
|
|
312
|
-
var _pkgJson = _path.join(_pkgDir, "package.json");
|
|
313
|
-
if (!_fs.existsSync(_pkgJson)) {
|
|
314
|
-
_pkgDir = _path.resolve(__dirname, "..");
|
|
315
|
-
_pkgJson = _path.join(_pkgDir, "package.json");
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Dependencies to verify — both required and optional
|
|
319
|
-
var _criticalDeps = ["better-sqlite3", "ws", "zod", "glob", "ignore"];
|
|
320
|
-
var _optionalDeps = ["open-agents-nexus", "nats.ws", "moondream", "aiwg"];
|
|
321
|
-
var _missing = [];
|
|
322
|
-
var _missingOptional = [];
|
|
323
|
-
|
|
324
|
-
function _canResolve(name) {
|
|
325
|
-
try {
|
|
326
|
-
// Check if the module exists in the package's node_modules
|
|
327
|
-
var modDir = _path.join(_pkgDir, "node_modules", name);
|
|
328
|
-
if (_fs.existsSync(modDir)) return true;
|
|
329
|
-
// Also try require.resolve from the package dir
|
|
330
|
-
require.resolve(name, { paths: [_pkgDir] });
|
|
331
|
-
return true;
|
|
332
|
-
} catch (e) {
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
for (var _i = 0; _i < _criticalDeps.length; _i++) {
|
|
338
|
-
if (!_canResolve(_criticalDeps[_i])) _missing.push(_criticalDeps[_i]);
|
|
339
|
-
}
|
|
340
|
-
for (var _j = 0; _j < _optionalDeps.length; _j++) {
|
|
341
|
-
if (!_canResolve(_optionalDeps[_j])) _missingOptional.push(_optionalDeps[_j]);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
var _allMissing = _missing.concat(_missingOptional);
|
|
345
|
-
|
|
346
|
-
if (_allMissing.length > 0) {
|
|
347
|
-
var _label = _missing.length > 0 ? "required" : "optional";
|
|
348
|
-
console.log(" Installing " + _allMissing.length + " missing " + _label + " sub-dependencies...");
|
|
349
|
-
console.log(" Missing: " + _allMissing.join(", "));
|
|
350
|
-
console.log("");
|
|
351
|
-
|
|
352
|
-
// Run npm install in the package directory to restore all deps
|
|
353
|
-
try {
|
|
354
|
-
_cp.execSync("npm install --no-audit --no-fund", {
|
|
355
|
-
cwd: _pkgDir,
|
|
356
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
357
|
-
timeout: 120000,
|
|
358
|
-
env: Object.assign({}, process.env, { OA_SELF_UPGRADE: "1" }),
|
|
359
|
-
});
|
|
360
|
-
console.log(" Sub-dependencies installed.");
|
|
361
|
-
console.log("");
|
|
362
|
-
} catch (e) {
|
|
363
|
-
// If full install fails, try installing each missing dep individually
|
|
364
|
-
for (var _k = 0; _k < _allMissing.length; _k++) {
|
|
365
|
-
var _dep = _allMissing[_k];
|
|
366
|
-
try {
|
|
367
|
-
var _isOpt = _missingOptional.indexOf(_dep) !== -1;
|
|
368
|
-
console.log(" Installing " + _dep + (_isOpt ? " (optional)" : "") + "...");
|
|
369
|
-
_cp.execSync("npm install " + _dep + " --no-audit --no-fund" + (_isOpt ? " --save-optional" : ""), {
|
|
370
|
-
cwd: _pkgDir,
|
|
371
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
372
|
-
timeout: 60000,
|
|
373
|
-
});
|
|
374
|
-
} catch (e2) {
|
|
375
|
-
if (_missing.indexOf(_dep) !== -1) {
|
|
376
|
-
console.error(" WARNING: Failed to install required dep: " + _dep);
|
|
377
|
-
}
|
|
378
|
-
// Optional deps failing is fine
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Restart-aware launcher loop.
|
|
385
|
-
// Exit code 120 = restart requested (from /update).
|
|
386
|
-
// The launcher spawns the ESM bundle as a child process. If it exits with
|
|
387
|
-
// code 120, the launcher resets the terminal and spawns again. This way the
|
|
388
|
-
// restart happens in a CLEAN new Node process with zero inherited state —
|
|
389
|
-
// no mouse tracking, no raw mode, no buffered stdin, no timers.
|
|
390
|
-
var cp = require("child_process");
|
|
391
|
-
var path = require("path");
|
|
392
|
-
|
|
393
|
-
function runOA() {
|
|
394
|
-
var bundlePath = path.join(__dirname, "index.js");
|
|
395
|
-
var child = cp.fork(bundlePath, process.argv.slice(2), {
|
|
396
|
-
stdio: "inherit",
|
|
397
|
-
env: process.env,
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
child.on("exit", function(code) {
|
|
401
|
-
if (code === 120) {
|
|
402
|
-
// Restart requested — reset terminal then spawn again
|
|
403
|
-
if (process.stdout.isTTY) {
|
|
404
|
-
process.stdout.write(
|
|
405
|
-
"\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l" +
|
|
406
|
-
"\x1B[0m\x1B[r\x1B[?25h\x1B[?1049l\x1B[2J\x1B[3J\x1B[H"
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
// Reset terminal line discipline
|
|
410
|
-
try { require("child_process").execSync("stty sane 2>/dev/null", { stdio: "pipe" }); } catch(e) {}
|
|
411
|
-
// Drain any buffered stdin
|
|
412
|
-
if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
413
|
-
try { process.stdin.setRawMode(false); } catch(e) {}
|
|
414
|
-
}
|
|
415
|
-
// Set __OA_RESUMED for the new instance
|
|
416
|
-
process.env.__OA_RESUMED = "update-only";
|
|
417
|
-
// Brief pause then restart
|
|
418
|
-
setTimeout(runOA, 500);
|
|
419
|
-
} else {
|
|
420
|
-
process.exit(code || 0);
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
child.on("error", function(err) {
|
|
425
|
-
console.error("Failed to start open-agents:", err.message || err);
|
|
426
|
-
process.exit(1);
|
|
71
|
+
// Normal exit or too many restarts
|
|
72
|
+
resetTerminal();
|
|
73
|
+
process.exit(typeof code === 'number' ? code : 0);
|
|
427
74
|
});
|
|
428
75
|
}
|
|
429
76
|
|
|
430
|
-
|
|
431
|
-
}
|
|
77
|
+
attach(child);
|
|
78
|
+
})();
|
|
@@ -401,10 +401,172 @@ function waitForHealth(timeoutMs, cb) {
|
|
|
401
401
|
|
|
402
402
|
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
403
403
|
|
|
404
|
+
// ─── Wrapper-modelfile self-heal ───────────────────────────────────────────
|
|
405
|
+
// Old OA versions wrote `FROM <blob-path>` into open-agents-* wrappers,
|
|
406
|
+
// which strips TEMPLATE/RENDERER/PARSER metadata and breaks tools support.
|
|
407
|
+
// On upgrade, scan local Ollama for stale wrappers and rebuild them with
|
|
408
|
+
// `FROM <baseModel>`. Best-effort, silent on failure — postinstall must not
|
|
409
|
+
// fail npm install.
|
|
410
|
+
function repairBrokenWrappers() {
|
|
411
|
+
// Independent opt-out from daemon install — wrapper repair is a different
|
|
412
|
+
// concern and runs even when OA_SKIP_DAEMON_INSTALL=1, unless explicitly
|
|
413
|
+
// disabled.
|
|
414
|
+
if (process.env.OA_SKIP_WRAPPER_REPAIR === "1") return;
|
|
415
|
+
// Skip if ollama isn't on PATH.
|
|
416
|
+
var ollamaBin = "";
|
|
417
|
+
try {
|
|
418
|
+
ollamaBin = cp.execSync("command -v ollama 2>/dev/null || which ollama 2>/dev/null", {
|
|
419
|
+
encoding: "utf8", stdio: "pipe", timeout: 5000,
|
|
420
|
+
}).trim();
|
|
421
|
+
} catch (e) { /* ignore */ }
|
|
422
|
+
if (!ollamaBin) return;
|
|
423
|
+
|
|
424
|
+
// List models. Format is one per line: NAME ID SIZE MODIFIED.
|
|
425
|
+
var listOut = "";
|
|
426
|
+
try {
|
|
427
|
+
listOut = cp.execSync(ollamaBin + " list 2>/dev/null", {
|
|
428
|
+
encoding: "utf8", stdio: "pipe", timeout: 8000,
|
|
429
|
+
});
|
|
430
|
+
} catch (e) { return; }
|
|
431
|
+
var lines = listOut.split(/\r?\n/).filter(function (l) { return l.trim().length > 0; });
|
|
432
|
+
// Skip header row if present.
|
|
433
|
+
if (lines.length > 0 && /^NAME\s/i.test(lines[0])) lines = lines.slice(1);
|
|
434
|
+
var allNames = lines.map(function (l) { return l.split(/\s+/)[0]; });
|
|
435
|
+
var wrappers = allNames.filter(function (n) { return /^open-agents-/i.test(n); });
|
|
436
|
+
var bases = allNames.filter(function (n) { return !/^open-agents-/i.test(n); });
|
|
437
|
+
if (wrappers.length === 0) return;
|
|
438
|
+
|
|
439
|
+
function expandedName(base) {
|
|
440
|
+
// Mirror packages/cli/src/tui/setup.ts:expandedModelName.
|
|
441
|
+
var canonical = base.replace(/:latest$/i, "");
|
|
442
|
+
return "open-agents-" + canonical.replace(":", "-").replace(/\./g, "");
|
|
443
|
+
}
|
|
444
|
+
function legacyExpandedName(base) {
|
|
445
|
+
return "open-agents-" + base.replace(":", "-").replace(/\./g, "");
|
|
446
|
+
}
|
|
447
|
+
function stripTag(n) { return (n || "").replace(/:[^:]+$/, ""); }
|
|
448
|
+
function guessBase(wrapper) {
|
|
449
|
+
var stripped = stripTag(wrapper);
|
|
450
|
+
// Try the FULL base name first (e.g. "qwen3.6:27b") so size-tagged
|
|
451
|
+
// variants don't collide with each other. expandedName/legacyExpandedName
|
|
452
|
+
// handle the tag internally.
|
|
453
|
+
for (var i = 0; i < bases.length; i++) {
|
|
454
|
+
var name = bases[i];
|
|
455
|
+
if (expandedName(name) === stripped || legacyExpandedName(name) === stripped) {
|
|
456
|
+
return name;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
// Then fall back to stripped-tag base — this is the only way to match
|
|
460
|
+
// wrappers that were built from `<base>:latest` and got their canonical
|
|
461
|
+
// form (`open-agents-<base-stripped>`). Prefer bases tagged ":latest"
|
|
462
|
+
// so that ambiguity (qwen3.6:27b vs qwen3.6:35b vs qwen3.6:latest)
|
|
463
|
+
// resolves to the user-facing default.
|
|
464
|
+
var latestFirst = bases.slice().sort(function (a, b) {
|
|
465
|
+
var aL = /:latest$/i.test(a) ? 0 : 1;
|
|
466
|
+
var bL = /:latest$/i.test(b) ? 0 : 1;
|
|
467
|
+
return aL - bL;
|
|
468
|
+
});
|
|
469
|
+
for (var j = 0; j < latestFirst.length; j++) {
|
|
470
|
+
var basis = stripTag(latestFirst[j]);
|
|
471
|
+
if (expandedName(basis) === stripped || legacyExpandedName(basis) === stripped) {
|
|
472
|
+
return latestFirst[j];
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
function showCapabilities(name) {
|
|
478
|
+
try {
|
|
479
|
+
var out = cp.execSync(ollamaBin + " show " + name + " 2>/dev/null", {
|
|
480
|
+
encoding: "utf8", stdio: "pipe", timeout: 8000,
|
|
481
|
+
});
|
|
482
|
+
// Parse capabilities section
|
|
483
|
+
var inCaps = false;
|
|
484
|
+
var caps = [];
|
|
485
|
+
var rows = out.split(/\r?\n/);
|
|
486
|
+
for (var i = 0; i < rows.length; i++) {
|
|
487
|
+
var t = rows[i];
|
|
488
|
+
if (/^\s*Capabilities\s*$/.test(t)) { inCaps = true; continue; }
|
|
489
|
+
if (inCaps) {
|
|
490
|
+
if (/^\s*[A-Z][a-z]/.test(t) || t.trim() === "") { inCaps = false; continue; }
|
|
491
|
+
var v = t.trim();
|
|
492
|
+
if (v) caps.push(v.toLowerCase());
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return caps;
|
|
496
|
+
} catch (e) { return null; }
|
|
497
|
+
}
|
|
498
|
+
function modelfileLooksBlob(name) {
|
|
499
|
+
try {
|
|
500
|
+
var mf = cp.execSync(ollamaBin + " show --modelfile " + name + " 2>/dev/null", {
|
|
501
|
+
encoding: "utf8", stdio: "pipe", timeout: 8000,
|
|
502
|
+
});
|
|
503
|
+
var m = mf.match(/^FROM\s+(.+)$/m);
|
|
504
|
+
if (!m) return false;
|
|
505
|
+
var f = m[1].trim();
|
|
506
|
+
return f.charAt(0) === "/" || /blobs\/sha256[-:]/.test(f);
|
|
507
|
+
} catch (e) { return false; }
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
var modelDir = path.join(HOME, ".open-agents", "models");
|
|
511
|
+
try { fs.mkdirSync(modelDir, { recursive: true }); } catch (e) {}
|
|
512
|
+
|
|
513
|
+
var rebuilt = 0;
|
|
514
|
+
var skipped = 0;
|
|
515
|
+
for (var i = 0; i < wrappers.length; i++) {
|
|
516
|
+
var w = wrappers[i];
|
|
517
|
+
var caps = showCapabilities(w);
|
|
518
|
+
var hasTools = caps !== null ? caps.indexOf("tools") !== -1 : true;
|
|
519
|
+
var blobby = modelfileLooksBlob(w);
|
|
520
|
+
if (hasTools && !blobby) { skipped++; continue; }
|
|
521
|
+
var base = guessBase(w);
|
|
522
|
+
if (!base) { skipped++; continue; }
|
|
523
|
+
|
|
524
|
+
// Read current num_ctx so we don't shrink it below what's already baked.
|
|
525
|
+
var numCtx = 32768;
|
|
526
|
+
try {
|
|
527
|
+
var pa = cp.execSync(ollamaBin + " show --parameters " + w + " 2>/dev/null", {
|
|
528
|
+
encoding: "utf8", stdio: "pipe", timeout: 5000,
|
|
529
|
+
});
|
|
530
|
+
var nm = pa.match(/num_ctx\s+(\d+)/);
|
|
531
|
+
if (nm) numCtx = Math.max(numCtx, parseInt(nm[1], 10));
|
|
532
|
+
} catch (e) {}
|
|
533
|
+
var numPredict = Math.min(16384, Math.max(2048, Math.floor(numCtx * 0.25)));
|
|
534
|
+
var content =
|
|
535
|
+
"FROM " + base + "\n" +
|
|
536
|
+
"PARAMETER num_ctx " + numCtx + "\n" +
|
|
537
|
+
"PARAMETER temperature 0\n" +
|
|
538
|
+
"PARAMETER num_predict " + numPredict + "\n" +
|
|
539
|
+
'PARAMETER stop "<|endoftext|>"\n';
|
|
540
|
+
var mfPath = path.join(modelDir, "Modelfile." + stripTag(w));
|
|
541
|
+
try { fs.writeFileSync(mfPath, content, "utf8"); } catch (e) { skipped++; continue; }
|
|
542
|
+
|
|
543
|
+
try {
|
|
544
|
+
cp.execSync(ollamaBin + " create " + stripTag(w) + " -f " + JSON.stringify(mfPath) + " 2>&1", {
|
|
545
|
+
stdio: "pipe", timeout: 180000,
|
|
546
|
+
});
|
|
547
|
+
log("repaired wrapper: " + w + " (FROM " + base + ", num_ctx=" + numCtx + ")");
|
|
548
|
+
rebuilt++;
|
|
549
|
+
} catch (e) {
|
|
550
|
+
warn("failed to rebuild " + w + ": " + (e && e.message ? e.message.slice(0, 200) : "unknown"));
|
|
551
|
+
skipped++;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (rebuilt > 0) {
|
|
556
|
+
log("Rebuilt " + rebuilt + " stale OA wrapper(s); " + skipped + " unchanged.");
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
404
560
|
function main() {
|
|
405
561
|
// Always do the nexus cleanup first, regardless of opt-out.
|
|
406
562
|
cleanNexus();
|
|
407
563
|
|
|
564
|
+
// Auto-repair stale OA model wrappers BEFORE restarting the daemon, so the
|
|
565
|
+
// freshly-restarted daemon picks up the rebuilt models on first inference.
|
|
566
|
+
try { repairBrokenWrappers(); } catch (e) {
|
|
567
|
+
warn("wrapper auto-repair crashed (non-fatal): " + (e && e.message));
|
|
568
|
+
}
|
|
569
|
+
|
|
408
570
|
if (process.env.OA_SKIP_DAEMON_INSTALL === "1") {
|
|
409
571
|
log("OA_SKIP_DAEMON_INSTALL=1 — skipping daemon service install.");
|
|
410
572
|
return safeExit(0);
|
package/dist/preinstall.cjs
CHANGED
|
@@ -1,508 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// Cross-platform: Linux, macOS, Windows (cmd, PowerShell, Git Bash).
|
|
5
|
-
// If Node is too old, guides the user through installing Node 22.
|
|
6
|
-
var nodeVersion = parseInt(process.versions.node, 10);
|
|
2
|
+
// Preinstall hook shim — no-op by default
|
|
3
|
+
process.exit(0);
|
|
7
4
|
|
|
8
|
-
if (nodeVersion >= 22) {
|
|
9
|
-
// Good to go — let npm continue installing deps normally
|
|
10
|
-
process.exit(0);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Prevent infinite loop: if we're inside a self-triggered reinstall, bail
|
|
14
|
-
if (process.env.OA_SELF_UPGRADE === "1") {
|
|
15
|
-
console.log(" [preinstall] Skipping — already inside a self-upgrade.");
|
|
16
|
-
console.log(" If this Node is still too old, open a new terminal with Node 22 and run:");
|
|
17
|
-
console.log(" npm i -g open-agents-ai");
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
var os = require("os");
|
|
22
|
-
var path = require("path");
|
|
23
|
-
var fs = require("fs");
|
|
24
|
-
var childProcess = require("child_process");
|
|
25
|
-
var readline = require("readline");
|
|
26
|
-
var https = require("https");
|
|
27
|
-
var http = require("http");
|
|
28
|
-
|
|
29
|
-
var platform = os.platform(); // "win32", "linux", "darwin"
|
|
30
|
-
var arch = os.arch();
|
|
31
|
-
var isWindows = platform === "win32";
|
|
32
|
-
|
|
33
|
-
console.log("");
|
|
34
|
-
console.log(" +---------------------------------------------------+");
|
|
35
|
-
console.log(" | open-agents -- Node.js Check |");
|
|
36
|
-
console.log(" +---------------------------------------------------+");
|
|
37
|
-
console.log("");
|
|
38
|
-
console.log(" Your Node.js: " + process.version);
|
|
39
|
-
console.log(" Required: >= 22.0.0");
|
|
40
|
-
console.log(" Platform: " + platform + "/" + arch);
|
|
41
|
-
console.log("");
|
|
42
|
-
|
|
43
|
-
// ── Cross-platform helpers ───────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
function hasCmd(cmd) {
|
|
46
|
-
try {
|
|
47
|
-
if (isWindows) {
|
|
48
|
-
childProcess.execSync("where " + cmd, { stdio: "pipe", timeout: 5000 });
|
|
49
|
-
} else {
|
|
50
|
-
childProcess.execSync("which " + cmd, { stdio: "pipe", timeout: 3000 });
|
|
51
|
-
}
|
|
52
|
-
return true;
|
|
53
|
-
} catch (e) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function run(cmd, opts) {
|
|
59
|
-
console.log(" $ " + cmd);
|
|
60
|
-
try {
|
|
61
|
-
childProcess.execSync(cmd, Object.assign({ stdio: "inherit" }, opts || {}));
|
|
62
|
-
return true;
|
|
63
|
-
} catch (e) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
69
|
-
|
|
70
|
-
function ask(question, cb) {
|
|
71
|
-
rl.question(question, function(answer) {
|
|
72
|
-
cb(answer.trim().toLowerCase());
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function bail(msg) {
|
|
77
|
-
console.log(msg);
|
|
78
|
-
rl.close();
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ── Node.js-native HTTPS downloader (works everywhere, no curl needed) ──
|
|
83
|
-
|
|
84
|
-
function download(url, cb) {
|
|
85
|
-
var mod = url.indexOf("https:") === 0 ? https : http;
|
|
86
|
-
mod.get(url, function(res) {
|
|
87
|
-
// Follow redirects (301/302/307/308)
|
|
88
|
-
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
89
|
-
download(res.headers.location, cb);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (res.statusCode !== 200) {
|
|
93
|
-
cb(new Error("HTTP " + res.statusCode + " from " + url), null);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
var chunks = [];
|
|
97
|
-
res.on("data", function(chunk) { chunks.push(chunk); });
|
|
98
|
-
res.on("end", function() { cb(null, Buffer.concat(chunks)); });
|
|
99
|
-
res.on("error", function(err) { cb(err, null); });
|
|
100
|
-
}).on("error", function(err) { cb(err, null); });
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function downloadToFile(url, dest, cb) {
|
|
104
|
-
download(url, function(err, data) {
|
|
105
|
-
if (err) { cb(err); return; }
|
|
106
|
-
try {
|
|
107
|
-
fs.writeFileSync(dest, data);
|
|
108
|
-
cb(null);
|
|
109
|
-
} catch (e) {
|
|
110
|
-
cb(e);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ── Shell / downloader detection ─────────────────────────────────────────
|
|
116
|
-
|
|
117
|
-
// Returns a shell command prefix for piped downloads, or null.
|
|
118
|
-
// On Windows, we prefer the Node.js-native download() function instead.
|
|
119
|
-
function getShellDownloader() {
|
|
120
|
-
if (hasCmd("curl")) return "curl -fsSL";
|
|
121
|
-
if (hasCmd("wget")) return "wget -qO-";
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function getShell() {
|
|
126
|
-
if (isWindows) return null; // Windows doesn't use bash shells for nvm
|
|
127
|
-
return process.env.SHELL || "/bin/bash";
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ── nvm detection (Unix) ─────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
var nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
|
|
133
|
-
var hasNvm = false;
|
|
134
|
-
try { fs.statSync(path.join(nvmDir, "nvm.sh")); hasNvm = true; } catch (e) {}
|
|
135
|
-
|
|
136
|
-
// nvm-windows detection
|
|
137
|
-
var nvmWinDir = process.env.NVM_HOME || "";
|
|
138
|
-
var hasNvmWin = false;
|
|
139
|
-
if (isWindows) {
|
|
140
|
-
if (!nvmWinDir) {
|
|
141
|
-
// Common install location
|
|
142
|
-
var appData = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
|
|
143
|
-
nvmWinDir = path.join(appData, "nvm");
|
|
144
|
-
}
|
|
145
|
-
try { fs.statSync(path.join(nvmWinDir, "nvm.exe")); hasNvmWin = true; } catch (e) {}
|
|
146
|
-
if (!hasNvmWin) { try { hasNvmWin = hasCmd("nvm"); } catch (e) {} }
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ── Windows flow ─────────────────────────────────────────────────────────
|
|
150
|
-
|
|
151
|
-
function windowsInstallNode(next) {
|
|
152
|
-
console.log(" Windows detected. Checking Node.js install options...");
|
|
153
|
-
console.log("");
|
|
154
|
-
|
|
155
|
-
// Option 1: nvm-windows is installed
|
|
156
|
-
if (hasNvmWin) {
|
|
157
|
-
console.log(" nvm-windows found.");
|
|
158
|
-
ask(" Install Node.js 22 via nvm? [Y/n] ", function(a) {
|
|
159
|
-
if (a === "n" || a === "no") {
|
|
160
|
-
bail("\n Install manually:\n nvm install 22\n nvm use 22\n npm i -g open-agents-ai\n");
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
var ok = run("nvm install 22") && run("nvm use 22");
|
|
164
|
-
if (!ok) {
|
|
165
|
-
bail("\n nvm install failed. Try manually:\n nvm install 22\n nvm use 22\n npm i -g open-agents-ai\n");
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
next();
|
|
169
|
-
});
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Option 2: winget available (Windows 10 1709+ / Windows 11)
|
|
174
|
-
if (hasCmd("winget")) {
|
|
175
|
-
ask(" Install Node.js 22 via winget? [Y/n] ", function(a) {
|
|
176
|
-
if (a === "n" || a === "no") {
|
|
177
|
-
windowsFallbackInstructions();
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
var ok = run("winget install -e --id OpenJS.NodeJS.LTS --accept-source-agreements --accept-package-agreements");
|
|
181
|
-
if (ok) {
|
|
182
|
-
console.log("");
|
|
183
|
-
console.log(" Node.js 22 installed via winget.");
|
|
184
|
-
console.log(" Please close and reopen your terminal, then run:");
|
|
185
|
-
console.log(" npm i -g open-agents-ai");
|
|
186
|
-
console.log("");
|
|
187
|
-
rl.close();
|
|
188
|
-
process.exit(0);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
console.log(" winget install failed, trying alternative...");
|
|
192
|
-
windowsDirectDownload(next);
|
|
193
|
-
});
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Option 3: choco available
|
|
198
|
-
if (hasCmd("choco")) {
|
|
199
|
-
ask(" Install Node.js 22 via Chocolatey? [Y/n] ", function(a) {
|
|
200
|
-
if (a === "n" || a === "no") {
|
|
201
|
-
windowsFallbackInstructions();
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
var ok = run("choco install nodejs-lts -y");
|
|
205
|
-
if (ok) {
|
|
206
|
-
console.log("");
|
|
207
|
-
console.log(" Node.js installed via Chocolatey.");
|
|
208
|
-
console.log(" Please close and reopen your terminal, then run:");
|
|
209
|
-
console.log(" npm i -g open-agents-ai");
|
|
210
|
-
console.log("");
|
|
211
|
-
rl.close();
|
|
212
|
-
process.exit(0);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
console.log(" choco install failed, trying alternative...");
|
|
216
|
-
windowsDirectDownload(next);
|
|
217
|
-
});
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Option 4: scoop available
|
|
222
|
-
if (hasCmd("scoop")) {
|
|
223
|
-
ask(" Install Node.js 22 via scoop? [Y/n] ", function(a) {
|
|
224
|
-
if (a === "n" || a === "no") {
|
|
225
|
-
windowsFallbackInstructions();
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
var ok = run("scoop install nodejs-lts");
|
|
229
|
-
if (ok) {
|
|
230
|
-
console.log("");
|
|
231
|
-
console.log(" Node.js installed via scoop.");
|
|
232
|
-
console.log(" Please close and reopen your terminal, then run:");
|
|
233
|
-
console.log(" npm i -g open-agents-ai");
|
|
234
|
-
console.log("");
|
|
235
|
-
rl.close();
|
|
236
|
-
process.exit(0);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
console.log(" scoop install failed, trying direct download...");
|
|
240
|
-
windowsDirectDownload(next);
|
|
241
|
-
});
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Option 5: direct MSI download via Node.js native https
|
|
246
|
-
windowsDirectDownload(next);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function windowsDirectDownload(next) {
|
|
250
|
-
var msiArch = arch === "x64" ? "x64" : arch === "arm64" ? "arm64" : "x86";
|
|
251
|
-
var msiUrl = "https://nodejs.org/dist/v22.16.0/node-v22.16.0-" + msiArch + ".msi";
|
|
252
|
-
var msiDest = path.join(os.tmpdir(), "node-v22-installer.msi");
|
|
253
|
-
|
|
254
|
-
ask(" Download Node.js 22 installer directly? [Y/n] ", function(a) {
|
|
255
|
-
if (a === "n" || a === "no") {
|
|
256
|
-
windowsFallbackInstructions();
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
console.log("");
|
|
260
|
-
console.log(" Downloading Node.js 22 from nodejs.org...");
|
|
261
|
-
console.log(" URL: " + msiUrl);
|
|
262
|
-
console.log(" (this may take a moment)");
|
|
263
|
-
console.log("");
|
|
264
|
-
|
|
265
|
-
downloadToFile(msiUrl, msiDest, function(err) {
|
|
266
|
-
if (err) {
|
|
267
|
-
console.log(" Download failed: " + (err.message || err));
|
|
268
|
-
console.log("");
|
|
269
|
-
windowsFallbackInstructions();
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
console.log(" Downloaded to: " + msiDest);
|
|
273
|
-
console.log("");
|
|
274
|
-
console.log(" Launching installer...");
|
|
275
|
-
var ok = run("msiexec /i \"" + msiDest + "\"");
|
|
276
|
-
if (ok) {
|
|
277
|
-
console.log("");
|
|
278
|
-
console.log(" Node.js 22 installer completed.");
|
|
279
|
-
console.log(" Close and reopen your terminal, then run:");
|
|
280
|
-
console.log(" npm i -g open-agents-ai");
|
|
281
|
-
console.log("");
|
|
282
|
-
} else {
|
|
283
|
-
console.log("");
|
|
284
|
-
console.log(" Installer may have been cancelled or requires admin privileges.");
|
|
285
|
-
console.log(" Run the installer manually:");
|
|
286
|
-
console.log(" " + msiDest);
|
|
287
|
-
console.log("");
|
|
288
|
-
console.log(" Then reopen your terminal and run:");
|
|
289
|
-
console.log(" npm i -g open-agents-ai");
|
|
290
|
-
console.log("");
|
|
291
|
-
}
|
|
292
|
-
rl.close();
|
|
293
|
-
process.exit(0);
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function windowsFallbackInstructions() {
|
|
299
|
-
bail(
|
|
300
|
-
"\n Install Node.js 22 manually:\n\n" +
|
|
301
|
-
" Option 1 — Download from nodejs.org:\n" +
|
|
302
|
-
" https://nodejs.org/en/download/\n\n" +
|
|
303
|
-
" Option 2 — winget (Windows 10/11):\n" +
|
|
304
|
-
" winget install OpenJS.NodeJS.LTS\n\n" +
|
|
305
|
-
" Option 3 — Chocolatey:\n" +
|
|
306
|
-
" choco install nodejs-lts\n\n" +
|
|
307
|
-
" Option 4 — nvm-windows:\n" +
|
|
308
|
-
" https://github.com/coreybutler/nvm-windows/releases\n" +
|
|
309
|
-
" nvm install 22 && nvm use 22\n\n" +
|
|
310
|
-
" Then re-run: npm i -g open-agents-ai\n"
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// ── Unix flow (Linux / macOS) ────────────────────────────────────────────
|
|
315
|
-
|
|
316
|
-
function unixInstallNvm(next) {
|
|
317
|
-
if (hasNvm) {
|
|
318
|
-
console.log(" nvm found at " + nvmDir);
|
|
319
|
-
console.log("");
|
|
320
|
-
next();
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
ask(" nvm is not installed. Install nvm now? [Y/n] ", function(a) {
|
|
325
|
-
if (a === "n" || a === "no") {
|
|
326
|
-
bail(
|
|
327
|
-
"\n Install nvm manually:\n" +
|
|
328
|
-
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
|
|
329
|
-
" source ~/.bashrc\n" +
|
|
330
|
-
" nvm install 22\n" +
|
|
331
|
-
" npm i -g open-agents-ai\n"
|
|
332
|
-
);
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
console.log("");
|
|
336
|
-
|
|
337
|
-
// Try shell downloader first (curl/wget), fall back to Node.js native https
|
|
338
|
-
var dl = getShellDownloader();
|
|
339
|
-
if (dl) {
|
|
340
|
-
var ok = run(dl + " https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash");
|
|
341
|
-
if (ok) {
|
|
342
|
-
nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
|
|
343
|
-
hasNvm = true;
|
|
344
|
-
console.log("");
|
|
345
|
-
next();
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Fallback: download nvm install script via Node.js https module
|
|
351
|
-
console.log(" Downloading nvm install script via Node.js...");
|
|
352
|
-
download("https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh", function(err, data) {
|
|
353
|
-
if (err) {
|
|
354
|
-
bail("\n Could not download nvm install script: " + (err.message || err) +
|
|
355
|
-
"\n Install nvm manually: https://github.com/nvm-sh/nvm#installing-and-updating\n");
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
var scriptPath = path.join(os.tmpdir(), "nvm-install.sh");
|
|
359
|
-
fs.writeFileSync(scriptPath, data, { mode: 0o755 });
|
|
360
|
-
var shell = getShell();
|
|
361
|
-
var ok = run(shell + " " + scriptPath);
|
|
362
|
-
try { fs.unlinkSync(scriptPath); } catch (e) {}
|
|
363
|
-
if (!ok) {
|
|
364
|
-
bail("\n nvm install failed. See https://github.com/nvm-sh/nvm#installing-and-updating\n");
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
|
|
368
|
-
hasNvm = true;
|
|
369
|
-
console.log("");
|
|
370
|
-
next();
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function unixInstallNode(next) {
|
|
376
|
-
ask(" Install Node.js 22 via nvm? [Y/n] ", function(a) {
|
|
377
|
-
if (a === "n" || a === "no") {
|
|
378
|
-
bail(
|
|
379
|
-
"\n Install manually:\n" +
|
|
380
|
-
" nvm install 22 && nvm alias default 22\n" +
|
|
381
|
-
" npm i -g open-agents-ai\n"
|
|
382
|
-
);
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
console.log("");
|
|
386
|
-
var shell = getShell();
|
|
387
|
-
var cmd = 'export NVM_DIR="' + nvmDir + '" && ' +
|
|
388
|
-
'[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ' +
|
|
389
|
-
"nvm install 22 && nvm alias default 22";
|
|
390
|
-
var ok = run(shell + " -c '" + cmd + "'");
|
|
391
|
-
if (!ok) {
|
|
392
|
-
bail("\n Node 22 install failed.\n");
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
console.log("");
|
|
396
|
-
next();
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Find the Node 22 binary installed by nvm (Unix only)
|
|
401
|
-
function findNode22Bin() {
|
|
402
|
-
var versionsDir = path.join(nvmDir, "versions", "node");
|
|
403
|
-
try {
|
|
404
|
-
var versions = fs.readdirSync(versionsDir).filter(function(v) {
|
|
405
|
-
return v.startsWith("v22");
|
|
406
|
-
}).sort().reverse();
|
|
407
|
-
if (versions.length > 0) {
|
|
408
|
-
var bin = path.join(versionsDir, versions[0], "bin", "node");
|
|
409
|
-
try { fs.statSync(bin); return bin; } catch (e) {}
|
|
410
|
-
}
|
|
411
|
-
} catch (e) {}
|
|
412
|
-
try {
|
|
413
|
-
var shell = getShell();
|
|
414
|
-
var result = childProcess.execSync(
|
|
415
|
-
shell + ' -c \'export NVM_DIR="' + nvmDir + '" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && nvm which 22\'',
|
|
416
|
-
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 10000 }
|
|
417
|
-
).trim();
|
|
418
|
-
if (result && fs.existsSync(result)) return result;
|
|
419
|
-
} catch (e) {}
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
function unixReinstall() {
|
|
424
|
-
ask(" Reinstall open-agents under Node 22? [Y/n] ", function(a) {
|
|
425
|
-
if (a === "n" || a === "no") {
|
|
426
|
-
console.log(
|
|
427
|
-
"\n Open a new terminal, then run:\n" +
|
|
428
|
-
" npm i -g open-agents-ai\n"
|
|
429
|
-
);
|
|
430
|
-
rl.close();
|
|
431
|
-
process.exit(1);
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
console.log("");
|
|
435
|
-
var shell = getShell();
|
|
436
|
-
var cmd = 'export OA_SELF_UPGRADE=1 && export NVM_DIR="' + nvmDir + '" && ' +
|
|
437
|
-
'[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ' +
|
|
438
|
-
"nvm use 22 && npm i -g open-agents-ai";
|
|
439
|
-
var ok = run(shell + " -c '" + cmd + "'");
|
|
440
|
-
if (!ok) {
|
|
441
|
-
console.log(
|
|
442
|
-
"\n Reinstall failed. Open a new terminal, then run:\n" +
|
|
443
|
-
" npm i -g open-agents-ai\n"
|
|
444
|
-
);
|
|
445
|
-
rl.close();
|
|
446
|
-
process.exit(1);
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
console.log("");
|
|
450
|
-
|
|
451
|
-
// Tell the user exactly how to launch
|
|
452
|
-
var node22 = findNode22Bin();
|
|
453
|
-
var binHint = node22 ? path.dirname(node22) : "~/.nvm/versions/node/v22.x.x/bin";
|
|
454
|
-
console.log(" +---------------------------------------------------+");
|
|
455
|
-
console.log(" | Done! Node 22 installed + open-agents ready. |");
|
|
456
|
-
console.log(" +---------------------------------------------------+");
|
|
457
|
-
console.log("");
|
|
458
|
-
console.log(" To launch immediately (no new terminal needed):");
|
|
459
|
-
console.log(" " + binHint + "/oa");
|
|
460
|
-
console.log("");
|
|
461
|
-
console.log(" Or source your shell config first:");
|
|
462
|
-
var rcFile = (process.env.SHELL || "").indexOf("zsh") !== -1 ? "~/.zshrc" : "~/.bashrc";
|
|
463
|
-
console.log(" source " + rcFile + " && oa");
|
|
464
|
-
console.log("");
|
|
465
|
-
rl.close();
|
|
466
|
-
process.exit(0);
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// ── Main flow — branch on platform ───────────────────────────────────────
|
|
471
|
-
|
|
472
|
-
ask(" Install Node.js 22 now? [Y/n] ", function(a) {
|
|
473
|
-
if (a === "n" || a === "no") {
|
|
474
|
-
if (isWindows) {
|
|
475
|
-
windowsFallbackInstructions();
|
|
476
|
-
} else {
|
|
477
|
-
bail(
|
|
478
|
-
"\n To install manually:\n" +
|
|
479
|
-
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
|
|
480
|
-
" source ~/.bashrc\n" +
|
|
481
|
-
" nvm install 22\n" +
|
|
482
|
-
" nvm alias default 22\n" +
|
|
483
|
-
" npm i -g open-agents-ai\n"
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
console.log("");
|
|
489
|
-
|
|
490
|
-
if (isWindows) {
|
|
491
|
-
windowsInstallNode(function() {
|
|
492
|
-
console.log("");
|
|
493
|
-
console.log(" Node.js 22 should now be available.");
|
|
494
|
-
console.log(" Close and reopen your terminal, then run:");
|
|
495
|
-
console.log(" npm i -g open-agents-ai");
|
|
496
|
-
console.log("");
|
|
497
|
-
rl.close();
|
|
498
|
-
process.exit(0);
|
|
499
|
-
});
|
|
500
|
-
} else {
|
|
501
|
-
// Unix flow: ensure downloader -> nvm -> node 22 -> reinstall
|
|
502
|
-
unixInstallNvm(function() {
|
|
503
|
-
unixInstallNode(function() {
|
|
504
|
-
unixReinstall();
|
|
505
|
-
});
|
|
506
|
-
});
|
|
507
|
-
}
|
|
508
|
-
});
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-agents-ai",
|
|
3
|
-
"version": "0.187.
|
|
3
|
+
"version": "0.187.461",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "open-agents-ai",
|
|
9
|
-
"version": "0.187.
|
|
9
|
+
"version": "0.187.461",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "CC-BY-NC-4.0",
|
|
12
12
|
"dependencies": {
|
package/package.json
CHANGED