@kl-c/matrixos 0.3.27 → 0.3.28
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 +131 -9
- package/dist/cli-node/index.js +131 -9
- package/dist/features/dashboard/data-provider.d.ts +23 -0
- package/dist/features/dashboard/frontend/css/style.css +17 -0
- package/dist/features/dashboard/frontend/js/api.js +22 -2
- package/dist/features/dashboard/frontend/js/app.js +101 -10
- package/dist/index.js +1 -1
- package/package.json +1 -1
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.
|
|
2166
|
+
version: "0.3.28",
|
|
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",
|
|
@@ -186929,6 +186929,30 @@ function getDb() {
|
|
|
186929
186929
|
return;
|
|
186930
186930
|
}
|
|
186931
186931
|
}
|
|
186932
|
+
function getDbWrite() {
|
|
186933
|
+
if (!fs21.existsSync(OPENCODE_DB_PATH))
|
|
186934
|
+
return;
|
|
186935
|
+
try {
|
|
186936
|
+
const db = new Database5(OPENCODE_DB_PATH);
|
|
186937
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
186938
|
+
return db;
|
|
186939
|
+
} catch {
|
|
186940
|
+
return;
|
|
186941
|
+
}
|
|
186942
|
+
}
|
|
186943
|
+
function ensureKanbanTable(db) {
|
|
186944
|
+
db.exec(`
|
|
186945
|
+
CREATE TABLE IF NOT EXISTS matrixos_kanban (
|
|
186946
|
+
id TEXT PRIMARY KEY,
|
|
186947
|
+
title TEXT NOT NULL,
|
|
186948
|
+
agent TEXT NOT NULL DEFAULT 'Unknown',
|
|
186949
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
186950
|
+
priority TEXT NOT NULL DEFAULT 'medium',
|
|
186951
|
+
created_at INTEGER NOT NULL,
|
|
186952
|
+
updated_at INTEGER NOT NULL
|
|
186953
|
+
)
|
|
186954
|
+
`);
|
|
186955
|
+
}
|
|
186932
186956
|
function midnightMs() {
|
|
186933
186957
|
const d = new Date;
|
|
186934
186958
|
d.setHours(0, 0, 0, 0);
|
|
@@ -187191,24 +187215,24 @@ function createDataProvider(config5) {
|
|
|
187191
187215
|
},
|
|
187192
187216
|
async getKanbanTasks() {
|
|
187193
187217
|
const board = { columns: { pending: [], in_progress: [], completed: [], failed: [] } };
|
|
187194
|
-
const db =
|
|
187218
|
+
const db = getDbWrite();
|
|
187195
187219
|
if (!db)
|
|
187196
187220
|
return board;
|
|
187197
187221
|
try {
|
|
187198
|
-
|
|
187199
|
-
|
|
187222
|
+
ensureKanbanTable(db);
|
|
187223
|
+
const rows = db.query("SELECT id, title, agent, status, priority, created_at, updated_at FROM matrixos_kanban ORDER BY updated_at DESC").all();
|
|
187200
187224
|
for (const row of rows) {
|
|
187201
187225
|
const status2 = row.status;
|
|
187202
187226
|
if (!board.columns[status2])
|
|
187203
187227
|
continue;
|
|
187204
187228
|
const task2 = {
|
|
187205
|
-
id:
|
|
187206
|
-
title: row.
|
|
187207
|
-
agent: "Unknown",
|
|
187229
|
+
id: row.id,
|
|
187230
|
+
title: row.title,
|
|
187231
|
+
agent: row.agent || "Unknown",
|
|
187208
187232
|
priority: row.priority ?? "medium",
|
|
187209
187233
|
status: status2,
|
|
187210
|
-
createdAt: new Date(row.
|
|
187211
|
-
updatedAt: new Date(row.
|
|
187234
|
+
createdAt: new Date(row.created_at).toISOString(),
|
|
187235
|
+
updatedAt: new Date(row.updated_at).toISOString()
|
|
187212
187236
|
};
|
|
187213
187237
|
board.columns[status2].push(task2);
|
|
187214
187238
|
}
|
|
@@ -187217,6 +187241,76 @@ function createDataProvider(config5) {
|
|
|
187217
187241
|
}
|
|
187218
187242
|
return board;
|
|
187219
187243
|
},
|
|
187244
|
+
async createKanbanTask(input) {
|
|
187245
|
+
const db = getDbWrite();
|
|
187246
|
+
if (!db)
|
|
187247
|
+
return { ok: false, error: "database unavailable" };
|
|
187248
|
+
try {
|
|
187249
|
+
ensureKanbanTable(db);
|
|
187250
|
+
const id = `kb_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
187251
|
+
const now = Date.now();
|
|
187252
|
+
const status2 = input.status ?? "pending";
|
|
187253
|
+
const priority = input.priority ?? "medium";
|
|
187254
|
+
db.query("INSERT INTO matrixos_kanban (id, title, agent, status, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run(id, input.title, input.agent ?? "Unknown", status2, priority, now, now);
|
|
187255
|
+
return { ok: true, id };
|
|
187256
|
+
} catch (e) {
|
|
187257
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
187258
|
+
} finally {
|
|
187259
|
+
db.close();
|
|
187260
|
+
}
|
|
187261
|
+
},
|
|
187262
|
+
async updateKanbanTask(id, input) {
|
|
187263
|
+
const db = getDbWrite();
|
|
187264
|
+
if (!db)
|
|
187265
|
+
return { ok: false, error: "database unavailable" };
|
|
187266
|
+
try {
|
|
187267
|
+
ensureKanbanTable(db);
|
|
187268
|
+
const existing = db.query("SELECT id FROM matrixos_kanban WHERE id = ?").get(id);
|
|
187269
|
+
if (!existing)
|
|
187270
|
+
return { ok: false, error: "task not found" };
|
|
187271
|
+
const sets = [];
|
|
187272
|
+
const params = [];
|
|
187273
|
+
if (input.title !== undefined) {
|
|
187274
|
+
sets.push("title = ?");
|
|
187275
|
+
params.push(input.title);
|
|
187276
|
+
}
|
|
187277
|
+
if (input.agent !== undefined) {
|
|
187278
|
+
sets.push("agent = ?");
|
|
187279
|
+
params.push(input.agent);
|
|
187280
|
+
}
|
|
187281
|
+
if (input.status !== undefined) {
|
|
187282
|
+
sets.push("status = ?");
|
|
187283
|
+
params.push(input.status);
|
|
187284
|
+
}
|
|
187285
|
+
if (input.priority !== undefined) {
|
|
187286
|
+
sets.push("priority = ?");
|
|
187287
|
+
params.push(input.priority);
|
|
187288
|
+
}
|
|
187289
|
+
sets.push("updated_at = ?");
|
|
187290
|
+
params.push(String(Date.now()));
|
|
187291
|
+
params.push(id);
|
|
187292
|
+
db.query(`UPDATE matrixos_kanban SET ${sets.join(", ")} WHERE id = ?`).run(...params);
|
|
187293
|
+
return { ok: true };
|
|
187294
|
+
} catch (e) {
|
|
187295
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
187296
|
+
} finally {
|
|
187297
|
+
db.close();
|
|
187298
|
+
}
|
|
187299
|
+
},
|
|
187300
|
+
async deleteKanbanTask(id) {
|
|
187301
|
+
const db = getDbWrite();
|
|
187302
|
+
if (!db)
|
|
187303
|
+
return { ok: false, error: "database unavailable" };
|
|
187304
|
+
try {
|
|
187305
|
+
ensureKanbanTable(db);
|
|
187306
|
+
db.query("DELETE FROM matrixos_kanban WHERE id = ?").run(id);
|
|
187307
|
+
return { ok: true };
|
|
187308
|
+
} catch (e) {
|
|
187309
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
187310
|
+
} finally {
|
|
187311
|
+
db.close();
|
|
187312
|
+
}
|
|
187313
|
+
},
|
|
187220
187314
|
async getIncidents(limit = 50) {
|
|
187221
187315
|
const lines = readJsonl("anti-loop.jsonl");
|
|
187222
187316
|
if (lines.length === 0) {
|
|
@@ -187530,6 +187624,34 @@ function createDashboardServer(dataProvider, config5) {
|
|
|
187530
187624
|
return Response.json(await dataProvider.getCost(), { headers: jsonHeaders });
|
|
187531
187625
|
case "/api/kanban":
|
|
187532
187626
|
return Response.json(await dataProvider.getKanbanTasks(), { headers: jsonHeaders });
|
|
187627
|
+
case "/api/kanban/task": {
|
|
187628
|
+
if (req.method === "POST") {
|
|
187629
|
+
const body = await req.json();
|
|
187630
|
+
if (!body.title || !body.title.trim()) {
|
|
187631
|
+
return Response.json({ ok: false, error: "title required" }, { status: 400, headers: jsonHeaders });
|
|
187632
|
+
}
|
|
187633
|
+
const result = await dataProvider.createKanbanTask(body);
|
|
187634
|
+
return Response.json(result, { status: result.ok ? 201 : 500, headers: jsonHeaders });
|
|
187635
|
+
}
|
|
187636
|
+
if (req.method === "PUT") {
|
|
187637
|
+
const body = await req.json();
|
|
187638
|
+
if (!body.id) {
|
|
187639
|
+
return Response.json({ ok: false, error: "id required" }, { status: 400, headers: jsonHeaders });
|
|
187640
|
+
}
|
|
187641
|
+
const result = await dataProvider.updateKanbanTask(body.id, body);
|
|
187642
|
+
return Response.json(result, { status: result.ok ? 200 : 500, headers: jsonHeaders });
|
|
187643
|
+
}
|
|
187644
|
+
if (req.method === "DELETE") {
|
|
187645
|
+
const url22 = new URL(req.url);
|
|
187646
|
+
const id = url22.searchParams.get("id");
|
|
187647
|
+
if (!id) {
|
|
187648
|
+
return Response.json({ ok: false, error: "id required" }, { status: 400, headers: jsonHeaders });
|
|
187649
|
+
}
|
|
187650
|
+
const result = await dataProvider.deleteKanbanTask(id);
|
|
187651
|
+
return Response.json(result, { status: result.ok ? 200 : 500, headers: jsonHeaders });
|
|
187652
|
+
}
|
|
187653
|
+
return new Response("Method Not Allowed", { status: 405, headers: corsHeaders });
|
|
187654
|
+
}
|
|
187533
187655
|
case "/api/incidents": {
|
|
187534
187656
|
const limit = parseInt(url3.searchParams.get("limit") ?? "50", 10);
|
|
187535
187657
|
return Response.json(await dataProvider.getIncidents(limit), { headers: jsonHeaders });
|
package/dist/cli-node/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.
|
|
2166
|
+
version: "0.3.28",
|
|
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",
|
|
@@ -186984,6 +186984,30 @@ function getDb() {
|
|
|
186984
186984
|
return;
|
|
186985
186985
|
}
|
|
186986
186986
|
}
|
|
186987
|
+
function getDbWrite() {
|
|
186988
|
+
if (!fs21.existsSync(OPENCODE_DB_PATH))
|
|
186989
|
+
return;
|
|
186990
|
+
try {
|
|
186991
|
+
const db = new Database5(OPENCODE_DB_PATH);
|
|
186992
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
186993
|
+
return db;
|
|
186994
|
+
} catch {
|
|
186995
|
+
return;
|
|
186996
|
+
}
|
|
186997
|
+
}
|
|
186998
|
+
function ensureKanbanTable(db) {
|
|
186999
|
+
db.exec(`
|
|
187000
|
+
CREATE TABLE IF NOT EXISTS matrixos_kanban (
|
|
187001
|
+
id TEXT PRIMARY KEY,
|
|
187002
|
+
title TEXT NOT NULL,
|
|
187003
|
+
agent TEXT NOT NULL DEFAULT 'Unknown',
|
|
187004
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
187005
|
+
priority TEXT NOT NULL DEFAULT 'medium',
|
|
187006
|
+
created_at INTEGER NOT NULL,
|
|
187007
|
+
updated_at INTEGER NOT NULL
|
|
187008
|
+
)
|
|
187009
|
+
`);
|
|
187010
|
+
}
|
|
186987
187011
|
function midnightMs() {
|
|
186988
187012
|
const d = new Date;
|
|
186989
187013
|
d.setHours(0, 0, 0, 0);
|
|
@@ -187246,24 +187270,24 @@ function createDataProvider(config5) {
|
|
|
187246
187270
|
},
|
|
187247
187271
|
async getKanbanTasks() {
|
|
187248
187272
|
const board = { columns: { pending: [], in_progress: [], completed: [], failed: [] } };
|
|
187249
|
-
const db =
|
|
187273
|
+
const db = getDbWrite();
|
|
187250
187274
|
if (!db)
|
|
187251
187275
|
return board;
|
|
187252
187276
|
try {
|
|
187253
|
-
|
|
187254
|
-
|
|
187277
|
+
ensureKanbanTable(db);
|
|
187278
|
+
const rows = db.query("SELECT id, title, agent, status, priority, created_at, updated_at FROM matrixos_kanban ORDER BY updated_at DESC").all();
|
|
187255
187279
|
for (const row of rows) {
|
|
187256
187280
|
const status2 = row.status;
|
|
187257
187281
|
if (!board.columns[status2])
|
|
187258
187282
|
continue;
|
|
187259
187283
|
const task2 = {
|
|
187260
|
-
id:
|
|
187261
|
-
title: row.
|
|
187262
|
-
agent: "Unknown",
|
|
187284
|
+
id: row.id,
|
|
187285
|
+
title: row.title,
|
|
187286
|
+
agent: row.agent || "Unknown",
|
|
187263
187287
|
priority: row.priority ?? "medium",
|
|
187264
187288
|
status: status2,
|
|
187265
|
-
createdAt: new Date(row.
|
|
187266
|
-
updatedAt: new Date(row.
|
|
187289
|
+
createdAt: new Date(row.created_at).toISOString(),
|
|
187290
|
+
updatedAt: new Date(row.updated_at).toISOString()
|
|
187267
187291
|
};
|
|
187268
187292
|
board.columns[status2].push(task2);
|
|
187269
187293
|
}
|
|
@@ -187272,6 +187296,76 @@ function createDataProvider(config5) {
|
|
|
187272
187296
|
}
|
|
187273
187297
|
return board;
|
|
187274
187298
|
},
|
|
187299
|
+
async createKanbanTask(input) {
|
|
187300
|
+
const db = getDbWrite();
|
|
187301
|
+
if (!db)
|
|
187302
|
+
return { ok: false, error: "database unavailable" };
|
|
187303
|
+
try {
|
|
187304
|
+
ensureKanbanTable(db);
|
|
187305
|
+
const id = `kb_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
187306
|
+
const now = Date.now();
|
|
187307
|
+
const status2 = input.status ?? "pending";
|
|
187308
|
+
const priority = input.priority ?? "medium";
|
|
187309
|
+
db.query("INSERT INTO matrixos_kanban (id, title, agent, status, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run(id, input.title, input.agent ?? "Unknown", status2, priority, now, now);
|
|
187310
|
+
return { ok: true, id };
|
|
187311
|
+
} catch (e) {
|
|
187312
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
187313
|
+
} finally {
|
|
187314
|
+
db.close();
|
|
187315
|
+
}
|
|
187316
|
+
},
|
|
187317
|
+
async updateKanbanTask(id, input) {
|
|
187318
|
+
const db = getDbWrite();
|
|
187319
|
+
if (!db)
|
|
187320
|
+
return { ok: false, error: "database unavailable" };
|
|
187321
|
+
try {
|
|
187322
|
+
ensureKanbanTable(db);
|
|
187323
|
+
const existing = db.query("SELECT id FROM matrixos_kanban WHERE id = ?").get(id);
|
|
187324
|
+
if (!existing)
|
|
187325
|
+
return { ok: false, error: "task not found" };
|
|
187326
|
+
const sets = [];
|
|
187327
|
+
const params = [];
|
|
187328
|
+
if (input.title !== undefined) {
|
|
187329
|
+
sets.push("title = ?");
|
|
187330
|
+
params.push(input.title);
|
|
187331
|
+
}
|
|
187332
|
+
if (input.agent !== undefined) {
|
|
187333
|
+
sets.push("agent = ?");
|
|
187334
|
+
params.push(input.agent);
|
|
187335
|
+
}
|
|
187336
|
+
if (input.status !== undefined) {
|
|
187337
|
+
sets.push("status = ?");
|
|
187338
|
+
params.push(input.status);
|
|
187339
|
+
}
|
|
187340
|
+
if (input.priority !== undefined) {
|
|
187341
|
+
sets.push("priority = ?");
|
|
187342
|
+
params.push(input.priority);
|
|
187343
|
+
}
|
|
187344
|
+
sets.push("updated_at = ?");
|
|
187345
|
+
params.push(String(Date.now()));
|
|
187346
|
+
params.push(id);
|
|
187347
|
+
db.query(`UPDATE matrixos_kanban SET ${sets.join(", ")} WHERE id = ?`).run(...params);
|
|
187348
|
+
return { ok: true };
|
|
187349
|
+
} catch (e) {
|
|
187350
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
187351
|
+
} finally {
|
|
187352
|
+
db.close();
|
|
187353
|
+
}
|
|
187354
|
+
},
|
|
187355
|
+
async deleteKanbanTask(id) {
|
|
187356
|
+
const db = getDbWrite();
|
|
187357
|
+
if (!db)
|
|
187358
|
+
return { ok: false, error: "database unavailable" };
|
|
187359
|
+
try {
|
|
187360
|
+
ensureKanbanTable(db);
|
|
187361
|
+
db.query("DELETE FROM matrixos_kanban WHERE id = ?").run(id);
|
|
187362
|
+
return { ok: true };
|
|
187363
|
+
} catch (e) {
|
|
187364
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
187365
|
+
} finally {
|
|
187366
|
+
db.close();
|
|
187367
|
+
}
|
|
187368
|
+
},
|
|
187275
187369
|
async getIncidents(limit = 50) {
|
|
187276
187370
|
const lines = readJsonl("anti-loop.jsonl");
|
|
187277
187371
|
if (lines.length === 0) {
|
|
@@ -187585,6 +187679,34 @@ function createDashboardServer(dataProvider, config5) {
|
|
|
187585
187679
|
return Response.json(await dataProvider.getCost(), { headers: jsonHeaders });
|
|
187586
187680
|
case "/api/kanban":
|
|
187587
187681
|
return Response.json(await dataProvider.getKanbanTasks(), { headers: jsonHeaders });
|
|
187682
|
+
case "/api/kanban/task": {
|
|
187683
|
+
if (req.method === "POST") {
|
|
187684
|
+
const body = await req.json();
|
|
187685
|
+
if (!body.title || !body.title.trim()) {
|
|
187686
|
+
return Response.json({ ok: false, error: "title required" }, { status: 400, headers: jsonHeaders });
|
|
187687
|
+
}
|
|
187688
|
+
const result = await dataProvider.createKanbanTask(body);
|
|
187689
|
+
return Response.json(result, { status: result.ok ? 201 : 500, headers: jsonHeaders });
|
|
187690
|
+
}
|
|
187691
|
+
if (req.method === "PUT") {
|
|
187692
|
+
const body = await req.json();
|
|
187693
|
+
if (!body.id) {
|
|
187694
|
+
return Response.json({ ok: false, error: "id required" }, { status: 400, headers: jsonHeaders });
|
|
187695
|
+
}
|
|
187696
|
+
const result = await dataProvider.updateKanbanTask(body.id, body);
|
|
187697
|
+
return Response.json(result, { status: result.ok ? 200 : 500, headers: jsonHeaders });
|
|
187698
|
+
}
|
|
187699
|
+
if (req.method === "DELETE") {
|
|
187700
|
+
const url22 = new URL(req.url);
|
|
187701
|
+
const id = url22.searchParams.get("id");
|
|
187702
|
+
if (!id) {
|
|
187703
|
+
return Response.json({ ok: false, error: "id required" }, { status: 400, headers: jsonHeaders });
|
|
187704
|
+
}
|
|
187705
|
+
const result = await dataProvider.deleteKanbanTask(id);
|
|
187706
|
+
return Response.json(result, { status: result.ok ? 200 : 500, headers: jsonHeaders });
|
|
187707
|
+
}
|
|
187708
|
+
return new Response("Method Not Allowed", { status: 405, headers: corsHeaders });
|
|
187709
|
+
}
|
|
187588
187710
|
case "/api/incidents": {
|
|
187589
187711
|
const limit = parseInt(url3.searchParams.get("limit") ?? "50", 10);
|
|
187590
187712
|
return Response.json(await dataProvider.getIncidents(limit), { headers: jsonHeaders });
|
|
@@ -13,6 +13,29 @@ export interface DataProvider {
|
|
|
13
13
|
getSessions(limit?: number): Promise<SessionSummary[]>;
|
|
14
14
|
getCost(): Promise<CostSummary>;
|
|
15
15
|
getKanbanTasks(): Promise<KanbanBoard>;
|
|
16
|
+
createKanbanTask(input: {
|
|
17
|
+
title: string;
|
|
18
|
+
agent?: string;
|
|
19
|
+
status?: string;
|
|
20
|
+
priority?: string;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
id?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
}>;
|
|
26
|
+
updateKanbanTask(id: string, input: {
|
|
27
|
+
title?: string;
|
|
28
|
+
agent?: string;
|
|
29
|
+
status?: string;
|
|
30
|
+
priority?: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
ok: boolean;
|
|
33
|
+
error?: string;
|
|
34
|
+
}>;
|
|
35
|
+
deleteKanbanTask(id: string): Promise<{
|
|
36
|
+
ok: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
}>;
|
|
16
39
|
getIncidents(limit?: number): Promise<IncidentEntry[]>;
|
|
17
40
|
getMetrics(range?: string): Promise<MetricsSnapshot[]>;
|
|
18
41
|
getLogs(): LogEntry[];
|
|
@@ -225,5 +225,22 @@ body{font-family:var(--font-body);font-size:var(--text-base);color:var(--text-pr
|
|
|
225
225
|
.agent-model-select:focus{outline:none;border-color:var(--accent-primary)}
|
|
226
226
|
.agent-model-select option{background:var(--bg-elevated);color:var(--text-primary)}
|
|
227
227
|
|
|
228
|
+
.btn-primary{background:var(--accent-primary);color:#fff;border:none;border-radius:var(--radius-md);padding:8px 16px;font-size:var(--text-sm);font-weight:600;cursor:pointer;transition:background .15s}
|
|
229
|
+
.btn-primary:hover{background:var(--accent-hover)}
|
|
230
|
+
.btn-secondary{background:var(--bg-elevated);color:var(--text-primary);border:1px solid var(--border-default);border-radius:var(--radius-md);padding:8px 16px;font-size:var(--text-sm);cursor:pointer}
|
|
231
|
+
.kanban-del{position:absolute;top:6px;right:6px;background:transparent;border:none;color:var(--text-tertiary);font-size:18px;line-height:1;cursor:pointer;opacity:0;transition:opacity .15s}
|
|
232
|
+
.kanban-card{position:relative}
|
|
233
|
+
.kanban-card:hover .kanban-del{opacity:1}
|
|
234
|
+
.kanban-card[draggable=true]{cursor:grab}
|
|
235
|
+
.kanban-card[draggable=true]:active{cursor:grabbing}
|
|
236
|
+
.kanban-col.drag-over{outline:2px dashed var(--accent-primary);outline-offset:-4px}
|
|
237
|
+
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:1000}
|
|
238
|
+
.modal-box{background:var(--bg-card);border:1px solid var(--border-default);border-radius:var(--radius-xl);padding:24px;width:380px;max-width:90vw;display:flex;flex-direction:column;gap:14px}
|
|
239
|
+
.modal-box h3{font-size:var(--text-lg);font-weight:700;margin-bottom:4px}
|
|
240
|
+
.modal-box label{display:flex;flex-direction:column;gap:6px;font-size:var(--text-xs);color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em}
|
|
241
|
+
.modal-box .input{background:var(--bg-secondary);border:1px solid var(--border-default);border-radius:var(--radius-md);padding:10px 12px;color:var(--text-primary);font-size:var(--text-sm);font-family:var(--font-body)}
|
|
242
|
+
.modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:8px}
|
|
243
|
+
|
|
244
|
+
|
|
228
245
|
@media(max-width:1024px){.kpi-grid,.grid-2{grid-template-columns:repeat(2,1fr)}.kanban-board{grid-template-columns:repeat(2,1fr)}.gauge-grid{grid-template-columns:repeat(2,1fr)}}
|
|
229
246
|
@media(max-width:768px){.kpi-grid,.grid-2{grid-template-columns:1fr}.kanban-board{grid-template-columns:1fr}.agent-grid{grid-template-columns:1fr}}
|
|
@@ -1,2 +1,22 @@
|
|
|
1
|
-
const API={
|
|
2
|
-
|
|
1
|
+
const API={
|
|
2
|
+
health:()=>fetchJSON('/health'),
|
|
3
|
+
agents:()=>fetchJSON('/agents'),
|
|
4
|
+
models:()=>fetchJSON('/models'),
|
|
5
|
+
sessions:(l)=>fetchJSON(`/sessions?limit=${l}`),
|
|
6
|
+
cost:()=>fetchJSON('/cost'),
|
|
7
|
+
kanban:()=>fetchJSON('/kanban'),
|
|
8
|
+
kanbanCreate:(body)=>fetchJSON('/kanban/task',{method:'POST',body}),
|
|
9
|
+
kanbanUpdate:(body)=>fetchJSON('/kanban/task',{method:'PUT',body}),
|
|
10
|
+
kanbanDelete:(id)=>fetchJSON(`/kanban/task?id=${id}`,{method:'DELETE'}),
|
|
11
|
+
incidents:(l)=>fetchJSON(`/incidents?limit=${l}`),
|
|
12
|
+
metrics:()=>fetchJSON('/metrics'),
|
|
13
|
+
config:()=>fetchJSON('/config'),
|
|
14
|
+
memory:()=>fetchJSON('/memory'),
|
|
15
|
+
skills:()=>fetchJSON('/skills'),
|
|
16
|
+
gatewayToken:(type,token,passphrase)=>fetch('/api/gateway/token',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({type,token,passphrase})}).then(r=>r.json())
|
|
17
|
+
}
|
|
18
|
+
async function fetchJSON(e,opts){
|
|
19
|
+
const r=await fetch(`/api${e}`,opts)
|
|
20
|
+
if(!r.ok)throw new Error(`API ${e}: ${r.status}`)
|
|
21
|
+
return r.json()
|
|
22
|
+
}
|
|
@@ -183,20 +183,111 @@ async function loadCost(){
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// ===== KANBAN =====
|
|
186
|
+
let kanbanData={columns:{}}
|
|
187
|
+
const KANBAN_STATUSES=['pending','in_progress','completed','failed']
|
|
188
|
+
const KANBAN_LABELS={pending:'Pending',in_progress:'In Progress',completed:'Completed',failed:'Failed'}
|
|
189
|
+
|
|
186
190
|
async function loadKanban(){
|
|
187
191
|
const board=document.getElementById('kanbanBoard')
|
|
188
192
|
try{
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
kanbanData=await API.kanban()
|
|
194
|
+
renderKanban()
|
|
195
|
+
}catch(e){board.innerHTML=`<div class="error" style="grid-column:1/-1"><p>Failed to load Kanban</p></div>`}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function renderKanban(){
|
|
199
|
+
const board=document.getElementById('kanbanBoard')
|
|
200
|
+
const cols=kanbanData.columns||{}
|
|
201
|
+
board.innerHTML=`
|
|
202
|
+
<div style="grid-column:1/-1;display:flex;justify-content:flex-end;margin-bottom:12px">
|
|
203
|
+
<button class="btn-primary" onclick="openKanbanModal()">+ New Task</button>
|
|
204
|
+
</div>`+
|
|
205
|
+
KANBAN_STATUSES.map(status=>{
|
|
206
|
+
const tasks=cols[status]||[]
|
|
207
|
+
return `<div class="kanban-col" data-status="${status}" ondragover="onKanbanDragOver(event)" ondrop="onKanbanDrop(event,'${status}')">
|
|
208
|
+
<div class="kanban-header"><span>${KANBAN_LABELS[status]}</span><span class="kanban-count">${tasks.length}</span></div>
|
|
209
|
+
<div class="kanban-body">${
|
|
210
|
+
tasks.length?tasks.map(t=>`<div class="kanban-card" draggable="true" ondragstart="onKanbanDragStart(event,'${t.id}')" ondblclick="openKanbanModal('${t.id}')">
|
|
211
|
+
<div class="kanban-card-title">${escapeHtml(t.title)}</div>
|
|
212
|
+
<div class="kanban-card-meta"><span>${escapeHtml(t.agent)}</span><span class="prio ${t.priority}">${t.priority}</span></div>
|
|
213
|
+
<button class="kanban-del" onclick="deleteKanbanTask('${t.id}')" title="Delete">×</button>
|
|
214
|
+
</div>`).join(''):'<div style="padding:20px;text-align:center;color:var(--text-tertiary);font-size:var(--text-xs)">No tasks</div>'
|
|
215
|
+
}</div>
|
|
216
|
+
</div>`
|
|
198
217
|
}).join('')
|
|
199
|
-
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function escapeHtml(s){return (s||'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]))}
|
|
221
|
+
|
|
222
|
+
let dragTaskId=null
|
|
223
|
+
function onKanbanDragStart(e,id){dragTaskId=id;e.dataTransfer.setData('text/plain',id)}
|
|
224
|
+
function onKanbanDragOver(e){e.preventDefault()}
|
|
225
|
+
async function onKanbanDrop(e,status){
|
|
226
|
+
e.preventDefault()
|
|
227
|
+
if(!dragTaskId)return
|
|
228
|
+
const id=dragTaskId;dragTaskId=null
|
|
229
|
+
const task=findKanbanTask(id)
|
|
230
|
+
if(!task||task.status===status)return
|
|
231
|
+
try{
|
|
232
|
+
await API.kanbanUpdate({id,status})
|
|
233
|
+
task.status=status
|
|
234
|
+
renderKanban()
|
|
235
|
+
}catch(err){alert('Erreur: '+err.message)}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function findKanbanTask(id){
|
|
239
|
+
for(const s of KANBAN_STATUSES){const t=(kanbanData.columns[s]||[]).find(x=>x.id===id);if(t)return t}
|
|
240
|
+
return null
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function deleteKanbanTask(id){
|
|
244
|
+
if(!confirm('Delete this task?'))return
|
|
245
|
+
try{
|
|
246
|
+
await API.kanbanDelete(id)
|
|
247
|
+
for(const s of KANBAN_STATUSES){kanbanData.columns[s]=(kanbanData.columns[s]||[]).filter(t=>t.id!==id)}
|
|
248
|
+
renderKanban()
|
|
249
|
+
}catch(err){alert('Erreur: '+err.message)}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function openKanbanModal(id){
|
|
253
|
+
const task=id?findKanbanTask(id):null
|
|
254
|
+
const modal=document.createElement('div')
|
|
255
|
+
modal.className='modal-overlay'
|
|
256
|
+
modal.innerHTML=`
|
|
257
|
+
<div class="modal-box">
|
|
258
|
+
<h3>${task?'Edit Task':'New Task'}</h3>
|
|
259
|
+
<label>Title<input id="kbTitle" class="input" value="${task?escapeHtml(task.title):''}"></label>
|
|
260
|
+
<label>Agent<input id="kbAgent" class="input" value="${task?escapeHtml(task.agent):''}" placeholder="e.g. Morpheus"></label>
|
|
261
|
+
<label>Priority<select id="kbPriority" class="input">
|
|
262
|
+
${['low','medium','high','urgent'].map(p=>`<option value="${p}" ${task&&task.priority===p?'selected':''}>${p}</option>`).join('')}
|
|
263
|
+
</select></label>
|
|
264
|
+
<label>Status<select id="kbStatus" class="input">
|
|
265
|
+
${KANBAN_STATUSES.map(s=>`<option value="${s}" ${task&&task.status===s?'selected':( !task&&s==='pending'?'selected':'')}>${KANBAN_LABELS[s]}</option>`).join('')}
|
|
266
|
+
</select></label>
|
|
267
|
+
<div class="modal-actions">
|
|
268
|
+
<button class="btn-secondary" onclick="this.closest('.modal-overlay').remove()">Cancel</button>
|
|
269
|
+
<button class="btn-primary" onclick="saveKanban('${id||''}')">${task?'Save':'Create'}</button>
|
|
270
|
+
</div>
|
|
271
|
+
</div>`
|
|
272
|
+
document.body.appendChild(modal)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function saveKanban(id){
|
|
276
|
+
const title=document.getElementById('kbTitle').value.trim()
|
|
277
|
+
const agent=document.getElementById('kbAgent').value.trim()
|
|
278
|
+
const priority=document.getElementById('kbPriority').value
|
|
279
|
+
const status=document.getElementById('kbStatus').value
|
|
280
|
+
if(!title){alert('Title required');return}
|
|
281
|
+
try{
|
|
282
|
+
if(id){
|
|
283
|
+
await API.kanbanUpdate({id,title,agent,priority,status})
|
|
284
|
+
}else{
|
|
285
|
+
const res=await API.kanbanCreate({title,agent,priority,status})
|
|
286
|
+
if(!res.ok){throw new Error(res.error||'create failed')}
|
|
287
|
+
}
|
|
288
|
+
document.querySelector('.modal-overlay')?.remove()
|
|
289
|
+
await loadKanban()
|
|
290
|
+
}catch(err){alert('Erreur: '+err.message)}
|
|
200
291
|
}
|
|
201
292
|
|
|
202
293
|
// ===== LOGS =====
|
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.
|
|
368022
|
+
version: "0.3.28",
|
|
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