@funnelsgrove/cli 0.1.262 → 0.1.264

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/dist/cli.js CHANGED
@@ -29,7 +29,7 @@ import { applyTemplateDocsUpdate, inspectTemplateDocs, loadBundledDocs, planTemp
29
29
  import { renderValidationHuman, renderValidationJson, } from './diagnosticOutput.js';
30
30
  import { validateFunnel } from './funnelValidation.js';
31
31
  import { StepContractMigrationError, applyStepContractV2Migration, checkStepContractV2Migration, recoverStepContractV2Migration, resolveStepContractMigrationMode, stepContractMigrationReportPath, } from './stepContractMigration.js';
32
- import { assertHasCohortData, assertHasConversionData, assertHasFunnelPathData, assertHasTransitionData, buildCohortReportPayload, buildConversionReportPayload, buildFunnelPathReportPayload, buildTransitionReportPayload, formatAnalyticsJson, formatCohortTable, formatConversionsTable, formatFunnelPathTable, formatTransitionsTable, normalizeAnalyticsOutputFormat, parseAnalyticsDate, } from './analyticsOutput.js';
32
+ import { assertHasCohortData, assertHasConversionData, assertHasFunnelPathData, assertHasTransitionData, buildCohortReportPayload, buildConversionReportPayload, buildFunnelPathReportPayload, buildJourneyVersionsReportPayload, buildTransitionReportPayload, formatAnalyticsJson, formatCohortTable, formatConversionsTable, formatFunnelPathTable, formatJourneyVersionsTable, formatTransitionsTable, journeyVersionLabel, normalizeAnalyticsOutputFormat, parseAnalyticsDate, parseAnalyticsPeriod, } from './analyticsOutput.js';
33
33
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
34
34
  const toKebabCase = (value) => value
35
35
  .trim()
@@ -1115,6 +1115,21 @@ export function buildAnalyticsCommandInput(options) {
1115
1115
  timezone,
1116
1116
  };
1117
1117
  }
1118
+ const parseAnalyticsJourneyVersion = (value) => {
1119
+ const normalized = (value || 'current').trim().toLowerCase();
1120
+ if (normalized === 'current' || normalized === 'all' || UUID_PATTERN.test(normalized)) {
1121
+ return normalized;
1122
+ }
1123
+ throw new Error('--journey-version must be current, all, or a journey version id from `fgrove analytics versions`.');
1124
+ };
1125
+ export function buildFunnelAnalyticsCommandInput(options) {
1126
+ return {
1127
+ period: parseAnalyticsPeriod(options),
1128
+ format: normalizeAnalyticsOutputFormat(options.format),
1129
+ timezone: options.timezone?.trim() || undefined,
1130
+ journeyVersion: parseAnalyticsJourneyVersion(options.journeyVersion),
1131
+ };
1132
+ }
1118
1133
  export function buildPatchSourceInput(input) {
1119
1134
  return {
1120
1135
  workspaceId: input.workspaceId,
@@ -2169,9 +2184,10 @@ const analyticsCommand = addExamples(program.command('analytics').description('D
2169
2184
  'fgrove analytics conversions --project claimbee --funnel claimbee-ios --date 2026-06-11 --format json --out analytics.json',
2170
2185
  'fgrove analytics funnel-path --project claimbee --funnel claimbee-ios --date 2026-06-11',
2171
2186
  'fgrove analytics transitions --project claimbee --funnel claimbee-ios --date 2026-06-11',
2187
+ 'fgrove analytics versions --project claimbee --funnel claimbee-ios',
2172
2188
  'fgrove analytics cohort --project claimbee --date 2026-06-11 --format json',
2173
2189
  ]);
2174
- const loadFunnelAnalyticsContext = async (options) => {
2190
+ const resolveFunnelAnalyticsTarget = async (options) => {
2175
2191
  const token = await readAuthToken();
2176
2192
  const workspace = await resolveWorkspace(token, options.workspace);
2177
2193
  const project = await resolveAnalyticsProject({
@@ -2189,7 +2205,13 @@ const loadFunnelAnalyticsContext = async (options) => {
2189
2205
  workspace,
2190
2206
  project,
2191
2207
  funnel,
2192
- commandInput: buildAnalyticsCommandInput(options),
2208
+ };
2209
+ };
2210
+ const loadFunnelAnalyticsContext = async (options) => {
2211
+ const commandInput = buildFunnelAnalyticsCommandInput(options);
2212
+ return {
2213
+ ...await resolveFunnelAnalyticsTarget(options),
2214
+ commandInput,
2193
2215
  };
2194
2216
  };
2195
2217
  const loadProjectAnalyticsContext = async (options) => {
@@ -2216,8 +2238,9 @@ const fetchStepDropoffAnalytics = async (input, apiCall = callApi) => {
2216
2238
  workspaceId: input.workspaceId,
2217
2239
  projectId: input.projectId,
2218
2240
  funnelId: input.funnelId,
2219
- from: input.commandInput.from,
2220
- to: input.commandInput.to,
2241
+ ...(input.commandInput.journeyVersion === 'current' ? {} : { versionId: input.commandInput.journeyVersion }),
2242
+ from: input.commandInput.period.fromIso,
2243
+ to: input.commandInput.period.toIso,
2221
2244
  timezone: input.commandInput.timezone,
2222
2245
  },
2223
2246
  });
@@ -2235,24 +2258,79 @@ const fetchPublishedFunnelFlow = async (input, apiCall = callApi) => {
2235
2258
  });
2236
2259
  };
2237
2260
  export const fetchFunnelPathAnalytics = async (input, apiCall = callApi) => {
2261
+ const { journeyVersion } = input.commandInput;
2262
+ if (journeyVersion !== 'current' && journeyVersion !== 'all') {
2263
+ // An explicit Journey Version reports its own structure and is never
2264
+ // paired with the current published path.
2265
+ const stepDropoff = await fetchStepDropoffAnalytics(input, apiCall);
2266
+ return { stepDropoff, pathFlow: stepDropoff.flow };
2267
+ }
2238
2268
  const [stepDropoff, publishedFunnelFlow] = await Promise.all([
2239
2269
  fetchStepDropoffAnalytics(input, apiCall),
2240
2270
  fetchPublishedFunnelFlow(input, apiCall),
2241
2271
  ]);
2242
- return { stepDropoff, publishedFunnelFlow };
2272
+ return {
2273
+ stepDropoff,
2274
+ pathFlow: publishedFunnelFlow.status === 'ready' ? publishedFunnelFlow.flow : null,
2275
+ };
2243
2276
  };
2244
- addExamples(analyticsCommand
2245
- .command('conversions')
2246
- .description('Download one-day conversion data, full funnel path, and step transitions')
2277
+ // The API reads analytics dates in this timezone when a request names none.
2278
+ const DEFAULT_ANALYTICS_TIMEZONE = 'America/Los_Angeles';
2279
+ const toAnalyticsDate = (value, timezone) => new Intl.DateTimeFormat('en-CA', { timeZone: timezone || DEFAULT_ANALYTICS_TIMEZONE }).format(value);
2280
+ export const fetchJourneyVersions = async (input, apiCall = callApi) => {
2281
+ const { today, timezone, ...target } = input;
2282
+ const current = await fetchStepDropoffAnalytics({
2283
+ ...target,
2284
+ commandInput: buildFunnelAnalyticsCommandInput({ date: today, timezone }),
2285
+ }, apiCall);
2286
+ const newestFirst = [...current.version.options].sort((left, right) => right.seq - left.seq);
2287
+ // A version is active from its start day until the next version starts;
2288
+ // version-scoped counts make the shared switch day safe to include in both.
2289
+ const startDate = (startedAt) => (startedAt ? toAnalyticsDate(new Date(startedAt), timezone) : null);
2290
+ const versions = await Promise.all(newestFirst.map(async (version, index) => {
2291
+ const activeFrom = startDate(version.publishedAt);
2292
+ const activeTo = index === 0 ? null : startDate(newestFirst[index - 1].publishedAt);
2293
+ const report = activeFrom
2294
+ ? await fetchStepDropoffAnalytics({
2295
+ ...target,
2296
+ commandInput: buildFunnelAnalyticsCommandInput({
2297
+ from: activeFrom,
2298
+ to: activeTo ?? today,
2299
+ journeyVersion: version.id,
2300
+ timezone,
2301
+ }),
2302
+ }, apiCall)
2303
+ : null;
2304
+ return {
2305
+ id: version.id,
2306
+ seq: version.seq,
2307
+ label: journeyVersionLabel(version),
2308
+ isCurrent: version.isCurrent,
2309
+ startedAt: version.publishedAt,
2310
+ activeFrom,
2311
+ activeTo,
2312
+ visitors: report ? report.totals.visitors ?? 0 : null,
2313
+ };
2314
+ }));
2315
+ return { funnel: current.funnel, versions };
2316
+ };
2317
+ const addFunnelReportOptions = (command) => command
2247
2318
  .option('--workspace <id-or-slug-or-name>', 'Workspace id, slug, or name')
2248
2319
  .option('--project <id-or-slug-or-name>', 'Project id, slug, or name')
2249
2320
  .option('--funnel <id-or-slug-or-name>', 'Funnel id, slug, or name')
2250
- .requiredOption('--date <yyyy-mm-dd>', 'Analytics date')
2321
+ .option('--date <yyyy-mm-dd>', 'Analytics date; use instead of --from/--to for one day')
2322
+ .option('--from <yyyy-mm-dd>', 'First analytics date of a range, used with --to')
2323
+ .option('--to <yyyy-mm-dd>', 'Last analytics date of a range, used with --from')
2324
+ .option('--journey-version <id|current|all>', 'Journey version: current, all, or an id from `fgrove analytics versions`', 'current')
2251
2325
  .option('--format <table-or-json>', 'Output format: table or json', 'table')
2252
2326
  .option('--out <path>', 'Write output to a file')
2253
- .option('--timezone <iana-timezone>', 'Analytics timezone, for example America/Los_Angeles'), [
2327
+ .option('--timezone <iana-timezone>', 'Analytics timezone, for example America/Los_Angeles');
2328
+ addExamples(addFunnelReportOptions(analyticsCommand
2329
+ .command('conversions')
2330
+ .description('Download conversion data, full funnel path, and step transitions for a day or date range')), [
2254
2331
  'fgrove analytics conversions --project claimbee --funnel claimbee-ios --date 2026-06-11',
2255
2332
  'fgrove analytics conversions --project claimbee --funnel claimbee-ios --date 2026-06-11 --format json --out analytics.json',
2333
+ 'fgrove analytics conversions --project claimbee --funnel claimbee-ios --from 2026-06-01 --to 2026-06-14 --journey-version all',
2256
2334
  ])
2257
2335
  .action(async (options) => {
2258
2336
  const context = await loadFunnelAnalyticsContext(options);
@@ -2265,8 +2343,8 @@ addExamples(analyticsCommand
2265
2343
  workspaceId: context.workspace.id,
2266
2344
  projectId: context.project.id,
2267
2345
  funnelId: context.funnel.id,
2268
- from: context.commandInput.from,
2269
- to: context.commandInput.to,
2346
+ from: context.commandInput.period.fromIso,
2347
+ to: context.commandInput.period.toIso,
2270
2348
  timezone: context.commandInput.timezone,
2271
2349
  limit: 20_000,
2272
2350
  },
@@ -2279,81 +2357,66 @@ addExamples(analyticsCommand
2279
2357
  commandInput: context.commandInput,
2280
2358
  }),
2281
2359
  ]);
2282
- const { stepDropoff, publishedFunnelFlow } = pathAnalytics;
2283
- assertHasConversionData(context.commandInput.date, overview, stepDropoff);
2284
- const payload = buildConversionReportPayload({
2285
- date: context.commandInput.date,
2286
- workspaceId: context.workspace.id,
2287
- project: context.project,
2288
- overview,
2360
+ const { stepDropoff, pathFlow } = pathAnalytics;
2361
+ assertHasConversionData(context.commandInput.period.label, overview, stepDropoff);
2362
+ const report = {
2363
+ period: context.commandInput.period,
2364
+ journeyVersion: context.commandInput.journeyVersion,
2289
2365
  stepDropoff,
2290
- publishedFunnelFlow,
2291
- });
2366
+ overview,
2367
+ pathFlow,
2368
+ };
2292
2369
  await writeOrPrintAnalyticsOutput({
2293
2370
  format: context.commandInput.format,
2294
- payload,
2295
- table: formatConversionsTable({
2296
- date: context.commandInput.date,
2297
- overview,
2298
- stepDropoff,
2299
- publishedFunnelFlow,
2371
+ payload: buildConversionReportPayload({
2372
+ ...report,
2373
+ workspaceId: context.workspace.id,
2374
+ project: context.project,
2300
2375
  }),
2376
+ table: formatConversionsTable(report),
2301
2377
  out: options.out,
2302
2378
  });
2303
2379
  });
2304
- addExamples(analyticsCommand
2380
+ addExamples(addFunnelReportOptions(analyticsCommand
2305
2381
  .command('funnel-path')
2306
- .description('Download the full one-day funnel path report')
2307
- .option('--workspace <id-or-slug-or-name>', 'Workspace id, slug, or name')
2308
- .option('--project <id-or-slug-or-name>', 'Project id, slug, or name')
2309
- .option('--funnel <id-or-slug-or-name>', 'Funnel id, slug, or name')
2310
- .requiredOption('--date <yyyy-mm-dd>', 'Analytics date')
2311
- .option('--format <table-or-json>', 'Output format: table or json', 'table')
2312
- .option('--out <path>', 'Write output to a file')
2313
- .option('--timezone <iana-timezone>', 'Analytics timezone, for example America/Los_Angeles'), [
2382
+ .description('Download the full funnel path report for a day or date range')), [
2314
2383
  'fgrove analytics funnel-path --project claimbee --funnel claimbee-ios --date 2026-06-11',
2315
2384
  'fgrove analytics funnel-path --project claimbee --funnel claimbee-ios --date 2026-06-11 --format json',
2385
+ 'fgrove analytics funnel-path --project claimbee --funnel claimbee-ios --from 2026-06-01 --to 2026-06-14 --journey-version <journey-version-id>',
2316
2386
  ])
2317
2387
  .action(async (options) => {
2318
2388
  const context = await loadFunnelAnalyticsContext(options);
2319
- const { stepDropoff, publishedFunnelFlow } = await fetchFunnelPathAnalytics({
2389
+ const { stepDropoff, pathFlow } = await fetchFunnelPathAnalytics({
2320
2390
  token: context.token,
2321
2391
  workspaceId: context.workspace.id,
2322
2392
  projectId: context.project.id,
2323
2393
  funnelId: context.funnel.id,
2324
2394
  commandInput: context.commandInput,
2325
2395
  });
2326
- assertHasFunnelPathData(context.commandInput.date, stepDropoff, publishedFunnelFlow);
2327
- const payload = buildFunnelPathReportPayload({
2328
- date: context.commandInput.date,
2329
- workspaceId: context.workspace.id,
2330
- project: context.project,
2396
+ assertHasFunnelPathData(context.commandInput.period.label, stepDropoff, pathFlow);
2397
+ const report = {
2398
+ period: context.commandInput.period,
2399
+ journeyVersion: context.commandInput.journeyVersion,
2331
2400
  stepDropoff,
2332
- publishedFunnelFlow,
2333
- });
2401
+ pathFlow,
2402
+ };
2334
2403
  await writeOrPrintAnalyticsOutput({
2335
2404
  format: context.commandInput.format,
2336
- payload,
2337
- table: formatFunnelPathTable({
2338
- date: context.commandInput.date,
2339
- stepDropoff,
2340
- publishedFunnelFlow,
2405
+ payload: buildFunnelPathReportPayload({
2406
+ ...report,
2407
+ workspaceId: context.workspace.id,
2408
+ project: context.project,
2341
2409
  }),
2410
+ table: formatFunnelPathTable(report),
2342
2411
  out: options.out,
2343
2412
  });
2344
2413
  });
2345
- addExamples(analyticsCommand
2414
+ addExamples(addFunnelReportOptions(analyticsCommand
2346
2415
  .command('transitions')
2347
- .description('Download one-day step transitions and drop-offs')
2348
- .option('--workspace <id-or-slug-or-name>', 'Workspace id, slug, or name')
2349
- .option('--project <id-or-slug-or-name>', 'Project id, slug, or name')
2350
- .option('--funnel <id-or-slug-or-name>', 'Funnel id, slug, or name')
2351
- .requiredOption('--date <yyyy-mm-dd>', 'Analytics date')
2352
- .option('--format <table-or-json>', 'Output format: table or json', 'table')
2353
- .option('--out <path>', 'Write output to a file')
2354
- .option('--timezone <iana-timezone>', 'Analytics timezone, for example America/Los_Angeles'), [
2416
+ .description('Download step transitions and drop-offs for a day or date range')), [
2355
2417
  'fgrove analytics transitions --project claimbee --funnel claimbee-ios --date 2026-06-11',
2356
2418
  'fgrove analytics transitions --project claimbee --funnel claimbee-ios --date 2026-06-11 --format json',
2419
+ 'fgrove analytics transitions --project claimbee --funnel claimbee-ios --from 2026-06-01 --to 2026-06-14 --journey-version <journey-version-id>',
2357
2420
  ])
2358
2421
  .action(async (options) => {
2359
2422
  const context = await loadFunnelAnalyticsContext(options);
@@ -2364,20 +2427,55 @@ addExamples(analyticsCommand
2364
2427
  funnelId: context.funnel.id,
2365
2428
  commandInput: context.commandInput,
2366
2429
  });
2367
- assertHasTransitionData(context.commandInput.date, stepDropoff);
2368
- const payload = buildTransitionReportPayload({
2369
- date: context.commandInput.date,
2370
- workspaceId: context.workspace.id,
2371
- project: context.project,
2430
+ assertHasTransitionData(context.commandInput.period.label, stepDropoff);
2431
+ const report = {
2432
+ period: context.commandInput.period,
2433
+ journeyVersion: context.commandInput.journeyVersion,
2372
2434
  stepDropoff,
2373
- });
2435
+ };
2374
2436
  await writeOrPrintAnalyticsOutput({
2375
2437
  format: context.commandInput.format,
2376
- payload,
2377
- table: formatTransitionsTable({
2378
- date: context.commandInput.date,
2379
- stepDropoff,
2438
+ payload: buildTransitionReportPayload({
2439
+ ...report,
2440
+ workspaceId: context.workspace.id,
2441
+ project: context.project,
2442
+ }),
2443
+ table: formatTransitionsTable(report),
2444
+ out: options.out,
2445
+ });
2446
+ });
2447
+ addExamples(analyticsCommand
2448
+ .command('versions')
2449
+ .description('List journey versions with their active days and visitors')
2450
+ .option('--workspace <id-or-slug-or-name>', 'Workspace id, slug, or name')
2451
+ .option('--project <id-or-slug-or-name>', 'Project id, slug, or name')
2452
+ .option('--funnel <id-or-slug-or-name>', 'Funnel id, slug, or name')
2453
+ .option('--format <table-or-json>', 'Output format: table or json', 'table')
2454
+ .option('--out <path>', 'Write output to a file')
2455
+ .option('--timezone <iana-timezone>', 'Analytics timezone, for example America/Los_Angeles'), [
2456
+ 'fgrove analytics versions --project claimbee --funnel claimbee-ios',
2457
+ 'fgrove analytics versions --project claimbee --funnel claimbee-ios --format json',
2458
+ ])
2459
+ .action(async (options) => {
2460
+ const format = normalizeAnalyticsOutputFormat(options.format);
2461
+ const timezone = options.timezone?.trim() || undefined;
2462
+ const target = await resolveFunnelAnalyticsTarget(options);
2463
+ const report = await fetchJourneyVersions({
2464
+ token: target.token,
2465
+ workspaceId: target.workspace.id,
2466
+ projectId: target.project.id,
2467
+ funnelId: target.funnel.id,
2468
+ timezone,
2469
+ today: toAnalyticsDate(new Date(), timezone),
2470
+ });
2471
+ await writeOrPrintAnalyticsOutput({
2472
+ format,
2473
+ payload: buildJourneyVersionsReportPayload({
2474
+ ...report,
2475
+ workspaceId: target.workspace.id,
2476
+ project: target.project,
2380
2477
  }),
2478
+ table: formatJourneyVersionsTable(report),
2381
2479
  out: options.out,
2382
2480
  });
2383
2481
  });
@@ -4,10 +4,10 @@
4
4
  "minimumCliVersion": "0.1.20",
5
5
  "entries": [
6
6
  {
7
- "repositoryCliVersion": "0.1.262",
7
+ "repositoryCliVersion": "0.1.264",
8
8
  "manifest": {
9
9
  "schemaVersion": 1,
10
- "bundleVersion": "2.0.255",
10
+ "bundleVersion": "2.0.257",
11
11
  "stepContractVersion": 3,
12
12
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
13
13
  "managedFiles": [
@@ -45,7 +45,7 @@
45
45
  },
46
46
  {
47
47
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
48
- "sha256": "d733607091b48f87b667e43c68984116b4f5c82cdc5ca04af688ccc7160c0e36"
48
+ "sha256": "a299775572c2aac26afb8905d770417e1dd2f5a0ff1026d5212ba080ef1d5e82"
49
49
  },
50
50
  {
51
51
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -145,16 +145,16 @@
145
145
  },
146
146
  {
147
147
  "path": "funnel-docs.config.json",
148
- "sha256": "3bb975a7ced201ae60030e863b150e51fc8b5d496e0d0fb93fc92c48953e0c39"
148
+ "sha256": "693f0649aedbb45a62b88661d482cbafeb01eb3fdb5279b473732b1a0c83e8ac"
149
149
  }
150
150
  ]
151
151
  }
152
152
  },
153
153
  {
154
- "repositoryCliVersion": "0.1.261",
154
+ "repositoryCliVersion": "0.1.263",
155
155
  "manifest": {
156
156
  "schemaVersion": 1,
157
- "bundleVersion": "2.0.254",
157
+ "bundleVersion": "2.0.256",
158
158
  "stepContractVersion": 3,
159
159
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
160
160
  "managedFiles": [
@@ -192,7 +192,7 @@
192
192
  },
193
193
  {
194
194
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
195
- "sha256": "92a56af5007b51ced39aec37795aeab3a94552e1d242c13f3dbd056a353ebdef"
195
+ "sha256": "afba67a5679827efbd37d706d290e393558d4abf13271b5606e069b1694960e8"
196
196
  },
197
197
  {
198
198
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -292,16 +292,16 @@
292
292
  },
293
293
  {
294
294
  "path": "funnel-docs.config.json",
295
- "sha256": "68a262476d89d22cf3206316ccbf935ae3cf1686a7d951f2024cfffc9e93384d"
295
+ "sha256": "ac03af2c7446ffefd0acd9e28db1c4d6fa7a04848b1c2a562a3e722d16f9a98a"
296
296
  }
297
297
  ]
298
298
  }
299
299
  },
300
300
  {
301
- "repositoryCliVersion": "0.1.260",
301
+ "repositoryCliVersion": "0.1.262",
302
302
  "manifest": {
303
303
  "schemaVersion": 1,
304
- "bundleVersion": "2.0.253",
304
+ "bundleVersion": "2.0.255",
305
305
  "stepContractVersion": 3,
306
306
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
307
307
  "managedFiles": [
@@ -339,7 +339,7 @@
339
339
  },
340
340
  {
341
341
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
342
- "sha256": "3f4c093fce58c01bd66604a5dd371bdd1f3cf3743bc7e556e2a1e871e0b24866"
342
+ "sha256": "d733607091b48f87b667e43c68984116b4f5c82cdc5ca04af688ccc7160c0e36"
343
343
  },
344
344
  {
345
345
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -439,16 +439,16 @@
439
439
  },
440
440
  {
441
441
  "path": "funnel-docs.config.json",
442
- "sha256": "dea21f974e2601112ec12aac3493ece0c0955eb612c6eb790874add999a11822"
442
+ "sha256": "3bb975a7ced201ae60030e863b150e51fc8b5d496e0d0fb93fc92c48953e0c39"
443
443
  }
444
444
  ]
445
445
  }
446
446
  },
447
447
  {
448
- "repositoryCliVersion": "0.1.259",
448
+ "repositoryCliVersion": "0.1.261",
449
449
  "manifest": {
450
450
  "schemaVersion": 1,
451
- "bundleVersion": "2.0.252",
451
+ "bundleVersion": "2.0.254",
452
452
  "stepContractVersion": 3,
453
453
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
454
454
  "managedFiles": [
@@ -486,7 +486,7 @@
486
486
  },
487
487
  {
488
488
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
489
- "sha256": "d1ca070960305b60bc78dae50355a59c8c068b59ea161b4acc9403ec1848b04c"
489
+ "sha256": "92a56af5007b51ced39aec37795aeab3a94552e1d242c13f3dbd056a353ebdef"
490
490
  },
491
491
  {
492
492
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -586,16 +586,16 @@
586
586
  },
587
587
  {
588
588
  "path": "funnel-docs.config.json",
589
- "sha256": "b683d23440209016d94de8319f46040e4e174567d3cc0a1f8ede194c29cc3e76"
589
+ "sha256": "68a262476d89d22cf3206316ccbf935ae3cf1686a7d951f2024cfffc9e93384d"
590
590
  }
591
591
  ]
592
592
  }
593
593
  },
594
594
  {
595
- "repositoryCliVersion": "0.1.258",
595
+ "repositoryCliVersion": "0.1.260",
596
596
  "manifest": {
597
597
  "schemaVersion": 1,
598
- "bundleVersion": "2.0.251",
598
+ "bundleVersion": "2.0.253",
599
599
  "stepContractVersion": 3,
600
600
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
601
601
  "managedFiles": [
@@ -633,7 +633,7 @@
633
633
  },
634
634
  {
635
635
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
636
- "sha256": "871dd4aa34ed91d4bf366e8ca7f0882f78d9ae1098ee2c587064743ecd81feba"
636
+ "sha256": "3f4c093fce58c01bd66604a5dd371bdd1f3cf3743bc7e556e2a1e871e0b24866"
637
637
  },
638
638
  {
639
639
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -733,16 +733,16 @@
733
733
  },
734
734
  {
735
735
  "path": "funnel-docs.config.json",
736
- "sha256": "c41f35a830e5a58e5896f76afb97d4313308734ad93c0cc3636b4495927d170e"
736
+ "sha256": "dea21f974e2601112ec12aac3493ece0c0955eb612c6eb790874add999a11822"
737
737
  }
738
738
  ]
739
739
  }
740
740
  },
741
741
  {
742
- "repositoryCliVersion": "0.1.256",
742
+ "repositoryCliVersion": "0.1.259",
743
743
  "manifest": {
744
744
  "schemaVersion": 1,
745
- "bundleVersion": "2.0.249",
745
+ "bundleVersion": "2.0.252",
746
746
  "stepContractVersion": 3,
747
747
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
748
748
  "managedFiles": [
@@ -780,7 +780,7 @@
780
780
  },
781
781
  {
782
782
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
783
- "sha256": "800853d3acaf8ccb9f56891b7d83a1a17c8fe8e63f40bc46029bc7b76cdb2ddd"
783
+ "sha256": "d1ca070960305b60bc78dae50355a59c8c068b59ea161b4acc9403ec1848b04c"
784
784
  },
785
785
  {
786
786
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -788,7 +788,7 @@
788
788
  },
789
789
  {
790
790
  "path": "docs/funnelsgrove/qa/local.md",
791
- "sha256": "97da7e26c5dbe8f63e654e4e0a035a4ecfbb9bcfd80db67d45c627141d6a2756"
791
+ "sha256": "c8a83c33cd33bea6d5efde91d7c479505f77077f16de8073064baacbfad98e5f"
792
792
  },
793
793
  {
794
794
  "path": "docs/funnelsgrove/qa/paywall-checkout.md",
@@ -880,16 +880,16 @@
880
880
  },
881
881
  {
882
882
  "path": "funnel-docs.config.json",
883
- "sha256": "5358d40a9accbc34e79924d07053d17f74915bb90db963756c208c00e90541e8"
883
+ "sha256": "b683d23440209016d94de8319f46040e4e174567d3cc0a1f8ede194c29cc3e76"
884
884
  }
885
885
  ]
886
886
  }
887
887
  },
888
888
  {
889
- "repositoryCliVersion": "0.1.255",
889
+ "repositoryCliVersion": "0.1.258",
890
890
  "manifest": {
891
891
  "schemaVersion": 1,
892
- "bundleVersion": "2.0.248",
892
+ "bundleVersion": "2.0.251",
893
893
  "stepContractVersion": 3,
894
894
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
895
895
  "managedFiles": [
@@ -911,7 +911,7 @@
911
911
  },
912
912
  {
913
913
  "path": "docs/funnelsgrove/contracts/content-answers.md",
914
- "sha256": "17c8a91800ec1d2247b1e0fd12cc80fbfce162297aa928432cc0a574acd9fc06"
914
+ "sha256": "38cd477fa65cb00718c6609ede520bc5b7538f331072c888a6cc32e8d0130d27"
915
915
  },
916
916
  {
917
917
  "path": "docs/funnelsgrove/contracts/flow-routing.md",
@@ -927,7 +927,7 @@
927
927
  },
928
928
  {
929
929
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
930
- "sha256": "19ea25028aebc54e553c223385ed1bf704a4f2bdef817250e01e566866034673"
930
+ "sha256": "871dd4aa34ed91d4bf366e8ca7f0882f78d9ae1098ee2c587064743ecd81feba"
931
931
  },
932
932
  {
933
933
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -935,7 +935,7 @@
935
935
  },
936
936
  {
937
937
  "path": "docs/funnelsgrove/qa/local.md",
938
- "sha256": "97da7e26c5dbe8f63e654e4e0a035a4ecfbb9bcfd80db67d45c627141d6a2756"
938
+ "sha256": "c8a83c33cd33bea6d5efde91d7c479505f77077f16de8073064baacbfad98e5f"
939
939
  },
940
940
  {
941
941
  "path": "docs/funnelsgrove/qa/paywall-checkout.md",
@@ -1027,7 +1027,7 @@
1027
1027
  },
1028
1028
  {
1029
1029
  "path": "funnel-docs.config.json",
1030
- "sha256": "07db87377a3d12b6bcf119d01bebffbbbb4702bb3cf83b8059132adbd2486a21"
1030
+ "sha256": "c41f35a830e5a58e5896f76afb97d4313308734ad93c0cc3636b4495927d170e"
1031
1031
  }
1032
1032
  ]
1033
1033
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/cli",
3
- "version": "0.1.262",
3
+ "version": "0.1.264",
4
4
  "description": "FunnelsGrove command-line tools for editing, syncing, and publishing funnels",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@funnelsgrove/analytics": "0.7.0",
44
- "@funnelsgrove/payments": "0.26.0",
44
+ "@funnelsgrove/payments": "0.27.0",
45
45
  "vitest": "^3.0.0"
46
46
  }
47
47
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "bundleVersion": "2.0.255",
3
+ "bundleVersion": "2.0.257",
4
4
  "stepContractVersion": 3,
5
5
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
6
6
  "managedFiles": [
@@ -38,7 +38,7 @@
38
38
  },
39
39
  {
40
40
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
41
- "sha256": "d733607091b48f87b667e43c68984116b4f5c82cdc5ca04af688ccc7160c0e36"
41
+ "sha256": "a299775572c2aac26afb8905d770417e1dd2f5a0ff1026d5212ba080ef1d5e82"
42
42
  },
43
43
  {
44
44
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  {
140
140
  "path": "funnel-docs.config.json",
141
- "sha256": "3bb975a7ced201ae60030e863b150e51fc8b5d496e0d0fb93fc92c48953e0c39"
141
+ "sha256": "693f0649aedbb45a62b88661d482cbafeb01eb3fdb5279b473732b1a0c83e8ac"
142
142
  }
143
143
  ]
144
144
  }
@@ -17,7 +17,7 @@ Supported read versions: `1`, `2`, `3`. Authoring and publish target version `3`
17
17
 
18
18
  ### Package release order
19
19
 
20
- Release `@funnelsgrove/sdk` `0.4.0` first, then `@funnelsgrove/runtime` `0.25.0`, then `@funnelsgrove/analytics` `0.7.0`, then `@funnelsgrove/payments` `0.26.0`. The production deploy verifies the zero-traffic API candidate, publishes and verifies `@funnelsgrove/cli` `0.1.262`, and only then promotes the candidate to production traffic. The serving API must never advertise an unpublished preferred CLI. Publishing packages and deploying production remain separately approved operational actions.
20
+ Release `@funnelsgrove/sdk` `0.4.0` first, then `@funnelsgrove/runtime` `0.25.0`, then `@funnelsgrove/analytics` `0.7.0`, then `@funnelsgrove/payments` `0.27.0`. The production deploy verifies the zero-traffic API candidate, publishes and verifies `@funnelsgrove/cli` `0.1.264`, and only then promotes the candidate to production traffic. The serving API must never advertise an unpublished preferred CLI. Publishing packages and deploying production remain separately approved operational actions.
21
21
  <!-- funnelsgrove:generated:end contract-v3/migration/step-contract-v3 -->
22
22
 
23
23
  ## Version-last policy
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "bundleVersion": "2.0.255",
3
+ "bundleVersion": "2.0.257",
4
4
  "contractSource": "funnelsgrove-repository://apps/funnel-runtime/contracts/step-contract-v2.json",
5
5
  "fullyGenerated": [
6
6
  ".funnelsgrove-docs.json",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "bundleVersion": "2.0.255",
3
+ "bundleVersion": "2.0.257",
4
4
  "stepContractVersion": 3,
5
5
  "contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
6
6
  "managedFiles": [
@@ -38,7 +38,7 @@
38
38
  },
39
39
  {
40
40
  "path": "docs/funnelsgrove/migrations/step-contract-v3.md",
41
- "sha256": "d733607091b48f87b667e43c68984116b4f5c82cdc5ca04af688ccc7160c0e36"
41
+ "sha256": "a299775572c2aac26afb8905d770417e1dd2f5a0ff1026d5212ba080ef1d5e82"
42
42
  },
43
43
  {
44
44
  "path": "docs/funnelsgrove/qa/analytics.md",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  {
140
140
  "path": "funnel-docs.config.json",
141
- "sha256": "3bb975a7ced201ae60030e863b150e51fc8b5d496e0d0fb93fc92c48953e0c39"
141
+ "sha256": "693f0649aedbb45a62b88661d482cbafeb01eb3fdb5279b473732b1a0c83e8ac"
142
142
  }
143
143
  ]
144
144
  }