opencrater 0.1.6 → 0.1.8

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 (3) hide show
  1. package/README.md +10 -0
  2. package/cli.js +42 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -13,3 +13,13 @@ One card at session edges (SessionStart / Stop), rendered by the same fail-silen
13
13
  Opt out anytime: `npx opencrater off` or `OPENCRATER_DISABLE=1`.
14
14
 
15
15
  Apache-2.0 · [opencrater.to](https://opencrater.to)
16
+
17
+ ## One-time trust prompts
18
+
19
+ - **VS Code**: the first ⌘-click on a sponsor link shows an "open external
20
+ website?" dialog — choose **Configure Trusted Domains → trust
21
+ api.opencrater.to** and it never asks again. (Dismissing with ✕ or
22
+ `npx opencrater x` never opens anything — it's handled locally.)
23
+ - **Codex**: asks once to trust newly installed hooks on its next launch —
24
+ approve to enable cards. This is Codex's own security model.
25
+
package/cli.js CHANGED
@@ -212,10 +212,43 @@ function showAgain() {
212
212
  console.log("opencrater: showing the last ad again.");
213
213
  }
214
214
 
215
+ /* Auto-detect which AI CLIs exist on this machine — `on` connects every
216
+ detected host's config automatically, and new hosts picked up here flow
217
+ into detection as we add them. */
218
+ function hasBin(name) {
219
+ try {
220
+ const { spawnSync } = require("node:child_process");
221
+ return spawnSync("which", [name], { stdio: "ignore" }).status === 0;
222
+ } catch { return false; }
223
+ }
224
+ function detectHosts() {
225
+ return {
226
+ claude_code: fs.existsSync(path.join(os.homedir(), ".claude")) || hasBin("claude"),
227
+ codex: fs.existsSync(path.join(process.env.CODEX_HOME || path.join(os.homedir(), ".codex"))) || hasBin("codex"),
228
+ };
229
+ }
230
+
215
231
  const cmd = process.argv[2] || "status";
216
232
  if (cmd === "on" || cmd === "enable") {
217
- enableIn(CLAUDE_SETTINGS, "claude_code");
218
- enableIn(CODEX_HOOKS, "codex");
233
+ const hosts = detectHosts();
234
+ if (!hosts.claude_code && !hosts.codex) {
235
+ console.log("No supported AI CLI found (looked for Claude Code and Codex).");
236
+ console.log("Install one, then run: npx opencrater on");
237
+ process.exit(1);
238
+ }
239
+ if (hosts.claude_code) {
240
+ enableIn(CLAUDE_SETTINGS, "claude_code");
241
+ console.log("✓ Claude Code detected — connected (" + CLAUDE_SETTINGS + ")");
242
+ } else {
243
+ console.log("· Claude Code not found — skipped");
244
+ }
245
+ if (hosts.codex) {
246
+ enableIn(CODEX_HOOKS, "codex");
247
+ console.log("✓ Codex detected — connected (" + CODEX_HOOKS + ")");
248
+ console.log(" Codex will ask once to trust the new hooks on its next launch — approve to enable.");
249
+ } else {
250
+ console.log("· Codex not found — skipped");
251
+ }
219
252
  // Pre-install the local hook runtime (background): hooks then run via
220
253
  // plain node — no npx resolution latency, no cold-cache races.
221
254
  try {
@@ -231,6 +264,10 @@ if (cmd === "on" || cmd === "enable") {
231
264
  console.log("Ads are personalized to what you're working on via anonymized keywords");
232
265
  console.log("(never raw prompts, paths, or secrets).");
233
266
  console.log("Turn off anytime: npx opencrater off (or OPENCRATER_DISABLE=1)");
267
+ console.log("");
268
+ console.log("VS Code tip: the first time you ⌘-click a sponsor link, choose");
269
+ console.log("'Configure Trusted Domains' → trust api.opencrater.to and the");
270
+ console.log("confirmation dialog never appears again.");
234
271
  } else if (cmd === "off" || cmd === "disable") {
235
272
  const a = disableIn(CLAUDE_SETTINGS);
236
273
  const b = disableIn(CODEX_HOOKS);
@@ -240,10 +277,11 @@ if (cmd === "on" || cmd === "enable") {
240
277
  } else if (cmd === "show" || cmd === "again") {
241
278
  showAgain();
242
279
  } else if (cmd === "status") {
280
+ const hosts = detectHosts();
243
281
  const cc = statusIn(CLAUDE_SETTINGS);
244
282
  const cx = statusIn(CODEX_HOOKS);
245
- console.log("Claude Code:", cc.length ? "enabled on " + cc.join(", ") : "not enabled");
246
- console.log("Codex: ", cx.length ? "enabled on " + cx.join(", ") : "not enabled");
283
+ console.log("Claude Code:", !hosts.claude_code ? "not installed" : cc.length ? "enabled (" + cc.length + " hooks)" : "detected — run: npx opencrater on");
284
+ console.log("Codex: ", !hosts.codex ? "not installed" : cx.length ? "enabled (" + cx.length + " hooks)" : "detected — run: npx opencrater on");
247
285
  } else {
248
286
  console.log("Usage: npx opencrater <on|off|status|x|show>");
249
287
  console.log(" x dismiss the sponsor card currently on screen");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrater",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "OpenCrater — sponsor cards in Claude Code and Codex. Free, one command, opt out anytime.",
5
5
  "keywords": [
6
6
  "opencrater",