@posthog/wizard 2.64.1 → 2.65.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.
- package/README.md +7 -2
- package/dist/{add-mcp-server-to-clients-BUqb93_I.js → add-mcp-server-to-clients-ArtlMX9-.js} +5 -5
- package/dist/{add-mcp-server-to-clients-BUqb93_I.js.map → add-mcp-server-to-clients-ArtlMX9-.js.map} +1 -1
- package/dist/{agent-interface-NurnwA01.js → agent-interface-ORzGEFNM.js} +76 -11
- package/dist/agent-interface-ORzGEFNM.js.map +1 -0
- package/dist/{agent-prompt-loader-CbowPuWI.js → agent-prompt-loader-D3w6sc34.js} +10 -5
- package/dist/agent-prompt-loader-D3w6sc34.js.map +1 -0
- package/dist/{agent-runner-DisJWxJa.js → agent-runner-Ca-e2TOQ.js} +25 -18
- package/dist/{agent-runner-DisJWxJa.js.map → agent-runner-Ca-e2TOQ.js.map} +1 -1
- package/dist/analytics-C4j6grao.js +2 -0
- package/dist/{analytics-D3vKvr3l.js → analytics-zBrIVjMV.js} +2 -2
- package/dist/{analytics-D3vKvr3l.js.map → analytics-zBrIVjMV.js.map} +1 -1
- package/dist/{api-Bhe8jpUR.js → api-Wgb7AhrP.js} +3 -3
- package/dist/{api-Bhe8jpUR.js.map → api-Wgb7AhrP.js.map} +1 -1
- package/dist/bin.js +200 -76
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-BeWc675I.js → bounded-fs-DqsVmh4r.js} +3 -3
- package/dist/{bounded-fs-BeWc675I.js.map → bounded-fs-DqsVmh4r.js.map} +1 -1
- package/dist/{ci-install-BpNzfghY.js → ci-install-D1QqmJIc.js} +4 -4
- package/dist/{ci-install-BpNzfghY.js.map → ci-install-D1QqmJIc.js.map} +1 -1
- package/dist/{debug-hy6aWAyk.js → debug-Cm1hvkVy.js} +14 -9
- package/dist/debug-Cm1hvkVy.js.map +1 -0
- package/dist/{debug-DGfRPr2A.js → debug-CtQ13sCW.js} +1 -1
- package/dist/{defaults-mrAre0xM.js → defaults-BHhXrX9F.js} +1 -1
- package/dist/{defaults-mrAre0xM.js.map → defaults-BHhXrX9F.js.map} +1 -1
- package/dist/{env-api-key-CMPe-WJp.js → env-api-key-CdI2XZIz.js} +2 -2
- package/dist/{env-api-key-CMPe-WJp.js.map → env-api-key-CdI2XZIz.js.map} +1 -1
- package/dist/{environment-Ktu0Ktjl.js → environment-BhFvfkQg.js} +4 -4
- package/dist/{environment-Ktu0Ktjl.js.map → environment-BhFvfkQg.js.map} +1 -1
- package/dist/{file-watcher-CqJ1dgjq.js → file-watcher-Dciz09Rr.js} +2 -2
- package/dist/{file-watcher-CqJ1dgjq.js.map → file-watcher-Dciz09Rr.js.map} +1 -1
- package/dist/{headless-ui-zZLgs4QL.js → headless-ui-B4FnKm11.js} +2 -2
- package/dist/{headless-ui-zZLgs4QL.js.map → headless-ui-B4FnKm11.js.map} +1 -1
- package/dist/{interactive-BUw1SEOz.js → interactive-DxHFVYr2.js} +2 -2
- package/dist/{interactive-BUw1SEOz.js.map → interactive-DxHFVYr2.js.map} +1 -1
- package/dist/local-dev-BN6NKQ0B.js +135 -0
- package/dist/local-dev-BN6NKQ0B.js.map +1 -0
- package/dist/{mcp-prompt-streaming-CKyqqB10.js → mcp-prompt-streaming-ro98iUDc.js} +20 -4
- package/dist/mcp-prompt-streaming-ro98iUDc.js.map +1 -0
- package/dist/{mcp-C7NMhhWa.js → mcp-t0UxAPur.js} +2 -2
- package/dist/{mcp-C7NMhhWa.js.map → mcp-t0UxAPur.js.map} +1 -1
- package/dist/{non-interactive-73xGtug6.js → non-interactive-BA2L_jDT.js} +2 -2
- package/dist/{non-interactive-73xGtug6.js.map → non-interactive-BA2L_jDT.js.map} +1 -1
- package/dist/{orchestrator-tools-DcMJzfDH.js → orchestrator-tools-vZmNsHy9.js} +3 -3
- package/dist/{orchestrator-tools-DcMJzfDH.js.map → orchestrator-tools-vZmNsHy9.js.map} +1 -1
- package/dist/{package-json-CDs1ZVKu.js → package-json-D0DCWpe5.js} +1 -1
- package/dist/{package-json-CDs1ZVKu.js.map → package-json-D0DCWpe5.js.map} +1 -1
- package/dist/{package-manager-KweKX3u_.js → package-manager-DgqJdAQk.js} +58 -3
- package/dist/package-manager-DgqJdAQk.js.map +1 -0
- package/dist/{pi-B4p4gpr0.js → pi-nwrCARRp.js} +11 -11
- package/dist/{pi-B4p4gpr0.js.map → pi-nwrCARRp.js.map} +1 -1
- package/dist/{playground-AEkWcB1E.js → playground-xkEke_h0.js} +7 -7
- package/dist/{playground-AEkWcB1E.js.map → playground-xkEke_h0.js.map} +1 -1
- package/dist/{posthog-4PljLcIz.js → posthog-9To56cSd.js} +2 -2
- package/dist/{posthog-4PljLcIz.js.map → posthog-9To56cSd.js.map} +1 -1
- package/dist/{posthog-integration-DKlEg8-Q.js → posthog-integration-CoPvN6YZ.js} +34 -29
- package/dist/posthog-integration-CoPvN6YZ.js.map +1 -0
- package/dist/{provisioning-QsG7HDCm.js → provisioning-BYFSHSHY.js} +3 -3
- package/dist/{provisioning-QsG7HDCm.js.map → provisioning-BYFSHSHY.js.map} +1 -1
- package/dist/{queue-tools-Jlz9dV_B.js → queue-tools-BREbgGSC.js} +3 -3
- package/dist/{queue-tools-Jlz9dV_B.js.map → queue-tools-BREbgGSC.js.map} +1 -1
- package/dist/{registry-PG_nV5Bf.js → registry-DGJQ_8QI.js} +309 -6
- package/dist/registry-DGJQ_8QI.js.map +1 -0
- package/dist/{security-BKUJk-Gg.js → security-wc-naGq5.js} +5 -5
- package/dist/{security-BKUJk-Gg.js.map → security-wc-naGq5.js.map} +1 -1
- package/dist/{setup-utils-DNpldqge.js → setup-utils-Cz0wPLsQ.js} +18 -13
- package/dist/setup-utils-Cz0wPLsQ.js.map +1 -0
- package/dist/smoke-test-ci.sh +12 -1
- package/dist/{start-tui-D4B0-2nr.js → start-tui-DDW9uVnD.js} +114 -25
- package/dist/start-tui-DDW9uVnD.js.map +1 -0
- package/dist/{steps-Dy0AXdGo.js → steps-CZI0B24_.js} +7 -7
- package/dist/{steps-Dy0AXdGo.js.map → steps-CZI0B24_.js.map} +1 -1
- package/dist/{store-DouLLelV.js → store-xMkU8xAa.js} +20 -6
- package/dist/store-xMkU8xAa.js.map +1 -0
- package/dist/{subagent-B4yVs5A2.js → subagent-BztacyoV.js} +2 -2
- package/dist/{subagent-B4yVs5A2.js.map → subagent-BztacyoV.js.map} +1 -1
- package/dist/{task-DRKYEbKM.js → task-CJ7x3McC.js} +29 -18
- package/dist/task-CJ7x3McC.js.map +1 -0
- package/dist/{task-stream-BGUP7yA-.js → task-stream-BK7JQ27G.js} +5 -5
- package/dist/{task-stream-BGUP7yA-.js.map → task-stream-BK7JQ27G.js.map} +1 -1
- package/dist/{tasks-B2GzXsZ0.js → tasks-FGzp_zBd.js} +2 -2
- package/dist/{tasks-B2GzXsZ0.js.map → tasks-FGzp_zBd.js.map} +1 -1
- package/dist/{telemetry-6zaFfCcy.js → telemetry-By56gAtF.js} +3 -3
- package/dist/{telemetry-6zaFfCcy.js.map → telemetry-By56gAtF.js.map} +1 -1
- package/dist/{terminal-Bu3eHFn0.js → terminal-C_rmkaku.js} +39 -31
- package/dist/terminal-C_rmkaku.js.map +1 -0
- package/dist/{tools-DQO5tKJg.js → tools-BpCJgMez.js} +7 -7
- package/dist/tools-BpCJgMez.js.map +1 -0
- package/dist/{wizard-abort-PgTdRS1l.js → wizard-abort-BlDla_Jd.js} +1 -1
- package/dist/{wizard-abort-D6jJh8u5.js → wizard-abort-CzwID162.js} +4 -4
- package/dist/{wizard-abort-D6jJh8u5.js.map → wizard-abort-CzwID162.js.map} +1 -1
- package/dist/{wizard-session-BUhlJ1b8.js → wizard-session-Bn6dO1gE.js} +16 -3
- package/dist/wizard-session-Bn6dO1gE.js.map +1 -0
- package/dist/{wizard-session-DZUDtS5d.js → wizard-session-UxA_A0cA.js} +1 -1
- package/dist/{yara-hooks-DjReXmTQ.js → yara-hooks-BrisBebM.js} +4 -4
- package/dist/{yara-hooks-DjReXmTQ.js.map → yara-hooks-BrisBebM.js.map} +1 -1
- package/dist/yara-hooks-D2B7Fd9G.js +2 -0
- package/package.json +1 -1
- package/dist/agent-interface-NurnwA01.js.map +0 -1
- package/dist/agent-prompt-loader-CbowPuWI.js.map +0 -1
- package/dist/analytics-hNca7GLq.js +0 -2
- package/dist/debug-hy6aWAyk.js.map +0 -1
- package/dist/mcp-prompt-streaming-CKyqqB10.js.map +0 -1
- package/dist/package-manager-KweKX3u_.js.map +0 -1
- package/dist/posthog-integration-DKlEg8-Q.js.map +0 -1
- package/dist/registry-PG_nV5Bf.js.map +0 -1
- package/dist/setup-utils-DNpldqge.js.map +0 -1
- package/dist/start-tui-D4B0-2nr.js.map +0 -1
- package/dist/store-DouLLelV.js.map +0 -1
- package/dist/task-DRKYEbKM.js.map +0 -1
- package/dist/terminal-Bu3eHFn0.js.map +0 -1
- package/dist/tools-DQO5tKJg.js.map +0 -1
- package/dist/wizard-session-BUhlJ1b8.js.map +0 -1
- package/dist/yara-hooks-CN_uFGCu.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-stream-BGUP7yA-.js","names":[],"sources":["../src/lib/task-stream/event-plan-watcher.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 * 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 { logToFile } from '@utils/debug';\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 return { type: 'wizard_error', message };\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 /** 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\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.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 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: buildTasks(tasks),\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
|
+
{"version":3,"file":"task-stream-BK7JQ27G.js","names":[],"sources":["../src/lib/task-stream/event-plan-watcher.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 * 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 { logToFile } from '@utils/debug';\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 return { type: 'wizard_error', message };\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 /** 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\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.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 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: buildTasks(tasks),\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-
|
|
1
|
+
import { f as getUI } from "./debug-Cm1hvkVy.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-
|
|
112
|
+
//# sourceMappingURL=tasks-FGzp_zBd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks-
|
|
1
|
+
{"version":3,"file":"tasks-FGzp_zBd.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-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
1
|
+
import "./debug-Cm1hvkVy.js";
|
|
2
|
+
import { n as analytics } from "./analytics-zBrIVjMV.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-
|
|
68
|
+
//# sourceMappingURL=telemetry-By56gAtF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-
|
|
1
|
+
{"version":3,"file":"telemetry-By56gAtF.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 { V as POSTHOG_APP_URL, h as SERVICE_LABELS, mt as getSkillsBaseUrl, pt as WIZARD_USER_AGENT, s as logToFile } from "./debug-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import { i as withUtm, n as openTrackedLink } from "./telemetry-
|
|
4
|
-
import { t as getOrAskForProjectData } from "./setup-utils-
|
|
5
|
-
import { a as fetchUserData, i as fetchSlackConnected } from "./api-
|
|
6
|
-
import "./wizard-session-
|
|
7
|
-
import { a as formatCostUsd, o as formatTokenCount } from "./agent-runner-
|
|
8
|
-
import {
|
|
9
|
-
import { y as AUDIT_SEVERITY_STYLE } from "./yara-hooks-
|
|
10
|
-
import { c as TextBlock, d as isClearBlock, f as isLinesBlock, h as Icons, l as computeVisibleRange, m as Colors, p as isObjectBlock } from "./posthog-integration-
|
|
1
|
+
import { V as POSTHOG_APP_URL, h as SERVICE_LABELS, mt as getSkillsBaseUrl, pt as WIZARD_USER_AGENT, s as logToFile } from "./debug-Cm1hvkVy.js";
|
|
2
|
+
import { n as analytics } from "./analytics-zBrIVjMV.js";
|
|
3
|
+
import { i as withUtm, n as openTrackedLink } from "./telemetry-By56gAtF.js";
|
|
4
|
+
import { t as getOrAskForProjectData } from "./setup-utils-Cz0wPLsQ.js";
|
|
5
|
+
import { a as fetchUserData, i as fetchSlackConnected } from "./api-Wgb7AhrP.js";
|
|
6
|
+
import "./wizard-session-Bn6dO1gE.js";
|
|
7
|
+
import { a as formatCostUsd, o as formatTokenCount } from "./agent-runner-Ca-e2TOQ.js";
|
|
8
|
+
import { E as fetchSkillMenu } from "./agent-interface-ORzGEFNM.js";
|
|
9
|
+
import { y as AUDIT_SEVERITY_STYLE } from "./yara-hooks-BrisBebM.js";
|
|
10
|
+
import { c as TextBlock, d as isClearBlock, f as isLinesBlock, h as Icons, l as computeVisibleRange, m as Colors, p as isObjectBlock } from "./posthog-integration-CoPvN6YZ.js";
|
|
11
11
|
import { E as getKindMeta, a as useStdoutDimensions, f as Program, 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-
|
|
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-
|
|
12
|
+
import { r as totalTokenCount } from "./store-xMkU8xAa.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-BHhXrX9F.js";
|
|
14
14
|
import opn from "opn";
|
|
15
15
|
import * as fs$1 from "fs";
|
|
16
16
|
import axios from "axios";
|
|
@@ -4625,6 +4625,13 @@ const FOLLOW_UP_DELAY_MS = 3e3;
|
|
|
4625
4625
|
const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
4626
4626
|
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
4627
4627
|
const session = store.session;
|
|
4628
|
+
const programId = useMemo(() => store.analyticsProgramId, [store]);
|
|
4629
|
+
const capture = useMemo(() => (event, properties) => {
|
|
4630
|
+
analytics.wizardCapture(event, {
|
|
4631
|
+
program_id: programId,
|
|
4632
|
+
...properties
|
|
4633
|
+
});
|
|
4634
|
+
}, [programId]);
|
|
4628
4635
|
const [phase, setPhase] = useState("choose");
|
|
4629
4636
|
const [profile, setProfile] = useState(null);
|
|
4630
4637
|
const greeting = useMemo(() => getRoleGreeting(session.roleAtOrganization), [session.roleAtOrganization]);
|
|
@@ -4692,7 +4699,7 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
|
4692
4699
|
if (cancelled) return;
|
|
4693
4700
|
setProfile(probed);
|
|
4694
4701
|
const offerSeed = probed.tier === "empty" && isKnownCloudHost(credentials.host.apiHost);
|
|
4695
|
-
|
|
4702
|
+
capture("mcp suggested prompts scouted", {
|
|
4696
4703
|
tier: probed.tier,
|
|
4697
4704
|
totalEvents: probed.totalEvents,
|
|
4698
4705
|
distinctEvents: probed.distinctEventCount,
|
|
@@ -4727,12 +4734,12 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
|
4727
4734
|
});
|
|
4728
4735
|
if (cancelled) return;
|
|
4729
4736
|
setProfile(seeded);
|
|
4730
|
-
|
|
4737
|
+
capture("mcp suggested prompts seeded", { totalEvents: seeded.totalEvents });
|
|
4731
4738
|
} catch (err) {
|
|
4732
4739
|
if (cancelled) return;
|
|
4733
4740
|
const message = err instanceof Error ? err.message : String(err);
|
|
4734
4741
|
logToFile(`[McpSuggestedPromptsScreen] seeding failed: ${message}`);
|
|
4735
|
-
|
|
4742
|
+
capture("mcp suggested prompts seed failed", { error: message });
|
|
4736
4743
|
}
|
|
4737
4744
|
if (cancelled) return;
|
|
4738
4745
|
setPhase("greeting");
|
|
@@ -4762,11 +4769,11 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
|
4762
4769
|
const finishStream = (kind, durationMs, errorText) => {
|
|
4763
4770
|
if (controller.signal.aborted) return;
|
|
4764
4771
|
setRunDurationSecs(Math.round(durationMs / 1e3));
|
|
4765
|
-
if (kind === "done")
|
|
4772
|
+
if (kind === "done") capture("mcp suggested prompts run", {
|
|
4766
4773
|
prompt: runningPrompt,
|
|
4767
4774
|
durationMs
|
|
4768
4775
|
});
|
|
4769
|
-
else
|
|
4776
|
+
else capture("mcp suggested prompts run failed", {
|
|
4770
4777
|
prompt: runningPrompt,
|
|
4771
4778
|
error: errorText
|
|
4772
4779
|
});
|
|
@@ -4835,20 +4842,20 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
|
4835
4842
|
const choice = Array.isArray(value) ? value[0] : value;
|
|
4836
4843
|
setLoginError(null);
|
|
4837
4844
|
if (choice === "login") {
|
|
4838
|
-
|
|
4845
|
+
capture("mcp suggested prompts choose", { choice: "login" });
|
|
4839
4846
|
startedTutorialRef.current = true;
|
|
4840
4847
|
setPhase(session.credentials ? "scouting" : "authenticating");
|
|
4841
4848
|
} else {
|
|
4842
|
-
|
|
4849
|
+
capture("mcp suggested prompts choose", { choice: "exit" });
|
|
4843
4850
|
enterGoodbye();
|
|
4844
4851
|
}
|
|
4845
4852
|
};
|
|
4846
4853
|
const handleSeedChoice = (value) => {
|
|
4847
4854
|
if ((Array.isArray(value) ? value[0] : value) === "seed") {
|
|
4848
|
-
|
|
4855
|
+
capture("mcp suggested prompts seed offer", { choice: "seed" });
|
|
4849
4856
|
setPhase("seeding");
|
|
4850
4857
|
} else {
|
|
4851
|
-
|
|
4858
|
+
capture("mcp suggested prompts seed offer", { choice: "skip" });
|
|
4852
4859
|
setPhase("greeting");
|
|
4853
4860
|
}
|
|
4854
4861
|
};
|
|
@@ -4864,14 +4871,14 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
|
4864
4871
|
const handleFollowUpPick = (value) => {
|
|
4865
4872
|
const picked = Array.isArray(value) ? value[0] : value;
|
|
4866
4873
|
if (picked === "__follow_up_exit__") {
|
|
4867
|
-
|
|
4874
|
+
capture("mcp suggested prompts follow-up", {
|
|
4868
4875
|
choice: "exit",
|
|
4869
4876
|
depth: branchHistory.length
|
|
4870
4877
|
});
|
|
4871
4878
|
enterGoodbye();
|
|
4872
4879
|
return;
|
|
4873
4880
|
}
|
|
4874
|
-
|
|
4881
|
+
capture("mcp suggested prompts follow-up", {
|
|
4875
4882
|
choice: "continue",
|
|
4876
4883
|
depth: branchHistory.length,
|
|
4877
4884
|
lastToolName
|
|
@@ -6896,9 +6903,10 @@ const OutroScreen = ({ store }) => {
|
|
|
6896
6903
|
* Shared "Skill: <id> / URL: <downloadUrl>" block for intro screens.
|
|
6897
6904
|
*
|
|
6898
6905
|
* `useSkillEntry` fetches the entry from the skill menu and re-runs when
|
|
6899
|
-
* `skillId`
|
|
6900
|
-
*
|
|
6901
|
-
*
|
|
6906
|
+
* `skillId` changes — detection sets it after mount. The previous fetch is
|
|
6907
|
+
* cancelled so a late result can't overwrite a newer one. Which registry to
|
|
6908
|
+
* fetch from is not a screen's business: `getSkillsBaseUrl()` reads the
|
|
6909
|
+
* process-wide target.
|
|
6902
6910
|
*
|
|
6903
6911
|
* `<SkillSourceInfo>` renders the block, taking the entry as a prop so the
|
|
6904
6912
|
* caller can reuse the same hook result for additional UI (e.g. showing
|
|
@@ -6924,7 +6932,7 @@ function resolveSkillEntry(entries, skillId) {
|
|
|
6924
6932
|
const variants = entries.filter((s) => s.id.startsWith(`integration-${skillId}-`));
|
|
6925
6933
|
return variants.length === 1 ? variants[0] : null;
|
|
6926
6934
|
}
|
|
6927
|
-
function useSkillEntry(skillId
|
|
6935
|
+
function useSkillEntry(skillId) {
|
|
6928
6936
|
const [skillEntry, setSkillEntry] = useState(null);
|
|
6929
6937
|
const [fetchFailed, setFetchFailed] = useState(false);
|
|
6930
6938
|
useEffect(() => {
|
|
@@ -6935,7 +6943,7 @@ function useSkillEntry(skillId, local) {
|
|
|
6935
6943
|
let cancelled = false;
|
|
6936
6944
|
setSkillEntry(null);
|
|
6937
6945
|
setFetchFailed(false);
|
|
6938
|
-
fetchSkillMenu(getSkillsBaseUrl(
|
|
6946
|
+
fetchSkillMenu(getSkillsBaseUrl()).then((menu) => {
|
|
6939
6947
|
if (cancelled) return;
|
|
6940
6948
|
if (!menu) {
|
|
6941
6949
|
setFetchFailed(true);
|
|
@@ -6948,7 +6956,7 @@ function useSkillEntry(skillId, local) {
|
|
|
6948
6956
|
return () => {
|
|
6949
6957
|
cancelled = true;
|
|
6950
6958
|
};
|
|
6951
|
-
}, [skillId
|
|
6959
|
+
}, [skillId]);
|
|
6952
6960
|
return {
|
|
6953
6961
|
skillEntry,
|
|
6954
6962
|
fetchFailed
|
|
@@ -7002,7 +7010,7 @@ const AiOptInRequiredScreen = ({ store }) => {
|
|
|
7002
7010
|
const [showSkill, setShowSkill] = useState(false);
|
|
7003
7011
|
const [retrying, setRetrying] = useState(false);
|
|
7004
7012
|
const [retryError, setRetryError] = useState(null);
|
|
7005
|
-
const { skillEntry } = useSkillEntry(session.skillId
|
|
7013
|
+
const { skillEntry } = useSkillEntry(session.skillId);
|
|
7006
7014
|
useEffect(() => {
|
|
7007
7015
|
analytics.wizardCapture("ai opt-in shown", { variant });
|
|
7008
7016
|
}, [variant]);
|
|
@@ -7218,4 +7226,4 @@ function releaseTerminal() {
|
|
|
7218
7226
|
//#endregion
|
|
7219
7227
|
export { EventPlanViewer as A, CardLayout as B, VisualizerTab as C, HNViewer as D, ContentSequencer as E, ConfirmationInput as F, GroupedPickerMenu as I, ProgressList as L, LinkText as M, extractUrls as N, TabContainer as O, ModalOverlay as P, LoadingBox as R, ServiceHealthList as S, LearnCard as T, 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, LogViewer 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, SplitView as z };
|
|
7220
7228
|
|
|
7221
|
-
//# sourceMappingURL=terminal-
|
|
7229
|
+
//# sourceMappingURL=terminal-C_rmkaku.js.map
|