@sellable/install 0.1.76 → 0.1.78

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.
@@ -20,11 +20,11 @@ Required first steps:
20
20
  1. Read the three required inputs.
21
21
  2. Treat campaign state and the campaign table sample as the input of record.
22
22
  Disk files are context/debug aids, not durable state.
23
- 3. Use the embedded Message Review Fast Path below. Do not load the full
24
- long-form `generate-messages` subskill in the normal path. Load it only when
25
- the fast path is missing a needed campaign-specific rule, the user explicitly
26
- asks for deep calibration, or the first fast-path draft fails quality gates
27
- and no local reference explains how to repair it.
23
+ 3. Use the embedded Message Review Safety Gate below. Do not load the full
24
+ long-form `generate-messages` subskill in this `create-campaign-v2` path. If
25
+ a needed rule is missing or the draft fails quality gates, return
26
+ `revise-messaging` with the exact failure instead of pulling the long prompt
27
+ into this worker.
28
28
 
29
29
  Owned outputs:
30
30
 
@@ -46,8 +46,8 @@ Do not write or modify:
46
46
 
47
47
  Process:
48
48
 
49
- 1. Run the embedded fast-path workflow in dry mode from the approved brief,
50
- lead-review source decision, and `lead-sample.json`.
49
+ 1. Run the embedded message-review safety-gate workflow in dry mode from the
50
+ approved brief, lead-review source decision, and `lead-sample.json`.
51
51
  2. Use `lead-sample.json` as the only lead sample source. Do not fetch new
52
52
  prospects or invent richer row signals.
53
53
  3. Build proof inventory, token fill rules, token adherence, angle drafts,
@@ -69,7 +69,8 @@ Process:
69
69
  Return a concise final status with:
70
70
 
71
71
  - artifacts written
72
- - whether embedded fast-path rules were used or the full fallback was needed
72
+ - whether the embedded message-review safety-gate rules passed or returned
73
+ `revise-messaging`
73
74
  - lead sample basis used
74
75
  - proposed template and one sample message
75
76
  - selected winner summary
@@ -78,12 +79,12 @@ Return a concise final status with:
78
79
  Quality bar:
79
80
 
80
81
  - Do not synthesize a lightweight message from general knowledge. The artifact
81
- must prove the embedded fast-path workflow ran.
82
+ must prove the embedded message-review safety-gate workflow ran.
82
83
  - Message generation can start before `lead-filter.md`, but message review
83
84
  cannot start until the parent verifies the selected basis rows still pass the
84
85
  final filter.
85
86
 
86
- ## Embedded Message Review Fast Path
87
+ ## Embedded Message Review Safety Gate
87
88
 
88
89
  Use this campaign-launch subset to produce a truthful first-send message,
89
90
  rendered token examples, and a decision without loading the full long-form
@@ -843,15 +843,21 @@ updates.
843
843
  4. For message generation, use the \`post-find-leads-message-scout\` agent when
844
844
  available; its prompt carries the campaign-launch message rules. In the
845
845
  parent-thread fallback, load
846
- \`mcp__sellable__get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/message-review-fast-path.md" })\`.
846
+ \`mcp__sellable__get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/message-review-safety-gate.md" })\`.
847
+ Do not load the full long-form \`generate-messages\` subskill in this
848
+ create-campaign path; if the safety gate cannot safely approve the draft, route
849
+ to revise messaging with the concrete failure.
847
850
  Do not synthesize \`message-validation.md\` from the brief, lead review, or
848
851
  general knowledge.
849
- 5. Treat message quality as the gate before minting. Do not create a campaign,
850
- show a commit gate, or mint anything until \`message-validation.md\` proves
851
- the fast-path message workflow ran and \`message-review.md\` recommends
852
- \`approve-message\` against the gold-standard rules.
853
- 6. Do not create or mutate the live campaign until the approval gate returns
854
- \`approve\`.
852
+ 5. Create the campaign shell early with the v1 brief so the user can open the
853
+ watch link and see useful setup state immediately. Import only the first
854
+ bounded review batch after the source is attached to the campaign; do not
855
+ queue workflow cells, attach a sequence, or start until
856
+ \`message-validation.md\` proves the message-review safety-gate workflow ran,
857
+ \`message-review.md\` approves the template, rubrics are saved, and the
858
+ approved message set is synced into the campaign brief.
859
+ 6. Keep \`selectedLeadListId\` as the source list and \`workflowTableId\` as the
860
+ campaign table. Do not use disk files as the post-mint source of truth.
855
861
  7. Do not ask the user to run another command.
856
862
 
857
863
  ## Fallback
@@ -1121,15 +1127,24 @@ function agentTemplateRoot() {
1121
1127
 
1122
1128
  function loadCanonicalAgents() {
1123
1129
  const root = agentTemplateRoot();
1124
- const registry = JSON.parse(readFileSync(join(root, "registry.json"), "utf8"));
1130
+ const registry = JSON.parse(
1131
+ readFileSync(join(root, "registry.json"), "utf8")
1132
+ );
1125
1133
  if (!Array.isArray(registry.agents)) {
1126
1134
  throw new Error("Sellable agent registry is missing agents array.");
1127
1135
  }
1128
1136
 
1129
1137
  return registry.agents.map((agent) => {
1130
1138
  const promptPath = join(root, agent.promptFile || "");
1131
- if (!agent.id || !agent.name || !agent.promptFile || !existsSync(promptPath)) {
1132
- throw new Error(`Invalid Sellable agent registry entry: ${agent.id || "unknown"}`);
1139
+ if (
1140
+ !agent.id ||
1141
+ !agent.name ||
1142
+ !agent.promptFile ||
1143
+ !existsSync(promptPath)
1144
+ ) {
1145
+ throw new Error(
1146
+ `Invalid Sellable agent registry entry: ${agent.id || "unknown"}`
1147
+ );
1133
1148
  }
1134
1149
  if (agent.codex?.name && agent.codex.name !== agent.name) {
1135
1150
  throw new Error(
@@ -1165,6 +1180,15 @@ function legacyClaudeCustomAgents() {
1165
1180
  return loadCanonicalAgents().flatMap((agent) => agent.legacy?.claude || []);
1166
1181
  }
1167
1182
 
1183
+ function legacyClaudeCommands() {
1184
+ return [
1185
+ {
1186
+ name: "sellable-create-campaign",
1187
+ filename: join("sellable", "create-campaign.md"),
1188
+ },
1189
+ ];
1190
+ }
1191
+
1168
1192
  function tomlArray(values) {
1169
1193
  return `[${values.map((value) => quoteToml(value)).join(", ")}]`;
1170
1194
  }
@@ -1240,7 +1264,9 @@ function writeCodexCustomAgents(home, opts) {
1240
1264
  }
1241
1265
  for (const agent of legacyCodexCustomAgents()) {
1242
1266
  const legacyPath = join(home, "agents", agent.filename);
1243
- logVerbose(`${C.grey}Removing legacy Codex scout agent ${legacyPath}${C.reset}`);
1267
+ logVerbose(
1268
+ `${C.grey}Removing legacy Codex scout agent ${legacyPath}${C.reset}`
1269
+ );
1244
1270
  if (!opts.dryRun) rmSync(legacyPath, { force: true });
1245
1271
  }
1246
1272
  }
@@ -1256,9 +1282,22 @@ function writeClaudeCustomAgents(opts) {
1256
1282
  }
1257
1283
  for (const agent of legacyClaudeCustomAgents()) {
1258
1284
  const legacyPath = join(home, "agents", agent.filename);
1259
- logVerbose(`${C.grey}Removing legacy Claude scout agent ${legacyPath}${C.reset}`);
1285
+ logVerbose(
1286
+ `${C.grey}Removing legacy Claude scout agent ${legacyPath}${C.reset}`
1287
+ );
1260
1288
  if (!opts.dryRun) rmSync(legacyPath, { force: true });
1261
1289
  }
1290
+ removeLegacyClaudeCommands(home, opts);
1291
+ }
1292
+
1293
+ function removeLegacyClaudeCommands(home, opts) {
1294
+ for (const command of legacyClaudeCommands()) {
1295
+ const commandPath = join(home, "commands", command.filename);
1296
+ logVerbose(
1297
+ `${C.grey}Removing legacy Claude command ${commandPath}${C.reset}`
1298
+ );
1299
+ if (!opts.dryRun) rmSync(commandPath, { force: true });
1300
+ }
1262
1301
  }
1263
1302
 
1264
1303
  function installCodexDesktopPlugin(opts) {
@@ -1396,8 +1435,12 @@ config_file = ${quoteToml(join(home, "agents", agent.filename))}`
1396
1435
  logVerbose(
1397
1436
  `${C.grey}+ enable [features].default_mode_request_user_input in ${configPath}${C.reset}`
1398
1437
  );
1399
- logVerbose(`${C.grey}+ write Codex custom agents in ${home}/agents${C.reset}`);
1400
- logVerbose(`${C.grey}+ register Codex custom agents in ${configPath}${C.reset}`);
1438
+ logVerbose(
1439
+ `${C.grey}+ write Codex custom agents in ${home}/agents${C.reset}`
1440
+ );
1441
+ logVerbose(
1442
+ `${C.grey}+ register Codex custom agents in ${configPath}${C.reset}`
1443
+ );
1401
1444
  }
1402
1445
 
1403
1446
  return {
@@ -1607,6 +1650,23 @@ function verify(opts) {
1607
1650
  ? "Claude scout MCP tool allowlists present"
1608
1651
  : "Claude scout MCP tool allowlists missing",
1609
1652
  });
1653
+ const legacyClaudePaths = [
1654
+ ...legacyClaudeCustomAgents().map((agent) =>
1655
+ join(claudeHome(), "agents", agent.filename)
1656
+ ),
1657
+ ...legacyClaudeCommands().map((command) =>
1658
+ join(claudeHome(), "commands", command.filename)
1659
+ ),
1660
+ ];
1661
+ const hasNoLegacyClaudeArtifacts = legacyClaudePaths.every(
1662
+ (artifactPath) => !existsSync(artifactPath)
1663
+ );
1664
+ checks.push({
1665
+ ok: hasNoLegacyClaudeArtifacts,
1666
+ label: hasNoLegacyClaudeArtifacts
1667
+ ? "Legacy Claude Sellable host artifacts cleaned"
1668
+ : "Legacy Claude Sellable host artifacts still present",
1669
+ });
1610
1670
  }
1611
1671
  if (opts.host === "codex" || opts.host === "all") {
1612
1672
  checks.push({
@@ -1671,6 +1731,19 @@ function verify(opts) {
1671
1731
  ? "Codex custom scout agents registered"
1672
1732
  : "Codex custom scout agents unregistered",
1673
1733
  });
1734
+ const hasNoLegacyCodexAgents = legacyCodexCustomAgents().every((agent) => {
1735
+ const agentPath = join(codexHome(), "agents", agent.filename);
1736
+ return (
1737
+ !existsSync(agentPath) &&
1738
+ !configContent.includes(`[agents.${agent.name}]`)
1739
+ );
1740
+ });
1741
+ checks.push({
1742
+ ok: hasNoLegacyCodexAgents,
1743
+ label: hasNoLegacyCodexAgents
1744
+ ? "Legacy Codex custom scout agents cleaned"
1745
+ : "Legacy Codex custom scout agents still present",
1746
+ });
1674
1747
  const hasFlag = configContent.includes(
1675
1748
  "default_mode_request_user_input = true"
1676
1749
  );
@@ -1899,7 +1972,10 @@ function runUninstall() {
1899
1972
  after = removeTomlSection(after, "marketplaces.sellable");
1900
1973
  after = removeTomlSection(after, 'plugins."sellable@sellable"');
1901
1974
  after = removeTomlSection(after, 'plugins."sellable@sellable-local"');
1902
- for (const agent of [...codexCustomAgents(), ...legacyCodexCustomAgents()]) {
1975
+ for (const agent of [
1976
+ ...codexCustomAgents(),
1977
+ ...legacyCodexCustomAgents(),
1978
+ ]) {
1903
1979
  after = removeTomlSection(after, `agents.${agent.name}`);
1904
1980
  }
1905
1981
  // Collapse 3+ blank lines that the removals may leave behind.
@@ -1949,7 +2025,10 @@ function runUninstall() {
1949
2025
  skipped.push(`Claude Code CLI not found`);
1950
2026
  }
1951
2027
 
1952
- for (const agent of [...claudeCustomAgents(), ...legacyClaudeCustomAgents()]) {
2028
+ for (const agent of [
2029
+ ...claudeCustomAgents(),
2030
+ ...legacyClaudeCustomAgents(),
2031
+ ]) {
1953
2032
  const agentPath = join(claudeHome(), "agents", agent.filename);
1954
2033
  if (!existsSync(agentPath)) continue;
1955
2034
  try {
@@ -1961,6 +2040,18 @@ function runUninstall() {
1961
2040
  );
1962
2041
  }
1963
2042
  }
2043
+ for (const command of legacyClaudeCommands()) {
2044
+ const commandPath = join(claudeHome(), "commands", command.filename);
2045
+ if (!existsSync(commandPath)) continue;
2046
+ try {
2047
+ rmSync(commandPath, { force: true });
2048
+ removed.push(`${commandPath}`);
2049
+ } catch (err) {
2050
+ console.log(
2051
+ ` ${C.yellow}!${C.reset} Could not remove ${commandPath}: ${err instanceof Error ? err.message : String(err)}`
2052
+ );
2053
+ }
2054
+ }
1964
2055
 
1965
2056
  // 3) Surgical removal of Sellable-installed artifacts inside ~/.sellable/
1966
2057
  const sellableDir = join(homedir(), ".sellable");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.76",
3
+ "version": "0.1.78",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code and Codex",
6
6
  "bin": {
@@ -490,14 +490,17 @@ updates.
490
490
  4. For message generation, use the `post-find-leads-message-scout` agent when
491
491
  available; its prompt carries the campaign-launch message rules. In the
492
492
  parent-thread fallback, load
493
- `mcp__sellable__get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/message-review-fast-path.md" })`.
493
+ `mcp__sellable__get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/message-review-safety-gate.md" })`.
494
+ Do not load the full long-form `generate-messages` subskill in this
495
+ create-campaign path; if the safety gate cannot safely approve the draft,
496
+ route to revise messaging with the concrete failure.
494
497
  Do not synthesize `message-validation.md` from the brief, lead review, or
495
498
  general knowledge.
496
499
  5. Create the campaign shell early with the v1 brief so the user can open the
497
500
  watch link and see useful setup state immediately. Import only the first
498
501
  bounded review batch after the source is attached to the campaign; do not
499
502
  queue workflow cells, attach a sequence, or start until
500
- `message-validation.md` proves the fast-path message workflow ran,
503
+ `message-validation.md` proves the message-review safety-gate workflow ran,
501
504
  `message-review.md` approves the template, rubrics are saved, and the
502
505
  approved message set is synced into the campaign brief.
503
506
  6. Keep `selectedLeadListId` as the source list and `workflowTableId` as the