@vedangiitb/qwintly-core 1.0.2

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 (226) hide show
  1. package/README.md +8 -0
  2. package/dist/ai/ai.d.ts +2 -0
  3. package/dist/ai/ai.d.ts.map +1 -0
  4. package/dist/ai/ai.js +2 -0
  5. package/dist/ai/ai.js.map +1 -0
  6. package/dist/ai/generate/gemini.client.d.ts +15 -0
  7. package/dist/ai/generate/gemini.client.d.ts.map +1 -0
  8. package/dist/ai/generate/gemini.client.js +39 -0
  9. package/dist/ai/generate/gemini.client.js.map +1 -0
  10. package/dist/ai/generate/generateClient.d.ts +3 -0
  11. package/dist/ai/generate/generateClient.d.ts.map +1 -0
  12. package/dist/ai/generate/generateClient.js +8 -0
  13. package/dist/ai/generate/generateClient.js.map +1 -0
  14. package/dist/ai/toolLoop/toolLoopContext.d.ts +33 -0
  15. package/dist/ai/toolLoop/toolLoopContext.d.ts.map +1 -0
  16. package/dist/ai/toolLoop/toolLoopContext.js +112 -0
  17. package/dist/ai/toolLoop/toolLoopContext.js.map +1 -0
  18. package/dist/ai/toolLoop/toolLoopRunner.d.ts +43 -0
  19. package/dist/ai/toolLoop/toolLoopRunner.d.ts.map +1 -0
  20. package/dist/ai/toolLoop/toolLoopRunner.js +227 -0
  21. package/dist/ai/toolLoop/toolLoopRunner.js.map +1 -0
  22. package/dist/ai/toolLoop/toolLoopRunnerUtils.d.ts +51 -0
  23. package/dist/ai/toolLoop/toolLoopRunnerUtils.d.ts.map +1 -0
  24. package/dist/ai/toolLoop/toolLoopRunnerUtils.js +164 -0
  25. package/dist/ai/toolLoop/toolLoopRunnerUtils.js.map +1 -0
  26. package/dist/ai/tools/helpers/applyPatch.helpers.d.ts +36 -0
  27. package/dist/ai/tools/helpers/applyPatch.helpers.d.ts.map +1 -0
  28. package/dist/ai/tools/helpers/applyPatch.helpers.js +307 -0
  29. package/dist/ai/tools/helpers/applyPatch.helpers.js.map +1 -0
  30. package/dist/ai/tools/helpers/applyPatch.helpers.test.d.ts +2 -0
  31. package/dist/ai/tools/helpers/applyPatch.helpers.test.d.ts.map +1 -0
  32. package/dist/ai/tools/helpers/applyPatch.helpers.test.js +50 -0
  33. package/dist/ai/tools/helpers/applyPatch.helpers.test.js.map +1 -0
  34. package/dist/ai/tools/helpers/fileSystem.helpers.d.ts +2 -0
  35. package/dist/ai/tools/helpers/fileSystem.helpers.d.ts.map +1 -0
  36. package/dist/ai/tools/helpers/fileSystem.helpers.js +45 -0
  37. package/dist/ai/tools/helpers/fileSystem.helpers.js.map +1 -0
  38. package/dist/ai/tools/helpers/fileSystem.helpers.test.d.ts +2 -0
  39. package/dist/ai/tools/helpers/fileSystem.helpers.test.d.ts.map +1 -0
  40. package/dist/ai/tools/helpers/fileSystem.helpers.test.js +15 -0
  41. package/dist/ai/tools/helpers/fileSystem.helpers.test.js.map +1 -0
  42. package/dist/ai/tools/helpers/format.helpers.d.ts +2 -0
  43. package/dist/ai/tools/helpers/format.helpers.d.ts.map +1 -0
  44. package/dist/ai/tools/helpers/format.helpers.js +14 -0
  45. package/dist/ai/tools/helpers/format.helpers.js.map +1 -0
  46. package/dist/ai/tools/helpers/nextRouteFilePolicy.d.ts +8 -0
  47. package/dist/ai/tools/helpers/nextRouteFilePolicy.d.ts.map +1 -0
  48. package/dist/ai/tools/helpers/nextRouteFilePolicy.js +26 -0
  49. package/dist/ai/tools/helpers/nextRouteFilePolicy.js.map +1 -0
  50. package/dist/ai/tools/implementations/applyPatch.impl.d.ts +53 -0
  51. package/dist/ai/tools/implementations/applyPatch.impl.d.ts.map +1 -0
  52. package/dist/ai/tools/implementations/applyPatch.impl.js +242 -0
  53. package/dist/ai/tools/implementations/applyPatch.impl.js.map +1 -0
  54. package/dist/ai/tools/implementations/applyPatch.impl.test.d.ts +2 -0
  55. package/dist/ai/tools/implementations/applyPatch.impl.test.d.ts.map +1 -0
  56. package/dist/ai/tools/implementations/applyPatch.impl.test.js +72 -0
  57. package/dist/ai/tools/implementations/applyPatch.impl.test.js.map +1 -0
  58. package/dist/ai/tools/implementations/factories.d.ts +90 -0
  59. package/dist/ai/tools/implementations/factories.d.ts.map +1 -0
  60. package/dist/ai/tools/implementations/factories.js +26 -0
  61. package/dist/ai/tools/implementations/factories.js.map +1 -0
  62. package/dist/ai/tools/implementations/listDir.impl.d.ts +3 -0
  63. package/dist/ai/tools/implementations/listDir.impl.d.ts.map +1 -0
  64. package/dist/ai/tools/implementations/listDir.impl.js +47 -0
  65. package/dist/ai/tools/implementations/listDir.impl.js.map +1 -0
  66. package/dist/ai/tools/implementations/readFile.impl.d.ts +3 -0
  67. package/dist/ai/tools/implementations/readFile.impl.d.ts.map +1 -0
  68. package/dist/ai/tools/implementations/readFile.impl.js +23 -0
  69. package/dist/ai/tools/implementations/readFile.impl.js.map +1 -0
  70. package/dist/ai/tools/implementations/search.impl.d.ts +18 -0
  71. package/dist/ai/tools/implementations/search.impl.d.ts.map +1 -0
  72. package/dist/ai/tools/implementations/search.impl.js +74 -0
  73. package/dist/ai/tools/implementations/search.impl.js.map +1 -0
  74. package/dist/ai/tools/implementations/workspaceDeps.d.ts +22 -0
  75. package/dist/ai/tools/implementations/workspaceDeps.d.ts.map +1 -0
  76. package/dist/ai/tools/implementations/workspaceDeps.js +2 -0
  77. package/dist/ai/tools/implementations/workspaceDeps.js.map +1 -0
  78. package/dist/ai/tools/implementations/writeFile.impl.d.ts +27 -0
  79. package/dist/ai/tools/implementations/writeFile.impl.d.ts.map +1 -0
  80. package/dist/ai/tools/implementations/writeFile.impl.js +62 -0
  81. package/dist/ai/tools/implementations/writeFile.impl.js.map +1 -0
  82. package/dist/ai/tools/schemas/applyPatch.schema.d.ts +16 -0
  83. package/dist/ai/tools/schemas/applyPatch.schema.d.ts.map +1 -0
  84. package/dist/ai/tools/schemas/applyPatch.schema.js +17 -0
  85. package/dist/ai/tools/schemas/applyPatch.schema.js.map +1 -0
  86. package/dist/ai/tools/schemas/listDir.schema.d.ts +22 -0
  87. package/dist/ai/tools/schemas/listDir.schema.d.ts.map +1 -0
  88. package/dist/ai/tools/schemas/listDir.schema.js +22 -0
  89. package/dist/ai/tools/schemas/listDir.schema.js.map +1 -0
  90. package/dist/ai/tools/schemas/readFile.schema.d.ts +26 -0
  91. package/dist/ai/tools/schemas/readFile.schema.d.ts.map +1 -0
  92. package/dist/ai/tools/schemas/readFile.schema.js +26 -0
  93. package/dist/ai/tools/schemas/readFile.schema.js.map +1 -0
  94. package/dist/ai/tools/schemas/search.schema.d.ts +16 -0
  95. package/dist/ai/tools/schemas/search.schema.d.ts.map +1 -0
  96. package/dist/ai/tools/schemas/search.schema.js +16 -0
  97. package/dist/ai/tools/schemas/search.schema.js.map +1 -0
  98. package/dist/ai/tools/schemas/submitCodegenDone.schema.d.ts +16 -0
  99. package/dist/ai/tools/schemas/submitCodegenDone.schema.d.ts.map +1 -0
  100. package/dist/ai/tools/schemas/submitCodegenDone.schema.js +16 -0
  101. package/dist/ai/tools/schemas/submitCodegenDone.schema.js.map +1 -0
  102. package/dist/ai/tools/schemas/submitPlannerTasks.schema.d.ts +33 -0
  103. package/dist/ai/tools/schemas/submitPlannerTasks.schema.d.ts.map +1 -0
  104. package/dist/ai/tools/schemas/submitPlannerTasks.schema.js +31 -0
  105. package/dist/ai/tools/schemas/submitPlannerTasks.schema.js.map +1 -0
  106. package/dist/ai/tools/schemas/writeFile.schema.d.ts +20 -0
  107. package/dist/ai/tools/schemas/writeFile.schema.d.ts.map +1 -0
  108. package/dist/ai/tools/schemas/writeFile.schema.js +23 -0
  109. package/dist/ai/tools/schemas/writeFile.schema.js.map +1 -0
  110. package/dist/ai/tools/toolsets/codegenTools.d.ts +3 -0
  111. package/dist/ai/tools/toolsets/codegenTools.d.ts.map +1 -0
  112. package/dist/ai/tools/toolsets/codegenTools.js +17 -0
  113. package/dist/ai/tools/toolsets/codegenTools.js.map +1 -0
  114. package/dist/ai/tools/toolsets/plannerTools.d.ts +3 -0
  115. package/dist/ai/tools/toolsets/plannerTools.d.ts.map +1 -0
  116. package/dist/ai/tools/toolsets/plannerTools.js +17 -0
  117. package/dist/ai/tools/toolsets/plannerTools.js.map +1 -0
  118. package/dist/core.d.ts +44 -0
  119. package/dist/core.d.ts.map +1 -0
  120. package/dist/core.js +80 -0
  121. package/dist/core.js.map +1 -0
  122. package/dist/index.d.ts +2 -0
  123. package/dist/index.d.ts.map +1 -0
  124. package/dist/index.js +3 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/indexer/codegenIndex.d.ts +3 -0
  127. package/dist/indexer/codegenIndex.d.ts.map +1 -0
  128. package/dist/indexer/codegenIndex.js +17 -0
  129. package/dist/indexer/codegenIndex.js.map +1 -0
  130. package/dist/indexer/data/configs.constants.d.ts +85 -0
  131. package/dist/indexer/data/configs.constants.d.ts.map +1 -0
  132. package/dist/indexer/data/configs.constants.js +136 -0
  133. package/dist/indexer/data/configs.constants.js.map +1 -0
  134. package/dist/indexer/helpers/buildFolderTree.d.ts +2 -0
  135. package/dist/indexer/helpers/buildFolderTree.d.ts.map +1 -0
  136. package/dist/indexer/helpers/buildFolderTree.js +40 -0
  137. package/dist/indexer/helpers/buildFolderTree.js.map +1 -0
  138. package/dist/indexer/plannerIndex.d.ts +3 -0
  139. package/dist/indexer/plannerIndex.d.ts.map +1 -0
  140. package/dist/indexer/plannerIndex.js +20 -0
  141. package/dist/indexer/plannerIndex.js.map +1 -0
  142. package/dist/indexer/projectInfoIndex.d.ts +3 -0
  143. package/dist/indexer/projectInfoIndex.d.ts.map +1 -0
  144. package/dist/indexer/projectInfoIndex.js +257 -0
  145. package/dist/indexer/projectInfoIndex.js.map +1 -0
  146. package/dist/indexer/validatorIndex.d.ts +3 -0
  147. package/dist/indexer/validatorIndex.d.ts.map +1 -0
  148. package/dist/indexer/validatorIndex.js +14 -0
  149. package/dist/indexer/validatorIndex.js.map +1 -0
  150. package/dist/lib/redis.d.ts +3 -0
  151. package/dist/lib/redis.d.ts.map +1 -0
  152. package/dist/lib/redis.js +7 -0
  153. package/dist/lib/redis.js.map +1 -0
  154. package/dist/lib/supabase.d.ts +2 -0
  155. package/dist/lib/supabase.d.ts.map +1 -0
  156. package/dist/lib/supabase.js +4 -0
  157. package/dist/lib/supabase.js.map +1 -0
  158. package/dist/logging/genStatus.service.d.ts +14 -0
  159. package/dist/logging/genStatus.service.d.ts.map +1 -0
  160. package/dist/logging/genStatus.service.js +36 -0
  161. package/dist/logging/genStatus.service.js.map +1 -0
  162. package/dist/logging/logging.utils.d.ts +12 -0
  163. package/dist/logging/logging.utils.d.ts.map +1 -0
  164. package/dist/logging/logging.utils.js +15 -0
  165. package/dist/logging/logging.utils.js.map +1 -0
  166. package/dist/logging/redis.service.d.ts +11 -0
  167. package/dist/logging/redis.service.d.ts.map +1 -0
  168. package/dist/logging/redis.service.js +26 -0
  169. package/dist/logging/redis.service.js.map +1 -0
  170. package/dist/repository/context.repository.d.ts +8 -0
  171. package/dist/repository/context.repository.d.ts.map +1 -0
  172. package/dist/repository/context.repository.js +59 -0
  173. package/dist/repository/context.repository.js.map +1 -0
  174. package/dist/repository/genStatus.repository.d.ts +13 -0
  175. package/dist/repository/genStatus.repository.d.ts.map +1 -0
  176. package/dist/repository/genStatus.repository.js +18 -0
  177. package/dist/repository/genStatus.repository.js.map +1 -0
  178. package/dist/repository/planTasks.repository.d.ts +9 -0
  179. package/dist/repository/planTasks.repository.d.ts.map +1 -0
  180. package/dist/repository/planTasks.repository.js +24 -0
  181. package/dist/repository/planTasks.repository.js.map +1 -0
  182. package/dist/repository/repository.d.ts +5 -0
  183. package/dist/repository/repository.d.ts.map +1 -0
  184. package/dist/repository/repository.js +7 -0
  185. package/dist/repository/repository.js.map +1 -0
  186. package/dist/types/context.types.d.ts +64 -0
  187. package/dist/types/context.types.d.ts.map +1 -0
  188. package/dist/types/context.types.js +55 -0
  189. package/dist/types/context.types.js.map +1 -0
  190. package/dist/types/events.d.ts +16 -0
  191. package/dist/types/events.d.ts.map +1 -0
  192. package/dist/types/events.js +14 -0
  193. package/dist/types/events.js.map +1 -0
  194. package/dist/types/index/configs.types.d.ts +28 -0
  195. package/dist/types/index/configs.types.d.ts.map +1 -0
  196. package/dist/types/index/configs.types.js +2 -0
  197. package/dist/types/index/configs.types.js.map +1 -0
  198. package/dist/types/index/conventions.types.d.ts +40 -0
  199. package/dist/types/index/conventions.types.d.ts.map +1 -0
  200. package/dist/types/index/conventions.types.js +2 -0
  201. package/dist/types/index/conventions.types.js.map +1 -0
  202. package/dist/types/index/index.types.d.ts +16 -0
  203. package/dist/types/index/index.types.d.ts.map +1 -0
  204. package/dist/types/index/index.types.js +2 -0
  205. package/dist/types/index/index.types.js.map +1 -0
  206. package/dist/types/index/indexing.types.d.ts +9 -0
  207. package/dist/types/index/indexing.types.d.ts.map +1 -0
  208. package/dist/types/index/indexing.types.js +2 -0
  209. package/dist/types/index/indexing.types.js.map +1 -0
  210. package/dist/types/projectInfo.types.d.ts +16 -0
  211. package/dist/types/projectInfo.types.d.ts.map +1 -0
  212. package/dist/types/projectInfo.types.js +2 -0
  213. package/dist/types/projectInfo.types.js.map +1 -0
  214. package/dist/types/updatePlan.types.d.ts +34 -0
  215. package/dist/types/updatePlan.types.d.ts.map +1 -0
  216. package/dist/types/updatePlan.types.js +18 -0
  217. package/dist/types/updatePlan.types.js.map +1 -0
  218. package/dist/utils/utils.d.ts +2 -0
  219. package/dist/utils/utils.d.ts.map +1 -0
  220. package/dist/utils/utils.js +6 -0
  221. package/dist/utils/utils.js.map +1 -0
  222. package/dist/utils/workspace.d.ts +13 -0
  223. package/dist/utils/workspace.d.ts.map +1 -0
  224. package/dist/utils/workspace.js +92 -0
  225. package/dist/utils/workspace.js.map +1 -0
  226. package/package.json +58 -0
@@ -0,0 +1,72 @@
1
+ import assert from "node:assert/strict";
2
+ import path from "node:path";
3
+ import test from "node:test";
4
+ import { createApplyPatchImpl } from "./applyPatch.impl.js";
5
+ const enoent = (message) => {
6
+ const err = new Error(message);
7
+ err.code = "ENOENT";
8
+ return err;
9
+ };
10
+ const makeMemFs = () => {
11
+ const files = new Map();
12
+ return {
13
+ files,
14
+ readFile: async (absolutePath) => {
15
+ const key = path.resolve(absolutePath);
16
+ const v = files.get(key);
17
+ if (v === undefined)
18
+ throw enoent(`ENOENT: no such file, open '${absolutePath}'`);
19
+ return v;
20
+ },
21
+ writeFile: async (absolutePath, content) => {
22
+ files.set(path.resolve(absolutePath), String(content ?? ""));
23
+ },
24
+ mkdirp: async () => { },
25
+ rmFile: async (absolutePath) => {
26
+ const key = path.resolve(absolutePath);
27
+ if (!files.has(key))
28
+ throw enoent(`ENOENT: no such file, unlink '${absolutePath}'`);
29
+ files.delete(key);
30
+ },
31
+ stat: async (absolutePath) => {
32
+ const key = path.resolve(absolutePath);
33
+ if (!files.has(key))
34
+ throw enoent(`ENOENT: no such file, stat '${absolutePath}'`);
35
+ return { isDirectory: () => false };
36
+ },
37
+ safeReadDir: async () => [],
38
+ };
39
+ };
40
+ test('apply_patch: Update + Move writes new path and deletes old path', async () => {
41
+ const workspaceRoot = path.resolve("C:\\virtual-workspace");
42
+ const fs = makeMemFs();
43
+ const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });
44
+ fs.files.set(path.resolve(workspaceRoot, "app/a/page.config.ts"), "export const config = { elements: [] };\n");
45
+ const res = await applyPatch(`*** Begin Patch
46
+ *** Update File: app/a/page.config.ts
47
+ *** Move to: app/b/page.config.ts
48
+ @@
49
+ export const config = { elements: [] };
50
+ *** End Patch
51
+ `);
52
+ assert.equal(res.success, true);
53
+ assert.equal(res.changed, true);
54
+ assert.equal(fs.files.has(path.resolve(workspaceRoot, "app/a/page.config.ts")), false);
55
+ assert.equal(fs.files.get(path.resolve(workspaceRoot, "app/b/page.config.ts")), "export const config = { elements: [] };\n");
56
+ });
57
+ test("apply_patch: context-only Update succeeds as no-op", async () => {
58
+ const workspaceRoot = path.resolve("C:\\virtual-workspace");
59
+ const fs = makeMemFs();
60
+ const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });
61
+ fs.files.set(path.resolve(workspaceRoot, "app/a/page.config.ts"), "export const config = { elements: [] };\n");
62
+ const res = await applyPatch(`*** Begin Patch
63
+ *** Update File: app/a/page.config.ts
64
+ @@
65
+ export const config = { elements: [] };
66
+ *** End Patch
67
+ `);
68
+ assert.equal(res.success, true);
69
+ assert.equal(res.changed, false);
70
+ assert.equal(fs.files.get(path.resolve(workspaceRoot, "app/a/page.config.ts")), "export const config = { elements: [] };\n");
71
+ });
72
+ //# sourceMappingURL=applyPatch.impl.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.impl.test.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/applyPatch.impl.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport path from \"node:path\";\nimport test from \"node:test\";\nimport { createApplyPatchImpl } from \"./applyPatch.impl.js\";\n\ntype MemFs = {\n files: Map<string, string>;\n};\n\nconst enoent = (message: string) => {\n const err = new Error(message) as NodeJS.ErrnoException;\n err.code = \"ENOENT\";\n return err;\n};\n\nconst makeMemFs = (): MemFs & Parameters<typeof createApplyPatchImpl>[0][\"fs\"] => {\n const files = new Map<string, string>();\n\n return {\n files,\n readFile: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n const v = files.get(key);\n if (v === undefined) throw enoent(`ENOENT: no such file, open '${absolutePath}'`);\n return v;\n },\n writeFile: async (absolutePath: string, content: string) => {\n files.set(path.resolve(absolutePath), String(content ?? \"\"));\n },\n mkdirp: async () => {},\n rmFile: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n if (!files.has(key)) throw enoent(`ENOENT: no such file, unlink '${absolutePath}'`);\n files.delete(key);\n },\n stat: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n if (!files.has(key)) throw enoent(`ENOENT: no such file, stat '${absolutePath}'`);\n return { isDirectory: () => false };\n },\n safeReadDir: async () => [],\n };\n};\n\ntest('apply_patch: Update + Move writes new path and deletes old path', async () => {\n const workspaceRoot = path.resolve(\"C:\\\\virtual-workspace\");\n const fs = makeMemFs();\n const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });\n\n fs.files.set(\n path.resolve(workspaceRoot, \"app/a/page.config.ts\"),\n \"export const config = { elements: [] };\\n\",\n );\n\n const res = await applyPatch(`*** Begin Patch\n*** Update File: app/a/page.config.ts\n*** Move to: app/b/page.config.ts\n@@\n export const config = { elements: [] };\n*** End Patch\n`);\n\n assert.equal(res.success, true);\n assert.equal((res as any).changed, true);\n assert.equal(fs.files.has(path.resolve(workspaceRoot, \"app/a/page.config.ts\")), false);\n assert.equal(\n fs.files.get(path.resolve(workspaceRoot, \"app/b/page.config.ts\")),\n \"export const config = { elements: [] };\\n\",\n );\n});\n\ntest(\"apply_patch: context-only Update succeeds as no-op\", async () => {\n const workspaceRoot = path.resolve(\"C:\\\\virtual-workspace\");\n const fs = makeMemFs();\n const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });\n\n fs.files.set(\n path.resolve(workspaceRoot, \"app/a/page.config.ts\"),\n \"export const config = { elements: [] };\\n\",\n );\n\n const res = await applyPatch(`*** Begin Patch\n*** Update File: app/a/page.config.ts\n@@\n export const config = { elements: [] };\n*** End Patch\n`);\n\n assert.equal(res.success, true);\n assert.equal((res as any).changed, false);\n assert.equal(\n fs.files.get(path.resolve(workspaceRoot, \"app/a/page.config.ts\")),\n \"export const config = { elements: [] };\\n\",\n );\n});\n"]}
@@ -0,0 +1,90 @@
1
+ import { type SearchDeps } from "./search.impl.js";
2
+ export { DEFAULT_NOT_FOUND_RESPONSE } from "./workspaceDeps.js";
3
+ export type { CoreDirent, CoreFs, WorkspaceDeps, } from "./workspaceDeps.js";
4
+ export { createApplyPatchImpl } from "./applyPatch.impl.js";
5
+ export { createListDirImpl } from "./listDir.impl.js";
6
+ export { createReadFileImpl } from "./readFile.impl.js";
7
+ export { createSearchImpl, type SearchDeps, type SearchResult, } from "./search.impl.js";
8
+ export { createWriteFileImpl } from "./writeFile.impl.js";
9
+ export declare const createWorkspaceToolImpls: (deps: SearchDeps) => {
10
+ readFileImpl: (filePath: string, startLine?: number, endLine?: number) => Promise<string>;
11
+ writeFileImpl: (filePath: string, content: string) => Promise<{
12
+ success: boolean;
13
+ rejected: boolean;
14
+ error: string;
15
+ allowed: string[];
16
+ rule?: undefined;
17
+ } | {
18
+ success: boolean;
19
+ rejected: boolean;
20
+ error: string;
21
+ allowed?: undefined;
22
+ rule?: undefined;
23
+ } | {
24
+ success: boolean;
25
+ rejected: boolean;
26
+ error: string;
27
+ rule: string;
28
+ allowed?: undefined;
29
+ } | {
30
+ success: boolean;
31
+ rejected?: undefined;
32
+ error?: undefined;
33
+ allowed?: undefined;
34
+ rule?: undefined;
35
+ }>;
36
+ listDirImpl: (dirPath: string, depth: number) => Promise<string>;
37
+ searchImpl: (searchQuery: string) => Promise<import("./search.impl.js").SearchResult[]>;
38
+ applyPatchImpl: (patchString: string) => Promise<{
39
+ success: boolean;
40
+ rejected: boolean;
41
+ error: string;
42
+ allowed: string[];
43
+ rule?: undefined;
44
+ changed?: undefined;
45
+ warnings?: undefined;
46
+ debug?: undefined;
47
+ } | {
48
+ success: boolean;
49
+ rejected: boolean;
50
+ error: string;
51
+ allowed?: undefined;
52
+ rule?: undefined;
53
+ changed?: undefined;
54
+ warnings?: undefined;
55
+ debug?: undefined;
56
+ } | {
57
+ success: boolean;
58
+ rejected: boolean;
59
+ error: string;
60
+ rule: string;
61
+ allowed?: undefined;
62
+ changed?: undefined;
63
+ warnings?: undefined;
64
+ debug?: undefined;
65
+ } | {
66
+ success: boolean;
67
+ changed: boolean;
68
+ warnings: string[] | undefined;
69
+ rejected?: undefined;
70
+ error?: undefined;
71
+ allowed?: undefined;
72
+ rule?: undefined;
73
+ debug?: undefined;
74
+ } | {
75
+ success: boolean;
76
+ error: string;
77
+ debug: {
78
+ files: {
79
+ path: string;
80
+ head: string;
81
+ }[];
82
+ } | undefined;
83
+ rejected?: undefined;
84
+ allowed?: undefined;
85
+ rule?: undefined;
86
+ changed?: undefined;
87
+ warnings?: undefined;
88
+ }>;
89
+ };
90
+ //# sourceMappingURL=factories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/factories.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,UAAU,EACV,MAAM,EACN,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,eAAO,MAAM,wBAAwB,GAAI,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAcxD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { createApplyPatchImpl } from "./applyPatch.impl.js";
2
+ import { createListDirImpl } from "./listDir.impl.js";
3
+ import { createReadFileImpl } from "./readFile.impl.js";
4
+ import { createSearchImpl } from "./search.impl.js";
5
+ import { createWriteFileImpl } from "./writeFile.impl.js";
6
+ export { DEFAULT_NOT_FOUND_RESPONSE } from "./workspaceDeps.js";
7
+ export { createApplyPatchImpl } from "./applyPatch.impl.js";
8
+ export { createListDirImpl } from "./listDir.impl.js";
9
+ export { createReadFileImpl } from "./readFile.impl.js";
10
+ export { createSearchImpl, } from "./search.impl.js";
11
+ export { createWriteFileImpl } from "./writeFile.impl.js";
12
+ export const createWorkspaceToolImpls = (deps) => {
13
+ const readFileImpl = createReadFileImpl(deps);
14
+ const writeFileImpl = createWriteFileImpl(deps);
15
+ const listDirImpl = createListDirImpl(deps);
16
+ const searchImpl = createSearchImpl(deps);
17
+ const applyPatchImpl = createApplyPatchImpl(deps);
18
+ return {
19
+ readFileImpl,
20
+ writeFileImpl,
21
+ listDirImpl,
22
+ searchImpl,
23
+ applyPatchImpl,
24
+ };
25
+ };
26
+ //# sourceMappingURL=factories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factories.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/factories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAmB,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAOhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EACL,gBAAgB,GAGjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,IAAgB,EAAE,EAAE;IAC3D,MAAM,YAAY,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAElD,OAAO;QACL,YAAY;QACZ,aAAa;QACb,WAAW;QACX,UAAU;QACV,cAAc;KACf,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { createApplyPatchImpl } from \"./applyPatch.impl.js\";\nimport { createListDirImpl } from \"./listDir.impl.js\";\nimport { createReadFileImpl } from \"./readFile.impl.js\";\nimport { createSearchImpl, type SearchDeps } from \"./search.impl.js\";\nimport { createWriteFileImpl } from \"./writeFile.impl.js\";\n\nexport { DEFAULT_NOT_FOUND_RESPONSE } from \"./workspaceDeps.js\";\nexport type {\n CoreDirent,\n CoreFs,\n WorkspaceDeps,\n} from \"./workspaceDeps.js\";\n\nexport { createApplyPatchImpl } from \"./applyPatch.impl.js\";\nexport { createListDirImpl } from \"./listDir.impl.js\";\nexport { createReadFileImpl } from \"./readFile.impl.js\";\nexport {\n createSearchImpl,\n type SearchDeps,\n type SearchResult,\n} from \"./search.impl.js\";\nexport { createWriteFileImpl } from \"./writeFile.impl.js\";\n\nexport const createWorkspaceToolImpls = (deps: SearchDeps) => {\n const readFileImpl = createReadFileImpl(deps);\n const writeFileImpl = createWriteFileImpl(deps);\n const listDirImpl = createListDirImpl(deps);\n const searchImpl = createSearchImpl(deps);\n const applyPatchImpl = createApplyPatchImpl(deps);\n\n return {\n readFileImpl,\n writeFileImpl,\n listDirImpl,\n searchImpl,\n applyPatchImpl,\n };\n};\n"]}
@@ -0,0 +1,3 @@
1
+ import { type WorkspaceDeps } from "./workspaceDeps.js";
2
+ export declare const createListDirImpl: (deps: WorkspaceDeps) => (dirPath: string, depth: number) => Promise<string>;
3
+ //# sourceMappingURL=listDir.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listDir.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/listDir.impl.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEpF,eAAO,MAAM,iBAAiB,GAAI,MAAM,aAAa,MAKrC,SAAS,MAAM,EAAE,OAAO,MAAM,oBAyC7C,CAAC"}
@@ -0,0 +1,47 @@
1
+ import path from "node:path";
2
+ import { toWorkspacePath } from "../helpers/fileSystem.helpers.js";
3
+ import { DEFAULT_NOT_FOUND_RESPONSE } from "./workspaceDeps.js";
4
+ export const createListDirImpl = (deps) => {
5
+ const { workspaceRoot, fs } = deps;
6
+ const MAX_LINES = 500;
7
+ return async (dirPath, depth) => {
8
+ const fullPath = toWorkspacePath(workspaceRoot, dirPath);
9
+ console.log("Tool list_dir", { path: fullPath, depth });
10
+ const effectiveDepth = Math.max(1, Math.min(3, depth ?? 1));
11
+ try {
12
+ const st = await fs.stat(fullPath);
13
+ if (!st.isDirectory())
14
+ return `not a directory: ${dirPath}`;
15
+ }
16
+ catch (err) {
17
+ const code = err?.code;
18
+ if (code === "ENOENT")
19
+ return DEFAULT_NOT_FOUND_RESPONSE;
20
+ throw err;
21
+ }
22
+ const lines = [];
23
+ const walk = async (dir, currentDepth, prefix) => {
24
+ if (lines.length >= MAX_LINES)
25
+ return;
26
+ const entries = await fs.safeReadDir(dir);
27
+ for (const entry of entries) {
28
+ if (lines.length >= MAX_LINES)
29
+ return;
30
+ if (!entry.isDirectory() && !entry.isFile())
31
+ continue;
32
+ const isDir = entry.isDirectory();
33
+ const displayName = isDir ? `/${entry.name}` : entry.name;
34
+ const line = prefix ? `${prefix}${displayName}` : displayName;
35
+ lines.push(line);
36
+ if (isDir && currentDepth < effectiveDepth) {
37
+ await walk(path.join(dir, entry.name), currentDepth + 1, `${prefix} `);
38
+ }
39
+ }
40
+ };
41
+ await walk(fullPath, 1, "");
42
+ if (lines.length >= MAX_LINES)
43
+ lines.push("... truncated ...");
44
+ return lines.join("\n");
45
+ };
46
+ };
47
+ //# sourceMappingURL=listDir.impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listDir.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/listDir.impl.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAsB,MAAM,oBAAoB,CAAC;AAEpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAmB,EAAE,EAAE;IACvD,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEnC,MAAM,SAAS,GAAG,GAAG,CAAC;IAEtB,OAAO,KAAK,EAAE,OAAe,EAAE,KAAa,EAAE,EAAE;QAC9C,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAExD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAc,CAAC;QAEzE,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE;gBAAE,OAAO,oBAAoB,OAAO,EAAE,CAAC;QAC9D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAI,GAAoC,EAAE,IAAI,CAAC;YACzD,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,0BAA0B,CAAC;YACzD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,MAAM,IAAI,GAAG,KAAK,EAAE,GAAW,EAAE,YAAoB,EAAE,MAAc,EAAE,EAAE;YACvE,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;gBAAE,OAAO;YACtC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAE1C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;oBAAE,OAAO;gBACtC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;oBAAE,SAAS;gBAEtD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;gBAClC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;gBAC9D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEjB,IAAI,KAAK,IAAI,YAAY,GAAG,cAAc,EAAE,CAAC;oBAC3C,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,CAAC,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC;gBAC1E,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAE5B,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC/D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import path from \"node:path\";\nimport { toWorkspacePath } from \"../helpers/fileSystem.helpers.js\";\nimport { DEFAULT_NOT_FOUND_RESPONSE, type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport const createListDirImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n const MAX_LINES = 500;\n\n return async (dirPath: string, depth: number) => {\n const fullPath = toWorkspacePath(workspaceRoot, dirPath);\n console.log(\"Tool list_dir\", { path: fullPath, depth });\n\n const effectiveDepth = Math.max(1, Math.min(3, depth ?? 1)) as 1 | 2 | 3;\n\n try {\n const st = await fs.stat(fullPath);\n if (!st.isDirectory()) return `not a directory: ${dirPath}`;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code === \"ENOENT\") return DEFAULT_NOT_FOUND_RESPONSE;\n throw err;\n }\n\n const lines: string[] = [];\n\n const walk = async (dir: string, currentDepth: number, prefix: string) => {\n if (lines.length >= MAX_LINES) return;\n const entries = await fs.safeReadDir(dir);\n\n for (const entry of entries) {\n if (lines.length >= MAX_LINES) return;\n if (!entry.isDirectory() && !entry.isFile()) continue;\n\n const isDir = entry.isDirectory();\n const displayName = isDir ? `/${entry.name}` : entry.name;\n const line = prefix ? `${prefix}${displayName}` : displayName;\n lines.push(line);\n\n if (isDir && currentDepth < effectiveDepth) {\n await walk(path.join(dir, entry.name), currentDepth + 1, `${prefix} `);\n }\n }\n };\n\n await walk(fullPath, 1, \"\");\n\n if (lines.length >= MAX_LINES) lines.push(\"... truncated ...\");\n return lines.join(\"\\n\");\n };\n};\n"]}
@@ -0,0 +1,3 @@
1
+ import { type WorkspaceDeps } from "./workspaceDeps.js";
2
+ export declare const createReadFileImpl: (deps: WorkspaceDeps) => (filePath: string, startLine?: number, endLine?: number) => Promise<string>;
3
+ //# sourceMappingURL=readFile.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readFile.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/readFile.impl.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEpF,eAAO,MAAM,kBAAkB,GAAI,MAAM,aAAa,MAGtC,UAAU,MAAM,EAAE,YAAY,MAAM,EAAE,UAAU,MAAM,oBAgBrE,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { toWorkspacePath } from "../helpers/fileSystem.helpers.js";
2
+ import { sliceByLines } from "../helpers/format.helpers.js";
3
+ import { DEFAULT_NOT_FOUND_RESPONSE } from "./workspaceDeps.js";
4
+ export const createReadFileImpl = (deps) => {
5
+ const { workspaceRoot, fs } = deps;
6
+ return async (filePath, startLine, endLine) => {
7
+ const fullPath = toWorkspacePath(workspaceRoot, filePath);
8
+ console.log("Tool read_file", { path: fullPath });
9
+ try {
10
+ await fs.stat(fullPath);
11
+ }
12
+ catch (err) {
13
+ const code = err?.code;
14
+ if (code === "ENOENT")
15
+ return DEFAULT_NOT_FOUND_RESPONSE;
16
+ console.log("Tool read_file failed", err, { path: fullPath });
17
+ throw err;
18
+ }
19
+ const content = await fs.readFile(fullPath);
20
+ return sliceByLines(content, startLine, endLine);
21
+ };
22
+ };
23
+ //# sourceMappingURL=readFile.impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readFile.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/readFile.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAsB,MAAM,oBAAoB,CAAC;AAEpF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAmB,EAAE,EAAE;IACxD,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEnC,OAAO,KAAK,EAAE,QAAgB,EAAE,SAAkB,EAAE,OAAgB,EAAE,EAAE;QACtE,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAI,GAAoC,EAAE,IAAI,CAAC;YACzD,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,0BAA0B,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC9D,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC5C,OAAO,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { toWorkspacePath } from \"../helpers/fileSystem.helpers.js\";\nimport { sliceByLines } from \"../helpers/format.helpers.js\";\nimport { DEFAULT_NOT_FOUND_RESPONSE, type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport const createReadFileImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (filePath: string, startLine?: number, endLine?: number) => {\n const fullPath = toWorkspacePath(workspaceRoot, filePath);\n console.log(\"Tool read_file\", { path: fullPath });\n\n try {\n await fs.stat(fullPath);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code === \"ENOENT\") return DEFAULT_NOT_FOUND_RESPONSE;\n console.log(\"Tool read_file failed\", err, { path: fullPath });\n throw err;\n }\n\n const content = await fs.readFile(fullPath);\n return sliceByLines(content, startLine, endLine);\n };\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import { type WorkspaceDeps } from "./workspaceDeps.js";
2
+ export type SearchResult = {
3
+ path: string;
4
+ content: string;
5
+ };
6
+ export type SearchDeps = WorkspaceDeps & {
7
+ execRg?: (input: {
8
+ query: string;
9
+ cwd: string;
10
+ maxCount: number;
11
+ }) => Promise<{
12
+ code: number;
13
+ stdout: string;
14
+ stderr: string;
15
+ }>;
16
+ };
17
+ export declare const createSearchImpl: (deps: SearchDeps) => (searchQuery: string) => Promise<SearchResult[]>;
18
+ //# sourceMappingURL=search.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/search.impl.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG;IACvC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE,CAAC;AA0CF,eAAO,MAAM,gBAAgB,GAAI,MAAM,UAAU,MAIjC,aAAa,MAAM,KAAG,OAAO,CAAC,YAAY,EAAE,CAwC3D,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { spawn } from "node:child_process";
2
+ const defaultExecRg = async ({ query, cwd, maxCount }) => {
3
+ return await new Promise((resolve, reject) => {
4
+ const child = spawn("rg", [
5
+ "-n",
6
+ "--no-heading",
7
+ "--color",
8
+ "never",
9
+ "--max-count",
10
+ String(maxCount),
11
+ query,
12
+ ".",
13
+ ], { cwd });
14
+ let stdout = "";
15
+ let stderr = "";
16
+ child.stdout.setEncoding("utf8");
17
+ child.stderr.setEncoding("utf8");
18
+ child.stdout.on("data", (chunk) => {
19
+ stdout += chunk;
20
+ });
21
+ child.stderr.on("data", (chunk) => {
22
+ stderr += chunk;
23
+ });
24
+ child.on("error", (err) => {
25
+ reject(err);
26
+ });
27
+ child.on("close", (code) => {
28
+ resolve({ code: code ?? 0, stdout, stderr });
29
+ });
30
+ });
31
+ };
32
+ export const createSearchImpl = (deps) => {
33
+ const { workspaceRoot } = deps;
34
+ const execRg = deps.execRg ?? defaultExecRg;
35
+ return async (searchQuery) => {
36
+ const trimmed = (searchQuery ?? "").trim();
37
+ console.log("Tool search", { query: trimmed });
38
+ if (!trimmed)
39
+ return [];
40
+ try {
41
+ const { code, stdout, stderr } = await execRg({
42
+ query: trimmed,
43
+ cwd: workspaceRoot,
44
+ maxCount: 20,
45
+ });
46
+ if (code === 1)
47
+ return [];
48
+ if (code !== 0) {
49
+ throw new Error(`rg exited with code ${code}${stderr ? `: ${stderr.trim()}` : ""}`);
50
+ }
51
+ const lines = stdout
52
+ .replace(/\r\n/g, "\n")
53
+ .split("\n")
54
+ .filter(Boolean)
55
+ .slice(0, 20);
56
+ return lines.map((line) => {
57
+ const first = line.indexOf(":");
58
+ const second = first === -1 ? -1 : line.indexOf(":", first + 1);
59
+ if (first === -1 || second === -1)
60
+ return { path: line, content: "" };
61
+ const file = line.slice(0, first);
62
+ const lineNo = line.slice(first + 1, second);
63
+ const content = line.slice(second + 1);
64
+ return { path: `${file}:${lineNo}`, content };
65
+ });
66
+ }
67
+ catch (err) {
68
+ const message = err instanceof Error ? err.message : String(err);
69
+ console.log("Tool search failed", err, { query: trimmed, message });
70
+ return [];
71
+ }
72
+ };
73
+ };
74
+ //# sourceMappingURL=search.impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/search.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport type SearchResult = { path: string; content: string };\n\nexport type SearchDeps = WorkspaceDeps & {\n execRg?: (input: {\n query: string;\n cwd: string;\n maxCount: number;\n }) => Promise<{ code: number; stdout: string; stderr: string }>;\n};\n\nconst defaultExecRg: NonNullable<SearchDeps[\"execRg\"]> = async ({ query, cwd, maxCount }) => {\n return await new Promise((resolve, reject) => {\n const child = spawn(\n \"rg\",\n [\n \"-n\",\n \"--no-heading\",\n \"--color\",\n \"never\",\n \"--max-count\",\n String(maxCount),\n query,\n \".\",\n ],\n { cwd },\n );\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout.setEncoding(\"utf8\");\n child.stderr.setEncoding(\"utf8\");\n\n child.stdout.on(\"data\", (chunk) => {\n stdout += chunk;\n });\n child.stderr.on(\"data\", (chunk) => {\n stderr += chunk;\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n\n child.on(\"close\", (code) => {\n resolve({ code: code ?? 0, stdout, stderr });\n });\n });\n};\n\nexport const createSearchImpl = (deps: SearchDeps) => {\n const { workspaceRoot } = deps;\n const execRg = deps.execRg ?? defaultExecRg;\n\n return async (searchQuery: string): Promise<SearchResult[]> => {\n const trimmed = (searchQuery ?? \"\").trim();\n console.log(\"Tool search\", { query: trimmed });\n\n if (!trimmed) return [];\n\n try {\n const { code, stdout, stderr } = await execRg({\n query: trimmed,\n cwd: workspaceRoot,\n maxCount: 20,\n });\n\n if (code === 1) return [];\n if (code !== 0) {\n throw new Error(`rg exited with code ${code}${stderr ? `: ${stderr.trim()}` : \"\"}`);\n }\n\n const lines = stdout\n .replace(/\\r\\n/g, \"\\n\")\n .split(\"\\n\")\n .filter(Boolean)\n .slice(0, 20);\n\n return lines.map((line): SearchResult => {\n const first = line.indexOf(\":\");\n const second = first === -1 ? -1 : line.indexOf(\":\", first + 1);\n if (first === -1 || second === -1) return { path: line, content: \"\" };\n\n const file = line.slice(0, first);\n const lineNo = line.slice(first + 1, second);\n const content = line.slice(second + 1);\n return { path: `${file}:${lineNo}`, content };\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.log(\"Tool search failed\", err, { query: trimmed, message });\n return [];\n }\n };\n};\n"]}
@@ -0,0 +1,22 @@
1
+ export type LogMeta = Record<string, unknown>;
2
+ export type CoreDirent = {
3
+ name: string;
4
+ isDirectory: () => boolean;
5
+ isFile: () => boolean;
6
+ };
7
+ export type CoreFs = {
8
+ readFile: (absolutePath: string) => Promise<string>;
9
+ writeFile: (absolutePath: string, content: string) => Promise<void>;
10
+ mkdirp: (absoluteDir: string) => Promise<void>;
11
+ rmFile: (absolutePath: string) => Promise<void>;
12
+ stat: (absolutePath: string) => Promise<{
13
+ isDirectory: () => boolean;
14
+ }>;
15
+ safeReadDir: (absoluteDir: string) => Promise<CoreDirent[]>;
16
+ };
17
+ export type WorkspaceDeps = {
18
+ workspaceRoot: string;
19
+ fs: CoreFs;
20
+ };
21
+ export declare const DEFAULT_NOT_FOUND_RESPONSE = "not found";
22
+ //# sourceMappingURL=workspaceDeps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceDeps.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/workspaceDeps.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,CAAC;IACxE,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC7D,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,eAAO,MAAM,0BAA0B,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_NOT_FOUND_RESPONSE = "not found";
2
+ //# sourceMappingURL=workspaceDeps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceDeps.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/workspaceDeps.ts"],"names":[],"mappings":"AAsBA,MAAM,CAAC,MAAM,0BAA0B,GAAG,WAAW,CAAC","sourcesContent":["export type LogMeta = Record<string, unknown>;\n\nexport type CoreDirent = {\n name: string;\n isDirectory: () => boolean;\n isFile: () => boolean;\n};\n\nexport type CoreFs = {\n readFile: (absolutePath: string) => Promise<string>;\n writeFile: (absolutePath: string, content: string) => Promise<void>;\n mkdirp: (absoluteDir: string) => Promise<void>;\n rmFile: (absolutePath: string) => Promise<void>;\n stat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }>;\n safeReadDir: (absoluteDir: string) => Promise<CoreDirent[]>;\n};\n\nexport type WorkspaceDeps = {\n workspaceRoot: string;\n fs: CoreFs;\n};\n\nexport const DEFAULT_NOT_FOUND_RESPONSE = \"not found\";\n"]}
@@ -0,0 +1,27 @@
1
+ import { type WorkspaceDeps } from "./workspaceDeps.js";
2
+ export declare const createWriteFileImpl: (deps: WorkspaceDeps) => (filePath: string, content: string) => Promise<{
3
+ success: boolean;
4
+ rejected: boolean;
5
+ error: string;
6
+ allowed: string[];
7
+ rule?: undefined;
8
+ } | {
9
+ success: boolean;
10
+ rejected: boolean;
11
+ error: string;
12
+ allowed?: undefined;
13
+ rule?: undefined;
14
+ } | {
15
+ success: boolean;
16
+ rejected: boolean;
17
+ error: string;
18
+ rule: string;
19
+ allowed?: undefined;
20
+ } | {
21
+ success: boolean;
22
+ rejected?: undefined;
23
+ error?: undefined;
24
+ allowed?: undefined;
25
+ rule?: undefined;
26
+ }>;
27
+ //# sourceMappingURL=writeFile.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeFile.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/writeFile.impl.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,eAAO,MAAM,mBAAmB,GAAI,MAAM,aAAa,MAGvC,UAAU,MAAM,EAAE,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;EA8DhD,CAAC"}
@@ -0,0 +1,62 @@
1
+ import path from "node:path";
2
+ import { toWorkspacePath } from "../helpers/fileSystem.helpers.js";
3
+ import { isAllowedRouteFilePath, isPageTsxPath, matchesPageTsxTemplate, normalizeFsPathForPolicy, PAGE_TSX_TEMPLATE, } from "../helpers/nextRouteFilePolicy.js";
4
+ export const createWriteFileImpl = (deps) => {
5
+ const { workspaceRoot, fs } = deps;
6
+ return async (filePath, content) => {
7
+ const policyPath = normalizeFsPathForPolicy(filePath);
8
+ if (!isAllowedRouteFilePath(policyPath)) {
9
+ return {
10
+ success: false,
11
+ rejected: true,
12
+ error: `write_file rejected: only route files named "page.tsx" or "page.config.ts" may be written.\n` +
13
+ `Got: "${policyPath}"`,
14
+ allowed: Array.from(["page.tsx", "page.config.ts"]),
15
+ };
16
+ }
17
+ const fullPath = toWorkspacePath(workspaceRoot, filePath);
18
+ console.log("Tool write_file", { path: fullPath });
19
+ if (isPageTsxPath(policyPath)) {
20
+ let exists = false;
21
+ try {
22
+ await fs.stat(fullPath);
23
+ exists = true;
24
+ }
25
+ catch (err) {
26
+ const code = err?.code;
27
+ if (code && code !== "ENOENT") {
28
+ const message = err instanceof Error ? err.message : String(err);
29
+ return {
30
+ success: false,
31
+ rejected: true,
32
+ error: `write_file rejected: could not check existing file "${policyPath}": ${message}`,
33
+ };
34
+ }
35
+ }
36
+ if (exists) {
37
+ return {
38
+ success: false,
39
+ rejected: true,
40
+ error: `write_file rejected: updates to "page.tsx" are not allowed for any route. ` +
41
+ `Only add (create) or delete is allowed, and once created it must never be edited.\n` +
42
+ `Path: "${policyPath}"`,
43
+ rule: "page.tsx is immutable after creation",
44
+ };
45
+ }
46
+ if (!matchesPageTsxTemplate(content)) {
47
+ return {
48
+ success: false,
49
+ rejected: true,
50
+ error: `write_file rejected: new "page.tsx" must match the exact required template (byte-for-byte).\n` +
51
+ `Path: "${policyPath}"\n` +
52
+ `Expected:\n${PAGE_TSX_TEMPLATE}`,
53
+ rule: "page.tsx must match template on creation",
54
+ };
55
+ }
56
+ }
57
+ await fs.mkdirp(path.dirname(fullPath));
58
+ await fs.writeFile(fullPath, content ?? "");
59
+ return { success: true };
60
+ };
61
+ };
62
+ //# sourceMappingURL=writeFile.impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeFile.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/writeFile.impl.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,sBAAsB,EACtB,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,mCAAmC,CAAC;AAG3C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAmB,EAAE,EAAE;IACzD,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEnC,OAAO,KAAK,EAAE,QAAgB,EAAE,OAAe,EAAE,EAAE;QACjD,MAAM,UAAU,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;YACxC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,IAAI;gBACd,KAAK,EACH,8FAA8F;oBAC9F,SAAS,UAAU,GAAG;gBACxB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;aACpD,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEnD,IAAI,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,IAAI,MAAM,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACxB,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,IAAI,GAAI,GAAoC,EAAE,IAAI,CAAC;gBACzD,IAAI,IAAI,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC9B,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACjE,OAAO;wBACL,OAAO,EAAE,KAAK;wBACd,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,uDAAuD,UAAU,MAAM,OAAO,EAAE;qBACxF,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,IAAI;oBACd,KAAK,EACH,4EAA4E;wBAC5E,qFAAqF;wBACrF,UAAU,UAAU,GAAG;oBACzB,IAAI,EAAE,sCAAsC;iBAC7C,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,IAAI;oBACd,KAAK,EACH,+FAA+F;wBAC/F,UAAU,UAAU,KAAK;wBACzB,cAAc,iBAAiB,EAAE;oBACnC,IAAI,EAAE,0CAA0C;iBACjD,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxC,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;QAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import path from \"node:path\";\nimport { toWorkspacePath } from \"../helpers/fileSystem.helpers.js\";\nimport {\n isAllowedRouteFilePath,\n isPageTsxPath,\n matchesPageTsxTemplate,\n normalizeFsPathForPolicy,\n PAGE_TSX_TEMPLATE,\n} from \"../helpers/nextRouteFilePolicy.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport const createWriteFileImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (filePath: string, content: string) => {\n const policyPath = normalizeFsPathForPolicy(filePath);\n if (!isAllowedRouteFilePath(policyPath)) {\n return {\n success: false,\n rejected: true,\n error:\n `write_file rejected: only route files named \"page.tsx\" or \"page.config.ts\" may be written.\\n` +\n `Got: \"${policyPath}\"`,\n allowed: Array.from([\"page.tsx\", \"page.config.ts\"]),\n };\n }\n\n const fullPath = toWorkspacePath(workspaceRoot, filePath);\n console.log(\"Tool write_file\", { path: fullPath });\n\n if (isPageTsxPath(policyPath)) {\n let exists = false;\n try {\n await fs.stat(fullPath);\n exists = true;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code && code !== \"ENOENT\") {\n const message = err instanceof Error ? err.message : String(err);\n return {\n success: false,\n rejected: true,\n error: `write_file rejected: could not check existing file \"${policyPath}\": ${message}`,\n };\n }\n }\n\n if (exists) {\n return {\n success: false,\n rejected: true,\n error:\n `write_file rejected: updates to \"page.tsx\" are not allowed for any route. ` +\n `Only add (create) or delete is allowed, and once created it must never be edited.\\n` +\n `Path: \"${policyPath}\"`,\n rule: \"page.tsx is immutable after creation\",\n };\n }\n\n if (!matchesPageTsxTemplate(content)) {\n return {\n success: false,\n rejected: true,\n error:\n `write_file rejected: new \"page.tsx\" must match the exact required template (byte-for-byte).\\n` +\n `Path: \"${policyPath}\"\\n` +\n `Expected:\\n${PAGE_TSX_TEMPLATE}`,\n rule: \"page.tsx must match template on creation\",\n };\n }\n }\n\n await fs.mkdirp(path.dirname(fullPath));\n await fs.writeFile(fullPath, content ?? \"\");\n return { success: true };\n };\n};\n"]}
@@ -0,0 +1,16 @@
1
+ import { Type } from "@google/genai";
2
+ export declare const ApplyPatchSchema: {
3
+ name: string;
4
+ description: string;
5
+ parameters: {
6
+ type: Type;
7
+ properties: {
8
+ patch_string: {
9
+ type: Type;
10
+ description: string;
11
+ };
12
+ };
13
+ required: string[];
14
+ };
15
+ };
16
+ //# sourceMappingURL=applyPatch.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/applyPatch.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAe5B,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Type } from "@google/genai";
2
+ export const ApplyPatchSchema = {
3
+ name: "apply_patch",
4
+ description: 'Applies a diff patch to a file or set of files. Policy: only "page.config.ts" and "page.tsx" route files are allowed. ' +
5
+ '"page.tsx" can only be added with the exact required template; updates to "page.tsx" are rejected (only add/delete).',
6
+ parameters: {
7
+ type: Type.OBJECT,
8
+ properties: {
9
+ patch_string: {
10
+ type: Type.STRING,
11
+ description: "The patch string to apply (*** Begin Patch ... *** End Patch).",
12
+ },
13
+ },
14
+ required: ["patch_string"],
15
+ },
16
+ };
17
+ //# sourceMappingURL=applyPatch.schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/applyPatch.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,wHAAwH;QACxH,sHAAsH;IACxH,UAAU,EAAE;QACV,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,UAAU,EAAE;YACV,YAAY,EAAE;gBACZ,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,WAAW,EAAE,gEAAgE;aAC9E;SACF;QACD,QAAQ,EAAE,CAAC,cAAc,CAAC;KAC3B;CACF,CAAC","sourcesContent":["import { Type } from \"@google/genai\";\n\nexport const ApplyPatchSchema = {\n name: \"apply_patch\",\n description:\n 'Applies a diff patch to a file or set of files. Policy: only \"page.config.ts\" and \"page.tsx\" route files are allowed. ' +\n '\"page.tsx\" can only be added with the exact required template; updates to \"page.tsx\" are rejected (only add/delete).',\n parameters: {\n type: Type.OBJECT,\n properties: {\n patch_string: {\n type: Type.STRING,\n description: \"The patch string to apply (*** Begin Patch ... *** End Patch).\",\n },\n },\n required: [\"patch_string\"],\n },\n};\n"]}