@glrs-dev/cli 2.0.1 → 2.1.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @glrs-dev/cli
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#51](https://github.com/iceglober/glrs/pull/51) [`c3c6be8`](https://github.com/iceglober/glrs/commit/c3c6be8fb21052275f0ff4c60ba1ed3d93d5532f) Thanks [@iceglober](https://github.com/iceglober)! - Add auto-update to the `glrs` CLI. On every invocation (rate-limited to once per hour), checks the npm registry for a newer version. If found, installs it globally via `bun add -g` and re-execs the command so the user always runs the latest version. Disable with `GLRS_AUTO_UPDATE=0`.
8
+
3
9
  ## 2.0.1
4
10
 
5
11
  ## 2.0.0
@@ -0,0 +1,113 @@
1
+ // src/lib/auto-update.ts
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ import { execFileSync } from "child_process";
6
+ var PACKAGE_NAME = "@glrs-dev/cli";
7
+ var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
8
+ var REGISTRY_TIMEOUT_MS = 3e3;
9
+ function getStateDir() {
10
+ const dir = join(homedir(), ".glorious", "cli");
11
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
12
+ return dir;
13
+ }
14
+ function getStatePath() {
15
+ return join(getStateDir(), "auto-update.json");
16
+ }
17
+ function readState() {
18
+ try {
19
+ return JSON.parse(readFileSync(getStatePath(), "utf8"));
20
+ } catch {
21
+ return { lastCheckAt: 0, latestVersion: null };
22
+ }
23
+ }
24
+ function writeState(state) {
25
+ try {
26
+ writeFileSync(getStatePath(), JSON.stringify(state), "utf8");
27
+ } catch {
28
+ }
29
+ }
30
+ function getCurrentVersion() {
31
+ try {
32
+ const __dirname = import.meta.dir;
33
+ const pkgPath = join(__dirname, "..", "package.json");
34
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
35
+ return pkg.version ?? null;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ async function fetchLatestVersion() {
41
+ try {
42
+ const controller = new AbortController();
43
+ const timer = setTimeout(() => controller.abort(), REGISTRY_TIMEOUT_MS);
44
+ const res = await fetch(
45
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
46
+ { signal: controller.signal }
47
+ );
48
+ clearTimeout(timer);
49
+ if (!res.ok) return null;
50
+ const data = await res.json();
51
+ return data.version ?? null;
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+ function isNewer(current, latest) {
57
+ const parse = (v) => v.split(".").map(Number);
58
+ const [cMaj, cMin, cPat] = parse(current);
59
+ const [lMaj, lMin, lPat] = parse(latest);
60
+ if (lMaj > cMaj) return true;
61
+ if (lMaj < cMaj) return false;
62
+ if (lMin > cMin) return true;
63
+ if (lMin < cMin) return false;
64
+ return lPat > cPat;
65
+ }
66
+ async function autoUpdate() {
67
+ if (process.env["GLRS_AUTO_UPDATE"] === "0") return false;
68
+ if (process.env["CI"]) return false;
69
+ if (process.env["GLRS_UPDATING"] === "1") return false;
70
+ const currentVersion = getCurrentVersion();
71
+ if (!currentVersion) return false;
72
+ const state = readState();
73
+ const now = Date.now();
74
+ if (now - state.lastCheckAt < CHECK_INTERVAL_MS) {
75
+ if (state.latestVersion && isNewer(currentVersion, state.latestVersion)) {
76
+ return doUpdate(currentVersion, state.latestVersion);
77
+ }
78
+ return false;
79
+ }
80
+ const latestVersion = await fetchLatestVersion();
81
+ writeState({ lastCheckAt: now, latestVersion });
82
+ if (!latestVersion) return false;
83
+ if (!isNewer(currentVersion, latestVersion)) return false;
84
+ return doUpdate(currentVersion, latestVersion);
85
+ }
86
+ function doUpdate(currentVersion, latestVersion) {
87
+ process.stderr.write(
88
+ `\x1B[36m[glrs]\x1B[0m Updating ${currentVersion} \u2192 ${latestVersion}...
89
+ `
90
+ );
91
+ try {
92
+ execFileSync("bun", ["add", "-g", `${PACKAGE_NAME}@${latestVersion}`], {
93
+ stdio: ["ignore", "ignore", "pipe"],
94
+ timeout: 3e4,
95
+ env: { ...process.env, GLRS_UPDATING: "1" }
96
+ });
97
+ process.stderr.write(
98
+ `\x1B[36m[glrs]\x1B[0m Updated to ${latestVersion} \u2713
99
+ `
100
+ );
101
+ return true;
102
+ } catch (err) {
103
+ process.stderr.write(
104
+ `\x1B[33m[glrs]\x1B[0m Auto-update failed (running ${currentVersion}): ${err instanceof Error ? err.message : String(err)}
105
+ `
106
+ );
107
+ return false;
108
+ }
109
+ }
110
+
111
+ export {
112
+ autoUpdate
113
+ };
package/dist/cli.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env bun
2
+ import {
3
+ autoUpdate
4
+ } from "./chunk-SB3MLROC.js";
2
5
  import {
3
6
  HELP_TEXT,
4
7
  SUBCOMMANDS,
@@ -35,6 +38,24 @@ import "./chunk-3RG5ZIWI.js";
35
38
  import { spawn } from "child_process";
36
39
  import * as path from "path";
37
40
  import { subcommands, run } from "cmd-ts";
41
+ var updated = await autoUpdate();
42
+ if (updated) {
43
+ const child = spawn("glrs", process.argv.slice(2), {
44
+ stdio: "inherit",
45
+ env: { ...process.env, GLRS_UPDATING: "1" }
46
+ // prevent infinite loop
47
+ });
48
+ child.on("exit", (code, signal) => {
49
+ if (signal) {
50
+ process.kill(process.pid, signal);
51
+ return;
52
+ }
53
+ process.exit(code ?? 0);
54
+ });
55
+ child.on("error", () => process.exit(1));
56
+ await new Promise(() => {
57
+ });
58
+ }
38
59
  var args = process.argv.slice(2);
39
60
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h" || args[0] === "help") {
40
61
  process.stdout.write(HELP_TEXT);
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Auto-update for the glrs CLI.
3
+ *
4
+ * On every invocation, checks if a newer version is available on npm.
5
+ * If yes, installs it globally and re-execs the current command so the
6
+ * user always runs the latest version.
7
+ *
8
+ * Rate-limited: checks at most once per hour (timestamp file).
9
+ * Non-blocking on network failure: if the registry is unreachable, skip silently.
10
+ * Opt-out: set GLRS_AUTO_UPDATE=0 to disable.
11
+ *
12
+ * The update installs @glrs-dev/cli@latest which pulls the harness as
13
+ * a dependency (via the fixed changesets group), so both packages update together.
14
+ */
15
+ /**
16
+ * Run the auto-update check. Call this at the top of cli.ts.
17
+ *
18
+ * Returns true if the CLI was updated and the process should re-exec.
19
+ * Returns false if no update needed or update failed.
20
+ */
21
+ declare function autoUpdate(): Promise<boolean>;
22
+
23
+ export { autoUpdate };
@@ -0,0 +1,7 @@
1
+ import {
2
+ autoUpdate
3
+ } from "../chunk-SB3MLROC.js";
4
+ import "../chunk-3RG5ZIWI.js";
5
+ export {
6
+ autoUpdate
7
+ };
@@ -2531,7 +2531,7 @@ import { join as join10 } from "path";
2531
2531
  var APP_KEY = "A-US-3617699429";
2532
2532
  var ENDPOINT = "https://us.aptabase.com/api/v0/event";
2533
2533
  var PKG_NAME = "@glrs-dev/harness-plugin-opencode";
2534
- var PKG_VERSION = true ? "2.0.1" : "dev";
2534
+ var PKG_VERSION = true ? "2.1.0" : "dev";
2535
2535
  var DISABLED = process.env.HARNESS_OPENCODE_TELEMETRY === "0" || process.env.HARNESS_OPENCODE_TELEMETRY === "false" || process.env.DO_NOT_TRACK === "1" || process.env.CI === "true";
2536
2536
  var SESSION_ID = randomUUID();
2537
2537
  function getInstallId() {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glrs-dev/harness-plugin-opencode",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glrs-dev/cli",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Unified CLI for the @glrs-dev ecosystem — OpenCode agent harness dispatch + worktree management.",
5
5
  "license": "MIT",
6
6
  "repository": {