@gurulu/cli 0.4.7 → 1.0.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 (190) hide show
  1. package/LICENSE +92 -0
  2. package/README.md +35 -106
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +25751 -0
  6. package/dist/commands/auth.d.ts +23 -20
  7. package/dist/commands/auth.d.ts.map +1 -0
  8. package/dist/commands/doctor.d.ts +20 -6
  9. package/dist/commands/doctor.d.ts.map +1 -0
  10. package/dist/commands/init.d.ts +33 -11
  11. package/dist/commands/init.d.ts.map +1 -0
  12. package/dist/commands/pull.d.ts +13 -0
  13. package/dist/commands/pull.d.ts.map +1 -0
  14. package/dist/commands/push.d.ts +40 -0
  15. package/dist/commands/push.d.ts.map +1 -0
  16. package/dist/commands/validate.d.ts +36 -0
  17. package/dist/commands/validate.d.ts.map +1 -0
  18. package/dist/index.d.ts +4 -1
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +25326 -876
  21. package/dist/lib/api.d.ts +139 -0
  22. package/dist/lib/api.d.ts.map +1 -0
  23. package/dist/lib/codegen.d.ts +4 -0
  24. package/dist/lib/codegen.d.ts.map +1 -0
  25. package/dist/lib/config.d.ts +43 -0
  26. package/dist/lib/config.d.ts.map +1 -0
  27. package/dist/lib/detect.d.ts +27 -0
  28. package/dist/lib/detect.d.ts.map +1 -0
  29. package/dist/lib/detect.js +106 -0
  30. package/dist/lib/exec-install.d.ts +21 -0
  31. package/dist/lib/exec-install.d.ts.map +1 -0
  32. package/dist/lib/install-plan.d.ts +25 -0
  33. package/dist/lib/install-plan.d.ts.map +1 -0
  34. package/dist/lib/install-plan.js +161 -0
  35. package/package.json +51 -20
  36. package/bin/gurulu.js +0 -2
  37. package/dist/api-client.d.ts +0 -33
  38. package/dist/api-client.js +0 -175
  39. package/dist/commands/add-server.d.ts +0 -9
  40. package/dist/commands/add-server.js +0 -162
  41. package/dist/commands/alerts.d.ts +0 -27
  42. package/dist/commands/alerts.js +0 -309
  43. package/dist/commands/api-keys.d.ts +0 -20
  44. package/dist/commands/api-keys.js +0 -130
  45. package/dist/commands/attribution.d.ts +0 -22
  46. package/dist/commands/attribution.js +0 -111
  47. package/dist/commands/audiences.d.ts +0 -23
  48. package/dist/commands/audiences.js +0 -243
  49. package/dist/commands/audit.d.ts +0 -20
  50. package/dist/commands/audit.js +0 -130
  51. package/dist/commands/auth.js +0 -249
  52. package/dist/commands/chat.d.ts +0 -19
  53. package/dist/commands/chat.js +0 -118
  54. package/dist/commands/config.d.ts +0 -10
  55. package/dist/commands/config.js +0 -92
  56. package/dist/commands/consent.d.ts +0 -27
  57. package/dist/commands/consent.js +0 -233
  58. package/dist/commands/conversion-paths.d.ts +0 -19
  59. package/dist/commands/conversion-paths.js +0 -55
  60. package/dist/commands/db.d.ts +0 -25
  61. package/dist/commands/db.js +0 -330
  62. package/dist/commands/destinations.d.ts +0 -20
  63. package/dist/commands/destinations.js +0 -191
  64. package/dist/commands/doctor.js +0 -360
  65. package/dist/commands/errors.d.ts +0 -27
  66. package/dist/commands/errors.js +0 -121
  67. package/dist/commands/events.d.ts +0 -33
  68. package/dist/commands/events.js +0 -371
  69. package/dist/commands/experiments.d.ts +0 -22
  70. package/dist/commands/experiments.js +0 -264
  71. package/dist/commands/funnels.d.ts +0 -17
  72. package/dist/commands/funnels.js +0 -203
  73. package/dist/commands/goals.d.ts +0 -18
  74. package/dist/commands/goals.js +0 -214
  75. package/dist/commands/heatmap.d.ts +0 -27
  76. package/dist/commands/heatmap.js +0 -112
  77. package/dist/commands/identity.d.ts +0 -29
  78. package/dist/commands/identity.js +0 -328
  79. package/dist/commands/init.js +0 -215
  80. package/dist/commands/insights.d.ts +0 -10
  81. package/dist/commands/insights.js +0 -77
  82. package/dist/commands/install.d.ts +0 -259
  83. package/dist/commands/install.js +0 -1590
  84. package/dist/commands/login.d.ts +0 -20
  85. package/dist/commands/login.js +0 -170
  86. package/dist/commands/logout.d.ts +0 -10
  87. package/dist/commands/logout.js +0 -41
  88. package/dist/commands/playground.d.ts +0 -11
  89. package/dist/commands/playground.js +0 -47
  90. package/dist/commands/releases.d.ts +0 -17
  91. package/dist/commands/releases.js +0 -54
  92. package/dist/commands/replay.d.ts +0 -18
  93. package/dist/commands/replay.js +0 -64
  94. package/dist/commands/secrets.d.ts +0 -19
  95. package/dist/commands/secrets.js +0 -145
  96. package/dist/commands/setup.d.ts +0 -21
  97. package/dist/commands/setup.js +0 -67
  98. package/dist/commands/sites.d.ts +0 -18
  99. package/dist/commands/sites.js +0 -139
  100. package/dist/commands/skad.d.ts +0 -18
  101. package/dist/commands/skad.js +0 -53
  102. package/dist/commands/sourcemap.d.ts +0 -33
  103. package/dist/commands/sourcemap.js +0 -204
  104. package/dist/commands/status.d.ts +0 -7
  105. package/dist/commands/status.js +0 -136
  106. package/dist/commands/upgrade.d.ts +0 -21
  107. package/dist/commands/upgrade.js +0 -183
  108. package/dist/commands/warehouse.d.ts +0 -20
  109. package/dist/commands/warehouse.js +0 -65
  110. package/dist/commands/warehouses.d.ts +0 -17
  111. package/dist/commands/warehouses.js +0 -182
  112. package/dist/commands/watch.d.ts +0 -45
  113. package/dist/commands/watch.js +0 -258
  114. package/dist/commands/whoami.d.ts +0 -9
  115. package/dist/commands/whoami.js +0 -50
  116. package/dist/config.d.ts +0 -75
  117. package/dist/config.js +0 -329
  118. package/dist/frameworks/detect.d.ts +0 -8
  119. package/dist/frameworks/detect.js +0 -458
  120. package/dist/install-intent-proposal.d.ts +0 -99
  121. package/dist/install-intent-proposal.js +0 -202
  122. package/dist/utils/api.d.ts +0 -20
  123. package/dist/utils/api.js +0 -47
  124. package/dist/utils/config.d.ts +0 -13
  125. package/dist/utils/config.js +0 -30
  126. package/dist/utils/confirm.d.ts +0 -17
  127. package/dist/utils/confirm.js +0 -40
  128. package/dist/utils/dry-run.d.ts +0 -20
  129. package/dist/utils/dry-run.js +0 -67
  130. package/dist/utils/from-file.d.ts +0 -9
  131. package/dist/utils/from-file.js +0 -72
  132. package/dist/utils/redact.d.ts +0 -14
  133. package/dist/utils/redact.js +0 -48
  134. package/dist/utils/ui.d.ts +0 -14
  135. package/dist/utils/ui.js +0 -59
  136. package/scripts/.gitkeep +0 -0
  137. package/scripts/README-gurulu-agentic-install.md +0 -114
  138. package/scripts/README-gurulu-scan.md +0 -98
  139. package/scripts/audit-cli-scopes.mjs +0 -204
  140. package/scripts/backfill-tenant-id.mjs +0 -172
  141. package/scripts/backfill-tenant-links.ts +0 -252
  142. package/scripts/backup-clickhouse.sh +0 -27
  143. package/scripts/backup-postgres.sh +0 -19
  144. package/scripts/bootstrap-runtime-schema.mjs +0 -87
  145. package/scripts/bootstrap-stripe.mjs +0 -158
  146. package/scripts/gurulu-agentic-install.lib.cjs +0 -762
  147. package/scripts/gurulu-agentic-install.mjs +0 -623
  148. package/scripts/gurulu-scan.lib.cjs +0 -1509
  149. package/scripts/gurulu-scan.mjs +0 -91
  150. package/scripts/gurulu-verify-install.lib.cjs +0 -334
  151. package/scripts/gurulu-verify-install.mjs +0 -59
  152. package/scripts/init-ssl.sh +0 -26
  153. package/scripts/migrate-flow-graph-enums.sh +0 -86
  154. package/scripts/monitor-disk.sh +0 -24
  155. package/scripts/patches/astro.patch.cjs +0 -74
  156. package/scripts/patches/auto-instrument/ast-helper.cjs +0 -480
  157. package/scripts/patches/auto-instrument/astro.cjs +0 -273
  158. package/scripts/patches/auto-instrument/express.cjs +0 -383
  159. package/scripts/patches/auto-instrument/fastify.cjs +0 -262
  160. package/scripts/patches/auto-instrument/hono.cjs +0 -392
  161. package/scripts/patches/auto-instrument/index.cjs +0 -80
  162. package/scripts/patches/auto-instrument/nestjs.cjs +0 -286
  163. package/scripts/patches/auto-instrument/nextjs-app-router.cjs +0 -345
  164. package/scripts/patches/auto-instrument/nextjs-pages.cjs +0 -361
  165. package/scripts/patches/auto-instrument/remix.cjs +0 -168
  166. package/scripts/patches/auto-instrument/sdk-helper-map.cjs +0 -241
  167. package/scripts/patches/auto-instrument/singleton-helper.cjs +0 -193
  168. package/scripts/patches/auto-instrument/sveltekit.cjs +0 -161
  169. package/scripts/patches/auto-instrument/vite-react.cjs +0 -37
  170. package/scripts/patches/auto-instrument/vue.cjs +0 -196
  171. package/scripts/patches/express.patch.cjs +0 -99
  172. package/scripts/patches/fastify.patch.cjs +0 -108
  173. package/scripts/patches/index.cjs +0 -300
  174. package/scripts/patches/nestjs.patch.cjs +0 -112
  175. package/scripts/patches/nextjs-app-router.patch.cjs +0 -97
  176. package/scripts/patches/nextjs-pages.patch.cjs +0 -97
  177. package/scripts/patches/remix.patch.cjs +0 -75
  178. package/scripts/patches/sveltekit.patch.cjs +0 -72
  179. package/scripts/patches/vite-react.patch.cjs +0 -73
  180. package/scripts/patches/vue.patch.cjs +0 -82
  181. package/scripts/renew-ssl.sh +0 -14
  182. package/scripts/resolve-migration.sh +0 -23
  183. package/scripts/seed-cli-dev-keys.mjs +0 -130
  184. package/scripts/seed-test-data.mjs +0 -391
  185. package/scripts/spike-browserless.ts +0 -65
  186. package/scripts/tenant-pivot-consistency-check.mjs +0 -205
  187. package/scripts/tenant-pivot-phase-3-cleanup.lib.cjs +0 -258
  188. package/scripts/tenant-pivot-phase-3-cleanup.mjs +0 -98
  189. package/scripts/test-identity-resolution.ts +0 -804
  190. package/scripts/validate-gurulu-schemas.mjs +0 -79
@@ -1,371 +0,0 @@
1
- "use strict";
2
- /**
3
- * Phase 19.5 W2 B1 — `gurulu events list` / `gurulu events tail`.
4
- *
5
- * Replaces the legacy Phase 10 `events` command (which talked to a
6
- * now-defunct credential store) with CLI-bearer-auth subcommands that hit
7
- * `/api/cli/events` (list) and `/api/cli/events/tail` (SSE stream).
8
- *
9
- * All subcommands support `--json` for scripting + agent parsing.
10
- */
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports._loadActiveProfile = void 0;
13
- exports.eventsCommand = eventsCommand;
14
- exports.legacyEventsCommand = legacyEventsCommand;
15
- const api_client_1 = require("../api-client");
16
- const config_1 = require("../config");
17
- const ui_1 = require("../utils/ui");
18
- async function eventsCommand(args) {
19
- const action = args.action || 'list';
20
- switch (action) {
21
- case 'list':
22
- return listCmd(args);
23
- case 'tail':
24
- return tailCmd(args);
25
- case 'schema':
26
- return schemaCmd(args);
27
- case 'define':
28
- return defineCmd(args);
29
- case 'verify':
30
- return verifyCmd(args);
31
- case 'templates':
32
- return templatesCmd(args);
33
- default:
34
- (0, ui_1.error)(`Unknown events action: ${action}`);
35
- (0, ui_1.info)('Usage: gurulu events [list|tail|schema|define|verify|templates]');
36
- process.exit(1);
37
- }
38
- }
39
- function parseFilterFlag(raw) {
40
- if (!raw)
41
- return {};
42
- // Support `event_name:foo` or `name=foo`
43
- const m = raw.match(/^(?:event_name|name)\s*[:=]\s*(.+)$/);
44
- if (m)
45
- return { eventName: m[1] };
46
- return { eventName: raw };
47
- }
48
- async function listCmd(args) {
49
- const qs = new URLSearchParams();
50
- if (args.site)
51
- qs.set('site', args.site);
52
- const filter = parseFilterFlag(args.filter);
53
- const eventName = args.eventName || filter.eventName;
54
- if (eventName)
55
- qs.set('event_name', eventName);
56
- if (args.since)
57
- qs.set('since', args.since);
58
- if (args.limit)
59
- qs.set('limit', String(args.limit));
60
- const path = `/api/cli/events${qs.toString() ? `?${qs.toString()}` : ''}`;
61
- const body = await (0, api_client_1.cliApiJson)(path, {
62
- profile: args.profile,
63
- });
64
- if (args.json) {
65
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
66
- return;
67
- }
68
- if (body.warning) {
69
- process.stderr.write((0, ui_1.dim)(`(warning: ${body.warning})\n`));
70
- }
71
- const events = body.events || [];
72
- if (events.length === 0) {
73
- (0, ui_1.info)('No events found in the selected window.');
74
- return;
75
- }
76
- process.stdout.write(['TS', 'EVENT', 'SITE', 'URL'].join('\t') + '\n');
77
- for (const e of events) {
78
- process.stdout.write([
79
- String(e.timestamp || e.event_ts || '-'),
80
- String(e.event_name || '-'),
81
- String(e.site_id || '-'),
82
- String(e.page_url || e.url || '-').slice(0, 60),
83
- ].join('\t') + '\n');
84
- }
85
- }
86
- async function tailCmd(args) {
87
- const qs = new URLSearchParams();
88
- if (args.site)
89
- qs.set('site', args.site);
90
- if (args.eventName)
91
- qs.set('event_name', args.eventName);
92
- const path = `/api/cli/events/tail${qs.toString() ? `?${qs.toString()}` : ''}`;
93
- // cliApi handles auth + base url; we then stream the body ourselves.
94
- const res = await (0, api_client_1.cliApi)(path, {
95
- profile: args.profile,
96
- headers: { accept: 'text/event-stream' },
97
- });
98
- if (!res.body) {
99
- (0, ui_1.error)('Tail stream returned no body.');
100
- process.exit(1);
101
- }
102
- (0, ui_1.info)('Streaming events — press Ctrl+C to stop');
103
- const reader = res.body.getReader?.();
104
- if (!reader) {
105
- // Node streams fallback
106
- const chunks = [];
107
- for await (const chunk of res.body) {
108
- process.stdout.write(formatFrame(Buffer.from(chunk).toString('utf8'), !!args.json));
109
- }
110
- void chunks;
111
- return;
112
- }
113
- const decoder = new TextDecoder();
114
- // eslint-disable-next-line no-constant-condition
115
- while (true) {
116
- const { done, value } = await reader.read();
117
- if (done)
118
- return;
119
- const text = decoder.decode(value, { stream: true });
120
- process.stdout.write(formatFrame(text, !!args.json));
121
- }
122
- }
123
- /* ── schema: show property schema & implementation examples ───────── */
124
- async function schemaCmd(args) {
125
- if (!args.eventName) {
126
- (0, ui_1.error)('Event name is required. Usage: gurulu events schema --event-name <name> --site <id>');
127
- process.exit(1);
128
- }
129
- if (!args.site) {
130
- (0, ui_1.error)('--site is required for schema lookup.');
131
- process.exit(1);
132
- }
133
- const path = `/api/cli/events/schema/${encodeURIComponent(args.eventName)}?siteId=${args.site}`;
134
- const data = await (0, api_client_1.cliApiJson)(path, { profile: args.profile });
135
- if (args.json) {
136
- process.stdout.write(JSON.stringify(data, null, 2) + '\n');
137
- return;
138
- }
139
- console.log((0, ui_1.bold)(`\nEvent: ${data.eventName}`));
140
- if (data.source)
141
- console.log(`Source: ${data.source}`);
142
- if (data.description)
143
- console.log(`Description: ${data.description}`);
144
- if (data.isRevenue)
145
- console.log((0, ui_1.yellow)(`Revenue event: ${data.revenueNote || 'yes'}`));
146
- if (data.propertySchema?.length) {
147
- console.log((0, ui_1.bold)('\nProperties:'));
148
- for (const p of data.propertySchema) {
149
- const req = p.required ? (0, ui_1.red)('REQUIRED') : (0, ui_1.dim)('optional');
150
- const fmt = p.format ? (0, ui_1.cyan)(` [${p.format}]`) : '';
151
- const ex = p.example !== undefined ? (0, ui_1.dim)(` e.g. ${JSON.stringify(p.example)}`) : '';
152
- console.log(` ${p.name}: ${(0, ui_1.cyan)(p.type)} (${req})${fmt} — ${p.description || ''}${ex}`);
153
- }
154
- }
155
- if (data.implementation && Object.keys(data.implementation).length) {
156
- console.log((0, ui_1.bold)('\nImplementation:'));
157
- for (const [platform, code] of Object.entries(data.implementation)) {
158
- console.log(` ${(0, ui_1.cyan)(`[${platform}]`)}: ${code}`);
159
- }
160
- }
161
- console.log('');
162
- }
163
- /* ── define: create a new custom event definition ────────────────── */
164
- async function defineCmd(args) {
165
- if (!args.site) {
166
- (0, ui_1.error)('--site is required.');
167
- process.exit(1);
168
- }
169
- if (!args.eventName) {
170
- (0, ui_1.error)('--event-name is required.');
171
- process.exit(1);
172
- }
173
- if (!args.displayName) {
174
- (0, ui_1.error)('--display-name is required.');
175
- process.exit(1);
176
- }
177
- let propertySchema = [];
178
- if (args.properties) {
179
- try {
180
- propertySchema = JSON.parse(args.properties);
181
- }
182
- catch {
183
- (0, ui_1.error)('Invalid JSON for --properties');
184
- process.exit(1);
185
- }
186
- }
187
- // Use the user-provided name verbatim. The CLI used to force a `$` prefix
188
- // because Gurulu's built-ins use one (`$page_view`, `$session_start`), but
189
- // built-ins are inconsistent (`click`, `engaged_session` have none) and
190
- // mutating the customer's chosen name silently broke schema lookups + made
191
- // the generated SDK snippets reference a name that no longer matched the
192
- // ingest payload.
193
- const eventName = args.eventName;
194
- const body = {
195
- siteId: args.site,
196
- eventName,
197
- displayName: args.displayName,
198
- description: args.description || '',
199
- intentName: args.category || 'engagement',
200
- fingerprint: { propertySchema },
201
- };
202
- const data = await (0, api_client_1.cliApiJson)('/api/cli/events/definitions', { profile: args.profile, method: 'POST', json: body });
203
- if (args.json) {
204
- process.stdout.write(JSON.stringify(data, null, 2) + '\n');
205
- return;
206
- }
207
- (0, ui_1.success)(`Event ${eventName} defined successfully`);
208
- (0, ui_1.info)(`Run: gurulu events schema --event-name ${eventName} --site ${args.site} to see implementation examples`);
209
- }
210
- /* ── verify: check event health / quality ────────────────────────── */
211
- async function verifyCmd(args) {
212
- if (!args.site) {
213
- (0, ui_1.error)('--site is required.');
214
- process.exit(1);
215
- }
216
- // Accept both `--event` (verify-original) and `--event-name` (used by
217
- // every other events subcommand). Removes the surprising flag-name
218
- // inconsistency without breaking existing scripts.
219
- const filterEvent = args.event || args.eventName;
220
- const qs = new URLSearchParams();
221
- qs.set('siteId', args.site);
222
- if (filterEvent)
223
- qs.set('eventName', filterEvent);
224
- const path = `/api/cli/events/health?${qs.toString()}`;
225
- const data = await (0, api_client_1.cliApiJson)(path, { profile: args.profile });
226
- if (args.json) {
227
- process.stdout.write(JSON.stringify(data, null, 2) + '\n');
228
- return;
229
- }
230
- console.log((0, ui_1.bold)('\nEvent Health Report'));
231
- console.log(`Site: ${args.site}`);
232
- console.log('');
233
- if (Array.isArray(data.events) && data.events.length > 0) {
234
- for (const ev of data.events) {
235
- const statusIcon = ev.status === 'active'
236
- ? (0, ui_1.green)('●')
237
- : ev.status === 'stale'
238
- ? (0, ui_1.yellow)('●')
239
- : (0, ui_1.red)('●');
240
- console.log(`${statusIcon} ${ev.event_name} — ${ev.total_count ?? 0} events (last: ${ev.last_seen ?? 'never'})`);
241
- if (ev.missing_properties?.length) {
242
- console.log((0, ui_1.yellow)(` Missing required properties: ${ev.missing_properties.join(', ')}`));
243
- }
244
- }
245
- }
246
- else if (data.total_events !== undefined) {
247
- console.log(`Total events (24h): ${data.total_events}`);
248
- console.log(`Unique event types: ${data.unique_types ?? 'N/A'}`);
249
- }
250
- else {
251
- // Phase 33 P33-WA — three-state empty output instead of one generic
252
- // "no telemetry yet" message. Helps the user tell apart "definition
253
- // exists but never matched" vs "definition missing entirely" vs "no
254
- // events at all on this site". Definition lookup is best-effort
255
- // (extra HTTP call) so a 4xx falls through to the legacy message.
256
- if (filterEvent) {
257
- let definitionExists = null;
258
- try {
259
- const defs = await (0, api_client_1.cliApiJson)(`/api/cli/events/definitions?siteId=${encodeURIComponent(args.site)}`, { profile: args.profile });
260
- definitionExists = Array.isArray(defs.definitions)
261
- && defs.definitions.some((d) => d.eventName === filterEvent);
262
- }
263
- catch {
264
- // best-effort — fall through to legacy message
265
- }
266
- if (definitionExists === true) {
267
- (0, ui_1.info)(`✓ "${filterEvent}" is registered (catalog has it) but no telemetry has matched in the last 24h.`);
268
- (0, ui_1.info)(` Likely cause: SDK hasn't fired this event yet. Check your client code and run verify again.`);
269
- }
270
- else if (definitionExists === false) {
271
- (0, ui_1.info)(`⚠ "${filterEvent}" is NOT registered yet (no CustomEventDefinition row).`);
272
- (0, ui_1.info)(` Phase 32 auto-registers on first sight, but you can also run:`);
273
- (0, ui_1.info)(` gurulu events define --site ${args.site} --event-name ${filterEvent} --display-name "..."`);
274
- }
275
- else {
276
- (0, ui_1.info)(`No telemetry yet for "${filterEvent}". Track it from your app and run verify again.`);
277
- }
278
- }
279
- else {
280
- (0, ui_1.info)('No telemetry data found for this site in the last 24h.');
281
- }
282
- }
283
- console.log('');
284
- }
285
- /* ── templates: list vertical event template catalogs ───────────── */
286
- async function templatesCmd(args) {
287
- const qs = new URLSearchParams();
288
- if (args.vertical)
289
- qs.set('vertical', args.vertical);
290
- const path = `/api/events/templates${qs.toString() ? `?${qs.toString()}` : ''}`;
291
- const data = await (0, api_client_1.cliApiJson)(path, { profile: args.profile });
292
- if (args.json) {
293
- process.stdout.write(JSON.stringify(data, null, 2) + '\n');
294
- return;
295
- }
296
- if (data.error) {
297
- (0, ui_1.error)(data.error);
298
- process.exit(1);
299
- }
300
- // List mode — no vertical specified
301
- if (data.verticals) {
302
- console.log((0, ui_1.bold)('\nAvailable Verticals\n'));
303
- for (const v of data.verticals) {
304
- console.log(` ${(0, ui_1.cyan)(v.id.padEnd(14))} ${v.name.padEnd(30)} ${(0, ui_1.dim)(`${v.eventCount} events`)}`);
305
- }
306
- console.log('');
307
- (0, ui_1.info)('Usage: gurulu events templates --vertical <id>');
308
- return;
309
- }
310
- // Detail mode — specific vertical
311
- console.log((0, ui_1.bold)(`\nVertical: ${data.vertical}`));
312
- console.log(`Confidence: ${data.confidence}\n`);
313
- if (data.events?.length) {
314
- console.log((0, ui_1.bold)('Events:\n'));
315
- for (const ev of data.events) {
316
- console.log(` ${(0, ui_1.green)(ev.name)} ${(0, ui_1.dim)(`[${ev.category}]`)}`);
317
- console.log(` ${(0, ui_1.dim)(ev.reasoning)}`);
318
- if (ev.propertySchema?.length) {
319
- for (const p of ev.propertySchema) {
320
- const req = p.required ? (0, ui_1.red)('REQUIRED') : (0, ui_1.dim)('optional');
321
- const fmt = p.format ? (0, ui_1.cyan)(` [${p.format}]`) : '';
322
- const ex = p.example !== undefined ? (0, ui_1.dim)(` e.g. ${JSON.stringify(p.example)}`) : '';
323
- console.log(` ${p.name}: ${(0, ui_1.cyan)(p.type)} (${req})${fmt}${ex}`);
324
- }
325
- }
326
- console.log('');
327
- }
328
- }
329
- if (data.funnels?.length) {
330
- console.log((0, ui_1.bold)('Funnels:\n'));
331
- for (const f of data.funnels) {
332
- console.log(` ${(0, ui_1.yellow)(f.name)} ${(0, ui_1.dim)(`[${f.category}]`)}`);
333
- console.log(` Steps: ${f.steps.join(' → ')}`);
334
- console.log(` ${(0, ui_1.dim)(f.reasoning)}`);
335
- console.log('');
336
- }
337
- }
338
- }
339
- function formatFrame(raw, json) {
340
- if (json)
341
- return raw;
342
- const out = [];
343
- for (const block of raw.split('\n\n')) {
344
- const lines = block.split('\n');
345
- let ev = 'message';
346
- let data = '';
347
- for (const line of lines) {
348
- if (line.startsWith('event: '))
349
- ev = line.slice(7).trim();
350
- else if (line.startsWith('data: '))
351
- data += line.slice(6);
352
- }
353
- if (data && ev === 'realtime_event') {
354
- try {
355
- const parsed = JSON.parse(data);
356
- out.push(`[${parsed.event_ts || '-'}] ${parsed.event_name || '-'} site=${parsed.site_id || '-'}\n`);
357
- }
358
- catch {
359
- out.push(`[event] ${data}\n`);
360
- }
361
- }
362
- }
363
- return out.join('');
364
- }
365
- // Keep the legacy call-site happy: the old signature used `site/json` only.
366
- async function legacyEventsCommand(args) {
367
- return eventsCommand({ ...args, action: 'list' });
368
- }
369
- // Ensure profile helper is linked so bundlers don't tree-shake away the
370
- // config module in edge builds.
371
- exports._loadActiveProfile = config_1.loadActiveProfile;
@@ -1,22 +0,0 @@
1
- /**
2
- * Phase 19.5 W2 B7 — `gurulu experiments list|show|results`.
3
- * Phase 20 W2 B4 — `create|update|delete|start|stop`.
4
- */
5
- export interface ExperimentsArgs {
6
- action?: string;
7
- target?: string;
8
- conversionEvent?: string;
9
- json?: boolean;
10
- profile?: string;
11
- fromFile?: string;
12
- site?: string;
13
- id?: string;
14
- key?: string;
15
- name?: string;
16
- description?: string;
17
- variants?: string;
18
- goal?: string;
19
- yes?: boolean;
20
- dryRun?: boolean;
21
- }
22
- export declare function experimentsCommand(args: ExperimentsArgs): Promise<void>;
@@ -1,264 +0,0 @@
1
- "use strict";
2
- /**
3
- * Phase 19.5 W2 B7 — `gurulu experiments list|show|results`.
4
- * Phase 20 W2 B4 — `create|update|delete|start|stop`.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.experimentsCommand = experimentsCommand;
8
- const api_client_1 = require("../api-client");
9
- const ui_1 = require("../utils/ui");
10
- const confirm_1 = require("../utils/confirm");
11
- const dry_run_1 = require("../utils/dry-run");
12
- const from_file_1 = require("../utils/from-file");
13
- async function experimentsCommand(args) {
14
- const action = args.action || 'list';
15
- switch (action) {
16
- case 'list':
17
- return listCmd(args);
18
- case 'show':
19
- return showCmd(args);
20
- case 'results':
21
- return resultsCmd(args);
22
- case 'create':
23
- return createCmd(args);
24
- case 'update':
25
- return updateCmd(args);
26
- case 'delete':
27
- return deleteCmd(args);
28
- case 'start':
29
- return startCmd(args);
30
- case 'stop':
31
- return stopCmd(args);
32
- default:
33
- (0, ui_1.error)(`Unknown experiments action: ${action}`);
34
- (0, ui_1.info)('Usage: gurulu experiments [list|show|results|create|update|delete|start|stop]');
35
- process.exit(1);
36
- }
37
- }
38
- async function listCmd(args) {
39
- const qs = args.site ? `?siteId=${encodeURIComponent(args.site)}` : '';
40
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments${qs}`, {
41
- profile: args.profile,
42
- });
43
- if (args.json) {
44
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
45
- return;
46
- }
47
- const rows = body.experiments || [];
48
- if (rows.length === 0) {
49
- (0, ui_1.info)('No experiments yet.');
50
- return;
51
- }
52
- process.stdout.write(['KEY', 'NAME', 'ACTIVE', 'ASSIGNMENTS', 'STARTED'].join('\t') + '\n');
53
- for (const e of rows) {
54
- process.stdout.write([
55
- e.key,
56
- e.name,
57
- e.isActive ? 'yes' : 'no',
58
- String(e.assignmentsCount ?? 0),
59
- String(e.startedAt || '-'),
60
- ].join('\t') + '\n');
61
- }
62
- }
63
- async function showCmd(args) {
64
- if (!args.target) {
65
- (0, ui_1.error)('Usage: gurulu experiments show <key>');
66
- process.exit(1);
67
- }
68
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(args.target)}`, { profile: args.profile });
69
- if (args.json) {
70
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
71
- return;
72
- }
73
- const e = body.experiment;
74
- process.stdout.write(`Key: ${e.key}\n`);
75
- process.stdout.write(`Name: ${e.name}\n`);
76
- process.stdout.write(`Active: ${e.isActive ? 'yes' : 'no'}\n`);
77
- process.stdout.write(`Assignments: ${e.assignmentsCount}\n`);
78
- process.stdout.write(`Variants: ${JSON.stringify(e.variants)}\n`);
79
- process.stdout.write(`Started: ${e.startedAt || '-'}\n`);
80
- process.stdout.write(`Ended: ${e.endedAt || '-'}\n`);
81
- }
82
- async function resultsCmd(args) {
83
- if (!args.target) {
84
- (0, ui_1.error)('Usage: gurulu experiments results <key>');
85
- process.exit(1);
86
- }
87
- const qs = args.conversionEvent
88
- ? `?conversionEvent=${encodeURIComponent(args.conversionEvent)}`
89
- : '';
90
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(args.target)}/results${qs}`, { profile: args.profile });
91
- if (args.json) {
92
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
93
- return;
94
- }
95
- process.stdout.write(`Experiment: ${body.experimentKey || body.experimentId}\n`);
96
- process.stdout.write(`Conversion: ${body.conversionEvent}\n`);
97
- process.stdout.write(['VARIANT', 'ASSIGNS', 'CONV', 'RATE', 'CI_LO', 'CI_HI'].join('\t') + '\n');
98
- for (const r of body.results || []) {
99
- process.stdout.write([
100
- r.variantId,
101
- String(r.assignments),
102
- String(r.conversions),
103
- r.conversionRate.toFixed(3),
104
- r.ciLower.toFixed(3),
105
- r.ciUpper.toFixed(3),
106
- ].join('\t') + '\n');
107
- }
108
- }
109
- async function createCmd(args) {
110
- let payload = {};
111
- if (args.fromFile)
112
- payload = (0, from_file_1.loadFromFile)(args.fromFile);
113
- if (args.site)
114
- payload.siteId = args.site;
115
- if (args.key)
116
- payload.key = args.key;
117
- if (args.name)
118
- payload.name = args.name;
119
- if (args.description !== undefined)
120
- payload.description = args.description;
121
- if (args.goal)
122
- payload.goalId = args.goal;
123
- if (args.variants) {
124
- try {
125
- payload.variants = JSON.parse(args.variants);
126
- }
127
- catch {
128
- (0, ui_1.error)('--variants must be valid JSON');
129
- process.exit(1);
130
- }
131
- }
132
- if (!payload.name || !Array.isArray(payload.variants)) {
133
- (0, ui_1.error)('name and variants[] are required (pass --name --variants \'[...]\' or --from-file).');
134
- process.exit(1);
135
- }
136
- if (!payload.siteId) {
137
- (0, ui_1.error)('site is required (pass --site)');
138
- process.exit(1);
139
- }
140
- if (args.dryRun) {
141
- const body = await (0, api_client_1.cliApiJson)('/api/cli/experiments?dryRun=1', {
142
- profile: args.profile,
143
- method: 'POST',
144
- json: payload,
145
- });
146
- (0, dry_run_1.printDryRun)(body, args.json);
147
- return;
148
- }
149
- const ok = await (0, confirm_1.promptConfirm)(`Create experiment '${payload.key}'?`, {
150
- yes: args.yes,
151
- defaultYes: true,
152
- });
153
- if (!ok)
154
- return (0, ui_1.info)('Aborted.');
155
- const body = await (0, api_client_1.cliApiJson)('/api/cli/experiments', {
156
- profile: args.profile,
157
- method: 'POST',
158
- json: payload,
159
- });
160
- if (args.json) {
161
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
162
- return;
163
- }
164
- (0, ui_1.success)(`Created experiment ${body.experiment?.key ?? ''}`);
165
- }
166
- async function updateCmd(args) {
167
- const resolveTarget = args.id || args.target;
168
- if (!resolveTarget) {
169
- (0, ui_1.error)('Usage: gurulu experiments update <key> [--id ...] [--name ...] [--variants ...]');
170
- process.exit(1);
171
- }
172
- let payload = {};
173
- if (args.fromFile)
174
- payload = (0, from_file_1.loadFromFile)(args.fromFile);
175
- if (args.name)
176
- payload.name = args.name;
177
- if (args.description !== undefined)
178
- payload.description = args.description;
179
- if (args.goal)
180
- payload.goalId = args.goal;
181
- if (args.variants) {
182
- try {
183
- payload.variants = JSON.parse(args.variants);
184
- }
185
- catch {
186
- (0, ui_1.error)('--variants must be valid JSON');
187
- process.exit(1);
188
- }
189
- }
190
- if (args.dryRun) {
191
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(resolveTarget)}?dryRun=1`, { profile: args.profile, method: 'PATCH', json: payload });
192
- (0, dry_run_1.printDryRun)(body, args.json);
193
- return;
194
- }
195
- const ok = await (0, confirm_1.promptConfirm)(`Update experiment '${resolveTarget}'?`, {
196
- yes: args.yes,
197
- defaultYes: true,
198
- });
199
- if (!ok)
200
- return (0, ui_1.info)('Aborted.');
201
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(resolveTarget)}`, { profile: args.profile, method: 'PATCH', json: payload });
202
- if (args.json) {
203
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
204
- return;
205
- }
206
- (0, ui_1.success)(`Updated experiment ${resolveTarget}`);
207
- }
208
- async function deleteCmd(args) {
209
- const resolveTarget = args.id || args.target;
210
- if (!resolveTarget) {
211
- (0, ui_1.error)('Usage: gurulu experiments delete <key> [--id ...]');
212
- process.exit(1);
213
- }
214
- if (args.dryRun) {
215
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(resolveTarget)}?dryRun=1`, { profile: args.profile, method: 'DELETE' });
216
- (0, dry_run_1.printDryRun)(body, args.json);
217
- return;
218
- }
219
- const ok = await (0, confirm_1.promptConfirm)(`About to delete experiment '${resolveTarget}'. Continue?`, { yes: args.yes, defaultYes: false });
220
- if (!ok)
221
- return (0, ui_1.info)('Aborted.');
222
- await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(resolveTarget)}`, { profile: args.profile, method: 'DELETE' });
223
- (0, ui_1.success)(`Deleted experiment ${resolveTarget}`);
224
- }
225
- async function startCmd(args) {
226
- if (!args.target) {
227
- (0, ui_1.error)('Usage: gurulu experiments start <key>');
228
- process.exit(1);
229
- }
230
- const ok = await (0, confirm_1.promptConfirm)(`Start experiment '${args.target}'?`, {
231
- yes: args.yes,
232
- defaultYes: true,
233
- });
234
- if (!ok)
235
- return (0, ui_1.info)('Aborted.');
236
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(args.target)}/start${args.dryRun ? '?dryRun=1' : ''}`, { profile: args.profile, method: 'POST', json: {} });
237
- if (args.dryRun)
238
- return (0, dry_run_1.printDryRun)(body, args.json);
239
- if (args.json) {
240
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
241
- return;
242
- }
243
- (0, ui_1.success)(`Started experiment ${args.target}`);
244
- }
245
- async function stopCmd(args) {
246
- if (!args.target) {
247
- (0, ui_1.error)('Usage: gurulu experiments stop <key>');
248
- process.exit(1);
249
- }
250
- const ok = await (0, confirm_1.promptConfirm)(`Stop experiment '${args.target}'?`, {
251
- yes: args.yes,
252
- defaultYes: true,
253
- });
254
- if (!ok)
255
- return (0, ui_1.info)('Aborted.');
256
- const body = await (0, api_client_1.cliApiJson)(`/api/cli/experiments/${encodeURIComponent(args.target)}/stop${args.dryRun ? '?dryRun=1' : ''}`, { profile: args.profile, method: 'POST', json: {} });
257
- if (args.dryRun)
258
- return (0, dry_run_1.printDryRun)(body, args.json);
259
- if (args.json) {
260
- process.stdout.write(JSON.stringify(body, null, 2) + '\n');
261
- return;
262
- }
263
- (0, ui_1.success)(`Stopped experiment ${args.target}`);
264
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * `gurulu funnels list|show|create|update|delete` — manage conversion funnels.
3
- */
4
- export interface FunnelsArgs {
5
- action?: string;
6
- target?: string;
7
- json?: boolean;
8
- profile?: string;
9
- fromFile?: string;
10
- site?: string;
11
- name?: string;
12
- description?: string;
13
- steps?: string;
14
- yes?: boolean;
15
- dryRun?: boolean;
16
- }
17
- export declare function funnelsCommand(args: FunnelsArgs): Promise<void>;