@sellable/mcp 0.1.417 → 0.1.419

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
@@ -66,8 +66,9 @@ reader value, validates proof/AI tells, and saves content artifacts under
66
66
 
67
67
  The refill-sends public command wrapper plans and executes approval-gated send
68
68
  refills. It supports `--yolo` and optional sender selectors such as
69
- `--sender "Christian Reyes"` or typed MCP calls to `refill_sends({ yolo,
70
- senders })` from:
69
+ `--sender "Christian Reyes"`, optional through-date selectors such as
70
+ `--until 2026-06-30`, or typed MCP calls to `refill_sends({ yolo, senders,
71
+ untilDate })` from:
71
72
 
72
73
  - `mcp/sellable/skills/refill-sends/SKILL.md`
73
74
 
@@ -296,6 +297,7 @@ Use the refill command for sender send refills:
296
297
 
297
298
  ```
298
299
  /sellable:refill-sends --yolo
300
+ /sellable:refill-sends --yolo --until 2026-06-30
299
301
  /sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
300
302
  ```
301
303
 
@@ -323,6 +325,7 @@ Use the Codex refill command with the same flags:
323
325
 
324
326
  ```
325
327
  $sellable:refill-sends --yolo
328
+ $sellable:refill-sends --yolo --until 2026-06-30
326
329
  $sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
327
330
  ```
328
331
 
@@ -6,6 +6,7 @@ type RefillSendsCommandInput = {
6
6
  senderIds?: string[];
7
7
  senderNames?: string[];
8
8
  horizonSendDays?: number;
9
+ untilDate?: string;
9
10
  campaignId?: string;
10
11
  tableId?: string;
11
12
  intent?: RefillSendsIntent;
@@ -48,6 +49,11 @@ export declare const refillSendsToolDefinitions: {
48
49
  maximum: number;
49
50
  description: string;
50
51
  };
52
+ untilDate: {
53
+ type: string;
54
+ pattern: string;
55
+ description: string;
56
+ };
51
57
  campaignId: {
52
58
  type: string;
53
59
  description: string;
@@ -78,7 +84,19 @@ export declare function refillSendsCommand(input?: RefillSendsCommandInput): {
78
84
  workflowPromptName: string;
79
85
  yolo: boolean;
80
86
  intent: RefillSendsIntent;
81
- horizonSendDays: number;
87
+ untilDate: string | null;
88
+ horizonSendDays: number | null;
89
+ fillWindow: {
90
+ mode: string;
91
+ untilDate: string;
92
+ description: string;
93
+ horizonSendDays?: undefined;
94
+ } | {
95
+ mode: string;
96
+ horizonSendDays: number | null;
97
+ description: string;
98
+ untilDate?: undefined;
99
+ };
82
100
  approvalMode: RefillSendsApprovalMode;
83
101
  campaignId: string | null;
84
102
  tableId: string | null;
@@ -101,7 +119,8 @@ export declare function refillSendsCommand(input?: RefillSendsCommandInput): {
101
119
  senders: string[];
102
120
  senderIds: string[];
103
121
  senderNames: string[];
104
- horizonSendDays: number;
122
+ untilDate: string | null;
123
+ horizonSendDays: number | null;
105
124
  campaignId: string | undefined;
106
125
  tableId: string | undefined;
107
126
  intent: RefillSendsIntent;
@@ -14,6 +14,25 @@ function normalizeHorizonSendDays(value) {
14
14
  }
15
15
  return Math.max(1, Math.min(7, Math.floor(value)));
16
16
  }
17
+ function normalizeUntilDate(value) {
18
+ if (value === undefined || value === null || value === "")
19
+ return null;
20
+ if (typeof value !== "string") {
21
+ throw new Error("untilDate must be a string in YYYY-MM-DD format.");
22
+ }
23
+ const trimmed = value.trim();
24
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
25
+ throw new Error("untilDate must use YYYY-MM-DD format.");
26
+ }
27
+ const [year, month, day] = trimmed.split("-").map((part) => Number(part));
28
+ const parsed = new Date(Date.UTC(year, month - 1, day));
29
+ if (parsed.getUTCFullYear() !== year ||
30
+ parsed.getUTCMonth() !== month - 1 ||
31
+ parsed.getUTCDate() !== day) {
32
+ throw new Error("untilDate must be a valid calendar date.");
33
+ }
34
+ return trimmed;
35
+ }
17
36
  export const refillSendsToolDefinitions = [
18
37
  {
19
38
  name: "refill_sends",
@@ -44,7 +63,12 @@ export const refillSendsToolDefinitions = [
44
63
  type: "number",
45
64
  minimum: 1,
46
65
  maximum: 7,
47
- description: "Number of sender-local send days to fill. Defaults to 2.",
66
+ description: "Number of sender-local send days to fill. Defaults to 2 when untilDate is not provided.",
67
+ },
68
+ untilDate: {
69
+ type: "string",
70
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$",
71
+ description: "Optional sender-local YYYY-MM-DD date to fill through, inclusive. Overrides the default two send-day horizon.",
48
72
  },
49
73
  campaignId: {
50
74
  type: "string",
@@ -76,7 +100,10 @@ export function refillSendsCommand(input = {}) {
76
100
  const senderNames = normalizeStrings(input.senderNames);
77
101
  const hasSenderSelectors = senders.length > 0 || senderIds.length > 0 || senderNames.length > 0;
78
102
  const yolo = input.yolo === true;
79
- const horizonSendDays = normalizeHorizonSendDays(input.horizonSendDays);
103
+ const untilDate = normalizeUntilDate(input.untilDate);
104
+ const horizonSendDays = untilDate
105
+ ? null
106
+ : normalizeHorizonSendDays(input.horizonSendDays);
80
107
  const intent = input.intent ?? "plain";
81
108
  const approvalMode = input.approvalMode ?? (yolo ? "approve" : "mark_ready");
82
109
  const senderScope = hasSenderSelectors
@@ -91,7 +118,19 @@ export function refillSendsCommand(input = {}) {
91
118
  workflowPromptName: "refill-sends-workflow",
92
119
  yolo,
93
120
  intent,
121
+ untilDate,
94
122
  horizonSendDays,
123
+ fillWindow: untilDate
124
+ ? {
125
+ mode: "until_date",
126
+ untilDate,
127
+ description: "Fill through this sender-local date inclusive, skipping no-send days and never extending beyond the date without a new packet.",
128
+ }
129
+ : {
130
+ mode: "horizon_send_days",
131
+ horizonSendDays,
132
+ description: "Fill the default bounded horizon by sender-local send days.",
133
+ },
95
134
  approvalMode,
96
135
  campaignId: input.campaignId ?? null,
97
136
  tableId: input.tableId ?? null,
@@ -105,6 +144,9 @@ export function refillSendsCommand(input = {}) {
105
144
  'Load get_subskill_prompt({ subskillName: "refill-sends-workflow" }) before any product operation.',
106
145
  `Resolve route with resolve_campaign_fill_route({ intent: "${intent}"${input.campaignId ? `, campaignId: "${input.campaignId}"` : ""}${input.tableId ? `, tableId: "${input.tableId}"` : ""} }).`,
107
146
  "Call list_senders and get_sender_routing, then resolve sender selectors against active enrolled campaign-backed sequence senders.",
147
+ untilDate
148
+ ? `Use fill window untilDate="${untilDate}" as the inclusive sender-local through date; do not extend beyond that date without a new approval packet.`
149
+ : `Use the default fill window of ${horizonSendDays} sender-local send days.`,
108
150
  "Read get_campaign_refill_state for enough exact candidate campaigns to pick the best per-sender target by recent/future scheduler-owned sends, then recent result evidence, then source health.",
109
151
  "Fresh reread get_campaign_refill_state immediately before any import, prep, approval, or horizon-fill mutation.",
110
152
  ],
@@ -125,10 +167,12 @@ export function refillSendsCommand(input = {}) {
125
167
  hostExamples: {
126
168
  claude: [
127
169
  "/sellable:refill-sends --yolo",
170
+ "/sellable:refill-sends --yolo --until 2026-06-30",
128
171
  '/sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"',
129
172
  ],
130
173
  codex: [
131
174
  "$sellable:refill-sends --yolo",
175
+ "$sellable:refill-sends --yolo --until 2026-06-30",
132
176
  '$sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"',
133
177
  ],
134
178
  mcpTool: {
@@ -138,6 +182,7 @@ export function refillSendsCommand(input = {}) {
138
182
  senders,
139
183
  senderIds,
140
184
  senderNames,
185
+ untilDate,
141
186
  horizonSendDays,
142
187
  campaignId: input.campaignId,
143
188
  tableId: input.tableId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.417",
3
+ "version": "0.1.419",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -234,7 +234,15 @@ blocker and would make the whole yolo plan non-autoExecutable even though the
234
234
  operator asked to leave it untouched. Inventory and waterfall proof may mention
235
235
  the protected lane, but selectedActionIds and lane workers must cover only the
236
236
  shared lane packets.
237
+ If the operator says to preserve existing active/live campaigns, preserve an
238
+ ACTIVE Post Engagers lane the same way: treat it as protected inventory, exclude
239
+ it from `postEngagerSenderIds` for the execution plan, and select only the
240
+ remaining missing/reusable shared-lane actionIds. Do not let a protected active
241
+ Post Engagers reuse packet block shared-lane verification or repair. Report the
242
+ protected active lane in inventory/final notes, but do not dispatch a worker for
243
+ it and do not include it in `selectedActionIds`.
237
244
  Short form: Do not include the protected active Post Engagers lane as a reuse packet when the operator requested only shared lane execution.
245
+ Short form: "preserve existing active/live campaigns" means exclude ACTIVE Post Engagers from yolo execution, not block all shared-lane work.
238
246
 
239
247
  When senders are ambiguous, ask which sender ids belong in the Post Engagers
240
248
  sender scope and which belong in the shared lane sender scope before planning.
@@ -346,6 +354,14 @@ When launching durable Codex CLI workers from an automation parent, pass an
346
354
  explicit supported worker model instead of relying on the Codex CLI default
347
355
  model. Use the parent runtime model when known, for example:
348
356
  `codex -a never -s danger-full-access exec --skip-git-repo-check -m <worker-model> -C <repo> -o <worker-final-file> -`.
357
+ In Codex CLI, the parent runtime model is visible in the run header as
358
+ `model: <model-name>`. Copy that exact model string into child worker launches
359
+ first. If the parent header says `model: gpt-5.5`, launch workers with
360
+ `-m gpt-5.5`; do not invent or probe nearby aliases such as `gpt-5.3-codex`,
361
+ `gpt-5.2`, `gpt-5-codex`, `codex-latest`, or `codex-mini-latest` before trying
362
+ the exact parent model. A one-line probe must count as supported only when it
363
+ exits 0 and returns the requested output; a session header followed by a
364
+ `not supported` error is rejected, not accepted.
349
365
  Do not rely on the Codex CLI default model; some customer and VPS installs
350
366
  default to unavailable model aliases. If the parent cannot identify a supported
351
367
  worker model and a test `codex exec -m <worker-model>` launch is rejected, stop
@@ -1033,6 +1049,13 @@ canonical lane receipt. Repair workers must stage successful repaired receipts
1033
1049
  under `repair-staged/` first; only after fresh MCP readbacks, improved current
1034
1050
  samples, exactly one approved generated route-proof row, and a local JSON
1035
1051
  self-check pass may the worker atomically replace the canonical lane receipt.
1052
+ Repair workers must not call `setup_evergreen_campaigns({ mode:"verify" })`
1053
+ or `setup_evergreen_campaigns({ mode:"plan" })`; parent verification and
1054
+ idempotency are parent responsibilities after all selected lane receipts are
1055
+ ready. A stale-plan/action response from any accidental repair-worker verify
1056
+ call is not a product-state blocker and must not prevent a repaired receipt from
1057
+ replacing the canonical receipt when fresh product readbacks and local
1058
+ sample/receipt checks pass.
1036
1059
  After the repair worker completes the final product readbacks
1037
1060
  (`get_campaign_messages_preview`, `get_campaign`, navigation/table readback),
1038
1061
  it must stage and then rewrite the durable receipt immediately before any
@@ -1049,6 +1072,8 @@ Short form: repair prompts use compact repair packets, not full receipt JSON.
1049
1072
  Short form: Do not include existing receipt JSON in repair prompts.
1050
1073
  Short form: repair workers stage repaired receipts before replacing canonical receipts.
1051
1074
  Short form: repair blockers never overwrite canonical success receipts.
1075
+ Short form: repair workers do not call setup_evergreen_campaigns verify or plan.
1076
+ Short form: parent owns setup_evergreen_campaigns verify and idempotency.
1052
1077
  Short form: repair workers write the durable receipt immediately after final readbacks.
1053
1078
  Short form: missing repair receipt rewrite is `blocked: repair_receipt_write_timeout`.
1054
1079
 
@@ -66,14 +66,18 @@ Accepted invocation flags in the same user request:
66
66
  fresh state reread.
67
67
  - `--sender <name-or-id>`: scope to a specific sender; repeat for multiple
68
68
  senders.
69
+ - `--until <YYYY-MM-DD>`: fill through that sender-local date, inclusive,
70
+ instead of the default two send-day horizon.
69
71
  - `senderIds: <id>, <id>` or `senderNames: <name>, <name>`: explicit selector
70
72
  alternatives when the host preserves natural-language arguments better than
71
73
  shell-style flags.
74
+ - `untilDate: YYYY-MM-DD`: explicit date selector alternative when the host
75
+ preserves natural-language arguments better than shell-style flags.
72
76
 
73
77
  When the host can call typed MCP tools, start with:
74
78
 
75
79
  ```text
76
- refill_sends({ yolo?: boolean, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number })
80
+ refill_sends({ yolo?: boolean, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD" })
77
81
  ```
78
82
 
79
83
  That command helper only normalizes arguments and returns the execution
@@ -132,13 +136,16 @@ reassignment, or campaigns outside those selected for the eligible sender set.
132
136
  Stop and re-plan if the route, sender set, ids, caps, blockers, or side-effect
133
137
  class drift before mutation.
134
138
 
135
- In `--yolo`, the default two-day fill horizon is two send days. For each target
136
- sender, compute the bounded gap from that sender's healthy daily capacity,
137
- existing future scheduler-owned scheduled sends, and rows already ready to
138
- schedule across active campaigns enrolled with that sender. Then pick the best
139
- same-sender campaign to fill the gap: prefer recent/future scheduler-owned sends
140
- for that sender, then strongest recent result evidence, then source health. Do
141
- not stop after filling only one sender when the request was sender-scoped. If a
139
+ In `--yolo`, the default two-day fill horizon is two send days unless
140
+ `--until`/`untilDate` is provided. If an until date is provided, compute bounded
141
+ gaps through that sender-local date inclusive, skipping no-send days and never
142
+ extending beyond that date without a new packet. For each target sender, compute
143
+ the bounded gap from that sender's healthy daily capacity, existing future
144
+ scheduler-owned scheduled sends, and rows already ready to schedule across
145
+ active campaigns enrolled with that sender. Then pick the best same-sender
146
+ campaign to fill the gap: prefer recent/future scheduler-owned sends for that
147
+ sender, then strongest recent result evidence, then source health. Do not stop
148
+ after filling only one sender when the request was sender-scoped. If a
142
149
  same-source copy hits the campaign-table row cap, split the current source into
143
150
  a bounded LinkedIn profile source list, confirm only that smaller list into the
144
151
  same campaign, and operate on the copied review batch. Do not fall back to