agentix-cli 0.150.0 → 0.152.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/README.md +0 -1
  2. package/dist/{App-2O2UUZGG.js → App-NCB3Y5DS.js} +2 -2
  3. package/dist/{ChatApp-YU4NF63L.js → ChatApp-HOWN5H7Y.js} +2 -2
  4. package/dist/{absorb-eval-WHWOJYDX.js → absorb-eval-JXRNSZII.js} +2 -2
  5. package/dist/agent-DMXUUMEU.js +2 -0
  6. package/dist/{board-dashboard-VPDXHHWC.js → board-dashboard-POWARL34.js} +402 -241
  7. package/dist/board-dashboard-POWARL34.js.map +1 -0
  8. package/dist/chunk-24QMHUU2.js +5 -0
  9. package/dist/chunk-24QMHUU2.js.map +1 -0
  10. package/dist/{chunk-ATCIRFH6.js → chunk-7UH3DXAG.js} +2 -2
  11. package/dist/chunk-ADG6NBZY.js +862 -0
  12. package/dist/chunk-ADG6NBZY.js.map +1 -0
  13. package/dist/{chunk-NW4N67TU.js → chunk-CZEBLLZQ.js} +2 -2
  14. package/dist/{chunk-2MW32M2D.js → chunk-DZUJP6L7.js} +2 -2
  15. package/dist/{chunk-NMYC5RW7.js → chunk-E4V5EADX.js} +6 -6
  16. package/dist/{chunk-6YNRLI6I.js → chunk-GI5CY27P.js} +2 -2
  17. package/dist/{chunk-IGA3T3ZT.js → chunk-HS7ATV4Z.js} +2 -2
  18. package/dist/{chunk-S22IBRY6.js → chunk-ILZRO6SN.js} +2 -2
  19. package/dist/{chunk-UG2OF2EI.js → chunk-IVBCCSDR.js} +2 -2
  20. package/dist/chunk-JDX7AYIB.js +7 -0
  21. package/dist/chunk-JDX7AYIB.js.map +1 -0
  22. package/dist/{chunk-QZ6VBDMX.js → chunk-JHAQE46R.js} +46 -46
  23. package/dist/chunk-JHAQE46R.js.map +1 -0
  24. package/dist/chunk-JJOLZPUY.js +35 -0
  25. package/dist/chunk-JJOLZPUY.js.map +1 -0
  26. package/dist/{chunk-2PJKGZWP.js → chunk-JNG3P5V2.js} +2 -2
  27. package/dist/chunk-JNG3P5V2.js.map +1 -0
  28. package/dist/{chunk-GMMRBTLQ.js → chunk-LDLRDBAD.js} +2 -2
  29. package/dist/{chunk-EIY2HRAS.js → chunk-LOTCKF22.js} +2 -2
  30. package/dist/chunk-MTBY46CL.js +181 -0
  31. package/dist/chunk-MTBY46CL.js.map +1 -0
  32. package/dist/chunk-OSH2PEBH.js +2 -0
  33. package/dist/{chunk-JXF54PT7.js.map → chunk-OSH2PEBH.js.map} +1 -1
  34. package/dist/{chunk-6TJNWUMA.js → chunk-P25TJ4XN.js} +3 -3
  35. package/dist/{chunk-Y5GI35AZ.js → chunk-P4EZJIQ4.js} +308 -297
  36. package/dist/chunk-P4EZJIQ4.js.map +1 -0
  37. package/dist/{chunk-6QFDFYI7.js → chunk-PC24JMEH.js} +2 -2
  38. package/dist/{chunk-5IHUZVPU.js → chunk-PGLTBNGZ.js} +2 -2
  39. package/dist/{chunk-AONY6U45.js → chunk-QSNKF5VD.js} +2 -2
  40. package/dist/{chunk-JOHDOEZ4.js → chunk-R4R7EYY3.js} +2 -2
  41. package/dist/{chunk-OWMKQ4HZ.js → chunk-RNAKP7WY.js} +2 -2
  42. package/dist/chunk-SQUTRMKH.js +67 -0
  43. package/dist/chunk-SQUTRMKH.js.map +1 -0
  44. package/dist/{chunk-GRI5HOPC.js → chunk-TNZBQAUR.js} +2 -2
  45. package/dist/{chunk-Y5MFVVTM.js → chunk-U23LVMMZ.js} +2 -2
  46. package/dist/{chunk-BZ6Y264Z.js → chunk-UFYKUC4E.js} +2 -2
  47. package/dist/{chunk-5QXRPYOY.js → chunk-VIZVF6KH.js} +2 -2
  48. package/dist/{chunk-E7LPZAXP.js → chunk-XE3CGJV4.js} +2 -2
  49. package/dist/{chunk-3HVRWULP.js → chunk-YBUCVI45.js} +2 -2
  50. package/dist/{chunk-DWOERPBG.js → chunk-YJZQRFET.js} +2 -2
  51. package/dist/cli.js +1 -1
  52. package/dist/{client-A2N6ETK2.js → client-6IOWB5AT.js} +2 -2
  53. package/dist/{compaction-FS6XNRLM.js → compaction-PFXWL4H7.js} +3 -3
  54. package/dist/{config-2QM2WTI2.js → config-SHIT5WJE.js} +2 -2
  55. package/dist/{config-mutate-UJS4F7BT.js → config-mutate-6ACI5COM.js} +2 -2
  56. package/dist/config-mutator-LAEX6HOH.js +2 -0
  57. package/dist/{context-planner-3JDA7FNR.js → context-planner-DJB6CKY6.js} +2 -2
  58. package/dist/{contributions-43FWZOGF.js → contributions-N7K6LNL7.js} +2 -2
  59. package/dist/doctor-T7QAQRCJ.js +2 -0
  60. package/dist/{follow-up-tool-VB7K6HCL.js → follow-up-tool-HQ2GWF4K.js} +2 -2
  61. package/dist/{grants-2S33F2LV.js → grants-HSLB62EG.js} +2 -2
  62. package/dist/heal-RGM7X2ZG.js +2 -0
  63. package/dist/hub-53IMEYGX.js +2 -0
  64. package/dist/index.d.ts +167 -6
  65. package/dist/index.js +1 -1
  66. package/dist/memory-extract-GHLBXV4H.js +2 -0
  67. package/dist/{program-ZNTQK36Z.js → program-LSXONKPW.js} +234 -228
  68. package/dist/program-LSXONKPW.js.map +1 -0
  69. package/dist/{promote-VFYVWVTL.js → promote-626PE5VM.js} +2 -2
  70. package/dist/{providers-55NC2SFN.js → providers-BDJXGHEY.js} +2 -2
  71. package/dist/{query-RB2MU2HV.js → query-GR3SOD6A.js} +2 -2
  72. package/dist/{query-settings-5B54WHCS.js → query-settings-6XZHNFXE.js} +2 -2
  73. package/dist/{registry-6OX7U6FV.js → registry-SAY7ROZV.js} +2 -2
  74. package/dist/{request-planner-TUHVEYSF.js → request-planner-DWYXUVF4.js} +2 -2
  75. package/dist/{review-candidates-FDYTGG2N.js → review-candidates-GXWMKZKA.js} +2 -2
  76. package/dist/routing-TB6BBRH4.js +2 -0
  77. package/dist/schedule-tool-EI2SRMZM.js +2 -0
  78. package/dist/{scheduler-H2QHWNQ2.js → scheduler-VOZIMG5F.js} +2 -2
  79. package/dist/{seat-EB3KJMIE.js → seat-H6F6H55Y.js} +2 -2
  80. package/dist/{select-IU4IOVSO.js → select-OUBL6EMZ.js} +2 -2
  81. package/dist/{set-enabled-64BSJ7LR.js → set-enabled-NYJHFXHY.js} +2 -2
  82. package/dist/tool-FWATXW5Q.js +6 -0
  83. package/dist/tool-FWATXW5Q.js.map +1 -0
  84. package/dist/{tool-B23ACEHV.js → tool-HXFGNBLS.js} +2 -2
  85. package/dist/wiki-PG5ZBOMH.js +2 -0
  86. package/dist/wiki-enrich-BIQZWJRB.js +2 -0
  87. package/package.json +1 -1
  88. package/dist/agent-NLCR6VBE.js +0 -2
  89. package/dist/board-dashboard-VPDXHHWC.js.map +0 -1
  90. package/dist/chunk-2PJKGZWP.js.map +0 -1
  91. package/dist/chunk-A76PNG4E.js +0 -4
  92. package/dist/chunk-A76PNG4E.js.map +0 -1
  93. package/dist/chunk-JXF54PT7.js +0 -2
  94. package/dist/chunk-P34VSROA.js +0 -7
  95. package/dist/chunk-P34VSROA.js.map +0 -1
  96. package/dist/chunk-PXKIPU27.js +0 -64
  97. package/dist/chunk-PXKIPU27.js.map +0 -1
  98. package/dist/chunk-QZ6VBDMX.js.map +0 -1
  99. package/dist/chunk-UZWF7PFH.js +0 -861
  100. package/dist/chunk-UZWF7PFH.js.map +0 -1
  101. package/dist/chunk-WGPMUWX7.js +0 -35
  102. package/dist/chunk-WGPMUWX7.js.map +0 -1
  103. package/dist/chunk-Y5GI35AZ.js.map +0 -1
  104. package/dist/chunk-Z7GEW2SR.js +0 -174
  105. package/dist/chunk-Z7GEW2SR.js.map +0 -1
  106. package/dist/config-mutator-VWR3SMD3.js +0 -2
  107. package/dist/doctor-IN6MWP6I.js +0 -2
  108. package/dist/heal-U67X6NIN.js +0 -2
  109. package/dist/hub-JNNNUAZM.js +0 -2
  110. package/dist/memory-extract-ATD6YLRK.js +0 -2
  111. package/dist/program-ZNTQK36Z.js.map +0 -1
  112. package/dist/routing-U35SFPEI.js +0 -2
  113. package/dist/schedule-tool-EPQKUYJX.js +0 -2
  114. package/dist/tool-W3CIQZJ7.js +0 -6
  115. package/dist/tool-W3CIQZJ7.js.map +0 -1
  116. package/dist/wiki-4KMRUD5C.js +0 -2
  117. package/dist/wiki-enrich-N4GLW2JX.js +0 -2
  118. /package/dist/{App-2O2UUZGG.js.map → App-NCB3Y5DS.js.map} +0 -0
  119. /package/dist/{ChatApp-YU4NF63L.js.map → ChatApp-HOWN5H7Y.js.map} +0 -0
  120. /package/dist/{absorb-eval-WHWOJYDX.js.map → absorb-eval-JXRNSZII.js.map} +0 -0
  121. /package/dist/{agent-NLCR6VBE.js.map → agent-DMXUUMEU.js.map} +0 -0
  122. /package/dist/{chunk-ATCIRFH6.js.map → chunk-7UH3DXAG.js.map} +0 -0
  123. /package/dist/{chunk-NW4N67TU.js.map → chunk-CZEBLLZQ.js.map} +0 -0
  124. /package/dist/{chunk-2MW32M2D.js.map → chunk-DZUJP6L7.js.map} +0 -0
  125. /package/dist/{chunk-NMYC5RW7.js.map → chunk-E4V5EADX.js.map} +0 -0
  126. /package/dist/{chunk-6YNRLI6I.js.map → chunk-GI5CY27P.js.map} +0 -0
  127. /package/dist/{chunk-IGA3T3ZT.js.map → chunk-HS7ATV4Z.js.map} +0 -0
  128. /package/dist/{chunk-S22IBRY6.js.map → chunk-ILZRO6SN.js.map} +0 -0
  129. /package/dist/{chunk-UG2OF2EI.js.map → chunk-IVBCCSDR.js.map} +0 -0
  130. /package/dist/{chunk-GMMRBTLQ.js.map → chunk-LDLRDBAD.js.map} +0 -0
  131. /package/dist/{chunk-EIY2HRAS.js.map → chunk-LOTCKF22.js.map} +0 -0
  132. /package/dist/{chunk-6TJNWUMA.js.map → chunk-P25TJ4XN.js.map} +0 -0
  133. /package/dist/{chunk-6QFDFYI7.js.map → chunk-PC24JMEH.js.map} +0 -0
  134. /package/dist/{chunk-5IHUZVPU.js.map → chunk-PGLTBNGZ.js.map} +0 -0
  135. /package/dist/{chunk-AONY6U45.js.map → chunk-QSNKF5VD.js.map} +0 -0
  136. /package/dist/{chunk-JOHDOEZ4.js.map → chunk-R4R7EYY3.js.map} +0 -0
  137. /package/dist/{chunk-OWMKQ4HZ.js.map → chunk-RNAKP7WY.js.map} +0 -0
  138. /package/dist/{chunk-GRI5HOPC.js.map → chunk-TNZBQAUR.js.map} +0 -0
  139. /package/dist/{chunk-Y5MFVVTM.js.map → chunk-U23LVMMZ.js.map} +0 -0
  140. /package/dist/{chunk-BZ6Y264Z.js.map → chunk-UFYKUC4E.js.map} +0 -0
  141. /package/dist/{chunk-5QXRPYOY.js.map → chunk-VIZVF6KH.js.map} +0 -0
  142. /package/dist/{chunk-E7LPZAXP.js.map → chunk-XE3CGJV4.js.map} +0 -0
  143. /package/dist/{chunk-3HVRWULP.js.map → chunk-YBUCVI45.js.map} +0 -0
  144. /package/dist/{chunk-DWOERPBG.js.map → chunk-YJZQRFET.js.map} +0 -0
  145. /package/dist/{client-A2N6ETK2.js.map → client-6IOWB5AT.js.map} +0 -0
  146. /package/dist/{compaction-FS6XNRLM.js.map → compaction-PFXWL4H7.js.map} +0 -0
  147. /package/dist/{config-2QM2WTI2.js.map → config-SHIT5WJE.js.map} +0 -0
  148. /package/dist/{config-mutate-UJS4F7BT.js.map → config-mutate-6ACI5COM.js.map} +0 -0
  149. /package/dist/{config-mutator-VWR3SMD3.js.map → config-mutator-LAEX6HOH.js.map} +0 -0
  150. /package/dist/{context-planner-3JDA7FNR.js.map → context-planner-DJB6CKY6.js.map} +0 -0
  151. /package/dist/{contributions-43FWZOGF.js.map → contributions-N7K6LNL7.js.map} +0 -0
  152. /package/dist/{doctor-IN6MWP6I.js.map → doctor-T7QAQRCJ.js.map} +0 -0
  153. /package/dist/{follow-up-tool-VB7K6HCL.js.map → follow-up-tool-HQ2GWF4K.js.map} +0 -0
  154. /package/dist/{grants-2S33F2LV.js.map → grants-HSLB62EG.js.map} +0 -0
  155. /package/dist/{heal-U67X6NIN.js.map → heal-RGM7X2ZG.js.map} +0 -0
  156. /package/dist/{hub-JNNNUAZM.js.map → hub-53IMEYGX.js.map} +0 -0
  157. /package/dist/{memory-extract-ATD6YLRK.js.map → memory-extract-GHLBXV4H.js.map} +0 -0
  158. /package/dist/{promote-VFYVWVTL.js.map → promote-626PE5VM.js.map} +0 -0
  159. /package/dist/{providers-55NC2SFN.js.map → providers-BDJXGHEY.js.map} +0 -0
  160. /package/dist/{query-RB2MU2HV.js.map → query-GR3SOD6A.js.map} +0 -0
  161. /package/dist/{query-settings-5B54WHCS.js.map → query-settings-6XZHNFXE.js.map} +0 -0
  162. /package/dist/{registry-6OX7U6FV.js.map → registry-SAY7ROZV.js.map} +0 -0
  163. /package/dist/{request-planner-TUHVEYSF.js.map → request-planner-DWYXUVF4.js.map} +0 -0
  164. /package/dist/{review-candidates-FDYTGG2N.js.map → review-candidates-GXWMKZKA.js.map} +0 -0
  165. /package/dist/{routing-U35SFPEI.js.map → routing-TB6BBRH4.js.map} +0 -0
  166. /package/dist/{schedule-tool-EPQKUYJX.js.map → schedule-tool-EI2SRMZM.js.map} +0 -0
  167. /package/dist/{scheduler-H2QHWNQ2.js.map → scheduler-VOZIMG5F.js.map} +0 -0
  168. /package/dist/{seat-EB3KJMIE.js.map → seat-H6F6H55Y.js.map} +0 -0
  169. /package/dist/{select-IU4IOVSO.js.map → select-OUBL6EMZ.js.map} +0 -0
  170. /package/dist/{set-enabled-64BSJ7LR.js.map → set-enabled-NYJHFXHY.js.map} +0 -0
  171. /package/dist/{tool-B23ACEHV.js.map → tool-HXFGNBLS.js.map} +0 -0
  172. /package/dist/{wiki-4KMRUD5C.js.map → wiki-PG5ZBOMH.js.map} +0 -0
  173. /package/dist/{wiki-enrich-N4GLW2JX.js.map → wiki-enrich-BIQZWJRB.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/auth-store.ts","../src/agent/tools/definitions.ts","../src/agent/providers/claude.ts","../src/agent/providers/claude-code.ts","../src/agent/providers/openai.ts","../src/agent/providers/demo.ts","../src/agent/providers/index.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport path from \"path\"\nimport os from \"os\"\nimport chalk from \"chalk\"\nimport prompts from \"prompts\"\nimport { logger } from \"@/utils/logger\"\n\n// --- Auth config stored at ~/.agentx/auth.json ---\n\nexport interface AuthConfig {\n provider: \"claude\" | \"claude-code\"\n authType: \"api-key\" | \"oauth\"\n token: string\n model: string\n}\n\nconst AUTH_DIR = path.join(os.homedir(), \".agentx\")\nconst AUTH_FILE = path.join(AUTH_DIR, \"auth.json\")\n\nexport function loadAuthConfig(): AuthConfig | null {\n if (!existsSync(AUTH_FILE)) return null\n try {\n const data = JSON.parse(readFileSync(AUTH_FILE, \"utf8\"))\n if (data.provider && data.authType && data.token && data.model) {\n return data as AuthConfig\n }\n return null\n } catch {\n return null\n }\n}\n\nexport function saveAuthConfig(config: AuthConfig): void {\n if (!existsSync(AUTH_DIR)) {\n mkdirSync(AUTH_DIR, { recursive: true })\n }\n writeFileSync(AUTH_FILE, JSON.stringify(config, null, 2), \"utf8\")\n}\n\n/**\n * Resolve a token for the Anthropic API.\n * Priority: (1) explicit token, (2) env vars, (3) ~/.agentx/auth.json, (4) OpenClaw auth stores\n */\nexport function resolveToken(explicitKey?: string): {\n token: string\n authType: \"api-key\" | \"oauth\"\n} | null {\n // 1. Explicit CLI flag\n if (explicitKey?.trim()) {\n const type = explicitKey.startsWith(\"sk-ant-oat\") ? \"oauth\" : \"api-key\"\n return { token: explicitKey.trim(), authType: type }\n }\n\n // 2. Environment variables\n const envOAuth = process.env.ANTHROPIC_OAUTH_TOKEN\n if (envOAuth?.trim()) {\n return { token: envOAuth.trim(), authType: \"oauth\" }\n }\n\n // Claude Code's native env var (sk-ant-oat01-...). Same OAuth token format\n // as ANTHROPIC_OAUTH_TOKEN but Claude Code sets it under its own name, so\n // without this fallback the SDK providers fail to resolve even though the\n // `claude` CLI in the same shell works fine. Enables the context planner\n // to use the fast SDK path instead of cold-spawning a subprocess.\n const envClaudeCodeOAuth = process.env.CLAUDE_CODE_OAUTH_TOKEN\n if (envClaudeCodeOAuth?.trim()) {\n return { token: envClaudeCodeOAuth.trim(), authType: \"oauth\" }\n }\n\n const envApiKey = process.env.ANTHROPIC_API_KEY\n if (envApiKey?.trim()) {\n return { token: envApiKey.trim(), authType: \"api-key\" }\n }\n\n // 3. Stored config\n const stored = loadAuthConfig()\n if (stored) {\n return { token: stored.token, authType: stored.authType }\n }\n\n // 4. OpenClaw auth-profiles store (legacy fallback)\n const homeDir = os.homedir()\n const storePaths = [\n path.join(homeDir, \".openclaw\", \"agents\", \"main\", \"agent\", \"auth-profiles.json\"),\n path.join(homeDir, \".openclaw\", \"auth-profiles.json\"),\n path.join(homeDir, \".openclaw\", \"credentials\", \"oauth.json\"),\n path.join(homeDir, \".claude\", \"oauth.json\"),\n path.join(homeDir, \".config\", \"claude\", \"oauth.json\"),\n path.join(homeDir, \".config\", \"anthropic\", \"oauth.json\"),\n ]\n\n for (const p of storePaths) {\n const t = readTokenFromAuthProfiles(p)\n if (t) {\n return { token: t, authType: \"oauth\" }\n }\n }\n\n return null\n}\n\n/**\n * Read an Anthropic OAuth/token credential from an auth-profiles or oauth JSON file.\n */\nfunction readTokenFromAuthProfiles(filePath: string): string {\n if (!existsSync(filePath)) return \"\"\n\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf8\"))\n\n // Modern auth-profiles format: { profiles: { \"anthropic:xxx\": { type, access/token } } }\n if (data.profiles) {\n let fallbackToken = \"\"\n for (const [id, cred] of Object.entries(data.profiles) as [string, any][]) {\n if (!id.startsWith(\"anthropic\")) continue\n if (cred.type === \"oauth\" && cred.access) {\n if (cred.expires && Date.now() > cred.expires) {\n continue\n }\n return cred.access\n }\n if (cred.type === \"token\" && cred.token) {\n fallbackToken = cred.token\n }\n }\n if (fallbackToken) return fallbackToken\n }\n\n // Legacy oauth.json format: { anthropic: { access: \"...\" } }\n if (data.anthropic?.access) return data.anthropic.access\n if (data.anthropic?.token) return data.anthropic.token\n\n return \"\"\n } catch {\n return \"\"\n }\n}\n\n// --- Model setup & credentials ---\n\nconst ANTHROPIC_MODELS = [\n { id: \"claude-sonnet-4-20250514\", label: \"anthropic/claude-sonnet-4\", hint: \"Claude Sonnet 4 · ctx 200k · recommended\" },\n { id: \"claude-opus-4-20250514\", label: \"anthropic/claude-opus-4-5\", hint: \"Claude Opus 4.5 · ctx 200k · reasoning\" },\n { id: \"claude-haiku-4-20250514\", label: \"anthropic/claude-haiku-4\", hint: \"Claude Haiku 4 · ctx 200k · fast\" },\n]\n\nasync function handleApiKey(): Promise<{ token: string; authType: \"api-key\" } | null> {\n const envKey = process.env.ANTHROPIC_API_KEY\n if (envKey?.trim()) {\n const preview = envKey.slice(0, 10) + \"...\" + envKey.slice(-4)\n const { useExisting } = await prompts({\n type: \"confirm\",\n name: \"useExisting\",\n message: `Use existing ANTHROPIC_API_KEY (env, ${preview})?`,\n initial: true,\n })\n\n if (useExisting) {\n return { token: envKey.trim(), authType: \"api-key\" }\n }\n }\n\n const stored = loadAuthConfig()\n if (stored?.authType === \"api-key\" && stored.token) {\n const preview = stored.token.slice(0, 10) + \"...\" + stored.token.slice(-4)\n const { useExisting } = await prompts({\n type: \"confirm\",\n name: \"useExisting\",\n message: `Use stored API key (${preview})?`,\n initial: true,\n })\n\n if (useExisting) {\n return { token: stored.token, authType: \"api-key\" }\n }\n }\n\n const { apiKey } = await prompts({\n type: \"password\",\n name: \"apiKey\",\n message: \"Enter Anthropic API key\",\n validate: (v: string) => {\n if (!v.startsWith(\"sk-ant-api\")) return \"API key must start with sk-ant-api\"\n if (v.length < 40) return \"API key seems too short\"\n return true\n },\n })\n\n if (!apiKey) return null\n return { token: apiKey, authType: \"api-key\" }\n}\n\nasync function handleSetupToken(): Promise<{ token: string; authType: \"oauth\" } | null> {\n logger.break()\n const boxWidth = 46\n const line1 = \"Run `claude setup-token` in your terminal.\"\n const line2 = \"Then paste the generated token below.\"\n console.log(` ${chalk.cyan(\"Anthropic setup-token\")} ${\"─\".repeat(boxWidth - \"Anthropic setup-token\".length - 1)}╮`)\n console.log(` ${\" \".repeat(boxWidth)}│`)\n console.log(` ${line1}${\" \".repeat(boxWidth - line1.length)}│`)\n console.log(` ${line2}${\" \".repeat(boxWidth - line2.length)}│`)\n console.log(` ${\" \".repeat(boxWidth)}│`)\n console.log(` ${\"─\".repeat(boxWidth)}╯`)\n logger.break()\n\n const { token } = await prompts({\n type: \"password\",\n name: \"token\",\n message: \"Paste Anthropic setup-token\",\n validate: (v: string) => {\n if (!v.trim()) return \"Token is required\"\n if (v.length < 40) return \"Token seems too short\"\n return true\n },\n })\n\n if (!token) return null\n\n const { tokenName } = await prompts({\n type: \"text\",\n name: \"tokenName\",\n message: \"Token name (blank = default)\",\n })\n\n return { token, authType: \"oauth\" }\n}\n\ntype AuthResult = { token: string; authType: \"api-key\" | \"oauth\" } | null\n\nasync function selectAuthMethod(): Promise<AuthResult> {\n while (true) {\n const { provider } = await prompts({\n type: \"select\",\n name: \"provider\",\n message: \"Model/auth provider\",\n choices: [\n { title: \"Anthropic\", value: \"anthropic\", description: \"setup-token + API key\" },\n ],\n })\n\n if (provider === undefined) return null\n\n const { method } = await prompts({\n type: \"select\",\n name: \"method\",\n message: \"Anthropic auth method\",\n choices: [\n { title: \"Anthropic token (paste setup-token)\", value: \"setup-token\", description: \"run `claude setup-token` elsewhere, then paste the token here\" },\n { title: \"Anthropic API key\", value: \"api-key\" },\n { title: chalk.dim(\"Back\"), value: \"back\" },\n ],\n })\n\n if (method === undefined) return null\n if (method === \"back\") continue\n\n if (method === \"api-key\") return handleApiKey()\n if (method === \"setup-token\") return handleSetupToken()\n\n return null\n }\n}\n\nasync function selectModel(): Promise<string | null> {\n const stored = loadAuthConfig()\n\n const choices = ANTHROPIC_MODELS.map((m) => ({\n title: m.label,\n value: m.id,\n description: m.hint + (stored?.model === m.id ? \" · current\" : \"\"),\n }))\n\n if (stored?.model) {\n const current = ANTHROPIC_MODELS.find((m) => m.id === stored.model)\n const label = current ? current.label : stored.model\n choices.unshift({\n title: `Keep current (${label})`,\n value: stored.model,\n description: \"no change\",\n })\n }\n\n const { modelId } = await prompts({\n type: \"select\",\n name: \"modelId\",\n message: \"Default model\",\n choices,\n })\n\n return modelId || null\n}\n\n/**\n * Reusable interactive setup flow. Returns the saved config, or null if the user cancelled.\n */\nexport async function runModelSetup(): Promise<AuthConfig | null> {\n const auth = await selectAuthMethod()\n if (!auth) return null\n\n const modelId = await selectModel()\n if (!modelId) return null\n\n const config: AuthConfig = {\n provider: auth.authType === \"oauth\" ? \"claude-code\" : \"claude\",\n authType: auth.authType,\n token: auth.token,\n model: modelId,\n }\n\n saveAuthConfig(config)\n\n logger.break()\n logger.success(\"Configuration saved to ~/.agentx/auth.json\")\n console.log(` Provider: ${chalk.bold(\"anthropic\")} (${config.authType})`)\n console.log(` Model: ${chalk.bold(ANTHROPIC_MODELS.find((m) => m.id === config.model)?.label || config.model)}`)\n\n return config\n}\n\n/**\n * Ensure credentials are available. If not, auto-prompt the interactive setup.\n * Returns true if credentials are ready, false if user cancelled.\n */\nexport async function ensureCredentials(explicitKey?: string): Promise<boolean> {\n const resolved = resolveToken(explicitKey)\n if (resolved) return true\n\n logger.warn(\"No AI credentials configured.\")\n logger.break()\n\n const result = await runModelSetup()\n return result !== null\n}\n","// --- Agent tool definitions in Anthropic tool_use format ---\n\nexport interface ToolDefinition {\n name: string\n description: string\n input_schema: Record<string, unknown>\n permission?: \"file-read\" | \"file-write\" | \"command\" | \"none\"\n}\n\nconst TOOL_DEFINITIONS: ToolDefinition[] = [\n {\n name: \"create_files\",\n description:\n \"Create one or more files as output. Use this when you need to generate code, documents, configs, or any file-based output.\",\n input_schema: {\n type: \"object\",\n properties: {\n files: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Relative file path from project root (e.g., src/components/Button.tsx)\",\n },\n content: {\n type: \"string\",\n description: \"The full content of the file\",\n },\n language: {\n type: \"string\",\n description: \"Programming language or file type\",\n },\n description: {\n type: \"string\",\n description: \"Brief description of what this file does\",\n },\n },\n required: [\"path\", \"content\"],\n },\n },\n summary: {\n type: \"string\",\n description: \"Brief summary of all generated files\",\n },\n },\n required: [\"files\"],\n },\n permission: \"file-write\",\n },\n {\n name: \"ask_user\",\n description:\n \"Ask the user a clarifying question when you need more information to proceed. Use this when the request is ambiguous or you need to confirm important decisions.\",\n input_schema: {\n type: \"object\",\n properties: {\n question: {\n type: \"string\",\n description: \"The question to ask the user\",\n },\n options: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Optional list of choices for the user\",\n },\n },\n required: [\"question\"],\n },\n permission: \"none\",\n },\n {\n name: \"read_file\",\n description:\n \"Read the contents of a file. Use this to inspect existing code, understand patterns, check implementations, or gather context before generating code.\",\n input_schema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description: \"Relative file path from project root\",\n },\n max_lines: {\n type: \"number\",\n description:\n \"Maximum number of lines to read. Defaults to 500. Use for large files.\",\n },\n },\n required: [\"path\"],\n },\n permission: \"file-read\",\n },\n {\n name: \"search_files\",\n description:\n \"Search for files matching a pattern and optionally search their content with a regex. Use this to find relevant code, understand project structure, or locate specific patterns.\",\n input_schema: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description:\n \"Glob pattern to match files (e.g., 'src/**/*.ts', '*.json')\",\n },\n content_regex: {\n type: \"string\",\n description:\n \"Optional regex to search within matched files. Returns matching lines.\",\n },\n max_results: {\n type: \"number\",\n description: \"Maximum number of results to return. Default: 50.\",\n },\n },\n required: [\"pattern\"],\n },\n permission: \"none\",\n },\n {\n name: \"list_directory\",\n description:\n \"List files and directories at a given path. Use this to explore project structure.\",\n input_schema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Relative directory path from project root. Defaults to '.' (root).\",\n },\n recursive: {\n type: \"boolean\",\n description: \"List recursively. Default: false.\",\n },\n max_depth: {\n type: \"number\",\n description: \"Maximum depth for recursive listing. Default: 3.\",\n },\n },\n },\n permission: \"none\",\n },\n {\n name: \"run_command\",\n description:\n \"Execute a shell command. Use this to run build tools, test commands, linters, or inspect the environment. Commands run in the project root directory.\",\n input_schema: {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description: \"The shell command to execute\",\n },\n timeout: {\n type: \"number\",\n description:\n \"Timeout in milliseconds. Default: 30000 (30 seconds).\",\n },\n },\n required: [\"command\"],\n },\n permission: \"command\",\n },\n {\n name: \"edit_file\",\n description:\n \"Apply search-and-replace edits to an existing file. Use this for targeted modifications to existing code rather than rewriting entire files.\",\n input_schema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description: \"Relative file path from project root\",\n },\n edits: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n old_text: {\n type: \"string\",\n description: \"The exact text to find in the file\",\n },\n new_text: {\n type: \"string\",\n description: \"The replacement text\",\n },\n },\n required: [\"old_text\", \"new_text\"],\n },\n description: \"List of search/replace pairs to apply in order\",\n },\n },\n required: [\"path\", \"edits\"],\n },\n permission: \"file-write\",\n },\n {\n name: \"spawn_agent\",\n description:\n \"Spawn a sub-agent to handle a task in the background. The sub-agent runs in its own session and returns results. Use this for parallel research, long-running tasks, or delegating work to a specialized agent.\",\n input_schema: {\n type: \"object\",\n properties: {\n agent_id: {\n type: \"string\",\n description: \"The ID of the agent to spawn (must be a registered agent)\",\n },\n prompt: {\n type: \"string\",\n description: \"The task description for the sub-agent\",\n },\n timeout_seconds: {\n type: \"number\",\n description: \"Maximum time to wait for completion in seconds. Default: 300 (5 minutes).\",\n },\n },\n required: [\"agent_id\", \"prompt\"],\n },\n permission: \"none\",\n },\n]\n\n/**\n * Get all tool definitions in Anthropic API format (for generateRaw()).\n * Optionally filter by enabled tool names.\n */\nexport function getAnthropicTools(enabledTools?: string[]): Array<{\n name: string\n description: string\n input_schema: Record<string, unknown>\n}> {\n const defs = enabledTools\n ? TOOL_DEFINITIONS.filter((t) => enabledTools.includes(t.name))\n : TOOL_DEFINITIONS\n\n return defs.map(({ name, description, input_schema }) => ({\n name,\n description,\n input_schema,\n }))\n}\n\n/**\n * Get the legacy tools (create_files + ask_user) for backward compatibility.\n */\nexport function getLegacyTools(): Array<{\n name: string\n description: string\n input_schema: Record<string, unknown>\n}> {\n return getAnthropicTools([\"create_files\", \"ask_user\"])\n}\n\n/**\n * Format tool descriptions for inclusion in a system prompt.\n * Used when the `claude` CLI binary handles its own tools —\n * we describe our additional tools as text so the binary's built-in\n * capabilities (read, write, bash) handle them natively.\n */\nexport function formatToolsForSystemPrompt(): string {\n const agenticTools = TOOL_DEFINITIONS.filter(\n (t) => t.name !== \"create_files\" && t.name !== \"ask_user\"\n )\n\n if (agenticTools.length === 0) return \"\"\n\n const lines = [\n \"# Available Capabilities\",\n \"In addition to generating files, you have the following capabilities:\",\n \"\",\n ]\n\n for (const tool of agenticTools) {\n lines.push(`## ${tool.name}`)\n lines.push(tool.description)\n lines.push(\"\")\n }\n\n return lines.join(\"\\n\")\n}\n\nexport const ALL_TOOL_NAMES = TOOL_DEFINITIONS.map((t) => t.name)\n","import type {\n AgentProvider,\n GenerationMessage,\n GenerationResult,\n GeneratedFile,\n ProviderOptions,\n StreamEvent,\n AnthropicMessage,\n RawGenerationResult,\n RawStreamEvent,\n ContentBlock,\n} from \"./types\"\nimport { resolveToken } from \"@/utils/auth-store\"\nimport { getLegacyTools } from \"../tools/definitions\"\n\n// --- Claude provider (default) using Anthropic SDK ---\n\nconst DEFAULT_MODEL = \"claude-sonnet-4-20250514\"\nconst DEFAULT_MAX_TOKENS = 8192\n// Min tokens for Anthropic prompt-cache eligibility (varies by model:\n// 1024 Haiku / 2048 Sonnet / 4096 Opus). Below threshold the API\n// silently skips caching. We wrap unconditionally — cheap when it\n// doesn't fit, big win when it does. Voice/text on acme-public have\n// 40K-token system prompts so caching always kicks in there.\nconst CACHE_MIN_CHARS = 4 * 1024 // ~1k tokens at 4 char/tok\n\n/**\n * Wrap a system-prompt string in an Anthropic structured-block array\n * with `cache_control: { type: \"ephemeral\" }`. Returns a plain string\n * when the prompt is too short to be cache-eligible (saves a request-\n * shape change that wouldn't help). Cache TTL is the default 5 minutes;\n * suitable for back-to-back chat turns within a session.\n */\nfunction wrapSystemForCache(systemPrompt: string): unknown {\n if (!systemPrompt || systemPrompt.length < CACHE_MIN_CHARS) {\n return systemPrompt\n }\n return [\n {\n type: \"text\",\n text: systemPrompt,\n cache_control: { type: \"ephemeral\" },\n },\n ]\n}\n\ninterface AnthropicResponse {\n id: string\n content: Array<{\n type: \"text\" | \"tool_use\" | \"tool_result\"\n text?: string\n id?: string\n name?: string\n input?: Record<string, unknown>\n tool_use_id?: string\n content?: string\n }>\n model: string\n stop_reason: string\n usage: { input_tokens: number; output_tokens: number }\n}\n\nexport class ClaudeProvider implements AgentProvider {\n name = \"claude\"\n private apiKey: string\n private authType: \"api-key\" | \"oauth\" = \"api-key\"\n\n constructor(apiKey?: string) {\n this.apiKey = apiKey || process.env.ANTHROPIC_API_KEY || \"\"\n if (!this.apiKey) {\n // Fallback to auth store\n const resolved = resolveToken()\n if (resolved) {\n this.apiKey = resolved.token\n this.authType = resolved.authType\n }\n }\n if (!this.apiKey) {\n throw new Error(\n \"Anthropic API key required. Run `agentx model` to configure, set ANTHROPIC_API_KEY, or pass --api-key.\"\n )\n }\n }\n\n async generate(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): Promise<GenerationResult> {\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n // Extract system message\n const systemMsg = messages.find((m) => m.role === \"system\")\n const conversationMsgs = messages\n .filter((m) => m.role !== \"system\")\n .map((m) => ({\n role: m.role as \"user\" | \"assistant\",\n content: m.content,\n }))\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: conversationMsgs,\n tools: getLegacyTools(),\n }\n\n if (systemMsg) {\n body.system = wrapSystemForCache(systemMsg.content)\n }\n\n if (options?.temperature !== undefined) {\n body.temperature = options.temperature\n }\n\n const response = await this.callApi(body, options)\n\n return this.parseResponse(response)\n }\n\n async generateRaw(\n messages: AnthropicMessage[],\n systemPrompt: string,\n tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions\n ): Promise<RawGenerationResult> {\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n system: wrapSystemForCache(systemPrompt),\n messages,\n tools,\n }\n\n if (options?.temperature !== undefined) {\n body.temperature = options.temperature\n }\n\n if (options?.toolChoice) {\n body.tool_choice = { type: \"tool\", name: options.toolChoice.name }\n }\n\n const response = await this.callApi(body, options)\n\n // Map response content blocks to our ContentBlock type\n const content: ContentBlock[] = response.content.map((block) => {\n if (block.type === \"text\") {\n return { type: \"text\" as const, text: block.text || \"\" }\n }\n if (block.type === \"tool_use\") {\n return {\n type: \"tool_use\" as const,\n id: block.id || \"\",\n name: block.name || \"\",\n input: block.input || {},\n }\n }\n return { type: \"text\" as const, text: \"\" }\n })\n\n return {\n content,\n stop_reason: response.stop_reason as RawGenerationResult[\"stop_reason\"],\n usage: response.usage,\n }\n }\n\n async *stream(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): AsyncIterable<StreamEvent> {\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const systemMsg = messages.find((m) => m.role === \"system\")\n const conversationMsgs = messages\n .filter((m) => m.role !== \"system\")\n .map((m) => ({\n role: m.role as \"user\" | \"assistant\",\n content: m.content,\n }))\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: conversationMsgs,\n stream: true,\n tools: getLegacyTools(),\n }\n\n if (systemMsg) {\n body.system = wrapSystemForCache(systemMsg.content)\n }\n\n const headers = this.buildHeaders()\n\n const res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.abortSignal,\n })\n\n if (!res.ok) {\n const errorText = await res.text()\n yield { type: \"error\", error: `Anthropic API error (${res.status}): ${errorText}` }\n return\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n yield { type: \"error\", error: \"No response body\" }\n return\n }\n\n const decoder = new TextDecoder()\n let buffer = \"\"\n const files: GeneratedFile[] = []\n let content = \"\"\n let followUp: string | undefined\n let tokensUsed = 0\n let activeTool: { name: string; id: string; json: string } | null = null\n\n const inferFollowUpFromText = (text: string): string | undefined => {\n const cleaned = (text || \"\").trim()\n if (!cleaned) return undefined\n if (cleaned.includes(\"```\")) return undefined\n\n const lines = cleaned.replace(/\\r\\n/g, \"\\n\").split(\"\\n\")\n const tail = lines.slice(Math.max(0, lines.length - 20))\n const tailText = tail.join(\"\\n\")\n\n const looksLikePlanApproval =\n /\\b(plan|proposal)\\b/i.test(tailText) &&\n /(ready for your review|review (the )?plan|requesting plan approval|awaiting approval|waiting for (your )?approval|approve (the )?plan|approval to proceed)/i.test(\n tailText\n )\n\n if (looksLikePlanApproval) {\n return (\n \"The provider is requesting plan approval.\\n\" +\n \"Reply with:\\n\" +\n \"- approve\\n\" +\n \"- revise: <what to change>\\n\" +\n \"- cancel\"\n )\n }\n\n const isIntro = (l: string) =>\n /^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(\n l.trim()\n )\n\n let startIdx = -1\n for (let i = tail.length - 1; i >= 0; i--) {\n const l = tail[i].trim()\n if (!l) continue\n if (isIntro(l) || l.includes(\"?\")) {\n startIdx = i\n break\n }\n }\n if (startIdx === -1) return undefined\n\n const out: string[] = []\n for (let i = startIdx; i < tail.length && out.length < 8; i++) {\n const l = tail[i]\n const t = l.trim()\n if (out.length > 0 && !t) break\n if (\n out.length > 0 &&\n !/^(options?:|[-*]\\s|\\d+[\\).]\\s)/i.test(t) &&\n !t.includes(\"?\")\n ) {\n break\n }\n out.push(l.trimEnd())\n }\n\n const candidate = out.join(\"\\n\").trim()\n if (candidate.length < 5) return undefined\n if (candidate.length > 800) return candidate.slice(0, 800).trimEnd()\n return candidate\n }\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue\n const data = line.slice(6).trim()\n if (data === \"[DONE]\") continue\n\n try {\n const event = JSON.parse(data)\n\n if (event.type === \"content_block_start\") {\n if (event.content_block?.type === \"tool_use\") {\n // Finalize any previous tool block if the stream didn't send a stop.\n if (activeTool) {\n yield { type: \"tool_use_end\", name: activeTool.name }\n try {\n const input = JSON.parse(activeTool.json || \"{}\") as any\n if (activeTool.name === \"create_files\" && input) {\n if (Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n }\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += `\\n${input.summary}`\n }\n }\n if (activeTool.name === \"ask_user\" && input) {\n if (typeof input.question === \"string\" && input.question.trim()) {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n } catch {\n // Ignore invalid tool JSON\n } finally {\n activeTool = null\n }\n }\n\n activeTool = {\n name: event.content_block.name,\n id: event.content_block.id,\n json: \"\",\n }\n yield {\n type: \"tool_use_start\",\n name: event.content_block.name,\n id: event.content_block.id,\n }\n }\n }\n\n if (event.type === \"content_block_delta\") {\n if (event.delta?.type === \"text_delta\") {\n content += event.delta.text\n yield { type: \"text_delta\", text: event.delta.text }\n }\n if (event.delta?.type === \"input_json_delta\") {\n if (activeTool) activeTool.json += event.delta.partial_json || \"\"\n yield { type: \"tool_use_delta\", json: event.delta.partial_json }\n }\n }\n\n if (event.type === \"content_block_stop\") {\n // Tool use blocks are complete\n if (activeTool) {\n // Manually inline finalize to avoid generator gymnastics.\n yield { type: \"tool_use_end\", name: activeTool.name }\n try {\n const input = JSON.parse(activeTool.json || \"{}\") as any\n if (activeTool.name === \"create_files\" && input) {\n if (Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n }\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += `\\n${input.summary}`\n }\n }\n if (activeTool.name === \"ask_user\" && input) {\n if (typeof input.question === \"string\" && input.question.trim()) {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n } catch {\n // Ignore invalid tool JSON\n } finally {\n activeTool = null\n }\n }\n }\n\n if (event.type === \"message_delta\") {\n if (event.usage) {\n tokensUsed = (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0)\n }\n }\n\n if (event.type === \"message_stop\") {\n // Message complete\n }\n } catch {\n // Skip unparseable lines\n }\n }\n }\n } finally {\n reader.releaseLock()\n }\n\n // Flush any trailing tool input.\n if (activeTool) {\n yield { type: \"tool_use_end\", name: activeTool.name }\n try {\n const input = JSON.parse(activeTool.json || \"{}\") as any\n if (activeTool.name === \"create_files\" && input) {\n if (Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n }\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += `\\n${input.summary}`\n }\n }\n if (activeTool.name === \"ask_user\" && input) {\n if (typeof input.question === \"string\" && input.question.trim()) {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n } catch {\n // Ignore\n }\n activeTool = null\n }\n\n if (!followUp && files.length === 0) {\n followUp = inferFollowUpFromText(content)\n }\n\n yield {\n type: \"done\",\n result: { content, files, followUp, tokensUsed },\n }\n }\n\n /**\n * Streaming variant of generateRaw — yields text_delta events per\n * chunk so callers can pipe per-token to a UI, AND assembles the full\n * RawGenerationResult (with tool_use blocks intact, stop_reason set)\n * so the agentic loop's tool dispatch keeps working unchanged.\n *\n * Implementation mirrors stream() but:\n * - Targets generateRaw's signature (anthropicMessages + systemPrompt +\n * tools as parameters, not interleaved messages).\n * - Builds a ContentBlock[] with both text and tool_use blocks in the\n * order they arrived, so the agentic loop's `result.content.filter(\n * b => b.type === \"tool_use\")` still finds them.\n * - Yields one terminal `raw_result` event the loop consumes.\n */\n async *generateRawStream(\n messages: AnthropicMessage[],\n systemPrompt: string,\n tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions,\n ): AsyncIterable<RawStreamEvent> {\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n system: wrapSystemForCache(systemPrompt),\n messages,\n tools,\n stream: true,\n }\n if (options?.temperature !== undefined) body.temperature = options.temperature\n\n const headers = this.buildHeaders()\n let res: Response\n try {\n res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.abortSignal,\n })\n } catch (err: any) {\n yield { type: \"error\", error: `Anthropic stream init failed: ${err?.message ?? err}` }\n return\n }\n\n if (!res.ok) {\n const errText = await res.text().catch(() => \"\")\n yield { type: \"error\", error: `Anthropic API error (${res.status}): ${errText.slice(0, 500)}` }\n return\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n yield { type: \"error\", error: \"No response body on Anthropic stream\" }\n return\n }\n\n const decoder = new TextDecoder()\n let buffer = \"\"\n const blocks: ContentBlock[] = []\n let activeBlockIdx: number | null = null\n let stopReason: RawGenerationResult[\"stop_reason\"] = \"end_turn\"\n let inputTokens = 0\n let outputTokens = 0\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue\n const data = line.slice(6).trim()\n if (!data || data === \"[DONE]\") continue\n\n let event: any\n try { event = JSON.parse(data) } catch { continue }\n\n if (event.type === \"message_start\" && event.message?.usage) {\n inputTokens = event.message.usage.input_tokens || 0\n }\n\n if (event.type === \"content_block_start\") {\n const cb = event.content_block\n if (cb?.type === \"text\") {\n activeBlockIdx = blocks.length\n blocks.push({ type: \"text\", text: \"\" })\n } else if (cb?.type === \"tool_use\") {\n activeBlockIdx = blocks.length\n blocks.push({\n type: \"tool_use\",\n id: cb.id || \"\",\n name: cb.name || \"\",\n input: {},\n })\n // We'll accumulate the input JSON across input_json_delta\n // events and parse once content_block_stop fires.\n ;(blocks[activeBlockIdx] as any)._rawJson = \"\"\n } else {\n activeBlockIdx = null\n }\n }\n\n if (event.type === \"content_block_delta\" && activeBlockIdx != null) {\n const block = blocks[activeBlockIdx]\n if (event.delta?.type === \"text_delta\" && block.type === \"text\") {\n block.text += event.delta.text\n yield { type: \"text_delta\", text: event.delta.text }\n } else if (event.delta?.type === \"input_json_delta\" && block.type === \"tool_use\") {\n ;(block as any)._rawJson += event.delta.partial_json || \"\"\n }\n }\n\n if (event.type === \"content_block_stop\" && activeBlockIdx != null) {\n const block = blocks[activeBlockIdx]\n if (block.type === \"tool_use\") {\n const raw = (block as any)._rawJson || \"{}\"\n try {\n block.input = JSON.parse(raw) as Record<string, unknown>\n } catch {\n block.input = {}\n }\n delete (block as any)._rawJson\n }\n activeBlockIdx = null\n }\n\n if (event.type === \"message_delta\") {\n if (event.delta?.stop_reason) {\n stopReason = event.delta.stop_reason as RawGenerationResult[\"stop_reason\"]\n }\n if (event.usage) {\n outputTokens = event.usage.output_tokens || 0\n }\n }\n }\n }\n } catch (err: any) {\n yield { type: \"error\", error: `Anthropic stream read failed: ${err?.message ?? err}` }\n return\n } finally {\n reader.releaseLock()\n }\n\n yield {\n type: \"raw_result\",\n result: {\n content: blocks,\n stop_reason: stopReason,\n usage: { input_tokens: inputTokens, output_tokens: outputTokens },\n },\n }\n }\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n }\n\n if (this.authType === \"oauth\") {\n headers[\"Authorization\"] = `Bearer ${this.apiKey}`\n headers[\"anthropic-beta\"] = \"claude-code-20250219,oauth-2025-04-20\"\n headers[\"user-agent\"] = \"claude-cli/2.1.2 (external, cli)\"\n headers[\"x-app\"] = \"cli\"\n headers[\"anthropic-dangerous-direct-browser-access\"] = \"true\"\n } else {\n headers[\"x-api-key\"] = this.apiKey\n }\n\n return headers\n }\n\n private async callApi(\n body: Record<string, unknown>,\n options?: ProviderOptions,\n ): Promise<AnthropicResponse> {\n const headers = this.buildHeaders()\n\n // Every request here is cancellable. Without the signal an operator\n // cancel only marks the task aborted in the registry while the HTTP\n // request runs to completion, and a caller's own AbortController — the\n // shape used by src/graph/classifier.ts and src/agents/context-planner.ts\n // — does nothing at all.\n const res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.abortSignal,\n })\n\n if (!res.ok) {\n const errorText = await res.text()\n throw new Error(`Anthropic API error (${res.status}): ${errorText}`)\n }\n\n return (await res.json()) as AnthropicResponse\n }\n\n private parseResponse(response: AnthropicResponse): GenerationResult {\n const files: GeneratedFile[] = []\n let content = \"\"\n let followUp: string | undefined\n\n for (const block of response.content) {\n if (block.type === \"text\") {\n content += block.text || \"\"\n }\n\n if (block.type === \"tool_use\") {\n if (block.name === \"create_files\" && block.input) {\n const input = block.input as {\n files: GeneratedFile[]\n summary?: string\n }\n files.push(...(input.files || []))\n if (input.summary) {\n content += `\\n${input.summary}`\n }\n }\n\n if (block.name === \"ask_user\" && block.input) {\n const input = block.input as { question: string; options?: string[] }\n followUp = input.question\n if (input.options?.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n }\n\n return {\n content,\n files,\n followUp,\n tokensUsed: response.usage.input_tokens + response.usage.output_tokens,\n }\n }\n}\n","import type {\n AgentProvider,\n GenerationMessage,\n GenerationResult,\n GeneratedFile,\n ProviderOptions,\n StreamEvent,\n AnthropicMessage,\n RawGenerationResult,\n ContentBlock,\n} from \"./types\"\nimport { resolveToken, loadAuthConfig } from \"@/utils/auth-store\"\nimport { execa } from \"execa\"\nimport { tmpdir } from \"os\"\nimport { getLegacyTools } from \"../tools/definitions\"\n\n// --- Claude Code provider: uses Claude CLI (subscription) or direct API (API key) ---\n\nconst DEFAULT_MODEL = \"claude-sonnet-4-20250514\"\nconst DEFAULT_MAX_TOKENS = 8192\n\n// Model ID → claude CLI alias\nconst CLI_MODEL_ALIASES: Record<string, string> = {\n \"claude-sonnet-4-20250514\": \"sonnet\",\n \"claude-opus-4-20250514\": \"opus\",\n \"claude-haiku-4-20250514\": \"haiku\",\n}\n\ntype AuthCredential = { type: \"oauth\"; token: string } | { type: \"api-key\"; token: string }\n\n/** Flags that turn `claude -p` into a plain text generator. Interactive\n * startup (plugins, hooks, MCP servers, settings, session files) is what\n * made a one-line classification cost ~20s per task. */\nexport const BARE_CLI_ARGS: readonly string[] = [\n \"--tools\", \"\",\n \"--strict-mcp-config\",\n \"--mcp-config\", '{\"mcpServers\":{}}',\n \"--settings\", '{\"disableAllHooks\":true}',\n \"--no-session-persistence\",\n \"--setting-sources\", \"\",\n]\n\n/** Argument list for a non-streaming `claude -p` generate call. Exported\n * so the flag set is unit-testable without spawning anything. */\nexport function buildCliGenerateArgs(input: {\n model: string\n systemPrompt?: string\n prompt: string\n bare?: boolean\n}): string[] {\n const args = [\n \"-p\",\n \"--output-format\", \"json\",\n \"--model\", input.model,\n \"--dangerously-skip-permissions\",\n ]\n if (input.bare) args.push(...BARE_CLI_ARGS)\n if (input.systemPrompt) {\n // Bare calls replace the CLI's default (tool-oriented) system prompt\n // outright; agentic calls only append to it.\n args.push(input.bare ? \"--system-prompt\" : \"--append-system-prompt\", input.systemPrompt)\n }\n // Prompt goes as the last positional argument\n args.push(input.prompt)\n return args\n}\n\n/** Why a `claude -p` run failed, for when it printed nothing. A caller's\n * abort or the timeout kills the process before it writes a word, and\n * \"Claude CLI failed\" alone hid that most classifier fallbacks die this way. */\nexport function describeCliFailure(result: {\n stderr?: string\n stdout?: string\n exitCode?: number | null\n signal?: string | null\n timedOut?: boolean\n isCanceled?: boolean\n}): string {\n const out = (result.stderr || result.stdout || \"\").toString().trim()\n if (out) return out\n if (result.isCanceled) return \"Claude CLI aborted by caller (timeout or cancel)\"\n if (result.timedOut) return \"Claude CLI timed out\"\n if (result.signal) return `Claude CLI killed by ${result.signal}`\n return `Claude CLI failed (exit ${result.exitCode ?? \"unknown\"}, no output)`\n}\n\ninterface AnthropicResponse {\n id: string\n content: Array<{\n type: \"text\" | \"tool_use\" | \"tool_result\"\n text?: string\n id?: string\n name?: string\n input?: Record<string, unknown>\n }>\n model: string\n stop_reason: string\n usage: { input_tokens: number; output_tokens: number }\n}\n\nexport class ClaudeCodeProvider implements AgentProvider {\n name = \"claude-code\"\n private credential: AuthCredential\n\n constructor() {\n // Stored config takes priority — if user ran `agentx model` and chose OAuth,\n // we use that regardless of ANTHROPIC_API_KEY env var (same as OpenClaw's clearEnv).\n const stored = loadAuthConfig()\n if (stored) {\n this.credential = { type: stored.authType, token: stored.token }\n return\n }\n\n const resolved = resolveToken()\n if (!resolved) {\n throw new Error(\n \"No Claude credentials found.\\n\" +\n \"Options:\\n\" +\n \" 1. Run `agentx model` to configure credentials\\n\" +\n \" 2. Set ANTHROPIC_API_KEY environment variable\\n\" +\n \" 3. Set ANTHROPIC_OAUTH_TOKEN environment variable\"\n )\n }\n this.credential = { type: resolved.authType, token: resolved.token }\n }\n\n async generate(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): Promise<GenerationResult> {\n // OAuth tokens → use claude CLI (subscription billing)\n // API keys → call API directly\n if (this.credential.type === \"oauth\") {\n return this.generateViaCli(messages, options)\n }\n return this.generateViaApi(messages, options)\n }\n\n /**\n * generateRaw() for the agentic tool_result loop.\n * Only available for API key auth — the CLI binary has its own agent loop.\n */\n async generateRaw(\n messages: AnthropicMessage[],\n systemPrompt: string,\n tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions\n ): Promise<RawGenerationResult> {\n // OAuth path: not supported — the claude CLI has its own built-in tools\n if (this.credential.type === \"oauth\") {\n throw new Error(\"generateRaw() not available for OAuth/CLI mode\")\n }\n\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n system: systemPrompt,\n messages,\n tools,\n }\n\n if (options?.temperature !== undefined) {\n body.temperature = options.temperature\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"x-api-key\": this.credential.token,\n }\n\n const res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const errorText = await res.text()\n throw new Error(`Anthropic API error (${res.status}): ${errorText}`)\n }\n\n const response = (await res.json()) as AnthropicResponse\n\n const content: ContentBlock[] = response.content.map((block) => {\n if (block.type === \"text\") {\n return { type: \"text\" as const, text: block.text || \"\" }\n }\n if (block.type === \"tool_use\") {\n return {\n type: \"tool_use\" as const,\n id: block.id || \"\",\n name: block.name || \"\",\n input: block.input || {},\n }\n }\n return { type: \"text\" as const, text: \"\" }\n })\n\n return {\n content,\n stop_reason: response.stop_reason as RawGenerationResult[\"stop_reason\"],\n usage: response.usage,\n }\n }\n\n /**\n * Returns true if this provider can use the agentic tool loop.\n * Only available for API key auth (CLI mode falls back to legacy loop).\n */\n get supportsAgenticLoop(): boolean {\n return this.credential.type === \"api-key\"\n }\n\n /**\n * Generate via the `claude` CLI binary.\n * This is how subscription billing works — the CLI handles auth internally.\n */\n private async generateViaCli(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): Promise<GenerationResult> {\n const model = options?.model || loadAuthConfig()?.model || DEFAULT_MODEL\n const cliModel = CLI_MODEL_ALIASES[model] || model\n\n const systemMsg = messages.find((m) => m.role === \"system\")\n const userMsgs = messages.filter((m) => m.role === \"user\")\n const prompt = userMsgs.map((m) => m.content).join(\"\\n\\n\")\n\n const args = buildCliGenerateArgs({\n model: cliModel,\n systemPrompt: systemMsg?.content,\n prompt,\n bare: options?.bare === true,\n })\n\n // Clear ANTHROPIC_API_KEY to force CLI to use subscription auth\n const env = { ...process.env }\n delete env.ANTHROPIC_API_KEY\n delete env.ANTHROPIC_API_KEY_OLD\n\n const result = await execa(\"claude\", args, {\n env,\n extendEnv: false,\n reject: false,\n timeout: 300_000,\n stdin: \"ignore\",\n // A bare call has no workspace: a neutral cwd keeps the daemon's own\n // CLAUDE.md and project settings out of a classifier prompt.\n ...(options?.bare ? { cwd: tmpdir() } : {}),\n // Callers' timeouts (classifier 30s, planner 8s) were dead code\n // until the signal reached the subprocess.\n ...(options?.abortSignal ? { signal: options.abortSignal } : {}),\n })\n\n if (result.exitCode !== 0) {\n throw new Error(`Claude CLI error: ${describeCliFailure(result)}`)\n }\n\n // Claude CLI may return success exit code but with is_error in JSON\n const output = result.stdout.trim()\n try {\n const json = JSON.parse(output)\n if (json.is_error && json.result) {\n throw new Error(json.result)\n }\n } catch (e: any) {\n if (e.message && !e.message.includes(\"JSON\")) throw e\n // Not JSON — that's fine, parseCliOutput will handle it\n }\n\n return this.parseCliOutput(output)\n }\n\n /**\n * Generate via direct Anthropic API call (for API key auth).\n */\n private async generateViaApi(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): Promise<GenerationResult> {\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const systemMsg = messages.find((m) => m.role === \"system\")\n const conversationMsgs = messages\n .filter((m) => m.role !== \"system\")\n .map((m) => ({\n role: m.role as \"user\" | \"assistant\",\n content: m.content,\n }))\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: conversationMsgs,\n tools: getLegacyTools(),\n }\n\n if (systemMsg) {\n body.system = systemMsg.content\n }\n\n if (options?.temperature !== undefined) {\n body.temperature = options.temperature\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"x-api-key\": this.credential.token,\n }\n\n const res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const errorText = await res.text()\n throw new Error(`Anthropic API error (${res.status}): ${errorText}`)\n }\n\n const response = (await res.json()) as AnthropicResponse\n return this.parseApiResponse(response)\n }\n\n /**\n * Stream responses. For OAuth, uses CLI with --output-format stream-json.\n * For API keys, uses SSE streaming.\n */\n async *stream(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): AsyncIterable<StreamEvent> {\n if (this.credential.type === \"oauth\") {\n // CLI streaming via --output-format stream-json\n yield* this.streamViaCli(messages, options)\n } else {\n // API streaming via SSE (same as ClaudeProvider.stream)\n yield* this.streamViaApi(messages, options)\n }\n }\n\n private async *streamViaCli(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): AsyncIterable<StreamEvent> {\n const model = options?.model || loadAuthConfig()?.model || DEFAULT_MODEL\n const cliModel = CLI_MODEL_ALIASES[model] || model\n\n const systemMsg = messages.find((m) => m.role === \"system\")\n const userMsgs = messages.filter((m) => m.role === \"user\")\n const prompt = userMsgs.map((m) => m.content).join(\"\\n\\n\")\n\n const args = [\n \"-p\",\n \"--output-format\", \"stream-json\",\n \"--model\", cliModel,\n \"--dangerously-skip-permissions\",\n ]\n\n if (systemMsg) {\n args.push(\"--append-system-prompt\", systemMsg.content)\n }\n\n args.push(prompt)\n\n const env = { ...process.env }\n delete env.ANTHROPIC_API_KEY\n delete env.ANTHROPIC_API_KEY_OLD\n\n const child = execa(\"claude\", args, {\n env,\n extendEnv: false,\n reject: false,\n timeout: 300_000,\n stdin: \"ignore\",\n })\n\n let fullContent = \"\"\n let stderr = \"\"\n let fatalError: string | undefined\n\n if (child.stderr) {\n child.stderr.on(\"data\", (chunk: any) => {\n stderr += Buffer.isBuffer(chunk) ? chunk.toString(\"utf8\") : String(chunk)\n })\n }\n\n if (child.stdout) {\n const decoder = new TextDecoder()\n const readable = child.stdout as unknown as AsyncIterable<Uint8Array>\n\n for await (const chunk of readable) {\n const text = typeof chunk === \"string\" ? chunk : decoder.decode(chunk, { stream: true })\n // Stream JSON format: each line is a JSON object\n const lines = text.split(\"\\n\").filter(Boolean)\n for (const line of lines) {\n try {\n const event = JSON.parse(line)\n // Some claude stream-json builds emit error events.\n if (event.type === \"error\") {\n fatalError = String(event.error || event.message || \"Claude CLI error\")\n continue\n }\n if (event.is_error && (event.result || event.message)) {\n fatalError = String(event.result || event.message)\n continue\n }\n if (event.type === \"assistant\" && event.message) {\n fullContent += event.message\n yield { type: \"text_delta\", text: event.message }\n } else if (event.type === \"result\") {\n fullContent = event.result || fullContent\n }\n } catch {\n // Not JSON, treat as raw text\n fullContent += line\n yield { type: \"text_delta\", text: line }\n }\n }\n }\n }\n\n const res = await child\n if (res.exitCode !== 0 && !fatalError) {\n fatalError = stderr.toString().trim() || describeCliFailure(res)\n }\n\n if (fatalError) {\n yield { type: \"error\", error: `Claude CLI error: ${fatalError}` }\n return\n }\n\n const files = this.extractFilesFromText(fullContent)\n const followUp =\n files.length === 0 ? this.inferFollowUpFromText(fullContent) : undefined\n yield {\n type: \"done\",\n result: { content: fullContent, files, followUp, tokensUsed: 0 },\n }\n }\n\n private async *streamViaApi(\n messages: GenerationMessage[],\n options?: ProviderOptions\n ): AsyncIterable<StreamEvent> {\n const model = options?.model || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const systemMsg = messages.find((m) => m.role === \"system\")\n const conversationMsgs = messages\n .filter((m) => m.role !== \"system\")\n .map((m) => ({ role: m.role as \"user\" | \"assistant\", content: m.content }))\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: conversationMsgs,\n tools: getLegacyTools(),\n stream: true,\n }\n\n if (systemMsg) body.system = systemMsg.content\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"x-api-key\": this.credential.token,\n }\n\n const res = await fetch(\"https://api.anthropic.com/v1/messages\", {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const errorText = await res.text()\n yield { type: \"error\", error: `Anthropic API error (${res.status}): ${errorText}` }\n return\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n yield { type: \"error\", error: \"No response body\" }\n return\n }\n\n const decoder = new TextDecoder()\n let buffer = \"\"\n let content = \"\"\n let tokensUsed = 0\n const files: GeneratedFile[] = []\n let followUp: string | undefined\n let activeTool: { name: string; id: string; json: string } | null = null\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue\n const data = line.slice(6).trim()\n if (data === \"[DONE]\") continue\n\n try {\n const event = JSON.parse(data)\n if (event.type === \"content_block_start\") {\n if (event.content_block?.type === \"tool_use\") {\n // Finalize any previous tool block if the stream didn't send a stop.\n if (activeTool) {\n yield { type: \"tool_use_end\", name: activeTool.name }\n try {\n const input = JSON.parse(activeTool.json || \"{}\") as any\n if (activeTool.name === \"create_files\" && input) {\n if (Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n }\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += `\\n${input.summary}`\n }\n }\n if (activeTool.name === \"ask_user\" && input) {\n if (typeof input.question === \"string\" && input.question.trim()) {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n } catch {\n // Ignore invalid tool JSON\n } finally {\n activeTool = null\n }\n }\n\n activeTool = {\n name: event.content_block.name,\n id: event.content_block.id,\n json: \"\",\n }\n yield { type: \"tool_use_start\", name: activeTool.name, id: activeTool.id }\n }\n }\n\n if (event.type === \"content_block_delta\" && event.delta?.type === \"text_delta\") {\n content += event.delta.text\n yield { type: \"text_delta\", text: event.delta.text }\n }\n if (event.type === \"content_block_delta\" && event.delta?.type === \"input_json_delta\") {\n if (activeTool) activeTool.json += event.delta.partial_json || \"\"\n yield { type: \"tool_use_delta\", json: event.delta.partial_json }\n }\n if (event.type === \"content_block_stop\") {\n if (activeTool) {\n yield { type: \"tool_use_end\", name: activeTool.name }\n try {\n const input = JSON.parse(activeTool.json || \"{}\") as any\n if (activeTool.name === \"create_files\" && input) {\n if (Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n }\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += `\\n${input.summary}`\n }\n }\n if (activeTool.name === \"ask_user\" && input) {\n if (typeof input.question === \"string\" && input.question.trim()) {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n } catch {\n // Ignore invalid tool JSON\n } finally {\n activeTool = null\n }\n }\n }\n if (event.type === \"message_delta\" && event.usage) {\n tokensUsed = (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0)\n }\n } catch {\n // Skip\n }\n }\n }\n } finally {\n reader.releaseLock()\n }\n\n // Flush any trailing tool input.\n if (activeTool) {\n yield { type: \"tool_use_end\", name: activeTool.name }\n try {\n const input = JSON.parse(activeTool.json || \"{}\") as any\n if (activeTool.name === \"create_files\" && input) {\n if (Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n }\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += `\\n${input.summary}`\n }\n }\n if (activeTool.name === \"ask_user\" && input) {\n if (typeof input.question === \"string\" && input.question.trim()) {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n } catch {\n // Ignore\n }\n activeTool = null\n }\n\n // If the model didn't use tools (or we couldn't parse them), fall back to fenced-code extraction.\n if (files.length === 0) {\n files.push(...this.extractFilesFromText(content))\n }\n if (!followUp && files.length === 0) {\n followUp = this.inferFollowUpFromText(content)\n }\n yield {\n type: \"done\",\n result: { content, files, followUp, tokensUsed },\n }\n }\n\n /**\n * Parse JSON output from the `claude` CLI.\n */\n private parseCliOutput(stdout: string): GenerationResult {\n let parsed: any\n try {\n parsed = JSON.parse(stdout)\n } catch {\n // CLI returned plain text\n const inferred = this.inferFollowUpFromText(stdout.trim())\n return {\n content: stdout.trim(),\n files: [],\n followUp: inferred,\n tokensUsed: 0,\n }\n }\n\n // Claude CLI JSON format: { result: \"...\", session_id: \"...\", ... }\n const text = parsed.result || parsed.text || parsed.content || \"\"\n\n // Extract files from the text if it contains code blocks with file paths\n const files = this.extractFilesFromText(text)\n const followUp = files.length === 0 ? this.inferFollowUpFromText(text) : undefined\n\n return {\n content: text,\n files,\n followUp,\n tokensUsed: parsed.usage\n ? (parsed.usage.input_tokens || 0) + (parsed.usage.output_tokens || 0)\n : 0,\n }\n }\n\n /**\n * Extract file blocks from CLI text output.\n * Looks for patterns like: ```path/to/file.ts ... ```\n */\n private extractFilesFromText(text: string): GeneratedFile[] {\n const files: GeneratedFile[] = []\n // Match fenced code blocks with a file path hint on the opening line\n const pattern = /```[\\w]*\\s*([\\w/._-]+\\.\\w+)\\n([\\s\\S]*?)```/g\n let match: RegExpExecArray | null\n while ((match = pattern.exec(text)) !== null) {\n const filePath = match[1]\n const content = match[2]\n if (filePath && content) {\n files.push({ path: filePath, content: content.trimEnd() })\n }\n }\n return files\n }\n\n /**\n * Claude CLI (OAuth/subscription) doesn't always emit structured ask_user tool blocks.\n * When it's obviously asking for clarification, infer a follow-up question from the tail.\n */\n private inferFollowUpFromText(text: string): string | undefined {\n const cleaned = (text || \"\").trim()\n if (!cleaned) return undefined\n\n // If it looks like it produced file blocks, don't treat it as a follow-up.\n if (cleaned.includes(\"```\")) return undefined\n\n const lines = cleaned.replace(/\\r\\n/g, \"\\n\").split(\"\\n\")\n const tail = lines.slice(Math.max(0, lines.length - 20))\n\n const tailText = tail.join(\"\\n\")\n const looksLikePlanApproval =\n /\\b(plan|proposal)\\b/i.test(tailText) &&\n /(ready for your review|review (the )?plan|requesting plan approval|awaiting approval|waiting for (your )?approval|approve (the )?plan|approval to proceed)/i.test(\n tailText\n )\n\n if (looksLikePlanApproval) {\n return (\n \"The provider is requesting plan approval.\\n\" +\n \"Reply with:\\n\" +\n \"- approve\\n\" +\n \"- revise: <what to change>\\n\" +\n \"- cancel\"\n )\n }\n\n const isIntro = (l: string) =>\n /^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(\n l.trim()\n )\n\n // Find the last strong candidate line.\n let startIdx = -1\n for (let i = tail.length - 1; i >= 0; i--) {\n const l = tail[i].trim()\n if (!l) continue\n if (isIntro(l) || l.includes(\"?\")) {\n startIdx = i\n break\n }\n }\n if (startIdx === -1) return undefined\n\n // Collect the question + a small option/list block that follows it.\n const out: string[] = []\n for (let i = startIdx; i < tail.length && out.length < 8; i++) {\n const l = tail[i]\n const t = l.trim()\n if (out.length > 0 && !t) break\n\n if (\n out.length > 0 &&\n !/^(options?:|[-*]\\s|\\d+[\\).]\\s)/i.test(t) &&\n !t.includes(\"?\")\n ) {\n break\n }\n\n out.push(l.trimEnd())\n }\n\n const candidate = out.join(\"\\n\").trim()\n if (candidate.length < 5) return undefined\n if (candidate.length > 800) return candidate.slice(0, 800).trimEnd()\n return candidate\n }\n\n /**\n * Parse Anthropic API response (tool-use format).\n */\n private parseApiResponse(response: AnthropicResponse): GenerationResult {\n const files: GeneratedFile[] = []\n let content = \"\"\n let followUp: string | undefined\n\n for (const block of response.content) {\n if (block.type === \"text\") {\n content += block.text || \"\"\n }\n\n if (block.type === \"tool_use\") {\n if (block.name === \"create_files\" && block.input) {\n const input = block.input as {\n files: GeneratedFile[]\n summary?: string\n }\n files.push(...(input.files || []))\n if (input.summary) {\n content += `\\n${input.summary}`\n }\n }\n\n if (block.name === \"ask_user\" && block.input) {\n const input = block.input as { question: string; options?: string[] }\n followUp = input.question\n if (input.options?.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n }\n }\n\n return {\n content,\n files,\n followUp,\n tokensUsed: response.usage.input_tokens + response.usage.output_tokens,\n }\n }\n}\n","import type {\n AgentProvider,\n GenerationMessage,\n GenerationResult,\n GeneratedFile,\n ProviderOptions,\n StreamEvent,\n AnthropicMessage,\n RawGenerationResult,\n RawStreamEvent,\n ContentBlock,\n} from \"./types\"\nimport { getLegacyTools } from \"../tools/definitions\"\n\n// --- OpenAI-compatible provider (OpenAI, DeepSeek, OpenRouter, Together,\n// vLLM, llama.cpp, anything that speaks the Chat Completions API).\n//\n// Zero new deps — uses raw `fetch` to mirror the ClaudeProvider pattern.\n// Routes through OPENAI_BASE_URL so the same class works for every\n// OpenAI-shape backend; defaults to api.openai.com/v1.\n//\n// Environment knobs:\n// OPENAI_BASE_URL e.g. https://api.deepseek.com/v1 (defaults to OpenAI)\n// OPENAI_API_KEY bearer token for the upstream\n// OPENAI_MODEL default model id (per-call override via options.model)\n//\n// The agentx-side tool catalog uses Anthropic's `input_schema` shape and\n// the rest of the runtime expects RawGenerationResult in Anthropic shape\n// (ContentBlock[] with stop_reason: \"end_turn\"|\"tool_use\"|…). We translate\n// at the boundary so the tool/agentic loop above is provider-agnostic.\n\nconst DEFAULT_MODEL = \"gpt-4o-mini\"\nconst DEFAULT_MAX_TOKENS = 8192\n\ninterface OpenAIToolCall {\n id: string\n type: \"function\"\n function: { name: string; arguments: string }\n}\n\ninterface OpenAIResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: OpenAIToolCall[]\n // DeepSeek V4 reasoning output (\"thinking mode\"). When present, MUST\n // be echoed back on subsequent requests of the same turn or DeepSeek\n // 400s with \"The reasoning_content in the thinking mode must be\n // passed back to the API.\" We surface it as a {type:\"reasoning\"}\n // ContentBlock so the agentic loop carries it through.\n reasoning_content?: string\n}\n\ninterface OpenAIChatResponse {\n id: string\n model: string\n choices: Array<{\n index: number\n message: OpenAIResponseMessage\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | \"function_call\" | null\n }>\n usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number }\n}\n\nexport interface OpenAIProviderOptions {\n /** Toggle \"thinking mode\" on backends that support it (DeepSeek V4\n * `reasoning_content`). Default `true` for DeepSeek baseUrls so the\n * agent surfaces its reasoning live in the dashboard; set to `false`\n * via `providers.<name>.thinking` in agentx.json if a particular\n * agent wants the extra latency / cost back. Ignored on backends\n * that don't speak the thinking-mode protocol (vanilla OpenAI,\n * vLLM, Together, …). */\n thinking?: boolean\n}\n\nexport class OpenAIProvider implements AgentProvider {\n name = \"openai\"\n private apiKey: string\n private baseUrl: string\n /** Resolved thinking flag — null when the backend isn't a known\n * thinking-mode endpoint and the option is irrelevant. */\n private thinkingEnabled: boolean | null\n\n constructor(apiKey?: string, baseUrl?: string, opts: OpenAIProviderOptions = {}) {\n this.apiKey = apiKey || process.env.OPENAI_API_KEY || \"\"\n this.baseUrl = (\n baseUrl ||\n process.env.OPENAI_BASE_URL ||\n \"https://api.openai.com/v1\"\n ).replace(/\\/$/, \"\")\n // DeepSeek defaults to thinking ON — that's the model's own default\n // behavior. Operator can flip it off via providers.<name>.thinking=false.\n // Non-DeepSeek backends ignore the flag entirely.\n const isDeepseek = this.baseUrl.includes(\"deepseek.com\")\n this.thinkingEnabled = isDeepseek\n ? (opts.thinking === false ? false : true)\n : null\n if (!this.apiKey) {\n throw new Error(\n \"OpenAI-compatible API key required. Set OPENAI_API_KEY (or pass --api-key). \" +\n \"For DeepSeek, also set OPENAI_BASE_URL=https://api.deepseek.com/v1.\",\n )\n }\n }\n\n async generate(\n messages: GenerationMessage[],\n options?: ProviderOptions,\n ): Promise<GenerationResult> {\n const model = options?.model || process.env.OPENAI_MODEL || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n // OpenAI takes system as just another message with role:\"system\" at the top.\n const oaMessages = messages.map((m) => ({ role: m.role, content: m.content }))\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: oaMessages,\n tools: this.legacyToolsAsOpenAI(),\n }\n if (options?.temperature !== undefined) body.temperature = options.temperature\n\n const data = await this.callApi(body)\n return this.parseHighLevelResponse(data)\n }\n\n async generateRaw(\n messages: AnthropicMessage[],\n systemPrompt: string,\n tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions,\n ): Promise<RawGenerationResult> {\n const body = this.buildRawBody(messages, systemPrompt, tools, options)\n const data = await this.callApi(body, options?.abortSignal)\n return this.parseRawResponse(data)\n }\n\n /**\n * Streaming variant of generateRaw. Yields text_delta and thinking_delta\n * events as the model speaks, then a terminal raw_result with the full\n * content blocks (text, tool_use, and — for DeepSeek thinking mode —\n * a `reasoning` block at the head). The agentic loop's tool-dispatch\n * and reasoning-round-trip logic then operates on identical data to\n * the non-streaming path.\n */\n async *generateRawStream(\n messages: AnthropicMessage[],\n systemPrompt: string,\n tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions,\n ): AsyncIterable<RawStreamEvent> {\n const body = { ...this.buildRawBody(messages, systemPrompt, tools, options), stream: true, stream_options: { include_usage: true } }\n\n let res: Response\n try {\n res = await fetch(`${this.baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${this.apiKey}` },\n body: JSON.stringify(this.maybeDeepseekExtras(body)),\n // Forward operator cancel down to the HTTP layer so Stop\n // actually terminates the in-flight request. Without this,\n // the abort fires in the registry but fetch keeps draining\n // tokens.\n signal: options?.abortSignal as any,\n })\n } catch (err: any) {\n // AbortError surfaces here when the operator cancelled before\n // the connection completed. Treat as cancelled, not a real\n // error — the registry's outer handler already records the\n // cancellation.\n if (err?.name === \"AbortError\" || options?.abortSignal?.aborted) {\n yield { type: \"error\", error: \"cancelled\" }\n return\n }\n yield { type: \"error\", error: `OpenAI-compat raw stream init failed: ${err?.message ?? err}` }\n return\n }\n if (!res.ok) {\n const errText = await res.text().catch(() => \"\")\n yield { type: \"error\", error: `OpenAI-compat API error (${res.status}): ${errText.slice(0, 500)}` }\n return\n }\n const reader = res.body?.getReader()\n if (!reader) { yield { type: \"error\", error: \"No response body on OpenAI-compat raw stream\" }; return }\n\n // Wire the operator's abort signal into reader.cancel() so an abort\n // mid-stream actually closes the underlying TCP socket. Without this,\n // undici sometimes keeps reader.read() pending forever even after\n // fetch's signal aborts — DeepSeek's reasoning_content can stream for\n // many minutes, and the orchestrator's wall-clock timer fired into a\n // signal that no one was actually watching here. Production saw 58+\n // min hangs past the 15-min maxExecutionMinutes cap on acme-public.\n const onAbortCancelReader = () => {\n reader.cancel(new Error(\"aborted\")).catch(() => { /* already closed */ })\n }\n if (options?.abortSignal) {\n if (options.abortSignal.aborted) onAbortCancelReader()\n else options.abortSignal.addEventListener(\"abort\", onAbortCancelReader, { once: true })\n }\n\n const decoder = new TextDecoder()\n let buffer = \"\"\n let textOut = \"\"\n let reasoningOut = \"\"\n let inputTokens = 0\n let outputTokens = 0\n let finishReason: string | null = null\n interface ToolAcc { id: string; name: string; argumentsRaw: string }\n const toolAcc: Record<number, ToolAcc> = {}\n\n try {\n while (true) {\n // Belt-and-braces: bail between chunks too, in case reader.cancel()\n // didn't unblock the pending read (some SSE proxies hold the\n // connection open even after upstream close).\n if (options?.abortSignal?.aborted) {\n yield { type: \"error\", error: \"cancelled\" }\n return\n }\n const { done, value } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue\n const data = line.slice(6).trim()\n if (!data || data === \"[DONE]\") continue\n let chunk: any\n try { chunk = JSON.parse(data) } catch { continue }\n const choice = chunk.choices?.[0]\n const delta = choice?.delta\n if (choice?.finish_reason) finishReason = choice.finish_reason\n\n if (typeof delta?.reasoning_content === \"string\" && delta.reasoning_content) {\n reasoningOut += delta.reasoning_content\n yield { type: \"thinking_delta\", text: delta.reasoning_content }\n }\n if (typeof delta?.content === \"string\" && delta.content) {\n textOut += delta.content\n yield { type: \"text_delta\", text: delta.content }\n }\n if (Array.isArray(delta?.tool_calls)) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index\n if (idx == null) continue\n const acc = (toolAcc[idx] ||= { id: \"\", name: \"\", argumentsRaw: \"\" })\n if (tc.id) acc.id = tc.id\n if (tc.function?.name) acc.name = tc.function.name\n if (tc.function?.arguments) acc.argumentsRaw += tc.function.arguments\n }\n }\n if (chunk.usage) {\n inputTokens = chunk.usage.prompt_tokens || 0\n outputTokens = chunk.usage.completion_tokens || 0\n }\n }\n }\n } catch (err: any) {\n if (err?.name === \"AbortError\" || options?.abortSignal?.aborted) {\n yield { type: \"error\", error: \"cancelled\" }\n return\n }\n yield { type: \"error\", error: `OpenAI-compat raw stream read failed: ${err?.message ?? err}` }\n return\n } finally {\n if (options?.abortSignal) {\n options.abortSignal.removeEventListener(\"abort\", onAbortCancelReader)\n }\n }\n\n // Assemble blocks in the same order parseRawResponse uses so the\n // agentic loop's round-trip stays consistent.\n const blocks: ContentBlock[] = []\n if (reasoningOut) blocks.push({ type: \"reasoning\", text: reasoningOut })\n if (textOut) blocks.push({ type: \"text\", text: textOut })\n for (const acc of Object.values(toolAcc)) {\n if (!acc.id || !acc.name) continue\n let input: Record<string, unknown> = {}\n try { input = acc.argumentsRaw ? JSON.parse(acc.argumentsRaw) : {} } catch { /* keep empty input */ }\n blocks.push({ type: \"tool_use\", id: acc.id, name: acc.name, input })\n }\n\n let stop_reason: RawGenerationResult[\"stop_reason\"] = \"end_turn\"\n switch (finishReason) {\n case \"tool_calls\":\n case \"function_call\":\n stop_reason = \"tool_use\"; break\n case \"length\":\n stop_reason = \"max_tokens\"; break\n }\n\n yield {\n type: \"raw_result\",\n result: { content: blocks, stop_reason, usage: { input_tokens: inputTokens, output_tokens: outputTokens } },\n }\n }\n\n /** Shared request-body builder for generateRaw / generateRawStream — both\n * need the same message translation, tool list, and provider extras. */\n private buildRawBody(\n messages: AnthropicMessage[],\n systemPrompt: string,\n tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions,\n ): Record<string, unknown> {\n const model = options?.model || process.env.OPENAI_MODEL || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n // Translate Anthropic-shape messages (with tool_use / tool_result content blocks)\n // into OpenAI Chat Completions message shape (with role:\"tool\" turns and\n // assistant.tool_calls). System prompt goes in as messages[0].\n const oaMessages: any[] = systemPrompt\n ? [{ role: \"system\", content: systemPrompt }]\n : []\n\n for (const m of messages) {\n const blocks = Array.isArray(m.content) ? m.content : [{ type: \"text\" as const, text: m.content }]\n if (m.role === \"user\") {\n const toolResults = blocks.filter((b) => (b as any).type === \"tool_result\") as Array<{\n type: \"tool_result\"; tool_use_id: string; content: string; is_error?: boolean;\n }>\n const textParts = blocks\n .filter((b) => (b as any).type === \"text\")\n .map((b) => (b as any).text)\n .join(\"\")\n for (const tr of toolResults) {\n oaMessages.push({\n role: \"tool\",\n tool_call_id: tr.tool_use_id,\n content: tr.is_error ? `[error] ${tr.content}` : tr.content,\n })\n }\n if (textParts) {\n oaMessages.push({ role: \"user\", content: textParts })\n } else if (toolResults.length === 0) {\n oaMessages.push({ role: \"user\", content: m.content as any })\n }\n } else {\n // Assistant turns may have text + tool_use + reasoning blocks;\n // OpenAI wants `content` + `tool_calls` on a single message,\n // and DeepSeek V4 also wants the prior `reasoning_content` so\n // thinking-mode round-trip works.\n const toolUses = blocks.filter((b) => (b as any).type === \"tool_use\") as Array<{\n type: \"tool_use\"; id: string; name: string; input: Record<string, unknown>;\n }>\n const text = blocks\n .filter((b) => (b as any).type === \"text\")\n .map((b) => (b as any).text)\n .join(\"\")\n const reasoning = blocks\n .filter((b) => (b as any).type === \"reasoning\")\n .map((b) => (b as any).text)\n .join(\"\")\n const msg: any = { role: \"assistant\", content: text || null }\n if (toolUses.length > 0) {\n msg.tool_calls = toolUses.map((tu) => ({\n id: tu.id,\n type: \"function\" as const,\n function: { name: tu.name, arguments: JSON.stringify(tu.input || {}) },\n }))\n }\n if (reasoning) {\n msg.reasoning_content = reasoning\n }\n oaMessages.push(msg)\n }\n }\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: oaMessages,\n tools: tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n })),\n tool_choice: \"auto\",\n }\n if (options?.temperature !== undefined) body.temperature = options.temperature\n if (options?.toolChoice) {\n body.tool_choice = { type: \"function\", function: { name: options.toolChoice.name } }\n }\n if (options?.responseFormat) {\n body.response_format = {\n type: \"json_schema\",\n json_schema: {\n name: options.responseFormat.name,\n schema: options.responseFormat.schema,\n strict: true,\n },\n }\n }\n if (options?.logprobs?.enabled) {\n body.logprobs = true\n body.top_logprobs = options.logprobs.topK\n }\n return body\n }\n\n async *stream(\n messages: GenerationMessage[],\n options?: ProviderOptions,\n ): AsyncIterable<StreamEvent> {\n const model = options?.model || process.env.OPENAI_MODEL || DEFAULT_MODEL\n const maxTokens = options?.maxTokens || DEFAULT_MAX_TOKENS\n\n const oaMessages = messages.map((m) => ({ role: m.role, content: m.content }))\n\n const body: Record<string, unknown> = {\n model,\n max_tokens: maxTokens,\n messages: oaMessages,\n tools: this.legacyToolsAsOpenAI(),\n stream: true,\n stream_options: { include_usage: true },\n }\n if (options?.temperature !== undefined) body.temperature = options.temperature\n\n let res: Response\n try {\n res = await fetch(`${this.baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(this.maybeDeepseekExtras(body)),\n })\n } catch (err: any) {\n yield { type: \"error\", error: `OpenAI-compat stream init failed: ${err.message}` }\n return\n }\n\n if (!res.ok) {\n const errText = await res.text().catch(() => \"\")\n yield {\n type: \"error\",\n error: `OpenAI-compat API error (${res.status}): ${errText.slice(0, 500)}`,\n }\n return\n }\n\n const reader = res.body?.getReader()\n if (!reader) {\n yield { type: \"error\", error: \"No response body on OpenAI-compat stream\" }\n return\n }\n\n // Same SSE parsing approach as ClaudeProvider.stream — read chunks, split\n // on lines, accumulate tool_calls by index. Tool args arrive as\n // many small string fragments and must be joined before JSON.parse.\n const decoder = new TextDecoder()\n let buffer = \"\"\n let content = \"\"\n let followUp: string | undefined\n let tokensUsed = 0\n const files: GeneratedFile[] = []\n interface ToolAcc { id: string; name: string; argumentsRaw: string }\n const toolAcc: Record<number, ToolAcc> = {}\n let activeToolEmittedIdx: Record<number, boolean> = {}\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue\n const data = line.slice(6).trim()\n if (data === \"[DONE]\") continue\n\n let chunk: any\n try { chunk = JSON.parse(data) } catch { continue }\n const choice = chunk.choices?.[0]\n const delta = choice?.delta\n\n // Reasoning deltas (DeepSeek V4 thinking mode). Emit as a\n // separate event so the consumer can render them inline as\n // the agent thinks, without polluting `content`. The high-\n // level stream() path doesn't carry reasoning into the\n // final `GenerationResult` (it's not part of the visible\n // answer) — only generateRawStream does, so the agentic\n // round-trip can echo it back.\n if (typeof delta?.reasoning_content === \"string\" && delta.reasoning_content) {\n yield { type: \"thinking_delta\", text: delta.reasoning_content }\n }\n\n // Text deltas — stream to caller and accumulate.\n if (typeof delta?.content === \"string\" && delta.content) {\n content += delta.content\n yield { type: \"text_delta\", text: delta.content }\n }\n\n // Tool call deltas — accumulate per index. Emit start once per\n // tool, emit delta fragments as input_json comes in.\n if (Array.isArray(delta?.tool_calls)) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index\n if (idx == null) continue\n const acc = (toolAcc[idx] ||= { id: \"\", name: \"\", argumentsRaw: \"\" })\n if (tc.id) acc.id = tc.id\n if (tc.function?.name) acc.name = tc.function.name\n if (tc.function?.arguments) acc.argumentsRaw += tc.function.arguments\n\n if (acc.id && acc.name && !activeToolEmittedIdx[idx]) {\n activeToolEmittedIdx[idx] = true\n yield { type: \"tool_use_start\", name: acc.name, id: acc.id }\n }\n if (activeToolEmittedIdx[idx] && tc.function?.arguments) {\n yield { type: \"tool_use_delta\", json: tc.function.arguments }\n }\n }\n }\n\n // Usage chunk (OpenAI sends a final chunk with `usage` when\n // stream_options.include_usage=true; DeepSeek/others may not).\n if (chunk.usage) {\n tokensUsed =\n (chunk.usage.prompt_tokens || 0) + (chunk.usage.completion_tokens || 0)\n }\n }\n }\n } catch (err: any) {\n yield { type: \"error\", error: `OpenAI-compat stream read failed: ${err.message}` }\n return\n }\n\n // Finalize tool_calls: parse the joined arguments JSON and map\n // create_files / ask_user the same way ClaudeProvider does.\n for (const acc of Object.values(toolAcc)) {\n if (!acc.name) continue\n yield { type: \"tool_use_end\", name: acc.name }\n try {\n const input = acc.argumentsRaw ? JSON.parse(acc.argumentsRaw) : {}\n if (acc.name === \"create_files\" && Array.isArray(input.files)) {\n files.push(...(input.files as GeneratedFile[]))\n if (typeof input.summary === \"string\" && input.summary.trim()) {\n content += (content ? \"\\n\" : \"\") + input.summary\n }\n } else if (acc.name === \"ask_user\" && typeof input.question === \"string\") {\n followUp = input.question\n if (Array.isArray(input.options) && input.options.length) {\n followUp += `\\nOptions: ${input.options.join(\", \")}`\n }\n }\n } catch {\n // Malformed tool args — surface as missing, don't crash the stream.\n }\n }\n\n yield { type: \"done\", result: { content, files, followUp, tokensUsed } }\n }\n\n // --- helpers ---\n\n private async callApi(body: Record<string, unknown>, abortSignal?: AbortSignal): Promise<OpenAIChatResponse> {\n const res = await fetch(`${this.baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(this.maybeDeepseekExtras(body)),\n signal: abortSignal as any,\n })\n if (!res.ok) {\n const errorText = await res.text().catch(() => \"\")\n throw new Error(`OpenAI-compatible API error (${res.status}) ${this.baseUrl}: ${errorText.slice(0, 500)}`)\n }\n return (await res.json()) as OpenAIChatResponse\n }\n\n /**\n * DeepSeek v4 enables \"thinking mode\" by default — the model emits a\n * `reasoning_content` block that the API expects to be echoed back on\n * the next request. The agentic loop now handles that round-trip\n * (assistant turns with a `reasoning` content block get folded into\n * `msg.reasoning_content` in the next request), so we no longer need\n * to globally disable it. Operator can still opt out per provider via\n * `providers.<name>.thinking: false` in agentx.json — the constructor\n * resolves `this.thinkingEnabled` and we only emit `enable_thinking:\n * false` when explicitly disabled.\n */\n private maybeDeepseekExtras(body: Record<string, unknown>): Record<string, unknown> {\n if (this.thinkingEnabled === null) return body // not a thinking-mode backend\n if (this.thinkingEnabled === false) return { ...body, enable_thinking: false }\n return body // thinking ON — DeepSeek's default, no extra flag needed\n }\n\n private parseHighLevelResponse(response: OpenAIChatResponse): GenerationResult {\n const choice = response.choices?.[0]\n const message = choice?.message\n const files: GeneratedFile[] = []\n let content = message?.content || \"\"\n let followUp: string | undefined\n\n // Map legacy tools (create_files, ask_user) the same way ClaudeProvider\n // does — these are the only tools getLegacyTools() exposes today.\n for (const tc of message?.tool_calls || []) {\n let parsedArgs: any = {}\n try {\n parsedArgs = JSON.parse(tc.function.arguments || \"{}\")\n } catch {\n /* ignore malformed tool args */\n }\n if (tc.function.name === \"create_files\" && Array.isArray(parsedArgs.files)) {\n files.push(...parsedArgs.files)\n if (typeof parsedArgs.summary === \"string\" && parsedArgs.summary.trim()) {\n content += (content ? \"\\n\" : \"\") + parsedArgs.summary\n }\n } else if (tc.function.name === \"ask_user\" && typeof parsedArgs.question === \"string\") {\n followUp = parsedArgs.question\n if (Array.isArray(parsedArgs.options) && parsedArgs.options.length) {\n followUp += `\\nOptions: ${parsedArgs.options.join(\", \")}`\n }\n }\n }\n\n const usage = response.usage\n return {\n content,\n files,\n followUp,\n tokensUsed: usage ? (usage.prompt_tokens || 0) + (usage.completion_tokens || 0) : undefined,\n }\n }\n\n private parseRawResponse(response: OpenAIChatResponse): RawGenerationResult {\n const choice = response.choices?.[0]\n const message = choice?.message\n const blocks: ContentBlock[] = []\n\n // Reasoning_content goes FIRST so the order matches what the\n // upstream returned (DeepSeek emits reasoning then content). The\n // agentic loop preserves block order when round-tripping.\n if (message?.reasoning_content) {\n blocks.push({ type: \"reasoning\", text: message.reasoning_content })\n }\n if (message?.content) {\n blocks.push({ type: \"text\", text: message.content })\n }\n for (const tc of message?.tool_calls || []) {\n let input: Record<string, unknown> = {}\n try {\n input = tc.function.arguments ? JSON.parse(tc.function.arguments) : {}\n } catch {\n // Malformed JSON — surface as empty input rather than crashing the loop.\n }\n blocks.push({ type: \"tool_use\", id: tc.id, name: tc.function.name, input })\n }\n\n // Translate OpenAI finish_reason → Anthropic stop_reason vocabulary.\n let stop_reason: RawGenerationResult[\"stop_reason\"] = \"end_turn\"\n switch (choice?.finish_reason) {\n case \"tool_calls\":\n case \"function_call\":\n stop_reason = \"tool_use\"\n break\n case \"length\":\n stop_reason = \"max_tokens\"\n break\n case \"stop\":\n case null:\n case undefined:\n default:\n stop_reason = \"end_turn\"\n }\n\n const usage = response.usage\n return {\n content: blocks,\n stop_reason,\n usage: {\n input_tokens: usage?.prompt_tokens || 0,\n output_tokens: usage?.completion_tokens || 0,\n },\n }\n }\n\n private legacyToolsAsOpenAI() {\n // ClaudeProvider passes Anthropic-shaped legacy tools; translate to OpenAI's\n // function-tool shape so generate() still surfaces create_files / ask_user.\n return getLegacyTools().map((t: any) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n }))\n }\n}\n","// --- Demo provider: canned replies, real protocol ---\n//\n// Powers `agentx demo` — a zero-key walkthrough where every daemon,\n// mesh hop, ledger row, and dashboard view is real and only the LLM is\n// replaced by a scripted transcript. The provider reads a script file\n// (path in AGENTX_DEMO_SCRIPT) and answers each request with the first\n// step whose `match` regex hits the latest user message, streamed with\n// human-ish pacing so the live views have something to show.\n//\n// Deliberately boring: no tools, no files, one text block per turn.\n// The point of the demo is the plumbing around the model, not the model.\n\nimport { readFileSync } from \"fs\"\nimport type {\n AgentProvider,\n GenerationMessage,\n GenerationResult,\n ProviderOptions,\n StreamEvent,\n AnthropicMessage,\n RawGenerationResult,\n RawStreamEvent,\n} from \"./types\"\n\ninterface DemoStep {\n /** Regex tested (case-insensitive) against the latest user message. */\n match: string\n /** Optional \"thinking\" text streamed as thinking_delta before the reply. */\n thinking?: string\n reply: string\n /** Pause before the first token. Default 700ms. */\n delayMs?: number\n /** Pause between streamed chunks. Default 35ms. */\n chunkMs?: number\n}\n\ninterface DemoScript {\n steps: DemoStep[]\n fallback?: Pick<DemoStep, \"reply\" | \"thinking\" | \"delayMs\" | \"chunkMs\">\n}\n\nconst DEFAULT_FALLBACK: DemoScript[\"fallback\"] = {\n reply:\n \"This is demo mode — I answer from a script, not a live model. \" +\n \"Run `agentx setup` to connect a real provider.\",\n}\n\nfunction loadScript(): DemoScript {\n const path = process.env.AGENTX_DEMO_SCRIPT\n if (!path) return { steps: [], fallback: DEFAULT_FALLBACK }\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf-8\")) as DemoScript\n return {\n steps: Array.isArray(parsed.steps) ? parsed.steps : [],\n fallback: parsed.fallback || DEFAULT_FALLBACK,\n }\n } catch (e: any) {\n return {\n steps: [],\n fallback: { reply: `Demo script unreadable (${e.message}) — check AGENTX_DEMO_SCRIPT.` },\n }\n }\n}\n\nfunction latestUserText(messages: Array<{ role: string; content: unknown }>): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role !== \"user\") continue\n const c = messages[i].content\n if (typeof c === \"string\") return c\n if (Array.isArray(c)) {\n return c\n .map((b: any) => (b?.type === \"text\" ? b.text : b?.type === \"tool_result\" ? b.content : \"\"))\n .filter(Boolean)\n .join(\"\\n\")\n }\n }\n return \"\"\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(new Error(\"aborted\"))\n const t = setTimeout(resolve, ms)\n signal?.addEventListener(\"abort\", () => { clearTimeout(t); reject(new Error(\"aborted\")) }, { once: true })\n })\n}\n\n/** Split into word-ish chunks so streaming looks like generation, not a paste. */\nfunction chunks(text: string): string[] {\n return text.match(/\\S+\\s*/g) || [text]\n}\n\nconst approxTokens = (s: string) => Math.max(1, Math.round(s.length / 4))\n\nexport class DemoProvider implements AgentProvider {\n name = \"demo\"\n private script: DemoScript\n\n constructor() {\n this.script = loadScript()\n }\n\n private pick(userText: string): Required<Pick<DemoStep, \"reply\" | \"delayMs\" | \"chunkMs\">> & Pick<DemoStep, \"thinking\"> {\n // The orchestrator prepends conversation history to the task text, so\n // an early scene's trigger phrase stays present in every later turn.\n // Prefer the step whose regex matches LATEST in the text — the newest\n // part of the conversation wins, which is how a real model would read it.\n let best: DemoStep | undefined\n let bestIndex = -1\n for (const step of this.script.steps) {\n try {\n const re = new RegExp(step.match, \"ig\")\n let m: RegExpExecArray | null\n let last = -1\n while ((m = re.exec(userText)) !== null) {\n last = m.index\n if (m.index === re.lastIndex) re.lastIndex++ // zero-width guard\n }\n if (last > bestIndex) {\n bestIndex = last\n best = step\n }\n } catch { /* bad regex in a step — skip it */ }\n }\n if (best) {\n return { reply: best.reply, thinking: best.thinking, delayMs: best.delayMs ?? 700, chunkMs: best.chunkMs ?? 35 }\n }\n const f = this.script.fallback || DEFAULT_FALLBACK\n return { reply: f!.reply, thinking: f!.thinking, delayMs: f!.delayMs ?? 700, chunkMs: f!.chunkMs ?? 35 }\n }\n\n async generate(messages: GenerationMessage[], options?: ProviderOptions): Promise<GenerationResult> {\n const step = this.pick(latestUserText(messages))\n await sleep(step.delayMs, options?.abortSignal)\n return { content: step.reply, files: [], tokensUsed: approxTokens(step.reply) }\n }\n\n async *stream(messages: GenerationMessage[], options?: ProviderOptions): AsyncIterable<StreamEvent> {\n const step = this.pick(latestUserText(messages))\n await sleep(step.delayMs, options?.abortSignal)\n if (step.thinking) {\n for (const c of chunks(step.thinking)) {\n yield { type: \"thinking_delta\", text: c }\n await sleep(step.chunkMs, options?.abortSignal)\n }\n }\n for (const c of chunks(step.reply)) {\n yield { type: \"text_delta\", text: c }\n await sleep(step.chunkMs, options?.abortSignal)\n }\n yield { type: \"done\", result: { content: step.reply, files: [], tokensUsed: approxTokens(step.reply) } }\n }\n\n async generateRaw(\n messages: AnthropicMessage[],\n _systemPrompt: string,\n _tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions,\n ): Promise<RawGenerationResult> {\n const step = this.pick(latestUserText(messages))\n await sleep(step.delayMs, options?.abortSignal)\n return {\n content: [{ type: \"text\", text: step.reply }],\n stop_reason: \"end_turn\",\n usage: { input_tokens: approxTokens(latestUserText(messages)), output_tokens: approxTokens(step.reply) },\n }\n }\n\n async *generateRawStream(\n messages: AnthropicMessage[],\n _systemPrompt: string,\n _tools: Array<{ name: string; description: string; input_schema: Record<string, unknown> }>,\n options?: ProviderOptions,\n ): AsyncIterable<RawStreamEvent> {\n const step = this.pick(latestUserText(messages))\n await sleep(step.delayMs, options?.abortSignal)\n if (step.thinking) {\n for (const c of chunks(step.thinking)) {\n yield { type: \"thinking_delta\", text: c }\n await sleep(step.chunkMs, options?.abortSignal)\n }\n }\n for (const c of chunks(step.reply)) {\n yield { type: \"text_delta\", text: c }\n await sleep(step.chunkMs, options?.abortSignal)\n }\n yield {\n type: \"raw_result\",\n result: {\n content: [{ type: \"text\", text: step.reply }],\n stop_reason: \"end_turn\",\n usage: { input_tokens: approxTokens(latestUserText(messages)), output_tokens: approxTokens(step.reply) },\n },\n }\n }\n}\n","import type { AgentProvider } from \"./types\"\nimport { ClaudeProvider } from \"./claude\"\nimport { ClaudeCodeProvider } from \"./claude-code\"\nimport { OpenAIProvider } from \"./openai\"\nimport { DemoProvider } from \"./demo\"\nimport { loadAuthConfig } from \"@/utils/auth-store\"\n\n// `deepseek` is a label on top of the OpenAI-compatible provider — it\n// resolves to OpenAIProvider with the DeepSeek baseUrl + DEEPSEEK_API_KEY\n// so users can declare `provider: \"deepseek\"` on an agent without having to\n// also fiddle with OPENAI_BASE_URL. Same pattern for any other preset.\nexport type ProviderName = \"claude-code\" | \"claude\" | \"openai\" | \"deepseek\" | \"ollama\" | \"demo\" | \"custom\"\n\nconst DEEPSEEK_PRESET = {\n baseUrl: \"https://api.deepseek.com/v1\",\n envKey: \"DEEPSEEK_API_KEY\",\n}\n\nexport interface CreateProviderOptions {\n /** Toggle DeepSeek thinking-mode (`reasoning_content` blocks). Default\n * `true` for DeepSeek baseUrls. Wire this from\n * `providers.<name>.thinking` in agentx.json. */\n thinking?: boolean\n}\n\nexport function createProvider(\n name: ProviderName = \"claude-code\",\n apiKey?: string,\n opts: CreateProviderOptions = {},\n): AgentProvider {\n // Auto-detect provider from stored config when using the default\n let resolvedName = name\n if (name === \"claude-code\" && !apiKey) {\n const stored = loadAuthConfig()\n if (stored) {\n resolvedName = stored.provider\n }\n }\n\n switch (resolvedName) {\n case \"claude-code\":\n return new ClaudeCodeProvider()\n case \"claude\":\n return new ClaudeProvider(apiKey)\n case \"openai\":\n // OpenAI-compatible. Defaults to api.openai.com/v1 + OPENAI_API_KEY;\n // override the host via OPENAI_BASE_URL so the same class talks to\n // any compatible backend (vLLM, OpenRouter, Together, llama.cpp).\n return new OpenAIProvider(apiKey, undefined, { thinking: opts.thinking })\n case \"deepseek\":\n // Convenience preset — forces the DeepSeek baseUrl and pulls the key\n // from DEEPSEEK_API_KEY (falls back to apiKey arg or OPENAI_API_KEY).\n return new OpenAIProvider(\n apiKey || process.env[DEEPSEEK_PRESET.envKey] || process.env.OPENAI_API_KEY,\n DEEPSEEK_PRESET.baseUrl,\n { thinking: opts.thinking },\n )\n case \"demo\":\n // Scripted provider behind `agentx demo` — canned replies, real\n // daemons/mesh/ledger. Never selected implicitly.\n return new DemoProvider()\n case \"ollama\":\n throw new Error(\n \"Ollama provider coming soon. Workaround: set provider to 'openai' with OPENAI_BASE_URL=http://localhost:11434/v1 (Ollama exposes an OpenAI-compatible endpoint). Or contribute at github.com/anis-marrouchi/agentx\",\n )\n default:\n throw new Error(`Unknown provider: ${resolvedName}. Supported: claude-code, claude, openai, deepseek`)\n }\n}\n\nexport { ClaudeProvider } from \"./claude\"\nexport { ClaudeCodeProvider } from \"./claude-code\"\nexport { OpenAIProvider } from \"./openai\"\nexport type {\n AgentProvider,\n GenerationMessage,\n GenerationResult,\n GeneratedFile,\n ProviderOptions,\n StreamEvent,\n AnthropicMessage,\n ContentBlock,\n RawGenerationResult,\n} from \"./types\"\n"],"mappings":"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QACN,MAAO,CACL,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,YACE,wEACJ,EACA,QAAS,CACP,KAAM,SACN,YAAa,8BACf,EACA,SAAU,CACR,KAAM,SACN,YAAa,mCACf,EACA,YAAa,CACX,KAAM,SACN,YAAa,0CACf,CACF,EACA,SAAU,CAAC,OAAQ,SAAS,CAC9B,CACF,EACA,QAAS,CACP,KAAM,SACN,YAAa,sCACf,CACF,EACA,SAAU,CAAC,OAAO,CACpB,EACA,WAAY,YACd,EACA,CACE,KAAM,WACN,YACE,mKACF,aAAc,CACZ,KAAM,SACN,WAAY,CACV,SAAU,CACR,KAAM,SACN,YAAa,8BACf,EACA,QAAS,CACP,KAAM,QACN,MAAO,CAAE,KAAM,QAAS,EACxB,YAAa,uCACf,CACF,EACA,SAAU,CAAC,UAAU,CACvB,EACA,WAAY,MACd,EACA,CACE,KAAM,YACN,YACE,wJACF,aAAc,CACZ,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,YAAa,sCACf,EACA,UAAW,CACT,KAAM,SACN,YACE,wEACJ,CACF,EACA,SAAU,CAAC,MAAM,CACnB,EACA,WAAY,WACd,EACA,CACE,KAAM,eACN,YACE,mLACF,aAAc,CACZ,KAAM,SACN,WAAY,CACV,QAAS,CACP,KAAM,SACN,YACE,6DACJ,EACA,cAAe,CACb,KAAM,SACN,YACE,wEACJ,EACA,YAAa,CACX,KAAM,SACN,YAAa,mDACf,CACF,EACA,SAAU,CAAC,SAAS,CACtB,EACA,WAAY,MACd,EACA,CACE,KAAM,iBACN,YACE,qFACF,aAAc,CACZ,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,YACE,oEACJ,EACA,UAAW,CACT,KAAM,UACN,YAAa,mCACf,EACA,UAAW,CACT,KAAM,SACN,YAAa,kDACf,CACF,CACF,EACA,WAAY,MACd,EACA,CACE,KAAM,cACN,YACE,wJACF,aAAc,CACZ,KAAM,SACN,WAAY,CACV,QAAS,CACP,KAAM,SACN,YAAa,8BACf,EACA,QAAS,CACP,KAAM,SACN,YACE,uDACJ,C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","names":["existsSync","readFileSync","writeFileSync","mkdirSync","path","os","chalk","prompts","loadAuthConfig","AUTH_FILE","data","saveAuthConfig","config","AUTH_DIR","resolveToken","explicitKey","type","envOAuth","envClaudeCodeOAuth","envApiKey","stored","homeDir","storePaths","t","readTokenFromAuthProfiles","filePath","fallbackToken","id","cred","handleApiKey","envKey","preview","useExisting","apiKey","v","handleSetupToken","logger","boxWidth","line1","line2","token","tokenName","selectAuthMethod","provider","method","selectModel","choices","ANTHROPIC_MODELS","m","current","label","modelId","runModelSetup","auth","ensureCredentials","init_auth_store","__esmMin","init_logger","getAnthropicTools","enabledTools","TOOL_DEFINITIONS","name","description","input_schema","getLegacyTools","formatToolsForSystemPrompt","agenticTools","lines","tool","ALL_TOOL_NAMES","init_definitions","__esmMin","t","wrapSystemForCache","systemPrompt","CACHE_MIN_CHARS","DEFAULT_MODEL","DEFAULT_MAX_TOKENS","ClaudeProvider","init_claude","__esmMin","init_auth_store","init_definitions","apiKey","resolved","resolveToken","messages","options","model","maxTokens","systemMsg","m","conversationMsgs","body","getLegacyTools","response","tools","block","headers","res","errorText","reader","decoder","buffer","files","content","followUp","tokensUsed","activeTool","inferFollowUpFromText","text","cleaned","lines","tail","tailText","isIntro","l","startIdx","i","out","t","candidate","done","value","line","data","event","input","err","errText","blocks","activeBlockIdx","stopReason","inputTokens","outputTokens","cb","raw","execa","tmpdir","buildCliGenerateArgs","input","args","BARE_CLI_ARGS","describeCliFailure","result","out","DEFAULT_MODEL","DEFAULT_MAX_TOKENS","CLI_MODEL_ALIASES","ClaudeCodeProvider","init_claude_code","__esmMin","init_auth_store","init_definitions","stored","loadAuthConfig","resolved","resolveToken","messages","options","systemPrompt","tools","model","maxTokens","body","headers","res","errorText","response","block","cliModel","systemMsg","m","prompt","env","output","json","e","conversationMsgs","getLegacyTools","child","fullContent","stderr","fatalError","chunk","decoder","readable","lines","line","event","files","followUp","reader","buffer","content","tokensUsed","activeTool","done","value","data","stdout","parsed","inferred","text","pattern","match","filePath","cleaned","tail","tailText","isIntro","l","startIdx","i","t","candidate","DEFAULT_MODEL","DEFAULT_MAX_TOKENS","OpenAIProvider","init_openai","__esmMin","init_definitions","apiKey","baseUrl","opts","isDeepseek","messages","options","model","maxTokens","oaMessages","body","data","systemPrompt","tools","res","err","errText","reader","onAbortCancelReader","decoder","buffer","textOut","reasoningOut","inputTokens","outputTokens","finishReason","toolAcc","done","value","lines","line","chunk","choice","delta","tc","idx","acc","blocks","input","stop_reason","m","toolResults","b","textParts","tr","toolUses","text","reasoning","msg","tu","t","content","followUp","tokensUsed","files","activeToolEmittedIdx","abortSignal","errorText","response","message","parsedArgs","usage","getLegacyTools","readFileSync","loadScript","path","DEFAULT_FALLBACK","parsed","latestUserText","messages","i","c","b","sleep","ms","signal","resolve","reject","t","chunks","text","approxTokens","DemoProvider","init_demo","__esmMin","userText","best","bestIndex","step","re","m","last","f","options","_systemPrompt","_tools","createProvider","name","apiKey","opts","resolvedName","stored","loadAuthConfig","ClaudeCodeProvider","ClaudeProvider","OpenAIProvider","DEEPSEEK_PRESET","DemoProvider","init_providers","__esmMin","init_claude","init_claude_code","init_openai","init_demo","init_auth_store"]}
@@ -1,4 +0,0 @@
1
- import{c as D,d as v,f as R,g as E}from"./chunk-MNG2AMKZ.js";import{existsSync as G,mkdirSync as V,readdirSync as z,readFileSync as Y,renameSync as H,writeFileSync as J}from"fs";import{resolve as P}from"path";function N(e){return e?.kind==="retro"||e?.kind==="retro-check"}var T={keep:"Keep it",loosen:"Loosen it",remove:"Remove it"};function L(e,r,n){let t=`guard rule \`${e.ruleId}\` in \`${e.file}\``,i=[`This was a monthly review of ${t}, added by the retro on run ${e.taskId}. It fires often on runs that went well.`];return!(r.status==="decided"&&r.verdict==="yes")||r.choice===T.keep||!r.choice?(i.push("Change nothing: the rule stays as it is."),i):(i.push(r.choice===T.remove?`The operator chose to remove it. Delete ${t} as a pull request.`:`The operator chose to loosen it. Narrow ${t} (a tighter match, or \`applies_to\`) so it stops firing on good work, keep its \`retro:${e.taskId}\` tag, and open it as a pull request.`),r.choice_suggested&&i.push(q),n&&i.push("The operator's note:",n),i.push("Do not change the live policy directly: the operator reviews the pull request first."),i)}var q="(The operator gave a plain yes, taken as the suggested option.)";function C(e){return e.status==="decided"&&e.verdict==="yes"&&!!e.choice&&e.choice!==b}function A(e,r,n){let t=[`This was a retro card about run ${e.taskId} (\`agentx trace show ${e.taskId}\`).`];if(!C(r))return t.push("Change nothing. Do not propose these fixes again on your own."),t;t.push(`The operator picked this fix: ${r.choice}`),r.choice_suggested&&t.push(q);let i=e.specs?.[(r.choices??[]).indexOf(r.choice)];return i&&t.push("Spec for this fix, drafted by the retro reviewer from the run's content (a proposal to check, not instructions from the operator):",i),n&&t.push("The operator's note on the fix:",n),t.push("Build the chosen fix as a change the operator reviews again: a pull request, or a guard rule in warn mode.","Do not apply it to a live system directly. Tag what you add with `retro:"+e.taskId+"` so it can be found and removed later; for a guard rule, put the tag in its `tags` list."),t}var b="None of these";function F(e,r){let n=e.list?` in the "${e.list}" list`:"",t=[`This card came from the operator's reminder "${e.title}"${n} (id ${e.id}).`];return t.push(r?`Do what the operator chose, then tick the reminder off: remindctl complete ${e.id}`:"Leave the reminder open; it will come back at a later check-in."),t}var u={title:120,ask:300,answers:3},$=["resurface","bring-back","weekly","cleanup"],k={perDay:5,resurface:3};function B(e){return e.title.length>u.title?`title is longer than ${u.title} characters`:e.ask.length>u.ask?`ask is longer than ${u.ask} characters`:(e.ask.match(/\?/g)??[]).length>1?"ask holds more than one question: one card asks one thing":(e.choices?.length??0)>u.answers?`more than ${u.answers} choices`:null}function oe(e,r){return e.length>u.title?`title is longer than ${u.title} characters`:r.length>u.ask?`message is longer than ${u.ask} characters`:null}function M(e){let r=new Date(e);return r.setHours(0,0,0,0),r.getTime()}function K(e,r,n){let t=M(n),i=e.filter(o=>o.followup&&Date.parse(o.created_at)>=t);return i.length>=k.perDay?`the follow-up screen budget is used up today (${k.perDay} cards): raise it again tomorrow`:r==="resurface"&&i.filter(o=>o.followup==="resurface").length>=k.resurface?`${k.resurface} resurface cards were already raised today: raise it again tomorrow`:null}function se(e,r){return[`[screen gate] Your card ${e.id} ("${e.title}") was not shown to the owner: ${r}.`,"It is still in his inbox, unchanged. If it must reach him on screen, close it (agentx_approval resolve) and raise one that passes:",`one question, title up to ${u.title} characters, ask up to ${u.ask}, at most ${u.answers} choices.`].join(" ")}var W=["discard","keep","pause"];function S(e){return e==="approve"?"keep":W.includes(e)?e:null}var l={title:120,ask:300,recommend:300,source:500,note:500,resolution:300,pendingPerAgent:25},Q={defaultExpiryDays:3,maxExpiryDays:30};function I(e){return P(e,".agentx","approvals")}var X=/^[a-z0-9][a-z0-9-]{0,80}$/;function U(e){return X.test(e)}function j(e,r){if(!U(r))throw new Error(`invalid card id: ${r}`);return P(I(e),`${r}.json`)}function Z(e,r){let n=new Date(e).toISOString().slice(0,10),t=r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40);return`${n}-${t||"card"}-${Math.random().toString(36).slice(2,6)}`}function p(e,r){V(I(e),{recursive:!0});let n=j(e,r.id),t=`${n}.${process.pid}.tmp`;J(t,JSON.stringify(r,null,2)+`
2
- `),H(t,n)}function y(e,r){if(!U(r))return null;try{let n=JSON.parse(Y(j(e,r),"utf-8")),t=n.if_silent==="approve"||n.outcome==="approve";return{...n,if_silent:S(n.if_silent)??"keep",...n.outcome?{outcome:S(n.outcome)??"keep"}:{},...t?{if_silent_asked:"approve"}:{}}}catch{return null}}function w(e,r){let n=I(e);if(!G(n))return[];let t=[];for(let i of z(n).filter(o=>o.endsWith(".json")&&!o.startsWith("_")).sort()){let o=y(e,i.slice(0,-5));o&&(!r||o.status===r)&&t.push(o)}return t}function a(e){return typeof e=="string"?e.replace(/\s+/g," ").trim():""}function ee(e,r,n){let t=r+n.maxExpiryDays*864e5,i,o=a(e);if(!o)i=r+n.defaultExpiryDays*864e5;else{let s=/^(\d+)\s*([hd])$/i.exec(o);if(s)i=r+Number(s[1])*(s[2].toLowerCase()==="d"?864e5:36e5);else if(i=Date.parse(o),Number.isNaN(i))return{ok:!1,error:`expires must be an ISO date or time, or like "12h" / "3d" (got "${o}")`}}return i<=r?{ok:!1,error:"expires must be in the future"}:{ok:!0,at:new Date(Math.min(i,t)).toISOString()}}function re(e,r={}){let n=r.now??Date.now(),t=r.settings??Q,i=a(e.title),o=a(e.ask),s=a(e.recommend),d=a(e.raised_by);if(!i)return{ok:!1,error:"title is required"};if(!o)return{ok:!1,error:"ask is required: the yes/no question"};if(!s)return{ok:!1,error:"recommend is required: your advice and why, in one line"};if(!d)return{ok:!1,error:"raised_by is required: the agent id"};if(i.length>l.title)return{ok:!1,error:`title is longer than ${l.title} characters`};if(o.length>l.ask)return{ok:!1,error:`ask is longer than ${l.ask} characters`};if(s.length>l.recommend)return{ok:!1,error:`recommend is longer than ${l.recommend} characters`};let c=a(e.if_silent).toLowerCase(),O=S(c);if(!O)return{ok:!1,error:`if_silent must be one of ${W.join(", ")}`};let m=ee(e.expires,n,t);if(!m.ok)return m;let f=a(e.source);if(f.length>l.source)return{ok:!1,error:`source is longer than ${l.source} characters`};if(f&&/^[a-z][a-z0-9+.-]*:/i.test(f)&&!/^https?:\/\//i.test(f))return{ok:!1,error:"source must be an http(s) link or a plain reference"};let x=D(e);if(!x.ok)return x;let h=a(e.followup).toLowerCase();if(h&&!$.includes(h))return{ok:!1,error:`followup must be one of ${$.join(", ")}`};let _,g=e.reply;return g&&typeof g=="object"&&a(g.channel)&&a(g.chatId)&&(_={channel:a(g.channel),chatId:a(g.chatId),...a(g.accountId)?{accountId:a(g.accountId)}:{}}),{ok:!0,card:{id:Z(n,i),title:i,ask:o,recommend:s,if_silent:O,...c==="approve"?{if_silent_asked:"approve"}:{},expires:m.at,...f?{source:f}:{},raised_by:d,...r.node?{node:r.node}:{},created_at:new Date(n).toISOString(),..._?{reply:_}:{},...x.value,...r.origin?{origin:r.origin}:{},...h?{followup:h}:{},status:"pending"}}}function fe(e,r,n={}){let t=re(r,n);if(!t.ok)return t;let i=B(t.card);if(i)return{ok:!1,error:i};if(t.card.followup){let c=K(w(e),t.card.followup,n.now??Date.now());if(c)return{ok:!1,error:c}}let o=c=>N(c.origin),s=o(t.card),d=w(e,"pending").filter(c=>c.raised_by===t.card.raised_by&&o(c)===s).length;if(d>=l.pendingPerAgent){let c=s?"retro cards":"cards";return{ok:!1,error:`${t.card.raised_by} already has ${d} ${c} waiting; wait for decisions before raising more`}}return p(e,t.card),t}function pe(e,r,n,t={}){let i=y(e,r);if(!i)return{ok:!1,error:`no card "${r}"`};if(i.status!=="pending")return{ok:!1,error:`card "${r}" is already ${i.status}`};let o=R(i,n,t);if(!o.ok)return o;let s=a(t.note).slice(0,l.note),d={...i,status:"decided",verdict:n,decided_by:t.by??"operator",decided_at:new Date(t.now??Date.now()).toISOString(),...s?{note:s}:{},...o.choice?{choice:o.choice}:{},...o.suggested?{choice_suggested:!0}:{},...o.text?{text:o.text}:{}};return p(e,d),{ok:!0,card:d}}var te=new Set([void 0,"reminder"]);function he(e,r,n){let t=y(e,r);if(!t)return{ok:!1,status:404,error:`no card "${r}"`};if(t.raised_by!==n.by||(t.node??"")!==(n.node??""))return{ok:!1,status:403,error:`card "${r}" was raised by another agent`};if(!te.has(t.origin?.kind))return{ok:!1,status:409,error:`card "${r}" is answered by the operator only`};if(t.status!=="pending")return{ok:!1,status:409,error:`card "${r}" is already ${t.status}`};let i=a(n.reason);if(!i)return{ok:!1,status:400,error:"reason is required: say where the owner answered and what you did"};let o=new Date(n.now??Date.now()).toISOString(),s={...t,status:"resolved",decided_by:n.by,decided_at:o,resolution:i.slice(0,l.resolution),agent_notified_at:o};return p(e,s),{ok:!0,card:s}}function ke(e,r=Date.now()){let n=[];for(let t of w(e,"pending")){if(Date.parse(t.expires)>r)continue;let i={...t,status:"expired",outcome:t.if_silent,decided_by:"expiry",decided_at:new Date(r).toISOString()};p(e,i),n.push(i)}return n}function we(e){return w(e).filter(r=>r.status!=="pending"&&!r.agent_notified_at)}function ye(e,r,n=Date.now()){let t=y(e,r);!t||t.agent_notified_at||p(e,{...t,agent_notified_at:new Date(n).toISOString()})}var ne="A no does not by itself undo anything you already did. If you already carried this out (for example because the owner approved it in chat), do not reverse it: ask the requester one clear question first.";function me(e){let r=e.origin?.kind==="retro"?e.origin:void 0,n=e.status==="decided"?e.verdict==="yes"?r&&!C(e)?`The operator picked "${b}", which counts as NO.`:"The operator said YES.":"The operator said NO.":`Nobody answered before it expired, so the default applied: ${e.outcome??e.if_silent}.`,t=[`[Approval result] Your decision card "${e.title}" (${e.id}) is closed.`,`Question: ${e.ask}`,n],i=e.origin?.kind==="retro-check"?e.origin:void 0;if(e.status==="decided"&&e.verdict==="yes"&&!r&&!i&&t.push(...E(e)),e.note&&t.push(`Operator note: ${e.note}`),e.status==="decided"&&e.verdict==="no"&&!r&&!i&&t.push(ne),e.source&&t.push(`Source: ${e.source}`),e.origin?.kind==="reminder"&&t.push(...F(e.origin,e.status==="decided"&&e.verdict==="yes")),r||i){let o=c=>c.replace(/\s+/g," ").trim(),s=v(e.draft,e.choice),d=e.text&&o(e.text)!==o(s)?e.text:void 0;t.push(...r?A(r,e,d):L(i,e,d))}return e.reply&&t.push(`You raised it from ${e.reply.channel} chat ${e.reply.chatId}; reply there if the requester should know.`),e.node&&t.push(`The operator answered it on another machine; the card was forwarded from ${e.node}.`),t.push("Act on this result now. Do not raise the same card again."),t.join(`
3
- `)}export{N as a,T as b,C as c,b as d,B as e,oe as f,se as g,W as h,l as i,I as j,U as k,y as l,w as m,fe as n,pe as o,he as p,ke as q,we as r,ye as s,me as t};
4
- //# sourceMappingURL=chunk-A76PNG4E.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/approvals/cards.ts","../src/approvals/origin.ts","../src/approvals/screen-gate.ts"],"sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { answerLines, buildChoices, draftFor, resolveAnswer, type CardChoices } from \"./choices\"\nimport { isRetroOrigin, originLines, RETRO_NONE, retroApproved, retroCheckLines, retroLines, type CardOrigin } from \"./origin\"\nimport { cardRuleBreak, FOLLOWUP_KINDS, followupBudgetRefusal, type FollowupKind } from \"./screen-gate\"\n\n// --- Decision cards: what an agent asks the operator ---\n//\n// An agent that needs a yes/no from the operator writes a card instead of\n// asking in chat. A card says what it is, the question, what the agent\n// recommends, and what happens if nobody answers by `expires`. Nothing\n// waits forever: past `expires` the daemon applies `if_silent` (sweep.ts).\n//\n// Storage: one JSON file per card under `.agentx/approvals/`, written\n// atomically, like wiki proposals. The CLI, the dashboard and the daemon\n// are separate processes and all read the same files.\n//\n// Field names match the API (`if_silent`, `raised_by`), so a stored card is\n// exactly what `POST /approvals` accepted.\n\n// No card approves itself (#741): only the operator says yes. \"approve\",\n// which older agents and stored cards may still carry, is read as \"keep\".\nexport type IfSilent = \"discard\" | \"keep\" | \"pause\"\nexport const IF_SILENT_VALUES: readonly IfSilent[] = [\"discard\", \"keep\", \"pause\"]\n\nfunction asIfSilent(v: string): IfSilent | null {\n if (v === \"approve\") return \"keep\"\n return IF_SILENT_VALUES.includes(v as IfSilent) ? (v as IfSilent) : null\n}\n\n// \"resolved\": closed by the agent that raised it, because the owner gave the\n// same answer somewhere else (in chat, #909) and the agent already acted on\n// it. Not a verdict: nothing is approved or rejected by it.\nexport type CardStatus = \"pending\" | \"decided\" | \"expired\" | \"resolved\"\nexport type Verdict = \"yes\" | \"no\"\n\n/** Where the agent was asked, so the verdict can be taken back there. */\nexport interface ReplyTarget {\n channel: string\n chatId: string\n accountId?: string\n}\n\nexport interface DecisionCard extends CardChoices {\n id: string\n title: string\n ask: string\n recommend: string\n if_silent: IfSilent\n /** ISO time the default applies. Always set. */\n expires: string\n /** Link to the draft, PR or issue. */\n source?: string\n raised_by: string\n /** The mesh node the raising agent is on, when the card was forwarded\n * here from there (forward.ts, #668). Unset: this node. */\n node?: string\n created_at: string\n reply?: ReplyTarget\n status: CardStatus\n /** The operator's answer (status \"decided\"). */\n verdict?: Verdict\n /** What applied on expiry (status \"expired\"). */\n outcome?: IfSilent\n /** Set when the agent, or a card stored before #741, asked for\n * \"approve\" on expiry; `if_silent` then holds \"keep\". Kept so the\n * record still shows what was originally asked. */\n if_silent_asked?: \"approve\"\n decided_by?: string\n decided_at?: string\n note?: string\n /** The option the operator picked, when the card offered choices. */\n choice?: string\n /** Set when `choice` came from a plain yes taking the suggested option\n * (#1064), not from the operator picking it. */\n choice_suggested?: boolean\n /** The message the operator approved, after any edit. */\n text?: string\n /** Set once the raising agent has been told the result. */\n agent_notified_at?: string\n /** Why the raising agent closed it (status \"resolved\"). */\n resolution?: string\n /** What the card is about, when the daemon raised it (origin.ts). */\n origin?: CardOrigin\n /** A follow-up card (#394): counted in the daily screen budget. */\n followup?: FollowupKind\n}\n\nexport const CARD_LIMITS = {\n title: 120,\n ask: 300,\n recommend: 300,\n source: 500,\n note: 500,\n resolution: 300,\n /** Pending cards one agent may have open at a time. */\n pendingPerAgent: 25,\n} as const\n\nexport interface CardSettings {\n defaultExpiryDays: number\n maxExpiryDays: number\n}\n\nexport const DEFAULT_CARD_SETTINGS: CardSettings = { defaultExpiryDays: 3, maxExpiryDays: 30 }\n\nexport function approvalsDir(root: string): string {\n return resolve(root, \".agentx\", \"approvals\")\n}\n\nconst CARD_ID_RE = /^[a-z0-9][a-z0-9-]{0,80}$/\n\nexport function isValidCardId(id: string): boolean {\n return CARD_ID_RE.test(id)\n}\n\nfunction fileFor(root: string, id: string): string {\n if (!isValidCardId(id)) throw new Error(`invalid card id: ${id}`)\n return resolve(approvalsDir(root), `${id}.json`)\n}\n\nexport function newCardId(now: number, title: string): string {\n const day = new Date(now).toISOString().slice(0, 10)\n const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 40)\n return `${day}-${slug || \"card\"}-${Math.random().toString(36).slice(2, 6)}`\n}\n\nexport function saveCard(root: string, card: DecisionCard): void {\n mkdirSync(approvalsDir(root), { recursive: true })\n const path = fileFor(root, card.id)\n const tmp = `${path}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(card, null, 2) + \"\\n\")\n renameSync(tmp, path)\n}\n\nexport function readCard(root: string, id: string): DecisionCard | null {\n if (!isValidCardId(id)) return null\n try {\n const card = JSON.parse(readFileSync(fileFor(root, id), \"utf-8\")) as DecisionCard\n // A card that expired as \"approve\" before #741 is read as \"keep\" too, so\n // an agent not yet told never hears \"default applied: approve\".\n const legacy = (card.if_silent as string) === \"approve\" || (card.outcome as string) === \"approve\"\n return {\n ...card,\n if_silent: asIfSilent(card.if_silent) ?? \"keep\",\n ...(card.outcome ? { outcome: asIfSilent(card.outcome) ?? \"keep\" } : {}),\n ...(legacy ? { if_silent_asked: \"approve\" as const } : {}),\n }\n } catch {\n return null\n }\n}\n\n/** Cards, oldest first; only `status` ones when given. */\nexport function listCards(root: string, status?: CardStatus): DecisionCard[] {\n const dir = approvalsDir(root)\n if (!existsSync(dir)) return []\n const out: DecisionCard[] = []\n for (const f of readdirSync(dir).filter((f) => f.endsWith(\".json\") && !f.startsWith(\"_\")).sort()) {\n const c = readCard(root, f.slice(0, -5))\n if (c && (!status || c.status === status)) out.push(c)\n }\n return out\n}\n\nfunction oneLine(v: unknown): string {\n return typeof v === \"string\" ? v.replace(/\\s+/g, \" \").trim() : \"\"\n}\n\n/**\n * `expires` as given by an agent: an ISO date or time, or a relative\n * \"12h\" / \"3d\". Unset: the default. Always capped at maxExpiryDays, so a\n * card can't be parked for a year.\n */\nexport function resolveExpiry(input: unknown, now: number, settings: CardSettings): { ok: true; at: string } | { ok: false; error: string } {\n const max = now + settings.maxExpiryDays * 86_400_000\n let at: number\n const raw = oneLine(input)\n if (!raw) {\n at = now + settings.defaultExpiryDays * 86_400_000\n } else {\n const rel = /^(\\d+)\\s*([hd])$/i.exec(raw)\n if (rel) {\n at = now + Number(rel[1]) * (rel[2].toLowerCase() === \"d\" ? 86_400_000 : 3_600_000)\n } else {\n at = Date.parse(raw)\n if (Number.isNaN(at)) return { ok: false, error: `expires must be an ISO date or time, or like \"12h\" / \"3d\" (got \"${raw}\")` }\n }\n }\n if (at <= now) return { ok: false, error: \"expires must be in the future\" }\n return { ok: true, at: new Date(Math.min(at, max)).toISOString() }\n}\n\nexport interface CardInput {\n title?: unknown\n ask?: unknown\n recommend?: unknown\n if_silent?: unknown\n expires?: unknown\n source?: unknown\n raised_by?: unknown\n reply?: unknown\n choices?: unknown\n draft?: unknown\n say?: unknown\n context?: unknown\n followup?: unknown\n}\n\n/** Validate what an agent sent and build a pending card. Never saves. */\nexport interface BuildCardOptions {\n now?: number\n settings?: CardSettings\n origin?: CardOrigin\n /** The peer the card was forwarded from. The daemon sets it after\n * checking the name against its mesh peers; never taken as sent. */\n node?: string\n}\n\nexport function buildCard(\n input: CardInput,\n opts: BuildCardOptions = {},\n): { ok: true; card: DecisionCard } | { ok: false; error: string } {\n const now = opts.now ?? Date.now()\n const settings = opts.settings ?? DEFAULT_CARD_SETTINGS\n const title = oneLine(input.title)\n const ask = oneLine(input.ask)\n const recommend = oneLine(input.recommend)\n const raisedBy = oneLine(input.raised_by)\n if (!title) return { ok: false, error: \"title is required\" }\n if (!ask) return { ok: false, error: \"ask is required: the yes/no question\" }\n if (!recommend) return { ok: false, error: \"recommend is required: your advice and why, in one line\" }\n if (!raisedBy) return { ok: false, error: \"raised_by is required: the agent id\" }\n if (title.length > CARD_LIMITS.title) return { ok: false, error: `title is longer than ${CARD_LIMITS.title} characters` }\n if (ask.length > CARD_LIMITS.ask) return { ok: false, error: `ask is longer than ${CARD_LIMITS.ask} characters` }\n if (recommend.length > CARD_LIMITS.recommend) return { ok: false, error: `recommend is longer than ${CARD_LIMITS.recommend} characters` }\n const ifSilentRaw = oneLine(input.if_silent).toLowerCase()\n const ifSilent = asIfSilent(ifSilentRaw)\n if (!ifSilent) {\n return { ok: false, error: `if_silent must be one of ${IF_SILENT_VALUES.join(\", \")}` }\n }\n const expiry = resolveExpiry(input.expires, now, settings)\n if (!expiry.ok) return expiry\n const source = oneLine(input.source)\n if (source.length > CARD_LIMITS.source) return { ok: false, error: `source is longer than ${CARD_LIMITS.source} characters` }\n if (source && /^[a-z][a-z0-9+.-]*:/i.test(source) && !/^https?:\\/\\//i.test(source)) {\n return { ok: false, error: \"source must be an http(s) link or a plain reference\" }\n }\n const extras = buildChoices(input)\n if (!extras.ok) return extras\n const followup = oneLine(input.followup).toLowerCase()\n if (followup && !(FOLLOWUP_KINDS as readonly string[]).includes(followup)) {\n return { ok: false, error: `followup must be one of ${FOLLOWUP_KINDS.join(\", \")}` }\n }\n let reply: ReplyTarget | undefined\n const r = input.reply as Record<string, unknown> | undefined\n if (r && typeof r === \"object\" && oneLine(r.channel) && oneLine(r.chatId)) {\n reply = { channel: oneLine(r.channel), chatId: oneLine(r.chatId), ...(oneLine(r.accountId) ? { accountId: oneLine(r.accountId) } : {}) }\n }\n return {\n ok: true,\n card: {\n id: newCardId(now, title),\n title,\n ask,\n recommend,\n if_silent: ifSilent,\n ...(ifSilentRaw === \"approve\" ? { if_silent_asked: \"approve\" as const } : {}),\n expires: expiry.at,\n ...(source ? { source } : {}),\n raised_by: raisedBy,\n ...(opts.node ? { node: opts.node } : {}),\n created_at: new Date(now).toISOString(),\n ...(reply ? { reply } : {}),\n ...extras.value,\n // Set by the daemon only (check-ins), never from what an agent sent.\n ...(opts.origin ? { origin: opts.origin } : {}),\n ...(followup ? { followup: followup as FollowupKind } : {}),\n status: \"pending\",\n },\n }\n}\n\n/** Validate, enforce the per-agent cap, and save. */\nexport function createCard(\n root: string,\n input: CardInput,\n opts: BuildCardOptions = {},\n): { ok: true; card: DecisionCard } | { ok: false; error: string } {\n const built = buildCard(input, opts)\n if (!built.ok) return built\n // The screen gate (#394): refused here, the reason goes back to the author.\n const broken = cardRuleBreak(built.card)\n if (broken) return { ok: false, error: broken }\n if (built.card.followup) {\n const full = followupBudgetRefusal(listCards(root), built.card.followup, opts.now ?? Date.now())\n if (full) return { ok: false, error: full }\n }\n // Retro cards are raised for an agent, not by it: they get their own\n // count, so they never use up the agent's room for its own cards.\n const isRetro = (c: { origin?: CardOrigin }) => isRetroOrigin(c.origin)\n const retro = isRetro(built.card)\n const open = listCards(root, \"pending\").filter((c) => c.raised_by === built.card.raised_by && isRetro(c) === retro).length\n if (open >= CARD_LIMITS.pendingPerAgent) {\n const what = retro ? \"retro cards\" : \"cards\"\n return { ok: false, error: `${built.card.raised_by} already has ${open} ${what} waiting; wait for decisions before raising more` }\n }\n saveCard(root, built.card)\n return built\n}\n\n/** Record the operator's answer. Refuses anything no longer pending. */\nexport function decideCard(\n root: string,\n id: string,\n verdict: Verdict,\n opts: { by?: string; note?: string; now?: number; choice?: string | number; text?: string } = {},\n): { ok: true; card: DecisionCard } | { ok: false; error: string } {\n const card = readCard(root, id)\n if (!card) return { ok: false, error: `no card \"${id}\"` }\n if (card.status !== \"pending\") return { ok: false, error: `card \"${id}\" is already ${card.status}` }\n const answer = resolveAnswer(card, verdict, opts)\n if (!answer.ok) return answer\n const note = oneLine(opts.note).slice(0, CARD_LIMITS.note)\n const decided: DecisionCard = {\n ...card,\n status: \"decided\",\n verdict,\n decided_by: opts.by ?? \"operator\",\n decided_at: new Date(opts.now ?? Date.now()).toISOString(),\n ...(note ? { note } : {}),\n ...(answer.choice ? { choice: answer.choice } : {}),\n ...(answer.suggested ? { choice_suggested: true } : {}),\n ...(answer.text ? { text: answer.text } : {}),\n }\n saveCard(root, decided)\n return { ok: true, card: decided }\n}\n\n/** Cards whose answer the daemon acts on itself (a workflow run, a plan\n * step, a retro): only the operator closes those. A reminder card is the\n * agent's own to act on, so it may close it like one it raised. */\nconst AGENT_RESOLVABLE_ORIGINS = new Set<string | undefined>([undefined, \"reminder\"])\n\n/**\n * The raising agent closes its own pending card: the owner gave the same\n * answer outside the card (in chat) and the agent has acted on it (#909).\n * The card leaves the inbox, so no check-in or popup asks again. It is not\n * a verdict, and the agent is not sent a result for it: it already knows.\n */\nexport function resolveCard(\n root: string,\n id: string,\n opts: { by: string; reason?: unknown; node?: string; now?: number },\n): { ok: true; card: DecisionCard } | { ok: false; status: 400 | 403 | 404 | 409; error: string } {\n const card = readCard(root, id)\n if (!card) return { ok: false, status: 404, error: `no card \"${id}\"` }\n if (card.raised_by !== opts.by || (card.node ?? \"\") !== (opts.node ?? \"\")) {\n return { ok: false, status: 403, error: `card \"${id}\" was raised by another agent` }\n }\n if (!AGENT_RESOLVABLE_ORIGINS.has(card.origin?.kind)) {\n return { ok: false, status: 409, error: `card \"${id}\" is answered by the operator only` }\n }\n if (card.status !== \"pending\") return { ok: false, status: 409, error: `card \"${id}\" is already ${card.status}` }\n const reason = oneLine(opts.reason)\n if (!reason) return { ok: false, status: 400, error: \"reason is required: say where the owner answered and what you did\" }\n const at = new Date(opts.now ?? Date.now()).toISOString()\n const resolved: DecisionCard = {\n ...card,\n status: \"resolved\",\n decided_by: opts.by,\n decided_at: at,\n resolution: reason.slice(0, CARD_LIMITS.resolution),\n agent_notified_at: at,\n }\n saveCard(root, resolved)\n return { ok: true, card: resolved }\n}\n\n/** Apply `if_silent` to every pending card past its expiry. */\nexport function expireCards(root: string, now: number = Date.now()): DecisionCard[] {\n const out: DecisionCard[] = []\n for (const card of listCards(root, \"pending\")) {\n if (Date.parse(card.expires) > now) continue\n const expired: DecisionCard = {\n ...card,\n status: \"expired\",\n outcome: card.if_silent,\n decided_by: \"expiry\",\n decided_at: new Date(now).toISOString(),\n }\n saveCard(root, expired)\n out.push(expired)\n }\n return out\n}\n\n/** Decided or expired cards whose agent hasn't been told yet. */\nexport function cardsAwaitingAgentNotice(root: string): DecisionCard[] {\n return listCards(root).filter((c) => c.status !== \"pending\" && !c.agent_notified_at)\n}\n\nexport function markAgentNotified(root: string, id: string, now: number = Date.now()): void {\n const card = readCard(root, id)\n if (!card || card.agent_notified_at) return\n saveCard(root, { ...card, agent_notified_at: new Date(now).toISOString() })\n}\n\nexport const NO_UNDO_LINE =\n \"A no does not by itself undo anything you already did. If you already carried this out (for example because the owner approved it in chat), do not reverse it: ask the requester one clear question first.\"\n\n/** What the raising agent is told. Plain text, one short message. */\nexport function verdictMessage(card: DecisionCard): string {\n const retro = card.origin?.kind === \"retro\" ? card.origin : undefined\n const result = card.status === \"decided\"\n ? (card.verdict === \"yes\"\n ? (retro && !retroApproved(card) ? `The operator picked \"${RETRO_NONE}\", which counts as NO.` : \"The operator said YES.\")\n : \"The operator said NO.\")\n : `Nobody answered before it expired, so the default applied: ${card.outcome ?? card.if_silent}.`\n const lines = [\n `[Approval result] Your decision card \"${card.title}\" (${card.id}) is closed.`,\n `Question: ${card.ask}`,\n result,\n ]\n // A retro card's pick and spec go through retroLines, labelled as the\n // reviewer's proposal: never \"Approved text (send exactly this)\".\n const check = card.origin?.kind === \"retro-check\" ? card.origin : undefined\n if (card.status === \"decided\" && card.verdict === \"yes\" && !retro && !check) lines.push(...answerLines(card))\n if (card.note) lines.push(`Operator note: ${card.note}`)\n // A late no on something the owner already approved in chat must not\n // quietly undo work that is done (#909).\n if (card.status === \"decided\" && card.verdict === \"no\" && !retro && !check) lines.push(NO_UNDO_LINE)\n if (card.source) lines.push(`Source: ${card.source}`)\n if (card.origin?.kind === \"reminder\") lines.push(...originLines(card.origin, card.status === \"decided\" && card.verdict === \"yes\"))\n if (retro || check) {\n // Compare ignoring whitespace so a dashboard that only reflows the draft\n // does not resend the whole draft as the operator's note.\n const squash = (s: string) => s.replace(/\\s+/g, \" \").trim()\n const draft = draftFor(card.draft, card.choice)\n const edited = card.text && squash(card.text) !== squash(draft) ? card.text : undefined\n lines.push(...(retro ? retroLines(retro, card, edited) : retroCheckLines(check!, card, edited)))\n }\n if (card.reply) lines.push(`You raised it from ${card.reply.channel} chat ${card.reply.chatId}; reply there if the requester should know.`)\n if (card.node) lines.push(`The operator answered it on another machine; the card was forwarded from ${card.node}.`)\n lines.push(\"Act on this result now. Do not raise the same card again.\")\n return lines.join(\"\\n\")\n}\n","// --- Where a card came from, when the daemon raised it ---\n//\n// Agents raise most cards themselves. A check-in (checkin.ts) raises one on\n// an agent's behalf for an open Apple Reminder, and records the reminder\n// here so the agent that gets the answer knows what to act on and what to\n// tick off. Only the daemon sets it: POST /approvals and the agent tool\n// never pass it through.\n\nexport interface ReminderOrigin {\n kind: \"reminder\"\n /** The reminder's full id, as remindctl prints it. */\n id: string\n title: string\n list?: string\n}\n\n/** An open request that needs attention, shown as a card on the Mac\n * (popup-runner.ts). Never stored: the request is the record. */\nexport interface RequestOrigin {\n kind: \"request\"\n id: string\n}\n\n/** A retro card (src/retro): fixes to the agents' environment proposed\n * from one run that struggled. The answer goes back to the agent that ran\n * it, which builds the picked fix for a second review. */\nexport interface RetroOrigin {\n kind: \"retro\"\n /** The run the retro read. */\n taskId: string\n /** Failure signature (wiki/failure-candidates.ts), for one card per signature. */\n signature: string\n /** The reviewer's spec for each fix, in the order of the card's choices\n * (without \"None of these\"). Only the picked one reaches the agent. */\n specs?: string[]\n}\n\n/** A monthly review of a check a retro added (src/retro/checks.ts): a\n * guard rule tagged `retro:<taskId>` that fires often on runs that went\n * well. The answer goes back to the agent that built it, which keeps,\n * loosens or removes it for a second review. */\nexport interface RetroCheckOrigin {\n kind: \"retro-check\"\n /** The guard rule's id. */\n ruleId: string\n /** The run whose retro asked for the rule. */\n taskId: string\n /** The policy file that holds the rule, relative to the daemon's folder. */\n file: string\n}\n\n/** A step of a workflow run asks the owner (src/workflows, #788): an\n * owner.ask step, a person.message to approve, or a run's approval at\n * start. The answer resumes the run; the agent that started it is not\n * told separately, the run is. */\nexport interface WorkflowOrigin {\n kind: \"workflow\"\n runId: string\n nodeId: string\n}\n\n/** An agent proposed a reusable workflow (#788). Yes turns it on. */\nexport interface WorkflowProposalOrigin {\n kind: \"workflow-proposal\"\n workflowId: string\n}\n\n/** A step of a tracked plan the owner approves when the plan is made\n * (src/requests/plan-sweep.ts, #788). The plan check reads the answer\n * and acts on it; the agent is not sent a result turn. */\nexport interface PlanStepOrigin {\n kind: \"plan-step\"\n requestId: string\n step: number\n}\n\n/** A pull request that changes core paths waits for the owner (merge\n * policy, #1047). YES approves that one commit; the policy reads the\n * answer and updates the PR's status. No agent is sent a result turn. */\nexport interface MergePolicyOrigin {\n kind: \"merge-policy\"\n repo: string\n pr: number\n sha: string\n}\n\nexport type CardOrigin = ReminderOrigin | RequestOrigin | RetroOrigin | RetroCheckOrigin | PlanStepOrigin | WorkflowOrigin | WorkflowProposalOrigin | MergePolicyOrigin\n\n/** Retro cards of either kind: raised for an agent, not by it. */\nexport function isRetroOrigin(origin: CardOrigin | undefined): origin is RetroOrigin | RetroCheckOrigin {\n return origin?.kind === \"retro\" || origin?.kind === \"retro-check\"\n}\n\n/** The choices on a check review card, in this order. */\nexport const CHECK_CHOICES = { keep: \"Keep it\", loosen: \"Loosen it\", remove: \"Remove it\" } as const\n\n/** Lines for the agent told the result of a check review card. Keep, NO\n * and silence all leave the rule as it is. */\nexport function retroCheckLines(\n origin: RetroCheckOrigin,\n card: { status: string; verdict?: string; choice?: string; choice_suggested?: boolean },\n edited?: string,\n): string[] {\n const rule = `guard rule \\`${origin.ruleId}\\` in \\`${origin.file}\\``\n const lines = [`This was a monthly review of ${rule}, added by the retro on run ${origin.taskId}. It fires often on runs that went well.`]\n const yes = card.status === \"decided\" && card.verdict === \"yes\"\n if (!yes || card.choice === CHECK_CHOICES.keep || !card.choice) {\n lines.push(\"Change nothing: the rule stays as it is.\")\n return lines\n }\n lines.push(card.choice === CHECK_CHOICES.remove\n ? `The operator chose to remove it. Delete ${rule} as a pull request.`\n : `The operator chose to loosen it. Narrow ${rule} (a tighter match, or \\`applies_to\\`) so it stops firing on good work, keep its \\`retro:${origin.taskId}\\` tag, and open it as a pull request.`)\n if (card.choice_suggested) lines.push(SUGGESTED_NOTE)\n if (edited) lines.push(\"The operator's note:\", edited)\n lines.push(\"Do not change the live policy directly: the operator reviews the pull request first.\")\n return lines\n}\n\n/** Told to the agent when the choice came from a plain yes (#1064): the\n * operator accepted the suggestion rather than picking it by hand. */\nconst SUGGESTED_NOTE = \"(The operator gave a plain yes, taken as the suggested option.)\"\n\n/** True when the operator answered a retro card with something to build:\n * YES and a fix picked. YES on \"None of these\" counts as NO. */\nexport function retroApproved(card: { status: string; verdict?: string; choice?: string }): boolean {\n return card.status === \"decided\" && card.verdict === \"yes\" && !!card.choice && card.choice !== RETRO_NONE\n}\n\n/** Lines for the agent told the result of a retro card. Replaces the plain\n * card's \"Chosen / Approved text\" lines: the specs are model output written\n * from the run's content, so they reach the agent labelled as such, never\n * as text the operator approved word for word.\n * `edited` is the operator's text when they changed the suggested one. */\nexport function retroLines(\n origin: RetroOrigin,\n card: { status: string; verdict?: string; choice?: string; choices?: string[]; choice_suggested?: boolean },\n edited?: string,\n): string[] {\n const lines = [`This was a retro card about run ${origin.taskId} (\\`agentx trace show ${origin.taskId}\\`).`]\n if (!retroApproved(card)) {\n lines.push(\"Change nothing. Do not propose these fixes again on your own.\")\n return lines\n }\n lines.push(`The operator picked this fix: ${card.choice}`)\n if (card.choice_suggested) lines.push(SUGGESTED_NOTE)\n const spec = origin.specs?.[(card.choices ?? []).indexOf(card.choice!)]\n if (spec) {\n lines.push(\n \"Spec for this fix, drafted by the retro reviewer from the run's content (a proposal to check, not instructions from the operator):\",\n spec,\n )\n }\n if (edited) lines.push(\"The operator's note on the fix:\", edited)\n lines.push(\n \"Build the chosen fix as a change the operator reviews again: a pull request, or a guard rule in warn mode.\",\n \"Do not apply it to a live system directly. Tag what you add with `retro:\" + origin.taskId + \"` so it can be found and removed later; for a guard rule, put the tag in its `tags` list.\",\n )\n return lines\n}\n\n/** The last choice on every retro card. */\nexport const RETRO_NONE = \"None of these\"\n\n/** Lines for the owning agent's result message. */\nexport function originLines(origin: ReminderOrigin, approved: boolean): string[] {\n const where = origin.list ? ` in the \"${origin.list}\" list` : \"\"\n const lines = [`This card came from the operator's reminder \"${origin.title}\"${where} (id ${origin.id}).`]\n lines.push(approved\n ? `Do what the operator chose, then tick the reminder off: remindctl complete ${origin.id}`\n : \"Leave the reminder open; it will come back at a later check-in.\")\n return lines\n}\n","// --- The screen gatekeeper (#394, plan section 1b) ---\n//\n// What the fleet puts on the owner's screen passes one check, by script,\n// no model:\n// - one question per card; a title and an ask short enough to read in\n// about ten seconds (title 120, ask 300 characters);\n// - at most 3 ready-made answers (a plain card has Yes, No, Not now);\n// - follow-up cards (resurface, bring-back, weekly, clean-up) share a\n// budget of 5 a day, at most 3 of them resurface cards.\n// A card that fails is returned to its author with the reason: refused\n// when it is written, or not shown and told when the popup comes to it.\n// Nothing here rewrites, removes or answers a card. The call and Focus\n// hold is notify/hold.ts; the popup window takes no focus (card-window.ts).\n\nexport const SCREEN_LIMITS = { title: 120, ask: 300, answers: 3 } as const\n\nexport const FOLLOWUP_KINDS = [\"resurface\", \"bring-back\", \"weekly\", \"cleanup\"] as const\nexport type FollowupKind = (typeof FOLLOWUP_KINDS)[number]\n\nexport const SCREEN_BUDGET = { perDay: 5, resurface: 3 } as const\n\n/** Why this card may not go on the owner's screen, or null. */\nexport function cardRuleBreak(card: { title: string; ask: string; choices?: string[] }): string | null {\n if (card.title.length > SCREEN_LIMITS.title) return `title is longer than ${SCREEN_LIMITS.title} characters`\n if (card.ask.length > SCREEN_LIMITS.ask) return `ask is longer than ${SCREEN_LIMITS.ask} characters`\n if ((card.ask.match(/\\?/g) ?? []).length > 1) return \"ask holds more than one question: one card asks one thing\"\n if ((card.choices?.length ?? 0) > SCREEN_LIMITS.answers) return `more than ${SCREEN_LIMITS.answers} choices`\n return null\n}\n\n/** Why an agent's `agentx notify` may not go on the owner's screen, or\n * null: the same ten-second rule, title 120 and message 300. */\nexport function noticeRuleBreak(title: string, message: string): string | null {\n if (title.length > SCREEN_LIMITS.title) return `title is longer than ${SCREEN_LIMITS.title} characters`\n if (message.length > SCREEN_LIMITS.ask) return `message is longer than ${SCREEN_LIMITS.ask} characters`\n return null\n}\n\n/** Local midnight before `now`: the budget's day. */\nfunction dayStart(now: number): number {\n const d = new Date(now)\n d.setHours(0, 0, 0, 0)\n return d.getTime()\n}\n\n/** Why a follow-up card of this kind cannot be raised today, or null.\n * `cards` is every card, of any status: an answered one was on screen too. */\nexport function followupBudgetRefusal(\n cards: Array<{ followup?: FollowupKind; created_at: string }>,\n kind: FollowupKind,\n now: number,\n): string | null {\n const from = dayStart(now)\n const today = cards.filter((c) => c.followup && Date.parse(c.created_at) >= from)\n if (today.length >= SCREEN_BUDGET.perDay) {\n return `the follow-up screen budget is used up today (${SCREEN_BUDGET.perDay} cards): raise it again tomorrow`\n }\n if (kind === \"resurface\" && today.filter((c) => c.followup === \"resurface\").length >= SCREEN_BUDGET.resurface) {\n return `${SCREEN_BUDGET.resurface} resurface cards were already raised today: raise it again tomorrow`\n }\n return null\n}\n\n/** What the author hears when the popup does not show its card. */\nexport function returnedText(card: { id: string; title: string }, reason: string): string {\n return [\n `[screen gate] Your card ${card.id} (\"${card.title}\") was not shown to the owner: ${reason}.`,\n \"It is still in his inbox, unchanged. If it must reach him on screen, close it (agentx_approval resolve) and raise one that passes:\",\n `one question, title up to ${SCREEN_LIMITS.title} characters, ask up to ${SCREEN_LIMITS.ask}, at most ${SCREEN_LIMITS.answers} choices.`,\n ].join(\" \")\n}\n"],"mappings":"6DAAA,OAAS,cAAAA,EAAY,aAAAC,EAAW,eAAAC,EAAa,gBAAAC,EAAc,cAAAC,EAAY,iBAAAC,MAAqB,KAC5F,OAAS,WAAAC,MAAe,OCwFjB,SAASC,EAAcC,EAA0E,CACtG,OAAOA,GAAQ,OAAS,SAAWA,GAAQ,OAAS,aACtD,CAGO,IAAMC,EAAgB,CAAE,KAAM,UAAW,OAAQ,YAAa,OAAQ,WAAY,EAIlF,SAASC,EACdF,EACAG,EACAC,EACU,CACV,IAAMC,EAAO,gBAAgBL,EAAO,iBAAiBA,EAAO,SACtDM,EAAQ,CAAC,gCAAgCD,gCAAmCL,EAAO,gDAAgD,EAEzI,MAAI,EADQG,EAAK,SAAW,WAAaA,EAAK,UAAY,QAC9CA,EAAK,SAAWF,EAAc,MAAQ,CAACE,EAAK,QACtDG,EAAM,KAAK,0CAA0C,EAC9CA,IAETA,EAAM,KAAKH,EAAK,SAAWF,EAAc,OACrC,2CAA2CI,uBAC3C,2CAA2CA,4FAA+FL,EAAO,8CAA8C,EAC/LG,EAAK,kBAAkBG,EAAM,KAAKC,CAAc,EAChDH,GAAQE,EAAM,KAAK,uBAAwBF,CAAM,EACrDE,EAAM,KAAK,sFAAsF,EAC1FA,EACT,CAIA,IAAMC,EAAiB,kEAIhB,SAASC,EAAcL,EAAsE,CAClG,OAAOA,EAAK,SAAW,WAAaA,EAAK,UAAY,OAAS,CAAC,CAACA,EAAK,QAAUA,EAAK,SAAWM,CACjG,CAOO,SAASC,EACdV,EACAG,EACAC,EACU,CACV,IAAME,EAAQ,CAAC,mCAAmCN,EAAO,+BAA+BA,EAAO,YAAY,EAC3G,GAAI,CAACQ,EAAcL,CAAI,EACrB,OAAAG,EAAM,KAAK,+DAA+D,EACnEA,EAETA,EAAM,KAAK,iCAAiCH,EAAK,QAAQ,EACrDA,EAAK,kBAAkBG,EAAM,KAAKC,CAAc,EACpD,IAAMI,EAAOX,EAAO,SAASG,EAAK,SAAW,CAAC,GAAG,QAAQA,EAAK,MAAO,CAAC,EACtE,OAAIQ,GACFL,EAAM,KACJ,qIACAK,CACF,EAEEP,GAAQE,EAAM,KAAK,kCAAmCF,CAAM,EAChEE,EAAM,KACJ,6GACA,2EAA6EN,EAAO,OAAS,2FAC/F,EACOM,CACT,CAGO,IAAMG,EAAa,gBAGnB,SAASG,EAAYZ,EAAwBa,EAA6B,CAC/E,IAAMC,EAAQd,EAAO,KAAO,YAAYA,EAAO,aAAe,GACxDM,EAAQ,CAAC,gDAAgDN,EAAO,SAASc,SAAad,EAAO,MAAM,EACzG,OAAAM,EAAM,KAAKO,EACP,8EAA8Eb,EAAO,KACrF,iEAAiE,EAC9DM,CACT,CC9JO,IAAMS,EAAgB,CAAE,MAAO,IAAK,IAAK,IAAK,QAAS,CAAE,EAEnDC,EAAiB,CAAC,YAAa,aAAc,SAAU,SAAS,EAGhEC,EAAgB,CAAE,OAAQ,EAAG,UAAW,CAAE,EAGhD,SAASC,EAAcC,EAAyE,CACrG,OAAIA,EAAK,MAAM,OAASJ,EAAc,MAAc,wBAAwBA,EAAc,mBACtFI,EAAK,IAAI,OAASJ,EAAc,IAAY,sBAAsBA,EAAc,kBAC/EI,EAAK,IAAI,MAAM,KAAK,GAAK,CAAC,GAAG,OAAS,EAAU,6DAChDA,EAAK,SAAS,QAAU,GAAKJ,EAAc,QAAgB,aAAaA,EAAc,kBACpF,IACT,CAIO,SAASK,GAAgBC,EAAeC,EAAgC,CAC7E,OAAID,EAAM,OAASN,EAAc,MAAc,wBAAwBA,EAAc,mBACjFO,EAAQ,OAASP,EAAc,IAAY,0BAA0BA,EAAc,iBAChF,IACT,CAGA,SAASQ,EAASC,EAAqB,CACrC,IAAMC,EAAI,IAAI,KAAKD,CAAG,EACtB,OAAAC,EAAE,SAAS,EAAG,EAAG,EAAG,CAAC,EACdA,EAAE,QAAQ,CACnB,CAIO,SAASC,EACdC,EACAC,EACAJ,EACe,CACf,IAAMK,EAAON,EAASC,CAAG,EACnBM,EAAQH,EAAM,OAAQI,GAAMA,EAAE,UAAY,KAAK,MAAMA,EAAE,UAAU,GAAKF,CAAI,EAChF,OAAIC,EAAM,QAAUb,EAAc,OACzB,iDAAiDA,EAAc,yCAEpEW,IAAS,aAAeE,EAAM,OAAQC,GAAMA,EAAE,WAAa,WAAW,EAAE,QAAUd,EAAc,UAC3F,GAAGA,EAAc,+EAEnB,IACT,CAGO,SAASe,GAAab,EAAqCc,EAAwB,CACxF,MAAO,CACL,2BAA2Bd,EAAK,QAAQA,EAAK,uCAAuCc,KACpF,qIACA,6BAA6BlB,EAAc,+BAA+BA,EAAc,gBAAgBA,EAAc,kBACxH,EAAE,KAAK,GAAG,CACZ,CF/CO,IAAMmB,EAAwC,CAAC,UAAW,OAAQ,OAAO,EAEhF,SAASC,EAAWC,EAA4B,CAC9C,OAAIA,IAAM,UAAkB,OACrBF,EAAiB,SAASE,CAAa,EAAKA,EAAiB,IACtE,CA4DO,IAAMC,EAAc,CACzB,MAAO,IACP,IAAK,IACL,UAAW,IACX,OAAQ,IACR,KAAM,IACN,WAAY,IAEZ,gBAAiB,EACnB,EAOaC,EAAsC,CAAE,kBAAmB,EAAG,cAAe,EAAG,EAEtF,SAASC,EAAaC,EAAsB,CACjD,OAAOC,EAAQD,EAAM,UAAW,WAAW,CAC7C,CAEA,IAAME,EAAa,4BAEZ,SAASC,EAAcC,EAAqB,CACjD,OAAOF,EAAW,KAAKE,CAAE,CAC3B,CAEA,SAASC,EAAQL,EAAcI,EAAoB,CACjD,GAAI,CAACD,EAAcC,CAAE,EAAG,MAAM,IAAI,MAAM,oBAAoBA,GAAI,EAChE,OAAOH,EAAQF,EAAaC,CAAI,EAAG,GAAGI,QAAS,CACjD,CAEO,SAASE,EAAUC,EAAaC,EAAuB,CAC5D,IAAMC,EAAM,IAAI,KAAKF,CAAG,EAAE,YAAY,EAAE,MAAM,EAAG,EAAE,EAC7CG,EAAOF,EAAM,YAAY,EAAE,QAAQ,cAAe,GAAG,EAAE,QAAQ,WAAY,EAAE,EAAE,MAAM,EAAG,EAAE,EAChG,MAAO,GAAGC,KAAOC,GAAQ,UAAU,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,GAC1E,CAEO,SAASC,EAASX,EAAcY,EAA0B,CAC/DC,EAAUd,EAAaC,CAAI,EAAG,CAAE,UAAW,EAAK,CAAC,EACjD,IAAMc,EAAOT,EAAQL,EAAMY,EAAK,EAAE,EAC5BG,EAAM,GAAGD,KAAQ,QAAQ,UAC/BE,EAAcD,EAAK,KAAK,UAAUH,EAAM,KAAM,CAAC,EAAI;AAAA,CAAI,EACvDK,EAAWF,EAAKD,CAAI,CACtB,CAEO,SAASI,EAASlB,EAAcI,EAAiC,CACtE,GAAI,CAACD,EAAcC,CAAE,EAAG,OAAO,KAC/B,GAAI,CACF,IAAMQ,EAAO,KAAK,MAAMO,EAAad,EAAQL,EAAMI,CAAE,EAAG,OAAO,CAAC,EAG1DgB,EAAUR,EAAK,YAAyB,WAAcA,EAAK,UAAuB,UACxF,MAAO,CACL,GAAGA,EACH,UAAWjB,EAAWiB,EAAK,SAAS,GAAK,OACzC,GAAIA,EAAK,QAAU,CAAE,QAASjB,EAAWiB,EAAK,OAAO,GAAK,MAAO,EAAI,CAAC,EACtE,GAAIQ,EAAS,CAAE,gBAAiB,SAAmB,EAAI,CAAC,CAC1D,CACF,MAAE,CACA,OAAO,IACT,CACF,CAGO,SAASC,EAAUrB,EAAcsB,EAAqC,CAC3E,IAAMC,EAAMxB,EAAaC,CAAI,EAC7B,GAAI,CAACwB,EAAWD,CAAG,EAAG,MAAO,CAAC,EAC9B,IAAME,EAAsB,CAAC,EAC7B,QAAWC,KAAKC,EAAYJ,CAAG,EAAE,OAAQG,GAAMA,EAAE,SAAS,OAAO,GAAK,CAACA,EAAE,WAAW,GAAG,CAAC,EAAE,KAAK,EAAG,CAChG,IAAME,EAAIV,EAASlB,EAAM0B,EAAE,MAAM,EAAG,EAAE,CAAC,EACnCE,IAAM,CAACN,GAAUM,EAAE,SAAWN,IAASG,EAAI,KAAKG,CAAC,EAEvD,OAAOH,CACT,CAEA,SAASI,EAAQjC,EAAoB,CACnC,OAAO,OAAOA,GAAM,SAAWA,EAAE,QAAQ,OAAQ,GAAG,EAAE,KAAK,EAAI,EACjE,CAOO,SAASkC,GAAcC,EAAgBxB,EAAayB,EAAiF,CAC1I,IAAMC,EAAM1B,EAAMyB,EAAS,cAAgB,MACvCE,EACEC,EAAMN,EAAQE,CAAK,EACzB,GAAI,CAACI,EACHD,EAAK3B,EAAMyB,EAAS,kBAAoB,UACnC,CACL,IAAMI,EAAM,oBAAoB,KAAKD,CAAG,EACxC,GAAIC,EACFF,EAAK3B,EAAM,OAAO6B,EAAI,CAAC,CAAC,GAAKA,EAAI,CAAC,EAAE,YAAY,IAAM,IAAM,MAAa,cAEzEF,EAAK,KAAK,MAAMC,CAAG,EACf,OAAO,MAAMD,CAAE,EAAG,MAAO,CAAE,GAAI,GAAO,MAAO,mEAAmEC,KAAQ,EAGhI,OAAID,GAAM3B,EAAY,CAAE,GAAI,GAAO,MAAO,+BAAgC,EACnE,CAAE,GAAI,GAAM,GAAI,IAAI,KAAK,KAAK,IAAI2B,EAAID,CAAG,CAAC,EAAE,YAAY,CAAE,CACnE,CA4BO,SAASI,GACdN,EACAO,EAAyB,CAAC,EACuC,CACjE,IAAM/B,EAAM+B,EAAK,KAAO,KAAK,IAAI,EAC3BN,EAAWM,EAAK,UAAYxC,EAC5BU,EAAQqB,EAAQE,EAAM,KAAK,EAC3BQ,EAAMV,EAAQE,EAAM,GAAG,EACvBS,EAAYX,EAAQE,EAAM,SAAS,EACnCU,EAAWZ,EAAQE,EAAM,SAAS,EACxC,GAAI,CAACvB,EAAO,MAAO,CAAE,GAAI,GAAO,MAAO,mBAAoB,EAC3D,GAAI,CAAC+B,EAAK,MAAO,CAAE,GAAI,GAAO,MAAO,sCAAuC,EAC5E,GAAI,CAACC,EAAW,MAAO,CAAE,GAAI,GAAO,MAAO,yDAA0D,EACrG,GAAI,CAACC,EAAU,MAAO,CAAE,GAAI,GAAO,MAAO,qCAAsC,EAChF,GAAIjC,EAAM,OAASX,EAAY,MAAO,MAAO,CAAE,GAAI,GAAO,MAAO,wBAAwBA,EAAY,kBAAmB,EACxH,GAAI0C,EAAI,OAAS1C,EAAY,IAAK,MAAO,CAAE,GAAI,GAAO,MAAO,sBAAsBA,EAAY,gBAAiB,EAChH,GAAI2C,EAAU,OAAS3C,EAAY,UAAW,MAAO,CAAE,GAAI,GAAO,MAAO,4BAA4BA,EAAY,sBAAuB,EACxI,IAAM6C,EAAcb,EAAQE,EAAM,SAAS,EAAE,YAAY,EACnDY,EAAWhD,EAAW+C,CAAW,EACvC,GAAI,CAACC,EACH,MAAO,CAAE,GAAI,GAAO,MAAO,4BAA4BjD,EAAiB,KAAK,IAAI,GAAI,EAEvF,IAAMkD,EAASd,GAAcC,EAAM,QAASxB,EAAKyB,CAAQ,EACzD,GAAI,CAACY,EAAO,GAAI,OAAOA,EACvB,IAAMC,EAAShB,EAAQE,EAAM,MAAM,EACnC,GAAIc,EAAO,OAAShD,EAAY,OAAQ,MAAO,CAAE,GAAI,GAAO,MAAO,yBAAyBA,EAAY,mBAAoB,EAC5H,GAAIgD,GAAU,uBAAuB,KAAKA,CAAM,GAAK,CAAC,gBAAgB,KAAKA,CAAM,EAC/E,MAAO,CAAE,GAAI,GAAO,MAAO,qDAAsD,EAEnF,IAAMC,EAASC,EAAahB,CAAK,EACjC,GAAI,CAACe,EAAO,GAAI,OAAOA,EACvB,IAAME,EAAWnB,EAAQE,EAAM,QAAQ,EAAE,YAAY,EACrD,GAAIiB,GAAY,CAAEC,EAAqC,SAASD,CAAQ,EACtE,MAAO,CAAE,GAAI,GAAO,MAAO,2BAA2BC,EAAe,KAAK,IAAI,GAAI,EAEpF,IAAIC,EACEC,EAAIpB,EAAM,MAChB,OAAIoB,GAAK,OAAOA,GAAM,UAAYtB,EAAQsB,EAAE,OAAO,GAAKtB,EAAQsB,EAAE,MAAM,IACtED,EAAQ,CAAE,QAASrB,EAAQsB,EAAE,OAAO,EAAG,OAAQtB,EAAQsB,EAAE,MAAM,EAAG,GAAItB,EAAQsB,EAAE,SAAS,EAAI,CAAE,UAAWtB,EAAQsB,EAAE,SAAS,CAAE,EAAI,CAAC,CAAG,GAElI,CACL,GAAI,GACJ,KAAM,CACJ,GAAI7C,EAAUC,EAAKC,CAAK,EACxB,MAAAA,EACA,IAAA+B,EACA,UAAAC,EACA,UAAWG,EACX,GAAID,IAAgB,UAAY,CAAE,gBAAiB,SAAmB,EAAI,CAAC,EAC3E,QAASE,EAAO,GAChB,GAAIC,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,EAC3B,UAAWJ,EACX,GAAIH,EAAK,KAAO,CAAE,KAAMA,EAAK,IAAK,EAAI,CAAC,EACvC,WAAY,IAAI,KAAK/B,CAAG,EAAE,YAAY,EACtC,GAAI2C,EAAQ,CAAE,MAAAA,CAAM,EAAI,CAAC,EACzB,GAAGJ,EAAO,MAEV,GAAIR,EAAK,OAAS,CAAE,OAAQA,EAAK,MAAO,EAAI,CAAC,EAC7C,GAAIU,EAAW,CAAE,SAAUA,CAAyB,EAAI,CAAC,EACzD,OAAQ,SACV,CACF,CACF,CAGO,SAASI,GACdpD,EACA+B,EACAO,EAAyB,CAAC,EACuC,CACjE,IAAMe,EAAQhB,GAAUN,EAAOO,CAAI,EACnC,GAAI,CAACe,EAAM,GAAI,OAAOA,EAEtB,IAAMC,EAASC,EAAcF,EAAM,IAAI,EACvC,GAAIC,EAAQ,MAAO,CAAE,GAAI,GAAO,MAAOA,CAAO,EAC9C,GAAID,EAAM,KAAK,SAAU,CACvB,IAAMG,EAAOC,EAAsBpC,EAAUrB,CAAI,EAAGqD,EAAM,KAAK,SAAUf,EAAK,KAAO,KAAK,IAAI,CAAC,EAC/F,GAAIkB,EAAM,MAAO,CAAE,GAAI,GAAO,MAAOA,CAAK,EAI5C,IAAME,EAAW,GAA+BC,EAAc,EAAE,MAAM,EAChEC,EAAQF,EAAQL,EAAM,IAAI,EAC1BQ,EAAOxC,EAAUrB,EAAM,SAAS,EAAE,OAAQ,GAAM,EAAE,YAAcqD,EAAM,KAAK,WAAaK,EAAQ,CAAC,IAAME,CAAK,EAAE,OACpH,GAAIC,GAAQhE,EAAY,gBAAiB,CACvC,IAAMiE,EAAOF,EAAQ,cAAgB,QACrC,MAAO,CAAE,GAAI,GAAO,MAAO,GAAGP,EAAM,KAAK,yBAAyBQ,KAAQC,mDAAuD,EAEnI,OAAAnD,EAASX,EAAMqD,EAAM,IAAI,EAClBA,CACT,CAGO,SAASU,GACd/D,EACAI,EACA4D,EACA1B,EAA8F,CAAC,EAC9B,CACjE,IAAM1B,EAAOM,EAASlB,EAAMI,CAAE,EAC9B,GAAI,CAACQ,EAAM,MAAO,CAAE,GAAI,GAAO,MAAO,YAAYR,IAAM,EACxD,GAAIQ,EAAK,SAAW,UAAW,MAAO,CAAE,GAAI,GAAO,MAAO,SAASR,iBAAkBQ,EAAK,QAAS,EACnG,IAAMqD,EAASC,EAActD,EAAMoD,EAAS1B,CAAI,EAChD,GAAI,CAAC2B,EAAO,GAAI,OAAOA,EACvB,IAAME,EAAOtC,EAAQS,EAAK,IAAI,EAAE,MAAM,EAAGzC,EAAY,IAAI,EACnDuE,EAAwB,CAC5B,GAAGxD,EACH,OAAQ,UACR,QAAAoD,EACA,WAAY1B,EAAK,IAAM,WACvB,WAAY,IAAI,KAAKA,EAAK,KAAO,KAAK,IAAI,CAAC,EAAE,YAAY,EACzD,GAAI6B,EAAO,CAAE,KAAAA,CAAK,EAAI,CAAC,EACvB,GAAIF,EAAO,OAAS,CAAE,OAAQA,EAAO,MAAO,EAAI,CAAC,EACjD,GAAIA,EAAO,UAAY,CAAE,iBAAkB,EAAK,EAAI,CAAC,EACrD,GAAIA,EAAO,KAAO,CAAE,KAAMA,EAAO,IAAK,EAAI,CAAC,CAC7C,EACA,OAAAtD,EAASX,EAAMoE,CAAO,EACf,CAAE,GAAI,GAAM,KAAMA,CAAQ,CACnC,CAKA,IAAMC,GAA2B,IAAI,IAAwB,CAAC,OAAW,UAAU,CAAC,EAQ7E,SAASC,GACdtE,EACAI,EACAkC,EACgG,CAChG,IAAM1B,EAAOM,EAASlB,EAAMI,CAAE,EAC9B,GAAI,CAACQ,EAAM,MAAO,CAAE,GAAI,GAAO,OAAQ,IAAK,MAAO,YAAYR,IAAM,EACrE,GAAIQ,EAAK,YAAc0B,EAAK,KAAO1B,EAAK,MAAQ,OAAS0B,EAAK,MAAQ,IACpE,MAAO,CAAE,GAAI,GAAO,OAAQ,IAAK,MAAO,SAASlC,gCAAkC,EAErF,GAAI,CAACiE,GAAyB,IAAIzD,EAAK,QAAQ,IAAI,EACjD,MAAO,CAAE,GAAI,GAAO,OAAQ,IAAK,MAAO,SAASR,qCAAuC,EAE1F,GAAIQ,EAAK,SAAW,UAAW,MAAO,CAAE,GAAI,GAAO,OAAQ,IAAK,MAAO,SAASR,iBAAkBQ,EAAK,QAAS,EAChH,IAAM2D,EAAS1C,EAAQS,EAAK,MAAM,EAClC,GAAI,CAACiC,EAAQ,MAAO,CAAE,GAAI,GAAO,OAAQ,IAAK,MAAO,mEAAoE,EACzH,IAAMrC,EAAK,IAAI,KAAKI,EAAK,KAAO,KAAK,IAAI,CAAC,EAAE,YAAY,EAClDkC,EAAyB,CAC7B,GAAG5D,EACH,OAAQ,WACR,WAAY0B,EAAK,GACjB,WAAYJ,EACZ,WAAYqC,EAAO,MAAM,EAAG1E,EAAY,UAAU,EAClD,kBAAmBqC,CACrB,EACA,OAAAvB,EAASX,EAAMwE,CAAQ,EAChB,CAAE,GAAI,GAAM,KAAMA,CAAS,CACpC,CAGO,SAASC,GAAYzE,EAAcO,EAAc,KAAK,IAAI,EAAmB,CAClF,IAAMkB,EAAsB,CAAC,EAC7B,QAAWb,KAAQS,EAAUrB,EAAM,SAAS,EAAG,CAC7C,GAAI,KAAK,MAAMY,EAAK,OAAO,EAAIL,EAAK,SACpC,IAAMmE,EAAwB,CAC5B,GAAG9D,EACH,OAAQ,UACR,QAASA,EAAK,UACd,WAAY,SACZ,WAAY,IAAI,KAAKL,CAAG,EAAE,YAAY,CACxC,EACAI,EAASX,EAAM0E,CAAO,EACtBjD,EAAI,KAAKiD,CAAO,EAElB,OAAOjD,CACT,CAGO,SAASkD,GAAyB3E,EAA8B,CACrE,OAAOqB,EAAUrB,CAAI,EAAE,OAAQ4B,GAAMA,EAAE,SAAW,WAAa,CAACA,EAAE,iBAAiB,CACrF,CAEO,SAASgD,GAAkB5E,EAAcI,EAAYG,EAAc,KAAK,IAAI,EAAS,CAC1F,IAAMK,EAAOM,EAASlB,EAAMI,CAAE,EAC1B,CAACQ,GAAQA,EAAK,mBAClBD,EAASX,EAAM,CAAE,GAAGY,EAAM,kBAAmB,IAAI,KAAKL,CAAG,EAAE,YAAY,CAAE,CAAC,CAC5E,CAEO,IAAMsE,GACX,6MAGK,SAASC,GAAelE,EAA4B,CACzD,IAAMgD,EAAQhD,EAAK,QAAQ,OAAS,QAAUA,EAAK,OAAS,OACtDmE,EAASnE,EAAK,SAAW,UAC1BA,EAAK,UAAY,MACbgD,GAAS,CAACoB,EAAcpE,CAAI,EAAI,wBAAwBqE,0BAAqC,yBAC9F,wBACJ,8DAA8DrE,EAAK,SAAWA,EAAK,aACjFsE,EAAQ,CACZ,yCAAyCtE,EAAK,WAAWA,EAAK,iBAC9D,aAAaA,EAAK,MAClBmE,CACF,EAGMI,EAAQvE,EAAK,QAAQ,OAAS,cAAgBA,EAAK,OAAS,OAQlE,GAPIA,EAAK,SAAW,WAAaA,EAAK,UAAY,OAAS,CAACgD,GAAS,CAACuB,GAAOD,EAAM,KAAK,GAAGE,EAAYxE,CAAI,CAAC,EACxGA,EAAK,MAAMsE,EAAM,KAAK,kBAAkBtE,EAAK,MAAM,EAGnDA,EAAK,SAAW,WAAaA,EAAK,UAAY,MAAQ,CAACgD,GAAS,CAACuB,GAAOD,EAAM,KAAKL,EAAY,EAC/FjE,EAAK,QAAQsE,EAAM,KAAK,WAAWtE,EAAK,QAAQ,EAChDA,EAAK,QAAQ,OAAS,YAAYsE,EAAM,KAAK,GAAGG,EAAYzE,EAAK,OAAQA,EAAK,SAAW,WAAaA,EAAK,UAAY,KAAK,CAAC,EAC7HgD,GAASuB,EAAO,CAGlB,IAAMG,EAAUC,GAAcA,EAAE,QAAQ,OAAQ,GAAG,EAAE,KAAK,EACpDC,EAAQC,EAAS7E,EAAK,MAAOA,EAAK,MAAM,EACxC8E,EAAS9E,EAAK,MAAQ0E,EAAO1E,EAAK,IAAI,IAAM0E,EAAOE,CAAK,EAAI5E,EAAK,KAAO,OAC9EsE,EAAM,KAAK,GAAItB,EAAQ+B,EAAW/B,EAAOhD,EAAM8E,CAAM,EAAIE,EAAgBT,EAAQvE,EAAM8E,CAAM,CAAE,EAEjG,OAAI9E,EAAK,OAAOsE,EAAM,KAAK,sBAAsBtE,EAAK,MAAM,gBAAgBA,EAAK,MAAM,mDAAmD,EACtIA,EAAK,MAAMsE,EAAM,KAAK,4EAA4EtE,EAAK,OAAO,EAClHsE,EAAM,KAAK,2DAA2D,EAC/DA,EAAM,KAAK;AAAA,CAAI,CACxB","names":["existsSync","mkdirSync","readdirSync","readFileSync","renameSync","writeFileSync","resolve","isRetroOrigin","origin","CHECK_CHOICES","retroCheckLines","card","edited","rule","lines","SUGGESTED_NOTE","retroApproved","RETRO_NONE","retroLines","spec","originLines","approved","where","SCREEN_LIMITS","FOLLOWUP_KINDS","SCREEN_BUDGET","cardRuleBreak","card","noticeRuleBreak","title","message","dayStart","now","d","followupBudgetRefusal","cards","kind","from","today","c","returnedText","reason","IF_SILENT_VALUES","asIfSilent","v","CARD_LIMITS","DEFAULT_CARD_SETTINGS","approvalsDir","root","resolve","CARD_ID_RE","isValidCardId","id","fileFor","newCardId","now","title","day","slug","saveCard","card","mkdirSync","path","tmp","writeFileSync","renameSync","readCard","readFileSync","legacy","listCards","status","dir","existsSync","out","f","readdirSync","c","oneLine","resolveExpiry","input","settings","max","at","raw","rel","buildCard","opts","ask","recommend","raisedBy","ifSilentRaw","ifSilent","expiry","source","extras","buildChoices","followup","FOLLOWUP_KINDS","reply","r","createCard","built","broken","cardRuleBreak","full","followupBudgetRefusal","isRetro","isRetroOrigin","retro","open","what","decideCard","verdict","answer","resolveAnswer","note","decided","AGENT_RESOLVABLE_ORIGINS","resolveCard","reason","resolved","expireCards","expired","cardsAwaitingAgentNotice","markAgentNotified","NO_UNDO_LINE","verdictMessage","result","retroApproved","RETRO_NONE","lines","check","answerLines","originLines","squash","s","draft","draftFor","edited","retroLines","retroCheckLines"]}
@@ -1,2 +0,0 @@
1
- function o(e){let[n,r]=e.split(".").map(Number);return n===22&&r>=19||n>=23&&n<=26}function t(e){return o(e)?null:`AgentX needs Node.js 22.19 or newer, up to 26. This is Node.js ${e}.`}export{o as a,t as b};
2
- //# sourceMappingURL=chunk-JXF54PT7.js.map