@sellable/mcp 0.1.556 → 0.1.557
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 +13 -2
- package/agents/registry.json +2 -2
- package/dist/api.js +3 -6
- package/dist/auth.d.ts +0 -6
- package/dist/auth.js +2 -44
- package/dist/refill-run-client.d.ts +0 -5
- package/dist/refill-run-client.js +0 -15
- package/dist/refill-run-loop.d.ts +1 -12
- package/dist/refill-run-loop.js +13 -158
- package/dist/server.js +23 -0
- package/dist/tools/auth.d.ts +0 -5
- package/dist/tools/auth.js +12 -49
- package/dist/tools/campaign-message-preparation.d.ts +0 -62
- package/dist/tools/campaign-message-preparation.js +0 -41
- package/dist/tools/campaigns.js +2 -2
- package/dist/tools/csv-dnc.js +2 -2
- package/dist/tools/evergreen-refill-plan.d.ts +0 -3
- package/dist/tools/evergreen-refill-plan.js +7 -29
- package/dist/tools/find-leads-runs.d.ts +151 -0
- package/dist/tools/find-leads-runs.js +98 -0
- package/dist/tools/leads.d.ts +317 -32
- package/dist/tools/leads.js +171 -10
- package/dist/tools/model-quality.js +4 -6
- package/dist/tools/prompts.d.ts +3 -3
- package/dist/tools/prompts.js +7 -15
- package/dist/tools/provider-preflight.d.ts +65 -2
- package/dist/tools/provider-preflight.js +97 -10
- package/dist/tools/readiness.d.ts +89 -5
- package/dist/tools/readiness.js +66 -0
- package/dist/tools/refill-executors.d.ts +0 -38
- package/dist/tools/refill-executors.js +3 -222
- package/dist/tools/refill-sends-v2.d.ts +1 -118
- package/dist/tools/refill-sends-v2.js +2 -310
- package/dist/tools/refill-sends.d.ts +32 -678
- package/dist/tools/refill-sends.js +13 -274
- package/dist/tools/refill-target-plan.js +14 -486
- package/dist/tools/registry.d.ts +330 -115
- package/dist/tools/registry.js +7 -1
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +0 -71
- package/dist/tools/scheduler-run.js +1 -203
- package/dist/tools/setup-evergreen-campaigns.js +1 -1
- package/dist/tools/workspace-context.d.ts +1 -1
- package/dist/tools/workspace-context.js +3 -8
- package/dist/tools/workspace-export.js +2 -2
- package/dist/tools/workspaces.d.ts +2 -48
- package/dist/tools/workspaces.js +5 -48
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +3 -3
- package/skills/create-campaign-v2/SKILL.md +1 -1
- package/skills/create-evergreen-campaigns/SKILL.md +16 -16
- package/skills/find-leads/SKILL.md +48 -630
- package/skills/find-leads-v2/SKILL.md +70 -0
- package/skills/find-leads-v2/core/flow.v1.json +31 -0
- package/skills/refill-sends/SKILL.md +353 -91
- package/skills/refill-sends-v2/SKILL.md +6 -6
- package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
- package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
- package/skills/refill-sends-workflow/SKILL.md +743 -100
- package/skills/refill-sends-workflow/core/flow.v1.json +1 -185
- package/dist/refill-contract.d.ts +0 -157
- package/dist/refill-contract.js +0 -487
- package/skills/refill-sends-workflow/core/contract.v2.json +0 -543
package/dist/tools/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import { getApi, SellableApiError } from "../api.js";
|
|
3
|
-
import { getConfig, getConfigPath,
|
|
3
|
+
import { getConfig, getConfigPath, getResolvedConfigsDir } from "../auth.js";
|
|
4
4
|
import { checkForUpdates } from "../update-check.js";
|
|
5
5
|
function maskToken(token) {
|
|
6
6
|
if (token.length <= 10)
|
|
@@ -38,8 +38,6 @@ export async function getAuthStatus() {
|
|
|
38
38
|
const checkedAt = new Date().toISOString();
|
|
39
39
|
const update = await getUpdateStatus();
|
|
40
40
|
let tokenPresent = false;
|
|
41
|
-
const workspaceLockRequired = isWorkspaceLockRequired();
|
|
42
|
-
const lockedWorkspaceId = getLockedWorkspaceId();
|
|
43
41
|
const base = {
|
|
44
42
|
ok: false,
|
|
45
43
|
configPath,
|
|
@@ -52,47 +50,27 @@ export async function getAuthStatus() {
|
|
|
52
50
|
tokenPresent: false,
|
|
53
51
|
tokenPrefix: null,
|
|
54
52
|
workspacesCount: null,
|
|
55
|
-
workspaceLock: {
|
|
56
|
-
enabled: Boolean(lockedWorkspaceId),
|
|
57
|
-
workspaceId: lockedWorkspaceId,
|
|
58
|
-
required: workspaceLockRequired,
|
|
59
|
-
},
|
|
60
53
|
_userNotice: appendUpdateNotice(null, update),
|
|
61
54
|
update,
|
|
62
55
|
checkedAt,
|
|
63
56
|
};
|
|
64
|
-
if (workspaceLockRequired && !lockedWorkspaceId) {
|
|
65
|
-
return {
|
|
66
|
-
...base,
|
|
67
|
-
error: {
|
|
68
|
-
type: "workspace",
|
|
69
|
-
message: "Customer profile workspace lock is missing.",
|
|
70
|
-
guidance: workspaceLockRequiredMessage("get_auth_status"),
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
57
|
try {
|
|
75
58
|
const config = getConfig();
|
|
76
59
|
tokenPresent = Boolean(config.token);
|
|
77
60
|
base.activeEnvName = config.activeEnvName || null;
|
|
78
61
|
const api = getApi();
|
|
79
62
|
const { workspaces } = await api.get("/api/v3/workspaces");
|
|
80
|
-
const activeWorkspaceId =
|
|
63
|
+
const activeWorkspaceId = config.activeWorkspaceId || config.workspaceId || null;
|
|
81
64
|
const activeWorkspace = activeWorkspaceId
|
|
82
65
|
? workspaces.find((ws) => ws.id === activeWorkspaceId)
|
|
83
66
|
: null;
|
|
84
|
-
const visibleWorkspacesCount = lockedWorkspaceId
|
|
85
|
-
? activeWorkspace
|
|
86
|
-
? 1
|
|
87
|
-
: 0
|
|
88
|
-
: workspaces.length;
|
|
89
67
|
if (!activeWorkspaceId) {
|
|
90
68
|
return {
|
|
91
69
|
...base,
|
|
92
70
|
apiUrl: config.apiUrl || null,
|
|
93
71
|
tokenPresent,
|
|
94
72
|
tokenPrefix: maskToken(config.token),
|
|
95
|
-
workspacesCount:
|
|
73
|
+
workspacesCount: workspaces.length,
|
|
96
74
|
error: {
|
|
97
75
|
type: "workspace",
|
|
98
76
|
message: "No active workspace selected.",
|
|
@@ -109,26 +87,22 @@ export async function getAuthStatus() {
|
|
|
109
87
|
apiUrl: config.apiUrl || null,
|
|
110
88
|
tokenPresent,
|
|
111
89
|
tokenPrefix: maskToken(config.token),
|
|
112
|
-
workspacesCount:
|
|
90
|
+
workspacesCount: workspaces.length,
|
|
113
91
|
error: {
|
|
114
92
|
type: "workspace",
|
|
115
93
|
message: `Active workspace ${activeWorkspaceId} not found in access list.`,
|
|
116
|
-
guidance:
|
|
117
|
-
?
|
|
118
|
-
: available
|
|
119
|
-
? `Available: ${available}. Run set_active_workspace with a valid ID.`
|
|
120
|
-
: "Run list_workspaces to view available workspaces, then set_active_workspace.",
|
|
94
|
+
guidance: available
|
|
95
|
+
? `Available: ${available}. Run set_active_workspace with a valid ID.`
|
|
96
|
+
: "Run list_workspaces to view available workspaces, then set_active_workspace.",
|
|
121
97
|
},
|
|
122
98
|
};
|
|
123
99
|
}
|
|
124
100
|
const workspaceName = activeWorkspace.name || config.activeWorkspaceName || null;
|
|
125
101
|
const envLabel = config.activeEnvName || null;
|
|
126
102
|
const wsLabel = workspaceName || activeWorkspaceId;
|
|
127
|
-
const
|
|
128
|
-
? `You're
|
|
129
|
-
:
|
|
130
|
-
? `You're in ${wsLabel} (${envLabel}).`
|
|
131
|
-
: `You're in ${wsLabel}.`;
|
|
103
|
+
const notice = envLabel
|
|
104
|
+
? `You're in ${wsLabel} (${envLabel}).`
|
|
105
|
+
: `You're in ${wsLabel}.`;
|
|
132
106
|
return {
|
|
133
107
|
ok: true,
|
|
134
108
|
configPath,
|
|
@@ -140,19 +114,8 @@ export async function getAuthStatus() {
|
|
|
140
114
|
activeWorkspaceName: workspaceName,
|
|
141
115
|
tokenPresent,
|
|
142
116
|
tokenPrefix: maskToken(config.token),
|
|
143
|
-
workspacesCount:
|
|
144
|
-
|
|
145
|
-
? {
|
|
146
|
-
enabled: true,
|
|
147
|
-
workspaceId: lockedWorkspaceId,
|
|
148
|
-
required: workspaceLockRequired,
|
|
149
|
-
}
|
|
150
|
-
: {
|
|
151
|
-
enabled: false,
|
|
152
|
-
workspaceId: null,
|
|
153
|
-
required: workspaceLockRequired,
|
|
154
|
-
},
|
|
155
|
-
_userNotice: appendUpdateNotice(noticePrefix, update),
|
|
117
|
+
workspacesCount: workspaces.length,
|
|
118
|
+
_userNotice: appendUpdateNotice(notice, update),
|
|
156
119
|
update,
|
|
157
120
|
checkedAt,
|
|
158
121
|
error: null,
|
|
@@ -36,16 +36,9 @@ type StartPrepareMessagesInput = PrepareMessagesBaseInput & {
|
|
|
36
36
|
requestSource?: string;
|
|
37
37
|
senderId?: string;
|
|
38
38
|
actionType?: string;
|
|
39
|
-
targetDate?: string;
|
|
40
|
-
refillLaneKey?: string;
|
|
41
|
-
sourceEpoch?: string;
|
|
42
39
|
};
|
|
43
40
|
type StatusPrepareMessagesInput = PrepareMessagesBaseInput;
|
|
44
41
|
type CancelPrepareMessagesInput = PrepareMessagesBaseInput;
|
|
45
|
-
type StopSatisfiedPrepareMessagesInput = PrepareMessagesBaseInput & {
|
|
46
|
-
jobId: string;
|
|
47
|
-
expectedUpdatedAt?: string;
|
|
48
|
-
};
|
|
49
42
|
export declare const campaignMessagePreparationToolDefinitions: ({
|
|
50
43
|
name: string;
|
|
51
44
|
description: string;
|
|
@@ -124,18 +117,6 @@ export declare const campaignMessagePreparationToolDefinitions: ({
|
|
|
124
117
|
enum: string[];
|
|
125
118
|
description: string;
|
|
126
119
|
};
|
|
127
|
-
targetDate: {
|
|
128
|
-
type: string;
|
|
129
|
-
description: string;
|
|
130
|
-
};
|
|
131
|
-
refillLaneKey: {
|
|
132
|
-
type: string;
|
|
133
|
-
description: string;
|
|
134
|
-
};
|
|
135
|
-
sourceEpoch: {
|
|
136
|
-
type: string;
|
|
137
|
-
description: string;
|
|
138
|
-
};
|
|
139
120
|
disableLowPassRateStop: {
|
|
140
121
|
type: string;
|
|
141
122
|
description: string;
|
|
@@ -145,7 +126,6 @@ export declare const campaignMessagePreparationToolDefinitions: ({
|
|
|
145
126
|
description: string;
|
|
146
127
|
};
|
|
147
128
|
jobId?: undefined;
|
|
148
|
-
expectedUpdatedAt?: undefined;
|
|
149
129
|
};
|
|
150
130
|
required: string[];
|
|
151
131
|
additionalProperties: boolean;
|
|
@@ -180,55 +160,13 @@ export declare const campaignMessagePreparationToolDefinitions: ({
|
|
|
180
160
|
autoContinue?: undefined;
|
|
181
161
|
senderId?: undefined;
|
|
182
162
|
actionType?: undefined;
|
|
183
|
-
targetDate?: undefined;
|
|
184
|
-
refillLaneKey?: undefined;
|
|
185
|
-
sourceEpoch?: undefined;
|
|
186
163
|
disableLowPassRateStop?: undefined;
|
|
187
|
-
expectedUpdatedAt?: undefined;
|
|
188
164
|
};
|
|
189
165
|
additionalProperties: boolean;
|
|
190
166
|
required?: undefined;
|
|
191
167
|
};
|
|
192
|
-
} | {
|
|
193
|
-
name: string;
|
|
194
|
-
description: string;
|
|
195
|
-
inputSchema: {
|
|
196
|
-
type: string;
|
|
197
|
-
properties: {
|
|
198
|
-
jobId: {
|
|
199
|
-
type: string;
|
|
200
|
-
};
|
|
201
|
-
expectedUpdatedAt: {
|
|
202
|
-
type: string;
|
|
203
|
-
description: string;
|
|
204
|
-
};
|
|
205
|
-
workspaceId: {
|
|
206
|
-
type: string;
|
|
207
|
-
description?: undefined;
|
|
208
|
-
};
|
|
209
|
-
campaignId?: undefined;
|
|
210
|
-
tableId?: undefined;
|
|
211
|
-
targetPreparedMessages?: undefined;
|
|
212
|
-
maxRowsToCheck?: undefined;
|
|
213
|
-
batchSize?: undefined;
|
|
214
|
-
maxBatchRows?: undefined;
|
|
215
|
-
approvalMode?: undefined;
|
|
216
|
-
rowSelector?: undefined;
|
|
217
|
-
excludeRowIds?: undefined;
|
|
218
|
-
autoContinue?: undefined;
|
|
219
|
-
senderId?: undefined;
|
|
220
|
-
actionType?: undefined;
|
|
221
|
-
targetDate?: undefined;
|
|
222
|
-
refillLaneKey?: undefined;
|
|
223
|
-
sourceEpoch?: undefined;
|
|
224
|
-
disableLowPassRateStop?: undefined;
|
|
225
|
-
};
|
|
226
|
-
required: string[];
|
|
227
|
-
additionalProperties: boolean;
|
|
228
|
-
};
|
|
229
168
|
})[];
|
|
230
169
|
export declare function startPrepareCampaignMessages(input: StartPrepareMessagesInput): Promise<unknown>;
|
|
231
170
|
export declare function getPrepareCampaignMessagesStatus(input: StatusPrepareMessagesInput): Promise<unknown>;
|
|
232
171
|
export declare function cancelPrepareCampaignMessages(input: CancelPrepareMessagesInput): Promise<unknown>;
|
|
233
|
-
export declare function stopSatisfiedPrepareCampaignMessages(input: StopSatisfiedPrepareMessagesInput): Promise<unknown>;
|
|
234
172
|
export {};
|
|
@@ -84,18 +84,6 @@ export const campaignMessagePreparationToolDefinitions = [
|
|
|
84
84
|
],
|
|
85
85
|
description: "Optional refill-scope send action. InMail scopes treat open and paid InMail as one contact-reuse family.",
|
|
86
86
|
},
|
|
87
|
-
targetDate: {
|
|
88
|
-
type: "string",
|
|
89
|
-
description: "Exact sender-local YYYY-MM-DD refill target date.",
|
|
90
|
-
},
|
|
91
|
-
refillLaneKey: {
|
|
92
|
-
type: "string",
|
|
93
|
-
description: "Normalized refill lane identity from the canonical target plan.",
|
|
94
|
-
},
|
|
95
|
-
sourceEpoch: {
|
|
96
|
-
type: "string",
|
|
97
|
-
description: "Stable source/provider epoch; only a material epoch change resets zero-yield recurrence.",
|
|
98
|
-
},
|
|
99
87
|
disableLowPassRateStop: {
|
|
100
88
|
type: "boolean",
|
|
101
89
|
description: "Operator override for explicit fill/exhaust requests. When true, keep processing eligible rows even if the enriched sample pass rate is low. Still bounded by targetPreparedMessages and maxRowsToCheck.",
|
|
@@ -123,23 +111,6 @@ export const campaignMessagePreparationToolDefinitions = [
|
|
|
123
111
|
additionalProperties: false,
|
|
124
112
|
},
|
|
125
113
|
},
|
|
126
|
-
{
|
|
127
|
-
name: "stop_satisfied_campaign_message_preparation",
|
|
128
|
-
description: "Cooperatively stop exactly one preparation job after the server rereads its persisted refill scope and proves its allocatable preparation deficit is zero. This never cancels table-wide workflow cells.",
|
|
129
|
-
inputSchema: {
|
|
130
|
-
type: "object",
|
|
131
|
-
properties: {
|
|
132
|
-
jobId: { type: "string" },
|
|
133
|
-
expectedUpdatedAt: {
|
|
134
|
-
type: "string",
|
|
135
|
-
description: "Optional optimistic job updatedAt revision from status.",
|
|
136
|
-
},
|
|
137
|
-
workspaceId: { type: "string" },
|
|
138
|
-
},
|
|
139
|
-
required: ["jobId"],
|
|
140
|
-
additionalProperties: false,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
114
|
{
|
|
144
115
|
name: "cancel_campaign_message_preparation",
|
|
145
116
|
description: "Cancel an active campaign message preparation job and cancel the same pending workflow-table cells that the UI Cancel Pending Cells button would cancel. Launch remains a separate explicit start_campaign step.",
|
|
@@ -174,9 +145,6 @@ export function startPrepareCampaignMessages(input) {
|
|
|
174
145
|
requestSource: input.requestSource,
|
|
175
146
|
senderId: input.senderId,
|
|
176
147
|
actionType: input.actionType,
|
|
177
|
-
targetDate: input.targetDate,
|
|
178
|
-
refillLaneKey: input.refillLaneKey,
|
|
179
|
-
sourceEpoch: input.sourceEpoch,
|
|
180
148
|
...(workspaceId ? { workspaceId } : {}),
|
|
181
149
|
}, workspaceId ?? undefined);
|
|
182
150
|
}
|
|
@@ -200,12 +168,3 @@ export function cancelPrepareCampaignMessages(input) {
|
|
|
200
168
|
...(workspaceId ? { workspaceId } : {}),
|
|
201
169
|
}, workspaceId ?? undefined);
|
|
202
170
|
}
|
|
203
|
-
export function stopSatisfiedPrepareCampaignMessages(input) {
|
|
204
|
-
const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
|
|
205
|
-
return postPrepareMessages({
|
|
206
|
-
action: "stop_if_target_satisfied",
|
|
207
|
-
jobId: input.jobId,
|
|
208
|
-
expectedUpdatedAt: input.expectedUpdatedAt,
|
|
209
|
-
...(workspaceId ? { workspaceId } : {}),
|
|
210
|
-
}, workspaceId ?? undefined);
|
|
211
|
-
}
|
package/dist/tools/campaigns.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getApi } from "../api.js";
|
|
2
|
-
import { getConfig
|
|
2
|
+
import { getConfig } from "../auth.js";
|
|
3
3
|
import { assertCreateCampaignPromptLoaded, assertNetNewCreateCampaignResearchReady, } from "./flow-preflight.js";
|
|
4
4
|
import { setCampaignInteractionMode, } from "./interaction-mode.js";
|
|
5
5
|
import { isLinkedInProfileInput, normalizeLinkedInProfileInput, } from "./linkedin-url.js";
|
|
@@ -114,7 +114,7 @@ function normalizeLeadSourceProvider(input) {
|
|
|
114
114
|
: null;
|
|
115
115
|
}
|
|
116
116
|
export function buildWatchUrl(config, path) {
|
|
117
|
-
const workspaceId =
|
|
117
|
+
const workspaceId = config.activeWorkspaceId || config.workspaceId;
|
|
118
118
|
const url = new URL(path, config.apiUrl);
|
|
119
119
|
if (workspaceId && !url.searchParams.has("workspaceId")) {
|
|
120
120
|
url.searchParams.set("workspaceId", workspaceId);
|
package/dist/tools/csv-dnc.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
|
3
3
|
import { readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
5
5
|
import { getApi } from "../api.js";
|
|
6
|
-
import { getConfig
|
|
6
|
+
import { getConfig } from "../auth.js";
|
|
7
7
|
import { resolveWorkspaceRoot } from "../utils/workspace-root.js";
|
|
8
8
|
import { sanitizeCsvDomainCandidate } from "./csv-domains.js";
|
|
9
9
|
import { validateAndNormalizeLinkedInUrl } from "./csv-linkedin.js";
|
|
@@ -324,7 +324,7 @@ function dedupeCandidates(candidates) {
|
|
|
324
324
|
}
|
|
325
325
|
async function getVerifiedActiveWorkspace() {
|
|
326
326
|
const config = getConfig();
|
|
327
|
-
const activeWorkspaceId =
|
|
327
|
+
const activeWorkspaceId = config.activeWorkspaceId || config.workspaceId;
|
|
328
328
|
if (!activeWorkspaceId) {
|
|
329
329
|
throw new Error("No active workspace selected. Run list_workspaces then set_active_workspace for the exact workspace whose Sellable DNC list should be read or updated.");
|
|
330
330
|
}
|
|
@@ -2,9 +2,6 @@ type GetRefillPlanV2Input = {
|
|
|
2
2
|
workspaceId?: string;
|
|
3
3
|
intent?: "auto" | "evergreen" | "plain" | "active";
|
|
4
4
|
senderIds?: string[];
|
|
5
|
-
horizonSendDays?: number;
|
|
6
|
-
untilDate?: string;
|
|
7
|
-
targetDate?: string;
|
|
8
5
|
runState?: Record<string, unknown>;
|
|
9
6
|
journal?: boolean;
|
|
10
7
|
journalNote?: string;
|
|
@@ -2,7 +2,6 @@ import * as path from "node:path";
|
|
|
2
2
|
import { getApi, SellableApiError } from "../api.js";
|
|
3
3
|
import { appendIndexLine, appendJournalEvent, createRunJournal, renderBootstrapSection, renderPlanSection, renderTerminalSection, } from "../refill-journal.js";
|
|
4
4
|
import { readRefillWorkspaceState } from "../refill-local-state.js";
|
|
5
|
-
import { getRefillTargetPlan } from "./refill-target-plan.js";
|
|
6
5
|
import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
|
|
7
6
|
const KNOWN_TOP_LEVEL_FIELDS = [
|
|
8
7
|
"readOnly",
|
|
@@ -200,24 +199,12 @@ export async function getRefillPlanV2(input) {
|
|
|
200
199
|
: buildRunStateFromLocalHints(workspaceId);
|
|
201
200
|
let raw;
|
|
202
201
|
try {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
input.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
intent: input.intent === "auto" ? undefined : (input.intent ?? undefined),
|
|
210
|
-
senderIds: input.senderIds,
|
|
211
|
-
targetDate: input.targetDate,
|
|
212
|
-
untilDate: input.untilDate,
|
|
213
|
-
horizonSendDays: input.horizonSendDays,
|
|
214
|
-
})
|
|
215
|
-
: await postRefillPlanV2({
|
|
216
|
-
workspaceId,
|
|
217
|
-
intent: input.intent ?? "auto",
|
|
218
|
-
senderIds: input.senderIds,
|
|
219
|
-
runState,
|
|
220
|
-
}, workspaceId);
|
|
202
|
+
raw = await postRefillPlanV2({
|
|
203
|
+
workspaceId,
|
|
204
|
+
intent: input.intent ?? "auto",
|
|
205
|
+
senderIds: input.senderIds,
|
|
206
|
+
runState,
|
|
207
|
+
}, workspaceId);
|
|
221
208
|
}
|
|
222
209
|
catch (error) {
|
|
223
210
|
if (!isWorkspaceAccessError(error))
|
|
@@ -251,16 +238,7 @@ export async function getRefillPlanV2(input) {
|
|
|
251
238
|
workspaceResolution: "explicit",
|
|
252
239
|
};
|
|
253
240
|
}
|
|
254
|
-
const
|
|
255
|
-
const target = isRecord(rawRecord.target) ? rawRecord.target : null;
|
|
256
|
-
const sanitized = sanitizeEvergreenRefillPlanResult(target
|
|
257
|
-
? {
|
|
258
|
-
...rawRecord,
|
|
259
|
-
plans: target.senderRefillPlans,
|
|
260
|
-
globalActionQueue: target.globalActionQueue,
|
|
261
|
-
packet: rawRecord,
|
|
262
|
-
}
|
|
263
|
-
: rawRecord);
|
|
241
|
+
const sanitized = sanitizeEvergreenRefillPlanResult(raw);
|
|
264
242
|
const warnings = Array.isArray(sanitized.warnings)
|
|
265
243
|
? [...sanitized.warnings]
|
|
266
244
|
: [];
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
type FindLeadsSnapshot = {
|
|
2
|
+
runId: string;
|
|
3
|
+
leadListId?: string;
|
|
4
|
+
version?: number;
|
|
5
|
+
status: string;
|
|
6
|
+
terminal?: boolean;
|
|
7
|
+
cancelled?: boolean;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
export declare const findLeadsRunToolDefinitions: readonly [{
|
|
11
|
+
readonly name: "bootstrap_find_leads";
|
|
12
|
+
readonly description: "Create or resume a durable campaignless Find Leads run and its lead list. No campaign or workingCampaignId is required.";
|
|
13
|
+
readonly inputSchema: {
|
|
14
|
+
readonly type: "object";
|
|
15
|
+
readonly properties: {
|
|
16
|
+
readonly bootstrapKey: {
|
|
17
|
+
readonly type: "string";
|
|
18
|
+
};
|
|
19
|
+
readonly name: {
|
|
20
|
+
readonly type: "string";
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
readonly required: readonly ["bootstrapKey"];
|
|
24
|
+
readonly additionalProperties: false;
|
|
25
|
+
};
|
|
26
|
+
}, {
|
|
27
|
+
readonly name: "get_find_leads_run";
|
|
28
|
+
readonly description: "Read the authoritative durable Find Leads snapshot.";
|
|
29
|
+
readonly inputSchema: {
|
|
30
|
+
readonly type: "object";
|
|
31
|
+
readonly properties: {
|
|
32
|
+
readonly runId: {
|
|
33
|
+
readonly type: "string";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly required: readonly ["runId"];
|
|
37
|
+
readonly additionalProperties: false;
|
|
38
|
+
};
|
|
39
|
+
}, {
|
|
40
|
+
readonly name: "update_find_leads_run";
|
|
41
|
+
readonly description: "Persist a provider/source/import approval receipt using optimistic concurrency.";
|
|
42
|
+
readonly inputSchema: {
|
|
43
|
+
readonly type: "object";
|
|
44
|
+
readonly properties: {
|
|
45
|
+
readonly runId: {
|
|
46
|
+
readonly type: "string";
|
|
47
|
+
};
|
|
48
|
+
readonly version: {
|
|
49
|
+
readonly type: "number";
|
|
50
|
+
};
|
|
51
|
+
readonly action: {
|
|
52
|
+
readonly type: "string";
|
|
53
|
+
readonly enum: readonly ["approve_provider", "approve_source_plan", "approve_import"];
|
|
54
|
+
};
|
|
55
|
+
readonly provider: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
readonly enum: readonly ["sales-nav", "prospeo", "signal-discovery"];
|
|
58
|
+
};
|
|
59
|
+
readonly receipt: {
|
|
60
|
+
readonly type: "object";
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
readonly required: readonly ["runId", "version", "action", "receipt"];
|
|
64
|
+
readonly additionalProperties: false;
|
|
65
|
+
};
|
|
66
|
+
}, {
|
|
67
|
+
readonly name: "wait_for_find_leads_run";
|
|
68
|
+
readonly description: "Poll durable Find Leads state until it changes or reaches a terminal state. Progress notifications are optional hints only.";
|
|
69
|
+
readonly inputSchema: {
|
|
70
|
+
readonly type: "object";
|
|
71
|
+
readonly properties: {
|
|
72
|
+
readonly runId: {
|
|
73
|
+
readonly type: "string";
|
|
74
|
+
};
|
|
75
|
+
readonly timeoutMs: {
|
|
76
|
+
readonly type: "number";
|
|
77
|
+
};
|
|
78
|
+
readonly intervalMs: {
|
|
79
|
+
readonly type: "number";
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
readonly required: readonly ["runId"];
|
|
83
|
+
readonly additionalProperties: false;
|
|
84
|
+
};
|
|
85
|
+
}, {
|
|
86
|
+
readonly name: "cancel_find_leads";
|
|
87
|
+
readonly description: "Cancel a mutable Find Leads run with its current version.";
|
|
88
|
+
readonly inputSchema: {
|
|
89
|
+
readonly type: "object";
|
|
90
|
+
readonly properties: {
|
|
91
|
+
readonly runId: {
|
|
92
|
+
readonly type: "string";
|
|
93
|
+
};
|
|
94
|
+
readonly version: {
|
|
95
|
+
readonly type: "number";
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
readonly required: readonly ["runId", "version"];
|
|
99
|
+
readonly additionalProperties: false;
|
|
100
|
+
};
|
|
101
|
+
}, {
|
|
102
|
+
readonly name: "reissue_find_leads_watch_link";
|
|
103
|
+
readonly description: "Rotate and return a fresh one-time live Find Leads watch handoff. Old links are revoked and cannot be reconstructed.";
|
|
104
|
+
readonly inputSchema: {
|
|
105
|
+
readonly type: "object";
|
|
106
|
+
readonly properties: {
|
|
107
|
+
readonly runId: {
|
|
108
|
+
readonly type: "string";
|
|
109
|
+
};
|
|
110
|
+
readonly mode: {
|
|
111
|
+
readonly type: "string";
|
|
112
|
+
readonly enum: readonly ["claude", "codex", "hermes"];
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
readonly required: readonly ["runId"];
|
|
116
|
+
readonly additionalProperties: false;
|
|
117
|
+
};
|
|
118
|
+
}];
|
|
119
|
+
export declare function bootstrapFindLeads(input: {
|
|
120
|
+
bootstrapKey: string;
|
|
121
|
+
name?: string;
|
|
122
|
+
}): Promise<FindLeadsSnapshot>;
|
|
123
|
+
export declare function getFindLeadsRun(input: {
|
|
124
|
+
runId: string;
|
|
125
|
+
}): Promise<FindLeadsSnapshot>;
|
|
126
|
+
export declare function updateFindLeadsRun(input: {
|
|
127
|
+
runId: string;
|
|
128
|
+
version: number;
|
|
129
|
+
action: "approve_provider" | "approve_source_plan" | "approve_import";
|
|
130
|
+
provider?: "sales-nav" | "prospeo" | "signal-discovery";
|
|
131
|
+
receipt: Record<string, unknown>;
|
|
132
|
+
}): Promise<FindLeadsSnapshot>;
|
|
133
|
+
export declare function cancelFindLeads(input: {
|
|
134
|
+
runId: string;
|
|
135
|
+
version: number;
|
|
136
|
+
}): Promise<FindLeadsSnapshot>;
|
|
137
|
+
export declare function reissueFindLeadsWatchLink(input: {
|
|
138
|
+
runId: string;
|
|
139
|
+
mode?: "claude" | "codex" | "hermes";
|
|
140
|
+
}): Promise<{
|
|
141
|
+
runId: string;
|
|
142
|
+
leadListId: string;
|
|
143
|
+
watchUrl: string;
|
|
144
|
+
expiresAt: string;
|
|
145
|
+
}>;
|
|
146
|
+
export declare function waitForFindLeadsRun(input: {
|
|
147
|
+
runId: string;
|
|
148
|
+
timeoutMs?: number;
|
|
149
|
+
intervalMs?: number;
|
|
150
|
+
}): Promise<FindLeadsSnapshot>;
|
|
151
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { getApi } from "../api.js";
|
|
2
|
+
import { getConfig } from "../auth.js";
|
|
3
|
+
function requestOptions() {
|
|
4
|
+
const config = getConfig();
|
|
5
|
+
const workspaceId = config.activeWorkspaceId || config.workspaceId || null;
|
|
6
|
+
if (!workspaceId) {
|
|
7
|
+
throw new Error("No active Sellable workspace. Run list_workspaces then set_active_workspace and retry Find Leads.");
|
|
8
|
+
}
|
|
9
|
+
return { workspaceId };
|
|
10
|
+
}
|
|
11
|
+
export const findLeadsRunToolDefinitions = [
|
|
12
|
+
{
|
|
13
|
+
name: "bootstrap_find_leads",
|
|
14
|
+
description: "Create or resume a durable campaignless Find Leads run and its lead list. No campaign or workingCampaignId is required.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: { bootstrapKey: { type: "string" }, name: { type: "string" } },
|
|
18
|
+
required: ["bootstrapKey"],
|
|
19
|
+
additionalProperties: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "get_find_leads_run",
|
|
24
|
+
description: "Read the authoritative durable Find Leads snapshot.",
|
|
25
|
+
inputSchema: { type: "object", properties: { runId: { type: "string" } }, required: ["runId"], additionalProperties: false },
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "update_find_leads_run",
|
|
29
|
+
description: "Persist a provider/source/import approval receipt using optimistic concurrency.",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
runId: { type: "string" }, version: { type: "number" },
|
|
34
|
+
action: { type: "string", enum: ["approve_provider", "approve_source_plan", "approve_import"] },
|
|
35
|
+
provider: { type: "string", enum: ["sales-nav", "prospeo", "signal-discovery"] },
|
|
36
|
+
receipt: { type: "object" },
|
|
37
|
+
},
|
|
38
|
+
required: ["runId", "version", "action", "receipt"],
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "wait_for_find_leads_run",
|
|
44
|
+
description: "Poll durable Find Leads state until it changes or reaches a terminal state. Progress notifications are optional hints only.",
|
|
45
|
+
inputSchema: {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: { runId: { type: "string" }, timeoutMs: { type: "number" }, intervalMs: { type: "number" } },
|
|
48
|
+
required: ["runId"], additionalProperties: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "cancel_find_leads",
|
|
53
|
+
description: "Cancel a mutable Find Leads run with its current version.",
|
|
54
|
+
inputSchema: { type: "object", properties: { runId: { type: "string" }, version: { type: "number" } }, required: ["runId", "version"], additionalProperties: false },
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "reissue_find_leads_watch_link",
|
|
58
|
+
description: "Rotate and return a fresh one-time live Find Leads watch handoff. Old links are revoked and cannot be reconstructed.",
|
|
59
|
+
inputSchema: { type: "object", properties: { runId: { type: "string" }, mode: { type: "string", enum: ["claude", "codex", "hermes"] } }, required: ["runId"], additionalProperties: false },
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
export async function bootstrapFindLeads(input) {
|
|
63
|
+
return getApi().post("/api/v3/find-leads/runs", input, requestOptions());
|
|
64
|
+
}
|
|
65
|
+
export async function getFindLeadsRun(input) {
|
|
66
|
+
return getApi().get(`/api/v3/find-leads/runs/${encodeURIComponent(input.runId)}`, requestOptions());
|
|
67
|
+
}
|
|
68
|
+
export async function updateFindLeadsRun(input) {
|
|
69
|
+
const kind = input.action === "approve_provider"
|
|
70
|
+
? "provider_prompt"
|
|
71
|
+
: input.action === "approve_source_plan"
|
|
72
|
+
? "source_plan"
|
|
73
|
+
: "import_approval";
|
|
74
|
+
const provider = input.provider?.replace(/-/g, "_");
|
|
75
|
+
return getApi().patch(`/api/v3/find-leads/runs/${encodeURIComponent(input.runId)}`, { action: "record_receipt", version: input.version, kind, receipt: input.receipt, ...(provider ? { provider } : {}) }, requestOptions());
|
|
76
|
+
}
|
|
77
|
+
export async function cancelFindLeads(input) {
|
|
78
|
+
return getApi().patch(`/api/v3/find-leads/runs/${encodeURIComponent(input.runId)}`, { action: "cancel", version: input.version }, requestOptions());
|
|
79
|
+
}
|
|
80
|
+
export async function reissueFindLeadsWatchLink(input) {
|
|
81
|
+
return getApi().post(`/api/v3/find-leads/runs/${encodeURIComponent(input.runId)}/watch-token`, { mode: input.mode ?? (process.env.CODEX_HOME ? "codex" : "claude") }, requestOptions());
|
|
82
|
+
}
|
|
83
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
84
|
+
export async function waitForFindLeadsRun(input) {
|
|
85
|
+
const timeoutMs = Math.min(Math.max(input.timeoutMs ?? 55_000, 25), 55_000);
|
|
86
|
+
const intervalMs = Math.min(Math.max(input.intervalMs ?? 2_000, 1), 10_000);
|
|
87
|
+
const startedAt = Date.now();
|
|
88
|
+
let previousVersion;
|
|
89
|
+
let snapshot = await getFindLeadsRun(input);
|
|
90
|
+
while (!snapshot.terminal && !snapshot.cancelled && Date.now() - startedAt < timeoutMs) {
|
|
91
|
+
if (previousVersion !== undefined && snapshot.version !== previousVersion)
|
|
92
|
+
return snapshot;
|
|
93
|
+
previousVersion = snapshot.version;
|
|
94
|
+
await sleep(intervalMs);
|
|
95
|
+
snapshot = await getFindLeadsRun(input);
|
|
96
|
+
}
|
|
97
|
+
return snapshot;
|
|
98
|
+
}
|