saasfunnels 0.1.0-beta.0 → 0.2.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.
@@ -23992,13 +23992,24 @@ var featureInstrumentationBindingSchema = external_exports.object({
23992
23992
  ),
23993
23993
  symbol: external_exports.string().min(1).max(240)
23994
23994
  }).strict();
23995
+ var featureInstrumentationManifestProducers = ["cli", "github_action", "github_app"];
23996
+ var featureInstrumentationScanRoles = ["series", "candidate"];
23995
23997
  var featureInstrumentationManifestSchema = external_exports.object({
23996
23998
  bindings: external_exports.array(featureInstrumentationBindingSchema).max(1e4),
23999
+ discoveryRoots: external_exports.array(
24000
+ external_exports.string().min(1).max(200).refine(
24001
+ (value) => !value.startsWith("/") && !value.includes(".."),
24002
+ "Discovery roots must be relative and contained."
24003
+ )
24004
+ ).max(50),
23997
24005
  environment: external_exports.enum(funnelFeatureEnvironments),
23998
24006
  manifestFingerprint: fingerprint2,
23999
24007
  manifestVersion: external_exports.string().min(1).max(80),
24008
+ producer: external_exports.enum(featureInstrumentationManifestProducers),
24009
+ repositoryKey: external_exports.string().min(1).max(200),
24000
24010
  repositoryRevision: external_exports.string().min(1).max(160),
24001
- schemaVersion: external_exports.literal(1),
24011
+ scanRole: external_exports.enum(featureInstrumentationScanRoles),
24012
+ schemaVersion: external_exports.literal(2),
24002
24013
  sdkVersions: external_exports.array(external_exports.string().max(40).regex(/^\d+\.\d+\.\d+$/)).max(10).default([]),
24003
24014
  validatedAt: timestamp2,
24004
24015
  validationState: external_exports.enum(["valid", "failed"])
@@ -24739,11 +24750,15 @@ function buildFeatureInstrumentationHandoff(input) {
24739
24750
  symbol: evidence.symbol
24740
24751
  }))
24741
24752
  ),
24753
+ discoveryRoots: [...new Set(input.discoveryRoots ?? [])].sort(),
24742
24754
  environment: input.manifest.environment,
24743
24755
  manifestFingerprint,
24744
24756
  manifestVersion: manifestFingerprint.slice(0, 16),
24757
+ producer: input.producer ?? "cli",
24758
+ repositoryKey: input.repositoryKey,
24745
24759
  repositoryRevision: input.repositoryRevision,
24746
- schemaVersion: 1,
24760
+ scanRole: input.scanRole ?? "series",
24761
+ schemaVersion: 2,
24747
24762
  sdkVersions: [...new Set(input.sdkVersions ?? [])].sort(),
24748
24763
  validatedAt: input.validatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
24749
24764
  validationState: "valid"
@@ -24786,7 +24801,7 @@ Applied reviewed edits. Change record: ${result3.changeRecordPath}` : result3.id
24786
24801
 
24787
24802
  // src/identity.ts
24788
24803
  var SAASFUNNELS_CLI_NAME = "saasfunnels";
24789
- var SAASFUNNELS_CLI_VERSION = "0.1.0-beta.0";
24804
+ var SAASFUNNELS_CLI_VERSION = "0.1.0-beta.1";
24790
24805
  var SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
24791
24806
  var SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
24792
24807
  var SAASFUNNELS_ENV = Object.freeze({
@@ -24817,6 +24832,73 @@ function saasFunnelsPublicText(value) {
24817
24832
  ).replaceAll("prevenueFeatureKeys", "saasFunnelsFeatureKeys").replaceAll("PrevenueFeatureKey", "SaaSFunnelsFeatureKey").replaceAll("SaaSFunnels", SAASFUNNELS_PRODUCT_NAME);
24818
24833
  }
24819
24834
 
24835
+ // src/check-summary.ts
24836
+ var kindHeadings = {
24837
+ added: "New Feature bindings",
24838
+ moved: "Moved bindings",
24839
+ removed: "Removed bindings",
24840
+ renamed: "Renamed bindings"
24841
+ };
24842
+ var rejectionReasons = {
24843
+ binding_duplicate: "duplicate evidence for one location",
24844
+ binding_fingerprint_invalid: "malformed fingerprint",
24845
+ binding_kind_unknown: "unrecognised binding kind",
24846
+ binding_path_unsafe: "unsafe or sensitive file path",
24847
+ binding_shape_invalid: "malformed binding"
24848
+ };
24849
+ function formatFeatureDriftCheckSummary(input) {
24850
+ const lines = [];
24851
+ const removed = input.drift.filter((entry) => entry.kind === "removed");
24852
+ const breaking = removed.filter(
24853
+ (entry) => entry.featureKey && (input.targetedFeatureKeys ?? []).includes(entry.featureKey)
24854
+ );
24855
+ if (breaking.length) {
24856
+ lines.push("### Live Funnels target Features this change removes");
24857
+ for (const entry of breaking) {
24858
+ lines.push(`- \`${entry.featureKey}\`${entry.location ? ` \u2014 ${entry.location}` : ""}`);
24859
+ }
24860
+ lines.push("");
24861
+ }
24862
+ if (!input.drift.length) {
24863
+ lines.push("No Feature binding changes.");
24864
+ } else {
24865
+ for (const kind of ["removed", "renamed", "moved", "added"]) {
24866
+ const entries = input.drift.filter((entry) => entry.kind === kind);
24867
+ if (!entries.length) continue;
24868
+ lines.push(`### ${kindHeadings[kind]}`);
24869
+ for (const entry of entries) {
24870
+ lines.push(
24871
+ `- \`${entry.featureKey ?? "unknown"}\`${entry.location ? ` \u2014 ${entry.location}` : ""}`
24872
+ );
24873
+ }
24874
+ lines.push("");
24875
+ }
24876
+ }
24877
+ if (input.proposedFeatureKeys?.length) {
24878
+ lines.push("### Found in code, not in your catalog");
24879
+ for (const featureKey of input.proposedFeatureKeys) {
24880
+ lines.push(`- \`${featureKey}\``);
24881
+ }
24882
+ lines.push("");
24883
+ }
24884
+ if (input.rejectedBindings?.length) {
24885
+ lines.push("### Evidence that could not be recorded");
24886
+ for (const rejection of input.rejectedBindings) {
24887
+ lines.push(
24888
+ `- \`${rejection.featureKey ?? "unknown"}\` \u2014 ${rejectionReasons[rejection.reason] ?? rejection.reason}`
24889
+ );
24890
+ }
24891
+ lines.push("");
24892
+ }
24893
+ return {
24894
+ // Never fail the build: a false positive blocking a merge queue is the
24895
+ // fastest way to get uninstalled.
24896
+ conclusion: "neutral",
24897
+ summary: lines.join("\n").trim(),
24898
+ title: breaking.length ? `${breaking.length} Feature${breaking.length === 1 ? "" : "s"} targeted by live Funnels removed` : input.drift.length ? `${input.drift.length} Feature binding change${input.drift.length === 1 ? "" : "s"}` : "No Feature binding changes"
24899
+ };
24900
+ }
24901
+
24820
24902
  // src/mcp.ts
24821
24903
  import { createInterface } from "node:readline";
24822
24904
 
@@ -26173,7 +26255,7 @@ Usage:
26173
26255
  ${SAASFUNNELS_CLI_NAME} events send-test [--file <file>] [--json]
26174
26256
  ${SAASFUNNELS_CLI_NAME} features setup [--root <paths>] [--exclude <paths>] [--accept <ids|all>] [--reject <ids>] [--map <id=key>] [--manifest-only] [--apply] [--json]
26175
26257
  ${SAASFUNNELS_CLI_NAME} features check --feature <key> --account-id <uuid> [--environment test] [--json]
26176
- ${SAASFUNNELS_CLI_NAME} features handoff [--file <path>] --repository-revision <revision> [--send] [--json]
26258
+ ${SAASFUNNELS_CLI_NAME} features handoff [--file <path>] --repository-revision <revision> --repository-key <key> [--discovery-roots <paths>] [--scan-role series|candidate] [--producer cli|github_action|github_app] [--send] [--json]
26177
26259
  ${SAASFUNNELS_CLI_NAME} catalog discover [feature setup options]
26178
26260
  ${SAASFUNNELS_CLI_NAME} catalog validate [file] [--json]
26179
26261
  ${SAASFUNNELS_CLI_NAME} catalog diff [feature setup options]
@@ -26396,6 +26478,27 @@ async function commandFeatures(args, flags, options) {
26396
26478
  "Missing --repository-revision for the structured Feature handoff.\n"
26397
26479
  );
26398
26480
  }
26481
+ const repositoryKey = flagString(flags, "repository-key");
26482
+ if (!repositoryKey) {
26483
+ return result(
26484
+ 2,
26485
+ "",
26486
+ "Missing --repository-key for the structured Feature handoff.\n"
26487
+ );
26488
+ }
26489
+ const scanRole = flagString(flags, "scan-role") ?? "series";
26490
+ if (scanRole !== "series" && scanRole !== "candidate") {
26491
+ return result(2, "", "Use --scan-role series or --scan-role candidate.\n");
26492
+ }
26493
+ const producer = flagString(flags, "producer") ?? "cli";
26494
+ if (producer !== "cli" && producer !== "github_action" && producer !== "github_app") {
26495
+ return result(
26496
+ 2,
26497
+ "",
26498
+ "Use --producer cli, --producer github_action, or --producer github_app.\n"
26499
+ );
26500
+ }
26501
+ const discoveryRoots = (flagString(flags, "discovery-roots") ?? "").split(",").map((root) => root.trim()).filter(Boolean);
26399
26502
  const source = await filesystem(options).readFile(
26400
26503
  resolve2(cwd(options), path),
26401
26504
  "utf8"
@@ -26422,8 +26525,12 @@ ${validation.errors.map((error51) => `- ${error51}`).join("\n")}
26422
26525
  } catch {
26423
26526
  }
26424
26527
  const handoff = buildFeatureInstrumentationHandoff({
26528
+ discoveryRoots,
26425
26529
  manifest: validation.manifest,
26530
+ producer,
26531
+ repositoryKey,
26426
26532
  repositoryRevision,
26533
+ scanRole,
26427
26534
  sdkVersions
26428
26535
  });
26429
26536
  if (hasFlag(flags, "send")) {
@@ -26434,8 +26541,9 @@ ${validation.errors.map((error51) => `- ${error51}`).join("\n")}
26434
26541
  "",
26435
26542
  "Missing SAASFUNNELS_API_KEY with features:write scope for --send.\n"
26436
26543
  );
26544
+ const endpoint = scanRole === "candidate" ? "/api/developer-tools/features/instrumentation/preview" : "/api/developer-tools/features/instrumentation";
26437
26545
  const response = await (options.fetch ?? fetch)(
26438
- `${apiBaseUrl2(options, flags)}/api/developer-tools/features/instrumentation`,
26546
+ `${apiBaseUrl2(options, flags)}${endpoint}`,
26439
26547
  {
26440
26548
  body: JSON.stringify(handoff),
26441
26549
  headers: {
@@ -26446,7 +26554,14 @@ ${validation.errors.map((error51) => `- ${error51}`).join("\n")}
26446
26554
  }
26447
26555
  );
26448
26556
  const body = await response.json();
26449
- return jsonMode(flags) ? jsonResult(response.ok ? 0 : 1, body) : response.ok ? result(
26557
+ const reported = response.ok ? {
26558
+ ...body,
26559
+ checkSummary: formatFeatureDriftCheckSummary({
26560
+ drift: body?.data?.drift ?? [],
26561
+ rejectedBindings: body?.data?.rejectedBindings ?? []
26562
+ })
26563
+ } : body;
26564
+ return jsonMode(flags) ? jsonResult(response.ok ? 0 : 1, reported) : response.ok ? result(
26450
26565
  0,
26451
26566
  "Feature instrumentation handoff accepted. Open the Features review link returned by SaaSFunnels.\n"
26452
26567
  ) : result(1, "", "Feature instrumentation handoff was rejected.\n");
@@ -0,0 +1,14 @@
1
+ export type AgentCapabilityId = "account.funnel_fit.simulate" | "account.strategy.read" | "developer.event.validate" | "developer.feature_manifest.validate" | "developer.handoff.generate" | "developer.workspace.read" | "funnel.entry.apply" | "funnel.entry.evidence.submit" | "funnel.entry.inspect" | "funnel.entry.plan" | "funnel.entry.test" | "setup.test_event.send";
2
+ type AgentExecutionBoundary = "api_key" | "hosted_mcp" | "in_app" | "local_cli" | "local_mcp" | "scheduled_agent";
3
+ type AgentOperationClass = "external_write" | "plan" | "prepare" | "read" | "reversible_write" | "simulate" | "validate";
4
+ type Capability = {
5
+ boundaries: AgentExecutionBoundary[];
6
+ enabled: true;
7
+ id: AgentCapabilityId;
8
+ operationClass: AgentOperationClass;
9
+ };
10
+ export declare function getAgentCapability(id: AgentCapabilityId): Capability;
11
+ export declare function agentCapabilityAllowedAtBoundary(id: AgentCapabilityId, boundary: AgentExecutionBoundary, { mutationsEnabled }?: {
12
+ mutationsEnabled?: boolean;
13
+ }): boolean;
14
+ export {};
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Renders a drift response as a GitHub check summary.
3
+ *
4
+ * Lives in the CLI package rather than the Action because this is the only part
5
+ * of the Action carrying logic worth testing; the Action itself is a thin
6
+ * wrapper around `features handoff` plus this formatter.
7
+ */
8
+ export type FeatureDriftEntry = {
9
+ featureKey: string | null;
10
+ kind: "added" | "moved" | "removed" | "renamed";
11
+ location: string | null;
12
+ };
13
+ export type FeatureDriftRejection = {
14
+ featureKey: string | null;
15
+ reason: string;
16
+ };
17
+ export declare function formatFeatureDriftCheckSummary(input: {
18
+ drift: FeatureDriftEntry[];
19
+ proposedFeatureKeys?: string[];
20
+ rejectedBindings?: FeatureDriftRejection[];
21
+ targetedFeatureKeys?: string[];
22
+ }): {
23
+ conclusion: "neutral";
24
+ summary: string;
25
+ title: string;
26
+ };
@@ -0,0 +1,255 @@
1
+ import { mkdir, rename, rm, writeFile } from "node:fs/promises";
2
+ import { z } from "zod";
3
+ declare const featureBindingKinds: readonly ["server_enforcement", "browser_presentation", "usage_reporter", "funnel_trigger", "discovery"];
4
+ export declare const featureCatalogManifestSchema: z.ZodObject<{
5
+ environment: z.ZodEnum<{
6
+ test: "test";
7
+ production: "production";
8
+ }>;
9
+ features: z.ZodArray<z.ZodObject<{
10
+ accessModel: z.ZodEnum<{
11
+ boolean: "boolean";
12
+ limit: "limit";
13
+ }>;
14
+ aliases: z.ZodArray<z.ZodString>;
15
+ description: z.ZodString;
16
+ evidence: z.ZodArray<z.ZodObject<{
17
+ bindingIdentityFingerprint: z.ZodString;
18
+ bindingKind: z.ZodEnum<{
19
+ server_enforcement: "server_enforcement";
20
+ browser_presentation: "browser_presentation";
21
+ usage_reporter: "usage_reporter";
22
+ funnel_trigger: "funnel_trigger";
23
+ discovery: "discovery";
24
+ }>;
25
+ confidenceBasisPoints: z.ZodNumber;
26
+ file: z.ZodString;
27
+ fingerprint: z.ZodString;
28
+ line: z.ZodNumber;
29
+ rationale: z.ZodString;
30
+ symbol: z.ZodString;
31
+ }, z.core.$strict>>;
32
+ key: z.ZodString;
33
+ name: z.ZodString;
34
+ unit: z.ZodNullable<z.ZodString>;
35
+ }, z.core.$strict>>;
36
+ generatedBy: z.ZodLiteral<"saasfunnels features setup">;
37
+ schemaVersion: z.ZodLiteral<1>;
38
+ }, z.core.$strict>;
39
+ export type FeatureCatalogManifest = z.infer<typeof featureCatalogManifestSchema>;
40
+ export type FeatureCandidate = {
41
+ accessModel: "boolean" | "limit";
42
+ bindingIdentityFingerprint: string;
43
+ bindingKind: (typeof featureBindingKinds)[number];
44
+ confidenceBasisPoints: number;
45
+ file: string;
46
+ fingerprint: string;
47
+ id: string;
48
+ line: number;
49
+ name: string;
50
+ rationale: string;
51
+ suggestedKey: string;
52
+ symbol: string;
53
+ unit: string | null;
54
+ };
55
+ export type FeatureSetupEdit = {
56
+ afterHash: string;
57
+ beforeHash: string | null;
58
+ diff: string;
59
+ id: string;
60
+ kind: "generated_constants" | "manifest";
61
+ path: string;
62
+ selected: boolean;
63
+ };
64
+ export type FeatureSetupInput = {
65
+ accept?: string[];
66
+ accountId?: string;
67
+ apiBaseUrl: string;
68
+ apply: boolean;
69
+ cwd: string;
70
+ environment: "test" | "production";
71
+ exclude?: string[];
72
+ fetch?: typeof fetch;
73
+ include?: string[];
74
+ manifestOnly: boolean;
75
+ mappings?: Record<string, string>;
76
+ prompt?: (message: string) => Promise<string>;
77
+ reject?: string[];
78
+ serverKey?: string;
79
+ };
80
+ export type FeatureRuntimeCheckResult = {
81
+ decision?: {
82
+ allowed: boolean;
83
+ reasonCode: string;
84
+ source: string;
85
+ value: unknown;
86
+ };
87
+ featureKey?: string;
88
+ reason?: string;
89
+ state: "failed" | "passed" | "skipped";
90
+ };
91
+ export type FeatureSetupResult = {
92
+ applied: boolean;
93
+ candidates: FeatureCandidate[];
94
+ changeRecordPath?: string;
95
+ edits: FeatureSetupEdit[];
96
+ environment: "test" | "production";
97
+ framework: {
98
+ framework: "nextjs" | "unsupported";
99
+ packageManager: "bun" | "npm" | "pnpm" | "unknown" | "yarn";
100
+ saasFunnelsPackages: string[];
101
+ roots: string[];
102
+ };
103
+ idempotent: boolean;
104
+ instructions: Array<{
105
+ featureKey: string;
106
+ file: string;
107
+ line: number;
108
+ message: string;
109
+ symbol: string;
110
+ }>;
111
+ manifest: FeatureCatalogManifest;
112
+ manifestPath: string;
113
+ ok: boolean;
114
+ reviewUrl: string;
115
+ runtimeCheck: {
116
+ featureKey?: string;
117
+ reason?: string;
118
+ state: "failed" | "passed" | "skipped";
119
+ };
120
+ scannedFileCount: number;
121
+ validation: {
122
+ errors: string[];
123
+ ok: boolean;
124
+ };
125
+ };
126
+ declare function readable(path: string): Promise<string | null>;
127
+ type FeatureSetupAtomicIo = {
128
+ mkdir: typeof mkdir;
129
+ read: typeof readable;
130
+ rename: typeof rename;
131
+ remove: typeof rm;
132
+ write: typeof writeFile;
133
+ };
134
+ export declare function applyFeatureSetupChangesAtomically(cwd: string, changes: Array<{
135
+ contents: string;
136
+ path: string;
137
+ }>, io?: FeatureSetupAtomicIo): Promise<void>;
138
+ export declare function validateFeatureCatalogManifest(value: unknown): {
139
+ errors: never[];
140
+ manifest: {
141
+ environment: "test" | "production";
142
+ features: {
143
+ accessModel: "boolean" | "limit";
144
+ aliases: string[];
145
+ description: string;
146
+ evidence: {
147
+ bindingIdentityFingerprint: string;
148
+ bindingKind: "server_enforcement" | "browser_presentation" | "usage_reporter" | "funnel_trigger" | "discovery";
149
+ confidenceBasisPoints: number;
150
+ file: string;
151
+ fingerprint: string;
152
+ line: number;
153
+ rationale: string;
154
+ symbol: string;
155
+ }[];
156
+ key: string;
157
+ name: string;
158
+ unit: string | null;
159
+ }[];
160
+ generatedBy: "saasfunnels features setup";
161
+ schemaVersion: 1;
162
+ };
163
+ ok: true;
164
+ } | {
165
+ errors: string[];
166
+ manifest: null;
167
+ ok: false;
168
+ };
169
+ export declare function readFeatureCatalogManifest(path: string): Promise<{
170
+ errors: never[];
171
+ manifest: {
172
+ environment: "test" | "production";
173
+ features: {
174
+ accessModel: "boolean" | "limit";
175
+ aliases: string[];
176
+ description: string;
177
+ evidence: {
178
+ bindingIdentityFingerprint: string;
179
+ bindingKind: "server_enforcement" | "browser_presentation" | "usage_reporter" | "funnel_trigger" | "discovery";
180
+ confidenceBasisPoints: number;
181
+ file: string;
182
+ fingerprint: string;
183
+ line: number;
184
+ rationale: string;
185
+ symbol: string;
186
+ }[];
187
+ key: string;
188
+ name: string;
189
+ unit: string | null;
190
+ }[];
191
+ generatedBy: "saasfunnels features setup";
192
+ schemaVersion: 1;
193
+ };
194
+ ok: true;
195
+ } | {
196
+ errors: string[];
197
+ manifest: null;
198
+ ok: false;
199
+ }>;
200
+ export declare function isFeatureKey(value: string): boolean;
201
+ export declare function runFeatureRuntimeCheck(input: {
202
+ accountId?: string;
203
+ apiBaseUrl: string;
204
+ featureKey?: string;
205
+ fetch?: typeof fetch;
206
+ serverKey?: string;
207
+ }): Promise<FeatureRuntimeCheckResult>;
208
+ export declare function runFeatureSetup(input: FeatureSetupInput): Promise<FeatureSetupResult>;
209
+ export declare function parseFeatureMappings(values: string[]): {
210
+ [k: string]: string;
211
+ };
212
+ export declare function parseFeatureManifestSource(source: string): {
213
+ errors: never[];
214
+ manifest: {
215
+ environment: "test" | "production";
216
+ features: {
217
+ accessModel: "boolean" | "limit";
218
+ aliases: string[];
219
+ description: string;
220
+ evidence: {
221
+ bindingIdentityFingerprint: string;
222
+ bindingKind: "server_enforcement" | "browser_presentation" | "usage_reporter" | "funnel_trigger" | "discovery";
223
+ confidenceBasisPoints: number;
224
+ file: string;
225
+ fingerprint: string;
226
+ line: number;
227
+ rationale: string;
228
+ symbol: string;
229
+ }[];
230
+ key: string;
231
+ name: string;
232
+ unit: string | null;
233
+ }[];
234
+ generatedBy: "saasfunnels features setup";
235
+ schemaVersion: 1;
236
+ };
237
+ ok: true;
238
+ } | {
239
+ errors: string[];
240
+ manifest: null;
241
+ ok: false;
242
+ };
243
+ export declare function buildFeatureInstrumentationHandoff(input: {
244
+ discoveryRoots?: readonly string[];
245
+ manifest: FeatureCatalogManifest;
246
+ producer?: "cli" | "github_action" | "github_app";
247
+ repositoryKey: string;
248
+ repositoryRevision: string;
249
+ scanRole?: "series" | "candidate";
250
+ sdkVersions?: readonly string[];
251
+ validatedAt?: string;
252
+ }): unknown;
253
+ export declare function featureSdkVersionsFromPackageJson(value: unknown): string[];
254
+ export declare function featureSetupSummary(result: FeatureSetupResult): string;
255
+ export {};
@@ -0,0 +1,14 @@
1
+ export declare const SAASFUNNELS_CLI_NAME = "saasfunnels";
2
+ export declare const SAASFUNNELS_CLI_VERSION = "0.1.0-beta.1";
3
+ export declare const SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
4
+ export declare const SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
5
+ export declare const SAASFUNNELS_ENV: Readonly<{
6
+ apiBaseUrl: string[];
7
+ apiKey: string[];
8
+ funnelsServerKey: string[];
9
+ ingestApiKey: string[];
10
+ mcpEnableFunnelWrites: string[];
11
+ mcpEnableFunnelTests: string[];
12
+ mcpEnableSendTestEvent: string[];
13
+ }>;
14
+ export declare function saasFunnelsPublicText(value: string): string;
@@ -0,0 +1,3 @@
1
+ export { formatFeatureDriftCheckSummary, type FeatureDriftEntry, type FeatureDriftRejection, } from "./check-summary.js";
2
+ export { callSaaSFunnelsMcpTool, handleSaaSFunnelsMcpMessage, hostedSaaSFunnelsMcpToolDefinitions, readSaaSFunnelsMcpResource, saasFunnelsMcpCapabilityForTool, saasFunnelsMcpResources, saasFunnelsMcpToolCapabilityIds, saasFunnelsMcpToolDefinitions, SAASFUNNELS_MCP_PROTOCOL_VERSION, SAASFUNNELS_MCP_SERVER_VERSION, serveSaaSFunnelsMcp, type SaaSFunnelsMcpJsonObject, type SaaSFunnelsMcpOptions, type SaaSFunnelsMcpResourceDefinition, type SaaSFunnelsMcpToolDefinition, type SaaSFunnelsMcpToolName, } from "./mcp.js";
3
+ export { SAASFUNNELS_CLI_NAME, SAASFUNNELS_CLI_VERSION, SAASFUNNELS_DEFAULT_API_BASE_URL, SAASFUNNELS_ENV, SAASFUNNELS_PRODUCT_NAME, } from "./identity.js";
@@ -0,0 +1,91 @@
1
+ import { type AgentCapabilityId } from "./capabilities.js";
2
+ type McpEnv = Record<string, string | undefined>;
3
+ export type SaaSFunnelsMcpJsonObject = Record<string, unknown>;
4
+ type JsonObject = SaaSFunnelsMcpJsonObject;
5
+ type JsonRpcId = number | string | null;
6
+ type JsonRpcResponse = {
7
+ error?: {
8
+ code: number;
9
+ data?: unknown;
10
+ message: string;
11
+ };
12
+ id: JsonRpcId;
13
+ jsonrpc: "2.0";
14
+ result?: unknown;
15
+ };
16
+ export type SaaSFunnelsMcpToolDefinition = {
17
+ annotations?: Record<string, unknown>;
18
+ description: string;
19
+ inputSchema: JsonObject;
20
+ name: string;
21
+ outputSchema?: JsonObject;
22
+ title: string;
23
+ };
24
+ type McpToolDefinition = SaaSFunnelsMcpToolDefinition;
25
+ export type SaaSFunnelsMcpResourceDefinition = {
26
+ description: string;
27
+ mimeType: string;
28
+ name: string;
29
+ title: string;
30
+ uri: string;
31
+ };
32
+ type McpResourceDefinition = SaaSFunnelsMcpResourceDefinition;
33
+ export declare const saasFunnelsMcpToolCapabilityIds: {
34
+ readonly get_account_strategy: "account.strategy.read";
35
+ readonly apply_funnel_entry: "funnel.entry.apply";
36
+ readonly generate_direct_api_handoff: "developer.handoff.generate";
37
+ readonly get_integration_health: "developer.workspace.read";
38
+ readonly get_signal_payload_preview: "developer.workspace.read";
39
+ readonly get_workspace_readiness: "developer.workspace.read";
40
+ readonly inspect_funnel_entry: "funnel.entry.inspect";
41
+ readonly list_mapping_gaps: "developer.workspace.read";
42
+ readonly list_recent_signals: "developer.workspace.read";
43
+ readonly simulate_account_funnel_fit: "account.funnel_fit.simulate";
44
+ readonly propose_funnel_entry_installation: "funnel.entry.plan";
45
+ readonly run_funnel_binding_test: "funnel.entry.test";
46
+ readonly send_test_event: "setup.test_event.send";
47
+ readonly submit_funnel_entry_evidence: "funnel.entry.evidence.submit";
48
+ readonly validate_event_payload: "developer.event.validate";
49
+ readonly validate_feature_catalog_manifest: "developer.feature_manifest.validate";
50
+ };
51
+ export type SaaSFunnelsMcpToolName = keyof typeof saasFunnelsMcpToolCapabilityIds;
52
+ export declare function saasFunnelsMcpCapabilityForTool(name: string): {
53
+ boundaries: ("api_key" | "hosted_mcp" | "in_app" | "local_cli" | "local_mcp" | "scheduled_agent")[];
54
+ enabled: true;
55
+ id: AgentCapabilityId;
56
+ operationClass: "external_write" | "plan" | "prepare" | "read" | "reversible_write" | "simulate" | "validate";
57
+ } | null;
58
+ export type SaaSFunnelsMcpOptions = {
59
+ apiBaseUrlOverride?: string;
60
+ allowFunnelWrites?: boolean;
61
+ allowFunnelTests?: boolean;
62
+ allowTestWrites?: boolean;
63
+ authorizationHeader?: string;
64
+ env?: McpEnv;
65
+ fetch?: typeof fetch;
66
+ hostedMode?: boolean;
67
+ input?: NodeJS.ReadableStream;
68
+ output?: Pick<NodeJS.WritableStream, "write">;
69
+ };
70
+ declare const mcpProtocolVersion = "2025-06-18";
71
+ declare const mcpServerVersion = "0.1.0-beta.1";
72
+ export declare function saasFunnelsMcpResources(): McpResourceDefinition[];
73
+ export declare function readSaaSFunnelsMcpResource(uri: string, options?: SaaSFunnelsMcpOptions): string;
74
+ export declare function saasFunnelsMcpToolDefinitions({ allowFunnelTests, allowFunnelWrites, allowTestWrites, includeHostedAccountTools, }?: {
75
+ allowFunnelTests?: boolean;
76
+ allowFunnelWrites?: boolean;
77
+ allowTestWrites?: boolean;
78
+ includeHostedAccountTools?: boolean;
79
+ }): McpToolDefinition[];
80
+ export declare function hostedSaaSFunnelsMcpToolDefinitions(): SaaSFunnelsMcpToolDefinition[];
81
+ export declare function callSaaSFunnelsMcpTool(name: string, args: JsonObject, options?: SaaSFunnelsMcpOptions): Promise<{
82
+ content: {
83
+ text: string;
84
+ type: string;
85
+ }[];
86
+ isError: boolean;
87
+ structuredContent: SaaSFunnelsMcpJsonObject;
88
+ }>;
89
+ export declare function handleSaaSFunnelsMcpMessage(message: unknown, options?: SaaSFunnelsMcpOptions): Promise<JsonRpcResponse | undefined>;
90
+ export declare function serveSaaSFunnelsMcp(options?: SaaSFunnelsMcpOptions): Promise<void>;
91
+ export { mcpProtocolVersion as SAASFUNNELS_MCP_PROTOCOL_VERSION, mcpServerVersion as SAASFUNNELS_MCP_SERVER_VERSION, };
@@ -0,0 +1,73 @@
1
+ export type DeveloperToolEventSource = "direct" | "posthog" | "segment";
2
+
3
+ export type DeveloperToolValidationIssue = {
4
+ code: string;
5
+ message: string;
6
+ path?: string;
7
+ severity: "error" | "info" | "warning";
8
+ };
9
+
10
+ export type DeveloperToolSourceContract = {
11
+ auth_summary: string;
12
+ docs_url: string;
13
+ endpoint: string;
14
+ key: DeveloperToolEventSource;
15
+ name: string;
16
+ recommended_allowlist: string[];
17
+ required_fields: string[];
18
+ sample_payload: Record<string, unknown>;
19
+ scope: string;
20
+ setup_steps: string[];
21
+ };
22
+
23
+ export const DEVELOPER_TOOLS_CONTRACT_SCHEMA_VERSION: string;
24
+ export const developerToolEventSources: readonly DeveloperToolEventSource[];
25
+ export const eventKinds: readonly string[];
26
+ export const eventSentimentSources: readonly string[];
27
+ export const eventSentiments: readonly string[];
28
+ export const semanticEventTypes: readonly string[];
29
+ export const signalFamilyContracts: readonly Array<{
30
+ description: string;
31
+ label: string;
32
+ optionalSemanticTypes: string[];
33
+ requiredSemanticTypes: string[];
34
+ signalFamilyKey: string;
35
+ }>;
36
+
37
+ export const featureInstrumentationManifestSchema: import("zod").ZodTypeAny;
38
+
39
+ export function getDeveloperToolAgentHandoffArtifacts(input: {
40
+ endpoint: string;
41
+ eventPlan?: unknown;
42
+ }): Record<
43
+ "claude-code" | "codex" | "cursor" | "markdown",
44
+ {
45
+ file_contents: string;
46
+ install_command?: string;
47
+ label: string;
48
+ prompt: string;
49
+ target: string;
50
+ target_path: string;
51
+ version: string;
52
+ }
53
+ >;
54
+
55
+ export function getDeveloperToolSourceContract(
56
+ source: DeveloperToolEventSource,
57
+ ): DeveloperToolSourceContract;
58
+
59
+ export function validateDeveloperToolEventPayload(input: {
60
+ payload: unknown;
61
+ source: DeveloperToolEventSource;
62
+ }): {
63
+ errors: DeveloperToolValidationIssue[];
64
+ idempotency: Record<string, unknown>;
65
+ mapping_hints: Record<string, unknown>;
66
+ normalized_event?: Record<string, unknown>;
67
+ ok: boolean;
68
+ redaction: Record<string, unknown>;
69
+ revenue_relevant?: boolean;
70
+ schema_version: string;
71
+ source: DeveloperToolEventSource;
72
+ warnings: DeveloperToolValidationIssue[];
73
+ };