@splinterzzz/ouro 0.1.6 → 0.1.7
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/package.json +1 -1
- package/src/commands/upgrade.js +86 -0
- package/src/index.js +14 -1
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
|
|
5
|
+
// `ouro --upgrade` — pull the newest published ouro without making the user
|
|
6
|
+
// remember the package name or the -g install incantation. Read our own name
|
|
7
|
+
// and version out of package.json so this keeps working if the package is ever
|
|
8
|
+
// renamed or forked.
|
|
9
|
+
|
|
10
|
+
const pkg = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
11
|
+
|
|
12
|
+
const REGISTRY = "https://registry.npmjs.org";
|
|
13
|
+
|
|
14
|
+
async function latestVersion(name) {
|
|
15
|
+
// Scoped names (@scope/pkg) need the slash percent-encoded for the registry.
|
|
16
|
+
const res = await fetch(`${REGISTRY}/${name.replace("/", "%2f")}/latest`, {
|
|
17
|
+
headers: { accept: "application/json" },
|
|
18
|
+
signal: AbortSignal.timeout(8000),
|
|
19
|
+
});
|
|
20
|
+
if (!res.ok) throw new Error(`registry returned ${res.status}`);
|
|
21
|
+
return (await res.json()).version;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Numeric-aware semver compare, enough for the "is latest newer than ours"
|
|
25
|
+
// question. Prerelease tags are ignored — the registry `latest` dist-tag never
|
|
26
|
+
// points at one, so we'd never see them here.
|
|
27
|
+
function isNewer(a, b) {
|
|
28
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
29
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
30
|
+
for (let i = 0; i < 3; i++) {
|
|
31
|
+
if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) > (pb[i] ?? 0);
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function runInstall(spec) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
// npm is a .cmd shim on Windows — spawn without a shell needs the real name.
|
|
39
|
+
const cmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
40
|
+
const proc = spawn(cmd, ["install", "-g", spec], { stdio: "inherit", windowsHide: true });
|
|
41
|
+
proc.on("error", reject);
|
|
42
|
+
proc.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`npm exited with code ${code}`))));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function upgradeCommand() {
|
|
47
|
+
const name = pkg.name;
|
|
48
|
+
const current = pkg.version;
|
|
49
|
+
|
|
50
|
+
console.log("");
|
|
51
|
+
console.log(chalk.gray(` current ${current}`));
|
|
52
|
+
|
|
53
|
+
let latest;
|
|
54
|
+
try {
|
|
55
|
+
latest = await latestVersion(name);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.log(chalk.red(` ! couldn't reach the npm registry: ${err.message}`));
|
|
58
|
+
console.log(chalk.gray(` Try manually: `) + chalk.cyan(`npm install -g ${name}@latest`));
|
|
59
|
+
console.log("");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(chalk.gray(` latest ${latest}`));
|
|
64
|
+
|
|
65
|
+
if (!isNewer(latest, current)) {
|
|
66
|
+
console.log("");
|
|
67
|
+
console.log(chalk.green(` ✓ already on the latest version`));
|
|
68
|
+
console.log("");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log("");
|
|
73
|
+
console.log(chalk.cyan(` Updating ${name} → ${latest} …`));
|
|
74
|
+
console.log("");
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
await runInstall(`${name}@latest`);
|
|
78
|
+
console.log("");
|
|
79
|
+
console.log(chalk.green(` ✓ upgraded to ${latest}`) + chalk.gray(` — restart running services with `) + chalk.cyan("ouro restart"));
|
|
80
|
+
} catch (err) {
|
|
81
|
+
console.log("");
|
|
82
|
+
console.log(chalk.red(` ! upgrade failed: ${err.message}`));
|
|
83
|
+
console.log(chalk.gray(` Try manually: `) + chalk.cyan(`npm install -g ${name}@latest`));
|
|
84
|
+
}
|
|
85
|
+
console.log("");
|
|
86
|
+
}
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { startCommand } from "./commands/start.js";
|
|
|
10
10
|
import { stopCommand } from "./commands/stop.js";
|
|
11
11
|
import { statusCommand } from "./commands/status.js";
|
|
12
12
|
import { logsCommand } from "./commands/logs.js";
|
|
13
|
+
import { upgradeCommand } from "./commands/upgrade.js";
|
|
13
14
|
|
|
14
15
|
const pkg = JSON.parse(
|
|
15
16
|
readFileSync(new URL("../package.json", import.meta.url), "utf8")
|
|
@@ -29,7 +30,19 @@ program
|
|
|
29
30
|
"and agents that run on your existing Claude Code / Codex subscription.\n" +
|
|
30
31
|
"No API key required."
|
|
31
32
|
)
|
|
32
|
-
.version(pkg.version)
|
|
33
|
+
.version(pkg.version)
|
|
34
|
+
// Root `--upgrade` flag so `ouro --upgrade` works, mirroring `--version`.
|
|
35
|
+
// With subcommands present, commander only runs this root action when none
|
|
36
|
+
// matched — so `ouro` alone still falls through to help, and every real
|
|
37
|
+
// subcommand is untouched.
|
|
38
|
+
.option("--upgrade", "update ouro to the latest published version")
|
|
39
|
+
.action((opts) => (opts.upgrade ? upgradeCommand() : program.help()));
|
|
40
|
+
|
|
41
|
+
// `ouro upgrade` — the idiomatic subcommand form of the same thing.
|
|
42
|
+
program
|
|
43
|
+
.command("upgrade")
|
|
44
|
+
.description("Update ouro to the latest published version")
|
|
45
|
+
.action(upgradeCommand);
|
|
33
46
|
|
|
34
47
|
program
|
|
35
48
|
.command("init")
|