@sellable/mcp 0.1.503 → 0.1.504

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.
Files changed (34) hide show
  1. package/dist/api.d.ts +5 -5
  2. package/dist/api.js +10 -10
  3. package/dist/index-dev.js +0 -0
  4. package/dist/index.js +0 -0
  5. package/dist/server.js +2 -2
  6. package/dist/tools/campaign-fill-routing.d.ts +0 -5
  7. package/dist/tools/campaign-fill-routing.js +3 -13
  8. package/dist/tools/campaign-message-preparation.d.ts +48 -7
  9. package/dist/tools/campaign-message-preparation.js +44 -21
  10. package/dist/tools/campaign-processing.d.ts +0 -19
  11. package/dist/tools/campaign-processing.js +8 -31
  12. package/dist/tools/campaign-refill-state.d.ts +0 -5
  13. package/dist/tools/campaign-refill-state.js +3 -13
  14. package/dist/tools/leads.d.ts +47 -6
  15. package/dist/tools/leads.js +30 -26
  16. package/dist/tools/prompts.js +1 -1
  17. package/dist/tools/readiness.d.ts +0 -6
  18. package/dist/tools/readiness.js +5 -12
  19. package/dist/tools/refill-sends.d.ts +32 -34
  20. package/dist/tools/refill-sends.js +608 -67
  21. package/dist/tools/refill-target-plan.d.ts +0 -5
  22. package/dist/tools/refill-target-plan.js +65 -32
  23. package/dist/tools/registry.d.ts +48 -205
  24. package/dist/tools/scheduler-fill-capacity.d.ts +0 -5
  25. package/dist/tools/scheduler-fill-capacity.js +3 -13
  26. package/dist/tools/sender-routing.d.ts +1 -8
  27. package/dist/tools/sender-routing.js +3 -12
  28. package/dist/tools/senders.d.ts +1 -14
  29. package/dist/tools/senders.js +5 -31
  30. package/package.json +1 -1
  31. package/skills/refill-sends/SKILL.md +28 -49
  32. package/skills/refill-sends-workflow/SKILL.md +10 -15
  33. package/dist/tools/workspace-context.d.ts +0 -36
  34. package/dist/tools/workspace-context.js +0 -39
@@ -1,11 +1,7 @@
1
1
  import { getApi } from "../api.js";
2
- import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
3
- async function postSchedulerFillCapacity(body, workspaceId) {
2
+ async function postSchedulerFillCapacity(body) {
4
3
  const api = getApi();
5
- const requestOptions = workspaceRequestOptions(workspaceId);
6
- return requestOptions
7
- ? api.post("/api/v3/mcp/scheduler-fill-capacity", body, requestOptions)
8
- : api.post("/api/v3/mcp/scheduler-fill-capacity", body);
4
+ return api.post("/api/v3/mcp/scheduler-fill-capacity", body);
9
5
  }
10
6
  export const schedulerFillCapacityToolDefinitions = [
11
7
  {
@@ -59,10 +55,6 @@ export const schedulerFillCapacityToolDefinitions = [
59
55
  enum: ["default_horizon", "target_date"],
60
56
  description: "Optional mode hint. Omit for default_horizon; target_date requires targetDate.",
61
57
  },
62
- workspaceId: {
63
- type: "string",
64
- description: "Explicit request-scoped workspace id for scheduled/yolo refill automation. Pass this instead of switching the shared active workspace.",
65
- },
66
58
  },
67
59
  required: ["capacityRequests"],
68
60
  additionalProperties: false,
@@ -70,11 +62,9 @@ export const schedulerFillCapacityToolDefinitions = [
70
62
  },
71
63
  ];
72
64
  export function getSchedulerFillCapacity(input) {
73
- const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
74
65
  return postSchedulerFillCapacity({
75
66
  capacityRequests: input.capacityRequests,
76
67
  targetDate: input.targetDate,
77
68
  mode: input.mode,
78
- ...(workspaceId ? { workspaceId } : {}),
79
- }, workspaceId ?? undefined);
69
+ });
80
70
  }
@@ -14,10 +14,6 @@ export declare const senderRoutingToolDefinitions: ({
14
14
  inputSchema: {
15
15
  type: string;
16
16
  properties: {
17
- workspaceId: {
18
- type: string;
19
- description: string;
20
- };
21
17
  rulesMarkdown?: undefined;
22
18
  };
23
19
  required: never[];
@@ -33,15 +29,12 @@ export declare const senderRoutingToolDefinitions: ({
33
29
  type: string;
34
30
  description: string;
35
31
  };
36
- workspaceId?: undefined;
37
32
  };
38
33
  required: never[];
39
34
  additionalProperties: boolean;
40
35
  };
41
36
  })[];
42
- export declare function getSenderRoutingTool(input?: {
43
- workspaceId?: string;
44
- }): Promise<SenderRoutingResponse>;
37
+ export declare function getSenderRoutingTool(): Promise<SenderRoutingResponse>;
45
38
  export declare function setSenderRoutingTool(input?: {
46
39
  rulesMarkdown?: string;
47
40
  }): Promise<{
@@ -1,5 +1,4 @@
1
1
  import { getApi } from "../api.js";
2
- import { workspaceRequestOptions } from "./workspace-context.js";
3
2
  const MAX_RULES_MARKDOWN_LENGTH = 65536;
4
3
  export const senderRoutingToolDefinitions = [
5
4
  {
@@ -7,12 +6,7 @@ export const senderRoutingToolDefinitions = [
7
6
  description: "Return the workspace's territory routing rules markdown plus the connected sender roster. If configured is false, routing is inactive and all campaign senders are eligible everywhere.",
8
7
  inputSchema: {
9
8
  type: "object",
10
- properties: {
11
- workspaceId: {
12
- type: "string",
13
- description: "Explicit request-scoped workspace id for scheduled/yolo refill automation. Pass this instead of switching the shared active workspace.",
14
- },
15
- },
9
+ properties: {},
16
10
  required: [],
17
11
  additionalProperties: false,
18
12
  },
@@ -33,12 +27,9 @@ export const senderRoutingToolDefinitions = [
33
27
  },
34
28
  },
35
29
  ];
36
- export async function getSenderRoutingTool(input = {}) {
30
+ export async function getSenderRoutingTool() {
37
31
  const api = getApi();
38
- const requestOptions = workspaceRequestOptions(input.workspaceId);
39
- return requestOptions
40
- ? api.get("/api/v3/sender-routing", requestOptions)
41
- : api.get("/api/v3/sender-routing");
32
+ return api.get("/api/v3/sender-routing");
42
33
  }
43
34
  export async function setSenderRoutingTool(input = {}) {
44
35
  if (input.rulesMarkdown &&
@@ -22,19 +22,14 @@ export type SenderListItem = {
22
22
  export type ListSendersResponse = {
23
23
  senders: SenderListItem[];
24
24
  };
25
- export type ListSendersInput = {
26
- workspaceId?: string;
27
- };
28
25
  export type GetSenderInput = {
29
26
  senderId: string;
30
- workspaceId?: string;
31
27
  };
32
28
  export type SenderDetailResponse = {
33
29
  sender: any;
34
30
  };
35
31
  export type RefreshPaidInmailCreditsInput = {
36
32
  senderId: string;
37
- workspaceId?: string;
38
33
  };
39
34
  export type PaidInmailCreditStatus = {
40
35
  available: number;
@@ -62,10 +57,6 @@ export declare const senderToolDefinitions: ({
62
57
  inputSchema: {
63
58
  type: string;
64
59
  properties: {
65
- workspaceId: {
66
- type: string;
67
- description: string;
68
- };
69
60
  senderId?: undefined;
70
61
  };
71
62
  required: never[];
@@ -81,16 +72,12 @@ export declare const senderToolDefinitions: ({
81
72
  type: string;
82
73
  description: string;
83
74
  };
84
- workspaceId: {
85
- type: string;
86
- description: string;
87
- };
88
75
  };
89
76
  required: string[];
90
77
  additionalProperties: boolean;
91
78
  };
92
79
  })[];
93
- export declare function listSenders(input?: ListSendersInput): Promise<ListSendersResponse>;
80
+ export declare function listSenders(): Promise<ListSendersResponse>;
94
81
  export declare function getSender(input: GetSenderInput): Promise<SenderDetailResponse>;
95
82
  export declare function refreshPaidInmailCredits(input: RefreshPaidInmailCreditsInput): Promise<RefreshPaidInmailCreditsResponse>;
96
83
  export {};
@@ -1,6 +1,5 @@
1
1
  import { getApi } from "../api.js";
2
2
  import { isLinkedInProfileInput, normalizeLinkedInProfileInput, } from "./linkedin-url.js";
3
- import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
4
3
  function pickString(...values) {
5
4
  for (const value of values) {
6
5
  if (typeof value !== "string")
@@ -108,12 +107,7 @@ export const senderToolDefinitions = [
108
107
  description: "List outbound sender identities available in the active workspace, including LinkedIn profile URL and verified identity proof when available. In create-campaign flows, use this at Settings/final launch handoff to verify available connected senders; auto-select only when a sender has an exact identity match to the researched campaign identity. If identity proof is missing, ask the user to confirm the sender.",
109
108
  inputSchema: {
110
109
  type: "object",
111
- properties: {
112
- workspaceId: {
113
- type: "string",
114
- description: "Explicit request-scoped workspace id for scheduled/yolo refill automation. Pass this instead of switching the shared active workspace.",
115
- },
116
- },
110
+ properties: {},
117
111
  required: [],
118
112
  additionalProperties: false,
119
113
  },
@@ -125,10 +119,6 @@ export const senderToolDefinitions = [
125
119
  type: "object",
126
120
  properties: {
127
121
  senderId: { type: "string", description: "Outbound sender ID" },
128
- workspaceId: {
129
- type: "string",
130
- description: "Explicit request-scoped workspace id for scheduled/yolo refill automation.",
131
- },
132
122
  },
133
123
  required: ["senderId"],
134
124
  additionalProperties: false,
@@ -144,22 +134,15 @@ export const senderToolDefinitions = [
144
134
  type: "string",
145
135
  description: "Exact Sender.id to refresh. The API verifies the sender belongs to the active workspace.",
146
136
  },
147
- workspaceId: {
148
- type: "string",
149
- description: "Explicit request-scoped workspace id for scheduled/yolo refill automation. Pass this instead of switching the shared active workspace.",
150
- },
151
137
  },
152
138
  required: ["senderId"],
153
139
  additionalProperties: false,
154
140
  },
155
141
  },
156
142
  ];
157
- export async function listSenders(input = {}) {
143
+ export async function listSenders() {
158
144
  const api = getApi();
159
- const requestOptions = workspaceRequestOptions(input.workspaceId);
160
- const senders = requestOptions
161
- ? await api.get("/api/v1/outbound-sender-identities", requestOptions)
162
- : await api.get("/api/v1/outbound-sender-identities");
145
+ const senders = await api.get("/api/v1/outbound-sender-identities");
163
146
  return {
164
147
  senders: (senders || []).map((s) => {
165
148
  const linkedinProfileUrl = computeLinkedinProfileUrl(s);
@@ -180,11 +163,7 @@ export async function listSenders(input = {}) {
180
163
  }
181
164
  export async function getSender(input) {
182
165
  const api = getApi();
183
- const requestOptions = workspaceRequestOptions(input.workspaceId);
184
- const path = `/api/v1/outbound-sender-identities/${encodeURIComponent(input.senderId)}`;
185
- const sender = requestOptions
186
- ? await api.get(path, requestOptions)
187
- : await api.get(path);
166
+ const sender = await api.get(`/api/v1/outbound-sender-identities/${encodeURIComponent(input.senderId)}`);
188
167
  return { sender };
189
168
  }
190
169
  function normalizeCreditStatus(raw) {
@@ -208,12 +187,7 @@ export async function refreshPaidInmailCredits(input) {
208
187
  throw new Error("senderId is required.");
209
188
  }
210
189
  const api = getApi();
211
- const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
212
- const requestOptions = workspaceRequestOptions(workspaceId);
213
- const body = workspaceId ? { workspaceId } : {};
214
- const result = requestOptions
215
- ? await api.post(`/api/v3/senders/${encodeURIComponent(senderId)}/refresh-inmail-credits`, body, requestOptions)
216
- : await api.post(`/api/v3/senders/${encodeURIComponent(senderId)}/refresh-inmail-credits`, body);
190
+ const result = await api.post(`/api/v3/senders/${encodeURIComponent(senderId)}/refresh-inmail-credits`, {});
217
191
  return {
218
192
  senderId,
219
193
  refreshed: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.503",
3
+ "version": "0.1.504",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -68,9 +68,6 @@ Accepted invocation flags in the same user request:
68
68
 
69
69
  - `--yolo`: auto-accept the rendered bounded refill packet after the required
70
70
  fresh state reread.
71
- - `workspaceId: <id>`: required for scheduled automation and `--yolo`; pass it
72
- through on every refill MCP tool call instead of relying on shared config
73
- state.
74
71
  - `--sender <name-or-id>`: scope to a specific sender; repeat for multiple
75
72
  senders.
76
73
  - `--until <YYYY-MM-DD>`: fill through that sender-local date, inclusive,
@@ -89,48 +86,23 @@ Accepted invocation flags in the same user request:
89
86
  When the host can call typed MCP tools, start with:
90
87
 
91
88
  ```text
92
- refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
89
+ refill_sends({ yolo?: boolean, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
93
90
  ```
94
91
 
95
- That command helper only normalizes arguments and returns the execution
96
- contract. It does not mutate. Continue with the workflow below for route
97
- selection, state rereads, approval gating, source import, preparation, and
98
- bounded approval.
99
-
100
- ## Workspace Contract
101
-
102
- First resolve the target workspace id from the user's request, automation config,
103
- or install-time workspace mapping. Pass `workspaceId` on every scheduled or
104
- `--yolo` refill tool call, including setup/read calls such as
105
- `refill_sends`, `get_refill_target_plan`, `list_senders`,
106
- `get_sender_routing`, `resolve_campaign_fill_route`,
107
- `get_campaign_refill_state`, `get_scheduler_fill_capacity`, and any later
108
- refill mutation covered by the packet. Missing `workspaceId` in scheduled or
109
- `--yolo` mode is a blocker; stop with `WORKSPACE_REQUIRED` instead of running
110
- against an implicit or guessed workspace.
111
-
112
- Do not solve scheduled or `--yolo` workspace uncertainty by changing the shared
113
- active workspace. Manual interactive workspace switching remains a separate
114
- diagnostic/setup flow, outside automation.
115
-
116
- Examples:
117
-
118
- ```text
119
- refill_sends({ yolo:true, executionMode:"yolo", requireWorkspace:true, workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
120
- get_refill_target_plan({ intent:"plain", approvalMode:"approve", workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
121
- list_senders({ workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
122
- ```
123
-
124
- Clover scheduled automation must name the Clover workspace explicitly:
125
-
126
- ```text
127
- refill_sends({ yolo:false, executionMode:"scheduled", requireWorkspace:true, workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
128
- get_refill_target_plan({ intent:"plain", approvalMode:"mark_ready", workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
129
- ```
130
-
131
- First call `get_auth_status({})`. If auth is not OK, follow the returned login
132
- guidance before route resolution. Do not run refill research against an implicit
133
- or guessed workspace.
92
+ That command helper normalizes arguments and returns the execution contract. In
93
+ non-yolo mode it does not mutate. In `--yolo`, it may execute exactly one safe
94
+ bounded primitive from the fresh `target.globalActionQueue[0]`, then reread and
95
+ return the new target plan; currently safe primitives are paid-credit refresh,
96
+ existing-row message preparation, same-source row copy, and read-only wait
97
+ rereads. It does not run unbounded approval, lower
98
+ paid-InMail thresholds, switch source families, create campaigns, launch, send,
99
+ or write scheduler rows. Continue with the workflow below for route selection,
100
+ state rereads, approval gating, source import, preparation, and bounded
101
+ approval.
102
+
103
+ First call `get_auth_status({})`. If auth or active workspace is not OK, follow
104
+ the returned login/workspace guidance before route resolution. Do not run refill
105
+ research against an implicit or guessed workspace.
134
106
 
135
107
  Treat "refill senders", "fill senders", "load everyone up", and "max out
136
108
  senders" as sender-scoped requests. The target set is senders enrolled in active
@@ -193,18 +165,25 @@ Structured planner packet:
193
165
  `Still need`.
194
166
  - `target.globalActionQueue` is the only cross-sender yolo execution queue.
195
167
  Execute exactly one globally ranked primitive from
196
- `target.globalActionQueue[0]`, then rerun `get_refill_target_plan` with the
197
- same `workspaceId` before
168
+ `target.globalActionQueue[0]`, then rerun `get_refill_target_plan` before
198
169
  choosing another action.
199
170
  - `manualAlternates` are not yolo actions. Threshold lowering and campaign
200
171
  creation are manual continuations only.
201
172
 
173
+ Refill action ladder: approve generated rows only when an explicit bounded
174
+ approval gate exists, process all existing same-campaign unenriched/unprepared
175
+ rows in bounded batches before any source work, then copy bounded net-new rows
176
+ from the selected source (`selectedLeadListId`, provider, and source
177
+ fingerprint preserved), then use provider-aligned source-more. A new source or
178
+ provider switch changes the reply-rate baseline and is a manual alternate, not a
179
+ `--yolo` side effect.
180
+
202
181
  Run-local paid-credit guard: in `--yolo`, the `refill_sends` MCP command
203
182
  automatically maintains a `refreshedPaidInmailSenderIds` set for the current
204
183
  command call. If its first target plan has stale/missing paid-InMail credit
205
184
  facts, it refreshes each selected sender at most once, reruns
206
185
  `get_refill_target_plan`, and returns the post-refresh `targetPlan` before
207
- choosing the next prep/approval/start action. If fresh facts are still below
186
+ choosing the next prep/source-copy/bounded-approval/read-only wait action. If fresh facts are still below
208
187
  threshold, below-threshold paid-InMail facts fall back to an existing connection
209
188
  lane, the same Sales Nav cascade campaign's connection branch, or a manual
210
189
  continuation.
@@ -271,7 +250,7 @@ If Christian includes `--yolo` in the same refill request, treat that flag as
271
250
  auto-accept for the rendered bounded refill packet after the required fresh state
272
251
  reread. For sender-scoped language with no named senders, `--yolo` means all
273
252
  eligible healthy senders enrolled in active campaign-backed sequence campaigns in
274
- the requested `workspaceId`. Without `--yolo`, if Christian did not name senders, ask
253
+ the active workspace. Without `--yolo`, if Christian did not name senders, ask
275
254
  which eligible enrolled senders to refill before choosing campaigns or mutating.
276
255
 
277
256
  `--yolo` only covers the exact sender set, per-sender target campaigns, caps,
@@ -293,7 +272,7 @@ they change `stateRevision`, not `targetShapeRevision`, and do not require a
293
272
  second approval.
294
273
 
295
274
  In `--yolo`, continue as far as the rendered packet safely allows. After each
296
- apply/prep/start result, reread state, settle processing when needed, and move to
275
+ apply/prep/source-copy/bounded-approval/read-only wait result, reread state, settle processing when needed, and move to
297
276
  the next selected sender or start-eligible same-packet campaign instead of
298
277
  stopping after the first partial result. If no in-packet safe action remains,
299
278
  return concrete continuation options with campaign names, exact ids, which option
@@ -307,7 +286,7 @@ selected sender: selected send days, gross capacity, actual sent cells, future
307
286
  scheduler-owned scheduled cells with non-null `scheduledFor`, projected count,
308
287
  ready-to-schedule buffer, remaining projected gap, paid-InMail feasibility,
309
288
  `targetShapeRevision`, `stateRevision`, and the next MCP primitive that can
310
- reduce the gap. After every apply/prep/start result, wait for processing, reread
289
+ reduce the gap. After every apply/prep/source-copy/bounded-approval/read-only wait result, wait for processing, reread
311
290
  the target plan/refill state, recompute the ledger, then keep applying safe
312
291
  bounded actions until projected coverage fills the target window or a concrete
313
292
  non-scheduler blocker is proven.
@@ -61,17 +61,6 @@ senders", and "load everyone up". A sender-scoped request targets senders
61
61
  enrolled in active campaign-backed sequence campaigns, not one arbitrary active
62
62
  campaign.
63
63
 
64
- Workspace contract: scheduled automation and `--yolo` must carry an explicit
65
- request-scoped `workspaceId`. Pass that same `workspaceId` on every refill tool
66
- call in this workflow: `get_refill_target_plan`, `list_senders`,
67
- `get_sender_routing`, `resolve_campaign_fill_route`,
68
- `get_campaign_refill_state`, `get_scheduler_fill_capacity`,
69
- `refresh_paid_inmail_credits`, source import/readiness calls, preparation calls,
70
- approval calls, and campaign start calls. Missing `workspaceId` in scheduled or
71
- `--yolo` mode is a blocker; return or report `WORKSPACE_REQUIRED` instead of
72
- falling back to shared config state. Manual interactive workspace switching is
73
- diagnostic setup only and is not an automation control path.
74
-
75
64
  Goal-mode continuation: a skill cannot create or invoke `/goal` by itself. When
76
65
  this workflow is already running inside an active Codex goal, keep that goal
77
66
  open until every selected sender lane is horizon-filled by projected coverage
@@ -114,18 +103,24 @@ in-progress wait state, not a reason to mark the goal complete or blocked.
114
103
  `Still need`.
115
104
  - `target.globalActionQueue` is the only cross-sender yolo execution queue.
116
105
  execute exactly one globally ranked primitive from
117
- `target.globalActionQueue[0]`, then rerun `get_refill_target_plan` with
118
- the same `workspaceId` before
106
+ `target.globalActionQueue[0]`, then rerun `get_refill_target_plan` before
119
107
  choosing another action.
120
108
  - `nextActions[0]` is the current sender's smallest safe primitive.
121
109
  - `manualAlternates` are not yolo actions. Threshold lowering and campaign
122
110
  creation are manual continuations only.
111
+ Refill action ladder: approve generated rows only when an explicit bounded
112
+ approval gate exists, process all existing same-campaign
113
+ unenriched/unprepared rows in bounded batches before any source work, then
114
+ copy bounded net-new rows from the selected source (`selectedLeadListId`,
115
+ provider, and source fingerprint preserved), then use provider-aligned
116
+ source-more. A new source or provider switch changes the reply-rate baseline
117
+ and is a manual alternate, not a `--yolo` side effect.
123
118
  Run-local paid-credit guard: in `--yolo`, the `refill_sends` MCP command
124
119
  automatically maintains a `refreshedPaidInmailSenderIds` set for the current
125
120
  command call. If its first target plan has stale/missing paid-InMail credit
126
121
  facts, it refreshes each selected sender at most once, reruns
127
122
  `get_refill_target_plan`, and returns the post-refresh `targetPlan` before
128
- choosing the next prep/approval/start action. If fresh facts are still below
123
+ choosing the next prep/source-copy/bounded-approval/read-only wait action. If fresh facts are still below
129
124
  threshold, below-threshold paid-InMail facts fall back to an existing
130
125
  connection lane, the same Sales Nav cascade campaign's connection branch, or
131
126
  a manual continuation.
@@ -564,7 +559,7 @@ same refill request, do not ask the `Accept` / `Decline` question. Instead:
564
559
  caps/dates, approval mode, blockers, and side-effect class still match the
565
560
  packet;
566
561
  4. execute only the exact packet;
567
- 5. after each terminal credit-refresh/apply/prep/start result, rerun
562
+ 5. after each terminal credit-refresh/apply/prep/source-copy/bounded-approval/read-only wait result, rerun
568
563
  `get_refill_target_plan`, reread state, settle processing when needed,
569
564
  recompute the target-window saturation ledger, and continue with the next smallest
570
565
  safe action inside the same bounded packet until every selected sender is
@@ -1,36 +0,0 @@
1
- import type { ApiRequestOptions } from "../api.js";
2
- export type WorkspaceExecutionMode = "manual" | "scheduled" | "yolo";
3
- export interface CreateWorkspaceContextInput {
4
- workspaceId?: string | null;
5
- executionMode: WorkspaceExecutionMode;
6
- toolName?: string;
7
- runId?: string;
8
- }
9
- export interface WorkspaceContext {
10
- workspaceId: string;
11
- requestOptions: Readonly<ApiRequestOptions>;
12
- executionMode: WorkspaceExecutionMode;
13
- toolName?: string;
14
- runId: string;
15
- workspaceResolution: "explicit";
16
- }
17
- export interface WorkspaceRequiredResult {
18
- ok: false;
19
- code: "WORKSPACE_REQUIRED";
20
- message: string;
21
- executionMode: WorkspaceExecutionMode;
22
- toolName?: string;
23
- workspaceResolution: "missing";
24
- }
25
- export interface WorkspaceContextResult {
26
- ok: true;
27
- context: Readonly<WorkspaceContext>;
28
- }
29
- export type CreateWorkspaceContextResult = WorkspaceContextResult | WorkspaceRequiredResult;
30
- export declare function workspaceRequired(params: {
31
- executionMode: WorkspaceExecutionMode;
32
- toolName?: string;
33
- }): WorkspaceRequiredResult;
34
- export declare function normalizeExplicitWorkspaceId(value: unknown): string | null;
35
- export declare function workspaceRequestOptions(workspaceId: unknown): Readonly<ApiRequestOptions> | undefined;
36
- export declare function createWorkspaceContext(input: CreateWorkspaceContextInput): CreateWorkspaceContextResult;
@@ -1,39 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- export function workspaceRequired(params) {
3
- const toolLabel = params.toolName ? ` for ${params.toolName}` : "";
4
- return {
5
- ok: false,
6
- code: "WORKSPACE_REQUIRED",
7
- message: `Explicit workspaceId is required${toolLabel} in ${params.executionMode} mode. ` +
8
- "Pass workspaceId on the tool call instead of switching the shared active workspace.",
9
- executionMode: params.executionMode,
10
- toolName: params.toolName,
11
- workspaceResolution: "missing",
12
- };
13
- }
14
- export function normalizeExplicitWorkspaceId(value) {
15
- return typeof value === "string" && value.trim() ? value.trim() : null;
16
- }
17
- export function workspaceRequestOptions(workspaceId) {
18
- const normalized = normalizeExplicitWorkspaceId(workspaceId);
19
- return normalized ? Object.freeze({ workspaceId: normalized }) : undefined;
20
- }
21
- export function createWorkspaceContext(input) {
22
- const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
23
- if (!workspaceId) {
24
- return workspaceRequired({
25
- executionMode: input.executionMode,
26
- toolName: input.toolName,
27
- });
28
- }
29
- const requestOptions = Object.freeze({ workspaceId });
30
- const context = Object.freeze({
31
- workspaceId,
32
- requestOptions,
33
- executionMode: input.executionMode,
34
- toolName: input.toolName,
35
- runId: input.runId?.trim() || randomUUID(),
36
- workspaceResolution: "explicit",
37
- });
38
- return { ok: true, context };
39
- }