@sellable/install 0.1.220 → 0.1.222

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.
@@ -991,8 +991,8 @@ const CREATE_CAMPAIGN_ALLOWED_TOOLS = [
991
991
  "mcp__sellable__record_campaign_review_batch",
992
992
  "mcp__sellable__queue_campaign_cells",
993
993
  "mcp__sellable__wait_for_campaign_processing",
994
- "mcp__sellable__refill_campaign_sends",
995
994
  "mcp__sellable__resolve_campaign_fill_route",
995
+ "mcp__sellable__get_campaign_refill_state",
996
996
  "mcp__sellable__fill_campaign_horizon",
997
997
  "mcp__sellable__start_campaign_message_preparation",
998
998
  "mcp__sellable__get_campaign_message_preparation_status",
@@ -28,14 +28,16 @@ export const REQUIRED_SELLABLE_MCP_TOOLS = [
28
28
  "get_campaign_messages_preview",
29
29
  "attach_sequence",
30
30
  "attach_recommended_sequence",
31
- "refill_campaign_sends",
32
31
  "resolve_campaign_fill_route",
32
+ "get_campaign_refill_state",
33
33
  "start_campaign_message_preparation",
34
34
  "get_campaign_message_preparation_status",
35
35
  "cancel_campaign_message_preparation",
36
36
  "start_campaign",
37
37
  ];
38
38
 
39
+ export const FORBIDDEN_SELLABLE_MCP_TOOLS = ["refill_campaign_sends"];
40
+
39
41
  export const CREATE_CAMPAIGN_SMOKE_CALLS = [
40
42
  {
41
43
  name: "get_auth_status",
@@ -59,6 +61,14 @@ export const CREATE_CAMPAIGN_SMOKE_CALLS = [
59
61
  limit: 1200,
60
62
  },
61
63
  },
64
+ {
65
+ name: "get_subskill_prompt",
66
+ arguments: {
67
+ subskillName: "refill-sends-workflow",
68
+ offset: 0,
69
+ limit: 1200,
70
+ },
71
+ },
62
72
  {
63
73
  name: "get_subskill_asset",
64
74
  arguments: {
@@ -310,6 +320,7 @@ function summarizeAttempt(result, attempt) {
310
320
  ok: result.ok === true,
311
321
  availableToolCount: result.availableTools?.length || 0,
312
322
  missingToolCount: result.missingTools?.length || 0,
323
+ forbiddenToolCount: result.forbiddenTools?.length || 0,
313
324
  error: result.error || null,
314
325
  createCampaignSmoke: result.createCampaignSmoke
315
326
  ? {
@@ -379,6 +390,7 @@ async function verifySellableMcpRuntimeOnce({
379
390
 
380
391
  let availableTools = [];
381
392
  let missingTools = [...requiredTools];
393
+ let forbiddenTools = [];
382
394
  let createCampaignSmoke = null;
383
395
  let error = null;
384
396
 
@@ -390,7 +402,19 @@ async function verifySellableMcpRuntimeOnce({
390
402
  });
391
403
  availableTools = toolList.tools.map((tool) => tool.name).sort();
392
404
  missingTools = missingRequiredTools(toolList.tools, requiredTools);
393
- if (missingTools.length === 0) {
405
+ forbiddenTools = availableTools.filter((tool) =>
406
+ FORBIDDEN_SELLABLE_MCP_TOOLS.includes(tool)
407
+ );
408
+ if (forbiddenTools.length > 0) {
409
+ createCampaignSmoke = {
410
+ ok: false,
411
+ missingTools: [],
412
+ calls: [],
413
+ error: `Forbidden MCP tool(s) exposed: ${forbiddenTools.join(", ")}`,
414
+ startedAt: new Date().toISOString(),
415
+ completedAt: new Date().toISOString(),
416
+ };
417
+ } else if (missingTools.length === 0) {
394
418
  createCampaignSmoke = await verifyCreateCampaignSmoke({
395
419
  client,
396
420
  availableTools,
@@ -420,13 +444,18 @@ async function verifySellableMcpRuntimeOnce({
420
444
  }
421
445
 
422
446
  return {
423
- ok: !error && missingTools.length === 0 && createCampaignSmoke?.ok === true,
447
+ ok:
448
+ !error &&
449
+ missingTools.length === 0 &&
450
+ forbiddenTools.length === 0 &&
451
+ createCampaignSmoke?.ok === true,
424
452
  skipped: false,
425
453
  command,
426
454
  args,
427
455
  requiredTools,
428
456
  availableTools,
429
457
  missingTools,
458
+ forbiddenTools,
430
459
  createCampaignSmoke,
431
460
  stderrTail: stderrLines,
432
461
  error: error ? redact(error) : null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.220",
3
+ "version": "0.1.222",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code and Codex",
6
6
  "bin": {
@@ -47,8 +47,8 @@ allowed-tools:
47
47
  - mcp__sellable__record_campaign_review_batch
48
48
  - mcp__sellable__queue_campaign_cells
49
49
  - mcp__sellable__wait_for_campaign_processing
50
- - mcp__sellable__refill_campaign_sends
51
50
  - mcp__sellable__resolve_campaign_fill_route
51
+ - mcp__sellable__get_campaign_refill_state
52
52
  - mcp__sellable__fill_campaign_horizon
53
53
  - mcp__sellable__start_campaign_message_preparation
54
54
  - mcp__sellable__get_campaign_message_preparation_status
@@ -118,44 +118,38 @@ The default path stays the existing first campaign-table execution slice:
118
118
  review the normal `reviewBatchLimit:15`, approve reviewed draft rows, then move
119
119
  to Settings/sequence/final greenlight. For any plain post-mint fill request
120
120
  such as "fill campaigns", "fill up", "refill sends", "max out sends", or
121
- "load sends", first call `refill_campaign_sends({ mode:"plan", intent:"plain" })`.
122
- If the user did not include `--yolo`, report the plan and stop. If the user did
123
- include `--yolo`, call plan first, inspect blockers, then call
124
- `refill_campaign_sends({ mode:"apply", yolo:true, planRevision, actionIds })`
125
- using only the selected immutable action IDs from the fresh plan. Plain fill is
126
- not an alias for `fill_campaign_horizon` or campaign creation. Keep
127
- `resolve_campaign_fill_route`, `fill_campaign_horizon`, and
128
- `start_campaign_message_preparation` as fallback/lower-level diagnostics only
129
- when `refill_campaign_sends` is unavailable or when the refill command itself
130
- returns an evergreen subplan. `fill_campaign_horizon` is evergreen-only and
131
- must not be used for regular campaign refill. When more leads are needed, the
132
- plan must recommend same-campaign source-ladder replenishment; do not create
133
- warm-post-engager side campaigns, on-demand campaigns, or unrelated campaigns.
134
- If fallback `resolve_campaign_fill_route` returns `route:"ask_create"`, ask
135
- whether to create a normal campaign or evergreen campaigns; campaign creation is
136
- never the default response to plain fill.
121
+ "load sends", hand off to the skill-led refill workflow:
122
+
123
+ ```text
124
+ get_subskill_prompt({ subskillName: "refill-sends-workflow" })
125
+ resolve_campaign_fill_route({ intent:"plain" })
126
+ get_campaign_refill_state
127
+ ```
128
+
129
+ Plain fill is not an alias for `fill_campaign_horizon` or campaign creation.
130
+ `fill_campaign_horizon` is evergreen-only and must not be used for regular
131
+ campaign refill. Route outcomes are `route:"evergreen_horizon"`,
132
+ `route:"active_campaigns"`, and `route:"ask_create"`; stay in the same `campaignOfferId`/`campaignId` context after minting. If route resolution
133
+ returns `route:"ask_create"`, ask whether to create a normal campaign or
134
+ evergreen campaigns. Campaign creation is allowed only after this route and
135
+ explicit user selection; it is never the default response to plain fill. When
136
+ more leads are needed, the refill workflow must recommend same-campaign
137
+ source-ladder replenishment; do not create warm-post-engager side campaigns,
138
+ on-demand campaigns, or unrelated campaigns. Surface sender-health blockers
139
+ separately from prepared/approved/scheduled counts.
140
+
137
141
  Treat active fills as capacity-fill preparation: calculate the bounded target
138
- from sender capacity when needed, then let the preparation job queue pending
139
- `Enrich Prospect` cells, wait for ICP/rubric and Generate Message cells to
140
- cascade, and mark ready or approve only the target cohort. Do not count
141
- `checkedRows` as enriched rows; it is only the table cursor. Use
142
- `progress.enrichedRows`, `progress.needsEnrichRows`, `activeCellCount`,
143
- `preparedMessages`, `approvedRows`, active preparation jobs, sender-health
144
- blockers, target, estimated row budget remaining, and `stopReason` to explain
145
- progress. If the user says "prepare/generate X messages", set
146
- `targetPreparedMessages:X`, omit `maxRowsToCheck`, and keep
147
- `approvalMode:"mark_ready"`. The backend calibrates on at least 100 actually
148
- enriched rows, estimates the row budget from observed rubric/pass yield, caps
149
- `maxRowsToCheck` at 300, then continues in batches capped at 100 newly checked
150
- rows. It will not pull another row batch while the current checked batch still
151
- has queueable or active cells. If the user says "approve X messages", use
152
- `approvalMode:"approve"` but still do not launch. If the user says "schedule X
153
- sends" or asks to fill sender sends, use `approvalMode:"approve"` only when
154
- the user explicitly asked for approval, approve exactly the bounded X-message
155
- cohort during preparation, then re-read scheduled counts; if scheduler-owned
156
- cells are not present, report prepared/approved/ready awaiting scheduler
157
- instead of success. Final launch remains a separate explicit user greenlight
158
- and must verify that bounded cohort and must not broad approve-all.
142
+ from sender capacity when needed, then use the refill workflow to decide source
143
+ replenishment, enrichment/prep, approval policy, and scheduler proof. Mutation
144
+ requires exact visible approval and a fresh `get_campaign_refill_state` reread.
145
+ If the user says "prepare/generate X messages", use message-prep primitives with
146
+ `targetPreparedMessages:X` and default `approvalMode:"mark_ready"`. If the user
147
+ says "approve X messages", use `approvalMode:"approve"` only for the bounded
148
+ cohort and still do not launch. If the user says "schedule X sends", approve
149
+ only when explicitly requested, then reread scheduled counts; if
150
+ scheduler-owned cells are not present, report prepared/approved/ready awaiting
151
+ scheduler instead of success. Final launch remains a separate explicit user
152
+ greenlight and must not broad approve-all.
159
153
  When approving reviewed draft rows in the campaign table, resolve the actual
160
154
  visible `Approved` cells with `select_campaign_cells({ columnRole: "approved",
161
155
  rowSelector: { type: "rowIds", rowIds } })` and `update_cell` those returned
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: refill-sends
3
+ description: Plan regular campaign and evergreen campaign send refill work through the skill-led refill workflow.
4
+ visibility: public
5
+ allowed-tools:
6
+ - mcp__sellable__get_subskill_prompt
7
+ - mcp__sellable__search_subskill_prompts
8
+ - mcp__sellable__resolve_campaign_fill_route
9
+ - mcp__sellable__get_campaign_refill_state
10
+ - mcp__sellable__fill_campaign_horizon
11
+ - mcp__sellable__get_campaign
12
+ - mcp__sellable__get_campaign_message_preparation_status
13
+ - mcp__sellable__start_campaign_message_preparation
14
+ - mcp__sellable__cancel_campaign_message_preparation
15
+ - mcp__sellable__import_leads
16
+ - mcp__sellable__wait_for_lead_list_ready
17
+ - mcp__sellable__confirm_lead_list
18
+ - mcp__sellable__search_signals
19
+ - mcp__sellable__fetch_post_engagers
20
+ - mcp__sellable__search_sales_nav
21
+ - mcp__sellable__lookup_sales_nav_filter
22
+ - mcp__sellable__search_prospeo
23
+ - mcp__sellable__search_prospeo_companies
24
+ - mcp__sellable__confirm_prospeo_company_accounts
25
+ - mcp__sellable__load_csv_linkedin_leads
26
+ - mcp__sellable__load_csv_domains
27
+ - mcp__sellable__list_dnc_entries
28
+ - mcp__sellable__load_csv_dnc_entries
29
+ - mcp__sellable__get_rows
30
+ - mcp__sellable__get_rows_minimal
31
+ - mcp__sellable__get_table_rows
32
+ ---
33
+
34
+ # Refill Sends
35
+
36
+ Use this public wrapper for plain operator requests such as "fill", "refill sends",
37
+ "max out sends", "load everyone up", or "fill horizon sends".
38
+
39
+ Load the internal workflow prompt before taking any operational step:
40
+
41
+ ```text
42
+ get_subskill_prompt({ subskillName: "refill-sends-workflow" })
43
+ ```
44
+
45
+ Then follow that workflow exactly. The default path is read-only research:
46
+ resolve the route, read target refill state, report the next safe step, and stop
47
+ before mutation unless the user has explicitly approved the exact workspace,
48
+ campaign/table/source ids, caps/dates, approval mode, expected side effects,
49
+ and stop/rollback condition.
50
+
51
+ Public concepts are regular campaign and evergreen campaign. Internal direct
52
+ campaign types are unsupported refill targets. `fill_campaign_horizon` is only a
53
+ legacy evergreen-only lower-level primitive after route and refill-state
54
+ evidence proves an evergreen target.