greprag 5.74.21 → 5.75.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/dist/commands/arm-reminder.js +4 -2
- package/dist/commands/codex.js +2 -7
- package/dist/commands/inbox-primer-reminder.js +16 -11
- package/dist/commands/inbox-watch-supervisor.js +17 -7
- package/dist/commands/inbox-watch.js +53 -29
- package/dist/commands/init.js +163 -4
- package/dist/commands/pipe-wrap.js +6 -5
- package/dist/commands/search-guard.js +2 -1
- package/dist/commands/status.js +29 -1
- package/dist/commands/watcher-registry.js +67 -22
- package/dist/grok-session.js +125 -0
- package/dist/harness.js +6 -0
- package/dist/hook-once.js +67 -0
- package/dist/hook-runtime.js +43 -0
- package/dist/hook.js +78 -17
- package/dist/index.js +17 -11
- package/dist/opencode-plugin.bundle.js +14 -7
- package/dist/session-id.js +46 -8
- package/package.json +3 -2
- package/skill/greprag/SKILL.md +6 -1
package/dist/commands/status.js
CHANGED
|
@@ -146,6 +146,9 @@ function readVersion() {
|
|
|
146
146
|
return 'unknown';
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
+
function grokHooksPath() {
|
|
150
|
+
return path.join(home(), '.grok', 'hooks', 'greprag.json');
|
|
151
|
+
}
|
|
149
152
|
function platformFromArgs(args) {
|
|
150
153
|
if (args.includes('--claude'))
|
|
151
154
|
return 'claude';
|
|
@@ -153,6 +156,8 @@ function platformFromArgs(args) {
|
|
|
153
156
|
return 'codex';
|
|
154
157
|
if (args.includes('--opencode'))
|
|
155
158
|
return 'opencode';
|
|
159
|
+
if (args.includes('--grok'))
|
|
160
|
+
return 'grok';
|
|
156
161
|
if (args.includes('--all-platforms'))
|
|
157
162
|
return 'all';
|
|
158
163
|
return 'all';
|
|
@@ -167,6 +172,8 @@ function buildStatus(cwd, platform = 'all') {
|
|
|
167
172
|
const identityCache = (0, identity_1.readCache)(identityCachePath);
|
|
168
173
|
const codexSkillPath = path.join(home(), '.codex', 'skills', 'greprag');
|
|
169
174
|
const claudeSkillPath = path.join(home(), '.claude', 'skills', 'greprag');
|
|
175
|
+
const grokSkillPath = path.join(home(), '.grok', 'skills', 'greprag');
|
|
176
|
+
const grokHooks = readJson(grokHooksPath(), {});
|
|
170
177
|
const opencodePluginPath = path.join(home(), '.config', 'opencode', 'plugins', 'greprag-memory.js');
|
|
171
178
|
const claudeHooks = {
|
|
172
179
|
session_start_recap: hasHook(settings.hooks?.SessionStart, 'recap'),
|
|
@@ -187,6 +194,15 @@ function buildStatus(cwd, platform = 'all') {
|
|
|
187
194
|
post_compact_session_id: hasCodexHook(codexHooks.hooks?.PostCompact, 'session-id'),
|
|
188
195
|
};
|
|
189
196
|
const opencodePluginInstalled = fs.existsSync(opencodePluginPath);
|
|
197
|
+
const grokHookStatus = {
|
|
198
|
+
session_start_recap: hasCodexHook(grokHooks.hooks?.SessionStart, 'recap'),
|
|
199
|
+
session_id: hasCodexHook(grokHooks.hooks?.SessionStart, 'session-id'),
|
|
200
|
+
session_start_drain: hasCodexHook(grokHooks.hooks?.SessionStart, 'drain'),
|
|
201
|
+
user_prompt_submit: hasCodexHook(grokHooks.hooks?.UserPromptSubmit, 'notify'),
|
|
202
|
+
crush_wrap: hasCodexHook(grokHooks.hooks?.PreToolUse, 'crush-wrap'),
|
|
203
|
+
stop_store: hasCodexHook(grokHooks.hooks?.Stop, 'store'),
|
|
204
|
+
stop_drain: hasCodexHook(grokHooks.hooks?.Stop, 'drain'),
|
|
205
|
+
};
|
|
190
206
|
return {
|
|
191
207
|
installed: true,
|
|
192
208
|
version: readVersion(),
|
|
@@ -212,6 +228,8 @@ function buildStatus(cwd, platform = 'all') {
|
|
|
212
228
|
codex_pre_tool_use_safety: codexHookStatus.pre_tool_use_safety,
|
|
213
229
|
codex_pre_tool_use_chip_guard: codexHookStatus.pre_tool_use_chip_guard,
|
|
214
230
|
codex_stop_store: codexHookStatus.stop_store,
|
|
231
|
+
grok_session_start_recap: grokHookStatus.session_start_recap,
|
|
232
|
+
grok_stop_store: grokHookStatus.stop_store,
|
|
215
233
|
},
|
|
216
234
|
platforms: {
|
|
217
235
|
claude: {
|
|
@@ -241,6 +259,16 @@ function buildStatus(cwd, platform = 'all') {
|
|
|
241
259
|
plugin_installed: opencodePluginInstalled,
|
|
242
260
|
note: 'OpenCode loads the GrepRAG plugin from its global plugin directory.',
|
|
243
261
|
},
|
|
262
|
+
grok: {
|
|
263
|
+
configured: !!api.key && grokHookStatus.session_start_recap && grokHookStatus.stop_store
|
|
264
|
+
&& fs.existsSync(grokSkillPath),
|
|
265
|
+
config_path: grokHooksPath(),
|
|
266
|
+
config_present: fs.existsSync(grokHooksPath()),
|
|
267
|
+
skill_path: grokSkillPath,
|
|
268
|
+
skill_installed: fs.existsSync(grokSkillPath),
|
|
269
|
+
hooks: grokHookStatus,
|
|
270
|
+
note: 'Grok recap is a sidecar + ~/.grok/rules (SessionStart stdout is ignored). Idle inbox: Grok monitor + quiet watch. Stop drain injects unread mail.',
|
|
271
|
+
},
|
|
244
272
|
},
|
|
245
273
|
project: {
|
|
246
274
|
cwd: path.resolve(cwd),
|
|
@@ -293,7 +321,7 @@ function renderPlatform(name, p) {
|
|
|
293
321
|
}
|
|
294
322
|
function renderHuman(s, docMirror) {
|
|
295
323
|
const yes = (b) => b ? 'yes' : 'no';
|
|
296
|
-
const platformNames = s.platform === 'all' ? ['claude', 'codex', 'opencode'] : [s.platform];
|
|
324
|
+
const platformNames = s.platform === 'all' ? ['claude', 'codex', 'opencode', 'grok'] : [s.platform];
|
|
297
325
|
return [
|
|
298
326
|
`greprag ${s.version}`,
|
|
299
327
|
`Shared env: ${s.shared_env_path}`,
|
|
@@ -79,13 +79,14 @@ exports.gcDeadSessions = gcDeadSessions;
|
|
|
79
79
|
const fs = __importStar(require("fs"));
|
|
80
80
|
const path = __importStar(require("path"));
|
|
81
81
|
const child_process_1 = require("child_process");
|
|
82
|
+
const session_id_1 = require("../session-id");
|
|
82
83
|
const WATCHER_DIRNAME = 'watchers';
|
|
83
84
|
// Matches a greprag watcher's command line in every launch shape (npm shim, bash
|
|
84
85
|
// relauncher, the supervisor's CreateProcess re-invocation). Anchored on the
|
|
85
86
|
// INVOKED BINARY (`greprag` or `index.js`) immediately followed by `inbox watch`
|
|
86
87
|
// — never a bare `inbox watch` substring. Retained for the owner-pid resolver's
|
|
87
88
|
// claude.exe match; the cleanup path no longer scans the process table at all.
|
|
88
|
-
const CLAUDE_PROC_RE = /^claude(\.exe)?$/i;
|
|
89
|
+
const CLAUDE_PROC_RE = /^(claude|grok)(\.exe)?$/i;
|
|
89
90
|
/** Default per-session watcher floor: keep this many freshest live watchers, reap
|
|
90
91
|
* only the surplus above it, never below it. K=2 = the live one + one margin. */
|
|
91
92
|
exports.DEFAULT_WATCHER_CAP = 2;
|
|
@@ -97,9 +98,26 @@ function watchersDir() {
|
|
|
97
98
|
const h = grepragHome();
|
|
98
99
|
return h ? path.join(h, WATCHER_DIRNAME) : null;
|
|
99
100
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
function sessionKey(short) {
|
|
102
|
+
return (0, session_id_1.truncateSessionId)(short) || short;
|
|
103
|
+
}
|
|
104
|
+
/** Pidfile names that belong to the same session: canonical short (16-hex
|
|
105
|
+
* for UUIDv7, 8-hex otherwise) plus the raw/--session string. A Grok watch
|
|
106
|
+
* armed with `$GROK_SESSION_ID` (dashed UUID) used to write
|
|
107
|
+
* `<full-uuid>.json` while Stop's isLocallyArmed looked at `<16-hex>.json`
|
|
108
|
+
* → perpetual UNARMED nag + singleton-guard bounce. */
|
|
109
|
+
function matchingPidfileNames(short) {
|
|
110
|
+
const want = sessionKey(short);
|
|
111
|
+
const names = new Set();
|
|
112
|
+
if (want)
|
|
113
|
+
names.add(want);
|
|
114
|
+
if (short)
|
|
115
|
+
names.add(short);
|
|
116
|
+
for (const name of allShorts()) {
|
|
117
|
+
if (name === short || sessionKey(name) === want)
|
|
118
|
+
names.add(name);
|
|
119
|
+
}
|
|
120
|
+
return [...names];
|
|
103
121
|
}
|
|
104
122
|
/** True iff `pid` is a live process. `process.kill(pid, 0)` sends no signal — it
|
|
105
123
|
* only probes existence. EPERM = exists but another user (alive); ESRCH = gone. */
|
|
@@ -114,20 +132,32 @@ function pidAlive(pid) {
|
|
|
114
132
|
return e?.code === 'EPERM';
|
|
115
133
|
}
|
|
116
134
|
}
|
|
117
|
-
/** Read a session's entry LIST.
|
|
118
|
-
*
|
|
135
|
+
/** Read a session's entry LIST. Merges alias pidfiles (dashed UUID, 16-hex,
|
|
136
|
+
* raw --session). Back-compat: a legacy single-object pidfile reads as a
|
|
137
|
+
* 1-element list. */
|
|
119
138
|
function readWatcherEntries(short) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (!p)
|
|
123
|
-
return [];
|
|
124
|
-
const parsed = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
125
|
-
const arr = Array.isArray(parsed) ? parsed : [parsed];
|
|
126
|
-
return arr.filter((r) => !!r && typeof r.pid === 'number');
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
139
|
+
const dir = watchersDir();
|
|
140
|
+
if (!dir)
|
|
129
141
|
return [];
|
|
142
|
+
const seen = new Set();
|
|
143
|
+
const out = [];
|
|
144
|
+
for (const name of matchingPidfileNames(short)) {
|
|
145
|
+
try {
|
|
146
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dir, `${name}.json`), 'utf-8'));
|
|
147
|
+
const arr = Array.isArray(parsed) ? parsed : [parsed];
|
|
148
|
+
for (const r of arr) {
|
|
149
|
+
if (!r || typeof r.pid !== 'number')
|
|
150
|
+
continue;
|
|
151
|
+
const rec = r;
|
|
152
|
+
if (seen.has(rec.pid))
|
|
153
|
+
continue;
|
|
154
|
+
seen.add(rec.pid);
|
|
155
|
+
out.push(rec);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch { /* missing alias is fine */ }
|
|
130
159
|
}
|
|
160
|
+
return out;
|
|
131
161
|
}
|
|
132
162
|
function writeWatcherEntries(short, entries) {
|
|
133
163
|
try {
|
|
@@ -135,12 +165,21 @@ function writeWatcherEntries(short, entries) {
|
|
|
135
165
|
if (!dir)
|
|
136
166
|
return;
|
|
137
167
|
fs.mkdirSync(dir, { recursive: true });
|
|
138
|
-
const
|
|
168
|
+
const key = sessionKey(short);
|
|
169
|
+
const canonical = path.join(dir, `${key}.json`);
|
|
170
|
+
for (const name of matchingPidfileNames(short)) {
|
|
171
|
+
if (name === key)
|
|
172
|
+
continue;
|
|
173
|
+
try {
|
|
174
|
+
fs.rmSync(path.join(dir, `${name}.json`), { force: true });
|
|
175
|
+
}
|
|
176
|
+
catch { /* best-effort */ }
|
|
177
|
+
}
|
|
139
178
|
if (entries.length === 0) {
|
|
140
|
-
fs.rmSync(
|
|
179
|
+
fs.rmSync(canonical, { force: true });
|
|
141
180
|
return;
|
|
142
181
|
}
|
|
143
|
-
fs.writeFileSync(
|
|
182
|
+
fs.writeFileSync(canonical, JSON.stringify(entries));
|
|
144
183
|
}
|
|
145
184
|
catch { /* best-effort — a failed write only means re-arm, never a crash */ }
|
|
146
185
|
}
|
|
@@ -155,12 +194,18 @@ function writeWatcherPidfile(short, pid, ownerPid) {
|
|
|
155
194
|
function removeWatcherEntry(short, pid) {
|
|
156
195
|
writeWatcherEntries(short, readWatcherEntries(short).filter(r => r.pid !== pid));
|
|
157
196
|
}
|
|
158
|
-
/** Remove a session's whole pidfile (legacy / full sweep). */
|
|
197
|
+
/** Remove a session's whole pidfile (legacy / full sweep), including aliases. */
|
|
159
198
|
function removeWatcherPidfile(short) {
|
|
160
199
|
try {
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
163
|
-
|
|
200
|
+
const dir = watchersDir();
|
|
201
|
+
if (!dir)
|
|
202
|
+
return;
|
|
203
|
+
for (const name of matchingPidfileNames(short)) {
|
|
204
|
+
try {
|
|
205
|
+
fs.rmSync(path.join(dir, `${name}.json`), { force: true });
|
|
206
|
+
}
|
|
207
|
+
catch { /* best-effort */ }
|
|
208
|
+
}
|
|
164
209
|
}
|
|
165
210
|
catch { /* best-effort */ }
|
|
166
211
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Grok Build session files + the recap sidecar SessionStart can write
|
|
3
|
+
* (Grok ignores SessionStart stdout, so the always-on rule points here).
|
|
4
|
+
* adr: adr/grok-platform.md */
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.grokSessionDir = grokSessionDir;
|
|
40
|
+
exports.readLatestGrokUserPrompt = readLatestGrokUserPrompt;
|
|
41
|
+
exports.grokSidecarPath = grokSidecarPath;
|
|
42
|
+
exports.writeGrokSidecar = writeGrokSidecar;
|
|
43
|
+
exports.appendGrokSidecar = appendGrokSidecar;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const os = __importStar(require("os"));
|
|
47
|
+
function grokHome() {
|
|
48
|
+
if (process.env.GROK_HOME)
|
|
49
|
+
return process.env.GROK_HOME;
|
|
50
|
+
return path.join(os.homedir(), '.grok');
|
|
51
|
+
}
|
|
52
|
+
function grokSessionDir(cwd, sessionId) {
|
|
53
|
+
const encoded = encodeURIComponent(path.resolve(cwd));
|
|
54
|
+
return path.join(grokHome(), 'sessions', encoded, sessionId);
|
|
55
|
+
}
|
|
56
|
+
function extractText(content) {
|
|
57
|
+
if (typeof content === 'string')
|
|
58
|
+
return content.trim();
|
|
59
|
+
if (!Array.isArray(content))
|
|
60
|
+
return '';
|
|
61
|
+
return content
|
|
62
|
+
.filter((b) => b?.type === 'text' && typeof b.text === 'string')
|
|
63
|
+
.map((b) => String(b.text))
|
|
64
|
+
.join('\n')
|
|
65
|
+
.trim();
|
|
66
|
+
}
|
|
67
|
+
function unwrapUserQuery(text) {
|
|
68
|
+
const m = text.match(/<user_query>\s*([\s\S]*?)\s*<\/user_query>/i);
|
|
69
|
+
return (m?.[1] || text).trim();
|
|
70
|
+
}
|
|
71
|
+
/** Latest real user prompt from Grok chat_history.jsonl. */
|
|
72
|
+
function readLatestGrokUserPrompt(cwd, sessionId) {
|
|
73
|
+
if (!sessionId)
|
|
74
|
+
return '';
|
|
75
|
+
const file = path.join(grokSessionDir(cwd, sessionId), 'chat_history.jsonl');
|
|
76
|
+
let raw;
|
|
77
|
+
try {
|
|
78
|
+
raw = fs.readFileSync(file, 'utf-8');
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
const lines = raw.split(/\n/);
|
|
84
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
85
|
+
const line = lines[i].trim();
|
|
86
|
+
if (!line)
|
|
87
|
+
continue;
|
|
88
|
+
let entry;
|
|
89
|
+
try {
|
|
90
|
+
entry = JSON.parse(line);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (entry.type !== 'user')
|
|
96
|
+
continue;
|
|
97
|
+
const text = unwrapUserQuery(extractText(entry.content));
|
|
98
|
+
if (text)
|
|
99
|
+
return text;
|
|
100
|
+
}
|
|
101
|
+
return '';
|
|
102
|
+
}
|
|
103
|
+
function grokSidecarPath(short) {
|
|
104
|
+
return path.join(os.homedir(), '.greprag', 'grok-context', `${short}.md`);
|
|
105
|
+
}
|
|
106
|
+
function writeGrokSidecar(short, text) {
|
|
107
|
+
if (!short || !text)
|
|
108
|
+
return;
|
|
109
|
+
try {
|
|
110
|
+
const file = grokSidecarPath(short);
|
|
111
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
112
|
+
fs.writeFileSync(file, text);
|
|
113
|
+
}
|
|
114
|
+
catch { /* sidecar is best-effort */ }
|
|
115
|
+
}
|
|
116
|
+
function appendGrokSidecar(short, text) {
|
|
117
|
+
if (!short || !text)
|
|
118
|
+
return;
|
|
119
|
+
try {
|
|
120
|
+
const file = grokSidecarPath(short);
|
|
121
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
122
|
+
fs.appendFileSync(file, (fs.existsSync(file) ? '\n\n' : '') + text);
|
|
123
|
+
}
|
|
124
|
+
catch { /* sidecar is best-effort */ }
|
|
125
|
+
}
|
package/dist/harness.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.REPAIR_TARGET_HARNESSES = [
|
|
|
8
8
|
'claude-code',
|
|
9
9
|
'codex',
|
|
10
10
|
'opencode',
|
|
11
|
+
'grok',
|
|
11
12
|
'all',
|
|
12
13
|
];
|
|
13
14
|
function normalizeHarness(raw) {
|
|
@@ -20,6 +21,8 @@ function normalizeHarness(raw) {
|
|
|
20
21
|
return 'codex';
|
|
21
22
|
if (v === 'opencode' || v === 'open-code' || v === 'open_code')
|
|
22
23
|
return 'opencode';
|
|
24
|
+
if (v === 'grok' || v === 'grok-build' || v === 'grok_build')
|
|
25
|
+
return 'grok';
|
|
23
26
|
if (v === 'all' || v === 'any' || v === 'universal')
|
|
24
27
|
return 'all';
|
|
25
28
|
return null;
|
|
@@ -30,6 +33,9 @@ function inferCurrentHarness() {
|
|
|
30
33
|
if (h && h !== 'all')
|
|
31
34
|
return h;
|
|
32
35
|
}
|
|
36
|
+
// Grok sets CLAUDE_PROJECT_DIR as a compat alias. Detect Grok BEFORE Claude.
|
|
37
|
+
if (process.env.GROK_SESSION_ID || process.env.GROK_HOOK_EVENT)
|
|
38
|
+
return 'grok';
|
|
33
39
|
if (process.env.CODEX_THREAD_ID)
|
|
34
40
|
return 'codex';
|
|
35
41
|
if (process.env.GREPRAG_OPENCODE_SESSION_ID || process.env.OPENCODE_SESSION_ID)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Once-per-event stamp so leaked Claude greprag hooks + dedicated
|
|
3
|
+
* ~/.grok/hooks/greprag.json cannot double-store / double-recap.
|
|
4
|
+
* adr: adr/grok-platform.md */
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.claimHookOnce = claimHookOnce;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const os = __importStar(require("os"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const TTL_MS = 60_000;
|
|
44
|
+
function stampPath(sessionId, event, sub, turnId) {
|
|
45
|
+
const safe = [sessionId, event, sub, turnId].join('-').replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 180);
|
|
46
|
+
return path.join(os.homedir(), '.greprag', 'hook-once', `${safe}.json`);
|
|
47
|
+
}
|
|
48
|
+
/** True = this process should run the subcommand. False = duplicate, skip. */
|
|
49
|
+
function claimHookOnce(sessionId, event, subcommand, turnId) {
|
|
50
|
+
if (!sessionId)
|
|
51
|
+
return true;
|
|
52
|
+
const key = turnId || 'noturn';
|
|
53
|
+
const file = stampPath(sessionId, event || 'unknown', subcommand, key);
|
|
54
|
+
try {
|
|
55
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
56
|
+
if (fs.existsSync(file)) {
|
|
57
|
+
const age = Date.now() - fs.statSync(file).mtimeMs;
|
|
58
|
+
if (age < TTL_MS)
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
fs.writeFileSync(file, JSON.stringify({ ts: Date.now(), subcommand }));
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/hook-runtime.js
CHANGED
|
@@ -33,12 +33,55 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeHookInput = normalizeHookInput;
|
|
37
|
+
exports.isGrokProcess = isGrokProcess;
|
|
38
|
+
exports.isShellTool = isShellTool;
|
|
36
39
|
exports.ensureEnv = ensureEnv;
|
|
37
40
|
exports.getHookConfig = getHookConfig;
|
|
38
41
|
exports.apiCall = apiCall;
|
|
39
42
|
exports.writeAdditionalContext = writeAdditionalContext;
|
|
40
43
|
const fs = __importStar(require("fs"));
|
|
41
44
|
const path = __importStar(require("path"));
|
|
45
|
+
function asString(v) {
|
|
46
|
+
return typeof v === 'string' && v ? v : undefined;
|
|
47
|
+
}
|
|
48
|
+
function asObj(v) {
|
|
49
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? v : undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Grok sends camelCase; Claude/Codex send snake_case. One bag for every hook.
|
|
52
|
+
* adr: adr/grok-platform.md */
|
|
53
|
+
function normalizeHookInput(raw) {
|
|
54
|
+
const r = (raw && typeof raw === 'object') ? raw : {};
|
|
55
|
+
const event = asString(r.hook_event_name) || asString(r.hookEventName)
|
|
56
|
+
|| asString(process.env.GROK_HOOK_EVENT);
|
|
57
|
+
const session = asString(r.session_id) || asString(r.sessionId)
|
|
58
|
+
|| asString(process.env.GROK_SESSION_ID)
|
|
59
|
+
|| asString(process.env.CLAUDE_CODE_SESSION_ID)
|
|
60
|
+
|| asString(process.env.CODEX_THREAD_ID);
|
|
61
|
+
const cwd = asString(r.cwd) || asString(r.workspaceRoot)
|
|
62
|
+
|| asString(process.env.GROK_WORKSPACE_ROOT);
|
|
63
|
+
const toolInput = asObj(r.tool_input) || asObj(r.toolInput);
|
|
64
|
+
return {
|
|
65
|
+
session_id: session,
|
|
66
|
+
turn_id: asString(r.turn_id) || asString(r.promptId) || asString(r.prompt_id),
|
|
67
|
+
transcript_path: asString(r.transcript_path) || asString(r.transcriptPath),
|
|
68
|
+
cwd,
|
|
69
|
+
hook_event_name: event,
|
|
70
|
+
prompt: asString(r.prompt),
|
|
71
|
+
model: asString(r.model),
|
|
72
|
+
last_assistant_message: asString(r.last_assistant_message) || asString(r.lastAssistantMessage),
|
|
73
|
+
tool_name: asString(r.tool_name) || asString(r.toolName),
|
|
74
|
+
tool_input: toolInput,
|
|
75
|
+
stop_hook_active: r.stop_hook_active === true || r.stopHookActive === true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function isGrokProcess() {
|
|
79
|
+
return !!(process.env.GROK_SESSION_ID || process.env.GROK_HOOK_EVENT);
|
|
80
|
+
}
|
|
81
|
+
function isShellTool(name) {
|
|
82
|
+
const n = (name || '').toLowerCase();
|
|
83
|
+
return n === 'bash' || n === 'run_terminal_command' || n === 'shell';
|
|
84
|
+
}
|
|
42
85
|
const API_URL_DEFAULT = 'https://api.greprag.com';
|
|
43
86
|
function loadEnvFile(filePath) {
|
|
44
87
|
try {
|