clisponsor 1.0.17 → 1.0.20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # CLIsponsor Hook
2
2
 
3
- Hook package codebase for the `clisponsor` installer and Codex, Claude Code, Gemini, Antigravity, OpenCode, Pi, GitHub Copilot CLI, and Qwen Code hook templates.
3
+ Hook package codebase for the `clisponsor` installer and Codex, Claude Code, Gemini, Antigravity, OpenCode, Pi, GitHub Copilot CLI, Qwen Code, Factory Droid, and Devin hook templates.
4
4
 
5
5
  This codebase owns local installation, device login, diagnostics, and hook adapters. It must not contain public website, dashboard app, API account, or ad-serving server code.
6
6
 
@@ -170,6 +170,14 @@ function qwenHome() {
170
170
  return process.env.QWEN_HOME || path.join(HOME, ".qwen");
171
171
  }
172
172
 
173
+ function factoryHome() {
174
+ return process.env.FACTORY_HOME || path.join(HOME, ".factory");
175
+ }
176
+
177
+ function devinConfigPath() {
178
+ return process.env.DEVIN_CONFIG_PATH || path.join(xdgConfigHome(), "devin", "config.json");
179
+ }
180
+
173
181
  function colorEnabled() {
174
182
  return Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
175
183
  }
@@ -269,6 +277,8 @@ function isClisponsorCommand(value) {
269
277
  value.includes("clisponsor_pi_extension") ||
270
278
  value.includes("clisponsor_copilot_hook.mjs") ||
271
279
  value.includes("clisponsor_qwen_hook.mjs") ||
280
+ value.includes("clisponsor_droid_hook.mjs") ||
281
+ value.includes("clisponsor_devin_hook.mjs") ||
272
282
  value.includes(`${path.sep}.clisponsor${path.sep}`) ||
273
283
  value.includes("/.clisponsor/") ||
274
284
  value.includes("\\.clisponsor\\"))
@@ -364,6 +374,51 @@ function addQwenCommandHook(settings, eventName, command) {
364
374
  return true;
365
375
  }
366
376
 
377
+ function addDroidCommandHook(settings, eventName, command) {
378
+ if (!isPlainObject(settings.hooks)) settings.hooks = {};
379
+ const current = Array.isArray(settings.hooks[eventName]) ? settings.hooks[eventName] : [];
380
+ const exists = current.some((entry) => isClisponsorHookEntry(entry));
381
+ if (exists) return false;
382
+
383
+ settings.hooks[eventName] = [
384
+ ...current,
385
+ {
386
+ hooks: [
387
+ {
388
+ type: "command",
389
+ command,
390
+ name: "clisponsor",
391
+ timeout: 5,
392
+ },
393
+ ],
394
+ },
395
+ ];
396
+ return true;
397
+ }
398
+
399
+ function addDevinCommandHook(settings, eventName, command) {
400
+ if (!isPlainObject(settings.hooks)) settings.hooks = {};
401
+ const current = Array.isArray(settings.hooks[eventName]) ? settings.hooks[eventName] : [];
402
+ const exists = current.some((entry) => isClisponsorHookEntry(entry));
403
+ if (exists) return false;
404
+
405
+ settings.hooks[eventName] = [
406
+ ...current,
407
+ {
408
+ matcher: "",
409
+ hooks: [
410
+ {
411
+ type: "command",
412
+ command,
413
+ name: "clisponsor",
414
+ timeout: 5,
415
+ },
416
+ ],
417
+ },
418
+ ];
419
+ return true;
420
+ }
421
+
367
422
  function removeClaudeCommandHooks(settings) {
368
423
  if (!isPlainObject(settings.hooks)) return false;
369
424
  let changed = false;
@@ -540,11 +595,17 @@ const event = process.argv[2] || "BeforeAgent";
540
595
  const outputMode = ${JSON.stringify(outputMode)};
541
596
  const placements = { SessionStart: "StartSession", PreInvocation: "StartTurn", BeforeAgent: "StartTurn", UserPromptSubmit: "StartTurn", PreToolUse: "StartTurn", AfterAgent: "EndTurn", PostInvocation: "EndTurn", Stop: "EndTurn", StartTurn: "StartTurn" };
542
597
  function writeNoop() {
543
- if (outputMode === "antigravity") console.log(JSON.stringify({}));
598
+ if (outputMode === "antigravity" || outputMode === "terminalMessage") console.log(JSON.stringify({}));
544
599
  }
545
600
  function sponsoredLine(line) {
546
601
  return "[Sponsored] " + line;
547
602
  }
603
+ function writeTerminalMessage(message) {
604
+ const target = process.env.CLISPONSOR_TTY_MESSAGE_PATH || "/dev/tty";
605
+ try {
606
+ fs.appendFileSync(target, "\\nCLIsponsor Message: " + message + "\\n");
607
+ } catch {}
608
+ }
548
609
  function readStdin() {
549
610
  return new Promise((resolve) => {
550
611
  let data = "";
@@ -597,6 +658,9 @@ try {
597
658
  const payload = {};
598
659
  if (ad.display_line) payload.injectSteps = [{ userMessage: sponsoredLine(ad.display_line) }];
599
660
  console.log(JSON.stringify(payload));
661
+ } else if (outputMode === "terminalMessage") {
662
+ if (ad.display_line) writeTerminalMessage(sponsoredLine(ad.display_line));
663
+ console.log(JSON.stringify({}));
600
664
  } else if (ad.display_line) {
601
665
  console.log(JSON.stringify({ systemMessage: sponsoredLine(ad.display_line) }));
602
666
  }
@@ -1003,7 +1067,7 @@ function installQwen() {
1003
1067
  const qwenDir = path.join(CONFIG_DIR, "qwen");
1004
1068
  fs.mkdirSync(qwenDir, { recursive: true });
1005
1069
  const hookPath = path.join(qwenDir, "clisponsor_qwen_hook.mjs");
1006
- fs.writeFileSync(hookPath, agentHookSource("QwenCode"), { mode: 0o755 });
1070
+ fs.writeFileSync(hookPath, agentHookSource("QwenCode", { outputMode: "terminalMessage" }), { mode: 0o755 });
1007
1071
 
1008
1072
  const settingsPath = path.join(qwenHome(), "settings.json");
1009
1073
  const settings = readEditableJson(settingsPath, {});
@@ -1015,6 +1079,48 @@ function installQwen() {
1015
1079
  console.log("Qwen Code CLI hook installed.");
1016
1080
  }
1017
1081
 
1082
+ function installDroid() {
1083
+ if (!commandExists("droid")) {
1084
+ console.log("Factory Droid CLI not found. To enable CLIsponsor for Droid, install Droid CLI and rerun: npx clisponsor@latest install");
1085
+ return;
1086
+ }
1087
+
1088
+ const droidDir = path.join(CONFIG_DIR, "droid");
1089
+ fs.mkdirSync(droidDir, { recursive: true });
1090
+ const hookPath = path.join(droidDir, "clisponsor_droid_hook.mjs");
1091
+ fs.writeFileSync(hookPath, agentHookSource("Droid"), { mode: 0o755 });
1092
+
1093
+ const hooksPath = path.join(factoryHome(), "hooks.json");
1094
+ const hooksConfig = readEditableJson(hooksPath, {});
1095
+ addDroidCommandHook(hooksConfig, "SessionStart", `node ${JSON.stringify(hookPath)} SessionStart`);
1096
+ addDroidCommandHook(hooksConfig, "UserPromptSubmit", `node ${JSON.stringify(hookPath)} UserPromptSubmit`);
1097
+ addDroidCommandHook(hooksConfig, "Stop", `node ${JSON.stringify(hookPath)} Stop`);
1098
+ writeJson(hooksPath, hooksConfig);
1099
+ console.log(`Updated ${hooksPath}`);
1100
+ console.log("Factory Droid CLI hook installed.");
1101
+ }
1102
+
1103
+ function installDevin() {
1104
+ if (!commandExists("devin")) {
1105
+ console.log("Devin CLI not found. To enable CLIsponsor for Devin, install Devin CLI and rerun: npx clisponsor@latest install");
1106
+ return;
1107
+ }
1108
+
1109
+ const devinDir = path.join(CONFIG_DIR, "devin");
1110
+ fs.mkdirSync(devinDir, { recursive: true });
1111
+ const hookPath = path.join(devinDir, "clisponsor_devin_hook.mjs");
1112
+ fs.writeFileSync(hookPath, agentHookSource("Devin"), { mode: 0o755 });
1113
+
1114
+ const settingsPath = devinConfigPath();
1115
+ const settings = readEditableJson(settingsPath, {});
1116
+ addDevinCommandHook(settings, "SessionStart", `node ${JSON.stringify(hookPath)} SessionStart`);
1117
+ addDevinCommandHook(settings, "UserPromptSubmit", `node ${JSON.stringify(hookPath)} UserPromptSubmit`);
1118
+ addDevinCommandHook(settings, "Stop", `node ${JSON.stringify(hookPath)} Stop`);
1119
+ writeJson(settingsPath, settings);
1120
+ console.log(`Updated ${settingsPath}`);
1121
+ console.log("Devin CLI hook installed.");
1122
+ }
1123
+
1018
1124
  function installTargets() {
1019
1125
  return [
1020
1126
  { target: "codex", label: "Codex CLI", command: "codex", install: installCodex },
@@ -1025,6 +1131,8 @@ function installTargets() {
1025
1131
  { target: "pi", label: "Pi Coding Agent", command: "pi", install: installPi },
1026
1132
  { target: "copilot", label: "GitHub Copilot CLI", command: "copilot", install: installCopilot },
1027
1133
  { target: "qwen", label: "Qwen Code", command: "qwen", install: installQwen },
1134
+ { target: "droid", label: "Factory Droid CLI", command: "droid", install: installDroid },
1135
+ { target: "devin", label: "Devin CLI", command: "devin", install: installDevin },
1028
1136
  ];
1029
1137
  }
1030
1138
 
@@ -1081,7 +1189,7 @@ function installAll() {
1081
1189
  function install() {
1082
1190
  const target = process.argv[3] && !process.argv[3].startsWith("--") ? process.argv[3] : "all";
1083
1191
  if (!["all", ...targetNames()].includes(target)) {
1084
- console.error("Unknown install target. Use: codex, claude, gemini, antigravity, opencode, pi, copilot, qwen, or all.");
1192
+ console.error("Unknown install target. Use: codex, claude, gemini, antigravity, opencode, pi, copilot, qwen, droid, devin, or all.");
1085
1193
  process.exit(1);
1086
1194
  }
1087
1195
  renderInstallHeader(target);
@@ -1189,10 +1297,42 @@ function uninstallQwen() {
1189
1297
  console.log("Removed Qwen Code hook script.");
1190
1298
  }
1191
1299
 
1300
+ function uninstallDroid() {
1301
+ const hooksPath = path.join(factoryHome(), "hooks.json");
1302
+ const hooksConfig = readEditableJson(hooksPath, {});
1303
+ if (removeClaudeCommandHooks(hooksConfig)) {
1304
+ writeJson(hooksPath, hooksConfig);
1305
+ console.log(`Removed CLIsponsor hooks from ${hooksPath}`);
1306
+ } else {
1307
+ console.log("No CLIsponsor Factory Droid hooks found.");
1308
+ }
1309
+ fs.rmSync(path.join(CONFIG_DIR, "droid", "clisponsor_droid_hook.mjs"), { force: true });
1310
+ try {
1311
+ fs.rmdirSync(path.join(CONFIG_DIR, "droid"));
1312
+ } catch {}
1313
+ console.log("Removed Factory Droid hook script.");
1314
+ }
1315
+
1316
+ function uninstallDevin() {
1317
+ const settingsPath = devinConfigPath();
1318
+ const settings = readEditableJson(settingsPath, {});
1319
+ if (removeClaudeCommandHooks(settings)) {
1320
+ writeJson(settingsPath, settings);
1321
+ console.log(`Removed CLIsponsor hooks from ${settingsPath}`);
1322
+ } else {
1323
+ console.log("No CLIsponsor Devin hooks found.");
1324
+ }
1325
+ fs.rmSync(path.join(CONFIG_DIR, "devin", "clisponsor_devin_hook.mjs"), { force: true });
1326
+ try {
1327
+ fs.rmdirSync(path.join(CONFIG_DIR, "devin"));
1328
+ } catch {}
1329
+ console.log("Removed Devin hook script.");
1330
+ }
1331
+
1192
1332
  function uninstall() {
1193
1333
  const target = process.argv[3] && !process.argv[3].startsWith("--") ? process.argv[3] : "all";
1194
- if (!["all", "codex", "claude", "gemini", "antigravity", "agy", "opencode", "pi", "copilot", "qwen"].includes(target)) {
1195
- console.error("Unknown uninstall target. Use: codex, claude, gemini, antigravity, opencode, pi, copilot, qwen, or all.");
1334
+ if (!["all", "codex", "claude", "gemini", "antigravity", "agy", "opencode", "pi", "copilot", "qwen", "droid", "devin"].includes(target)) {
1335
+ console.error("Unknown uninstall target. Use: codex, claude, gemini, antigravity, opencode, pi, copilot, qwen, droid, devin, or all.");
1196
1336
  process.exit(1);
1197
1337
  }
1198
1338
  if (target === "all" || target === "codex") uninstallCodex();
@@ -1203,6 +1343,8 @@ function uninstall() {
1203
1343
  if (target === "all" || target === "pi") uninstallPi();
1204
1344
  if (target === "all" || target === "copilot") uninstallCopilot();
1205
1345
  if (target === "all" || target === "qwen") uninstallQwen();
1346
+ if (target === "all" || target === "droid") uninstallDroid();
1347
+ if (target === "all" || target === "devin") uninstallDevin();
1206
1348
  if (hasFlag("--config")) {
1207
1349
  fs.rmSync(CONFIG_PATH, { force: true });
1208
1350
  console.log(`Removed ${CONFIG_PATH}`);
@@ -1256,17 +1398,19 @@ async function doctor() {
1256
1398
  email: cfg.email || null,
1257
1399
  userId: cfg.userId || null,
1258
1400
  deviceCode: cfg.deviceCode || null,
1259
- installed: {
1260
- codexPluginStaged: fs.existsSync(path.join(CONFIG_DIR, "codex-marketplace", "plugins", "clisponsor")),
1261
- claudeSettings: fs.existsSync(path.join(HOME, ".claude", "settings.json")),
1262
- claudeHookScript: fs.existsSync(path.join(CONFIG_DIR, "claude", "clisponsor_claude_hook.mjs")),
1263
- geminiHookScript: fs.existsSync(path.join(CONFIG_DIR, "gemini", "clisponsor_gemini_hook.mjs")),
1264
- antigravityHookScript: fs.existsSync(path.join(CONFIG_DIR, "antigravity", "clisponsor_antigravity_hook.mjs")),
1265
- opencodePlugin: fs.existsSync(path.join(openCodeConfigDir(), "plugins", "clisponsor_opencode_plugin.js")),
1266
- piExtension: fs.existsSync(path.join(HOME, ".pi", "agent", "extensions", "clisponsor_pi_extension.ts")),
1267
- copilotHook: fs.existsSync(path.join(copilotHome(), "hooks", "clisponsor.json")),
1268
- qwenHookScript: fs.existsSync(path.join(CONFIG_DIR, "qwen", "clisponsor_qwen_hook.mjs")),
1269
- },
1401
+ installed: {
1402
+ codexPluginStaged: fs.existsSync(path.join(CONFIG_DIR, "codex-marketplace", "plugins", "clisponsor")),
1403
+ claudeSettings: fs.existsSync(path.join(HOME, ".claude", "settings.json")),
1404
+ claudeHookScript: fs.existsSync(path.join(CONFIG_DIR, "claude", "clisponsor_claude_hook.mjs")),
1405
+ geminiHookScript: fs.existsSync(path.join(CONFIG_DIR, "gemini", "clisponsor_gemini_hook.mjs")),
1406
+ antigravityHookScript: fs.existsSync(path.join(CONFIG_DIR, "antigravity", "clisponsor_antigravity_hook.mjs")),
1407
+ opencodePlugin: fs.existsSync(path.join(openCodeConfigDir(), "plugins", "clisponsor_opencode_plugin.js")),
1408
+ piExtension: fs.existsSync(path.join(HOME, ".pi", "agent", "extensions", "clisponsor_pi_extension.ts")),
1409
+ copilotHook: fs.existsSync(path.join(copilotHome(), "hooks", "clisponsor.json")),
1410
+ qwenHookScript: fs.existsSync(path.join(CONFIG_DIR, "qwen", "clisponsor_qwen_hook.mjs")),
1411
+ droidHookScript: fs.existsSync(path.join(CONFIG_DIR, "droid", "clisponsor_droid_hook.mjs")),
1412
+ devinHookScript: fs.existsSync(path.join(CONFIG_DIR, "devin", "clisponsor_devin_hook.mjs")),
1413
+ },
1270
1414
  network: {},
1271
1415
  };
1272
1416
 
@@ -1297,6 +1441,8 @@ async function doctor() {
1297
1441
  console.log(`Pi extension: ${diagnostics.installed.piExtension ? "yes" : "no"}`);
1298
1442
  console.log(`GitHub Copilot CLI hook: ${diagnostics.installed.copilotHook ? "yes" : "no"}`);
1299
1443
  console.log(`Qwen Code hook script: ${diagnostics.installed.qwenHookScript ? "yes" : "no"}`);
1444
+ console.log(`Factory Droid hook script: ${diagnostics.installed.droidHookScript ? "yes" : "no"}`);
1445
+ console.log(`Devin hook script: ${diagnostics.installed.devinHookScript ? "yes" : "no"}`);
1300
1446
  if (skipNetwork) {
1301
1447
  console.log("Network: skipped");
1302
1448
  } else {
@@ -1307,9 +1453,9 @@ async function doctor() {
1307
1453
 
1308
1454
  function help() {
1309
1455
  console.log(`clisponsor commands:
1310
- clisponsor install [all|codex|claude|gemini|antigravity|opencode|pi|copilot|qwen]
1456
+ clisponsor install [all|codex|claude|gemini|antigravity|opencode|pi|copilot|qwen|droid|devin]
1311
1457
  clisponsor login <email> [--label=<device-label>]
1312
- clisponsor uninstall [all|codex|claude|gemini|antigravity|opencode|pi|copilot|qwen] [--config]
1458
+ clisponsor uninstall [all|codex|claude|gemini|antigravity|opencode|pi|copilot|qwen|droid|devin] [--config]
1313
1459
  clisponsor status
1314
1460
  clisponsor doctor [--json] [--skip-network]
1315
1461
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "clisponsor",
3
- "version": "1.0.17",
4
- "description": "CLIsponsor installer for Codex, Claude Code, Gemini, Antigravity, OpenCode, Pi, GitHub Copilot CLI, and Qwen Code sponsored CLI placements.",
3
+ "version": "1.0.20",
4
+ "description": "CLIsponsor installer for Codex, Claude Code, Gemini, Antigravity, OpenCode, Pi, GitHub Copilot CLI, Qwen Code, Factory Droid, and Devin sponsored CLI placements.",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": ">=20"