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.
- package/dist/{agentCommands-BLig9RpJ.mjs → agentCommands-BMbdp3lO.mjs} +5 -5
- package/dist/{auth-BFDgK8NY.mjs → auth-DFV_MjVU.mjs} +1 -1
- package/dist/cli.mjs +60 -60
- package/dist/{commands-2qJ_Bh8F.mjs → commands-BA8pUB80.mjs} +2 -2
- package/dist/{commands-DgCf4FCQ.mjs → commands-CVMpx7Ws.mjs} +5 -5
- package/dist/{commands-C0NGT-PG.mjs → commands-CW1VrEei.mjs} +2 -2
- package/dist/{commands-NKOF_jF-.mjs → commands-Cbg4_aEA.mjs} +2 -2
- package/dist/{commands-C03E7eP5.mjs → commands-Ccbl9q_M.mjs} +44 -2
- package/dist/{commands-CrOYWa85.mjs → commands-DfD7ACo-.mjs} +1 -1
- package/dist/{commands-DRI2MMHg.mjs → commands-DnTtqcre.mjs} +1 -1
- package/dist/{fleet-CaFacVAt.mjs → fleet-Caxg-9CC.mjs} +1 -1
- package/dist/{frpc-gMUAwe3q.mjs → frpc-Sq_r6a9i.mjs} +1 -1
- package/dist/{headlessCli-DxAlTlhs.mjs → headlessCli-CqDPtg1x.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{package-BNVXH7XA.mjs → package-Df28hcfX.mjs} +2 -2
- package/dist/{rpc-GTsR01jv.mjs → rpc-BJKoRzGK.mjs} +24 -19
- package/dist/{rpc-_aPtyAzL.mjs → rpc-DXp0vpxD.mjs} +13 -1
- package/dist/{run-DyqabMH2.mjs → run-B5xwuwIO.mjs} +1 -1
- package/dist/{run-DsGZVxkK.mjs → run-CsqoYIvO.mjs} +34 -13
- package/dist/runStore-CtptN7US.mjs +168 -0
- package/dist/{scheduler-9mJf0_7T.mjs → scheduler-CSYBbqjZ.mjs} +23 -17
- package/dist/{serveCommands-CrjiFbbs.mjs → serveCommands-CHWW6Mon.mjs} +5 -5
- package/dist/{serveManager-CtbAmKJ7.mjs → serveManager-CkEjrt25.mjs} +2 -2
- package/dist/{sideband-5D9B_PyP.mjs → sideband-BXQYf8dr.mjs} +1 -1
- package/dist/{store-DEZ8e-uE.mjs → store-BTs0H_y0.mjs} +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
-
import { m as resolveProjectRoot,
|
|
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
|
-
"
|
|
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 {
|
|
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 {
|
|
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-
|
|
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-
|
|
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 {
|
|
2
|
-
import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-
|
|
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-
|
|
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.
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import { g as
|
|
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
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
out.push(
|
|
71
|
-
|
|
72
|
-
if (
|
|
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:
|
|
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
|
|
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 {
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 {
|
|
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 };
|