@sellable/install 0.1.68 → 0.1.69
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/bin/sellable-install.mjs
CHANGED
|
@@ -1089,6 +1089,112 @@ function codexPluginSkills() {
|
|
|
1089
1089
|
];
|
|
1090
1090
|
}
|
|
1091
1091
|
|
|
1092
|
+
function codexCustomAgents() {
|
|
1093
|
+
const commonPrefix = `You are part of the Sellable find-leads source scout.
|
|
1094
|
+
|
|
1095
|
+
Work only on your assigned source lane. Do not import leads, create campaigns, write campaign artifacts, or draft messages. Return concise structured evidence to the parent agent so it can synthesize the lead-source decision.`;
|
|
1096
|
+
|
|
1097
|
+
return [
|
|
1098
|
+
{
|
|
1099
|
+
filename: "linkedin-engagement-scout.toml",
|
|
1100
|
+
content: `name = "linkedin_engagement_scout"
|
|
1101
|
+
description = "Sellable lead-source scout for LinkedIn post engagement and active conversation signals."
|
|
1102
|
+
model_reasoning_effort = "medium"
|
|
1103
|
+
sandbox_mode = "read-only"
|
|
1104
|
+
nickname_candidates = ["LinkedIn Engagement Scout", "Post Scout", "Engager Scout"]
|
|
1105
|
+
developer_instructions = """
|
|
1106
|
+
${commonPrefix}
|
|
1107
|
+
|
|
1108
|
+
Your lane is LinkedIn Engagement. Internally, use the signal-discovery provider prompt and the Signals tools when available.
|
|
1109
|
+
|
|
1110
|
+
Use the inherited Sellable MCP tools when available:
|
|
1111
|
+
- get_provider_prompt for signal-discovery before searching
|
|
1112
|
+
- search_signals to find recent post lanes
|
|
1113
|
+
- fetch_post_engagers to sample engagers from selected posts
|
|
1114
|
+
|
|
1115
|
+
Process:
|
|
1116
|
+
1. Search 3-5 keyword/topic lanes, favoring fresh posts from the last 7-14 days.
|
|
1117
|
+
2. Select 3-5 promising posts when available.
|
|
1118
|
+
3. Fetch or sample engagers for selected posts and score rough ICP fit from visible headline/display cues.
|
|
1119
|
+
4. Estimate usable prospects per selected post from sampled pass rate.
|
|
1120
|
+
5. If the sample is good but volume is low, say how many more similar posts should be added or scraped.
|
|
1121
|
+
|
|
1122
|
+
Return:
|
|
1123
|
+
- keyword lanes searched, timeframe, raw posts found, finalist posts reviewed
|
|
1124
|
+
- selected post URL/title, author/topic, age, engager count, sampled engagers, good fits as n/N, estimated usable prospects per post, use/discard
|
|
1125
|
+
- sample leads if any
|
|
1126
|
+
- estimated good-fit range, directional reply-rate range, false positives, recommendation, confidence
|
|
1127
|
+
"""
|
|
1128
|
+
`,
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
filename: "sales-nav-scout.toml",
|
|
1132
|
+
content: `name = "sales_nav_scout"
|
|
1133
|
+
description = "Sellable lead-source scout for Sales Navigator role, company, and activity filters."
|
|
1134
|
+
model_reasoning_effort = "medium"
|
|
1135
|
+
sandbox_mode = "read-only"
|
|
1136
|
+
nickname_candidates = ["Sales Nav Scout", "Role Filter Scout", "Activity Scout"]
|
|
1137
|
+
developer_instructions = """
|
|
1138
|
+
${commonPrefix}
|
|
1139
|
+
|
|
1140
|
+
Your lane is Sales Nav.
|
|
1141
|
+
|
|
1142
|
+
Use the inherited Sellable MCP tools when available:
|
|
1143
|
+
- get_provider_prompt for sales-nav before searching
|
|
1144
|
+
- lookup_sales_nav_filter before dynamic filters
|
|
1145
|
+
- search_sales_nav for campaignless preview searches
|
|
1146
|
+
|
|
1147
|
+
Process:
|
|
1148
|
+
1. Preserve target role names with CURRENT_TITLE lookups; do not rely on seniority alone when the brief names concrete roles.
|
|
1149
|
+
2. Build a broad-but-reasonable baseline from role/title, geography, company size, industry/account context, and recent LinkedIn activity when relevant.
|
|
1150
|
+
3. Run the baseline plus 1-2 refinements if the first pass is noisy or under-scaled.
|
|
1151
|
+
4. Verify filters actually applied: search URL contains filters, first-page rows match the intended lane, and result count does not look like an unfiltered pool.
|
|
1152
|
+
|
|
1153
|
+
Return:
|
|
1154
|
+
- exact filter recipe and lookup IDs used
|
|
1155
|
+
- raw result count, sampled people, good fits as n/N
|
|
1156
|
+
- estimated good-fit range after cleanup
|
|
1157
|
+
- directional acceptance/reply-rate ranges
|
|
1158
|
+
- sample leads, false positives, recommendation, confidence
|
|
1159
|
+
"""
|
|
1160
|
+
`,
|
|
1161
|
+
},
|
|
1162
|
+
{
|
|
1163
|
+
filename: "prospeo-contact-scout.toml",
|
|
1164
|
+
content: `name = "prospeo_contact_scout"
|
|
1165
|
+
description = "Sellable lead-source scout for Prospeo account/domain and broad contact expansion."
|
|
1166
|
+
model_reasoning_effort = "medium"
|
|
1167
|
+
sandbox_mode = "read-only"
|
|
1168
|
+
nickname_candidates = ["Prospeo Contact Scout", "Domain Scout", "Contact Scout"]
|
|
1169
|
+
developer_instructions = """
|
|
1170
|
+
${commonPrefix}
|
|
1171
|
+
|
|
1172
|
+
Your lane is Prospeo Contact.
|
|
1173
|
+
|
|
1174
|
+
Use the inherited Sellable MCP tools when available:
|
|
1175
|
+
- get_provider_prompt for prospeo before searching
|
|
1176
|
+
- load_csv_domains when the parent supplies a CSV or domain list and no domainFilterId exists
|
|
1177
|
+
- search_prospeo for campaignless people previews
|
|
1178
|
+
|
|
1179
|
+
Process:
|
|
1180
|
+
1. Identify whether this is domain/account targeting or broad persona expansion.
|
|
1181
|
+
2. For domain targeting, use or create the standalone domainFilterId before searching; never pass raw domains directly into search_prospeo.
|
|
1182
|
+
3. Run the narrowest useful Prospeo people preview and 1-2 refinements if quality or scale is unclear.
|
|
1183
|
+
4. Call out that Prospeo gives contact/account coverage but usually weaker LinkedIn intent than LinkedIn Engagement or Sales Nav activity slices.
|
|
1184
|
+
|
|
1185
|
+
Return:
|
|
1186
|
+
- mode and domain/account inputs
|
|
1187
|
+
- exact search recipe
|
|
1188
|
+
- raw result count, sampled people, good fits as n/N
|
|
1189
|
+
- estimated good-fit range after cleanup
|
|
1190
|
+
- directional reply-rate range
|
|
1191
|
+
- sample leads, false positives, recommendation, confidence
|
|
1192
|
+
"""
|
|
1193
|
+
`,
|
|
1194
|
+
},
|
|
1195
|
+
];
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1092
1198
|
function writeCodexPluginSkills(pluginRoot, opts) {
|
|
1093
1199
|
for (const skill of codexPluginSkills()) {
|
|
1094
1200
|
const skillRoot = join(pluginRoot, "skills", skill.dir);
|
|
@@ -1104,6 +1210,12 @@ function writeCodexPluginSkills(pluginRoot, opts) {
|
|
|
1104
1210
|
}
|
|
1105
1211
|
}
|
|
1106
1212
|
|
|
1213
|
+
function writeCodexCustomAgents(home, opts) {
|
|
1214
|
+
for (const agent of codexCustomAgents()) {
|
|
1215
|
+
writeFile(join(home, "agents", agent.filename), agent.content, opts);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1107
1219
|
function installCodexDesktopPlugin(opts) {
|
|
1108
1220
|
const home = codexHome();
|
|
1109
1221
|
const configPath = join(home, "config.toml");
|
|
@@ -1154,6 +1266,7 @@ function installCodexDesktopPlugin(opts) {
|
|
|
1154
1266
|
opts
|
|
1155
1267
|
);
|
|
1156
1268
|
writeCodexPluginSkills(pluginRoot, opts);
|
|
1269
|
+
writeCodexCustomAgents(home, opts);
|
|
1157
1270
|
|
|
1158
1271
|
if (!opts.dryRun) {
|
|
1159
1272
|
rmSync(cacheRoot, { recursive: true, force: true });
|
|
@@ -1220,6 +1333,7 @@ enabled = false`
|
|
|
1220
1333
|
logVerbose(
|
|
1221
1334
|
`${C.grey}+ enable [features].default_mode_request_user_input in ${configPath}${C.reset}`
|
|
1222
1335
|
);
|
|
1336
|
+
logVerbose(`${C.grey}+ write Codex custom scout agents in ${home}/agents${C.reset}`);
|
|
1223
1337
|
}
|
|
1224
1338
|
|
|
1225
1339
|
return {
|
|
@@ -1442,6 +1556,18 @@ function verify(opts) {
|
|
|
1442
1556
|
? "Codex skill bundle present"
|
|
1443
1557
|
: "Codex skill bundle missing",
|
|
1444
1558
|
});
|
|
1559
|
+
const codexAgentPaths = codexCustomAgents().map((agent) =>
|
|
1560
|
+
join(codexHome(), "agents", agent.filename)
|
|
1561
|
+
);
|
|
1562
|
+
const hasCodexScouts = codexAgentPaths.every((agentPath) =>
|
|
1563
|
+
existsSync(agentPath)
|
|
1564
|
+
);
|
|
1565
|
+
checks.push({
|
|
1566
|
+
ok: hasCodexScouts,
|
|
1567
|
+
label: hasCodexScouts
|
|
1568
|
+
? "Codex custom scout agents present"
|
|
1569
|
+
: "Codex custom scout agents missing",
|
|
1570
|
+
});
|
|
1445
1571
|
const configPath = join(codexHome(), "config.toml");
|
|
1446
1572
|
const configContent = existsSync(configPath)
|
|
1447
1573
|
? readFileSync(configPath, "utf8")
|
|
@@ -1592,6 +1718,7 @@ function printNextSteps(installedHosts, authReused) {
|
|
|
1592
1718
|
if (hasCodex) {
|
|
1593
1719
|
console.log(` ${C.green}✓${C.reset} Codex Desktop plugin installed`);
|
|
1594
1720
|
console.log(` ${C.green}✓${C.reset} Skills installed`);
|
|
1721
|
+
console.log(` ${C.green}✓${C.reset} Codex source scout agents installed`);
|
|
1595
1722
|
}
|
|
1596
1723
|
if (authReused) {
|
|
1597
1724
|
console.log(
|
package/package.json
CHANGED
|
@@ -99,10 +99,15 @@ denominator, and sample basis.
|
|
|
99
99
|
|
|
100
100
|
When the user has not supplied a source and multiple source angles are viable,
|
|
101
101
|
scout those angles as independent branches when the host can actually do it:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
LinkedIn Engagement / active post engagers (internal `signal-discovery`
|
|
103
|
+
provider prompt), Sales Nav / title + company filters, and Prospeo Contact /
|
|
104
|
+
domains only when relevant. In Codex, explicitly spawn the named custom scouts
|
|
105
|
+
`linkedin_engagement_scout`, `sales_nav_scout`, and `prospeo_contact_scout` for
|
|
106
|
+
the credible lanes; Codex does not infer subagent fan-out from generic source
|
|
107
|
+
comparison wording. In Claude Code, keep using the existing Task agents under
|
|
108
|
+
`.claude/agents/`. If the host runs them sequentially, do not claim they ran in
|
|
109
|
+
parallel. In chat, call the downstream copy stage `message generation`;
|
|
110
|
+
`message-validation.md` is only an internal proof artifact.
|
|
106
111
|
|
|
107
112
|
Use rendered Markdown for user review surfaces, not fenced code blocks. Keep
|
|
108
113
|
lines short, use indexed section labels and bullets, and translate internal
|