twining-mcp 1.3.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/LICENSE +21 -0
- package/README.md +165 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/api-routes.d.ts +21 -0
- package/dist/dashboard/api-routes.d.ts.map +1 -0
- package/dist/dashboard/api-routes.js +516 -0
- package/dist/dashboard/api-routes.js.map +1 -0
- package/dist/dashboard/dashboard-config.d.ts +19 -0
- package/dist/dashboard/dashboard-config.d.ts.map +1 -0
- package/dist/dashboard/dashboard-config.js +17 -0
- package/dist/dashboard/dashboard-config.js.map +1 -0
- package/dist/dashboard/http-server.d.ts +29 -0
- package/dist/dashboard/http-server.d.ts.map +1 -0
- package/dist/dashboard/http-server.js +177 -0
- package/dist/dashboard/http-server.js.map +1 -0
- package/dist/dashboard/public/app.js +2396 -0
- package/dist/dashboard/public/assets/favicon.svg +44 -0
- package/dist/dashboard/public/assets/icon-512.png +0 -0
- package/dist/dashboard/public/assets/logo.svg +45 -0
- package/dist/dashboard/public/favicon.ico +0 -0
- package/dist/dashboard/public/index.html +338 -0
- package/dist/dashboard/public/style.css +858 -0
- package/dist/dashboard/public/vendor/cytoscape.min.js +1 -0
- package/dist/dashboard/public/vendor/vis-timeline-graph2d.min.css +2 -0
- package/dist/dashboard/public/vendor/vis-timeline-graph2d.min.js +48 -0
- package/dist/embeddings/embedder.d.ts +24 -0
- package/dist/embeddings/embedder.d.ts.map +1 -0
- package/dist/embeddings/embedder.js +109 -0
- package/dist/embeddings/embedder.js.map +1 -0
- package/dist/embeddings/index-manager.d.ts +27 -0
- package/dist/embeddings/index-manager.d.ts.map +1 -0
- package/dist/embeddings/index-manager.js +115 -0
- package/dist/embeddings/index-manager.js.map +1 -0
- package/dist/embeddings/search.d.ts +52 -0
- package/dist/embeddings/search.d.ts.map +1 -0
- package/dist/embeddings/search.js +170 -0
- package/dist/embeddings/search.js.map +1 -0
- package/dist/engine/archiver.d.ts +28 -0
- package/dist/engine/archiver.d.ts.map +1 -0
- package/dist/engine/archiver.js +153 -0
- package/dist/engine/archiver.js.map +1 -0
- package/dist/engine/blackboard.d.ts +55 -0
- package/dist/engine/blackboard.d.ts.map +1 -0
- package/dist/engine/blackboard.js +90 -0
- package/dist/engine/blackboard.js.map +1 -0
- package/dist/engine/context-assembler.d.ts +50 -0
- package/dist/engine/context-assembler.d.ts.map +1 -0
- package/dist/engine/context-assembler.js +483 -0
- package/dist/engine/context-assembler.js.map +1 -0
- package/dist/engine/coordination.d.ts +53 -0
- package/dist/engine/coordination.d.ts.map +1 -0
- package/dist/engine/coordination.js +239 -0
- package/dist/engine/coordination.js.map +1 -0
- package/dist/engine/decisions.d.ts +147 -0
- package/dist/engine/decisions.d.ts.map +1 -0
- package/dist/engine/decisions.js +540 -0
- package/dist/engine/decisions.js.map +1 -0
- package/dist/engine/exporter.d.ts +30 -0
- package/dist/engine/exporter.d.ts.map +1 -0
- package/dist/engine/exporter.js +192 -0
- package/dist/engine/exporter.js.map +1 -0
- package/dist/engine/graph.d.ts +55 -0
- package/dist/engine/graph.d.ts.map +1 -0
- package/dist/engine/graph.js +119 -0
- package/dist/engine/graph.js.map +1 -0
- package/dist/engine/planning-bridge.d.ts +53 -0
- package/dist/engine/planning-bridge.d.ts.map +1 -0
- package/dist/engine/planning-bridge.js +170 -0
- package/dist/engine/planning-bridge.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +82 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/agent-store.d.ts +36 -0
- package/dist/storage/agent-store.d.ts.map +1 -0
- package/dist/storage/agent-store.js +119 -0
- package/dist/storage/agent-store.js.map +1 -0
- package/dist/storage/blackboard-store.d.ts +21 -0
- package/dist/storage/blackboard-store.d.ts.map +1 -0
- package/dist/storage/blackboard-store.js +56 -0
- package/dist/storage/blackboard-store.js.map +1 -0
- package/dist/storage/decision-store.d.ts +23 -0
- package/dist/storage/decision-store.d.ts.map +1 -0
- package/dist/storage/decision-store.js +179 -0
- package/dist/storage/decision-store.js.map +1 -0
- package/dist/storage/file-store.d.ts +20 -0
- package/dist/storage/file-store.d.ts.map +1 -0
- package/dist/storage/file-store.js +108 -0
- package/dist/storage/file-store.js.map +1 -0
- package/dist/storage/graph-store.d.ts +39 -0
- package/dist/storage/graph-store.d.ts.map +1 -0
- package/dist/storage/graph-store.js +143 -0
- package/dist/storage/graph-store.js.map +1 -0
- package/dist/storage/handoff-store.d.ts +44 -0
- package/dist/storage/handoff-store.d.ts.map +1 -0
- package/dist/storage/handoff-store.js +136 -0
- package/dist/storage/handoff-store.js.map +1 -0
- package/dist/storage/init.d.ts +10 -0
- package/dist/storage/init.d.ts.map +1 -0
- package/dist/storage/init.js +48 -0
- package/dist/storage/init.js.map +1 -0
- package/dist/tools/blackboard-tools.d.ts +4 -0
- package/dist/tools/blackboard-tools.d.ts.map +1 -0
- package/dist/tools/blackboard-tools.js +131 -0
- package/dist/tools/blackboard-tools.js.map +1 -0
- package/dist/tools/context-tools.d.ts +4 -0
- package/dist/tools/context-tools.d.ts.map +1 -0
- package/dist/tools/context-tools.js +76 -0
- package/dist/tools/context-tools.js.map +1 -0
- package/dist/tools/coordination-tools.d.ts +6 -0
- package/dist/tools/coordination-tools.d.ts.map +1 -0
- package/dist/tools/coordination-tools.js +220 -0
- package/dist/tools/coordination-tools.js.map +1 -0
- package/dist/tools/decision-tools.d.ts +4 -0
- package/dist/tools/decision-tools.d.ts.map +1 -0
- package/dist/tools/decision-tools.js +265 -0
- package/dist/tools/decision-tools.js.map +1 -0
- package/dist/tools/export-tools.d.ts +4 -0
- package/dist/tools/export-tools.d.ts.map +1 -0
- package/dist/tools/export-tools.js +30 -0
- package/dist/tools/export-tools.js.map +1 -0
- package/dist/tools/graph-tools.d.ts +4 -0
- package/dist/tools/graph-tools.d.ts.map +1 -0
- package/dist/tools/graph-tools.js +127 -0
- package/dist/tools/graph-tools.js.map +1 -0
- package/dist/tools/lifecycle-tools.d.ts +9 -0
- package/dist/tools/lifecycle-tools.d.ts.map +1 -0
- package/dist/tools/lifecycle-tools.js +142 -0
- package/dist/tools/lifecycle-tools.js.map +1 -0
- package/dist/utils/errors.d.ts +24 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +31 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/ids.d.ts +2 -0
- package/dist/utils/ids.d.ts.map +1 -0
- package/dist/utils/ids.js +10 -0
- package/dist/utils/ids.js.map +1 -0
- package/dist/utils/liveness.d.ts +14 -0
- package/dist/utils/liveness.d.ts.map +1 -0
- package/dist/utils/liveness.js +19 -0
- package/dist/utils/liveness.js.map +1 -0
- package/dist/utils/tags.d.ts +9 -0
- package/dist/utils/tags.d.ts.map +1 -0
- package/dist/utils/tags.js +12 -0
- package/dist/utils/tags.js.map +1 -0
- package/dist/utils/tokens.d.ts +6 -0
- package/dist/utils/tokens.d.ts.map +1 -0
- package/dist/utils/tokens.js +8 -0
- package/dist/utils/tokens.js.map +1 -0
- package/dist/utils/types.d.ts +308 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +18 -0
- package/dist/utils/types.js.map +1 -0
- package/package.json +60 -0
- package/src/dashboard/public/app.js +2396 -0
- package/src/dashboard/public/assets/favicon.svg +44 -0
- package/src/dashboard/public/assets/icon-512.png +0 -0
- package/src/dashboard/public/assets/logo.svg +45 -0
- package/src/dashboard/public/favicon.ico +0 -0
- package/src/dashboard/public/index.html +338 -0
- package/src/dashboard/public/style.css +858 -0
- package/src/dashboard/public/vendor/cytoscape.min.js +1 -0
- package/src/dashboard/public/vendor/vis-timeline-graph2d.min.css +2 -0
- package/src/dashboard/public/vendor/vis-timeline-graph2d.min.js +48 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard API route handlers.
|
|
3
|
+
*
|
|
4
|
+
* Factory function creates a request handler that serves JSON endpoints
|
|
5
|
+
* for blackboard entries, decisions, graph data, and operational status.
|
|
6
|
+
*
|
|
7
|
+
* CRITICAL: Never use console.log or process.stdout in this module.
|
|
8
|
+
* The MCP StdioServerTransport owns stdout exclusively.
|
|
9
|
+
*/
|
|
10
|
+
import http from "node:http";
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { BlackboardStore } from "../storage/blackboard-store.js";
|
|
14
|
+
import { DecisionStore } from "../storage/decision-store.js";
|
|
15
|
+
import { GraphStore } from "../storage/graph-store.js";
|
|
16
|
+
import { AgentStore } from "../storage/agent-store.js";
|
|
17
|
+
import { HandoffStore } from "../storage/handoff-store.js";
|
|
18
|
+
import { BlackboardEngine } from "../engine/blackboard.js";
|
|
19
|
+
import { DecisionEngine } from "../engine/decisions.js";
|
|
20
|
+
import { GraphEngine } from "../engine/graph.js";
|
|
21
|
+
import { Embedder } from "../embeddings/embedder.js";
|
|
22
|
+
import { IndexManager } from "../embeddings/index-manager.js";
|
|
23
|
+
import { SearchEngine } from "../embeddings/search.js";
|
|
24
|
+
import { scoreAgent, parseDelegationMetadata, isDelegationExpired, } from "../engine/coordination.js";
|
|
25
|
+
import { computeLiveness, DEFAULT_LIVENESS_THRESHOLDS, } from "../utils/liveness.js";
|
|
26
|
+
/** Send a JSON response with standard headers. */
|
|
27
|
+
function sendJSON(res, data, statusCode = 200) {
|
|
28
|
+
const body = JSON.stringify(data);
|
|
29
|
+
res.writeHead(statusCode, {
|
|
30
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
31
|
+
"Cache-Control": "no-cache",
|
|
32
|
+
});
|
|
33
|
+
res.end(body);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create an API request handler for the given project root.
|
|
37
|
+
*
|
|
38
|
+
* Returns an async function that handles /api/* routes and returns true
|
|
39
|
+
* if the request was handled, false if it should fall through to other
|
|
40
|
+
* handlers (e.g., static file serving).
|
|
41
|
+
*
|
|
42
|
+
* Store instances are created once in the closure, not per-request.
|
|
43
|
+
*/
|
|
44
|
+
export function createApiHandler(projectRoot) {
|
|
45
|
+
const twiningDir = path.join(projectRoot, ".twining");
|
|
46
|
+
const blackboardStore = new BlackboardStore(twiningDir);
|
|
47
|
+
const decisionStore = new DecisionStore(twiningDir);
|
|
48
|
+
const graphStore = new GraphStore(twiningDir);
|
|
49
|
+
const agentStore = new AgentStore(twiningDir);
|
|
50
|
+
const handoffStore = new HandoffStore(twiningDir);
|
|
51
|
+
// Engine layer for search — lazily initialized to avoid creating
|
|
52
|
+
// .twining/embeddings/ directory on uninitialized projects
|
|
53
|
+
let searchEngines = null;
|
|
54
|
+
function getSearchEngines() {
|
|
55
|
+
if (!searchEngines) {
|
|
56
|
+
const embedder = Embedder.getInstance(twiningDir);
|
|
57
|
+
const indexManager = new IndexManager(twiningDir);
|
|
58
|
+
const searchEngine = new SearchEngine(embedder, indexManager);
|
|
59
|
+
const bbEngine = new BlackboardEngine(blackboardStore, embedder, indexManager, searchEngine);
|
|
60
|
+
const decEngine = new DecisionEngine(decisionStore, bbEngine, embedder, indexManager, projectRoot, searchEngine);
|
|
61
|
+
const grEngine = new GraphEngine(graphStore);
|
|
62
|
+
searchEngines = {
|
|
63
|
+
blackboardEngine: bbEngine,
|
|
64
|
+
decisionEngine: decEngine,
|
|
65
|
+
graphEngine: grEngine,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return searchEngines;
|
|
69
|
+
}
|
|
70
|
+
return async (req, res) => {
|
|
71
|
+
const url = req.url || "/";
|
|
72
|
+
// GET /api/search?q=...
|
|
73
|
+
if (url.startsWith("/api/search")) {
|
|
74
|
+
try {
|
|
75
|
+
if (!fs.existsSync(twiningDir)) {
|
|
76
|
+
const parsed = new URL(url, "http://localhost");
|
|
77
|
+
sendJSON(res, {
|
|
78
|
+
query: parsed.searchParams.get("q") || "",
|
|
79
|
+
results: [],
|
|
80
|
+
total: 0,
|
|
81
|
+
fallback_mode: true,
|
|
82
|
+
});
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const parsed = new URL(url, "http://localhost");
|
|
86
|
+
const q = parsed.searchParams.get("q") || "";
|
|
87
|
+
const typesParam = parsed.searchParams.get("types");
|
|
88
|
+
const scope = parsed.searchParams.get("scope");
|
|
89
|
+
const status = parsed.searchParams.get("status");
|
|
90
|
+
const domain = parsed.searchParams.get("domain");
|
|
91
|
+
const confidence = parsed.searchParams.get("confidence");
|
|
92
|
+
const tagsParam = parsed.searchParams.get("tags");
|
|
93
|
+
const since = parsed.searchParams.get("since");
|
|
94
|
+
const until = parsed.searchParams.get("until");
|
|
95
|
+
const limitParam = parsed.searchParams.get("limit");
|
|
96
|
+
const limit = limitParam ? parseInt(limitParam, 10) : 20;
|
|
97
|
+
if (!q) {
|
|
98
|
+
sendJSON(res, {
|
|
99
|
+
query: "",
|
|
100
|
+
results: [],
|
|
101
|
+
total: 0,
|
|
102
|
+
fallback_mode: true,
|
|
103
|
+
});
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
const requestedTypes = typesParam
|
|
107
|
+
? typesParam.split(",").map((t) => t.trim())
|
|
108
|
+
: ["blackboard", "decisions", "entities"];
|
|
109
|
+
const tags = tagsParam
|
|
110
|
+
? tagsParam.split(",").map((t) => t.trim())
|
|
111
|
+
: null;
|
|
112
|
+
const engines = getSearchEngines();
|
|
113
|
+
const allResults = [];
|
|
114
|
+
let fallbackMode = true;
|
|
115
|
+
// Search blackboard
|
|
116
|
+
if (requestedTypes.includes("blackboard")) {
|
|
117
|
+
const bbResult = await engines.blackboardEngine.query(q, { limit });
|
|
118
|
+
if (!bbResult.fallback_mode) {
|
|
119
|
+
fallbackMode = false;
|
|
120
|
+
}
|
|
121
|
+
for (const r of bbResult.results) {
|
|
122
|
+
const entry = r.entry;
|
|
123
|
+
// Post-filter by scope
|
|
124
|
+
if (scope && !entry.scope.startsWith(scope))
|
|
125
|
+
continue;
|
|
126
|
+
// Post-filter by tags
|
|
127
|
+
if (tags && !tags.some((t) => entry.tags.includes(t)))
|
|
128
|
+
continue;
|
|
129
|
+
// Post-filter by since/until
|
|
130
|
+
if (since && entry.timestamp < since)
|
|
131
|
+
continue;
|
|
132
|
+
if (until && entry.timestamp > until)
|
|
133
|
+
continue;
|
|
134
|
+
allResults.push({
|
|
135
|
+
type: "blackboard",
|
|
136
|
+
id: entry.id,
|
|
137
|
+
summary: entry.summary,
|
|
138
|
+
scope: entry.scope,
|
|
139
|
+
timestamp: entry.timestamp,
|
|
140
|
+
entry_type: entry.entry_type,
|
|
141
|
+
relevance: r.relevance,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Search decisions
|
|
146
|
+
if (requestedTypes.includes("decisions")) {
|
|
147
|
+
const decResult = await engines.decisionEngine.searchDecisions(q, {
|
|
148
|
+
domain: domain || undefined,
|
|
149
|
+
status: status || undefined,
|
|
150
|
+
confidence: confidence || undefined,
|
|
151
|
+
}, limit);
|
|
152
|
+
for (const r of decResult.results) {
|
|
153
|
+
// Post-filter by scope
|
|
154
|
+
if (scope && !r.scope.startsWith(scope))
|
|
155
|
+
continue;
|
|
156
|
+
// Post-filter by since/until
|
|
157
|
+
if (since && r.timestamp < since)
|
|
158
|
+
continue;
|
|
159
|
+
if (until && r.timestamp > until)
|
|
160
|
+
continue;
|
|
161
|
+
allResults.push({
|
|
162
|
+
type: "decision",
|
|
163
|
+
id: r.id,
|
|
164
|
+
summary: r.summary,
|
|
165
|
+
scope: r.scope,
|
|
166
|
+
domain: r.domain,
|
|
167
|
+
status: r.status,
|
|
168
|
+
confidence: r.confidence,
|
|
169
|
+
timestamp: r.timestamp,
|
|
170
|
+
relevance: r.relevance,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Search entities
|
|
175
|
+
if (requestedTypes.includes("entities")) {
|
|
176
|
+
const entResult = await engines.graphEngine.query(q, undefined, limit);
|
|
177
|
+
for (const entity of entResult.entities) {
|
|
178
|
+
allResults.push({
|
|
179
|
+
type: "entity",
|
|
180
|
+
id: entity.id,
|
|
181
|
+
name: entity.name,
|
|
182
|
+
entity_type: entity.type,
|
|
183
|
+
properties: entity.properties,
|
|
184
|
+
relevance: 0.5,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Sort by relevance descending, then timestamp descending as tiebreaker
|
|
189
|
+
allResults.sort((a, b) => {
|
|
190
|
+
if (b.relevance !== a.relevance)
|
|
191
|
+
return b.relevance - a.relevance;
|
|
192
|
+
const aTime = a.timestamp || "";
|
|
193
|
+
const bTime = b.timestamp || "";
|
|
194
|
+
return bTime.localeCompare(aTime);
|
|
195
|
+
});
|
|
196
|
+
sendJSON(res, {
|
|
197
|
+
query: q,
|
|
198
|
+
results: allResults,
|
|
199
|
+
total: allResults.length,
|
|
200
|
+
fallback_mode: fallbackMode,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
console.error("[twining] API /api/search error:", err);
|
|
205
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
// GET /api/status
|
|
210
|
+
if (url === "/api/status") {
|
|
211
|
+
try {
|
|
212
|
+
if (!fs.existsSync(twiningDir)) {
|
|
213
|
+
sendJSON(res, {
|
|
214
|
+
initialized: false,
|
|
215
|
+
blackboard_entries: 0,
|
|
216
|
+
active_decisions: 0,
|
|
217
|
+
provisional_decisions: 0,
|
|
218
|
+
graph_entities: 0,
|
|
219
|
+
graph_relations: 0,
|
|
220
|
+
last_activity: "none",
|
|
221
|
+
registered_agents: 0,
|
|
222
|
+
active_agents: 0,
|
|
223
|
+
pending_delegations: 0,
|
|
224
|
+
total_handoffs: 0,
|
|
225
|
+
});
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
const { total_count: blackboard_entries } = await blackboardStore.read();
|
|
229
|
+
const index = await decisionStore.getIndex();
|
|
230
|
+
const active_decisions = index.filter((e) => e.status === "active").length;
|
|
231
|
+
const provisional_decisions = index.filter((e) => e.status === "provisional").length;
|
|
232
|
+
const entities = await graphStore.getEntities();
|
|
233
|
+
const relations = await graphStore.getRelations();
|
|
234
|
+
const graph_entities = entities.length;
|
|
235
|
+
const graph_relations = relations.length;
|
|
236
|
+
// Compute last_activity from most recent blackboard entry and decision
|
|
237
|
+
const recentEntries = await blackboardStore.recent(1);
|
|
238
|
+
const lastBBActivity = recentEntries.length > 0
|
|
239
|
+
? recentEntries[recentEntries.length - 1].timestamp
|
|
240
|
+
: null;
|
|
241
|
+
const lastDecisionActivity = index.length > 0
|
|
242
|
+
? index.reduce((latest, e) => e.timestamp > latest ? e.timestamp : latest, index[0].timestamp)
|
|
243
|
+
: null;
|
|
244
|
+
let last_activity = "none";
|
|
245
|
+
if (lastBBActivity && lastDecisionActivity) {
|
|
246
|
+
last_activity =
|
|
247
|
+
lastBBActivity > lastDecisionActivity
|
|
248
|
+
? lastBBActivity
|
|
249
|
+
: lastDecisionActivity;
|
|
250
|
+
}
|
|
251
|
+
else if (lastBBActivity) {
|
|
252
|
+
last_activity = lastBBActivity;
|
|
253
|
+
}
|
|
254
|
+
else if (lastDecisionActivity) {
|
|
255
|
+
last_activity = lastDecisionActivity;
|
|
256
|
+
}
|
|
257
|
+
// Coordination counts
|
|
258
|
+
const agents = await agentStore.getAll();
|
|
259
|
+
const registered_agents = agents.length;
|
|
260
|
+
const now = new Date();
|
|
261
|
+
const active_agents = agents.filter((a) => computeLiveness(a.last_active, now, DEFAULT_LIVENESS_THRESHOLDS) ===
|
|
262
|
+
"active").length;
|
|
263
|
+
const { entries: needEntries } = await blackboardStore.read({
|
|
264
|
+
entry_types: ["need"],
|
|
265
|
+
});
|
|
266
|
+
const pending_delegations = needEntries.filter((entry) => {
|
|
267
|
+
const meta = parseDelegationMetadata(entry);
|
|
268
|
+
return meta !== null && !isDelegationExpired(meta, now);
|
|
269
|
+
}).length;
|
|
270
|
+
const handoffs = await handoffStore.list({});
|
|
271
|
+
const total_handoffs = handoffs.length;
|
|
272
|
+
sendJSON(res, {
|
|
273
|
+
initialized: true,
|
|
274
|
+
blackboard_entries,
|
|
275
|
+
active_decisions,
|
|
276
|
+
provisional_decisions,
|
|
277
|
+
graph_entities,
|
|
278
|
+
graph_relations,
|
|
279
|
+
last_activity,
|
|
280
|
+
registered_agents,
|
|
281
|
+
active_agents,
|
|
282
|
+
pending_delegations,
|
|
283
|
+
total_handoffs,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
console.error("[twining] API /api/status error:", err);
|
|
288
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
289
|
+
}
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
// GET /api/blackboard
|
|
293
|
+
if (url === "/api/blackboard") {
|
|
294
|
+
try {
|
|
295
|
+
if (!fs.existsSync(twiningDir)) {
|
|
296
|
+
sendJSON(res, {
|
|
297
|
+
initialized: false,
|
|
298
|
+
entries: [],
|
|
299
|
+
total_count: 0,
|
|
300
|
+
});
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
const { entries, total_count } = await blackboardStore.read();
|
|
304
|
+
sendJSON(res, { initialized: true, entries, total_count });
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
console.error("[twining] API /api/blackboard error:", err);
|
|
308
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
// GET /api/decisions/:id (must come before /api/decisions exact match)
|
|
313
|
+
if (url.startsWith("/api/decisions/")) {
|
|
314
|
+
try {
|
|
315
|
+
const id = url.slice("/api/decisions/".length);
|
|
316
|
+
if (!id) {
|
|
317
|
+
sendJSON(res, { error: "Decision ID required" }, 400);
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
if (!fs.existsSync(twiningDir)) {
|
|
321
|
+
sendJSON(res, { error: "Decision not found" }, 404);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
const decision = await decisionStore.get(id);
|
|
325
|
+
if (!decision) {
|
|
326
|
+
sendJSON(res, { error: "Decision not found" }, 404);
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
sendJSON(res, decision);
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
console.error("[twining] API /api/decisions/:id error:", err);
|
|
333
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
334
|
+
}
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
// GET /api/decisions
|
|
338
|
+
if (url === "/api/decisions") {
|
|
339
|
+
try {
|
|
340
|
+
if (!fs.existsSync(twiningDir)) {
|
|
341
|
+
sendJSON(res, {
|
|
342
|
+
initialized: false,
|
|
343
|
+
decisions: [],
|
|
344
|
+
total_count: 0,
|
|
345
|
+
});
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
const decisions = await decisionStore.getIndex();
|
|
349
|
+
sendJSON(res, {
|
|
350
|
+
initialized: true,
|
|
351
|
+
decisions,
|
|
352
|
+
total_count: decisions.length,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
catch (err) {
|
|
356
|
+
console.error("[twining] API /api/decisions error:", err);
|
|
357
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
358
|
+
}
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
// GET /api/agents
|
|
362
|
+
if (url === "/api/agents") {
|
|
363
|
+
try {
|
|
364
|
+
if (!fs.existsSync(twiningDir)) {
|
|
365
|
+
sendJSON(res, { initialized: false, agents: [], total: 0 });
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
const agents = await agentStore.getAll();
|
|
369
|
+
const now = new Date();
|
|
370
|
+
const mapped = agents.map((agent) => ({
|
|
371
|
+
...agent,
|
|
372
|
+
liveness: computeLiveness(agent.last_active, now, DEFAULT_LIVENESS_THRESHOLDS),
|
|
373
|
+
}));
|
|
374
|
+
sendJSON(res, { initialized: true, agents: mapped, total: mapped.length });
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
console.error("[twining] API /api/agents error:", err);
|
|
378
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
379
|
+
}
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
// GET /api/delegations
|
|
383
|
+
if (url === "/api/delegations") {
|
|
384
|
+
try {
|
|
385
|
+
if (!fs.existsSync(twiningDir)) {
|
|
386
|
+
sendJSON(res, { initialized: false, delegations: [], total: 0 });
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
const { entries: needEntries } = await blackboardStore.read({
|
|
390
|
+
entry_types: ["need"],
|
|
391
|
+
});
|
|
392
|
+
const agents = await agentStore.getAll();
|
|
393
|
+
const now = new Date();
|
|
394
|
+
const delegations = [];
|
|
395
|
+
for (const entry of needEntries) {
|
|
396
|
+
const meta = parseDelegationMetadata(entry);
|
|
397
|
+
if (!meta)
|
|
398
|
+
continue;
|
|
399
|
+
const expired = isDelegationExpired(meta, now);
|
|
400
|
+
// Score agents, filter out gone, sort by total_score, take top 5
|
|
401
|
+
const scored = agents
|
|
402
|
+
.map((agent) => scoreAgent(agent, meta.required_capabilities, DEFAULT_LIVENESS_THRESHOLDS, now))
|
|
403
|
+
.filter((s) => s.liveness !== "gone")
|
|
404
|
+
.sort((a, b) => b.total_score - a.total_score)
|
|
405
|
+
.slice(0, 5)
|
|
406
|
+
.map((s) => ({
|
|
407
|
+
agent_id: s.agent_id,
|
|
408
|
+
capabilities: s.capabilities,
|
|
409
|
+
role: s.role,
|
|
410
|
+
liveness: s.liveness,
|
|
411
|
+
total_score: s.total_score,
|
|
412
|
+
}));
|
|
413
|
+
delegations.push({
|
|
414
|
+
entry_id: entry.id,
|
|
415
|
+
timestamp: entry.timestamp,
|
|
416
|
+
summary: entry.summary,
|
|
417
|
+
scope: entry.scope,
|
|
418
|
+
agent_id: entry.agent_id,
|
|
419
|
+
required_capabilities: meta.required_capabilities,
|
|
420
|
+
urgency: meta.urgency,
|
|
421
|
+
expires_at: meta.expires_at,
|
|
422
|
+
expired,
|
|
423
|
+
suggested_agents: scored,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
sendJSON(res, {
|
|
427
|
+
initialized: true,
|
|
428
|
+
delegations,
|
|
429
|
+
total: delegations.length,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
catch (err) {
|
|
433
|
+
console.error("[twining] API /api/delegations error:", err);
|
|
434
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
435
|
+
}
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
// GET /api/handoffs/:id (must come before /api/handoffs exact match)
|
|
439
|
+
if (url.startsWith("/api/handoffs/")) {
|
|
440
|
+
try {
|
|
441
|
+
const id = url.slice("/api/handoffs/".length);
|
|
442
|
+
if (!id) {
|
|
443
|
+
sendJSON(res, { error: "Handoff ID required" }, 400);
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
if (!fs.existsSync(twiningDir)) {
|
|
447
|
+
sendJSON(res, { error: "Handoff not found" }, 404);
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
const handoff = await handoffStore.get(id);
|
|
451
|
+
if (!handoff) {
|
|
452
|
+
sendJSON(res, { error: "Handoff not found" }, 404);
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
455
|
+
sendJSON(res, handoff);
|
|
456
|
+
}
|
|
457
|
+
catch (err) {
|
|
458
|
+
console.error("[twining] API /api/handoffs/:id error:", err);
|
|
459
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
460
|
+
}
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
// GET /api/handoffs
|
|
464
|
+
if (url === "/api/handoffs") {
|
|
465
|
+
try {
|
|
466
|
+
if (!fs.existsSync(twiningDir)) {
|
|
467
|
+
sendJSON(res, { initialized: false, handoffs: [], total: 0 });
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
const entries = await handoffStore.list({});
|
|
471
|
+
sendJSON(res, {
|
|
472
|
+
initialized: true,
|
|
473
|
+
handoffs: entries,
|
|
474
|
+
total: entries.length,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
catch (err) {
|
|
478
|
+
console.error("[twining] API /api/handoffs error:", err);
|
|
479
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
480
|
+
}
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
// GET /api/graph
|
|
484
|
+
if (url === "/api/graph") {
|
|
485
|
+
try {
|
|
486
|
+
if (!fs.existsSync(twiningDir)) {
|
|
487
|
+
sendJSON(res, {
|
|
488
|
+
initialized: false,
|
|
489
|
+
entities: [],
|
|
490
|
+
relations: [],
|
|
491
|
+
entity_count: 0,
|
|
492
|
+
relation_count: 0,
|
|
493
|
+
});
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
const entities = await graphStore.getEntities();
|
|
497
|
+
const relations = await graphStore.getRelations();
|
|
498
|
+
sendJSON(res, {
|
|
499
|
+
initialized: true,
|
|
500
|
+
entities,
|
|
501
|
+
relations,
|
|
502
|
+
entity_count: entities.length,
|
|
503
|
+
relation_count: relations.length,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
catch (err) {
|
|
507
|
+
console.error("[twining] API /api/graph error:", err);
|
|
508
|
+
sendJSON(res, { error: "Internal server error" }, 500);
|
|
509
|
+
}
|
|
510
|
+
return true;
|
|
511
|
+
}
|
|
512
|
+
// Not an API route we handle
|
|
513
|
+
return false;
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
//# sourceMappingURL=api-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-routes.js","sourceRoot":"","sources":["../../src/dashboard/api-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,UAAU,EACV,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,eAAe,EACf,2BAA2B,GAC5B,MAAM,sBAAsB,CAAC;AAE9B,kDAAkD;AAClD,SAAS,QAAQ,CACf,GAAwB,EACxB,IAAa,EACb,aAAqB,GAAG;IAExB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE;QACxB,cAAc,EAAE,iCAAiC;QACjD,eAAe,EAAE,UAAU;KAC5B,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,WAAmB;IAEnB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,UAAU,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAC;IAElD,iEAAiE;IACjE,2DAA2D;IAC3D,IAAI,aAAa,GAIN,IAAI,CAAC;IAEhB,SAAS,gBAAgB;QACvB,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YAClD,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAC;YAClD,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YAC9D,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CACnC,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,YAAY,CACb,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,cAAc,CAClC,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,YAAY,CACb,CAAC;YACF,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC;YAC7C,aAAa,GAAG;gBACd,gBAAgB,EAAE,QAAQ;gBAC1B,cAAc,EAAE,SAAS;gBACzB,WAAW,EAAE,QAAQ;aACtB,CAAC;QACJ,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,OAAO,KAAK,EACV,GAAyB,EACzB,GAAwB,EACN,EAAE;QACpB,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;QAE3B,wBAAwB;QACxB,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;oBAChD,QAAQ,CAAC,GAAG,EAAE;wBACZ,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE;wBACzC,OAAO,EAAE,EAAE;wBACX,KAAK,EAAE,CAAC;wBACR,aAAa,EAAE,IAAI;qBACpB,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;gBAChD,MAAM,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACpD,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACjD,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACjD,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACzD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClD,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC/C,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACpD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAEzD,IAAI,CAAC,CAAC,EAAE,CAAC;oBACP,QAAQ,CAAC,GAAG,EAAE;wBACZ,KAAK,EAAE,EAAE;wBACT,OAAO,EAAE,EAAE;wBACX,KAAK,EAAE,CAAC;wBACR,aAAa,EAAE,IAAI;qBACpB,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,cAAc,GAAG,UAAU;oBAC/B,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC5C,CAAC,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;gBAC5C,MAAM,IAAI,GAAG,SAAS;oBACpB,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC3C,CAAC,CAAC,IAAI,CAAC;gBAkBT,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;gBACnC,MAAM,UAAU,GAAoB,EAAE,CAAC;gBACvC,IAAI,YAAY,GAAG,IAAI,CAAC;gBAExB,oBAAoB;gBACpB,IAAI,cAAc,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;oBACpE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;wBAC5B,YAAY,GAAG,KAAK,CAAC;oBACvB,CAAC;oBACD,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;wBACjC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;wBACtB,uBAAuB;wBACvB,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;4BAAE,SAAS;wBACtD,sBAAsB;wBACtB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;4BAAE,SAAS;wBAChE,6BAA6B;wBAC7B,IAAI,KAAK,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK;4BAAE,SAAS;wBAC/C,IAAI,KAAK,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK;4BAAE,SAAS;wBAE/C,UAAU,CAAC,IAAI,CAAC;4BACd,IAAI,EAAE,YAAY;4BAClB,EAAE,EAAE,KAAK,CAAC,EAAE;4BACZ,OAAO,EAAE,KAAK,CAAC,OAAO;4BACtB,KAAK,EAAE,KAAK,CAAC,KAAK;4BAClB,SAAS,EAAE,KAAK,CAAC,SAAS;4BAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;4BAC5B,SAAS,EAAE,CAAC,CAAC,SAAS;yBACvB,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAED,mBAAmB;gBACnB,IAAI,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;oBACzC,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,eAAe,CAC5D,CAAC,EACD;wBACE,MAAM,EAAE,MAAM,IAAI,SAAS;wBAC3B,MAAM,EAAG,MAAiE,IAAI,SAAS;wBACvF,UAAU,EAAG,UAAwC,IAAI,SAAS;qBACnE,EACD,KAAK,CACN,CAAC;oBACF,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBAClC,uBAAuB;wBACvB,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;4BAAE,SAAS;wBAClD,6BAA6B;wBAC7B,IAAI,KAAK,IAAI,CAAC,CAAC,SAAS,GAAG,KAAK;4BAAE,SAAS;wBAC3C,IAAI,KAAK,IAAI,CAAC,CAAC,SAAS,GAAG,KAAK;4BAAE,SAAS;wBAE3C,UAAU,CAAC,IAAI,CAAC;4BACd,IAAI,EAAE,UAAU;4BAChB,EAAE,EAAE,CAAC,CAAC,EAAE;4BACR,OAAO,EAAE,CAAC,CAAC,OAAO;4BAClB,KAAK,EAAE,CAAC,CAAC,KAAK;4BACd,MAAM,EAAE,CAAC,CAAC,MAAM;4BAChB,MAAM,EAAE,CAAC,CAAC,MAAM;4BAChB,UAAU,EAAE,CAAC,CAAC,UAAU;4BACxB,SAAS,EAAE,CAAC,CAAC,SAAS;4BACtB,SAAS,EAAE,CAAC,CAAC,SAAS;yBACvB,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAED,kBAAkB;gBAClB,IAAI,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;oBACxC,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;oBACvE,KAAK,MAAM,MAAM,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;wBACxC,UAAU,CAAC,IAAI,CAAC;4BACd,IAAI,EAAE,QAAQ;4BACd,EAAE,EAAE,MAAM,CAAC,EAAE;4BACb,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,WAAW,EAAE,MAAM,CAAC,IAAI;4BACxB,UAAU,EAAE,MAAM,CAAC,UAAU;4BAC7B,SAAS,EAAE,GAAG;yBACf,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAED,wEAAwE;gBACxE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;oBACvB,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS;wBAAE,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;oBAClE,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;oBAChC,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;oBAChC,OAAO,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBACpC,CAAC,CAAC,CAAC;gBAEH,QAAQ,CAAC,GAAG,EAAE;oBACZ,KAAK,EAAE,CAAC;oBACR,OAAO,EAAE,UAAU;oBACnB,KAAK,EAAE,UAAU,CAAC,MAAM;oBACxB,aAAa,EAAE,YAAY;iBAC5B,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;gBACvD,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kBAAkB;QAClB,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE;wBACZ,WAAW,EAAE,KAAK;wBAClB,kBAAkB,EAAE,CAAC;wBACrB,gBAAgB,EAAE,CAAC;wBACnB,qBAAqB,EAAE,CAAC;wBACxB,cAAc,EAAE,CAAC;wBACjB,eAAe,EAAE,CAAC;wBAClB,aAAa,EAAE,MAAM;wBACrB,iBAAiB,EAAE,CAAC;wBACpB,aAAa,EAAE,CAAC;wBAChB,mBAAmB,EAAE,CAAC;wBACtB,cAAc,EAAE,CAAC;qBAClB,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,GACvC,MAAM,eAAe,CAAC,IAAI,EAAE,CAAC;gBAE/B,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC;gBAC7C,MAAM,gBAAgB,GAAG,KAAK,CAAC,MAAM,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAC7B,CAAC,MAAM,CAAC;gBACT,MAAM,qBAAqB,GAAG,KAAK,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAClC,CAAC,MAAM,CAAC;gBAET,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC;gBAChD,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC;gBAClD,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC;gBACvC,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC;gBAEzC,uEAAuE;gBACvE,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACtD,MAAM,cAAc,GAClB,aAAa,CAAC,MAAM,GAAG,CAAC;oBACtB,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,SAAS;oBACpD,CAAC,CAAC,IAAI,CAAC;gBACX,MAAM,oBAAoB,GACxB,KAAK,CAAC,MAAM,GAAG,CAAC;oBACd,CAAC,CAAC,KAAK,CAAC,MAAM,CACV,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAC7C,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CACpB;oBACH,CAAC,CAAC,IAAI,CAAC;gBAEX,IAAI,aAAa,GAAG,MAAM,CAAC;gBAC3B,IAAI,cAAc,IAAI,oBAAoB,EAAE,CAAC;oBAC3C,aAAa;wBACX,cAAc,GAAG,oBAAoB;4BACnC,CAAC,CAAC,cAAc;4BAChB,CAAC,CAAC,oBAAoB,CAAC;gBAC7B,CAAC;qBAAM,IAAI,cAAc,EAAE,CAAC;oBAC1B,aAAa,GAAG,cAAc,CAAC;gBACjC,CAAC;qBAAM,IAAI,oBAAoB,EAAE,CAAC;oBAChC,aAAa,GAAG,oBAAoB,CAAC;gBACvC,CAAC;gBAED,sBAAsB;gBACtB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;gBACzC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;gBACxC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CACjC,CAAC,CAAC,EAAE,EAAE,CACJ,eAAe,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,EAAE,2BAA2B,CAAC;oBAChE,QAAQ,CACX,CAAC,MAAM,CAAC;gBAET,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC;oBAC1D,WAAW,EAAE,CAAC,MAAM,CAAC;iBACtB,CAAC,CAAC;gBACH,MAAM,mBAAmB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;oBACvD,MAAM,IAAI,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;oBAC5C,OAAO,IAAI,KAAK,IAAI,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAC1D,CAAC,CAAC,CAAC,MAAM,CAAC;gBAEV,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7C,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC;gBAEvC,QAAQ,CAAC,GAAG,EAAE;oBACZ,WAAW,EAAE,IAAI;oBACjB,kBAAkB;oBAClB,gBAAgB;oBAChB,qBAAqB;oBACrB,cAAc;oBACd,eAAe;oBACf,aAAa;oBACb,iBAAiB;oBACjB,aAAa;oBACb,mBAAmB;oBACnB,cAAc;iBACf,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;gBACvD,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,sBAAsB;QACtB,IAAI,GAAG,KAAK,iBAAiB,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE;wBACZ,WAAW,EAAE,KAAK;wBAClB,OAAO,EAAE,EAAE;wBACX,WAAW,EAAE,CAAC;qBACf,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,CAAC;gBAC9D,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;gBAC3D,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,uEAAuE;QACvE,IAAI,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;gBAC/C,IAAI,CAAC,EAAE,EAAE,CAAC;oBACR,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAE,GAAG,CAAC,CAAC;oBACtD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;oBACpD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;oBACpD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC1B,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;gBAC9D,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,qBAAqB;QACrB,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE;wBACZ,WAAW,EAAE,KAAK;wBAClB,SAAS,EAAE,EAAE;wBACb,WAAW,EAAE,CAAC;qBACf,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC;gBACjD,QAAQ,CAAC,GAAG,EAAE;oBACZ,WAAW,EAAE,IAAI;oBACjB,SAAS;oBACT,WAAW,EAAE,SAAS,CAAC,MAAM;iBAC9B,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;gBAC1D,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kBAAkB;QAClB,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC5D,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;gBACzC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBACpC,GAAG,KAAK;oBACR,QAAQ,EAAE,eAAe,CACvB,KAAK,CAAC,WAAW,EACjB,GAAG,EACH,2BAA2B,CAC5B;iBACF,CAAC,CAAC,CAAC;gBACJ,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7E,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;gBACvD,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,uBAAuB;QACvB,IAAI,GAAG,KAAK,kBAAkB,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBACjE,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC;oBAC1D,WAAW,EAAE,CAAC,MAAM,CAAC;iBACtB,CAAC,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;gBACzC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBAEvB,MAAM,WAAW,GAiBZ,EAAE,CAAC;gBAER,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;oBAChC,MAAM,IAAI,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;oBAC5C,IAAI,CAAC,IAAI;wBAAE,SAAS;oBAEpB,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;oBAE/C,iEAAiE;oBACjE,MAAM,MAAM,GAAG,MAAM;yBAClB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACb,UAAU,CACR,KAAK,EACL,IAAI,CAAC,qBAAqB,EAC1B,2BAA2B,EAC3B,GAAG,CACJ,CACF;yBACA,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;yBACpC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;yBAC7C,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;yBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACX,QAAQ,EAAE,CAAC,CAAC,QAAQ;wBACpB,YAAY,EAAE,CAAC,CAAC,YAAY;wBAC5B,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;wBACpB,WAAW,EAAE,CAAC,CAAC,WAAW;qBAC3B,CAAC,CAAC,CAAC;oBAEN,WAAW,CAAC,IAAI,CAAC;wBACf,QAAQ,EAAE,KAAK,CAAC,EAAE;wBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;wBACjD,OAAO,EAAE,IAAI,CAAC,OAAO;wBACrB,UAAU,EAAE,IAAI,CAAC,UAAU;wBAC3B,OAAO;wBACP,gBAAgB,EAAE,MAAM;qBACzB,CAAC,CAAC;gBACL,CAAC;gBAED,QAAQ,CAAC,GAAG,EAAE;oBACZ,WAAW,EAAE,IAAI;oBACjB,WAAW;oBACX,KAAK,EAAE,WAAW,CAAC,MAAM;iBAC1B,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;gBAC5D,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,qEAAqE;QACrE,IAAI,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBAC9C,IAAI,CAAC,EAAE,EAAE,CAAC;oBACR,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAAE,GAAG,CAAC,CAAC;oBACrD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;oBACnD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;oBACnD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;gBAC7D,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,oBAAoB;QACpB,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC9D,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC5C,QAAQ,CAAC,GAAG,EAAE;oBACZ,WAAW,EAAE,IAAI;oBACjB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,OAAO,CAAC,MAAM;iBACtB,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;gBACzD,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,iBAAiB;QACjB,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC/B,QAAQ,CAAC,GAAG,EAAE;wBACZ,WAAW,EAAE,KAAK;wBAClB,QAAQ,EAAE,EAAE;wBACZ,SAAS,EAAE,EAAE;wBACb,YAAY,EAAE,CAAC;wBACf,cAAc,EAAE,CAAC;qBAClB,CAAC,CAAC;oBACH,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC;gBAChD,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC;gBAClD,QAAQ,CAAC,GAAG,EAAE;oBACZ,WAAW,EAAE,IAAI;oBACjB,QAAQ;oBACR,SAAS;oBACT,YAAY,EAAE,QAAQ,CAAC,MAAM;oBAC7B,cAAc,EAAE,SAAS,CAAC,MAAM;iBACjC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;gBACtD,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,6BAA6B;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard configuration from environment variables.
|
|
3
|
+
* All dashboard config is read from env vars to allow MCP host configuration
|
|
4
|
+
* without modifying .twining/config.yml.
|
|
5
|
+
*/
|
|
6
|
+
export interface DashboardConfig {
|
|
7
|
+
/** Port number for the HTTP server (default: 24282) */
|
|
8
|
+
port: number;
|
|
9
|
+
/** Whether the dashboard is enabled (default: true, disable with TWINING_DASHBOARD=0) */
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
/** Whether to auto-open browser on start (default: true, disable with TWINING_DASHBOARD_NO_OPEN=1) */
|
|
12
|
+
autoOpen: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Read dashboard configuration from environment variables.
|
|
16
|
+
* Defaults: port 24282, enabled true, autoOpen true.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getDashboardConfig(): DashboardConfig;
|
|
19
|
+
//# sourceMappingURL=dashboard-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-config.d.ts","sourceRoot":"","sources":["../../src/dashboard/dashboard-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;IACjB,sGAAsG;IACtG,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAMpD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard configuration from environment variables.
|
|
3
|
+
* All dashboard config is read from env vars to allow MCP host configuration
|
|
4
|
+
* without modifying .twining/config.yml.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Read dashboard configuration from environment variables.
|
|
8
|
+
* Defaults: port 24282, enabled true, autoOpen true.
|
|
9
|
+
*/
|
|
10
|
+
export function getDashboardConfig() {
|
|
11
|
+
return {
|
|
12
|
+
port: parseInt(process.env["TWINING_DASHBOARD_PORT"] || "24282", 10),
|
|
13
|
+
enabled: process.env["TWINING_DASHBOARD"] !== "0",
|
|
14
|
+
autoOpen: process.env["TWINING_DASHBOARD_NO_OPEN"] !== "1",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=dashboard-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-config.js","sourceRoot":"","sources":["../../src/dashboard/dashboard-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,OAAO,EAAE,EAAE,CAAC;QACpE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,GAAG;QACjD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,KAAK,GAAG;KAC3D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded HTTP server for the Twining dashboard.
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL: Never use console.log or process.stdout in this module.
|
|
5
|
+
* The MCP StdioServerTransport owns stdout exclusively — any writes
|
|
6
|
+
* corrupt the JSON-RPC byte stream.
|
|
7
|
+
*/
|
|
8
|
+
import http from "node:http";
|
|
9
|
+
/**
|
|
10
|
+
* Create a request handler that routes between API and static files.
|
|
11
|
+
* API routes are checked first, then health check, then static files.
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleRequest(publicDir: string, projectRoot: string): (req: http.IncomingMessage, res: http.ServerResponse) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Start the dashboard HTTP server.
|
|
16
|
+
* Returns the server and actual port, or null if the dashboard is disabled.
|
|
17
|
+
*
|
|
18
|
+
* @param projectRoot - The project root directory (used for API data access)
|
|
19
|
+
*/
|
|
20
|
+
export declare function startDashboard(projectRoot: string): Promise<{
|
|
21
|
+
server: http.Server;
|
|
22
|
+
port: number;
|
|
23
|
+
} | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Register signal handlers for graceful dashboard shutdown.
|
|
26
|
+
* Closes the HTTP server on SIGTERM/SIGINT with a 3-second force-exit timeout.
|
|
27
|
+
*/
|
|
28
|
+
export declare function setupDashboardShutdown(httpServer: http.Server): void;
|
|
29
|
+
//# sourceMappingURL=http-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/dashboard/http-server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAmG7B;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CA8B/D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA2BvD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAiBpE"}
|