@sellable/install 0.1.302 → 0.1.303

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Sellable Installer
2
2
 
3
- Installs Sellable MCP for Claude Code, Codex, and Hermes.
3
+ Installs Sellable MCP for Claude Code and Codex.
4
4
 
5
5
  ```bash
6
6
  curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh
@@ -16,9 +16,7 @@ Windows users can use PowerShell or Windows Terminal:
16
16
  iwr "https://app.sellable.dev/api/v2/cli/install.ps1" | iex
17
17
  ```
18
18
 
19
- After install, restart Claude Code, Codex Desktop, or Hermes so Sellable MCP
20
- tools and skills reload. In an active Hermes session, `/reload-mcp` and
21
- `/reload-skills` can reload the new config.
19
+ After install, restart Codex Desktop so the Sellable skill appears.
22
20
 
23
21
  Verify the runtime tools with:
24
22
 
@@ -34,11 +32,11 @@ sellable create
34
32
  ```
35
33
 
36
34
  Campaign creation, sender send refills, foundation memory, content
37
- capture/ideation, and post drafting run inside Claude Code, Codex, or Hermes,
38
- where the Sellable MCP tools and approval flows are available.
35
+ capture/ideation, and post drafting run inside Claude Code or Codex, where the
36
+ Sellable MCP tools and approval flows are available.
39
37
 
40
38
  Install is auth-free by default. The normal path is first-run login: launch a
41
- Sellable workflow in Claude Code, Codex, or Hermes and the agent handles Sellable
39
+ Sellable workflow in Claude Code or Codex and the agent handles Sellable
42
40
  sign-in with a browser magic-link handoff.
43
41
 
44
42
  The installer uses package stdio MCP by default:
@@ -47,7 +45,7 @@ The installer uses package stdio MCP by default:
47
45
  npm exec --yes --package @sellable/mcp@latest -- sellable-mcp
48
46
  ```
49
47
 
50
- That keeps new Claude Code/Codex/Hermes MCP starts on the latest stable package. The
48
+ That keeps new Claude Code/Codex MCP starts on the latest stable package. The
51
49
  MCP server also checks npm at startup and during `get_auth_status`, caching the
52
50
  result at `~/.sellable/update-check.json` so users are prompted to rerun the
53
51
  latest installer only when an update is actually available.
@@ -83,7 +81,7 @@ Auth is stored once at:
83
81
  ~/.sellable/config.json
84
82
  ```
85
83
 
86
- Claude Code, Codex, and Hermes are configured to launch the same packaged MCP server. The
84
+ Claude Code and Codex are configured to launch the same packaged MCP server. The
87
85
  installer also writes Sellable agent definitions from the packaged `agents/`
88
86
  registry, but normal create-campaign runs use only the Message Drafting
89
87
  background agent (`post-find-leads-message-scout`). Source discovery and
@@ -94,7 +92,7 @@ source-scout agents.
94
92
 
95
93
  ## Names
96
94
 
97
- Use the same public entrypoints across supported hosts:
95
+ Use the same public entrypoints in both hosts:
98
96
 
99
97
  - Claude Code: `/sellable:create-campaign`
100
98
  - Claude Code: `/sellable:create-ab-test`
@@ -112,14 +110,6 @@ Use the same public entrypoints across supported hosts:
112
110
  - Codex: `$sellable:create-post`
113
111
  - Codex: `$sellable:refresh-sender-engagement`
114
112
  - Codex: `$sellable:refill-sends`
115
- - Hermes: `/sellable-create-campaign`
116
- - Hermes: `/sellable-create-ab-test`
117
- - Hermes: `/sellable-create-evergreen-campaigns`
118
- - Hermes: `/sellable-foundation`
119
- - Hermes: `/sellable-content`
120
- - Hermes: `/sellable-create-post`
121
- - Hermes: `/sellable-refresh-sender-engagement`
122
- - Hermes: `/sellable-refill-sends`
123
113
  - Codex Desktop plugin: `sellable@sellable`
124
114
  - Codex visible skill: `Sellable Create Campaign`
125
115
  - Codex visible skill: `Sellable Create A/B Test`
@@ -135,8 +125,7 @@ Use the same public entrypoints across supported hosts:
135
125
 
136
126
  Do not ask users to run `/sellable:create-campaign-v2`,
137
127
  `$sellable:create-campaign-v2`, `$sellable:load-voice`, or
138
- `$sellable:sellable:create-campaign`. Do not ask Hermes users to run
139
- `/sellable:create-campaign`; use `/sellable-create-campaign`. `create-campaign-v2` is loaded internally
128
+ `$sellable:sellable:create-campaign`. `create-campaign-v2` is loaded internally
140
129
  by the campaign skill. `foundation` is the preferred entrypoint for durable
141
130
  founder/company memory. `content` is the preferred entrypoint for adding
142
131
  transcripts, recurring ideas, and post seeds. `create-post` remains a supported
@@ -151,12 +140,6 @@ mode support by writing `default_mode_request_user_input = true` under
151
140
  `[features]` in `~/.codex/config.toml`. `codex exec` is non-interactive, so it
152
141
  cannot show the structured questionnaire UI.
153
142
 
154
- Hermes skills use plain chat for setup and approval questions unless a
155
- Hermes-native approval tool is visible in the current session. Hermes exposes
156
- Sellable MCP tools as `mcp_sellable_<tool>`, for example
157
- `mcp_sellable_get_auth_status`, `mcp_sellable_start_cli_login`, and
158
- `mcp_sellable_wait_for_cli_login`.
159
-
160
143
  For Codex Desktop, the installer also writes a local Sellable plugin bundle into
161
144
  `~/.sellable/codex-marketplace`, includes the Sellable skill entrypoints, and
162
145
  enables it in `~/.codex/config.toml`.
@@ -174,4 +157,4 @@ The installer writes compatibility cache aliases for recent Codex plugin
174
157
  versions so stale Desktop skill links resolve to the current wrapper instead of
175
158
  showing file/version debugging to the user.
176
159
 
177
- If only one host is installed, `--host all` installs the available host and tells you how to add the others later.
160
+ If only one host is installed, `--host all` installs the available host and tells you how to add the other one later.
@@ -15,7 +15,6 @@ import { dirname, join, relative } from "node:path";
15
15
  import { stdout as output } from "node:process";
16
16
  import { createInterface } from "node:readline/promises";
17
17
  import { fileURLToPath } from "node:url";
18
- import { parseDocument } from "yaml";
19
18
  import {
20
19
  REQUIRED_SELLABLE_MCP_TOOLS,
21
20
  verifySellableMcpRuntime,
@@ -171,7 +170,7 @@ Commands:
171
170
  uninstall Remove Sellable host config and installed artifacts.
172
171
 
173
172
  Options:
174
- --host <host> claude, codex, hermes, or all. Default: all
173
+ --host <host> claude, codex, or all. Default: all
175
174
  --server <mode> package, local, or hosted. Default: package
176
175
  --token <token> Sellable API token. Also reads SELLABLE_TOKEN.
177
176
  --workspace-id <id> Sellable workspace id. Also reads SELLABLE_WORKSPACE_ID.
@@ -191,9 +190,8 @@ Options:
191
190
  Auth:
192
191
  Install is auth-free by default. Sign in happens on the first run of
193
192
  /sellable:create-campaign, /sellable:create-evergreen-campaigns,
194
- /sellable:foundation, /sellable:content, /sellable:create-post,
195
- /sellable:refresh-sender-engagement, or /sellable:refill-sends in Claude Code,
196
- Codex, or Hermes,
193
+ /sellable:foundation, /sellable:content, /sellable:create-post, or
194
+ /sellable:refresh-sender-engagement, or /sellable:refill-sends in Claude Code or Codex,
197
195
  where the agent walks you through signup or sign-in and stores credentials
198
196
  in ~/.sellable/config.json.
199
197
 
@@ -205,7 +203,7 @@ Auth:
205
203
 
206
204
  function printCreateCommandHint() {
207
205
  printBanner();
208
- console.log(` ${C.bold}Run Sellable from Claude Code, Codex, or Hermes.${C.reset}`);
206
+ console.log(` ${C.bold}Run Sellable from Claude Code or Codex.${C.reset}`);
209
207
  console.log("");
210
208
  console.log(
211
209
  ` ${C.grey}The terminal command installs and verifies Sellable. Campaign creation runs inside your agent session so the workflow can use MCP tools, live state, and approval gates.${C.reset}`
@@ -239,18 +237,6 @@ function printCreateCommandHint() {
239
237
  { label: "Refill", command: "$sellable:refill-sends" },
240
238
  ]);
241
239
  console.log("");
242
- console.log("");
243
- printAgentBox("Using Hermes?", "hermes", [
244
- { label: "Campaign", command: "/sellable-create-campaign" },
245
- { label: "A/B Test", command: "/sellable-create-ab-test" },
246
- { label: "Evergreen", command: "/sellable-create-evergreen-campaigns" },
247
- { label: "Foundation", command: "/sellable-foundation" },
248
- { label: "Content", command: "/sellable-content" },
249
- { label: "Post", command: "/sellable-create-post" },
250
- { label: "Refresh", command: "/sellable-refresh-sender-engagement" },
251
- { label: "Refill", command: "/sellable-refill-sends" },
252
- ]);
253
- console.log("");
254
240
  console.log(` ${"─".repeat(63)}`);
255
241
  console.log(` ${C.grey}If those commands are missing, run:${C.reset}`);
256
242
  console.log("");
@@ -263,10 +249,7 @@ function printCreateCommandHint() {
263
249
 
264
250
  function parseArgs(argv) {
265
251
  const opts = {
266
- host:
267
- process.env.SELLABLE_INSTALLER_HOST ||
268
- process.env.SELLABLE_INSTALL_HOST ||
269
- "all",
252
+ host: process.env.SELLABLE_INSTALL_HOST || "all",
270
253
  server: process.env.SELLABLE_INSTALL_SERVER || "package",
271
254
  token: process.env.SELLABLE_TOKEN || "",
272
255
  workspaceId: process.env.SELLABLE_WORKSPACE_ID || "",
@@ -330,8 +313,8 @@ function parseArgs(argv) {
330
313
  }
331
314
  }
332
315
 
333
- if (!["claude", "codex", "hermes", "all"].includes(opts.host)) {
334
- throw new Error("--host must be claude, codex, hermes, or all");
316
+ if (!["claude", "codex", "all"].includes(opts.host)) {
317
+ throw new Error("--host must be claude, codex, or all");
335
318
  }
336
319
  if (!["package", "local", "hosted"].includes(opts.server)) {
337
320
  throw new Error("--server must be package, local, or hosted");
@@ -1192,29 +1175,6 @@ the Claude Code instruction for customer-facing language and host functions.
1192
1175
 
1193
1176
  Do not tell Claude Code users to run \`$sellable:${commandName}\`, use
1194
1177
  \`request_user_input\`, or restart Codex Desktop. Do not describe this run as Codex.`;
1195
- }
1196
- if (host === "hermes") {
1197
- return `## Installed Host Contract
1198
-
1199
- This installed skill is running in Hermes Agent. When the shared workflow body
1200
- or fallback text mentions Claude Code, Codex, or Hermes for internal parity,
1201
- choose the Hermes instruction for customer-facing language and host functions.
1202
-
1203
- - Customer-facing command: \`/sellable-${commandName}\`
1204
- - MCP tool naming: Hermes exposes Sellable tools as \`mcp_sellable_<tool>\`;
1205
- when shared instructions show \`mcp__sellable__<tool>\`, call the matching
1206
- \`mcp_sellable_<tool>\` tool instead.
1207
- - Structured questions: ask plainly in chat unless a Hermes-native approval or
1208
- question tool is visible in the current session.
1209
- - Bootstrap host label: \`host: "Hermes"\`
1210
- - Install/reload blocker label: Hermes install/reload problem
1211
- - Reload instruction: restart Hermes, or run \`/reload-mcp\` in the active
1212
- Hermes session after install
1213
-
1214
- Do not tell Hermes users to run \`$sellable:${commandName}\` or
1215
- \`/sellable:${commandName}\`, use \`AskUserQuestion\` or \`request_user_input\`,
1216
- or restart Claude Code or Codex Desktop. Do not describe this run as Claude Code
1217
- or Codex.`;
1218
1178
  }
1219
1179
  return "";
1220
1180
  }
@@ -2624,256 +2584,6 @@ function codexPluginSkills() {
2624
2584
  ];
2625
2585
  }
2626
2586
 
2627
- function hermesCommandName(commandName) {
2628
- return `sellable-${commandName}`;
2629
- }
2630
-
2631
- function normalizeHermesSkillMarkdown(markdown, commandName) {
2632
- const hermesName = hermesCommandName(commandName);
2633
- let content = String(markdown);
2634
- if (/^name:\s*.+$/m.test(content)) {
2635
- content = content.replace(/^name:\s*.+$/m, `name: ${hermesName}`);
2636
- } else {
2637
- content = content.replace(/^---\n/m, `---\nname: ${hermesName}\n`);
2638
- }
2639
-
2640
- let normalized = content
2641
- .replace(/mcp__sellable__<tool>/g, "mcp_sellable_<tool>")
2642
- .replace(/mcp__([A-Za-z0-9_-]+)__<tool>/g, (_, server) => {
2643
- return `mcp_${String(server).replaceAll("-", "_")}_<tool>`;
2644
- })
2645
- .replace(/\bmcp__([A-Za-z0-9_-]+)__([A-Za-z0-9_-]+)\b/g, (_, server, tool) => {
2646
- return `mcp_${String(server).replaceAll("-", "_")}_${String(tool).replaceAll("-", "_")}`;
2647
- })
2648
- .replace(/\bmcp__sellable__/g, "mcp_sellable_")
2649
- .replace(/\$sellable:/g, "/sellable-")
2650
- .replace(/\/sellable:/g, "/sellable-")
2651
- .replace(/Codex install\/reload problem/g, "Hermes install/reload problem")
2652
- .replace(/Claude Code install\/reload problem/g, "Hermes install/reload problem")
2653
- .replace(/fully quit and reopen Codex Desktop, then start a new thread/g, "restart Hermes, or run `/reload-mcp` in the active Hermes session")
2654
- .replace(/fully quit and reopen Claude Code, then start a new session/g, "restart Hermes, or run `/reload-mcp` in the active Hermes session")
2655
- .replace(/Codex Desktop/g, "Hermes")
2656
- .replace(/Claude Code\/Codex/g, "Hermes")
2657
- .replace(/Claude Code or Codex/g, "Hermes")
2658
- .replace(/Codex or Claude Code/g, "Hermes")
2659
- .replace(/Claude Code and Codex/g, "Hermes")
2660
- .replace(/Codex\/Claude/g, "Hermes")
2661
- .replace(/quick question panel/g, "approval prompt")
2662
- .replace(/request_user_input/g, "plain chat")
2663
- .replace(/AskUserQuestion/g, "plain chat");
2664
-
2665
- normalized = normalized.replace(
2666
- /Do not tell Hermes users to run[\s\S]*?Do not describe this run as Claude Code\nor Codex\./g,
2667
- "Do not tell Hermes users to run Codex or Claude command forms, use Codex/Claude structured-question APIs, or restart Codex Desktop or Claude Code. Do not describe this run as Claude Code or Codex."
2668
- );
2669
-
2670
- normalized = normalized.replace(
2671
- /## Structured Questions\n\nUse the host-native structured question gate for intake and approval:[\s\S]*?## Host Runtime Functions/g,
2672
- `## Structured Questions
2673
-
2674
- Hermes should ask setup questions directly in chat unless the current Hermes
2675
- session exposes a native approval or question tool. Use a bounded approval gate
2676
- only for explicit approval decisions. For open text like LinkedIn URLs, company
2677
- domains, notes, pasted context, campaign ideas, or feedback, ask in normal chat
2678
- and wait for the user to paste the value.
2679
-
2680
- Campaign setup questions are single-choice decisions. Use mutually exclusive
2681
- options and route blended or custom answers through a short free-text follow-up.
2682
- Customer-facing language should call this "a couple setup choices" during
2683
- normal campaign progress.
2684
-
2685
- ## Host Runtime Functions`
2686
- );
2687
-
2688
- normalized = normalized.replace(
2689
- /## Names To Use\n\nUse these exact public names[\s\S]*?## Structured Questions/g,
2690
- `## Names To Use
2691
-
2692
- Use these exact public names for Hermes:
2693
-
2694
- - Hermes command: \`/${hermesName}\`
2695
- - Hermes skill directory: \`skills/sellable/${hermesName}/SKILL.md\`
2696
- - MCP server name: \`sellable\`
2697
- - Hermes MCP tool prefix: \`mcp_sellable_\`
2698
- - Internal workflow prompt: \`create-campaign-v2\`
2699
-
2700
- Do not tell users to run internal subskill names. \`create-campaign-v2\` is only
2701
- the internal subskill loaded through
2702
- \`mcp_sellable_get_subskill_prompt({ subskillName: "create-campaign-v2" })\`.
2703
-
2704
- ## Structured Questions`
2705
- );
2706
-
2707
- normalized = normalized.replace(
2708
- /- `ask_user`:[\s\S]*?(?=\n- `load_subprompt`:)/g,
2709
- `- \`ask_user\`: ask directly in chat unless a Hermes-native approval or
2710
- question tool is visible in the current session. Use this for
2711
- multiple-choice intake, campaign-focus choices, source decisions, and
2712
- approvals. Campaign setup questions are single-choice only; do not use
2713
- multi-select or checkbox variants.`
2714
- );
2715
-
2716
- normalized = normalized.replace(
2717
- /- `launch_message_drafting`:[\s\S]*?\n\nIf a required interactive/g,
2718
- `- \`launch_message_drafting\`: if Hermes exposes a background-agent capability,
2719
- use the compatible Message Drafting agent. Otherwise run the same message
2720
- drafting branch inline in the parent session with \`statusSource:
2721
- "parent-thread-fallback"\`.
2722
-
2723
- If a required interactive`
2724
- );
2725
-
2726
- normalized = normalized.replace(
2727
- /Do not silently ask (?:Codex|Hermes) intake or approval questions as plain chat[\s\S]*?Plain chat questions are only acceptable in non-interactive `codex exec`\nsmoke\/rehearsal runs because structured user input is unavailable by design\nthere\.\n\n/g,
2728
- ""
2729
- );
2730
-
2731
- normalized = normalized.replace(
2732
- /## Active Model Metadata\n\nBefore calling `bootstrap_create_campaign`, collect[\s\S]*?Never invent the model or reasoning effort\. Never pass config defaults as active\nmetadata\. If bootstrap returns `modelQuality\.status === "unknown"`, continue\nwithout asking the user to switch models\.\n\n/g,
2733
- `## Active Model Metadata
2734
-
2735
- Before calling \`bootstrap_create_campaign\`, pass \`host: "Hermes"\`. If the
2736
- current Hermes session exposes model and effort metadata for this same turn,
2737
- pass those exact values with \`modelMetadataSource: "hermes_runtime_metadata"\`.
2738
- If the current Hermes session context explicitly states both the exact model ID
2739
- and effort/thinking level, pass them with
2740
- \`modelMetadataSource: "hermes_session_context"\`. Otherwise omit \`model\`,
2741
- \`reasoningEffort\`, and \`modelMetadataSource\`.
2742
-
2743
- Never invent the model or reasoning effort. Never inspect Codex or Claude config
2744
- files as proof of the active Hermes session. If bootstrap returns
2745
- \`modelQuality.status === "unknown"\`, continue without asking the user to
2746
- switch models.
2747
-
2748
- `
2749
- );
2750
-
2751
- normalized = normalized.replace(/not `plain chat`/g, "not internal API names");
2752
-
2753
- normalized = normalized
2754
- .replace(/this is a Codex\ninstall\/reload problem/g, "this is a Hermes\ninstall/reload problem")
2755
- .replace(/Hermes plugin/g, "Hermes skills");
2756
-
2757
- return normalized;
2758
- }
2759
-
2760
- function compactHermesEvergreenSkillMd() {
2761
- return normalizeHermesSkillMarkdown(
2762
- stampInstalledHost(`---
2763
- name: create-evergreen-campaigns
2764
- description: Create or repair evergreen campaign lanes without launching sends.
2765
- visibility: public
2766
- allowed-tools:
2767
- ${allowedToolsYaml(CREATE_EVERGREEN_CAMPAIGNS_ALLOWED_TOOLS)}
2768
- ---
2769
-
2770
- # Sellable Create Evergreen Campaigns
2771
-
2772
- Use this as the customer-facing entrypoint for the Sellable
2773
- \`create-evergreen-campaigns\` workflow in Hermes.
2774
-
2775
- ## Bootstrap
2776
-
2777
- MCP prompt and command access are required. First call
2778
- \`mcp__sellable__get_auth_status({})\`. Do not inspect repo files, run shell
2779
- commands, use \`npm\`, \`node\`, local harness scripts, or read local prompt
2780
- files to emulate this workflow.
2781
-
2782
- If the Sellable MCP prompt tools are unavailable, stop and say this is a Hermes
2783
- install/reload problem. Tell the user to run
2784
- \`curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh\`, then restart
2785
- Hermes or run \`/reload-mcp\`.
2786
-
2787
- ## Execute Workflow
2788
-
2789
- 1. Load the canonical prompt via
2790
- \`mcp__sellable__get_subskill_prompt({ subskillName: "create-evergreen-campaigns" })\`.
2791
- If the response has \`hasMore=true\`, continue with \`nextOffset\` until
2792
- \`hasMore=false\`.
2793
- 2. Ask for bounded approval in normal chat before mutating if the plan requires
2794
- approval. Do not call Codex app thread tools or Codex CLI workers from
2795
- Hermes.
2796
- 3. Use \`mcp__sellable__setup_evergreen_campaigns({ mode: "plan" })\` for the
2797
- plan/readback packet, then use the canonical prompt's approved mutation path
2798
- and return to \`setup_evergreen_campaigns({ mode: "verify" })\` with
2799
- customer-visible receipts.
2800
- 4. Do not launch campaigns, schedule sends, archive campaigns, delete tables,
2801
- or spend paid credits.
2802
-
2803
- ## MCP Prompt Fallback
2804
-
2805
- If exact subskill lookup fails, use
2806
- \`mcp__sellable__search_subskill_prompts({ query: "create-evergreen-campaigns", includePublic: true, includeInternal: true })\`,
2807
- then retry \`get_subskill_prompt\`.
2808
- `, "hermes", "create-evergreen-campaigns"),
2809
- "create-evergreen-campaigns"
2810
- );
2811
- }
2812
-
2813
- function hermesSkillDefinitions() {
2814
- return [
2815
- {
2816
- commandName: "create-campaign",
2817
- dir: hermesCommandName("create-campaign"),
2818
- skillMd: normalizeHermesSkillMarkdown(
2819
- createCampaignSkillMd("hermes"),
2820
- "create-campaign"
2821
- ),
2822
- soulMd: createCampaignSoulMd(),
2823
- },
2824
- {
2825
- commandName: "create-ab-test",
2826
- dir: hermesCommandName("create-ab-test"),
2827
- skillMd: normalizeHermesSkillMarkdown(
2828
- createAbTestSkillMd("hermes"),
2829
- "create-ab-test"
2830
- ),
2831
- },
2832
- {
2833
- commandName: "create-evergreen-campaigns",
2834
- dir: hermesCommandName("create-evergreen-campaigns"),
2835
- skillMd: compactHermesEvergreenSkillMd(),
2836
- },
2837
- {
2838
- commandName: "foundation",
2839
- dir: hermesCommandName("foundation"),
2840
- skillMd: normalizeHermesSkillMarkdown(
2841
- foundationSkillMd("hermes"),
2842
- "foundation"
2843
- ),
2844
- },
2845
- {
2846
- commandName: "content",
2847
- dir: hermesCommandName("content"),
2848
- skillMd: normalizeHermesSkillMarkdown(contentSkillMd("hermes"), "content"),
2849
- },
2850
- {
2851
- commandName: "create-post",
2852
- dir: hermesCommandName("create-post"),
2853
- skillMd: normalizeHermesSkillMarkdown(
2854
- createPostSkillMd("hermes"),
2855
- "create-post"
2856
- ),
2857
- },
2858
- {
2859
- commandName: "refresh-sender-engagement",
2860
- dir: hermesCommandName("refresh-sender-engagement"),
2861
- skillMd: normalizeHermesSkillMarkdown(
2862
- refreshSenderEngagementSkillMd("hermes"),
2863
- "refresh-sender-engagement"
2864
- ),
2865
- },
2866
- {
2867
- commandName: "refill-sends",
2868
- dir: hermesCommandName("refill-sends"),
2869
- skillMd: normalizeHermesSkillMarkdown(
2870
- refillSendsSkillMd("hermes"),
2871
- "refill-sends"
2872
- ),
2873
- },
2874
- ];
2875
- }
2876
-
2877
2587
  function installerPackageRoot() {
2878
2588
  return join(dirname(fileURLToPath(import.meta.url)), "..");
2879
2589
  }
@@ -3442,7 +3152,6 @@ exec ${shellQuote(npmCommand)} exec --yes --package ${shellQuote(INSTALL_PACKAGE
3442
3152
  const WATCH_MODE_DRIVER_ENV = {
3443
3153
  claude: "SELLABLE_WATCH_MODE_DRIVER=claude",
3444
3154
  codex: "SELLABLE_WATCH_MODE_DRIVER=codex",
3445
- hermes: "SELLABLE_WATCH_MODE_DRIVER=hermes",
3446
3155
  };
3447
3156
 
3448
3157
  function withHostedWatchModeDriver(rawUrl, driver) {
@@ -3568,169 +3277,6 @@ function codexPluginMcpServerMatches(content, opts) {
3568
3277
  }
3569
3278
  }
3570
3279
 
3571
- function hermesHome() {
3572
- return process.env.HERMES_HOME?.trim() || join(homedir(), ".hermes");
3573
- }
3574
-
3575
- function hermesConfigPath() {
3576
- return join(hermesHome(), "config.yaml");
3577
- }
3578
-
3579
- function hermesSkillsRoot() {
3580
- return join(hermesHome(), "skills", "sellable");
3581
- }
3582
-
3583
- function hermesLikelyInstalled() {
3584
- return (
3585
- Boolean(process.env.HERMES_HOME?.trim()) ||
3586
- commandExists("hermes") ||
3587
- existsSync(hermesConfigPath()) ||
3588
- existsSync(join(hermesHome(), "skills"))
3589
- );
3590
- }
3591
-
3592
- function parseHermesConfig(raw, configPath = hermesConfigPath()) {
3593
- const source = raw.trim() ? raw : "{}\n";
3594
- const doc = parseDocument(source, { prettyErrors: false });
3595
- if (doc.errors.length > 0) {
3596
- throw new Error(
3597
- `Invalid Hermes config YAML at ${configPath}: ${doc.errors[0].message}`
3598
- );
3599
- }
3600
- const value = doc.toJSON() ?? {};
3601
- if (!value || typeof value !== "object" || Array.isArray(value)) {
3602
- throw new Error(
3603
- `Invalid Hermes config YAML at ${configPath}: expected a mapping at the document root`
3604
- );
3605
- }
3606
- return value;
3607
- }
3608
-
3609
- function readHermesConfig() {
3610
- const configPath = hermesConfigPath();
3611
- const raw = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
3612
- return { raw, config: parseHermesConfig(raw, configPath), configPath };
3613
- }
3614
-
3615
- function hermesMcpServer(opts) {
3616
- if (opts.server === "hosted") {
3617
- return {
3618
- url: withHostedWatchModeDriver(opts.hostedUrl, "hermes"),
3619
- enabled: true,
3620
- env: {
3621
- SELLABLE_WATCH_MODE_DRIVER: "hermes",
3622
- },
3623
- };
3624
- }
3625
-
3626
- const [command, args] = mcpCommand(opts);
3627
- return {
3628
- command,
3629
- args,
3630
- enabled: true,
3631
- env: {
3632
- SELLABLE_WATCH_MODE_DRIVER: "hermes",
3633
- },
3634
- };
3635
- }
3636
-
3637
- function writeHermesConfig(configPath, config, opts) {
3638
- if (opts.dryRun) return;
3639
- mkdirSync(dirname(configPath), { recursive: true, mode: 0o700 });
3640
- const doc = parseDocument("{}\n");
3641
- doc.contents = config;
3642
- writeFileSync(configPath, String(doc), { mode: 0o600 });
3643
- }
3644
-
3645
- function writeHermesMcpServer(opts) {
3646
- const { config, configPath } = readHermesConfig();
3647
- const existingMcpServers =
3648
- config.mcp_servers &&
3649
- typeof config.mcp_servers === "object" &&
3650
- !Array.isArray(config.mcp_servers)
3651
- ? config.mcp_servers
3652
- : {};
3653
- const nextConfig = {
3654
- ...config,
3655
- mcp_servers: {
3656
- ...existingMcpServers,
3657
- sellable: hermesMcpServer(opts),
3658
- },
3659
- };
3660
- writeHermesConfig(configPath, nextConfig, opts);
3661
- return configPath;
3662
- }
3663
-
3664
- function installHermesSkills(opts) {
3665
- const root = hermesSkillsRoot();
3666
- for (const skill of hermesSkillDefinitions()) {
3667
- const skillRoot = join(root, skill.dir);
3668
- writeFile(join(skillRoot, "SKILL.md"), skill.skillMd, opts);
3669
- if (skill.soulMd) {
3670
- writeFile(join(skillRoot, "SOUL.md"), skill.soulMd, opts);
3671
- }
3672
- }
3673
- return root;
3674
- }
3675
-
3676
- function installHermes(opts) {
3677
- // Parse config before writing skills so invalid user YAML cannot leave a
3678
- // half-installed Hermes skill tree behind.
3679
- readHermesConfig();
3680
- let skillsRoot = null;
3681
- try {
3682
- skillsRoot = installHermesSkills(opts);
3683
- const configPath = writeHermesMcpServer(opts);
3684
- logVerbose(`${C.grey}+ Hermes config updated: ${configPath}${C.reset}`);
3685
- return { installed: true, configPath, skillsRoot };
3686
- } catch (err) {
3687
- if (skillsRoot && !opts.dryRun) {
3688
- rmSync(skillsRoot, { recursive: true, force: true });
3689
- }
3690
- throw err;
3691
- }
3692
- }
3693
-
3694
- function hermesMcpServerMatches(config, opts) {
3695
- const server = config?.mcp_servers?.sellable;
3696
- if (!server || typeof server !== "object") return false;
3697
- const expected = hermesMcpServer(opts);
3698
- return JSON.stringify(server) === JSON.stringify(expected);
3699
- }
3700
-
3701
- function hermesSkillChecks() {
3702
- const root = hermesSkillsRoot();
3703
- const skills = hermesSkillDefinitions();
3704
- const paths = skills.map((skill) => join(root, skill.dir, "SKILL.md"));
3705
- const allPresent = paths.every((skillPath) => existsSync(skillPath));
3706
- const contents = paths
3707
- .filter((skillPath) => existsSync(skillPath))
3708
- .map((skillPath) => readFileSync(skillPath, "utf8"));
3709
- const commandNamesCurrent =
3710
- contents.length === skills.length &&
3711
- skills.every((skill, index) =>
3712
- contents[index]?.includes(`name: ${hermesCommandName(skill.commandName)}`)
3713
- );
3714
- const slashCommandsCurrent =
3715
- contents.length === skills.length &&
3716
- skills.every((skill, index) =>
3717
- contents[index]?.includes(`/${hermesCommandName(skill.commandName)}`)
3718
- );
3719
- const forbiddenSyntax = contents.some((content) =>
3720
- /\$sellable:|\/sellable:|mcp__sellable__|request_user_input|AskUserQuestion/.test(
3721
- content
3722
- )
3723
- );
3724
- return {
3725
- root,
3726
- paths,
3727
- allPresent,
3728
- commandNamesCurrent,
3729
- slashCommandsCurrent,
3730
- forbiddenSyntax,
3731
- };
3732
- }
3733
-
3734
3280
  function installClaude(opts) {
3735
3281
  if (!commandExists("claude")) {
3736
3282
  const message =
@@ -4012,13 +3558,6 @@ function warningCheck(ok, label) {
4012
3558
  return { ok, label, required: false };
4013
3559
  }
4014
3560
 
4015
- function firstRunCommandForHost(host) {
4016
- if (host === "hermes") return "/sellable-create-campaign";
4017
- if (host === "codex") return "$sellable:create-campaign";
4018
- if (host === "claude") return "/sellable:create-campaign";
4019
- return "/sellable:create-campaign, $sellable:create-campaign, or /sellable-create-campaign";
4020
- }
4021
-
4022
3561
  async function verify(opts) {
4023
3562
  const startedAt = new Date().toISOString();
4024
3563
  const stored = readStoredAuth();
@@ -4034,7 +3573,7 @@ async function verify(opts) {
4034
3573
  checks.push(
4035
3574
  warningCheck(
4036
3575
  true,
4037
- `Auth: not yet signed in — sign in on first run of ${firstRunCommandForHost(opts.host)}`
3576
+ `Auth: not yet signed in — sign in on first run of /sellable:create-campaign`
4038
3577
  )
4039
3578
  );
4040
3579
  }
@@ -4321,88 +3860,6 @@ async function verify(opts) {
4321
3860
  )
4322
3861
  );
4323
3862
  }
4324
- if (opts.host === "hermes" || opts.host === "all") {
4325
- let hermesConfig = null;
4326
- let hermesConfigError = "";
4327
- try {
4328
- hermesConfig = readHermesConfig().config;
4329
- } catch (err) {
4330
- hermesConfigError = err instanceof Error ? err.message : String(err);
4331
- }
4332
- const npmPresent = opts.server !== "package" || commandExists(packageManagerCommand());
4333
- const skillChecks = hermesSkillChecks();
4334
- const configMatches = hermesConfig
4335
- ? hermesMcpServerMatches(hermesConfig, opts)
4336
- : false;
4337
- const hasHermesDriver =
4338
- hermesConfig?.mcp_servers?.sellable?.env?.SELLABLE_WATCH_MODE_DRIVER ===
4339
- "hermes";
4340
-
4341
- const check =
4342
- opts.host === "hermes" ? requiredCheck : warningCheck;
4343
- checks.push(
4344
- check(
4345
- !hermesConfigError,
4346
- hermesConfigError || `Hermes config readable: ${hermesConfigPath()}`
4347
- )
4348
- );
4349
- checks.push(
4350
- check(
4351
- configMatches,
4352
- configMatches
4353
- ? "Hermes Sellable MCP entry canonical"
4354
- : "Hermes Sellable MCP entry missing or stale"
4355
- )
4356
- );
4357
- checks.push(
4358
- check(
4359
- hasHermesDriver,
4360
- hasHermesDriver
4361
- ? "Hermes watch mode driver pinned to hermes"
4362
- : "Hermes watch mode driver missing"
4363
- )
4364
- );
4365
- checks.push(
4366
- check(
4367
- skillChecks.allPresent,
4368
- skillChecks.allPresent
4369
- ? "Hermes Sellable skills present"
4370
- : "Hermes Sellable skills missing"
4371
- )
4372
- );
4373
- checks.push(
4374
- check(
4375
- skillChecks.commandNamesCurrent,
4376
- skillChecks.commandNamesCurrent
4377
- ? "Hermes skill names current"
4378
- : "Hermes skill names stale"
4379
- )
4380
- );
4381
- checks.push(
4382
- check(
4383
- skillChecks.slashCommandsCurrent,
4384
- skillChecks.slashCommandsCurrent
4385
- ? "Hermes slash command hints current"
4386
- : "Hermes slash command hints stale"
4387
- )
4388
- );
4389
- checks.push(
4390
- check(
4391
- !skillChecks.forbiddenSyntax,
4392
- !skillChecks.forbiddenSyntax
4393
- ? "Hermes skills use Hermes MCP/tool syntax"
4394
- : "Hermes skills contain Claude/Codex-only syntax"
4395
- )
4396
- );
4397
- checks.push(
4398
- check(
4399
- npmPresent,
4400
- npmPresent
4401
- ? "Hermes package runtime command present"
4402
- : `Hermes package runtime command missing: ${packageManagerCommand()}`
4403
- )
4404
- );
4405
- }
4406
3863
 
4407
3864
  let runtimeMcp;
4408
3865
  try {
@@ -4585,7 +4042,7 @@ function printNextSteps(installedHosts, authReused) {
4585
4042
  ` ${C.bold}Almost there — install an agent first.${C.reset}`
4586
4043
  );
4587
4044
  console.log(
4588
- ` ${C.yellow}!${C.reset} No agent CLI/profile found (Claude Code, Codex, or Hermes)`
4045
+ ` ${C.yellow}!${C.reset} No agent CLI found (Claude Code or Codex)`
4589
4046
  );
4590
4047
  console.log("");
4591
4048
  console.log("");
@@ -4629,7 +4086,6 @@ function printNextSteps(installedHosts, authReused) {
4629
4086
 
4630
4087
  const hasClaude = installedHosts.includes("Claude Code");
4631
4088
  const hasCodex = installedHosts.includes("Codex");
4632
- const hasHermes = installedHosts.includes("Hermes");
4633
4089
 
4634
4090
  // Header
4635
4091
  if (authReused) {
@@ -4645,11 +4101,6 @@ function printNextSteps(installedHosts, authReused) {
4645
4101
  console.log(` ${C.green}✓${C.reset} Skills installed`);
4646
4102
  console.log(` ${C.green}✓${C.reset} Codex custom agents installed`);
4647
4103
  }
4648
- if (hasHermes) {
4649
- console.log(
4650
- ` ${C.green}✓${C.reset} Hermes skills and MCP config installed`
4651
- );
4652
- }
4653
4104
  if (hasClaude) {
4654
4105
  console.log(
4655
4106
  ` ${C.green}✓${C.reset} Claude slash commands and custom agents installed`
@@ -4693,19 +4144,6 @@ function printNextSteps(installedHosts, authReused) {
4693
4144
  ]);
4694
4145
  console.log("");
4695
4146
  }
4696
- if (hasHermes) {
4697
- printAgentBox("Using Hermes?", "hermes", [
4698
- { label: "Campaign", command: "/sellable-create-campaign" },
4699
- { label: "A/B Test", command: "/sellable-create-ab-test" },
4700
- { label: "Evergreen", command: "/sellable-create-evergreen-campaigns" },
4701
- { label: "Foundation", command: "/sellable-foundation" },
4702
- { label: "Content", command: "/sellable-content" },
4703
- { label: "Post", command: "/sellable-create-post" },
4704
- { label: "Refresh", command: "/sellable-refresh-sender-engagement" },
4705
- { label: "Refill", command: "/sellable-refill-sends" },
4706
- ]);
4707
- console.log("");
4708
- }
4709
4147
 
4710
4148
  console.log("");
4711
4149
  console.log(` ${"─".repeat(63)}`);
@@ -4735,7 +4173,7 @@ function removeTomlSection(content, header) {
4735
4173
  return content.replace(pattern, "");
4736
4174
  }
4737
4175
 
4738
- function runUninstall(opts = { host: "all" }) {
4176
+ function runUninstall() {
4739
4177
  console.log("");
4740
4178
  console.log(` ${C.bold}Uninstalling Sellable…${C.reset}`);
4741
4179
  console.log("");
@@ -4746,7 +4184,7 @@ function runUninstall(opts = { host: "all" }) {
4746
4184
 
4747
4185
  // 1) Surgical removal from Codex config.toml
4748
4186
  const codexConfigPath = join(codexHome(), "config.toml");
4749
- if ((opts.host === "codex" || opts.host === "all") && existsSync(codexConfigPath)) {
4187
+ if (existsSync(codexConfigPath)) {
4750
4188
  try {
4751
4189
  const before = readFileSync(codexConfigPath, "utf8");
4752
4190
  const ts = new Date()
@@ -4783,11 +4221,10 @@ function runUninstall(opts = { host: "all" }) {
4783
4221
  ` ${C.yellow}!${C.reset} Could not edit Codex config: ${err instanceof Error ? err.message : String(err)}`
4784
4222
  );
4785
4223
  }
4786
- } else if (opts.host === "codex" || opts.host === "all") {
4224
+ } else {
4787
4225
  skipped.push(`Codex config not found at ${codexConfigPath}`);
4788
4226
  }
4789
4227
 
4790
- if (opts.host === "codex" || opts.host === "all") {
4791
4228
  for (const agent of [...codexCustomAgents(), ...legacyCodexCustomAgents()]) {
4792
4229
  const agentPath = join(codexHome(), "agents", agent.filename);
4793
4230
  if (!existsSync(agentPath)) continue;
@@ -4800,10 +4237,9 @@ function runUninstall(opts = { host: "all" }) {
4800
4237
  );
4801
4238
  }
4802
4239
  }
4803
- }
4804
4240
 
4805
4241
  // 2) Claude Code MCP removal
4806
- if ((opts.host === "claude" || opts.host === "all") && commandExists("claude")) {
4242
+ if (commandExists("claude")) {
4807
4243
  const r = spawnSync("claude", ["mcp", "remove", "sellable"], {
4808
4244
  encoding: "utf8",
4809
4245
  });
@@ -4812,11 +4248,10 @@ function runUninstall(opts = { host: "all" }) {
4812
4248
  } else {
4813
4249
  skipped.push(`Claude Code MCP (none registered or already removed)`);
4814
4250
  }
4815
- } else if (opts.host === "claude" || opts.host === "all") {
4251
+ } else {
4816
4252
  skipped.push(`Claude Code CLI not found`);
4817
4253
  }
4818
4254
 
4819
- if (opts.host === "claude" || opts.host === "all") {
4820
4255
  for (const agent of [
4821
4256
  ...claudeCustomAgents(),
4822
4257
  ...legacyClaudeCustomAgents(),
@@ -4844,66 +4279,10 @@ function runUninstall(opts = { host: "all" }) {
4844
4279
  );
4845
4280
  }
4846
4281
  }
4847
- }
4848
4282
 
4849
- // 3) Hermes config and skill removal
4850
- if (opts.host === "hermes" || opts.host === "all") {
4851
- const configPath = hermesConfigPath();
4852
- if (existsSync(configPath)) {
4853
- try {
4854
- const before = readFileSync(configPath, "utf8");
4855
- const ts = new Date()
4856
- .toISOString()
4857
- .replace(/[-:]/g, "")
4858
- .replace(/\..+/, "");
4859
- const backupPath = `${configPath}.bak-sellable-uninstall-${ts}`;
4860
- writeFileSync(backupPath, before, { mode: 0o600 });
4861
- const config = parseHermesConfig(before, configPath);
4862
- if (
4863
- config.mcp_servers &&
4864
- typeof config.mcp_servers === "object" &&
4865
- !Array.isArray(config.mcp_servers) &&
4866
- "sellable" in config.mcp_servers
4867
- ) {
4868
- const nextMcpServers = { ...config.mcp_servers };
4869
- delete nextMcpServers.sellable;
4870
- writeHermesConfig(
4871
- configPath,
4872
- { ...config, mcp_servers: nextMcpServers },
4873
- { dryRun: false }
4874
- );
4875
- removed.push(`Hermes config (sellable removed in ${configPath})`);
4876
- removed.push(` backup: ${backupPath}`);
4877
- } else {
4878
- skipped.push(`Hermes config had no sellable MCP server`);
4879
- }
4880
- } catch (err) {
4881
- console.log(
4882
- ` ${C.yellow}!${C.reset} Could not edit Hermes config: ${err instanceof Error ? err.message : String(err)}`
4883
- );
4884
- }
4885
- } else {
4886
- skipped.push(`Hermes config not found at ${configPath}`);
4887
- }
4888
-
4889
- const skillsRoot = hermesSkillsRoot();
4890
- if (existsSync(skillsRoot)) {
4891
- try {
4892
- rmSync(skillsRoot, { recursive: true, force: true });
4893
- removed.push(`${skillsRoot}`);
4894
- } catch (err) {
4895
- console.log(
4896
- ` ${C.yellow}!${C.reset} Could not remove ${skillsRoot}: ${err instanceof Error ? err.message : String(err)}`
4897
- );
4898
- }
4899
- } else {
4900
- skipped.push(`Hermes Sellable skills not found at ${skillsRoot}`);
4901
- }
4902
- }
4903
-
4904
- // 4) Surgical removal of Sellable-installed artifacts inside ~/.sellable/
4283
+ // 3) Surgical removal of Sellable-installed artifacts inside ~/.sellable/
4905
4284
  const sellableDir = join(homedir(), ".sellable");
4906
- if (opts.host === "all" && existsSync(sellableDir)) {
4285
+ if (existsSync(sellableDir)) {
4907
4286
  const tracked = [
4908
4287
  "config.json",
4909
4288
  "update-check.json",
@@ -4942,13 +4321,13 @@ function runUninstall(opts = { host: "all" }) {
4942
4321
  // ignore
4943
4322
  }
4944
4323
  }
4945
- } else if (opts.host === "all") {
4324
+ } else {
4946
4325
  skipped.push(`~/.sellable not present`);
4947
4326
  }
4948
4327
 
4949
- // 5) Self-shim
4328
+ // 4) Self-shim
4950
4329
  const shimPath = join(homedir(), ".local", "bin", "sellable");
4951
- if (opts.host === "all" && existsSync(shimPath)) {
4330
+ if (existsSync(shimPath)) {
4952
4331
  try {
4953
4332
  rmSync(shimPath, { force: true });
4954
4333
  removed.push(`${shimPath}`);
@@ -5061,13 +4440,6 @@ async function main() {
5061
4440
  console.log(` Codex: $sellable:create-post`);
5062
4441
  console.log(` Codex: $sellable:refresh-sender-engagement`);
5063
4442
  console.log(` Codex: $sellable:refill-sends`);
5064
- console.log(` Hermes: /sellable-create-campaign`);
5065
- console.log(` Hermes: /sellable-create-evergreen-campaigns`);
5066
- console.log(` Hermes: /sellable-foundation`);
5067
- console.log(` Hermes: /sellable-content`);
5068
- console.log(` Hermes: /sellable-create-post`);
5069
- console.log(` Hermes: /sellable-refresh-sender-engagement`);
5070
- console.log(` Hermes: /sellable-refill-sends`);
5071
4443
  process.exit(0);
5072
4444
  }
5073
4445
  if (rawArgs[0] === "prefs") {
@@ -5110,8 +4482,7 @@ async function main() {
5110
4482
  process.exit(0);
5111
4483
  }
5112
4484
  if (rawArgs[0] === "uninstall") {
5113
- const opts = parseArgs(rawArgs.slice(1));
5114
- runUninstall(opts);
4485
+ runUninstall();
5115
4486
  process.exit(0);
5116
4487
  }
5117
4488
  if (rawArgs[0] === "create") {
@@ -5129,7 +4500,7 @@ async function main() {
5129
4500
  if (!opts.verifyOnly) {
5130
4501
  printBanner();
5131
4502
  console.log(
5132
- ` ${C.bold}Connecting Sellable to Claude Code, Codex, and Hermes…${C.reset}`
4503
+ ` ${C.bold}Connecting Sellable to Claude Code and Codex…${C.reset}`
5133
4504
  );
5134
4505
  console.log("");
5135
4506
  } else if (!opts.json) {
@@ -5165,15 +4536,6 @@ async function main() {
5165
4536
  installedHosts.push("Codex");
5166
4537
  }
5167
4538
  }
5168
- if (
5169
- opts.host === "hermes" ||
5170
- (opts.host === "all" && hermesLikelyInstalled())
5171
- ) {
5172
- const result = installHermes(opts);
5173
- if (result.installed) {
5174
- installedHosts.push("Hermes");
5175
- }
5176
- }
5177
4539
  }
5178
4540
 
5179
4541
  if (opts.dryRun) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.302",
3
+ "version": "0.1.303",
4
4
  "type": "module",
5
- "description": "One-command installer for Sellable MCP in Claude Code, Codex, and Hermes",
5
+ "description": "One-command installer for Sellable MCP in Claude Code and Codex",
6
6
  "bin": {
7
7
  "sellable": "bin/sellable-install.mjs"
8
8
  },
@@ -18,15 +18,13 @@
18
18
  "README.md"
19
19
  ],
20
20
  "dependencies": {
21
- "@modelcontextprotocol/sdk": "^1.25.2",
22
- "yaml": "^2.8.1"
21
+ "@modelcontextprotocol/sdk": "^1.25.2"
23
22
  },
24
23
  "keywords": [
25
24
  "sellable",
26
25
  "mcp",
27
26
  "claude-code",
28
27
  "codex",
29
- "hermes",
30
28
  "linkedin",
31
29
  "outbound"
32
30
  ],