@kl-c/matrixos 0.1.17 → 0.1.18

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
@@ -2145,7 +2145,7 @@ var package_default;
2145
2145
  var init_package = __esm(() => {
2146
2146
  package_default = {
2147
2147
  name: "@kl-c/matrixos",
2148
- version: "0.1.17",
2148
+ version: "0.1.18",
2149
2149
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
2150
2150
  main: "./dist/index.js",
2151
2151
  types: "dist/index.d.ts",
@@ -141031,101 +141031,55 @@ var AGENT_ROLES = {
141031
141031
  Neo: "Executor",
141032
141032
  Tank: "Deep Work"
141033
141033
  };
141034
+ var OPENCODE_DB_PATH = path24.resolve(os12.homedir(), ".local", "share", "opencode", "opencode.db");
141035
+ var THIRTY_MIN_MS = 30 * 60 * 1000;
141036
+ var FIVE_MIN_MS = 5 * 60 * 1000;
141037
+ var BUDGET_TOTAL = 5000;
141034
141038
  function randomBetween(min2, max2) {
141035
141039
  return Math.floor(Math.random() * (max2 - min2 + 1)) + min2;
141036
141040
  }
141037
141041
  function randomChoice(arr) {
141038
141042
  return arr[Math.floor(Math.random() * arr.length)];
141039
141043
  }
141040
- function generateMockAgents() {
141041
- return AGENT_NAMES.map((name2) => ({
141042
- name: name2,
141043
- role: AGENT_ROLES[name2] ?? "Agent",
141044
- status: randomChoice(["online", "online", "online", "idle", "idle", "offline"]),
141045
- sessions: randomBetween(0, 25),
141046
- uptime: randomBetween(100, 86400),
141047
- cpuPercent: randomBetween(2, 85),
141048
- memoryPercent: randomBetween(10, 75)
141049
- }));
141044
+ function parseModel(modelRaw) {
141045
+ if (!modelRaw)
141046
+ return "unknown";
141047
+ try {
141048
+ const parsed = JSON.parse(modelRaw);
141049
+ if (parsed.id)
141050
+ return parsed.id;
141051
+ } catch {}
141052
+ return modelRaw;
141053
+ }
141054
+ function getDb() {
141055
+ if (!fs20.existsSync(OPENCODE_DB_PATH))
141056
+ return;
141057
+ try {
141058
+ return new Database5(OPENCODE_DB_PATH, { readonly: true });
141059
+ } catch {
141060
+ return;
141061
+ }
141050
141062
  }
141051
- function generateMockSessions(count) {
141052
- const models2 = ["deepseek-v4-flash-free", "gpt-5.5-pro", "claude-opus-4-7", "gemini-3.1-pro", "glm-5.2"];
141053
- return Array.from({ length: count }, (_2, i3) => ({
141054
- id: `ses_${randomBetween(1e5, 999999).toString(16)}`,
141055
- agent: randomChoice(AGENT_NAMES),
141056
- model: randomChoice(models2),
141057
- duration: randomBetween(5, 600),
141058
- cost: Math.round(randomBetween(1, 500) * 100) / 100,
141059
- status: randomChoice(["active", "completed", "completed", "completed", "failed", "timeout"]),
141060
- startedAt: new Date(Date.now() - randomBetween(0, 86400000)).toISOString()
141061
- }));
141063
+ function midnightMs() {
141064
+ const d = new Date;
141065
+ d.setHours(0, 0, 0, 0);
141066
+ return d.getTime();
141062
141067
  }
141063
- function generateMockCost() {
141064
- const agents = AGENT_NAMES.map((name2) => ({
141065
- agent: name2,
141066
- cost: Math.round(randomBetween(50, 2000) * 100) / 100,
141067
- percentage: 0
141068
- }));
141069
- const total = agents.reduce((s, a2) => s + a2.cost, 0);
141070
- agents.forEach((a2) => {
141071
- a2.percentage = Math.round(a2.cost / total * 100);
141072
- });
141073
- return {
141074
- total: Math.round(total * 100) / 100,
141075
- daily: Math.round(randomBetween(50, 300) * 100) / 100,
141076
- monthly: Math.round(randomBetween(1500, 9000) * 100) / 100,
141077
- budgetRemaining: Math.round(randomBetween(500, 5000) * 100) / 100,
141078
- byAgent: agents,
141079
- byDay: Array.from({ length: 30 }, (_2, i3) => ({
141080
- date: new Date(Date.now() - (29 - i3) * 86400000).toISOString().slice(0, 10),
141081
- cost: Math.round(randomBetween(20, 300) * 100) / 100
141082
- })),
141083
- alerts: [
141084
- { severity: "warning", message: "Morpheus approaching budget threshold (85%)" },
141085
- { severity: "critical", message: "Tank exceeded daily budget cap ($500)" }
141086
- ]
141087
- };
141068
+ function thirtyDaysAgoMs() {
141069
+ return Date.now() - 30 * 24 * 60 * 60 * 1000;
141088
141070
  }
141089
- function generateMockKanban() {
141090
- const statuses = ["pending", "in_progress", "completed", "failed"];
141091
- const columns = {};
141092
- for (const s of statuses) {
141093
- columns[s] = Array.from({ length: randomBetween(2, 6) }, (_2, i3) => ({
141094
- id: `task_${randomBetween(1000, 9999)}`,
141095
- title: randomChoice([
141096
- "Implement Watchdog daemon",
141097
- "Design System tokens",
141098
- "API rate limiting",
141099
- "Session persistence",
141100
- "User auth flow",
141101
- "Database migration",
141102
- "Cache invalidation",
141103
- "Webhook integration",
141104
- "Telegram notifications",
141105
- "Cost optimization",
141106
- "Security audit",
141107
- "Performance profiling"
141108
- ]),
141109
- agent: randomChoice(AGENT_NAMES),
141110
- priority: randomChoice(["low", "medium", "high", "critical"]),
141111
- status: s,
141112
- createdAt: new Date(Date.now() - randomBetween(0, 604800000)).toISOString(),
141113
- updatedAt: new Date(Date.now() - randomBetween(0, 86400000)).toISOString()
141114
- }));
141071
+ function readPackageVersion2() {
141072
+ try {
141073
+ const pkgPath = new URL("../../../../package.json", import.meta.url).pathname;
141074
+ const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf-8"));
141075
+ return pkg.version ?? "0.0.0";
141076
+ } catch {
141077
+ return "0.0.0";
141115
141078
  }
141116
- return { columns };
141117
- }
141118
- function generateMockMetrics() {
141119
- return Array.from({ length: 60 }, (_2, i3) => ({
141120
- timestamp: Date.now() - (59 - i3) * 60000,
141121
- cpuPercent: randomBetween(10, 95),
141122
- memoryPercent: randomBetween(30, 85),
141123
- diskPercent: randomBetween(40, 70),
141124
- sessionsActive: randomBetween(1, 8)
141125
- }));
141126
141079
  }
141127
141080
  function createDataProvider(config4) {
141128
141081
  const matrixosHome = config4?.matrixosHome ?? ".matrixos";
141082
+ const version3 = readPackageVersion2();
141129
141083
  function readJsonl(filePath) {
141130
141084
  try {
141131
141085
  const fullPath = path24.resolve(matrixosHome, "logs", filePath);
@@ -141141,13 +141095,33 @@ function createDataProvider(config4) {
141141
141095
  async getHealth() {
141142
141096
  const mem = process.memoryUsage();
141143
141097
  const totalMem = os12.totalmem();
141098
+ const db = getDb();
141099
+ let agentsOnline = AGENT_NAMES.length;
141100
+ let activeSessions = 0;
141101
+ let tasksQueued = 0;
141102
+ if (db) {
141103
+ try {
141104
+ const agentRow = db.query("SELECT COUNT(DISTINCT agent) as count FROM session").get();
141105
+ if (agentRow)
141106
+ agentsOnline = agentRow.count;
141107
+ const cutoff = Date.now() - THIRTY_MIN_MS;
141108
+ const sessionRows = db.query("SELECT COUNT(*) as count FROM session WHERE time_archived IS NULL AND time_updated > ?").all(cutoff);
141109
+ if (sessionRows.length > 0)
141110
+ activeSessions = sessionRows[0].count;
141111
+ const todoRows = db.query("SELECT COUNT(*) as count FROM todo WHERE status = 'pending'").all();
141112
+ if (todoRows.length > 0)
141113
+ tasksQueued = todoRows[0].count;
141114
+ } catch {} finally {
141115
+ db.close();
141116
+ }
141117
+ }
141144
141118
  return {
141145
- agentsOnline: AGENT_NAMES.length - randomBetween(1, 3),
141119
+ agentsOnline,
141146
141120
  totalAgents: AGENT_NAMES.length,
141147
- activeSessions: randomBetween(2, 8),
141148
- tasksQueued: randomBetween(5, 20),
141121
+ activeSessions,
141122
+ tasksQueued,
141149
141123
  uptime: process.uptime(),
141150
- version: "0.1.0",
141124
+ version: version3,
141151
141125
  memoryUsage: {
141152
141126
  used: Math.round(mem.rss / 1024 / 1024),
141153
141127
  total: Math.round(totalMem / 1024 / 1024),
@@ -141157,16 +141131,181 @@ function createDataProvider(config4) {
141157
141131
  };
141158
141132
  },
141159
141133
  async getAgents() {
141160
- return generateMockAgents();
141134
+ const db = getDb();
141135
+ if (db) {
141136
+ try {
141137
+ const cutoff = Date.now() - THIRTY_MIN_MS;
141138
+ const rows = db.query(`SELECT agent, COUNT(*) as sessions
141139
+ FROM session
141140
+ WHERE agent IS NOT NULL AND agent != ''
141141
+ GROUP BY agent`).all();
141142
+ if (rows.length > 0) {
141143
+ const result = [];
141144
+ for (const row of rows) {
141145
+ const name2 = row.agent;
141146
+ const onlineRows = db.query("SELECT COUNT(*) as count FROM session WHERE agent = ? AND time_updated > ?").all(name2, cutoff);
141147
+ const status2 = onlineRows.length > 0 && onlineRows[0].count > 0 ? "online" : "idle";
141148
+ result.push({
141149
+ name: name2,
141150
+ role: AGENT_ROLES[name2] ?? "Agent",
141151
+ status: status2,
141152
+ sessions: row.sessions,
141153
+ uptime: 0,
141154
+ cpuPercent: 0,
141155
+ memoryPercent: 0
141156
+ });
141157
+ }
141158
+ db.close();
141159
+ return result;
141160
+ }
141161
+ } catch {} finally {
141162
+ db.close();
141163
+ }
141164
+ }
141165
+ return AGENT_NAMES.map((name2) => ({
141166
+ name: name2,
141167
+ role: AGENT_ROLES[name2] ?? "Agent",
141168
+ status: "idle",
141169
+ sessions: 0,
141170
+ uptime: 0,
141171
+ cpuPercent: 0,
141172
+ memoryPercent: 0
141173
+ }));
141161
141174
  },
141162
141175
  async getSessions(limit = 20) {
141163
- return generateMockSessions(limit).slice(0, limit);
141176
+ const db = getDb();
141177
+ if (!db)
141178
+ return [];
141179
+ try {
141180
+ const now = Date.now();
141181
+ const rows = db.query(`SELECT id, title, agent, model, cost, time_created, time_updated, time_archived
141182
+ FROM session
141183
+ ORDER BY time_updated DESC
141184
+ LIMIT ?`).all(limit);
141185
+ const result = [];
141186
+ for (const row of rows) {
141187
+ const duration3 = Math.max(0, Math.round((row.time_updated - row.time_created) / 1000));
141188
+ let status2 = "completed";
141189
+ if (row.time_archived !== null) {
141190
+ status2 = "completed";
141191
+ } else if (row.time_updated > now - FIVE_MIN_MS) {
141192
+ status2 = "active";
141193
+ } else {
141194
+ status2 = "completed";
141195
+ }
141196
+ result.push({
141197
+ id: row.id,
141198
+ agent: row.agent ?? "unknown",
141199
+ model: parseModel(row.model),
141200
+ duration: duration3,
141201
+ cost: row.cost,
141202
+ status: status2,
141203
+ startedAt: new Date(row.time_created).toISOString()
141204
+ });
141205
+ }
141206
+ return result;
141207
+ } catch {
141208
+ return [];
141209
+ } finally {
141210
+ db.close();
141211
+ }
141164
141212
  },
141165
141213
  async getCost() {
141166
- return generateMockCost();
141214
+ const db = getDb();
141215
+ if (!db) {
141216
+ return {
141217
+ total: 0,
141218
+ daily: 0,
141219
+ monthly: 0,
141220
+ budgetRemaining: BUDGET_TOTAL,
141221
+ byAgent: [],
141222
+ byDay: [],
141223
+ alerts: []
141224
+ };
141225
+ }
141226
+ try {
141227
+ const totalRows = db.query("SELECT COALESCE(SUM(cost), 0) as sum FROM session").all();
141228
+ const total = totalRows.length > 0 ? totalRows[0].sum ?? 0 : 0;
141229
+ const dailyRows = db.query("SELECT COALESCE(SUM(cost), 0) as sum FROM session WHERE time_created > ?").all(midnightMs());
141230
+ const daily = dailyRows.length > 0 ? dailyRows[0].sum ?? 0 : 0;
141231
+ const monthlyRows = db.query("SELECT COALESCE(SUM(cost), 0) as sum FROM session WHERE time_created > ?").all(thirtyDaysAgoMs());
141232
+ const monthly = monthlyRows.length > 0 ? monthlyRows[0].sum ?? 0 : 0;
141233
+ const agentRows = db.query(`SELECT agent, COALESCE(SUM(cost), 0) as cost
141234
+ FROM session
141235
+ WHERE agent IS NOT NULL AND agent != ''
141236
+ GROUP BY agent`).all();
141237
+ const byAgent = agentRows.map((r2) => ({
141238
+ agent: r2.agent,
141239
+ cost: r2.cost,
141240
+ percentage: total > 0 ? Math.round(r2.cost / total * 100) : 0
141241
+ }));
141242
+ const byDayRows = db.query(`SELECT strftime('%Y-%m-%d', time_created / 1000, 'unixepoch') as day,
141243
+ COALESCE(SUM(cost), 0) as cost
141244
+ FROM session
141245
+ WHERE time_created > ?
141246
+ GROUP BY day
141247
+ ORDER BY day ASC`).all(thirtyDaysAgoMs());
141248
+ const byDayMap = new Map;
141249
+ for (const r2 of byDayRows) {
141250
+ byDayMap.set(r2.day, r2.cost);
141251
+ }
141252
+ const byDay = [];
141253
+ const today = new Date;
141254
+ for (let i3 = 29;i3 >= 0; i3--) {
141255
+ const d = new Date(today);
141256
+ d.setDate(d.getDate() - i3);
141257
+ const key = d.toISOString().slice(0, 10);
141258
+ byDay.push({ date: key, cost: byDayMap.get(key) ?? 0 });
141259
+ }
141260
+ const budgetRemaining = Math.max(0, BUDGET_TOTAL - total);
141261
+ const alerts = [];
141262
+ if (total > BUDGET_TOTAL) {
141263
+ alerts.push({ severity: "critical", message: `Total cost $${total.toFixed(2)} exceeds budget $${BUDGET_TOTAL}` });
141264
+ } else if (total > BUDGET_TOTAL * 0.85) {
141265
+ alerts.push({ severity: "warning", message: `Cost $${total.toFixed(2)} approaching budget threshold (85%)` });
141266
+ }
141267
+ return { total, daily, monthly, budgetRemaining, byAgent, byDay, alerts };
141268
+ } catch {
141269
+ return {
141270
+ total: 0,
141271
+ daily: 0,
141272
+ monthly: 0,
141273
+ budgetRemaining: BUDGET_TOTAL,
141274
+ byAgent: [],
141275
+ byDay: [],
141276
+ alerts: []
141277
+ };
141278
+ } finally {
141279
+ db.close();
141280
+ }
141167
141281
  },
141168
141282
  async getKanbanTasks() {
141169
- return generateMockKanban();
141283
+ const board = { columns: { pending: [], in_progress: [], completed: [], failed: [] } };
141284
+ const db = getDb();
141285
+ if (!db)
141286
+ return board;
141287
+ try {
141288
+ const rows = db.query("SELECT content, status, priority, time_created, time_updated FROM todo ORDER BY time_updated DESC").all();
141289
+ let idx = 0;
141290
+ for (const row of rows) {
141291
+ const status2 = row.status;
141292
+ if (!board.columns[status2])
141293
+ continue;
141294
+ const task2 = {
141295
+ id: `todo_${idx++}`,
141296
+ title: row.content,
141297
+ agent: "Unknown",
141298
+ priority: row.priority ?? "medium",
141299
+ status: status2,
141300
+ createdAt: new Date(row.time_created).toISOString(),
141301
+ updatedAt: new Date(row.time_updated).toISOString()
141302
+ };
141303
+ board.columns[status2].push(task2);
141304
+ }
141305
+ } catch {} finally {
141306
+ db.close();
141307
+ }
141308
+ return board;
141170
141309
  },
141171
141310
  async getIncidents(limit = 50) {
141172
141311
  const lines = readJsonl("anti-loop.jsonl");
@@ -141190,7 +141329,33 @@ function createDataProvider(config4) {
141190
141329
  }).filter(Boolean);
141191
141330
  },
141192
141331
  async getMetrics() {
141193
- return generateMockMetrics();
141332
+ const db = getDb();
141333
+ let activeSessions = 0;
141334
+ if (db) {
141335
+ try {
141336
+ const cutoff = Date.now() - THIRTY_MIN_MS;
141337
+ const rows = db.query("SELECT COUNT(*) as count FROM session WHERE time_archived IS NULL AND time_updated > ?").all(cutoff);
141338
+ if (rows.length > 0)
141339
+ activeSessions = rows[0].count;
141340
+ } catch {} finally {
141341
+ db.close();
141342
+ }
141343
+ }
141344
+ const totalMem = os12.totalmem();
141345
+ const mem = process.memoryUsage();
141346
+ const memPercent = Math.round(mem.rss / totalMem * 100);
141347
+ const cpuPercent = Math.round(os12.loadavg()[0] * 100);
141348
+ const snapshots = [];
141349
+ for (let i3 = 0;i3 < 60; i3++) {
141350
+ snapshots.push({
141351
+ timestamp: Date.now() - (59 - i3) * 60000,
141352
+ cpuPercent,
141353
+ memoryPercent: memPercent,
141354
+ diskPercent: 0,
141355
+ sessionsActive: activeSessions
141356
+ });
141357
+ }
141358
+ return snapshots;
141194
141359
  },
141195
141360
  getLogs() {
141196
141361
  const logFiles = [
@@ -141537,7 +141702,7 @@ function createDashboardServer(dataProvider, config4) {
141537
141702
  // packages/omo-opencode/src/cli/dashboard.ts
141538
141703
  async function dashboardCli(options) {
141539
141704
  const port = options.port ?? 9123;
141540
- const host = options.host ?? "127.0.0.1";
141705
+ const host = options.host ?? "0.0.0.0";
141541
141706
  const frontendDir = path25.resolve(import.meta.dir, "../features/dashboard/frontend");
141542
141707
  console.log(`[dashboard] starting MaTrixOS dashboard on http://${host}:${port}`);
141543
141708
  console.log(`[dashboard] frontend: ${frontendDir}`);
@@ -141859,7 +142024,7 @@ function configureRuntimeCommands(program2) {
141859
142024
  const exitCode = await architectRollback({ ...options, id });
141860
142025
  process.exit(exitCode);
141861
142026
  });
141862
- program2.command("dashboard").description("Start the MaTrixOS web dashboard (port 9123)").option("-p, --port <number>", "HTTP port", "9123").option("--host <addr>", "Bind address", "127.0.0.1").option("--daemon", "Run in background (no Ctrl+C)").action(async (options) => {
142027
+ program2.command("dashboard").description("Start the MaTrixOS web dashboard (port 9123)").option("-p, --port <number>", "HTTP port", "9123").option("--host <addr>", "Bind address", "0.0.0.0").option("--daemon", "Run in background (no Ctrl+C)").action(async (options) => {
141863
142028
  const exitCode = await dashboardCli({
141864
142029
  port: parseInt(options.port ?? "9123", 10),
141865
142030
  host: options.host,
@@ -2145,7 +2145,7 @@ var package_default;
2145
2145
  var init_package = __esm(() => {
2146
2146
  package_default = {
2147
2147
  name: "@kl-c/matrixos",
2148
- version: "0.1.17",
2148
+ version: "0.1.18",
2149
2149
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
2150
2150
  main: "./dist/index.js",
2151
2151
  types: "dist/index.d.ts",
@@ -141086,101 +141086,55 @@ var AGENT_ROLES = {
141086
141086
  Neo: "Executor",
141087
141087
  Tank: "Deep Work"
141088
141088
  };
141089
+ var OPENCODE_DB_PATH = path24.resolve(os12.homedir(), ".local", "share", "opencode", "opencode.db");
141090
+ var THIRTY_MIN_MS = 30 * 60 * 1000;
141091
+ var FIVE_MIN_MS = 5 * 60 * 1000;
141092
+ var BUDGET_TOTAL = 5000;
141089
141093
  function randomBetween(min2, max2) {
141090
141094
  return Math.floor(Math.random() * (max2 - min2 + 1)) + min2;
141091
141095
  }
141092
141096
  function randomChoice(arr) {
141093
141097
  return arr[Math.floor(Math.random() * arr.length)];
141094
141098
  }
141095
- function generateMockAgents() {
141096
- return AGENT_NAMES.map((name2) => ({
141097
- name: name2,
141098
- role: AGENT_ROLES[name2] ?? "Agent",
141099
- status: randomChoice(["online", "online", "online", "idle", "idle", "offline"]),
141100
- sessions: randomBetween(0, 25),
141101
- uptime: randomBetween(100, 86400),
141102
- cpuPercent: randomBetween(2, 85),
141103
- memoryPercent: randomBetween(10, 75)
141104
- }));
141099
+ function parseModel(modelRaw) {
141100
+ if (!modelRaw)
141101
+ return "unknown";
141102
+ try {
141103
+ const parsed = JSON.parse(modelRaw);
141104
+ if (parsed.id)
141105
+ return parsed.id;
141106
+ } catch {}
141107
+ return modelRaw;
141108
+ }
141109
+ function getDb() {
141110
+ if (!fs20.existsSync(OPENCODE_DB_PATH))
141111
+ return;
141112
+ try {
141113
+ return new Database5(OPENCODE_DB_PATH, { readonly: true });
141114
+ } catch {
141115
+ return;
141116
+ }
141105
141117
  }
141106
- function generateMockSessions(count) {
141107
- const models2 = ["deepseek-v4-flash-free", "gpt-5.5-pro", "claude-opus-4-7", "gemini-3.1-pro", "glm-5.2"];
141108
- return Array.from({ length: count }, (_2, i3) => ({
141109
- id: `ses_${randomBetween(1e5, 999999).toString(16)}`,
141110
- agent: randomChoice(AGENT_NAMES),
141111
- model: randomChoice(models2),
141112
- duration: randomBetween(5, 600),
141113
- cost: Math.round(randomBetween(1, 500) * 100) / 100,
141114
- status: randomChoice(["active", "completed", "completed", "completed", "failed", "timeout"]),
141115
- startedAt: new Date(Date.now() - randomBetween(0, 86400000)).toISOString()
141116
- }));
141118
+ function midnightMs() {
141119
+ const d = new Date;
141120
+ d.setHours(0, 0, 0, 0);
141121
+ return d.getTime();
141117
141122
  }
141118
- function generateMockCost() {
141119
- const agents = AGENT_NAMES.map((name2) => ({
141120
- agent: name2,
141121
- cost: Math.round(randomBetween(50, 2000) * 100) / 100,
141122
- percentage: 0
141123
- }));
141124
- const total = agents.reduce((s, a2) => s + a2.cost, 0);
141125
- agents.forEach((a2) => {
141126
- a2.percentage = Math.round(a2.cost / total * 100);
141127
- });
141128
- return {
141129
- total: Math.round(total * 100) / 100,
141130
- daily: Math.round(randomBetween(50, 300) * 100) / 100,
141131
- monthly: Math.round(randomBetween(1500, 9000) * 100) / 100,
141132
- budgetRemaining: Math.round(randomBetween(500, 5000) * 100) / 100,
141133
- byAgent: agents,
141134
- byDay: Array.from({ length: 30 }, (_2, i3) => ({
141135
- date: new Date(Date.now() - (29 - i3) * 86400000).toISOString().slice(0, 10),
141136
- cost: Math.round(randomBetween(20, 300) * 100) / 100
141137
- })),
141138
- alerts: [
141139
- { severity: "warning", message: "Morpheus approaching budget threshold (85%)" },
141140
- { severity: "critical", message: "Tank exceeded daily budget cap ($500)" }
141141
- ]
141142
- };
141123
+ function thirtyDaysAgoMs() {
141124
+ return Date.now() - 30 * 24 * 60 * 60 * 1000;
141143
141125
  }
141144
- function generateMockKanban() {
141145
- const statuses = ["pending", "in_progress", "completed", "failed"];
141146
- const columns = {};
141147
- for (const s of statuses) {
141148
- columns[s] = Array.from({ length: randomBetween(2, 6) }, (_2, i3) => ({
141149
- id: `task_${randomBetween(1000, 9999)}`,
141150
- title: randomChoice([
141151
- "Implement Watchdog daemon",
141152
- "Design System tokens",
141153
- "API rate limiting",
141154
- "Session persistence",
141155
- "User auth flow",
141156
- "Database migration",
141157
- "Cache invalidation",
141158
- "Webhook integration",
141159
- "Telegram notifications",
141160
- "Cost optimization",
141161
- "Security audit",
141162
- "Performance profiling"
141163
- ]),
141164
- agent: randomChoice(AGENT_NAMES),
141165
- priority: randomChoice(["low", "medium", "high", "critical"]),
141166
- status: s,
141167
- createdAt: new Date(Date.now() - randomBetween(0, 604800000)).toISOString(),
141168
- updatedAt: new Date(Date.now() - randomBetween(0, 86400000)).toISOString()
141169
- }));
141126
+ function readPackageVersion2() {
141127
+ try {
141128
+ const pkgPath = new URL("../../../../package.json", import.meta.url).pathname;
141129
+ const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf-8"));
141130
+ return pkg.version ?? "0.0.0";
141131
+ } catch {
141132
+ return "0.0.0";
141170
141133
  }
141171
- return { columns };
141172
- }
141173
- function generateMockMetrics() {
141174
- return Array.from({ length: 60 }, (_2, i3) => ({
141175
- timestamp: Date.now() - (59 - i3) * 60000,
141176
- cpuPercent: randomBetween(10, 95),
141177
- memoryPercent: randomBetween(30, 85),
141178
- diskPercent: randomBetween(40, 70),
141179
- sessionsActive: randomBetween(1, 8)
141180
- }));
141181
141134
  }
141182
141135
  function createDataProvider(config4) {
141183
141136
  const matrixosHome = config4?.matrixosHome ?? ".matrixos";
141137
+ const version3 = readPackageVersion2();
141184
141138
  function readJsonl(filePath) {
141185
141139
  try {
141186
141140
  const fullPath = path24.resolve(matrixosHome, "logs", filePath);
@@ -141196,13 +141150,33 @@ function createDataProvider(config4) {
141196
141150
  async getHealth() {
141197
141151
  const mem = process.memoryUsage();
141198
141152
  const totalMem = os12.totalmem();
141153
+ const db = getDb();
141154
+ let agentsOnline = AGENT_NAMES.length;
141155
+ let activeSessions = 0;
141156
+ let tasksQueued = 0;
141157
+ if (db) {
141158
+ try {
141159
+ const agentRow = db.query("SELECT COUNT(DISTINCT agent) as count FROM session").get();
141160
+ if (agentRow)
141161
+ agentsOnline = agentRow.count;
141162
+ const cutoff = Date.now() - THIRTY_MIN_MS;
141163
+ const sessionRows = db.query("SELECT COUNT(*) as count FROM session WHERE time_archived IS NULL AND time_updated > ?").all(cutoff);
141164
+ if (sessionRows.length > 0)
141165
+ activeSessions = sessionRows[0].count;
141166
+ const todoRows = db.query("SELECT COUNT(*) as count FROM todo WHERE status = 'pending'").all();
141167
+ if (todoRows.length > 0)
141168
+ tasksQueued = todoRows[0].count;
141169
+ } catch {} finally {
141170
+ db.close();
141171
+ }
141172
+ }
141199
141173
  return {
141200
- agentsOnline: AGENT_NAMES.length - randomBetween(1, 3),
141174
+ agentsOnline,
141201
141175
  totalAgents: AGENT_NAMES.length,
141202
- activeSessions: randomBetween(2, 8),
141203
- tasksQueued: randomBetween(5, 20),
141176
+ activeSessions,
141177
+ tasksQueued,
141204
141178
  uptime: process.uptime(),
141205
- version: "0.1.0",
141179
+ version: version3,
141206
141180
  memoryUsage: {
141207
141181
  used: Math.round(mem.rss / 1024 / 1024),
141208
141182
  total: Math.round(totalMem / 1024 / 1024),
@@ -141212,16 +141186,181 @@ function createDataProvider(config4) {
141212
141186
  };
141213
141187
  },
141214
141188
  async getAgents() {
141215
- return generateMockAgents();
141189
+ const db = getDb();
141190
+ if (db) {
141191
+ try {
141192
+ const cutoff = Date.now() - THIRTY_MIN_MS;
141193
+ const rows = db.query(`SELECT agent, COUNT(*) as sessions
141194
+ FROM session
141195
+ WHERE agent IS NOT NULL AND agent != ''
141196
+ GROUP BY agent`).all();
141197
+ if (rows.length > 0) {
141198
+ const result = [];
141199
+ for (const row of rows) {
141200
+ const name2 = row.agent;
141201
+ const onlineRows = db.query("SELECT COUNT(*) as count FROM session WHERE agent = ? AND time_updated > ?").all(name2, cutoff);
141202
+ const status2 = onlineRows.length > 0 && onlineRows[0].count > 0 ? "online" : "idle";
141203
+ result.push({
141204
+ name: name2,
141205
+ role: AGENT_ROLES[name2] ?? "Agent",
141206
+ status: status2,
141207
+ sessions: row.sessions,
141208
+ uptime: 0,
141209
+ cpuPercent: 0,
141210
+ memoryPercent: 0
141211
+ });
141212
+ }
141213
+ db.close();
141214
+ return result;
141215
+ }
141216
+ } catch {} finally {
141217
+ db.close();
141218
+ }
141219
+ }
141220
+ return AGENT_NAMES.map((name2) => ({
141221
+ name: name2,
141222
+ role: AGENT_ROLES[name2] ?? "Agent",
141223
+ status: "idle",
141224
+ sessions: 0,
141225
+ uptime: 0,
141226
+ cpuPercent: 0,
141227
+ memoryPercent: 0
141228
+ }));
141216
141229
  },
141217
141230
  async getSessions(limit = 20) {
141218
- return generateMockSessions(limit).slice(0, limit);
141231
+ const db = getDb();
141232
+ if (!db)
141233
+ return [];
141234
+ try {
141235
+ const now = Date.now();
141236
+ const rows = db.query(`SELECT id, title, agent, model, cost, time_created, time_updated, time_archived
141237
+ FROM session
141238
+ ORDER BY time_updated DESC
141239
+ LIMIT ?`).all(limit);
141240
+ const result = [];
141241
+ for (const row of rows) {
141242
+ const duration3 = Math.max(0, Math.round((row.time_updated - row.time_created) / 1000));
141243
+ let status2 = "completed";
141244
+ if (row.time_archived !== null) {
141245
+ status2 = "completed";
141246
+ } else if (row.time_updated > now - FIVE_MIN_MS) {
141247
+ status2 = "active";
141248
+ } else {
141249
+ status2 = "completed";
141250
+ }
141251
+ result.push({
141252
+ id: row.id,
141253
+ agent: row.agent ?? "unknown",
141254
+ model: parseModel(row.model),
141255
+ duration: duration3,
141256
+ cost: row.cost,
141257
+ status: status2,
141258
+ startedAt: new Date(row.time_created).toISOString()
141259
+ });
141260
+ }
141261
+ return result;
141262
+ } catch {
141263
+ return [];
141264
+ } finally {
141265
+ db.close();
141266
+ }
141219
141267
  },
141220
141268
  async getCost() {
141221
- return generateMockCost();
141269
+ const db = getDb();
141270
+ if (!db) {
141271
+ return {
141272
+ total: 0,
141273
+ daily: 0,
141274
+ monthly: 0,
141275
+ budgetRemaining: BUDGET_TOTAL,
141276
+ byAgent: [],
141277
+ byDay: [],
141278
+ alerts: []
141279
+ };
141280
+ }
141281
+ try {
141282
+ const totalRows = db.query("SELECT COALESCE(SUM(cost), 0) as sum FROM session").all();
141283
+ const total = totalRows.length > 0 ? totalRows[0].sum ?? 0 : 0;
141284
+ const dailyRows = db.query("SELECT COALESCE(SUM(cost), 0) as sum FROM session WHERE time_created > ?").all(midnightMs());
141285
+ const daily = dailyRows.length > 0 ? dailyRows[0].sum ?? 0 : 0;
141286
+ const monthlyRows = db.query("SELECT COALESCE(SUM(cost), 0) as sum FROM session WHERE time_created > ?").all(thirtyDaysAgoMs());
141287
+ const monthly = monthlyRows.length > 0 ? monthlyRows[0].sum ?? 0 : 0;
141288
+ const agentRows = db.query(`SELECT agent, COALESCE(SUM(cost), 0) as cost
141289
+ FROM session
141290
+ WHERE agent IS NOT NULL AND agent != ''
141291
+ GROUP BY agent`).all();
141292
+ const byAgent = agentRows.map((r2) => ({
141293
+ agent: r2.agent,
141294
+ cost: r2.cost,
141295
+ percentage: total > 0 ? Math.round(r2.cost / total * 100) : 0
141296
+ }));
141297
+ const byDayRows = db.query(`SELECT strftime('%Y-%m-%d', time_created / 1000, 'unixepoch') as day,
141298
+ COALESCE(SUM(cost), 0) as cost
141299
+ FROM session
141300
+ WHERE time_created > ?
141301
+ GROUP BY day
141302
+ ORDER BY day ASC`).all(thirtyDaysAgoMs());
141303
+ const byDayMap = new Map;
141304
+ for (const r2 of byDayRows) {
141305
+ byDayMap.set(r2.day, r2.cost);
141306
+ }
141307
+ const byDay = [];
141308
+ const today = new Date;
141309
+ for (let i3 = 29;i3 >= 0; i3--) {
141310
+ const d = new Date(today);
141311
+ d.setDate(d.getDate() - i3);
141312
+ const key = d.toISOString().slice(0, 10);
141313
+ byDay.push({ date: key, cost: byDayMap.get(key) ?? 0 });
141314
+ }
141315
+ const budgetRemaining = Math.max(0, BUDGET_TOTAL - total);
141316
+ const alerts = [];
141317
+ if (total > BUDGET_TOTAL) {
141318
+ alerts.push({ severity: "critical", message: `Total cost $${total.toFixed(2)} exceeds budget $${BUDGET_TOTAL}` });
141319
+ } else if (total > BUDGET_TOTAL * 0.85) {
141320
+ alerts.push({ severity: "warning", message: `Cost $${total.toFixed(2)} approaching budget threshold (85%)` });
141321
+ }
141322
+ return { total, daily, monthly, budgetRemaining, byAgent, byDay, alerts };
141323
+ } catch {
141324
+ return {
141325
+ total: 0,
141326
+ daily: 0,
141327
+ monthly: 0,
141328
+ budgetRemaining: BUDGET_TOTAL,
141329
+ byAgent: [],
141330
+ byDay: [],
141331
+ alerts: []
141332
+ };
141333
+ } finally {
141334
+ db.close();
141335
+ }
141222
141336
  },
141223
141337
  async getKanbanTasks() {
141224
- return generateMockKanban();
141338
+ const board = { columns: { pending: [], in_progress: [], completed: [], failed: [] } };
141339
+ const db = getDb();
141340
+ if (!db)
141341
+ return board;
141342
+ try {
141343
+ const rows = db.query("SELECT content, status, priority, time_created, time_updated FROM todo ORDER BY time_updated DESC").all();
141344
+ let idx = 0;
141345
+ for (const row of rows) {
141346
+ const status2 = row.status;
141347
+ if (!board.columns[status2])
141348
+ continue;
141349
+ const task2 = {
141350
+ id: `todo_${idx++}`,
141351
+ title: row.content,
141352
+ agent: "Unknown",
141353
+ priority: row.priority ?? "medium",
141354
+ status: status2,
141355
+ createdAt: new Date(row.time_created).toISOString(),
141356
+ updatedAt: new Date(row.time_updated).toISOString()
141357
+ };
141358
+ board.columns[status2].push(task2);
141359
+ }
141360
+ } catch {} finally {
141361
+ db.close();
141362
+ }
141363
+ return board;
141225
141364
  },
141226
141365
  async getIncidents(limit = 50) {
141227
141366
  const lines = readJsonl("anti-loop.jsonl");
@@ -141245,7 +141384,33 @@ function createDataProvider(config4) {
141245
141384
  }).filter(Boolean);
141246
141385
  },
141247
141386
  async getMetrics() {
141248
- return generateMockMetrics();
141387
+ const db = getDb();
141388
+ let activeSessions = 0;
141389
+ if (db) {
141390
+ try {
141391
+ const cutoff = Date.now() - THIRTY_MIN_MS;
141392
+ const rows = db.query("SELECT COUNT(*) as count FROM session WHERE time_archived IS NULL AND time_updated > ?").all(cutoff);
141393
+ if (rows.length > 0)
141394
+ activeSessions = rows[0].count;
141395
+ } catch {} finally {
141396
+ db.close();
141397
+ }
141398
+ }
141399
+ const totalMem = os12.totalmem();
141400
+ const mem = process.memoryUsage();
141401
+ const memPercent = Math.round(mem.rss / totalMem * 100);
141402
+ const cpuPercent = Math.round(os12.loadavg()[0] * 100);
141403
+ const snapshots = [];
141404
+ for (let i3 = 0;i3 < 60; i3++) {
141405
+ snapshots.push({
141406
+ timestamp: Date.now() - (59 - i3) * 60000,
141407
+ cpuPercent,
141408
+ memoryPercent: memPercent,
141409
+ diskPercent: 0,
141410
+ sessionsActive: activeSessions
141411
+ });
141412
+ }
141413
+ return snapshots;
141249
141414
  },
141250
141415
  getLogs() {
141251
141416
  const logFiles = [
@@ -141592,7 +141757,7 @@ function createDashboardServer(dataProvider, config4) {
141592
141757
  // packages/omo-opencode/src/cli/dashboard.ts
141593
141758
  async function dashboardCli(options) {
141594
141759
  const port = options.port ?? 9123;
141595
- const host = options.host ?? "127.0.0.1";
141760
+ const host = options.host ?? "0.0.0.0";
141596
141761
  const frontendDir = path25.resolve(import.meta.dir, "../features/dashboard/frontend");
141597
141762
  console.log(`[dashboard] starting MaTrixOS dashboard on http://${host}:${port}`);
141598
141763
  console.log(`[dashboard] frontend: ${frontendDir}`);
@@ -141914,7 +142079,7 @@ function configureRuntimeCommands(program2) {
141914
142079
  const exitCode = await architectRollback({ ...options, id });
141915
142080
  process.exit(exitCode);
141916
142081
  });
141917
- program2.command("dashboard").description("Start the MaTrixOS web dashboard (port 9123)").option("-p, --port <number>", "HTTP port", "9123").option("--host <addr>", "Bind address", "127.0.0.1").option("--daemon", "Run in background (no Ctrl+C)").action(async (options) => {
142082
+ program2.command("dashboard").description("Start the MaTrixOS web dashboard (port 9123)").option("-p, --port <number>", "HTTP port", "9123").option("--host <addr>", "Bind address", "0.0.0.0").option("--daemon", "Run in background (no Ctrl+C)").action(async (options) => {
141918
142083
  const exitCode = await dashboardCli({
141919
142084
  port: parseInt(options.port ?? "9123", 10),
141920
142085
  host: options.host,
@@ -23,11 +23,13 @@
23
23
  <div class="sidebar-section">Operations</div>
24
24
  <a href="#" class="sidebar-item" data-tab="health"><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>Incidents<span class="sidebar-badge danger" id="badgeIncidents">3</span></a>
25
25
  <a href="#" class="sidebar-item" data-tab="logs"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M14 2H2v12h12V2z"/><path d="M5 8h6M5 11h4"/></svg>Logs</a>
26
- <a href="#" class="sidebar-item"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 14A6 6 0 108 2a6 6 0 000 12z"/><path d="M8 5v3l2 2"/></svg>Schedule</a>
26
+ <a href="#" class="sidebar-item" data-tab="schedule"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 14A6 6 0 108 2a6 6 0 000 12z"/><path d="M8 5v3l2 2"/></svg>Schedule</a>
27
+ <a href="#" class="sidebar-item" data-tab="memory"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="2" y="3" width="12" height="11" rx="1"/><path d="M2 6h12"/><circle cx="8" cy="10" r="1.5"/></svg>Memory</a>
28
+ <a href="#" class="sidebar-item" data-tab="skills"><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="6" r="3"/><path d="M3 14c0-3 2.5-5 5-5s5 2 5 5"/></svg>Skills</a>
27
29
  <div class="sidebar-section">System</div>
28
30
  <a href="#" class="sidebar-item" data-tab="config"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="2" y="2" width="12" height="12" rx="2"/><path d="M6 6h4M6 8h4M6 10h2"/></svg>Config</a>
29
- <a href="#" class="sidebar-item"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M12 8A4 4 0 114 8a4 4 0 018 0z"/><path d="M8 2v1M8 13v1M2 8h1M13 8h1"/></svg>Settings</a>
30
- <a href="#" class="sidebar-item"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M9 2H4a1 1 0 00-1 1v10a1 1 0 001 1h8a1 1 0 001-1V7l-5-5z"/><path d="M9 2v5h5"/></svg>Audit Trail</a>
31
+ <a href="#" class="sidebar-item" data-tab="config"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M12 8A4 4 0 114 8a4 4 0 018 0z"/><path d="M8 2v1M8 13v1M2 8h1M13 8h1"/></svg>Settings</a>
32
+ <a href="#" class="sidebar-item" data-tab="logs"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M9 2H4a1 1 0 00-1 1v10a1 1 0 001 1h8a1 1 0 001-1V7l-5-5z"/><path d="M9 2v5h5"/></svg>Audit Trail</a>
31
33
  </nav>
32
34
  <div class="sidebar-footer">
33
35
  <div class="sidebar-avatar">SM</div>
@@ -165,6 +167,13 @@
165
167
  </div>
166
168
  <div class="card"><div class="card-header"><span class="card-title">matrixos.jsonc</span><span id="configStatus" style="font-size:var(--text-xs);color:var(--text-tertiary)"></span></div><div class="card-body"><textarea id="configEditor" class="config-editor" spellcheck="false"></textarea></div></div>
167
169
  </div>
170
+
171
+ <div id="tab-schedule" class="tab-panel">
172
+ <div class="page-header">
173
+ <div><h1 class="page-title">Schedule</h1><p class="page-subtitle">Cron jobs and scheduled tasks for MaTrixOS agents</p></div>
174
+ </div>
175
+ <div class="card"><div class="card-body" id="scheduleBody"></div></div>
176
+ </div>
168
177
  </div>
169
178
  </div>
170
179
  <script src="js/api.js"></script>
@@ -10,7 +10,7 @@ document.querySelectorAll('[data-tab]').forEach(el=>{
10
10
  el.addEventListener('click',e=>{
11
11
  e.preventDefault()
12
12
  const tab=el.dataset.tab
13
- if(!tab||!['architect','health','cost','kanban','agents','sessions','logs','config'].includes(tab))return
13
+ if(!tab||!['architect','health','cost','kanban','agents','sessions','logs','config','memory','skills','schedule'].includes(tab))return
14
14
  const realTab=tab==='agents'||tab==='sessions'?'architect':tab
15
15
  document.querySelectorAll('.sidebar-item.active,.header-tab.active,.tab-panel.active').forEach(n=>n.classList.remove('active'))
16
16
  document.querySelectorAll(`.sidebar-item[data-tab="${tab}"],.header-tab[data-tab="${realTab}"]`).forEach(n=>n.classList.add('active'))
@@ -20,7 +20,7 @@ document.querySelectorAll('[data-tab]').forEach(el=>{
20
20
  })
21
21
 
22
22
  // Tab loading dispatch
23
- function loadTab(tab){const f={architect:loadArchitect,health:loadHealth,cost:loadCost,kanban:loadKanban,logs:loadLogs,config:loadConfig,memory:loadMemory,skills:loadSkills}[tab];f&&f()}
23
+ function loadTab(tab){const f={architect:loadArchitect,health:loadHealth,cost:loadCost,kanban:loadKanban,logs:loadLogs,config:loadConfig,memory:loadMemory,skills:loadSkills,schedule:loadSchedule}[tab];f&&f()}
24
24
 
25
25
  // Skeleton helpers
26
26
  function showSkeleton(container,type,count=4){
@@ -338,6 +338,16 @@ async function loadSkills(){
338
338
  }catch(e){grid.innerHTML=`<div class="error"><p>Failed to load skills: ${e.message}</p></div>`}
339
339
  }
340
340
 
341
+ // ===== SCHEDULE =====
342
+ function loadSchedule(){
343
+ const body=document.getElementById('scheduleBody')
344
+ if(!body)return
345
+ body.innerHTML=`<div class="empty" style="padding:40px">
346
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
347
+ <p>Schedule feature not configured — enable cron in matrixos.jsonc to start scheduling agent tasks.</p>
348
+ </div>`
349
+ }
350
+
341
351
  // ===== INIT =====
342
352
  document.getElementById('refreshBtn').onclick=()=>{const t=document.querySelector('.header-tab.active');t&&loadTab(t.dataset.tab)}
343
353
  document.getElementById('archRefresh').onclick=()=>loadArchitect()
package/dist/index.js CHANGED
@@ -367932,7 +367932,7 @@ function getCachedVersion(options = {}) {
367932
367932
  // package.json
367933
367933
  var package_default = {
367934
367934
  name: "@kl-c/matrixos",
367935
- version: "0.1.17",
367935
+ version: "0.1.18",
367936
367936
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
367937
367937
  main: "./dist/index.js",
367938
367938
  types: "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kl-c/matrixos",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
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",