@posthog/wizard 2.78.0 → 2.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +20 -11
  2. package/dist/{add-mcp-server-to-clients-JMv8LP-O.js → add-mcp-server-to-clients-amlJWW7W.js} +5 -5
  3. package/dist/{add-mcp-server-to-clients-JMv8LP-O.js.map → add-mcp-server-to-clients-amlJWW7W.js.map} +1 -1
  4. package/dist/{agent-bCZ3i3fh.js → agent-CNrEC-9v.js} +130 -31
  5. package/dist/agent-CNrEC-9v.js.map +1 -0
  6. package/dist/{agent-interface-BAOIHuXS.js → agent-interface-BXvmAm4c.js} +48 -22
  7. package/dist/agent-interface-BXvmAm4c.js.map +1 -0
  8. package/dist/{agent-prompt-loader-7Pd4CfZO.js → agent-prompt-loader-DiKUbhi_.js} +5 -5
  9. package/dist/{agent-prompt-loader-7Pd4CfZO.js.map → agent-prompt-loader-DiKUbhi_.js.map} +1 -1
  10. package/dist/analytics-DxwRi2Hf.js +2 -0
  11. package/dist/{analytics-CHCZ_qUR.js → analytics-VRYdebXW.js} +4 -4
  12. package/dist/{analytics-CHCZ_qUR.js.map → analytics-VRYdebXW.js.map} +1 -1
  13. package/dist/{api-Diy_2fp8.js → api-DGuJTzjr.js} +3 -3
  14. package/dist/{api-Diy_2fp8.js.map → api-DGuJTzjr.js.map} +1 -1
  15. package/dist/bin.js +56 -53
  16. package/dist/bin.js.map +1 -1
  17. package/dist/{bounded-fs-Bx9zTe6m.js → bounded-fs-Cpn129A4.js} +3 -3
  18. package/dist/{bounded-fs-Bx9zTe6m.js.map → bounded-fs-Cpn129A4.js.map} +1 -1
  19. package/dist/{ci-install-CDdQYsPe.js → ci-install-BPA6gzEq.js} +6 -6
  20. package/dist/ci-install-BPA6gzEq.js.map +1 -0
  21. package/dist/{constants-jFI2SaE1.js → constants-CuJfQEcC.js} +3 -3
  22. package/dist/{constants-jFI2SaE1.js.map → constants-CuJfQEcC.js.map} +1 -1
  23. package/dist/{debug-M2gV2iDq.js → debug-B9k4ideV.js} +1 -1
  24. package/dist/{debug-Ch4BDOtD.js → debug-Cj-8vfXY.js} +2 -2
  25. package/dist/{debug-Ch4BDOtD.js.map → debug-Cj-8vfXY.js.map} +1 -1
  26. package/dist/{endpoints-DCVbM06L.js → endpoints-DnIX0pZH.js} +3 -3
  27. package/dist/{endpoints-DCVbM06L.js.map → endpoints-DnIX0pZH.js.map} +1 -1
  28. package/dist/{env-api-key-Qx8NnYHm.js → env-api-key-BWdKpGEr.js} +2 -2
  29. package/dist/{env-api-key-Qx8NnYHm.js.map → env-api-key-BWdKpGEr.js.map} +1 -1
  30. package/dist/{environment-B07Bmxae.js → environment-DZYUSCpV.js} +4 -4
  31. package/dist/{environment-B07Bmxae.js.map → environment-DZYUSCpV.js.map} +1 -1
  32. package/dist/{errors-CQ9kttJD.js → errors-ddDE6MbA.js} +4 -46
  33. package/dist/errors-ddDE6MbA.js.map +1 -0
  34. package/dist/{file-BcLTjU16.js → file-dEhr-l3n.js} +3 -3
  35. package/dist/file-dEhr-l3n.js.map +1 -0
  36. package/dist/{file-watcher-DWc_bTs6.js → file-watcher-CPM-Nn9L.js} +2 -2
  37. package/dist/{file-watcher-DWc_bTs6.js.map → file-watcher-CPM-Nn9L.js.map} +1 -1
  38. package/dist/{gateway-CjoShdLa.js → gateway-CVU1G0H3.js} +38 -8
  39. package/dist/gateway-CVU1G0H3.js.map +1 -0
  40. package/dist/{headless-ui-BFFmYC4v.js → headless-ui-pY2xB5ug.js} +2 -2
  41. package/dist/{headless-ui-BFFmYC4v.js.map → headless-ui-pY2xB5ug.js.map} +1 -1
  42. package/dist/{interactive-D6zV7brJ.js → interactive-BOGlinZe.js} +2 -2
  43. package/dist/interactive-BOGlinZe.js.map +1 -0
  44. package/dist/{logging-ui-_TwoMNbG.js → logging-ui-CUxNYF2t.js} +4 -4
  45. package/dist/{logging-ui-_TwoMNbG.js.map → logging-ui-CUxNYF2t.js.map} +1 -1
  46. package/dist/{mcp-DAgaoGk5.js → mcp-JcsBBnWv.js} +4 -4
  47. package/dist/{mcp-DAgaoGk5.js.map → mcp-JcsBBnWv.js.map} +1 -1
  48. package/dist/{mcp-prompt-streaming-I2U_X7BC.js → mcp-prompt-streaming-B-p_Pvb2.js} +6 -6
  49. package/dist/mcp-prompt-streaming-B-p_Pvb2.js.map +1 -0
  50. package/dist/{mint-failure-D4nd2XmZ.js → mint-failure-CZFZpHpW.js} +687 -125
  51. package/dist/mint-failure-CZFZpHpW.js.map +1 -0
  52. package/dist/{models-DDdBJKwT.js → models-DnAY67Lg.js} +2 -2
  53. package/dist/{models-DDdBJKwT.js.map → models-DnAY67Lg.js.map} +1 -1
  54. package/dist/{non-interactive-Dzow7YKY.js → non-interactive-DR1CWXY1.js} +3 -3
  55. package/dist/{non-interactive-Dzow7YKY.js.map → non-interactive-DR1CWXY1.js.map} +1 -1
  56. package/dist/{oauth-session-DJ8h6GFa.js → oauth-session-CQTFOk-I.js} +2 -2
  57. package/dist/{oauth-session-DJ8h6GFa.js.map → oauth-session-CQTFOk-I.js.map} +1 -1
  58. package/dist/{orchestrator-tools-szcdscwn.js → orchestrator-tools-CBdt-SXO.js} +3 -3
  59. package/dist/{orchestrator-tools-szcdscwn.js.map → orchestrator-tools-CBdt-SXO.js.map} +1 -1
  60. package/dist/{pi-D3h5Ok0i.js → pi-BtqcLX3y.js} +143 -44
  61. package/dist/pi-BtqcLX3y.js.map +1 -0
  62. package/dist/{playground-5AB4WgNF.js → playground-Dz-ZVjBk.js} +9 -9
  63. package/dist/playground-Dz-ZVjBk.js.map +1 -0
  64. package/dist/{posthog-DNn574nW.js → posthog-6Uqw_Eux.js} +3 -3
  65. package/dist/posthog-6Uqw_Eux.js.map +1 -0
  66. package/dist/{provisioning-B8uSqRZk.js → provisioning-Zf7yPcEs.js} +4 -4
  67. package/dist/{provisioning-B8uSqRZk.js.map → provisioning-Zf7yPcEs.js.map} +1 -1
  68. package/dist/{queue-tools-9OOVx5TE.js → queue-tools-B7_aCyd-.js} +3 -3
  69. package/dist/{queue-tools-9OOVx5TE.js.map → queue-tools-B7_aCyd-.js.map} +1 -1
  70. package/dist/{registry-8YG-kuXk.js → registry-B6iLGorH.js} +49 -49
  71. package/dist/registry-B6iLGorH.js.map +1 -0
  72. package/dist/{run-agent-legacy-d7rWlzQR.js → run-agent-legacy-6WcYMaR9.js} +822 -1020
  73. package/dist/run-agent-legacy-6WcYMaR9.js.map +1 -0
  74. package/dist/{security-Cg_4a7vB.js → security-lkBwWbrK.js} +16 -6
  75. package/dist/security-lkBwWbrK.js.map +1 -0
  76. package/dist/{setup-utils-CmTCTPkX.js → setup-utils-dCViCC6s.js} +11 -11
  77. package/dist/setup-utils-dCViCC6s.js.map +1 -0
  78. package/dist/{start-tui-CB2PZs1x.js → start-tui-oCWMgsDP.js} +26 -26
  79. package/dist/start-tui-oCWMgsDP.js.map +1 -0
  80. package/dist/{steps-BZcXRJNY.js → steps-gx0Pq4I4.js} +7 -7
  81. package/dist/{steps-BZcXRJNY.js.map → steps-gx0Pq4I4.js.map} +1 -1
  82. package/dist/{store-UN7c-ASf.js → store-xYy_6Ruv.js} +10 -10
  83. package/dist/store-xYy_6Ruv.js.map +1 -0
  84. package/dist/{subagent-BofIDK-O.js → subagent-Bfy0sfhU.js} +3 -3
  85. package/dist/{subagent-BofIDK-O.js.map → subagent-Bfy0sfhU.js.map} +1 -1
  86. package/dist/{task-r9t1UhQP.js → task-BOfw7GPc.js} +16 -16
  87. package/dist/{task-r9t1UhQP.js.map → task-BOfw7GPc.js.map} +1 -1
  88. package/dist/{task-stream-CMUilu54.js → task-stream-kYlm9qd0.js} +9 -9
  89. package/dist/task-stream-kYlm9qd0.js.map +1 -0
  90. package/dist/{telemetry-D6ruCtnv.js → telemetry-Bpv-Mh5B.js} +3 -3
  91. package/dist/{telemetry-D6ruCtnv.js.map → telemetry-Bpv-Mh5B.js.map} +1 -1
  92. package/dist/{terminal-DrGyci_a.js → terminal-D07EQ2y0.js} +15 -15
  93. package/dist/terminal-D07EQ2y0.js.map +1 -0
  94. package/dist/{tools-Dyfh9aCD.js → tools-Cc41af5W.js} +8 -8
  95. package/dist/{tools-Dyfh9aCD.js.map → tools-Cc41af5W.js.map} +1 -1
  96. package/dist/{ui-BBVuTM1v.js → ui-CGXtC7Vn.js} +3 -3
  97. package/dist/{ui-BBVuTM1v.js.map → ui-CGXtC7Vn.js.map} +1 -1
  98. package/dist/{version-aXxpgRKx.js → version-Cadof0Z_.js} +2 -2
  99. package/dist/{version-aXxpgRKx.js.map → version-Cadof0Z_.js.map} +1 -1
  100. package/dist/{wizard-abort-BBkiUxfS.js → wizard-abort-HDbP3YcS.js} +6 -6
  101. package/dist/{wizard-abort-BBkiUxfS.js.map → wizard-abort-HDbP3YcS.js.map} +1 -1
  102. package/dist/wizard-abort-Y-Ip2K4z.js +3 -0
  103. package/dist/wizard-session-2w4Ru-Wz.js.map +1 -1
  104. package/dist/yara-hooks-B49RIk5d.js +2 -0
  105. package/dist/{yara-hooks-DCeMDd1o.js → yara-hooks-DCfROpZt.js} +5 -5
  106. package/dist/{yara-hooks-DCeMDd1o.js.map → yara-hooks-DCfROpZt.js.map} +1 -1
  107. package/package.json +2 -1
  108. package/dist/agent-bCZ3i3fh.js.map +0 -1
  109. package/dist/agent-interface-BAOIHuXS.js.map +0 -1
  110. package/dist/analytics-BcV-WCM4.js +0 -2
  111. package/dist/ci-install-CDdQYsPe.js.map +0 -1
  112. package/dist/errors-CQ9kttJD.js.map +0 -1
  113. package/dist/file-BcLTjU16.js.map +0 -1
  114. package/dist/gateway-CjoShdLa.js.map +0 -1
  115. package/dist/interactive-D6zV7brJ.js.map +0 -1
  116. package/dist/mcp-prompt-streaming-I2U_X7BC.js.map +0 -1
  117. package/dist/mint-failure-D4nd2XmZ.js.map +0 -1
  118. package/dist/pi-D3h5Ok0i.js.map +0 -1
  119. package/dist/playground-5AB4WgNF.js.map +0 -1
  120. package/dist/posthog-DNn574nW.js.map +0 -1
  121. package/dist/registry-8YG-kuXk.js.map +0 -1
  122. package/dist/run-agent-legacy-d7rWlzQR.js.map +0 -1
  123. package/dist/security-Cg_4a7vB.js.map +0 -1
  124. package/dist/setup-utils-CmTCTPkX.js.map +0 -1
  125. package/dist/start-tui-CB2PZs1x.js.map +0 -1
  126. package/dist/store-UN7c-ASf.js.map +0 -1
  127. package/dist/task-stream-CMUilu54.js.map +0 -1
  128. package/dist/terminal-DrGyci_a.js.map +0 -1
  129. package/dist/wizard-abort-BU4aLyvh.js +0 -3
  130. package/dist/yara-hooks-DSGuCU9A.js +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-ddDE6MbA.js","names":[],"sources":["../src/shared/errors/codes.ts","../src/shared/errors/emit.ts","../src/shared/errors/catalog.ts","../src/shared/errors/wizard-error.ts","../src/shared/errors/auth.ts","../src/shared/errors/skill-map.ts","../src/shared/errors/sanitize.ts","../src/shared/errors/run-failure.ts"],"sourcesContent":["export const ErrorCodes = {\n CliNodeVersion: 'PHW_CLI_NODE_VERSION',\n CliBadArgs: 'PHW_CLI_BAD_ARGS',\n CliFlagUnavailable: 'PHW_CLI_FLAG_UNAVAILABLE',\n CliInteractiveRequired: 'PHW_CLI_INTERACTIVE_REQUIRED',\n ArgsMissingApiKey: 'PHW_ARGS_MISSING_API_KEY',\n ArgsMissingInstallDir: 'PHW_ARGS_MISSING_INSTALL_DIR',\n ArgsMissingEmail: 'PHW_ARGS_MISSING_EMAIL',\n ArgsSignupProvisionFailed: 'PHW_ARGS_SIGNUP_PROVISION_FAILED',\n AuthKeyType: 'PHW_AUTH_KEY_TYPE',\n AuthMissingScope: 'PHW_AUTH_MISSING_SCOPE',\n AuthRegionMismatch: 'PHW_AUTH_REGION_MISMATCH',\n AuthInvalidOrExpired: 'PHW_AUTH_INVALID_OR_EXPIRED',\n /** The OAuth grant itself is gone — distinct from a merely expired token. */\n AuthSessionExpired: 'PHW_AUTH_SESSION_EXPIRED',\n AuthSettingsConflict: 'PHW_AUTH_SETTINGS_CONFLICT',\n AuthStoredLoginConflict: 'PHW_AUTH_STORED_LOGIN_CONFLICT',\n AuthProjectFetchFailed: 'PHW_AUTH_PROJECT_FETCH_FAILED',\n EnvLocalServicesDown: 'PHW_ENV_LOCAL_SERVICES_DOWN',\n EnvServiceOutage: 'PHW_ENV_SERVICE_OUTAGE',\n DetectBadDirectory: 'PHW_DETECT_BAD_DIRECTORY',\n DetectNoFramework: 'PHW_DETECT_NO_FRAMEWORK',\n DetectUnsupportedVersion: 'PHW_DETECT_UNSUPPORTED_VERSION',\n DetectUnsupportedPlatform: 'PHW_DETECT_UNSUPPORTED_PLATFORM',\n DetectNoPosthogSdk: 'PHW_DETECT_NO_POSTHOG_SDK',\n DetectNoProjectFiles: 'PHW_DETECT_NO_PROJECT_FILES',\n DetectNoSources: 'PHW_DETECT_NO_SOURCES',\n DetectNoPackageJson: 'PHW_DETECT_NO_PACKAGE_JSON',\n DetectNoSdks: 'PHW_DETECT_NO_SDKS',\n DetectMissingStripe: 'PHW_DETECT_MISSING_STRIPE',\n DetectUnclassified: 'PHW_DETECT_UNCLASSIFIED',\n SkillMenuFetchFailed: 'PHW_SKILL_MENU_FETCH_FAILED',\n SkillNotFound: 'PHW_SKILL_NOT_FOUND',\n SkillDownloadFailed: 'PHW_SKILL_DOWNLOAD_FAILED',\n AgentAbort: 'PHW_AGENT_ABORT',\n AgenticDetectionTimeout: 'PHW_AGENTIC_DETECTION_TIMEOUT',\n AgentMcpMissing: 'PHW_AGENT_MCP_MISSING',\n AgentResourceMissing: 'PHW_AGENT_RESOURCE_MISSING',\n AgentRateLimit: 'PHW_AGENT_RATE_LIMIT',\n AgentApiError: 'PHW_AGENT_API_ERROR',\n AgentYaraViolation: 'PHW_AGENT_YARA_VIOLATION',\n AgentNoProgress: 'PHW_AGENT_NO_PROGRESS',\n AgentInvalidStructuredOutput: 'PHW_AGENT_INVALID_STRUCTURED_OUTPUT',\n AgentIncompleteTasks: 'PHW_AGENT_INCOMPLETE_TASKS',\n AgentOrchestratorSkillVariantMissing:\n 'PHW_AGENT_ORCHESTRATOR_SKILL_VARIANT_MISSING',\n AgentOrchestratorTasksFailed: 'PHW_AGENT_ORCHESTRATOR_TASKS_FAILED',\n AgentOrchestratorHollowRun: 'PHW_AGENT_ORCHESTRATOR_HOLLOW_RUN',\n AgentOrchestratorSinkInvariant: 'PHW_AGENT_ORCHESTRATOR_SINK_INVARIANT',\n /** The backend answered the mint with a deliberate refusal. */\n GatewayMintRefused: 'PHW_GATEWAY_MINT_REFUSED',\n /** The mint was unreachable, errored, or returned an unusable token. */\n GatewayMintFailed: 'PHW_GATEWAY_MINT_FAILED',\n SettingsUnfixableConflict: 'PHW_SETTINGS_UNFIXABLE_CONFLICT',\n InternalUnhandled: 'PHW_INTERNAL_UNHANDLED',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\nexport const ERROR_CODE_PATTERN = /^PHW_[A-Z][A-Z0-9_]*$/;\n\nexport function isErrorCode(value: string): value is ErrorCode {\n return (Object.values(ErrorCodes) as string[]).includes(value);\n}\n","import type { ErrorCode } from './codes';\n\nexport const PHW_ERROR_PREFIX = 'phw-error:';\n\nexport interface WizardErrorLine {\n code: ErrorCode;\n message: string;\n detail?: Record<string, unknown>;\n}\n\nexport function formatWizardErrorLine(line: WizardErrorLine): string {\n return `${PHW_ERROR_PREFIX} ${JSON.stringify(line)}`;\n}\n\nexport function emitWizardError(line: WizardErrorLine): void {\n process.stderr.write(`${formatWizardErrorLine(line)}\\n`);\n}\n","import { ErrorCodes, type ErrorCode } from './codes';\nimport type { ErrorCatalogEntry } from './types';\n\nexport const ERROR_CATALOG: Record<ErrorCode, ErrorCatalogEntry> = {\n [ErrorCodes.CliNodeVersion]: {\n group: 'cli',\n retry: 'no',\n description: 'Node.js runtime is older than the required range.',\n },\n [ErrorCodes.CliBadArgs]: {\n group: 'cli',\n retry: 'no',\n description: 'Unrecognized command or option.',\n },\n [ErrorCodes.CliFlagUnavailable]: {\n group: 'cli',\n retry: 'no',\n description: 'A dev-only flag or env var was passed to a published build.',\n },\n [ErrorCodes.CliInteractiveRequired]: {\n group: 'cli',\n retry: 'no',\n description:\n 'The command requires an interactive terminal and has no non-interactive fallback.',\n },\n [ErrorCodes.ArgsMissingApiKey]: {\n group: 'args',\n retry: 'no',\n description: 'Non-interactive run without --api-key.',\n },\n [ErrorCodes.ArgsMissingInstallDir]: {\n group: 'args',\n retry: 'no',\n description: 'Non-interactive run without --install-dir.',\n },\n [ErrorCodes.ArgsMissingEmail]: {\n group: 'args',\n retry: 'no',\n description: 'Signup run without --email.',\n },\n [ErrorCodes.ArgsSignupProvisionFailed]: {\n group: 'args',\n retry: 'yes',\n description: 'Account provisioning for --signup failed.',\n },\n [ErrorCodes.AuthKeyType]: {\n group: 'auth',\n retry: 'no',\n description: 'The API key has the wrong type or prefix for this mode.',\n },\n [ErrorCodes.AuthInvalidOrExpired]: {\n group: 'auth',\n retry: 'no',\n description: 'The credential was rejected by the LLM gateway or API.',\n },\n [ErrorCodes.AuthSessionExpired]: {\n group: 'auth',\n // Retryable, unlike its neighbours: a new run means a new login.\n retry: 'yes',\n description: 'The OAuth grant expired or was revoked mid-run.',\n },\n [ErrorCodes.AuthMissingScope]: {\n group: 'auth',\n retry: 'no',\n description: 'The personal API key lacks a scope the run requires.',\n },\n [ErrorCodes.AuthRegionMismatch]: {\n group: 'auth',\n retry: 'no',\n description: 'The resolved region does not match the credential.',\n },\n [ErrorCodes.AuthSettingsConflict]: {\n group: 'auth',\n retry: 'no',\n description: 'A Claude settings file overrides the gateway credential.',\n },\n [ErrorCodes.AuthStoredLoginConflict]: {\n group: 'auth',\n retry: 'no',\n description:\n 'The agent SDK used a stored Claude login instead of the gateway token.',\n },\n [ErrorCodes.AuthProjectFetchFailed]: {\n group: 'auth',\n retry: 'yes',\n description: 'Fetching user or project data from the PostHog API failed.',\n },\n [ErrorCodes.EnvLocalServicesDown]: {\n group: 'env',\n retry: 'yes',\n description: 'A local dev target service is not running.',\n },\n [ErrorCodes.EnvServiceOutage]: {\n group: 'env',\n retry: 'yes',\n description: 'Blocking external services are down.',\n },\n [ErrorCodes.DetectBadDirectory]: {\n group: 'detect',\n retry: 'no',\n description:\n 'The install directory is missing, not a directory, or unreadable.',\n },\n [ErrorCodes.DetectNoFramework]: {\n group: 'detect',\n retry: 'no',\n description: 'Framework auto-detection found no supported framework.',\n },\n [ErrorCodes.DetectUnsupportedVersion]: {\n group: 'detect',\n retry: 'no',\n description:\n 'The detected framework version is below the supported minimum.',\n },\n [ErrorCodes.DetectUnsupportedPlatform]: {\n group: 'detect',\n retry: 'no',\n description: 'The project platform has no matching skill variant.',\n },\n [ErrorCodes.DetectNoPosthogSdk]: {\n group: 'detect',\n retry: 'no',\n description:\n 'The program requires an installed PostHog SDK and none was found.',\n },\n [ErrorCodes.DetectNoProjectFiles]: {\n group: 'detect',\n retry: 'no',\n description: 'The project has no files for the program to work on.',\n },\n [ErrorCodes.DetectNoSources]: {\n group: 'detect',\n retry: 'no',\n description: 'No data warehouse sources were found.',\n },\n [ErrorCodes.DetectNoPackageJson]: {\n group: 'detect',\n retry: 'no',\n description: 'The project has no package.json for the program to scan.',\n },\n [ErrorCodes.DetectNoSdks]: {\n group: 'detect',\n retry: 'no',\n description: 'None of the SDKs the program needs are installed.',\n },\n [ErrorCodes.DetectMissingStripe]: {\n group: 'detect',\n retry: 'no',\n description: 'Revenue analytics requires a Stripe SDK and none was found.',\n },\n [ErrorCodes.DetectUnclassified]: {\n group: 'detect',\n // A detect step reported a precondition failure we have no code for yet.\n // Every known cause is a property of the user's project, so retrying can\n // only burn budget — fail closed rather than inheriting `internal`'s 'yes'.\n retry: 'no',\n description: 'A detect step failed with a kind absent from the catalog.',\n },\n [ErrorCodes.SkillMenuFetchFailed]: {\n group: 'skill',\n retry: 'yes',\n description: 'The context-mill skill menu could not be fetched.',\n },\n [ErrorCodes.SkillNotFound]: {\n group: 'skill',\n retry: 'no',\n description: 'The skill id is absent from the context-mill menu.',\n },\n [ErrorCodes.SkillDownloadFailed]: {\n group: 'skill',\n retry: 'yes',\n description: 'The skill download or extraction failed.',\n },\n [ErrorCodes.AgentAbort]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The agent emitted an [ABORT] signal with a reason.',\n },\n [ErrorCodes.AgenticDetectionTimeout]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent run exceeded its configured time limit.',\n },\n [ErrorCodes.AgentMcpMissing]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent could not reach the PostHog MCP server.',\n },\n [ErrorCodes.AgentResourceMissing]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent could not access a setup resource.',\n },\n [ErrorCodes.AgentRateLimit]: {\n group: 'agent',\n retry: 'yes',\n description: 'The LLM gateway rate-limited the run.',\n },\n [ErrorCodes.AgentApiError]: {\n group: 'agent',\n retry: 'yes',\n description: 'The agent hit an API error other than a rate limit.',\n },\n [ErrorCodes.AgentYaraViolation]: {\n group: 'agent',\n retry: 'no',\n description: 'The security scanner terminated the run.',\n },\n [ErrorCodes.AgentNoProgress]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The agent ended without a single tool call.',\n },\n [ErrorCodes.AgentInvalidStructuredOutput]: {\n group: 'agent',\n retry: 'yes',\n description:\n 'The agent ended a schema-bound run without output matching the schema.',\n },\n [ErrorCodes.AgentIncompleteTasks]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The agent stopped with planned tasks still open.',\n },\n [ErrorCodes.AgentOrchestratorSkillVariantMissing]: {\n group: 'agent',\n retry: 'yes',\n description: 'The orchestrator could not download a needed skill variant.',\n },\n [ErrorCodes.AgentOrchestratorTasksFailed]: {\n group: 'agent',\n retry: 'case-by-case',\n description: 'The orchestrator queue drained with failed or blocked tasks.',\n },\n [ErrorCodes.AgentOrchestratorHollowRun]: {\n group: 'agent',\n retry: 'yes',\n description:\n 'The orchestrator drained with zero tasks — the seed step got no usable model output.',\n },\n [ErrorCodes.AgentOrchestratorSinkInvariant]: {\n group: 'agent',\n retry: 'no',\n description: 'The orchestrator plan failed the sink coverage invariant.',\n },\n [ErrorCodes.GatewayMintRefused]: {\n group: 'gateway',\n // 429 clears with the daily window, 401 with a fresh login, 403 never.\n retry: 'case-by-case',\n description:\n 'The PostHog backend refused to mint a gateway token for this run.',\n },\n [ErrorCodes.GatewayMintFailed]: {\n group: 'gateway',\n retry: 'yes',\n description:\n 'The PostHog backend could not mint a gateway token: unreachable, a 5xx, or an unusable response.',\n },\n [ErrorCodes.SettingsUnfixableConflict]: {\n group: 'settings',\n retry: 'no',\n description:\n 'A Claude settings conflict cannot be neutralized automatically.',\n },\n [ErrorCodes.InternalUnhandled]: {\n group: 'internal',\n retry: 'yes',\n description: 'An unexpected error escaped the pipeline.',\n },\n};\n","import type { ErrorCode } from './codes';\n\n/**\n * Structured error data for analytics and the machine-readable error line.\n *\n * A data carrier: the agent returns it inside a failure and the legacy adapter\n * hands it to `wizardAbort()`, which captures it. Never thrown by the wizard.\n */\nexport class WizardError extends Error {\n readonly code?: ErrorCode;\n\n constructor(\n message: string,\n public readonly context?: Record<string, unknown>,\n code?: ErrorCode,\n ) {\n super(message);\n this.name = 'WizardError';\n this.code = code;\n }\n}\n","import { ErrorCodes, type ErrorCode } from './codes';\n\nexport interface AuthFailureInput {\n hasSettingsConflict?: boolean;\n usingManagedLogin?: boolean;\n /** A pre-run token refresh already failed on a dead grant this run. */\n sessionExpired?: boolean;\n apiKey?: string;\n missingScopes?: readonly string[];\n gatewayRegion?: 'us' | 'eu' | 'local';\n sessionRegion?: 'us' | 'eu';\n}\n\nexport function classifyAuthFailure(input: AuthFailureInput): ErrorCode {\n // First: the only branch backed by a server verdict rather than inference.\n // The token endpoint already told us the grant is dead, so every heuristic\n // below would be guessing at a cause we know.\n if (input.sessionExpired) return ErrorCodes.AuthSessionExpired;\n if (input.usingManagedLogin) return ErrorCodes.AuthStoredLoginConflict;\n if (input.hasSettingsConflict) return ErrorCodes.AuthSettingsConflict;\n if (\n input.apiKey &&\n !input.apiKey.startsWith('phx_') &&\n !input.apiKey.startsWith('pha_')\n ) {\n return ErrorCodes.AuthKeyType;\n }\n if (input.missingScopes && input.missingScopes.length > 0) {\n return ErrorCodes.AuthMissingScope;\n }\n if (\n input.gatewayRegion &&\n input.sessionRegion &&\n input.gatewayRegion !== 'local' &&\n input.gatewayRegion !== input.sessionRegion\n ) {\n return ErrorCodes.AuthRegionMismatch;\n }\n return ErrorCodes.AuthInvalidOrExpired;\n}\n","import { ErrorCodes, type ErrorCode } from './codes';\nimport type { InstallSkillResult } from '@agent/types';\n\nconst SKILL_CODES: Record<\n Exclude<InstallSkillResult['kind'], 'ok'>,\n ErrorCode\n> = {\n 'menu-fetch-failed': ErrorCodes.SkillMenuFetchFailed,\n 'skill-not-found': ErrorCodes.SkillNotFound,\n 'download-failed': ErrorCodes.SkillDownloadFailed,\n};\n\nexport function skillErrorCode(result: InstallSkillResult): ErrorCode | null {\n if (result.kind === 'ok') return null;\n return SKILL_CODES[result.kind];\n}\n","const DETAIL_ALLOWLIST = ['reason', 'detected', 'platform'] as const;\n\nexport function sanitizeErrorDetail(\n detail: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!detail) return undefined;\n const safe: Record<string, unknown> = {};\n for (const key of DETAIL_ALLOWLIST) {\n if (detail[key] !== undefined) safe[key] = detail[key];\n }\n return Object.keys(safe).length > 0 ? safe : undefined;\n}\n","import { ErrorCodes, isErrorCode, type ErrorCode } from './codes';\n\nexport interface RunFailure {\n code: ErrorCode;\n message: string;\n /** True when the error carried its own code: a decision, not a crash. */\n coded: boolean;\n}\n\n/**\n * How a run's terminal error is reported. A coded WizardError (a mint refusal,\n * say) keeps its own message and code; anything else is unhandled and gets the\n * generic framing. Duck-typed on `code` so callers need not load wizard-abort.\n */\nexport function classifyRunFailure(err: unknown): RunFailure {\n const message = err instanceof Error ? err.message : String(err);\n const code =\n err instanceof Error ? (err as { code?: unknown }).code : undefined;\n if (typeof code === 'string' && isErrorCode(code)) {\n return { code, message, coded: true };\n }\n return { code: ErrorCodes.InternalUnhandled, message, coded: false };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { d as WIZARD_TASK_STREAM_FILE, s as logToFile } from "./debug-Ch4BDOtD.js";
1
+ import { d as WIZARD_TASK_STREAM_FILE, s as logToFile } from "./debug-Cj-8vfXY.js";
2
2
  import { dirname, isAbsolute, resolve } from "node:path";
3
3
  import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
4
- //#region src/lib/task-stream/destinations/file.ts
4
+ //#region src/programs/task-stream/destinations/file.ts
5
5
  /**
6
6
  * Dumps every *attempted* sync to a local JSONL file, one line per push. A line
7
7
  * means the run published that payload, not that a backend accepted it — `--ci`
@@ -57,4 +57,4 @@ function createFileDestination(value, opts = {}) {
57
57
  //#endregion
58
58
  export { FileDestination, createFileDestination };
59
59
 
60
- //# sourceMappingURL=file-BcLTjU16.js.map
60
+ //# sourceMappingURL=file-dEhr-l3n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-dEhr-l3n.js","names":[],"sources":["../src/programs/task-stream/destinations/file.ts"],"sourcesContent":["/**\n * Dumps every *attempted* sync to a local JSONL file, one line per push. A line\n * means the run published that payload, not that a backend accepted it — `--ci`\n * swaps the PostHog destination for this one, so a synthetic run never creates a\n * session row in a real project.\n *\n * Dev builds only: the payload holds the run's handoff report.\n */\n\nimport { appendFileSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { IS_PRODUCTION_BUILD } from '@env';\nimport { WIZARD_TASK_STREAM_FILE } from '@utils/paths';\nimport { logToFile } from '@utils/debug';\nimport type {\n StreamEvent,\n TaskStreamDestination,\n TaskStreamUpdate,\n} from '@programs/task-stream/types';\n\nexport interface FileDestinationOptions {\n path: string;\n /** Override for tests. */\n now?: () => string;\n}\n\nexport class FileDestination implements TaskStreamDestination {\n readonly name = 'file';\n readonly path: string;\n\n private readonly now: () => string;\n private disabled = false;\n\n constructor(opts: FileDestinationOptions) {\n this.path = opts.path;\n this.now = opts.now ?? (() => new Date().toISOString());\n // Truncate up front: one run, one file.\n this.write(() => writeFileSync(this.path, '', { mode: 0o600 }));\n }\n\n send(event: StreamEvent, payload: TaskStreamUpdate): Promise<void> {\n if (!this.disabled) {\n const line = `${JSON.stringify({ at: this.now(), event, payload })}\\n`;\n this.write(() => appendFileSync(this.path, line, { mode: 0o600 }));\n }\n return Promise.resolve();\n }\n\n /** Never throws, never writes to stdio; the first failure ends the dump. */\n private write(op: () => void): void {\n try {\n mkdirSync(dirname(this.path), { recursive: true });\n op();\n } catch (err) {\n this.disabled = true;\n logToFile(\n `[task-stream] file destination disabled (${\n err instanceof Error ? err.message : String(err)\n }): ${this.path}`,\n );\n }\n }\n}\n\n/**\n * Resolve a `--task-stream-log` value, or null when the run did not ask for a\n * dump. `''` and `true` mean the default path — how `--ci` asks for one.\n */\nexport function createFileDestination(\n value: unknown,\n opts: { productionBuild?: boolean; cwd?: string } = {},\n): FileDestination | null {\n if (opts.productionBuild ?? IS_PRODUCTION_BUILD) return null;\n if (value === undefined || value === null || value === false) return null;\n\n const raw = typeof value === 'string' ? value.trim() : '';\n const path =\n raw === ''\n ? WIZARD_TASK_STREAM_FILE\n : isAbsolute(raw)\n ? raw\n : resolve(opts.cwd ?? process.cwd(), raw);\n\n logToFile(`[task-stream] file destination enabled: ${path}`);\n return new FileDestination({ path });\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,IAAa,kBAAb,MAA8D;CAC5D,OAAgB;CAChB;CAEA;CACA,WAAmB;CAEnB,YAAY,MAA8B;AACxC,OAAK,OAAO,KAAK;AACjB,OAAK,MAAM,KAAK,+BAAc,IAAI,MAAM,EAAC,aAAa;AAEtD,OAAK,YAAY,cAAc,KAAK,MAAM,IAAI,EAAE,MAAM,KAAO,CAAC,CAAC;;CAGjE,KAAK,OAAoB,SAA0C;AACjE,MAAI,CAAC,KAAK,UAAU;GAClB,MAAM,OAAO,GAAG,KAAK,UAAU;IAAE,IAAI,KAAK,KAAK;IAAE;IAAO;IAAS,CAAC,CAAC;AACnE,QAAK,YAAY,eAAe,KAAK,MAAM,MAAM,EAAE,MAAM,KAAO,CAAC,CAAC;;AAEpE,SAAO,QAAQ,SAAS;;;CAI1B,MAAc,IAAsB;AAClC,MAAI;AACF,aAAU,QAAQ,KAAK,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAClD,OAAI;WACG,KAAK;AACZ,QAAK,WAAW;AAChB,aACE,4CACE,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACjD,KAAK,KAAK,OACZ;;;;;;;;AASP,SAAgB,sBACd,OACA,OAAoD,EAAE,EAC9B;AACxB,KAAI,KAAK,mBAAA,KAAwC,QAAO;AACxD,KAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,MAAO,QAAO;CAErE,MAAM,MAAM,OAAO,UAAU,WAAW,MAAM,MAAM,GAAG;CACvD,MAAM,OACJ,QAAQ,KACJ,0BACA,WAAW,IAAI,GACf,MACA,QAAQ,KAAK,OAAO,QAAQ,KAAK,EAAE,IAAI;AAE7C,WAAU,2CAA2C,OAAO;AAC5D,QAAO,IAAI,gBAAgB,EAAE,MAAM,CAAC"}
@@ -1,4 +1,4 @@
1
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
1
+ import { s as logToFile } from "./debug-Cj-8vfXY.js";
2
2
  import * as fs$1 from "fs";
3
3
  import { basename, dirname } from "node:path";
4
4
  //#region src/lib/file-watcher.ts
@@ -120,4 +120,4 @@ function startFileWatcher(path, onUpdate, options = {}) {
120
120
  //#endregion
121
121
  export { startFileWatcher as t };
122
122
 
123
- //# sourceMappingURL=file-watcher-DWc_bTs6.js.map
123
+ //# sourceMappingURL=file-watcher-CPM-Nn9L.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-watcher-DWc_bTs6.js","names":["fs"],"sources":["../src/lib/file-watcher.ts"],"sourcesContent":["/**\n * JSON file watcher shared by runner and UI machinery.\n *\n * `fs.watch` alone is unreliable for atomic-rename writes, so the watcher\n * pairs it with a continuous mtime-polled re-read. The poll catches missed\n * events; the watch keeps latency low when it does fire.\n */\n\nimport * as fs from 'fs';\nimport { basename, dirname } from 'node:path';\nimport { logToFile } from '@utils/debug';\n\nconst DEFAULT_POLL_INTERVAL_MS = 5000;\nconst DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1000;\nconst DEFAULT_WATCH_DEBOUNCE_MS = 25;\n\nexport interface FileWatcherHandle {\n refresh(): void;\n stop(): void;\n}\n\nexport interface FileWatcherOptions {\n /** ms between mtime checks once the file exists. */\n pollIntervalMs?: number;\n /** ms between attach attempts while waiting for the file to appear. */\n attachRetryIntervalMs?: number;\n /** ms to coalesce duplicate filesystem events. */\n watchDebounceMs?: number;\n /** Ignore the file that exists when the watcher starts until it changes. */\n ignoreInitialFile?: boolean;\n /** Refuse to read files larger than this many bytes. */\n maxFileSizeBytes?: number;\n}\n\n/** Watch `path` for JSON updates and call `onUpdate(parsed)` whenever the\n * file's mtime changes and the contents are valid JSON. Caller must invoke\n * `handle.stop()` to release the watcher. */\nexport function startFileWatcher(\n path: string,\n onUpdate: (parsed: unknown) => void,\n options: FileWatcherOptions = {},\n): FileWatcherHandle {\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const attachRetryIntervalMs =\n options.attachRetryIntervalMs ?? DEFAULT_ATTACH_RETRY_INTERVAL_MS;\n const watchDebounceMs = options.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS;\n\n const watchers: fs.FSWatcher[] = [];\n const intervals: Array<ReturnType<typeof setInterval>> = [];\n const targetDir = dirname(path);\n const targetName = basename(path);\n let lastMtimeMs = 0;\n let ignoredInitialSignature: string | null = null;\n let watchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let lastReadErrorSignature: string | null = null;\n let stopped = false;\n\n const signature = (stat: fs.Stats): string =>\n `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;\n\n if (options.ignoreInitialFile) {\n try {\n const stat = fs.lstatSync(path);\n if (stat.isFile() && !stat.isSymbolicLink()) {\n ignoredInitialSignature = signature(stat);\n }\n } catch {\n // No initial file to ignore.\n }\n }\n\n const logReadError = (errorSignature: string, message: string) => {\n if (lastReadErrorSignature === errorSignature) return;\n lastReadErrorSignature = errorSignature;\n logToFile(`[file-watcher] ${message}: ${path}`);\n };\n\n const read = (force = false) => {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(path);\n } catch {\n return;\n }\n\n if (!stat.isFile() || stat.isSymbolicLink()) return;\n const fileSignature = signature(stat);\n\n try {\n if (ignoredInitialSignature) {\n if (fileSignature === ignoredInitialSignature) return;\n ignoredInitialSignature = null;\n }\n if (\n options.maxFileSizeBytes !== undefined &&\n stat.size > options.maxFileSizeBytes\n ) {\n logReadError(\n `oversized:${fileSignature}`,\n `refusing oversized JSON file (${stat.size} bytes, limit ${options.maxFileSizeBytes} bytes)`,\n );\n return;\n }\n if (!force && stat.mtimeMs === lastMtimeMs) return;\n lastMtimeMs = stat.mtimeMs;\n const parsed: unknown = JSON.parse(fs.readFileSync(path, 'utf-8'));\n lastReadErrorSignature = null;\n onUpdate(parsed);\n } catch (error) {\n logReadError(\n `invalid:${fileSignature}:${String(error)}`,\n `could not read valid JSON (${String(error)})`,\n );\n }\n };\n\n const scheduleRead = () => {\n if (stopped) return;\n if (watchDebounceTimer) clearTimeout(watchDebounceTimer);\n watchDebounceTimer = setTimeout(() => {\n watchDebounceTimer = null;\n read(true);\n }, watchDebounceMs);\n };\n\n const attachWatch = () => {\n watchers.push(\n fs.watch(targetDir, (_eventType, filename) => {\n if (filename == null || filename.toString() === targetName) {\n scheduleRead();\n }\n }),\n );\n };\n\n intervals.push(setInterval(() => read(), pollIntervalMs));\n\n try {\n attachWatch();\n // Defer the initial callback until the caller has received the handle, so\n // callbacks that stop their watcher cannot race handle assignment.\n queueMicrotask(() => {\n if (!stopped) read(true);\n });\n } catch {\n // Parent directory does not exist yet. Polling still covers a later file;\n // retry attaching the low-latency directory watcher until it appears.\n const attachInterval = setInterval(() => {\n try {\n fs.accessSync(targetDir);\n clearInterval(attachInterval);\n const idx = intervals.indexOf(attachInterval);\n if (idx >= 0) intervals.splice(idx, 1);\n attachWatch();\n read(true);\n } catch {\n // Still waiting.\n }\n }, attachRetryIntervalMs);\n intervals.push(attachInterval);\n }\n\n return {\n refresh() {\n if (stopped) return;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n read(true);\n },\n stop() {\n stopped = true;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n for (const watcher of watchers) watcher.close();\n for (const interval of intervals) clearInterval(interval);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,2BAA2B;AACjC,MAAM,mCAAmC;AACzC,MAAM,4BAA4B;;;;AAuBlC,SAAgB,iBACd,MACA,UACA,UAA8B,EAAE,EACb;CACnB,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,wBACJ,QAAQ,yBAAyB;CACnC,MAAM,kBAAkB,QAAQ,mBAAmB;CAEnD,MAAM,WAA2B,EAAE;CACnC,MAAM,YAAmD,EAAE;CAC3D,MAAM,YAAY,QAAQ,KAAK;CAC/B,MAAM,aAAa,SAAS,KAAK;CACjC,IAAI,cAAc;CAClB,IAAI,0BAAyC;CAC7C,IAAI,qBAA2D;CAC/D,IAAI,yBAAwC;CAC5C,IAAI,UAAU;CAEd,MAAM,aAAa,SACjB,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,KAAK,GAAG,KAAK,QAAQ,GAAG,KAAK;AAE/D,KAAI,QAAQ,kBACV,KAAI;EACF,MAAM,OAAOA,KAAG,UAAU,KAAK;AAC/B,MAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,gBAAgB,CACzC,2BAA0B,UAAU,KAAK;SAErC;CAKV,MAAM,gBAAgB,gBAAwB,YAAoB;AAChE,MAAI,2BAA2B,eAAgB;AAC/C,2BAAyB;AACzB,YAAU,kBAAkB,QAAQ,IAAI,OAAO;;CAGjD,MAAM,QAAQ,QAAQ,UAAU;EAC9B,IAAI;AACJ,MAAI;AACF,UAAOA,KAAG,UAAU,KAAK;UACnB;AACN;;AAGF,MAAI,CAAC,KAAK,QAAQ,IAAI,KAAK,gBAAgB,CAAE;EAC7C,MAAM,gBAAgB,UAAU,KAAK;AAErC,MAAI;AACF,OAAI,yBAAyB;AAC3B,QAAI,kBAAkB,wBAAyB;AAC/C,8BAA0B;;AAE5B,OACE,QAAQ,qBAAqB,KAAA,KAC7B,KAAK,OAAO,QAAQ,kBACpB;AACA,iBACE,aAAa,iBACb,iCAAiC,KAAK,KAAK,gBAAgB,QAAQ,iBAAiB,SACrF;AACD;;AAEF,OAAI,CAAC,SAAS,KAAK,YAAY,YAAa;AAC5C,iBAAc,KAAK;GACnB,MAAM,SAAkB,KAAK,MAAMA,KAAG,aAAa,MAAM,QAAQ,CAAC;AAClE,4BAAyB;AACzB,YAAS,OAAO;WACT,OAAO;AACd,gBACE,WAAW,cAAc,GAAG,OAAO,MAAM,IACzC,8BAA8B,OAAO,MAAM,CAAC,GAC7C;;;CAIL,MAAM,qBAAqB;AACzB,MAAI,QAAS;AACb,MAAI,mBAAoB,cAAa,mBAAmB;AACxD,uBAAqB,iBAAiB;AACpC,wBAAqB;AACrB,QAAK,KAAK;KACT,gBAAgB;;CAGrB,MAAM,oBAAoB;AACxB,WAAS,KACPA,KAAG,MAAM,YAAY,YAAY,aAAa;AAC5C,OAAI,YAAY,QAAQ,SAAS,UAAU,KAAK,WAC9C,eAAc;IAEhB,CACH;;AAGH,WAAU,KAAK,kBAAkB,MAAM,EAAE,eAAe,CAAC;AAEzD,KAAI;AACF,eAAa;AAGb,uBAAqB;AACnB,OAAI,CAAC,QAAS,MAAK,KAAK;IACxB;SACI;EAGN,MAAM,iBAAiB,kBAAkB;AACvC,OAAI;AACF,SAAG,WAAW,UAAU;AACxB,kBAAc,eAAe;IAC7B,MAAM,MAAM,UAAU,QAAQ,eAAe;AAC7C,QAAI,OAAO,EAAG,WAAU,OAAO,KAAK,EAAE;AACtC,iBAAa;AACb,SAAK,KAAK;WACJ;KAGP,sBAAsB;AACzB,YAAU,KAAK,eAAe;;AAGhC,QAAO;EACL,UAAU;AACR,OAAI,QAAS;AACb,OAAI,oBAAoB;AACtB,iBAAa,mBAAmB;AAChC,yBAAqB;;AAEvB,QAAK,KAAK;;EAEZ,OAAO;AACL,aAAU;AACV,OAAI,oBAAoB;AACtB,iBAAa,mBAAmB;AAChC,yBAAqB;;AAEvB,QAAK,MAAM,WAAW,SAAU,SAAQ,OAAO;AAC/C,QAAK,MAAM,YAAY,UAAW,eAAc,SAAS;;EAE5D"}
1
+ {"version":3,"file":"file-watcher-CPM-Nn9L.js","names":["fs"],"sources":["../src/lib/file-watcher.ts"],"sourcesContent":["/**\n * JSON file watcher shared by runner and UI machinery.\n *\n * `fs.watch` alone is unreliable for atomic-rename writes, so the watcher\n * pairs it with a continuous mtime-polled re-read. The poll catches missed\n * events; the watch keeps latency low when it does fire.\n */\n\nimport * as fs from 'fs';\nimport { basename, dirname } from 'node:path';\nimport { logToFile } from '@utils/debug';\n\nconst DEFAULT_POLL_INTERVAL_MS = 5000;\nconst DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1000;\nconst DEFAULT_WATCH_DEBOUNCE_MS = 25;\n\nexport interface FileWatcherHandle {\n refresh(): void;\n stop(): void;\n}\n\nexport interface FileWatcherOptions {\n /** ms between mtime checks once the file exists. */\n pollIntervalMs?: number;\n /** ms between attach attempts while waiting for the file to appear. */\n attachRetryIntervalMs?: number;\n /** ms to coalesce duplicate filesystem events. */\n watchDebounceMs?: number;\n /** Ignore the file that exists when the watcher starts until it changes. */\n ignoreInitialFile?: boolean;\n /** Refuse to read files larger than this many bytes. */\n maxFileSizeBytes?: number;\n}\n\n/** Watch `path` for JSON updates and call `onUpdate(parsed)` whenever the\n * file's mtime changes and the contents are valid JSON. Caller must invoke\n * `handle.stop()` to release the watcher. */\nexport function startFileWatcher(\n path: string,\n onUpdate: (parsed: unknown) => void,\n options: FileWatcherOptions = {},\n): FileWatcherHandle {\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const attachRetryIntervalMs =\n options.attachRetryIntervalMs ?? DEFAULT_ATTACH_RETRY_INTERVAL_MS;\n const watchDebounceMs = options.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS;\n\n const watchers: fs.FSWatcher[] = [];\n const intervals: Array<ReturnType<typeof setInterval>> = [];\n const targetDir = dirname(path);\n const targetName = basename(path);\n let lastMtimeMs = 0;\n let ignoredInitialSignature: string | null = null;\n let watchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let lastReadErrorSignature: string | null = null;\n let stopped = false;\n\n const signature = (stat: fs.Stats): string =>\n `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;\n\n if (options.ignoreInitialFile) {\n try {\n const stat = fs.lstatSync(path);\n if (stat.isFile() && !stat.isSymbolicLink()) {\n ignoredInitialSignature = signature(stat);\n }\n } catch {\n // No initial file to ignore.\n }\n }\n\n const logReadError = (errorSignature: string, message: string) => {\n if (lastReadErrorSignature === errorSignature) return;\n lastReadErrorSignature = errorSignature;\n logToFile(`[file-watcher] ${message}: ${path}`);\n };\n\n const read = (force = false) => {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(path);\n } catch {\n return;\n }\n\n if (!stat.isFile() || stat.isSymbolicLink()) return;\n const fileSignature = signature(stat);\n\n try {\n if (ignoredInitialSignature) {\n if (fileSignature === ignoredInitialSignature) return;\n ignoredInitialSignature = null;\n }\n if (\n options.maxFileSizeBytes !== undefined &&\n stat.size > options.maxFileSizeBytes\n ) {\n logReadError(\n `oversized:${fileSignature}`,\n `refusing oversized JSON file (${stat.size} bytes, limit ${options.maxFileSizeBytes} bytes)`,\n );\n return;\n }\n if (!force && stat.mtimeMs === lastMtimeMs) return;\n lastMtimeMs = stat.mtimeMs;\n const parsed: unknown = JSON.parse(fs.readFileSync(path, 'utf-8'));\n lastReadErrorSignature = null;\n onUpdate(parsed);\n } catch (error) {\n logReadError(\n `invalid:${fileSignature}:${String(error)}`,\n `could not read valid JSON (${String(error)})`,\n );\n }\n };\n\n const scheduleRead = () => {\n if (stopped) return;\n if (watchDebounceTimer) clearTimeout(watchDebounceTimer);\n watchDebounceTimer = setTimeout(() => {\n watchDebounceTimer = null;\n read(true);\n }, watchDebounceMs);\n };\n\n const attachWatch = () => {\n watchers.push(\n fs.watch(targetDir, (_eventType, filename) => {\n if (filename == null || filename.toString() === targetName) {\n scheduleRead();\n }\n }),\n );\n };\n\n intervals.push(setInterval(() => read(), pollIntervalMs));\n\n try {\n attachWatch();\n // Defer the initial callback until the caller has received the handle, so\n // callbacks that stop their watcher cannot race handle assignment.\n queueMicrotask(() => {\n if (!stopped) read(true);\n });\n } catch {\n // Parent directory does not exist yet. Polling still covers a later file;\n // retry attaching the low-latency directory watcher until it appears.\n const attachInterval = setInterval(() => {\n try {\n fs.accessSync(targetDir);\n clearInterval(attachInterval);\n const idx = intervals.indexOf(attachInterval);\n if (idx >= 0) intervals.splice(idx, 1);\n attachWatch();\n read(true);\n } catch {\n // Still waiting.\n }\n }, attachRetryIntervalMs);\n intervals.push(attachInterval);\n }\n\n return {\n refresh() {\n if (stopped) return;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n read(true);\n },\n stop() {\n stopped = true;\n if (watchDebounceTimer) {\n clearTimeout(watchDebounceTimer);\n watchDebounceTimer = null;\n }\n for (const watcher of watchers) watcher.close();\n for (const interval of intervals) clearInterval(interval);\n },\n };\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { d as ErrorCodes, l as WizardError } from "./errors-CQ9kttJD.js";
2
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
3
- import { n as analytics } from "./analytics-CHCZ_qUR.js";
4
- import { t as checkLlmGatewayHealth } from "./endpoints-DCVbM06L.js";
5
- import { a as oauthLoginKey } from "./oauth-session-DJ8h6GFa.js";
6
- import { i as modelCapabilities } from "./models-DDdBJKwT.js";
1
+ import { a as WizardError, s as ErrorCodes } from "./errors-ddDE6MbA.js";
2
+ import { s as logToFile } from "./debug-Cj-8vfXY.js";
3
+ import { n as analytics } from "./analytics-VRYdebXW.js";
4
+ import { t as checkLlmGatewayHealth } from "./endpoints-DnIX0pZH.js";
5
+ import { a as oauthLoginKey } from "./oauth-session-CQTFOk-I.js";
6
+ import { i as modelCapabilities } from "./models-DnAY67Lg.js";
7
7
  import "node:fs";
8
8
  //#region src/agent/gateway-session.ts
9
9
  /**
@@ -259,6 +259,36 @@ function stripPropertyPrefix(key) {
259
259
  return key.toUpperCase().startsWith(LEGACY_PROPERTY_PREFIX) ? key.slice(19).toLowerCase() : key;
260
260
  }
261
261
  //#endregion
262
+ //#region src/agent/signals.ts
263
+ /**
264
+ * Agent signal vocabulary — the marker strings the agent emits and the error
265
+ * taxonomy the runner returns. Kept as a dependency-free leaf module so both
266
+ * `agent-interface.ts` and `output-signals.ts` can import it without a cycle.
267
+ */
268
+ const AgentSignals = {
269
+ STATUS: "[STATUS]",
270
+ ERROR_MCP_MISSING: "[ERROR-MCP-MISSING]",
271
+ ERROR_RESOURCE_MISSING: "[ERROR-RESOURCE-MISSING]",
272
+ SKILL_INSTALL_FAILED: "[SKILL-INSTALL-FAILED]",
273
+ ABORT: "[ABORT]",
274
+ WIZARD_REMARK: "[WIZARD-REMARK]",
275
+ BENCHMARK: "[BENCHMARK]",
276
+ DASHBOARD_URL: "[DASHBOARD_URL]",
277
+ NOTEBOOK_URL: "[NOTEBOOK_URL]"
278
+ };
279
+ /**
280
+ * End-of-run reflection ask, shared by both harnesses so remarks are
281
+ * comparable. The format clause comes FIRST and nothing trails the marker —
282
+ * literal models (gpt-5-mini) echo whatever text follows it. The parser also
283
+ * drops remarks that quote this instruction (see AgentOutputSignals.remark).
284
+ */
285
+ const REMARK_INSTRUCTION = `Reply with a single line that starts with ${AgentSignals.WIZARD_REMARK} and no other lines. In that line, state briefly what information or guidance would have been useful to have in the integration prompt or documentation for this run — specifically anything that would have prevented tool failures, erroneous edits, or other wasted turns.`;
286
+ /**
287
+ * First prompt of a session resumed after a mid-run re-mint. The transcript
288
+ * carries the work so far; the model only needs to pick it up.
289
+ */
290
+ const RESUME_INSTRUCTION = "Your previous request failed with a transient gateway authentication error that has since been fixed. Continue the task from where you left off.";
291
+ //#endregion
262
292
  //#region src/agent/runner/harness/pi/gateway.ts
263
293
  /**
264
294
  * PostHog AI gateway provider spec for pi sessions, shared by the linear run
@@ -421,6 +451,6 @@ function withGatewayRemint(opts) {
421
451
  };
422
452
  }
423
453
  //#endregion
424
- export { gatewayTerminalFailure as a, configureGatewayFromCIEnvironment as c, gatewayApiFor as i, gatewayAuth as l, buildGatewayModel as n, withGatewayRemint as o, buildGatewayProvider as r, buildWizardPropertiesBlob as s, GATEWAY_PROVIDER as t, isPastRefresh as u };
454
+ export { gatewayTerminalFailure as a, REMARK_INSTRUCTION as c, configureGatewayFromCIEnvironment as d, gatewayAuth as f, gatewayApiFor as i, RESUME_INSTRUCTION as l, buildGatewayModel as n, withGatewayRemint as o, isPastRefresh as p, buildGatewayProvider as r, AgentSignals as s, GATEWAY_PROVIDER as t, buildWizardPropertiesBlob as u };
425
455
 
426
- //# sourceMappingURL=gateway-CjoShdLa.js.map
456
+ //# sourceMappingURL=gateway-CVU1G0H3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-CVU1G0H3.js","names":[],"sources":["../src/agent/gateway-session.ts","../src/agent/signals.ts","../src/agent/runner/harness/pi/gateway.ts"],"sourcesContent":["/**\n * Gateway auth for a wizard run: a `phe_` scoped token the backend mints, with\n * pinned attribution, a spend cap and an expiry.\n *\n * Every mint failure throws: a silent downgrade would spend uncapped,\n * unattributed money to hide an outage.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { logToFile } from '@utils/debug';\nimport { analytics } from '@utils/analytics';\nimport { ErrorCodes, WizardError } from '@shared/errors';\nimport type { HostResolution } from '@shared/host-resolution';\nimport { oauthLoginKey } from '@shared/oauth-session';\nimport { checkLlmGatewayHealth } from '@shared/health-checks/endpoints';\nimport { ServiceHealthStatus } from '@shared/health-checks/types';\nimport { IS_PRODUCTION_BUILD, runtimeEnv } from '@env';\nimport type { CloudRegion } from '@utils/types';\n\nexport interface GatewayAuth {\n /** Base URL for model calls (no `/v1`; transports append their route). */\n gatewayUrl: string;\n /** Gateway bearer, minted normally or supplied directly by CI. */\n token: string;\n /** Team verified by the mint, or explicitly supplied for CI attribution. */\n teamId?: number;\n /**\n * Instant past which a 401 on this bearer is age rather than a bad\n * credential: the cache re-mints past it, and a session still holding the\n * old bearer may re-mint once. Before it the mint has to be trusted.\n */\n refreshAtMs: number;\n}\n\ninterface CachedAuth {\n key: string;\n auth: GatewayAuth;\n /** Re-resolve once past this instant. */\n staleAtMs: number;\n}\n\nlet cached: CachedAuth | null = null;\n/**\n * Shared so concurrent callers mint once. The orchestrator starts every runnable\n * task at once, and each would otherwise take its own token and its own cap.\n */\nlet inFlight: { key: string; promise: Promise<GatewayAuth> } | null = null;\nlet ciAuth: GatewayAuth | null = null;\n\n// Snapshot CI supplies a gateway bearer without minting or re-minting.\nexport function configureGatewayCredentialsForCI(\n token: string,\n projectId: number,\n gatewayUrl: string,\n): void {\n if (IS_PRODUCTION_BUILD)\n throw new Error('CI gateway auth requires a non-production build');\n if (!token.trim() || !Number.isSafeInteger(projectId) || projectId <= 0) {\n throw new Error('CI gateway auth requires a token and valid project ID');\n }\n if (\n !/^https?:\\/\\//.test(gatewayUrl) ||\n !isTrustedGatewayUrl(gatewayUrl, '')\n ) {\n throw new Error('CI gateway auth requires a trusted gateway origin');\n }\n resetGatewaySession();\n ciAuth = {\n token: token.trim(),\n teamId: projectId,\n gatewayUrl: gatewayUrl.replace(/\\/+$/, ''),\n refreshAtMs: Infinity,\n };\n}\n\n// TODO: CI credential loading belongs outside the agent. It leaves with the rest\n// of this module once RunInput carries resolved inference auth, later in the\n// refactor.\nexport function configureGatewayFromCIEnvironment(\n projectId: number,\n region: CloudRegion,\n): void {\n if (IS_PRODUCTION_BUILD)\n throw new Error('CI gateway auth requires a non-production build');\n const path = runtimeEnv('WIZARD_CI_GATEWAY_TOKEN_FILE');\n if (!path) throw new Error('WIZARD_CI_GATEWAY_TOKEN_FILE is required for CI');\n const token = readFileSync(path, 'utf8');\n delete process.env.WIZARD_CI_GATEWAY_TOKEN_FILE;\n configureGatewayCredentialsForCI(\n token,\n projectId,\n runtimeEnv('WIZARD_CI_GATEWAY_URL') ||\n `https://ai-gateway.${region}.posthog.com`,\n );\n}\n\n/**\n * Adoption floor. The anthropic subprocess holds its credential until a 401\n * forces a re-mint, so a token below this would churn mints.\n */\nconst MIN_USABLE_TTL_MS = 2 * 60 * 1000;\n/** Re-resolve at this fraction of the token's life, leaving a usable remainder. */\nconst REFRESH_AT_FRACTION = 0.8;\n// Exceeds the backend's own 10s gateway timeout: a slow mint that lands after the\n// CLI hangs up spends a daily mint and orphans a live token.\nconst MINT_TIMEOUT_MS = 20_000;\n/** Longer than any refusal the mint writes; a body past this is not a message. */\nconst MAX_REFUSAL_DETAIL_LENGTH = 500;\n/** Outcomes are short snake_case labels; anything longer is not one. */\nconst MAX_REFUSAL_OUTCOME_LENGTH = 64;\n\n/** Resolve this run's gateway auth, minting and re-minting near expiry. */\nexport async function gatewayAuth(\n host: HostResolution,\n accessToken: string,\n program: string | undefined,\n): Promise<GatewayAuth> {\n if (ciAuth) return ciAuth;\n // Keyed by program: a token pins `wizard:<program>`, so reusing one across\n // programs bills the wrong budget. Keyed by login rather than OAuth token:\n // the token rotates mid-run, and each new one would spend a weekly mint.\n const key = `${host.apiHost}\\n${oauthLoginKey(accessToken)}\\n${\n program ?? ''\n }`;\n if (cached && cached.key === key && Date.now() < cached.staleAtMs) {\n return cached.auth;\n }\n if (inFlight && inFlight.key === key) return inFlight.promise;\n const promise = resolveGatewayAuth(host, accessToken, key, program);\n inFlight = { key, promise };\n try {\n return await promise;\n } finally {\n if (inFlight?.promise === promise) inFlight = null;\n }\n}\n\nasync function resolveGatewayAuth(\n host: HostResolution,\n accessToken: string,\n key: string,\n program: string | undefined,\n): Promise<GatewayAuth> {\n if (!program) {\n // Every run has one; absent means a caller was not wired, and the spend would\n // be unattributable.\n logToFile('[gateway] run has no program id; failing the run');\n throw new GatewayMintFailed(\n 'this run has no program to attribute its spend to',\n );\n }\n const minted = await mintGatewayToken(host, accessToken, program);\n const health = await checkLlmGatewayHealth(minted.gatewayUrl);\n if (health.status !== ServiceHealthStatus.Healthy) {\n throw new WizardError(\n 'The PostHog AI gateway is unavailable. Please try again later.',\n undefined,\n ErrorCodes.EnvServiceOutage,\n );\n }\n const expiresAtMs = Date.parse(minted.expiresAt);\n const ttlMs = expiresAtMs - Date.now();\n if (!Number.isFinite(expiresAtMs) || ttlMs < MIN_USABLE_TTL_MS) {\n // Expired, unreadable, or too short to serve a session. Adopting it would\n // 401 mid-run, and downgrading would spend the rest of the run uncapped.\n logToFile(\n `[gateway] mint returned a token with ${ttlMs}ms of life; failing the run`,\n );\n throw new GatewayMintFailed(\n `the PostHog gateway issued a token with ${ttlMs}ms of life`,\n );\n }\n const staleAtMs = Date.now() + ttlMs * REFRESH_AT_FRACTION;\n // Only failures are logged otherwise, so a successful run leaves no\n // local trace. Never log the token itself.\n logToFile(\n `[gateway] minted a scoped token: program=${program} team=${\n minted.teamId ?? 'unknown'\n } ttl=${Math.round(ttlMs / 1000)}s url=${minted.gatewayUrl}`,\n );\n const auth: GatewayAuth = {\n gatewayUrl: minted.gatewayUrl,\n token: minted.token,\n teamId: minted.teamId,\n refreshAtMs: staleAtMs,\n };\n cached = { key, auth, staleAtMs };\n return auth;\n}\n\n/** Test hook: drop the cached auth so the next call re-resolves. */\nexport function resetGatewaySession(): void {\n cached = null;\n inFlight = null;\n ciAuth = null;\n}\n\n/** Whether a 401 on this bearer may be age (past its refresh instant) rather than a bad credential. */\nexport function isPastRefresh(auth: GatewayAuth, now = Date.now()): boolean {\n return now >= auth.refreshAtMs;\n}\n\n/**\n * Whether a server-supplied origin may receive a bearer and prompt content:\n * https (loopback excepted), and either a current cloud gateway or the host the run\n * authenticated against.\n */\nexport function isTrustedGatewayUrl(value: string, apiHost: string): boolean {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return false;\n }\n // Consumers append routes to this value, so anything beyond an origin\n // (path, query, fragment, userinfo) would build a malformed endpoint.\n if (\n url.pathname !== '/' ||\n url.search ||\n url.hash ||\n url.username ||\n url.password\n ) {\n return false;\n }\n const localhost =\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === 'host.docker.internal';\n // Loopback is the dev gateway, and is the one case allowed over http.\n if (localhost) return true;\n if (url.protocol !== 'https:') return false;\n if (url.hostname.endsWith('.posthog.com')) {\n return (\n url.origin === 'https://ai-gateway.us.posthog.com' ||\n url.origin === 'https://ai-gateway.eu.posthog.com'\n );\n }\n try {\n return url.hostname === new URL(apiHost).hostname;\n } catch {\n return false;\n }\n}\n\ninterface MintedToken {\n token: string;\n expiresAt: string;\n gatewayUrl: string;\n teamId?: number;\n}\n\n/**\n * A deliberate refusal from the mint endpoint, as opposed to the mint being\n * unavailable. Thrown so the run stops instead of proceeding without the\n * controls the refusal was enforcing. A WizardError, so the runners print its\n * message as-is and `wizardAbort` resolves its code.\n */\nexport class GatewayMintRefused extends WizardError {\n readonly status: number;\n /** The backend's refusal outcome (`blocked`, `throttled`, ...), when it sent one. */\n readonly outcome?: string;\n\n constructor(status: number, message: string, outcome?: string) {\n super(message, { status, outcome }, ErrorCodes.GatewayMintRefused);\n this.name = 'GatewayMintRefused';\n this.status = status;\n this.outcome = outcome;\n }\n}\n\n/**\n * The mint could not produce a usable credential: unreachable, a 5xx, or a\n * response the client cannot use.\n */\nexport class GatewayMintFailed extends WizardError {\n constructor(message: string) {\n super(message, undefined, ErrorCodes.GatewayMintFailed);\n this.name = 'GatewayMintFailed';\n }\n}\n\n/**\n * Whether a mint status means \"refused this run\" rather than \"not available\".\n * 429 the daily run limit, 403 revoked project access, 400 a login covering\n * more than one project, 401 a credential the mint does not accept, 404 an\n * instance without the mint endpoint.\n */\nfunction isMintRefusal(status: number): boolean {\n return (\n status === 400 ||\n status === 401 ||\n status === 403 ||\n status === 404 ||\n status === 429\n );\n}\n\ninterface MintRefusal {\n detail?: string;\n outcome?: string;\n}\n\n/**\n * The server's own reason for a refusal, when it sent one. DRF answers every\n * refusal as `{\"detail\": \"...\", \"code\": \"<outcome>\"}`; the blocklist's detail\n * names the contact address, which the fixed messages below cannot. `code` is\n * the backend's own label for the refusal (`outcome` on older backends) and\n * rides the client event.\n */\nfunction cleanRefusalText(value: unknown): string {\n if (typeof value !== 'string') return '';\n // Not because the server sends escapes, but because this string is printed\n // straight to a terminal: sanitizing at the boundary means no later message\n // can move the cursor or repaint the screen.\n // eslint-disable-next-line no-control-regex\n return value.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/g, ' ').trim();\n}\n\nasync function readRefusal(resp: Response): Promise<MintRefusal> {\n try {\n const body = (await resp.json()) as {\n detail?: unknown;\n code?: unknown;\n outcome?: unknown;\n };\n const detail = cleanRefusalText(body?.detail);\n // The DRF handler flattens a dict detail, so the outcome rides as `code`.\n // A `code` that cleans to nothing does not shadow a usable `outcome`.\n const outcome =\n cleanRefusalText(body?.code) || cleanRefusalText(body?.outcome);\n return {\n detail:\n detail.length > 0 && detail.length <= MAX_REFUSAL_DETAIL_LENGTH\n ? detail\n : undefined,\n outcome:\n outcome.length > 0 && outcome.length <= MAX_REFUSAL_OUTCOME_LENGTH\n ? outcome\n : undefined,\n };\n } catch {\n return {};\n }\n}\n\nfunction mintRefusalMessage(status: number, detail?: string): string {\n if (detail) return detail;\n switch (status) {\n case 429:\n return 'This wizard program has used its daily run limit. Try again tomorrow.';\n case 403:\n return 'Your access to this project has changed. Re-authenticate and try again.';\n case 400:\n // The only 400 the mint answers is the exactly-one-project check.\n return 'Your PostHog login must cover exactly one project. Re-authenticate and try again.';\n case 401:\n return 'PostHog did not accept this login. Re-authenticate with `npx @posthog/wizard@latest`.';\n case 404:\n return 'This PostHog instance does not issue gateway tokens. Upgrade with `npx @posthog/wizard@latest` and try again.';\n default:\n return 'The PostHog gateway refused this run.';\n }\n}\n\nasync function mintGatewayToken(\n host: HostResolution,\n accessToken: string,\n program: string,\n): Promise<MintedToken> {\n try {\n const resp = await fetch(`${host.apiHost}/api/wizard/gateway_token/`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n // The flag tells the server this build reads a refusal, so it may answer\n // with the reason. A build that omits it gets a 404, which is its signal\n // to fall back to the legacy gateway.\n body: JSON.stringify({ program, reads_refusal_reason: true }),\n signal: AbortSignal.timeout(MINT_TIMEOUT_MS),\n });\n if (!resp.ok) {\n if (isMintRefusal(resp.status)) {\n const refusal = await readRefusal(resp);\n logToFile(\n `[gateway] mint refused with HTTP ${resp.status} (${\n refusal.outcome ?? 'no outcome'\n }); failing the run`,\n );\n // The terminal denial event for this run. The backend's own event has\n // no run id, so this is what joins a refusal to the session.\n analytics.wizardCapture('gateway mint refused', {\n status: resp.status,\n outcome: refusal.outcome,\n program,\n });\n throw new GatewayMintRefused(\n resp.status,\n mintRefusalMessage(resp.status, refusal.detail),\n refusal.outcome,\n );\n }\n logToFile(\n `[gateway] mint failed with HTTP ${resp.status}; failing the run`,\n );\n throw new GatewayMintFailed(\n `the PostHog gateway could not issue a token (HTTP ${resp.status})`,\n );\n }\n const body = (await resp.json()) as {\n token?: string;\n expires_at?: string;\n gateway_url?: string;\n team_id?: number;\n };\n // Checked one at a time, not in a loop, so each clause narrows the optional\n // field for the return below and each names itself in the failure.\n if (!body.token) {\n logToFile('[gateway] mint response omitted token; failing the run');\n throw new GatewayMintFailed('mint response omitted token');\n }\n if (!body.expires_at) {\n logToFile('[gateway] mint response omitted expires_at; failing the run');\n throw new GatewayMintFailed('mint response omitted expires_at');\n }\n if (!body.gateway_url) {\n logToFile('[gateway] mint response omitted gateway_url; failing the run');\n throw new GatewayMintFailed('mint response omitted gateway_url');\n }\n if (!isTrustedGatewayUrl(body.gateway_url, host.apiHost)) {\n logToFile(\n '[gateway] mint returned an untrusted gateway url; failing the run',\n );\n throw new GatewayMintFailed('mint returned an untrusted gateway url');\n }\n const gatewayUrl = new URL(body.gateway_url);\n if (\n ['localhost', '127.0.0.1'].includes(new URL(host.apiHost).hostname) &&\n gatewayUrl.hostname === 'host.docker.internal'\n ) {\n gatewayUrl.hostname = 'localhost';\n }\n return {\n token: body.token,\n expiresAt: body.expires_at,\n gatewayUrl: gatewayUrl.origin,\n teamId: body.team_id,\n };\n } catch (e) {\n // Decisions and failures both pass through: this catch exists for transport\n // errors, and folding the others into it would lose the reason.\n if (e instanceof GatewayMintRefused || e instanceof GatewayMintFailed)\n throw e;\n logToFile(\n `[gateway] mint transport failure (${String(e)}); failing the run`,\n );\n throw new GatewayMintFailed(\n `could not reach the PostHog gateway (${String(e)})`,\n );\n }\n}\n\n/**\n * The v2 run-metadata carrier: one JSON blob for the `X-PostHog-Properties`\n * header. Plain keys only, since the gateway strips `$`-prefixed keys as reserved,\n * so feature-flag variants land as `wizard_flag_<key>` instead of the legacy\n * `$feature/<key>` (dashboards keying on `$feature/wizard-*` read the new key\n * post-cutover).\n */\nexport function buildWizardPropertiesBlob(\n wizardMetadata: Record<string, string>,\n wizardFlags: Record<string, string>,\n teamId?: number,\n): string {\n // The gateway pins `$ai_product` to `wizard:<program>`, and rejects a legacy\n // product override on a scoped token, so the unprefixed key every cost and\n // error consumer reads is only present if this blob declares it.\n const props: Record<string, string | number> = { ai_product: 'wizard' };\n if (teamId !== undefined) props.team_id = teamId;\n for (const [key, value] of Object.entries(wizardMetadata)) {\n props[stripPropertyPrefix(key)] = value;\n }\n for (const [flagKey, variant] of Object.entries(wizardFlags)) {\n if (!flagKey.toLowerCase().startsWith('wizard')) continue;\n props[`wizard_flag_${flagKey.toLowerCase()}`] = variant;\n }\n return JSON.stringify(props);\n}\n\nconst LEGACY_PROPERTY_PREFIX = 'X-POSTHOG-PROPERTY-';\n\nfunction stripPropertyPrefix(key: string): string {\n return key.toUpperCase().startsWith(LEGACY_PROPERTY_PREFIX)\n ? key.slice(LEGACY_PROPERTY_PREFIX.length).toLowerCase()\n : key;\n}\n","/**\n * Agent signal vocabulary — the marker strings the agent emits and the error\n * taxonomy the runner returns. Kept as a dependency-free leaf module so both\n * `agent-interface.ts` and `output-signals.ts` can import it without a cycle.\n */\n\nexport const AgentSignals = {\n /** Signal emitted when the agent reports progress to the user */\n STATUS: '[STATUS]',\n /** Signal emitted when the agent cannot access the PostHog MCP server */\n ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',\n /** Signal emitted when the agent cannot access the setup resource */\n ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',\n /**\n * Signal emitted when `install_skill` failed and the agent is continuing\n * the integration WITHOUT the skill (best-effort from its own knowledge).\n * Format: \"[SKILL-INSTALL-FAILED] <skill id — reason>\". Non-fatal by\n * design: a freestyled integration beats an outright failure, but the run\n * must be measurable — the runner captures it as an analytics event.\n */\n SKILL_INSTALL_FAILED: '[SKILL-INSTALL-FAILED]',\n /**\n * Signal emitted when the agent cannot complete the program and is\n * aborting intentionally (distinct from errors). Format: \"[ABORT] <reason>\".\n * Programs can declare an onAbort handler to render a custom screen.\n */\n ABORT: '[ABORT]',\n /** Signal emitted when the agent provides a remark about its run */\n WIZARD_REMARK: '[WIZARD-REMARK]',\n /** Signal prefix for benchmark logging */\n BENCHMARK: '[BENCHMARK]',\n /**\n * Signal emitted when the agent has created a PostHog dashboard for the\n * user. Format: `[DASHBOARD_URL] <full https url>`. The URL is captured\n * onto `session.dashboardUrl` and surfaced by programs in their outro.\n */\n DASHBOARD_URL: '[DASHBOARD_URL]',\n /**\n * Signal emitted when the agent has uploaded a report to a PostHog\n * notebook. Format: `[NOTEBOOK_URL] <full https url>`. The URL is captured\n * onto `session.notebookUrl` and surfaced by programs in their outro.\n */\n NOTEBOOK_URL: '[NOTEBOOK_URL]',\n} as const;\n\nexport type AgentSignal = (typeof AgentSignals)[keyof typeof AgentSignals];\n\n/**\n * End-of-run reflection ask, shared by both harnesses so remarks are\n * comparable. The format clause comes FIRST and nothing trails the marker —\n * literal models (gpt-5-mini) echo whatever text follows it. The parser also\n * drops remarks that quote this instruction (see AgentOutputSignals.remark).\n */\nexport const REMARK_INSTRUCTION = `Reply with a single line that starts with ${AgentSignals.WIZARD_REMARK} and no other lines. In that line, state briefly what information or guidance would have been useful to have in the integration prompt or documentation for this run — specifically anything that would have prevented tool failures, erroneous edits, or other wasted turns.`;\n\n/**\n * First prompt of a session resumed after a mid-run re-mint. The transcript\n * carries the work so far; the model only needs to pick it up.\n */\nexport const RESUME_INSTRUCTION =\n 'Your previous request failed with a transient gateway authentication error that has since been fixed. Continue the task from where you left off.';\n\n/**\n * Error types that can be returned from agent execution.\n * These correspond to the error signals that the agent emits.\n */\nexport enum AgentErrorType {\n /** The configured run deadline elapsed and the SDK query was aborted */\n AGENTIC_DETECTION_TIMEOUT = 'WIZARD_AGENTIC_DETECTION_TIMEOUT',\n /** Agent could not access the PostHog MCP server */\n MCP_MISSING = 'WIZARD_MCP_MISSING',\n /** Agent could not access the setup resource */\n RESOURCE_MISSING = 'WIZARD_RESOURCE_MISSING',\n /** API rate limit exceeded */\n RATE_LIMIT = 'WIZARD_RATE_LIMIT',\n /** Generic API error */\n API_ERROR = 'WIZARD_API_ERROR',\n /** YARA scanner detected a security violation */\n YARA_VIOLATION = 'WIZARD_YARA_VIOLATION',\n /** Agent intentionally aborted the program (emitted [ABORT] <reason>) */\n ABORT = 'WIZARD_ABORT',\n /** Agent ended without making a single tool call — a no-op run that did no work */\n NO_PROGRESS = 'WIZARD_NO_PROGRESS',\n /** A schema-bound run ended without output matching its schema */\n INVALID_STRUCTURED_OUTPUT = 'WIZARD_INVALID_STRUCTURED_OUTPUT',\n /** Agent acted but stopped short — planned tasks left open and/or no skill installed */\n INCOMPLETE_TASKS = 'WIZARD_INCOMPLETE_TASKS',\n}\n","/**\n * PostHog AI gateway provider spec for pi sessions, shared by the linear run\n * and the orchestrator's per-task runs so both speak to the gateway\n * identically: bearer auth, the wizard properties header, transport shape\n * inferred from the model id. The caller registers the spec on its own\n * (lazily imported, properly typed) pi ModelRegistry.\n */\n\nimport {\n buildWizardPropertiesBlob,\n isPastRefresh,\n type GatewayAuth,\n} from '@agent/gateway-session';\nimport {\n modelCapabilities,\n type ThinkingLevel,\n} from '../../switchboard/models';\nimport { AgentErrorType } from '@agent/signals';\n\n/** Provider registered on the in-memory registry for this run. */\nexport const GATEWAY_PROVIDER = 'posthog-gateway';\n\n/** The pi transports the gateway serves. */\nexport type GatewayApi =\n | 'anthropic-messages'\n | 'openai-completions'\n | 'openai-responses';\n\n/**\n * The gateway speaks two shapes on two endpoints: Anthropic models over\n * `anthropic-messages` (the SDK appends `/v1/messages`, so the base URL has no\n * `/v1`), and OpenAI-class models (`openai/gpt-5`, …) over an OpenAI shape at\n * `/v1/responses` or `/v1/chat/completions` (base URL keeps `/v1`). Infer the\n * shape from the model id so a pair's model selects the right transport.\n *\n * OpenAI models take the Responses API because OpenAI rejects function tools\n * combined with `reasoning_effort` on chat completions and every task sends both.\n */\nexport function gatewayApiFor(modelId: string): GatewayApi {\n return modelId.startsWith('openai/')\n ? 'openai-responses'\n : 'anthropic-messages';\n}\n\n/**\n * Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path: one\n * `X-PostHog-Properties` JSON blob (Bedrock fallback is native, so no opt-in)\n * plus the 1M context beta, since pi otherwise runs at 200k and overflows on\n * larger projects (the post-run compaction failures).\n */\nexport function buildGatewayHeaders(\n wizardMetadata: Record<string, string>,\n wizardFlags: Record<string, string>,\n teamId?: number,\n): Record<string, string> {\n return {\n 'anthropic-beta': 'context-1m-2025-08-07',\n 'X-PostHog-Properties': buildWizardPropertiesBlob(\n wizardMetadata,\n wizardFlags,\n teamId,\n ),\n };\n}\n\nexport interface GatewayProviderInputs {\n gatewayUrl: string;\n accessToken: string;\n /** Customer team for the properties blob (from the mint response). */\n teamId?: number;\n wizardMetadata: Record<string, string>;\n wizardFlags: Record<string, string>;\n modelId: string;\n // Resolved effort override — the switchboard's flag/payload pick on linear\n // runs, the prompt-frontmatter effort on per-task agents. Overrides the\n // table default for a reasoning model when set.\n effort?: ThinkingLevel;\n}\n\n/**\n * One gateway model spec — the single description of how to reach a model on\n * the gateway. The provider spec below wraps it for pi's registry; one-shot\n * callers (scan triage) hand it straight to `completeSimple`.\n */\nexport function buildGatewayModel(inputs: GatewayProviderInputs) {\n const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId } = inputs;\n const api = gatewayApiFor(modelId);\n return {\n id: modelId,\n name: `${modelId} (PostHog Gateway)`,\n api,\n provider: GATEWAY_PROVIDER,\n // Anthropic drops /v1 (the SDK appends /v1/messages); the OpenAI shape keeps it.\n baseUrl: api === 'anthropic-messages' ? gatewayUrl : `${gatewayUrl}/v1`,\n // A model trait resolved by the switchboard, not a harness guess:\n // non-reasoning openai models reject `reasoning_effort` (gpt-4o → gateway\n // UnsupportedParamsError → the run no-ops).\n reasoning: modelCapabilities(modelId).reasoning,\n input: ['text' as const],\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n contextWindow: 1_000_000,\n maxTokens: 64_000,\n headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId),\n };\n}\n\n/**\n * The provider object for `registry.registerProvider(GATEWAY_PROVIDER, …)`,\n * plus the derived traits the session setup needs (`caps.thinkingLevel`).\n */\nexport function buildGatewayProvider(inputs: GatewayProviderInputs): {\n provider: Record<string, unknown>;\n api: GatewayApi;\n caps: ReturnType<typeof modelCapabilities>;\n gatewayUrl: string;\n baseUrl: string;\n} {\n const { gatewayUrl, accessToken, modelId, effort } = inputs;\n const api = gatewayApiFor(modelId);\n // One resolution point for the model's traits and the run's effort override.\n // pi clamps whatever comes out of here against the levels this spec declares,\n // so a level the spec doesn't carry is silently reduced by the session.\n const tableCaps = modelCapabilities(modelId);\n const caps =\n effort && effort !== 'off' && tableCaps.reasoning\n ? modelCapabilities(modelId, effort)\n : effort === 'off' && tableCaps.reasoning\n ? { ...tableCaps, thinkingLevel: 'off' as const }\n : tableCaps;\n\n const model = buildGatewayModel(inputs);\n const provider = {\n name: 'PostHog Gateway',\n baseUrl: model.baseUrl,\n apiKey: accessToken,\n authHeader: true,\n api,\n headers: model.headers,\n models: [model],\n };\n return { provider, api, caps, gatewayUrl, baseUrl: model.baseUrl };\n}\n\n/** The part of a pi assistant turn that says why it failed. */\nexport interface GatewayTurnError {\n errorMessage?: string;\n diagnostics?: { error?: { name?: string; code?: string | number } }[];\n}\n\nexport type GatewayTerminalFailure = {\n classification:\n | AgentErrorType.API_ERROR\n | AgentErrorType.RATE_LIMIT\n | AgentErrorType.ABORT;\n message: string;\n status?: number;\n};\n\nexport function gatewayTerminalFailure(\n turn: ({ stopReason?: string } & GatewayTurnError) | undefined,\n): GatewayTerminalFailure | undefined {\n if (!turn || (turn.stopReason !== 'error' && turn.stopReason !== 'aborted'))\n return undefined;\n const message =\n turn.errorMessage ||\n (turn.stopReason === 'aborted'\n ? 'Agent turn aborted'\n : 'Gateway request failed');\n if (turn.stopReason === 'aborted') {\n return { classification: AgentErrorType.ABORT, message };\n }\n const codes =\n turn.diagnostics\n ?.map((d) => d.error?.code)\n .filter((code) => code !== undefined) ?? [];\n const structuredStatus = codes\n .map(Number)\n .find((code) => Number.isInteger(code) && code >= 400 && code < 600);\n const rateLimited =\n structuredStatus !== undefined\n ? structuredStatus === 429\n : /\\b429\\b|rate limit/i.test(message);\n return {\n classification: rateLimited\n ? AgentErrorType.RATE_LIMIT\n : AgentErrorType.API_ERROR,\n message,\n status:\n structuredStatus ?? (isGatewayAuthRejection(turn) ? 401 : undefined),\n };\n}\n\n/**\n * Whether a turn's error is the gateway rejecting the bearer. pi attaches the\n * SDK's own error to `diagnostics`, so its code decides when one is present.\n * The message match is the fallback for a turn that failed before pi built a\n * diagnostic, where the status survives only as prose.\n */\nexport function isGatewayAuthRejection(\n turn: GatewayTurnError | string | undefined,\n): boolean {\n const { errorMessage, diagnostics } =\n typeof turn === 'string'\n ? { errorMessage: turn, diagnostics: undefined }\n : turn ?? {};\n const structuredStatus = (diagnostics ?? [])\n .map((diagnostic) => Number(diagnostic.error?.code))\n .find((code) => Number.isInteger(code) && code >= 400 && code < 600);\n if (structuredStatus !== undefined) return structuredStatus === 401;\n for (const diagnostic of diagnostics ?? []) {\n const code = diagnostic.error?.code;\n if (code === 401 || code === '401') return true;\n if (/^authentication_?error$/i.test(diagnostic.error?.name ?? ''))\n return true;\n }\n return /\\b401\\b|authentication_error|unauthorized/i.test(errorMessage ?? '');\n}\n\nexport interface GatewayRemintOptions {\n signal?: AbortSignal;\n session: { prompt(text: string): Promise<void> };\n registry: { registerProvider(providerName: string, config: never): void };\n auth: GatewayAuth;\n /** The cache: the same token while fresh, a new mint past the refresh point. */\n refreshAuth: () => Promise<GatewayAuth>;\n providerInputs: (auth: GatewayAuth) => GatewayProviderInputs;\n /** The prompt that resumes the work after a re-mint. */\n continueText: string | (() => string);\n onRemint?: () => void;\n}\n\n/**\n * Wraps a pi session's prompt(): when a turn ends on a 401 from a bearer past\n * its refresh instant, mint once, re-register the provider with the new\n * bearer (pi resolves the apiKey per request), and continue. A 401 on a fresh\n * bearer, or a second one, is left to the harness's normal failure path.\n */\nexport function withGatewayRemint(opts: GatewayRemintOptions): {\n prompt(text: string): Promise<void>;\n /** Feed every assistant `message_end`; the last turn decides. */\n noteAssistantTurn(message: unknown): void;\n terminalFailure(): GatewayTerminalFailure | undefined;\n} {\n let auth = opts.auth;\n let rejected = false;\n let reminted = false;\n let lastTurn: ({ stopReason?: string } & GatewayTurnError) | undefined;\n return {\n noteAssistantTurn(message) {\n lastTurn = message as\n | ({ stopReason?: string } & GatewayTurnError)\n | undefined;\n rejected =\n lastTurn?.stopReason === 'error' && isGatewayAuthRejection(lastTurn);\n },\n terminalFailure: () => gatewayTerminalFailure(lastTurn),\n async prompt(text) {\n if (opts.signal?.aborted) return;\n rejected = false;\n lastTurn = undefined;\n await opts.session.prompt(text);\n if (opts.signal?.aborted || !rejected || reminted || !isPastRefresh(auth))\n return;\n reminted = true;\n auth = await opts.refreshAuth();\n if (opts.signal?.aborted) return;\n opts.registry.registerProvider(\n GATEWAY_PROVIDER,\n buildGatewayProvider(opts.providerInputs(auth)).provider as never,\n );\n opts.onRemint?.();\n rejected = false;\n lastTurn = undefined;\n const next = opts.continueText;\n if (opts.signal?.aborted) return;\n await opts.session.prompt(typeof next === 'function' ? next() : next);\n },\n };\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import "./wizard-session-2w4Ru-Wz.js";
2
- import { t as LoggingUI } from "./logging-ui-_TwoMNbG.js";
2
+ import { t as LoggingUI } from "./logging-ui-CUxNYF2t.js";
3
3
  //#region src/ui/headless-ui.ts
4
4
  /**
5
5
  * `LoggingUI` plus it feeds run state into a `WizardStore` so the background
@@ -41,4 +41,4 @@ var HeadlessUI = class extends LoggingUI {
41
41
  //#endregion
42
42
  export { HeadlessUI };
43
43
 
44
- //# sourceMappingURL=headless-ui-BFFmYC4v.js.map
44
+ //# sourceMappingURL=headless-ui-pY2xB5ug.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"headless-ui-BFFmYC4v.js","names":[],"sources":["../src/ui/headless-ui.ts"],"sourcesContent":["import { RunPhase, type Credentials } from '@lib/wizard-session';\nimport { LoggingUI } from './logging-ui';\nimport type { WizardStore } from './tui/store';\n\n/**\n * `LoggingUI` plus it feeds run state into a `WizardStore` so the background\n * wizard-session sync (`TaskStreamPush`) can observe a headless run. We extend\n * `LoggingUI` (not `InkUI`) because its blocking/gate methods would wait on a\n * TUI that never renders; the runner drives phase transitions on the store\n * directly, so only UI-originated per-run updates tee through here. The audit\n * ledger arrives through `setFrameworkContext`, the seam every UI implements.\n */\nexport class HeadlessUI extends LoggingUI {\n constructor(private readonly store: WizardStore) {\n super();\n }\n\n startRun(): void {\n super.startRun();\n this.store.setRunPhase(RunPhase.Running);\n }\n\n setCredentials(credentials: Credentials): void {\n this.store.setAccessToken(credentials);\n }\n\n setAccessToken(credentials: Credentials): void {\n this.store.setAccessToken(credentials);\n }\n\n syncTodos(\n todos: Array<{\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n }>,\n ): void {\n super.syncTodos(todos);\n this.store.syncTodos(todos);\n }\n\n setHandoffText(text: string): void {\n this.store.setHandoffText(text);\n }\n\n setFrameworkContext(key: string, value: unknown): void {\n this.store.setFrameworkContext(key, value);\n }\n\n getFrameworkContext(key: string): unknown {\n return this.store.session.frameworkContext[key];\n }\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAa,aAAb,cAAgC,UAAU;CACxC,YAAY,OAAqC;AAC/C,SAAO;AADoB,OAAA,QAAA;;CAI7B,WAAiB;AACf,QAAM,UAAU;AAChB,OAAK,MAAM,YAAA,UAA6B;;CAG1C,eAAe,aAAgC;AAC7C,OAAK,MAAM,eAAe,YAAY;;CAGxC,eAAe,aAAgC;AAC7C,OAAK,MAAM,eAAe,YAAY;;CAGxC,UACE,OAOM;AACN,QAAM,UAAU,MAAM;AACtB,OAAK,MAAM,UAAU,MAAM;;CAG7B,eAAe,MAAoB;AACjC,OAAK,MAAM,eAAe,KAAK;;CAGjC,oBAAoB,KAAa,OAAsB;AACrD,OAAK,MAAM,oBAAoB,KAAK,MAAM;;CAG5C,oBAAoB,KAAsB;AACxC,SAAO,KAAK,MAAM,QAAQ,iBAAiB"}
1
+ {"version":3,"file":"headless-ui-pY2xB5ug.js","names":[],"sources":["../src/ui/headless-ui.ts"],"sourcesContent":["import { RunPhase, type Credentials } from '@lib/wizard-session';\nimport { LoggingUI } from './logging-ui';\nimport type { WizardStore } from './tui/store';\n\n/**\n * `LoggingUI` plus it feeds run state into a `WizardStore` so the background\n * wizard-session sync (`TaskStreamPush`) can observe a headless run. We extend\n * `LoggingUI` (not `InkUI`) because its blocking/gate methods would wait on a\n * TUI that never renders; the runner drives phase transitions on the store\n * directly, so only UI-originated per-run updates tee through here. The audit\n * ledger arrives through `setFrameworkContext`, the seam every UI implements.\n */\nexport class HeadlessUI extends LoggingUI {\n constructor(private readonly store: WizardStore) {\n super();\n }\n\n startRun(): void {\n super.startRun();\n this.store.setRunPhase(RunPhase.Running);\n }\n\n setCredentials(credentials: Credentials): void {\n this.store.setAccessToken(credentials);\n }\n\n setAccessToken(credentials: Credentials): void {\n this.store.setAccessToken(credentials);\n }\n\n syncTodos(\n todos: Array<{\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n }>,\n ): void {\n super.syncTodos(todos);\n this.store.syncTodos(todos);\n }\n\n setHandoffText(text: string): void {\n this.store.setHandoffText(text);\n }\n\n setFrameworkContext(key: string, value: unknown): void {\n this.store.setFrameworkContext(key, value);\n }\n\n getFrameworkContext(key: string): unknown {\n return this.store.session.frameworkContext[key];\n }\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAa,aAAb,cAAgC,UAAU;CACxC,YAAY,OAAqC;AAC/C,SAAO;AADoB,OAAA,QAAA;;CAI7B,WAAiB;AACf,QAAM,UAAU;AAChB,OAAK,MAAM,YAAA,UAA6B;;CAG1C,eAAe,aAAgC;AAC7C,OAAK,MAAM,eAAe,YAAY;;CAGxC,eAAe,aAAgC;AAC7C,OAAK,MAAM,eAAe,YAAY;;CAGxC,UACE,OAOM;AACN,QAAM,UAAU,MAAM;AACtB,OAAK,MAAM,UAAU,MAAM;;CAG7B,eAAe,MAAoB;AACjC,OAAK,MAAM,eAAe,KAAK;;CAGjC,oBAAoB,KAAa,OAAsB;AACrD,OAAK,MAAM,oBAAoB,KAAK,MAAM;;CAG5C,oBAAoB,KAAsB;AACxC,SAAO,KAAK,MAAM,QAAQ,iBAAiB"}
@@ -1,4 +1,4 @@
1
- import { X as posthogIntegrationConfig } from "./mint-failure-D4nd2XmZ.js";
1
+ import { X as posthogIntegrationConfig } from "./mint-failure-CZFZpHpW.js";
2
2
  import { d as runWizard } from "./bin.js";
3
3
  //#region src/commands/basic-integration/interactive.ts
4
4
  /** Default flow: run the posthog-integration program through the TUI. */
@@ -8,4 +8,4 @@ function runInteractive(argv) {
8
8
  //#endregion
9
9
  export { runInteractive };
10
10
 
11
- //# sourceMappingURL=interactive-D6zV7brJ.js.map
11
+ //# sourceMappingURL=interactive-BOGlinZe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-BOGlinZe.js","names":[],"sources":["../src/commands/basic-integration/interactive.ts"],"sourcesContent":["import type { Arguments } from 'yargs';\nimport { runWizard } from '@lib/runners';\nimport { posthogIntegrationConfig } from '@programs/posthog-integration/index';\n\n/** Default flow: run the posthog-integration program through the TUI. */\nexport function runInteractive(argv: Arguments): void {\n runWizard(posthogIntegrationConfig, argv);\n}\n"],"mappings":";;;;AAKA,SAAgB,eAAe,MAAuB;AACpD,WAAU,0BAA0B,KAAK"}
@@ -1,7 +1,7 @@
1
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
2
- import { E as OAUTH_TIMEOUT_MS } from "./constants-jFI2SaE1.js";
1
+ import { s as logToFile } from "./debug-Cj-8vfXY.js";
2
+ import { E as OAUTH_TIMEOUT_MS } from "./constants-CuJfQEcC.js";
3
3
  import "./wizard-ui-DoyOZxK8.js";
4
- import { n as checkSkillsOriginHealth } from "./endpoints-DCVbM06L.js";
4
+ import { n as checkSkillsOriginHealth } from "./endpoints-DnIX0pZH.js";
5
5
  //#region src/shared/health-checks/readiness.ts
6
6
  const SERVICE_LABELS = { skillsOrigin: "Skills download" };
7
7
  const DEFAULT_WIZARD_READINESS_CONFIG = { downBlocksRun: ["skillsOrigin"] };
@@ -223,4 +223,4 @@ var LoggingUI = class {
223
223
  //#endregion
224
224
  export { getBlockingServiceKeys as a, evaluateWizardReadiness as i, SERVICE_LABELS as n, SIGNUP_WIZARD_READINESS_CONFIG as r, LoggingUI as t };
225
225
 
226
- //# sourceMappingURL=logging-ui-_TwoMNbG.js.map
226
+ //# sourceMappingURL=logging-ui-CUxNYF2t.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logging-ui-_TwoMNbG.js","names":[],"sources":["../src/shared/health-checks/readiness.ts","../src/ui/logging-ui.ts"],"sourcesContent":["import {\n ServiceHealthStatus,\n type AllServicesHealth,\n type BaseHealthResult,\n type HealthCheckKey,\n} from './types';\nimport { checkSkillsOriginHealth } from './endpoints';\nimport { logToFile } from '@utils/debug';\n\n// ---------------------------------------------------------------------------\n// Service labels (used in human-readable reason strings)\n// ---------------------------------------------------------------------------\n\nexport const SERVICE_LABELS: Record<HealthCheckKey, string> = {\n skillsOrigin: 'Skills download',\n};\n\n// ---------------------------------------------------------------------------\n// Readiness config\n// ---------------------------------------------------------------------------\n\nexport interface WizardReadinessConfig {\n /** Services where status=Down blocks the run (readiness=No). */\n downBlocksRun: HealthCheckKey[];\n /** Services where status=Degraded (or worse) blocks the run (readiness=No). */\n degradedBlocksRun?: HealthCheckKey[];\n}\n\n// Skills gate startup; gateway readiness is checked against the minted URL.\nexport const DEFAULT_WIZARD_READINESS_CONFIG: WizardReadinessConfig = {\n downBlocksRun: ['skillsOrigin'],\n};\n\nexport const SIGNUP_WIZARD_READINESS_CONFIG = DEFAULT_WIZARD_READINESS_CONFIG;\n\n// ---------------------------------------------------------------------------\n// Aggregate check\n// ---------------------------------------------------------------------------\n\nexport async function checkAllExternalServices(): Promise<AllServicesHealth> {\n return { skillsOrigin: await checkSkillsOriginHealth() };\n}\n\n// ---------------------------------------------------------------------------\n// Wizard readiness evaluation\n// ---------------------------------------------------------------------------\n\nexport enum WizardReadiness {\n Yes = 'yes',\n No = 'no',\n YesWithWarnings = 'yes_with_warnings',\n}\n\nexport interface WizardReadinessResult {\n decision: WizardReadiness;\n health: AllServicesHealth;\n reasons: string[];\n}\n\nfunction describeResult(label: string, h: BaseHealthResult): string {\n const parts = [`${label}: ${h.status}`];\n if (h.rawIndicator) parts.push(`indicator=${h.rawIndicator}`);\n if (h.error) parts.push(h.error);\n return parts.join(' — ');\n}\n\n// Each probe can take up to one base timeout + two retries with the\n// 500ms / 2000ms backoffs in endpoints.ts (worst case ~17.5s for a\n// network failure that exhausts retries). Probes run in parallel so\n// the aggregate ceiling is one probe, not the sum.\nconst READINESS_TIMEOUT_MS = 20_000;\n\nexport async function evaluateWizardReadiness(\n config: WizardReadinessConfig = DEFAULT_WIZARD_READINESS_CONFIG,\n): Promise<WizardReadinessResult> {\n try {\n const health = await Promise.race([\n checkAllExternalServices(),\n new Promise<AllServicesHealth>((resolve) =>\n setTimeout(\n () => resolve(allUnknown('Health check timed out')),\n READINESS_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const blockingKeys = getBlockingServiceKeys(health, config);\n const reasons = blockingKeys.map((key) =>\n describeResult(SERVICE_LABELS[key], health[key]),\n );\n if (blockingKeys.length > 0) {\n const blockingDetails = blockingKeys.map((key) => {\n const h = health[key];\n return `${key} (${h.status}${h.error ? ` — ${h.error}` : ''})`;\n });\n logToFile(`[health-checks] blocked by: ${blockingDetails.join(', ')}`);\n return { decision: WizardReadiness.No, health, reasons };\n }\n\n return { decision: WizardReadiness.Yes, health, reasons };\n } catch (err) {\n logToFile(\n `[health-checks] error: ${err instanceof Error ? err.message : err}`,\n );\n // Health checks must never block the wizard run\n return {\n decision: WizardReadiness.Yes,\n health: allUnknown('Unexpected error'),\n reasons: [],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Blocking service detection\n// ---------------------------------------------------------------------------\n\n// Report only dependencies that prevent this run from starting.\nexport function getBlockingServiceKeys(\n health: AllServicesHealth,\n config: WizardReadinessConfig = DEFAULT_WIZARD_READINESS_CONFIG,\n): HealthCheckKey[] {\n return (Object.keys(health) as HealthCheckKey[]).filter((key) => {\n const result = health[key];\n if (\n config.downBlocksRun.includes(key) &&\n (result.status === ServiceHealthStatus.Down ||\n result.status === ServiceHealthStatus.NoConnection)\n ) {\n return true;\n }\n if (\n (config.degradedBlocksRun ?? []).includes(key) &&\n result.status !== ServiceHealthStatus.Healthy\n ) {\n return true;\n }\n return false;\n });\n}\n\n/** Build an AllServicesHealth where every service is Degraded with the given error. */\nfunction allUnknown(error: string): AllServicesHealth {\n const base: BaseHealthResult = {\n status: ServiceHealthStatus.Degraded,\n error,\n };\n return { skillsOrigin: base };\n}\n","/* eslint-disable no-console */\n/**\n * LoggingUI — Logging-only implementation for CI mode.\n * No prompts, no TUI, no interactivity. Just console output.\n */\n\nimport {\n TaskStatus,\n type WizardUI,\n type SpinnerHandle,\n type AuthErrorDetail,\n type TokenUsageDelta,\n} from './wizard-ui';\nimport type { SettingsConflict } from '@shared/claude-settings';\nimport type { ApiUser } from '@shared/api';\nimport { OAUTH_TIMEOUT_MS } from '@shared/constants';\nimport {\n type WizardReadinessResult,\n getBlockingServiceKeys,\n SERVICE_LABELS,\n} from '@shared/health-checks/readiness';\nimport type {\n AskAnswers,\n Credentials,\n OutroData,\n PendingQuestion,\n TaskNotice,\n} from '@lib/wizard-session';\n\nexport class LoggingUI implements WizardUI {\n intro(message: string): void {\n console.log(`┌ ${message}`);\n }\n\n outro(message: string): void {\n console.log(`└ ${message}`);\n }\n\n outroError(data: OutroData): void {\n console.log(`✖ ${data.message ?? 'Wizard aborted'}`);\n if (data.body) console.log(`│ ${data.body}`);\n if (data.docsUrl) console.log(`│ Docs: ${data.docsUrl}`);\n }\n\n waitForOutroDismissed(): Promise<void> {\n return Promise.resolve();\n }\n\n waitForAiOptIn(): Promise<void> {\n // Non-TUI runs are CI runs, which auto-consent to AI usage.\n return Promise.resolve();\n }\n\n cancel(message: string): void {\n console.log(`■ ${message}`);\n }\n\n log = {\n info(message: string): void {\n console.log(`│ ${message}`);\n },\n warn(message: string): void {\n console.log(`▲ ${message}`);\n },\n error(message: string): void {\n console.log(`✖ ${message}`);\n },\n success(message: string): void {\n console.log(`✔ ${message}`);\n },\n step(message: string): void {\n console.log(`◇ ${message}`);\n },\n };\n\n note(message: string): void {\n console.log(`│ ${message}`);\n }\n\n spinner(): SpinnerHandle {\n return {\n start(message?: string) {\n if (message) console.log(`◌ ${message}`);\n },\n stop(message?: string) {\n if (message) console.log(`● ${message}`);\n },\n message(msg?: string) {\n if (msg) console.log(`◌ ${msg}`);\n },\n };\n }\n\n pushStatus(message: string): void {\n console.log(`◇ ${message}`);\n }\n\n setDetectedFramework(label: string): void {\n console.log(`✔ Framework: ${label}`);\n }\n\n onEnterScreen(_screen: string, _fn: () => void): void {\n // No screen transitions in CI\n }\n\n setLoginUrl(url: string | null): void {\n if (url) {\n console.log(\n `│ If the browser didn't open automatically, use this link:`,\n );\n console.log(`│ ${url}`);\n }\n }\n\n setAuthorizeUrl(_url: string | null): void {\n // Manual-paste modal is TUI-only; CI/non-interactive runs don't use it.\n }\n\n showBlockingOutage(result: WizardReadinessResult): Promise<void> {\n console.log(`▲ Service health issues detected.`);\n const blockingKeys = getBlockingServiceKeys(result.health);\n if (blockingKeys.length > 0) {\n console.log(`│`);\n console.log(`│ Blocking services:`);\n for (const key of blockingKeys) {\n const status = result.health[key].status;\n const error = result.health[key].error;\n const label = SERVICE_LABELS[key];\n const detail = error ? ` — ${error}` : '';\n console.log(`│ ✖ ${label}: ${status}${detail}`);\n }\n console.log(`│`);\n }\n for (const reason of result.reasons) {\n console.log(`│ ${reason}`);\n }\n console.log(\n `│ Continuing anyway — health checks are advisory in non-interactive runs.`,\n );\n return Promise.resolve();\n }\n\n setReadinessWarnings(result: WizardReadinessResult): void {\n console.log(`▲ Service health warnings detected.`);\n for (const reason of result.reasons) {\n console.log(`│ ${reason}`);\n }\n }\n\n showPortConflict(_processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void> {\n return Promise.resolve();\n }\n\n waitForManualAuthCode(): Promise<string> {\n // No interactive prompt in CI/logging mode — never resolves. CI bypasses\n // OAuth entirely, so this is only here to satisfy the interface.\n return new Promise<string>(() => {\n /* intentionally never resolves */\n });\n }\n\n showTaskNotice(_notice: TaskNotice): Promise<boolean> {\n return Promise.resolve(false);\n }\n\n cancelTaskNotice(): void {\n // Nothing to dismiss — showTaskNotice never opened anything.\n }\n\n showSettingsOverride(\n _conflicts: SettingsConflict[],\n _backupAndFix: () => boolean,\n ): Promise<void> {\n return Promise.resolve();\n }\n\n requestQuestion(_question: PendingQuestion): Promise<AskAnswers> {\n return Promise.reject(\n new Error(\n 'wizard_ask is not available in CI / non-interactive mode. ' +\n 'Re-run the wizard without --ci to answer interactively.',\n ),\n );\n }\n\n cancelPendingQuestion(): void {\n // Nothing to dismiss — requestQuestion never opens an overlay here.\n }\n\n showAuthError(detail?: AuthErrorDetail): void {\n console.log(`✖ Authentication failed (401)`);\n if (detail?.hasSettingsConflict) {\n console.log(\n `│ Claude Code auth is conflicting with the wizard. Please try again after logging out:`,\n );\n console.log(`│ claude auth logout`);\n } else {\n console.log(\n `│ The PostHog LLM Gateway rejected the API key. Common causes:`,\n );\n console.log(\n `│ - Wrong key type: pass a personal API key (phx_xxx). pha_ is an OAuth access token, phc_ is a project key.`,\n );\n console.log(\n `│ - Missing scope: the personal API key needs the \"llm_gateway:read\" scope.`,\n );\n console.log(`│ - Expired or revoked key.`);\n console.log(\n `│ - Region mismatch: --region must match the region the key was issued in (us vs eu).`,\n );\n }\n if (detail?.logFilePath) {\n console.log(`│ Verbose log: ${detail.logFilePath}`);\n }\n }\n\n showSessionTimeout(): void {\n const minutes = Math.round(OAUTH_TIMEOUT_MS / 60_000);\n console.log(\n `✖ Login timed out. The OAuth link timed out after ${minutes} minutes.`,\n );\n console.log(`│ Re-run the wizard to get a fresh link and try again.`);\n }\n\n startRun(): void {\n // No-op in CI mode\n }\n\n setCredentials(_credentials: Credentials): void {\n // No-op in CI mode — credentials are handled directly\n }\n\n setAccessToken(_credentials: Credentials): void {\n // No-op in CI mode — CI runs on a non-expiring key and never refreshes\n }\n\n setRoleAtOrganization(_role: string | null): void {\n // No-op in CI mode — there's no TUI to render role-tailored prompts\n }\n\n setApiUser(_user: ApiUser | null): void {\n // No-op in CI mode — there's no TUI to read account context from\n // the session.\n }\n\n private lastTodoLine = '';\n\n syncTodos(\n todos: Array<{\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n }>,\n ): void {\n const completed = todos.filter(\n (t) => t.status === TaskStatus.Completed,\n ).length;\n const active = todos.filter((t) => t.status === TaskStatus.InProgress);\n if (active.length === 0) return;\n const labels = active.map((t) => t.activeForm || t.content).join(' · ');\n const line = `◌ [${completed}/${todos.length}] ${labels}`;\n // The queue re-renders on every transition; print only what changed.\n if (line === this.lastTodoLine) return;\n this.lastTodoLine = line;\n console.log(line);\n }\n\n setEventPlan(_events: Array<{ name: string; description: string }>): void {\n // No-op in CI mode\n }\n\n setDashboardUrl(_url: string): void {\n // No-op in CI mode\n }\n\n setStage(_stage: string): void {\n // No-op in CI mode\n }\n\n setNotebookUrl(_url: string): void {\n // No-op in CI mode\n }\n\n setHandoffText(_text: string): void {\n // No-op without a store — HeadlessUI overrides to feed the session sync\n }\n\n addTokenUsage(_delta: TokenUsageDelta): void {\n // No-op — the hidden Ctrl+T HUD is TUI-only\n }\n\n setFinalTokenCostUsd(_costUsd: number): void {\n // No-op — the hidden Ctrl+T HUD is TUI-only\n }\n\n setOutroData(_data: import('@lib/wizard-session').OutroData): void {\n // No-op in CI mode\n }\n\n setFrameworkContext(_key: string, _value: unknown): void {\n // No-op in CI mode\n }\n\n getFrameworkContext(_key: string): unknown {\n // No frameworkContext in CI mode\n return undefined;\n }\n\n waitForGate(_stepId: string): Promise<void> {\n // No interactive gates in CI mode\n return Promise.resolve();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"logging-ui-CUxNYF2t.js","names":[],"sources":["../src/shared/health-checks/readiness.ts","../src/ui/logging-ui.ts"],"sourcesContent":["import {\n ServiceHealthStatus,\n type AllServicesHealth,\n type BaseHealthResult,\n type HealthCheckKey,\n} from './types';\nimport { checkSkillsOriginHealth } from './endpoints';\nimport { logToFile } from '@utils/debug';\n\n// ---------------------------------------------------------------------------\n// Service labels (used in human-readable reason strings)\n// ---------------------------------------------------------------------------\n\nexport const SERVICE_LABELS: Record<HealthCheckKey, string> = {\n skillsOrigin: 'Skills download',\n};\n\n// ---------------------------------------------------------------------------\n// Readiness config\n// ---------------------------------------------------------------------------\n\nexport interface WizardReadinessConfig {\n /** Services where status=Down blocks the run (readiness=No). */\n downBlocksRun: HealthCheckKey[];\n /** Services where status=Degraded (or worse) blocks the run (readiness=No). */\n degradedBlocksRun?: HealthCheckKey[];\n}\n\n// Skills gate startup; gateway readiness is checked against the minted URL.\nexport const DEFAULT_WIZARD_READINESS_CONFIG: WizardReadinessConfig = {\n downBlocksRun: ['skillsOrigin'],\n};\n\nexport const SIGNUP_WIZARD_READINESS_CONFIG = DEFAULT_WIZARD_READINESS_CONFIG;\n\n// ---------------------------------------------------------------------------\n// Aggregate check\n// ---------------------------------------------------------------------------\n\nexport async function checkAllExternalServices(): Promise<AllServicesHealth> {\n return { skillsOrigin: await checkSkillsOriginHealth() };\n}\n\n// ---------------------------------------------------------------------------\n// Wizard readiness evaluation\n// ---------------------------------------------------------------------------\n\nexport enum WizardReadiness {\n Yes = 'yes',\n No = 'no',\n YesWithWarnings = 'yes_with_warnings',\n}\n\nexport interface WizardReadinessResult {\n decision: WizardReadiness;\n health: AllServicesHealth;\n reasons: string[];\n}\n\nfunction describeResult(label: string, h: BaseHealthResult): string {\n const parts = [`${label}: ${h.status}`];\n if (h.rawIndicator) parts.push(`indicator=${h.rawIndicator}`);\n if (h.error) parts.push(h.error);\n return parts.join(' — ');\n}\n\n// Each probe can take up to one base timeout + two retries with the\n// 500ms / 2000ms backoffs in endpoints.ts (worst case ~17.5s for a\n// network failure that exhausts retries). Probes run in parallel so\n// the aggregate ceiling is one probe, not the sum.\nconst READINESS_TIMEOUT_MS = 20_000;\n\nexport async function evaluateWizardReadiness(\n config: WizardReadinessConfig = DEFAULT_WIZARD_READINESS_CONFIG,\n): Promise<WizardReadinessResult> {\n try {\n const health = await Promise.race([\n checkAllExternalServices(),\n new Promise<AllServicesHealth>((resolve) =>\n setTimeout(\n () => resolve(allUnknown('Health check timed out')),\n READINESS_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const blockingKeys = getBlockingServiceKeys(health, config);\n const reasons = blockingKeys.map((key) =>\n describeResult(SERVICE_LABELS[key], health[key]),\n );\n if (blockingKeys.length > 0) {\n const blockingDetails = blockingKeys.map((key) => {\n const h = health[key];\n return `${key} (${h.status}${h.error ? ` — ${h.error}` : ''})`;\n });\n logToFile(`[health-checks] blocked by: ${blockingDetails.join(', ')}`);\n return { decision: WizardReadiness.No, health, reasons };\n }\n\n return { decision: WizardReadiness.Yes, health, reasons };\n } catch (err) {\n logToFile(\n `[health-checks] error: ${err instanceof Error ? err.message : err}`,\n );\n // Health checks must never block the wizard run\n return {\n decision: WizardReadiness.Yes,\n health: allUnknown('Unexpected error'),\n reasons: [],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Blocking service detection\n// ---------------------------------------------------------------------------\n\n// Report only dependencies that prevent this run from starting.\nexport function getBlockingServiceKeys(\n health: AllServicesHealth,\n config: WizardReadinessConfig = DEFAULT_WIZARD_READINESS_CONFIG,\n): HealthCheckKey[] {\n return (Object.keys(health) as HealthCheckKey[]).filter((key) => {\n const result = health[key];\n if (\n config.downBlocksRun.includes(key) &&\n (result.status === ServiceHealthStatus.Down ||\n result.status === ServiceHealthStatus.NoConnection)\n ) {\n return true;\n }\n if (\n (config.degradedBlocksRun ?? []).includes(key) &&\n result.status !== ServiceHealthStatus.Healthy\n ) {\n return true;\n }\n return false;\n });\n}\n\n/** Build an AllServicesHealth where every service is Degraded with the given error. */\nfunction allUnknown(error: string): AllServicesHealth {\n const base: BaseHealthResult = {\n status: ServiceHealthStatus.Degraded,\n error,\n };\n return { skillsOrigin: base };\n}\n","/* eslint-disable no-console */\n/**\n * LoggingUI — Logging-only implementation for CI mode.\n * No prompts, no TUI, no interactivity. Just console output.\n */\n\nimport {\n TaskStatus,\n type WizardUI,\n type SpinnerHandle,\n type AuthErrorDetail,\n type TokenUsageDelta,\n} from './wizard-ui';\nimport type { SettingsConflict } from '@shared/claude-settings';\nimport type { ApiUser } from '@shared/api';\nimport { OAUTH_TIMEOUT_MS } from '@shared/constants';\nimport {\n type WizardReadinessResult,\n getBlockingServiceKeys,\n SERVICE_LABELS,\n} from '@shared/health-checks/readiness';\nimport type {\n AskAnswers,\n Credentials,\n OutroData,\n PendingQuestion,\n TaskNotice,\n} from '@lib/wizard-session';\n\nexport class LoggingUI implements WizardUI {\n intro(message: string): void {\n console.log(`┌ ${message}`);\n }\n\n outro(message: string): void {\n console.log(`└ ${message}`);\n }\n\n outroError(data: OutroData): void {\n console.log(`✖ ${data.message ?? 'Wizard aborted'}`);\n if (data.body) console.log(`│ ${data.body}`);\n if (data.docsUrl) console.log(`│ Docs: ${data.docsUrl}`);\n }\n\n waitForOutroDismissed(): Promise<void> {\n return Promise.resolve();\n }\n\n waitForAiOptIn(): Promise<void> {\n // Non-TUI runs are CI runs, which auto-consent to AI usage.\n return Promise.resolve();\n }\n\n cancel(message: string): void {\n console.log(`■ ${message}`);\n }\n\n log = {\n info(message: string): void {\n console.log(`│ ${message}`);\n },\n warn(message: string): void {\n console.log(`▲ ${message}`);\n },\n error(message: string): void {\n console.log(`✖ ${message}`);\n },\n success(message: string): void {\n console.log(`✔ ${message}`);\n },\n step(message: string): void {\n console.log(`◇ ${message}`);\n },\n };\n\n note(message: string): void {\n console.log(`│ ${message}`);\n }\n\n spinner(): SpinnerHandle {\n return {\n start(message?: string) {\n if (message) console.log(`◌ ${message}`);\n },\n stop(message?: string) {\n if (message) console.log(`● ${message}`);\n },\n message(msg?: string) {\n if (msg) console.log(`◌ ${msg}`);\n },\n };\n }\n\n pushStatus(message: string): void {\n console.log(`◇ ${message}`);\n }\n\n setDetectedFramework(label: string): void {\n console.log(`✔ Framework: ${label}`);\n }\n\n onEnterScreen(_screen: string, _fn: () => void): void {\n // No screen transitions in CI\n }\n\n setLoginUrl(url: string | null): void {\n if (url) {\n console.log(\n `│ If the browser didn't open automatically, use this link:`,\n );\n console.log(`│ ${url}`);\n }\n }\n\n setAuthorizeUrl(_url: string | null): void {\n // Manual-paste modal is TUI-only; CI/non-interactive runs don't use it.\n }\n\n showBlockingOutage(result: WizardReadinessResult): Promise<void> {\n console.log(`▲ Service health issues detected.`);\n const blockingKeys = getBlockingServiceKeys(result.health);\n if (blockingKeys.length > 0) {\n console.log(`│`);\n console.log(`│ Blocking services:`);\n for (const key of blockingKeys) {\n const status = result.health[key].status;\n const error = result.health[key].error;\n const label = SERVICE_LABELS[key];\n const detail = error ? ` — ${error}` : '';\n console.log(`│ ✖ ${label}: ${status}${detail}`);\n }\n console.log(`│`);\n }\n for (const reason of result.reasons) {\n console.log(`│ ${reason}`);\n }\n console.log(\n `│ Continuing anyway — health checks are advisory in non-interactive runs.`,\n );\n return Promise.resolve();\n }\n\n setReadinessWarnings(result: WizardReadinessResult): void {\n console.log(`▲ Service health warnings detected.`);\n for (const reason of result.reasons) {\n console.log(`│ ${reason}`);\n }\n }\n\n showPortConflict(_processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void> {\n return Promise.resolve();\n }\n\n waitForManualAuthCode(): Promise<string> {\n // No interactive prompt in CI/logging mode — never resolves. CI bypasses\n // OAuth entirely, so this is only here to satisfy the interface.\n return new Promise<string>(() => {\n /* intentionally never resolves */\n });\n }\n\n showTaskNotice(_notice: TaskNotice): Promise<boolean> {\n return Promise.resolve(false);\n }\n\n cancelTaskNotice(): void {\n // Nothing to dismiss — showTaskNotice never opened anything.\n }\n\n showSettingsOverride(\n _conflicts: SettingsConflict[],\n _backupAndFix: () => boolean,\n ): Promise<void> {\n return Promise.resolve();\n }\n\n requestQuestion(_question: PendingQuestion): Promise<AskAnswers> {\n return Promise.reject(\n new Error(\n 'wizard_ask is not available in CI / non-interactive mode. ' +\n 'Re-run the wizard without --ci to answer interactively.',\n ),\n );\n }\n\n cancelPendingQuestion(): void {\n // Nothing to dismiss — requestQuestion never opens an overlay here.\n }\n\n showAuthError(detail?: AuthErrorDetail): void {\n console.log(`✖ Authentication failed (401)`);\n if (detail?.hasSettingsConflict) {\n console.log(\n `│ Claude Code auth is conflicting with the wizard. Please try again after logging out:`,\n );\n console.log(`│ claude auth logout`);\n } else {\n console.log(\n `│ The PostHog LLM Gateway rejected the API key. Common causes:`,\n );\n console.log(\n `│ - Wrong key type: pass a personal API key (phx_xxx). pha_ is an OAuth access token, phc_ is a project key.`,\n );\n console.log(\n `│ - Missing scope: the personal API key needs the \"llm_gateway:read\" scope.`,\n );\n console.log(`│ - Expired or revoked key.`);\n console.log(\n `│ - Region mismatch: --region must match the region the key was issued in (us vs eu).`,\n );\n }\n if (detail?.logFilePath) {\n console.log(`│ Verbose log: ${detail.logFilePath}`);\n }\n }\n\n showSessionTimeout(): void {\n const minutes = Math.round(OAUTH_TIMEOUT_MS / 60_000);\n console.log(\n `✖ Login timed out. The OAuth link timed out after ${minutes} minutes.`,\n );\n console.log(`│ Re-run the wizard to get a fresh link and try again.`);\n }\n\n startRun(): void {\n // No-op in CI mode\n }\n\n setCredentials(_credentials: Credentials): void {\n // No-op in CI mode — credentials are handled directly\n }\n\n setAccessToken(_credentials: Credentials): void {\n // No-op in CI mode — CI runs on a non-expiring key and never refreshes\n }\n\n setRoleAtOrganization(_role: string | null): void {\n // No-op in CI mode — there's no TUI to render role-tailored prompts\n }\n\n setApiUser(_user: ApiUser | null): void {\n // No-op in CI mode — there's no TUI to read account context from\n // the session.\n }\n\n private lastTodoLine = '';\n\n syncTodos(\n todos: Array<{\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n }>,\n ): void {\n const completed = todos.filter(\n (t) => t.status === TaskStatus.Completed,\n ).length;\n const active = todos.filter((t) => t.status === TaskStatus.InProgress);\n if (active.length === 0) return;\n const labels = active.map((t) => t.activeForm || t.content).join(' · ');\n const line = `◌ [${completed}/${todos.length}] ${labels}`;\n // The queue re-renders on every transition; print only what changed.\n if (line === this.lastTodoLine) return;\n this.lastTodoLine = line;\n console.log(line);\n }\n\n setEventPlan(_events: Array<{ name: string; description: string }>): void {\n // No-op in CI mode\n }\n\n setDashboardUrl(_url: string): void {\n // No-op in CI mode\n }\n\n setStage(_stage: string): void {\n // No-op in CI mode\n }\n\n setNotebookUrl(_url: string): void {\n // No-op in CI mode\n }\n\n setHandoffText(_text: string): void {\n // No-op without a store — HeadlessUI overrides to feed the session sync\n }\n\n addTokenUsage(_delta: TokenUsageDelta): void {\n // No-op — the hidden Ctrl+T HUD is TUI-only\n }\n\n setFinalTokenCostUsd(_costUsd: number): void {\n // No-op — the hidden Ctrl+T HUD is TUI-only\n }\n\n setOutroData(_data: import('@lib/wizard-session').OutroData): void {\n // No-op in CI mode\n }\n\n setFrameworkContext(_key: string, _value: unknown): void {\n // No-op in CI mode\n }\n\n getFrameworkContext(_key: string): unknown {\n // No frameworkContext in CI mode\n return undefined;\n }\n\n waitForGate(_stepId: string): Promise<void> {\n // No interactive gates in CI mode\n return Promise.resolve();\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
2
- import { t as VERSION } from "./version-aXxpgRKx.js";
3
- import { o as onAccessTokenRotated } from "./oauth-session-DJ8h6GFa.js";
1
+ import { s as logToFile } from "./debug-Cj-8vfXY.js";
2
+ import { t as VERSION } from "./version-Cadof0Z_.js";
3
+ import { o as onAccessTokenRotated } from "./oauth-session-CQTFOk-I.js";
4
4
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
5
5
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
6
6
  import { createJiti } from "jiti";
@@ -94,4 +94,4 @@ async function setupPostHogMcp(opts) {
94
94
  //#endregion
95
95
  export { fetchInstructions, setupPostHogMcp };
96
96
 
97
- //# sourceMappingURL=mcp-DAgaoGk5.js.map
97
+ //# sourceMappingURL=mcp-JcsBBnWv.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-DAgaoGk5.js","names":[],"sources":["../src/agent/runner/harness/pi/mcp.ts"],"sourcesContent":["/**\n * pi has no built-in MCP; `pi-mcp-adapter` — pi's own MCP extension, built here\n * with its supported `createMcpAdapter` embedding API — bridges the same hosted\n * MCP the anthropic path uses into the agent.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport { createJiti } from 'jiti';\nimport { VERSION } from '@shared/version';\nimport { logToFile } from '@utils/debug';\nimport { onAccessTokenRotated } from '@shared/oauth-session';\n\nconst MCP_TOKEN_ENV = 'POSTHOG_MCP_TOKEN';\nlet mcpTokenOwners = 0;\nlet activeMcpToken: string | undefined;\nlet previousMcpToken: string | undefined;\n\nlet stopFollowingRotations: (() => void) | undefined;\n\nfunction setMcpToken(token: string): void {\n activeMcpToken = token;\n process.env[MCP_TOKEN_ENV] = token;\n}\n\nfunction acquireMcpToken(token: string): () => void {\n if (mcpTokenOwners === 0) {\n previousMcpToken = process.env[MCP_TOKEN_ENV];\n // The adapter reads the env on each connect, so reconnects take the rotated token.\n stopFollowingRotations = onAccessTokenRotated(setMcpToken);\n }\n // A later session after a rotation carries the newer token of the same login.\n if (activeMcpToken !== token) setMcpToken(token);\n mcpTokenOwners += 1;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n mcpTokenOwners -= 1;\n if (mcpTokenOwners > 0) return;\n stopFollowingRotations?.();\n stopFollowingRotations = undefined;\n if (previousMcpToken === undefined) delete process.env[MCP_TOKEN_ENV];\n else process.env[MCP_TOKEN_ENV] = previousMcpToken;\n activeMcpToken = undefined;\n previousMcpToken = undefined;\n };\n}\n\nexport interface PostHogMcpSetup {\n /** pi ExtensionFactory to add to the resource loader's `extensionFactories`. */\n extensionFactory: (pi: unknown) => void;\n /** Release this setup's token ownership. Call after the run. */\n cleanup: () => void;\n}\n\n/** Server `instructions` for the system prompt — the adapter exposes no accessor, so one standard-SDK handshake; best-effort. */\nexport async function fetchInstructions(\n mcpUrl: string,\n accessToken: string,\n userAgent: string,\n): Promise<string | undefined> {\n const client = new Client({ name: 'posthog-wizard', version: VERSION });\n try {\n const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {\n requestInit: {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': userAgent,\n },\n },\n });\n await client.connect(transport);\n const instructions = client.getInstructions() || undefined;\n logToFile(`[pi-mcp] instructions ${instructions?.length ?? 0} chars`);\n return instructions;\n } catch (err) {\n logToFile(`[pi-mcp] instructions fetch skipped: ${String(err)}`);\n return undefined;\n } finally {\n await client.close().catch(() => undefined);\n }\n}\n\nexport async function setupPostHogMcp(opts: {\n mcpUrl: string;\n accessToken: string;\n userAgent: string;\n}): Promise<PostHogMcpSetup> {\n const { mcpUrl, accessToken, userAgent } = opts;\n\n // By env NAME: the token stays in this process, off disk, and never reaches pi's env-scrubbed tool subprocesses.\n const cleanup = acquireMcpToken(accessToken);\n\n try {\n // The adapter ships raw TypeScript; loading through jiti is its documented requirement.\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import<{\n createMcpAdapter: (\n options: unknown,\n ) => PostHogMcpSetup['extensionFactory'];\n }>('pi-mcp-adapter');\n const extensionFactory = mod.createMcpAdapter({\n config: {\n mcpServers: {\n posthog: {\n url: mcpUrl,\n auth: 'bearer',\n bearerTokenEnv: MCP_TOKEN_ENV,\n headers: { 'User-Agent': userAgent },\n // Connect at extension load — direct tools register without a session_start.\n lifecycle: 'eager',\n // Register only `exec`: `directTools: true` also mints a `posthog_get_<name>` tool per MCP resource, whose sentence-length names overflow Anthropic's 128-char tool-name limit and 400 the whole request.\n directTools: ['exec'],\n exposeResources: false,\n },\n },\n // Disable the proxy `mcp` tool (its search indirection pollutes context); the adapter re-enables it only if no direct tools resolve.\n settings: { disableProxyTool: true, toolPrefix: 'posthog' },\n },\n });\n logToFile(`[pi-mcp] adapter loaded; posthog MCP at ${mcpUrl}`);\n return { extensionFactory, cleanup };\n } catch (error) {\n cleanup();\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,gBAAgB;AACtB,IAAI,iBAAiB;AACrB,IAAI;AACJ,IAAI;AAEJ,IAAI;AAEJ,SAAS,YAAY,OAAqB;AACxC,kBAAiB;AACjB,SAAQ,IAAI,iBAAiB;;AAG/B,SAAS,gBAAgB,OAA2B;AAClD,KAAI,mBAAmB,GAAG;AACxB,qBAAmB,QAAQ,IAAI;AAE/B,2BAAyB,qBAAqB,YAAY;;AAG5D,KAAI,mBAAmB,MAAO,aAAY,MAAM;AAChD,mBAAkB;CAClB,IAAI,WAAW;AACf,cAAa;AACX,MAAI,SAAU;AACd,aAAW;AACX,oBAAkB;AAClB,MAAI,iBAAiB,EAAG;AACxB,4BAA0B;AAC1B,2BAAyB,KAAA;AACzB,MAAI,qBAAqB,KAAA,EAAW,QAAO,QAAQ,IAAI;MAClD,SAAQ,IAAI,iBAAiB;AAClC,mBAAiB,KAAA;AACjB,qBAAmB,KAAA;;;;AAYvB,eAAsB,kBACpB,QACA,aACA,WAC6B;CAC7B,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAAkB,SAAS;EAAS,CAAC;AACvE,KAAI;EACF,MAAM,YAAY,IAAI,8BAA8B,IAAI,IAAI,OAAO,EAAE,EACnE,aAAa,EACX,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,EACF,CAAC;AACF,QAAM,OAAO,QAAQ,UAAU;EAC/B,MAAM,eAAe,OAAO,iBAAiB,IAAI,KAAA;AACjD,YAAU,yBAAyB,cAAc,UAAU,EAAE,QAAQ;AACrE,SAAO;UACA,KAAK;AACZ,YAAU,wCAAwC,OAAO,IAAI,GAAG;AAChE;WACQ;AACR,QAAM,OAAO,OAAO,CAAC,YAAY,KAAA,EAAU;;;AAI/C,eAAsB,gBAAgB,MAIT;CAC3B,MAAM,EAAE,QAAQ,aAAa,cAAc;CAG3C,MAAM,UAAU,gBAAgB,YAAY;AAE5C,KAAI;EAQF,MAAM,oBALM,MADC,WAAW,OAAO,KAAK,IAAI,CACjB,OAIpB,iBAAiB,EACS,iBAAiB,EAC5C,QAAQ;GACN,YAAY,EACV,SAAS;IACP,KAAK;IACL,MAAM;IACN,gBAAgB;IAChB,SAAS,EAAE,cAAc,WAAW;IAEpC,WAAW;IAEX,aAAa,CAAC,OAAO;IACrB,iBAAiB;IAClB,EACF;GAED,UAAU;IAAE,kBAAkB;IAAM,YAAY;IAAW;GAC5D,EACF,CAAC;AACF,YAAU,2CAA2C,SAAS;AAC9D,SAAO;GAAE;GAAkB;GAAS;UAC7B,OAAO;AACd,WAAS;AACT,QAAM"}
1
+ {"version":3,"file":"mcp-JcsBBnWv.js","names":[],"sources":["../src/agent/runner/harness/pi/mcp.ts"],"sourcesContent":["/**\n * pi has no built-in MCP; `pi-mcp-adapter` — pi's own MCP extension, built here\n * with its supported `createMcpAdapter` embedding API — bridges the same hosted\n * MCP the anthropic path uses into the agent.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport { createJiti } from 'jiti';\nimport { VERSION } from '@shared/version';\nimport { logToFile } from '@utils/debug';\nimport { onAccessTokenRotated } from '@shared/oauth-session';\n\nconst MCP_TOKEN_ENV = 'POSTHOG_MCP_TOKEN';\nlet mcpTokenOwners = 0;\nlet activeMcpToken: string | undefined;\nlet previousMcpToken: string | undefined;\n\nlet stopFollowingRotations: (() => void) | undefined;\n\nfunction setMcpToken(token: string): void {\n activeMcpToken = token;\n process.env[MCP_TOKEN_ENV] = token;\n}\n\nfunction acquireMcpToken(token: string): () => void {\n if (mcpTokenOwners === 0) {\n previousMcpToken = process.env[MCP_TOKEN_ENV];\n // The adapter reads the env on each connect, so reconnects take the rotated token.\n stopFollowingRotations = onAccessTokenRotated(setMcpToken);\n }\n // A later session after a rotation carries the newer token of the same login.\n if (activeMcpToken !== token) setMcpToken(token);\n mcpTokenOwners += 1;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n mcpTokenOwners -= 1;\n if (mcpTokenOwners > 0) return;\n stopFollowingRotations?.();\n stopFollowingRotations = undefined;\n if (previousMcpToken === undefined) delete process.env[MCP_TOKEN_ENV];\n else process.env[MCP_TOKEN_ENV] = previousMcpToken;\n activeMcpToken = undefined;\n previousMcpToken = undefined;\n };\n}\n\nexport interface PostHogMcpSetup {\n /** pi ExtensionFactory to add to the resource loader's `extensionFactories`. */\n extensionFactory: (pi: unknown) => void;\n /** Release this setup's token ownership. Call after the run. */\n cleanup: () => void;\n}\n\n/** Server `instructions` for the system prompt — the adapter exposes no accessor, so one standard-SDK handshake; best-effort. */\nexport async function fetchInstructions(\n mcpUrl: string,\n accessToken: string,\n userAgent: string,\n): Promise<string | undefined> {\n const client = new Client({ name: 'posthog-wizard', version: VERSION });\n try {\n const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {\n requestInit: {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': userAgent,\n },\n },\n });\n await client.connect(transport);\n const instructions = client.getInstructions() || undefined;\n logToFile(`[pi-mcp] instructions ${instructions?.length ?? 0} chars`);\n return instructions;\n } catch (err) {\n logToFile(`[pi-mcp] instructions fetch skipped: ${String(err)}`);\n return undefined;\n } finally {\n await client.close().catch(() => undefined);\n }\n}\n\nexport async function setupPostHogMcp(opts: {\n mcpUrl: string;\n accessToken: string;\n userAgent: string;\n}): Promise<PostHogMcpSetup> {\n const { mcpUrl, accessToken, userAgent } = opts;\n\n // By env NAME: the token stays in this process, off disk, and never reaches pi's env-scrubbed tool subprocesses.\n const cleanup = acquireMcpToken(accessToken);\n\n try {\n // The adapter ships raw TypeScript; loading through jiti is its documented requirement.\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import<{\n createMcpAdapter: (\n options: unknown,\n ) => PostHogMcpSetup['extensionFactory'];\n }>('pi-mcp-adapter');\n const extensionFactory = mod.createMcpAdapter({\n config: {\n mcpServers: {\n posthog: {\n url: mcpUrl,\n auth: 'bearer',\n bearerTokenEnv: MCP_TOKEN_ENV,\n headers: { 'User-Agent': userAgent },\n // Connect at extension load — direct tools register without a session_start.\n lifecycle: 'eager',\n // Register only `exec`: `directTools: true` also mints a `posthog_get_<name>` tool per MCP resource, whose sentence-length names overflow Anthropic's 128-char tool-name limit and 400 the whole request.\n directTools: ['exec'],\n exposeResources: false,\n },\n },\n // Disable the proxy `mcp` tool (its search indirection pollutes context); the adapter re-enables it only if no direct tools resolve.\n settings: { disableProxyTool: true, toolPrefix: 'posthog' },\n },\n });\n logToFile(`[pi-mcp] adapter loaded; posthog MCP at ${mcpUrl}`);\n return { extensionFactory, cleanup };\n } catch (error) {\n cleanup();\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,gBAAgB;AACtB,IAAI,iBAAiB;AACrB,IAAI;AACJ,IAAI;AAEJ,IAAI;AAEJ,SAAS,YAAY,OAAqB;AACxC,kBAAiB;AACjB,SAAQ,IAAI,iBAAiB;;AAG/B,SAAS,gBAAgB,OAA2B;AAClD,KAAI,mBAAmB,GAAG;AACxB,qBAAmB,QAAQ,IAAI;AAE/B,2BAAyB,qBAAqB,YAAY;;AAG5D,KAAI,mBAAmB,MAAO,aAAY,MAAM;AAChD,mBAAkB;CAClB,IAAI,WAAW;AACf,cAAa;AACX,MAAI,SAAU;AACd,aAAW;AACX,oBAAkB;AAClB,MAAI,iBAAiB,EAAG;AACxB,4BAA0B;AAC1B,2BAAyB,KAAA;AACzB,MAAI,qBAAqB,KAAA,EAAW,QAAO,QAAQ,IAAI;MAClD,SAAQ,IAAI,iBAAiB;AAClC,mBAAiB,KAAA;AACjB,qBAAmB,KAAA;;;;AAYvB,eAAsB,kBACpB,QACA,aACA,WAC6B;CAC7B,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAAkB,SAAS;EAAS,CAAC;AACvE,KAAI;EACF,MAAM,YAAY,IAAI,8BAA8B,IAAI,IAAI,OAAO,EAAE,EACnE,aAAa,EACX,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,EACF,CAAC;AACF,QAAM,OAAO,QAAQ,UAAU;EAC/B,MAAM,eAAe,OAAO,iBAAiB,IAAI,KAAA;AACjD,YAAU,yBAAyB,cAAc,UAAU,EAAE,QAAQ;AACrE,SAAO;UACA,KAAK;AACZ,YAAU,wCAAwC,OAAO,IAAI,GAAG;AAChE;WACQ;AACR,QAAM,OAAO,OAAO,CAAC,YAAY,KAAA,EAAU;;;AAI/C,eAAsB,gBAAgB,MAIT;CAC3B,MAAM,EAAE,QAAQ,aAAa,cAAc;CAG3C,MAAM,UAAU,gBAAgB,YAAY;AAE5C,KAAI;EAQF,MAAM,oBALM,MADC,WAAW,OAAO,KAAK,IAAI,CACjB,OAIpB,iBAAiB,EACS,iBAAiB,EAC5C,QAAQ;GACN,YAAY,EACV,SAAS;IACP,KAAK;IACL,MAAM;IACN,gBAAgB;IAChB,SAAS,EAAE,cAAc,WAAW;IAEpC,WAAW;IAEX,aAAa,CAAC,OAAO;IACrB,iBAAiB;IAClB,EACF;GAED,UAAU;IAAE,kBAAkB;IAAM,YAAY;IAAW;GAC5D,EACF,CAAC;AACF,YAAU,2CAA2C,SAAS;AAC9D,SAAO;GAAE;GAAkB;GAAS;UAC7B,OAAO;AACd,WAAS;AACT,QAAM"}
@@ -1,8 +1,8 @@
1
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
2
- import { Q as WIZARD_USER_AGENT, l as DEFAULT_AGENT_MODEL } from "./constants-jFI2SaE1.js";
3
- import { n as analytics } from "./analytics-CHCZ_qUR.js";
4
- import { l as gatewayAuth } from "./gateway-CjoShdLa.js";
5
- import { f as sanitizeAgentSubprocessEnv, n as buildRunTags, o as createIsolatedAgentConfigDir, t as buildAgentEnv } from "./agent-interface-BAOIHuXS.js";
1
+ import { s as logToFile } from "./debug-Cj-8vfXY.js";
2
+ import { Q as WIZARD_USER_AGENT, l as DEFAULT_AGENT_MODEL } from "./constants-CuJfQEcC.js";
3
+ import { n as analytics } from "./analytics-VRYdebXW.js";
4
+ import { f as gatewayAuth } from "./gateway-CVU1G0H3.js";
5
+ import { f as sanitizeAgentSubprocessEnv, n as buildRunTags, o as createIsolatedAgentConfigDir, t as buildAgentEnv } from "./agent-interface-BXvmAm4c.js";
6
6
  //#region src/agent/mcp-prompt-streaming.ts
7
7
  let _sdkModule = null;
8
8
  async function loadSdk() {
@@ -250,4 +250,4 @@ async function* runMcpPromptViaSdk(args) {
250
250
  //#endregion
251
251
  export { runMcpPromptViaSdk };
252
252
 
253
- //# sourceMappingURL=mcp-prompt-streaming-I2U_X7BC.js.map
253
+ //# sourceMappingURL=mcp-prompt-streaming-B-p_Pvb2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-prompt-streaming-B-p_Pvb2.js","names":[],"sources":["../src/agent/mcp-prompt-streaming.ts"],"sourcesContent":["/**\n * Streaming prompt runner for the McpSuggestedPromptsScreen.\n *\n * Calls the Claude Agent SDK's `query()` directly with just the PostHog\n * MCP server configured — no skills, no sandbox, no settings sources,\n * no wizard-tools. This is the lightweight cousin of `runAgent` in\n * `agent-interface.ts`: same SDK, much narrower surface, suitable for\n * \"user asked a question, show the answer\" interactions.\n *\n * The function is an async generator that yields `AgentChunk`s extracted\n * from the SDK's message stream. Callers (the screen) consume them via\n * `for await (...)` and render as they arrive.\n */\n\nimport type { Credentials } from '@shared/api';\nimport { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@shared/constants';\nimport { logToFile } from '@utils/debug';\nimport { gatewayAuth } from '@agent/gateway-session';\nimport { buildAgentEnv, buildRunTags } from '@agent/agent-interface';\nimport { sanitizeAgentSubprocessEnv } from '@shared/agent-env-isolation';\nimport { createIsolatedAgentConfigDir } from '@agent/stored-login';\nimport { analytics } from '@utils/analytics';\n\n/**\n * Discriminated union covering every kind of streamed event the screen\n * needs to render. Production yields these from Claude SDK messages;\n * the playground yields them from canned scripts.\n */\nexport type AgentChunk =\n | { kind: 'text'; text: string }\n /** `command` carries CLI mode's exec command string (`call <tool> …`) so the\n * screen can recover the inner tool for context-aware follow-ups. */\n | { kind: 'tool-call'; toolName: string; detail: string; command?: string }\n | { kind: 'tool-result'; toolName: string; detail: string }\n | { kind: 'error'; text: string }\n /** Stream completed. `sessionId` is the SDK session ID of the just-\n * completed turn; pass it back as `resumeSessionId` on a follow-up\n * call to continue the conversation with full history. */\n | { kind: 'done'; sessionId?: string };\n\n// Cached SDK module — first call pays the dynamic-import cost; later\n// calls reuse the same module.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _sdkModule: any | null = null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function loadSdk(): Promise<any> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\nconst MODEL = DEFAULT_AGENT_MODEL;\n\n// Bounded turn count so a single prompt can't loop forever on the\n// user's nickel. 20 gives the agent room for non-trivial multi-step\n// chains (multi-tool reads → reason → write → verify → summarize) while\n// still capping runaway loops. Worth tuning down once we see real\n// telemetry on average turn counts per prompt.\nconst MAX_TURNS = 30;\n\n/**\n * Extract a short, single-line summary from an arbitrary value. Used\n * for tool-call args and tool-result bodies so the screen has something\n * compact to render.\n */\nfunction summarize(value: unknown, maxLen = 120): string {\n if (value == null) return '';\n let text: string;\n if (typeof value === 'string') text = value;\n else {\n try {\n text = JSON.stringify(value);\n } catch {\n text = String(value);\n }\n }\n text = text.replace(/\\s+/g, ' ').trim();\n if (text.length > maxLen) text = text.slice(0, maxLen - 1) + '…';\n return text;\n}\n\n/**\n * Convert one SDK message into zero or more AgentChunks. Mirrors the\n * subset of message shapes the wizard's main runAgent middleware\n * handles, but narrowed to just the kinds the screen needs to render.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction messageToChunks(message: any): AgentChunk[] {\n const chunks: AgentChunk[] = [];\n\n if (message?.type === 'assistant') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n if (text) chunks.push({ kind: 'text', text });\n } else if (type === 'tool_use') {\n const name = (block as { name?: string }).name ?? 'tool';\n const input = (block as { input?: unknown }).input;\n // CLI mode's exec tool takes a `command` string; keep it verbatim so\n // the screen can recover the inner tool name for follow-ups.\n const command = (input as { command?: unknown })?.command;\n chunks.push({\n kind: 'tool-call',\n toolName: name,\n detail: summarize(input),\n command: typeof command === 'string' ? command : undefined,\n });\n }\n }\n }\n }\n\n if (message?.type === 'user') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'tool_result') {\n const detail = summarize((block as { content?: unknown }).content);\n chunks.push({ kind: 'tool-result', toolName: 'tool', detail });\n }\n }\n }\n }\n\n if (message?.type === 'result') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const sessionId = (message as { session_id?: string }).session_id;\n chunks.push({ kind: 'done', sessionId });\n }\n\n return chunks;\n}\n\n/**\n * Build a system-prompt append that nudges the agent to fit its response\n * inside the current terminal window. We can't actually constrain Claude\n * — this is a soft cap that the model usually honors. The screen also\n * applies a hard truncation cap as a fallback for non-compliant runs.\n *\n * Core principle nudged at the model: TALL CONTENT IS BAD, WIDE CONTENT\n * IS GOOD. Default terminal is 120 columns × 24 rows — that's a lot of\n * horizontal space, not much vertical. Spread data across columns, never\n * stack it down rows when a horizontal layout would work.\n */\nfunction buildTerminalFitPrompt(): string {\n const cols = process.stdout.columns ?? 120;\n const rows = process.stdout.rows ?? 24;\n // Reserve rows for wizard chrome (title, status, hint, margins).\n const messageBudget = Math.max(8, rows - 10);\n\n return [\n `You are responding inside a CLI window that is exactly ${cols} columns wide and ${rows} rows tall. The user CAN'T SCROLL — your entire reply must fit on screen.`,\n ``,\n `LAYOUT PRINCIPLE: tall content is the enemy, wide content is your friend. You have ${cols} columns of horizontal space; use them. Spread data across columns instead of stacking it down rows.`,\n ``,\n `Tables:`,\n `- Max 5 body rows. The prompts the user picks already constrain results to 5 or fewer — honor that and do not pad with extra rows.`,\n `- If a tool result returns more than 5 items, show the top 5 and mention the rest count inline (e.g. \"...and 12 more\").`,\n `- Prefer transposing wide-but-short data (items across columns, metrics down rows) when labels are short.`,\n `- A two-column table with many rows is the tall layout to AVOID.`,\n ``,\n `Other limits:`,\n `- Aim for 3-5 lines of prose. Maximum ${messageBudget} lines total.`,\n `- DO NOT announce what you are about to do. Skip preamble like \"I'll query…\", \"Let me check…\", \"Now I'll…\", \"I'm going to…\". Go straight to running tools and then the answer.`,\n `- Lists: if there are 6+ short items, format them inline (comma-separated), not as a vertical bullet list.`,\n `- For tool results, summarize the 1-3 numbers that matter. Do NOT echo raw JSON or the full payload.`,\n `- Code blocks: no language tag, no leading blank lines.`,\n `- No closing pleasantries (\"let me know if…\", \"feel free to…\"). Stop when the answer is delivered.`,\n `- No section headers unless the response actually has multiple sections.`,\n ``,\n `Naming saved artifacts:`,\n `- Every dashboard, insight, notebook, or annotation you create MUST include \"(wizard MCP tutorial)\" at the end of its title or name field. Examples: \"Weekly signups (wizard MCP tutorial)\", \"Top errors this week (wizard MCP tutorial)\", \"Onboarding analysis (wizard MCP tutorial)\".`,\n `- This applies on both create AND rename calls. If the user asks you to rename a saved artifact, preserve the \"(wizard MCP tutorial)\" suffix unless they explicitly ask you to drop it.`,\n `- Reason: lets the user find / clean up everything this tutorial created from one search in PostHog. Don't skip it — it's the only signal they'll have that an artifact came from the wizard.`,\n ``,\n `Tone & framing:`,\n `- This is a tutorial demoing PostHog (the product the user just installed). You are showing it off, not auditing it. Stay constructive and neutral about PostHog throughout.`,\n `- Don't editorialize about PostHog's reliability, performance, or cost. Describe what the data shows; treat anomalies as the user's data, not a platform issue.`,\n `- If a tool call fails or returns nothing, say \"the query didn't return data — try a different angle\" or similar. Do NOT speculate about outages, gateway issues, MCP problems, or service health.`,\n `- Avoid value-laden phrases like \"worth investigating\", \"concerning\", \"red flag\", \"problematic\", \"suspicious\", \"alarming\" when describing the user's metrics. Stick to what the numbers show; the user draws conclusions.`,\n ].join('\\n');\n}\n\n/**\n * Gateway trace tags for a tutorial prompt run — without them the gateway has\n * nothing to attribute its `$ai_generation` events to. Returns `{}` when no\n * program is supplied. Exported so the contract is testable without the SDK.\n */\nexport function buildTutorialRunTags(args: {\n programId?: string;\n integration?: string;\n}): Record<string, string> {\n if (!args.programId) return {};\n return buildRunTags({\n programId: args.programId,\n // The tutorial usually has no detected framework; fall back to the\n // program so the axis is never an empty string.\n integration: args.integration ?? args.programId,\n runId: analytics.runId,\n build: analytics.build,\n });\n}\n\nexport async function* runMcpPromptViaSdk(args: {\n prompt: string;\n credentials: Credentials;\n signal: AbortSignal;\n /** When set, the SDK loads the named session's prior turns as\n * context so the follow-up prompt can reference what the agent\n * already showed. */\n resumeSessionId?: string;\n /** Program this run's gateway spend attributes to. Omitting it fails the run\n * rather than going unattributed, so every caller must supply one. */\n programId?: string;\n /** Integration label for the trace tags; the tutorial usually has none. */\n integration?: string;\n}): AsyncIterable<AgentChunk> {\n const { prompt, credentials, signal, resumeSessionId } = args;\n\n // Assembled here rather than passed in so the TUI service layer doesn't\n // have to import this module's dependencies.\n const wizardMetadata = buildTutorialRunTags(args);\n\n // Route the SDK's LLM calls through the PostHog AI gateway, authed\n // with the run's minted token. Set BEFORE loading the SDK in\n // case any in-process code reads env at module init (cached base\n // URLs, OAuth setup, etc.) — same reason `initializeAgent` does this\n // before its query() call. Without these the SDK tries to\n // authenticate directly against Anthropic and 401s with \"Invalid\n // authentication credentials\".\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n\n // The url and the bearer are one unit: a run must take both from the same\n // mint.\n const auth = await gatewayAuth(\n credentials.host,\n credentials.accessToken,\n args.programId,\n );\n const gatewayUrl = auth.gatewayUrl;\n process.env.ANTHROPIC_BASE_URL = gatewayUrl;\n process.env.ANTHROPIC_AUTH_TOKEN = auth.token;\n process.env.CLAUDE_CODE_OAUTH_TOKEN = auth.token;\n\n logToFile(\n `[runMcpPromptViaSdk] gatewayUrl=${gatewayUrl} tokenPrefix=${\n auth.token ? auth.token.slice(0, 4) + '***' : '(missing)'\n }`,\n );\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { query } = await loadSdk();\n\n // Bridge external AbortSignal → SDK AbortController.\n const abortController = new AbortController();\n if (signal.aborted) abortController.abort();\n else\n signal.addEventListener('abort', () => abortController.abort(), {\n once: true,\n });\n\n const mcpUrl = credentials.host.mcpUrl;\n logToFile(\n `[runMcpPromptViaSdk] mcpUrl=${mcpUrl} model=${MODEL} resume=${\n resumeSessionId ?? '(none)'\n }`,\n );\n\n // The SDK expects an async generator for the prompt that stays open\n // until the result is received. For a single-turn prompt we yield one\n // user message and then await an abort (which fires when streaming\n // completes or the caller cancels).\n const createPromptStream = async function* () {\n yield {\n type: 'user' as const,\n session_id: '',\n message: { role: 'user' as const, content: prompt },\n parent_tool_use_id: null,\n };\n // Hold the stream open until abort. The SDK closes its end when it\n // sees a `result` message; we close ours via the abortController in\n // the finally block below.\n await new Promise<void>((resolve) => {\n if (abortController.signal.aborted) {\n resolve();\n return;\n }\n abortController.signal.addEventListener('abort', () => resolve(), {\n once: true,\n });\n });\n };\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n const response = query({\n prompt: createPromptStream(),\n options: {\n abortController,\n model: MODEL,\n cwd: process.cwd(),\n permissionMode: 'acceptEdits',\n maxTurns: MAX_TURNS,\n // Match agent-interface.ts — the 1M context beta is what keeps\n // resumed follow-up sessions from truncating after a few turns.\n betas: ['context-1m-2025-08-07'],\n // Only load project-level skills/settings. Without this the SDK\n // defaults to ['user', 'project'] and a user's\n // `~/.claude/settings.json` (apiKeyHelper / env block) can\n // override the OAuth routing we set above.\n settingSources: ['project'],\n // When set, the SDK replays the named session's turns into the\n // new query so the follow-up prompt has full conversation\n // context. Omit on the first prompt for a fresh session.\n ...(resumeSessionId ? { resume: resumeSessionId } : {}),\n // Without `canUseTool` the SDK falls back to \"ask the user\" on\n // every MCP tool call — `permissionMode: 'acceptEdits'` only\n // relaxes Edit/Write, not MCP. Our Ink TUI has no surface to\n // answer that prompt, so the agent would stall mid-stream\n // saying things like \"needs your approval to create dashboard\".\n // The tutorial's whole point is demoing the MCP tools against\n // the user's project, so we auto-allow everything that matches\n // the prefix and deny anything else (defense in depth — the\n // `allowedTools` filter above already enforces this).\n canUseTool: (toolName: string, input: unknown) => {\n if (toolName.startsWith('mcp__posthog-wizard__')) {\n return Promise.resolve({\n behavior: 'allow' as const,\n updatedInput: (input ?? {}) as Record<string, unknown>,\n });\n }\n logToFile(`[runMcpPromptViaSdk] denying non-MCP tool: ${toolName}`);\n return Promise.resolve({\n behavior: 'deny' as const,\n message: `${toolName} is not available in the MCP tutorial — only PostHog MCP tools are permitted.`,\n });\n },\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: buildTerminalFitPrompt(),\n },\n mcpServers: {\n 'posthog-wizard': {\n type: 'http',\n url: mcpUrl,\n headers: {\n // Env reference, not the token: the SDK puts this config on the\n // spawned CLI's argv, where `ps` shows it to any local process.\n Authorization: 'Bearer ${POSTHOG_MCP_TOKEN}',\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // CLI mode's single `exec` tool carries the full command reference\n // on its schema — keep it in context, never deferred behind tool\n // search.\n alwaysLoad: true,\n },\n },\n // Only let the agent use MCP tools — no shell, no file I/O,\n // no Read/Edit/Write. This is a chat-with-MCP run, not a\n // wizard skill execution.\n allowedTools: ['mcp__posthog-wizard__*'],\n env: {\n // Drop the ENTIRE ANTHROPIC_*/CLAUDE_CODE_* namespace from the\n // inherited env so no shell/settings value can silently bypass the\n // PostHog gateway and defeat quota tracking / the OAuth flow; the\n // wizard's own gateway routing is injected fresh below. See\n // agent-env-isolation.ts.\n ...sanitizeAgentSubprocessEnv(process.env),\n // Gateway routing from this run's own auth, not process.env: a\n // concurrent run writes those globals too, and there is an await\n // between the write above and this read.\n ANTHROPIC_BASE_URL: auth.gatewayUrl,\n ANTHROPIC_AUTH_TOKEN: auth.token,\n CLAUDE_CODE_OAUTH_TOKEN: auth.token,\n // Point the binary at an empty config dir so it cannot resolve a\n // stored Claude login and send that to the gateway, which 401s it.\n // See stored-login.ts.\n CLAUDE_CONFIG_DIR: createIsolatedAgentConfigDir(),\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // The MCP config resolves this in the child; sending the value would\n // put it on the CLI's argv.\n POSTHOG_MCP_TOKEN: credentials.accessToken,\n // SDK 0.3.142+ connects MCP servers in the background by\n // default; without this the agent may try to call tools\n // before posthog-wizard is connected on turn 1.\n MCP_CONNECTION_NONBLOCKING: '0',\n // This run's trace tags, which the gateway reads to attribute its\n // `$ai_generation` events. Flags stay empty: the tutorial doesn't\n // fork on any.\n ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(\n wizardMetadata ?? {},\n {},\n auth.teamId,\n ),\n },\n },\n });\n\n for await (const message of response as AsyncIterable<unknown>) {\n if (signal.aborted) return;\n for (const chunk of messageToChunks(message)) {\n yield chunk;\n if (chunk.kind === 'done') return;\n }\n }\n } catch (err) {\n const text = err instanceof Error ? err.message : String(err);\n logToFile(`[runMcpPromptViaSdk] error: ${text}`);\n yield { kind: 'error', text };\n } finally {\n // Closes the prompt stream so `query()` shuts down cleanly even if\n // we never saw a 'result' message.\n abortController.abort();\n }\n}\n"],"mappings":"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"}