opencrater 0.1.2 → 0.1.4
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 +59 -4
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -43,9 +43,21 @@ const CODEX_EVENTS = [
|
|
|
43
43
|
];
|
|
44
44
|
const MARKER = "--package " + PKG + " "; // identifies OUR hook entries only
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
// Resilient hook command: prefer the pre-installed local runtime (no npx on
|
|
47
|
+
// the hot path — concurrent fires racing a cold npx cache caused
|
|
48
|
+
// "opencrater-hook: command not found" noise in the host); fall back to npx;
|
|
49
|
+
// ALWAYS exit 0 with stderr silenced — a sponsor hook must never surface an
|
|
50
|
+
// error inside someone's session.
|
|
51
|
+
const cmdFor = (event, host) => {
|
|
52
|
+
const args = "--placement " + event + " --key " + KEY +
|
|
53
|
+
" --package " + PKG + " --host " + host;
|
|
54
|
+
const runtime = '"$HOME/.config/opencrater/runtime/node_modules/@opencrater/sdk/dist/hook.js"';
|
|
55
|
+
return (
|
|
56
|
+
"{ if [ -f " + runtime + " ]; then node " + runtime + " " + args +
|
|
57
|
+
"; else npx -y -p @opencrater/sdk opencrater-hook " + args +
|
|
58
|
+
"; fi; } 2>/dev/null || true"
|
|
59
|
+
);
|
|
60
|
+
};
|
|
49
61
|
|
|
50
62
|
const CLAUDE_SETTINGS = path.join(os.homedir(), ".claude", "settings.json");
|
|
51
63
|
const CODEX_HOOKS = path.join(
|
|
@@ -133,10 +145,50 @@ function statusIn(file) {
|
|
|
133
145
|
);
|
|
134
146
|
}
|
|
135
147
|
|
|
148
|
+
/* Dismiss the sponsor card currently on screen — no browser needed.
|
|
149
|
+
Writes the painter's local dismiss signal, records the dismissal against
|
|
150
|
+
the API (idempotent), and SIGTERMs the painter so the card clears NOW. */
|
|
151
|
+
async function dismissNow() {
|
|
152
|
+
const dir = path.join(os.homedir(), ".config", "opencrater");
|
|
153
|
+
let lock = null;
|
|
154
|
+
try {
|
|
155
|
+
lock = JSON.parse(fs.readFileSync(path.join(dir, "painter.lock"), "utf8"));
|
|
156
|
+
} catch {
|
|
157
|
+
console.log("opencrater: no sponsor card is on screen.");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
162
|
+
fs.writeFileSync(
|
|
163
|
+
path.join(dir, "dismiss.signal"),
|
|
164
|
+
JSON.stringify({ impressionId: lock.impressionId, at: Date.now() }),
|
|
165
|
+
);
|
|
166
|
+
} catch {}
|
|
167
|
+
if (lock.impressionId) {
|
|
168
|
+
const origin = process.env.OPENCRATER_API_ORIGIN || "https://api.opencrater.to";
|
|
169
|
+
try {
|
|
170
|
+
await fetch(origin + "/x/" + lock.impressionId, { signal: AbortSignal.timeout(2500) });
|
|
171
|
+
} catch {}
|
|
172
|
+
}
|
|
173
|
+
if (lock.pid && lock.pid > 1) {
|
|
174
|
+
try { process.kill(lock.pid, "SIGTERM"); } catch {}
|
|
175
|
+
}
|
|
176
|
+
console.log("opencrater: ad dismissed — feedback recorded.");
|
|
177
|
+
}
|
|
178
|
+
|
|
136
179
|
const cmd = process.argv[2] || "status";
|
|
137
180
|
if (cmd === "on" || cmd === "enable") {
|
|
138
181
|
enableIn(CLAUDE_SETTINGS, "claude_code");
|
|
139
182
|
enableIn(CODEX_HOOKS, "codex");
|
|
183
|
+
// Pre-install the local hook runtime (background): hooks then run via
|
|
184
|
+
// plain node — no npx resolution latency, no cold-cache races.
|
|
185
|
+
try {
|
|
186
|
+
const { spawn } = require("node:child_process");
|
|
187
|
+
spawn("npm", ["install", "--prefix",
|
|
188
|
+
path.join(os.homedir(), ".config", "opencrater", "runtime"),
|
|
189
|
+
"@opencrater/sdk@latest", "--silent", "--no-audit", "--no-fund"],
|
|
190
|
+
{ detached: true, stdio: "ignore" }).unref();
|
|
191
|
+
} catch {}
|
|
140
192
|
console.log("OpenCrater ads enabled for Claude Code + Codex.");
|
|
141
193
|
console.log("All hooks registered as triggers; cards render only at session edges");
|
|
142
194
|
console.log("(SessionStart, Stop, SessionEnd, Notification) with a machine-wide frequency cap.");
|
|
@@ -147,12 +199,15 @@ if (cmd === "on" || cmd === "enable") {
|
|
|
147
199
|
const a = disableIn(CLAUDE_SETTINGS);
|
|
148
200
|
const b = disableIn(CODEX_HOOKS);
|
|
149
201
|
console.log(a || b ? "OpenCrater ads disabled. Publisher hooks (if any) were not touched." : "Nothing to remove — OpenCrater ads were not enabled.");
|
|
202
|
+
} else if (cmd === "x" || cmd === "dismiss") {
|
|
203
|
+
dismissNow();
|
|
150
204
|
} else if (cmd === "status") {
|
|
151
205
|
const cc = statusIn(CLAUDE_SETTINGS);
|
|
152
206
|
const cx = statusIn(CODEX_HOOKS);
|
|
153
207
|
console.log("Claude Code:", cc.length ? "enabled on " + cc.join(", ") : "not enabled");
|
|
154
208
|
console.log("Codex: ", cx.length ? "enabled on " + cx.join(", ") : "not enabled");
|
|
155
209
|
} else {
|
|
156
|
-
console.log("Usage: npx opencrater <on|off|status>");
|
|
210
|
+
console.log("Usage: npx opencrater <on|off|status|x>");
|
|
211
|
+
console.log(" x dismiss the sponsor card currently on screen");
|
|
157
212
|
process.exitCode = 1;
|
|
158
213
|
}
|