@tryglen/cli 0.5.1 → 0.6.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/README.md +3 -3
- package/dist/_utils/agents-table.d.ts +10 -0
- package/dist/_utils/agents-table.js +26 -0
- package/dist/_utils/agents-table.js.map +1 -0
- package/dist/_utils/cli-error.d.ts +11 -0
- package/dist/_utils/cli-error.js +24 -0
- package/dist/_utils/cli-error.js.map +1 -0
- package/dist/_utils/codex-app-server.js +4 -1
- package/dist/_utils/codex-app-server.js.map +1 -1
- package/dist/_utils/config.js +3 -1
- package/dist/_utils/config.js.map +1 -1
- package/dist/_utils/credentials.d.ts +1 -1
- package/dist/_utils/credentials.js +8 -3
- package/dist/_utils/credentials.js.map +1 -1
- package/dist/_utils/find-bin.d.ts +6 -0
- package/dist/_utils/find-bin.js +85 -0
- package/dist/_utils/find-bin.js.map +1 -0
- package/dist/_utils/http.d.ts +10 -3
- package/dist/_utils/http.js +56 -5
- package/dist/_utils/http.js.map +1 -1
- package/dist/_utils/loopback-server.d.ts +1 -1
- package/dist/_utils/loopback-server.js +17 -2
- package/dist/_utils/loopback-server.js.map +1 -1
- package/dist/_utils/open-browser.js +3 -0
- package/dist/_utils/open-browser.js.map +1 -1
- package/dist/_utils/plugin-status.d.ts +4 -0
- package/dist/_utils/plugin-status.js +23 -0
- package/dist/_utils/plugin-status.js.map +1 -0
- package/dist/_utils/run-bin.d.ts +13 -0
- package/dist/_utils/run-bin.js +51 -0
- package/dist/_utils/run-bin.js.map +1 -0
- package/dist/_utils/state-line.js +3 -1
- package/dist/_utils/state-line.js.map +1 -1
- package/dist/_utils/state.d.ts +1 -1
- package/dist/_utils/state.js +8 -2
- package/dist/_utils/state.js.map +1 -1
- package/dist/_utils/update.d.ts +20 -2
- package/dist/_utils/update.js +111 -15
- package/dist/_utils/update.js.map +1 -1
- package/dist/_utils/version.js +12 -1
- package/dist/_utils/version.js.map +1 -1
- package/dist/_utils/which.d.ts +3 -2
- package/dist/_utils/which.js +5 -12
- package/dist/_utils/which.js.map +1 -1
- package/dist/bin.js +44 -22
- package/dist/bin.js.map +1 -1
- package/dist/commands/doctor.d.ts +6 -3
- package/dist/commands/doctor.js +68 -54
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/incognito.d.ts +2 -1
- package/dist/commands/incognito.js +16 -4
- package/dist/commands/incognito.js.map +1 -1
- package/dist/commands/ingest.d.ts +1 -5
- package/dist/commands/ingest.js +47 -16
- package/dist/commands/ingest.js.map +1 -1
- package/dist/commands/install.d.ts +5 -1
- package/dist/commands/install.js +121 -81
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.d.ts +2 -1
- package/dist/commands/login.js +41 -10
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +2 -1
- package/dist/commands/logout.js +20 -5
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/onboard.d.ts +2 -1
- package/dist/commands/onboard.js +7 -3
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/org.d.ts +3 -2
- package/dist/commands/org.js +40 -9
- package/dist/commands/org.js.map +1 -1
- package/dist/commands/search.d.ts +2 -4
- package/dist/commands/search.js +25 -16
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/session-start.d.ts +6 -3
- package/dist/commands/session-start.js +16 -6
- package/dist/commands/session-start.js.map +1 -1
- package/dist/commands/status.d.ts +2 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.d.ts +7 -5
- package/dist/commands/statusline.js +18 -8
- package/dist/commands/statusline.js.map +1 -1
- package/dist/commands/uninstall.d.ts +2 -1
- package/dist/commands/uninstall.js +8 -3
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts +10 -3
- package/dist/commands/update.js +111 -12
- package/dist/commands/update.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,9 +21,9 @@ glen login
|
|
|
21
21
|
| `glen org list` | List your organizations; active one is marked with `✓`. |
|
|
22
22
|
| `glen org switch [slug]` | Switch the active organization for this machine (interactive picker without `slug`). |
|
|
23
23
|
| `glen ingest [--agent <name>]` | Ingest a turn from stdin — used by agent hooks (`claude-code` or `codex`). |
|
|
24
|
-
| `glen install` |
|
|
25
|
-
| `glen update` | Update the glen CLI
|
|
26
|
-
| `glen doctor [--auto]` |
|
|
24
|
+
| `glen install [--agent <claude\|codex>]` | Set up or update glen for detected coding agents (plugin + hooks); idempotent, so re-running repairs a broken setup. `--claude-path <path>` / `--codex-path <path>` point at a binary when auto-detection fails. |
|
|
25
|
+
| `glen update` | Update the glen CLI **and** any installed glen plugins, and re-verify the Codex hook registration. Never installs a plugin that isn't already installed — that's `glen install`'s job. |
|
|
26
|
+
| `glen doctor [--auto]` | Print machine-readable `status:` lines (CLI version/latest/channel, login + org, per-agent plugin + hook state) plus `→` remedy lines — the glen-setup skill branches on them. `--auto` runs background updates silently (used by hooks). |
|
|
27
27
|
| `glen statusline` | Output a single status line for the agent's UI status bar — used by hooks. |
|
|
28
28
|
| `glen session-start [--agent <name>]` | Output hook JSON for the agent's `SessionStart` event — used by hooks. |
|
|
29
29
|
| `glen version` | Print the CLI version. |
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type Agent = {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly bin: "claude" | "codex";
|
|
4
|
+
readonly steps: readonly (readonly string[])[];
|
|
5
|
+
readonly updateSteps: readonly (readonly string[])[];
|
|
6
|
+
readonly postInstall: "claude" | "codex";
|
|
7
|
+
};
|
|
8
|
+
declare const AGENTS: readonly Agent[];
|
|
9
|
+
export { AGENTS };
|
|
10
|
+
export type { Agent };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const AGENTS = [
|
|
2
|
+
{
|
|
3
|
+
name: "Claude Code",
|
|
4
|
+
bin: "claude",
|
|
5
|
+
steps: [
|
|
6
|
+
["plugin", "marketplace", "add", "Glen-Web-App/glen-claude-code-plugin"],
|
|
7
|
+
["plugin", "install", "glen@glen"],
|
|
8
|
+
],
|
|
9
|
+
updateSteps: [["plugin", "update", "glen@glen"]],
|
|
10
|
+
postInstall: "claude",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "Codex",
|
|
14
|
+
bin: "codex",
|
|
15
|
+
steps: [
|
|
16
|
+
["plugin", "marketplace", "add", "Glen-Web-App/glen-codex-plugin"],
|
|
17
|
+
// codex requires the <plugin>@<marketplace> form (or --marketplace);
|
|
18
|
+
// a bare "glen" fails with "plugin requires --marketplace".
|
|
19
|
+
["plugin", "add", "glen@glen"],
|
|
20
|
+
],
|
|
21
|
+
updateSteps: [["plugin", "marketplace", "upgrade", "glen"]],
|
|
22
|
+
postInstall: "codex",
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
export { AGENTS };
|
|
26
|
+
//# sourceMappingURL=agents-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-table.js","sourceRoot":"","sources":["../../src/_utils/agents-table.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,GAAqB;IAC/B;QACE,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE,QAAQ;QACb,KAAK,EAAE;YACL,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,sCAAsC,CAAC;YACxE,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC;SACnC;QACD,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAChD,WAAW,EAAE,QAAQ;KACtB;IACD;QACE,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,OAAO;QACZ,KAAK,EAAE;YACL,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gCAAgC,CAAC;YAClE,qEAAqE;YACrE,4DAA4D;YAC5D,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC;SAC/B;QACD,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC3D,WAAW,EAAE,OAAO;KACrB;CACF,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type CliError = {
|
|
2
|
+
readonly what: string;
|
|
3
|
+
readonly why?: string;
|
|
4
|
+
readonly path?: string;
|
|
5
|
+
readonly remedy: string;
|
|
6
|
+
};
|
|
7
|
+
declare const cliErr: (e: CliError) => CliError;
|
|
8
|
+
declare const causeOf: (e: unknown) => string;
|
|
9
|
+
declare const formatCliError: (e: CliError) => string;
|
|
10
|
+
export { cliErr, causeOf, formatCliError };
|
|
11
|
+
export type { CliError };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Identity constructor — exists so call sites read as cliErr({...}) and the
|
|
2
|
+
// contract scan can distinguish structured errors from raw strings.
|
|
3
|
+
const cliErr = (e) => e;
|
|
4
|
+
// Best-effort root-cause string from an unknown caught value.
|
|
5
|
+
const causeOf = (e) => {
|
|
6
|
+
if (typeof e === "string" && e.length > 0)
|
|
7
|
+
return e;
|
|
8
|
+
if (e instanceof Error) {
|
|
9
|
+
const code = e.code;
|
|
10
|
+
return code ? `${code}: ${e.message}` : e.message;
|
|
11
|
+
}
|
|
12
|
+
return "unknown error";
|
|
13
|
+
};
|
|
14
|
+
const formatCliError = (e) => {
|
|
15
|
+
const lines = [`✗ ${e.what}`];
|
|
16
|
+
if (e.why)
|
|
17
|
+
lines.push(` cause: ${e.why}`);
|
|
18
|
+
if (e.path)
|
|
19
|
+
lines.push(` path: ${e.path}`);
|
|
20
|
+
lines.push(` → ${e.remedy}`);
|
|
21
|
+
return `${lines.join("\n")}\n`;
|
|
22
|
+
};
|
|
23
|
+
export { cliErr, causeOf, formatCliError };
|
|
24
|
+
//# sourceMappingURL=cli-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-error.js","sourceRoot":"","sources":["../../src/_utils/cli-error.ts"],"names":[],"mappings":"AAYA,4EAA4E;AAC5E,oEAAoE;AACpE,MAAM,MAAM,GAAG,CAAC,CAAW,EAAY,EAAE,CAAC,CAAC,CAAC;AAE5C,8DAA8D;AAC9D,MAAM,OAAO,GAAG,CAAC,CAAU,EAAU,EAAE;IACrC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,YAAY,KAAK,EAAE,CAAC;QACvB,MAAM,IAAI,GAAI,CAA2B,CAAC,IAAI,CAAC;QAC/C,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACpD,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,CAAW,EAAU,EAAE;IAC7C,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9B,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { findBin } from "./find-bin.js";
|
|
2
3
|
import { err, ok } from "./result.js";
|
|
3
4
|
import { cliVersion } from "./version.js";
|
|
4
5
|
const TIMEOUT_MS = 15_000;
|
|
@@ -30,7 +31,9 @@ const extractEntries = (msg) => {
|
|
|
30
31
|
};
|
|
31
32
|
const rpc = (id, method, params) => `${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`;
|
|
32
33
|
const listCodexHooks = (cwd) => new Promise((resolve) => {
|
|
33
|
-
|
|
34
|
+
// Resolve via findBin so users whose codex lives off this process's PATH
|
|
35
|
+
// (well-known dirs, login-shell PATH, --codex-path override) still work.
|
|
36
|
+
const child = spawn(findBin("codex") ?? "codex", ["app-server"], {
|
|
34
37
|
stdio: ["pipe", "pipe", "ignore"],
|
|
35
38
|
});
|
|
36
39
|
const finish = (r) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-app-server.js","sourceRoot":"","sources":["../../src/_utils/codex-app-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAe,GAAG,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAe1C,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,MAAM,cAAc,GAAG,CAAC,GAAY,EAA2B,EAAE;IAC/D,MAAM,MAAM,GAAI,GAAuC,CAAC,MAAM,CAAC;IAC/D,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAA6B,EAAE,CAAC;QACxD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QACzC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAkC,EAAE,CAAC;YACxD,IACE,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;gBACzB,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;gBAC7B,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;gBAC5B,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ;gBACjC,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,EACjC,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC;oBACX,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;iBAC3B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,MAAc,EAAE,MAAe,EAAU,EAAE,CAClE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC;AAEhE,MAAM,cAAc,GAAG,CACrB,GAAW,EACgC,EAAE,CAC7C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"codex-app-server.js","sourceRoot":"","sources":["../../src/_utils/codex-app-server.ts"],"names":[],"mappings":"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"}
|
package/dist/_utils/config.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
// Strip trailing slashes so a GLEN_BASE_URL like "https://x.test/" doesn't
|
|
2
|
+
// produce double-slash endpoint URLs ("https://x.test//api/…").
|
|
3
|
+
const baseUrl = (process.env.GLEN_BASE_URL ?? "https://app.tryglen.com").replace(/\/+$/, "");
|
|
2
4
|
const config = {
|
|
3
5
|
baseUrl,
|
|
4
6
|
connectUrl: `${baseUrl}/connect/cli`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,UAAU,EAAE,GAAG,OAAO,cAAc;IACpC,WAAW,EAAE,GAAG,OAAO,2BAA2B;IAClD,OAAO,EAAE,GAAG,OAAO,qBAAqB;IACxC,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,eAAe,EAAE,IAAI;IACrB,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;CAC1B,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -6,7 +6,7 @@ type Credentials = {
|
|
|
6
6
|
declare const credentialsPath: () => string;
|
|
7
7
|
declare const readCredentials: () => Promise<Credentials | null>;
|
|
8
8
|
declare const writeCredentials: (creds: Credentials) => Promise<Result<void, unknown>>;
|
|
9
|
-
declare const clearCredentials: () => Promise<void
|
|
9
|
+
declare const clearCredentials: () => Promise<Result<void, unknown>>;
|
|
10
10
|
declare const resolveAuthHeader: () => Promise<{
|
|
11
11
|
headerName: "x-api-key";
|
|
12
12
|
headerValue: string;
|
|
@@ -33,7 +33,8 @@ const writeCredentials = async (creds) => {
|
|
|
33
33
|
const mkdirResult = await fromPromise(mkdir(dir, { recursive: true, mode: 0o700 }));
|
|
34
34
|
if (!mkdirResult.ok)
|
|
35
35
|
return mkdirResult;
|
|
36
|
-
|
|
36
|
+
// pid-suffixed so concurrent writers never clobber each other's tmp file.
|
|
37
|
+
const tmpPath = `${filePath}.${process.pid}.tmp`;
|
|
37
38
|
const json = JSON.stringify(creds, null, 2);
|
|
38
39
|
const writeResult = await fromPromise(writeFile(tmpPath, json, { mode: 0o600 }));
|
|
39
40
|
if (!writeResult.ok)
|
|
@@ -46,9 +47,13 @@ const writeCredentials = async (creds) => {
|
|
|
46
47
|
return renameResult;
|
|
47
48
|
return { ok: true, value: undefined };
|
|
48
49
|
};
|
|
50
|
+
// ENOENT counts as success (nothing to clear); any other failure is returned
|
|
51
|
+
// so the caller can tell the user the file is still on disk.
|
|
49
52
|
const clearCredentials = async () => {
|
|
50
|
-
const
|
|
51
|
-
|
|
53
|
+
const r = await fromPromise(unlink(credentialsPath()));
|
|
54
|
+
if (!r.ok && r.error.code !== "ENOENT")
|
|
55
|
+
return r;
|
|
56
|
+
return { ok: true, value: undefined };
|
|
52
57
|
};
|
|
53
58
|
const resolveAuthHeader = async () => {
|
|
54
59
|
const creds = await readCredentials();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/_utils/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,MAAM,eAAe,GAAG,GAAW,EAAE;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAClD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,KAAK,IAAiC,EAAE;IAC9D,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9D,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAY,CAAC,CACrD,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;IAC1B,IACE,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,MAAM,IAAI,IAAI;QACd,KAAK,IAAI,IAAI;QACZ,IAA0B,CAAC,IAAI,KAAK,QAAQ;QAC7C,OAAQ,IAAyB,CAAC,GAAG,KAAK,QAAQ,EAClD,CAAC;QACD,OAAO,IAAmB,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,KAAK,EAC5B,KAAkB,EACc,EAAE;IAClC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE9B,MAAM,WAAW,GAAG,MAAM,WAAW,CACnC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAC7C,CAAC;IACF,IAAI,CAAC,WAAW,CAAC,EAAE;QAAE,OAAO,WAAW,CAAC;IAExC,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/_utils/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Result } from "./result.js";
|
|
2
|
+
declare const agentsJsonPath: () => string;
|
|
3
|
+
declare const isExecutable: (p: string) => boolean;
|
|
4
|
+
declare const findBin: (bin: string) => string | null;
|
|
5
|
+
declare const persistAgentPath: (bin: string, path: string) => Promise<Result<void, unknown>>;
|
|
6
|
+
export { findBin, persistAgentPath, agentsJsonPath, isExecutable };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { constants, accessSync, readFileSync } from "node:fs";
|
|
2
|
+
import { mkdir, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fromPromise } from "./result.js";
|
|
6
|
+
import { runBin } from "./run-bin.js";
|
|
7
|
+
const agentsJsonPath = () => process.env.GLEN_AGENTS_PATH ?? join(homedir(), ".glen", "agents.json");
|
|
8
|
+
const isExecutable = (p) => {
|
|
9
|
+
try {
|
|
10
|
+
accessSync(p, constants.X_OK);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const readOverrides = () => {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(readFileSync(agentsJsonPath(), "utf8"));
|
|
20
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
21
|
+
return {};
|
|
22
|
+
if (Array.isArray(parsed))
|
|
23
|
+
return {};
|
|
24
|
+
return Object.fromEntries(Object.entries(parsed).filter((e) => typeof e[1] === "string"));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const WELL_KNOWN_DIRS = [
|
|
31
|
+
"/opt/homebrew/bin",
|
|
32
|
+
"/usr/local/bin",
|
|
33
|
+
join(homedir(), ".local", "bin"),
|
|
34
|
+
join(homedir(), "bin"),
|
|
35
|
+
];
|
|
36
|
+
// Resolves an agent binary: persisted override → which → well-known macOS
|
|
37
|
+
// dirs → login-shell PATH probe. Returns null when nothing works — the
|
|
38
|
+
// caller owns the actionable "run `which codex` then
|
|
39
|
+
// `glen install --codex-path <path>`" message.
|
|
40
|
+
const findBin = (bin) => {
|
|
41
|
+
// Only simple binary names — guards the shell-interpolated login probe and dir joins.
|
|
42
|
+
if (!/^[A-Za-z0-9._-]+$/.test(bin))
|
|
43
|
+
return null;
|
|
44
|
+
const override = readOverrides()[bin];
|
|
45
|
+
if (override && isExecutable(override))
|
|
46
|
+
return override;
|
|
47
|
+
const viaWhich = runBin("which", [bin], { timeoutMs: 3000 });
|
|
48
|
+
if (viaWhich.ok) {
|
|
49
|
+
const p = viaWhich.value.stdout.trim();
|
|
50
|
+
if (p)
|
|
51
|
+
return p;
|
|
52
|
+
}
|
|
53
|
+
const dirs = process.env.GLEN_EXTRA_BIN_DIR
|
|
54
|
+
? [process.env.GLEN_EXTRA_BIN_DIR, ...WELL_KNOWN_DIRS]
|
|
55
|
+
: WELL_KNOWN_DIRS;
|
|
56
|
+
for (const dir of dirs) {
|
|
57
|
+
const p = join(dir, bin);
|
|
58
|
+
if (isExecutable(p))
|
|
59
|
+
return p;
|
|
60
|
+
}
|
|
61
|
+
const shell = process.env.SHELL ?? "/bin/zsh";
|
|
62
|
+
const viaLogin = runBin(shell, ["-lc", `command -v ${bin}`], {
|
|
63
|
+
timeoutMs: 4000,
|
|
64
|
+
});
|
|
65
|
+
if (viaLogin.ok) {
|
|
66
|
+
const p = viaLogin.value.stdout.trim().split("\n").pop() ?? "";
|
|
67
|
+
if (p.startsWith("/") && isExecutable(p))
|
|
68
|
+
return p;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
};
|
|
72
|
+
const persistAgentPath = async (bin, path) => {
|
|
73
|
+
const file = agentsJsonPath();
|
|
74
|
+
const next = { ...readOverrides(), [bin]: path };
|
|
75
|
+
const mk = await fromPromise(mkdir(dirname(file), { recursive: true }));
|
|
76
|
+
if (!mk.ok)
|
|
77
|
+
return mk;
|
|
78
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
79
|
+
const w = await fromPromise(writeFile(tmp, JSON.stringify(next, null, 2)));
|
|
80
|
+
if (!w.ok)
|
|
81
|
+
return w;
|
|
82
|
+
return fromPromise(rename(tmp, file));
|
|
83
|
+
};
|
|
84
|
+
export { findBin, persistAgentPath, agentsJsonPath, isExecutable };
|
|
85
|
+
//# sourceMappingURL=find-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-bin.js","sourceRoot":"","sources":["../../src/_utils/find-bin.ts"],"names":[],"mappings":"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"}
|
package/dist/_utils/http.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ type HttpOptions = {
|
|
|
11
11
|
readonly body?: string;
|
|
12
12
|
readonly timeoutMs?: number;
|
|
13
13
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
type HttpFailure = {
|
|
15
|
+
readonly kind: "dns" | "refused" | "timeout" | "tls" | "network";
|
|
16
|
+
readonly host: string;
|
|
17
|
+
readonly detail: string;
|
|
18
|
+
};
|
|
19
|
+
declare const classifyFetchError: (e: unknown, url: string) => HttpFailure;
|
|
20
|
+
declare const httpJson: (url: string, options?: HttpOptions) => Promise<Result<HttpResponse, HttpFailure>>;
|
|
21
|
+
declare const networkRemedy: (failure: HttpFailure) => string;
|
|
22
|
+
export { httpJson, classifyFetchError, networkRemedy };
|
|
23
|
+
export type { HttpResponse, HttpOptions, HttpFailure };
|
package/dist/_utils/http.js
CHANGED
|
@@ -1,4 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { causeOf } from "./cli-error.js";
|
|
2
|
+
import { err, fromPromise } from "./result.js";
|
|
3
|
+
const hostOf = (url) => {
|
|
4
|
+
try {
|
|
5
|
+
return new URL(url).host;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return url;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const classifyFetchError = (e, url) => {
|
|
12
|
+
const host = hostOf(url);
|
|
13
|
+
const cause = e?.cause;
|
|
14
|
+
const code = cause?.code ?? e?.code;
|
|
15
|
+
if (e?.name === "AbortError" || code === "ABORT_ERR")
|
|
16
|
+
return { kind: "timeout", host, detail: `request to ${host} timed out` };
|
|
17
|
+
if (code === "ENOTFOUND" || code === "EAI_AGAIN")
|
|
18
|
+
return {
|
|
19
|
+
kind: "dns",
|
|
20
|
+
host,
|
|
21
|
+
detail: `could not resolve ${host} (DNS lookup failed)`,
|
|
22
|
+
};
|
|
23
|
+
if (code === "ECONNREFUSED")
|
|
24
|
+
return {
|
|
25
|
+
kind: "refused",
|
|
26
|
+
host,
|
|
27
|
+
detail: `connection to ${host} refused`,
|
|
28
|
+
};
|
|
29
|
+
if (typeof code === "string" && code.startsWith("CERT_"))
|
|
30
|
+
return {
|
|
31
|
+
kind: "tls",
|
|
32
|
+
host,
|
|
33
|
+
detail: `TLS error talking to ${host} (${code}) — a proxy may be intercepting traffic`,
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
kind: "network",
|
|
37
|
+
host,
|
|
38
|
+
detail: `network error reaching ${host} (${causeOf(e)})`,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
2
41
|
const httpJson = async (url, options = {}) => {
|
|
3
42
|
const { method = "GET", headers, body, timeoutMs } = options;
|
|
4
43
|
const controller = new AbortController();
|
|
@@ -14,11 +53,17 @@ const httpJson = async (url, options = {}) => {
|
|
|
14
53
|
if (timeoutId !== undefined)
|
|
15
54
|
clearTimeout(timeoutId);
|
|
16
55
|
if (!fetchResult.ok)
|
|
17
|
-
return fetchResult;
|
|
56
|
+
return err(classifyFetchError(fetchResult.error, url));
|
|
18
57
|
const response = fetchResult.value;
|
|
19
58
|
const text = await fromPromise(response.text());
|
|
20
|
-
if (!text.ok)
|
|
21
|
-
|
|
59
|
+
if (!text.ok) {
|
|
60
|
+
const host = hostOf(url);
|
|
61
|
+
return err({
|
|
62
|
+
kind: "network",
|
|
63
|
+
host,
|
|
64
|
+
detail: `failed reading response from ${host} (${causeOf(text.error)})`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
22
67
|
const rawText = text.value.trim();
|
|
23
68
|
const json = (() => {
|
|
24
69
|
try {
|
|
@@ -38,5 +83,11 @@ const httpJson = async (url, options = {}) => {
|
|
|
38
83
|
},
|
|
39
84
|
};
|
|
40
85
|
};
|
|
41
|
-
|
|
86
|
+
// Remedy for a transport failure: HttpFailure.detail stays purely
|
|
87
|
+
// descriptive; the actionable part lives here, on the CliError side. Only
|
|
88
|
+
// refused/dns plausibly point at a misconfigured custom base URL.
|
|
89
|
+
const networkRemedy = (failure) => failure.kind === "refused" || failure.kind === "dns"
|
|
90
|
+
? "check your connection and retry; if you use a custom GLEN_BASE_URL, verify it"
|
|
91
|
+
: "check your connection and retry";
|
|
92
|
+
export { httpJson, classifyFetchError, networkRemedy };
|
|
42
93
|
//# sourceMappingURL=http.js.map
|
package/dist/_utils/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/_utils/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/_utils/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,5 +6,5 @@ type LoopbackServer = {
|
|
|
6
6
|
readonly redirectUri: string;
|
|
7
7
|
readonly waitForCallback: () => Promise<CallbackResult>;
|
|
8
8
|
};
|
|
9
|
-
declare const startLoopbackServer: (timeoutMs?: number, expectedState?: string) => Promise<LoopbackServer>;
|
|
9
|
+
declare const startLoopbackServer: (timeoutMs?: number, expectedState?: string, port?: number) => Promise<LoopbackServer>;
|
|
10
10
|
export { startLoopbackServer };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
|
+
import { causeOf, cliErr } from "./cli-error.js";
|
|
2
3
|
import { renderCallbackPage } from "./render-callback-page.js";
|
|
3
|
-
|
|
4
|
+
// `port` exists for tests (forcing an EADDRINUSE collision); production
|
|
5
|
+
// callers always bind an ephemeral port (0).
|
|
6
|
+
const startLoopbackServer = (timeoutMs = 300_000, expectedState, port = 0) => new Promise((resolveStart, rejectStart) => {
|
|
4
7
|
const callback = {
|
|
5
8
|
settled: false,
|
|
6
9
|
resolve: (_v) => { },
|
|
@@ -36,7 +39,19 @@ const startLoopbackServer = (timeoutMs = 300_000, expectedState) => new Promise(
|
|
|
36
39
|
server.close();
|
|
37
40
|
}, timeoutMs);
|
|
38
41
|
timer.unref();
|
|
39
|
-
|
|
42
|
+
// Without this handler a listen failure (EADDRINUSE/EACCES — firewall,
|
|
43
|
+
// VPN, exhausted ports) emits an uncaught 'error' event and crashes the
|
|
44
|
+
// process. Reject the start promise with a CliError instead so login can
|
|
45
|
+
// return it as a structured failure.
|
|
46
|
+
server.on("error", (e) => {
|
|
47
|
+
rejectStart(cliErr({
|
|
48
|
+
what: "could not start the local login listener on 127.0.0.1",
|
|
49
|
+
why: causeOf(e),
|
|
50
|
+
remedy: "check local firewall/VPN settings and retry `glen login`",
|
|
51
|
+
}));
|
|
52
|
+
server.close();
|
|
53
|
+
});
|
|
54
|
+
server.listen(port, "127.0.0.1", () => {
|
|
40
55
|
const addr = server.address();
|
|
41
56
|
resolveStart({
|
|
42
57
|
redirectUri: `http://127.0.0.1:${addr.port}/callback`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loopback-server.js","sourceRoot":"","sources":["../../src/_utils/loopback-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAW/D,MAAM,mBAAmB,GAAG,CAC1B,SAAS,GAAG,OAAO,EACnB,aAAsB,
|
|
1
|
+
{"version":3,"file":"loopback-server.js","sourceRoot":"","sources":["../../src/_utils/loopback-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,9 @@ const openBrowser = (url) => {
|
|
|
11
11
|
detached: true,
|
|
12
12
|
shell: process.platform === "win32",
|
|
13
13
|
});
|
|
14
|
+
child.on("error", () => {
|
|
15
|
+
// best-effort — the caller already printed the URL as a manual fallback
|
|
16
|
+
});
|
|
14
17
|
child.unref();
|
|
15
18
|
};
|
|
16
19
|
export { openBrowser };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-browser.js","sourceRoot":"","sources":["../../src/_utils/open-browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,WAAW,GAAG,CAAC,GAAW,EAAQ,EAAE;IACxC,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAC3B,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,UAAU,CAAC;IACnB,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;QAC7B,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;KACpC,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"open-browser.js","sourceRoot":"","sources":["../../src/_utils/open-browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,WAAW,GAAG,CAAC,GAAW,EAAQ,EAAE;IACxC,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAC3B,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,UAAU,CAAC;IACnB,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;QAC7B,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;KACpC,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,wEAAwE;IAC1E,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { findBin } from "./find-bin.js";
|
|
2
|
+
import { runBin } from "./run-bin.js";
|
|
3
|
+
// A line whose first token is the glen plugin: claude lists `❯ glen@glen`
|
|
4
|
+
// entries (selection marker before the name), codex lists plugin names
|
|
5
|
+
// (`glen — …`) — match exactly `glen` (optionally `@<marketplace>`) at line
|
|
6
|
+
// start, tolerating common list markers (`❯`, `>`, `•`, `*`, `-`) before the
|
|
7
|
+
// name, so `foo@glen`, `glenda`, or a description merely mentioning glen
|
|
8
|
+
// never false-positives.
|
|
9
|
+
const GLEN_PLUGIN_LINE = /^[\s>❯•*-]*glen(@\S+)?(\s|$)/im;
|
|
10
|
+
// Detects whether the glen plugin is installed for an agent by parsing
|
|
11
|
+
// `<agent> plugin list` output. "unknown" (agent missing or list failed)
|
|
12
|
+
// lets callers fall back to attempting an install.
|
|
13
|
+
const glenPluginStatus = (agentBin) => {
|
|
14
|
+
const bin = findBin(agentBin);
|
|
15
|
+
if (!bin)
|
|
16
|
+
return "unknown";
|
|
17
|
+
const r = runBin(bin, ["plugin", "list"], { timeoutMs: 30_000 });
|
|
18
|
+
if (!r.ok)
|
|
19
|
+
return "unknown";
|
|
20
|
+
return GLEN_PLUGIN_LINE.test(r.value.stdout) ? "installed" : "not-installed";
|
|
21
|
+
};
|
|
22
|
+
export { glenPluginStatus };
|
|
23
|
+
//# sourceMappingURL=plugin-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-status.js","sourceRoot":"","sources":["../../src/_utils/plugin-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAItC,0EAA0E;AAC1E,uEAAuE;AACvE,4EAA4E;AAC5E,6EAA6E;AAC7E,yEAAyE;AACzE,yBAAyB;AACzB,MAAM,gBAAgB,GAAG,gCAAgC,CAAC;AAE1D,uEAAuE;AACvE,yEAAyE;AACzE,mDAAmD;AACnD,MAAM,gBAAgB,GAAG,CAAC,QAA4B,EAAgB,EAAE;IACtE,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,CAAC,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC;AAC/E,CAAC,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Result } from "./result.js";
|
|
2
|
+
type RunBinFailure = {
|
|
3
|
+
readonly code: number | null;
|
|
4
|
+
readonly stderrTail: string;
|
|
5
|
+
readonly spawnError?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const runBin: (bin: string, args: readonly string[], opts?: {
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}) => Result<{
|
|
10
|
+
stdout: string;
|
|
11
|
+
}, RunBinFailure>;
|
|
12
|
+
export { runBin };
|
|
13
|
+
export type { RunBinFailure };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { err, ok } from "./result.js";
|
|
3
|
+
const tail = (s) => s
|
|
4
|
+
.split("\n")
|
|
5
|
+
.map((l) => l.trim())
|
|
6
|
+
.filter(Boolean)
|
|
7
|
+
.slice(-3)
|
|
8
|
+
.join(" · ")
|
|
9
|
+
.slice(0, 400);
|
|
10
|
+
// Synchronous on purpose: install/update steps are sequential UX with a
|
|
11
|
+
// ✓/✗ per line. 60s default timeout.
|
|
12
|
+
const runBin = (bin, args, opts = {}) => {
|
|
13
|
+
try {
|
|
14
|
+
const stdout = execFileSync(bin, args, {
|
|
15
|
+
encoding: "utf8",
|
|
16
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
17
|
+
timeout: opts.timeoutMs ?? 60_000,
|
|
18
|
+
});
|
|
19
|
+
return ok({ stdout });
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
const ex = e;
|
|
23
|
+
if (ex.code === "ENOENT") {
|
|
24
|
+
return err({
|
|
25
|
+
code: null,
|
|
26
|
+
stderrTail: "",
|
|
27
|
+
spawnError: `ENOENT: ${bin} not found`,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const stderr = typeof ex.stderr === "string"
|
|
31
|
+
? ex.stderr
|
|
32
|
+
: (ex.stderr?.toString("utf8") ?? "");
|
|
33
|
+
if (ex.code === "ETIMEDOUT") {
|
|
34
|
+
return err({
|
|
35
|
+
code: ex.status ?? null,
|
|
36
|
+
stderrTail: tail(stderr),
|
|
37
|
+
spawnError: `ETIMEDOUT: ${bin} ${args[0] ?? ""} timed out`.trim(),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (ex.signal) {
|
|
41
|
+
return err({
|
|
42
|
+
code: ex.status ?? null,
|
|
43
|
+
stderrTail: tail(stderr),
|
|
44
|
+
spawnError: `killed by ${ex.signal}`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return err({ code: ex.status ?? null, stderrTail: tail(stderr) });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
export { runBin };
|
|
51
|
+
//# sourceMappingURL=run-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-bin.js","sourceRoot":"","sources":["../../src/_utils/run-bin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAe,GAAG,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAQnD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CACjC,CAAC;KACE,KAAK,CAAC,IAAI,CAAC;KACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KACpB,MAAM,CAAC,OAAO,CAAC;KACf,KAAK,CAAC,CAAC,CAAC,CAAC;KACT,IAAI,CAAC,KAAK,CAAC;KACX,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAEnB,wEAAwE;AACxE,qCAAqC;AACrC,MAAM,MAAM,GAAG,CACb,GAAW,EACX,IAAuB,EACvB,OAA+B,EAAE,EACU,EAAE;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,EAAE,IAAgB,EAAE;YACjD,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,OAAO,EAAE,IAAI,CAAC,SAAS,IAAI,MAAM;SAClC,CAAC,CAAC;QACH,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,EAAE,GAAG,CAIV,CAAC;QACF,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzB,OAAO,GAAG,CAAC;gBACT,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,EAAE;gBACd,UAAU,EAAE,WAAW,GAAG,YAAY;aACvC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,MAAM,GACV,OAAO,EAAE,CAAC,MAAM,KAAK,QAAQ;YAC3B,CAAC,CAAC,EAAE,CAAC,MAAM;YACX,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1C,IAAI,EAAE,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC5B,OAAO,GAAG,CAAC;gBACT,IAAI,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI;gBACvB,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;gBACxB,UAAU,EAAE,cAAc,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE;aAClE,CAAC,CAAC;QACL,CAAC;QACD,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,GAAG,CAAC;gBACT,IAAI,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI;gBACvB,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;gBACxB,UAAU,EAAE,aAAa,EAAE,CAAC,MAAM,EAAE;aACrC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const formatStateLine = (state) => {
|
|
2
2
|
if (!state)
|
|
3
3
|
return null;
|
|
4
|
-
|
|
4
|
+
// Org slugs are auto-generated ("acme-1234") — the NAME is the
|
|
5
|
+
// human-meaningful field, so prefer it.
|
|
6
|
+
const org = state.activeOrgName ?? state.activeOrgSlug ?? state.activeOrgId;
|
|
5
7
|
return state.incognito
|
|
6
8
|
? `[glen] org: ${org} · incognito: ON — nothing this session is being recorded`
|
|
7
9
|
: `[glen] org: ${org} · recording`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-line.js","sourceRoot":"","sources":["../../src/_utils/state-line.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,CAAC,KAAuB,EAAiB,EAAE;IACjE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,WAAW,CAAC;IAC5E,OAAO,KAAK,CAAC,SAAS;QACpB,CAAC,CAAC,eAAe,GAAG,2DAA2D;QAC/E,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC;AACvC,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"state-line.js","sourceRoot":"","sources":["../../src/_utils/state-line.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,CAAC,KAAuB,EAAiB,EAAE;IACjE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,+DAA+D;IAC/D,wCAAwC;IACxC,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,WAAW,CAAC;IAC5E,OAAO,KAAK,CAAC,SAAS;QACpB,CAAC,CAAC,eAAe,GAAG,2DAA2D;QAC/E,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC;AACvC,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|