@volter/supercode-orchestrator 0.4.65 → 0.4.67
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 -1
- package/board/dispatch.mjs +22 -5
- package/board/store.mjs +7 -1
- package/board/workflow.mjs +4 -3
- package/package.json +1 -1
package/board/cli.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { basename, join, resolve } from 'node:path';
|
|
|
10
10
|
import { tmpdir } from 'node:os';
|
|
11
11
|
import { read } from '../orchestration.mjs';
|
|
12
12
|
import { holdDispatcherLock } from '../hermes-locks.mjs';
|
|
13
|
-
import { backingOf, boardExists, boardPath, DEFAULT_BOARD, event, json, listBoards, logsDir, now, openBoard, tx } from './store.mjs';
|
|
13
|
+
import { backingOf, boardExists, boardPath, DEFAULT_BOARD, event, json, listBoards, logsDir, now, openBoard, setActor, tx } from './store.mjs';
|
|
14
14
|
import * as engine from './engine.mjs';
|
|
15
15
|
import { adoptSession, boardAddress, boardLabel, boardSettings, callerSession, lanesOf, localMachine, observeFleet, paused, plan, startCard, tick } from './dispatch.mjs';
|
|
16
16
|
import { loadWorkflow, statusOf, useWorkflow, workflowEntry, workflowFor } from './workflow.mjs';
|
|
@@ -234,6 +234,8 @@ export async function runWorkflow(argv) {
|
|
|
234
234
|
|
|
235
235
|
// a caller that is a card's own session (its harness names it; the board recorded which session it launched)
|
|
236
236
|
const sid = callerSession();
|
|
237
|
+
// what this command records is the calling session's act (its address, as its subscriptions name it)
|
|
238
|
+
if (sid) setActor(`sc:${localMachine()}:${sid === process.env.CODEX_THREAD_ID ? 'codex' : 'claude-code'}:${sid}`);
|
|
237
239
|
if (sid && !READS.has(verb) && boardExists(root, slug)) {
|
|
238
240
|
withBoard((b) => { const own = ownCard(b.db, sid); if (own) authorize(b.db, verb, rest, args, own); });
|
|
239
241
|
}
|
package/board/dispatch.mjs
CHANGED
|
@@ -500,11 +500,6 @@ function observeIdle(board, fleet, settings, report, entry, effects) {
|
|
|
500
500
|
|
|
501
501
|
/** A session effect a committed move asked for: a message to the card's current actor, or closing a slot's pane. */
|
|
502
502
|
export async function sessionEffect(board, e) {
|
|
503
|
-
if (e.kind === 'tell') {
|
|
504
|
-
// an ask is sent under the id the card's block waits on
|
|
505
|
-
await send(boardAddress(board.label), board.label, e.to, e.text, e.messageId ?? `board-tell-${e.id}-${now()}`, { ask: Boolean(e.messageId) });
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
503
|
if (e.kind === 'send_to_actor') {
|
|
509
504
|
const run = tx(board, (db) => currentRun(db, e.id));
|
|
510
505
|
const session = run?.metadata?.supercode;
|
|
@@ -854,6 +849,25 @@ async function send(from, label, to, body, key, { queue = false, ask = false } =
|
|
|
854
849
|
if (answer.code !== 0) throw new Error((answer.text || r.stderr || `no answer (exit ${r.code})`).trim().slice(-300));
|
|
855
850
|
}
|
|
856
851
|
|
|
852
|
+
/**
|
|
853
|
+
* The messages the workflow has the board send (`tell`, `ask`: board_message events) that it has not sent yet, sent now
|
|
854
|
+
* and marked board_message_sent. A question goes under the id its card waits on; a resend of a sent one is a no-op
|
|
855
|
+
* (the id is the send's idempotency key). One that fails is tried again next tick.
|
|
856
|
+
*/
|
|
857
|
+
async function sendBoardMessages(board, report) {
|
|
858
|
+
const rows = tx(board, (db) => db.prepare(`SELECT id, task_id, payload FROM task_events e WHERE kind = 'board_message' AND NOT EXISTS
|
|
859
|
+
(SELECT 1 FROM task_events s WHERE s.kind = 'board_message_sent' AND s.task_id = e.task_id AND json_extract(s.payload, '$.event') = e.id) ORDER BY id`).all());
|
|
860
|
+
for (const row of rows) {
|
|
861
|
+
const m = json(row.payload, {}) ?? {};
|
|
862
|
+
try {
|
|
863
|
+
await send(boardAddress(board.label), board.label, m.to, m.text, m.message_id ?? `board-message-${row.id}`, { ask: Boolean(m.message_id) });
|
|
864
|
+
tx(board, (db) => event(db, row.task_id, 'board_message_sent', { event: row.id, to: m.to, ...(m.message_id ? { message_id: m.message_id } : {}) }));
|
|
865
|
+
} catch (error) {
|
|
866
|
+
report.undelivered.push([row.task_id, m.to, String(error.message).slice(-200)]);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
857
871
|
/** The board's own address: where its notices come from and where card updates are mailed. */
|
|
858
872
|
export const boardAddress = (label) => `sc:${localMachine()}:board:${label.replace(/[^A-Za-z0-9_.-]/g, '-')}`;
|
|
859
873
|
|
|
@@ -917,6 +931,8 @@ async function notify(board, fleet, report, entry) {
|
|
|
917
931
|
try {
|
|
918
932
|
for (const ev of events) {
|
|
919
933
|
const p = json(ev.payload, {}) ?? {};
|
|
934
|
+
// nobody is told of their own act
|
|
935
|
+
if (p.by && p.by === sub.chat_id) { cursor = ev.id; continue; }
|
|
920
936
|
let text;
|
|
921
937
|
if (ev.kind === 'commented') {
|
|
922
938
|
if (p.author === sub.chat_id) { cursor = ev.id; continue; }
|
|
@@ -1216,6 +1232,7 @@ export async function tick({ root, lanes, settings, only = null, slugs = null, d
|
|
|
1216
1232
|
supervise(board, fleet, settings, report, entry, effects); closeRequested(board, report); phase('supervise');
|
|
1217
1233
|
report.unsettled = [];
|
|
1218
1234
|
report.promoted = recomputeReady(board, effects, report.unsettled);
|
|
1235
|
+
await sendBoardMessages(board, report);
|
|
1219
1236
|
const before = report.started.length;
|
|
1220
1237
|
if (dispatch) startCards(board, fleet, lanes, settings, report, entry, effects, { only, hostRunning });
|
|
1221
1238
|
hostRunning += report.started.length - before; phase('start');
|
package/board/store.mjs
CHANGED
|
@@ -196,8 +196,14 @@ export function json(text, fallback = null) {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/** Append one event to a card's thread (Hermes's `task_events`); answers its id. */
|
|
199
|
+
// the session whose command this process runs (its address), set by the CLI: each event it records says who acted
|
|
200
|
+
// (`by`), so the session is not told of its own act
|
|
201
|
+
let actor = null;
|
|
202
|
+
export function setActor(address) { actor = address || null; }
|
|
203
|
+
|
|
199
204
|
export function event(db, taskId, kind, payload = null, runId = null) {
|
|
205
|
+
const said = actor && !(payload && 'by' in payload) ? { ...(payload ?? {}), by: actor } : payload;
|
|
200
206
|
const r = db.prepare('INSERT INTO task_events (task_id, run_id, kind, payload, created_at) VALUES (?, ?, ?, ?, ?)')
|
|
201
|
-
.run(taskId, runId, kind,
|
|
207
|
+
.run(taskId, runId, kind, said ? JSON.stringify(said) : null, now());
|
|
202
208
|
return Number(r.lastInsertRowid);
|
|
203
209
|
}
|
package/board/workflow.mjs
CHANGED
|
@@ -534,15 +534,16 @@ const ACTIONS = {
|
|
|
534
534
|
return;
|
|
535
535
|
}
|
|
536
536
|
},
|
|
537
|
-
// a message from the board to a session (`to`: its address)
|
|
538
|
-
|
|
537
|
+
// a message from the board to a session (`to`: its address), kept on the card as a board_message event until the
|
|
538
|
+
// dispatcher has sent it: a move settled by any verb (a list settles too) is never lost with its effects
|
|
539
|
+
tell(ctx, { to, text }) { if (to) record(ctx.db, ctx.id, 'board_message', { to: String(to), text: String(text ?? '') }, null); },
|
|
539
540
|
// a question from the board to a session, sent under a message id chosen now: `{{asked}}` in the actions after it is
|
|
540
541
|
// that id (what a block waits on), and the answer to it lands in the board's mailbox
|
|
541
542
|
ask(ctx, { to, text }) {
|
|
542
543
|
if (!to) throw new Error(`the workflow asks nobody about ${ctx.id} (ask.to is empty)`);
|
|
543
544
|
const id = `m-${randomBytes(12).toString('hex')}`;
|
|
544
545
|
ctx.scope.asked = id;
|
|
545
|
-
ctx.
|
|
546
|
+
record(ctx.db, ctx.id, 'board_message', { to: String(to), text: `${String(text ?? '')}\n\nAnswer with reply_to ${id}.`, message_id: id }, null);
|
|
546
547
|
},
|
|
547
548
|
send_to_actor(ctx, text) { ctx.effects.push({ kind: 'send_to_actor', id: ctx.id, text }); },
|
|
548
549
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-orchestrator",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.67",
|
|
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": {
|