@volter/supercode-orchestrator 0.4.59 → 0.4.61

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 CHANGED
@@ -767,7 +767,7 @@ export async function runWorkflow(argv) {
767
767
  case 'close': {
768
768
  need(1, 'a card id');
769
769
  const closed = withBoard((b) => closeSession(b, id));
770
- say(args, closed ? `closed ${closed.session_id} (pane ${closed.pane} on ${closed.machine})` : `${id} has no live session`, { ok: true, closed });
770
+ say(args, closed ? closed.map((c) => `closed ${c.session_id} (pane ${c.pane} on ${c.machine})`).join('\n') : `${id} has no live session`, { ok: true, closed });
771
771
  return 0;
772
772
  }
773
773
 
@@ -1044,17 +1044,28 @@ function authorize(db, verb, rest, args, own) {
1044
1044
  for (const other of args.ids ?? []) if (other !== own.id && engine.getTask(db, other)?.subtask_of !== own.id) refuse(`writes only its own card and its subtasks, not ${other}`);
1045
1045
  }
1046
1046
 
1047
- /** Close the live session of a card that is not running, freeing its machine's place. */
1047
+ /** Close the live sessions of a card that is not running (its worker's and its reviewers'), freeing its machine's place. */
1048
1048
  function closeSession(board, id) {
1049
- const { task, session } = tx(board, (db) => ({ task: engine.getTask(db, id), session: engine.lastSession(db, id) }));
1049
+ const { task, rows } = tx(board, (db) => ({ task: engine.getTask(db, id), rows: db.prepare('SELECT id, metadata FROM task_runs WHERE task_id = ? AND metadata IS NOT NULL ORDER BY id DESC').all(id) }));
1050
1050
  if (!task) throw new Error(`no card ${id}`);
1051
1051
  if (task.status === 'running') throw new Error(`${id} is running; block, complete or reclaim it before closing its session`);
1052
- if (!session?.pane) return null;
1053
- // the board closes its card's pane, whichever session ran `workflow close`
1054
- const r = spawnSync(process.env.SUPERCODE_BIN || 'supercode', ['teams', 'panes', 'close', session.pane, '--machine', session.machine], { cwd: tmpdir(), encoding: 'utf8', timeout: 60_000, env: { ...process.env, SUPERCODE_CALLER: boardAddress(board.label) } });
1055
- if (r.status !== 0) throw new Error(`closing pane ${session.pane} on ${session.machine}: ${(r.stderr || r.stdout).trim().slice(-300)}`);
1056
- tx(board, (db) => event(db, id, 'session_closed', { session_id: session.session_id, machine: session.machine, pane: session.pane }));
1057
- return session;
1052
+ const closed = [];
1053
+ const seen = new Set();
1054
+ for (const row of rows) {
1055
+ const session = json(row.metadata, {})?.supercode;
1056
+ if (!session?.pane || session.closed_at || seen.has(session.session_id)) continue;
1057
+ seen.add(session.session_id);
1058
+ // the board closes its card's pane, whichever session ran `workflow close`
1059
+ const r = spawnSync(process.env.SUPERCODE_BIN || 'supercode', ['teams', 'panes', 'close', session.pane, '--machine', session.machine], { cwd: tmpdir(), encoding: 'utf8', timeout: 60_000, env: { ...process.env, SUPERCODE_CALLER: boardAddress(board.label) } });
1060
+ if (r.status !== 0) throw new Error(`closing pane ${session.pane} on ${session.machine}: ${(r.stderr || r.stdout).trim().slice(-300)}`);
1061
+ tx(board, (db) => {
1062
+ const whole = json(db.prepare('SELECT metadata FROM task_runs WHERE id = ?').get(row.id)?.metadata, {}) ?? {};
1063
+ db.prepare('UPDATE task_runs SET metadata = ? WHERE id = ?').run(JSON.stringify({ ...whole, supercode: { ...whole.supercode, closed_at: now() } }), row.id);
1064
+ event(db, id, 'session_closed', { session_id: session.session_id, machine: session.machine, pane: session.pane });
1065
+ });
1066
+ closed.push(session);
1067
+ }
1068
+ return closed.length ? closed : null;
1058
1069
  }
1059
1070
 
1060
1071
  export function summary(r) {
@@ -456,7 +456,13 @@ const ACTIONS = {
456
456
  const e = said ?? {};
457
457
  const summary = e.summary ?? null;
458
458
  run(ctx.db, 'UPDATE tasks SET result = COALESCE(?, result), completed_at = COALESCE(completed_at, ?) WHERE id = ?', e.result ?? summary ?? null, now(), ctx.id);
459
- if (ctx.runId) run(ctx.db, 'UPDATE task_runs SET summary = COALESCE(?, summary), metadata = COALESCE(?, metadata) WHERE id = ?', summary, e.metadata ? JSON.stringify(e.metadata) : null, ctx.runId);
459
+ if (!ctx.runId) return;
460
+ // the completion's metadata joins the run's; the board's record of the run's session (`supercode`) stays, so the
461
+ // session is still closed when the card is done
462
+ const was = json(one(ctx.db, 'SELECT metadata FROM task_runs WHERE id = ?', ctx.runId)?.metadata, {}) ?? {};
463
+ const given = e.metadata && typeof e.metadata === 'object' ? e.metadata : null;
464
+ run(ctx.db, 'UPDATE task_runs SET summary = COALESCE(?, summary), metadata = ? WHERE id = ?', summary,
465
+ given ? JSON.stringify({ ...was, ...given, ...(was.supercode ? { supercode: was.supercode } : {}) }) : (Object.keys(was).length ? JSON.stringify(was) : null), ctx.runId);
460
466
  },
461
467
  link(ctx, parent) {
462
468
  if (!one(ctx.db, 'SELECT id FROM tasks WHERE id = ?', parent)) throw new Error(`${parent} is no card on this board`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-orchestrator",
3
- "version": "0.4.59",
3
+ "version": "0.4.61",
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": {