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
package/dist/client/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>AgentFlow Dashboard</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-DA9m90ZC.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BQBa4cES.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/dist/index.cjs
CHANGED
|
@@ -42,6 +42,11 @@ var fs3 = __toESM(require("fs"), 1);
|
|
|
42
42
|
var import_node_http = require("http");
|
|
43
43
|
var path3 = __toESM(require("path"), 1);
|
|
44
44
|
var import_node_url2 = require("url");
|
|
45
|
+
var import_agentflow_core3 = require("agentflow-core");
|
|
46
|
+
var import_chokidar2 = __toESM(require("chokidar"), 1);
|
|
47
|
+
var import_express = __toESM(require("express"), 1);
|
|
48
|
+
var import_express_rate_limit = __toESM(require("express-rate-limit"), 1);
|
|
49
|
+
var import_ws = require("ws");
|
|
45
50
|
|
|
46
51
|
// src/config.ts
|
|
47
52
|
var import_node_fs = require("fs");
|
|
@@ -114,12 +119,6 @@ function getProcessPreference(config) {
|
|
|
114
119
|
return config.processPreference ?? null;
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
// src/server.ts
|
|
118
|
-
var import_agentflow_core3 = require("agentflow-core");
|
|
119
|
-
var import_chokidar2 = __toESM(require("chokidar"), 1);
|
|
120
|
-
var import_express = __toESM(require("express"), 1);
|
|
121
|
-
var import_ws = require("ws");
|
|
122
|
-
|
|
123
122
|
// src/adapters/agentflow.ts
|
|
124
123
|
var SKIP_FILES = /* @__PURE__ */ new Set([
|
|
125
124
|
"workers.json",
|
|
@@ -131,7 +130,14 @@ var SKIP_FILES = /* @__PURE__ */ new Set([
|
|
|
131
130
|
"models.json",
|
|
132
131
|
"config.json"
|
|
133
132
|
]);
|
|
134
|
-
var SKIP_SUFFIXES = [
|
|
133
|
+
var SKIP_SUFFIXES = [
|
|
134
|
+
"-state.json",
|
|
135
|
+
"-config.json",
|
|
136
|
+
"-watch-state.json",
|
|
137
|
+
".tmp",
|
|
138
|
+
".bak",
|
|
139
|
+
".backup"
|
|
140
|
+
];
|
|
135
141
|
var AgentFlowAdapter = class {
|
|
136
142
|
name = "agentflow";
|
|
137
143
|
detect(_dirPath) {
|
|
@@ -408,8 +414,14 @@ registerAdapter(new AgentFlowAdapter());
|
|
|
408
414
|
var PURPOSE_KEYWORDS = [
|
|
409
415
|
{ keywords: ["email", "mail", "inbox", "smtp"], group: "Email Processors" },
|
|
410
416
|
{ keywords: ["monitor", "watch", "alert", "surveillance"], group: "Monitors" },
|
|
411
|
-
{
|
|
412
|
-
|
|
417
|
+
{
|
|
418
|
+
keywords: ["digest", "newsletter", "summary", "report", "briefing"],
|
|
419
|
+
group: "Digests & Reports"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
keywords: ["curator", "janitor", "distiller", "surveyor", "worker", "indexer"],
|
|
423
|
+
group: "Workers"
|
|
424
|
+
},
|
|
413
425
|
{ keywords: ["cron", "schedule", "timer", "periodic"], group: "Scheduled Jobs" },
|
|
414
426
|
{ keywords: ["search", "scrape", "crawl", "fetch"], group: "Data Collection" },
|
|
415
427
|
{ keywords: ["embed", "vector", "index"], group: "Embeddings" }
|
|
@@ -441,6 +453,7 @@ function capitalize(s) {
|
|
|
441
453
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
442
454
|
}
|
|
443
455
|
function deduplicateAgents(agents) {
|
|
456
|
+
var _a, _b, _c, _d;
|
|
444
457
|
const tagged = agents.map((a) => ({
|
|
445
458
|
...a,
|
|
446
459
|
...extractSource(a.agentId)
|
|
@@ -457,14 +470,14 @@ function deduplicateAgents(agents) {
|
|
|
457
470
|
const mergedIds = /* @__PURE__ */ new Set();
|
|
458
471
|
const mergedAgents = [];
|
|
459
472
|
for (const [_key, group] of suffixGroups) {
|
|
460
|
-
const suffix = extractSuffix(group[0].localId);
|
|
473
|
+
const suffix = extractSuffix((_a = group[0]) == null ? void 0 : _a.localId);
|
|
461
474
|
if (group.length < 2) continue;
|
|
462
475
|
const prefixes = new Set(group.map((a) => a.localId.split("-")[0]));
|
|
463
476
|
if (prefixes.size < 2) continue;
|
|
464
477
|
const longPrefixes = [...prefixes].filter((p) => p !== suffix && p.length > 2);
|
|
465
478
|
if (longPrefixes.length >= 2) continue;
|
|
466
479
|
const merged = {
|
|
467
|
-
agentId: group[0].source === "agentflow" ? suffix : `${group[0].source}:${suffix}`,
|
|
480
|
+
agentId: ((_b = group[0]) == null ? void 0 : _b.source) === "agentflow" ? suffix : `${(_c = group[0]) == null ? void 0 : _c.source}:${suffix}`,
|
|
468
481
|
displayName: suffix,
|
|
469
482
|
totalExecutions: group.reduce((s, a) => s + a.totalExecutions, 0),
|
|
470
483
|
successfulExecutions: group.reduce((s, a) => s + a.successfulExecutions, 0),
|
|
@@ -475,7 +488,7 @@ function deduplicateAgents(agents) {
|
|
|
475
488
|
triggers: {},
|
|
476
489
|
recentActivity: group.flatMap((a) => a.recentActivity).sort((a, b) => b.timestamp - a.timestamp).slice(0, 50),
|
|
477
490
|
sources: group.map((a) => a.agentId),
|
|
478
|
-
adapterSource: group[0].source
|
|
491
|
+
adapterSource: (_d = group[0]) == null ? void 0 : _d.source
|
|
479
492
|
};
|
|
480
493
|
merged.successRate = merged.totalExecutions > 0 ? merged.successfulExecutions / merged.totalExecutions * 100 : 0;
|
|
481
494
|
const totalExecTime = group.reduce((s, a) => s + a.avgExecutionTime * a.totalExecutions, 0);
|
|
@@ -891,7 +904,9 @@ var TraceWatcher = class _TraceWatcher extends import_node_events.EventEmitter {
|
|
|
891
904
|
...getSkipFiles(this.userConfig)
|
|
892
905
|
]);
|
|
893
906
|
this.userSkipDirs = new Set(getSkipDirectories(this.userConfig));
|
|
894
|
-
this.allWatchDirs = [
|
|
907
|
+
this.allWatchDirs = [
|
|
908
|
+
...new Set([this.tracesDir, ...this.dataDirs].map((d) => path.resolve(d)))
|
|
909
|
+
];
|
|
895
910
|
this.ensureTracesDir();
|
|
896
911
|
this.loadExistingFiles();
|
|
897
912
|
this.archiveOldTraces();
|
|
@@ -901,7 +916,7 @@ var TraceWatcher = class _TraceWatcher extends import_node_events.EventEmitter {
|
|
|
901
916
|
/** Move trace files older than maxAgeMs into archive/YYYY-MM/ subdirectories. */
|
|
902
917
|
archiveOldTraces() {
|
|
903
918
|
const cutoff = Date.now() - this.maxAgeMs;
|
|
904
|
-
|
|
919
|
+
const _archived = 0;
|
|
905
920
|
for (const dir of this.allWatchDirs) {
|
|
906
921
|
if (!fs.existsSync(dir)) continue;
|
|
907
922
|
try {
|
|
@@ -918,7 +933,8 @@ var TraceWatcher = class _TraceWatcher extends import_node_events.EventEmitter {
|
|
|
918
933
|
try {
|
|
919
934
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
920
935
|
for (const entry of entries) {
|
|
921
|
-
if (entry.name.startsWith(".") || entry.name === "archive" || this.userSkipDirs.has(entry.name))
|
|
936
|
+
if (entry.name.startsWith(".") || entry.name === "archive" || this.userSkipDirs.has(entry.name))
|
|
937
|
+
continue;
|
|
922
938
|
const fullPath = path.join(dir, entry.name);
|
|
923
939
|
if (entry.isDirectory()) {
|
|
924
940
|
archived += this.archiveDirectory(fullPath, cutoff, depth + 1);
|
|
@@ -2165,7 +2181,9 @@ var path2 = __toESM(require("path"), 1);
|
|
|
2165
2181
|
var import_node_url = require("url");
|
|
2166
2182
|
var import_meta = {};
|
|
2167
2183
|
var __cliDirname = path2.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
2168
|
-
var VERSION = JSON.parse(
|
|
2184
|
+
var VERSION = JSON.parse(
|
|
2185
|
+
fs2.readFileSync(path2.resolve(__cliDirname, "../package.json"), "utf-8")
|
|
2186
|
+
).version;
|
|
2169
2187
|
function getLanAddress() {
|
|
2170
2188
|
const interfaces = os.networkInterfaces();
|
|
2171
2189
|
for (const name of Object.keys(interfaces)) {
|
|
@@ -2423,6 +2441,17 @@ var DashboardServer = class {
|
|
|
2423
2441
|
userConfig;
|
|
2424
2442
|
configPath;
|
|
2425
2443
|
setupExpress() {
|
|
2444
|
+
this.app.use(
|
|
2445
|
+
"/api/",
|
|
2446
|
+
(0, import_express_rate_limit.default)({
|
|
2447
|
+
windowMs: 60 * 1e3,
|
|
2448
|
+
// 1 minute
|
|
2449
|
+
max: 300,
|
|
2450
|
+
// 300 requests per minute per IP
|
|
2451
|
+
standardHeaders: true,
|
|
2452
|
+
legacyHeaders: false
|
|
2453
|
+
})
|
|
2454
|
+
);
|
|
2426
2455
|
if (this.config.enableCors) {
|
|
2427
2456
|
this.app.use((_req, res, next) => {
|
|
2428
2457
|
res.header("Access-Control-Allow-Origin", "*");
|
|
@@ -2449,10 +2478,6 @@ var DashboardServer = class {
|
|
|
2449
2478
|
if (fs3.existsSync(clientDir)) {
|
|
2450
2479
|
this.app.use(import_express.default.static(clientDir));
|
|
2451
2480
|
}
|
|
2452
|
-
const pkgVersion = JSON.parse(fs3.readFileSync(path3.resolve(__dirname, "../package.json"), "utf-8")).version;
|
|
2453
|
-
this.app.get("/api/version", (_req, res) => {
|
|
2454
|
-
res.json({ version: pkgVersion });
|
|
2455
|
-
});
|
|
2456
2481
|
this.app.get("/api/traces", (req, res) => {
|
|
2457
2482
|
try {
|
|
2458
2483
|
const limit = Math.min(Math.max(parseInt(req.query.limit, 10) || 50, 1), 200);
|
|
@@ -2669,6 +2694,7 @@ var DashboardServer = class {
|
|
|
2669
2694
|
}
|
|
2670
2695
|
});
|
|
2671
2696
|
this.app.get("/api/process-model/:agentId", (req, res) => {
|
|
2697
|
+
var _a, _b;
|
|
2672
2698
|
try {
|
|
2673
2699
|
const agentId = req.params.agentId;
|
|
2674
2700
|
const allTraces = this.watcher.getTracesByAgent(agentId);
|
|
@@ -2686,8 +2712,8 @@ var DashboardServer = class {
|
|
|
2686
2712
|
const nodeArr = Object.values(nodes);
|
|
2687
2713
|
const sorted = nodeArr.filter((n) => n.name && typeof n.startTime === "number" && n.startTime > 0).sort((a, b) => (a.startTime ?? 0) - (b.startTime ?? 0));
|
|
2688
2714
|
for (let i = 0; i < sorted.length - 1; i++) {
|
|
2689
|
-
const from = sorted[i].name;
|
|
2690
|
-
const to = sorted[i + 1].name;
|
|
2715
|
+
const from = (_a = sorted[i]) == null ? void 0 : _a.name;
|
|
2716
|
+
const to = (_b = sorted[i + 1]) == null ? void 0 : _b.name;
|
|
2691
2717
|
const key = `${from}|||${to}`;
|
|
2692
2718
|
transMap.set(key, (transMap.get(key) ?? 0) + 1);
|
|
2693
2719
|
}
|
|
@@ -2786,7 +2812,11 @@ var DashboardServer = class {
|
|
|
2786
2812
|
try {
|
|
2787
2813
|
const reportPath = path3.join(somaVault, "..", "soma-report.json");
|
|
2788
2814
|
if (!fs3.existsSync(reportPath)) {
|
|
2789
|
-
return res.json({
|
|
2815
|
+
return res.json({
|
|
2816
|
+
available: false,
|
|
2817
|
+
teaser: false,
|
|
2818
|
+
message: "No report file yet. Run soma watch."
|
|
2819
|
+
});
|
|
2790
2820
|
}
|
|
2791
2821
|
const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
|
|
2792
2822
|
res.json(report);
|
|
@@ -2810,7 +2840,9 @@ var DashboardServer = class {
|
|
|
2810
2840
|
available: true,
|
|
2811
2841
|
layers: report.layers ?? { archive: 0, working: 0, emerging: 0, canon: 0 },
|
|
2812
2842
|
governance: report.governance ?? { pending: 0, promoted: 0, rejected: 0 },
|
|
2813
|
-
insights: (report.insights ?? []).filter(
|
|
2843
|
+
insights: (report.insights ?? []).filter(
|
|
2844
|
+
(i) => i.layer === "emerging" && i.proposal_status === "pending"
|
|
2845
|
+
),
|
|
2814
2846
|
canon: (report.insights ?? []).filter((i) => i.layer === "canon"),
|
|
2815
2847
|
generatedAt: report.generatedAt
|
|
2816
2848
|
});
|
|
@@ -2819,21 +2851,23 @@ var DashboardServer = class {
|
|
|
2819
2851
|
res.status(500).json({ available: false, message: "Failed to read governance data" });
|
|
2820
2852
|
}
|
|
2821
2853
|
});
|
|
2822
|
-
const
|
|
2823
|
-
const sanitizeReason = (s) => s.replace(/["`$\\]/g, "").slice(0, 500);
|
|
2854
|
+
const isValidId = (s) => /^[a-zA-Z0-9_\-.:]+$/.test(s);
|
|
2824
2855
|
this.app.post("/api/soma/governance/promote", (req, res) => {
|
|
2825
2856
|
var _a;
|
|
2826
2857
|
const somaVault = this.config.somaVault;
|
|
2827
2858
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2828
2859
|
const { entryId } = req.body ?? {};
|
|
2829
|
-
if (!entryId
|
|
2860
|
+
if (!entryId || !isValidId(String(entryId)))
|
|
2861
|
+
return res.status(400).json({ error: "Invalid entryId" });
|
|
2830
2862
|
try {
|
|
2831
|
-
const
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2863
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
2864
|
+
"npx",
|
|
2865
|
+
["soma", "governance", "promote", String(entryId), "--vault", somaVault],
|
|
2866
|
+
{
|
|
2867
|
+
encoding: "utf-8",
|
|
2868
|
+
timeout: 1e4
|
|
2869
|
+
}
|
|
2870
|
+
);
|
|
2837
2871
|
res.json({ success: true, message: result.trim() });
|
|
2838
2872
|
} catch (error) {
|
|
2839
2873
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2844,15 +2878,27 @@ var DashboardServer = class {
|
|
|
2844
2878
|
const somaVault = this.config.somaVault;
|
|
2845
2879
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2846
2880
|
const { entryId, reason } = req.body ?? {};
|
|
2847
|
-
if (!entryId || !
|
|
2881
|
+
if (!entryId || !isValidId(String(entryId)))
|
|
2882
|
+
return res.status(400).json({ error: "Invalid entryId" });
|
|
2883
|
+
if (!reason || typeof reason !== "string")
|
|
2884
|
+
return res.status(400).json({ error: "reason required" });
|
|
2848
2885
|
try {
|
|
2849
|
-
const
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2886
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
2887
|
+
"npx",
|
|
2888
|
+
[
|
|
2889
|
+
"soma",
|
|
2890
|
+
"governance",
|
|
2891
|
+
"reject",
|
|
2892
|
+
String(entryId),
|
|
2893
|
+
String(reason).slice(0, 500),
|
|
2894
|
+
"--vault",
|
|
2895
|
+
somaVault
|
|
2896
|
+
],
|
|
2897
|
+
{
|
|
2898
|
+
encoding: "utf-8",
|
|
2899
|
+
timeout: 1e4
|
|
2900
|
+
}
|
|
2901
|
+
);
|
|
2856
2902
|
res.json({ success: true, message: result.trim() });
|
|
2857
2903
|
} catch (error) {
|
|
2858
2904
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2862,13 +2908,16 @@ var DashboardServer = class {
|
|
|
2862
2908
|
var _a;
|
|
2863
2909
|
const somaVault = this.config.somaVault;
|
|
2864
2910
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2911
|
+
if (!isValidId(String(req.params.id))) return res.status(400).json({ error: "Invalid id" });
|
|
2865
2912
|
try {
|
|
2866
|
-
const
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2913
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
2914
|
+
"npx",
|
|
2915
|
+
["soma", "governance", "show", String(req.params.id), "--vault", somaVault],
|
|
2916
|
+
{
|
|
2917
|
+
encoding: "utf-8",
|
|
2918
|
+
timeout: 1e4
|
|
2919
|
+
}
|
|
2920
|
+
);
|
|
2872
2921
|
res.json({ available: true, output: result.trim() });
|
|
2873
2922
|
} catch (error) {
|
|
2874
2923
|
res.status(404).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2891,16 +2940,24 @@ var DashboardServer = class {
|
|
|
2891
2940
|
const somaVault = this.config.somaVault;
|
|
2892
2941
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2893
2942
|
const { name, enforcement, scope, conditions } = req.body ?? {};
|
|
2894
|
-
if (!name
|
|
2943
|
+
if (!name || !isValidId(String(name)))
|
|
2944
|
+
return res.status(400).json({ error: "Invalid policy name" });
|
|
2945
|
+
const enf = String(enforcement || "warn");
|
|
2946
|
+
if (!isValidId(enf)) return res.status(400).json({ error: "Invalid enforcement value" });
|
|
2895
2947
|
try {
|
|
2896
|
-
const
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2948
|
+
const args = [
|
|
2949
|
+
"soma",
|
|
2950
|
+
"policy",
|
|
2951
|
+
"create",
|
|
2952
|
+
String(name),
|
|
2953
|
+
"--enforcement",
|
|
2954
|
+
enf,
|
|
2955
|
+
"--vault",
|
|
2956
|
+
somaVault
|
|
2957
|
+
];
|
|
2958
|
+
if (scope) args.push("--scope", String(scope).slice(0, 500));
|
|
2959
|
+
if (conditions) args.push("--conditions", String(conditions).slice(0, 500));
|
|
2960
|
+
const result = (0, import_node_child_process.execFileSync)("npx", args, { encoding: "utf-8", timeout: 1e4 });
|
|
2904
2961
|
res.json({ success: true, message: result.trim() });
|
|
2905
2962
|
} catch (error) {
|
|
2906
2963
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2910,11 +2967,16 @@ var DashboardServer = class {
|
|
|
2910
2967
|
var _a;
|
|
2911
2968
|
const somaVault = this.config.somaVault;
|
|
2912
2969
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2970
|
+
if (!isValidId(String(req.params.name)))
|
|
2971
|
+
return res.status(400).json({ error: "Invalid policy name" });
|
|
2913
2972
|
try {
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
{
|
|
2973
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
2974
|
+
"npx",
|
|
2975
|
+
["soma", "policy", "delete", String(req.params.name), "--vault", somaVault],
|
|
2976
|
+
{
|
|
2977
|
+
encoding: "utf-8",
|
|
2978
|
+
timeout: 1e4
|
|
2979
|
+
}
|
|
2918
2980
|
);
|
|
2919
2981
|
res.json({ success: true, message: result.trim() });
|
|
2920
2982
|
} catch (error) {
|
|
@@ -2932,16 +2994,28 @@ var DashboardServer = class {
|
|
|
2932
2994
|
...(report.agents ?? []).map((a) => ({ ...a, type: "agent", id: a.name })),
|
|
2933
2995
|
...(report.insights ?? []).map((i, idx) => {
|
|
2934
2996
|
var _a;
|
|
2935
|
-
return {
|
|
2997
|
+
return {
|
|
2998
|
+
...i,
|
|
2999
|
+
type: i.type || "insight",
|
|
3000
|
+
id: ((_a = i.title) == null ? void 0 : _a.replace(/\s+/g, "-").toLowerCase()) || `insight-${idx}`
|
|
3001
|
+
};
|
|
2936
3002
|
}),
|
|
2937
3003
|
...(report.policies ?? []).map((p) => ({ ...p, type: "policy", id: p.name }))
|
|
2938
3004
|
];
|
|
2939
|
-
const {
|
|
3005
|
+
const {
|
|
3006
|
+
type,
|
|
3007
|
+
layer,
|
|
3008
|
+
q,
|
|
3009
|
+
limit: limitStr,
|
|
3010
|
+
offset: offsetStr
|
|
3011
|
+
} = req.query;
|
|
2940
3012
|
if (type) entities = entities.filter((e) => e.type === type);
|
|
2941
3013
|
if (layer) entities = entities.filter((e) => e.layer === layer);
|
|
2942
3014
|
if (q) {
|
|
2943
3015
|
const lq = q.toLowerCase();
|
|
2944
|
-
entities = entities.filter(
|
|
3016
|
+
entities = entities.filter(
|
|
3017
|
+
(e) => (e.name || e.title || "").toLowerCase().includes(lq) || (e.claim || e.body || "").toLowerCase().includes(lq)
|
|
3018
|
+
);
|
|
2945
3019
|
}
|
|
2946
3020
|
const total = entities.length;
|
|
2947
3021
|
const offset = parseInt(offsetStr || "0", 10);
|
|
@@ -3032,9 +3106,7 @@ var DashboardServer = class {
|
|
|
3032
3106
|
const orphans = uniqueProcesses.filter(
|
|
3033
3107
|
(p) => !allKnownPids.has(p.pid) && p.pid !== process.pid && p.pid !== process.ppid
|
|
3034
3108
|
);
|
|
3035
|
-
const problems = services.flatMap(
|
|
3036
|
-
(s) => s.audit.problems.map((p) => `[${s.name}] ${p}`)
|
|
3037
|
-
);
|
|
3109
|
+
const problems = services.flatMap((s) => s.audit.problems.map((p) => `[${s.name}] ${p}`));
|
|
3038
3110
|
const result = {
|
|
3039
3111
|
// Backward-compatible fields from primary service
|
|
3040
3112
|
pidFile: (primary == null ? void 0 : primary.audit.pidFile) ?? null,
|
|
@@ -3089,19 +3161,24 @@ var DashboardServer = class {
|
|
|
3089
3161
|
}
|
|
3090
3162
|
} catch {
|
|
3091
3163
|
}
|
|
3092
|
-
const watched = [
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3164
|
+
const watched = [
|
|
3165
|
+
...new Set(
|
|
3166
|
+
[this.config.tracesDir, ...this.config.dataDirs || [], ...extraDirs].map(
|
|
3167
|
+
(w) => path3.resolve(w)
|
|
3168
|
+
)
|
|
3169
|
+
)
|
|
3170
|
+
];
|
|
3097
3171
|
const discovered = [];
|
|
3098
3172
|
const svcNames = getSystemdServices(this.userConfig);
|
|
3099
3173
|
if (svcNames.length > 0) {
|
|
3100
3174
|
try {
|
|
3101
|
-
const
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
{
|
|
3175
|
+
const raw = (0, import_node_child_process.execFileSync)(
|
|
3176
|
+
"systemctl",
|
|
3177
|
+
["--user", "show", "--property=ExecStart", "--no-pager", ...svcNames],
|
|
3178
|
+
{
|
|
3179
|
+
encoding: "utf8",
|
|
3180
|
+
timeout: 5e3
|
|
3181
|
+
}
|
|
3105
3182
|
);
|
|
3106
3183
|
for (const line of raw.split("\n")) {
|
|
3107
3184
|
const match = line.match(/path=([^\s;]+)/);
|
|
@@ -3133,10 +3210,19 @@ var DashboardServer = class {
|
|
|
3133
3210
|
this.app.post("/api/directories", import_express.default.json(), (req, res) => {
|
|
3134
3211
|
try {
|
|
3135
3212
|
const { add, remove } = req.body;
|
|
3136
|
-
if (add
|
|
3137
|
-
|
|
3213
|
+
if (add) {
|
|
3214
|
+
const resolved = path3.resolve(add);
|
|
3215
|
+
if (resolved !== add || add.includes("..")) {
|
|
3216
|
+
return res.status(400).json({ error: "Invalid directory path" });
|
|
3217
|
+
}
|
|
3218
|
+
if (!fs3.existsSync(resolved)) {
|
|
3219
|
+
return res.status(400).json({ error: `Directory does not exist: ${add}` });
|
|
3220
|
+
}
|
|
3138
3221
|
}
|
|
3139
|
-
const configPath = path3.join(
|
|
3222
|
+
const configPath = path3.join(
|
|
3223
|
+
process.env.HOME ?? "/home/trader",
|
|
3224
|
+
".agentflow/dashboard-config.json"
|
|
3225
|
+
);
|
|
3140
3226
|
let config = {};
|
|
3141
3227
|
try {
|
|
3142
3228
|
if (fs3.existsSync(configPath)) {
|
|
@@ -3346,13 +3432,31 @@ var DashboardServer = class {
|
|
|
3346
3432
|
isVirtual: false
|
|
3347
3433
|
});
|
|
3348
3434
|
}
|
|
3349
|
-
const
|
|
3350
|
-
const
|
|
3351
|
-
const
|
|
3352
|
-
for (const
|
|
3353
|
-
}
|
|
3354
|
-
nodes.push({
|
|
3355
|
-
|
|
3435
|
+
const _rootSteps = new Set(model.steps);
|
|
3436
|
+
const _childSteps = new Set(model.transitions.map((t) => t.to));
|
|
3437
|
+
const _leafSteps = new Set(model.steps);
|
|
3438
|
+
for (const _t of model.transitions) {
|
|
3439
|
+
}
|
|
3440
|
+
nodes.push({
|
|
3441
|
+
id: "[START]",
|
|
3442
|
+
label: "[START]",
|
|
3443
|
+
count: model.totalGraphs,
|
|
3444
|
+
frequency: 1,
|
|
3445
|
+
avgDuration: 0,
|
|
3446
|
+
failRate: 0,
|
|
3447
|
+
p95Duration: 0,
|
|
3448
|
+
isVirtual: true
|
|
3449
|
+
});
|
|
3450
|
+
nodes.push({
|
|
3451
|
+
id: "[END]",
|
|
3452
|
+
label: "[END]",
|
|
3453
|
+
count: model.totalGraphs,
|
|
3454
|
+
frequency: 1,
|
|
3455
|
+
avgDuration: 0,
|
|
3456
|
+
failRate: 0,
|
|
3457
|
+
p95Duration: 0,
|
|
3458
|
+
isVirtual: true
|
|
3459
|
+
});
|
|
3356
3460
|
const edges = model.transitions.map((t) => ({
|
|
3357
3461
|
source: t.from,
|
|
3358
3462
|
target: t.to,
|
|
@@ -3372,7 +3476,10 @@ var DashboardServer = class {
|
|
|
3372
3476
|
}
|
|
3373
3477
|
}
|
|
3374
3478
|
const maxEdgeCount = Math.max(...edges.map((e) => e.count), 1);
|
|
3375
|
-
const maxNodeCount = Math.max(
|
|
3479
|
+
const maxNodeCount = Math.max(
|
|
3480
|
+
...nodes.filter((n) => !n.isVirtual).map((n) => n.count),
|
|
3481
|
+
1
|
|
3482
|
+
);
|
|
3376
3483
|
return { agentId, totalTraces: model.totalGraphs, nodes, edges, maxEdgeCount, maxNodeCount };
|
|
3377
3484
|
}
|
|
3378
3485
|
/**
|