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.
- package/dist/{agentCommands-C4upUtMc.mjs → agentCommands-kchQlyIS.mjs} +5 -5
- package/dist/{auth-BKN98KO4.mjs → auth-oH2upjHc.mjs} +1 -1
- package/dist/cli.mjs +61 -61
- package/dist/{commands-BbqjhR4z.mjs → commands-9LT5p45A.mjs} +2 -2
- package/dist/{commands-D03sBXV4.mjs → commands-CXtkDntj.mjs} +2 -2
- package/dist/{commands-D2lD-S4d.mjs → commands-CbrJ16x7.mjs} +5 -5
- package/dist/{commands-BF_Wy2B4.mjs → commands-Cu6nPOsD.mjs} +1 -1
- package/dist/{commands-CkygtYMZ.mjs → commands-DBi7fxGX.mjs} +2 -2
- package/dist/{commands-BssfhM-2.mjs → commands-DGkX7Kcr.mjs} +1 -1
- package/dist/{commands-DICHik9Y.mjs → commands-DHbv5qMP.mjs} +19 -13
- package/dist/{commands-CSK-jSnk.mjs → commands-USG2Z4XP.mjs} +1 -1
- package/dist/{fleet-qUmhLn41.mjs → fleet-BcS8xNkk.mjs} +1 -1
- package/dist/{frpc-BDZgTsi8.mjs → frpc-Bm7BrLan.mjs} +1 -1
- package/dist/{headlessCli-BG-PcYjM.mjs → headlessCli-B4CVNI7S.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{package-CMB-hfB0.mjs → package-DndVS0ln.mjs} +2 -2
- package/dist/{rpc-gCEvLUNu.mjs → rpc-BbaS0cLh.mjs} +1 -1
- package/dist/{rpc-CQTahguB.mjs → rpc-DVNDMfl8.mjs} +11 -9
- package/dist/{run-Buov6wz-.mjs → run-BmpyfykC.mjs} +29 -10
- package/dist/{run-DGs1hcvd.mjs → run-Cr1yt_tm.mjs} +1 -1
- package/dist/scheduler-BusuolPD.mjs +93 -0
- package/dist/{serveCommands-C6l8yA9_.mjs → serveCommands-Crb8ENkv.mjs} +5 -5
- package/dist/{serveManager-B_Bj1AF4.mjs → serveManager-DQByExEO.mjs} +2 -2
- package/dist/{sideband-BYiyQgZR.mjs → sideband-B4L2zR2U.mjs} +1 -1
- package/dist/store-BPL__e4D.mjs +125 -0
- package/package.json +2 -2
- 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-
|
|
3
|
-
import { r as removeWorkflow, g as getWorkflow, l as listWorkflows, s as saveWorkflow, a as rawWorkflow } from './store-
|
|
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.
|
|
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") ||
|
|
70
|
-
if (onKinds.includes("dispatch")) on.
|
|
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)}, ${
|
|
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)
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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 {
|
|
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-
|
|
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-
|
|
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 {
|
|
2
|
-
import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-
|
|
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-
|
|
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.
|
|
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-
|
|
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-
|
|
3
|
-
import { g as getWorkflow, r as removeWorkflow, s as saveWorkflow, a as rawWorkflow, l as listWorkflows } from './store-
|
|
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
|
-
|
|
39
|
-
if (
|
|
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
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 {
|
|
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 {
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 {
|
|
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 };
|