@kl-c/matrixos 0.3.35 → 0.3.37

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.35",
2166
+ version: "0.3.37",
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",
@@ -186946,6 +186946,7 @@ function ensureKanbanTable(db) {
186946
186946
  id TEXT PRIMARY KEY,
186947
186947
  title TEXT NOT NULL,
186948
186948
  description TEXT NOT NULL DEFAULT '',
186949
+ output TEXT NOT NULL DEFAULT '',
186949
186950
  agent TEXT NOT NULL DEFAULT 'Unknown',
186950
186951
  status TEXT NOT NULL DEFAULT 'pending',
186951
186952
  priority TEXT NOT NULL DEFAULT 'medium',
@@ -186958,6 +186959,11 @@ function ensureKanbanTable(db) {
186958
186959
  } catch {
186959
186960
  db.exec("ALTER TABLE matrixos_kanban ADD COLUMN description TEXT NOT NULL DEFAULT ''");
186960
186961
  }
186962
+ try {
186963
+ db.query("SELECT output FROM matrixos_kanban LIMIT 1").all();
186964
+ } catch {
186965
+ db.exec("ALTER TABLE matrixos_kanban ADD COLUMN output TEXT NOT NULL DEFAULT ''");
186966
+ }
186961
186967
  }
186962
186968
  function midnightMs() {
186963
186969
  const d = new Date;
@@ -187226,7 +187232,7 @@ function createDataProvider(config5) {
187226
187232
  return board;
187227
187233
  try {
187228
187234
  ensureKanbanTable(db);
187229
- const rows = db.query("SELECT id, title, description, agent, status, priority, created_at, updated_at FROM matrixos_kanban ORDER BY updated_at DESC").all();
187235
+ const rows = db.query("SELECT id, title, description, output, agent, status, priority, created_at, updated_at FROM matrixos_kanban ORDER BY updated_at DESC").all();
187230
187236
  for (const row of rows) {
187231
187237
  const status2 = row.status;
187232
187238
  if (!board.columns[status2])
@@ -187235,6 +187241,7 @@ function createDataProvider(config5) {
187235
187241
  id: row.id,
187236
187242
  title: row.title,
187237
187243
  description: row.description || "",
187244
+ output: row.output || "",
187238
187245
  agent: row.agent || "Unknown",
187239
187246
  priority: row.priority ?? "medium",
187240
187247
  status: status2,
@@ -187308,6 +187315,44 @@ function createDataProvider(config5) {
187308
187315
  db.close();
187309
187316
  }
187310
187317
  },
187318
+ async executeKanbanTask(id) {
187319
+ const db = getDbWrite();
187320
+ if (!db)
187321
+ return { ok: false, error: "database unavailable" };
187322
+ try {
187323
+ ensureKanbanTable(db);
187324
+ const row = db.query("SELECT title, description, agent, status FROM matrixos_kanban WHERE id = ?").get(id);
187325
+ if (!row)
187326
+ return { ok: false, error: "task not found" };
187327
+ const agent2 = row.agent || "Morpheus";
187328
+ const prompt = `Task: ${row.title}
187329
+ ${row.description ? `Description: ${row.description}
187330
+ ` : ""}Execute this task.`;
187331
+ db.query("UPDATE matrixos_kanban SET status = ?, updated_at = ? WHERE id = ?").run("in_progress", Date.now(), id);
187332
+ const proc = Bun.spawn({
187333
+ cmd: ["matrixos", "run", "--agent", agent2, "--json", JSON.stringify(prompt)],
187334
+ env: { ...process.env, PATH: `${process.env.PATH || ""}:/root/.bun/bin:/usr/bin` },
187335
+ stdout: "pipe",
187336
+ stderr: "pipe"
187337
+ });
187338
+ const result = await proc.exited;
187339
+ const decoder = new TextDecoder;
187340
+ const output = decoder.decode(await new Response(proc.stdout).arrayBuffer());
187341
+ const errOutput = decoder.decode(await new Response(proc.stderr).arrayBuffer());
187342
+ const combined = [output, errOutput].filter(Boolean).join(`
187343
+ `).slice(0, 4000);
187344
+ const finalStatus = result === 0 ? "completed" : "failed";
187345
+ db.query("UPDATE matrixos_kanban SET status = ?, output = ?, updated_at = ? WHERE id = ?").run(finalStatus, combined, Date.now(), id);
187346
+ return { ok: true, status: finalStatus, output: combined };
187347
+ } catch (e) {
187348
+ try {
187349
+ db.query("UPDATE matrixos_kanban SET status = ?, updated_at = ? WHERE id = ?").run("failed", Date.now(), id);
187350
+ } catch {}
187351
+ return { ok: false, error: e instanceof Error ? e.message : String(e), status: "failed" };
187352
+ } finally {
187353
+ db.close();
187354
+ }
187355
+ },
187311
187356
  async deleteKanbanTask(id) {
187312
187357
  const db = getDbWrite();
187313
187358
  if (!db)
@@ -187663,6 +187708,17 @@ function createDashboardServer(dataProvider, config5) {
187663
187708
  }
187664
187709
  return new Response("Method Not Allowed", { status: 405, headers: corsHeaders });
187665
187710
  }
187711
+ case "/api/kanban/execute": {
187712
+ if (req.method !== "POST") {
187713
+ return new Response("Method Not Allowed", { status: 405, headers: corsHeaders });
187714
+ }
187715
+ const body = await req.json();
187716
+ if (!body.id) {
187717
+ return Response.json({ ok: false, error: "id required" }, { status: 400, headers: jsonHeaders });
187718
+ }
187719
+ const result = await dataProvider.executeKanbanTask(body.id);
187720
+ return Response.json(result, { status: result.ok ? 200 : 500, headers: jsonHeaders });
187721
+ }
187666
187722
  case "/api/incidents": {
187667
187723
  const limit = parseInt(url3.searchParams.get("limit") ?? "50", 10);
187668
187724
  return Response.json(await dataProvider.getIncidents(limit), { headers: jsonHeaders });
@@ -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.35",
2166
+ version: "0.3.37",
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",
@@ -187001,6 +187001,7 @@ function ensureKanbanTable(db) {
187001
187001
  id TEXT PRIMARY KEY,
187002
187002
  title TEXT NOT NULL,
187003
187003
  description TEXT NOT NULL DEFAULT '',
187004
+ output TEXT NOT NULL DEFAULT '',
187004
187005
  agent TEXT NOT NULL DEFAULT 'Unknown',
187005
187006
  status TEXT NOT NULL DEFAULT 'pending',
187006
187007
  priority TEXT NOT NULL DEFAULT 'medium',
@@ -187013,6 +187014,11 @@ function ensureKanbanTable(db) {
187013
187014
  } catch {
187014
187015
  db.exec("ALTER TABLE matrixos_kanban ADD COLUMN description TEXT NOT NULL DEFAULT ''");
187015
187016
  }
187017
+ try {
187018
+ db.query("SELECT output FROM matrixos_kanban LIMIT 1").all();
187019
+ } catch {
187020
+ db.exec("ALTER TABLE matrixos_kanban ADD COLUMN output TEXT NOT NULL DEFAULT ''");
187021
+ }
187016
187022
  }
187017
187023
  function midnightMs() {
187018
187024
  const d = new Date;
@@ -187281,7 +187287,7 @@ function createDataProvider(config5) {
187281
187287
  return board;
187282
187288
  try {
187283
187289
  ensureKanbanTable(db);
187284
- const rows = db.query("SELECT id, title, description, agent, status, priority, created_at, updated_at FROM matrixos_kanban ORDER BY updated_at DESC").all();
187290
+ const rows = db.query("SELECT id, title, description, output, agent, status, priority, created_at, updated_at FROM matrixos_kanban ORDER BY updated_at DESC").all();
187285
187291
  for (const row of rows) {
187286
187292
  const status2 = row.status;
187287
187293
  if (!board.columns[status2])
@@ -187290,6 +187296,7 @@ function createDataProvider(config5) {
187290
187296
  id: row.id,
187291
187297
  title: row.title,
187292
187298
  description: row.description || "",
187299
+ output: row.output || "",
187293
187300
  agent: row.agent || "Unknown",
187294
187301
  priority: row.priority ?? "medium",
187295
187302
  status: status2,
@@ -187363,6 +187370,44 @@ function createDataProvider(config5) {
187363
187370
  db.close();
187364
187371
  }
187365
187372
  },
187373
+ async executeKanbanTask(id) {
187374
+ const db = getDbWrite();
187375
+ if (!db)
187376
+ return { ok: false, error: "database unavailable" };
187377
+ try {
187378
+ ensureKanbanTable(db);
187379
+ const row = db.query("SELECT title, description, agent, status FROM matrixos_kanban WHERE id = ?").get(id);
187380
+ if (!row)
187381
+ return { ok: false, error: "task not found" };
187382
+ const agent2 = row.agent || "Morpheus";
187383
+ const prompt = `Task: ${row.title}
187384
+ ${row.description ? `Description: ${row.description}
187385
+ ` : ""}Execute this task.`;
187386
+ db.query("UPDATE matrixos_kanban SET status = ?, updated_at = ? WHERE id = ?").run("in_progress", Date.now(), id);
187387
+ const proc = Bun.spawn({
187388
+ cmd: ["matrixos", "run", "--agent", agent2, "--json", JSON.stringify(prompt)],
187389
+ env: { ...process.env, PATH: `${process.env.PATH || ""}:/root/.bun/bin:/usr/bin` },
187390
+ stdout: "pipe",
187391
+ stderr: "pipe"
187392
+ });
187393
+ const result = await proc.exited;
187394
+ const decoder = new TextDecoder;
187395
+ const output = decoder.decode(await new Response(proc.stdout).arrayBuffer());
187396
+ const errOutput = decoder.decode(await new Response(proc.stderr).arrayBuffer());
187397
+ const combined = [output, errOutput].filter(Boolean).join(`
187398
+ `).slice(0, 4000);
187399
+ const finalStatus = result === 0 ? "completed" : "failed";
187400
+ db.query("UPDATE matrixos_kanban SET status = ?, output = ?, updated_at = ? WHERE id = ?").run(finalStatus, combined, Date.now(), id);
187401
+ return { ok: true, status: finalStatus, output: combined };
187402
+ } catch (e) {
187403
+ try {
187404
+ db.query("UPDATE matrixos_kanban SET status = ?, updated_at = ? WHERE id = ?").run("failed", Date.now(), id);
187405
+ } catch {}
187406
+ return { ok: false, error: e instanceof Error ? e.message : String(e), status: "failed" };
187407
+ } finally {
187408
+ db.close();
187409
+ }
187410
+ },
187366
187411
  async deleteKanbanTask(id) {
187367
187412
  const db = getDbWrite();
187368
187413
  if (!db)
@@ -187718,6 +187763,17 @@ function createDashboardServer(dataProvider, config5) {
187718
187763
  }
187719
187764
  return new Response("Method Not Allowed", { status: 405, headers: corsHeaders });
187720
187765
  }
187766
+ case "/api/kanban/execute": {
187767
+ if (req.method !== "POST") {
187768
+ return new Response("Method Not Allowed", { status: 405, headers: corsHeaders });
187769
+ }
187770
+ const body = await req.json();
187771
+ if (!body.id) {
187772
+ return Response.json({ ok: false, error: "id required" }, { status: 400, headers: jsonHeaders });
187773
+ }
187774
+ const result = await dataProvider.executeKanbanTask(body.id);
187775
+ return Response.json(result, { status: result.ok ? 200 : 500, headers: jsonHeaders });
187776
+ }
187721
187777
  case "/api/incidents": {
187722
187778
  const limit = parseInt(url3.searchParams.get("limit") ?? "50", 10);
187723
187779
  return Response.json(await dataProvider.getIncidents(limit), { headers: jsonHeaders });
@@ -15,6 +15,7 @@ export interface DataProvider {
15
15
  getKanbanTasks(): Promise<KanbanBoard>;
16
16
  createKanbanTask(input: {
17
17
  title: string;
18
+ description?: string;
18
19
  agent?: string;
19
20
  status?: string;
20
21
  priority?: string;
@@ -25,6 +26,7 @@ export interface DataProvider {
25
26
  }>;
26
27
  updateKanbanTask(id: string, input: {
27
28
  title?: string;
29
+ description?: string;
28
30
  agent?: string;
29
31
  status?: string;
30
32
  priority?: string;
@@ -32,6 +34,12 @@ export interface DataProvider {
32
34
  ok: boolean;
33
35
  error?: string;
34
36
  }>;
37
+ executeKanbanTask(id: string): Promise<{
38
+ ok: boolean;
39
+ error?: string;
40
+ output?: string;
41
+ status?: string;
42
+ }>;
35
43
  deleteKanbanTask(id: string): Promise<{
36
44
  ok: boolean;
37
45
  error?: string;
@@ -243,6 +243,13 @@ body{font-family:var(--font-body);font-size:var(--text-base);color:var(--text-pr
243
243
  .modal-box select.input option{background:var(--bg-elevated);color:var(--text-primary)}
244
244
  .modal-box textarea.input{resize:vertical;min-height:60px;font-family:var(--font-body)}
245
245
  .kanban-card-desc{font-size:var(--text-xs);color:var(--text-secondary);margin:4px 0 2px;line-height:1.4;max-height:60px;overflow:hidden}
246
+ .kanban-card-actions{display:flex;justify-content:space-between;align-items:center;gap:6px;margin-top:6px}
247
+ .kanban-run{all:unset;cursor:pointer;font-size:var(--text-xs);background:var(--success);color:#fff;border-radius:var(--radius-sm);padding:3px 8px;transition:opacity .15s}
248
+ .kanban-run:hover{opacity:.85}
249
+ .kanban-run:disabled{opacity:.4;cursor:not-allowed}
250
+ .kanban-card.running{border:1px solid var(--success);box-shadow:0 0 8px rgba(59,203,137,.2)}
251
+ .kanban-output-toggle{all:unset;cursor:pointer;font-size:var(--text-xs);color:var(--info);text-decoration:underline;margin-top:4px}
252
+ .kanban-card-output{background:var(--bg-secondary);border:1px solid var(--border-default);border-radius:var(--radius-sm);padding:8px;margin-top:6px;font-size:var(--text-xs);color:var(--text-secondary);white-space:pre-wrap;max-height:200px;overflow:auto}
246
253
  .modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:8px}
247
254
 
248
255
 
@@ -5,10 +5,10 @@ const API={
5
5
  sessions:(l)=>fetchJSON(`/sessions?limit=${l}`),
6
6
  cost:()=>fetchJSON('/cost'),
7
7
  kanban:()=>fetchJSON('/kanban'),
8
- kanbanCreate:(body)=>fetchJSON('/kanban/task',{method:'POST',body:JSON.stringify(body),headers:{'Content-Type':'application/json'}}),
9
- kanbanUpdate:(body)=>fetchJSON('/kanban/task',{method:'PUT',body:JSON.stringify(body),headers:{'Content-Type':'application/json'}}),
10
- kanbanDelete:(id)=>fetchJSON(`/kanban/task?id=${id}`,{method:'DELETE'}),
11
- incidents:(l)=>fetchJSON(`/incidents?limit=${l}`),
8
+ kanbanCreate:(body)=>fetchJSON('/kanban/task',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}),
9
+ kanbanUpdate:(body)=>fetchJSON('/kanban/task',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}),
10
+ kanbanDelete:(id)=>fetchJSON(`/kanban/task?id=${encodeURIComponent(id)}`,{method:'DELETE'}),
11
+ kanbanExecute:(id)=>fetchJSON('/kanban/execute',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id})}),
12
12
  metrics:()=>fetchJSON('/metrics'),
13
13
  config:()=>fetchJSON('/config'),
14
14
  memory:()=>fetchJSON('/memory'),
@@ -207,11 +207,15 @@ function renderKanban(){
207
207
  return `<div class="kanban-col" data-status="${status}" ondragover="onKanbanDragOver(event)" ondragleave="onKanbanDragLeave(event)" ondrop="onKanbanDrop(event)">
208
208
  <div class="kanban-header"><span>${KANBAN_LABELS[status]}</span><span class="kanban-count">${tasks.length}</span></div>
209
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}')">
210
+ tasks.length?tasks.map(t=>`<div class="kanban-card ${t.status==='in_progress'?'running':''}" draggable="true" ondragstart="onKanbanDragStart(event,'${t.id}')" ondblclick="openKanbanModal('${t.id}')">
211
211
  <div class="kanban-card-title">${escapeHtml(t.title)}</div>
212
212
  ${t.description?`<div class="kanban-card-desc">${escapeHtml(t.description)}</div>`:''}
213
+ ${t.output?`<button class="kanban-output-toggle" onclick="toggleKanbanOutput(event,'${t.id}')">Voir résultat</button><pre id="ko-${t.id}" class="kanban-card-output" style="display:none">${escapeHtml(t.output)}</pre>`:''}
213
214
  <div class="kanban-card-meta"><span>${escapeHtml(t.agent)}</span><span class="prio ${t.priority}">${t.priority}</span></div>
214
- <button class="kanban-del" onclick="deleteKanbanTask('${t.id}')" title="Delete">×</button>
215
+ <div class="kanban-card-actions">
216
+ <button class="kanban-run" onclick="runKanbanTask('${t.id}')" title="Run" ${t.status==='in_progress'?'disabled':''}>▶ Run</button>
217
+ <button class="kanban-del" onclick="deleteKanbanTask('${t.id}')" title="Delete">×</button>
218
+ </div>
215
219
  </div>`).join(''):'<div style="padding:20px;text-align:center;color:var(--text-tertiary);font-size:var(--text-xs)">No tasks</div>'
216
220
  }</div>
217
221
  </div>`
@@ -316,6 +320,43 @@ async function saveKanban(id){
316
320
  }catch(err){alert('Erreur: '+err.message)}
317
321
  }
318
322
 
323
+ async function runKanbanTask(id){
324
+ const task=findKanbanTask(id)
325
+ if(!task||task.status==='in_progress')return
326
+ if(!confirm(`Exécuter "${task.title}" avec ${task.agent||'Morpheus'} ?`))return
327
+ for(const s of KANBAN_STATUSES){
328
+ kanbanData.columns[s]=(kanbanData.columns[s]||[]).filter(t=>t.id!==id)
329
+ }
330
+ task.status='in_progress'
331
+ kanbanData.columns.in_progress=(kanbanData.columns.in_progress||[])
332
+ kanbanData.columns.in_progress.unshift(task)
333
+ renderKanban()
334
+ try{
335
+ const res=await API.kanbanExecute(id)
336
+ if(!res.ok)throw new Error(res.error||'execution failed')
337
+ for(const s of KANBAN_STATUSES){
338
+ kanbanData.columns[s]=(kanbanData.columns[s]||[]).filter(t=>t.id!==id)
339
+ }
340
+ task.status=res.status||'completed'
341
+ task.output=res.output||''
342
+ kanbanData.columns[task.status]=(kanbanData.columns[task.status]||[])
343
+ kanbanData.columns[task.status].unshift(task)
344
+ renderKanban()
345
+ }catch(err){
346
+ alert('Erreur: '+err.message)
347
+ await loadKanban()
348
+ }
349
+ }
350
+
351
+ function toggleKanbanOutput(e,id){
352
+ e.stopPropagation()
353
+ const el=document.getElementById('ko-'+id)
354
+ if(!el)return
355
+ const show=el.style.display==='none'
356
+ el.style.display=show?'block':'none'
357
+ e.target.textContent=show?'Masquer résultat':'Voir résultat'
358
+ }
359
+
319
360
  // ===== LOGS =====
320
361
  let logStream=null
321
362
  async function loadLogs(){
@@ -44,6 +44,7 @@ export interface KanbanTask {
44
44
  agent: string;
45
45
  priority: "low" | "medium" | "high" | "urgent";
46
46
  status: "pending" | "in_progress" | "completed" | "failed";
47
+ output?: string;
47
48
  createdAt: string;
48
49
  updatedAt: string;
49
50
  }
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.35",
368022
+ version: "0.3.37",
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.35",
3
+ "version": "0.3.37",
4
4
  "description": "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "dist/index.d.ts",