svamp-cli 0.2.115 → 0.2.117

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.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: crew
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.
5
+ ---
6
+
7
+ # Crew — a lead session that delegates features to managed worktree children
8
+
9
+ This skill turns one session into a **lead** that delegates each feature to an isolated
10
+ **worktree child** and pulls the finished work back to the base branch automatically — so
11
+ you talk to **one** session per project instead of shepherding a dozen that all fight over
12
+ the same working tree.
13
+
14
+ A **crew** is emergent, not a heavy object: it is just plain sessions linked by
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).
19
+
20
+ ## The verbs (these are your tools)
21
+
22
+ ```
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.
26
+ svamp feature list [--json]
27
+ # (lead) your children: branch, ahead/behind base, dirty, idle/active.
28
+ svamp feature report "<text>" [--blocker]
29
+ # (child) push a progress note or blocker to your lead.
30
+ svamp feature done [--summary "<text>"]
31
+ # (child) signal completion: sends a merge-request to your lead.
32
+ svamp feature merge <child-id> [--keep-child]
33
+ # (lead) verify → merge branch into base → remove worktree → archive the child.
34
+ ```
35
+
36
+ ## If you are a LEAD
37
+
38
+ You coordinate the project. Keep your own working tree (the base branch, e.g. `main`) clean —
39
+ **delegate features, don't do them in your own tree.**
40
+
41
+ - **Delegate:** for each distinct feature, run `svamp feature start "<brief>"`. Give a crisp,
42
+ self-contained brief and, when there's a test/build that proves the feature, pass
43
+ `--oracle "<cmd>"` so it's auto-checked.
44
+ - **Stay aware:** run `svamp feature list` when you start working and whenever you manage the
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.
48
+ - **Review & merge — this is the gradient that closes the loop.** When a child sends a
49
+ `<merge-request>` or you receive a `<supervision-verdict … verdict="approved">` from a
50
+ child, **run `svamp feature merge <child-id>`**. With an oracle that passed, this is the
51
+ default path — merge promptly. The merge verifies the child's worktree is clean, merges its
52
+ branch into the base, removes the worktree, and archives the child. On a conflict or a dirty
53
+ worktree the merge is **deferred to rework** (the child is re-woken with guidance and left
54
+ alive — un-merged work is never destroyed); help it resolve, then merge again.
55
+ - **Nudge stalled children.** If `feature list` shows a child idle with committed, ahead-of-base
56
+ work that hasn't been reported done, send `svamp session inbox send <child> "status?"` (or
57
+ `feature report`-style ping) to move it along.
58
+
59
+ ## If you are a FEATURE CHILD
60
+
61
+ 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
+
64
+ - **Work in your worktree.** Implement the feature. Commit as you go. Keep the oracle/tests green.
65
+ - **Report.** Use `svamp feature report "<note>"` for milestones and `--blocker` when stuck —
66
+ your lead is watching.
67
+ - **Finish cleanly.** When the feature is complete and committed (worktree clean, tests green),
68
+ run `svamp feature done --summary "<what changed>"`. This sends a merge-request to your lead.
69
+ - **Do not merge your own branch or remove your own worktree** — the lead does the merge-back so
70
+ the base tree isn't corrupted. After the lead merges, your worktree is removed and you are
71
+ archived. If you get a `<crew-freeze>` message, stop editing immediately. If you get a
72
+ `<crew-rework>` message, address the guidance and run `svamp feature done` again.
73
+
74
+ ## Why this design
75
+
76
+ - **One conversation, many features.** The lead is your single point of control; children run in
77
+ parallel isolation and report up.
78
+ - **Merge-and-close is the default, not a chore.** The supervisor routes a verdict to the lead,
79
+ the lead merges, the child closes — the "gradient" that keeps finished work from rotting on a
80
+ stale branch.
81
+ - **Isolation by worktree.** Each feature has its own branch + tree, so children never collide on
82
+ one working directory (the mess this skill exists to fix).
83
+ - **Safety:** merges only proceed from a clean child worktree and a clean base tree; conflicts and
84
+ dirty trees defer to rework. Crew never destroys un-merged work.
85
+
86
+ See `docs/crew-design.md` and the frozen `docs/supervisor-gate-design.md` for the full model.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: loop
3
- version: 0.3.2
3
+ version: 0.3.3
4
4
  description: Run a task as a reliable, self-verifying loop — iterate until objective exit conditions are met, with an independent evaluator instead of self-judging. Use when a task needs repeated iterations until "done" (fix until tests pass, refactor until clean, build until a spec is met, autonomous long-running work).
5
5
  ---
6
6
 
@@ -71,6 +71,9 @@ 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).
76
+ ...(criteria ? { criteria: criteria.trim() } : {}),
74
77
  oracle: oracle ? { command: oracle, timeout_sec: 600 } : null,
75
78
  evaluator: { enabled: evaluatorOn, model },
76
79
  max_iterations: max,
@@ -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 { n as shortId } from './run-DXzaCfex.mjs';
5
+ import { n as shortId } from './run-Ci6VToZR.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-DXzaCfex.mjs').then(function (n) { return n.T; });
99
+ const { projectName, writeProjectInfo, sanitizeDescription, projectInfoPath } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.T; });
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-B3NhziMR.mjs');
183
+ const { connectAndGetMachine } = await import('./commands-BxXUQlBD.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-B3NhziMR.mjs');
200
+ const { resolveSessionId } = await import('./commands-BxXUQlBD.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 { F as resolveModel } from './run-DXzaCfex.mjs';
1
+ import { F as resolveModel } from './run-Ci6VToZR.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-DXzaCfex.mjs';
1
+ import { e as clearStopMarker, f as stopMarkerExists, s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-Ci6VToZR.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-DXzaCfex.mjs').then(function (n) { return n._; });
37
+ const { getLoadedConfig } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n._; });
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-DXzaCfex.mjs').then(function (n) { return n.a0; });
54
+ const { restartDaemon } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.a0; });
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-Vudp6ihZ.mjs');
347
+ const { handleServiceCommand } = await import('./commands-CsJyJgin.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-CFO3GtKq.mjs');
355
+ const { handleServeCommand } = await import('./serveCommands-BuA8btah.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-Dmh59asw.mjs');
364
+ const { processCommand } = await import('./commands-Q1xvobXM.mjs');
365
365
  let machineId;
366
366
  const processArgs = args.slice(1);
367
367
  const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
@@ -375,18 +375,22 @@ async function main() {
375
375
  }), machineId);
376
376
  process.exit(0);
377
377
  } else if (subcommand === "routine" || subcommand === "routines") {
378
- const { routineCommand } = await import('./commands-DbQ14J-R.mjs');
378
+ const { routineCommand } = await import('./commands-BvKgI__M.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
+ } else if (subcommand === "feature" || subcommand === "crew") {
385
+ const { crewCommand } = await import('./commands-Do6Od6jK.mjs');
386
+ await crewCommand(args.slice(1));
387
+ process.exit(0);
384
388
  } else if (subcommand === "--help" || subcommand === "-h") {
385
389
  printHelp();
386
390
  } else if (!subcommand || subcommand === "start") {
387
391
  await handleInteractiveCommand();
388
392
  } else if (subcommand === "--version" || subcommand === "-v") {
389
- const pkg = await import('./package-BuIQUz-N.mjs').catch(() => ({ default: { version: "unknown" } }));
393
+ const pkg = await import('./package-uOEzgreT.mjs').catch(() => ({ default: { version: "unknown" } }));
390
394
  console.log(`svamp version: ${pkg.default.version}`);
391
395
  } else {
392
396
  console.error(`Unknown command: ${subcommand}`);
@@ -395,7 +399,7 @@ async function main() {
395
399
  }
396
400
  }
397
401
  async function handleInteractiveCommand() {
398
- const { runInteractive } = await import('./run-BnPtZvoP.mjs');
402
+ const { runInteractive } = await import('./run-C1jI28ZZ.mjs');
399
403
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
400
404
  let directory = process.cwd();
401
405
  let resumeSessionId;
@@ -440,7 +444,7 @@ async function handleAgentCommand() {
440
444
  return;
441
445
  }
442
446
  if (agentArgs[0] === "list") {
443
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.W; });
447
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.W; });
444
448
  console.log("Known agents:");
445
449
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
446
450
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -452,7 +456,7 @@ async function handleAgentCommand() {
452
456
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
453
457
  return;
454
458
  }
455
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.W; });
459
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.W; });
456
460
  let cwd = process.cwd();
457
461
  const filteredArgs = [];
458
462
  for (let i = 0; i < agentArgs.length; i++) {
@@ -476,12 +480,12 @@ async function handleAgentCommand() {
476
480
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
477
481
  let backend;
478
482
  if (KNOWN_MCP_AGENTS[config.agentName]) {
479
- const { CodexMcpBackend } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.X; });
483
+ const { CodexMcpBackend } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.X; });
480
484
  backend = new CodexMcpBackend({ cwd, log: logFn });
481
485
  } else {
482
- const { AcpBackend } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.V; });
483
- const { GeminiTransport } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.Y; });
484
- const { DefaultTransport } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.U; });
486
+ const { AcpBackend } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.V; });
487
+ const { GeminiTransport } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.Y; });
488
+ const { DefaultTransport } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.U; });
485
489
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
486
490
  backend = new AcpBackend({
487
491
  agentName: config.agentName,
@@ -608,7 +612,7 @@ async function handleSessionCommand() {
608
612
  process.exit(1);
609
613
  }
610
614
  }
611
- 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-B3NhziMR.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-BxXUQlBD.mjs');
612
616
  const parseFlagStr = (flag, shortFlag) => {
613
617
  for (let i = 1; i < sessionArgs.length; i++) {
614
618
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -676,7 +680,7 @@ async function handleSessionCommand() {
676
680
  allowDomain.push(sessionArgs[++i]);
677
681
  }
678
682
  }
679
- const { parseShareArg } = await import('./commands-B3NhziMR.mjs');
683
+ const { parseShareArg } = await import('./commands-BxXUQlBD.mjs');
680
684
  const shareEntries = share.map((s) => parseShareArg(s));
681
685
  await sessionSpawn(agent, dir, targetMachineId, {
682
686
  message,
@@ -755,30 +759,6 @@ async function handleSessionCommand() {
755
759
  model: parseFlagStr("--model"),
756
760
  plain: hasFlag("--plain")
757
761
  });
758
- } else if (sessionSubcommand === "edit-message" || sessionSubcommand === "edit") {
759
- if (!sessionArgs[1] || !sessionArgs[2] || sessionArgs[3] === void 0) {
760
- console.error("Usage: svamp session edit-message <session-id> <message-id> <new-text>");
761
- console.error(" Rewinds history: rewrites the message + drops everything after it, then restarts Claude.");
762
- process.exit(1);
763
- }
764
- const { sessionEditMessage } = await import('./commands-B3NhziMR.mjs');
765
- await sessionEditMessage(sessionArgs[1], sessionArgs[2], sessionArgs[3], targetMachineId);
766
- } else if (sessionSubcommand === "refine") {
767
- if (!sessionArgs[1] || !sessionArgs[2]) {
768
- console.error("Usage: svamp session refine <session-id> <instruction>");
769
- console.error(" Asks the agent to revise its latest reply in place (no extra round).");
770
- process.exit(1);
771
- }
772
- const { sessionRefineLastReply } = await import('./commands-B3NhziMR.mjs');
773
- await sessionRefineLastReply(sessionArgs[1], sessionArgs[2], targetMachineId);
774
- } else if (sessionSubcommand === "undo-edit" || sessionSubcommand === "undo") {
775
- if (!sessionArgs[1]) {
776
- console.error("Usage: svamp session undo-edit <session-id>");
777
- console.error(" Reverts the most recent edit/refine, restoring the pre-edit history.");
778
- process.exit(1);
779
- }
780
- const { sessionUndoEdit } = await import('./commands-B3NhziMR.mjs');
781
- await sessionUndoEdit(sessionArgs[1], targetMachineId);
782
762
  } else if (sessionSubcommand === "query") {
783
763
  const dir = sessionArgs[1];
784
764
  const prompt = sessionArgs[2];
@@ -787,7 +767,7 @@ async function handleSessionCommand() {
787
767
  console.error(" Spawns a stateless Claude session in <directory>, sends <prompt>, prints the answer, then deletes the session.");
788
768
  process.exit(1);
789
769
  }
790
- const { sessionQuery } = await import('./commands-B3NhziMR.mjs');
770
+ const { sessionQuery } = await import('./commands-BxXUQlBD.mjs');
791
771
  await sessionQuery(dir, prompt, targetMachineId, {
792
772
  timeout: parseFlagInt("--timeout"),
793
773
  json: hasFlag("--json"),
@@ -820,7 +800,7 @@ async function handleSessionCommand() {
820
800
  console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
821
801
  process.exit(1);
822
802
  }
823
- const { sessionApprove } = await import('./commands-B3NhziMR.mjs');
803
+ const { sessionApprove } = await import('./commands-BxXUQlBD.mjs');
824
804
  const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
825
805
  await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
826
806
  json: hasFlag("--json")
@@ -830,7 +810,7 @@ async function handleSessionCommand() {
830
810
  console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
831
811
  process.exit(1);
832
812
  }
833
- const { sessionDeny } = await import('./commands-B3NhziMR.mjs');
813
+ const { sessionDeny } = await import('./commands-BxXUQlBD.mjs');
834
814
  const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
835
815
  await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
836
816
  json: hasFlag("--json")
@@ -859,13 +839,34 @@ async function handleSessionCommand() {
859
839
  process.exit(1);
860
840
  }
861
841
  await sessionLoopStatus(sessionArgs[1], targetMachineId);
842
+ } else if (sessionSubcommand === "supervise") {
843
+ if (!sessionArgs[1] || !sessionArgs[2]) {
844
+ console.error('Usage: svamp session supervise <session-id> "<criteria>" [--oracle "cmd"] [--agent] [--parent <id>] [--action nudge|block] [--max N]');
845
+ process.exit(1);
846
+ }
847
+ const { sessionSupervise } = await import('./commands-BxXUQlBD.mjs');
848
+ const actionStr = parseFlagStr("--action");
849
+ await sessionSupervise(sessionArgs[1], sessionArgs[2], targetMachineId, {
850
+ oracle: parseFlagStr("--oracle"),
851
+ agent: hasFlag("--agent"),
852
+ parent: parseFlagStr("--parent"),
853
+ action: actionStr === "nudge" || actionStr === "block" ? actionStr : void 0,
854
+ maxRounds: parseFlagInt("--max") ?? parseFlagInt("--max-rounds")
855
+ });
856
+ } else if (sessionSubcommand === "unsupervise") {
857
+ if (!sessionArgs[1]) {
858
+ console.error("Usage: svamp session unsupervise <session-id>");
859
+ process.exit(1);
860
+ }
861
+ const { sessionUnsupervise } = await import('./commands-BxXUQlBD.mjs');
862
+ await sessionUnsupervise(sessionArgs[1], targetMachineId);
862
863
  } else if (sessionSubcommand === "set-title") {
863
864
  const title = sessionArgs[1];
864
865
  if (!title) {
865
866
  console.error("Usage: svamp session set-title <title>");
866
867
  process.exit(1);
867
868
  }
868
- const { sessionSetTitle } = await import('./agentCommands-CFWM6S7e.mjs');
869
+ const { sessionSetTitle } = await import('./agentCommands-CZgIpC1Z.mjs');
869
870
  await sessionSetTitle(title);
870
871
  } else if (sessionSubcommand === "set-project-description" || sessionSubcommand === "set-project") {
871
872
  const desc = sessionArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
@@ -873,7 +874,7 @@ async function handleSessionCommand() {
873
874
  console.error("Usage: svamp session set-project-description <text>");
874
875
  process.exit(1);
875
876
  }
876
- const { sessionSetProjectDescription } = await import('./agentCommands-CFWM6S7e.mjs');
877
+ const { sessionSetProjectDescription } = await import('./agentCommands-CZgIpC1Z.mjs');
877
878
  await sessionSetProjectDescription(desc);
878
879
  } else if (sessionSubcommand === "set-link") {
879
880
  const url = sessionArgs[1];
@@ -882,7 +883,7 @@ async function handleSessionCommand() {
882
883
  process.exit(1);
883
884
  }
884
885
  const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
885
- const { sessionSetLink } = await import('./agentCommands-CFWM6S7e.mjs');
886
+ const { sessionSetLink } = await import('./agentCommands-CZgIpC1Z.mjs');
886
887
  await sessionSetLink(url, label);
887
888
  } else if (sessionSubcommand === "notify") {
888
889
  const message = sessionArgs[1];
@@ -891,7 +892,7 @@ async function handleSessionCommand() {
891
892
  process.exit(1);
892
893
  }
893
894
  const level = parseFlagStr("--level") || "info";
894
- const { sessionNotify } = await import('./agentCommands-CFWM6S7e.mjs');
895
+ const { sessionNotify } = await import('./agentCommands-CZgIpC1Z.mjs');
895
896
  await sessionNotify(message, level);
896
897
  } else if (sessionSubcommand === "broadcast") {
897
898
  const action = sessionArgs[1];
@@ -899,7 +900,7 @@ async function handleSessionCommand() {
899
900
  console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
900
901
  process.exit(1);
901
902
  }
902
- const { sessionBroadcast } = await import('./agentCommands-CFWM6S7e.mjs');
903
+ const { sessionBroadcast } = await import('./agentCommands-CZgIpC1Z.mjs');
903
904
  await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
904
905
  } else if (sessionSubcommand === "inbox") {
905
906
  const inboxSubcmd = sessionArgs[1];
@@ -910,7 +911,7 @@ async function handleSessionCommand() {
910
911
  process.exit(1);
911
912
  }
912
913
  if (agentSessionId) {
913
- const { inboxSend } = await import('./agentCommands-CFWM6S7e.mjs');
914
+ const { inboxSend } = await import('./agentCommands-CZgIpC1Z.mjs');
914
915
  await inboxSend(sessionArgs[2], {
915
916
  body: sessionArgs[3],
916
917
  subject: parseFlagStr("--subject"),
@@ -925,7 +926,7 @@ async function handleSessionCommand() {
925
926
  }
926
927
  } else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
927
928
  if (agentSessionId && !sessionArgs[2]) {
928
- const { inboxList } = await import('./agentCommands-CFWM6S7e.mjs');
929
+ const { inboxList } = await import('./agentCommands-CZgIpC1Z.mjs');
929
930
  await inboxList({
930
931
  unread: hasFlag("--unread"),
931
932
  limit: parseFlagInt("--limit"),
@@ -947,7 +948,7 @@ async function handleSessionCommand() {
947
948
  process.exit(1);
948
949
  }
949
950
  if (agentSessionId && !sessionArgs[3]) {
950
- const { inboxList } = await import('./agentCommands-CFWM6S7e.mjs');
951
+ const { inboxList } = await import('./agentCommands-CZgIpC1Z.mjs');
951
952
  await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
952
953
  } else if (sessionArgs[3]) {
953
954
  await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
@@ -957,7 +958,7 @@ async function handleSessionCommand() {
957
958
  }
958
959
  } else if (inboxSubcmd === "reply") {
959
960
  if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
960
- const { inboxReply } = await import('./agentCommands-CFWM6S7e.mjs');
961
+ const { inboxReply } = await import('./agentCommands-CZgIpC1Z.mjs');
961
962
  await inboxReply(sessionArgs[2], sessionArgs[3]);
962
963
  } else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
963
964
  await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
@@ -993,7 +994,7 @@ async function handleMachineCommand() {
993
994
  return;
994
995
  }
995
996
  if (machineSubcommand === "share") {
996
- const { machineShare } = await import('./commands-B3NhziMR.mjs');
997
+ const { machineShare } = await import('./commands-BxXUQlBD.mjs');
997
998
  let machineId;
998
999
  const shareArgs = [];
999
1000
  for (let i = 1; i < machineArgs.length; i++) {
@@ -1023,7 +1024,7 @@ async function handleMachineCommand() {
1023
1024
  }
1024
1025
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
1025
1026
  } else if (machineSubcommand === "exec") {
1026
- const { machineExec } = await import('./commands-B3NhziMR.mjs');
1027
+ const { machineExec } = await import('./commands-BxXUQlBD.mjs');
1027
1028
  let machineId;
1028
1029
  let cwd;
1029
1030
  const cmdParts = [];
@@ -1043,7 +1044,7 @@ async function handleMachineCommand() {
1043
1044
  }
1044
1045
  await machineExec(machineId, command, cwd);
1045
1046
  } else if (machineSubcommand === "info") {
1046
- const { machineInfo } = await import('./commands-B3NhziMR.mjs');
1047
+ const { machineInfo } = await import('./commands-BxXUQlBD.mjs');
1047
1048
  let machineId;
1048
1049
  for (let i = 1; i < machineArgs.length; i++) {
1049
1050
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -1063,10 +1064,10 @@ async function handleMachineCommand() {
1063
1064
  level = machineArgs[++i];
1064
1065
  }
1065
1066
  }
1066
- const { machineNotify } = await import('./agentCommands-CFWM6S7e.mjs');
1067
+ const { machineNotify } = await import('./agentCommands-CZgIpC1Z.mjs');
1067
1068
  await machineNotify(message, level);
1068
1069
  } else if (machineSubcommand === "ls") {
1069
- const { machineLs } = await import('./commands-B3NhziMR.mjs');
1070
+ const { machineLs } = await import('./commands-BxXUQlBD.mjs');
1070
1071
  let machineId;
1071
1072
  let showHidden = false;
1072
1073
  let path;
@@ -1124,24 +1125,24 @@ Examples:
1124
1125
  };
1125
1126
  const hasFlag = (name) => fleetArgs.includes(`--${name}`);
1126
1127
  if (sub === "status") {
1127
- const { fleetStatus } = await import('./fleet-F8KB5IcM.mjs');
1128
+ const { fleetStatus } = await import('./fleet-l4Ku9jry.mjs');
1128
1129
  await fleetStatus();
1129
1130
  } else if (sub === "exec") {
1130
1131
  const command = fleetArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
1131
- const { fleetExec } = await import('./fleet-F8KB5IcM.mjs');
1132
+ const { fleetExec } = await import('./fleet-l4Ku9jry.mjs');
1132
1133
  await fleetExec(command, { cwd: flag("cwd") });
1133
1134
  } else if (sub === "upgrade-claude") {
1134
- const { fleetUpgradeClaude } = await import('./fleet-F8KB5IcM.mjs');
1135
+ const { fleetUpgradeClaude } = await import('./fleet-l4Ku9jry.mjs');
1135
1136
  await fleetUpgradeClaude({ version: flag("version", "-v") });
1136
1137
  } else if (sub === "upgrade-svamp") {
1137
- const { fleetUpgradeSvamp } = await import('./fleet-F8KB5IcM.mjs');
1138
+ const { fleetUpgradeSvamp } = await import('./fleet-l4Ku9jry.mjs');
1138
1139
  await fleetUpgradeSvamp({ version: flag("version", "-v"), excludeSelf: hasFlag("exclude-self") });
1139
1140
  } else if (sub === "daemon-restart") {
1140
- const { fleetDaemonRestart } = await import('./fleet-F8KB5IcM.mjs');
1141
+ const { fleetDaemonRestart } = await import('./fleet-l4Ku9jry.mjs');
1141
1142
  await fleetDaemonRestart({ graceful: !hasFlag("cleanup") });
1142
1143
  } else if (sub === "push-skill") {
1143
1144
  const name = fleetArgs[1];
1144
- const { fleetPushSkill } = await import('./fleet-F8KB5IcM.mjs');
1145
+ const { fleetPushSkill } = await import('./fleet-l4Ku9jry.mjs');
1145
1146
  await fleetPushSkill(name);
1146
1147
  } else {
1147
1148
  console.error(`Unknown fleet subcommand: ${sub}`);
@@ -1157,7 +1158,7 @@ async function handleSkillsCommand() {
1157
1158
  await printSkillsHelp();
1158
1159
  return;
1159
1160
  }
1160
- const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-Dj2M3sTB.mjs');
1161
+ const { skillsFind, skillsInstall, skillsList, skillsRemove, skillsPublish } = await import('./commands-QWVhHPCf.mjs');
1161
1162
  if (skillsSubcommand === "find" || skillsSubcommand === "search") {
1162
1163
  const query = skillsArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
1163
1164
  if (!query) {
@@ -1204,7 +1205,7 @@ async function loginToHypha() {
1204
1205
  process.exit(1);
1205
1206
  }
1206
1207
  const anchor = anchorArg.replace(/\/+$/, "");
1207
- const { loadInstanceConfig } = await import('./run-DXzaCfex.mjs').then(function (n) { return n._; });
1208
+ const { loadInstanceConfig } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n._; });
1208
1209
  let cfg = null;
1209
1210
  try {
1210
1211
  cfg = await loadInstanceConfig({ anchor, force: true });
@@ -1315,7 +1316,7 @@ async function logoutFromHypha() {
1315
1316
  } catch {
1316
1317
  }
1317
1318
  try {
1318
- const { clearInstanceConfigCache } = await import('./run-DXzaCfex.mjs').then(function (n) { return n._; });
1319
+ const { clearInstanceConfigCache } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n._; });
1319
1320
  clearInstanceConfigCache();
1320
1321
  } catch {
1321
1322
  }
@@ -1575,6 +1576,13 @@ Commands:
1575
1576
  svamp session approve/deny <id> Approve or deny pending permission requests
1576
1577
  svamp session --help Show ALL session commands and detailed options
1577
1578
 
1579
+ Crew (lead delegates features to managed worktree children):
1580
+ svamp feature start "<brief>" Spawn a worktree child of this lead + supervisor (oracle\u2192parent)
1581
+ svamp feature list This lead's feature children (branch, ahead/behind, status)
1582
+ svamp feature done|report (run by a child) signal completion / report progress to the lead
1583
+ svamp feature merge <child> (run by the lead) verify \u2192 merge \u2192 remove worktree \u2192 archive child
1584
+ svamp feature --help Show all crew commands and options
1585
+
1578
1586
  File serving:
1579
1587
  svamp serve <name> [directory] Serve a directory via the shared file server
1580
1588
  svamp serve remove <name> Remove a served mount
@@ -1646,7 +1654,7 @@ async function applyClaudeAuthFlags(argv) {
1646
1654
  "--use-hypha-proxy, --use-claude-login, and --anthropic-base-url/--anthropic-api-key are mutually exclusive"
1647
1655
  );
1648
1656
  }
1649
- const mod = await import('./run-DXzaCfex.mjs').then(function (n) { return n.Z; });
1657
+ const mod = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.Z; });
1650
1658
  if (hasHypha) {
1651
1659
  let url;
1652
1660
  const hyphaIdx = argv.indexOf("--use-hypha-proxy");
@@ -1700,7 +1708,7 @@ async function applyDaemonShareFlag(argv) {
1700
1708
  }
1701
1709
  }
1702
1710
  if (collected.length === 0) return;
1703
- const { updateEnvFile } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.Z; });
1711
+ const { updateEnvFile } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.Z; });
1704
1712
  const seen = /* @__PURE__ */ new Set();
1705
1713
  const deduped = collected.filter((e) => {
1706
1714
  const k = e.toLowerCase();
@@ -1733,7 +1741,7 @@ async function handleWiseAgentCommand(rest) {
1733
1741
  }
1734
1742
  });
1735
1743
  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(" ");
1736
- const { wiseAskCli } = await import('./commands-B3NhziMR.mjs');
1744
+ const { wiseAskCli } = await import('./commands-BxXUQlBD.mjs');
1737
1745
  await wiseAskCli(machineId, message, sessionId, { json });
1738
1746
  return;
1739
1747
  }
@@ -1745,7 +1753,7 @@ async function handleWiseAgentCommand(rest) {
1745
1753
  }
1746
1754
  return void 0;
1747
1755
  };
1748
- const { runWiseVoiceCli } = await import('./headlessCli-6Cps9gnO.mjs');
1756
+ const { runWiseVoiceCli } = await import('./headlessCli-BsVvbKhN.mjs');
1749
1757
  await runWiseVoiceCli({ voice: valueOf(["--voice"]), wakeKeywordPath: valueOf(["--wake"]), model: valueOf(["--model"]) });
1750
1758
  return;
1751
1759
  }
@@ -1787,7 +1795,7 @@ If none is set, hitting a WISE Agent channel returns a clear "not configured" er
1787
1795
  return;
1788
1796
  }
1789
1797
  const authArgs = rest.slice(1);
1790
- const mod = await import('./auth-B3NsDWG9.mjs');
1798
+ const mod = await import('./auth-Dkiiq1bg.mjs');
1791
1799
  let action;
1792
1800
  try {
1793
1801
  action = mod.parseWiseAgentAuthArgs(authArgs);
@@ -1797,7 +1805,7 @@ If none is set, hitting a WISE Agent channel returns a clear "not configured" er
1797
1805
  return;
1798
1806
  }
1799
1807
  if (action) {
1800
- const { updateEnvFile } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.Z; });
1808
+ const { updateEnvFile } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.Z; });
1801
1809
  const updates = mod.buildWiseAgentEnvUpdates(action);
1802
1810
  updateEnvFile(updates);
1803
1811
  for (const [k, v] of Object.entries(updates)) {
@@ -1811,7 +1819,7 @@ If none is set, hitting a WISE Agent channel returns a clear "not configured" er
1811
1819
  }
1812
1820
  async function handleDaemonAuthCommand(argv) {
1813
1821
  const sub = (argv[0] || "status").toLowerCase();
1814
- const mod = await import('./run-DXzaCfex.mjs').then(function (n) { return n.Z; });
1822
+ const mod = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.Z; });
1815
1823
  if (sub === "--help" || sub === "-h" || sub === "help") {
1816
1824
  console.log(`
1817
1825
  svamp daemon auth \u2014 Configure how Claude subprocesses authenticate
@@ -1968,6 +1976,10 @@ COMMANDS:
1968
1976
  loop-cancel <id> Cancel the loop
1969
1977
  loop-status <id> Show loop phase + iteration
1970
1978
 
1979
+ Supervisor (attach a Stop gate + success criteria to any session):
1980
+ supervise <id> "<criteria>" [opts] Attach: --oracle "cmd" --agent --parent <id> --max N
1981
+ unsupervise <id> Detach the supervisor
1982
+
1971
1983
  Inbox:
1972
1984
  inbox send <id> "<body>" [opts] Send a message to session inbox
1973
1985
  inbox list <id> [--unread] [--json] List inbox messages
@@ -2114,7 +2126,7 @@ Examples:
2114
2126
  async function printSkillsHelp() {
2115
2127
  let browseUrl = "<HYPHA_SERVER_URL>/<workspace>/artifacts/marketplace (set HYPHA_SERVER_URL)";
2116
2128
  try {
2117
- const { getArtifactBaseUrl, getSkillsCollectionName } = await import('./run-DXzaCfex.mjs').then(function (n) { return n.$; });
2129
+ const { getArtifactBaseUrl, getSkillsCollectionName } = await import('./run-Ci6VToZR.mjs').then(function (n) { return n.$; });
2118
2130
  browseUrl = `${getArtifactBaseUrl()}/${getSkillsCollectionName()}`;
2119
2131
  } catch {
2120
2132
  }
@@ -1,6 +1,6 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import { createServer } from 'node:http';
3
- import { R as RoutineStore, m as RoutineRunner } from './run-DXzaCfex.mjs';
3
+ import { R as RoutineStore, m as RoutineRunner } from './run-Ci6VToZR.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
6
6
  import 'fs';