@aicopycoders/exodus 2026.6.2400 → 2026.6.2700-beta.2

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.
@@ -92,6 +92,9 @@ Save to `/tmp/genesis-seeds.txt` (one per line, `#` comments allowed), or pass `
92
92
  **Pass count is the user's knob** — if they didn't specify, surface a quick menu (1 pass / 2 variants recommended · 2 passes / 4 variants · more) rather than assuming. Always `run_in_background: true` — these runs are past the 10-min foreground cap.
93
93
 
94
94
  ```bash
95
+ # Resolve hook mode FIRST (see "Hook selection mode" below) — these commands
96
+ # assume a saved default exists, else add --stop-at-hooks or --auto-hooks or they error.
97
+
95
98
  # Default — 1 pass per bot = 2 variants (1 Mario × Brand + 1 Infeed × Brand):
96
99
  npx @aicopycoders/exodus genesis run --brief "<brief>" --awareness <level>
97
100
 
@@ -110,12 +113,17 @@ npx @aicopycoders/exodus genesis run --brief "<brief>" --awareness <level> --aut
110
113
 
111
114
  `--brief` accepts inline text or a file path. `--passes <n>` (1–5) is the friendly knob; `--variants <n>` (1–10) is an advanced raw-total override that wins if both are given.
112
115
 
113
- **Hook Selection Mode:**
114
- The pipeline can pause after Genesis generates hooks, allowing the user to pick which hooks to keep before writing body copy. This is controlled by a persisted per-user preference (manual or auto-select).
116
+ **Hook selection mode — REQUIRED gate before EVERY run (do not skip):**
117
+ The pipeline can pause after hook generation so the user picks which hooks become body copy — the human quality gate. You MUST resolve the mode **before** firing a run. A `genesis run` with **no** `--stop-at-hooks`/`--auto-hooks` **and** no saved preference now **hard-errors** (`Hook-selection preference not set`) **by design** — so the gate can't be silently skipped. If you see that error, you skipped this step; do it now.
118
+
119
+ Resolve it in this order, every time, BEFORE you run:
120
+ 1. **Check the saved default:** run `npx @aicopycoders/exodus genesis hook-pref` (no argument). It prints `manual`, `auto`, or `unset` on the first line.
121
+ 2. **If it prints `manual` or `auto`:** just fire the run — the saved default applies, no flag needed.
122
+ 3. **If it prints `unset`:** STOP and ask the user once, plainly — *"Want to choose the hooks yourself before I write the copy, or have me auto-pick and write straight through?"* Then fire the run with the matching flag (`--stop-at-hooks` = they choose, `--auto-hooks` = auto), and after it starts, offer to save it as their default so you never ask again: `npx @aicopycoders/exodus genesis hook-pref <manual|auto>`. **Do NOT fire the run before they answer.**
115
123
 
116
- - **`--stop-at-hooks`** — pause after hook generation. The run lands in `awaiting_hook_selection` status and the CLI prints a dashboard URL. The user reviews and picks hooks on the run-detail page; the pipeline then continues automatically to body-copy generation.
117
- - **`--auto-hooks`** — force auto-select for this run (overrides a saved "manual" default). The pipeline auto-computes the strongest hooks and runs straight through without pausing.
118
- - **Saved preference** — the first time a user runs Genesis (or when no preference is saved), you should ask once: *"Want to choose the hooks yourself, or have me auto-pick and write straight through?"* Then run with `--stop-at-hooks` (manual mode) or `--auto-hooks` (auto mode), and after reporting the result, offer to save the choice with `npx @aicopycoders/exodus genesis hook-pref <manual|auto>` so you don't ask again. If the user has already set a preference via `hook-pref`, skip the question and just run with the saved default.
124
+ Flags:
125
+ - **`--stop-at-hooks`** — pause after hook generation. The run lands in `awaiting_hook_selection` and the CLI prints a dashboard URL; the user picks hooks on the run-detail page and the pipeline continues automatically to body copy.
126
+ - **`--auto-hooks`** — auto-pick the strongest hooks and write straight through (also overrides a saved "manual" default for this one run).
119
127
 
120
128
  > "Genesis run started at problem-aware — 1 pass per bot (2 variants: Mario × Brand + Infeed × Brand). I'll surface the Doc when it lands."
121
129
 
@@ -122,6 +122,8 @@ Skip the menu only if the user already said how many ("just give me two", "run a
122
122
 
123
123
  Hand off to the `exodus-genesis` skill — it owns the run (double-pass hooks, the built-in 15-point QA, the editing menu). Always background it; even the default run is ~12–15 min, past the 10-min foreground cap.
124
124
 
125
+ **Before firing, resolve the hook-selection gate** (the `exodus-genesis` skill's "Hook selection mode" step): run `npx @aicopycoders/exodus genesis hook-pref` — if it prints `unset`, ask the user *"choose the hooks yourself, or auto-pick and write straight through?"* and pass `--stop-at-hooks` or `--auto-hooks` accordingly (offer to save the choice). A run with no flag and no saved default hard-errors by design — don't skip this.
126
+
125
127
  ```bash
126
128
  # Default — 1 pass per bot = 2 variants:
127
129
  npx @aicopycoders/exodus genesis run --brief "<brief>" --awareness <level>
@@ -446,8 +446,24 @@ async function waitForGenesisRun(runId) {
446
446
  async function runHookPref() {
447
447
  const positionals = parsePositional();
448
448
  const pref = positionals[1];
449
+ if (pref === undefined) {
450
+ const res = await apiGet("/api/v2/genesis/hook-pref");
451
+ if (!res.ok) {
452
+ console.log(`Error: ${res.data.error ?? "Unknown error"}`);
453
+ process.exit(1);
454
+ }
455
+ const cur = res.data.preference ?? null;
456
+ if (cur === null) {
457
+ console.log("unset");
458
+ console.log("No saved hook preference. Runs require --stop-at-hooks or --auto-hooks until one is set.");
459
+ }
460
+ else {
461
+ console.log(cur);
462
+ }
463
+ return;
464
+ }
449
465
  if (pref !== "manual" && pref !== "auto") {
450
- console.error('Usage: exodus genesis hook-pref <manual|auto>');
466
+ console.error('Usage: exodus genesis hook-pref [manual|auto] (no arg prints the current value)');
451
467
  console.error(' manual Pause each run at hook selection so you choose hooks.');
452
468
  console.error(' auto Skip hook selection and let the pipeline pick automatically.');
453
469
  process.exit(1);
package/package.json CHANGED
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "@aicopycoders/exodus",
3
- "version": "2026.6.2400",
3
+ "version": "2026.6.2700-beta.2",
4
4
  "description": "CLI + Claude Code skills for the Copycoders Exodus ad pipeline",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/aicopycoders/exodus.git"
8
+ },
9
+ "homepage": "https://github.com/aicopycoders/exodus#readme",
5
10
  "type": "module",
6
11
  "bin": {
7
- "exodus": "./dist/bin/exodus.js"
12
+ "exodus": "dist/bin/exodus.js"
8
13
  },
9
- "files": ["dist", "assets"],
14
+ "files": [
15
+ "dist",
16
+ "assets"
17
+ ],
10
18
  "engines": {
11
19
  "node": ">=20"
12
20
  },
@@ -1,12 +0,0 @@
1
- # Genesis Bots credentials. Keep this file private — never commit or share it.
2
- # Easiest: replace this ENTIRE file with what the portal's "Copy .env" button
3
- # gives you (https://genesis.copycoders.ai/portal), then add your provider key.
4
-
5
- GENESIS_BASE_URL=https://gas.copycoders.ai/api/v1
6
- GENESIS_API_KEY=gen_your_key_here
7
-
8
- # Your provider key (you pay usage). Use ONE of these — match the name to your key:
9
- # Anthropic → ANTHROPIC_API_KEY=sk-ant-...
10
- # OpenRouter → OPENROUTER_API_KEY=sk-or-...
11
- # (`npx @aicopycoders/exodus keys pull` writes these names for you from the dashboard.)
12
- ANTHROPIC_API_KEY=sk-ant-your_provider_key_here
@@ -1 +0,0 @@
1
- export {};
@@ -1,12 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { buildBriefBody } from "../genesis.js";
3
- describe("buildBriefBody stopAtHooks", () => {
4
- it("omits stopAtHooks when unset", () => {
5
- const b = buildBriefBody("brief text", { awarenessLevel: "problem-aware" });
6
- expect("stopAtHooks" in b).toBe(false);
7
- });
8
- it("includes stopAtHooks:true when set", () => {
9
- const b = buildBriefBody("brief text", { awarenessLevel: "problem-aware", stopAtHooks: true });
10
- expect(b.stopAtHooks).toBe(true);
11
- });
12
- });