@sellable/mcp 0.1.237 → 0.1.239
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/engage-memory.d.ts +1 -0
- package/dist/engage-memory.js +18 -2
- package/dist/identity-memory.d.ts +1 -0
- package/dist/identity-memory.js +27 -0
- package/dist/tools/content-posts.d.ts +8 -0
- package/dist/tools/content-posts.js +23 -7
- package/dist/tools/engage-memory.js +1 -1
- package/dist/tools/registry.d.ts +2 -0
- package/package.json +2 -1
- package/skills/create-campaign-v2/SKILL.md +5 -4
- package/skills/create-campaign-v2/SOUL.md +4 -3
- package/skills/create-campaign-v2/core/flow.v2.json +1 -1
- package/skills/create-campaign-v2/references/approval-gate-framing.md +1 -1
- package/skills/create-campaign-v2/references/validation-criteria.md +4 -4
- package/skills/create-post/SKILL.md +119 -13
- package/skills/create-post/references/gold-standard-post-pack.md +211 -0
- package/skills/create-post/references/hook-research-playbook.md +103 -4
- package/skills/create-post/references/post-file-contract.md +5 -1
- package/skills/create-post/references/post-validation.md +76 -1
- package/skills/generate-messages/SKILL.md +5 -0
- package/skills/interview/references/reference-curation.md +27 -0
package/dist/engage-memory.d.ts
CHANGED
package/dist/engage-memory.js
CHANGED
|
@@ -116,8 +116,18 @@ function buildMarkdownTable(headers, rows) {
|
|
|
116
116
|
// ── Style guide ────────────────────────────────────────────────────────────
|
|
117
117
|
const FLAT_STYLE_CORE_PATH = "writing/styleguide-core.md";
|
|
118
118
|
const STYLE_COMMENTS_PATH = "writing/comments.md";
|
|
119
|
+
const STYLE_POSTS_PATH = "writing/posts.md";
|
|
119
120
|
const LEGACY_AUDIENCE_ICP_PATH = "audience/icp.md";
|
|
120
121
|
const LEGACY_FAQS_CORE_PATH = "faqs/core.md";
|
|
122
|
+
function readPostWritingRules() {
|
|
123
|
+
const markdown = readFile(STYLE_POSTS_PATH);
|
|
124
|
+
if (!markdown)
|
|
125
|
+
return undefined;
|
|
126
|
+
return {
|
|
127
|
+
markdown,
|
|
128
|
+
updatedAt: latestUpdatedAt([STYLE_POSTS_PATH]),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
121
131
|
function readStyleGuide(senderId, identityMemory) {
|
|
122
132
|
const corePath = senderPath(senderId, "styleguide-core.md", FLAT_STYLE_CORE_PATH);
|
|
123
133
|
const core = readFile(corePath);
|
|
@@ -200,7 +210,8 @@ function hasCoreIdentityMemory(identityMemory) {
|
|
|
200
210
|
identityMemory.decisionRules ||
|
|
201
211
|
identityMemory.changeLog ||
|
|
202
212
|
identityMemory.transcripts?.index ||
|
|
203
|
-
identityMemory.references?.index
|
|
213
|
+
identityMemory.references?.index ||
|
|
214
|
+
(identityMemory.references?.childIndexes?.length ?? 0) > 0);
|
|
204
215
|
}
|
|
205
216
|
function appendCoreSection(parts, sourcePaths, title, chunk) {
|
|
206
217
|
if (!chunk)
|
|
@@ -209,9 +220,12 @@ function appendCoreSection(parts, sourcePaths, title, chunk) {
|
|
|
209
220
|
sourcePaths.push(chunk.source.relativePath);
|
|
210
221
|
}
|
|
211
222
|
function appendCoreDirectoryIndex(parts, sourcePaths, title, directory) {
|
|
212
|
-
if (!directory
|
|
223
|
+
if (!directory)
|
|
213
224
|
return;
|
|
214
225
|
appendCoreSection(parts, sourcePaths, title, directory.index);
|
|
226
|
+
for (const childIndex of directory.childIndexes ?? []) {
|
|
227
|
+
appendCoreSection(parts, sourcePaths, title, childIndex);
|
|
228
|
+
}
|
|
215
229
|
}
|
|
216
230
|
function appendCompatibilitySection(parts, sourcePaths, section) {
|
|
217
231
|
parts.push(`## ${section.title} (${section.relativePath})\n\n${section.markdown.trim()}`);
|
|
@@ -229,11 +243,13 @@ function latestUpdatedAt(relativePaths) {
|
|
|
229
243
|
export function getEngageMemory(senderId) {
|
|
230
244
|
const identityMemory = readIdentityMemory({ connectedSenderId: senderId });
|
|
231
245
|
const styleGuide = readStyleGuide(senderId, identityMemory);
|
|
246
|
+
const postWritingRules = readPostWritingRules();
|
|
232
247
|
const provenSearches = readProvenSearches(senderId);
|
|
233
248
|
const trackedPeople = readTrackedPeople(senderId);
|
|
234
249
|
return {
|
|
235
250
|
memory: {
|
|
236
251
|
styleGuide,
|
|
252
|
+
postWritingRules,
|
|
237
253
|
provenSearches,
|
|
238
254
|
trackedPeople,
|
|
239
255
|
...identityMemory,
|
|
@@ -23,6 +23,7 @@ export interface IdentityMemoryChunk {
|
|
|
23
23
|
export interface IdentityMemoryDirectory {
|
|
24
24
|
source: IdentityMemorySource;
|
|
25
25
|
index?: IdentityMemoryChunk;
|
|
26
|
+
childIndexes?: IdentityMemoryChunk[];
|
|
26
27
|
}
|
|
27
28
|
export interface IdentityMemory {
|
|
28
29
|
identity?: IdentityMemoryChunk;
|
package/dist/identity-memory.js
CHANGED
|
@@ -81,5 +81,32 @@ function readDirectory(configsDir, relativePath) {
|
|
|
81
81
|
if (index) {
|
|
82
82
|
directory.index = index;
|
|
83
83
|
}
|
|
84
|
+
const childIndexes = readChildIndexes(configsDir, relativePath);
|
|
85
|
+
if (childIndexes.length > 0) {
|
|
86
|
+
directory.childIndexes = childIndexes;
|
|
87
|
+
}
|
|
84
88
|
return directory;
|
|
85
89
|
}
|
|
90
|
+
function readChildIndexes(configsDir, relativePath) {
|
|
91
|
+
const root = path.join(configsDir, relativePath);
|
|
92
|
+
const indexes = [];
|
|
93
|
+
function walk(currentFullPath, currentRelativePath) {
|
|
94
|
+
for (const entry of fs.readdirSync(currentFullPath).sort()) {
|
|
95
|
+
const entryFullPath = path.join(currentFullPath, entry);
|
|
96
|
+
const entryRelativePath = `${currentRelativePath}/${entry}`;
|
|
97
|
+
const stat = fs.statSync(entryFullPath);
|
|
98
|
+
if (stat.isDirectory()) {
|
|
99
|
+
walk(entryFullPath, entryRelativePath);
|
|
100
|
+
}
|
|
101
|
+
else if (stat.isFile() &&
|
|
102
|
+
entry === "INDEX.md" &&
|
|
103
|
+
entryRelativePath !== `${relativePath}/INDEX.md`) {
|
|
104
|
+
const chunk = readMarkdownChunk(configsDir, entryRelativePath);
|
|
105
|
+
if (chunk)
|
|
106
|
+
indexes.push(chunk);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
walk(root, relativePath);
|
|
111
|
+
return indexes;
|
|
112
|
+
}
|
|
@@ -58,6 +58,7 @@ export declare const contentPostToolDefinitions: ({
|
|
|
58
58
|
keywords?: undefined;
|
|
59
59
|
sourcePosts?: undefined;
|
|
60
60
|
selectedPatterns?: undefined;
|
|
61
|
+
previewBudget?: undefined;
|
|
61
62
|
notes?: undefined;
|
|
62
63
|
createdAt?: undefined;
|
|
63
64
|
draftId?: undefined;
|
|
@@ -130,6 +131,11 @@ export declare const contentPostToolDefinitions: ({
|
|
|
130
131
|
type: string;
|
|
131
132
|
};
|
|
132
133
|
};
|
|
134
|
+
previewBudget: {
|
|
135
|
+
type: string;
|
|
136
|
+
description: string;
|
|
137
|
+
additionalProperties: boolean;
|
|
138
|
+
};
|
|
133
139
|
notes: {
|
|
134
140
|
type: string;
|
|
135
141
|
};
|
|
@@ -192,6 +198,7 @@ export declare const contentPostToolDefinitions: ({
|
|
|
192
198
|
keywords?: undefined;
|
|
193
199
|
sourcePosts?: undefined;
|
|
194
200
|
selectedPatterns?: undefined;
|
|
201
|
+
previewBudget?: undefined;
|
|
195
202
|
notes?: undefined;
|
|
196
203
|
};
|
|
197
204
|
required: string[];
|
|
@@ -245,6 +252,7 @@ export declare function saveHookResearchTool(input: {
|
|
|
245
252
|
keywords?: string[];
|
|
246
253
|
sourcePosts?: Array<Record<string, unknown>>;
|
|
247
254
|
selectedPatterns?: string[];
|
|
255
|
+
previewBudget?: Record<string, unknown>;
|
|
248
256
|
notes?: string;
|
|
249
257
|
createdAt?: string;
|
|
250
258
|
}): {
|
|
@@ -66,6 +66,11 @@ export const contentPostToolDefinitions = [
|
|
|
66
66
|
type: "array",
|
|
67
67
|
items: { type: "string" },
|
|
68
68
|
},
|
|
69
|
+
previewBudget: {
|
|
70
|
+
type: "object",
|
|
71
|
+
description: "Optional structured LinkedIn preview-budget summary for studied hooks and selected patterns.",
|
|
72
|
+
additionalProperties: true,
|
|
73
|
+
},
|
|
69
74
|
notes: { type: "string" },
|
|
70
75
|
createdAt: { type: "string" },
|
|
71
76
|
},
|
|
@@ -202,11 +207,14 @@ export function capturePostIdeaTool(input) {
|
|
|
202
207
|
const markdown = buildMarkdown(metadata, [
|
|
203
208
|
["Distilled Brief", input.distilledBrief || ""],
|
|
204
209
|
["Raw Source", rawBlock(input.rawSource)],
|
|
205
|
-
[
|
|
210
|
+
[
|
|
211
|
+
"Source Metadata",
|
|
212
|
+
jsonBlock(stripUndefined({
|
|
206
213
|
sourceType: input.sourceType,
|
|
207
214
|
sourceUrl: input.sourceUrl,
|
|
208
215
|
capturedAt: now,
|
|
209
|
-
}))
|
|
216
|
+
})),
|
|
217
|
+
],
|
|
210
218
|
]);
|
|
211
219
|
writeArtifact(relativePath, markdown);
|
|
212
220
|
return {
|
|
@@ -246,6 +254,7 @@ export function saveHookResearchTool(input) {
|
|
|
246
254
|
const markdown = buildMarkdown(metadata, [
|
|
247
255
|
["Keywords", listBlock(input.keywords ?? [])],
|
|
248
256
|
["Selected Patterns", listBlock(input.selectedPatterns ?? [])],
|
|
257
|
+
["Preview Budget", jsonBlock(input.previewBudget ?? {})],
|
|
249
258
|
["Source Posts", jsonBlock(input.sourcePosts ?? [])],
|
|
250
259
|
["Notes", input.notes || ""],
|
|
251
260
|
]);
|
|
@@ -332,18 +341,24 @@ export function markPostPublishedTool(input) {
|
|
|
332
341
|
};
|
|
333
342
|
const markdown = buildMarkdown(metadata, [
|
|
334
343
|
["Final Text", input.finalText || ""],
|
|
335
|
-
[
|
|
344
|
+
[
|
|
345
|
+
"Publish Metadata",
|
|
346
|
+
jsonBlock(stripUndefined({
|
|
336
347
|
draftId: safeDraftId,
|
|
337
348
|
publishUrl: input.publishUrl,
|
|
338
349
|
activityId: activityId || undefined,
|
|
339
350
|
publishedAt,
|
|
340
|
-
}))
|
|
341
|
-
|
|
351
|
+
})),
|
|
352
|
+
],
|
|
353
|
+
[
|
|
354
|
+
"Future Metrics",
|
|
355
|
+
jsonBlock({
|
|
342
356
|
impressions: null,
|
|
343
357
|
reactions: null,
|
|
344
358
|
comments: null,
|
|
345
359
|
snapshots: [],
|
|
346
|
-
})
|
|
360
|
+
}),
|
|
361
|
+
],
|
|
347
362
|
]);
|
|
348
363
|
writeArtifact(relativePath, markdown);
|
|
349
364
|
return {
|
|
@@ -483,7 +498,8 @@ function validateRelativePath(relativePath) {
|
|
|
483
498
|
}
|
|
484
499
|
function isPathInside(candidate, root) {
|
|
485
500
|
const relative = path.relative(root, candidate);
|
|
486
|
-
return relative === "" ||
|
|
501
|
+
return (relative === "" ||
|
|
502
|
+
(!relative.startsWith("..") && !path.isAbsolute(relative)));
|
|
487
503
|
}
|
|
488
504
|
function normalizeArtifactId(id, label) {
|
|
489
505
|
requireString(id, label);
|
|
@@ -2,7 +2,7 @@ import { copySenderConfig, getEngageMemory, migrateFlatConfigs, recordProvenSear
|
|
|
2
2
|
export const engageMemoryToolDefinitions = [
|
|
3
3
|
{
|
|
4
4
|
name: "get_engage_memory",
|
|
5
|
-
description: "Load backward-compatible engage memory from ~/.sellable/configs/: style guide, proven search keywords, tracked people, plus optional core identity/company memory. All data lives in readable markdown files the user can also edit directly. When senderId is provided, reads compatibility overrides from senders/{senderId}/ with flat-path fallback.",
|
|
5
|
+
description: "Load backward-compatible engage memory from ~/.sellable/configs/: style guide, post writing rules, proven search keywords, tracked people, plus optional core identity/company memory. All data lives in readable markdown files the user can also edit directly. When senderId is provided, reads compatibility overrides from senders/{senderId}/ with flat-path fallback.",
|
|
6
6
|
inputSchema: {
|
|
7
7
|
type: "object",
|
|
8
8
|
properties: {
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -1214,6 +1214,7 @@ export declare const allTools: ({
|
|
|
1214
1214
|
keywords?: undefined;
|
|
1215
1215
|
sourcePosts?: undefined;
|
|
1216
1216
|
selectedPatterns?: undefined;
|
|
1217
|
+
previewBudget?: undefined;
|
|
1217
1218
|
notes?: undefined;
|
|
1218
1219
|
createdAt?: undefined;
|
|
1219
1220
|
draftId?: undefined;
|
|
@@ -1279,6 +1280,7 @@ export declare const allTools: ({
|
|
|
1279
1280
|
keywords?: undefined;
|
|
1280
1281
|
sourcePosts?: undefined;
|
|
1281
1282
|
selectedPatterns?: undefined;
|
|
1283
|
+
previewBudget?: undefined;
|
|
1282
1284
|
notes?: undefined;
|
|
1283
1285
|
};
|
|
1284
1286
|
required: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sellable/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.239",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Sellable MCP server for Claude Code and Codex campaign workflows",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
|
+
"prepack": "npm run build",
|
|
14
15
|
"start": "node dist/index.js",
|
|
15
16
|
"start:dev": "node dist/index-dev.js",
|
|
16
17
|
"dev": "ts-node src/index.ts"
|
|
@@ -107,8 +107,8 @@ This is based on what I found. If your site or LinkedIn is stale, tell me what
|
|
|
107
107
|
to update before I build the lead list.
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
Ask: "
|
|
111
|
-
must not include quoted first-message copy. If a message-shape hint is useful,
|
|
110
|
+
Ask: "Does this brief look right, and how should Sellable continue?" The early
|
|
111
|
+
brief must not include quoted first-message copy. If a message-shape hint is useful,
|
|
112
112
|
keep it as non-final bullets and say: "This is not the message yet; I will write
|
|
113
113
|
real examples after we find and filter leads."
|
|
114
114
|
|
|
@@ -120,8 +120,9 @@ watch-link handoff, then ask approve/revise.
|
|
|
120
120
|
## YOLO Mode
|
|
121
121
|
|
|
122
122
|
Enable YOLO when the user asks for yolo/autopilot, passes `--yolo` or
|
|
123
|
-
`mode=yolo`, selects `Approve + YOLO
|
|
124
|
-
guesses. If identity is missing, ask only for the LinkedIn
|
|
123
|
+
`mode=yolo`, selects `Approve brief + activate YOLO mode (Recommended)`, or asks
|
|
124
|
+
you to use best guesses. If identity is missing, ask only for the LinkedIn
|
|
125
|
+
profile URL; never
|
|
125
126
|
continue from a website/domain alone. Infer buyer, offer/CTA, proof, source,
|
|
126
127
|
filters, and message direction from evidence plus user directions; newest wins.
|
|
127
128
|
Set `interactionMode: "autonomous"` once `campaignId` exists. Auto-select
|
|
@@ -364,9 +364,10 @@ wants to "sell first." Say "sender and company" for the person/company context,
|
|
|
364
364
|
and ask what we should "pitch to prospects first" for the offer/CTA choice.
|
|
365
365
|
|
|
366
366
|
At the brief approval gate, do not add a negative list of future steps that are
|
|
367
|
-
not approved. Ask
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
not approved. Ask whether the brief looks right and how Sellable should continue:
|
|
368
|
+
activate YOLO mode, build the campaign with AI step by step, or revise the
|
|
369
|
+
brief. The YOLO option approves the brief, auto-decides the remaining setup
|
|
370
|
+
choices with best guesses, and still stops before final launch.
|
|
370
371
|
|
|
371
372
|
At message review, if the user asks for edits, write the revised template and
|
|
372
373
|
examples before asking approval again. Route the feedback back to Message
|