svamp-cli 0.2.200 → 0.2.202

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 (26) hide show
  1. package/dist/{agentCommands-BLig9RpJ.mjs → agentCommands-BMbdp3lO.mjs} +5 -5
  2. package/dist/{auth-BFDgK8NY.mjs → auth-DFV_MjVU.mjs} +1 -1
  3. package/dist/cli.mjs +60 -60
  4. package/dist/{commands-2qJ_Bh8F.mjs → commands-BA8pUB80.mjs} +2 -2
  5. package/dist/{commands-DgCf4FCQ.mjs → commands-CVMpx7Ws.mjs} +5 -5
  6. package/dist/{commands-C0NGT-PG.mjs → commands-CW1VrEei.mjs} +2 -2
  7. package/dist/{commands-NKOF_jF-.mjs → commands-Cbg4_aEA.mjs} +2 -2
  8. package/dist/{commands-C03E7eP5.mjs → commands-Ccbl9q_M.mjs} +44 -2
  9. package/dist/{commands-CrOYWa85.mjs → commands-DfD7ACo-.mjs} +1 -1
  10. package/dist/{commands-DRI2MMHg.mjs → commands-DnTtqcre.mjs} +1 -1
  11. package/dist/{fleet-CaFacVAt.mjs → fleet-Caxg-9CC.mjs} +1 -1
  12. package/dist/{frpc-gMUAwe3q.mjs → frpc-Sq_r6a9i.mjs} +1 -1
  13. package/dist/{headlessCli-DxAlTlhs.mjs → headlessCli-CqDPtg1x.mjs} +2 -2
  14. package/dist/index.mjs +1 -1
  15. package/dist/{package-BNVXH7XA.mjs → package-Df28hcfX.mjs} +2 -2
  16. package/dist/{rpc-GTsR01jv.mjs → rpc-BJKoRzGK.mjs} +24 -19
  17. package/dist/{rpc-_aPtyAzL.mjs → rpc-DXp0vpxD.mjs} +13 -1
  18. package/dist/{run-DyqabMH2.mjs → run-B5xwuwIO.mjs} +1 -1
  19. package/dist/{run-DsGZVxkK.mjs → run-CsqoYIvO.mjs} +34 -13
  20. package/dist/runStore-CtptN7US.mjs +168 -0
  21. package/dist/{scheduler-9mJf0_7T.mjs → scheduler-CSYBbqjZ.mjs} +23 -17
  22. package/dist/{serveCommands-CrjiFbbs.mjs → serveCommands-CHWW6Mon.mjs} +5 -5
  23. package/dist/{serveManager-CtbAmKJ7.mjs → serveManager-CkEjrt25.mjs} +2 -2
  24. package/dist/{sideband-5D9B_PyP.mjs → sideband-BXQYf8dr.mjs} +1 -1
  25. package/dist/{store-DEZ8e-uE.mjs → store-BTs0H_y0.mjs} +1 -1
  26. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { execSync } from 'node:child_process';
2
- import { m as resolveProjectRoot, t as searchIssues, q as listIssues, o as addComment, u as updateIssue, n as getIssue, v as isVisibleTo, x as summarize, p as addIssue } from './run-DsGZVxkK.mjs';
2
+ import { m as resolveProjectRoot, w as searchIssues, v as listIssues, o as resumeIssue, p as pauseIssue, q as addComment, u as updateIssue, n as getIssue, x as isVisibleTo, z as summarize, t as addIssue } from './run-CsqoYIvO.mjs';
3
3
  import 'os';
4
4
  import 'fs/promises';
5
5
  import 'fs';
@@ -24,8 +24,14 @@ import 'node:util';
24
24
  const STATUS_GLYPH = {
25
25
  ready: "\u25C9",
26
26
  in_progress: "\u25D0",
27
+ paused: "\u23F8",
27
28
  archived: "\u25A3"
28
29
  };
30
+ function allFlags(args, name) {
31
+ const out = [];
32
+ for (let i = 0; i < args.length; i++) if (args[i] === name && i + 1 < args.length) out.push(args[++i]);
33
+ return out;
34
+ }
29
35
  function flag(args, name) {
30
36
  const i = args.indexOf(name);
31
37
  return i !== -1 && i + 1 < args.length ? args[i + 1] : void 0;
@@ -293,6 +299,37 @@ ${tail}
293
299
  ok(updated, `Commented on #${updated.id}`);
294
300
  break;
295
301
  }
302
+ case "pause": {
303
+ const id = positional(rest)[0];
304
+ if (!id) {
305
+ console.error('usage: svamp issue pause <id> [--question "\u2026"] [--option "A" --option "B"]');
306
+ process.exit(1);
307
+ }
308
+ const question = flag(rest, "--question");
309
+ const options = allFlags(rest, "--option");
310
+ const updated = pauseIssue(root, id, question ? { text: question, options } : void 0);
311
+ if (!updated) {
312
+ console.error(`Issue not found: ${id}`);
313
+ process.exit(1);
314
+ }
315
+ ok(updated, `Paused #${updated.id}${question ? ` \u2014 asked: ${question}` : ""}`);
316
+ break;
317
+ }
318
+ case "resume": {
319
+ const id = positional(rest)[0];
320
+ if (!id) {
321
+ console.error('usage: svamp issue resume <id> [--answer "\u2026"]');
322
+ process.exit(1);
323
+ }
324
+ const answer = flag(rest, "--answer") || positional(rest)[1];
325
+ const updated = resumeIssue(root, id, answer);
326
+ if (!updated) {
327
+ console.error(`Issue not found: ${id}`);
328
+ process.exit(1);
329
+ }
330
+ ok(updated, `Resumed #${updated.id}`);
331
+ break;
332
+ }
296
333
  case "pending": {
297
334
  const mine = flag(rest, "--session") || (has(rest, "--mine") ? sessionId : null);
298
335
  const inScope = (i) => !mine || isVisibleTo(i, mine);
@@ -361,7 +398,12 @@ ${tail}
361
398
  " NEVER close an issue that isn't genuinely resolved.",
362
399
  " CONVERGE TO MAIN: if an issue used an isolated branch/worktree, merge it back to `main` (and remove",
363
400
  " the worktree) BEFORE closing \u2014 never leave unmerged branches.",
364
- " Keep going until `svamp issue pending --session <id>` is empty."
401
+ " BLOCKED ON THE USER? Do NOT churn. PAUSE the issue with the question (and options, if any):",
402
+ ' svamp issue pause <id> --question "\u2026" [--option "A" --option "B"]',
403
+ " A paused issue is EXCLUDED from `pending`, so the loop can STOP cleanly instead of re-running on",
404
+ " something only the user can unblock. The user answers (the app renders the options as buttons) \u2192",
405
+ ' the issue resumes (`svamp issue resume <id> [--answer "\u2026"]`) and you pick it up again.',
406
+ " Keep going until `svamp issue pending --session <id>` is empty (paused issues don't count)."
365
407
  ].join("\n"));
366
408
  } else {
367
409
  out("usage: svamp issue guide <triage|work>");
@@ -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 { D as parseFrontmatter, E as getSkillsServer, F as getSkillsWorkspaceName, G as getSkillsCollectionName, H as fetchWithTimeout, I as searchSkills, J as SKILLS_DIR, K as getSkillInfo, L as downloadSkillFile, M as listSkillFiles } from './run-DsGZVxkK.mjs';
4
+ import { F as parseFrontmatter, G as getSkillsServer, H as getSkillsWorkspaceName, I as getSkillsCollectionName, J as fetchWithTimeout, K as searchSkills, L as SKILLS_DIR, M as getSkillInfo, N as downloadSkillFile, O as listSkillFiles } from './run-CsqoYIvO.mjs';
5
5
  import 'fs/promises';
6
6
  import 'url';
7
7
  import 'child_process';
@@ -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 { O as formatHandle, P as normalizeAllowedUser, Q as loadSecurityContextConfig, T as resolveSecurityContext, U as buildSecurityContextFromFlags, V as mergeSecurityContexts, c as connectToHypha, W as buildSessionShareUrl, X as computeOutboundHop, y as shortId, Y as buildMachineShareUrl, Z as parseHandle, _ as handleMatchesMetadata } from './run-DsGZVxkK.mjs';
5
+ import { Q as formatHandle, T as normalizeAllowedUser, U as loadSecurityContextConfig, V as resolveSecurityContext, W as buildSecurityContextFromFlags, X as mergeSecurityContexts, c as connectToHypha, Y as buildSessionShareUrl, Z as computeOutboundHop, A as shortId, _ as buildMachineShareUrl, $ as parseHandle, a0 as handleMatchesMetadata } from './run-CsqoYIvO.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -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-DsGZVxkK.mjs';
4
+ import { c as connectToHypha } from './run-CsqoYIvO.mjs';
5
5
  import { PINNED_CLAUDE_CODE_VERSION } from './pinnedClaudeCode-HydRNEt7.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
@@ -4,7 +4,7 @@ import { mkdirSync, writeFileSync, unlinkSync, existsSync, chmodSync, readFileSy
4
4
  import { join } from 'path';
5
5
  import { homedir, platform, arch } from 'os';
6
6
  import { randomUUID, createHash } from 'crypto';
7
- import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-DsGZVxkK.mjs';
7
+ import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-CsqoYIvO.mjs';
8
8
  import 'fs/promises';
9
9
  import 'url';
10
10
  import 'node:crypto';
@@ -1,5 +1,5 @@
1
- import { N as resolveModel, $ as describeMisconfiguration, a0 as buildMachineDeps } from './run-DsGZVxkK.mjs';
2
- import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-5D9B_PyP.mjs';
1
+ import { P as resolveModel, a1 as describeMisconfiguration, a2 as buildMachineDeps } from './run-CsqoYIvO.mjs';
2
+ import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-BXQYf8dr.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-DsGZVxkK.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-CsqoYIvO.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.200";
2
+ var version = "0.2.202";
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";
@@ -19,7 +19,7 @@ var exports$1 = {
19
19
  var scripts = {
20
20
  build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/loop bin/skills/loop && cp -r ../../skills/crew bin/skills/crew && tsc --noEmit && pkgroll",
21
21
  typecheck: "tsc --noEmit",
22
- test: "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-sharing-notify-sync.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-loop-activation.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-btw-proxy-env.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox-store.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-issue-rpc.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-workflow-rpc.mjs && npx tsx test/test-workflow-scheduler.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-hotreload-seam.mjs && npx tsx test/test-hot-reload.mjs && npx tsx test/test-hot-reload-live.mjs && npx tsx test/test-session-core.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-channel-upload.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs && npx tsx test/test-crew-standalone.mjs",
22
+ test: "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-sharing-notify-sync.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-loop-activation.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-btw-proxy-env.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox-store.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-issue-rpc.mjs && npx tsx test/test-issue-pause.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-workflow-rpc.mjs && npx tsx test/test-workflow-scheduler.mjs && npx tsx test/test-workflow-runs.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-hotreload-seam.mjs && npx tsx test/test-hot-reload.mjs && npx tsx test/test-hot-reload-live.mjs && npx tsx test/test-session-core.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-channel-upload.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs && npx tsx test/test-crew-standalone.mjs",
23
23
  "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
24
24
  dev: "tsx src/cli.ts",
25
25
  "dev:daemon": "tsx src/cli.ts daemon start-sync",
@@ -1,6 +1,6 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { m as resolveProjectRoot } from './run-DsGZVxkK.mjs';
3
- import { g as getWorkflow, w as workflowSteps, s as setWorkflowEnabled, r as removeWorkflow, a as saveWorkflow, b as rawWorkflow, l as listWorkflows } from './store-DEZ8e-uE.mjs';
1
+ import { m as resolveProjectRoot } from './run-CsqoYIvO.mjs';
2
+ import { g as getWorkflow, s as setWorkflowEnabled, r as removeWorkflow, a as saveWorkflow, b as rawWorkflow, l as listWorkflows } from './store-BTs0H_y0.mjs';
3
+ import { g as getRun, l as listRuns, r as runWorkflow } from './runStore-CtptN7US.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
6
6
  import 'fs';
@@ -10,6 +10,7 @@ import 'child_process';
10
10
  import 'crypto';
11
11
  import 'node:crypto';
12
12
  import 'node:fs';
13
+ import 'node:child_process';
13
14
  import 'util';
14
15
  import 'node:path';
15
16
  import 'node:events';
@@ -23,7 +24,7 @@ import 'node:fs/promises';
23
24
  import 'node:util';
24
25
  import 'yaml';
25
26
 
26
- function workflowRpc(cwd, params) {
27
+ async function workflowRpc(cwd, params) {
27
28
  const root = resolveProjectRoot(cwd || process.cwd());
28
29
  const op = params.op;
29
30
  switch (op) {
@@ -62,22 +63,26 @@ function workflowRpc(cwd, params) {
62
63
  case "run": {
63
64
  const wf = getWorkflow(root, String(params.name));
64
65
  if (!wf) throw new Error(`Workflow not found: ${params.name}`);
65
- const steps = workflowSteps(wf);
66
- const stepEnv = wf.session ? { ...process.env, SVAMP_SESSION_ID: wf.session } : process.env;
67
- const out = [`\u25B6 running workflow "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"})`];
68
- for (let i = 0; i < steps.length; i++) {
69
- const step = steps[i];
70
- out.push(` [${i + 1}/${steps.length}] $ ${step.run}`);
71
- const r = spawnSync("sh", ["-c", step.run], { cwd: root, encoding: "utf-8", timeout: 12e4, env: stepEnv });
72
- if (r.stdout) out.push(r.stdout.trimEnd());
73
- if (r.stderr) out.push(r.stderr.trimEnd());
74
- if (r.status !== 0) {
75
- out.push(` \u2717 step ${i + 1} failed (exit ${r.status ?? "signal"}). Stopping.`);
76
- return { ok: false, output: out.join("\n") };
77
- }
66
+ const run = await runWorkflow(root, wf, { trigger: "manual", actor: params.actor || params.session || null });
67
+ const out = [`\u25B6 ran workflow "${wf.name}" (${run.steps.length} step${run.steps.length === 1 ? "" : "s"}) \u2192 ${run.status}`];
68
+ for (const s of run.steps) {
69
+ out.push(` [${s.index + 1}] $ ${s.cmd}`);
70
+ if (s.stdout) out.push(s.stdout.trimEnd());
71
+ if (s.stderr) out.push(s.stderr.trimEnd());
72
+ if (s.timedOut) out.push(` \u2717 step ${s.index + 1} timed out.`);
73
+ else if (s.exitCode !== 0) out.push(` \u2717 step ${s.index + 1} failed (exit ${s.exitCode ?? "signal"}).`);
78
74
  }
79
- out.push(`\u2713 workflow "${wf.name}" completed.`);
80
- return { ok: true, output: out.join("\n") };
75
+ out.push(run.status === "success" ? `\u2713 workflow "${wf.name}" completed.` : `\u2717 workflow "${wf.name}" failed.`);
76
+ return { ok: run.status === "success", output: out.join("\n"), runId: run.id };
77
+ }
78
+ case "runs": {
79
+ const limit = Number(params.limit) > 0 ? Number(params.limit) : void 0;
80
+ return { runs: listRuns(root, String(params.name), limit) };
81
+ }
82
+ case "run-detail": {
83
+ const run = getRun(root, String(params.name), String(params.runId));
84
+ if (!run) throw new Error(`Run not found: ${params.name}/${params.runId}`);
85
+ return run;
81
86
  }
82
87
  default:
83
88
  throw new Error(`workflow rpc: unknown op "${op}"`);
@@ -1,4 +1,4 @@
1
- import { m as resolveProjectRoot, u as updateIssue, n as getIssue, o as addComment, p as addIssue, q as listIssues, t as searchIssues, v as isVisibleTo } from './run-DsGZVxkK.mjs';
1
+ import { m as resolveProjectRoot, u as updateIssue, n as getIssue, o as resumeIssue, p as pauseIssue, q as addComment, t as addIssue, v as listIssues, w as searchIssues, x as isVisibleTo } from './run-CsqoYIvO.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -115,6 +115,18 @@ function issueRpc(cwd, params, deps = {}) {
115
115
  notifyOwnerOnFollowUp(updated, text, params.session || null, deps);
116
116
  return updated;
117
117
  }
118
+ case "pause": {
119
+ const question = params.question ? { text: String(params.question), options: Array.isArray(params.options) ? params.options.map(String) : [] } : void 0;
120
+ const updated = pauseIssue(root, String(params.id), question);
121
+ if (!updated) throw new Error(`Issue not found: ${params.id}`);
122
+ if (question) notifyOwnerOnFollowUp(updated, `needs your input: ${question.text}`, params.session || null, deps);
123
+ return updated;
124
+ }
125
+ case "resume": {
126
+ const updated = resumeIssue(root, String(params.id), params.answer ? String(params.answer) : void 0);
127
+ if (!updated) throw new Error(`Issue not found: ${params.id}`);
128
+ return updated;
129
+ }
118
130
  case "status": {
119
131
  const status = STATUS_MAP[params.status];
120
132
  if (!status) throw new Error(`issue status: unknown status "${params.status}"`);
@@ -1,4 +1,4 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a1 as applyClaudeProxyEnv, a2 as composeSessionId, a3 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a4 as generateHookSettings } from './run-DsGZVxkK.mjs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a3 as applyClaudeProxyEnv, a4 as composeSessionId, a5 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a6 as generateHookSettings } from './run-CsqoYIvO.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';
@@ -2912,7 +2912,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
2912
2912
  const tunnels = handlers.tunnels;
2913
2913
  if (!tunnels) throw new Error("Tunnel management not available");
2914
2914
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
2915
- const { FrpcTunnel } = await import('./frpc-gMUAwe3q.mjs');
2915
+ const { FrpcTunnel } = await import('./frpc-Sq_r6a9i.mjs');
2916
2916
  const tunnel = new FrpcTunnel({
2917
2917
  name: params.name,
2918
2918
  ports: params.ports,
@@ -3359,7 +3359,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3359
3359
  }
3360
3360
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
3361
3361
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
3362
- const { toolsForRole } = await import('./sideband-5D9B_PyP.mjs');
3362
+ const { toolsForRole } = await import('./sideband-BXQYf8dr.mjs');
3363
3363
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
3364
3364
  return fmt(r2);
3365
3365
  }
@@ -3458,7 +3458,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3458
3458
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
3459
3459
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
3460
3460
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
3461
- const { queryCore } = await import('./commands-DRI2MMHg.mjs');
3461
+ const { queryCore } = await import('./commands-DnTtqcre.mjs');
3462
3462
  const timeout = c.reply?.timeout_sec || 120;
3463
3463
  let result;
3464
3464
  try {
@@ -10389,9 +10389,9 @@ class ProcessSupervisor {
10389
10389
  function normalizeStatus(s) {
10390
10390
  if (s === "backlog") return "ready";
10391
10391
  if (s === "done") return "archived";
10392
- return s === "ready" || s === "in_progress" || s === "archived" ? s : "ready";
10392
+ return s === "ready" || s === "in_progress" || s === "paused" || s === "archived" ? s : "ready";
10393
10393
  }
10394
- const FIELD_ORDER = ["id", "title", "status", "scope", "labels", "verify", "disposition", "triaged", "branch", "session", "owner", "original", "created", "closed"];
10394
+ const FIELD_ORDER = ["id", "title", "status", "scope", "labels", "verify", "disposition", "triaged", "branch", "session", "owner", "original", "created", "closed", "question"];
10395
10395
  function resolveProjectRoot(start = process.cwd()) {
10396
10396
  let dir = start;
10397
10397
  for (let i = 0; i < 40; i++) {
@@ -10452,6 +10452,7 @@ function parseIssue(content) {
10452
10452
  original: fm.original ?? null,
10453
10453
  created: String(fm.created ?? (/* @__PURE__ */ new Date()).toISOString()),
10454
10454
  closed: fm.closed ?? null,
10455
+ question: fm.question && typeof fm.question === "object" ? fm.question : null,
10455
10456
  body: (m[2] || "").trim() || void 0
10456
10457
  };
10457
10458
  }
@@ -10559,6 +10560,26 @@ ${text.trim()}`;
10559
10560
  const body = (cur.body ? cur.body.replace(/\s+$/, "") : "") + entry;
10560
10561
  return updateIssue(projectRoot, id, { body });
10561
10562
  }
10563
+ function pauseIssue(projectRoot, id, question) {
10564
+ const cur = getIssue(projectRoot, id);
10565
+ if (!cur) return null;
10566
+ const q = question?.text ? { text: question.text.trim(), options: (question.options || []).map((o) => String(o).trim()).filter(Boolean), askedAt: (/* @__PURE__ */ new Date()).toISOString() } : null;
10567
+ if (q) {
10568
+ const optLine = q.options && q.options.length ? `
10569
+ Options: ${q.options.join(" \xB7 ")}` : "";
10570
+ addComment(projectRoot, id, `\u23F8 Paused \u2014 needs your input: ${q.text}${optLine}`);
10571
+ } else {
10572
+ addComment(projectRoot, id, "\u23F8 Paused \u2014 waiting on your input.");
10573
+ }
10574
+ return updateIssue(projectRoot, id, { status: "paused", question: q });
10575
+ }
10576
+ function resumeIssue(projectRoot, id, answer) {
10577
+ const cur = getIssue(projectRoot, id);
10578
+ if (!cur) return null;
10579
+ if (answer && answer.trim()) addComment(projectRoot, id, `\u25B6 Resumed \u2014 your answer: ${answer.trim()}`);
10580
+ else addComment(projectRoot, id, "\u25B6 Resumed.");
10581
+ return updateIssue(projectRoot, id, { status: "in_progress", question: null });
10582
+ }
10562
10583
  function routeCrewVerdict(projectRoot, childSessionId, v) {
10563
10584
  const linked = listIssues(projectRoot, { includeArchived: true }).find((i) => i.disposition === "crew" && i.session === childSessionId);
10564
10585
  if (!linked) return null;
@@ -12101,7 +12122,7 @@ async function startDaemon(options) {
12101
12122
  saveExposedTunnels(list);
12102
12123
  }
12103
12124
  async function createExposedTunnel(spec) {
12104
- const { FrpcTunnel } = await import('./frpc-gMUAwe3q.mjs');
12125
+ const { FrpcTunnel } = await import('./frpc-Sq_r6a9i.mjs');
12105
12126
  const tunnel = new FrpcTunnel({
12106
12127
  name: spec.name,
12107
12128
  ports: spec.ports,
@@ -12121,7 +12142,7 @@ async function startDaemon(options) {
12121
12142
  return tunnel;
12122
12143
  }
12123
12144
  const tunnelRecreateState = /* @__PURE__ */ new Map();
12124
- const { ServeManager } = await import('./serveManager-CtbAmKJ7.mjs');
12145
+ const { ServeManager } = await import('./serveManager-CkEjrt25.mjs');
12125
12146
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
12126
12147
  ensureAutoInstalledSkills(logger).catch(() => {
12127
12148
  });
@@ -13985,11 +14006,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
13985
14006
  });
13986
14007
  },
13987
14008
  onIssue: async (params) => {
13988
- const { issueRpc } = await import('./rpc-_aPtyAzL.mjs');
14009
+ const { issueRpc } = await import('./rpc-DXp0vpxD.mjs');
13989
14010
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner });
13990
14011
  },
13991
14012
  onWorkflow: async (params) => {
13992
- const { workflowRpc } = await import('./rpc-GTsR01jv.mjs');
14013
+ const { workflowRpc } = await import('./rpc-BJKoRzGK.mjs');
13993
14014
  return workflowRpc(params?.cwd || directory, params || {});
13994
14015
  },
13995
14016
  onRipgrep: async (args, cwd) => {
@@ -14499,11 +14520,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
14499
14520
  });
14500
14521
  },
14501
14522
  onIssue: async (params) => {
14502
- const { issueRpc } = await import('./rpc-_aPtyAzL.mjs');
14523
+ const { issueRpc } = await import('./rpc-DXp0vpxD.mjs');
14503
14524
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner });
14504
14525
  },
14505
14526
  onWorkflow: async (params) => {
14506
- const { workflowRpc } = await import('./rpc-GTsR01jv.mjs');
14527
+ const { workflowRpc } = await import('./rpc-BJKoRzGK.mjs');
14507
14528
  return workflowRpc(params?.cwd || directory, params || {});
14508
14529
  },
14509
14530
  onRipgrep: async (args, cwd) => {
@@ -15288,7 +15309,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
15288
15309
  const PING_TIMEOUT_MS = 15e3;
15289
15310
  const POST_RECONNECT_GRACE_MS = 2e4;
15290
15311
  const RECONNECT_JITTER_MS = 2500;
15291
- const { WorkflowScheduler } = await import('./scheduler-9mJf0_7T.mjs');
15312
+ const { WorkflowScheduler } = await import('./scheduler-CSYBbqjZ.mjs');
15292
15313
  const workflowScheduler = new WorkflowScheduler({
15293
15314
  projectRoots: () => {
15294
15315
  const dirs = /* @__PURE__ */ new Set();
@@ -15867,4 +15888,4 @@ var run = /*#__PURE__*/Object.freeze({
15867
15888
  writeStopMarker: writeStopMarker
15868
15889
  });
15869
15890
 
15870
- export { describeMisconfiguration as $, buildMachineInstructions as A, machineToolsForRole as B, buildMachineTools as C, parseFrontmatter as D, getSkillsServer as E, getSkillsWorkspaceName as F, getSkillsCollectionName as G, fetchWithTimeout as H, searchSkills as I, SKILLS_DIR as J, getSkillInfo as K, downloadSkillFile as L, listSkillFiles as M, resolveModel as N, formatHandle as O, normalizeAllowedUser as P, loadSecurityContextConfig as Q, READ_ONLY_TOOLS as R, ServeAuth as S, resolveSecurityContext as T, buildSecurityContextFromFlags as U, mergeSecurityContexts as V, buildSessionShareUrl as W, computeOutboundHop as X, buildMachineShareUrl as Y, parseHandle as Z, handleMatchesMetadata as _, createSessionStore as a, buildMachineDeps as a0, applyClaudeProxyEnv as a1, composeSessionId as a2, generateFriendlyName as a3, generateHookSettings as a4, claudeAuth as a5, projectInfo as a6, DefaultTransport$1 as a7, acpBackend as a8, acpAgentConfig as a9, codexMcpBackend as aa, GeminiTransport$1 as ab, instanceConfig as ac, api as ad, run as ae, stopDaemon as b, connectToHypha as c, daemonStatus as d, clearStopMarker as e, stopMarkerExists as f, getHyphaServerUrl$1 as g, getFrpsSubdomainHost as h, getFrpsServerPort as i, getFrpsServerAddr as j, getHyphaServerUrl as k, hasCookieToken as l, resolveProjectRoot as m, getIssue as n, addComment as o, addIssue as p, listIssues as q, registerMachineService as r, startDaemon as s, searchIssues as t, updateIssue as u, isVisibleTo as v, cronMatches as w, summarize as x, shortId as y, loadMachineContext as z };
15891
+ export { parseHandle as $, shortId as A, loadMachineContext as B, buildMachineInstructions as C, machineToolsForRole as D, buildMachineTools as E, parseFrontmatter as F, getSkillsServer as G, getSkillsWorkspaceName as H, getSkillsCollectionName as I, fetchWithTimeout as J, searchSkills as K, SKILLS_DIR as L, getSkillInfo as M, downloadSkillFile as N, listSkillFiles as O, resolveModel as P, formatHandle as Q, READ_ONLY_TOOLS as R, ServeAuth as S, normalizeAllowedUser as T, loadSecurityContextConfig as U, resolveSecurityContext as V, buildSecurityContextFromFlags as W, mergeSecurityContexts as X, buildSessionShareUrl as Y, computeOutboundHop as Z, buildMachineShareUrl as _, createSessionStore as a, handleMatchesMetadata as a0, describeMisconfiguration as a1, buildMachineDeps as a2, applyClaudeProxyEnv as a3, composeSessionId as a4, generateFriendlyName as a5, generateHookSettings as a6, claudeAuth as a7, projectInfo as a8, DefaultTransport$1 as a9, acpBackend as aa, acpAgentConfig as ab, codexMcpBackend as ac, GeminiTransport$1 as ad, instanceConfig as ae, api as af, run as ag, stopDaemon as b, connectToHypha as c, daemonStatus as d, clearStopMarker as e, stopMarkerExists as f, getHyphaServerUrl$1 as g, getFrpsSubdomainHost as h, getFrpsServerPort as i, getFrpsServerAddr as j, getHyphaServerUrl as k, hasCookieToken as l, resolveProjectRoot as m, getIssue as n, resumeIssue as o, pauseIssue as p, addComment as q, registerMachineService as r, startDaemon as s, addIssue as t, updateIssue as u, listIssues as v, searchIssues as w, isVisibleTo as x, cronMatches as y, summarize as z };
@@ -0,0 +1,168 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { c as workflowSteps, d as workflowsDir } from './store-BTs0H_y0.mjs';
5
+
6
+ const MAX_RUNS_PER_WORKFLOW = 50;
7
+ const MAX_STREAM_CHARS = 8e3;
8
+ const STEP_TIMEOUT_MS = 12e4;
9
+ function capStream(s, max = MAX_STREAM_CHARS) {
10
+ if (s.length <= max) return s;
11
+ const head = Math.floor(max * 0.6);
12
+ const tail = max - head;
13
+ const omitted = s.length - max;
14
+ return `${s.slice(0, head)}
15
+ \u2026 [${omitted} chars omitted] \u2026
16
+ ${s.slice(s.length - tail)}`;
17
+ }
18
+ function runsDir(projectRoot) {
19
+ return join(workflowsDir(projectRoot), ".runs");
20
+ }
21
+ function runsFile(projectRoot, workflow) {
22
+ const safe = workflow.replace(/[^\w.-]+/g, "_");
23
+ return join(runsDir(projectRoot), `${safe}.jsonl`);
24
+ }
25
+ function shortRunId(seed) {
26
+ let h = 2166136261;
27
+ for (let i = 0; i < seed.length; i++) {
28
+ h ^= seed.charCodeAt(i);
29
+ h = Math.imul(h, 16777619);
30
+ }
31
+ return (h >>> 0).toString(36).padStart(7, "0").slice(0, 7);
32
+ }
33
+ function recordRun(projectRoot, run) {
34
+ try {
35
+ const dir = runsDir(projectRoot);
36
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
37
+ const file = runsFile(projectRoot, run.workflow);
38
+ const existing = loadRuns(projectRoot, run.workflow);
39
+ const idx = existing.findIndex((r) => r.id === run.id);
40
+ if (idx >= 0) existing[idx] = run;
41
+ else existing.push(run);
42
+ const kept = existing.slice(-MAX_RUNS_PER_WORKFLOW);
43
+ const tmp = `${file}.tmp`;
44
+ writeFileSync(tmp, kept.map((r) => JSON.stringify(r)).join("\n") + "\n");
45
+ renameSync(tmp, file);
46
+ } catch {
47
+ }
48
+ }
49
+ function loadRuns(projectRoot, workflow) {
50
+ try {
51
+ const file = runsFile(projectRoot, workflow);
52
+ if (!existsSync(file)) return [];
53
+ return readFileSync(file, "utf-8").split("\n").filter(Boolean).map((l) => {
54
+ try {
55
+ return JSON.parse(l);
56
+ } catch {
57
+ return null;
58
+ }
59
+ }).filter((r) => !!r);
60
+ } catch {
61
+ return [];
62
+ }
63
+ }
64
+ function listRuns(projectRoot, workflow, limit = MAX_RUNS_PER_WORKFLOW) {
65
+ return loadRuns(projectRoot, workflow).slice(-limit).reverse().map((r) => {
66
+ const failedStep = r.steps.findIndex((s) => s.exitCode !== 0 && s.exitCode !== null || s.timedOut);
67
+ const { steps, ...rest } = r;
68
+ return { ...rest, stepCount: steps.length, failedStep: failedStep >= 0 ? failedStep : void 0 };
69
+ });
70
+ }
71
+ function getRun(projectRoot, workflow, runId) {
72
+ return loadRuns(projectRoot, workflow).find((r) => r.id === runId) || null;
73
+ }
74
+ function defaultExecStep(root, cmd, env) {
75
+ return new Promise((resolve) => {
76
+ let stdout = "", stderr = "", timedOut = false, settled = false;
77
+ const finish = (exitCode) => {
78
+ if (settled) return;
79
+ settled = true;
80
+ resolve({ exitCode, stdout, stderr, timedOut });
81
+ };
82
+ try {
83
+ const child = spawn("sh", ["-c", cmd], { cwd: root, env, stdio: ["ignore", "pipe", "pipe"] });
84
+ const timer = setTimeout(() => {
85
+ timedOut = true;
86
+ try {
87
+ child.kill("SIGKILL");
88
+ } catch {
89
+ }
90
+ }, STEP_TIMEOUT_MS);
91
+ child.stdout?.on("data", (d) => {
92
+ stdout += d.toString();
93
+ if (stdout.length > MAX_STREAM_CHARS * 4) stdout = capStream(stdout);
94
+ });
95
+ child.stderr?.on("data", (d) => {
96
+ stderr += d.toString();
97
+ if (stderr.length > MAX_STREAM_CHARS * 4) stderr = capStream(stderr);
98
+ });
99
+ child.on("error", (e) => {
100
+ clearTimeout(timer);
101
+ stderr += `
102
+ [spawn error] ${e.message}`;
103
+ finish(null);
104
+ });
105
+ child.on("close", (code) => {
106
+ clearTimeout(timer);
107
+ finish(code);
108
+ });
109
+ } catch (e) {
110
+ stderr += `[spawn threw] ${e?.message || e}`;
111
+ finish(null);
112
+ }
113
+ });
114
+ }
115
+ async function runWorkflow(projectRoot, wf, opts) {
116
+ const now = opts.now || (() => {
117
+ const d = /* @__PURE__ */ new Date();
118
+ return { iso: d.toISOString(), ms: d.getTime() };
119
+ });
120
+ const exec = opts.execStep || defaultExecStep;
121
+ const start = now();
122
+ const id = shortRunId(`${wf.name}:${start.iso}:${start.ms}`);
123
+ const env = wf.session ? { ...process.env, SVAMP_SESSION_ID: wf.session } : process.env;
124
+ const run = {
125
+ id,
126
+ workflow: wf.name,
127
+ trigger: opts.trigger,
128
+ triggerContext: opts.triggerContext,
129
+ actor: opts.actor ?? wf.session ?? null,
130
+ startedAt: start.iso,
131
+ status: "running",
132
+ steps: []
133
+ };
134
+ recordRun(projectRoot, run);
135
+ const steps = workflowSteps(wf);
136
+ try {
137
+ for (let i = 0; i < steps.length; i++) {
138
+ const s0 = now();
139
+ const r = await exec(projectRoot, steps[i].run, env);
140
+ const s1 = now();
141
+ run.steps.push({
142
+ index: i,
143
+ cmd: steps[i].run,
144
+ exitCode: r.exitCode,
145
+ stdout: capStream(r.stdout),
146
+ stderr: capStream(r.stderr),
147
+ durationMs: s1.ms - s0.ms,
148
+ timedOut: r.timedOut || void 0
149
+ });
150
+ if (r.timedOut || r.exitCode !== 0) {
151
+ run.status = "failed";
152
+ break;
153
+ }
154
+ }
155
+ if (run.status === "running") run.status = "success";
156
+ } catch (e) {
157
+ run.status = "failed";
158
+ run.error = e?.message || String(e);
159
+ }
160
+ const end = now();
161
+ run.finishedAt = end.iso;
162
+ run.durationMs = end.ms - start.ms;
163
+ recordRun(projectRoot, run);
164
+ opts.log?.(`[workflow] run ${id} "${wf.name}" \u2192 ${run.status} (${run.steps.length} step${run.steps.length === 1 ? "" : "s"})`);
165
+ return run;
166
+ }
167
+
168
+ export { getRun as g, listRuns as l, runWorkflow as r };