sessionpipe-core 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/index.js +204 -63
- package/dist/index.js.map +3 -3
- package/dist/schema/v1.d.ts +2 -0
- package/dist/schema/v1.d.ts.map +1 -1
- package/dist/schema.js +3 -1
- package/dist/schema.js.map +2 -2
- package/dist/src/adapters/antigravity.d.ts.map +1 -1
- package/dist/src/adapters/claude-code.d.ts +1 -1
- package/dist/src/adapters/claude-code.d.ts.map +1 -1
- package/dist/src/adapters/claude-shaped.d.ts +35 -2
- package/dist/src/adapters/claude-shaped.d.ts.map +1 -1
- package/dist/src/adapters/codex.d.ts.map +1 -1
- package/dist/src/adapters/gemini-cli.d.ts +5 -0
- package/dist/src/adapters/gemini-cli.d.ts.map +1 -1
- package/dist/src/adapters/types.d.ts +23 -7
- package/dist/src/adapters/types.d.ts.map +1 -1
- package/dist/src/config.d.ts +1 -0
- package/dist/src/config.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
// sessionpipe-core 0.1.
|
|
1
|
+
// sessionpipe-core 0.1.1 · Apache-2.0 · https://sessionpipe.org
|
|
2
2
|
|
|
3
3
|
// src/adapters/antigravity.ts
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
existsSync as existsSync2,
|
|
6
|
+
mkdirSync as mkdirSync2,
|
|
7
|
+
readdirSync as readdirSync2,
|
|
8
|
+
readFileSync as readFileSync2,
|
|
9
|
+
realpathSync,
|
|
10
|
+
statSync as statSync2,
|
|
11
|
+
unlinkSync as unlinkSync2,
|
|
12
|
+
writeFileSync as writeFileSync2
|
|
13
|
+
} from "node:fs";
|
|
5
14
|
import path4 from "node:path";
|
|
6
15
|
|
|
7
16
|
// src/paths.ts
|
|
@@ -228,16 +237,42 @@ function readAntigravity(lines, from) {
|
|
|
228
237
|
}
|
|
229
238
|
|
|
230
239
|
// src/adapters/claude-shaped.ts
|
|
231
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
240
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
232
241
|
import path3 from "node:path";
|
|
233
242
|
var OURS = /sessionpipe[^"\n]*[\\/]hook\.js"?\s+[a-z][a-z-]*\s+[A-Za-z]+\s*$/;
|
|
234
243
|
var isOurs = (h) => Array.isArray(h?.hooks) && h.hooks.some((x) => typeof x.command === "string" && OURS.test(x.command));
|
|
235
|
-
function
|
|
244
|
+
function readJsonFile(file) {
|
|
245
|
+
let raw;
|
|
236
246
|
try {
|
|
237
|
-
|
|
247
|
+
raw = readFileSync(file, "utf8");
|
|
238
248
|
} catch {
|
|
239
|
-
return {};
|
|
249
|
+
return { ok: true, existed: false, value: {}, raw: "", indent: " ", eol: "\n", finalNewline: true };
|
|
240
250
|
}
|
|
251
|
+
let value;
|
|
252
|
+
try {
|
|
253
|
+
value = JSON.parse(raw);
|
|
254
|
+
} catch {
|
|
255
|
+
const hint = /^\s*\/\/|\/\*/m.test(raw) ? "not plain JSON (it has comments)" : "not plain JSON";
|
|
256
|
+
return { ok: false, existed: true, reason: hint };
|
|
257
|
+
}
|
|
258
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
259
|
+
return { ok: false, existed: true, reason: "not a JSON object" };
|
|
260
|
+
const eol = raw.includes("\r\n") ? "\r\n" : "\n";
|
|
261
|
+
const m = /^( +|\t+)\S/m.exec(raw);
|
|
262
|
+
const indent = m?.[1] ?? " ";
|
|
263
|
+
return {
|
|
264
|
+
ok: true,
|
|
265
|
+
existed: true,
|
|
266
|
+
value,
|
|
267
|
+
raw,
|
|
268
|
+
indent,
|
|
269
|
+
eol,
|
|
270
|
+
finalNewline: /\r?\n$/.test(raw)
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function formatJson(value, f) {
|
|
274
|
+
const text = JSON.stringify(value, null, f.indent).replace(/\n/g, f.eol);
|
|
275
|
+
return f.finalNewline ? text + f.eol : text;
|
|
241
276
|
}
|
|
242
277
|
function entryFor(event, harness, cmd, o) {
|
|
243
278
|
const matcher = o.matcherFor(event);
|
|
@@ -247,9 +282,22 @@ function entryFor(event, harness, cmd, o) {
|
|
|
247
282
|
};
|
|
248
283
|
}
|
|
249
284
|
function installClaudeShaped(file, harness, events, cmd, o) {
|
|
250
|
-
const
|
|
285
|
+
const f = readJsonFile(file);
|
|
286
|
+
if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };
|
|
287
|
+
const settings2 = f.value;
|
|
251
288
|
const hooks = settings2.hooks && typeof settings2.hooks === "object" ? settings2.hooks : {};
|
|
252
289
|
let changed = false;
|
|
290
|
+
const want = new Set(events);
|
|
291
|
+
for (const ev of Object.keys(hooks)) {
|
|
292
|
+
if (want.has(ev)) continue;
|
|
293
|
+
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
294
|
+
const kept = list.filter((h) => !isOurs(h));
|
|
295
|
+
if (kept.length !== list.length) {
|
|
296
|
+
changed = true;
|
|
297
|
+
if (kept.length) hooks[ev] = kept;
|
|
298
|
+
else delete hooks[ev];
|
|
299
|
+
}
|
|
300
|
+
}
|
|
253
301
|
for (const ev of events) {
|
|
254
302
|
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
255
303
|
const entry2 = entryFor(ev, harness, cmd, o);
|
|
@@ -268,19 +316,19 @@ function installClaudeShaped(file, harness, events, cmd, o) {
|
|
|
268
316
|
if (changed) {
|
|
269
317
|
settings2.hooks = hooks;
|
|
270
318
|
mkdirSync(path3.dirname(file), { recursive: true });
|
|
271
|
-
writeFileSync(file,
|
|
272
|
-
`);
|
|
319
|
+
writeFileSync(file, formatJson(settings2, f));
|
|
273
320
|
}
|
|
274
|
-
return { file, changed };
|
|
321
|
+
return { file, changed, created: !f.existed && changed };
|
|
275
322
|
}
|
|
276
|
-
function uninstallClaudeShaped(file, events) {
|
|
323
|
+
function uninstallClaudeShaped(file, events, opts = {}) {
|
|
277
324
|
if (!existsSync(file)) return { file, changed: false };
|
|
278
|
-
const
|
|
279
|
-
|
|
325
|
+
const f = readJsonFile(file);
|
|
326
|
+
if (!f.ok) return { file, changed: false, skipped: true, note: `${f.reason}; not touched` };
|
|
327
|
+
const settings2 = f.value;
|
|
280
328
|
const hooks = settings2.hooks;
|
|
281
329
|
if (!hooks || typeof hooks !== "object") return { file, changed: false };
|
|
282
330
|
let changed = false;
|
|
283
|
-
for (const ev of events) {
|
|
331
|
+
for (const ev of [...events, ...Object.keys(hooks)]) {
|
|
284
332
|
const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
|
|
285
333
|
const kept = list.filter((h) => !isOurs(h));
|
|
286
334
|
if (kept.length !== list.length) {
|
|
@@ -291,13 +339,17 @@ function uninstallClaudeShaped(file, events) {
|
|
|
291
339
|
}
|
|
292
340
|
if (!changed) return { file, changed: false };
|
|
293
341
|
if (!Object.keys(hooks).length) delete settings2.hooks;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
342
|
+
if (opts.created && !Object.keys(settings2).length) {
|
|
343
|
+
unlinkSync(file);
|
|
344
|
+
return { file, changed: true, note: "removed (sessionpipe created it)" };
|
|
345
|
+
}
|
|
346
|
+
const next = formatJson(settings2, f);
|
|
347
|
+
if (next !== f.raw) writeFileSync(file, next);
|
|
297
348
|
return { file, changed: true };
|
|
298
349
|
}
|
|
299
350
|
function installedClaudeShaped(file, harness, events, cmd, o) {
|
|
300
|
-
const
|
|
351
|
+
const f = readJsonFile(file);
|
|
352
|
+
const hooks = f.ok ? f.value.hooks ?? {} : {};
|
|
301
353
|
let present = 0;
|
|
302
354
|
let current = 0;
|
|
303
355
|
for (const ev of events) {
|
|
@@ -306,6 +358,9 @@ function installedClaudeShaped(file, harness, events, cmd, o) {
|
|
|
306
358
|
if (mine.length) present++;
|
|
307
359
|
if (mine.length === 1 && JSON.stringify(mine[0]) === JSON.stringify(entryFor(ev, harness, cmd, o))) current++;
|
|
308
360
|
}
|
|
361
|
+
for (const ev of Object.keys(hooks))
|
|
362
|
+
if (!events.includes(ev) && (Array.isArray(hooks[ev]) ? hooks[ev] : []).some((h) => isOurs(h)))
|
|
363
|
+
return "stale";
|
|
309
364
|
if (!present) return "missing";
|
|
310
365
|
return current === events.length ? "current" : "stale";
|
|
311
366
|
}
|
|
@@ -320,10 +375,13 @@ var projectsDir = (env) => path4.join(gemini(env), "config", "projects");
|
|
|
320
375
|
var dataDirs = (env) => ["antigravity", "antigravity-cli", "antigravity-ide"].map((d) => path4.join(gemini(env), d));
|
|
321
376
|
var ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
322
377
|
var validTool = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
|
|
323
|
-
function entry(cmd) {
|
|
378
|
+
function entry(cmd, lean) {
|
|
324
379
|
const handler = (e) => ({ type: "command", command: cmd([NAME, e]).command, timeout: 5 });
|
|
325
380
|
const out = { enabled: true };
|
|
326
|
-
for (const e of AG_EVENTS)
|
|
381
|
+
for (const e of AG_EVENTS) {
|
|
382
|
+
if (lean && e === "PreToolUse") continue;
|
|
383
|
+
out[e] = /Tool/.test(e) ? [{ matcher: "*", hooks: [handler(e)] }] : [handler(e)];
|
|
384
|
+
}
|
|
327
385
|
return out;
|
|
328
386
|
}
|
|
329
387
|
var antigravity = {
|
|
@@ -331,34 +389,49 @@ var antigravity = {
|
|
|
331
389
|
events: AG_EVENTS,
|
|
332
390
|
detect: (env = process.env) => existsSync2(path4.join(gemini(env), "config")) || dataDirs(env).some((d) => existsSync2(d)),
|
|
333
391
|
configFiles: (env = process.env) => [hooksFile(env)],
|
|
334
|
-
install(cmd, env = process.env) {
|
|
392
|
+
install(cmd, env = process.env, opts = {}) {
|
|
335
393
|
const file = hooksFile(env);
|
|
336
|
-
const
|
|
337
|
-
|
|
394
|
+
const f = readJsonFile(file);
|
|
395
|
+
if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];
|
|
396
|
+
const hooks = f.value;
|
|
397
|
+
const e = entry(cmd, opts.lean);
|
|
338
398
|
if (JSON.stringify(hooks[HOOK_NAME]) === JSON.stringify(e)) return [{ file, changed: false }];
|
|
339
399
|
hooks[HOOK_NAME] = e;
|
|
340
400
|
mkdirSync2(path4.dirname(file), { recursive: true });
|
|
341
|
-
writeFileSync2(file,
|
|
342
|
-
`);
|
|
401
|
+
writeFileSync2(file, formatJson(hooks, f));
|
|
343
402
|
return [
|
|
344
|
-
{
|
|
403
|
+
{
|
|
404
|
+
file,
|
|
405
|
+
changed: true,
|
|
406
|
+
created: !f.existed,
|
|
407
|
+
note: "hooks.json is read when a conversation starts; open ones report after a restart"
|
|
408
|
+
}
|
|
345
409
|
];
|
|
346
410
|
},
|
|
347
|
-
uninstall(env = process.env) {
|
|
411
|
+
uninstall(env = process.env, opts = {}) {
|
|
348
412
|
const file = hooksFile(env);
|
|
349
413
|
if (!existsSync2(file)) return [{ file, changed: false }];
|
|
350
|
-
const
|
|
414
|
+
const f = readJsonFile(file);
|
|
415
|
+
if (!f.ok) return [{ file, changed: false, skipped: true, note: `${f.reason}; not touched` }];
|
|
416
|
+
const hooks = f.value;
|
|
351
417
|
if (!(HOOK_NAME in hooks)) return [{ file, changed: false }];
|
|
352
418
|
delete hooks[HOOK_NAME];
|
|
353
|
-
|
|
354
|
-
|
|
419
|
+
if (opts.created?.includes(file) && !Object.keys(hooks).length) {
|
|
420
|
+
unlinkSync2(file);
|
|
421
|
+
return [{ file, changed: true, note: "removed (sessionpipe created it)" }];
|
|
422
|
+
}
|
|
423
|
+
writeFileSync2(file, formatJson(hooks, f));
|
|
355
424
|
return [{ file, changed: true }];
|
|
356
425
|
},
|
|
357
|
-
installed(cmd, env = process.env) {
|
|
426
|
+
installed(cmd, env = process.env, opts = {}) {
|
|
358
427
|
const file = hooksFile(env);
|
|
359
|
-
const
|
|
428
|
+
const f = readJsonFile(file);
|
|
429
|
+
const have = f.ok ? f.value[HOOK_NAME] : void 0;
|
|
360
430
|
return [
|
|
361
|
-
{
|
|
431
|
+
{
|
|
432
|
+
file,
|
|
433
|
+
state: !have ? "missing" : JSON.stringify(have) === JSON.stringify(entry(cmd, opts.lean)) ? "current" : "stale"
|
|
434
|
+
}
|
|
362
435
|
];
|
|
363
436
|
},
|
|
364
437
|
fromHook(input) {
|
|
@@ -624,8 +697,11 @@ var CLAUDE_EVENTS = [
|
|
|
624
697
|
"SubagentStop",
|
|
625
698
|
"PreCompact",
|
|
626
699
|
"PostCompact",
|
|
627
|
-
"SessionEnd"
|
|
700
|
+
"SessionEnd",
|
|
701
|
+
"StopFailure"
|
|
628
702
|
];
|
|
703
|
+
var LEAN_SKIP = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUseFailure"]);
|
|
704
|
+
var eventsFor = (lean) => lean ? CLAUDE_EVENTS.filter((e) => !LEAN_SKIP.has(e)) : [...CLAUDE_EVENTS];
|
|
629
705
|
var OPTS = { matcherFor: (e) => /Tool|Permission/.test(e) ? "" : void 0, timeout: 5 };
|
|
630
706
|
var DESKTOP_ID = /^local_[A-Za-z0-9-]{1,64}$/;
|
|
631
707
|
function claudeDirs(env = process.env, home = HOME) {
|
|
@@ -657,11 +733,13 @@ var claudeCode = {
|
|
|
657
733
|
events: CLAUDE_EVENTS,
|
|
658
734
|
detect: (env = process.env) => claudeDirs(env).some((d) => existsSync3(d)),
|
|
659
735
|
configFiles: (env = process.env) => claudeDirs(env).map(settingsIn),
|
|
660
|
-
install: (cmd, env = process.env) => claudeDirs(env).map((d) => installClaudeShaped(settingsIn(d), NAME2,
|
|
661
|
-
uninstall: (env = process.env) => claudeDirs(env).map(
|
|
662
|
-
|
|
736
|
+
install: (cmd, env = process.env, opts = {}) => claudeDirs(env).map((d) => installClaudeShaped(settingsIn(d), NAME2, eventsFor(opts.lean), cmd, OPTS)),
|
|
737
|
+
uninstall: (env = process.env, opts = {}) => claudeDirs(env).map(
|
|
738
|
+
(d) => uninstallClaudeShaped(settingsIn(d), CLAUDE_EVENTS, { created: opts.created?.includes(settingsIn(d)) })
|
|
739
|
+
),
|
|
740
|
+
installed: (cmd, env = process.env, opts = {}) => claudeDirs(env).map((d) => ({
|
|
663
741
|
file: settingsIn(d),
|
|
664
|
-
state: installedClaudeShaped(settingsIn(d), NAME2,
|
|
742
|
+
state: installedClaudeShaped(settingsIn(d), NAME2, eventsFor(opts.lean), cmd, OPTS)
|
|
665
743
|
})),
|
|
666
744
|
fromHook(input) {
|
|
667
745
|
const event = input.argv[1] ?? "";
|
|
@@ -752,6 +830,15 @@ var claudeCode = {
|
|
|
752
830
|
case "Stop":
|
|
753
831
|
events.push(ev("turn.ended", { turn_id, reason: "stop" }));
|
|
754
832
|
break;
|
|
833
|
+
case "StopFailure":
|
|
834
|
+
events.push(
|
|
835
|
+
ev("turn.ended", {
|
|
836
|
+
turn_id,
|
|
837
|
+
reason: "error",
|
|
838
|
+
error: typeof s.error === "string" ? s.error.slice(0, 200) : void 0
|
|
839
|
+
})
|
|
840
|
+
);
|
|
841
|
+
break;
|
|
755
842
|
case "SubagentStart":
|
|
756
843
|
events.push(
|
|
757
844
|
ev("subagent.started", {
|
|
@@ -1263,6 +1350,7 @@ var CODEX_EVENTS = [
|
|
|
1263
1350
|
"SessionEnd"
|
|
1264
1351
|
];
|
|
1265
1352
|
var OPTS2 = { matcherFor: (e) => /Tool|Permission/.test(e) ? "" : void 0, timeout: 5 };
|
|
1353
|
+
var eventsFor2 = (lean) => lean ? CODEX_EVENTS.filter((e) => e !== "PreToolUse") : [...CODEX_EVENTS];
|
|
1266
1354
|
var codexHome = (env) => env.CODEX_HOME || path6.join(HOME, ".codex");
|
|
1267
1355
|
var hooksFile2 = (env) => path6.join(codexHome(env), "hooks.json");
|
|
1268
1356
|
var configFile2 = (env) => path6.join(codexHome(env), "config.toml");
|
|
@@ -1311,7 +1399,8 @@ function installNotify(cmd, env) {
|
|
|
1311
1399
|
return {
|
|
1312
1400
|
file,
|
|
1313
1401
|
changed: false,
|
|
1314
|
-
|
|
1402
|
+
skipped: true,
|
|
1403
|
+
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`
|
|
1315
1404
|
};
|
|
1316
1405
|
}
|
|
1317
1406
|
write(withNotify(text, line));
|
|
@@ -1368,14 +1457,21 @@ var codex = {
|
|
|
1368
1457
|
events: CODEX_EVENTS,
|
|
1369
1458
|
detect: (env = process.env) => existsSync4(codexHome(env)),
|
|
1370
1459
|
configFiles: (env = process.env) => [hooksFile2(env), configFile2(env)],
|
|
1371
|
-
install: (cmd, env = process.env) => [
|
|
1372
|
-
installClaudeShaped(hooksFile2(env), NAME3,
|
|
1460
|
+
install: (cmd, env = process.env, opts = {}) => [
|
|
1461
|
+
installClaudeShaped(hooksFile2(env), NAME3, eventsFor2(opts.lean), cmd, OPTS2),
|
|
1373
1462
|
installNotify(cmd, env)
|
|
1374
1463
|
],
|
|
1375
|
-
uninstall: (env = process.env) => [
|
|
1376
|
-
|
|
1464
|
+
uninstall: (env = process.env, opts = {}) => [
|
|
1465
|
+
uninstallClaudeShaped(hooksFile2(env), CODEX_EVENTS, { created: opts.created?.includes(hooksFile2(env)) }),
|
|
1466
|
+
uninstallNotify(env)
|
|
1467
|
+
],
|
|
1468
|
+
installed: (cmd, env = process.env, opts = {}) => {
|
|
1377
1469
|
const out = [
|
|
1378
|
-
{
|
|
1470
|
+
{
|
|
1471
|
+
file: hooksFile2(env),
|
|
1472
|
+
state: installedClaudeShaped(hooksFile2(env), NAME3, eventsFor2(opts.lean), cmd, OPTS2),
|
|
1473
|
+
note: "Codex runs non-managed hooks only after the review in `codex` (/hooks); until then nothing is reported unless the notify fallback is ours"
|
|
1474
|
+
}
|
|
1379
1475
|
];
|
|
1380
1476
|
let text = "";
|
|
1381
1477
|
try {
|
|
@@ -1563,6 +1659,7 @@ function codexFacts(file) {
|
|
|
1563
1659
|
}
|
|
1564
1660
|
|
|
1565
1661
|
// src/adapters/gemini-cli.ts
|
|
1662
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1566
1663
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
1567
1664
|
import path7 from "node:path";
|
|
1568
1665
|
var NAME4 = "gemini-cli";
|
|
@@ -1580,17 +1677,61 @@ var OPTS3 = { matcherFor: (e) => /Tool/.test(e) ? ".*" : void 0, timeout: 5e3 };
|
|
|
1580
1677
|
var geminiDir = (env) => env.GEMINI_CLI_HOME || path7.join(HOME, ".gemini");
|
|
1581
1678
|
var settings = (env) => path7.join(geminiDir(env), "settings.json");
|
|
1582
1679
|
var validTool4 = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
|
|
1680
|
+
var eventsFor3 = (lean) => lean ? GEMINI_EVENTS.filter((e) => e !== "BeforeTool") : [...GEMINI_EVENTS];
|
|
1681
|
+
function geminiHooksActive(settingsFile) {
|
|
1682
|
+
let tools;
|
|
1683
|
+
try {
|
|
1684
|
+
tools = JSON.parse(readFileSync5(settingsFile, "utf8")).tools;
|
|
1685
|
+
} catch {
|
|
1686
|
+
}
|
|
1687
|
+
if (tools?.enableHooks === true) return { active: true };
|
|
1688
|
+
if (tools?.enableHooks === false)
|
|
1689
|
+
return { active: false, note: "inactive: tools.enableHooks is false in settings.json" };
|
|
1690
|
+
let version = "";
|
|
1691
|
+
try {
|
|
1692
|
+
version = execFileSync3("gemini", ["--version"], {
|
|
1693
|
+
encoding: "utf8",
|
|
1694
|
+
timeout: 4e3,
|
|
1695
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1696
|
+
}).trim();
|
|
1697
|
+
} catch {
|
|
1698
|
+
return {
|
|
1699
|
+
active: true,
|
|
1700
|
+
note: "could not run `gemini --version`; hooks need tools.enableHooks on versions before 0.46"
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
const m = /(\d+)\.(\d+)/.exec(version);
|
|
1704
|
+
if (m && (Number(m[1]) > 0 || Number(m[2]) >= 46)) return { active: true };
|
|
1705
|
+
return {
|
|
1706
|
+
active: false,
|
|
1707
|
+
note: `inactive: Gemini CLI ${version || "?"} runs hooks only with "tools": {"enableHooks": true} in settings.json`
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1583
1710
|
var geminiCli = {
|
|
1584
1711
|
name: NAME4,
|
|
1585
1712
|
events: GEMINI_EVENTS,
|
|
1586
1713
|
// ~/.gemini also belongs to Antigravity; Gemini CLI is here when its settings or its chat logs exist.
|
|
1587
1714
|
detect: (env = process.env) => existsSync5(settings(env)) || existsSync5(path7.join(geminiDir(env), "tmp")),
|
|
1588
1715
|
configFiles: (env = process.env) => [settings(env)],
|
|
1589
|
-
install: (cmd, env = process.env
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1716
|
+
install: (cmd, env = process.env, opts = {}) => {
|
|
1717
|
+
const r = installClaudeShaped(settings(env), NAME4, eventsFor3(opts.lean), cmd, OPTS3);
|
|
1718
|
+
const a = geminiHooksActive(settings(env));
|
|
1719
|
+
return [a.note && !r.skipped ? { ...r, note: [r.note, a.note].filter(Boolean).join("; ") } : r];
|
|
1720
|
+
},
|
|
1721
|
+
uninstall: (env = process.env, opts = {}) => [
|
|
1722
|
+
uninstallClaudeShaped(settings(env), GEMINI_EVENTS, { created: opts.created?.includes(settings(env)) })
|
|
1593
1723
|
],
|
|
1724
|
+
installed: (cmd, env = process.env, opts = {}) => {
|
|
1725
|
+
const state = installedClaudeShaped(settings(env), NAME4, eventsFor3(opts.lean), cmd, OPTS3);
|
|
1726
|
+
const a = geminiHooksActive(settings(env));
|
|
1727
|
+
return [
|
|
1728
|
+
{
|
|
1729
|
+
file: settings(env),
|
|
1730
|
+
state: state === "current" && !a.active ? "inactive" : state,
|
|
1731
|
+
...a.note ? { note: a.note } : {}
|
|
1732
|
+
}
|
|
1733
|
+
];
|
|
1734
|
+
},
|
|
1594
1735
|
fromHook(input) {
|
|
1595
1736
|
const event = input.argv[1] ?? "";
|
|
1596
1737
|
let s = {};
|
|
@@ -1802,7 +1943,7 @@ import {
|
|
|
1802
1943
|
readSync as readSync2,
|
|
1803
1944
|
renameSync,
|
|
1804
1945
|
statSync as statSync4,
|
|
1805
|
-
unlinkSync,
|
|
1946
|
+
unlinkSync as unlinkSync3,
|
|
1806
1947
|
writeFileSync as writeFileSync5
|
|
1807
1948
|
} from "node:fs";
|
|
1808
1949
|
import path9 from "node:path";
|
|
@@ -1830,8 +1971,8 @@ var Outbox = class {
|
|
|
1830
1971
|
} catch {
|
|
1831
1972
|
n = this.lastSeqInFile(ref) + 1;
|
|
1832
1973
|
}
|
|
1833
|
-
mkdirSync5(path9.dirname(f), { recursive: true });
|
|
1834
|
-
writeFileSync5(f, String(n + 1));
|
|
1974
|
+
mkdirSync5(path9.dirname(f), { recursive: true, mode: 448 });
|
|
1975
|
+
writeFileSync5(f, String(n + 1), { mode: 384 });
|
|
1835
1976
|
return n;
|
|
1836
1977
|
}
|
|
1837
1978
|
lastSeqInFile(ref) {
|
|
@@ -1849,9 +1990,9 @@ var Outbox = class {
|
|
|
1849
1990
|
}
|
|
1850
1991
|
append(ref, events) {
|
|
1851
1992
|
if (!events.length) return;
|
|
1852
|
-
mkdirSync5(this.dir(ref.harness), { recursive: true });
|
|
1993
|
+
mkdirSync5(this.dir(ref.harness), { recursive: true, mode: 448 });
|
|
1853
1994
|
appendFileSync(this.file(ref), `${events.map((e) => JSON.stringify(e)).join("\n")}
|
|
1854
|
-
|
|
1995
|
+
`, { mode: 384 });
|
|
1855
1996
|
}
|
|
1856
1997
|
/** Every session file, newest first. */
|
|
1857
1998
|
sessions() {
|
|
@@ -1915,9 +2056,9 @@ var Outbox = class {
|
|
|
1915
2056
|
const f = this.file(ref);
|
|
1916
2057
|
try {
|
|
1917
2058
|
if (statSync4(f).mtimeMs < cutoff) {
|
|
1918
|
-
|
|
2059
|
+
unlinkSync3(f);
|
|
1919
2060
|
try {
|
|
1920
|
-
|
|
2061
|
+
unlinkSync3(this.seqFile(ref));
|
|
1921
2062
|
} catch {
|
|
1922
2063
|
}
|
|
1923
2064
|
n++;
|
|
@@ -1930,7 +2071,7 @@ var Outbox = class {
|
|
|
1930
2071
|
delete(ref) {
|
|
1931
2072
|
for (const f of [this.file(ref), this.seqFile(ref)]) {
|
|
1932
2073
|
try {
|
|
1933
|
-
|
|
2074
|
+
unlinkSync3(f);
|
|
1934
2075
|
} catch {
|
|
1935
2076
|
}
|
|
1936
2077
|
}
|
|
@@ -1955,9 +2096,9 @@ var Cursors = class {
|
|
|
1955
2096
|
}
|
|
1956
2097
|
write(c) {
|
|
1957
2098
|
const f = this.file();
|
|
1958
|
-
mkdirSync5(path9.dirname(f), { recursive: true });
|
|
2099
|
+
mkdirSync5(path9.dirname(f), { recursive: true, mode: 448 });
|
|
1959
2100
|
const tmp = `${f}.${process.pid}.tmp`;
|
|
1960
|
-
writeFileSync5(tmp, JSON.stringify(c));
|
|
2101
|
+
writeFileSync5(tmp, JSON.stringify(c), { mode: 384 });
|
|
1961
2102
|
renameSync(tmp, f);
|
|
1962
2103
|
}
|
|
1963
2104
|
key(ref) {
|
|
@@ -1966,10 +2107,10 @@ var Cursors = class {
|
|
|
1966
2107
|
};
|
|
1967
2108
|
function takeLock(root, ref, staleMs = 5 * 6e4) {
|
|
1968
2109
|
const dir = path9.join(root, "locks");
|
|
1969
|
-
mkdirSync5(dir, { recursive: true });
|
|
2110
|
+
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
1970
2111
|
const f = path9.join(dir, `${safeId(ref.harness)}-${safeId(ref.session)}.lock`);
|
|
1971
2112
|
try {
|
|
1972
|
-
if (Date.now() - statSync4(f).mtimeMs > staleMs)
|
|
2113
|
+
if (Date.now() - statSync4(f).mtimeMs > staleMs) unlinkSync3(f);
|
|
1973
2114
|
else return null;
|
|
1974
2115
|
} catch {
|
|
1975
2116
|
}
|
|
@@ -1980,7 +2121,7 @@ function takeLock(root, ref, staleMs = 5 * 6e4) {
|
|
|
1980
2121
|
}
|
|
1981
2122
|
return () => {
|
|
1982
2123
|
try {
|
|
1983
|
-
|
|
2124
|
+
unlinkSync3(f);
|
|
1984
2125
|
} catch {
|
|
1985
2126
|
}
|
|
1986
2127
|
};
|
|
@@ -2116,7 +2257,7 @@ function redactAssignments(text) {
|
|
|
2116
2257
|
function isSecretName(name) {
|
|
2117
2258
|
if (/^[A-Z0-9_]+_KEY$/.test(name)) return true;
|
|
2118
2259
|
const flat = name.toLowerCase().replace(/[_-]/g, "");
|
|
2119
|
-
return /(?:pass(?:word|wd|phrase|code)
|
|
2260
|
+
return /(?:pass(?:word|wd|phrase|code)|pwd|secret|secretkey|secretaccesskey|clientsecret|apikey|accesskey|accesstoken|authtoken|refreshtoken|privatekey|token|credential|creds)s?$/.test(
|
|
2120
2261
|
flat
|
|
2121
2262
|
);
|
|
2122
2263
|
}
|
|
@@ -2208,7 +2349,7 @@ var DATA_ALLOW = {
|
|
|
2208
2349
|
"session.backfill": { 0: ["started_at", "last_at", "turns"] },
|
|
2209
2350
|
"session.forgotten": { 0: [] },
|
|
2210
2351
|
"turn.started": { 0: ["turn_id"], 1: ["prompt_chars"] },
|
|
2211
|
-
"turn.ended": { 0: ["turn_id", "reason", "ms"] },
|
|
2352
|
+
"turn.ended": { 0: ["turn_id", "reason", "ms"], 1: ["error"] },
|
|
2212
2353
|
"turn.transcript": { 2: ["turn", "user", "assistant", "at"] },
|
|
2213
2354
|
"tool.started": { 1: ["tool", "call_id", "turn_id", "agent_id"], 3: ["input"] },
|
|
2214
2355
|
"tool.ended": { 1: ["tool", "call_id", "turn_id", "agent_id", "ms", "ok", "error"], 3: ["input", "output"] },
|