@burtson-labs/agent-core 1.6.13

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 (195) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +88 -0
  3. package/dist/index.d.ts +16 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +52 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/mcp/activation.d.ts +60 -0
  8. package/dist/mcp/activation.d.ts.map +1 -0
  9. package/dist/mcp/activation.js +139 -0
  10. package/dist/mcp/activation.js.map +1 -0
  11. package/dist/mcp/clientPool.d.ts +202 -0
  12. package/dist/mcp/clientPool.d.ts.map +1 -0
  13. package/dist/mcp/clientPool.js +469 -0
  14. package/dist/mcp/clientPool.js.map +1 -0
  15. package/dist/mcp/index.d.ts +18 -0
  16. package/dist/mcp/index.d.ts.map +1 -0
  17. package/dist/mcp/index.js +28 -0
  18. package/dist/mcp/index.js.map +1 -0
  19. package/dist/mcp/server.d.ts +43 -0
  20. package/dist/mcp/server.d.ts.map +1 -0
  21. package/dist/mcp/server.js +130 -0
  22. package/dist/mcp/server.js.map +1 -0
  23. package/dist/mcp/toolAdapter.d.ts +57 -0
  24. package/dist/mcp/toolAdapter.d.ts.map +1 -0
  25. package/dist/mcp/toolAdapter.js +223 -0
  26. package/dist/mcp/toolAdapter.js.map +1 -0
  27. package/dist/mcp/types.d.ts +122 -0
  28. package/dist/mcp/types.d.ts.map +1 -0
  29. package/dist/mcp/types.js +15 -0
  30. package/dist/mcp/types.js.map +1 -0
  31. package/dist/providers/deterministic-provider.d.ts +21 -0
  32. package/dist/providers/deterministic-provider.d.ts.map +1 -0
  33. package/dist/providers/deterministic-provider.js +80 -0
  34. package/dist/providers/deterministic-provider.js.map +1 -0
  35. package/dist/providers/provider-client.d.ts +12 -0
  36. package/dist/providers/provider-client.d.ts.map +1 -0
  37. package/dist/providers/provider-client.js +11 -0
  38. package/dist/providers/provider-client.js.map +1 -0
  39. package/dist/runtime/AgentRuntime.d.ts +67 -0
  40. package/dist/runtime/AgentRuntime.d.ts.map +1 -0
  41. package/dist/runtime/AgentRuntime.js +382 -0
  42. package/dist/runtime/AgentRuntime.js.map +1 -0
  43. package/dist/security/secretPatterns.d.ts +76 -0
  44. package/dist/security/secretPatterns.d.ts.map +1 -0
  45. package/dist/security/secretPatterns.js +290 -0
  46. package/dist/security/secretPatterns.js.map +1 -0
  47. package/dist/tools/ask-user-tool.d.ts +19 -0
  48. package/dist/tools/ask-user-tool.d.ts.map +1 -0
  49. package/dist/tools/ask-user-tool.js +148 -0
  50. package/dist/tools/ask-user-tool.js.map +1 -0
  51. package/dist/tools/compactMessages.d.ts +52 -0
  52. package/dist/tools/compactMessages.d.ts.map +1 -0
  53. package/dist/tools/compactMessages.js +158 -0
  54. package/dist/tools/compactMessages.js.map +1 -0
  55. package/dist/tools/core-tools.d.ts +29 -0
  56. package/dist/tools/core-tools.d.ts.map +1 -0
  57. package/dist/tools/core-tools.js +2214 -0
  58. package/dist/tools/core-tools.js.map +1 -0
  59. package/dist/tools/git-tools.d.ts +32 -0
  60. package/dist/tools/git-tools.d.ts.map +1 -0
  61. package/dist/tools/git-tools.js +330 -0
  62. package/dist/tools/git-tools.js.map +1 -0
  63. package/dist/tools/index.d.ts +15 -0
  64. package/dist/tools/index.d.ts.map +1 -0
  65. package/dist/tools/index.js +31 -0
  66. package/dist/tools/index.js.map +1 -0
  67. package/dist/tools/language-adapters.d.ts +48 -0
  68. package/dist/tools/language-adapters.d.ts.map +1 -0
  69. package/dist/tools/language-adapters.js +299 -0
  70. package/dist/tools/language-adapters.js.map +1 -0
  71. package/dist/tools/loop/compactionTrigger.d.ts +47 -0
  72. package/dist/tools/loop/compactionTrigger.d.ts.map +1 -0
  73. package/dist/tools/loop/compactionTrigger.js +32 -0
  74. package/dist/tools/loop/compactionTrigger.js.map +1 -0
  75. package/dist/tools/loop/finalAnswerNudges.d.ts +68 -0
  76. package/dist/tools/loop/finalAnswerNudges.d.ts.map +1 -0
  77. package/dist/tools/loop/finalAnswerNudges.js +87 -0
  78. package/dist/tools/loop/finalAnswerNudges.js.map +1 -0
  79. package/dist/tools/loop/goalAnchor.d.ts +72 -0
  80. package/dist/tools/loop/goalAnchor.d.ts.map +1 -0
  81. package/dist/tools/loop/goalAnchor.js +76 -0
  82. package/dist/tools/loop/goalAnchor.js.map +1 -0
  83. package/dist/tools/loop/llmStream.d.ts +70 -0
  84. package/dist/tools/loop/llmStream.d.ts.map +1 -0
  85. package/dist/tools/loop/llmStream.js +181 -0
  86. package/dist/tools/loop/llmStream.js.map +1 -0
  87. package/dist/tools/loop/parallelExecute.d.ts +57 -0
  88. package/dist/tools/loop/parallelExecute.d.ts.map +1 -0
  89. package/dist/tools/loop/parallelExecute.js +54 -0
  90. package/dist/tools/loop/parallelExecute.js.map +1 -0
  91. package/dist/tools/loop/singleToolExecute.d.ts +71 -0
  92. package/dist/tools/loop/singleToolExecute.d.ts.map +1 -0
  93. package/dist/tools/loop/singleToolExecute.js +139 -0
  94. package/dist/tools/loop/singleToolExecute.js.map +1 -0
  95. package/dist/tools/loop/toolCallNormalize.d.ts +57 -0
  96. package/dist/tools/loop/toolCallNormalize.d.ts.map +1 -0
  97. package/dist/tools/loop/toolCallNormalize.js +99 -0
  98. package/dist/tools/loop/toolCallNormalize.js.map +1 -0
  99. package/dist/tools/loop/turnSetup.d.ts +43 -0
  100. package/dist/tools/loop/turnSetup.d.ts.map +1 -0
  101. package/dist/tools/loop/turnSetup.js +48 -0
  102. package/dist/tools/loop/turnSetup.js.map +1 -0
  103. package/dist/tools/ocr.d.ts +52 -0
  104. package/dist/tools/ocr.d.ts.map +1 -0
  105. package/dist/tools/ocr.js +238 -0
  106. package/dist/tools/ocr.js.map +1 -0
  107. package/dist/tools/post-edit-checks.d.ts +46 -0
  108. package/dist/tools/post-edit-checks.d.ts.map +1 -0
  109. package/dist/tools/post-edit-checks.js +236 -0
  110. package/dist/tools/post-edit-checks.js.map +1 -0
  111. package/dist/tools/skill-loader.d.ts +94 -0
  112. package/dist/tools/skill-loader.d.ts.map +1 -0
  113. package/dist/tools/skill-loader.js +422 -0
  114. package/dist/tools/skill-loader.js.map +1 -0
  115. package/dist/tools/skill-registry.d.ts +44 -0
  116. package/dist/tools/skill-registry.d.ts.map +1 -0
  117. package/dist/tools/skill-registry.js +118 -0
  118. package/dist/tools/skill-registry.js.map +1 -0
  119. package/dist/tools/skill-types.d.ts +38 -0
  120. package/dist/tools/skill-types.d.ts.map +1 -0
  121. package/dist/tools/skill-types.js +10 -0
  122. package/dist/tools/skill-types.js.map +1 -0
  123. package/dist/tools/skills/code-review-skill.d.ts +9 -0
  124. package/dist/tools/skills/code-review-skill.d.ts.map +1 -0
  125. package/dist/tools/skills/code-review-skill.js +66 -0
  126. package/dist/tools/skills/code-review-skill.js.map +1 -0
  127. package/dist/tools/skills/core-skill.d.ts +13 -0
  128. package/dist/tools/skills/core-skill.d.ts.map +1 -0
  129. package/dist/tools/skills/core-skill.js +23 -0
  130. package/dist/tools/skills/core-skill.js.map +1 -0
  131. package/dist/tools/skills/git-skill.d.ts +10 -0
  132. package/dist/tools/skills/git-skill.d.ts.map +1 -0
  133. package/dist/tools/skills/git-skill.js +30 -0
  134. package/dist/tools/skills/git-skill.js.map +1 -0
  135. package/dist/tools/skills/index.d.ts +17 -0
  136. package/dist/tools/skills/index.d.ts.map +1 -0
  137. package/dist/tools/skills/index.js +49 -0
  138. package/dist/tools/skills/index.js.map +1 -0
  139. package/dist/tools/skills/interaction-skill.d.ts +14 -0
  140. package/dist/tools/skills/interaction-skill.d.ts.map +1 -0
  141. package/dist/tools/skills/interaction-skill.js +24 -0
  142. package/dist/tools/skills/interaction-skill.js.map +1 -0
  143. package/dist/tools/skills/mail-search-skill.d.ts +25 -0
  144. package/dist/tools/skills/mail-search-skill.d.ts.map +1 -0
  145. package/dist/tools/skills/mail-search-skill.js +343 -0
  146. package/dist/tools/skills/mail-search-skill.js.map +1 -0
  147. package/dist/tools/skills/plan-skill.d.ts +10 -0
  148. package/dist/tools/skills/plan-skill.d.ts.map +1 -0
  149. package/dist/tools/skills/plan-skill.js +126 -0
  150. package/dist/tools/skills/plan-skill.js.map +1 -0
  151. package/dist/tools/skills/semantic-search-skill.d.ts +22 -0
  152. package/dist/tools/skills/semantic-search-skill.d.ts.map +1 -0
  153. package/dist/tools/skills/semantic-search-skill.js +244 -0
  154. package/dist/tools/skills/semantic-search-skill.js.map +1 -0
  155. package/dist/tools/skills/test-gen-skill.d.ts +9 -0
  156. package/dist/tools/skills/test-gen-skill.d.ts.map +1 -0
  157. package/dist/tools/skills/test-gen-skill.js +123 -0
  158. package/dist/tools/skills/test-gen-skill.js.map +1 -0
  159. package/dist/tools/tool-registry.d.ts +60 -0
  160. package/dist/tools/tool-registry.d.ts.map +1 -0
  161. package/dist/tools/tool-registry.js +200 -0
  162. package/dist/tools/tool-registry.js.map +1 -0
  163. package/dist/tools/tool-types.d.ts +281 -0
  164. package/dist/tools/tool-types.d.ts.map +1 -0
  165. package/dist/tools/tool-types.js +10 -0
  166. package/dist/tools/tool-types.js.map +1 -0
  167. package/dist/tools/tool-use-loop.d.ts +231 -0
  168. package/dist/tools/tool-use-loop.d.ts.map +1 -0
  169. package/dist/tools/tool-use-loop.js +2057 -0
  170. package/dist/tools/tool-use-loop.js.map +1 -0
  171. package/dist/tools/tool-use-parser.d.ts +78 -0
  172. package/dist/tools/tool-use-parser.d.ts.map +1 -0
  173. package/dist/tools/tool-use-parser.js +427 -0
  174. package/dist/tools/tool-use-parser.js.map +1 -0
  175. package/dist/tools/toolAvailabilityDetector.d.ts +48 -0
  176. package/dist/tools/toolAvailabilityDetector.d.ts.map +1 -0
  177. package/dist/tools/toolAvailabilityDetector.js +156 -0
  178. package/dist/tools/toolAvailabilityDetector.js.map +1 -0
  179. package/dist/tools/unified-patch.d.ts +87 -0
  180. package/dist/tools/unified-patch.d.ts.map +1 -0
  181. package/dist/tools/unified-patch.js +217 -0
  182. package/dist/tools/unified-patch.js.map +1 -0
  183. package/dist/types/agent.d.ts +69 -0
  184. package/dist/types/agent.d.ts.map +1 -0
  185. package/dist/types/agent.js +54 -0
  186. package/dist/types/agent.js.map +1 -0
  187. package/dist/types/tasks.d.ts +22 -0
  188. package/dist/types/tasks.d.ts.map +1 -0
  189. package/dist/types/tasks.js +3 -0
  190. package/dist/types/tasks.js.map +1 -0
  191. package/dist/utils/event-emitter.d.ts +13 -0
  192. package/dist/utils/event-emitter.d.ts.map +1 -0
  193. package/dist/utils/event-emitter.js +54 -0
  194. package/dist/utils/event-emitter.js.map +1 -0
  195. package/package.json +33 -0
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ /**
3
+ * Local OCR — extract printed text from an image file without an LLM.
4
+ *
5
+ * Dispatcher picks the best available engine for the platform:
6
+ * macOS → Apple Vision via `swift` running a VNRecognizeTextRequest
7
+ * script. ~100-300ms per image, excellent on rendered text
8
+ * (code, logs, stack traces, dialogs).
9
+ * Linux → tesseract CLI (`apt install tesseract-ocr`). ~500ms-2s.
10
+ * Windows → tesseract CLI (PowerShell.Windows.Media.Ocr could be
11
+ * added later; tesseract covers the common case today).
12
+ *
13
+ * Used by the extension/CLI on bandit-logic turns where a user paste
14
+ * an image. When OCR yields usable text, we inline it into the prompt
15
+ * as an `[Image text (OCR): …]` block and skip the model swap. When
16
+ * OCR returns nothing (diagrams, photos, blurry), we fall back to a
17
+ * vision-capable model for that turn.
18
+ *
19
+ * Binary OCR engines themselves are not bundled — we shell out to what
20
+ * the user's OS already ships. Linux/Windows users see a one-time
21
+ * install hint when tesseract is missing.
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.detectOcrAvailability = detectOcrAvailability;
58
+ exports.extractImageText = extractImageText;
59
+ exports.ocrYieldedUsefulText = ocrYieldedUsefulText;
60
+ const cp = __importStar(require("child_process"));
61
+ const fs = __importStar(require("fs"));
62
+ const os = __importStar(require("os"));
63
+ const path = __importStar(require("path"));
64
+ /**
65
+ * Detect available OCR engines without actually running one. Used by the
66
+ * UI to decide whether to offer the "OCR-first" toggle. Results are
67
+ * cached for the process lifetime because `which` is a filesystem
68
+ * lookup we don't need to repeat on every image.
69
+ */
70
+ let cachedAvailability = null;
71
+ function detectOcrAvailability() {
72
+ if (cachedAvailability)
73
+ return cachedAvailability;
74
+ const apple = process.platform === 'darwin' && hasBinary('swift');
75
+ const tesseract = hasBinary('tesseract');
76
+ cachedAvailability = { apple, tesseract };
77
+ return cachedAvailability;
78
+ }
79
+ function hasBinary(name) {
80
+ try {
81
+ const result = cp.spawnSync(process.platform === 'win32' ? 'where' : 'which', [name], { stdio: 'pipe' });
82
+ return result.status === 0;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * Extract text from an image at `imagePath`. Returns an OcrResult with
90
+ * empty `.text` on failure rather than throwing — callers treat "empty
91
+ * text" as the signal to fall back to an LLM-vision path.
92
+ */
93
+ async function extractImageText(imagePath, options) {
94
+ const startedAt = Date.now();
95
+ const timeout = options?.timeoutMs ?? 8000;
96
+ if (!fs.existsSync(imagePath)) {
97
+ return { text: '', engine: 'none', durationMs: 0 };
98
+ }
99
+ const availability = detectOcrAvailability();
100
+ if (process.platform === 'darwin' && availability.apple) {
101
+ const text = await runAppleVision(imagePath, timeout);
102
+ if (text.length > 0) {
103
+ return { text, engine: 'apple-vision', durationMs: Date.now() - startedAt };
104
+ }
105
+ }
106
+ if (availability.tesseract) {
107
+ const text = await runTesseract(imagePath, timeout);
108
+ if (text.length > 0) {
109
+ return { text, engine: 'tesseract', durationMs: Date.now() - startedAt };
110
+ }
111
+ }
112
+ return { text: '', engine: 'none', durationMs: Date.now() - startedAt };
113
+ }
114
+ /**
115
+ * Inline Swift script that drives Apple's Vision framework. Using
116
+ * `swift -e` avoids shipping a compiled binary — Xcode CLT's `swift`
117
+ * is present on any Mac with dev tools. The script accepts the image
118
+ * path as argv[1] and prints extracted strings (one per line) to
119
+ * stdout. Any error goes to stderr with a non-zero exit so the caller
120
+ * can distinguish "empty image" from "tool failure".
121
+ */
122
+ const APPLE_VISION_SCRIPT = `
123
+ import Foundation
124
+ import Vision
125
+ import AppKit
126
+
127
+ guard CommandLine.arguments.count >= 2 else {
128
+ FileHandle.standardError.write("usage: ocr <image-path>\\n".data(using: .utf8)!)
129
+ exit(2)
130
+ }
131
+ let path = CommandLine.arguments[1]
132
+ guard let nsimage = NSImage(contentsOfFile: path), let tiff = nsimage.tiffRepresentation,
133
+ let rep = NSBitmapImageRep(data: tiff), let cg = rep.cgImage else {
134
+ FileHandle.standardError.write("failed to load image\\n".data(using: .utf8)!)
135
+ exit(3)
136
+ }
137
+ let request = VNRecognizeTextRequest()
138
+ request.recognitionLevel = .accurate
139
+ request.usesLanguageCorrection = false
140
+ let handler = VNImageRequestHandler(cgImage: cg, options: [:])
141
+ do {
142
+ try handler.perform([request])
143
+ let observations = request.results ?? []
144
+ var lines: [String] = []
145
+ for obs in observations {
146
+ if let top = obs.topCandidates(1).first {
147
+ lines.append(top.string)
148
+ }
149
+ }
150
+ print(lines.joined(separator: "\\n"))
151
+ } catch {
152
+ FileHandle.standardError.write("vision error: \\(error.localizedDescription)\\n".data(using: .utf8)!)
153
+ exit(4)
154
+ }
155
+ `;
156
+ function runAppleVision(imagePath, timeoutMs) {
157
+ return new Promise((resolve) => {
158
+ // Cache the script on disk so repeat invocations don't re-write it
159
+ // every call. `swift` interprets it with its line-by-line mode
160
+ // each time — the script itself is free, the Swift runtime cold
161
+ // start costs ~80-120ms.
162
+ const cachedScriptPath = path.join(os.tmpdir(), 'bandit-ocr-apple-vision.swift');
163
+ try {
164
+ if (!fs.existsSync(cachedScriptPath)) {
165
+ fs.writeFileSync(cachedScriptPath, APPLE_VISION_SCRIPT, 'utf-8');
166
+ }
167
+ }
168
+ catch {
169
+ resolve('');
170
+ return;
171
+ }
172
+ const child = cp.spawn('swift', [cachedScriptPath, imagePath], { stdio: ['ignore', 'pipe', 'pipe'] });
173
+ let stdout = '';
174
+ let stderr = '';
175
+ const timer = setTimeout(() => { try {
176
+ child.kill('SIGTERM');
177
+ }
178
+ catch { /* already gone */ } }, timeoutMs);
179
+ child.stdout.on('data', (d) => { stdout += d.toString(); });
180
+ child.stderr.on('data', (d) => { stderr += d.toString(); });
181
+ child.on('close', (code) => {
182
+ clearTimeout(timer);
183
+ if (code !== 0) {
184
+ resolve('');
185
+ return;
186
+ }
187
+ resolve(stdout.trim());
188
+ });
189
+ child.on('error', () => { clearTimeout(timer); resolve(''); });
190
+ });
191
+ }
192
+ /**
193
+ * Tesseract CLI invocation. `--psm 6` (uniform block of text) gives the
194
+ * best results on screenshots of code/logs; `--psm 3` (default) splits
195
+ * columns which hurts accuracy when the model then reads the result.
196
+ * `-l eng` is the safe default; users can override via a setting later.
197
+ */
198
+ function runTesseract(imagePath, timeoutMs) {
199
+ return new Promise((resolve) => {
200
+ const child = cp.spawn('tesseract', [imagePath, '-', '-l', 'eng', '--psm', '6'], {
201
+ stdio: ['ignore', 'pipe', 'pipe']
202
+ });
203
+ let stdout = '';
204
+ const timer = setTimeout(() => { try {
205
+ child.kill('SIGTERM');
206
+ }
207
+ catch { /* already gone */ } }, timeoutMs);
208
+ child.stdout.on('data', (d) => { stdout += d.toString(); });
209
+ child.on('close', (code) => {
210
+ clearTimeout(timer);
211
+ if (code !== 0) {
212
+ resolve('');
213
+ return;
214
+ }
215
+ resolve(stdout.trim());
216
+ });
217
+ child.on('error', () => { clearTimeout(timer); resolve(''); });
218
+ });
219
+ }
220
+ /**
221
+ * Heuristic for "the OCR captured enough to be useful". Used by the
222
+ * image-handling path to decide between "inline OCR text + stay on
223
+ * current model" vs "fall back to a vision-capable model". Very cheap;
224
+ * runs once per image.
225
+ */
226
+ function ocrYieldedUsefulText(text) {
227
+ if (!text)
228
+ return false;
229
+ const trimmed = text.trim();
230
+ if (trimmed.length < 30)
231
+ return false;
232
+ // Printable-ratio sanity check — if the "text" is mostly gibberish
233
+ // tokens (photo, diagram, blurry UI) the ratio of word chars to
234
+ // length drops below ~50%. Cheap and effective.
235
+ const alphaNum = (trimmed.match(/[A-Za-z0-9]/g) ?? []).length;
236
+ return alphaNum / trimmed.length > 0.45;
237
+ }
238
+ //# sourceMappingURL=ocr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocr.js","sourceRoot":"","sources":["../../src/tools/ocr.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Post-edit deep checks — close the agent's feedback loop.
3
+ *
4
+ * Bandit's self-evaluations have repeatedly flagged "no automatic
5
+ * verification after changes" as a top gap. The existing language-
6
+ * adapter system runs a per-file PARSE check (ts.transpileModule for
7
+ * TS, JSON.parse for JSON, etc.) before write — fast, but doesn't
8
+ * catch type errors, broken imports, or any cross-file regression
9
+ * the model just introduced.
10
+ *
11
+ * This module runs the project-level tooling AFTER the write has
12
+ * landed and surfaces ONLY the errors that weren't there before.
13
+ * Pre-existing rot is ignored (same invariant as introducedNewErrors
14
+ * — we only block when THIS edit introduced something new).
15
+ *
16
+ * Strategy:
17
+ * - lazy: only fires when the touched file lives in a project that
18
+ * has the relevant tooling installed (tsconfig.json + typescript
19
+ * in node_modules for the TS check). Quietly returns no-op when
20
+ * the workspace doesn't support it — never blocks an edit on
21
+ * missing tooling.
22
+ * - per-project caching: the first edit to a project pays for
23
+ * baselining the existing error set, subsequent edits diff
24
+ * against that cached baseline (and update it after each run).
25
+ * - bounded: 30s hard timeout so a broken tsconfig or huge project
26
+ * can't lock up the loop.
27
+ * - opt-in via NO env var (defaults on). Can be disabled per-call
28
+ * by callers passing a flag, or globally by setting
29
+ * BANDIT_DISABLE_POST_EDIT_CHECKS=1.
30
+ */
31
+ import type { ToolExecutionContext } from './tool-types';
32
+ export interface PostEditCheckResult {
33
+ /** Human-readable warning to append to the tool result. Undefined when
34
+ * the check found no new errors or could not run. */
35
+ warning?: string;
36
+ /** Number of NEW errors detected (post − pre). Always 0 if warning is
37
+ * undefined. Useful for telemetry. */
38
+ newErrorCount: number;
39
+ }
40
+ /**
41
+ * Run a post-edit project-level type check on the touched file's
42
+ * project. Returns any NEW errors introduced by this edit, ignoring
43
+ * pre-existing ones.
44
+ */
45
+ export declare function runPostEditTypeCheck(absPath: string, ctx: ToolExecutionContext): Promise<PostEditCheckResult>;
46
+ //# sourceMappingURL=post-edit-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-edit-checks.d.ts","sourceRoot":"","sources":["../../src/tools/post-edit-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAmFzD,MAAM,WAAW,mBAAmB;IAClC;0DACsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;2CACuC;IACvC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAkF9B"}
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ /**
3
+ * Post-edit deep checks — close the agent's feedback loop.
4
+ *
5
+ * Bandit's self-evaluations have repeatedly flagged "no automatic
6
+ * verification after changes" as a top gap. The existing language-
7
+ * adapter system runs a per-file PARSE check (ts.transpileModule for
8
+ * TS, JSON.parse for JSON, etc.) before write — fast, but doesn't
9
+ * catch type errors, broken imports, or any cross-file regression
10
+ * the model just introduced.
11
+ *
12
+ * This module runs the project-level tooling AFTER the write has
13
+ * landed and surfaces ONLY the errors that weren't there before.
14
+ * Pre-existing rot is ignored (same invariant as introducedNewErrors
15
+ * — we only block when THIS edit introduced something new).
16
+ *
17
+ * Strategy:
18
+ * - lazy: only fires when the touched file lives in a project that
19
+ * has the relevant tooling installed (tsconfig.json + typescript
20
+ * in node_modules for the TS check). Quietly returns no-op when
21
+ * the workspace doesn't support it — never blocks an edit on
22
+ * missing tooling.
23
+ * - per-project caching: the first edit to a project pays for
24
+ * baselining the existing error set, subsequent edits diff
25
+ * against that cached baseline (and update it after each run).
26
+ * - bounded: 30s hard timeout so a broken tsconfig or huge project
27
+ * can't lock up the loop.
28
+ * - opt-in via NO env var (defaults on). Can be disabled per-call
29
+ * by callers passing a flag, or globally by setting
30
+ * BANDIT_DISABLE_POST_EDIT_CHECKS=1.
31
+ */
32
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ var desc = Object.getOwnPropertyDescriptor(m, k);
35
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
36
+ desc = { enumerable: true, get: function() { return m[k]; } };
37
+ }
38
+ Object.defineProperty(o, k2, desc);
39
+ }) : (function(o, m, k, k2) {
40
+ if (k2 === undefined) k2 = k;
41
+ o[k2] = m[k];
42
+ }));
43
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
44
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
45
+ }) : function(o, v) {
46
+ o["default"] = v;
47
+ });
48
+ var __importStar = (this && this.__importStar) || (function () {
49
+ var ownKeys = function(o) {
50
+ ownKeys = Object.getOwnPropertyNames || function (o) {
51
+ var ar = [];
52
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
53
+ return ar;
54
+ };
55
+ return ownKeys(o);
56
+ };
57
+ return function (mod) {
58
+ if (mod && mod.__esModule) return mod;
59
+ var result = {};
60
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
61
+ __setModuleDefault(result, mod);
62
+ return result;
63
+ };
64
+ })();
65
+ Object.defineProperty(exports, "__esModule", { value: true });
66
+ exports.runPostEditTypeCheck = runPostEditTypeCheck;
67
+ const path = __importStar(require("node:path"));
68
+ const fs = __importStar(require("node:fs"));
69
+ /**
70
+ * Per-project baseline cache — error set keyed by absolute tsconfig
71
+ * path. Module-scoped so it persists across edits in a single
72
+ * session. Fresh process / fresh CLI launch starts empty.
73
+ */
74
+ const TS_BASELINE_CACHE = new Map();
75
+ const POST_EDIT_TIMEOUT_MS = 30000;
76
+ const MAX_NEW_ERRORS_REPORTED = 8;
77
+ const TSC_FILE_EXTS = new Set(['ts', 'tsx', 'cts', 'mts']);
78
+ /**
79
+ * Walk up from `start` looking for the nearest `tsconfig.json` (or
80
+ * `jsconfig.json` as a fallback for JS-only projects). Returns
81
+ * undefined if none found before hitting the filesystem root.
82
+ */
83
+ function findNearestTsconfig(start) {
84
+ let dir = path.dirname(start);
85
+ const root = path.parse(dir).root;
86
+ while (dir && dir !== root) {
87
+ for (const candidate of ['tsconfig.json', 'jsconfig.json']) {
88
+ const probe = path.join(dir, candidate);
89
+ try {
90
+ if (fs.statSync(probe).isFile())
91
+ return probe;
92
+ }
93
+ catch { /* not present, keep walking */ }
94
+ }
95
+ const next = path.dirname(dir);
96
+ if (next === dir)
97
+ break;
98
+ dir = next;
99
+ }
100
+ return undefined;
101
+ }
102
+ /**
103
+ * Detect whether the project has typescript installed locally —
104
+ * either a direct dep or hoisted to a parent `node_modules`. We
105
+ * check by looking for the ts binary in node_modules/.bin OR the
106
+ * package's package.json. Cheap stat, no resolve overhead.
107
+ */
108
+ function hasTypeScriptInstalled(tsconfigPath) {
109
+ let dir = path.dirname(tsconfigPath);
110
+ const root = path.parse(dir).root;
111
+ while (dir && dir !== root) {
112
+ const probes = [
113
+ path.join(dir, 'node_modules', 'typescript', 'package.json'),
114
+ path.join(dir, 'node_modules', '.bin', 'tsc')
115
+ ];
116
+ for (const p of probes) {
117
+ try {
118
+ if (fs.statSync(p))
119
+ return true;
120
+ }
121
+ catch { /* keep walking */ }
122
+ }
123
+ const next = path.dirname(dir);
124
+ if (next === dir)
125
+ break;
126
+ dir = next;
127
+ }
128
+ return false;
129
+ }
130
+ /**
131
+ * Parse `tsc --noEmit` output into a set of unique error lines.
132
+ * tsc lines look like:
133
+ * src/foo.ts(12,3): error TS2304: Cannot find name 'bar'.
134
+ * We normalize position info out so the same logical error round-trips
135
+ * across edits that shift line numbers — same trick as
136
+ * introducedNewErrors in core-tools.ts.
137
+ */
138
+ function parseTscErrors(stdout) {
139
+ const errors = new Set();
140
+ for (const rawLine of stdout.split('\n')) {
141
+ const line = rawLine.trim();
142
+ if (!line)
143
+ continue;
144
+ // Look for the "error TSxxxx" marker — tsc emits both errors and
145
+ // warnings; we only care about errors here.
146
+ if (!/error TS\d+:/.test(line))
147
+ continue;
148
+ // Strip line/col so a position shift doesn't register as a new
149
+ // error. "src/foo.ts(12,3)" → "src/foo.ts(N,N)".
150
+ const normalized = line.replace(/\(\d+,\d+\)/g, '(N,N)');
151
+ errors.add(normalized);
152
+ }
153
+ return errors;
154
+ }
155
+ /**
156
+ * Run a post-edit project-level type check on the touched file's
157
+ * project. Returns any NEW errors introduced by this edit, ignoring
158
+ * pre-existing ones.
159
+ */
160
+ async function runPostEditTypeCheck(absPath, ctx) {
161
+ if (process.env.BANDIT_DISABLE_POST_EDIT_CHECKS === '1') {
162
+ return { newErrorCount: 0 };
163
+ }
164
+ // Only TS/TSX/CTS/MTS files trigger the tsc check. JS/JSX edits
165
+ // don't catch much from tsc unless allowJs is on, which is
166
+ // project-specific; skip for now to avoid false positives.
167
+ const ext = absPath.split('.').pop()?.toLowerCase() ?? '';
168
+ if (!TSC_FILE_EXTS.has(ext))
169
+ return { newErrorCount: 0 };
170
+ const tsconfig = findNearestTsconfig(absPath);
171
+ if (!tsconfig)
172
+ return { newErrorCount: 0 };
173
+ if (!hasTypeScriptInstalled(tsconfig))
174
+ return { newErrorCount: 0 };
175
+ // Run tsc --noEmit on the project. Use --incremental so subsequent
176
+ // runs in the same session use cached build info (much faster than
177
+ // a cold compile). The buildinfo path is per-tsconfig hash so two
178
+ // workspaces don't collide.
179
+ const tsconfigDir = path.dirname(tsconfig);
180
+ let result;
181
+ try {
182
+ // Use a Promise.race against a timeout — ctx.runCommand does its
183
+ // own timeout but we want a hard cap regardless of host config.
184
+ result = await Promise.race([
185
+ ctx.runCommand('npx', ['--no-install', 'tsc', '--noEmit', '-p', tsconfig, '--incremental'], tsconfigDir),
186
+ new Promise((resolve) => {
187
+ setTimeout(() => resolve({
188
+ stdout: '',
189
+ stderr: 'post-edit-check: tsc timed out after 30s',
190
+ exitCode: 124
191
+ }), POST_EDIT_TIMEOUT_MS);
192
+ })
193
+ ]);
194
+ }
195
+ catch (err) {
196
+ // Don't let post-edit-check failure break the tool result.
197
+ return { newErrorCount: 0, warning: undefined };
198
+ }
199
+ if (result.exitCode === 124) {
200
+ // Timeout — skip silently rather than report a stale baseline.
201
+ return { newErrorCount: 0 };
202
+ }
203
+ const currentErrors = parseTscErrors(result.stdout + '\n' + result.stderr);
204
+ const cached = TS_BASELINE_CACHE.get(tsconfig);
205
+ // Update cache regardless so the next edit diffs against THIS state.
206
+ TS_BASELINE_CACHE.set(tsconfig, currentErrors);
207
+ // First run for this project — no baseline to diff against. Record
208
+ // the current error set as the baseline; do not report anything.
209
+ // The first edit per project per session is "free" — we only catch
210
+ // NEW errors from EDIT N+1 onwards. Trade-off: the very first edit
211
+ // could introduce errors that go unreported until the next edit.
212
+ // Acceptable for now; alternative is to baseline pre-edit on EVERY
213
+ // first edit which doubles the latency budget.
214
+ if (!cached)
215
+ return { newErrorCount: 0 };
216
+ const newErrors = [];
217
+ for (const err of currentErrors) {
218
+ if (!cached.has(err))
219
+ newErrors.push(err);
220
+ }
221
+ if (newErrors.length === 0)
222
+ return { newErrorCount: 0 };
223
+ const shown = newErrors.slice(0, MAX_NEW_ERRORS_REPORTED);
224
+ const more = newErrors.length > MAX_NEW_ERRORS_REPORTED
225
+ ? `\n …and ${newErrors.length - MAX_NEW_ERRORS_REPORTED} more`
226
+ : '';
227
+ const projectLabel = path.relative(process.cwd(), tsconfig) || tsconfig;
228
+ return {
229
+ newErrorCount: newErrors.length,
230
+ warning: `\n\n[Post-edit type check on ${projectLabel}] ${newErrors.length} NEW TypeScript error${newErrors.length === 1 ? '' : 's'} this edit introduced:\n ` +
231
+ shown.join('\n ') +
232
+ more +
233
+ '\n\nFix these in the next iteration. Pre-existing errors in the project are ignored.'
234
+ };
235
+ }
236
+ //# sourceMappingURL=post-edit-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-edit-checks.js","sourceRoot":"","sources":["../../src/tools/post-edit-checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Skill loader — discovers and loads custom skills from the workspace.
3
+ *
4
+ * Scans `.bandit/skills/` and registers any skills it finds with the
5
+ * SkillRegistry. Two formats are supported:
6
+ *
7
+ * 1. Markdown (`.md`) — preferred. Matches Claude Code's shape. A skill is
8
+ * a context package: YAML frontmatter for metadata, markdown body for
9
+ * the prose instructions the agent reads when the skill activates.
10
+ * No `tools[]` — skills guide the agent on how to use tools it already
11
+ * has (run_command, git_*, write_file, …). This eliminates the nested
12
+ * JSON-in-JSON escaping trap that plagued the JSON format.
13
+ *
14
+ * 2. JSON (`.json`) — legacy. Still loads so existing `.bandit/skills/*.json`
15
+ * keep working, but new authoring should use markdown. Logs a one-time
16
+ * deprecation note in dev.
17
+ *
18
+ * Markdown layout (both `.bandit/skills/<name>.md` and
19
+ * `.bandit/skills/<name>/SKILL.md` are supported — the folder variant lets
20
+ * users bundle helper scripts next to the skill):
21
+ *
22
+ * ---
23
+ * id: github
24
+ * name: GitHub CLI
25
+ * description: Use when the user mentions GitHub — PRs, issues, commits
26
+ * triggers: [gh, github, pr, "pull request"]
27
+ * ---
28
+ *
29
+ * When the user asks about GitHub work, use `run_command` with `gh`:
30
+ *
31
+ * - `gh pr create --title "<t>" --body "<b>"` — open a PR
32
+ * - `gh pr list` — list open PRs
33
+ * - `gh issue list` — list issues
34
+ *
35
+ * Suggest `gh auth status` if commands fail.
36
+ *
37
+ * Frontmatter keys recognized: `id`, `name`, `description`, `version`,
38
+ * `activation` (always|auto|on-demand — defaults to auto), `triggers`
39
+ * (simple substring list — matched case-insensitive against the user
40
+ * message), and `triggerPatterns` (explicit regex list — advanced).
41
+ *
42
+ * Legacy JSON schema (still supported, deprecated for new skills):
43
+ *
44
+ * {
45
+ * "id": "custom/my-skill",
46
+ * "name": "My Custom Skill",
47
+ * "description": "…",
48
+ * "activation": "auto",
49
+ * "triggerPatterns": ["\\bmy-keyword\\b"],
50
+ * "tools": [
51
+ * { "name": "my_tool", "description": "…", "command": "node x.js {{arg}}" }
52
+ * ]
53
+ * }
54
+ */
55
+ import type { SkillManifest } from './skill-types';
56
+ import type { AgentTool } from './tool-types';
57
+ import { SkillRegistry } from './skill-registry';
58
+ interface RawToolManifest {
59
+ name: string;
60
+ description: string;
61
+ parameters?: Array<{
62
+ name: string;
63
+ description: string;
64
+ required?: boolean;
65
+ }>;
66
+ command?: string;
67
+ }
68
+ export declare function buildToolFromManifest(raw: RawToolManifest): AgentTool;
69
+ /**
70
+ * Load custom skills from `.bandit/skills/` in the workspace.
71
+ *
72
+ * Discovers markdown skills first (preferred), then JSON skills (legacy).
73
+ * When a JSON skill has the same id as a markdown one already loaded, the
74
+ * markdown version wins and the JSON one is skipped — that's the migration
75
+ * path: drop a `.md` next to the old `.json` and the new format takes over.
76
+ *
77
+ * @param listFiles lists files matching a glob pattern relative to cwd
78
+ * @param readFile reads a file's text content at an absolute path
79
+ * @param workspaceRoot absolute workspace root
80
+ */
81
+ export declare function loadWorkspaceSkills(listFiles: (pattern: string, cwd?: string) => Promise<string[]>, readFile: (path: string) => Promise<string>, workspaceRoot: string): Promise<SkillManifest[]>;
82
+ /**
83
+ * Load workspace skills and register them with the given registry.
84
+ */
85
+ export declare function registerWorkspaceSkills(registry: SkillRegistry, listFiles: (pattern: string, cwd?: string) => Promise<string[]>, readFile: (path: string) => Promise<string>, workspaceRoot: string): Promise<number>;
86
+ /**
87
+ * A ready-to-save markdown skill scaffold. Used by the CLI's `/skill new`
88
+ * slash command so users (and the agent) never have to hand-write the YAML
89
+ * frontmatter from scratch. Kept here so there's one canonical template
90
+ * and it can't drift from what the parser expects.
91
+ */
92
+ export declare function scaffoldMarkdownSkill(id: string, displayName?: string): string;
93
+ export {};
94
+ //# sourceMappingURL=skill-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-loader.d.ts","sourceRoot":"","sources":["../../src/tools/skill-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAoC,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIjD,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuBD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,SAAS,CA2DrE;AA+ND;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,EAC/D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAC3C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CAoD1B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,EAC/D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAC3C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAsB9E"}