@sellable/mcp 0.1.0
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/.claude-plugin/plugin.json +12 -0
- package/.mcp.json +9 -0
- package/README.md +355 -0
- package/dist/api.d.ts +21 -0
- package/dist/api.js +73 -0
- package/dist/auth.d.ts +60 -0
- package/dist/auth.js +246 -0
- package/dist/engage-memory.d.ts +63 -0
- package/dist/engage-memory.js +354 -0
- package/dist/index-dev.d.ts +2 -0
- package/dist/index-dev.js +17 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +499 -0
- package/dist/skills.d.ts +11 -0
- package/dist/skills.js +97 -0
- package/dist/tools/auth.d.ts +30 -0
- package/dist/tools/auth.js +124 -0
- package/dist/tools/blueprint-commit.d.ts +174 -0
- package/dist/tools/blueprint-commit.js +286 -0
- package/dist/tools/bootstrap.d.ts +64 -0
- package/dist/tools/bootstrap.js +246 -0
- package/dist/tools/campaigns.d.ts +589 -0
- package/dist/tools/campaigns.js +892 -0
- package/dist/tools/cells.d.ts +58 -0
- package/dist/tools/cells.js +48 -0
- package/dist/tools/context.d.ts +88 -0
- package/dist/tools/context.js +271 -0
- package/dist/tools/csv-domains.d.ts +73 -0
- package/dist/tools/csv-domains.js +464 -0
- package/dist/tools/csv-linkedin.d.ts +102 -0
- package/dist/tools/csv-linkedin.js +712 -0
- package/dist/tools/direct-campaigns.d.ts +240 -0
- package/dist/tools/direct-campaigns.js +250 -0
- package/dist/tools/engage-bootstrap.d.ts +94 -0
- package/dist/tools/engage-bootstrap.js +205 -0
- package/dist/tools/engage-discovery.d.ts +78 -0
- package/dist/tools/engage-discovery.js +150 -0
- package/dist/tools/engage-memory.d.ts +181 -0
- package/dist/tools/engage-memory.js +143 -0
- package/dist/tools/engage-state.d.ts +72 -0
- package/dist/tools/engage-state.js +62 -0
- package/dist/tools/enrichment.d.ts +167 -0
- package/dist/tools/enrichment.js +174 -0
- package/dist/tools/flow-preflight.d.ts +68 -0
- package/dist/tools/flow-preflight.js +138 -0
- package/dist/tools/framework.d.ts +44 -0
- package/dist/tools/framework.js +153 -0
- package/dist/tools/interaction-mode.d.ts +27 -0
- package/dist/tools/interaction-mode.js +102 -0
- package/dist/tools/leads.d.ts +2417 -0
- package/dist/tools/leads.js +2307 -0
- package/dist/tools/linkedin.d.ts +210 -0
- package/dist/tools/linkedin.js +229 -0
- package/dist/tools/navigation.d.ts +91 -0
- package/dist/tools/navigation.js +381 -0
- package/dist/tools/one-off.d.ts +229 -0
- package/dist/tools/one-off.js +273 -0
- package/dist/tools/processing.d.ts +70 -0
- package/dist/tools/processing.js +56 -0
- package/dist/tools/prompts.d.ts +211 -0
- package/dist/tools/prompts.js +210 -0
- package/dist/tools/provider-preflight.d.ts +21 -0
- package/dist/tools/provider-preflight.js +59 -0
- package/dist/tools/readiness.d.ts +261 -0
- package/dist/tools/readiness.js +510 -0
- package/dist/tools/rows.d.ts +126 -0
- package/dist/tools/rows.js +105 -0
- package/dist/tools/rubrics.d.ts +497 -0
- package/dist/tools/rubrics.js +681 -0
- package/dist/tools/senders.d.ts +44 -0
- package/dist/tools/senders.js +69 -0
- package/dist/tools/sequencer.d.ts +127 -0
- package/dist/tools/sequencer.js +194 -0
- package/dist/tools/tables.d.ts +35 -0
- package/dist/tools/tables.js +36 -0
- package/dist/tools/verify-row.d.ts +36 -0
- package/dist/tools/verify-row.js +38 -0
- package/dist/tools/workspaces.d.ts +140 -0
- package/dist/tools/workspaces.js +139 -0
- package/dist/utils/workspace-root.d.ts +1 -0
- package/dist/utils/workspace-root.js +39 -0
- package/package.json +46 -0
- package/skills/building-gtm-tables/SKILL.md +216 -0
- package/skills/building-gtm-tables/core/auto-execute.yaml +19 -0
- package/skills/building-gtm-tables/core/blueprint-schema.json +72 -0
- package/skills/building-gtm-tables/references/brief-to-blueprint.md +334 -0
- package/skills/building-gtm-tables/references/column-type-catalog.md +318 -0
- package/skills/building-gtm-tables/references/common-blueprints.fixtures.ts +199 -0
- package/skills/building-gtm-tables/references/common-blueprints.md +44 -0
- package/skills/building-gtm-tables/references/failure-taxonomy.md +197 -0
- package/skills/building-gtm-tables/references/uat-seed-prompts.md +37 -0
- package/skills/building-gtm-tables/references/verify-loop.md +74 -0
- package/skills/campaign-messages/SKILL.md +173 -0
- package/skills/campaign-messages/flow.v1.json +75 -0
- package/skills/craft-message/SKILL.md +401 -0
- package/skills/create-campaign/ARCHITECTURE.md +232 -0
- package/skills/create-campaign/DISCUSS.md +296 -0
- package/skills/create-campaign/FLOW_ASCII.md +240 -0
- package/skills/create-campaign/HOST-PARITY-CHECKLIST.md +49 -0
- package/skills/create-campaign/README.md +142 -0
- package/skills/create-campaign/SKILL.md +286 -0
- package/skills/create-campaign/context/README.md +67 -0
- package/skills/create-campaign/context/_TEMPLATE.md +12 -0
- package/skills/create-campaign/context/context.md +35 -0
- package/skills/create-campaign/context/learnings.md +16 -0
- package/skills/create-campaign/context/registry.json +19 -0
- package/skills/create-campaign/core/flow.v1.json +217 -0
- package/skills/create-campaign/core/policy.md +191 -0
- package/skills/create-campaign/core/providers/apollo.json +35 -0
- package/skills/create-campaign/core/providers/prospeo.json +34 -0
- package/skills/create-campaign/core/providers/registry.json +31 -0
- package/skills/create-campaign/core/providers/sales-nav.json +37 -0
- package/skills/create-campaign/core/providers/signal-discovery.json +42 -0
- package/skills/create-campaign/references/brief-template.md +64 -0
- package/skills/create-campaign/references/campaign-quality.md +84 -0
- package/skills/create-campaign/references/copy-calibration-examples.md +120 -0
- package/skills/create-campaign/references/offer-patterns.md +108 -0
- package/skills/create-campaign/references/provider-selection-strategy.md +212 -0
- package/skills/create-campaign/references/question-examples.md +167 -0
- package/skills/create-campaign/references/token-fill-examples.md +81 -0
- package/skills/create-campaign-brief/ARCHITECTURE.md +72 -0
- package/skills/create-campaign-brief/DISCUSS.md +64 -0
- package/skills/create-campaign-brief/README.md +176 -0
- package/skills/create-campaign-brief/SKILL.md +537 -0
- package/skills/create-campaign-brief/references/brief-synthesis-rules.md +100 -0
- package/skills/create-campaign-brief/references/brief-template.md +220 -0
- package/skills/create-campaign-brief/references/campaign-idea-options.md +30 -0
- package/skills/create-campaign-brief/references/copy-appendix-template.md +62 -0
- package/skills/create-campaign-brief/references/draft-lifecycle.md +23 -0
- package/skills/create-campaign-brief/references/examples/MANIFEST.json +89 -0
- package/skills/create-campaign-brief/references/examples/briefs/clover.md +223 -0
- package/skills/create-campaign-brief/references/examples/briefs/galley.md +222 -0
- package/skills/create-campaign-brief/references/examples/briefs/gelee.md +220 -0
- package/skills/create-campaign-brief/references/examples/briefs/hey-digital.md +234 -0
- package/skills/create-campaign-brief/references/examples/briefs/persona.md +231 -0
- package/skills/create-campaign-brief/references/examples/briefs/revvix.md +220 -0
- package/skills/create-campaign-brief/references/examples/briefs/sellable-dev.md +220 -0
- package/skills/create-campaign-brief/references/examples/briefs/superposition.md +233 -0
- package/skills/create-campaign-brief/references/examples/briefs/superpower.md +219 -0
- package/skills/create-campaign-brief/references/examples/briefs/westpark-villas.md +220 -0
- package/skills/create-campaign-brief/references/icp-lock-question-bank.md +43 -0
- package/skills/create-campaign-brief/references/messaging-inputs.md +58 -0
- package/skills/create-campaign-brief/references/output-acceptance-rubric.md +62 -0
- package/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md +248 -0
- package/skills/create-campaign-brief/references/phase75-canonical-brief-template.md +319 -0
- package/skills/create-campaign-brief/references/phase75-good-brief-and-messaging-examples.md +445 -0
- package/skills/create-campaign-brief/references/quick-research-protocol.md +39 -0
- package/skills/create-campaign-brief/references/reference-sheet-protocol.md +60 -0
- package/skills/create-campaign-brief/references/zero-shot-iteration-rules.md +66 -0
- package/skills/create-campaign-v2/SKILL.md +1619 -0
- package/skills/create-campaign-v2/core/auto-execute.README.md +219 -0
- package/skills/create-campaign-v2/core/auto-execute.yaml +121 -0
- package/skills/create-campaign-v2/core/flow.v2.json +1643 -0
- package/skills/create-campaign-v2/core/policy.md +82 -0
- package/skills/create-campaign-v2/references/ai-tells.md +253 -0
- package/skills/create-campaign-v2/references/approval-gate-framing.md +346 -0
- package/skills/create-campaign-v2/references/draft-lifecycle.md +110 -0
- package/skills/create-campaign-v2/references/escalation-ladder.md +119 -0
- package/skills/create-campaign-v2/references/filter-leads.md +495 -0
- package/skills/create-campaign-v2/references/final-handoff-contract.md +176 -0
- package/skills/create-campaign-v2/references/gold-standard-message-examples.md +394 -0
- package/skills/create-campaign-v2/references/gold-standard-message-patterns.md +314 -0
- package/skills/create-campaign-v2/references/gold-standard-message-validation-example.md +212 -0
- package/skills/create-campaign-v2/references/lead-validation-preview.md +172 -0
- package/skills/create-campaign-v2/references/parallel-critique-protocol.md +368 -0
- package/skills/create-campaign-v2/references/sample-validation-loop.md +289 -0
- package/skills/create-campaign-v2/references/step-13-import-leads.md +151 -0
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +90 -0
- package/skills/create-campaign-v2/references/thomas-revision-filters.md +521 -0
- package/skills/create-campaign-v2/references/thomas-variant-selection.md +202 -0
- package/skills/create-campaign-v2/references/tier-routing-matrix.md +66 -0
- package/skills/create-campaign-v2/references/validation-criteria.md +367 -0
- package/skills/create-campaign-v2/references/watch-link-handoff.md +106 -0
- package/skills/create-campaign-v2-validation/SKILL.md +296 -0
- package/skills/create-post/SKILL.md +1308 -0
- package/skills/create-rubric/SKILL.md +251 -0
- package/skills/engage/SKILL.md +549 -0
- package/skills/engage/core/README.md +23 -0
- package/skills/engage/core/proven-searches.json +11 -0
- package/skills/engage/core/style-guide.template.md +47 -0
- package/skills/engage/core/tracked-people.json +10 -0
- package/skills/enrich-prospects/SKILL.md +97 -0
- package/skills/find-leads/SKILL.md +467 -0
- package/skills/generate-messages/SKILL.md +2361 -0
- package/skills/interview/SKILL.md +132 -0
- package/skills/interview/core/ENGAGE_STYLE_GUIDE.template.md +54 -0
- package/skills/interview/core/ICP.template.md +54 -0
- package/skills/interview/core/VOICE_PROFILE.template.md +101 -0
- package/skills/providers/apollo.md +520 -0
- package/skills/providers/prospeo.md +398 -0
- package/skills/providers/sales-nav.md +372 -0
- package/skills/providers/signal-discovery.md +495 -0
- package/skills/research/SKILL.md +258 -0
- package/skills/research/config.json +9 -0
- package/skills/research/override.md +13 -0
- package/skills/research-prospect/SKILL.md +99 -0
- package/skills/research-sender/SKILL.md +158 -0
- package/skills/workflow-sequences/SKILL.md +85 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
let createCampaignPromptState = null;
|
|
2
|
+
let researchPromptStates = {};
|
|
3
|
+
let latestResearchPromptState = null;
|
|
4
|
+
let senderEnrichmentSnapshot = null;
|
|
5
|
+
let senderResearchCompletionState = null;
|
|
6
|
+
export function markCreateCampaignPromptLoaded() {
|
|
7
|
+
createCampaignPromptState = {
|
|
8
|
+
loadedAt: new Date().toISOString(),
|
|
9
|
+
};
|
|
10
|
+
return createCampaignPromptState;
|
|
11
|
+
}
|
|
12
|
+
export function markResearchPromptLoaded(mode = "generic", subskillName) {
|
|
13
|
+
const normalizedSubskillName = subskillName ||
|
|
14
|
+
(mode === "sender"
|
|
15
|
+
? "research-sender"
|
|
16
|
+
: mode === "prospect"
|
|
17
|
+
? "research-prospect"
|
|
18
|
+
: "research");
|
|
19
|
+
const state = {
|
|
20
|
+
loadedAt: new Date().toISOString(),
|
|
21
|
+
mode,
|
|
22
|
+
subskillName: normalizedSubskillName,
|
|
23
|
+
};
|
|
24
|
+
researchPromptStates[mode] = state;
|
|
25
|
+
latestResearchPromptState = state;
|
|
26
|
+
return state;
|
|
27
|
+
}
|
|
28
|
+
export function markSenderEnrichmentObserved(input) {
|
|
29
|
+
const hasContent = (value) => {
|
|
30
|
+
if (value == null)
|
|
31
|
+
return false;
|
|
32
|
+
if (typeof value === "string")
|
|
33
|
+
return value.trim().length > 0;
|
|
34
|
+
if (Array.isArray(value))
|
|
35
|
+
return value.length > 0;
|
|
36
|
+
if (typeof value === "object")
|
|
37
|
+
return Object.keys(value).length > 0;
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
senderEnrichmentSnapshot = {
|
|
41
|
+
observedAt: new Date().toISOString(),
|
|
42
|
+
enrichmentStatus: input.enrichmentStatus,
|
|
43
|
+
hasCaseStudies: hasContent(input.caseStudies),
|
|
44
|
+
hasProof: hasContent(input.proof),
|
|
45
|
+
};
|
|
46
|
+
// Any fresh enrich_sender call invalidates prior sender research completion.
|
|
47
|
+
senderResearchCompletionState = null;
|
|
48
|
+
return senderEnrichmentSnapshot;
|
|
49
|
+
}
|
|
50
|
+
export function markSenderResearchCompleted(input) {
|
|
51
|
+
const toNonNegativeInteger = (value) => {
|
|
52
|
+
if (typeof value !== "number" || Number.isNaN(value))
|
|
53
|
+
return 0;
|
|
54
|
+
if (!Number.isFinite(value))
|
|
55
|
+
return 0;
|
|
56
|
+
return Math.max(0, Math.floor(value));
|
|
57
|
+
};
|
|
58
|
+
senderResearchCompletionState = {
|
|
59
|
+
completedAt: new Date().toISOString(),
|
|
60
|
+
depth: input?.depth ?? "minimal-verification",
|
|
61
|
+
proofItemsFound: toNonNegativeInteger(input?.proofItemsFound),
|
|
62
|
+
caseStudyItemsFound: toNonNegativeInteger(input?.caseStudyItemsFound),
|
|
63
|
+
credibilitySignalsFound: toNonNegativeInteger(input?.credibilitySignalsFound),
|
|
64
|
+
notes: input?.notes ?? null,
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
ok: true,
|
|
68
|
+
...senderResearchCompletionState,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function assertCreateCampaignPromptLoaded() {
|
|
72
|
+
if (createCampaignPromptState) {
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
loadedAt: createCampaignPromptState.loadedAt,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
throw new Error('FLOW_PRECONDITION: create_campaign requires prompt preload. Call get_subskill_prompt({ subskillName: "create-campaign" }) and follow that workflow before create_campaign.');
|
|
79
|
+
}
|
|
80
|
+
export function assertResearchPromptLoaded(mode = "any") {
|
|
81
|
+
const researchPromptState = mode === "any" ? latestResearchPromptState : researchPromptStates[mode];
|
|
82
|
+
if (researchPromptState) {
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
loadedAt: researchPromptState.loadedAt,
|
|
86
|
+
mode: researchPromptState.mode,
|
|
87
|
+
subskillName: researchPromptState.subskillName,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (mode === "sender") {
|
|
91
|
+
throw new Error('FLOW_PRECONDITION: net-new create_campaign requires sender research preload. Call get_subskill_prompt({ subskillName: "research-sender" }) and run sender research before create_campaign.');
|
|
92
|
+
}
|
|
93
|
+
throw new Error("FLOW_PRECONDITION: research preload missing. Call get_subskill_prompt with the matching research wrapper (research-sender or research-prospect), then run research before continuing.");
|
|
94
|
+
}
|
|
95
|
+
export function assertNetNewCreateCampaignResearchReady() {
|
|
96
|
+
if (!senderEnrichmentSnapshot) {
|
|
97
|
+
throw new Error("FLOW_PRECONDITION: net-new create_campaign requires sender enrichment context. Call enrich_sender first.");
|
|
98
|
+
}
|
|
99
|
+
const enrichmentLooksComplete = senderEnrichmentSnapshot.enrichmentStatus === "complete" &&
|
|
100
|
+
senderEnrichmentSnapshot.hasCaseStudies &&
|
|
101
|
+
senderEnrichmentSnapshot.hasProof;
|
|
102
|
+
const senderResearchPromptState = researchPromptStates.sender;
|
|
103
|
+
if (!senderResearchPromptState) {
|
|
104
|
+
throw new Error('FLOW_PRECONDITION: net-new create_campaign requires sender research after enrich_sender. Call get_subskill_prompt({ subskillName: "research-sender" }) and run sender research before create_campaign.');
|
|
105
|
+
}
|
|
106
|
+
if (!senderResearchCompletionState) {
|
|
107
|
+
throw new Error("FLOW_PRECONDITION: completed sender research is required before create_campaign. After running research-sender, call complete_sender_research({ depth, proofItemsFound, caseStudyItemsFound, credibilitySignalsFound, notes? }).");
|
|
108
|
+
}
|
|
109
|
+
if (new Date(senderResearchCompletionState.completedAt).getTime() <
|
|
110
|
+
new Date(senderEnrichmentSnapshot.observedAt).getTime()) {
|
|
111
|
+
throw new Error("FLOW_PRECONDITION: sender research completion is stale for the latest enrichment. Rerun research-sender after enrich_sender, then call complete_sender_research before create_campaign.");
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
enrichmentStatus: senderEnrichmentSnapshot.enrichmentStatus,
|
|
116
|
+
hasCaseStudies: senderEnrichmentSnapshot.hasCaseStudies,
|
|
117
|
+
hasProof: senderEnrichmentSnapshot.hasProof,
|
|
118
|
+
enrichmentLooksComplete,
|
|
119
|
+
usedResearchPrompt: Boolean(senderResearchPromptState),
|
|
120
|
+
researchPromptMode: senderResearchPromptState?.mode ?? null,
|
|
121
|
+
researchPromptSubskillName: senderResearchPromptState?.subskillName ?? null,
|
|
122
|
+
researchCompletion: {
|
|
123
|
+
depth: senderResearchCompletionState.depth,
|
|
124
|
+
proofItemsFound: senderResearchCompletionState.proofItemsFound,
|
|
125
|
+
caseStudyItemsFound: senderResearchCompletionState.caseStudyItemsFound,
|
|
126
|
+
credibilitySignalsFound: senderResearchCompletionState.credibilitySignalsFound,
|
|
127
|
+
completedAt: senderResearchCompletionState.completedAt,
|
|
128
|
+
},
|
|
129
|
+
needsResearch: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export function resetFlowPreflightState() {
|
|
133
|
+
createCampaignPromptState = null;
|
|
134
|
+
researchPromptStates = {};
|
|
135
|
+
latestResearchPromptState = null;
|
|
136
|
+
senderEnrichmentSnapshot = null;
|
|
137
|
+
senderResearchCompletionState = null;
|
|
138
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
type GetCampaignFrameworkInput = {
|
|
2
|
+
flowVersion?: "v1" | "v2";
|
|
3
|
+
includePlugins?: boolean;
|
|
4
|
+
};
|
|
5
|
+
type ProviderRegistryEntry = {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
configPath: string;
|
|
9
|
+
};
|
|
10
|
+
type ProviderRegistry = {
|
|
11
|
+
version: string;
|
|
12
|
+
defaultProviderOrder: string[];
|
|
13
|
+
providers: ProviderRegistryEntry[];
|
|
14
|
+
};
|
|
15
|
+
export declare const frameworkToolDefinitions: {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: string;
|
|
20
|
+
properties: {
|
|
21
|
+
flowVersion: {
|
|
22
|
+
type: string;
|
|
23
|
+
enum: string[];
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
includePlugins: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
additionalProperties: boolean;
|
|
32
|
+
};
|
|
33
|
+
}[];
|
|
34
|
+
export declare function getCampaignFramework(input: GetCampaignFrameworkInput): {
|
|
35
|
+
flowVersion: "v1" | "v2";
|
|
36
|
+
policy: string;
|
|
37
|
+
flow: Record<string, unknown>;
|
|
38
|
+
providerRegistry: ProviderRegistry;
|
|
39
|
+
providers: Record<string, unknown>;
|
|
40
|
+
plugins: unknown[];
|
|
41
|
+
overrides: Record<string, unknown>;
|
|
42
|
+
warnings: string[];
|
|
43
|
+
};
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
|
+
import { dirname, isAbsolute, join, resolve } from "path";
|
|
3
|
+
import { resolveWorkspaceRoot } from "../utils/workspace-root.js";
|
|
4
|
+
const entryPath = process.argv[1] ? resolve(process.argv[1]) : process.cwd();
|
|
5
|
+
const entryDir = dirname(entryPath);
|
|
6
|
+
const workspaceRoot = resolveWorkspaceRoot(entryDir);
|
|
7
|
+
const frameworkRoot = join(workspaceRoot, "mcp/sellable/skills/create-campaign");
|
|
8
|
+
const frameworkV2Root = join(workspaceRoot, "mcp/sellable/skills/create-campaign-v2");
|
|
9
|
+
function getFrameworkRoot(flowVersion) {
|
|
10
|
+
return flowVersion === "v2" ? frameworkV2Root : frameworkRoot;
|
|
11
|
+
}
|
|
12
|
+
function resolveFromRoot(filePath) {
|
|
13
|
+
if (isAbsolute(filePath))
|
|
14
|
+
return filePath;
|
|
15
|
+
return resolve(workspaceRoot, filePath);
|
|
16
|
+
}
|
|
17
|
+
function readJson(filePath) {
|
|
18
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
19
|
+
return JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
function loadProviderRegistry() {
|
|
22
|
+
const registryPath = join(frameworkRoot, "core/providers/registry.json");
|
|
23
|
+
if (!existsSync(registryPath)) {
|
|
24
|
+
throw new Error(`Provider registry not found at ${registryPath}`);
|
|
25
|
+
}
|
|
26
|
+
return readJson(registryPath);
|
|
27
|
+
}
|
|
28
|
+
function loadProviders(registry) {
|
|
29
|
+
const providers = {};
|
|
30
|
+
const warnings = [];
|
|
31
|
+
for (const entry of registry.providers) {
|
|
32
|
+
try {
|
|
33
|
+
const configPath = resolveFromRoot(entry.configPath);
|
|
34
|
+
providers[entry.id] = readJson(configPath);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
warnings.push(`Failed to load provider config for ${entry.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { providers, warnings };
|
|
41
|
+
}
|
|
42
|
+
function loadPluginRegistry() {
|
|
43
|
+
const registryPath = join(frameworkRoot, "context/registry.json");
|
|
44
|
+
if (!existsSync(registryPath))
|
|
45
|
+
return null;
|
|
46
|
+
return readJson(registryPath);
|
|
47
|
+
}
|
|
48
|
+
function mergeOverrides(entries) {
|
|
49
|
+
const merged = {};
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (!entry.overrides)
|
|
52
|
+
continue;
|
|
53
|
+
Object.assign(merged, entry.overrides);
|
|
54
|
+
}
|
|
55
|
+
return merged;
|
|
56
|
+
}
|
|
57
|
+
function loadPlugins(registry) {
|
|
58
|
+
if (!registry) {
|
|
59
|
+
return {
|
|
60
|
+
plugins: [],
|
|
61
|
+
overrides: {},
|
|
62
|
+
warnings: ["Plugin registry not found; continuing without plugins."],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const enabledEntries = registry.plugins.filter((p) => p.enabled !== false);
|
|
66
|
+
const warnings = [];
|
|
67
|
+
const plugins = enabledEntries.map((entry) => {
|
|
68
|
+
const fullPath = resolveFromRoot(entry.path);
|
|
69
|
+
if (!existsSync(fullPath)) {
|
|
70
|
+
warnings.push(`Plugin file missing for ${entry.id}: ${fullPath}`);
|
|
71
|
+
return {
|
|
72
|
+
id: entry.id,
|
|
73
|
+
path: entry.path,
|
|
74
|
+
description: entry.description || "",
|
|
75
|
+
content: "",
|
|
76
|
+
overrides: entry.overrides || {},
|
|
77
|
+
missing: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
81
|
+
return {
|
|
82
|
+
id: entry.id,
|
|
83
|
+
path: entry.path,
|
|
84
|
+
description: entry.description || "",
|
|
85
|
+
content,
|
|
86
|
+
overrides: entry.overrides || {},
|
|
87
|
+
missing: false,
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
const overrides = mergeOverrides(enabledEntries);
|
|
91
|
+
return { plugins, overrides, warnings };
|
|
92
|
+
}
|
|
93
|
+
export const frameworkToolDefinitions = [
|
|
94
|
+
{
|
|
95
|
+
name: "get_campaign_framework",
|
|
96
|
+
description: "Load the versioned create-campaign framework (policy, flow, providers, plugins, overrides). Call this at the start of create-campaign.",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {
|
|
100
|
+
flowVersion: {
|
|
101
|
+
type: "string",
|
|
102
|
+
enum: ["v1", "v2"],
|
|
103
|
+
description: "Framework flow version to load (default: v1)",
|
|
104
|
+
},
|
|
105
|
+
includePlugins: {
|
|
106
|
+
type: "boolean",
|
|
107
|
+
description: "Whether to include plugin context and overrides (default: true)",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
additionalProperties: false,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
export function getCampaignFramework(input) {
|
|
115
|
+
const flowVersion = input.flowVersion || "v1";
|
|
116
|
+
const includePlugins = input.includePlugins !== false;
|
|
117
|
+
const selectedFrameworkRoot = getFrameworkRoot(flowVersion);
|
|
118
|
+
const versionedPolicyPath = join(selectedFrameworkRoot, "core/policy.md");
|
|
119
|
+
const policyPath = existsSync(versionedPolicyPath)
|
|
120
|
+
? versionedPolicyPath
|
|
121
|
+
: join(frameworkRoot, "core/policy.md");
|
|
122
|
+
const flowPath = join(selectedFrameworkRoot, `core/flow.${flowVersion}.json`);
|
|
123
|
+
if (!existsSync(policyPath)) {
|
|
124
|
+
throw new Error(`Policy file not found at ${policyPath}`);
|
|
125
|
+
}
|
|
126
|
+
if (!existsSync(flowPath)) {
|
|
127
|
+
throw new Error(`Flow file not found at ${flowPath}`);
|
|
128
|
+
}
|
|
129
|
+
const policy = readFileSync(policyPath, "utf-8");
|
|
130
|
+
const flow = readJson(flowPath);
|
|
131
|
+
const providerRegistry = loadProviderRegistry();
|
|
132
|
+
const { providers, warnings: providerWarnings } = loadProviders(providerRegistry);
|
|
133
|
+
let plugins = [];
|
|
134
|
+
let overrides = {};
|
|
135
|
+
let pluginWarnings = [];
|
|
136
|
+
if (includePlugins) {
|
|
137
|
+
const pluginRegistry = loadPluginRegistry();
|
|
138
|
+
const pluginResult = loadPlugins(pluginRegistry);
|
|
139
|
+
plugins = pluginResult.plugins;
|
|
140
|
+
overrides = pluginResult.overrides;
|
|
141
|
+
pluginWarnings = pluginResult.warnings;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
flowVersion,
|
|
145
|
+
policy,
|
|
146
|
+
flow,
|
|
147
|
+
providerRegistry,
|
|
148
|
+
providers,
|
|
149
|
+
plugins,
|
|
150
|
+
overrides,
|
|
151
|
+
warnings: [...providerWarnings, ...pluginWarnings],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type InteractionMode = "step-by-step" | "autonomous" | "ask-when-needed";
|
|
2
|
+
export type ApprovalAction = "provider-preflight" | "provider-search" | "import-leads" | "confirm-lead-list";
|
|
3
|
+
export declare function setCampaignInteractionMode(input: {
|
|
4
|
+
campaignId: string;
|
|
5
|
+
interactionMode: string;
|
|
6
|
+
}): {
|
|
7
|
+
readonly campaignId: string;
|
|
8
|
+
readonly interactionMode: InteractionMode;
|
|
9
|
+
};
|
|
10
|
+
export declare function resolveCampaignInteractionMode(input: {
|
|
11
|
+
campaignId?: string | null;
|
|
12
|
+
persistedMode?: unknown;
|
|
13
|
+
}): InteractionMode;
|
|
14
|
+
export declare function assertInteractionApproval(input: {
|
|
15
|
+
campaignId?: string | null;
|
|
16
|
+
persistedMode?: unknown;
|
|
17
|
+
action: ApprovalAction;
|
|
18
|
+
confirmed?: boolean;
|
|
19
|
+
}): {
|
|
20
|
+
readonly ok: true;
|
|
21
|
+
readonly campaignId: string | null;
|
|
22
|
+
readonly interactionMode: InteractionMode;
|
|
23
|
+
readonly action: ApprovalAction;
|
|
24
|
+
readonly needsApproval: boolean;
|
|
25
|
+
readonly confirmed: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare function resetInteractionModeState(): void;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const campaignInteractionMode = new Map();
|
|
2
|
+
function normalizeInteractionMode(input) {
|
|
3
|
+
if (typeof input !== "string")
|
|
4
|
+
return null;
|
|
5
|
+
const normalized = input
|
|
6
|
+
.trim()
|
|
7
|
+
.toLowerCase()
|
|
8
|
+
.replace(/_/g, "-")
|
|
9
|
+
.replace(/\s+/g, " ");
|
|
10
|
+
if (normalized === "step-by-step" ||
|
|
11
|
+
normalized === "step by step" ||
|
|
12
|
+
normalized === "continue step by step") {
|
|
13
|
+
return "step-by-step";
|
|
14
|
+
}
|
|
15
|
+
if (normalized === "autonomous" ||
|
|
16
|
+
normalized === "use best judgment" ||
|
|
17
|
+
normalized === "best judgment" ||
|
|
18
|
+
normalized === "auto") {
|
|
19
|
+
return "autonomous";
|
|
20
|
+
}
|
|
21
|
+
if (normalized === "ask-when-needed" ||
|
|
22
|
+
normalized === "ask when needed" ||
|
|
23
|
+
normalized === "ask only when needed") {
|
|
24
|
+
return "ask-when-needed";
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function requiresApproval(interactionMode, action) {
|
|
29
|
+
if (interactionMode === "step-by-step") {
|
|
30
|
+
// Provider selection approval should be enough to proceed through
|
|
31
|
+
// provider preflight + first search without a second "yes".
|
|
32
|
+
return action === "import-leads" || action === "confirm-lead-list";
|
|
33
|
+
}
|
|
34
|
+
if (interactionMode === "ask-when-needed") {
|
|
35
|
+
return action === "import-leads" || action === "confirm-lead-list";
|
|
36
|
+
}
|
|
37
|
+
// autonomous
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
export function setCampaignInteractionMode(input) {
|
|
41
|
+
const campaignId = input.campaignId?.trim();
|
|
42
|
+
if (!campaignId) {
|
|
43
|
+
throw new Error("interactionMode update requires campaignId");
|
|
44
|
+
}
|
|
45
|
+
const normalized = normalizeInteractionMode(input.interactionMode);
|
|
46
|
+
if (!normalized) {
|
|
47
|
+
throw new Error(`Invalid interactionMode: ${input.interactionMode}. Valid values: step-by-step, autonomous, ask-when-needed.`);
|
|
48
|
+
}
|
|
49
|
+
campaignInteractionMode.set(campaignId, normalized);
|
|
50
|
+
return {
|
|
51
|
+
campaignId,
|
|
52
|
+
interactionMode: normalized,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function resolveCampaignInteractionMode(input) {
|
|
56
|
+
const persisted = normalizeInteractionMode(input.persistedMode);
|
|
57
|
+
const campaignId = input.campaignId?.trim();
|
|
58
|
+
if (campaignId && persisted) {
|
|
59
|
+
campaignInteractionMode.set(campaignId, persisted);
|
|
60
|
+
return persisted;
|
|
61
|
+
}
|
|
62
|
+
if (campaignId) {
|
|
63
|
+
const cached = campaignInteractionMode.get(campaignId);
|
|
64
|
+
if (cached)
|
|
65
|
+
return cached;
|
|
66
|
+
}
|
|
67
|
+
return "ask-when-needed";
|
|
68
|
+
}
|
|
69
|
+
export function assertInteractionApproval(input) {
|
|
70
|
+
const interactionMode = resolveCampaignInteractionMode({
|
|
71
|
+
campaignId: input.campaignId,
|
|
72
|
+
persistedMode: input.persistedMode,
|
|
73
|
+
});
|
|
74
|
+
const needsApproval = requiresApproval(interactionMode, input.action);
|
|
75
|
+
if (needsApproval && input.confirmed !== true) {
|
|
76
|
+
const blockingMessage = `Action "${input.action}" requires confirmation in ${interactionMode} mode.`;
|
|
77
|
+
const diagnostics = {
|
|
78
|
+
code: "APPROVAL_REQUIRED",
|
|
79
|
+
safeToProceed: false,
|
|
80
|
+
campaignId: input.campaignId ?? null,
|
|
81
|
+
interactionMode,
|
|
82
|
+
action: input.action,
|
|
83
|
+
blockingErrors: [blockingMessage],
|
|
84
|
+
nextStep: "Ask the user for confirmation, then retry the same tool call with confirmed: true.",
|
|
85
|
+
};
|
|
86
|
+
const error = new Error(`APPROVAL_REQUIRED: ${blockingMessage} Next step: ${diagnostics.nextStep}`);
|
|
87
|
+
error.diagnostics =
|
|
88
|
+
diagnostics;
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
ok: true,
|
|
93
|
+
campaignId: input.campaignId ?? null,
|
|
94
|
+
interactionMode,
|
|
95
|
+
action: input.action,
|
|
96
|
+
needsApproval,
|
|
97
|
+
confirmed: input.confirmed === true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function resetInteractionModeState() {
|
|
101
|
+
campaignInteractionMode.clear();
|
|
102
|
+
}
|