opencrater 0.1.9 → 0.2.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/cli.js +84 -8
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -37,6 +37,13 @@ const CLAUDE_EVENTS = [
|
|
|
37
37
|
"Elicitation", "ElicitationResult", "ConfigChange", "InstructionsLoaded",
|
|
38
38
|
"WorktreeCreate", "WorktreeRemove", "CwdChanged", "FileChanged", "MessageDisplay",
|
|
39
39
|
];
|
|
40
|
+
// Gemini CLI hooks (verified HookEventName set, GA since v0.26.0):
|
|
41
|
+
// ~/.gemini/settings.json takes the same rule shape as Claude Code.
|
|
42
|
+
const GEMINI_EVENTS = [
|
|
43
|
+
"SessionStart", "SessionEnd", "BeforeAgent", "AfterAgent", "BeforeModel",
|
|
44
|
+
"AfterModel", "BeforeToolSelection", "BeforeTool", "AfterTool",
|
|
45
|
+
"PreCompress", "Notification",
|
|
46
|
+
];
|
|
40
47
|
const CODEX_EVENTS = [
|
|
41
48
|
"SessionStart", "Stop", "UserPromptSubmit", "PreToolUse", "PostToolUse",
|
|
42
49
|
"PermissionRequest", "PreCompact", "PostCompact",
|
|
@@ -64,6 +71,7 @@ const CODEX_HOOKS = path.join(
|
|
|
64
71
|
process.env.CODEX_HOME || path.join(os.homedir(), ".codex"),
|
|
65
72
|
"hooks.json",
|
|
66
73
|
);
|
|
74
|
+
const GEMINI_SETTINGS = path.join(os.homedir(), ".gemini", "settings.json");
|
|
67
75
|
|
|
68
76
|
function readJson(p) {
|
|
69
77
|
try {
|
|
@@ -92,7 +100,9 @@ const isOurs = (rule) =>
|
|
|
92
100
|
);
|
|
93
101
|
|
|
94
102
|
function enableIn(file, host) {
|
|
95
|
-
const events =
|
|
103
|
+
const events =
|
|
104
|
+
host === "codex" ? CODEX_EVENTS :
|
|
105
|
+
host === "gemini_cli" ? GEMINI_EVENTS : CLAUDE_EVENTS;
|
|
96
106
|
const settings = readJson(file);
|
|
97
107
|
if (!settings.hooks) settings.hooks = {};
|
|
98
108
|
let changed = false;
|
|
@@ -180,6 +190,60 @@ async function dismissNow() {
|
|
|
180
190
|
console.log(" changed your mind? npx opencrater show");
|
|
181
191
|
}
|
|
182
192
|
|
|
193
|
+
/* Report the sponsor card currently on screen (or the last one shown).
|
|
194
|
+
Blocks the campaign on this machine permanently (reported-ads.json — the
|
|
195
|
+
SDK skips reported campaigns forever), clears the card, and opens the
|
|
196
|
+
hosted report screen so the user can pick a reason. */
|
|
197
|
+
async function reportAd() {
|
|
198
|
+
const dir = path.join(os.homedir(), ".config", "opencrater");
|
|
199
|
+
let lock = null;
|
|
200
|
+
let saved = null;
|
|
201
|
+
try { lock = JSON.parse(fs.readFileSync(path.join(dir, "painter.lock"), "utf8")); } catch {}
|
|
202
|
+
try { saved = JSON.parse(fs.readFileSync(path.join(dir, "last-ad.json"), "utf8")); } catch {}
|
|
203
|
+
const impressionId = (lock && lock.impressionId) || (saved && saved.payload && saved.payload.impressionId);
|
|
204
|
+
const campaignId = saved && saved.payload && saved.payload.campaignId;
|
|
205
|
+
if (!impressionId && !campaignId) {
|
|
206
|
+
console.log("opencrater: no sponsor card to report.");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// permanent local block — never render this campaign here again
|
|
210
|
+
if (campaignId) {
|
|
211
|
+
const file = path.join(dir, "reported-ads.json");
|
|
212
|
+
let reported = {};
|
|
213
|
+
try { reported = JSON.parse(fs.readFileSync(file, "utf8")) || {}; } catch {}
|
|
214
|
+
reported[campaignId] = Date.now();
|
|
215
|
+
try {
|
|
216
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
217
|
+
fs.writeFileSync(file, JSON.stringify(reported));
|
|
218
|
+
} catch {}
|
|
219
|
+
}
|
|
220
|
+
// clear the live card, if any
|
|
221
|
+
if (lock) {
|
|
222
|
+
try {
|
|
223
|
+
fs.writeFileSync(
|
|
224
|
+
path.join(dir, "dismiss.signal"),
|
|
225
|
+
JSON.stringify({ impressionId: lock.impressionId, at: Date.now() }),
|
|
226
|
+
);
|
|
227
|
+
} catch {}
|
|
228
|
+
if (lock.pid && lock.pid > 1) {
|
|
229
|
+
try { process.kill(lock.pid, "SIGTERM"); } catch {}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
console.log("opencrater: reported — you won't see this ad on this machine again.");
|
|
233
|
+
if (impressionId) {
|
|
234
|
+
const origin = process.env.OPENCRATER_API_ORIGIN || "https://api.opencrater.to";
|
|
235
|
+
const url = origin + "/r/" + impressionId;
|
|
236
|
+
const { spawnSync } = require("node:child_process");
|
|
237
|
+
const opener = process.platform === "darwin" ? "open" : "xdg-open";
|
|
238
|
+
const res = spawnSync(opener, [url], { stdio: "ignore" });
|
|
239
|
+
if (res.status === 0) {
|
|
240
|
+
console.log(" tell us why in the tab that just opened (10 seconds).");
|
|
241
|
+
} else {
|
|
242
|
+
console.log(" tell us why (optional): " + url);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
183
247
|
/* Repaint the last sponsor card ("show ad again"). Reads the payload the
|
|
184
248
|
painter saved, resolves THIS terminal's tty, and spawns the local-runtime
|
|
185
249
|
painter detached — exactly how the hook does it. */
|
|
@@ -251,11 +315,15 @@ if (cmd === "on" || cmd === "enable") {
|
|
|
251
315
|
} else {
|
|
252
316
|
console.log("· Codex not found — skipped");
|
|
253
317
|
}
|
|
254
|
-
if (hosts.openclaw) {
|
|
255
|
-
console.log("✓ OpenClaw detected — native hook support is rolling out; cards will enable automatically.");
|
|
256
|
-
}
|
|
257
318
|
if (hosts.gemini_cli) {
|
|
258
|
-
|
|
319
|
+
enableIn(GEMINI_SETTINGS, "gemini_cli");
|
|
320
|
+
console.log("✓ Gemini CLI detected — connected (" + GEMINI_SETTINGS + ")");
|
|
321
|
+
} else {
|
|
322
|
+
console.log("· Gemini CLI not found — skipped");
|
|
323
|
+
}
|
|
324
|
+
if (hosts.openclaw) {
|
|
325
|
+
console.log("· OpenClaw detected — its hooks run inside the gateway (no terminal");
|
|
326
|
+
console.log(" overlay surface); message-level sponsorship is on the roadmap.");
|
|
259
327
|
}
|
|
260
328
|
// Pre-install the local hook runtime (background): hooks then run via
|
|
261
329
|
// plain node — no npx resolution latency, no cold-cache races.
|
|
@@ -279,20 +347,28 @@ if (cmd === "on" || cmd === "enable") {
|
|
|
279
347
|
} else if (cmd === "off" || cmd === "disable") {
|
|
280
348
|
const a = disableIn(CLAUDE_SETTINGS);
|
|
281
349
|
const b = disableIn(CODEX_HOOKS);
|
|
350
|
+
const c = disableIn(GEMINI_SETTINGS);
|
|
351
|
+
void c;
|
|
282
352
|
console.log(a || b ? "OpenCrater ads disabled. Publisher hooks (if any) were not touched." : "Nothing to remove — OpenCrater ads were not enabled.");
|
|
283
353
|
} else if (cmd === "x" || cmd === "dismiss") {
|
|
284
354
|
dismissNow();
|
|
355
|
+
} else if (cmd === "report" || cmd === "flag") {
|
|
356
|
+
reportAd();
|
|
285
357
|
} else if (cmd === "show" || cmd === "again") {
|
|
286
358
|
showAgain();
|
|
287
359
|
} else if (cmd === "status") {
|
|
288
360
|
const hosts = detectHosts();
|
|
289
361
|
const cc = statusIn(CLAUDE_SETTINGS);
|
|
290
362
|
const cx = statusIn(CODEX_HOOKS);
|
|
363
|
+
const gm = statusIn(GEMINI_SETTINGS);
|
|
291
364
|
console.log("Claude Code:", !hosts.claude_code ? "not installed" : cc.length ? "enabled (" + cc.length + " hooks)" : "detected — run: npx opencrater on");
|
|
292
365
|
console.log("Codex: ", !hosts.codex ? "not installed" : cx.length ? "enabled (" + cx.length + " hooks)" : "detected — run: npx opencrater on");
|
|
366
|
+
console.log("Gemini CLI:", !hosts.gemini_cli ? "not installed" : gm.length ? "enabled (" + gm.length + " hooks)" : "detected — run: npx opencrater on");
|
|
367
|
+
if (hosts.openclaw) console.log("OpenClaw: detected — message-level sponsorship on the roadmap");
|
|
293
368
|
} else {
|
|
294
|
-
console.log("Usage: npx opencrater <on|off|status|x|show>");
|
|
295
|
-
console.log(" x
|
|
296
|
-
console.log("
|
|
369
|
+
console.log("Usage: npx opencrater <on|off|status|x|report|show>");
|
|
370
|
+
console.log(" x dismiss the sponsor card currently on screen");
|
|
371
|
+
console.log(" report report the ad (never shows on this machine again)");
|
|
372
|
+
console.log(" show bring the last dismissed ad back");
|
|
297
373
|
process.exitCode = 1;
|
|
298
374
|
}
|