svamp-cli 0.2.342 → 0.2.346

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.
Files changed (67) hide show
  1. package/bin/skills/artifact/SKILL.md +1 -1
  2. package/bin/skills/crew/SKILL.md +21 -3
  3. package/dist/DefaultTransport-vfp78fug.mjs +47 -0
  4. package/dist/GeminiTransport-3OkhtFRO.mjs +130 -0
  5. package/dist/KimiTransport-D8n009Tr.mjs +141 -0
  6. package/dist/acpAgentConfig-CObOPlA8.mjs +48 -0
  7. package/dist/acpBackend-BZ1MJhQV.mjs +922 -0
  8. package/dist/{adminCommands-CRTBDZan.mjs → adminCommands-BvsYnRDA.mjs} +2 -18
  9. package/dist/{agentCommands-BuO988tJ.mjs → agentCommands-B2Nl7Fof.mjs} +6 -23
  10. package/dist/api-BHjyC0Ph.mjs +157 -0
  11. package/dist/{auth--WS0wezs.mjs → auth-CRz8TsEl.mjs} +1 -22
  12. package/dist/bootStatus-DqtNgJch.mjs +143 -0
  13. package/dist/claudeAuth-iAerdaMr.mjs +247 -0
  14. package/dist/cli.mjs +2939 -5
  15. package/dist/codexAppServerBackend-VGsYtbqg.mjs +786 -0
  16. package/dist/codexProvider-BtxYc5Rj.mjs +68 -0
  17. package/dist/{commands-DXM17M6n.mjs → commands-BB1Kcyt-.mjs} +13 -19
  18. package/dist/{commands-DU4B-4Gh.mjs → commands-BOpoVBOM.mjs} +55 -25
  19. package/dist/{commands-C0HQiu-S.mjs → commands-C2aODeVc.mjs} +58 -33
  20. package/dist/{commands-Cwxy-C5N.mjs → commands-CiRCwjkJ.mjs} +10 -32
  21. package/dist/{commands-DDuGBSsz.mjs → commands-D1pZq3d4.mjs} +103 -41
  22. package/dist/{commands-BKb1g8Gq.mjs → commands-D69mnkYu.mjs} +20 -30
  23. package/dist/{commands-BsKgZ5sQ.mjs → commands-DW5RnHZw.mjs} +2 -19
  24. package/dist/{commands-DXLOKJOj.mjs → commands-H4PsTGn8.mjs} +58 -26
  25. package/dist/cron-hHGdb5kU.mjs +132 -0
  26. package/dist/detectIsolation-CzoDCEnh.mjs +319 -0
  27. package/dist/envFlag-COOuJ3AH.mjs +11 -0
  28. package/dist/fileLock-BMPwCrB6.mjs +80 -0
  29. package/dist/{fleet-BHzlAvnu.mjs → fleet-DM_Q7w69.mjs} +85 -24
  30. package/dist/flushExit-C-i6SGjj.mjs +37 -0
  31. package/dist/friendlyName-1UZcyDhu.mjs +586 -0
  32. package/dist/{headlessCli-C2gvOpOt.mjs → headlessCli-C8HzQvis.mjs} +3 -21
  33. package/dist/hookSettings-DYMTUgVA.mjs +10399 -0
  34. package/dist/{httpServer-Be1Hcddr.mjs → httpServer-BzEDbOGn.mjs} +14 -5
  35. package/dist/hyphaClient-ybivOjZo.mjs +49 -0
  36. package/dist/index.mjs +40 -8
  37. package/dist/instance-CeHz5C8v.mjs +203 -0
  38. package/dist/kimiProvider-DbxODebR.mjs +69 -0
  39. package/dist/kimiSetup-NGsoYB5h.mjs +48 -0
  40. package/dist/loopVerify-B47sSjxe.mjs +444 -0
  41. package/dist/machineTools-DygM1jXW.mjs +580 -0
  42. package/dist/model-CUHojegn.mjs +66 -0
  43. package/dist/{notifyCommands-0aZUwKQK.mjs → notifyCommands-D-IKIxiq.mjs} +3 -18
  44. package/dist/package-DtuINqf5.mjs +64 -0
  45. package/dist/pinnedCodex-XW4qvOAe.mjs +11 -0
  46. package/dist/pinnedNono-5ZHb6328.mjs +15 -0
  47. package/dist/{rpc-rAQQ1q8t.mjs → rpc-BB6RF4-F.mjs} +38 -6
  48. package/dist/{rpc-B2Lc2BAB.mjs → rpc-Cf0grcru.mjs} +28 -20
  49. package/dist/{run-C7QVfyw4.mjs → run-ChdsgaSD.mjs} +17 -9
  50. package/dist/run-DkjwF-zA.mjs +9695 -0
  51. package/dist/sandboxDetect-Cdzsj5TC.mjs +19 -0
  52. package/dist/{scheduler-CzF4lOe_.mjs → scheduler-BY30ZrB9.mjs} +38 -6
  53. package/dist/securityContext-Cm5UTCuD.mjs +218 -0
  54. package/dist/serveAuth-DbVLRCRR.mjs +418 -0
  55. package/dist/{serveCommands-EIEqdaVu.mjs → serveCommands-CUHUiYnZ.mjs} +13 -34
  56. package/dist/sharingNotificationSync-qGIQ-3yf.mjs +359 -0
  57. package/dist/{sideband-BoutiRJi.mjs → sideband-68HhGT0i.mjs} +1 -21
  58. package/dist/store-Bn0ByYev.mjs +347 -0
  59. package/dist/store-fi0f-ff1.mjs +184 -0
  60. package/dist/types-57J3Re0n.mjs +17 -0
  61. package/dist/wantsHelp-6bMOeNUz.mjs +5 -0
  62. package/dist/wrapCommand-CdNawSaa.mjs +117 -0
  63. package/package.json +3 -3
  64. package/dist/cli-B24CmIli.mjs +0 -2780
  65. package/dist/package-CTbGYaJG.mjs +0 -64
  66. package/dist/run-CF4kAVPW.mjs +0 -26508
  67. package/dist/sandboxDetect-DNTcbgWD.mjs +0 -12
@@ -2,24 +2,19 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { execSync, execFileSync } from 'node:child_process';
3
3
  import { basename, resolve, join, isAbsolute } from 'node:path';
4
4
  import os from 'node:os';
5
- import { a5 as formatHandle, a6 as normalizeAllowedUser, a7 as loadSecurityContextConfig, a8 as resolveSecurityContext, a9 as buildSecurityContextFromFlags, aa as mergeSecurityContexts, c as connectToHypha, ab as buildSessionShareUrl, ac as computeOutboundHop, e as shortId, ad as registerAwaitingReply, ae as buildMachineShareUrl, af as parseHandle, ag as handleMatchesMetadata } from './run-CF4kAVPW.mjs';
6
- import 'os';
7
- import 'fs/promises';
5
+ import { c as connectToHypha } from './hyphaClient-ybivOjZo.mjs';
6
+ import { f as formatHandle, c as computeOutboundHop, s as shortId, r as registerAwaitingReply, p as parseHandle, h as handleMatchesMetadata } from './friendlyName-1UZcyDhu.mjs';
7
+ import { n as normalizeAllowedUser } from './types-57J3Re0n.mjs';
8
+ import { loadSecurityContextConfig, resolveSecurityContext, buildSecurityContextFromFlags, mergeSecurityContexts } from './securityContext-Cm5UTCuD.mjs';
9
+ import { b as buildSessionShareUrl, U as UNBOUNDED_LOOP_ITERATIONS, a as buildMachineShareUrl } from './loopVerify-B47sSjxe.mjs';
10
+ import { f as flushStdout } from './flushExit-C-i6SGjj.mjs';
11
+ import 'node:crypto';
12
+ import './instance-CeHz5C8v.mjs';
8
13
  import 'fs';
9
14
  import 'path';
10
- import 'url';
11
- import 'child_process';
12
- import 'crypto';
13
- import 'node:crypto';
14
- import 'util';
15
- import 'http';
16
- import 'net';
17
- import 'node:events';
18
- import '@agentclientprotocol/sdk';
19
- import 'node:util';
20
- import 'node:readline';
21
- import 'node:fs/promises';
22
- import 'yaml';
15
+ import 'os';
16
+ import './store-Bn0ByYev.mjs';
17
+ import './fileLock-BMPwCrB6.mjs';
23
18
 
24
19
  function formatTime(ts) {
25
20
  if (!ts) return "-";
@@ -88,6 +83,30 @@ function formatJson(data) {
88
83
  return JSON.stringify(data, null, 2);
89
84
  }
90
85
 
86
+ function machineLabelOf(machine, index) {
87
+ return String(
88
+ machine?.metadata?.displayName || machine?.metadata?.host || machine?.machineId || machine?.id || `machine #${index}`
89
+ );
90
+ }
91
+ function describeRejection(reason) {
92
+ if (reason instanceof Error) return reason.message || String(reason);
93
+ if (typeof reason === "string") return reason;
94
+ try {
95
+ const json = JSON.stringify(reason);
96
+ return typeof json === "string" ? json : String(reason);
97
+ } catch {
98
+ return String(reason);
99
+ }
100
+ }
101
+ function warnUnreachableMachines(unreachable, total) {
102
+ if (unreachable.length === 0) return false;
103
+ const detail = unreachable.map((u) => `${u.machine}: ${u.error}`).join("; ");
104
+ console.error(
105
+ `warning: ${unreachable.length} of ${total} machine(s) did not respond \u2014 this list is INCOMPLETE (${detail})`
106
+ );
107
+ return true;
108
+ }
109
+
91
110
  const SESSION_RPC_PARAMS = {
92
111
  getMessages: ["afterSeq", "limit"],
93
112
  getMessageCount: [],
@@ -395,13 +414,19 @@ async function connectAndGetAllMachines() {
395
414
  process.exit(1);
396
415
  }
397
416
  const machines = [];
417
+ const unreachableMachines = [];
398
418
  try {
399
419
  const services = await server.listServices({ query: { type: "svamp-machine" }, include_unlisted: true, _rkwargs: true });
400
420
  const results = await Promise.allSettled(
401
421
  services.map((svc) => server.getService(svc.id || svc.name))
402
422
  );
403
- for (const r of results) {
423
+ for (let i = 0; i < results.length; i++) {
424
+ const r = results[i];
404
425
  if (r.status === "fulfilled") machines.push(r.value);
426
+ else unreachableMachines.push({
427
+ machine: String(services[i]?.id || services[i]?.name || `#${i}`),
428
+ error: describeRejection(r.reason)
429
+ });
405
430
  }
406
431
  } catch (err) {
407
432
  restoreConsole();
@@ -415,7 +440,7 @@ async function connectAndGetAllMachines() {
415
440
  await server.disconnect();
416
441
  process.exit(1);
417
442
  }
418
- return { server, machines };
443
+ return { server, machines, unreachable: unreachableMachines };
419
444
  }
420
445
  async function sessionMachines() {
421
446
  loadDotEnv();
@@ -817,9 +842,9 @@ async function sessionList(machineId, opts) {
817
842
  await server.disconnect();
818
843
  }
819
844
  } else {
820
- const { server, machines } = await connectAndGetAllMachines();
845
+ const { server, machines, unreachable: discoveryUnreachable } = await connectAndGetAllMachines();
821
846
  try {
822
- await listSessionsFromMachines(server, machines, opts);
847
+ await listSessionsFromMachines(server, machines, opts, discoveryUnreachable);
823
848
  } finally {
824
849
  await server.disconnect();
825
850
  }
@@ -837,7 +862,7 @@ function formatPeerLine(s) {
837
862
  }
838
863
  async function sessionWhoami(opts) {
839
864
  const currentSessionId = process.env.SVAMP_SESSION_ID;
840
- const { server, machines } = await connectAndGetAllMachines();
865
+ const { server, machines, unreachable } = await connectAndGetAllMachines();
841
866
  try {
842
867
  const perMachine = await Promise.allSettled(
843
868
  machines.map(async (machine) => {
@@ -849,6 +874,17 @@ async function sessionWhoami(opts) {
849
874
  })
850
875
  );
851
876
  const gathered = perMachine.filter((r) => r.status === "fulfilled").map((r) => r.value);
877
+ const whoamiUnreachable = [...unreachable];
878
+ for (let i = 0; i < perMachine.length; i++) {
879
+ const r = perMachine[i];
880
+ if (r.status === "rejected") {
881
+ whoamiUnreachable.push({
882
+ machine: machineLabelOf(machines[i], i),
883
+ error: describeRejection(r.reason)
884
+ });
885
+ }
886
+ }
887
+ warnUnreachableMachines(whoamiUnreachable, machines.length + unreachable.length);
852
888
  const machineLabel = (info) => info?.metadata?.displayName || info?.metadata?.host || info?.metadata?.hostname || info?.machineId || "unknown";
853
889
  let current = null;
854
890
  let currentSession = null;
@@ -951,7 +987,7 @@ async function sessionWhoami(opts) {
951
987
  await server.disconnect();
952
988
  }
953
989
  }
954
- async function listSessionsFromMachines(_server, machines, opts) {
990
+ async function listSessionsFromMachines(_server, machines, opts, discoveryUnreachable = []) {
955
991
  const allSessions = [];
956
992
  const machineResults = await Promise.allSettled(
957
993
  machines.map(async (machine) => {
@@ -966,11 +1002,18 @@ async function listSessionsFromMachines(_server, machines, opts) {
966
1002
  return sessions;
967
1003
  })
968
1004
  );
969
- for (const r of machineResults) {
1005
+ const unreachable = [...discoveryUnreachable];
1006
+ for (let i = 0; i < machineResults.length; i++) {
1007
+ const r = machineResults[i];
970
1008
  if (r.status === "fulfilled") allSessions.push(...r.value);
1009
+ else unreachable.push({
1010
+ machine: machineLabelOf(machines[i], i),
1011
+ error: describeRejection(r.reason)
1012
+ });
971
1013
  }
972
1014
  const filtered = opts?.active ? allSessions.filter((s) => s.active) : allSessions;
973
1015
  if (filtered.length === 0) {
1016
+ warnUnreachableMachines(unreachable, machines.length + discoveryUnreachable.length);
974
1017
  if (opts?.json) {
975
1018
  console.log(formatJson([]));
976
1019
  } else {
@@ -989,6 +1032,7 @@ async function listSessionsFromMachines(_server, machines, opts) {
989
1032
  host: m.host || s.machineHost || ""
990
1033
  };
991
1034
  });
1035
+ warnUnreachableMachines(unreachable, machines.length + discoveryUnreachable.length);
992
1036
  if (opts?.json) {
993
1037
  console.log(formatJson(enriched.map((s) => ({
994
1038
  sessionId: s.sessionId,
@@ -1724,11 +1768,13 @@ async function sendCore(machine, fullId, message, opts) {
1724
1768
  }
1725
1769
  if (opts?.asIssue) {
1726
1770
  const issue = await machine.sessionRPC(fullId, "issue", {
1727
- op: "add",
1728
- body: message,
1729
- session: fullId,
1730
- rekick: true,
1731
- ...opts.issueTitle ? { title: opts.issueTitle } : {}
1771
+ params: {
1772
+ op: "add",
1773
+ body: message,
1774
+ session: fullId,
1775
+ rekick: true,
1776
+ ...opts.issueTitle ? { title: opts.issueTitle } : {}
1777
+ }
1732
1778
  });
1733
1779
  return {
1734
1780
  sessionId: fullId,
@@ -1744,9 +1790,11 @@ async function sendCore(machine, fullId, message, opts) {
1744
1790
  const shouldWait = !!opts?.wait || wantResponse;
1745
1791
  if (opts?.plain) {
1746
1792
  const { randomUUID: ruuid } = await import('node:crypto');
1793
+ let plainBypassEnsured = false;
1747
1794
  if (shouldWait && !opts?.requireApproval) {
1748
1795
  try {
1749
1796
  await machine.sessionRPC(fullId, "switchMode", { mode: "bypassPermissions" });
1797
+ plainBypassEnsured = true;
1750
1798
  } catch {
1751
1799
  }
1752
1800
  }
@@ -1757,7 +1805,7 @@ async function sendCore(machine, fullId, message, opts) {
1757
1805
  let pWait;
1758
1806
  if (shouldWait) pWait = await waitForBusyThenIdle(machine, fullId, (opts?.timeout || 300) * 1e3);
1759
1807
  if (pWait?.pendingPermissions?.length) {
1760
- return { sessionId: fullId, mode: "send", sent: true, messageId: sendRes?.id, waited: true, status: "permission-pending", pendingPermissions: pWait.pendingPermissions };
1808
+ return { sessionId: fullId, mode: "send", sent: true, messageId: sendRes?.id, waited: true, status: "permission-pending", pendingPermissions: pWait.pendingPermissions, ...plainBypassEnsured ? { bypassEnsured: true } : {} };
1761
1809
  }
1762
1810
  let pResp;
1763
1811
  if (wantResponse) pResp = await collectAssistantResponse(machine, fullId, preSeq2);
@@ -1768,14 +1816,17 @@ async function sendCore(machine, fullId, message, opts) {
1768
1816
  messageId: sendRes?.id,
1769
1817
  waited: !!shouldWait,
1770
1818
  status: shouldWait ? "idle" : "sent",
1771
- ...wantResponse && pResp ? { response: pResp.text, responseSeqs: pResp.messageSeqs } : {}
1819
+ ...wantResponse && pResp ? { response: pResp.text, responseSeqs: pResp.messageSeqs } : {},
1820
+ ...plainBypassEnsured ? { bypassEnsured: true } : {}
1772
1821
  };
1773
1822
  }
1774
1823
  if (opts?.model) {
1775
1824
  const { randomUUID: ruuid } = await import('node:crypto');
1825
+ let modelBypassEnsured = false;
1776
1826
  if (shouldWait && !opts?.requireApproval) {
1777
1827
  try {
1778
1828
  await machine.sessionRPC(fullId, "switchMode", { mode: "bypassPermissions" });
1829
+ modelBypassEnsured = true;
1779
1830
  } catch {
1780
1831
  }
1781
1832
  }
@@ -1803,7 +1854,8 @@ async function sendCore(machine, fullId, message, opts) {
1803
1854
  messageId: sendRes?.id,
1804
1855
  waited: true,
1805
1856
  status: "permission-pending",
1806
- pendingPermissions: mWait.pendingPermissions
1857
+ pendingPermissions: mWait.pendingPermissions,
1858
+ ...modelBypassEnsured ? { bypassEnsured: true } : {}
1807
1859
  };
1808
1860
  }
1809
1861
  let mResponse;
@@ -1817,7 +1869,8 @@ async function sendCore(machine, fullId, message, opts) {
1817
1869
  messageId: sendRes?.id,
1818
1870
  waited: shouldWait,
1819
1871
  status: shouldWait ? "idle" : "sent",
1820
- ...wantResponse && mResponse ? { response: mResponse.text, responseSeqs: mResponse.messageSeqs } : {}
1872
+ ...wantResponse && mResponse ? { response: mResponse.text, responseSeqs: mResponse.messageSeqs } : {},
1873
+ ...modelBypassEnsured ? { bypassEnsured: true } : {}
1821
1874
  };
1822
1875
  }
1823
1876
  let bypassEnsured = false;
@@ -2392,6 +2445,7 @@ async function wiseAskCli(machineId, message, sessionId, opts) {
2392
2445
  const res = await machine.wiseAsk({ message, sessionId });
2393
2446
  if (opts?.json) {
2394
2447
  console.log(JSON.stringify(res, null, 2));
2448
+ await flushStdout();
2395
2449
  process.exit(res?.success ? 0 : 1);
2396
2450
  }
2397
2451
  if (res?.error) {
@@ -2419,6 +2473,7 @@ async function wiseJoinMeetingCli(machineId, url, sessionId, opts) {
2419
2473
  const res = await machine.wiseJoinMeeting({ meetingUrl: url, sessionId, mode, mission: opts?.mission });
2420
2474
  if (opts?.json) {
2421
2475
  console.log(JSON.stringify(res, null, 2));
2476
+ await flushStdout();
2422
2477
  process.exit(res?.success ? 0 : 1);
2423
2478
  }
2424
2479
  if (res?.error) {
@@ -2437,6 +2492,7 @@ async function wiseLeaveMeetingCli(machineId, sessionId, opts) {
2437
2492
  const res = await machine.wiseLeaveMeeting({ sessionId });
2438
2493
  if (opts?.json) {
2439
2494
  console.log(JSON.stringify(res, null, 2));
2495
+ await flushStdout();
2440
2496
  process.exit(res?.success ? 0 : 1);
2441
2497
  }
2442
2498
  if (res?.error) {
@@ -2459,6 +2515,7 @@ async function wiseAnnounceCli(machineId, text, sessionId, opts) {
2459
2515
  const res = await machine.wiseAnnounce({ text, sessionId });
2460
2516
  if (opts?.json) {
2461
2517
  console.log(JSON.stringify(res, null, 2));
2518
+ await flushStdout();
2462
2519
  process.exit(res?.success ? 0 : 1);
2463
2520
  }
2464
2521
  if (res?.error) {
@@ -2477,6 +2534,7 @@ async function wiseMeetingsCli(machineId, opts) {
2477
2534
  const res = await machine.wiseMeetingStatus({});
2478
2535
  if (opts?.json) {
2479
2536
  console.log(JSON.stringify(res, null, 2));
2537
+ await flushStdout();
2480
2538
  process.exit(0);
2481
2539
  }
2482
2540
  const ms = res?.meetings || [];
@@ -2536,8 +2594,7 @@ async function sessionLoopStart(sessionIdPartial, task, machineId, opts) {
2536
2594
  const svc = getSessionProxy(machine, fullId);
2537
2595
  const until = opts?.until || opts?.criteria;
2538
2596
  const isStart = !!(task || until);
2539
- const maxIterations = opts?.maxIterations ?? (isStart ? 1e4 : void 0);
2540
- const evaluator = opts?.agent ? true : opts?.evaluator !== false;
2597
+ const maxIterations = opts?.maxIterations ?? (isStart ? UNBOUNDED_LOOP_ITERATIONS : void 0);
2541
2598
  const budget = opts?.maxTokensPerHour || opts?.maxRuntimeSec ? {
2542
2599
  ...opts?.maxTokensPerHour ? { max_tokens_per_hour: opts.maxTokensPerHour } : {},
2543
2600
  ...opts?.maxRuntimeSec ? { max_runtime_sec: opts.maxRuntimeSec } : {}
@@ -2547,11 +2604,15 @@ async function sessionLoopStart(sessionIdPartial, task, machineId, opts) {
2547
2604
  ...task ? { task } : {},
2548
2605
  ...until ? { until } : {},
2549
2606
  ...opts?.oracle ? { oracle: opts.oracle } : {},
2550
- ...opts?.parent ? { parent: opts.parent } : {},
2551
2607
  ...maxIterations != null ? { max_iterations: maxIterations } : {},
2552
- ...budget ? { budget } : {},
2553
- ...opts?.engine ? { engine: opts.engine } : {},
2554
- evaluator
2608
+ ...budget ? { budget } : {}
2609
+ // #1499: `parent`, `engine` and `evaluator` are no longer sent. The /goal kickoff in
2610
+ // daemon/run.ts reads only task/until/oracle/max_iterations/budget/durable, so these
2611
+ // three travelled the whole RPC and were dropped — while the CLI echoed them back as
2612
+ // if applied. Sending a field nobody reads is how a flag becomes documented as a
2613
+ // control (#1415 was the same shape one command over). The legacy `supervisor` key's
2614
+ // normalizer still accepts `parent`/`evaluator` for back-compat; that path is
2615
+ // untouched.
2555
2616
  }
2556
2617
  });
2557
2618
  if (!isStart) {
@@ -2561,9 +2622,10 @@ async function sessionLoopStart(sessionIdPartial, task, machineId, opts) {
2561
2622
  if (task) console.log(` Task: ${task.slice(0, 100)}${task.length > 100 ? "..." : ""}`);
2562
2623
  if (until) console.log(` Until: ${until.slice(0, 100)}${until.length > 100 ? "..." : ""}`);
2563
2624
  console.log(` Oracle: ${opts?.oracle || "(none)"}`);
2564
- console.log(` Evaluator: ${evaluator ? "on" : "off"}`);
2565
- if (opts?.parent) console.log(` Parent review: ${opts.parent.slice(0, 8)}`);
2566
- if (maxIterations != null) console.log(` Max iterations: ${maxIterations}`);
2625
+ console.log(` Evaluator: on`);
2626
+ if (maxIterations != null) {
2627
+ console.log(maxIterations >= UNBOUNDED_LOOP_ITERATIONS ? ` Max iterations: unbounded (no iteration cap \u2014 cost/runtime ceilings only)` : ` Max iterations: ${maxIterations}`);
2628
+ }
2567
2629
  if (!task) console.log(` (hot-plug \u2014 gating the session's current work)`);
2568
2630
  }
2569
2631
  } finally {
@@ -1,27 +1,13 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { f as resolveProjectRoot, L as workflowSteps, y as setWorkflowEnabled, F as isWorkflowEnabled, z as removeWorkflow, w as getWorkflow, E as listWorkflows, A as validateCronExpr, C as saveWorkflow, D as rawWorkflow, M as describeNextFire } from './run-CF4kAVPW.mjs';
3
- import { w as wantsHelp } from './cli-B24CmIli.mjs';
4
- import 'os';
5
- import 'fs/promises';
6
- import 'fs';
7
- import 'path';
8
- import 'url';
9
- import 'child_process';
10
- import 'crypto';
1
+ import { r as resolveProjectRoot } from './store-Bn0ByYev.mjs';
2
+ import { w as wantsHelp } from './wantsHelp-6bMOeNUz.mjs';
3
+ import { s as setWorkflowEnabled, i as isWorkflowEnabled, r as removeWorkflow, g as getWorkflow, l as listWorkflows, c as workflowSteps, a as saveWorkflow, b as rawWorkflow } from './store-fi0f-ff1.mjs';
4
+ import { v as validateCronExpr, d as describeNextFire } from './cron-hHGdb5kU.mjs';
11
5
  import 'node:fs';
12
6
  import 'node:path';
13
7
  import 'node:crypto';
14
- import 'util';
15
- import 'http';
16
- import 'net';
17
- import 'node:os';
18
- import 'node:events';
19
- import '@agentclientprotocol/sdk';
20
- import 'node:util';
21
- import 'node:readline';
22
- import 'node:fs/promises';
8
+ import 'node:child_process';
9
+ import './fileLock-BMPwCrB6.mjs';
23
10
  import 'yaml';
24
- import './serviceManager-hlOVxkhW.mjs';
25
11
 
26
12
  function flag(args, name) {
27
13
  const i = args.indexOf(name);
@@ -161,16 +147,20 @@ async function workflowCommand(args) {
161
147
  console.error(`Workflow not found: ${name}`);
162
148
  process.exit(1);
163
149
  }
164
- const steps = workflowSteps(wf);
165
- console.log(`\u25B6 running workflow "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"})`);
166
- for (let i = 0; i < steps.length; i++) {
167
- const step = steps[i];
168
- console.log(` [${i + 1}/${steps.length}] $ ${step.run}`);
169
- const r = spawnSync("sh", ["-c", step.run], { cwd: root, stdio: "inherit" });
170
- if (r.status !== 0) {
171
- console.error(` \u2717 step ${i + 1} failed (exit ${r.status ?? "signal"}). Stopping.`);
172
- process.exit(r.status ?? 1);
173
- }
150
+ const { runWorkflow } = await import('./run-DkjwF-zA.mjs').then(function (n) { return n.e; });
151
+ const run = await runWorkflow(root, wf, { trigger: "manual", actor: process.env.SVAMP_SESSION_ID || null });
152
+ console.log(`\u25B6 ran workflow "${wf.name}" (${run.steps.length} step${run.steps.length === 1 ? "" : "s"}) \u2192 ${run.status}`);
153
+ for (const st of run.steps) {
154
+ console.log(` [${st.index + 1}] $ ${st.cmd}`);
155
+ if (st.stdout) console.log(st.stdout.trimEnd());
156
+ if (st.stderr) console.error(st.stderr.trimEnd());
157
+ if (st.timedOut) console.error(` \u2717 step ${st.index + 1} timed out.`);
158
+ else if (st.exitCode !== 0) console.error(` \u2717 step ${st.index + 1} failed (exit ${st.exitCode ?? "signal"}).`);
159
+ }
160
+ if (run.escalatedIssue) console.log(` \u21B3 escalated to issue #${run.escalatedIssue} (agent will correct the workflow).`);
161
+ if (run.status !== "success") {
162
+ console.error(`\u2717 workflow "${wf.name}" failed.`);
163
+ process.exit(1);
174
164
  }
175
165
  console.log(`\u2713 workflow "${wf.name}" completed.`);
176
166
  break;
@@ -1,25 +1,8 @@
1
1
  import os from 'os';
2
2
  import fs__default from 'fs';
3
3
  import { resolve, join, relative } from 'path';
4
- import { W as parseFrontmatter, X as getSkillsServer, Y as getSkillsWorkspaceName, Z as getSkillsCollectionName, _ as fetchWithTimeout, $ as searchSkills, a0 as SKILLS_DIR, a1 as getSkillInfo, a2 as downloadSkillFile, a3 as listSkillFiles } from './run-CF4kAVPW.mjs';
5
- import 'fs/promises';
6
- import 'url';
7
- import 'child_process';
8
- import 'crypto';
9
- import 'node:fs';
10
- import 'node:path';
11
- import 'node:crypto';
12
- import 'node:child_process';
13
- import 'util';
14
- import 'http';
15
- import 'net';
16
- import 'node:os';
17
- import 'node:events';
18
- import '@agentclientprotocol/sdk';
19
- import 'node:util';
20
- import 'node:readline';
21
- import 'node:fs/promises';
22
- import 'yaml';
4
+ import { parseFrontmatter, getSkillsServer, getSkillsWorkspaceName, getSkillsCollectionName, fetchWithTimeout, searchSkills, SKILLS_DIR, getSkillInfo, downloadSkillFile, listSkillFiles } from './api-BHjyC0Ph.mjs';
5
+ import './instance-CeHz5C8v.mjs';
23
6
 
24
7
  const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
25
8
  const ENV_FILE = join(SVAMP_HOME, ".env");
@@ -1,27 +1,10 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { f as flushAndExit } from './cli-B24CmIli.mjs';
4
- import { f as resolveProjectRoot, o as searchIssues, m as listIssues, n as isPendingIssue, j as resumeIssue, p as pauseIssue, k as addComment, u as updateIssue, h as getIssue, J as checkVerifyCommand, q as isVisibleTo, K as summarize, l as addIssue } from './run-CF4kAVPW.mjs';
5
- import './serviceManager-hlOVxkhW.mjs';
6
- import 'os';
7
- import 'fs/promises';
8
- import 'fs';
9
- import 'path';
10
- import 'url';
11
- import 'child_process';
12
- import 'crypto';
3
+ import { a as flushAndExit } from './flushExit-C-i6SGjj.mjs';
4
+ import { r as resolveProjectRoot, s as searchIssues, l as listIssues, i as isPendingIssue, d as resumeIssue, e as pauseIssue, f as addComment, u as updateIssue, p as parseScopeArg, I as ISSUE_SCOPES, a as parseStatusArg, b as ISSUE_STATUSES, g as getIssue, k as checkVerifyCommand, j as isVisibleTo, m as summarize, h as addIssue } from './store-Bn0ByYev.mjs';
13
5
  import 'node:crypto';
14
6
  import 'node:child_process';
15
- import 'util';
16
- import 'http';
17
- import 'net';
18
- import 'node:os';
19
- import 'node:events';
20
- import '@agentclientprotocol/sdk';
21
- import 'node:util';
22
- import 'node:readline';
23
- import 'node:fs/promises';
24
- import 'yaml';
7
+ import './fileLock-BMPwCrB6.mjs';
25
8
 
26
9
  const STATUS_GLYPH = {
27
10
  ready: "\u25C9",
@@ -64,12 +47,27 @@ function loopActiveForCwd(cwd = process.cwd(), sid = process.env.SVAMP_SESSION_I
64
47
  }
65
48
  return false;
66
49
  }
50
+ const VALUE_FLAGS = /* @__PURE__ */ new Set([
51
+ "--answer",
52
+ "--blocked",
53
+ "--body",
54
+ "--branch",
55
+ "--label",
56
+ "--option",
57
+ "--question",
58
+ "--scope",
59
+ "--session",
60
+ "--status",
61
+ "--title",
62
+ "--verify",
63
+ "--verify-cmd"
64
+ ]);
67
65
  function positional(args) {
68
66
  const out = [];
69
67
  for (let i = 0; i < args.length; i++) {
70
68
  const a = args[i];
71
69
  if (a.startsWith("--")) {
72
- if (a !== "--json" && a !== "--ready") i++;
70
+ if (!a.includes("=") && VALUE_FLAGS.has(a)) i++;
73
71
  continue;
74
72
  }
75
73
  out.push(a);
@@ -272,11 +270,44 @@ ${res.output || ""}
272
270
  if (labels.length) patch.labels = labels;
273
271
  const v = buildVerify(rest);
274
272
  if (v || has(rest, "--no-verify")) patch.verify = has(rest, "--no-verify") ? null : v;
275
- if (flag(rest, "--scope")) patch.scope = flag(rest, "--scope");
273
+ if (flag(rest, "--scope")) {
274
+ const nextScope = parseScopeArg(flag(rest, "--scope"));
275
+ if (!nextScope) {
276
+ console.error(`Invalid --scope "${flag(rest, "--scope")}". Must be one of: ${ISSUE_SCOPES.join(", ")}.`);
277
+ process.exit(1);
278
+ }
279
+ patch.scope = nextScope;
280
+ }
276
281
  if (has(rest, "--unclaim")) patch.session = null;
277
282
  else if (flag(rest, "--session")) patch.session = flag(rest, "--session");
278
283
  if (flag(rest, "--body")) patch.body = flag(rest, "--body");
279
- if (flag(rest, "--status")) patch.status = flag(rest, "--status");
284
+ if (flag(rest, "--status")) {
285
+ const nextStatus = parseStatusArg(flag(rest, "--status"));
286
+ if (!nextStatus) {
287
+ console.error(`Invalid --status "${flag(rest, "--status")}". Must be one of: ${ISSUE_STATUSES.join(", ")}.`);
288
+ console.error(`(To close an issue, use \`svamp issue close ${id}\` \u2014 it runs the verify-cmd.)`);
289
+ process.exit(1);
290
+ }
291
+ if (nextStatus === "archived") {
292
+ const current = getIssue(root, id);
293
+ const vc = current?.verify?.type === "command" ? current.verify.text?.trim() : "";
294
+ if (vc && current?.status !== "archived") {
295
+ if (has(rest, "--force")) {
296
+ console.error(`\u26A0 #${id}: archiving WITHOUT running verify-cmd (--force): \`${vc}\``);
297
+ } else {
298
+ const res = checkVerifyCommand(root, current);
299
+ if (!res.ok) {
300
+ console.error(`Refusing to archive #${id} via edit: its verify-cmd failed \u2014 the fix is not verified.
301
+ $ ${res.cmd}
302
+ ${res.output || ""}
303
+ (Use \`svamp issue archive\` for an obsolete/duplicate item, or pass --force to override.)`);
304
+ process.exit(1);
305
+ }
306
+ }
307
+ }
308
+ }
309
+ patch.status = nextStatus;
310
+ }
280
311
  if (has(rest, "--crew")) patch.disposition = "crew";
281
312
  else if (has(rest, "--inline")) patch.disposition = "inline";
282
313
  if (has(rest, "--triaged")) patch.triaged = true;
@@ -291,7 +322,7 @@ ${res.output || ""}
291
322
  case "triage": {
292
323
  const id = positional(rest)[0];
293
324
  if (!id) {
294
- console.error('usage: svamp issue triage <id> [--title "\u2026"] [--label x \u2026] [--crew|--inline] [--verify-cmd "cmd" | --verify "criterion" | --manual] [--body "rewritten"] [--backlog]');
325
+ console.error('usage: svamp issue triage <id> [--title "\u2026"] [--label x \u2026] [--crew|--inline] [--verify-cmd "cmd" | --verify "criterion" | --manual] [--body "rewritten"]');
295
326
  process.exit(1);
296
327
  }
297
328
  const patch = { triaged: true };
@@ -497,7 +528,8 @@ the user explicitly reserved): re-run with \`--blocked "<the specific blocker>"\
497
528
  " # A paused issue drops out of `pending`, so a loop converges cleanly instead",
498
529
  ' # of spinning on it. NOT for "please check my work" \u2014 close finished work.',
499
530
  ' resume <id> [--answer "\u2026"] # un-pause (the user answering a --question resumes it automatically)',
500
- " pending [--session <id>] [--mine] # exit 0 if no actionable (ready/in_progress) issues \u2014 the loop oracle",
531
+ " pending [--session <id>] [--mine] # exit 0 when NO issue is open \u2014 i.e. every issue is",
532
+ " # archived or paused. Counted by EXCLUSION, not an allow-list (#107). The loop oracle.",
501
533
  ' search "<query>" [--json]',
502
534
  " guide <triage|work> # the triage / work-loop procedure (so triggers can stay short)"
503
535
  ].join("\n"));
@@ -508,4 +540,4 @@ the user explicitly reserved): re-run with \`--blocked "<the specific blocker>"\
508
540
  }
509
541
  }
510
542
 
511
- export { issueCommand, loopActiveForCwd };
543
+ export { VALUE_FLAGS, issueCommand, loopActiveForCwd, positional };