@sellable/install 0.1.211 → 0.1.212
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 +137 -64
- package/package.json +1 -1
- package/skill-templates/create-campaign.md +77 -32
package/bin/sellable-install.mjs
CHANGED
|
@@ -72,8 +72,9 @@ const CODEX_PLUGIN_COMPAT_VERSIONS = [
|
|
|
72
72
|
"0.1.40",
|
|
73
73
|
"0.1.41",
|
|
74
74
|
];
|
|
75
|
-
const
|
|
75
|
+
const RAW_INSTALL_PACKAGE_SPEC =
|
|
76
76
|
process.env.SELLABLE_INSTALL_PACKAGE_SPEC || "@sellable/install@latest";
|
|
77
|
+
const INSTALL_PACKAGE_SPEC = normalizeWindowsPackageSpec(RAW_INSTALL_PACKAGE_SPEC);
|
|
77
78
|
|
|
78
79
|
const useColor = Boolean(output.isTTY) && process.env.NO_COLOR === undefined;
|
|
79
80
|
const C = {
|
|
@@ -89,6 +90,15 @@ const C = {
|
|
|
89
90
|
|
|
90
91
|
let VERBOSE = false;
|
|
91
92
|
|
|
93
|
+
function normalizeWindowsPackageSpec(value) {
|
|
94
|
+
if (typeof value !== "string") return value;
|
|
95
|
+
if (/^[A-Za-z]:\//.test(value)) return value.replace(/\//g, "\\");
|
|
96
|
+
if (/^\/[A-Za-z]\//.test(value)) {
|
|
97
|
+
return `${value[1]}:${value.slice(2)}`.replace(/\//g, "\\");
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
|
|
92
102
|
function logVerbose(line) {
|
|
93
103
|
if (VERBOSE) console.log(line);
|
|
94
104
|
}
|
|
@@ -263,7 +273,7 @@ function parseArgs(argv) {
|
|
|
263
273
|
} else if (arg === "--api-url") {
|
|
264
274
|
opts.apiUrl = next();
|
|
265
275
|
} else if (arg === "--mcp-package") {
|
|
266
|
-
opts.mcpPackage = next();
|
|
276
|
+
opts.mcpPackage = normalizeWindowsPackageSpec(next());
|
|
267
277
|
} else if (arg === "--local-command") {
|
|
268
278
|
opts.localCommand = next();
|
|
269
279
|
} else if (arg === "--hosted-url") {
|
|
@@ -771,46 +781,54 @@ function codexSkillOpenAiYaml(displayName, description) {
|
|
|
771
781
|
`;
|
|
772
782
|
}
|
|
773
783
|
|
|
774
|
-
function
|
|
784
|
+
function installedHostContract(host, commandName) {
|
|
775
785
|
if (host === "codex") {
|
|
776
786
|
return `## Installed Host Contract
|
|
777
787
|
|
|
778
|
-
This installed skill is running in Codex.
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
\`mcp__sellable__bootstrap_create_campaign\` with \`host: "Codex"\` plus the
|
|
782
|
-
current Codex model and reasoning when available.
|
|
788
|
+
This installed skill is running in Codex. When the shared workflow body or
|
|
789
|
+
fallback text mentions both Claude Code and Codex for internal parity, choose
|
|
790
|
+
the Codex instruction for customer-facing language and host functions.
|
|
783
791
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
792
|
+
- Customer-facing command: \`$sellable:${commandName}\`
|
|
793
|
+
- Structured question function: \`request_user_input\`
|
|
794
|
+
- Bootstrap host label: \`host: "Codex"\`
|
|
795
|
+
- Install/reload blocker label: Codex install/reload problem
|
|
796
|
+
- Reload instruction: fully quit and reopen Codex Desktop, then start a new thread
|
|
787
797
|
|
|
798
|
+
Do not tell Codex users to run \`/sellable:${commandName}\`, use
|
|
799
|
+
\`AskUserQuestion\`, or restart Claude Code. Do not describe this run as Claude Code.`;
|
|
800
|
+
}
|
|
788
801
|
if (host === "claude") {
|
|
789
802
|
return `## Installed Host Contract
|
|
790
803
|
|
|
791
|
-
This installed command is running in Claude Code.
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
\`mcp__sellable__bootstrap_create_campaign\` with \`host: "Claude Code"\` plus
|
|
795
|
-
the current Claude Code model and reasoning when available.
|
|
804
|
+
This installed command is running in Claude Code. When the shared workflow body
|
|
805
|
+
or fallback text mentions both Claude Code and Codex for internal parity, choose
|
|
806
|
+
the Claude Code instruction for customer-facing language and host functions.
|
|
796
807
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
808
|
+
- Customer-facing command: \`/sellable:${commandName}\`
|
|
809
|
+
- Structured question function: \`AskUserQuestion\`
|
|
810
|
+
- Bootstrap host label: \`host: "Claude Code"\`
|
|
811
|
+
- Install/reload blocker label: Claude Code install/reload problem
|
|
812
|
+
- Reload instruction: fully quit and reopen Claude Code, then start a new session
|
|
800
813
|
|
|
814
|
+
Do not tell Claude Code users to run \`$sellable:${commandName}\`, use
|
|
815
|
+
\`request_user_input\`, or restart Codex Desktop. Do not describe this run as Codex.`;
|
|
816
|
+
}
|
|
801
817
|
return "";
|
|
802
818
|
}
|
|
803
819
|
|
|
804
|
-
function
|
|
805
|
-
const
|
|
806
|
-
if (!
|
|
820
|
+
function stampInstalledHost(markdown, host, commandName) {
|
|
821
|
+
const preamble = installedHostContract(host, commandName);
|
|
822
|
+
if (!preamble || markdown.includes("## Installed Host Contract")) {
|
|
823
|
+
return markdown;
|
|
824
|
+
}
|
|
807
825
|
return String(markdown).replace(
|
|
808
|
-
|
|
809
|
-
|
|
826
|
+
/(^# .+\n\n)/m,
|
|
827
|
+
`$1${preamble}\n\n`
|
|
810
828
|
);
|
|
811
829
|
}
|
|
812
830
|
|
|
813
|
-
function createCampaignSkillMd(
|
|
831
|
+
function createCampaignSkillMd(host = "shared") {
|
|
814
832
|
// Single source of truth: ../skill-templates/create-campaign.md, which is
|
|
815
833
|
// copied from the canonical mcp/sellable/skills/create-campaign/SKILL.md at
|
|
816
834
|
// publish time via scripts/sync-skill-templates.mjs (prepublishOnly hook).
|
|
@@ -825,15 +843,16 @@ function createCampaignSkillMd({ host = "shared" } = {}) {
|
|
|
825
843
|
"create-campaign.md"
|
|
826
844
|
);
|
|
827
845
|
if (existsSync(templatePath)) {
|
|
828
|
-
return
|
|
846
|
+
return stampInstalledHost(
|
|
829
847
|
readFileSync(templatePath, "utf8"),
|
|
830
|
-
host
|
|
848
|
+
host,
|
|
849
|
+
"create-campaign"
|
|
831
850
|
);
|
|
832
851
|
}
|
|
833
852
|
} catch {
|
|
834
853
|
// fall through to hardcoded fallback below
|
|
835
854
|
}
|
|
836
|
-
return `---
|
|
855
|
+
return stampInstalledHost(`---
|
|
837
856
|
name: create-campaign
|
|
838
857
|
description: Create a Sellable campaign through the approval-gated workflow.
|
|
839
858
|
allowed-tools:
|
|
@@ -856,17 +875,11 @@ person/company this campaign is for, then I’ll turn that into a campaign brief
|
|
|
856
875
|
before anything is created.
|
|
857
876
|
\`\`\`
|
|
858
877
|
|
|
859
|
-
Exception: if \`bootstrap_create_campaign.modelQuality.status === "warn"
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
message generation, or launch review. If \`metadataStale === true\`, continue
|
|
865
|
-
normally and do not ask the user to switch.
|
|
866
|
-
|
|
867
|
-
If \`bootstrap_create_campaign.modelQuality.metadataStale === true\`, continue
|
|
868
|
-
normally. Do not ask the user to switch models; this is an accepted Codex host
|
|
869
|
-
metadata mismatch.
|
|
878
|
+
Exception: if \`bootstrap_create_campaign.modelQuality.status === "warn"\`, the
|
|
879
|
+
first visible campaign message must be the model-quality warning from
|
|
880
|
+
\`modelQuality.message\`. Only trust that warning when bootstrap received active
|
|
881
|
+
turn/runtime metadata or an explicit user-confirmed model. Do not warn from
|
|
882
|
+
config defaults, stale host labels, or inferred model names.
|
|
870
883
|
|
|
871
884
|
If a linked/local skill file is stale or missing, silently use the installed
|
|
872
885
|
\`sellable@sellable\` plugin copy. Do not tell the user about the stale link,
|
|
@@ -884,6 +897,56 @@ clear business decisions, tradeoffs, and approval gates. Use product language:
|
|
|
884
897
|
- "I can create a draft shell for you to watch with approval gates before
|
|
885
898
|
sourcing", not mutation jargon
|
|
886
899
|
|
|
900
|
+
## Active Model Metadata
|
|
901
|
+
|
|
902
|
+
Before calling \`bootstrap_create_campaign\`, collect the active host model data
|
|
903
|
+
only from a source that can describe this turn:
|
|
904
|
+
|
|
905
|
+
- Codex: if \`mcp__node_repl__js\` is available, inspect only
|
|
906
|
+
\`nodeRepl.requestMeta["x-codex-turn-metadata"].model\` and
|
|
907
|
+
\`nodeRepl.requestMeta["x-codex-turn-metadata"].reasoning_effort\`. Pass those
|
|
908
|
+
values as \`model\` and \`reasoningEffort\`, with
|
|
909
|
+
\`modelMetadataSource: "codex_turn_metadata"\`.
|
|
910
|
+
- Codex fallback/cross-check: if active turn metadata is unavailable, you may
|
|
911
|
+
inspect \`~/.codex/config.toml\` for \`model\` and
|
|
912
|
+
\`model_reasoning_effort\`, but pass
|
|
913
|
+
\`modelMetadataSource: "codex_config_fallback"\` and do not treat it as a
|
|
914
|
+
reason to ask the user to switch models. Active turn metadata wins if it
|
|
915
|
+
differs from config.
|
|
916
|
+
- Claude Code / Opus: use active Claude runtime metadata only if the current
|
|
917
|
+
host exposes model and effort for this same session, with
|
|
918
|
+
\`modelMetadataSource: "claude_runtime_metadata"\`. Current Claude Code MCP
|
|
919
|
+
tool calls may not include model or effort metadata; when they do not, omit
|
|
920
|
+
\`model\`, \`reasoningEffort\`, and \`modelMetadataSource\`.
|
|
921
|
+
- Claude Code session-context self-report: if your current Claude session
|
|
922
|
+
context explicitly states both the exact model ID and effort/thinking level,
|
|
923
|
+
report it internally in this shape and pass it to bootstrap with
|
|
924
|
+
\`modelMetadataSource: "claude_session_context"\`:
|
|
925
|
+
|
|
926
|
+
\`\`\`text
|
|
927
|
+
- Model (name): ...
|
|
928
|
+
- Model (ID): ...
|
|
929
|
+
- Reasoning effort: ...
|
|
930
|
+
- Source: active Claude Code session context
|
|
931
|
+
\`\`\`
|
|
932
|
+
|
|
933
|
+
Use this only when the values are explicitly present in the current session
|
|
934
|
+
context. Do not infer an ID from the friendly name, do not infer effort from
|
|
935
|
+
\`alwaysThinkingEnabled\`, and do not show this self-report to the user during
|
|
936
|
+
normal campaign setup.
|
|
937
|
+
- Do not run a nested \`claude -p\`, inspect \`~/.claude/settings.json\`, or read
|
|
938
|
+
Claude CLI defaults as proof of the user's active Claude Code session. Those
|
|
939
|
+
checks can validate a new child session or saved defaults, but not this
|
|
940
|
+
session's actual model and effort.
|
|
941
|
+
- If the user explicitly provides active Claude \`/status\` or \`/model\` output
|
|
942
|
+
that includes both model and effort, pass it with
|
|
943
|
+
\`modelMetadataSource: "user_confirmed"\`. If it is missing either model or
|
|
944
|
+
effort, treat the metadata as unknown and continue.
|
|
945
|
+
|
|
946
|
+
Never invent the model or reasoning effort. Never pass config defaults as active
|
|
947
|
+
metadata. If bootstrap returns \`modelQuality.status === "unknown"\`, continue
|
|
948
|
+
without asking the user to switch models.
|
|
949
|
+
|
|
887
950
|
When explaining source decisions, show the concrete counts behind the
|
|
888
951
|
logic: lanes searched, timeframe, raw result counts, finalist posts or preview
|
|
889
952
|
rows, sampled people, sampled fits as n/N (%), estimated usable people, and the
|
|
@@ -1305,13 +1368,19 @@ updates.
|
|
|
1305
1368
|
- Do not call \`mcp__sellable__get_campaigns\`.
|
|
1306
1369
|
- Do not call \`mcp__sellable__get_campaign\` to hunt for IDs.
|
|
1307
1370
|
- Do not call \`mcp__sellable__create_campaign({ campaignId: ... })\` unless the user supplied that id.
|
|
1308
|
-
5. Call \`mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort? })\`.
|
|
1309
|
-
Pass
|
|
1371
|
+
5. Call \`mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort?, modelMetadataSource? })\`.
|
|
1372
|
+
Pass model metadata only when collected by the Active Model Metadata rules
|
|
1373
|
+
above. For Codex active turn metadata, pass
|
|
1374
|
+
\`modelMetadataSource: "codex_turn_metadata"\`. For explicit Claude session
|
|
1375
|
+
context, pass \`modelMetadataSource: "claude_session_context"\`. For explicit
|
|
1376
|
+
user-confirmed Claude \`/status\` or \`/model\` output, pass
|
|
1377
|
+
\`modelMetadataSource: "user_confirmed"\` only when it includes both model and
|
|
1378
|
+
effort.
|
|
1310
1379
|
6. If \`safeToProceed !== true\`, stop and show \`blockingErrors\` + \`nextStep\`.
|
|
1311
|
-
7. If \`modelQuality.status === "warn"
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1380
|
+
7. If \`modelQuality.status === "warn"\`, show \`modelQuality.message\` before
|
|
1381
|
+
any setup/research and wait for the user to switch or explicitly continue. If
|
|
1382
|
+
\`modelQuality.status === "unknown"\`, continue; do not tell the user to
|
|
1383
|
+
switch models.
|
|
1315
1384
|
|
|
1316
1385
|
## Execute Workflow
|
|
1317
1386
|
|
|
@@ -1392,10 +1461,10 @@ updates.
|
|
|
1392
1461
|
If subskill lookup fails, use
|
|
1393
1462
|
\`mcp__sellable__search_subskill_prompts({ query: "create-campaign-v2" })\`,
|
|
1394
1463
|
then retry \`get_subskill_prompt\`.
|
|
1395
|
-
|
|
1464
|
+
`, host, "create-campaign");
|
|
1396
1465
|
}
|
|
1397
1466
|
|
|
1398
|
-
function createAbTestSkillMd() {
|
|
1467
|
+
function createAbTestSkillMd(host = "shared") {
|
|
1399
1468
|
try {
|
|
1400
1469
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
1401
1470
|
const templatePath = join(
|
|
@@ -1405,12 +1474,16 @@ function createAbTestSkillMd() {
|
|
|
1405
1474
|
"create-ab-test.md"
|
|
1406
1475
|
);
|
|
1407
1476
|
if (existsSync(templatePath)) {
|
|
1408
|
-
return
|
|
1477
|
+
return stampInstalledHost(
|
|
1478
|
+
readFileSync(templatePath, "utf8"),
|
|
1479
|
+
host,
|
|
1480
|
+
"create-ab-test"
|
|
1481
|
+
);
|
|
1409
1482
|
}
|
|
1410
1483
|
} catch {
|
|
1411
1484
|
// fall through to hardcoded fallback below
|
|
1412
1485
|
}
|
|
1413
|
-
return `---
|
|
1486
|
+
return stampInstalledHost(`---
|
|
1414
1487
|
name: create-ab-test
|
|
1415
1488
|
description: Create a Sellable campaign A/B test from a clean source lead list.
|
|
1416
1489
|
visibility: public
|
|
@@ -1426,11 +1499,11 @@ allowed-tools:
|
|
|
1426
1499
|
# Sellable Create A/B Test
|
|
1427
1500
|
|
|
1428
1501
|
Use \`prepare_campaign_ab_test\` to create clean A/B split lead lists and review-copy campaigns. Do not call \`export_table_csv\` from generated campaign workflow tables as lead source data, and do not call \`start_campaign\`.
|
|
1429
|
-
|
|
1502
|
+
`, host, "create-ab-test");
|
|
1430
1503
|
}
|
|
1431
1504
|
|
|
1432
|
-
function genericSellableSkillMd({ name, title, description }) {
|
|
1433
|
-
return `---
|
|
1505
|
+
function genericSellableSkillMd({ name, title, description, host = "shared" }) {
|
|
1506
|
+
return stampInstalledHost(`---
|
|
1434
1507
|
name: ${name}
|
|
1435
1508
|
description: ${yamlString(description)}
|
|
1436
1509
|
allowed-tools:
|
|
@@ -1465,11 +1538,11 @@ Desktop, then start a new thread.
|
|
|
1465
1538
|
## MCP Prompt Fallback
|
|
1466
1539
|
|
|
1467
1540
|
If subskill lookup fails, use \`mcp__sellable__search_subskill_prompts({ query: "${name}" })\`, then retry \`get_subskill_prompt\`.
|
|
1468
|
-
|
|
1541
|
+
`, host, name);
|
|
1469
1542
|
}
|
|
1470
1543
|
|
|
1471
|
-
function foundationSkillMd() {
|
|
1472
|
-
return `---
|
|
1544
|
+
function foundationSkillMd(host = "shared") {
|
|
1545
|
+
return stampInstalledHost(`---
|
|
1473
1546
|
name: foundation
|
|
1474
1547
|
description: ${yamlString(FOUNDATION_SKILL_DESCRIPTION)}
|
|
1475
1548
|
allowed-tools:
|
|
@@ -1528,11 +1601,11 @@ Desktop, then start a new thread.
|
|
|
1528
1601
|
If exact subskill lookup fails, use
|
|
1529
1602
|
\`mcp__sellable__search_subskill_prompts({ query: "foundation", includePublic: true, includeInternal: true })\`,
|
|
1530
1603
|
then retry \`get_subskill_prompt\`.
|
|
1531
|
-
|
|
1604
|
+
`, host, "foundation");
|
|
1532
1605
|
}
|
|
1533
1606
|
|
|
1534
|
-
function contentSkillMd() {
|
|
1535
|
-
return `---
|
|
1607
|
+
function contentSkillMd(host = "shared") {
|
|
1608
|
+
return stampInstalledHost(`---
|
|
1536
1609
|
name: content
|
|
1537
1610
|
description: Add transcripts and rough ideas, cluster recurring themes, ideate post seeds, and hand draft requests to create-post.
|
|
1538
1611
|
allowed-tools:
|
|
@@ -1598,11 +1671,11 @@ Desktop, then start a new thread.
|
|
|
1598
1671
|
If exact subskill lookup fails, use
|
|
1599
1672
|
\`mcp__sellable__search_subskill_prompts({ query: "content", includePublic: true, includeInternal: true })\`,
|
|
1600
1673
|
then retry \`get_subskill_prompt\`.
|
|
1601
|
-
|
|
1674
|
+
`, host, "content");
|
|
1602
1675
|
}
|
|
1603
1676
|
|
|
1604
|
-
function createPostSkillMd() {
|
|
1605
|
-
return `---
|
|
1677
|
+
function createPostSkillMd(host = "shared") {
|
|
1678
|
+
return stampInstalledHost(`---
|
|
1606
1679
|
name: create-post
|
|
1607
1680
|
description: Capture rough LinkedIn post ideas, develop a valuable premise, research current hooks and audience tension, then save validated drafts in the user's voice.
|
|
1608
1681
|
allowed-tools:
|
|
@@ -1672,7 +1745,7 @@ Desktop, then start a new thread.
|
|
|
1672
1745
|
If exact subskill lookup fails, use
|
|
1673
1746
|
\`mcp__sellable__search_subskill_prompts({ query: "create-post", includePublic: true, includeInternal: true })\`,
|
|
1674
1747
|
then retry \`get_subskill_prompt\`.
|
|
1675
|
-
|
|
1748
|
+
`, host, "create-post");
|
|
1676
1749
|
}
|
|
1677
1750
|
|
|
1678
1751
|
function createCampaignSoulMd() {
|
|
@@ -1869,7 +1942,7 @@ function codexPluginSkills() {
|
|
|
1869
1942
|
dir: "sellable-create-campaign",
|
|
1870
1943
|
displayName: "Sellable Create Campaign",
|
|
1871
1944
|
description: "Create a Sellable campaign with approval gates",
|
|
1872
|
-
skillMd: createCampaignSkillMd(
|
|
1945
|
+
skillMd: createCampaignSkillMd("codex"),
|
|
1873
1946
|
soulMd: createCampaignSoulMd(),
|
|
1874
1947
|
},
|
|
1875
1948
|
{
|
|
@@ -2093,7 +2166,7 @@ function claudeCommands() {
|
|
|
2093
2166
|
filename: join("sellable", "create-campaign.md"),
|
|
2094
2167
|
description: "Create a Sellable campaign through the approval-gated workflow.",
|
|
2095
2168
|
argumentHint: "[campaign goal, company, or offer]",
|
|
2096
|
-
skillMd: createCampaignSkillMd(
|
|
2169
|
+
skillMd: createCampaignSkillMd("claude"),
|
|
2097
2170
|
allowedTools: ["AskUserQuestion", "Task", ...CREATE_CAMPAIGN_ALLOWED_TOOLS],
|
|
2098
2171
|
},
|
|
2099
2172
|
{
|
package/package.json
CHANGED
|
@@ -179,17 +179,11 @@ person/company this campaign is for, then I’ll turn that into a campaign brief
|
|
|
179
179
|
before we move into lead sourcing.
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
Exception: if `bootstrap_create_campaign.modelQuality.status === "warn"
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
message generation, or launch review. If `metadataStale === true`, continue
|
|
188
|
-
normally and do not ask the user to switch.
|
|
189
|
-
|
|
190
|
-
If `bootstrap_create_campaign.modelQuality.metadataStale === true`, continue
|
|
191
|
-
normally. Do not ask the user to switch models; this is an accepted Codex host
|
|
192
|
-
metadata mismatch.
|
|
182
|
+
Exception: if `bootstrap_create_campaign.modelQuality.status === "warn"`, the
|
|
183
|
+
first visible campaign message must be the model-quality warning from
|
|
184
|
+
`modelQuality.message`. Only trust that warning when bootstrap received active
|
|
185
|
+
turn/runtime metadata or an explicit user-confirmed model. Do not warn from
|
|
186
|
+
config defaults, stale host labels, or inferred model names.
|
|
193
187
|
|
|
194
188
|
If a linked/local skill file is stale or missing, silently use the installed
|
|
195
189
|
`sellable@sellable` plugin copy. Do not tell the user about the stale link,
|
|
@@ -207,6 +201,55 @@ clear business decisions, tradeoffs, and approval gates. Use product language:
|
|
|
207
201
|
- "I can create a draft shell for you to watch with approval gates before
|
|
208
202
|
sourcing", not mutation jargon
|
|
209
203
|
|
|
204
|
+
## Active Model Metadata
|
|
205
|
+
|
|
206
|
+
Before calling `bootstrap_create_campaign`, collect the active host model data
|
|
207
|
+
only from a source that can describe this turn:
|
|
208
|
+
|
|
209
|
+
- Codex: if `mcp__node_repl__js` is available, inspect only
|
|
210
|
+
`nodeRepl.requestMeta["x-codex-turn-metadata"].model` and
|
|
211
|
+
`nodeRepl.requestMeta["x-codex-turn-metadata"].reasoning_effort`. Pass those
|
|
212
|
+
values as `model` and `reasoningEffort`, with
|
|
213
|
+
`modelMetadataSource: "codex_turn_metadata"`.
|
|
214
|
+
- Codex fallback/cross-check: if active turn metadata is unavailable, you may
|
|
215
|
+
inspect `~/.codex/config.toml` for `model` and `model_reasoning_effort`, but
|
|
216
|
+
pass `modelMetadataSource: "codex_config_fallback"` and do not treat it as a
|
|
217
|
+
reason to ask the user to switch models. Active turn metadata wins if it
|
|
218
|
+
differs from config.
|
|
219
|
+
- Claude Code / Opus: use active Claude runtime metadata only if the current
|
|
220
|
+
host exposes model and effort for this same session, with
|
|
221
|
+
`modelMetadataSource: "claude_runtime_metadata"`. Current Claude Code MCP
|
|
222
|
+
tool calls may not include model or effort metadata; when they do not, omit
|
|
223
|
+
`model`, `reasoningEffort`, and `modelMetadataSource`.
|
|
224
|
+
- Claude Code session-context self-report: if your current Claude session
|
|
225
|
+
context explicitly states both the exact model ID and effort/thinking level,
|
|
226
|
+
report it internally in this shape and pass it to bootstrap with
|
|
227
|
+
`modelMetadataSource: "claude_session_context"`:
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
- Model (name): ...
|
|
231
|
+
- Model (ID): ...
|
|
232
|
+
- Reasoning effort: ...
|
|
233
|
+
- Source: active Claude Code session context
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Use this only when the values are explicitly present in the current session
|
|
237
|
+
context. Do not infer an ID from the friendly name, do not infer effort from
|
|
238
|
+
`alwaysThinkingEnabled`, and do not show this self-report to the user during
|
|
239
|
+
normal campaign setup.
|
|
240
|
+
- Do not run a nested `claude -p`, inspect `~/.claude/settings.json`, or read
|
|
241
|
+
Claude CLI defaults as proof of the user's active Claude Code session. Those
|
|
242
|
+
checks can validate a new child session or saved defaults, but not this
|
|
243
|
+
session's actual model and effort.
|
|
244
|
+
- If the user explicitly provides active Claude `/status` or `/model` output
|
|
245
|
+
that includes both model and effort, pass it with
|
|
246
|
+
`modelMetadataSource: "user_confirmed"`. If it is missing either model or
|
|
247
|
+
effort, treat the metadata as unknown and continue.
|
|
248
|
+
|
|
249
|
+
Never invent the model or reasoning effort. Never pass config defaults as active
|
|
250
|
+
metadata. If bootstrap returns `modelQuality.status === "unknown"`, continue
|
|
251
|
+
without asking the user to switch models.
|
|
252
|
+
|
|
210
253
|
Approval and safety copy should be tasteful. State what the current approval
|
|
211
254
|
covers once, in one short sentence, then move on. Do not append repeated
|
|
212
255
|
"nothing starts / no leads import / no sending" disclaimers to routine progress
|
|
@@ -775,10 +818,9 @@ messages, and wait for final launch approval.
|
|
|
775
818
|
What's your LinkedIn profile URL or handle?
|
|
776
819
|
```
|
|
777
820
|
|
|
778
|
-
|
|
779
|
-
`request_user_input` is unavailable in an interactive
|
|
780
|
-
|
|
781
|
-
In Codex, stop and tell the user:
|
|
821
|
+
Do not silently ask Codex intake or approval questions as plain chat when
|
|
822
|
+
`request_user_input` is unavailable in an interactive session. Stop and tell
|
|
823
|
+
the user:
|
|
782
824
|
|
|
783
825
|
```text
|
|
784
826
|
I need Codex’s quick question panel to collect campaign inputs and approvals cleanly.
|
|
@@ -817,18 +859,17 @@ there.
|
|
|
817
859
|
## Bootstrap
|
|
818
860
|
|
|
819
861
|
MCP tool access is required. First call `mcp__sellable__get_auth_status({})`
|
|
820
|
-
directly. If that tool is unavailable, stop and say this is a
|
|
821
|
-
install/reload problem
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
want an agent-readable checklist, tell them:
|
|
862
|
+
directly. If that tool is unavailable, stop and say this is a Codex
|
|
863
|
+
install/reload problem, not a campaign problem. Tell the user to
|
|
864
|
+
run `curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh` so the
|
|
865
|
+
packaged MCP server, Codex Desktop plugin, and Sellable skill bundle are
|
|
866
|
+
installed. If they want an agent-readable checklist, tell them:
|
|
825
867
|
`Install Sellable CLI and skills using https://app.sellable.dev/agent-install.txt`.
|
|
826
868
|
For CLI verification, tell them to run
|
|
827
869
|
`sellable --verify-only --host all --json --artifact "$HOME/.local/sellable/app-sellable-dev/installer/.last-verify.json"`.
|
|
828
|
-
After that, they must fully quit and reopen
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
harness as a fallback for this interactive skill.
|
|
870
|
+
After that, they must fully quit and reopen Codex Desktop before starting a new
|
|
871
|
+
thread. Do not use `scripts/mcp/sellable-tool-call.mjs`, `npm run`, `node`, or
|
|
872
|
+
any local harness as a fallback for this interactive skill.
|
|
832
873
|
Do not mention prompt loading, local skill files, missing linked versions,
|
|
833
874
|
plugin cache paths, MCP namespaces, or runbooks in customer-facing progress
|
|
834
875
|
updates.
|
|
@@ -940,15 +981,19 @@ updates.
|
|
|
940
981
|
- Do not call `mcp__sellable__get_campaigns`.
|
|
941
982
|
- Do not call `mcp__sellable__get_campaign` to hunt for IDs.
|
|
942
983
|
- Do not call `mcp__sellable__create_campaign({ campaignId: ... })` unless the user supplied that id.
|
|
943
|
-
6. Call `mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host
|
|
944
|
-
Pass
|
|
945
|
-
|
|
946
|
-
|
|
984
|
+
6. Call `mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort?, modelMetadataSource? })`.
|
|
985
|
+
Pass model metadata only when collected by the Active Model Metadata rules
|
|
986
|
+
above. For Codex active turn metadata, pass
|
|
987
|
+
`modelMetadataSource: "codex_turn_metadata"`. For explicit Claude session
|
|
988
|
+
context, pass `modelMetadataSource: "claude_session_context"`. For explicit
|
|
989
|
+
user-confirmed Claude `/status` or `/model` output, pass
|
|
990
|
+
`modelMetadataSource: "user_confirmed"` only when it includes both model and
|
|
991
|
+
effort.
|
|
947
992
|
7. If `safeToProceed !== true`, stop and show `blockingErrors` + `nextStep`.
|
|
948
|
-
8. If `modelQuality.status === "warn"
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
993
|
+
8. If `modelQuality.status === "warn"`, show `modelQuality.message` before any
|
|
994
|
+
setup/research and wait for the user to switch or explicitly continue. If
|
|
995
|
+
`modelQuality.status === "unknown"`, continue; do not tell the user to
|
|
996
|
+
switch models.
|
|
952
997
|
|
|
953
998
|
## Execute Workflow
|
|
954
999
|
|