reasonix 0.4.21 → 0.4.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -294
- package/dist/cli/index.js +207 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +81 -4
- package/dist/index.js +105 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -4260,11 +4260,109 @@ function sep() {
|
|
|
4260
4260
|
return process.platform === "win32" ? "\\" : "/";
|
|
4261
4261
|
}
|
|
4262
4262
|
|
|
4263
|
-
// src/
|
|
4264
|
-
|
|
4263
|
+
// src/version.ts
|
|
4264
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
4265
|
+
import { homedir as homedir3 } from "os";
|
|
4266
|
+
import { dirname as dirname5, join as join4 } from "path";
|
|
4267
|
+
import { fileURLToPath } from "url";
|
|
4268
|
+
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
4269
|
+
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
4270
|
+
var LATEST_FETCH_TIMEOUT_MS = 2e3;
|
|
4271
|
+
function readPackageVersion() {
|
|
4272
|
+
try {
|
|
4273
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
4274
|
+
for (let i = 0; i < 6; i++) {
|
|
4275
|
+
const p = join4(dir, "package.json");
|
|
4276
|
+
if (existsSync4(p)) {
|
|
4277
|
+
const pkg = JSON.parse(readFileSync6(p, "utf8"));
|
|
4278
|
+
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
4279
|
+
return pkg.version;
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
const parent = dirname5(dir);
|
|
4283
|
+
if (parent === dir) break;
|
|
4284
|
+
dir = parent;
|
|
4285
|
+
}
|
|
4286
|
+
} catch {
|
|
4287
|
+
}
|
|
4288
|
+
return "0.0.0-dev";
|
|
4289
|
+
}
|
|
4290
|
+
var VERSION = readPackageVersion();
|
|
4291
|
+
function cachePath(homeDirOverride) {
|
|
4292
|
+
return join4(homeDirOverride ?? homedir3(), ".reasonix", "version-cache.json");
|
|
4293
|
+
}
|
|
4294
|
+
function readCache(homeDirOverride) {
|
|
4295
|
+
try {
|
|
4296
|
+
const raw = readFileSync6(cachePath(homeDirOverride), "utf8");
|
|
4297
|
+
const parsed = JSON.parse(raw);
|
|
4298
|
+
if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
|
|
4299
|
+
return parsed;
|
|
4300
|
+
}
|
|
4301
|
+
} catch {
|
|
4302
|
+
}
|
|
4303
|
+
return null;
|
|
4304
|
+
}
|
|
4305
|
+
function writeCache(entry, homeDirOverride) {
|
|
4306
|
+
try {
|
|
4307
|
+
const p = cachePath(homeDirOverride);
|
|
4308
|
+
mkdirSync4(dirname5(p), { recursive: true });
|
|
4309
|
+
writeFileSync4(p, JSON.stringify(entry), "utf8");
|
|
4310
|
+
} catch {
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
async function getLatestVersion(opts = {}) {
|
|
4314
|
+
const ttl = opts.ttlMs ?? LATEST_CACHE_TTL_MS;
|
|
4315
|
+
if (!opts.force) {
|
|
4316
|
+
const cached = readCache(opts.homeDir);
|
|
4317
|
+
if (cached && Date.now() - cached.checkedAt < ttl) return cached.version;
|
|
4318
|
+
}
|
|
4319
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
4320
|
+
if (!fetchImpl) return null;
|
|
4321
|
+
const url = opts.registryUrl ?? REGISTRY_URL;
|
|
4322
|
+
const timeout = opts.timeoutMs ?? LATEST_FETCH_TIMEOUT_MS;
|
|
4323
|
+
const controller = new AbortController();
|
|
4324
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
4325
|
+
try {
|
|
4326
|
+
const res = await fetchImpl(url, {
|
|
4327
|
+
signal: controller.signal,
|
|
4328
|
+
headers: { accept: "application/json" }
|
|
4329
|
+
});
|
|
4330
|
+
if (!res.ok) return null;
|
|
4331
|
+
const body = await res.json();
|
|
4332
|
+
if (typeof body.version !== "string") return null;
|
|
4333
|
+
writeCache({ version: body.version, checkedAt: Date.now() }, opts.homeDir);
|
|
4334
|
+
return body.version;
|
|
4335
|
+
} catch {
|
|
4336
|
+
return null;
|
|
4337
|
+
} finally {
|
|
4338
|
+
clearTimeout(timer);
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
function compareVersions(a, b) {
|
|
4342
|
+
const [aCore = "0", aPre = ""] = a.split("-", 2);
|
|
4343
|
+
const [bCore = "0", bPre = ""] = b.split("-", 2);
|
|
4344
|
+
const aParts = aCore.split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
4345
|
+
const bParts = bCore.split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
4346
|
+
for (let i = 0; i < 3; i++) {
|
|
4347
|
+
const diff = (aParts[i] ?? 0) - (bParts[i] ?? 0);
|
|
4348
|
+
if (diff !== 0) return diff;
|
|
4349
|
+
}
|
|
4350
|
+
if (!aPre && !bPre) return 0;
|
|
4351
|
+
if (!aPre) return 1;
|
|
4352
|
+
if (!bPre) return -1;
|
|
4353
|
+
return aPre < bPre ? -1 : aPre > bPre ? 1 : 0;
|
|
4354
|
+
}
|
|
4355
|
+
function isNpxInstall() {
|
|
4356
|
+
const bin = process.argv[1] ?? "";
|
|
4357
|
+
if (/[/\\]_npx[/\\]/.test(bin)) return true;
|
|
4358
|
+
if (/[/\\]\.pnpm[/\\]/.test(bin) && /dlx/i.test(bin)) return true;
|
|
4359
|
+
const ua = process.env.npm_config_user_agent ?? "";
|
|
4360
|
+
if (ua.includes("npx/")) return true;
|
|
4361
|
+
return false;
|
|
4362
|
+
}
|
|
4265
4363
|
|
|
4266
4364
|
// src/cli/commands/chat.tsx
|
|
4267
|
-
import { existsSync as
|
|
4365
|
+
import { existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
4268
4366
|
import { render } from "ink";
|
|
4269
4367
|
import React15, { useState as useState7 } from "react";
|
|
4270
4368
|
|
|
@@ -5255,7 +5353,8 @@ function StatsPanel({
|
|
|
5255
5353
|
harvestOn,
|
|
5256
5354
|
branchBudget,
|
|
5257
5355
|
planMode,
|
|
5258
|
-
balance
|
|
5356
|
+
balance,
|
|
5357
|
+
updateAvailable
|
|
5259
5358
|
}) {
|
|
5260
5359
|
const hitPct = (summary.cacheHitRatio * 100).toFixed(1);
|
|
5261
5360
|
const hitColor = summary.cacheHitRatio >= 0.7 ? "green" : summary.cacheHitRatio >= 0.4 ? "yellow" : "red";
|
|
@@ -5263,7 +5362,7 @@ function StatsPanel({
|
|
|
5263
5362
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
|
|
5264
5363
|
const ctxRatio = summary.lastPromptTokens / ctxMax;
|
|
5265
5364
|
const ctxColor = ctxRatio >= 0.8 ? "red" : ctxRatio >= 0.5 ? "yellow" : void 0;
|
|
5266
|
-
return /* @__PURE__ */ React11.createElement(Box10, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Box10, { justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan", bold: true }, "Reasonix"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 model "), /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, model), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 prefix "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, prefixHash), harvestOn ? /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, " \xB7 branch", branchBudget) : null, planMode ? /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, " ", "\xB7 PLAN") : null), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "turns ", summary.turns, " \xB7 type /help")), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache hit "), /* @__PURE__ */ React11.createElement(Text10, { color: hitColor, bold: true }, hitPct, "%")), /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React11.createElement(Text10, { color: "green", bold: true }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")")), summary.lastPromptTokens > 0 ? /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "ctx "), /* @__PURE__ */ React11.createElement(Text10, { color: ctxColor, bold: ctxColor !== void 0 }, formatTokens(summary.lastPromptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " (", (ctxRatio * 100).toFixed(0), "%)"), ctxRatio >= 0.8 ? /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, " ", "\xB7 /compact") : null) : null, balance ? /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "balance "), /* @__PURE__ */ React11.createElement(Text10, { color: balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green", bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : "")) : null));
|
|
5365
|
+
return /* @__PURE__ */ React11.createElement(Box10, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Box10, { justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan", bold: true }, "Reasonix"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, ` v${VERSION}`), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 model "), /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, model), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 prefix "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, prefixHash), harvestOn ? /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, " \xB7 branch", branchBudget) : null, planMode ? /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, " ", "\xB7 PLAN") : null), /* @__PURE__ */ React11.createElement(Text10, null, updateAvailable ? /* @__PURE__ */ React11.createElement(Text10, { color: "yellow", bold: true }, `update: ${updateAvailable} \xB7 `) : null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "turns ", summary.turns, " \xB7 type /help"))), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache hit "), /* @__PURE__ */ React11.createElement(Text10, { color: hitColor, bold: true }, hitPct, "%")), /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React11.createElement(Text10, { color: "green", bold: true }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")")), summary.lastPromptTokens > 0 ? /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "ctx "), /* @__PURE__ */ React11.createElement(Text10, { color: ctxColor, bold: ctxColor !== void 0 }, formatTokens(summary.lastPromptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " (", (ctxRatio * 100).toFixed(0), "%)"), ctxRatio >= 0.8 ? /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, " ", "\xB7 /compact") : null) : null, balance ? /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "balance "), /* @__PURE__ */ React11.createElement(Text10, { color: balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green", bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : "")) : null));
|
|
5267
5366
|
}
|
|
5268
5367
|
function formatTokens(n) {
|
|
5269
5368
|
if (n < 1e3) return String(n);
|
|
@@ -6030,6 +6129,7 @@ function App({
|
|
|
6030
6129
|
const [toolProgress, setToolProgress] = useState5(null);
|
|
6031
6130
|
const [statusLine, setStatusLine] = useState5(null);
|
|
6032
6131
|
const [balance, setBalance] = useState5(null);
|
|
6132
|
+
const [updateAvailable, setUpdateAvailable] = useState5(null);
|
|
6033
6133
|
const lastEditSnapshots = useRef2(null);
|
|
6034
6134
|
const pendingEdits = useRef2([]);
|
|
6035
6135
|
const [pendingShell, setPendingShell] = useState5(null);
|
|
@@ -6101,6 +6201,17 @@ function App({
|
|
|
6101
6201
|
cancelled = true;
|
|
6102
6202
|
};
|
|
6103
6203
|
}, [loop]);
|
|
6204
|
+
useEffect2(() => {
|
|
6205
|
+
let cancelled = false;
|
|
6206
|
+
void (async () => {
|
|
6207
|
+
const latest = await getLatestVersion();
|
|
6208
|
+
if (cancelled || !latest) return;
|
|
6209
|
+
if (compareVersions(VERSION, latest) < 0) setUpdateAvailable(latest);
|
|
6210
|
+
})();
|
|
6211
|
+
return () => {
|
|
6212
|
+
cancelled = true;
|
|
6213
|
+
};
|
|
6214
|
+
}, []);
|
|
6104
6215
|
useEffect2(() => {
|
|
6105
6216
|
if (!progressSink) return;
|
|
6106
6217
|
progressSink.current = (info) => {
|
|
@@ -6659,7 +6770,8 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
6659
6770
|
harvestOn: loop.harvestEnabled,
|
|
6660
6771
|
branchBudget: loop.branchOptions.budget,
|
|
6661
6772
|
planMode,
|
|
6662
|
-
balance
|
|
6773
|
+
balance,
|
|
6774
|
+
updateAvailable
|
|
6663
6775
|
}
|
|
6664
6776
|
), /* @__PURE__ */ React12.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React12.createElement(EventRow, { key: item.id, event: item })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(EventRow, { event: streaming })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React12.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React12.createElement(
|
|
6665
6777
|
PlanRefineInput,
|
|
@@ -7016,7 +7128,7 @@ async function chatCommand(opts) {
|
|
|
7016
7128
|
const prior = loadSessionMessages(opts.session);
|
|
7017
7129
|
if (prior.length > 0) {
|
|
7018
7130
|
const p = sessionPath(opts.session);
|
|
7019
|
-
const mtime =
|
|
7131
|
+
const mtime = existsSync5(p) ? statSync3(p).mtime : /* @__PURE__ */ new Date();
|
|
7020
7132
|
sessionPreview = { messageCount: prior.length, lastActive: mtime };
|
|
7021
7133
|
}
|
|
7022
7134
|
} else if (opts.session && opts.forceNew) {
|
|
@@ -7085,7 +7197,7 @@ async function codeCommand(opts = {}) {
|
|
|
7085
7197
|
}
|
|
7086
7198
|
|
|
7087
7199
|
// src/cli/commands/diff.ts
|
|
7088
|
-
import { writeFileSync as
|
|
7200
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
7089
7201
|
import { basename as basename2 } from "path";
|
|
7090
7202
|
import { render as render2 } from "ink";
|
|
7091
7203
|
import React18 from "react";
|
|
@@ -7231,7 +7343,7 @@ async function diffCommand(opts) {
|
|
|
7231
7343
|
if (wantMarkdown) {
|
|
7232
7344
|
console.log(renderSummaryTable(report));
|
|
7233
7345
|
const md = renderMarkdown(report);
|
|
7234
|
-
|
|
7346
|
+
writeFileSync5(opts.mdPath, md, "utf8");
|
|
7235
7347
|
console.log(`
|
|
7236
7348
|
markdown report written to ${opts.mdPath}`);
|
|
7237
7349
|
return;
|
|
@@ -8038,13 +8150,13 @@ async function setupCommand(_opts = {}) {
|
|
|
8038
8150
|
}
|
|
8039
8151
|
|
|
8040
8152
|
// src/cli/commands/stats.ts
|
|
8041
|
-
import { existsSync as
|
|
8153
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
8042
8154
|
function statsCommand(opts) {
|
|
8043
|
-
if (!
|
|
8155
|
+
if (!existsSync6(opts.transcript)) {
|
|
8044
8156
|
console.error(`no such transcript: ${opts.transcript}`);
|
|
8045
8157
|
process.exit(1);
|
|
8046
8158
|
}
|
|
8047
|
-
const lines =
|
|
8159
|
+
const lines = readFileSync7(opts.transcript, "utf8").split(/\r?\n/).filter(Boolean);
|
|
8048
8160
|
let assistantTurns = 0;
|
|
8049
8161
|
let toolCalls = 0;
|
|
8050
8162
|
let lastTurn = 0;
|
|
@@ -8063,6 +8175,84 @@ function statsCommand(opts) {
|
|
|
8063
8175
|
console.log(`last turn index: ${lastTurn}`);
|
|
8064
8176
|
}
|
|
8065
8177
|
|
|
8178
|
+
// src/cli/commands/update.ts
|
|
8179
|
+
import { spawn as spawn3 } from "child_process";
|
|
8180
|
+
function planUpdate(input) {
|
|
8181
|
+
const diff = compareVersions(input.current, input.latest);
|
|
8182
|
+
if (diff > 0) {
|
|
8183
|
+
return {
|
|
8184
|
+
action: "newer-local",
|
|
8185
|
+
message: `current (${input.current}) is newer than the published ${input.latest} \u2014 nothing to do.`
|
|
8186
|
+
};
|
|
8187
|
+
}
|
|
8188
|
+
if (diff === 0) {
|
|
8189
|
+
return { action: "up-to-date", message: `reasonix ${input.current} is up to date.` };
|
|
8190
|
+
}
|
|
8191
|
+
if (input.npx) {
|
|
8192
|
+
return {
|
|
8193
|
+
action: "npx-hint",
|
|
8194
|
+
message: [
|
|
8195
|
+
`reasonix ${input.latest} is available.`,
|
|
8196
|
+
"you're running via npx \u2014 the next `npx reasonix ...` launch will auto-fetch",
|
|
8197
|
+
"the latest (npx caches packages for a short window). to force a refresh",
|
|
8198
|
+
"sooner, clear the cache: `npm cache clean --force`."
|
|
8199
|
+
].join("\n")
|
|
8200
|
+
};
|
|
8201
|
+
}
|
|
8202
|
+
return {
|
|
8203
|
+
action: "run-npm-install",
|
|
8204
|
+
message: `upgrading reasonix ${input.current} \u2192 ${input.latest}`,
|
|
8205
|
+
command: ["npm", "install", "-g", "reasonix@latest"]
|
|
8206
|
+
};
|
|
8207
|
+
}
|
|
8208
|
+
function defaultSpawn(argv) {
|
|
8209
|
+
return new Promise((resolve6, reject) => {
|
|
8210
|
+
const child = spawn3(argv[0], argv.slice(1), {
|
|
8211
|
+
stdio: "inherit",
|
|
8212
|
+
shell: process.platform === "win32"
|
|
8213
|
+
});
|
|
8214
|
+
child.once("error", reject);
|
|
8215
|
+
child.once("exit", (code) => resolve6(code ?? 1));
|
|
8216
|
+
});
|
|
8217
|
+
}
|
|
8218
|
+
async function updateCommand(opts = {}) {
|
|
8219
|
+
const write = opts.write ?? ((m) => process.stdout.write(m));
|
|
8220
|
+
const exit = opts.exit ?? ((c) => process.exit(c));
|
|
8221
|
+
const fetchLatest = opts.fetchLatest ?? (() => getLatestVersion({ force: true }));
|
|
8222
|
+
const isNpx = opts.isNpx ?? isNpxInstall;
|
|
8223
|
+
const doSpawn = opts.spawnInstall ?? defaultSpawn;
|
|
8224
|
+
write(`current: reasonix ${VERSION}
|
|
8225
|
+
`);
|
|
8226
|
+
const latest = await fetchLatest();
|
|
8227
|
+
if (!latest) {
|
|
8228
|
+
write("could not reach registry.npmjs.org \u2014 check your network.\n");
|
|
8229
|
+
exit(1);
|
|
8230
|
+
return;
|
|
8231
|
+
}
|
|
8232
|
+
write(`latest: reasonix ${latest}
|
|
8233
|
+
`);
|
|
8234
|
+
const plan = planUpdate({ current: VERSION, latest, npx: isNpx() });
|
|
8235
|
+
write(`
|
|
8236
|
+
${plan.message}
|
|
8237
|
+
`);
|
|
8238
|
+
if (plan.action !== "run-npm-install" || !plan.command) return;
|
|
8239
|
+
if (opts.dryRun) {
|
|
8240
|
+
write(`(dry run) would run: ${plan.command.join(" ")}
|
|
8241
|
+
`);
|
|
8242
|
+
return;
|
|
8243
|
+
}
|
|
8244
|
+
write(`
|
|
8245
|
+
running: ${plan.command.join(" ")}
|
|
8246
|
+
`);
|
|
8247
|
+
const code = await doSpawn(plan.command);
|
|
8248
|
+
if (code !== 0) {
|
|
8249
|
+
write(`
|
|
8250
|
+
npm exited with code ${code}. upgrade did not complete.
|
|
8251
|
+
`);
|
|
8252
|
+
exit(code);
|
|
8253
|
+
}
|
|
8254
|
+
}
|
|
8255
|
+
|
|
8066
8256
|
// src/cli/commands/version.ts
|
|
8067
8257
|
function versionCommand() {
|
|
8068
8258
|
console.log(`reasonix ${VERSION}`);
|
|
@@ -8255,6 +8445,11 @@ mcp.command("inspect <spec>").description(
|
|
|
8255
8445
|
}
|
|
8256
8446
|
});
|
|
8257
8447
|
program.command("version").description("Print Reasonix version.").action(versionCommand);
|
|
8448
|
+
program.command("update").description(
|
|
8449
|
+
"Check the npm registry for a newer Reasonix and install it. Detects npx vs global install; for npx users, prints a cache-refresh hint instead of running `npm i -g`."
|
|
8450
|
+
).option("--dry-run", "Print the plan without executing the install").action(async (opts) => {
|
|
8451
|
+
await updateCommand({ dryRun: !!opts.dryRun });
|
|
8452
|
+
});
|
|
8258
8453
|
program.parseAsync(process.argv).catch((err) => {
|
|
8259
8454
|
console.error(err);
|
|
8260
8455
|
process.exit(1);
|