@erdoai/cli 0.139.1 → 0.140.1

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.
Files changed (2) hide show
  1. package/dist/index.js +64 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15,13 +15,34 @@ function advertiserVerificationAction(container) {
15
15
 
16
16
  // src/refresh.ts
17
17
  function describeRefreshTrigger(state) {
18
- if (state.disarmed) return "disarmed \u2014 the experiment has settled";
19
- if (state.strategy === "live_webhook") return "incoming webhook events \u2014 page views do not trigger this feed";
20
- if (state.strategy === "live_native_poll") return "not running \u2014 native polling is unavailable; configure script_js with a schedule or live_webhook";
21
- if (!state.job_id) return "not running \u2014 no linked job; configure the refresh again";
22
- if (state.job_enabled === false) return "not running \u2014 the linked job is disabled; configure the refresh again";
23
- if (state.schedule) return state.schedule_enabled === false ? `cron ${state.schedule} is disabled` : `cron: ${state.schedule}`;
24
- return state.refresh_on_view_enabled !== false ? "runs on view \u2014 when a bound page is opened and the data is stale" : "manual only \u2014 page views do not trigger this refresh";
18
+ const event = describeEventTriggers(state);
19
+ if (state.disarmed) return event ? `disarmed \u2014 the experiment has settled; ${event}` : "disarmed \u2014 the experiment has settled";
20
+ if (state.strategy === "live_webhook") return event ? `incoming webhook events \u2014 page views do not trigger this feed; ${event}` : "incoming webhook events \u2014 page views do not trigger this feed";
21
+ if (state.strategy === "live_native_poll") return event ? `not running \u2014 native polling is unavailable; ${event}` : "not running \u2014 native polling is unavailable; configure script_js with a schedule or live_webhook";
22
+ if (!state.job_id) return event ? `not running \u2014 no linked job; ${event}` : "not running \u2014 no linked job; configure the refresh again";
23
+ if (state.job_enabled === false) return event ? `not running \u2014 the linked job is disabled; ${event}` : "not running \u2014 the linked job is disabled; configure the refresh again";
24
+ const trigger = state.schedule ? state.schedule_enabled === false ? `cron ${state.schedule} is disabled` : `cron: ${state.schedule}` : state.refresh_on_view_enabled !== false ? "runs on view \u2014 when a bound page is opened and the data is stale" : event ? void 0 : "manual only \u2014 page views do not trigger this refresh";
25
+ return [trigger, event, state.test_run_success === false ? "configuration test failed" : void 0].filter(Boolean).join("; ");
26
+ }
27
+ function describeEventTriggers(state) {
28
+ if (!state.event_triggers?.length) {
29
+ if (!state.event_dataset_ids?.length) return void 0;
30
+ return `event-driven \u2014 configured for ${state.event_dataset_ids.join(", ")} (debounce ${state.event_debounce_seconds ?? 0}s)`;
31
+ }
32
+ const triggers = state.event_triggers;
33
+ const ownerActive = !!state.job_id && state.disarmed !== true && state.job_enabled !== false;
34
+ const enabled = ownerActive ? triggers.filter((trigger) => trigger.enabled) : [];
35
+ const disabled = ownerActive ? triggers.filter((trigger) => !trigger.enabled) : triggers;
36
+ const parts = [];
37
+ if (enabled.length) {
38
+ const debounce = new Set(enabled.map((trigger) => trigger.debounce_seconds));
39
+ parts.push(`event-driven \u2014 enabled for ${enabled.map((trigger) => trigger.dataset_id).join(", ")}${debounce.size === 1 ? ` (debounce ${enabled[0].debounce_seconds}s)` : ""}`);
40
+ }
41
+ if (disabled.length || enabled.length !== triggers.length) {
42
+ const unavailable = disabled.map((trigger) => trigger.dataset_id);
43
+ parts.push(`event-driven \u2014 disabled for ${unavailable.join(", ")}`);
44
+ }
45
+ return parts.join("; ");
25
46
  }
26
47
  function describeRefreshWrites(strategy, mode, key, liveMode) {
27
48
  if (strategy?.startsWith("live_")) return liveMode === "append" ? "append \u2014 each incoming event adds rows" : "replace \u2014 each incoming event replaces the current rows";
@@ -7470,6 +7491,8 @@ refreshCmd.command("show <slug>").description(
7470
7491
  if (res.experiment_run_id) rows.push(["experiment", res.experiment_run_id]);
7471
7492
  rows.push(["writes", describeRefreshWrites(res.strategy, res.refresh_mode, res.key_column, res.live_write_mode)]);
7472
7493
  rows.push(["trigger", describeRefreshTrigger(res)]);
7494
+ const eventTriggers = describeEventTriggers(res);
7495
+ if (eventTriggers) rows.push(["event triggers", eventTriggers]);
7473
7496
  if (res.schedule) {
7474
7497
  const zone = res.schedule_timezone || "UTC";
7475
7498
  rows.push([
@@ -7520,7 +7543,7 @@ refreshCmd.command("show <slug>").description(
7520
7543
  }
7521
7544
  if (res.job_id) rows.push(["job", res.job_id]);
7522
7545
  printAlignedTable(["setting", "value"], rows);
7523
- if (!res.strategy?.startsWith("live_") && res.job_id && res.job_enabled !== false && !res.disarmed && !res.schedule && !res.refresh_on_view_enabled) {
7546
+ if (!res.strategy?.startsWith("live_") && res.job_id && res.job_enabled !== false && !res.disarmed && !res.schedule && !res.refresh_on_view_enabled && !eventTriggers) {
7524
7547
  console.log(
7525
7548
  `
7526
7549
  Nothing triggers this refresh on its own \u2014 it runs only when asked: erdo datasets refresh run ${res.dataset_slug}`
@@ -7554,7 +7577,7 @@ refreshCmd.command("set <slug>").description(
7554
7577
  ).option("--agent-prompt <textOr@file>", "instructions for the agent_run strategy, inline or @path").option(
7555
7578
  "--context-datasets <csv>",
7556
7579
  "slugs of other datasets the recipe reads besides the one it writes"
7557
- ).option(
7580
+ ).option("--event-datasets <csv>", "dataset slugs whose writes trigger this refresh (up to 16, comma-separated)").option("--event-debounce <seconds>", "wait after the first source write to coalesce a burst (integer 0\u20133600 seconds)").option(
7558
7581
  "--on-view",
7559
7582
  "let a page view trigger this refresh (the platform default); pass --no-on-view to turn it off. Sent only when you pass one of the two"
7560
7583
  ).option("--no-on-view", "stop page views from triggering this refresh").option(
@@ -7617,6 +7640,31 @@ refreshCmd.command("set <slug>").description(
7617
7640
  const slugs = opts.contextDatasets.split(",").map((s) => s.trim()).filter(Boolean);
7618
7641
  if (slugs.length) body.context_dataset_slugs = slugs;
7619
7642
  }
7643
+ let eventDatasetSlugs;
7644
+ if (opts.eventDatasets !== void 0) {
7645
+ eventDatasetSlugs = opts.eventDatasets.split(",").map((s) => s.trim());
7646
+ if (!eventDatasetSlugs.length || eventDatasetSlugs.some((slug2) => !slug2)) {
7647
+ fail(new Error("--event-datasets must include at least one non-blank dataset slug"));
7648
+ return;
7649
+ }
7650
+ if (eventDatasetSlugs.length > 16) {
7651
+ fail(new Error("--event-datasets supports at most 16 dataset slugs"));
7652
+ return;
7653
+ }
7654
+ body.event_dataset_slugs = eventDatasetSlugs;
7655
+ }
7656
+ if (opts.eventDebounce !== void 0) {
7657
+ const value = Number(opts.eventDebounce);
7658
+ if (!opts.eventDebounce.trim() || !Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > 3600) {
7659
+ fail(new Error("--event-debounce must be a finite integer between 0 and 3600"));
7660
+ return;
7661
+ }
7662
+ if (!eventDatasetSlugs?.length) {
7663
+ fail(new Error("--event-debounce requires non-empty --event-datasets"));
7664
+ return;
7665
+ }
7666
+ body.event_debounce_seconds = value;
7667
+ }
7620
7668
  if (opts.onView !== void 0) body.refresh_on_view_enabled = opts.onView;
7621
7669
  if (opts.staleAfter !== void 0) {
7622
7670
  body.refresh_on_view_stale_after_seconds = opts.staleAfter;
@@ -7637,7 +7685,13 @@ refreshCmd.command("set <slug>").description(
7637
7685
  `Installed a ${res.strategy} refresh on ${res.dataset_slug}${res.previous_strategy ? ` (replacing ${res.previous_strategy})` : ""}`
7638
7686
  );
7639
7687
  console.log(`writes: ${describeRefreshWrites(res.strategy, res.refresh_mode, body.key_column, body.live_write_mode)}`);
7640
- console.log(describeRefreshTrigger({ ...res, refresh_on_view_enabled: body.refresh_on_view_enabled }));
7688
+ console.log(describeRefreshTrigger({
7689
+ ...res,
7690
+ event_dataset_ids: res.event_dataset_ids,
7691
+ event_debounce_seconds: res.event_debounce_seconds ?? body.event_debounce_seconds,
7692
+ refresh_on_view_enabled: body.refresh_on_view_enabled,
7693
+ test_run_success: res.test_run?.success
7694
+ }));
7641
7695
  if (res.job_id) console.log(`job: ${res.job_id}`);
7642
7696
  if (res.webhook_url) {
7643
7697
  console.log(`webhook url: ${res.webhook_url}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erdoai/cli",
3
- "version": "0.139.1",
3
+ "version": "0.140.1",
4
4
  "description": "Erdo CLI \u2014 drive datasets, pages, and evals from the terminal or CI",
5
5
  "type": "module",
6
6
  "bin": {