agentflow-dashboard 0.8.2 → 0.8.4
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/dist/{chunk-EG254FLY.js → chunk-YLQ5MVCW.js} +204 -104
- package/dist/cli.cjs +193 -86
- package/dist/cli.js +1 -1
- package/dist/client/assets/index-BQBa4cES.css +1 -0
- package/dist/client/assets/{index-DCSWGDzI.js → index-DA9m90ZC.js} +7 -7
- package/dist/client/index.html +2 -2
- package/dist/index.cjs +193 -86
- package/dist/index.js +1 -1
- package/dist/server.cjs +193 -86
- package/dist/server.js +1 -1
- package/package.json +21 -7
- package/dist/client/assets/index-DHcSpTgM.css +0 -1
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
1
|
// src/server.ts
|
|
9
|
-
import { execSync } from "child_process";
|
|
2
|
+
import { execFileSync, execSync } from "child_process";
|
|
10
3
|
import * as fs3 from "fs";
|
|
11
4
|
import { createServer } from "http";
|
|
12
5
|
import * as path3 from "path";
|
|
13
6
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
|
+
import {
|
|
8
|
+
auditProcesses,
|
|
9
|
+
createExecutionEvent,
|
|
10
|
+
createKnowledgeStore,
|
|
11
|
+
discoverAllProcessConfigs,
|
|
12
|
+
discoverProcess,
|
|
13
|
+
findVariants,
|
|
14
|
+
getBottlenecks,
|
|
15
|
+
loadGraph as loadGraph2
|
|
16
|
+
} from "agentflow-core";
|
|
17
|
+
import chokidar2 from "chokidar";
|
|
18
|
+
import express from "express";
|
|
19
|
+
import rateLimit from "express-rate-limit";
|
|
20
|
+
import { WebSocketServer } from "ws";
|
|
14
21
|
|
|
15
22
|
// src/config.ts
|
|
16
23
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -83,21 +90,6 @@ function getProcessPreference(config) {
|
|
|
83
90
|
return config.processPreference ?? null;
|
|
84
91
|
}
|
|
85
92
|
|
|
86
|
-
// src/server.ts
|
|
87
|
-
import {
|
|
88
|
-
auditProcesses,
|
|
89
|
-
createExecutionEvent,
|
|
90
|
-
createKnowledgeStore,
|
|
91
|
-
discoverAllProcessConfigs,
|
|
92
|
-
discoverProcess,
|
|
93
|
-
findVariants,
|
|
94
|
-
getBottlenecks,
|
|
95
|
-
loadGraph as loadGraph2
|
|
96
|
-
} from "agentflow-core";
|
|
97
|
-
import chokidar2 from "chokidar";
|
|
98
|
-
import express from "express";
|
|
99
|
-
import { WebSocketServer } from "ws";
|
|
100
|
-
|
|
101
93
|
// src/adapters/agentflow.ts
|
|
102
94
|
var SKIP_FILES = /* @__PURE__ */ new Set([
|
|
103
95
|
"workers.json",
|
|
@@ -109,7 +101,14 @@ var SKIP_FILES = /* @__PURE__ */ new Set([
|
|
|
109
101
|
"models.json",
|
|
110
102
|
"config.json"
|
|
111
103
|
]);
|
|
112
|
-
var SKIP_SUFFIXES = [
|
|
104
|
+
var SKIP_SUFFIXES = [
|
|
105
|
+
"-state.json",
|
|
106
|
+
"-config.json",
|
|
107
|
+
"-watch-state.json",
|
|
108
|
+
".tmp",
|
|
109
|
+
".bak",
|
|
110
|
+
".backup"
|
|
111
|
+
];
|
|
113
112
|
var AgentFlowAdapter = class {
|
|
114
113
|
name = "agentflow";
|
|
115
114
|
detect(_dirPath) {
|
|
@@ -234,7 +233,7 @@ var OpenClawAdapter = class {
|
|
|
234
233
|
};
|
|
235
234
|
|
|
236
235
|
// src/adapters/otel.ts
|
|
237
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3
|
|
236
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
238
237
|
import { join as join3 } from "path";
|
|
239
238
|
var SPAN_TYPE_MAP = {
|
|
240
239
|
"gen_ai.chat": "llm",
|
|
@@ -386,8 +385,14 @@ registerAdapter(new AgentFlowAdapter());
|
|
|
386
385
|
var PURPOSE_KEYWORDS = [
|
|
387
386
|
{ keywords: ["email", "mail", "inbox", "smtp"], group: "Email Processors" },
|
|
388
387
|
{ keywords: ["monitor", "watch", "alert", "surveillance"], group: "Monitors" },
|
|
389
|
-
{
|
|
390
|
-
|
|
388
|
+
{
|
|
389
|
+
keywords: ["digest", "newsletter", "summary", "report", "briefing"],
|
|
390
|
+
group: "Digests & Reports"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
keywords: ["curator", "janitor", "distiller", "surveyor", "worker", "indexer"],
|
|
394
|
+
group: "Workers"
|
|
395
|
+
},
|
|
391
396
|
{ keywords: ["cron", "schedule", "timer", "periodic"], group: "Scheduled Jobs" },
|
|
392
397
|
{ keywords: ["search", "scrape", "crawl", "fetch"], group: "Data Collection" },
|
|
393
398
|
{ keywords: ["embed", "vector", "index"], group: "Embeddings" }
|
|
@@ -419,6 +424,7 @@ function capitalize(s) {
|
|
|
419
424
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
420
425
|
}
|
|
421
426
|
function deduplicateAgents(agents) {
|
|
427
|
+
var _a, _b, _c, _d;
|
|
422
428
|
const tagged = agents.map((a) => ({
|
|
423
429
|
...a,
|
|
424
430
|
...extractSource(a.agentId)
|
|
@@ -435,14 +441,14 @@ function deduplicateAgents(agents) {
|
|
|
435
441
|
const mergedIds = /* @__PURE__ */ new Set();
|
|
436
442
|
const mergedAgents = [];
|
|
437
443
|
for (const [_key, group] of suffixGroups) {
|
|
438
|
-
const suffix = extractSuffix(group[0].localId);
|
|
444
|
+
const suffix = extractSuffix((_a = group[0]) == null ? void 0 : _a.localId);
|
|
439
445
|
if (group.length < 2) continue;
|
|
440
446
|
const prefixes = new Set(group.map((a) => a.localId.split("-")[0]));
|
|
441
447
|
if (prefixes.size < 2) continue;
|
|
442
448
|
const longPrefixes = [...prefixes].filter((p) => p !== suffix && p.length > 2);
|
|
443
449
|
if (longPrefixes.length >= 2) continue;
|
|
444
450
|
const merged = {
|
|
445
|
-
agentId: group[0].source === "agentflow" ? suffix : `${group[0].source}:${suffix}`,
|
|
451
|
+
agentId: ((_b = group[0]) == null ? void 0 : _b.source) === "agentflow" ? suffix : `${(_c = group[0]) == null ? void 0 : _c.source}:${suffix}`,
|
|
446
452
|
displayName: suffix,
|
|
447
453
|
totalExecutions: group.reduce((s, a) => s + a.totalExecutions, 0),
|
|
448
454
|
successfulExecutions: group.reduce((s, a) => s + a.successfulExecutions, 0),
|
|
@@ -453,7 +459,7 @@ function deduplicateAgents(agents) {
|
|
|
453
459
|
triggers: {},
|
|
454
460
|
recentActivity: group.flatMap((a) => a.recentActivity).sort((a, b) => b.timestamp - a.timestamp).slice(0, 50),
|
|
455
461
|
sources: group.map((a) => a.agentId),
|
|
456
|
-
adapterSource: group[0].source
|
|
462
|
+
adapterSource: (_d = group[0]) == null ? void 0 : _d.source
|
|
457
463
|
};
|
|
458
464
|
merged.successRate = merged.totalExecutions > 0 ? merged.successfulExecutions / merged.totalExecutions * 100 : 0;
|
|
459
465
|
const totalExecTime = group.reduce((s, a) => s + a.avgExecutionTime * a.totalExecutions, 0);
|
|
@@ -869,7 +875,9 @@ var TraceWatcher = class _TraceWatcher extends EventEmitter {
|
|
|
869
875
|
...getSkipFiles(this.userConfig)
|
|
870
876
|
]);
|
|
871
877
|
this.userSkipDirs = new Set(getSkipDirectories(this.userConfig));
|
|
872
|
-
this.allWatchDirs = [
|
|
878
|
+
this.allWatchDirs = [
|
|
879
|
+
...new Set([this.tracesDir, ...this.dataDirs].map((d) => path.resolve(d)))
|
|
880
|
+
];
|
|
873
881
|
this.ensureTracesDir();
|
|
874
882
|
this.loadExistingFiles();
|
|
875
883
|
this.archiveOldTraces();
|
|
@@ -879,7 +887,7 @@ var TraceWatcher = class _TraceWatcher extends EventEmitter {
|
|
|
879
887
|
/** Move trace files older than maxAgeMs into archive/YYYY-MM/ subdirectories. */
|
|
880
888
|
archiveOldTraces() {
|
|
881
889
|
const cutoff = Date.now() - this.maxAgeMs;
|
|
882
|
-
|
|
890
|
+
const _archived = 0;
|
|
883
891
|
for (const dir of this.allWatchDirs) {
|
|
884
892
|
if (!fs.existsSync(dir)) continue;
|
|
885
893
|
try {
|
|
@@ -896,7 +904,8 @@ var TraceWatcher = class _TraceWatcher extends EventEmitter {
|
|
|
896
904
|
try {
|
|
897
905
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
898
906
|
for (const entry of entries) {
|
|
899
|
-
if (entry.name.startsWith(".") || entry.name === "archive" || this.userSkipDirs.has(entry.name))
|
|
907
|
+
if (entry.name.startsWith(".") || entry.name === "archive" || this.userSkipDirs.has(entry.name))
|
|
908
|
+
continue;
|
|
900
909
|
const fullPath = path.join(dir, entry.name);
|
|
901
910
|
if (entry.isDirectory()) {
|
|
902
911
|
archived += this.archiveDirectory(fullPath, cutoff, depth + 1);
|
|
@@ -2142,7 +2151,9 @@ import * as os from "os";
|
|
|
2142
2151
|
import * as path2 from "path";
|
|
2143
2152
|
import { fileURLToPath } from "url";
|
|
2144
2153
|
var __cliDirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
2145
|
-
var VERSION = JSON.parse(
|
|
2154
|
+
var VERSION = JSON.parse(
|
|
2155
|
+
fs2.readFileSync(path2.resolve(__cliDirname, "../package.json"), "utf-8")
|
|
2156
|
+
).version;
|
|
2146
2157
|
function getLanAddress() {
|
|
2147
2158
|
const interfaces = os.networkInterfaces();
|
|
2148
2159
|
for (const name of Object.keys(interfaces)) {
|
|
@@ -2399,6 +2410,17 @@ var DashboardServer = class {
|
|
|
2399
2410
|
userConfig;
|
|
2400
2411
|
configPath;
|
|
2401
2412
|
setupExpress() {
|
|
2413
|
+
this.app.use(
|
|
2414
|
+
"/api/",
|
|
2415
|
+
rateLimit({
|
|
2416
|
+
windowMs: 60 * 1e3,
|
|
2417
|
+
// 1 minute
|
|
2418
|
+
max: 300,
|
|
2419
|
+
// 300 requests per minute per IP
|
|
2420
|
+
standardHeaders: true,
|
|
2421
|
+
legacyHeaders: false
|
|
2422
|
+
})
|
|
2423
|
+
);
|
|
2402
2424
|
if (this.config.enableCors) {
|
|
2403
2425
|
this.app.use((_req, res, next) => {
|
|
2404
2426
|
res.header("Access-Control-Allow-Origin", "*");
|
|
@@ -2425,10 +2447,6 @@ var DashboardServer = class {
|
|
|
2425
2447
|
if (fs3.existsSync(clientDir)) {
|
|
2426
2448
|
this.app.use(express.static(clientDir));
|
|
2427
2449
|
}
|
|
2428
|
-
const pkgVersion = JSON.parse(fs3.readFileSync(path3.resolve(__dirname, "../package.json"), "utf-8")).version;
|
|
2429
|
-
this.app.get("/api/version", (_req, res) => {
|
|
2430
|
-
res.json({ version: pkgVersion });
|
|
2431
|
-
});
|
|
2432
2450
|
this.app.get("/api/traces", (req, res) => {
|
|
2433
2451
|
try {
|
|
2434
2452
|
const limit = Math.min(Math.max(parseInt(req.query.limit, 10) || 50, 1), 200);
|
|
@@ -2645,6 +2663,7 @@ var DashboardServer = class {
|
|
|
2645
2663
|
}
|
|
2646
2664
|
});
|
|
2647
2665
|
this.app.get("/api/process-model/:agentId", (req, res) => {
|
|
2666
|
+
var _a, _b;
|
|
2648
2667
|
try {
|
|
2649
2668
|
const agentId = req.params.agentId;
|
|
2650
2669
|
const allTraces = this.watcher.getTracesByAgent(agentId);
|
|
@@ -2662,8 +2681,8 @@ var DashboardServer = class {
|
|
|
2662
2681
|
const nodeArr = Object.values(nodes);
|
|
2663
2682
|
const sorted = nodeArr.filter((n) => n.name && typeof n.startTime === "number" && n.startTime > 0).sort((a, b) => (a.startTime ?? 0) - (b.startTime ?? 0));
|
|
2664
2683
|
for (let i = 0; i < sorted.length - 1; i++) {
|
|
2665
|
-
const from = sorted[i].name;
|
|
2666
|
-
const to = sorted[i + 1].name;
|
|
2684
|
+
const from = (_a = sorted[i]) == null ? void 0 : _a.name;
|
|
2685
|
+
const to = (_b = sorted[i + 1]) == null ? void 0 : _b.name;
|
|
2667
2686
|
const key = `${from}|||${to}`;
|
|
2668
2687
|
transMap.set(key, (transMap.get(key) ?? 0) + 1);
|
|
2669
2688
|
}
|
|
@@ -2762,7 +2781,11 @@ var DashboardServer = class {
|
|
|
2762
2781
|
try {
|
|
2763
2782
|
const reportPath = path3.join(somaVault, "..", "soma-report.json");
|
|
2764
2783
|
if (!fs3.existsSync(reportPath)) {
|
|
2765
|
-
return res.json({
|
|
2784
|
+
return res.json({
|
|
2785
|
+
available: false,
|
|
2786
|
+
teaser: false,
|
|
2787
|
+
message: "No report file yet. Run soma watch."
|
|
2788
|
+
});
|
|
2766
2789
|
}
|
|
2767
2790
|
const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
|
|
2768
2791
|
res.json(report);
|
|
@@ -2786,7 +2809,9 @@ var DashboardServer = class {
|
|
|
2786
2809
|
available: true,
|
|
2787
2810
|
layers: report.layers ?? { archive: 0, working: 0, emerging: 0, canon: 0 },
|
|
2788
2811
|
governance: report.governance ?? { pending: 0, promoted: 0, rejected: 0 },
|
|
2789
|
-
insights: (report.insights ?? []).filter(
|
|
2812
|
+
insights: (report.insights ?? []).filter(
|
|
2813
|
+
(i) => i.layer === "emerging" && i.proposal_status === "pending"
|
|
2814
|
+
),
|
|
2790
2815
|
canon: (report.insights ?? []).filter((i) => i.layer === "canon"),
|
|
2791
2816
|
generatedAt: report.generatedAt
|
|
2792
2817
|
});
|
|
@@ -2795,21 +2820,23 @@ var DashboardServer = class {
|
|
|
2795
2820
|
res.status(500).json({ available: false, message: "Failed to read governance data" });
|
|
2796
2821
|
}
|
|
2797
2822
|
});
|
|
2798
|
-
const
|
|
2799
|
-
const sanitizeReason = (s) => s.replace(/["`$\\]/g, "").slice(0, 500);
|
|
2823
|
+
const isValidId = (s) => /^[a-zA-Z0-9_\-.:]+$/.test(s);
|
|
2800
2824
|
this.app.post("/api/soma/governance/promote", (req, res) => {
|
|
2801
2825
|
var _a;
|
|
2802
2826
|
const somaVault = this.config.somaVault;
|
|
2803
2827
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2804
2828
|
const { entryId } = req.body ?? {};
|
|
2805
|
-
if (!entryId
|
|
2829
|
+
if (!entryId || !isValidId(String(entryId)))
|
|
2830
|
+
return res.status(400).json({ error: "Invalid entryId" });
|
|
2806
2831
|
try {
|
|
2807
|
-
const
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2832
|
+
const result = execFileSync(
|
|
2833
|
+
"npx",
|
|
2834
|
+
["soma", "governance", "promote", String(entryId), "--vault", somaVault],
|
|
2835
|
+
{
|
|
2836
|
+
encoding: "utf-8",
|
|
2837
|
+
timeout: 1e4
|
|
2838
|
+
}
|
|
2839
|
+
);
|
|
2813
2840
|
res.json({ success: true, message: result.trim() });
|
|
2814
2841
|
} catch (error) {
|
|
2815
2842
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2820,15 +2847,27 @@ var DashboardServer = class {
|
|
|
2820
2847
|
const somaVault = this.config.somaVault;
|
|
2821
2848
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2822
2849
|
const { entryId, reason } = req.body ?? {};
|
|
2823
|
-
if (!entryId || !
|
|
2850
|
+
if (!entryId || !isValidId(String(entryId)))
|
|
2851
|
+
return res.status(400).json({ error: "Invalid entryId" });
|
|
2852
|
+
if (!reason || typeof reason !== "string")
|
|
2853
|
+
return res.status(400).json({ error: "reason required" });
|
|
2824
2854
|
try {
|
|
2825
|
-
const
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2855
|
+
const result = execFileSync(
|
|
2856
|
+
"npx",
|
|
2857
|
+
[
|
|
2858
|
+
"soma",
|
|
2859
|
+
"governance",
|
|
2860
|
+
"reject",
|
|
2861
|
+
String(entryId),
|
|
2862
|
+
String(reason).slice(0, 500),
|
|
2863
|
+
"--vault",
|
|
2864
|
+
somaVault
|
|
2865
|
+
],
|
|
2866
|
+
{
|
|
2867
|
+
encoding: "utf-8",
|
|
2868
|
+
timeout: 1e4
|
|
2869
|
+
}
|
|
2870
|
+
);
|
|
2832
2871
|
res.json({ success: true, message: result.trim() });
|
|
2833
2872
|
} catch (error) {
|
|
2834
2873
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2838,13 +2877,16 @@ var DashboardServer = class {
|
|
|
2838
2877
|
var _a;
|
|
2839
2878
|
const somaVault = this.config.somaVault;
|
|
2840
2879
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2880
|
+
if (!isValidId(String(req.params.id))) return res.status(400).json({ error: "Invalid id" });
|
|
2841
2881
|
try {
|
|
2842
|
-
const
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2882
|
+
const result = execFileSync(
|
|
2883
|
+
"npx",
|
|
2884
|
+
["soma", "governance", "show", String(req.params.id), "--vault", somaVault],
|
|
2885
|
+
{
|
|
2886
|
+
encoding: "utf-8",
|
|
2887
|
+
timeout: 1e4
|
|
2888
|
+
}
|
|
2889
|
+
);
|
|
2848
2890
|
res.json({ available: true, output: result.trim() });
|
|
2849
2891
|
} catch (error) {
|
|
2850
2892
|
res.status(404).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2867,16 +2909,24 @@ var DashboardServer = class {
|
|
|
2867
2909
|
const somaVault = this.config.somaVault;
|
|
2868
2910
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2869
2911
|
const { name, enforcement, scope, conditions } = req.body ?? {};
|
|
2870
|
-
if (!name
|
|
2912
|
+
if (!name || !isValidId(String(name)))
|
|
2913
|
+
return res.status(400).json({ error: "Invalid policy name" });
|
|
2914
|
+
const enf = String(enforcement || "warn");
|
|
2915
|
+
if (!isValidId(enf)) return res.status(400).json({ error: "Invalid enforcement value" });
|
|
2871
2916
|
try {
|
|
2872
|
-
const
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2917
|
+
const args = [
|
|
2918
|
+
"soma",
|
|
2919
|
+
"policy",
|
|
2920
|
+
"create",
|
|
2921
|
+
String(name),
|
|
2922
|
+
"--enforcement",
|
|
2923
|
+
enf,
|
|
2924
|
+
"--vault",
|
|
2925
|
+
somaVault
|
|
2926
|
+
];
|
|
2927
|
+
if (scope) args.push("--scope", String(scope).slice(0, 500));
|
|
2928
|
+
if (conditions) args.push("--conditions", String(conditions).slice(0, 500));
|
|
2929
|
+
const result = execFileSync("npx", args, { encoding: "utf-8", timeout: 1e4 });
|
|
2880
2930
|
res.json({ success: true, message: result.trim() });
|
|
2881
2931
|
} catch (error) {
|
|
2882
2932
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2886,11 +2936,16 @@ var DashboardServer = class {
|
|
|
2886
2936
|
var _a;
|
|
2887
2937
|
const somaVault = this.config.somaVault;
|
|
2888
2938
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2939
|
+
if (!isValidId(String(req.params.name)))
|
|
2940
|
+
return res.status(400).json({ error: "Invalid policy name" });
|
|
2889
2941
|
try {
|
|
2890
|
-
const
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
{
|
|
2942
|
+
const result = execFileSync(
|
|
2943
|
+
"npx",
|
|
2944
|
+
["soma", "policy", "delete", String(req.params.name), "--vault", somaVault],
|
|
2945
|
+
{
|
|
2946
|
+
encoding: "utf-8",
|
|
2947
|
+
timeout: 1e4
|
|
2948
|
+
}
|
|
2894
2949
|
);
|
|
2895
2950
|
res.json({ success: true, message: result.trim() });
|
|
2896
2951
|
} catch (error) {
|
|
@@ -2908,16 +2963,28 @@ var DashboardServer = class {
|
|
|
2908
2963
|
...(report.agents ?? []).map((a) => ({ ...a, type: "agent", id: a.name })),
|
|
2909
2964
|
...(report.insights ?? []).map((i, idx) => {
|
|
2910
2965
|
var _a;
|
|
2911
|
-
return {
|
|
2966
|
+
return {
|
|
2967
|
+
...i,
|
|
2968
|
+
type: i.type || "insight",
|
|
2969
|
+
id: ((_a = i.title) == null ? void 0 : _a.replace(/\s+/g, "-").toLowerCase()) || `insight-${idx}`
|
|
2970
|
+
};
|
|
2912
2971
|
}),
|
|
2913
2972
|
...(report.policies ?? []).map((p) => ({ ...p, type: "policy", id: p.name }))
|
|
2914
2973
|
];
|
|
2915
|
-
const {
|
|
2974
|
+
const {
|
|
2975
|
+
type,
|
|
2976
|
+
layer,
|
|
2977
|
+
q,
|
|
2978
|
+
limit: limitStr,
|
|
2979
|
+
offset: offsetStr
|
|
2980
|
+
} = req.query;
|
|
2916
2981
|
if (type) entities = entities.filter((e) => e.type === type);
|
|
2917
2982
|
if (layer) entities = entities.filter((e) => e.layer === layer);
|
|
2918
2983
|
if (q) {
|
|
2919
2984
|
const lq = q.toLowerCase();
|
|
2920
|
-
entities = entities.filter(
|
|
2985
|
+
entities = entities.filter(
|
|
2986
|
+
(e) => (e.name || e.title || "").toLowerCase().includes(lq) || (e.claim || e.body || "").toLowerCase().includes(lq)
|
|
2987
|
+
);
|
|
2921
2988
|
}
|
|
2922
2989
|
const total = entities.length;
|
|
2923
2990
|
const offset = parseInt(offsetStr || "0", 10);
|
|
@@ -3008,9 +3075,7 @@ var DashboardServer = class {
|
|
|
3008
3075
|
const orphans = uniqueProcesses.filter(
|
|
3009
3076
|
(p) => !allKnownPids.has(p.pid) && p.pid !== process.pid && p.pid !== process.ppid
|
|
3010
3077
|
);
|
|
3011
|
-
const problems = services.flatMap(
|
|
3012
|
-
(s) => s.audit.problems.map((p) => `[${s.name}] ${p}`)
|
|
3013
|
-
);
|
|
3078
|
+
const problems = services.flatMap((s) => s.audit.problems.map((p) => `[${s.name}] ${p}`));
|
|
3014
3079
|
const result = {
|
|
3015
3080
|
// Backward-compatible fields from primary service
|
|
3016
3081
|
pidFile: (primary == null ? void 0 : primary.audit.pidFile) ?? null,
|
|
@@ -3065,19 +3130,24 @@ var DashboardServer = class {
|
|
|
3065
3130
|
}
|
|
3066
3131
|
} catch {
|
|
3067
3132
|
}
|
|
3068
|
-
const watched = [
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3133
|
+
const watched = [
|
|
3134
|
+
...new Set(
|
|
3135
|
+
[this.config.tracesDir, ...this.config.dataDirs || [], ...extraDirs].map(
|
|
3136
|
+
(w) => path3.resolve(w)
|
|
3137
|
+
)
|
|
3138
|
+
)
|
|
3139
|
+
];
|
|
3073
3140
|
const discovered = [];
|
|
3074
3141
|
const svcNames = getSystemdServices(this.userConfig);
|
|
3075
3142
|
if (svcNames.length > 0) {
|
|
3076
3143
|
try {
|
|
3077
|
-
const
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
{
|
|
3144
|
+
const raw = execFileSync(
|
|
3145
|
+
"systemctl",
|
|
3146
|
+
["--user", "show", "--property=ExecStart", "--no-pager", ...svcNames],
|
|
3147
|
+
{
|
|
3148
|
+
encoding: "utf8",
|
|
3149
|
+
timeout: 5e3
|
|
3150
|
+
}
|
|
3081
3151
|
);
|
|
3082
3152
|
for (const line of raw.split("\n")) {
|
|
3083
3153
|
const match = line.match(/path=([^\s;]+)/);
|
|
@@ -3109,10 +3179,19 @@ var DashboardServer = class {
|
|
|
3109
3179
|
this.app.post("/api/directories", express.json(), (req, res) => {
|
|
3110
3180
|
try {
|
|
3111
3181
|
const { add, remove } = req.body;
|
|
3112
|
-
if (add
|
|
3113
|
-
|
|
3182
|
+
if (add) {
|
|
3183
|
+
const resolved = path3.resolve(add);
|
|
3184
|
+
if (resolved !== add || add.includes("..")) {
|
|
3185
|
+
return res.status(400).json({ error: "Invalid directory path" });
|
|
3186
|
+
}
|
|
3187
|
+
if (!fs3.existsSync(resolved)) {
|
|
3188
|
+
return res.status(400).json({ error: `Directory does not exist: ${add}` });
|
|
3189
|
+
}
|
|
3114
3190
|
}
|
|
3115
|
-
const configPath = path3.join(
|
|
3191
|
+
const configPath = path3.join(
|
|
3192
|
+
process.env.HOME ?? "/home/trader",
|
|
3193
|
+
".agentflow/dashboard-config.json"
|
|
3194
|
+
);
|
|
3116
3195
|
let config = {};
|
|
3117
3196
|
try {
|
|
3118
3197
|
if (fs3.existsSync(configPath)) {
|
|
@@ -3322,13 +3401,31 @@ var DashboardServer = class {
|
|
|
3322
3401
|
isVirtual: false
|
|
3323
3402
|
});
|
|
3324
3403
|
}
|
|
3325
|
-
const
|
|
3326
|
-
const
|
|
3327
|
-
const
|
|
3328
|
-
for (const
|
|
3329
|
-
}
|
|
3330
|
-
nodes.push({
|
|
3331
|
-
|
|
3404
|
+
const _rootSteps = new Set(model.steps);
|
|
3405
|
+
const _childSteps = new Set(model.transitions.map((t) => t.to));
|
|
3406
|
+
const _leafSteps = new Set(model.steps);
|
|
3407
|
+
for (const _t of model.transitions) {
|
|
3408
|
+
}
|
|
3409
|
+
nodes.push({
|
|
3410
|
+
id: "[START]",
|
|
3411
|
+
label: "[START]",
|
|
3412
|
+
count: model.totalGraphs,
|
|
3413
|
+
frequency: 1,
|
|
3414
|
+
avgDuration: 0,
|
|
3415
|
+
failRate: 0,
|
|
3416
|
+
p95Duration: 0,
|
|
3417
|
+
isVirtual: true
|
|
3418
|
+
});
|
|
3419
|
+
nodes.push({
|
|
3420
|
+
id: "[END]",
|
|
3421
|
+
label: "[END]",
|
|
3422
|
+
count: model.totalGraphs,
|
|
3423
|
+
frequency: 1,
|
|
3424
|
+
avgDuration: 0,
|
|
3425
|
+
failRate: 0,
|
|
3426
|
+
p95Duration: 0,
|
|
3427
|
+
isVirtual: true
|
|
3428
|
+
});
|
|
3332
3429
|
const edges = model.transitions.map((t) => ({
|
|
3333
3430
|
source: t.from,
|
|
3334
3431
|
target: t.to,
|
|
@@ -3348,7 +3445,10 @@ var DashboardServer = class {
|
|
|
3348
3445
|
}
|
|
3349
3446
|
}
|
|
3350
3447
|
const maxEdgeCount = Math.max(...edges.map((e) => e.count), 1);
|
|
3351
|
-
const maxNodeCount = Math.max(
|
|
3448
|
+
const maxNodeCount = Math.max(
|
|
3449
|
+
...nodes.filter((n) => !n.isVirtual).map((n) => n.count),
|
|
3450
|
+
1
|
|
3451
|
+
);
|
|
3352
3452
|
return { agentId, totalTraces: model.totalGraphs, nodes, edges, maxEdgeCount, maxNodeCount };
|
|
3353
3453
|
}
|
|
3354
3454
|
/**
|