gh-axi 0.1.5 → 0.1.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/dist/src/hooks.js +92 -46
- package/dist/src/hooks.js.map +1 -1
- package/package.json +6 -1
package/dist/src/hooks.js
CHANGED
|
@@ -3,51 +3,62 @@
|
|
|
3
3
|
* Ensures ambient context hooks are installed idempotently.
|
|
4
4
|
* Failures are non-fatal — errors log to stderr and never throw.
|
|
5
5
|
*/
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from
|
|
7
|
-
import { homedir } from
|
|
8
|
-
import { join } from
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
9
|
/** Marker used to identify our hook entries in config files. */
|
|
10
|
-
const HOOK_ID =
|
|
10
|
+
const HOOK_ID = "gh-axi";
|
|
11
11
|
function getExePath() {
|
|
12
12
|
return process.argv[1];
|
|
13
13
|
}
|
|
14
|
+
function ensureHookCollection(config) {
|
|
15
|
+
if (!config.hooks) {
|
|
16
|
+
config.hooks = {};
|
|
17
|
+
}
|
|
18
|
+
return config.hooks;
|
|
19
|
+
}
|
|
20
|
+
function ensureSessionStartBlocks(hooks) {
|
|
21
|
+
if (!Array.isArray(hooks.SessionStart)) {
|
|
22
|
+
hooks.SessionStart = [];
|
|
23
|
+
}
|
|
24
|
+
return hooks.SessionStart;
|
|
25
|
+
}
|
|
26
|
+
function isManagedHook(hook) {
|
|
27
|
+
return typeof hook?.command === "string" && hook.command.includes(HOOK_ID);
|
|
28
|
+
}
|
|
29
|
+
function createMatcherBlock(command) {
|
|
30
|
+
return {
|
|
31
|
+
matcher: "",
|
|
32
|
+
hooks: [
|
|
33
|
+
{
|
|
34
|
+
type: "command",
|
|
35
|
+
command,
|
|
36
|
+
timeout: 10,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
14
41
|
// ---------------------------------------------------------------------------
|
|
15
42
|
// Claude Code hooks: ~/.claude/settings.json
|
|
16
43
|
// ---------------------------------------------------------------------------
|
|
17
44
|
function ensureClaudeHook(exePath) {
|
|
18
|
-
const claudeDir = join(homedir(),
|
|
45
|
+
const claudeDir = join(homedir(), ".claude");
|
|
19
46
|
if (!existsSync(claudeDir))
|
|
20
47
|
return;
|
|
21
|
-
const settingsPath = join(claudeDir,
|
|
48
|
+
const settingsPath = join(claudeDir, "settings.json");
|
|
22
49
|
let settings = {};
|
|
23
50
|
if (existsSync(settingsPath)) {
|
|
24
|
-
const raw = readFileSync(settingsPath,
|
|
51
|
+
const raw = readFileSync(settingsPath, "utf-8");
|
|
25
52
|
settings = JSON.parse(raw);
|
|
26
53
|
}
|
|
27
|
-
|
|
28
|
-
settings.hooks = {};
|
|
29
|
-
}
|
|
30
|
-
if (!Array.isArray(settings.hooks.SessionStart)) {
|
|
31
|
-
settings.hooks.SessionStart = [];
|
|
32
|
-
}
|
|
33
|
-
const matcherBlocks = settings.hooks.SessionStart;
|
|
54
|
+
const matcherBlocks = ensureSessionStartBlocks(ensureHookCollection(settings));
|
|
34
55
|
const hookCommand = `${exePath} --session-start`;
|
|
35
56
|
// Find existing gh-axi matcher block (by looking for gh-axi in any nested hook command)
|
|
36
|
-
const existingIdx = matcherBlocks.findIndex((block) => Array.isArray(block.hooks) &&
|
|
37
|
-
|
|
38
|
-
const matcherBlock = {
|
|
39
|
-
matcher: '',
|
|
40
|
-
hooks: [
|
|
41
|
-
{
|
|
42
|
-
type: 'command',
|
|
43
|
-
command: hookCommand,
|
|
44
|
-
timeout: 10,
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
};
|
|
57
|
+
const existingIdx = matcherBlocks.findIndex((block) => Array.isArray(block.hooks) && block.hooks.some(isManagedHook));
|
|
58
|
+
const matcherBlock = createMatcherBlock(hookCommand);
|
|
48
59
|
if (existingIdx >= 0) {
|
|
49
60
|
// Check if command is already correct
|
|
50
|
-
const existingHook = matcherBlocks[existingIdx].hooks?.find(
|
|
61
|
+
const existingHook = matcherBlocks[existingIdx].hooks?.find(isManagedHook);
|
|
51
62
|
if (existingHook?.command === hookCommand) {
|
|
52
63
|
return; // no-op
|
|
53
64
|
}
|
|
@@ -57,42 +68,77 @@ function ensureClaudeHook(exePath) {
|
|
|
57
68
|
else {
|
|
58
69
|
matcherBlocks.push(matcherBlock);
|
|
59
70
|
}
|
|
60
|
-
writeFileSync(settingsPath, JSON.stringify(settings, null, 2),
|
|
71
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
61
72
|
}
|
|
62
73
|
// ---------------------------------------------------------------------------
|
|
63
74
|
// Codex hooks: ~/.codex/hooks.json
|
|
75
|
+
// Uses `hooks.SessionStart` matcher blocks and migrates legacy
|
|
76
|
+
// `hooks.session_start` entries when present.
|
|
64
77
|
// ---------------------------------------------------------------------------
|
|
65
78
|
function ensureCodexHook(exePath) {
|
|
66
|
-
const codexDir = join(homedir(),
|
|
79
|
+
const codexDir = join(homedir(), ".codex");
|
|
67
80
|
if (!existsSync(codexDir))
|
|
68
81
|
return;
|
|
69
|
-
const hooksPath = join(codexDir,
|
|
82
|
+
const hooksPath = join(codexDir, "hooks.json");
|
|
70
83
|
let config = {};
|
|
71
84
|
if (existsSync(hooksPath)) {
|
|
72
|
-
const raw = readFileSync(hooksPath,
|
|
85
|
+
const raw = readFileSync(hooksPath, "utf-8");
|
|
73
86
|
config = JSON.parse(raw);
|
|
74
87
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
if
|
|
79
|
-
|
|
88
|
+
const hooks = ensureHookCollection(config);
|
|
89
|
+
let changed = false;
|
|
90
|
+
const hookCommand = `${exePath} --session-start`;
|
|
91
|
+
// Migrate our legacy lowercase key if present.
|
|
92
|
+
if (Array.isArray(hooks.session_start)) {
|
|
93
|
+
const filteredLegacyHooks = hooks.session_start.filter((hook) => !isManagedHook(hook));
|
|
94
|
+
if (filteredLegacyHooks.length !== hooks.session_start.length) {
|
|
95
|
+
changed = true;
|
|
96
|
+
}
|
|
97
|
+
if (filteredLegacyHooks.length > 0) {
|
|
98
|
+
hooks.session_start = filteredLegacyHooks;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
delete hooks.session_start;
|
|
102
|
+
}
|
|
80
103
|
}
|
|
81
|
-
const
|
|
82
|
-
const existingIdx =
|
|
83
|
-
const
|
|
84
|
-
command: exePath,
|
|
85
|
-
};
|
|
104
|
+
const matcherBlocks = ensureSessionStartBlocks(hooks);
|
|
105
|
+
const existingIdx = matcherBlocks.findIndex((block) => Array.isArray(block.hooks) && block.hooks.some(isManagedHook));
|
|
106
|
+
const matcherBlock = createMatcherBlock(hookCommand);
|
|
86
107
|
if (existingIdx >= 0) {
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
const existingBlock = matcherBlocks[existingIdx];
|
|
109
|
+
const existingHook = existingBlock.hooks?.find(isManagedHook);
|
|
110
|
+
const matcher = existingBlock?.matcher;
|
|
111
|
+
const matcherIsMatchAll = matcher === "" || matcher === "*" || matcher == null;
|
|
112
|
+
if (existingHook?.command === hookCommand &&
|
|
113
|
+
matcherIsMatchAll &&
|
|
114
|
+
existingHook?.type === "command") {
|
|
115
|
+
if (!changed)
|
|
116
|
+
return; // no-op
|
|
117
|
+
}
|
|
118
|
+
else if (existingHook) {
|
|
119
|
+
existingHook.command = hookCommand;
|
|
120
|
+
existingHook.type = "command";
|
|
121
|
+
changed = true;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
if (!Array.isArray(existingBlock.hooks)) {
|
|
125
|
+
existingBlock.hooks = [];
|
|
126
|
+
}
|
|
127
|
+
existingBlock.hooks.push({
|
|
128
|
+
type: "command",
|
|
129
|
+
command: hookCommand,
|
|
130
|
+
timeout: 10,
|
|
131
|
+
});
|
|
132
|
+
changed = true;
|
|
89
133
|
}
|
|
90
|
-
hooks[existingIdx] = hookEntry;
|
|
91
134
|
}
|
|
92
135
|
else {
|
|
93
|
-
|
|
136
|
+
matcherBlocks.push(matcherBlock);
|
|
137
|
+
changed = true;
|
|
94
138
|
}
|
|
95
|
-
|
|
139
|
+
if (!changed)
|
|
140
|
+
return;
|
|
141
|
+
writeFileSync(hooksPath, JSON.stringify(config, null, 2), "utf-8");
|
|
96
142
|
}
|
|
97
143
|
// ---------------------------------------------------------------------------
|
|
98
144
|
// Public API
|
package/dist/src/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,gEAAgE;AAChE,MAAM,OAAO,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gh-axi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "AXI-compliant gh CLI wrapper — token-efficient TOON output, contextual suggestions, idempotent mutations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -41,9 +41,14 @@
|
|
|
41
41
|
"@toon-format/toon": "^2.1.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
+
"@eslint/js": "^10.0.1",
|
|
44
45
|
"@types/node": "^22.0.0",
|
|
46
|
+
"eslint": "^10.1.0",
|
|
47
|
+
"globals": "^17.4.0",
|
|
48
|
+
"prettier": "^3.8.1",
|
|
45
49
|
"tsx": "^4.0.0",
|
|
46
50
|
"typescript": "^5.7.0",
|
|
51
|
+
"typescript-eslint": "^8.58.0",
|
|
47
52
|
"vitest": "^3.0.0"
|
|
48
53
|
}
|
|
49
54
|
}
|