agentflow-dashboard 0.8.0 → 0.8.1

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.
@@ -94,6 +94,7 @@ import {
94
94
  getBottlenecks,
95
95
  loadGraph as loadGraph2
96
96
  } from "agentflow-core";
97
+ import chokidar2 from "chokidar";
97
98
  import express from "express";
98
99
  import { WebSocketServer } from "ws";
99
100
 
@@ -868,7 +869,7 @@ var TraceWatcher = class _TraceWatcher extends EventEmitter {
868
869
  ...getSkipFiles(this.userConfig)
869
870
  ]);
870
871
  this.userSkipDirs = new Set(getSkipDirectories(this.userConfig));
871
- this.allWatchDirs = [this.tracesDir, ...this.dataDirs];
872
+ this.allWatchDirs = [...new Set([this.tracesDir, ...this.dataDirs].map((d) => path.resolve(d)))];
872
873
  this.ensureTracesDir();
873
874
  this.loadExistingFiles();
874
875
  this.archiveOldTraces();
@@ -2172,7 +2173,9 @@ function printBanner(config, traceCount, stats, configPath) {
2172
2173
  \u2192 http://localhost:${port}${isPublic && lan ? `
2173
2174
  \u2192 http://${lan}:${port} (LAN)` : ""}
2174
2175
 
2175
- Views: Agent Profile \xB7 Execution Detail \xB7 Governance
2176
+ Pages: Agents \xB7 SOMA
2177
+ Agent: Profile \xB7 Execution Detail
2178
+ SOMA: Intelligence \xB7 Review \xB7 Policies \xB7 Knowledge \xB7 Activity
2176
2179
  Tabs: Flame Chart \xB7 Agent Flow \xB7 Metrics \xB7 Dependencies
2177
2180
  State Machine \xB7 Summary \xB7 Transcript
2178
2181
 
@@ -2357,6 +2360,7 @@ var DashboardServer = class {
2357
2360
  this.setupExpress();
2358
2361
  this.setupWebSocket();
2359
2362
  this.setupTraceWatcher();
2363
+ this.setupSomaReportWatcher();
2360
2364
  let knowledgeCount = 0;
2361
2365
  for (const trace of this.watcher.getAllTraces()) {
2362
2366
  this.stats.processTrace(trace);
@@ -2715,6 +2719,27 @@ var DashboardServer = class {
2715
2719
  res.status(500).json({ error: "Failed to load agent statistics" });
2716
2720
  }
2717
2721
  });
2722
+ this.app.get("/api/soma/tier", (_req, res) => {
2723
+ const somaVault = this.config.somaVault;
2724
+ if (!somaVault) {
2725
+ return res.json({ tier: "teaser", somaVault: false, governanceAvailable: false });
2726
+ }
2727
+ try {
2728
+ const reportPath = path3.join(somaVault, "..", "soma-report.json");
2729
+ if (!fs3.existsSync(reportPath)) {
2730
+ return res.json({ tier: "free", somaVault: true, governanceAvailable: false });
2731
+ }
2732
+ const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
2733
+ const hasGovernance = report.governance && typeof report.governance.pending === "number";
2734
+ return res.json({
2735
+ tier: hasGovernance ? "pro" : "free",
2736
+ somaVault: true,
2737
+ governanceAvailable: !!hasGovernance
2738
+ });
2739
+ } catch {
2740
+ return res.json({ tier: "free", somaVault: true, governanceAvailable: false });
2741
+ }
2742
+ });
2718
2743
  this.app.get("/api/soma/report", (_req, res) => {
2719
2744
  const somaVault = this.config.somaVault;
2720
2745
  if (!somaVault) {
@@ -2811,6 +2836,118 @@ var DashboardServer = class {
2811
2836
  res.status(404).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
2812
2837
  }
2813
2838
  });
2839
+ this.app.get("/api/soma/policies", (_req, res) => {
2840
+ const somaVault = this.config.somaVault;
2841
+ if (!somaVault) return res.json({ policies: [] });
2842
+ try {
2843
+ const reportPath = path3.join(somaVault, "..", "soma-report.json");
2844
+ if (!fs3.existsSync(reportPath)) return res.json({ policies: [] });
2845
+ const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
2846
+ res.json({ policies: report.policies ?? [] });
2847
+ } catch {
2848
+ res.json({ policies: [] });
2849
+ }
2850
+ });
2851
+ this.app.post("/api/soma/policies", express.json(), (req, res) => {
2852
+ var _a;
2853
+ const somaVault = this.config.somaVault;
2854
+ if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
2855
+ const { name, enforcement, scope, conditions } = req.body ?? {};
2856
+ if (!name) return res.status(400).json({ error: "name required" });
2857
+ try {
2858
+ const safeName = sanitizeArg(String(name));
2859
+ const safeEnf = sanitizeArg(String(enforcement || "warn"));
2860
+ const safeScope = sanitizeReason(String(scope || "all"));
2861
+ const safeCond = sanitizeReason(String(conditions || ""));
2862
+ const result = execSync(
2863
+ `npx soma policy create "${safeName}" --enforcement ${safeEnf} --scope "${safeScope}" --conditions "${safeCond}" --vault "${somaVault}"`,
2864
+ { encoding: "utf-8", timeout: 1e4 }
2865
+ );
2866
+ res.json({ success: true, message: result.trim() });
2867
+ } catch (error) {
2868
+ res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
2869
+ }
2870
+ });
2871
+ this.app.delete("/api/soma/policies/:name", (req, res) => {
2872
+ var _a;
2873
+ const somaVault = this.config.somaVault;
2874
+ if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
2875
+ try {
2876
+ const safeName = sanitizeArg(String(req.params.name));
2877
+ const result = execSync(
2878
+ `npx soma policy delete "${safeName}" --vault "${somaVault}"`,
2879
+ { encoding: "utf-8", timeout: 1e4 }
2880
+ );
2881
+ res.json({ success: true, message: result.trim() });
2882
+ } catch (error) {
2883
+ res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
2884
+ }
2885
+ });
2886
+ this.app.get("/api/soma/vault/entities", (req, res) => {
2887
+ const somaVault = this.config.somaVault;
2888
+ if (!somaVault) return res.json({ entities: [], total: 0 });
2889
+ try {
2890
+ const reportPath = path3.join(somaVault, "..", "soma-report.json");
2891
+ if (!fs3.existsSync(reportPath)) return res.json({ entities: [], total: 0 });
2892
+ const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
2893
+ let entities = [
2894
+ ...(report.agents ?? []).map((a) => ({ ...a, type: "agent", id: a.name })),
2895
+ ...(report.insights ?? []).map((i, idx) => {
2896
+ var _a;
2897
+ return { ...i, type: i.type || "insight", id: ((_a = i.title) == null ? void 0 : _a.replace(/\s+/g, "-").toLowerCase()) || `insight-${idx}` };
2898
+ }),
2899
+ ...(report.policies ?? []).map((p) => ({ ...p, type: "policy", id: p.name }))
2900
+ ];
2901
+ const { type, layer, q, limit: limitStr, offset: offsetStr } = req.query;
2902
+ if (type) entities = entities.filter((e) => e.type === type);
2903
+ if (layer) entities = entities.filter((e) => e.layer === layer);
2904
+ if (q) {
2905
+ const lq = q.toLowerCase();
2906
+ entities = entities.filter((e) => (e.name || e.title || "").toLowerCase().includes(lq) || (e.claim || e.body || "").toLowerCase().includes(lq));
2907
+ }
2908
+ const total = entities.length;
2909
+ const offset = parseInt(offsetStr || "0", 10);
2910
+ const limit = Math.min(parseInt(limitStr || "50", 10), 200);
2911
+ entities = entities.slice(offset, offset + limit);
2912
+ res.json({ entities, total });
2913
+ } catch (error) {
2914
+ console.error("Vault entities error:", error);
2915
+ res.json({ entities: [], total: 0 });
2916
+ }
2917
+ });
2918
+ this.app.get("/api/soma/vault/entities/:type/:id", (req, res) => {
2919
+ const somaVault = this.config.somaVault;
2920
+ if (!somaVault) return res.status(404).json({ error: "Soma vault not configured" });
2921
+ try {
2922
+ const reportPath = path3.join(somaVault, "..", "soma-report.json");
2923
+ const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
2924
+ const { type, id } = req.params;
2925
+ let entity = null;
2926
+ if (type === "agent") {
2927
+ entity = (report.agents ?? []).find((a) => a.name === id);
2928
+ } else if (type === "policy") {
2929
+ entity = (report.policies ?? []).find((p) => p.name === id);
2930
+ } else {
2931
+ entity = (report.insights ?? []).find(
2932
+ (i) => {
2933
+ var _a;
2934
+ return (((_a = i.title) == null ? void 0 : _a.replace(/\s+/g, "-").toLowerCase()) || "") === id || i.title === id;
2935
+ }
2936
+ );
2937
+ }
2938
+ if (!entity) return res.status(404).json({ error: "Entity not found" });
2939
+ res.json({
2940
+ ...entity,
2941
+ type,
2942
+ id,
2943
+ body: entity.claim || entity.conditions || "",
2944
+ tags: entity.tags ?? [],
2945
+ related: entity.related ?? []
2946
+ });
2947
+ } catch {
2948
+ res.status(404).json({ error: "Entity not found" });
2949
+ }
2950
+ });
2814
2951
  this.app.get("/api/process-health", (_req, res) => {
2815
2952
  var _a, _b;
2816
2953
  try {
@@ -2914,11 +3051,11 @@ var DashboardServer = class {
2914
3051
  }
2915
3052
  } catch {
2916
3053
  }
2917
- const watched = [
3054
+ const watched = [...new Set([
2918
3055
  this.config.tracesDir,
2919
3056
  ...this.config.dataDirs || [],
2920
3057
  ...extraDirs
2921
- ];
3058
+ ].map((w) => path3.resolve(w)))];
2922
3059
  const discovered = [];
2923
3060
  const svcNames = getSystemdServices(this.userConfig);
2924
3061
  if (svcNames.length > 0) {
@@ -3072,6 +3209,41 @@ var DashboardServer = class {
3072
3209
  });
3073
3210
  });
3074
3211
  }
3212
+ /** Watch soma-report.json for changes and broadcast updates via WebSocket. */
3213
+ setupSomaReportWatcher() {
3214
+ const somaVault = this.config.somaVault;
3215
+ if (!somaVault) return;
3216
+ const reportPath = path3.join(somaVault, "..", "soma-report.json");
3217
+ const reportDir = path3.dirname(reportPath);
3218
+ if (!fs3.existsSync(reportDir)) return;
3219
+ let debounceTimer = null;
3220
+ const watcher = chokidar2.watch(reportPath, {
3221
+ ignoreInitial: true,
3222
+ persistent: true,
3223
+ awaitWriteFinish: { stabilityThreshold: 500 }
3224
+ });
3225
+ watcher.on("change", () => {
3226
+ if (debounceTimer) clearTimeout(debounceTimer);
3227
+ debounceTimer = setTimeout(() => {
3228
+ var _a, _b;
3229
+ try {
3230
+ const report = JSON.parse(fs3.readFileSync(reportPath, "utf-8"));
3231
+ this.broadcast({ type: "soma-report-updated", data: report });
3232
+ if (report.generatedAt) {
3233
+ this.broadcast({
3234
+ type: "soma-activity",
3235
+ data: {
3236
+ action: "report-updated",
3237
+ description: `Report updated: ${((_a = report.totals) == null ? void 0 : _a.agents) ?? 0} agents, ${((_b = report.totals) == null ? void 0 : _b.insights) ?? 0} insights`,
3238
+ timestamp: report.generatedAt
3239
+ }
3240
+ });
3241
+ }
3242
+ } catch {
3243
+ }
3244
+ }, 500);
3245
+ });
3246
+ }
3075
3247
  /**
3076
3248
  * Filter an agent's traces to valid ExecutionGraphs and convert via loadGraph().
3077
3249
  * Returns only traces with proper nodes (Map or non-empty object), skipping session-only traces.
package/dist/cli.cjs CHANGED
@@ -116,6 +116,7 @@ function getProcessPreference(config) {
116
116
 
117
117
  // src/server.ts
118
118
  var import_agentflow_core3 = require("agentflow-core");
119
+ var import_chokidar2 = __toESM(require("chokidar"), 1);
119
120
  var import_express = __toESM(require("express"), 1);
120
121
  var import_ws = require("ws");
121
122
 
@@ -890,7 +891,7 @@ var TraceWatcher = class _TraceWatcher extends import_node_events.EventEmitter {
890
891
  ...getSkipFiles(this.userConfig)
891
892
  ]);
892
893
  this.userSkipDirs = new Set(getSkipDirectories(this.userConfig));
893
- this.allWatchDirs = [this.tracesDir, ...this.dataDirs];
894
+ this.allWatchDirs = [...new Set([this.tracesDir, ...this.dataDirs].map((d) => path.resolve(d)))];
894
895
  this.ensureTracesDir();
895
896
  this.loadExistingFiles();
896
897
  this.archiveOldTraces();
@@ -2202,6 +2203,7 @@ var DashboardServer = class {
2202
2203
  this.setupExpress();
2203
2204
  this.setupWebSocket();
2204
2205
  this.setupTraceWatcher();
2206
+ this.setupSomaReportWatcher();
2205
2207
  let knowledgeCount = 0;
2206
2208
  for (const trace of this.watcher.getAllTraces()) {
2207
2209
  this.stats.processTrace(trace);
@@ -2560,6 +2562,27 @@ var DashboardServer = class {
2560
2562
  res.status(500).json({ error: "Failed to load agent statistics" });
2561
2563
  }
2562
2564
  });
2565
+ this.app.get("/api/soma/tier", (_req, res) => {
2566
+ const somaVault = this.config.somaVault;
2567
+ if (!somaVault) {
2568
+ return res.json({ tier: "teaser", somaVault: false, governanceAvailable: false });
2569
+ }
2570
+ try {
2571
+ const reportPath = path2.join(somaVault, "..", "soma-report.json");
2572
+ if (!fs2.existsSync(reportPath)) {
2573
+ return res.json({ tier: "free", somaVault: true, governanceAvailable: false });
2574
+ }
2575
+ const report = JSON.parse(fs2.readFileSync(reportPath, "utf-8"));
2576
+ const hasGovernance = report.governance && typeof report.governance.pending === "number";
2577
+ return res.json({
2578
+ tier: hasGovernance ? "pro" : "free",
2579
+ somaVault: true,
2580
+ governanceAvailable: !!hasGovernance
2581
+ });
2582
+ } catch {
2583
+ return res.json({ tier: "free", somaVault: true, governanceAvailable: false });
2584
+ }
2585
+ });
2563
2586
  this.app.get("/api/soma/report", (_req, res) => {
2564
2587
  const somaVault = this.config.somaVault;
2565
2588
  if (!somaVault) {
@@ -2656,6 +2679,118 @@ var DashboardServer = class {
2656
2679
  res.status(404).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
2657
2680
  }
2658
2681
  });
2682
+ this.app.get("/api/soma/policies", (_req, res) => {
2683
+ const somaVault = this.config.somaVault;
2684
+ if (!somaVault) return res.json({ policies: [] });
2685
+ try {
2686
+ const reportPath = path2.join(somaVault, "..", "soma-report.json");
2687
+ if (!fs2.existsSync(reportPath)) return res.json({ policies: [] });
2688
+ const report = JSON.parse(fs2.readFileSync(reportPath, "utf-8"));
2689
+ res.json({ policies: report.policies ?? [] });
2690
+ } catch {
2691
+ res.json({ policies: [] });
2692
+ }
2693
+ });
2694
+ this.app.post("/api/soma/policies", import_express.default.json(), (req, res) => {
2695
+ var _a;
2696
+ const somaVault = this.config.somaVault;
2697
+ if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
2698
+ const { name, enforcement, scope, conditions } = req.body ?? {};
2699
+ if (!name) return res.status(400).json({ error: "name required" });
2700
+ try {
2701
+ const safeName = sanitizeArg(String(name));
2702
+ const safeEnf = sanitizeArg(String(enforcement || "warn"));
2703
+ const safeScope = sanitizeReason(String(scope || "all"));
2704
+ const safeCond = sanitizeReason(String(conditions || ""));
2705
+ const result = (0, import_node_child_process.execSync)(
2706
+ `npx soma policy create "${safeName}" --enforcement ${safeEnf} --scope "${safeScope}" --conditions "${safeCond}" --vault "${somaVault}"`,
2707
+ { encoding: "utf-8", timeout: 1e4 }
2708
+ );
2709
+ res.json({ success: true, message: result.trim() });
2710
+ } catch (error) {
2711
+ res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
2712
+ }
2713
+ });
2714
+ this.app.delete("/api/soma/policies/:name", (req, res) => {
2715
+ var _a;
2716
+ const somaVault = this.config.somaVault;
2717
+ if (!somaVault) return res.status(400).json({ error: "Soma vault not configured" });
2718
+ try {
2719
+ const safeName = sanitizeArg(String(req.params.name));
2720
+ const result = (0, import_node_child_process.execSync)(
2721
+ `npx soma policy delete "${safeName}" --vault "${somaVault}"`,
2722
+ { encoding: "utf-8", timeout: 1e4 }
2723
+ );
2724
+ res.json({ success: true, message: result.trim() });
2725
+ } catch (error) {
2726
+ res.status(400).json({ error: ((_a = error.stderr) == null ? void 0 : _a.trim()) || error.message });
2727
+ }
2728
+ });
2729
+ this.app.get("/api/soma/vault/entities", (req, res) => {
2730
+ const somaVault = this.config.somaVault;
2731
+ if (!somaVault) return res.json({ entities: [], total: 0 });
2732
+ try {
2733
+ const reportPath = path2.join(somaVault, "..", "soma-report.json");
2734
+ if (!fs2.existsSync(reportPath)) return res.json({ entities: [], total: 0 });
2735
+ const report = JSON.parse(fs2.readFileSync(reportPath, "utf-8"));
2736
+ let entities = [
2737
+ ...(report.agents ?? []).map((a) => ({ ...a, type: "agent", id: a.name })),
2738
+ ...(report.insights ?? []).map((i, idx) => {
2739
+ var _a;
2740
+ return { ...i, type: i.type || "insight", id: ((_a = i.title) == null ? void 0 : _a.replace(/\s+/g, "-").toLowerCase()) || `insight-${idx}` };
2741
+ }),
2742
+ ...(report.policies ?? []).map((p) => ({ ...p, type: "policy", id: p.name }))
2743
+ ];
2744
+ const { type, layer, q, limit: limitStr, offset: offsetStr } = req.query;
2745
+ if (type) entities = entities.filter((e) => e.type === type);
2746
+ if (layer) entities = entities.filter((e) => e.layer === layer);
2747
+ if (q) {
2748
+ const lq = q.toLowerCase();
2749
+ entities = entities.filter((e) => (e.name || e.title || "").toLowerCase().includes(lq) || (e.claim || e.body || "").toLowerCase().includes(lq));
2750
+ }
2751
+ const total = entities.length;
2752
+ const offset = parseInt(offsetStr || "0", 10);
2753
+ const limit = Math.min(parseInt(limitStr || "50", 10), 200);
2754
+ entities = entities.slice(offset, offset + limit);
2755
+ res.json({ entities, total });
2756
+ } catch (error) {
2757
+ console.error("Vault entities error:", error);
2758
+ res.json({ entities: [], total: 0 });
2759
+ }
2760
+ });
2761
+ this.app.get("/api/soma/vault/entities/:type/:id", (req, res) => {
2762
+ const somaVault = this.config.somaVault;
2763
+ if (!somaVault) return res.status(404).json({ error: "Soma vault not configured" });
2764
+ try {
2765
+ const reportPath = path2.join(somaVault, "..", "soma-report.json");
2766
+ const report = JSON.parse(fs2.readFileSync(reportPath, "utf-8"));
2767
+ const { type, id } = req.params;
2768
+ let entity = null;
2769
+ if (type === "agent") {
2770
+ entity = (report.agents ?? []).find((a) => a.name === id);
2771
+ } else if (type === "policy") {
2772
+ entity = (report.policies ?? []).find((p) => p.name === id);
2773
+ } else {
2774
+ entity = (report.insights ?? []).find(
2775
+ (i) => {
2776
+ var _a;
2777
+ return (((_a = i.title) == null ? void 0 : _a.replace(/\s+/g, "-").toLowerCase()) || "") === id || i.title === id;
2778
+ }
2779
+ );
2780
+ }
2781
+ if (!entity) return res.status(404).json({ error: "Entity not found" });
2782
+ res.json({
2783
+ ...entity,
2784
+ type,
2785
+ id,
2786
+ body: entity.claim || entity.conditions || "",
2787
+ tags: entity.tags ?? [],
2788
+ related: entity.related ?? []
2789
+ });
2790
+ } catch {
2791
+ res.status(404).json({ error: "Entity not found" });
2792
+ }
2793
+ });
2659
2794
  this.app.get("/api/process-health", (_req, res) => {
2660
2795
  var _a, _b;
2661
2796
  try {
@@ -2759,11 +2894,11 @@ var DashboardServer = class {
2759
2894
  }
2760
2895
  } catch {
2761
2896
  }
2762
- const watched = [
2897
+ const watched = [...new Set([
2763
2898
  this.config.tracesDir,
2764
2899
  ...this.config.dataDirs || [],
2765
2900
  ...extraDirs
2766
- ];
2901
+ ].map((w) => path2.resolve(w)))];
2767
2902
  const discovered = [];
2768
2903
  const svcNames = getSystemdServices(this.userConfig);
2769
2904
  if (svcNames.length > 0) {
@@ -2917,6 +3052,41 @@ var DashboardServer = class {
2917
3052
  });
2918
3053
  });
2919
3054
  }
3055
+ /** Watch soma-report.json for changes and broadcast updates via WebSocket. */
3056
+ setupSomaReportWatcher() {
3057
+ const somaVault = this.config.somaVault;
3058
+ if (!somaVault) return;
3059
+ const reportPath = path2.join(somaVault, "..", "soma-report.json");
3060
+ const reportDir = path2.dirname(reportPath);
3061
+ if (!fs2.existsSync(reportDir)) return;
3062
+ let debounceTimer = null;
3063
+ const watcher = import_chokidar2.default.watch(reportPath, {
3064
+ ignoreInitial: true,
3065
+ persistent: true,
3066
+ awaitWriteFinish: { stabilityThreshold: 500 }
3067
+ });
3068
+ watcher.on("change", () => {
3069
+ if (debounceTimer) clearTimeout(debounceTimer);
3070
+ debounceTimer = setTimeout(() => {
3071
+ var _a, _b;
3072
+ try {
3073
+ const report = JSON.parse(fs2.readFileSync(reportPath, "utf-8"));
3074
+ this.broadcast({ type: "soma-report-updated", data: report });
3075
+ if (report.generatedAt) {
3076
+ this.broadcast({
3077
+ type: "soma-activity",
3078
+ data: {
3079
+ action: "report-updated",
3080
+ description: `Report updated: ${((_a = report.totals) == null ? void 0 : _a.agents) ?? 0} agents, ${((_b = report.totals) == null ? void 0 : _b.insights) ?? 0} insights`,
3081
+ timestamp: report.generatedAt
3082
+ }
3083
+ });
3084
+ }
3085
+ } catch {
3086
+ }
3087
+ }, 500);
3088
+ });
3089
+ }
2920
3090
  /**
2921
3091
  * Filter an agent's traces to valid ExecutionGraphs and convert via loadGraph().
2922
3092
  * Returns only traces with proper nodes (Map or non-empty object), skipping session-only traces.
@@ -3233,7 +3403,9 @@ function printBanner(config, traceCount, stats, configPath) {
3233
3403
  \u2192 http://localhost:${port}${isPublic && lan ? `
3234
3404
  \u2192 http://${lan}:${port} (LAN)` : ""}
3235
3405
 
3236
- Views: Agent Profile \xB7 Execution Detail \xB7 Governance
3406
+ Pages: Agents \xB7 SOMA
3407
+ Agent: Profile \xB7 Execution Detail
3408
+ SOMA: Intelligence \xB7 Review \xB7 Policies \xB7 Knowledge \xB7 Activity
3237
3409
  Tabs: Flame Chart \xB7 Agent Flow \xB7 Metrics \xB7 Dependencies
3238
3410
  State Machine \xB7 Summary \xB7 Transcript
3239
3411
 
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startDashboard
3
- } from "./chunk-NZFXRZYU.js";
3
+ } from "./chunk-JRVE5NM3.js";
4
4
  export {
5
5
  startDashboard
6
6
  };