agentflow-dashboard 0.8.3 → 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-E5RJCBK2.js → chunk-YLQ5MVCW.js} +204 -100
- package/dist/cli.cjs +193 -82
- package/dist/cli.js +1 -1
- package/dist/client/assets/index-BQBa4cES.css +1 -0
- package/dist/client/assets/{index-BgEw2MGK.js → index-DA9m90ZC.js} +7 -7
- package/dist/client/index.html +2 -2
- package/dist/index.cjs +193 -82
- package/dist/index.js +1 -1
- package/dist/server.cjs +193 -82
- 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", "*");
|
|
@@ -2665,6 +2694,7 @@ var DashboardServer = class {
|
|
|
2665
2694
|
}
|
|
2666
2695
|
});
|
|
2667
2696
|
this.app.get("/api/process-model/:agentId", (req, res) => {
|
|
2697
|
+
var _a, _b;
|
|
2668
2698
|
try {
|
|
2669
2699
|
const agentId = req.params.agentId;
|
|
2670
2700
|
const allTraces = this.watcher.getTracesByAgent(agentId);
|
|
@@ -2682,8 +2712,8 @@ var DashboardServer = class {
|
|
|
2682
2712
|
const nodeArr = Object.values(nodes);
|
|
2683
2713
|
const sorted = nodeArr.filter((n) => n.name && typeof n.startTime === "number" && n.startTime > 0).sort((a, b) => (a.startTime ?? 0) - (b.startTime ?? 0));
|
|
2684
2714
|
for (let i = 0; i < sorted.length - 1; i++) {
|
|
2685
|
-
const from = sorted[i].name;
|
|
2686
|
-
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;
|
|
2687
2717
|
const key = `${from}|||${to}`;
|
|
2688
2718
|
transMap.set(key, (transMap.get(key) ?? 0) + 1);
|
|
2689
2719
|
}
|
|
@@ -2782,7 +2812,11 @@ var DashboardServer = class {
|
|
|
2782
2812
|
try {
|
|
2783
2813
|
const reportPath = path3.join(somaVault, "..", "soma-report.json");
|
|
2784
2814
|
if (!fs3.existsSync(reportPath)) {
|
|
2785
|
-
return res.json({
|
|
2815
|
+
return res.json({
|
|
2816
|
+
available: false,
|
|
2817
|
+
teaser: false,
|
|
2818
|
+
message: "No report file yet. Run soma watch."
|
|
2819
|
+
});
|
|
2786
2820
|
}
|
|
2787
2821
|
const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
|
|
2788
2822
|
res.json(report);
|
|
@@ -2806,7 +2840,9 @@ var DashboardServer = class {
|
|
|
2806
2840
|
available: true,
|
|
2807
2841
|
layers: report.layers ?? { archive: 0, working: 0, emerging: 0, canon: 0 },
|
|
2808
2842
|
governance: report.governance ?? { pending: 0, promoted: 0, rejected: 0 },
|
|
2809
|
-
insights: (report.insights ?? []).filter(
|
|
2843
|
+
insights: (report.insights ?? []).filter(
|
|
2844
|
+
(i) => i.layer === "emerging" && i.proposal_status === "pending"
|
|
2845
|
+
),
|
|
2810
2846
|
canon: (report.insights ?? []).filter((i) => i.layer === "canon"),
|
|
2811
2847
|
generatedAt: report.generatedAt
|
|
2812
2848
|
});
|
|
@@ -2815,21 +2851,23 @@ var DashboardServer = class {
|
|
|
2815
2851
|
res.status(500).json({ available: false, message: "Failed to read governance data" });
|
|
2816
2852
|
}
|
|
2817
2853
|
});
|
|
2818
|
-
const
|
|
2819
|
-
const sanitizeReason = (s) => s.replace(/["`$\\]/g, "").slice(0, 500);
|
|
2854
|
+
const isValidId = (s) => /^[a-zA-Z0-9_\-.:]+$/.test(s);
|
|
2820
2855
|
this.app.post("/api/soma/governance/promote", (req, res) => {
|
|
2821
2856
|
var _a;
|
|
2822
2857
|
const somaVault = this.config.somaVault;
|
|
2823
2858
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2824
2859
|
const { entryId } = req.body ?? {};
|
|
2825
|
-
if (!entryId
|
|
2860
|
+
if (!entryId || !isValidId(String(entryId)))
|
|
2861
|
+
return res.status(400).json({ error: "Invalid entryId" });
|
|
2826
2862
|
try {
|
|
2827
|
-
const
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
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
|
+
);
|
|
2833
2871
|
res.json({ success: true, message: result.trim() });
|
|
2834
2872
|
} catch (error) {
|
|
2835
2873
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2840,15 +2878,27 @@ var DashboardServer = class {
|
|
|
2840
2878
|
const somaVault = this.config.somaVault;
|
|
2841
2879
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2842
2880
|
const { entryId, reason } = req.body ?? {};
|
|
2843
|
-
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" });
|
|
2844
2885
|
try {
|
|
2845
|
-
const
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
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
|
+
);
|
|
2852
2902
|
res.json({ success: true, message: result.trim() });
|
|
2853
2903
|
} catch (error) {
|
|
2854
2904
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2858,13 +2908,16 @@ var DashboardServer = class {
|
|
|
2858
2908
|
var _a;
|
|
2859
2909
|
const somaVault = this.config.somaVault;
|
|
2860
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" });
|
|
2861
2912
|
try {
|
|
2862
|
-
const
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
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
|
+
);
|
|
2868
2921
|
res.json({ available: true, output: result.trim() });
|
|
2869
2922
|
} catch (error) {
|
|
2870
2923
|
res.status(404).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2887,16 +2940,24 @@ var DashboardServer = class {
|
|
|
2887
2940
|
const somaVault = this.config.somaVault;
|
|
2888
2941
|
if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
|
|
2889
2942
|
const { name, enforcement, scope, conditions } = req.body ?? {};
|
|
2890
|
-
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" });
|
|
2891
2947
|
try {
|
|
2892
|
-
const
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
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 });
|
|
2900
2961
|
res.json({ success: true, message: result.trim() });
|
|
2901
2962
|
} catch (error) {
|
|
2902
2963
|
res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
|
|
@@ -2906,11 +2967,16 @@ var DashboardServer = class {
|
|
|
2906
2967
|
var _a;
|
|
2907
2968
|
const somaVault = this.config.somaVault;
|
|
2908
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" });
|
|
2909
2972
|
try {
|
|
2910
|
-
const
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
{
|
|
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
|
+
}
|
|
2914
2980
|
);
|
|
2915
2981
|
res.json({ success: true, message: result.trim() });
|
|
2916
2982
|
} catch (error) {
|
|
@@ -2928,16 +2994,28 @@ var DashboardServer = class {
|
|
|
2928
2994
|
...(report.agents ?? []).map((a) => ({ ...a, type: "agent", id: a.name })),
|
|
2929
2995
|
...(report.insights ?? []).map((i, idx) => {
|
|
2930
2996
|
var _a;
|
|
2931
|
-
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
|
+
};
|
|
2932
3002
|
}),
|
|
2933
3003
|
...(report.policies ?? []).map((p) => ({ ...p, type: "policy", id: p.name }))
|
|
2934
3004
|
];
|
|
2935
|
-
const {
|
|
3005
|
+
const {
|
|
3006
|
+
type,
|
|
3007
|
+
layer,
|
|
3008
|
+
q,
|
|
3009
|
+
limit: limitStr,
|
|
3010
|
+
offset: offsetStr
|
|
3011
|
+
} = req.query;
|
|
2936
3012
|
if (type) entities = entities.filter((e) => e.type === type);
|
|
2937
3013
|
if (layer) entities = entities.filter((e) => e.layer === layer);
|
|
2938
3014
|
if (q) {
|
|
2939
3015
|
const lq = q.toLowerCase();
|
|
2940
|
-
entities = entities.filter(
|
|
3016
|
+
entities = entities.filter(
|
|
3017
|
+
(e) => (e.name || e.title || "").toLowerCase().includes(lq) || (e.claim || e.body || "").toLowerCase().includes(lq)
|
|
3018
|
+
);
|
|
2941
3019
|
}
|
|
2942
3020
|
const total = entities.length;
|
|
2943
3021
|
const offset = parseInt(offsetStr || "0", 10);
|
|
@@ -3028,9 +3106,7 @@ var DashboardServer = class {
|
|
|
3028
3106
|
const orphans = uniqueProcesses.filter(
|
|
3029
3107
|
(p) => !allKnownPids.has(p.pid) && p.pid !== process.pid && p.pid !== process.ppid
|
|
3030
3108
|
);
|
|
3031
|
-
const problems = services.flatMap(
|
|
3032
|
-
(s) => s.audit.problems.map((p) => `[${s.name}] ${p}`)
|
|
3033
|
-
);
|
|
3109
|
+
const problems = services.flatMap((s) => s.audit.problems.map((p) => `[${s.name}] ${p}`));
|
|
3034
3110
|
const result = {
|
|
3035
3111
|
// Backward-compatible fields from primary service
|
|
3036
3112
|
pidFile: (primary == null ? void 0 : primary.audit.pidFile) ?? null,
|
|
@@ -3085,19 +3161,24 @@ var DashboardServer = class {
|
|
|
3085
3161
|
}
|
|
3086
3162
|
} catch {
|
|
3087
3163
|
}
|
|
3088
|
-
const watched = [
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3164
|
+
const watched = [
|
|
3165
|
+
...new Set(
|
|
3166
|
+
[this.config.tracesDir, ...this.config.dataDirs || [], ...extraDirs].map(
|
|
3167
|
+
(w) => path3.resolve(w)
|
|
3168
|
+
)
|
|
3169
|
+
)
|
|
3170
|
+
];
|
|
3093
3171
|
const discovered = [];
|
|
3094
3172
|
const svcNames = getSystemdServices(this.userConfig);
|
|
3095
3173
|
if (svcNames.length > 0) {
|
|
3096
3174
|
try {
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
{
|
|
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
|
+
}
|
|
3101
3182
|
);
|
|
3102
3183
|
for (const line of raw.split("\n")) {
|
|
3103
3184
|
const match = line.match(/path=([^\s;]+)/);
|
|
@@ -3129,10 +3210,19 @@ var DashboardServer = class {
|
|
|
3129
3210
|
this.app.post("/api/directories", import_express.default.json(), (req, res) => {
|
|
3130
3211
|
try {
|
|
3131
3212
|
const { add, remove } = req.body;
|
|
3132
|
-
if (add
|
|
3133
|
-
|
|
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
|
+
}
|
|
3134
3221
|
}
|
|
3135
|
-
const configPath = path3.join(
|
|
3222
|
+
const configPath = path3.join(
|
|
3223
|
+
process.env.HOME ?? "/home/trader",
|
|
3224
|
+
".agentflow/dashboard-config.json"
|
|
3225
|
+
);
|
|
3136
3226
|
let config = {};
|
|
3137
3227
|
try {
|
|
3138
3228
|
if (fs3.existsSync(configPath)) {
|
|
@@ -3342,13 +3432,31 @@ var DashboardServer = class {
|
|
|
3342
3432
|
isVirtual: false
|
|
3343
3433
|
});
|
|
3344
3434
|
}
|
|
3345
|
-
const
|
|
3346
|
-
const
|
|
3347
|
-
const
|
|
3348
|
-
for (const
|
|
3349
|
-
}
|
|
3350
|
-
nodes.push({
|
|
3351
|
-
|
|
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
|
+
});
|
|
3352
3460
|
const edges = model.transitions.map((t) => ({
|
|
3353
3461
|
source: t.from,
|
|
3354
3462
|
target: t.to,
|
|
@@ -3368,7 +3476,10 @@ var DashboardServer = class {
|
|
|
3368
3476
|
}
|
|
3369
3477
|
}
|
|
3370
3478
|
const maxEdgeCount = Math.max(...edges.map((e) => e.count), 1);
|
|
3371
|
-
const maxNodeCount = Math.max(
|
|
3479
|
+
const maxNodeCount = Math.max(
|
|
3480
|
+
...nodes.filter((n) => !n.isVirtual).map((n) => n.count),
|
|
3481
|
+
1
|
|
3482
|
+
);
|
|
3372
3483
|
return { agentId, totalTraces: model.totalGraphs, nodes, edges, maxEdgeCount, maxNodeCount };
|
|
3373
3484
|
}
|
|
3374
3485
|
/**
|