@sellable/install 0.1.207 → 0.1.208
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 +5 -3
- package/bin/sellable-install.mjs +6 -6
- package/lib/runtime-verify.mjs +242 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,11 +55,13 @@ Agents should use the agent-readable handoff instead of guessing commands:
|
|
|
55
55
|
Install Sellable CLI and skills using https://app.sellable.dev/agent-install.txt
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
The direct npm installer
|
|
59
|
-
|
|
58
|
+
The direct npm installer is only a package-level troubleshooting fallback for
|
|
59
|
+
maintainers. Public installs should keep using the curl endpoint above because
|
|
60
|
+
it bootstraps Node, repairs legacy state, installs skills, and runs runtime
|
|
61
|
+
verification in one path:
|
|
60
62
|
|
|
61
63
|
```bash
|
|
62
|
-
|
|
64
|
+
curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh
|
|
63
65
|
```
|
|
64
66
|
|
|
65
67
|
For CI/scripted installs, get a Sellable API token from:
|
package/bin/sellable-install.mjs
CHANGED
|
@@ -1315,7 +1315,7 @@ local harness scripts, or read local prompt files to emulate this workflow.
|
|
|
1315
1315
|
|
|
1316
1316
|
If the Sellable MCP tool is unavailable, stop and say this is a Codex
|
|
1317
1317
|
install/reload problem. Tell the user to run
|
|
1318
|
-
\`
|
|
1318
|
+
\`curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh\`, fully quit and reopen Codex
|
|
1319
1319
|
Desktop, then start a new thread.
|
|
1320
1320
|
|
|
1321
1321
|
1. Call \`mcp__sellable__get_auth_status({})\`.
|
|
@@ -1363,7 +1363,7 @@ emulate this workflow.
|
|
|
1363
1363
|
|
|
1364
1364
|
If the Sellable MCP prompt tools are unavailable, stop and say this is a Codex
|
|
1365
1365
|
install/reload problem. Tell the user to run
|
|
1366
|
-
\`
|
|
1366
|
+
\`curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh\`, fully quit and reopen Codex
|
|
1367
1367
|
Desktop, then start a new thread.
|
|
1368
1368
|
|
|
1369
1369
|
## Execute Workflow
|
|
@@ -1440,7 +1440,7 @@ emulate this workflow.
|
|
|
1440
1440
|
|
|
1441
1441
|
If the Sellable MCP prompt tools are unavailable, stop and say this is a Codex
|
|
1442
1442
|
install/reload problem. Tell the user to run
|
|
1443
|
-
\`
|
|
1443
|
+
\`curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh\`, fully quit and reopen Codex
|
|
1444
1444
|
Desktop, then start a new thread.
|
|
1445
1445
|
|
|
1446
1446
|
## Execute Workflow
|
|
@@ -1512,7 +1512,7 @@ emulate this workflow.
|
|
|
1512
1512
|
|
|
1513
1513
|
If the Sellable MCP prompt tools are unavailable, stop and say this is a Codex
|
|
1514
1514
|
install/reload problem. Tell the user to run
|
|
1515
|
-
\`
|
|
1515
|
+
\`curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh\`, fully quit and reopen Codex
|
|
1516
1516
|
Desktop, then start a new thread.
|
|
1517
1517
|
|
|
1518
1518
|
## Execute Workflow
|
|
@@ -2690,8 +2690,8 @@ async function verify(opts) {
|
|
|
2690
2690
|
(runtimeRequired ? requiredCheck : warningCheck)(
|
|
2691
2691
|
runtimeMcp.ok,
|
|
2692
2692
|
runtimeMcp.ok
|
|
2693
|
-
? `MCP runtime exposes required tools (${runtimeMcp.availableTools.length} total)`
|
|
2694
|
-
: `MCP runtime
|
|
2693
|
+
? `MCP runtime exposes required campaign tools (${runtimeMcp.availableTools.length} total) and create-campaign smoke passed`
|
|
2694
|
+
: `MCP runtime verification failed: ${runtimeMcp.missingTools.join(", ") || runtimeMcp.createCampaignSmoke?.error || runtimeMcp.error || "unknown failure"}`
|
|
2695
2695
|
)
|
|
2696
2696
|
);
|
|
2697
2697
|
}
|
package/lib/runtime-verify.mjs
CHANGED
|
@@ -6,12 +6,64 @@ const DEFAULT_VERIFY_TIMEOUT_MS = 10_000;
|
|
|
6
6
|
|
|
7
7
|
export const REQUIRED_SELLABLE_MCP_TOOLS = [
|
|
8
8
|
"get_auth_status",
|
|
9
|
+
"start_cli_login",
|
|
10
|
+
"wait_for_cli_login",
|
|
9
11
|
"bootstrap_create_campaign",
|
|
12
|
+
"get_subskill_prompt",
|
|
13
|
+
"get_subskill_asset",
|
|
14
|
+
"search_subskill_prompts",
|
|
10
15
|
"create_campaign",
|
|
11
16
|
"import_leads",
|
|
17
|
+
"confirm_lead_list",
|
|
18
|
+
"wait_for_lead_list_ready",
|
|
19
|
+
"wait_for_campaign_table_ready",
|
|
12
20
|
"update_campaign",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
21
|
+
"update_campaign_brief",
|
|
22
|
+
"get_campaign",
|
|
23
|
+
"get_campaign_context",
|
|
24
|
+
"get_campaign_framework",
|
|
25
|
+
"get_campaign_navigation_state",
|
|
26
|
+
"get_campaign_messages_preview",
|
|
27
|
+
"attach_sequence",
|
|
28
|
+
"attach_recommended_sequence",
|
|
29
|
+
"start_campaign_message_preparation",
|
|
30
|
+
"get_campaign_message_preparation_status",
|
|
31
|
+
"cancel_campaign_message_preparation",
|
|
32
|
+
"start_campaign",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const CREATE_CAMPAIGN_SMOKE_CALLS = [
|
|
36
|
+
{
|
|
37
|
+
name: "get_auth_status",
|
|
38
|
+
arguments: {},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "bootstrap_create_campaign",
|
|
42
|
+
arguments: {
|
|
43
|
+
flowVersion: "v2",
|
|
44
|
+
includeTableCheck: false,
|
|
45
|
+
host: "sellable-install-verify",
|
|
46
|
+
model: "installer-smoke",
|
|
47
|
+
reasoningEffort: "none",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "get_subskill_prompt",
|
|
52
|
+
arguments: {
|
|
53
|
+
subskillName: "create-campaign-v2",
|
|
54
|
+
offset: 0,
|
|
55
|
+
limit: 1200,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "get_subskill_asset",
|
|
60
|
+
arguments: {
|
|
61
|
+
subskillName: "create-campaign-v2",
|
|
62
|
+
assetPath: "core/flow.v2.json",
|
|
63
|
+
offset: 0,
|
|
64
|
+
limit: 1200,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
15
67
|
];
|
|
16
68
|
|
|
17
69
|
function collectStderrLines(stream) {
|
|
@@ -73,6 +125,172 @@ export function missingRequiredTools(tools, requiredTools) {
|
|
|
73
125
|
return requiredTools.filter((name) => !available.has(name));
|
|
74
126
|
}
|
|
75
127
|
|
|
128
|
+
function textFromToolResult(result) {
|
|
129
|
+
return (result?.content || [])
|
|
130
|
+
.filter((part) => part?.type === "text" && typeof part.text === "string")
|
|
131
|
+
.map((part) => part.text)
|
|
132
|
+
.join("\n");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function parseJsonText(text) {
|
|
136
|
+
if (!text) return null;
|
|
137
|
+
try {
|
|
138
|
+
return JSON.parse(text);
|
|
139
|
+
} catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function summarizeToolResult(name, result) {
|
|
145
|
+
const text = redact(textFromToolResult(result));
|
|
146
|
+
const parsed = parseJsonText(text);
|
|
147
|
+
const summary = {
|
|
148
|
+
isError: result?.isError === true,
|
|
149
|
+
textChars: text.length,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (name === "get_auth_status" && parsed) {
|
|
153
|
+
return {
|
|
154
|
+
...summary,
|
|
155
|
+
authOk: parsed.ok === true,
|
|
156
|
+
errorType: parsed.error?.type || null,
|
|
157
|
+
activeWorkspaceId: parsed.activeWorkspaceId || null,
|
|
158
|
+
activeWorkspaceName: parsed.activeWorkspaceName || null,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (name === "bootstrap_create_campaign" && parsed) {
|
|
163
|
+
return {
|
|
164
|
+
...summary,
|
|
165
|
+
safeToProceed: parsed.safeToProceed === true,
|
|
166
|
+
flowVersion: parsed.flowVersion || null,
|
|
167
|
+
blockingChecks: Array.isArray(parsed.blockingErrors)
|
|
168
|
+
? parsed.blockingErrors.map((entry) => entry?.check).filter(Boolean)
|
|
169
|
+
: [],
|
|
170
|
+
requiredChecks: Array.isArray(parsed.requiredChecks)
|
|
171
|
+
? parsed.requiredChecks.map((entry) => ({
|
|
172
|
+
key: entry?.key || null,
|
|
173
|
+
ok: entry?.ok === true,
|
|
174
|
+
blocking: entry?.blocking === true,
|
|
175
|
+
}))
|
|
176
|
+
: [],
|
|
177
|
+
nextStepChars:
|
|
178
|
+
typeof parsed.nextStep === "string" ? parsed.nextStep.length : 0,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (name === "get_subskill_prompt" && parsed) {
|
|
183
|
+
return {
|
|
184
|
+
...summary,
|
|
185
|
+
subskillName: parsed.name || null,
|
|
186
|
+
promptChars: typeof parsed.prompt === "string" ? parsed.prompt.length : 0,
|
|
187
|
+
hasMore: parsed.hasMore === true,
|
|
188
|
+
nextOffset:
|
|
189
|
+
typeof parsed.nextOffset === "number" ? parsed.nextOffset : null,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (name === "get_subskill_asset" && parsed) {
|
|
194
|
+
return {
|
|
195
|
+
...summary,
|
|
196
|
+
subskillName: parsed.subskillName || null,
|
|
197
|
+
assetPath: parsed.assetPath || null,
|
|
198
|
+
assetChars: typeof parsed.content === "string" ? parsed.content.length : 0,
|
|
199
|
+
hasMore: parsed.hasMore === true,
|
|
200
|
+
nextOffset:
|
|
201
|
+
typeof parsed.nextOffset === "number" ? parsed.nextOffset : null,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return summary;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function verifyCreateCampaignSmoke({
|
|
209
|
+
client,
|
|
210
|
+
availableTools,
|
|
211
|
+
timeoutMs,
|
|
212
|
+
smokeCalls = CREATE_CAMPAIGN_SMOKE_CALLS,
|
|
213
|
+
}) {
|
|
214
|
+
const startedAt = new Date().toISOString();
|
|
215
|
+
const available = new Set(availableTools || []);
|
|
216
|
+
const missingTools = smokeCalls
|
|
217
|
+
.map((call) => call.name)
|
|
218
|
+
.filter((name) => !available.has(name));
|
|
219
|
+
const calls = [];
|
|
220
|
+
|
|
221
|
+
if (missingTools.length > 0) {
|
|
222
|
+
return {
|
|
223
|
+
ok: false,
|
|
224
|
+
missingTools,
|
|
225
|
+
calls,
|
|
226
|
+
error: `Missing smoke tool(s): ${missingTools.join(", ")}`,
|
|
227
|
+
startedAt,
|
|
228
|
+
completedAt: new Date().toISOString(),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
for (const call of smokeCalls) {
|
|
233
|
+
const callStartedAt = new Date().toISOString();
|
|
234
|
+
try {
|
|
235
|
+
const result = await client.callTool(
|
|
236
|
+
{ name: call.name, arguments: call.arguments },
|
|
237
|
+
undefined,
|
|
238
|
+
{
|
|
239
|
+
timeout: timeoutMs,
|
|
240
|
+
maxTotalTimeout: timeoutMs,
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
const summary = summarizeToolResult(call.name, result);
|
|
244
|
+
calls.push({
|
|
245
|
+
name: call.name,
|
|
246
|
+
arguments: call.arguments,
|
|
247
|
+
ok: summary.isError !== true,
|
|
248
|
+
summary,
|
|
249
|
+
startedAt: callStartedAt,
|
|
250
|
+
completedAt: new Date().toISOString(),
|
|
251
|
+
});
|
|
252
|
+
if (summary.isError === true) {
|
|
253
|
+
return {
|
|
254
|
+
ok: false,
|
|
255
|
+
missingTools: [],
|
|
256
|
+
calls,
|
|
257
|
+
error: `${call.name} returned an MCP tool error`,
|
|
258
|
+
startedAt,
|
|
259
|
+
completedAt: new Date().toISOString(),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
} catch (err) {
|
|
263
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
264
|
+
calls.push({
|
|
265
|
+
name: call.name,
|
|
266
|
+
arguments: call.arguments,
|
|
267
|
+
ok: false,
|
|
268
|
+
summary: null,
|
|
269
|
+
error: redact(error),
|
|
270
|
+
startedAt: callStartedAt,
|
|
271
|
+
completedAt: new Date().toISOString(),
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
ok: false,
|
|
275
|
+
missingTools: [],
|
|
276
|
+
calls,
|
|
277
|
+
error: redact(error),
|
|
278
|
+
startedAt,
|
|
279
|
+
completedAt: new Date().toISOString(),
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
ok: true,
|
|
286
|
+
missingTools: [],
|
|
287
|
+
calls,
|
|
288
|
+
error: null,
|
|
289
|
+
startedAt,
|
|
290
|
+
completedAt: new Date().toISOString(),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
76
294
|
export async function verifySellableMcpRuntime({
|
|
77
295
|
command,
|
|
78
296
|
args = [],
|
|
@@ -116,6 +334,7 @@ export async function verifySellableMcpRuntime({
|
|
|
116
334
|
|
|
117
335
|
let availableTools = [];
|
|
118
336
|
let missingTools = [...requiredTools];
|
|
337
|
+
let createCampaignSmoke = null;
|
|
119
338
|
let error = null;
|
|
120
339
|
|
|
121
340
|
try {
|
|
@@ -126,6 +345,25 @@ export async function verifySellableMcpRuntime({
|
|
|
126
345
|
});
|
|
127
346
|
availableTools = toolList.tools.map((tool) => tool.name).sort();
|
|
128
347
|
missingTools = missingRequiredTools(toolList.tools, requiredTools);
|
|
348
|
+
if (missingTools.length === 0) {
|
|
349
|
+
createCampaignSmoke = await verifyCreateCampaignSmoke({
|
|
350
|
+
client,
|
|
351
|
+
availableTools,
|
|
352
|
+
timeoutMs,
|
|
353
|
+
});
|
|
354
|
+
} else {
|
|
355
|
+
createCampaignSmoke = {
|
|
356
|
+
ok: false,
|
|
357
|
+
missingTools: CREATE_CAMPAIGN_SMOKE_CALLS.map((call) => call.name).filter(
|
|
358
|
+
(name) => !availableTools.includes(name)
|
|
359
|
+
),
|
|
360
|
+
calls: [],
|
|
361
|
+
error:
|
|
362
|
+
"Skipping create-campaign smoke because required MCP tools are missing.",
|
|
363
|
+
startedAt: new Date().toISOString(),
|
|
364
|
+
completedAt: new Date().toISOString(),
|
|
365
|
+
};
|
|
366
|
+
}
|
|
129
367
|
} catch (err) {
|
|
130
368
|
error = err instanceof Error ? err.message : String(err);
|
|
131
369
|
} finally {
|
|
@@ -137,13 +375,14 @@ export async function verifySellableMcpRuntime({
|
|
|
137
375
|
}
|
|
138
376
|
|
|
139
377
|
return {
|
|
140
|
-
ok: !error && missingTools.length === 0,
|
|
378
|
+
ok: !error && missingTools.length === 0 && createCampaignSmoke?.ok === true,
|
|
141
379
|
skipped: false,
|
|
142
380
|
command,
|
|
143
381
|
args,
|
|
144
382
|
requiredTools,
|
|
145
383
|
availableTools,
|
|
146
384
|
missingTools,
|
|
385
|
+
createCampaignSmoke,
|
|
147
386
|
stderrTail: stderrLines,
|
|
148
387
|
error: error ? redact(error) : null,
|
|
149
388
|
startedAt,
|