@tryglen/cli 0.24.5 → 0.24.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/README.md +12 -0
- package/dist/_utils/codex-hooks-setup.d.ts +6 -1
- package/dist/_utils/codex-hooks-setup.js +34 -11
- package/dist/_utils/codex-hooks-setup.js.map +1 -1
- package/dist/_utils/git-hook-setup.d.ts +10 -1
- package/dist/_utils/git-hook-setup.js +54 -2
- package/dist/_utils/git-hook-setup.js.map +1 -1
- package/dist/_utils/install-receipt.d.ts +32 -0
- package/dist/_utils/install-receipt.js +126 -0
- package/dist/_utils/install-receipt.js.map +1 -0
- package/dist/_utils/purge-agent-plugins.d.ts +8 -0
- package/dist/_utils/purge-agent-plugins.js +62 -0
- package/dist/_utils/purge-agent-plugins.js.map +1 -0
- package/dist/_utils/purge-claude-statusline.d.ts +12 -0
- package/dist/_utils/purge-claude-statusline.js +57 -0
- package/dist/_utils/purge-claude-statusline.js.map +1 -0
- package/dist/_utils/purge-local-state.d.ts +7 -0
- package/dist/_utils/purge-local-state.js +40 -0
- package/dist/_utils/purge-local-state.js.map +1 -0
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/commands/ingest.js +56 -40
- package/dist/commands/ingest.js.map +1 -1
- package/dist/commands/install.js +39 -4
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/uninstall.d.ts +6 -9
- package/dist/commands/uninstall.js +104 -54
- package/dist/commands/uninstall.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ glen login
|
|
|
23
23
|
| `glen org switch [slug]` | Switch the active organization for this machine (interactive picker without `slug`). |
|
|
24
24
|
| `glen ingest [--agent <name>]` | Ingest a turn from stdin — used by agent hooks (`claude-code`, `codex`, `cursor`, or `pi`). |
|
|
25
25
|
| `glen install [--agent <claude\|codex\|cursor\|pi>]` | 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>` / `--pi-path <path>` point at a binary when auto-detection fails. |
|
|
26
|
+
| `glen uninstall` | Permanently remove Glen's local plugins, marketplaces, hooks, PATH entries, credentials, state, caches, and global npm CLI. |
|
|
26
27
|
| `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. |
|
|
27
28
|
| `glen doctor [--auto]` | Print machine-readable `status:` lines (CLI version/latest/channel, login + org, per-agent plugin + hook state) plus `→` remedy lines — the setup skill branches on them. `--auto` runs background updates silently (used by hooks). |
|
|
28
29
|
| `glen statusline` | Output a single status line for the agent's UI status bar — used by hooks. |
|
|
@@ -38,6 +39,17 @@ glen login
|
|
|
38
39
|
|
|
39
40
|
The state file is what the CLI sends as `x-glen-org-id` / `x-glen-incognito` headers on every request. The server validates org membership on every call — no state is stored server-side.
|
|
40
41
|
|
|
42
|
+
## Uninstall
|
|
43
|
+
|
|
44
|
+
`glen uninstall` permanently removes Glen's local agent plugins, marketplaces,
|
|
45
|
+
hooks, PATH entries, credentials, state, caches, and global npm CLI. It preserves
|
|
46
|
+
source repositories, agent transcripts, and cloud account/team data.
|
|
47
|
+
|
|
48
|
+
Cursor plugins must be removed in Cursor's plugin settings because Cursor does
|
|
49
|
+
not expose a supported plugin-removal CLI. If Cursor is detected, the command
|
|
50
|
+
reports the exact manual step and exits nonzero until that editor-managed residue
|
|
51
|
+
is addressed.
|
|
52
|
+
|
|
41
53
|
## Environment variables
|
|
42
54
|
|
|
43
55
|
| Variable | Default | Description |
|
|
@@ -4,5 +4,10 @@ declare const installCodexHooks: () => Promise<Result<{
|
|
|
4
4
|
trusted: boolean;
|
|
5
5
|
backedUp: boolean;
|
|
6
6
|
}, string>>;
|
|
7
|
-
declare const uninstallCodexHooks: (
|
|
7
|
+
declare const uninstallCodexHooks: (snapshot?: {
|
|
8
|
+
readonly hooksPath: string;
|
|
9
|
+
readonly hooksExisted: boolean;
|
|
10
|
+
readonly configPath: string;
|
|
11
|
+
readonly configExisted: boolean;
|
|
12
|
+
}) => Promise<Result<void, string>>;
|
|
8
13
|
export { installCodexHooks, isCodexHooksInstalled, uninstallCodexHooks };
|
|
@@ -4,6 +4,7 @@ import { listCodexHooks } from "./codex-app-server.js";
|
|
|
4
4
|
import { GLEN_OWNER_PREFIX, normalizeHooksFile, stripGlenHooks, withGlenHooks, } from "./codex-hooks-merge.js";
|
|
5
5
|
import { codexConfigTomlPath, codexHooksJsonPath } from "./codex-paths.js";
|
|
6
6
|
import { removeTrustBlocks, upsertTrustBlocks } from "./codex-trust-toml.js";
|
|
7
|
+
import { installReceipt } from "./install-receipt.js";
|
|
7
8
|
import { err, fromPromise, ok } from "./result.js";
|
|
8
9
|
import { statePath } from "./state.js";
|
|
9
10
|
// Marker recording that THIS machine opted into glen's codex hooks (gates
|
|
@@ -46,8 +47,7 @@ const atomicWrite = async (filePath, content) => {
|
|
|
46
47
|
// missing file from an empty one. Unparseable → backed up during install
|
|
47
48
|
// (never clobber another tool's data silently) and treated as empty;
|
|
48
49
|
// uninstall passes backupOnUnparseable=false and skips the rewrite instead.
|
|
49
|
-
const readExistingHooks = async (backupOnUnparseable) => {
|
|
50
|
-
const hooksPath = codexHooksJsonPath();
|
|
50
|
+
const readExistingHooks = async (backupOnUnparseable, hooksPath = codexHooksJsonPath()) => {
|
|
51
51
|
const raw = await fromPromise(readFile(hooksPath, "utf-8"));
|
|
52
52
|
if (!raw.ok)
|
|
53
53
|
return ok({ file: { hooks: {} }, backedUp: false, absent: true });
|
|
@@ -82,6 +82,8 @@ const trustGlenHooks = async () => {
|
|
|
82
82
|
return w.ok ? entries.map((e) => e.key) : [];
|
|
83
83
|
};
|
|
84
84
|
const installCodexHooks = async () => {
|
|
85
|
+
const hooksBefore = await fromPromise(readFile(codexHooksJsonPath(), "utf-8"));
|
|
86
|
+
const configBefore = await fromPromise(readFile(codexConfigTomlPath(), "utf-8"));
|
|
85
87
|
const existing = await readExistingHooks(true);
|
|
86
88
|
if (!existing.ok)
|
|
87
89
|
return existing;
|
|
@@ -95,6 +97,14 @@ const installCodexHooks = async () => {
|
|
|
95
97
|
const m = await atomicWrite(markerPath(), `${JSON.stringify({ installedAt: new Date().toISOString(), trustedKeys }, null, 2)}\n`);
|
|
96
98
|
if (!m.ok)
|
|
97
99
|
return err(`could not write install marker ${markerPath()}`);
|
|
100
|
+
const receipt = await installReceipt.recordCodexFiles({
|
|
101
|
+
hooksPath: codexHooksJsonPath(),
|
|
102
|
+
hooksExisted: hooksBefore.ok,
|
|
103
|
+
configPath: codexConfigTomlPath(),
|
|
104
|
+
configExisted: configBefore.ok,
|
|
105
|
+
});
|
|
106
|
+
if (!receipt.ok)
|
|
107
|
+
return err("could not write codex uninstall receipt");
|
|
98
108
|
return ok({
|
|
99
109
|
trusted: trustedKeys.length > 0,
|
|
100
110
|
backedUp: existing.value.backedUp,
|
|
@@ -102,26 +112,31 @@ const installCodexHooks = async () => {
|
|
|
102
112
|
};
|
|
103
113
|
// Removes glen's trust blocks from config.toml (no-op when the file is
|
|
104
114
|
// unreadable or there is nothing to remove).
|
|
105
|
-
const removeGlenTrustBlocks = async (keys) => {
|
|
115
|
+
const removeGlenTrustBlocks = async (keys, tomlPath = codexConfigTomlPath(), deleteIfEmpty = false) => {
|
|
106
116
|
if (keys.length === 0)
|
|
107
117
|
return ok(undefined);
|
|
108
|
-
const tomlPath = codexConfigTomlPath();
|
|
109
118
|
const raw = await fromPromise(readFile(tomlPath, "utf-8"));
|
|
110
119
|
if (!raw.ok)
|
|
111
120
|
return ok(undefined);
|
|
112
121
|
const updated = removeTrustBlocks(raw.value, keys);
|
|
122
|
+
if (deleteIfEmpty && updated.trim().length === 0) {
|
|
123
|
+
const removed = await fromPromise(unlink(tomlPath));
|
|
124
|
+
return removed.ok ? ok(undefined) : err(`could not remove ${tomlPath}`);
|
|
125
|
+
}
|
|
113
126
|
const w = await atomicWrite(tomlPath, updated);
|
|
114
127
|
return w.ok ? ok(undefined) : err(`could not write ${tomlPath}`);
|
|
115
128
|
};
|
|
116
|
-
const uninstallCodexHooks = async () => {
|
|
129
|
+
const uninstallCodexHooks = async (snapshot) => {
|
|
130
|
+
const hooksPath = snapshot?.hooksPath ?? codexHooksJsonPath();
|
|
131
|
+
const configPath = snapshot?.configPath ?? codexConfigTomlPath();
|
|
117
132
|
const marker = await readMarker();
|
|
118
|
-
const existing = await readExistingHooks(false);
|
|
133
|
+
const existing = await readExistingHooks(false, hooksPath);
|
|
119
134
|
if (!existing.ok)
|
|
120
135
|
return existing;
|
|
121
136
|
// Clean machine (no hooks.json): never touch ~/.codex or spawn the
|
|
122
137
|
// app-server — only remove marker-recorded trust blocks if any.
|
|
123
138
|
if (existing.value.absent) {
|
|
124
|
-
const t = await removeGlenTrustBlocks(marker?.trustedKeys ?? []);
|
|
139
|
+
const t = await removeGlenTrustBlocks(marker?.trustedKeys ?? [], configPath, snapshot?.configExisted === false);
|
|
125
140
|
if (!t.ok)
|
|
126
141
|
return t;
|
|
127
142
|
await fromPromise(unlink(markerPath()));
|
|
@@ -138,11 +153,19 @@ const uninstallCodexHooks = async () => {
|
|
|
138
153
|
// "skip") → leave it alone; still clean up trust blocks + marker.
|
|
139
154
|
if (!existing.value.backedUp) {
|
|
140
155
|
const stripped = stripGlenHooks(existing.value.file);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
156
|
+
if (snapshot?.hooksExisted === false &&
|
|
157
|
+
Object.keys(stripped.hooks).length === 0) {
|
|
158
|
+
const removed = await fromPromise(unlink(hooksPath));
|
|
159
|
+
if (!removed.ok)
|
|
160
|
+
return err(`could not remove ${hooksPath}`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
const w = await atomicWrite(hooksPath, `${JSON.stringify(stripped, null, 2)}\n`);
|
|
164
|
+
if (!w.ok)
|
|
165
|
+
return err(`could not write ${hooksPath}`);
|
|
166
|
+
}
|
|
144
167
|
}
|
|
145
|
-
const t = await removeGlenTrustBlocks(keys);
|
|
168
|
+
const t = await removeGlenTrustBlocks(keys, configPath, snapshot?.configExisted === false);
|
|
146
169
|
if (!t.ok)
|
|
147
170
|
return t;
|
|
148
171
|
await fromPromise(unlink(markerPath()));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-hooks-setup.js","sourceRoot":"","sources":["../../src/_utils/codex-hooks-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,iBAAiB,EAEjB,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EAAe,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,0EAA0E;AAC1E,wEAAwE;AACxE,4EAA4E;AAC5E,MAAM,UAAU,GAAG,GAAW,EAAE,CAC9B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,4BAA4B,CAAC,CAAC;AAE3D,MAAM,SAAS,GAAG,CAAC,GAAW,EAAW,EAAE;IACzC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,sEAAsE;AACtE,6DAA6D;AAC7D,MAAM,UAAU,GAAG,KAAK,IAA+C,EAAE;IACvE,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAqC,CAAC;IACxE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC;QACpD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACtE,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,EAAE,WAAW,EAAE,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,IAAsB,EAAE,CACzD,CAAC,MAAM,UAAU,EAAE,CAAC,KAAK,IAAI,CAAC;AAEhC,MAAM,WAAW,GAAG,KAAK,EACvB,QAAgB,EAChB,OAAe,EACiB,EAAE;IAClC,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5E,IAAI,CAAC,EAAE,CAAC,EAAE;QAAE,OAAO,EAAE,CAAC;IACtB,2EAA2E;IAC3E,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IAC7C,MAAM,CAAC,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,IAAI,CAAC,CAAC,CAAC,EAAE;QAAE,OAAO,CAAC,CAAC;IACpB,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,uEAAuE;AACvE,yEAAyE;AACzE,qEAAqE;AACrE,4EAA4E;AAC5E,MAAM,iBAAiB,GAAG,KAAK,EAC7B,mBAA4B,
|
|
1
|
+
{"version":3,"file":"codex-hooks-setup.js","sourceRoot":"","sources":["../../src/_utils/codex-hooks-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,4 +6,13 @@ declare const installPrepareCommitMsgHook: (input: {
|
|
|
6
6
|
installed: boolean;
|
|
7
7
|
chained: boolean;
|
|
8
8
|
}, string>>;
|
|
9
|
-
|
|
9
|
+
declare const uninstallPrepareCommitMsgHook: (input: {
|
|
10
|
+
cwd: string;
|
|
11
|
+
snapshot?: {
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly existed: boolean;
|
|
14
|
+
readonly before: string | null;
|
|
15
|
+
readonly installedHash: string;
|
|
16
|
+
};
|
|
17
|
+
}) => Promise<Result<void, string>>;
|
|
18
|
+
export { installPrepareCommitMsgHook, uninstallPrepareCommitMsgHook };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { chmod, mkdir, readFile, rename, unlink, writeFile, } from "node:fs/promises";
|
|
3
4
|
import { dirname, isAbsolute, join } from "node:path";
|
|
5
|
+
import { installReceipt } from "./install-receipt.js";
|
|
4
6
|
import { err, fromPromise, ok } from "./result.js";
|
|
5
7
|
const GLEN_MARK = "# glen commit-anchor hook";
|
|
6
8
|
const git = (cwd, args) => {
|
|
@@ -58,7 +60,57 @@ const installPrepareCommitMsgHook = async (input) => {
|
|
|
58
60
|
const mv = await fromPromise(rename(tmp, hookPath));
|
|
59
61
|
if (!mv.ok)
|
|
60
62
|
return err("could not install hook");
|
|
63
|
+
const receipt = await installReceipt.recordGitHook({
|
|
64
|
+
path: hookPath,
|
|
65
|
+
existed: existing.ok,
|
|
66
|
+
before: existing.ok ? existing.value : null,
|
|
67
|
+
installedHash: createHash("sha256").update(script).digest("hex"),
|
|
68
|
+
});
|
|
69
|
+
if (!receipt.ok)
|
|
70
|
+
return err("could not record git hook for uninstall");
|
|
61
71
|
return ok({ installed: true, chained });
|
|
62
72
|
};
|
|
63
|
-
|
|
73
|
+
const uninstallPrepareCommitMsgHook = async (input) => {
|
|
74
|
+
const dir = input.snapshot
|
|
75
|
+
? dirname(input.snapshot.path)
|
|
76
|
+
: hooksDir(input.cwd);
|
|
77
|
+
if (!dir)
|
|
78
|
+
return ok(undefined);
|
|
79
|
+
const hookPath = input.snapshot?.path ?? join(dir, "prepare-commit-msg");
|
|
80
|
+
const backupPath = `${hookPath}.glen-bak`;
|
|
81
|
+
const current = await fromPromise(readFile(hookPath, "utf8"));
|
|
82
|
+
if (!current.ok) {
|
|
83
|
+
return current.error.code === "ENOENT"
|
|
84
|
+
? ok(undefined)
|
|
85
|
+
: err(`could not read ${hookPath}`);
|
|
86
|
+
}
|
|
87
|
+
if (input.snapshot &&
|
|
88
|
+
createHash("sha256").update(current.value).digest("hex") !==
|
|
89
|
+
input.snapshot.installedHash)
|
|
90
|
+
return err(`${hookPath} changed after Glen installed; remove its Glen lines manually`);
|
|
91
|
+
if (!current.value.includes(GLEN_MARK))
|
|
92
|
+
return ok(undefined);
|
|
93
|
+
if (input.snapshot?.existed && input.snapshot.before !== null) {
|
|
94
|
+
const temp = `${hookPath}.${process.pid}.tmp`;
|
|
95
|
+
const written = await fromPromise(writeFile(temp, input.snapshot.before));
|
|
96
|
+
if (!written.ok)
|
|
97
|
+
return err(`could not restore ${hookPath}`);
|
|
98
|
+
const secured = await fromPromise(chmod(temp, 0o755));
|
|
99
|
+
if (!secured.ok)
|
|
100
|
+
return err(`could not chmod restored ${hookPath}`);
|
|
101
|
+
const moved = await fromPromise(rename(temp, hookPath));
|
|
102
|
+
if (!moved.ok)
|
|
103
|
+
return err(`could not restore ${hookPath}`);
|
|
104
|
+
await fromPromise(unlink(backupPath));
|
|
105
|
+
return ok(undefined);
|
|
106
|
+
}
|
|
107
|
+
const backup = await fromPromise(readFile(backupPath, "utf8"));
|
|
108
|
+
if (backup.ok) {
|
|
109
|
+
const restored = await fromPromise(rename(backupPath, hookPath));
|
|
110
|
+
return restored.ok ? ok(undefined) : err(`could not restore ${hookPath}`);
|
|
111
|
+
}
|
|
112
|
+
const removed = await fromPromise(unlink(hookPath));
|
|
113
|
+
return removed.ok ? ok(undefined) : err(`could not remove ${hookPath}`);
|
|
114
|
+
};
|
|
115
|
+
export { installPrepareCommitMsgHook, uninstallPrepareCommitMsgHook };
|
|
64
116
|
//# sourceMappingURL=git-hook-setup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-hook-setup.js","sourceRoot":"","sources":["../../src/_utils/git-hook-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"git-hook-setup.js","sourceRoot":"","sources":["../../src/_utils/git-hook-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Result } from "./result.js";
|
|
2
|
+
type FileSnapshot = {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly existed: boolean;
|
|
5
|
+
readonly before: string | null;
|
|
6
|
+
readonly installedHash: string;
|
|
7
|
+
};
|
|
8
|
+
type CodexFilesSnapshot = {
|
|
9
|
+
readonly hooksPath: string;
|
|
10
|
+
readonly hooksExisted: boolean;
|
|
11
|
+
readonly configPath: string;
|
|
12
|
+
readonly configExisted: boolean;
|
|
13
|
+
};
|
|
14
|
+
type InstallReceipt = {
|
|
15
|
+
readonly version: 1;
|
|
16
|
+
readonly shellProfiles: string[];
|
|
17
|
+
readonly claudeSettings: FileSnapshot | null;
|
|
18
|
+
readonly codexFiles: CodexFilesSnapshot | null;
|
|
19
|
+
readonly gitHooks: FileSnapshot[];
|
|
20
|
+
readonly statePaths: string[];
|
|
21
|
+
};
|
|
22
|
+
declare const installReceipt: {
|
|
23
|
+
path: () => string;
|
|
24
|
+
read: () => Promise<InstallReceipt | null>;
|
|
25
|
+
recordShellProfile: (path: string) => Promise<Result<void, unknown>>;
|
|
26
|
+
recordClaudeSettings: (snapshot: FileSnapshot) => Promise<Result<void, unknown>>;
|
|
27
|
+
recordCodexFiles: (snapshot: CodexFilesSnapshot) => Promise<Result<void, unknown>>;
|
|
28
|
+
recordGitHook: (snapshot: FileSnapshot) => Promise<Result<void, unknown>>;
|
|
29
|
+
recordStatePath: (path: string) => Promise<Result<void, unknown>>;
|
|
30
|
+
remove: () => Promise<Result<void, unknown>>;
|
|
31
|
+
};
|
|
32
|
+
export { installReceipt };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, rename, unlink, writeFile, } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fromPromise, ok } from "./result.js";
|
|
5
|
+
const receiptPath = () => process.env.GLEN_INSTALL_RECEIPT_PATH ??
|
|
6
|
+
join(homedir(), ".glen", "install-receipt.json");
|
|
7
|
+
const emptyReceipt = () => ({
|
|
8
|
+
version: 1,
|
|
9
|
+
shellProfiles: [],
|
|
10
|
+
claudeSettings: null,
|
|
11
|
+
codexFiles: null,
|
|
12
|
+
gitHooks: [],
|
|
13
|
+
statePaths: [],
|
|
14
|
+
});
|
|
15
|
+
const isFileSnapshot = (value) => {
|
|
16
|
+
if (!value || typeof value !== "object")
|
|
17
|
+
return false;
|
|
18
|
+
const item = value;
|
|
19
|
+
return (typeof item.path === "string" &&
|
|
20
|
+
typeof item.existed === "boolean" &&
|
|
21
|
+
(typeof item.before === "string" || item.before === null) &&
|
|
22
|
+
typeof item.installedHash === "string");
|
|
23
|
+
};
|
|
24
|
+
const parseReceipt = (raw) => {
|
|
25
|
+
const parsed = (() => {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(raw);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
if (!parsed || typeof parsed !== "object")
|
|
34
|
+
return null;
|
|
35
|
+
const value = parsed;
|
|
36
|
+
if (value.version !== 1)
|
|
37
|
+
return null;
|
|
38
|
+
if (!Array.isArray(value.shellProfiles))
|
|
39
|
+
return null;
|
|
40
|
+
if (!value.shellProfiles.every((item) => typeof item === "string"))
|
|
41
|
+
return null;
|
|
42
|
+
if (value.claudeSettings !== null && !isFileSnapshot(value.claudeSettings))
|
|
43
|
+
return null;
|
|
44
|
+
if (!Array.isArray(value.gitHooks) || !value.gitHooks.every(isFileSnapshot))
|
|
45
|
+
return null;
|
|
46
|
+
if (!Array.isArray(value.statePaths))
|
|
47
|
+
return null;
|
|
48
|
+
if (!value.statePaths.every((item) => typeof item === "string"))
|
|
49
|
+
return null;
|
|
50
|
+
const codex = value.codexFiles;
|
|
51
|
+
if (codex !== null &&
|
|
52
|
+
(!codex ||
|
|
53
|
+
typeof codex !== "object" ||
|
|
54
|
+
typeof codex.hooksPath !== "string" ||
|
|
55
|
+
typeof codex.hooksExisted !== "boolean" ||
|
|
56
|
+
typeof codex.configPath !== "string" ||
|
|
57
|
+
typeof codex.configExisted !== "boolean"))
|
|
58
|
+
return null;
|
|
59
|
+
return value;
|
|
60
|
+
};
|
|
61
|
+
const read = async () => {
|
|
62
|
+
const result = await fromPromise(readFile(receiptPath(), "utf8"));
|
|
63
|
+
return result.ok ? parseReceipt(result.value) : null;
|
|
64
|
+
};
|
|
65
|
+
const write = async (receipt) => {
|
|
66
|
+
const path = receiptPath();
|
|
67
|
+
const dir = dirname(path);
|
|
68
|
+
const made = await fromPromise(mkdir(dir, { recursive: true, mode: 0o700 }));
|
|
69
|
+
if (!made.ok)
|
|
70
|
+
return made;
|
|
71
|
+
const securedDir = await fromPromise(chmod(dir, 0o700));
|
|
72
|
+
if (!securedDir.ok)
|
|
73
|
+
return securedDir;
|
|
74
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
75
|
+
const written = await fromPromise(writeFile(temp, `${JSON.stringify(receipt, null, 2)}\n`, { mode: 0o600 }));
|
|
76
|
+
if (!written.ok)
|
|
77
|
+
return written;
|
|
78
|
+
const securedFile = await fromPromise(chmod(temp, 0o600));
|
|
79
|
+
if (!securedFile.ok)
|
|
80
|
+
return securedFile;
|
|
81
|
+
return fromPromise(rename(temp, path));
|
|
82
|
+
};
|
|
83
|
+
const update = async (change) => write(change((await read()) ?? emptyReceipt()));
|
|
84
|
+
const recordClaudeSettings = async (snapshot) => update((current) => ({
|
|
85
|
+
...current,
|
|
86
|
+
claudeSettings: current.claudeSettings
|
|
87
|
+
? { ...current.claudeSettings, installedHash: snapshot.installedHash }
|
|
88
|
+
: snapshot,
|
|
89
|
+
}));
|
|
90
|
+
const recordCodexFiles = async (snapshot) => update((current) => ({
|
|
91
|
+
...current,
|
|
92
|
+
codexFiles: current.codexFiles ?? snapshot,
|
|
93
|
+
}));
|
|
94
|
+
const recordGitHook = async (snapshot) => update((current) => {
|
|
95
|
+
const prior = current.gitHooks.find((hook) => hook.path === snapshot.path);
|
|
96
|
+
const gitHooks = prior
|
|
97
|
+
? current.gitHooks.map((hook) => hook.path === snapshot.path
|
|
98
|
+
? { ...hook, installedHash: snapshot.installedHash }
|
|
99
|
+
: hook)
|
|
100
|
+
: [...current.gitHooks, snapshot];
|
|
101
|
+
return { ...current, gitHooks };
|
|
102
|
+
});
|
|
103
|
+
const remove = async () => {
|
|
104
|
+
const result = await fromPromise(unlink(receiptPath()));
|
|
105
|
+
if (!result.ok && result.error.code !== "ENOENT")
|
|
106
|
+
return result;
|
|
107
|
+
return ok(undefined);
|
|
108
|
+
};
|
|
109
|
+
const installReceipt = {
|
|
110
|
+
path: receiptPath,
|
|
111
|
+
read,
|
|
112
|
+
recordShellProfile: (path) => update((current) => ({
|
|
113
|
+
...current,
|
|
114
|
+
shellProfiles: [...new Set([...current.shellProfiles, path])],
|
|
115
|
+
})),
|
|
116
|
+
recordClaudeSettings,
|
|
117
|
+
recordCodexFiles,
|
|
118
|
+
recordGitHook,
|
|
119
|
+
recordStatePath: (path) => update((current) => ({
|
|
120
|
+
...current,
|
|
121
|
+
statePaths: [...new Set([...current.statePaths, path])],
|
|
122
|
+
})),
|
|
123
|
+
remove,
|
|
124
|
+
};
|
|
125
|
+
export { installReceipt };
|
|
126
|
+
//# sourceMappingURL=install-receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-receipt.js","sourceRoot":"","sources":["../../src/_utils/install-receipt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { PI_PLUGIN_SOURCE } from "./agents-table.js";
|
|
4
|
+
import { err, fromPromise, ok } from "./result.js";
|
|
5
|
+
import { runBin } from "./run-bin.js";
|
|
6
|
+
const absentFailure = (detail) => /not installed|not found|does not exist|unknown marketplace|no such/i.test(detail);
|
|
7
|
+
const purgeAgentPlugins = async (input) => {
|
|
8
|
+
const steps = [
|
|
9
|
+
...(input.claude
|
|
10
|
+
? [
|
|
11
|
+
{
|
|
12
|
+
bin: input.claude,
|
|
13
|
+
args: ["plugin", "uninstall", "glen@glen", "-y", "--prune"],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
bin: input.claude,
|
|
17
|
+
args: ["plugin", "marketplace", "remove", "glen"],
|
|
18
|
+
},
|
|
19
|
+
]
|
|
20
|
+
: []),
|
|
21
|
+
...(input.codex
|
|
22
|
+
? [
|
|
23
|
+
{
|
|
24
|
+
bin: input.codex,
|
|
25
|
+
args: ["plugin", "remove", "glen@glen"],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
bin: input.codex,
|
|
29
|
+
args: ["plugin", "marketplace", "remove", "glen"],
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
: []),
|
|
33
|
+
...(input.pi
|
|
34
|
+
? [{ bin: input.pi, args: ["remove", PI_PLUGIN_SOURCE] }]
|
|
35
|
+
: []),
|
|
36
|
+
];
|
|
37
|
+
const commandFailures = steps.flatMap((step) => {
|
|
38
|
+
const result = runBin(step.bin, step.args, { timeoutMs: 60_000 });
|
|
39
|
+
if (result.ok)
|
|
40
|
+
return [];
|
|
41
|
+
const detail = result.error.stderrTail || result.error.spawnError || "failed";
|
|
42
|
+
return absentFailure(detail)
|
|
43
|
+
? []
|
|
44
|
+
: [`${step.bin} ${step.args.join(" ")}: ${detail}`];
|
|
45
|
+
});
|
|
46
|
+
const cachePaths = [
|
|
47
|
+
join(input.home, ".claude", "plugins", "cache", "glen"),
|
|
48
|
+
join(input.home, ".claude", "plugins", "data", "glen-glen"),
|
|
49
|
+
join(input.home, ".claude", "plugins", "marketplaces", "glen"),
|
|
50
|
+
join(input.home, ".codex", "plugins", "cache", "glen"),
|
|
51
|
+
join(input.home, ".codex", ".tmp", "marketplaces", "glen"),
|
|
52
|
+
];
|
|
53
|
+
const cacheResults = await Promise.all(cachePaths.map(async (path) => ({
|
|
54
|
+
path,
|
|
55
|
+
result: await fromPromise(rm(path, { recursive: true, force: true })),
|
|
56
|
+
})));
|
|
57
|
+
const cacheFailures = cacheResults.flatMap(({ path, result }) => result.ok ? [] : [`remove ${path}: ${String(result.error)}`]);
|
|
58
|
+
const failures = [...commandFailures, ...cacheFailures];
|
|
59
|
+
return failures.length === 0 ? ok(undefined) : err(failures);
|
|
60
|
+
};
|
|
61
|
+
export { purgeAgentPlugins };
|
|
62
|
+
//# sourceMappingURL=purge-agent-plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purge-agent-plugins.js","sourceRoot":"","sources":["../../src/_utils/purge-agent-plugins.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Result } from "./result.js";
|
|
2
|
+
type Snapshot = {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly existed: boolean;
|
|
5
|
+
readonly before: string | null;
|
|
6
|
+
readonly installedHash: string;
|
|
7
|
+
};
|
|
8
|
+
declare const purgeClaudeStatusline: (input: {
|
|
9
|
+
path: string;
|
|
10
|
+
receipt: Snapshot | null;
|
|
11
|
+
}) => Promise<Result<void, string[]>>;
|
|
12
|
+
export { purgeClaudeStatusline };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { err, fromPromise, ok } from "./result.js";
|
|
5
|
+
const GLEN_STATUSLINE = { type: "command", command: "glen statusline" };
|
|
6
|
+
const atomicWrite = async (path, content) => {
|
|
7
|
+
const made = await fromPromise(mkdir(dirname(path), { recursive: true }));
|
|
8
|
+
if (!made.ok)
|
|
9
|
+
return err([`create ${dirname(path)}: ${String(made.error)}`]);
|
|
10
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
11
|
+
const written = await fromPromise(writeFile(temp, content));
|
|
12
|
+
if (!written.ok)
|
|
13
|
+
return err([`write ${path}: ${String(written.error)}`]);
|
|
14
|
+
const moved = await fromPromise(rename(temp, path));
|
|
15
|
+
return moved.ok
|
|
16
|
+
? ok(undefined)
|
|
17
|
+
: err([`replace ${path}: ${String(moved.error)}`]);
|
|
18
|
+
};
|
|
19
|
+
const purgeClaudeStatusline = async (input) => {
|
|
20
|
+
const current = await fromPromise(readFile(input.path, "utf8"));
|
|
21
|
+
if (!current.ok) {
|
|
22
|
+
return current.error.code === "ENOENT"
|
|
23
|
+
? ok(undefined)
|
|
24
|
+
: err([`read ${input.path}: ${String(current.error)}`]);
|
|
25
|
+
}
|
|
26
|
+
const hash = createHash("sha256").update(current.value).digest("hex");
|
|
27
|
+
if (input.receipt?.installedHash === hash) {
|
|
28
|
+
if (!input.receipt.existed) {
|
|
29
|
+
const removed = await fromPromise(unlink(input.path));
|
|
30
|
+
return removed.ok
|
|
31
|
+
? ok(undefined)
|
|
32
|
+
: err([`remove ${input.path}: ${String(removed.error)}`]);
|
|
33
|
+
}
|
|
34
|
+
if (input.receipt.before !== null)
|
|
35
|
+
return atomicWrite(input.path, input.receipt.before);
|
|
36
|
+
}
|
|
37
|
+
const parsed = (() => {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(current.value);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
45
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
46
|
+
return current.value.includes("glen statusline")
|
|
47
|
+
? err([`remove the Glen statusLine from ${input.path} manually`])
|
|
48
|
+
: ok(undefined);
|
|
49
|
+
}
|
|
50
|
+
const settings = parsed;
|
|
51
|
+
if (JSON.stringify(settings.statusLine) !== JSON.stringify(GLEN_STATUSLINE))
|
|
52
|
+
return ok(undefined);
|
|
53
|
+
const { statusLine: _removed, ...preserved } = settings;
|
|
54
|
+
return atomicWrite(input.path, `${JSON.stringify(preserved, null, 2)}\n`);
|
|
55
|
+
};
|
|
56
|
+
export { purgeClaudeStatusline };
|
|
57
|
+
//# sourceMappingURL=purge-claude-statusline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purge-claude-statusline.js","sourceRoot":"","sources":["../../src/_utils/purge-claude-statusline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAe,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAShE,MAAM,eAAe,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAExE,MAAM,WAAW,GAAG,KAAK,EACvB,IAAY,EACZ,OAAe,EACkB,EAAE;IACnC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1E,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC,CAAC,UAAU,OAAO,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC,CAAC,SAAS,IAAI,KAAK,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC,EAAE;QACb,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;QACf,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,KAGpC,EAAmC,EAAE;IACpC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,OAAQ,OAAO,CAAC,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAC/D,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;YACf,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC,EAAE;gBACf,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;gBACf,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,IAAI;YAC/B,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAY,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IACL,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC9C,CAAC,CAAC,GAAG,CAAC,CAAC,mCAAmC,KAAK,CAAC,IAAI,WAAW,CAAC,CAAC;YACjE,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,MAAiC,CAAC;IACnD,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;QACzE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACvB,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAE,GAAG,QAAQ,CAAC;IACxD,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5E,CAAC,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|