@studio-foundation/runner 0.3.0-beta.1

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 (268) hide show
  1. package/ARCHITECTURE.md +53 -0
  2. package/LICENSE +663 -0
  3. package/README.md +125 -0
  4. package/configs/agents/analyst.agent.yaml +31 -0
  5. package/configs/agents/code-generator.agent.yaml +31 -0
  6. package/configs/agents/generic.agent.yaml +23 -0
  7. package/dist/__tests__/script-executor.test.d.ts +2 -0
  8. package/dist/__tests__/script-executor.test.d.ts.map +1 -0
  9. package/dist/__tests__/script-executor.test.js +173 -0
  10. package/dist/__tests__/script-executor.test.js.map +1 -0
  11. package/dist/index.d.ts +38 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +76 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/integrations/integration-loader.d.ts +20 -0
  16. package/dist/integrations/integration-loader.d.ts.map +1 -0
  17. package/dist/integrations/integration-loader.js +71 -0
  18. package/dist/integrations/integration-loader.js.map +1 -0
  19. package/dist/integrations/integration-loader.test.d.ts +2 -0
  20. package/dist/integrations/integration-loader.test.d.ts.map +1 -0
  21. package/dist/integrations/integration-loader.test.js +77 -0
  22. package/dist/integrations/integration-loader.test.js.map +1 -0
  23. package/dist/middleware/anonymization.d.ts +22 -0
  24. package/dist/middleware/anonymization.d.ts.map +1 -0
  25. package/dist/middleware/anonymization.js +37 -0
  26. package/dist/middleware/anonymization.js.map +1 -0
  27. package/dist/plugins/index.d.ts +5 -0
  28. package/dist/plugins/index.d.ts.map +1 -0
  29. package/dist/plugins/index.js +10 -0
  30. package/dist/plugins/index.js.map +1 -0
  31. package/dist/plugins/mcp-client.d.ts +19 -0
  32. package/dist/plugins/mcp-client.d.ts.map +1 -0
  33. package/dist/plugins/mcp-client.js +126 -0
  34. package/dist/plugins/mcp-client.js.map +1 -0
  35. package/dist/plugins/mcp-client.test.d.ts +2 -0
  36. package/dist/plugins/mcp-client.test.d.ts.map +1 -0
  37. package/dist/plugins/mcp-client.test.js +160 -0
  38. package/dist/plugins/mcp-client.test.js.map +1 -0
  39. package/dist/plugins/oauth-provider.d.ts +27 -0
  40. package/dist/plugins/oauth-provider.d.ts.map +1 -0
  41. package/dist/plugins/oauth-provider.js +140 -0
  42. package/dist/plugins/oauth-provider.js.map +1 -0
  43. package/dist/plugins/oauth-provider.test.d.ts +2 -0
  44. package/dist/plugins/oauth-provider.test.d.ts.map +1 -0
  45. package/dist/plugins/oauth-provider.test.js +144 -0
  46. package/dist/plugins/oauth-provider.test.js.map +1 -0
  47. package/dist/plugins/plugin-loader.d.ts +29 -0
  48. package/dist/plugins/plugin-loader.d.ts.map +1 -0
  49. package/dist/plugins/plugin-loader.js +71 -0
  50. package/dist/plugins/plugin-loader.js.map +1 -0
  51. package/dist/plugins/plugin-loader.test.d.ts +2 -0
  52. package/dist/plugins/plugin-loader.test.d.ts.map +1 -0
  53. package/dist/plugins/plugin-loader.test.js +87 -0
  54. package/dist/plugins/plugin-loader.test.js.map +1 -0
  55. package/dist/prompt-builder.d.ts +47 -0
  56. package/dist/prompt-builder.d.ts.map +1 -0
  57. package/dist/prompt-builder.js +263 -0
  58. package/dist/prompt-builder.js.map +1 -0
  59. package/dist/prompt-builder.test.d.ts +2 -0
  60. package/dist/prompt-builder.test.d.ts.map +1 -0
  61. package/dist/prompt-builder.test.js +154 -0
  62. package/dist/prompt-builder.test.js.map +1 -0
  63. package/dist/providers/anthropic.d.ts +14 -0
  64. package/dist/providers/anthropic.d.ts.map +1 -0
  65. package/dist/providers/anthropic.js +118 -0
  66. package/dist/providers/anthropic.js.map +1 -0
  67. package/dist/providers/anthropic.test.d.ts +2 -0
  68. package/dist/providers/anthropic.test.d.ts.map +1 -0
  69. package/dist/providers/anthropic.test.js +76 -0
  70. package/dist/providers/anthropic.test.js.map +1 -0
  71. package/dist/providers/mock.d.ts +17 -0
  72. package/dist/providers/mock.d.ts.map +1 -0
  73. package/dist/providers/mock.js +39 -0
  74. package/dist/providers/mock.js.map +1 -0
  75. package/dist/providers/ollama.d.ts +18 -0
  76. package/dist/providers/ollama.d.ts.map +1 -0
  77. package/dist/providers/ollama.js +155 -0
  78. package/dist/providers/ollama.js.map +1 -0
  79. package/dist/providers/ollama.test.d.ts +2 -0
  80. package/dist/providers/ollama.test.d.ts.map +1 -0
  81. package/dist/providers/ollama.test.js +123 -0
  82. package/dist/providers/ollama.test.js.map +1 -0
  83. package/dist/providers/openai-responses.d.ts +18 -0
  84. package/dist/providers/openai-responses.d.ts.map +1 -0
  85. package/dist/providers/openai-responses.js +175 -0
  86. package/dist/providers/openai-responses.js.map +1 -0
  87. package/dist/providers/openai.d.ts +16 -0
  88. package/dist/providers/openai.d.ts.map +1 -0
  89. package/dist/providers/openai.js +132 -0
  90. package/dist/providers/openai.js.map +1 -0
  91. package/dist/providers/openai.test.d.ts +2 -0
  92. package/dist/providers/openai.test.d.ts.map +1 -0
  93. package/dist/providers/openai.test.js +51 -0
  94. package/dist/providers/openai.test.js.map +1 -0
  95. package/dist/providers/provider.d.ts +42 -0
  96. package/dist/providers/provider.d.ts.map +1 -0
  97. package/dist/providers/provider.js +10 -0
  98. package/dist/providers/provider.js.map +1 -0
  99. package/dist/providers/registry.d.ts +42 -0
  100. package/dist/providers/registry.d.ts.map +1 -0
  101. package/dist/providers/registry.js +65 -0
  102. package/dist/providers/registry.js.map +1 -0
  103. package/dist/runner.d.ts +46 -0
  104. package/dist/runner.d.ts.map +1 -0
  105. package/dist/runner.js +324 -0
  106. package/dist/runner.js.map +1 -0
  107. package/dist/runner.test.d.ts +2 -0
  108. package/dist/runner.test.d.ts.map +1 -0
  109. package/dist/runner.test.js +280 -0
  110. package/dist/runner.test.js.map +1 -0
  111. package/dist/script-executor.d.ts +11 -0
  112. package/dist/script-executor.d.ts.map +1 -0
  113. package/dist/script-executor.js +85 -0
  114. package/dist/script-executor.js.map +1 -0
  115. package/dist/tools/builtin/git.d.ts +6 -0
  116. package/dist/tools/builtin/git.d.ts.map +1 -0
  117. package/dist/tools/builtin/git.js +294 -0
  118. package/dist/tools/builtin/git.js.map +1 -0
  119. package/dist/tools/builtin/patch.d.ts +6 -0
  120. package/dist/tools/builtin/patch.d.ts.map +1 -0
  121. package/dist/tools/builtin/patch.js +238 -0
  122. package/dist/tools/builtin/patch.js.map +1 -0
  123. package/dist/tools/builtin/repo-manager.d.ts +6 -0
  124. package/dist/tools/builtin/repo-manager.d.ts.map +1 -0
  125. package/dist/tools/builtin/repo-manager.js +171 -0
  126. package/dist/tools/builtin/repo-manager.js.map +1 -0
  127. package/dist/tools/builtin/search.d.ts +6 -0
  128. package/dist/tools/builtin/search.d.ts.map +1 -0
  129. package/dist/tools/builtin/search.js +104 -0
  130. package/dist/tools/builtin/search.js.map +1 -0
  131. package/dist/tools/builtin/shell.d.ts +6 -0
  132. package/dist/tools/builtin/shell.d.ts.map +1 -0
  133. package/dist/tools/builtin/shell.js +78 -0
  134. package/dist/tools/builtin/shell.js.map +1 -0
  135. package/dist/tools/builtin/studio-run.d.ts +12 -0
  136. package/dist/tools/builtin/studio-run.d.ts.map +1 -0
  137. package/dist/tools/builtin/studio-run.js +61 -0
  138. package/dist/tools/builtin/studio-run.js.map +1 -0
  139. package/dist/tools/builtin/web-search.d.ts +7 -0
  140. package/dist/tools/builtin/web-search.d.ts.map +1 -0
  141. package/dist/tools/builtin/web-search.js +94 -0
  142. package/dist/tools/builtin/web-search.js.map +1 -0
  143. package/dist/tools/builtin/web-search.test.d.ts +5 -0
  144. package/dist/tools/builtin/web-search.test.d.ts.map +1 -0
  145. package/dist/tools/builtin/web-search.test.js +90 -0
  146. package/dist/tools/builtin/web-search.test.js.map +1 -0
  147. package/dist/tools/errors.d.ts +4 -0
  148. package/dist/tools/errors.d.ts.map +1 -0
  149. package/dist/tools/errors.js +11 -0
  150. package/dist/tools/errors.js.map +1 -0
  151. package/dist/tools/errors.test.d.ts +2 -0
  152. package/dist/tools/errors.test.d.ts.map +1 -0
  153. package/dist/tools/errors.test.js +14 -0
  154. package/dist/tools/errors.test.js.map +1 -0
  155. package/dist/tools/plugin-loader.d.ts +31 -0
  156. package/dist/tools/plugin-loader.d.ts.map +1 -0
  157. package/dist/tools/plugin-loader.js +183 -0
  158. package/dist/tools/plugin-loader.js.map +1 -0
  159. package/dist/tools/plugin-loader.test.d.ts +2 -0
  160. package/dist/tools/plugin-loader.test.d.ts.map +1 -0
  161. package/dist/tools/plugin-loader.test.js +116 -0
  162. package/dist/tools/plugin-loader.test.js.map +1 -0
  163. package/dist/tools/skills/skill-loader.d.ts +23 -0
  164. package/dist/tools/skills/skill-loader.d.ts.map +1 -0
  165. package/dist/tools/skills/skill-loader.js +58 -0
  166. package/dist/tools/skills/skill-loader.js.map +1 -0
  167. package/dist/tools/skills/skill-loader.test.d.ts +2 -0
  168. package/dist/tools/skills/skill-loader.test.d.ts.map +1 -0
  169. package/dist/tools/skills/skill-loader.test.js +92 -0
  170. package/dist/tools/skills/skill-loader.test.js.map +1 -0
  171. package/dist/tools/tool-executor.d.ts +12 -0
  172. package/dist/tools/tool-executor.d.ts.map +1 -0
  173. package/dist/tools/tool-executor.js +76 -0
  174. package/dist/tools/tool-executor.js.map +1 -0
  175. package/dist/tools/tool-executor.test.d.ts +2 -0
  176. package/dist/tools/tool-executor.test.d.ts.map +1 -0
  177. package/dist/tools/tool-executor.test.js +83 -0
  178. package/dist/tools/tool-executor.test.js.map +1 -0
  179. package/dist/tools/tool-registry.d.ts +65 -0
  180. package/dist/tools/tool-registry.d.ts.map +1 -0
  181. package/dist/tools/tool-registry.js +112 -0
  182. package/dist/tools/tool-registry.js.map +1 -0
  183. package/dist/tools/yaml-executor.d.ts +22 -0
  184. package/dist/tools/yaml-executor.d.ts.map +1 -0
  185. package/dist/tools/yaml-executor.js +80 -0
  186. package/dist/tools/yaml-executor.js.map +1 -0
  187. package/dist/utils/race-signal.d.ts +6 -0
  188. package/dist/utils/race-signal.d.ts.map +1 -0
  189. package/dist/utils/race-signal.js +21 -0
  190. package/dist/utils/race-signal.js.map +1 -0
  191. package/dist/utils/race-signal.test.d.ts +2 -0
  192. package/dist/utils/race-signal.test.d.ts.map +1 -0
  193. package/dist/utils/race-signal.test.js +48 -0
  194. package/dist/utils/race-signal.test.js.map +1 -0
  195. package/package.json +36 -0
  196. package/src/__tests__/script-executor.test.ts +180 -0
  197. package/src/index.ts +68 -0
  198. package/src/integrations/integration-loader.test.ts +88 -0
  199. package/src/integrations/integration-loader.ts +68 -0
  200. package/src/middleware/anonymization.ts +38 -0
  201. package/src/plugins/index.ts +4 -0
  202. package/src/plugins/mcp-client.test.ts +148 -0
  203. package/src/plugins/mcp-client.ts +128 -0
  204. package/src/plugins/oauth-provider.test.ts +167 -0
  205. package/src/plugins/oauth-provider.ts +175 -0
  206. package/src/plugins/plugin-loader.test.ts +114 -0
  207. package/src/plugins/plugin-loader.ts +90 -0
  208. package/src/prompt-builder.test.ts +167 -0
  209. package/src/prompt-builder.ts +332 -0
  210. package/src/providers/anthropic.test.ts +101 -0
  211. package/src/providers/anthropic.ts +135 -0
  212. package/src/providers/mock.ts +57 -0
  213. package/src/providers/ollama.test.ts +166 -0
  214. package/src/providers/ollama.ts +152 -0
  215. package/src/providers/openai-responses.ts +212 -0
  216. package/src/providers/openai.test.ts +67 -0
  217. package/src/providers/openai.ts +139 -0
  218. package/src/providers/provider.ts +54 -0
  219. package/src/providers/registry.ts +77 -0
  220. package/src/runner.test.ts +343 -0
  221. package/src/runner.ts +396 -0
  222. package/src/script-executor.ts +107 -0
  223. package/src/tools/builtin/git.ts +311 -0
  224. package/src/tools/builtin/patch.ts +257 -0
  225. package/src/tools/builtin/repo-manager.ts +142 -0
  226. package/src/tools/builtin/search.ts +108 -0
  227. package/src/tools/builtin/shell.ts +82 -0
  228. package/src/tools/builtin/studio-run.ts +73 -0
  229. package/src/tools/builtin/web-search.test.ts +122 -0
  230. package/src/tools/builtin/web-search.ts +101 -0
  231. package/src/tools/errors.test.ts +12 -0
  232. package/src/tools/errors.ts +6 -0
  233. package/src/tools/plugin-loader.test.ts +130 -0
  234. package/src/tools/plugin-loader.ts +203 -0
  235. package/src/tools/skills/README.md +49 -0
  236. package/src/tools/skills/skill-loader.test.ts +106 -0
  237. package/src/tools/skills/skill-loader.ts +62 -0
  238. package/src/tools/tool-executor.test.ts +88 -0
  239. package/src/tools/tool-executor.ts +84 -0
  240. package/src/tools/tool-registry.ts +130 -0
  241. package/src/tools/yaml-executor.ts +120 -0
  242. package/src/utils/race-signal.test.ts +50 -0
  243. package/src/utils/race-signal.ts +17 -0
  244. package/templates/integrations/linear.integration.yaml +35 -0
  245. package/templates/integrations/slack.integration.yaml +22 -0
  246. package/templates/integrations/webhook.integration.yaml +17 -0
  247. package/templates/tools/git.tool.yaml +80 -0
  248. package/templates/tools/repo-manager.tool.yaml +64 -0
  249. package/templates/tools/search.tool.yaml +22 -0
  250. package/templates/tools/shell.tool.yaml +19 -0
  251. package/templates/tools/web-search.tool.yaml +24 -0
  252. package/tests/anonymization-middleware.test.ts +61 -0
  253. package/tests/anthropic.test.ts +87 -0
  254. package/tests/apply-patch.test.ts +355 -0
  255. package/tests/fixtures/tools/test-builtin.tool.yaml +14 -0
  256. package/tests/fixtures/tools/test-shell.tool.yaml +19 -0
  257. package/tests/mock-provider.test.ts +104 -0
  258. package/tests/openai.test.ts +72 -0
  259. package/tests/plugin-loader.test.ts +54 -0
  260. package/tests/prompt-builder.test.ts +468 -0
  261. package/tests/runner-anonymization.test.ts +89 -0
  262. package/tests/runner.test.ts +885 -0
  263. package/tests/studio-run.test.ts +94 -0
  264. package/tests/tool-executor.test.ts +115 -0
  265. package/tests/tool-registry.test.ts +84 -0
  266. package/tests/yaml-executor.test.ts +76 -0
  267. package/tsconfig.json +20 -0
  268. package/vitest.config.ts +7 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-executor.d.ts","sourceRoot":"","sources":["../src/script-executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,OAAO,EAAE,YAAY,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2BD,wBAAsB,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAmErF"}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runScript = runScript;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const RUNTIME_COMMANDS = {
8
+ python: 'python3',
9
+ node: 'node',
10
+ shell: 'sh',
11
+ };
12
+ function buildEnv(runtime, cwd) {
13
+ const env = { ...process.env };
14
+ if (runtime === 'python') {
15
+ const venvPath = (0, node_fs_1.existsSync)((0, node_path_1.join)(cwd, 'venv'))
16
+ ? (0, node_path_1.join)(cwd, 'venv')
17
+ : (0, node_fs_1.existsSync)((0, node_path_1.join)(cwd, '.venv'))
18
+ ? (0, node_path_1.join)(cwd, '.venv')
19
+ : null;
20
+ if (venvPath) {
21
+ env.VIRTUAL_ENV = venvPath;
22
+ env.PATH = `${(0, node_path_1.join)(venvPath, 'bin')}:${env.PATH ?? ''}`;
23
+ }
24
+ }
25
+ return env;
26
+ }
27
+ async function runScript(config) {
28
+ const startTime = Date.now();
29
+ const cwd = config.cwd ?? process.cwd();
30
+ const timeoutMs = config.timeoutMs ?? 30_000;
31
+ const cmd = RUNTIME_COMMANDS[config.runtime];
32
+ const env = buildEnv(config.runtime, cwd);
33
+ const stdin = JSON.stringify(config.context);
34
+ return new Promise((resolve) => {
35
+ const proc = (0, node_child_process_1.spawn)(cmd, [config.scriptPath], {
36
+ cwd,
37
+ env,
38
+ stdio: ['pipe', 'pipe', 'pipe'],
39
+ });
40
+ let stdout = '';
41
+ let stderr = '';
42
+ let timedOut = false;
43
+ let settled = false;
44
+ const settle = (result) => {
45
+ if (settled)
46
+ return;
47
+ settled = true;
48
+ clearTimeout(timer);
49
+ resolve(result);
50
+ };
51
+ const timer = setTimeout(() => {
52
+ timedOut = true;
53
+ proc.kill('SIGTERM');
54
+ setTimeout(() => proc.kill('SIGKILL'), 1000);
55
+ }, timeoutMs);
56
+ proc.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
57
+ proc.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
58
+ proc.stdin.write(stdin);
59
+ proc.stdin.end();
60
+ proc.on('close', (exitCode) => {
61
+ const duration_ms = Date.now() - startTime;
62
+ if (timedOut) {
63
+ settle({ output: null, tool_calls: [], tool_calls_count: 0, duration_ms, error: `Script timed out after ${timeoutMs}ms` });
64
+ return;
65
+ }
66
+ if (exitCode !== 0) {
67
+ settle({ output: null, tool_calls: [], tool_calls_count: 0, duration_ms, error: `Script exited with code ${exitCode}: ${stderr.trim()}` });
68
+ return;
69
+ }
70
+ let output;
71
+ try {
72
+ output = JSON.parse(stdout.trim());
73
+ }
74
+ catch {
75
+ settle({ output: null, tool_calls: [], tool_calls_count: 0, duration_ms, error: `Script output is not valid JSON: ${stdout.slice(0, 200)}` });
76
+ return;
77
+ }
78
+ settle({ output, tool_calls: [], tool_calls_count: 0, duration_ms });
79
+ });
80
+ proc.on('error', (err) => {
81
+ settle({ output: null, tool_calls: [], tool_calls_count: 0, duration_ms: Date.now() - startTime, error: `Script process error: ${err.message}` });
82
+ });
83
+ });
84
+ }
85
+ //# sourceMappingURL=script-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-executor.js","sourceRoot":"","sources":["../src/script-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Git tools - branch, commit, push, pull, status, diff
3
+ */
4
+ import type { Tool } from '../tool-registry.js';
5
+ export declare function createGitTools(workingDir: string): Tool[];
6
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/tools/builtin/git.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAmBhD,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,CA6RzD"}
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ /**
3
+ * Git tools - branch, commit, push, pull, status, diff
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createGitTools = createGitTools;
7
+ const child_process_1 = require("child_process");
8
+ const util_1 = require("util");
9
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
10
+ const PROTECTED_BRANCHES = ['main', 'master', 'develop', 'production'];
11
+ async function isGitRepo(workingDir) {
12
+ try {
13
+ await execAsync('git rev-parse --git-dir', { cwd: workingDir });
14
+ return true;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ async function runGit(args, workingDir) {
21
+ return execAsync(`git ${args}`, { cwd: workingDir, timeout: 30000 });
22
+ }
23
+ function createGitTools(workingDir) {
24
+ return [
25
+ {
26
+ name: 'git-checkout',
27
+ description: 'Checkout or create a branch',
28
+ parameters: {
29
+ type: 'object',
30
+ properties: {
31
+ branch: {
32
+ type: 'string',
33
+ description: 'Branch name to checkout or create'
34
+ },
35
+ create: {
36
+ type: 'boolean',
37
+ description: 'Create the branch if it does not exist (-b flag). Default: false'
38
+ }
39
+ },
40
+ required: ['branch']
41
+ },
42
+ execute: async ({ branch, create }) => {
43
+ const branchName = branch;
44
+ const shouldCreate = create ?? false;
45
+ if (!(await isGitRepo(workingDir))) {
46
+ return { success: false, output: null, error: 'Not a git repository' };
47
+ }
48
+ if (shouldCreate && PROTECTED_BRANCHES.includes(branchName)) {
49
+ return {
50
+ success: false,
51
+ output: null,
52
+ error: `Cannot create protected branch: ${branchName}`
53
+ };
54
+ }
55
+ try {
56
+ const flag = shouldCreate ? '-b ' : '';
57
+ const { stdout, stderr } = await runGit(`checkout ${flag}${branchName}`, workingDir);
58
+ return {
59
+ success: true,
60
+ output: { branch: branchName, created: shouldCreate, stdout: stdout.trim(), stderr: stderr.trim() }
61
+ };
62
+ }
63
+ catch (error) {
64
+ const e = error;
65
+ return {
66
+ success: false,
67
+ output: null,
68
+ error: e.stderr?.trim() || e.message || 'git checkout failed'
69
+ };
70
+ }
71
+ }
72
+ },
73
+ {
74
+ name: 'git-commit',
75
+ description: 'Stage files and commit changes',
76
+ parameters: {
77
+ type: 'object',
78
+ properties: {
79
+ message: {
80
+ type: 'string',
81
+ description: 'Commit message'
82
+ },
83
+ files: {
84
+ type: 'array',
85
+ items: { type: 'string' },
86
+ description: 'Files to stage. If empty or omitted, stages all changes (git add -A)'
87
+ }
88
+ },
89
+ required: ['message']
90
+ },
91
+ execute: async ({ message, files }) => {
92
+ const commitMessage = message;
93
+ const filesToStage = files;
94
+ if (!(await isGitRepo(workingDir))) {
95
+ return { success: false, output: null, error: 'Not a git repository' };
96
+ }
97
+ try {
98
+ // Check for merge conflicts
99
+ const { stdout: statusOut } = await runGit('status --porcelain', workingDir);
100
+ const hasConflicts = statusOut.split('\n').some(line => line.startsWith('UU') || line.startsWith('AA') || line.startsWith('DD'));
101
+ if (hasConflicts) {
102
+ return { success: false, output: null, error: 'Cannot commit: merge conflicts detected' };
103
+ }
104
+ // Stage files
105
+ if (filesToStage && filesToStage.length > 0) {
106
+ await runGit(`add -- ${filesToStage.map(f => `"${f}"`).join(' ')}`, workingDir);
107
+ }
108
+ else {
109
+ await runGit('add -A', workingDir);
110
+ }
111
+ // Commit
112
+ const { stdout } = await runGit(`commit -m ${JSON.stringify(commitMessage)}`, workingDir);
113
+ return {
114
+ success: true,
115
+ output: { message: commitMessage, stdout: stdout.trim() }
116
+ };
117
+ }
118
+ catch (error) {
119
+ const e = error;
120
+ return {
121
+ success: false,
122
+ output: null,
123
+ error: e.stderr?.trim() || e.stdout?.trim() || e.message || 'git commit failed'
124
+ };
125
+ }
126
+ }
127
+ },
128
+ {
129
+ name: 'git-push',
130
+ description: 'Push current branch to remote',
131
+ parameters: {
132
+ type: 'object',
133
+ properties: {
134
+ remote: {
135
+ type: 'string',
136
+ description: 'Remote name. Default: origin'
137
+ },
138
+ set_upstream: {
139
+ type: 'boolean',
140
+ description: 'Set upstream tracking (-u flag). Default: true'
141
+ }
142
+ },
143
+ required: []
144
+ },
145
+ execute: async ({ remote, set_upstream }) => {
146
+ const remoteName = remote ?? 'origin';
147
+ const setUpstream = set_upstream ?? true;
148
+ if (!(await isGitRepo(workingDir))) {
149
+ return { success: false, output: null, error: 'Not a git repository' };
150
+ }
151
+ try {
152
+ const { stdout: branchOut } = await runGit('rev-parse --abbrev-ref HEAD', workingDir);
153
+ const currentBranch = branchOut.trim();
154
+ const upstreamFlag = setUpstream ? `-u ` : '';
155
+ const { stdout, stderr } = await runGit(`push ${upstreamFlag}${remoteName} ${currentBranch}`, workingDir);
156
+ return {
157
+ success: true,
158
+ output: { remote: remoteName, branch: currentBranch, stdout: stdout.trim(), stderr: stderr.trim() }
159
+ };
160
+ }
161
+ catch (error) {
162
+ const e = error;
163
+ return {
164
+ success: false,
165
+ output: null,
166
+ error: e.stderr?.trim() || e.message || 'git push failed'
167
+ };
168
+ }
169
+ }
170
+ },
171
+ {
172
+ name: 'git-pull',
173
+ description: 'Pull latest changes from remote',
174
+ parameters: {
175
+ type: 'object',
176
+ properties: {
177
+ remote: {
178
+ type: 'string',
179
+ description: 'Remote name. Default: origin'
180
+ },
181
+ branch: {
182
+ type: 'string',
183
+ description: 'Branch to pull. If omitted, pulls current branch'
184
+ }
185
+ },
186
+ required: []
187
+ },
188
+ execute: async ({ remote, branch }) => {
189
+ const remoteName = remote ?? 'origin';
190
+ const branchName = branch;
191
+ if (!(await isGitRepo(workingDir))) {
192
+ return { success: false, output: null, error: 'Not a git repository' };
193
+ }
194
+ try {
195
+ const branchArg = branchName ? ` ${branchName}` : '';
196
+ const { stdout, stderr } = await runGit(`pull ${remoteName}${branchArg}`, workingDir);
197
+ return {
198
+ success: true,
199
+ output: { remote: remoteName, branch: branchName ?? 'current', stdout: stdout.trim(), stderr: stderr.trim() }
200
+ };
201
+ }
202
+ catch (error) {
203
+ const e = error;
204
+ return {
205
+ success: false,
206
+ output: null,
207
+ error: e.stderr?.trim() || e.stdout?.trim() || e.message || 'git pull failed'
208
+ };
209
+ }
210
+ }
211
+ },
212
+ {
213
+ name: 'git-status',
214
+ description: 'Show working tree status (modified, added, deleted files)',
215
+ parameters: {
216
+ type: 'object',
217
+ properties: {},
218
+ required: []
219
+ },
220
+ execute: async () => {
221
+ if (!(await isGitRepo(workingDir))) {
222
+ return { success: false, output: null, error: 'Not a git repository' };
223
+ }
224
+ try {
225
+ const { stdout: porcelain } = await runGit('status --porcelain', workingDir);
226
+ const { stdout: branch } = await runGit('rev-parse --abbrev-ref HEAD', workingDir);
227
+ const files = porcelain
228
+ .split('\n')
229
+ .filter(line => line.trim())
230
+ .map(line => ({ status: line.slice(0, 2).trim(), file: line.slice(3) }));
231
+ return {
232
+ success: true,
233
+ output: {
234
+ branch: branch.trim(),
235
+ clean: files.length === 0,
236
+ files
237
+ }
238
+ };
239
+ }
240
+ catch (error) {
241
+ const e = error;
242
+ return {
243
+ success: false,
244
+ output: null,
245
+ error: e.stderr?.trim() || e.message || 'git status failed'
246
+ };
247
+ }
248
+ }
249
+ },
250
+ {
251
+ name: 'git-diff',
252
+ description: 'Show changes in working tree or staged files',
253
+ parameters: {
254
+ type: 'object',
255
+ properties: {
256
+ staged: {
257
+ type: 'boolean',
258
+ description: 'Show staged changes (--cached). Default: false'
259
+ },
260
+ file: {
261
+ type: 'string',
262
+ description: 'Diff a specific file. If omitted, shows all changes'
263
+ }
264
+ },
265
+ required: []
266
+ },
267
+ execute: async ({ staged, file }) => {
268
+ const showStaged = staged ?? false;
269
+ const filePath = file;
270
+ if (!(await isGitRepo(workingDir))) {
271
+ return { success: false, output: null, error: 'Not a git repository' };
272
+ }
273
+ try {
274
+ const stagedFlag = showStaged ? '--cached ' : '';
275
+ const fileArg = filePath ? `-- "${filePath}"` : '';
276
+ const { stdout } = await runGit(`diff ${stagedFlag}${fileArg}`.trim(), workingDir);
277
+ return {
278
+ success: true,
279
+ output: { diff: stdout, staged: showStaged, file: filePath ?? null }
280
+ };
281
+ }
282
+ catch (error) {
283
+ const e = error;
284
+ return {
285
+ success: false,
286
+ output: null,
287
+ error: e.stderr?.trim() || e.message || 'git diff failed'
288
+ };
289
+ }
290
+ }
291
+ }
292
+ ];
293
+ }
294
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/tools/builtin/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Patch tool - apply unified diffs to files
3
+ */
4
+ import type { Tool } from '../tool-registry.js';
5
+ export declare function createPatchTools(repoPath: string): Tool[];
6
+ //# sourceMappingURL=patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../../../src/tools/builtin/patch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,qBAAqB,CAAC;AAwJ5D,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,CAkGzD"}
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ /**
3
+ * Patch tool - apply unified diffs to files
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createPatchTools = createPatchTools;
40
+ const fs = __importStar(require("fs/promises"));
41
+ const path = __importStar(require("path"));
42
+ /**
43
+ * Parse a unified diff string into hunks.
44
+ */
45
+ function parseHunks(patch) {
46
+ const rawLines = patch.split('\n');
47
+ // Remove the trailing empty string that split() produces when the patch ends
48
+ // with '\n'. Without this, the '' is treated as a blank context line and gets
49
+ // appended to getOldBlock(), causing spurious "Ambiguous match" errors when
50
+ // the file contains blank lines.
51
+ if (rawLines.length > 0 && rawLines[rawLines.length - 1] === '') {
52
+ rawLines.pop();
53
+ }
54
+ // Filter out --- / +++ headers
55
+ const lines = rawLines.filter((l) => !l.startsWith('---') && !l.startsWith('+++'));
56
+ const hunks = [];
57
+ let current = null;
58
+ for (const line of lines) {
59
+ const hunkHeader = line.match(/^@@\s+-(\d+)(?:,(\d+))?\s+\+\d+(?:,\d+)?\s*@@/);
60
+ if (hunkHeader) {
61
+ current = {
62
+ oldStart: parseInt(hunkHeader[1], 10),
63
+ oldCount: parseInt(hunkHeader[2] ?? '1', 10),
64
+ lines: [],
65
+ };
66
+ hunks.push(current);
67
+ continue;
68
+ }
69
+ if (!current)
70
+ continue;
71
+ if (line.startsWith('+')) {
72
+ current.lines.push({ type: 'add', content: line.slice(1) });
73
+ }
74
+ else if (line.startsWith('-')) {
75
+ current.lines.push({ type: 'remove', content: line.slice(1) });
76
+ }
77
+ else if (line.startsWith(' ') || line === '') {
78
+ // Context line — space prefix or empty line
79
+ const content = line.startsWith(' ') ? line.slice(1) : line;
80
+ current.lines.push({ type: 'context', content });
81
+ }
82
+ // Ignore lines like ""
83
+ }
84
+ return hunks;
85
+ }
86
+ /**
87
+ * Build the "old block" — context + removed lines that must match the file.
88
+ */
89
+ function getOldBlock(hunk) {
90
+ return hunk.lines
91
+ .filter((l) => l.type === 'context' || l.type === 'remove')
92
+ .map((l) => l.content);
93
+ }
94
+ /**
95
+ * Build the "new block" — context + added lines that replace the old block.
96
+ */
97
+ function getNewBlock(hunk) {
98
+ return hunk.lines
99
+ .filter((l) => l.type === 'context' || l.type === 'add')
100
+ .map((l) => l.content);
101
+ }
102
+ /**
103
+ * Compare two strings with trailing whitespace tolerance.
104
+ */
105
+ function fuzzyMatch(a, b) {
106
+ return a.trimEnd() === b.trimEnd();
107
+ }
108
+ /**
109
+ * Check if oldBlock matches fileLines starting at position `start`.
110
+ */
111
+ function blockMatchesAt(fileLines, oldBlock, start) {
112
+ if (start + oldBlock.length > fileLines.length)
113
+ return false;
114
+ return oldBlock.every((line, i) => fuzzyMatch(fileLines[start + i], line));
115
+ }
116
+ /**
117
+ * Find where the old block matches in the file.
118
+ * Tries the hinted line first, then scans the full file.
119
+ * Returns the 0-based start index.
120
+ */
121
+ function findMatch(fileLines, oldBlock, hintLine, hunkIndex) {
122
+ // Convert 1-based hint to 0-based
123
+ const hint = hintLine - 1;
124
+ // Pure-insertion hunk: @@ -N,0 ... has no context or removed lines.
125
+ // Scanning for an empty block would vacuously match every position, so we
126
+ // insert directly at the hinted position instead.
127
+ if (oldBlock.length === 0) {
128
+ return Math.max(0, hint);
129
+ }
130
+ // Fast path: try at the hinted position
131
+ if (hint >= 0 && blockMatchesAt(fileLines, oldBlock, hint)) {
132
+ return hint;
133
+ }
134
+ // Slow path: scan the whole file
135
+ const matches = [];
136
+ for (let i = 0; i < fileLines.length; i++) {
137
+ if (blockMatchesAt(fileLines, oldBlock, i)) {
138
+ matches.push(i);
139
+ }
140
+ }
141
+ if (matches.length === 1)
142
+ return matches[0];
143
+ if (matches.length === 0) {
144
+ const expected = oldBlock[0] ?? '(empty)';
145
+ throw new Error(`Context mismatch at hunk ${hunkIndex + 1}: could not find context "${expected}" in file`);
146
+ }
147
+ throw new Error(`Ambiguous match at hunk ${hunkIndex + 1}: context found at lines ${matches.map((m) => m + 1).join(', ')}. Add more context lines.`);
148
+ }
149
+ function createPatchTools(repoPath) {
150
+ return [
151
+ {
152
+ name: 'repo_manager-apply_patch',
153
+ description: 'Apply a unified diff patch to a file. The patch must include enough context lines for unambiguous matching. Fails loudly if context doesn\'t match the file content.',
154
+ parameters: {
155
+ type: 'object',
156
+ properties: {
157
+ path: {
158
+ type: 'string',
159
+ description: 'Relative path to the file to patch (from workspace root)',
160
+ },
161
+ patch: {
162
+ type: 'string',
163
+ description: 'Unified diff format patch. Must start with @@ hunk headers. Use - for removed lines, + for added lines, space for context lines. Include at least 3 context lines before and after changes.',
164
+ },
165
+ },
166
+ required: ['path', 'patch'],
167
+ },
168
+ execute: async ({ path: filePath, patch: patchStr }) => {
169
+ try {
170
+ const fullPath = path.join(repoPath, filePath);
171
+ // Read file
172
+ let fileContent;
173
+ try {
174
+ fileContent = await fs.readFile(fullPath, 'utf-8');
175
+ }
176
+ catch {
177
+ return {
178
+ success: false,
179
+ output: null,
180
+ error: `File not found: ${filePath}`,
181
+ };
182
+ }
183
+ // Parse hunks
184
+ const hunks = parseHunks(patchStr);
185
+ if (hunks.length === 0) {
186
+ return {
187
+ success: false,
188
+ output: null,
189
+ error: 'Invalid patch format: no hunks found (expected @@ headers)',
190
+ };
191
+ }
192
+ const fileLines = fileContent.split('\n');
193
+ let totalAdded = 0;
194
+ let totalRemoved = 0;
195
+ // Find all match positions first (before any modifications)
196
+ const matchPositions = [];
197
+ for (let i = 0; i < hunks.length; i++) {
198
+ const oldBlock = getOldBlock(hunks[i]);
199
+ const pos = findMatch(fileLines, oldBlock, hunks[i].oldStart, i);
200
+ matchPositions.push(pos);
201
+ }
202
+ // Apply hunks in reverse order to preserve line numbers
203
+ const indices = hunks.map((_, i) => i);
204
+ indices.sort((a, b) => matchPositions[b] - matchPositions[a]);
205
+ for (const i of indices) {
206
+ const hunk = hunks[i];
207
+ const pos = matchPositions[i];
208
+ const oldBlock = getOldBlock(hunk);
209
+ const newBlock = getNewBlock(hunk);
210
+ fileLines.splice(pos, oldBlock.length, ...newBlock);
211
+ totalAdded += hunk.lines.filter((l) => l.type === 'add').length;
212
+ totalRemoved += hunk.lines.filter((l) => l.type === 'remove').length;
213
+ }
214
+ // Write file back
215
+ await fs.writeFile(fullPath, fileLines.join('\n'), 'utf-8');
216
+ const result = {
217
+ success: true,
218
+ path: filePath,
219
+ hunks_applied: hunks.length,
220
+ hunks_total: hunks.length,
221
+ lines_added: totalAdded,
222
+ lines_removed: totalRemoved,
223
+ };
224
+ return { success: true, output: result };
225
+ }
226
+ catch (error) {
227
+ const errorMessage = error instanceof Error ? error.message : String(error);
228
+ return {
229
+ success: false,
230
+ output: null,
231
+ error: errorMessage,
232
+ };
233
+ }
234
+ },
235
+ },
236
+ ];
237
+ }
238
+ //# sourceMappingURL=patch.js.map