@kl-c/matrixos 0.3.48 → 0.3.49
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/cron.d.ts +5 -0
- package/dist/cli/index.js +1336 -119
- package/dist/cli/service.d.ts +1 -0
- package/dist/cli-node/index.js +1336 -119
- package/dist/features/cron/store.d.ts +2 -3
- package/dist/features/dashboard/data-provider.d.ts +16 -0
- package/dist/features/dashboard/frontend/css/style.css +9 -0
- package/dist/features/dashboard/frontend/index.html +22 -0
- package/dist/features/dashboard/frontend/js/api.js +3 -0
- package/dist/features/dashboard/frontend/js/app.js +39 -5
- package/dist/index.js +53 -14
- package/package.json +1 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cron / Scheduled (§4.5) — durable job definitions.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* No delivery yet (future: matrix-gateway-core channels).
|
|
4
|
+
* SQLite-backed store (persists across restarts). Uses the same opencode.db
|
|
5
|
+
* as Kanban/Goals for consistency.
|
|
7
6
|
*/
|
|
8
7
|
import * as z from "zod";
|
|
9
8
|
export declare const CronJobSchema: z.ZodObject<{
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CronJob } from "../cron/store";
|
|
1
2
|
import type { AgentStatus, SessionSummary, CostSummary, KanbanBoard, Goal, IncidentEntry, HealthResponse, MetricsSnapshot } from "./types";
|
|
2
3
|
export interface DataProviderConfig {
|
|
3
4
|
matrixosHome: string;
|
|
@@ -73,6 +74,21 @@ export interface DataProvider {
|
|
|
73
74
|
path?: string;
|
|
74
75
|
error?: string;
|
|
75
76
|
}>;
|
|
77
|
+
listCron(): CronJob[];
|
|
78
|
+
addCron(input: {
|
|
79
|
+
name: string;
|
|
80
|
+
schedule: string;
|
|
81
|
+
command: string;
|
|
82
|
+
channel?: string;
|
|
83
|
+
}): {
|
|
84
|
+
ok: boolean;
|
|
85
|
+
id?: string;
|
|
86
|
+
error?: string;
|
|
87
|
+
};
|
|
88
|
+
removeCron(id: string): {
|
|
89
|
+
ok: boolean;
|
|
90
|
+
error?: string;
|
|
91
|
+
};
|
|
76
92
|
getIncidents(limit?: number): Promise<IncidentEntry[]>;
|
|
77
93
|
getMetrics(range?: string): Promise<MetricsSnapshot[]>;
|
|
78
94
|
getLogs(): LogEntry[];
|
|
@@ -410,3 +410,12 @@ body{font-family:var(--font-body);font-size:var(--text-base);color:var(--text-pr
|
|
|
410
410
|
.modal-label{font-size:var(--text-xs);font-weight:600;color:var(--text-secondary);margin-top:6px}
|
|
411
411
|
.skill-preview{margin-top:8px;background:var(--bg-code);border:1px solid var(--border-default);border-radius:var(--radius-sm);padding:10px;font-family:var(--font-mono);font-size:11px;color:var(--text-secondary);white-space:pre-wrap;max-height:160px;overflow:auto}
|
|
412
412
|
.modal-footer{display:flex;justify-content:flex-end;gap:8px;margin-top:6px}
|
|
413
|
+
|
|
414
|
+
.btn-danger{background:var(--bg-danger,#3a1518);color:#ff6b6b;border:1px solid var(--border-danger,#5a2026)}
|
|
415
|
+
.btn-danger:hover{background:#4a1a1f}
|
|
416
|
+
.btn-sm{padding:4px 10px;font-size:var(--text-xs)}
|
|
417
|
+
.schedule-table{width:100%;border-collapse:collapse;font-size:var(--text-sm)}
|
|
418
|
+
.schedule-table th{text-align:left;padding:10px 12px;color:var(--text-secondary);font-weight:600;border-bottom:1px solid var(--border-default)}
|
|
419
|
+
.schedule-table td{padding:10px 12px;border-bottom:1px solid var(--border-subtle);color:var(--text-primary)}
|
|
420
|
+
.schedule-table code{background:var(--bg-code);padding:2px 6px;border-radius:4px;font-size:11px;color:var(--text-secondary)}
|
|
421
|
+
.badge-green{background:rgba(16,185,129,.15);color:#10b981}
|
|
@@ -209,8 +209,30 @@
|
|
|
209
209
|
<div id="tab-schedule" class="tab-panel">
|
|
210
210
|
<div class="page-header">
|
|
211
211
|
<div><h1 class="page-title">Schedule</h1><p class="page-subtitle">Cron jobs and scheduled tasks for MaTrixOS agents</p></div>
|
|
212
|
+
<div class="page-actions"><button class="btn btn-primary" id="newCronBtn" style="margin-left:12px">+ New Job</button></div>
|
|
212
213
|
</div>
|
|
213
214
|
<div class="card"><div class="card-body" id="scheduleBody"></div></div>
|
|
215
|
+
<div class="modal-overlay" id="cronModal" style="display:none">
|
|
216
|
+
<div class="modal-box">
|
|
217
|
+
<div class="modal-header"><h3>New Scheduled Job</h3><button class="modal-close" onclick="closeCronModal()">×</button></div>
|
|
218
|
+
<div class="modal-body">
|
|
219
|
+
<label class="modal-label">Name</label>
|
|
220
|
+
<input class="input" id="cronName" placeholder="daily brief" />
|
|
221
|
+
<label class="modal-label">Schedule (cron expr)</label>
|
|
222
|
+
<input class="input" id="cronSchedule" placeholder="0 9 * * *" />
|
|
223
|
+
<label class="modal-label">Command</label>
|
|
224
|
+
<input class="input" id="cronCommand" placeholder="matrixos run --agent TheOracle 'daily brief'" />
|
|
225
|
+
<label class="modal-label">Channel (optional)</label>
|
|
226
|
+
<select class="input" id="cronChannel">
|
|
227
|
+
<option value="">None</option>
|
|
228
|
+
<option value="telegram">Telegram</option>
|
|
229
|
+
<option value="discord">Discord</option>
|
|
230
|
+
<option value="whatsapp">WhatsApp</option>
|
|
231
|
+
</select>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="modal-footer"><button class="btn btn-secondary" onclick="closeCronModal()">Cancel</button><button class="btn btn-primary" onclick="createCron()">Create</button></div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
214
236
|
</div>
|
|
215
237
|
</div>
|
|
216
238
|
</div>
|
|
@@ -17,6 +17,9 @@ const API={
|
|
|
17
17
|
config:()=>fetchJSON('/config'),
|
|
18
18
|
memory:()=>fetchJSON('/memory'),
|
|
19
19
|
skills:()=>fetchJSON('/skills'),
|
|
20
|
+
cronList:()=>fetchJSON('/cron'),
|
|
21
|
+
cronAdd:(body)=>fetchJSON('/cron',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}),
|
|
22
|
+
cronRemove:(id)=>fetchJSON(`/cron?id=${encodeURIComponent(id)}`,{method:'DELETE'}),
|
|
20
23
|
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())
|
|
21
24
|
}
|
|
22
25
|
async function fetchJSON(e,opts){
|
|
@@ -666,19 +666,53 @@ async function createSkill(){
|
|
|
666
666
|
}
|
|
667
667
|
|
|
668
668
|
// ===== SCHEDULE =====
|
|
669
|
-
function loadSchedule(){
|
|
669
|
+
async function loadSchedule(){
|
|
670
670
|
const body=document.getElementById('scheduleBody')
|
|
671
671
|
if(!body)return
|
|
672
|
-
body.innerHTML
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
672
|
+
body.innerHTML='<div style="padding:20px;color:var(--text-tertiary)">Loading...</div>'
|
|
673
|
+
try{
|
|
674
|
+
const jobs=await API.cronList()
|
|
675
|
+
if(!jobs||!jobs.length){
|
|
676
|
+
body.innerHTML=`<div class="empty"><p>No scheduled jobs yet. Click "+ New Job" to add one.</p></div>`
|
|
677
|
+
}else{
|
|
678
|
+
body.innerHTML=`<table class="schedule-table"><thead><tr><th>Name</th><th>Schedule</th><th>Command</th><th>Channel</th><th>Status</th><th></th></tr></thead><tbody>${jobs.map(j=>`<tr>
|
|
679
|
+
<td>${j.name}</td>
|
|
680
|
+
<td><code>${j.schedule}</code></td>
|
|
681
|
+
<td><code>${j.command}</code></td>
|
|
682
|
+
<td>${j.channel||'—'}</td>
|
|
683
|
+
<td>${j.enabled?'<span class="badge badge-green">enabled</span>':'<span class="badge">disabled</span>'}</td>
|
|
684
|
+
<td><button class="btn btn-danger btn-sm" onclick="removeCron('${j.id}')">Remove</button></td>
|
|
685
|
+
</tr>`).join('')}</tbody></table>`
|
|
686
|
+
}
|
|
687
|
+
}catch(e){body.innerHTML=`<div class="error"><p>Failed to load schedule: ${e.message}</p></div>`}
|
|
688
|
+
}
|
|
689
|
+
async function removeCron(id){
|
|
690
|
+
if(!confirm('Remove this scheduled job?'))return
|
|
691
|
+
try{await API.cronRemove(id);loadSchedule()}catch(e){alert('Remove failed: '+e.message)}
|
|
692
|
+
}
|
|
693
|
+
function openCronModal(){
|
|
694
|
+
document.getElementById('cronModal').style.display='flex'
|
|
695
|
+
document.getElementById('cronName').value=''
|
|
696
|
+
document.getElementById('cronSchedule').value=''
|
|
697
|
+
document.getElementById('cronCommand').value=''
|
|
698
|
+
document.getElementById('cronChannel').value=''
|
|
699
|
+
}
|
|
700
|
+
function closeCronModal(){document.getElementById('cronModal').style.display='none'}
|
|
701
|
+
async function createCron(){
|
|
702
|
+
const name=document.getElementById('cronName').value.trim()
|
|
703
|
+
const schedule=document.getElementById('cronSchedule').value.trim()
|
|
704
|
+
const command=document.getElementById('cronCommand').value.trim()
|
|
705
|
+
const channel=document.getElementById('cronChannel').value
|
|
706
|
+
if(!name||!schedule||!command){alert('Name, schedule and command required');return}
|
|
707
|
+
closeCronModal()
|
|
708
|
+
try{await API.cronAdd({name,schedule,command,channel:channel||undefined});loadSchedule()}catch(e){alert('Job creation failed: '+e.message)}
|
|
676
709
|
}
|
|
677
710
|
|
|
678
711
|
// ===== INIT =====
|
|
679
712
|
document.getElementById('refreshBtn').onclick=()=>{const t=document.querySelector('.header-tab.active');t&&loadTab(t.dataset.tab)}
|
|
680
713
|
document.getElementById('archRefresh').onclick=()=>loadArchitect()
|
|
681
714
|
document.getElementById('newSkillBtn').onclick=()=>openSkillModal()
|
|
715
|
+
document.getElementById('newCronBtn').onclick=()=>openCronModal()
|
|
682
716
|
document.getElementById('deployBtn').onclick=()=>alert('Deploy Agent — coming soon')
|
|
683
717
|
document.getElementById('diagBtn').onclick=()=>alert('Diagnostics — coming soon')
|
|
684
718
|
document.getElementById('notifBtn').onclick=()=>alert('3 notifications pending')
|
package/dist/index.js
CHANGED
|
@@ -368086,7 +368086,7 @@ function getCachedVersion(options = {}) {
|
|
|
368086
368086
|
// package.json
|
|
368087
368087
|
var package_default = {
|
|
368088
368088
|
name: "@kl-c/matrixos",
|
|
368089
|
-
version: "0.3.
|
|
368089
|
+
version: "0.3.49",
|
|
368090
368090
|
description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
|
|
368091
368091
|
main: "./dist/index.js",
|
|
368092
368092
|
types: "dist/index.d.ts",
|
|
@@ -452232,6 +452232,9 @@ class CronRunner {
|
|
|
452232
452232
|
|
|
452233
452233
|
// packages/omo-opencode/src/features/cron/store.ts
|
|
452234
452234
|
import * as z67 from "zod";
|
|
452235
|
+
import { Database as Database3 } from "bun:sqlite";
|
|
452236
|
+
import { homedir as homedir38 } from "os";
|
|
452237
|
+
import { resolve as resolve43 } from "path";
|
|
452235
452238
|
var CronJobSchema = z67.object({
|
|
452236
452239
|
id: z67.string().min(1),
|
|
452237
452240
|
name: z67.string().min(1).max(100),
|
|
@@ -452243,15 +452246,34 @@ var CronJobSchema = z67.object({
|
|
|
452243
452246
|
createdAt: z67.string(),
|
|
452244
452247
|
updatedAt: z67.string()
|
|
452245
452248
|
}).strict();
|
|
452249
|
+
var DB_PATH = resolve43(homedir38(), ".local", "share", "opencode", "opencode.db");
|
|
452250
|
+
function openDb() {
|
|
452251
|
+
const db = new Database3(DB_PATH);
|
|
452252
|
+
db.run(`CREATE TABLE IF NOT EXISTS matrixos_cron (
|
|
452253
|
+
id TEXT PRIMARY KEY,
|
|
452254
|
+
name TEXT NOT NULL,
|
|
452255
|
+
schedule TEXT NOT NULL,
|
|
452256
|
+
command TEXT NOT NULL,
|
|
452257
|
+
channel TEXT,
|
|
452258
|
+
recipient TEXT,
|
|
452259
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
452260
|
+
created_at TEXT NOT NULL,
|
|
452261
|
+
updated_at TEXT NOT NULL
|
|
452262
|
+
)`);
|
|
452263
|
+
return db;
|
|
452264
|
+
}
|
|
452265
|
+
var counter = 0;
|
|
452266
|
+
function nextId() {
|
|
452267
|
+
counter += 1;
|
|
452268
|
+
return `cron-${Date.now()}-${counter}`;
|
|
452269
|
+
}
|
|
452246
452270
|
function createCronStore() {
|
|
452247
|
-
const
|
|
452248
|
-
let counter = 0;
|
|
452271
|
+
const db = openDb();
|
|
452249
452272
|
return {
|
|
452250
452273
|
add(input2) {
|
|
452251
|
-
counter += 1;
|
|
452252
452274
|
const now = new Date().toISOString();
|
|
452253
452275
|
const job = {
|
|
452254
|
-
id:
|
|
452276
|
+
id: nextId(),
|
|
452255
452277
|
name: input2.name,
|
|
452256
452278
|
schedule: input2.schedule,
|
|
452257
452279
|
command: input2.command,
|
|
@@ -452262,15 +452284,17 @@ function createCronStore() {
|
|
|
452262
452284
|
updatedAt: now
|
|
452263
452285
|
};
|
|
452264
452286
|
CronJobSchema.parse(job);
|
|
452265
|
-
|
|
452287
|
+
db.query(`INSERT INTO matrixos_cron (id, name, schedule, command, channel, recipient, enabled, created_at, updated_at)
|
|
452288
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(job.id, job.name, job.schedule, job.command, job.channel ?? null, job.recipient ?? null, job.enabled ? 1 : 0, job.createdAt, job.updatedAt);
|
|
452266
452289
|
return job;
|
|
452267
452290
|
},
|
|
452268
452291
|
get(id) {
|
|
452269
|
-
|
|
452292
|
+
const row = db.query("SELECT * FROM matrixos_cron WHERE id = ?").get(id);
|
|
452293
|
+
return row ? rowToJob(row) : undefined;
|
|
452270
452294
|
},
|
|
452271
452295
|
list(filter) {
|
|
452272
|
-
const all =
|
|
452273
|
-
return all.filter((j2) => {
|
|
452296
|
+
const all = db.query("SELECT * FROM matrixos_cron ORDER BY created_at DESC").all();
|
|
452297
|
+
return all.map(rowToJob).filter((j2) => {
|
|
452274
452298
|
if (filter?.enabled !== undefined && j2.enabled !== filter.enabled)
|
|
452275
452299
|
return false;
|
|
452276
452300
|
if (filter?.channel && j2.channel !== filter.channel)
|
|
@@ -452279,13 +452303,28 @@ function createCronStore() {
|
|
|
452279
452303
|
});
|
|
452280
452304
|
},
|
|
452281
452305
|
remove(id) {
|
|
452282
|
-
|
|
452306
|
+
const res = db.query("DELETE FROM matrixos_cron WHERE id = ?").run(id);
|
|
452307
|
+
return res.changes > 0;
|
|
452283
452308
|
},
|
|
452284
452309
|
size() {
|
|
452285
|
-
|
|
452310
|
+
const row = db.query("SELECT COUNT(*) as c FROM matrixos_cron").get();
|
|
452311
|
+
return row.c;
|
|
452286
452312
|
}
|
|
452287
452313
|
};
|
|
452288
452314
|
}
|
|
452315
|
+
function rowToJob(row) {
|
|
452316
|
+
return {
|
|
452317
|
+
id: String(row.id),
|
|
452318
|
+
name: String(row.name),
|
|
452319
|
+
schedule: String(row.schedule),
|
|
452320
|
+
command: String(row.command),
|
|
452321
|
+
channel: row.channel ? row.channel : undefined,
|
|
452322
|
+
recipient: row.recipient ? String(row.recipient) : undefined,
|
|
452323
|
+
enabled: Number(row.enabled) === 1,
|
|
452324
|
+
createdAt: String(row.created_at),
|
|
452325
|
+
updatedAt: String(row.updated_at)
|
|
452326
|
+
};
|
|
452327
|
+
}
|
|
452289
452328
|
|
|
452290
452329
|
// packages/omo-opencode/src/testing/create-plugin-module.ts
|
|
452291
452330
|
import * as fs31 from "fs";
|
|
@@ -452647,7 +452686,7 @@ function createPluginModule(overrides2 = {}) {
|
|
|
452647
452686
|
try {
|
|
452648
452687
|
await gateway.stop();
|
|
452649
452688
|
} catch {}
|
|
452650
|
-
await new Promise((
|
|
452689
|
+
await new Promise((resolve44) => setTimeout(resolve44, 3000));
|
|
452651
452690
|
}
|
|
452652
452691
|
try {
|
|
452653
452692
|
const gwConfig = buildGwConfig();
|
|
@@ -452690,7 +452729,7 @@ function createPluginModule(overrides2 = {}) {
|
|
|
452690
452729
|
loadGatewayEnvFile(undefined, true);
|
|
452691
452730
|
if (gateway) {
|
|
452692
452731
|
await gateway.stop();
|
|
452693
|
-
await new Promise((
|
|
452732
|
+
await new Promise((resolve44) => setTimeout(resolve44, 1000));
|
|
452694
452733
|
}
|
|
452695
452734
|
await createAndStartGateway();
|
|
452696
452735
|
} catch (error) {
|
|
@@ -452705,7 +452744,7 @@ function createPluginModule(overrides2 = {}) {
|
|
|
452705
452744
|
const envPath = path29.join(getConfigDir(), GATEWAY_ENV_FILENAME);
|
|
452706
452745
|
try {
|
|
452707
452746
|
gatewayWatcher = fs31.watch(envPath, { persistent: false }, async (_eventType) => {
|
|
452708
|
-
await new Promise((
|
|
452747
|
+
await new Promise((resolve44) => setTimeout(resolve44, 300));
|
|
452709
452748
|
await reloadGateway();
|
|
452710
452749
|
});
|
|
452711
452750
|
} catch (error) {
|
package/package.json
CHANGED