@glrs-dev/cli 2.0.0 → 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 +8 -0
- package/dist/chunk-SB3MLROC.js +113 -0
- package/dist/cli.js +21 -0
- package/dist/lib/auto-update.d.ts +23 -0
- package/dist/lib/auto-update.js +7 -0
- package/dist/vendor/harness-opencode/dist/cli.js +25 -14
- package/dist/vendor/harness-opencode/dist/index.js +1 -1
- package/dist/vendor/harness-opencode/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
9
|
+
## 2.0.1
|
|
10
|
+
|
|
3
11
|
## 2.0.0
|
|
4
12
|
|
|
5
13
|
## 1.2.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 };
|
|
@@ -22,8 +22,8 @@ import {
|
|
|
22
22
|
flag as flag2,
|
|
23
23
|
option as option3,
|
|
24
24
|
optional as optional3,
|
|
25
|
-
positional
|
|
26
|
-
restPositionals,
|
|
25
|
+
positional,
|
|
26
|
+
restPositionals as restPositionals2,
|
|
27
27
|
string as string2,
|
|
28
28
|
subcommands as subcommands2,
|
|
29
29
|
run
|
|
@@ -642,7 +642,8 @@ var configureCmd = command({
|
|
|
642
642
|
});
|
|
643
643
|
|
|
644
644
|
// src/pilot/cli/scope.ts
|
|
645
|
-
import { command as command2,
|
|
645
|
+
import { command as command2, restPositionals, string } from "cmd-ts";
|
|
646
|
+
import { input as input2 } from "@inquirer/prompts";
|
|
646
647
|
|
|
647
648
|
// src/pilot/scope.ts
|
|
648
649
|
import * as fs5 from "fs";
|
|
@@ -887,11 +888,10 @@ async function runScopePhase(opts) {
|
|
|
887
888
|
closeDb();
|
|
888
889
|
try {
|
|
889
890
|
const { spawn: spawn2 } = await import("child_process");
|
|
890
|
-
const
|
|
891
|
-
fs5.writeFileSync(promptPath, scoperPrompt, "utf8");
|
|
891
|
+
const scoperPrompt2 = buildScopePrompt({ goal, scopePath, workflowId });
|
|
892
892
|
const child = spawn2(
|
|
893
893
|
"opencode",
|
|
894
|
-
["--agent", "pilot-scoper", "--prompt",
|
|
894
|
+
["--agent", "pilot-scoper", "--prompt", scoperPrompt2],
|
|
895
895
|
{
|
|
896
896
|
stdio: "inherit",
|
|
897
897
|
// TUI takes over the terminal
|
|
@@ -903,10 +903,6 @@ async function runScopePhase(opts) {
|
|
|
903
903
|
child.on("close", (code) => resolve2(code ?? 1));
|
|
904
904
|
child.on("error", () => resolve2(1));
|
|
905
905
|
});
|
|
906
|
-
try {
|
|
907
|
-
fs5.unlinkSync(promptPath);
|
|
908
|
-
} catch {
|
|
909
|
-
}
|
|
910
906
|
if (exitCode !== 0) {
|
|
911
907
|
return {
|
|
912
908
|
ok: false,
|
|
@@ -999,14 +995,29 @@ var scopeCmd = command2({
|
|
|
999
995
|
name: "scope",
|
|
1000
996
|
description: "Start a new pilot workflow with interactive scoping. Produces scope.json for `pilot go`.",
|
|
1001
997
|
args: {
|
|
1002
|
-
|
|
998
|
+
goalWords: restPositionals({
|
|
1003
999
|
type: string,
|
|
1004
1000
|
displayName: "goal",
|
|
1005
|
-
description:
|
|
1001
|
+
description: "What you want to build (optional \u2014 will prompt if not provided)"
|
|
1006
1002
|
})
|
|
1007
1003
|
},
|
|
1008
|
-
handler: async ({
|
|
1004
|
+
handler: async ({ goalWords }) => {
|
|
1009
1005
|
const cwd = process.cwd();
|
|
1006
|
+
let goal = goalWords.join(" ").trim();
|
|
1007
|
+
if (!goal) {
|
|
1008
|
+
if (!process.stdin.isTTY) {
|
|
1009
|
+
process.stderr.write("pilot scope: no goal provided and not running in a TTY.\n");
|
|
1010
|
+
process.stderr.write(' Usage: pilot scope "<what you want to build>"\n');
|
|
1011
|
+
process.exit(1);
|
|
1012
|
+
}
|
|
1013
|
+
goal = await input2({
|
|
1014
|
+
message: "What do you want to build?"
|
|
1015
|
+
});
|
|
1016
|
+
if (!goal.trim()) {
|
|
1017
|
+
process.stderr.write("pilot scope: goal cannot be empty.\n");
|
|
1018
|
+
process.exit(1);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1010
1021
|
console.log(`
|
|
1011
1022
|
\x1B[1mPilot v2 \u2014 Scope phase\x1B[0m`);
|
|
1012
1023
|
console.log(`Goal: ${goal}
|
|
@@ -2293,7 +2304,7 @@ var planCheckCmd = command6({
|
|
|
2293
2304
|
type: optional3(string2),
|
|
2294
2305
|
description: "Structural validation; exits 1 if any item is invalid."
|
|
2295
2306
|
}),
|
|
2296
|
-
rest:
|
|
2307
|
+
rest: restPositionals2({
|
|
2297
2308
|
type: string2,
|
|
2298
2309
|
displayName: "plan-path",
|
|
2299
2310
|
description: "Path to a plan markdown file. Required unless --run / --check is given."
|
|
@@ -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.
|
|
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() {
|