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.
- package/README.md +171 -65
- package/dist/cli/daemon.js +1 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/index.js +27 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/secret-commands.d.ts +16 -0
- package/dist/cli/secret-commands.d.ts.map +1 -0
- package/dist/cli/secret-commands.js +87 -0
- package/dist/cli/secret-commands.js.map +1 -0
- package/dist/cli/skill-commands.d.ts.map +1 -1
- package/dist/cli/skill-commands.js +75 -0
- package/dist/cli/skill-commands.js.map +1 -1
- package/dist/cli/subagent-commands.d.ts +13 -0
- package/dist/cli/subagent-commands.d.ts.map +1 -0
- package/dist/cli/subagent-commands.js +80 -0
- package/dist/cli/subagent-commands.js.map +1 -0
- package/dist/config/defaults.d.ts +6 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +6 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/dashboard/cost-tracker.d.ts +40 -0
- package/dist/dashboard/cost-tracker.d.ts.map +1 -0
- package/dist/dashboard/cost-tracker.js +63 -0
- package/dist/dashboard/cost-tracker.js.map +1 -0
- package/dist/dashboard/frontend/dist/assets/{index-DSXaCp9r.js → index-Bi0V-1ti.js} +83 -83
- package/dist/dashboard/frontend/dist/assets/index-SQqtXVeO.css +1 -0
- package/dist/dashboard/frontend/dist/index.html +2 -2
- package/dist/dashboard/server.d.ts +5 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +17 -0
- package/dist/dashboard/server.js.map +1 -1
- package/dist/hooks/built-in/audit-log.d.ts +13 -0
- package/dist/hooks/built-in/audit-log.d.ts.map +1 -0
- package/dist/hooks/built-in/audit-log.js +48 -0
- package/dist/hooks/built-in/audit-log.js.map +1 -0
- package/dist/hooks/built-in/rate-limit.d.ts +18 -0
- package/dist/hooks/built-in/rate-limit.d.ts.map +1 -0
- package/dist/hooks/built-in/rate-limit.js +30 -0
- package/dist/hooks/built-in/rate-limit.js.map +1 -0
- package/dist/hooks/built-in/secret-redact.d.ts +7 -0
- package/dist/hooks/built-in/secret-redact.d.ts.map +1 -0
- package/dist/hooks/built-in/secret-redact.js +33 -0
- package/dist/hooks/built-in/secret-redact.js.map +1 -0
- package/dist/hooks/built-in/shell-safety.d.ts +7 -0
- package/dist/hooks/built-in/shell-safety.d.ts.map +1 -0
- package/dist/hooks/built-in/shell-safety.js +34 -0
- package/dist/hooks/built-in/shell-safety.js.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tool-hook-runner.d.ts +36 -0
- package/dist/hooks/tool-hook-runner.d.ts.map +1 -0
- package/dist/hooks/tool-hook-runner.js +49 -0
- package/dist/hooks/tool-hook-runner.js.map +1 -0
- package/dist/lib/error-normalizer.d.ts +53 -0
- package/dist/lib/error-normalizer.d.ts.map +1 -0
- package/dist/lib/error-normalizer.js +128 -0
- package/dist/lib/error-normalizer.js.map +1 -0
- package/dist/memory/context-compressor.d.ts +3 -1
- package/dist/memory/context-compressor.d.ts.map +1 -1
- package/dist/memory/context-compressor.js +18 -3
- package/dist/memory/context-compressor.js.map +1 -1
- package/dist/memory/plan-cache.d.ts +27 -0
- package/dist/memory/plan-cache.d.ts.map +1 -0
- package/dist/memory/plan-cache.js +91 -0
- package/dist/memory/plan-cache.js.map +1 -0
- package/dist/orchestrator/code-tool-runner.d.ts +41 -0
- package/dist/orchestrator/code-tool-runner.d.ts.map +1 -0
- package/dist/orchestrator/code-tool-runner.js +375 -0
- package/dist/orchestrator/code-tool-runner.js.map +1 -0
- package/dist/orchestrator/error-pattern-detector.d.ts +54 -0
- package/dist/orchestrator/error-pattern-detector.d.ts.map +1 -0
- package/dist/orchestrator/error-pattern-detector.js +87 -0
- package/dist/orchestrator/error-pattern-detector.js.map +1 -0
- package/dist/orchestrator/execution-planner.d.ts +33 -0
- package/dist/orchestrator/execution-planner.d.ts.map +1 -0
- package/dist/orchestrator/execution-planner.js +67 -0
- package/dist/orchestrator/execution-planner.js.map +1 -0
- package/dist/orchestrator/orchestrator.d.ts +77 -0
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +595 -29
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/orchestrator/retry-queue.d.ts +7 -1
- package/dist/orchestrator/retry-queue.d.ts.map +1 -1
- package/dist/orchestrator/retry-queue.js +10 -4
- package/dist/orchestrator/retry-queue.js.map +1 -1
- package/dist/orchestrator/step-classifier.d.ts +26 -0
- package/dist/orchestrator/step-classifier.d.ts.map +1 -0
- package/dist/orchestrator/step-classifier.js +77 -0
- package/dist/orchestrator/step-classifier.js.map +1 -0
- package/dist/orchestrator/tlci-dispatcher.d.ts +47 -0
- package/dist/orchestrator/tlci-dispatcher.d.ts.map +1 -0
- package/dist/orchestrator/tlci-dispatcher.js +116 -0
- package/dist/orchestrator/tlci-dispatcher.js.map +1 -0
- package/dist/routines/heartbeat.d.ts.map +1 -1
- package/dist/routines/heartbeat.js +3 -1
- package/dist/routines/heartbeat.js.map +1 -1
- package/dist/routines/routine-manager.d.ts.map +1 -1
- package/dist/routines/routine-manager.js +3 -1
- package/dist/routines/routine-manager.js.map +1 -1
- package/dist/security/intent-capsule.d.ts +19 -0
- package/dist/security/intent-capsule.d.ts.map +1 -1
- package/dist/security/intent-capsule.js +84 -1
- package/dist/security/intent-capsule.js.map +1 -1
- package/dist/security/policy-engine.d.ts +1 -0
- package/dist/security/policy-engine.d.ts.map +1 -1
- package/dist/security/policy-engine.js +22 -1
- package/dist/security/policy-engine.js.map +1 -1
- package/dist/services/negative-cache.d.ts +67 -0
- package/dist/services/negative-cache.d.ts.map +1 -0
- package/dist/services/negative-cache.js +164 -0
- package/dist/services/negative-cache.js.map +1 -0
- package/dist/skills/skill-auditor.d.ts +36 -0
- package/dist/skills/skill-auditor.d.ts.map +1 -0
- package/dist/skills/skill-auditor.js +89 -0
- package/dist/skills/skill-auditor.js.map +1 -0
- package/dist/skills/skill-installer.d.ts +41 -0
- package/dist/skills/skill-installer.d.ts.map +1 -0
- package/dist/skills/skill-installer.js +141 -0
- package/dist/skills/skill-installer.js.map +1 -0
- package/dist/skills/skill-scanner.d.ts +30 -0
- package/dist/skills/skill-scanner.d.ts.map +1 -0
- package/dist/skills/skill-scanner.js +249 -0
- package/dist/skills/skill-scanner.js.map +1 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/planning-tool.d.ts +95 -0
- package/dist/tools/planning-tool.d.ts.map +1 -0
- package/dist/tools/planning-tool.js +117 -0
- package/dist/tools/planning-tool.js.map +1 -0
- package/dist/tools/skill-tool.d.ts +94 -0
- package/dist/tools/skill-tool.d.ts.map +1 -0
- package/dist/tools/skill-tool.js +202 -0
- package/dist/tools/skill-tool.js.map +1 -0
- package/dist/tools/subagent-tool.d.ts +11 -0
- package/dist/tools/subagent-tool.d.ts.map +1 -0
- package/dist/tools/subagent-tool.js +87 -0
- package/dist/tools/subagent-tool.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/args.d.ts +5 -0
- package/dist/utils/args.d.ts.map +1 -0
- package/dist/utils/args.js +20 -0
- package/dist/utils/args.js.map +1 -0
- package/package.json +4 -1
- package/dist/dashboard/frontend/dist/assets/index-2FaDr6iS.js +0 -277
- package/dist/dashboard/frontend/dist/assets/index-B9-KXW14.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-BMxbyTer.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-BXUfB9iR.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-BcOGj1EF.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-BtiFO9YN.js +0 -261
- package/dist/dashboard/frontend/dist/assets/index-CQmpMTLW.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-Cfjy5acU.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-D41hcjgc.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-D83BawFd.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-DAODjoxu.css +0 -1
- package/dist/dashboard/frontend/dist/assets/index-DB-Eu5oV.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-W0VVEDu6.js +0 -253
- package/dist/dashboard/frontend/dist/assets/index-aK9PWl6w.js +0 -253
- package/dist/dashboard/frontend/vite.config.d.ts +0 -3
- package/dist/dashboard/frontend/vite.config.d.ts.map +0 -1
- package/dist/dashboard/frontend/vite.config.js +0 -11
- 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
|