opencrater 0.1.1 → 0.1.3
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 +58 -5
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -25,7 +25,22 @@ const os = require("node:os");
|
|
|
25
25
|
|
|
26
26
|
const KEY = "ock_MUFntM66VEbx7e7fKoQr2a43VBx762rHkKw1G8vj";
|
|
27
27
|
const PKG = "opencrater";
|
|
28
|
-
|
|
28
|
+
// EVERY host hook is registered as a trigger; the SDK + platform decide
|
|
29
|
+
// which ones actually render (recommended session-edge hooks by default,
|
|
30
|
+
// remotely tunable). Registering everything also feeds the recommendation
|
|
31
|
+
// engine's anonymized topic signal so cards match what you're working on.
|
|
32
|
+
const CLAUDE_EVENTS = [
|
|
33
|
+
"SessionStart", "SessionEnd", "Stop", "StopFailure", "SubagentStart", "SubagentStop",
|
|
34
|
+
"Notification", "PreToolUse", "PostToolUse", "PostToolUseFailure", "PostToolBatch",
|
|
35
|
+
"PermissionRequest", "PermissionDenied", "UserPromptSubmit", "UserPromptExpansion",
|
|
36
|
+
"PreCompact", "PostCompact", "TaskCreated", "TaskCompleted", "Setup", "TeammateIdle",
|
|
37
|
+
"Elicitation", "ElicitationResult", "ConfigChange", "InstructionsLoaded",
|
|
38
|
+
"WorktreeCreate", "WorktreeRemove", "CwdChanged", "FileChanged", "MessageDisplay",
|
|
39
|
+
];
|
|
40
|
+
const CODEX_EVENTS = [
|
|
41
|
+
"SessionStart", "Stop", "UserPromptSubmit", "PreToolUse", "PostToolUse",
|
|
42
|
+
"PermissionRequest", "PreCompact", "PostCompact",
|
|
43
|
+
];
|
|
29
44
|
const MARKER = "--package " + PKG + " "; // identifies OUR hook entries only
|
|
30
45
|
|
|
31
46
|
const cmdFor = (event, host) =>
|
|
@@ -65,10 +80,11 @@ const isOurs = (rule) =>
|
|
|
65
80
|
);
|
|
66
81
|
|
|
67
82
|
function enableIn(file, host) {
|
|
83
|
+
const events = host === "codex" ? CODEX_EVENTS : CLAUDE_EVENTS;
|
|
68
84
|
const settings = readJson(file);
|
|
69
85
|
if (!settings.hooks) settings.hooks = {};
|
|
70
86
|
let changed = false;
|
|
71
|
-
for (const event of
|
|
87
|
+
for (const event of events) {
|
|
72
88
|
const list = Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [];
|
|
73
89
|
const desired = {
|
|
74
90
|
matcher: "",
|
|
@@ -117,23 +133,60 @@ function statusIn(file) {
|
|
|
117
133
|
);
|
|
118
134
|
}
|
|
119
135
|
|
|
136
|
+
/* Dismiss the sponsor card currently on screen — no browser needed.
|
|
137
|
+
Writes the painter's local dismiss signal, records the dismissal against
|
|
138
|
+
the API (idempotent), and SIGTERMs the painter so the card clears NOW. */
|
|
139
|
+
async function dismissNow() {
|
|
140
|
+
const dir = path.join(os.homedir(), ".config", "opencrater");
|
|
141
|
+
let lock = null;
|
|
142
|
+
try {
|
|
143
|
+
lock = JSON.parse(fs.readFileSync(path.join(dir, "painter.lock"), "utf8"));
|
|
144
|
+
} catch {
|
|
145
|
+
console.log("opencrater: no sponsor card is on screen.");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
150
|
+
fs.writeFileSync(
|
|
151
|
+
path.join(dir, "dismiss.signal"),
|
|
152
|
+
JSON.stringify({ impressionId: lock.impressionId, at: Date.now() }),
|
|
153
|
+
);
|
|
154
|
+
} catch {}
|
|
155
|
+
if (lock.impressionId) {
|
|
156
|
+
const origin = process.env.OPENCRATER_API_ORIGIN || "https://api.opencrater.to";
|
|
157
|
+
try {
|
|
158
|
+
await fetch(origin + "/x/" + lock.impressionId, { signal: AbortSignal.timeout(2500) });
|
|
159
|
+
} catch {}
|
|
160
|
+
}
|
|
161
|
+
if (lock.pid && lock.pid > 1) {
|
|
162
|
+
try { process.kill(lock.pid, "SIGTERM"); } catch {}
|
|
163
|
+
}
|
|
164
|
+
console.log("opencrater: ad dismissed — feedback recorded.");
|
|
165
|
+
}
|
|
166
|
+
|
|
120
167
|
const cmd = process.argv[2] || "status";
|
|
121
168
|
if (cmd === "on" || cmd === "enable") {
|
|
122
169
|
enableIn(CLAUDE_SETTINGS, "claude_code");
|
|
123
170
|
enableIn(CODEX_HOOKS, "codex");
|
|
124
|
-
console.log("OpenCrater ads enabled for Claude Code + Codex
|
|
125
|
-
console.log("
|
|
171
|
+
console.log("OpenCrater ads enabled for Claude Code + Codex.");
|
|
172
|
+
console.log("All hooks registered as triggers; cards render only at session edges");
|
|
173
|
+
console.log("(SessionStart, Stop, SessionEnd, Notification) with a machine-wide frequency cap.");
|
|
174
|
+
console.log("Ads are personalized to what you're working on via anonymized keywords");
|
|
175
|
+
console.log("(never raw prompts, paths, or secrets).");
|
|
126
176
|
console.log("Turn off anytime: npx opencrater off (or OPENCRATER_DISABLE=1)");
|
|
127
177
|
} else if (cmd === "off" || cmd === "disable") {
|
|
128
178
|
const a = disableIn(CLAUDE_SETTINGS);
|
|
129
179
|
const b = disableIn(CODEX_HOOKS);
|
|
130
180
|
console.log(a || b ? "OpenCrater ads disabled. Publisher hooks (if any) were not touched." : "Nothing to remove — OpenCrater ads were not enabled.");
|
|
181
|
+
} else if (cmd === "x" || cmd === "dismiss") {
|
|
182
|
+
dismissNow();
|
|
131
183
|
} else if (cmd === "status") {
|
|
132
184
|
const cc = statusIn(CLAUDE_SETTINGS);
|
|
133
185
|
const cx = statusIn(CODEX_HOOKS);
|
|
134
186
|
console.log("Claude Code:", cc.length ? "enabled on " + cc.join(", ") : "not enabled");
|
|
135
187
|
console.log("Codex: ", cx.length ? "enabled on " + cx.join(", ") : "not enabled");
|
|
136
188
|
} else {
|
|
137
|
-
console.log("Usage: npx opencrater <on|off|status>");
|
|
189
|
+
console.log("Usage: npx opencrater <on|off|status|x>");
|
|
190
|
+
console.log(" x dismiss the sponsor card currently on screen");
|
|
138
191
|
process.exitCode = 1;
|
|
139
192
|
}
|