nodebench-mcp 2.28.0 → 2.30.0

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 CHANGED
@@ -194,6 +194,92 @@ All analytics data is stored locally in `~/.nodebench/analytics.db` and never le
194
194
 
195
195
  ---
196
196
 
197
+ ## Headless Engine API (v2.30.0)
198
+
199
+ NodeBench now ships a **headless, API-first Agentic Engine** — plug it into any client workflow and sell results, not software seats.
200
+
201
+ ```bash
202
+ # Start MCP server with engine API on port 6276
203
+ npx nodebench-mcp --engine
204
+
205
+ # With auth token
206
+ npx nodebench-mcp --engine --engine-secret "your-token"
207
+ # or: ENGINE_SECRET=your-token npx nodebench-mcp --engine
208
+ ```
209
+
210
+ ### API Endpoints
211
+
212
+ | Method | Path | Purpose |
213
+ |--------|------|---------|
214
+ | GET | `/` | Engine status, tool count, uptime |
215
+ | GET | `/api/health` | Health check |
216
+ | GET | `/api/tools` | List all available tools |
217
+ | POST | `/api/tools/:name` | Execute a single tool |
218
+ | GET | `/api/workflows` | List all 32 workflow chains |
219
+ | POST | `/api/workflows/:name` | Execute a workflow (with SSE streaming) |
220
+ | POST | `/api/sessions` | Create an isolated session |
221
+ | GET | `/api/sessions/:id` | Session status + call history |
222
+ | GET | `/api/sessions/:id/trace` | Full disclosure trace |
223
+ | GET | `/api/sessions/:id/report` | Conformance report |
224
+ | DELETE | `/api/sessions/:id` | End session |
225
+ | GET | `/api/presets` | List presets with tool counts |
226
+
227
+ ### Quick Examples
228
+
229
+ ```bash
230
+ # Execute a single tool
231
+ curl -X POST http://127.0.0.1:6276/api/tools/discover_tools \
232
+ -H "Content-Type: application/json" \
233
+ -d '{"args": {"query": "security audit"}, "preset": "full"}'
234
+
235
+ # Run a workflow with streaming
236
+ curl -N -X POST http://127.0.0.1:6276/api/workflows/fix_bug \
237
+ -H "Content-Type: application/json" \
238
+ -d '{"preset": "web_dev", "streaming": true}'
239
+
240
+ # Create a session, execute tools, get conformance report
241
+ SESSION=$(curl -s -X POST http://127.0.0.1:6276/api/sessions \
242
+ -H "Content-Type: application/json" \
243
+ -d '{"preset": "web_dev"}' | jq -r .sessionId)
244
+
245
+ curl -X POST "http://127.0.0.1:6276/api/tools/run_recon" \
246
+ -H "Content-Type: application/json" \
247
+ -d "{\"args\": {\"focusArea\": \"web\"}, \"sessionId\": \"$SESSION\"}"
248
+
249
+ curl "http://127.0.0.1:6276/api/sessions/$SESSION/report"
250
+ ```
251
+
252
+ ### Conformance Reports
253
+
254
+ Every workflow execution produces a conformance report scoring:
255
+ - **Step completeness** — did all required tools execute?
256
+ - **Quality gate** — did the quality gate pass?
257
+ - **Test layers** — were unit/integration/e2e results logged?
258
+ - **Flywheel** — was the methodology completed?
259
+ - **Learnings** — were findings banked for next time?
260
+
261
+ Grades: A (90+) / B (75+) / C (60+) / D (40+) / F (<40). Sell these reports as "Zero-bug deployment certificates" or "Automated WebMCP Conformance Reports."
262
+
263
+ ### SSE Streaming
264
+
265
+ Workflow execution supports Server-Sent Events for real-time progress:
266
+
267
+ ```
268
+ event: start
269
+ data: {"workflow":"fix_bug","totalSteps":7,"sessionId":"eng_..."}
270
+
271
+ event: step
272
+ data: {"stepIndex":0,"tool":"search_all_knowledge","status":"running"}
273
+
274
+ event: step
275
+ data: {"stepIndex":0,"tool":"search_all_knowledge","status":"complete","durationMs":42}
276
+
277
+ event: complete
278
+ data: {"totalSteps":7,"totalDurationMs":340,"conformanceScore":88,"grade":"B"}
279
+ ```
280
+
281
+ ---
282
+
197
283
  ## What You Get — The AI Flywheel
198
284
 
199
285
  The default setup (no `--preset` flag) gives you **50 tools** that implement the complete [AI Flywheel](https://github.com/HomenShum/nodebench-ai/blob/main/AI_FLYWHEEL.md) methodology — two interlocking loops that compound quality over time:
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Engine Conformance Scoring
3
+ *
4
+ * Computes a deterministic conformance score from a session's tool call history.
5
+ * Used to generate "Conformance Reports" — the sellable output of the engine.
6
+ */
7
+ import type { EngineSession } from "./session.js";
8
+ export interface ConformanceBreakdown {
9
+ stepsCompleted: boolean;
10
+ qualityGatePassed: boolean;
11
+ testLayersLogged: boolean;
12
+ flywheelCompleted: boolean;
13
+ learningsRecorded: boolean;
14
+ reconPerformed: boolean;
15
+ verificationCycleStarted: boolean;
16
+ noErrors: boolean;
17
+ }
18
+ export interface ConformanceReport {
19
+ sessionId: string;
20
+ preset: string;
21
+ score: number;
22
+ grade: "A" | "B" | "C" | "D" | "F";
23
+ breakdown: ConformanceBreakdown;
24
+ summary: string;
25
+ totalSteps: number;
26
+ successfulSteps: number;
27
+ failedSteps: number;
28
+ totalDurationMs: number;
29
+ generatedAt: number;
30
+ }
31
+ export declare function computeConformance(session: EngineSession, expectedSteps?: number): ConformanceReport;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Engine Conformance Scoring
3
+ *
4
+ * Computes a deterministic conformance score from a session's tool call history.
5
+ * Used to generate "Conformance Reports" — the sellable output of the engine.
6
+ */
7
+ const FLYWHEEL_TOOLS = [
8
+ "start_flywheel",
9
+ "log_flywheel_step",
10
+ "run_quality_gate",
11
+ ];
12
+ const TEST_TOOLS = [
13
+ "log_test_result",
14
+ ];
15
+ const LEARNING_TOOLS = [
16
+ "log_learning",
17
+ "save_session_note",
18
+ "search_all_knowledge",
19
+ ];
20
+ const RECON_TOOLS = [
21
+ "run_recon",
22
+ "log_recon_finding",
23
+ ];
24
+ const VERIFICATION_TOOLS = [
25
+ "start_verification_cycle",
26
+ "log_verification_step",
27
+ ];
28
+ const QUALITY_GATE_TOOLS = [
29
+ "run_quality_gate",
30
+ ];
31
+ function hasToolCalled(history, toolNames) {
32
+ return history.some((r) => toolNames.includes(r.toolName) && r.status === "success");
33
+ }
34
+ function countByStatus(history, status) {
35
+ return history.filter((r) => r.status === status).length;
36
+ }
37
+ export function computeConformance(session, expectedSteps) {
38
+ const history = session.callHistory;
39
+ const successful = countByStatus(history, "success");
40
+ const failed = countByStatus(history, "error");
41
+ const total = history.length;
42
+ const totalDurationMs = history.reduce((sum, r) => sum + r.durationMs, 0);
43
+ const breakdown = {
44
+ stepsCompleted: expectedSteps ? successful >= expectedSteps : successful > 0,
45
+ qualityGatePassed: hasToolCalled(history, QUALITY_GATE_TOOLS),
46
+ testLayersLogged: hasToolCalled(history, TEST_TOOLS),
47
+ flywheelCompleted: hasToolCalled(history, FLYWHEEL_TOOLS),
48
+ learningsRecorded: hasToolCalled(history, LEARNING_TOOLS),
49
+ reconPerformed: hasToolCalled(history, RECON_TOOLS),
50
+ verificationCycleStarted: hasToolCalled(history, VERIFICATION_TOOLS),
51
+ noErrors: failed === 0,
52
+ };
53
+ // Score: each check is worth 12.5 points (8 checks × 12.5 = 100)
54
+ const checks = Object.values(breakdown);
55
+ const passed = checks.filter(Boolean).length;
56
+ const score = Math.round((passed / checks.length) * 100);
57
+ const grade = score >= 90 ? "A" :
58
+ score >= 75 ? "B" :
59
+ score >= 60 ? "C" :
60
+ score >= 40 ? "D" : "F";
61
+ const failedChecks = Object.entries(breakdown)
62
+ .filter(([, v]) => !v)
63
+ .map(([k]) => k.replace(/([A-Z])/g, " $1").toLowerCase().trim());
64
+ const summary = score === 100
65
+ ? `All conformance checks passed. ${successful}/${total} tool calls succeeded in ${totalDurationMs}ms.`
66
+ : `Score ${score}/100 (${grade}). Missing: ${failedChecks.join(", ")}. ${successful}/${total} calls succeeded.`;
67
+ return {
68
+ sessionId: session.id,
69
+ preset: session.preset,
70
+ score,
71
+ grade,
72
+ breakdown,
73
+ summary,
74
+ totalSteps: total,
75
+ successfulSteps: successful,
76
+ failedSteps: failed,
77
+ totalDurationMs,
78
+ generatedAt: Date.now(),
79
+ };
80
+ }
81
+ //# sourceMappingURL=conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.js","sourceRoot":"","sources":["../../src/engine/conformance.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6BH,MAAM,cAAc,GAAG;IACrB,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;CACnB,CAAC;AAEF,MAAM,UAAU,GAAG;IACjB,iBAAiB;CAClB,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,cAAc;IACd,mBAAmB;IACnB,sBAAsB;CACvB,CAAC;AAEF,MAAM,WAAW,GAAG;IAClB,WAAW;IACX,mBAAmB;CACpB,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,0BAA0B;IAC1B,uBAAuB;CACxB,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,kBAAkB;CACnB,CAAC;AAEF,SAAS,aAAa,CAAC,OAAyB,EAAE,SAAmB;IACnE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACvF,CAAC;AAED,SAAS,aAAa,CAAC,OAAyB,EAAE,MAA2B;IAC3E,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,aAAsB;IAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IACpC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7B,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAE1E,MAAM,SAAS,GAAyB;QACtC,cAAc,EAAE,aAAa,CAAC,CAAC,CAAC,UAAU,IAAI,aAAa,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC;QAC5E,iBAAiB,EAAE,aAAa,CAAC,OAAO,EAAE,kBAAkB,CAAC;QAC7D,gBAAgB,EAAE,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC;QACpD,iBAAiB,EAAE,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC;QACzD,iBAAiB,EAAE,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC;QACzD,cAAc,EAAE,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC;QACnD,wBAAwB,EAAE,aAAa,CAAC,OAAO,EAAE,kBAAkB,CAAC;QACpE,QAAQ,EAAE,MAAM,KAAK,CAAC;KACvB,CAAC;IAEF,iEAAiE;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;IAEzD,MAAM,KAAK,GACT,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnB,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACnB,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACnB,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE1B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;SACrB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,KAAK,KAAK,GAAG;QAC3B,CAAC,CAAC,kCAAkC,UAAU,IAAI,KAAK,4BAA4B,eAAe,KAAK;QACvG,CAAC,CAAC,SAAS,KAAK,SAAS,KAAK,eAAe,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,UAAU,IAAI,KAAK,mBAAmB,CAAC;IAElH,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK;QACL,KAAK;QACL,SAAS;QACT,OAAO;QACP,UAAU,EAAE,KAAK;QACjB,eAAe,EAAE,UAAU;QAC3B,WAAW,EAAE,MAAM;QACnB,eAAe;QACf,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;KACxB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * NodeBench Engine — Headless API-First Agentic Engine
3
+ *
4
+ * HTTP server exposing MCP tool handlers as a REST API.
5
+ * Supports: tool execution, workflow chains (with SSE streaming),
6
+ * session management, preset gating, and conformance reports.
7
+ *
8
+ * Port: 6276 (follows 6274 dashboard, 6275 brief convention)
9
+ */
10
+ import type { McpTool } from "../types.js";
11
+ import type { WorkflowChain } from "../tools/toolRegistry.js";
12
+ export interface EngineServerConfig {
13
+ toolMap: Map<string, McpTool>;
14
+ allTools: McpTool[];
15
+ workflowChains: Record<string, WorkflowChain>;
16
+ presets: Record<string, string[]>;
17
+ toolsetMap: Record<string, McpTool[]>;
18
+ toolToToolset: Map<string, string>;
19
+ secret?: string;
20
+ }
21
+ export declare function startEngineServer(config: EngineServerConfig, preferredPort?: number): Promise<number>;
22
+ export declare function stopEngineServer(): void;
23
+ export declare function getEngineUrl(): string | null;
@@ -0,0 +1,404 @@
1
+ /**
2
+ * NodeBench Engine — Headless API-First Agentic Engine
3
+ *
4
+ * HTTP server exposing MCP tool handlers as a REST API.
5
+ * Supports: tool execution, workflow chains (with SSE streaming),
6
+ * session management, preset gating, and conformance reports.
7
+ *
8
+ * Port: 6276 (follows 6274 dashboard, 6275 brief convention)
9
+ */
10
+ import { createServer } from "node:http";
11
+ import { createSession, getSession, endSession, listSessions, executeToolInSession, getSessionCount, } from "./session.js";
12
+ import { computeConformance } from "./conformance.js";
13
+ // ── State ─────────────────────────────────────────────────────────────
14
+ let _server = null;
15
+ let _port = 0;
16
+ let _config = null;
17
+ const _startedAt = Date.now();
18
+ // ── Server Lifecycle ──────────────────────────────────────────────────
19
+ export function startEngineServer(config, preferredPort = 6276) {
20
+ return new Promise((resolve, reject) => {
21
+ if (_server) {
22
+ resolve(_port);
23
+ return;
24
+ }
25
+ _config = config;
26
+ _server = createServer((req, res) => handleRequest(req, res));
27
+ let attempts = 0;
28
+ const maxRetries = 5;
29
+ function tryListen(port) {
30
+ _server.once("error", (err) => {
31
+ if (err.code === "EADDRINUSE" && attempts < maxRetries) {
32
+ attempts++;
33
+ tryListen(port + 1);
34
+ }
35
+ else {
36
+ reject(err);
37
+ }
38
+ });
39
+ _server.listen(port, "127.0.0.1", () => {
40
+ _port = port;
41
+ resolve(port);
42
+ });
43
+ }
44
+ tryListen(preferredPort);
45
+ });
46
+ }
47
+ export function stopEngineServer() {
48
+ if (_server) {
49
+ _server.close();
50
+ _server = null;
51
+ _port = 0;
52
+ }
53
+ }
54
+ export function getEngineUrl() {
55
+ return _port ? `http://127.0.0.1:${_port}` : null;
56
+ }
57
+ // ── Helpers ───────────────────────────────────────────────────────────
58
+ function json(res, data, status = 200) {
59
+ res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
60
+ res.end(JSON.stringify(data));
61
+ }
62
+ function error(res, message, status = 400) {
63
+ json(res, { ok: false, error: message }, status);
64
+ }
65
+ function parseBody(req) {
66
+ return new Promise((resolve, reject) => {
67
+ let body = "";
68
+ req.on("data", (chunk) => { body += chunk; });
69
+ req.on("end", () => {
70
+ if (!body) {
71
+ resolve({});
72
+ return;
73
+ }
74
+ try {
75
+ resolve(JSON.parse(body));
76
+ }
77
+ catch {
78
+ reject(new Error("Invalid JSON body"));
79
+ }
80
+ });
81
+ req.on("error", reject);
82
+ });
83
+ }
84
+ function checkAuth(req, res) {
85
+ if (!_config?.secret)
86
+ return true;
87
+ const auth = req.headers.authorization;
88
+ if (auth === `Bearer ${_config.secret}`)
89
+ return true;
90
+ error(res, "Unauthorized", 401);
91
+ return false;
92
+ }
93
+ function getToolMeta(name) {
94
+ const toolset = _config?.toolToToolset.get(name) ?? "unknown";
95
+ return { category: toolset };
96
+ }
97
+ // ── Request Router ────────────────────────────────────────────────────
98
+ async function handleRequest(req, res) {
99
+ const url = new URL(req.url || "/", `http://127.0.0.1:${_port}`);
100
+ const path = url.pathname;
101
+ const method = req.method ?? "GET";
102
+ // CORS
103
+ res.setHeader("Access-Control-Allow-Origin", "*");
104
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
105
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
106
+ if (method === "OPTIONS") {
107
+ res.writeHead(204);
108
+ res.end();
109
+ return;
110
+ }
111
+ if (!checkAuth(req, res))
112
+ return;
113
+ try {
114
+ // ── Root ──────────────────────────────────────
115
+ if (path === "/" && method === "GET") {
116
+ return json(res, {
117
+ engine: "nodebench-engine",
118
+ version: "1.0.0",
119
+ toolCount: _config?.allTools.length ?? 0,
120
+ uptimeMs: Date.now() - _startedAt,
121
+ activeSessions: getSessionCount(),
122
+ endpoints: [
123
+ "GET /api/health",
124
+ "GET /api/tools",
125
+ "POST /api/tools/:toolName",
126
+ "GET /api/workflows",
127
+ "POST /api/workflows/:chainName",
128
+ "POST /api/sessions",
129
+ "GET /api/sessions",
130
+ "GET /api/sessions/:id",
131
+ "GET /api/sessions/:id/trace",
132
+ "GET /api/sessions/:id/report",
133
+ "DELETE /api/sessions/:id",
134
+ "GET /api/presets",
135
+ ],
136
+ });
137
+ }
138
+ // ── Health ────────────────────────────────────
139
+ if (path === "/api/health" && method === "GET") {
140
+ return json(res, {
141
+ ok: true,
142
+ uptimeMs: Date.now() - _startedAt,
143
+ toolCount: _config?.allTools.length ?? 0,
144
+ activeSessions: getSessionCount(),
145
+ memoryMb: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
146
+ });
147
+ }
148
+ // ── List Tools ───────────────────────────────
149
+ if (path === "/api/tools" && method === "GET") {
150
+ const tools = (_config?.allTools ?? []).map((t) => ({
151
+ name: t.name,
152
+ description: t.description.slice(0, 200),
153
+ inputSchema: t.inputSchema,
154
+ ...getToolMeta(t.name),
155
+ }));
156
+ return json(res, { ok: true, count: tools.length, tools });
157
+ }
158
+ // ── Execute Tool ─────────────────────────────
159
+ const toolExecMatch = path.match(/^\/api\/tools\/([^/]+)$/);
160
+ if (toolExecMatch && method === "POST") {
161
+ const toolName = decodeURIComponent(toolExecMatch[1]);
162
+ const body = await parseBody(req);
163
+ const args = body.args ?? {};
164
+ const presetName = body.preset ?? "full";
165
+ // Use session if provided, else create ephemeral
166
+ let session;
167
+ if (body.sessionId) {
168
+ const existing = getSession(body.sessionId);
169
+ if (!existing)
170
+ return error(res, `Session "${body.sessionId}" not found`, 404);
171
+ session = existing;
172
+ }
173
+ else {
174
+ session = createSession(presetName, _config.presets, _config.toolsetMap, _config.toolMap);
175
+ }
176
+ const record = await executeToolInSession(session, toolName, args);
177
+ // Clean up ephemeral sessions
178
+ if (!body.sessionId)
179
+ endSession(session.id);
180
+ return json(res, {
181
+ ok: record.status === "success",
182
+ toolName,
183
+ result: record.result,
184
+ meta: {
185
+ durationMs: record.durationMs,
186
+ sessionId: session.id,
187
+ ...getToolMeta(toolName),
188
+ },
189
+ });
190
+ }
191
+ // ── List Workflows ───────────────────────────
192
+ if (path === "/api/workflows" && method === "GET") {
193
+ const chains = _config?.workflowChains ?? {};
194
+ const workflows = Object.entries(chains).map(([key, chain]) => ({
195
+ key,
196
+ name: chain.name,
197
+ description: chain.description,
198
+ stepCount: chain.steps.length,
199
+ steps: chain.steps.map((s, i) => ({ index: i, tool: s.tool, action: s.action })),
200
+ }));
201
+ return json(res, { ok: true, count: workflows.length, workflows });
202
+ }
203
+ // ── Execute Workflow ─────────────────────────
204
+ const workflowExecMatch = path.match(/^\/api\/workflows\/([^/]+)$/);
205
+ if (workflowExecMatch && method === "POST") {
206
+ const chainName = decodeURIComponent(workflowExecMatch[1]);
207
+ const chain = _config?.workflowChains[chainName];
208
+ if (!chain)
209
+ return error(res, `Workflow "${chainName}" not found`, 404);
210
+ const body = await parseBody(req);
211
+ const stepArgs = body.stepArgs ?? {};
212
+ const presetName = body.preset ?? "full";
213
+ const streaming = body.streaming === true;
214
+ // Create or reuse session
215
+ let session;
216
+ if (body.sessionId) {
217
+ const existing = getSession(body.sessionId);
218
+ if (!existing)
219
+ return error(res, `Session "${body.sessionId}" not found`, 404);
220
+ session = existing;
221
+ }
222
+ else {
223
+ session = createSession(presetName, _config.presets, _config.toolsetMap, _config.toolMap);
224
+ }
225
+ if (streaming) {
226
+ return executeWorkflowStreaming(res, session, chain, chainName, stepArgs, !body.sessionId);
227
+ }
228
+ // Non-streaming: execute all steps, return batch result
229
+ const results = [];
230
+ for (let i = 0; i < chain.steps.length; i++) {
231
+ const step = chain.steps[i];
232
+ const args = stepArgs[step.tool] ?? {};
233
+ const record = await executeToolInSession(session, step.tool, args);
234
+ results.push({
235
+ stepIndex: i,
236
+ tool: step.tool,
237
+ action: step.action,
238
+ status: record.status,
239
+ durationMs: record.durationMs,
240
+ result: record.result,
241
+ });
242
+ }
243
+ const report = computeConformance(session, chain.steps.length);
244
+ if (!body.sessionId)
245
+ endSession(session.id);
246
+ return json(res, {
247
+ ok: true,
248
+ workflow: chainName,
249
+ totalSteps: chain.steps.length,
250
+ results,
251
+ conformance: report,
252
+ });
253
+ }
254
+ // ── Create Session ───────────────────────────
255
+ if (path === "/api/sessions" && method === "POST") {
256
+ const body = await parseBody(req);
257
+ const presetName = body.preset ?? "default";
258
+ const session = createSession(presetName, _config.presets, _config.toolsetMap, _config.toolMap);
259
+ return json(res, {
260
+ ok: true,
261
+ sessionId: session.id,
262
+ preset: session.preset,
263
+ toolCount: session.toolMap.size,
264
+ createdAt: session.createdAt,
265
+ }, 201);
266
+ }
267
+ // ── List Sessions ────────────────────────────
268
+ if (path === "/api/sessions" && method === "GET") {
269
+ return json(res, { ok: true, sessions: listSessions() });
270
+ }
271
+ // ── Session Detail ───────────────────────────
272
+ const sessionDetailMatch = path.match(/^\/api\/sessions\/([^/]+)$/);
273
+ if (sessionDetailMatch && method === "GET") {
274
+ const session = getSession(decodeURIComponent(sessionDetailMatch[1]));
275
+ if (!session)
276
+ return error(res, "Session not found", 404);
277
+ return json(res, {
278
+ ok: true,
279
+ id: session.id,
280
+ preset: session.preset,
281
+ status: session.status,
282
+ toolCount: session.toolMap.size,
283
+ callCount: session.callHistory.length,
284
+ createdAt: session.createdAt,
285
+ lastActivity: session.lastActivity,
286
+ callHistory: session.callHistory.map((r) => ({
287
+ id: r.id,
288
+ toolName: r.toolName,
289
+ status: r.status,
290
+ durationMs: r.durationMs,
291
+ timestamp: r.timestamp,
292
+ })),
293
+ });
294
+ }
295
+ // ── Session Trace ────────────────────────────
296
+ const sessionTraceMatch = path.match(/^\/api\/sessions\/([^/]+)\/trace$/);
297
+ if (sessionTraceMatch && method === "GET") {
298
+ const session = getSession(decodeURIComponent(sessionTraceMatch[1]));
299
+ if (!session)
300
+ return error(res, "Session not found", 404);
301
+ return json(res, {
302
+ ok: true,
303
+ sessionId: session.id,
304
+ events: session.disclosureEvents,
305
+ callHistory: session.callHistory,
306
+ });
307
+ }
308
+ // ── Session Report ───────────────────────────
309
+ const sessionReportMatch = path.match(/^\/api\/sessions\/([^/]+)\/report$/);
310
+ if (sessionReportMatch && method === "GET") {
311
+ const session = getSession(decodeURIComponent(sessionReportMatch[1]));
312
+ if (!session)
313
+ return error(res, "Session not found", 404);
314
+ const report = computeConformance(session);
315
+ return json(res, { ok: true, report });
316
+ }
317
+ // ── Delete Session ───────────────────────────
318
+ if (sessionDetailMatch && method === "DELETE") {
319
+ const deleted = endSession(decodeURIComponent(sessionDetailMatch[1]));
320
+ if (!deleted)
321
+ return error(res, "Session not found", 404);
322
+ return json(res, { ok: true, deleted: true });
323
+ }
324
+ // ── List Presets ─────────────────────────────
325
+ if (path === "/api/presets" && method === "GET") {
326
+ const presets = _config?.presets ?? {};
327
+ const toolsetMap = _config?.toolsetMap ?? {};
328
+ const list = Object.entries(presets).map(([name, domains]) => {
329
+ let toolCount = 0;
330
+ for (const d of domains) {
331
+ toolCount += toolsetMap[d]?.length ?? 0;
332
+ }
333
+ return { name, domains, toolCount };
334
+ });
335
+ return json(res, { ok: true, presets: list });
336
+ }
337
+ // ── 404 ──────────────────────────────────────
338
+ error(res, "Not found", 404);
339
+ }
340
+ catch (err) {
341
+ error(res, err.message ?? "Internal server error", 500);
342
+ }
343
+ }
344
+ // ── SSE Workflow Execution ────────────────────────────────────────────
345
+ async function executeWorkflowStreaming(res, session, chain, chainName, stepArgs, ephemeral) {
346
+ res.writeHead(200, {
347
+ "Content-Type": "text/event-stream",
348
+ "Cache-Control": "no-cache",
349
+ Connection: "keep-alive",
350
+ "Access-Control-Allow-Origin": "*",
351
+ });
352
+ function send(event, data) {
353
+ res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
354
+ }
355
+ send("start", { workflow: chainName, totalSteps: chain.steps.length, sessionId: session.id });
356
+ for (let i = 0; i < chain.steps.length; i++) {
357
+ const step = chain.steps[i];
358
+ const args = stepArgs[step.tool] ?? {};
359
+ // Emit running event
360
+ const runningEvent = {
361
+ kind: "tool.invoke",
362
+ toolName: step.tool,
363
+ stepIndex: i,
364
+ status: "running",
365
+ timestamp: Date.now(),
366
+ };
367
+ session.disclosureEvents.push(runningEvent);
368
+ send("step", { stepIndex: i, tool: step.tool, action: step.action, status: "running" });
369
+ // Execute
370
+ const record = await executeToolInSession(session, step.tool, args);
371
+ // Emit complete event
372
+ const completeEvent = {
373
+ kind: "tool.invoke",
374
+ toolName: step.tool,
375
+ stepIndex: i,
376
+ status: record.status === "success" ? "complete" : "error",
377
+ data: record.result,
378
+ timestamp: Date.now(),
379
+ };
380
+ session.disclosureEvents.push(completeEvent);
381
+ send("step", {
382
+ stepIndex: i,
383
+ tool: step.tool,
384
+ action: step.action,
385
+ status: record.status === "success" ? "complete" : "error",
386
+ durationMs: record.durationMs,
387
+ result: record.result,
388
+ });
389
+ }
390
+ // Final conformance
391
+ const report = computeConformance(session, chain.steps.length);
392
+ send("complete", {
393
+ workflow: chainName,
394
+ totalSteps: chain.steps.length,
395
+ totalDurationMs: report.totalDurationMs,
396
+ conformanceScore: report.score,
397
+ grade: report.grade,
398
+ sessionId: session.id,
399
+ });
400
+ if (ephemeral)
401
+ endSession(session.id);
402
+ res.end();
403
+ }
404
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/engine/server.ts"],"names":[],"mappings":"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"}