ethos-cli 0.7.0 → 0.7.1

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.
@@ -3,14 +3,14 @@ import { resolveAgentClientId } from "../lib/agent-clients.js";
3
3
  import { withClient } from "../lib/command-helpers.js";
4
4
  import { isJsonMode } from "../lib/config.js";
5
5
  import { createFindPeopleHandoff } from "../lib/find-people-flow.js";
6
- import { installEagerOpenHook, uninstallEagerOpenHook } from "../lib/hooks-installer.js";
6
+ import { ALL_HOOK_AGENTS, detectHookAgents, installEagerOpenHook, parseHookAgents, uninstallEagerOpenHook, } from "../lib/hooks-installer.js";
7
7
  import { openInBrowser } from "../lib/open-browser.js";
8
8
  import { printResult } from "../lib/output.js";
9
9
  const SKILL = "find-people-at-companies";
10
10
  const HOOK_EVENT = "UserPromptSubmit";
11
- // Explicit invocation only: the skill named in the prompt, with or without a
12
- // leading slash. Conservative on purpose so unrelated prompts never open a browser.
13
- const EAGER_OPEN_TRIGGER = /(^|\s)\/?find-people-at-companies\b/i;
11
+ // Explicit invocation only: Codex's skill-link shape must appear in the prompt.
12
+ // Mentions in prose, pasted transcripts, and debug discussion should no-op.
13
+ const EAGER_OPEN_TRIGGER = /\[\$find-people-at-companies\]\([^)]*\/find-people-at-companies\/SKILL\.md\)/i;
14
14
  export function registerHooks(program) {
15
15
  const hooks = program
16
16
  .command("hooks")
@@ -25,24 +25,24 @@ export function matchesEagerOpenTrigger(prompt) {
25
25
  function registerEagerOpen(hooks) {
26
26
  const eagerOpen = hooks
27
27
  .command("eager-open")
28
- .description(`${HOOK_EVENT} hook handler (Claude Code): when the ${SKILL} skill is invoked, pre-open the upload browser and inject the started handoff for the skill to reuse`);
28
+ .description(`${HOOK_EVENT} hook handler: when the ${SKILL} skill is invoked, create the upload handoff and inject it for the skill to reuse`);
29
29
  eagerOpen.action(async () => {
30
+ const prompt = readHookPrompt();
31
+ if (!matchesEagerOpenTrigger(prompt))
32
+ return; // not this skill - leave the prompt untouched
30
33
  try {
31
- const prompt = readHookPrompt();
32
- if (!matchesEagerOpenTrigger(prompt))
33
- return; // not this skill - leave the prompt untouched
34
- // Codex's upload is its agent-driven in-app Browser, which this hook can't
35
- // open; the skill drives Codex, so the hook is a no-op there.
36
- if (resolveAgentClientId("auto") === "codex")
37
- return;
38
34
  await withClient(eagerOpen, async (client, config) => {
39
- const handoff = await createFindPeopleHandoff(client, config, { agentClient: "claude-desktop" });
40
- openInBrowser(handoff.handoff_url);
41
- emitAdditionalContext(eagerOpenContext(handoff));
35
+ const clientId = resolveAgentClientId("auto");
36
+ const handoff = await createFindPeopleHandoff(client, config, { agentClient: clientId });
37
+ // Codex uploads in its in-app Browser, which only the agent can open.
38
+ // Shell clients get the latency win from opening the OS browser here.
39
+ if (clientId !== "codex")
40
+ openInBrowser(handoff.handoff_url);
41
+ emitAdditionalContext(eagerOpenContext(handoff, clientId));
42
42
  });
43
43
  }
44
- catch {
45
- // Never block or fail the user's prompt; the skill's own `flows start` is the fallback.
44
+ catch (error) {
45
+ emitAdditionalContext(eagerOpenFailureContext(error));
46
46
  }
47
47
  });
48
48
  }
@@ -60,13 +60,35 @@ function readHookPrompt() {
60
60
  return "";
61
61
  }
62
62
  }
63
- function eagerOpenContext(handoff) {
63
+ function eagerOpenContext(handoff, clientId) {
64
64
  const workspace = handoff.org_name ? ` in workspace "${handoff.org_name}"` : "";
65
- return (`Ethos find-people: the CSV upload browser is already opening${workspace} (pre-started by a hook). ` +
66
- `Reuse this flow when running the ${SKILL} skill - do NOT run \`ethos flows start\` again. ` +
67
- `handoff_token=${handoff.handoff_token}. ` +
68
- `Next: ask the user for their ICP and buying-signal brief while they upload, then run ` +
69
- `\`ethos flows wait ${handoff.handoff_token} --json\` to capture the uploaded table id.`);
65
+ const browserInstruction = clientId === "codex"
66
+ ? `Open upload_url in the Codex in-app Browser now.`
67
+ : `The upload browser is already opening in the OS browser.`;
68
+ return [
69
+ `ETHOS_FIND_PEOPLE_HANDOFF_READY`,
70
+ `This is the hook-created upload handoff for the current ${SKILL} request${workspace}.`,
71
+ `Do not say no hook handoff was injected.`,
72
+ `Do not run \`ethos flows start\` or create another handoff.`,
73
+ `If the user provided a local CLI path, the hook already used the installed hook command for this environment.`,
74
+ browserInstruction,
75
+ `handoff_token=${handoff.handoff_token}`,
76
+ `upload_url=${handoff.upload_url}`,
77
+ `agent_client=${handoff.agent_client}`,
78
+ `org_id=${handoff.org_id}`,
79
+ `org_name=${handoff.org_name}`,
80
+ `Next: ask the user for their ICP and buying-signal brief while they upload, then run \`ethos flows wait ${handoff.handoff_token} --json\` to capture the uploaded table id.`,
81
+ ].join("\n");
82
+ }
83
+ function eagerOpenFailureContext(error) {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ if (/missing api token/i.test(message)) {
86
+ return (`Ethos find-people: the eager handoff hook could not create an upload flow because the Ethos CLI is not authenticated. ` +
87
+ `Do NOT run \`ethos flows start\` before logging in; it will fail the same way. ` +
88
+ `Run \`ethos auth login --agent-client auto\`, then use the skill's \`ethos flows start find-people-at-companies --agent-client auto --json\` fallback for this turn.`);
89
+ }
90
+ return (`Ethos find-people: the eager handoff hook could not create an upload flow (${message}). ` +
91
+ `Continue with the skill fallback; if auth is missing, run \`ethos auth login --agent-client auto\` before \`ethos flows start\`.`);
70
92
  }
71
93
  function emitAdditionalContext(additionalContext) {
72
94
  process.stdout.write(JSON.stringify({
@@ -76,28 +98,33 @@ function emitAdditionalContext(additionalContext) {
76
98
  function registerInstall(hooks) {
77
99
  const install = hooks
78
100
  .command("install")
79
- .description("Register the find-people eager-open UserPromptSubmit hook in Claude Code (and prune any legacy Codex hook)");
101
+ .description("Register the find-people eager-open UserPromptSubmit hook in your agent config(s)")
102
+ .option("-a, --agents <list>", `comma-separated agents (default: auto-detect). Supported: ${ALL_HOOK_AGENTS.join(", ")}`);
80
103
  install.action(async () => {
81
- const { command, claude, codexPruned } = await installEagerOpenHook();
82
- const notes = [`Claude Code: ${claude.action} (${claude.path})`];
83
- if (codexPruned.action === "removed")
84
- notes.push(`removed legacy Codex hook (${codexPruned.path})`);
104
+ const agents = parseHookAgents(install.opts().agents) ?? detectHookAgents();
105
+ const { command, results } = await installEagerOpenHook({ agents });
85
106
  printHooksResult(install, {
86
- label: `Eager-open hook ${claude.action} for Claude Code (command: ${command})`,
87
- data: { command, claude, codex_pruned: codexPruned, notes },
107
+ label: results.length
108
+ ? `Eager-open hook installed for ${results.map((entry) => entry.agent).join(", ")} (command: ${command})`
109
+ : "No supported agents detected (claude-code, codex). Install an agent, then run `ethos hooks install`.",
110
+ data: { command, agents: results },
88
111
  });
89
112
  });
90
113
  }
91
114
  function registerUninstall(hooks) {
92
115
  const uninstall = hooks
93
116
  .command("uninstall")
94
- .description("Remove the find-people eager-open hook from Claude Code (and any legacy Codex hook)");
117
+ .description("Remove the find-people eager-open hook from your agent config(s)")
118
+ .option("-a, --agents <list>", `comma-separated agents (default: all). Supported: ${ALL_HOOK_AGENTS.join(", ")}`);
95
119
  uninstall.action(async () => {
96
- const { claude, codex } = await uninstallEagerOpenHook();
97
- const removed = [claude, codex].filter((entry) => entry.action === "removed");
120
+ const agents = parseHookAgents(uninstall.opts().agents);
121
+ const { results } = await uninstallEagerOpenHook({ agents });
122
+ const removed = results.reduce((total, entry) => total + entry.removed, 0);
98
123
  printHooksResult(uninstall, {
99
- label: removed.length ? `Removed the eager-open hook from ${removed.map((entry) => entry.path).join(", ")}` : "Nothing to remove.",
100
- data: { claude, codex },
124
+ label: removed
125
+ ? `Removed the eager-open hook from ${results.filter((entry) => entry.removed).map((entry) => entry.agent).join(", ")}`
126
+ : "Nothing to remove.",
127
+ data: { agents: results },
101
128
  });
102
129
  });
103
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"}
@@ -1,23 +1,39 @@
1
- export type HookFileResult = {
1
+ export type HookAgentName = "claude-code" | "codex";
2
+ export interface HookAgent {
3
+ name: HookAgentName;
4
+ displayName: string;
5
+ settingsFile(): string;
6
+ detect(): boolean;
7
+ }
8
+ export declare const HOOK_AGENTS: Record<HookAgentName, HookAgent>;
9
+ export declare const ALL_HOOK_AGENTS: HookAgentName[];
10
+ export type HookInstallResult = {
11
+ agent: HookAgentName;
2
12
  path: string;
3
- action: "installed" | "updated" | "removed" | "absent";
13
+ action: "installed" | "updated";
14
+ };
15
+ export type HookRemoveResult = {
16
+ agent: HookAgentName;
17
+ path: string;
18
+ removed: number;
4
19
  };
5
- export declare function claudeCodeDetected(): boolean;
6
- export declare function claudeSettingsPath(): string;
7
20
  /**
8
21
  * The command the hook runs. Bound to whichever CLI installs it: the dev CLI
9
22
  * sets ETHOS_CLI_COMMAND (so `make dev` points the hook at localhost), while a
10
23
  * normal `npm install` / global run has it unset and binds to prod `ethos`.
11
24
  */
12
25
  export declare function eagerOpenCommand(): string;
26
+ export declare function detectHookAgents(): HookAgentName[];
13
27
  export declare function installEagerOpenHook(options?: {
28
+ agents?: HookAgentName[];
14
29
  command?: string;
15
30
  }): Promise<{
16
31
  command: string;
17
- claude: HookFileResult;
18
- codexPruned: HookFileResult;
32
+ results: HookInstallResult[];
19
33
  }>;
20
- export declare function uninstallEagerOpenHook(): Promise<{
21
- claude: HookFileResult;
22
- codex: HookFileResult;
34
+ export declare function uninstallEagerOpenHook(options?: {
35
+ agents?: HookAgentName[];
36
+ }): Promise<{
37
+ results: HookRemoveResult[];
23
38
  }>;
39
+ export declare function parseHookAgents(value: string | undefined): HookAgentName[] | undefined;
@@ -2,23 +2,25 @@ import { existsSync } from "node:fs";
2
2
  import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { dirname, join } from "node:path";
5
- // The eager-open hook is Claude Code only. On Codex the CSV upload happens in its
6
- // agent-driven in-app Browser, which a hook cannot open, so a Codex hook would
7
- // only create a duplicate handoff — the find-people skill drives Codex itself.
8
- // ethos-cli <= 0.6.0 also installed a Codex hook; install prunes that legacy file.
5
+ export const HOOK_AGENTS = {
6
+ "claude-code": {
7
+ name: "claude-code",
8
+ displayName: "Claude Code",
9
+ settingsFile: () => join(process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude"), "settings.json"),
10
+ detect: () => existsSync(process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude")),
11
+ },
12
+ codex: {
13
+ name: "codex",
14
+ displayName: "Codex",
15
+ settingsFile: () => join(process.env.CODEX_HOME || join(homedir(), ".codex"), "hooks.json"),
16
+ detect: () => existsSync(process.env.CODEX_HOME || join(homedir(), ".codex")),
17
+ },
18
+ };
19
+ export const ALL_HOOK_AGENTS = Object.keys(HOOK_AGENTS);
9
20
  const HOOK_EVENT = "UserPromptSubmit";
10
21
  // Substring identifying our handler, so install/uninstall stay idempotent and
11
22
  // migrate an older binding (e.g. a dev-CLI path) in place.
12
23
  const HOOK_COMMAND_MARKER = "hooks eager-open";
13
- export function claudeCodeDetected() {
14
- return existsSync(process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude"));
15
- }
16
- export function claudeSettingsPath() {
17
- return join(process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude"), "settings.json");
18
- }
19
- function legacyCodexHooksPath() {
20
- return join(process.env.CODEX_HOME || join(homedir(), ".codex"), "hooks.json");
21
- }
22
24
  /**
23
25
  * The command the hook runs. Bound to whichever CLI installs it: the dev CLI
24
26
  * sets ETHOS_CLI_COMMAND (so `make dev` points the hook at localhost), while a
@@ -27,30 +29,27 @@ function legacyCodexHooksPath() {
27
29
  export function eagerOpenCommand() {
28
30
  return `${process.env.ETHOS_CLI_COMMAND || "ethos"} hooks eager-open`;
29
31
  }
32
+ export function detectHookAgents() {
33
+ return ALL_HOOK_AGENTS.filter((name) => HOOK_AGENTS[name].detect());
34
+ }
30
35
  export async function installEagerOpenHook(options = {}) {
31
36
  const command = options.command ?? eagerOpenCommand();
32
- const claude = await mergeHook(claudeSettingsPath(), command);
33
- // Best-effort: remove any legacy Codex hook so it can't fire a duplicate
34
- // handoff there. Never let a malformed Codex file fail the Claude install.
35
- let codexPruned;
36
- try {
37
- codexPruned = await removeHook(legacyCodexHooksPath());
37
+ const agents = options.agents ?? detectHookAgents();
38
+ const results = [];
39
+ for (const name of agents) {
40
+ const merged = await mergeHook(HOOK_AGENTS[name].settingsFile(), command);
41
+ results.push({ agent: name, ...merged });
38
42
  }
39
- catch {
40
- codexPruned = { path: legacyCodexHooksPath(), action: "absent" };
41
- }
42
- return { command, claude, codexPruned };
43
+ return { command, results };
43
44
  }
44
- export async function uninstallEagerOpenHook() {
45
- const claude = await removeHook(claudeSettingsPath());
46
- let codex;
47
- try {
48
- codex = await removeHook(legacyCodexHooksPath());
49
- }
50
- catch {
51
- codex = { path: legacyCodexHooksPath(), action: "absent" };
45
+ export async function uninstallEagerOpenHook(options = {}) {
46
+ const agents = options.agents ?? ALL_HOOK_AGENTS;
47
+ const results = [];
48
+ for (const name of agents) {
49
+ const removed = await removeHook(HOOK_AGENTS[name].settingsFile());
50
+ results.push({ agent: name, ...removed });
52
51
  }
53
- return { claude, codex };
52
+ return { results };
54
53
  }
55
54
  async function mergeHook(path, command) {
56
55
  const config = await readJsonObject(path);
@@ -73,11 +72,11 @@ async function mergeHook(path, command) {
73
72
  }
74
73
  async function removeHook(path) {
75
74
  if (!existsSync(path))
76
- return { path, action: "absent" };
75
+ return { path, removed: 0 };
77
76
  const config = await readJsonObject(path);
78
77
  const list = config.hooks?.[HOOK_EVENT];
79
78
  if (!config.hooks || !list)
80
- return { path, action: "absent" };
79
+ return { path, removed: 0 };
81
80
  let removed = 0;
82
81
  const kept = [];
83
82
  for (const group of list) {
@@ -92,7 +91,7 @@ async function removeHook(path) {
92
91
  else
93
92
  delete config.hooks[HOOK_EVENT];
94
93
  await writeJsonFile(path, config);
95
- return { path, action: removed ? "removed" : "absent" };
94
+ return { path, removed };
96
95
  }
97
96
  async function readJsonObject(path) {
98
97
  let raw;
@@ -134,4 +133,16 @@ async function writeJsonFile(path, value) {
134
133
  throw error;
135
134
  }
136
135
  }
136
+ export function parseHookAgents(value) {
137
+ if (!value)
138
+ return undefined;
139
+ const parsed = [];
140
+ for (const raw of value.split(",").map((part) => part.trim()).filter(Boolean)) {
141
+ if (ALL_HOOK_AGENTS.includes(raw))
142
+ parsed.push(raw);
143
+ else
144
+ throw new Error(`unknown hook agent: ${raw} (supported: ${ALL_HOOK_AGENTS.join(", ")})`);
145
+ }
146
+ return parsed.length ? parsed : undefined;
147
+ }
137
148
  //# sourceMappingURL=hooks-installer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks-installer.js","sourceRoot":"","sources":["../../src/lib/hooks-installer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,kFAAkF;AAClF,+EAA+E;AAC/E,+EAA+E;AAC/E,mFAAmF;AACnF,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACtC,8EAA8E;AAC9E,2DAA2D;AAC3D,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAQ/C,MAAM,UAAU,kBAAkB;IAChC,OAAO,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,eAAe,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,oBAAoB;IAC3B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,mBAAmB,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAAgC,EAAE;IAElC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC;IAC9D,yEAAyE;IACzE,2EAA2E;IAC3E,IAAI,WAA2B,CAAC;IAChC,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACtD,IAAI,KAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,OAAe;IACpD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;IAE3C,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;YACtC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACrF,KAAK,CAAC,IAAI,GAAG,SAAS,CAAC;gBACvB,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;gBACxB,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAEnE,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC7D,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACzD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAE9D,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAChC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAC/F,CAAC;QACF,OAAO,IAAI,UAAU,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/C,IAAI,QAAQ,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,IAAI,CAAC,MAAM;QAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;;QAC5C,OAAO,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAErC,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC1D,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC,CAAC,4BAA4B;QAC/F,MAAM,KAAK,CAAC,CAAC,2DAA2D;IAC1E,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IAC3B,8EAA8E;IAC9E,gFAAgF;IAChF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,MAAqB,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,sBAAsB,IAAI,qBAAqB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,CACxI,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,KAAc;IACvD,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,8EAA8E;IAC9E,gFAAgF;IAChF,iFAAiF;IACjF,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;IACvD,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"hooks-installer.js","sourceRoot":"","sources":["../../src/lib/hooks-installer.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
- import { claudeCodeDetected, installEagerOpenHook } from "../lib/hooks-installer.js";
2
- // Runs on `npm install`. Re-binds the Claude Code find-people eager-open hook to
3
- // the CLI being installed — for a normal global install that is prod `ethos`, so
4
- // installing through npm always returns the hook to production (a `make dev` run
5
- // rebinds it to the dev CLI for local testing). Also prunes any legacy Codex hook.
1
+ import { detectHookAgents, installEagerOpenHook } from "../lib/hooks-installer.js";
2
+ // Runs on `npm install`. Re-binds the find-people eager-open hook to the CLI
3
+ // being installed — for a normal global install that is prod `ethos`, so
4
+ // installing through npm always returns hooks to production (a `make dev` run
5
+ // rebinds them to the dev CLI for local testing).
6
6
  async function main() {
7
7
  if (process.env.ETHOS_SKIP_HOOKS || process.env.ETHOS_SKIP_SKILLS) {
8
8
  process.stderr.write("ethos: skipping eager-open hook install.\n");
@@ -13,13 +13,11 @@ async function main() {
13
13
  process.stderr.write("ethos: detected sudo install - skipping hook install. Run `ethos hooks install` as your user.\n");
14
14
  return;
15
15
  }
16
- if (!claudeCodeDetected())
17
- return; // the hook is Claude Code only
18
- const { command, claude, codexPruned } = await installEagerOpenHook();
19
- let line = `ethos: eager-open hook ${claude.action} for Claude Code (command: ${command})`;
20
- if (codexPruned.action === "removed")
21
- line += "; removed legacy Codex hook";
22
- process.stderr.write(line + "\n");
16
+ const agents = detectHookAgents();
17
+ if (!agents.length)
18
+ return;
19
+ const { command, results } = await installEagerOpenHook({ agents });
20
+ process.stderr.write(`ethos: eager-open hook installed for ${results.map((entry) => entry.agent).join(", ")} (command: ${command})\n`);
23
21
  }
24
22
  main().catch((err) => {
25
23
  process.stderr.write(`ethos: hook install failed (continuing) - ${err instanceof Error ? err.message : String(err)}\nRun \`ethos hooks install\` manually after install completes.\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../src/scripts/install-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAErF,iFAAiF;AACjF,iFAAiF;AACjF,iFAAiF;AACjF,mFAAmF;AACnF,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAClE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,IAAI,GAAG,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iGAAiG,CAClG,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,kBAAkB,EAAE;QAAE,OAAO,CAAC,+BAA+B;IAElE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,oBAAoB,EAAE,CAAC;IACtE,IAAI,IAAI,GAAG,0BAA0B,MAAM,CAAC,MAAM,8BAA8B,OAAO,GAAG,CAAC;IAC3F,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,IAAI,6BAA6B,CAAC;IAC5E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6CACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,mEAAmE,CACpE,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../src/scripts/install-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEnF,6EAA6E;AAC7E,yEAAyE;AACzE,8EAA8E;AAC9E,kDAAkD;AAClD,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAClE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,IAAI,GAAG,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iGAAiG,CAClG,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO;IAE3B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wCAAwC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,OAAO,KAAK,CACjH,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6CACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,mEAAmE,CACpE,CAAC;AACJ,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ethos-cli",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Commander-based CLI for Ethos table operations",
5
5
  "homepage": "https://github.com/cluster-software/ethos#readme",
6
6
  "repository": {
@@ -18,21 +18,22 @@ The Ethos CLI (`ethos`) is required. If `ethos` is not installed or not on
18
18
  npm install -g ethos-cli@latest --prefer-online
19
19
  ```
20
20
 
21
- If a command fails because the CLI is not authenticated, run
21
+ If a CLI command fails because the CLI is not authenticated, run
22
22
  `ethos auth login --agent-client auto`, then retry. Do not run a separate
23
- `ethos auth status` first; the flow commands already require auth and surface a
24
- clear error when login is needed.
23
+ `ethos auth status` first; the flow and table commands already require auth and
24
+ surface a clear error when login is needed.
25
25
 
26
26
  ## Flow
27
27
 
28
28
  Keep CSV upload in the browser-based Ethos product flow:
29
29
 
30
- 1. Get the upload flow. On Claude Code a `UserPromptSubmit` hook may have already started one if the conversation has an injected `handoff_token`, REUSE it and do NOT run `ethos flows start`. Otherwise run `ethos flows start find-people-at-companies --agent-client auto --json` and save `handoff_token` and `upload_url`. Add `--open` only on shell clients (Claude Code, Cursor) to open the OS browser; on Codex do NOT pass `--open`.
31
- 2. Open `upload_url` in the right surface. On Codex, open it in the in-app Browser — the default surface (OS-open, via `--open` or `open <url>`, is only a fallback if the in-app Browser is not working). On Claude Code and other shell clients, `--open` already opened the OS browser.
32
- 3. Immediately ask the user for ICP, buying signals, person targets, and max contacts while they upload.
33
- 4. Capture the uploaded table id with `ethos flows wait "$HANDOFF_TOKEN" --json`. Do not ask the user to paste the table URL unless `flows wait` cannot recover.
34
- 5. Once the brief is ready, inspect the table, create the `people_sourcing` agent, and create the agent-client-created column with the CLI.
35
- 6. Run the column for the FIRST 3 ROWS ONLY. Tell the user you're running for 3 rows to see if the results are good. If yes, the next step is to run on the whole table. If not, refine the agent based on their feedback so it finds the right people.
30
+ 1. Use the hook-created upload flow first. If the context contains `ETHOS_FIND_PEOPLE_HANDOFF_READY`, that is the injected Ethos handoff for this request. REUSE its `handoff_token` and `upload_url`; do NOT run `ethos flows start`, even if the user also provided a local CLI path. On Codex, immediately open `upload_url` in the in-app Browser. On Claude Code and other shell clients, the hook already opened the OS browser.
31
+ 2. If the hook injected an auth failure, do NOT try `ethos flows start` first. Run `ethos auth login --agent-client auto`, then use the `flows start` fallback for this turn.
32
+ 3. Only if no hook handoff was injected, run the `flows start` fallback and save `handoff_token` and `upload_url`. Add `--open` only on shell clients (Claude Code, Cursor) to open the OS browser; on Codex do NOT pass `--open`.
33
+ 4. Immediately ask the user for ICP, buying signals, person targets, and max contacts while they upload.
34
+ 5. Capture the uploaded table id with `ethos flows wait "$HANDOFF_TOKEN" --json`. Do not ask the user to paste the table URL unless `flows wait` cannot recover.
35
+ 6. Once the brief is ready, inspect the table, create the `people_sourcing` agent, and create the agent-client-created column with the CLI.
36
+ 7. Run the column for the FIRST 3 ROWS ONLY. Tell the user you're running for 3 rows to see if the results are good. If yes, the next step is to run on the whole table. If not, refine the agent based on their feedback so it finds the right people.
36
37
 
37
38
  Do not run `ethos tables import-csv` for this skill unless the user explicitly
38
39
  asks for a CLI-only/non-browser fallback. The browser upload is part of the
@@ -40,29 +41,50 @@ product flow and must not be replaced by CLI import.
40
41
 
41
42
  ## Authenticate
42
43
 
43
- Authentication is handled implicitly by `flows start`; do not run a separate
44
- `ethos auth status` pre-check. Only if `flows start` reports that the CLI is not
45
- authenticated, run:
44
+ Authentication is handled implicitly by the hook or by the fallback
45
+ `flows start`; do not run a separate `ethos auth status` pre-check. Only if a
46
+ flow/table command reports that the CLI is not authenticated, run:
46
47
 
47
48
  ```sh
48
49
  ethos auth login --agent-client auto
49
50
  ```
50
51
 
51
- then re-run the `flows start` command. The browser claim flow handles production
52
- auth. Do not ask for API tokens unless the user explicitly wants a non-browser
53
- setup.
52
+ then retry the failed command. The browser claim flow handles production auth.
53
+ Do not ask for API tokens unless the user explicitly wants a non-browser setup.
54
54
 
55
55
  ## Start Upload Flow
56
56
 
57
- **Reuse a pre-started flow first (Claude Code).** On Claude Code a
58
- `UserPromptSubmit` hook may have already started the flow and injected a
59
- `handoff_token` ("upload browser is already opening"). If so, do NOT run
60
- `ethos flows start` again — reuse that `handoff_token`: skip to the brief and
61
- then `ethos flows wait <handoff_token>`. The hook does not run on Codex, so there
62
- you always run the command below.
57
+ **Use the hook handoff first.** A `UserPromptSubmit` hook may have already
58
+ started the flow and injected an `ETHOS_FIND_PEOPLE_HANDOFF_READY` block with a
59
+ `handoff_token` plus `upload_url`.
63
60
 
64
- Otherwise start the handoff through the CLI abstraction instead of constructing
65
- client-specific URLs:
61
+ - On Codex, the hook cannot open the in-app Browser itself. Open the injected
62
+ `upload_url` in the in-app Browser immediately, then ask the brief.
63
+ - On Claude Code, Cursor, or another shell client, the hook may have already
64
+ opened the OS browser. Reuse the injected `handoff_token`, then ask the brief.
65
+
66
+ If you see `ETHOS_FIND_PEOPLE_HANDOFF_READY`, do NOT claim that no hook handoff
67
+ was injected, and do NOT run `ethos flows start` again. Save the injected
68
+ `handoff_token`, `upload_url`, `agent_client`, `org_id`, and `org_name`; later
69
+ run `ethos flows wait <handoff_token>`. Do not mention hooks, injected context,
70
+ handoff tokens, or hook handoffs in user-facing messages.
71
+
72
+ If the user provides a local CLI path and `ETHOS_FIND_PEOPLE_HANDOFF_READY` is
73
+ also present, the hook has already prepared the local handoff. Use the injected
74
+ URL; do not run the local CLI path until `flows wait`.
75
+
76
+ If the hook injected an auth failure, do NOT run `ethos flows start` before
77
+ logging in. It will fail with the same missing-token error. Run:
78
+
79
+ ```sh
80
+ ethos auth login --agent-client auto
81
+ ```
82
+
83
+ then use the fallback `flows start` command below for this turn. The hook will
84
+ prepare the handoff on future turns once the CLI auth is valid.
85
+
86
+ Only when no hook handoff was injected, start the handoff through the CLI
87
+ fallback instead of constructing client-specific URLs:
66
88
 
67
89
  ```sh
68
90
  ethos flows start find-people-at-companies --agent-client auto --json
@@ -94,18 +116,19 @@ session.
94
116
  ## Open Browser Upload
95
117
 
96
118
  Open the upload page in the browser surface for this client. Use `upload_url`
97
- from the reused hook handoff (Claude Code) or from the `flows start` response.
119
+ from the reused hook handoff or from the fallback `flows start` response.
98
120
 
99
121
  - **Codex**: open `upload_url` in the **in-app Browser** — the default and only
100
122
  surface you open. Do NOT also OS-open it. Only if the user says the in-app
101
123
  Browser is not working, fall back to OS-opening it (`open "$UPLOAD_URL"`). Do
102
124
  not click `Import CSV` or take other browser actions after navigating unless
103
125
  the user asks for help.
104
- - **Claude Code, Cursor, or another shell-based client**: `--open` already
105
- opened the OS browser. If it failed (for example, no desktop session), run
106
- `open "$UPLOAD_URL"` yourself, and only fall back to MCP browser tools, Chrome
107
- connectors, or in-app browser plugins if that also fails. If every option
108
- fails, show the URL and ask the user to open it.
126
+ - **Claude Code, Cursor, or another shell-based client**: the hook or fallback
127
+ `--open` already opened the OS browser. If it failed (for example, no desktop
128
+ session), run `open "$UPLOAD_URL"` yourself, and only fall back to MCP browser
129
+ tools, Chrome connectors, in-app browser plugins, or other browser automation
130
+ connectors if that also fails. If every option fails, show the URL and ask the
131
+ user to open it.
109
132
 
110
133
  Right after the browser opens, immediately ask `response.next_prompt`. If the
111
134
  flow response is not available for some reason, ask:
@@ -130,7 +153,7 @@ returns `response.table_id` and `response.org_id`. Save both.
130
153
  says they have uploaded — so the table is usually already there and the
131
154
  command returns right away.
132
155
  - If it times out because the user has not uploaded yet, just re-run the same
133
- command. The upload window is about 10 minutes from `flows start`.
156
+ command. The upload window is about 10 minutes from the handoff creation.
134
157
  - Only fall back if `flows wait` reports the flow expired or keeps timing out:
135
158
  if you can inspect the browser URL, the completed shape is
136
159
  `/tables/<TABLE_ID>?agent_flow=find-people-at-companies&uploaded=1&...`;
@@ -297,6 +320,10 @@ user asks for them or you are actively debugging.
297
320
  - While you execute the flow, keep communication simple and approachable. Avoid
298
321
  explaining UI behavior that should happen automatically when everything is
299
322
  working. Do not mention internal Ethos concepts unless explicitly necessary.
323
+ - Do not disclose whether upload context came from hooks, injected context, or
324
+ `ethos flows start`. Treat that as implementation detail. When opening the
325
+ upload page, say something general like: "I'm opening a window for you to
326
+ upload a company list."
300
327
 
301
328
  For example, instead of
302
329