@posthog/wizard 2.75.0 → 2.76.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 (106) hide show
  1. package/dist/{add-mcp-server-to-clients-CjfnPMbO.js → add-mcp-server-to-clients-Exddicp2.js} +5 -5
  2. package/dist/{add-mcp-server-to-clients-CjfnPMbO.js.map → add-mcp-server-to-clients-Exddicp2.js.map} +1 -1
  3. package/dist/{agent-interface-BKLTDSyN.js → agent-interface-CZWRgZMc.js} +69 -46
  4. package/dist/agent-interface-CZWRgZMc.js.map +1 -0
  5. package/dist/{agent-prompt-loader-DAagxT3p.js → agent-prompt-loader-BobuLDIg.js} +5 -5
  6. package/dist/{agent-prompt-loader-DAagxT3p.js.map → agent-prompt-loader-BobuLDIg.js.map} +1 -1
  7. package/dist/{agent-runner-BkQontri.js → agent-runner-C_R1X_UT.js} +40 -16
  8. package/dist/agent-runner-C_R1X_UT.js.map +1 -0
  9. package/dist/{analytics-DSK0GXg1.js → analytics-C_RyE8fz.js} +3 -2
  10. package/dist/analytics-C_RyE8fz.js.map +1 -0
  11. package/dist/analytics-DXvdQqyp.js +2 -0
  12. package/dist/{api-CwNulLDK.js → api-k5aGQpIZ.js} +3 -3
  13. package/dist/{api-CwNulLDK.js.map → api-k5aGQpIZ.js.map} +1 -1
  14. package/dist/bin.js +83 -59
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{bounded-fs-D85Tk3nS.js → bounded-fs-BHLy83N9.js} +3 -3
  17. package/dist/{bounded-fs-D85Tk3nS.js.map → bounded-fs-BHLy83N9.js.map} +1 -1
  18. package/dist/{ci-install-CQLi_a-r.js → ci-install-CXt4c41q.js} +4 -4
  19. package/dist/{ci-install-CQLi_a-r.js.map → ci-install-CXt4c41q.js.map} +1 -1
  20. package/dist/{debug-CBmI5YUF.js → debug-BxMMpepn.js} +1 -1
  21. package/dist/{debug-DUmMVUHn.js → debug-C5Zz8hmm.js} +6 -4
  22. package/dist/{debug-DUmMVUHn.js.map → debug-C5Zz8hmm.js.map} +1 -1
  23. package/dist/{defaults-DDDwYTN5.js → defaults-DulzMJpN.js} +1 -1
  24. package/dist/{defaults-DDDwYTN5.js.map → defaults-DulzMJpN.js.map} +1 -1
  25. package/dist/{env-api-key-CGC1Bqwq.js → env-api-key-Ca-CrkgV.js} +2 -2
  26. package/dist/{env-api-key-CGC1Bqwq.js.map → env-api-key-Ca-CrkgV.js.map} +1 -1
  27. package/dist/{environment-DC4RDnzR.js → environment-B0uTamFf.js} +4 -4
  28. package/dist/{environment-DC4RDnzR.js.map → environment-B0uTamFf.js.map} +1 -1
  29. package/dist/file-CNstcW8F.js +60 -0
  30. package/dist/file-CNstcW8F.js.map +1 -0
  31. package/dist/{file-watcher-hafFFQib.js → file-watcher-CiT-oZpu.js} +2 -2
  32. package/dist/{file-watcher-hafFFQib.js.map → file-watcher-CiT-oZpu.js.map} +1 -1
  33. package/dist/{gateway-session-zwwZAyTt.js → gateway-session-BIVN_Xfr.js} +1 -1
  34. package/dist/{gateway-session-Ctc2xaz7.js → gateway-session-C3Uqwc4R.js} +4 -4
  35. package/dist/{gateway-session-Ctc2xaz7.js.map → gateway-session-C3Uqwc4R.js.map} +1 -1
  36. package/dist/{headless-ui-CQ46FOTh.js → headless-ui-TpSp-F43.js} +10 -5
  37. package/dist/headless-ui-TpSp-F43.js.map +1 -0
  38. package/dist/{interactive-5O4XQf59.js → interactive-B72L-sO5.js} +2 -2
  39. package/dist/{interactive-5O4XQf59.js.map → interactive-B72L-sO5.js.map} +1 -1
  40. package/dist/{mcp-D0Dni4tL.js → mcp-CNc6CLK0.js} +2 -2
  41. package/dist/{mcp-D0Dni4tL.js.map → mcp-CNc6CLK0.js.map} +1 -1
  42. package/dist/{mcp-prompt-streaming-DNCDeU51.js → mcp-prompt-streaming-BvBNkzjv.js} +5 -5
  43. package/dist/{mcp-prompt-streaming-DNCDeU51.js.map → mcp-prompt-streaming-BvBNkzjv.js.map} +1 -1
  44. package/dist/{mint-failure-CQqypC_v.js → mint-failure-CZ5FZ0Jd.js} +38 -17
  45. package/dist/mint-failure-CZ5FZ0Jd.js.map +1 -0
  46. package/dist/{non-interactive-D5-lCBy6.js → non-interactive-UeQlnU0U.js} +2 -2
  47. package/dist/{non-interactive-D5-lCBy6.js.map → non-interactive-UeQlnU0U.js.map} +1 -1
  48. package/dist/{orchestrator-tools-D8ZQS2DM.js → orchestrator-tools-CLADku26.js} +3 -3
  49. package/dist/{orchestrator-tools-D8ZQS2DM.js.map → orchestrator-tools-CLADku26.js.map} +1 -1
  50. package/dist/{package-manager-hyP-CPSZ.js → package-manager-CppzeIgu.js} +2 -2
  51. package/dist/{package-manager-hyP-CPSZ.js.map → package-manager-CppzeIgu.js.map} +1 -1
  52. package/dist/{pi-DARAk2I_.js → pi-Bs1Tbt0C.js} +12 -12
  53. package/dist/{pi-DARAk2I_.js.map → pi-Bs1Tbt0C.js.map} +1 -1
  54. package/dist/{playground-Djabnagq.js → playground-CZgZX4j0.js} +6 -6
  55. package/dist/{playground-Djabnagq.js.map → playground-CZgZX4j0.js.map} +1 -1
  56. package/dist/{posthog-C3Sncfan.js → posthog-BZ3NNCyh.js} +2 -2
  57. package/dist/{posthog-C3Sncfan.js.map → posthog-BZ3NNCyh.js.map} +1 -1
  58. package/dist/{provisioning-B74q1uSQ.js → provisioning-Ba7GWKzK.js} +3 -3
  59. package/dist/{provisioning-B74q1uSQ.js.map → provisioning-Ba7GWKzK.js.map} +1 -1
  60. package/dist/{queue-tools-FLMG8hcB.js → queue-tools-D09PNS0X.js} +3 -3
  61. package/dist/{queue-tools-FLMG8hcB.js.map → queue-tools-D09PNS0X.js.map} +1 -1
  62. package/dist/{registry-DZoReEU3.js → registry-COcpEsMD.js} +5 -5
  63. package/dist/{registry-DZoReEU3.js.map → registry-COcpEsMD.js.map} +1 -1
  64. package/dist/{security-DiBFYwh7.js → security-CpAT0fZa.js} +5 -5
  65. package/dist/{security-DiBFYwh7.js.map → security-CpAT0fZa.js.map} +1 -1
  66. package/dist/{setup-utils-C3tsa6D6.js → setup-utils-BUAoRjw3.js} +8 -8
  67. package/dist/{setup-utils-C3tsa6D6.js.map → setup-utils-BUAoRjw3.js.map} +1 -1
  68. package/dist/{start-tui-BXjJGNx2.js → start-tui-Bz23_yym.js} +20 -33
  69. package/dist/start-tui-Bz23_yym.js.map +1 -0
  70. package/dist/{steps-CeFanezY.js → steps-DbsDish5.js} +7 -7
  71. package/dist/{steps-CeFanezY.js.map → steps-DbsDish5.js.map} +1 -1
  72. package/dist/{store-DN_6FaoQ.js → store-D5ROpUje.js} +5 -5
  73. package/dist/store-D5ROpUje.js.map +1 -0
  74. package/dist/{subagent-BzhCH9c3.js → subagent-CSBZnhgK.js} +2 -2
  75. package/dist/{subagent-BzhCH9c3.js.map → subagent-CSBZnhgK.js.map} +1 -1
  76. package/dist/{task-DZKmaWYF.js → task-D8sTR7jZ.js} +17 -14
  77. package/dist/task-D8sTR7jZ.js.map +1 -0
  78. package/dist/{task-stream-h-b1nWdM.js → task-stream-Dl0XEsZ9.js} +48 -6
  79. package/dist/task-stream-Dl0XEsZ9.js.map +1 -0
  80. package/dist/{tasks-0Rb5AXpz.js → tasks-BDt427kT.js} +2 -2
  81. package/dist/{tasks-0Rb5AXpz.js.map → tasks-BDt427kT.js.map} +1 -1
  82. package/dist/{telemetry-QpeVhVtU.js → telemetry-Dp6zjZBj.js} +3 -3
  83. package/dist/{telemetry-QpeVhVtU.js.map → telemetry-Dp6zjZBj.js.map} +1 -1
  84. package/dist/{terminal-dLoYiXsd.js → terminal-pInlleVD.js} +12 -12
  85. package/dist/{terminal-dLoYiXsd.js.map → terminal-pInlleVD.js.map} +1 -1
  86. package/dist/{tools-DmwO0eBZ.js → tools-MkyMOjQI.js} +82 -18
  87. package/dist/tools-MkyMOjQI.js.map +1 -0
  88. package/dist/{wizard-abort-B0c5VDie.js → wizard-abort-BCnUgT9z.js} +3 -3
  89. package/dist/{wizard-abort-B0c5VDie.js.map → wizard-abort-BCnUgT9z.js.map} +1 -1
  90. package/dist/{wizard-abort-C9Jbm-m7.js → wizard-abort-BHLKVKLN.js} +1 -1
  91. package/dist/{yara-hooks-uCiAIcqU.js → yara-hooks-BJWVgTpU.js} +4 -4
  92. package/dist/{yara-hooks-uCiAIcqU.js.map → yara-hooks-BJWVgTpU.js.map} +1 -1
  93. package/dist/yara-hooks-Dp82xJGd.js +2 -0
  94. package/package.json +1 -1
  95. package/dist/agent-interface-BKLTDSyN.js.map +0 -1
  96. package/dist/agent-runner-BkQontri.js.map +0 -1
  97. package/dist/analytics-DSK0GXg1.js.map +0 -1
  98. package/dist/analytics-yurAACt5.js +0 -2
  99. package/dist/headless-ui-CQ46FOTh.js.map +0 -1
  100. package/dist/mint-failure-CQqypC_v.js.map +0 -1
  101. package/dist/start-tui-BXjJGNx2.js.map +0 -1
  102. package/dist/store-DN_6FaoQ.js.map +0 -1
  103. package/dist/task-DZKmaWYF.js.map +0 -1
  104. package/dist/task-stream-h-b1nWdM.js.map +0 -1
  105. package/dist/tools-DmwO0eBZ.js.map +0 -1
  106. package/dist/yara-hooks-B7prW1Ng.js +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-stream-Dl0XEsZ9.js","names":[],"sources":["../src/lib/task-stream/event-plan-watcher.ts","../src/lib/task-stream/audit-areas.ts","../src/lib/task-stream/task-stream-push.ts"],"sourcesContent":["import type { PlannedEvent, WizardStore } from '@ui/tui/store';\nimport {\n startFileWatcher,\n type FileWatcherHandle,\n type FileWatcherOptions,\n} from '@lib/file-watcher';\n\nconst MAX_EVENT_PLAN_FILE_BYTES = 256 * 1024;\nconst MAX_EVENT_COUNT = 50;\nconst MAX_EVENT_NAME_LENGTH = 400;\nconst MAX_EVENT_DESCRIPTION_LENGTH = 4000;\n\nfunction firstString(...values: unknown[]): string | null {\n const value = values.find((candidate) => typeof candidate === 'string');\n return typeof value === 'string' ? value : null;\n}\n\nexport function normalizeEventPlan(parsed: unknown): PlannedEvent[] | null {\n if (!Array.isArray(parsed)) return null;\n\n const events: PlannedEvent[] = [];\n for (const value of parsed) {\n if (events.length >= MAX_EVENT_COUNT) break;\n\n const entry =\n value && typeof value === 'object'\n ? (value as Record<string, unknown>)\n : {};\n const name = firstString(entry.event_name, entry.name, entry.event);\n if (!name || !name.trim() || name.length > MAX_EVENT_NAME_LENGTH) continue;\n\n const description =\n firstString(entry.event_description, entry.description) ?? '';\n events.push({\n name,\n description: description.slice(0, MAX_EVENT_DESCRIPTION_LENGTH),\n });\n }\n\n return events;\n}\n\nexport class EventPlanWatcher {\n private handle: FileWatcherHandle | null = null;\n private captured = false;\n\n constructor(\n private readonly store: WizardStore,\n private readonly path: string,\n private readonly options: FileWatcherOptions = {},\n ) {}\n\n start(): void {\n if (this.handle || this.captured) return;\n\n this.handle = startFileWatcher(\n this.path,\n (parsed) => {\n const events = normalizeEventPlan(parsed);\n if (!events || events.length === 0) return;\n\n this.captured = true;\n this.store.setEventPlan(events);\n this.stop();\n },\n {\n ignoreInitialFile: true,\n maxFileSizeBytes: MAX_EVENT_PLAN_FILE_BYTES,\n ...this.options,\n },\n );\n }\n\n refresh(): void {\n if (this.captured) return;\n this.handle?.refresh();\n }\n\n stop(): void {\n this.handle?.stop();\n this.handle = null;\n }\n}\n","/**\n * Audit ledger → stream tasks: one row per audit *area*, never per check.\n *\n * A run resolves tens of checks, and each row carries a `file` path and a\n * `details` string derived from the user's code. Neither belongs on the wire.\n * A finding is progress, not a failure, so an area never reports `failed`.\n */\n\nimport type { AuditCheck, AuditStatus } from '@lib/programs/audit/types';\nimport { StreamTaskStatus, type StreamTask } from './types';\n\nexport const MAX_AUDIT_AREAS = 24;\nconst MAX_AREA_TITLE_LENGTH = 80;\n\nconst RESOLVED: readonly AuditStatus[] = [\n 'pass',\n 'error',\n 'warning',\n 'suggestion',\n];\n\nfunction areaTitle(value: unknown): string | null {\n if (typeof value !== 'string' || !value.trim()) return null;\n return value.trim().slice(0, MAX_AREA_TITLE_LENGTH);\n}\n\n/** `idOffset` continues the program's task ids, which are stringified integers. */\nexport function rollUpAuditAreas(checks: unknown, idOffset = 0): StreamTask[] {\n if (!Array.isArray(checks)) return [];\n\n // Map keeps insertion order, which is the order the ledger seeds its areas in.\n const areas = new Map<string, { total: number; resolved: number }>();\n\n for (const entry of checks) {\n if (!entry || typeof entry !== 'object') continue;\n const title = areaTitle((entry as Partial<AuditCheck>).area);\n if (!title) continue;\n\n let counts = areas.get(title);\n if (!counts) {\n if (areas.size >= MAX_AUDIT_AREAS) continue;\n counts = { total: 0, resolved: 0 };\n areas.set(title, counts);\n }\n counts.total += 1;\n // The ledger is agent-written: anything unrecognized counts as unresolved.\n if (RESOLVED.includes((entry as Partial<AuditCheck>).status as AuditStatus))\n counts.resolved += 1;\n }\n\n return [...areas.entries()].map(([title, { total, resolved }], index) => ({\n id: String(idOffset + index),\n title,\n status:\n resolved === 0\n ? StreamTaskStatus.Pending\n : resolved < total\n ? StreamTaskStatus.InProgress\n : StreamTaskStatus.Completed,\n }));\n}\n","/**\n * Task-stream push — subscribes to WizardStore, builds payloads,\n * and fans out async to all registered destinations.\n *\n * Behaviour:\n * - `attach(store)` subscribe to store changes\n * - task updates debounced 250ms (trailing edge)\n * - phase transitions flush immediately, bypass debounce\n * - RunPhase.Idle skipped (no push)\n * - enabled === false destination delivery is disabled\n * - shutdown(timeoutMs) cancel pending, flush terminal phase\n * with timeout, never throw\n *\n * Concurrency: only one fan-out at a time. Emits during an in-flight\n * push are coalesced — at most one follow-up push fires with the\n * latest state once the current one settles.\n */\n\nimport type { WizardStore, TaskItem } from '@ui/tui/store';\nimport { TaskStatus } from '@ui/wizard-ui';\nimport {\n RunPhase,\n OutroKind,\n type OutroData,\n type PendingQuestion,\n} from '@lib/wizard-session';\nimport {\n type TaskStreamDestination,\n type TaskStreamUpdate,\n type StreamTask,\n type TaskStreamError,\n type StreamPendingInput,\n StreamTaskStatus,\n StreamEvent,\n} from './types';\nimport { EventPlanWatcher } from './event-plan-watcher';\nimport { rollUpAuditAreas } from './audit-areas';\nimport { logToFile } from '@utils/debug';\nimport { sanitizeErrorDetail } from '@lib/errors';\n\n/** Trailing-edge debounce window for non-phase-change emits. */\nconst DEBOUNCE_MS = 250;\n/** Default shutdown timeout for the final terminal flush. */\nconst DEFAULT_SHUTDOWN_TIMEOUT_MS = 2000;\n\nconst STATUS_MAP: Record<TaskStatus, StreamTaskStatus> = {\n [TaskStatus.Pending]: StreamTaskStatus.Pending,\n [TaskStatus.InProgress]: StreamTaskStatus.InProgress,\n [TaskStatus.Completed]: StreamTaskStatus.Completed,\n // The stream has no skipped state; skipped is terminal, so report it resolved.\n [TaskStatus.Skipped]: StreamTaskStatus.Completed,\n};\n\nfunction buildTasks(items: TaskItem[]): StreamTask[] {\n return items.map((item, i) => ({\n id: String(i),\n title: item.label,\n status: STATUS_MAP[item.status] ?? StreamTaskStatus.Pending,\n }));\n}\n\n/** Drop \".SSSZ\" → \"Z\" so session_id segments stay routing-safe. */\nfunction secondPrecisionIso(d: Date): string {\n return d.toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n\n/**\n * `workflow_id` and `skill_id` end up unescaped in Redis pub/sub\n * channel names, so the backend rejects anything outside\n * `^[A-Za-z0-9_.-]{1,255}$` with a 400. All current values already\n * comply; this is defence in depth in case a future caller passes\n * something with `:`, spaces, or other separators.\n */\nfunction sanitizeChannelId(value: string): string {\n return value.replace(/[^A-Za-z0-9_.-]/g, '-').slice(0, 255);\n}\n\nfunction buildError(\n phase: RunPhase,\n outroData: OutroData | null,\n): TaskStreamError | undefined {\n if (phase !== RunPhase.Error) return undefined;\n if (outroData?.kind === OutroKind.Error) {\n const message = outroData.message ?? outroData.body ?? 'Wizard run failed';\n const error: TaskStreamError = { type: 'wizard_error', message };\n if (outroData.errorCode) error.code = outroData.errorCode;\n const safeDetail = sanitizeErrorDetail(outroData.errorDetail);\n if (safeDetail) error.detail = safeDetail;\n return error;\n }\n return { type: 'wizard_error', message: 'Wizard run failed' };\n}\n\n/**\n * Sensitive asks (secrets, API keys) publish only the fact that input is\n * required — never the prompt text. The session row is team-visible and\n * outlives the prompt.\n */\nfunction buildPendingInput(\n question: PendingQuestion | null | undefined,\n): StreamPendingInput | undefined {\n if (!question) return undefined;\n const sensitive = question.questions.some((q) => q.sensitive === true);\n return {\n id: question.id,\n asked_at: question.askedAt ?? new Date().toISOString(),\n question_count: question.questions.length,\n sensitive,\n prompts: sensitive ? undefined : question.questions.map((q) => q.prompt),\n };\n}\n\nexport interface TaskStreamPushOptions {\n store: WizardStore;\n programId: string;\n destinations: TaskStreamDestination[];\n /** Optional absolute event-plan path to load into the store once. */\n eventPlanPath?: string;\n /** The run's audit ledger, when it has one. The runner owns the watcher. */\n auditChecks?: () => unknown;\n /** When false, destination subscription/delivery remains disabled. */\n enabled?: boolean;\n}\n\nexport class TaskStreamPush {\n private readonly store: WizardStore;\n private readonly destinations: TaskStreamDestination[];\n private readonly startedAt: string;\n private readonly programId: string;\n private readonly sessionId: string;\n private readonly eventPlanWatcher: EventPlanWatcher | null;\n private readonly auditChecks: (() => unknown) | null;\n\n private enabled: boolean;\n private created = false;\n private lastPushedPhase: RunPhase | null = null;\n private lastPushedQuestionId: string | null = null;\n\n private unsubscribe: (() => void) | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private inFlight: Promise<void> | null = null;\n private needsAnotherPush = false;\n private shuttingDown = false;\n\n constructor(opts: TaskStreamPushOptions) {\n this.store = opts.store;\n this.programId = sanitizeChannelId(opts.programId);\n this.destinations = opts.destinations;\n this.enabled = opts.enabled ?? true;\n const startedAt = new Date();\n this.eventPlanWatcher = opts.eventPlanPath\n ? new EventPlanWatcher(this.store, opts.eventPlanPath)\n : null;\n this.auditChecks = opts.auditChecks ?? null;\n this.startedAt = secondPrecisionIso(startedAt);\n // skillId may not be set yet — fall back to programId so the\n // session_id is stable for the whole run regardless of when the\n // program metadata is populated.\n const skillId = sanitizeChannelId(\n this.store.session.skillId ?? this.programId,\n );\n this.sessionId = `${this.programId}-${skillId}-${this.startedAt}`;\n }\n\n /**\n * Load the event plan and subscribe to store changes. Destination delivery\n * remains disabled when `enabled === false`, but the plan still populates the\n * store for local and headless consumers.\n */\n attach(store?: WizardStore): void {\n this.eventPlanWatcher?.start();\n if (!this.enabled) return;\n if (this.unsubscribe) return;\n const target = store ?? this.store;\n this.unsubscribe = target.subscribe(() => this.onStoreChange());\n }\n\n /** Stop subscribing. Does not flush. */\n detach(): void {\n this.eventPlanWatcher?.stop();\n if (this.unsubscribe) {\n this.unsubscribe();\n this.unsubscribe = null;\n }\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n }\n\n /**\n * Cancel pending debounce, flush one final push if the current\n * phase is terminal, and resolve. Never throws. Bounded by\n * `timeoutMs` — if a destination hangs, this returns anyway.\n */\n async shutdown(\n timeoutMs: number = DEFAULT_SHUTDOWN_TIMEOUT_MS,\n ): Promise<void> {\n this.shuttingDown = true;\n this.eventPlanWatcher?.refresh();\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n this.detach();\n if (!this.enabled) return;\n\n const phase = this.store.session.runPhase;\n const isTerminal = phase === RunPhase.Completed || phase === RunPhase.Error;\n if (!isTerminal) return;\n\n const flush = this.flush();\n if (timeoutMs <= 0) return;\n await Promise.race([\n flush,\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),\n ]);\n }\n\n /**\n * Imperative push — fires immediately regardless of phase. Kept as\n * the building block for both subscription-driven and direct calls.\n */\n async push(): Promise<void> {\n await this.flush();\n }\n\n // ── Internal ────────────────────────────────────────────────────\n\n private onStoreChange(): void {\n if (!this.enabled || this.shuttingDown) return;\n const phase = this.store.session.runPhase;\n if (phase === RunPhase.Idle) return;\n\n // A push is already in flight — coalesce. The in-flight push's\n // settle handler will trigger one follow-up with the latest state.\n if (this.inFlight) {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n this.needsAnotherPush = true;\n return;\n }\n\n const phaseChanged = phase !== this.lastPushedPhase;\n const questionId = this.store.session.pendingQuestion?.id ?? null;\n const questionChanged = questionId !== this.lastPushedQuestionId;\n if (phaseChanged || questionChanged) {\n // Phase transitions bypass the debounce: the web app needs to\n // see Running → Completed as soon as it lands. A wizard_ask\n // opening or closing is the same shape — the whole point of\n // publishing it is that the user is looking at the web app, so\n // a 250ms-stale \"needs your input\" defeats the purpose.\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n void this.flush();\n return;\n }\n\n // Task updates can arrive faster than we want to push. Debounce\n // them — the last update in a burst wins.\n if (this.debounceTimer) return;\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n void this.flush();\n }, DEBOUNCE_MS);\n }\n\n /**\n * Fan out the current state to every destination. Serialized — if\n * a flush is already running, mark \"needs another\" and let the\n * in-flight one schedule the follow-up when it settles.\n */\n private flush(): Promise<void> {\n if (this.inFlight) {\n this.needsAnotherPush = true;\n return this.inFlight;\n }\n\n const run = async (): Promise<void> => {\n try {\n await this.sendOnce();\n } finally {\n this.inFlight = null;\n if (this.needsAnotherPush) {\n this.needsAnotherPush = false;\n // Re-enter to push the latest snapshot.\n await this.flush();\n }\n }\n };\n\n this.inFlight = run();\n return this.inFlight;\n }\n\n private async sendOnce(): Promise<void> {\n const { session, tasks, eventPlan, handoffText } = this.store;\n const skillId = sanitizeChannelId(session.skillId ?? this.programId);\n const phase = session.runPhase;\n\n // Program rows carry the phase; the area rows carry the audit's progress.\n const programTasks = buildTasks(tasks);\n const auditAreas = this.auditChecks\n ? rollUpAuditAreas(this.auditChecks(), programTasks.length)\n : [];\n\n const payload: TaskStreamUpdate = {\n session_id: this.sessionId,\n workflow_id: this.programId,\n skill_id: skillId,\n started_at: this.startedAt,\n run_phase: phase,\n tasks: [...programTasks, ...auditAreas],\n event_plan: eventPlan.length > 0 ? { events: eventPlan } : undefined,\n error: buildError(phase, session.outroData),\n pending_input: buildPendingInput(session.pendingQuestion),\n // Included on every push once captured; the backend keeps it sticky, so\n // pushes that raced the capture cannot un-set it.\n handoff_text: handoffText ?? undefined,\n timestamp: new Date().toISOString(),\n };\n logToFile(\n `[task-stream-push] push phase=${phase} handoff_text=${\n handoffText === null ? 'absent' : `${handoffText.length} chars`\n }`,\n );\n\n let event: StreamEvent;\n if (!this.created) {\n this.created = true;\n event = StreamEvent.Create;\n } else if (phase === RunPhase.Completed) {\n event = StreamEvent.Complete;\n } else if (phase === RunPhase.Error) {\n event = StreamEvent.Error;\n } else {\n event = StreamEvent.Update;\n }\n\n this.lastPushedPhase = phase;\n this.lastPushedQuestionId = payload.pending_input?.id ?? null;\n\n await Promise.all(\n this.destinations.map((d) =>\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n d.send(event, payload).catch(() => {}),\n ),\n );\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { f as getUI } from "./debug-DUmMVUHn.js";
1
+ import { p as getUI } from "./debug-C5Zz8hmm.js";
2
2
  import { Type } from "typebox";
3
3
  import { defineTool } from "@earendil-works/pi-coding-agent";
4
4
  //#region src/lib/agent/runner/harness/pi/tasks.ts
@@ -109,4 +109,4 @@ function createWizardPiTaskTools() {
109
109
  //#endregion
110
110
  export { createWizardPiTaskTools };
111
111
 
112
- //# sourceMappingURL=tasks-0Rb5AXpz.js.map
112
+ //# sourceMappingURL=tasks-BDt427kT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-0Rb5AXpz.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/tasks.ts"],"sourcesContent":["/**\n * Task/todo parity for pi (#526). The same four Task tools the anthropic path\n * exposes (TaskCreate/Update/Get/List), as pi `defineTool` tools backed by a\n * shared in-memory store. Every mutation pushes the list to the TUI via\n * `getUI().syncTodos`, so the todo panel updates live under pi exactly like the\n * anthropic path — the thing that was missing before.\n */\n\nimport { Type } from 'typebox';\nimport { defineTool } from '@earendil-works/pi-coding-agent';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { getUI } from '@ui';\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed';\nexport interface TaskEntry {\n content: string;\n status: TaskStatus;\n activeForm?: string;\n}\nexport type TaskStore = Map<string, TaskEntry>;\n\nfunction text(s: string): {\n content: [{ type: 'text'; text: string }];\n details: unknown;\n} {\n return { content: [{ type: 'text', text: s }], details: {} };\n}\n\nfunction syncToTui(store: TaskStore): void {\n getUI().syncTodos(\n Array.from(store.values()).map((t) => ({\n content: t.content,\n status: t.status,\n activeForm: t.activeForm,\n })),\n );\n}\n\n/** Build the four Task tools over a fresh store. */\nexport function createWizardPiTaskTools(): {\n tools: ToolDefinition[];\n store: TaskStore;\n} {\n const store: TaskStore = new Map();\n\n const taskCreate = defineTool({\n name: 'TaskCreate',\n label: 'Create task',\n description:\n 'Create a task in the shared todo list. Returns its assigned id.',\n promptSnippet:\n 'TaskCreate(content) — add a todo (surfaces progress in the UI)',\n parameters: Type.Object({\n content: Type.String({ description: 'Imperative task description' }),\n activeForm: Type.Optional(\n Type.String({ description: 'Present-continuous form for the spinner' }),\n ),\n }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const id = `task-${store.size + 1}`;\n store.set(id, {\n content: args.content,\n status: 'pending',\n activeForm: args.activeForm,\n });\n syncToTui(store);\n return text(`Created ${id}`);\n },\n });\n\n const taskUpdate = defineTool({\n name: 'TaskUpdate',\n label: 'Update task',\n description:\n 'Update an existing task by id (status, content, or activeForm).',\n promptSnippet:\n 'TaskUpdate(taskId, status) — mark a todo in_progress/completed',\n parameters: Type.Object({\n taskId: Type.String(),\n status: Type.Optional(\n Type.Union([\n Type.Literal('pending'),\n Type.Literal('in_progress'),\n Type.Literal('completed'),\n ]),\n ),\n content: Type.Optional(Type.String()),\n activeForm: Type.Optional(Type.String()),\n }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const existing = store.get(args.taskId);\n if (!existing) return text(`No such task: ${args.taskId}`);\n store.set(args.taskId, {\n content: args.content ?? existing.content,\n status: (args.status as TaskStatus) ?? existing.status,\n activeForm: args.activeForm ?? existing.activeForm,\n });\n syncToTui(store);\n return text(`Updated ${args.taskId}`);\n },\n });\n\n const taskGet = defineTool({\n name: 'TaskGet',\n label: 'Get task',\n description: 'Fetch a single task by id.',\n parameters: Type.Object({ taskId: Type.String() }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const t = store.get(args.taskId);\n return text(\n t\n ? JSON.stringify({ id: args.taskId, ...t })\n : `No such task: ${args.taskId}`,\n );\n },\n });\n\n const taskList = defineTool({\n name: 'TaskList',\n label: 'List tasks',\n description: 'List all tasks in the shared todo list.',\n parameters: Type.Object({}),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute() {\n return text(\n JSON.stringify(\n Array.from(store.entries()).map(([id, t]) => ({ id, ...t })),\n ),\n );\n },\n });\n\n return { tools: [taskCreate, taskUpdate, taskGet, taskList], store };\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAS,KAAK,GAGZ;AACA,QAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAG,CAAC;EAAE,SAAS,EAAE;EAAE;;AAG9D,SAAS,UAAU,OAAwB;AACzC,QAAO,CAAC,UACN,MAAM,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAK,OAAO;EACrC,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,YAAY,EAAE;EACf,EAAE,CACJ;;;AAIH,SAAgB,0BAGd;CACA,MAAM,wBAAmB,IAAI,KAAK;AA4FlC,QAAO;EAAE,OAAO;GA1FG,WAAW;IAC5B,MAAM;IACN,OAAO;IACP,aACE;IACF,eACE;IACF,YAAY,KAAK,OAAO;KACtB,SAAS,KAAK,OAAO,EAAE,aAAa,+BAA+B,CAAC;KACpE,YAAY,KAAK,SACf,KAAK,OAAO,EAAE,aAAa,2CAA2C,CAAC,CACxE;KACF,CAAC;IAEF,MAAM,QAAQ,KAAK,MAAM;KACvB,MAAM,KAAK,QAAQ,MAAM,OAAO;AAChC,WAAM,IAAI,IAAI;MACZ,SAAS,KAAK;MACd,QAAQ;MACR,YAAY,KAAK;MAClB,CAAC;AACF,eAAU,MAAM;AAChB,YAAO,KAAK,WAAW,KAAK;;IAE/B,CAAC;GAEiB,WAAW;IAC5B,MAAM;IACN,OAAO;IACP,aACE;IACF,eACE;IACF,YAAY,KAAK,OAAO;KACtB,QAAQ,KAAK,QAAQ;KACrB,QAAQ,KAAK,SACX,KAAK,MAAM;MACT,KAAK,QAAQ,UAAU;MACvB,KAAK,QAAQ,cAAc;MAC3B,KAAK,QAAQ,YAAY;MAC1B,CAAC,CACH;KACD,SAAS,KAAK,SAAS,KAAK,QAAQ,CAAC;KACrC,YAAY,KAAK,SAAS,KAAK,QAAQ,CAAC;KACzC,CAAC;IAEF,MAAM,QAAQ,KAAK,MAAM;KACvB,MAAM,WAAW,MAAM,IAAI,KAAK,OAAO;AACvC,SAAI,CAAC,SAAU,QAAO,KAAK,iBAAiB,KAAK,SAAS;AAC1D,WAAM,IAAI,KAAK,QAAQ;MACrB,SAAS,KAAK,WAAW,SAAS;MAClC,QAAS,KAAK,UAAyB,SAAS;MAChD,YAAY,KAAK,cAAc,SAAS;MACzC,CAAC;AACF,eAAU,MAAM;AAChB,YAAO,KAAK,WAAW,KAAK,SAAS;;IAExC,CAAC;GAEc,WAAW;IACzB,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY,KAAK,OAAO,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC;IAElD,MAAM,QAAQ,KAAK,MAAM;KACvB,MAAM,IAAI,MAAM,IAAI,KAAK,OAAO;AAChC,YAAO,KACL,IACI,KAAK,UAAU;MAAE,IAAI,KAAK;MAAQ,GAAG;MAAG,CAAC,GACzC,iBAAiB,KAAK,SAC3B;;IAEJ,CAAC;GAEe,WAAW;IAC1B,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY,KAAK,OAAO,EAAE,CAAC;IAE3B,MAAM,UAAU;AACd,YAAO,KACL,KAAK,UACH,MAAM,KAAK,MAAM,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,QAAQ;MAAE;MAAI,GAAG;MAAG,EAAE,CAC7D,CACF;;IAEJ,CAAC;GAEyD;EAAE;EAAO"}
1
+ {"version":3,"file":"tasks-BDt427kT.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/tasks.ts"],"sourcesContent":["/**\n * Task/todo parity for pi (#526). The same four Task tools the anthropic path\n * exposes (TaskCreate/Update/Get/List), as pi `defineTool` tools backed by a\n * shared in-memory store. Every mutation pushes the list to the TUI via\n * `getUI().syncTodos`, so the todo panel updates live under pi exactly like the\n * anthropic path — the thing that was missing before.\n */\n\nimport { Type } from 'typebox';\nimport { defineTool } from '@earendil-works/pi-coding-agent';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { getUI } from '@ui';\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed';\nexport interface TaskEntry {\n content: string;\n status: TaskStatus;\n activeForm?: string;\n}\nexport type TaskStore = Map<string, TaskEntry>;\n\nfunction text(s: string): {\n content: [{ type: 'text'; text: string }];\n details: unknown;\n} {\n return { content: [{ type: 'text', text: s }], details: {} };\n}\n\nfunction syncToTui(store: TaskStore): void {\n getUI().syncTodos(\n Array.from(store.values()).map((t) => ({\n content: t.content,\n status: t.status,\n activeForm: t.activeForm,\n })),\n );\n}\n\n/** Build the four Task tools over a fresh store. */\nexport function createWizardPiTaskTools(): {\n tools: ToolDefinition[];\n store: TaskStore;\n} {\n const store: TaskStore = new Map();\n\n const taskCreate = defineTool({\n name: 'TaskCreate',\n label: 'Create task',\n description:\n 'Create a task in the shared todo list. Returns its assigned id.',\n promptSnippet:\n 'TaskCreate(content) — add a todo (surfaces progress in the UI)',\n parameters: Type.Object({\n content: Type.String({ description: 'Imperative task description' }),\n activeForm: Type.Optional(\n Type.String({ description: 'Present-continuous form for the spinner' }),\n ),\n }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const id = `task-${store.size + 1}`;\n store.set(id, {\n content: args.content,\n status: 'pending',\n activeForm: args.activeForm,\n });\n syncToTui(store);\n return text(`Created ${id}`);\n },\n });\n\n const taskUpdate = defineTool({\n name: 'TaskUpdate',\n label: 'Update task',\n description:\n 'Update an existing task by id (status, content, or activeForm).',\n promptSnippet:\n 'TaskUpdate(taskId, status) — mark a todo in_progress/completed',\n parameters: Type.Object({\n taskId: Type.String(),\n status: Type.Optional(\n Type.Union([\n Type.Literal('pending'),\n Type.Literal('in_progress'),\n Type.Literal('completed'),\n ]),\n ),\n content: Type.Optional(Type.String()),\n activeForm: Type.Optional(Type.String()),\n }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const existing = store.get(args.taskId);\n if (!existing) return text(`No such task: ${args.taskId}`);\n store.set(args.taskId, {\n content: args.content ?? existing.content,\n status: (args.status as TaskStatus) ?? existing.status,\n activeForm: args.activeForm ?? existing.activeForm,\n });\n syncToTui(store);\n return text(`Updated ${args.taskId}`);\n },\n });\n\n const taskGet = defineTool({\n name: 'TaskGet',\n label: 'Get task',\n description: 'Fetch a single task by id.',\n parameters: Type.Object({ taskId: Type.String() }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const t = store.get(args.taskId);\n return text(\n t\n ? JSON.stringify({ id: args.taskId, ...t })\n : `No such task: ${args.taskId}`,\n );\n },\n });\n\n const taskList = defineTool({\n name: 'TaskList',\n label: 'List tasks',\n description: 'List all tasks in the shared todo list.',\n parameters: Type.Object({}),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute() {\n return text(\n JSON.stringify(\n Array.from(store.entries()).map(([id, t]) => ({ id, ...t })),\n ),\n );\n },\n });\n\n return { tools: [taskCreate, taskUpdate, taskGet, taskList], store };\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAS,KAAK,GAGZ;AACA,QAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAG,CAAC;EAAE,SAAS,EAAE;EAAE;;AAG9D,SAAS,UAAU,OAAwB;AACzC,QAAO,CAAC,UACN,MAAM,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAK,OAAO;EACrC,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,YAAY,EAAE;EACf,EAAE,CACJ;;;AAIH,SAAgB,0BAGd;CACA,MAAM,wBAAmB,IAAI,KAAK;AA4FlC,QAAO;EAAE,OAAO;GA1FG,WAAW;IAC5B,MAAM;IACN,OAAO;IACP,aACE;IACF,eACE;IACF,YAAY,KAAK,OAAO;KACtB,SAAS,KAAK,OAAO,EAAE,aAAa,+BAA+B,CAAC;KACpE,YAAY,KAAK,SACf,KAAK,OAAO,EAAE,aAAa,2CAA2C,CAAC,CACxE;KACF,CAAC;IAEF,MAAM,QAAQ,KAAK,MAAM;KACvB,MAAM,KAAK,QAAQ,MAAM,OAAO;AAChC,WAAM,IAAI,IAAI;MACZ,SAAS,KAAK;MACd,QAAQ;MACR,YAAY,KAAK;MAClB,CAAC;AACF,eAAU,MAAM;AAChB,YAAO,KAAK,WAAW,KAAK;;IAE/B,CAAC;GAEiB,WAAW;IAC5B,MAAM;IACN,OAAO;IACP,aACE;IACF,eACE;IACF,YAAY,KAAK,OAAO;KACtB,QAAQ,KAAK,QAAQ;KACrB,QAAQ,KAAK,SACX,KAAK,MAAM;MACT,KAAK,QAAQ,UAAU;MACvB,KAAK,QAAQ,cAAc;MAC3B,KAAK,QAAQ,YAAY;MAC1B,CAAC,CACH;KACD,SAAS,KAAK,SAAS,KAAK,QAAQ,CAAC;KACrC,YAAY,KAAK,SAAS,KAAK,QAAQ,CAAC;KACzC,CAAC;IAEF,MAAM,QAAQ,KAAK,MAAM;KACvB,MAAM,WAAW,MAAM,IAAI,KAAK,OAAO;AACvC,SAAI,CAAC,SAAU,QAAO,KAAK,iBAAiB,KAAK,SAAS;AAC1D,WAAM,IAAI,KAAK,QAAQ;MACrB,SAAS,KAAK,WAAW,SAAS;MAClC,QAAS,KAAK,UAAyB,SAAS;MAChD,YAAY,KAAK,cAAc,SAAS;MACzC,CAAC;AACF,eAAU,MAAM;AAChB,YAAO,KAAK,WAAW,KAAK,SAAS;;IAExC,CAAC;GAEc,WAAW;IACzB,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY,KAAK,OAAO,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC;IAElD,MAAM,QAAQ,KAAK,MAAM;KACvB,MAAM,IAAI,MAAM,IAAI,KAAK,OAAO;AAChC,YAAO,KACL,IACI,KAAK,UAAU;MAAE,IAAI,KAAK;MAAQ,GAAG;MAAG,CAAC,GACzC,iBAAiB,KAAK,SAC3B;;IAEJ,CAAC;GAEe,WAAW;IAC1B,MAAM;IACN,OAAO;IACP,aAAa;IACb,YAAY,KAAK,OAAO,EAAE,CAAC;IAE3B,MAAM,UAAU;AACd,YAAO,KACL,KAAK,UACH,MAAM,KAAK,MAAM,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,QAAQ;MAAE;MAAI,GAAG;MAAG,EAAE,CAC7D,CACF;;IAEJ,CAAC;GAEyD;EAAE;EAAO"}
@@ -1,5 +1,5 @@
1
- import "./debug-DUmMVUHn.js";
2
- import { n as analytics } from "./analytics-DSK0GXg1.js";
1
+ import "./debug-C5Zz8hmm.js";
2
+ import { n as analytics } from "./analytics-C_RyE8fz.js";
3
3
  import opn from "opn";
4
4
  //#region src/utils/links.ts
5
5
  /**
@@ -65,4 +65,4 @@ function updateProgress(step) {
65
65
  //#endregion
66
66
  export { withUtm as i, openTrackedLink as n, setEntryCommand as r, withProgress as t };
67
67
 
68
- //# sourceMappingURL=telemetry-QpeVhVtU.js.map
68
+ //# sourceMappingURL=telemetry-Dp6zjZBj.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry-QpeVhVtU.js","names":[],"sources":["../src/utils/links.ts","../src/telemetry.ts"],"sourcesContent":["/**\n * Outbound links: UTM tagging and tracked opens.\n *\n * Every URL the wizard sends a user to — auto-opened or printed in the TUI —\n * carries `utm_source=wizard`, `utm_medium=cli`, `utm_content=<which link>`.\n * The command dimension rides on every wizard event as the `command` tag.\n * Opening a link also captures a wizard event.\n */\nimport opn from 'opn';\nimport { NODE_ENV } from '@env';\nimport { analytics } from './analytics';\n\n/**\n * Record the CLI command this run was started with (e.g. `integrate`,\n * `slack`, `mcp-add`). Set once at dispatch; tagged onto every wizard\n * event so wizard-side events segment by command.\n */\nexport function setEntryCommand(command: string): void {\n analytics.setTag('command', command);\n}\n\n/**\n * Tag a URL with the wizard's UTM params. `content` names the specific link\n * (e.g. `oauth-signup`, `slack-connect-setup`). URLs that already carry a\n * utm_source — or don't parse — are returned untouched.\n */\nexport function withUtm(url: string, content: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return url;\n }\n if (parsed.searchParams.has('utm_source')) return url;\n parsed.searchParams.set('utm_source', 'wizard');\n parsed.searchParams.set('utm_medium', 'cli');\n parsed.searchParams.set('utm_content', content);\n return parsed.toString();\n}\n\n/**\n * Open a URL in the user's browser, UTM-tagged (pass `skipUtm` for\n * destinations that aren't PostHog properties or are already final), and\n * capture the interaction. `auto` marks opens the wizard initiated itself,\n * as opposed to a user picking a link on screen. opn throws in headless\n * environments — the URL is always also printed on screen, so the failure\n * is swallowed.\n */\nexport function openTrackedLink(\n url: string,\n content: string,\n opts?: { auto?: boolean; skipUtm?: boolean },\n): void {\n const finalUrl = opts?.skipUtm ? url : withUtm(url, content);\n analytics.wizardCapture('link opened', {\n content,\n url: finalUrl,\n auto: opts?.auto ?? false,\n });\n if (NODE_ENV !== 'test') {\n opn(finalUrl, { wait: false }).catch(() => {\n // No browser available — the printed URL is the fallback.\n });\n }\n}\n","import { analytics } from '@utils/analytics';\n\nexport function withProgress<T>(step: string, callback: () => T): T {\n updateProgress(step);\n return callback();\n}\n\nexport function updateProgress(step: string) {\n analytics.setTag('progress', step);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,gBAAgB,SAAuB;AACrD,WAAU,OAAO,WAAW,QAAQ;;;;;;;AAQtC,SAAgB,QAAQ,KAAa,SAAyB;CAC5D,IAAI;AACJ,KAAI;AACF,WAAS,IAAI,IAAI,IAAI;SACf;AACN,SAAO;;AAET,KAAI,OAAO,aAAa,IAAI,aAAa,CAAE,QAAO;AAClD,QAAO,aAAa,IAAI,cAAc,SAAS;AAC/C,QAAO,aAAa,IAAI,cAAc,MAAM;AAC5C,QAAO,aAAa,IAAI,eAAe,QAAQ;AAC/C,QAAO,OAAO,UAAU;;;;;;;;;;AAW1B,SAAgB,gBACd,KACA,SACA,MACM;CACN,MAAM,WAAW,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ;AAC5D,WAAU,cAAc,eAAe;EACrC;EACA,KAAK;EACL,MAAM,MAAM,QAAQ;EACrB,CAAC;AAEA,KAAI,UAAU,EAAE,MAAM,OAAO,CAAC,CAAC,YAAY,GAEzC;;;;AC5DN,SAAgB,aAAgB,MAAc,UAAsB;AAClE,gBAAe,KAAK;AACpB,QAAO,UAAU;;AAGnB,SAAgB,eAAe,MAAc;AAC3C,WAAU,OAAO,YAAY,KAAK"}
1
+ {"version":3,"file":"telemetry-Dp6zjZBj.js","names":[],"sources":["../src/utils/links.ts","../src/telemetry.ts"],"sourcesContent":["/**\n * Outbound links: UTM tagging and tracked opens.\n *\n * Every URL the wizard sends a user to — auto-opened or printed in the TUI —\n * carries `utm_source=wizard`, `utm_medium=cli`, `utm_content=<which link>`.\n * The command dimension rides on every wizard event as the `command` tag.\n * Opening a link also captures a wizard event.\n */\nimport opn from 'opn';\nimport { NODE_ENV } from '@env';\nimport { analytics } from './analytics';\n\n/**\n * Record the CLI command this run was started with (e.g. `integrate`,\n * `slack`, `mcp-add`). Set once at dispatch; tagged onto every wizard\n * event so wizard-side events segment by command.\n */\nexport function setEntryCommand(command: string): void {\n analytics.setTag('command', command);\n}\n\n/**\n * Tag a URL with the wizard's UTM params. `content` names the specific link\n * (e.g. `oauth-signup`, `slack-connect-setup`). URLs that already carry a\n * utm_source — or don't parse — are returned untouched.\n */\nexport function withUtm(url: string, content: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return url;\n }\n if (parsed.searchParams.has('utm_source')) return url;\n parsed.searchParams.set('utm_source', 'wizard');\n parsed.searchParams.set('utm_medium', 'cli');\n parsed.searchParams.set('utm_content', content);\n return parsed.toString();\n}\n\n/**\n * Open a URL in the user's browser, UTM-tagged (pass `skipUtm` for\n * destinations that aren't PostHog properties or are already final), and\n * capture the interaction. `auto` marks opens the wizard initiated itself,\n * as opposed to a user picking a link on screen. opn throws in headless\n * environments — the URL is always also printed on screen, so the failure\n * is swallowed.\n */\nexport function openTrackedLink(\n url: string,\n content: string,\n opts?: { auto?: boolean; skipUtm?: boolean },\n): void {\n const finalUrl = opts?.skipUtm ? url : withUtm(url, content);\n analytics.wizardCapture('link opened', {\n content,\n url: finalUrl,\n auto: opts?.auto ?? false,\n });\n if (NODE_ENV !== 'test') {\n opn(finalUrl, { wait: false }).catch(() => {\n // No browser available — the printed URL is the fallback.\n });\n }\n}\n","import { analytics } from '@utils/analytics';\n\nexport function withProgress<T>(step: string, callback: () => T): T {\n updateProgress(step);\n return callback();\n}\n\nexport function updateProgress(step: string) {\n analytics.setTag('progress', step);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,gBAAgB,SAAuB;AACrD,WAAU,OAAO,WAAW,QAAQ;;;;;;;AAQtC,SAAgB,QAAQ,KAAa,SAAyB;CAC5D,IAAI;AACJ,KAAI;AACF,WAAS,IAAI,IAAI,IAAI;SACf;AACN,SAAO;;AAET,KAAI,OAAO,aAAa,IAAI,aAAa,CAAE,QAAO;AAClD,QAAO,aAAa,IAAI,cAAc,SAAS;AAC/C,QAAO,aAAa,IAAI,cAAc,MAAM;AAC5C,QAAO,aAAa,IAAI,eAAe,QAAQ;AAC/C,QAAO,OAAO,UAAU;;;;;;;;;;AAW1B,SAAgB,gBACd,KACA,SACA,MACM;CACN,MAAM,WAAW,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ;AAC5D,WAAU,cAAc,eAAe;EACrC;EACA,KAAK;EACL,MAAM,MAAM,QAAQ;EACrB,CAAC;AAEA,KAAI,UAAU,EAAE,MAAM,OAAO,CAAC,CAAC,YAAY,GAEzC;;;;AC5DN,SAAgB,aAAgB,MAAc,UAAsB;AAClE,gBAAe,KAAK;AACpB,QAAO,UAAU;;AAGnB,SAAgB,eAAe,MAAc;AAC3C,WAAU,OAAO,YAAY,KAAK"}
@@ -1,16 +1,16 @@
1
- import { U as POSTHOG_APP_URL, ft as WIZARD_USER_AGENT, h as SERVICE_LABELS, pt as getSkillsBaseUrl, s as logToFile } from "./debug-DUmMVUHn.js";
1
+ import { W as POSTHOG_APP_URL, g as SERVICE_LABELS, mt as getSkillsBaseUrl, pt as WIZARD_USER_AGENT, s as logToFile } from "./debug-C5Zz8hmm.js";
2
2
  import "./wizard-session-FSJCkTcP.js";
3
- import { n as analytics } from "./analytics-DSK0GXg1.js";
4
- import { i as withUtm, n as openTrackedLink } from "./telemetry-QpeVhVtU.js";
5
- import { t as getOrAskForProjectData } from "./setup-utils-C3tsa6D6.js";
6
- import { a as fetchSlackConnected, o as fetchUserData } from "./api-CwNulLDK.js";
7
- import { L as fetchSkillMenu } from "./agent-interface-BKLTDSyN.js";
8
- import { a as formatCostUsd, o as formatTokenCount } from "./agent-runner-BkQontri.js";
9
- import { y as AUDIT_SEVERITY_STYLE } from "./yara-hooks-uCiAIcqU.js";
10
- import { $ as wordWrap, H as getKindMeta, Q as computeVisibleRange, Z as TextBlock, et as isClearBlock, it as Icons, nt as isObjectBlock, o as Program, rt as Colors, tt as isLinesBlock } from "./mint-failure-CQqypC_v.js";
3
+ import { n as analytics } from "./analytics-C_RyE8fz.js";
4
+ import { i as withUtm, n as openTrackedLink } from "./telemetry-Dp6zjZBj.js";
5
+ import { t as getOrAskForProjectData } from "./setup-utils-BUAoRjw3.js";
6
+ import { a as fetchSlackConnected, o as fetchUserData } from "./api-k5aGQpIZ.js";
7
+ import { G as fetchSkillMenu } from "./agent-interface-CZWRgZMc.js";
8
+ import { a as formatCostUsd, o as formatTokenCount } from "./agent-runner-C_R1X_UT.js";
9
+ import { y as AUDIT_SEVERITY_STYLE } from "./yara-hooks-BJWVgTpU.js";
10
+ import { $ as wordWrap, H as getKindMeta, Q as computeVisibleRange, Z as TextBlock, et as isClearBlock, it as Icons, nt as isObjectBlock, o as Program, rt as Colors, tt as isLinesBlock } from "./mint-failure-CZ5FZ0Jd.js";
11
11
  import { a as useStdoutDimensions, i as useKeyboardHintsContext, n as useKeyBindings, o as ConfirmButton, r as KeyboardHintsProvider, s as PromptLabel, t as PickerMenu } from "./bin.js";
12
- import { r as totalTokenCount } from "./store-DN_6FaoQ.js";
13
- import { c as namesWithStatus, n as AVAILABLE_FEATURES, o as isAllFeaturesSelected, s as isOk, t as ALL_FEATURE_VALUES, u as summarizeFailure } from "./defaults-DDDwYTN5.js";
12
+ import { r as totalTokenCount } from "./store-D5ROpUje.js";
13
+ import { c as namesWithStatus, n as AVAILABLE_FEATURES, o as isAllFeaturesSelected, s as isOk, t as ALL_FEATURE_VALUES, u as summarizeFailure } from "./defaults-DulzMJpN.js";
14
14
  import opn from "opn";
15
15
  import * as fs$1 from "fs";
16
16
  import axios from "axios";
@@ -7224,4 +7224,4 @@ function releaseTerminal() {
7224
7224
  //#endregion
7225
7225
  export { ViewportTooSmall as A, SplitView as B, VisualizerTab as C, HNViewer as D, ContentSequencer as E, ModalOverlay as F, ConfirmationInput as I, GroupedPickerMenu as L, LogViewer as M, LinkText as N, TabContainer as O, extractUrls as P, ProgressList as R, ServiceHealthList as S, LearnCard as T, CardLayout as V, TAILORED_ROLES as _, useSkillEntry as a, SEVERITY_LABEL as b, SlackConnectScreen as c, AuditChecksViewer as d, seedDemoEvents as f, probeProjectData as g, assembleProfile as h, SkillSourceInfo as i, EventPlanViewer as j, ScreenContainer as k, AUDIT_AREA_SLIDES as l, McpSuggestedPromptsScreen as m, releaseTerminal as n, OutroScreen as o, seededProfile as p, AiOptInRequiredScreen as r, useDismissOnAnyKey as s, enterDarkTerminal as t, VisualBox as u, McpScreen as v, TipsCard as w, SEVERITY_ORDER as x, IssueTable as y, LoadingBox as z };
7226
7226
 
7227
- //# sourceMappingURL=terminal-dLoYiXsd.js.map
7227
+ //# sourceMappingURL=terminal-pInlleVD.js.map