@posthog/wizard 2.74.1 → 2.75.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 (115) hide show
  1. package/README.md +31 -17
  2. package/dist/README.md +10 -0
  3. package/dist/{add-mcp-server-to-clients-CBtInAoH.js → add-mcp-server-to-clients-CjfnPMbO.js} +5 -5
  4. package/dist/{add-mcp-server-to-clients-CBtInAoH.js.map → add-mcp-server-to-clients-CjfnPMbO.js.map} +1 -1
  5. package/dist/{agent-interface-lCIi_alS.js → agent-interface-BKLTDSyN.js} +144 -339
  6. package/dist/agent-interface-BKLTDSyN.js.map +1 -0
  7. package/dist/{agent-prompt-loader-CSxm81TM.js → agent-prompt-loader-DAagxT3p.js} +5 -5
  8. package/dist/{agent-prompt-loader-CSxm81TM.js.map → agent-prompt-loader-DAagxT3p.js.map} +1 -1
  9. package/dist/{agent-runner-DVrkOFDA.js → agent-runner-BkQontri.js} +133 -44
  10. package/dist/agent-runner-BkQontri.js.map +1 -0
  11. package/dist/{analytics-CeVMOExk.js → analytics-DSK0GXg1.js} +6 -4
  12. package/dist/analytics-DSK0GXg1.js.map +1 -0
  13. package/dist/analytics-yurAACt5.js +2 -0
  14. package/dist/{api-2nAofyKY.js → api-CwNulLDK.js} +3 -3
  15. package/dist/{api-2nAofyKY.js.map → api-CwNulLDK.js.map} +1 -1
  16. package/dist/bin.js +125 -4072
  17. package/dist/bin.js.map +1 -1
  18. package/dist/{bounded-fs-DmcmFPRq.js → bounded-fs-D85Tk3nS.js} +3 -3
  19. package/dist/{bounded-fs-DmcmFPRq.js.map → bounded-fs-D85Tk3nS.js.map} +1 -1
  20. package/dist/{ci-install-lwYLQ4Yw.js → ci-install-CQLi_a-r.js} +4 -4
  21. package/dist/{ci-install-lwYLQ4Yw.js.map → ci-install-CQLi_a-r.js.map} +1 -1
  22. package/dist/{debug-BvheXnxB.js → debug-CBmI5YUF.js} +1 -1
  23. package/dist/{debug-GxjVplPx.js → debug-DUmMVUHn.js} +3 -3
  24. package/dist/debug-DUmMVUHn.js.map +1 -0
  25. package/dist/{defaults-DI642M3n.js → defaults-DDDwYTN5.js} +1 -1
  26. package/dist/{defaults-DI642M3n.js.map → defaults-DDDwYTN5.js.map} +1 -1
  27. package/dist/{env-api-key-BMXH7_4u.js → env-api-key-CGC1Bqwq.js} +2 -2
  28. package/dist/{env-api-key-BMXH7_4u.js.map → env-api-key-CGC1Bqwq.js.map} +1 -1
  29. package/dist/{environment-C3nfPBu-.js → environment-DC4RDnzR.js} +4 -4
  30. package/dist/{environment-C3nfPBu-.js.map → environment-DC4RDnzR.js.map} +1 -1
  31. package/dist/{file-watcher-BGElIpJi.js → file-watcher-hafFFQib.js} +2 -2
  32. package/dist/{file-watcher-BGElIpJi.js.map → file-watcher-hafFFQib.js.map} +1 -1
  33. package/dist/gateway-session-Ctc2xaz7.js +271 -0
  34. package/dist/gateway-session-Ctc2xaz7.js.map +1 -0
  35. package/dist/gateway-session-zwwZAyTt.js +2 -0
  36. package/dist/{headless-ui-jkS2Dm_G.js → headless-ui-CQ46FOTh.js} +2 -2
  37. package/dist/{headless-ui-jkS2Dm_G.js.map → headless-ui-CQ46FOTh.js.map} +1 -1
  38. package/dist/{interactive-CrQWwMr2.js → interactive-5O4XQf59.js} +2 -2
  39. package/dist/{interactive-CrQWwMr2.js.map → interactive-5O4XQf59.js.map} +1 -1
  40. package/dist/{mcp-S3yX8Uz1.js → mcp-D0Dni4tL.js} +2 -2
  41. package/dist/{mcp-S3yX8Uz1.js.map → mcp-D0Dni4tL.js.map} +1 -1
  42. package/dist/{mcp-prompt-streaming-BvvCZBYa.js → mcp-prompt-streaming-DNCDeU51.js} +6 -5
  43. package/dist/{mcp-prompt-streaming-BvvCZBYa.js.map → mcp-prompt-streaming-DNCDeU51.js.map} +1 -1
  44. package/dist/mint-failure-CQqypC_v.js +5718 -0
  45. package/dist/mint-failure-CQqypC_v.js.map +1 -0
  46. package/dist/{non-interactive-B-MIn3vt.js → non-interactive-D5-lCBy6.js} +2 -2
  47. package/dist/{non-interactive-B-MIn3vt.js.map → non-interactive-D5-lCBy6.js.map} +1 -1
  48. package/dist/{orchestrator-tools-CefodRf2.js → orchestrator-tools-D8ZQS2DM.js} +5 -5
  49. package/dist/orchestrator-tools-D8ZQS2DM.js.map +1 -0
  50. package/dist/{package-manager-pB6S0gyu.js → package-manager-hyP-CPSZ.js} +2 -2
  51. package/dist/{package-manager-pB6S0gyu.js.map → package-manager-hyP-CPSZ.js.map} +1 -1
  52. package/dist/{pi-Dbw8VakI.js → pi-DARAk2I_.js} +35 -24
  53. package/dist/pi-DARAk2I_.js.map +1 -0
  54. package/dist/{playground-C7DwGktN.js → playground-Djabnagq.js} +8 -8
  55. package/dist/{playground-C7DwGktN.js.map → playground-Djabnagq.js.map} +1 -1
  56. package/dist/{posthog-B3RuLfxH.js → posthog-C3Sncfan.js} +2 -2
  57. package/dist/{posthog-B3RuLfxH.js.map → posthog-C3Sncfan.js.map} +1 -1
  58. package/dist/{provisioning-B4Lr3-aS.js → provisioning-B74q1uSQ.js} +3 -3
  59. package/dist/{provisioning-B4Lr3-aS.js.map → provisioning-B74q1uSQ.js.map} +1 -1
  60. package/dist/{queue-tools-BveMVXQm.js → queue-tools-FLMG8hcB.js} +17 -5
  61. package/dist/queue-tools-FLMG8hcB.js.map +1 -0
  62. package/dist/{registry-D8MIZ9kJ.js → registry-DZoReEU3.js} +5 -5
  63. package/dist/{registry-D8MIZ9kJ.js.map → registry-DZoReEU3.js.map} +1 -1
  64. package/dist/{security-B_Eo15wD.js → security-DiBFYwh7.js} +5 -5
  65. package/dist/{security-B_Eo15wD.js.map → security-DiBFYwh7.js.map} +1 -1
  66. package/dist/{setup-utils-D3OK2RE_.js → setup-utils-C3tsa6D6.js} +48 -9
  67. package/dist/setup-utils-C3tsa6D6.js.map +1 -0
  68. package/dist/smoke-test-ci.sh +9 -14
  69. package/dist/{start-tui-B7u962uh.js → start-tui-BXjJGNx2.js} +849 -115
  70. package/dist/start-tui-BXjJGNx2.js.map +1 -0
  71. package/dist/{steps-D4mHkYX4.js → steps-CeFanezY.js} +7 -7
  72. package/dist/{steps-D4mHkYX4.js.map → steps-CeFanezY.js.map} +1 -1
  73. package/dist/{store-Cn1VK6U0.js → store-DN_6FaoQ.js} +63 -10
  74. package/dist/store-DN_6FaoQ.js.map +1 -0
  75. package/dist/{subagent-1UEmD7bE.js → subagent-BzhCH9c3.js} +2 -2
  76. package/dist/{subagent-1UEmD7bE.js.map → subagent-BzhCH9c3.js.map} +1 -1
  77. package/dist/{task-DNHNZMO0.js → task-DZKmaWYF.js} +19 -22
  78. package/dist/task-DZKmaWYF.js.map +1 -0
  79. package/dist/{task-stream-BJrRzR9K.js → task-stream-h-b1nWdM.js} +5 -5
  80. package/dist/{task-stream-BJrRzR9K.js.map → task-stream-h-b1nWdM.js.map} +1 -1
  81. package/dist/{tasks-DSEJ8GZC.js → tasks-0Rb5AXpz.js} +2 -2
  82. package/dist/{tasks-DSEJ8GZC.js.map → tasks-0Rb5AXpz.js.map} +1 -1
  83. package/dist/{telemetry-DWkTy6TJ.js → telemetry-QpeVhVtU.js} +3 -3
  84. package/dist/{telemetry-DWkTy6TJ.js.map → telemetry-QpeVhVtU.js.map} +1 -1
  85. package/dist/{terminal-DNnNkvFu.js → terminal-dLoYiXsd.js} +20 -18
  86. package/dist/{terminal-DNnNkvFu.js.map → terminal-dLoYiXsd.js.map} +1 -1
  87. package/dist/{tools-HHK4XbnC.js → tools-DmwO0eBZ.js} +22 -16
  88. package/dist/tools-DmwO0eBZ.js.map +1 -0
  89. package/dist/{wizard-abort-BVmjqUAQ.js → wizard-abort-B0c5VDie.js} +4 -4
  90. package/dist/{wizard-abort-BVmjqUAQ.js.map → wizard-abort-B0c5VDie.js.map} +1 -1
  91. package/dist/{wizard-abort-CG_xzEFN.js → wizard-abort-C9Jbm-m7.js} +1 -1
  92. package/dist/{wizard-session-BWAQoi9q.js → wizard-session-CYvyYnti.js} +1 -1
  93. package/dist/{wizard-session-GdDN_aMS.js → wizard-session-FSJCkTcP.js} +9 -2
  94. package/dist/wizard-session-FSJCkTcP.js.map +1 -0
  95. package/dist/yara-hooks-B7prW1Ng.js +2 -0
  96. package/dist/{yara-hooks-qRkdjYiV.js → yara-hooks-uCiAIcqU.js} +4 -4
  97. package/dist/{yara-hooks-qRkdjYiV.js.map → yara-hooks-uCiAIcqU.js.map} +1 -1
  98. package/package.json +1 -1
  99. package/dist/agent-interface-lCIi_alS.js.map +0 -1
  100. package/dist/agent-runner-DVrkOFDA.js.map +0 -1
  101. package/dist/analytics-3H_AlflZ.js +0 -2
  102. package/dist/analytics-CeVMOExk.js.map +0 -1
  103. package/dist/debug-GxjVplPx.js.map +0 -1
  104. package/dist/orchestrator-tools-CefodRf2.js.map +0 -1
  105. package/dist/pi-Dbw8VakI.js.map +0 -1
  106. package/dist/posthog-integration-su2LXi3-.js +0 -1475
  107. package/dist/posthog-integration-su2LXi3-.js.map +0 -1
  108. package/dist/queue-tools-BveMVXQm.js.map +0 -1
  109. package/dist/setup-utils-D3OK2RE_.js.map +0 -1
  110. package/dist/start-tui-B7u962uh.js.map +0 -1
  111. package/dist/store-Cn1VK6U0.js.map +0 -1
  112. package/dist/task-DNHNZMO0.js.map +0 -1
  113. package/dist/tools-HHK4XbnC.js.map +0 -1
  114. package/dist/wizard-session-GdDN_aMS.js.map +0 -1
  115. package/dist/yara-hooks-BOMbtTOr.js +0 -2
@@ -1,1475 +0,0 @@
1
- import { d as ErrorCodes, o as AgentSignals } from "./errors--OqLxmWR.js";
2
- import { S as AGENTIC_DETECTION_TIMEOUT_MS, _ as evaluateWizardReadiness, f as getUI, g as SIGNUP_WIZARD_READINESS_CONFIG, it as WIZARD_INTERACTION_EVENT_NAME, s as logToFile, v as getBlockingServiceKeys } from "./debug-GxjVplPx.js";
3
- import { o as mayReportScanResults } from "./wizard-session-GdDN_aMS.js";
4
- import { n as analytics } from "./analytics-CeVMOExk.js";
5
- import { i as withUtm, n as openTrackedLink } from "./telemetry-DWkTy6TJ.js";
6
- import { i as tryGetPackageJson, n as isUsingTypeScript } from "./setup-utils-D3OK2RE_.js";
7
- import { i as requestDeepLink } from "./provisioning-B4Lr3-aS.js";
8
- import { i as wizardAbort } from "./wizard-abort-BVmjqUAQ.js";
9
- import { A as WIZARD_TOOL_NAMES } from "./agent-interface-lCIi_alS.js";
10
- import { _ as detectFramework, f as getDetectedWarehouseSources, g as gatherFrameworkContext, h as resolveProjectDir, m as detectProjectsWithAgent, n as runAgent, r as shouldDisableAsk, s as detectPostHogIntegration, v as authenticate } from "./agent-runner-DVrkOFDA.js";
11
- import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-D8MIZ9kJ.js";
12
- import { h as EVENT_PLAN_FILE } from "./yara-hooks-qRkdjYiV.js";
13
- import { Text } from "ink";
14
- import { useEffect, useMemo, useRef, useState } from "react";
15
- import { jsx, jsxs } from "react/jsx-runtime";
16
- //#region src/lib/detection/project-scope.ts
17
- /** Non-interactive project scoping — scan the repo agentically and pick which project the run integrates. */
18
- /** Integration framework targets for the agentic detector (id → display name). */
19
- const INTEGRATION_TARGETS = Object.entries(FRAMEWORK_REGISTRY).map(([id, config]) => ({
20
- id,
21
- name: config.metadata.name
22
- }));
23
- /** Run the agentic detector for the wizard's integration frameworks — the single home of targets + purpose. */
24
- async function detectIntegrationProjects(session, options) {
25
- return detectProjectsWithAgent(session, {
26
- ...options,
27
- targets: INTEGRATION_TARGETS,
28
- purpose: "set up a PostHog SDK integration"
29
- });
30
- }
31
- /** Pick the recommended-if-supported project (even with PostHog — the main app wins), else the first supported PostHog-free one. */
32
- function chooseIntegrationProject(projects) {
33
- return projects.find((p) => p.recommended === true && p.targetId != null) ?? projects.find((p) => p.targetId != null && !p.hasPostHog);
34
- }
35
- /** Sentinel for a scan that outran AGENTIC_DETECTION_TIMEOUT_MS. */
36
- const TIMED_OUT = Symbol("timed-out");
37
- function captureOutcome(outcome, properties = {}) {
38
- analytics.wizardCapture("agentic detection", {
39
- outcome,
40
- ...properties
41
- });
42
- }
43
- /** Flag-gated non-interactive monorepo phase: scan, auto-choose the recommended project, re-point session.installDir; every failure leaves the session untouched. */
44
- async function scopeInstallDirToProject(session) {
45
- await authenticate(session, "posthog-integration");
46
- if ((await analytics.getAllFlagsForWizard())["wizard-basic-integration-agentic-detection"] !== "true") {
47
- captureOutcome("flag-off");
48
- return;
49
- }
50
- getUI().log.info("Scanning the repo for projects...");
51
- const startedAt = Date.now();
52
- let report;
53
- try {
54
- report = await Promise.race([detectIntegrationProjects(session, {
55
- programId: "posthog-integration",
56
- recommend: true,
57
- onEvent: (line) => logToFile("[agentic detect]", line)
58
- }), new Promise((resolve) => setTimeout(() => resolve(TIMED_OUT), AGENTIC_DETECTION_TIMEOUT_MS))]);
59
- } catch (err) {
60
- const error = err instanceof Error ? err : new Error(String(err));
61
- analytics.captureException(error, { step: "agentic_detection" });
62
- captureOutcome("error", {
63
- duration_ms: Date.now() - startedAt,
64
- error_message: error.message
65
- });
66
- getUI().log.warn(`Project scan failed (${error.message}); continuing with the install dir as-is.`);
67
- return;
68
- }
69
- if (report === TIMED_OUT) {
70
- captureOutcome("timeout", { duration_ms: Date.now() - startedAt });
71
- getUI().log.warn(`Project scan timed out after ${AGENTIC_DETECTION_TIMEOUT_MS / 1e3}s; continuing with the install dir as-is.`);
72
- return;
73
- }
74
- const { projects } = report;
75
- const recommended = projects.find((p) => p.recommended === true);
76
- const scanProperties = {
77
- duration_ms: Date.now() - startedAt,
78
- repo_type: report.repoType,
79
- project_count: projects.length,
80
- supported_count: projects.filter((p) => p.targetId != null).length,
81
- has_recommendation: recommended !== void 0,
82
- recommended_path: recommended?.path ?? null,
83
- projects: projects.slice(0, 25)
84
- };
85
- const project = chooseIntegrationProject(projects);
86
- if (!project) {
87
- captureOutcome("no-project", scanProperties);
88
- getUI().log.info("The scan found no supported project; continuing with the install dir as-is.");
89
- return;
90
- }
91
- session.installDir = resolveProjectDir(session.installDir, project.path);
92
- captureOutcome(project.recommended ? "recommended" : "first-instrumentable", {
93
- ...scanProperties,
94
- chosen_framework: project.targetId,
95
- chosen_path: project.path
96
- });
97
- getUI().log.info(`Continuing with ${project.path} (${project.framework}).`);
98
- }
99
- //#endregion
100
- //#region src/lib/programs/shared/health-check-step.ts
101
- function healthCheckReady(session) {
102
- if (!session.readinessResult) return false;
103
- if (session.signup) {
104
- const hardBlocking = getBlockingServiceKeys(session.readinessResult.health, SIGNUP_WIZARD_READINESS_CONFIG);
105
- const defaultBlocking = getBlockingServiceKeys(session.readinessResult.health);
106
- if (hardBlocking.length === 0 && defaultBlocking.length === 0) return true;
107
- return session.outageDismissed;
108
- }
109
- if (session.readinessResult.decision === "no") return session.outageDismissed;
110
- return true;
111
- }
112
- const HEALTH_CHECK_STEP = {
113
- id: "health-check",
114
- label: "Health check",
115
- screenId: "health-check",
116
- gate: healthCheckReady,
117
- onInit: (ctx) => {
118
- evaluateWizardReadiness().then((readiness) => {
119
- logToFile(`[health-checks] TUI pre-flight complete: decision=${readiness.decision}`);
120
- ctx.setReadinessResult(readiness);
121
- }).catch((err) => {
122
- logToFile("[health-checks] TUI pre-flight failed:", err);
123
- ctx.setReadinessResult({
124
- decision: "yes",
125
- health: {},
126
- reasons: []
127
- });
128
- });
129
- }
130
- };
131
- //#endregion
132
- //#region src/lib/programs/posthog-integration/steps.ts
133
- function needsSetup(session) {
134
- const config = session.frameworkConfig;
135
- if (!config?.metadata.setup?.questions) return false;
136
- return config.metadata.setup.questions.some((q) => !(q.key in session.frameworkContext));
137
- }
138
- const POSTHOG_INTEGRATION_PROGRAM = [
139
- {
140
- id: "detect",
141
- label: "Detecting framework",
142
- onReady: (ctx) => detectPostHogIntegration(ctx)
143
- },
144
- {
145
- id: "intro",
146
- label: "Welcome",
147
- screenId: "intro",
148
- gate: (session) => session.setupConfirmed
149
- },
150
- HEALTH_CHECK_STEP,
151
- {
152
- id: "setup",
153
- label: "Setup",
154
- screenId: "setup",
155
- show: needsSetup,
156
- isComplete: (session) => !needsSetup(session)
157
- },
158
- {
159
- id: "auth",
160
- label: "Authentication",
161
- screenId: "auth",
162
- isComplete: (session) => session.credentials !== null
163
- },
164
- {
165
- id: "run",
166
- label: "Integration",
167
- screenId: "run",
168
- isComplete: (session) => session.runPhase === "completed" || session.runPhase === "error"
169
- },
170
- {
171
- id: "outro",
172
- label: "Done",
173
- screenId: "outro",
174
- isComplete: (session) => session.outroDismissed
175
- },
176
- {
177
- id: "mcp",
178
- label: "MCP servers",
179
- screenId: "mcp",
180
- isComplete: (session) => session.mcpComplete
181
- },
182
- {
183
- id: "slack-connect",
184
- label: "Connect Slack",
185
- screenId: "slack-connect",
186
- isComplete: (session) => session.slackStepDismissed
187
- },
188
- {
189
- id: "keep-skills",
190
- label: "Keep Skills",
191
- screenId: "keep-skills"
192
- }
193
- ];
194
- //#endregion
195
- //#region src/ui/tui/styles.ts
196
- const Colors = {
197
- primary: "cyan",
198
- accent: "#DC9300",
199
- titleColor: "#3D2800",
200
- success: "green",
201
- error: "red",
202
- muted: "gray"
203
- };
204
- const Icons = {
205
- diamond: "◆",
206
- diamondOpen: "◇",
207
- check: "✔",
208
- warning: "⚠",
209
- squareFilled: "◼",
210
- squareOpen: "◻",
211
- triangleRight: "▶",
212
- triangleSmallRight: "▸",
213
- bullet: "•"
214
- };
215
- //#endregion
216
- //#region src/ui/tui/primitives/text-helpers.ts
217
- /**
218
- * Text-splitting helpers for sentence boundary detection.
219
- * Used by TextBlock for animation pauses at punctuation.
220
- */
221
- /** Split text into sentences (keeps the delimiter attached) */
222
- function splitSentences(text) {
223
- const parts = [];
224
- const re = /[^.!?]*[.!?]+\s*/g;
225
- let match;
226
- let lastIndex = 0;
227
- while ((match = re.exec(text)) !== null) {
228
- parts.push(match[0]);
229
- lastIndex = re.lastIndex;
230
- }
231
- if (lastIndex < text.length) parts.push(text.slice(lastIndex));
232
- return parts;
233
- }
234
- /** Build a set of character indices where sentences end (for typewriter pause) */
235
- function sentenceEndChars(text) {
236
- const ends = /* @__PURE__ */ new Set();
237
- const sentences = splitSentences(text);
238
- let pos = 0;
239
- for (const s of sentences) {
240
- pos += s.length;
241
- ends.add(pos - 1);
242
- }
243
- return ends;
244
- }
245
- /** Build a set of word indices where sentences end (for word-by-word pause) */
246
- function sentenceEndWords(text) {
247
- const ends = /* @__PURE__ */ new Set();
248
- const sentences = splitSentences(text);
249
- let wordCount = 0;
250
- for (const s of sentences) {
251
- const words = s.trim().split(/\s+/).filter(Boolean);
252
- wordCount += words.length;
253
- ends.add(wordCount - 1);
254
- }
255
- return ends;
256
- }
257
- //#endregion
258
- //#region src/ui/tui/primitives/content-types.ts
259
- /** Type guard for lines blocks. */
260
- function isLinesBlock(block) {
261
- return typeof block !== "string" && "type" in block && block.type === "lines";
262
- }
263
- /** Type guard for clear blocks. */
264
- function isClearBlock(block) {
265
- return typeof block !== "string" && "type" in block && block.type === "clear";
266
- }
267
- /** Type guard for object blocks (text or node content). */
268
- function isObjectBlock(block) {
269
- return typeof block !== "string" && !("type" in block);
270
- }
271
- //#endregion
272
- //#region src/ui/tui/primitives/layout-helpers.ts
273
- /**
274
- * Estimate the number of terminal rows a content block will occupy,
275
- * including 1 row of marginBottom.
276
- */
277
- function estimateBlockHeight(block, availableWidth) {
278
- if (typeof block === "string") return wordWrap(block, availableWidth).length + 1;
279
- if (isClearBlock(block)) return 0;
280
- if (isLinesBlock(block)) return block.lines.length + 1;
281
- if (isObjectBlock(block)) {
282
- if (typeof block.content === "string") return wordWrap(block.content, availableWidth).length + 1;
283
- return 4;
284
- }
285
- return 1;
286
- }
287
- /**
288
- * Given all blocks, the active index, available width, and a row budget,
289
- * return [startIdx, endIdx] — the range of blocks to render.
290
- *
291
- * Always includes activeIdx. Walks backward to include as many completed
292
- * blocks as fit within maxHeight.
293
- */
294
- function computeVisibleRange(blocks, activeIdx, availableWidth, maxHeight) {
295
- const budget = Math.max(4, maxHeight - 2);
296
- let totalHeight = estimateBlockHeight(blocks[activeIdx], availableWidth);
297
- let start = activeIdx;
298
- for (let i = activeIdx - 1; i >= 0; i--) {
299
- if (isClearBlock(blocks[i])) break;
300
- const h = estimateBlockHeight(blocks[i], availableWidth);
301
- if (totalHeight + h > budget) break;
302
- totalHeight += h;
303
- start = i;
304
- }
305
- return [start, activeIdx];
306
- }
307
- /**
308
- * Word-wrap text at clean word boundaries. Always returns pre-wrapped text
309
- * joined with \n — this avoids Ink's native wrap which can leave leading
310
- * spaces on continuation lines.
311
- *
312
- * Uses a 1-char safety margin so slight width estimate mismatches don't
313
- * cause Ink to re-wrap our already-wrapped lines.
314
- */
315
- function wordWrap(text, availableWidth) {
316
- const safeWidth = Math.max(10, availableWidth - 1);
317
- const words = text.split(/\s+/);
318
- const lines = [];
319
- let currentLine = "";
320
- for (const word of words) if (currentLine.length + word.length + 1 > safeWidth && currentLine.length > 0) {
321
- lines.push(currentLine);
322
- currentLine = word;
323
- } else currentLine += (currentLine.length > 0 ? " " : "") + word;
324
- if (currentLine.length > 0) lines.push(currentLine);
325
- return lines;
326
- }
327
- /**
328
- * Word-wrap text and return only the last `maxRows` lines.
329
- * Used for intra-block truncation when a single text block exceeds the viewport.
330
- * Also used for normal rendering to avoid Ink's leading-space wrap artifacts.
331
- */
332
- function wrapAndTruncate(text, availableWidth, maxRows) {
333
- const lines = wordWrap(text, availableWidth);
334
- if (lines.length <= maxRows) return lines.join("\n");
335
- return lines.slice(-maxRows).join("\n");
336
- }
337
- //#endregion
338
- //#region src/ui/tui/primitives/TextBlock.tsx
339
- /**
340
- * TextBlock — Animates a single string paragraph.
341
- *
342
- * Self-contained: owns its own animIdx and timer.
343
- * Calls onComplete() when the animation finishes.
344
- *
345
- * Five animation modes:
346
- * 1. Typewriter — character-by-character reveal
347
- * 2. Word by word — each word appears in order
348
- * 3. Sentence by sentence — sentences appear one at a time
349
- * 4. Paragraph fade — paragraph appears at full opacity immediately
350
- * 5. Sentence fade — paragraph dim, sentences light up in order
351
- */
352
- /** Default interval per mode (ms) */
353
- const TEXT_REVEAL_MODE_DEFAULTS = {
354
- [1]: 240,
355
- [0]: 32,
356
- [2]: 1800,
357
- [3]: 4800,
358
- [4]: 2400
359
- };
360
- const TextBlock = ({ text, active, completed, onComplete, mode, bullet, animationInterval, sentenceInterval = 1600, maxHeight, availableWidth, dimWhenComplete = true }) => {
361
- const speed = animationInterval ?? TEXT_REVEAL_MODE_DEFAULTS[mode];
362
- const [animIdx, setAnimIdx] = useState(mode === 4 ? 1 : 0);
363
- const resetRef = useRef(0);
364
- const prevMode = useRef(mode);
365
- if (prevMode.current !== mode) {
366
- prevMode.current = mode;
367
- resetRef.current += 1;
368
- setAnimIdx(mode === 4 ? 1 : 0);
369
- }
370
- const words = text.split(/\s+/);
371
- const sentences = splitSentences(text);
372
- const sentenceCharEnds = useMemo(() => sentenceEndChars(text), [text]);
373
- const sentenceWordEnds = useMemo(() => sentenceEndWords(text), [text]);
374
- const isDone = mode === 0 ? animIdx >= text.length : mode === 3 ? true : mode === 1 ? animIdx >= words.length : mode === 4 || mode === 2 ? animIdx >= sentences.length : true;
375
- useEffect(() => {
376
- if (isDone && active) onComplete();
377
- }, [
378
- isDone,
379
- active,
380
- onComplete
381
- ]);
382
- useEffect(() => {
383
- if (!active || mode === 3 || isDone) return;
384
- const token = resetRef.current;
385
- const isFirstTick = animIdx === 0;
386
- let delay = isFirstTick ? 0 : speed;
387
- if (!isFirstTick && mode === 0 && animIdx > 0 && sentenceCharEnds.has(animIdx - 1)) delay = sentenceInterval;
388
- else if (!isFirstTick && mode === 1 && animIdx > 0 && sentenceWordEnds.has(animIdx - 1)) delay = sentenceInterval;
389
- const timer = setTimeout(() => {
390
- if (token !== resetRef.current) return;
391
- setAnimIdx((c) => c + 1);
392
- }, delay);
393
- return () => clearTimeout(timer);
394
- }, [
395
- active,
396
- mode,
397
- animIdx,
398
- isDone,
399
- speed,
400
- sentenceInterval,
401
- sentenceCharEnds,
402
- sentenceWordEnds
403
- ]);
404
- const wrap = (visibleText) => {
405
- if (availableWidth == null) return visibleText;
406
- if (maxHeight == null) return wrapAndTruncate(visibleText, availableWidth, Infinity);
407
- return wrapAndTruncate(visibleText, availableWidth, maxHeight);
408
- };
409
- if (completed) return /* @__PURE__ */ jsxs(Text, {
410
- dimColor: dimWhenComplete,
411
- children: [bullet, wrap(text)]
412
- });
413
- if (mode === 0) {
414
- const revealed = text.slice(0, animIdx);
415
- return /* @__PURE__ */ jsxs(Text, { children: [
416
- bullet,
417
- wrap(/[.!?]\s*$/.test(revealed) ? revealed.trimEnd() : revealed),
418
- /* @__PURE__ */ jsx(Text, {
419
- color: Colors.muted,
420
- children: "▌"
421
- })
422
- ] });
423
- }
424
- if (mode === 1) return /* @__PURE__ */ jsxs(Text, { children: [bullet, wrap(words.slice(0, animIdx).join(" "))] });
425
- if (mode === 3) return /* @__PURE__ */ jsxs(Text, { children: [bullet, wrap(text)] });
426
- if (mode === 2) return /* @__PURE__ */ jsxs(Text, { children: [bullet, wrap(sentences.slice(0, animIdx).join(""))] });
427
- return /* @__PURE__ */ jsxs(Text, { children: [bullet, sentences.map((s, si) => /* @__PURE__ */ jsx(Text, {
428
- dimColor: si >= animIdx,
429
- children: s
430
- }, si))] });
431
- };
432
- //#endregion
433
- //#region src/ui/tui/components/StatusPeekTrigger.tsx
434
- /**
435
- * StatusPeekTrigger — Fires the status-bar expansion once, renders a hint.
436
- *
437
- * Module-level `peekedOnce` guards against re-mounts (resize, tab switch)
438
- * so the peek only happens a single time per process.
439
- */
440
- let peekedOnce = false;
441
- const StatusPeekTrigger = ({ store, duration = 1e4 }) => {
442
- useEffect(() => {
443
- if (peekedOnce) return;
444
- peekedOnce = true;
445
- store?.setStatusExpanded(true);
446
- setTimeout(() => {
447
- store?.setStatusExpanded(false);
448
- }, duration);
449
- }, [store, duration]);
450
- return /* @__PURE__ */ jsx(Text, { children: "You can view the Wizard's status below." });
451
- };
452
- //#endregion
453
- //#region src/lib/programs/posthog-integration/content/data-flow.tsx
454
- /**
455
- * POSTHOG_DATA_FLOW — ASCII diagram of the PostHog event ingestion flow.
456
- */
457
- const POSTHOG_DATA_FLOW = {
458
- type: "lines",
459
- interval: 500,
460
- pause: 8e3,
461
- lines: [
462
- /* @__PURE__ */ jsx(Text, {
463
- color: "gray",
464
- children: " ┌──────────────────────────────┐"
465
- }),
466
- /* @__PURE__ */ jsxs(Text, { children: [
467
- /* @__PURE__ */ jsx(Text, {
468
- color: "gray",
469
- children: " │ "
470
- }),
471
- /* @__PURE__ */ jsx(Text, {
472
- bold: true,
473
- color: "cyan",
474
- children: "Your App"
475
- }),
476
- /* @__PURE__ */ jsx(Text, {
477
- color: "gray",
478
- children: " │"
479
- })
480
- ] }),
481
- /* @__PURE__ */ jsxs(Text, { children: [
482
- /* @__PURE__ */ jsx(Text, {
483
- color: "gray",
484
- children: " │ │ "
485
- }),
486
- /* @__PURE__ */ jsx(Text, { children: "posthog.capture()" }),
487
- /* @__PURE__ */ jsx(Text, {
488
- color: "gray",
489
- children: " │"
490
- })
491
- ] }),
492
- /* @__PURE__ */ jsxs(Text, { children: [
493
- /* @__PURE__ */ jsx(Text, {
494
- color: "gray",
495
- children: " │ │ "
496
- }),
497
- /* @__PURE__ */ jsx(Text, {
498
- dimColor: true,
499
- children: "custom events"
500
- }),
501
- /* @__PURE__ */ jsx(Text, {
502
- color: "gray",
503
- children: " │"
504
- })
505
- ] }),
506
- /* @__PURE__ */ jsxs(Text, { children: [
507
- /* @__PURE__ */ jsx(Text, {
508
- color: "gray",
509
- children: " │ │ "
510
- }),
511
- /* @__PURE__ */ jsx(Text, {
512
- dimColor: true,
513
- children: "custom properties"
514
- }),
515
- /* @__PURE__ */ jsx(Text, {
516
- color: "gray",
517
- children: " │"
518
- })
519
- ] }),
520
- /* @__PURE__ */ jsxs(Text, { children: [
521
- /* @__PURE__ */ jsx(Text, {
522
- color: "gray",
523
- children: " │ │ "
524
- }),
525
- /* @__PURE__ */ jsx(Text, {
526
- dimColor: true,
527
- children: "person profiles"
528
- }),
529
- /* @__PURE__ */ jsx(Text, {
530
- color: "gray",
531
- children: " │"
532
- })
533
- ] }),
534
- /* @__PURE__ */ jsxs(Text, { children: [
535
- /* @__PURE__ */ jsx(Text, {
536
- color: "gray",
537
- children: " │ ↓ "
538
- }),
539
- /* @__PURE__ */ jsx(Text, {
540
- dimColor: true,
541
- children: "groups"
542
- }),
543
- /* @__PURE__ */ jsx(Text, {
544
- color: "gray",
545
- children: " │"
546
- })
547
- ] }),
548
- /* @__PURE__ */ jsxs(Text, { children: [
549
- /* @__PURE__ */ jsx(Text, {
550
- color: "gray",
551
- children: " │ "
552
- }),
553
- /* @__PURE__ */ jsx(Text, {
554
- bold: true,
555
- color: Colors.accent,
556
- children: "PostHog SDK"
557
- }),
558
- /* @__PURE__ */ jsx(Text, {
559
- color: "gray",
560
- children: " │"
561
- })
562
- ] }),
563
- /* @__PURE__ */ jsxs(Text, { children: [
564
- /* @__PURE__ */ jsx(Text, {
565
- color: "gray",
566
- children: " │ ↓ "
567
- }),
568
- /* @__PURE__ */ jsx(Text, { children: "HTTP" }),
569
- /* @__PURE__ */ jsx(Text, {
570
- color: "gray",
571
- children: " │"
572
- })
573
- ] }),
574
- /* @__PURE__ */ jsxs(Text, { children: [
575
- /* @__PURE__ */ jsx(Text, {
576
- color: "gray",
577
- children: " │ "
578
- }),
579
- /* @__PURE__ */ jsx(Text, {
580
- bold: true,
581
- color: Colors.accent,
582
- children: "PostHog Cloud"
583
- }),
584
- /* @__PURE__ */ jsx(Text, {
585
- color: "gray",
586
- children: " │"
587
- })
588
- ] }),
589
- /* @__PURE__ */ jsxs(Text, { children: [
590
- /* @__PURE__ */ jsx(Text, {
591
- color: "gray",
592
- children: " │ ↓ "
593
- }),
594
- /* @__PURE__ */ jsx(Text, { children: "query + visualize" }),
595
- /* @__PURE__ */ jsx(Text, {
596
- color: "gray",
597
- children: " │"
598
- })
599
- ] }),
600
- /* @__PURE__ */ jsxs(Text, { children: [
601
- /* @__PURE__ */ jsx(Text, {
602
- color: "gray",
603
- children: " │ "
604
- }),
605
- /* @__PURE__ */ jsx(Text, {
606
- bold: true,
607
- color: "green",
608
- children: "Dashboards & Insights"
609
- }),
610
- /* @__PURE__ */ jsx(Text, {
611
- color: "gray",
612
- children: " │"
613
- })
614
- ] }),
615
- /* @__PURE__ */ jsx(Text, {
616
- color: "gray",
617
- children: " └──────────────────────────────┘"
618
- })
619
- ]
620
- };
621
- //#endregion
622
- //#region src/lib/programs/posthog-integration/content/product-suite.tsx
623
- /**
624
- * PRODUCT_SUITE_BLOCK — Two-column listing of PostHog products.
625
- */
626
- const PRODUCT_SUITE_BLOCK = {
627
- type: "lines",
628
- interval: 1e3,
629
- pause: 15e3,
630
- lines: [
631
- /* @__PURE__ */ jsxs(Text, { children: [
632
- /* @__PURE__ */ jsx(Text, {
633
- color: "cyan",
634
- children: " ◆ "
635
- }),
636
- "Product Analytics ",
637
- /* @__PURE__ */ jsx(Text, {
638
- color: "cyan",
639
- children: "◆ "
640
- }),
641
- "Error Tracking"
642
- ] }),
643
- /* @__PURE__ */ jsxs(Text, { children: [
644
- /* @__PURE__ */ jsx(Text, {
645
- color: "cyan",
646
- children: " ◆ "
647
- }),
648
- "Web Analytics ",
649
- /* @__PURE__ */ jsx(Text, {
650
- color: "cyan",
651
- children: "◆ "
652
- }),
653
- "Session Replay"
654
- ] }),
655
- /* @__PURE__ */ jsxs(Text, { children: [
656
- /* @__PURE__ */ jsx(Text, {
657
- color: "cyan",
658
- children: " ◆ "
659
- }),
660
- "Feature Flags ",
661
- /* @__PURE__ */ jsx(Text, {
662
- color: "cyan",
663
- children: "◆ "
664
- }),
665
- "Data Pipelines"
666
- ] }),
667
- /* @__PURE__ */ jsxs(Text, { children: [
668
- /* @__PURE__ */ jsx(Text, {
669
- color: "cyan",
670
- children: " ◆ "
671
- }),
672
- "Experiments ",
673
- /* @__PURE__ */ jsx(Text, {
674
- color: "cyan",
675
- children: "◆ "
676
- }),
677
- "Data Warehouse"
678
- ] }),
679
- /* @__PURE__ */ jsxs(Text, { children: [
680
- /* @__PURE__ */ jsx(Text, {
681
- color: "cyan",
682
- children: " ◆ "
683
- }),
684
- "AI Observability ",
685
- /* @__PURE__ */ jsx(Text, {
686
- color: "cyan",
687
- children: "◆ "
688
- }),
689
- "Surveys"
690
- ] }),
691
- /* @__PURE__ */ jsxs(Text, { children: [
692
- /* @__PURE__ */ jsx(Text, {
693
- color: "cyan",
694
- children: " ◆ "
695
- }),
696
- "Workflows ",
697
- /* @__PURE__ */ jsx(Text, {
698
- color: "cyan",
699
- children: "◆ "
700
- }),
701
- "Logs"
702
- ] }),
703
- /* @__PURE__ */ jsxs(Text, { children: [
704
- /* @__PURE__ */ jsx(Text, {
705
- color: "cyan",
706
- children: " ◆ "
707
- }),
708
- "Product Tours ",
709
- /* @__PURE__ */ jsx(Text, {
710
- color: "cyan",
711
- children: "◆ "
712
- }),
713
- "Support"
714
- ] }),
715
- /* @__PURE__ */ jsxs(Text, { children: [
716
- /* @__PURE__ */ jsx(Text, {
717
- color: "cyan",
718
- children: " ◆ "
719
- }),
720
- "Revenue Analytics ",
721
- /* @__PURE__ */ jsx(Text, {
722
- color: "cyan",
723
- children: "◆ "
724
- }),
725
- "Endpoints"
726
- ] }),
727
- /* @__PURE__ */ jsxs(Text, { children: [
728
- /* @__PURE__ */ jsx(Text, {
729
- color: "cyan",
730
- children: " ◆ "
731
- }),
732
- "Customer Analytics ",
733
- /* @__PURE__ */ jsx(Text, {
734
- color: "cyan",
735
- children: "◆ "
736
- }),
737
- "PostHog Code"
738
- ] })
739
- ]
740
- };
741
- //#endregion
742
- //#region src/lib/programs/posthog-integration/content/line-chart.tsx
743
- /**
744
- * LINE_CHART_BLOCK — ASCII trends chart illustrating an insight.
745
- */
746
- const LINE_CHART_BLOCK = {
747
- type: "lines",
748
- interval: 300,
749
- pause: 6e3,
750
- lines: [
751
- /* @__PURE__ */ jsx(Text, {
752
- bold: true,
753
- children: " Trends · user signups (monthly)"
754
- }),
755
- /* @__PURE__ */ jsx(Text, { children: " " }),
756
- /* @__PURE__ */ jsxs(Text, { children: [
757
- /* @__PURE__ */ jsx(Text, {
758
- color: "gray",
759
- children: " 10k ┤"
760
- }),
761
- " ",
762
- /* @__PURE__ */ jsx(Text, {
763
- color: "cyan",
764
- children: "╭──"
765
- }),
766
- /* @__PURE__ */ jsx(Text, {
767
- dimColor: true,
768
- children: " 9,575"
769
- })
770
- ] }),
771
- /* @__PURE__ */ jsxs(Text, { children: [
772
- /* @__PURE__ */ jsx(Text, {
773
- color: "gray",
774
- children: " │"
775
- }),
776
- " ",
777
- /* @__PURE__ */ jsx(Text, {
778
- color: "cyan",
779
- children: "╭╯"
780
- })
781
- ] }),
782
- /* @__PURE__ */ jsxs(Text, { children: [
783
- /* @__PURE__ */ jsx(Text, {
784
- color: "gray",
785
- children: " 7.5k ┤"
786
- }),
787
- " ",
788
- /* @__PURE__ */ jsx(Text, {
789
- color: "cyan",
790
- children: "╭╯"
791
- })
792
- ] }),
793
- /* @__PURE__ */ jsxs(Text, { children: [
794
- /* @__PURE__ */ jsx(Text, {
795
- color: "gray",
796
- children: " │"
797
- }),
798
- " ",
799
- /* @__PURE__ */ jsx(Text, {
800
- color: "cyan",
801
- children: "╭─╯"
802
- })
803
- ] }),
804
- /* @__PURE__ */ jsxs(Text, { children: [
805
- /* @__PURE__ */ jsx(Text, {
806
- color: "gray",
807
- children: " 5k ┤"
808
- }),
809
- " ",
810
- /* @__PURE__ */ jsx(Text, {
811
- color: "cyan",
812
- children: "╭─╯"
813
- })
814
- ] }),
815
- /* @__PURE__ */ jsxs(Text, { children: [
816
- /* @__PURE__ */ jsx(Text, {
817
- color: "gray",
818
- children: " │"
819
- }),
820
- " ",
821
- /* @__PURE__ */ jsx(Text, {
822
- color: "cyan",
823
- children: "╭──╯"
824
- })
825
- ] }),
826
- /* @__PURE__ */ jsxs(Text, { children: [
827
- /* @__PURE__ */ jsx(Text, {
828
- color: "gray",
829
- children: " 2.5k ┤"
830
- }),
831
- " ",
832
- /* @__PURE__ */ jsx(Text, {
833
- color: "cyan",
834
- children: "╭───╯"
835
- })
836
- ] }),
837
- /* @__PURE__ */ jsxs(Text, { children: [
838
- /* @__PURE__ */ jsx(Text, {
839
- color: "gray",
840
- children: " │"
841
- }),
842
- " ",
843
- /* @__PURE__ */ jsx(Text, {
844
- color: "cyan",
845
- children: "╭──────╯"
846
- })
847
- ] }),
848
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
849
- color: "gray",
850
- children: " 0 ┤"
851
- }), /* @__PURE__ */ jsx(Text, {
852
- color: "cyan",
853
- children: "──────╯"
854
- })] }),
855
- /* @__PURE__ */ jsx(Text, {
856
- color: "gray",
857
- children: " └┬─────┬─────┬─────┬─────┬──"
858
- }),
859
- /* @__PURE__ */ jsx(Text, {
860
- dimColor: true,
861
- children: " May Aug Nov Feb May"
862
- })
863
- ]
864
- };
865
- //#endregion
866
- //#region src/lib/programs/posthog-integration/content/funnel.tsx
867
- /**
868
- * FUNNEL_BLOCK — ASCII funnel illustrating step conversion.
869
- */
870
- const FUNNEL_BLOCK = {
871
- type: "lines",
872
- interval: 200,
873
- pause: 8e3,
874
- lines: [
875
- /* @__PURE__ */ jsx(Text, {
876
- bold: true,
877
- children: " Funnel · ride conversion"
878
- }),
879
- /* @__PURE__ */ jsx(Text, { children: " " }),
880
- /* @__PURE__ */ jsxs(Text, { children: [
881
- " ",
882
- /* @__PURE__ */ jsx(Text, {
883
- bold: true,
884
- children: "1"
885
- }),
886
- " app_launched",
887
- " ",
888
- /* @__PURE__ */ jsx(Text, {
889
- bold: true,
890
- color: "green",
891
- children: "100.00%"
892
- })
893
- ] }),
894
- /* @__PURE__ */ jsx(Text, {
895
- color: "cyan",
896
- children: " ██████████████████████████████"
897
- }),
898
- /* @__PURE__ */ jsx(Text, {
899
- dimColor: true,
900
- children: " → 1,200 users"
901
- }),
902
- /* @__PURE__ */ jsx(Text, { children: " " }),
903
- /* @__PURE__ */ jsxs(Text, { children: [
904
- " ",
905
- /* @__PURE__ */ jsx(Text, {
906
- bold: true,
907
- children: "2"
908
- }),
909
- " ride_requested",
910
- " ",
911
- /* @__PURE__ */ jsx(Text, {
912
- dimColor: true,
913
- children: "avg 2m 30s"
914
- }),
915
- " ",
916
- /* @__PURE__ */ jsx(Text, {
917
- bold: true,
918
- color: "green",
919
- children: "72.00%"
920
- })
921
- ] }),
922
- /* @__PURE__ */ jsxs(Text, { children: [
923
- " ",
924
- /* @__PURE__ */ jsx(Text, {
925
- color: "cyan",
926
- children: "██████████████████████"
927
- }),
928
- /* @__PURE__ */ jsx(Text, {
929
- dimColor: true,
930
- children: "░░░░░░░░░"
931
- })
932
- ] }),
933
- /* @__PURE__ */ jsxs(Text, { children: [
934
- " ",
935
- /* @__PURE__ */ jsx(Text, {
936
- dimColor: true,
937
- children: "→ 864 users"
938
- }),
939
- " ",
940
- /* @__PURE__ */ jsx(Text, {
941
- color: "red",
942
- children: "↘"
943
- }),
944
- /* @__PURE__ */ jsx(Text, {
945
- dimColor: true,
946
- children: " 336 (28%)"
947
- })
948
- ] }),
949
- /* @__PURE__ */ jsx(Text, { children: " " }),
950
- /* @__PURE__ */ jsxs(Text, { children: [
951
- " ",
952
- /* @__PURE__ */ jsx(Text, {
953
- bold: true,
954
- children: "3"
955
- }),
956
- " ride_accepted",
957
- " ",
958
- /* @__PURE__ */ jsx(Text, {
959
- dimColor: true,
960
- children: "avg 5m 12s"
961
- }),
962
- " ",
963
- /* @__PURE__ */ jsx(Text, {
964
- bold: true,
965
- color: "green",
966
- children: "51.00%"
967
- })
968
- ] }),
969
- /* @__PURE__ */ jsxs(Text, { children: [
970
- " ",
971
- /* @__PURE__ */ jsx(Text, {
972
- color: "cyan",
973
- children: "██████████████████"
974
- }),
975
- /* @__PURE__ */ jsx(Text, {
976
- dimColor: true,
977
- children: "░░░░░░░░░░░░░"
978
- })
979
- ] }),
980
- /* @__PURE__ */ jsxs(Text, { children: [
981
- " ",
982
- /* @__PURE__ */ jsx(Text, {
983
- dimColor: true,
984
- children: "→ 612 users"
985
- }),
986
- " ",
987
- /* @__PURE__ */ jsx(Text, {
988
- color: "red",
989
- children: "↘"
990
- }),
991
- /* @__PURE__ */ jsx(Text, {
992
- dimColor: true,
993
- children: " 252 (29%)"
994
- })
995
- ] }),
996
- /* @__PURE__ */ jsx(Text, { children: " " }),
997
- /* @__PURE__ */ jsxs(Text, { children: [
998
- " ",
999
- /* @__PURE__ */ jsx(Text, {
1000
- bold: true,
1001
- children: "4"
1002
- }),
1003
- " ride_started",
1004
- " ",
1005
- /* @__PURE__ */ jsx(Text, {
1006
- dimColor: true,
1007
- children: "avg 1m 45s"
1008
- }),
1009
- " ",
1010
- /* @__PURE__ */ jsx(Text, {
1011
- bold: true,
1012
- color: "green",
1013
- children: "38.00%"
1014
- })
1015
- ] }),
1016
- /* @__PURE__ */ jsxs(Text, { children: [
1017
- " ",
1018
- /* @__PURE__ */ jsx(Text, {
1019
- color: "cyan",
1020
- children: "█████████████"
1021
- }),
1022
- /* @__PURE__ */ jsx(Text, {
1023
- dimColor: true,
1024
- children: "░░░░░░░░░░░░░░░░░░"
1025
- })
1026
- ] }),
1027
- /* @__PURE__ */ jsxs(Text, { children: [
1028
- " ",
1029
- /* @__PURE__ */ jsx(Text, {
1030
- dimColor: true,
1031
- children: "→ 456 users"
1032
- }),
1033
- " ",
1034
- /* @__PURE__ */ jsx(Text, {
1035
- color: "red",
1036
- children: "↘"
1037
- }),
1038
- /* @__PURE__ */ jsx(Text, {
1039
- dimColor: true,
1040
- children: " 156 (25%)"
1041
- })
1042
- ] })
1043
- ]
1044
- };
1045
- //#endregion
1046
- //#region src/lib/programs/posthog-integration/content/index.tsx
1047
- /**
1048
- * Integration learn-deck — the narrative script played while the agent
1049
- * runs the PostHog integration flow. Weaves typewriter lines, pauses,
1050
- * `clear` markers, and the diagram blocks into one sequence.
1051
- */
1052
- const getContentBlocks = (store) => [
1053
- {
1054
- content: store?.session.apiUser?.first_name ? `Welcome, ${store.session.apiUser.first_name}.` : "Welcome.",
1055
- pause: 3e3,
1056
- mode: 0,
1057
- animationInterval: 160
1058
- },
1059
- {
1060
- content: "The Wizard is an agent.",
1061
- pause: 4e3
1062
- },
1063
- {
1064
- content: "It handles the entire PostHog setup process on your behalf.",
1065
- pause: 5e3
1066
- },
1067
- {
1068
- content: "As we speak, it's building a plan to set up PostHog in your project.",
1069
- pause: 6e3
1070
- },
1071
- {
1072
- type: "clear",
1073
- pause: 2e3
1074
- },
1075
- {
1076
- pause: 5e3,
1077
- persist: true,
1078
- content: /* @__PURE__ */ jsx(StatusPeekTrigger, { store })
1079
- },
1080
- {
1081
- pause: 6e3,
1082
- content: /* @__PURE__ */ jsxs(Text, { children: [
1083
- "Press",
1084
- " ",
1085
- /* @__PURE__ */ jsx(Text, {
1086
- color: Colors.accent,
1087
- bold: true,
1088
- children: "S"
1089
- }),
1090
- " ",
1091
- "to expand or collapse the status."
1092
- ] })
1093
- },
1094
- {
1095
- type: "clear",
1096
- pause: 2e3
1097
- },
1098
- {
1099
- content: "It takes about eight minutes.",
1100
- pause: 2e3
1101
- },
1102
- {
1103
- content: "So grab some coffee ☕️.",
1104
- pause: 2e3
1105
- },
1106
- {
1107
- content: "Or stick around and learn about PostHog.",
1108
- pause: 5e3
1109
- },
1110
- {
1111
- type: "clear",
1112
- pause: 3e3
1113
- },
1114
- {
1115
- content: "Events are the foundation of the PostHog platform.",
1116
- pause: 4e3
1117
- },
1118
- {
1119
- content: "Every time an action is performed in your codebase — like button clicks, function calls, or thrown errors — we can capture an event.",
1120
- pause: 6e3
1121
- },
1122
- {
1123
- content: "Events are sent to PostHog and joined with other product data.",
1124
- pause: 6e3
1125
- },
1126
- {
1127
- type: "clear",
1128
- pause: 1e3
1129
- },
1130
- {
1131
- content: "Here's the flow.",
1132
- pause: 1e3
1133
- },
1134
- POSTHOG_DATA_FLOW,
1135
- {
1136
- type: "clear",
1137
- pause: 2e3
1138
- },
1139
- {
1140
- content: "With enough event data, you can answer powerful questions about your product.",
1141
- pause: 4e3
1142
- },
1143
- {
1144
- content: "And create insights.",
1145
- pause: 4e3
1146
- },
1147
- {
1148
- type: "clear",
1149
- pause: 500
1150
- },
1151
- {
1152
- content: "Like trends to measure growth.",
1153
- pause: 2500
1154
- },
1155
- LINE_CHART_BLOCK,
1156
- {
1157
- type: "clear",
1158
- pause: 500
1159
- },
1160
- {
1161
- content: "Or funnels to reveal bottlenecks.",
1162
- pause: 2500
1163
- },
1164
- FUNNEL_BLOCK,
1165
- {
1166
- type: "clear",
1167
- pause: 1e3
1168
- },
1169
- {
1170
- content: "Use those signals to decide what to build next.",
1171
- pause: 4e3
1172
- },
1173
- {
1174
- content: "PostHog has all the dev tools you need.",
1175
- pause: 3e3
1176
- },
1177
- PRODUCT_SUITE_BLOCK
1178
- ];
1179
- //#endregion
1180
- //#region src/lib/programs/posthog-integration/handoff.ts
1181
- /**
1182
- * The one-line prompt the operator pastes into their own coding agent after a
1183
- * run: open the setup-report notebook, work its "Verify before merging"
1184
- * checklist. Surfaced via `OutroData.handoffPrompt` (printed to scrollback on
1185
- * exit); only exists when the run captured a notebook URL, since no report
1186
- * file is written. The wording demands investigate-then-approval, and stops
1187
- * there — the operator's own agent governs how changes land. Background:
1188
- * https://github.com/PostHog/wizard/issues/447
1189
- */
1190
- function buildCodingAgentPrompt(notebookUrl) {
1191
- return `Open ${notebookUrl} (the PostHog setup report) and work through its "Verify before merging" checklist: investigate each item, then list the changes you'd make and get my approval before applying any of them.`;
1192
- }
1193
- //#endregion
1194
- //#region src/lib/programs/posthog-integration/index.ts
1195
- const DASHBOARD_DEEP_LINK_KEY = "dashboardDeepLink";
1196
- const WAREHOUSE_SOURCES_DOCS_URL = "https://posthog.com/docs/data-warehouse/sources";
1197
- function resolveContinueUrl(sess, host, deepLink) {
1198
- if (!sess.signup) return void 0;
1199
- if (typeof deepLink === "string" && deepLink) return deepLink;
1200
- return withUtm(`${host.appHost}/products?source=wizard`, "outro-continue");
1201
- }
1202
- /** Sources listed with their own link before the outro falls back to a summary line. */
1203
- const WAREHOUSE_LINK_LIMIT = 3;
1204
- /**
1205
- * The app's new-source page, pre-selected to one source kind.
1206
- *
1207
- * `kind` is matched case-insensitively against the connector list, and a kind
1208
- * the app cannot resolve lands on the source catalog rather than erroring. So a
1209
- * source we detect but the app has not shipped a connector for still takes the
1210
- * user somewhere useful.
1211
- */
1212
- function warehouseSourceUrl(host, projectId, kind) {
1213
- return withUtm(`${host.appHost}/project/${projectId}/data-warehouse/new-source?kind=${encodeURIComponent(kind)}`, "outro-warehouse");
1214
- }
1215
- /**
1216
- * Outro suggestion for data sources found in the project but not connected.
1217
- *
1218
- * A pointer at the app, not an inline flow. Connecting a source needs
1219
- * interactive credential collection, and chaining that as a second agent run
1220
- * before the outro would let any of its terminal failure paths `process.exit()`
1221
- * — costing the user the success outro and the post-outro MCP / Slack steps on
1222
- * a run where PostHog installed fine.
1223
- *
1224
- * Each source gets its own pre-filled link, because the alternative we shipped
1225
- * first — naming the `wizard warehouse` command — asks the user to start a
1226
- * second CLI run before they can connect anything. A link opens the form for
1227
- * that one source. The command line stays for anyone who wants every source in
1228
- * one pass, and it is the only route offered once the list is too long to read.
1229
- *
1230
- * Returns undefined when nothing was detected, so the outro is unchanged for
1231
- * projects with no connectable source.
1232
- */
1233
- function buildWarehouseNextSteps(sess, host, projectId) {
1234
- const sources = getDetectedWarehouseSources(sess);
1235
- if (sources.length === 0) return void 0;
1236
- const listed = sources.slice(0, WAREHOUSE_LINK_LIMIT);
1237
- const items = listed.map((s) => `Connect ${s.label}: ${warehouseSourceUrl(host, projectId, s.kind)}`);
1238
- const remaining = sources.length - listed.length;
1239
- if (remaining > 0) items.push(`And ${remaining} more we found in this project.`);
1240
- items.push("Connect them all at once with: npx @posthog/wizard warehouse");
1241
- return {
1242
- heading: "Query your other data in PostHog:",
1243
- items
1244
- };
1245
- }
1246
- /**
1247
- * Prompt fragment asking the agent to note the detected data sources in the
1248
- * setup report's checklist.
1249
- *
1250
- * Empty string when nothing was detected, so the prompt is byte-identical to
1251
- * today for projects with no connectable source. Best-effort by nature — the
1252
- * agent may word it differently or skip it. That is acceptable here precisely
1253
- * because it is a note in a report: the outro `nextSteps` bullet carries the
1254
- * same information deterministically, so nothing is lost if the agent drops it.
1255
- */
1256
- function warehouseReportInstruction(sess) {
1257
- const sources = getDetectedWarehouseSources(sess);
1258
- if (sources.length === 0) return "";
1259
- return `Finally: this project also contains data sources PostHog can import (${sources.map((s) => s.label).join(", ")}). In the setup report's "Verify before merging" checklist, add one item noting these were found and that \`npx @posthog/wizard warehouse\` will connect them to PostHog's data warehouse. Do not attempt to set them up yourself in this run.`;
1260
- }
1261
- /**
1262
- * The orchestrator task that connects the data sources detection found in the
1263
- * project — the one step of the flow that stops to ask the user for
1264
- * credentials. Queued here rather than by the planner: whether it belongs in
1265
- * the run is a fact about the project the wizard already scanned, so a model
1266
- * can neither invent it nor forget it.
1267
- *
1268
- * It runs at the end of the queue, not the start. Where exactly is the agent
1269
- * prompt's business (`dependsOn` in the warehouse agent's frontmatter, resolved
1270
- * by `seeded-deps.ts` once the planner has run) — this file only decides whether
1271
- * the task belongs in the run at all.
1272
- *
1273
- * Empty when nothing was detected, and in CI, signup, and any other run where
1274
- * `wizard_ask` is disabled — a credential prompt nobody can answer would burn
1275
- * the task's whole timeout and then fail the run.
1276
- */
1277
- const warehouseSeedTasks = (sess) => {
1278
- if (shouldDisableAsk(sess)) return [];
1279
- const sources = getDetectedWarehouseSources(sess);
1280
- if (sources.length === 0) return [];
1281
- if (mayReportScanResults(sess)) analytics.wizardCapture("orchestrator warehouse task queued", {
1282
- warehouse_source_count: sources.length,
1283
- warehouse_source_kinds: sources.map((s) => s.kind)
1284
- });
1285
- return [{
1286
- type: "warehouse",
1287
- inputs: { sources: sources.map((s) => ({
1288
- kind: s.kind,
1289
- label: s.label,
1290
- mode: s.mode,
1291
- matchedSignal: s.matchedSignal
1292
- })) },
1293
- notice: {
1294
- title: "Connect your data sources",
1295
- body: ["We detected some warehouse sources we can connect to enrich your PostHog data. Answer now, and we connect them at the end of the run, after your code changes. We will ask you for the credentials at that point, and beep when we do.", "You can select [Skip] if you'd like to do this later in PostHog."],
1296
- items: sources.map((s) => s.label),
1297
- docsLabel: "Learn more about warehouse sources",
1298
- docsUrl: WAREHOUSE_SOURCES_DOCS_URL,
1299
- prompt: "Connect these during setup?",
1300
- confirmLabel: "Continue [Enter]",
1301
- cancelLabel: "Skip [Esc]"
1302
- }
1303
- }];
1304
- };
1305
- const SETUP_REPORT_FILE = "posthog-setup-report.md";
1306
- const posthogIntegrationConfig = {
1307
- command: "integrate",
1308
- description: "Set up PostHog SDK integration",
1309
- id: "posthog-integration",
1310
- agentFlow: "integration-v2",
1311
- eventPlanFile: EVENT_PLAN_FILE,
1312
- steps: POSTHOG_INTEGRATION_PROGRAM,
1313
- getContentBlocks,
1314
- disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],
1315
- seedTasks: warehouseSeedTasks,
1316
- ciPreRun: async (session) => {
1317
- await scopeInstallDirToProject(session);
1318
- const integration = await detectFramework(session.installDir);
1319
- if (!integration) {
1320
- await wizardAbort({
1321
- code: ErrorCodes.DetectNoFramework,
1322
- message: "Could not auto-detect your framework for this project."
1323
- });
1324
- return;
1325
- }
1326
- session.integration = integration;
1327
- analytics.setTag("integration", integration);
1328
- const frameworkConfig = FRAMEWORK_REGISTRY[integration];
1329
- session.frameworkConfig = frameworkConfig;
1330
- const context = await gatherFrameworkContext(frameworkConfig, {
1331
- installDir: session.installDir,
1332
- debug: session.debug,
1333
- signup: session.signup,
1334
- ci: true,
1335
- benchmark: session.benchmark,
1336
- yaraReport: session.yaraReport
1337
- });
1338
- for (const [key, value] of Object.entries(context)) if (!(key in session.frameworkContext)) session.frameworkContext[key] = value;
1339
- },
1340
- run: async (session) => {
1341
- const config = session.frameworkConfig;
1342
- const typeScriptDetected = isUsingTypeScript({ installDir: session.installDir });
1343
- session.typescript = typeScriptDetected;
1344
- analytics.setTag("typescript", typeScriptDetected);
1345
- const usesPackageJson = config.detection.usesPackageJson !== false;
1346
- let frameworkVersion;
1347
- if (usesPackageJson) {
1348
- const packageJson = await tryGetPackageJson({ installDir: session.installDir });
1349
- if (packageJson) {
1350
- const { hasDeclaredDependency } = await import("./package-json-xt3eeyBI.js").then((n) => n.i);
1351
- if (!hasDeclaredDependency(config.detection.packageName, packageJson)) getUI().log.warn(`${config.detection.packageDisplayName} does not seem to be installed. Continuing anyway — the agent will handle it.`);
1352
- frameworkVersion = config.detection.getVersion(packageJson);
1353
- } else getUI().log.warn("Could not find package.json. Continuing anyway — the agent will handle it.");
1354
- } else frameworkVersion = config.detection.getVersion(null);
1355
- if (frameworkVersion && config.detection.getVersionBucket) {
1356
- const versionBucket = config.detection.getVersionBucket(frameworkVersion);
1357
- analytics.setTag(`${config.metadata.integration}-version`, versionBucket);
1358
- }
1359
- const frameworkContext = session.frameworkContext;
1360
- const contextTags = config.analytics.getTags(frameworkContext);
1361
- Object.entries(contextTags).forEach(([key, value]) => {
1362
- analytics.setTag(key, value);
1363
- });
1364
- return {
1365
- integrationLabel: config.metadata.integration,
1366
- additionalMcpServers: config.metadata.additionalMcpServers,
1367
- detectPackageManager: config.detection.detectPackageManager,
1368
- spinnerMessage: SPINNER_MESSAGE,
1369
- successMessage: config.ui.successMessage,
1370
- estimatedDurationMinutes: config.ui.estimatedDurationMinutes,
1371
- reportFile: SETUP_REPORT_FILE,
1372
- docsUrl: config.metadata.docsUrl,
1373
- errorMessage: "Integration failed",
1374
- additionalFeatureQueue: session.additionalFeatureQueue,
1375
- richLinks: true,
1376
- customPrompt: (ctx) => {
1377
- const additionalLines = config.prompts.getAdditionalContextLines ? config.prompts.getAdditionalContextLines(frameworkContext) : [];
1378
- const additionalContext = additionalLines.length > 0 ? "\n" + additionalLines.map((line) => `- ${line}`).join("\n") : "";
1379
- return `You have access to the PostHog MCP server which provides skills to integrate PostHog into this ${config.metadata.name} project.
1380
-
1381
- Project context:
1382
- - PostHog Project ID: ${ctx.projectId}
1383
- - Framework: ${config.metadata.name} ${frameworkVersion || "latest"}
1384
- - TypeScript: ${typeScriptDetected ? "Yes" : "No"}
1385
- - PostHog public token: ${ctx.projectApiKey}
1386
- - PostHog Host: ${ctx.host.apiHost}
1387
- - Project type: ${config.prompts.projectTypeDetection}
1388
- - Package installation: ${config.prompts.packageInstallation ?? "Use the detect_package_manager tool to determine the package manager. Do not manually edit package.json; the package manager handles it automatically."}${additionalContext}
1389
-
1390
- Instructions (follow these steps IN ORDER - do not skip or reorder):
1391
-
1392
- STEP 1: Call load_skill_menu (from the wizard-tools MCP server) to see available skills.
1393
- If the tool fails, emit: ${AgentSignals.ERROR_MCP_MISSING} Could not load skill menu and halt.
1394
-
1395
- Choose a skill from the \`integration\` category that matches this project's framework. Do NOT pick skills from other categories (llm-analytics, error-tracking, feature-flags, omnibus, etc.) — those are handled separately.
1396
- If no suitable integration skill is found, emit: ${AgentSignals.ERROR_RESOURCE_MISSING} Could not find a suitable skill for this project.
1397
-
1398
- STEP 2: Call install_skill (from the wizard-tools MCP server) with the chosen skill ID (e.g., "integration-nextjs-app-router").
1399
- Do NOT run any shell commands to install skills.
1400
- If install_skill fails, emit on its own line: ${AgentSignals.SKILL_INSTALL_FAILED} <skill id — one-line reason>. Then CONTINUE and SKIP to STEP 5 the integration without the skill, following these steps and your knowledge of ${config.metadata.name} and PostHog's official docs, and note in the setup report that the skill could not be installed.
1401
-
1402
- STEP 3: Load the installed skill's SKILL.md file to understand what references are available.
1403
-
1404
- STEP 4: Follow the skill's program files in sequence. Look for numbered program files in the references (e.g., files with patterns like "1-", "2-", "3-"). Start with the first one and proceed through each step until completion. Each program file will tell you what to do and which file comes next. Never directly write PostHog tokens directly to code files; always use environment variables.
1405
-
1406
- STEP 5: Set up environment variables for PostHog using the wizard-tools MCP server (this runs locally — secret values never leave the machine):
1407
- - Use check_env_keys to see which keys the project already sets, and where. Omit filePath and it scans every .env file in the project, so you don't have to guess between .env, .env.local and a nested one. It answers { status, foundIn } per key: "present" means a real env file sets the key, while a key found only in a committed template (.env.example and friends) reads as "missing" — a template documents a key rather than setting it, and is never a file to write credentials into.
1408
- - Use set_env_values to create or update the PostHog public token and host, using the appropriate environment variable naming convention for ${config.metadata.name}, which you'll find in example code. The tool will also ensure .gitignore coverage. Don't assume the presence of keys means the value is up to date. Write the correct value each time.
1409
- - Reference these environment variables in the code files you create instead of hardcoding the public token and host.
1410
-
1411
- Important: Use the detect_package_manager tool (from the wizard-tools MCP server) to determine which package manager the project uses, then run its install command to add the SDK. Do not manually search for lockfiles or config files. If a file already EXISTS, read it immediately before you edit or overwrite it — writing from a stale read causes a tool failure. Creating a brand-new file needs no prior read: never read a path that does not exist yet; just write it.
1412
-
1413
- ${warehouseReportInstruction(session)}
1414
- `;
1415
- },
1416
- postRun: async (sess, credentials) => {
1417
- const envVars = config.environment.getEnvVars(credentials.projectApiKey, credentials.host.apiHost);
1418
- if (config.environment.uploadToHosting) {
1419
- const { uploadEnvironmentVariablesStep } = await import("./steps-D4mHkYX4.js");
1420
- const uploadedEnvVars = await uploadEnvironmentVariablesStep(envVars, {
1421
- integration: config.metadata.integration,
1422
- session: sess
1423
- });
1424
- if (uploadedEnvVars.length > 0) analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {
1425
- action: "wizard_env_vars_uploaded",
1426
- integration: config.metadata.integration,
1427
- variable_count: uploadedEnvVars.length,
1428
- variable_keys: uploadedEnvVars
1429
- });
1430
- }
1431
- if (sess.signup) {
1432
- const deepLink = await requestDeepLink(credentials.accessToken, credentials.host);
1433
- if (deepLink) {
1434
- const taggedDeepLink = withUtm(deepLink, "dashboard-deeplink");
1435
- sess.frameworkContext[DASHBOARD_DEEP_LINK_KEY] = taggedDeepLink;
1436
- openTrackedLink(taggedDeepLink, "dashboard-deeplink", { auto: true });
1437
- }
1438
- }
1439
- },
1440
- buildOutroData: (sess, credentials) => {
1441
- const envVars = config.environment.getEnvVars(credentials.projectApiKey, credentials.host.apiHost);
1442
- const deepLink = sess.frameworkContext[DASHBOARD_DEEP_LINK_KEY];
1443
- const continueUrl = resolveContinueUrl(sess, credentials.host, deepLink);
1444
- return {
1445
- kind: "success",
1446
- message: "Successfully installed PostHog!",
1447
- changes: [...config.ui.getOutroChanges(frameworkContext), Object.keys(envVars).length > 0 ? "Added environment variables to .env file" : ""].filter(Boolean),
1448
- docsUrl: config.metadata.docsUrl,
1449
- continueUrl,
1450
- nextSteps: buildWarehouseNextSteps(sess, credentials.host, credentials.projectId),
1451
- notebookUrl: sess.notebookUrl ?? void 0,
1452
- handoffPrompt: sess.notebookUrl ? buildCodingAgentPrompt(sess.notebookUrl) : void 0
1453
- };
1454
- }
1455
- };
1456
- }
1457
- };
1458
- /**
1459
- * Self-contained run step that runs the integration agent. Other programs
1460
- * import this and splice it into their own step list to compose the
1461
- * integration's work as one of their run steps — self-driving sets up PostHog
1462
- * this way before its own run. The host program supplies `show`/`onRunPrep`/
1463
- * `targetDir`; this carries the run.
1464
- */
1465
- const integrationRunStep = {
1466
- id: "run",
1467
- label: "Integration",
1468
- screenId: "run",
1469
- run: (session) => runAgent(posthogIntegrationConfig, session, { composed: true }),
1470
- isComplete: (session) => session.runPhase === "completed" || session.runPhase === "error"
1471
- };
1472
- //#endregion
1473
- export { detectIntegrationProjects as _, LINE_CHART_BLOCK as a, TextBlock as c, isClearBlock as d, isLinesBlock as f, HEALTH_CHECK_STEP as g, Icons as h, FUNNEL_BLOCK as i, computeVisibleRange as l, Colors as m, integrationRunStep as n, PRODUCT_SUITE_BLOCK as o, isObjectBlock as p, posthogIntegrationConfig as r, StatusPeekTrigger as s, SETUP_REPORT_FILE as t, wordWrap as u, scopeInstallDirToProject as v };
1474
-
1475
- //# sourceMappingURL=posthog-integration-su2LXi3-.js.map