@sellable/install 0.1.285 → 0.1.287

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
@@ -100,6 +100,7 @@ Use the same public entrypoints in both hosts:
100
100
  - Claude Code: `/sellable:foundation`
101
101
  - Claude Code: `/sellable:content`
102
102
  - Claude Code: `/sellable:create-post`
103
+ - Claude Code: `/sellable:refresh-sender-engagement`
103
104
  - Claude Code: `/sellable:refill-sends`
104
105
  - Codex: `$sellable:create-campaign`
105
106
  - Codex: `$sellable:create-ab-test`
@@ -107,6 +108,7 @@ Use the same public entrypoints in both hosts:
107
108
  - Codex: `$sellable:foundation`
108
109
  - Codex: `$sellable:content`
109
110
  - Codex: `$sellable:create-post`
111
+ - Codex: `$sellable:refresh-sender-engagement`
110
112
  - Codex: `$sellable:refill-sends`
111
113
  - Codex Desktop plugin: `sellable@sellable`
112
114
  - Codex visible skill: `Sellable Create Campaign`
@@ -115,6 +117,7 @@ Use the same public entrypoints in both hosts:
115
117
  - Codex visible skill: `Sellable Foundation`
116
118
  - Codex visible skill: `Sellable Content`
117
119
  - Codex visible skill: `Sellable Create Post`
120
+ - Codex visible skill: `Sellable Refresh Sender Engagement`
118
121
  - Codex visible skill: `Sellable Refill Sends`
119
122
  - Internal MCP workflow prompt: `create-campaign-v2`
120
123
  - Internal MCP workflow prompt: `refill-sends-workflow`
@@ -37,7 +37,7 @@ function getInstallVersion() {
37
37
  }
38
38
  }
39
39
 
40
- const CODEX_PLUGIN_VERSION = "0.1.53";
40
+ const CODEX_PLUGIN_VERSION = "0.1.54";
41
41
  const CODEX_PLUGIN_COMPAT_VERSIONS = [
42
42
  "0.1.8",
43
43
  "0.1.9",
@@ -75,6 +75,7 @@ const CODEX_PLUGIN_COMPAT_VERSIONS = [
75
75
  "0.1.41",
76
76
  "0.1.51",
77
77
  "0.1.52",
78
+ "0.1.53",
78
79
  ];
79
80
  const RAW_INSTALL_PACKAGE_SPEC =
80
81
  process.env.SELLABLE_INSTALL_PACKAGE_SPEC || "@sellable/install@latest";
@@ -190,7 +191,7 @@ Auth:
190
191
  Install is auth-free by default. Sign in happens on the first run of
191
192
  /sellable:create-campaign, /sellable:create-evergreen-campaigns,
192
193
  /sellable:foundation, /sellable:content, /sellable:create-post, or
193
- /sellable:refill-sends in Claude Code or Codex,
194
+ /sellable:refresh-sender-engagement, or /sellable:refill-sends in Claude Code or Codex,
194
195
  where the agent walks you through signup or sign-in and stores credentials
195
196
  in ~/.sellable/config.json.
196
197
 
@@ -220,6 +221,7 @@ function printCreateCommandHint() {
220
221
  { label: "Foundation", command: "/sellable:foundation" },
221
222
  { label: "Content", command: "/sellable:content" },
222
223
  { label: "Post", command: "/sellable:create-post" },
224
+ { label: "Refresh", command: "/sellable:refresh-sender-engagement" },
223
225
  { label: "Refill", command: "/sellable:refill-sends" },
224
226
  ]);
225
227
  console.log("");
@@ -231,6 +233,7 @@ function printCreateCommandHint() {
231
233
  { label: "Foundation", command: "$sellable:foundation" },
232
234
  { label: "Content", command: "$sellable:content" },
233
235
  { label: "Post", command: "$sellable:create-post" },
236
+ { label: "Refresh", command: "$sellable:refresh-sender-engagement" },
234
237
  { label: "Refill", command: "$sellable:refill-sends" },
235
238
  ]);
236
239
  console.log("");
@@ -1094,6 +1097,29 @@ const REFILL_SENDS_ALLOWED_TOOLS = [
1094
1097
  "mcp__sellable__get_sender",
1095
1098
  ];
1096
1099
 
1100
+ const REFRESH_SENDER_ENGAGEMENT_ALLOWED_TOOLS = [
1101
+ "mcp__sellable__get_auth_status",
1102
+ "mcp__sellable__start_cli_login",
1103
+ "mcp__sellable__wait_for_cli_login",
1104
+ "mcp__sellable__get_active_workspace",
1105
+ "mcp__sellable__list_workspaces",
1106
+ "mcp__sellable__set_active_workspace",
1107
+ "mcp__sellable__get_subskill_prompt",
1108
+ "mcp__sellable__search_subskill_prompts",
1109
+ "mcp__sellable__list_senders",
1110
+ "mcp__sellable__get_sender",
1111
+ "mcp__sellable__get_campaigns",
1112
+ "mcp__sellable__get_campaign",
1113
+ "mcp__sellable__get_campaign_context",
1114
+ "mcp__sellable__get_campaign_table_schema",
1115
+ "mcp__sellable__list_tables",
1116
+ "mcp__sellable__get_rows_minimal",
1117
+ "mcp__sellable__fetch_linkedin_posts",
1118
+ "mcp__sellable__select_promising_posts",
1119
+ "mcp__sellable__fetch_post_engagers",
1120
+ "mcp__sellable__add_on_demand_leads",
1121
+ ];
1122
+
1097
1123
  function allowedToolsYaml(tools) {
1098
1124
  return [...new Set(tools)].map((tool) => ` - ${tool}`).join("\n");
1099
1125
  }
@@ -1977,6 +2003,75 @@ then retry \`get_subskill_prompt\`.
1977
2003
  `, host, "refill-sends");
1978
2004
  }
1979
2005
 
2006
+ function refreshSenderEngagementSkillMd(host = "shared") {
2007
+ try {
2008
+ const here = dirname(fileURLToPath(import.meta.url));
2009
+ const templatePath = join(
2010
+ here,
2011
+ "..",
2012
+ "skill-templates",
2013
+ "refresh-sender-engagement.md"
2014
+ );
2015
+ if (existsSync(templatePath)) {
2016
+ return stampInstalledHost(
2017
+ addOrReplaceAllowedTools(
2018
+ readFileSync(templatePath, "utf8"),
2019
+ REFRESH_SENDER_ENGAGEMENT_ALLOWED_TOOLS
2020
+ ),
2021
+ host,
2022
+ "refresh-sender-engagement"
2023
+ );
2024
+ }
2025
+ } catch {
2026
+ // fall through to hardcoded fallback below
2027
+ }
2028
+ return stampInstalledHost(`---
2029
+ name: refresh-sender-engagement
2030
+ description: Refresh sender-owned Post Engagers campaigns by finding active Signal Discovery campaigns, fetching recent sender-authored posts, and adding net-new engagers without sending.
2031
+ visibility: public
2032
+ allowed-tools:
2033
+ ${allowedToolsYaml(REFRESH_SENDER_ENGAGEMENT_ALLOWED_TOOLS)}
2034
+ ---
2035
+
2036
+ # Sellable Refresh Sender Engagement
2037
+
2038
+ Use this as the customer-facing entrypoint for the Sellable
2039
+ \`refresh-sender-engagement\` workflow. It finds active sender-owned Post
2040
+ Engagers / Signal Discovery campaigns, fetches recent sender-authored LinkedIn
2041
+ posts, pulls latest engagers, filters to ICP, and adds net-new leads with
2042
+ dedupe. It never creates messages, approves rows, schedules sends, or launches
2043
+ campaigns.
2044
+
2045
+ ## Bootstrap
2046
+
2047
+ MCP prompt and command access are required. Do not inspect repo files, run shell
2048
+ commands, use \`npm\`, \`node\`, local harness scripts, or read local prompt
2049
+ files to emulate this workflow.
2050
+
2051
+ If the Sellable MCP prompt tools are unavailable, stop and say this is a Codex
2052
+ install/reload problem. Tell the user to run
2053
+ \`curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh\`, fully quit and reopen Codex
2054
+ Desktop, then start a new thread.
2055
+
2056
+ ## Execute Workflow
2057
+
2058
+ 1. Call \`mcp__sellable__get_auth_status({})\`.
2059
+ 2. Load the canonical prompt via
2060
+ \`mcp__sellable__get_subskill_prompt({ subskillName: "refresh-sender-engagement" })\`.
2061
+ If the response has \`hasMore=true\`, continue with \`nextOffset\` until
2062
+ \`hasMore=false\`.
2063
+ 3. Follow the canonical prompt exactly. Target active/paused sender-owned Post
2064
+ Engagers campaigns backed by Signal Discovery, and do not touch shared lanes
2065
+ or send-state tools.
2066
+
2067
+ ## MCP Prompt Fallback
2068
+
2069
+ If exact subskill lookup fails, use
2070
+ \`mcp__sellable__search_subskill_prompts({ query: "refresh-sender-engagement", includePublic: true, includeInternal: true })\`,
2071
+ then retry \`get_subskill_prompt\`.
2072
+ `, host, "refresh-sender-engagement");
2073
+ }
2074
+
1980
2075
  function genericSellableSkillMd({ name, title, description, host = "shared" }) {
1981
2076
  return stampInstalledHost(`---
1982
2077
  name: ${name}
@@ -2450,6 +2545,12 @@ function codexPluginSkills() {
2450
2545
  description: "Capture ideas and draft LinkedIn posts in your voice",
2451
2546
  skillMd: createPostSkillMd(),
2452
2547
  },
2548
+ {
2549
+ dir: "sellable-refresh-sender-engagement",
2550
+ displayName: "Sellable Refresh Sender Engagement",
2551
+ description: "Refresh post-engager campaigns from recent sender posts",
2552
+ skillMd: refreshSenderEngagementSkillMd("codex"),
2553
+ },
2453
2554
  {
2454
2555
  dir: "sellable-refill-sends",
2455
2556
  displayName: "Sellable Refill Sends",
@@ -2681,6 +2782,19 @@ function claudeCommands() {
2681
2782
  argumentHint: "[post idea or source material]",
2682
2783
  skillMd: createPostSkillMd(),
2683
2784
  },
2785
+ {
2786
+ name: "refresh-sender-engagement",
2787
+ title: "Refresh Sender Engagement",
2788
+ filename: join("sellable", "refresh-sender-engagement.md"),
2789
+ description:
2790
+ "Refresh sender-owned Post Engagers campaigns from recent sender posts.",
2791
+ argumentHint: "[--sender name-or-id ...] [lookback window]",
2792
+ skillMd: refreshSenderEngagementSkillMd("claude"),
2793
+ allowedTools: [
2794
+ "AskUserQuestion",
2795
+ ...REFRESH_SENDER_ENGAGEMENT_ALLOWED_TOOLS,
2796
+ ],
2797
+ },
2684
2798
  {
2685
2799
  name: "refill-sends",
2686
2800
  title: "Refill Sends",
@@ -3988,6 +4102,7 @@ function printNextSteps(installedHosts, authReused) {
3988
4102
  { label: "Foundation", command: "/sellable:foundation" },
3989
4103
  { label: "Content", command: "/sellable:content" },
3990
4104
  { label: "Post", command: "/sellable:create-post" },
4105
+ { label: "Refresh", command: "/sellable:refresh-sender-engagement" },
3991
4106
  { label: "Refill", command: "/sellable:refill-sends" },
3992
4107
  ]);
3993
4108
  console.log("");
@@ -4000,6 +4115,7 @@ function printNextSteps(installedHosts, authReused) {
4000
4115
  { label: "Foundation", command: "$sellable:foundation" },
4001
4116
  { label: "Content", command: "$sellable:content" },
4002
4117
  { label: "Post", command: "$sellable:create-post" },
4118
+ { label: "Refresh", command: "$sellable:refresh-sender-engagement" },
4003
4119
  { label: "Refill", command: "$sellable:refill-sends" },
4004
4120
  ]);
4005
4121
  console.log("");
@@ -4291,12 +4407,14 @@ async function main() {
4291
4407
  console.log(` Claude Code: /sellable:foundation`);
4292
4408
  console.log(` Claude Code: /sellable:content`);
4293
4409
  console.log(` Claude Code: /sellable:create-post`);
4410
+ console.log(` Claude Code: /sellable:refresh-sender-engagement`);
4294
4411
  console.log(` Claude Code: /sellable:refill-sends`);
4295
4412
  console.log(` Codex: $sellable:create-campaign`);
4296
4413
  console.log(` Codex: $sellable:create-evergreen-campaigns`);
4297
4414
  console.log(` Codex: $sellable:foundation`);
4298
4415
  console.log(` Codex: $sellable:content`);
4299
4416
  console.log(` Codex: $sellable:create-post`);
4417
+ console.log(` Codex: $sellable:refresh-sender-engagement`);
4300
4418
  console.log(` Codex: $sellable:refill-sends`);
4301
4419
  process.exit(0);
4302
4420
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.285",
3
+ "version": "0.1.287",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code and Codex",
6
6
  "bin": {
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: refresh-sender-engagement
3
+ description: Top up a sender's post-engager pipeline — fetch their recent LinkedIn posts, pull new engagers, filter by headline ICP criteria, and add net-new leads to their post-engagers campaign with dedupe. Schedule-automation friendly ("refresh sender engagement for these people"). Read-only on LinkedIn; never sends.
4
+ visibility: public
5
+ allowed-tools:
6
+ - mcp__sellable__get_auth_status
7
+ - mcp__sellable__start_cli_login
8
+ - mcp__sellable__wait_for_cli_login
9
+ - mcp__sellable__get_active_workspace
10
+ - mcp__sellable__list_workspaces
11
+ - mcp__sellable__set_active_workspace
12
+ - mcp__sellable__get_subskill_prompt
13
+ - mcp__sellable__search_subskill_prompts
14
+ - mcp__sellable__list_senders
15
+ - mcp__sellable__get_sender
16
+ - mcp__sellable__get_campaigns
17
+ - mcp__sellable__get_campaign
18
+ - mcp__sellable__get_campaign_context
19
+ - mcp__sellable__get_campaign_table_schema
20
+ - mcp__sellable__list_tables
21
+ - mcp__sellable__get_rows_minimal
22
+ - mcp__sellable__fetch_linkedin_posts
23
+ - mcp__sellable__select_promising_posts
24
+ - mcp__sellable__fetch_post_engagers
25
+ - mcp__sellable__add_on_demand_leads
26
+ ---
27
+
28
+ # Refresh Sender Engagement
29
+
30
+ <role>
31
+ You are a pipeline supply agent. People who engage with a sender's LinkedIn posts are their warmest prospects; your job is to capture them into the sender's post-engagers campaign before they go cold — with zero duplicates and zero sends.
32
+ </role>
33
+
34
+ <inputs>
35
+ The invoking prompt names the senders ("refresh sender engagement for csreyes92 and thomas"). Resolve each via `list_senders` (match name/handle/LinkedIn URL). With no names given, inspect the active workspace and refresh every connected sender that has an active/paused sender-owned Post Engagers campaign backed by Signal Discovery.
36
+
37
+ Optional: lookback window (default: posts from the last 30 days), engagement sources (default `both` reactions+comments), target sender names/ids, maximum posts per sender (default 5, hard cap 5 unless the user explicitly asks for more), and target campaign ids/names when the user wants to force a specific campaign.
38
+ </inputs>
39
+
40
+ <entrypoint>
41
+ This is a public Sellable command:
42
+
43
+ - Claude Code: `/sellable:refresh-sender-engagement`
44
+ - Codex: `$sellable:refresh-sender-engagement`
45
+
46
+ Use this command when the user asks to refresh recent engagers, top up tracked
47
+ campaign post engagers, pull latest engagers from sender posts, or refill warm
48
+ post-engager source rows. It is not a send-refill command; if the user asks to
49
+ prepare/schedule sends after adding rows, finish this refresh first and then
50
+ suggest `refill-sends`.
51
+ </entrypoint>
52
+
53
+ <objective>
54
+ For each target sender/campaign:
55
+
56
+ 1. **Find active Signal Discovery/Post Engagers campaigns first**:
57
+ - Call `get_auth_status` and confirm the active workspace.
58
+ - Call `get_campaigns` and, when needed, `list_tables`/`get_campaign` to find candidate campaigns.
59
+ - Keep only active or paused campaign-backed sender-owned Post Engagers campaigns. Strong signals include campaign/table names like `<Sender> - Post Engagers`, `sourceProvider:"signal-discovery"`, sender attachment to exactly one sender, and source/list/table readback indicating post engagers.
60
+ - Exclude shared Signal Discovery lanes, Shared Cold Fallback lanes, archived/completed campaigns, non-campaign tables, direct/on-demand-only campaigns, and any campaign attached to multiple senders unless the user explicitly selected it and the readback proves it is sender-owned.
61
+ - If no matching campaign exists for a sender, report "no active Post Engagers Signal Discovery campaign — create one first" and skip; do not silently create campaigns.
62
+ 2. **Resolve the sender and source boundary**:
63
+ - Match each candidate campaign to its sender from `list_senders`/`get_sender`.
64
+ - Use the sender's own LinkedIn profile URL/handle as the only source author boundary.
65
+ - Never scrape third-party authors into a sender-owned Post Engagers campaign.
66
+ 3. **Find relevant sender-authored posts to refresh**:
67
+ - Call `fetch_linkedin_posts({ linkedinUrl: sender profile, limit: 25 })`.
68
+ - Keep original posts authored by that exact sender, not reposts, from the lookback window.
69
+ - Rank posts by recency, engagement count, and fit to the campaign's buyer/problem/topic. Prefer posts likely to attract the target buyer over generic company updates.
70
+ - If the campaign has an existing Signal Discovery/source state that names tracked/selected posts, prefer refreshing those posts when they are still inside the lookback window and relevant; otherwise choose the strongest recent sender-authored posts.
71
+ - When the product flow expects selected posts to be visible, call `select_promising_posts` before scraping.
72
+ 4. **Pull latest engagers**:
73
+ - For the top posts (up to 5 per sender per run), call `fetch_post_engagers({ postUrl, sources })`.
74
+ - Default `sources` to `"both"` unless the user requested reactions-only or comments-only.
75
+ 5. **Filter to ICP** using the campaign's existing headline ICP criteria (from `get_campaign` brief/rubrics/table schema). Judge each engager's headline against those criteria; exclude obvious non-fits, the sender's own colleagues, existing employees, students/job-seekers, competitors, and anyone with no usable headline. When the campaign has no criteria, keep likely decision-makers/operators and exclude weak-fit profiles.
76
+ 6. **Add net-new leads only**:
77
+ - Use `add_on_demand_leads({ tableId, leads, skipDuplicates: true })` with name, headline-derived title, profile URL, and source/post context where the tool accepts it.
78
+ - Dedupe is mandatory. Never disable dedupe on a scheduled run.
79
+ - Do not generate, approve, schedule, or send messages.
80
+ 7. **Report**: campaigns inspected, target campaigns selected, posts scanned, engagers found, ICP-passing, net-new added per sender/campaign. If a sender posted nothing in the window, say "no recent posts — nothing to refresh" (that is a truthful no-op, not a failure).
81
+ </objective>
82
+
83
+ <safety>
84
+ - LinkedIn operations here are read-only fetches plus adding rows to a campaign table. **No messages are generated, approved, or sent by this skill.**
85
+ - Respect workspace boundaries: only add leads to campaigns in the active workspace, and only for senders that belong to it.
86
+ - Respect campaign boundaries: only add engagers to the matched sender-owned Post Engagers campaign/table. Do not mix shared-lane engagers into sender-owned campaigns or sender-owned engagers into shared lanes.
87
+ - Cap provider usage per run: at most 5 posts × `fetch_post_engagers` per sender. If the invoking automation wants more, it must say so explicitly.
88
+ - Never call `start_campaign`, `attach_sequence`, `queue_campaign_cells`, `start_campaign_message_preparation`, approval tools, or any send/schedule tool.
89
+ </safety>
90
+
91
+ <output>
92
+ ```
93
+ Sender Engagement Refresh — {date}
94
+ • csreyes92: 3 recent posts → 142 engagers → 38 ICP-fit → 15 net-new added to "Christian Reyes - Post Engagers"
95
+ • thomas: no posts in last 30 days — nothing to refresh (consider /engage or /create-post to restart supply)
96
+ Follow with fill-send-horizon to prepare messages for the new leads.
97
+ ```
98
+ </output>