@gurulu/cli 0.4.7 → 1.0.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.
Files changed (182) 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 +25410 -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 +25 -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 +24985 -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/package.json +40 -20
  28. package/bin/gurulu.js +0 -2
  29. package/dist/api-client.d.ts +0 -33
  30. package/dist/api-client.js +0 -175
  31. package/dist/commands/add-server.d.ts +0 -9
  32. package/dist/commands/add-server.js +0 -162
  33. package/dist/commands/alerts.d.ts +0 -27
  34. package/dist/commands/alerts.js +0 -309
  35. package/dist/commands/api-keys.d.ts +0 -20
  36. package/dist/commands/api-keys.js +0 -130
  37. package/dist/commands/attribution.d.ts +0 -22
  38. package/dist/commands/attribution.js +0 -111
  39. package/dist/commands/audiences.d.ts +0 -23
  40. package/dist/commands/audiences.js +0 -243
  41. package/dist/commands/audit.d.ts +0 -20
  42. package/dist/commands/audit.js +0 -130
  43. package/dist/commands/auth.js +0 -249
  44. package/dist/commands/chat.d.ts +0 -19
  45. package/dist/commands/chat.js +0 -118
  46. package/dist/commands/config.d.ts +0 -10
  47. package/dist/commands/config.js +0 -92
  48. package/dist/commands/consent.d.ts +0 -27
  49. package/dist/commands/consent.js +0 -233
  50. package/dist/commands/conversion-paths.d.ts +0 -19
  51. package/dist/commands/conversion-paths.js +0 -55
  52. package/dist/commands/db.d.ts +0 -25
  53. package/dist/commands/db.js +0 -330
  54. package/dist/commands/destinations.d.ts +0 -20
  55. package/dist/commands/destinations.js +0 -191
  56. package/dist/commands/doctor.js +0 -360
  57. package/dist/commands/errors.d.ts +0 -27
  58. package/dist/commands/errors.js +0 -121
  59. package/dist/commands/events.d.ts +0 -33
  60. package/dist/commands/events.js +0 -371
  61. package/dist/commands/experiments.d.ts +0 -22
  62. package/dist/commands/experiments.js +0 -264
  63. package/dist/commands/funnels.d.ts +0 -17
  64. package/dist/commands/funnels.js +0 -203
  65. package/dist/commands/goals.d.ts +0 -18
  66. package/dist/commands/goals.js +0 -214
  67. package/dist/commands/heatmap.d.ts +0 -27
  68. package/dist/commands/heatmap.js +0 -112
  69. package/dist/commands/identity.d.ts +0 -29
  70. package/dist/commands/identity.js +0 -328
  71. package/dist/commands/init.js +0 -215
  72. package/dist/commands/insights.d.ts +0 -10
  73. package/dist/commands/insights.js +0 -77
  74. package/dist/commands/install.d.ts +0 -259
  75. package/dist/commands/install.js +0 -1590
  76. package/dist/commands/login.d.ts +0 -20
  77. package/dist/commands/login.js +0 -170
  78. package/dist/commands/logout.d.ts +0 -10
  79. package/dist/commands/logout.js +0 -41
  80. package/dist/commands/playground.d.ts +0 -11
  81. package/dist/commands/playground.js +0 -47
  82. package/dist/commands/releases.d.ts +0 -17
  83. package/dist/commands/releases.js +0 -54
  84. package/dist/commands/replay.d.ts +0 -18
  85. package/dist/commands/replay.js +0 -64
  86. package/dist/commands/secrets.d.ts +0 -19
  87. package/dist/commands/secrets.js +0 -145
  88. package/dist/commands/setup.d.ts +0 -21
  89. package/dist/commands/setup.js +0 -67
  90. package/dist/commands/sites.d.ts +0 -18
  91. package/dist/commands/sites.js +0 -139
  92. package/dist/commands/skad.d.ts +0 -18
  93. package/dist/commands/skad.js +0 -53
  94. package/dist/commands/sourcemap.d.ts +0 -33
  95. package/dist/commands/sourcemap.js +0 -204
  96. package/dist/commands/status.d.ts +0 -7
  97. package/dist/commands/status.js +0 -136
  98. package/dist/commands/upgrade.d.ts +0 -21
  99. package/dist/commands/upgrade.js +0 -183
  100. package/dist/commands/warehouse.d.ts +0 -20
  101. package/dist/commands/warehouse.js +0 -65
  102. package/dist/commands/warehouses.d.ts +0 -17
  103. package/dist/commands/warehouses.js +0 -182
  104. package/dist/commands/watch.d.ts +0 -45
  105. package/dist/commands/watch.js +0 -258
  106. package/dist/commands/whoami.d.ts +0 -9
  107. package/dist/commands/whoami.js +0 -50
  108. package/dist/config.d.ts +0 -75
  109. package/dist/config.js +0 -329
  110. package/dist/frameworks/detect.d.ts +0 -8
  111. package/dist/frameworks/detect.js +0 -458
  112. package/dist/install-intent-proposal.d.ts +0 -99
  113. package/dist/install-intent-proposal.js +0 -202
  114. package/dist/utils/api.d.ts +0 -20
  115. package/dist/utils/api.js +0 -47
  116. package/dist/utils/config.d.ts +0 -13
  117. package/dist/utils/config.js +0 -30
  118. package/dist/utils/confirm.d.ts +0 -17
  119. package/dist/utils/confirm.js +0 -40
  120. package/dist/utils/dry-run.d.ts +0 -20
  121. package/dist/utils/dry-run.js +0 -67
  122. package/dist/utils/from-file.d.ts +0 -9
  123. package/dist/utils/from-file.js +0 -72
  124. package/dist/utils/redact.d.ts +0 -14
  125. package/dist/utils/redact.js +0 -48
  126. package/dist/utils/ui.d.ts +0 -14
  127. package/dist/utils/ui.js +0 -59
  128. package/scripts/.gitkeep +0 -0
  129. package/scripts/README-gurulu-agentic-install.md +0 -114
  130. package/scripts/README-gurulu-scan.md +0 -98
  131. package/scripts/audit-cli-scopes.mjs +0 -204
  132. package/scripts/backfill-tenant-id.mjs +0 -172
  133. package/scripts/backfill-tenant-links.ts +0 -252
  134. package/scripts/backup-clickhouse.sh +0 -27
  135. package/scripts/backup-postgres.sh +0 -19
  136. package/scripts/bootstrap-runtime-schema.mjs +0 -87
  137. package/scripts/bootstrap-stripe.mjs +0 -158
  138. package/scripts/gurulu-agentic-install.lib.cjs +0 -762
  139. package/scripts/gurulu-agentic-install.mjs +0 -623
  140. package/scripts/gurulu-scan.lib.cjs +0 -1509
  141. package/scripts/gurulu-scan.mjs +0 -91
  142. package/scripts/gurulu-verify-install.lib.cjs +0 -334
  143. package/scripts/gurulu-verify-install.mjs +0 -59
  144. package/scripts/init-ssl.sh +0 -26
  145. package/scripts/migrate-flow-graph-enums.sh +0 -86
  146. package/scripts/monitor-disk.sh +0 -24
  147. package/scripts/patches/astro.patch.cjs +0 -74
  148. package/scripts/patches/auto-instrument/ast-helper.cjs +0 -480
  149. package/scripts/patches/auto-instrument/astro.cjs +0 -273
  150. package/scripts/patches/auto-instrument/express.cjs +0 -383
  151. package/scripts/patches/auto-instrument/fastify.cjs +0 -262
  152. package/scripts/patches/auto-instrument/hono.cjs +0 -392
  153. package/scripts/patches/auto-instrument/index.cjs +0 -80
  154. package/scripts/patches/auto-instrument/nestjs.cjs +0 -286
  155. package/scripts/patches/auto-instrument/nextjs-app-router.cjs +0 -345
  156. package/scripts/patches/auto-instrument/nextjs-pages.cjs +0 -361
  157. package/scripts/patches/auto-instrument/remix.cjs +0 -168
  158. package/scripts/patches/auto-instrument/sdk-helper-map.cjs +0 -241
  159. package/scripts/patches/auto-instrument/singleton-helper.cjs +0 -193
  160. package/scripts/patches/auto-instrument/sveltekit.cjs +0 -161
  161. package/scripts/patches/auto-instrument/vite-react.cjs +0 -37
  162. package/scripts/patches/auto-instrument/vue.cjs +0 -196
  163. package/scripts/patches/express.patch.cjs +0 -99
  164. package/scripts/patches/fastify.patch.cjs +0 -108
  165. package/scripts/patches/index.cjs +0 -300
  166. package/scripts/patches/nestjs.patch.cjs +0 -112
  167. package/scripts/patches/nextjs-app-router.patch.cjs +0 -97
  168. package/scripts/patches/nextjs-pages.patch.cjs +0 -97
  169. package/scripts/patches/remix.patch.cjs +0 -75
  170. package/scripts/patches/sveltekit.patch.cjs +0 -72
  171. package/scripts/patches/vite-react.patch.cjs +0 -73
  172. package/scripts/patches/vue.patch.cjs +0 -82
  173. package/scripts/renew-ssl.sh +0 -14
  174. package/scripts/resolve-migration.sh +0 -23
  175. package/scripts/seed-cli-dev-keys.mjs +0 -130
  176. package/scripts/seed-test-data.mjs +0 -391
  177. package/scripts/spike-browserless.ts +0 -65
  178. package/scripts/tenant-pivot-consistency-check.mjs +0 -205
  179. package/scripts/tenant-pivot-phase-3-cleanup.lib.cjs +0 -258
  180. package/scripts/tenant-pivot-phase-3-cleanup.mjs +0 -98
  181. package/scripts/test-identity-resolution.ts +0 -804
  182. 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>;