clisponsor 1.0.3 → 1.0.5

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.
Files changed (2) hide show
  1. package/bin/clisponsor.mjs +119 -39
  2. package/package.json +1 -1
@@ -130,6 +130,23 @@ function chmodExecutable(file) {
130
130
  }
131
131
 
132
132
  function commandExists(command) {
133
+ const paths = String(process.env.PATH || "").split(path.delimiter).filter(Boolean);
134
+ const extensions = process.platform === "win32" ? String(process.env.PATHEXT || ".EXE;.CMD;.BAT").split(";") : [""];
135
+ for (const directory of paths) {
136
+ for (const extension of extensions) {
137
+ const candidate = path.join(directory, command + extension.toLowerCase());
138
+ try {
139
+ fs.accessSync(candidate, fs.constants.X_OK);
140
+ return true;
141
+ } catch {}
142
+ if (extension) {
143
+ try {
144
+ fs.accessSync(path.join(directory, command + extension.toUpperCase()), fs.constants.X_OK);
145
+ return true;
146
+ } catch {}
147
+ }
148
+ }
149
+ }
133
150
  try {
134
151
  execFileSync(command, ["--version"], { stdio: "ignore" });
135
152
  return true;
@@ -140,14 +157,15 @@ function commandExists(command) {
140
157
 
141
158
  function isClisponsorCommand(value) {
142
159
  return (
143
- typeof value === "string" &&
144
- (value.includes("clisponsor_claude_hook.mjs") ||
145
- value.includes("clisponsor_gemini_hook.mjs") ||
146
- value.includes(`${path.sep}.clisponsor${path.sep}`) ||
147
- value.includes("/.clisponsor/") ||
148
- value.includes("\\.clisponsor\\"))
149
- );
150
- }
160
+ typeof value === "string" &&
161
+ (value.includes("clisponsor_claude_hook.mjs") ||
162
+ value.includes("clisponsor_gemini_hook.mjs") ||
163
+ value.includes("clisponsor_antigravity_hook.mjs") ||
164
+ value.includes(`${path.sep}.clisponsor${path.sep}`) ||
165
+ value.includes("/.clisponsor/") ||
166
+ value.includes("\\.clisponsor\\"))
167
+ );
168
+ }
151
169
 
152
170
  function isClisponsorHookEntry(entry) {
153
171
  if (!isPlainObject(entry)) return false;
@@ -299,6 +317,11 @@ async function login() {
299
317
  }
300
318
 
301
319
  function installCodex() {
320
+ if (!commandExists("codex")) {
321
+ console.log("Codex CLI not found. To enable CLIsponsor for Codex, install Codex CLI and rerun: npx clisponsor@latest install");
322
+ return;
323
+ }
324
+
302
325
  const pluginRoot = path.join(CONFIG_DIR, "codex-plugin");
303
326
  copyDir(path.join(ROOT, "templates", "codex-plugin"), pluginRoot);
304
327
  patchFile(path.join(pluginRoot, "hooks", "hooks.json"), {
@@ -328,29 +351,23 @@ function installCodex() {
328
351
  },
329
352
  ],
330
353
  });
331
- try {
332
- execFileSync("codex", ["plugin", "marketplace", "add", marketplaceRoot], { stdio: "ignore" });
333
- } catch {}
334
- try {
335
- execFileSync("codex", ["plugin", "add", "clisponsor@clisponsor-local"], { stdio: "ignore" });
336
- console.log("Codex CLI plugin installed.");
337
- } catch {
338
- console.log("Codex CLI plugin staged. After installing Codex CLI, rerun: npx clisponsor install");
339
- }
354
+ execFileSync("codex", ["plugin", "marketplace", "add", marketplaceRoot], { stdio: "ignore" });
355
+ execFileSync("codex", ["plugin", "add", "clisponsor@clisponsor-local"], { stdio: "ignore" });
356
+ console.log("Codex CLI plugin installed.");
340
357
  }
341
358
 
342
359
  function installClaude() {
360
+ if (!commandExists("claude")) {
361
+ console.log("Claude Code CLI not found. To enable CLIsponsor for Claude Code, install Claude Code CLI and rerun: npx clisponsor@latest install");
362
+ return;
363
+ }
364
+
343
365
  const claudeDir = path.join(CONFIG_DIR, "claude");
344
366
  const installedHook = path.join(claudeDir, "clisponsor_claude_hook.mjs");
345
367
  fs.mkdirSync(claudeDir, { recursive: true });
346
368
  fs.copyFileSync(path.join(ROOT, "templates", "claude", "clisponsor_claude_hook.mjs"), installedHook);
347
369
  chmodExecutable(installedHook);
348
370
 
349
- if (!commandExists("claude")) {
350
- console.log("Claude Code CLI hook staged. After installing Claude Code CLI, rerun: npx clisponsor install");
351
- return;
352
- }
353
-
354
371
  const settingsPath = path.join(HOME, ".claude", "settings.json");
355
372
  const settings = readEditableJson(settingsPath, {});
356
373
  addClaudeCommandHook(settings, "SessionStart", `node ${JSON.stringify(installedHook)} SessionStart`);
@@ -361,13 +378,15 @@ function installClaude() {
361
378
  console.log("Claude Code CLI hook installed.");
362
379
  }
363
380
 
364
- function geminiHookSource() {
381
+ function agentHookSource(client, options = {}) {
382
+ const outputMode = options.outputMode || "systemMessage";
365
383
  return `#!/usr/bin/env node
366
384
  import fs from "node:fs";
367
385
  import crypto from "node:crypto";
368
386
  const cfg = JSON.parse(fs.readFileSync(${JSON.stringify(CONFIG_PATH)}, "utf8"));
369
387
  const event = process.argv[2] || "BeforeAgent";
370
- const placements = { SessionStart: "StartSession", BeforeAgent: "StartTurn", AfterAgent: "EndTurn", StartTurn: "StartTurn" };
388
+ const outputMode = ${JSON.stringify(outputMode)};
389
+ const placements = { SessionStart: "StartSession", PreInvocation: "StartSession", BeforeAgent: "StartTurn", UserPromptSubmit: "StartTurn", PreToolUse: "StartTurn", AfterAgent: "EndTurn", PostInvocation: "EndTurn", Stop: "EndTurn", StartTurn: "StartTurn" };
371
390
  const serveBaseUrl = cfg.serveBaseUrl || cfg.apiBaseUrl;
372
391
  function sponsoredLine(line) {
373
392
  return "[Sponsored] " + line;
@@ -383,7 +402,7 @@ await readStdin();
383
402
  try {
384
403
  if (!serveBaseUrl || !cfg.userId || !cfg.deviceCode || !cfg.deviceSecret) process.exit(0);
385
404
  const placement = placements[event] || event;
386
- const body = { user_id: cfg.userId, device_code: cfg.deviceCode, client: "Gemini", hook_event: event, placement, idempotency_key: crypto.randomUUID(), metadata: { hookVersion: ${JSON.stringify(HOOK_VERSION)} } };
405
+ const body = { user_id: cfg.userId, device_code: cfg.deviceCode, client: ${JSON.stringify(client)}, hook_event: event, placement, idempotency_key: crypto.randomUUID(), metadata: { hookVersion: ${JSON.stringify(HOOK_VERSION)} } };
387
406
  const res = await fetch(serveBaseUrl + "/v1/ads/serve", {
388
407
  method: "POST",
389
408
  headers: {
@@ -395,7 +414,13 @@ try {
395
414
  });
396
415
  if (res.ok) {
397
416
  const ad = await res.json();
398
- if (ad.display_line) console.log(JSON.stringify({ systemMessage: sponsoredLine(ad.display_line) }));
417
+ if (outputMode === "antigravity") {
418
+ const payload = { decision: "allow" };
419
+ if (ad.display_line) payload.systemMessage = sponsoredLine(ad.display_line);
420
+ console.log(JSON.stringify(payload));
421
+ } else if (ad.display_line) {
422
+ console.log(JSON.stringify({ systemMessage: sponsoredLine(ad.display_line) }));
423
+ }
399
424
  }
400
425
  } catch {
401
426
  process.exit(0);
@@ -405,14 +430,14 @@ try {
405
430
 
406
431
  function installGemini() {
407
432
  if (!commandExists("gemini")) {
408
- console.log("Gemini CLI not found. To enable CLIsponsor for Gemini, install Gemini CLI and rerun: npx clisponsor install");
433
+ console.log("Gemini CLI not found. To enable CLIsponsor for Gemini, install Gemini CLI and rerun: npx clisponsor@latest install");
409
434
  return;
410
435
  }
411
436
 
412
437
  const geminiDir = path.join(CONFIG_DIR, "gemini");
413
438
  fs.mkdirSync(geminiDir, { recursive: true });
414
439
  const hookPath = path.join(geminiDir, "clisponsor_gemini_hook.mjs");
415
- fs.writeFileSync(hookPath, geminiHookSource(), { mode: 0o755 });
440
+ fs.writeFileSync(hookPath, agentHookSource("Gemini"), { mode: 0o755 });
416
441
 
417
442
  const settingsPath = path.join(HOME, ".gemini", "settings.json");
418
443
  const settings = readEditableJson(settingsPath, {});
@@ -424,10 +449,46 @@ function installGemini() {
424
449
  console.log("Gemini CLI hook installed.");
425
450
  }
426
451
 
452
+ function installAntigravity() {
453
+ if (!commandExists("agy")) {
454
+ console.log("Antigravity CLI not found. To enable CLIsponsor for Antigravity, install Antigravity CLI and rerun: npx clisponsor@latest install");
455
+ return;
456
+ }
457
+
458
+ const antigravityDir = path.join(CONFIG_DIR, "antigravity");
459
+ fs.mkdirSync(antigravityDir, { recursive: true });
460
+ const hookPath = path.join(antigravityDir, "clisponsor_antigravity_hook.mjs");
461
+ fs.writeFileSync(hookPath, agentHookSource("Antigravity", { outputMode: "antigravity" }), { mode: 0o755 });
462
+
463
+ const hooksPath = path.join(HOME, ".gemini", "config", "hooks.json");
464
+ const hooksConfig = readEditableJson(hooksPath, {});
465
+ addGeminiCommandHook(hooksConfig, "PreInvocation", "*", `node ${JSON.stringify(hookPath)} PreInvocation`);
466
+ addGeminiCommandHook(hooksConfig, "UserPromptSubmit", "*", `node ${JSON.stringify(hookPath)} UserPromptSubmit`);
467
+ addGeminiCommandHook(hooksConfig, "PostInvocation", "*", `node ${JSON.stringify(hookPath)} PostInvocation`);
468
+ addGeminiCommandHook(hooksConfig, "Stop", "*", `node ${JSON.stringify(hookPath)} Stop`);
469
+ writeJson(hooksPath, hooksConfig);
470
+ console.log(`Updated ${hooksPath}`);
471
+ console.log("Antigravity CLI hook installed.");
472
+ }
473
+
427
474
  function installAll() {
428
475
  installCodex();
429
476
  installClaude();
430
477
  installGemini();
478
+ installAntigravity();
479
+ }
480
+
481
+ function install() {
482
+ const target = process.argv[3] && !process.argv[3].startsWith("--") ? process.argv[3] : "all";
483
+ if (!["all", "codex", "claude", "gemini", "antigravity", "agy"].includes(target)) {
484
+ console.error("Unknown install target. Use: codex, claude, gemini, antigravity, or all.");
485
+ process.exit(1);
486
+ }
487
+ if (target === "all") installAll();
488
+ else if (target === "codex") installCodex();
489
+ else if (target === "claude") installClaude();
490
+ else if (target === "gemini") installGemini();
491
+ else installAntigravity();
431
492
  }
432
493
 
433
494
  function uninstallCodex() {
@@ -464,15 +525,32 @@ function uninstallGemini() {
464
525
  console.log("Removed Gemini hook script.");
465
526
  }
466
527
 
528
+ function uninstallAntigravity() {
529
+ const hooksPath = path.join(HOME, ".gemini", "config", "hooks.json");
530
+ const hooksConfig = readEditableJson(hooksPath, {});
531
+ if (removeClaudeCommandHooks(hooksConfig)) {
532
+ writeJson(hooksPath, hooksConfig);
533
+ console.log(`Removed CLIsponsor hooks from ${hooksPath}`);
534
+ } else {
535
+ console.log("No CLIsponsor Antigravity hooks found.");
536
+ }
537
+ fs.rmSync(path.join(CONFIG_DIR, "antigravity", "clisponsor_antigravity_hook.mjs"), { force: true });
538
+ try {
539
+ fs.rmdirSync(path.join(CONFIG_DIR, "antigravity"));
540
+ } catch {}
541
+ console.log("Removed Antigravity hook script.");
542
+ }
543
+
467
544
  function uninstall() {
468
545
  const target = process.argv[3] && !process.argv[3].startsWith("--") ? process.argv[3] : "all";
469
- if (!["all", "codex", "claude", "gemini"].includes(target)) {
470
- console.error("Unknown uninstall target. Use: codex, claude, gemini, or all.");
546
+ if (!["all", "codex", "claude", "gemini", "antigravity", "agy"].includes(target)) {
547
+ console.error("Unknown uninstall target. Use: codex, claude, gemini, antigravity, or all.");
471
548
  process.exit(1);
472
549
  }
473
550
  if (target === "all" || target === "codex") uninstallCodex();
474
551
  if (target === "all" || target === "claude") uninstallClaude();
475
552
  if (target === "all" || target === "gemini") uninstallGemini();
553
+ if (target === "all" || target === "antigravity" || target === "agy") uninstallAntigravity();
476
554
  if (hasFlag("--config")) {
477
555
  fs.rmSync(CONFIG_PATH, { force: true });
478
556
  console.log(`Removed ${CONFIG_PATH}`);
@@ -526,12 +604,13 @@ async function doctor() {
526
604
  email: cfg.email || null,
527
605
  userId: cfg.userId || null,
528
606
  deviceCode: cfg.deviceCode || null,
529
- installed: {
530
- codexPluginStaged: fs.existsSync(path.join(CONFIG_DIR, "codex-marketplace", "plugins", "clisponsor")),
531
- claudeSettings: fs.existsSync(path.join(HOME, ".claude", "settings.json")),
532
- claudeHookScript: fs.existsSync(path.join(CONFIG_DIR, "claude", "clisponsor_claude_hook.mjs")),
533
- geminiHookScript: fs.existsSync(path.join(CONFIG_DIR, "gemini", "clisponsor_gemini_hook.mjs")),
534
- },
607
+ installed: {
608
+ codexPluginStaged: fs.existsSync(path.join(CONFIG_DIR, "codex-marketplace", "plugins", "clisponsor")),
609
+ claudeSettings: fs.existsSync(path.join(HOME, ".claude", "settings.json")),
610
+ claudeHookScript: fs.existsSync(path.join(CONFIG_DIR, "claude", "clisponsor_claude_hook.mjs")),
611
+ geminiHookScript: fs.existsSync(path.join(CONFIG_DIR, "gemini", "clisponsor_gemini_hook.mjs")),
612
+ antigravityHookScript: fs.existsSync(path.join(CONFIG_DIR, "antigravity", "clisponsor_antigravity_hook.mjs")),
613
+ },
535
614
  network: {},
536
615
  };
537
616
 
@@ -557,6 +636,7 @@ async function doctor() {
557
636
  console.log(`Claude settings: ${diagnostics.installed.claudeSettings ? "yes" : "no"}`);
558
637
  console.log(`Claude hook script: ${diagnostics.installed.claudeHookScript ? "yes" : "no"}`);
559
638
  console.log(`Gemini hook script: ${diagnostics.installed.geminiHookScript ? "yes" : "no"}`);
639
+ console.log(`Antigravity hook script: ${diagnostics.installed.antigravityHookScript ? "yes" : "no"}`);
560
640
  if (skipNetwork) {
561
641
  console.log("Network: skipped");
562
642
  } else {
@@ -567,9 +647,9 @@ async function doctor() {
567
647
 
568
648
  function help() {
569
649
  console.log(`clisponsor commands:
570
- clisponsor install
650
+ clisponsor install [all|codex|claude|gemini|antigravity]
571
651
  clisponsor login <email> [--label=<device-label>]
572
- clisponsor uninstall [--config]
652
+ clisponsor uninstall [all|codex|claude|gemini|antigravity] [--config]
573
653
  clisponsor status
574
654
  clisponsor doctor [--json] [--skip-network]
575
655
 
@@ -579,7 +659,7 @@ Environment:
579
659
 
580
660
  const command = process.argv[2] || "help";
581
661
  if (command === "login") await login();
582
- else if (command === "install" && (!process.argv[3] || process.argv[3] === "all")) installAll();
662
+ else if (command === "install") install();
583
663
  else if (command === "uninstall") uninstall();
584
664
  else if (command === "status") await status();
585
665
  else if (command === "doctor") await doctor();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clisponsor",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "CLIsponsor installer for Codex, Claude Code, and Gemini sponsored CLI placements.",
5
5
  "type": "module",
6
6
  "engines": {