@volter/supercode-orchestrator 0.4.94 → 0.4.96
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/board/cli.mjs +3 -2
- package/board/rows.mjs +16 -0
- package/board/workflow.mjs +1 -1
- package/board/ztrack.mjs +12 -2
- package/package.json +1 -1
package/board/cli.mjs
CHANGED
|
@@ -236,7 +236,8 @@ export async function runWorkflow(argv) {
|
|
|
236
236
|
const ids = (first = rest) => [...first, ...(args.ids ?? [])];
|
|
237
237
|
|
|
238
238
|
// a caller that is a card's own session (its harness names it; the board recorded which session it launched)
|
|
239
|
-
const
|
|
239
|
+
const listing = ['list','ls'].includes(verb);
|
|
240
|
+
const sid = listing && !args.mine ? null : callerSession();
|
|
240
241
|
// what this command records is the calling session's act (its address, as its subscriptions name it)
|
|
241
242
|
if (sid) setActor(`sc:${localMachine()}:${sid === process.env.CODEX_THREAD_ID ? 'codex' : 'claude-code'}:${sid}`);
|
|
242
243
|
if (sid && !READS.has(verb) && boardExists(root, slug)) {
|
|
@@ -244,7 +245,7 @@ export async function runWorkflow(argv) {
|
|
|
244
245
|
}
|
|
245
246
|
// the board's workflow (the IR's): what each verb does, and who may send it, is its
|
|
246
247
|
// every verb reads the board through its workflow (a list settles cards too), so every verb loads it
|
|
247
|
-
if (verb !== 'help') await loadWorkflow(root).catch((error) => { if (verb !== 'init' && verb !== 'boards') throw error; });
|
|
248
|
+
if (verb !== 'help' && !listing) await loadWorkflow(root).catch((error) => { if (verb !== 'init' && verb !== 'boards') throw error; });
|
|
248
249
|
engine.setCaller((db, cardId) => rolesFor(db, cardId, sid, workflowFor(root).params));
|
|
249
250
|
// a verb with no session behind it (a person at the CLI, the board file's sync) is the manager's, as its roles are
|
|
250
251
|
if (!sid && verb !== 'help') { try { setActor([].concat(workflowFor(root).params?.managers ?? [])[0] ?? null); } catch { /* no workflow */ } }
|
package/board/rows.mjs
CHANGED
|
@@ -57,6 +57,21 @@ export class RuntimeRows {
|
|
|
57
57
|
return {name,key,value:row,source:{name,key,row}};
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
+
mirror(changes, revision) {
|
|
61
|
+
const previous=Number(this.db.prepare("SELECT value FROM state WHERE key='read_revision'").get()?.value??-1);
|
|
62
|
+
for(const name of ['tasks','supercode_cards']) {
|
|
63
|
+
const table=this.tables.get(name); if(!table)return;
|
|
64
|
+
this.db.exec(table.sql.replace(/^CREATE TABLE (?:IF NOT EXISTS )?(?:"[^"]+"|\w+)/,`CREATE TABLE IF NOT EXISTS ${quote('read_'+name)}`));
|
|
65
|
+
}
|
|
66
|
+
const rows=previous===revision-1?changes.filter(c=>['tasks','supercode_cards'].includes(c.source.name)).map(c=>c.source):this.db.prepare("SELECT name,key,value FROM runtime_rows WHERE name IN ('@task_cache','@card_cache')").all().map(r=>({name:r.name==='@task_cache'?'tasks':'supercode_cards',key:JSON.stringify([r.key]),row:json(r.value,null)}));
|
|
67
|
+
for(const {name,key,row} of rows) {
|
|
68
|
+
const table=this.tables.get(name), target=quote('read_'+name);
|
|
69
|
+
if(!row) {this.db.prepare(`DELETE FROM ${target} WHERE ${table.keys.map(k=>`${quote(k)} IS ?`).join(' AND ')}`).run(...JSON.parse(key));continue;}
|
|
70
|
+
const keys=Object.keys(row);
|
|
71
|
+
this.db.prepare(`INSERT OR REPLACE INTO ${target} (${keys.map(quote)}) VALUES (${keys.map(()=>'?')})`).run(...keys.map(k=>row[k]??null));
|
|
72
|
+
}
|
|
73
|
+
this.db.prepare("INSERT INTO state VALUES('read_revision',?) ON CONFLICT(key) DO UPDATE SET value=excluded.value").run(String(revision));
|
|
74
|
+
}
|
|
60
75
|
write(changes) {
|
|
61
76
|
this.db.exec(`CREATE TABLE IF NOT EXISTS runtime_schema(name TEXT PRIMARY KEY,sql TEXT NOT NULL); CREATE TABLE IF NOT EXISTS runtime_rows(name TEXT,key TEXT,value TEXT,revision INTEGER NOT NULL,PRIMARY KEY(name,key)); CREATE INDEX IF NOT EXISTS runtime_rows_revision ON runtime_rows(revision); CREATE INDEX IF NOT EXISTS runtime_rows_task ON runtime_rows(name,json_extract(value,'$.task_id'),json_extract(value,'$.id')); CREATE INDEX IF NOT EXISTS runtime_rows_id ON runtime_rows(name,json_extract(value,'$.id'))`);
|
|
62
77
|
const revision=Number(this.db.prepare("SELECT value FROM state WHERE key='rows_revision'").get()?.value??0)+1;
|
|
@@ -77,6 +92,7 @@ export class RuntimeRows {
|
|
|
77
92
|
}
|
|
78
93
|
for(const {name,sql} of this.tables.values())if(!OMIT.has(name))this.db.prepare('INSERT OR IGNORE INTO runtime_schema VALUES(?,?)').run(name,sql);
|
|
79
94
|
this.db.prepare("INSERT INTO state VALUES('rows_revision',?) ON CONFLICT(key) DO UPDATE SET value=excluded.value").run(String(revision));
|
|
95
|
+
this.mirror(changes,revision);
|
|
80
96
|
this.revision=revision;
|
|
81
97
|
}
|
|
82
98
|
}
|
package/board/workflow.mjs
CHANGED
|
@@ -113,7 +113,7 @@ function lastCommitAt(path, id) { return path ? commitTimes.get(`${path}:${id}`)
|
|
|
113
113
|
export function refreshCardInputs(board, id, { commits = false } = {}) {
|
|
114
114
|
const task=board.db.prepare('SELECT t.*,c.subtask_of FROM tasks t LEFT JOIN supercode_cards c ON c.task_id=t.id WHERE t.id=?').get(id);
|
|
115
115
|
if (!task)return;
|
|
116
|
-
if (commits) {
|
|
116
|
+
if (commits && !task.subtask_of) {
|
|
117
117
|
const own=task.workspace_kind!=='scratch'?task.workspace_path:null;
|
|
118
118
|
const parent=!own && task.subtask_of?board.db.prepare('SELECT workspace_path FROM tasks WHERE id=?').get(task.subtask_of)?.workspace_path:null;
|
|
119
119
|
const path=own??parent??null;
|
package/board/ztrack.mjs
CHANGED
|
@@ -219,12 +219,21 @@ class ZtrackBoard {
|
|
|
219
219
|
this.mem.prepare(`INSERT OR REPLACE INTO ${quote(table)} (${keys.map(quote).join(',')}) VALUES (${keys.map(() => '?').join(',')})`).run(...keys.map((k) => row[k] ?? null));
|
|
220
220
|
}
|
|
221
221
|
openCachedReader(saved) {
|
|
222
|
+
const native = this.get('read_revision',-1)===this.get('rows_revision',0);
|
|
223
|
+
if(this.cachedReader && native!==this.nativeReader)this.invalidate();
|
|
222
224
|
if (!this.cachedReader) {
|
|
223
225
|
this.mem?.close(); this.mem=new DatabaseSync(':memory:'); this.init(this.mem,{fresh:true});
|
|
224
226
|
for(const row of this.runtime.prepare('SELECT name,sql FROM runtime_schema').all())this.mem.exec(row.sql.replace('CREATE TABLE ','CREATE TABLE IF NOT EXISTS '));
|
|
225
|
-
this.mem.prepare('ATTACH DATABASE ? AS source').run(
|
|
227
|
+
this.mem.prepare('ATTACH DATABASE ? AS source').run(this.runtimePath);
|
|
226
228
|
const tables=this.mem.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();
|
|
227
229
|
for(const {name} of tables) {
|
|
230
|
+
if (native && name==='tasks') {
|
|
231
|
+
const fields=this.mem.prepare('PRAGMA main.table_info(tasks)').all().map(({name:column})=>column==='status'?'COALESCE(c.stage,t.status) AS status':`t.${quote(column)}`);
|
|
232
|
+
this.mem.exec(`CREATE TEMP VIEW tasks AS SELECT ${fields.join(',')} FROM source.read_tasks t LEFT JOIN source.read_supercode_cards c ON c.task_id=t.id`);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if(native && name==='supercode_cards') {this.mem.exec('CREATE TEMP VIEW supercode_cards AS SELECT * FROM source.read_supercode_cards');continue;}
|
|
236
|
+
if(native && name==='task_links') {this.mem.exec("CREATE TEMP VIEW task_links AS SELECT json_extract(b.value,'$.id') parent_id,r.task_id child_id FROM source.read_supercode_cards r,json_each(r.blocked_by) b WHERE json_extract(b.value,'$.kind')='card'");continue;}
|
|
228
237
|
if(name==='task_links') {
|
|
229
238
|
this.mem.exec(`CREATE TEMP VIEW task_links AS SELECT json_extract(b.value,'$.id') parent_id,r.key child_id FROM source.runtime_rows r,json_each(json_extract(r.value,'$.blocked_by')) b WHERE r.name='@card_cache' AND json_extract(b.value,'$.kind')='card'`);
|
|
230
239
|
continue;
|
|
@@ -235,7 +244,8 @@ class ZtrackBoard {
|
|
|
235
244
|
const join=name==='tasks'?" LEFT JOIN source.runtime_rows c ON c.name='@card_cache' AND c.key=r.key":'';
|
|
236
245
|
this.mem.exec(`CREATE TEMP VIEW ${quote(name)} AS SELECT ${fields.join(',')} FROM source.runtime_rows r${join} WHERE r.name='${recordName}' AND r.value IS NOT NULL`);
|
|
237
246
|
}
|
|
238
|
-
this.
|
|
247
|
+
this.mem.exec('PRAGMA query_only=ON');
|
|
248
|
+
this.cachedReader=true;this.nativeReader=native;
|
|
239
249
|
}
|
|
240
250
|
this.saved=saved; this.errors.clear();
|
|
241
251
|
for(const [id,reason] of saved.errors??[])this.errors.set(id,reason);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-orchestrator",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.96",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The orchestrator runtime over the Volter Harness ontology: one typed operational model whose folder is its serialization, read and written through the harness orchestration doors (docs/ORCHESTRATOR-IR.md)",
|
|
6
6
|
"exports": {
|