opencrater 0.2.0 → 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.
Files changed (2) hide show
  1. package/cli.js +60 -3
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -190,6 +190,60 @@ async function dismissNow() {
190
190
  console.log(" changed your mind? npx opencrater show");
191
191
  }
192
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
+
193
247
  /* Repaint the last sponsor card ("show ad again"). Reads the payload the
194
248
  painter saved, resolves THIS terminal's tty, and spawns the local-runtime
195
249
  painter detached — exactly how the hook does it. */
@@ -298,6 +352,8 @@ if (cmd === "on" || cmd === "enable") {
298
352
  console.log(a || b ? "OpenCrater ads disabled. Publisher hooks (if any) were not touched." : "Nothing to remove — OpenCrater ads were not enabled.");
299
353
  } else if (cmd === "x" || cmd === "dismiss") {
300
354
  dismissNow();
355
+ } else if (cmd === "report" || cmd === "flag") {
356
+ reportAd();
301
357
  } else if (cmd === "show" || cmd === "again") {
302
358
  showAgain();
303
359
  } else if (cmd === "status") {
@@ -310,8 +366,9 @@ if (cmd === "on" || cmd === "enable") {
310
366
  console.log("Gemini CLI:", !hosts.gemini_cli ? "not installed" : gm.length ? "enabled (" + gm.length + " hooks)" : "detected — run: npx opencrater on");
311
367
  if (hosts.openclaw) console.log("OpenClaw: detected — message-level sponsorship on the roadmap");
312
368
  } else {
313
- console.log("Usage: npx opencrater <on|off|status|x|show>");
314
- console.log(" x dismiss the sponsor card currently on screen");
315
- console.log(" show bring the last dismissed ad back");
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");
316
373
  process.exitCode = 1;
317
374
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrater",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "OpenCrater — sponsor cards in Claude Code and Codex. Free, one command, opt out anytime.",
5
5
  "keywords": [
6
6
  "opencrater",