@posthog/wizard 2.84.0 → 2.84.1
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/dist/{agent-interface-BNssNetq.js → agent-interface-D8mrarFD.js} +10 -10
- package/dist/{agent-interface-BNssNetq.js.map → agent-interface-D8mrarFD.js.map} +1 -1
- package/dist/{agent-prompt-loader-iV11XVEF.js → agent-prompt-loader-Bt6mrV7q.js} +6 -6
- package/dist/{agent-prompt-loader-iV11XVEF.js.map → agent-prompt-loader-Bt6mrV7q.js.map} +1 -1
- package/dist/{analytics-Drox5LSW.js → analytics-CX2kvq0R.js} +2 -2
- package/dist/{analytics-Drox5LSW.js.map → analytics-CX2kvq0R.js.map} +1 -1
- package/dist/analytics-DgLAjlIK.js +2 -0
- package/dist/{api-Dfu655Qt.js → api-BOP8gF35.js} +2 -2
- package/dist/{api-Dfu655Qt.js.map → api-BOP8gF35.js.map} +1 -1
- package/dist/api-BphZo4f2.js +2 -0
- package/dist/api-key-login-BEi3wymJ.js +2 -0
- package/dist/{api-key-login-BgwfAXfv.js → api-key-login-DbrZknHp.js} +5 -5
- package/dist/{api-key-login-BgwfAXfv.js.map → api-key-login-DbrZknHp.js.map} +1 -1
- package/dist/bin.js +1 -1
- package/dist/{bounded-fs-TRL6IsoU.js → bounded-fs-BENh-Jzc.js} +3 -3
- package/dist/{bounded-fs-TRL6IsoU.js.map → bounded-fs-BENh-Jzc.js.map} +1 -1
- package/dist/{ci-install-nc1IKuX2.js → ci-install-DnjuAl1l.js} +4 -4
- package/dist/{ci-install-nc1IKuX2.js.map → ci-install-DnjuAl1l.js.map} +1 -1
- package/dist/{debug-BfO_Txo8.js → debug-C_9xDg9j.js} +3 -3
- package/dist/{debug-BfO_Txo8.js.map → debug-C_9xDg9j.js.map} +1 -1
- package/dist/{gateway-CLQQb96F.js → gateway-C6_zPLyx.js} +5 -5
- package/dist/{gateway-CLQQb96F.js.map → gateway-C6_zPLyx.js.map} +1 -1
- package/dist/{headless-DMO8N_FD.js → headless-BIQpNAHc.js} +2 -2
- package/dist/{headless-DMO8N_FD.js.map → headless-BIQpNAHc.js.map} +1 -1
- package/dist/{headless-CHGNEzO3.js → headless-sWzDbxAu.js} +1 -1
- package/dist/{host-resolution-DftfSjJD.js → host-resolution-C3ctTKNg.js} +4 -4
- package/dist/{host-resolution-DftfSjJD.js.map → host-resolution-C3ctTKNg.js.map} +1 -1
- package/dist/{install-MWoo1hXL.js → install-CDhljVka.js} +1 -1
- package/dist/{install-C9FPM37m.js → install-Dayhuaun.js} +5 -5
- package/dist/{install-C9FPM37m.js.map → install-Dayhuaun.js.map} +1 -1
- package/dist/{interactive-DOnolJHB.js → interactive-CjbttghI.js} +3 -3
- package/dist/{interactive-DOnolJHB.js.map → interactive-CjbttghI.js.map} +1 -1
- package/dist/{links-CatXPRxH.js → links-BOOGSL_G.js} +3 -3
- package/dist/{links-CatXPRxH.js.map → links-BOOGSL_G.js.map} +1 -1
- package/dist/{main-CINmZtoW.js → main-MzQaWN8w.js} +20 -20
- package/dist/{main-CINmZtoW.js.map → main-MzQaWN8w.js.map} +1 -1
- package/dist/{mcp-KVV6Z_bq.js → mcp-BwlD260T.js} +3 -3
- package/dist/{mcp-KVV6Z_bq.js.map → mcp-BwlD260T.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-M6UnLgGX.js → mcp-prompt-streaming-CoplNPI8.js} +5 -5
- package/dist/{mcp-prompt-streaming-M6UnLgGX.js.map → mcp-prompt-streaming-CoplNPI8.js.map} +1 -1
- package/dist/{models-B0huHItG.js → models-HwzgIr2E.js} +2 -2
- package/dist/{models-B0huHItG.js.map → models-HwzgIr2E.js.map} +1 -1
- package/dist/{oauth-session-9EU3ky0v.js → oauth-session-C4JV-yA9.js} +2 -2
- package/dist/{oauth-session-9EU3ky0v.js.map → oauth-session-C4JV-yA9.js.map} +1 -1
- package/dist/{orchestrator-tools-QWyDLu_7.js → orchestrator-tools-Dr4w80Tn.js} +3 -3
- package/dist/{orchestrator-tools-QWyDLu_7.js.map → orchestrator-tools-Dr4w80Tn.js.map} +1 -1
- package/dist/{package-manager-B-9I_fAT.js → package-manager-Zw0JN1Kh.js} +4 -4
- package/dist/{package-manager-B-9I_fAT.js.map → package-manager-Zw0JN1Kh.js.map} +1 -1
- package/dist/{pi-BSnSk6rv.js → pi-qzRJcTgu.js} +12 -12
- package/dist/{pi-BSnSk6rv.js.map → pi-qzRJcTgu.js.map} +1 -1
- package/dist/{playground-Drz1qszs.js → playground-B0SpcGYQ.js} +4 -4
- package/dist/{playground-Drz1qszs.js.map → playground-B0SpcGYQ.js.map} +1 -1
- package/dist/{posthog-integration-mIQGBc1f.js → posthog-integration-4vQjbU-f.js} +21 -21
- package/dist/{posthog-integration-mIQGBc1f.js.map → posthog-integration-4vQjbU-f.js.map} +1 -1
- package/dist/{programs-mxhRXwP-.js → programs-7aIrstFy.js} +15 -15
- package/dist/{programs-mxhRXwP-.js.map → programs-7aIrstFy.js.map} +1 -1
- package/dist/programs-B9Iu3Mye.js +3 -0
- package/dist/provisioning-BG_lh4hk.js +2 -0
- package/dist/{provisioning-CHUjae9V.js → provisioning-BMJ3J0Vb.js} +4 -4
- package/dist/{provisioning-CHUjae9V.js.map → provisioning-BMJ3J0Vb.js.map} +1 -1
- package/dist/{queue-tools-PFG6H93Q.js → queue-tools-D8HPaGck.js} +4 -4
- package/dist/{queue-tools-PFG6H93Q.js.map → queue-tools-D8HPaGck.js.map} +1 -1
- package/dist/{results-5yCKf2cI.js → results-8xNiBbaP.js} +2 -2
- package/dist/{results-5yCKf2cI.js.map → results-8xNiBbaP.js.map} +1 -1
- package/dist/{run-D5TKJuSL.js → run-DUcJFhzP.js} +7 -7
- package/dist/{run-D5TKJuSL.js.map → run-DUcJFhzP.js.map} +1 -1
- package/dist/{run-W03b6jNM.js → run-Dte7AuRg.js} +10 -10
- package/dist/{run-W03b6jNM.js.map → run-Dte7AuRg.js.map} +1 -1
- package/dist/run-tool-BXpuefYa.js +2 -0
- package/dist/{run-tool-DTQF8mmI.js → run-tool-sdhoPp9H.js} +13 -13
- package/dist/{run-tool-DTQF8mmI.js.map → run-tool-sdhoPp9H.js.map} +1 -1
- package/dist/{runners-B_84kPyf.js → runners-DxbNGuKH.js} +8 -8
- package/dist/{runners-B_84kPyf.js.map → runners-DxbNGuKH.js.map} +1 -1
- package/dist/{security-pApVawYb.js → security-BMqK129i.js} +5 -5
- package/dist/{security-pApVawYb.js.map → security-BMqK129i.js.map} +1 -1
- package/dist/{setup-utils-CQY8PHjR.js → setup-utils-DBOw3lnu.js} +3 -3
- package/dist/{setup-utils-CQY8PHjR.js.map → setup-utils-DBOw3lnu.js.map} +1 -1
- package/dist/{start-playground-DAw1GbLt.js → start-playground-Uf3nte-P.js} +7 -7
- package/dist/{start-playground-DAw1GbLt.js.map → start-playground-Uf3nte-P.js.map} +1 -1
- package/dist/{subagent-YLGSvgoZ.js → subagent-DYza5kN6.js} +3 -3
- package/dist/{subagent-YLGSvgoZ.js.map → subagent-DYza5kN6.js.map} +1 -1
- package/dist/{task-3hRSovmK.js → task-CiStV2CD.js} +14 -14
- package/dist/{task-3hRSovmK.js.map → task-CiStV2CD.js.map} +1 -1
- package/dist/{telemetry-BPBzqsb_.js → telemetry-DLLuQiCt.js} +2 -2
- package/dist/{telemetry-BPBzqsb_.js.map → telemetry-DLLuQiCt.js.map} +1 -1
- package/dist/{terminal-DZsYFbm9.js → terminal-B4EXuZra.js} +18 -18
- package/dist/{terminal-DZsYFbm9.js.map → terminal-B4EXuZra.js.map} +1 -1
- package/dist/{tools-D_AtrhbO.js → tools-BTAi_RrA.js} +13 -13
- package/dist/{tools-D_AtrhbO.js.map → tools-BTAi_RrA.js.map} +1 -1
- package/dist/{tools-DyzRi_dQ.js → tools-M5ENAiPc.js} +8 -8
- package/dist/{tools-DyzRi_dQ.js.map → tools-M5ENAiPc.js.map} +1 -1
- package/dist/{tui-UI6ctBQJ.js → tui-DU9MmsAK.js} +1 -1
- package/dist/{tui-CRp0iCuT.js → tui-DigZ-Q1i.js} +4 -4
- package/dist/{tui-CRp0iCuT.js.map → tui-DigZ-Q1i.js.map} +1 -1
- package/dist/{upload-step-DrYXnpzI.js → upload-step-VNWq-3aL.js} +3 -3
- package/dist/{upload-step-DrYXnpzI.js.map → upload-step-VNWq-3aL.js.map} +1 -1
- package/dist/{urls-WeqfBLP4.js → urls-Bgngk5HI.js} +2 -2
- package/dist/{urls-WeqfBLP4.js.map → urls-Bgngk5HI.js.map} +1 -1
- package/dist/{wizard-abort-BwEefm6P.js → wizard-abort-CdKk1lpi.js} +4 -4
- package/dist/{wizard-abort-BwEefm6P.js.map → wizard-abort-CdKk1lpi.js.map} +1 -1
- package/dist/{yara-hooks-MDtFbuoM.js → yara-hooks-DCgSsXFP.js} +1 -1
- package/dist/{yara-hooks-aDbdsitJ.js → yara-hooks-DPqy6eVo.js} +4 -4
- package/dist/{yara-hooks-aDbdsitJ.js.map → yara-hooks-DPqy6eVo.js.map} +1 -1
- package/package.json +6 -1
- package/dist/analytics-Ix9HEra3.js +0 -2
- package/dist/api-H2UaPgjv.js +0 -2
- package/dist/api-key-login-Cow3UDAN.js +0 -2
- package/dist/programs-Bv0_YHzE.js +0 -3
- package/dist/provisioning-BVsxSNve.js +0 -2
- package/dist/run-tool-DjERhu7G.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-Dfu655Qt.js","names":[],"sources":["../src/shared/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\nimport type { HostResolution } from './host-resolution';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\n/** A pre-issued gateway token and the gateway it's for. */\nexport type GatewayCredential = { token: string; url: string };\n\n/** What a login (or a CI api key) resolves to: the wizard's access to one project. */\nexport interface Credentials {\n accessToken: string;\n /** OAuth refresh token when the grant carried one; absent on CI api-key runs. */\n refreshToken?: string;\n /** Epoch ms when `accessToken` expires — drives the pre-run refresh. */\n expiresAt?: number;\n /** Minting OAuth client when it differs from the default login app (provisioning signups). */\n oauthClientId?: string;\n projectApiKey: string;\n /** Resolved at auth time and immutable thereafter — see {@link HostResolution}. */\n host: HostResolution;\n projectId: number;\n /** A pre-issued gateway token the run uses instead of minting (dev and test `--ci` runs). */\n gateway?: GatewayCredential;\n /**\n * Requested OAuth scopes the grant came back without — deselected on the\n * consent screen or clamped by the app's ceiling. Read when a run fails so\n * the error can name the missing permission and the fix (re-run and grant\n * it during the OAuth flow) instead of the generic report-a-bug line.\n * Empty/absent on CI api-key runs, where there is no scope request to diff\n * against.\n */\n missingScopes?: readonly string[];\n}\n\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\n/**\n * Check whether the project already has a GitHub App integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers (the\n * SelfDrivingGitHubScreen poll) decide how to degrade and are responsible for\n * capturing the error exactly once.\n */\nexport async function fetchGithubConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n // The list is paged, so a project with many integrations could push GitHub off page one.\n params: { kind: 'github' },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'github');\n}\n\n/** One `ph-markdown-notebook` node holding the report, the shape the MCP's `notebooks-create-markdown` stores. */\nconst markdownNotebookBody = (markdown: string) => ({\n content: {\n type: 'doc',\n content: [\n {\n type: 'ph-markdown-notebook',\n attrs: { nodeId: 'markdown-notebook-v2', markdown },\n },\n ],\n },\n text_content: markdown,\n});\n\nconst NotebookResponseSchema = z.object({ version: z.number() }).passthrough();\n\nconst NOTEBOOK_TIMEOUT_MS = 15_000;\n\nconst notebookRequest = (accessToken: string, signal?: AbortSignal) => ({\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: NOTEBOOK_TIMEOUT_MS,\n signal,\n});\n\n/**\n * Create a notebook holding `markdown` under a caller-chosen `shortId`.\n * Requires the `notebook:write` scope. Returns the notebook's version for the\n * next update; throws on failure — the caller decides how to degrade.\n */\nexport async function createMarkdownNotebook(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n notebook: { shortId: string; title: string; markdown: string },\n signal?: AbortSignal,\n): Promise<number> {\n const response = await axios.post(\n `${baseUrl}/api/projects/${projectId}/notebooks/`,\n {\n title: notebook.title,\n short_id: notebook.shortId,\n ...markdownNotebookBody(notebook.markdown),\n },\n notebookRequest(accessToken, signal),\n );\n return NotebookResponseSchema.parse(response.data).version;\n}\n\n/**\n * Replace the markdown of a notebook `createMarkdownNotebook` made. `version`\n * is the one the previous create or update returned. Returns the new version;\n * throws on failure.\n */\nexport async function updateMarkdownNotebook(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n notebook: { shortId: string; markdown: string; version: number },\n signal?: AbortSignal,\n): Promise<number> {\n const response = await axios.patch(\n `${baseUrl}/api/projects/${projectId}/notebooks/${notebook.shortId}/`,\n { ...markdownNotebookBody(notebook.markdown), version: notebook.version },\n notebookRequest(accessToken, signal),\n );\n return NotebookResponseSchema.parse(response.data).version;\n}\n\n/**\n * Read a notebook's current version and markdown by `shortId`, or null when it\n * does not exist. Lets a caller whose create or update lost its response find\n * out whether the write landed.\n */\nexport async function fetchMarkdownNotebook(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n shortId: string,\n signal?: AbortSignal,\n): Promise<{ version: number; markdown: string | undefined } | null> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/notebooks/${shortId}/`,\n notebookRequest(accessToken, signal),\n );\n const notebook = NotebookResponseSchema.parse(response.data);\n const text = (response.data as { text_content?: unknown }).text_content;\n return {\n version: notebook.version,\n markdown: typeof text === 'string' ? text : undefined,\n };\n } catch (error) {\n if (axios.isAxiosError(error) && error.response?.status === 404) {\n return null;\n }\n throw error;\n }\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api-BOP8gF35.js","names":[],"sources":["../src/shared/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\nimport type { HostResolution } from './host-resolution';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\n/** A pre-issued gateway token and the gateway it's for. */\nexport type GatewayCredential = { token: string; url: string };\n\n/** What a login (or a CI api key) resolves to: the wizard's access to one project. */\nexport interface Credentials {\n accessToken: string;\n /** OAuth refresh token when the grant carried one; absent on CI api-key runs. */\n refreshToken?: string;\n /** Epoch ms when `accessToken` expires — drives the pre-run refresh. */\n expiresAt?: number;\n /** Minting OAuth client when it differs from the default login app (provisioning signups). */\n oauthClientId?: string;\n projectApiKey: string;\n /** Resolved at auth time and immutable thereafter — see {@link HostResolution}. */\n host: HostResolution;\n projectId: number;\n /** A pre-issued gateway token the run uses instead of minting (dev and test `--ci` runs). */\n gateway?: GatewayCredential;\n /**\n * Requested OAuth scopes the grant came back without — deselected on the\n * consent screen or clamped by the app's ceiling. Read when a run fails so\n * the error can name the missing permission and the fix (re-run and grant\n * it during the OAuth flow) instead of the generic report-a-bug line.\n * Empty/absent on CI api-key runs, where there is no scope request to diff\n * against.\n */\n missingScopes?: readonly string[];\n}\n\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\n/**\n * Check whether the project already has a GitHub App integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers (the\n * SelfDrivingGitHubScreen poll) decide how to degrade and are responsible for\n * capturing the error exactly once.\n */\nexport async function fetchGithubConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n // The list is paged, so a project with many integrations could push GitHub off page one.\n params: { kind: 'github' },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'github');\n}\n\n/** One `ph-markdown-notebook` node holding the report, the shape the MCP's `notebooks-create-markdown` stores. */\nconst markdownNotebookBody = (markdown: string) => ({\n content: {\n type: 'doc',\n content: [\n {\n type: 'ph-markdown-notebook',\n attrs: { nodeId: 'markdown-notebook-v2', markdown },\n },\n ],\n },\n text_content: markdown,\n});\n\nconst NotebookResponseSchema = z.object({ version: z.number() }).passthrough();\n\nconst NOTEBOOK_TIMEOUT_MS = 15_000;\n\nconst notebookRequest = (accessToken: string, signal?: AbortSignal) => ({\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: NOTEBOOK_TIMEOUT_MS,\n signal,\n});\n\n/**\n * Create a notebook holding `markdown` under a caller-chosen `shortId`.\n * Requires the `notebook:write` scope. Returns the notebook's version for the\n * next update; throws on failure — the caller decides how to degrade.\n */\nexport async function createMarkdownNotebook(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n notebook: { shortId: string; title: string; markdown: string },\n signal?: AbortSignal,\n): Promise<number> {\n const response = await axios.post(\n `${baseUrl}/api/projects/${projectId}/notebooks/`,\n {\n title: notebook.title,\n short_id: notebook.shortId,\n ...markdownNotebookBody(notebook.markdown),\n },\n notebookRequest(accessToken, signal),\n );\n return NotebookResponseSchema.parse(response.data).version;\n}\n\n/**\n * Replace the markdown of a notebook `createMarkdownNotebook` made. `version`\n * is the one the previous create or update returned. Returns the new version;\n * throws on failure.\n */\nexport async function updateMarkdownNotebook(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n notebook: { shortId: string; markdown: string; version: number },\n signal?: AbortSignal,\n): Promise<number> {\n const response = await axios.patch(\n `${baseUrl}/api/projects/${projectId}/notebooks/${notebook.shortId}/`,\n { ...markdownNotebookBody(notebook.markdown), version: notebook.version },\n notebookRequest(accessToken, signal),\n );\n return NotebookResponseSchema.parse(response.data).version;\n}\n\n/**\n * Read a notebook's current version and markdown by `shortId`, or null when it\n * does not exist. Lets a caller whose create or update lost its response find\n * out whether the write landed.\n */\nexport async function fetchMarkdownNotebook(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n shortId: string,\n signal?: AbortSignal,\n): Promise<{ version: number; markdown: string | undefined } | null> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/notebooks/${shortId}/`,\n notebookRequest(accessToken, signal),\n );\n const notebook = NotebookResponseSchema.parse(response.data);\n const text = (response.data as { text_content?: unknown }).text_content;\n return {\n version: notebook.version,\n markdown: typeof text === 'string' ? text : undefined,\n };\n } catch (error) {\n if (axios.isAxiosError(error) && error.response?.status === 404) {\n return null;\n }\n throw error;\n }\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { o as logToFile } from "./debug-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import { t as HostResolution } from "./host-resolution-
|
|
4
|
-
import { c as fetchProjectData, u as fetchUserData } from "./api-
|
|
1
|
+
import { o as logToFile } from "./debug-C_9xDg9j.js";
|
|
2
|
+
import { n as analytics } from "./analytics-CX2kvq0R.js";
|
|
3
|
+
import { t as HostResolution } from "./host-resolution-C3ctTKNg.js";
|
|
4
|
+
import { c as fetchProjectData, u as fetchUserData } from "./api-BOP8gF35.js";
|
|
5
5
|
//#region src/shared/api-key-login.ts
|
|
6
6
|
/** What a personal API key logs in to, the way `--ci` does: no browser, no OAuth. */
|
|
7
7
|
/** The host, the project and, when the key can read it, the user `apiKey` belongs to. */
|
|
@@ -52,4 +52,4 @@ async function fetchProjectDataById(apiKey, projectId, cloudUrl) {
|
|
|
52
52
|
//#endregion
|
|
53
53
|
export { resolveApiKeyProject as t };
|
|
54
54
|
|
|
55
|
-
//# sourceMappingURL=api-key-login-
|
|
55
|
+
//# sourceMappingURL=api-key-login-DbrZknHp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-key-login-
|
|
1
|
+
{"version":3,"file":"api-key-login-DbrZknHp.js","names":[],"sources":["../src/shared/api-key-login.ts"],"sourcesContent":["/** What a personal API key logs in to, the way `--ci` does: no browser, no OAuth. */\n\nimport {\n fetchProjectData,\n fetchUserData,\n type ApiProject,\n type ApiUser,\n} from './api';\nimport { HostResolution } from './host-resolution';\nimport { analytics } from './utils/analytics';\nimport { logToFile } from './utils/debug';\nimport type { CloudRegion } from './utils/types';\n\nexport type ApiKeyLoginOptions = {\n region?: CloudRegion;\n baseUrl?: string; // pins every PostHog origin and skips region resolution\n localMcp?: boolean; // resolves `host.mcpUrl` to the local MCP server\n projectId?: number; // the project to use; else the key's current project\n onWarning?: (message: string) => void; // shown when the key can't read its user\n onInfo?: (message: string) => void; // the login's progress line\n};\n\n/** The host, the project and, when the key can read it, the user `apiKey` belongs to. */\nexport async function resolveApiKeyProject(\n apiKey: string,\n options: ApiKeyLoginOptions = {},\n): Promise<{\n host: HostResolution;\n project: ApiProject;\n projectId: number;\n apiUser: ApiUser | null;\n}> {\n options.onInfo?.('Using provided API key (CI mode - OAuth bypassed)');\n const host = await HostResolution.fromAccessToken(apiKey, {\n region: options.region,\n localMcp: options.localMcp,\n baseUrl: options.baseUrl,\n });\n const cloudUrl = host.appHost;\n const projectData =\n options.projectId != null\n ? await fetchProjectDataById(apiKey, options.projectId, cloudUrl)\n : await fetchProjectDataWithApiKey(apiKey, cloudUrl);\n\n // Best-effort user fetch — CI flows may run with project-scoped keys\n // that 403 on /api/users/@me/, so swallow errors and continue with\n // a null user (and null role).\n let apiUser: ApiUser | null = null;\n try {\n apiUser = await fetchUserData(apiKey, cloudUrl);\n } catch (err) {\n logToFile(\n '[ci-auth] user lookup failed:',\n err instanceof Error ? err.message : String(err),\n );\n }\n if (apiUser) {\n analytics.identifyUser(apiUser);\n logToFile(\n '[ci-auth] identified via API key; flags evaluate as the key owner',\n );\n } else {\n options.onWarning?.(\n 'Could not resolve the API key user (key needs user:read scope) — feature flags evaluate anonymously; user-targeted flags will not match.',\n );\n }\n return {\n host,\n project: projectData.project,\n projectId: projectData.id,\n apiUser,\n };\n}\n\nasync function fetchProjectDataWithApiKey(\n apiKey: string,\n cloudUrl: string,\n): Promise<{ api_token: string; id: number; project: ApiProject }> {\n const userData = await fetchUserData(apiKey, cloudUrl);\n const projectId = userData.team?.id;\n\n if (!projectId) {\n throw new Error(\n 'Could not determine project ID from API key. Please ensure your API key has access to a project in this cloud region.',\n );\n }\n\n const projectData = await fetchProjectData(apiKey, projectId, cloudUrl);\n return {\n api_token: projectData.api_token,\n id: projectId,\n project: projectData,\n };\n}\n\nasync function fetchProjectDataById(\n apiKey: string,\n projectId: number,\n cloudUrl: string,\n): Promise<{ api_token: string; id: number; project: ApiProject }> {\n const projectData = await fetchProjectData(apiKey, projectId, cloudUrl);\n return {\n api_token: projectData.api_token,\n id: projectId,\n project: projectData,\n };\n}\n"],"mappings":";;;;;;;AAuBA,eAAsB,qBACpB,QACA,UAA8B,EAAE,EAM/B;AACD,SAAQ,SAAS,oDAAoD;CACrE,MAAM,OAAO,MAAM,eAAe,gBAAgB,QAAQ;EACxD,QAAQ,QAAQ;EAChB,UAAU,QAAQ;EAClB,SAAS,QAAQ;EAClB,CAAC;CACF,MAAM,WAAW,KAAK;CACtB,MAAM,cACJ,QAAQ,aAAa,OACjB,MAAM,qBAAqB,QAAQ,QAAQ,WAAW,SAAS,GAC/D,MAAM,2BAA2B,QAAQ,SAAS;CAKxD,IAAI,UAA0B;AAC9B,KAAI;AACF,YAAU,MAAM,cAAc,QAAQ,SAAS;UACxC,KAAK;AACZ,YACE,iCACA,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACjD;;AAEH,KAAI,SAAS;AACX,YAAU,aAAa,QAAQ;AAC/B,YACE,oEACD;OAED,SAAQ,YACN,2IACD;AAEH,QAAO;EACL;EACA,SAAS,YAAY;EACrB,WAAW,YAAY;EACvB;EACD;;AAGH,eAAe,2BACb,QACA,UACiE;CAEjE,MAAM,aADW,MAAM,cAAc,QAAQ,SAAS,EAC3B,MAAM;AAEjC,KAAI,CAAC,UACH,OAAM,IAAI,MACR,wHACD;CAGH,MAAM,cAAc,MAAM,iBAAiB,QAAQ,WAAW,SAAS;AACvE,QAAO;EACL,WAAW,YAAY;EACvB,IAAI;EACJ,SAAS;EACV;;AAGH,eAAe,qBACb,QACA,WACA,UACiE;CACjE,MAAM,cAAc,MAAM,iBAAiB,QAAQ,WAAW,SAAS;AACvE,QAAO;EACL,WAAW,YAAY;EACvB,IAAI;EACJ,SAAS;EACV"}
|
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as logToFile } from "./debug-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
1
|
+
import { o as logToFile } from "./debug-C_9xDg9j.js";
|
|
2
|
+
import { n as analytics } from "./analytics-CX2kvq0R.js";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import fg from "fast-glob";
|
|
@@ -257,4 +257,4 @@ function readFileHead(filePath, bytes) {
|
|
|
257
257
|
//#endregion
|
|
258
258
|
export { safeReadFile as a, readProjectFile as i, boundedGlob as n, walkProjectFiles as o, readFileHead as r, IGNORED_DIRS as t };
|
|
259
259
|
|
|
260
|
-
//# sourceMappingURL=bounded-fs-
|
|
260
|
+
//# sourceMappingURL=bounded-fs-BENh-Jzc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bounded-fs-TRL6IsoU.js","names":[],"sources":["../src/shared/utils/bounded-fs.ts"],"sourcesContent":["/**\n * Bounded filesystem primitives for scanning USER project trees. Every\n * detection-time glob, walk, and project-file read goes through here so the\n * worst case is a constant, never a function of the user's repo.\n */\nimport path from 'path';\nimport fs from 'fs';\nimport type { Dirent } from 'fs';\nimport fg from 'fast-glob';\nimport { analytics } from './analytics';\nimport { logToFile } from './debug';\nimport type { WizardRunOptions } from './types';\n\n/**\n * Errno codes that are expected while walking an arbitrary tree and mean\n * \"skip this entry\", not \"something is broken\". Scanning from a broad dir\n * (e.g. `~`) routinely hits OS-protected paths (macOS `Library/Group\n * Containers/group.com.apple.*`) that throw EPERM/EACCES per entry — capturing\n * each as an exception buried real errors under thousands of noise events.\n */\nconst BENIGN_FS_ERROR_CODES = new Set<string>([\n 'EACCES', // permission denied\n 'EPERM', // operation not permitted (macOS-protected dirs)\n 'ENOENT', // entry vanished mid-walk\n 'ENOTDIR', // path component isn't a directory\n 'ELOOP', // symlink loop\n 'ENAMETOOLONG', // path too long\n 'EMFILE', // too many open files (environmental, not a wizard bug)\n 'ENFILE',\n 'EBUSY', // file locked by another process (Windows)\n 'UNKNOWN', // libuv could not map the OS error (Windows locked/placeholder files)\n]);\n\n/**\n * Report a swallowed filesystem error. Traversal stays best-effort — the caller\n * still skips the failing entry. Expected errno codes (permission denied, entry\n * vanished, symlink loops…) are logged to the debug file only; anything else is\n * genuinely unexpected and gets captured to error tracking. Preserves the\n * original Error (and its `code`, e.g. EACCES / ENOENT) when available.\n */\nfunction reportFsError(step: string, filePath: string, error: unknown): void {\n const code = (error as NodeJS.ErrnoException | null)?.code;\n if (code && BENIGN_FS_ERROR_CODES.has(code)) {\n logToFile(`[bounded-fs] skipped ${step} (${code}): ${filePath}`);\n return;\n }\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step, path: filePath },\n );\n}\n\nexport function getDotGitignore({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>) {\n const gitignorePath = path.join(installDir, '.gitignore');\n const gitignoreExists = fs.existsSync(gitignorePath);\n\n if (gitignoreExists) {\n return gitignorePath;\n }\n\n return undefined;\n}\n\n/**\n * Directory names to skip when scanning a project tree — dependency\n * directories, build output, virtual environments, vendored trees.\n * Used verbatim by walkProjectFiles and as glob patterns by boundedGlob.\n */\nexport const IGNORED_DIRS = new Set<string>([\n 'node_modules',\n '.git',\n '.next',\n '.nuxt',\n '.svelte-kit',\n '.turbo',\n '.cache',\n '.parcel-cache',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.coverage',\n 'venv',\n '.venv',\n '__pycache__',\n '.pytest_cache',\n 'vendor',\n 'target',\n '.gradle',\n '.idea',\n '.vscode',\n 'site-packages',\n 'DerivedData',\n 'Pods',\n]);\n\n/** IGNORED_DIRS as fast-glob ignore patterns. */\nexport const PROJECT_IGNORE_GLOBS: readonly string[] = [...IGNORED_DIRS].map(\n (dir) => `**/${dir}/**`,\n);\n\n// Files larger than this are skipped, never materialized.\nexport const MAX_PROJECT_FILE_BYTES = 2 * 1024 * 1024;\n\n// A glob returns at most this many entries.\nexport const MAX_GLOB_MATCHES = 500;\n\n// A glob's traversal is destroyed after this long, even when abandoned.\nexport const GLOB_DEADLINE_MS = 8_000;\n\n// A directory contributes at most this many entries to a walk.\nexport const MAX_DIR_ENTRIES = 10_000;\n\n// A walk fires at most this many onFile callbacks.\nexport const MAX_WALK_FILES = 100_000;\n\nexport interface BoundedGlobOptions {\n cwd: string;\n /** Appended to PROJECT_IGNORE_GLOBS. */\n extraIgnore?: readonly string[];\n /** Stop after this many matches. Defaults to MAX_GLOB_MATCHES. */\n limit?: number;\n /** Match dotfiles. Traversal of dot-DIRECTORIES stays blocked by the ignore set. */\n dot?: boolean;\n /** fast-glob `deep` — maximum directory depth. */\n deep?: number;\n}\n\n/**\n * Streams matches, stops at `limit`, destroys the crawl at GLOB_DEADLINE_MS.\n * Returns paths relative to `cwd`, possibly truncated.\n */\nexport async function boundedGlob(\n patterns: string | string[],\n options: BoundedGlobOptions,\n): Promise<string[]> {\n const limit = options.limit ?? MAX_GLOB_MATCHES;\n const stream = fg.stream(patterns, {\n cwd: options.cwd,\n dot: options.dot ?? false,\n onlyFiles: true,\n deep: options.deep,\n ignore: [...PROJECT_IGNORE_GLOBS, ...(options.extraIgnore ?? [])],\n suppressErrors: true,\n followSymbolicLinks: false,\n }) as NodeJS.ReadableStream & { destroy(): void };\n\n const matches: string[] = [];\n return new Promise((resolve) => {\n let settled = false;\n const finish = (): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(matches);\n };\n const timer = setTimeout(() => {\n stream.destroy();\n finish();\n }, GLOB_DEADLINE_MS);\n stream.on('data', (entry: string | Buffer) => {\n matches.push(String(entry));\n if (matches.length >= limit) {\n stream.destroy();\n finish();\n }\n });\n stream.once('error', finish);\n stream.once('end', finish);\n stream.once('close', finish);\n });\n}\n\nexport interface WalkOptions {\n /**\n * Follow symlinked files and directories. Defaults to true. A caller that\n * reports what it reads turns this off: a symlink can point anywhere on the\n * machine, outside the project it is scanning.\n */\n followSymlinks?: boolean;\n}\n\n/**\n * Walk a project tree, invoking `onFile(name, fullPath)` for every regular\n * file — including dotfiles like `.env` (the caller decides what it cares\n * about). Skips `IGNORED_DIRS` and hidden directories, follows symlinks\n * (unless `followSymlinks` is false) with realpath-based loop protection,\n * descends at most `maxDepth` levels below `rootDir`, and stops at the\n * per-directory and whole-walk caps. Filesystem errors are reported and\n * skipped (best-effort).\n *\n * Returns whether the walk saw the whole tree within `maxDepth`: false when it\n * stopped at a cap or skipped a directory it could not read.\n */\nexport function walkProjectFiles(\n rootDir: string,\n onFile: (name: string, fullPath: string) => void,\n maxDepth = 3,\n { followSymlinks = true }: WalkOptions = {},\n): boolean {\n const visited = new Set<string>();\n let filesSeen = 0;\n let complete = true;\n // Explicit stack — no call-stack recursion.\n const stack: Array<{ dir: string; depth: number }> = [\n { dir: rootDir, depth: 0 },\n ];\n\n while (stack.length > 0) {\n if (filesSeen >= MAX_WALK_FILES) {\n complete = false;\n break;\n }\n const { dir, depth } = stack.pop()!;\n\n // realpath both resolves symlinked dirs and gives us a stable key to\n // detect loops (symlink cycles, e.g. a -> ../a).\n let realDir: string;\n try {\n realDir = fs.realpathSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.realpath', dir, error);\n complete = false;\n continue;\n }\n if (visited.has(realDir)) continue;\n visited.add(realDir);\n\n let handle: fs.Dir;\n try {\n handle = fs.opendirSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.opendir', dir, error);\n complete = false;\n continue;\n }\n try {\n let entriesRead = 0;\n let entry: Dirent | null;\n while ((entry = handle.readSync()) !== null) {\n if (++entriesRead > MAX_DIR_ENTRIES || filesSeen >= MAX_WALK_FILES) {\n logToFile(\n `[bounded-fs] walk capped in ${dir} (entries=${entriesRead}, files=${filesSeen})`,\n );\n complete = false;\n break;\n }\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = path.join(dir, entry.name);\n\n // Symlinks report isDirectory()/isFile() as false under withFileTypes,\n // so resolve the target before deciding how to handle the entry.\n let isDir = entry.isDirectory();\n let isFile = entry.isFile();\n if (entry.isSymbolicLink()) {\n if (!followSymlinks) continue;\n try {\n const st = fs.statSync(fullPath);\n isDir = st.isDirectory();\n isFile = st.isFile();\n } catch (error) {\n reportFsError('walkProjectFiles.stat', fullPath, error);\n continue;\n }\n }\n\n if (isDir) {\n if (entry.name.startsWith('.')) continue; // skip hidden directories\n if (depth < maxDepth) stack.push({ dir: fullPath, depth: depth + 1 });\n } else if (isFile) {\n filesSeen += 1;\n onFile(entry.name, fullPath);\n }\n }\n } finally {\n try {\n handle.closeSync();\n } catch {\n /* already closed */\n }\n }\n }\n return complete;\n}\n\n/**\n * Read a project file as UTF-8, or null when missing, unreadable, or over\n * `maxBytes` (stat-gated: an oversized file is never materialized).\n */\nexport function readProjectFile(\n filePath: string,\n maxBytes = MAX_PROJECT_FILE_BYTES,\n): string | null {\n try {\n if (fs.statSync(filePath).size > maxBytes) return null;\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/**\n * `readProjectFile` that also reports unexpected errors to error tracking.\n * For walk callbacks where a failing read is worth a telemetry breadcrumb.\n */\nexport function safeReadFile(fullPath: string): string | null {\n try {\n if (fs.statSync(fullPath).size > MAX_PROJECT_FILE_BYTES) {\n logToFile(`[bounded-fs] skipped oversized file: ${fullPath}`);\n return null;\n }\n return fs.readFileSync(fullPath, 'utf-8');\n } catch (error) {\n reportFsError('safeReadFile', fullPath, error);\n return null;\n }\n}\n\n/**\n * The first `bytes` of a file without materializing the rest.\n */\nexport function readFileHead(filePath: string, bytes: number): string | null {\n try {\n const fd = fs.openSync(filePath, 'r');\n try {\n const buffer = Buffer.alloc(bytes);\n const read = fs.readSync(fd, buffer, 0, bytes, 0);\n return buffer.toString('utf-8', 0, read);\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bounded-fs-BENh-Jzc.js","names":[],"sources":["../src/shared/utils/bounded-fs.ts"],"sourcesContent":["/**\n * Bounded filesystem primitives for scanning USER project trees. Every\n * detection-time glob, walk, and project-file read goes through here so the\n * worst case is a constant, never a function of the user's repo.\n */\nimport path from 'path';\nimport fs from 'fs';\nimport type { Dirent } from 'fs';\nimport fg from 'fast-glob';\nimport { analytics } from './analytics';\nimport { logToFile } from './debug';\nimport type { WizardRunOptions } from './types';\n\n/**\n * Errno codes that are expected while walking an arbitrary tree and mean\n * \"skip this entry\", not \"something is broken\". Scanning from a broad dir\n * (e.g. `~`) routinely hits OS-protected paths (macOS `Library/Group\n * Containers/group.com.apple.*`) that throw EPERM/EACCES per entry — capturing\n * each as an exception buried real errors under thousands of noise events.\n */\nconst BENIGN_FS_ERROR_CODES = new Set<string>([\n 'EACCES', // permission denied\n 'EPERM', // operation not permitted (macOS-protected dirs)\n 'ENOENT', // entry vanished mid-walk\n 'ENOTDIR', // path component isn't a directory\n 'ELOOP', // symlink loop\n 'ENAMETOOLONG', // path too long\n 'EMFILE', // too many open files (environmental, not a wizard bug)\n 'ENFILE',\n 'EBUSY', // file locked by another process (Windows)\n 'UNKNOWN', // libuv could not map the OS error (Windows locked/placeholder files)\n]);\n\n/**\n * Report a swallowed filesystem error. Traversal stays best-effort — the caller\n * still skips the failing entry. Expected errno codes (permission denied, entry\n * vanished, symlink loops…) are logged to the debug file only; anything else is\n * genuinely unexpected and gets captured to error tracking. Preserves the\n * original Error (and its `code`, e.g. EACCES / ENOENT) when available.\n */\nfunction reportFsError(step: string, filePath: string, error: unknown): void {\n const code = (error as NodeJS.ErrnoException | null)?.code;\n if (code && BENIGN_FS_ERROR_CODES.has(code)) {\n logToFile(`[bounded-fs] skipped ${step} (${code}): ${filePath}`);\n return;\n }\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step, path: filePath },\n );\n}\n\nexport function getDotGitignore({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>) {\n const gitignorePath = path.join(installDir, '.gitignore');\n const gitignoreExists = fs.existsSync(gitignorePath);\n\n if (gitignoreExists) {\n return gitignorePath;\n }\n\n return undefined;\n}\n\n/**\n * Directory names to skip when scanning a project tree — dependency\n * directories, build output, virtual environments, vendored trees.\n * Used verbatim by walkProjectFiles and as glob patterns by boundedGlob.\n */\nexport const IGNORED_DIRS = new Set<string>([\n 'node_modules',\n '.git',\n '.next',\n '.nuxt',\n '.svelte-kit',\n '.turbo',\n '.cache',\n '.parcel-cache',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.coverage',\n 'venv',\n '.venv',\n '__pycache__',\n '.pytest_cache',\n 'vendor',\n 'target',\n '.gradle',\n '.idea',\n '.vscode',\n 'site-packages',\n 'DerivedData',\n 'Pods',\n]);\n\n/** IGNORED_DIRS as fast-glob ignore patterns. */\nexport const PROJECT_IGNORE_GLOBS: readonly string[] = [...IGNORED_DIRS].map(\n (dir) => `**/${dir}/**`,\n);\n\n// Files larger than this are skipped, never materialized.\nexport const MAX_PROJECT_FILE_BYTES = 2 * 1024 * 1024;\n\n// A glob returns at most this many entries.\nexport const MAX_GLOB_MATCHES = 500;\n\n// A glob's traversal is destroyed after this long, even when abandoned.\nexport const GLOB_DEADLINE_MS = 8_000;\n\n// A directory contributes at most this many entries to a walk.\nexport const MAX_DIR_ENTRIES = 10_000;\n\n// A walk fires at most this many onFile callbacks.\nexport const MAX_WALK_FILES = 100_000;\n\nexport interface BoundedGlobOptions {\n cwd: string;\n /** Appended to PROJECT_IGNORE_GLOBS. */\n extraIgnore?: readonly string[];\n /** Stop after this many matches. Defaults to MAX_GLOB_MATCHES. */\n limit?: number;\n /** Match dotfiles. Traversal of dot-DIRECTORIES stays blocked by the ignore set. */\n dot?: boolean;\n /** fast-glob `deep` — maximum directory depth. */\n deep?: number;\n}\n\n/**\n * Streams matches, stops at `limit`, destroys the crawl at GLOB_DEADLINE_MS.\n * Returns paths relative to `cwd`, possibly truncated.\n */\nexport async function boundedGlob(\n patterns: string | string[],\n options: BoundedGlobOptions,\n): Promise<string[]> {\n const limit = options.limit ?? MAX_GLOB_MATCHES;\n const stream = fg.stream(patterns, {\n cwd: options.cwd,\n dot: options.dot ?? false,\n onlyFiles: true,\n deep: options.deep,\n ignore: [...PROJECT_IGNORE_GLOBS, ...(options.extraIgnore ?? [])],\n suppressErrors: true,\n followSymbolicLinks: false,\n }) as NodeJS.ReadableStream & { destroy(): void };\n\n const matches: string[] = [];\n return new Promise((resolve) => {\n let settled = false;\n const finish = (): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(matches);\n };\n const timer = setTimeout(() => {\n stream.destroy();\n finish();\n }, GLOB_DEADLINE_MS);\n stream.on('data', (entry: string | Buffer) => {\n matches.push(String(entry));\n if (matches.length >= limit) {\n stream.destroy();\n finish();\n }\n });\n stream.once('error', finish);\n stream.once('end', finish);\n stream.once('close', finish);\n });\n}\n\nexport interface WalkOptions {\n /**\n * Follow symlinked files and directories. Defaults to true. A caller that\n * reports what it reads turns this off: a symlink can point anywhere on the\n * machine, outside the project it is scanning.\n */\n followSymlinks?: boolean;\n}\n\n/**\n * Walk a project tree, invoking `onFile(name, fullPath)` for every regular\n * file — including dotfiles like `.env` (the caller decides what it cares\n * about). Skips `IGNORED_DIRS` and hidden directories, follows symlinks\n * (unless `followSymlinks` is false) with realpath-based loop protection,\n * descends at most `maxDepth` levels below `rootDir`, and stops at the\n * per-directory and whole-walk caps. Filesystem errors are reported and\n * skipped (best-effort).\n *\n * Returns whether the walk saw the whole tree within `maxDepth`: false when it\n * stopped at a cap or skipped a directory it could not read.\n */\nexport function walkProjectFiles(\n rootDir: string,\n onFile: (name: string, fullPath: string) => void,\n maxDepth = 3,\n { followSymlinks = true }: WalkOptions = {},\n): boolean {\n const visited = new Set<string>();\n let filesSeen = 0;\n let complete = true;\n // Explicit stack — no call-stack recursion.\n const stack: Array<{ dir: string; depth: number }> = [\n { dir: rootDir, depth: 0 },\n ];\n\n while (stack.length > 0) {\n if (filesSeen >= MAX_WALK_FILES) {\n complete = false;\n break;\n }\n const { dir, depth } = stack.pop()!;\n\n // realpath both resolves symlinked dirs and gives us a stable key to\n // detect loops (symlink cycles, e.g. a -> ../a).\n let realDir: string;\n try {\n realDir = fs.realpathSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.realpath', dir, error);\n complete = false;\n continue;\n }\n if (visited.has(realDir)) continue;\n visited.add(realDir);\n\n let handle: fs.Dir;\n try {\n handle = fs.opendirSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.opendir', dir, error);\n complete = false;\n continue;\n }\n try {\n let entriesRead = 0;\n let entry: Dirent | null;\n while ((entry = handle.readSync()) !== null) {\n if (++entriesRead > MAX_DIR_ENTRIES || filesSeen >= MAX_WALK_FILES) {\n logToFile(\n `[bounded-fs] walk capped in ${dir} (entries=${entriesRead}, files=${filesSeen})`,\n );\n complete = false;\n break;\n }\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = path.join(dir, entry.name);\n\n // Symlinks report isDirectory()/isFile() as false under withFileTypes,\n // so resolve the target before deciding how to handle the entry.\n let isDir = entry.isDirectory();\n let isFile = entry.isFile();\n if (entry.isSymbolicLink()) {\n if (!followSymlinks) continue;\n try {\n const st = fs.statSync(fullPath);\n isDir = st.isDirectory();\n isFile = st.isFile();\n } catch (error) {\n reportFsError('walkProjectFiles.stat', fullPath, error);\n continue;\n }\n }\n\n if (isDir) {\n if (entry.name.startsWith('.')) continue; // skip hidden directories\n if (depth < maxDepth) stack.push({ dir: fullPath, depth: depth + 1 });\n } else if (isFile) {\n filesSeen += 1;\n onFile(entry.name, fullPath);\n }\n }\n } finally {\n try {\n handle.closeSync();\n } catch {\n /* already closed */\n }\n }\n }\n return complete;\n}\n\n/**\n * Read a project file as UTF-8, or null when missing, unreadable, or over\n * `maxBytes` (stat-gated: an oversized file is never materialized).\n */\nexport function readProjectFile(\n filePath: string,\n maxBytes = MAX_PROJECT_FILE_BYTES,\n): string | null {\n try {\n if (fs.statSync(filePath).size > maxBytes) return null;\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/**\n * `readProjectFile` that also reports unexpected errors to error tracking.\n * For walk callbacks where a failing read is worth a telemetry breadcrumb.\n */\nexport function safeReadFile(fullPath: string): string | null {\n try {\n if (fs.statSync(fullPath).size > MAX_PROJECT_FILE_BYTES) {\n logToFile(`[bounded-fs] skipped oversized file: ${fullPath}`);\n return null;\n }\n return fs.readFileSync(fullPath, 'utf-8');\n } catch (error) {\n reportFsError('safeReadFile', fullPath, error);\n return null;\n }\n}\n\n/**\n * The first `bytes` of a file without materializing the rest.\n */\nexport function readFileHead(filePath: string, bytes: number): string | null {\n try {\n const fd = fs.openSync(filePath, 'r');\n try {\n const buffer = Buffer.alloc(bytes);\n const read = fs.readSync(fd, buffer, 0, bytes, 0);\n return buffer.toString('utf-8', 0, read);\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as ErrorCodes, t as emitWizardError } from "./emit-BqLCdV8Y.js";
|
|
2
2
|
import "./errors-BXlWujEw.js";
|
|
3
|
-
import { n as runWizardCI, r as API_KEY_HINT, t as runWizardHeadless } from "./runners-
|
|
3
|
+
import { n as runWizardCI, r as API_KEY_HINT, t as runWizardHeadless } from "./runners-DxbNGuKH.js";
|
|
4
4
|
import { t as consoleLog } from "./console-log-BMhBoX-o.js";
|
|
5
|
-
import { t as config } from "./posthog-integration-
|
|
6
|
-
import { n as provisionNewAccount } from "./provisioning-
|
|
5
|
+
import { t as config } from "./posthog-integration-4vQjbU-f.js";
|
|
6
|
+
import { n as provisionNewAccount } from "./provisioning-BMJ3J0Vb.js";
|
|
7
7
|
//#region src/cli/commands/basic-integration/ci-install.ts
|
|
8
8
|
/**
|
|
9
9
|
* CI-mode install entry point (`--ci`, dev/test builds). Thin shell over the
|
|
@@ -114,4 +114,4 @@ async function provisionForSignup(options) {
|
|
|
114
114
|
//#endregion
|
|
115
115
|
export { runCIInstall, runHeadlessInstall };
|
|
116
116
|
|
|
117
|
-
//# sourceMappingURL=ci-install-
|
|
117
|
+
//# sourceMappingURL=ci-install-DnjuAl1l.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci-install-
|
|
1
|
+
{"version":3,"file":"ci-install-DnjuAl1l.js","names":["posthogIntegrationConfig"],"sources":["../src/cli/commands/basic-integration/ci-install.ts"],"sourcesContent":["import type { Arguments } from 'yargs';\nimport { consoleLog } from '@shared/console-log';\nimport { API_KEY_HINT, runWizardCI, runWizardHeadless } from '@cli/runners';\nimport type { NonInteractiveMode } from '@headless';\nimport { provisionNewAccount } from '@utils/provisioning';\nimport { config as posthogIntegrationConfig } from '@programs/posthog-integration';\nimport { ErrorCodes, type ErrorCode } from '@shared/errors';\nimport { emitWizardError } from '@shared/errors';\n\ntype Options = Arguments & {\n region?: string;\n baseUrl?: string;\n installDir?: string;\n apiKey?: string;\n signup?: boolean;\n email?: string;\n name?: string;\n projectId?: string;\n};\n\n/**\n * CI-mode install entry point (`--ci`, dev/test builds). Thin shell over the\n * shared non-interactive install — see `runNonInteractiveInstall`.\n */\nexport function runCIInstall(argv: Arguments): void {\n runNonInteractiveInstall(argv, 'ci');\n}\n\n/**\n * Headless install entry point (the experimental published-build run path; see\n * @shared/headless-mode). Thin shell over the shared non-interactive install.\n * Today it behaves exactly like `runCIInstall`; it is a separate function so\n * headless can diverge later (auth, prompts, …) without touching the CI path.\n */\nexport function runHeadlessInstall(argv: Arguments): void {\n runNonInteractiveInstall(argv, 'headless');\n}\n\n/**\n * Non-interactive install shared by CI and headless. Validates signup flags,\n * optionally provisions an account, then installs. `mode` only changes\n * user-facing labels and which runner is invoked; the accepted keys and the\n * install itself are identical (see runNonInteractive).\n */\nfunction runNonInteractiveInstall(\n argv: Arguments,\n mode: NonInteractiveMode,\n): void {\n const options = { ...argv } as Options;\n const headless = mode === 'headless';\n const label = headless ? 'Headless' : 'CI';\n const runWizard = headless ? runWizardHeadless : runWizardCI;\n\n // Base validation (region/install-dir/api-key) is owned by the runner.\n // This layer only adds the signup branch on top.\n if (!options.apiKey && !options.signup) {\n return failCI(\n `${label} mode requires --api-key (${API_KEY_HINT}). ` +\n 'To create a new account instead, use --signup --email you@example.com.',\n ErrorCodes.ArgsMissingApiKey,\n );\n }\n if (!options.apiKey && options.signup && !options.email) {\n return failCI(\n `${label} --signup requires --email to create a new account.`,\n ErrorCodes.ArgsMissingEmail,\n );\n }\n warnOnUnexpectedKeyPrefix(options.apiKey);\n\n void (async () => {\n if (!options.apiKey && options.signup) {\n // Fail before the irreversible provisioning step rather than after it.\n if (!options.installDir) {\n return failCI(\n `${label} mode requires --install-dir (directory to install in)`,\n ErrorCodes.ArgsMissingInstallDir,\n );\n }\n const provisioned = await provisionForSignup(options);\n options.apiKey = provisioned.personalApiKey;\n if (options.projectId == null) options.projectId = provisioned.projectId;\n }\n runWizard(posthogIntegrationConfig, options);\n })().catch((error: unknown) => {\n emitWizardError({\n code: ErrorCodes.ArgsSignupProvisionFailed,\n message: error instanceof Error ? error.message : String(error),\n });\n process.exit(1);\n });\n}\n\nfunction failCI(message: string, code?: ErrorCode): void {\n consoleLog.intro('PostHog Wizard');\n consoleLog.log.error(message);\n if (code) emitWizardError({ code, message });\n process.exit(1);\n}\n\n/**\n * Decide whether to warn about an unexpected `--api-key` prefix, and with what\n * message. Returns `null` when the key is acceptable.\n *\n * CI and headless accept the same two credentials: a personal API key (`phx_`)\n * and a `pha_` OAuth access token minted under the wizard's own OAuth\n * application (cloud runs, and the CI bot). Both authenticate the mint the\n * same way. Anything else is unexpected and warns.\n *\n * Extracted as a pure predicate so it can be unit-tested without a UI.\n */\nexport function keyPrefixWarning(apiKey: string | undefined): string | null {\n if (!apiKey || apiKey.startsWith('phx_') || apiKey.startsWith('pha_')) {\n return null;\n }\n const hint = apiKey.startsWith('phc_')\n ? ' (phc_ is a project/client key; expected a personal API key or a wizard-app token)'\n : '';\n return `--api-key does not start with \"phx_\" or \"pha_\"${hint}. Continuing anyway, but the LLM Gateway may reject it with a 401.`;\n}\n\nfunction warnOnUnexpectedKeyPrefix(apiKey: string | undefined): void {\n const message = keyPrefixWarning(apiKey);\n if (!message) return;\n consoleLog.intro('PostHog Wizard');\n consoleLog.log.warn(message);\n}\n\n/**\n * Provision a new account and return its credentials. Throws on any failure\n * (after logging a user-facing message); the caller's `.catch` turns that\n * into a non-zero exit. The return type carries no failure sentinel.\n */\nasync function provisionForSignup(\n options: Options,\n): Promise<{ personalApiKey: string; projectId: string }> {\n consoleLog.intro('PostHog Wizard');\n const signupRegion = ((options.region as string) || 'us').toUpperCase() as\n | 'US'\n | 'EU';\n consoleLog.log.info(\n `Provisioning new PostHog account for ${String(\n options.email,\n )} in ${signupRegion}...`,\n );\n\n let result;\n try {\n result = await provisionNewAccount(\n options.email as string,\n options.name ?? '',\n signupRegion,\n { baseUrl: options.baseUrl },\n );\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n consoleLog.log.error(`Provisioning failed: ${msg}`);\n throw error;\n }\n\n if (!result.personalApiKey) {\n consoleLog.log.error(\n 'Provisioning succeeded but no personal API key was returned — cannot continue install.',\n );\n throw new Error('provisioning returned no personal API key');\n }\n\n consoleLog.log.success('Account ready.');\n consoleLog.log.info(` Project API Key: ${result.projectApiKey}`);\n consoleLog.log.info(` Personal API Key: ${result.personalApiKey}`);\n consoleLog.log.info(` Host: ${result.host}`);\n return {\n personalApiKey: result.personalApiKey,\n projectId: result.projectId,\n };\n}\n"],"mappings":";;;;;;;;;;;AAwBA,SAAgB,aAAa,MAAuB;AAClD,0BAAyB,MAAM,KAAK;;;;;;;;AAStC,SAAgB,mBAAmB,MAAuB;AACxD,0BAAyB,MAAM,WAAW;;;;;;;;AAS5C,SAAS,yBACP,MACA,MACM;CACN,MAAM,UAAU,EAAE,GAAG,MAAM;CAC3B,MAAM,WAAW,SAAS;CAC1B,MAAM,QAAQ,WAAW,aAAa;CACtC,MAAM,YAAY,WAAW,oBAAoB;AAIjD,KAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,OAC9B,QAAO,OACL,GAAG,MAAM,4BAA4B,aAAa,4EAElD,WAAW,kBACZ;AAEH,KAAI,CAAC,QAAQ,UAAU,QAAQ,UAAU,CAAC,QAAQ,MAChD,QAAO,OACL,GAAG,MAAM,sDACT,WAAW,iBACZ;AAEH,2BAA0B,QAAQ,OAAO;AAEzC,EAAM,YAAY;AAChB,MAAI,CAAC,QAAQ,UAAU,QAAQ,QAAQ;AAErC,OAAI,CAAC,QAAQ,WACX,QAAO,OACL,GAAG,MAAM,yDACT,WAAW,sBACZ;GAEH,MAAM,cAAc,MAAM,mBAAmB,QAAQ;AACrD,WAAQ,SAAS,YAAY;AAC7B,OAAI,QAAQ,aAAa,KAAM,SAAQ,YAAY,YAAY;;AAEjE,YAAUA,QAA0B,QAAQ;KAC1C,CAAC,OAAO,UAAmB;AAC7B,kBAAgB;GACd,MAAM,WAAW;GACjB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAChE,CAAC;AACF,UAAQ,KAAK,EAAE;GACf;;AAGJ,SAAS,OAAO,SAAiB,MAAwB;AACvD,YAAW,MAAM,iBAAiB;AAClC,YAAW,IAAI,MAAM,QAAQ;AAC7B,KAAI,KAAM,iBAAgB;EAAE;EAAM;EAAS,CAAC;AAC5C,SAAQ,KAAK,EAAE;;;;;;;;;;;;;AAcjB,SAAgB,iBAAiB,QAA2C;AAC1E,KAAI,CAAC,UAAU,OAAO,WAAW,OAAO,IAAI,OAAO,WAAW,OAAO,CACnE,QAAO;AAKT,QAAO,iDAHM,OAAO,WAAW,OAAO,GAClC,uFACA,GACyD;;AAG/D,SAAS,0BAA0B,QAAkC;CACnE,MAAM,UAAU,iBAAiB,OAAO;AACxC,KAAI,CAAC,QAAS;AACd,YAAW,MAAM,iBAAiB;AAClC,YAAW,IAAI,KAAK,QAAQ;;;;;;;AAQ9B,eAAe,mBACb,SACwD;AACxD,YAAW,MAAM,iBAAiB;CAClC,MAAM,gBAAiB,QAAQ,UAAqB,MAAM,aAAa;AAGvE,YAAW,IAAI,KACb,wCAAwC,OACtC,QAAQ,MACT,CAAC,MAAM,aAAa,KACtB;CAED,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,oBACb,QAAQ,OACR,QAAQ,QAAQ,IAChB,cACA,EAAE,SAAS,QAAQ,SAAS,CAC7B;UACM,OAAO;EACd,MAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAClE,aAAW,IAAI,MAAM,wBAAwB,MAAM;AACnD,QAAM;;AAGR,KAAI,CAAC,OAAO,gBAAgB;AAC1B,aAAW,IAAI,MACb,yFACD;AACD,QAAM,IAAI,MAAM,4CAA4C;;AAG9D,YAAW,IAAI,QAAQ,iBAAiB;AACxC,YAAW,IAAI,KAAK,uBAAuB,OAAO,gBAAgB;AAClE,YAAW,IAAI,KAAK,uBAAuB,OAAO,iBAAiB;AACnE,YAAW,IAAI,KAAK,uBAAuB,OAAO,OAAO;AACzD,QAAO;EACL,gBAAgB,OAAO;EACvB,WAAW,OAAO;EACnB"}
|
|
@@ -41,7 +41,7 @@ const TASK_RUN_ID = runtimeEnv("POSTHOG_TASK_RUN_ID") || void 0;
|
|
|
41
41
|
const TASK_ID = runtimeEnv("POSTHOG_TASK_ID") || void 0;
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region src/shared/version.ts
|
|
44
|
-
const VERSION = "2.84.
|
|
44
|
+
const VERSION = "2.84.1";
|
|
45
45
|
//#endregion
|
|
46
46
|
//#region src/shared/utils/paths.ts
|
|
47
47
|
const TMP = process.platform === "win32" ? tmpdir() : "/tmp";
|
|
@@ -95,7 +95,7 @@ let reportedLogFailure = false;
|
|
|
95
95
|
function reportLogFailureOnce(err) {
|
|
96
96
|
if (reportedLogFailure) return;
|
|
97
97
|
reportedLogFailure = true;
|
|
98
|
-
import("./analytics-
|
|
98
|
+
import("./analytics-DgLAjlIK.js").then(({ analytics }) => analytics.captureException(err instanceof Error ? err : new Error(String(err)), {
|
|
99
99
|
source: "log-file-write",
|
|
100
100
|
log_path: logFilePath,
|
|
101
101
|
platform: process.platform
|
|
@@ -134,4 +134,4 @@ function logToFile(...args) {
|
|
|
134
134
|
//#endregion
|
|
135
135
|
export { TASK_RUN_ID as _, initLogFile as a, WIZARD_LOG_FILE as c, relativeToInstallDir as d, VERSION as f, TASK_ID as g, RUN_SURFACE as h, getLogFilePath as i, WIZARD_TASK_STREAM_FILE as l, NODE_ENV as m, configureLogFileFromEnvironment as n, logToFile as o, HEADLESS_FLAG as p, formatLogLine as r, WIZARD_BENCHMARK_FILE as s, configureLogFile as t, WIZARD_YARA_REPORT_FILE as u, runtimeEnv as v };
|
|
136
136
|
|
|
137
|
-
//# sourceMappingURL=debug-
|
|
137
|
+
//# sourceMappingURL=debug-C_9xDg9j.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug-BfO_Txo8.js","names":["join","sep"],"sources":["../src/env.ts","../src/shared/version.ts","../src/shared/utils/paths.ts","../src/shared/utils/debug.ts"],"sourcesContent":["/**\n * Central environment variable access for the PostHog wizard.\n *\n * ── Build-time constants ────────────────────────────────────────────\n * Inlined by tsdown's `env` option at compile time. After build, the\n * runtime value of these env vars has zero effect on the wizard.\n *\n * ── Runtime variables ───────────────────────────────────────────────\n * Read through `runtimeEnv()` with a typed allowlist. This makes every\n * runtime dependency on the environment explicit and grep-able.\n *\n * ── Direct process.env access ───────────────────────────────────────\n * Reserved for subprocess environment configuration (writes) and\n * vendored code. Production source outside those cases should use\n * this module instead.\n */\n\n/**\n * The on-CLI flag name. Intentionally ugly + undocumented; do not surface it in\n * `--help`, the README, or user-facing error messages.\n */\nexport const HEADLESS_FLAG = 'headless-DONOTUSE-EXPERIMENTAL';\n\n// ── Build-time constants ─────────────────────────────────────────────\n// tsdown replaces `process.env.NODE_ENV` with a string literal.\n// After build these are just `\"production\"`, `false`, etc.\n\nexport const NODE_ENV = process.env.NODE_ENV as string;\nexport const IS_DEV =\n process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';\n\n/**\n * True only in published/production builds. tsdown inlines\n * `process.env.NODE_ENV` as the literal `\"production\"` at build time, so this\n * collapses to `true` in `dist/` and stays `false` for `tsx`/dev/test runs\n * (where NODE_ENV is unset, `development`, or `test`). Used to gate features\n * that aren't supported in the shipped package — e.g. `--ci` mode.\n */\nexport const IS_PRODUCTION_BUILD = process.env.NODE_ENV === 'production';\n\n/** 'cloud' when launched with the experimental headless flag, else 'local' — resolved once from argv at launch. */\nexport const RUN_SURFACE: 'cloud' | 'local' = process.argv.some(\n (a) => a === `--${HEADLESS_FLAG}` || a.startsWith(`--${HEADLESS_FLAG}=`),\n)\n ? 'cloud'\n : 'local';\n\n// ── Runtime environment ──────────────────────────────────────────────\n\n/**\n * Exhaustive allowlist of env vars the wizard reads at runtime.\n * Add new keys here when a new runtime dependency is needed.\n */\ntype RuntimeEnvKey =\n // CI-build-only flag overrides (see utils/ci-flag-overrides.ts).\n // Deliberately NOT POSTHOG_WIZARD_-prefixed: yargs .env('POSTHOG_WIZARD')\n // would claim it as an unknown CLI option and strict-reject the run.\n | 'WIZARD_CI_FLAG_OVERRIDES'\n | 'WIZARD_CI_EXCLUDE_TASKS'\n | 'WIZARD_CI_GATEWAY_TOKEN_FILE'\n | 'WIZARD_CI_GATEWAY_URL'\n // Wizard CLI configuration (yargs POSTHOG_WIZARD_ prefix)\n | 'POSTHOG_WIZARD_BENCHMARK_CONFIG'\n | 'POSTHOG_WIZARD_BENCHMARK_FILE'\n | 'POSTHOG_WIZARD_LOG_DIR'\n | 'POSTHOG_WIZARD_DEBUG'\n // Identity of the PostHog task run whose sandbox launched this wizard. Set by\n // the sandbox for every run it starts, agent or wizard. Deliberately NOT\n // POSTHOG_WIZARD_-prefixed, for the same reason as the two keys above:\n // yargs .env('POSTHOG_WIZARD') would claim them as CLI options and\n // .strictOptions() would reject the run unless the wizard also declared them,\n // which would tie every sandbox deploy to an npm release of this package.\n | 'POSTHOG_WIZARD_RUN_ID'\n | 'POSTHOG_TASK_RUN_ID'\n | 'POSTHOG_TASK_ID'\n | 'POSTHOG_HANDOFF_OUTPUT_PATH'\n // Local/CI escape hatch to disable Warlock scanning without the PostHog flag.\n | 'POSTHOG_WIZARD_WARLOCK_DISABLED'\n // Dev-build override of the Decisions judgment service's mode: off, shadow or primary.\n | 'WIZARD_DECISIONS_DETECTION'\n | 'DEBUG'\n // Agent / MCP\n | 'MCP_URL'\n | 'POSTHOG_API_KEY'\n // Platform: terminal detection\n | 'TERM'\n | 'TERM_PROGRAM'\n | 'TERMINAL_EMULATOR'\n | 'CI'\n | 'WT_SESSION'\n | 'TERMINUS_SUBLIME'\n | 'ConEmuTask'\n // Platform: paths\n | 'APPDATA'\n | 'OPENCODE_CONFIG_DIR'\n | 'XDG_CONFIG_HOME';\n\n/** Read a runtime environment variable. Only allowlisted keys compile. */\nexport function runtimeEnv(key: RuntimeEnvKey): string | undefined {\n return process.env[key];\n}\n\n/**\n * The PostHog task run that launched this wizard, when one did. A cloud run's\n * sandbox exports both ids into the wizard's environment; every local run\n * leaves them undefined. Resolved once at launch, like RUN_SURFACE above.\n */\nexport const TASK_RUN_ID: string | undefined =\n runtimeEnv('POSTHOG_TASK_RUN_ID') || undefined;\nexport const TASK_ID: string | undefined =\n runtimeEnv('POSTHOG_TASK_ID') || undefined;\n","// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.84.0';\n","import { tmpdir } from 'node:os';\nimport { join, sep } from 'node:path';\n\n// /tmp is stable and discoverable on macOS/Linux; Windows needs os.tmpdir()\nconst TMP = process.platform === 'win32' ? tmpdir() : '/tmp';\n\nexport const WIZARD_LOG_FILE = join(TMP, 'posthog-wizard.log');\nexport const WIZARD_BENCHMARK_FILE = join(TMP, 'posthog-wizard-benchmark.json');\n/** Default target of `--task-stream-log`. Dev builds only. */\nexport const WIZARD_TASK_STREAM_FILE = join(\n TMP,\n 'posthog-wizard-task-stream.jsonl',\n);\nexport const WIZARD_YARA_REPORT_FILE = join(\n TMP,\n 'posthog-wizard-yara-report.json',\n);\n/**\n * Strip an absolute installDir prefix off a project file path so the UI\n * renders `index.js:12` instead of `/Users/.../index.js:12`. Defends\n * against false matches like `/Users/foo` ⊂ `/Users/foobar/x.js` by\n * normalizing to a trailing path separator before the prefix check.\n */\nexport function relativeToInstallDir(file: string, installDir: string): string {\n const prefix = installDir.endsWith(sep) ? installDir : installDir + sep;\n return file.startsWith(prefix) ? file.slice(prefix.length) : file;\n}\n","import { appendFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { inspect } from 'node:util';\nimport { IS_DEV, runtimeEnv } from '@env';\nimport { WIZARD_LOG_FILE } from './paths';\n\n// Dev builds may redirect the log so concurrent runs don't interleave one file.\nlet logFilePath =\n (IS_DEV && process.env.POSTHOG_WIZARD_LOG_FILE) || WIZARD_LOG_FILE;\nlet fileLoggingEnabled = true;\n// An explicit --log-file wins over every later path change while pinned.\nlet logFilePinned = false;\n\nfunction stringify(value: unknown): string {\n if (typeof value === 'string') return value;\n if (value instanceof Error) return value.stack ?? String(value);\n try {\n // JSON.stringify throws on cycles and skips some values — fall back to\n // inspect so a crash log line is never dropped.\n return JSON.stringify(value, null, 2) ?? inspect(value, { depth: 3 });\n } catch {\n return inspect(value, { depth: 3 });\n }\n}\n\n/** One log line from `logToFile`-style arguments: strings as they are, errors as their stack, the rest as JSON. */\nexport function formatLogLine(...args: readonly unknown[]): string {\n return args.map(stringify).join(' ');\n}\n\nexport function getLogFilePath(): string {\n return logFilePath;\n}\n\nexport function configureLogFile(opts: {\n path?: string;\n enabled?: boolean;\n pin?: boolean;\n}): void {\n if (opts.pin === false) logFilePinned = false;\n if (opts.path !== undefined && !logFilePinned) {\n logFilePath = opts.path;\n ensuredLogDir = false;\n }\n if (opts.pin === true) logFilePinned = true;\n if (opts.enabled !== undefined) fileLoggingEnabled = opts.enabled;\n}\n\nlet ensuredLogDir = false;\nlet reportedLogFailure = false;\n\n// Failed log writes go to error tracking, once per process. Dynamic import:\n// analytics logs through this module, so a static import would be a cycle.\nfunction reportLogFailureOnce(err: unknown): void {\n if (reportedLogFailure) return;\n reportedLogFailure = true;\n void import('./analytics')\n .then(({ analytics }) =>\n analytics.captureException(\n err instanceof Error ? err : new Error(String(err)),\n {\n source: 'log-file-write',\n log_path: logFilePath,\n platform: process.platform,\n },\n ),\n )\n .catch(() => {\n // Reporting must never crash the wizard either.\n });\n}\n\n// The log's directory isn't guaranteed to exist (Windows %TEMP%,\n// POSTHOG_WIZARD_LOG_DIR) — create it on first failure.\nfunction appendLine(text: string): void {\n try {\n appendFileSync(logFilePath, text);\n } catch (err) {\n if (ensuredLogDir) {\n reportLogFailureOnce(err);\n return;\n }\n ensuredLogDir = true;\n try {\n mkdirSync(path.dirname(logFilePath), { recursive: true });\n appendFileSync(logFilePath, text);\n } catch (retryErr) {\n reportLogFailureOnce(retryErr);\n }\n }\n}\n\nexport function configureLogFileFromEnvironment(): void {\n const dir = runtimeEnv('POSTHOG_WIZARD_LOG_DIR');\n if (dir) {\n configureLogFile({ path: path.join(dir, 'posthog-wizard.log') });\n }\n}\n\nexport function initLogFile(): void {\n if (!fileLoggingEnabled) return;\n const divider = '='.repeat(60);\n appendLine(\n `\\n${divider}\\nPostHog Wizard Run: ${new Date().toISOString()}\\n${divider}\\n`,\n );\n}\n\nexport function logToFile(...args: unknown[]): void {\n if (!fileLoggingEnabled) return;\n const ts = new Date().toISOString();\n appendLine(`[${ts}] ${formatLogLine(...args)}\\n`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"debug-C_9xDg9j.js","names":["join","sep"],"sources":["../src/env.ts","../src/shared/version.ts","../src/shared/utils/paths.ts","../src/shared/utils/debug.ts"],"sourcesContent":["/**\n * Central environment variable access for the PostHog wizard.\n *\n * ── Build-time constants ────────────────────────────────────────────\n * Inlined by tsdown's `env` option at compile time. After build, the\n * runtime value of these env vars has zero effect on the wizard.\n *\n * ── Runtime variables ───────────────────────────────────────────────\n * Read through `runtimeEnv()` with a typed allowlist. This makes every\n * runtime dependency on the environment explicit and grep-able.\n *\n * ── Direct process.env access ───────────────────────────────────────\n * Reserved for subprocess environment configuration (writes) and\n * vendored code. Production source outside those cases should use\n * this module instead.\n */\n\n/**\n * The on-CLI flag name. Intentionally ugly + undocumented; do not surface it in\n * `--help`, the README, or user-facing error messages.\n */\nexport const HEADLESS_FLAG = 'headless-DONOTUSE-EXPERIMENTAL';\n\n// ── Build-time constants ─────────────────────────────────────────────\n// tsdown replaces `process.env.NODE_ENV` with a string literal.\n// After build these are just `\"production\"`, `false`, etc.\n\nexport const NODE_ENV = process.env.NODE_ENV as string;\nexport const IS_DEV =\n process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';\n\n/**\n * True only in published/production builds. tsdown inlines\n * `process.env.NODE_ENV` as the literal `\"production\"` at build time, so this\n * collapses to `true` in `dist/` and stays `false` for `tsx`/dev/test runs\n * (where NODE_ENV is unset, `development`, or `test`). Used to gate features\n * that aren't supported in the shipped package — e.g. `--ci` mode.\n */\nexport const IS_PRODUCTION_BUILD = process.env.NODE_ENV === 'production';\n\n/** 'cloud' when launched with the experimental headless flag, else 'local' — resolved once from argv at launch. */\nexport const RUN_SURFACE: 'cloud' | 'local' = process.argv.some(\n (a) => a === `--${HEADLESS_FLAG}` || a.startsWith(`--${HEADLESS_FLAG}=`),\n)\n ? 'cloud'\n : 'local';\n\n// ── Runtime environment ──────────────────────────────────────────────\n\n/**\n * Exhaustive allowlist of env vars the wizard reads at runtime.\n * Add new keys here when a new runtime dependency is needed.\n */\ntype RuntimeEnvKey =\n // CI-build-only flag overrides (see utils/ci-flag-overrides.ts).\n // Deliberately NOT POSTHOG_WIZARD_-prefixed: yargs .env('POSTHOG_WIZARD')\n // would claim it as an unknown CLI option and strict-reject the run.\n | 'WIZARD_CI_FLAG_OVERRIDES'\n | 'WIZARD_CI_EXCLUDE_TASKS'\n | 'WIZARD_CI_GATEWAY_TOKEN_FILE'\n | 'WIZARD_CI_GATEWAY_URL'\n // Wizard CLI configuration (yargs POSTHOG_WIZARD_ prefix)\n | 'POSTHOG_WIZARD_BENCHMARK_CONFIG'\n | 'POSTHOG_WIZARD_BENCHMARK_FILE'\n | 'POSTHOG_WIZARD_LOG_DIR'\n | 'POSTHOG_WIZARD_DEBUG'\n // Identity of the PostHog task run whose sandbox launched this wizard. Set by\n // the sandbox for every run it starts, agent or wizard. Deliberately NOT\n // POSTHOG_WIZARD_-prefixed, for the same reason as the two keys above:\n // yargs .env('POSTHOG_WIZARD') would claim them as CLI options and\n // .strictOptions() would reject the run unless the wizard also declared them,\n // which would tie every sandbox deploy to an npm release of this package.\n | 'POSTHOG_WIZARD_RUN_ID'\n | 'POSTHOG_TASK_RUN_ID'\n | 'POSTHOG_TASK_ID'\n | 'POSTHOG_HANDOFF_OUTPUT_PATH'\n // Local/CI escape hatch to disable Warlock scanning without the PostHog flag.\n | 'POSTHOG_WIZARD_WARLOCK_DISABLED'\n // Dev-build override of the Decisions judgment service's mode: off, shadow or primary.\n | 'WIZARD_DECISIONS_DETECTION'\n | 'DEBUG'\n // Agent / MCP\n | 'MCP_URL'\n | 'POSTHOG_API_KEY'\n // Platform: terminal detection\n | 'TERM'\n | 'TERM_PROGRAM'\n | 'TERMINAL_EMULATOR'\n | 'CI'\n | 'WT_SESSION'\n | 'TERMINUS_SUBLIME'\n | 'ConEmuTask'\n // Platform: paths\n | 'APPDATA'\n | 'OPENCODE_CONFIG_DIR'\n | 'XDG_CONFIG_HOME';\n\n/** Read a runtime environment variable. Only allowlisted keys compile. */\nexport function runtimeEnv(key: RuntimeEnvKey): string | undefined {\n return process.env[key];\n}\n\n/**\n * The PostHog task run that launched this wizard, when one did. A cloud run's\n * sandbox exports both ids into the wizard's environment; every local run\n * leaves them undefined. Resolved once at launch, like RUN_SURFACE above.\n */\nexport const TASK_RUN_ID: string | undefined =\n runtimeEnv('POSTHOG_TASK_RUN_ID') || undefined;\nexport const TASK_ID: string | undefined =\n runtimeEnv('POSTHOG_TASK_ID') || undefined;\n","// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.84.1';\n","import { tmpdir } from 'node:os';\nimport { join, sep } from 'node:path';\n\n// /tmp is stable and discoverable on macOS/Linux; Windows needs os.tmpdir()\nconst TMP = process.platform === 'win32' ? tmpdir() : '/tmp';\n\nexport const WIZARD_LOG_FILE = join(TMP, 'posthog-wizard.log');\nexport const WIZARD_BENCHMARK_FILE = join(TMP, 'posthog-wizard-benchmark.json');\n/** Default target of `--task-stream-log`. Dev builds only. */\nexport const WIZARD_TASK_STREAM_FILE = join(\n TMP,\n 'posthog-wizard-task-stream.jsonl',\n);\nexport const WIZARD_YARA_REPORT_FILE = join(\n TMP,\n 'posthog-wizard-yara-report.json',\n);\n/**\n * Strip an absolute installDir prefix off a project file path so the UI\n * renders `index.js:12` instead of `/Users/.../index.js:12`. Defends\n * against false matches like `/Users/foo` ⊂ `/Users/foobar/x.js` by\n * normalizing to a trailing path separator before the prefix check.\n */\nexport function relativeToInstallDir(file: string, installDir: string): string {\n const prefix = installDir.endsWith(sep) ? installDir : installDir + sep;\n return file.startsWith(prefix) ? file.slice(prefix.length) : file;\n}\n","import { appendFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { inspect } from 'node:util';\nimport { IS_DEV, runtimeEnv } from '@env';\nimport { WIZARD_LOG_FILE } from './paths';\n\n// Dev builds may redirect the log so concurrent runs don't interleave one file.\nlet logFilePath =\n (IS_DEV && process.env.POSTHOG_WIZARD_LOG_FILE) || WIZARD_LOG_FILE;\nlet fileLoggingEnabled = true;\n// An explicit --log-file wins over every later path change while pinned.\nlet logFilePinned = false;\n\nfunction stringify(value: unknown): string {\n if (typeof value === 'string') return value;\n if (value instanceof Error) return value.stack ?? String(value);\n try {\n // JSON.stringify throws on cycles and skips some values — fall back to\n // inspect so a crash log line is never dropped.\n return JSON.stringify(value, null, 2) ?? inspect(value, { depth: 3 });\n } catch {\n return inspect(value, { depth: 3 });\n }\n}\n\n/** One log line from `logToFile`-style arguments: strings as they are, errors as their stack, the rest as JSON. */\nexport function formatLogLine(...args: readonly unknown[]): string {\n return args.map(stringify).join(' ');\n}\n\nexport function getLogFilePath(): string {\n return logFilePath;\n}\n\nexport function configureLogFile(opts: {\n path?: string;\n enabled?: boolean;\n pin?: boolean;\n}): void {\n if (opts.pin === false) logFilePinned = false;\n if (opts.path !== undefined && !logFilePinned) {\n logFilePath = opts.path;\n ensuredLogDir = false;\n }\n if (opts.pin === true) logFilePinned = true;\n if (opts.enabled !== undefined) fileLoggingEnabled = opts.enabled;\n}\n\nlet ensuredLogDir = false;\nlet reportedLogFailure = false;\n\n// Failed log writes go to error tracking, once per process. Dynamic import:\n// analytics logs through this module, so a static import would be a cycle.\nfunction reportLogFailureOnce(err: unknown): void {\n if (reportedLogFailure) return;\n reportedLogFailure = true;\n void import('./analytics')\n .then(({ analytics }) =>\n analytics.captureException(\n err instanceof Error ? err : new Error(String(err)),\n {\n source: 'log-file-write',\n log_path: logFilePath,\n platform: process.platform,\n },\n ),\n )\n .catch(() => {\n // Reporting must never crash the wizard either.\n });\n}\n\n// The log's directory isn't guaranteed to exist (Windows %TEMP%,\n// POSTHOG_WIZARD_LOG_DIR) — create it on first failure.\nfunction appendLine(text: string): void {\n try {\n appendFileSync(logFilePath, text);\n } catch (err) {\n if (ensuredLogDir) {\n reportLogFailureOnce(err);\n return;\n }\n ensuredLogDir = true;\n try {\n mkdirSync(path.dirname(logFilePath), { recursive: true });\n appendFileSync(logFilePath, text);\n } catch (retryErr) {\n reportLogFailureOnce(retryErr);\n }\n }\n}\n\nexport function configureLogFileFromEnvironment(): void {\n const dir = runtimeEnv('POSTHOG_WIZARD_LOG_DIR');\n if (dir) {\n configureLogFile({ path: path.join(dir, 'posthog-wizard.log') });\n }\n}\n\nexport function initLogFile(): void {\n if (!fileLoggingEnabled) return;\n const divider = '='.repeat(60);\n appendLine(\n `\\n${divider}\\nPostHog Wizard Run: ${new Date().toISOString()}\\n${divider}\\n`,\n );\n}\n\nexport function logToFile(...args: unknown[]): void {\n if (!fileLoggingEnabled) return;\n const ts = new Date().toISOString();\n appendLine(`[${ts}] ${formatLogLine(...args)}\\n`);\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as ErrorCodes } from "./emit-BqLCdV8Y.js";
|
|
2
|
-
import { o as logToFile } from "./debug-
|
|
3
|
-
import { b as GITHUB_SKILLS_BASE_URL, n as analytics, u as AWS_SKILLS_BASE_URL } from "./analytics-
|
|
2
|
+
import { o as logToFile } from "./debug-C_9xDg9j.js";
|
|
3
|
+
import { b as GITHUB_SKILLS_BASE_URL, n as analytics, u as AWS_SKILLS_BASE_URL } from "./analytics-CX2kvq0R.js";
|
|
4
4
|
import { a as WizardError } from "./errors-BXlWujEw.js";
|
|
5
|
-
import { a as oauthLoginKey } from "./oauth-session-
|
|
6
|
-
import { i as modelCapabilities } from "./models-
|
|
5
|
+
import { a as oauthLoginKey } from "./oauth-session-C4JV-yA9.js";
|
|
6
|
+
import { i as modelCapabilities } from "./models-HwzgIr2E.js";
|
|
7
7
|
//#region src/shared/health-checks/endpoints.ts
|
|
8
8
|
function noConnectionResult(error, attempts) {
|
|
9
9
|
return {
|
|
@@ -595,4 +595,4 @@ function withGatewayRemint(opts) {
|
|
|
595
595
|
//#endregion
|
|
596
596
|
export { gatewayApiFor as a, AgentSignals as c, policyAbortReason as d, buildWizardPropertiesBlob as f, checkSkillsOriginHealth as g, useRunGatewayCredential as h, createGatewayRuntime as i, REMARK_INSTRUCTION as l, isPastRefresh as m, buildGatewayModel as n, gatewayTerminalFailure as o, gatewayAuth as p, buildGatewayProvider as r, withGatewayRemint as s, GATEWAY_PROVIDER as t, RESUME_INSTRUCTION as u };
|
|
597
597
|
|
|
598
|
-
//# sourceMappingURL=gateway-
|
|
598
|
+
//# sourceMappingURL=gateway-C6_zPLyx.js.map
|