@kl-c/matrixos 0.3.1 → 0.3.3

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/cli/index.js CHANGED
@@ -2163,7 +2163,7 @@ var package_default;
2163
2163
  var init_package = __esm(() => {
2164
2164
  package_default = {
2165
2165
  name: "@kl-c/matrixos",
2166
- version: "0.3.1",
2166
+ version: "0.3.3",
2167
2167
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
2168
2168
  main: "./dist/index.js",
2169
2169
  types: "dist/index.d.ts",
@@ -186555,18 +186555,32 @@ import * as os12 from "os";
186555
186555
  import * as fs21 from "fs";
186556
186556
  import * as path24 from "path";
186557
186557
  import { Database as Database5 } from "bun:sqlite";
186558
- var AGENT_NAMES = ["Morpheus", "Trinity", "Keymaker", "Oracle", "Prometheus", "Boulder", "Sentinel", "Ghost", "Neo", "Tank"];
186558
+ var BUILTIN_AGENT_NAMES2 = BuiltinAgentNameSchema.options.map((v) => v);
186559
+ var AGENT_DISPLAY_NAMES2 = {
186560
+ morpheus: "Morpheus",
186561
+ tank: "Tank",
186562
+ "the-oracle": "The Oracle",
186563
+ oracle: "Oracle",
186564
+ link: "Link",
186565
+ ghost: "Ghost",
186566
+ "the-analyst": "The Analyst",
186567
+ "the-keymaker": "The Keymaker",
186568
+ "agent-smith": "Agent Smith",
186569
+ "the-operator": "The Operator",
186570
+ neo: "Neo"
186571
+ };
186559
186572
  var AGENT_ROLES = {
186560
- Morpheus: "Orchestrator",
186561
- Trinity: "Design",
186562
- Keymaker: "Planning",
186563
- Oracle: "Strategy",
186564
- Prometheus: "Planning",
186565
- Boulder: "State",
186566
- Sentinel: "QA",
186567
- Ghost: "Search",
186568
- Neo: "Executor",
186569
- Tank: "Deep Work"
186573
+ morpheus: "Orchestrator",
186574
+ tank: "Deep Work",
186575
+ "the-oracle": "Strategy",
186576
+ oracle: "Consultation",
186577
+ link: "Search",
186578
+ ghost: "Contextual Grep",
186579
+ "the-analyst": "Vision / PDF",
186580
+ "the-keymaker": "Pre-planning",
186581
+ "agent-smith": "Plan Review",
186582
+ "the-operator": "Todo Orchestrator",
186583
+ neo: "Executor"
186570
186584
  };
186571
186585
  var DEFAULT_MODEL = "opencode/deepseek-v4-flash-free";
186572
186586
  var AVAILABLE_MODELS = [
@@ -186671,7 +186685,7 @@ function createDataProvider(config5) {
186671
186685
  const mem = process.memoryUsage();
186672
186686
  const totalMem = os12.totalmem();
186673
186687
  const db = getDb();
186674
- let agentsOnline = AGENT_NAMES.length;
186688
+ let agentsOnline = BUILTIN_AGENT_NAMES2.length;
186675
186689
  let activeSessions = 0;
186676
186690
  let tasksQueued = 0;
186677
186691
  if (db) {
@@ -186692,7 +186706,7 @@ function createDataProvider(config5) {
186692
186706
  }
186693
186707
  return {
186694
186708
  agentsOnline,
186695
- totalAgents: AGENT_NAMES.length,
186709
+ totalAgents: BUILTIN_AGENT_NAMES2.length,
186696
186710
  activeSessions,
186697
186711
  tasksQueued,
186698
186712
  uptime: process.uptime(),
@@ -186706,56 +186720,47 @@ function createDataProvider(config5) {
186706
186720
  };
186707
186721
  },
186708
186722
  async getAgents() {
186723
+ const cfgAgents = readAgentModels();
186709
186724
  const db = getDb();
186725
+ const cutoff = Date.now() - THIRTY_MIN_MS;
186726
+ const dbAgentMap = new Map;
186710
186727
  if (db) {
186711
186728
  try {
186712
- const cutoff = Date.now() - THIRTY_MIN_MS;
186713
186729
  const rows = db.query(`SELECT agent, COUNT(*) as sessions
186714
186730
  FROM session
186715
186731
  WHERE agent IS NOT NULL AND agent != ''
186716
186732
  GROUP BY agent`).all();
186717
- if (rows.length > 0) {
186718
- const cfgAgents2 = readAgentModels();
186719
- const result = [];
186720
- for (const row of rows) {
186721
- const name2 = row.agent;
186722
- const onlineRows = db.query("SELECT COUNT(*) as count FROM session WHERE agent = ? AND time_updated > ?").all(name2, cutoff);
186723
- const status2 = onlineRows.length > 0 && onlineRows[0].count > 0 ? "online" : "idle";
186724
- const model = cfgAgents2[name2];
186725
- result.push({
186726
- name: name2,
186727
- role: AGENT_ROLES[name2] ?? "Agent",
186728
- status: status2,
186729
- sessions: row.sessions,
186730
- uptime: 0,
186731
- cpuPercent: 0,
186732
- memoryPercent: 0,
186733
- model: model ?? DEFAULT_MODEL,
186734
- modelInherited: !model
186735
- });
186736
- }
186737
- db.close();
186738
- return result;
186733
+ for (const row of rows) {
186734
+ const onlineRows = db.query("SELECT COUNT(*) as count FROM session WHERE agent = ? AND time_updated > ?").all(row.agent, cutoff);
186735
+ dbAgentMap.set(row.agent, {
186736
+ sessions: row.sessions,
186737
+ online: onlineRows.length > 0 && onlineRows[0].count > 0
186738
+ });
186739
186739
  }
186740
186740
  } catch {} finally {
186741
186741
  db.close();
186742
186742
  }
186743
186743
  }
186744
- const cfgAgents = readAgentModels();
186745
- return AGENT_NAMES.map((name2) => {
186746
- const model = cfgAgents[name2];
186747
- return {
186748
- name: name2,
186749
- role: AGENT_ROLES[name2] ?? "Agent",
186750
- status: "idle",
186751
- sessions: 0,
186744
+ const result = [];
186745
+ for (const id of BUILTIN_AGENT_NAMES2) {
186746
+ const displayName = AGENT_DISPLAY_NAMES2[id] ?? id;
186747
+ const dbState = dbAgentMap.get(displayName) ?? dbAgentMap.get(id);
186748
+ const sessions = dbState?.sessions ?? 0;
186749
+ const status2 = dbState?.online ? "online" : sessions > 0 ? "idle" : "idle";
186750
+ const model = cfgAgents[id] ?? cfgAgents[displayName];
186751
+ result.push({
186752
+ name: displayName,
186753
+ role: AGENT_ROLES[id] ?? "Agent",
186754
+ status: status2,
186755
+ sessions,
186752
186756
  uptime: 0,
186753
186757
  cpuPercent: 0,
186754
186758
  memoryPercent: 0,
186755
186759
  model: model ?? DEFAULT_MODEL,
186756
186760
  modelInherited: !model
186757
- };
186758
- });
186761
+ });
186762
+ }
186763
+ return result;
186759
186764
  },
186760
186765
  getModels() {
186761
186766
  return AVAILABLE_MODELS;
@@ -186919,15 +186924,7 @@ function createDataProvider(config5) {
186919
186924
  async getIncidents(limit = 50) {
186920
186925
  const lines = readJsonl("anti-loop.jsonl");
186921
186926
  if (lines.length === 0) {
186922
- return Array.from({ length: 10 }, () => ({
186923
- timestamp: Date.now() - randomBetween(0, 86400000),
186924
- trigger: randomChoice(["heartbeat_loss", "memory_exceeded", "cpu_exceeded", "doom_loop", "stuck"]),
186925
- fromLevel: randomChoice(["nudge", "fallback", "restart"]),
186926
- toLevel: randomChoice(["nudge", "fallback", "restart", "notify", "safe"]),
186927
- actionTaken: randomChoice(["nudge", "fallback", "restart", "notify"]),
186928
- outcome: randomChoice(["success", "success", "success", "failed"]),
186929
- detail: "Mock incident data"
186930
- })).slice(0, limit);
186927
+ return [];
186931
186928
  }
186932
186929
  return lines.slice(0, limit).map((l2) => {
186933
186930
  try {
@@ -186954,13 +186951,18 @@ function createDataProvider(config5) {
186954
186951
  const mem = process.memoryUsage();
186955
186952
  const memPercent = Math.round(mem.rss / totalMem * 100);
186956
186953
  const cpuPercent = Math.round(os12.loadavg()[0] * 100);
186954
+ let diskPercent = 0;
186955
+ try {
186956
+ const stat = fs21.statfsSync("/");
186957
+ diskPercent = Math.round((stat.blocks - stat.bavail) / stat.blocks * 100);
186958
+ } catch {}
186957
186959
  const snapshots = [];
186958
186960
  for (let i3 = 0;i3 < 60; i3++) {
186959
186961
  snapshots.push({
186960
186962
  timestamp: Date.now() - (59 - i3) * 60000,
186961
186963
  cpuPercent,
186962
186964
  memoryPercent: memPercent,
186963
- diskPercent: 0,
186965
+ diskPercent,
186964
186966
  sessionsActive: activeSessions
186965
186967
  });
186966
186968
  }
@@ -186986,34 +186988,6 @@ function createDataProvider(config5) {
186986
186988
  } catch {}
186987
186989
  }
186988
186990
  }
186989
- if (entries.length < 20) {
186990
- const mockMsgs = [
186991
- ["Session started", "info"],
186992
- ["Tool executed: read_file", "info"],
186993
- ["Token count: 12,847", "debug"],
186994
- ["Model switch: deepseek-v4-flash-free", "info"],
186995
- ["Cost threshold warning: 78%", "warn"],
186996
- ["Heartbeat received from Morpheus", "debug"],
186997
- ["Session completed (4m 23s)", "info"],
186998
- ["Memory compaction triggered", "info"],
186999
- ["Config change detected", "info"],
187000
- ["Anti-loop triggered: Boulder retry cycle", "error"],
187001
- ["Cache hit rate: 89%", "info"],
187002
- ["Background task completed", "info"],
187003
- ["Gateway reconnected", "info"],
187004
- ["API rate limit: 45/60", "warn"],
187005
- ["Watchdog cycle #1247", "debug"],
187006
- ["Session ses_a1b2c3d4 failed", "error"]
187007
- ];
187008
- for (const [msg, level] of mockMsgs.slice(0, 30 - entries.length)) {
187009
- entries.push({
187010
- timestamp: new Date(Date.now() - randomBetween(0, 3600000)).toISOString(),
187011
- level,
187012
- source: randomChoice(["system", "gateway", "agent", "watchdog"]),
187013
- message: msg
187014
- });
187015
- }
187016
- }
187017
186991
  return entries.sort((a2, b2) => b2.timestamp.localeCompare(a2.timestamp)).slice(0, 100);
187018
186992
  },
187019
186993
  getConfig() {
@@ -2163,7 +2163,7 @@ var package_default;
2163
2163
  var init_package = __esm(() => {
2164
2164
  package_default = {
2165
2165
  name: "@kl-c/matrixos",
2166
- version: "0.3.1",
2166
+ version: "0.3.3",
2167
2167
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
2168
2168
  main: "./dist/index.js",
2169
2169
  types: "dist/index.d.ts",
@@ -186610,18 +186610,32 @@ import * as os12 from "os";
186610
186610
  import * as fs21 from "fs";
186611
186611
  import * as path24 from "path";
186612
186612
  import { Database as Database5 } from "bun:sqlite";
186613
- var AGENT_NAMES = ["Morpheus", "Trinity", "Keymaker", "Oracle", "Prometheus", "Boulder", "Sentinel", "Ghost", "Neo", "Tank"];
186613
+ var BUILTIN_AGENT_NAMES2 = BuiltinAgentNameSchema.options.map((v) => v);
186614
+ var AGENT_DISPLAY_NAMES2 = {
186615
+ morpheus: "Morpheus",
186616
+ tank: "Tank",
186617
+ "the-oracle": "The Oracle",
186618
+ oracle: "Oracle",
186619
+ link: "Link",
186620
+ ghost: "Ghost",
186621
+ "the-analyst": "The Analyst",
186622
+ "the-keymaker": "The Keymaker",
186623
+ "agent-smith": "Agent Smith",
186624
+ "the-operator": "The Operator",
186625
+ neo: "Neo"
186626
+ };
186614
186627
  var AGENT_ROLES = {
186615
- Morpheus: "Orchestrator",
186616
- Trinity: "Design",
186617
- Keymaker: "Planning",
186618
- Oracle: "Strategy",
186619
- Prometheus: "Planning",
186620
- Boulder: "State",
186621
- Sentinel: "QA",
186622
- Ghost: "Search",
186623
- Neo: "Executor",
186624
- Tank: "Deep Work"
186628
+ morpheus: "Orchestrator",
186629
+ tank: "Deep Work",
186630
+ "the-oracle": "Strategy",
186631
+ oracle: "Consultation",
186632
+ link: "Search",
186633
+ ghost: "Contextual Grep",
186634
+ "the-analyst": "Vision / PDF",
186635
+ "the-keymaker": "Pre-planning",
186636
+ "agent-smith": "Plan Review",
186637
+ "the-operator": "Todo Orchestrator",
186638
+ neo: "Executor"
186625
186639
  };
186626
186640
  var DEFAULT_MODEL = "opencode/deepseek-v4-flash-free";
186627
186641
  var AVAILABLE_MODELS = [
@@ -186726,7 +186740,7 @@ function createDataProvider(config5) {
186726
186740
  const mem = process.memoryUsage();
186727
186741
  const totalMem = os12.totalmem();
186728
186742
  const db = getDb();
186729
- let agentsOnline = AGENT_NAMES.length;
186743
+ let agentsOnline = BUILTIN_AGENT_NAMES2.length;
186730
186744
  let activeSessions = 0;
186731
186745
  let tasksQueued = 0;
186732
186746
  if (db) {
@@ -186747,7 +186761,7 @@ function createDataProvider(config5) {
186747
186761
  }
186748
186762
  return {
186749
186763
  agentsOnline,
186750
- totalAgents: AGENT_NAMES.length,
186764
+ totalAgents: BUILTIN_AGENT_NAMES2.length,
186751
186765
  activeSessions,
186752
186766
  tasksQueued,
186753
186767
  uptime: process.uptime(),
@@ -186761,56 +186775,47 @@ function createDataProvider(config5) {
186761
186775
  };
186762
186776
  },
186763
186777
  async getAgents() {
186778
+ const cfgAgents = readAgentModels();
186764
186779
  const db = getDb();
186780
+ const cutoff = Date.now() - THIRTY_MIN_MS;
186781
+ const dbAgentMap = new Map;
186765
186782
  if (db) {
186766
186783
  try {
186767
- const cutoff = Date.now() - THIRTY_MIN_MS;
186768
186784
  const rows = db.query(`SELECT agent, COUNT(*) as sessions
186769
186785
  FROM session
186770
186786
  WHERE agent IS NOT NULL AND agent != ''
186771
186787
  GROUP BY agent`).all();
186772
- if (rows.length > 0) {
186773
- const cfgAgents2 = readAgentModels();
186774
- const result = [];
186775
- for (const row of rows) {
186776
- const name2 = row.agent;
186777
- const onlineRows = db.query("SELECT COUNT(*) as count FROM session WHERE agent = ? AND time_updated > ?").all(name2, cutoff);
186778
- const status2 = onlineRows.length > 0 && onlineRows[0].count > 0 ? "online" : "idle";
186779
- const model = cfgAgents2[name2];
186780
- result.push({
186781
- name: name2,
186782
- role: AGENT_ROLES[name2] ?? "Agent",
186783
- status: status2,
186784
- sessions: row.sessions,
186785
- uptime: 0,
186786
- cpuPercent: 0,
186787
- memoryPercent: 0,
186788
- model: model ?? DEFAULT_MODEL,
186789
- modelInherited: !model
186790
- });
186791
- }
186792
- db.close();
186793
- return result;
186788
+ for (const row of rows) {
186789
+ const onlineRows = db.query("SELECT COUNT(*) as count FROM session WHERE agent = ? AND time_updated > ?").all(row.agent, cutoff);
186790
+ dbAgentMap.set(row.agent, {
186791
+ sessions: row.sessions,
186792
+ online: onlineRows.length > 0 && onlineRows[0].count > 0
186793
+ });
186794
186794
  }
186795
186795
  } catch {} finally {
186796
186796
  db.close();
186797
186797
  }
186798
186798
  }
186799
- const cfgAgents = readAgentModels();
186800
- return AGENT_NAMES.map((name2) => {
186801
- const model = cfgAgents[name2];
186802
- return {
186803
- name: name2,
186804
- role: AGENT_ROLES[name2] ?? "Agent",
186805
- status: "idle",
186806
- sessions: 0,
186799
+ const result = [];
186800
+ for (const id of BUILTIN_AGENT_NAMES2) {
186801
+ const displayName = AGENT_DISPLAY_NAMES2[id] ?? id;
186802
+ const dbState = dbAgentMap.get(displayName) ?? dbAgentMap.get(id);
186803
+ const sessions = dbState?.sessions ?? 0;
186804
+ const status2 = dbState?.online ? "online" : sessions > 0 ? "idle" : "idle";
186805
+ const model = cfgAgents[id] ?? cfgAgents[displayName];
186806
+ result.push({
186807
+ name: displayName,
186808
+ role: AGENT_ROLES[id] ?? "Agent",
186809
+ status: status2,
186810
+ sessions,
186807
186811
  uptime: 0,
186808
186812
  cpuPercent: 0,
186809
186813
  memoryPercent: 0,
186810
186814
  model: model ?? DEFAULT_MODEL,
186811
186815
  modelInherited: !model
186812
- };
186813
- });
186816
+ });
186817
+ }
186818
+ return result;
186814
186819
  },
186815
186820
  getModels() {
186816
186821
  return AVAILABLE_MODELS;
@@ -186974,15 +186979,7 @@ function createDataProvider(config5) {
186974
186979
  async getIncidents(limit = 50) {
186975
186980
  const lines = readJsonl("anti-loop.jsonl");
186976
186981
  if (lines.length === 0) {
186977
- return Array.from({ length: 10 }, () => ({
186978
- timestamp: Date.now() - randomBetween(0, 86400000),
186979
- trigger: randomChoice(["heartbeat_loss", "memory_exceeded", "cpu_exceeded", "doom_loop", "stuck"]),
186980
- fromLevel: randomChoice(["nudge", "fallback", "restart"]),
186981
- toLevel: randomChoice(["nudge", "fallback", "restart", "notify", "safe"]),
186982
- actionTaken: randomChoice(["nudge", "fallback", "restart", "notify"]),
186983
- outcome: randomChoice(["success", "success", "success", "failed"]),
186984
- detail: "Mock incident data"
186985
- })).slice(0, limit);
186982
+ return [];
186986
186983
  }
186987
186984
  return lines.slice(0, limit).map((l2) => {
186988
186985
  try {
@@ -187009,13 +187006,18 @@ function createDataProvider(config5) {
187009
187006
  const mem = process.memoryUsage();
187010
187007
  const memPercent = Math.round(mem.rss / totalMem * 100);
187011
187008
  const cpuPercent = Math.round(os12.loadavg()[0] * 100);
187009
+ let diskPercent = 0;
187010
+ try {
187011
+ const stat = fs21.statfsSync("/");
187012
+ diskPercent = Math.round((stat.blocks - stat.bavail) / stat.blocks * 100);
187013
+ } catch {}
187012
187014
  const snapshots = [];
187013
187015
  for (let i3 = 0;i3 < 60; i3++) {
187014
187016
  snapshots.push({
187015
187017
  timestamp: Date.now() - (59 - i3) * 60000,
187016
187018
  cpuPercent,
187017
187019
  memoryPercent: memPercent,
187018
- diskPercent: 0,
187020
+ diskPercent,
187019
187021
  sessionsActive: activeSessions
187020
187022
  });
187021
187023
  }
@@ -187041,34 +187043,6 @@ function createDataProvider(config5) {
187041
187043
  } catch {}
187042
187044
  }
187043
187045
  }
187044
- if (entries.length < 20) {
187045
- const mockMsgs = [
187046
- ["Session started", "info"],
187047
- ["Tool executed: read_file", "info"],
187048
- ["Token count: 12,847", "debug"],
187049
- ["Model switch: deepseek-v4-flash-free", "info"],
187050
- ["Cost threshold warning: 78%", "warn"],
187051
- ["Heartbeat received from Morpheus", "debug"],
187052
- ["Session completed (4m 23s)", "info"],
187053
- ["Memory compaction triggered", "info"],
187054
- ["Config change detected", "info"],
187055
- ["Anti-loop triggered: Boulder retry cycle", "error"],
187056
- ["Cache hit rate: 89%", "info"],
187057
- ["Background task completed", "info"],
187058
- ["Gateway reconnected", "info"],
187059
- ["API rate limit: 45/60", "warn"],
187060
- ["Watchdog cycle #1247", "debug"],
187061
- ["Session ses_a1b2c3d4 failed", "error"]
187062
- ];
187063
- for (const [msg, level] of mockMsgs.slice(0, 30 - entries.length)) {
187064
- entries.push({
187065
- timestamp: new Date(Date.now() - randomBetween(0, 3600000)).toISOString(),
187066
- level,
187067
- source: randomChoice(["system", "gateway", "agent", "watchdog"]),
187068
- message: msg
187069
- });
187070
- }
187071
- }
187072
187046
  return entries.sort((a2, b2) => b2.timestamp.localeCompare(a2.timestamp)).slice(0, 100);
187073
187047
  },
187074
187048
  getConfig() {
@@ -116,44 +116,39 @@ async function loadHealth(){
116
116
  const kpi=document.getElementById('healthKpis'),gauges=document.getElementById('gaugeGrid'),hb=document.getElementById('heartbeatGrid'),inc=document.getElementById('incidentList')
117
117
  showSkeleton(kpi,'kpi')
118
118
  try{
119
- const[health,metrics,incidents]=await Promise.all([API.health(),API.metrics(),API.incidents(8)])
120
- const cpu=metrics.length?metrics[metrics.length-1].cpuPercent:45
121
- const mem=health.memoryUsage?health.memoryUsage.percent||50:50
122
- const disk=65
119
+ const[health,metrics,incidents,agents]=await Promise.all([API.health(),API.metrics(),API.incidents(8),API.agents()])
120
+ const cpu=metrics.length?metrics[metrics.length-1].cpuPercent:0
121
+ const mem=health.memoryUsage?health.memoryUsage.percent||0:0
122
+ const disk=metrics.length?metrics[metrics.length-1].diskPercent||0:0
123
123
  const cpuColor=cpu>80?'var(--danger)':cpu>60?'var(--warning)':'var(--success)'
124
124
  const memColor=mem>80?'var(--danger)':mem>60?'var(--warning)':'var(--success)'
125
125
  const diskColor=disk>80?'var(--danger)':disk>60?'var(--warning)':'var(--info)'
126
126
 
127
127
  kpi.innerHTML=`
128
- <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">System Status</span><div class="kpi-icon green"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 8l3 3 5-6"/></svg></div></div><div class="kpi-value" style="color:var(--success)">Healthy</div><div class="kpi-trend flat"><span class="live-dot" style="margin-right:4px"></span>All systems operational</div></div>
129
- <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">Uptime</span><div class="kpi-icon cyan"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="8" r="6"/><path d="M8 4.5v3.5l2.5 1.5"/></svg></div></div><div class="kpi-value">99.97%</div><div class="kpi-trend up">Last 30d: ${rand(5,20)}m downtime</div></div>
130
- <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">Active Incidents</span><div class="kpi-icon red"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 2L1.5 13h13L8 2z"/><path d="M8 7v2.5M8 11.5v.5"/></svg></div></div><div class="kpi-value" style="color:var(--danger)">${incidents.length}</div><div class="kpi-trend down"><svg width="10" height="10" viewBox="0 0 10 10" fill="currentColor"><path d="M5 2L9 7H1z"/></svg>+${rand(0,3)} in last hour</div></div>
131
- <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">Watchdog Cycles</span><div class="kpi-icon blue"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="8" r="6"/><path d="M8 5v3"/><circle cx="8" cy="11" r="0.5" fill="currentColor"/></svg></div></div><div class="kpi-value">${rand(800,2000)}</div><div class="kpi-trend flat">Last check: ${rand(1,10)}s ago</div></div>`
128
+ <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">System Status</span><div class="kpi-icon green"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 8l3 3 5-6"/></svg></div></div><div class="kpi-value" style="color:var(--success)">Online</div><div class="kpi-trend flat"><span class="live-dot" style="margin-right:4px"></span>v${health.version}</div></div>
129
+ <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">Uptime</span><div class="kpi-icon cyan"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="8" r="6"/><path d="M8 4.5v3.5l2.5 1.5"/></svg></div></div><div class="kpi-value">${fmtDur(Math.round(health.uptime))}</div><div class="kpi-trend up">Since last restart</div></div>
130
+ <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">Active Incidents</span><div class="kpi-icon red"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 2L1.5 13h13L8 2z"/><path d="M8 7v2.5M8 11.5v.5"/></svg></div></div><div class="kpi-value" style="color:${incidents.length?'var(--danger)':'var(--success)'}">${incidents.length}</div><div class="kpi-trend ${incidents.length?'down':'flat'}">${incidents.length?'Needs attention':'All clear'}</div></div>
131
+ <div class="kpi-card"><div class="kpi-card-header"><span class="kpi-label">Active Sessions</span><div class="kpi-icon blue"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="8" r="6"/><path d="M8 5v3"/><circle cx="8" cy="11" r="0.5" fill="currentColor"/></svg></div></div><div class="kpi-value">${health.activeSessions}</div><div class="kpi-trend flat">${health.tasksQueued} queued</div></div>`
132
132
 
133
133
  // Resource gauges (SVG)
134
134
  function gauge(pct,color,label,sub){
135
135
  const r=16,c=2*Math.PI*r,offset=c-(c*pct/100)
136
136
  return `<div class="gauge-card"><div class="gauge-ring"><svg viewBox="0 0 40 40"><circle class="track" cx="20" cy="20" r="${r}"/><circle stroke="${color}" cx="20" cy="20" r="${r}" stroke-dasharray="${c}" stroke-dashoffset="${offset}" style="transition:stroke-dashoffset 500ms"/></svg><div class="gauge-val" style="color:${color}">${pct}%</div></div><div class="gauge-label">${label}</div><div class="gauge-sub">${sub}</div></div>`
137
137
  }
138
- const totalMem=(health.memoryUsage&&health.memoryUsage.total)||32
138
+ const totalMem=(health.memoryUsage&&health.memoryUsage.total)||0
139
139
  const usedMem=Math.round(totalMem*(mem||0)/100)
140
- gauges.innerHTML=gauge(Math.round(cpu),cpuColor,'CPU Usage','8 cores / 16 threads')+gauge(mem,memColor,'Memory',`${usedMem} / ${totalMem} GB`)+gauge(disk,diskColor,'Disk','270 / 500 GB')
140
+ gauges.innerHTML=gauge(Math.round(cpu),cpuColor,'CPU Usage','Load avg')+gauge(mem,memColor,'Memory',`${usedMem} / ${totalMem} MB`)+gauge(disk,diskColor,'Disk','/ filesystem')
141
141
 
142
- // Heartbeat Grid
143
- const agents=['Morpheus','Keymaker','Trinity','Oracle','Boulder']
142
+ // Heartbeat Grid — real agents
143
+ const agentNames=agents.slice(0,8).map(a=>a.name)
144
144
  const hbLegendEl=document.getElementById('hbLegend')
145
- hbLegendEl.innerHTML=`<span style="display:flex;align-items:center;gap:4px;font-size:var(--text-xs);color:var(--success)"><span style="width:6px;height:6px;border-radius:50%;background:var(--success)"></span>Healthy</span><span style="display:flex;align-items:center;gap:4px;font-size:var(--text-xs);color:var(--warning)"><span style="width:6px;height:6px;border-radius:50%;background:var(--warning)"></span>Degraded</span><span style="display:flex;align-items:center;gap:4px;font-size:var(--text-xs);color:var(--danger)"><span style="width:6px;height:6px;border-radius:50%;background:var(--danger)"></span>Missed</span>`
146
- hb.innerHTML=agents.map((name,i)=>{
147
- const initial=name[0]
148
- const cells=[]
149
- for(let t=0;t<8;t++){
150
- const r=Math.random()
151
- const cls=r>0.85?'fail':r>0.7&&i>2?'warn':'healthy'
152
- cells.push(`<div class="hb-cell ${cls}" title="${name} t-${(7-t)*10}s">${initial}</div>`)
153
- }
154
- return cells.join('')
145
+ hbLegendEl.innerHTML=`<span style="display:flex;align-items:center;gap:4px;font-size:var(--text-xs);color:var(--success)"><span style="width:6px;height:6px;border-radius:50%;background:var(--success)"></span>Online</span><span style="display:flex;align-items:center;gap:4px;font-size:var(--text-xs);color:var(--warning)"><span style="width:6px;height:6px;border-radius:50%;background:var(--warning)"></span>Idle</span><span style="display:flex;align-items:center;gap:4px;font-size:var(--text-xs);color:var(--danger)"><span style="width:6px;height:6px;border-radius:50%;background:var(--danger)"></span>Offline</span>`
146
+ hb.innerHTML=agentNames.map((name)=>{
147
+ const agent=agents.find(a=>a.name===name)
148
+ const cls=agent&&agent.status==='online'?'healthy':agent&&agent.status==='idle'?'warn':'fail'
149
+ return `<div class="hb-cell ${cls}" title="${name}">${name[0]}</div>`
155
150
  }).join('')
156
- hb.insertAdjacentHTML('afterend',`<div style="margin-top:var(--space-3);font-size:var(--text-xs);color:var(--text-tertiary)">Agents: ${agents.map(a=>a[0]+'='+a).join(', ')}</div>`)
151
+ hb.insertAdjacentHTML('afterend',`<div style="margin-top:var(--space-3);font-size:var(--text-xs);color:var(--text-tertiary)">Agents: ${agentNames.map(a=>a[0]+'='+a).join(', ')}</div>`)
157
152
 
158
153
  // Incidents
159
154
  if(!incidents.length){showEmpty(inc,'No incidents recorded');return}
package/dist/index.js CHANGED
@@ -368019,7 +368019,7 @@ function getCachedVersion(options = {}) {
368019
368019
  // package.json
368020
368020
  var package_default = {
368021
368021
  name: "@kl-c/matrixos",
368022
- version: "0.3.1",
368022
+ version: "0.3.3",
368023
368023
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
368024
368024
  main: "./dist/index.js",
368025
368025
  types: "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kl-c/matrixos",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "MaTrixOS — Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "dist/index.d.ts",