opencrater 0.1.4 → 0.1.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/cli.js +37 -2
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -164,6 +164,9 @@ async function dismissNow() {
164
164
  JSON.stringify({ impressionId: lock.impressionId, at: Date.now() }),
165
165
  );
166
166
  } catch {}
167
+ if (lock.dismissUrl) {
168
+ try { await fetch(lock.dismissUrl, { signal: AbortSignal.timeout(1000) }); } catch {}
169
+ }
167
170
  if (lock.impressionId) {
168
171
  const origin = process.env.OPENCRATER_API_ORIGIN || "https://api.opencrater.to";
169
172
  try {
@@ -174,6 +177,35 @@ async function dismissNow() {
174
177
  try { process.kill(lock.pid, "SIGTERM"); } catch {}
175
178
  }
176
179
  console.log("opencrater: ad dismissed — feedback recorded.");
180
+ console.log(" changed your mind? npx opencrater show");
181
+ }
182
+
183
+ /* Repaint the last sponsor card ("show ad again"). Reads the payload the
184
+ painter saved, resolves THIS terminal's tty, and spawns the local-runtime
185
+ painter detached — exactly how the hook does it. */
186
+ function showAgain() {
187
+ const dir = path.join(os.homedir(), ".config", "opencrater");
188
+ let saved = null;
189
+ try {
190
+ saved = JSON.parse(fs.readFileSync(path.join(dir, "last-ad.json"), "utf8"));
191
+ } catch {
192
+ console.log("opencrater: no recent ad to show.");
193
+ return;
194
+ }
195
+ const painter = path.join(dir, "runtime", "node_modules", "@opencrater", "sdk", "dist", "paint.js");
196
+ if (!fs.existsSync(painter)) {
197
+ console.log("opencrater: hook runtime not installed yet — run: npx opencrater on");
198
+ return;
199
+ }
200
+ const { spawnSync, spawn } = require("node:child_process");
201
+ // our own terminal's device (we are running interactively)
202
+ const tty = spawnSync("tty", { stdio: ["inherit", "pipe", "ignore"], encoding: "utf8" })
203
+ .stdout?.trim();
204
+ const env = { ...process.env, OPENCRATER_PAINT: JSON.stringify(saved.payload) };
205
+ if (tty && tty.startsWith("/dev/")) env.OPENCRATER_TTY = tty;
206
+ const child = spawn(process.execPath, [painter], { detached: true, stdio: "ignore", env });
207
+ child.unref();
208
+ console.log("opencrater: showing the last ad again.");
177
209
  }
178
210
 
179
211
  const cmd = process.argv[2] || "status";
@@ -201,13 +233,16 @@ if (cmd === "on" || cmd === "enable") {
201
233
  console.log(a || b ? "OpenCrater ads disabled. Publisher hooks (if any) were not touched." : "Nothing to remove — OpenCrater ads were not enabled.");
202
234
  } else if (cmd === "x" || cmd === "dismiss") {
203
235
  dismissNow();
236
+ } else if (cmd === "show" || cmd === "again") {
237
+ showAgain();
204
238
  } else if (cmd === "status") {
205
239
  const cc = statusIn(CLAUDE_SETTINGS);
206
240
  const cx = statusIn(CODEX_HOOKS);
207
241
  console.log("Claude Code:", cc.length ? "enabled on " + cc.join(", ") : "not enabled");
208
242
  console.log("Codex: ", cx.length ? "enabled on " + cx.join(", ") : "not enabled");
209
243
  } else {
210
- console.log("Usage: npx opencrater <on|off|status|x>");
211
- console.log(" x dismiss the sponsor card currently on screen");
244
+ console.log("Usage: npx opencrater <on|off|status|x|show>");
245
+ console.log(" x dismiss the sponsor card currently on screen");
246
+ console.log(" show bring the last dismissed ad back");
212
247
  process.exitCode = 1;
213
248
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrater",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "OpenCrater — sponsor cards in Claude Code and Codex. Free, one command, opt out anytime.",
5
5
  "keywords": [
6
6
  "opencrater",