@gurulu/cli 0.4.6 → 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 (180) 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 -853
  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 -18
  45. package/dist/commands/chat.js +0 -117
  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 -349
  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 -65
  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/sites.d.ts +0 -18
  89. package/dist/commands/sites.js +0 -139
  90. package/dist/commands/skad.d.ts +0 -18
  91. package/dist/commands/skad.js +0 -53
  92. package/dist/commands/sourcemap.d.ts +0 -33
  93. package/dist/commands/sourcemap.js +0 -204
  94. package/dist/commands/status.d.ts +0 -7
  95. package/dist/commands/status.js +0 -136
  96. package/dist/commands/upgrade.d.ts +0 -21
  97. package/dist/commands/upgrade.js +0 -183
  98. package/dist/commands/warehouse.d.ts +0 -20
  99. package/dist/commands/warehouse.js +0 -65
  100. package/dist/commands/warehouses.d.ts +0 -17
  101. package/dist/commands/warehouses.js +0 -182
  102. package/dist/commands/watch.d.ts +0 -45
  103. package/dist/commands/watch.js +0 -258
  104. package/dist/commands/whoami.d.ts +0 -9
  105. package/dist/commands/whoami.js +0 -50
  106. package/dist/config.d.ts +0 -75
  107. package/dist/config.js +0 -329
  108. package/dist/frameworks/detect.d.ts +0 -8
  109. package/dist/frameworks/detect.js +0 -444
  110. package/dist/install-intent-proposal.d.ts +0 -99
  111. package/dist/install-intent-proposal.js +0 -202
  112. package/dist/utils/api.d.ts +0 -20
  113. package/dist/utils/api.js +0 -47
  114. package/dist/utils/config.d.ts +0 -13
  115. package/dist/utils/config.js +0 -30
  116. package/dist/utils/confirm.d.ts +0 -17
  117. package/dist/utils/confirm.js +0 -40
  118. package/dist/utils/dry-run.d.ts +0 -20
  119. package/dist/utils/dry-run.js +0 -67
  120. package/dist/utils/from-file.d.ts +0 -9
  121. package/dist/utils/from-file.js +0 -72
  122. package/dist/utils/redact.d.ts +0 -14
  123. package/dist/utils/redact.js +0 -48
  124. package/dist/utils/ui.d.ts +0 -14
  125. package/dist/utils/ui.js +0 -59
  126. package/scripts/.gitkeep +0 -0
  127. package/scripts/README-gurulu-agentic-install.md +0 -114
  128. package/scripts/README-gurulu-scan.md +0 -98
  129. package/scripts/audit-cli-scopes.mjs +0 -204
  130. package/scripts/backfill-tenant-id.mjs +0 -172
  131. package/scripts/backfill-tenant-links.ts +0 -252
  132. package/scripts/backup-clickhouse.sh +0 -27
  133. package/scripts/backup-postgres.sh +0 -19
  134. package/scripts/bootstrap-runtime-schema.mjs +0 -87
  135. package/scripts/bootstrap-stripe.mjs +0 -158
  136. package/scripts/gurulu-agentic-install.lib.cjs +0 -762
  137. package/scripts/gurulu-agentic-install.mjs +0 -623
  138. package/scripts/gurulu-scan.lib.cjs +0 -1509
  139. package/scripts/gurulu-scan.mjs +0 -91
  140. package/scripts/gurulu-verify-install.lib.cjs +0 -334
  141. package/scripts/gurulu-verify-install.mjs +0 -59
  142. package/scripts/init-ssl.sh +0 -26
  143. package/scripts/migrate-flow-graph-enums.sh +0 -86
  144. package/scripts/monitor-disk.sh +0 -24
  145. package/scripts/patches/astro.patch.cjs +0 -74
  146. package/scripts/patches/auto-instrument/ast-helper.cjs +0 -480
  147. package/scripts/patches/auto-instrument/astro.cjs +0 -273
  148. package/scripts/patches/auto-instrument/express.cjs +0 -383
  149. package/scripts/patches/auto-instrument/fastify.cjs +0 -262
  150. package/scripts/patches/auto-instrument/hono.cjs +0 -392
  151. package/scripts/patches/auto-instrument/index.cjs +0 -80
  152. package/scripts/patches/auto-instrument/nestjs.cjs +0 -286
  153. package/scripts/patches/auto-instrument/nextjs-app-router.cjs +0 -345
  154. package/scripts/patches/auto-instrument/nextjs-pages.cjs +0 -361
  155. package/scripts/patches/auto-instrument/remix.cjs +0 -168
  156. package/scripts/patches/auto-instrument/sdk-helper-map.cjs +0 -241
  157. package/scripts/patches/auto-instrument/singleton-helper.cjs +0 -193
  158. package/scripts/patches/auto-instrument/sveltekit.cjs +0 -161
  159. package/scripts/patches/auto-instrument/vite-react.cjs +0 -37
  160. package/scripts/patches/auto-instrument/vue.cjs +0 -196
  161. package/scripts/patches/express.patch.cjs +0 -99
  162. package/scripts/patches/fastify.patch.cjs +0 -108
  163. package/scripts/patches/index.cjs +0 -300
  164. package/scripts/patches/nestjs.patch.cjs +0 -112
  165. package/scripts/patches/nextjs-app-router.patch.cjs +0 -97
  166. package/scripts/patches/nextjs-pages.patch.cjs +0 -97
  167. package/scripts/patches/remix.patch.cjs +0 -75
  168. package/scripts/patches/sveltekit.patch.cjs +0 -72
  169. package/scripts/patches/vite-react.patch.cjs +0 -73
  170. package/scripts/patches/vue.patch.cjs +0 -82
  171. package/scripts/renew-ssl.sh +0 -14
  172. package/scripts/resolve-migration.sh +0 -23
  173. package/scripts/seed-cli-dev-keys.mjs +0 -130
  174. package/scripts/seed-test-data.mjs +0 -391
  175. package/scripts/spike-browserless.ts +0 -65
  176. package/scripts/tenant-pivot-consistency-check.mjs +0 -205
  177. package/scripts/tenant-pivot-phase-3-cleanup.lib.cjs +0 -258
  178. package/scripts/tenant-pivot-phase-3-cleanup.mjs +0 -98
  179. package/scripts/test-identity-resolution.ts +0 -804
  180. package/scripts/validate-gurulu-schemas.mjs +0 -79
@@ -1,349 +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
- // Empty: no telemetry yet for the requested filter / definition. Without
252
- // this branch the report printed only its header — users couldn't tell
253
- // success from "no data found".
254
- if (filterEvent) {
255
- (0, ui_1.info)(`No telemetry yet for "${filterEvent}". Track it from your app and run verify again.`);
256
- }
257
- else {
258
- (0, ui_1.info)('No telemetry data found for this site in the last 24h.');
259
- }
260
- }
261
- console.log('');
262
- }
263
- /* ── templates: list vertical event template catalogs ───────────── */
264
- async function templatesCmd(args) {
265
- const qs = new URLSearchParams();
266
- if (args.vertical)
267
- qs.set('vertical', args.vertical);
268
- const path = `/api/events/templates${qs.toString() ? `?${qs.toString()}` : ''}`;
269
- const data = await (0, api_client_1.cliApiJson)(path, { profile: args.profile });
270
- if (args.json) {
271
- process.stdout.write(JSON.stringify(data, null, 2) + '\n');
272
- return;
273
- }
274
- if (data.error) {
275
- (0, ui_1.error)(data.error);
276
- process.exit(1);
277
- }
278
- // List mode — no vertical specified
279
- if (data.verticals) {
280
- console.log((0, ui_1.bold)('\nAvailable Verticals\n'));
281
- for (const v of data.verticals) {
282
- console.log(` ${(0, ui_1.cyan)(v.id.padEnd(14))} ${v.name.padEnd(30)} ${(0, ui_1.dim)(`${v.eventCount} events`)}`);
283
- }
284
- console.log('');
285
- (0, ui_1.info)('Usage: gurulu events templates --vertical <id>');
286
- return;
287
- }
288
- // Detail mode — specific vertical
289
- console.log((0, ui_1.bold)(`\nVertical: ${data.vertical}`));
290
- console.log(`Confidence: ${data.confidence}\n`);
291
- if (data.events?.length) {
292
- console.log((0, ui_1.bold)('Events:\n'));
293
- for (const ev of data.events) {
294
- console.log(` ${(0, ui_1.green)(ev.name)} ${(0, ui_1.dim)(`[${ev.category}]`)}`);
295
- console.log(` ${(0, ui_1.dim)(ev.reasoning)}`);
296
- if (ev.propertySchema?.length) {
297
- for (const p of ev.propertySchema) {
298
- const req = p.required ? (0, ui_1.red)('REQUIRED') : (0, ui_1.dim)('optional');
299
- const fmt = p.format ? (0, ui_1.cyan)(` [${p.format}]`) : '';
300
- const ex = p.example !== undefined ? (0, ui_1.dim)(` e.g. ${JSON.stringify(p.example)}`) : '';
301
- console.log(` ${p.name}: ${(0, ui_1.cyan)(p.type)} (${req})${fmt}${ex}`);
302
- }
303
- }
304
- console.log('');
305
- }
306
- }
307
- if (data.funnels?.length) {
308
- console.log((0, ui_1.bold)('Funnels:\n'));
309
- for (const f of data.funnels) {
310
- console.log(` ${(0, ui_1.yellow)(f.name)} ${(0, ui_1.dim)(`[${f.category}]`)}`);
311
- console.log(` Steps: ${f.steps.join(' → ')}`);
312
- console.log(` ${(0, ui_1.dim)(f.reasoning)}`);
313
- console.log('');
314
- }
315
- }
316
- }
317
- function formatFrame(raw, json) {
318
- if (json)
319
- return raw;
320
- const out = [];
321
- for (const block of raw.split('\n\n')) {
322
- const lines = block.split('\n');
323
- let ev = 'message';
324
- let data = '';
325
- for (const line of lines) {
326
- if (line.startsWith('event: '))
327
- ev = line.slice(7).trim();
328
- else if (line.startsWith('data: '))
329
- data += line.slice(6);
330
- }
331
- if (data && ev === 'realtime_event') {
332
- try {
333
- const parsed = JSON.parse(data);
334
- out.push(`[${parsed.event_ts || '-'}] ${parsed.event_name || '-'} site=${parsed.site_id || '-'}\n`);
335
- }
336
- catch {
337
- out.push(`[event] ${data}\n`);
338
- }
339
- }
340
- }
341
- return out.join('');
342
- }
343
- // Keep the legacy call-site happy: the old signature used `site/json` only.
344
- async function legacyEventsCommand(args) {
345
- return eventsCommand({ ...args, action: 'list' });
346
- }
347
- // Ensure profile helper is linked so bundlers don't tree-shake away the
348
- // config module in edge builds.
349
- 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>;