@aicopycoders/exodus 2026.6.2900-beta.4 → 2026.6.2900-beta.6

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.
@@ -50,6 +50,7 @@ export type IdeaAction = {
50
50
  kind: "error";
51
51
  message: string;
52
52
  };
53
+ export declare function runsWillPauseAtHooks(stopAtHooks: boolean | undefined, savedPref: "manual" | "auto" | null): boolean;
53
54
  export declare function resolveIdeaAction(positionals: string[], flags: Record<string, string | boolean>): IdeaAction;
54
55
  export declare function run(flags: Record<string, string | boolean>): Promise<void>;
55
56
  export {};
@@ -67,6 +67,15 @@ function resolveStopAtHooks(flags) {
67
67
  return false;
68
68
  return undefined;
69
69
  }
70
+ export function runsWillPauseAtHooks(stopAtHooks, savedPref) {
71
+ if (typeof stopAtHooks === "boolean")
72
+ return stopAtHooks;
73
+ return savedPref === "manual";
74
+ }
75
+ async function fetchSavedHookPref() {
76
+ const res = await apiGet("/api/v2/genesis/hook-pref");
77
+ return res.ok ? (res.data.preference ?? null) : null;
78
+ }
70
79
  function printHookPauseHint(dispatched) {
71
80
  if (dispatched.length === 0)
72
81
  return;
@@ -250,7 +259,8 @@ export async function run(flags) {
250
259
  }
251
260
  for (const d of result.dispatched)
252
261
  console.log(` ✓ banked ${d.key} → Genesis run ${d.runId}`);
253
- if (action.stopAtHooks === true)
262
+ const willPause = runsWillPauseAtHooks(action.stopAtHooks, action.stopAtHooks === undefined ? await fetchSavedHookPref() : null);
263
+ if (willPause)
254
264
  printHookPauseHint(result.dispatched);
255
265
  console.log("");
256
266
  console.log("Track them: exodus idea list (status flips to 'written' with a doc link)");
@@ -335,12 +345,15 @@ export async function run(flags) {
335
345
  }
336
346
  const dispatched = res.data.dispatched ?? [];
337
347
  const skipped = res.data.skipped ?? [];
338
- console.log(`Dispatched ${dispatched.length} run(s) — fire-and-forget.`);
348
+ const willPause = runsWillPauseAtHooks(action.stopAtHooks, action.stopAtHooks === undefined ? await fetchSavedHookPref() : null);
349
+ console.log(willPause
350
+ ? `Dispatched ${dispatched.length} run(s).`
351
+ : `Dispatched ${dispatched.length} run(s) — fire-and-forget.`);
339
352
  for (const d of dispatched)
340
353
  console.log(` ${d.key} → run ${d.runId}`);
341
354
  for (const s of skipped)
342
355
  console.log(` skipped ${s.key}: ${s.reason}`);
343
- if (action.stopAtHooks === true)
356
+ if (willPause)
344
357
  printHookPauseHint(dispatched);
345
358
  console.log("");
346
359
  console.log("Track them: exodus idea list (status flips to 'written' with a doc link)");
@@ -1,4 +1,4 @@
1
- import { PROVIDER_ENV_MAP, fetchRemoteKeys, mapKeysToEnvVars, resolveEnvFilePath, upsertEnvVars, } from "../lib/keys-sync.js";
1
+ import { PROVIDER_ENV_MAP, SERVER_RESOLVED_PROVIDERS, fetchRemoteKeys, mapKeysToEnvVars, resolveEnvFilePath, upsertEnvVars, } from "../lib/keys-sync.js";
2
2
  export const helpText = `
3
3
  exodus keys — sync your provider API keys from the dashboard to local .env
4
4
 
@@ -24,6 +24,7 @@ const PROVIDER_LABEL = {
24
24
  openrouter: "OpenRouter",
25
25
  elevenlabs: "ElevenLabs",
26
26
  kie: "Kie.ai",
27
+ imgflip: "Imgflip",
27
28
  };
28
29
  async function status() {
29
30
  let remote;
@@ -46,6 +47,12 @@ async function status() {
46
47
  const local = localSet ? "local ✓" : "local —";
47
48
  console.log(` ${label} ${dash} ${local} (${envName})`);
48
49
  }
50
+ for (const provider of SERVER_RESOLVED_PROVIDERS) {
51
+ const inDashboard = provider in remote.keys;
52
+ const label = (PROVIDER_LABEL[provider] ?? provider).padEnd(11);
53
+ const dash = inDashboard ? "dashboard ✓" : "dashboard —";
54
+ console.log(` ${label} ${dash} server-side (Settings → Keys; no .env)`);
55
+ }
49
56
  if (remote.failed.length) {
50
57
  console.log(`\n⚠ Could not decrypt: ${remote.failed.join(", ")} — re-save in the dashboard.`);
51
58
  }
@@ -69,7 +76,7 @@ async function pull() {
69
76
  }
70
77
  return;
71
78
  }
72
- const { vars, skipped } = mapKeysToEnvVars(remote.keys);
79
+ const { vars, serverResolved, skipped } = mapKeysToEnvVars(remote.keys);
73
80
  const envPath = resolveEnvFilePath();
74
81
  const results = upsertEnvVars(envPath, vars);
75
82
  const added = results.filter((r) => r.action === "added").map((r) => r.name);
@@ -82,6 +89,9 @@ async function pull() {
82
89
  console.log(` updated: ${updated.join(", ")}`);
83
90
  if (unchanged.length)
84
91
  console.log(` unchanged: ${unchanged.join(", ")}`);
92
+ if (serverResolved.length) {
93
+ console.log(` dashboard: ${serverResolved.join(", ")} — used server-side from Settings → Keys; no .env entry needed.`);
94
+ }
85
95
  if (skipped.length) {
86
96
  console.log(` skipped: ${skipped.join(", ")} (no known env var mapping)`);
87
97
  }
@@ -1,4 +1,5 @@
1
1
  export declare const PROVIDER_ENV_MAP: Record<string, string>;
2
+ export declare const SERVER_RESOLVED_PROVIDERS: Set<string>;
2
3
  export interface RemoteKeys {
3
4
  keys: Record<string, string>;
4
5
  failed: string[];
@@ -12,5 +13,6 @@ export interface UpsertResult {
12
13
  export declare function upsertEnvVars(filePath: string, vars: Record<string, string>): UpsertResult[];
13
14
  export declare function mapKeysToEnvVars(keys: Record<string, string>): {
14
15
  vars: Record<string, string>;
16
+ serverResolved: string[];
15
17
  skipped: string[];
16
18
  };
@@ -8,6 +8,7 @@ export const PROVIDER_ENV_MAP = {
8
8
  elevenlabs: "ELEVENLABS_API_KEY",
9
9
  kie: "KIE_API_KEY",
10
10
  };
11
+ export const SERVER_RESOLVED_PROVIDERS = new Set(["imgflip"]);
11
12
  export async function fetchRemoteKeys() {
12
13
  const res = await apiGetDashboard("/api/settings/keys");
13
14
  if (!res.ok) {
@@ -70,15 +71,18 @@ export function upsertEnvVars(filePath, vars) {
70
71
  }
71
72
  export function mapKeysToEnvVars(keys) {
72
73
  const vars = {};
74
+ const serverResolved = [];
73
75
  const skipped = [];
74
76
  for (const [provider, value] of Object.entries(keys)) {
75
77
  const envName = PROVIDER_ENV_MAP[provider];
76
78
  if (envName)
77
79
  vars[envName] = value;
80
+ else if (SERVER_RESOLVED_PROVIDERS.has(provider))
81
+ serverResolved.push(provider);
78
82
  else
79
83
  skipped.push(provider);
80
84
  }
81
- return { vars, skipped };
85
+ return { vars, serverResolved, skipped };
82
86
  }
83
87
  function formatEnvValue(value) {
84
88
  if (/[\s#'"]/.test(value)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicopycoders/exodus",
3
- "version": "2026.6.2900-beta.4",
3
+ "version": "2026.6.2900-beta.6",
4
4
  "description": "CLI + Claude Code skills for the Copycoders Exodus ad pipeline",
5
5
  "repository": {
6
6
  "type": "git",