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