sparkecoder 0.1.22 → 0.1.23

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 (290) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +1308 -212
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +1933 -454
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +20 -3
  7. package/dist/db/index.js +97 -0
  8. package/dist/db/index.js.map +1 -1
  9. package/dist/{index-CNwLFGiZ.d.ts → index-BblbmG_0.d.ts} +19 -4
  10. package/dist/index.d.ts +6 -6
  11. package/dist/index.js +1913 -434
  12. package/dist/index.js.map +1 -1
  13. package/dist/{schema-Df7MU3nM.d.ts → schema-D_8A4k01.d.ts} +246 -2
  14. package/dist/search-ybREg7F_.d.ts +254 -0
  15. package/dist/server/index.js +1918 -439
  16. package/dist/server/index.js.map +1 -1
  17. package/dist/tools/index.d.ts +7 -56
  18. package/dist/tools/index.js +894 -27
  19. package/dist/tools/index.js.map +1 -1
  20. package/package.json +5 -1
  21. package/web/.next/BUILD_ID +1 -1
  22. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  23. package/web/.next/standalone/web/.next/app-path-routes-manifest.json +4 -0
  24. package/web/.next/standalone/web/.next/build-manifest.json +7 -6
  25. package/web/.next/standalone/web/.next/prerender-manifest.json +99 -3
  26. package/web/.next/standalone/web/.next/required-server-files.json +28 -4
  27. package/web/.next/standalone/web/.next/routes-manifest.json +24 -0
  28. package/web/.next/standalone/web/.next/server/app/(main)/page/build-manifest.json +5 -4
  29. package/web/.next/standalone/web/.next/server/app/(main)/page.js +2 -2
  30. package/web/.next/standalone/web/.next/server/app/(main)/page.js.nft.json +1 -1
  31. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  32. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page/build-manifest.json +5 -4
  33. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js +2 -2
  34. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  35. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_global-error/page/build-manifest.json +5 -4
  37. package/web/.next/standalone/web/.next/server/app/_global-error/page.js +2 -2
  38. package/web/.next/standalone/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  41. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/_not-found/page/build-manifest.json +5 -4
  48. package/web/.next/standalone/web/.next/server/app/_not-found/page.js +2 -2
  49. package/web/.next/standalone/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  50. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  51. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  52. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  53. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  54. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  56. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
  60. package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/installation/page/app-paths-manifest.json +3 -0
  62. package/web/.next/standalone/web/.next/server/app/docs/installation/page/build-manifest.json +18 -0
  63. package/web/.next/standalone/web/.next/server/app/docs/installation/page/next-font-manifest.json +11 -0
  64. package/web/.next/standalone/web/.next/server/app/docs/installation/page/react-loadable-manifest.json +1 -0
  65. package/web/.next/standalone/web/.next/server/app/docs/installation/page/server-reference-manifest.json +4 -0
  66. package/web/.next/standalone/web/.next/server/app/docs/installation/page.js +21 -0
  67. package/web/.next/standalone/web/.next/server/app/docs/installation/page.js.map +5 -0
  68. package/web/.next/standalone/web/.next/server/app/docs/installation/page.js.nft.json +1 -0
  69. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +2 -0
  70. package/web/.next/standalone/web/.next/server/app/docs/installation.html +86 -0
  71. package/web/.next/standalone/web/.next/server/app/docs/installation.meta +16 -0
  72. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +36 -0
  73. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +36 -0
  74. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +6 -0
  75. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +7 -0
  76. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +3 -0
  77. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +22 -0
  78. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +4 -0
  79. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +5 -0
  80. package/web/.next/standalone/web/.next/server/app/docs/page/app-paths-manifest.json +3 -0
  81. package/web/.next/standalone/web/.next/server/app/docs/page/build-manifest.json +18 -0
  82. package/web/.next/standalone/web/.next/server/app/docs/page/next-font-manifest.json +11 -0
  83. package/web/.next/standalone/web/.next/server/app/docs/page/react-loadable-manifest.json +1 -0
  84. package/web/.next/standalone/web/.next/server/app/docs/page/server-reference-manifest.json +4 -0
  85. package/web/.next/standalone/web/.next/server/app/docs/page.js +21 -0
  86. package/web/.next/standalone/web/.next/server/app/docs/page.js.map +5 -0
  87. package/web/.next/standalone/web/.next/server/app/docs/page.js.nft.json +1 -0
  88. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +2 -0
  89. package/web/.next/standalone/web/.next/server/app/docs/skills/page/app-paths-manifest.json +3 -0
  90. package/web/.next/standalone/web/.next/server/app/docs/skills/page/build-manifest.json +18 -0
  91. package/web/.next/standalone/web/.next/server/app/docs/skills/page/next-font-manifest.json +11 -0
  92. package/web/.next/standalone/web/.next/server/app/docs/skills/page/react-loadable-manifest.json +1 -0
  93. package/web/.next/standalone/web/.next/server/app/docs/skills/page/server-reference-manifest.json +4 -0
  94. package/web/.next/standalone/web/.next/server/app/docs/skills/page.js +21 -0
  95. package/web/.next/standalone/web/.next/server/app/docs/skills/page.js.map +5 -0
  96. package/web/.next/standalone/web/.next/server/app/docs/skills/page.js.nft.json +1 -0
  97. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +2 -0
  98. package/web/.next/standalone/web/.next/server/app/docs/skills.html +268 -0
  99. package/web/.next/standalone/web/.next/server/app/docs/skills.meta +16 -0
  100. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +82 -0
  101. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +82 -0
  102. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +6 -0
  103. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +7 -0
  104. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +3 -0
  105. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +66 -0
  106. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +4 -0
  107. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +5 -0
  108. package/web/.next/standalone/web/.next/server/app/docs/tools/page/app-paths-manifest.json +3 -0
  109. package/web/.next/standalone/web/.next/server/app/docs/tools/page/build-manifest.json +18 -0
  110. package/web/.next/standalone/web/.next/server/app/docs/tools/page/next-font-manifest.json +11 -0
  111. package/web/.next/standalone/web/.next/server/app/docs/tools/page/react-loadable-manifest.json +1 -0
  112. package/web/.next/standalone/web/.next/server/app/docs/tools/page/server-reference-manifest.json +4 -0
  113. package/web/.next/standalone/web/.next/server/app/docs/tools/page.js +21 -0
  114. package/web/.next/standalone/web/.next/server/app/docs/tools/page.js.map +5 -0
  115. package/web/.next/standalone/web/.next/server/app/docs/tools/page.js.nft.json +1 -0
  116. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +2 -0
  117. package/web/.next/standalone/web/.next/server/app/docs/tools.html +242 -0
  118. package/web/.next/standalone/web/.next/server/app/docs/tools.meta +16 -0
  119. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +87 -0
  120. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +87 -0
  121. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +6 -0
  122. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +7 -0
  123. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +3 -0
  124. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +72 -0
  125. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +4 -0
  126. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +5 -0
  127. package/web/.next/standalone/web/.next/server/app/docs.html +74 -0
  128. package/web/.next/standalone/web/.next/server/app/docs.meta +15 -0
  129. package/web/.next/standalone/web/.next/server/app/docs.rsc +34 -0
  130. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +34 -0
  131. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +6 -0
  132. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +7 -0
  133. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +3 -0
  134. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +20 -0
  135. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +5 -0
  136. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  137. package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
  138. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  139. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  140. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
  141. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  142. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  143. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  144. package/web/.next/standalone/web/.next/server/app-paths-manifest.json +4 -0
  145. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_5f58fd73._.js → 2374f_244589df._.js} +1 -1
  146. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_84859a94._.js → 2374f_41a27541._.js} +1 -1
  147. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_65fcfd95._.js → 2374f_47c9e2d5._.js} +1 -1
  148. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_f1038f7c._.js → 2374f_4bf2df9d._.js} +1 -1
  149. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_663d1038._.js +3 -0
  150. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_954e49c0._.js +3 -0
  151. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_387a1437._.js → 2374f_c33b095a._.js} +1 -1
  152. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_cfd0137a._.js → 2374f_fa61fbb2._.js} +1 -1
  153. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_741f6b67._.js → 2374f_fb82ac0d._.js} +1 -1
  154. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_96bca05b._.js → 2374f_next_dist_bbe64674._.js} +2 -2
  155. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__7f04455b._.js → [root-of-the-server]__1e06ddf7._.js} +2 -2
  156. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__2b151e1c._.js +3 -0
  157. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__2dbf511a._.js +9 -0
  158. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__397fadd4._.js +3 -0
  159. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__44bd8bd1._.js +3 -0
  160. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__70cecda8._.js +3 -0
  161. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__9fdf9974._.js +3 -0
  162. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__f18f92f4._.js → [root-of-the-server]__b050bb8f._.js} +2 -2
  163. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__d3034cd2._.js +3 -0
  164. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__c3a1e22c._.js → [root-of-the-server]__ef2713cf._.js} +2 -2
  165. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__f764bebe._.js +3 -0
  166. package/web/.next/standalone/web/.next/server/chunks/ssr/web_046bf7db._.js +3 -0
  167. package/web/.next/standalone/web/.next/server/chunks/ssr/web_656c1e45._.js +7 -0
  168. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_c7618534._.js → web_76ccf09f._.js} +4 -4
  169. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app_docs_installation_page_actions_52cc0648.js +3 -0
  170. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app_docs_page_actions_4fe77da8.js +3 -0
  171. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app_docs_skills_page_actions_251df2e1.js +3 -0
  172. package/web/.next/standalone/web/.next/server/chunks/ssr/web__next-internal_server_app_docs_tools_page_actions_3e6382b0.js +3 -0
  173. package/web/.next/standalone/web/.next/server/chunks/ssr/web_a565dc94._.js +4 -0
  174. package/web/.next/standalone/web/.next/server/chunks/ssr/web_b1cce0b7._.js +4 -0
  175. package/web/.next/standalone/web/.next/server/chunks/ssr/web_b42ed1be._.js +3 -0
  176. package/web/.next/standalone/web/.next/server/chunks/ssr/web_c0c2bee4._.js +4 -0
  177. package/web/.next/standalone/web/.next/server/chunks/ssr/web_eea9c122._.js +3 -0
  178. package/web/.next/standalone/web/.next/server/chunks/ssr/web_ff00a5c3._.js +4 -0
  179. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_layout_tsx_453f6492._.js +3 -0
  180. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_page_tsx_5ac4794b._.js +3 -0
  181. package/web/.next/standalone/web/.next/server/middleware-build-manifest.js +5 -4
  182. package/web/.next/standalone/web/.next/server/next-font-manifest.js +1 -1
  183. package/web/.next/standalone/web/.next/server/next-font-manifest.json +16 -0
  184. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  185. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  186. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  187. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  188. package/web/.next/standalone/web/.next/static/chunks/0cc382a66266188e.js +7 -0
  189. package/web/.next/standalone/web/.next/static/chunks/0fda34e553582102.js +1 -0
  190. package/web/.next/standalone/web/.next/static/{static/chunks/5e5b485d77ac0d8f.js → chunks/6407c045dfc908fe.js} +3 -3
  191. package/web/.next/standalone/web/.next/static/chunks/651e187cc15d66de.js +1 -0
  192. package/web/.next/standalone/web/.next/static/chunks/862ced58ce21a270.js +4 -0
  193. package/web/.next/standalone/web/.next/static/chunks/89bc21c0443670f4.js +1 -0
  194. package/web/.next/standalone/web/.next/static/chunks/8f4edf22ededc29b.js +7 -0
  195. package/web/.next/standalone/web/.next/static/chunks/ad6b9dbb257d62cc.js +1 -0
  196. package/web/.next/standalone/web/.next/static/chunks/af22745850132107.css +1 -0
  197. package/web/.next/standalone/web/.next/static/chunks/b9ad1584d4e11d12.js +1 -0
  198. package/web/.next/standalone/web/.next/static/chunks/db9b22c844a35e20.js +5 -0
  199. package/web/.next/standalone/web/.next/static/chunks/turbopack-597558bb7b6982f6.js +4 -0
  200. package/web/.next/standalone/web/.next/static/static/chunks/0cc382a66266188e.js +7 -0
  201. package/web/.next/standalone/web/.next/static/static/chunks/0fda34e553582102.js +1 -0
  202. package/web/.next/{static/chunks/5e5b485d77ac0d8f.js → standalone/web/.next/static/static/chunks/6407c045dfc908fe.js} +3 -3
  203. package/web/.next/standalone/web/.next/static/static/chunks/651e187cc15d66de.js +1 -0
  204. package/web/.next/standalone/web/.next/static/static/chunks/862ced58ce21a270.js +4 -0
  205. package/web/.next/standalone/web/.next/static/static/chunks/89bc21c0443670f4.js +1 -0
  206. package/web/.next/standalone/web/.next/static/static/chunks/8f4edf22ededc29b.js +7 -0
  207. package/web/.next/standalone/web/.next/static/static/chunks/ad6b9dbb257d62cc.js +1 -0
  208. package/web/.next/standalone/web/.next/static/static/chunks/af22745850132107.css +1 -0
  209. package/web/.next/standalone/web/.next/static/static/chunks/b9ad1584d4e11d12.js +1 -0
  210. package/web/.next/standalone/web/.next/static/static/chunks/db9b22c844a35e20.js +5 -0
  211. package/web/.next/standalone/web/.next/static/static/chunks/turbopack-597558bb7b6982f6.js +4 -0
  212. package/web/.next/standalone/web/mdx-components.tsx +119 -0
  213. package/web/.next/standalone/web/next.config.ts +15 -1
  214. package/web/.next/standalone/web/package-lock.json +559 -4
  215. package/web/.next/standalone/web/package.json +4 -0
  216. package/web/.next/standalone/web/runtime-config.json +1 -1
  217. package/web/.next/standalone/web/server.js +1 -1
  218. package/web/.next/standalone/web/src/app/(main)/page.tsx +127 -5
  219. package/web/.next/standalone/web/src/app/docs/installation/page.mdx +128 -0
  220. package/web/.next/standalone/web/src/app/docs/layout.tsx +74 -0
  221. package/web/.next/standalone/web/src/app/docs/page.mdx +90 -0
  222. package/web/.next/standalone/web/src/app/docs/skills/page.mdx +334 -0
  223. package/web/.next/standalone/web/src/app/docs/tools/page.mdx +300 -0
  224. package/web/.next/standalone/web/src/components/ai-elements/mention-input.tsx +809 -0
  225. package/web/.next/standalone/web/src/components/ai-elements/search-tool.tsx +400 -0
  226. package/web/.next/standalone/web/src/components/ai-elements/subagent-modal.tsx +275 -0
  227. package/web/.next/standalone/web/src/components/ai-elements/write-file-tool.tsx +19 -5
  228. package/web/.next/standalone/web/src/components/chat-interface.tsx +525 -71
  229. package/web/.next/standalone/web/src/hooks/use-workspace-files.ts +108 -0
  230. package/web/.next/standalone/web/src/lib/api.ts +90 -4
  231. package/web/.next/static/chunks/0cc382a66266188e.js +7 -0
  232. package/web/.next/static/chunks/0fda34e553582102.js +1 -0
  233. package/web/.next/{standalone/web/.next/static/chunks/5e5b485d77ac0d8f.js → static/chunks/6407c045dfc908fe.js} +3 -3
  234. package/web/.next/static/chunks/651e187cc15d66de.js +1 -0
  235. package/web/.next/static/chunks/862ced58ce21a270.js +4 -0
  236. package/web/.next/static/chunks/89bc21c0443670f4.js +1 -0
  237. package/web/.next/static/chunks/8f4edf22ededc29b.js +7 -0
  238. package/web/.next/static/chunks/ad6b9dbb257d62cc.js +1 -0
  239. package/web/.next/static/chunks/af22745850132107.css +1 -0
  240. package/web/.next/static/chunks/b9ad1584d4e11d12.js +1 -0
  241. package/web/.next/static/chunks/db9b22c844a35e20.js +5 -0
  242. package/web/.next/static/chunks/turbopack-597558bb7b6982f6.js +4 -0
  243. package/web/package.json +4 -0
  244. package/dist/bash-CGAqW7HR.d.ts +0 -80
  245. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_814be2c9._.js +0 -3
  246. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__0f6b5fa7._.js +0 -3
  247. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__3ec22171._.js +0 -9
  248. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__513c6b45._.js +0 -3
  249. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__de58a952._.js +0 -3
  250. package/web/.next/standalone/web/.next/server/chunks/ssr/web_d7d3e40d._.js +0 -7
  251. package/web/.next/standalone/web/.next/server/chunks/ssr/web_e6034803._.js +0 -3
  252. package/web/.next/standalone/web/.next/static/chunks/03d4169891280e04.js +0 -7
  253. package/web/.next/standalone/web/.next/static/chunks/2d5da0cfc011b8d9.js +0 -1
  254. package/web/.next/standalone/web/.next/static/chunks/3bb454ca848ec78e.js +0 -7
  255. package/web/.next/standalone/web/.next/static/chunks/634fd97fab9ed4e4.js +0 -4
  256. package/web/.next/standalone/web/.next/static/chunks/77e4bf0421481629.js +0 -1
  257. package/web/.next/standalone/web/.next/static/chunks/beb9625c4a470042.js +0 -1
  258. package/web/.next/standalone/web/.next/static/chunks/c2244168e74b8c78.js +0 -1
  259. package/web/.next/standalone/web/.next/static/chunks/c81c1aec4369c77f.js +0 -5
  260. package/web/.next/standalone/web/.next/static/chunks/cb355fac10c6ad11.css +0 -1
  261. package/web/.next/standalone/web/.next/static/chunks/turbopack-54bc7d566cd2d105.js +0 -4
  262. package/web/.next/standalone/web/.next/static/static/chunks/03d4169891280e04.js +0 -7
  263. package/web/.next/standalone/web/.next/static/static/chunks/2d5da0cfc011b8d9.js +0 -1
  264. package/web/.next/standalone/web/.next/static/static/chunks/3bb454ca848ec78e.js +0 -7
  265. package/web/.next/standalone/web/.next/static/static/chunks/634fd97fab9ed4e4.js +0 -4
  266. package/web/.next/standalone/web/.next/static/static/chunks/77e4bf0421481629.js +0 -1
  267. package/web/.next/standalone/web/.next/static/static/chunks/beb9625c4a470042.js +0 -1
  268. package/web/.next/standalone/web/.next/static/static/chunks/c2244168e74b8c78.js +0 -1
  269. package/web/.next/standalone/web/.next/static/static/chunks/c81c1aec4369c77f.js +0 -5
  270. package/web/.next/standalone/web/.next/static/static/chunks/cb355fac10c6ad11.css +0 -1
  271. package/web/.next/standalone/web/.next/static/static/chunks/turbopack-54bc7d566cd2d105.js +0 -4
  272. package/web/.next/static/chunks/03d4169891280e04.js +0 -7
  273. package/web/.next/static/chunks/2d5da0cfc011b8d9.js +0 -1
  274. package/web/.next/static/chunks/3bb454ca848ec78e.js +0 -7
  275. package/web/.next/static/chunks/634fd97fab9ed4e4.js +0 -4
  276. package/web/.next/static/chunks/77e4bf0421481629.js +0 -1
  277. package/web/.next/static/chunks/beb9625c4a470042.js +0 -1
  278. package/web/.next/static/chunks/c2244168e74b8c78.js +0 -1
  279. package/web/.next/static/chunks/c81c1aec4369c77f.js +0 -5
  280. package/web/.next/static/chunks/cb355fac10c6ad11.css +0 -1
  281. package/web/.next/static/chunks/turbopack-54bc7d566cd2d105.js +0 -4
  282. /package/web/.next/standalone/web/.next/static/{n86r6x1RoUipFp6nLIk-R → static/uXbuwS0U7fRElucaXbKUe}/_buildManifest.js +0 -0
  283. /package/web/.next/standalone/web/.next/static/{n86r6x1RoUipFp6nLIk-R → static/uXbuwS0U7fRElucaXbKUe}/_clientMiddlewareManifest.json +0 -0
  284. /package/web/.next/standalone/web/.next/static/{n86r6x1RoUipFp6nLIk-R → static/uXbuwS0U7fRElucaXbKUe}/_ssgManifest.js +0 -0
  285. /package/web/.next/standalone/web/.next/static/{static/n86r6x1RoUipFp6nLIk-R → uXbuwS0U7fRElucaXbKUe}/_buildManifest.js +0 -0
  286. /package/web/.next/standalone/web/.next/static/{static/n86r6x1RoUipFp6nLIk-R → uXbuwS0U7fRElucaXbKUe}/_clientMiddlewareManifest.json +0 -0
  287. /package/web/.next/standalone/web/.next/static/{static/n86r6x1RoUipFp6nLIk-R → uXbuwS0U7fRElucaXbKUe}/_ssgManifest.js +0 -0
  288. /package/web/.next/static/{n86r6x1RoUipFp6nLIk-R → uXbuwS0U7fRElucaXbKUe}/_buildManifest.js +0 -0
  289. /package/web/.next/static/{n86r6x1RoUipFp6nLIk-R → uXbuwS0U7fRElucaXbKUe}/_clientMiddlewareManifest.json +0 -0
  290. /package/web/.next/static/{n86r6x1RoUipFp6nLIk-R → uXbuwS0U7fRElucaXbKUe}/_ssgManifest.js +0 -0
@@ -1,13 +1,426 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/config/types.ts
12
+ import { z } from "zod";
13
+ var ToolApprovalConfigSchema, SkillMetadataSchema, SessionConfigSchema, SparkcoderConfigSchema;
14
+ var init_types = __esm({
15
+ "src/config/types.ts"() {
16
+ "use strict";
17
+ ToolApprovalConfigSchema = z.object({
18
+ bash: z.boolean().optional().default(true),
19
+ write_file: z.boolean().optional().default(false),
20
+ read_file: z.boolean().optional().default(false),
21
+ load_skill: z.boolean().optional().default(false),
22
+ todo: z.boolean().optional().default(false)
23
+ });
24
+ SkillMetadataSchema = z.object({
25
+ name: z.string(),
26
+ description: z.string(),
27
+ // Whether to always inject this skill into context (vs on-demand loading)
28
+ alwaysApply: z.boolean().optional().default(false),
29
+ // Glob patterns - auto-inject when working with matching files
30
+ globs: z.array(z.string()).optional().default([])
31
+ });
32
+ SessionConfigSchema = z.object({
33
+ toolApprovals: z.record(z.string(), z.boolean()).optional(),
34
+ approvalWebhook: z.string().url().optional(),
35
+ skillsDirectory: z.string().optional(),
36
+ maxContextChars: z.number().optional().default(2e5)
37
+ });
38
+ SparkcoderConfigSchema = z.object({
39
+ // Default model to use (Vercel AI Gateway format)
40
+ defaultModel: z.string().default("anthropic/claude-opus-4-5"),
41
+ // Working directory for file operations
42
+ workingDirectory: z.string().optional(),
43
+ // Tool approval settings
44
+ toolApprovals: ToolApprovalConfigSchema.optional().default({}),
45
+ // Approval webhook URL (called when approval is needed)
46
+ approvalWebhook: z.string().url().optional(),
47
+ // Skills configuration
48
+ skills: z.object({
49
+ // Directory containing skill files
50
+ directory: z.string().optional().default("./skills"),
51
+ // Additional skill directories to include
52
+ additionalDirectories: z.array(z.string()).optional().default([])
53
+ }).optional().default({}),
54
+ // Context management
55
+ context: z.object({
56
+ // Maximum context size before summarization (in characters)
57
+ maxChars: z.number().optional().default(2e5),
58
+ // Enable automatic summarization
59
+ autoSummarize: z.boolean().optional().default(true),
60
+ // Number of recent messages to keep after summarization
61
+ keepRecentMessages: z.number().optional().default(10)
62
+ }).optional().default({}),
63
+ // Server configuration
64
+ server: z.object({
65
+ port: z.number().default(3141),
66
+ host: z.string().default("127.0.0.1"),
67
+ // Public URL for web UI to connect to API (for Docker/remote access)
68
+ // If not set, defaults to http://{host}:{port}
69
+ publicUrl: z.string().url().optional()
70
+ }).default({ port: 3141, host: "127.0.0.1" }),
71
+ // Database path
72
+ databasePath: z.string().optional().default("./sparkecoder.db")
73
+ });
74
+ }
75
+ });
76
+
77
+ // src/skills/index.ts
78
+ var skills_exports = {};
79
+ __export(skills_exports, {
80
+ formatAgentsMdContent: () => formatAgentsMdContent,
81
+ formatAlwaysLoadedSkills: () => formatAlwaysLoadedSkills,
82
+ formatGlobMatchedSkills: () => formatGlobMatchedSkills,
83
+ formatSkillsForContext: () => formatSkillsForContext,
84
+ getGlobMatchedSkills: () => getGlobMatchedSkills,
85
+ loadAgentsMd: () => loadAgentsMd,
86
+ loadAllSkills: () => loadAllSkills,
87
+ loadAllSkillsFromDiscovered: () => loadAllSkillsFromDiscovered,
88
+ loadSkillContent: () => loadSkillContent,
89
+ loadSkillsFromDirectory: () => loadSkillsFromDirectory
90
+ });
91
+ import { readFile as readFile6, readdir } from "fs/promises";
92
+ import { resolve as resolve6, basename, extname as extname3, relative as relative4 } from "path";
93
+ import { existsSync as existsSync8 } from "fs";
94
+ import { minimatch } from "minimatch";
95
+ function parseSkillFrontmatter(content) {
96
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
97
+ if (!frontmatterMatch) {
98
+ return null;
99
+ }
100
+ const [, frontmatter, body] = frontmatterMatch;
101
+ try {
102
+ const lines = frontmatter.split("\n");
103
+ const data = {};
104
+ let currentArray = null;
105
+ let currentArrayKey = null;
106
+ for (const line of lines) {
107
+ if (currentArrayKey && line.trim().startsWith("-")) {
108
+ let value = line.trim().slice(1).trim();
109
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
110
+ value = value.slice(1, -1);
111
+ }
112
+ currentArray?.push(value);
113
+ continue;
114
+ }
115
+ if (currentArrayKey && currentArray) {
116
+ data[currentArrayKey] = currentArray;
117
+ currentArray = null;
118
+ currentArrayKey = null;
119
+ }
120
+ const colonIndex = line.indexOf(":");
121
+ if (colonIndex > 0) {
122
+ const key = line.slice(0, colonIndex).trim();
123
+ let value = line.slice(colonIndex + 1).trim();
124
+ if (value === "" || value === "[]") {
125
+ currentArrayKey = key;
126
+ currentArray = [];
127
+ continue;
128
+ }
129
+ if (value.startsWith("[") && value.endsWith("]")) {
130
+ const arrayContent = value.slice(1, -1);
131
+ const items = arrayContent.split(",").map((item) => {
132
+ let trimmed = item.trim();
133
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
134
+ trimmed = trimmed.slice(1, -1);
135
+ }
136
+ return trimmed;
137
+ }).filter((item) => item.length > 0);
138
+ data[key] = items;
139
+ continue;
140
+ }
141
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
142
+ value = value.slice(1, -1);
143
+ }
144
+ if (value === "true") {
145
+ data[key] = true;
146
+ } else if (value === "false") {
147
+ data[key] = false;
148
+ } else {
149
+ data[key] = value;
150
+ }
151
+ }
152
+ }
153
+ if (currentArrayKey && currentArray) {
154
+ data[currentArrayKey] = currentArray;
155
+ }
156
+ const metadata = SkillMetadataSchema.parse(data);
157
+ return { metadata, body: body.trim() };
158
+ } catch {
159
+ return null;
160
+ }
161
+ }
162
+ function getSkillNameFromPath(filePath) {
163
+ return basename(filePath, extname3(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
164
+ }
165
+ async function loadSkillsFromDirectory(directory, options = {}) {
166
+ const {
167
+ priority = 50,
168
+ defaultLoadType = "on_demand",
169
+ forceAlwaysApply = false
170
+ } = options;
171
+ if (!existsSync8(directory)) {
172
+ return [];
173
+ }
174
+ const skills = [];
175
+ const entries = await readdir(directory, { withFileTypes: true });
176
+ for (const entry of entries) {
177
+ let filePath;
178
+ let fileName;
179
+ if (entry.isDirectory()) {
180
+ const skillMdPath = resolve6(directory, entry.name, "SKILL.md");
181
+ if (existsSync8(skillMdPath)) {
182
+ filePath = skillMdPath;
183
+ fileName = entry.name;
184
+ } else {
185
+ continue;
186
+ }
187
+ } else if (entry.name.endsWith(".md") || entry.name.endsWith(".mdc")) {
188
+ filePath = resolve6(directory, entry.name);
189
+ fileName = entry.name;
190
+ } else {
191
+ continue;
192
+ }
193
+ const content = await readFile6(filePath, "utf-8");
194
+ const parsed = parseSkillFrontmatter(content);
195
+ if (parsed) {
196
+ const alwaysApply = forceAlwaysApply || parsed.metadata.alwaysApply;
197
+ const loadType = alwaysApply ? "always" : defaultLoadType;
198
+ skills.push({
199
+ name: parsed.metadata.name,
200
+ description: parsed.metadata.description,
201
+ filePath,
202
+ alwaysApply,
203
+ globs: parsed.metadata.globs,
204
+ loadType,
205
+ priority,
206
+ sourceDir: directory
207
+ });
208
+ } else {
209
+ const name = getSkillNameFromPath(filePath);
210
+ const firstParagraph = content.split("\n\n")[0]?.slice(0, 200) || "No description";
211
+ skills.push({
212
+ name,
213
+ description: firstParagraph.replace(/^#\s*/, "").trim(),
214
+ filePath,
215
+ alwaysApply: forceAlwaysApply,
216
+ globs: [],
217
+ loadType: forceAlwaysApply ? "always" : defaultLoadType,
218
+ priority,
219
+ sourceDir: directory
220
+ });
221
+ }
222
+ }
223
+ return skills;
224
+ }
225
+ async function loadAllSkills(directories) {
226
+ const allSkills = [];
227
+ const seenNames = /* @__PURE__ */ new Set();
228
+ for (const dir of directories) {
229
+ const skills = await loadSkillsFromDirectory(dir);
230
+ for (const skill of skills) {
231
+ if (!seenNames.has(skill.name.toLowerCase())) {
232
+ seenNames.add(skill.name.toLowerCase());
233
+ allSkills.push(skill);
234
+ }
235
+ }
236
+ }
237
+ return allSkills;
238
+ }
239
+ async function loadAllSkillsFromDiscovered(discovered) {
240
+ const allSkills = [];
241
+ const seenNames = /* @__PURE__ */ new Set();
242
+ for (const { path, priority } of discovered.alwaysLoadedDirs) {
243
+ const skills = await loadSkillsFromDirectory(path, {
244
+ priority,
245
+ defaultLoadType: "always",
246
+ forceAlwaysApply: true
247
+ });
248
+ for (const skill of skills) {
249
+ if (!seenNames.has(skill.name.toLowerCase())) {
250
+ seenNames.add(skill.name.toLowerCase());
251
+ allSkills.push(skill);
252
+ }
253
+ }
254
+ }
255
+ for (const { path, priority } of discovered.onDemandDirs) {
256
+ const skills = await loadSkillsFromDirectory(path, {
257
+ priority,
258
+ defaultLoadType: "on_demand",
259
+ forceAlwaysApply: false
260
+ });
261
+ for (const skill of skills) {
262
+ if (!seenNames.has(skill.name.toLowerCase())) {
263
+ seenNames.add(skill.name.toLowerCase());
264
+ allSkills.push(skill);
265
+ }
266
+ }
267
+ }
268
+ const alwaysSkills = allSkills.filter((s) => s.alwaysApply || s.loadType === "always");
269
+ const onDemandSkills = allSkills.filter((s) => !s.alwaysApply && s.loadType !== "always");
270
+ const alwaysWithContent = await Promise.all(
271
+ alwaysSkills.map(async (skill) => {
272
+ const content = await readFile6(skill.filePath, "utf-8");
273
+ const parsed = parseSkillFrontmatter(content);
274
+ return {
275
+ ...skill,
276
+ content: parsed ? parsed.body : content
277
+ };
278
+ })
279
+ );
280
+ return {
281
+ always: alwaysWithContent,
282
+ onDemand: onDemandSkills,
283
+ all: allSkills
284
+ };
285
+ }
286
+ async function getGlobMatchedSkills(skills, activeFiles, workingDirectory) {
287
+ if (activeFiles.length === 0) {
288
+ return [];
289
+ }
290
+ const relativeFiles = activeFiles.map((f) => {
291
+ if (f.startsWith(workingDirectory)) {
292
+ return relative4(workingDirectory, f);
293
+ }
294
+ return f;
295
+ });
296
+ const matchedSkills = skills.filter((skill) => {
297
+ if (skill.alwaysApply || skill.loadType === "always") {
298
+ return false;
299
+ }
300
+ if (!skill.globs || skill.globs.length === 0) {
301
+ return false;
302
+ }
303
+ return relativeFiles.some(
304
+ (file) => skill.globs.some((pattern) => minimatch(file, pattern, { matchBase: true }))
305
+ );
306
+ });
307
+ const matchedWithContent = await Promise.all(
308
+ matchedSkills.map(async (skill) => {
309
+ const content = await readFile6(skill.filePath, "utf-8");
310
+ const parsed = parseSkillFrontmatter(content);
311
+ return {
312
+ ...skill,
313
+ content: parsed ? parsed.body : content,
314
+ loadType: "glob_matched"
315
+ };
316
+ })
317
+ );
318
+ return matchedWithContent;
319
+ }
320
+ async function loadAgentsMd(agentsMdPath) {
321
+ if (!agentsMdPath || !existsSync8(agentsMdPath)) {
322
+ return null;
323
+ }
324
+ const content = await readFile6(agentsMdPath, "utf-8");
325
+ return content;
326
+ }
327
+ async function loadSkillContent(skillName, directories) {
328
+ const allSkills = await loadAllSkills(directories);
329
+ const skill = allSkills.find(
330
+ (s) => s.name.toLowerCase() === skillName.toLowerCase()
331
+ );
332
+ if (!skill) {
333
+ return null;
334
+ }
335
+ const content = await readFile6(skill.filePath, "utf-8");
336
+ const parsed = parseSkillFrontmatter(content);
337
+ return {
338
+ ...skill,
339
+ content: parsed ? parsed.body : content
340
+ };
341
+ }
342
+ function formatSkillsForContext(skills) {
343
+ const onDemandSkills = skills.filter((s) => !s.alwaysApply && s.loadType !== "always");
344
+ if (onDemandSkills.length === 0) {
345
+ return "No on-demand skills available.";
346
+ }
347
+ const lines = ["Available skills (use load_skill tool to load into context):"];
348
+ for (const skill of onDemandSkills) {
349
+ const globInfo = skill.globs?.length ? ` [auto-loads for: ${skill.globs.join(", ")}]` : "";
350
+ lines.push(`- ${skill.name}: ${skill.description}${globInfo}`);
351
+ }
352
+ return lines.join("\n");
353
+ }
354
+ function formatAlwaysLoadedSkills(skills) {
355
+ if (skills.length === 0) {
356
+ return "";
357
+ }
358
+ const sections = [];
359
+ for (const skill of skills) {
360
+ sections.push(`### ${skill.name}
361
+
362
+ ${skill.content}`);
363
+ }
364
+ return `## Active Rules & Skills (Always Loaded)
365
+
366
+ ${sections.join("\n\n---\n\n")}`;
367
+ }
368
+ function formatGlobMatchedSkills(skills) {
369
+ if (skills.length === 0) {
370
+ return "";
371
+ }
372
+ const sections = [];
373
+ for (const skill of skills) {
374
+ sections.push(`### ${skill.name}
375
+
376
+ ${skill.content}`);
377
+ }
378
+ return `## Context-Relevant Skills (Auto-loaded based on active files)
379
+
380
+ ${sections.join("\n\n---\n\n")}`;
381
+ }
382
+ function formatAgentsMdContent(content) {
383
+ if (!content) {
384
+ return "";
385
+ }
386
+ return `## Project Instructions (AGENTS.md)
387
+
388
+ ${content}`;
389
+ }
390
+ var init_skills = __esm({
391
+ "src/skills/index.ts"() {
392
+ "use strict";
393
+ init_types();
394
+ }
395
+ });
396
+
1
397
  // src/agent/index.ts
2
398
  import {
3
- streamText,
4
- generateText as generateText2,
5
- tool as tool7,
6
- stepCountIs
399
+ streamText as streamText2,
400
+ generateText as generateText3,
401
+ tool as tool9,
402
+ stepCountIs as stepCountIs2
7
403
  } from "ai";
8
- import { gateway as gateway2 } from "@ai-sdk/gateway";
9
- import { z as z8 } from "zod";
10
- import { nanoid as nanoid3 } from "nanoid";
404
+
405
+ // src/agent/model.ts
406
+ import { gateway } from "@ai-sdk/gateway";
407
+ var ANTHROPIC_PREFIX = "anthropic/";
408
+ function isAnthropicModel(modelId) {
409
+ const normalized = modelId.trim().toLowerCase();
410
+ return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
411
+ }
412
+ function resolveModel(modelId) {
413
+ return gateway(modelId.trim());
414
+ }
415
+ var SUBAGENT_MODELS = {
416
+ search: "google/gemini-2.0-flash",
417
+ analyze: "google/gemini-2.0-flash",
418
+ default: "google/gemini-2.0-flash"
419
+ };
420
+
421
+ // src/agent/index.ts
422
+ import { z as z10 } from "zod";
423
+ import { nanoid as nanoid4 } from "nanoid";
11
424
 
12
425
  // src/db/index.ts
13
426
  import Database from "better-sqlite3";
@@ -115,6 +528,26 @@ var fileBackups = sqliteTable("file_backups", {
115
528
  existed: integer("existed", { mode: "boolean" }).notNull().default(true),
116
529
  createdAt: integer("created_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
117
530
  });
531
+ var subagentExecutions = sqliteTable("subagent_executions", {
532
+ id: text("id").primaryKey(),
533
+ sessionId: text("session_id").notNull().references(() => sessions.id, { onDelete: "cascade" }),
534
+ toolCallId: text("tool_call_id").notNull(),
535
+ // The tool call that spawned this subagent
536
+ subagentType: text("subagent_type").notNull(),
537
+ // e.g., 'search', 'analyze', etc.
538
+ task: text("task").notNull(),
539
+ // The task/query given to the subagent
540
+ model: text("model").notNull(),
541
+ // The model used (e.g., 'gemini-2.0-flash')
542
+ status: text("status", { enum: ["running", "completed", "error", "cancelled"] }).notNull().default("running"),
543
+ // Steps taken by the subagent (stored as JSON array)
544
+ steps: text("steps", { mode: "json" }).$type().default([]),
545
+ // Final result/output
546
+ result: text("result", { mode: "json" }),
547
+ error: text("error"),
548
+ startedAt: integer("started_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date()),
549
+ completedAt: integer("completed_at", { mode: "timestamp" })
550
+ });
118
551
 
119
552
  // src/db/index.ts
120
553
  var db = null;
@@ -420,69 +853,70 @@ var fileBackupQueries = {
420
853
  return result.changes;
421
854
  }
422
855
  };
856
+ var subagentQueries = {
857
+ create(data) {
858
+ const id = nanoid();
859
+ const result = getDb().insert(subagentExecutions).values({
860
+ id,
861
+ sessionId: data.sessionId,
862
+ toolCallId: data.toolCallId,
863
+ subagentType: data.subagentType,
864
+ task: data.task,
865
+ model: data.model,
866
+ status: "running",
867
+ steps: [],
868
+ startedAt: /* @__PURE__ */ new Date()
869
+ }).returning().get();
870
+ return result;
871
+ },
872
+ getById(id) {
873
+ return getDb().select().from(subagentExecutions).where(eq(subagentExecutions.id, id)).get();
874
+ },
875
+ getByToolCallId(toolCallId) {
876
+ return getDb().select().from(subagentExecutions).where(eq(subagentExecutions.toolCallId, toolCallId)).get();
877
+ },
878
+ getBySession(sessionId) {
879
+ return getDb().select().from(subagentExecutions).where(eq(subagentExecutions.sessionId, sessionId)).orderBy(desc(subagentExecutions.startedAt)).all();
880
+ },
881
+ addStep(id, step) {
882
+ const existing = this.getById(id);
883
+ if (!existing) return void 0;
884
+ const currentSteps = existing.steps || [];
885
+ const newSteps = [...currentSteps, step];
886
+ return getDb().update(subagentExecutions).set({ steps: newSteps }).where(eq(subagentExecutions.id, id)).returning().get();
887
+ },
888
+ complete(id, result) {
889
+ return getDb().update(subagentExecutions).set({
890
+ status: "completed",
891
+ result,
892
+ completedAt: /* @__PURE__ */ new Date()
893
+ }).where(eq(subagentExecutions.id, id)).returning().get();
894
+ },
895
+ markError(id, error) {
896
+ return getDb().update(subagentExecutions).set({
897
+ status: "error",
898
+ error,
899
+ completedAt: /* @__PURE__ */ new Date()
900
+ }).where(eq(subagentExecutions.id, id)).returning().get();
901
+ },
902
+ cancel(id) {
903
+ return getDb().update(subagentExecutions).set({
904
+ status: "cancelled",
905
+ completedAt: /* @__PURE__ */ new Date()
906
+ }).where(eq(subagentExecutions.id, id)).returning().get();
907
+ },
908
+ deleteBySession(sessionId) {
909
+ const result = getDb().delete(subagentExecutions).where(eq(subagentExecutions.sessionId, sessionId)).run();
910
+ return result.changes;
911
+ }
912
+ };
423
913
 
424
914
  // src/config/index.ts
915
+ init_types();
916
+ init_types();
425
917
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
426
918
  import { resolve, dirname, join } from "path";
427
919
  import { homedir, platform } from "os";
428
-
429
- // src/config/types.ts
430
- import { z } from "zod";
431
- var ToolApprovalConfigSchema = z.object({
432
- bash: z.boolean().optional().default(true),
433
- write_file: z.boolean().optional().default(false),
434
- read_file: z.boolean().optional().default(false),
435
- load_skill: z.boolean().optional().default(false),
436
- todo: z.boolean().optional().default(false)
437
- });
438
- var SkillMetadataSchema = z.object({
439
- name: z.string(),
440
- description: z.string()
441
- });
442
- var SessionConfigSchema = z.object({
443
- toolApprovals: z.record(z.string(), z.boolean()).optional(),
444
- approvalWebhook: z.string().url().optional(),
445
- skillsDirectory: z.string().optional(),
446
- maxContextChars: z.number().optional().default(2e5)
447
- });
448
- var SparkcoderConfigSchema = z.object({
449
- // Default model to use (Vercel AI Gateway format)
450
- defaultModel: z.string().default("anthropic/claude-opus-4-5"),
451
- // Working directory for file operations
452
- workingDirectory: z.string().optional(),
453
- // Tool approval settings
454
- toolApprovals: ToolApprovalConfigSchema.optional().default({}),
455
- // Approval webhook URL (called when approval is needed)
456
- approvalWebhook: z.string().url().optional(),
457
- // Skills configuration
458
- skills: z.object({
459
- // Directory containing skill files
460
- directory: z.string().optional().default("./skills"),
461
- // Additional skill directories to include
462
- additionalDirectories: z.array(z.string()).optional().default([])
463
- }).optional().default({}),
464
- // Context management
465
- context: z.object({
466
- // Maximum context size before summarization (in characters)
467
- maxChars: z.number().optional().default(2e5),
468
- // Enable automatic summarization
469
- autoSummarize: z.boolean().optional().default(true),
470
- // Number of recent messages to keep after summarization
471
- keepRecentMessages: z.number().optional().default(10)
472
- }).optional().default({}),
473
- // Server configuration
474
- server: z.object({
475
- port: z.number().default(3141),
476
- host: z.string().default("127.0.0.1"),
477
- // Public URL for web UI to connect to API (for Docker/remote access)
478
- // If not set, defaults to http://{host}:{port}
479
- publicUrl: z.string().url().optional()
480
- }).default({ port: 3141, host: "127.0.0.1" }),
481
- // Database path
482
- databasePath: z.string().optional().default("./sparkecoder.db")
483
- });
484
-
485
- // src/config/index.ts
486
920
  function getAppDataDirectory() {
487
921
  const appName = "sparkecoder";
488
922
  switch (platform()) {
@@ -1228,12 +1662,12 @@ function findNearestRoot(startDir, markers) {
1228
1662
  }
1229
1663
  async function commandExists(cmd) {
1230
1664
  try {
1231
- const { exec: exec4 } = await import("child_process");
1232
- const { promisify: promisify4 } = await import("util");
1233
- const execAsync4 = promisify4(exec4);
1665
+ const { exec: exec5 } = await import("child_process");
1666
+ const { promisify: promisify5 } = await import("util");
1667
+ const execAsync5 = promisify5(exec5);
1234
1668
  const isWindows = process.platform === "win32";
1235
1669
  const checkCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
1236
- await execAsync4(checkCmd);
1670
+ await execAsync5(checkCmd);
1237
1671
  return true;
1238
1672
  } catch {
1239
1673
  return false;
@@ -1523,7 +1957,7 @@ async function createClient(serverId, handle, root) {
1523
1957
  },
1524
1958
  async waitForDiagnostics(filePath, timeoutMs = 5e3) {
1525
1959
  const normalized = normalizePath(filePath);
1526
- return new Promise((resolve8) => {
1960
+ return new Promise((resolve9) => {
1527
1961
  const startTime = Date.now();
1528
1962
  let debounceTimer;
1529
1963
  let resolved = false;
@@ -1542,7 +1976,7 @@ async function createClient(serverId, handle, root) {
1542
1976
  if (resolved) return;
1543
1977
  resolved = true;
1544
1978
  cleanup();
1545
- resolve8(diagnostics.get(normalized) || []);
1979
+ resolve9(diagnostics.get(normalized) || []);
1546
1980
  };
1547
1981
  const onDiagnostic = () => {
1548
1982
  if (debounceTimer) clearTimeout(debounceTimer);
@@ -1700,6 +2134,7 @@ function isSupported(filePath) {
1700
2134
  }
1701
2135
 
1702
2136
  // src/tools/write-file.ts
2137
+ var MAX_PROGRESS_CHUNK_SIZE = 16 * 1024;
1703
2138
  var writeFileInputSchema = z4.object({
1704
2139
  path: z4.string().describe("The path to the file. Can be relative to working directory or absolute."),
1705
2140
  mode: z4.enum(["full", "str_replace"]).describe('Write mode: "full" for complete file write, "str_replace" for targeted string replacement'),
@@ -1743,24 +2178,76 @@ Working directory: ${options.workingDirectory}`,
1743
2178
  error: 'Content is required for "full" mode'
1744
2179
  };
1745
2180
  }
2181
+ const existed = existsSync7(absolutePath);
2182
+ const action = existed ? "replaced" : "created";
2183
+ console.log("[WRITE-FILE] onProgress callback exists:", !!options.onProgress);
2184
+ console.log("[WRITE-FILE] Emitting started event for:", relativePath);
2185
+ options.onProgress?.({
2186
+ path: absolutePath,
2187
+ relativePath,
2188
+ mode: "full",
2189
+ status: "started",
2190
+ action,
2191
+ totalLength: content.length
2192
+ });
2193
+ if (content.length <= MAX_PROGRESS_CHUNK_SIZE) {
2194
+ options.onProgress?.({
2195
+ path: absolutePath,
2196
+ relativePath,
2197
+ mode: "full",
2198
+ status: "content",
2199
+ content,
2200
+ action,
2201
+ totalLength: content.length
2202
+ });
2203
+ } else {
2204
+ const chunkCount = Math.ceil(content.length / MAX_PROGRESS_CHUNK_SIZE);
2205
+ for (let i = 0; i < chunkCount; i += 1) {
2206
+ const chunkStart = i * MAX_PROGRESS_CHUNK_SIZE;
2207
+ const chunk = content.slice(chunkStart, chunkStart + MAX_PROGRESS_CHUNK_SIZE);
2208
+ options.onProgress?.({
2209
+ path: absolutePath,
2210
+ relativePath,
2211
+ mode: "full",
2212
+ status: "content",
2213
+ content: chunk,
2214
+ action,
2215
+ totalLength: content.length,
2216
+ chunkIndex: i,
2217
+ chunkCount,
2218
+ chunkStart,
2219
+ isChunked: true
2220
+ });
2221
+ if (chunkCount > 1) {
2222
+ await new Promise((resolve9) => setTimeout(resolve9, 0));
2223
+ }
2224
+ }
2225
+ }
1746
2226
  await backupFile(options.sessionId, options.workingDirectory, absolutePath);
1747
2227
  const dir = dirname5(absolutePath);
1748
2228
  if (!existsSync7(dir)) {
1749
2229
  await mkdir3(dir, { recursive: true });
1750
2230
  }
1751
- const existed = existsSync7(absolutePath);
1752
2231
  await writeFile3(absolutePath, content, "utf-8");
1753
2232
  let diagnosticsOutput = "";
1754
2233
  if (options.enableLSP !== false && isSupported(absolutePath)) {
1755
2234
  await touchFile(absolutePath, true);
1756
2235
  diagnosticsOutput = await formatDiagnosticsOutput(absolutePath);
1757
2236
  }
2237
+ options.onProgress?.({
2238
+ path: absolutePath,
2239
+ relativePath,
2240
+ mode: "full",
2241
+ status: "completed",
2242
+ action,
2243
+ totalLength: content.length
2244
+ });
1758
2245
  return {
1759
2246
  success: true,
1760
2247
  path: absolutePath,
1761
- relativePath: relative3(options.workingDirectory, absolutePath),
2248
+ relativePath,
1762
2249
  mode: "full",
1763
- action: existed ? "replaced" : "created",
2250
+ action,
1764
2251
  bytesWritten: Buffer.byteLength(content, "utf-8"),
1765
2252
  lineCount: content.split("\n").length,
1766
2253
  ...diagnosticsOutput && { diagnostics: diagnosticsOutput }
@@ -1778,6 +2265,22 @@ Working directory: ${options.workingDirectory}`,
1778
2265
  error: `File not found: ${path}. Use "full" mode to create new files.`
1779
2266
  };
1780
2267
  }
2268
+ options.onProgress?.({
2269
+ path: absolutePath,
2270
+ relativePath,
2271
+ mode: "str_replace",
2272
+ status: "started",
2273
+ action: "edited"
2274
+ });
2275
+ options.onProgress?.({
2276
+ path: absolutePath,
2277
+ relativePath,
2278
+ mode: "str_replace",
2279
+ status: "content",
2280
+ oldString: old_string,
2281
+ newString: new_string,
2282
+ action: "edited"
2283
+ });
1781
2284
  await backupFile(options.sessionId, options.workingDirectory, absolutePath);
1782
2285
  const currentContent = await readFile5(absolutePath, "utf-8");
1783
2286
  if (!currentContent.includes(old_string)) {
@@ -1808,10 +2311,17 @@ Working directory: ${options.workingDirectory}`,
1808
2311
  await touchFile(absolutePath, true);
1809
2312
  diagnosticsOutput = await formatDiagnosticsOutput(absolutePath);
1810
2313
  }
2314
+ options.onProgress?.({
2315
+ path: absolutePath,
2316
+ relativePath,
2317
+ mode: "str_replace",
2318
+ status: "completed",
2319
+ action: "edited"
2320
+ });
1811
2321
  return {
1812
2322
  success: true,
1813
2323
  path: absolutePath,
1814
- relativePath: relative3(options.workingDirectory, absolutePath),
2324
+ relativePath,
1815
2325
  mode: "str_replace",
1816
2326
  linesRemoved: oldLines,
1817
2327
  linesAdded: newLines,
@@ -1959,112 +2469,9 @@ function formatTodoItem(item) {
1959
2469
  }
1960
2470
 
1961
2471
  // src/tools/load-skill.ts
2472
+ init_skills();
1962
2473
  import { tool as tool5 } from "ai";
1963
2474
  import { z as z6 } from "zod";
1964
-
1965
- // src/skills/index.ts
1966
- import { readFile as readFile6, readdir } from "fs/promises";
1967
- import { resolve as resolve6, basename, extname as extname3 } from "path";
1968
- import { existsSync as existsSync8 } from "fs";
1969
- function parseSkillFrontmatter(content) {
1970
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
1971
- if (!frontmatterMatch) {
1972
- return null;
1973
- }
1974
- const [, frontmatter, body] = frontmatterMatch;
1975
- try {
1976
- const lines = frontmatter.split("\n");
1977
- const data = {};
1978
- for (const line of lines) {
1979
- const colonIndex = line.indexOf(":");
1980
- if (colonIndex > 0) {
1981
- const key = line.slice(0, colonIndex).trim();
1982
- let value = line.slice(colonIndex + 1).trim();
1983
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1984
- value = value.slice(1, -1);
1985
- }
1986
- data[key] = value;
1987
- }
1988
- }
1989
- const metadata = SkillMetadataSchema.parse(data);
1990
- return { metadata, body: body.trim() };
1991
- } catch {
1992
- return null;
1993
- }
1994
- }
1995
- function getSkillNameFromPath(filePath) {
1996
- return basename(filePath, extname3(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
1997
- }
1998
- async function loadSkillsFromDirectory(directory) {
1999
- if (!existsSync8(directory)) {
2000
- return [];
2001
- }
2002
- const skills = [];
2003
- const files = await readdir(directory);
2004
- for (const file of files) {
2005
- if (!file.endsWith(".md")) continue;
2006
- const filePath = resolve6(directory, file);
2007
- const content = await readFile6(filePath, "utf-8");
2008
- const parsed = parseSkillFrontmatter(content);
2009
- if (parsed) {
2010
- skills.push({
2011
- name: parsed.metadata.name,
2012
- description: parsed.metadata.description,
2013
- filePath
2014
- });
2015
- } else {
2016
- const name = getSkillNameFromPath(filePath);
2017
- const firstParagraph = content.split("\n\n")[0]?.slice(0, 200) || "No description";
2018
- skills.push({
2019
- name,
2020
- description: firstParagraph.replace(/^#\s*/, "").trim(),
2021
- filePath
2022
- });
2023
- }
2024
- }
2025
- return skills;
2026
- }
2027
- async function loadAllSkills(directories) {
2028
- const allSkills = [];
2029
- const seenNames = /* @__PURE__ */ new Set();
2030
- for (const dir of directories) {
2031
- const skills = await loadSkillsFromDirectory(dir);
2032
- for (const skill of skills) {
2033
- if (!seenNames.has(skill.name.toLowerCase())) {
2034
- seenNames.add(skill.name.toLowerCase());
2035
- allSkills.push(skill);
2036
- }
2037
- }
2038
- }
2039
- return allSkills;
2040
- }
2041
- async function loadSkillContent(skillName, directories) {
2042
- const allSkills = await loadAllSkills(directories);
2043
- const skill = allSkills.find(
2044
- (s) => s.name.toLowerCase() === skillName.toLowerCase()
2045
- );
2046
- if (!skill) {
2047
- return null;
2048
- }
2049
- const content = await readFile6(skill.filePath, "utf-8");
2050
- const parsed = parseSkillFrontmatter(content);
2051
- return {
2052
- ...skill,
2053
- content: parsed ? parsed.body : content
2054
- };
2055
- }
2056
- function formatSkillsForContext(skills) {
2057
- if (skills.length === 0) {
2058
- return "No skills available.";
2059
- }
2060
- const lines = ["Available skills (use load_skill tool to load into context):"];
2061
- for (const skill of skills) {
2062
- lines.push(`- ${skill.name}: ${skill.description}`);
2063
- }
2064
- return lines.join("\n");
2065
- }
2066
-
2067
- // src/tools/load-skill.ts
2068
2475
  var loadSkillInputSchema = z6.object({
2069
2476
  action: z6.enum(["list", "load"]).describe('Action to perform: "list" to see available skills, "load" to load a skill'),
2070
2477
  skillName: z6.string().optional().describe('For "load" action: The name of the skill to load')
@@ -2147,7 +2554,7 @@ Once loaded, a skill's content will be available in the conversation context.`,
2147
2554
  // src/tools/linter.ts
2148
2555
  import { tool as tool6 } from "ai";
2149
2556
  import { z as z7 } from "zod";
2150
- import { resolve as resolve7, relative as relative4, isAbsolute as isAbsolute3, extname as extname4 } from "path";
2557
+ import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as extname4 } from "path";
2151
2558
  import { existsSync as existsSync9 } from "fs";
2152
2559
  import { readdir as readdir2, stat as stat2 } from "fs/promises";
2153
2560
  var linterInputSchema = z7.object({
@@ -2264,7 +2671,7 @@ function formatDiagnosticsResult(diagnosticsMap, workingDirectory) {
2264
2671
  let totalInfo = 0;
2265
2672
  const files = [];
2266
2673
  for (const [filePath, diagnostics] of Object.entries(diagnosticsMap)) {
2267
- const relativePath = relative4(workingDirectory, filePath);
2674
+ const relativePath = relative5(workingDirectory, filePath);
2268
2675
  let fileErrors = 0;
2269
2676
  let fileWarnings = 0;
2270
2677
  const formattedDiagnostics = diagnostics.map((d) => {
@@ -2337,6 +2744,621 @@ ${file.relativePath}:`);
2337
2744
  return lines.join("\n");
2338
2745
  }
2339
2746
 
2747
+ // src/tools/search.ts
2748
+ import { tool as tool8 } from "ai";
2749
+ import { z as z9 } from "zod";
2750
+
2751
+ // src/agent/subagent.ts
2752
+ import {
2753
+ generateText,
2754
+ stepCountIs
2755
+ } from "ai";
2756
+ import { nanoid as nanoid3 } from "nanoid";
2757
+ var Subagent = class {
2758
+ /** Model to use (defaults to gemini-2.0-flash) */
2759
+ model;
2760
+ /** Maximum steps before stopping */
2761
+ maxSteps = 20;
2762
+ constructor(model) {
2763
+ this.model = model || SUBAGENT_MODELS.default;
2764
+ }
2765
+ /**
2766
+ * Parse the final result from the subagent's output.
2767
+ * Override this to structure the result for your subagent type.
2768
+ */
2769
+ parseResult(text2, steps) {
2770
+ return { text: text2, steps };
2771
+ }
2772
+ /**
2773
+ * Run the subagent with streaming progress updates
2774
+ */
2775
+ async run(options) {
2776
+ const { task, sessionId, toolCallId, onProgress, abortSignal } = options;
2777
+ const steps = [];
2778
+ const execution = subagentQueries.create({
2779
+ sessionId,
2780
+ toolCallId,
2781
+ subagentType: this.type,
2782
+ task,
2783
+ model: this.model
2784
+ });
2785
+ const addStep = async (step) => {
2786
+ const fullStep = {
2787
+ id: nanoid3(8),
2788
+ timestamp: Date.now(),
2789
+ ...step
2790
+ };
2791
+ steps.push(fullStep);
2792
+ subagentQueries.addStep(execution.id, fullStep);
2793
+ await onProgress?.({
2794
+ type: "step",
2795
+ subagentId: execution.id,
2796
+ subagentType: this.type,
2797
+ step: fullStep
2798
+ });
2799
+ };
2800
+ try {
2801
+ const tools = this.getTools(options);
2802
+ const systemPrompt = this.getSystemPrompt(options);
2803
+ const result = await generateText({
2804
+ model: resolveModel(this.model),
2805
+ system: systemPrompt,
2806
+ messages: [
2807
+ { role: "user", content: task }
2808
+ ],
2809
+ tools,
2810
+ stopWhen: stepCountIs(this.maxSteps),
2811
+ abortSignal,
2812
+ onStepFinish: async (step) => {
2813
+ if (step.text) {
2814
+ await addStep({
2815
+ type: "text",
2816
+ content: step.text
2817
+ });
2818
+ await onProgress?.({
2819
+ type: "text",
2820
+ subagentId: execution.id,
2821
+ subagentType: this.type,
2822
+ text: step.text
2823
+ });
2824
+ }
2825
+ if (step.toolCalls) {
2826
+ for (const toolCall of step.toolCalls) {
2827
+ await addStep({
2828
+ type: "tool_call",
2829
+ content: `Calling ${toolCall.toolName}`,
2830
+ toolName: toolCall.toolName,
2831
+ toolInput: toolCall.input
2832
+ });
2833
+ await onProgress?.({
2834
+ type: "tool_call",
2835
+ subagentId: execution.id,
2836
+ subagentType: this.type,
2837
+ toolName: toolCall.toolName,
2838
+ toolInput: toolCall.input
2839
+ });
2840
+ }
2841
+ }
2842
+ if (step.toolResults) {
2843
+ for (const toolResult of step.toolResults) {
2844
+ await addStep({
2845
+ type: "tool_result",
2846
+ content: `Result from ${toolResult.toolName}`,
2847
+ toolName: toolResult.toolName,
2848
+ toolOutput: toolResult.output
2849
+ });
2850
+ await onProgress?.({
2851
+ type: "tool_result",
2852
+ subagentId: execution.id,
2853
+ subagentType: this.type,
2854
+ toolName: toolResult.toolName,
2855
+ toolOutput: toolResult.output
2856
+ });
2857
+ }
2858
+ }
2859
+ }
2860
+ });
2861
+ const parsedResult = this.parseResult(result.text, steps);
2862
+ subagentQueries.complete(execution.id, parsedResult);
2863
+ await onProgress?.({
2864
+ type: "complete",
2865
+ subagentId: execution.id,
2866
+ subagentType: this.type,
2867
+ result: parsedResult
2868
+ });
2869
+ return {
2870
+ success: true,
2871
+ result: parsedResult,
2872
+ steps,
2873
+ executionId: execution.id
2874
+ };
2875
+ } catch (error) {
2876
+ const errorMessage = error.message || "Unknown error";
2877
+ subagentQueries.markError(execution.id, errorMessage);
2878
+ await onProgress?.({
2879
+ type: "error",
2880
+ subagentId: execution.id,
2881
+ subagentType: this.type,
2882
+ error: errorMessage
2883
+ });
2884
+ return {
2885
+ success: false,
2886
+ error: errorMessage,
2887
+ steps,
2888
+ executionId: execution.id
2889
+ };
2890
+ }
2891
+ }
2892
+ /**
2893
+ * Run with streaming (for real-time progress in UI)
2894
+ */
2895
+ async *stream(options) {
2896
+ const events = [];
2897
+ let resolveNext = null;
2898
+ let done = false;
2899
+ const eventQueue = [];
2900
+ const runPromise = this.run({
2901
+ ...options,
2902
+ onProgress: async (event) => {
2903
+ eventQueue.push(event);
2904
+ if (resolveNext) {
2905
+ resolveNext(eventQueue.shift());
2906
+ resolveNext = null;
2907
+ }
2908
+ }
2909
+ }).then((result) => {
2910
+ done = true;
2911
+ if (resolveNext) {
2912
+ resolveNext(null);
2913
+ }
2914
+ return result;
2915
+ });
2916
+ while (!done || eventQueue.length > 0) {
2917
+ if (eventQueue.length > 0) {
2918
+ yield eventQueue.shift();
2919
+ } else if (!done) {
2920
+ const event = await new Promise((resolve9) => {
2921
+ resolveNext = resolve9;
2922
+ });
2923
+ if (event) {
2924
+ yield event;
2925
+ }
2926
+ }
2927
+ }
2928
+ await runPromise;
2929
+ }
2930
+ };
2931
+
2932
+ // src/agent/subagents/search.ts
2933
+ import { tool as tool7 } from "ai";
2934
+ import { z as z8 } from "zod";
2935
+ import { exec as exec4 } from "child_process";
2936
+ import { promisify as promisify4 } from "util";
2937
+ import { readFile as readFile7, stat as stat3, readdir as readdir3 } from "fs/promises";
2938
+ import { resolve as resolve8, relative as relative6, isAbsolute as isAbsolute4 } from "path";
2939
+ import { existsSync as existsSync10 } from "fs";
2940
+ var execAsync4 = promisify4(exec4);
2941
+ var MAX_OUTPUT_CHARS4 = 2e4;
2942
+ var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
2943
+ var SearchSubagent = class extends Subagent {
2944
+ type = "search";
2945
+ name = "Search Agent";
2946
+ constructor(model) {
2947
+ super(model || SUBAGENT_MODELS.search);
2948
+ this.maxSteps = 15;
2949
+ }
2950
+ getSystemPrompt(options) {
2951
+ return `You are a specialized search agent for exploring codebases. Your job is to find relevant code, files, and patterns based on the user's query.
2952
+
2953
+ Working Directory: ${options.workingDirectory}
2954
+
2955
+ You have these tools available:
2956
+ - grep: Search for patterns in files using ripgrep (rg)
2957
+ - glob: Find files matching a pattern
2958
+ - read_file: Read contents of a specific file
2959
+ - list_dir: List directory contents
2960
+
2961
+ ## Strategy - Search in Parallel
2962
+
2963
+ IMPORTANT: When searching, run MULTIPLE searches in PARALLEL to cover different variations and related terms. Don't search sequentially - batch your searches together!
2964
+
2965
+ For example, if asked "how does authentication work":
2966
+ - Search for "auth", "login", "session", "jwt", "token" all at once
2967
+ - Search in different likely directories: src/auth/, lib/auth/, services/auth/
2968
+ - Look for common patterns: AuthProvider, useAuth, authenticate, isAuthenticated
2969
+
2970
+ **Parallel Search Patterns:**
2971
+ 1. Try multiple naming conventions at once:
2972
+ - camelCase: "getUserData", "handleAuth"
2973
+ - snake_case: "get_user_data", "handle_auth"
2974
+ - PascalCase: "UserService", "AuthProvider"
2975
+
2976
+ 2. Search for related concepts together:
2977
+ - For "database": search "db", "database", "query", "model", "schema"
2978
+ - For "api": search "endpoint", "route", "handler", "controller", "api"
2979
+
2980
+ 3. Use glob AND grep together:
2981
+ - Find files: \`*.auth.ts\`, \`*Auth*.tsx\`, \`auth/*.ts\`
2982
+ - Search content: patterns, function names, class names
2983
+
2984
+ ## Execution Flow
2985
+ 1. First, run 2-4 parallel searches covering different angles of the query
2986
+ 2. Review results and identify the most relevant files
2987
+ 3. Read the key files to understand the full context
2988
+ 4. Provide a clear summary with exact file paths and line numbers
2989
+
2990
+ Be efficient - you have limited steps. Maximize coverage with parallel tool calls.
2991
+
2992
+ ## Output Format
2993
+ When done, provide a summary with:
2994
+ - Key files/locations found (with full paths)
2995
+ - Relevant code snippets showing the important parts
2996
+ - How the pieces connect together
2997
+
2998
+ Keep your responses concise and focused on actionable information.`;
2999
+ }
3000
+ getTools(options) {
3001
+ const workingDirectory = options.workingDirectory;
3002
+ return {
3003
+ grep: tool7({
3004
+ description: "Search for patterns in files using ripgrep. Returns matching lines with file paths and line numbers.",
3005
+ inputSchema: z8.object({
3006
+ pattern: z8.string().describe("The regex pattern to search for"),
3007
+ path: z8.string().optional().describe("Subdirectory or file to search in (relative to working directory)"),
3008
+ fileType: z8.string().optional().describe('File type to filter (e.g., "ts", "js", "py")'),
3009
+ maxResults: z8.number().optional().default(50).describe("Maximum number of results to return")
3010
+ }),
3011
+ execute: async ({ pattern, path, fileType, maxResults }) => {
3012
+ try {
3013
+ const searchPath = path ? resolve8(workingDirectory, path) : workingDirectory;
3014
+ let args = ["rg", "--line-number", "--no-heading"];
3015
+ if (fileType) {
3016
+ args.push("--type", fileType);
3017
+ }
3018
+ args.push("--max-count", String(maxResults || 50));
3019
+ args.push("--", pattern, searchPath);
3020
+ const { stdout, stderr } = await execAsync4(args.join(" "), {
3021
+ cwd: workingDirectory,
3022
+ maxBuffer: 5 * 1024 * 1024,
3023
+ timeout: 3e4
3024
+ });
3025
+ const output = truncateOutput(stdout || "No matches found", MAX_OUTPUT_CHARS4);
3026
+ const matchCount = (stdout || "").split("\n").filter(Boolean).length;
3027
+ return {
3028
+ success: true,
3029
+ output,
3030
+ matchCount,
3031
+ pattern
3032
+ };
3033
+ } catch (error) {
3034
+ if (error.code === 1 && !error.stderr) {
3035
+ return {
3036
+ success: true,
3037
+ output: "No matches found",
3038
+ matchCount: 0,
3039
+ pattern
3040
+ };
3041
+ }
3042
+ return {
3043
+ success: false,
3044
+ error: error.message,
3045
+ pattern
3046
+ };
3047
+ }
3048
+ }
3049
+ }),
3050
+ glob: tool7({
3051
+ description: "Find files matching a glob pattern. Returns list of matching file paths.",
3052
+ inputSchema: z8.object({
3053
+ pattern: z8.string().describe('Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json")'),
3054
+ maxResults: z8.number().optional().default(100).describe("Maximum number of files to return")
3055
+ }),
3056
+ execute: async ({ pattern, maxResults }) => {
3057
+ try {
3058
+ const { stdout } = await execAsync4(
3059
+ `find . -type f -name "${pattern.replace("**/", "")}" 2>/dev/null | head -n ${maxResults || 100}`,
3060
+ {
3061
+ cwd: workingDirectory,
3062
+ timeout: 3e4
3063
+ }
3064
+ );
3065
+ const files = stdout.trim().split("\n").filter(Boolean);
3066
+ return {
3067
+ success: true,
3068
+ files,
3069
+ count: files.length,
3070
+ pattern
3071
+ };
3072
+ } catch (error) {
3073
+ return {
3074
+ success: false,
3075
+ error: error.message,
3076
+ pattern
3077
+ };
3078
+ }
3079
+ }
3080
+ }),
3081
+ read_file: tool7({
3082
+ description: "Read the contents of a file. Use this to examine specific files found in search.",
3083
+ inputSchema: z8.object({
3084
+ path: z8.string().describe("Path to the file (relative to working directory or absolute)"),
3085
+ startLine: z8.number().optional().describe("Start reading from this line (1-indexed)"),
3086
+ endLine: z8.number().optional().describe("Stop reading at this line (1-indexed, inclusive)")
3087
+ }),
3088
+ execute: async ({ path, startLine, endLine }) => {
3089
+ try {
3090
+ const absolutePath = isAbsolute4(path) ? path : resolve8(workingDirectory, path);
3091
+ if (!existsSync10(absolutePath)) {
3092
+ return {
3093
+ success: false,
3094
+ error: `File not found: ${path}`
3095
+ };
3096
+ }
3097
+ const stats = await stat3(absolutePath);
3098
+ if (stats.size > MAX_FILE_SIZE2) {
3099
+ return {
3100
+ success: false,
3101
+ error: `File too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Use startLine/endLine to read portions.`
3102
+ };
3103
+ }
3104
+ let content = await readFile7(absolutePath, "utf-8");
3105
+ if (startLine !== void 0 || endLine !== void 0) {
3106
+ const lines = content.split("\n");
3107
+ const start = (startLine ?? 1) - 1;
3108
+ const end = endLine ?? lines.length;
3109
+ content = lines.slice(start, end).join("\n");
3110
+ }
3111
+ return {
3112
+ success: true,
3113
+ path: relative6(workingDirectory, absolutePath),
3114
+ content: truncateOutput(content, MAX_OUTPUT_CHARS4),
3115
+ lineCount: content.split("\n").length
3116
+ };
3117
+ } catch (error) {
3118
+ return {
3119
+ success: false,
3120
+ error: error.message
3121
+ };
3122
+ }
3123
+ }
3124
+ }),
3125
+ list_dir: tool7({
3126
+ description: "List contents of a directory. Shows files and subdirectories.",
3127
+ inputSchema: z8.object({
3128
+ path: z8.string().optional().default(".").describe("Directory path (relative to working directory)"),
3129
+ recursive: z8.boolean().optional().default(false).describe("List recursively (be careful with large directories)"),
3130
+ maxDepth: z8.number().optional().default(2).describe("Maximum depth for recursive listing")
3131
+ }),
3132
+ execute: async ({ path, recursive, maxDepth }) => {
3133
+ try {
3134
+ const absolutePath = isAbsolute4(path) ? path : resolve8(workingDirectory, path);
3135
+ if (!existsSync10(absolutePath)) {
3136
+ return {
3137
+ success: false,
3138
+ error: `Directory not found: ${path}`
3139
+ };
3140
+ }
3141
+ const stats = await stat3(absolutePath);
3142
+ if (!stats.isDirectory()) {
3143
+ return {
3144
+ success: false,
3145
+ error: `Not a directory: ${path}`
3146
+ };
3147
+ }
3148
+ if (recursive) {
3149
+ const { stdout } = await execAsync4(
3150
+ `find . -maxdepth ${maxDepth} -type f 2>/dev/null | head -n 200`,
3151
+ {
3152
+ cwd: absolutePath,
3153
+ timeout: 1e4
3154
+ }
3155
+ );
3156
+ const files = stdout.trim().split("\n").filter(Boolean);
3157
+ return {
3158
+ success: true,
3159
+ path: relative6(workingDirectory, absolutePath) || ".",
3160
+ files,
3161
+ count: files.length,
3162
+ recursive: true
3163
+ };
3164
+ } else {
3165
+ const entries = await readdir3(absolutePath, { withFileTypes: true });
3166
+ const items = entries.slice(0, 200).map((e) => ({
3167
+ name: e.name,
3168
+ type: e.isDirectory() ? "directory" : "file"
3169
+ }));
3170
+ return {
3171
+ success: true,
3172
+ path: relative6(workingDirectory, absolutePath) || ".",
3173
+ items,
3174
+ count: items.length
3175
+ };
3176
+ }
3177
+ } catch (error) {
3178
+ return {
3179
+ success: false,
3180
+ error: error.message
3181
+ };
3182
+ }
3183
+ }
3184
+ })
3185
+ };
3186
+ }
3187
+ parseResult(text2, steps) {
3188
+ const findings = [];
3189
+ let filesSearched = 0;
3190
+ let matchCount = 0;
3191
+ for (const step of steps) {
3192
+ if (step.type === "tool_result" && step.toolOutput) {
3193
+ const output = step.toolOutput;
3194
+ if (step.toolName === "grep" && output.success) {
3195
+ matchCount += output.matchCount || 0;
3196
+ const lines = (output.output || "").split("\n").filter(Boolean).slice(0, 10);
3197
+ for (const line of lines) {
3198
+ const match = line.match(/^([^:]+):(\d+):(.*)$/);
3199
+ if (match) {
3200
+ findings.push({
3201
+ type: "match",
3202
+ path: match[1],
3203
+ lineNumber: parseInt(match[2], 10),
3204
+ content: match[3].trim(),
3205
+ relevance: "high"
3206
+ });
3207
+ }
3208
+ }
3209
+ } else if (step.toolName === "glob" && output.success) {
3210
+ filesSearched += output.count || 0;
3211
+ for (const file of (output.files || []).slice(0, 5)) {
3212
+ findings.push({
3213
+ type: "file",
3214
+ path: file,
3215
+ relevance: "medium"
3216
+ });
3217
+ }
3218
+ } else if (step.toolName === "read_file" && output.success) {
3219
+ findings.push({
3220
+ type: "file",
3221
+ path: output.path,
3222
+ relevance: "high",
3223
+ context: `${output.lineCount} lines`
3224
+ });
3225
+ }
3226
+ }
3227
+ }
3228
+ const query = steps.length > 0 ? steps.find((s) => s.type === "text")?.content || "" : "";
3229
+ return {
3230
+ query,
3231
+ summary: text2,
3232
+ findings: findings.slice(0, 20),
3233
+ // Limit findings
3234
+ filesSearched,
3235
+ matchCount
3236
+ };
3237
+ }
3238
+ };
3239
+ function createSearchSubagent(model) {
3240
+ return new SearchSubagent(model);
3241
+ }
3242
+
3243
+ // src/tools/search.ts
3244
+ var MAX_RESULT_CHARS = 8e3;
3245
+ function createSearchTool(options) {
3246
+ return tool8({
3247
+ description: `Delegate a search task to a specialized search agent. Use this when you need to:
3248
+ - Find files or code matching a pattern
3249
+ - Explore the codebase structure
3250
+ - Search for specific functions, classes, or variables
3251
+ - Understand how a feature is implemented
3252
+
3253
+ The search agent will explore the codebase and return a summary of findings.
3254
+ This is more thorough than a simple grep because it can follow references and understand context.
3255
+
3256
+ Examples:
3257
+ - "Find all React components that use the useState hook"
3258
+ - "Where is the authentication logic implemented?"
3259
+ - "Find all API routes and their handlers"
3260
+ - "Search for usages of the UserService class"`,
3261
+ inputSchema: z9.object({
3262
+ query: z9.string().describe("What to search for. Be specific about what you're looking for."),
3263
+ context: z9.string().optional().describe("Optional additional context about why you need this information.")
3264
+ }),
3265
+ execute: async ({ query, context }, toolOptions) => {
3266
+ const toolCallId = toolOptions.toolCallId || `search_${Date.now()}`;
3267
+ await options.onProgress?.({
3268
+ status: "started",
3269
+ subagentId: toolCallId
3270
+ });
3271
+ try {
3272
+ const subagent = createSearchSubagent();
3273
+ const fullTask = context ? `${query}
3274
+
3275
+ Context: ${context}` : query;
3276
+ const result = await subagent.run({
3277
+ task: fullTask,
3278
+ sessionId: options.sessionId,
3279
+ toolCallId,
3280
+ workingDirectory: options.workingDirectory,
3281
+ onProgress: async (event) => {
3282
+ if (event.type === "step" && event.step) {
3283
+ await options.onProgress?.({
3284
+ status: "step",
3285
+ subagentId: event.subagentId,
3286
+ stepType: event.step.type,
3287
+ stepContent: event.step.content,
3288
+ toolName: event.step.toolName,
3289
+ toolInput: event.step.toolInput,
3290
+ toolOutput: event.step.toolOutput
3291
+ });
3292
+ } else if (event.type === "complete") {
3293
+ await options.onProgress?.({
3294
+ status: "complete",
3295
+ subagentId: event.subagentId,
3296
+ result: event.result
3297
+ });
3298
+ } else if (event.type === "error") {
3299
+ await options.onProgress?.({
3300
+ status: "error",
3301
+ subagentId: event.subagentId,
3302
+ error: event.error
3303
+ });
3304
+ }
3305
+ }
3306
+ });
3307
+ if (!result.success) {
3308
+ return {
3309
+ success: false,
3310
+ error: result.error || "Search failed",
3311
+ executionId: result.executionId
3312
+ };
3313
+ }
3314
+ const searchResult = result.result;
3315
+ let formattedResult = `## Search Results
3316
+
3317
+ `;
3318
+ formattedResult += `**Summary:** ${searchResult.summary}
3319
+
3320
+ `;
3321
+ if (searchResult.findings.length > 0) {
3322
+ formattedResult += `### Key Findings (${searchResult.findings.length} items)
3323
+
3324
+ `;
3325
+ for (const finding of searchResult.findings) {
3326
+ if (finding.type === "match") {
3327
+ formattedResult += `- **${finding.path}:${finding.lineNumber}** - ${truncateOutput(finding.content || "", 200)}
3328
+ `;
3329
+ } else if (finding.type === "file") {
3330
+ formattedResult += `- **${finding.path}** ${finding.context ? `(${finding.context})` : ""}
3331
+ `;
3332
+ }
3333
+ }
3334
+ }
3335
+ formattedResult += `
3336
+ **Stats:** ${searchResult.matchCount} matches across ${searchResult.filesSearched} files searched`;
3337
+ return {
3338
+ success: true,
3339
+ query: searchResult.query,
3340
+ summary: searchResult.summary,
3341
+ findings: searchResult.findings,
3342
+ matchCount: searchResult.matchCount,
3343
+ filesSearched: searchResult.filesSearched,
3344
+ formattedResult: truncateOutput(formattedResult, MAX_RESULT_CHARS),
3345
+ executionId: result.executionId,
3346
+ stepsCount: result.steps.length
3347
+ };
3348
+ } catch (error) {
3349
+ await options.onProgress?.({
3350
+ status: "error",
3351
+ error: error.message
3352
+ });
3353
+ return {
3354
+ success: false,
3355
+ error: error.message
3356
+ };
3357
+ }
3358
+ }
3359
+ });
3360
+ }
3361
+
2340
3362
  // src/tools/index.ts
2341
3363
  function createTools(options) {
2342
3364
  return {
@@ -2352,7 +3374,8 @@ function createTools(options) {
2352
3374
  write_file: createWriteFileTool({
2353
3375
  workingDirectory: options.workingDirectory,
2354
3376
  sessionId: options.sessionId,
2355
- enableLSP: options.enableLSP ?? true
3377
+ enableLSP: options.enableLSP ?? true,
3378
+ onProgress: options.onWriteFileProgress
2356
3379
  }),
2357
3380
  todo: createTodoTool({
2358
3381
  sessionId: options.sessionId
@@ -2363,15 +3386,20 @@ function createTools(options) {
2363
3386
  }),
2364
3387
  linter: createLinterTool({
2365
3388
  workingDirectory: options.workingDirectory
3389
+ }),
3390
+ search: createSearchTool({
3391
+ sessionId: options.sessionId,
3392
+ workingDirectory: options.workingDirectory,
3393
+ onProgress: options.onSearchProgress
2366
3394
  })
2367
3395
  };
2368
3396
  }
2369
3397
 
2370
3398
  // src/agent/context.ts
2371
- import { generateText } from "ai";
2372
- import { gateway } from "@ai-sdk/gateway";
3399
+ import { generateText as generateText2 } from "ai";
2373
3400
 
2374
3401
  // src/agent/prompts.ts
3402
+ init_skills();
2375
3403
  import os from "os";
2376
3404
  function getSearchInstructions() {
2377
3405
  const platform2 = process.platform;
@@ -2390,9 +3418,33 @@ function getSearchInstructions() {
2390
3418
  - **If ripgrep (\`rg\`) is installed**: \`rg "pattern" -t ts src/\` - faster and respects .gitignore`;
2391
3419
  }
2392
3420
  async function buildSystemPrompt(options) {
2393
- const { workingDirectory, skillsDirectories, sessionId, customInstructions } = options;
2394
- const skills = await loadAllSkills(skillsDirectories);
2395
- const skillsContext = formatSkillsForContext(skills);
3421
+ const {
3422
+ workingDirectory,
3423
+ skillsDirectories,
3424
+ sessionId,
3425
+ discoveredSkills,
3426
+ activeFiles = [],
3427
+ customInstructions
3428
+ } = options;
3429
+ let alwaysLoadedContent = "";
3430
+ let globMatchedContent = "";
3431
+ let agentsMdContent = "";
3432
+ let onDemandSkillsContext = "";
3433
+ if (discoveredSkills) {
3434
+ const { always, onDemand, all } = await loadAllSkillsFromDiscovered(discoveredSkills);
3435
+ alwaysLoadedContent = formatAlwaysLoadedSkills(always);
3436
+ onDemandSkillsContext = formatSkillsForContext(onDemand);
3437
+ const agentsMd = await loadAgentsMd(discoveredSkills.agentsMdPath);
3438
+ agentsMdContent = formatAgentsMdContent(agentsMd);
3439
+ if (activeFiles.length > 0) {
3440
+ const globMatched = await getGlobMatchedSkills(all, activeFiles, workingDirectory);
3441
+ globMatchedContent = formatGlobMatchedSkills(globMatched);
3442
+ }
3443
+ } else {
3444
+ const { loadAllSkills: loadAllSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
3445
+ const skills = await loadAllSkills2(skillsDirectories);
3446
+ onDemandSkillsContext = formatSkillsForContext(skills);
3447
+ }
2396
3448
  const todos = todoQueries.getBySession(sessionId);
2397
3449
  const todosContext = formatTodosForContext(todos);
2398
3450
  const platform2 = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
@@ -2413,6 +3465,7 @@ You have access to powerful tools for:
2413
3465
  - **linter**: Check files for type errors and lint issues (TypeScript, JavaScript, TSX, JSX)
2414
3466
  - **todo**: Manage your task list to track progress on complex operations
2415
3467
  - **load_skill**: Load specialized knowledge documents for specific tasks
3468
+ - **search**: Semantic search using a subagent - for exploratory questions and finding code by meaning
2416
3469
 
2417
3470
 
2418
3471
  IMPORTANT: If you have zero context of where you are working, always explore it first to understand the structure before doing things for the user.
@@ -2489,6 +3542,9 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
2489
3542
  - Use \`write_file\` with mode "full" only for new files or complete rewrites
2490
3543
  - After making changes, use the \`linter\` tool to check for type errors and lint issues
2491
3544
  - The \`write_file\` tool automatically shows lint errors in its output for TypeScript/JavaScript files
3545
+ - If the user asks to write/create a file, always use \`write_file\` rather than printing the full contents
3546
+ - If the user requests a file but does not provide a path, choose a sensible default (e.g. \`index.html\`) and proceed
3547
+ - For large content (hundreds of lines), avoid placing it in chat output; write to a file instead
2492
3548
 
2493
3549
  ### Linter Tool
2494
3550
  The linter tool uses Language Server Protocol (LSP) to detect type errors and lint issues:
@@ -2500,6 +3556,30 @@ linter({ paths: ["src/"] }) // Check all files in a directory
2500
3556
  Use this proactively after making code changes to catch errors early.
2501
3557
 
2502
3558
  ### Searching and Exploration
3559
+
3560
+ **Choose the right search approach:**
3561
+
3562
+ 1. **Use the \`search\` tool (subagent)** for:
3563
+ - Semantic/exploratory questions: "How does authentication work?", "Where is user data processed?"
3564
+ - Finding code by meaning or concept, not exact text
3565
+ - Understanding how features are implemented across multiple files
3566
+ - Exploring unfamiliar parts of the codebase
3567
+ - Questions like "where", "how", "what does X do"
3568
+
3569
+ The search subagent is a mini-agent that intelligently explores the codebase, reads relevant files, and returns a summary of what it found. It's best for understanding and discovery.
3570
+
3571
+ 2. **Use direct commands (grep/rg, find)** for:
3572
+ - Exact string matches: \`rg "functionName"\`, \`rg "class MyClass"\`
3573
+ - Finding files by name: \`find . -name "*.config.ts"\`
3574
+ - Simple pattern matching when you know exactly what you're looking for
3575
+ - Counting occurrences or listing all matches
3576
+
3577
+ **Examples:**
3578
+ - "Where is the API authentication handled?" \u2192 Use \`search\` tool
3579
+ - "Find all usages of getUserById" \u2192 Use \`rg "getUserById"\`
3580
+ - "How does the payment flow work?" \u2192 Use \`search\` tool
3581
+ - "Find files named config" \u2192 Use \`find . -name "*config*"\`
3582
+
2503
3583
  ${searchInstructions}
2504
3584
 
2505
3585
  ###Follow these principles when designing and implementing software:
@@ -2522,11 +3602,11 @@ ${searchInstructions}
2522
3602
  16. **Diversity** \u2014 Distrust all claims for "one true way"
2523
3603
  17. **Extensibility** \u2014 Design for the future, because it will be here sooner than you think
2524
3604
 
2525
- ###Follow these ruls to be a good agent for the user:
3605
+ ### Follow these rules to be a good agent for the user:
2526
3606
 
2527
- 1. Understand first - Read relevant files before making any changes. Use search tools to explore the codebase and understand the existing patterns and structure.
3607
+ 1. Understand first - Read relevant files before making any changes. Use the \`search\` tool for exploratory questions about how things work, and direct searches (grep/rg) for finding exact strings or file names.
2528
3608
  2. Plan for complexity - If the task involves 3+ steps or has meaningful trade-offs, create a todo list to track progress before implementing.
2529
- 3. Use the right tools - Have specialized tools for reading files, editing code, searching by pattern , running terminal commands, and more. Prefer these over raw shell commands.
3609
+ 3. Use the right tools - Have specialized tools for reading files, editing code, semantic search via subagents, and running terminal commands. Prefer these over raw shell commands.
2530
3610
  4. Work efficiently - When need to do multiple independent things (like reading several files), do them in parallel rather than one at a time.
2531
3611
  5. Be direct - Focus on technical accuracy rather than validation. If see issues with an approach or need clarification, say so.
2532
3612
  6. Verify my work - After making changes, check for linter errors and fix any introduced.
@@ -2539,8 +3619,14 @@ ${searchInstructions}
2539
3619
  - Ask clarifying questions when requirements are ambiguous
2540
3620
  - Report progress on multi-step tasks
2541
3621
 
2542
- ## Skills
2543
- ${skillsContext}
3622
+ ${agentsMdContent}
3623
+
3624
+ ${alwaysLoadedContent}
3625
+
3626
+ ${globMatchedContent}
3627
+
3628
+ ## On-Demand Skills
3629
+ ${onDemandSkillsContext}
2544
3630
 
2545
3631
  ## Current Task List
2546
3632
  ${todosContext}
@@ -2635,8 +3721,8 @@ ${this.summary}`
2635
3721
  try {
2636
3722
  const config = getConfig();
2637
3723
  const summaryPrompt = createSummaryPrompt(historyText);
2638
- const result = await generateText({
2639
- model: gateway(config.defaultModel),
3724
+ const result = await generateText2({
3725
+ model: resolveModel(config.defaultModel),
2640
3726
  prompt: summaryPrompt
2641
3727
  });
2642
3728
  this.summary = result.text;
@@ -2706,7 +3792,9 @@ var Agent = class _Agent {
2706
3792
  sessionId: this.session.id,
2707
3793
  workingDirectory: this.session.workingDirectory,
2708
3794
  skillsDirectories: config.resolvedSkillsDirectories,
2709
- onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0
3795
+ onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
3796
+ onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
3797
+ onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "search", data: progress }) : void 0
2710
3798
  });
2711
3799
  }
2712
3800
  /**
@@ -2815,28 +3903,33 @@ ${prompt}` });
2815
3903
  const systemPrompt = await buildSystemPrompt({
2816
3904
  workingDirectory: this.session.workingDirectory,
2817
3905
  skillsDirectories: config.resolvedSkillsDirectories,
2818
- sessionId: this.session.id
3906
+ sessionId: this.session.id,
3907
+ discoveredSkills: config.discoveredSkills,
3908
+ // TODO: Pass activeFiles from client for glob matching
3909
+ activeFiles: []
2819
3910
  });
2820
3911
  const messages2 = await this.context.getMessages();
2821
3912
  const tools = options.onToolProgress ? this.createToolsWithCallbacks({ onToolProgress: options.onToolProgress }) : this.baseTools;
2822
3913
  const wrappedTools = this.wrapToolsWithApproval(options, tools);
2823
- const stream = streamText({
2824
- model: gateway2(this.session.model),
3914
+ const useAnthropic = isAnthropicModel(this.session.model);
3915
+ const stream = streamText2({
3916
+ model: resolveModel(this.session.model),
2825
3917
  system: systemPrompt,
2826
3918
  messages: messages2,
2827
3919
  tools: wrappedTools,
2828
- stopWhen: stepCountIs(500),
3920
+ stopWhen: stepCountIs2(500),
2829
3921
  // Forward abort signal if provided
2830
3922
  abortSignal: options.abortSignal,
2831
3923
  // Enable extended thinking/reasoning for models that support it
2832
- providerOptions: {
3924
+ providerOptions: useAnthropic ? {
2833
3925
  anthropic: {
3926
+ toolStreaming: true,
2834
3927
  thinking: {
2835
3928
  type: "enabled",
2836
3929
  budgetTokens: 1e4
2837
3930
  }
2838
3931
  }
2839
- },
3932
+ } : void 0,
2840
3933
  onStepFinish: async (step) => {
2841
3934
  options.onStepFinish?.(step);
2842
3935
  },
@@ -2866,26 +3959,29 @@ ${prompt}` });
2866
3959
  const systemPrompt = await buildSystemPrompt({
2867
3960
  workingDirectory: this.session.workingDirectory,
2868
3961
  skillsDirectories: config.resolvedSkillsDirectories,
2869
- sessionId: this.session.id
3962
+ sessionId: this.session.id,
3963
+ discoveredSkills: config.discoveredSkills,
3964
+ activeFiles: []
2870
3965
  });
2871
3966
  const messages2 = await this.context.getMessages();
2872
3967
  const tools = options.onToolProgress ? this.createToolsWithCallbacks({ onToolProgress: options.onToolProgress }) : this.baseTools;
2873
3968
  const wrappedTools = this.wrapToolsWithApproval(options, tools);
2874
- const result = await generateText2({
2875
- model: gateway2(this.session.model),
3969
+ const useAnthropic = isAnthropicModel(this.session.model);
3970
+ const result = await generateText3({
3971
+ model: resolveModel(this.session.model),
2876
3972
  system: systemPrompt,
2877
3973
  messages: messages2,
2878
3974
  tools: wrappedTools,
2879
- stopWhen: stepCountIs(500),
3975
+ stopWhen: stepCountIs2(500),
2880
3976
  // Enable extended thinking/reasoning for models that support it
2881
- providerOptions: {
3977
+ providerOptions: useAnthropic ? {
2882
3978
  anthropic: {
2883
3979
  thinking: {
2884
3980
  type: "enabled",
2885
3981
  budgetTokens: 1e4
2886
3982
  }
2887
3983
  }
2888
- }
3984
+ } : void 0
2889
3985
  });
2890
3986
  const responseMessages = result.response.messages;
2891
3987
  this.context.addResponseMessages(responseMessages);
@@ -2907,11 +4003,11 @@ ${prompt}` });
2907
4003
  wrappedTools[name] = originalTool;
2908
4004
  continue;
2909
4005
  }
2910
- wrappedTools[name] = tool7({
4006
+ wrappedTools[name] = tool9({
2911
4007
  description: originalTool.description || "",
2912
- inputSchema: originalTool.inputSchema || z8.object({}),
4008
+ inputSchema: originalTool.inputSchema || z10.object({}),
2913
4009
  execute: async (input, toolOptions) => {
2914
- const toolCallId = toolOptions.toolCallId || nanoid3();
4010
+ const toolCallId = toolOptions.toolCallId || nanoid4();
2915
4011
  const execution = toolExecutionQueries.create({
2916
4012
  sessionId: this.session.id,
2917
4013
  toolName: name,
@@ -2923,8 +4019,8 @@ ${prompt}` });
2923
4019
  this.pendingApprovals.set(toolCallId, execution);
2924
4020
  options.onApprovalRequired?.(execution);
2925
4021
  sessionQueries.updateStatus(this.session.id, "waiting");
2926
- const approved = await new Promise((resolve8) => {
2927
- approvalResolvers.set(toolCallId, { resolve: resolve8, sessionId: this.session.id });
4022
+ const approved = await new Promise((resolve9) => {
4023
+ approvalResolvers.set(toolCallId, { resolve: resolve9, sessionId: this.session.id });
2928
4024
  });
2929
4025
  const resolverData = approvalResolvers.get(toolCallId);
2930
4026
  approvalResolvers.delete(toolCallId);