zora-agent 0.10.0 → 0.10.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 (166) hide show
  1. package/README.md +171 -65
  2. package/dist/cli/daemon.js +1 -0
  3. package/dist/cli/daemon.js.map +1 -1
  4. package/dist/cli/index.js +27 -0
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/secret-commands.d.ts +16 -0
  7. package/dist/cli/secret-commands.d.ts.map +1 -0
  8. package/dist/cli/secret-commands.js +87 -0
  9. package/dist/cli/secret-commands.js.map +1 -0
  10. package/dist/cli/skill-commands.d.ts.map +1 -1
  11. package/dist/cli/skill-commands.js +75 -0
  12. package/dist/cli/skill-commands.js.map +1 -1
  13. package/dist/cli/subagent-commands.d.ts +13 -0
  14. package/dist/cli/subagent-commands.d.ts.map +1 -0
  15. package/dist/cli/subagent-commands.js +80 -0
  16. package/dist/cli/subagent-commands.js.map +1 -0
  17. package/dist/config/defaults.d.ts +6 -0
  18. package/dist/config/defaults.d.ts.map +1 -1
  19. package/dist/config/defaults.js +6 -0
  20. package/dist/config/defaults.js.map +1 -1
  21. package/dist/dashboard/cost-tracker.d.ts +40 -0
  22. package/dist/dashboard/cost-tracker.d.ts.map +1 -0
  23. package/dist/dashboard/cost-tracker.js +63 -0
  24. package/dist/dashboard/cost-tracker.js.map +1 -0
  25. package/dist/dashboard/frontend/dist/assets/{index-DSXaCp9r.js → index-Bi0V-1ti.js} +83 -83
  26. package/dist/dashboard/frontend/dist/assets/index-SQqtXVeO.css +1 -0
  27. package/dist/dashboard/frontend/dist/index.html +2 -2
  28. package/dist/dashboard/server.d.ts +5 -0
  29. package/dist/dashboard/server.d.ts.map +1 -1
  30. package/dist/dashboard/server.js +17 -0
  31. package/dist/dashboard/server.js.map +1 -1
  32. package/dist/hooks/built-in/audit-log.d.ts +13 -0
  33. package/dist/hooks/built-in/audit-log.d.ts.map +1 -0
  34. package/dist/hooks/built-in/audit-log.js +48 -0
  35. package/dist/hooks/built-in/audit-log.js.map +1 -0
  36. package/dist/hooks/built-in/rate-limit.d.ts +18 -0
  37. package/dist/hooks/built-in/rate-limit.d.ts.map +1 -0
  38. package/dist/hooks/built-in/rate-limit.js +30 -0
  39. package/dist/hooks/built-in/rate-limit.js.map +1 -0
  40. package/dist/hooks/built-in/secret-redact.d.ts +7 -0
  41. package/dist/hooks/built-in/secret-redact.d.ts.map +1 -0
  42. package/dist/hooks/built-in/secret-redact.js +33 -0
  43. package/dist/hooks/built-in/secret-redact.js.map +1 -0
  44. package/dist/hooks/built-in/shell-safety.d.ts +7 -0
  45. package/dist/hooks/built-in/shell-safety.d.ts.map +1 -0
  46. package/dist/hooks/built-in/shell-safety.js +34 -0
  47. package/dist/hooks/built-in/shell-safety.js.map +1 -0
  48. package/dist/hooks/index.d.ts +5 -0
  49. package/dist/hooks/index.d.ts.map +1 -1
  50. package/dist/hooks/index.js +5 -0
  51. package/dist/hooks/index.js.map +1 -1
  52. package/dist/hooks/tool-hook-runner.d.ts +36 -0
  53. package/dist/hooks/tool-hook-runner.d.ts.map +1 -0
  54. package/dist/hooks/tool-hook-runner.js +49 -0
  55. package/dist/hooks/tool-hook-runner.js.map +1 -0
  56. package/dist/lib/error-normalizer.d.ts +53 -0
  57. package/dist/lib/error-normalizer.d.ts.map +1 -0
  58. package/dist/lib/error-normalizer.js +128 -0
  59. package/dist/lib/error-normalizer.js.map +1 -0
  60. package/dist/memory/context-compressor.d.ts +3 -1
  61. package/dist/memory/context-compressor.d.ts.map +1 -1
  62. package/dist/memory/context-compressor.js +18 -3
  63. package/dist/memory/context-compressor.js.map +1 -1
  64. package/dist/memory/plan-cache.d.ts +27 -0
  65. package/dist/memory/plan-cache.d.ts.map +1 -0
  66. package/dist/memory/plan-cache.js +91 -0
  67. package/dist/memory/plan-cache.js.map +1 -0
  68. package/dist/orchestrator/code-tool-runner.d.ts +41 -0
  69. package/dist/orchestrator/code-tool-runner.d.ts.map +1 -0
  70. package/dist/orchestrator/code-tool-runner.js +375 -0
  71. package/dist/orchestrator/code-tool-runner.js.map +1 -0
  72. package/dist/orchestrator/error-pattern-detector.d.ts +54 -0
  73. package/dist/orchestrator/error-pattern-detector.d.ts.map +1 -0
  74. package/dist/orchestrator/error-pattern-detector.js +87 -0
  75. package/dist/orchestrator/error-pattern-detector.js.map +1 -0
  76. package/dist/orchestrator/execution-planner.d.ts +33 -0
  77. package/dist/orchestrator/execution-planner.d.ts.map +1 -0
  78. package/dist/orchestrator/execution-planner.js +67 -0
  79. package/dist/orchestrator/execution-planner.js.map +1 -0
  80. package/dist/orchestrator/orchestrator.d.ts +77 -0
  81. package/dist/orchestrator/orchestrator.d.ts.map +1 -1
  82. package/dist/orchestrator/orchestrator.js +595 -29
  83. package/dist/orchestrator/orchestrator.js.map +1 -1
  84. package/dist/orchestrator/retry-queue.d.ts +7 -1
  85. package/dist/orchestrator/retry-queue.d.ts.map +1 -1
  86. package/dist/orchestrator/retry-queue.js +10 -4
  87. package/dist/orchestrator/retry-queue.js.map +1 -1
  88. package/dist/orchestrator/step-classifier.d.ts +26 -0
  89. package/dist/orchestrator/step-classifier.d.ts.map +1 -0
  90. package/dist/orchestrator/step-classifier.js +77 -0
  91. package/dist/orchestrator/step-classifier.js.map +1 -0
  92. package/dist/orchestrator/tlci-dispatcher.d.ts +47 -0
  93. package/dist/orchestrator/tlci-dispatcher.d.ts.map +1 -0
  94. package/dist/orchestrator/tlci-dispatcher.js +116 -0
  95. package/dist/orchestrator/tlci-dispatcher.js.map +1 -0
  96. package/dist/routines/heartbeat.d.ts.map +1 -1
  97. package/dist/routines/heartbeat.js +3 -1
  98. package/dist/routines/heartbeat.js.map +1 -1
  99. package/dist/routines/routine-manager.d.ts.map +1 -1
  100. package/dist/routines/routine-manager.js +3 -1
  101. package/dist/routines/routine-manager.js.map +1 -1
  102. package/dist/security/intent-capsule.d.ts +19 -0
  103. package/dist/security/intent-capsule.d.ts.map +1 -1
  104. package/dist/security/intent-capsule.js +84 -1
  105. package/dist/security/intent-capsule.js.map +1 -1
  106. package/dist/security/policy-engine.d.ts +1 -0
  107. package/dist/security/policy-engine.d.ts.map +1 -1
  108. package/dist/security/policy-engine.js +22 -1
  109. package/dist/security/policy-engine.js.map +1 -1
  110. package/dist/services/negative-cache.d.ts +67 -0
  111. package/dist/services/negative-cache.d.ts.map +1 -0
  112. package/dist/services/negative-cache.js +164 -0
  113. package/dist/services/negative-cache.js.map +1 -0
  114. package/dist/skills/skill-auditor.d.ts +36 -0
  115. package/dist/skills/skill-auditor.d.ts.map +1 -0
  116. package/dist/skills/skill-auditor.js +89 -0
  117. package/dist/skills/skill-auditor.js.map +1 -0
  118. package/dist/skills/skill-installer.d.ts +41 -0
  119. package/dist/skills/skill-installer.d.ts.map +1 -0
  120. package/dist/skills/skill-installer.js +141 -0
  121. package/dist/skills/skill-installer.js.map +1 -0
  122. package/dist/skills/skill-scanner.d.ts +30 -0
  123. package/dist/skills/skill-scanner.d.ts.map +1 -0
  124. package/dist/skills/skill-scanner.js +249 -0
  125. package/dist/skills/skill-scanner.js.map +1 -0
  126. package/dist/tools/index.d.ts +2 -0
  127. package/dist/tools/index.d.ts.map +1 -1
  128. package/dist/tools/index.js +2 -0
  129. package/dist/tools/index.js.map +1 -1
  130. package/dist/tools/planning-tool.d.ts +95 -0
  131. package/dist/tools/planning-tool.d.ts.map +1 -0
  132. package/dist/tools/planning-tool.js +117 -0
  133. package/dist/tools/planning-tool.js.map +1 -0
  134. package/dist/tools/skill-tool.d.ts +94 -0
  135. package/dist/tools/skill-tool.d.ts.map +1 -0
  136. package/dist/tools/skill-tool.js +202 -0
  137. package/dist/tools/skill-tool.js.map +1 -0
  138. package/dist/tools/subagent-tool.d.ts +11 -0
  139. package/dist/tools/subagent-tool.d.ts.map +1 -0
  140. package/dist/tools/subagent-tool.js +87 -0
  141. package/dist/tools/subagent-tool.js.map +1 -0
  142. package/dist/types.d.ts +22 -0
  143. package/dist/types.d.ts.map +1 -1
  144. package/dist/utils/args.d.ts +5 -0
  145. package/dist/utils/args.d.ts.map +1 -0
  146. package/dist/utils/args.js +20 -0
  147. package/dist/utils/args.js.map +1 -0
  148. package/package.json +4 -1
  149. package/dist/dashboard/frontend/dist/assets/index-2FaDr6iS.js +0 -277
  150. package/dist/dashboard/frontend/dist/assets/index-B9-KXW14.css +0 -1
  151. package/dist/dashboard/frontend/dist/assets/index-BMxbyTer.css +0 -1
  152. package/dist/dashboard/frontend/dist/assets/index-BXUfB9iR.js +0 -253
  153. package/dist/dashboard/frontend/dist/assets/index-BcOGj1EF.css +0 -1
  154. package/dist/dashboard/frontend/dist/assets/index-BtiFO9YN.js +0 -261
  155. package/dist/dashboard/frontend/dist/assets/index-CQmpMTLW.js +0 -253
  156. package/dist/dashboard/frontend/dist/assets/index-Cfjy5acU.css +0 -1
  157. package/dist/dashboard/frontend/dist/assets/index-D41hcjgc.js +0 -253
  158. package/dist/dashboard/frontend/dist/assets/index-D83BawFd.css +0 -1
  159. package/dist/dashboard/frontend/dist/assets/index-DAODjoxu.css +0 -1
  160. package/dist/dashboard/frontend/dist/assets/index-DB-Eu5oV.js +0 -253
  161. package/dist/dashboard/frontend/dist/assets/index-W0VVEDu6.js +0 -253
  162. package/dist/dashboard/frontend/dist/assets/index-aK9PWl6w.js +0 -253
  163. package/dist/dashboard/frontend/vite.config.d.ts +0 -3
  164. package/dist/dashboard/frontend/vite.config.d.ts.map +0 -1
  165. package/dist/dashboard/frontend/vite.config.js +0 -11
  166. package/dist/dashboard/frontend/vite.config.js.map +0 -1
@@ -0,0 +1,375 @@
1
+ /**
2
+ * CodeToolRunner — Tier 1 deterministic tool implementations for TLCI.
3
+ *
4
+ * Each function corresponds to a `suggestedCodeTool` hint from the StepClassifier.
5
+ * Callers pass structured parameters via `step.context`.
6
+ *
7
+ * Context keys (caller-provided):
8
+ * httpFetch: { url: string, headers?: Record<string,string> }
9
+ * httpPost: { url: string, body?: unknown, headers?: Record<string,string> }
10
+ * transform: { data: unknown, operation?: 'json-parse'|'json-stringify'|'to-array'|'flatten' }
11
+ * collectionOp:{ data: unknown[], operation?: 'sort'|'filter'|'count'|'deduplicate', key?: string, value?: unknown }
12
+ * fileOp: { path: string, operation?: 'read'|'write'|'list'|'exists', content?: string }
13
+ * compute: { expression: string } — safe arithmetic only (no eval)
14
+ * validate: { data: unknown, required?: string[] }
15
+ * notify: { message: string, channel?: string }
16
+ * dbQuery: { query: string } — stub; real DB wired by caller
17
+ */
18
+ import fs from 'node:fs/promises';
19
+ import path from 'node:path';
20
+ import os from 'node:os';
21
+ import { createLogger } from '../utils/logger.js';
22
+ const log = createLogger('code-tool-runner');
23
+ function validateUrl(url) {
24
+ let parsed;
25
+ try {
26
+ parsed = new URL(url);
27
+ }
28
+ catch {
29
+ throw new Error(`Invalid URL: ${url}`);
30
+ }
31
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
32
+ throw new Error(`Blocked URL scheme "${parsed.protocol}" — only http/https allowed`);
33
+ }
34
+ const host = parsed.hostname.toLowerCase();
35
+ // Block literal private/metadata IP ranges and known internal hostnames.
36
+ // KNOWN LIMITATION: DNS-rebinding attacks (public hostname → private IP) are not
37
+ // prevented here because pre-resolution DNS checks have an inherent TOCTOU race.
38
+ // For production hardening, use a network-level egress proxy or firewall instead.
39
+ const BLOCKED = [
40
+ /^localhost$/,
41
+ /^127\./,
42
+ /^10\./,
43
+ /^172\.(1[6-9]|2\d|3[01])\./,
44
+ /^192\.168\./,
45
+ /^169\.254\./, // link-local / AWS metadata
46
+ /^::1$/, // IPv6 loopback (URL parser strips brackets)
47
+ /^::ffff:/, // IPv4-mapped IPv6 (e.g. ::ffff:192.168.1.1)
48
+ /^0+:0+:0+:0+:0+:0+:0+:1$/, // full-form IPv6 loopback
49
+ /^metadata\.google\.internal$/,
50
+ ];
51
+ if (BLOCKED.some(r => r.test(host))) {
52
+ throw new Error(`Blocked host "${host}" — private/metadata addresses not allowed`);
53
+ }
54
+ }
55
+ // ─── Individual tool implementations ─────────────────────────────────────────
56
+ async function runHttpFetch(ctx) {
57
+ const url = ctx['url'];
58
+ if (!url)
59
+ return { tool: 'httpFetch', success: false, error: 'context.url required' };
60
+ const headers = ctx['headers'] ?? {};
61
+ try {
62
+ validateUrl(url);
63
+ }
64
+ catch (err) {
65
+ return { tool: 'httpFetch', success: false, error: String(err) };
66
+ }
67
+ try {
68
+ const controller = new AbortController();
69
+ const timeout = setTimeout(() => controller.abort(), 30_000);
70
+ const res = await fetch(url, { headers, signal: controller.signal });
71
+ clearTimeout(timeout);
72
+ const text = await res.text();
73
+ let data = text;
74
+ try {
75
+ data = JSON.parse(text);
76
+ }
77
+ catch { /* keep raw text */ }
78
+ log.debug({ url, status: res.status }, 'httpFetch complete');
79
+ return { tool: 'httpFetch', success: res.ok, data };
80
+ }
81
+ catch (err) {
82
+ return { tool: 'httpFetch', success: false, error: String(err) };
83
+ }
84
+ }
85
+ async function runHttpPost(ctx) {
86
+ const url = ctx['url'];
87
+ if (!url)
88
+ return { tool: 'httpPost', success: false, error: 'context.url required' };
89
+ const body = ctx['body'];
90
+ const headers = ctx['headers'] ?? { 'Content-Type': 'application/json' };
91
+ try {
92
+ validateUrl(url);
93
+ }
94
+ catch (err) {
95
+ return { tool: 'httpPost', success: false, error: String(err) };
96
+ }
97
+ try {
98
+ const controller = new AbortController();
99
+ const timeout = setTimeout(() => controller.abort(), 30_000);
100
+ const res = await fetch(url, {
101
+ method: 'POST',
102
+ headers,
103
+ body: body !== undefined ? JSON.stringify(body) : undefined,
104
+ signal: controller.signal,
105
+ });
106
+ clearTimeout(timeout);
107
+ const text = await res.text();
108
+ let data = text;
109
+ try {
110
+ data = JSON.parse(text);
111
+ }
112
+ catch { /* keep raw text */ }
113
+ log.debug({ url, status: res.status }, 'httpPost complete');
114
+ return { tool: 'httpPost', success: res.ok, data };
115
+ }
116
+ catch (err) {
117
+ return { tool: 'httpPost', success: false, error: String(err) };
118
+ }
119
+ }
120
+ function runTransform(ctx) {
121
+ const data = ctx['data'];
122
+ const operation = ctx['operation'] ?? 'json-stringify';
123
+ try {
124
+ let result;
125
+ switch (operation) {
126
+ case 'json-parse':
127
+ result = typeof data === 'string' ? JSON.parse(data) : data;
128
+ break;
129
+ case 'json-stringify':
130
+ result = JSON.stringify(data, null, 2);
131
+ break;
132
+ case 'to-array':
133
+ result = Array.isArray(data) ? data : data !== undefined ? [data] : [];
134
+ break;
135
+ case 'flatten':
136
+ result = Array.isArray(data) ? data.flat(Infinity) : data;
137
+ break;
138
+ default:
139
+ result = data;
140
+ }
141
+ return { tool: 'transform', success: true, data: result };
142
+ }
143
+ catch (err) {
144
+ return { tool: 'transform', success: false, error: String(err) };
145
+ }
146
+ }
147
+ function runCollectionOp(ctx) {
148
+ const raw = ctx['data'];
149
+ const arr = Array.isArray(raw) ? raw : raw !== undefined ? [raw] : [];
150
+ const operation = ctx['operation'] ?? 'count';
151
+ const key = ctx['key'];
152
+ const value = ctx['value'];
153
+ try {
154
+ let result;
155
+ switch (operation) {
156
+ case 'count':
157
+ result = arr.length;
158
+ break;
159
+ case 'filter':
160
+ result = key !== undefined
161
+ ? arr.filter((item) => typeof item === 'object' && item !== null && item[key] === value)
162
+ : arr;
163
+ break;
164
+ case 'sort':
165
+ result = key !== undefined
166
+ ? [...arr].sort((a, b) => {
167
+ const av = typeof a === 'object' && a !== null ? a[key] : a;
168
+ const bv = typeof b === 'object' && b !== null ? b[key] : b;
169
+ if (av === undefined && bv === undefined)
170
+ return 0;
171
+ if (av === undefined)
172
+ return 1;
173
+ if (bv === undefined)
174
+ return -1;
175
+ return av < bv ? -1 : av > bv ? 1 : 0;
176
+ })
177
+ : [...arr].sort();
178
+ break;
179
+ case 'deduplicate':
180
+ result = key !== undefined
181
+ ? [...new Map(arr.map((item) => [item[key], item])).values()]
182
+ : [...new Set(arr)];
183
+ break;
184
+ case 'sum':
185
+ result = arr.reduce((acc, item) => {
186
+ const v = key !== undefined && typeof item === 'object' && item !== null
187
+ ? Number(item[key])
188
+ : Number(item);
189
+ return acc + (isNaN(v) ? 0 : v);
190
+ }, 0);
191
+ break;
192
+ default:
193
+ result = arr;
194
+ }
195
+ return { tool: 'collectionOp', success: true, data: result };
196
+ }
197
+ catch (err) {
198
+ return { tool: 'collectionOp', success: false, error: String(err) };
199
+ }
200
+ }
201
+ async function runFileOp(ctx) {
202
+ const filePath = ctx['path'];
203
+ if (!filePath)
204
+ return { tool: 'fileOp', success: false, error: 'context.path required' };
205
+ const expanded = filePath.replace(/^~/, os.homedir() ?? '');
206
+ const normalized = path.resolve(expanded);
207
+ if (normalized.includes('\0')) {
208
+ return { tool: 'fileOp', success: false, error: 'Path traversal attempt blocked' };
209
+ }
210
+ // Restrict to safe directories — block sensitive paths first, then require an allowed prefix
211
+ const home = os.homedir() ?? os.tmpdir();
212
+ const ALLOWED_PREFIXES = [
213
+ path.join(home, '.zora'),
214
+ path.join(home, 'Dev'),
215
+ path.join(home, 'Documents'),
216
+ '/tmp',
217
+ '/private/tmp', // macOS resolves /tmp → /private/tmp
218
+ os.tmpdir(), // macOS: /var/folders/... or /tmp on Linux
219
+ process.cwd(),
220
+ ];
221
+ const BLOCKED_PREFIXES = [
222
+ path.join(home, '.ssh'),
223
+ path.join(home, '.gnupg'),
224
+ path.join(home, '.aws'),
225
+ path.join(home, '.env'),
226
+ '/etc',
227
+ '/sys',
228
+ '/proc',
229
+ ];
230
+ if (BLOCKED_PREFIXES.some(p => normalized.startsWith(p))) {
231
+ return { tool: 'fileOp', success: false, error: `Path "${normalized}" is outside allowed workspace` };
232
+ }
233
+ if (!ALLOWED_PREFIXES.some(p => normalized.startsWith(p))) {
234
+ return { tool: 'fileOp', success: false, error: `Path "${normalized}" is outside allowed workspace` };
235
+ }
236
+ const operation = ctx['operation'] ?? 'read';
237
+ try {
238
+ let data;
239
+ switch (operation) {
240
+ case 'read': {
241
+ const raw = await fs.readFile(normalized, 'utf-8');
242
+ try {
243
+ data = JSON.parse(raw);
244
+ }
245
+ catch {
246
+ data = raw;
247
+ }
248
+ break;
249
+ }
250
+ case 'write': {
251
+ const content = ctx['content'];
252
+ const str = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
253
+ await fs.writeFile(normalized, str, 'utf-8');
254
+ data = { written: str.length };
255
+ break;
256
+ }
257
+ case 'list': {
258
+ const entries = await fs.readdir(normalized, { withFileTypes: true });
259
+ data = entries.map(e => ({ name: e.name, isDir: e.isDirectory() }));
260
+ break;
261
+ }
262
+ case 'exists': {
263
+ try {
264
+ await fs.access(normalized);
265
+ data = true;
266
+ }
267
+ catch {
268
+ data = false;
269
+ }
270
+ break;
271
+ }
272
+ default:
273
+ return { tool: 'fileOp', success: false, error: `Unknown operation: ${operation}` };
274
+ }
275
+ log.debug({ path: normalized, operation }, 'fileOp complete');
276
+ return { tool: 'fileOp', success: true, data };
277
+ }
278
+ catch (err) {
279
+ return { tool: 'fileOp', success: false, error: String(err) };
280
+ }
281
+ }
282
+ function runCompute(ctx) {
283
+ const expression = ctx['expression'];
284
+ if (!expression)
285
+ return { tool: 'compute', success: false, error: 'context.expression required' };
286
+ // Safe: only allow numbers, operators, parentheses, spaces, dots
287
+ if (!/^[\d\s+\-*/().%]+$/.test(expression)) {
288
+ return { tool: 'compute', success: false, error: 'Expression contains disallowed characters (only arithmetic allowed)' };
289
+ }
290
+ try {
291
+ // Use Function constructor with no scope — safe for pure arithmetic
292
+ // eslint-disable-next-line no-new-func
293
+ const result = new Function(`"use strict"; return (${expression});`)();
294
+ return { tool: 'compute', success: true, data: result };
295
+ }
296
+ catch (err) {
297
+ return { tool: 'compute', success: false, error: String(err) };
298
+ }
299
+ }
300
+ function runValidate(ctx) {
301
+ const data = ctx['data'];
302
+ const required = ctx['required'];
303
+ if (!required || required.length === 0) {
304
+ return { tool: 'validate', success: true, data: { valid: data !== null && data !== undefined } };
305
+ }
306
+ if (typeof data !== 'object' || data === null) {
307
+ return { tool: 'validate', success: true, data: { valid: false, missing: required } };
308
+ }
309
+ const obj = data;
310
+ const missing = required.filter(k => !(k in obj) || obj[k] === null || obj[k] === undefined);
311
+ return { tool: 'validate', success: true, data: { valid: missing.length === 0, missing } };
312
+ }
313
+ function runNotify(ctx) {
314
+ const message = ctx['message'] ?? 'Notification';
315
+ const channel = ctx['channel'] ?? 'log';
316
+ log.info({ channel, message }, 'tlci notify step');
317
+ return { tool: 'notify', success: true, data: { sent: true, channel, message } };
318
+ }
319
+ async function runDbQuery(ctx) {
320
+ // Stub — real DB connection is caller-provided via context.execute fn
321
+ const query = ctx['query'];
322
+ const executeFn = ctx['execute'];
323
+ if (executeFn && query) {
324
+ try {
325
+ const rows = await executeFn(query);
326
+ return { tool: 'dbQuery', success: true, data: rows };
327
+ }
328
+ catch (err) {
329
+ return { tool: 'dbQuery', success: false, error: String(err) };
330
+ }
331
+ }
332
+ log.info({ query }, 'tlci dbQuery step (stub — provide context.execute for real queries)');
333
+ return { tool: 'dbQuery', success: true, data: { rows: [], stub: true } };
334
+ }
335
+ // ─── Dispatch table ───────────────────────────────────────────────────────────
336
+ const SYNC_TOOLS = {
337
+ transform: runTransform,
338
+ collectionOp: runCollectionOp,
339
+ compute: runCompute,
340
+ validate: runValidate,
341
+ notify: runNotify,
342
+ };
343
+ const ASYNC_TOOLS = {
344
+ httpFetch: runHttpFetch,
345
+ httpPost: runHttpPost,
346
+ fileOp: runFileOp,
347
+ dbQuery: runDbQuery,
348
+ };
349
+ // ─── Public runner ────────────────────────────────────────────────────────────
350
+ /**
351
+ * Execute a Tier 1 code tool step.
352
+ * Returns a CodeToolResult — callers may inspect result.data for downstream steps.
353
+ */
354
+ export async function runCodeTool(tool, context = {}) {
355
+ const asyncFn = ASYNC_TOOLS[tool];
356
+ if (asyncFn)
357
+ return asyncFn(context);
358
+ const syncFn = SYNC_TOOLS[tool];
359
+ if (syncFn)
360
+ return syncFn(context);
361
+ // Unknown tool — log and pass through
362
+ log.info({ tool }, 'tlci code-tool step (no implementation for this tool — pass-through)');
363
+ return { tool, success: true, data: null };
364
+ }
365
+ /**
366
+ * Resolve the suggested tool from a ClassifiedStep and run it.
367
+ * The step's `context` field holds structured parameters.
368
+ */
369
+ export async function runCodeToolStep(step) {
370
+ const tool = step.suggestedCodeTool ?? 'pass-through';
371
+ const ctx = step.context ?? {};
372
+ log.debug({ stepId: step.id, tool }, 'running code tool');
373
+ return runCodeTool(tool, ctx);
374
+ }
375
+ //# sourceMappingURL=code-tool-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-tool-runner.js","sourceRoot":"","sources":["../../src/orchestrator/code-tool-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * ErrorPatternDetector — ERR-10: In-Session Repeat Detection (Circuit Breaker)
3
+ *
4
+ * Maintains a rolling window of recent tool results within a single session.
5
+ * If the same tool+args signature fails twice, it injects a hard steering hint
6
+ * to force the LLM to change its approach.
7
+ */
8
+ export interface ToolAttempt {
9
+ signature: string;
10
+ toolName: string;
11
+ /** Canonical string of args used to generate the signature */
12
+ argsKey: string;
13
+ succeeded: boolean;
14
+ timestamp: number;
15
+ }
16
+ export interface RepeatDetectionResult {
17
+ /** True if the same (tool, args) has failed the threshold number of times */
18
+ isRepeating: boolean;
19
+ /** Steering hint to inject when isRepeating is true */
20
+ hint?: string;
21
+ /** Tool name that is repeating */
22
+ toolName?: string;
23
+ }
24
+ export declare class ErrorPatternDetector {
25
+ /** Rolling window of the last N tool attempts (per session instance) */
26
+ private readonly _window;
27
+ /**
28
+ * Record a tool result in the rolling window.
29
+ *
30
+ * @param toolName - Name of the tool that was called
31
+ * @param args - Arguments passed to the tool
32
+ * @param succeeded - Whether the tool call succeeded
33
+ * @returns RepeatDetectionResult — isRepeating=true if a steering hint should be injected
34
+ */
35
+ record(toolName: string, args: Record<string, unknown>, succeeded: boolean): RepeatDetectionResult;
36
+ /**
37
+ * Reset the rolling window (e.g. at the start of a new task).
38
+ */
39
+ reset(): void;
40
+ /**
41
+ * Return the current window contents for inspection/testing.
42
+ */
43
+ getWindow(): readonly ToolAttempt[];
44
+ /**
45
+ * Compute a stable SHA-256 hash over tool_name + canonical args string.
46
+ */
47
+ private _computeSignature;
48
+ /**
49
+ * Normalize args to a canonical string for stable hashing.
50
+ * Sorts keys so {a:1, b:2} and {b:2, a:1} produce the same signature.
51
+ */
52
+ private _normalizeArgs;
53
+ }
54
+ //# sourceMappingURL=error-pattern-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-pattern-detector.d.ts","sourceRoot":"","sources":["../../src/orchestrator/error-pattern-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAYD,qBAAa,oBAAoB;IAC/B,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C;;;;;;;OAOG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,GAAG,qBAAqB;IAsClG;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,SAAS,IAAI,SAAS,WAAW,EAAE;IAMnC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;OAGG;IACH,OAAO,CAAC,cAAc;CAGvB"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * ErrorPatternDetector — ERR-10: In-Session Repeat Detection (Circuit Breaker)
3
+ *
4
+ * Maintains a rolling window of recent tool results within a single session.
5
+ * If the same tool+args signature fails twice, it injects a hard steering hint
6
+ * to force the LLM to change its approach.
7
+ */
8
+ import crypto from 'node:crypto';
9
+ import { canonicalizeArgs } from '../utils/args.js';
10
+ // ─── Constants ────────────────────────────────────────────────────────
11
+ /** How many recent tool results to keep in the rolling window */
12
+ const WINDOW_SIZE = 5;
13
+ /** How many failures of the same signature trigger a steering injection */
14
+ const FAILURE_THRESHOLD = 2;
15
+ // ─── ErrorPatternDetector ─────────────────────────────────────────────
16
+ export class ErrorPatternDetector {
17
+ /** Rolling window of the last N tool attempts (per session instance) */
18
+ _window = [];
19
+ /**
20
+ * Record a tool result in the rolling window.
21
+ *
22
+ * @param toolName - Name of the tool that was called
23
+ * @param args - Arguments passed to the tool
24
+ * @param succeeded - Whether the tool call succeeded
25
+ * @returns RepeatDetectionResult — isRepeating=true if a steering hint should be injected
26
+ */
27
+ record(toolName, args, succeeded) {
28
+ const argsKey = this._normalizeArgs(args);
29
+ const signature = this._computeSignature(toolName, argsKey);
30
+ const attempt = {
31
+ signature,
32
+ toolName,
33
+ argsKey,
34
+ succeeded,
35
+ timestamp: Date.now(),
36
+ };
37
+ // Append and keep only the last WINDOW_SIZE entries
38
+ this._window.push(attempt);
39
+ if (this._window.length > WINDOW_SIZE) {
40
+ this._window.shift();
41
+ }
42
+ // Check if this signature has failed >= FAILURE_THRESHOLD times in the window
43
+ if (!succeeded) {
44
+ const failureCount = this._window.filter(a => a.signature === signature && !a.succeeded).length;
45
+ if (failureCount >= FAILURE_THRESHOLD) {
46
+ return {
47
+ isRepeating: true,
48
+ toolName,
49
+ hint: `You have attempted ${toolName} with these arguments ${failureCount} time(s) and failed. ` +
50
+ `You MUST change your parameters or use a different tool.`,
51
+ };
52
+ }
53
+ }
54
+ return { isRepeating: false };
55
+ }
56
+ /**
57
+ * Reset the rolling window (e.g. at the start of a new task).
58
+ */
59
+ reset() {
60
+ this._window.length = 0;
61
+ }
62
+ /**
63
+ * Return the current window contents for inspection/testing.
64
+ */
65
+ getWindow() {
66
+ return this._window;
67
+ }
68
+ // ─── Internal ──────────────────────────────────────────────────────
69
+ /**
70
+ * Compute a stable SHA-256 hash over tool_name + canonical args string.
71
+ */
72
+ _computeSignature(toolName, argsKey) {
73
+ return crypto
74
+ .createHash('sha256')
75
+ .update(toolName + ':' + argsKey)
76
+ .digest('hex')
77
+ .slice(0, 16); // 16 hex chars = 64 bits — sufficient for in-session use
78
+ }
79
+ /**
80
+ * Normalize args to a canonical string for stable hashing.
81
+ * Sorts keys so {a:1, b:2} and {b:2, a:1} produce the same signature.
82
+ */
83
+ _normalizeArgs(args) {
84
+ return canonicalizeArgs(args);
85
+ }
86
+ }
87
+ //# sourceMappingURL=error-pattern-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-pattern-detector.js","sourceRoot":"","sources":["../../src/orchestrator/error-pattern-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAsBpD,yEAAyE;AAEzE,iEAAiE;AACjE,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,2EAA2E;AAC3E,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,yEAAyE;AAEzE,MAAM,OAAO,oBAAoB;IAC/B,wEAAwE;IACvD,OAAO,GAAkB,EAAE,CAAC;IAE7C;;;;;;;OAOG;IACH,MAAM,CAAC,QAAgB,EAAE,IAA6B,EAAE,SAAkB;QACxE,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE5D,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,QAAQ;YACR,OAAO;YACP,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,oDAAoD;QACpD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAED,8EAA8E;QAC9E,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,CAC/C,CAAC,MAAM,CAAC;YAET,IAAI,YAAY,IAAI,iBAAiB,EAAE,CAAC;gBACtC,OAAO;oBACL,WAAW,EAAE,IAAI;oBACjB,QAAQ;oBACR,IAAI,EACF,sBAAsB,QAAQ,yBAAyB,YAAY,uBAAuB;wBAC1F,0DAA0D;iBAC7D,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,sEAAsE;IAEtE;;OAEG;IACK,iBAAiB,CAAC,QAAgB,EAAE,OAAe;QACzD,OAAO,MAAM;aACV,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC,QAAQ,GAAG,GAAG,GAAG,OAAO,CAAC;aAChC,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,yDAAyD;IAC5E,CAAC;IAED;;;OAGG;IACK,cAAc,CAAC,IAA6B;QAClD,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ import { type ClassifiedStep, type WorkflowStep, type StepTier } from './step-classifier.js';
2
+ export interface TierBreakdown {
3
+ code: number;
4
+ slm: number;
5
+ frontier: number;
6
+ }
7
+ export interface CostComparison {
8
+ tlciEstimate: number;
9
+ allLLMEstimate: number;
10
+ savingsUSD: number;
11
+ savingsPct: number;
12
+ }
13
+ export interface ExecutionPlan {
14
+ planId: string;
15
+ planHash: string;
16
+ steps: ClassifiedStep[];
17
+ tierBreakdown: TierBreakdown;
18
+ costComparison: CostComparison;
19
+ createdAt: number;
20
+ approvedAt?: number;
21
+ approved: boolean;
22
+ }
23
+ export type { StepTier };
24
+ /**
25
+ * Compute a deterministic plan hash from step descriptions and type metadata.
26
+ * Excludes `context` (runtime state) — only classification-relevant fields are hashed.
27
+ * 32 hex chars (128 bits) to reduce collision risk.
28
+ */
29
+ export declare function computePlanHash(steps: WorkflowStep[]): string;
30
+ export declare function buildExecutionPlan(steps: WorkflowStep[]): ExecutionPlan;
31
+ export declare function formatPlanForApproval(plan: ExecutionPlan): string;
32
+ export declare function formatPlanSummary(plan: ExecutionPlan): string;
33
+ //# sourceMappingURL=execution-planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-planner.d.ts","sourceRoot":"","sources":["../../src/orchestrator/execution-planner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE5G,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;CAAE;AAC/E,MAAM,WAAW,cAAc;IAAG,YAAY,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;CAAE;AACzH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,EAAE,CAAC;IAC1D,aAAa,EAAE,aAAa,CAAC;IAAC,cAAc,EAAE,cAAc,CAAC;IAC7D,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;CAC3D;AAGD,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAO7D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,aAAa,CAqBvE;AAoBD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAcjE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAM7D"}
@@ -0,0 +1,67 @@
1
+ // Stub — full implementation in feature/tlci-foundation (will be resolved on merge)
2
+ import { createHash } from 'node:crypto';
3
+ import { classifySteps } from './step-classifier.js';
4
+ /**
5
+ * Compute a deterministic plan hash from step descriptions and type metadata.
6
+ * Excludes `context` (runtime state) — only classification-relevant fields are hashed.
7
+ * 32 hex chars (128 bits) to reduce collision risk.
8
+ */
9
+ export function computePlanHash(steps) {
10
+ return createHash('sha256')
11
+ .update(steps.map(s => `${s.description.trim().toLowerCase()}|${s.inputType ?? ''}|${s.outputType ?? ''}`).join('||'))
12
+ .digest('hex')
13
+ .slice(0, 32);
14
+ }
15
+ export function buildExecutionPlan(steps) {
16
+ const classified = classifySteps(steps);
17
+ const tierBreakdown = classified.reduce((acc, s) => { acc[s.tier]++; return acc; }, { code: 0, slm: 0, frontier: 0 });
18
+ const tlciEstimate = classified.reduce((sum, s) => sum + s.estimatedCostUSD, 0);
19
+ const allLLMEstimate = steps.length * 0.065;
20
+ const savingsUSD = allLLMEstimate - tlciEstimate;
21
+ const savingsPct = allLLMEstimate === 0 ? 0 : Math.round((savingsUSD / allLLMEstimate) * 100);
22
+ const planHash = computePlanHash(steps);
23
+ const planId = `plan_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
24
+ return {
25
+ planId,
26
+ planHash,
27
+ steps: classified,
28
+ tierBreakdown,
29
+ costComparison: { tlciEstimate, allLLMEstimate, savingsUSD, savingsPct },
30
+ createdAt: Date.now(),
31
+ approved: false,
32
+ };
33
+ }
34
+ const TIER_ICONS = {
35
+ code: '⚙️',
36
+ slm: '🔵',
37
+ frontier: '🟣',
38
+ };
39
+ const TIER_LABELS = {
40
+ code: 'CODE ',
41
+ slm: 'SLM ',
42
+ frontier: 'AI ',
43
+ };
44
+ /** Strip ANSI escape sequences from user-supplied text to prevent terminal injection. */
45
+ function sanitize(s) {
46
+ // eslint-disable-next-line no-control-regex
47
+ return s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '').replace(/[\x00-\x08\x0b-\x1f\x7f]/g, '');
48
+ }
49
+ export function formatPlanForApproval(plan) {
50
+ const { steps, tierBreakdown, costComparison } = plan;
51
+ const lines = [
52
+ `┌─ Execution Plan ──────────────────────────────────────`,
53
+ `│ Est. cost: $${costComparison.tlciEstimate.toFixed(4)} (vs $${costComparison.allLLMEstimate.toFixed(2)} all-LLM → ${costComparison.savingsPct}% savings)`,
54
+ `│ Tiers: ⚙️ ${tierBreakdown.code} code 🔵 ${tierBreakdown.slm} local 🟣 ${tierBreakdown.frontier} frontier`,
55
+ `├───────────────────────────────────────────────────────`,
56
+ ...steps.map((s, i) => `│ ${String(i + 1).padStart(2)}. ${TIER_ICONS[s.tier]} [${TIER_LABELS[s.tier]}] ${sanitize(s.description)}`),
57
+ `└───────────────────────────────────────────────────────`,
58
+ ` Proceed? (y/n/edit)`,
59
+ ];
60
+ return lines.join('\n');
61
+ }
62
+ export function formatPlanSummary(plan) {
63
+ const { tierBreakdown, costComparison } = plan;
64
+ return (`TLCI Plan: ${tierBreakdown.code} code / ${tierBreakdown.slm} SLM / ${tierBreakdown.frontier} frontier` +
65
+ ` | Est. $${costComparison.tlciEstimate.toFixed(4)} (${costComparison.savingsPct}% cheaper than all-LLM)`);
66
+ }
67
+ //# sourceMappingURL=execution-planner.js.map