svamp-cli 0.2.175 → 0.2.176

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 (27) hide show
  1. package/dist/{agentCommands-C4upUtMc.mjs → agentCommands-kchQlyIS.mjs} +5 -5
  2. package/dist/{auth-BKN98KO4.mjs → auth-oH2upjHc.mjs} +1 -1
  3. package/dist/cli.mjs +61 -61
  4. package/dist/{commands-BbqjhR4z.mjs → commands-9LT5p45A.mjs} +2 -2
  5. package/dist/{commands-D03sBXV4.mjs → commands-CXtkDntj.mjs} +2 -2
  6. package/dist/{commands-D2lD-S4d.mjs → commands-CbrJ16x7.mjs} +5 -5
  7. package/dist/{commands-BF_Wy2B4.mjs → commands-Cu6nPOsD.mjs} +1 -1
  8. package/dist/{commands-CkygtYMZ.mjs → commands-DBi7fxGX.mjs} +2 -2
  9. package/dist/{commands-BssfhM-2.mjs → commands-DGkX7Kcr.mjs} +1 -1
  10. package/dist/{commands-DICHik9Y.mjs → commands-DHbv5qMP.mjs} +19 -13
  11. package/dist/{commands-CSK-jSnk.mjs → commands-USG2Z4XP.mjs} +1 -1
  12. package/dist/{fleet-qUmhLn41.mjs → fleet-BcS8xNkk.mjs} +1 -1
  13. package/dist/{frpc-BDZgTsi8.mjs → frpc-Bm7BrLan.mjs} +1 -1
  14. package/dist/{headlessCli-BG-PcYjM.mjs → headlessCli-B4CVNI7S.mjs} +2 -2
  15. package/dist/index.mjs +1 -1
  16. package/dist/{package-CMB-hfB0.mjs → package-DndVS0ln.mjs} +2 -2
  17. package/dist/{rpc-gCEvLUNu.mjs → rpc-BbaS0cLh.mjs} +1 -1
  18. package/dist/{rpc-CQTahguB.mjs → rpc-DVNDMfl8.mjs} +11 -9
  19. package/dist/{run-Buov6wz-.mjs → run-BmpyfykC.mjs} +29 -10
  20. package/dist/{run-DGs1hcvd.mjs → run-Cr1yt_tm.mjs} +1 -1
  21. package/dist/scheduler-BusuolPD.mjs +93 -0
  22. package/dist/{serveCommands-C6l8yA9_.mjs → serveCommands-Crb8ENkv.mjs} +5 -5
  23. package/dist/{serveManager-B_Bj1AF4.mjs → serveManager-DQByExEO.mjs} +2 -2
  24. package/dist/{sideband-BYiyQgZR.mjs → sideband-B4L2zR2U.mjs} +1 -1
  25. package/dist/store-BPL__e4D.mjs +125 -0
  26. package/package.json +2 -2
  27. package/dist/store-D2HNe-Kv.mjs +0 -74
@@ -1,6 +1,6 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { m as resolveProjectRoot } from './run-Buov6wz-.mjs';
3
- import { r as removeWorkflow, g as getWorkflow, l as listWorkflows, s as saveWorkflow, a as rawWorkflow } from './store-D2HNe-Kv.mjs';
2
+ import { m as resolveProjectRoot } from './run-BmpyfykC.mjs';
3
+ import { w as workflowSteps, r as removeWorkflow, g as getWorkflow, l as listWorkflows, s as saveWorkflow, a as rawWorkflow } from './store-BPL__e4D.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
6
6
  import 'fs';
@@ -45,8 +45,8 @@ function positional(args) {
45
45
  function describeOn(on) {
46
46
  if (!on) return "manual";
47
47
  const parts = [];
48
- if (on.schedule) parts.push(`schedule(${on.schedule})`);
49
- if (on.dispatch) parts.push("dispatch");
48
+ if (on.schedule?.length) parts.push(`schedule(${on.schedule.map((s) => s.cron).join(", ")})`);
49
+ if (on.workflow_dispatch) parts.push("workflow_dispatch");
50
50
  if (on.channel) parts.push(`channel(${on.channel})`);
51
51
  if (on.issue?.length) parts.push(`issue(${on.issue.join("/")})`);
52
52
  return parts.length ? parts.join(" ") : "manual";
@@ -65,16 +65,18 @@ async function workflowCommand(args) {
65
65
  process.exit(1);
66
66
  }
67
67
  const onKinds = allFlags(rest, "--on");
68
+ const crons = allFlags(rest, "--cron");
68
69
  const on = {};
69
- if (onKinds.includes("schedule") || flag(rest, "--cron")) on.schedule = flag(rest, "--cron") || "0 * * * *";
70
- if (onKinds.includes("dispatch")) on.dispatch = true;
70
+ if (onKinds.includes("schedule") || crons.length) on.schedule = (crons.length ? crons : ["0 * * * *"]).map((c) => ({ cron: c }));
71
+ if (onKinds.includes("dispatch") || onKinds.includes("workflow_dispatch")) on.workflow_dispatch = true;
71
72
  if (onKinds.includes("channel") || flag(rest, "--channel")) on.channel = flag(rest, "--channel") || "default";
72
73
  if (onKinds.includes("issue") || flag(rest, "--issue")) on.issue = (flag(rest, "--issue") || "ready").split(",").map((s) => s.trim()).filter(Boolean);
73
74
  const owner = flag(rest, "--session") || process.env.SVAMP_SESSION_ID || null;
74
- const wf = { name, on: Object.keys(on).length ? on : void 0, jobs: runs.map((r) => ({ run: r })), session: owner };
75
+ const wf = { name, on: Object.keys(on).length ? on : void 0, jobs: { run: { steps: runs.map((r) => ({ run: r })) } }, session: owner };
75
76
  saveWorkflow(root, wf);
77
+ const nSteps = workflowSteps(wf).length;
76
78
  if (json) console.log(JSON.stringify(wf));
77
- else console.log(`Saved workflow "${name}" (on: ${describeOn(wf.on)}, ${wf.jobs.length} step${wf.jobs.length === 1 ? "" : "s"}).`);
79
+ else console.log(`Saved workflow "${name}" (on: ${describeOn(wf.on)}, ${nSteps} step${nSteps === 1 ? "" : "s"}).`);
78
80
  break;
79
81
  }
80
82
  case "list":
@@ -88,7 +90,10 @@ async function workflowCommand(args) {
88
90
  console.log("No workflows.");
89
91
  break;
90
92
  }
91
- for (const wf of all) console.log(`${wf.name} [${describeOn(wf.on)}] ${wf.jobs.length} step${wf.jobs.length === 1 ? "" : "s"}`);
93
+ for (const wf of all) {
94
+ const n = workflowSteps(wf).length;
95
+ console.log(`${wf.name} [${describeOn(wf.on)}] ${n} step${n === 1 ? "" : "s"}`);
96
+ }
92
97
  break;
93
98
  }
94
99
  case "show": {
@@ -119,10 +124,11 @@ async function workflowCommand(args) {
119
124
  console.error(`Workflow not found: ${name}`);
120
125
  process.exit(1);
121
126
  }
122
- console.log(`\u25B6 running workflow "${wf.name}" (${wf.jobs.length} step${wf.jobs.length === 1 ? "" : "s"})`);
123
- for (let i = 0; i < wf.jobs.length; i++) {
124
- const step = wf.jobs[i];
125
- console.log(` [${i + 1}/${wf.jobs.length}] $ ${step.run}`);
127
+ const steps = workflowSteps(wf);
128
+ console.log(`\u25B6 running workflow "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"})`);
129
+ for (let i = 0; i < steps.length; i++) {
130
+ const step = steps[i];
131
+ console.log(` [${i + 1}/${steps.length}] $ ${step.run}`);
126
132
  const r = spawnSync("sh", ["-c", step.run], { cwd: root, stdio: "inherit" });
127
133
  if (r.status !== 0) {
128
134
  console.error(` \u2717 step ${i + 1} failed (exit ${r.status ?? "signal"}). Stopping.`);
@@ -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-Buov6wz-.mjs';
4
+ import { E as parseFrontmatter, F as getSkillsServer, G as getSkillsWorkspaceName, H as getSkillsCollectionName, I as fetchWithTimeout, J as searchSkills, K as SKILLS_DIR, L as getSkillInfo, M as downloadSkillFile, N as listSkillFiles } from './run-BmpyfykC.mjs';
5
5
  import 'fs/promises';
6
6
  import 'url';
7
7
  import 'child_process';
@@ -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-Buov6wz-.mjs';
4
+ import { c as connectToHypha } from './run-BmpyfykC.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-Buov6wz-.mjs';
7
+ import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-BmpyfykC.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-Buov6wz-.mjs';
2
- import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-BYiyQgZR.mjs';
1
+ import { O as resolveModel, a0 as describeMisconfiguration, a1 as buildMachineDeps } from './run-BmpyfykC.mjs';
2
+ import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-B4L2zR2U.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-Buov6wz-.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-BmpyfykC.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.175";
2
+ var version = "0.2.176";
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-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.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-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-routine.mjs && npx tsx test/test-routine-rpc.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-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-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",
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-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.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-routine.mjs && npx tsx test/test-routine-rpc.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-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-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",
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,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 } from './run-Buov6wz-.mjs';
1
+ import { m as resolveProjectRoot, u as updateIssue, n as getIssue, o as addComment, p as addIssue, q as listIssues, t as searchIssues } from './run-BmpyfykC.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,6 +1,6 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { m as resolveProjectRoot } from './run-Buov6wz-.mjs';
3
- import { g as getWorkflow, r as removeWorkflow, s as saveWorkflow, a as rawWorkflow, l as listWorkflows } from './store-D2HNe-Kv.mjs';
2
+ import { m as resolveProjectRoot } from './run-BmpyfykC.mjs';
3
+ import { g as getWorkflow, w as workflowSteps, r as removeWorkflow, s as saveWorkflow, a as rawWorkflow, l as listWorkflows } from './store-BPL__e4D.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
6
6
  import 'fs';
@@ -35,8 +35,9 @@ function workflowRpc(cwd, params) {
35
35
  }
36
36
  case "add": {
37
37
  const on = {};
38
- if (params.cron) on.schedule = String(params.cron);
39
- if (params.dispatch) on.dispatch = true;
38
+ const crons = Array.isArray(params.cron) ? params.cron.map(String) : params.cron ? [String(params.cron)] : [];
39
+ if (crons.length) on.schedule = crons.map((c) => ({ cron: c }));
40
+ if (params.dispatch || params.workflow_dispatch) on.workflow_dispatch = true;
40
41
  if (params.channel) on.channel = String(params.channel);
41
42
  if (Array.isArray(params.issue) && params.issue.length) on.issue = params.issue.map(String);
42
43
  const runs = Array.isArray(params.runs) ? params.runs.map(String).filter(Boolean) : [];
@@ -44,7 +45,7 @@ function workflowRpc(cwd, params) {
44
45
  const wf = {
45
46
  name: String(params.name),
46
47
  on: Object.keys(on).length ? on : void 0,
47
- jobs: runs.map((r) => ({ run: r })),
48
+ jobs: { run: { steps: runs.map((r) => ({ run: r })) } },
48
49
  session: params.session || null
49
50
  };
50
51
  saveWorkflow(root, wf);
@@ -55,10 +56,11 @@ function workflowRpc(cwd, params) {
55
56
  case "run": {
56
57
  const wf = getWorkflow(root, String(params.name));
57
58
  if (!wf) throw new Error(`Workflow not found: ${params.name}`);
58
- const out = [`\u25B6 running workflow "${wf.name}" (${wf.jobs.length} step${wf.jobs.length === 1 ? "" : "s"})`];
59
- for (let i = 0; i < wf.jobs.length; i++) {
60
- const step = wf.jobs[i];
61
- out.push(` [${i + 1}/${wf.jobs.length}] $ ${step.run}`);
59
+ const steps = workflowSteps(wf);
60
+ const out = [`\u25B6 running workflow "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"})`];
61
+ for (let i = 0; i < steps.length; i++) {
62
+ const step = steps[i];
63
+ out.push(` [${i + 1}/${steps.length}] $ ${step.run}`);
62
64
  const r = spawnSync("sh", ["-c", step.run], { cwd: root, encoding: "utf-8", timeout: 12e4 });
63
65
  if (r.stdout) out.push(r.stdout.trimEnd());
64
66
  if (r.stderr) out.push(r.stderr.trimEnd());
@@ -2791,7 +2791,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
2791
2791
  const tunnels = handlers.tunnels;
2792
2792
  if (!tunnels) throw new Error("Tunnel management not available");
2793
2793
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
2794
- const { FrpcTunnel } = await import('./frpc-BDZgTsi8.mjs');
2794
+ const { FrpcTunnel } = await import('./frpc-Bm7BrLan.mjs');
2795
2795
  const tunnel = new FrpcTunnel({
2796
2796
  name: params.name,
2797
2797
  ports: params.ports,
@@ -3238,7 +3238,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3238
3238
  }
3239
3239
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
3240
3240
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
3241
- const { toolsForRole } = await import('./sideband-BYiyQgZR.mjs');
3241
+ const { toolsForRole } = await import('./sideband-B4L2zR2U.mjs');
3242
3242
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
3243
3243
  return fmt(r2);
3244
3244
  }
@@ -3337,7 +3337,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3337
3337
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
3338
3338
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
3339
3339
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
3340
- const { queryCore } = await import('./commands-BssfhM-2.mjs');
3340
+ const { queryCore } = await import('./commands-DGkX7Kcr.mjs');
3341
3341
  const timeout = c.reply?.timeout_sec || 120;
3342
3342
  let result;
3343
3343
  try {
@@ -11907,7 +11907,7 @@ async function startDaemon(options) {
11907
11907
  saveExposedTunnels(list);
11908
11908
  }
11909
11909
  async function createExposedTunnel(spec) {
11910
- const { FrpcTunnel } = await import('./frpc-BDZgTsi8.mjs');
11910
+ const { FrpcTunnel } = await import('./frpc-Bm7BrLan.mjs');
11911
11911
  const tunnel = new FrpcTunnel({
11912
11912
  name: spec.name,
11913
11913
  ports: spec.ports,
@@ -11927,7 +11927,7 @@ async function startDaemon(options) {
11927
11927
  return tunnel;
11928
11928
  }
11929
11929
  const tunnelRecreateState = /* @__PURE__ */ new Map();
11930
- const { ServeManager } = await import('./serveManager-B_Bj1AF4.mjs');
11930
+ const { ServeManager } = await import('./serveManager-DQByExEO.mjs');
11931
11931
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
11932
11932
  ensureAutoInstalledSkills(logger).catch(() => {
11933
11933
  });
@@ -13727,11 +13727,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
13727
13727
  });
13728
13728
  },
13729
13729
  onIssue: async (params) => {
13730
- const { issueRpc } = await import('./rpc-gCEvLUNu.mjs');
13730
+ const { issueRpc } = await import('./rpc-BbaS0cLh.mjs');
13731
13731
  return issueRpc(params?.cwd || directory, params || {});
13732
13732
  },
13733
13733
  onWorkflow: async (params) => {
13734
- const { workflowRpc } = await import('./rpc-CQTahguB.mjs');
13734
+ const { workflowRpc } = await import('./rpc-DVNDMfl8.mjs');
13735
13735
  return workflowRpc(params?.cwd || directory, params || {});
13736
13736
  },
13737
13737
  onRipgrep: async (args, cwd) => {
@@ -14246,11 +14246,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
14246
14246
  });
14247
14247
  },
14248
14248
  onIssue: async (params) => {
14249
- const { issueRpc } = await import('./rpc-gCEvLUNu.mjs');
14249
+ const { issueRpc } = await import('./rpc-BbaS0cLh.mjs');
14250
14250
  return issueRpc(params?.cwd || directory, params || {});
14251
14251
  },
14252
14252
  onWorkflow: async (params) => {
14253
- const { workflowRpc } = await import('./rpc-CQTahguB.mjs');
14253
+ const { workflowRpc } = await import('./rpc-DVNDMfl8.mjs');
14254
14254
  return workflowRpc(params?.cwd || directory, params || {});
14255
14255
  },
14256
14256
  onRipgrep: async (args, cwd) => {
@@ -15003,6 +15003,24 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
15003
15003
  const PING_TIMEOUT_MS = 15e3;
15004
15004
  const POST_RECONNECT_GRACE_MS = 2e4;
15005
15005
  const RECONNECT_JITTER_MS = 2500;
15006
+ const { WorkflowScheduler } = await import('./scheduler-BusuolPD.mjs');
15007
+ const workflowScheduler = new WorkflowScheduler({
15008
+ projectRoots: () => {
15009
+ const dirs = /* @__PURE__ */ new Set();
15010
+ for (const s of pidToTrackedSession.values()) {
15011
+ if (!s.stopped && s.directory) dirs.add(s.directory);
15012
+ }
15013
+ return [...dirs];
15014
+ },
15015
+ log: (m) => logger.log(m)
15016
+ });
15017
+ const workflowSchedulerInterval = setInterval(() => {
15018
+ try {
15019
+ workflowScheduler.tick(/* @__PURE__ */ new Date());
15020
+ } catch (e) {
15021
+ logger.log(`[workflow] scheduler tick error: ${e?.message || e}`);
15022
+ }
15023
+ }, 2e4);
15006
15024
  let heartbeatRunning = false;
15007
15025
  let lastReconnectAt = 0;
15008
15026
  let heartbeatCycle = 0;
@@ -15225,6 +15243,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
15225
15243
  const cleanup = async (source) => {
15226
15244
  logger.log(`Cleaning up (source: ${source})...`);
15227
15245
  clearInterval(heartbeatInterval);
15246
+ clearInterval(workflowSchedulerInterval);
15228
15247
  if (proxyTokenRefreshInterval) clearInterval(proxyTokenRefreshInterval);
15229
15248
  if (oauthRefreshInterval) clearInterval(oauthRefreshInterval);
15230
15249
  if (unhandledRejectionResetTimer) clearTimeout(unhandledRejectionResetTimer);
@@ -15563,4 +15582,4 @@ var run = /*#__PURE__*/Object.freeze({
15563
15582
  writeStopMarker: writeStopMarker
15564
15583
  });
15565
15584
 
15566
- 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, RoutineStore 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, composeSessionId as a1, generateFriendlyName as a2, generateHookSettings as a3, projectInfo as a4, DefaultTransport$1 as a5, acpBackend as a6, acpAgentConfig as a7, codexMcpBackend as a8, GeminiTransport$1 as a9, claudeAuth as aa, instanceConfig as ab, api as ac, run as ad, 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, summarize as v, RoutineRunner as w, shortId as x, READ_ONLY_TOOLS as y, loadMachineContext as z };
15585
+ export { handleMatchesMetadata as $, loadMachineContext as A, buildMachineInstructions as B, machineToolsForRole as C, buildMachineTools as D, parseFrontmatter as E, getSkillsServer as F, getSkillsWorkspaceName as G, getSkillsCollectionName as H, fetchWithTimeout as I, searchSkills as J, SKILLS_DIR as K, getSkillInfo as L, downloadSkillFile as M, listSkillFiles as N, resolveModel as O, formatHandle as P, normalizeAllowedUser as Q, RoutineStore as R, ServeAuth as S, loadSecurityContextConfig as T, resolveSecurityContext as U, buildSecurityContextFromFlags as V, mergeSecurityContexts as W, buildSessionShareUrl as X, computeOutboundHop as Y, buildMachineShareUrl as Z, parseHandle as _, createSessionStore as a, describeMisconfiguration as a0, buildMachineDeps as a1, composeSessionId as a2, generateFriendlyName as a3, generateHookSettings as a4, projectInfo as a5, DefaultTransport$1 as a6, acpBackend as a7, acpAgentConfig as a8, codexMcpBackend as a9, GeminiTransport$1 as aa, claudeAuth 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, cronMatches as v, summarize as w, RoutineRunner as x, shortId as y, READ_ONLY_TOOLS as z };
@@ -1,4 +1,4 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a1 as composeSessionId, a2 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a3 as generateHookSettings } from './run-Buov6wz-.mjs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a2 as composeSessionId, a3 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a4 as generateHookSettings } from './run-BmpyfykC.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';
@@ -0,0 +1,93 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { m as resolveProjectRoot, v as cronMatches } from './run-BmpyfykC.mjs';
3
+ import { l as listWorkflows, b as workflowCrons, w as workflowSteps } from './store-BPL__e4D.mjs';
4
+ import 'os';
5
+ import 'fs/promises';
6
+ import 'fs';
7
+ import 'path';
8
+ import 'url';
9
+ import 'child_process';
10
+ import 'crypto';
11
+ import 'node:crypto';
12
+ import 'node:fs';
13
+ import 'util';
14
+ import 'node:path';
15
+ import 'node:events';
16
+ import 'node:os';
17
+ import '@agentclientprotocol/sdk';
18
+ import '@modelcontextprotocol/sdk/client/index.js';
19
+ import '@modelcontextprotocol/sdk/client/stdio.js';
20
+ import '@modelcontextprotocol/sdk/types.js';
21
+ import 'zod';
22
+ import 'node:fs/promises';
23
+ import 'node:util';
24
+ import 'yaml';
25
+
26
+ function defaultRunStep(root, command, log) {
27
+ try {
28
+ const child = spawn("sh", ["-c", command], { cwd: root, detached: true, stdio: "ignore" });
29
+ child.on("error", (e) => log?.(`[workflow] step spawn error in ${root}: ${e.message}`));
30
+ child.unref();
31
+ } catch (e) {
32
+ log?.(`[workflow] step spawn threw in ${root}: ${e?.message || e}`);
33
+ }
34
+ }
35
+ function cronMatchesSafe(expr, date) {
36
+ try {
37
+ return cronMatches(expr, date);
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+ class WorkflowScheduler {
43
+ constructor(deps) {
44
+ this.deps = deps;
45
+ }
46
+ // Wall-clock minute we last processed, so multiple sub-minute ticks fire a workflow at most once
47
+ // per minute (cron granularity is one minute).
48
+ lastMinuteKey = null;
49
+ static minuteKey(d) {
50
+ return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}-${d.getHours()}-${d.getMinutes()}`;
51
+ }
52
+ /** Fire all scheduled workflows whose cron matches `now`. Returns the names fired (for tests/logs). */
53
+ tick(now) {
54
+ const key = WorkflowScheduler.minuteKey(now);
55
+ if (key === this.lastMinuteKey) return [];
56
+ this.lastMinuteKey = key;
57
+ const fired = [];
58
+ const seen = /* @__PURE__ */ new Set();
59
+ for (const dir of this.deps.projectRoots()) {
60
+ let root;
61
+ try {
62
+ root = resolveProjectRoot(dir);
63
+ } catch {
64
+ continue;
65
+ }
66
+ if (seen.has(root)) continue;
67
+ seen.add(root);
68
+ let workflows;
69
+ try {
70
+ workflows = listWorkflows(root);
71
+ } catch {
72
+ continue;
73
+ }
74
+ for (const wf of workflows) {
75
+ const crons = workflowCrons(wf);
76
+ if (!crons.length) continue;
77
+ if (crons.some((c) => cronMatchesSafe(c, now))) {
78
+ this.fire(root, wf);
79
+ fired.push(wf.name);
80
+ }
81
+ }
82
+ }
83
+ return fired;
84
+ }
85
+ fire(root, wf) {
86
+ const steps = workflowSteps(wf);
87
+ this.deps.log?.(`[workflow] schedule fired "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"}) in ${root}`);
88
+ const run = this.deps.runStep || ((r, c) => defaultRunStep(r, c, this.deps.log));
89
+ for (const step of steps) run(root, step.run);
90
+ }
91
+ }
92
+
93
+ export { WorkflowScheduler, cronMatchesSafe };
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-BssfhM-2.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-DGkX7Kcr.mjs');
58
58
  const pos = positionalArgs(args);
59
59
  const name = pos[0];
60
60
  if (!name) {
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
93
93
  }
94
94
  }
95
95
  async function serveApply(args, machineId) {
96
- const { connectAndGetMachine } = await import('./commands-BssfhM-2.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-DGkX7Kcr.mjs');
97
97
  const fs = await import('fs');
98
98
  const yaml = await import('yaml');
99
99
  const file = positionalArgs(args)[0];
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
182
182
  }
183
183
  }
184
184
  async function serveRemove(args, machineId) {
185
- const { connectAndGetMachine } = await import('./commands-BssfhM-2.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-DGkX7Kcr.mjs');
186
186
  const pos = positionalArgs(args);
187
187
  const name = pos[0];
188
188
  if (!name) {
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
202
202
  }
203
203
  }
204
204
  async function serveList(args, machineId) {
205
- const { connectAndGetMachine } = await import('./commands-BssfhM-2.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-DGkX7Kcr.mjs');
206
206
  const all = hasFlag(args, "--all", "-a");
207
207
  const json = hasFlag(args, "--json");
208
208
  const sessionId = getFlag(args, "--session");
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
235
235
  }
236
236
  }
237
237
  async function serveInfo(machineId) {
238
- const { connectAndGetMachine } = await import('./commands-BssfhM-2.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-DGkX7Kcr.mjs');
239
239
  const { machine, server } = await connectAndGetMachine(machineId);
240
240
  try {
241
241
  const info = await machine.serveInfo();
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import * as http from 'http';
5
5
  import * as net from 'net';
6
6
  import * as path from 'path';
7
- import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-Buov6wz-.mjs';
7
+ import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-BmpyfykC.mjs';
8
8
  import 'os';
9
9
  import 'fs/promises';
10
10
  import 'url';
@@ -733,7 +733,7 @@ class ServeManager {
733
733
  const mount = this.mounts.get(mountName);
734
734
  const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
735
735
  try {
736
- const { FrpcTunnel } = await import('./frpc-BDZgTsi8.mjs');
736
+ const { FrpcTunnel } = await import('./frpc-Bm7BrLan.mjs');
737
737
  let tunnel;
738
738
  tunnel = new FrpcTunnel({
739
739
  name: tunnelName,
@@ -1,4 +1,4 @@
1
- import { y as READ_ONLY_TOOLS, z as loadMachineContext, A as buildMachineInstructions, B as machineToolsForRole, C as buildMachineTools } from './run-Buov6wz-.mjs';
1
+ import { z as READ_ONLY_TOOLS, A as loadMachineContext, B as buildMachineInstructions, C as machineToolsForRole, D as buildMachineTools } from './run-BmpyfykC.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';
@@ -0,0 +1,125 @@
1
+ import { existsSync, unlinkSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { parse, stringify } from 'yaml';
4
+
5
+ function workflowSteps(wf) {
6
+ return Object.values(wf.jobs || {}).flatMap((j) => j?.steps || []);
7
+ }
8
+ function workflowCrons(wf) {
9
+ return (wf.on?.schedule || []).map((s) => s?.cron).filter((c) => !!c);
10
+ }
11
+ function workflowsDir(projectRoot) {
12
+ return join(projectRoot, ".svamp", "workflows");
13
+ }
14
+ function workflowPath(projectRoot, name) {
15
+ return join(workflowsDir(projectRoot), `${name}.yaml`);
16
+ }
17
+ function normalizeOn(on) {
18
+ if (!on || typeof on !== "object") {
19
+ return void 0;
20
+ }
21
+ const out = {};
22
+ if (Array.isArray(on.schedule)) {
23
+ const sched = on.schedule.map((s) => ({ cron: String(s?.cron ?? s ?? "") })).filter((s) => s.cron);
24
+ if (sched.length) out.schedule = sched;
25
+ } else if (typeof on.schedule === "string" && on.schedule.trim()) {
26
+ out.schedule = [{ cron: on.schedule.trim() }];
27
+ }
28
+ if ("workflow_dispatch" in on || on.dispatch === true) out.workflow_dispatch = true;
29
+ if (typeof on.channel === "string" && on.channel) out.channel = on.channel;
30
+ if (Array.isArray(on.issue) && on.issue.length) out.issue = on.issue.map(String);
31
+ return Object.keys(out).length ? out : void 0;
32
+ }
33
+ function normalizeJobs(jobs) {
34
+ if (Array.isArray(jobs)) {
35
+ const steps = jobs.map((j) => ({ run: String(j?.run ?? "") })).filter((s) => s.run);
36
+ return steps.length ? { run: { steps } } : {};
37
+ }
38
+ if (jobs && typeof jobs === "object") {
39
+ const out = {};
40
+ for (const [id, job] of Object.entries(jobs)) {
41
+ const rawSteps = Array.isArray(job?.steps) ? job.steps : job?.run ? [{ run: job.run }] : [];
42
+ const steps = rawSteps.map((s) => ({ run: String(s?.run ?? ""), ...s?.name ? { name: String(s.name) } : {} })).filter((s) => s.run);
43
+ if (steps.length) out[String(id)] = { steps };
44
+ }
45
+ return out;
46
+ }
47
+ return {};
48
+ }
49
+ function parseWorkflow(content) {
50
+ try {
51
+ const o = parse(content);
52
+ if (!o || typeof o !== "object" || !o.name) return null;
53
+ return {
54
+ name: String(o.name),
55
+ on: normalizeOn(o.on),
56
+ jobs: normalizeJobs(o.jobs),
57
+ session: o.session ?? null
58
+ };
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+ function serializeWorkflow(wf) {
64
+ const clean = { name: wf.name };
65
+ if (wf.session) clean.session = wf.session;
66
+ const on = {};
67
+ if (wf.on?.schedule?.length) on.schedule = wf.on.schedule.map((s) => ({ cron: s.cron }));
68
+ if (wf.on?.workflow_dispatch) on.workflow_dispatch = {};
69
+ if (wf.on?.channel) on.channel = wf.on.channel;
70
+ if (wf.on?.issue?.length) on.issue = wf.on.issue;
71
+ if (Object.keys(on).length) clean.on = on;
72
+ const jobs = {};
73
+ for (const [id, job] of Object.entries(wf.jobs || {})) {
74
+ jobs[id] = { steps: (job.steps || []).map((s) => s.name ? { name: s.name, run: s.run } : { run: s.run }) };
75
+ }
76
+ clean.jobs = Object.keys(jobs).length ? jobs : { run: { steps: [] } };
77
+ return stringify(clean);
78
+ }
79
+ function listWorkflows(projectRoot) {
80
+ const dir = workflowsDir(projectRoot);
81
+ if (!existsSync(dir)) return [];
82
+ const out = [];
83
+ for (const name of readdirSync(dir)) {
84
+ if (!name.endsWith(".yaml") && !name.endsWith(".yml")) continue;
85
+ try {
86
+ const wf = parseWorkflow(readFileSync(join(dir, name), "utf-8"));
87
+ if (wf) out.push(wf);
88
+ } catch {
89
+ }
90
+ }
91
+ return out.sort((a, b) => a.name.localeCompare(b.name));
92
+ }
93
+ function getWorkflow(projectRoot, name) {
94
+ const p = workflowPath(projectRoot, name);
95
+ if (!existsSync(p)) return null;
96
+ try {
97
+ return parseWorkflow(readFileSync(p, "utf-8"));
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ function rawWorkflow(projectRoot, name) {
103
+ const p = workflowPath(projectRoot, name);
104
+ return existsSync(p) ? readFileSync(p, "utf-8") : null;
105
+ }
106
+ function saveWorkflow(projectRoot, wf) {
107
+ const dir = workflowsDir(projectRoot);
108
+ mkdirSync(dir, { recursive: true });
109
+ const path = workflowPath(projectRoot, wf.name);
110
+ const tmp = `${path}.tmp-${process.pid}`;
111
+ writeFileSync(tmp, serializeWorkflow(wf));
112
+ renameSync(tmp, path);
113
+ }
114
+ function removeWorkflow(projectRoot, name) {
115
+ const p = workflowPath(projectRoot, name);
116
+ if (!existsSync(p)) return false;
117
+ try {
118
+ unlinkSync(p);
119
+ return true;
120
+ } catch {
121
+ return false;
122
+ }
123
+ }
124
+
125
+ export { rawWorkflow as a, workflowCrons as b, getWorkflow as g, listWorkflows as l, removeWorkflow as r, saveWorkflow as s, workflowSteps as w };