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.
- package/dist/commands/hooks.js +62 -35
- package/dist/commands/hooks.js.map +1 -1
- package/dist/lib/hooks-installer.d.ts +25 -9
- package/dist/lib/hooks-installer.js +46 -35
- package/dist/lib/hooks-installer.js.map +1 -1
- package/dist/scripts/install-hooks.js +10 -12
- package/dist/scripts/install-hooks.js.map +1 -1
- package/package.json +1 -1
- package/skills/find-people-at-companies.md +57 -30
package/dist/commands/hooks.js
CHANGED
|
@@ -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:
|
|
12
|
-
//
|
|
13
|
-
const EAGER_OPEN_TRIGGER =
|
|
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
|
|
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
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
`
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
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
|
|
82
|
-
const
|
|
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:
|
|
87
|
-
|
|
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
|
|
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
|
|
97
|
-
const
|
|
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
|
|
100
|
-
|
|
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":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,
|
|
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
|
|
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"
|
|
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
|
-
|
|
18
|
-
codexPruned: HookFileResult;
|
|
32
|
+
results: HookInstallResult[];
|
|
19
33
|
}>;
|
|
20
|
-
export declare function uninstallEagerOpenHook(
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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 {
|
|
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,
|
|
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,
|
|
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,
|
|
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;
|
|
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 {
|
|
2
|
-
// Runs on `npm install`. Re-binds the
|
|
3
|
-
//
|
|
4
|
-
// installing through npm always returns
|
|
5
|
-
// rebinds
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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,
|
|
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
|
@@ -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
|
|
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.
|
|
31
|
-
2.
|
|
32
|
-
3.
|
|
33
|
-
4.
|
|
34
|
-
5.
|
|
35
|
-
6.
|
|
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
|
|
44
|
-
`ethos auth status` pre-check. Only if
|
|
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
|
|
52
|
-
|
|
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
|
-
**
|
|
58
|
-
|
|
59
|
-
`handoff_token`
|
|
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
|
-
|
|
65
|
-
|
|
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
|
|
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**:
|
|
105
|
-
opened the OS browser. If it failed (for example, no desktop
|
|
106
|
-
`open "$UPLOAD_URL"` yourself, and only fall back to MCP browser
|
|
107
|
-
connectors,
|
|
108
|
-
fails, show the URL and ask the
|
|
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
|
|
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
|
|