sessionpipe-conformance 0.1.0 → 0.2.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 +1 -1
- package/dist/cli.js +197 -50
- package/dist/cli.js.map +3 -3
- package/dist/index.js +197 -50
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
// sessionpipe-conformance 0.
|
|
1
|
+
// sessionpipe-conformance 0.2.0 · Apache-2.0 · https://sessionpipe.org
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
5
5
|
|
|
6
6
|
// ../core/src/adapters/antigravity.ts
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
existsSync as existsSync2,
|
|
9
|
+
mkdirSync as mkdirSync2,
|
|
10
|
+
readdirSync as readdirSync2,
|
|
11
|
+
readFileSync as readFileSync2,
|
|
12
|
+
realpathSync,
|
|
13
|
+
statSync as statSync2,
|
|
14
|
+
unlinkSync as unlinkSync2,
|
|
15
|
+
writeFileSync as writeFileSync2
|
|
16
|
+
} from "node:fs";
|
|
8
17
|
import path3 from "node:path";
|
|
9
18
|
|
|
10
19
|
// ../core/src/paths.ts
|
|
@@ -212,28 +221,67 @@ function readAntigravity(lines, from) {
|
|
|
212
221
|
}
|
|
213
222
|
|
|
214
223
|
// ../core/src/adapters/claude-shaped.ts
|
|
215
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
224
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
216
225
|
import path2 from "node:path";
|
|
217
226
|
var OURS = /sessionpipe[^"\n]*[\\/]hook\.js"?\s+[a-z][a-z-]*\s+[A-Za-z]+\s*$/;
|
|
218
227
|
var isOurs = (h) => Array.isArray(h?.hooks) && h.hooks.some((x) => typeof x.command === "string" && OURS.test(x.command));
|
|
219
|
-
function
|
|
228
|
+
function readJsonFile(file) {
|
|
229
|
+
let raw;
|
|
220
230
|
try {
|
|
221
|
-
|
|
231
|
+
raw = readFileSync(file, "utf8");
|
|
222
232
|
} catch {
|
|
223
|
-
return {};
|
|
233
|
+
return { ok: true, existed: false, value: {}, raw: "", indent: " ", eol: "\n", finalNewline: true };
|
|
224
234
|
}
|
|
235
|
+
let value;
|
|
236
|
+
try {
|
|
237
|
+
value = JSON.parse(raw);
|
|
238
|
+
} catch {
|
|
239
|
+
const hint = /^\s*\/\/|\/\*/m.test(raw) ? "not plain JSON (it has comments)" : "not plain JSON";
|
|
240
|
+
return { ok: false, existed: true, reason: hint };
|
|
241
|
+
}
|
|
242
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
243
|
+
return { ok: false, existed: true, reason: "not a JSON object" };
|
|
244
|
+
const eol = raw.includes("\r\n") ? "\r\n" : "\n";
|
|
245
|
+
const m = /^( +|\t+)\S/m.exec(raw);
|
|
246
|
+
const indent = m?.[1] ?? " ";
|
|
247
|
+
return {
|
|
248
|
+
ok: true,
|
|
249
|
+
existed: true,
|
|
250
|
+
value,
|
|
251
|
+
raw,
|
|
252
|
+
indent,
|
|
253
|
+
eol,
|
|
254
|
+
finalNewline: /\r?\n$/.test(raw)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function formatJson(value, f) {
|
|
258
|
+
const text = JSON.stringify(value, null, f.indent).replace(/\n/g, f.eol);
|
|
259
|
+
return f.finalNewline ? text + f.eol : text;
|
|
225
260
|
}
|
|
226
261
|
function entryFor(event, harness, cmd, o) {
|
|
227
262
|
const matcher = o.matcherFor(event);
|
|
228
263
|
return {
|
|
229
264
|
...matcher !== void 0 ? { matcher } : {},
|
|
230
|
-
hooks: [{ type: "command", command: cmd([harness, event]).command, timeout: o.timeout }]
|
|
265
|
+
hooks: [{ type: "command", command: cmd([harness, event]).command, timeout: o.timeoutFor?.(event) ?? o.timeout }]
|
|
231
266
|
};
|
|
232
267
|
}
|
|
233
268
|
function installClaudeShaped(file, harness, events, cmd, o) {
|
|
234
|
-
const
|
|
269
|
+
const f = readJsonFile(file);
|
|
270
|
+
if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };
|
|
271
|
+
const settings2 = f.value;
|
|
235
272
|
const hooks = settings2.hooks && typeof settings2.hooks === "object" ? settings2.hooks : {};
|
|
236
273
|
let changed = false;
|
|
274
|
+
const want = new Set(events);
|
|
275
|
+
for (const ev of Object.keys(hooks)) {
|
|
276
|
+
if (want.has(ev)) continue;
|
|
277
|
+
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
278
|
+
const kept = list.filter((h) => !isOurs(h));
|
|
279
|
+
if (kept.length !== list.length) {
|
|
280
|
+
changed = true;
|
|
281
|
+
if (kept.length) hooks[ev] = kept;
|
|
282
|
+
else delete hooks[ev];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
237
285
|
for (const ev of events) {
|
|
238
286
|
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
239
287
|
const entry2 = entryFor(ev, harness, cmd, o);
|
|
@@ -252,19 +300,19 @@ function installClaudeShaped(file, harness, events, cmd, o) {
|
|
|
252
300
|
if (changed) {
|
|
253
301
|
settings2.hooks = hooks;
|
|
254
302
|
mkdirSync(path2.dirname(file), { recursive: true });
|
|
255
|
-
writeFileSync(file,
|
|
256
|
-
`);
|
|
303
|
+
writeFileSync(file, formatJson(settings2, f));
|
|
257
304
|
}
|
|
258
|
-
return { file, changed };
|
|
305
|
+
return { file, changed, created: !f.existed && changed };
|
|
259
306
|
}
|
|
260
|
-
function uninstallClaudeShaped(file, events) {
|
|
307
|
+
function uninstallClaudeShaped(file, events, opts = {}) {
|
|
261
308
|
if (!existsSync(file)) return { file, changed: false };
|
|
262
|
-
const
|
|
263
|
-
|
|
309
|
+
const f = readJsonFile(file);
|
|
310
|
+
if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };
|
|
311
|
+
const settings2 = f.value;
|
|
264
312
|
const hooks = settings2.hooks;
|
|
265
313
|
if (!hooks || typeof hooks !== "object") return { file, changed: false };
|
|
266
314
|
let changed = false;
|
|
267
|
-
for (const ev of events) {
|
|
315
|
+
for (const ev of [...events, ...Object.keys(hooks)]) {
|
|
268
316
|
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
269
317
|
const kept = list.filter((h) => !isOurs(h));
|
|
270
318
|
if (kept.length !== list.length) {
|
|
@@ -275,13 +323,17 @@ function uninstallClaudeShaped(file, events) {
|
|
|
275
323
|
}
|
|
276
324
|
if (!changed) return { file, changed: false };
|
|
277
325
|
if (!Object.keys(hooks).length) delete settings2.hooks;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
326
|
+
if (opts.created && !Object.keys(settings2).length) {
|
|
327
|
+
unlinkSync(file);
|
|
328
|
+
return { file, changed: true, note: "removed (sessionpipe created it)" };
|
|
329
|
+
}
|
|
330
|
+
const next = formatJson(settings2, f);
|
|
331
|
+
if (next !== f.raw) writeFileSync(file, next);
|
|
281
332
|
return { file, changed: true };
|
|
282
333
|
}
|
|
283
334
|
function installedClaudeShaped(file, harness, events, cmd, o) {
|
|
284
|
-
const
|
|
335
|
+
const f = readJsonFile(file);
|
|
336
|
+
const hooks = f.ok ? f.value.hooks ?? {} : {};
|
|
285
337
|
let present = 0;
|
|
286
338
|
let current = 0;
|
|
287
339
|
for (const ev of events) {
|
|
@@ -290,6 +342,9 @@ function installedClaudeShaped(file, harness, events, cmd, o) {
|
|
|
290
342
|
if (mine.length) present++;
|
|
291
343
|
if (mine.length === 1 && JSON.stringify(mine[0]) === JSON.stringify(entryFor(ev, harness, cmd, o))) current++;
|
|
292
344
|
}
|
|
345
|
+
for (const ev of Object.keys(hooks))
|
|
346
|
+
if (!events.includes(ev) && (Array.isArray(hooks[ev]) ? hooks[ev] : []).some((h) => isOurs(h)))
|
|
347
|
+
return "stale";
|
|
293
348
|
if (!present) return "missing";
|
|
294
349
|
return current === events.length ? "current" : "stale";
|
|
295
350
|
}
|
|
@@ -304,10 +359,13 @@ var projectsDir = (env) => path3.join(gemini(env), "config", "projects");
|
|
|
304
359
|
var dataDirs = (env) => ["antigravity", "antigravity-cli", "antigravity-ide"].map((d) => path3.join(gemini(env), d));
|
|
305
360
|
var ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
306
361
|
var validTool = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
|
|
307
|
-
function entry(cmd) {
|
|
362
|
+
function entry(cmd, lean) {
|
|
308
363
|
const handler = (e) => ({ type: "command", command: cmd([NAME, e]).command, timeout: 5 });
|
|
309
364
|
const out = { enabled: true };
|
|
310
|
-
for (const e of AG_EVENTS)
|
|
365
|
+
for (const e of AG_EVENTS) {
|
|
366
|
+
if (lean && e === "PreToolUse") continue;
|
|
367
|
+
out[e] = /Tool/.test(e) ? [{ matcher: "*", hooks: [handler(e)] }] : [handler(e)];
|
|
368
|
+
}
|
|
311
369
|
return out;
|
|
312
370
|
}
|
|
313
371
|
var antigravity = {
|
|
@@ -315,34 +373,49 @@ var antigravity = {
|
|
|
315
373
|
events: AG_EVENTS,
|
|
316
374
|
detect: (env = process.env) => existsSync2(path3.join(gemini(env), "config")) || dataDirs(env).some((d) => existsSync2(d)),
|
|
317
375
|
configFiles: (env = process.env) => [hooksFile(env)],
|
|
318
|
-
install(cmd, env = process.env) {
|
|
376
|
+
install(cmd, env = process.env, opts = {}) {
|
|
319
377
|
const file = hooksFile(env);
|
|
320
|
-
const
|
|
321
|
-
|
|
378
|
+
const f = readJsonFile(file);
|
|
379
|
+
if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];
|
|
380
|
+
const hooks = f.value;
|
|
381
|
+
const e = entry(cmd, opts.lean);
|
|
322
382
|
if (JSON.stringify(hooks[HOOK_NAME]) === JSON.stringify(e)) return [{ file, changed: false }];
|
|
323
383
|
hooks[HOOK_NAME] = e;
|
|
324
384
|
mkdirSync2(path3.dirname(file), { recursive: true });
|
|
325
|
-
writeFileSync2(file,
|
|
326
|
-
`);
|
|
385
|
+
writeFileSync2(file, formatJson(hooks, f));
|
|
327
386
|
return [
|
|
328
|
-
{
|
|
387
|
+
{
|
|
388
|
+
file,
|
|
389
|
+
changed: true,
|
|
390
|
+
created: !f.existed,
|
|
391
|
+
note: "hooks.json is read when a conversation starts; open ones report after a restart"
|
|
392
|
+
}
|
|
329
393
|
];
|
|
330
394
|
},
|
|
331
|
-
uninstall(env = process.env) {
|
|
395
|
+
uninstall(env = process.env, opts = {}) {
|
|
332
396
|
const file = hooksFile(env);
|
|
333
397
|
if (!existsSync2(file)) return [{ file, changed: false }];
|
|
334
|
-
const
|
|
398
|
+
const f = readJsonFile(file);
|
|
399
|
+
if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];
|
|
400
|
+
const hooks = f.value;
|
|
335
401
|
if (!(HOOK_NAME in hooks)) return [{ file, changed: false }];
|
|
336
402
|
delete hooks[HOOK_NAME];
|
|
337
|
-
|
|
338
|
-
|
|
403
|
+
if (opts.created?.includes(file) && !Object.keys(hooks).length) {
|
|
404
|
+
unlinkSync2(file);
|
|
405
|
+
return [{ file, changed: true, note: "removed (sessionpipe created it)" }];
|
|
406
|
+
}
|
|
407
|
+
writeFileSync2(file, formatJson(hooks, f));
|
|
339
408
|
return [{ file, changed: true }];
|
|
340
409
|
},
|
|
341
|
-
installed(cmd, env = process.env) {
|
|
410
|
+
installed(cmd, env = process.env, opts = {}) {
|
|
342
411
|
const file = hooksFile(env);
|
|
343
|
-
const
|
|
412
|
+
const f = readJsonFile(file);
|
|
413
|
+
const have = f.ok ? f.value[HOOK_NAME] : void 0;
|
|
344
414
|
return [
|
|
345
|
-
{
|
|
415
|
+
{
|
|
416
|
+
file,
|
|
417
|
+
state: !have ? "missing" : JSON.stringify(have) === JSON.stringify(entry(cmd, opts.lean)) ? "current" : "stale"
|
|
418
|
+
}
|
|
346
419
|
];
|
|
347
420
|
},
|
|
348
421
|
fromHook(input) {
|
|
@@ -608,9 +681,18 @@ var CLAUDE_EVENTS = [
|
|
|
608
681
|
"SubagentStop",
|
|
609
682
|
"PreCompact",
|
|
610
683
|
"PostCompact",
|
|
611
|
-
"SessionEnd"
|
|
684
|
+
"SessionEnd",
|
|
685
|
+
"StopFailure"
|
|
612
686
|
];
|
|
613
|
-
var
|
|
687
|
+
var LEAN_SKIP = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUseFailure"]);
|
|
688
|
+
var eventsFor = (lean) => lean ? CLAUDE_EVENTS.filter((e) => !LEAN_SKIP.has(e)) : [...CLAUDE_EVENTS];
|
|
689
|
+
var OPTS = {
|
|
690
|
+
matcherFor: (e) => /Tool|Permission/.test(e) ? "" : void 0,
|
|
691
|
+
timeout: 5,
|
|
692
|
+
// The hook waits up to 125 s for a verified control answer, and only when control
|
|
693
|
+
// is paired on this machine; everywhere else it exits in milliseconds as before.
|
|
694
|
+
timeoutFor: (e) => e === "PermissionRequest" ? 130 : void 0
|
|
695
|
+
};
|
|
614
696
|
var DESKTOP_ID = /^local_[A-Za-z0-9-]{1,64}$/;
|
|
615
697
|
function claudeDirs(env = process.env, home = HOME) {
|
|
616
698
|
const out = [];
|
|
@@ -641,11 +723,13 @@ var claudeCode = {
|
|
|
641
723
|
events: CLAUDE_EVENTS,
|
|
642
724
|
detect: (env = process.env) => claudeDirs(env).some((d) => existsSync3(d)),
|
|
643
725
|
configFiles: (env = process.env) => claudeDirs(env).map(settingsIn),
|
|
644
|
-
install: (cmd, env = process.env) => claudeDirs(env).map((d) => installClaudeShaped(settingsIn(d), NAME2,
|
|
645
|
-
uninstall: (env = process.env) => claudeDirs(env).map(
|
|
646
|
-
|
|
726
|
+
install: (cmd, env = process.env, opts = {}) => claudeDirs(env).map((d) => installClaudeShaped(settingsIn(d), NAME2, eventsFor(opts.lean), cmd, OPTS)),
|
|
727
|
+
uninstall: (env = process.env, opts = {}) => claudeDirs(env).map(
|
|
728
|
+
(d) => uninstallClaudeShaped(settingsIn(d), CLAUDE_EVENTS, { created: opts.created?.includes(settingsIn(d)) })
|
|
729
|
+
),
|
|
730
|
+
installed: (cmd, env = process.env, opts = {}) => claudeDirs(env).map((d) => ({
|
|
647
731
|
file: settingsIn(d),
|
|
648
|
-
state: installedClaudeShaped(settingsIn(d), NAME2,
|
|
732
|
+
state: installedClaudeShaped(settingsIn(d), NAME2, eventsFor(opts.lean), cmd, OPTS)
|
|
649
733
|
})),
|
|
650
734
|
fromHook(input) {
|
|
651
735
|
const event = input.argv[1] ?? "";
|
|
@@ -736,6 +820,15 @@ var claudeCode = {
|
|
|
736
820
|
case "Stop":
|
|
737
821
|
events.push(ev("turn.ended", { turn_id, reason: "stop" }));
|
|
738
822
|
break;
|
|
823
|
+
case "StopFailure":
|
|
824
|
+
events.push(
|
|
825
|
+
ev("turn.ended", {
|
|
826
|
+
turn_id,
|
|
827
|
+
reason: "error",
|
|
828
|
+
error: typeof s.error === "string" ? s.error.slice(0, 200) : void 0
|
|
829
|
+
})
|
|
830
|
+
);
|
|
831
|
+
break;
|
|
739
832
|
case "SubagentStart":
|
|
740
833
|
events.push(
|
|
741
834
|
ev("subagent.started", {
|
|
@@ -1247,6 +1340,7 @@ var CODEX_EVENTS = [
|
|
|
1247
1340
|
"SessionEnd"
|
|
1248
1341
|
];
|
|
1249
1342
|
var OPTS2 = { matcherFor: (e) => /Tool|Permission/.test(e) ? "" : void 0, timeout: 5 };
|
|
1343
|
+
var eventsFor2 = (lean) => lean ? CODEX_EVENTS.filter((e) => e !== "PreToolUse") : [...CODEX_EVENTS];
|
|
1250
1344
|
var codexHome = (env) => env.CODEX_HOME || path5.join(HOME, ".codex");
|
|
1251
1345
|
var hooksFile2 = (env) => path5.join(codexHome(env), "hooks.json");
|
|
1252
1346
|
var configFile = (env) => path5.join(codexHome(env), "config.toml");
|
|
@@ -1295,7 +1389,8 @@ function installNotify(cmd, env) {
|
|
|
1295
1389
|
return {
|
|
1296
1390
|
file,
|
|
1297
1391
|
changed: false,
|
|
1298
|
-
|
|
1392
|
+
skipped: true,
|
|
1393
|
+
note: `notify belongs to ${(n.argv?.[0] ?? n.raw).replace(/^.*\//, "").slice(0, 40)}; left alone. Codex will report nothing until you approve the hooks: start \`codex\` and accept the hook review`
|
|
1299
1394
|
};
|
|
1300
1395
|
}
|
|
1301
1396
|
write(withNotify(text, line));
|
|
@@ -1352,14 +1447,21 @@ var codex = {
|
|
|
1352
1447
|
events: CODEX_EVENTS,
|
|
1353
1448
|
detect: (env = process.env) => existsSync4(codexHome(env)),
|
|
1354
1449
|
configFiles: (env = process.env) => [hooksFile2(env), configFile(env)],
|
|
1355
|
-
install: (cmd, env = process.env) => [
|
|
1356
|
-
installClaudeShaped(hooksFile2(env), NAME3,
|
|
1450
|
+
install: (cmd, env = process.env, opts = {}) => [
|
|
1451
|
+
installClaudeShaped(hooksFile2(env), NAME3, eventsFor2(opts.lean), cmd, OPTS2),
|
|
1357
1452
|
installNotify(cmd, env)
|
|
1358
1453
|
],
|
|
1359
|
-
uninstall: (env = process.env) => [
|
|
1360
|
-
|
|
1454
|
+
uninstall: (env = process.env, opts = {}) => [
|
|
1455
|
+
uninstallClaudeShaped(hooksFile2(env), CODEX_EVENTS, { created: opts.created?.includes(hooksFile2(env)) }),
|
|
1456
|
+
uninstallNotify(env)
|
|
1457
|
+
],
|
|
1458
|
+
installed: (cmd, env = process.env, opts = {}) => {
|
|
1361
1459
|
const out = [
|
|
1362
|
-
{
|
|
1460
|
+
{
|
|
1461
|
+
file: hooksFile2(env),
|
|
1462
|
+
state: installedClaudeShaped(hooksFile2(env), NAME3, eventsFor2(opts.lean), cmd, OPTS2),
|
|
1463
|
+
note: "Codex runs non-managed hooks only after the review in `codex` (/hooks); until then nothing is reported unless the notify fallback is ours"
|
|
1464
|
+
}
|
|
1363
1465
|
];
|
|
1364
1466
|
let text = "";
|
|
1365
1467
|
try {
|
|
@@ -1547,6 +1649,7 @@ function codexFacts(file) {
|
|
|
1547
1649
|
}
|
|
1548
1650
|
|
|
1549
1651
|
// ../core/src/adapters/gemini-cli.ts
|
|
1652
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1550
1653
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
1551
1654
|
import path6 from "node:path";
|
|
1552
1655
|
var NAME4 = "gemini-cli";
|
|
@@ -1564,17 +1667,61 @@ var OPTS3 = { matcherFor: (e) => /Tool/.test(e) ? ".*" : void 0, timeout: 5e3 };
|
|
|
1564
1667
|
var geminiDir = (env) => env.GEMINI_CLI_HOME || path6.join(HOME, ".gemini");
|
|
1565
1668
|
var settings = (env) => path6.join(geminiDir(env), "settings.json");
|
|
1566
1669
|
var validTool4 = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
|
|
1670
|
+
var eventsFor3 = (lean) => lean ? GEMINI_EVENTS.filter((e) => e !== "BeforeTool") : [...GEMINI_EVENTS];
|
|
1671
|
+
function geminiHooksActive(settingsFile) {
|
|
1672
|
+
let tools;
|
|
1673
|
+
try {
|
|
1674
|
+
tools = JSON.parse(readFileSync5(settingsFile, "utf8")).tools;
|
|
1675
|
+
} catch {
|
|
1676
|
+
}
|
|
1677
|
+
if (tools?.enableHooks === true) return { active: true };
|
|
1678
|
+
if (tools?.enableHooks === false)
|
|
1679
|
+
return { active: false, note: "inactive: tools.enableHooks is false in settings.json" };
|
|
1680
|
+
let version = "";
|
|
1681
|
+
try {
|
|
1682
|
+
version = execFileSync3("gemini", ["--version"], {
|
|
1683
|
+
encoding: "utf8",
|
|
1684
|
+
timeout: 4e3,
|
|
1685
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1686
|
+
}).trim();
|
|
1687
|
+
} catch {
|
|
1688
|
+
return {
|
|
1689
|
+
active: true,
|
|
1690
|
+
note: "could not run `gemini --version`; hooks need tools.enableHooks on versions before 0.46"
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
const m = /(\d+)\.(\d+)/.exec(version);
|
|
1694
|
+
if (m && (Number(m[1]) > 0 || Number(m[2]) >= 46)) return { active: true };
|
|
1695
|
+
return {
|
|
1696
|
+
active: false,
|
|
1697
|
+
note: `inactive: Gemini CLI ${version || "?"} runs hooks only with "tools": {"enableHooks": true} in settings.json`
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1567
1700
|
var geminiCli = {
|
|
1568
1701
|
name: NAME4,
|
|
1569
1702
|
events: GEMINI_EVENTS,
|
|
1570
1703
|
// ~/.gemini also belongs to Antigravity; Gemini CLI is here when its settings or its chat logs exist.
|
|
1571
1704
|
detect: (env = process.env) => existsSync5(settings(env)) || existsSync5(path6.join(geminiDir(env), "tmp")),
|
|
1572
1705
|
configFiles: (env = process.env) => [settings(env)],
|
|
1573
|
-
install: (cmd, env = process.env
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1706
|
+
install: (cmd, env = process.env, opts = {}) => {
|
|
1707
|
+
const r = installClaudeShaped(settings(env), NAME4, eventsFor3(opts.lean), cmd, OPTS3);
|
|
1708
|
+
const a = geminiHooksActive(settings(env));
|
|
1709
|
+
return [a.note && !r.skipped ? { ...r, note: [r.note, a.note].filter(Boolean).join("; ") } : r];
|
|
1710
|
+
},
|
|
1711
|
+
uninstall: (env = process.env, opts = {}) => [
|
|
1712
|
+
uninstallClaudeShaped(settings(env), GEMINI_EVENTS, { created: opts.created?.includes(settings(env)) })
|
|
1577
1713
|
],
|
|
1714
|
+
installed: (cmd, env = process.env, opts = {}) => {
|
|
1715
|
+
const state = installedClaudeShaped(settings(env), NAME4, eventsFor3(opts.lean), cmd, OPTS3);
|
|
1716
|
+
const a = geminiHooksActive(settings(env));
|
|
1717
|
+
return [
|
|
1718
|
+
{
|
|
1719
|
+
file: settings(env),
|
|
1720
|
+
state: state === "current" && !a.active ? "inactive" : state,
|
|
1721
|
+
...a.note ? { note: a.note } : {}
|
|
1722
|
+
}
|
|
1723
|
+
];
|
|
1724
|
+
},
|
|
1578
1725
|
fromHook(input) {
|
|
1579
1726
|
const event = input.argv[1] ?? "";
|
|
1580
1727
|
let s = {};
|