svamp-cli 0.2.128 → 0.2.129

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.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: crew
3
3
  version: 0.1.0
4
- description: Coordinate work as a lead delegating features to managed worktree children — spawn a child per feature on its own branch, supervise it, and pull finished work back to the base branch with merge-and-close. Use when one session should run a project and farm out features instead of piling many sessions on one working tree.
4
+ description: Coordinate work as a lead delegating features to managed worktree children — spawn a child per feature on its own branch, run it as a loop until done, and pull finished work back to the base branch with merge-and-close. Use when one session should run a project and farm out features instead of piling many sessions on one working tree.
5
5
  ---
6
6
 
7
7
  # Crew — a lead session that delegates features to managed worktree children
@@ -13,16 +13,16 @@ the same working tree.
13
13
 
14
14
  A **crew** is emergent, not a heavy object: it is just plain sessions linked by
15
15
  `parentSessionId` + a `crew.role`. A **feature child** always (a) has the lead as its
16
- parent, (b) lives in its own `.dev/worktree/<n>` on its own branch, and (c) is supervised
17
- with `judge: parent` — i.e. **the lead is the judge** that decides when the child is done
18
- (this is the `judge:parent` case of the Supervisor Gate; see the loop/supervisor skill).
16
+ parent, (b) lives in its own `.dev/worktree/<n>` on its own branch, and (c) runs as a loop
17
+ with `parent: <lead>` — i.e. **the lead is the judge** that decides when the child is done
18
+ (this is the `parent`-routed case of the loop … until gate; see the `loop` skill).
19
19
 
20
20
  ## The verbs (these are your tools)
21
21
 
22
22
  ```
23
23
  svamp feature start "<brief>" [--oracle "<test cmd>"] [--base <branch>] [--action nudge|block]
24
- # (lead) create a worktree child on a new branch, attach a supervisor
25
- # (oracle → parent), and brief it. Prints the child id.
24
+ # (lead) create a worktree child on a new branch, run it as a loop until done
25
+ # (oracle → parent verdict), and brief it. Prints the child id.
26
26
  svamp feature list [--json]
27
27
  # (lead) your children: branch, ahead/behind base, dirty, idle/active.
28
28
  svamp feature report "<text>" [--blocker]
@@ -43,8 +43,9 @@ You coordinate the project. Keep your own working tree (the base branch, e.g. `m
43
43
  `--oracle "<cmd>"` so it's auto-checked.
44
44
  - **Stay aware:** run `svamp feature list` when you start working and whenever you manage the
45
45
  crew. Your children also **push** to you: progress notes, blockers, merge-requests, and
46
- supervision verdicts all arrive in your inbox as `<feature-progress>`, `<feature-blocker>`,
47
- `<merge-request>`, and `<supervision-verdict>` messages.
46
+ loop verdicts all arrive in your inbox as `<feature-progress>`, `<feature-blocker>`,
47
+ `<merge-request>`, and `<supervision-verdict>` messages (the verdict's wire tag name is
48
+ unchanged for back-compat).
48
49
  - **Review & merge — this is the gradient that closes the loop.** When a child sends a
49
50
  `<merge-request>` or you receive a `<supervision-verdict … verdict="approved">` from a
50
51
  child, **run `svamp feature merge <child-id>`**. With an oracle that passed, this is the
@@ -59,7 +60,7 @@ You coordinate the project. Keep your own working tree (the base branch, e.g. `m
59
60
  ## If you are a FEATURE CHILD
60
61
 
61
62
  You own one feature in an isolated worktree on your own branch, reporting to your lead. Your
62
- brief (and your supervisor's criteria) is injected each turn.
63
+ brief (and your loop's "until" criteria) is injected each turn.
63
64
 
64
65
  - **Work in your worktree.** Implement the feature. Commit as you go. Keep the oracle/tests green.
65
66
  - **Report.** Use `svamp feature report "<note>"` for milestones and `--blocker` when stuck —
@@ -75,7 +76,7 @@ brief (and your supervisor's criteria) is injected each turn.
75
76
 
76
77
  - **One conversation, many features.** The lead is your single point of control; children run in
77
78
  parallel isolation and report up.
78
- - **Merge-and-close is the default, not a chore.** The supervisor routes a verdict to the lead,
79
+ - **Merge-and-close is the default, not a chore.** The loop gate routes a verdict to the lead,
79
80
  the lead merges, the child closes — the "gradient" that keeps finished work from rotting on a
80
81
  stale branch.
81
82
  - **Isolation by worktree.** Each feature has its own branch + tree, so children never collide on
@@ -16,8 +16,9 @@ import { join, dirname } from 'node:path';
16
16
  import { execSync } from 'node:child_process';
17
17
 
18
18
  // CANONICAL: the session checklist lives INSIDE the loop dir at
19
- // <project>/.svamp/<sid>/loop/checklist.json — beside the other supervisor state
20
- // (loop-state.json, supervisor-verdict.json). Matches the daemon writer
19
+ // <project>/.svamp/<sid>/loop/checklist.json — beside the other loop-gate state
20
+ // (loop-state.json, supervisor-verdict.json the latter is the daemon's legacy
21
+ // verdict file name). Matches the daemon writer
21
22
  // (checklist/core.ts checklistPath) + the frontend (sync/ops.ts sessionChecklistRel).
22
23
  export function sessionChecklistPath(loopDir) { return join(loopDir, 'checklist.json'); }
23
24
  export function projectChecklistPath(projectDir) { return join(projectDir, '.svamp', 'checklist.json'); }
@@ -71,8 +71,8 @@ const config = {
71
71
  // and resolve their own dir relatively) read this to run the oracle + fingerprint the
72
72
  // work product, since their depth no longer encodes the project root.
73
73
  project_dir: dir,
74
- // The success contract — the durable thing the gate judges against. Read by the daemon
75
- // to populate the supervision:verdict event (docs/supervisor-gate-design.md).
74
+ // The success contract — the "until" the loop gate runs against. Read by the daemon
75
+ // to populate the loop verdict event (legacy wire type: supervision:verdict).
76
76
  ...(criteria ? { criteria: criteria.trim() } : {}),
77
77
  oracle: oracle ? { command: oracle, timeout_sec: 600 } : null,
78
78
  evaluator: { enabled: evaluatorOn, model },
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync } from '
2
2
  import { join, dirname } from 'node:path';
3
3
  import os from 'node:os';
4
4
  import { requireNotSandboxed } from './sandboxDetect-DNTcbgWD.mjs';
5
- import { m as shortId } from './run-C23-A9KM.mjs';
5
+ import { m as shortId } from './run-BaTwfE1Q.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -96,7 +96,7 @@ async function sessionSetTitle(title) {
96
96
  }
97
97
  async function sessionSetProjectDescription(description) {
98
98
  const dir = process.cwd();
99
- const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.Z; });
99
+ const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.Z; });
100
100
  const desc = sanitizeDescription(description, 240);
101
101
  if (!desc) {
102
102
  console.error("Project description is empty.");
@@ -180,7 +180,7 @@ async function sessionBroadcast(action, args) {
180
180
  console.log(`Broadcast sent: ${action}`);
181
181
  }
182
182
  async function connectToMachineService() {
183
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
183
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
184
184
  return connectAndGetMachine();
185
185
  }
186
186
  async function inboxSend(targetSessionId, opts) {
@@ -197,7 +197,7 @@ async function inboxSend(targetSessionId, opts) {
197
197
  }
198
198
  const { server, machine } = await connectToMachineService();
199
199
  try {
200
- const { resolveSessionId } = await import('./commands-BVx72l2K.mjs');
200
+ const { resolveSessionId } = await import('./commands-BV30A1zt.mjs');
201
201
  const sessions = await machine.listSessions();
202
202
  const match = resolveSessionId(sessions, targetSessionId);
203
203
  const fullTargetId = match.sessionId;
@@ -1,4 +1,4 @@
1
- import { D as resolveModel } from './run-C23-A9KM.mjs';
1
+ import { D as resolveModel } from './run-BaTwfE1Q.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { e as clearStopMarker, f as stopMarkerExists, s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-C23-A9KM.mjs';
1
+ import { e as clearStopMarker, f as stopMarkerExists, s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-BaTwfE1Q.mjs';
2
2
  import { ensureSupervisorViaServiceManager, LAUNCHD_LABEL } from './serviceManager-hlOVxkhW.mjs';
3
3
  import 'os';
4
4
  import 'fs/promises';
@@ -34,7 +34,7 @@ const subcommand = args[0];
34
34
  let daemonSubcommand = args[1];
35
35
  async function main() {
36
36
  try {
37
- const { getLoadedConfig } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a4; });
37
+ const { getLoadedConfig } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a4; });
38
38
  getLoadedConfig();
39
39
  } catch {
40
40
  }
@@ -51,7 +51,7 @@ async function main() {
51
51
  console.error(`svamp daemon restart: ${err.message || err}`);
52
52
  process.exit(1);
53
53
  }
54
- const { restartDaemon } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a6; });
54
+ const { restartDaemon } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a6; });
55
55
  await restartDaemon();
56
56
  process.exit(0);
57
57
  }
@@ -344,7 +344,7 @@ async function main() {
344
344
  console.error("svamp service: Service commands are not available in sandboxed sessions.");
345
345
  process.exit(1);
346
346
  }
347
- const { handleServiceCommand } = await import('./commands-BLYvHcrD.mjs');
347
+ const { handleServiceCommand } = await import('./commands-CK1ZOskY.mjs');
348
348
  await handleServiceCommand();
349
349
  } else if (subcommand === "serve") {
350
350
  const { isSandboxed: isSandboxedServe } = await import('./sandboxDetect-DNTcbgWD.mjs');
@@ -352,7 +352,7 @@ async function main() {
352
352
  console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
353
353
  process.exit(1);
354
354
  }
355
- const { handleServeCommand } = await import('./serveCommands-BBIKhjxn.mjs');
355
+ const { handleServeCommand } = await import('./serveCommands-GzGpHWlP.mjs');
356
356
  await handleServeCommand();
357
357
  process.exit(0);
358
358
  } else if (subcommand === "process" || subcommand === "proc") {
@@ -361,7 +361,7 @@ async function main() {
361
361
  console.error("svamp process: Process commands are not available in sandboxed sessions.");
362
362
  process.exit(1);
363
363
  }
364
- const { processCommand } = await import('./commands-Dif088xw.mjs');
364
+ const { processCommand } = await import('./commands-oF0MQ_jX.mjs');
365
365
  let machineId;
366
366
  const processArgs = args.slice(1);
367
367
  const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
@@ -375,14 +375,14 @@ async function main() {
375
375
  }), machineId);
376
376
  process.exit(0);
377
377
  } else if (subcommand === "trigger" || subcommand === "triggers" || subcommand === "routine" || subcommand === "routines") {
378
- const { routineCommand } = await import('./commands-CO-lf8m_.mjs');
378
+ const { routineCommand } = await import('./commands-DEZSgxop.mjs');
379
379
  await routineCommand(args.slice(1));
380
380
  process.exit(0);
381
381
  } else if (subcommand === "wise-agent" || subcommand === "wise") {
382
382
  await handleWiseAgentCommand(args.slice(1));
383
383
  process.exit(0);
384
384
  } else if (subcommand === "feature" || subcommand === "crew") {
385
- const { crewCommand } = await import('./commands-deNTJ9jb.mjs');
385
+ const { crewCommand } = await import('./commands-CWIKYhzM.mjs');
386
386
  await crewCommand(args.slice(1));
387
387
  process.exit(0);
388
388
  } else if (subcommand === "--help" || subcommand === "-h") {
@@ -390,7 +390,7 @@ async function main() {
390
390
  } else if (!subcommand || subcommand === "start") {
391
391
  await handleInteractiveCommand();
392
392
  } else if (subcommand === "--version" || subcommand === "-v") {
393
- const pkg = await import('./package-C5owhm4c.mjs').catch(() => ({ default: { version: "unknown" } }));
393
+ const pkg = await import('./package-DzPfT1Xs.mjs').catch(() => ({ default: { version: "unknown" } }));
394
394
  console.log(`svamp version: ${pkg.default.version}`);
395
395
  } else {
396
396
  console.error(`Unknown command: ${subcommand}`);
@@ -399,7 +399,7 @@ async function main() {
399
399
  }
400
400
  }
401
401
  async function handleInteractiveCommand() {
402
- const { runInteractive } = await import('./run-CkPzZuKK.mjs');
402
+ const { runInteractive } = await import('./run-C6Q6ZlNu.mjs');
403
403
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
404
404
  let directory = process.cwd();
405
405
  let resumeSessionId;
@@ -444,7 +444,7 @@ async function handleAgentCommand() {
444
444
  return;
445
445
  }
446
446
  if (agentArgs[0] === "list") {
447
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a0; });
447
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a0; });
448
448
  console.log("Known agents:");
449
449
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
450
450
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -456,7 +456,7 @@ async function handleAgentCommand() {
456
456
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
457
457
  return;
458
458
  }
459
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a0; });
459
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a0; });
460
460
  let cwd = process.cwd();
461
461
  const filteredArgs = [];
462
462
  for (let i = 0; i < agentArgs.length; i++) {
@@ -480,12 +480,12 @@ async function handleAgentCommand() {
480
480
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
481
481
  let backend;
482
482
  if (KNOWN_MCP_AGENTS[config.agentName]) {
483
- const { CodexMcpBackend } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a1; });
483
+ const { CodexMcpBackend } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a1; });
484
484
  backend = new CodexMcpBackend({ cwd, log: logFn });
485
485
  } else {
486
- const { AcpBackend } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.$; });
487
- const { GeminiTransport } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a2; });
488
- const { DefaultTransport } = await import('./run-C23-A9KM.mjs').then(function (n) { return n._; });
486
+ const { AcpBackend } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.$; });
487
+ const { GeminiTransport } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a2; });
488
+ const { DefaultTransport } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n._; });
489
489
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
490
490
  backend = new AcpBackend({
491
491
  agentName: config.agentName,
@@ -612,7 +612,7 @@ async function handleSessionCommand() {
612
612
  process.exit(1);
613
613
  }
614
614
  }
615
- const { sessionList, sessionWhoami, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionLoopStart, sessionLoopCancel, sessionLoopStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-BVx72l2K.mjs');
615
+ const { sessionList, sessionWhoami, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionLoopStart, sessionLoopCancel, sessionLoopStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-BV30A1zt.mjs');
616
616
  const parseFlagStr = (flag, shortFlag) => {
617
617
  for (let i = 1; i < sessionArgs.length; i++) {
618
618
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -680,7 +680,7 @@ async function handleSessionCommand() {
680
680
  allowDomain.push(sessionArgs[++i]);
681
681
  }
682
682
  }
683
- const { parseShareArg } = await import('./commands-BVx72l2K.mjs');
683
+ const { parseShareArg } = await import('./commands-BV30A1zt.mjs');
684
684
  const shareEntries = share.map((s) => parseShareArg(s));
685
685
  await sessionSpawn(agent, dir, targetMachineId, {
686
686
  message,
@@ -765,7 +765,7 @@ async function handleSessionCommand() {
765
765
  console.error(" Rewinds history: rewrites the message + drops everything after it, then restarts Claude.");
766
766
  process.exit(1);
767
767
  }
768
- const { sessionEditMessage } = await import('./commands-BVx72l2K.mjs');
768
+ const { sessionEditMessage } = await import('./commands-BV30A1zt.mjs');
769
769
  await sessionEditMessage(sessionArgs[1], sessionArgs[2], sessionArgs[3], targetMachineId);
770
770
  } else if (sessionSubcommand === "refine") {
771
771
  if (!sessionArgs[1] || !sessionArgs[2]) {
@@ -773,7 +773,7 @@ async function handleSessionCommand() {
773
773
  console.error(" Asks the agent to revise its latest reply in place (no extra round).");
774
774
  process.exit(1);
775
775
  }
776
- const { sessionRefineLastReply } = await import('./commands-BVx72l2K.mjs');
776
+ const { sessionRefineLastReply } = await import('./commands-BV30A1zt.mjs');
777
777
  await sessionRefineLastReply(sessionArgs[1], sessionArgs[2], targetMachineId);
778
778
  } else if (sessionSubcommand === "undo-edit" || sessionSubcommand === "undo") {
779
779
  if (!sessionArgs[1]) {
@@ -781,7 +781,7 @@ async function handleSessionCommand() {
781
781
  console.error(" Reverts the most recent edit/refine, restoring the pre-edit history.");
782
782
  process.exit(1);
783
783
  }
784
- const { sessionUndoEdit } = await import('./commands-BVx72l2K.mjs');
784
+ const { sessionUndoEdit } = await import('./commands-BV30A1zt.mjs');
785
785
  await sessionUndoEdit(sessionArgs[1], targetMachineId);
786
786
  } else if (sessionSubcommand === "query") {
787
787
  const dir = sessionArgs[1];
@@ -791,7 +791,7 @@ async function handleSessionCommand() {
791
791
  console.error(" Spawns a stateless Claude session in <directory>, sends <prompt>, prints the answer, then deletes the session.");
792
792
  process.exit(1);
793
793
  }
794
- const { sessionQuery } = await import('./commands-BVx72l2K.mjs');
794
+ const { sessionQuery } = await import('./commands-BV30A1zt.mjs');
795
795
  await sessionQuery(dir, prompt, targetMachineId, {
796
796
  timeout: parseFlagInt("--timeout"),
797
797
  json: hasFlag("--json"),
@@ -824,7 +824,7 @@ async function handleSessionCommand() {
824
824
  console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
825
825
  process.exit(1);
826
826
  }
827
- const { sessionApprove } = await import('./commands-BVx72l2K.mjs');
827
+ const { sessionApprove } = await import('./commands-BV30A1zt.mjs');
828
828
  const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
829
829
  await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
830
830
  json: hasFlag("--json")
@@ -834,21 +834,28 @@ async function handleSessionCommand() {
834
834
  console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
835
835
  process.exit(1);
836
836
  }
837
- const { sessionDeny } = await import('./commands-BVx72l2K.mjs');
837
+ const { sessionDeny } = await import('./commands-BV30A1zt.mjs');
838
838
  const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
839
839
  await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
840
840
  json: hasFlag("--json")
841
841
  });
842
- } else if (sessionSubcommand === "loop-start" || sessionSubcommand === "loop") {
843
- if (!sessionArgs[1] || !sessionArgs[2]) {
844
- console.error('Usage: svamp session loop-start <session-id> "<task>" [--criteria TEXT] [--oracle "cmd"] [--max N] [--evaluator on|off]');
842
+ } else if (sessionSubcommand === "loop" || sessionSubcommand === "loop-start") {
843
+ const id = sessionArgs[1];
844
+ const maybeTask = sessionArgs[2] && !sessionArgs[2].startsWith("-") ? sessionArgs[2] : void 0;
845
+ const until = parseFlagStr("--until") ?? parseFlagStr("--criteria");
846
+ if (!id || !maybeTask && !until) {
847
+ console.error('Usage: svamp session loop <session-id> ["<task>"] --until "<criteria>" [--oracle "cmd"] [--agent] [--parent <id>] [--max N] [--evaluator on|off]');
848
+ console.error(" With a task: kicks the agent off and gates it until done.");
849
+ console.error(" With only --until: hot-plugs the gate onto the running session (no kickoff).");
845
850
  process.exit(1);
846
851
  }
847
852
  const evalStr = parseFlagStr("--evaluator");
848
- await sessionLoopStart(sessionArgs[1], sessionArgs[2], targetMachineId, {
849
- criteria: parseFlagStr("--criteria"),
853
+ await sessionLoopStart(id, maybeTask, targetMachineId, {
854
+ until,
850
855
  oracle: parseFlagStr("--oracle"),
851
- maxIterations: parseFlagInt("--max") ?? parseFlagInt("--max-iterations"),
856
+ agent: hasFlag("--agent"),
857
+ parent: parseFlagStr("--parent"),
858
+ maxIterations: parseFlagInt("--max") ?? parseFlagInt("--max-iterations") ?? parseFlagInt("--max-rounds"),
852
859
  evaluator: evalStr ? evalStr !== "off" : void 0
853
860
  });
854
861
  } else if (sessionSubcommand === "loop-cancel") {
@@ -863,34 +870,13 @@ async function handleSessionCommand() {
863
870
  process.exit(1);
864
871
  }
865
872
  await sessionLoopStatus(sessionArgs[1], targetMachineId);
866
- } else if (sessionSubcommand === "supervise") {
867
- if (!sessionArgs[1] || !sessionArgs[2]) {
868
- console.error('Usage: svamp session supervise <session-id> "<criteria>" [--oracle "cmd"] [--agent] [--parent <id>] [--action nudge|block] [--max N]');
869
- process.exit(1);
870
- }
871
- const { sessionSupervise } = await import('./commands-BVx72l2K.mjs');
872
- const actionStr = parseFlagStr("--action");
873
- await sessionSupervise(sessionArgs[1], sessionArgs[2], targetMachineId, {
874
- oracle: parseFlagStr("--oracle"),
875
- agent: hasFlag("--agent"),
876
- parent: parseFlagStr("--parent"),
877
- action: actionStr === "nudge" || actionStr === "block" ? actionStr : void 0,
878
- maxRounds: parseFlagInt("--max") ?? parseFlagInt("--max-rounds")
879
- });
880
- } else if (sessionSubcommand === "unsupervise") {
881
- if (!sessionArgs[1]) {
882
- console.error("Usage: svamp session unsupervise <session-id>");
883
- process.exit(1);
884
- }
885
- const { sessionUnsupervise } = await import('./commands-BVx72l2K.mjs');
886
- await sessionUnsupervise(sessionArgs[1], targetMachineId);
887
873
  } else if (sessionSubcommand === "set-title") {
888
874
  const title = sessionArgs[1];
889
875
  if (!title) {
890
876
  console.error("Usage: svamp session set-title <title>");
891
877
  process.exit(1);
892
878
  }
893
- const { sessionSetTitle } = await import('./agentCommands-jGCEdEYn.mjs');
879
+ const { sessionSetTitle } = await import('./agentCommands-CZk6NL7b.mjs');
894
880
  await sessionSetTitle(title);
895
881
  } else if (sessionSubcommand === "set-project-description" || sessionSubcommand === "set-project") {
896
882
  const desc = sessionArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
@@ -898,7 +884,7 @@ async function handleSessionCommand() {
898
884
  console.error("Usage: svamp session set-project-description <text>");
899
885
  process.exit(1);
900
886
  }
901
- const { sessionSetProjectDescription } = await import('./agentCommands-jGCEdEYn.mjs');
887
+ const { sessionSetProjectDescription } = await import('./agentCommands-CZk6NL7b.mjs');
902
888
  await sessionSetProjectDescription(desc);
903
889
  } else if (sessionSubcommand === "set-link") {
904
890
  const url = sessionArgs[1];
@@ -907,7 +893,7 @@ async function handleSessionCommand() {
907
893
  process.exit(1);
908
894
  }
909
895
  const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
910
- const { sessionSetLink } = await import('./agentCommands-jGCEdEYn.mjs');
896
+ const { sessionSetLink } = await import('./agentCommands-CZk6NL7b.mjs');
911
897
  await sessionSetLink(url, label);
912
898
  } else if (sessionSubcommand === "notify") {
913
899
  const message = sessionArgs[1];
@@ -916,7 +902,7 @@ async function handleSessionCommand() {
916
902
  process.exit(1);
917
903
  }
918
904
  const level = parseFlagStr("--level") || "info";
919
- const { sessionNotify } = await import('./agentCommands-jGCEdEYn.mjs');
905
+ const { sessionNotify } = await import('./agentCommands-CZk6NL7b.mjs');
920
906
  await sessionNotify(message, level);
921
907
  } else if (sessionSubcommand === "broadcast") {
922
908
  const action = sessionArgs[1];
@@ -924,7 +910,7 @@ async function handleSessionCommand() {
924
910
  console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
925
911
  process.exit(1);
926
912
  }
927
- const { sessionBroadcast } = await import('./agentCommands-jGCEdEYn.mjs');
913
+ const { sessionBroadcast } = await import('./agentCommands-CZk6NL7b.mjs');
928
914
  await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
929
915
  } else if (sessionSubcommand === "inbox") {
930
916
  const inboxSubcmd = sessionArgs[1];
@@ -935,7 +921,7 @@ async function handleSessionCommand() {
935
921
  process.exit(1);
936
922
  }
937
923
  if (agentSessionId) {
938
- const { inboxSend } = await import('./agentCommands-jGCEdEYn.mjs');
924
+ const { inboxSend } = await import('./agentCommands-CZk6NL7b.mjs');
939
925
  await inboxSend(sessionArgs[2], {
940
926
  body: sessionArgs[3],
941
927
  subject: parseFlagStr("--subject"),
@@ -950,7 +936,7 @@ async function handleSessionCommand() {
950
936
  }
951
937
  } else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
952
938
  if (agentSessionId && !sessionArgs[2]) {
953
- const { inboxList } = await import('./agentCommands-jGCEdEYn.mjs');
939
+ const { inboxList } = await import('./agentCommands-CZk6NL7b.mjs');
954
940
  await inboxList({
955
941
  unread: hasFlag("--unread"),
956
942
  limit: parseFlagInt("--limit"),
@@ -972,7 +958,7 @@ async function handleSessionCommand() {
972
958
  process.exit(1);
973
959
  }
974
960
  if (agentSessionId && !sessionArgs[3]) {
975
- const { inboxList } = await import('./agentCommands-jGCEdEYn.mjs');
961
+ const { inboxList } = await import('./agentCommands-CZk6NL7b.mjs');
976
962
  await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
977
963
  } else if (sessionArgs[3]) {
978
964
  await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
@@ -982,7 +968,7 @@ async function handleSessionCommand() {
982
968
  }
983
969
  } else if (inboxSubcmd === "reply") {
984
970
  if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
985
- const { inboxReply } = await import('./agentCommands-jGCEdEYn.mjs');
971
+ const { inboxReply } = await import('./agentCommands-CZk6NL7b.mjs');
986
972
  await inboxReply(sessionArgs[2], sessionArgs[3]);
987
973
  } else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
988
974
  await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
@@ -1018,7 +1004,7 @@ async function handleMachineCommand() {
1018
1004
  return;
1019
1005
  }
1020
1006
  if (machineSubcommand === "share") {
1021
- const { machineShare } = await import('./commands-BVx72l2K.mjs');
1007
+ const { machineShare } = await import('./commands-BV30A1zt.mjs');
1022
1008
  let machineId;
1023
1009
  const shareArgs = [];
1024
1010
  for (let i = 1; i < machineArgs.length; i++) {
@@ -1069,14 +1055,14 @@ async function handleMachineCommand() {
1069
1055
  process.exit(1);
1070
1056
  }
1071
1057
  if (all) {
1072
- const { fleetExec } = await import('./fleet-D3L05h5k.mjs');
1058
+ const { fleetExec } = await import('./fleet-BwmE0enl.mjs');
1073
1059
  await fleetExec(command, { cwd });
1074
1060
  } else {
1075
- const { machineExec } = await import('./commands-BVx72l2K.mjs');
1061
+ const { machineExec } = await import('./commands-BV30A1zt.mjs');
1076
1062
  await machineExec(machineId, command, cwd);
1077
1063
  }
1078
1064
  } else if (machineSubcommand === "info") {
1079
- const { machineInfo } = await import('./commands-BVx72l2K.mjs');
1065
+ const { machineInfo } = await import('./commands-BV30A1zt.mjs');
1080
1066
  let machineId;
1081
1067
  for (let i = 1; i < machineArgs.length; i++) {
1082
1068
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -1096,10 +1082,10 @@ async function handleMachineCommand() {
1096
1082
  level = machineArgs[++i];
1097
1083
  }
1098
1084
  }
1099
- const { machineNotify } = await import('./agentCommands-jGCEdEYn.mjs');
1085
+ const { machineNotify } = await import('./agentCommands-CZk6NL7b.mjs');
1100
1086
  await machineNotify(message, level);
1101
1087
  } else if (machineSubcommand === "ls") {
1102
- const { machineLs } = await import('./commands-BVx72l2K.mjs');
1088
+ const { machineLs } = await import('./commands-BV30A1zt.mjs');
1103
1089
  let machineId;
1104
1090
  let showHidden = false;
1105
1091
  let path;
@@ -1155,20 +1141,20 @@ Examples:
1155
1141
  };
1156
1142
  const hasFlag = (name) => fleetArgs.includes(`--${name}`);
1157
1143
  if (sub === "status") {
1158
- const { fleetStatus } = await import('./fleet-D3L05h5k.mjs');
1144
+ const { fleetStatus } = await import('./fleet-BwmE0enl.mjs');
1159
1145
  await fleetStatus();
1160
1146
  } else if (sub === "upgrade-claude") {
1161
- const { fleetUpgradeClaude } = await import('./fleet-D3L05h5k.mjs');
1147
+ const { fleetUpgradeClaude } = await import('./fleet-BwmE0enl.mjs');
1162
1148
  await fleetUpgradeClaude({ version: flag("version", "-v") });
1163
1149
  } else if (sub === "upgrade-svamp") {
1164
- const { fleetUpgradeSvamp } = await import('./fleet-D3L05h5k.mjs');
1150
+ const { fleetUpgradeSvamp } = await import('./fleet-BwmE0enl.mjs');
1165
1151
  await fleetUpgradeSvamp({ version: flag("version", "-v"), excludeSelf: hasFlag("exclude-self") });
1166
1152
  } else if (sub === "daemon-restart") {
1167
- const { fleetDaemonRestart } = await import('./fleet-D3L05h5k.mjs');
1153
+ const { fleetDaemonRestart } = await import('./fleet-BwmE0enl.mjs');
1168
1154
  await fleetDaemonRestart({ graceful: !hasFlag("cleanup") });
1169
1155
  } else if (sub === "push-skill") {
1170
1156
  const name = fleetArgs[1];
1171
- const { fleetPushSkill } = await import('./fleet-D3L05h5k.mjs');
1157
+ const { fleetPushSkill } = await import('./fleet-BwmE0enl.mjs');
1172
1158
  await fleetPushSkill(name);
1173
1159
  } else {
1174
1160
  console.error(`Unknown fleet subcommand: ${sub}`);
@@ -1184,7 +1170,7 @@ async function handleSkillsCommand() {
1184
1170
  await printSkillsHelp();
1185
1171
  return;
1186
1172
  }
1187
- const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-CHUE-0Mz.mjs');
1173
+ const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-CCqAWMnX.mjs');
1188
1174
  if (skillsSubcommand === "find" || skillsSubcommand === "search") {
1189
1175
  const query = skillsArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
1190
1176
  if (!query) {
@@ -1231,7 +1217,7 @@ async function loginToHypha() {
1231
1217
  process.exit(1);
1232
1218
  }
1233
1219
  const anchor = anchorArg.replace(/\/+$/, "");
1234
- const { loadInstanceConfig } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a4; });
1220
+ const { loadInstanceConfig } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a4; });
1235
1221
  let cfg = null;
1236
1222
  try {
1237
1223
  cfg = await loadInstanceConfig({ anchor, force: true });
@@ -1342,7 +1328,7 @@ async function logoutFromHypha() {
1342
1328
  } catch {
1343
1329
  }
1344
1330
  try {
1345
- const { clearInstanceConfigCache } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a4; });
1331
+ const { clearInstanceConfigCache } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a4; });
1346
1332
  clearInstanceConfigCache();
1347
1333
  } catch {
1348
1334
  }
@@ -1603,7 +1589,7 @@ Commands:
1603
1589
  svamp session --help Show ALL session commands and detailed options
1604
1590
 
1605
1591
  Crew (lead delegates features to managed worktree children):
1606
- svamp feature start "<brief>" Spawn a worktree child of this lead + supervisor (oracle\u2192parent)
1592
+ svamp feature start "<brief>" Spawn a worktree child of this lead + loop gate (oracle\u2192parent)
1607
1593
  svamp feature list This lead's feature children (branch, ahead/behind, status)
1608
1594
  svamp feature done|report (run by a child) signal completion / report progress to the lead
1609
1595
  svamp feature merge <child> (run by the lead) verify \u2192 merge \u2192 remove worktree \u2192 archive child
@@ -1680,7 +1666,7 @@ async function applyClaudeAuthFlags(argv) {
1680
1666
  "--use-hypha-proxy, --use-claude-login, and --anthropic-base-url/--anthropic-api-key are mutually exclusive"
1681
1667
  );
1682
1668
  }
1683
- const mod = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a3; });
1669
+ const mod = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a3; });
1684
1670
  if (hasHypha) {
1685
1671
  let url;
1686
1672
  const hyphaIdx = argv.indexOf("--use-hypha-proxy");
@@ -1734,7 +1720,7 @@ async function applyDaemonShareFlag(argv) {
1734
1720
  }
1735
1721
  }
1736
1722
  if (collected.length === 0) return;
1737
- const { updateEnvFile } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a3; });
1723
+ const { updateEnvFile } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a3; });
1738
1724
  const seen = /* @__PURE__ */ new Set();
1739
1725
  const deduped = collected.filter((e) => {
1740
1726
  const k = e.toLowerCase();
@@ -1767,7 +1753,7 @@ async function handleWiseAgentCommand(rest) {
1767
1753
  }
1768
1754
  });
1769
1755
  const message = rest.slice(1).map((a, idx) => ({ a, idx: idx + 1 })).filter(({ a, idx }) => !a.startsWith("-") && !consumed.has(String(idx))).map(({ a }) => a).join(" ");
1770
- const { wiseAskCli } = await import('./commands-BVx72l2K.mjs');
1756
+ const { wiseAskCli } = await import('./commands-BV30A1zt.mjs');
1771
1757
  await wiseAskCli(machineId, message, sessionId, { json });
1772
1758
  return;
1773
1759
  }
@@ -1779,7 +1765,7 @@ async function handleWiseAgentCommand(rest) {
1779
1765
  }
1780
1766
  return void 0;
1781
1767
  };
1782
- const { runWiseVoiceCli } = await import('./headlessCli-CB9HN7zY.mjs');
1768
+ const { runWiseVoiceCli } = await import('./headlessCli-Cj4WQsCx.mjs');
1783
1769
  await runWiseVoiceCli({ voice: valueOf(["--voice"]), wakeKeywordPath: valueOf(["--wake"]), model: valueOf(["--model"]) });
1784
1770
  return;
1785
1771
  }
@@ -1821,7 +1807,7 @@ If none is set, hitting a WISE Agent channel returns a clear "not configured" er
1821
1807
  return;
1822
1808
  }
1823
1809
  const authArgs = rest.slice(1);
1824
- const mod = await import('./auth-DVa-sVa9.mjs');
1810
+ const mod = await import('./auth-C4miUceQ.mjs');
1825
1811
  let action;
1826
1812
  try {
1827
1813
  action = mod.parseWiseAgentAuthArgs(authArgs);
@@ -1831,7 +1817,7 @@ If none is set, hitting a WISE Agent channel returns a clear "not configured" er
1831
1817
  return;
1832
1818
  }
1833
1819
  if (action) {
1834
- const { updateEnvFile } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a3; });
1820
+ const { updateEnvFile } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a3; });
1835
1821
  const updates = mod.buildWiseAgentEnvUpdates(action);
1836
1822
  updateEnvFile(updates);
1837
1823
  for (const [k, v] of Object.entries(updates)) {
@@ -1845,7 +1831,7 @@ If none is set, hitting a WISE Agent channel returns a clear "not configured" er
1845
1831
  }
1846
1832
  async function handleDaemonAuthCommand(argv) {
1847
1833
  const sub = (argv[0] || "status").toLowerCase();
1848
- const mod = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a3; });
1834
+ const mod = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a3; });
1849
1835
  if (sub === "--help" || sub === "-h" || sub === "help") {
1850
1836
  console.log(`
1851
1837
  svamp daemon auth \u2014 Configure how Claude subprocesses authenticate
@@ -1997,15 +1983,15 @@ COMMANDS:
1997
1983
  share <id> --remove <email> Remove shared user
1998
1984
  share <id> --public <view|interact|off> Set public link access
1999
1985
 
2000
- Loop (self-verifying iterative automation):
2001
- loop-start <id> "<task>" [options] Start a self-verifying loop
2002
- loop-cancel <id> Cancel the loop
1986
+ Loop (self-verifying gate \u2014 iterate/gate until criteria are met):
1987
+ loop <id> ["<task>"] --until "<criteria>" [opts]
1988
+ Attach a Stop gate. WITH a task \u2192 kick the agent
1989
+ off and gate until done. WITHOUT (only --until) \u2192
1990
+ HOT-PLUG onto the running session (no kickoff).
1991
+ opts: --oracle "cmd" --agent --parent <id> --max N
1992
+ loop-cancel <id> Cancel the loop / release the gate
2003
1993
  loop-status <id> Show loop phase + iteration
2004
1994
 
2005
- Supervisor (attach a Stop gate + success criteria to any session):
2006
- supervise <id> "<criteria>" [opts] Attach: --oracle "cmd" --agent --parent <id> --max N
2007
- unsupervise <id> Detach the supervisor
2008
-
2009
1995
  Inbox:
2010
1996
  inbox send <id> "<body>" [opts] Send a message to session inbox
2011
1997
  inbox list <id> [--unread] [--json] List inbox messages
@@ -2058,11 +2044,14 @@ MESSAGES OPTIONS:
2058
2044
  --json Output as JSON array of {id, seq, role, text, createdAt}
2059
2045
  --raw With --json: include full raw objects (tool_use, tool_result, thinking)
2060
2046
 
2061
- LOOP OPTIONS (for loop-start):
2062
- --criteria <text> Success criteria \u2014 how we'll know it's done (seeds the evaluator)
2047
+ LOOP OPTIONS (for loop):
2048
+ --until <text> Success criteria \u2014 how we'll know it's done (the gate's goal)
2063
2049
  --oracle <cmd> Pass/fail command (tests/build/lint) the gate runs each iteration
2050
+ --agent Independent evaluator judge (on by default)
2051
+ --parent <id> Route the verdict to a lead session (crew)
2064
2052
  --max <n> Max iterations before giving up (default: 20)
2065
2053
  --evaluator <on|off> Independent evaluator that judges "done" (default: on)
2054
+ (omit the task and pass only --until to HOT-PLUG the gate onto a running session)
2066
2055
 
2067
2056
  EXIT CODES (for wait, send --wait, spawn --wait):
2068
2057
  0 Agent is idle (task completed successfully)
@@ -2115,9 +2104,10 @@ EXAMPLES:
2115
2104
  # === Isolated session with network restrictions ===
2116
2105
  svamp session spawn claude -d /tmp/sandbox --isolate --deny-network
2117
2106
 
2118
- # === Loop: self-verifying iterative automation ===
2119
- svamp session loop-start abc1 "Fix all linting errors" \\
2120
- --criteria "eslint reports zero errors" --oracle "npm run lint" --max 15
2107
+ # === Loop: self-verifying gate (task \u2192 kickoff; --until only \u2192 hot-plug) ===
2108
+ svamp session loop abc1 "Fix all linting errors" \\
2109
+ --until "eslint reports zero errors" --oracle "npm run lint" --max 15
2110
+ svamp session loop abc1 --until "all tests pass" --oracle "npm test" # hot-plug onto a running session
2121
2111
  `);
2122
2112
  }
2123
2113
  function printMachineHelp() {
@@ -2154,7 +2144,7 @@ Examples:
2154
2144
  async function printSkillsHelp() {
2155
2145
  let browseUrl = "<HYPHA_SERVER_URL>/<workspace>/artifacts/marketplace (set HYPHA_SERVER_URL)";
2156
2146
  try {
2157
- const { getArtifactBaseUrl, getSkillsCollectionName } = await import('./run-C23-A9KM.mjs').then(function (n) { return n.a5; });
2147
+ const { getArtifactBaseUrl, getSkillsCollectionName } = await import('./run-BaTwfE1Q.mjs').then(function (n) { return n.a5; });
2158
2148
  browseUrl = `${getArtifactBaseUrl()}/${getSkillsCollectionName()}`;
2159
2149
  } catch {
2160
2150
  }
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { execSync } from 'node:child_process';
3
3
  import { basename, resolve, join, isAbsolute } from 'node:path';
4
4
  import os from 'node:os';
5
- import { I as formatHandle, J as normalizeAllowedUser, K as loadSecurityContextConfig, L as resolveSecurityContext, M as buildSecurityContextFromFlags, N as mergeSecurityContexts, c as connectToHypha, O as buildSessionShareUrl, P as computeOutboundHop, m as shortId, Q as buildMachineShareUrl, T as parseHandle, U as handleMatchesMetadata } from './run-C23-A9KM.mjs';
5
+ import { I as formatHandle, J as normalizeAllowedUser, K as loadSecurityContextConfig, L as resolveSecurityContext, M as buildSecurityContextFromFlags, N as mergeSecurityContexts, c as connectToHypha, O as buildSessionShareUrl, P as computeOutboundHop, m as shortId, Q as buildMachineShareUrl, T as parseHandle, U as handleMatchesMetadata } from './run-BaTwfE1Q.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -2384,23 +2384,27 @@ async function sessionLoopStart(sessionIdPartial, task, machineId, opts) {
2384
2384
  const { server, machine, fullId } = await connectAndResolveSession(sessionIdPartial, machineId);
2385
2385
  try {
2386
2386
  const svc = getSessionProxy(machine, fullId);
2387
+ const until = opts?.until || opts?.criteria;
2387
2388
  const maxIterations = opts?.maxIterations ?? 20;
2388
- const evaluator = opts?.evaluator !== false;
2389
+ const evaluator = opts?.agent ? true : opts?.evaluator !== false;
2389
2390
  await svc.updateConfig({
2390
2391
  loop: {
2391
- task,
2392
- ...opts?.criteria ? { criteria: opts.criteria } : {},
2392
+ ...task ? { task } : {},
2393
+ ...until ? { until } : {},
2393
2394
  ...opts?.oracle ? { oracle: opts.oracle } : {},
2395
+ ...opts?.parent ? { parent: opts.parent } : {},
2394
2396
  max_iterations: maxIterations,
2395
2397
  evaluator
2396
2398
  }
2397
2399
  });
2398
- console.log(`Loop started on session ${fullId.slice(0, 8)}`);
2399
- console.log(` Task: ${task.slice(0, 100)}${task.length > 100 ? "..." : ""}`);
2400
- if (opts?.criteria) console.log(` Success criteria: ${opts.criteria.slice(0, 100)}${opts.criteria.length > 100 ? "..." : ""}`);
2400
+ console.log(`\u{1F501} Loop ${task ? "started" : "attached"} on session ${fullId.slice(0, 8)}`);
2401
+ if (task) console.log(` Task: ${task.slice(0, 100)}${task.length > 100 ? "..." : ""}`);
2402
+ if (until) console.log(` Until: ${until.slice(0, 100)}${until.length > 100 ? "..." : ""}`);
2401
2403
  console.log(` Oracle: ${opts?.oracle || "(none)"}`);
2402
2404
  console.log(` Evaluator: ${evaluator ? "on" : "off"}`);
2405
+ if (opts?.parent) console.log(` Parent review: ${opts.parent.slice(0, 8)}`);
2403
2406
  console.log(` Max iterations: ${maxIterations}`);
2407
+ if (!task) console.log(` (hot-plug \u2014 gating the session's current work)`);
2404
2408
  } finally {
2405
2409
  await server.disconnect();
2406
2410
  }
@@ -2456,44 +2460,6 @@ async function sessionLoopStatus(sessionIdPartial, machineId) {
2456
2460
  await server.disconnect();
2457
2461
  }
2458
2462
  }
2459
- async function sessionSupervise(sessionIdPartial, criteria, machineId, opts) {
2460
- const { server, machine, fullId } = await connectAndResolveSession(sessionIdPartial, machineId);
2461
- try {
2462
- const svc = getSessionProxy(machine, fullId);
2463
- const judges = [];
2464
- if (opts?.oracle) judges.push({ type: "oracle", cmd: opts.oracle, on_fail: opts?.parent ? "escalate" : "reject" });
2465
- if (opts?.parent) judges.push({ type: "parent", parent: opts.parent });
2466
- if (opts?.agent || judges.length === 0) judges.push({ type: "agent" });
2467
- const maxRounds = opts?.maxRounds ?? 20;
2468
- await svc.updateConfig({
2469
- supervisor: {
2470
- criteria,
2471
- judges,
2472
- action: opts?.action || "block",
2473
- max_rounds: maxRounds
2474
- }
2475
- });
2476
- const judgeLabel = judges.map((j) => j.type).join("\u2192");
2477
- console.log(`\u{1F441} Supervisor attached to session ${fullId.slice(0, 8)}`);
2478
- console.log(` Criteria: ${criteria.slice(0, 100)}${criteria.length > 100 ? "..." : ""}`);
2479
- console.log(` Judges: ${judgeLabel}`);
2480
- if (opts?.oracle) console.log(` Oracle: ${opts.oracle}`);
2481
- if (opts?.parent) console.log(` Parent review: ${opts.parent.slice(0, 8)} (async)`);
2482
- console.log(` Max rounds: ${maxRounds}`);
2483
- } finally {
2484
- await server.disconnect();
2485
- }
2486
- }
2487
- async function sessionUnsupervise(sessionIdPartial, machineId) {
2488
- const { server, machine, fullId } = await connectAndResolveSession(sessionIdPartial, machineId);
2489
- try {
2490
- const svc = getSessionProxy(machine, fullId);
2491
- await svc.updateConfig({ supervisor: null });
2492
- console.log(`Supervisor detached from session ${fullId.slice(0, 8)}`);
2493
- } finally {
2494
- await server.disconnect();
2495
- }
2496
- }
2497
2463
  async function sessionInboxSend(sessionIdPartial, body, machineId, opts) {
2498
2464
  const { server, machine, fullId } = await connectAndResolveSession(sessionIdPartial, machineId);
2499
2465
  try {
@@ -2634,4 +2600,4 @@ async function sessionInboxClear(sessionIdPartial, machineId, opts) {
2634
2600
  }
2635
2601
  }
2636
2602
 
2637
- export { collectAssistantResponse, connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, queryCore, renderMessage, resolveSessionId, sendCore, sessionApprove, sessionArchive, sessionAttach, sessionDelete, sessionDeny, sessionEditMessage, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionLoopCancel, sessionLoopStart, sessionLoopStatus, sessionMachines, sessionMessages, sessionQuery, sessionRefineLastReply, sessionResume, sessionSend, sessionShare, sessionSpawn, sessionSupervise, sessionUndoEdit, sessionUnsupervise, sessionWait, sessionWhoami, snapshotLatestSeq, validateSendOptions, wiseAskCli };
2603
+ export { collectAssistantResponse, connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, queryCore, renderMessage, resolveSessionId, sendCore, sessionApprove, sessionArchive, sessionAttach, sessionDelete, sessionDeny, sessionEditMessage, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionLoopCancel, sessionLoopStart, sessionLoopStatus, sessionMachines, sessionMessages, sessionQuery, sessionRefineLastReply, sessionResume, sessionSend, sessionShare, sessionSpawn, sessionUndoEdit, sessionWait, sessionWhoami, snapshotLatestSeq, validateSendOptions, wiseAskCli };
@@ -1,7 +1,7 @@
1
1
  import os from 'os';
2
2
  import fs__default from 'fs';
3
3
  import { resolve, join, relative } from 'path';
4
- import { p as parseFrontmatter, n as getSkillsServer, o as getSkillsWorkspaceName, q as getSkillsCollectionName, t as fetchWithTimeout, u as searchSkills, v as SKILLS_DIR, w as getSkillInfo, x as downloadSkillFile, y as listSkillFiles } from './run-C23-A9KM.mjs';
4
+ import { p as parseFrontmatter, n as getSkillsServer, o as getSkillsWorkspaceName, q as getSkillsCollectionName, t as fetchWithTimeout, u as searchSkills, v as SKILLS_DIR, w as getSkillInfo, x as downloadSkillFile, y as listSkillFiles } from './run-BaTwfE1Q.mjs';
5
5
  import 'fs/promises';
6
6
  import 'url';
7
7
  import 'child_process';
@@ -58,7 +58,7 @@ async function serviceExpose(args) {
58
58
  process.exit(1);
59
59
  }
60
60
  if (foreground) {
61
- const { runFrpcTunnel } = await import('./frpc-CWyoLax7.mjs');
61
+ const { runFrpcTunnel } = await import('./frpc-BpBOWRbL.mjs');
62
62
  await runFrpcTunnel(name, ports, void 0, {
63
63
  group,
64
64
  groupKey,
@@ -68,7 +68,7 @@ async function serviceExpose(args) {
68
68
  });
69
69
  return;
70
70
  }
71
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
71
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
72
72
  const { server, machine } = await connectAndGetMachine();
73
73
  try {
74
74
  const status = await machine.tunnelStart({
@@ -123,7 +123,7 @@ async function serviceServe(args) {
123
123
  };
124
124
  process.on("SIGINT", cleanup);
125
125
  process.on("SIGTERM", cleanup);
126
- const { runFrpcTunnel } = await import('./frpc-CWyoLax7.mjs');
126
+ const { runFrpcTunnel } = await import('./frpc-BpBOWRbL.mjs');
127
127
  await runFrpcTunnel(name, [caddyPort]);
128
128
  } catch (err) {
129
129
  console.error(`Error serving directory: ${err.message}`);
@@ -132,7 +132,7 @@ async function serviceServe(args) {
132
132
  }
133
133
  async function serviceList(_args) {
134
134
  try {
135
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
135
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
136
136
  const { server, machine } = await connectAndGetMachine();
137
137
  try {
138
138
  const tunnels = await machine.tunnelList({});
@@ -161,7 +161,7 @@ async function serviceDelete(args) {
161
161
  process.exit(1);
162
162
  }
163
163
  try {
164
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
164
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
165
165
  const { server, machine } = await connectAndGetMachine();
166
166
  try {
167
167
  await machine.tunnelStop({ name });
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { connectAndGetMachine, resolveSessionId, createWorktree, connectAndResolveSession } from './commands-BVx72l2K.mjs';
2
+ import { connectAndGetMachine, resolveSessionId, createWorktree, connectAndResolveSession } from './commands-BV30A1zt.mjs';
3
3
  import { execSync } from 'node:child_process';
4
- import { m as shortId } from './run-C23-A9KM.mjs';
4
+ import { m as shortId } from './run-BaTwfE1Q.mjs';
5
5
  import 'node:path';
6
6
  import 'node:os';
7
7
  import 'os';
@@ -204,17 +204,17 @@ async function featureStart(brief, opts = {}) {
204
204
  let judges = [];
205
205
  if (oracle) {
206
206
  judges = [{ type: "oracle", cmd: oracle, on_fail: "escalate" }, { type: "parent", parent: lead.sessionId }];
207
- patch.supervisor = {
208
- criteria: brief.trim(),
209
- judges,
210
- action: opts.action || "nudge",
211
- max_rounds: opts.maxRounds ?? 20
207
+ patch.loop = {
208
+ until: brief.trim(),
209
+ oracle,
210
+ parent: lead.sessionId,
211
+ max_iterations: opts.maxRounds ?? 20
212
212
  };
213
213
  }
214
214
  try {
215
215
  await rpc(machine, childId, "updateConfig", { patch });
216
216
  } catch (e) {
217
- console.warn(`Note: could not write crew/supervisor config yet (${e.message}).`);
217
+ console.warn(`Note: could not write crew/loop config yet (${e.message}).`);
218
218
  }
219
219
  try {
220
220
  await rpc(machine, childId, "sendMessage", {
@@ -453,7 +453,7 @@ const FEATURE_HELP = `Usage: svamp feature <command>
453
453
 
454
454
  start "<brief>" [--oracle "<cmd>"] [--base <branch>] [--action nudge|block]
455
455
  [--max N] [--dir <path>] [--lead <id>] [-m <machine>]
456
- Spawn a managed worktree child of the lead + attach a supervisor (oracle\u2192parent).
456
+ Spawn a managed worktree child of the lead + attach a loop gate (oracle\u2192parent).
457
457
  list [--json] [--lead <id>] [-m <machine>]
458
458
  The lead's feature children: branch, ahead/behind, status.
459
459
  report "<text>" [--blocker] [-m <machine>] (run by a child) progress/blocker \u2192 lead
@@ -1,7 +1,7 @@
1
1
  import { execSync, execFileSync } from 'node:child_process';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { createServer } from 'node:http';
4
- import { E as readChecklist, F as compileChecklist, G as RoutineStore, H as RoutineRunner } from './run-C23-A9KM.mjs';
4
+ import { E as readChecklist, F as compileChecklist, G as RoutineStore, H as RoutineRunner } from './run-BaTwfE1Q.mjs';
5
5
  import 'os';
6
6
  import 'fs/promises';
7
7
  import 'fs';
@@ -104,7 +104,7 @@ Criteria: ${res.criteria || "(none)"}
104
104
  urgency: "normal",
105
105
  hopCount: 1
106
106
  };
107
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
107
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
108
108
  const { server, machine } = await connectAndGetMachine();
109
109
  try {
110
110
  await machine.sessionRPC(reportTo, "sendInboxMessage", { message });
@@ -1,11 +1,11 @@
1
1
  import { writeFileSync, readFileSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- import { connectAndGetMachine } from './commands-BVx72l2K.mjs';
3
+ import { connectAndGetMachine } from './commands-BV30A1zt.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:child_process';
6
6
  import 'node:path';
7
7
  import 'node:os';
8
- import './run-C23-A9KM.mjs';
8
+ import './run-BaTwfE1Q.mjs';
9
9
  import 'os';
10
10
  import 'fs/promises';
11
11
  import 'url';
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import os from 'node:os';
4
- import { c as connectToHypha } from './run-C23-A9KM.mjs';
4
+ import { c as connectToHypha } from './run-BaTwfE1Q.mjs';
5
5
  import { PINNED_CLAUDE_CODE_VERSION } from './pinnedClaudeCode-HydRNEt7.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
@@ -3,7 +3,7 @@ import { mkdirSync, writeFileSync, unlinkSync, existsSync, chmodSync, readFileSy
3
3
  import { join } from 'path';
4
4
  import { homedir, platform, arch } from 'os';
5
5
  import { createHash, randomUUID } from 'crypto';
6
- import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-C23-A9KM.mjs';
6
+ import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-BaTwfE1Q.mjs';
7
7
  import 'fs/promises';
8
8
  import 'url';
9
9
  import 'node:crypto';
@@ -1,5 +1,5 @@
1
- import { D as resolveModel, V as describeMisconfiguration, W as buildMachineDeps } from './run-C23-A9KM.mjs';
2
- import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-D5F6XGss.mjs';
1
+ import { D as resolveModel, V as describeMisconfiguration, W as buildMachineDeps } from './run-BaTwfE1Q.mjs';
2
+ import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-D_Hzijan.mjs';
3
3
  import { WebSocket } from 'ws';
4
4
  import { execSync, spawn } from 'child_process';
5
5
  import 'os';
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-C23-A9KM.mjs';
1
+ export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-BaTwfE1Q.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,5 +1,5 @@
1
1
  var name = "svamp-cli";
2
- var version = "0.2.128";
2
+ var version = "0.2.129";
3
3
  var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
4
4
  var author = "Amun AI AB";
5
5
  var license = "SEE LICENSE IN LICENSE";
@@ -2677,7 +2677,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
2677
2677
  const tunnels = handlers.tunnels;
2678
2678
  if (!tunnels) throw new Error("Tunnel management not available");
2679
2679
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
2680
- const { FrpcTunnel } = await import('./frpc-CWyoLax7.mjs');
2680
+ const { FrpcTunnel } = await import('./frpc-BpBOWRbL.mjs');
2681
2681
  const tunnel = new FrpcTunnel({
2682
2682
  name: params.name,
2683
2683
  ports: params.ports,
@@ -2938,7 +2938,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
2938
2938
  }
2939
2939
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
2940
2940
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
2941
- const { toolsForRole } = await import('./sideband-D5F6XGss.mjs');
2941
+ const { toolsForRole } = await import('./sideband-D_Hzijan.mjs');
2942
2942
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
2943
2943
  return fmt(r2);
2944
2944
  }
@@ -3037,7 +3037,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3037
3037
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
3038
3038
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
3039
3039
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
3040
- const { queryCore } = await import('./commands-BVx72l2K.mjs');
3040
+ const { queryCore } = await import('./commands-BV30A1zt.mjs');
3041
3041
  const timeout = c.reply?.timeout_sec || 120;
3042
3042
  let result;
3043
3043
  try {
@@ -10804,15 +10804,32 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
10804
10804
  loopChecker();
10805
10805
  };
10806
10806
  const writeConfig = (patch) => {
10807
- if ("loop" in patch) {
10808
- const lp = patch.loop;
10809
- if (lp && typeof lp === "object" && typeof lp.task === "string" && lp.task.trim()) {
10810
- const oracle = typeof lp.oracle === "string" && lp.oracle.trim() ? lp.oracle.trim() : void 0;
10811
- const maxIterations = typeof lp.max_iterations === "number" ? lp.max_iterations : 20;
10812
- const evaluator = lp.evaluator !== false;
10807
+ const _gateKey = "loop" in patch ? "loop" : "supervisor" in patch ? "supervisor" : null;
10808
+ if (_gateKey) {
10809
+ let cfg = patch[_gateKey];
10810
+ if (_gateKey === "supervisor" && cfg && typeof cfg === "object") {
10811
+ const j = Array.isArray(cfg.judges) ? cfg.judges : [];
10812
+ const oj = j.find((x) => x?.type === "oracle");
10813
+ const pj = j.find((x) => x?.type === "parent");
10814
+ cfg = {
10815
+ // legacy supervisor = hot-plug (no task); criteria → until.
10816
+ until: cfg.criteria,
10817
+ oracle: (oj && typeof oj.cmd === "string" ? oj.cmd : void 0) || cfg.oracle,
10818
+ evaluator: j.length === 0 || j.some((x) => x?.type === "agent"),
10819
+ parent: pj?.parent || cfg.parent,
10820
+ max_iterations: cfg.max_rounds
10821
+ };
10822
+ }
10823
+ const task = cfg && typeof cfg.task === "string" && cfg.task.trim() ? cfg.task.trim() : void 0;
10824
+ const until = cfg && typeof cfg.until === "string" && cfg.until.trim() ? cfg.until.trim() : cfg && typeof cfg.criteria === "string" && cfg.criteria.trim() ? cfg.criteria.trim() : void 0;
10825
+ if (cfg && typeof cfg === "object" && (task || until)) {
10826
+ const oracle = typeof cfg.oracle === "string" && cfg.oracle.trim() ? cfg.oracle.trim() : void 0;
10827
+ const evaluator = cfg.evaluator !== false;
10828
+ const maxIterations = typeof cfg.max_iterations === "number" ? cfg.max_iterations : typeof cfg.max_rounds === "number" ? cfg.max_rounds : 20;
10813
10829
  const ok = initLoop(directory, {
10814
- task: lp.task.trim(),
10815
- criteria: typeof lp.criteria === "string" && lp.criteria.trim() ? lp.criteria.trim() : void 0,
10830
+ task: task || until,
10831
+ // LOOP.md goal = the task, or the until-criteria when hot-plugging
10832
+ criteria: until,
10816
10833
  oracle,
10817
10834
  maxIterations,
10818
10835
  evaluator,
@@ -10820,24 +10837,23 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
10820
10837
  });
10821
10838
  if (ok) {
10822
10839
  const existingQueue = getMetadata().messageQueue || [];
10823
- const kickoff = "Begin the loop. Read LOOP.md and work on the task until the exit conditions are met. Do not stop early \u2014 an independent Stop gate will re-check before the loop can end.";
10824
- setMetadata((m) => ({
10825
- ...m,
10826
- messageQueue: [...existingQueue, {
10827
- id: randomUUID$1(),
10828
- text: kickoff,
10829
- // Compact chat badge; full task lives in LOOP.md. Show an ellipsis
10830
- // when truncated so it's clear the preview is shortened, not the task.
10831
- displayText: `\u{1F501} Loop started: ${lp.task.trim().slice(0, 100)}${lp.task.trim().length > 100 ? "\u2026" : ""}`,
10832
- createdAt: Date.now()
10833
- }]
10834
- }));
10840
+ if (task) {
10841
+ const kickoff = "Begin the loop. Read LOOP.md and work on the task until the exit conditions are met. Do not stop early \u2014 an independent Stop gate will re-check before the loop can end.";
10842
+ setMetadata((m) => ({ ...m, messageQueue: [...existingQueue, { id: randomUUID$1(), text: kickoff, displayText: `\u{1F501} Loop started: ${task.slice(0, 100)}${task.length > 100 ? "\u2026" : ""}`, createdAt: Date.now() }] }));
10843
+ } else {
10844
+ const idle = getMetadata().lifecycleState === "idle";
10845
+ if (idle) {
10846
+ const nudge = `A loop gate is now active. Keep working until this is met: ${until}
10847
+ Or verify and finish \u2014 an independent Stop gate re-checks before you can stop.`;
10848
+ setMetadata((m) => ({ ...m, messageQueue: [...existingQueue, { id: randomUUID$1(), text: nudge, displayText: `\u{1F501} Loop until: ${until.slice(0, 100)}${until.length > 100 ? "\u2026" : ""}`, createdAt: Date.now() }] }));
10849
+ }
10850
+ }
10851
+ onLoopActivated?.();
10835
10852
  sessionService.pushMessage(
10836
- { type: "message", message: `\u{1F501} Loop started \u2014 iterating until done (oracle: ${oracle || "none"}, evaluator ${evaluator ? "on" : "off"}, max ${maxIterations}).` },
10853
+ { type: "message", message: `\u{1F501} Loop active \u2014 ${task ? "iterating on the task" : "gating current work"} (until: ${until || "done"}, oracle: ${oracle || "none"}, evaluator ${evaluator ? "on" : "off"}, max ${maxIterations}).` },
10837
10854
  "event"
10838
10855
  );
10839
- logger.log(`[svampConfig] Loop started: "${lp.task.trim().slice(0, 50)}..."`);
10840
- onLoopActivated?.();
10856
+ logger.log(`[svampConfig] Loop active (${task ? "kickoff" : "hot-plug"}): until="${(until || task || "").slice(0, 50)}"`);
10841
10857
  } else {
10842
10858
  sessionService.pushMessage(
10843
10859
  { type: "message", message: "Failed to start loop \u2014 the loop skill could not be located. Reinstall with: svamp skills install loop --force", level: "error" },
@@ -10850,54 +10866,7 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
10850
10866
  sessionService.pushMessage({ type: "message", message: "Loop cancelled." }, "event");
10851
10867
  logger.log(`[svampConfig] Loop cancelled`);
10852
10868
  }
10853
- const { loop: _, ...restPatch } = patch;
10854
- patch = restPatch;
10855
- }
10856
- if ("supervisor" in patch) {
10857
- const sup = patch.supervisor;
10858
- if (sup && typeof sup === "object" && typeof sup.criteria === "string" && sup.criteria.trim()) {
10859
- const criteria = sup.criteria.trim();
10860
- const judges = Array.isArray(sup.judges) ? sup.judges : [];
10861
- const oracleJudge = judges.find((j) => j?.type === "oracle");
10862
- const oracle = oracleJudge && typeof oracleJudge.cmd === "string" && oracleJudge.cmd.trim() ? oracleJudge.cmd.trim() : typeof sup.oracle === "string" && sup.oracle.trim() ? sup.oracle.trim() : void 0;
10863
- const hasAgentJudge = judges.length === 0 || judges.some((j) => j?.type === "agent");
10864
- const maxRounds = typeof sup.max_rounds === "number" ? sup.max_rounds : 20;
10865
- const ok = initLoop(directory, {
10866
- task: criteria,
10867
- // P1: criteria seeds LOOP.md as the goal (skill carries it as config.criteria in #30)
10868
- criteria,
10869
- oracle,
10870
- maxIterations: maxRounds,
10871
- evaluator: hasAgentJudge,
10872
- sessionId
10873
- });
10874
- if (ok) {
10875
- const judgeLabel = judges.length ? judges.map((j) => j.type).join("\u2192") : "agent";
10876
- const idle = getMetadata().lifecycleState === "idle";
10877
- if (idle) {
10878
- const existingQueue = getMetadata().messageQueue || [];
10879
- const nudge = `You are now under supervision. Success criteria: ${criteria}
10880
- Continue working until they are met, or verify and finish \u2014 an independent Stop gate will re-check before you can stop.`;
10881
- setMetadata((m) => ({ ...m, messageQueue: [...existingQueue, { id: randomUUID$1(), text: nudge, displayText: `\u{1F441} Supervisor attached`, createdAt: Date.now() }] }));
10882
- onLoopActivated?.();
10883
- }
10884
- sessionService.pushMessage(
10885
- { type: "message", message: `\u{1F441} Supervisor attached \u2014 judges: ${judgeLabel}, max ${maxRounds}. Criteria: ${criteria.slice(0, 120)}${criteria.length > 120 ? "\u2026" : ""}` },
10886
- "event"
10887
- );
10888
- logger.log(`[svampConfig] Supervisor attached (judges: ${judgeLabel}, max ${maxRounds})`);
10889
- } else {
10890
- sessionService.pushMessage(
10891
- { type: "message", message: "Failed to attach supervisor \u2014 the loop skill could not be located. Reinstall with: svamp skills install loop --force", level: "error" },
10892
- "event"
10893
- );
10894
- }
10895
- } else {
10896
- deactivateLoop(directory, sessionId);
10897
- sessionService.pushMessage({ type: "message", message: "Supervisor detached." }, "event");
10898
- logger.log(`[svampConfig] Supervisor detached`);
10899
- }
10900
- const { supervisor: _s, ...restPatch } = patch;
10869
+ const { [_gateKey]: _drop, ...restPatch } = patch;
10901
10870
  patch = restPatch;
10902
10871
  }
10903
10872
  if ("checklist" in patch) {
@@ -11359,7 +11328,7 @@ async function startDaemon(options) {
11359
11328
  const list = loadExposedTunnels().filter((t) => t.name !== name);
11360
11329
  saveExposedTunnels(list);
11361
11330
  }
11362
- const { ServeManager } = await import('./serveManager-CxbgXYEo.mjs');
11331
+ const { ServeManager } = await import('./serveManager-cPgahjYE.mjs');
11363
11332
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
11364
11333
  ensureAutoInstalledSkills(logger).catch(() => {
11365
11334
  });
@@ -14047,7 +14016,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
14047
14016
  const specs = loadExposedTunnels();
14048
14017
  if (specs.length === 0) return;
14049
14018
  logger.log(`[exposed-tunnels] Restoring ${specs.length} tunnel(s) from ${EXPOSED_TUNNELS_FILE}`);
14050
- const { FrpcTunnel } = await import('./frpc-CWyoLax7.mjs');
14019
+ const { FrpcTunnel } = await import('./frpc-BpBOWRbL.mjs');
14051
14020
  for (const spec of specs) {
14052
14021
  if (tunnels.has(spec.name)) continue;
14053
14022
  try {
@@ -1,4 +1,4 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { X as generateFriendlyName, m as shortId, c as connectToHypha, a as createSessionStore, r as registerMachineService, Y as generateHookSettings } from './run-C23-A9KM.mjs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { X as generateFriendlyName, m as shortId, c as connectToHypha, a as createSessionStore, r as registerMachineService, Y as generateHookSettings } from './run-BaTwfE1Q.mjs';
2
2
  import os from 'node:os';
3
3
  import { resolve, join } from 'node:path';
4
4
  import { existsSync, readFileSync, watch } from 'node:fs';
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
58
58
  const pos = positionalArgs(args);
59
59
  const name = pos[0];
60
60
  if (!name) {
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
93
93
  }
94
94
  }
95
95
  async function serveApply(args, machineId) {
96
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
97
97
  const fs = await import('fs');
98
98
  const yaml = await import('yaml');
99
99
  const file = positionalArgs(args)[0];
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
182
182
  }
183
183
  }
184
184
  async function serveRemove(args, machineId) {
185
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
186
186
  const pos = positionalArgs(args);
187
187
  const name = pos[0];
188
188
  if (!name) {
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
202
202
  }
203
203
  }
204
204
  async function serveList(args, machineId) {
205
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
206
206
  const all = hasFlag(args, "--all", "-a");
207
207
  const json = hasFlag(args, "--json");
208
208
  const sessionId = getFlag(args, "--session");
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
235
235
  }
236
236
  }
237
237
  async function serveInfo(machineId) {
238
- const { connectAndGetMachine } = await import('./commands-BVx72l2K.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-BV30A1zt.mjs');
239
239
  const { machine, server } = await connectAndGetMachine(machineId);
240
240
  try {
241
241
  const info = await machine.serveInfo();
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import * as http from 'http';
5
5
  import * as net from 'net';
6
6
  import * as path from 'path';
7
- import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-C23-A9KM.mjs';
7
+ import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-BaTwfE1Q.mjs';
8
8
  import 'os';
9
9
  import 'fs/promises';
10
10
  import 'url';
@@ -713,7 +713,7 @@ class ServeManager {
713
713
  const mount = this.mounts.get(mountName);
714
714
  const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, `static-${subdomainSafe}-${mount.linkToken}`]]) : void 0;
715
715
  try {
716
- const { FrpcTunnel } = await import('./frpc-CWyoLax7.mjs');
716
+ const { FrpcTunnel } = await import('./frpc-BpBOWRbL.mjs');
717
717
  let tunnel;
718
718
  tunnel = new FrpcTunnel({
719
719
  name: tunnelName,
@@ -1,4 +1,4 @@
1
- import { R as READ_ONLY_TOOLS, z as loadMachineContext, A as buildMachineInstructions, B as machineToolsForRole, C as buildMachineTools } from './run-C23-A9KM.mjs';
1
+ import { R as READ_ONLY_TOOLS, z as loadMachineContext, A as buildMachineInstructions, B as machineToolsForRole, C as buildMachineTools } from './run-BaTwfE1Q.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.128",
3
+ "version": "0.2.129",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",