@posthog/wizard 2.78.0 → 2.79.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +20 -11
  2. package/dist/PickerMenu-dG5DQCZA.js +758 -0
  3. package/dist/PickerMenu-dG5DQCZA.js.map +1 -0
  4. package/dist/{add-mcp-server-to-clients-JMv8LP-O.js → add-mcp-server-to-clients-DIaTRWMY.js} +7 -18
  5. package/dist/{add-mcp-server-to-clients-JMv8LP-O.js.map → add-mcp-server-to-clients-DIaTRWMY.js.map} +1 -1
  6. package/dist/add-mcp-server-to-clients-artmN7mz.js +2 -0
  7. package/dist/agent-BEjARD2a.js +6 -0
  8. package/dist/{agent-bCZ3i3fh.js → agent-BWFhuLgo.js} +131 -38
  9. package/dist/agent-BWFhuLgo.js.map +1 -0
  10. package/dist/{agent-interface-BAOIHuXS.js → agent-interface-FkbaBJwz.js} +66 -28
  11. package/dist/agent-interface-FkbaBJwz.js.map +1 -0
  12. package/dist/{agent-prompt-loader-7Pd4CfZO.js → agent-prompt-loader-D0weQ-7k.js} +5 -5
  13. package/dist/{agent-prompt-loader-7Pd4CfZO.js.map → agent-prompt-loader-D0weQ-7k.js.map} +1 -1
  14. package/dist/analytics-DFtbRjYh.js +2 -0
  15. package/dist/{analytics-CHCZ_qUR.js → analytics-DXK1gc12.js} +4 -4
  16. package/dist/{analytics-CHCZ_qUR.js.map → analytics-DXK1gc12.js.map} +1 -1
  17. package/dist/api-Cm9UtKZh.js +2 -0
  18. package/dist/{api-Diy_2fp8.js → api-CrbCIQOz.js} +4 -16
  19. package/dist/{api-Diy_2fp8.js.map → api-CrbCIQOz.js.map} +1 -1
  20. package/dist/bin.js +5 -2957
  21. package/dist/bin.js.map +1 -1
  22. package/dist/{bounded-fs-Bx9zTe6m.js → bounded-fs-vAq-T-K7.js} +3 -3
  23. package/dist/{bounded-fs-Bx9zTe6m.js.map → bounded-fs-vAq-T-K7.js.map} +1 -1
  24. package/dist/{ci-install-CDdQYsPe.js → ci-install-COcV8SY2.js} +8 -7
  25. package/dist/ci-install-COcV8SY2.js.map +1 -0
  26. package/dist/{constants-jFI2SaE1.js → constants-DHCBSfnx.js} +3 -3
  27. package/dist/{constants-jFI2SaE1.js.map → constants-DHCBSfnx.js.map} +1 -1
  28. package/dist/{debug-M2gV2iDq.js → debug-BuYHGr6_.js} +1 -1
  29. package/dist/{debug-Ch4BDOtD.js → debug-kAHwWGg7.js} +2 -2
  30. package/dist/{debug-Ch4BDOtD.js.map → debug-kAHwWGg7.js.map} +1 -1
  31. package/dist/{defaults-C6J7yL4O.js → defaults-a9TelDhJ.js} +1 -1
  32. package/dist/{defaults-C6J7yL4O.js.map → defaults-a9TelDhJ.js.map} +1 -1
  33. package/dist/emit-BSetXzDV.js +69 -0
  34. package/dist/emit-BSetXzDV.js.map +1 -0
  35. package/dist/{endpoints-DCVbM06L.js → endpoints-BVMYm9F4.js} +3 -3
  36. package/dist/{endpoints-DCVbM06L.js.map → endpoints-BVMYm9F4.js.map} +1 -1
  37. package/dist/{env-api-key-Qx8NnYHm.js → env-api-key-BP-NFFXt.js} +3 -5
  38. package/dist/{env-api-key-Qx8NnYHm.js.map → env-api-key-BP-NFFXt.js.map} +1 -1
  39. package/dist/env-api-key-CaWEDj_9.js +2 -0
  40. package/dist/{environment-B07Bmxae.js → environment-BATlQxcQ.js} +5 -10
  41. package/dist/{environment-B07Bmxae.js.map → environment-BATlQxcQ.js.map} +1 -1
  42. package/dist/environment-CwD8OPYj.js +2 -0
  43. package/dist/errors-C2domSkK.js +79 -0
  44. package/dist/errors-C2domSkK.js.map +1 -0
  45. package/dist/file-C5JMsyR1.js +2 -0
  46. package/dist/{file-BcLTjU16.js → file-DcRKycV8.js} +4 -4
  47. package/dist/file-DcRKycV8.js.map +1 -0
  48. package/dist/{file-watcher-DWc_bTs6.js → file-watcher-Brq2nnHV.js} +2 -2
  49. package/dist/{file-watcher-DWc_bTs6.js.map → file-watcher-Brq2nnHV.js.map} +1 -1
  50. package/dist/{gateway-CjoShdLa.js → gateway-C9-GlLO9.js} +39 -8
  51. package/dist/gateway-C9-GlLO9.js.map +1 -0
  52. package/dist/{headless-ui-BFFmYC4v.js → headless-ui-CqI2gXlD.js} +2 -2
  53. package/dist/{headless-ui-BFFmYC4v.js.map → headless-ui-CqI2gXlD.js.map} +1 -1
  54. package/dist/{interactive-D6zV7brJ.js → interactive-B_Ti_CsS.js} +3 -3
  55. package/dist/interactive-B_Ti_CsS.js.map +1 -0
  56. package/dist/{logging-ui-_TwoMNbG.js → logging-ui-Dza4D0MK.js} +5 -5
  57. package/dist/{logging-ui-_TwoMNbG.js.map → logging-ui-Dza4D0MK.js.map} +1 -1
  58. package/dist/main-CgKxbwMP.js +1396 -0
  59. package/dist/main-CgKxbwMP.js.map +1 -0
  60. package/dist/{mcp-DAgaoGk5.js → mcp-DnAyW0-w.js} +4 -4
  61. package/dist/{mcp-DAgaoGk5.js.map → mcp-DnAyW0-w.js.map} +1 -1
  62. package/dist/{mcp-prompt-streaming-I2U_X7BC.js → mcp-prompt-streaming-DDWQ-FCA.js} +6 -6
  63. package/dist/mcp-prompt-streaming-DDWQ-FCA.js.map +1 -0
  64. package/dist/{mint-failure-D4nd2XmZ.js → mint-failure-u8xQKNOn.js} +689 -126
  65. package/dist/mint-failure-u8xQKNOn.js.map +1 -0
  66. package/dist/{models-DDdBJKwT.js → models-WcwUnSKb.js} +2 -2
  67. package/dist/{models-DDdBJKwT.js.map → models-WcwUnSKb.js.map} +1 -1
  68. package/dist/{non-interactive-Dzow7YKY.js → non-interactive-DyVC1AGc.js} +4 -3
  69. package/dist/{non-interactive-Dzow7YKY.js.map → non-interactive-DyVC1AGc.js.map} +1 -1
  70. package/dist/{oauth-session-DJ8h6GFa.js → oauth-session-DYM2Hrl2.js} +2 -2
  71. package/dist/{oauth-session-DJ8h6GFa.js.map → oauth-session-DYM2Hrl2.js.map} +1 -1
  72. package/dist/{orchestrator-tools-szcdscwn.js → orchestrator-tools-DbgNBFGA.js} +3 -3
  73. package/dist/{orchestrator-tools-szcdscwn.js.map → orchestrator-tools-DbgNBFGA.js.map} +1 -1
  74. package/dist/{package-json-DY70kkNp.js → package-json-Atg34fa4.js} +2 -8
  75. package/dist/{package-json-DY70kkNp.js.map → package-json-Atg34fa4.js.map} +1 -1
  76. package/dist/package-json-D8Ga03tK.js +2 -0
  77. package/dist/{pi-D3h5Ok0i.js → pi-8KsYsPmM.js} +145 -45
  78. package/dist/pi-8KsYsPmM.js.map +1 -0
  79. package/dist/{playground-5AB4WgNF.js → playground-BlYRBMj7.js} +11 -11
  80. package/dist/playground-BlYRBMj7.js.map +1 -0
  81. package/dist/{posthog-DNn574nW.js → posthog-Bt0Aplb8.js} +4 -9
  82. package/dist/posthog-Bt0Aplb8.js.map +1 -0
  83. package/dist/posthog-CUgCEhH0.js +2 -0
  84. package/dist/{provisioning-B8uSqRZk.js → provisioning-Bo2NRxFz.js} +5 -11
  85. package/dist/{provisioning-B8uSqRZk.js.map → provisioning-Bo2NRxFz.js.map} +1 -1
  86. package/dist/provisioning-OGFGlzf7.js +2 -0
  87. package/dist/{queue-tools-9OOVx5TE.js → queue-tools-C8mXOh7e.js} +3 -3
  88. package/dist/{queue-tools-9OOVx5TE.js.map → queue-tools-C8mXOh7e.js.map} +1 -1
  89. package/dist/registry-C06e_x-p.js +2 -0
  90. package/dist/{registry-8YG-kuXk.js → registry-CD5RQt38.js} +51 -53
  91. package/dist/registry-CD5RQt38.js.map +1 -0
  92. package/dist/run-agent-legacy-ChacZImU.js +2 -0
  93. package/dist/{run-agent-legacy-d7rWlzQR.js → run-agent-legacy-DOlM6DQu.js} +823 -1022
  94. package/dist/run-agent-legacy-DOlM6DQu.js.map +1 -0
  95. package/dist/runners-ov3EXF1n.js +834 -0
  96. package/dist/runners-ov3EXF1n.js.map +1 -0
  97. package/dist/{security-Cg_4a7vB.js → security-C71pkwqH.js} +16 -6
  98. package/dist/security-C71pkwqH.js.map +1 -0
  99. package/dist/{setup-utils-CmTCTPkX.js → setup-utils-B26Lf2yF.js} +12 -22
  100. package/dist/setup-utils-B26Lf2yF.js.map +1 -0
  101. package/dist/setup-utils-CVS86NYR.js +2 -0
  102. package/dist/{start-tui-CB2PZs1x.js → start-tui-Bo2L0bar.js} +30 -28
  103. package/dist/start-tui-Bo2L0bar.js.map +1 -0
  104. package/dist/{steps-BZcXRJNY.js → steps-BPcg3_3Q.js} +7 -7
  105. package/dist/{steps-BZcXRJNY.js.map → steps-BPcg3_3Q.js.map} +1 -1
  106. package/dist/{store-UN7c-ASf.js → store-BTzcvRGT.js} +12 -18
  107. package/dist/store-BTzcvRGT.js.map +1 -0
  108. package/dist/store-BpqySPXm.js +5 -0
  109. package/dist/{subagent-BofIDK-O.js → subagent-D1TrTchE.js} +3 -3
  110. package/dist/{subagent-BofIDK-O.js.map → subagent-D1TrTchE.js.map} +1 -1
  111. package/dist/{task-r9t1UhQP.js → task-DqRlQBfs.js} +18 -16
  112. package/dist/task-DqRlQBfs.js.map +1 -0
  113. package/dist/{task-stream-CMUilu54.js → task-stream-Bw6JaLCX.js} +10 -10
  114. package/dist/task-stream-Bw6JaLCX.js.map +1 -0
  115. package/dist/{tasks-Bbv_lOBG.js → tasks-ChWufsdO.js} +1 -1
  116. package/dist/{tasks-Bbv_lOBG.js.map → tasks-ChWufsdO.js.map} +1 -1
  117. package/dist/{telemetry-D6ruCtnv.js → telemetry-B7zJdRmA.js} +3 -3
  118. package/dist/{telemetry-D6ruCtnv.js.map → telemetry-B7zJdRmA.js.map} +1 -1
  119. package/dist/{terminal-DrGyci_a.js → terminal-zgkEfoCL.js} +17 -17
  120. package/dist/terminal-zgkEfoCL.js.map +1 -0
  121. package/dist/{tools-Dyfh9aCD.js → tools-CkJ2y9Wt.js} +9 -9
  122. package/dist/tools-CkJ2y9Wt.js.map +1 -0
  123. package/dist/{ui-BBVuTM1v.js → ui-Q6-RvERF.js} +3 -3
  124. package/dist/{ui-BBVuTM1v.js.map → ui-Q6-RvERF.js.map} +1 -1
  125. package/dist/{version-aXxpgRKx.js → version-CHhJjz_H.js} +2 -2
  126. package/dist/{version-aXxpgRKx.js.map → version-CHhJjz_H.js.map} +1 -1
  127. package/dist/{wizard-abort-BBkiUxfS.js → wizard-abort-BPdv07np.js} +7 -6
  128. package/dist/{wizard-abort-BBkiUxfS.js.map → wizard-abort-BPdv07np.js.map} +1 -1
  129. package/dist/wizard-abort-Br1qMDNa.js +3 -0
  130. package/dist/wizard-session-2w4Ru-Wz.js.map +1 -1
  131. package/dist/{wizard-ui-DoyOZxK8.js → wizard-ui-DVqrYaOM.js} +1 -1
  132. package/dist/{wizard-ui-DoyOZxK8.js.map → wizard-ui-DVqrYaOM.js.map} +1 -1
  133. package/dist/{yara-hooks-DCeMDd1o.js → yara-hooks-BnxejtXK.js} +5 -5
  134. package/dist/{yara-hooks-DCeMDd1o.js.map → yara-hooks-BnxejtXK.js.map} +1 -1
  135. package/dist/yara-hooks-DSuExwb4.js +2 -0
  136. package/package.json +2 -1
  137. package/dist/agent-bCZ3i3fh.js.map +0 -1
  138. package/dist/agent-interface-BAOIHuXS.js.map +0 -1
  139. package/dist/analytics-BcV-WCM4.js +0 -2
  140. package/dist/ci-install-CDdQYsPe.js.map +0 -1
  141. package/dist/errors-CQ9kttJD.js +0 -185
  142. package/dist/errors-CQ9kttJD.js.map +0 -1
  143. package/dist/file-BcLTjU16.js.map +0 -1
  144. package/dist/gateway-CjoShdLa.js.map +0 -1
  145. package/dist/interactive-D6zV7brJ.js.map +0 -1
  146. package/dist/mcp-prompt-streaming-I2U_X7BC.js.map +0 -1
  147. package/dist/mint-failure-D4nd2XmZ.js.map +0 -1
  148. package/dist/pi-D3h5Ok0i.js.map +0 -1
  149. package/dist/playground-5AB4WgNF.js.map +0 -1
  150. package/dist/posthog-DNn574nW.js.map +0 -1
  151. package/dist/registry-8YG-kuXk.js.map +0 -1
  152. package/dist/rolldown-runtime-B_-DWIq7.js +0 -15
  153. package/dist/run-agent-legacy-d7rWlzQR.js.map +0 -1
  154. package/dist/security-Cg_4a7vB.js.map +0 -1
  155. package/dist/setup-utils-CmTCTPkX.js.map +0 -1
  156. package/dist/start-tui-CB2PZs1x.js.map +0 -1
  157. package/dist/store-UN7c-ASf.js.map +0 -1
  158. package/dist/task-r9t1UhQP.js.map +0 -1
  159. package/dist/task-stream-CMUilu54.js.map +0 -1
  160. package/dist/terminal-DrGyci_a.js.map +0 -1
  161. package/dist/tools-Dyfh9aCD.js.map +0 -1
  162. package/dist/wizard-abort-BU4aLyvh.js +0 -3
  163. package/dist/yara-hooks-DSGuCU9A.js +0 -2
@@ -1,10 +1,10 @@
1
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
2
- import { n as analytics } from "./analytics-CHCZ_qUR.js";
3
- import { p as detectNodePackageManagers } from "./setup-utils-CmTCTPkX.js";
4
- import { $ as vaultSensitiveAnswers, A as CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION, B as describeAskCancellation, C as AUDIT_ADD_CHECKS_PARAM_DESCRIPTION, D as AUDIT_SEED_CHECKS_PARAM_DESCRIPTION, E as AUDIT_SEED_CHECKS_DESCRIPTION, F as WIZARD_ASK_TOOL_DESCRIPTION, G as mergeEnvValues, H as ensureGitignoreCoverage, I as WIZARD_TOOL_NAMES, J as resolveAuditChecks, K as normaliseAskSubject, L as addAuditChecks, M as WIZARD_ASK_KIND_DESCRIPTION, N as WIZARD_ASK_SENSITIVE_DESCRIPTION, O as AUDIT_STATUSES, P as WIZARD_ASK_SUBJECT_DESCRIPTION, Q as templateEnvWriteRefusal, R as checkEnvKeys, S as AUDIT_ADD_CHECKS_DESCRIPTION, T as AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION, U as installSkillById, W as legacyKeyNameRefusal, X as resolveEnvSecretRefs, Y as resolveEnvPath, Z as seedAuditChecks, _ as createSecretVault, b as PUBLISH_HANDOFF_TOOL_NAME, et as fetchSkillMenu, it as isFullyCancelled, j as ENV_FILE_PATH_DESCRIPTION, k as CHECK_ENV_KEYS_DESCRIPTION, q as resolveAskQuestionKinds, v as PUBLISH_HANDOFF_CONTENT_DESCRIPTION, w as AUDIT_RESOLVE_CHECKS_DESCRIPTION, x as publishHandoff, y as PUBLISH_HANDOFF_DESCRIPTION, z as createAskAccounting } from "./agent-interface-BAOIHuXS.js";
5
- import { o as withMode } from "./pi-D3h5Ok0i.js";
6
- import { h as AUDIT_CHECKS_FILE } from "./yara-hooks-DCeMDd1o.js";
7
- import { v as makeMutex } from "./queue-tools-9OOVx5TE.js";
1
+ import { $ as vaultSensitiveAnswers, A as CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION, B as describeAskCancellation, C as AUDIT_ADD_CHECKS_PARAM_DESCRIPTION, D as AUDIT_SEED_CHECKS_PARAM_DESCRIPTION, E as AUDIT_SEED_CHECKS_DESCRIPTION, F as WIZARD_ASK_TOOL_DESCRIPTION, G as mergeEnvValues, H as ensureGitignoreCoverage, I as WIZARD_TOOL_NAMES, J as resolveAuditChecks, K as normaliseAskSubject, L as addAuditChecks, M as WIZARD_ASK_KIND_DESCRIPTION, N as WIZARD_ASK_SENSITIVE_DESCRIPTION, O as AUDIT_STATUSES, P as WIZARD_ASK_SUBJECT_DESCRIPTION, Q as templateEnvWriteRefusal, R as checkEnvKeys, S as AUDIT_ADD_CHECKS_DESCRIPTION, T as AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION, U as installSkillById, W as legacyKeyNameRefusal, X as resolveEnvSecretRefs, Y as resolveEnvPath, Z as seedAuditChecks, _ as createSecretVault, b as PUBLISH_HANDOFF_TOOL_NAME, et as fetchSkillMenu, it as isFullyCancelled, j as ENV_FILE_PATH_DESCRIPTION, k as CHECK_ENV_KEYS_DESCRIPTION, q as resolveAskQuestionKinds, v as PUBLISH_HANDOFF_CONTENT_DESCRIPTION, w as AUDIT_RESOLVE_CHECKS_DESCRIPTION, x as publishHandoff, y as PUBLISH_HANDOFF_DESCRIPTION, z as createAskAccounting } from "./agent-interface-FkbaBJwz.js";
2
+ import { s as logToFile } from "./debug-kAHwWGg7.js";
3
+ import { n as analytics } from "./analytics-DXK1gc12.js";
4
+ import { g as detectNodePackageManagers } from "./setup-utils-B26Lf2yF.js";
5
+ import { o as withMode } from "./pi-8KsYsPmM.js";
6
+ import { h as AUDIT_CHECKS_FILE } from "./yara-hooks-BnxejtXK.js";
7
+ import { v as makeMutex } from "./queue-tools-C8mXOh7e.js";
8
8
  import fs from "fs";
9
9
  import path from "path";
10
10
  import { Type } from "typebox";
@@ -266,7 +266,7 @@ function createWizardPiTools(ctx) {
266
266
  promptSnippet: "publish_handoff(content) — publish the full report markdown to the wizard session",
267
267
  parameters: Type.Object({ content: Type.String({ description: PUBLISH_HANDOFF_CONTENT_DESCRIPTION }) }),
268
268
  execute(_id, args) {
269
- const result = publishHandoff(args.content, ctx.emit);
269
+ const result = publishHandoff(args.content, ctx.emit, { taskAgent: ctx.taskAgent });
270
270
  logToFile(`[pi] publish_handoff: ${result.message}`);
271
271
  return Promise.resolve(text(result.message));
272
272
  }
@@ -288,4 +288,4 @@ function createWizardPiTools(ctx) {
288
288
  //#endregion
289
289
  export { createWizardPiTools };
290
290
 
291
- //# sourceMappingURL=tools-Dyfh9aCD.js.map
291
+ //# sourceMappingURL=tools-CkJ2y9Wt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools-CkJ2y9Wt.js","names":["checkEnvKeys","checkEnvKeysCore"],"sources":["../src/agent/runner/harness/pi/tools.ts"],"sourcesContent":["/**\n * Wizard capabilities as pi custom tools (#5). pi does not mount MCP servers,\n * so the tools the wizard prompt depends on — skill discovery/install and\n * fenced `.env` edits — are exposed to pi as native `defineTool` tools backed\n * by the same helpers the claude-agent-sdk path uses (`fetchSkillMenu`,\n * `installSkillById`, `checkEnvKeys`, `mergeEnvValues`). Same tool names as the\n * MCP server so the shared prompt is unchanged. `wizard_ask` is wired here too\n * (same schema, caps, and askBridge as the MCP tool) so interactive programs\n * can interview the user on pi; without a bridge (CI) it errors on call.\n * Sensitive answers are vaulted to `{secretRef}` and resolved host-side by\n * set_env_values — the raw value never enters the model conversation.\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { Type } from 'typebox';\nimport { defineTool } from '@earendil-works/pi-coding-agent';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { analytics } from '@utils/analytics';\nimport { logToFile } from '@utils/debug';\nimport {\n ASK_MAX_QUESTIONS_PER_CALL,\n AUDIT_ADD_CHECKS_DESCRIPTION,\n AUDIT_ADD_CHECKS_PARAM_DESCRIPTION,\n AUDIT_RESOLVE_CHECKS_DESCRIPTION,\n AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION,\n AUDIT_SEED_CHECKS_DESCRIPTION,\n AUDIT_SEED_CHECKS_PARAM_DESCRIPTION,\n AUDIT_STATUSES,\n CHECK_ENV_KEYS_DESCRIPTION,\n CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION,\n DEFAULT_ASK_MAX_QUESTIONS,\n ENV_FILE_PATH_DESCRIPTION,\n WIZARD_TOOL_NAMES,\n addAuditChecks,\n checkEnvKeys as checkEnvKeysCore,\n resolveAuditChecks,\n seedAuditChecks,\n createAskAccounting,\n describeAskCancellation,\n ensureGitignoreCoverage,\n installSkillById,\n mergeEnvValues,\n normaliseAskSubject,\n resolveAskQuestionKinds,\n resolveEnvPath,\n resolveEnvSecretRefs,\n templateEnvWriteRefusal,\n legacyKeyNameRefusal,\n vaultSensitiveAnswers,\n WIZARD_ASK_KIND_DESCRIPTION,\n WIZARD_ASK_SENSITIVE_DESCRIPTION,\n WIZARD_ASK_SUBJECT_DESCRIPTION,\n WIZARD_ASK_TOOL_DESCRIPTION,\n} from '@agent/tools/tools';\nimport { fetchSkillMenu } from '@shared/skill-menu';\nimport type { LLMProvider } from '@posthog/warlock';\nimport type { ProgressEmitter } from '@agent/progress';\nimport {\n isFullyCancelled,\n type WizardAskBridge,\n} from '@agent/wizard-ask-bridge';\nimport {\n PUBLISH_HANDOFF_CONTENT_DESCRIPTION,\n PUBLISH_HANDOFF_DESCRIPTION,\n PUBLISH_HANDOFF_TOOL_NAME,\n publishHandoff,\n} from '@agent/tools/handoff';\nimport { createSecretVault } from '@shared/secret-vault';\nimport {\n AUDIT_CHECKS_FILE,\n type AuditCheck,\n type AuditStatus,\n} from '@shared/audit-ledger';\nimport { makeMutex } from '@utils/atomic-ledger';\nimport { withMode } from './index';\nimport {\n detectNodePackageManagers,\n type PackageManagerDetector,\n} from '@utils/package-manager';\n\nfunction text(s: string): {\n content: [{ type: 'text'; text: string }];\n details: unknown;\n} {\n return { content: [{ type: 'text', text: s }], details: {} };\n}\n\nexport interface PiToolsContext {\n workingDirectory: string;\n skillsBaseUrl: string;\n /** Framework's package-manager detector. Defaults to Node detection. */\n detectPackageManager?: PackageManagerDetector;\n /** Drives the `wizard_ask` overlay. Omitted in CI → the tool errors on call. */\n askBridge?: WizardAskBridge;\n /** Per-run cap on wizard_ask calls. Defaults to {@link DEFAULT_ASK_MAX_QUESTIONS}. */\n maxQuestions?: number;\n /** Overlay open/closed signal — the security gate blocks Write/Edit while open. */\n onAskPendingChange?: (pending: boolean) => void;\n /** Program disallow list; gates wizard_ask here since pi tools carry bare names the MCP-prefixed security gate misses. */\n disallowedTools?: readonly string[];\n /** Scan-triage classifier, resolved once in bootstrap. Absent → scans fail closed. */\n triageProvider?: LLMProvider;\n /** Where `publish_handoff` reports. Absent → the handoff is written but reported nowhere. */\n emit?: ProgressEmitter;\n /** Set for one task of an orchestrated run: `publish_handoff` then reminds it to report with complete_task. */\n taskAgent?: boolean;\n}\n\nexport function createWizardPiTools(ctx: PiToolsContext): ToolDefinition[] {\n const {\n workingDirectory,\n skillsBaseUrl,\n askBridge,\n onAskPendingChange,\n triageProvider,\n } = ctx;\n const detectPackageManager =\n ctx.detectPackageManager ?? detectNodePackageManagers;\n const askMaxQuestions = ctx.maxQuestions ?? DEFAULT_ASK_MAX_QUESTIONS;\n // Per-run wizard_ask accounting (total cap + one-time per-subject adjacency\n // nudge). Same shared implementation the MCP server drives, so the two\n // facades cannot diverge on the cap, the nudge or the refund.\n const askAccounting = createAskAccounting(askMaxQuestions);\n // Session-scoped secret vault, same contract as the MCP server: wizard_ask\n // mints `{secretRef}` for sensitive answers, set_env_values resolves them.\n const secretVault = createSecretVault();\n\n // Fetch the skill menu at most once per run — the agent calls load_skill_menu\n // 2-3× otherwise, each a fresh HTTP round-trip (profiled slowness).\n let menuPromise: ReturnType<typeof fetchSkillMenu> | undefined;\n const getSkillMenu = () => (menuPromise ??= fetchSkillMenu(skillsBaseUrl));\n\n const loadSkillMenu = defineTool({\n name: 'load_skill_menu',\n label: 'Load skill menu',\n description:\n 'Load available PostHog skills for a category. Returns skill IDs and names. Call this first, then install_skill with the chosen ID.',\n promptSnippet:\n 'load_skill_menu(category) — list installable PostHog skills',\n parameters: Type.Object({\n category: Type.String({\n description: 'Skill category, e.g. \"integration\"',\n }),\n }),\n async execute(_id, args) {\n const menu = await getSkillMenu();\n if (!menu) return text('Error: could not load the skill menu.');\n const skills = menu.categories[args.category] ?? [];\n if (skills.length === 0) {\n return text(`No skills found for category \"${args.category}\".`);\n }\n logToFile(`[pi] load_skill_menu: ${skills.length} skills`);\n return text(skills.map((s) => `- ${s.id}: ${s.name}`).join('\\n'));\n },\n });\n\n const installSkill = defineTool({\n name: 'install_skill',\n label: 'Install skill',\n description:\n 'Download and install a PostHog skill by ID into .claude/skills/<skillId>/. Call load_skill_menu first. Then read the installed SKILL.md and follow it.',\n promptSnippet:\n 'install_skill(skillId) — install a skill, then read its SKILL.md',\n parameters: Type.Object({\n skillId: Type.String({ description: 'Skill ID from load_skill_menu' }),\n }),\n async execute(_id, args) {\n const result = await installSkillById(\n args.skillId,\n workingDirectory,\n skillsBaseUrl,\n { triage: triageProvider },\n );\n if (result.kind !== 'ok') {\n logToFile(`[pi] install_skill ${args.skillId}: ${result.kind}`);\n return text(\n `Error installing skill \"${args.skillId}\": ${result.kind}. Use load_skill_menu to see valid IDs.`,\n );\n }\n logToFile(`[pi] install_skill ${args.skillId} -> ${result.path}`);\n return text(\n `Installed \"${args.skillId}\" at ${result.path}. Read ${result.path}/SKILL.md and follow it.`,\n );\n },\n });\n\n const checkEnvKeys = defineTool({\n name: 'check_env_keys',\n label: 'Check env keys',\n description: CHECK_ENV_KEYS_DESCRIPTION,\n promptSnippet:\n 'check_env_keys(keys) — see which .env keys exist, and in which file',\n parameters: Type.Object({\n filePath: Type.Optional(\n Type.String({\n description: CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION,\n }),\n ),\n keys: Type.Array(Type.String(), {\n description: 'Environment variable key names to check',\n }),\n }),\n // `async` with nothing to await, on purpose: it is what turns a thrown\n // error into a rejection. `checkEnvKeys` throws on a filePath that escapes\n // the working directory, and pi wraps `execute` in a plain (non-async)\n // arrow, so without this the throw leaves the tool synchronously instead\n // of arriving as a failed tool call. The scan replaced an awaited read,\n // which is the only reason there is nothing left to await.\n // eslint-disable-next-line @typescript-eslint/require-await\n async execute(_id, args) {\n const results = checkEnvKeysCore(\n workingDirectory,\n args.keys,\n args.filePath,\n );\n return text(JSON.stringify(results, null, 2));\n },\n });\n\n const setEnvValues = defineTool({\n name: 'set_env_values',\n label: 'Set env values',\n description:\n 'Create or update environment variable keys in a .env file (creates the file if missing). Each value is either a literal string or a secret reference `{ \"secretRef\": \"secret:...\" }` returned by wizard_ask — refs are resolved locally, so the actual value is written to the file but never returned to the agent.',\n promptSnippet:\n 'set_env_values(filePath, values) — write .env keys (never hardcode secrets in source)',\n parameters: Type.Object({\n filePath: Type.String({\n description: ENV_FILE_PATH_DESCRIPTION,\n }),\n values: Type.Record(\n Type.String(),\n Type.Union([Type.String(), Type.Object({ secretRef: Type.String() })]),\n {\n description:\n 'Key → (literal string OR { secretRef } pointing to a vaulted secret)',\n },\n ),\n }),\n async execute(_id, args) {\n const keyRefusal = legacyKeyNameRefusal(\n workingDirectory,\n Object.keys(args.values),\n );\n if (keyRefusal) return text(keyRefusal);\n // Resolve secret refs host-side; the value never reaches the agent.\n const resolution = resolveEnvSecretRefs(args.values, secretVault);\n if (!resolution.ok) {\n return text(\n `Error: secret reference \"${resolution.secretRef}\" for key \"${resolution.key}\" is not known to the vault. The ref may have expired, been minted in a different run, or been mistyped.`,\n );\n }\n const resolved = resolveEnvPath(workingDirectory, args.filePath);\n const templateRefusal = templateEnvWriteRefusal(resolved);\n if (templateRefusal) {\n logToFile(`[pi] set_env_values: refused template target ${resolved}`);\n analytics.wizardCapture('set_env_values template target refused', {\n file_name: path.basename(resolved),\n });\n return text(templateRefusal);\n }\n const existing = fs.existsSync(resolved)\n ? await fs.promises.readFile(resolved, 'utf8')\n : '';\n const merged = mergeEnvValues(existing, resolution.values);\n const dir = path.dirname(resolved);\n if (!fs.existsSync(dir))\n await fs.promises.mkdir(dir, { recursive: true });\n await fs.promises.writeFile(resolved, merged, 'utf8');\n // Same post-write pass as the MCP facade: a credential file the\n // project does not ignore yet gets committed by the next `git add`.\n ensureGitignoreCoverage(workingDirectory, path.basename(resolved));\n logToFile(\n `[pi] set_env_values: ${resolved} keys=${Object.keys(args.values).join(\n ',',\n )}`,\n );\n return text(\n `Wrote ${Object.keys(args.values).length} key(s) to ${args.filePath}.`,\n );\n },\n });\n\n // ── Audit ledger ────────────────────────────────────────────────────\n // Native mirror of the three MCP audit tools; pi mounts no MCP server, so\n // without these an audit cannot move a check off pending. Descriptions and\n // write semantics come from the shared helpers, so the facades cannot drift.\n const auditLedgerPath = path.join(workingDirectory, AUDIT_CHECKS_FILE);\n const auditMutex = makeMutex();\n const auditStatus = Type.Union(\n AUDIT_STATUSES.map((s) => Type.Literal(s)),\n { description: 'Check outcome' },\n );\n const auditCheck = Type.Object({\n id: Type.String({ description: 'Stable kebab-case check id' }),\n area: Type.String({ description: 'Short group name, e.g. Installation' }),\n label: Type.String({ description: 'Short human name for the check' }),\n status: auditStatus,\n file: Type.Optional(Type.String({ description: 'Optional path:line' })),\n details: Type.Optional(\n Type.String({ description: 'Optional one-line explanation' }),\n ),\n });\n\n const auditSeedChecks = defineTool({\n name: 'audit_seed_checks',\n label: 'Seed audit checks',\n description: AUDIT_SEED_CHECKS_DESCRIPTION,\n promptSnippet:\n 'audit_seed_checks(checks) — write the full pending checklist to the audit ledger',\n parameters: Type.Object({\n checks: Type.Array(auditCheck, {\n description: AUDIT_SEED_CHECKS_PARAM_DESCRIPTION,\n }),\n }),\n execute: (_id, args) =>\n auditMutex(() => {\n const result = seedAuditChecks(\n auditLedgerPath,\n args.checks as AuditCheck[],\n );\n logToFile(`[pi] audit_seed_checks: ${result.message}`);\n return text(result.message);\n }),\n });\n\n const auditAddChecks = defineTool({\n name: 'audit_add_checks',\n label: 'Add audit checks',\n description: AUDIT_ADD_CHECKS_DESCRIPTION,\n promptSnippet:\n 'audit_add_checks(checks) — append runtime-discovered checks to the ledger',\n parameters: Type.Object({\n checks: Type.Array(auditCheck, {\n minItems: 1,\n description: AUDIT_ADD_CHECKS_PARAM_DESCRIPTION,\n }),\n }),\n execute: (_id, args) =>\n auditMutex(() => {\n const result = addAuditChecks(\n auditLedgerPath,\n args.checks as AuditCheck[],\n );\n logToFile(`[pi] audit_add_checks: ${result.message}`);\n return text(result.message);\n }),\n });\n\n const auditResolveChecks = defineTool({\n name: 'audit_resolve_checks',\n label: 'Resolve audit checks',\n description: AUDIT_RESOLVE_CHECKS_DESCRIPTION,\n promptSnippet:\n 'audit_resolve_checks(updates) — patch each check by id as you finish it',\n parameters: Type.Object({\n updates: Type.Array(\n Type.Object({\n id: Type.String({ description: 'Existing check id' }),\n status: auditStatus,\n file: Type.Optional(\n Type.String({ description: 'Optional path:line' }),\n ),\n details: Type.Optional(\n Type.String({ description: 'Optional one-line explanation' }),\n ),\n }),\n { minItems: 1, description: AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION },\n ),\n }),\n execute: (_id, args) =>\n auditMutex(() => {\n const result = resolveAuditChecks(\n auditLedgerPath,\n args.updates as Array<{\n id: string;\n status: AuditStatus;\n file?: string;\n details?: string;\n }>,\n );\n logToFile(`[pi] audit_resolve_checks: ${result.message}`);\n return text(result.message);\n }),\n });\n\n const detectPm = defineTool({\n name: 'detect_package_manager',\n label: 'Detect package manager',\n description:\n \"Detect the project's package manager(s). Returns the name and the install command for each. Call this before installing a dependency, then RUN the returned install command (with the posthog package) via bash — the SDK package must end up in the project manifest, or the app will not build.\",\n promptSnippet:\n 'detect_package_manager() — find the PM + install command, then run it via bash to add the SDK',\n parameters: Type.Object({}),\n async execute() {\n const result = await detectPackageManager(workingDirectory);\n logToFile(\n `[pi] detect_package_manager: ${result.detected.length} detected`,\n );\n return text(JSON.stringify(result, null, 2));\n },\n });\n\n // Native mirror of the MCP `wizard_ask` tool: same name, schema, and\n // askBridge, so the shared prompt is unchanged.\n const wizardAsk = defineTool({\n name: 'wizard_ask',\n label: 'Ask the user',\n description: WIZARD_ASK_TOOL_DESCRIPTION,\n promptSnippet:\n 'wizard_ask(questions, subject) — ask the user structured questions and wait for answers; tag each call with the subject it collects for',\n parameters: Type.Object({\n questions: Type.Array(\n Type.Object({\n id: Type.String({\n description: 'Stable key for the answer in the response map',\n }),\n prompt: Type.String({\n description: 'Question text shown to the user',\n }),\n kind: Type.Optional(\n Type.Union(\n [\n Type.Literal('single'),\n Type.Literal('multi'),\n Type.Literal('text'),\n ],\n { description: WIZARD_ASK_KIND_DESCRIPTION },\n ),\n ),\n options: Type.Optional(\n Type.Array(\n Type.Object({\n label: Type.String(),\n value: Type.String(),\n description: Type.Optional(Type.String()),\n }),\n {\n description:\n 'Required for kind=single|multi; ignored for kind=text',\n },\n ),\n ),\n required: Type.Optional(\n Type.Boolean({ description: 'Defaults to true' }),\n ),\n sensitive: Type.Optional(\n Type.Boolean({\n description: WIZARD_ASK_SENSITIVE_DESCRIPTION,\n }),\n ),\n }),\n { minItems: 1, maxItems: ASK_MAX_QUESTIONS_PER_CALL },\n ),\n subject: Type.Optional(\n Type.String({ description: WIZARD_ASK_SUBJECT_DESCRIPTION }),\n ),\n }),\n async execute(_id, args) {\n if (!askBridge) {\n return text(\n 'Error: wizard_ask is not available in this environment (CI / non-interactive). Proceed with sensible defaults or emit [ABORT] requirements-incomplete.',\n );\n }\n\n const cap = askAccounting.evaluate(args.subject);\n if (cap.kind === 'capped') {\n const { callCount } = askAccounting.snapshot();\n logToFile(\n `[pi] wizard_ask capped: reason=${cap.reason} count=${callCount} subject=${cap.subject} run=${cap.subjectRunLength}`,\n );\n analytics.wizardCapture('wizard_ask capped', {\n reason: cap.reason,\n call_count: callCount,\n max_questions: askMaxQuestions,\n subject: cap.subject,\n subject_run_length: cap.subjectRunLength,\n });\n return text(cap.message);\n }\n\n // A question with no kind takes the one its options imply, so the\n // overlay always has an input to render. See resolveAskQuestionKinds.\n const questions = resolveAskQuestionKinds(args.questions);\n\n // The schema can't enforce per-kind requirements or unique ids.\n const ids = new Set<string>();\n for (const q of questions) {\n if ((q.kind === 'single' || q.kind === 'multi') && !q.options?.length) {\n return text(\n `Error: question \"${q.id}\" has kind=\"${q.kind}\" but no options. Provide at least one { label, value }, or use kind=\"text\".`,\n );\n }\n if (q.sensitive && q.kind !== 'text') {\n return text(\n `Error: question \"${q.id}\" sets sensitive=true but kind=\"${q.kind}\". Only kind=\"text\" answers can be sensitive.`,\n );\n }\n if (ids.has(q.id)) {\n return text(\n `Error: duplicate question id \"${q.id}\". Each question needs a unique id.`,\n );\n }\n ids.add(q.id);\n }\n\n // Optimistically take the slot; refund it on a cancellation or a bridge\n // error so a declined/failed ask doesn't burn the budget for later ones.\n askAccounting.record(args.subject);\n // Block Write/Edit for as long as the overlay is open, so the agent can't\n // mutate files while it's waiting on the user's answer.\n onAskPendingChange?.(true);\n try {\n const { answers, timedOut } = await askBridge.request({\n questions,\n subject: normaliseAskSubject(args.subject),\n });\n if (isFullyCancelled(answers)) askAccounting.refund(args.subject);\n // Sensitive answers go to the vault; the agent sees an opaque ref\n // (same contract as the MCP wizard_ask).\n const sanitised = vaultSensitiveAnswers(\n questions,\n answers,\n secretVault,\n );\n // State an uncollected field as an outcome rather than leaving the\n // agent to recognise a sentinel answer value (same as the MCP facade).\n const cancelled = describeAskCancellation(sanitised, timedOut);\n logToFile(\n `[pi] wizard_ask: resolved ${\n Object.keys(answers).length\n } answer(s) for ${args.questions.length} question(s)${\n cancelled ? `, cancelled: ${cancelled.reason}` : ''\n }`,\n );\n return text(\n JSON.stringify(\n { answers: sanitised, ...(cancelled ? { cancelled } : {}) },\n null,\n 2,\n ),\n );\n } catch (err) {\n askAccounting.refund(args.subject);\n const message = err instanceof Error ? err.message : String(err);\n logToFile(`[pi] wizard_ask: error: ${message}`);\n return text(`Error: wizard_ask failed: ${message}`);\n } finally {\n onAskPendingChange?.(false);\n }\n },\n });\n\n // Native mirror of the MCP `publish_handoff` tool (shared description, so no drift).\n const publishHandoffTool = defineTool({\n name: PUBLISH_HANDOFF_TOOL_NAME,\n label: 'Publish handoff',\n description: PUBLISH_HANDOFF_DESCRIPTION,\n promptSnippet:\n 'publish_handoff(content) — publish the full report markdown to the wizard session',\n parameters: Type.Object({\n content: Type.String({\n description: PUBLISH_HANDOFF_CONTENT_DESCRIPTION,\n }),\n }),\n execute(_id, args) {\n const result = publishHandoff(args.content, ctx.emit, {\n taskAgent: ctx.taskAgent,\n });\n logToFile(`[pi] publish_handoff: ${result.message}`);\n return Promise.resolve(text(result.message));\n },\n });\n\n const tools = [\n loadSkillMenu,\n installSkill,\n checkEnvKeys,\n setEnvValues,\n detectPm,\n // Parallel: the mutex serializes the writes, so a subagent fan-out is safe.\n withMode(auditSeedChecks, 'parallel'),\n withMode(auditAddChecks, 'parallel'),\n withMode(auditResolveChecks, 'parallel'),\n // Sequential: it publishes the run's handoff.\n withMode(publishHandoffTool, 'sequential'),\n ];\n // Register wizard_ask only when the program allows it. posthog-integration\n // disallows it (runs without structured user input); self-driving keeps it.\n // Sequential: the ask bridge holds a single in-flight question slot, so a\n // batched turn must never dispatch two asks (or an ask + a write) at once.\n const askDisallowed =\n ctx.disallowedTools?.includes(WIZARD_TOOL_NAMES.wizardAsk) ?? false;\n if (!askDisallowed) tools.push(withMode(wizardAsk, 'sequential'));\n return tools;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { c as setDebugSink } from "./debug-Ch4BDOtD.js";
2
- import { t as LoggingUI } from "./logging-ui-_TwoMNbG.js";
1
+ import { c as setDebugSink } from "./debug-kAHwWGg7.js";
2
+ import { t as LoggingUI } from "./logging-ui-Dza4D0MK.js";
3
3
  //#region src/ui/index.ts
4
4
  let currentUI = new LoggingUI();
5
5
  setDebugSink((line) => currentUI.log.info(line));
@@ -12,4 +12,4 @@ function setUI(ui) {
12
12
  //#endregion
13
13
  export { setUI as n, getUI as t };
14
14
 
15
- //# sourceMappingURL=ui-BBVuTM1v.js.map
15
+ //# sourceMappingURL=ui-Q6-RvERF.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-BBVuTM1v.js","names":[],"sources":["../src/ui/index.ts"],"sourcesContent":["/**\n * UI singleton — provides getUI() and setUI() for the wizard.\n * Default: LoggingUI. Swap to InkUI at startup for TUI mode.\n */\n\nimport type { WizardUI } from './wizard-ui';\nimport { LoggingUI } from './logging-ui';\nimport { setDebugSink } from '@utils/debug';\n\nlet currentUI: WizardUI = new LoggingUI();\n\n// Shared code never looks the UI up; `debug()` reports through whichever UI\n// is current, installed here so the sink follows setUI().\nsetDebugSink((line) => currentUI.log.info(line));\n\nexport function getUI(): WizardUI {\n return currentUI;\n}\n\nexport function setUI(ui: WizardUI): void {\n currentUI = ui;\n}\n\nexport type { WizardUI, SpinnerHandle } from './wizard-ui';\n"],"mappings":";;;AASA,IAAI,YAAsB,IAAI,WAAW;AAIzC,cAAc,SAAS,UAAU,IAAI,KAAK,KAAK,CAAC;AAEhD,SAAgB,QAAkB;AAChC,QAAO;;AAGT,SAAgB,MAAM,IAAoB;AACxC,aAAY"}
1
+ {"version":3,"file":"ui-Q6-RvERF.js","names":[],"sources":["../src/ui/index.ts"],"sourcesContent":["/**\n * UI singleton — provides getUI() and setUI() for the wizard.\n * Default: LoggingUI. Swap to InkUI at startup for TUI mode.\n */\n\nimport type { WizardUI } from './wizard-ui';\nimport { LoggingUI } from './logging-ui';\nimport { setDebugSink } from '@utils/debug';\n\nlet currentUI: WizardUI = new LoggingUI();\n\n// Shared code never looks the UI up; `debug()` reports through whichever UI\n// is current, installed here so the sink follows setUI().\nsetDebugSink((line) => currentUI.log.info(line));\n\nexport function getUI(): WizardUI {\n return currentUI;\n}\n\nexport function setUI(ui: WizardUI): void {\n currentUI = ui;\n}\n\nexport type { WizardUI, SpinnerHandle } from './wizard-ui';\n"],"mappings":";;;AASA,IAAI,YAAsB,IAAI,WAAW;AAIzC,cAAc,SAAS,UAAU,IAAI,KAAK,KAAK,CAAC;AAEhD,SAAgB,QAAkB;AAChC,QAAO;;AAGT,SAAgB,MAAM,IAAoB;AACxC,aAAY"}
@@ -1,6 +1,6 @@
1
1
  //#region src/shared/version.ts
2
- const VERSION = "2.78.0";
2
+ const VERSION = "2.79.1";
3
3
  //#endregion
4
4
  export { VERSION as t };
5
5
 
6
- //# sourceMappingURL=version-aXxpgRKx.js.map
6
+ //# sourceMappingURL=version-CHhJjz_H.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-aXxpgRKx.js","names":[],"sources":["../src/shared/version.ts"],"sourcesContent":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.78.0';\n"],"mappings":";AACA,MAAa,UAAU"}
1
+ {"version":3,"file":"version-CHhJjz_H.js","names":[],"sources":["../src/shared/version.ts"],"sourcesContent":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.79.1';\n"],"mappings":";AACA,MAAa,UAAU"}
@@ -1,9 +1,10 @@
1
- import { l as WizardError, n as sanitizeErrorDetail, u as emitWizardError } from "./errors-CQ9kttJD.js";
2
- import { s as logToFile } from "./debug-Ch4BDOtD.js";
1
+ import { t as emitWizardError } from "./emit-BSetXzDV.js";
2
+ import { s as logToFile } from "./debug-kAHwWGg7.js";
3
3
  import "./wizard-session-2w4Ru-Wz.js";
4
- import { n as analytics } from "./analytics-CHCZ_qUR.js";
5
- import { t as LoggingUI } from "./logging-ui-_TwoMNbG.js";
6
- import { t as getUI } from "./ui-BBVuTM1v.js";
4
+ import { n as analytics } from "./analytics-DXK1gc12.js";
5
+ import { a as WizardError, n as sanitizeErrorDetail } from "./errors-C2domSkK.js";
6
+ import { t as LoggingUI } from "./logging-ui-Dza4D0MK.js";
7
+ import { t as getUI } from "./ui-Q6-RvERF.js";
7
8
  //#region src/shared/utils/wizard-abort.ts
8
9
  /**
9
10
  * Single exit point for the wizard. Use instead of process.exit() directly.
@@ -71,4 +72,4 @@ async function wizardAbort(options) {
71
72
  //#endregion
72
73
  export { wizardAbort as i, registerShutdown as n, runCleanups as r, registerCleanup as t };
73
74
 
74
- //# sourceMappingURL=wizard-abort-BBkiUxfS.js.map
75
+ //# sourceMappingURL=wizard-abort-BPdv07np.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wizard-abort-BBkiUxfS.js","names":[],"sources":["../src/shared/utils/wizard-abort.ts"],"sourcesContent":["/**\n * Single exit point for the wizard. Use instead of process.exit() directly.\n *\n * Sequence: cleanup -> error capture (optional) -> analytics shutdown -> outro -> process.exit\n *\n * WizardError (from `@lib/errors`) is a data carrier passed to wizardAbort() for analytics context, never thrown.\n * The legacy abort() in setup-utils.ts delegates here.\n */\nimport { analytics } from './analytics';\nimport { logToFile } from './debug';\nimport { getUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { OutroKind, type OutroData } from '@lib/wizard-session';\nimport type { ErrorCode } from '@shared/errors';\nimport {\n WizardError,\n emitWizardError,\n sanitizeErrorDetail,\n} from '@shared/errors';\n\n// Still importable from here; the class lives with the error codes.\nexport { WizardError };\n\ninterface WizardAbortOptions {\n message?: string;\n /** Structured error data. Renders via `outroError` instead of `outro`. */\n outroData?: OutroData;\n error?: Error | WizardError;\n exitCode?: number;\n code?: ErrorCode;\n detail?: Record<string, unknown>;\n /** Terminal analytics status. Defaults from whether `error` is set. */\n status?: 'error' | 'cancelled';\n}\n\nconst cleanupFns: Array<() => void> = [];\nconst shutdownFns = new Set<\n (outcome: 'failed' | 'cancelled') => Promise<void>\n>();\n\nexport function registerShutdown(\n fn: (outcome: 'failed' | 'cancelled') => Promise<void>,\n): () => void {\n shutdownFns.add(fn);\n return () => {\n shutdownFns.delete(fn);\n };\n}\n\nexport function registerCleanup(fn: () => void): void {\n cleanupFns.push(fn);\n}\n\nexport function clearCleanup(): void {\n cleanupFns.length = 0;\n shutdownFns.clear();\n}\n\n/** Runs all registered cleanup functions and drains the array. */\nexport function runCleanups(): void {\n const fns = cleanupFns.splice(0);\n for (const fn of fns) {\n try {\n fn();\n } catch {\n /* cleanup should not prevent exit */\n }\n }\n}\n\nfunction resolveErrorCode(\n options: WizardAbortOptions,\n error: Error | WizardError | undefined,\n): ErrorCode | undefined {\n if (options.code) return options.code;\n if (error instanceof WizardError) return error.code;\n return undefined;\n}\n\nexport async function wizardAbort(\n options?: WizardAbortOptions,\n): Promise<never> {\n const {\n message = 'Wizard setup cancelled.',\n outroData,\n error,\n exitCode = 1,\n } = options ?? {};\n\n const code = resolveErrorCode(options ?? {}, error);\n const detail = options?.detail;\n\n logToFile(\n `[wizard-abort] exitCode=${exitCode}, code=${\n code ?? 'none'\n }, message: ${message}`,\n );\n if (error) {\n logToFile('[wizard-abort] error:', error);\n }\n\n // 1. Run registered cleanup functions\n runCleanups();\n const status = options?.status ?? (error ? 'error' : 'cancelled');\n await Promise.allSettled(\n [...shutdownFns].map((fn) =>\n fn(status === 'cancelled' ? 'cancelled' : 'failed'),\n ),\n );\n\n // 2. Capture error in analytics. An 'error' ending with no Error object\n // is captured as its code and message.\n const captured =\n error ??\n (status === 'error'\n ? new WizardError(message, undefined, code)\n : undefined);\n if (captured) {\n analytics.captureException(captured, {\n ...((captured instanceof WizardError && captured.context) || {}),\n ...(code ? { error_code: code } : {}),\n });\n }\n\n // 3. Shutdown analytics\n await analytics.shutdown(status);\n\n // 4. Render the error outro. Synthesize OutroData from `message`\n // when the caller didn't provide structured data.\n const ui = getUI();\n const resolvedOutroData: OutroData = outroData ?? {\n kind: OutroKind.Error,\n message,\n };\n if (code && resolvedOutroData.kind === OutroKind.Error) {\n resolvedOutroData.errorCode ??= code;\n if (detail) resolvedOutroData.errorDetail ??= detail;\n }\n ui.outroError(resolvedOutroData);\n\n // 5. Wait for the user to dismiss the outro screen. In a TUI this gives\n // them time to read the error; in non-TUI environments it resolves\n // immediately.\n await ui.waitForOutroDismissed();\n\n // 6. Emit the machine-readable error line for non-interactive hosts\n // (LoggingUI and its HeadlessUI subclass); the TUI never sees it.\n if (code && ui instanceof LoggingUI) {\n emitWizardError({\n code,\n message: resolvedOutroData.message ?? message,\n detail: sanitizeErrorDetail(resolvedOutroData.errorDetail ?? detail),\n });\n }\n\n // 7. Exit (fires 'exit' event so TUI cleanup runs)\n return process.exit(exitCode);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmCA,MAAM,aAAgC,EAAE;AACxC,MAAM,8BAAc,IAAI,KAErB;AAEH,SAAgB,iBACd,IACY;AACZ,aAAY,IAAI,GAAG;AACnB,cAAa;AACX,cAAY,OAAO,GAAG;;;AAI1B,SAAgB,gBAAgB,IAAsB;AACpD,YAAW,KAAK,GAAG;;;AASrB,SAAgB,cAAoB;CAClC,MAAM,MAAM,WAAW,OAAO,EAAE;AAChC,MAAK,MAAM,MAAM,IACf,KAAI;AACF,MAAI;SACE;;AAMZ,SAAS,iBACP,SACA,OACuB;AACvB,KAAI,QAAQ,KAAM,QAAO,QAAQ;AACjC,KAAI,iBAAiB,YAAa,QAAO,MAAM;;AAIjD,eAAsB,YACpB,SACgB;CAChB,MAAM,EACJ,UAAU,2BACV,WACA,OACA,WAAW,MACT,WAAW,EAAE;CAEjB,MAAM,OAAO,iBAAiB,WAAW,EAAE,EAAE,MAAM;CACnD,MAAM,SAAS,SAAS;AAExB,WACE,2BAA2B,SAAS,SAClC,QAAQ,OACT,aAAa,UACf;AACD,KAAI,MACF,WAAU,yBAAyB,MAAM;AAI3C,cAAa;CACb,MAAM,SAAS,SAAS,WAAW,QAAQ,UAAU;AACrD,OAAM,QAAQ,WACZ,CAAC,GAAG,YAAY,CAAC,KAAK,OACpB,GAAG,WAAW,cAAc,cAAc,SAAS,CACpD,CACF;CAID,MAAM,WACJ,UACC,WAAW,UACR,IAAI,YAAY,SAAS,KAAA,GAAW,KAAK,GACzC,KAAA;AACN,KAAI,SACF,WAAU,iBAAiB,UAAU;EACnC,GAAK,oBAAoB,eAAe,SAAS,WAAY,EAAE;EAC/D,GAAI,OAAO,EAAE,YAAY,MAAM,GAAG,EAAE;EACrC,CAAC;AAIJ,OAAM,UAAU,SAAS,OAAO;CAIhC,MAAM,KAAK,OAAO;CAClB,MAAM,oBAA+B,aAAa;EAChD,MAAA;EACA;EACD;AACD,KAAI,QAAQ,kBAAkB,SAAA,SAA0B;AACtD,oBAAkB,cAAc;AAChC,MAAI,OAAQ,mBAAkB,gBAAgB;;AAEhD,IAAG,WAAW,kBAAkB;AAKhC,OAAM,GAAG,uBAAuB;AAIhC,KAAI,QAAQ,cAAc,UACxB,iBAAgB;EACd;EACA,SAAS,kBAAkB,WAAW;EACtC,QAAQ,oBAAoB,kBAAkB,eAAe,OAAO;EACrE,CAAC;AAIJ,QAAO,QAAQ,KAAK,SAAS"}
1
+ {"version":3,"file":"wizard-abort-BPdv07np.js","names":[],"sources":["../src/shared/utils/wizard-abort.ts"],"sourcesContent":["/**\n * Single exit point for the wizard. Use instead of process.exit() directly.\n *\n * Sequence: cleanup -> error capture (optional) -> analytics shutdown -> outro -> process.exit\n *\n * WizardError (from `@lib/errors`) is a data carrier passed to wizardAbort() for analytics context, never thrown.\n * The legacy abort() in setup-utils.ts delegates here.\n */\nimport { analytics } from './analytics';\nimport { logToFile } from './debug';\nimport { getUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { OutroKind, type OutroData } from '@lib/wizard-session';\nimport type { ErrorCode } from '@shared/errors';\nimport {\n WizardError,\n emitWizardError,\n sanitizeErrorDetail,\n} from '@shared/errors';\n\n// Still importable from here; the class lives with the error codes.\nexport { WizardError };\n\ninterface WizardAbortOptions {\n message?: string;\n /** Structured error data. Renders via `outroError` instead of `outro`. */\n outroData?: OutroData;\n error?: Error | WizardError;\n exitCode?: number;\n code?: ErrorCode;\n detail?: Record<string, unknown>;\n /** Terminal analytics status. Defaults from whether `error` is set. */\n status?: 'error' | 'cancelled';\n}\n\nconst cleanupFns: Array<() => void> = [];\nconst shutdownFns = new Set<\n (outcome: 'failed' | 'cancelled') => Promise<void>\n>();\n\nexport function registerShutdown(\n fn: (outcome: 'failed' | 'cancelled') => Promise<void>,\n): () => void {\n shutdownFns.add(fn);\n return () => {\n shutdownFns.delete(fn);\n };\n}\n\nexport function registerCleanup(fn: () => void): void {\n cleanupFns.push(fn);\n}\n\nexport function clearCleanup(): void {\n cleanupFns.length = 0;\n shutdownFns.clear();\n}\n\n/** Runs all registered cleanup functions and drains the array. */\nexport function runCleanups(): void {\n const fns = cleanupFns.splice(0);\n for (const fn of fns) {\n try {\n fn();\n } catch {\n /* cleanup should not prevent exit */\n }\n }\n}\n\nfunction resolveErrorCode(\n options: WizardAbortOptions,\n error: Error | WizardError | undefined,\n): ErrorCode | undefined {\n if (options.code) return options.code;\n if (error instanceof WizardError) return error.code;\n return undefined;\n}\n\nexport async function wizardAbort(\n options?: WizardAbortOptions,\n): Promise<never> {\n const {\n message = 'Wizard setup cancelled.',\n outroData,\n error,\n exitCode = 1,\n } = options ?? {};\n\n const code = resolveErrorCode(options ?? {}, error);\n const detail = options?.detail;\n\n logToFile(\n `[wizard-abort] exitCode=${exitCode}, code=${\n code ?? 'none'\n }, message: ${message}`,\n );\n if (error) {\n logToFile('[wizard-abort] error:', error);\n }\n\n // 1. Run registered cleanup functions\n runCleanups();\n const status = options?.status ?? (error ? 'error' : 'cancelled');\n await Promise.allSettled(\n [...shutdownFns].map((fn) =>\n fn(status === 'cancelled' ? 'cancelled' : 'failed'),\n ),\n );\n\n // 2. Capture error in analytics. An 'error' ending with no Error object\n // is captured as its code and message.\n const captured =\n error ??\n (status === 'error'\n ? new WizardError(message, undefined, code)\n : undefined);\n if (captured) {\n analytics.captureException(captured, {\n ...((captured instanceof WizardError && captured.context) || {}),\n ...(code ? { error_code: code } : {}),\n });\n }\n\n // 3. Shutdown analytics\n await analytics.shutdown(status);\n\n // 4. Render the error outro. Synthesize OutroData from `message`\n // when the caller didn't provide structured data.\n const ui = getUI();\n const resolvedOutroData: OutroData = outroData ?? {\n kind: OutroKind.Error,\n message,\n };\n if (code && resolvedOutroData.kind === OutroKind.Error) {\n resolvedOutroData.errorCode ??= code;\n if (detail) resolvedOutroData.errorDetail ??= detail;\n }\n ui.outroError(resolvedOutroData);\n\n // 5. Wait for the user to dismiss the outro screen. In a TUI this gives\n // them time to read the error; in non-TUI environments it resolves\n // immediately.\n await ui.waitForOutroDismissed();\n\n // 6. Emit the machine-readable error line for non-interactive hosts\n // (LoggingUI and its HeadlessUI subclass); the TUI never sees it.\n if (code && ui instanceof LoggingUI) {\n emitWizardError({\n code,\n message: resolvedOutroData.message ?? message,\n detail: sanitizeErrorDetail(resolvedOutroData.errorDetail ?? detail),\n });\n }\n\n // 7. Exit (fires 'exit' event so TUI cleanup runs)\n return process.exit(exitCode);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmCA,MAAM,aAAgC,EAAE;AACxC,MAAM,8BAAc,IAAI,KAErB;AAEH,SAAgB,iBACd,IACY;AACZ,aAAY,IAAI,GAAG;AACnB,cAAa;AACX,cAAY,OAAO,GAAG;;;AAI1B,SAAgB,gBAAgB,IAAsB;AACpD,YAAW,KAAK,GAAG;;;AASrB,SAAgB,cAAoB;CAClC,MAAM,MAAM,WAAW,OAAO,EAAE;AAChC,MAAK,MAAM,MAAM,IACf,KAAI;AACF,MAAI;SACE;;AAMZ,SAAS,iBACP,SACA,OACuB;AACvB,KAAI,QAAQ,KAAM,QAAO,QAAQ;AACjC,KAAI,iBAAiB,YAAa,QAAO,MAAM;;AAIjD,eAAsB,YACpB,SACgB;CAChB,MAAM,EACJ,UAAU,2BACV,WACA,OACA,WAAW,MACT,WAAW,EAAE;CAEjB,MAAM,OAAO,iBAAiB,WAAW,EAAE,EAAE,MAAM;CACnD,MAAM,SAAS,SAAS;AAExB,WACE,2BAA2B,SAAS,SAClC,QAAQ,OACT,aAAa,UACf;AACD,KAAI,MACF,WAAU,yBAAyB,MAAM;AAI3C,cAAa;CACb,MAAM,SAAS,SAAS,WAAW,QAAQ,UAAU;AACrD,OAAM,QAAQ,WACZ,CAAC,GAAG,YAAY,CAAC,KAAK,OACpB,GAAG,WAAW,cAAc,cAAc,SAAS,CACpD,CACF;CAID,MAAM,WACJ,UACC,WAAW,UACR,IAAI,YAAY,SAAS,KAAA,GAAW,KAAK,GACzC,KAAA;AACN,KAAI,SACF,WAAU,iBAAiB,UAAU;EACnC,GAAK,oBAAoB,eAAe,SAAS,WAAY,EAAE;EAC/D,GAAI,OAAO,EAAE,YAAY,MAAM,GAAG,EAAE;EACrC,CAAC;AAIJ,OAAM,UAAU,SAAS,OAAO;CAIhC,MAAM,KAAK,OAAO;CAClB,MAAM,oBAA+B,aAAa;EAChD,MAAA;EACA;EACD;AACD,KAAI,QAAQ,kBAAkB,SAAA,SAA0B;AACtD,oBAAkB,cAAc;AAChC,MAAI,OAAQ,mBAAkB,gBAAgB;;AAEhD,IAAG,WAAW,kBAAkB;AAKhC,OAAM,GAAG,uBAAuB;AAIhC,KAAI,QAAQ,cAAc,UACxB,iBAAgB;EACd;EACA,SAAS,kBAAkB,WAAW;EACtC,QAAQ,oBAAoB,kBAAkB,eAAe,OAAO;EACrE,CAAC;AAIJ,QAAO,QAAQ,KAAK,SAAS"}
@@ -0,0 +1,3 @@
1
+ import { a as WizardError } from "./errors-C2domSkK.js";
2
+ import { i as wizardAbort } from "./wizard-abort-BPdv07np.js";
3
+ export { WizardError, wizardAbort };
@@ -1 +1 @@
1
- {"version":3,"file":"wizard-session-2w4Ru-Wz.js","names":[],"sources":["../src/agent/progress.ts","../src/lib/wizard-session.ts"],"sourcesContent":["/**\n * The agent's public progress and interaction contracts.\n *\n * `runAgent` reports through one optional callback and asks through one\n * optional set of capabilities. Neither reaches into a UI singleton, a store,\n * or a session: every payload is copied data, every question is awaited on an\n * injected answerer. The legacy adapter in `src/lib/programs/run-agent-legacy.ts`\n * maps these back onto `WizardUI` one call per event, so the terminal output of\n * every existing runner is unchanged.\n */\n\nimport type { SettingsConflict } from '@shared/claude-settings';\n\n// ── What the agent hands back and asks with ─────────────────────────\n\n/** Outcome kind for the outro screen */\nexport enum OutroKind {\n Success = 'success',\n Error = 'error',\n Cancel = 'cancel',\n}\n\nexport interface OutroData {\n kind: OutroKind;\n /** Main headline (green check for Success, red X for Error, etc.) */\n message?: string;\n /** Free-form body text shown under the headline. Use \\n for paragraph breaks. */\n body?: string;\n /** Success-only: bulleted list of \"what the agent did\" */\n changes?: string[];\n /**\n * Success-only: a prominent, labeled link to where the user should go\n * next (e.g. an inbox the program just configured). Rendered right under\n * the headline and shown verbatim — no UTM tagging — so the URL stays\n * clean and copy-pasteable. Set per-program in buildOutroData.\n */\n primaryLink?: { label: string; url: string };\n /**\n * Success-only: a short \"what to do next\" checklist with its own heading,\n * rendered as a bulleted list. Distinct from `changes`, which recaps what\n * the agent already did.\n */\n nextSteps?: { heading: string; items: string[] };\n docsUrl?: string;\n continueUrl?: string;\n /** Report file the agent wrote (e.g. \"posthog-setup-report.md\") */\n reportFile?: string;\n /** Stable machine-readable error code from the error catalog (@lib/errors). */\n errorCode?: import('@shared/errors').ErrorCode;\n /** Structured context for the error code; safe for telemetry payloads. */\n errorDetail?: Record<string, unknown>;\n /** PostHog dashboard URL the program created on the user's behalf. */\n dashboardUrl?: string;\n /** PostHog notebook URL the program uploaded the report to. */\n notebookUrl?: string;\n /**\n * Copy-paste prompt the operator hands to their coding agent to finish the\n * job (work the report's checklist). Printed to the terminal's main buffer on\n * exit (see getExitLine in start-tui.ts) — the TUI's alternate screen is wiped\n * on exit, so the scrollback line is where it survives and can be\n * triple-click-selected. Set per-program in buildOutroData.\n */\n handoffPrompt?: string;\n}\n\n/** A single question rendered by the WizardAsk overlay. */\nexport interface AskQuestion {\n /** Key for the response map */\n id: string;\n prompt: string;\n /** text = single-line free input; single/multi = picker */\n kind: 'single' | 'multi' | 'text';\n /** Required for `single` and `multi`. Ignored for `text`. */\n options?: { label: string; value: string; description?: string }[];\n /** Defaults to true */\n required?: boolean;\n /**\n * Only meaningful for kind='text'. When true, the wizard-tools `wizard_ask`\n * tool stores the user's answer in the session secret vault and returns\n * `{ secretRef }` to the agent instead of the plain string — so the value\n * never enters the LLM conversation. The TUI masks the input as it is typed\n * (see `shouldMaskAnswer`). See `secret-vault.ts`.\n */\n sensitive?: boolean;\n}\n\n/**\n * Copy for a modal shown before an optional step runs, so the user can decline\n * it. The program that owns the step supplies the words; the runner and the\n * screen only carry them.\n */\nexport interface TaskNotice {\n title: string;\n /** Paragraphs, in order. */\n body: string[];\n /** Optional highlighted list, e.g. what was detected. */\n items?: string[];\n docsLabel?: string;\n docsUrl?: string;\n confirmLabel: string;\n cancelLabel: string;\n prompt: string;\n}\n\n/** Map of question id → answer (string for single/text, string[] for multi). */\nexport type AskAnswers = Record<string, string | string[]>;\n\n/** A pending wizard_ask request held by the store. */\nexport interface PendingQuestion {\n id: string;\n questions: AskQuestion[];\n /**\n * UTC ISO 8601 timestamp of when the ask was created. Published on the\n * task stream as `pending_input.asked_at` so the web app can age the\n * prompt; stable across pushes for the lifetime of one ask.\n */\n askedAt?: string;\n /** Skill id of the caller. Set by the wizard from session.skillId. */\n source: string;\n /**\n * When true, the ask overlay renders standalone URLs in prompt text as\n * OSC 8 hyperlinks and copies a lone URL to the clipboard. Opt-in per\n * program (set from `AgentRunDefinition.richLinks` via the ask bridge); defaults\n * to false so existing flows render prompts exactly as before. See\n * `LinkText` / `link-helpers`.\n */\n richLinks?: boolean;\n}\n\n// ── What the agent reports ──────────────────────────────────────────\n\n/**\n * One assistant turn's token usage, for the hidden Ctrl+T token/cost HUD.\n * `model` is the model that produced *this* turn (e.g. the SDK's\n * `message.message.model`) — a subagent can run on a different model than\n * the main session, and some programs override to Haiku, so pricing must key\n * off the per-turn model rather than a single run-wide assumption. Omit only\n * when the caller genuinely has no model context (falls back to Sonnet\n * pricing — see `pricePerMtokForModel` in `@lib/agent/token-pricing`).\n */\nexport interface TokenUsageDelta {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n cacheCreation5m: number;\n cacheCreation1h: number;\n model?: string;\n}\n\n/** The run spinner as the agent drives it: `WizardUI.spinner()` returns one. */\nexport interface SpinnerHandle {\n start(message?: string): void;\n stop(message?: string): void;\n message(msg?: string): void;\n}\n\n/**\n * Context the agent attaches to a 401 so the host can pick the right copy.\n *\n * `hasSettingsConflict` is true when a Claude Code settings file (project,\n * project-local, the user's global config, or managed) actually overrides the\n * LLM Gateway auth. `conflicts` carries the exact files and keys so the screen\n * can name them. When there is no conflict, the 401 has a different cause (bad\n * PAT prefix, missing scope, expired key, region mismatch) and we should not\n * advise the user to log out of Claude Code.\n */\nexport interface AuthErrorDetail {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n /**\n * True when the agent SDK authenticated from a stored Claude login\n * (`apiKeySource: \"/login managed key\"`) instead of the wizard's gateway\n * token — conflicting Anthropic credentials. Takes priority in the screen.\n */\n usingManagedLogin?: boolean;\n /** Human-readable places a conflicting Anthropic credential may live. */\n credentialPlaces?: string[];\n /**\n * True when a pre-run refresh already failed on a dead grant. The login is\n * gone and re-running is the only fix, so this outranks every other branch —\n * none of the usual advice (key type, scopes, region) applies.\n */\n sessionExpired?: boolean;\n logFilePath: string;\n}\n\n/** One task as the host renders it. The same shape `WizardUI.syncTodos` takes. */\nexport interface TaskSnapshot {\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n}\n\nexport type ProgressLogLevel = 'info' | 'warn' | 'error' | 'success' | 'step';\n\n/**\n * Everything the agent reports while it runs. One event per former\n * `getUI()` call, in the same order, with the same payload, so a reducer that\n * maps each case back onto `WizardUI` reproduces today's output exactly.\n *\n * Payloads are copies. Never a store, a setter, a function or a live\n * collection. The callback returns nothing and the agent never branches on it.\n */\nexport type AgentProgress =\n /** The run's main work has started (`WizardUI.startRun`). */\n | { kind: 'lifecycle'; phase: 'started' }\n /** The run finished and the host may show its outro (`WizardUI.outro`). */\n | { kind: 'lifecycle'; phase: 'completed'; message: string }\n /** The run spinner (`WizardUI.spinner()`), one handle per run. */\n | {\n kind: 'spinner';\n action: 'start' | 'stop' | 'message';\n message?: string;\n }\n /** A log line (`WizardUI.log[level]`). */\n | { kind: 'log'; level: ProgressLogLevel; message: string }\n /** A `[STATUS]` line the agent printed (`WizardUI.pushStatus`). */\n | { kind: 'status'; message: string }\n /** The full task list, already sorted for display (`WizardUI.syncTodos`). */\n | { kind: 'tasks'; tasks: TaskSnapshot[] }\n /** The stage of work derived from the active tool (`WizardUI.setStage`). */\n | { kind: 'stage'; stage: string }\n /** A PostHog URL the agent created (`setDashboardUrl` / `setNotebookUrl`). */\n | { kind: 'url'; which: 'dashboard' | 'notebook'; url: string }\n /** One assistant turn's token usage (`WizardUI.addTokenUsage`). */\n | { kind: 'usage'; delta: TokenUsageDelta }\n /** The SDK's authoritative run cost (`WizardUI.setFinalTokenCostUsd`). */\n | { kind: 'finalCost'; usd: number }\n /** The gateway returned 401; a failure follows (`WizardUI.showAuthError`). */\n | { kind: 'authError'; detail: AuthErrorDetail }\n /** The handoff document the agent published (`WizardUI.setHandoffText`). */\n | { kind: 'handoff'; text: string }\n /** The run's final outro payload (`WizardUI.setOutroData`). */\n | { kind: 'completion'; outro: OutroData };\n\nexport type ProgressEmitter = (event: AgentProgress) => void;\n\n/**\n * The questions the agent may need a person (or a script) to answer. Every\n * capability is optional. With none supplied the agent installs no ask bridge,\n * so `wizard_ask` returns its existing \"not available\" error, and an optional\n * task notice is declined — the same path a `--ci` run takes today.\n * Each request's `signal` aborts when that request times out, the run's\n * signal aborts, or another task fails the run. On that abort the host\n * dismisses that request alone, and that dismissal must not throw: abort\n * listeners run where the agent cannot catch them, so Node would rethrow the\n * error as an uncaught exception.\n */\nexport interface AgentInteraction {\n /**\n * Open a question and resolve with the answers. The bridge that calls this\n * owns the timeout, the `__cancelled__` sentinel and the analytics.\n */\n ask?: (\n question: PendingQuestion,\n context: { signal: AbortSignal },\n ) => Promise<AskAnswers>;\n /** Offer an optional step and resolve with whether to keep it. */\n taskNotice?: (\n notice: TaskNotice,\n context: { signal: AbortSignal },\n ) => Promise<boolean>;\n}\n","/**\n * WizardSession — single source of truth for every decision the wizard needs.\n *\n * Populated in layers:\n * CLI args / env vars → populate fields directly\n * Auto-detection → framework, typescript, package manager\n * TUI screens → region, framework disambiguation, etc.\n * OAuth → credentials\n *\n * Business logic reads from the session. Never calls a prompt.\n */\n\nimport { POSTHOG_LOCAL_URL, resolveLocalDev } from '@shared/local-dev';\nimport type { Harness, Integration, Sequence } from '@shared/constants';\nimport type { FrameworkConfig } from './framework-config';\nimport type { WizardReadinessResult } from '@shared/health-checks/readiness';\nimport type { SettingsConflict } from '@shared/claude-settings';\nimport type { ApiUser, ApiProject, Credentials } from '@shared/api';\nimport type { CloudRegion } from '@utils/types';\nimport type {\n AskAnswers,\n AskQuestion,\n OutroData,\n PendingQuestion,\n TaskNotice,\n} from '@agent/types';\n// Leaf module on purpose: shared analytics imports this file, so the agent\n// entry would form a module cycle here.\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports -- B2: the session becomes a TUI projection\nimport { OutroKind } from '@agent/progress';\n\n// These shapes moved to their owners; re-exported so every session reader\n// keeps its import path. `Credentials` sits with the API types, and the\n// outro, question and task-notice shapes are the agent's contract.\nexport type { Credentials, CloudRegion };\nexport { OutroKind };\nexport type { AskAnswers, AskQuestion, OutroData, PendingQuestion, TaskNotice };\n\nfunction parseProjectIdArg(value: string | undefined): number | undefined {\n if (value === undefined || value === '') return undefined;\n const n = Number(value);\n return Number.isInteger(n) && n > 0 ? n : undefined;\n}\n\n/** Lifecycle phase of the main work (agent run, MCP install, etc.) */\nexport enum RunPhase {\n /** Still gathering input (intro, setup screens) */\n Idle = 'idle',\n /** Main work is in progress */\n Running = 'running',\n /** Main work finished successfully */\n Completed = 'completed',\n /** Main work finished with an error */\n Error = 'error',\n}\n\n/** Features discovered by the feature-discovery subagent */\nexport enum DiscoveredFeature {\n Stripe = 'stripe',\n LLM = 'llm',\n}\n\n/** Consent to report what local detection found (see `scanConsent` below). */\nexport enum ScanConsent {\n Undecided = 'undecided',\n Granted = 'granted',\n Declined = 'declined',\n}\n\n/** Outcome of the MCP server installation step */\nexport enum McpOutcome {\n NoClients = 'no_clients',\n Skipped = 'skipped',\n Installed = 'installed',\n Failed = 'failed',\n}\n\n/**\n * PostHog dashboard URL emitted by the agent during a program run.\n * Populated via the `[DASHBOARD_URL]` text marker in agent assistant messages\n * — see `handleSDKMessage` in `agent/agent-interface.ts`. Read by programs\n * (e.g. events-audit) inside `buildOutroData` to surface a dashboard link\n * the agent actually created.\n */\n\nexport interface WizardSession {\n // From CLI args\n debug: boolean;\n installDir: string;\n ci: boolean;\n signup: boolean;\n /**\n * Harness-only escape hatch: keep the `wizard_ask` bridge wired in a `ci`\n * session so an e2e run can answer the agent's questions.\n *\n * Only the e2e TUI host sets it, from the `E2E_ASK` env var. There is no CLI\n * flag, `bin.ts` never populates it, and nothing in a published build reads\n * the env var — so a normal `--ci` run is unchanged. See `shouldDisableAsk`.\n *\n * Guarding `E2E_ASK` is not enough on its own: the CI runner spreads the\n * whole `POSTHOG_WIZARD_*` bag into `buildSession`, which would let\n * `POSTHOG_WIZARD_e2e_ask=true` set this field. `readEnvironment` drops it —\n * see `NEVER_FROM_ENV`, and keep that list in step with this comment.\n */\n e2eAsk: boolean;\n /**\n * `--local-posthog` folds into `baseUrl`, and `--local-context-mill` is read\n * from `getLocalDev()` — neither belongs here. This one stays because\n * `mcp add|remove|tutorial --local` populate it from their own flag.\n */\n localMcp: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n /**\n * Explicit PostHog base URL (`--base-url`). When set, it pins every PostHog\n * origin — API host, cloud/app URL, OAuth server — and `region` is ignored.\n * The runtime equivalent of the dev-build localhost routing; lets the shipped\n * wizard target a local/self-hosted stack. Threaded into the URL helpers in\n * `@utils/urls`. Empty/unset → region-based resolution.\n */\n baseUrl?: string;\n benchmark: boolean;\n yaraReport: boolean;\n projectId?: number;\n noTelemetry: boolean;\n\n /**\n * `--capture-aio`: mirror every wizard LLM call as an `$ai_generation` event\n * into the authenticated project's AI Observability tab. Dev/test builds\n * only — the flag is undeclared in published builds so this stays `false`\n * there. See `src/agent/aio-capture.ts`.\n */\n captureAio: boolean;\n\n /** `--harness` override, read by `resolveHarness`. Wins over the runner flag. */\n harness?: Harness;\n /** `--sequence` override, read in `runProgram`. Wins over the orchestrator flag. */\n sequence?: Sequence;\n /** `--model` override (gateway id), read by `resolveHarness`. Wins over the binding's model. */\n model?: string;\n\n // From detection + screens\n setupConfirmed: boolean;\n /**\n * Gates reporting only; local detection runs either way. Reporting treats\n * 'undecided' as 'declined', so a path that reports before the user was\n * asked sends nothing rather than everything.\n */\n scanConsent: ScanConsent;\n /** Guards against reporting twice; consent resolves from two paths. */\n warehouseSourcesReported: boolean;\n /**\n * Guards `maybeStampAiSdkDetected` against running twice: it is called from\n * both run-wizard.ts's auth step and bootstrap.ts, since either can be the\n * first real `authenticate()` to complete depending on the program.\n */\n aiSdkStampReported: boolean;\n integration: Integration | null;\n frameworkContext: Record<string, unknown>;\n typescript: boolean;\n\n /** Human-readable label for the detected framework variant (e.g., \"Django with Wagtail CMS\") */\n detectedFrameworkLabel: string | null;\n\n /** PostHog found in the project's dependencies. A signal, not a verified install. */\n posthogSdkDetected: boolean;\n\n /** True once framework detection has run (whether it found something or not) */\n detectionComplete: boolean;\n\n /** Set when the detected framework version is too old for the wizard */\n unsupportedVersion: {\n current: string;\n minimum: string;\n docsUrl: string;\n } | null;\n\n // From OAuth\n credentials: Credentials | null;\n\n /**\n * `role_at_organization` from `/api/users/@me/`. Null when the upstream\n * value is missing (older accounts, fresh signups before onboarding).\n * Drives role-tailored MCP prompt suggestions on the McpSuggestedPromptsScreen.\n *\n * Mirrors `apiUser?.role_at_organization` — kept as a top-level convenience\n * because it has dedicated UI semantics (role-tailored kits) and pre-dates\n * the broader `apiUser` plumbing.\n */\n roleAtOrganization: string | null;\n\n /**\n * Full user payload from `/api/users/@me/` — identifiers, profile,\n * current team + organization, preferences, etc. Null until OAuth /\n * CI-key auth populates it. Schema lives in `src/shared/api.ts` and\n * passes through unknown upstream fields so downstream features can\n * read account context (plan, org name, email, etc.) without\n * re-fetching.\n */\n apiUser: ApiUser | null;\n\n /**\n * Project payload resolved at authentication, kept so a second agent run in\n * the same invocation (e.g. self-driving's integration phase) reuses the\n * first login wholesale instead of re-authenticating. The resolved region\n * lives on `credentials.host.region`.\n */\n apiProject: ApiProject | null;\n\n // Lifecycle\n runPhase: RunPhase;\n loginUrl: string | null;\n // Direct PostHog authorize URL, shown in the manual-paste modal for\n // headless/remote shells (the localhost loginUrl is unreachable there).\n authorizeUrl: string | null;\n\n // Feature discovery\n discoveredFeatures: DiscoveredFeature[];\n\n // ScreenId completion\n mcpComplete: boolean;\n mcpOutcome: McpOutcome | null;\n mcpInstalledClients: string[];\n /** Editor-owned login commands still to run (e.g. `claude mcp login posthog`), echoed at exit. */\n mcpLoginCommands: string[];\n mcpSuggestedPromptsDismissed: boolean;\n /** True once the user has acted on (opened or skipped) the Connect-Slack step. */\n slackStepDismissed: boolean;\n /**\n * Whether the project already has a Slack integration connected.\n * `null` until detected. Prefetched by the tutorial screen as soon as\n * credentials exist so the Connect-Slack step renders the right\n * variant immediately instead of flashing the nudge first.\n */\n slackConnected: boolean | null;\n skillsComplete: boolean;\n outroDismissed: boolean;\n\n /**\n * Self-driving only: whether to integrate PostHog as part of this run.\n * `null` until decided. When detection finds no PostHog SDK, the\n * integration-check screen sets this to `true` (Self-driving needs an SDK,\n * so we always integrate in that case) — and, on the same screen, asks\n * whether the user already has a PostHog account: \"yes\" leaves `signup`\n * false (OAuth login); \"no\" flips `signup` and collects `email`/`region`\n * so auth provisions a new account. The `--integrate` flag pre-sets this to\n * `true`, skipping the screen entirely and defaulting to the OAuth login.\n * When `true`, the self-driving prompt has the agent set up the SDK before\n * the Self-driving steps. Unused by other programs.\n */\n integrate: boolean | null;\n\n /**\n * Ids of composed run steps that have completed — e.g. self-driving's\n * `integrate-run`. Lets a run step's `isComplete` hold after it ran,\n * independent of the shared `runPhase`.\n */\n completedRuns: string[];\n\n /**\n * Self-driving only: whether the user confirmed the handoff screen shown\n * after the integration run (\"PostHog is installed — now set up Self-driving\").\n * Gates the Self-driving run so it doesn't start until acknowledged. Only\n * reached in the integrate path; the already-has-PostHog path skips it.\n */\n selfDrivingHandoffConfirmed: boolean;\n\n /**\n * Self-driving only: whether the project has the PostHog GitHub App\n * connected. `null` until the GitHub gate's first check resolves. Self-driving\n * cannot research issues or open fixes without it, so the gate holds the run\n * until this is `true`.\n */\n githubConnected: boolean | null;\n\n /**\n * Self-driving only: the user answered \"I can't connect right now\" on the\n * GitHub gate. Completes the gate step and hides the run step, so the flow\n * lands on the outro without starting the agent.\n */\n githubDeclined: boolean;\n\n // Runtime\n readinessResult: WizardReadinessResult | null;\n outageDismissed: boolean;\n settingsOverrideKeys: string[] | null;\n settingsConflicts: SettingsConflict[] | null;\n /** Mirrors `AuthErrorDetail` in `@ui/wizard-ui` — keep the two in step. */\n authErrorDetail: {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n usingManagedLogin?: boolean;\n credentialPlaces?: string[];\n sessionExpired?: boolean;\n logFilePath: string;\n } | null;\n portConflictProcess: {\n command: string;\n pid: string;\n port: number;\n user: string;\n } | null;\n /** Copy for the task-notice modal, set while it is open. */\n taskNotice: TaskNotice | null;\n outroData: OutroData | null;\n /** Skill saved for the user's own agent during the handoff. */\n spellbook: { path: string; skillsIncluded: boolean } | null;\n /**\n * How the user left the mint-failure screen: `continue` walks the\n * post-run steps (MCP, Slack, keep-skills), `exit` leaves. Null until then.\n */\n mintHandoff: 'continue' | 'exit' | null;\n dashboardUrl: string | null;\n notebookUrl: string | null;\n\n // Program metadata (set by runWizard in bin.ts)\n programLabel: string | null;\n skillId: string | null;\n\n // Resolved framework config (set after integration is known)\n frameworkConfig: FrameworkConfig | null;\n\n /** Active wizard_ask request, set by the bridge when the agent calls the tool. */\n pendingQuestion: PendingQuestion | null;\n}\n\n/**\n * Build a WizardSession from CLI args, pre-populating whatever is known.\n */\nexport function buildSession(args: {\n debug?: boolean;\n installDir?: string;\n ci?: boolean;\n signup?: boolean;\n /** Harness-only. Set by the e2e TUI host from `E2E_ASK`, never by a flag. */\n e2eAsk?: boolean;\n localDev?: boolean;\n localMcp?: boolean;\n localPosthog?: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n baseUrl?: string;\n integration?: Integration;\n benchmark?: boolean;\n yaraReport?: boolean;\n projectId?: string;\n noTelemetry?: boolean;\n harness?: Harness;\n sequence?: Sequence;\n model?: string;\n integrate?: boolean;\n captureAio?: boolean;\n}): WizardSession {\n const local = resolveLocalDev(args);\n return {\n debug: args.debug ?? false,\n installDir: args.installDir ?? process.cwd(),\n ci: args.ci ?? false,\n signup: args.signup ?? false,\n e2eAsk: args.e2eAsk ?? false,\n localMcp: local.localMcp,\n mcpFeatures: args.mcpFeatures,\n apiKey: args.apiKey,\n email: args.email,\n region: args.region,\n // `--local-posthog` is sugar over `--base-url`, which every downstream URL\n // helper already honours. An explicit `--base-url` is more specific, so it wins.\n baseUrl:\n args.baseUrl ?? (local.localPosthog ? POSTHOG_LOCAL_URL : undefined),\n benchmark: args.benchmark ?? false,\n yaraReport: args.yaraReport ?? false,\n projectId: parseProjectIdArg(args.projectId),\n noTelemetry: args.noTelemetry ?? false,\n captureAio: args.captureAio ?? false,\n harness: args.harness,\n sequence: args.sequence,\n model: args.model,\n\n setupConfirmed: false,\n // No screen can ask in a scripted CI run, so granting keeps CI's\n // telemetry as it was. --signup alone still provisions a brand-new\n // account headlessly, and that user has never seen the disclosure — a\n // headless `--ci --signup` run stays covered by the ci branch above.\n scanConsent: args.ci ? ScanConsent.Granted : ScanConsent.Undecided,\n warehouseSourcesReported: false,\n aiSdkStampReported: false,\n integration: args.integration ?? null,\n frameworkContext: {},\n typescript: false,\n detectedFrameworkLabel: null,\n posthogSdkDetected: false,\n detectionComplete: false,\n unsupportedVersion: null,\n\n runPhase: RunPhase.Idle,\n discoveredFeatures: [],\n mcpComplete: false,\n mcpOutcome: null,\n mcpInstalledClients: [],\n mcpLoginCommands: [],\n mcpSuggestedPromptsDismissed: false,\n slackStepDismissed: false,\n slackConnected: null,\n skillsComplete: false,\n outroDismissed: false,\n // `--integrate` forces integration (skip the question); otherwise the\n // integration-check screen resolves it from null.\n integrate: args.integrate === true ? true : null,\n completedRuns: [],\n selfDrivingHandoffConfirmed: false,\n githubConnected: null,\n githubDeclined: false,\n loginUrl: null,\n authorizeUrl: null,\n credentials: null,\n roleAtOrganization: null,\n apiUser: null,\n apiProject: null,\n readinessResult: null,\n outageDismissed: false,\n settingsOverrideKeys: null,\n settingsConflicts: null,\n authErrorDetail: null,\n portConflictProcess: null,\n taskNotice: null,\n outroData: null,\n spellbook: null,\n mintHandoff: null,\n dashboardUrl: null,\n notebookUrl: null,\n programLabel: null,\n skillId: null,\n frameworkConfig: null,\n pendingQuestion: null,\n };\n}\n\n/** One place to ask, so a new consent state does not need three edits. */\nexport function mayReportScanResults(session: WizardSession): boolean {\n return session.scanConsent === ScanConsent.Granted;\n}\n\n/** Lives here so analytics infrastructure never learns what consent means. */\nexport function reportableDiscoveredFeatures(\n session: WizardSession,\n): DiscoveredFeature[] | undefined {\n return mayReportScanResults(session) ? session.discoveredFeatures : undefined;\n}\n\n/** Also a scan result, so it travels under the same consent as the rest. */\nexport function reportablePosthogSdkDetected(\n session: WizardSession,\n): boolean | undefined {\n return mayReportScanResults(session) ? session.posthogSdkDetected : undefined;\n}\n"],"mappings":";;;AAgBA,IAAY,YAAL,yBAAA,WAAA;AACL,WAAA,aAAA;AACA,WAAA,WAAA;AACA,WAAA,YAAA;;KACD;;;;;;;;;;;;;;ACkBD,SAAS,kBAAkB,OAA+C;AACxE,KAAI,UAAU,KAAA,KAAa,UAAU,GAAI,QAAO,KAAA;CAChD,MAAM,IAAI,OAAO,MAAM;AACvB,QAAO,OAAO,UAAU,EAAE,IAAI,IAAI,IAAI,IAAI,KAAA;;;AAI5C,IAAY,WAAL,yBAAA,UAAA;;AAEL,UAAA,UAAA;;AAEA,UAAA,aAAA;;AAEA,UAAA,eAAA;;AAEA,UAAA,WAAA;;KACD;;;;AAqRD,SAAgB,aAAa,MAyBX;CAChB,MAAM,QAAQ,gBAAgB,KAAK;AACnC,QAAO;EACL,OAAO,KAAK,SAAS;EACrB,YAAY,KAAK,cAAc,QAAQ,KAAK;EAC5C,IAAI,KAAK,MAAM;EACf,QAAQ,KAAK,UAAU;EACvB,QAAQ,KAAK,UAAU;EACvB,UAAU,MAAM;EAChB,aAAa,KAAK;EAClB,QAAQ,KAAK;EACb,OAAO,KAAK;EACZ,QAAQ,KAAK;EAGb,SACE,KAAK,YAAY,MAAM,eAAA,0BAAmC,KAAA;EAC5D,WAAW,KAAK,aAAa;EAC7B,YAAY,KAAK,cAAc;EAC/B,WAAW,kBAAkB,KAAK,UAAU;EAC5C,aAAa,KAAK,eAAe;EACjC,YAAY,KAAK,cAAc;EAC/B,SAAS,KAAK;EACd,UAAU,KAAK;EACf,OAAO,KAAK;EAEZ,gBAAgB;EAKhB,aAAa,KAAK,KAAA,YAAA;EAClB,0BAA0B;EAC1B,oBAAoB;EACpB,aAAa,KAAK,eAAe;EACjC,kBAAkB,EAAE;EACpB,YAAY;EACZ,wBAAwB;EACxB,oBAAoB;EACpB,mBAAmB;EACnB,oBAAoB;EAEpB,UAAA;EACA,oBAAoB,EAAE;EACtB,aAAa;EACb,YAAY;EACZ,qBAAqB,EAAE;EACvB,kBAAkB,EAAE;EACpB,8BAA8B;EAC9B,oBAAoB;EACpB,gBAAgB;EAChB,gBAAgB;EAChB,gBAAgB;EAGhB,WAAW,KAAK,cAAc,OAAO,OAAO;EAC5C,eAAe,EAAE;EACjB,6BAA6B;EAC7B,iBAAiB;EACjB,gBAAgB;EAChB,UAAU;EACV,cAAc;EACd,aAAa;EACb,oBAAoB;EACpB,SAAS;EACT,YAAY;EACZ,iBAAiB;EACjB,iBAAiB;EACjB,sBAAsB;EACtB,mBAAmB;EACnB,iBAAiB;EACjB,qBAAqB;EACrB,YAAY;EACZ,WAAW;EACX,WAAW;EACX,aAAa;EACb,cAAc;EACd,aAAa;EACb,cAAc;EACd,SAAS;EACT,iBAAiB;EACjB,iBAAiB;EAClB;;;AAIH,SAAgB,qBAAqB,SAAiC;AACpE,QAAO,QAAQ,gBAAA;;;AAIjB,SAAgB,6BACd,SACiC;AACjC,QAAO,qBAAqB,QAAQ,GAAG,QAAQ,qBAAqB,KAAA;;;AAItE,SAAgB,6BACd,SACqB;AACrB,QAAO,qBAAqB,QAAQ,GAAG,QAAQ,qBAAqB,KAAA"}
1
+ {"version":3,"file":"wizard-session-2w4Ru-Wz.js","names":[],"sources":["../src/agent/progress.ts","../src/lib/wizard-session.ts"],"sourcesContent":["/**\n * The agent's public progress and interaction contracts.\n *\n * `runAgent` reports through one optional callback and asks through one\n * optional set of capabilities. Neither reaches into a UI singleton, a store,\n * or a session: every payload is copied data, every question is awaited on an\n * injected answerer. The legacy adapter in `src/programs/run-agent-legacy.ts`\n * maps these back onto `WizardUI` one call per event, so the terminal output of\n * every existing runner is unchanged.\n */\n\nimport type { SettingsConflict } from '@shared/claude-settings';\n\n// ── What the agent hands back and asks with ─────────────────────────\n\n/** Outcome kind for the outro screen */\nexport enum OutroKind {\n Success = 'success',\n Error = 'error',\n Cancel = 'cancel',\n}\n\nexport interface OutroData {\n kind: OutroKind;\n /** Main headline (green check for Success, red X for Error, etc.) */\n message?: string;\n /** Free-form body text shown under the headline. Use \\n for paragraph breaks. */\n body?: string;\n /** Success-only: bulleted list of \"what the agent did\" */\n changes?: string[];\n /**\n * Success-only: a prominent, labeled link to where the user should go\n * next (e.g. an inbox the program just configured). Rendered right under\n * the headline and shown verbatim — no UTM tagging — so the URL stays\n * clean and copy-pasteable. Set per-program in buildOutroData.\n */\n primaryLink?: { label: string; url: string };\n /**\n * Success-only: a short \"what to do next\" checklist with its own heading,\n * rendered as a bulleted list. Distinct from `changes`, which recaps what\n * the agent already did.\n */\n nextSteps?: { heading: string; items: string[] };\n docsUrl?: string;\n continueUrl?: string;\n /** Report file the agent wrote (e.g. \"posthog-setup-report.md\") */\n reportFile?: string;\n /** Stable machine-readable error code from the error catalog (@lib/errors). */\n errorCode?: import('@shared/errors').ErrorCode;\n /** Structured context for the error code; safe for telemetry payloads. */\n errorDetail?: Record<string, unknown>;\n /** PostHog dashboard URL the program created on the user's behalf. */\n dashboardUrl?: string;\n /** PostHog notebook URL the program uploaded the report to. */\n notebookUrl?: string;\n /**\n * Copy-paste prompt the operator hands to their coding agent to finish the\n * job (work the report's checklist). Printed to the terminal's main buffer on\n * exit (see getExitLine in start-tui.ts) — the TUI's alternate screen is wiped\n * on exit, so the scrollback line is where it survives and can be\n * triple-click-selected. Set per-program in buildOutroData.\n */\n handoffPrompt?: string;\n}\n\n/** A single question rendered by the WizardAsk overlay. */\nexport interface AskQuestion {\n /** Key for the response map */\n id: string;\n prompt: string;\n /** text = single-line free input; single/multi = picker */\n kind: 'single' | 'multi' | 'text';\n /** Required for `single` and `multi`. Ignored for `text`. */\n options?: { label: string; value: string; description?: string }[];\n /** Defaults to true */\n required?: boolean;\n /**\n * Only meaningful for kind='text'. When true, the wizard-tools `wizard_ask`\n * tool stores the user's answer in the session secret vault and returns\n * `{ secretRef }` to the agent instead of the plain string — so the value\n * never enters the LLM conversation. The TUI masks the input as it is typed\n * (see `shouldMaskAnswer`). See `secret-vault.ts`.\n */\n sensitive?: boolean;\n}\n\n/**\n * Copy for a modal shown before an optional step runs, so the user can decline\n * it. The program that owns the step supplies the words; the runner and the\n * screen only carry them.\n */\nexport interface TaskNotice {\n title: string;\n /** Paragraphs, in order. */\n body: string[];\n /** Optional highlighted list, e.g. what was detected. */\n items?: string[];\n docsLabel?: string;\n docsUrl?: string;\n confirmLabel: string;\n cancelLabel: string;\n prompt: string;\n}\n\n/** Map of question id → answer (string for single/text, string[] for multi). */\nexport type AskAnswers = Record<string, string | string[]>;\n\n/** A pending wizard_ask request held by the store. */\nexport interface PendingQuestion {\n id: string;\n questions: AskQuestion[];\n /**\n * UTC ISO 8601 timestamp of when the ask was created. Published on the\n * task stream as `pending_input.asked_at` so the web app can age the\n * prompt; stable across pushes for the lifetime of one ask.\n */\n askedAt?: string;\n /** Skill id of the caller. Set by the wizard from session.skillId. */\n source: string;\n /**\n * When true, the ask overlay renders standalone URLs in prompt text as\n * OSC 8 hyperlinks and copies a lone URL to the clipboard. Opt-in per\n * program (set from `AgentRunDefinition.richLinks` via the ask bridge); defaults\n * to false so existing flows render prompts exactly as before. See\n * `LinkText` / `link-helpers`.\n */\n richLinks?: boolean;\n}\n\n// ── What the agent reports ──────────────────────────────────────────\n\n/**\n * One assistant turn's token usage, for the hidden Ctrl+T token/cost HUD.\n * `model` is the model that produced *this* turn (e.g. the SDK's\n * `message.message.model`) — a subagent can run on a different model than\n * the main session, and some programs override to Haiku, so pricing must key\n * off the per-turn model rather than a single run-wide assumption. Omit only\n * when the caller genuinely has no model context (falls back to Sonnet\n * pricing — see `pricePerMtokForModel` in `@lib/agent/token-pricing`).\n */\nexport interface TokenUsageDelta {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n cacheCreation5m: number;\n cacheCreation1h: number;\n model?: string;\n}\n\n/** The run spinner as the agent drives it: `WizardUI.spinner()` returns one. */\nexport interface SpinnerHandle {\n start(message?: string): void;\n stop(message?: string): void;\n message(msg?: string): void;\n}\n\n/**\n * Context the agent attaches to a 401 so the caller can pick the right copy.\n *\n * `hasSettingsConflict` is true when a Claude Code settings file (project,\n * project-local, the user's global config, or managed) actually overrides the\n * LLM Gateway auth. `conflicts` carries the exact files and keys so the screen\n * can name them. When there is no conflict, the 401 has a different cause (bad\n * PAT prefix, missing scope, expired key, region mismatch) and we should not\n * advise the user to log out of Claude Code.\n */\nexport interface AuthErrorDetail {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n /**\n * True when the agent SDK authenticated from a stored Claude login\n * (`apiKeySource: \"/login managed key\"`) instead of the wizard's gateway\n * token — conflicting Anthropic credentials. Takes priority in the screen.\n */\n usingManagedLogin?: boolean;\n /** Human-readable places a conflicting Anthropic credential may live. */\n credentialPlaces?: string[];\n /**\n * True when a pre-run refresh already failed on a dead grant. The login is\n * gone and re-running is the only fix, so this outranks every other branch —\n * none of the usual advice (key type, scopes, region) applies.\n */\n sessionExpired?: boolean;\n logFilePath: string;\n}\n\n/** One task as the caller renders it. The same shape `WizardUI.syncTodos` takes. */\nexport interface TaskSnapshot {\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n}\n\nexport type ProgressLogLevel = 'info' | 'warn' | 'error' | 'success' | 'step';\n\n/**\n * Everything the agent reports while it runs. One event per former\n * `getUI()` call, in the same order, with the same payload, so a reducer that\n * maps each case back onto `WizardUI` reproduces today's output exactly.\n *\n * Payloads are copies. Never a store, a setter, a function or a live\n * collection. The callback returns nothing and the agent never branches on it.\n */\nexport type AgentProgress =\n /** The run's main work has started (`WizardUI.startRun`). */\n | { kind: 'lifecycle'; phase: 'started' }\n /** The run finished and the caller may show its outro (`WizardUI.outro`). */\n | { kind: 'lifecycle'; phase: 'completed'; message: string }\n /** The run spinner (`WizardUI.spinner()`), one handle per run. */\n | {\n kind: 'spinner';\n action: 'start' | 'stop' | 'message';\n message?: string;\n }\n /** A log line (`WizardUI.log[level]`). */\n | { kind: 'log'; level: ProgressLogLevel; message: string }\n /** A `[STATUS]` line the agent printed (`WizardUI.pushStatus`). */\n | { kind: 'status'; message: string }\n /** The full task list, already sorted for display (`WizardUI.syncTodos`). */\n | { kind: 'tasks'; tasks: TaskSnapshot[] }\n /** The stage of work derived from the active tool (`WizardUI.setStage`). */\n | { kind: 'stage'; stage: string }\n /** A PostHog URL the agent created (`setDashboardUrl` / `setNotebookUrl`). */\n | { kind: 'url'; which: 'dashboard' | 'notebook'; url: string }\n /** One assistant turn's token usage (`WizardUI.addTokenUsage`). */\n | { kind: 'usage'; delta: TokenUsageDelta }\n /** The SDK's authoritative run cost (`WizardUI.setFinalTokenCostUsd`). */\n | { kind: 'finalCost'; usd: number }\n /** The gateway returned 401; a failure follows (`WizardUI.showAuthError`). */\n | { kind: 'authError'; detail: AuthErrorDetail }\n /** The handoff document the agent published (`WizardUI.setHandoffText`). */\n | { kind: 'handoff'; text: string }\n /** The run's final outro payload (`WizardUI.setOutroData`). */\n | { kind: 'completion'; outro: OutroData }\n /** One short line per agent step, only from a run that collects its transcript. */\n | { kind: 'activity'; line: string };\n\nexport type ProgressEmitter = (event: AgentProgress) => void;\n\n/**\n * The questions the agent may need a person (or a script) to answer. Every\n * capability is optional. With none supplied the agent installs no ask bridge,\n * so `wizard_ask` returns its existing \"not available\" error, and an optional\n * task notice is declined — the same path a `--ci` run takes today.\n * Each request's `signal` aborts when that request times out, the run's\n * signal aborts, or another task fails the run. On that abort the caller\n * dismisses that request alone, and that dismissal must not throw: abort\n * listeners run where the agent cannot catch them, so Node would rethrow the\n * error as an uncaught exception.\n */\nexport interface AgentInteraction {\n /**\n * Open a question and resolve with the answers. The bridge that calls this\n * owns the timeout, the `__cancelled__` sentinel and the analytics.\n */\n ask?: (\n question: PendingQuestion,\n context: { signal: AbortSignal },\n ) => Promise<AskAnswers>;\n /** Offer an optional step and resolve with whether to keep it. */\n taskNotice?: (\n notice: TaskNotice,\n context: { signal: AbortSignal },\n ) => Promise<boolean>;\n}\n","/**\n * WizardSession — single source of truth for every decision the wizard needs.\n *\n * Populated in layers:\n * CLI args / env vars → populate fields directly\n * Auto-detection → framework, typescript, package manager\n * TUI screens → region, framework disambiguation, etc.\n * OAuth → credentials\n *\n * Business logic reads from the session. Never calls a prompt.\n */\n\nimport { POSTHOG_LOCAL_URL, resolveLocalDev } from '@shared/local-dev';\nimport type { Harness, Integration, Sequence } from '@shared/constants';\nimport type { FrameworkConfig } from '@programs/types';\nimport type { WizardReadinessResult } from '@shared/health-checks/readiness';\nimport type { SettingsConflict } from '@shared/claude-settings';\nimport type { ApiUser, ApiProject, Credentials } from '@shared/api';\nimport type { CloudRegion } from '@utils/types';\nimport type {\n AskAnswers,\n AskQuestion,\n OutroData,\n PendingQuestion,\n TaskNotice,\n} from '@agent/types';\n// Leaf module on purpose: shared analytics imports this file, so the agent\n// entry would form a module cycle here.\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports -- the session becomes a TUI projection later in the refactor\nimport { OutroKind } from '@agent/progress';\nimport { DiscoveredFeature } from '@shared/discovered-feature';\n\n// These shapes moved to their owners; re-exported so every session reader\n// keeps its import path. `Credentials` sits with the API types,\n// `DiscoveredFeature` sits in shared so programs can name it without the\n// session, and the outro, question and task-notice shapes are the agent's\n// contract.\nexport type { Credentials, CloudRegion };\nexport { OutroKind, DiscoveredFeature };\nexport type { AskAnswers, AskQuestion, OutroData, PendingQuestion, TaskNotice };\n\nfunction parseProjectIdArg(value: string | undefined): number | undefined {\n if (value === undefined || value === '') return undefined;\n const n = Number(value);\n return Number.isInteger(n) && n > 0 ? n : undefined;\n}\n\n/** Lifecycle phase of the main work (agent run, MCP install, etc.) */\nexport enum RunPhase {\n /** Still gathering input (intro, setup screens) */\n Idle = 'idle',\n /** Main work is in progress */\n Running = 'running',\n /** Main work finished successfully */\n Completed = 'completed',\n /** Main work finished with an error */\n Error = 'error',\n}\n\n/** Consent to report what local detection found (see `scanConsent` below). */\nexport enum ScanConsent {\n Undecided = 'undecided',\n Granted = 'granted',\n Declined = 'declined',\n}\n\n/** Outcome of the MCP server installation step */\nexport enum McpOutcome {\n NoClients = 'no_clients',\n Skipped = 'skipped',\n Installed = 'installed',\n Failed = 'failed',\n}\n\n/**\n * PostHog dashboard URL emitted by the agent during a program run.\n * Populated via the `[DASHBOARD_URL]` text marker in agent assistant messages\n * — see `handleSDKMessage` in `agent/agent-interface.ts`. Read by programs\n * (e.g. events-audit) inside `buildOutroData` to surface a dashboard link\n * the agent actually created.\n */\n\nexport interface WizardSession {\n // From CLI args\n debug: boolean;\n installDir: string;\n ci: boolean;\n signup: boolean;\n /**\n * Harness-only escape hatch: keep the `wizard_ask` bridge wired in a `ci`\n * session so an e2e run can answer the agent's questions.\n *\n * Only the e2e TUI host sets it, from the `E2E_ASK` env var. There is no CLI\n * flag, `bin.ts` never populates it, and nothing in a published build reads\n * the env var — so a normal `--ci` run is unchanged. See `shouldDisableAsk`.\n *\n * Guarding `E2E_ASK` is not enough on its own: the CI runner spreads the\n * whole `POSTHOG_WIZARD_*` bag into `buildSession`, which would let\n * `POSTHOG_WIZARD_e2e_ask=true` set this field. `readEnvironment` drops it —\n * see `NEVER_FROM_ENV`, and keep that list in step with this comment.\n */\n e2eAsk: boolean;\n /**\n * `--local-posthog` folds into `baseUrl`, and `--local-context-mill` is read\n * from `getLocalDev()` — neither belongs here. This one stays because\n * `mcp add|remove|tutorial --local` populate it from their own flag.\n */\n localMcp: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n /**\n * Explicit PostHog base URL (`--base-url`). When set, it pins every PostHog\n * origin — API host, cloud/app URL, OAuth server — and `region` is ignored.\n * The runtime equivalent of the dev-build localhost routing; lets the shipped\n * wizard target a local/self-hosted stack. Threaded into the URL helpers in\n * `@utils/urls`. Empty/unset → region-based resolution.\n */\n baseUrl?: string;\n benchmark: boolean;\n yaraReport: boolean;\n projectId?: number;\n noTelemetry: boolean;\n\n /**\n * `--capture-aio`: mirror every wizard LLM call as an `$ai_generation` event\n * into the authenticated project's AI Observability tab. Dev/test builds\n * only — the flag is undeclared in published builds so this stays `false`\n * there. See `src/agent/aio-capture.ts`.\n */\n captureAio: boolean;\n\n /** `--harness` override, read by `resolveHarness`. Wins over the runner flag. */\n harness?: Harness;\n /** `--sequence` override, read in `runProgram`. Wins over the orchestrator flag. */\n sequence?: Sequence;\n /** `--model` override (gateway id), read by `resolveHarness`. Wins over the binding's model. */\n model?: string;\n\n // From detection + screens\n setupConfirmed: boolean;\n /**\n * Gates reporting only; local detection runs either way. Reporting treats\n * 'undecided' as 'declined', so a path that reports before the user was\n * asked sends nothing rather than everything.\n */\n scanConsent: ScanConsent;\n /** Guards against reporting twice; consent resolves from two paths. */\n warehouseSourcesReported: boolean;\n /**\n * Guards `maybeStampAiSdkDetected` against running twice: it is called from\n * both run-wizard.ts's auth step and bootstrap.ts, since either can be the\n * first real `authenticate()` to complete depending on the program.\n */\n aiSdkStampReported: boolean;\n integration: Integration | null;\n frameworkContext: Record<string, unknown>;\n typescript: boolean;\n\n /** Human-readable label for the detected framework variant (e.g., \"Django with Wagtail CMS\") */\n detectedFrameworkLabel: string | null;\n\n /** PostHog found in the project's dependencies. A signal, not a verified install. */\n posthogSdkDetected: boolean;\n\n /** True once framework detection has run (whether it found something or not) */\n detectionComplete: boolean;\n\n /** Set when the detected framework version is too old for the wizard */\n unsupportedVersion: {\n current: string;\n minimum: string;\n docsUrl: string;\n } | null;\n\n // From OAuth\n credentials: Credentials | null;\n\n /**\n * `role_at_organization` from `/api/users/@me/`. Null when the upstream\n * value is missing (older accounts, fresh signups before onboarding).\n * Drives role-tailored MCP prompt suggestions on the McpSuggestedPromptsScreen.\n *\n * Mirrors `apiUser?.role_at_organization` — kept as a top-level convenience\n * because it has dedicated UI semantics (role-tailored kits) and pre-dates\n * the broader `apiUser` plumbing.\n */\n roleAtOrganization: string | null;\n\n /**\n * Full user payload from `/api/users/@me/` — identifiers, profile,\n * current team + organization, preferences, etc. Null until OAuth /\n * CI-key auth populates it. Schema lives in `src/shared/api.ts` and\n * passes through unknown upstream fields so downstream features can\n * read account context (plan, org name, email, etc.) without\n * re-fetching.\n */\n apiUser: ApiUser | null;\n\n /**\n * Project payload resolved at authentication, kept so a second agent run in\n * the same invocation (e.g. self-driving's integration phase) reuses the\n * first login wholesale instead of re-authenticating. The resolved region\n * lives on `credentials.host.region`.\n */\n apiProject: ApiProject | null;\n\n // Lifecycle\n runPhase: RunPhase;\n loginUrl: string | null;\n // Direct PostHog authorize URL, shown in the manual-paste modal for\n // headless/remote shells (the localhost loginUrl is unreachable there).\n authorizeUrl: string | null;\n\n // Feature discovery\n discoveredFeatures: DiscoveredFeature[];\n\n // ScreenId completion\n mcpComplete: boolean;\n mcpOutcome: McpOutcome | null;\n mcpInstalledClients: string[];\n /** Editor-owned login commands still to run (e.g. `claude mcp login posthog`), echoed at exit. */\n mcpLoginCommands: string[];\n mcpSuggestedPromptsDismissed: boolean;\n /** True once the user has acted on (opened or skipped) the Connect-Slack step. */\n slackStepDismissed: boolean;\n /**\n * Whether the project already has a Slack integration connected.\n * `null` until detected. Prefetched by the tutorial screen as soon as\n * credentials exist so the Connect-Slack step renders the right\n * variant immediately instead of flashing the nudge first.\n */\n slackConnected: boolean | null;\n skillsComplete: boolean;\n outroDismissed: boolean;\n\n /**\n * Self-driving only: whether to integrate PostHog as part of this run.\n * `null` until decided. When detection finds no PostHog SDK, the\n * integration-check screen sets this to `true` (Self-driving needs an SDK,\n * so we always integrate in that case) — and, on the same screen, asks\n * whether the user already has a PostHog account: \"yes\" leaves `signup`\n * false (OAuth login); \"no\" flips `signup` and collects `email`/`region`\n * so auth provisions a new account. The `--integrate` flag pre-sets this to\n * `true`, skipping the screen entirely and defaulting to the OAuth login.\n * When `true`, the self-driving prompt has the agent set up the SDK before\n * the Self-driving steps. Unused by other programs.\n */\n integrate: boolean | null;\n\n /**\n * Ids of composed run steps that have completed — e.g. self-driving's\n * `integrate-run`. Lets a run step's `isComplete` hold after it ran,\n * independent of the shared `runPhase`.\n */\n completedRuns: string[];\n\n /**\n * Self-driving only: whether the user confirmed the handoff screen shown\n * after the integration run (\"PostHog is installed — now set up Self-driving\").\n * Gates the Self-driving run so it doesn't start until acknowledged. Only\n * reached in the integrate path; the already-has-PostHog path skips it.\n */\n selfDrivingHandoffConfirmed: boolean;\n\n /**\n * Self-driving only: whether the project has the PostHog GitHub App\n * connected. `null` until the GitHub gate's first check resolves. Self-driving\n * cannot research issues or open fixes without it, so the gate holds the run\n * until this is `true`.\n */\n githubConnected: boolean | null;\n\n /**\n * Self-driving only: the user answered \"I can't connect right now\" on the\n * GitHub gate. Completes the gate step and hides the run step, so the flow\n * lands on the outro without starting the agent.\n */\n githubDeclined: boolean;\n\n // Runtime\n readinessResult: WizardReadinessResult | null;\n outageDismissed: boolean;\n settingsOverrideKeys: string[] | null;\n settingsConflicts: SettingsConflict[] | null;\n /** Mirrors `AuthErrorDetail` in `@ui/wizard-ui` — keep the two in step. */\n authErrorDetail: {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n usingManagedLogin?: boolean;\n credentialPlaces?: string[];\n sessionExpired?: boolean;\n logFilePath: string;\n } | null;\n portConflictProcess: {\n command: string;\n pid: string;\n port: number;\n user: string;\n } | null;\n /** Copy for the task-notice modal, set while it is open. */\n taskNotice: TaskNotice | null;\n outroData: OutroData | null;\n /** Skill saved for the user's own agent during the handoff. */\n spellbook: { path: string; skillsIncluded: boolean } | null;\n /**\n * How the user left the mint-failure screen: `continue` walks the\n * post-run steps (MCP, Slack, keep-skills), `exit` leaves. Null until then.\n */\n mintHandoff: 'continue' | 'exit' | null;\n dashboardUrl: string | null;\n notebookUrl: string | null;\n\n // Program metadata (set by runWizard in bin.ts)\n programLabel: string | null;\n skillId: string | null;\n\n // Resolved framework config (set after integration is known)\n frameworkConfig: FrameworkConfig | null;\n\n /** Active wizard_ask request, set by the bridge when the agent calls the tool. */\n pendingQuestion: PendingQuestion | null;\n}\n\n/**\n * Build a WizardSession from CLI args, pre-populating whatever is known.\n */\nexport function buildSession(args: {\n debug?: boolean;\n installDir?: string;\n ci?: boolean;\n signup?: boolean;\n /** Harness-only. Set by the e2e TUI host from `E2E_ASK`, never by a flag. */\n e2eAsk?: boolean;\n localDev?: boolean;\n localMcp?: boolean;\n localPosthog?: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n baseUrl?: string;\n integration?: Integration;\n benchmark?: boolean;\n yaraReport?: boolean;\n projectId?: string;\n noTelemetry?: boolean;\n harness?: Harness;\n sequence?: Sequence;\n model?: string;\n integrate?: boolean;\n captureAio?: boolean;\n}): WizardSession {\n const local = resolveLocalDev(args);\n return {\n debug: args.debug ?? false,\n installDir: args.installDir ?? process.cwd(),\n ci: args.ci ?? false,\n signup: args.signup ?? false,\n e2eAsk: args.e2eAsk ?? false,\n localMcp: local.localMcp,\n mcpFeatures: args.mcpFeatures,\n apiKey: args.apiKey,\n email: args.email,\n region: args.region,\n // `--local-posthog` is sugar over `--base-url`, which every downstream URL\n // helper already honours. An explicit `--base-url` is more specific, so it wins.\n baseUrl:\n args.baseUrl ?? (local.localPosthog ? POSTHOG_LOCAL_URL : undefined),\n benchmark: args.benchmark ?? false,\n yaraReport: args.yaraReport ?? false,\n projectId: parseProjectIdArg(args.projectId),\n noTelemetry: args.noTelemetry ?? false,\n captureAio: args.captureAio ?? false,\n harness: args.harness,\n sequence: args.sequence,\n model: args.model,\n\n setupConfirmed: false,\n // No screen can ask in a scripted CI run, so granting keeps CI's\n // telemetry as it was. --signup alone still provisions a brand-new\n // account headlessly, and that user has never seen the disclosure — a\n // headless `--ci --signup` run stays covered by the ci branch above.\n scanConsent: args.ci ? ScanConsent.Granted : ScanConsent.Undecided,\n warehouseSourcesReported: false,\n aiSdkStampReported: false,\n integration: args.integration ?? null,\n frameworkContext: {},\n typescript: false,\n detectedFrameworkLabel: null,\n posthogSdkDetected: false,\n detectionComplete: false,\n unsupportedVersion: null,\n\n runPhase: RunPhase.Idle,\n discoveredFeatures: [],\n mcpComplete: false,\n mcpOutcome: null,\n mcpInstalledClients: [],\n mcpLoginCommands: [],\n mcpSuggestedPromptsDismissed: false,\n slackStepDismissed: false,\n slackConnected: null,\n skillsComplete: false,\n outroDismissed: false,\n // `--integrate` forces integration (skip the question); otherwise the\n // integration-check screen resolves it from null.\n integrate: args.integrate === true ? true : null,\n completedRuns: [],\n selfDrivingHandoffConfirmed: false,\n githubConnected: null,\n githubDeclined: false,\n loginUrl: null,\n authorizeUrl: null,\n credentials: null,\n roleAtOrganization: null,\n apiUser: null,\n apiProject: null,\n readinessResult: null,\n outageDismissed: false,\n settingsOverrideKeys: null,\n settingsConflicts: null,\n authErrorDetail: null,\n portConflictProcess: null,\n taskNotice: null,\n outroData: null,\n spellbook: null,\n mintHandoff: null,\n dashboardUrl: null,\n notebookUrl: null,\n programLabel: null,\n skillId: null,\n frameworkConfig: null,\n pendingQuestion: null,\n };\n}\n\n/** One place to ask, so a new consent state does not need three edits. */\nexport function mayReportScanResults(session: WizardSession): boolean {\n return session.scanConsent === ScanConsent.Granted;\n}\n\n/** Lives here so analytics infrastructure never learns what consent means. */\nexport function reportableDiscoveredFeatures(\n session: WizardSession,\n): DiscoveredFeature[] | undefined {\n return mayReportScanResults(session) ? session.discoveredFeatures : undefined;\n}\n\n/** Also a scan result, so it travels under the same consent as the rest. */\nexport function reportablePosthogSdkDetected(\n session: WizardSession,\n): boolean | undefined {\n return mayReportScanResults(session) ? session.posthogSdkDetected : undefined;\n}\n"],"mappings":";;;AAgBA,IAAY,YAAL,yBAAA,WAAA;AACL,WAAA,aAAA;AACA,WAAA,WAAA;AACA,WAAA,YAAA;;KACD;;;;;;;;;;;;;;ACqBD,SAAS,kBAAkB,OAA+C;AACxE,KAAI,UAAU,KAAA,KAAa,UAAU,GAAI,QAAO,KAAA;CAChD,MAAM,IAAI,OAAO,MAAM;AACvB,QAAO,OAAO,UAAU,EAAE,IAAI,IAAI,IAAI,IAAI,KAAA;;;AAI5C,IAAY,WAAL,yBAAA,UAAA;;AAEL,UAAA,UAAA;;AAEA,UAAA,aAAA;;AAEA,UAAA,eAAA;;AAEA,UAAA,WAAA;;KACD;;;;AA+QD,SAAgB,aAAa,MAyBX;CAChB,MAAM,QAAQ,gBAAgB,KAAK;AACnC,QAAO;EACL,OAAO,KAAK,SAAS;EACrB,YAAY,KAAK,cAAc,QAAQ,KAAK;EAC5C,IAAI,KAAK,MAAM;EACf,QAAQ,KAAK,UAAU;EACvB,QAAQ,KAAK,UAAU;EACvB,UAAU,MAAM;EAChB,aAAa,KAAK;EAClB,QAAQ,KAAK;EACb,OAAO,KAAK;EACZ,QAAQ,KAAK;EAGb,SACE,KAAK,YAAY,MAAM,eAAA,0BAAmC,KAAA;EAC5D,WAAW,KAAK,aAAa;EAC7B,YAAY,KAAK,cAAc;EAC/B,WAAW,kBAAkB,KAAK,UAAU;EAC5C,aAAa,KAAK,eAAe;EACjC,YAAY,KAAK,cAAc;EAC/B,SAAS,KAAK;EACd,UAAU,KAAK;EACf,OAAO,KAAK;EAEZ,gBAAgB;EAKhB,aAAa,KAAK,KAAA,YAAA;EAClB,0BAA0B;EAC1B,oBAAoB;EACpB,aAAa,KAAK,eAAe;EACjC,kBAAkB,EAAE;EACpB,YAAY;EACZ,wBAAwB;EACxB,oBAAoB;EACpB,mBAAmB;EACnB,oBAAoB;EAEpB,UAAA;EACA,oBAAoB,EAAE;EACtB,aAAa;EACb,YAAY;EACZ,qBAAqB,EAAE;EACvB,kBAAkB,EAAE;EACpB,8BAA8B;EAC9B,oBAAoB;EACpB,gBAAgB;EAChB,gBAAgB;EAChB,gBAAgB;EAGhB,WAAW,KAAK,cAAc,OAAO,OAAO;EAC5C,eAAe,EAAE;EACjB,6BAA6B;EAC7B,iBAAiB;EACjB,gBAAgB;EAChB,UAAU;EACV,cAAc;EACd,aAAa;EACb,oBAAoB;EACpB,SAAS;EACT,YAAY;EACZ,iBAAiB;EACjB,iBAAiB;EACjB,sBAAsB;EACtB,mBAAmB;EACnB,iBAAiB;EACjB,qBAAqB;EACrB,YAAY;EACZ,WAAW;EACX,WAAW;EACX,aAAa;EACb,cAAc;EACd,aAAa;EACb,cAAc;EACd,SAAS;EACT,iBAAiB;EACjB,iBAAiB;EAClB;;;AAIH,SAAgB,qBAAqB,SAAiC;AACpE,QAAO,QAAQ,gBAAA;;;AAIjB,SAAgB,6BACd,SACiC;AACjC,QAAO,qBAAqB,QAAQ,GAAG,QAAQ,qBAAqB,KAAA;;;AAItE,SAAgB,6BACd,SACqB;AACrB,QAAO,qBAAqB,QAAQ,GAAG,QAAQ,qBAAqB,KAAA"}
@@ -13,4 +13,4 @@ function isTaskStatus(value) {
13
13
  //#endregion
14
14
  export { isTaskStatus as n, TaskStatus as t };
15
15
 
16
- //# sourceMappingURL=wizard-ui-DoyOZxK8.js.map
16
+ //# sourceMappingURL=wizard-ui-DVqrYaOM.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wizard-ui-DoyOZxK8.js","names":[],"sources":["../src/ui/wizard-ui.ts"],"sourcesContent":["/**\n * WizardUI — abstraction layer for all user-facing operations.\n *\n * Business logic calls `getUI()` instead of importing the store directly.\n * Implementations: InkUI (TUI), LoggingUI (CI).\n *\n * No prompt methods — the TUI screens own all user input.\n * Session-mutating methods trigger reactive screen resolution in the TUI.\n */\n\nimport type { SettingsConflict } from '@shared/claude-settings';\nimport type { WizardReadinessResult } from '@shared/health-checks/readiness';\nimport type { ApiUser } from '@shared/api';\nimport type { Credentials, TaskNotice } from '@lib/wizard-session';\nimport type {\n AskAnswers,\n OutroData,\n PendingQuestion,\n} from '@lib/wizard-session';\n\nexport enum TaskStatus {\n Pending = 'pending',\n InProgress = 'in_progress',\n Completed = 'completed',\n Skipped = 'skipped',\n Failed = 'failed',\n}\n\nexport function isTaskStatus(value: string): value is TaskStatus {\n return (Object.values(TaskStatus) as string[]).includes(value);\n}\n\n// Progress payloads are the agent's contract; re-exported so UI code keeps its import path.\nimport type {\n AuthErrorDetail,\n SpinnerHandle,\n TokenUsageDelta,\n} from '@agent/types';\nexport type { AuthErrorDetail, SpinnerHandle, TokenUsageDelta };\n\nexport interface WizardUI {\n // ── Lifecycle messages ────────────────────────────────────────────\n intro(message: string): void;\n /** Success outro with a plain text message. */\n outro(message: string): void;\n /**\n * Error outro. Sets structured outroData and transitions run phase so\n * the router advances to the outro screen. Use for abort/failure paths\n * that need a custom error render — do NOT build the outroData by\n * mutating session directly (nanostore holds a shallow copy).\n */\n outroError(data: OutroData): void;\n /** Resolves when the user dismisses the outro screen (presses any key).\n * Lets the abort path wait for the user to read the error before the\n * process exits. Resolves immediately in non-TUI environments. */\n waitForOutroDismissed(): Promise<void>;\n cancel(message: string): void;\n\n // ── Logging ───────────────────────────────────────────────────────\n log: {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n };\n\n note(message: string): void;\n pushStatus(message: string): void;\n\n // ── Spinner ───────────────────────────────────────────────────────\n spinner(): SpinnerHandle;\n\n // ── Session state (triggers reactive screen resolution in TUI) ────\n /** Signal that the main work (agent run) has started. */\n startRun(): void;\n\n /** Store OAuth/API credentials. Resolves past AuthScreen in TUI. */\n setCredentials(credentials: Credentials): void;\n\n /**\n * Replace the credentials after a token refresh. Same store write as\n * {@link setCredentials} without the `auth complete` capture — the user\n * authenticated once, and a refresh is not a second login.\n */\n setAccessToken(credentials: Credentials): void;\n\n /**\n * Persist the user's `role_at_organization` once it's been fetched from\n * `/api/users/@me/`. Drives role-tailored prompt suggestions on the\n * McpSuggestedPromptsScreen. Pass `null` to clear / when unknown.\n */\n setRoleAtOrganization(role: string | null): void;\n\n /**\n * Persist the full user payload from `/api/users/@me/` so downstream\n * screens can read account context (current org, team, plan, email,\n * preferences, etc.) without re-fetching. Pass `null` to clear or\n * when the request failed.\n */\n setApiUser(user: ApiUser | null): void;\n\n /**\n * Park until the org's AI opt-in gate clears\n * (`organization.is_ai_data_processing_approved === true`, or the\n * program never registered the gate — requiresAi: false / no auth\n * step / CI session). The agent runner awaits this after setApiUser\n * and BEFORE skill install or agent start: this is the enforcement\n * point that keeps source on the machine while the TUI shows\n * AiOptInRequiredScreen. Resolves immediately in non-TUI\n * environments (CI auto-consents to AI usage).\n */\n waitForAiOptIn(): Promise<void>;\n\n /** Show blocking service outage (pushes outage overlay in TUI). Blocks until dismissed. */\n showBlockingOutage(result: WizardReadinessResult): Promise<void>;\n\n /** Store non-blocking readiness warnings (shown as Health tab in RunScreen). */\n setReadinessWarnings(result: WizardReadinessResult): void;\n\n /** Warn that another process is blocking the OAuth port (pushes overlay in TUI). */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void>;\n\n /**\n * Resolve with an OAuth authorization code the user enters by hand — the\n * fallback for headless/remote shells where the browser can't reach the\n * local callback server. The OAuth flow races this against the callback\n * server. Implementations that can't prompt (CI/logging) never resolve.\n */\n waitForManualAuthCode(): Promise<string>;\n\n showSettingsOverride(\n conflicts: SettingsConflict[],\n backupAndFix: () => boolean,\n ): Promise<void>;\n\n /**\n * Show an optional step's notice and return whether to keep that step. Hosts\n * that cannot prompt resolve false: a step nobody can answer must not run.\n */\n showTaskNotice(notice: TaskNotice): Promise<boolean>;\n\n /**\n * Dismiss an in-flight task notice as declined. Called when the offer times\n * out: the notice sits in front of the run's final steps, so left unanswered\n * it would hold the report behind a modal nobody is looking at.\n */\n cancelTaskNotice(): void;\n\n /** Show auth error overlay when Anthropic API returns 401. */\n showAuthError(detail?: AuthErrorDetail): void;\n\n /** Show the session-timeout overlay when the OAuth login window expires. */\n showSessionTimeout(): void;\n\n /**\n * Open the wizard_ask overlay and resolve with the user's answers.\n * Implementations that can't ask (CI/logging) reject so the bridge can\n * surface a clear \"not available\" error to the agent.\n */\n requestQuestion(question: PendingQuestion): Promise<AskAnswers>;\n\n /**\n * Dismiss the in-flight wizard_ask overlay, resolving its request with\n * cancelled sentinels. No-op when nothing is pending. The ask bridge calls\n * this on timeout so a stale pending question can't block later asks.\n */\n cancelPendingQuestion(): void;\n\n // ── Display state ──────────────────────────────────────────────────\n /** Set the detected framework label (e.g., \"Django with Wagtail CMS\") */\n setDetectedFramework(label: string): void;\n\n /** Register a callback to run when the TUI transitions onto the given screen. */\n onEnterScreen(screen: string, fn: () => void): void;\n\n setLoginUrl(url: string | null): void;\n\n /** Direct PostHog authorize URL, shown in the manual-paste modal. */\n setAuthorizeUrl(url: string | null): void;\n\n // ── Task tracking from SDK TaskCreate/TaskUpdate events ───────────\n // Receives the full materialised task list each call. The caller (agent\n // loop) maintains a Map<taskId, …> from incremental Task* events and\n // re-emits the snapshot here, preserving the existing store semantics.\n syncTodos(\n todos: Array<{\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n }>,\n ): void;\n\n // ── Event plan from .posthog-events.json ────────────────────\n setEventPlan(events: Array<{ name: string; description: string }>): void;\n\n // ── Dashboard URL emitted by the agent via [DASHBOARD_URL] marker ──\n setDashboardUrl(url: string): void;\n\n /** Current \"stage of work\" — derived from the active tool call. Drives the\n * Visualizer tab's NOW PLAYING display. Pass an AgentPhase value. */\n setStage(stage: string): void;\n\n // ── Notebook URL emitted by the agent via [NOTEBOOK_URL] marker ──\n setNotebookUrl(url: string): void;\n\n /** Handoff doc from the `publish_handoff` tool; the task-stream push carries it as `handoff_text`. */\n setHandoffText(text: string): void;\n\n /** Accumulate one assistant turn's token usage into the hidden Ctrl+T\n * token/cost HUD's running estimate. No-op outside the TUI. */\n addTokenUsage(delta: TokenUsageDelta): void;\n\n /** Reconcile the HUD's running cost estimate to the SDK's authoritative\n * `total_cost_usd` once the agent run completes. No-op outside the TUI. */\n setFinalTokenCostUsd(costUsd: number): void;\n\n // ── Outro payload built by agent-runner ──\n // Replaces the direct `session.outroData = X` mutation that breaks once\n // setKey-based store mutations have forked the session reference.\n setOutroData(data: OutroData): void;\n\n // ── Generic frameworkContext setter for program file watchers ─────\n setFrameworkContext(key: string, value: unknown): void;\n\n /** Read a frameworkContext value from the LIVE session (store may have\n * forked the reference the runner holds). Used by run configs to read\n * values written by post-auth screens (e.g. the source-maps picker). */\n getFrameworkContext(key: string): unknown;\n\n /** Park until the named program step's gate predicate flips true. Resolves\n * immediately if the step has no gate. Mirrors waitForAiOptIn for any\n * post-auth interactive step the agent run must wait on. */\n waitForGate(stepId: string): Promise<void>;\n}\n"],"mappings":";AAoBA,IAAY,aAAL,yBAAA,YAAA;AACL,YAAA,aAAA;AACA,YAAA,gBAAA;AACA,YAAA,eAAA;AACA,YAAA,aAAA;AACA,YAAA,YAAA;;KACD;AAED,SAAgB,aAAa,OAAoC;AAC/D,QAAQ,OAAO,OAAO,WAAW,CAAc,SAAS,MAAM"}
1
+ {"version":3,"file":"wizard-ui-DVqrYaOM.js","names":[],"sources":["../src/ui/wizard-ui.ts"],"sourcesContent":["/**\n * WizardUI — abstraction layer for all user-facing operations.\n *\n * Business logic calls `getUI()` instead of importing the store directly.\n * Implementations: InkUI (TUI), LoggingUI (CI).\n *\n * No prompt methods — the TUI screens own all user input.\n * Session-mutating methods trigger reactive screen resolution in the TUI.\n */\n\nimport type { SettingsConflict } from '@shared/claude-settings';\nimport type { WizardReadinessResult } from '@shared/health-checks/readiness';\nimport type { ApiUser } from '@shared/api';\nimport type { Credentials, TaskNotice } from '@lib/wizard-session';\nimport type {\n AskAnswers,\n OutroData,\n PendingQuestion,\n} from '@lib/wizard-session';\n\nexport enum TaskStatus {\n Pending = 'pending',\n InProgress = 'in_progress',\n Completed = 'completed',\n Skipped = 'skipped',\n Failed = 'failed',\n}\n\nexport function isTaskStatus(value: string): value is TaskStatus {\n return (Object.values(TaskStatus) as string[]).includes(value);\n}\n\n// Progress payloads are the agent's contract; re-exported so UI code keeps its import path.\nimport type {\n AuthErrorDetail,\n SpinnerHandle,\n TokenUsageDelta,\n} from '@agent/types';\nexport type { AuthErrorDetail, SpinnerHandle, TokenUsageDelta };\n\nexport interface WizardUI {\n // ── Lifecycle messages ────────────────────────────────────────────\n intro(message: string): void;\n /** Success outro with a plain text message. */\n outro(message: string): void;\n /**\n * Error outro. Sets structured outroData and transitions run phase so\n * the router advances to the outro screen. Use for abort/failure paths\n * that need a custom error render — do NOT build the outroData by\n * mutating session directly (nanostore holds a shallow copy).\n */\n outroError(data: OutroData): void;\n /** Resolves when the user dismisses the outro screen (presses any key).\n * Lets the abort path wait for the user to read the error before the\n * process exits. Resolves immediately in non-TUI environments. */\n waitForOutroDismissed(): Promise<void>;\n cancel(message: string): void;\n\n // ── Logging ───────────────────────────────────────────────────────\n log: {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n };\n\n note(message: string): void;\n pushStatus(message: string): void;\n\n // ── Spinner ───────────────────────────────────────────────────────\n spinner(): SpinnerHandle;\n\n // ── Session state (triggers reactive screen resolution in TUI) ────\n /** Signal that the main work (agent run) has started. */\n startRun(): void;\n\n /** Store OAuth/API credentials. Resolves past AuthScreen in TUI. */\n setCredentials(credentials: Credentials): void;\n\n /**\n * Replace the credentials after a token refresh. Same store write as\n * {@link setCredentials} without the `auth complete` capture — the user\n * authenticated once, and a refresh is not a second login.\n */\n setAccessToken(credentials: Credentials): void;\n\n /**\n * Persist the user's `role_at_organization` once it's been fetched from\n * `/api/users/@me/`. Drives role-tailored prompt suggestions on the\n * McpSuggestedPromptsScreen. Pass `null` to clear / when unknown.\n */\n setRoleAtOrganization(role: string | null): void;\n\n /**\n * Persist the full user payload from `/api/users/@me/` so downstream\n * screens can read account context (current org, team, plan, email,\n * preferences, etc.) without re-fetching. Pass `null` to clear or\n * when the request failed.\n */\n setApiUser(user: ApiUser | null): void;\n\n /**\n * Park until the org's AI opt-in gate clears\n * (`organization.is_ai_data_processing_approved === true`, or the\n * program never registered the gate — requiresAi: false / no auth\n * step / CI session). The agent runner awaits this after setApiUser\n * and BEFORE skill install or agent start: this is the enforcement\n * point that keeps source on the machine while the TUI shows\n * AiOptInRequiredScreen. Resolves immediately in non-TUI\n * environments (CI auto-consents to AI usage).\n */\n waitForAiOptIn(): Promise<void>;\n\n /** Show blocking service outage (pushes outage overlay in TUI). Blocks until dismissed. */\n showBlockingOutage(result: WizardReadinessResult): Promise<void>;\n\n /** Store non-blocking readiness warnings (shown as Health tab in RunScreen). */\n setReadinessWarnings(result: WizardReadinessResult): void;\n\n /** Warn that another process is blocking the OAuth port (pushes overlay in TUI). */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void>;\n\n /**\n * Resolve with an OAuth authorization code the user enters by hand — the\n * fallback for headless/remote shells where the browser can't reach the\n * local callback server. The OAuth flow races this against the callback\n * server. Implementations that can't prompt (CI/logging) never resolve.\n */\n waitForManualAuthCode(): Promise<string>;\n\n showSettingsOverride(\n conflicts: SettingsConflict[],\n backupAndFix: () => boolean,\n ): Promise<void>;\n\n /**\n * Show an optional step's notice and return whether to keep that step. Hosts\n * that cannot prompt resolve false: a step nobody can answer must not run.\n */\n showTaskNotice(notice: TaskNotice): Promise<boolean>;\n\n /**\n * Dismiss an in-flight task notice as declined. Called when the offer times\n * out: the notice sits in front of the run's final steps, so left unanswered\n * it would hold the report behind a modal nobody is looking at.\n */\n cancelTaskNotice(): void;\n\n /** Show auth error overlay when Anthropic API returns 401. */\n showAuthError(detail?: AuthErrorDetail): void;\n\n /** Show the session-timeout overlay when the OAuth login window expires. */\n showSessionTimeout(): void;\n\n /**\n * Open the wizard_ask overlay and resolve with the user's answers.\n * Implementations that can't ask (CI/logging) reject so the bridge can\n * surface a clear \"not available\" error to the agent.\n */\n requestQuestion(question: PendingQuestion): Promise<AskAnswers>;\n\n /**\n * Dismiss the in-flight wizard_ask overlay, resolving its request with\n * cancelled sentinels. No-op when nothing is pending. The ask bridge calls\n * this on timeout so a stale pending question can't block later asks.\n */\n cancelPendingQuestion(): void;\n\n // ── Display state ──────────────────────────────────────────────────\n /** Set the detected framework label (e.g., \"Django with Wagtail CMS\") */\n setDetectedFramework(label: string): void;\n\n /** Register a callback to run when the TUI transitions onto the given screen. */\n onEnterScreen(screen: string, fn: () => void): void;\n\n setLoginUrl(url: string | null): void;\n\n /** Direct PostHog authorize URL, shown in the manual-paste modal. */\n setAuthorizeUrl(url: string | null): void;\n\n // ── Task tracking from SDK TaskCreate/TaskUpdate events ───────────\n // Receives the full materialised task list each call. The caller (agent\n // loop) maintains a Map<taskId, …> from incremental Task* events and\n // re-emits the snapshot here, preserving the existing store semantics.\n syncTodos(\n todos: Array<{\n id?: string;\n source?: string;\n content: string;\n status: string;\n activeForm?: string;\n }>,\n ): void;\n\n // ── Event plan from .posthog-events.json ────────────────────\n setEventPlan(events: Array<{ name: string; description: string }>): void;\n\n // ── Dashboard URL emitted by the agent via [DASHBOARD_URL] marker ──\n setDashboardUrl(url: string): void;\n\n /** Current \"stage of work\" — derived from the active tool call. Drives the\n * Visualizer tab's NOW PLAYING display. Pass an AgentPhase value. */\n setStage(stage: string): void;\n\n // ── Notebook URL emitted by the agent via [NOTEBOOK_URL] marker ──\n setNotebookUrl(url: string): void;\n\n /** Handoff doc from the `publish_handoff` tool; the task-stream push carries it as `handoff_text`. */\n setHandoffText(text: string): void;\n\n /** Accumulate one assistant turn's token usage into the hidden Ctrl+T\n * token/cost HUD's running estimate. No-op outside the TUI. */\n addTokenUsage(delta: TokenUsageDelta): void;\n\n /** Reconcile the HUD's running cost estimate to the SDK's authoritative\n * `total_cost_usd` once the agent run completes. No-op outside the TUI. */\n setFinalTokenCostUsd(costUsd: number): void;\n\n // ── Outro payload built by agent-runner ──\n // Replaces the direct `session.outroData = X` mutation that breaks once\n // setKey-based store mutations have forked the session reference.\n setOutroData(data: OutroData): void;\n\n // ── Generic frameworkContext setter for program file watchers ─────\n setFrameworkContext(key: string, value: unknown): void;\n\n /** Read a frameworkContext value from the LIVE session (store may have\n * forked the reference the runner holds). Used by run configs to read\n * values written by post-auth screens (e.g. the source-maps picker). */\n getFrameworkContext(key: string): unknown;\n\n /** Park until the named program step's gate predicate flips true. Resolves\n * immediately if the step has no gate. Mirrors waitForAiOptIn for any\n * post-auth interactive step the agent run must wait on. */\n waitForGate(stepId: string): Promise<void>;\n}\n"],"mappings":";AAoBA,IAAY,aAAL,yBAAA,YAAA;AACL,YAAA,aAAA;AACA,YAAA,gBAAA;AACA,YAAA,eAAA;AACA,YAAA,aAAA;AACA,YAAA,YAAA;;KACD;AAED,SAAgB,aAAa,OAAoC;AAC/D,QAAQ,OAAO,OAAO,WAAW,CAAc,SAAS,MAAM"}
@@ -1,7 +1,7 @@
1
- import { f as WIZARD_YARA_REPORT_FILE, s as logToFile } from "./debug-Ch4BDOtD.js";
2
- import { f as EVENTS_AUDIT_REPORT_FILE, h as EVENT_PLAN_FILE, m as EVENT_INVENTORY_PART_PATTERN, p as EVENT_INVENTORY_FILE } from "./constants-jFI2SaE1.js";
3
- import { n as analytics } from "./analytics-CHCZ_qUR.js";
4
- import { r as readFileHead } from "./bounded-fs-Bx9zTe6m.js";
1
+ import { f as WIZARD_YARA_REPORT_FILE, s as logToFile } from "./debug-kAHwWGg7.js";
2
+ import { f as EVENTS_AUDIT_REPORT_FILE, h as EVENT_PLAN_FILE, m as EVENT_INVENTORY_PART_PATTERN, p as EVENT_INVENTORY_FILE } from "./constants-DHCBSfnx.js";
3
+ import { n as analytics } from "./analytics-DXK1gc12.js";
4
+ import { r as readFileHead } from "./bounded-fs-vAq-T-K7.js";
5
5
  import fs from "fs";
6
6
  import path from "path";
7
7
  import fg from "fast-glob";
@@ -733,4 +733,4 @@ async function scanSkillFiles(cwd, skillDir, llmProvider) {
733
733
  //#endregion
734
734
  export { coerceAuditChecks as _, flushScanReport as a, isWizardDocumentationPath as c, repeatBlockReason as d, scanAndTriage as f, AUDIT_REPORT_FILE as g, AUDIT_CHECKS_FILE as h, createRepeatBlockTracker as i, prewarmYaraScanner as l, writeScanReport as m, createPostToolUseYaraHooks as n, formatScanReport as o, scanInstalledSkill as p, createPreToolUseYaraHooks as r, formatYaraAbortMessage as s, captureScanReport as t, recordExternalScan as u, publishBlockingMatch as v, scanVerdict as y };
735
735
 
736
- //# sourceMappingURL=yara-hooks-DCeMDd1o.js.map
736
+ //# sourceMappingURL=yara-hooks-BnxejtXK.js.map