@pushary/agent-hooks 0.62.0 → 0.62.1
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 +28 -0
- package/dist/bin/pushary-clean.js +21 -4
- package/dist/bin/pushary-connect.js +2 -1
- package/dist/bin/pushary-doctor.js +2 -1
- package/dist/bin/pushary-login.js +2 -1
- package/dist/bin/pushary-logout.js +2 -1
- package/dist/bin/pushary-setup.js +6 -4
- package/dist/bin/pushary-status.js +2 -1
- package/dist/bin/pushary-upgrade.js +13 -7
- package/dist/chunk-6MTNS63X.js +55 -0
- package/dist/{chunk-247C4RE5.js → chunk-COC6NPWG.js} +12 -59
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.62.1
|
|
4
|
+
|
|
5
|
+
### `pushary clean --dry-run` was not a dry run
|
|
6
|
+
|
|
7
|
+
In 0.62.0 the flag ran four real operations while printing "would":
|
|
8
|
+
|
|
9
|
+
- uninstalled the global `@pushary/agent-hooks` package
|
|
10
|
+
- rewrote your shell profile to remove the `claude` alias
|
|
11
|
+
- stripped the Pushary block from `~/.codex/AGENTS.md`
|
|
12
|
+
- stripped it from `~/.gemini/GEMINI.md`
|
|
13
|
+
|
|
14
|
+
If you ran `pushary clean --dry-run` on 0.62.0 and the CLI then seemed to
|
|
15
|
+
disappear, that is why. Reinstall with `npm i -g @pushary/agent-hooks`, and check
|
|
16
|
+
your shell profile and those two files against version control if you keep them
|
|
17
|
+
there.
|
|
18
|
+
|
|
19
|
+
### `pushary upgrade` could destroy `~/.claude.json`
|
|
20
|
+
|
|
21
|
+
`upgrade` treated an unparseable config as an empty one and wrote it back, so a
|
|
22
|
+
truncated `~/.claude.json` was replaced with nothing but the Pushary MCP entry,
|
|
23
|
+
losing every project, MCP server and permission rule in it. A half-written
|
|
24
|
+
`~/.claude.json` is what an interrupted write leaves behind, so this needed only
|
|
25
|
+
one earlier crash to line up.
|
|
26
|
+
|
|
27
|
+
A config that cannot be parsed is now left untouched, and the other agent files
|
|
28
|
+
are still refreshed around it.
|
|
29
|
+
|
|
30
|
+
|
|
3
31
|
## 0.62.0
|
|
4
32
|
|
|
5
33
|
### `pushary clean` could leave your API key on disk
|
|
@@ -91,6 +91,19 @@ var guardedExec = (command, options, describe) => {
|
|
|
91
91
|
if (dryRun) return wouldNote("run ", describe);
|
|
92
92
|
execSync(command, options);
|
|
93
93
|
};
|
|
94
|
+
var guardedInstructionBlockRemoval = (path) => {
|
|
95
|
+
if (!dryRun) return removeInstructionBlock(path);
|
|
96
|
+
if (!existsSync(path)) return false;
|
|
97
|
+
const hasBlock = readFileSync(path, "utf-8").includes("pushary");
|
|
98
|
+
if (hasBlock) wouldNote("rewrite", path);
|
|
99
|
+
return hasBlock;
|
|
100
|
+
};
|
|
101
|
+
var guardedAliasRemoval = () => {
|
|
102
|
+
if (!dryRun) return removeClaudeAlias();
|
|
103
|
+
const shells = [".zshrc", ".bashrc", ".bash_profile", ".profile"].map((name) => join(homedir(), name)).filter((path) => existsSync(path) && readFileSync(path, "utf-8").includes("pushary claude"));
|
|
104
|
+
for (const path of shells) wouldNote("rewrite", path);
|
|
105
|
+
return shells;
|
|
106
|
+
};
|
|
94
107
|
var writeJson = (path, data) => {
|
|
95
108
|
guardedWrite(path, JSON.stringify(data, null, 2) + "\n");
|
|
96
109
|
};
|
|
@@ -219,7 +232,7 @@ var main = async () => {
|
|
|
219
232
|
console.log(` ${skip} Codex hooks ${dim("(not found)")}`);
|
|
220
233
|
}
|
|
221
234
|
const codexAgentsMd2 = codexAgentsMd();
|
|
222
|
-
if (
|
|
235
|
+
if (guardedInstructionBlockRemoval(codexAgentsMd2)) {
|
|
223
236
|
console.log(` ${check} Codex AGENTS.md ${dim("(removed Pushary block)")}`);
|
|
224
237
|
} else {
|
|
225
238
|
console.log(` ${skip} Codex AGENTS.md ${dim("(no pushary block)")}`);
|
|
@@ -244,7 +257,7 @@ var main = async () => {
|
|
|
244
257
|
console.log(` ${skip} Gemini CLI settings ${dim("(not found)")}`);
|
|
245
258
|
}
|
|
246
259
|
const geminiMd = join(homedir(), ".gemini", "GEMINI.md");
|
|
247
|
-
if (
|
|
260
|
+
if (guardedInstructionBlockRemoval(geminiMd)) {
|
|
248
261
|
console.log(` ${check} Gemini GEMINI.md ${dim("(removed Pushary block)")}`);
|
|
249
262
|
} else {
|
|
250
263
|
console.log(` ${skip} Gemini GEMINI.md ${dim("(no pushary block)")}`);
|
|
@@ -288,7 +301,7 @@ var main = async () => {
|
|
|
288
301
|
} catch {
|
|
289
302
|
}
|
|
290
303
|
}
|
|
291
|
-
const aliasRemovedFrom =
|
|
304
|
+
const aliasRemovedFrom = guardedAliasRemoval();
|
|
292
305
|
if (aliasRemovedFrom.length > 0) {
|
|
293
306
|
console.log(` ${check} claude alias ${dim(`(removed from ${aliasRemovedFrom.map((p) => p.split("/").pop()).join(", ")})`)}`);
|
|
294
307
|
} else {
|
|
@@ -314,7 +327,11 @@ var main = async () => {
|
|
|
314
327
|
} catch {
|
|
315
328
|
}
|
|
316
329
|
try {
|
|
317
|
-
|
|
330
|
+
if (dryRun) {
|
|
331
|
+
wouldNote("run ", "npm uninstall -g @pushary/agent-hooks");
|
|
332
|
+
} else {
|
|
333
|
+
execNpm("uninstall -g --no-workspaces @pushary/agent-hooks", { stdio: "ignore", timeout: 3e4 });
|
|
334
|
+
}
|
|
318
335
|
console.log(` ${check} Global package ${dim(did("uninstalled"))}`);
|
|
319
336
|
} catch {
|
|
320
337
|
console.log(` ${skip} Global package ${dim("(not installed)")}`);
|
|
@@ -42,13 +42,15 @@ import {
|
|
|
42
42
|
} from "../chunk-N4DA4CJB.js";
|
|
43
43
|
import {
|
|
44
44
|
KEY_FILE_MODE,
|
|
45
|
-
backupFile,
|
|
46
45
|
exportLine,
|
|
46
|
+
writeKey
|
|
47
|
+
} from "../chunk-COC6NPWG.js";
|
|
48
|
+
import {
|
|
49
|
+
backupFile,
|
|
47
50
|
readJsonSafe,
|
|
48
51
|
writeFileAtomic,
|
|
49
|
-
writeJsonAtomic
|
|
50
|
-
|
|
51
|
-
} from "../chunk-247C4RE5.js";
|
|
52
|
+
writeJsonAtomic
|
|
53
|
+
} from "../chunk-6MTNS63X.js";
|
|
52
54
|
import {
|
|
53
55
|
checkApiKey,
|
|
54
56
|
describeKeyCheck
|
|
@@ -19,6 +19,9 @@ import {
|
|
|
19
19
|
codexHooksJson,
|
|
20
20
|
hasCodexHooks
|
|
21
21
|
} from "../chunk-ER657KRJ.js";
|
|
22
|
+
import {
|
|
23
|
+
readJsonSafe
|
|
24
|
+
} from "../chunk-6MTNS63X.js";
|
|
22
25
|
import {
|
|
23
26
|
execNpm,
|
|
24
27
|
npmErrorMessage,
|
|
@@ -48,11 +51,10 @@ import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
|
|
|
48
51
|
var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
|
|
49
52
|
var CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
50
53
|
var readJson = (filePath) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
54
|
+
const result = readJsonSafe(filePath);
|
|
55
|
+
if (result.kind === "ok") return result.value;
|
|
56
|
+
if (result.kind === "missing") return {};
|
|
57
|
+
return null;
|
|
56
58
|
};
|
|
57
59
|
var writeJson = (filePath, data) => {
|
|
58
60
|
const dir = dirname(filePath);
|
|
@@ -68,10 +70,13 @@ var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
|
68
70
|
const claudeJson = readJson(claudeJsonPath);
|
|
69
71
|
const configured = settings != null && hasPusharyClaudeHooks(settings) || claudeJson != null && hasPusharyMcp(claudeJson);
|
|
70
72
|
if (!configured) return { reapplied: false, hooks: false, mcp: false };
|
|
73
|
+
const settingsWritable = settings != null;
|
|
74
|
+
const claudeJsonWritable = claudeJson != null;
|
|
71
75
|
let hooks = false;
|
|
72
76
|
let mcp = false;
|
|
73
77
|
try {
|
|
74
|
-
|
|
78
|
+
if (!settingsWritable) throw new Error("settings.json could not be parsed");
|
|
79
|
+
const s = settings;
|
|
75
80
|
addPusharyToolPermissions(s);
|
|
76
81
|
addPusharyHooks(s, resolveGlobalBinDir("pushary-hook"));
|
|
77
82
|
writeJson(settingsPath, s);
|
|
@@ -80,7 +85,8 @@ var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
|
80
85
|
}
|
|
81
86
|
if (apiKey) {
|
|
82
87
|
try {
|
|
83
|
-
|
|
88
|
+
if (!claudeJsonWritable) throw new Error(".claude.json could not be parsed");
|
|
89
|
+
const cj = claudeJson;
|
|
84
90
|
addClaudeMcpServer(cj, apiKey);
|
|
85
91
|
writeJson(claudeJsonPath, cj);
|
|
86
92
|
mcp = true;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/cli/fsx.ts
|
|
2
|
+
import { copyFileSync, existsSync, fsyncSync, mkdirSync, openSync, closeSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
var readJsonSafe = (filePath) => {
|
|
5
|
+
let raw;
|
|
6
|
+
try {
|
|
7
|
+
raw = readFileSync(filePath, "utf-8");
|
|
8
|
+
} catch (err) {
|
|
9
|
+
const error = err;
|
|
10
|
+
if (error.code === "ENOENT") return { kind: "missing" };
|
|
11
|
+
return { kind: "unreadable", error };
|
|
12
|
+
}
|
|
13
|
+
if (raw.trim() === "") return { kind: "ok", value: {} };
|
|
14
|
+
try {
|
|
15
|
+
return { kind: "ok", value: JSON.parse(raw) };
|
|
16
|
+
} catch (err) {
|
|
17
|
+
return { kind: "unparseable", error: err, raw };
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var stamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
21
|
+
var backupFile = (filePath) => {
|
|
22
|
+
const target = `${filePath}.pushary-backup-${stamp()}`;
|
|
23
|
+
copyFileSync(filePath, target);
|
|
24
|
+
return target;
|
|
25
|
+
};
|
|
26
|
+
var writeFileAtomic = (filePath, contents, mode) => {
|
|
27
|
+
const dir = dirname(filePath);
|
|
28
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
29
|
+
const temp = join(dir, `.${process.pid}-${stamp()}.pushary-tmp`);
|
|
30
|
+
try {
|
|
31
|
+
writeFileSync(temp, contents, mode === void 0 ? "utf-8" : { encoding: "utf-8", mode });
|
|
32
|
+
const handle = openSync(temp, "r+");
|
|
33
|
+
try {
|
|
34
|
+
fsyncSync(handle);
|
|
35
|
+
} finally {
|
|
36
|
+
closeSync(handle);
|
|
37
|
+
}
|
|
38
|
+
renameSync(temp, filePath);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
try {
|
|
41
|
+
if (existsSync(temp)) unlinkSync(temp);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var writeJsonAtomic = (filePath, data, mode) => writeFileAtomic(filePath, `${JSON.stringify(data, null, 2)}
|
|
48
|
+
`, mode);
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
readJsonSafe,
|
|
52
|
+
backupFile,
|
|
53
|
+
writeFileAtomic,
|
|
54
|
+
writeJsonAtomic
|
|
55
|
+
};
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
backupFile,
|
|
3
|
+
readJsonSafe,
|
|
4
|
+
writeFileAtomic,
|
|
5
|
+
writeJsonAtomic
|
|
6
|
+
} from "./chunk-6MTNS63X.js";
|
|
1
7
|
import {
|
|
2
8
|
resolveShellRc
|
|
3
9
|
} from "./chunk-BC3VCZ3E.js";
|
|
@@ -5,59 +11,10 @@ import {
|
|
|
5
11
|
configFilePath
|
|
6
12
|
} from "./chunk-2UMNXADU.js";
|
|
7
13
|
|
|
8
|
-
// src/cli/fsx.ts
|
|
9
|
-
import { copyFileSync, existsSync, fsyncSync, mkdirSync, openSync, closeSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
10
|
-
import { dirname, join } from "path";
|
|
11
|
-
var readJsonSafe = (filePath) => {
|
|
12
|
-
let raw;
|
|
13
|
-
try {
|
|
14
|
-
raw = readFileSync(filePath, "utf-8");
|
|
15
|
-
} catch (err) {
|
|
16
|
-
const error = err;
|
|
17
|
-
if (error.code === "ENOENT") return { kind: "missing" };
|
|
18
|
-
return { kind: "unreadable", error };
|
|
19
|
-
}
|
|
20
|
-
if (raw.trim() === "") return { kind: "ok", value: {} };
|
|
21
|
-
try {
|
|
22
|
-
return { kind: "ok", value: JSON.parse(raw) };
|
|
23
|
-
} catch (err) {
|
|
24
|
-
return { kind: "unparseable", error: err, raw };
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var stamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
28
|
-
var backupFile = (filePath) => {
|
|
29
|
-
const target = `${filePath}.pushary-backup-${stamp()}`;
|
|
30
|
-
copyFileSync(filePath, target);
|
|
31
|
-
return target;
|
|
32
|
-
};
|
|
33
|
-
var writeFileAtomic = (filePath, contents, mode) => {
|
|
34
|
-
const dir = dirname(filePath);
|
|
35
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
36
|
-
const temp = join(dir, `.${process.pid}-${stamp()}.pushary-tmp`);
|
|
37
|
-
try {
|
|
38
|
-
writeFileSync(temp, contents, mode === void 0 ? "utf-8" : { encoding: "utf-8", mode });
|
|
39
|
-
const handle = openSync(temp, "r+");
|
|
40
|
-
try {
|
|
41
|
-
fsyncSync(handle);
|
|
42
|
-
} finally {
|
|
43
|
-
closeSync(handle);
|
|
44
|
-
}
|
|
45
|
-
renameSync(temp, filePath);
|
|
46
|
-
} catch (err) {
|
|
47
|
-
try {
|
|
48
|
-
if (existsSync(temp)) unlinkSync(temp);
|
|
49
|
-
} catch {
|
|
50
|
-
}
|
|
51
|
-
throw err;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
var writeJsonAtomic = (filePath, data, mode) => writeFileAtomic(filePath, `${JSON.stringify(data, null, 2)}
|
|
55
|
-
`, mode);
|
|
56
|
-
|
|
57
14
|
// src/keystore.ts
|
|
58
|
-
import { chmodSync, existsSync
|
|
15
|
+
import { chmodSync, existsSync, readFileSync, realpathSync, writeFileSync } from "fs";
|
|
59
16
|
import { homedir } from "os";
|
|
60
|
-
import { join
|
|
17
|
+
import { join } from "path";
|
|
61
18
|
var KEY_FILE_MODE = 384;
|
|
62
19
|
var FALLBACK_RCS = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"];
|
|
63
20
|
var OUR_EXPORT = /^[ \t]*export[ \t]+PUSHARY_API_KEY=(['"]?)(pk_[a-f0-9]+\.[a-f0-9]+)\1[ \t]*$/;
|
|
@@ -86,7 +43,7 @@ var rewriteRcExport = (rcPath, apiKey, shell = null) => {
|
|
|
86
43
|
const target = realPathOf(rcPath);
|
|
87
44
|
let content = "";
|
|
88
45
|
try {
|
|
89
|
-
content =
|
|
46
|
+
content = readFileSync(target, "utf-8");
|
|
90
47
|
} catch (err) {
|
|
91
48
|
const error = err;
|
|
92
49
|
if (error.code !== "ENOENT") {
|
|
@@ -141,7 +98,7 @@ var rewriteRcExport = (rcPath, apiKey, shell = null) => {
|
|
|
141
98
|
var resolveRcTarget = () => {
|
|
142
99
|
const resolved = resolveShellRc();
|
|
143
100
|
if (resolved) return { path: resolved.path, shell: resolved.shell };
|
|
144
|
-
const fallback = FALLBACK_RCS.map((name) =>
|
|
101
|
+
const fallback = FALLBACK_RCS.map((name) => join(homedir(), name)).find(existsSync);
|
|
145
102
|
return fallback ? { path: fallback, shell: null } : null;
|
|
146
103
|
};
|
|
147
104
|
var writeKey = (apiKey, options = {}) => {
|
|
@@ -181,13 +138,13 @@ var clearKey = (options = {}) => {
|
|
|
181
138
|
if (target) {
|
|
182
139
|
try {
|
|
183
140
|
const real = realpathSync(target.path);
|
|
184
|
-
const lines =
|
|
141
|
+
const lines = readFileSync(real, "utf8").split("\n");
|
|
185
142
|
const next = lines.map((line) => {
|
|
186
143
|
if (!OUR_EXPORT.test(line)) return line;
|
|
187
144
|
rcLinesDisabled += 1;
|
|
188
145
|
return `# ${line.trim()} # removed by pushary logout`;
|
|
189
146
|
});
|
|
190
|
-
if (rcLinesDisabled > 0)
|
|
147
|
+
if (rcLinesDisabled > 0) writeFileSync(real, next.join("\n"));
|
|
191
148
|
} catch {
|
|
192
149
|
rcLinesDisabled = 0;
|
|
193
150
|
}
|
|
@@ -223,10 +180,6 @@ var readKeySource = () => {
|
|
|
223
180
|
};
|
|
224
181
|
|
|
225
182
|
export {
|
|
226
|
-
readJsonSafe,
|
|
227
|
-
backupFile,
|
|
228
|
-
writeFileAtomic,
|
|
229
|
-
writeJsonAtomic,
|
|
230
183
|
KEY_FILE_MODE,
|
|
231
184
|
exportLine,
|
|
232
185
|
keyPrefix,
|