@sellable/mcp 0.1.373 → 0.1.375

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/server.js CHANGED
@@ -11,7 +11,7 @@ import { fillCampaignHorizon } from "./tools/campaign-horizon-fill.js";
11
11
  import { cancelPrepareCampaignMessages, getPrepareCampaignMessagesStatus, startPrepareCampaignMessages, } from "./tools/campaign-message-preparation.js";
12
12
  import { getCampaignRefillState } from "./tools/campaign-refill-state.js";
13
13
  import { getCampaignTableSchema, queueCampaignCells, recordCampaignReviewBatch, reviseMessageTemplateAndRerun, selectCampaignCells, waitForCampaignProcessing, } from "./tools/campaign-processing.js";
14
- import { createCampaign, duplicateCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
14
+ import { archiveCampaign, createCampaign, duplicateCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
15
15
  import { queueCells, updateCell } from "./tools/cells.js";
16
16
  import { handleStartCliLogin, handleWaitForCliLogin, } from "./tools/cli-login.js";
17
17
  import { handleDeleteColumn } from "./tools/column-delete.js";
@@ -298,6 +298,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
298
298
  case "pause_campaign":
299
299
  result = await pauseCampaign(args?.campaignId);
300
300
  break;
301
+ case "archive_campaign":
302
+ result = await archiveCampaign(args?.campaignId);
303
+ if (args?.campaignId && result?.success) {
304
+ markCampaignContextDirty(args.campaignId, "archive_campaign");
305
+ }
306
+ break;
301
307
  case "duplicate_campaign":
302
308
  result = await duplicateCampaign(args?.campaignId);
303
309
  if (result?.campaignOfferId) {
@@ -827,6 +827,13 @@ export declare function startCampaign(campaignId: string): Promise<{
827
827
  export declare function pauseCampaign(campaignId: string): Promise<{
828
828
  success: boolean;
829
829
  }>;
830
+ export declare function archiveCampaign(campaignId: string): Promise<{
831
+ success: boolean;
832
+ campaignStatus: string;
833
+ archivedAlready?: boolean;
834
+ cellsReset?: number;
835
+ workflowTableId?: string;
836
+ }>;
830
837
  export declare function duplicateCampaign(campaignId: string): Promise<{
831
838
  campaignOfferId: string;
832
839
  campaignName: string;
@@ -177,6 +177,21 @@ function assertBriefHandoffWatchUrl(watchUrl, campaignId) {
177
177
  "with create_campaign({ campaignId }) or get_campaign before asking for approval.");
178
178
  }
179
179
  export const campaignToolDefinitions = [
180
+ {
181
+ name: "archive_campaign",
182
+ description: "Archive a campaign through Sellable's product archive endpoint. This is an explicit cleanup/archive action, is idempotent, and may unschedule pending cells owned by that campaign table. Do not use from refill/setup commands unless the user explicitly asked to archive exact campaign ids.",
183
+ inputSchema: {
184
+ type: "object",
185
+ properties: {
186
+ campaignId: {
187
+ type: "string",
188
+ description: "Exact CampaignOffer id to archive.",
189
+ },
190
+ },
191
+ required: ["campaignId"],
192
+ additionalProperties: false,
193
+ },
194
+ },
180
195
  {
181
196
  name: "duplicate_campaign",
182
197
  description: "Duplicate a campaign by calling Sellable's existing duplicate endpoint. Returns campaignOfferId, campaignName, and workflowTableId for the new copy.",
@@ -1007,6 +1022,10 @@ export async function pauseCampaign(campaignId) {
1007
1022
  const api = getApi();
1008
1023
  return api.post(`/api/v3/campaigns/${campaignId}/pause`);
1009
1024
  }
1025
+ export async function archiveCampaign(campaignId) {
1026
+ const api = getApi();
1027
+ return api.post(`/api/v3/campaigns/${campaignId}/archive`);
1028
+ }
1010
1029
  export async function duplicateCampaign(campaignId) {
1011
1030
  const api = getApi();
1012
1031
  return api.post(`/api/v3/campaigns/${campaignId}/duplicate`);
@@ -6,7 +6,7 @@ async function postSetupEvergreenCampaigns(body) {
6
6
  export const setupEvergreenCampaignsToolDefinitions = [
7
7
  {
8
8
  name: "setup_evergreen_campaigns",
9
- description: "Evergreen campaign setup plan/verify command. Use plan mode first to inspect exact workspace/sender/campaign/table/source state and receive immutable lane packets. `selectedSenderIds` is a legacy shorthand for both scopes; prefer `postEngagerSenderIds` for the Post Engagers sender scope and `sharedSenderIds` for the shared lane sender scope when they differ. The command plans one Post Engagers lane per post-engager sender plus shared Signal Discovery and Shared Cold Fallback lanes for the shared sender set. yolo is only a parent-skill auto-execution hint for safe lane packets; this backend command remains read-only in plan mode and verifies receipts in verify mode. Each lane packet includes workerDispatch with acceptedRuntimes, rejectedRuntimes, requiresVisibleThreadOrDurableReceipt, and receiptArtifactHint; `multi_agent_v1.spawn_agent`/opaque spawn_agent is not accepted for mutating command proof unless the parent has visible thread or durable receipt proof. In local Codex, call `codex_app.list_projects` first, then `codex_app.create_thread` with a local project target; do not create a worktree for lane execution. When safe-yolo needs normal setup work, the parent skill may ask for bounded delegated approval: one approval over the current planRevision, selected action ids, caps, allowed side-effect classes, and stop conditions lets lane workers execute without per-substep approval while staying inside that packet. Lane workers must explicitly load and use the installed `$sellable:create-campaign` wrapper as the nested workflow entrypoint, then load `create-campaign-v2` and `create-campaign-v2/core/flow.v2.json`; they must execute creation, source import, create-campaign workflow steps, generate-messages, sequence attachment, pause_campaign review-state transition when the current table is still DRAFT, and review readiness through that existing create-campaign workflow/subskills, then return receipts here for verification. Customer-visible verify receipts must set status:'succeeded' or status:'completed'; status:'passed', status:'pass', and status:'passed_with_warnings' are rejected as primary success statuses. Receipts must include createCampaignStepReceipt with setupPlanCall, createCampaignWorkflowReceipt, campaignBriefReceipt, sourceDecisionReceipt, filterDecisionReceipt, messageDraftingReceipt, reviewBatchReceipt, sequenceReceipt, and verifyCall nested inside createCampaignStepReceipt; top-level-only copies of those objects are not enough and are not promoted by verify. setupPlanCall must use canonical keys: planRevision, actionId, laneKey, workspaceId, senderIds, campaignId, tableId, createIntent. Do not use laneActionId, lanePacketActionId, delegatedPlanRevision, delegatedActionId, or requestedCall text as a substitute for those canonical fields. createCampaignWorkflowReceipt must include skillCommand:'$sellable:create-campaign', skillName:'create-campaign', wrapperSkillLoaded:true, workflowPromptName:'create-campaign-v2', workflowPromptLoadedToHasMoreFalse:true, workflowAssetPath:'create-campaign-v2/core/flow.v2.json', workflowAssetLoaded:true, workerRuntime, workerThreadId or receiptArtifactPath, durableReceiptWritten when using a receipt file, and notAdHoc:true. messageDraftingReceipt must use exactly statusSource:'branch' or statusSource:'packaged-generate-messages-worker'; descriptive aliases such as statusSource:'package-readback-local-thread' are rejected. It must include proof that generate-messages was loaded, start_campaign_message_preparation/get_campaign_message_preparation_status ran when the packaged worker path is used, validationResult:'passed', a passed qualityReview, and at least 3 concrete sampleMessages with rowId, generatedMessageText, verdict, and issues; Do not substitute `message` for `generatedMessageText`; Do not substitute `passVerdict` for `verdict`. Before writing durable receipts, run a receipt self-check: top-level `planRevision`, `actionId`, `laneKey`, `laneType`, `workspaceId`, and `senderIds` must exist; if the self-check fails, fix the receipt before ending. Use start_campaign_message_preparation with approvalMode:\"mark_ready\" only for evergreen setup. Never call `start_campaign_message_preparation` with `approvalMode:\"approve\"`; approve exactly one semantic Approved cell through select_campaign_cells/update_cell and final proof must show approvedGeneratedMessageCount exactly 1. Shared Cold Fallback samples with a standalone name followed by 'Hey there' are rejected. This command does not launch campaigns, does not schedule sends, does not assign scheduler-owned send fields, does not raw-write campaign status, does not archive/delete cleanup targets, and does not spend paid credits.",
9
+ description: "Evergreen campaign setup plan/verify command. Use plan mode first to inspect exact workspace/sender/campaign/table/source state and receive immutable lane packets. `selectedSenderIds` is a legacy shorthand for both scopes; prefer `postEngagerSenderIds` for the Post Engagers sender scope and `sharedSenderIds` for the shared lane sender scope when they differ. The command plans one Post Engagers lane per post-engager sender plus shared Signal Discovery and Shared Cold Fallback lanes for the shared sender set. yolo is only a parent-skill auto-execution hint for safe lane packets; this backend command remains read-only in plan mode and verifies receipts in verify mode. Package-backed prompt authority: lane workers must use get_subskill_prompt and get_subskill_asset for `$sellable:create-campaign`, create-campaign-v2, generate-messages, and assets; filesystem prompt fallback is a failed UAT. Use mcp__sellable only for workspace selection and product mutations/readbacks. Do not use mcp__sellable_admin, direct DB, Prisma, or SQL as execution proof. Worker-local replans are read-only drift checks and must preserve the exact parent sender scopes, including postEngagerSenderIds:[] when intentionally empty and the exact sharedSenderIds array; if scope, planRevision, actionId, or laneKey drifts, stop with blocked:worker_plan_scope_drift before mutation. Each lane packet includes workerDispatch with acceptedRuntimes, rejectedRuntimes, requiresVisibleThreadOrDurableReceipt, and receiptArtifactHint; `multi_agent_v1.spawn_agent`/opaque spawn_agent is not accepted for mutating command proof unless the parent has visible thread or durable receipt proof. In local Codex, call `codex_app.list_projects` first, then `codex_app.create_thread` with a local project target; do not create a worktree for lane execution. When safe-yolo needs normal setup work, the parent skill may ask for bounded delegated approval: one approval over the current planRevision, selected action ids, caps, allowed side-effect classes, and stop conditions lets lane workers execute without per-substep approval while staying inside that packet. Lane workers must explicitly load and use the installed `$sellable:create-campaign` wrapper as the nested workflow entrypoint, then load `create-campaign-v2` and `create-campaign-v2/core/flow.v2.json`; they must execute creation, source import, create-campaign workflow steps, generate-messages, sequence attachment, pause_campaign review-state transition when the current table is still DRAFT, and review readiness through that existing create-campaign workflow/subskills, then return receipts here for verification. Customer-visible verify receipts must set status:'succeeded' or status:'completed'; status:'passed', status:'pass', and status:'passed_with_warnings' are rejected as primary success statuses. Receipts must include createCampaignStepReceipt with setupPlanCall, createCampaignWorkflowReceipt, campaignBriefReceipt, sourceDecisionReceipt, filterDecisionReceipt, messageDraftingReceipt, reviewBatchReceipt, sequenceReceipt, and verifyCall nested inside createCampaignStepReceipt; top-level-only copies of those objects are not enough and are not promoted by verify. setupPlanCall must use canonical keys: planRevision, actionId, laneKey, workspaceId, senderIds, campaignId, tableId, createIntent. Do not use laneActionId, lanePacketActionId, delegatedPlanRevision, delegatedActionId, or requestedCall text as a substitute for those canonical fields. createCampaignWorkflowReceipt must include skillCommand:'$sellable:create-campaign', skillName:'create-campaign', wrapperSkillLoaded:true, workflowPromptName:'create-campaign-v2', workflowPromptLoadedToHasMoreFalse:true, workflowAssetPath:'create-campaign-v2/core/flow.v2.json', workflowAssetLoaded:true, workerRuntime, workerThreadId or receiptArtifactPath, durableReceiptWritten when using a receipt file, and notAdHoc:true. messageDraftingReceipt must use exactly statusSource:'branch' or statusSource:'packaged-generate-messages-worker'; descriptive aliases such as statusSource:'package-readback-local-thread' are rejected. It must include proof that generate-messages was loaded, start_campaign_message_preparation/get_campaign_message_preparation_status ran when the packaged worker path is used, validationResult:'passed', a passed qualityReview, and at least 3 concrete sampleMessages with rowId, generatedMessageText, verdict, and issues; Do not substitute `message` for `generatedMessageText`; Do not substitute `passVerdict` for `verdict`. Before writing durable receipts, run a receipt self-check: top-level `planRevision`, `actionId`, `laneKey`, `laneType`, `workspaceId`, and `senderIds` must exist; if the self-check fails, fix the receipt before ending. Use start_campaign_message_preparation with approvalMode:\"mark_ready\" only for evergreen setup. Never call `start_campaign_message_preparation` with `approvalMode:\"approve\"`; approve exactly one semantic Approved cell through select_campaign_cells/update_cell and final proof must show approvedGeneratedMessageCount exactly 1. Shared Cold Fallback samples with a standalone name followed by 'Hey there' are rejected. This command does not launch campaigns, does not schedule sends, does not assign scheduler-owned send fields, does not raw-write campaign status, does not archive/delete cleanup targets, and does not spend paid credits.",
10
10
  inputSchema: {
11
11
  type: "object",
12
12
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.373",
3
+ "version": "0.1.375",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -73,6 +73,29 @@ readback, and setup plan/verify results. If MCP surfaces disagree on counts or
73
73
  state, record the discrepancy and resolve or explain the canonical gate before
74
74
  reporting the command complete.
75
75
 
76
+ Package-backed prompt authority: when this command or any lane worker says to
77
+ load `$sellable:create-campaign`, `create-campaign-v2`, `generate-messages`, or
78
+ any referenced workflow asset, the package-backed MCP loaders are the source of
79
+ truth. Use `get_subskill_prompt` and `get_subskill_asset` until `hasMore:false`.
80
+ Do not locate, open, read, or summarize local skill files from repo paths,
81
+ installed plugin cache paths, or any filesystem shortcut. Do not use repo-local,
82
+ plugin-cache, or filesystem `SKILL.md` files as workflow authority, even when a
83
+ session header shows a path. If package-backed prompt or asset loaders are not
84
+ callable, stop with `blocked: package_prompt_loader_unavailable`; filesystem
85
+ prompt fallback is a failed UAT and is not proof that the packaged command works.
86
+ Short form: Do not use repo-local, plugin-cache, or filesystem `SKILL.md`.
87
+ Short form: filesystem prompt fallback is a failed UAT.
88
+
89
+ Package-backed tool surface: use `mcp__sellable` only for workspace selection,
90
+ campaign/table/source/message mutations, and product-visible readbacks. Do not
91
+ use `mcp__sellable_admin`, admin workspace setters, direct DB tools, Prisma, or
92
+ SQL as part of command execution proof. Before any worker mutation, record
93
+ normal-surface workspace proof with
94
+ `set_active_workspace({ workspaceId, userConfirmed:true })` or the equivalent
95
+ `mcp__sellable` call, then reread the active workspace.
96
+ Short form: mcp__sellable only.
97
+ Short form: Do not use `mcp__sellable_admin`.
98
+
76
99
  Plan shape:
77
100
 
78
101
  - one Post Engagers lane per sender in the **Post Engagers sender scope**;
@@ -154,6 +177,20 @@ execution boundary, not guidance. Read and preserve `workerDispatch.acceptedRunt
154
177
  `workerDispatch.rejectedRuntimes`, and `workerDispatch.receiptArtifactHint`
155
178
  before dispatch.
156
179
 
180
+ Worker-local replans are read-only drift checks, never a replacement execution
181
+ basis. The parent planRevision, selectedActionIds, actionId, laneKey, workspace
182
+ id, and sender scopes remain authoritative for the worker receipt. If a worker
183
+ calls `setup_evergreen_campaigns({ mode:"plan", ... })` before mutation, that
184
+ call must include the exact original sender scopes from the parent plan,
185
+ including `postEngagerSenderIds:[]` when the Post Engagers scope is intentionally
186
+ empty, and the exact `sharedSenderIds` array. If a worker-local plan omits
187
+ `postEngagerSenderIds:[]`, changes `sharedSenderIds`, returns a different
188
+ planRevision/actionId/laneKey, or introduces any Post Engagers lane outside the
189
+ parent packet, do not mutate and do not use it as `setupPlanCall` proof; stop
190
+ with `blocked: worker_plan_scope_drift` and ask the parent to re-plan.
191
+ Short form: If a worker-local plan omits `postEngagerSenderIds:[]`, do not use it as `setupPlanCall` proof.
192
+ Short form: stop with `blocked: worker_plan_scope_drift`.
193
+
157
194
  Worker fan-out must use visible or durable execution. Preferred in local Codex
158
195
  is a visible Codex thread created with the actual Codex app thread tools:
159
196
  first call `codex_app.list_projects`, select the current repo project, then