sparkecoder 0.1.59 → 0.1.61

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 (179) hide show
  1. package/dist/agent/index.d.ts +4 -3
  2. package/dist/agent/index.js +662 -203
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +906 -129
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +3 -2
  7. package/dist/db/index.js.map +1 -1
  8. package/dist/{index-Csad1Nx4.d.ts → index-DuGtMaAJ.d.ts} +85 -4
  9. package/dist/index.d.ts +6 -5
  10. package/dist/index.js +1302 -711
  11. package/dist/index.js.map +1 -1
  12. package/dist/schema-C7Mm4Ykn.d.ts +1410 -0
  13. package/dist/{search-BETuS1vh.d.ts → search-C_IFImt1.d.ts} +3 -3
  14. package/dist/server/index.js +692 -101
  15. package/dist/server/index.js.map +1 -1
  16. package/dist/skills/default/browser.md +143 -0
  17. package/dist/skills/default/code-review.md +122 -0
  18. package/dist/skills/default/debugging.md +105 -0
  19. package/dist/skills/default/refactoring.md +197 -0
  20. package/dist/tools/index.d.ts +54 -4
  21. package/dist/tools/index.js +304 -29
  22. package/dist/tools/index.js.map +1 -1
  23. package/package.json +6 -1
  24. package/src/skills/default/browser.md +143 -0
  25. package/src/skills/default/code-review.md +122 -0
  26. package/src/skills/default/debugging.md +105 -0
  27. package/src/skills/default/refactoring.md +197 -0
  28. package/web/.next/BUILD_ID +1 -1
  29. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  30. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  31. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  32. package/web/.next/standalone/web/.next/server/app/(main)/page.js.nft.json +1 -1
  33. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  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.html +2 -2
  37. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  44. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  45. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  46. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  47. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  49. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  52. package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
  53. package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  56. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
  57. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
  58. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
  61. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  67. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
  68. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  71. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
  72. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  77. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
  79. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  81. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
  82. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  86. package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
  87. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
  88. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  90. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  91. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
  94. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  95. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  96. package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
  97. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  98. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  99. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
  100. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  101. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  102. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  103. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_19289e11._.js → 2374f_03d22c16._.js} +1 -1
  104. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b4b86c1f._.js → 2374f_0d0b1fb9._.js} +1 -1
  105. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_4858a1ea._.js → 2374f_3f7d6d28._.js} +1 -1
  106. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_51385fed._.js → 2374f_6166d14d._.js} +1 -1
  107. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_40e35a02._.js → 2374f_67b9525f._.js} +1 -1
  108. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_fb95e3c9._.js → 2374f_6b436efc._.js} +1 -1
  109. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_2f0d9f6f._.js → 2374f_784d851c._.js} +1 -1
  110. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_35475cbe._.js → 2374f_976b2ded._.js} +1 -1
  111. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_7db22cde._.js → 2374f_98eba491._.js} +1 -1
  112. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_90b8e4fb._.js → 2374f_99b7b533._.js} +1 -1
  113. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_4666c827._.js → 2374f_a1a36483._.js} +1 -1
  114. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_076f03ec._.js → 2374f_b98835eb._.js} +1 -1
  115. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b17fce11._.js → 2374f_e19eaecc._.js} +1 -1
  116. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d8b9ce38._.js → 2374f_e3aec189._.js} +1 -1
  117. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__7775f784._.js → [root-of-the-server]__4f176a16._.js} +2 -2
  118. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__d59f831d._.js +15 -0
  119. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_645f4b90._.js → web_693f514e._.js} +2 -2
  120. package/web/.next/standalone/web/.next/server/chunks/ssr/web_a42a2651._.js +7 -0
  121. package/web/.next/standalone/web/.next/server/chunks/ssr/web_dc6ce793._.js +7 -0
  122. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
  123. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  124. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  125. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  126. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  127. package/web/.next/standalone/web/.next/static/chunks/0358a0e7a40cfb93.css +1 -0
  128. package/web/.next/standalone/web/.next/static/chunks/1ecde4c0d426a635.js +1 -0
  129. package/web/.next/standalone/web/.next/static/chunks/20e0fa99c7a1c1fc.js +13 -0
  130. package/web/.next/standalone/web/.next/static/chunks/36688a049d72e8ab.js +5 -0
  131. package/web/.next/standalone/web/.next/static/chunks/95436454a7559b0d.js +7 -0
  132. package/web/.next/standalone/web/.next/static/chunks/a751ca474cc46212.js +5 -0
  133. package/web/.next/standalone/web/.next/static/static/chunks/0358a0e7a40cfb93.css +1 -0
  134. package/web/.next/standalone/web/.next/static/static/chunks/1ecde4c0d426a635.js +1 -0
  135. package/web/.next/standalone/web/.next/static/static/chunks/20e0fa99c7a1c1fc.js +13 -0
  136. package/web/.next/standalone/web/.next/static/static/chunks/36688a049d72e8ab.js +5 -0
  137. package/web/.next/standalone/web/.next/static/static/chunks/95436454a7559b0d.js +7 -0
  138. package/web/.next/standalone/web/.next/static/static/chunks/a751ca474cc46212.js +5 -0
  139. package/web/.next/standalone/web/src/components/ai-elements/complete-task-tool.tsx +126 -0
  140. package/web/.next/standalone/web/src/components/chat-interface.tsx +68 -3
  141. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +18 -1
  142. package/web/.next/standalone/web/src/lib/api.ts +12 -0
  143. package/web/.next/static/chunks/0358a0e7a40cfb93.css +1 -0
  144. package/web/.next/static/chunks/1ecde4c0d426a635.js +1 -0
  145. package/web/.next/static/chunks/20e0fa99c7a1c1fc.js +13 -0
  146. package/web/.next/static/chunks/36688a049d72e8ab.js +5 -0
  147. package/web/.next/static/chunks/95436454a7559b0d.js +7 -0
  148. package/web/.next/static/chunks/a751ca474cc46212.js +5 -0
  149. package/dist/schema-NcQknWCg.d.ts +0 -295
  150. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__bd396152._.js +0 -15
  151. package/web/.next/standalone/web/.next/server/chunks/ssr/web_9c9f0e3b._.js +0 -7
  152. package/web/.next/standalone/web/.next/server/chunks/ssr/web_d08270f7._.js +0 -7
  153. package/web/.next/standalone/web/.next/static/chunks/2868b007ce5163fc.css +0 -1
  154. package/web/.next/standalone/web/.next/static/chunks/3f295b6960943c38.js +0 -1
  155. package/web/.next/standalone/web/.next/static/chunks/631b023d37a08635.js +0 -13
  156. package/web/.next/standalone/web/.next/static/chunks/a2b4737b190d1b54.js +0 -5
  157. package/web/.next/standalone/web/.next/static/chunks/e97212fcc8221479.js +0 -5
  158. package/web/.next/standalone/web/.next/static/chunks/f6e47c8a9766ce91.js +0 -7
  159. package/web/.next/standalone/web/.next/static/static/chunks/2868b007ce5163fc.css +0 -1
  160. package/web/.next/standalone/web/.next/static/static/chunks/3f295b6960943c38.js +0 -1
  161. package/web/.next/standalone/web/.next/static/static/chunks/631b023d37a08635.js +0 -13
  162. package/web/.next/standalone/web/.next/static/static/chunks/a2b4737b190d1b54.js +0 -5
  163. package/web/.next/standalone/web/.next/static/static/chunks/e97212fcc8221479.js +0 -5
  164. package/web/.next/standalone/web/.next/static/static/chunks/f6e47c8a9766ce91.js +0 -7
  165. package/web/.next/static/chunks/2868b007ce5163fc.css +0 -1
  166. package/web/.next/static/chunks/3f295b6960943c38.js +0 -1
  167. package/web/.next/static/chunks/631b023d37a08635.js +0 -13
  168. package/web/.next/static/chunks/a2b4737b190d1b54.js +0 -5
  169. package/web/.next/static/chunks/e97212fcc8221479.js +0 -5
  170. package/web/.next/static/chunks/f6e47c8a9766ce91.js +0 -7
  171. /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
  172. /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
  173. /package/web/.next/standalone/web/.next/static/{static/u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
  174. /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
  175. /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
  176. /package/web/.next/standalone/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → static/8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
  177. /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
  178. /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
  179. /package/web/.next/static/{u5qqIWWrYpWW_mZUgKKjg → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
 
11
11
  // src/config/types.ts
12
12
  import { z } from "zod";
13
- var ToolApprovalConfigSchema, SkillMetadataSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
13
+ var ToolApprovalConfigSchema, SkillMetadataSchema, TaskConfigSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
14
14
  var init_types = __esm({
15
15
  "src/config/types.ts"() {
16
16
  "use strict";
@@ -29,11 +29,22 @@ var init_types = __esm({
29
29
  // Glob patterns - auto-inject when working with matching files
30
30
  globs: z.array(z.string()).optional().default([])
31
31
  });
32
+ TaskConfigSchema = z.object({
33
+ enabled: z.boolean(),
34
+ outputSchema: z.record(z.string(), z.unknown()),
35
+ webhookUrl: z.string().url().optional(),
36
+ maxIterations: z.number().optional(),
37
+ status: z.enum(["running", "completed", "failed"]),
38
+ result: z.unknown().optional(),
39
+ error: z.string().optional(),
40
+ iterations: z.number().optional()
41
+ });
32
42
  SessionConfigSchema = z.object({
33
43
  toolApprovals: z.record(z.string(), z.boolean()).optional(),
34
44
  approvalWebhook: z.string().url().optional(),
35
45
  skillsDirectory: z.string().optional(),
36
- maxContextChars: z.number().optional().default(2e5)
46
+ maxContextChars: z.number().optional().default(2e5),
47
+ task: TaskConfigSchema.optional()
37
48
  });
38
49
  VectorGatewayConfigSchema = z.object({
39
50
  // Redis cluster nodes URL for Vector Gateway (or use REDIS_CLUSTER_NODES env var)
@@ -426,7 +437,7 @@ var init_hasher = __esm({
426
437
  });
427
438
 
428
439
  // src/semantic/chunker.ts
429
- import { extname as extname5, basename as basename2 } from "path";
440
+ import { extname as extname6, basename as basename2 } from "path";
430
441
  var init_chunker = __esm({
431
442
  "src/semantic/chunker.ts"() {
432
443
  "use strict";
@@ -1296,26 +1307,41 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
1296
1307
  import { tool as tool2 } from "ai";
1297
1308
  import { z as z3 } from "zod";
1298
1309
  import { readFile as readFile2, stat } from "fs/promises";
1299
- import { resolve as resolve2, relative, isAbsolute } from "path";
1310
+ import { resolve as resolve2, relative, isAbsolute, extname } from "path";
1300
1311
  import { existsSync as existsSync3 } from "fs";
1301
1312
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
1313
+ var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
1302
1314
  var MAX_OUTPUT_CHARS3 = 5e4;
1315
+ var IMAGE_EXTENSIONS = {
1316
+ ".png": "image/png",
1317
+ ".jpg": "image/jpeg",
1318
+ ".jpeg": "image/jpeg",
1319
+ ".gif": "image/gif",
1320
+ ".webp": "image/webp"
1321
+ };
1322
+ function isImageFile(filePath) {
1323
+ return extname(filePath).toLowerCase() in IMAGE_EXTENSIONS;
1324
+ }
1325
+ function getImageMediaType(filePath) {
1326
+ return IMAGE_EXTENSIONS[extname(filePath).toLowerCase()] || "image/png";
1327
+ }
1303
1328
  var readFileInputSchema = z3.object({
1304
- path: z3.string().describe("The path to the file to read. Can be relative to working directory or absolute."),
1305
- startLine: z3.number().optional().describe("Optional: Start reading from this line number (1-indexed)"),
1306
- endLine: z3.number().optional().describe("Optional: Stop reading at this line number (1-indexed, inclusive)")
1329
+ path: z3.string().describe("The path to the file to read. Can be relative to working directory or absolute. Supports text files and images (png, jpg, jpeg, gif, webp)."),
1330
+ startLine: z3.number().optional().describe("Optional: Start reading from this line number (1-indexed). Only for text files."),
1331
+ endLine: z3.number().optional().describe("Optional: Stop reading at this line number (1-indexed, inclusive). Only for text files.")
1307
1332
  });
1308
1333
  function createReadFileTool(options) {
1309
1334
  return tool2({
1310
1335
  description: `Read the contents of a file. Provide a path relative to the working directory (${options.workingDirectory}) or an absolute path.
1311
- Large files will be automatically truncated. Binary files are not supported.
1312
- Use this to understand existing code, check file contents, or gather context.`,
1336
+ Supports text files (automatically truncated if large) and image files (png, jpg, jpeg, gif, webp).
1337
+ For images, the file contents are returned as visual data you can see and analyze.
1338
+ Use this to understand existing code, check file contents, view screenshots, or gather context.`,
1313
1339
  inputSchema: readFileInputSchema,
1314
- execute: async ({ path, startLine, endLine }) => {
1340
+ execute: async ({ path: filePath, startLine, endLine }) => {
1315
1341
  try {
1316
- const absolutePath = isAbsolute(path) ? path : resolve2(options.workingDirectory, path);
1342
+ const absolutePath = isAbsolute(filePath) ? filePath : resolve2(options.workingDirectory, filePath);
1317
1343
  const relativePath = relative(options.workingDirectory, absolutePath);
1318
- if (relativePath.startsWith("..") && !isAbsolute(path)) {
1344
+ if (relativePath.startsWith("..") && !isAbsolute(filePath)) {
1319
1345
  return {
1320
1346
  success: false,
1321
1347
  error: "Path escapes the working directory. Use an absolute path if intentional.",
@@ -1325,22 +1351,43 @@ Use this to understand existing code, check file contents, or gather context.`,
1325
1351
  if (!existsSync3(absolutePath)) {
1326
1352
  return {
1327
1353
  success: false,
1328
- error: `File not found: ${path}`,
1354
+ error: `File not found: ${filePath}`,
1329
1355
  content: null
1330
1356
  };
1331
1357
  }
1332
1358
  const stats = await stat(absolutePath);
1333
- if (stats.size > MAX_FILE_SIZE) {
1359
+ if (stats.isDirectory()) {
1334
1360
  return {
1335
1361
  success: false,
1336
- error: `File is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_FILE_SIZE / 1024 / 1024}MB.`,
1362
+ error: 'Path is a directory, not a file. Use bash with "ls" to list directory contents.',
1337
1363
  content: null
1338
1364
  };
1339
1365
  }
1340
- if (stats.isDirectory()) {
1366
+ if (isImageFile(absolutePath)) {
1367
+ if (stats.size > MAX_IMAGE_SIZE) {
1368
+ return {
1369
+ success: false,
1370
+ error: `Image is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_IMAGE_SIZE / 1024 / 1024}MB.`,
1371
+ content: null
1372
+ };
1373
+ }
1374
+ const buffer = await readFile2(absolutePath);
1375
+ const base64 = buffer.toString("base64");
1376
+ const mediaType = getImageMediaType(absolutePath);
1377
+ return {
1378
+ success: true,
1379
+ path: absolutePath,
1380
+ relativePath: relative(options.workingDirectory, absolutePath),
1381
+ content: `[Image: ${relativePath} (${mediaType}, ${(stats.size / 1024).toFixed(1)}KB)]`,
1382
+ mediaType,
1383
+ imageData: base64,
1384
+ sizeBytes: stats.size
1385
+ };
1386
+ }
1387
+ if (stats.size > MAX_FILE_SIZE) {
1341
1388
  return {
1342
1389
  success: false,
1343
- error: 'Path is a directory, not a file. Use bash with "ls" to list directory contents.',
1390
+ error: `File is too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum size is ${MAX_FILE_SIZE / 1024 / 1024}MB.`,
1344
1391
  content: null
1345
1392
  };
1346
1393
  }
@@ -1356,9 +1403,7 @@ Use this to understand existing code, check file contents, or gather context.`,
1356
1403
  content: null
1357
1404
  };
1358
1405
  }
1359
- content = lines.slice(start, end).join("\n");
1360
- const lineNumbers = lines.slice(start, end).map((line, idx) => `${(start + idx + 1).toString().padStart(4)}: ${line}`).join("\n");
1361
- content = lineNumbers;
1406
+ content = lines.slice(start, end).map((line, idx) => `${(start + idx + 1).toString().padStart(4)}: ${line}`).join("\n");
1362
1407
  }
1363
1408
  const truncatedContent = truncateOutput(content, MAX_OUTPUT_CHARS3);
1364
1409
  const wasTruncated = truncatedContent.length < content.length;
@@ -1385,6 +1430,19 @@ Use this to understand existing code, check file contents, or gather context.`,
1385
1430
  content: null
1386
1431
  };
1387
1432
  }
1433
+ },
1434
+ toModelOutput: ({ output }) => {
1435
+ if (output && typeof output === "object" && "imageData" in output && output.imageData) {
1436
+ const result = output;
1437
+ return {
1438
+ type: "content",
1439
+ value: [
1440
+ { type: "text", text: result.content },
1441
+ { type: "image-data", data: result.imageData, mediaType: result.mediaType }
1442
+ ]
1443
+ };
1444
+ }
1445
+ return typeof output === "string" ? { type: "text", value: output } : { type: "json", value: output };
1388
1446
  }
1389
1447
  });
1390
1448
  }
@@ -1449,7 +1507,7 @@ async function backupFile(sessionId, workingDirectory, filePath) {
1449
1507
  }
1450
1508
 
1451
1509
  // src/lsp/index.ts
1452
- import { extname as extname2, dirname as dirname4 } from "path";
1510
+ import { extname as extname3, dirname as dirname4 } from "path";
1453
1511
 
1454
1512
  // src/lsp/servers.ts
1455
1513
  import { spawn } from "child_process";
@@ -1572,9 +1630,9 @@ import {
1572
1630
  import { pathToFileURL, fileURLToPath } from "url";
1573
1631
  import { readFile as readFile4 } from "fs/promises";
1574
1632
  import { existsSync as existsSync6 } from "fs";
1575
- import { extname, normalize } from "path";
1633
+ import { extname as extname2, normalize } from "path";
1576
1634
  function getLanguageId(filePath) {
1577
- const ext = extname(filePath).toLowerCase();
1635
+ const ext = extname2(filePath).toLowerCase();
1578
1636
  const map = {
1579
1637
  ".ts": "typescript",
1580
1638
  ".tsx": "typescriptreact",
@@ -1962,7 +2020,7 @@ var state = {
1962
2020
  };
1963
2021
  async function getClientForFile(filePath) {
1964
2022
  const normalized = normalizePath(filePath);
1965
- const ext = extname2(normalized);
2023
+ const ext = extname3(normalized);
1966
2024
  const serverDef = getServerForExtension(ext);
1967
2025
  if (!serverDef) {
1968
2026
  return null;
@@ -2055,7 +2113,7 @@ async function formatDiagnosticsOutput(filePath, options = {}) {
2055
2113
  return formatDiagnosticsForAgent(filePath, diagnostics, options);
2056
2114
  }
2057
2115
  function isSupported(filePath) {
2058
- const ext = extname2(filePath);
2116
+ const ext = extname3(filePath);
2059
2117
  return getServerForExtension(ext) !== null;
2060
2118
  }
2061
2119
 
@@ -2402,7 +2460,7 @@ import { z as z6 } from "zod";
2402
2460
  // src/skills/index.ts
2403
2461
  init_types();
2404
2462
  import { readFile as readFile6, readdir } from "fs/promises";
2405
- import { resolve as resolve6, basename, extname as extname3, relative as relative4 } from "path";
2463
+ import { resolve as resolve6, basename, extname as extname4, relative as relative4 } from "path";
2406
2464
  import { existsSync as existsSync8 } from "fs";
2407
2465
  import { minimatch } from "minimatch";
2408
2466
  function parseSkillFrontmatter(content) {
@@ -2473,7 +2531,7 @@ function parseSkillFrontmatter(content) {
2473
2531
  }
2474
2532
  }
2475
2533
  function getSkillNameFromPath(filePath) {
2476
- return basename(filePath, extname3(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2534
+ return basename(filePath, extname4(filePath)).replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2477
2535
  }
2478
2536
  async function loadSkillsFromDirectory(directory, options = {}) {
2479
2537
  const {
@@ -2661,7 +2719,7 @@ Once loaded, a skill's content will be available in the conversation context.`,
2661
2719
  // src/tools/linter.ts
2662
2720
  import { tool as tool6 } from "ai";
2663
2721
  import { z as z7 } from "zod";
2664
- import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as extname4 } from "path";
2722
+ import { resolve as resolve7, relative as relative5, isAbsolute as isAbsolute3, extname as extname5 } from "path";
2665
2723
  import { existsSync as existsSync9 } from "fs";
2666
2724
  import { readdir as readdir2, stat as stat2 } from "fs/promises";
2667
2725
  var linterInputSchema = z7.object({
@@ -2684,7 +2742,7 @@ async function findSupportedFiles(dir, workingDirectory, maxFiles = 50) {
2684
2742
  }
2685
2743
  await walk(fullPath);
2686
2744
  } else if (entry.isFile()) {
2687
- const ext = extname4(entry.name);
2745
+ const ext = extname5(entry.name);
2688
2746
  if (supportedExtensions.includes(ext)) {
2689
2747
  files.push(fullPath);
2690
2748
  }
@@ -2864,7 +2922,165 @@ import { nanoid as nanoid2 } from "nanoid";
2864
2922
 
2865
2923
  // src/agent/model.ts
2866
2924
  import { gateway } from "@ai-sdk/gateway";
2925
+
2926
+ // src/agent/remote-model.ts
2927
+ function serializePrompt(prompt) {
2928
+ return prompt.map((msg) => {
2929
+ if (!Array.isArray(msg.content)) return msg;
2930
+ return {
2931
+ ...msg,
2932
+ content: msg.content.map((part) => {
2933
+ if (part.type === "file" && part.data instanceof Uint8Array) {
2934
+ return {
2935
+ ...part,
2936
+ data: Buffer.from(part.data).toString("base64"),
2937
+ _base64: true
2938
+ };
2939
+ }
2940
+ return part;
2941
+ })
2942
+ };
2943
+ });
2944
+ }
2945
+ function deserializeValue(value) {
2946
+ if (value && typeof value === "object") {
2947
+ if (value.__uint8array && typeof value.data === "string") {
2948
+ return Buffer.from(value.data, "base64");
2949
+ }
2950
+ if (Array.isArray(value)) {
2951
+ return value.map(deserializeValue);
2952
+ }
2953
+ const result = {};
2954
+ for (const [k, v] of Object.entries(value)) {
2955
+ result[k] = deserializeValue(v);
2956
+ }
2957
+ return result;
2958
+ }
2959
+ return value;
2960
+ }
2961
+ function prepareOptions(options) {
2962
+ const { abortSignal, ...rest } = options;
2963
+ return {
2964
+ ...rest,
2965
+ prompt: serializePrompt(options.prompt)
2966
+ };
2967
+ }
2968
+ function createRemoteModel(modelId, config) {
2969
+ const baseUrl = config.url.replace(/\/$/, "");
2970
+ const headers = {
2971
+ "Content-Type": "application/json",
2972
+ "Authorization": `Bearer ${config.authKey}`
2973
+ };
2974
+ return {
2975
+ specificationVersion: "v3",
2976
+ provider: "remote-proxy",
2977
+ modelId,
2978
+ supportedUrls: {},
2979
+ async doGenerate(options) {
2980
+ const res = await fetch(`${baseUrl}/inference/generate`, {
2981
+ method: "POST",
2982
+ headers,
2983
+ body: JSON.stringify({
2984
+ modelId,
2985
+ options: prepareOptions(options)
2986
+ }),
2987
+ signal: options.abortSignal
2988
+ });
2989
+ if (!res.ok) {
2990
+ const err = await res.json().catch(() => ({}));
2991
+ throw new Error(
2992
+ `Remote inference failed (${res.status}): ${err.error || res.statusText}`
2993
+ );
2994
+ }
2995
+ const result = await res.json();
2996
+ return deserializeValue(result);
2997
+ },
2998
+ async doStream(options) {
2999
+ const res = await fetch(`${baseUrl}/inference/stream`, {
3000
+ method: "POST",
3001
+ headers,
3002
+ body: JSON.stringify({
3003
+ modelId,
3004
+ options: prepareOptions(options)
3005
+ }),
3006
+ signal: options.abortSignal
3007
+ });
3008
+ if (!res.ok) {
3009
+ const err = await res.json().catch(() => ({}));
3010
+ throw new Error(
3011
+ `Remote inference failed (${res.status}): ${err.error || res.statusText}`
3012
+ );
3013
+ }
3014
+ const reader = res.body.getReader();
3015
+ const decoder = new TextDecoder();
3016
+ let buffer = "";
3017
+ const stream = new ReadableStream({
3018
+ async pull(controller) {
3019
+ while (true) {
3020
+ const { done, value } = await reader.read();
3021
+ if (done) {
3022
+ if (buffer.trim()) {
3023
+ try {
3024
+ const parsed = deserializeValue(JSON.parse(buffer.trim()));
3025
+ if (parsed.type === "error") {
3026
+ controller.error(new Error(parsed.error));
3027
+ } else {
3028
+ controller.enqueue(parsed);
3029
+ }
3030
+ } catch {
3031
+ }
3032
+ }
3033
+ controller.close();
3034
+ return;
3035
+ }
3036
+ buffer += decoder.decode(value, { stream: true });
3037
+ const lines = buffer.split("\n");
3038
+ buffer = lines.pop() || "";
3039
+ for (const line of lines) {
3040
+ if (!line.trim()) continue;
3041
+ try {
3042
+ const parsed = deserializeValue(JSON.parse(line));
3043
+ if (parsed.type === "error") {
3044
+ controller.error(new Error(parsed.error));
3045
+ return;
3046
+ }
3047
+ controller.enqueue(parsed);
3048
+ } catch {
3049
+ }
3050
+ }
3051
+ }
3052
+ },
3053
+ cancel() {
3054
+ reader.cancel();
3055
+ }
3056
+ });
3057
+ const responseHeaders = {};
3058
+ res.headers.forEach((v, k) => {
3059
+ if (k.startsWith("x-upstream-")) {
3060
+ responseHeaders[k.replace("x-upstream-", "")] = v;
3061
+ }
3062
+ });
3063
+ return {
3064
+ stream,
3065
+ response: Object.keys(responseHeaders).length > 0 ? { headers: responseHeaders } : void 0
3066
+ };
3067
+ }
3068
+ };
3069
+ }
3070
+
3071
+ // src/agent/model.ts
3072
+ init_config();
2867
3073
  function resolveModel(modelId) {
3074
+ try {
3075
+ const config = getConfig();
3076
+ if (config.resolvedRemoteServer.isConfigured) {
3077
+ return createRemoteModel(modelId.trim(), {
3078
+ url: config.resolvedRemoteServer.url,
3079
+ authKey: config.resolvedRemoteServer.authKey
3080
+ });
3081
+ }
3082
+ } catch {
3083
+ }
2868
3084
  return gateway(modelId.trim());
2869
3085
  }
2870
3086
  var SUBAGENT_MODELS = {
@@ -4034,6 +4250,59 @@ Context: ${context}` : query;
4034
4250
 
4035
4251
  // src/tools/index.ts
4036
4252
  init_semantic_search();
4253
+
4254
+ // src/tools/task.ts
4255
+ import { tool as tool11 } from "ai";
4256
+ import { z as z12 } from "zod";
4257
+ import Ajv from "ajv";
4258
+ var ajv = new Ajv({ allErrors: true });
4259
+ function createCompleteTaskTool(options) {
4260
+ const validate = ajv.compile(options.outputSchema);
4261
+ return tool11({
4262
+ description: "Call this tool when you have completed the task. Pass the result as a JSON object matching the required output schema. If the result does not match the schema, you will receive validation errors and should fix and retry.",
4263
+ inputSchema: z12.object({
4264
+ result: z12.record(z12.string(), z12.unknown()).describe("The task result as a JSON object matching the output schema")
4265
+ }),
4266
+ execute: async (input) => {
4267
+ const valid = validate(input.result);
4268
+ if (!valid) {
4269
+ const errors = validate.errors?.map((e) => ({
4270
+ path: e.instancePath || "/",
4271
+ message: e.message,
4272
+ params: e.params
4273
+ }));
4274
+ return {
4275
+ status: "validation_error",
4276
+ message: "The result does not match the required output schema. Fix the errors and call complete_task again.",
4277
+ errors,
4278
+ expectedSchema: options.outputSchema
4279
+ };
4280
+ }
4281
+ options.onComplete({ status: "completed", result: input.result });
4282
+ return {
4283
+ status: "completed",
4284
+ message: "Task completed successfully."
4285
+ };
4286
+ }
4287
+ });
4288
+ }
4289
+ function createTaskFailedTool(options) {
4290
+ return tool11({
4291
+ description: "Call this tool if you are unable to complete the task. Provide a clear reason explaining why the task cannot be completed.",
4292
+ inputSchema: z12.object({
4293
+ reason: z12.string().describe("Explanation of why the task cannot be completed")
4294
+ }),
4295
+ execute: async (input) => {
4296
+ options.onComplete({ status: "failed", error: input.reason });
4297
+ return {
4298
+ status: "failed",
4299
+ message: `Task marked as failed: ${input.reason}`
4300
+ };
4301
+ }
4302
+ });
4303
+ }
4304
+
4305
+ // src/tools/index.ts
4037
4306
  init_semantic();
4038
4307
  init_semantic_search();
4039
4308
  async function createTools(options) {
@@ -4085,16 +4354,22 @@ async function createTools(options) {
4085
4354
  } catch {
4086
4355
  }
4087
4356
  }
4357
+ if (options.taskTools) {
4358
+ tools.complete_task = createCompleteTaskTool(options.taskTools);
4359
+ tools.task_failed = createTaskFailedTool(options.taskTools);
4360
+ }
4088
4361
  return tools;
4089
4362
  }
4090
4363
  export {
4091
4364
  createBashTool,
4092
4365
  createCodeGraphTool,
4366
+ createCompleteTaskTool,
4093
4367
  createLinterTool,
4094
4368
  createLoadSkillTool,
4095
4369
  createReadFileTool,
4096
4370
  createSearchTool,
4097
4371
  createSemanticSearchTool,
4372
+ createTaskFailedTool,
4098
4373
  createTodoTool,
4099
4374
  createTools,
4100
4375
  createWriteFileTool