@posthog/wizard 2.77.0 → 2.78.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 +30 -15
- package/dist/{add-mcp-server-to-clients-BnRyE4pw.js → add-mcp-server-to-clients-JMv8LP-O.js} +6 -5
- package/dist/{add-mcp-server-to-clients-BnRyE4pw.js.map → add-mcp-server-to-clients-JMv8LP-O.js.map} +1 -1
- package/dist/agent-bCZ3i3fh.js +3085 -0
- package/dist/agent-bCZ3i3fh.js.map +1 -0
- package/dist/{agent-interface-Avtr_5M5.js → agent-interface-BAOIHuXS.js} +429 -378
- package/dist/agent-interface-BAOIHuXS.js.map +1 -0
- package/dist/{agent-prompt-loader-CHixNPgY.js → agent-prompt-loader-7Pd4CfZO.js} +6 -6
- package/dist/agent-prompt-loader-7Pd4CfZO.js.map +1 -0
- package/dist/analytics-BcV-WCM4.js +2 -0
- package/dist/{analytics-C67F2vee.js → analytics-CHCZ_qUR.js} +10 -6
- package/dist/analytics-CHCZ_qUR.js.map +1 -0
- package/dist/{api-Dj1yabTj.js → api-Diy_2fp8.js} +4 -17
- package/dist/api-Diy_2fp8.js.map +1 -0
- package/dist/bin.js +410 -68
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-CWRYuLAn.js → bounded-fs-Bx9zTe6m.js} +4 -4
- package/dist/bounded-fs-Bx9zTe6m.js.map +1 -0
- package/dist/check-screens.tsx +1 -1
- package/dist/{ci-install-CvXL5h13.js → ci-install-CDdQYsPe.js} +6 -5
- package/dist/ci-install-CDdQYsPe.js.map +1 -0
- package/dist/constants-jFI2SaE1.js +260 -0
- package/dist/constants-jFI2SaE1.js.map +1 -0
- package/dist/debug-Ch4BDOtD.js +171 -0
- package/dist/debug-Ch4BDOtD.js.map +1 -0
- package/dist/{debug-CziFS0cA.js → debug-M2gV2iDq.js} +1 -1
- package/dist/{defaults-4c4YwTmW.js → defaults-C6J7yL4O.js} +1 -1
- package/dist/{defaults-4c4YwTmW.js.map → defaults-C6J7yL4O.js.map} +1 -1
- package/dist/endpoints-DCVbM06L.js +108 -0
- package/dist/endpoints-DCVbM06L.js.map +1 -0
- package/dist/{env-api-key-BZ5wE3Y4.js → env-api-key-Qx8NnYHm.js} +3 -3
- package/dist/env-api-key-Qx8NnYHm.js.map +1 -0
- package/dist/{environment-BEvsey6i.js → environment-B07Bmxae.js} +6 -6
- package/dist/environment-B07Bmxae.js.map +1 -0
- package/dist/{errors-BoJvrdw8.js → errors-CQ9kttJD.js} +27 -34
- package/dist/errors-CQ9kttJD.js.map +1 -0
- package/dist/{file-BoD3REGB.js → file-BcLTjU16.js} +2 -2
- package/dist/{file-BoD3REGB.js.map → file-BcLTjU16.js.map} +1 -1
- package/dist/{file-watcher-BPFazvG_.js → file-watcher-DWc_bTs6.js} +2 -2
- package/dist/{file-watcher-BPFazvG_.js.map → file-watcher-DWc_bTs6.js.map} +1 -1
- package/dist/{gateway-session-xPFv6p5c.js → gateway-CjoShdLa.js} +175 -20
- package/dist/gateway-CjoShdLa.js.map +1 -0
- package/dist/generate-version.cjs +1 -1
- package/dist/{headless-ui-CsmQrDIl.js → headless-ui-BFFmYC4v.js} +13 -2
- package/dist/headless-ui-BFFmYC4v.js.map +1 -0
- package/dist/{interactive-Dej-sxvR.js → interactive-D6zV7brJ.js} +2 -2
- package/dist/{interactive-Dej-sxvR.js.map → interactive-D6zV7brJ.js.map} +1 -1
- package/dist/{local-dev-DPZiIPCK.js → local-dev-McsurOC-.js} +2 -2
- package/dist/local-dev-McsurOC-.js.map +1 -0
- package/dist/logging-ui-_TwoMNbG.js +226 -0
- package/dist/logging-ui-_TwoMNbG.js.map +1 -0
- package/dist/mcp-DAgaoGk5.js +97 -0
- package/dist/mcp-DAgaoGk5.js.map +1 -0
- package/dist/{mcp-prompt-streaming-BU_kuur_.js → mcp-prompt-streaming-I2U_X7BC.js} +7 -6
- package/dist/mcp-prompt-streaming-I2U_X7BC.js.map +1 -0
- package/dist/{mint-failure-BrleGqMd.js → mint-failure-D4nd2XmZ.js} +82 -25
- package/dist/mint-failure-D4nd2XmZ.js.map +1 -0
- package/dist/models-DDdBJKwT.js +83 -0
- package/dist/models-DDdBJKwT.js.map +1 -0
- package/dist/{non-interactive-DcOjH2fw.js → non-interactive-Dzow7YKY.js} +3 -3
- package/dist/non-interactive-Dzow7YKY.js.map +1 -0
- package/dist/oauth-session-DJ8h6GFa.js +74 -0
- package/dist/oauth-session-DJ8h6GFa.js.map +1 -0
- package/dist/{orchestrator-tools-DXwr8Sp3.js → orchestrator-tools-szcdscwn.js} +4 -4
- package/dist/orchestrator-tools-szcdscwn.js.map +1 -0
- package/dist/{package-json-xt3eeyBI.js → package-json-DY70kkNp.js} +2 -2
- package/dist/package-json-DY70kkNp.js.map +1 -0
- package/dist/{pi-mY8I2XkG.js → pi-D3h5Ok0i.js} +329 -65
- package/dist/pi-D3h5Ok0i.js.map +1 -0
- package/dist/{playground-CDUUKLkC.js → playground-5AB4WgNF.js} +11 -7
- package/dist/playground-5AB4WgNF.js.map +1 -0
- package/dist/{posthog-Hc_-9wrr.js → posthog-DNn574nW.js} +8 -3
- package/dist/posthog-DNn574nW.js.map +1 -0
- package/dist/{provisioning-xfdjhFtA.js → provisioning-B8uSqRZk.js} +6 -5
- package/dist/provisioning-B8uSqRZk.js.map +1 -0
- package/dist/{queue-tools-C8y_xZJi.js → queue-tools-9OOVx5TE.js} +7 -86
- package/dist/queue-tools-9OOVx5TE.js.map +1 -0
- package/dist/{registry-DTmREJ-f.js → registry-8YG-kuXk.js} +265 -6
- package/dist/registry-8YG-kuXk.js.map +1 -0
- package/dist/run-agent-legacy-d7rWlzQR.js +3739 -0
- package/dist/run-agent-legacy-d7rWlzQR.js.map +1 -0
- package/dist/{security-Dw2oFJjP.js → security-Cg_4a7vB.js} +6 -6
- package/dist/security-Cg_4a7vB.js.map +1 -0
- package/dist/{setup-utils-fjJTBhaB.js → setup-utils-CmTCTPkX.js} +46 -18
- package/dist/setup-utils-CmTCTPkX.js.map +1 -0
- package/dist/smoke-test.sh +1 -1
- package/dist/{start-tui-UNe2xQ0U.js → start-tui-CB2PZs1x.js} +38 -44
- package/dist/start-tui-CB2PZs1x.js.map +1 -0
- package/dist/{steps-C2yqOk_h.js → steps-BZcXRJNY.js} +7 -7
- package/dist/{steps-C2yqOk_h.js.map → steps-BZcXRJNY.js.map} +1 -1
- package/dist/{store-Bic4Cr3L.js → store-UN7c-ASf.js} +18 -28
- package/dist/store-UN7c-ASf.js.map +1 -0
- package/dist/{subagent-Dz41vV9j.js → subagent-BofIDK-O.js} +8 -3
- package/dist/subagent-BofIDK-O.js.map +1 -0
- package/dist/{task-5-fw_Vw3.js → task-r9t1UhQP.js} +124 -36
- package/dist/task-r9t1UhQP.js.map +1 -0
- package/dist/{task-stream-dVzl6b_q.js → task-stream-CMUilu54.js} +45 -15
- package/dist/task-stream-CMUilu54.js.map +1 -0
- package/dist/{tasks-D1c2z1aw.js → tasks-Bbv_lOBG.js} +17 -13
- package/dist/tasks-Bbv_lOBG.js.map +1 -0
- package/dist/{telemetry-BRnxBRWK.js → telemetry-D6ruCtnv.js} +5 -5
- package/dist/telemetry-D6ruCtnv.js.map +1 -0
- package/dist/{terminal-9bvRa4Qt.js → terminal-DrGyci_a.js} +39 -74
- package/dist/terminal-DrGyci_a.js.map +1 -0
- package/dist/{tools-Dp6i9k70.js → tools-Dyfh9aCD.js} +11 -11
- package/dist/tools-Dyfh9aCD.js.map +1 -0
- package/dist/ui-BBVuTM1v.js +15 -0
- package/dist/ui-BBVuTM1v.js.map +1 -0
- package/dist/version-aXxpgRKx.js +6 -0
- package/dist/version-aXxpgRKx.js.map +1 -0
- package/dist/warlock-smoke-test.ts +2 -2
- package/dist/{wizard-abort-lE6umflt.js → wizard-abort-BBkiUxfS.js} +23 -20
- package/dist/wizard-abort-BBkiUxfS.js.map +1 -0
- package/dist/wizard-abort-BU4aLyvh.js +3 -0
- package/dist/{wizard-session-FSJCkTcP.js → wizard-session-2w4Ru-Wz.js} +12 -16
- package/dist/wizard-session-2w4Ru-Wz.js.map +1 -0
- package/dist/wizard-session-DGaUHOF3.js +2 -0
- package/dist/wizard-ui-DoyOZxK8.js +16 -0
- package/dist/wizard-ui-DoyOZxK8.js.map +1 -0
- package/dist/{yara-hooks-BTNJ6MGW.js → yara-hooks-DCeMDd1o.js} +19 -68
- package/dist/yara-hooks-DCeMDd1o.js.map +1 -0
- package/dist/yara-hooks-DSGuCU9A.js +2 -0
- package/package.json +1 -1
- package/dist/agent-interface-Avtr_5M5.js.map +0 -1
- package/dist/agent-prompt-loader-CHixNPgY.js.map +0 -1
- package/dist/agent-runner-COOIUJCP.js +0 -6188
- package/dist/agent-runner-COOIUJCP.js.map +0 -1
- package/dist/analytics-C67F2vee.js.map +0 -1
- package/dist/analytics-CJA1uLlk.js +0 -2
- package/dist/api-Dj1yabTj.js.map +0 -1
- package/dist/bounded-fs-CWRYuLAn.js.map +0 -1
- package/dist/ci-install-CvXL5h13.js.map +0 -1
- package/dist/debug-B4kzIZPi.js +0 -754
- package/dist/debug-B4kzIZPi.js.map +0 -1
- package/dist/env-api-key-BZ5wE3Y4.js.map +0 -1
- package/dist/environment-BEvsey6i.js.map +0 -1
- package/dist/errors-BoJvrdw8.js.map +0 -1
- package/dist/gateway-session-C118uACz.js +0 -2
- package/dist/gateway-session-xPFv6p5c.js.map +0 -1
- package/dist/headless-ui-CsmQrDIl.js.map +0 -1
- package/dist/local-dev-DPZiIPCK.js.map +0 -1
- package/dist/mcp-Cbuw_xss.js +0 -64
- package/dist/mcp-Cbuw_xss.js.map +0 -1
- package/dist/mcp-prompt-streaming-BU_kuur_.js.map +0 -1
- package/dist/mint-failure-BrleGqMd.js.map +0 -1
- package/dist/non-interactive-DcOjH2fw.js.map +0 -1
- package/dist/orchestrator-tools-DXwr8Sp3.js.map +0 -1
- package/dist/package-json-xt3eeyBI.js.map +0 -1
- package/dist/package-manager-DR23m5Jg.js +0 -290
- package/dist/package-manager-DR23m5Jg.js.map +0 -1
- package/dist/pi-mY8I2XkG.js.map +0 -1
- package/dist/playground-CDUUKLkC.js.map +0 -1
- package/dist/posthog-Hc_-9wrr.js.map +0 -1
- package/dist/provisioning-xfdjhFtA.js.map +0 -1
- package/dist/queue-tools-C8y_xZJi.js.map +0 -1
- package/dist/registry-DTmREJ-f.js.map +0 -1
- package/dist/security-Dw2oFJjP.js.map +0 -1
- package/dist/setup-utils-fjJTBhaB.js.map +0 -1
- package/dist/start-tui-UNe2xQ0U.js.map +0 -1
- package/dist/store-Bic4Cr3L.js.map +0 -1
- package/dist/subagent-Dz41vV9j.js.map +0 -1
- package/dist/task-5-fw_Vw3.js.map +0 -1
- package/dist/task-stream-dVzl6b_q.js.map +0 -1
- package/dist/tasks-D1c2z1aw.js.map +0 -1
- package/dist/telemetry-BRnxBRWK.js.map +0 -1
- package/dist/terminal-9bvRa4Qt.js.map +0 -1
- package/dist/tools-Dp6i9k70.js.map +0 -1
- package/dist/wizard-abort-CAcInAxg.js +0 -2
- package/dist/wizard-abort-lE6umflt.js.map +0 -1
- package/dist/wizard-session-CYvyYnti.js +0 -2
- package/dist/wizard-session-FSJCkTcP.js.map +0 -1
- package/dist/yara-hooks-BTNJ6MGW.js.map +0 -1
- package/dist/yara-hooks-CFY4pGcW.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults-4c4YwTmW.js","names":["z"],"sources":["../src/steps/add-mcp-server-to-clients/results.ts","../src/steps/add-mcp-server-to-clients/defaults.ts"],"sourcesContent":["/**\n * Per-client outcome of an MCP server / plugin install or removal.\n *\n * \"Nothing to do\" is a first-class outcome rather than a silent no-op:\n * re-running `mcp add` on a machine that's already set up is the common case,\n * and collapsing it into an empty result set is what made the flow report\n * \"Installation skipped.\" with no explanation. Failures carry a short reason\n * for the same reason — an empty list tells the user nothing.\n *\n * The names are action-neutral because both `mcp add` and `mcp remove` report\n * through them: `Changed` is \"installed\" or \"removed\" depending on the flow.\n */\n\nexport enum McpClientStatus {\n /** We made the change — wrote the config, installed or removed the server. */\n Changed = 'changed',\n /** Already in the requested state; nothing was touched. */\n Unchanged = 'unchanged',\n Failed = 'failed',\n}\n\nexport interface McpClientResult {\n name: string;\n status: McpClientStatus;\n /** Short, user-facing explanation. Set for failures. */\n detail?: string;\n}\n\n/** Result shape every client's addServer/removeServer/installPlugin returns. */\nexport interface InstallResult {\n success: boolean;\n /** Already in the requested state — nothing was written or removed. */\n alreadyInstalled?: boolean;\n /** Raw failure text from the underlying CLI or filesystem error. */\n reason?: string;\n}\n\n/**\n * Failure text comes from CLIs we invoke with the user's personal API key on the\n * command line (`--header \"Authorization: Bearer phx_...\"`), so it can carry the\n * key into the log file, the TUI and exception reports. Mask it first.\n *\n * The plugin stages clone git repositories and read the user's own config, so\n * the text reaching here is no longer only ours: a failing clone echoes the\n * remote URL with any credentials embedded in it, and a config error can quote\n * a foreign provider's key. Each pattern below is a shape we have seen a CLI\n * print, not a guess at every possible secret.\n */\nexport const redactSecrets = (raw: string): string =>\n raw\n .replace(/Bearer\\s+\\S+/gi, 'Bearer [redacted]')\n .replace(/ph[xspc]_[A-Za-z0-9_-]+/g, '[redacted]')\n // `https://user:token@github.com/...` — git prints the whole remote back.\n .replace(/(\\bhttps?:\\/\\/)[^/\\s:@]+:[^/\\s@]+@/gi, '$1[redacted]@')\n // GitHub tokens, which a clone failure quotes verbatim.\n .replace(/\\bgh[pousr]_[A-Za-z0-9]{16,}/g, '[redacted]')\n .replace(/\\bgithub_pat_[A-Za-z0-9_]{20,}/g, '[redacted]')\n // OpenAI keys: `OPENAI_API_KEY` is already a failure codex reports on.\n .replace(/\\bsk-[A-Za-z0-9_-]{16,}/g, '[redacted]')\n // Google keys, which a config error quotes the same way.\n .replace(/\\bAIza[A-Za-z0-9_-]{16,}/g, '[redacted]')\n // The catch-all for providers we have no shape for: a config error prints\n // the offending line, and the variable's own name says it holds a secret.\n // The name is kept — `OPENAI_API_KEY` is wording an expected-failure hint\n // matches on, and masking it would turn that hint back into an exception.\n .replace(\n /\\b([A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIALS?)[A-Za-z0-9_]*)(\\s*[=:]\\s*)[\"']?[A-Za-z0-9_\\-./+]{8,}[\"']?/gi,\n '$1$2[redacted]',\n );\n\n/**\n * Replace the user's home directory with `~`. Error tracking fingerprints on\n * the message, so a path that differs per user splits one root cause into one\n * issue per user — and the username itself never needs to leave the machine.\n */\nexport const scrubHomePaths = (raw: string): string =>\n raw\n .replace(/\\/(?:Users|home)\\/[^/\\s'\"]+/g, '~')\n .replace(/[A-Za-z]:\\\\Users\\\\[^\\\\\\s'\"]+/gi, '~');\n\n/**\n * A failure that lives entirely in the user's environment: a CLI too old, a\n * broken install, an unreadable config. We can't fix these, so we hand back a\n * hint instead of filing an issue nobody can action.\n *\n * Silencing a failure is the expensive direction: a pattern that matches too\n * much retires a real bug of ours into a hint nobody reads. So an entry says\n * where it applies (`stages`) and what disqualifies it (`unless`), and anything\n * it cannot claim confidently goes back to being reported.\n */\nexport interface ExpectedFailure {\n match: RegExp;\n /**\n * Stages this hint is allowed to fire on. Omitted means any stage. Wording\n * that means one thing during `plugin install` can mean something else during\n * `mcp add`, and a hint naming the wrong command is worse than none.\n */\n stages?: string[];\n /**\n * Wording that disqualifies the match even when `match` hits — the tell that\n * the failure is ours, not the environment's.\n */\n unless?: RegExp;\n /** One short line, shown to the user as the failure detail. */\n hint: string;\n}\n\n/**\n * The first matching hint, or undefined when the failure is worth reporting.\n *\n * `stage` is the caller's name for what it was doing. Passing it lets an entry\n * narrow itself; omitting it only considers entries that claim every stage,\n * because an unscoped call cannot honour a scoped entry.\n */\nexport const expectedFailureHint = (\n text: string,\n table: ExpectedFailure[],\n stage?: string,\n): string | undefined => {\n if (!text.trim()) return undefined;\n return table.find(\n (f) =>\n (f.stages === undefined ||\n (stage !== undefined && f.stages.includes(stage))) &&\n f.match.test(text) &&\n !f.unless?.test(text),\n )?.hint;\n};\n\n/** First non-empty line of an error, trimmed to something a TUI line can hold. */\nexport const summarizeFailure = (raw?: string): string | undefined => {\n const line = redactSecrets(raw ?? '')\n .split('\\n')\n .map((l) => l.trim())\n .find((l) => l.length > 0);\n if (!line) return undefined;\n return line.length > 120 ? `${line.slice(0, 117)}...` : line;\n};\n\nexport const toClientResult = (\n name: string,\n result: InstallResult | undefined,\n): McpClientResult => {\n if (!result?.success) {\n return {\n name,\n status: McpClientStatus.Failed,\n detail: summarizeFailure(result?.reason),\n };\n }\n return {\n name,\n status: result.alreadyInstalled\n ? McpClientStatus.Unchanged\n : McpClientStatus.Changed,\n };\n};\n\nexport const isOk = (r: McpClientResult): boolean =>\n r.status !== McpClientStatus.Failed;\n\nexport const namesWithStatus = (\n results: McpClientResult[],\n status: McpClientStatus,\n): string[] => results.filter((r) => r.status === status).map((r) => r.name);\n","import z from 'zod';\n\nexport const DefaultMCPClientConfig = z\n .object({\n mcpServers: z.record(\n z.string(),\n z.union([\n z.object({\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n }),\n z.object({\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n }),\n ]),\n ),\n })\n .passthrough();\n\nexport const AVAILABLE_FEATURES = {\n 'Data & Analytics': [\n {\n value: 'dashboards',\n label: 'Dashboards',\n hint: 'Dashboard creation and management',\n },\n {\n value: 'insights',\n label: 'Insights',\n hint: 'Analytics insights',\n },\n {\n value: 'product_analytics',\n label: 'Product Analytics',\n hint: 'Insight CRUD management',\n },\n {\n value: 'experiments',\n label: 'Experiments',\n hint: 'A/B testing experiments',\n },\n {\n value: 'surveys',\n label: 'Surveys',\n hint: 'Survey management',\n },\n {\n value: 'annotations',\n label: 'Annotations',\n hint: 'Annotation management',\n },\n {\n value: 'replay',\n label: 'Session Replay',\n hint: 'Session recording management',\n },\n {\n value: 'sql',\n label: 'SQL',\n hint: 'SQL query execution',\n },\n {\n value: 'web_analytics',\n label: 'Web Analytics',\n hint: 'Web analytics queries and digests',\n },\n {\n value: 'customer_analytics',\n label: 'Usage metrics',\n hint: 'Customer usage metric tracking',\n },\n {\n value: 'signals',\n label: 'Signals',\n hint: 'Signal reports and source configs',\n },\n ],\n 'AI Engineering': [\n {\n value: 'llm_analytics',\n label: 'AI Observability',\n hint: 'LLM usage and cost tracking',\n },\n ],\n 'Development Tools': [\n {\n value: 'error_tracking',\n label: 'Error Tracking',\n hint: 'Error monitoring and debugging',\n },\n {\n value: 'logs',\n label: 'Logs',\n hint: 'Log querying',\n },\n {\n value: 'flags',\n label: 'Feature Flags',\n hint: 'Feature flag management',\n },\n {\n value: 'early_access_features',\n label: 'Early Access Features',\n hint: 'Early access feature management',\n },\n {\n value: 'cohorts',\n label: 'Cohorts',\n hint: 'Cohort management',\n },\n {\n value: 'sdk_doctor',\n label: 'SDK Doctor',\n hint: 'SDK health diagnostics',\n },\n {\n value: 'tracing',\n label: 'APM Tracing',\n hint: 'Distributed trace and span queries',\n },\n ],\n 'Data Management': [\n {\n value: 'events',\n label: 'Events',\n hint: 'Event and property definitions',\n },\n {\n value: 'persons',\n label: 'Persons',\n hint: 'Person and group management',\n },\n {\n value: 'actions',\n label: 'Actions',\n hint: 'Action definitions',\n },\n {\n value: 'data_warehouse',\n label: 'Data Warehouse',\n hint: 'Data warehouse management',\n },\n {\n value: 'endpoints',\n label: 'Endpoints',\n hint: 'Data warehouse endpoint management',\n },\n {\n value: 'data_schema',\n label: 'Data Schema',\n hint: 'Data schema exploration',\n },\n {\n value: 'batch_exports',\n label: 'Batch Exports',\n hint: 'Scheduled data exports',\n },\n ],\n 'CDP & Automation': [\n {\n value: 'hog_functions',\n label: 'Hog Functions',\n hint: 'CDP function management',\n },\n {\n value: 'hog_function_templates',\n label: 'Hog Function Templates',\n hint: 'CDP function template browsing',\n },\n {\n value: 'workflows',\n label: 'Workflows',\n hint: 'Workflow management',\n },\n ],\n 'Platform & Management': [\n {\n value: 'workspace',\n label: 'Workspace',\n hint: 'Organization and project management',\n },\n {\n value: 'docs',\n label: 'Documentation',\n hint: 'PostHog documentation search',\n },\n {\n value: 'notebooks',\n label: 'Notebooks',\n hint: 'Notebook management',\n },\n {\n value: 'alerts',\n label: 'Alerts',\n hint: 'Alert management',\n },\n {\n value: 'platform_features',\n label: 'Platform Features',\n hint: 'Activity logs, approvals, comments, and roles',\n },\n {\n value: 'integrations',\n label: 'Integrations',\n hint: 'Connected integration management',\n },\n {\n value: 'conversations',\n label: 'Conversations',\n hint: 'Support ticket management',\n },\n {\n value: 'core',\n label: 'Subscriptions',\n hint: 'Scheduled insight and dashboard deliveries',\n },\n {\n value: 'search',\n label: 'Search',\n hint: 'Entity search across the project',\n },\n {\n value: 'reverse_proxy',\n label: 'Reverse Proxy',\n hint: 'Reverse proxy record management',\n },\n {\n value: 'debug',\n label: 'Debug',\n hint: 'Debug and diagnostic tools',\n },\n ],\n};\n\nexport const ALL_FEATURE_VALUES = Object.values(AVAILABLE_FEATURES)\n .flat()\n .map((feature) => feature.value);\n\nexport const isAllFeaturesSelected = (features: string[]): boolean =>\n features.length === ALL_FEATURE_VALUES.length &&\n ALL_FEATURE_VALUES.every((feature) => features.includes(feature));\n\nexport const buildMCPUrl = (selectedFeatures?: string[], local?: boolean) => {\n const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';\n const baseUrl = `${host}/mcp`;\n\n const params: string[] = [];\n\n // Add features param if not all features selected\n if (\n selectedFeatures &&\n selectedFeatures.length > 0 &&\n !isAllFeaturesSelected(selectedFeatures)\n ) {\n params.push(`features=${selectedFeatures.join(',')}`);\n }\n\n return params.length > 0 ? `${baseUrl}?${params.join('&')}` : baseUrl;\n};\n\nexport const getNativeHTTPServerConfig = (\n apiKey: string | undefined,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const config: Record<string, unknown> = {\n url: buildMCPUrl(selectedFeatures, local),\n };\n\n // Only add auth header if API key is provided (not OAuth mode)\n if (apiKey) {\n config.headers = {\n Authorization: `Bearer ${apiKey}`,\n };\n }\n\n return config;\n};\n\nexport const getDefaultServerConfig = (\n apiKey: string | undefined,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const urlWithFeatures = buildMCPUrl(selectedFeatures, local);\n\n // OAuth mode: no auth header, let MCP handle OAuth\n if (!apiKey) {\n return {\n command: 'npx',\n args: ['-y', 'mcp-remote@latest', urlWithFeatures],\n };\n }\n\n // API key mode: include auth header\n return {\n command: 'npx',\n args: [\n '-y',\n 'mcp-remote@latest',\n urlWithFeatures,\n '--header',\n `Authorization:\\${POSTHOG_AUTH_HEADER}`,\n ],\n env: {\n POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;AAgDA,MAAa,iBAAiB,QAC5B,IACG,QAAQ,kBAAkB,oBAAoB,CAC9C,QAAQ,4BAA4B,aAAa,CAEjD,QAAQ,wCAAwC,gBAAgB,CAEhE,QAAQ,iCAAiC,aAAa,CACtD,QAAQ,mCAAmC,aAAa,CAExD,QAAQ,4BAA4B,aAAa,CAEjD,QAAQ,6BAA6B,aAAa,CAKlD,QACC,gIACA,iBACD;;;;;;AAOL,MAAa,kBAAkB,QAC7B,IACG,QAAQ,gCAAgC,IAAI,CAC5C,QAAQ,kCAAkC,IAAI;;;;;;;;AAoCnD,MAAa,uBACX,MACA,OACA,UACuB;AACvB,KAAI,CAAC,KAAK,MAAM,CAAE,QAAO,KAAA;AACzB,QAAO,MAAM,MACV,OACE,EAAE,WAAW,KAAA,KACX,UAAU,KAAA,KAAa,EAAE,OAAO,SAAS,MAAM,KAClD,EAAE,MAAM,KAAK,KAAK,IAClB,CAAC,EAAE,QAAQ,KAAK,KAAK,CACxB,EAAE;;;AAIL,MAAa,oBAAoB,QAAqC;CACpE,MAAM,OAAO,cAAc,OAAO,GAAG,CAClC,MAAM,KAAK,CACX,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,MAAM,MAAM,EAAE,SAAS,EAAE;AAC5B,KAAI,CAAC,KAAM,QAAO,KAAA;AAClB,QAAO,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO;;AAG1D,MAAa,kBACX,MACA,WACoB;AACpB,KAAI,CAAC,QAAQ,QACX,QAAO;EACL;EACA,QAAA;EACA,QAAQ,iBAAiB,QAAQ,OAAO;EACzC;AAEH,QAAO;EACL;EACA,QAAQ,OAAO,mBAAA,cAAA;EAGhB;;AAGH,MAAa,QAAQ,MACnB,EAAE,WAAA;AAEJ,MAAa,mBACX,SACA,WACa,QAAQ,QAAQ,MAAM,EAAE,WAAW,OAAO,CAAC,KAAK,MAAM,EAAE,KAAK;AClKtCA,IACnC,OAAO,EACN,YAAYA,IAAE,OACZA,IAAE,QAAQ,EACVA,IAAE,MAAM,CACNA,IAAE,OAAO;CACP,SAASA,IAAE,QAAQ,CAAC,UAAU;CAC9B,MAAMA,IAAE,MAAMA,IAAE,QAAQ,CAAC,CAAC,UAAU;CACpC,KAAKA,IAAE,OAAOA,IAAE,QAAQ,EAAEA,IAAE,QAAQ,CAAC,CAAC,UAAU;CACjD,CAAC,EACFA,IAAE,OAAO;CACP,KAAKA,IAAE,QAAQ;CACf,SAASA,IAAE,OAAOA,IAAE,QAAQ,EAAEA,IAAE,QAAQ,CAAC,CAAC,UAAU;CACrD,CAAC,CACH,CAAC,CACH,EACF,CAAC,CACD,aAAa;AAEhB,MAAa,qBAAqB;CAChC,oBAAoB;EAClB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,kBAAkB,CAChB;EACE,OAAO;EACP,OAAO;EACP,MAAM;EACP,CACF;CACD,qBAAqB;EACnB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,mBAAmB;EACjB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,oBAAoB;EAClB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,yBAAyB;EACvB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACF;AAED,MAAa,qBAAqB,OAAO,OAAO,mBAAmB,CAChE,MAAM,CACN,KAAK,YAAY,QAAQ,MAAM;AAElC,MAAa,yBAAyB,aACpC,SAAS,WAAW,mBAAmB,UACvC,mBAAmB,OAAO,YAAY,SAAS,SAAS,QAAQ,CAAC;AAEnE,MAAa,eAAe,kBAA6B,UAAoB;CAE3E,MAAM,UAAU,GADH,QAAQ,0BAA0B,0BACvB;CAExB,MAAM,SAAmB,EAAE;AAG3B,KACE,oBACA,iBAAiB,SAAS,KAC1B,CAAC,sBAAsB,iBAAiB,CAExC,QAAO,KAAK,YAAY,iBAAiB,KAAK,IAAI,GAAG;AAGvD,QAAO,OAAO,SAAS,IAAI,GAAG,QAAQ,GAAG,OAAO,KAAK,IAAI,KAAK;;AAGhE,MAAa,6BACX,QACA,kBACA,UACG;CACH,MAAM,SAAkC,EACtC,KAAK,YAAY,kBAAkB,MAAM,EAC1C;AAGD,KAAI,OACF,QAAO,UAAU,EACf,eAAe,UAAU,UAC1B;AAGH,QAAO;;AAGT,MAAa,0BACX,QACA,kBACA,UACG;CACH,MAAM,kBAAkB,YAAY,kBAAkB,MAAM;AAG5D,KAAI,CAAC,OACH,QAAO;EACL,SAAS;EACT,MAAM;GAAC;GAAM;GAAqB;GAAgB;EACnD;AAIH,QAAO;EACL,SAAS;EACT,MAAM;GACJ;GACA;GACA;GACA;GACA;GACD;EACD,KAAK,EACH,qBAAqB,UAAU,UAChC;EACF"}
|
|
1
|
+
{"version":3,"file":"defaults-C6J7yL4O.js","names":["z"],"sources":["../src/steps/add-mcp-server-to-clients/results.ts","../src/steps/add-mcp-server-to-clients/defaults.ts"],"sourcesContent":["/**\n * Per-client outcome of an MCP server / plugin install or removal.\n *\n * \"Nothing to do\" is a first-class outcome rather than a silent no-op:\n * re-running `mcp add` on a machine that's already set up is the common case,\n * and collapsing it into an empty result set is what made the flow report\n * \"Installation skipped.\" with no explanation. Failures carry a short reason\n * for the same reason — an empty list tells the user nothing.\n *\n * The names are action-neutral because both `mcp add` and `mcp remove` report\n * through them: `Changed` is \"installed\" or \"removed\" depending on the flow.\n */\n\nexport enum McpClientStatus {\n /** We made the change — wrote the config, installed or removed the server. */\n Changed = 'changed',\n /** Already in the requested state; nothing was touched. */\n Unchanged = 'unchanged',\n Failed = 'failed',\n}\n\nexport interface McpClientResult {\n name: string;\n status: McpClientStatus;\n /** Short, user-facing explanation. Set for failures. */\n detail?: string;\n}\n\n/** Result shape every client's addServer/removeServer/installPlugin returns. */\nexport interface InstallResult {\n success: boolean;\n /** Already in the requested state — nothing was written or removed. */\n alreadyInstalled?: boolean;\n /** Raw failure text from the underlying CLI or filesystem error. */\n reason?: string;\n}\n\n/**\n * Failure text comes from CLIs we invoke with the user's personal API key on the\n * command line (`--header \"Authorization: Bearer phx_...\"`), so it can carry the\n * key into the log file, the TUI and exception reports. Mask it first.\n *\n * The plugin stages clone git repositories and read the user's own config, so\n * the text reaching here is no longer only ours: a failing clone echoes the\n * remote URL with any credentials embedded in it, and a config error can quote\n * a foreign provider's key. Each pattern below is a shape we have seen a CLI\n * print, not a guess at every possible secret.\n */\nexport const redactSecrets = (raw: string): string =>\n raw\n .replace(/Bearer\\s+\\S+/gi, 'Bearer [redacted]')\n .replace(/ph[xspc]_[A-Za-z0-9_-]+/g, '[redacted]')\n // `https://user:token@github.com/...` — git prints the whole remote back.\n .replace(/(\\bhttps?:\\/\\/)[^/\\s:@]+:[^/\\s@]+@/gi, '$1[redacted]@')\n // GitHub tokens, which a clone failure quotes verbatim.\n .replace(/\\bgh[pousr]_[A-Za-z0-9]{16,}/g, '[redacted]')\n .replace(/\\bgithub_pat_[A-Za-z0-9_]{20,}/g, '[redacted]')\n // OpenAI keys: `OPENAI_API_KEY` is already a failure codex reports on.\n .replace(/\\bsk-[A-Za-z0-9_-]{16,}/g, '[redacted]')\n // Google keys, which a config error quotes the same way.\n .replace(/\\bAIza[A-Za-z0-9_-]{16,}/g, '[redacted]')\n // The catch-all for providers we have no shape for: a config error prints\n // the offending line, and the variable's own name says it holds a secret.\n // The name is kept — `OPENAI_API_KEY` is wording an expected-failure hint\n // matches on, and masking it would turn that hint back into an exception.\n .replace(\n /\\b([A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIALS?)[A-Za-z0-9_]*)(\\s*[=:]\\s*)[\"']?[A-Za-z0-9_\\-./+]{8,}[\"']?/gi,\n '$1$2[redacted]',\n );\n\n/**\n * Replace the user's home directory with `~`. Error tracking fingerprints on\n * the message, so a path that differs per user splits one root cause into one\n * issue per user — and the username itself never needs to leave the machine.\n */\nexport const scrubHomePaths = (raw: string): string =>\n raw\n .replace(/\\/(?:Users|home)\\/[^/\\s'\"]+/g, '~')\n .replace(/[A-Za-z]:\\\\Users\\\\[^\\\\\\s'\"]+/gi, '~');\n\n/**\n * A failure that lives entirely in the user's environment: a CLI too old, a\n * broken install, an unreadable config. We can't fix these, so we hand back a\n * hint instead of filing an issue nobody can action.\n *\n * Silencing a failure is the expensive direction: a pattern that matches too\n * much retires a real bug of ours into a hint nobody reads. So an entry says\n * where it applies (`stages`) and what disqualifies it (`unless`), and anything\n * it cannot claim confidently goes back to being reported.\n */\nexport interface ExpectedFailure {\n match: RegExp;\n /**\n * Stages this hint is allowed to fire on. Omitted means any stage. Wording\n * that means one thing during `plugin install` can mean something else during\n * `mcp add`, and a hint naming the wrong command is worse than none.\n */\n stages?: string[];\n /**\n * Wording that disqualifies the match even when `match` hits — the tell that\n * the failure is ours, not the environment's.\n */\n unless?: RegExp;\n /** One short line, shown to the user as the failure detail. */\n hint: string;\n}\n\n/**\n * The first matching hint, or undefined when the failure is worth reporting.\n *\n * `stage` is the caller's name for what it was doing. Passing it lets an entry\n * narrow itself; omitting it only considers entries that claim every stage,\n * because an unscoped call cannot honour a scoped entry.\n */\nexport const expectedFailureHint = (\n text: string,\n table: ExpectedFailure[],\n stage?: string,\n): string | undefined => {\n if (!text.trim()) return undefined;\n return table.find(\n (f) =>\n (f.stages === undefined ||\n (stage !== undefined && f.stages.includes(stage))) &&\n f.match.test(text) &&\n !f.unless?.test(text),\n )?.hint;\n};\n\n/** First non-empty line of an error, trimmed to something a TUI line can hold. */\nexport const summarizeFailure = (raw?: string): string | undefined => {\n const line = redactSecrets(raw ?? '')\n .split('\\n')\n .map((l) => l.trim())\n .find((l) => l.length > 0);\n if (!line) return undefined;\n return line.length > 120 ? `${line.slice(0, 117)}...` : line;\n};\n\nexport const toClientResult = (\n name: string,\n result: InstallResult | undefined,\n): McpClientResult => {\n if (!result?.success) {\n return {\n name,\n status: McpClientStatus.Failed,\n detail: summarizeFailure(result?.reason),\n };\n }\n return {\n name,\n status: result.alreadyInstalled\n ? McpClientStatus.Unchanged\n : McpClientStatus.Changed,\n };\n};\n\nexport const isOk = (r: McpClientResult): boolean =>\n r.status !== McpClientStatus.Failed;\n\nexport const namesWithStatus = (\n results: McpClientResult[],\n status: McpClientStatus,\n): string[] => results.filter((r) => r.status === status).map((r) => r.name);\n","import z from 'zod';\n\nexport const DefaultMCPClientConfig = z\n .object({\n mcpServers: z.record(\n z.string(),\n z.union([\n z.object({\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n }),\n z.object({\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n }),\n ]),\n ),\n })\n .passthrough();\n\nexport const AVAILABLE_FEATURES = {\n 'Data & Analytics': [\n {\n value: 'dashboards',\n label: 'Dashboards',\n hint: 'Dashboard creation and management',\n },\n {\n value: 'insights',\n label: 'Insights',\n hint: 'Analytics insights',\n },\n {\n value: 'product_analytics',\n label: 'Product Analytics',\n hint: 'Insight CRUD management',\n },\n {\n value: 'experiments',\n label: 'Experiments',\n hint: 'A/B testing experiments',\n },\n {\n value: 'surveys',\n label: 'Surveys',\n hint: 'Survey management',\n },\n {\n value: 'annotations',\n label: 'Annotations',\n hint: 'Annotation management',\n },\n {\n value: 'replay',\n label: 'Session Replay',\n hint: 'Session recording management',\n },\n {\n value: 'sql',\n label: 'SQL',\n hint: 'SQL query execution',\n },\n {\n value: 'web_analytics',\n label: 'Web Analytics',\n hint: 'Web analytics queries and digests',\n },\n {\n value: 'customer_analytics',\n label: 'Usage metrics',\n hint: 'Customer usage metric tracking',\n },\n {\n value: 'signals',\n label: 'Signals',\n hint: 'Signal reports and source configs',\n },\n ],\n 'AI Engineering': [\n {\n value: 'llm_analytics',\n label: 'AI Observability',\n hint: 'LLM usage and cost tracking',\n },\n ],\n 'Development Tools': [\n {\n value: 'error_tracking',\n label: 'Error Tracking',\n hint: 'Error monitoring and debugging',\n },\n {\n value: 'logs',\n label: 'Logs',\n hint: 'Log querying',\n },\n {\n value: 'flags',\n label: 'Feature Flags',\n hint: 'Feature flag management',\n },\n {\n value: 'early_access_features',\n label: 'Early Access Features',\n hint: 'Early access feature management',\n },\n {\n value: 'cohorts',\n label: 'Cohorts',\n hint: 'Cohort management',\n },\n {\n value: 'sdk_doctor',\n label: 'SDK Doctor',\n hint: 'SDK health diagnostics',\n },\n {\n value: 'tracing',\n label: 'APM Tracing',\n hint: 'Distributed trace and span queries',\n },\n ],\n 'Data Management': [\n {\n value: 'events',\n label: 'Events',\n hint: 'Event and property definitions',\n },\n {\n value: 'persons',\n label: 'Persons',\n hint: 'Person and group management',\n },\n {\n value: 'actions',\n label: 'Actions',\n hint: 'Action definitions',\n },\n {\n value: 'data_warehouse',\n label: 'Data Warehouse',\n hint: 'Data warehouse management',\n },\n {\n value: 'endpoints',\n label: 'Endpoints',\n hint: 'Data warehouse endpoint management',\n },\n {\n value: 'data_schema',\n label: 'Data Schema',\n hint: 'Data schema exploration',\n },\n {\n value: 'batch_exports',\n label: 'Batch Exports',\n hint: 'Scheduled data exports',\n },\n ],\n 'CDP & Automation': [\n {\n value: 'hog_functions',\n label: 'Hog Functions',\n hint: 'CDP function management',\n },\n {\n value: 'hog_function_templates',\n label: 'Hog Function Templates',\n hint: 'CDP function template browsing',\n },\n {\n value: 'workflows',\n label: 'Workflows',\n hint: 'Workflow management',\n },\n ],\n 'Platform & Management': [\n {\n value: 'workspace',\n label: 'Workspace',\n hint: 'Organization and project management',\n },\n {\n value: 'docs',\n label: 'Documentation',\n hint: 'PostHog documentation search',\n },\n {\n value: 'notebooks',\n label: 'Notebooks',\n hint: 'Notebook management',\n },\n {\n value: 'alerts',\n label: 'Alerts',\n hint: 'Alert management',\n },\n {\n value: 'platform_features',\n label: 'Platform Features',\n hint: 'Activity logs, approvals, comments, and roles',\n },\n {\n value: 'integrations',\n label: 'Integrations',\n hint: 'Connected integration management',\n },\n {\n value: 'conversations',\n label: 'Conversations',\n hint: 'Support ticket management',\n },\n {\n value: 'core',\n label: 'Subscriptions',\n hint: 'Scheduled insight and dashboard deliveries',\n },\n {\n value: 'search',\n label: 'Search',\n hint: 'Entity search across the project',\n },\n {\n value: 'reverse_proxy',\n label: 'Reverse Proxy',\n hint: 'Reverse proxy record management',\n },\n {\n value: 'debug',\n label: 'Debug',\n hint: 'Debug and diagnostic tools',\n },\n ],\n};\n\nexport const ALL_FEATURE_VALUES = Object.values(AVAILABLE_FEATURES)\n .flat()\n .map((feature) => feature.value);\n\nexport const isAllFeaturesSelected = (features: string[]): boolean =>\n features.length === ALL_FEATURE_VALUES.length &&\n ALL_FEATURE_VALUES.every((feature) => features.includes(feature));\n\nexport const buildMCPUrl = (selectedFeatures?: string[], local?: boolean) => {\n const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';\n const baseUrl = `${host}/mcp`;\n\n const params: string[] = [];\n\n // Add features param if not all features selected\n if (\n selectedFeatures &&\n selectedFeatures.length > 0 &&\n !isAllFeaturesSelected(selectedFeatures)\n ) {\n params.push(`features=${selectedFeatures.join(',')}`);\n }\n\n return params.length > 0 ? `${baseUrl}?${params.join('&')}` : baseUrl;\n};\n\nexport const getNativeHTTPServerConfig = (\n apiKey: string | undefined,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const config: Record<string, unknown> = {\n url: buildMCPUrl(selectedFeatures, local),\n };\n\n // Only add auth header if API key is provided (not OAuth mode)\n if (apiKey) {\n config.headers = {\n Authorization: `Bearer ${apiKey}`,\n };\n }\n\n return config;\n};\n\nexport const getDefaultServerConfig = (\n apiKey: string | undefined,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const urlWithFeatures = buildMCPUrl(selectedFeatures, local);\n\n // OAuth mode: no auth header, let MCP handle OAuth\n if (!apiKey) {\n return {\n command: 'npx',\n args: ['-y', 'mcp-remote@latest', urlWithFeatures],\n };\n }\n\n // API key mode: include auth header\n return {\n command: 'npx',\n args: [\n '-y',\n 'mcp-remote@latest',\n urlWithFeatures,\n '--header',\n `Authorization:\\${POSTHOG_AUTH_HEADER}`,\n ],\n env: {\n POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;AAgDA,MAAa,iBAAiB,QAC5B,IACG,QAAQ,kBAAkB,oBAAoB,CAC9C,QAAQ,4BAA4B,aAAa,CAEjD,QAAQ,wCAAwC,gBAAgB,CAEhE,QAAQ,iCAAiC,aAAa,CACtD,QAAQ,mCAAmC,aAAa,CAExD,QAAQ,4BAA4B,aAAa,CAEjD,QAAQ,6BAA6B,aAAa,CAKlD,QACC,gIACA,iBACD;;;;;;AAOL,MAAa,kBAAkB,QAC7B,IACG,QAAQ,gCAAgC,IAAI,CAC5C,QAAQ,kCAAkC,IAAI;;;;;;;;AAoCnD,MAAa,uBACX,MACA,OACA,UACuB;AACvB,KAAI,CAAC,KAAK,MAAM,CAAE,QAAO,KAAA;AACzB,QAAO,MAAM,MACV,OACE,EAAE,WAAW,KAAA,KACX,UAAU,KAAA,KAAa,EAAE,OAAO,SAAS,MAAM,KAClD,EAAE,MAAM,KAAK,KAAK,IAClB,CAAC,EAAE,QAAQ,KAAK,KAAK,CACxB,EAAE;;;AAIL,MAAa,oBAAoB,QAAqC;CACpE,MAAM,OAAO,cAAc,OAAO,GAAG,CAClC,MAAM,KAAK,CACX,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,MAAM,MAAM,EAAE,SAAS,EAAE;AAC5B,KAAI,CAAC,KAAM,QAAO,KAAA;AAClB,QAAO,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO;;AAG1D,MAAa,kBACX,MACA,WACoB;AACpB,KAAI,CAAC,QAAQ,QACX,QAAO;EACL;EACA,QAAA;EACA,QAAQ,iBAAiB,QAAQ,OAAO;EACzC;AAEH,QAAO;EACL;EACA,QAAQ,OAAO,mBAAA,cAAA;EAGhB;;AAGH,MAAa,QAAQ,MACnB,EAAE,WAAA;AAEJ,MAAa,mBACX,SACA,WACa,QAAQ,QAAQ,MAAM,EAAE,WAAW,OAAO,CAAC,KAAK,MAAM,EAAE,KAAK;AClKtCA,IACnC,OAAO,EACN,YAAYA,IAAE,OACZA,IAAE,QAAQ,EACVA,IAAE,MAAM,CACNA,IAAE,OAAO;CACP,SAASA,IAAE,QAAQ,CAAC,UAAU;CAC9B,MAAMA,IAAE,MAAMA,IAAE,QAAQ,CAAC,CAAC,UAAU;CACpC,KAAKA,IAAE,OAAOA,IAAE,QAAQ,EAAEA,IAAE,QAAQ,CAAC,CAAC,UAAU;CACjD,CAAC,EACFA,IAAE,OAAO;CACP,KAAKA,IAAE,QAAQ;CACf,SAASA,IAAE,OAAOA,IAAE,QAAQ,EAAEA,IAAE,QAAQ,CAAC,CAAC,UAAU;CACrD,CAAC,CACH,CAAC,CACH,EACF,CAAC,CACD,aAAa;AAEhB,MAAa,qBAAqB;CAChC,oBAAoB;EAClB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,kBAAkB,CAChB;EACE,OAAO;EACP,OAAO;EACP,MAAM;EACP,CACF;CACD,qBAAqB;EACnB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,mBAAmB;EACjB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,oBAAoB;EAClB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACD,yBAAyB;EACvB;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACD;GACE,OAAO;GACP,OAAO;GACP,MAAM;GACP;EACF;CACF;AAED,MAAa,qBAAqB,OAAO,OAAO,mBAAmB,CAChE,MAAM,CACN,KAAK,YAAY,QAAQ,MAAM;AAElC,MAAa,yBAAyB,aACpC,SAAS,WAAW,mBAAmB,UACvC,mBAAmB,OAAO,YAAY,SAAS,SAAS,QAAQ,CAAC;AAEnE,MAAa,eAAe,kBAA6B,UAAoB;CAE3E,MAAM,UAAU,GADH,QAAQ,0BAA0B,0BACvB;CAExB,MAAM,SAAmB,EAAE;AAG3B,KACE,oBACA,iBAAiB,SAAS,KAC1B,CAAC,sBAAsB,iBAAiB,CAExC,QAAO,KAAK,YAAY,iBAAiB,KAAK,IAAI,GAAG;AAGvD,QAAO,OAAO,SAAS,IAAI,GAAG,QAAQ,GAAG,OAAO,KAAK,IAAI,KAAK;;AAGhE,MAAa,6BACX,QACA,kBACA,UACG;CACH,MAAM,SAAkC,EACtC,KAAK,YAAY,kBAAkB,MAAM,EAC1C;AAGD,KAAI,OACF,QAAO,UAAU,EACf,eAAe,UAAU,UAC1B;AAGH,QAAO;;AAGT,MAAa,0BACX,QACA,kBACA,UACG;CACH,MAAM,kBAAkB,YAAY,kBAAkB,MAAM;AAG5D,KAAI,CAAC,OACH,QAAO;EACL,SAAS;EACT,MAAM;GAAC;GAAM;GAAqB;GAAgB;EACnD;AAIH,QAAO;EACL,SAAS;EACT,MAAM;GACJ;GACA;GACA;GACA;GACA;GACD;EACD,KAAK,EACH,qBAAqB,UAAU,UAChC;EACF"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { s as logToFile } from "./debug-Ch4BDOtD.js";
|
|
2
|
+
import { g as GITHUB_SKILLS_BASE_URL, o as AWS_SKILLS_BASE_URL } from "./constants-jFI2SaE1.js";
|
|
3
|
+
//#region src/shared/health-checks/endpoints.ts
|
|
4
|
+
function noConnectionResult(error, attempts) {
|
|
5
|
+
return {
|
|
6
|
+
status: "no-connection",
|
|
7
|
+
error,
|
|
8
|
+
rawIndicator: attempts > 1 ? `attempts=${attempts}` : void 0
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function downResult(error) {
|
|
12
|
+
return {
|
|
13
|
+
status: "down",
|
|
14
|
+
error
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const RETRY_BACKOFFS_MS = [500, 2e3];
|
|
18
|
+
async function attemptFetch(url, timeoutMs, redirect) {
|
|
19
|
+
const controller = new AbortController();
|
|
20
|
+
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(url, {
|
|
23
|
+
signal: controller.signal,
|
|
24
|
+
redirect
|
|
25
|
+
});
|
|
26
|
+
clearTimeout(tid);
|
|
27
|
+
return {
|
|
28
|
+
kind: "response",
|
|
29
|
+
res
|
|
30
|
+
};
|
|
31
|
+
} catch (e) {
|
|
32
|
+
clearTimeout(tid);
|
|
33
|
+
const err = e instanceof Error ? e : /* @__PURE__ */ new Error("Unknown error");
|
|
34
|
+
return {
|
|
35
|
+
kind: "error",
|
|
36
|
+
error: err,
|
|
37
|
+
timedOut: err.name === "AbortError"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function fetchEndpointHealth(url, timeoutMs = 5e3, isExpectedStatus = (s) => s === 200, redirect = "follow") {
|
|
42
|
+
let lastHttpStatus = null;
|
|
43
|
+
let lastError = "Unknown error";
|
|
44
|
+
let attempts = 0;
|
|
45
|
+
for (let i = 0; i <= RETRY_BACKOFFS_MS.length; i++) {
|
|
46
|
+
if (i > 0) {
|
|
47
|
+
const wait = RETRY_BACKOFFS_MS[i - 1];
|
|
48
|
+
logToFile(`[health-checks] retry ${i}/${RETRY_BACKOFFS_MS.length} for ${url} in ${wait}ms (last: ${lastError})`);
|
|
49
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
50
|
+
}
|
|
51
|
+
attempts++;
|
|
52
|
+
const outcome = await attemptFetch(url, timeoutMs, redirect);
|
|
53
|
+
if (outcome.kind === "response") {
|
|
54
|
+
const res = outcome.res;
|
|
55
|
+
if (isExpectedStatus(res.status)) {
|
|
56
|
+
const result = {
|
|
57
|
+
status: "healthy",
|
|
58
|
+
rawIndicator: attempts > 1 ? `HTTP ${res.status} (attempts=${attempts})` : `HTTP ${res.status}`
|
|
59
|
+
};
|
|
60
|
+
logToFile(`[health-checks] GET ${url} -> ${result.status} (${result.rawIndicator})`);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
lastHttpStatus = res.status;
|
|
64
|
+
lastError = `HTTP ${res.status}`;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
lastError = outcome.timedOut ? `Request timed out after ${timeoutMs}ms` : outcome.error.message;
|
|
68
|
+
}
|
|
69
|
+
const result = lastHttpStatus !== null ? downResult(`HTTP ${lastHttpStatus} (attempts=${attempts})`) : noConnectionResult(lastError, attempts);
|
|
70
|
+
logToFile(`[health-checks] GET ${url} -> ${result.status} (attempts=${attempts}, ${result.error})`);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
const checkLlmGatewayHealth = (gatewayUrl) => fetchEndpointHealth(new URL("/readyz", gatewayUrl).href);
|
|
74
|
+
/**
|
|
75
|
+
* Skills are published to two origins under the same filenames and
|
|
76
|
+
* `fetchWithRetry` fails over between them, so the run is only blocked when
|
|
77
|
+
* neither answers. Probed in parallel — sequential probes would double the
|
|
78
|
+
* worst case past `READINESS_TIMEOUT_MS`.
|
|
79
|
+
*/
|
|
80
|
+
const checkSkillsOriginHealth = async () => {
|
|
81
|
+
const [github, aws] = await Promise.all([fetchEndpointHealth(`${GITHUB_SKILLS_BASE_URL}/skill-menu.json`), fetchEndpointHealth(`${AWS_SKILLS_BASE_URL}/skill-menu.json`)]);
|
|
82
|
+
return combineOriginHealth(github, aws);
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Mirrors `fetchWithRetry`: a download tries GitHub, then AWS, so the run is
|
|
86
|
+
* only blocked when neither origin answers. Whichever failure the probes saw,
|
|
87
|
+
* one origin serving means skills are reachable.
|
|
88
|
+
*/
|
|
89
|
+
function combineOriginHealth(github, aws) {
|
|
90
|
+
if (github.status === "healthy") return aws.status === "healthy" ? github : withIndicatorSuffix(github, "aws unavailable");
|
|
91
|
+
if (aws.status === "healthy") return withIndicatorSuffix(aws, "via aws, github unavailable");
|
|
92
|
+
const error = `github: ${github.error ?? "unknown"} | aws: ${aws.error ?? "unknown"}`;
|
|
93
|
+
return {
|
|
94
|
+
status: github.status === "down" || aws.status === "down" ? "down" : "no-connection",
|
|
95
|
+
error,
|
|
96
|
+
rawIndicator: github.rawIndicator ?? aws.rawIndicator
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function withIndicatorSuffix(result, suffix) {
|
|
100
|
+
return {
|
|
101
|
+
...result,
|
|
102
|
+
rawIndicator: result.rawIndicator ? `${result.rawIndicator} (${suffix})` : suffix
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { checkSkillsOriginHealth as n, checkLlmGatewayHealth as t };
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=endpoints-DCVbM06L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints-DCVbM06L.js","names":[],"sources":["../src/shared/health-checks/endpoints.ts"],"sourcesContent":["import { AWS_SKILLS_BASE_URL, GITHUB_SKILLS_BASE_URL } from '@shared/constants';\nimport { logToFile } from '@utils/debug';\nimport { ServiceHealthStatus, type BaseHealthResult } from './types';\n\n// Direct gateway and skill-origin checks distinguish HTTP failures from connection failures.\n\nfunction noConnectionResult(error: string, attempts: number): BaseHealthResult {\n return {\n status: ServiceHealthStatus.NoConnection,\n error,\n rawIndicator: attempts > 1 ? `attempts=${attempts}` : undefined,\n };\n}\n\nfunction downResult(error: string): BaseHealthResult {\n return { status: ServiceHealthStatus.Down, error };\n}\n\n// Backoffs sized to cover typical wifi flakiness — a single dropped\n// packet recovers via the 500ms retry; a wifi access point reconnect\n// or wifi↔LTE handoff (2-5s) is caught by the 2000ms retry. Tighter\n// schedules miss multi-second blips because all retries land in the\n// same dead window.\nconst RETRY_BACKOFFS_MS = [500, 2000];\n\nasync function attemptFetch(\n url: string,\n timeoutMs: number,\n redirect: 'follow' | 'manual' | 'error',\n): Promise<\n | { kind: 'response'; res: Response }\n | { kind: 'error'; error: Error; timedOut: boolean }\n> {\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(url, { signal: controller.signal, redirect });\n clearTimeout(tid);\n return { kind: 'response', res };\n } catch (e) {\n clearTimeout(tid);\n const err = e instanceof Error ? e : new Error('Unknown error');\n return { kind: 'error', error: err, timedOut: err.name === 'AbortError' };\n }\n}\n\n// Exported so tests can pin the retry/taxonomy machinery directly.\nexport async function fetchEndpointHealth(\n url: string,\n timeoutMs = 5000,\n isExpectedStatus: (status: number) => boolean = (s) => s === 200,\n redirect: 'follow' | 'manual' | 'error' = 'follow',\n): Promise<BaseHealthResult> {\n // Total attempts = 1 initial + RETRY_BACKOFFS_MS.length retries. Both\n // unexpected HTTP statuses (4xx/5xx) and network errors trigger a retry:\n // transient 5xx and Cloudflare edge blips often recover on a retry, and\n // even nominally deterministic 4xx can be transient (CDN propagation\n // lag after a release, token rotation, rate-limit window resets). GETs\n // are idempotent so retrying is safe.\n //\n // Final status if every attempt fails:\n // - At least one HTTP response observed → `Down` (server-side evidence)\n // - Only network errors observed → `NoConnection`\n let lastHttpStatus: number | null = null;\n let lastError = 'Unknown error';\n let attempts = 0;\n\n for (let i = 0; i <= RETRY_BACKOFFS_MS.length; i++) {\n if (i > 0) {\n const wait = RETRY_BACKOFFS_MS[i - 1];\n logToFile(\n `[health-checks] retry ${i}/${RETRY_BACKOFFS_MS.length} for ${url} in ${wait}ms (last: ${lastError})`,\n );\n await new Promise((r) => setTimeout(r, wait));\n }\n attempts++;\n\n const outcome = await attemptFetch(url, timeoutMs, redirect);\n\n if (outcome.kind === 'response') {\n const res = outcome.res;\n if (isExpectedStatus(res.status)) {\n const result: BaseHealthResult = {\n status: ServiceHealthStatus.Healthy,\n rawIndicator:\n attempts > 1\n ? `HTTP ${res.status} (attempts=${attempts})`\n : `HTTP ${res.status}`,\n };\n logToFile(\n `[health-checks] GET ${url} -> ${result.status}` +\n ` (${result.rawIndicator})`,\n );\n return result;\n }\n lastHttpStatus = res.status;\n lastError = `HTTP ${res.status}`;\n continue;\n }\n\n lastError = outcome.timedOut\n ? `Request timed out after ${timeoutMs}ms`\n : outcome.error.message;\n }\n\n const result =\n lastHttpStatus !== null\n ? downResult(`HTTP ${lastHttpStatus} (attempts=${attempts})`)\n : noConnectionResult(lastError, attempts);\n logToFile(\n `[health-checks] GET ${url} -> ${result.status}` +\n ` (attempts=${attempts}, ${result.error})`,\n );\n return result;\n}\n\nexport const checkLlmGatewayHealth = (\n gatewayUrl: string,\n): Promise<BaseHealthResult> =>\n fetchEndpointHealth(new URL('/readyz', gatewayUrl).href);\n\n/**\n * Skills are published to two origins under the same filenames and\n * `fetchWithRetry` fails over between them, so the run is only blocked when\n * neither answers. Probed in parallel — sequential probes would double the\n * worst case past `READINESS_TIMEOUT_MS`.\n */\nexport const checkSkillsOriginHealth = async (): Promise<BaseHealthResult> => {\n const [github, aws] = await Promise.all([\n fetchEndpointHealth(`${GITHUB_SKILLS_BASE_URL}/skill-menu.json`),\n fetchEndpointHealth(`${AWS_SKILLS_BASE_URL}/skill-menu.json`),\n ]);\n return combineOriginHealth(github, aws);\n};\n\n/**\n * Mirrors `fetchWithRetry`: a download tries GitHub, then AWS, so the run is\n * only blocked when neither origin answers. Whichever failure the probes saw,\n * one origin serving means skills are reachable.\n */\nfunction combineOriginHealth(\n github: BaseHealthResult,\n aws: BaseHealthResult,\n): BaseHealthResult {\n if (github.status === ServiceHealthStatus.Healthy) {\n // Naming the dead origin makes a one-sided outage legible in the log and\n // in the readiness reasons, where the status alone reads as \"fine\".\n return aws.status === ServiceHealthStatus.Healthy\n ? github\n : withIndicatorSuffix(github, 'aws unavailable');\n }\n\n if (aws.status === ServiceHealthStatus.Healthy) {\n return withIndicatorSuffix(aws, 'via aws, github unavailable');\n }\n\n const error = `github: ${github.error ?? 'unknown'} | aws: ${\n aws.error ?? 'unknown'\n }`;\n const confirmedDown =\n github.status === ServiceHealthStatus.Down ||\n aws.status === ServiceHealthStatus.Down;\n return {\n status: confirmedDown\n ? ServiceHealthStatus.Down\n : ServiceHealthStatus.NoConnection,\n error,\n // Keeps the `attempts=N` the blocked-readiness analytics parses.\n rawIndicator: github.rawIndicator ?? aws.rawIndicator,\n };\n}\n\nfunction withIndicatorSuffix(\n result: BaseHealthResult,\n suffix: string,\n): BaseHealthResult {\n return {\n ...result,\n rawIndicator: result.rawIndicator\n ? `${result.rawIndicator} (${suffix})`\n : suffix,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { i as readProjectFile } from "./bounded-fs-
|
|
2
|
+
import { i as readProjectFile } from "./bounded-fs-Bx9zTe6m.js";
|
|
3
3
|
import * as path$1 from "path";
|
|
4
|
-
//#region src/utils/env-api-key.ts
|
|
4
|
+
//#region src/shared/utils/env-api-key.ts
|
|
5
5
|
var env_api_key_exports = /* @__PURE__ */ __exportAll({ readApiKeyFromEnv: () => readApiKeyFromEnv });
|
|
6
6
|
/**
|
|
7
7
|
* Read POSTHOG_PERSONAL_API_KEY from .env.local or .env in the current
|
|
@@ -16,4 +16,4 @@ function readApiKeyFromEnv() {
|
|
|
16
16
|
//#endregion
|
|
17
17
|
export { readApiKeyFromEnv as n, env_api_key_exports as t };
|
|
18
18
|
|
|
19
|
-
//# sourceMappingURL=env-api-key-
|
|
19
|
+
//# sourceMappingURL=env-api-key-Qx8NnYHm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-api-key-Qx8NnYHm.js","names":["path"],"sources":["../src/shared/utils/env-api-key.ts"],"sourcesContent":["import * as path from 'path';\nimport { readProjectFile } from './bounded-fs';\n\n/**\n * Read POSTHOG_PERSONAL_API_KEY from .env.local or .env in the current\n * working directory. Returns undefined when no key is found.\n */\nexport function readApiKeyFromEnv(): string | undefined {\n for (const envFile of ['.env.local', '.env']) {\n // null when missing or unreadable, e.g. a `.env` directory (a Python virtualenv).\n const content = readProjectFile(path.join(process.cwd(), envFile));\n const match = content?.match(/^POSTHOG_PERSONAL_API_KEY=(.+)$/m);\n if (match) return match[1].trim();\n }\n return undefined;\n}\n"],"mappings":";;;;;;;;;AAOA,SAAgB,oBAAwC;AACtD,MAAK,MAAM,WAAW,CAAC,cAAc,OAAO,EAAE;EAG5C,MAAM,QADU,gBAAgBA,OAAK,KAAK,QAAQ,KAAK,EAAE,QAAQ,CAAC,EAC3C,MAAM,mCAAmC;AAChE,MAAI,MAAO,QAAO,MAAM,GAAG,MAAM"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import "./
|
|
3
|
-
import "./bounded-fs-
|
|
4
|
-
import "./setup-utils-
|
|
2
|
+
import "./constants-jFI2SaE1.js";
|
|
3
|
+
import "./bounded-fs-Bx9zTe6m.js";
|
|
4
|
+
import "./setup-utils-CmTCTPkX.js";
|
|
5
5
|
import readEnvModule from "read-env";
|
|
6
|
-
//#region src/utils/environment.ts
|
|
6
|
+
//#region src/shared/utils/environment.ts
|
|
7
7
|
var environment_exports = /* @__PURE__ */ __exportAll({
|
|
8
8
|
isNonInteractiveEnvironment: () => isNonInteractiveEnvironment,
|
|
9
9
|
readEnvironment: () => readEnvironment
|
|
@@ -22,7 +22,7 @@ function isNonInteractiveEnvironment() {
|
|
|
22
22
|
* so every question would stall for the bridge timeout instead of failing fast
|
|
23
23
|
* with an actionable error. See `shouldDisableAsk`.
|
|
24
24
|
*/
|
|
25
|
-
const NEVER_FROM_ENV = ["e2eAsk"];
|
|
25
|
+
const NEVER_FROM_ENV = ["e2eAsk", "runId"];
|
|
26
26
|
/**
|
|
27
27
|
* Session args from the `POSTHOG_WIZARD_*` environment variables.
|
|
28
28
|
*
|
|
@@ -41,4 +41,4 @@ function readEnvironment() {
|
|
|
41
41
|
//#endregion
|
|
42
42
|
export { isNonInteractiveEnvironment as n, environment_exports as t };
|
|
43
43
|
|
|
44
|
-
//# sourceMappingURL=environment-
|
|
44
|
+
//# sourceMappingURL=environment-B07Bmxae.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-B07Bmxae.js","names":[],"sources":["../src/shared/utils/environment.ts"],"sourcesContent":["import readEnvModule from 'read-env';\n\nconst readEnv =\n typeof readEnvModule === 'function'\n ? readEnvModule\n : (readEnvModule as any).default;\nimport { tryGetPackageJson } from './setup-utils';\nimport type { WizardRunOptions } from './types';\nimport { boundedGlob } from './bounded-fs';\nimport { IS_DEV } from '@shared/constants';\n\nexport function isNonInteractiveEnvironment(): boolean {\n if (IS_DEV) {\n return false;\n }\n\n if (!process.stdout.isTTY || !process.stderr.isTTY) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Session fields the environment must never set, matched case-insensitively\n * against the camel-cased key `read-env` produces.\n *\n * `e2eAsk` re-wires the `wizard_ask` bridge in an otherwise non-interactive\n * run. Only the e2e TUI host may set it: a real `--ci` run has nobody to answer,\n * so every question would stall for the bridge timeout instead of failing fast\n * with an actionable error. See `shouldDisableAsk`.\n */\nconst NEVER_FROM_ENV = ['e2eAsk', 'runId'];\n\n/**\n * Session args from the `POSTHOG_WIZARD_*` environment variables.\n *\n * `read-env` camel-cases every prefixed variable into a key, and the CI runner\n * spreads the whole bag into `buildSession` — so adding a field to the session\n * silently adds an environment variable that sets it. Most of them are meant to\n * work that way (`POSTHOG_WIZARD_DEBUG` → `debug`); the ones in\n * {@link NEVER_FROM_ENV} are not, and are dropped here rather than at the call\n * site, so a second caller cannot reopen the door.\n */\nexport function readEnvironment(): Record<string, unknown> {\n const result = readEnv('POSTHOG_WIZARD') as Record<string, unknown>;\n\n for (const key of Object.keys(result)) {\n if (NEVER_FROM_ENV.some((k) => k.toLowerCase() === key.toLowerCase())) {\n delete result[key];\n }\n }\n\n return result;\n}\n\nexport async function detectEnvVarPrefix(\n options: WizardRunOptions,\n): Promise<string> {\n const packageJson = await tryGetPackageJson(options);\n if (!packageJson) return 'VITE_PUBLIC_';\n\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n const has = (name: string) => name in deps;\n // O(1) matches per probe: one config file existing anywhere answers it.\n const hasAnyFile = async (patterns: string[]) => {\n const matches = await boundedGlob(patterns, {\n cwd: options.installDir,\n limit: 1,\n });\n return matches.length > 0;\n };\n\n // --- Next.js\n if (has('next') || (await hasAnyFile(['**/next.config.{js,ts,mjs,cjs}']))) {\n return 'NEXT_PUBLIC_';\n }\n\n // --- Create React App\n if (\n has('react-scripts') ||\n has('create-react-app') ||\n (await hasAnyFile(['**/config-overrides.js']))\n ) {\n return 'REACT_APP_';\n }\n\n // --- Vite (vanilla, TanStack, Solid, etc.)\n // Note: Vite does not need PUBLIC_ but we use it to follow the docs, to improve the chances of an LLM getting it right.\n if (has('vite') || (await hasAnyFile(['**/vite.config.{js,ts,mjs,cjs}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SvelteKit\n if (\n has('@sveltejs/kit') ||\n (await hasAnyFile(['**/svelte.config.{js,ts}']))\n ) {\n return 'PUBLIC_';\n }\n\n // --- TanStack Start (uses Vite)\n if (\n has('@tanstack/start') ||\n (await hasAnyFile(['**/tanstack.config.{js,ts}']))\n ) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SolidStart (uses Vite)\n if (has('solid-start') || (await hasAnyFile(['**/solid.config.{js,ts}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- Astro\n if (has('astro') || (await hasAnyFile(['**/astro.config.{js,ts,mjs}']))) {\n return 'PUBLIC_';\n }\n\n // We default to Vite if we can't detect a specific framework, since it's the most commonly used.\n return 'VITE_PUBLIC_';\n}\n"],"mappings":";;;;;;;;;;AAEA,MAAM,UACJ,OAAO,kBAAkB,aACrB,gBACC,cAAsB;AAM7B,SAAgB,8BAAuC;AAKrD,KAAI,CAAC,QAAQ,OAAO,SAAS,CAAC,QAAQ,OAAO,MAC3C,QAAO;AAGT,QAAO;;;;;;;;;;;AAYT,MAAM,iBAAiB,CAAC,UAAU,QAAQ;;;;;;;;;;;AAY1C,SAAgB,kBAA2C;CACzD,MAAM,SAAS,QAAQ,iBAAiB;AAExC,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,eAAe,MAAM,MAAM,EAAE,aAAa,KAAK,IAAI,aAAa,CAAC,CACnE,QAAO,OAAO;AAIlB,QAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/shared/errors/codes.ts
|
|
2
2
|
const ErrorCodes = {
|
|
3
3
|
CliNodeVersion: "PHW_CLI_NODE_VERSION",
|
|
4
4
|
CliBadArgs: "PHW_CLI_BAD_ARGS",
|
|
@@ -54,7 +54,7 @@ function isErrorCode(value) {
|
|
|
54
54
|
return Object.values(ErrorCodes).includes(value);
|
|
55
55
|
}
|
|
56
56
|
//#endregion
|
|
57
|
-
//#region src/
|
|
57
|
+
//#region src/shared/errors/emit.ts
|
|
58
58
|
const PHW_ERROR_PREFIX = "phw-error:";
|
|
59
59
|
function formatWizardErrorLine(line) {
|
|
60
60
|
return `${PHW_ERROR_PREFIX} ${JSON.stringify(line)}`;
|
|
@@ -64,7 +64,24 @@ function emitWizardError(line) {
|
|
|
64
64
|
}
|
|
65
65
|
ErrorCodes.CliNodeVersion, ErrorCodes.CliBadArgs, ErrorCodes.CliFlagUnavailable, ErrorCodes.CliInteractiveRequired, ErrorCodes.ArgsMissingApiKey, ErrorCodes.ArgsMissingInstallDir, ErrorCodes.ArgsMissingEmail, ErrorCodes.ArgsSignupProvisionFailed, ErrorCodes.AuthKeyType, ErrorCodes.AuthInvalidOrExpired, ErrorCodes.AuthSessionExpired, ErrorCodes.AuthMissingScope, ErrorCodes.AuthRegionMismatch, ErrorCodes.AuthSettingsConflict, ErrorCodes.AuthStoredLoginConflict, ErrorCodes.AuthProjectFetchFailed, ErrorCodes.EnvLocalServicesDown, ErrorCodes.EnvServiceOutage, ErrorCodes.DetectBadDirectory, ErrorCodes.DetectNoFramework, ErrorCodes.DetectUnsupportedVersion, ErrorCodes.DetectUnsupportedPlatform, ErrorCodes.DetectNoPosthogSdk, ErrorCodes.DetectNoProjectFiles, ErrorCodes.DetectNoSources, ErrorCodes.DetectNoPackageJson, ErrorCodes.DetectNoSdks, ErrorCodes.DetectMissingStripe, ErrorCodes.DetectUnclassified, ErrorCodes.SkillMenuFetchFailed, ErrorCodes.SkillNotFound, ErrorCodes.SkillDownloadFailed, ErrorCodes.AgentAbort, ErrorCodes.AgenticDetectionTimeout, ErrorCodes.AgentMcpMissing, ErrorCodes.AgentResourceMissing, ErrorCodes.AgentRateLimit, ErrorCodes.AgentApiError, ErrorCodes.AgentYaraViolation, ErrorCodes.AgentNoProgress, ErrorCodes.AgentIncompleteTasks, ErrorCodes.AgentOrchestratorSkillVariantMissing, ErrorCodes.AgentOrchestratorTasksFailed, ErrorCodes.AgentOrchestratorHollowRun, ErrorCodes.AgentOrchestratorSinkInvariant, ErrorCodes.GatewayMintRefused, ErrorCodes.GatewayMintFailed, ErrorCodes.SettingsUnfixableConflict, ErrorCodes.InternalUnhandled;
|
|
66
66
|
//#endregion
|
|
67
|
-
//#region src/
|
|
67
|
+
//#region src/shared/errors/wizard-error.ts
|
|
68
|
+
/**
|
|
69
|
+
* Structured error data for analytics and the machine-readable error line.
|
|
70
|
+
*
|
|
71
|
+
* A data carrier: the agent returns it inside a failure and the legacy adapter
|
|
72
|
+
* hands it to `wizardAbort()`, which captures it. Never thrown by the wizard.
|
|
73
|
+
*/
|
|
74
|
+
var WizardError = class extends Error {
|
|
75
|
+
code;
|
|
76
|
+
constructor(message, context, code) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.context = context;
|
|
79
|
+
this.name = "WizardError";
|
|
80
|
+
this.code = code;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/shared/errors/auth.ts
|
|
68
85
|
function classifyAuthFailure(input) {
|
|
69
86
|
if (input.sessionExpired) return ErrorCodes.AuthSessionExpired;
|
|
70
87
|
if (input.usingManagedLogin) return ErrorCodes.AuthStoredLoginConflict;
|
|
@@ -75,7 +92,7 @@ function classifyAuthFailure(input) {
|
|
|
75
92
|
return ErrorCodes.AuthInvalidOrExpired;
|
|
76
93
|
}
|
|
77
94
|
//#endregion
|
|
78
|
-
//#region src/
|
|
95
|
+
//#region src/agent/signals.ts
|
|
79
96
|
/**
|
|
80
97
|
* Agent signal vocabulary — the marker strings the agent emits and the error
|
|
81
98
|
* taxonomy the runner returns. Kept as a dependency-free leaf module so both
|
|
@@ -105,7 +122,7 @@ const REMARK_INSTRUCTION = `Reply with a single line that starts with ${AgentSig
|
|
|
105
122
|
*/
|
|
106
123
|
const RESUME_INSTRUCTION = "Your previous request failed with a transient gateway authentication error that has since been fixed. Continue the task from where you left off.";
|
|
107
124
|
//#endregion
|
|
108
|
-
//#region src/
|
|
125
|
+
//#region src/shared/errors/agent-map.ts
|
|
109
126
|
const AGENT_ERROR_CODE = {
|
|
110
127
|
["WIZARD_AGENTIC_DETECTION_TIMEOUT"]: ErrorCodes.AgenticDetectionTimeout,
|
|
111
128
|
["WIZARD_MCP_MISSING"]: ErrorCodes.AgentMcpMissing,
|
|
@@ -118,31 +135,7 @@ const AGENT_ERROR_CODE = {
|
|
|
118
135
|
["WIZARD_INCOMPLETE_TASKS"]: ErrorCodes.AgentIncompleteTasks
|
|
119
136
|
};
|
|
120
137
|
//#endregion
|
|
121
|
-
//#region src/
|
|
122
|
-
const DETECT_CODES = {
|
|
123
|
-
"bad-directory": ErrorCodes.DetectBadDirectory,
|
|
124
|
-
"unsupported-platform": ErrorCodes.DetectUnsupportedPlatform,
|
|
125
|
-
"no-project-files": ErrorCodes.DetectNoProjectFiles,
|
|
126
|
-
"no-sources": ErrorCodes.DetectNoSources,
|
|
127
|
-
"no-package-json": ErrorCodes.DetectNoPackageJson,
|
|
128
|
-
"no-sdks": ErrorCodes.DetectNoSdks,
|
|
129
|
-
"missing-stripe": ErrorCodes.DetectMissingStripe,
|
|
130
|
-
"no-posthog-sdk": ErrorCodes.DetectNoPosthogSdk,
|
|
131
|
-
"no-posthog": ErrorCodes.DetectNoPosthogSdk,
|
|
132
|
-
"missing-posthog": ErrorCodes.DetectNoPosthogSdk
|
|
133
|
-
};
|
|
134
|
-
/**
|
|
135
|
-
* `kind` arrives as a bare string — `frameworkContext.detectError` is untyped
|
|
136
|
-
* storage — so the lookup can still miss. It falls back to a detect-group code
|
|
137
|
-
* with `retry: 'no'`, never to `InternalUnhandled`: an unrecognized precondition
|
|
138
|
-
* failure is still a precondition failure, and telling a sandbox to retry one
|
|
139
|
-
* costs it the whole budget.
|
|
140
|
-
*/
|
|
141
|
-
function detectErrorCode(kind) {
|
|
142
|
-
return DETECT_CODES[kind] ?? ErrorCodes.DetectUnclassified;
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
145
|
-
//#region src/lib/errors/skill-map.ts
|
|
138
|
+
//#region src/shared/errors/skill-map.ts
|
|
146
139
|
const SKILL_CODES = {
|
|
147
140
|
"menu-fetch-failed": ErrorCodes.SkillMenuFetchFailed,
|
|
148
141
|
"skill-not-found": ErrorCodes.SkillNotFound,
|
|
@@ -153,7 +146,7 @@ function skillErrorCode(result) {
|
|
|
153
146
|
return SKILL_CODES[result.kind];
|
|
154
147
|
}
|
|
155
148
|
//#endregion
|
|
156
|
-
//#region src/
|
|
149
|
+
//#region src/shared/errors/sanitize.ts
|
|
157
150
|
const DETAIL_ALLOWLIST = [
|
|
158
151
|
"reason",
|
|
159
152
|
"detected",
|
|
@@ -166,7 +159,7 @@ function sanitizeErrorDetail(detail) {
|
|
|
166
159
|
return Object.keys(safe).length > 0 ? safe : void 0;
|
|
167
160
|
}
|
|
168
161
|
//#endregion
|
|
169
|
-
//#region src/
|
|
162
|
+
//#region src/shared/errors/run-failure.ts
|
|
170
163
|
/**
|
|
171
164
|
* How a run's terminal error is reported. A coded WizardError (a mint refusal,
|
|
172
165
|
* say) keeps its own message and code; anything else is unhandled and gets the
|
|
@@ -187,6 +180,6 @@ function classifyRunFailure(err) {
|
|
|
187
180
|
};
|
|
188
181
|
}
|
|
189
182
|
//#endregion
|
|
190
|
-
export {
|
|
183
|
+
export { AgentSignals as a, classifyAuthFailure as c, ErrorCodes as d, AGENT_ERROR_CODE as i, WizardError as l, sanitizeErrorDetail as n, REMARK_INSTRUCTION as o, skillErrorCode as r, RESUME_INSTRUCTION as s, classifyRunFailure as t, emitWizardError as u };
|
|
191
184
|
|
|
192
|
-
//# sourceMappingURL=errors-
|
|
185
|
+
//# sourceMappingURL=errors-CQ9kttJD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-CQ9kttJD.js","names":[],"sources":["../src/shared/errors/codes.ts","../src/shared/errors/emit.ts","../src/shared/errors/catalog.ts","../src/shared/errors/wizard-error.ts","../src/shared/errors/auth.ts","../src/agent/signals.ts","../src/shared/errors/agent-map.ts","../src/shared/errors/skill-map.ts","../src/shared/errors/sanitize.ts","../src/shared/errors/run-failure.ts"],"sourcesContent":["export const ErrorCodes = {\n CliNodeVersion: 'PHW_CLI_NODE_VERSION',\n CliBadArgs: 'PHW_CLI_BAD_ARGS',\n CliFlagUnavailable: 'PHW_CLI_FLAG_UNAVAILABLE',\n CliInteractiveRequired: 'PHW_CLI_INTERACTIVE_REQUIRED',\n ArgsMissingApiKey: 'PHW_ARGS_MISSING_API_KEY',\n ArgsMissingInstallDir: 'PHW_ARGS_MISSING_INSTALL_DIR',\n ArgsMissingEmail: 'PHW_ARGS_MISSING_EMAIL',\n ArgsSignupProvisionFailed: 'PHW_ARGS_SIGNUP_PROVISION_FAILED',\n AuthKeyType: 'PHW_AUTH_KEY_TYPE',\n AuthMissingScope: 'PHW_AUTH_MISSING_SCOPE',\n AuthRegionMismatch: 'PHW_AUTH_REGION_MISMATCH',\n AuthInvalidOrExpired: 'PHW_AUTH_INVALID_OR_EXPIRED',\n /** The OAuth grant itself is gone — distinct from a merely expired token. */\n AuthSessionExpired: 'PHW_AUTH_SESSION_EXPIRED',\n AuthSettingsConflict: 'PHW_AUTH_SETTINGS_CONFLICT',\n AuthStoredLoginConflict: 'PHW_AUTH_STORED_LOGIN_CONFLICT',\n AuthProjectFetchFailed: 'PHW_AUTH_PROJECT_FETCH_FAILED',\n EnvLocalServicesDown: 'PHW_ENV_LOCAL_SERVICES_DOWN',\n EnvServiceOutage: 'PHW_ENV_SERVICE_OUTAGE',\n DetectBadDirectory: 'PHW_DETECT_BAD_DIRECTORY',\n DetectNoFramework: 'PHW_DETECT_NO_FRAMEWORK',\n DetectUnsupportedVersion: 'PHW_DETECT_UNSUPPORTED_VERSION',\n DetectUnsupportedPlatform: 'PHW_DETECT_UNSUPPORTED_PLATFORM',\n DetectNoPosthogSdk: 'PHW_DETECT_NO_POSTHOG_SDK',\n DetectNoProjectFiles: 'PHW_DETECT_NO_PROJECT_FILES',\n DetectNoSources: 'PHW_DETECT_NO_SOURCES',\n DetectNoPackageJson: 'PHW_DETECT_NO_PACKAGE_JSON',\n DetectNoSdks: 'PHW_DETECT_NO_SDKS',\n DetectMissingStripe: 'PHW_DETECT_MISSING_STRIPE',\n DetectUnclassified: 'PHW_DETECT_UNCLASSIFIED',\n SkillMenuFetchFailed: 'PHW_SKILL_MENU_FETCH_FAILED',\n SkillNotFound: 'PHW_SKILL_NOT_FOUND',\n SkillDownloadFailed: 'PHW_SKILL_DOWNLOAD_FAILED',\n AgentAbort: 'PHW_AGENT_ABORT',\n AgenticDetectionTimeout: 'PHW_AGENTIC_DETECTION_TIMEOUT',\n AgentMcpMissing: 'PHW_AGENT_MCP_MISSING',\n AgentResourceMissing: 'PHW_AGENT_RESOURCE_MISSING',\n AgentRateLimit: 'PHW_AGENT_RATE_LIMIT',\n AgentApiError: 'PHW_AGENT_API_ERROR',\n AgentYaraViolation: 'PHW_AGENT_YARA_VIOLATION',\n AgentNoProgress: 'PHW_AGENT_NO_PROGRESS',\n AgentIncompleteTasks: 'PHW_AGENT_INCOMPLETE_TASKS',\n AgentOrchestratorSkillVariantMissing:\n 'PHW_AGENT_ORCHESTRATOR_SKILL_VARIANT_MISSING',\n AgentOrchestratorTasksFailed: 'PHW_AGENT_ORCHESTRATOR_TASKS_FAILED',\n AgentOrchestratorHollowRun: 'PHW_AGENT_ORCHESTRATOR_HOLLOW_RUN',\n AgentOrchestratorSinkInvariant: 'PHW_AGENT_ORCHESTRATOR_SINK_INVARIANT',\n /** The backend answered the mint with a deliberate refusal. */\n GatewayMintRefused: 'PHW_GATEWAY_MINT_REFUSED',\n /** The mint was unreachable, errored, or returned an unusable token. */\n GatewayMintFailed: 'PHW_GATEWAY_MINT_FAILED',\n SettingsUnfixableConflict: 'PHW_SETTINGS_UNFIXABLE_CONFLICT',\n InternalUnhandled: 'PHW_INTERNAL_UNHANDLED',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\nexport const ERROR_CODE_PATTERN = /^PHW_[A-Z][A-Z0-9_]*$/;\n\nexport function isErrorCode(value: string): value is ErrorCode {\n return (Object.values(ErrorCodes) as string[]).includes(value);\n}\n","import type { ErrorCode } from './codes';\n\nexport const PHW_ERROR_PREFIX = 'phw-error:';\n\nexport interface WizardErrorLine {\n code: ErrorCode;\n message: string;\n detail?: Record<string, unknown>;\n}\n\nexport function formatWizardErrorLine(line: WizardErrorLine): string {\n return `${PHW_ERROR_PREFIX} ${JSON.stringify(line)}`;\n}\n\nexport function emitWizardError(line: WizardErrorLine): void {\n process.stderr.write(`${formatWizardErrorLine(line)}\\n`);\n}\n","import { ErrorCodes, type ErrorCode } from './codes';\nimport type { ErrorCatalogEntry } from './types';\n\nexport const ERROR_CATALOG: Record<ErrorCode, ErrorCatalogEntry> = {\n [ErrorCodes.CliNodeVersion]: {\n group: 'cli',\n retry: 'no',\n description: 'Node.js runtime is older than the required range.',\n },\n [ErrorCodes.CliBadArgs]: {\n group: 'cli',\n retry: 'no',\n description: 'Unrecognized command or option.',\n },\n [ErrorCodes.CliFlagUnavailable]: {\n group: 'cli',\n retry: 'no',\n description: 'A dev-only flag or env var was passed to a published build.',\n },\n [ErrorCodes.CliInteractiveRequired]: {\n group: 'cli',\n retry: 'no',\n description:\n 'The command requires an interactive terminal and has no non-interactive fallback.',\n },\n [ErrorCodes.ArgsMissingApiKey]: {\n group: 'args',\n retry: 'no',\n description: 'Non-interactive run without --api-key.',\n },\n [ErrorCodes.ArgsMissingInstallDir]: {\n group: 'args',\n retry: 'no',\n description: 'Non-interactive run without --install-dir.',\n },\n [ErrorCodes.ArgsMissingEmail]: {\n group: 'args',\n retry: 'no',\n description: 'Signup run without --email.',\n },\n [ErrorCodes.ArgsSignupProvisionFailed]: {\n group: 'args',\n retry: 'yes',\n description: 'Account provisioning for --signup failed.',\n },\n [ErrorCodes.AuthKeyType]: {\n group: 'auth',\n retry: 'no',\n description: 'The API key has the wrong type or prefix for this mode.',\n },\n [ErrorCodes.AuthInvalidOrExpired]: {\n group: 'auth',\n retry: 'no',\n description: 'The credential was rejected by the LLM gateway or API.',\n },\n [ErrorCodes.AuthSessionExpired]: {\n group: 'auth',\n // Retryable, unlike its neighbours: a new run means a new login.\n retry: 'yes',\n description: 'The OAuth grant expired or was revoked mid-run.',\n },\n [ErrorCodes.AuthMissingScope]: {\n group: 'auth',\n retry: 'no',\n description: 'The personal API key lacks a scope the run requires.',\n },\n [ErrorCodes.AuthRegionMismatch]: {\n group: 'auth',\n retry: 'no',\n description: 'The resolved region does not match the credential.',\n },\n [ErrorCodes.AuthSettingsConflict]: {\n group: 'auth',\n retry: 'no',\n description: 'A Claude settings file overrides the gateway credential.',\n },\n [ErrorCodes.AuthStoredLoginConflict]: {\n group: 'auth',\n retry: 'no',\n description:\n 'The agent SDK used a stored Claude login instead of the gateway token.',\n },\n [ErrorCodes.AuthProjectFetchFailed]: {\n group: 'auth',\n retry: 'yes',\n description: 'Fetching user or project data from the PostHog API failed.',\n },\n [ErrorCodes.EnvLocalServicesDown]: {\n group: 'env',\n retry: 'yes',\n description: 'A local dev target service is not running.',\n },\n [ErrorCodes.EnvServiceOutage]: {\n group: 'env',\n retry: 'yes',\n description: 'Blocking external services are down.',\n },\n [ErrorCodes.DetectBadDirectory]: {\n group: 'detect',\n retry: 'no',\n description:\n 'The install directory is missing, not a directory, or unreadable.',\n },\n [ErrorCodes.DetectNoFramework]: {\n group: 'detect',\n retry: 'no',\n description: 'Framework auto-detection found no supported framework.',\n },\n [ErrorCodes.DetectUnsupportedVersion]: {\n group: 'detect',\n retry: 'no',\n description:\n 'The detected framework version is below the supported minimum.',\n },\n [ErrorCodes.DetectUnsupportedPlatform]: {\n group: 'detect',\n retry: 'no',\n description: 'The project platform has no matching skill variant.',\n },\n [ErrorCodes.DetectNoPosthogSdk]: {\n group: 'detect',\n retry: 'no',\n description:\n 'The program requires an installed PostHog SDK and none was found.',\n },\n [ErrorCodes.DetectNoProjectFiles]: {\n group: 'detect',\n retry: 'no',\n description: 'The project has no files for the program to work on.',\n },\n [ErrorCodes.DetectNoSources]: {\n group: 'detect',\n retry: 'no',\n description: 'No data warehouse sources were found.',\n },\n [ErrorCodes.DetectNoPackageJson]: {\n group: 'detect',\n retry: 'no',\n description: 'The project has no package.json for the program to scan.',\n },\n [ErrorCodes.DetectNoSdks]: {\n group: 'detect',\n retry: 'no',\n description: 'None of the SDKs the program needs are installed.',\n },\n [ErrorCodes.DetectMissingStripe]: {\n group: 'detect',\n retry: 'no',\n description: 'Revenue analytics requires a Stripe SDK and none was found.',\n },\n [ErrorCodes.DetectUnclassified]: {\n group: 'detect',\n // A detect step reported a precondition failure we have no code for yet.\n // Every known cause is a property of the user's project, so retrying can\n // only burn budget — fail closed rather than inheriting `internal`'s 'yes'.\n retry: 'no',\n description: 'A detect step failed with a kind absent from the catalog.',\n },\n [ErrorCodes.SkillMenuFetchFailed]: {\n group: 'skill',\n retry: 'yes',\n description: 'The context-mill skill menu could not be fetched.',\n },\n [ErrorCodes.SkillNotFound]: {\n group: 'skill',\n retry: 'no',\n description: 'The skill id is absent from the context-mill menu.',\n },\n [ErrorCodes.SkillDownloadFailed]: {\n group: 'skill',\n retry: 'yes',\n description: 'The skill download or extraction failed.',\n },\n [ErrorCodes.AgentAbort]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The agent emitted an [ABORT] signal with a reason.',\n },\n [ErrorCodes.AgenticDetectionTimeout]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent run exceeded its configured time limit.',\n },\n [ErrorCodes.AgentMcpMissing]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent could not reach the PostHog MCP server.',\n },\n [ErrorCodes.AgentResourceMissing]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent could not access a setup resource.',\n },\n [ErrorCodes.AgentRateLimit]: {\n group: 'agent',\n retry: 'yes',\n description: 'The LLM gateway rate-limited the run.',\n },\n [ErrorCodes.AgentApiError]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent hit an API error other than a rate limit.',\n },\n [ErrorCodes.AgentYaraViolation]: {\n group: 'agent',\n retry: 'no',\n description: 'The security scanner terminated the run.',\n },\n [ErrorCodes.AgentNoProgress]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The agent ended without a single tool call.',\n },\n [ErrorCodes.AgentIncompleteTasks]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The agent stopped with planned tasks still open.',\n },\n [ErrorCodes.AgentOrchestratorSkillVariantMissing]: {\n group: 'agent',\n retry: 'yes',\n description: 'The orchestrator could not download a needed skill variant.',\n },\n [ErrorCodes.AgentOrchestratorTasksFailed]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The orchestrator queue drained with failed or blocked tasks.',\n },\n [ErrorCodes.AgentOrchestratorHollowRun]: {\n group: 'agent',\n retry: 'yes',\n description:\n 'The orchestrator drained with zero tasks — the seed step got no usable model output.',\n },\n [ErrorCodes.AgentOrchestratorSinkInvariant]: {\n group: 'agent',\n retry: 'no',\n description: 'The orchestrator plan failed the sink coverage invariant.',\n },\n [ErrorCodes.GatewayMintRefused]: {\n group: 'gateway',\n // 429 clears with the daily window, 401 with a fresh login, 403 never.\n retry: 'case-by-case',\n description:\n 'The PostHog backend refused to mint a gateway token for this run.',\n },\n [ErrorCodes.GatewayMintFailed]: {\n group: 'gateway',\n retry: 'yes',\n description:\n 'The PostHog backend could not mint a gateway token: unreachable, a 5xx, or an unusable response.',\n },\n [ErrorCodes.SettingsUnfixableConflict]: {\n group: 'settings',\n retry: 'no',\n description:\n 'A Claude settings conflict cannot be neutralized automatically.',\n },\n [ErrorCodes.InternalUnhandled]: {\n group: 'internal',\n retry: 'yes',\n description: 'An unexpected error escaped the pipeline.',\n },\n};\n","import type { ErrorCode } from './codes';\n\n/**\n * Structured error data for analytics and the machine-readable error line.\n *\n * A data carrier: the agent returns it inside a failure and the legacy adapter\n * hands it to `wizardAbort()`, which captures it. Never thrown by the wizard.\n */\nexport class WizardError extends Error {\n readonly code?: ErrorCode;\n\n constructor(\n message: string,\n public readonly context?: Record<string, unknown>,\n code?: ErrorCode,\n ) {\n super(message);\n this.name = 'WizardError';\n this.code = code;\n }\n}\n","import { ErrorCodes, type ErrorCode } from './codes';\n\nexport interface AuthFailureInput {\n hasSettingsConflict?: boolean;\n usingManagedLogin?: boolean;\n /** A pre-run token refresh already failed on a dead grant this run. */\n sessionExpired?: boolean;\n apiKey?: string;\n missingScopes?: readonly string[];\n gatewayRegion?: 'us' | 'eu' | 'local';\n sessionRegion?: 'us' | 'eu';\n}\n\nexport function classifyAuthFailure(input: AuthFailureInput): ErrorCode {\n // First: the only branch backed by a server verdict rather than inference.\n // The token endpoint already told us the grant is dead, so every heuristic\n // below would be guessing at a cause we know.\n if (input.sessionExpired) return ErrorCodes.AuthSessionExpired;\n if (input.usingManagedLogin) return ErrorCodes.AuthStoredLoginConflict;\n if (input.hasSettingsConflict) return ErrorCodes.AuthSettingsConflict;\n if (\n input.apiKey &&\n !input.apiKey.startsWith('phx_') &&\n !input.apiKey.startsWith('pha_')\n ) {\n return ErrorCodes.AuthKeyType;\n }\n if (input.missingScopes && input.missingScopes.length > 0) {\n return ErrorCodes.AuthMissingScope;\n }\n if (\n input.gatewayRegion &&\n input.sessionRegion &&\n input.gatewayRegion !== 'local' &&\n input.gatewayRegion !== input.sessionRegion\n ) {\n return ErrorCodes.AuthRegionMismatch;\n }\n return ErrorCodes.AuthInvalidOrExpired;\n}\n","/**\n * Agent signal vocabulary — the marker strings the agent emits and the error\n * taxonomy the runner returns. Kept as a dependency-free leaf module so both\n * `agent-interface.ts` and `output-signals.ts` can import it without a cycle.\n */\n\nexport const AgentSignals = {\n /** Signal emitted when the agent reports progress to the user */\n STATUS: '[STATUS]',\n /** Signal emitted when the agent cannot access the PostHog MCP server */\n ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',\n /** Signal emitted when the agent cannot access the setup resource */\n ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',\n /**\n * Signal emitted when `install_skill` failed and the agent is continuing\n * the integration WITHOUT the skill (best-effort from its own knowledge).\n * Format: \"[SKILL-INSTALL-FAILED] <skill id — reason>\". Non-fatal by\n * design: a freestyled integration beats an outright failure, but the run\n * must be measurable — the runner captures it as an analytics event.\n */\n SKILL_INSTALL_FAILED: '[SKILL-INSTALL-FAILED]',\n /**\n * Signal emitted when the agent cannot complete the program and is\n * aborting intentionally (distinct from errors). Format: \"[ABORT] <reason>\".\n * Programs can declare an onAbort handler to render a custom screen.\n */\n ABORT: '[ABORT]',\n /** Signal emitted when the agent provides a remark about its run */\n WIZARD_REMARK: '[WIZARD-REMARK]',\n /** Signal prefix for benchmark logging */\n BENCHMARK: '[BENCHMARK]',\n /**\n * Signal emitted when the agent has created a PostHog dashboard for the\n * user. Format: `[DASHBOARD_URL] <full https url>`. The URL is captured\n * onto `session.dashboardUrl` and surfaced by programs in their outro.\n */\n DASHBOARD_URL: '[DASHBOARD_URL]',\n /**\n * Signal emitted when the agent has uploaded a report to a PostHog\n * notebook. Format: `[NOTEBOOK_URL] <full https url>`. The URL is captured\n * onto `session.notebookUrl` and surfaced by programs in their outro.\n */\n NOTEBOOK_URL: '[NOTEBOOK_URL]',\n} as const;\n\nexport type AgentSignal = (typeof AgentSignals)[keyof typeof AgentSignals];\n\n/**\n * End-of-run reflection ask, shared by both harnesses so remarks are\n * comparable. The format clause comes FIRST and nothing trails the marker —\n * literal models (gpt-5-mini) echo whatever text follows it. The parser also\n * drops remarks that quote this instruction (see AgentOutputSignals.remark).\n */\nexport const REMARK_INSTRUCTION = `Reply with a single line that starts with ${AgentSignals.WIZARD_REMARK} and no other lines. In that line, state briefly what information or guidance would have been useful to have in the integration prompt or documentation for this run — specifically anything that would have prevented tool failures, erroneous edits, or other wasted turns.`;\n\n/**\n * First prompt of a session resumed after a mid-run re-mint. The transcript\n * carries the work so far; the model only needs to pick it up.\n */\nexport const RESUME_INSTRUCTION =\n 'Your previous request failed with a transient gateway authentication error that has since been fixed. Continue the task from where you left off.';\n\n/**\n * Error types that can be returned from agent execution.\n * These correspond to the error signals that the agent emits.\n */\nexport enum AgentErrorType {\n /** The configured run deadline elapsed and the SDK query was aborted */\n AGENTIC_DETECTION_TIMEOUT = 'WIZARD_AGENTIC_DETECTION_TIMEOUT',\n /** Agent could not access the PostHog MCP server */\n MCP_MISSING = 'WIZARD_MCP_MISSING',\n /** Agent could not access the setup resource */\n RESOURCE_MISSING = 'WIZARD_RESOURCE_MISSING',\n /** API rate limit exceeded */\n RATE_LIMIT = 'WIZARD_RATE_LIMIT',\n /** Generic API error */\n API_ERROR = 'WIZARD_API_ERROR',\n /** YARA scanner detected a security violation */\n YARA_VIOLATION = 'WIZARD_YARA_VIOLATION',\n /** Agent intentionally aborted the program (emitted [ABORT] <reason>) */\n ABORT = 'WIZARD_ABORT',\n /** Agent ended without making a single tool call — a no-op run that did no work */\n NO_PROGRESS = 'WIZARD_NO_PROGRESS',\n /** Agent acted but stopped short — planned tasks left open and/or no skill installed */\n INCOMPLETE_TASKS = 'WIZARD_INCOMPLETE_TASKS',\n}\n","// Leaf module on purpose: every module imports the errors, so the agent entry\n// would form a module cycle here.\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports -- B1: error codes move next to their owners\nimport { AgentErrorType } from '@agent/signals';\nimport { ErrorCodes, type ErrorCode } from './codes';\n\nexport const AGENT_ERROR_CODE: Record<AgentErrorType, ErrorCode> = {\n [AgentErrorType.AGENTIC_DETECTION_TIMEOUT]:\n ErrorCodes.AgenticDetectionTimeout,\n [AgentErrorType.MCP_MISSING]: ErrorCodes.AgentMcpMissing,\n [AgentErrorType.RESOURCE_MISSING]: ErrorCodes.AgentResourceMissing,\n [AgentErrorType.RATE_LIMIT]: ErrorCodes.AgentRateLimit,\n [AgentErrorType.API_ERROR]: ErrorCodes.AgentApiError,\n [AgentErrorType.YARA_VIOLATION]: ErrorCodes.AgentYaraViolation,\n [AgentErrorType.ABORT]: ErrorCodes.AgentAbort,\n [AgentErrorType.NO_PROGRESS]: ErrorCodes.AgentNoProgress,\n [AgentErrorType.INCOMPLETE_TASKS]: ErrorCodes.AgentIncompleteTasks,\n};\n","import { ErrorCodes, type ErrorCode } from './codes';\nimport type { InstallSkillResult } from '@agent/types';\n\nconst SKILL_CODES: Record<\n Exclude<InstallSkillResult['kind'], 'ok'>,\n ErrorCode\n> = {\n 'menu-fetch-failed': ErrorCodes.SkillMenuFetchFailed,\n 'skill-not-found': ErrorCodes.SkillNotFound,\n 'download-failed': ErrorCodes.SkillDownloadFailed,\n};\n\nexport function skillErrorCode(result: InstallSkillResult): ErrorCode | null {\n if (result.kind === 'ok') return null;\n return SKILL_CODES[result.kind];\n}\n","const DETAIL_ALLOWLIST = ['reason', 'detected', 'platform'] as const;\n\nexport function sanitizeErrorDetail(\n detail: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!detail) return undefined;\n const safe: Record<string, unknown> = {};\n for (const key of DETAIL_ALLOWLIST) {\n if (detail[key] !== undefined) safe[key] = detail[key];\n }\n return Object.keys(safe).length > 0 ? safe : undefined;\n}\n","import { ErrorCodes, isErrorCode, type ErrorCode } from './codes';\n\nexport interface RunFailure {\n code: ErrorCode;\n message: string;\n /** True when the error carried its own code: a decision, not a crash. */\n coded: boolean;\n}\n\n/**\n * How a run's terminal error is reported. A coded WizardError (a mint refusal,\n * say) keeps its own message and code; anything else is unhandled and gets the\n * generic framing. Duck-typed on `code` so callers need not load wizard-abort.\n */\nexport function classifyRunFailure(err: unknown): RunFailure {\n const message = err instanceof Error ? err.message : String(err);\n const code =\n err instanceof Error ? (err as { code?: unknown }).code : undefined;\n if (typeof code === 'string' && isErrorCode(code)) {\n return { code, message, coded: true };\n }\n return { code: ErrorCodes.InternalUnhandled, message, coded: false };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as WIZARD_TASK_STREAM_FILE, s as logToFile } from "./debug-Ch4BDOtD.js";
|
|
2
2
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
3
|
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/lib/task-stream/destinations/file.ts
|
|
@@ -57,4 +57,4 @@ function createFileDestination(value, opts = {}) {
|
|
|
57
57
|
//#endregion
|
|
58
58
|
export { FileDestination, createFileDestination };
|
|
59
59
|
|
|
60
|
-
//# sourceMappingURL=file-
|
|
60
|
+
//# sourceMappingURL=file-BcLTjU16.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-
|
|
1
|
+
{"version":3,"file":"file-BcLTjU16.js","names":[],"sources":["../src/lib/task-stream/destinations/file.ts"],"sourcesContent":["/**\n * Dumps every *attempted* sync to a local JSONL file, one line per push. A line\n * means the run published that payload, not that a backend accepted it — `--ci`\n * swaps the PostHog destination for this one, so a synthetic run never creates a\n * session row in a real project.\n *\n * Dev builds only: the payload holds the run's handoff report.\n */\n\nimport { appendFileSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { IS_PRODUCTION_BUILD } from '@env';\nimport { WIZARD_TASK_STREAM_FILE } from '@utils/paths';\nimport { logToFile } from '@utils/debug';\nimport type {\n StreamEvent,\n TaskStreamDestination,\n TaskStreamUpdate,\n} from '@lib/task-stream/types';\n\nexport interface FileDestinationOptions {\n path: string;\n /** Override for tests. */\n now?: () => string;\n}\n\nexport class FileDestination implements TaskStreamDestination {\n readonly name = 'file';\n readonly path: string;\n\n private readonly now: () => string;\n private disabled = false;\n\n constructor(opts: FileDestinationOptions) {\n this.path = opts.path;\n this.now = opts.now ?? (() => new Date().toISOString());\n // Truncate up front: one run, one file.\n this.write(() => writeFileSync(this.path, '', { mode: 0o600 }));\n }\n\n send(event: StreamEvent, payload: TaskStreamUpdate): Promise<void> {\n if (!this.disabled) {\n const line = `${JSON.stringify({ at: this.now(), event, payload })}\\n`;\n this.write(() => appendFileSync(this.path, line, { mode: 0o600 }));\n }\n return Promise.resolve();\n }\n\n /** Never throws, never writes to stdio; the first failure ends the dump. */\n private write(op: () => void): void {\n try {\n mkdirSync(dirname(this.path), { recursive: true });\n op();\n } catch (err) {\n this.disabled = true;\n logToFile(\n `[task-stream] file destination disabled (${\n err instanceof Error ? err.message : String(err)\n }): ${this.path}`,\n );\n }\n }\n}\n\n/**\n * Resolve a `--task-stream-log` value, or null when the run did not ask for a\n * dump. `''` and `true` mean the default path — how `--ci` asks for one.\n */\nexport function createFileDestination(\n value: unknown,\n opts: { productionBuild?: boolean; cwd?: string } = {},\n): FileDestination | null {\n if (opts.productionBuild ?? IS_PRODUCTION_BUILD) return null;\n if (value === undefined || value === null || value === false) return null;\n\n const raw = typeof value === 'string' ? value.trim() : '';\n const path =\n raw === ''\n ? WIZARD_TASK_STREAM_FILE\n : isAbsolute(raw)\n ? raw\n : resolve(opts.cwd ?? process.cwd(), raw);\n\n logToFile(`[task-stream] file destination enabled: ${path}`);\n return new FileDestination({ path });\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,IAAa,kBAAb,MAA8D;CAC5D,OAAgB;CAChB;CAEA;CACA,WAAmB;CAEnB,YAAY,MAA8B;AACxC,OAAK,OAAO,KAAK;AACjB,OAAK,MAAM,KAAK,+BAAc,IAAI,MAAM,EAAC,aAAa;AAEtD,OAAK,YAAY,cAAc,KAAK,MAAM,IAAI,EAAE,MAAM,KAAO,CAAC,CAAC;;CAGjE,KAAK,OAAoB,SAA0C;AACjE,MAAI,CAAC,KAAK,UAAU;GAClB,MAAM,OAAO,GAAG,KAAK,UAAU;IAAE,IAAI,KAAK,KAAK;IAAE;IAAO;IAAS,CAAC,CAAC;AACnE,QAAK,YAAY,eAAe,KAAK,MAAM,MAAM,EAAE,MAAM,KAAO,CAAC,CAAC;;AAEpE,SAAO,QAAQ,SAAS;;;CAI1B,MAAc,IAAsB;AAClC,MAAI;AACF,aAAU,QAAQ,KAAK,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAClD,OAAI;WACG,KAAK;AACZ,QAAK,WAAW;AAChB,aACE,4CACE,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACjD,KAAK,KAAK,OACZ;;;;;;;;AASP,SAAgB,sBACd,OACA,OAAoD,EAAE,EAC9B;AACxB,KAAI,KAAK,mBAAA,KAAwC,QAAO;AACxD,KAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,MAAO,QAAO;CAErE,MAAM,MAAM,OAAO,UAAU,WAAW,MAAM,MAAM,GAAG;CACvD,MAAM,OACJ,QAAQ,KACJ,0BACA,WAAW,IAAI,GACf,MACA,QAAQ,KAAK,OAAO,QAAQ,KAAK,EAAE,IAAI;AAE7C,WAAU,2CAA2C,OAAO;AAC5D,QAAO,IAAI,gBAAgB,EAAE,MAAM,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as logToFile } from "./debug-
|
|
1
|
+
import { s as logToFile } from "./debug-Ch4BDOtD.js";
|
|
2
2
|
import * as fs$1 from "fs";
|
|
3
3
|
import { basename, dirname } from "node:path";
|
|
4
4
|
//#region src/lib/file-watcher.ts
|
|
@@ -120,4 +120,4 @@ function startFileWatcher(path, onUpdate, options = {}) {
|
|
|
120
120
|
//#endregion
|
|
121
121
|
export { startFileWatcher as t };
|
|
122
122
|
|
|
123
|
-
//# sourceMappingURL=file-watcher-
|
|
123
|
+
//# sourceMappingURL=file-watcher-DWc_bTs6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-watcher-
|
|
1
|
+
{"version":3,"file":"file-watcher-DWc_bTs6.js","names":["fs"],"sources":["../src/lib/file-watcher.ts"],"sourcesContent":["/**\n * JSON file watcher shared by runner and UI machinery.\n *\n * `fs.watch` alone is unreliable for atomic-rename writes, so the watcher\n * pairs it with a continuous mtime-polled re-read. The poll catches missed\n * events; the watch keeps latency low when it does fire.\n */\n\nimport * as fs from 'fs';\nimport { basename, dirname } from 'node:path';\nimport { logToFile } from '@utils/debug';\n\nconst DEFAULT_POLL_INTERVAL_MS = 5000;\nconst DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1000;\nconst DEFAULT_WATCH_DEBOUNCE_MS = 25;\n\nexport interface FileWatcherHandle {\n refresh(): void;\n stop(): void;\n}\n\nexport interface FileWatcherOptions {\n /** ms between mtime checks once the file exists. */\n pollIntervalMs?: number;\n /** ms between attach attempts while waiting for the file to appear. */\n attachRetryIntervalMs?: number;\n /** ms to coalesce duplicate filesystem events. */\n watchDebounceMs?: number;\n /** Ignore the file that exists when the watcher starts until it changes. */\n ignoreInitialFile?: boolean;\n /** Refuse to read files larger than this many bytes. */\n maxFileSizeBytes?: number;\n}\n\n/** Watch `path` for JSON updates and call `onUpdate(parsed)` whenever the\n * file's mtime changes and the contents are valid JSON. Caller must invoke\n * `handle.stop()` to release the watcher. */\nexport function startFileWatcher(\n path: string,\n onUpdate: (parsed: unknown) => void,\n options: FileWatcherOptions = {},\n): FileWatcherHandle {\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const attachRetryIntervalMs =\n options.attachRetryIntervalMs ?? DEFAULT_ATTACH_RETRY_INTERVAL_MS;\n const watchDebounceMs = options.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS;\n\n const watchers: fs.FSWatcher[] = [];\n const intervals: Array<ReturnType<typeof setInterval>> = [];\n const targetDir = dirname(path);\n const targetName = basename(path);\n let lastMtimeMs = 0;\n let ignoredInitialSignature: string | null = null;\n let watchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let lastReadErrorSignature: string | null = null;\n let stopped = false;\n\n const signature = (stat: fs.Stats): string =>\n `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;\n\n if (options.ignoreInitialFile) {\n try {\n const stat = fs.lstatSync(path);\n if (stat.isFile() && !stat.isSymbolicLink()) {\n ignoredInitialSignature = signature(stat);\n }\n } catch {\n // No initial file to ignore.\n }\n }\n\n const logReadError = (errorSignature: string, message: string) => {\n if (lastReadErrorSignature === errorSignature) return;\n lastReadErrorSignature = errorSignature;\n logToFile(`[file-watcher] ${message}: ${path}`);\n };\n\n const read = (force = false) => {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(path);\n } catch {\n return;\n }\n\n if (!stat.isFile() || stat.isSymbolicLink()) return;\n const fileSignature = signature(stat);\n\n try {\n if (ignoredInitialSignature) {\n if (fileSignature === ignoredInitialSignature) return;\n ignoredInitialSignature = null;\n }\n if (\n options.maxFileSizeBytes !== undefined &&\n stat.size > options.maxFileSizeBytes\n ) {\n logReadError(\n `oversized:${fileSignature}`,\n `refusing oversized JSON file (${stat.size} bytes, limit ${options.maxFileSizeBytes} bytes)`,\n );\n return;\n }\n if (!force && stat.mtimeMs === lastMtimeMs) return;\n lastMtimeMs = stat.mtimeMs;\n const parsed: unknown = JSON.parse(fs.readFileSync(path, 'utf-8'));\n lastReadErrorSignature = null;\n onUpdate(parsed);\n } catch (error) {\n logReadError(\n `invalid:${fileSignature}:${String(error)}`,\n `could not read valid JSON (${String(error)})`,\n );\n }\n };\n\n const scheduleRead = () => {\n if (stopped) return;\n if (watchDebounceTimer) clearTimeout(watchDebounceTimer);\n watchDebounceTimer = setTimeout(() => {\n watchDebounceTimer = null;\n read(true);\n }, watchDebounceMs);\n };\n\n const attachWatch = () => {\n watchers.push(\n fs.watch(targetDir, (_eventType, filename) => {\n if (filename == null || filename.toString() === targetName) {\n scheduleRead();\n }\n }),\n );\n };\n\n intervals.push(setInterval(() => read(), pollIntervalMs));\n\n try {\n attachWatch();\n // Defer the initial callback until the caller has received the handle, so\n // callbacks that stop their watcher cannot race handle assignment.\n queueMicrotask(() => {\n if (!stopped) read(true);\n });\n } catch {\n // Parent directory does not exist yet. Polling still covers a later file;\n // retry attaching the low-latency directory watcher until it appears.\n const attachInterval = setInterval(() => {\n try {\n fs.accessSync(targetDir);\n clearInterval(attachInterval);\n const idx = intervals.indexOf(attachInterval);\n if (idx >= 0) intervals.splice(idx, 1);\n attachWatch();\n read(true);\n } catch {\n // Still waiting.\n }\n }, attachRetryIntervalMs);\n intervals.push(attachInterval);\n }\n\n return {\n refresh() {\n if (stopped) return;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n read(true);\n },\n stop() {\n stopped = true;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n for (const watcher of watchers) watcher.close();\n for (const interval of intervals) clearInterval(interval);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,2BAA2B;AACjC,MAAM,mCAAmC;AACzC,MAAM,4BAA4B;;;;AAuBlC,SAAgB,iBACd,MACA,UACA,UAA8B,EAAE,EACb;CACnB,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,wBACJ,QAAQ,yBAAyB;CACnC,MAAM,kBAAkB,QAAQ,mBAAmB;CAEnD,MAAM,WAA2B,EAAE;CACnC,MAAM,YAAmD,EAAE;CAC3D,MAAM,YAAY,QAAQ,KAAK;CAC/B,MAAM,aAAa,SAAS,KAAK;CACjC,IAAI,cAAc;CAClB,IAAI,0BAAyC;CAC7C,IAAI,qBAA2D;CAC/D,IAAI,yBAAwC;CAC5C,IAAI,UAAU;CAEd,MAAM,aAAa,SACjB,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,KAAK,GAAG,KAAK,QAAQ,GAAG,KAAK;AAE/D,KAAI,QAAQ,kBACV,KAAI;EACF,MAAM,OAAOA,KAAG,UAAU,KAAK;AAC/B,MAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,gBAAgB,CACzC,2BAA0B,UAAU,KAAK;SAErC;CAKV,MAAM,gBAAgB,gBAAwB,YAAoB;AAChE,MAAI,2BAA2B,eAAgB;AAC/C,2BAAyB;AACzB,YAAU,kBAAkB,QAAQ,IAAI,OAAO;;CAGjD,MAAM,QAAQ,QAAQ,UAAU;EAC9B,IAAI;AACJ,MAAI;AACF,UAAOA,KAAG,UAAU,KAAK;UACnB;AACN;;AAGF,MAAI,CAAC,KAAK,QAAQ,IAAI,KAAK,gBAAgB,CAAE;EAC7C,MAAM,gBAAgB,UAAU,KAAK;AAErC,MAAI;AACF,OAAI,yBAAyB;AAC3B,QAAI,kBAAkB,wBAAyB;AAC/C,8BAA0B;;AAE5B,OACE,QAAQ,qBAAqB,KAAA,KAC7B,KAAK,OAAO,QAAQ,kBACpB;AACA,iBACE,aAAa,iBACb,iCAAiC,KAAK,KAAK,gBAAgB,QAAQ,iBAAiB,SACrF;AACD;;AAEF,OAAI,CAAC,SAAS,KAAK,YAAY,YAAa;AAC5C,iBAAc,KAAK;GACnB,MAAM,SAAkB,KAAK,MAAMA,KAAG,aAAa,MAAM,QAAQ,CAAC;AAClE,4BAAyB;AACzB,YAAS,OAAO;WACT,OAAO;AACd,gBACE,WAAW,cAAc,GAAG,OAAO,MAAM,IACzC,8BAA8B,OAAO,MAAM,CAAC,GAC7C;;;CAIL,MAAM,qBAAqB;AACzB,MAAI,QAAS;AACb,MAAI,mBAAoB,cAAa,mBAAmB;AACxD,uBAAqB,iBAAiB;AACpC,wBAAqB;AACrB,QAAK,KAAK;KACT,gBAAgB;;CAGrB,MAAM,oBAAoB;AACxB,WAAS,KACPA,KAAG,MAAM,YAAY,YAAY,aAAa;AAC5C,OAAI,YAAY,QAAQ,SAAS,UAAU,KAAK,WAC9C,eAAc;IAEhB,CACH;;AAGH,WAAU,KAAK,kBAAkB,MAAM,EAAE,eAAe,CAAC;AAEzD,KAAI;AACF,eAAa;AAGb,uBAAqB;AACnB,OAAI,CAAC,QAAS,MAAK,KAAK;IACxB;SACI;EAGN,MAAM,iBAAiB,kBAAkB;AACvC,OAAI;AACF,SAAG,WAAW,UAAU;AACxB,kBAAc,eAAe;IAC7B,MAAM,MAAM,UAAU,QAAQ,eAAe;AAC7C,QAAI,OAAO,EAAG,WAAU,OAAO,KAAK,EAAE;AACtC,iBAAa;AACb,SAAK,KAAK;WACJ;KAGP,sBAAsB;AACzB,YAAU,KAAK,eAAe;;AAGhC,QAAO;EACL,UAAU;AACR,OAAI,QAAS;AACb,OAAI,oBAAoB;AACtB,iBAAa,mBAAmB;AAChC,yBAAqB;;AAEvB,QAAK,KAAK;;EAEZ,OAAO;AACL,aAAU;AACV,OAAI,oBAAoB;AACtB,iBAAa,mBAAmB;AAChC,yBAAqB;;AAEvB,QAAK,MAAM,WAAW,SAAU,SAAQ,OAAO;AAC/C,QAAK,MAAM,YAAY,UAAW,eAAc,SAAS;;EAE5D"}
|