@volter/supercode-orchestrator 0.4.75 → 0.4.76

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/engine.mjs CHANGED
@@ -105,7 +105,7 @@ export function currentRun(db, taskId) {
105
105
  export function setRunSession(db, runId, session) {
106
106
  const row = one(db, 'SELECT metadata FROM task_runs WHERE id = ?', runId);
107
107
  const whole = json(row?.metadata, {}) ?? {};
108
- whole.supercode = session;
108
+ whole.supercode = { ...whole.supercode, ...session };
109
109
  run(db, 'UPDATE task_runs SET metadata = ? WHERE id = ?', JSON.stringify(whole), runId);
110
110
  return whole;
111
111
  }
package/board/store.mjs CHANGED
@@ -203,6 +203,17 @@ export const actorOf = () => actor;
203
203
  export function setActor(address) { actor = address || null; }
204
204
 
205
205
  export function event(db, taskId, kind, payload = null, runId = null) {
206
+ // Session observations belong to the run machine. Legacy runs without a machine state retain
207
+ // their Hermes event stream; a new instance never sends supervision as card notices.
208
+ if (runId && ['claimed', 'spawned', 'session_started', 'session_resumed', 'session_replaced', 'session_adopted', 'claim_extended'].includes(kind)) {
209
+ const row = db.prepare('SELECT metadata FROM task_runs WHERE id = ?').get(runId);
210
+ const meta = json(row?.metadata, {}) ?? {};
211
+ if (meta.supercode?.state) {
212
+ meta.events = [...(meta.events ?? []), { kind, payload, by: actor, at: now() }];
213
+ db.prepare('UPDATE task_runs SET metadata = ? WHERE id = ?').run(JSON.stringify(meta), runId);
214
+ return 0;
215
+ }
216
+ }
206
217
  const said = actor && !(payload && 'by' in payload) ? { ...(payload ?? {}), by: actor } : payload;
207
218
  const r = db.prepare('INSERT INTO task_events (task_id, run_id, kind, payload, created_at) VALUES (?, ?, ?, ?, ?)')
208
219
  .run(taskId, runId, kind, said ? JSON.stringify(said) : null, now());
@@ -5,7 +5,7 @@
5
5
  // the engine's primitives (the rows Hermes's tables hold); the I/O an action asks for (stopping a worker, closing a
6
6
  // pane, sending a session a message, cleaning a workspace) is answered as effects the caller runs after commit.
7
7
  import { spawnSync } from 'node:child_process';
8
- import { readFileSync } from 'node:fs';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
9
  import { resolve, relative, isAbsolute } from 'node:path';
10
10
  import { randomBytes } from 'node:crypto';
11
11
  import { actorOf, event as record, json, now } from './store.mjs';
@@ -64,6 +64,7 @@ export function storedAs(workflow, status) {
64
64
 
65
65
  /** Where a card interrupted in `status` resumes: its `exited` transition's unguarded target (data, not a rule here). */
66
66
  export function resumeOf(workflow, status) {
67
+ if (workflow.statuses[status]?.resume_as) return workflow.statuses[status].resume_as;
67
68
  const exited = workflow.statuses[status]?.on?.exited ?? [];
68
69
  const fallback = [...exited].reverse().find((t) => !t.guard && t.target && !t.target.includes('{{'));
69
70
  return fallback?.target ?? status;
@@ -221,6 +222,8 @@ export function scopeOf(db, board, task, { params, event = {}, extra = {} } = {}
221
222
  return lastCommitAt(own ?? arcWs ?? null, task.id);
222
223
  },
223
224
  };
225
+ const runMeta = json(currentRun?.metadata, {}) ?? {};
226
+ for (const e of runMeta.events ?? []) card.last_events[e.kind] = { created_at: e.at, payload: e.payload ?? {} };
224
227
  for (const [key, expr] of Object.entries(loaded.get(board.root)?.workflow?.derived ?? {})) card[key] = evaluate(expr, { card, event, params, now: now() });
225
228
  return {
226
229
  card,
@@ -278,6 +281,7 @@ export function fire(db, board, entry, id, name, { roles = [], payload = {}, ext
278
281
  const effects = [];
279
282
  const to = take(db, board, entry, task, from, taken, scope, effects);
280
283
  settle(db, board, entry, id, effects);
284
+ projectStatus(db, board, entry, id);
281
285
  return { from, to: statusOf(db, cardOf(db, id)), moved: to !== from, effects };
282
286
  }
283
287
 
@@ -346,7 +350,7 @@ export function settle(db, board, entry, id, effects = []) {
346
350
  const scope = scopeOf(db, board, task, { params, extra: { lanes: lanesIn(entry) } });
347
351
  let t = (workflow.statuses[from]?.always ?? []).find((x) => holds(x.guard ?? null, scope));
348
352
  if (!t) t = dueAfter(db, workflow, task, from, scope);
349
- if (!t) return effects;
353
+ if (!t) { projectStatus(db, board, entry, id); return effects; }
350
354
  const to = take(db, board, entry, task, from, t, scope, effects);
351
355
  if (to === from) return effects;
352
356
  }
@@ -708,6 +712,7 @@ export function runSpec(entry, status) {
708
712
  const file = resolve(entry.root, spec.prompt_file);
709
713
  const rel = relative(entry.root, file);
710
714
  if (rel.startsWith('..') || isAbsolute(rel)) throw new Error('prompt file must live in the orchestration home');
715
+ if (!existsSync(file) && spec.prompt) return spec; // embedded prompts of the built-in instance
711
716
  return { ...spec, prompt: readFileSync(file, 'utf8') };
712
717
  }
713
718
 
@@ -728,7 +733,7 @@ export function fireRun(db, board, entry, id, name, { roles = [], payload = {},
728
733
  const from = meta.supercode?.state ?? machine.initial;
729
734
  const scope = scopeOf(db, board, task, { params: entry.params, event: payload, extra: { ...extra, sender: roles, run: { ...row, state: from } } });
730
735
  const candidates = [...(machine.states[from]?.on?.[name] ?? []), ...(machine.on?.[name] ?? [])];
731
- const t = candidates.find((t) => (!t.by?.length || t.by.some((r) => roles.includes(r))) && holds(t.guard ?? null, scope));
736
+ const t = candidates.find((t) => (!t.from?.length || t.from.includes(from)) && (!t.by?.length || t.by.some((r) => roles.includes(r))) && holds(t.guard ?? null, scope));
732
737
  if (!t) { const error = new Error(`${id}: run event ${name} does not apply`); error.noTransition = true; throw error; }
733
738
  for (const v of t.validate ?? []) if (!holds(v.expr, scope)) throw new Error(v.message);
734
739
  const to = t.target ? String(templateValue(t.target, scope)) : from;
@@ -746,6 +751,7 @@ export function fireRun(db, board, entry, id, name, { roles = [], payload = {},
746
751
  const outcome = (machine.outcomes?.[to] ?? []).find((t) => holds(t.guard ?? null, after));
747
752
  if (outcome) take(db, board, entry, cardOf(db, id), statusOf(db, cardOf(db, id)), outcome, after, effects);
748
753
  }
754
+ projectStatus(db, board, entry, id);
749
755
  return { from: status, to: statusOf(db, cardOf(db, id)), effects };
750
756
  }
751
757
 
@@ -762,3 +768,15 @@ function settleRelations(db, board, entry, id, effects) {
762
768
  if (name) effects.push(...fire(db, board, entry, id, name, { roles: ['platform'], payload: { on: block.id, reason: answer ? `reply ${answer}` : `${block.id} ${status}` } }).effects);
763
769
  }
764
770
  }
771
+
772
+
773
+ export function projectStatus(db, board, entry, id) {
774
+ if (!entry.workflow.stored_as?.length) return;
775
+ const task = cardOf(db, id);
776
+ const status = statusOf(db, task);
777
+ const scope = scopeOf(db, board, task, { params: entry.params });
778
+ const rule = entry.workflow.stored_as.find((r) => holds(r.guard, scope));
779
+ const stored = rule?.status ?? storedAs(entry.workflow, status);
780
+ run(db, 'UPDATE tasks SET status = ? WHERE id = ?', stored, id);
781
+ run(db, 'INSERT INTO supercode_cards (task_id, stage) VALUES (?, ?) ON CONFLICT(task_id) DO UPDATE SET stage = excluded.stage', id, status);
782
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-orchestrator",
3
- "version": "0.4.75",
3
+ "version": "0.4.76",
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": {