@posthog/wizard 2.81.0 → 2.81.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 (111) hide show
  1. package/dist/{agent-interface-BFzBnz10.js → agent-interface-DMP3DZRd.js} +8 -8
  2. package/dist/{agent-interface-BFzBnz10.js.map → agent-interface-DMP3DZRd.js.map} +1 -1
  3. package/dist/{agent-prompt-loader-CbCW6YbP.js → agent-prompt-loader-BrivWIna.js} +6 -6
  4. package/dist/{agent-prompt-loader-CbCW6YbP.js.map → agent-prompt-loader-BrivWIna.js.map} +1 -1
  5. package/dist/{analytics-CGGE7OSa.js → analytics-X7JfAmh6.js} +2 -2
  6. package/dist/{analytics-CGGE7OSa.js.map → analytics-X7JfAmh6.js.map} +1 -1
  7. package/dist/analytics-dcL9EQ4r.js +2 -0
  8. package/dist/{api-ZZhiRtbb.js → api-BkDwZoL4.js} +2 -2
  9. package/dist/{api-ZZhiRtbb.js.map → api-BkDwZoL4.js.map} +1 -1
  10. package/dist/api-BrMGAI-b.js +2 -0
  11. package/dist/api-key-login-CZEgx2jb.js +2 -0
  12. package/dist/{api-key-login-D0KBr1dx.js → api-key-login-DE0yKkP4.js} +5 -5
  13. package/dist/{api-key-login-D0KBr1dx.js.map → api-key-login-DE0yKkP4.js.map} +1 -1
  14. package/dist/bin.js +1 -1
  15. package/dist/{bounded-fs-DwL2Tasp.js → bounded-fs-iDiqDQ9v.js} +3 -3
  16. package/dist/{bounded-fs-DwL2Tasp.js.map → bounded-fs-iDiqDQ9v.js.map} +1 -1
  17. package/dist/{ci-install-DKXrt_ow.js → ci-install-BAftKh2Z.js} +4 -4
  18. package/dist/{ci-install-DKXrt_ow.js.map → ci-install-BAftKh2Z.js.map} +1 -1
  19. package/dist/{debug-sB20p-Ek.js → debug-C3tLP-ZW.js} +3 -3
  20. package/dist/{debug-sB20p-Ek.js.map → debug-C3tLP-ZW.js.map} +1 -1
  21. package/dist/{gateway-Dg4Fm-nC.js → gateway-IQjQ582o.js} +5 -5
  22. package/dist/{gateway-Dg4Fm-nC.js.map → gateway-IQjQ582o.js.map} +1 -1
  23. package/dist/{headless-DhTDC9ga.js → headless-DOhxEmw5.js} +2 -2
  24. package/dist/{headless-DhTDC9ga.js.map → headless-DOhxEmw5.js.map} +1 -1
  25. package/dist/{headless-B3Ol1nkU.js → headless-XNvdWVEp.js} +1 -1
  26. package/dist/{host-resolution-DDYJXiAQ.js → host-resolution-DI2oucSK.js} +4 -4
  27. package/dist/{host-resolution-DDYJXiAQ.js.map → host-resolution-DI2oucSK.js.map} +1 -1
  28. package/dist/{install-Dh8Z5R15.js → install-BixbBDLR.js} +5 -5
  29. package/dist/{install-Dh8Z5R15.js.map → install-BixbBDLR.js.map} +1 -1
  30. package/dist/{install-CZeR38cD.js → install-DaZ6pvEl.js} +1 -1
  31. package/dist/{interactive-hqHk6kz4.js → interactive-WLNQWF0D.js} +3 -3
  32. package/dist/{interactive-hqHk6kz4.js.map → interactive-WLNQWF0D.js.map} +1 -1
  33. package/dist/{links-rMot83W2.js → links-Bye4fsrj.js} +3 -3
  34. package/dist/{links-rMot83W2.js.map → links-Bye4fsrj.js.map} +1 -1
  35. package/dist/{main-DNIeasXx.js → main-CN8nbuZO.js} +20 -20
  36. package/dist/{main-DNIeasXx.js.map → main-CN8nbuZO.js.map} +1 -1
  37. package/dist/{mcp-SZcGfaOz.js → mcp-B2o4d9DS.js} +3 -3
  38. package/dist/{mcp-SZcGfaOz.js.map → mcp-B2o4d9DS.js.map} +1 -1
  39. package/dist/{mcp-prompt-streaming-BuRMBgbo.js → mcp-prompt-streaming-COs1DfAm.js} +5 -5
  40. package/dist/{mcp-prompt-streaming-BuRMBgbo.js.map → mcp-prompt-streaming-COs1DfAm.js.map} +1 -1
  41. package/dist/{models-G1j-wgwe.js → models-Cow22jET.js} +2 -2
  42. package/dist/{models-G1j-wgwe.js.map → models-Cow22jET.js.map} +1 -1
  43. package/dist/{oauth-session-C2fVSGfr.js → oauth-session-Bj_-BY7o.js} +2 -2
  44. package/dist/{oauth-session-C2fVSGfr.js.map → oauth-session-Bj_-BY7o.js.map} +1 -1
  45. package/dist/{orchestrator-tools-BchqG7Qi.js → orchestrator-tools-lhFIBGnp.js} +3 -3
  46. package/dist/{orchestrator-tools-BchqG7Qi.js.map → orchestrator-tools-lhFIBGnp.js.map} +1 -1
  47. package/dist/{package-manager-B3_qSybg.js → package-manager-DZ4wcTz3.js} +4 -4
  48. package/dist/{package-manager-B3_qSybg.js.map → package-manager-DZ4wcTz3.js.map} +1 -1
  49. package/dist/{pi-Cw7CPXSl.js → pi-DREdQRPP.js} +12 -12
  50. package/dist/{pi-Cw7CPXSl.js.map → pi-DREdQRPP.js.map} +1 -1
  51. package/dist/{playground-CPNrQfb3.js → playground-CJx3lwTH.js} +4 -4
  52. package/dist/{playground-CPNrQfb3.js.map → playground-CJx3lwTH.js.map} +1 -1
  53. package/dist/{posthog-integration-FAWfClH3.js → posthog-integration-DDSPdbpw.js} +20 -20
  54. package/dist/{posthog-integration-FAWfClH3.js.map → posthog-integration-DDSPdbpw.js.map} +1 -1
  55. package/dist/{programs-Ml6OLybj.js → programs-6SFfUBmm.js} +15 -15
  56. package/dist/{programs-Ml6OLybj.js.map → programs-6SFfUBmm.js.map} +1 -1
  57. package/dist/programs-DvlhdeM_.js +3 -0
  58. package/dist/provisioning-CPGWgv7p.js +2 -0
  59. package/dist/{provisioning-BTVL49jD.js → provisioning-tRDPH7EQ.js} +4 -4
  60. package/dist/{provisioning-BTVL49jD.js.map → provisioning-tRDPH7EQ.js.map} +1 -1
  61. package/dist/{queue-tools-BQfRI_uD.js → queue-tools-DrJKvFHZ.js} +4 -4
  62. package/dist/{queue-tools-BQfRI_uD.js.map → queue-tools-DrJKvFHZ.js.map} +1 -1
  63. package/dist/{results-ycm_Tf31.js → results-Crcubw0Q.js} +2 -2
  64. package/dist/{results-ycm_Tf31.js.map → results-Crcubw0Q.js.map} +1 -1
  65. package/dist/{run-C6Ei6vvb.js → run-BrIGaPy7.js} +7 -7
  66. package/dist/{run-C6Ei6vvb.js.map → run-BrIGaPy7.js.map} +1 -1
  67. package/dist/{run-Bgg-ctbA.js → run-DVFTMbxf.js} +10 -10
  68. package/dist/{run-Bgg-ctbA.js.map → run-DVFTMbxf.js.map} +1 -1
  69. package/dist/{run-tool-CrN2xWzU.js → run-tool-CxdPXmlY.js} +18 -18
  70. package/dist/{run-tool-CrN2xWzU.js.map → run-tool-CxdPXmlY.js.map} +1 -1
  71. package/dist/run-tool-GfISLgEs.js +2 -0
  72. package/dist/{runners-GGYJs0Ny.js → runners-loOOmHyc.js} +8 -8
  73. package/dist/{runners-GGYJs0Ny.js.map → runners-loOOmHyc.js.map} +1 -1
  74. package/dist/{security-C36p8lu6.js → security-C_grSgIM.js} +5 -5
  75. package/dist/{security-C36p8lu6.js.map → security-C_grSgIM.js.map} +1 -1
  76. package/dist/{setup-utils-Dfgse6pY.js → setup-utils-BYXbb9NM.js} +3 -3
  77. package/dist/{setup-utils-Dfgse6pY.js.map → setup-utils-BYXbb9NM.js.map} +1 -1
  78. package/dist/{start-playground-D0TrdLmc.js → start-playground-Blh0Swil.js} +13 -13
  79. package/dist/{start-playground-D0TrdLmc.js.map → start-playground-Blh0Swil.js.map} +1 -1
  80. package/dist/{subagent-DR5caRzL.js → subagent-DQ_enM8C.js} +3 -3
  81. package/dist/{subagent-DR5caRzL.js.map → subagent-DQ_enM8C.js.map} +1 -1
  82. package/dist/{task-C1qKgsAf.js → task-Dm9wZbVW.js} +14 -14
  83. package/dist/{task-C1qKgsAf.js.map → task-Dm9wZbVW.js.map} +1 -1
  84. package/dist/{telemetry-Ch9ZJvm7.js → telemetry-NeZhrBeW.js} +2 -2
  85. package/dist/{telemetry-Ch9ZJvm7.js.map → telemetry-NeZhrBeW.js.map} +1 -1
  86. package/dist/{terminal-D20JFN3J.js → terminal-Z4hCXfie.js} +115 -89
  87. package/dist/terminal-Z4hCXfie.js.map +1 -0
  88. package/dist/{tools-CmSMclOD.js → tools-1aM6bI9Y.js} +8 -8
  89. package/dist/{tools-CmSMclOD.js.map → tools-1aM6bI9Y.js.map} +1 -1
  90. package/dist/{tools-BZseGChD.js → tools-dUJHRo6X.js} +13 -13
  91. package/dist/{tools-BZseGChD.js.map → tools-dUJHRo6X.js.map} +1 -1
  92. package/dist/{tui-DJf3ZPRh.js → tui-CCO7VVTA.js} +1 -1
  93. package/dist/{tui-BXe1D0tc.js → tui-Cmi_ckGg.js} +4 -4
  94. package/dist/{tui-BXe1D0tc.js.map → tui-Cmi_ckGg.js.map} +1 -1
  95. package/dist/{upload-step-BlAN7MC5.js → upload-step-e2Jp2fcr.js} +3 -3
  96. package/dist/{upload-step-BlAN7MC5.js.map → upload-step-e2Jp2fcr.js.map} +1 -1
  97. package/dist/{urls-eFaChZ9d.js → urls-Cu4RO30x.js} +2 -2
  98. package/dist/{urls-eFaChZ9d.js.map → urls-Cu4RO30x.js.map} +1 -1
  99. package/dist/{wizard-abort-BX3O4Hg4.js → wizard-abort-BPEiPCXk.js} +4 -4
  100. package/dist/{wizard-abort-BX3O4Hg4.js.map → wizard-abort-BPEiPCXk.js.map} +1 -1
  101. package/dist/{yara-hooks-DV4EkkZY.js → yara-hooks-CFD60h78.js} +1 -1
  102. package/dist/{yara-hooks-C4HOysrM.js → yara-hooks-canFIYTc.js} +4 -4
  103. package/dist/{yara-hooks-C4HOysrM.js.map → yara-hooks-canFIYTc.js.map} +1 -1
  104. package/package.json +1 -1
  105. package/dist/analytics-D6NAIJxP.js +0 -2
  106. package/dist/api-DM4uMJ00.js +0 -2
  107. package/dist/api-key-login-C30LRht2.js +0 -2
  108. package/dist/programs-DjCmEcxb.js +0 -3
  109. package/dist/provisioning-DL0xCJXH.js +0 -2
  110. package/dist/run-tool-tNjm8S-E.js +0 -2
  111. package/dist/terminal-D20JFN3J.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-SZcGfaOz.js","names":[],"sources":["../src/agent/runner/harness/pi/mcp.ts"],"sourcesContent":["/**\n * pi has no built-in MCP; `pi-mcp-adapter` — pi's own MCP extension, built here\n * with its supported `createMcpAdapter` embedding API — bridges the same hosted\n * MCP the anthropic path uses into the agent.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport { createJiti } from 'jiti';\nimport { VERSION } from '@shared/version';\nimport { logToFile } from '@utils/debug';\nimport { onAccessTokenRotated } from '@shared/oauth-session';\n\nconst MCP_TOKEN_ENV = 'POSTHOG_MCP_TOKEN';\nlet mcpTokenOwners = 0;\nlet activeMcpToken: string | undefined;\nlet previousMcpToken: string | undefined;\n\nlet stopFollowingRotations: (() => void) | undefined;\n\nfunction setMcpToken(token: string): void {\n activeMcpToken = token;\n process.env[MCP_TOKEN_ENV] = token;\n}\n\nfunction acquireMcpToken(token: string): () => void {\n if (mcpTokenOwners === 0) {\n previousMcpToken = process.env[MCP_TOKEN_ENV];\n // The adapter reads the env on each connect, so reconnects take the rotated token.\n stopFollowingRotations = onAccessTokenRotated(setMcpToken);\n }\n // A later session after a rotation carries the newer token of the same login.\n if (activeMcpToken !== token) setMcpToken(token);\n mcpTokenOwners += 1;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n mcpTokenOwners -= 1;\n if (mcpTokenOwners > 0) return;\n stopFollowingRotations?.();\n stopFollowingRotations = undefined;\n if (previousMcpToken === undefined) delete process.env[MCP_TOKEN_ENV];\n else process.env[MCP_TOKEN_ENV] = previousMcpToken;\n activeMcpToken = undefined;\n previousMcpToken = undefined;\n };\n}\n\nexport interface PostHogMcpSetup {\n /** pi ExtensionFactory to add to the resource loader's `extensionFactories`. */\n extensionFactory: (pi: unknown) => void;\n /** Release this setup's token ownership. Call after the run. */\n cleanup: () => void;\n}\n\n/** Server `instructions` for the system prompt — the adapter exposes no accessor, so one standard-SDK handshake; best-effort. */\nexport async function fetchInstructions(\n mcpUrl: string,\n accessToken: string,\n userAgent: string,\n): Promise<string | undefined> {\n const client = new Client({ name: 'posthog-wizard', version: VERSION });\n try {\n const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {\n requestInit: {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': userAgent,\n },\n },\n });\n await client.connect(transport);\n const instructions = client.getInstructions() || undefined;\n logToFile(`[pi-mcp] instructions ${instructions?.length ?? 0} chars`);\n return instructions;\n } catch (err) {\n logToFile(`[pi-mcp] instructions fetch skipped: ${String(err)}`);\n return undefined;\n } finally {\n await client.close().catch(() => undefined);\n }\n}\n\nexport async function setupPostHogMcp(opts: {\n mcpUrl: string;\n accessToken: string;\n userAgent: string;\n}): Promise<PostHogMcpSetup> {\n const { mcpUrl, accessToken, userAgent } = opts;\n\n // By env NAME: the token stays in this process, off disk, and never reaches pi's env-scrubbed tool subprocesses.\n const cleanup = acquireMcpToken(accessToken);\n\n try {\n // The adapter ships raw TypeScript; loading through jiti is its documented requirement.\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import<{\n createMcpAdapter: (\n options: unknown,\n ) => PostHogMcpSetup['extensionFactory'];\n }>('pi-mcp-adapter');\n const extensionFactory = mod.createMcpAdapter({\n config: {\n mcpServers: {\n posthog: {\n url: mcpUrl,\n auth: 'bearer',\n bearerTokenEnv: MCP_TOKEN_ENV,\n headers: { 'User-Agent': userAgent },\n // Connect at extension load — direct tools register without a session_start.\n lifecycle: 'eager',\n // Register only `exec`: `directTools: true` also mints a `posthog_get_<name>` tool per MCP resource, whose sentence-length names overflow Anthropic's 128-char tool-name limit and 400 the whole request.\n directTools: ['exec'],\n exposeResources: false,\n },\n },\n // Disable the proxy `mcp` tool (its search indirection pollutes context); the adapter re-enables it only if no direct tools resolve.\n settings: { disableProxyTool: true, toolPrefix: 'posthog' },\n },\n });\n logToFile(`[pi-mcp] adapter loaded; posthog MCP at ${mcpUrl}`);\n return { extensionFactory, cleanup };\n } catch (error) {\n cleanup();\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAM,gBAAgB;AACtB,IAAI,iBAAiB;AACrB,IAAI;AACJ,IAAI;AAEJ,IAAI;AAEJ,SAAS,YAAY,OAAqB;AACxC,kBAAiB;AACjB,SAAQ,IAAI,iBAAiB;;AAG/B,SAAS,gBAAgB,OAA2B;AAClD,KAAI,mBAAmB,GAAG;AACxB,qBAAmB,QAAQ,IAAI;AAE/B,2BAAyB,qBAAqB,YAAY;;AAG5D,KAAI,mBAAmB,MAAO,aAAY,MAAM;AAChD,mBAAkB;CAClB,IAAI,WAAW;AACf,cAAa;AACX,MAAI,SAAU;AACd,aAAW;AACX,oBAAkB;AAClB,MAAI,iBAAiB,EAAG;AACxB,4BAA0B;AAC1B,2BAAyB,KAAA;AACzB,MAAI,qBAAqB,KAAA,EAAW,QAAO,QAAQ,IAAI;MAClD,SAAQ,IAAI,iBAAiB;AAClC,mBAAiB,KAAA;AACjB,qBAAmB,KAAA;;;;AAYvB,eAAsB,kBACpB,QACA,aACA,WAC6B;CAC7B,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAAkB,SAAS;EAAS,CAAC;AACvE,KAAI;EACF,MAAM,YAAY,IAAI,8BAA8B,IAAI,IAAI,OAAO,EAAE,EACnE,aAAa,EACX,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,EACF,CAAC;AACF,QAAM,OAAO,QAAQ,UAAU;EAC/B,MAAM,eAAe,OAAO,iBAAiB,IAAI,KAAA;AACjD,YAAU,yBAAyB,cAAc,UAAU,EAAE,QAAQ;AACrE,SAAO;UACA,KAAK;AACZ,YAAU,wCAAwC,OAAO,IAAI,GAAG;AAChE;WACQ;AACR,QAAM,OAAO,OAAO,CAAC,YAAY,KAAA,EAAU;;;AAI/C,eAAsB,gBAAgB,MAIT;CAC3B,MAAM,EAAE,QAAQ,aAAa,cAAc;CAG3C,MAAM,UAAU,gBAAgB,YAAY;AAE5C,KAAI;EAQF,MAAM,oBALM,MADC,WAAW,OAAO,KAAK,IAAI,CACjB,OAIpB,iBAAiB,EACS,iBAAiB,EAC5C,QAAQ;GACN,YAAY,EACV,SAAS;IACP,KAAK;IACL,MAAM;IACN,gBAAgB;IAChB,SAAS,EAAE,cAAc,WAAW;IAEpC,WAAW;IAEX,aAAa,CAAC,OAAO;IACrB,iBAAiB;IAClB,EACF;GAED,UAAU;IAAE,kBAAkB;IAAM,YAAY;IAAW;GAC5D,EACF,CAAC;AACF,YAAU,2CAA2C,SAAS;AAC9D,SAAO;GAAE;GAAkB;GAAS;UAC7B,OAAO;AACd,WAAS;AACT,QAAM"}
1
+ {"version":3,"file":"mcp-B2o4d9DS.js","names":[],"sources":["../src/agent/runner/harness/pi/mcp.ts"],"sourcesContent":["/**\n * pi has no built-in MCP; `pi-mcp-adapter` — pi's own MCP extension, built here\n * with its supported `createMcpAdapter` embedding API — bridges the same hosted\n * MCP the anthropic path uses into the agent.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport { createJiti } from 'jiti';\nimport { VERSION } from '@shared/version';\nimport { logToFile } from '@utils/debug';\nimport { onAccessTokenRotated } from '@shared/oauth-session';\n\nconst MCP_TOKEN_ENV = 'POSTHOG_MCP_TOKEN';\nlet mcpTokenOwners = 0;\nlet activeMcpToken: string | undefined;\nlet previousMcpToken: string | undefined;\n\nlet stopFollowingRotations: (() => void) | undefined;\n\nfunction setMcpToken(token: string): void {\n activeMcpToken = token;\n process.env[MCP_TOKEN_ENV] = token;\n}\n\nfunction acquireMcpToken(token: string): () => void {\n if (mcpTokenOwners === 0) {\n previousMcpToken = process.env[MCP_TOKEN_ENV];\n // The adapter reads the env on each connect, so reconnects take the rotated token.\n stopFollowingRotations = onAccessTokenRotated(setMcpToken);\n }\n // A later session after a rotation carries the newer token of the same login.\n if (activeMcpToken !== token) setMcpToken(token);\n mcpTokenOwners += 1;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n mcpTokenOwners -= 1;\n if (mcpTokenOwners > 0) return;\n stopFollowingRotations?.();\n stopFollowingRotations = undefined;\n if (previousMcpToken === undefined) delete process.env[MCP_TOKEN_ENV];\n else process.env[MCP_TOKEN_ENV] = previousMcpToken;\n activeMcpToken = undefined;\n previousMcpToken = undefined;\n };\n}\n\nexport interface PostHogMcpSetup {\n /** pi ExtensionFactory to add to the resource loader's `extensionFactories`. */\n extensionFactory: (pi: unknown) => void;\n /** Release this setup's token ownership. Call after the run. */\n cleanup: () => void;\n}\n\n/** Server `instructions` for the system prompt — the adapter exposes no accessor, so one standard-SDK handshake; best-effort. */\nexport async function fetchInstructions(\n mcpUrl: string,\n accessToken: string,\n userAgent: string,\n): Promise<string | undefined> {\n const client = new Client({ name: 'posthog-wizard', version: VERSION });\n try {\n const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {\n requestInit: {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': userAgent,\n },\n },\n });\n await client.connect(transport);\n const instructions = client.getInstructions() || undefined;\n logToFile(`[pi-mcp] instructions ${instructions?.length ?? 0} chars`);\n return instructions;\n } catch (err) {\n logToFile(`[pi-mcp] instructions fetch skipped: ${String(err)}`);\n return undefined;\n } finally {\n await client.close().catch(() => undefined);\n }\n}\n\nexport async function setupPostHogMcp(opts: {\n mcpUrl: string;\n accessToken: string;\n userAgent: string;\n}): Promise<PostHogMcpSetup> {\n const { mcpUrl, accessToken, userAgent } = opts;\n\n // By env NAME: the token stays in this process, off disk, and never reaches pi's env-scrubbed tool subprocesses.\n const cleanup = acquireMcpToken(accessToken);\n\n try {\n // The adapter ships raw TypeScript; loading through jiti is its documented requirement.\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import<{\n createMcpAdapter: (\n options: unknown,\n ) => PostHogMcpSetup['extensionFactory'];\n }>('pi-mcp-adapter');\n const extensionFactory = mod.createMcpAdapter({\n config: {\n mcpServers: {\n posthog: {\n url: mcpUrl,\n auth: 'bearer',\n bearerTokenEnv: MCP_TOKEN_ENV,\n headers: { 'User-Agent': userAgent },\n // Connect at extension load — direct tools register without a session_start.\n lifecycle: 'eager',\n // Register only `exec`: `directTools: true` also mints a `posthog_get_<name>` tool per MCP resource, whose sentence-length names overflow Anthropic's 128-char tool-name limit and 400 the whole request.\n directTools: ['exec'],\n exposeResources: false,\n },\n },\n // Disable the proxy `mcp` tool (its search indirection pollutes context); the adapter re-enables it only if no direct tools resolve.\n settings: { disableProxyTool: true, toolPrefix: 'posthog' },\n },\n });\n logToFile(`[pi-mcp] adapter loaded; posthog MCP at ${mcpUrl}`);\n return { extensionFactory, cleanup };\n } catch (error) {\n cleanup();\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAM,gBAAgB;AACtB,IAAI,iBAAiB;AACrB,IAAI;AACJ,IAAI;AAEJ,IAAI;AAEJ,SAAS,YAAY,OAAqB;AACxC,kBAAiB;AACjB,SAAQ,IAAI,iBAAiB;;AAG/B,SAAS,gBAAgB,OAA2B;AAClD,KAAI,mBAAmB,GAAG;AACxB,qBAAmB,QAAQ,IAAI;AAE/B,2BAAyB,qBAAqB,YAAY;;AAG5D,KAAI,mBAAmB,MAAO,aAAY,MAAM;AAChD,mBAAkB;CAClB,IAAI,WAAW;AACf,cAAa;AACX,MAAI,SAAU;AACd,aAAW;AACX,oBAAkB;AAClB,MAAI,iBAAiB,EAAG;AACxB,4BAA0B;AAC1B,2BAAyB,KAAA;AACzB,MAAI,qBAAqB,KAAA,EAAW,QAAO,QAAQ,IAAI;MAClD,SAAQ,IAAI,iBAAiB;AAClC,mBAAiB,KAAA;AACjB,qBAAmB,KAAA;;;;AAYvB,eAAsB,kBACpB,QACA,aACA,WAC6B;CAC7B,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAAkB,SAAS;EAAS,CAAC;AACvE,KAAI;EACF,MAAM,YAAY,IAAI,8BAA8B,IAAI,IAAI,OAAO,EAAE,EACnE,aAAa,EACX,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,EACF,CAAC;AACF,QAAM,OAAO,QAAQ,UAAU;EAC/B,MAAM,eAAe,OAAO,iBAAiB,IAAI,KAAA;AACjD,YAAU,yBAAyB,cAAc,UAAU,EAAE,QAAQ;AACrE,SAAO;UACA,KAAK;AACZ,YAAU,wCAAwC,OAAO,IAAI,GAAG;AAChE;WACQ;AACR,QAAM,OAAO,OAAO,CAAC,YAAY,KAAA,EAAU;;;AAI/C,eAAsB,gBAAgB,MAIT;CAC3B,MAAM,EAAE,QAAQ,aAAa,cAAc;CAG3C,MAAM,UAAU,gBAAgB,YAAY;AAE5C,KAAI;EAQF,MAAM,oBALM,MADC,WAAW,OAAO,KAAK,IAAI,CACjB,OAIpB,iBAAiB,EACS,iBAAiB,EAC5C,QAAQ;GACN,YAAY,EACV,SAAS;IACP,KAAK;IACL,MAAM;IACN,gBAAgB;IAChB,SAAS,EAAE,cAAc,WAAW;IAEpC,WAAW;IAEX,aAAa,CAAC,OAAO;IACrB,iBAAiB;IAClB,EACF;GAED,UAAU;IAAE,kBAAkB;IAAM,YAAY;IAAW;GAC5D,EACF,CAAC;AACF,YAAU,2CAA2C,SAAS;AAC9D,SAAO;GAAE;GAAkB;GAAS;UAC7B,OAAO;AACd,WAAS;AACT,QAAM"}
@@ -1,7 +1,7 @@
1
- import { o as logToFile } from "./debug-sB20p-Ek.js";
2
- import { f as DEFAULT_AGENT_MODEL, n as analytics, nt as WIZARD_USER_AGENT } from "./analytics-CGGE7OSa.js";
3
- import { d as gatewayAuth } from "./gateway-Dg4Fm-nC.js";
4
- import { f as sanitizeAgentSubprocessEnv, n as buildRunTags, o as createIsolatedAgentConfigDir, t as buildAgentEnv } from "./agent-interface-BFzBnz10.js";
1
+ import { o as logToFile } from "./debug-C3tLP-ZW.js";
2
+ import { f as DEFAULT_AGENT_MODEL, n as analytics, nt as WIZARD_USER_AGENT } from "./analytics-X7JfAmh6.js";
3
+ import { d as gatewayAuth } from "./gateway-IQjQ582o.js";
4
+ import { f as sanitizeAgentSubprocessEnv, n as buildRunTags, o as createIsolatedAgentConfigDir, t as buildAgentEnv } from "./agent-interface-DMP3DZRd.js";
5
5
  //#region src/agent/mcp-prompt-streaming.ts
6
6
  let _sdkModule = null;
7
7
  async function loadSdk() {
@@ -250,4 +250,4 @@ async function* streamMcpPrompt(args) {
250
250
  //#endregion
251
251
  export { streamMcpPrompt };
252
252
 
253
- //# sourceMappingURL=mcp-prompt-streaming-BuRMBgbo.js.map
253
+ //# sourceMappingURL=mcp-prompt-streaming-COs1DfAm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-prompt-streaming-BuRMBgbo.js","names":[],"sources":["../src/agent/mcp-prompt-streaming.ts"],"sourcesContent":["/**\n * Streaming prompt runner for the McpSuggestedPromptsScreen.\n *\n * Calls the Claude Agent SDK's `query()` directly with just the PostHog\n * MCP server configured — no skills, no sandbox, no settings sources,\n * no wizard-tools. This is the lightweight cousin of `runAgent` in\n * `agent-interface.ts`: same SDK, much narrower surface, suitable for\n * \"user asked a question, show the answer\" interactions.\n *\n * The function is an async generator that yields `McpPromptChunk`s extracted\n * from the SDK's message stream. Callers (the screen) consume them via\n * `for await (...)` and render as they arrive.\n */\n\nimport type { Credentials } from '@shared/api';\nimport { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@shared/constants';\nimport { logToFile } from '@utils/debug';\nimport { gatewayAuth } from './gateway-session';\nimport { buildAgentEnv, buildRunTags } from './agent-interface';\nimport { sanitizeAgentSubprocessEnv } from '@shared/agent-env-isolation';\nimport { createIsolatedAgentConfigDir } from './stored-login';\nimport { analytics } from '@utils/analytics';\n\n/**\n * Discriminated union covering every kind of streamed event the screen\n * needs to render. Production yields these from Claude SDK messages;\n * the playground yields them from canned scripts.\n */\nexport type McpPromptChunk =\n | { kind: 'text'; text: string }\n /** `command` carries CLI mode's exec command string (`call <tool> …`) so the\n * screen can recover the inner tool for context-aware follow-ups. */\n | { kind: 'tool-call'; toolName: string; detail: string; command?: string }\n | { kind: 'tool-result'; toolName: string; detail: string }\n | { kind: 'error'; text: string }\n /** Stream completed. `sessionId` is the SDK session ID of the just-\n * completed turn; pass it back as `resumeSessionId` on a follow-up\n * call to continue the conversation with full history. */\n | { kind: 'done'; sessionId?: string };\n\n// Cached SDK module — first call pays the dynamic-import cost; later\n// calls reuse the same module.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _sdkModule: any | null = null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function loadSdk(): Promise<any> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\nconst MODEL = DEFAULT_AGENT_MODEL;\n\n// Bounded turn count so a single prompt can't loop forever on the\n// user's nickel. 20 gives the agent room for non-trivial multi-step\n// chains (multi-tool reads → reason → write → verify → summarize) while\n// still capping runaway loops. Worth tuning down once we see real\n// telemetry on average turn counts per prompt.\nconst MAX_TURNS = 30;\n\n/**\n * Extract a short, single-line summary from an arbitrary value. Used\n * for tool-call args and tool-result bodies so the screen has something\n * compact to render.\n */\nfunction summarize(value: unknown, maxLen = 120): string {\n if (value == null) return '';\n let text: string;\n if (typeof value === 'string') text = value;\n else {\n try {\n text = JSON.stringify(value);\n } catch {\n text = String(value);\n }\n }\n text = text.replace(/\\s+/g, ' ').trim();\n if (text.length > maxLen) text = text.slice(0, maxLen - 1) + '…';\n return text;\n}\n\n/**\n * Convert one SDK message into zero or more AgentChunks. Mirrors the\n * subset of message shapes the wizard's main runAgent middleware\n * handles, but narrowed to just the kinds the screen needs to render.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction messageToChunks(message: any): McpPromptChunk[] {\n const chunks: McpPromptChunk[] = [];\n\n if (message?.type === 'assistant') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n if (text) chunks.push({ kind: 'text', text });\n } else if (type === 'tool_use') {\n const name = (block as { name?: string }).name ?? 'tool';\n const input = (block as { input?: unknown }).input;\n // CLI mode's exec tool takes a `command` string; keep it verbatim so\n // the screen can recover the inner tool name for follow-ups.\n const command = (input as { command?: unknown })?.command;\n chunks.push({\n kind: 'tool-call',\n toolName: name,\n detail: summarize(input),\n command: typeof command === 'string' ? command : undefined,\n });\n }\n }\n }\n }\n\n if (message?.type === 'user') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'tool_result') {\n const detail = summarize((block as { content?: unknown }).content);\n chunks.push({ kind: 'tool-result', toolName: 'tool', detail });\n }\n }\n }\n }\n\n if (message?.type === 'result') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const sessionId = (message as { session_id?: string }).session_id;\n chunks.push({ kind: 'done', sessionId });\n }\n\n return chunks;\n}\n\n/**\n * Build a system-prompt append that nudges the agent to fit its response\n * inside the current terminal window. We can't actually constrain Claude\n * — this is a soft cap that the model usually honors. The screen also\n * applies a hard truncation cap as a fallback for non-compliant runs.\n *\n * Core principle nudged at the model: TALL CONTENT IS BAD, WIDE CONTENT\n * IS GOOD. Default terminal is 120 columns × 24 rows — that's a lot of\n * horizontal space, not much vertical. Spread data across columns, never\n * stack it down rows when a horizontal layout would work.\n */\nfunction buildTerminalFitPrompt(): string {\n const cols = process.stdout.columns ?? 120;\n const rows = process.stdout.rows ?? 24;\n // Reserve rows for wizard chrome (title, status, hint, margins).\n const messageBudget = Math.max(8, rows - 10);\n\n return [\n `You are responding inside a CLI window that is exactly ${cols} columns wide and ${rows} rows tall. The user CAN'T SCROLL — your entire reply must fit on screen.`,\n ``,\n `LAYOUT PRINCIPLE: tall content is the enemy, wide content is your friend. You have ${cols} columns of horizontal space; use them. Spread data across columns instead of stacking it down rows.`,\n ``,\n `Tables:`,\n `- Max 5 body rows. The prompts the user picks already constrain results to 5 or fewer — honor that and do not pad with extra rows.`,\n `- If a tool result returns more than 5 items, show the top 5 and mention the rest count inline (e.g. \"...and 12 more\").`,\n `- Prefer transposing wide-but-short data (items across columns, metrics down rows) when labels are short.`,\n `- A two-column table with many rows is the tall layout to AVOID.`,\n ``,\n `Other limits:`,\n `- Aim for 3-5 lines of prose. Maximum ${messageBudget} lines total.`,\n `- DO NOT announce what you are about to do. Skip preamble like \"I'll query…\", \"Let me check…\", \"Now I'll…\", \"I'm going to…\". Go straight to running tools and then the answer.`,\n `- Lists: if there are 6+ short items, format them inline (comma-separated), not as a vertical bullet list.`,\n `- For tool results, summarize the 1-3 numbers that matter. Do NOT echo raw JSON or the full payload.`,\n `- Code blocks: no language tag, no leading blank lines.`,\n `- No closing pleasantries (\"let me know if…\", \"feel free to…\"). Stop when the answer is delivered.`,\n `- No section headers unless the response actually has multiple sections.`,\n ``,\n `Naming saved artifacts:`,\n `- Every dashboard, insight, notebook, or annotation you create MUST include \"(wizard MCP tutorial)\" at the end of its title or name field. Examples: \"Weekly signups (wizard MCP tutorial)\", \"Top errors this week (wizard MCP tutorial)\", \"Onboarding analysis (wizard MCP tutorial)\".`,\n `- This applies on both create AND rename calls. If the user asks you to rename a saved artifact, preserve the \"(wizard MCP tutorial)\" suffix unless they explicitly ask you to drop it.`,\n `- Reason: lets the user find / clean up everything this tutorial created from one search in PostHog. Don't skip it — it's the only signal they'll have that an artifact came from the wizard.`,\n ``,\n `Tone & framing:`,\n `- This is a tutorial demoing PostHog (the product the user just installed). You are showing it off, not auditing it. Stay constructive and neutral about PostHog throughout.`,\n `- Don't editorialize about PostHog's reliability, performance, or cost. Describe what the data shows; treat anomalies as the user's data, not a platform issue.`,\n `- If a tool call fails or returns nothing, say \"the query didn't return data — try a different angle\" or similar. Do NOT speculate about outages, gateway issues, MCP problems, or service health.`,\n `- Avoid value-laden phrases like \"worth investigating\", \"concerning\", \"red flag\", \"problematic\", \"suspicious\", \"alarming\" when describing the user's metrics. Stick to what the numbers show; the user draws conclusions.`,\n ].join('\\n');\n}\n\n/**\n * Gateway trace tags for a tutorial prompt run — without them the gateway has\n * nothing to attribute its `$ai_generation` events to. Returns `{}` when no\n * program is supplied. Exported so the contract is testable without the SDK.\n */\nexport function buildTutorialRunTags(args: {\n programId?: string;\n integration?: string;\n}): Record<string, string> {\n if (!args.programId) return {};\n return buildRunTags({\n programId: args.programId,\n // The tutorial usually has no detected framework; fall back to the\n // program so the axis is never an empty string.\n integration: args.integration ?? args.programId,\n runId: analytics.runId,\n build: analytics.build,\n });\n}\n\nexport async function* streamMcpPrompt(args: {\n prompt: string;\n credentials: Credentials;\n signal: AbortSignal;\n /** When set, the SDK loads the named session's prior turns as\n * context so the follow-up prompt can reference what the agent\n * already showed. */\n resumeSessionId?: string;\n /** Program this run's gateway spend attributes to. Omitting it fails the run\n * rather than going unattributed, so every caller must supply one. */\n programId?: string;\n /** Integration label for the trace tags; the tutorial usually has none. */\n integration?: string;\n}): AsyncIterable<McpPromptChunk> {\n const { prompt, credentials, signal, resumeSessionId } = args;\n\n // Assembled here rather than passed in so the TUI service layer doesn't\n // have to import this module's dependencies.\n const wizardMetadata = buildTutorialRunTags(args);\n\n // Route the SDK's LLM calls through the PostHog AI gateway, authed\n // with the run's minted token. Set BEFORE loading the SDK in\n // case any in-process code reads env at module init (cached base\n // URLs, OAuth setup, etc.) — same reason `initializeAgent` does this\n // before its query() call. Without these the SDK tries to\n // authenticate directly against Anthropic and 401s with \"Invalid\n // authentication credentials\".\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n\n // The url and the bearer are one unit: a run must take both from the same\n // mint.\n const auth = await gatewayAuth(\n credentials.host,\n credentials.accessToken,\n args.programId,\n );\n const gatewayUrl = auth.gatewayUrl;\n process.env.ANTHROPIC_BASE_URL = gatewayUrl;\n process.env.ANTHROPIC_AUTH_TOKEN = auth.token;\n process.env.CLAUDE_CODE_OAUTH_TOKEN = auth.token;\n\n logToFile(\n `[streamMcpPrompt] gatewayUrl=${gatewayUrl} tokenPrefix=${\n auth.token ? auth.token.slice(0, 4) + '***' : '(missing)'\n }`,\n );\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { query } = await loadSdk();\n\n // Bridge external AbortSignal → SDK AbortController.\n const abortController = new AbortController();\n if (signal.aborted) abortController.abort();\n else\n signal.addEventListener('abort', () => abortController.abort(), {\n once: true,\n });\n\n const mcpUrl = credentials.host.mcpUrl;\n logToFile(\n `[streamMcpPrompt] mcpUrl=${mcpUrl} model=${MODEL} resume=${\n resumeSessionId ?? '(none)'\n }`,\n );\n\n // The SDK expects an async generator for the prompt that stays open\n // until the result is received. For a single-turn prompt we yield one\n // user message and then await an abort (which fires when streaming\n // completes or the caller cancels).\n const createPromptStream = async function* () {\n yield {\n type: 'user' as const,\n session_id: '',\n message: { role: 'user' as const, content: prompt },\n parent_tool_use_id: null,\n };\n // Hold the stream open until abort. The SDK closes its end when it\n // sees a `result` message; we close ours via the abortController in\n // the finally block below.\n await new Promise<void>((resolve) => {\n if (abortController.signal.aborted) {\n resolve();\n return;\n }\n abortController.signal.addEventListener('abort', () => resolve(), {\n once: true,\n });\n });\n };\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n const response = query({\n prompt: createPromptStream(),\n options: {\n abortController,\n model: MODEL,\n cwd: process.cwd(),\n permissionMode: 'acceptEdits',\n maxTurns: MAX_TURNS,\n // Match agent-interface.ts — the 1M context beta is what keeps\n // resumed follow-up sessions from truncating after a few turns.\n betas: ['context-1m-2025-08-07'],\n // Only load project-level skills/settings. Without this the SDK\n // defaults to ['user', 'project'] and a user's\n // `~/.claude/settings.json` (apiKeyHelper / env block) can\n // override the OAuth routing we set above.\n settingSources: ['project'],\n // Repo hooks would run as the developer outside the MCP-only gate.\n settings: { disableAllHooks: true },\n // When set, the SDK replays the named session's turns into the\n // new query so the follow-up prompt has full conversation\n // context. Omit on the first prompt for a fresh session.\n ...(resumeSessionId ? { resume: resumeSessionId } : {}),\n // Without `canUseTool` the SDK falls back to \"ask the user\" on\n // every MCP tool call — `permissionMode: 'acceptEdits'` only\n // relaxes Edit/Write, not MCP. Our Ink TUI has no surface to\n // answer that prompt, so the agent would stall mid-stream\n // saying things like \"needs your approval to create dashboard\".\n // The tutorial's whole point is demoing the MCP tools against\n // the user's project, so we auto-allow everything that matches\n // the prefix and deny anything else (defense in depth — the\n // `allowedTools` filter above already enforces this).\n canUseTool: (toolName: string, input: unknown) => {\n if (toolName.startsWith('mcp__posthog-wizard__')) {\n return Promise.resolve({\n behavior: 'allow' as const,\n updatedInput: (input ?? {}) as Record<string, unknown>,\n });\n }\n logToFile(`[streamMcpPrompt] denying non-MCP tool: ${toolName}`);\n return Promise.resolve({\n behavior: 'deny' as const,\n message: `${toolName} is not available in the MCP tutorial — only PostHog MCP tools are permitted.`,\n });\n },\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: buildTerminalFitPrompt(),\n },\n mcpServers: {\n 'posthog-wizard': {\n type: 'http',\n url: mcpUrl,\n headers: {\n // Env reference, not the token: the SDK puts this config on the\n // spawned CLI's argv, where `ps` shows it to any local process.\n Authorization: 'Bearer ${POSTHOG_MCP_TOKEN}',\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // CLI mode's single `exec` tool carries the full command reference\n // on its schema — keep it in context, never deferred behind tool\n // search.\n alwaysLoad: true,\n },\n },\n // Only let the agent use MCP tools — no shell, no file I/O,\n // no Read/Edit/Write. This is a chat-with-MCP run, not a\n // wizard skill execution.\n allowedTools: ['mcp__posthog-wizard__*'],\n env: {\n // Drop the ENTIRE ANTHROPIC_*/CLAUDE_CODE_* namespace from the\n // inherited env so no shell/settings value can silently bypass the\n // PostHog gateway and defeat quota tracking / the OAuth flow; the\n // wizard's own gateway routing is injected fresh below. See\n // agent-env-isolation.ts.\n ...sanitizeAgentSubprocessEnv(process.env),\n // Gateway routing from this run's own auth, not process.env: a\n // concurrent run writes those globals too, and there is an await\n // between the write above and this read.\n ANTHROPIC_BASE_URL: auth.gatewayUrl,\n ANTHROPIC_AUTH_TOKEN: auth.token,\n CLAUDE_CODE_OAUTH_TOKEN: auth.token,\n // Point the binary at an empty config dir so it cannot resolve a\n // stored Claude login and send that to the gateway, which 401s it.\n // See stored-login.ts.\n CLAUDE_CONFIG_DIR: createIsolatedAgentConfigDir(),\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // The MCP config resolves this in the child; sending the value would\n // put it on the CLI's argv.\n POSTHOG_MCP_TOKEN: credentials.accessToken,\n // SDK 0.3.142+ connects MCP servers in the background by\n // default; without this the agent may try to call tools\n // before posthog-wizard is connected on turn 1.\n MCP_CONNECTION_NONBLOCKING: '0',\n // This run's trace tags, which the gateway reads to attribute its\n // `$ai_generation` events. Flags stay empty: the tutorial doesn't\n // fork on any.\n ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(\n wizardMetadata ?? {},\n {},\n auth.teamId,\n ),\n },\n },\n });\n\n for await (const message of response as AsyncIterable<unknown>) {\n if (signal.aborted) return;\n for (const chunk of messageToChunks(message)) {\n yield chunk;\n if (chunk.kind === 'done') return;\n }\n }\n } catch (err) {\n const text = err instanceof Error ? err.message : String(err);\n logToFile(`[streamMcpPrompt] error: ${text}`);\n yield { kind: 'error', text };\n } finally {\n // Closes the prompt stream so `query()` shuts down cleanly even if\n // we never saw a 'result' message.\n abortController.abort();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-prompt-streaming-COs1DfAm.js","names":[],"sources":["../src/agent/mcp-prompt-streaming.ts"],"sourcesContent":["/**\n * Streaming prompt runner for the McpSuggestedPromptsScreen.\n *\n * Calls the Claude Agent SDK's `query()` directly with just the PostHog\n * MCP server configured — no skills, no sandbox, no settings sources,\n * no wizard-tools. This is the lightweight cousin of `runAgent` in\n * `agent-interface.ts`: same SDK, much narrower surface, suitable for\n * \"user asked a question, show the answer\" interactions.\n *\n * The function is an async generator that yields `McpPromptChunk`s extracted\n * from the SDK's message stream. Callers (the screen) consume them via\n * `for await (...)` and render as they arrive.\n */\n\nimport type { Credentials } from '@shared/api';\nimport { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@shared/constants';\nimport { logToFile } from '@utils/debug';\nimport { gatewayAuth } from './gateway-session';\nimport { buildAgentEnv, buildRunTags } from './agent-interface';\nimport { sanitizeAgentSubprocessEnv } from '@shared/agent-env-isolation';\nimport { createIsolatedAgentConfigDir } from './stored-login';\nimport { analytics } from '@utils/analytics';\n\n/**\n * Discriminated union covering every kind of streamed event the screen\n * needs to render. Production yields these from Claude SDK messages;\n * the playground yields them from canned scripts.\n */\nexport type McpPromptChunk =\n | { kind: 'text'; text: string }\n /** `command` carries CLI mode's exec command string (`call <tool> …`) so the\n * screen can recover the inner tool for context-aware follow-ups. */\n | { kind: 'tool-call'; toolName: string; detail: string; command?: string }\n | { kind: 'tool-result'; toolName: string; detail: string }\n | { kind: 'error'; text: string }\n /** Stream completed. `sessionId` is the SDK session ID of the just-\n * completed turn; pass it back as `resumeSessionId` on a follow-up\n * call to continue the conversation with full history. */\n | { kind: 'done'; sessionId?: string };\n\n// Cached SDK module — first call pays the dynamic-import cost; later\n// calls reuse the same module.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _sdkModule: any | null = null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function loadSdk(): Promise<any> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\nconst MODEL = DEFAULT_AGENT_MODEL;\n\n// Bounded turn count so a single prompt can't loop forever on the\n// user's nickel. 20 gives the agent room for non-trivial multi-step\n// chains (multi-tool reads → reason → write → verify → summarize) while\n// still capping runaway loops. Worth tuning down once we see real\n// telemetry on average turn counts per prompt.\nconst MAX_TURNS = 30;\n\n/**\n * Extract a short, single-line summary from an arbitrary value. Used\n * for tool-call args and tool-result bodies so the screen has something\n * compact to render.\n */\nfunction summarize(value: unknown, maxLen = 120): string {\n if (value == null) return '';\n let text: string;\n if (typeof value === 'string') text = value;\n else {\n try {\n text = JSON.stringify(value);\n } catch {\n text = String(value);\n }\n }\n text = text.replace(/\\s+/g, ' ').trim();\n if (text.length > maxLen) text = text.slice(0, maxLen - 1) + '…';\n return text;\n}\n\n/**\n * Convert one SDK message into zero or more AgentChunks. Mirrors the\n * subset of message shapes the wizard's main runAgent middleware\n * handles, but narrowed to just the kinds the screen needs to render.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction messageToChunks(message: any): McpPromptChunk[] {\n const chunks: McpPromptChunk[] = [];\n\n if (message?.type === 'assistant') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'text') {\n const text = (block as { text?: string }).text ?? '';\n if (text) chunks.push({ kind: 'text', text });\n } else if (type === 'tool_use') {\n const name = (block as { name?: string }).name ?? 'tool';\n const input = (block as { input?: unknown }).input;\n // CLI mode's exec tool takes a `command` string; keep it verbatim so\n // the screen can recover the inner tool name for follow-ups.\n const command = (input as { command?: unknown })?.command;\n chunks.push({\n kind: 'tool-call',\n toolName: name,\n detail: summarize(input),\n command: typeof command === 'string' ? command : undefined,\n });\n }\n }\n }\n }\n\n if (message?.type === 'user') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== 'object') continue;\n const type = (block as { type?: string }).type;\n if (type === 'tool_result') {\n const detail = summarize((block as { content?: unknown }).content);\n chunks.push({ kind: 'tool-result', toolName: 'tool', detail });\n }\n }\n }\n }\n\n if (message?.type === 'result') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const sessionId = (message as { session_id?: string }).session_id;\n chunks.push({ kind: 'done', sessionId });\n }\n\n return chunks;\n}\n\n/**\n * Build a system-prompt append that nudges the agent to fit its response\n * inside the current terminal window. We can't actually constrain Claude\n * — this is a soft cap that the model usually honors. The screen also\n * applies a hard truncation cap as a fallback for non-compliant runs.\n *\n * Core principle nudged at the model: TALL CONTENT IS BAD, WIDE CONTENT\n * IS GOOD. Default terminal is 120 columns × 24 rows — that's a lot of\n * horizontal space, not much vertical. Spread data across columns, never\n * stack it down rows when a horizontal layout would work.\n */\nfunction buildTerminalFitPrompt(): string {\n const cols = process.stdout.columns ?? 120;\n const rows = process.stdout.rows ?? 24;\n // Reserve rows for wizard chrome (title, status, hint, margins).\n const messageBudget = Math.max(8, rows - 10);\n\n return [\n `You are responding inside a CLI window that is exactly ${cols} columns wide and ${rows} rows tall. The user CAN'T SCROLL — your entire reply must fit on screen.`,\n ``,\n `LAYOUT PRINCIPLE: tall content is the enemy, wide content is your friend. You have ${cols} columns of horizontal space; use them. Spread data across columns instead of stacking it down rows.`,\n ``,\n `Tables:`,\n `- Max 5 body rows. The prompts the user picks already constrain results to 5 or fewer — honor that and do not pad with extra rows.`,\n `- If a tool result returns more than 5 items, show the top 5 and mention the rest count inline (e.g. \"...and 12 more\").`,\n `- Prefer transposing wide-but-short data (items across columns, metrics down rows) when labels are short.`,\n `- A two-column table with many rows is the tall layout to AVOID.`,\n ``,\n `Other limits:`,\n `- Aim for 3-5 lines of prose. Maximum ${messageBudget} lines total.`,\n `- DO NOT announce what you are about to do. Skip preamble like \"I'll query…\", \"Let me check…\", \"Now I'll…\", \"I'm going to…\". Go straight to running tools and then the answer.`,\n `- Lists: if there are 6+ short items, format them inline (comma-separated), not as a vertical bullet list.`,\n `- For tool results, summarize the 1-3 numbers that matter. Do NOT echo raw JSON or the full payload.`,\n `- Code blocks: no language tag, no leading blank lines.`,\n `- No closing pleasantries (\"let me know if…\", \"feel free to…\"). Stop when the answer is delivered.`,\n `- No section headers unless the response actually has multiple sections.`,\n ``,\n `Naming saved artifacts:`,\n `- Every dashboard, insight, notebook, or annotation you create MUST include \"(wizard MCP tutorial)\" at the end of its title or name field. Examples: \"Weekly signups (wizard MCP tutorial)\", \"Top errors this week (wizard MCP tutorial)\", \"Onboarding analysis (wizard MCP tutorial)\".`,\n `- This applies on both create AND rename calls. If the user asks you to rename a saved artifact, preserve the \"(wizard MCP tutorial)\" suffix unless they explicitly ask you to drop it.`,\n `- Reason: lets the user find / clean up everything this tutorial created from one search in PostHog. Don't skip it — it's the only signal they'll have that an artifact came from the wizard.`,\n ``,\n `Tone & framing:`,\n `- This is a tutorial demoing PostHog (the product the user just installed). You are showing it off, not auditing it. Stay constructive and neutral about PostHog throughout.`,\n `- Don't editorialize about PostHog's reliability, performance, or cost. Describe what the data shows; treat anomalies as the user's data, not a platform issue.`,\n `- If a tool call fails or returns nothing, say \"the query didn't return data — try a different angle\" or similar. Do NOT speculate about outages, gateway issues, MCP problems, or service health.`,\n `- Avoid value-laden phrases like \"worth investigating\", \"concerning\", \"red flag\", \"problematic\", \"suspicious\", \"alarming\" when describing the user's metrics. Stick to what the numbers show; the user draws conclusions.`,\n ].join('\\n');\n}\n\n/**\n * Gateway trace tags for a tutorial prompt run — without them the gateway has\n * nothing to attribute its `$ai_generation` events to. Returns `{}` when no\n * program is supplied. Exported so the contract is testable without the SDK.\n */\nexport function buildTutorialRunTags(args: {\n programId?: string;\n integration?: string;\n}): Record<string, string> {\n if (!args.programId) return {};\n return buildRunTags({\n programId: args.programId,\n // The tutorial usually has no detected framework; fall back to the\n // program so the axis is never an empty string.\n integration: args.integration ?? args.programId,\n runId: analytics.runId,\n build: analytics.build,\n });\n}\n\nexport async function* streamMcpPrompt(args: {\n prompt: string;\n credentials: Credentials;\n signal: AbortSignal;\n /** When set, the SDK loads the named session's prior turns as\n * context so the follow-up prompt can reference what the agent\n * already showed. */\n resumeSessionId?: string;\n /** Program this run's gateway spend attributes to. Omitting it fails the run\n * rather than going unattributed, so every caller must supply one. */\n programId?: string;\n /** Integration label for the trace tags; the tutorial usually has none. */\n integration?: string;\n}): AsyncIterable<McpPromptChunk> {\n const { prompt, credentials, signal, resumeSessionId } = args;\n\n // Assembled here rather than passed in so the TUI service layer doesn't\n // have to import this module's dependencies.\n const wizardMetadata = buildTutorialRunTags(args);\n\n // Route the SDK's LLM calls through the PostHog AI gateway, authed\n // with the run's minted token. Set BEFORE loading the SDK in\n // case any in-process code reads env at module init (cached base\n // URLs, OAuth setup, etc.) — same reason `initializeAgent` does this\n // before its query() call. Without these the SDK tries to\n // authenticate directly against Anthropic and 401s with \"Invalid\n // authentication credentials\".\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n\n // The url and the bearer are one unit: a run must take both from the same\n // mint.\n const auth = await gatewayAuth(\n credentials.host,\n credentials.accessToken,\n args.programId,\n );\n const gatewayUrl = auth.gatewayUrl;\n process.env.ANTHROPIC_BASE_URL = gatewayUrl;\n process.env.ANTHROPIC_AUTH_TOKEN = auth.token;\n process.env.CLAUDE_CODE_OAUTH_TOKEN = auth.token;\n\n logToFile(\n `[streamMcpPrompt] gatewayUrl=${gatewayUrl} tokenPrefix=${\n auth.token ? auth.token.slice(0, 4) + '***' : '(missing)'\n }`,\n );\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { query } = await loadSdk();\n\n // Bridge external AbortSignal → SDK AbortController.\n const abortController = new AbortController();\n if (signal.aborted) abortController.abort();\n else\n signal.addEventListener('abort', () => abortController.abort(), {\n once: true,\n });\n\n const mcpUrl = credentials.host.mcpUrl;\n logToFile(\n `[streamMcpPrompt] mcpUrl=${mcpUrl} model=${MODEL} resume=${\n resumeSessionId ?? '(none)'\n }`,\n );\n\n // The SDK expects an async generator for the prompt that stays open\n // until the result is received. For a single-turn prompt we yield one\n // user message and then await an abort (which fires when streaming\n // completes or the caller cancels).\n const createPromptStream = async function* () {\n yield {\n type: 'user' as const,\n session_id: '',\n message: { role: 'user' as const, content: prompt },\n parent_tool_use_id: null,\n };\n // Hold the stream open until abort. The SDK closes its end when it\n // sees a `result` message; we close ours via the abortController in\n // the finally block below.\n await new Promise<void>((resolve) => {\n if (abortController.signal.aborted) {\n resolve();\n return;\n }\n abortController.signal.addEventListener('abort', () => resolve(), {\n once: true,\n });\n });\n };\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n const response = query({\n prompt: createPromptStream(),\n options: {\n abortController,\n model: MODEL,\n cwd: process.cwd(),\n permissionMode: 'acceptEdits',\n maxTurns: MAX_TURNS,\n // Match agent-interface.ts — the 1M context beta is what keeps\n // resumed follow-up sessions from truncating after a few turns.\n betas: ['context-1m-2025-08-07'],\n // Only load project-level skills/settings. Without this the SDK\n // defaults to ['user', 'project'] and a user's\n // `~/.claude/settings.json` (apiKeyHelper / env block) can\n // override the OAuth routing we set above.\n settingSources: ['project'],\n // Repo hooks would run as the developer outside the MCP-only gate.\n settings: { disableAllHooks: true },\n // When set, the SDK replays the named session's turns into the\n // new query so the follow-up prompt has full conversation\n // context. Omit on the first prompt for a fresh session.\n ...(resumeSessionId ? { resume: resumeSessionId } : {}),\n // Without `canUseTool` the SDK falls back to \"ask the user\" on\n // every MCP tool call — `permissionMode: 'acceptEdits'` only\n // relaxes Edit/Write, not MCP. Our Ink TUI has no surface to\n // answer that prompt, so the agent would stall mid-stream\n // saying things like \"needs your approval to create dashboard\".\n // The tutorial's whole point is demoing the MCP tools against\n // the user's project, so we auto-allow everything that matches\n // the prefix and deny anything else (defense in depth — the\n // `allowedTools` filter above already enforces this).\n canUseTool: (toolName: string, input: unknown) => {\n if (toolName.startsWith('mcp__posthog-wizard__')) {\n return Promise.resolve({\n behavior: 'allow' as const,\n updatedInput: (input ?? {}) as Record<string, unknown>,\n });\n }\n logToFile(`[streamMcpPrompt] denying non-MCP tool: ${toolName}`);\n return Promise.resolve({\n behavior: 'deny' as const,\n message: `${toolName} is not available in the MCP tutorial — only PostHog MCP tools are permitted.`,\n });\n },\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: buildTerminalFitPrompt(),\n },\n mcpServers: {\n 'posthog-wizard': {\n type: 'http',\n url: mcpUrl,\n headers: {\n // Env reference, not the token: the SDK puts this config on the\n // spawned CLI's argv, where `ps` shows it to any local process.\n Authorization: 'Bearer ${POSTHOG_MCP_TOKEN}',\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // CLI mode's single `exec` tool carries the full command reference\n // on its schema — keep it in context, never deferred behind tool\n // search.\n alwaysLoad: true,\n },\n },\n // Only let the agent use MCP tools — no shell, no file I/O,\n // no Read/Edit/Write. This is a chat-with-MCP run, not a\n // wizard skill execution.\n allowedTools: ['mcp__posthog-wizard__*'],\n env: {\n // Drop the ENTIRE ANTHROPIC_*/CLAUDE_CODE_* namespace from the\n // inherited env so no shell/settings value can silently bypass the\n // PostHog gateway and defeat quota tracking / the OAuth flow; the\n // wizard's own gateway routing is injected fresh below. See\n // agent-env-isolation.ts.\n ...sanitizeAgentSubprocessEnv(process.env),\n // Gateway routing from this run's own auth, not process.env: a\n // concurrent run writes those globals too, and there is an await\n // between the write above and this read.\n ANTHROPIC_BASE_URL: auth.gatewayUrl,\n ANTHROPIC_AUTH_TOKEN: auth.token,\n CLAUDE_CODE_OAUTH_TOKEN: auth.token,\n // Point the binary at an empty config dir so it cannot resolve a\n // stored Claude login and send that to the gateway, which 401s it.\n // See stored-login.ts.\n CLAUDE_CONFIG_DIR: createIsolatedAgentConfigDir(),\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // The MCP config resolves this in the child; sending the value would\n // put it on the CLI's argv.\n POSTHOG_MCP_TOKEN: credentials.accessToken,\n // SDK 0.3.142+ connects MCP servers in the background by\n // default; without this the agent may try to call tools\n // before posthog-wizard is connected on turn 1.\n MCP_CONNECTION_NONBLOCKING: '0',\n // This run's trace tags, which the gateway reads to attribute its\n // `$ai_generation` events. Flags stay empty: the tutorial doesn't\n // fork on any.\n ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(\n wizardMetadata ?? {},\n {},\n auth.teamId,\n ),\n },\n },\n });\n\n for await (const message of response as AsyncIterable<unknown>) {\n if (signal.aborted) return;\n for (const chunk of messageToChunks(message)) {\n yield chunk;\n if (chunk.kind === 'done') return;\n }\n }\n } catch (err) {\n const text = err instanceof Error ? err.message : String(err);\n logToFile(`[streamMcpPrompt] error: ${text}`);\n yield { kind: 'error', text };\n } finally {\n // Closes the prompt stream so `query()` shuts down cleanly even if\n // we never saw a 'result' message.\n abortController.abort();\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { C as HAIKU_MODEL, H as SONNET_5_MODEL, S as GPT5_6_TERRA_MODEL, b as GPT5_6_LUNA_MODEL, w as HAIKU_TRIAGE_MODEL, x as GPT5_6_SOL_MODEL } from "./analytics-CGGE7OSa.js";
1
+ import { C as HAIKU_MODEL, H as SONNET_5_MODEL, S as GPT5_6_TERRA_MODEL, b as GPT5_6_LUNA_MODEL, w as HAIKU_TRIAGE_MODEL, x as GPT5_6_SOL_MODEL } from "./analytics-X7JfAmh6.js";
2
2
  //#region src/agent/runner/switchboard/models.ts
3
3
  /** Reasoning effort, mapped by each harness to its provider transport. */
4
4
  const THINKING_LEVELS = [
@@ -80,4 +80,4 @@ function modelCapabilities(modelId, effortOverride) {
80
80
  //#endregion
81
81
  export { requireKnownModel as a, modelCapabilities as i, isThinkingLevel as n, triageModelFor as o, isValidModel as r, VALID_MODELS as t };
82
82
 
83
- //# sourceMappingURL=models-G1j-wgwe.js.map
83
+ //# sourceMappingURL=models-Cow22jET.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models-G1j-wgwe.js","names":[],"sources":["../src/agent/runner/switchboard/models.ts"],"sourcesContent":["// Local capabilities inform transport parameters; gateway policy independently admits models and efforts.\nimport {\n SONNET_5_MODEL,\n HAIKU_MODEL,\n GPT5_6_LUNA_MODEL,\n GPT5_6_SOL_MODEL,\n GPT5_6_TERRA_MODEL,\n HAIKU_TRIAGE_MODEL,\n Harness,\n} from '@shared/constants';\n\n/** Reasoning effort, mapped by each harness to its provider transport. */\nconst THINKING_LEVELS = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n] as const;\nexport type ThinkingLevel = (typeof THINKING_LEVELS)[number];\n\n/** Whether a value (e.g. remote prompt frontmatter) names a valid effort. */\nexport function isThinkingLevel(value: unknown): value is ThinkingLevel {\n return (THINKING_LEVELS as readonly unknown[]).includes(value);\n}\n\n/**\n * An effort *override* is always a positive level — `'off'` is a model trait\n * (`reasoning: false`), not something a flag may force onto a reasoning model.\n */\nexport type EffortLevel = Exclude<ThinkingLevel, 'off'>;\n\nexport interface ModelCapabilities {\n /** Model supports reasoning; safe to request reasoning effort. */\n reasoning: boolean;\n /** Effort to request when reasoning. Omit for the harness/provider default. */\n thinkingLevel?: ThinkingLevel;\n}\n\n/**\n * Explicit per-model traits. Anything absent falls back to `defaultCaps`.\n *\n * A reasoning model without a `thinkingLevel` leaves the effort to the harness,\n * and the mint pins effort per model (posthog `WIZARD_MODEL_ALLOWLIST`), so an\n * unpinned reasoning model is refused with no tool calls. Every level below is\n * one the mint allows for that model.\n */\nexport const MODEL_CAPABILITIES: Record<string, ModelCapabilities> = {\n // The mint takes sonnet 5 at `none` or `high`; high is the only level it\n // serves once reasoning is on.\n [SONNET_5_MODEL]: { reasoning: true, thinkingLevel: 'high' },\n // The mint takes haiku with no effort parameter at all, which is `off`.\n [HAIKU_MODEL]: { reasoning: true, thinkingLevel: 'off' },\n // The openai 5.6 line; all reasoning models, so they must opt in past the\n // openai-completions default (reasoning off). Luna stays low for cheap,\n // short-context mechanical work; terra runs medium as the sonnet-tier parallel\n // — enough reasoning depth for the judgment tasks without high's latency blowup.\n [GPT5_6_LUNA_MODEL]: { reasoning: true, thinkingLevel: 'low' },\n [GPT5_6_TERRA_MODEL]: { reasoning: true, thinkingLevel: 'medium' },\n [GPT5_6_SOL_MODEL]: { reasoning: true, thinkingLevel: 'medium' },\n};\n\n/**\n * The mint's per-model effort pin, mirrored from posthog\n * `WIZARD_MODEL_ALLOWLIST`. `'off'` is the CLI's spelling of the mint's\n * `\"none\"` — a call carrying no effort parameter.\n */\nexport const MINT_ALLOWED_EFFORTS: Record<string, readonly ThinkingLevel[]> = {\n [SONNET_5_MODEL]: ['off', 'high'],\n [HAIKU_MODEL]: ['off'],\n [GPT5_6_LUNA_MODEL]: ['low'],\n [GPT5_6_SOL_MODEL]: ['medium'],\n [GPT5_6_TERRA_MODEL]: ['low', 'medium', 'high'],\n};\n\n// Local model choices; gateway admission also requires allowed models, efforts, and prompt compatibility.\nexport const VALID_MODELS: ReadonlySet<string> = new Set(\n Object.keys(MODEL_CAPABILITIES),\n);\n\n/** Whether the value is an allow-listed model. */\nexport function isValidModel(model: unknown): model is string {\n return typeof model === 'string' && VALID_MODELS.has(model);\n}\n\n/** First allow-listed candidate, else throw so a bad id fails loud. */\nexport function requireKnownModel(\n ...candidates: (string | undefined)[]\n): string {\n for (const c of candidates) if (isValidModel(c)) return c;\n throw new Error(\n `No valid model to dispatch on (tried ${JSON.stringify(candidates)}). ` +\n `Allowed: ${[...VALID_MODELS].join(', ')}.`,\n );\n}\n\n// Unknown Anthropic models default to reasoning; OpenAI models must opt in through the local table.\nfunction defaultCaps(modelId: string): ModelCapabilities {\n return { reasoning: !modelId.startsWith('openai/') };\n}\n\n// Triage requests must satisfy gateway safety policy and preserve Warlock’s classifier format.\nexport const TRIAGE_MODELS: Record<Harness, string> = {\n [Harness.anthropic]: HAIKU_TRIAGE_MODEL,\n [Harness.pi]: GPT5_6_LUNA_MODEL,\n};\n\nexport function triageModelFor(harness: Harness): string {\n return TRIAGE_MODELS[harness];\n}\n\n/**\n * Capabilities for a gateway model id, table override then transport default.\n * `effortOverride` is a switchboard-resolved effort (e.g. from a pi effort\n * flag); it applies only when the model reasons at all — a non-reasoning model\n * rejects reasoning effort, so the override is dropped.\n */\nexport function modelCapabilities(\n modelId: string,\n effortOverride?: EffortLevel,\n): ModelCapabilities {\n const caps = MODEL_CAPABILITIES[modelId] ?? defaultCaps(modelId);\n if (caps.reasoning && effortOverride) {\n return { ...caps, thinkingLevel: effortOverride };\n }\n return caps;\n}\n"],"mappings":";;;AAYA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACD;;AAID,SAAgB,gBAAgB,OAAwC;AACtE,QAAQ,gBAAuC,SAAS,MAAM;;;;;;;;;;AAwBhE,MAAa,qBAAwD;EAGlE,iBAAiB;EAAE,WAAW;EAAM,eAAe;EAAQ;EAE3D,cAAc;EAAE,WAAW;EAAM,eAAe;EAAO;EAKvD,oBAAoB;EAAE,WAAW;EAAM,eAAe;EAAO;EAC7D,qBAAqB;EAAE,WAAW;EAAM,eAAe;EAAU;EACjE,mBAAmB;EAAE,WAAW;EAAM,eAAe;EAAU;CACjE;AAgBD,MAAa,eAAoC,IAAI,IACnD,OAAO,KAAK,mBAAmB,CAChC;;AAGD,SAAgB,aAAa,OAAiC;AAC5D,QAAO,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM;;;AAI7D,SAAgB,kBACd,GAAG,YACK;AACR,MAAK,MAAM,KAAK,WAAY,KAAI,aAAa,EAAE,CAAE,QAAO;AACxD,OAAM,IAAI,MACR,wCAAwC,KAAK,UAAU,WAAW,CAAC,cACrD,CAAC,GAAG,aAAa,CAAC,KAAK,KAAK,CAAC,GAC5C;;AAIH,SAAS,YAAY,SAAoC;AACvD,QAAO,EAAE,WAAW,CAAC,QAAQ,WAAW,UAAU,EAAE;;AAItD,MAAa,gBAAyC;gBAC/B;SACP;CACf;AAED,SAAgB,eAAe,SAA0B;AACvD,QAAO,cAAc;;;;;;;;AASvB,SAAgB,kBACd,SACA,gBACmB;CACnB,MAAM,OAAO,mBAAmB,YAAY,YAAY,QAAQ;AAChE,KAAI,KAAK,aAAa,eACpB,QAAO;EAAE,GAAG;EAAM,eAAe;EAAgB;AAEnD,QAAO"}
1
+ {"version":3,"file":"models-Cow22jET.js","names":[],"sources":["../src/agent/runner/switchboard/models.ts"],"sourcesContent":["// Local capabilities inform transport parameters; gateway policy independently admits models and efforts.\nimport {\n SONNET_5_MODEL,\n HAIKU_MODEL,\n GPT5_6_LUNA_MODEL,\n GPT5_6_SOL_MODEL,\n GPT5_6_TERRA_MODEL,\n HAIKU_TRIAGE_MODEL,\n Harness,\n} from '@shared/constants';\n\n/** Reasoning effort, mapped by each harness to its provider transport. */\nconst THINKING_LEVELS = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n] as const;\nexport type ThinkingLevel = (typeof THINKING_LEVELS)[number];\n\n/** Whether a value (e.g. remote prompt frontmatter) names a valid effort. */\nexport function isThinkingLevel(value: unknown): value is ThinkingLevel {\n return (THINKING_LEVELS as readonly unknown[]).includes(value);\n}\n\n/**\n * An effort *override* is always a positive level — `'off'` is a model trait\n * (`reasoning: false`), not something a flag may force onto a reasoning model.\n */\nexport type EffortLevel = Exclude<ThinkingLevel, 'off'>;\n\nexport interface ModelCapabilities {\n /** Model supports reasoning; safe to request reasoning effort. */\n reasoning: boolean;\n /** Effort to request when reasoning. Omit for the harness/provider default. */\n thinkingLevel?: ThinkingLevel;\n}\n\n/**\n * Explicit per-model traits. Anything absent falls back to `defaultCaps`.\n *\n * A reasoning model without a `thinkingLevel` leaves the effort to the harness,\n * and the mint pins effort per model (posthog `WIZARD_MODEL_ALLOWLIST`), so an\n * unpinned reasoning model is refused with no tool calls. Every level below is\n * one the mint allows for that model.\n */\nexport const MODEL_CAPABILITIES: Record<string, ModelCapabilities> = {\n // The mint takes sonnet 5 at `none` or `high`; high is the only level it\n // serves once reasoning is on.\n [SONNET_5_MODEL]: { reasoning: true, thinkingLevel: 'high' },\n // The mint takes haiku with no effort parameter at all, which is `off`.\n [HAIKU_MODEL]: { reasoning: true, thinkingLevel: 'off' },\n // The openai 5.6 line; all reasoning models, so they must opt in past the\n // openai-completions default (reasoning off). Luna stays low for cheap,\n // short-context mechanical work; terra runs medium as the sonnet-tier parallel\n // — enough reasoning depth for the judgment tasks without high's latency blowup.\n [GPT5_6_LUNA_MODEL]: { reasoning: true, thinkingLevel: 'low' },\n [GPT5_6_TERRA_MODEL]: { reasoning: true, thinkingLevel: 'medium' },\n [GPT5_6_SOL_MODEL]: { reasoning: true, thinkingLevel: 'medium' },\n};\n\n/**\n * The mint's per-model effort pin, mirrored from posthog\n * `WIZARD_MODEL_ALLOWLIST`. `'off'` is the CLI's spelling of the mint's\n * `\"none\"` — a call carrying no effort parameter.\n */\nexport const MINT_ALLOWED_EFFORTS: Record<string, readonly ThinkingLevel[]> = {\n [SONNET_5_MODEL]: ['off', 'high'],\n [HAIKU_MODEL]: ['off'],\n [GPT5_6_LUNA_MODEL]: ['low'],\n [GPT5_6_SOL_MODEL]: ['medium'],\n [GPT5_6_TERRA_MODEL]: ['low', 'medium', 'high'],\n};\n\n// Local model choices; gateway admission also requires allowed models, efforts, and prompt compatibility.\nexport const VALID_MODELS: ReadonlySet<string> = new Set(\n Object.keys(MODEL_CAPABILITIES),\n);\n\n/** Whether the value is an allow-listed model. */\nexport function isValidModel(model: unknown): model is string {\n return typeof model === 'string' && VALID_MODELS.has(model);\n}\n\n/** First allow-listed candidate, else throw so a bad id fails loud. */\nexport function requireKnownModel(\n ...candidates: (string | undefined)[]\n): string {\n for (const c of candidates) if (isValidModel(c)) return c;\n throw new Error(\n `No valid model to dispatch on (tried ${JSON.stringify(candidates)}). ` +\n `Allowed: ${[...VALID_MODELS].join(', ')}.`,\n );\n}\n\n// Unknown Anthropic models default to reasoning; OpenAI models must opt in through the local table.\nfunction defaultCaps(modelId: string): ModelCapabilities {\n return { reasoning: !modelId.startsWith('openai/') };\n}\n\n// Triage requests must satisfy gateway safety policy and preserve Warlock’s classifier format.\nexport const TRIAGE_MODELS: Record<Harness, string> = {\n [Harness.anthropic]: HAIKU_TRIAGE_MODEL,\n [Harness.pi]: GPT5_6_LUNA_MODEL,\n};\n\nexport function triageModelFor(harness: Harness): string {\n return TRIAGE_MODELS[harness];\n}\n\n/**\n * Capabilities for a gateway model id, table override then transport default.\n * `effortOverride` is a switchboard-resolved effort (e.g. from a pi effort\n * flag); it applies only when the model reasons at all — a non-reasoning model\n * rejects reasoning effort, so the override is dropped.\n */\nexport function modelCapabilities(\n modelId: string,\n effortOverride?: EffortLevel,\n): ModelCapabilities {\n const caps = MODEL_CAPABILITIES[modelId] ?? defaultCaps(modelId);\n if (caps.reasoning && effortOverride) {\n return { ...caps, thinkingLevel: effortOverride };\n }\n return caps;\n}\n"],"mappings":";;;AAYA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACD;;AAID,SAAgB,gBAAgB,OAAwC;AACtE,QAAQ,gBAAuC,SAAS,MAAM;;;;;;;;;;AAwBhE,MAAa,qBAAwD;EAGlE,iBAAiB;EAAE,WAAW;EAAM,eAAe;EAAQ;EAE3D,cAAc;EAAE,WAAW;EAAM,eAAe;EAAO;EAKvD,oBAAoB;EAAE,WAAW;EAAM,eAAe;EAAO;EAC7D,qBAAqB;EAAE,WAAW;EAAM,eAAe;EAAU;EACjE,mBAAmB;EAAE,WAAW;EAAM,eAAe;EAAU;CACjE;AAgBD,MAAa,eAAoC,IAAI,IACnD,OAAO,KAAK,mBAAmB,CAChC;;AAGD,SAAgB,aAAa,OAAiC;AAC5D,QAAO,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM;;;AAI7D,SAAgB,kBACd,GAAG,YACK;AACR,MAAK,MAAM,KAAK,WAAY,KAAI,aAAa,EAAE,CAAE,QAAO;AACxD,OAAM,IAAI,MACR,wCAAwC,KAAK,UAAU,WAAW,CAAC,cACrD,CAAC,GAAG,aAAa,CAAC,KAAK,KAAK,CAAC,GAC5C;;AAIH,SAAS,YAAY,SAAoC;AACvD,QAAO,EAAE,WAAW,CAAC,QAAQ,WAAW,UAAU,EAAE;;AAItD,MAAa,gBAAyC;gBAC/B;SACP;CACf;AAED,SAAgB,eAAe,SAA0B;AACvD,QAAO,cAAc;;;;;;;;AASvB,SAAgB,kBACd,SACA,gBACmB;CACnB,MAAM,OAAO,mBAAmB,YAAY,YAAY,QAAQ;AAChE,KAAI,KAAK,aAAa,eACpB,QAAO;EAAE,GAAG;EAAM,eAAe;EAAgB;AAEnD,QAAO"}
@@ -1,4 +1,4 @@
1
- import { o as logToFile } from "./debug-sB20p-Ek.js";
1
+ import { o as logToFile } from "./debug-C3tLP-ZW.js";
2
2
  //#region src/shared/oauth-session.ts
3
3
  const REFRESH_WHEN_REMAINING_MS = 3e3 * 1e3;
4
4
  let current = null;
@@ -71,4 +71,4 @@ async function refresh(rotateWith, credentials) {
71
71
  //#endregion
72
72
  export { onAccessTokenRotated as a, oauthLoginKey as i, currentAccessToken as n, currentCredentials as r, configureOAuthSession as t };
73
73
 
74
- //# sourceMappingURL=oauth-session-C2fVSGfr.js.map
74
+ //# sourceMappingURL=oauth-session-Bj_-BY7o.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-session-C2fVSGfr.js","names":[],"sources":["../src/shared/oauth-session.ts"],"sourcesContent":["// The run's one OAuth token, shaped like gateway-session. The host supplies the rotation.\n\nimport type { Credentials } from '@shared/api';\nimport { logToFile } from '@utils/debug';\n\n// Below this remaining lifetime a run risks outliving its token; just-minted and 7-day tokens skip.\nconst REFRESH_WHEN_REMAINING_MS = 50 * 60 * 1000;\n\n/** Returns the rotated credentials, or the same object when the rotation failed. Never throws. */\nexport type RotateCredentials = (\n credentials: Credentials,\n) => Promise<Credentials>;\n\nlet current: Credentials | null = null;\nlet rotate: RotateCredentials | undefined;\nlet onRefreshed: ((credentials: Credentials) => void) | undefined;\n// Shared so concurrent callers rotate once: a second rotation would spend the refresh token the first replaced.\nlet inFlight: Promise<Credentials> | null = null;\nconst listeners = new Set<(accessToken: string) => void>();\n// Every access token this login has held; the first one names the login.\nlet lineage = new Set<string>();\nlet lineageRoot: string | undefined;\n\n/** Adopt the run's credentials; a stale copy of the held login gets the newer one back through `onRefreshed`. */\nexport function configureOAuthSession(\n credentials: Credentials,\n options: {\n rotate: RotateCredentials;\n onRefreshed?: (credentials: Credentials) => void;\n },\n): void {\n rotate = options.rotate;\n onRefreshed = options.onRefreshed;\n if (\n current &&\n sameLogin(current, credentials) &&\n (current.expiresAt ?? 0) > (credentials.expiresAt ?? 0)\n ) {\n onRefreshed?.(current);\n return;\n }\n if (!current || !sameLogin(current, credentials)) {\n lineage = new Set();\n lineageRoot = credentials.accessToken;\n }\n lineage.add(credentials.accessToken);\n current = credentials;\n}\n\n/** A key that stays the same across this login's rotations, so caches keyed on it survive one. */\nexport function oauthLoginKey(accessToken: string): string {\n return lineageRoot && lineage.has(accessToken) ? lineageRoot : accessToken;\n}\n\n/** The current credentials, refreshed first when near expiry or when `force` is set. */\nexport async function oauthCredentials(\n force = false,\n): Promise<Credentials | null> {\n if (!current) return null;\n if (!rotate || !current.refreshToken || (!force && !nearExpiry(current)))\n return current;\n inFlight ??= refresh(rotate, current).finally(() => {\n inFlight = null;\n });\n return inFlight;\n}\n\n/** The credentials to use now for this login, or the fallback when another login is held. */\nexport async function currentCredentials(\n fallback: Credentials,\n force = false,\n): Promise<Credentials> {\n if (!current || !sameLogin(current, fallback)) return fallback;\n return (await oauthCredentials(force)) ?? fallback;\n}\n\n/** The access token to use now for this login. */\nexport async function currentAccessToken(\n fallback: Credentials,\n): Promise<string> {\n return (await currentCredentials(fallback)).accessToken;\n}\n\n/** Called with each new access token after a rotation. Returns the unsubscribe. */\nexport function onAccessTokenRotated(\n listener: (accessToken: string) => void,\n): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\n/** Test hook: drop the held credentials so the next run configures afresh. */\nexport function resetOAuthSession(): void {\n current = null;\n rotate = undefined;\n onRefreshed = undefined;\n inFlight = null;\n listeners.clear();\n lineage = new Set();\n lineageRoot = undefined;\n}\n\nfunction sameLogin(a: Credentials, b: Credentials): boolean {\n return a.host.apiHost === b.host.apiHost && a.projectId === b.projectId;\n}\n\nfunction nearExpiry(credentials: Credentials): boolean {\n // No expiry means we cannot tell how much life is left, so leave it alone.\n return (\n credentials.expiresAt !== undefined &&\n credentials.expiresAt - Date.now() < REFRESH_WHEN_REMAINING_MS\n );\n}\n\nasync function refresh(\n rotateWith: RotateCredentials,\n credentials: Credentials,\n): Promise<Credentials> {\n const refreshed = await rotateWith(credentials);\n if (refreshed === credentials) return credentials;\n logToFile('[oauth-session] token rotated');\n lineage.add(refreshed.accessToken);\n current = refreshed;\n onRefreshed?.(refreshed);\n for (const listener of listeners) listener(refreshed.accessToken);\n return refreshed;\n}\n"],"mappings":";;AAMA,MAAM,4BAA4B,MAAU;AAO5C,IAAI,UAA8B;AAClC,IAAI;AACJ,IAAI;AAEJ,IAAI,WAAwC;AAC5C,MAAM,4BAAY,IAAI,KAAoC;AAE1D,IAAI,0BAAU,IAAI,KAAa;AAC/B,IAAI;;AAGJ,SAAgB,sBACd,aACA,SAIM;AACN,UAAS,QAAQ;AACjB,eAAc,QAAQ;AACtB,KACE,WACA,UAAU,SAAS,YAAY,KAC9B,QAAQ,aAAa,MAAM,YAAY,aAAa,IACrD;AACA,gBAAc,QAAQ;AACtB;;AAEF,KAAI,CAAC,WAAW,CAAC,UAAU,SAAS,YAAY,EAAE;AAChD,4BAAU,IAAI,KAAK;AACnB,gBAAc,YAAY;;AAE5B,SAAQ,IAAI,YAAY,YAAY;AACpC,WAAU;;;AAIZ,SAAgB,cAAc,aAA6B;AACzD,QAAO,eAAe,QAAQ,IAAI,YAAY,GAAG,cAAc;;;AAIjE,eAAsB,iBACpB,QAAQ,OACqB;AAC7B,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,CAAC,UAAU,CAAC,QAAQ,gBAAiB,CAAC,SAAS,CAAC,WAAW,QAAQ,CACrE,QAAO;AACT,cAAa,QAAQ,QAAQ,QAAQ,CAAC,cAAc;AAClD,aAAW;GACX;AACF,QAAO;;;AAIT,eAAsB,mBACpB,UACA,QAAQ,OACc;AACtB,KAAI,CAAC,WAAW,CAAC,UAAU,SAAS,SAAS,CAAE,QAAO;AACtD,QAAQ,MAAM,iBAAiB,MAAM,IAAK;;;AAI5C,eAAsB,mBACpB,UACiB;AACjB,SAAQ,MAAM,mBAAmB,SAAS,EAAE;;;AAI9C,SAAgB,qBACd,UACY;AACZ,WAAU,IAAI,SAAS;AACvB,cAAa;AACX,YAAU,OAAO,SAAS;;;AAe9B,SAAS,UAAU,GAAgB,GAAyB;AAC1D,QAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,cAAc,EAAE;;AAGhE,SAAS,WAAW,aAAmC;AAErD,QACE,YAAY,cAAc,KAAA,KAC1B,YAAY,YAAY,KAAK,KAAK,GAAG;;AAIzC,eAAe,QACb,YACA,aACsB;CACtB,MAAM,YAAY,MAAM,WAAW,YAAY;AAC/C,KAAI,cAAc,YAAa,QAAO;AACtC,WAAU,gCAAgC;AAC1C,SAAQ,IAAI,UAAU,YAAY;AAClC,WAAU;AACV,eAAc,UAAU;AACxB,MAAK,MAAM,YAAY,UAAW,UAAS,UAAU,YAAY;AACjE,QAAO"}
1
+ {"version":3,"file":"oauth-session-Bj_-BY7o.js","names":[],"sources":["../src/shared/oauth-session.ts"],"sourcesContent":["// The run's one OAuth token, shaped like gateway-session. The host supplies the rotation.\n\nimport type { Credentials } from '@shared/api';\nimport { logToFile } from '@utils/debug';\n\n// Below this remaining lifetime a run risks outliving its token; just-minted and 7-day tokens skip.\nconst REFRESH_WHEN_REMAINING_MS = 50 * 60 * 1000;\n\n/** Returns the rotated credentials, or the same object when the rotation failed. Never throws. */\nexport type RotateCredentials = (\n credentials: Credentials,\n) => Promise<Credentials>;\n\nlet current: Credentials | null = null;\nlet rotate: RotateCredentials | undefined;\nlet onRefreshed: ((credentials: Credentials) => void) | undefined;\n// Shared so concurrent callers rotate once: a second rotation would spend the refresh token the first replaced.\nlet inFlight: Promise<Credentials> | null = null;\nconst listeners = new Set<(accessToken: string) => void>();\n// Every access token this login has held; the first one names the login.\nlet lineage = new Set<string>();\nlet lineageRoot: string | undefined;\n\n/** Adopt the run's credentials; a stale copy of the held login gets the newer one back through `onRefreshed`. */\nexport function configureOAuthSession(\n credentials: Credentials,\n options: {\n rotate: RotateCredentials;\n onRefreshed?: (credentials: Credentials) => void;\n },\n): void {\n rotate = options.rotate;\n onRefreshed = options.onRefreshed;\n if (\n current &&\n sameLogin(current, credentials) &&\n (current.expiresAt ?? 0) > (credentials.expiresAt ?? 0)\n ) {\n onRefreshed?.(current);\n return;\n }\n if (!current || !sameLogin(current, credentials)) {\n lineage = new Set();\n lineageRoot = credentials.accessToken;\n }\n lineage.add(credentials.accessToken);\n current = credentials;\n}\n\n/** A key that stays the same across this login's rotations, so caches keyed on it survive one. */\nexport function oauthLoginKey(accessToken: string): string {\n return lineageRoot && lineage.has(accessToken) ? lineageRoot : accessToken;\n}\n\n/** The current credentials, refreshed first when near expiry or when `force` is set. */\nexport async function oauthCredentials(\n force = false,\n): Promise<Credentials | null> {\n if (!current) return null;\n if (!rotate || !current.refreshToken || (!force && !nearExpiry(current)))\n return current;\n inFlight ??= refresh(rotate, current).finally(() => {\n inFlight = null;\n });\n return inFlight;\n}\n\n/** The credentials to use now for this login, or the fallback when another login is held. */\nexport async function currentCredentials(\n fallback: Credentials,\n force = false,\n): Promise<Credentials> {\n if (!current || !sameLogin(current, fallback)) return fallback;\n return (await oauthCredentials(force)) ?? fallback;\n}\n\n/** The access token to use now for this login. */\nexport async function currentAccessToken(\n fallback: Credentials,\n): Promise<string> {\n return (await currentCredentials(fallback)).accessToken;\n}\n\n/** Called with each new access token after a rotation. Returns the unsubscribe. */\nexport function onAccessTokenRotated(\n listener: (accessToken: string) => void,\n): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\n/** Test hook: drop the held credentials so the next run configures afresh. */\nexport function resetOAuthSession(): void {\n current = null;\n rotate = undefined;\n onRefreshed = undefined;\n inFlight = null;\n listeners.clear();\n lineage = new Set();\n lineageRoot = undefined;\n}\n\nfunction sameLogin(a: Credentials, b: Credentials): boolean {\n return a.host.apiHost === b.host.apiHost && a.projectId === b.projectId;\n}\n\nfunction nearExpiry(credentials: Credentials): boolean {\n // No expiry means we cannot tell how much life is left, so leave it alone.\n return (\n credentials.expiresAt !== undefined &&\n credentials.expiresAt - Date.now() < REFRESH_WHEN_REMAINING_MS\n );\n}\n\nasync function refresh(\n rotateWith: RotateCredentials,\n credentials: Credentials,\n): Promise<Credentials> {\n const refreshed = await rotateWith(credentials);\n if (refreshed === credentials) return credentials;\n logToFile('[oauth-session] token rotated');\n lineage.add(refreshed.accessToken);\n current = refreshed;\n onRefreshed?.(refreshed);\n for (const listener of listeners) listener(refreshed.accessToken);\n return refreshed;\n}\n"],"mappings":";;AAMA,MAAM,4BAA4B,MAAU;AAO5C,IAAI,UAA8B;AAClC,IAAI;AACJ,IAAI;AAEJ,IAAI,WAAwC;AAC5C,MAAM,4BAAY,IAAI,KAAoC;AAE1D,IAAI,0BAAU,IAAI,KAAa;AAC/B,IAAI;;AAGJ,SAAgB,sBACd,aACA,SAIM;AACN,UAAS,QAAQ;AACjB,eAAc,QAAQ;AACtB,KACE,WACA,UAAU,SAAS,YAAY,KAC9B,QAAQ,aAAa,MAAM,YAAY,aAAa,IACrD;AACA,gBAAc,QAAQ;AACtB;;AAEF,KAAI,CAAC,WAAW,CAAC,UAAU,SAAS,YAAY,EAAE;AAChD,4BAAU,IAAI,KAAK;AACnB,gBAAc,YAAY;;AAE5B,SAAQ,IAAI,YAAY,YAAY;AACpC,WAAU;;;AAIZ,SAAgB,cAAc,aAA6B;AACzD,QAAO,eAAe,QAAQ,IAAI,YAAY,GAAG,cAAc;;;AAIjE,eAAsB,iBACpB,QAAQ,OACqB;AAC7B,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,CAAC,UAAU,CAAC,QAAQ,gBAAiB,CAAC,SAAS,CAAC,WAAW,QAAQ,CACrE,QAAO;AACT,cAAa,QAAQ,QAAQ,QAAQ,CAAC,cAAc;AAClD,aAAW;GACX;AACF,QAAO;;;AAIT,eAAsB,mBACpB,UACA,QAAQ,OACc;AACtB,KAAI,CAAC,WAAW,CAAC,UAAU,SAAS,SAAS,CAAE,QAAO;AACtD,QAAQ,MAAM,iBAAiB,MAAM,IAAK;;;AAI5C,eAAsB,mBACpB,UACiB;AACjB,SAAQ,MAAM,mBAAmB,SAAS,EAAE;;;AAI9C,SAAgB,qBACd,UACY;AACZ,WAAU,IAAI,SAAS;AACvB,cAAa;AACX,YAAU,OAAO,SAAS;;;AAe9B,SAAS,UAAU,GAAgB,GAAyB;AAC1D,QAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,cAAc,EAAE;;AAGhE,SAAS,WAAW,aAAmC;AAErD,QACE,YAAY,cAAc,KAAA,KAC1B,YAAY,YAAY,KAAK,KAAK,GAAG;;AAIzC,eAAe,QACb,YACA,aACsB;CACtB,MAAM,YAAY,MAAM,WAAW,YAAY;AAC/C,KAAI,cAAc,YAAa,QAAO;AACtC,WAAU,gCAAgC;AAC1C,SAAQ,IAAI,UAAU,YAAY;AAClC,WAAU;AACV,eAAc,UAAU;AACxB,MAAK,MAAM,YAAY,UAAW,UAAS,UAAU,YAAY;AACjE,QAAO"}
@@ -1,5 +1,5 @@
1
- import { n as analytics } from "./analytics-CGGE7OSa.js";
2
- import { a as REMARK_ASK, c as applyReadHandoffs, f as NotNeededReason, i as NOT_NEEDED_REASON_ASK, n as ENQUEUE_MODEL_DESCRIPTION, o as applyComplete, r as HANDOFF_FIELDS, s as applyEnqueue, t as COMPLETE_TASK_DESCRIPTION } from "./queue-tools-BQfRI_uD.js";
1
+ import { n as analytics } from "./analytics-X7JfAmh6.js";
2
+ import { a as REMARK_ASK, c as applyReadHandoffs, f as NotNeededReason, i as NOT_NEEDED_REASON_ASK, n as ENQUEUE_MODEL_DESCRIPTION, o as applyComplete, r as HANDOFF_FIELDS, s as applyEnqueue, t as COMPLETE_TASK_DESCRIPTION } from "./queue-tools-DrJKvFHZ.js";
3
3
  import { Type } from "typebox";
4
4
  import { defineTool } from "@earendil-works/pi-coding-agent";
5
5
  //#region src/agent/runner/harness/pi/orchestrator-tools.ts
@@ -110,4 +110,4 @@ function createPiOrchestratorTools(ctx) {
110
110
  //#endregion
111
111
  export { createPiOrchestratorTools };
112
112
 
113
- //# sourceMappingURL=orchestrator-tools-BchqG7Qi.js.map
113
+ //# sourceMappingURL=orchestrator-tools-lhFIBGnp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-tools-BchqG7Qi.js","names":[],"sources":["../src/agent/runner/harness/pi/orchestrator-tools.ts"],"sourcesContent":["/**\n * Orchestrator queue tools as pi custom tools. The queue lives in-process, and\n * `applyEnqueue` / `applyComplete` / `applyReadHandoffs` are plain exported\n * functions — so pi needs no MCP transport, just `defineTool` wrappers around\n * the same guards and apply logic the anthropic path mounts through the\n * wizard-tools MCP server. Tool names match the MCP short names so the shared\n * agent prompts are unchanged.\n *\n * Lazily imported (typebox is ESM and must stay out of the static module graph\n * so CommonJS unit tests can load the backend seam without parsing it).\n */\n\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 {\n applyComplete,\n applyEnqueue,\n applyReadHandoffs,\n COMPLETE_TASK_DESCRIPTION,\n ENQUEUE_MODEL_DESCRIPTION,\n HANDOFF_FIELDS,\n NOT_NEEDED_REASON_ASK,\n REMARK_ASK,\n type CompleteArgs,\n type EnqueueArgs,\n type OrchestratorToolsContext,\n} from '../../sequence/orchestrator/queue-tools';\nimport { NotNeededReason } from '../../sequence/orchestrator/queue';\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\n/** Mirrors the zod `HANDOFF_SHAPE`; both read their text from HANDOFF_FIELDS. */\nconst HANDOFF_PARAMS = Type.Object({\n goals: Type.String({ description: HANDOFF_FIELDS.goals }),\n did: Type.String({ description: HANDOFF_FIELDS.did }),\n forNextAgent: Type.String({ description: HANDOFF_FIELDS.forNextAgent }),\n filesTouched: Type.Optional(\n Type.Array(Type.String(), { description: HANDOFF_FIELDS.filesTouched }),\n ),\n evidence: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.evidence }),\n ),\n assumptions: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.assumptions }),\n ),\n conflict: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.conflict }),\n ),\n reportSection: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.reportSection }),\n ),\n});\n\n/** Exported so the parity test can compare both harnesses' field sets. */\nexport const PI_HANDOFF_PARAM_KEYS: readonly string[] = Object.keys(\n HANDOFF_PARAMS.properties,\n);\n\n/** Mirrors the zod `COMPLETE_SHAPE`; ctx-independent, so it lives out here. */\nconst COMPLETE_PARAMS = Type.Object({\n status: Type.Union([\n Type.Literal('done'),\n Type.Literal('failed'),\n Type.Literal('not needed'),\n ]),\n handoff: HANDOFF_PARAMS,\n remark: Type.Optional(Type.String({ description: REMARK_ASK })),\n notNeededReason: Type.Optional(\n Type.Union(\n [\n Type.Literal(NotNeededReason.NotApplicable),\n Type.Literal(NotNeededReason.UserDeclined),\n Type.Literal(NotNeededReason.Blocked),\n ],\n { description: NOT_NEEDED_REASON_ASK },\n ),\n ),\n});\n\n/** Exported so the parity test can compare both harnesses' field sets. */\nexport const PI_COMPLETE_PARAM_KEYS: readonly string[] = Object.keys(\n COMPLETE_PARAMS.properties,\n);\n\n/** The three queue tools bound to one agent's orchestrator context. */\nexport function createPiOrchestratorTools(\n ctx: OrchestratorToolsContext,\n): ToolDefinition[] {\n const enqueueTask = defineTool({\n name: 'enqueue_task',\n label: 'Enqueue task',\n description:\n 'Add a task to the orchestrator queue. Use it to seed work and to enqueue follow-up work you discover. Keep tasks small and discrete.',\n promptSnippet:\n 'enqueue_task({type, label, dependsOn, reason}) — add a task to the queue; the task type goes in the \"type\" field, and it returns the task id',\n parameters: Type.Object({\n type: Type.String({\n description: `The task type. One of: ${ctx.validTypes.join(', ')}.`,\n }),\n label: Type.Optional(\n Type.String({\n description:\n 'A short label for the UI — the action in a few words (e.g. \"Add the PostHog SDK\", \"Initialize PostHog\"). Leave out file names, class names, and other specifics.',\n }),\n ),\n inputs: Type.Optional(Type.Record(Type.String(), Type.Unknown())),\n dependsOn: Type.Optional(\n Type.Array(Type.String(), {\n description: 'Task ids that must be done before this task runs.',\n }),\n ),\n model: Type.Optional(\n Type.String({ description: ENQUEUE_MODEL_DESCRIPTION }),\n ),\n reason: Type.String({\n description: 'One line on why this task is needed.',\n }),\n }),\n execute(_id, args) {\n const res = applyEnqueue(ctx, args as EnqueueArgs);\n if (!res.ok) {\n analytics.wizardCapture('orchestrator guard tripped', {\n guard: res.guard,\n type: (args as EnqueueArgs).type,\n });\n return Promise.resolve(text(`Error: ${res.message}`));\n }\n return Promise.resolve(text(JSON.stringify({ id: res.task.id })));\n },\n });\n\n const completeTask = defineTool({\n name: 'complete_task',\n label: 'Complete task',\n description: COMPLETE_TASK_DESCRIPTION,\n promptSnippet:\n 'complete_task(status, handoff) — report your outcome exactly once when done, with goals/did/forNextAgent nested inside handoff',\n parameters: COMPLETE_PARAMS,\n execute(_id, args) {\n const res = applyComplete(ctx, args as CompleteArgs);\n if (!res.ok) return Promise.resolve(text(`Error: ${res.message}`));\n return Promise.resolve(text('ok'));\n },\n });\n\n const readHandoffs = defineTool({\n name: 'read_handoffs',\n label: 'Read handoffs',\n description:\n 'Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.',\n promptSnippet:\n 'read_handoffs() — read what earlier tasks handed off (defaults to your dependencies)',\n parameters: Type.Object({\n type: Type.Optional(Type.String()),\n taskId: Type.Optional(Type.String()),\n }),\n execute(_id, args) {\n const handoffs = applyReadHandoffs(\n ctx,\n args as { type?: string; taskId?: string },\n );\n return Promise.resolve(text(JSON.stringify(handoffs, null, 2)));\n },\n });\n\n return [enqueueTask, completeTask, readHandoffs];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator-tools-lhFIBGnp.js","names":[],"sources":["../src/agent/runner/harness/pi/orchestrator-tools.ts"],"sourcesContent":["/**\n * Orchestrator queue tools as pi custom tools. The queue lives in-process, and\n * `applyEnqueue` / `applyComplete` / `applyReadHandoffs` are plain exported\n * functions — so pi needs no MCP transport, just `defineTool` wrappers around\n * the same guards and apply logic the anthropic path mounts through the\n * wizard-tools MCP server. Tool names match the MCP short names so the shared\n * agent prompts are unchanged.\n *\n * Lazily imported (typebox is ESM and must stay out of the static module graph\n * so CommonJS unit tests can load the backend seam without parsing it).\n */\n\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 {\n applyComplete,\n applyEnqueue,\n applyReadHandoffs,\n COMPLETE_TASK_DESCRIPTION,\n ENQUEUE_MODEL_DESCRIPTION,\n HANDOFF_FIELDS,\n NOT_NEEDED_REASON_ASK,\n REMARK_ASK,\n type CompleteArgs,\n type EnqueueArgs,\n type OrchestratorToolsContext,\n} from '../../sequence/orchestrator/queue-tools';\nimport { NotNeededReason } from '../../sequence/orchestrator/queue';\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\n/** Mirrors the zod `HANDOFF_SHAPE`; both read their text from HANDOFF_FIELDS. */\nconst HANDOFF_PARAMS = Type.Object({\n goals: Type.String({ description: HANDOFF_FIELDS.goals }),\n did: Type.String({ description: HANDOFF_FIELDS.did }),\n forNextAgent: Type.String({ description: HANDOFF_FIELDS.forNextAgent }),\n filesTouched: Type.Optional(\n Type.Array(Type.String(), { description: HANDOFF_FIELDS.filesTouched }),\n ),\n evidence: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.evidence }),\n ),\n assumptions: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.assumptions }),\n ),\n conflict: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.conflict }),\n ),\n reportSection: Type.Optional(\n Type.String({ description: HANDOFF_FIELDS.reportSection }),\n ),\n});\n\n/** Exported so the parity test can compare both harnesses' field sets. */\nexport const PI_HANDOFF_PARAM_KEYS: readonly string[] = Object.keys(\n HANDOFF_PARAMS.properties,\n);\n\n/** Mirrors the zod `COMPLETE_SHAPE`; ctx-independent, so it lives out here. */\nconst COMPLETE_PARAMS = Type.Object({\n status: Type.Union([\n Type.Literal('done'),\n Type.Literal('failed'),\n Type.Literal('not needed'),\n ]),\n handoff: HANDOFF_PARAMS,\n remark: Type.Optional(Type.String({ description: REMARK_ASK })),\n notNeededReason: Type.Optional(\n Type.Union(\n [\n Type.Literal(NotNeededReason.NotApplicable),\n Type.Literal(NotNeededReason.UserDeclined),\n Type.Literal(NotNeededReason.Blocked),\n ],\n { description: NOT_NEEDED_REASON_ASK },\n ),\n ),\n});\n\n/** Exported so the parity test can compare both harnesses' field sets. */\nexport const PI_COMPLETE_PARAM_KEYS: readonly string[] = Object.keys(\n COMPLETE_PARAMS.properties,\n);\n\n/** The three queue tools bound to one agent's orchestrator context. */\nexport function createPiOrchestratorTools(\n ctx: OrchestratorToolsContext,\n): ToolDefinition[] {\n const enqueueTask = defineTool({\n name: 'enqueue_task',\n label: 'Enqueue task',\n description:\n 'Add a task to the orchestrator queue. Use it to seed work and to enqueue follow-up work you discover. Keep tasks small and discrete.',\n promptSnippet:\n 'enqueue_task({type, label, dependsOn, reason}) — add a task to the queue; the task type goes in the \"type\" field, and it returns the task id',\n parameters: Type.Object({\n type: Type.String({\n description: `The task type. One of: ${ctx.validTypes.join(', ')}.`,\n }),\n label: Type.Optional(\n Type.String({\n description:\n 'A short label for the UI — the action in a few words (e.g. \"Add the PostHog SDK\", \"Initialize PostHog\"). Leave out file names, class names, and other specifics.',\n }),\n ),\n inputs: Type.Optional(Type.Record(Type.String(), Type.Unknown())),\n dependsOn: Type.Optional(\n Type.Array(Type.String(), {\n description: 'Task ids that must be done before this task runs.',\n }),\n ),\n model: Type.Optional(\n Type.String({ description: ENQUEUE_MODEL_DESCRIPTION }),\n ),\n reason: Type.String({\n description: 'One line on why this task is needed.',\n }),\n }),\n execute(_id, args) {\n const res = applyEnqueue(ctx, args as EnqueueArgs);\n if (!res.ok) {\n analytics.wizardCapture('orchestrator guard tripped', {\n guard: res.guard,\n type: (args as EnqueueArgs).type,\n });\n return Promise.resolve(text(`Error: ${res.message}`));\n }\n return Promise.resolve(text(JSON.stringify({ id: res.task.id })));\n },\n });\n\n const completeTask = defineTool({\n name: 'complete_task',\n label: 'Complete task',\n description: COMPLETE_TASK_DESCRIPTION,\n promptSnippet:\n 'complete_task(status, handoff) — report your outcome exactly once when done, with goals/did/forNextAgent nested inside handoff',\n parameters: COMPLETE_PARAMS,\n execute(_id, args) {\n const res = applyComplete(ctx, args as CompleteArgs);\n if (!res.ok) return Promise.resolve(text(`Error: ${res.message}`));\n return Promise.resolve(text('ok'));\n },\n });\n\n const readHandoffs = defineTool({\n name: 'read_handoffs',\n label: 'Read handoffs',\n description:\n 'Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.',\n promptSnippet:\n 'read_handoffs() — read what earlier tasks handed off (defaults to your dependencies)',\n parameters: Type.Object({\n type: Type.Optional(Type.String()),\n taskId: Type.Optional(Type.String()),\n }),\n execute(_id, args) {\n const handoffs = applyReadHandoffs(\n ctx,\n args as { type?: string; taskId?: string },\n );\n return Promise.resolve(text(JSON.stringify(handoffs, null, 2)));\n },\n });\n\n return [enqueueTask, completeTask, readHandoffs];\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { n as analytics } from "./analytics-CGGE7OSa.js";
2
- import { r as readFileHead } from "./bounded-fs-DwL2Tasp.js";
3
- import { t as withProgress } from "./telemetry-Ch9ZJvm7.js";
1
+ import { n as analytics } from "./analytics-X7JfAmh6.js";
2
+ import { r as readFileHead } from "./bounded-fs-iDiqDQ9v.js";
3
+ import { t as withProgress } from "./telemetry-NeZhrBeW.js";
4
4
  import * as fs$1 from "fs";
5
5
  import * as path$1 from "path";
6
6
  //#region src/shared/utils/package-manager.ts
@@ -102,4 +102,4 @@ function detectNodePackageManagers(installDir) {
102
102
  //#endregion
103
103
  export { detectNodePackageManagers as n, detectAllPackageManagers as t };
104
104
 
105
- //# sourceMappingURL=package-manager-B3_qSybg.js.map
105
+ //# sourceMappingURL=package-manager-DZ4wcTz3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager-B3_qSybg.js","names":["fs","path"],"sources":["../src/shared/utils/package-manager.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { readFileHead } from './bounded-fs';\nimport { withProgress } from './telemetry';\nimport { analytics } from './analytics';\nimport type { WizardRunOptions } from './types';\n\ntype InstallDirOpt = Pick<WizardRunOptions, 'installDir'>;\n\nexport interface PackageManager {\n name: string;\n label: string;\n installCommand: string;\n buildCommand: string;\n /** Command the manager uses to execute a `package.json` script. */\n runScriptCommand: string;\n flags: string;\n detect: (opts: InstallDirOpt) => boolean;\n}\n\nfunction hasLockfile(installDir: string, file: string): boolean {\n return fs.existsSync(path.join(installDir, file));\n}\n\nfunction lockfileHeaderContains(\n installDir: string,\n file: string,\n needle: string,\n): boolean {\n // Reads only the first 500 bytes of the lockfile.\n return (\n readFileHead(path.join(installDir, file), 500)?.includes(needle) ?? false\n );\n}\n\nexport const BUN: PackageManager = {\n name: 'bun',\n label: 'Bun',\n installCommand: 'bun add',\n buildCommand: 'bun run build',\n runScriptCommand: 'bun run',\n flags: '',\n detect: ({ installDir }) =>\n hasLockfile(installDir, 'bun.lockb') || hasLockfile(installDir, 'bun.lock'),\n};\n\nexport const YARN_V1: PackageManager = {\n name: 'yarn',\n label: 'Yarn V1',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '--ignore-workspace-root-check',\n detect: ({ installDir }) =>\n lockfileHeaderContains(installDir, 'yarn.lock', 'yarn lockfile v1'),\n};\n\n/** YARN V2/3/4 */\nexport const YARN_V2: PackageManager = {\n name: 'yarn',\n label: 'Yarn V2/3/4',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '',\n detect: ({ installDir }) =>\n lockfileHeaderContains(installDir, 'yarn.lock', '__metadata'),\n};\n\nexport const PNPM: PackageManager = {\n name: 'pnpm',\n label: 'pnpm',\n installCommand: 'pnpm add',\n buildCommand: 'pnpm build',\n runScriptCommand: 'pnpm',\n flags: '--ignore-workspace-root-check',\n detect: ({ installDir }) => hasLockfile(installDir, 'pnpm-lock.yaml'),\n};\n\nexport const NPM: PackageManager = {\n name: 'npm',\n label: 'npm',\n installCommand: 'npm add',\n buildCommand: 'npm run build',\n runScriptCommand: 'npm run',\n flags: '',\n detect: ({ installDir }) => hasLockfile(installDir, 'package-lock.json'),\n};\n\n// Expo is selected by upstream config (app.json / app.config.*) rather than\n// a lockfile, so its detect always returns false here.\nexport const EXPO: PackageManager = {\n name: 'expo',\n label: 'Expo',\n installCommand: 'npx expo install',\n buildCommand: 'npx expo build',\n runScriptCommand: 'npx expo run',\n flags: '',\n detect: () => false,\n};\n\nexport const packageManagers: PackageManager[] = [\n BUN,\n YARN_V1,\n YARN_V2,\n PNPM,\n NPM,\n EXPO,\n];\n\nexport function detectAllPackageManagers({\n installDir,\n}: InstallDirOpt): PackageManager[] {\n return withProgress('detect-package-manager', () => {\n const matches = packageManagers.filter((pm) => pm.detect({ installDir }));\n if (matches.length === 0) {\n analytics.setTag('package-manager', 'not-detected');\n }\n return matches;\n });\n}\n\n// ---------------------------------------------------------------------------\n// The detector contract the agent's `detect_package_manager` tool calls\n// ---------------------------------------------------------------------------\n\n/** Structured package manager info the agent can act on */\nexport interface DetectedPackageManager {\n name: string;\n label: string;\n installCommand: string;\n runCommand?: string;\n}\n\n/** Result returned by every detector */\nexport interface PackageManagerInfo {\n detected: DetectedPackageManager[];\n primary: DetectedPackageManager | null;\n recommendation: string;\n}\n\n/** Signature each framework implements */\nexport type PackageManagerDetector = (\n installDir: string,\n) => Promise<PackageManagerInfo>;\n\n// ---------------------------------------------------------------------------\n// Node.js helper\n// ---------------------------------------------------------------------------\n\nfunction serializeNodePM(pm: PackageManager): DetectedPackageManager {\n return {\n name: pm.name,\n label: pm.label,\n installCommand: pm.installCommand,\n runCommand: pm.runScriptCommand,\n };\n}\n\n/**\n * Detect Node.js package managers via lockfiles.\n * Wraps detectAllPackageManagers() above.\n */\nexport function detectNodePackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const detected = detectAllPackageManagers({ installDir }).map(\n serializeNodePM,\n );\n\n if (detected.length === 0) {\n return Promise.resolve({\n detected: [],\n primary: null,\n recommendation: 'No lockfile found. Default to npm (npm add, npm run).',\n });\n }\n\n const primary = detected[0];\n return Promise.resolve({\n detected,\n primary,\n recommendation:\n detected.length === 1\n ? `Use ${primary.label} (${primary.installCommand}).`\n : `Multiple package managers detected. Prefer ${primary.label} (${primary.installCommand}).`,\n });\n}\n"],"mappings":";;;;;;AAoBA,SAAS,YAAY,YAAoB,MAAuB;AAC9D,QAAOA,KAAG,WAAWC,OAAK,KAAK,YAAY,KAAK,CAAC;;AAGnD,SAAS,uBACP,YACA,MACA,QACS;AAET,QACE,aAAaA,OAAK,KAAK,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,OAAO,IAAI;;AAsExE,MAAa,kBAAoC;CAlEd;EACjC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBACT,YAAY,YAAY,YAAY,IAAI,YAAY,YAAY,WAAW;EAC9E;CAEsC;EACrC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBACT,uBAAuB,YAAY,aAAa,mBAAmB;EACtE;CAGsC;EACrC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBACT,uBAAuB,YAAY,aAAa,aAAa;EAChE;CAEmC;EAClC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBAAiB,YAAY,YAAY,iBAAiB;EACtE;CAEkC;EACjC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBAAiB,YAAY,YAAY,oBAAoB;EACzE;CAImC;EAClC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,cAAc;EACf;CASA;AAED,SAAgB,yBAAyB,EACvC,cACkC;AAClC,QAAO,aAAa,gCAAgC;EAClD,MAAM,UAAU,gBAAgB,QAAQ,OAAO,GAAG,OAAO,EAAE,YAAY,CAAC,CAAC;AACzE,MAAI,QAAQ,WAAW,EACrB,WAAU,OAAO,mBAAmB,eAAe;AAErD,SAAO;GACP;;AA+BJ,SAAS,gBAAgB,IAA4C;AACnE,QAAO;EACL,MAAM,GAAG;EACT,OAAO,GAAG;EACV,gBAAgB,GAAG;EACnB,YAAY,GAAG;EAChB;;;;;;AAOH,SAAgB,0BACd,YAC6B;CAC7B,MAAM,WAAW,yBAAyB,EAAE,YAAY,CAAC,CAAC,IACxD,gBACD;AAED,KAAI,SAAS,WAAW,EACtB,QAAO,QAAQ,QAAQ;EACrB,UAAU,EAAE;EACZ,SAAS;EACT,gBAAgB;EACjB,CAAC;CAGJ,MAAM,UAAU,SAAS;AACzB,QAAO,QAAQ,QAAQ;EACrB;EACA;EACA,gBACE,SAAS,WAAW,IAChB,OAAO,QAAQ,MAAM,IAAI,QAAQ,eAAe,MAChD,8CAA8C,QAAQ,MAAM,IAAI,QAAQ,eAAe;EAC9F,CAAC"}
1
+ {"version":3,"file":"package-manager-DZ4wcTz3.js","names":["fs","path"],"sources":["../src/shared/utils/package-manager.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { readFileHead } from './bounded-fs';\nimport { withProgress } from './telemetry';\nimport { analytics } from './analytics';\nimport type { WizardRunOptions } from './types';\n\ntype InstallDirOpt = Pick<WizardRunOptions, 'installDir'>;\n\nexport interface PackageManager {\n name: string;\n label: string;\n installCommand: string;\n buildCommand: string;\n /** Command the manager uses to execute a `package.json` script. */\n runScriptCommand: string;\n flags: string;\n detect: (opts: InstallDirOpt) => boolean;\n}\n\nfunction hasLockfile(installDir: string, file: string): boolean {\n return fs.existsSync(path.join(installDir, file));\n}\n\nfunction lockfileHeaderContains(\n installDir: string,\n file: string,\n needle: string,\n): boolean {\n // Reads only the first 500 bytes of the lockfile.\n return (\n readFileHead(path.join(installDir, file), 500)?.includes(needle) ?? false\n );\n}\n\nexport const BUN: PackageManager = {\n name: 'bun',\n label: 'Bun',\n installCommand: 'bun add',\n buildCommand: 'bun run build',\n runScriptCommand: 'bun run',\n flags: '',\n detect: ({ installDir }) =>\n hasLockfile(installDir, 'bun.lockb') || hasLockfile(installDir, 'bun.lock'),\n};\n\nexport const YARN_V1: PackageManager = {\n name: 'yarn',\n label: 'Yarn V1',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '--ignore-workspace-root-check',\n detect: ({ installDir }) =>\n lockfileHeaderContains(installDir, 'yarn.lock', 'yarn lockfile v1'),\n};\n\n/** YARN V2/3/4 */\nexport const YARN_V2: PackageManager = {\n name: 'yarn',\n label: 'Yarn V2/3/4',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '',\n detect: ({ installDir }) =>\n lockfileHeaderContains(installDir, 'yarn.lock', '__metadata'),\n};\n\nexport const PNPM: PackageManager = {\n name: 'pnpm',\n label: 'pnpm',\n installCommand: 'pnpm add',\n buildCommand: 'pnpm build',\n runScriptCommand: 'pnpm',\n flags: '--ignore-workspace-root-check',\n detect: ({ installDir }) => hasLockfile(installDir, 'pnpm-lock.yaml'),\n};\n\nexport const NPM: PackageManager = {\n name: 'npm',\n label: 'npm',\n installCommand: 'npm add',\n buildCommand: 'npm run build',\n runScriptCommand: 'npm run',\n flags: '',\n detect: ({ installDir }) => hasLockfile(installDir, 'package-lock.json'),\n};\n\n// Expo is selected by upstream config (app.json / app.config.*) rather than\n// a lockfile, so its detect always returns false here.\nexport const EXPO: PackageManager = {\n name: 'expo',\n label: 'Expo',\n installCommand: 'npx expo install',\n buildCommand: 'npx expo build',\n runScriptCommand: 'npx expo run',\n flags: '',\n detect: () => false,\n};\n\nexport const packageManagers: PackageManager[] = [\n BUN,\n YARN_V1,\n YARN_V2,\n PNPM,\n NPM,\n EXPO,\n];\n\nexport function detectAllPackageManagers({\n installDir,\n}: InstallDirOpt): PackageManager[] {\n return withProgress('detect-package-manager', () => {\n const matches = packageManagers.filter((pm) => pm.detect({ installDir }));\n if (matches.length === 0) {\n analytics.setTag('package-manager', 'not-detected');\n }\n return matches;\n });\n}\n\n// ---------------------------------------------------------------------------\n// The detector contract the agent's `detect_package_manager` tool calls\n// ---------------------------------------------------------------------------\n\n/** Structured package manager info the agent can act on */\nexport interface DetectedPackageManager {\n name: string;\n label: string;\n installCommand: string;\n runCommand?: string;\n}\n\n/** Result returned by every detector */\nexport interface PackageManagerInfo {\n detected: DetectedPackageManager[];\n primary: DetectedPackageManager | null;\n recommendation: string;\n}\n\n/** Signature each framework implements */\nexport type PackageManagerDetector = (\n installDir: string,\n) => Promise<PackageManagerInfo>;\n\n// ---------------------------------------------------------------------------\n// Node.js helper\n// ---------------------------------------------------------------------------\n\nfunction serializeNodePM(pm: PackageManager): DetectedPackageManager {\n return {\n name: pm.name,\n label: pm.label,\n installCommand: pm.installCommand,\n runCommand: pm.runScriptCommand,\n };\n}\n\n/**\n * Detect Node.js package managers via lockfiles.\n * Wraps detectAllPackageManagers() above.\n */\nexport function detectNodePackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const detected = detectAllPackageManagers({ installDir }).map(\n serializeNodePM,\n );\n\n if (detected.length === 0) {\n return Promise.resolve({\n detected: [],\n primary: null,\n recommendation: 'No lockfile found. Default to npm (npm add, npm run).',\n });\n }\n\n const primary = detected[0];\n return Promise.resolve({\n detected,\n primary,\n recommendation:\n detected.length === 1\n ? `Use ${primary.label} (${primary.installCommand}).`\n : `Multiple package managers detected. Prefer ${primary.label} (${primary.installCommand}).`,\n });\n}\n"],"mappings":";;;;;;AAoBA,SAAS,YAAY,YAAoB,MAAuB;AAC9D,QAAOA,KAAG,WAAWC,OAAK,KAAK,YAAY,KAAK,CAAC;;AAGnD,SAAS,uBACP,YACA,MACA,QACS;AAET,QACE,aAAaA,OAAK,KAAK,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,OAAO,IAAI;;AAsExE,MAAa,kBAAoC;CAlEd;EACjC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBACT,YAAY,YAAY,YAAY,IAAI,YAAY,YAAY,WAAW;EAC9E;CAEsC;EACrC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBACT,uBAAuB,YAAY,aAAa,mBAAmB;EACtE;CAGsC;EACrC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBACT,uBAAuB,YAAY,aAAa,aAAa;EAChE;CAEmC;EAClC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBAAiB,YAAY,YAAY,iBAAiB;EACtE;CAEkC;EACjC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,SAAS,EAAE,iBAAiB,YAAY,YAAY,oBAAoB;EACzE;CAImC;EAClC,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,cAAc;EACd,kBAAkB;EAClB,OAAO;EACP,cAAc;EACf;CASA;AAED,SAAgB,yBAAyB,EACvC,cACkC;AAClC,QAAO,aAAa,gCAAgC;EAClD,MAAM,UAAU,gBAAgB,QAAQ,OAAO,GAAG,OAAO,EAAE,YAAY,CAAC,CAAC;AACzE,MAAI,QAAQ,WAAW,EACrB,WAAU,OAAO,mBAAmB,eAAe;AAErD,SAAO;GACP;;AA+BJ,SAAS,gBAAgB,IAA4C;AACnE,QAAO;EACL,MAAM,GAAG;EACT,OAAO,GAAG;EACV,gBAAgB,GAAG;EACnB,YAAY,GAAG;EAChB;;;;;;AAOH,SAAgB,0BACd,YAC6B;CAC7B,MAAM,WAAW,yBAAyB,EAAE,YAAY,CAAC,CAAC,IACxD,gBACD;AAED,KAAI,SAAS,WAAW,EACtB,QAAO,QAAQ,QAAQ;EACrB,UAAU,EAAE;EACZ,SAAS;EACT,gBAAgB;EACjB,CAAC;CAGJ,MAAM,UAAU,SAAS;AACzB,QAAO,QAAQ,QAAQ;EACrB;EACA;EACA,gBACE,SAAS,WAAW,IAChB,OAAO,QAAQ,MAAM,IAAI,QAAQ,eAAe,MAChD,8CAA8C,QAAQ,MAAM,IAAI,QAAQ,eAAe;EAC9F,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { n as ErrorCodes } from "./emit-BqLCdV8Y.js";
2
- import { f as VERSION, i as getLogFilePath, o as logToFile } from "./debug-sB20p-Ek.js";
3
- import { $ as WIZARD_REMARK_EVENT_NAME, it as wizardUserAgentForProgram, n as analytics } from "./analytics-CGGE7OSa.js";
2
+ import { f as VERSION, i as getLogFilePath, o as logToFile } from "./debug-C3tLP-ZW.js";
3
+ import { $ as WIZARD_REMARK_EVENT_NAME, it as wizardUserAgentForProgram, n as analytics } from "./analytics-X7JfAmh6.js";
4
4
  import { t as classifyRunFailure } from "./errors-DhFeR8Sp.js";
5
- import { n as currentAccessToken } from "./oauth-session-C2fVSGfr.js";
6
- import { c as REMARK_INSTRUCTION, d as gatewayAuth, o as withGatewayRemint, r as buildGatewayProvider, s as AgentSignals, t as GATEWAY_PROVIDER } from "./gateway-Dg4Fm-nC.js";
7
- import { h as AgentOutputSignals, v as assembleCommandments } from "./agent-interface-BFzBnz10.js";
5
+ import { n as currentAccessToken } from "./oauth-session-Bj_-BY7o.js";
6
+ import { c as REMARK_INSTRUCTION, d as gatewayAuth, o as withGatewayRemint, r as buildGatewayProvider, s as AgentSignals, t as GATEWAY_PROVIDER } from "./gateway-IQjQ582o.js";
7
+ import { h as AgentOutputSignals, v as assembleCommandments } from "./agent-interface-DMP3DZRd.js";
8
8
  import fs from "fs";
9
9
  import path from "path";
10
10
  function appendStatus(messages, message) {
@@ -644,7 +644,7 @@ const piBackend = {
644
644
  message: "pi: gateway model could not be resolved"
645
645
  };
646
646
  const askState = { pending: false };
647
- const { createSecurityExtension, READ_ONLY_PI_TOOLS } = await import("./security-C36p8lu6.js");
647
+ const { createSecurityExtension, READ_ONLY_PI_TOOLS } = await import("./security-C_grSgIM.js");
648
648
  const security = createSecurityExtension({
649
649
  readOnly: config.readOnly,
650
650
  disallowedTools: runConfig.disallowedTools,
@@ -653,13 +653,13 @@ const piBackend = {
653
653
  workingDirectory: input.installDir
654
654
  });
655
655
  securityState = security.state;
656
- const { prewarmYaraScanner } = await import("./yara-hooks-DV4EkkZY.js");
656
+ const { prewarmYaraScanner } = await import("./yara-hooks-CFD60h78.js");
657
657
  prewarmYaraScanner();
658
658
  const extensionFactories = [security.factory];
659
659
  let mcpInstructions;
660
660
  let posthogMcp = false;
661
661
  if (!config.readOnly) try {
662
- const { setupPostHogMcp, fetchInstructions } = await import("./mcp-SZcGfaOz.js");
662
+ const { setupPostHogMcp, fetchInstructions } = await import("./mcp-B2o4d9DS.js");
663
663
  const mcpToken = await currentAccessToken(boot.credentials);
664
664
  const mcpUserAgent = wizardUserAgentForProgram(config.integrationLabel);
665
665
  const instructionsPromise = fetchInstructions(boot.credentials.host.mcpUrl, mcpToken, mcpUserAgent);
@@ -705,9 +705,9 @@ const piBackend = {
705
705
  extensionFactories
706
706
  });
707
707
  await resourceLoader.reload();
708
- const { createWizardPiTools } = await import("./tools-CmSMclOD.js");
708
+ const { createWizardPiTools } = await import("./tools-1aM6bI9Y.js");
709
709
  const { createWizardPiTaskTools } = await import("./tasks-BfJhVky2.js");
710
- const { createDispatchAgentTool } = await import("./subagent-DR5caRzL.js");
710
+ const { createDispatchAgentTool } = await import("./subagent-DQ_enM8C.js");
711
711
  const wizardTaskTools = createWizardPiTaskTools((tasks) => emit({
712
712
  kind: "tasks",
713
713
  tasks
@@ -997,11 +997,11 @@ const piBackend = {
997
997
  }
998
998
  },
999
999
  async runTask(inputs) {
1000
- const { runPiTask } = await import("./task-C1qKgsAf.js");
1000
+ const { runPiTask } = await import("./task-Dm9wZbVW.js");
1001
1001
  return runPiTask(inputs);
1002
1002
  }
1003
1003
  };
1004
1004
  //#endregion
1005
1005
  export { piBackend as a, runErrorType as c, createEmitSpinner as d, createProgressCollector as f, lastStatusLine as i, createAioCapture as l, buildScrubbedEnv as n, withMode as o, appendStatus as p, extractText as r, bindPiCancellation as s, applyOutroMarkers as t, createEmitLog as u };
1006
1006
 
1007
- //# sourceMappingURL=pi-Cw7CPXSl.js.map
1007
+ //# sourceMappingURL=pi-DREdQRPP.js.map