reasonix 0.41.0 → 0.43.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 (186) hide show
  1. package/README.md +26 -3
  2. package/dashboard/dist/app.js +98 -3
  3. package/dashboard/dist/app.js.map +1 -1
  4. package/dist/cli/{acp-64VQZLDJ.js → acp-DAGPCVFZ.js} +33 -28
  5. package/dist/cli/acp-DAGPCVFZ.js.map +1 -0
  6. package/dist/cli/chat-7ES4IBNH.js +50 -0
  7. package/dist/cli/{chunk-E46ECXJD.js → chunk-2425HK6U.js} +2 -1
  8. package/dist/cli/{chunk-E46ECXJD.js.map → chunk-2425HK6U.js.map} +1 -1
  9. package/dist/cli/chunk-25T6CVUP.js +172 -0
  10. package/dist/cli/chunk-25T6CVUP.js.map +1 -0
  11. package/dist/cli/{chunk-CD4SCQL4.js → chunk-2K65GZBT.js} +11 -2
  12. package/dist/cli/chunk-2K65GZBT.js.map +1 -0
  13. package/dist/cli/{chunk-H4OLWRSX.js → chunk-2KDUS647.js} +5 -4
  14. package/dist/cli/chunk-2KDUS647.js.map +1 -0
  15. package/dist/cli/chunk-2R4QCDOZ.js +11392 -0
  16. package/dist/cli/chunk-2R4QCDOZ.js.map +1 -0
  17. package/dist/cli/{chunk-3Q3C4W66.js → chunk-2UQP6H6T.js} +2 -1
  18. package/dist/cli/{chunk-3Q3C4W66.js.map → chunk-2UQP6H6T.js.map} +1 -1
  19. package/dist/cli/chunk-2Z35JOA4.js +96 -0
  20. package/dist/cli/chunk-2Z35JOA4.js.map +1 -0
  21. package/dist/cli/chunk-32TIKD5U.js +54 -0
  22. package/dist/cli/{chunk-L7W3HJZQ.js.map → chunk-32TIKD5U.js.map} +1 -1
  23. package/dist/cli/{chunk-A3LL4XDV.js → chunk-3BXRZFWS.js} +59 -3
  24. package/dist/cli/chunk-3BXRZFWS.js.map +1 -0
  25. package/dist/cli/{chunk-SXLJBFIV.js → chunk-3Z6IBU3D.js} +11 -7
  26. package/dist/cli/chunk-3Z6IBU3D.js.map +1 -0
  27. package/dist/cli/{chunk-A7VHMMDE.js → chunk-45U62RI3.js} +12 -5
  28. package/dist/cli/chunk-45U62RI3.js.map +1 -0
  29. package/dist/cli/{chunk-7VFNPMKG.js → chunk-4QUNBQQ2.js} +3 -2
  30. package/dist/cli/{chunk-7VFNPMKG.js.map → chunk-4QUNBQQ2.js.map} +1 -1
  31. package/dist/cli/{chunk-ARF3N2SY.js → chunk-5JJRUIPA.js} +4 -3
  32. package/dist/cli/{chunk-ARF3N2SY.js.map → chunk-5JJRUIPA.js.map} +1 -1
  33. package/dist/cli/{chunk-CFY2XLY6.js → chunk-6AK4EY3D.js} +7 -5
  34. package/dist/cli/{chunk-CFY2XLY6.js.map → chunk-6AK4EY3D.js.map} +1 -1
  35. package/dist/cli/chunk-6G3CUUFG.js +34320 -0
  36. package/dist/cli/chunk-6G3CUUFG.js.map +1 -0
  37. package/dist/cli/{chunk-YJFKFTAL.js → chunk-6PBZN4VI.js} +15 -3
  38. package/dist/cli/chunk-6PBZN4VI.js.map +1 -0
  39. package/dist/cli/{chunk-4W2CICFQ.js → chunk-6PZ3CXBP.js} +71 -60
  40. package/dist/cli/chunk-6PZ3CXBP.js.map +1 -0
  41. package/dist/cli/chunk-74EX7SUH.js +25293 -0
  42. package/dist/cli/chunk-74EX7SUH.js.map +1 -0
  43. package/dist/cli/{chunk-WE3YZULK.js → chunk-7O5ALB4C.js} +3 -2
  44. package/dist/cli/{chunk-WE3YZULK.js.map → chunk-7O5ALB4C.js.map} +1 -1
  45. package/dist/cli/{chunk-2CXPDAWX.js → chunk-DOYHN4KB.js} +3 -2
  46. package/dist/cli/{chunk-2CXPDAWX.js.map → chunk-DOYHN4KB.js.map} +1 -1
  47. package/dist/cli/{chunk-VFG4GIT3.js → chunk-F3PXYSNN.js} +3 -2
  48. package/dist/cli/{chunk-VFG4GIT3.js.map → chunk-F3PXYSNN.js.map} +1 -1
  49. package/dist/cli/{chunk-7SPOFTMT.js → chunk-FHOGSSCH.js} +4 -3
  50. package/dist/cli/{chunk-7SPOFTMT.js.map → chunk-FHOGSSCH.js.map} +1 -1
  51. package/dist/cli/{chunk-LTXADNCO.js → chunk-H6PS7IUE.js} +3 -2
  52. package/dist/cli/{chunk-LTXADNCO.js.map → chunk-H6PS7IUE.js.map} +1 -1
  53. package/dist/cli/{chunk-ZTLZO42A.js → chunk-HFEAY5DT.js} +3 -2
  54. package/dist/cli/{chunk-ZTLZO42A.js.map → chunk-HFEAY5DT.js.map} +1 -1
  55. package/dist/cli/{chunk-FWGEHRB7.js → chunk-J5XJHLWM.js} +2 -1
  56. package/dist/cli/{chunk-FWGEHRB7.js.map → chunk-J5XJHLWM.js.map} +1 -1
  57. package/dist/cli/{chunk-Y5XNV3NX.js → chunk-JMBMLOBP.js} +2 -1
  58. package/dist/cli/{chunk-Y5XNV3NX.js.map → chunk-JMBMLOBP.js.map} +1 -1
  59. package/dist/cli/{chunk-BYZGO3BX.js → chunk-O52OLQL3.js} +11 -3
  60. package/dist/cli/chunk-O52OLQL3.js.map +1 -0
  61. package/dist/cli/{chunk-4DCHFFEY.js → chunk-OSZC7C6F.js} +3 -2
  62. package/dist/cli/{chunk-4DCHFFEY.js.map → chunk-OSZC7C6F.js.map} +1 -1
  63. package/dist/cli/chunk-P7EKE5ZQ.js +60641 -0
  64. package/dist/cli/chunk-P7EKE5ZQ.js.map +1 -0
  65. package/dist/cli/{chunk-FM57FNPJ.js → chunk-PLHAZOLZ.js} +2 -1
  66. package/dist/cli/{chunk-FM57FNPJ.js.map → chunk-PLHAZOLZ.js.map} +1 -1
  67. package/dist/cli/{chunk-BOFL3T45.js → chunk-PQXPXJBJ.js} +12 -11
  68. package/dist/cli/chunk-PQXPXJBJ.js.map +1 -0
  69. package/dist/cli/{chunk-DAEAAVDF.js → chunk-PV55UMTO.js} +2 -1
  70. package/dist/cli/{chunk-DAEAAVDF.js.map → chunk-PV55UMTO.js.map} +1 -1
  71. package/dist/cli/{chunk-MHGPBJ2T.js → chunk-RE4RAVFF.js} +45 -10
  72. package/dist/cli/chunk-RE4RAVFF.js.map +1 -0
  73. package/dist/cli/chunk-S4XVGLRW.js +499 -0
  74. package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
  75. package/dist/cli/{chunk-WJ3YX4PZ.js → chunk-SZ5XES2N.js} +3 -2
  76. package/dist/cli/{chunk-WJ3YX4PZ.js.map → chunk-SZ5XES2N.js.map} +1 -1
  77. package/dist/cli/{chunk-UV7XJUJH.js → chunk-TJX6BFZZ.js} +16 -9
  78. package/dist/cli/{chunk-UV7XJUJH.js.map → chunk-TJX6BFZZ.js.map} +1 -1
  79. package/dist/cli/chunk-TUK7OWJA.js +51 -0
  80. package/dist/cli/{chunk-KZYLMMU5.js → chunk-VK5HG73G.js} +13 -12
  81. package/dist/cli/{chunk-KZYLMMU5.js.map → chunk-VK5HG73G.js.map} +1 -1
  82. package/dist/cli/{chunk-4H3ZRJ2U.js → chunk-XCGGEJTI.js} +4 -3
  83. package/dist/cli/{chunk-4H3ZRJ2U.js.map → chunk-XCGGEJTI.js.map} +1 -1
  84. package/dist/cli/{chunk-SOZE7V7V.js → chunk-XJXDHAES.js} +3 -2
  85. package/dist/cli/{chunk-SOZE7V7V.js.map → chunk-XJXDHAES.js.map} +1 -1
  86. package/dist/cli/chunk-XPDVG52A.js +2648 -0
  87. package/dist/cli/chunk-XPDVG52A.js.map +1 -0
  88. package/dist/cli/{chunk-CRPQUBP6.js → chunk-XXC2BYTV.js} +2 -1
  89. package/dist/cli/{chunk-CRPQUBP6.js.map → chunk-XXC2BYTV.js.map} +1 -1
  90. package/dist/cli/{chunk-AT6GGIBV.js → chunk-YFGF5NKA.js} +17 -14
  91. package/dist/cli/{chunk-AT6GGIBV.js.map → chunk-YFGF5NKA.js.map} +1 -1
  92. package/dist/cli/{chunk-ORM6PK57.js → chunk-YQ6NTIIE.js} +2 -1
  93. package/dist/cli/{chunk-ORM6PK57.js.map → chunk-YQ6NTIIE.js.map} +1 -1
  94. package/dist/cli/{chunk-RAUPWSYA.js → chunk-YYQAUTTN.js} +3 -2
  95. package/dist/cli/{chunk-RAUPWSYA.js.map → chunk-YYQAUTTN.js.map} +1 -1
  96. package/dist/cli/chunk-ZZM6QJ4W.js +109 -0
  97. package/dist/cli/chunk-ZZM6QJ4W.js.map +1 -0
  98. package/dist/cli/{code-X3M6ENTQ.js → code-SMKEW6CD.js} +60 -56
  99. package/dist/cli/code-SMKEW6CD.js.map +1 -0
  100. package/dist/cli/{commands-QY7MSQG7.js → commands-FVVB5FZF.js} +7 -5
  101. package/dist/cli/{commands-QY7MSQG7.js.map → commands-FVVB5FZF.js.map} +1 -1
  102. package/dist/cli/{commit-BRCQ3OQO.js → commit-HE4VSPZ7.js} +7 -4
  103. package/dist/cli/{commit-BRCQ3OQO.js.map → commit-HE4VSPZ7.js.map} +1 -1
  104. package/dist/cli/{desktop-ZTMHQR2Y.js → desktop-Q7NDXCON.js} +162 -74
  105. package/dist/cli/desktop-Q7NDXCON.js.map +1 -0
  106. package/dist/cli/devtools-YECO25QO.js +3719 -0
  107. package/dist/cli/devtools-YECO25QO.js.map +1 -0
  108. package/dist/cli/diff-435UTPC5.js +165 -0
  109. package/dist/cli/{diff-YASCB7PU.js.map → diff-435UTPC5.js.map} +1 -1
  110. package/dist/cli/doctor-OT7KH75K.js +27 -0
  111. package/dist/cli/{events-2AJTXR7I.js → events-XEFAD5VX.js} +6 -4
  112. package/dist/cli/{events-2AJTXR7I.js.map → events-XEFAD5VX.js.map} +1 -1
  113. package/dist/cli/index.js +3209 -133
  114. package/dist/cli/index.js.map +1 -1
  115. package/dist/cli/{mcp-YMWBLRR7.js → mcp-WUL2WO75.js} +6 -4
  116. package/dist/cli/{mcp-YMWBLRR7.js.map → mcp-WUL2WO75.js.map} +1 -1
  117. package/dist/cli/{mcp-browse-XLDUE6SB.js → mcp-browse-RR7R4XET.js} +32 -21
  118. package/dist/cli/{mcp-browse-XLDUE6SB.js.map → mcp-browse-RR7R4XET.js.map} +1 -1
  119. package/dist/cli/{mcp-inspect-H4D2HSJP.js → mcp-inspect-REGLYBWT.js} +8 -5
  120. package/dist/cli/{mcp-inspect-H4D2HSJP.js.map → mcp-inspect-REGLYBWT.js.map} +1 -1
  121. package/dist/cli/package.json +3 -0
  122. package/dist/cli/prompt-UW6EFLVR.js +16 -0
  123. package/dist/cli/{prune-sessions-4N3BVST2.js → prune-sessions-3RWUBYRS.js} +4 -2
  124. package/dist/cli/{prune-sessions-4N3BVST2.js.map → prune-sessions-3RWUBYRS.js.map} +1 -1
  125. package/dist/cli/{replay-3GTWM75X.js → replay-YOURXV4C.js} +42 -30
  126. package/dist/cli/{replay-3GTWM75X.js.map → replay-YOURXV4C.js.map} +1 -1
  127. package/dist/cli/{run-BLZPTRDX.js → run-Q6BUXV66.js} +24 -21
  128. package/dist/cli/{run-BLZPTRDX.js.map → run-Q6BUXV66.js.map} +1 -1
  129. package/dist/cli/{server-DRFPXXSH.js → server-XGDBRWMB.js} +40 -43
  130. package/dist/cli/server-XGDBRWMB.js.map +1 -0
  131. package/dist/cli/{sessions-BOWFPTXT.js → sessions-FH7QVYSY.js} +22 -19
  132. package/dist/cli/{sessions-BOWFPTXT.js.map → sessions-FH7QVYSY.js.map} +1 -1
  133. package/dist/cli/setup-VDS6SVEP.js +618 -0
  134. package/dist/cli/setup-VDS6SVEP.js.map +1 -0
  135. package/dist/cli/stats-MQVI2XQH.js +14 -0
  136. package/dist/cli/update-6ITLPRDV.js +15 -0
  137. package/dist/cli/update-6ITLPRDV.js.map +1 -0
  138. package/dist/cli/version-DAHGZY5N.js +33 -0
  139. package/dist/cli/{version-XQXYSJ5L.js.map → version-DAHGZY5N.js.map} +1 -1
  140. package/dist/index.d.ts +12 -3
  141. package/dist/index.js +182 -97
  142. package/dist/index.js.map +1 -1
  143. package/package.json +1 -1
  144. package/dist/cli/acp-64VQZLDJ.js.map +0 -1
  145. package/dist/cli/chat-ZAGX52RV.js +0 -46
  146. package/dist/cli/chunk-4W2CICFQ.js.map +0 -1
  147. package/dist/cli/chunk-5X7LZJDE.js +0 -36
  148. package/dist/cli/chunk-5X7LZJDE.js.map +0 -1
  149. package/dist/cli/chunk-65Q5HQ26.js +0 -892
  150. package/dist/cli/chunk-65Q5HQ26.js.map +0 -1
  151. package/dist/cli/chunk-A3LL4XDV.js.map +0 -1
  152. package/dist/cli/chunk-A7VHMMDE.js.map +0 -1
  153. package/dist/cli/chunk-AFFZF3MW.js +0 -36
  154. package/dist/cli/chunk-AFFZF3MW.js.map +0 -1
  155. package/dist/cli/chunk-BOFL3T45.js.map +0 -1
  156. package/dist/cli/chunk-BYZGO3BX.js.map +0 -1
  157. package/dist/cli/chunk-CD4SCQL4.js.map +0 -1
  158. package/dist/cli/chunk-CPOV2O73.js +0 -39
  159. package/dist/cli/chunk-CPOV2O73.js.map +0 -1
  160. package/dist/cli/chunk-F2AV2QDK.js +0 -16514
  161. package/dist/cli/chunk-F2AV2QDK.js.map +0 -1
  162. package/dist/cli/chunk-H4OLWRSX.js.map +0 -1
  163. package/dist/cli/chunk-IEA6JOIP.js +0 -5430
  164. package/dist/cli/chunk-IEA6JOIP.js.map +0 -1
  165. package/dist/cli/chunk-L7W3HJZQ.js +0 -46
  166. package/dist/cli/chunk-LN27AKV3.js +0 -26
  167. package/dist/cli/chunk-LN27AKV3.js.map +0 -1
  168. package/dist/cli/chunk-MHGPBJ2T.js.map +0 -1
  169. package/dist/cli/chunk-SXLJBFIV.js.map +0 -1
  170. package/dist/cli/chunk-YJFKFTAL.js.map +0 -1
  171. package/dist/cli/code-X3M6ENTQ.js.map +0 -1
  172. package/dist/cli/desktop-ZTMHQR2Y.js.map +0 -1
  173. package/dist/cli/diff-YASCB7PU.js +0 -153
  174. package/dist/cli/doctor-XCN5ETVP.js +0 -24
  175. package/dist/cli/prompt-RSIHN62V.js +0 -14
  176. package/dist/cli/server-DRFPXXSH.js.map +0 -1
  177. package/dist/cli/setup-FQL2JJC2.js +0 -516
  178. package/dist/cli/setup-FQL2JJC2.js.map +0 -1
  179. package/dist/cli/stats-5RJCATCE.js +0 -12
  180. package/dist/cli/update-GUCWB4UN.js +0 -13
  181. package/dist/cli/version-XQXYSJ5L.js +0 -30
  182. /package/dist/cli/{chat-ZAGX52RV.js.map → chat-7ES4IBNH.js.map} +0 -0
  183. /package/dist/cli/{doctor-XCN5ETVP.js.map → chunk-TUK7OWJA.js.map} +0 -0
  184. /package/dist/cli/{prompt-RSIHN62V.js.map → doctor-OT7KH75K.js.map} +0 -0
  185. /package/dist/cli/{stats-5RJCATCE.js.map → prompt-UW6EFLVR.js.map} +0 -0
  186. /package/dist/cli/{update-GUCWB4UN.js.map → stats-MQVI2XQH.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tools/scaffold.ts","../../src/code/setup.ts"],"sourcesContent":["/** Agent-facing tools for scaffolding skills + MCP servers from chat. Persists via the same paths the wizard / `/skill new` use. */\n\nimport { defaultConfigPath, readConfig, writeConfig } from \"../config.js\";\nimport { MCP_CATALOG } from \"../mcp/catalog.js\";\nimport { preflightStdioSpec } from \"../mcp/preflight.js\";\nimport { type McpSpec, parseMcpSpec } from \"../mcp/spec.js\";\nimport { SkillStore } from \"../skills.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\nexport interface ScaffoldToolsOptions {\n homeDir?: string;\n projectRoot?: string;\n /** Override config path — tests point this at a tmp file. */\n configPath?: string;\n}\n\nconst VALID_SKILL_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;\nconst VALID_SERVER_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$/;\nconst VALID_TOOL_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;\n\nexport function registerScaffoldTools(\n registry: ToolRegistry,\n opts: ScaffoldToolsOptions = {},\n): ToolRegistry {\n const configPath = opts.configPath ?? defaultConfigPath();\n\n registry.register({\n name: \"create_skill\",\n description:\n 'Scaffold a new skill (`SKILL.md` in `.reasonix/skills/<name>.md`) the user can invoke later via `/skill <name>`. Use this when the user asks the agent to add a playbook, automate a recurring workflow, or capture a multi-step recipe as a named skill. The frontmatter is filled from the structured args here (description / allowed_tools / run_as / model) so the model never has to write raw YAML. Use `run_as: \"subagent\"` for read-and-synthesize playbooks where only the final answer should come back; default `\"inline\"` appends the body to the parent log so the user sees the steps. Refuses to overwrite an existing skill — pick a different name or ask the user to delete the old one.',\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Skill identifier — letters/digits/`_`/`-`/`.`, 1–64 chars. Becomes the `name` frontmatter and the `<name>.md` filename.\",\n },\n description: {\n type: \"string\",\n description:\n 'One-line summary shown in the pinned skills index. Lead with the verb (\"Run X and …\") so the parent agent can scan it.',\n },\n body: {\n type: \"string\",\n description:\n \"Markdown body of the skill — the playbook the model follows when invoked. Plain prose + bullets; reference tools by name.\",\n },\n scope: {\n type: \"string\",\n enum: [\"project\", \"global\"],\n description:\n \"`project` = `.reasonix/skills/` under the workspace (default, requires `reasonix code`); `global` = `~/.reasonix/skills/` shared across all repos.\",\n },\n allowed_tools: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Optional whitelist of tool names the subagent registry is scoped to (only meaningful for `run_as: subagent`). Common values: `read_file`, `search_content`, `directory_tree`, `run_command`. Omit to give the subagent the full inherited toolset.\",\n },\n run_as: {\n type: \"string\",\n enum: [\"inline\", \"subagent\"],\n description:\n \"`inline` (default) appends the body to the parent log as a tool result. `subagent` spawns an isolated child loop and only the final answer comes back — use for read-and-synthesize playbooks (explore, research, review).\",\n },\n model: {\n type: \"string\",\n enum: [\"deepseek-v4-flash\", \"deepseek-v4-pro\"],\n description:\n \"Subagent model override (only meaningful for `run_as: subagent`). Default is the same as `spawn_subagent` — `deepseek-v4-flash`. Set to `deepseek-v4-pro` only when the playbook empirically needs the stronger model.\",\n },\n },\n required: [\"name\", \"description\", \"body\"],\n },\n fn: async (args: {\n name?: unknown;\n description?: unknown;\n body?: unknown;\n scope?: unknown;\n allowed_tools?: unknown;\n run_as?: unknown;\n model?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!VALID_SKILL_NAME.test(name)) {\n return JSON.stringify({\n error: `invalid skill name: ${JSON.stringify(name)} — use letters, digits, _, -, .`,\n });\n }\n const description =\n typeof args.description === \"string\" ? args.description.trim().replace(/\\n+/g, \" \") : \"\";\n if (!description) {\n return JSON.stringify({\n error: \"create_skill requires a non-empty 'description'\",\n });\n }\n const body = typeof args.body === \"string\" ? args.body : \"\";\n if (!body.trim()) {\n return JSON.stringify({ error: \"create_skill requires a non-empty 'body'\" });\n }\n const scope: \"project\" | \"global\" =\n args.scope === \"global\" ? \"global\" : opts.projectRoot ? \"project\" : \"global\";\n const runAs: \"inline\" | \"subagent\" = args.run_as === \"subagent\" ? \"subagent\" : \"inline\";\n const allowedTools = parseAllowedTools(args.allowed_tools);\n if (allowedTools && \"error\" in allowedTools) {\n return JSON.stringify({ error: allowedTools.error });\n }\n const model =\n typeof args.model === \"string\" && args.model.startsWith(\"deepseek-\")\n ? args.model\n : undefined;\n\n const content = serializeSkill({\n name,\n description,\n runAs,\n allowedTools: allowedTools ?? undefined,\n model,\n body,\n });\n\n const store = new SkillStore({\n homeDir: opts.homeDir,\n projectRoot: opts.projectRoot,\n });\n const result = store.createWithContent(name, scope, content);\n if (\"error\" in result) {\n return JSON.stringify({ error: result.error });\n }\n return JSON.stringify({\n success: true,\n path: result.path,\n scope,\n name,\n run_as: runAs,\n });\n },\n });\n\n registry.register({\n name: \"add_mcp_server\",\n description:\n 'Register a new MCP server in the user\\'s Reasonix config (`mcp` array). Takes effect on the next session — does NOT spawn the server now. Use stdio for local commands (npx packages, local binaries), `sse` or `streamable-http` for remote endpoints. Pass `from_catalog: \"<name>\"` (e.g. `\"filesystem\"`, `\"memory\"`, `\"github\"`) to auto-fill `command` + `args` from the bundled catalog — the user still has to supply user-args (filesystem: a sandbox dir; github: GITHUB_PERSONAL_ACCESS_TOKEN in env). Refuses to add a server whose name collides with an existing entry.',\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Server name — used as the namespace prefix on every tool the server exposes. Letters/digits/`_`/`-`, must start with a letter or `_`.\",\n },\n transport: {\n type: \"string\",\n enum: [\"stdio\", \"sse\", \"streamable-http\"],\n description:\n \"`stdio` = spawn a local command and pipe MCP over stdin/stdout. `sse` = HTTP+SSE remote. `streamable-http` = Streamable HTTP remote. Required unless `from_catalog` is set.\",\n },\n command: {\n type: \"string\",\n description:\n 'Argv[0] for stdio servers — typically `npx` or a binary path. Required when `transport: \"stdio\"` (and no `from_catalog`).',\n },\n args: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n 'Remaining argv for stdio servers — e.g. `[\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/dir\"]`. The dir at the tail is enforced to exist by the preflight check.',\n },\n url: {\n type: \"string\",\n description:\n \"Endpoint URL for `sse` / `streamable-http` transports. Must be `http://` or `https://`.\",\n },\n from_catalog: {\n type: \"string\",\n description:\n \"Optional shortcut — name out of the bundled catalog (`filesystem`, `memory`, `github`, `puppeteer`, `everything`). When set, fills `command` + `args` from the catalog entry; you still supply `name` (defaults to the catalog name) and any user-args via `args`.\",\n },\n },\n required: [\"name\"],\n },\n fn: async (args: {\n name?: unknown;\n transport?: unknown;\n command?: unknown;\n args?: unknown;\n url?: unknown;\n from_catalog?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!VALID_SERVER_NAME.test(name)) {\n return JSON.stringify({\n error: `invalid server name: ${JSON.stringify(name)} — must match [a-zA-Z_][a-zA-Z0-9_-]*`,\n });\n }\n\n const specStr = buildSpecString({\n name,\n transport: typeof args.transport === \"string\" ? args.transport : undefined,\n command: typeof args.command === \"string\" ? args.command : undefined,\n argv: Array.isArray(args.args)\n ? (args.args.filter((a) => typeof a === \"string\") as string[])\n : undefined,\n url: typeof args.url === \"string\" ? args.url : undefined,\n fromCatalog: typeof args.from_catalog === \"string\" ? args.from_catalog : undefined,\n });\n if (\"error\" in specStr) {\n return JSON.stringify({ error: specStr.error });\n }\n\n let parsed: McpSpec;\n try {\n parsed = parseMcpSpec(specStr.spec);\n } catch (err) {\n return JSON.stringify({ error: (err as Error).message });\n }\n if (parsed.transport === \"stdio\") {\n try {\n preflightStdioSpec(parsed);\n } catch (err) {\n return JSON.stringify({ error: (err as Error).message });\n }\n }\n\n const cfg = readConfig(configPath);\n const existing = cfg.mcp ?? [];\n const collision = existing.find((s) => parseSpecName(s) === name);\n if (collision) {\n return JSON.stringify({\n error: `MCP server ${JSON.stringify(name)} already registered: ${collision}`,\n });\n }\n cfg.mcp = [...existing, specStr.spec];\n writeConfig(cfg, configPath);\n return JSON.stringify({\n success: true,\n name,\n transport: parsed.transport,\n spec: specStr.spec,\n config_path: configPath,\n active_on_next_launch: true,\n });\n },\n });\n\n return registry;\n}\n\ninterface SerializeSkillArgs {\n name: string;\n description: string;\n runAs: \"inline\" | \"subagent\";\n allowedTools?: readonly string[];\n model?: string;\n body: string;\n}\n\nexport function serializeSkill(args: SerializeSkillArgs): string {\n const lines: string[] = [\"---\", `name: ${args.name}`, `description: ${args.description}`];\n if (args.runAs === \"subagent\") {\n lines.push(\"runAs: subagent\");\n }\n if (args.allowedTools && args.allowedTools.length > 0) {\n lines.push(`allowed-tools: ${args.allowedTools.join(\", \")}`);\n }\n if (args.model) {\n lines.push(`model: ${args.model}`);\n }\n lines.push(\"---\", \"\");\n return `${lines.join(\"\\n\")}\\n${args.body.trim()}\\n`;\n}\n\nfunction parseAllowedTools(raw: unknown): readonly string[] | { error: string } | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (!Array.isArray(raw)) {\n return { error: \"'allowed_tools' must be an array of tool-name strings\" };\n }\n const out: string[] = [];\n for (const v of raw) {\n if (typeof v !== \"string\") {\n return { error: \"'allowed_tools' entries must be strings\" };\n }\n const trimmed = v.trim();\n if (!trimmed) continue;\n if (!VALID_TOOL_NAME.test(trimmed)) {\n return { error: `invalid tool name in allowed_tools: ${JSON.stringify(trimmed)}` };\n }\n out.push(trimmed);\n }\n return out.length > 0 ? out : undefined;\n}\n\ninterface BuildSpecInput {\n name: string;\n transport?: string;\n command?: string;\n argv?: string[];\n url?: string;\n fromCatalog?: string;\n}\n\nfunction buildSpecString(input: BuildSpecInput): { spec: string } | { error: string } {\n if (input.fromCatalog) {\n const entry = MCP_CATALOG.find((e) => e.name === input.fromCatalog);\n if (!entry) {\n const known = MCP_CATALOG.map((e) => e.name).join(\", \");\n return {\n error: `unknown catalog entry: ${JSON.stringify(input.fromCatalog)} — known: ${known}`,\n };\n }\n const userArgs = input.argv ?? [];\n if (entry.userArgs && userArgs.length === 0) {\n return {\n error: `catalog entry \"${entry.name}\" needs ${entry.userArgs} — pass it via the 'args' parameter`,\n };\n }\n const tail = userArgs.map(quoteIfNeeded).join(\" \");\n const body = `npx -y ${entry.package}${tail ? ` ${tail}` : \"\"}`;\n return { spec: `${input.name}=${body}` };\n }\n\n const transport = input.transport;\n if (!transport) {\n return { error: \"add_mcp_server requires 'transport' (or 'from_catalog')\" };\n }\n if (transport === \"stdio\") {\n if (!input.command || !input.command.trim()) {\n return { error: \"stdio transport requires 'command'\" };\n }\n const tail = (input.argv ?? []).map(quoteIfNeeded).join(\" \");\n const body = `${quoteIfNeeded(input.command.trim())}${tail ? ` ${tail}` : \"\"}`;\n return { spec: `${input.name}=${body}` };\n }\n if (transport === \"sse\" || transport === \"streamable-http\") {\n if (!input.url || !/^https?:\\/\\//i.test(input.url)) {\n return { error: `${transport} transport requires an http(s):// 'url'` };\n }\n const prefix = transport === \"streamable-http\" ? \"streamable+\" : \"\";\n return { spec: `${input.name}=${prefix}${input.url.trim()}` };\n }\n return { error: `unknown transport: ${JSON.stringify(transport)}` };\n}\n\nfunction parseSpecName(spec: string): string | null {\n const m = spec.trim().match(/^([a-zA-Z_][a-zA-Z0-9_-]*)=/);\n return m ? (m[1] ?? null) : null;\n}\n\nfunction quoteIfNeeded(s: string): string {\n return /\\s|\"/.test(s) ? `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"` : s;\n}\n","import { DeepSeekClient } from \"../client.js\";\nimport {\n loadBaseUrl,\n loadEditMode,\n loadProjectShellAllowed,\n searchEnabled,\n webSearchEndpoint,\n webSearchEngine,\n} from \"../config.js\";\nimport { bootstrapSemanticSearchInCodeMode } from \"../index/semantic/tool.js\";\nimport { ToolRegistry } from \"../tools.js\";\nimport { registerChoiceTool } from \"../tools/choice.js\";\nimport { registerFilesystemTools } from \"../tools/filesystem.js\";\nimport { JobRegistry } from \"../tools/jobs.js\";\nimport { registerMemoryTools } from \"../tools/memory.js\";\nimport { registerPlanTool } from \"../tools/plan.js\";\nimport { registerScaffoldTools } from \"../tools/scaffold.js\";\nimport { registerShellTools } from \"../tools/shell.js\";\nimport { registerSkillTools } from \"../tools/skills.js\";\nimport { formatSubagentResult, spawnSubagent } from \"../tools/subagent.js\";\nimport { registerTodoTool } from \"../tools/todo.js\";\nimport { registerWebTools } from \"../tools/web.js\";\n\nexport interface CodeToolsetOpts {\n rootDir: string;\n}\n\nexport interface CodeToolset {\n tools: ToolRegistry;\n jobs: JobRegistry;\n registerRooted: (root: string) => void;\n reBootstrapSemantic: (root: string) => Promise<{ enabled: boolean }>;\n semantic: { enabled: boolean };\n}\n\nexport async function buildCodeToolset(opts: CodeToolsetOpts): Promise<CodeToolset> {\n const tools = new ToolRegistry();\n const jobs = new JobRegistry();\n\n const registerRooted = (root: string): void => {\n registerFilesystemTools(tools, { rootDir: root });\n registerShellTools(tools, {\n rootDir: root,\n extraAllowed: () => loadProjectShellAllowed(root),\n allowAll: () => loadEditMode() === \"yolo\",\n jobs,\n });\n registerMemoryTools(tools, { projectRoot: root });\n };\n\n const reBootstrapSemantic = async (root: string): Promise<{ enabled: boolean }> => {\n const result = await bootstrapSemanticSearchInCodeMode(tools, root);\n if (!result.enabled) tools.unregister(\"semantic_search\");\n return result;\n };\n\n registerRooted(opts.rootDir);\n registerPlanTool(tools);\n registerChoiceTool(tools);\n registerTodoTool(tools);\n registerScaffoldTools(tools, { projectRoot: opts.rootDir });\n if (searchEnabled()) {\n registerWebTools(tools, {\n webSearchEngine: webSearchEngine(),\n webSearchEndpoint: webSearchEndpoint(),\n });\n }\n // Lazy: constructing DeepSeekClient throws when DEEPSEEK_API_KEY is unset,\n // which would kill `reasonix code` before the setup wizard can prompt for\n // one. Defer to first subagent dispatch — by then the user has either keyed\n // in or we error per-call instead of at boot.\n let subagentClient: DeepSeekClient | null = null;\n registerSkillTools(tools, {\n projectRoot: opts.rootDir,\n subagentRunner: async (skill, task, signal) => {\n if (!subagentClient) subagentClient = new DeepSeekClient({ baseUrl: loadBaseUrl() });\n const result = await spawnSubagent({\n client: subagentClient,\n parentRegistry: tools,\n parentSignal: signal,\n system: skill.body,\n task,\n model: skill.model,\n allowedTools: skill.allowedTools,\n });\n return formatSubagentResult(result);\n },\n });\n\n const semantic = await reBootstrapSemantic(opts.rootDir);\n\n return { tools, jobs, registerRooted, reBootstrapSemantic, semantic };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/tools/scaffold.ts","../../src/code/setup.ts"],"sourcesContent":["/** Agent-facing tools for scaffolding skills + MCP servers from chat. Persists via the same paths the wizard / `/skill new` use. */\n\nimport { defaultConfigPath, readConfig, writeConfig } from \"../config.js\";\nimport { MCP_CATALOG } from \"../mcp/catalog.js\";\nimport { preflightStdioSpec } from \"../mcp/preflight.js\";\nimport { type McpSpec, parseMcpSpec } from \"../mcp/spec.js\";\nimport { SkillStore } from \"../skills.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\nexport interface ScaffoldToolsOptions {\n homeDir?: string;\n projectRoot?: string;\n /** Override config path — tests point this at a tmp file. */\n configPath?: string;\n}\n\nconst VALID_SKILL_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;\nconst VALID_SERVER_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$/;\nconst VALID_TOOL_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;\n\nexport function registerScaffoldTools(\n registry: ToolRegistry,\n opts: ScaffoldToolsOptions = {},\n): ToolRegistry {\n const configPath = opts.configPath ?? defaultConfigPath();\n\n registry.register({\n name: \"create_skill\",\n description:\n 'Scaffold a new skill (`SKILL.md` in `.reasonix/skills/<name>.md`) the user can invoke later via `/skill <name>`. Use this when the user asks the agent to add a playbook, automate a recurring workflow, or capture a multi-step recipe as a named skill. The frontmatter is filled from the structured args here (description / allowed_tools / run_as / model) so the model never has to write raw YAML. Use `run_as: \"subagent\"` for read-and-synthesize playbooks where only the final answer should come back; default `\"inline\"` appends the body to the parent log so the user sees the steps. Refuses to overwrite an existing skill — pick a different name or ask the user to delete the old one.',\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Skill identifier — letters/digits/`_`/`-`/`.`, 1–64 chars. Becomes the `name` frontmatter and the `<name>.md` filename.\",\n },\n description: {\n type: \"string\",\n description:\n 'One-line summary shown in the pinned skills index. Lead with the verb (\"Run X and …\") so the parent agent can scan it.',\n },\n body: {\n type: \"string\",\n description:\n \"Markdown body of the skill — the playbook the model follows when invoked. Plain prose + bullets; reference tools by name.\",\n },\n scope: {\n type: \"string\",\n enum: [\"project\", \"global\"],\n description:\n \"`project` = `.reasonix/skills/` under the workspace (default, requires `reasonix code`); `global` = `~/.reasonix/skills/` shared across all repos.\",\n },\n allowed_tools: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Optional whitelist of tool names the subagent registry is scoped to (only meaningful for `run_as: subagent`). Common values: `read_file`, `search_content`, `directory_tree`, `run_command`. Omit to give the subagent the full inherited toolset.\",\n },\n run_as: {\n type: \"string\",\n enum: [\"inline\", \"subagent\"],\n description:\n \"`inline` (default) appends the body to the parent log as a tool result. `subagent` spawns an isolated child loop and only the final answer comes back — use for read-and-synthesize playbooks (explore, research, review).\",\n },\n model: {\n type: \"string\",\n enum: [\"deepseek-v4-flash\", \"deepseek-v4-pro\"],\n description:\n \"Subagent model override (only meaningful for `run_as: subagent`). Default is the same as `spawn_subagent` — `deepseek-v4-flash`. Set to `deepseek-v4-pro` only when the playbook empirically needs the stronger model.\",\n },\n },\n required: [\"name\", \"description\", \"body\"],\n },\n fn: async (args: {\n name?: unknown;\n description?: unknown;\n body?: unknown;\n scope?: unknown;\n allowed_tools?: unknown;\n run_as?: unknown;\n model?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!VALID_SKILL_NAME.test(name)) {\n return JSON.stringify({\n error: `invalid skill name: ${JSON.stringify(name)} — use letters, digits, _, -, .`,\n });\n }\n const description =\n typeof args.description === \"string\" ? args.description.trim().replace(/\\n+/g, \" \") : \"\";\n if (!description) {\n return JSON.stringify({\n error: \"create_skill requires a non-empty 'description'\",\n });\n }\n const body = typeof args.body === \"string\" ? args.body : \"\";\n if (!body.trim()) {\n return JSON.stringify({ error: \"create_skill requires a non-empty 'body'\" });\n }\n const scope: \"project\" | \"global\" =\n args.scope === \"global\" ? \"global\" : opts.projectRoot ? \"project\" : \"global\";\n const runAs: \"inline\" | \"subagent\" = args.run_as === \"subagent\" ? \"subagent\" : \"inline\";\n const allowedTools = parseAllowedTools(args.allowed_tools);\n if (allowedTools && \"error\" in allowedTools) {\n return JSON.stringify({ error: allowedTools.error });\n }\n const model =\n typeof args.model === \"string\" && args.model.startsWith(\"deepseek-\")\n ? args.model\n : undefined;\n\n const content = serializeSkill({\n name,\n description,\n runAs,\n allowedTools: allowedTools ?? undefined,\n model,\n body,\n });\n\n const store = new SkillStore({\n homeDir: opts.homeDir,\n projectRoot: opts.projectRoot,\n });\n const result = store.createWithContent(name, scope, content);\n if (\"error\" in result) {\n return JSON.stringify({ error: result.error });\n }\n return JSON.stringify({\n success: true,\n path: result.path,\n scope,\n name,\n run_as: runAs,\n });\n },\n });\n\n registry.register({\n name: \"add_mcp_server\",\n description:\n 'Register a new MCP server in the user\\'s Reasonix config (`mcp` array). Takes effect on the next session — does NOT spawn the server now. Use stdio for local commands (npx packages, local binaries), `sse` or `streamable-http` for remote endpoints. Pass `from_catalog: \"<name>\"` (e.g. `\"filesystem\"`, `\"memory\"`, `\"github\"`) to auto-fill `command` + `args` from the bundled catalog — the user still has to supply user-args (filesystem: a sandbox dir; github: GITHUB_PERSONAL_ACCESS_TOKEN in env). Refuses to add a server whose name collides with an existing entry.',\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Server name — used as the namespace prefix on every tool the server exposes. Letters/digits/`_`/`-`, must start with a letter or `_`.\",\n },\n transport: {\n type: \"string\",\n enum: [\"stdio\", \"sse\", \"streamable-http\"],\n description:\n \"`stdio` = spawn a local command and pipe MCP over stdin/stdout. `sse` = HTTP+SSE remote. `streamable-http` = Streamable HTTP remote. Required unless `from_catalog` is set.\",\n },\n command: {\n type: \"string\",\n description:\n 'Argv[0] for stdio servers — typically `npx` or a binary path. Required when `transport: \"stdio\"` (and no `from_catalog`).',\n },\n args: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n 'Remaining argv for stdio servers — e.g. `[\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/dir\"]`. The dir at the tail is enforced to exist by the preflight check.',\n },\n url: {\n type: \"string\",\n description:\n \"Endpoint URL for `sse` / `streamable-http` transports. Must be `http://` or `https://`.\",\n },\n from_catalog: {\n type: \"string\",\n description:\n \"Optional shortcut — name out of the bundled catalog (`filesystem`, `memory`, `github`, `puppeteer`, `everything`). When set, fills `command` + `args` from the catalog entry; you still supply `name` (defaults to the catalog name) and any user-args via `args`.\",\n },\n },\n required: [\"name\"],\n },\n fn: async (args: {\n name?: unknown;\n transport?: unknown;\n command?: unknown;\n args?: unknown;\n url?: unknown;\n from_catalog?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!VALID_SERVER_NAME.test(name)) {\n return JSON.stringify({\n error: `invalid server name: ${JSON.stringify(name)} — must match [a-zA-Z_][a-zA-Z0-9_-]*`,\n });\n }\n\n const specStr = buildSpecString({\n name,\n transport: typeof args.transport === \"string\" ? args.transport : undefined,\n command: typeof args.command === \"string\" ? args.command : undefined,\n argv: Array.isArray(args.args)\n ? (args.args.filter((a) => typeof a === \"string\") as string[])\n : undefined,\n url: typeof args.url === \"string\" ? args.url : undefined,\n fromCatalog: typeof args.from_catalog === \"string\" ? args.from_catalog : undefined,\n });\n if (\"error\" in specStr) {\n return JSON.stringify({ error: specStr.error });\n }\n\n let parsed: McpSpec;\n try {\n parsed = parseMcpSpec(specStr.spec);\n } catch (err) {\n return JSON.stringify({ error: (err as Error).message });\n }\n if (parsed.transport === \"stdio\") {\n try {\n preflightStdioSpec(parsed);\n } catch (err) {\n return JSON.stringify({ error: (err as Error).message });\n }\n }\n\n const cfg = readConfig(configPath);\n const existing = cfg.mcp ?? [];\n const collision = existing.find((s) => parseSpecName(s) === name);\n if (collision) {\n return JSON.stringify({\n error: `MCP server ${JSON.stringify(name)} already registered: ${collision}`,\n });\n }\n cfg.mcp = [...existing, specStr.spec];\n writeConfig(cfg, configPath);\n return JSON.stringify({\n success: true,\n name,\n transport: parsed.transport,\n spec: specStr.spec,\n config_path: configPath,\n active_on_next_launch: true,\n });\n },\n });\n\n return registry;\n}\n\ninterface SerializeSkillArgs {\n name: string;\n description: string;\n runAs: \"inline\" | \"subagent\";\n allowedTools?: readonly string[];\n model?: string;\n body: string;\n}\n\nexport function serializeSkill(args: SerializeSkillArgs): string {\n const lines: string[] = [\"---\", `name: ${args.name}`, `description: ${args.description}`];\n if (args.runAs === \"subagent\") {\n lines.push(\"runAs: subagent\");\n }\n if (args.allowedTools && args.allowedTools.length > 0) {\n lines.push(`allowed-tools: ${args.allowedTools.join(\", \")}`);\n }\n if (args.model) {\n lines.push(`model: ${args.model}`);\n }\n lines.push(\"---\", \"\");\n return `${lines.join(\"\\n\")}\\n${args.body.trim()}\\n`;\n}\n\nfunction parseAllowedTools(raw: unknown): readonly string[] | { error: string } | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (!Array.isArray(raw)) {\n return { error: \"'allowed_tools' must be an array of tool-name strings\" };\n }\n const out: string[] = [];\n for (const v of raw) {\n if (typeof v !== \"string\") {\n return { error: \"'allowed_tools' entries must be strings\" };\n }\n const trimmed = v.trim();\n if (!trimmed) continue;\n if (!VALID_TOOL_NAME.test(trimmed)) {\n return { error: `invalid tool name in allowed_tools: ${JSON.stringify(trimmed)}` };\n }\n out.push(trimmed);\n }\n return out.length > 0 ? out : undefined;\n}\n\ninterface BuildSpecInput {\n name: string;\n transport?: string;\n command?: string;\n argv?: string[];\n url?: string;\n fromCatalog?: string;\n}\n\nfunction buildSpecString(input: BuildSpecInput): { spec: string } | { error: string } {\n if (input.fromCatalog) {\n const entry = MCP_CATALOG.find((e) => e.name === input.fromCatalog);\n if (!entry) {\n const known = MCP_CATALOG.map((e) => e.name).join(\", \");\n return {\n error: `unknown catalog entry: ${JSON.stringify(input.fromCatalog)} — known: ${known}`,\n };\n }\n const userArgs = input.argv ?? [];\n if (entry.userArgs && userArgs.length === 0) {\n return {\n error: `catalog entry \"${entry.name}\" needs ${entry.userArgs} — pass it via the 'args' parameter`,\n };\n }\n const tail = userArgs.map(quoteIfNeeded).join(\" \");\n const body = `npx -y ${entry.package}${tail ? ` ${tail}` : \"\"}`;\n return { spec: `${input.name}=${body}` };\n }\n\n const transport = input.transport;\n if (!transport) {\n return { error: \"add_mcp_server requires 'transport' (or 'from_catalog')\" };\n }\n if (transport === \"stdio\") {\n if (!input.command || !input.command.trim()) {\n return { error: \"stdio transport requires 'command'\" };\n }\n const tail = (input.argv ?? []).map(quoteIfNeeded).join(\" \");\n const body = `${quoteIfNeeded(input.command.trim())}${tail ? ` ${tail}` : \"\"}`;\n return { spec: `${input.name}=${body}` };\n }\n if (transport === \"sse\" || transport === \"streamable-http\") {\n if (!input.url || !/^https?:\\/\\//i.test(input.url)) {\n return { error: `${transport} transport requires an http(s):// 'url'` };\n }\n const prefix = transport === \"streamable-http\" ? \"streamable+\" : \"\";\n return { spec: `${input.name}=${prefix}${input.url.trim()}` };\n }\n return { error: `unknown transport: ${JSON.stringify(transport)}` };\n}\n\nfunction parseSpecName(spec: string): string | null {\n const m = spec.trim().match(/^([a-zA-Z_][a-zA-Z0-9_-]*)=/);\n return m ? (m[1] ?? null) : null;\n}\n\nfunction quoteIfNeeded(s: string): string {\n return /\\s|\"/.test(s) ? `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"` : s;\n}\n","import { DeepSeekClient } from \"../client.js\";\nimport {\n loadBaseUrl,\n loadEditMode,\n loadProjectShellAllowed,\n searchEnabled,\n webSearchEndpoint,\n webSearchEngine,\n} from \"../config.js\";\nimport { bootstrapSemanticSearchInCodeMode } from \"../index/semantic/tool.js\";\nimport { ToolRegistry } from \"../tools.js\";\nimport { registerChoiceTool } from \"../tools/choice.js\";\nimport { registerFilesystemTools } from \"../tools/filesystem.js\";\nimport { JobRegistry } from \"../tools/jobs.js\";\nimport { registerMemoryTools } from \"../tools/memory.js\";\nimport { registerPlanTool } from \"../tools/plan.js\";\nimport { registerScaffoldTools } from \"../tools/scaffold.js\";\nimport { registerShellTools } from \"../tools/shell.js\";\nimport { registerSkillTools } from \"../tools/skills.js\";\nimport { formatSubagentResult, spawnSubagent } from \"../tools/subagent.js\";\nimport { registerTodoTool } from \"../tools/todo.js\";\nimport { registerWebTools } from \"../tools/web.js\";\n\nexport interface CodeToolsetOpts {\n rootDir: string;\n}\n\nexport interface CodeToolset {\n tools: ToolRegistry;\n jobs: JobRegistry;\n registerRooted: (root: string) => void;\n reBootstrapSemantic: (root: string) => Promise<{ enabled: boolean }>;\n semantic: { enabled: boolean };\n}\n\nexport async function buildCodeToolset(opts: CodeToolsetOpts): Promise<CodeToolset> {\n const tools = new ToolRegistry();\n const jobs = new JobRegistry();\n\n const registerRooted = (root: string): void => {\n registerFilesystemTools(tools, { rootDir: root });\n registerShellTools(tools, {\n rootDir: root,\n extraAllowed: () => loadProjectShellAllowed(root),\n allowAll: () => loadEditMode() === \"yolo\",\n jobs,\n });\n registerMemoryTools(tools, { projectRoot: root });\n };\n\n const reBootstrapSemantic = async (root: string): Promise<{ enabled: boolean }> => {\n const result = await bootstrapSemanticSearchInCodeMode(tools, root);\n if (!result.enabled) tools.unregister(\"semantic_search\");\n return result;\n };\n\n registerRooted(opts.rootDir);\n registerPlanTool(tools);\n registerChoiceTool(tools);\n registerTodoTool(tools);\n registerScaffoldTools(tools, { projectRoot: opts.rootDir });\n if (searchEnabled()) {\n registerWebTools(tools, {\n webSearchEngine: webSearchEngine(),\n webSearchEndpoint: webSearchEndpoint(),\n });\n }\n // Lazy: constructing DeepSeekClient throws when DEEPSEEK_API_KEY is unset,\n // which would kill `reasonix code` before the setup wizard can prompt for\n // one. Defer to first subagent dispatch — by then the user has either keyed\n // in or we error per-call instead of at boot.\n let subagentClient: DeepSeekClient | null = null;\n registerSkillTools(tools, {\n projectRoot: opts.rootDir,\n subagentRunner: async (skill, task, signal) => {\n if (!subagentClient) subagentClient = new DeepSeekClient({ baseUrl: loadBaseUrl() });\n const result = await spawnSubagent({\n client: subagentClient,\n parentRegistry: tools,\n parentSignal: signal,\n system: skill.body,\n task,\n model: skill.model,\n allowedTools: skill.allowedTools,\n maxToolIters: skill.maxToolIters,\n skillName: skill.name,\n });\n return formatSubagentResult(result);\n },\n });\n\n const semantic = await reBootstrapSemantic(opts.rootDir);\n\n return { tools, jobs, registerRooted, reBootstrapSemantic, semantic };\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
2
3
 
3
4
  // src/telemetry/stats.ts
4
5
  var DEEPSEEK_PRICING = {
@@ -137,4 +138,4 @@ export {
137
138
  claudeEquivalentCost,
138
139
  SessionStats
139
140
  };
140
- //# sourceMappingURL=chunk-ORM6PK57.js.map
141
+ //# sourceMappingURL=chunk-YQ6NTIIE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/telemetry/stats.ts"],"sourcesContent":["import type { Usage } from \"../client.js\";\n\n/** USD per 1M tokens; CNY sheet converted at fixed 7.2 — revisit if FX moves >±5%. */\nexport const DEEPSEEK_PRICING: Record<\n string,\n { inputCacheHit: number; inputCacheMiss: number; output: number }\n> = {\n \"deepseek-v4-flash\": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },\n \"deepseek-v4-pro\": { inputCacheHit: 0.139, inputCacheMiss: 1.667, output: 3.333 },\n // Compat aliases — priced as v4-flash per the deprecation notice.\n \"deepseek-chat\": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },\n \"deepseek-reasoner\": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },\n};\n\n/** Reference Claude Sonnet 4.6 pricing (USD per 1M tokens). */\nexport const CLAUDE_SONNET_PRICING = { input: 3.0, output: 15.0 };\n\n/** Prompt-side window only; completion caps live server-side and don't affect this gauge. */\nexport const DEEPSEEK_CONTEXT_TOKENS: Record<string, number> = {\n \"deepseek-v4-flash\": 1_000_000,\n \"deepseek-v4-pro\": 1_000_000,\n \"deepseek-chat\": 1_000_000,\n \"deepseek-reasoner\": 1_000_000,\n};\n\n/** Fallback when the caller's model id isn't in the table — safe lower bound. */\nexport const DEFAULT_CONTEXT_TOKENS = 131_072;\n\nexport function costUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (\n (usage.promptCacheHitTokens * p.inputCacheHit +\n usage.promptCacheMissTokens * p.inputCacheMiss +\n usage.completionTokens * p.output) /\n 1_000_000\n );\n}\n\n/** Input-side cost only (prompt, cache hit + miss). Used for the panel breakdown. */\nexport function inputCostUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (\n (usage.promptCacheHitTokens * p.inputCacheHit +\n usage.promptCacheMissTokens * p.inputCacheMiss) /\n 1_000_000\n );\n}\n\n/** Output-side cost only (completion tokens). Used for the panel breakdown. */\nexport function outputCostUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (usage.completionTokens * p.output) / 1_000_000;\n}\n\nexport function cacheSavingsUsd(model: string, hitTokens: number): number {\n if (hitTokens <= 0) return 0;\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (hitTokens * (p.inputCacheMiss - p.inputCacheHit)) / 1_000_000;\n}\n\nexport function claudeEquivalentCost(usage: Usage): number {\n return (\n (usage.promptTokens * CLAUDE_SONNET_PRICING.input +\n usage.completionTokens * CLAUDE_SONNET_PRICING.output) /\n 1_000_000\n );\n}\n\nexport interface TurnStats {\n turn: number;\n model: string;\n usage: Usage;\n cost: number;\n cacheHitRatio: number;\n}\n\nexport interface SessionSummary {\n turns: number;\n totalCostUsd: number;\n totalInputCostUsd: number;\n /** Output-side (completion) cost aggregated across the session. */\n totalOutputCostUsd: number;\n /** @deprecated Claude reference; kept for benchmarks + replay compat, no longer surfaced in the TUI. */\n claudeEquivalentUsd: number;\n /** @deprecated. Same as claudeEquivalentUsd — synthetic ratio, not a real measurement. */\n savingsVsClaudePct: number;\n cacheHitRatio: number;\n /** Floor estimate for next call — actual cost = this + user delta + new tool outputs. */\n lastPromptTokens: number;\n lastTurnCostUsd: number;\n}\n\nexport class SessionStats {\n readonly turns: TurnStats[] = [];\n /** Cost from prior runs of a resumed session, restored from session meta. */\n private _carryoverCost = 0;\n /** Turn count from prior runs of a resumed session. */\n private _carryoverTurns = 0;\n private _carryoverCacheHit = 0;\n private _carryoverCacheMiss = 0;\n /** Last turn's promptTokens before exit — surfaced via summary() until the next live turn lands. */\n private _carryoverLastPromptTokens = 0;\n\n /** Seed totals from a resumed session's persisted meta — only call once at construction. */\n seedCarryover(opts: {\n totalCostUsd?: number;\n turnCount?: number;\n cacheHitTokens?: number;\n cacheMissTokens?: number;\n lastPromptTokens?: number;\n }): void {\n if (typeof opts.totalCostUsd === \"number\" && opts.totalCostUsd > 0) {\n this._carryoverCost = opts.totalCostUsd;\n }\n if (typeof opts.turnCount === \"number\" && opts.turnCount > 0) {\n this._carryoverTurns = opts.turnCount;\n }\n if (typeof opts.cacheHitTokens === \"number\" && opts.cacheHitTokens > 0) {\n this._carryoverCacheHit = opts.cacheHitTokens;\n }\n if (typeof opts.cacheMissTokens === \"number\" && opts.cacheMissTokens > 0) {\n this._carryoverCacheMiss = opts.cacheMissTokens;\n }\n if (typeof opts.lastPromptTokens === \"number\" && opts.lastPromptTokens > 0) {\n this._carryoverLastPromptTokens = opts.lastPromptTokens;\n }\n }\n\n record(turn: number, model: string, usage: Usage): TurnStats {\n const cost = costUsd(model, usage);\n const stats: TurnStats = {\n turn,\n model,\n usage,\n cost,\n cacheHitRatio: usage.cacheHitRatio,\n };\n this.turns.push(stats);\n return stats;\n }\n\n get totalCost(): number {\n return this._carryoverCost + this.turns.reduce((sum, t) => sum + t.cost, 0);\n }\n\n get totalClaudeEquivalent(): number {\n return this.turns.reduce((sum, t) => sum + claudeEquivalentCost(t.usage), 0);\n }\n\n get savingsVsClaude(): number {\n const c = this.totalClaudeEquivalent;\n return c > 0 ? 1 - this.totalCost / c : 0;\n }\n\n get totalInputCost(): number {\n return this.turns.reduce((sum, t) => sum + inputCostUsd(t.model, t.usage), 0);\n }\n\n get totalOutputCost(): number {\n return this.turns.reduce((sum, t) => sum + outputCostUsd(t.model, t.usage), 0);\n }\n\n get aggregateCacheHitRatio(): number {\n let hit = this._carryoverCacheHit;\n let miss = this._carryoverCacheMiss;\n for (const t of this.turns) {\n hit += t.usage.promptCacheHitTokens;\n miss += t.usage.promptCacheMissTokens;\n }\n const denom = hit + miss;\n return denom > 0 ? hit / denom : 0;\n }\n\n summary(): SessionSummary {\n const last = this.turns[this.turns.length - 1];\n return {\n turns: this.turns.length + this._carryoverTurns,\n totalCostUsd: round(this.totalCost, 6),\n totalInputCostUsd: round(this.totalInputCost, 6),\n totalOutputCostUsd: round(this.totalOutputCost, 6),\n claudeEquivalentUsd: round(this.totalClaudeEquivalent, 6),\n savingsVsClaudePct: round(this.savingsVsClaude * 100, 2),\n cacheHitRatio: round(this.aggregateCacheHitRatio, 4),\n lastPromptTokens: last?.usage.promptTokens ?? this._carryoverLastPromptTokens,\n lastTurnCostUsd: round(last?.cost ?? 0, 6),\n };\n }\n}\n\nfunction round(n: number, digits: number): number {\n const f = 10 ** digits;\n return Math.round(n * f) / f;\n}\n"],"mappings":";;;AAGO,IAAM,mBAGT;AAAA,EACF,qBAAqB,EAAE,eAAe,OAAO,gBAAgB,OAAO,QAAQ,MAAM;AAAA,EAClF,mBAAmB,EAAE,eAAe,OAAO,gBAAgB,OAAO,QAAQ,MAAM;AAAA;AAAA,EAEhF,iBAAiB,EAAE,eAAe,OAAO,gBAAgB,OAAO,QAAQ,MAAM;AAAA,EAC9E,qBAAqB,EAAE,eAAe,OAAO,gBAAgB,OAAO,QAAQ,MAAM;AACpF;AAGO,IAAM,wBAAwB,EAAE,OAAO,GAAK,QAAQ,GAAK;AAGzD,IAAM,0BAAkD;AAAA,EAC7D,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,qBAAqB;AACvB;AAGO,IAAM,yBAAyB;AAE/B,SAAS,QAAQ,OAAe,OAAsB;AAC3D,QAAM,IAAI,iBAAiB,KAAK;AAChC,MAAI,CAAC,EAAG,QAAO;AACf,UACG,MAAM,uBAAuB,EAAE,gBAC9B,MAAM,wBAAwB,EAAE,iBAChC,MAAM,mBAAmB,EAAE,UAC7B;AAEJ;AAGO,SAAS,aAAa,OAAe,OAAsB;AAChE,QAAM,IAAI,iBAAiB,KAAK;AAChC,MAAI,CAAC,EAAG,QAAO;AACf,UACG,MAAM,uBAAuB,EAAE,gBAC9B,MAAM,wBAAwB,EAAE,kBAClC;AAEJ;AAGO,SAAS,cAAc,OAAe,OAAsB;AACjE,QAAM,IAAI,iBAAiB,KAAK;AAChC,MAAI,CAAC,EAAG,QAAO;AACf,SAAQ,MAAM,mBAAmB,EAAE,SAAU;AAC/C;AAEO,SAAS,gBAAgB,OAAe,WAA2B;AACxE,MAAI,aAAa,EAAG,QAAO;AAC3B,QAAM,IAAI,iBAAiB,KAAK;AAChC,MAAI,CAAC,EAAG,QAAO;AACf,SAAQ,aAAa,EAAE,iBAAiB,EAAE,iBAAkB;AAC9D;AAEO,SAAS,qBAAqB,OAAsB;AACzD,UACG,MAAM,eAAe,sBAAsB,QAC1C,MAAM,mBAAmB,sBAAsB,UACjD;AAEJ;AA0BO,IAAM,eAAN,MAAmB;AAAA,EACf,QAAqB,CAAC;AAAA;AAAA,EAEvB,iBAAiB;AAAA;AAAA,EAEjB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA;AAAA,EAEtB,6BAA6B;AAAA;AAAA,EAGrC,cAAc,MAML;AACP,QAAI,OAAO,KAAK,iBAAiB,YAAY,KAAK,eAAe,GAAG;AAClE,WAAK,iBAAiB,KAAK;AAAA,IAC7B;AACA,QAAI,OAAO,KAAK,cAAc,YAAY,KAAK,YAAY,GAAG;AAC5D,WAAK,kBAAkB,KAAK;AAAA,IAC9B;AACA,QAAI,OAAO,KAAK,mBAAmB,YAAY,KAAK,iBAAiB,GAAG;AACtE,WAAK,qBAAqB,KAAK;AAAA,IACjC;AACA,QAAI,OAAO,KAAK,oBAAoB,YAAY,KAAK,kBAAkB,GAAG;AACxE,WAAK,sBAAsB,KAAK;AAAA,IAClC;AACA,QAAI,OAAO,KAAK,qBAAqB,YAAY,KAAK,mBAAmB,GAAG;AAC1E,WAAK,6BAA6B,KAAK;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,OAAO,MAAc,OAAe,OAAyB;AAC3D,UAAM,OAAO,QAAQ,OAAO,KAAK;AACjC,UAAM,QAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe,MAAM;AAAA,IACvB;AACA,SAAK,MAAM,KAAK,KAAK;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,iBAAiB,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC;AAAA,EAC5E;AAAA,EAEA,IAAI,wBAAgC;AAClC,WAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,qBAAqB,EAAE,KAAK,GAAG,CAAC;AAAA,EAC7E;AAAA,EAEA,IAAI,kBAA0B;AAC5B,UAAM,IAAI,KAAK;AACf,WAAO,IAAI,IAAI,IAAI,KAAK,YAAY,IAAI;AAAA,EAC1C;AAAA,EAEA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,aAAa,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC;AAAA,EAC9E;AAAA,EAEA,IAAI,kBAA0B;AAC5B,WAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,cAAc,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC;AAAA,EAC/E;AAAA,EAEA,IAAI,yBAAiC;AACnC,QAAI,MAAM,KAAK;AACf,QAAI,OAAO,KAAK;AAChB,eAAW,KAAK,KAAK,OAAO;AAC1B,aAAO,EAAE,MAAM;AACf,cAAQ,EAAE,MAAM;AAAA,IAClB;AACA,UAAM,QAAQ,MAAM;AACpB,WAAO,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACnC;AAAA,EAEA,UAA0B;AACxB,UAAM,OAAO,KAAK,MAAM,KAAK,MAAM,SAAS,CAAC;AAC7C,WAAO;AAAA,MACL,OAAO,KAAK,MAAM,SAAS,KAAK;AAAA,MAChC,cAAc,MAAM,KAAK,WAAW,CAAC;AAAA,MACrC,mBAAmB,MAAM,KAAK,gBAAgB,CAAC;AAAA,MAC/C,oBAAoB,MAAM,KAAK,iBAAiB,CAAC;AAAA,MACjD,qBAAqB,MAAM,KAAK,uBAAuB,CAAC;AAAA,MACxD,oBAAoB,MAAM,KAAK,kBAAkB,KAAK,CAAC;AAAA,MACvD,eAAe,MAAM,KAAK,wBAAwB,CAAC;AAAA,MACnD,kBAAkB,MAAM,MAAM,gBAAgB,KAAK;AAAA,MACnD,iBAAiB,MAAM,MAAM,QAAQ,GAAG,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,MAAM,GAAW,QAAwB;AAChD,QAAM,IAAI,MAAM;AAChB,SAAO,KAAK,MAAM,IAAI,CAAC,IAAI;AAC7B;","names":[]}
1
+ {"version":3,"sources":["../../src/telemetry/stats.ts"],"sourcesContent":["import type { Usage } from \"../client.js\";\n\n/** USD per 1M tokens; CNY sheet converted at fixed 7.2 — revisit if FX moves >±5%. */\nexport const DEEPSEEK_PRICING: Record<\n string,\n { inputCacheHit: number; inputCacheMiss: number; output: number }\n> = {\n \"deepseek-v4-flash\": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },\n \"deepseek-v4-pro\": { inputCacheHit: 0.139, inputCacheMiss: 1.667, output: 3.333 },\n // Compat aliases — priced as v4-flash per the deprecation notice.\n \"deepseek-chat\": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },\n \"deepseek-reasoner\": { inputCacheHit: 0.028, inputCacheMiss: 0.139, output: 0.278 },\n};\n\n/** Reference Claude Sonnet 4.6 pricing (USD per 1M tokens). */\nexport const CLAUDE_SONNET_PRICING = { input: 3.0, output: 15.0 };\n\n/** Prompt-side window only; completion caps live server-side and don't affect this gauge. */\nexport const DEEPSEEK_CONTEXT_TOKENS: Record<string, number> = {\n \"deepseek-v4-flash\": 1_000_000,\n \"deepseek-v4-pro\": 1_000_000,\n \"deepseek-chat\": 1_000_000,\n \"deepseek-reasoner\": 1_000_000,\n};\n\n/** Fallback when the caller's model id isn't in the table — safe lower bound. */\nexport const DEFAULT_CONTEXT_TOKENS = 131_072;\n\nexport function costUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (\n (usage.promptCacheHitTokens * p.inputCacheHit +\n usage.promptCacheMissTokens * p.inputCacheMiss +\n usage.completionTokens * p.output) /\n 1_000_000\n );\n}\n\n/** Input-side cost only (prompt, cache hit + miss). Used for the panel breakdown. */\nexport function inputCostUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (\n (usage.promptCacheHitTokens * p.inputCacheHit +\n usage.promptCacheMissTokens * p.inputCacheMiss) /\n 1_000_000\n );\n}\n\n/** Output-side cost only (completion tokens). Used for the panel breakdown. */\nexport function outputCostUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (usage.completionTokens * p.output) / 1_000_000;\n}\n\nexport function cacheSavingsUsd(model: string, hitTokens: number): number {\n if (hitTokens <= 0) return 0;\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (hitTokens * (p.inputCacheMiss - p.inputCacheHit)) / 1_000_000;\n}\n\nexport function claudeEquivalentCost(usage: Usage): number {\n return (\n (usage.promptTokens * CLAUDE_SONNET_PRICING.input +\n usage.completionTokens * CLAUDE_SONNET_PRICING.output) /\n 1_000_000\n );\n}\n\nexport interface TurnStats {\n turn: number;\n model: string;\n usage: Usage;\n cost: number;\n cacheHitRatio: number;\n}\n\nexport interface SessionSummary {\n turns: number;\n totalCostUsd: number;\n totalInputCostUsd: number;\n /** Output-side (completion) cost aggregated across the session. */\n totalOutputCostUsd: number;\n /** @deprecated Claude reference; kept for benchmarks + replay compat, no longer surfaced in the TUI. */\n claudeEquivalentUsd: number;\n /** @deprecated. Same as claudeEquivalentUsd — synthetic ratio, not a real measurement. */\n savingsVsClaudePct: number;\n cacheHitRatio: number;\n /** Floor estimate for next call — actual cost = this + user delta + new tool outputs. */\n lastPromptTokens: number;\n lastTurnCostUsd: number;\n}\n\nexport class SessionStats {\n readonly turns: TurnStats[] = [];\n /** Cost from prior runs of a resumed session, restored from session meta. */\n private _carryoverCost = 0;\n /** Turn count from prior runs of a resumed session. */\n private _carryoverTurns = 0;\n private _carryoverCacheHit = 0;\n private _carryoverCacheMiss = 0;\n /** Last turn's promptTokens before exit — surfaced via summary() until the next live turn lands. */\n private _carryoverLastPromptTokens = 0;\n\n /** Seed totals from a resumed session's persisted meta — only call once at construction. */\n seedCarryover(opts: {\n totalCostUsd?: number;\n turnCount?: number;\n cacheHitTokens?: number;\n cacheMissTokens?: number;\n lastPromptTokens?: number;\n }): void {\n if (typeof opts.totalCostUsd === \"number\" && opts.totalCostUsd > 0) {\n this._carryoverCost = opts.totalCostUsd;\n }\n if (typeof opts.turnCount === \"number\" && opts.turnCount > 0) {\n this._carryoverTurns = opts.turnCount;\n }\n if (typeof opts.cacheHitTokens === \"number\" && opts.cacheHitTokens > 0) {\n this._carryoverCacheHit = opts.cacheHitTokens;\n }\n if (typeof opts.cacheMissTokens === \"number\" && opts.cacheMissTokens > 0) {\n this._carryoverCacheMiss = opts.cacheMissTokens;\n }\n if (typeof opts.lastPromptTokens === \"number\" && opts.lastPromptTokens > 0) {\n this._carryoverLastPromptTokens = opts.lastPromptTokens;\n }\n }\n\n record(turn: number, model: string, usage: Usage): TurnStats {\n const cost = costUsd(model, usage);\n const stats: TurnStats = {\n turn,\n model,\n usage,\n cost,\n cacheHitRatio: usage.cacheHitRatio,\n };\n this.turns.push(stats);\n return stats;\n }\n\n get totalCost(): number {\n return this._carryoverCost + this.turns.reduce((sum, t) => sum + t.cost, 0);\n }\n\n get totalClaudeEquivalent(): number {\n return this.turns.reduce((sum, t) => sum + claudeEquivalentCost(t.usage), 0);\n }\n\n get savingsVsClaude(): number {\n const c = this.totalClaudeEquivalent;\n return c > 0 ? 1 - this.totalCost / c : 0;\n }\n\n get totalInputCost(): number {\n return this.turns.reduce((sum, t) => sum + inputCostUsd(t.model, t.usage), 0);\n }\n\n get totalOutputCost(): number {\n return this.turns.reduce((sum, t) => sum + outputCostUsd(t.model, t.usage), 0);\n }\n\n get aggregateCacheHitRatio(): number {\n let hit = this._carryoverCacheHit;\n let miss = this._carryoverCacheMiss;\n for (const t of this.turns) {\n hit += t.usage.promptCacheHitTokens;\n miss += t.usage.promptCacheMissTokens;\n }\n const denom = hit + miss;\n return denom > 0 ? hit / denom : 0;\n }\n\n summary(): SessionSummary {\n const last = this.turns[this.turns.length - 1];\n return {\n turns: this.turns.length + this._carryoverTurns,\n totalCostUsd: round(this.totalCost, 6),\n totalInputCostUsd: round(this.totalInputCost, 6),\n totalOutputCostUsd: round(this.totalOutputCost, 6),\n claudeEquivalentUsd: round(this.totalClaudeEquivalent, 6),\n savingsVsClaudePct: round(this.savingsVsClaude * 100, 2),\n cacheHitRatio: round(this.aggregateCacheHitRatio, 4),\n lastPromptTokens: last?.usage.promptTokens ?? this._carryoverLastPromptTokens,\n lastTurnCostUsd: round(last?.cost ?? 0, 6),\n };\n }\n}\n\nfunction round(n: number, digits: number): number {\n const f = 10 ** digits;\n return Math.round(n * f) / f;\n}\n"],"mappings":"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","names":[]}
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
2
3
  import {
3
4
  indexCompatible,
4
5
  querySemantic
5
- } from "./chunk-4H3ZRJ2U.js";
6
+ } from "./chunk-XCGGEJTI.js";
6
7
 
7
8
  // src/index/semantic/tool.ts
8
9
  async function registerSemanticSearchTool(registry, opts) {
@@ -91,4 +92,4 @@ export {
91
92
  registerSemanticSearchTool,
92
93
  bootstrapSemanticSearchInCodeMode
93
94
  };
94
- //# sourceMappingURL=chunk-RAUPWSYA.js.map
95
+ //# sourceMappingURL=chunk-YYQAUTTN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index/semantic/tool.ts"],"sourcesContent":["import type { ToolRegistry } from \"../../tools.js\";\nimport { indexCompatible, indexExists, querySemantic } from \"./builder.js\";\nimport type { SearchHit } from \"./store.js\";\n\ntype SemanticToolOptions = {\n provider?: \"ollama\" | \"openai-compat\";\n baseUrl?: string;\n apiKey?: string;\n model?: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n root: string;\n defaultTopK?: number;\n defaultMinScore?: number;\n};\n\nexport async function registerSemanticSearchTool(\n registry: ToolRegistry,\n opts: SemanticToolOptions,\n): Promise<boolean> {\n if (!(await indexCompatible(opts.root, { provider: opts.provider, model: opts.model })))\n return false;\n const defaultTopK = opts.defaultTopK ?? 8;\n const defaultMinScore = opts.defaultMinScore ?? 0.3;\n\n registry.register({\n name: \"semantic_search\",\n description:\n \"FIRST CHOICE for descriptive queries. Use this BEFORE search_content (grep) when the user describes WHAT code does ('where do we handle X', 'which file owns Y', 'how does Z work', 'find the logic that …'). Returns ranked snippets ordered by semantic relevance — finds the right file even when your description shares no words with the code. Falls back to search_content / search_files only for: exact identifiers, regex patterns, or counting occurrences of a known token. If your first instinct is grep on a paraphrased question, you are wrong — try semantic_search first.\",\n readOnly: true,\n parallelSafe: true,\n parameters: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description:\n \"Natural-language description, phrased as a question or noun phrase: 'where do we validate the session cookie?' / 'retry backoff logic' / 'code that prevents user changes from immediately landing on disk'. Do NOT pass exact identifiers — those are search_content's job.\",\n },\n topK: {\n type: \"integer\",\n description: `Number of snippets to return (1..16). Default ${defaultTopK}.`,\n },\n minScore: {\n type: \"number\",\n description: `Drop snippets with cosine score below this (0..1). Default ${defaultMinScore}. Raise for stricter matches; lower if the index is small.`,\n },\n },\n required: [\"query\"],\n },\n fn: async (args: { query: string; topK?: number; minScore?: number }, ctx) => {\n const hits = await querySemantic(opts.root, args.query, {\n topK: args.topK ?? defaultTopK,\n minScore: args.minScore ?? defaultMinScore,\n provider: opts.provider,\n baseUrl: opts.baseUrl,\n apiKey: opts.apiKey,\n model: opts.model,\n extraBody: opts.extraBody,\n signal: ctx?.signal,\n });\n if (hits === null) {\n return \"No semantic index found for this project. Run `reasonix index` to build one.\";\n }\n if (hits.length === 0) {\n return `query: ${args.query}\\n\\nno matches above the score threshold (${args.minScore ?? defaultMinScore}).`;\n }\n return formatHits(args.query, hits);\n },\n });\n return true;\n}\n\nexport function formatHits(query: string, hits: readonly SearchHit[]): string {\n const lines: string[] = [`query: ${query}`, `\\nresults (${hits.length}):`];\n hits.forEach((h, i) => {\n const { entry, score } = h;\n lines.push(\n `\\n${i + 1}. ${entry.path}:${entry.startLine}-${entry.endLine} (score ${score.toFixed(3)})`,\n );\n // Cap each snippet so a 60-line chunk doesn't dominate the\n // model's context. The full chunk is still discoverable via\n // read_file once the model picks the most relevant hit.\n const preview = entry.text.split(\"\\n\").slice(0, 8).join(\"\\n\");\n lines.push(indentBlock(preview, \" \"));\n if (entry.text.split(\"\\n\").length > 8) {\n lines.push(\n ` …(${entry.text.split(\"\\n\").length - 8} more lines — read_file ${entry.path}:${entry.startLine} for the full chunk)`,\n );\n }\n });\n return lines.join(\"\\n\");\n}\n\nfunction indentBlock(text: string, prefix: string): string {\n return text\n .split(\"\\n\")\n .map((l) => prefix + l)\n .join(\"\\n\");\n}\n\n/** Silent: register if index exists, else skip — no Ollama probe, no setup prompt. */\nexport async function bootstrapSemanticSearchInCodeMode(\n registry: ToolRegistry,\n rootDir: string,\n opts: Omit<SemanticToolOptions, \"root\" | \"defaultTopK\" | \"defaultMinScore\"> = {},\n): Promise<{ enabled: boolean }> {\n if (await indexCompatible(rootDir, { provider: opts.provider, model: opts.model })) {\n await registerSemanticSearchTool(registry, { ...opts, root: rootDir });\n return { enabled: true };\n }\n return { enabled: false };\n}\n"],"mappings":";;;;;;;AAgBA,eAAsB,2BACpB,UACA,MACkB;AAClB,MAAI,CAAE,MAAM,gBAAgB,KAAK,MAAM,EAAE,UAAU,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC;AACnF,WAAO;AACT,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,kBAAkB,KAAK,mBAAmB;AAEhD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aACE;AAAA,IACF,UAAU;AAAA,IACV,cAAc;AAAA,IACd,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,aAAa,iDAAiD,WAAW;AAAA,QAC3E;AAAA,QACA,UAAU;AAAA,UACR,MAAM;AAAA,UACN,aAAa,8DAA8D,eAAe;AAAA,QAC5F;AAAA,MACF;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,IACA,IAAI,OAAO,MAA2D,QAAQ;AAC5E,YAAM,OAAO,MAAM,cAAc,KAAK,MAAM,KAAK,OAAO;AAAA,QACtD,MAAM,KAAK,QAAQ;AAAA,QACnB,UAAU,KAAK,YAAY;AAAA,QAC3B,UAAU,KAAK;AAAA,QACf,SAAS,KAAK;AAAA,QACd,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,QAAQ,KAAK;AAAA,MACf,CAAC;AACD,UAAI,SAAS,MAAM;AACjB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,WAAW,GAAG;AACrB,eAAO,UAAU,KAAK,KAAK;AAAA;AAAA,wCAA6C,KAAK,YAAY,eAAe;AAAA,MAC1G;AACA,aAAO,WAAW,KAAK,OAAO,IAAI;AAAA,IACpC;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEO,SAAS,WAAW,OAAe,MAAoC;AAC5E,QAAM,QAAkB,CAAC,UAAU,KAAK,IAAI;AAAA,WAAc,KAAK,MAAM,IAAI;AACzE,OAAK,QAAQ,CAAC,GAAG,MAAM;AACrB,UAAM,EAAE,OAAO,MAAM,IAAI;AACzB,UAAM;AAAA,MACJ;AAAA,EAAK,IAAI,CAAC,KAAK,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI,MAAM,OAAO,YAAY,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC3F;AAIA,UAAM,UAAU,MAAM,KAAK,MAAM,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI;AAC5D,UAAM,KAAK,YAAY,SAAS,KAAK,CAAC;AACtC,QAAI,MAAM,KAAK,MAAM,IAAI,EAAE,SAAS,GAAG;AACrC,YAAM;AAAA,QACJ,aAAQ,MAAM,KAAK,MAAM,IAAI,EAAE,SAAS,CAAC,gCAA2B,MAAM,IAAI,IAAI,MAAM,SAAS;AAAA,MACnG;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,YAAY,MAAc,QAAwB;AACzD,SAAO,KACJ,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,SAAS,CAAC,EACrB,KAAK,IAAI;AACd;AAGA,eAAsB,kCACpB,UACA,SACA,OAA8E,CAAC,GAChD;AAC/B,MAAI,MAAM,gBAAgB,SAAS,EAAE,UAAU,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC,GAAG;AAClF,UAAM,2BAA2B,UAAU,EAAE,GAAG,MAAM,MAAM,QAAQ,CAAC;AACrE,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AACA,SAAO,EAAE,SAAS,MAAM;AAC1B;","names":[]}
1
+ {"version":3,"sources":["../../src/index/semantic/tool.ts"],"sourcesContent":["import type { ToolRegistry } from \"../../tools.js\";\nimport { indexCompatible, indexExists, querySemantic } from \"./builder.js\";\nimport type { SearchHit } from \"./store.js\";\n\ntype SemanticToolOptions = {\n provider?: \"ollama\" | \"openai-compat\";\n baseUrl?: string;\n apiKey?: string;\n model?: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n root: string;\n defaultTopK?: number;\n defaultMinScore?: number;\n};\n\nexport async function registerSemanticSearchTool(\n registry: ToolRegistry,\n opts: SemanticToolOptions,\n): Promise<boolean> {\n if (!(await indexCompatible(opts.root, { provider: opts.provider, model: opts.model })))\n return false;\n const defaultTopK = opts.defaultTopK ?? 8;\n const defaultMinScore = opts.defaultMinScore ?? 0.3;\n\n registry.register({\n name: \"semantic_search\",\n description:\n \"FIRST CHOICE for descriptive queries. Use this BEFORE search_content (grep) when the user describes WHAT code does ('where do we handle X', 'which file owns Y', 'how does Z work', 'find the logic that …'). Returns ranked snippets ordered by semantic relevance — finds the right file even when your description shares no words with the code. Falls back to search_content / search_files only for: exact identifiers, regex patterns, or counting occurrences of a known token. If your first instinct is grep on a paraphrased question, you are wrong — try semantic_search first.\",\n readOnly: true,\n parallelSafe: true,\n parameters: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description:\n \"Natural-language description, phrased as a question or noun phrase: 'where do we validate the session cookie?' / 'retry backoff logic' / 'code that prevents user changes from immediately landing on disk'. Do NOT pass exact identifiers — those are search_content's job.\",\n },\n topK: {\n type: \"integer\",\n description: `Number of snippets to return (1..16). Default ${defaultTopK}.`,\n },\n minScore: {\n type: \"number\",\n description: `Drop snippets with cosine score below this (0..1). Default ${defaultMinScore}. Raise for stricter matches; lower if the index is small.`,\n },\n },\n required: [\"query\"],\n },\n fn: async (args: { query: string; topK?: number; minScore?: number }, ctx) => {\n const hits = await querySemantic(opts.root, args.query, {\n topK: args.topK ?? defaultTopK,\n minScore: args.minScore ?? defaultMinScore,\n provider: opts.provider,\n baseUrl: opts.baseUrl,\n apiKey: opts.apiKey,\n model: opts.model,\n extraBody: opts.extraBody,\n signal: ctx?.signal,\n });\n if (hits === null) {\n return \"No semantic index found for this project. Run `reasonix index` to build one.\";\n }\n if (hits.length === 0) {\n return `query: ${args.query}\\n\\nno matches above the score threshold (${args.minScore ?? defaultMinScore}).`;\n }\n return formatHits(args.query, hits);\n },\n });\n return true;\n}\n\nexport function formatHits(query: string, hits: readonly SearchHit[]): string {\n const lines: string[] = [`query: ${query}`, `\\nresults (${hits.length}):`];\n hits.forEach((h, i) => {\n const { entry, score } = h;\n lines.push(\n `\\n${i + 1}. ${entry.path}:${entry.startLine}-${entry.endLine} (score ${score.toFixed(3)})`,\n );\n // Cap each snippet so a 60-line chunk doesn't dominate the\n // model's context. The full chunk is still discoverable via\n // read_file once the model picks the most relevant hit.\n const preview = entry.text.split(\"\\n\").slice(0, 8).join(\"\\n\");\n lines.push(indentBlock(preview, \" \"));\n if (entry.text.split(\"\\n\").length > 8) {\n lines.push(\n ` …(${entry.text.split(\"\\n\").length - 8} more lines — read_file ${entry.path}:${entry.startLine} for the full chunk)`,\n );\n }\n });\n return lines.join(\"\\n\");\n}\n\nfunction indentBlock(text: string, prefix: string): string {\n return text\n .split(\"\\n\")\n .map((l) => prefix + l)\n .join(\"\\n\");\n}\n\n/** Silent: register if index exists, else skip — no Ollama probe, no setup prompt. */\nexport async function bootstrapSemanticSearchInCodeMode(\n registry: ToolRegistry,\n rootDir: string,\n opts: Omit<SemanticToolOptions, \"root\" | \"defaultTopK\" | \"defaultMinScore\"> = {},\n): Promise<{ enabled: boolean }> {\n if (await indexCompatible(rootDir, { provider: opts.provider, model: opts.model })) {\n await registerSemanticSearchTool(registry, { ...opts, root: rootDir });\n return { enabled: true };\n }\n return { enabled: false };\n}\n"],"mappings":";;;;;;;;AAgBA,eAAsB,2BACpB,UACA,MACkB;AAClB,MAAI,CAAE,MAAM,gBAAgB,KAAK,MAAM,EAAE,UAAU,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC;AACnF,WAAO;AACT,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,kBAAkB,KAAK,mBAAmB;AAEhD,WAAS,SAAS;AAAA,IAChB,MAAM;AAAA,IACN,aACE;AAAA,IACF,UAAU;AAAA,IACV,cAAc;AAAA,IACd,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,aAAa,iDAAiD,WAAW;AAAA,QAC3E;AAAA,QACA,UAAU;AAAA,UACR,MAAM;AAAA,UACN,aAAa,8DAA8D,eAAe;AAAA,QAC5F;AAAA,MACF;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,IACA,IAAI,OAAO,MAA2D,QAAQ;AAC5E,YAAM,OAAO,MAAM,cAAc,KAAK,MAAM,KAAK,OAAO;AAAA,QACtD,MAAM,KAAK,QAAQ;AAAA,QACnB,UAAU,KAAK,YAAY;AAAA,QAC3B,UAAU,KAAK;AAAA,QACf,SAAS,KAAK;AAAA,QACd,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,QAAQ,KAAK;AAAA,MACf,CAAC;AACD,UAAI,SAAS,MAAM;AACjB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,WAAW,GAAG;AACrB,eAAO,UAAU,KAAK,KAAK;AAAA;AAAA,wCAA6C,KAAK,YAAY,eAAe;AAAA,MAC1G;AACA,aAAO,WAAW,KAAK,OAAO,IAAI;AAAA,IACpC;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEO,SAAS,WAAW,OAAe,MAAoC;AAC5E,QAAM,QAAkB,CAAC,UAAU,KAAK,IAAI;AAAA,WAAc,KAAK,MAAM,IAAI;AACzE,OAAK,QAAQ,CAAC,GAAG,MAAM;AACrB,UAAM,EAAE,OAAO,MAAM,IAAI;AACzB,UAAM;AAAA,MACJ;AAAA,EAAK,IAAI,CAAC,KAAK,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI,MAAM,OAAO,YAAY,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC3F;AAIA,UAAM,UAAU,MAAM,KAAK,MAAM,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI;AAC5D,UAAM,KAAK,YAAY,SAAS,KAAK,CAAC;AACtC,QAAI,MAAM,KAAK,MAAM,IAAI,EAAE,SAAS,GAAG;AACrC,YAAM;AAAA,QACJ,aAAQ,MAAM,KAAK,MAAM,IAAI,EAAE,SAAS,CAAC,gCAA2B,MAAM,IAAI,IAAI,MAAM,SAAS;AAAA,MACnG;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,YAAY,MAAc,QAAwB;AACzD,SAAO,KACJ,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,SAAS,CAAC,EACrB,KAAK,IAAI;AACd;AAGA,eAAsB,kCACpB,UACA,SACA,OAA8E,CAAC,GAChD;AAC/B,MAAI,MAAM,gBAAgB,SAAS,EAAE,UAAU,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC,GAAG;AAClF,UAAM,2BAA2B,UAAU,EAAE,GAAG,MAAM,MAAM,QAAQ,CAAC;AACrE,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AACA,SAAO,EAAE,SAAS,MAAM;AAC1B;","names":[]}
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+
4
+ // src/cli/cpu-prof.ts
5
+ import { writeFileSync } from "fs";
6
+ import { Session } from "inspector/promises";
7
+ import { resolve } from "path";
8
+ import { gzipSync } from "zlib";
9
+ var session = null;
10
+ var outPath = null;
11
+ var signalHandlerInstalled = false;
12
+ var stopping = false;
13
+ function defaultOutPath() {
14
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("Z", "");
15
+ return resolve(process.cwd(), `reasonix-cpu-${stamp}.cpuprofile`);
16
+ }
17
+ async function startCpuProfile(pathArg) {
18
+ if (session) return outPath ?? defaultOutPath();
19
+ outPath = typeof pathArg === "string" ? resolve(pathArg) : defaultOutPath();
20
+ session = new Session();
21
+ session.connect();
22
+ await session.post("Profiler.enable");
23
+ await session.post("Profiler.start");
24
+ process.stderr.write(`\u25B8 cpu profile recording \u2014 will save to ${outPath} on exit
25
+ `);
26
+ installSignalHandler();
27
+ return outPath;
28
+ }
29
+ async function stopAndSaveCpuProfile() {
30
+ if (!session || !outPath || stopping) return;
31
+ stopping = true;
32
+ const s = session;
33
+ const baseOut = outPath;
34
+ session = null;
35
+ try {
36
+ const { profile } = await s.post("Profiler.stop");
37
+ const json = JSON.stringify(profile);
38
+ const gz = gzipSync(json);
39
+ const gzPath = `${baseOut}.gz`;
40
+ writeFileSync(gzPath, gz);
41
+ const mb = (gz.length / (1024 * 1024)).toFixed(2);
42
+ process.stderr.write(
43
+ `\u25B8 cpu profile saved \u2192 ${gzPath} (${mb} MB gzipped)
44
+ drag into a GitHub issue comment, or:
45
+ gh issue comment <N> --repo esengine/DeepSeek-Reasonix -F "${gzPath}"
46
+ `
47
+ );
48
+ } catch (e) {
49
+ process.stderr.write(`\u25B2 cpu profile save failed: ${e.message}
50
+ `);
51
+ } finally {
52
+ try {
53
+ s.disconnect();
54
+ } catch {
55
+ }
56
+ }
57
+ }
58
+ function installSignalHandler() {
59
+ if (signalHandlerInstalled) return;
60
+ signalHandlerInstalled = true;
61
+ for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) {
62
+ process.on(sig, () => {
63
+ void (async () => {
64
+ await stopAndSaveCpuProfile();
65
+ process.exit(sig === "SIGINT" ? 130 : 0);
66
+ })();
67
+ });
68
+ }
69
+ }
70
+
71
+ // src/cli/startup-profile.ts
72
+ import { performance } from "perf_hooks";
73
+ var marks = [];
74
+ var dumped = false;
75
+ function envFlag() {
76
+ const v = process.env.REASONIX_PROFILE_STARTUP;
77
+ return v === "1" || v === "true" || v === "yes";
78
+ }
79
+ function markPhase(name) {
80
+ if (!envFlag()) return;
81
+ marks.push({ name, t: performance.now() });
82
+ }
83
+ function dumpStartupProfile(stream = process.stderr) {
84
+ if (!envFlag() || dumped || marks.length === 0) return;
85
+ dumped = true;
86
+ const totalMs = marks[marks.length - 1].t;
87
+ const widest = String(Math.round(totalMs)).length;
88
+ const lines = ["[startup-profile]"];
89
+ let prev = 0;
90
+ for (const m of marks) {
91
+ const cum = Math.round(m.t).toString().padStart(widest);
92
+ const delta = Math.round(m.t - prev);
93
+ lines.push(` ${cum}ms ${m.name.padEnd(28)} (+${delta})`);
94
+ prev = m.t;
95
+ }
96
+ lines.push(
97
+ `\u2500\u2500\u2500 ${Math.round(totalMs)}ms total \xB7 last phase ${marks[marks.length - 1].name} \xB7 set REASONIX_PROFILE_STARTUP=0 to silence`
98
+ );
99
+ stream.write(`${lines.join("\n")}
100
+ `);
101
+ }
102
+
103
+ export {
104
+ startCpuProfile,
105
+ stopAndSaveCpuProfile,
106
+ markPhase,
107
+ dumpStartupProfile
108
+ };
109
+ //# sourceMappingURL=chunk-ZZM6QJ4W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/cpu-prof.ts","../../src/cli/startup-profile.ts"],"sourcesContent":["import { writeFileSync } from \"node:fs\";\nimport { Session } from \"node:inspector/promises\";\nimport { resolve } from \"node:path\";\nimport { gzipSync } from \"node:zlib\";\n\nlet session: Session | null = null;\nlet outPath: string | null = null;\nlet signalHandlerInstalled = false;\nlet stopping = false;\n\nfunction defaultOutPath(): string {\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\").replace(\"Z\", \"\");\n return resolve(process.cwd(), `reasonix-cpu-${stamp}.cpuprofile`);\n}\n\nexport async function startCpuProfile(pathArg?: string | true): Promise<string> {\n if (session) return outPath ?? defaultOutPath();\n outPath = typeof pathArg === \"string\" ? resolve(pathArg) : defaultOutPath();\n session = new Session();\n session.connect();\n await session.post(\"Profiler.enable\");\n await session.post(\"Profiler.start\");\n process.stderr.write(`▸ cpu profile recording — will save to ${outPath} on exit\\n`);\n installSignalHandler();\n return outPath;\n}\n\nexport async function stopAndSaveCpuProfile(): Promise<void> {\n if (!session || !outPath || stopping) return;\n stopping = true;\n const s = session;\n const baseOut = outPath;\n session = null;\n try {\n const { profile } = (await s.post(\"Profiler.stop\")) as { profile: unknown };\n const json = JSON.stringify(profile);\n const gz = gzipSync(json);\n const gzPath = `${baseOut}.gz`;\n writeFileSync(gzPath, gz);\n const mb = (gz.length / (1024 * 1024)).toFixed(2);\n process.stderr.write(\n `▸ cpu profile saved → ${gzPath} (${mb} MB gzipped)\\n drag into a GitHub issue comment, or:\\n gh issue comment <N> --repo esengine/DeepSeek-Reasonix -F \"${gzPath}\"\\n`,\n );\n } catch (e) {\n process.stderr.write(`▲ cpu profile save failed: ${(e as Error).message}\\n`);\n } finally {\n try {\n s.disconnect();\n } catch {\n /* ignore */\n }\n }\n}\n\nfunction installSignalHandler(): void {\n if (signalHandlerInstalled) return;\n signalHandlerInstalled = true;\n for (const sig of [\"SIGINT\", \"SIGTERM\", \"SIGHUP\"] as const) {\n process.on(sig, () => {\n void (async () => {\n await stopAndSaveCpuProfile();\n process.exit(sig === \"SIGINT\" ? 130 : 0);\n })();\n });\n }\n}\n","import { performance } from \"node:perf_hooks\";\n\ninterface PhaseMark {\n name: string;\n t: number;\n}\n\nconst marks: PhaseMark[] = [];\nlet dumped = false;\n\nfunction envFlag(): boolean {\n const v = process.env.REASONIX_PROFILE_STARTUP;\n return v === \"1\" || v === \"true\" || v === \"yes\";\n}\n\nexport function isStartupProfileEnabled(): boolean {\n return envFlag();\n}\n\nexport function markPhase(name: string): void {\n if (!envFlag()) return;\n marks.push({ name, t: performance.now() });\n}\n\nexport function dumpStartupProfile(stream: NodeJS.WriteStream = process.stderr): void {\n if (!envFlag() || dumped || marks.length === 0) return;\n dumped = true;\n const totalMs = marks[marks.length - 1]!.t;\n const widest = String(Math.round(totalMs)).length;\n const lines: string[] = [\"[startup-profile]\"];\n let prev = 0;\n for (const m of marks) {\n const cum = Math.round(m.t).toString().padStart(widest);\n const delta = Math.round(m.t - prev);\n lines.push(` ${cum}ms ${m.name.padEnd(28)} (+${delta})`);\n prev = m.t;\n }\n lines.push(\n `─── ${Math.round(totalMs)}ms total · last phase ${marks[marks.length - 1]!.name} · set REASONIX_PROFILE_STARTUP=0 to silence`,\n );\n stream.write(`${lines.join(\"\\n\")}\\n`);\n}\n\nexport function _resetForTests(): void {\n marks.length = 0;\n dumped = false;\n}\n"],"mappings":"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","names":[]}
@@ -1,74 +1,82 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- buildCodeToolset
4
- } from "./chunk-AT6GGIBV.js";
5
- import "./chunk-RAUPWSYA.js";
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
6
3
  import {
7
4
  chatCommand
8
- } from "./chunk-F2AV2QDK.js";
9
- import "./chunk-LN27AKV3.js";
10
- import "./chunk-Y5XNV3NX.js";
11
- import "./chunk-SXLJBFIV.js";
12
- import "./chunk-A7VHMMDE.js";
13
- import "./chunk-LTXADNCO.js";
14
- import "./chunk-BOFL3T45.js";
5
+ } from "./chunk-P7EKE5ZQ.js";
6
+ import "./chunk-2Z35JOA4.js";
7
+ import "./chunk-JMBMLOBP.js";
8
+ import "./chunk-3Z6IBU3D.js";
9
+ import {
10
+ buildCodeToolset
11
+ } from "./chunk-YFGF5NKA.js";
12
+ import "./chunk-45U62RI3.js";
13
+ import "./chunk-H6PS7IUE.js";
14
+ import "./chunk-PQXPXJBJ.js";
15
15
  import {
16
16
  markPhase
17
- } from "./chunk-CPOV2O73.js";
18
- import "./chunk-IEA6JOIP.js";
19
- import "./chunk-VFG4GIT3.js";
20
- import "./chunk-7SPOFTMT.js";
21
- import "./chunk-CFY2XLY6.js";
22
- import "./chunk-ARF3N2SY.js";
23
- import "./chunk-4W2CICFQ.js";
24
- import "./chunk-UV7XJUJH.js";
25
- import "./chunk-E46ECXJD.js";
26
- import "./chunk-KZYLMMU5.js";
27
- import "./chunk-AFFZF3MW.js";
28
- import "./chunk-DAEAAVDF.js";
29
- import "./chunk-H4OLWRSX.js";
17
+ } from "./chunk-ZZM6QJ4W.js";
18
+ import "./chunk-2R4QCDOZ.js";
19
+ import "./chunk-F3PXYSNN.js";
20
+ import "./chunk-FHOGSSCH.js";
21
+ import "./chunk-6AK4EY3D.js";
22
+ import "./chunk-5JJRUIPA.js";
23
+ import "./chunk-6PZ3CXBP.js";
24
+ import "./chunk-TJX6BFZZ.js";
25
+ import "./chunk-6G3CUUFG.js";
26
+ import {
27
+ resolvePreset
28
+ } from "./chunk-2425HK6U.js";
29
+ import "./chunk-VK5HG73G.js";
30
+ import "./chunk-74EX7SUH.js";
31
+ import "./chunk-PV55UMTO.js";
32
+ import "./chunk-2KDUS647.js";
33
+ import "./chunk-25T6CVUP.js";
30
34
  import {
31
35
  loadDotenv
32
- } from "./chunk-3Q3C4W66.js";
33
- import "./chunk-4DCHFFEY.js";
34
- import "./chunk-WJ3YX4PZ.js";
35
- import "./chunk-A3LL4XDV.js";
36
- import "./chunk-SOZE7V7V.js";
37
- import "./chunk-7VFNPMKG.js";
38
- import "./chunk-BYZGO3BX.js";
36
+ } from "./chunk-2UQP6H6T.js";
37
+ import "./chunk-OSZC7C6F.js";
38
+ import "./chunk-SZ5XES2N.js";
39
+ import "./chunk-3BXRZFWS.js";
40
+ import "./chunk-4QUNBQQ2.js";
41
+ import "./chunk-XJXDHAES.js";
42
+ import "./chunk-YYQAUTTN.js";
43
+ import "./chunk-O52OLQL3.js";
39
44
  import {
40
45
  detectForeignAgentPlatform
41
- } from "./chunk-CD4SCQL4.js";
42
- import "./chunk-FM57FNPJ.js";
43
- import "./chunk-2CXPDAWX.js";
44
- import "./chunk-4H3ZRJ2U.js";
45
- import "./chunk-WE3YZULK.js";
46
- import "./chunk-5X7LZJDE.js";
46
+ } from "./chunk-2K65GZBT.js";
47
+ import "./chunk-PLHAZOLZ.js";
48
+ import "./chunk-DOYHN4KB.js";
49
+ import "./chunk-XCGGEJTI.js";
50
+ import "./chunk-7O5ALB4C.js";
51
+ import "./chunk-S4XVGLRW.js";
47
52
  import {
48
53
  sanitizeName
49
- } from "./chunk-YJFKFTAL.js";
54
+ } from "./chunk-6PBZN4VI.js";
50
55
  import {
51
56
  t
52
- } from "./chunk-MHGPBJ2T.js";
57
+ } from "./chunk-RE4RAVFF.js";
53
58
  import {
54
59
  loadApiKey,
60
+ loadPreset,
55
61
  readConfig
56
- } from "./chunk-65Q5HQ26.js";
57
- import "./chunk-ZTLZO42A.js";
58
- import "./chunk-ORM6PK57.js";
59
- import "./chunk-CRPQUBP6.js";
62
+ } from "./chunk-XPDVG52A.js";
63
+ import "./chunk-HFEAY5DT.js";
64
+ import "./chunk-YQ6NTIIE.js";
65
+ import "./chunk-XXC2BYTV.js";
66
+ import "./chunk-TUK7OWJA.js";
60
67
 
61
68
  // src/cli/commands/code.tsx
62
69
  import { readFileSync } from "fs";
63
70
  import { basename, resolve } from "path";
64
71
  async function codeCommand(opts = {}) {
65
72
  markPhase("code_command_enter");
73
+ const resolvedModel = opts.model ?? resolvePreset(loadPreset()).model;
66
74
  loadDotenv();
67
75
  const cfgKey = loadApiKey();
68
76
  if (cfgKey && !process.env.DEEPSEEK_API_KEY) {
69
77
  process.env.DEEPSEEK_API_KEY = cfgKey;
70
78
  }
71
- const { codeSystemPrompt } = await import("./prompt-RSIHN62V.js");
79
+ const { codeSystemPrompt } = await import("./prompt-UW6EFLVR.js");
72
80
  const rootDir = resolve(opts.dir ?? process.cwd());
73
81
  const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
74
82
  markPhase("semantic_bootstrap_start");
@@ -89,17 +97,14 @@ async function codeCommand(opts = {}) {
89
97
  );
90
98
  const foreign = detectForeignAgentPlatform(rootDir);
91
99
  if (foreign) {
92
- process.stderr.write(
93
- `\u26A0 workspace contains another agent platform's files (${foreign.join(", ")}). Reasonix Code may read them as project content; relaunch with --dir <your-project> if that's not what you want.
94
- `
95
- );
100
+ process.stderr.write(t("code.workspaceConflict", { platforms: foreign.join(", ") }));
96
101
  }
97
102
  process.once("exit", () => {
98
103
  void jobs.shutdown();
99
104
  });
100
105
  let systemAppendFileContents;
101
106
  if (opts.systemAppend !== void 0 && opts.systemAppend.trim().length === 0) {
102
- process.stderr.write("--system-append is empty \u2014 no prompt text will be appended\n");
107
+ process.stderr.write(t("code.systemAppendEmpty"));
103
108
  }
104
109
  if (opts.systemAppendFile) {
105
110
  const filePath = resolve(opts.systemAppendFile);
@@ -107,10 +112,8 @@ async function codeCommand(opts = {}) {
107
112
  systemAppendFileContents = readFileSync(filePath, "utf8");
108
113
  } catch (err) {
109
114
  const e = err;
110
- process.stderr.write(
111
- `Error: cannot read --system-append-file "${filePath}": ${e.code ? `[${e.code}] ` : ""}${e.message}
112
- `
113
- );
115
+ const errorDetails = e.code ? `[${e.code}] ${e.message}` : e.message;
116
+ process.stderr.write(t("code.systemAppendFileReadError", { filePath, errorDetails }));
114
117
  process.exit(1);
115
118
  }
116
119
  }
@@ -118,10 +121,10 @@ async function codeCommand(opts = {}) {
118
121
  hasSemanticSearch: semantic.enabled,
119
122
  systemAppend: opts.systemAppend,
120
123
  systemAppendFile: systemAppendFileContents,
121
- modelId: opts.model ?? "deepseek-v4-flash"
124
+ modelId: resolvedModel
122
125
  });
123
126
  await chatCommand({
124
- model: opts.model ?? "deepseek-v4-flash",
127
+ model: resolvedModel,
125
128
  budgetUsd: opts.budgetUsd,
126
129
  failureThreshold: opts.failureThreshold,
127
130
  system: codeRebuildSystem(),
@@ -139,6 +142,7 @@ async function codeCommand(opts = {}) {
139
142
  forceResume: opts.forceResume,
140
143
  forceNew: opts.forceNew,
141
144
  noDashboard: opts.noDashboard,
145
+ openDashboard: opts.openDashboard,
142
146
  dashboardPort: opts.dashboardPort,
143
147
  altScreen: opts.altScreen,
144
148
  mouse: opts.mouse
@@ -147,4 +151,4 @@ async function codeCommand(opts = {}) {
147
151
  export {
148
152
  codeCommand
149
153
  };
150
- //# sourceMappingURL=code-X3M6ENTQ.js.map
154
+ //# sourceMappingURL=code-SMKEW6CD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/code.tsx"],"sourcesContent":["/**\n * `reasonix code [dir]` — opinionated wrapper around `reasonix chat` for\n * code-editing workflows.\n *\n * What it does differently from plain chat:\n * - Registers native filesystem tools rooted at the given directory\n * (CWD by default). No subprocess, no `npx install` step, R1-\n * friendly schemas. Replaced the old `@modelcontextprotocol/server-filesystem`\n * subprocess in 0.4.9 because its `edit_file` argv shape was the\n * biggest driver of R1 DSML hallucinations.\n * - Uses a coding-focused system prompt (src/code/prompt.ts) that\n * teaches the model to propose edits as SEARCH/REPLACE blocks.\n * - Defaults to the `smart` preset (reasoner + harvest) because\n * coding tasks pay back R1 thinking.\n * - Scopes its session to the directory so projects don't share\n * conversation history.\n * - Hooks `codeMode` into the TUI so assistant replies get parsed\n * for SEARCH/REPLACE blocks and applied on disk after each turn.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { buildCodeToolset } from \"../../code/setup.js\";\nimport { loadApiKey, loadPreset, readConfig } from \"../../config.js\";\nimport { loadDotenv } from \"../../env.js\";\nimport { t } from \"../../i18n/index.js\";\nimport { detectForeignAgentPlatform } from \"../../memory/project.js\";\nimport { sanitizeName } from \"../../memory/session.js\";\nimport { markPhase } from \"../startup-profile.js\";\nimport { resolvePreset } from \"../ui/presets.js\";\nimport { chatCommand } from \"./chat.js\";\n\nexport interface CodeOptions {\n /** Directory to root the filesystem tools at. Defaults to process.cwd(). */\n dir?: string;\n /** Override the default `smart` model. */\n model?: string;\n /** Disable session persistence. */\n noSession?: boolean;\n /** Transcript file for replay/diff. */\n transcript?: string;\n /** Skip the session picker — always resume prior messages. */\n forceResume?: boolean;\n /** Skip the session picker — always wipe prior messages and start fresh. */\n forceNew?: boolean;\n /**\n * Soft USD spend cap. Off by default. Same semantics as `chat`:\n * warns at 80%, refuses next turn at 100%. Mid-session adjustable\n * via `/budget <usd>` slash command.\n */\n budgetUsd?: number;\n /** Per-turn repair-signal count required to escalate flash→pro. Undefined → loop default (3). */\n failureThreshold?: number;\n /** Suppress the auto-launched embedded web dashboard. */\n noDashboard?: boolean;\n /** When true and the dashboard is enabled, open its URL in the system default browser as soon as the server is ready. */\n openDashboard?: boolean;\n /** Pin the dashboard to a fixed port. `undefined` keeps ephemeral assignment. */\n dashboardPort?: number;\n /** Inline string appended to the code system prompt after the generated base prompt. */\n systemAppend?: string;\n /** Path to a UTF-8 text file whose contents are appended to the code system prompt. */\n systemAppendFile?: string;\n /** Default true. Pass false (CLI: `--no-alt-screen`) to keep chat output in shell scrollback. */\n altScreen?: boolean;\n /** Default true. Pass false (CLI: `--no-mouse`) to keep terminal-native drag-select unmodified. */\n mouse?: boolean;\n}\n\nexport async function codeCommand(opts: CodeOptions = {}): Promise<void> {\n markPhase(\"code_command_enter\");\n const resolvedModel = opts.model ?? resolvePreset(loadPreset()).model;\n // Bridge .env + ~/.reasonix/config.json into process.env so buildCodeToolset's\n // eager DeepSeekClient constructions (subagent client; semantic embedder) can\n // pick up a key the user already configured via `reasonix setup`. chatCommand\n // does the same dance — code.tsx wraps chatCommand but must also seed env\n // before buildCodeToolset runs, which is BEFORE chatCommand.\n loadDotenv();\n const cfgKey = loadApiKey();\n if (cfgKey && !process.env.DEEPSEEK_API_KEY) {\n process.env.DEEPSEEK_API_KEY = cfgKey;\n }\n const { codeSystemPrompt } = await import(\"../../code/prompt.js\");\n const rootDir = resolve(opts.dir ?? process.cwd());\n // Per-directory session so switching projects doesn't mix histories.\n // `code-<sanitized-basename>` fits the session name rules without\n // truncating most project names.\n const session = opts.noSession ? undefined : `code-${sanitizeName(basename(rootDir))}`;\n\n markPhase(\"semantic_bootstrap_start\");\n const { tools, jobs, registerRooted, reBootstrapSemantic, semantic } = await buildCodeToolset({\n rootDir,\n });\n markPhase(\n semantic.enabled ? \"semantic_bootstrap_done_enabled\" : \"semantic_bootstrap_done_skipped\",\n );\n\n process.stderr.write(\n `${t(\"startup.codeRooted\", {\n rootDir,\n session: session ?? t(\"startup.ephemeral\"),\n tools: tools.size,\n semantic: semantic.enabled ? t(\"startup.semanticOn\") : \"\",\n })}\\n`,\n );\n\n const foreign = detectForeignAgentPlatform(rootDir);\n if (foreign) {\n process.stderr.write(t(\"code.workspaceConflict\", { platforms: foreign.join(\", \") }));\n }\n\n // Belt-and-suspenders cleanup: even though spawn(detached:false)\n // should tie child processes to the parent's lifetime, Windows cmd.exe\n // wrappers occasionally leak. We DON'T install SIGINT/SIGTERM\n // handlers here — that overrode Node's default \"exit on Ctrl+C\" with\n // a silent no-op, which made Ctrl+C feel broken in the TUI. App.tsx\n // owns the SIGINT path now (it shows the quit-armed banner and calls\n // exit() on confirmation); this 'exit' hook just guarantees the job\n // registry is drained on the way out, regardless of which exit path\n // fired.\n process.once(\"exit\", () => {\n void jobs.shutdown();\n });\n\n let systemAppendFileContents: string | undefined;\n if (opts.systemAppend !== undefined && opts.systemAppend.trim().length === 0) {\n process.stderr.write(t(\"code.systemAppendEmpty\"));\n }\n if (opts.systemAppendFile) {\n const filePath = resolve(opts.systemAppendFile);\n try {\n systemAppendFileContents = readFileSync(filePath, \"utf8\");\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n const errorDetails = e.code ? `[${e.code}] ${e.message}` : e.message;\n process.stderr.write(t(\"code.systemAppendFileReadError\", { filePath, errorDetails }));\n process.exit(1);\n }\n }\n\n const codeRebuildSystem = () =>\n codeSystemPrompt(rootDir, {\n hasSemanticSearch: semantic.enabled,\n systemAppend: opts.systemAppend,\n systemAppendFile: systemAppendFileContents,\n modelId: resolvedModel,\n });\n await chatCommand({\n model: resolvedModel,\n budgetUsd: opts.budgetUsd,\n failureThreshold: opts.failureThreshold,\n system: codeRebuildSystem(),\n rebuildSystem: codeRebuildSystem,\n transcript: opts.transcript,\n session,\n seedTools: tools,\n codeMode: {\n rootDir,\n jobs,\n reregisterTools: registerRooted,\n reBootstrapSemantic,\n },\n mcp: readConfig().mcp,\n forceResume: opts.forceResume,\n forceNew: opts.forceNew,\n noDashboard: opts.noDashboard,\n openDashboard: opts.openDashboard,\n dashboardPort: opts.dashboardPort,\n altScreen: opts.altScreen,\n mouse: opts.mouse,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,eAAe;AAgDlC,eAAsB,YAAY,OAAoB,CAAC,GAAkB;AACvE,YAAU,oBAAoB;AAC9B,QAAM,gBAAgB,KAAK,SAAS,cAAc,WAAW,CAAC,EAAE;AAMhE,aAAW;AACX,QAAM,SAAS,WAAW;AAC1B,MAAI,UAAU,CAAC,QAAQ,IAAI,kBAAkB;AAC3C,YAAQ,IAAI,mBAAmB;AAAA,EACjC;AACA,QAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,sBAAsB;AAChE,QAAM,UAAU,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC;AAIjD,QAAM,UAAU,KAAK,YAAY,SAAY,QAAQ,aAAa,SAAS,OAAO,CAAC,CAAC;AAEpF,YAAU,0BAA0B;AACpC,QAAM,EAAE,OAAO,MAAM,gBAAgB,qBAAqB,SAAS,IAAI,MAAM,iBAAiB;AAAA,IAC5F;AAAA,EACF,CAAC;AACD;AAAA,IACE,SAAS,UAAU,oCAAoC;AAAA,EACzD;AAEA,UAAQ,OAAO;AAAA,IACb,GAAG,EAAE,sBAAsB;AAAA,MACzB;AAAA,MACA,SAAS,WAAW,EAAE,mBAAmB;AAAA,MACzC,OAAO,MAAM;AAAA,MACb,UAAU,SAAS,UAAU,EAAE,oBAAoB,IAAI;AAAA,IACzD,CAAC,CAAC;AAAA;AAAA,EACJ;AAEA,QAAM,UAAU,2BAA2B,OAAO;AAClD,MAAI,SAAS;AACX,YAAQ,OAAO,MAAM,EAAE,0BAA0B,EAAE,WAAW,QAAQ,KAAK,IAAI,EAAE,CAAC,CAAC;AAAA,EACrF;AAWA,UAAQ,KAAK,QAAQ,MAAM;AACzB,SAAK,KAAK,SAAS;AAAA,EACrB,CAAC;AAED,MAAI;AACJ,MAAI,KAAK,iBAAiB,UAAa,KAAK,aAAa,KAAK,EAAE,WAAW,GAAG;AAC5E,YAAQ,OAAO,MAAM,EAAE,wBAAwB,CAAC;AAAA,EAClD;AACA,MAAI,KAAK,kBAAkB;AACzB,UAAM,WAAW,QAAQ,KAAK,gBAAgB;AAC9C,QAAI;AACF,iCAA2B,aAAa,UAAU,MAAM;AAAA,IAC1D,SAAS,KAAK;AACZ,YAAM,IAAI;AACV,YAAM,eAAe,EAAE,OAAO,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,KAAK,EAAE;AAC7D,cAAQ,OAAO,MAAM,EAAE,kCAAkC,EAAE,UAAU,aAAa,CAAC,CAAC;AACpF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,oBAAoB,MACxB,iBAAiB,SAAS;AAAA,IACxB,mBAAmB,SAAS;AAAA,IAC5B,cAAc,KAAK;AAAA,IACnB,kBAAkB;AAAA,IAClB,SAAS;AAAA,EACX,CAAC;AACH,QAAM,YAAY;AAAA,IAChB,OAAO;AAAA,IACP,WAAW,KAAK;AAAA,IAChB,kBAAkB,KAAK;AAAA,IACvB,QAAQ,kBAAkB;AAAA,IAC1B,eAAe;AAAA,IACf,YAAY,KAAK;AAAA,IACjB;AAAA,IACA,WAAW;AAAA,IACX,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB;AAAA,IACF;AAAA,IACA,KAAK,WAAW,EAAE;AAAA,IAClB,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,IACf,aAAa,KAAK;AAAA,IAClB,eAAe,KAAK;AAAA,IACpB,eAAe,KAAK;AAAA,IACpB,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,EACd,CAAC;AACH;","names":[]}
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
2
3
  import {
3
4
  checkOllamaStatus,
4
5
  pullOllamaModel,
5
6
  startOllamaDaemon
6
- } from "./chunk-2CXPDAWX.js";
7
+ } from "./chunk-DOYHN4KB.js";
7
8
  import {
8
9
  buildIndex
9
- } from "./chunk-4H3ZRJ2U.js";
10
- import "./chunk-5X7LZJDE.js";
10
+ } from "./chunk-XCGGEJTI.js";
11
+ import "./chunk-S4XVGLRW.js";
11
12
  import {
12
13
  loadIndexConfig,
13
14
  resolveSemanticEmbeddingConfig
14
- } from "./chunk-65Q5HQ26.js";
15
+ } from "./chunk-XPDVG52A.js";
16
+ import "./chunk-TUK7OWJA.js";
15
17
 
16
18
  // src/cli/commands/index.ts
17
19
  import { resolve } from "path";
@@ -351,4 +353,4 @@ function makeTtyWriter() {
351
353
  export {
352
354
  indexCommand
353
355
  };
354
- //# sourceMappingURL=commands-QY7MSQG7.js.map
356
+ //# sourceMappingURL=commands-FVVB5FZF.js.map