@volter/supercode-orchestrator 0.5.124 → 0.5.125
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 +12 -3
- package/board/dispatch.mjs +22 -4
- package/board/store.mjs +4 -0
- package/package.json +1 -1
package/board/cli.mjs
CHANGED
|
@@ -26,7 +26,7 @@ import * as slowLog from '@volter/supercode-harness-sdk/slow-log';
|
|
|
26
26
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
27
27
|
import { fileURLToPath } from 'node:url';
|
|
28
28
|
import { homedir, tmpdir, userInfo } from 'node:os';
|
|
29
|
-
import { actorOf, heldConfigWatched, heldDocumentsChanged, heldDocumentsWatched, holdBoards, retireHeldBoards, releaseHeldBoards, publishMarked, view, backingPaths, layOut, backingOf, boardExists, boardPath, DEFAULT_BOARD, event, json, listBoards, logsDir, now, openBoard, setActor, setPrincipal, principalOf, isCaller, tx } from './store.mjs';
|
|
29
|
+
import { actorOf, heldConfigWatched, heldDocumentsChanged, heldDocumentsWatched, holdBoards, retireHeldBoards, releaseHeldBoards, publishMarked, view, backingPaths, layOut, backingOf, boardExists, boardPath, briefPath, DEFAULT_BOARD, event, json, listBoards, logsDir, now, openBoard, setActor, setPrincipal, principalOf, isCaller, tx } from './store.mjs';
|
|
30
30
|
import { isLocalWorkspace } from './workspace.mjs';
|
|
31
31
|
import { openZtrackBoard } from './ztrack.mjs';
|
|
32
32
|
import * as engine from './engine.mjs';
|
|
@@ -90,7 +90,7 @@ The board's verbs, with their flags:
|
|
|
90
90
|
[--tenant] [--priority] [--triage] [--idempotency-key] [--max-runtime 30m] [--created-by] [--skill]... [--max-retries]
|
|
91
91
|
[--model] [--provider] [--goal|--no-goal] [--goal-max-turns] [--initial-status blocked|running]
|
|
92
92
|
swarm <goal> --worker PROFILE:TITLE[:SKILL,SKILL]... --verifier P --synthesizer P
|
|
93
|
-
list [--mine] [--assignee] [--status] [--tenant] [--session] [--archived] [--sort] show <id> context <id> runs <id>
|
|
93
|
+
list [--mine] [--assignee] [--status] [--tenant] [--session] [--archived] [--sort] show <id> context <id> brief <id> [--run N] runs <id>
|
|
94
94
|
set <id> <assignee|machine|model|every> <value|none> [--provider] [--ids ...] assign <id> <profile|none> set-model <id> [model] [--provider] set-goal <id>... [--goal-max-turns N] [--off]
|
|
95
95
|
reassign <id> --agent AGENT [--role implementer] (moves a card role's assignment to another agent; sessions keep their identity)
|
|
96
96
|
claim <id> [--ttl] reclaim <id> [--reason] heartbeat <id> [--note] [--until <time|30m>] link|unlink <parent> <child>
|
|
@@ -634,6 +634,15 @@ export async function runVerb(argv) {
|
|
|
634
634
|
return 0;
|
|
635
635
|
}
|
|
636
636
|
|
|
637
|
+
case 'brief': {
|
|
638
|
+
need(1, 'a card id');
|
|
639
|
+
const run = args.run ?? withBoard((b) => view(b, (db) => engine.getTask(db, id)?.current_run_id));
|
|
640
|
+
const file = run == null ? null : briefPath(root, slug, id, run);
|
|
641
|
+
if (!file || !existsSync(file)) throw new Error(`the board keeps no brief for ${run == null ? 'a run' : `run ${run}`} of ${id}`);
|
|
642
|
+
current().out(readFileSync(file, 'utf8'));
|
|
643
|
+
return 0;
|
|
644
|
+
}
|
|
645
|
+
|
|
637
646
|
case 'context': need(1, 'a card id'); current().out(`${withBoard((b) => view(b, (db) => engine.cardContext(db, id)))}\n`); return 0;
|
|
638
647
|
|
|
639
648
|
case 'runs': {
|
|
@@ -1374,7 +1383,7 @@ function ownCard(db, sessionId) {
|
|
|
1374
1383
|
return engine.lastSession(db, hit.task_id)?.session_id === sessionId ? engine.getTask(db, hit.task_id) : null;
|
|
1375
1384
|
}
|
|
1376
1385
|
|
|
1377
|
-
const READS = new Set(['list', 'ls', 'show', 'context', 'runs', 'log', 'tail', 'watch', 'stats', 'assignees', 'diagnostics', 'diag', 'attachments', 'notify-list', 'capacity', 'help', 'init']);
|
|
1386
|
+
const READS = new Set(['list', 'ls', 'show', 'context', 'brief', 'runs', 'log', 'tail', 'watch', 'stats', 'assignees', 'diagnostics', 'diag', 'attachments', 'notify-list', 'capacity', 'help', 'init']);
|
|
1378
1387
|
|
|
1379
1388
|
/** The main session of each agent the workflow names a manager (`sc:<machine>:agent:<name>`), asked of this machine's
|
|
1380
1389
|
* daemon, which keeps agents' records (mail step 1c), once per call before its verb runs: a manager named by its agent
|
package/board/dispatch.mjs
CHANGED
|
@@ -39,7 +39,7 @@ import { homedir, hostname, tmpdir, totalmem } from 'node:os';
|
|
|
39
39
|
import { basename, dirname, join } from 'node:path';
|
|
40
40
|
import { createHash, randomUUID } from 'node:crypto';
|
|
41
41
|
import { fileURLToPath } from 'node:url';
|
|
42
|
-
import { view, boardCopyOf, boardPath, claimer, claimHolds, copyRefusal, event, json, listBoards, logsDir, newClaim, now, openBoard, setActor, storageFault, tx } from './store.mjs';
|
|
42
|
+
import { view, boardCopyOf, boardPath, briefPath, claimer, claimHolds, copyRefusal, event, json, listBoards, logsDir, newClaim, now, openBoard, setActor, storageFault, tx } from './store.mjs';
|
|
43
43
|
import { doors, fire, loadWorkflow, resumeOf, runSpec, runWorkingSeconds, requestSessionClose, retireSupersededRuns, refreshCardInputs, refreshRelationAnswers, transitionsFor, scopeOf, statusOf, projectStatus, storedStatus, templateValue, workflowFor } from './workflow.mjs';
|
|
44
44
|
import { checkWorkspace, assertWorkspaceOwner, notePresence, resolveWorkspace } from './workspace.mjs';
|
|
45
45
|
import { capacity, harnessDefaults, holdings } from './capacity.mjs';
|
|
@@ -922,13 +922,13 @@ async function launchAttempt(board, entry, id, lane, fleet, settings, runId) {
|
|
|
922
922
|
agent_profile_intent:structuredClone(agent.intended.resolved),
|
|
923
923
|
agent_env:agentEnvironment(agent,{root:board.root,context:normalMachine(task.machine??localMachine())===localMachine()?localReaderContext(team.org,agent.identity.id)??undefined:undefined})});
|
|
924
924
|
// The agent's own memory reaches every session of it: headless runs open its home; a pane, which may sit on
|
|
925
|
-
// another machine, gets the home's snapshot in its
|
|
925
|
+
// another machine, gets the home's snapshot in its run's brief. A shared profile's memory is never used.
|
|
926
926
|
const agentHome=materializeAgentHome(board.root,team.org,agent.identity.id,lane);
|
|
927
927
|
assertRunCurrent(board,id,runId);
|
|
928
928
|
if(surface==='headless')meta.agent_env.HERMES_HOME=agentHome;
|
|
929
929
|
else{const memory=await memorySnapshot(agentHome).catch(()=>'');assertRunCurrent(board,id,runId);if(memory)prompt=`${prompt}\n\n${memory}`;}
|
|
930
930
|
const result = surface === 'pane'
|
|
931
|
-
? await launchPane(board, task, runId, lane, fleet, { input: prompt, slot, meta })
|
|
931
|
+
? await launchPane(board, task, runId, lane, fleet, { input: briefByReference(board, task, runId, spec.role ?? slot, where, prompt), slot, meta })
|
|
932
932
|
: await launchHeadless(board, task, runId, lane, settings, { prompt, skills: spec.skills ?? [], meta });
|
|
933
933
|
tx(board,db=>{
|
|
934
934
|
if(!runCurrent(db,id,runId))return; // replaced once launched: its session is the ended run's, closed as one
|
|
@@ -960,6 +960,24 @@ async function launchAttempt(board, entry, id, lane, fleet, settings, runId) {
|
|
|
960
960
|
}
|
|
961
961
|
}
|
|
962
962
|
|
|
963
|
+
/**
|
|
964
|
+
* What the board types into a pane session to start a run: one short line in the board's own words naming the role,
|
|
965
|
+
* the card and where the run's brief is, with the brief itself kept in a file. A terminal harness takes its input as a
|
|
966
|
+
* paste, and Claude Code records a paste of more than two lines or about 800 characters as a `<pasted_content>`
|
|
967
|
+
* attachment with no typed words beside it, which a session rightly reads as material, not as its instruction. The
|
|
968
|
+
* line stays one line and far under that size whatever the card holds; the session on the board's machine reads the
|
|
969
|
+
* file, one elsewhere prints it through the board's door.
|
|
970
|
+
*/
|
|
971
|
+
export function briefByReference(board, task, runId, role, where, prompt) {
|
|
972
|
+
const file = briefPath(board.root, board.slug, task.id, runId);
|
|
973
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
974
|
+
writeFileSync(file, `${prompt}\n`, { mode: 0o600 });
|
|
975
|
+
const local = !task.machine || normalMachine(task.machine) === localMachine();
|
|
976
|
+
const from = local ? `in the file ${file}: read the whole file now`
|
|
977
|
+
: `kept by the board: print it with \`supercode workflow brief ${task.id} ${where}\` (into a file outside your repository when it is long) and read all of it now`;
|
|
978
|
+
return `The ${board.label} board started run ${runId} of card ${task.id} and you are its ${role}. Your instructions from the board are the brief ${from}, then carry it out as your own task without waiting for another message.`;
|
|
979
|
+
}
|
|
980
|
+
|
|
963
981
|
/** Start one card now by a person's word (a triage card's session, a manager's start): the workflow's start event. */
|
|
964
982
|
export async function startCard(board, id, { roles = ['manager'], lanes, settings } = {}) {
|
|
965
983
|
// the board's own published fleet projection, as a tick reads it: a manager's or creator's start that continues the
|
|
@@ -1898,7 +1916,7 @@ async function launchPane(board, task, runId, lane, fleet, { input = null, slot
|
|
|
1898
1916
|
if (monitorsRuns(workflowFor(board.root)) && prev.monitor_held && !authorization && !released) throw new Error(`session ${prev.session_id} is stopped by incident ${prev.incident ?? 'unknown'}; only its manager or creator may restart it with workflow start`);
|
|
1899
1917
|
// a resumed session is told what this run is for, as a kept one is: the run's own prompt (a reviewer resumed for
|
|
1900
1918
|
// its next round gets that round's prompt, its arc's context with it), not only that it was resumed
|
|
1901
|
-
const told = input ? `The board resumed this session for this run of card ${task.id}
|
|
1919
|
+
const told = input ? `The board resumed this session for this run of card ${task.id}. ${input}` : `The board resumed this session after it was lost; you are still on card ${task.id}: ${task.title}. Carry on.`;
|
|
1902
1920
|
// a session is resumed in its own harness, whatever the lane's is now
|
|
1903
1921
|
const its = HARNESSES[prev.harness ?? 'claude-code'] ?? HARNESSES['claude-code'];
|
|
1904
1922
|
const launchKey = `board-${task.id}-r${runId}-resume`;
|
package/board/store.mjs
CHANGED
|
@@ -124,6 +124,10 @@ export function boardPath(root, slug = DEFAULT_BOARD) {
|
|
|
124
124
|
/** The directory of the board's worker logs, as Hermes lays them out. */
|
|
125
125
|
export const logsDir = (root, slug = DEFAULT_BOARD) => join(boardDirOf(root, slug), 'logs');
|
|
126
126
|
|
|
127
|
+
/** The file holding the brief of run `run` of card `id`: what the board hands a pane session by reference, kept with
|
|
128
|
+
* the board's logs and removed with them. */
|
|
129
|
+
export const briefPath = (root, slug, id, run) => join(logsDir(root, slug), `${id}-r${run}.brief.md`);
|
|
130
|
+
|
|
127
131
|
/** The home's boards that exist: `default` when it does, and every named one. */
|
|
128
132
|
export function listBoards(root) {
|
|
129
133
|
const out = boardExists(root) ? [DEFAULT_BOARD] : [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-orchestrator",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.125",
|
|
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": {
|