@agimon-ai/po-workflow 0.0.0-alpha.37 → 0.0.0-alpha.39
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/{RecoverWorkflowService-BLehH1qi.cjs → RecoverWorkflowService-CEYR10KF.cjs} +136 -445
- package/dist/RecoverWorkflowService-CEYR10KF.cjs.map +1 -0
- package/dist/{RecoverWorkflowService-BOCa93OS.mjs → RecoverWorkflowService-CY8wIc3A.mjs} +137 -434
- package/dist/RecoverWorkflowService-CY8wIc3A.mjs.map +1 -0
- package/dist/cli.cjs +94 -1592
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +95 -1593
- package/dist/cli.mjs.map +1 -1
- package/dist/extensions/native.mjs +2 -0
- package/dist/extensions/native.mjs.map +1 -1
- package/dist/extensions/server.cjs +40 -25
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.mjs +40 -25
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +5 -3
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{workflowLaunchCommand-GGqimmTC.mjs → workflowLaunchCommand-7WRoiOKJ.mjs} +5 -3
- package/dist/workflowLaunchCommand-7WRoiOKJ.mjs.map +1 -0
- package/dist/{workflowLaunchCommand-C69Nn3k5.cjs → workflowLaunchCommand-C7anFsDH.cjs} +5 -3
- package/dist/workflowLaunchCommand-C7anFsDH.cjs.map +1 -0
- package/package.json +20 -20
- package/dist/RecoverWorkflowService-BLehH1qi.cjs.map +0 -1
- package/dist/RecoverWorkflowService-BOCa93OS.mjs.map +0 -1
- package/dist/workflowLaunchCommand-C69Nn3k5.cjs.map +0 -1
- package/dist/workflowLaunchCommand-GGqimmTC.mjs.map +0 -1
|
@@ -378,6 +378,7 @@ const StepFieldsSchema = zod.z.object({
|
|
|
378
378
|
artifacts: StepArtifactsSchema.optional(),
|
|
379
379
|
"timeout-minutes": zod.z.number().optional(),
|
|
380
380
|
env: CoercedEnvRecord.optional(),
|
|
381
|
+
secrets: zod.z.array(zod.z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "Secret names are environment variable names.")).min(1).optional().describe("Env names a run step's command receives from its Po profile; values never reach logs or run records."),
|
|
381
382
|
with: zod.z.record(zod.z.string(), zod.z.string()).optional(),
|
|
382
383
|
"working-directory": zod.z.string().optional(),
|
|
383
384
|
if: zod.z.string().optional(),
|
|
@@ -418,6 +419,11 @@ function refineStep(step, context) {
|
|
|
418
419
|
message: `${key} is only supported with a templated interactiveRun.`,
|
|
419
420
|
path: [key]
|
|
420
421
|
});
|
|
422
|
+
if (step.secrets !== void 0 && (step.run === void 0 || step.interactiveRun || step.customRun)) context.addIssue({
|
|
423
|
+
code: "custom",
|
|
424
|
+
message: "secrets are only supported on run steps.",
|
|
425
|
+
path: ["secrets"]
|
|
426
|
+
});
|
|
421
427
|
if (step["restart-from"] !== void 0 && (step.run === void 0 || step.interactiveRun || step.customRun)) context.addIssue({
|
|
422
428
|
code: "custom",
|
|
423
429
|
message: "restart-from is only supported on run steps.",
|
|
@@ -750,6 +756,7 @@ const WorkflowLauncherMetadataSchema = zod.z.discriminatedUnion("type", [
|
|
|
750
756
|
]);
|
|
751
757
|
const WorkflowRunRecordSchema = zod.z.object({
|
|
752
758
|
activeRepairId: zod.z.string().regex(/^\d+$/).optional(),
|
|
759
|
+
/** Read-only legacy metadata. New runs only write runner. */
|
|
753
760
|
cliAgent: zod.z.string().optional(),
|
|
754
761
|
continueOnError: zod.z.boolean().optional(),
|
|
755
762
|
displayName: zod.z.string(),
|
|
@@ -773,6 +780,7 @@ const WorkflowRunRecordSchema = zod.z.object({
|
|
|
773
780
|
runner: zod.z.string().optional(),
|
|
774
781
|
command: zod.z.string().optional().describe("Command the launch selected for templated interactiveRun steps."),
|
|
775
782
|
choice: zod.z.string().optional().describe("Choice the launch selected for steps that do not pin one."),
|
|
783
|
+
profile: zod.z.string().optional().describe("Po profile name the launch selected as the default runConfig.profile; never its secrets."),
|
|
776
784
|
runId: zod.z.string().uuid().optional(),
|
|
777
785
|
runKey: zod.z.string(),
|
|
778
786
|
secretFile: zod.z.string().optional(),
|
|
@@ -4745,7 +4753,6 @@ var WorkflowRegistryService = class {
|
|
|
4745
4753
|
const runId = (0, node_crypto.randomUUID)();
|
|
4746
4754
|
const runRecord = {
|
|
4747
4755
|
activeRepairId: input.activeRepairId,
|
|
4748
|
-
cliAgent: input.cliAgent,
|
|
4749
4756
|
continueOnError: input.continueOnError,
|
|
4750
4757
|
displayName: input.displayName,
|
|
4751
4758
|
dryRun: input.dryRun,
|
|
@@ -4759,6 +4766,7 @@ var WorkflowRegistryService = class {
|
|
|
4759
4766
|
runner: input.runner,
|
|
4760
4767
|
...input.command === void 0 ? {} : { command: input.command },
|
|
4761
4768
|
...input.choice === void 0 ? {} : { choice: input.choice },
|
|
4769
|
+
...input.profile === void 0 ? {} : { profile: input.profile },
|
|
4762
4770
|
runDirectory: input.runDirectory,
|
|
4763
4771
|
runId,
|
|
4764
4772
|
secretFile: input.secretFile,
|
|
@@ -6425,127 +6433,6 @@ const MAX_STEP_TIMEOUT_MINUTES = Math.floor(2147483647 / 6e4);
|
|
|
6425
6433
|
const StepTimeoutMinutesSchema = zod.z.number().positive().finite().max(MAX_STEP_TIMEOUT_MINUTES);
|
|
6426
6434
|
const StepTimeoutRetriesSchema = zod.z.number().int().min(0).max(STEP_TIMEOUT_RETRIES_LIMIT).default(STEP_TIMEOUT_MAX_RETRIES);
|
|
6427
6435
|
//#endregion
|
|
6428
|
-
//#region src/services/CodexQuotaService/index.ts
|
|
6429
|
-
/**
|
|
6430
|
-
* CodexQuotaService
|
|
6431
|
-
*
|
|
6432
|
-
* DESIGN PATTERNS:
|
|
6433
|
-
* - Service pattern for business logic encapsulation
|
|
6434
|
-
* - Single responsibility principle
|
|
6435
|
-
*
|
|
6436
|
-
* CODING STANDARDS:
|
|
6437
|
-
* - Use async/await for asynchronous operations
|
|
6438
|
-
* - Throw descriptive errors for error cases
|
|
6439
|
-
* - Keep methods focused and well-named
|
|
6440
|
-
* - Document complex logic with comments
|
|
6441
|
-
*
|
|
6442
|
-
* AVOID:
|
|
6443
|
-
* - Mixing concerns (keep focused on single domain)
|
|
6444
|
-
* - Direct tool implementation (services should be tool-agnostic)
|
|
6445
|
-
*/
|
|
6446
|
-
const DEFAULT_CODEX_HOME_DIRNAME = ".codex";
|
|
6447
|
-
const AUTH_FILENAME = "auth.json";
|
|
6448
|
-
const CONFIG_FILENAME = "config.toml";
|
|
6449
|
-
const DEFAULT_CHATGPT_BASE_URL = "https://chatgpt.com/backend-api/";
|
|
6450
|
-
const CHATGPT_HOST = "https://chatgpt.com";
|
|
6451
|
-
const CHAT_OPENAI_HOST = "https://chat.openai.com";
|
|
6452
|
-
const BACKEND_API_SEGMENT = "/backend-api";
|
|
6453
|
-
const QUOTA_USER_AGENT = "codex-cli";
|
|
6454
|
-
const PRIMARY_WINDOW = "primary";
|
|
6455
|
-
const SECONDARY_WINDOW = "secondary";
|
|
6456
|
-
const QUOTA_REACHED_PERCENT = 100;
|
|
6457
|
-
var CodexQuotaService = class {
|
|
6458
|
-
codexHome;
|
|
6459
|
-
fetchFn;
|
|
6460
|
-
now;
|
|
6461
|
-
readTextFile;
|
|
6462
|
-
constructor(runtime, deps = {}) {
|
|
6463
|
-
this.codexHome = deps.codexHome ?? runtime.baseEnvironment.CODEX_HOME ?? (0, node_path.join)(runtime.homeDirectory, DEFAULT_CODEX_HOME_DIRNAME);
|
|
6464
|
-
this.fetchFn = deps.fetchFn ?? fetch;
|
|
6465
|
-
this.now = deps.now ?? (() => Date.now());
|
|
6466
|
-
this.readTextFile = deps.readTextFile ?? (async (path) => (0, _agimon_ai_po_core_platform.getOrThrow)(await runtime.fs.readTextFile(path, runtime.ioContext)));
|
|
6467
|
-
}
|
|
6468
|
-
isCodexCommand(command, _sourceAgentKey) {
|
|
6469
|
-
const trimmed = command.trim();
|
|
6470
|
-
return trimmed === "codex" || trimmed.startsWith("codex ");
|
|
6471
|
-
}
|
|
6472
|
-
async getQuotaStatus() {
|
|
6473
|
-
const auth = await this.readAuthFile();
|
|
6474
|
-
const accessToken = auth?.tokens?.access_token?.trim();
|
|
6475
|
-
const accountId = auth?.tokens?.account_id?.trim();
|
|
6476
|
-
if (!accessToken || !accountId) return null;
|
|
6477
|
-
const baseUrl = await this.readChatgptBaseUrl();
|
|
6478
|
-
const response = await this.fetchFn(this.buildUsageUrl(baseUrl), { headers: {
|
|
6479
|
-
Authorization: `Bearer ${accessToken}`,
|
|
6480
|
-
"ChatGPT-Account-Id": accountId,
|
|
6481
|
-
"User-Agent": QUOTA_USER_AGENT
|
|
6482
|
-
} });
|
|
6483
|
-
if (!response.ok) throw new Error(`codex quota request failed with HTTP ${response.status}`);
|
|
6484
|
-
const payload = await response.json();
|
|
6485
|
-
return {
|
|
6486
|
-
blockingLimit: this.findBlockingLimit(payload),
|
|
6487
|
-
planType: payload.plan_type ?? null
|
|
6488
|
-
};
|
|
6489
|
-
}
|
|
6490
|
-
async readAuthFile() {
|
|
6491
|
-
const raw = await this.readOptionalTextFile((0, node_path.join)(this.codexHome, AUTH_FILENAME));
|
|
6492
|
-
if (!raw) return null;
|
|
6493
|
-
return JSON.parse(raw);
|
|
6494
|
-
}
|
|
6495
|
-
async readChatgptBaseUrl() {
|
|
6496
|
-
const match = (await this.readOptionalTextFile((0, node_path.join)(this.codexHome, CONFIG_FILENAME)))?.match(/^\s*chatgpt_base_url\s*=\s*"([^"]+)"/m);
|
|
6497
|
-
return this.normalizeBaseUrl(match?.[1] ?? DEFAULT_CHATGPT_BASE_URL);
|
|
6498
|
-
}
|
|
6499
|
-
buildUsageUrl(baseUrl) {
|
|
6500
|
-
return baseUrl.includes(BACKEND_API_SEGMENT) ? `${baseUrl}/wham/usage` : `${baseUrl}/api/codex/usage`;
|
|
6501
|
-
}
|
|
6502
|
-
normalizeBaseUrl(baseUrl) {
|
|
6503
|
-
let normalized = baseUrl.trim().replace(/\/+$/, "");
|
|
6504
|
-
if ((normalized.startsWith(CHATGPT_HOST) || normalized.startsWith(CHAT_OPENAI_HOST)) && !normalized.includes(BACKEND_API_SEGMENT)) normalized = `${normalized}${BACKEND_API_SEGMENT}`;
|
|
6505
|
-
return normalized;
|
|
6506
|
-
}
|
|
6507
|
-
async readOptionalTextFile(path) {
|
|
6508
|
-
try {
|
|
6509
|
-
return await this.readTextFile(path);
|
|
6510
|
-
} catch (error) {
|
|
6511
|
-
if (error.code === "ENOENT") return null;
|
|
6512
|
-
throw error;
|
|
6513
|
-
}
|
|
6514
|
-
}
|
|
6515
|
-
findBlockingLimit(payload) {
|
|
6516
|
-
const blocks = [];
|
|
6517
|
-
this.collectBlockingLimit(blocks, "codex", "codex", payload.rate_limit);
|
|
6518
|
-
for (const additionalLimit of payload.additional_rate_limits ?? []) this.collectBlockingLimit(blocks, additionalLimit.metered_feature ?? additionalLimit.limit_name ?? "codex", additionalLimit.limit_name ?? additionalLimit.metered_feature ?? "codex", additionalLimit.rate_limit);
|
|
6519
|
-
blocks.sort((left, right) => left.resetAt - right.resetAt || right.usedPercent - left.usedPercent);
|
|
6520
|
-
return blocks[0] ?? null;
|
|
6521
|
-
}
|
|
6522
|
-
collectBlockingLimit(blocks, limitId, limitName, limit) {
|
|
6523
|
-
if (!limit) return;
|
|
6524
|
-
const windows = [{
|
|
6525
|
-
payload: limit.primary_window,
|
|
6526
|
-
window: PRIMARY_WINDOW
|
|
6527
|
-
}, {
|
|
6528
|
-
payload: limit.secondary_window,
|
|
6529
|
-
window: SECONDARY_WINDOW
|
|
6530
|
-
}];
|
|
6531
|
-
for (const { payload, window } of windows) {
|
|
6532
|
-
const resetAt = payload?.reset_at;
|
|
6533
|
-
const usedPercent = payload?.used_percent ?? 0;
|
|
6534
|
-
if (typeof resetAt !== "number") continue;
|
|
6535
|
-
if (!(usedPercent >= QUOTA_REACHED_PERCENT || limit.limit_reached === true && resetAt * 1e3 > this.now() || limit.allowed === false && resetAt * 1e3 > this.now())) continue;
|
|
6536
|
-
blocks.push({
|
|
6537
|
-
limitId,
|
|
6538
|
-
limitName,
|
|
6539
|
-
resetAfterSeconds: payload?.reset_after_seconds ?? null,
|
|
6540
|
-
resetAt,
|
|
6541
|
-
usedPercent,
|
|
6542
|
-
window,
|
|
6543
|
-
windowSeconds: payload?.limit_window_seconds ?? null
|
|
6544
|
-
});
|
|
6545
|
-
}
|
|
6546
|
-
}
|
|
6547
|
-
};
|
|
6548
|
-
//#endregion
|
|
6549
6436
|
//#region src/services/StepRunnerService/index.ts
|
|
6550
6437
|
/**
|
|
6551
6438
|
* StepRunnerService
|
|
@@ -6620,6 +6507,10 @@ const INTERACTIVE_RUN_KEY = "interactiveRun";
|
|
|
6620
6507
|
const CUSTOM_RUN_KEY = "customRun";
|
|
6621
6508
|
const CUSTOM_RUN_UNSUPPORTED_MESSAGE = "customRun needs a host step executor and no run or interactiveRun fallback exists for step";
|
|
6622
6509
|
const IN_PROCESS_ONLY_UNSUPPORTED_MESSAGE = "has no run template, and this host cannot run it in-process";
|
|
6510
|
+
const SECRETS_UNAVAILABLE_MESSAGE = "profile secrets are unavailable for step";
|
|
6511
|
+
const SECRETS_LOG_PREFIX = "secrets: ";
|
|
6512
|
+
const RUN_CONFIG_PROFILE_KEY = "profile";
|
|
6513
|
+
const REDACTED = "[redacted]";
|
|
6623
6514
|
const WORKFLOW_RUN_CONFIG_ENV_KEY = "WORKFLOW_RUN_CONFIG";
|
|
6624
6515
|
const DEFAULT_CHOICE = "default";
|
|
6625
6516
|
const OUTPUT_TAIL_LINES = 50;
|
|
@@ -6704,38 +6595,35 @@ const WORKFLOW_STEP_NAME_ENV_KEY = "WORKFLOW_STEP_NAME";
|
|
|
6704
6595
|
const WORKFLOW_STEP_DISPLAY_ENV_KEY = "WORKFLOW_STEP_DISPLAY";
|
|
6705
6596
|
const WORKFLOW_STEP_ARTIFACTS_ENV_KEY = "WORKFLOW_STEP_ARTIFACTS";
|
|
6706
6597
|
const WORKFLOW_TERMINAL_TITLE = "workflow-mcp";
|
|
6707
|
-
const STATUS_FILE_PREFIX = "workflow-step-";
|
|
6708
|
-
const STATUS_FILE_SUFFIX = ".status";
|
|
6709
|
-
const STATUS_FILE_COMPLETION_VALUE = "YES";
|
|
6710
|
-
const STATUS_FILE_COMPLETED_RESULT = { status: "status_completed" };
|
|
6711
|
-
const TRANSIENT_FS_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
6712
|
-
"ENOENT",
|
|
6713
|
-
"EBUSY",
|
|
6714
|
-
"EAGAIN",
|
|
6715
|
-
"EPERM",
|
|
6716
|
-
"not_found"
|
|
6717
|
-
]);
|
|
6718
|
-
const STATUS_FILE_POLL_INTERVAL_MS = 1e3;
|
|
6719
6598
|
const STOP_REQUEST_POLL_INTERVAL_MS = 1e3;
|
|
6720
|
-
const STATUS_DONE = "done";
|
|
6721
6599
|
const STATUS_STOP = "stop";
|
|
6722
6600
|
const EXPLICIT_RUNNER_MISSING_PREFIX = "runner";
|
|
6723
6601
|
const EXPLICIT_RUNNER_MISSING_MIDDLE = "not found for step";
|
|
6724
6602
|
const EXPLICIT_RUNNER_AVAILABLE_PREFIX = "available runner keys:";
|
|
6725
|
-
const QUOTA_WAIT_POLL_INTERVAL_MS = 3e4;
|
|
6726
|
-
const QUOTA_WAIT_RESET_BUFFER_MS = 1e3;
|
|
6727
|
-
const QUOTA_WAIT_SOURCE = "StepRunnerService.waitForCodexQuota";
|
|
6728
|
-
const QUOTA_RETRY_REASON = "codex quota reached after failed step, retrying after reset";
|
|
6729
6603
|
const RESULT_STATUS_COMPLETED = "completed";
|
|
6730
6604
|
const RESULT_STATUS_SPAWN_ERROR = "spawn_error";
|
|
6731
6605
|
const RESULT_STATUS_SIGNALED = "signaled";
|
|
6732
6606
|
const RESULT_STATUS_TIMED_OUT = "timed_out";
|
|
6733
|
-
const RESULT_STATUS_STATUS_COMPLETED = "status_completed";
|
|
6734
6607
|
const RESULT_STATUS_STOP_REQUESTED = "stop_requested";
|
|
6735
6608
|
const RESULT_STATUS_PAUSE_REQUESTED = "pause_requested";
|
|
6736
6609
|
/** The reason a step failure carries when nothing more specific was recorded. */
|
|
6737
6610
|
const STEP_FAILED_REASON = "The step failed.";
|
|
6738
6611
|
/**
|
|
6612
|
+
* Mask each secret value in step output, in its raw, JSON-escaped and
|
|
6613
|
+
* URL-encoded forms, and line by line for a value that spans lines.
|
|
6614
|
+
*/
|
|
6615
|
+
function secretRedactor(values) {
|
|
6616
|
+
const forms = /* @__PURE__ */ new Set();
|
|
6617
|
+
for (const value of values) for (const form of [
|
|
6618
|
+
value,
|
|
6619
|
+
JSON.stringify(value).slice(1, -1),
|
|
6620
|
+
encodeURIComponent(value),
|
|
6621
|
+
...value.split("\n")
|
|
6622
|
+
]) if (form) forms.add(form);
|
|
6623
|
+
const longestFirst = [...forms].sort((left, right) => right.length - left.length);
|
|
6624
|
+
return (text) => longestFirst.reduce((current, form) => current.split(form).join(REDACTED), text);
|
|
6625
|
+
}
|
|
6626
|
+
/**
|
|
6739
6627
|
* Executes workflow steps in child processes and tracks the active process so
|
|
6740
6628
|
* the workflow runner can interrupt it safely.
|
|
6741
6629
|
*
|
|
@@ -6748,16 +6636,15 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6748
6636
|
runtime;
|
|
6749
6637
|
parser;
|
|
6750
6638
|
logger;
|
|
6751
|
-
|
|
6752
|
-
watchStatusFile;
|
|
6639
|
+
watchControlFile;
|
|
6753
6640
|
runDirectoryService;
|
|
6754
6641
|
ownsTerminal;
|
|
6755
6642
|
stepExecutor;
|
|
6643
|
+
resolveSecrets;
|
|
6756
6644
|
activeStep = null;
|
|
6757
6645
|
activeExternal = null;
|
|
6758
6646
|
lastInteractiveReap = null;
|
|
6759
6647
|
interruptedSignal = null;
|
|
6760
|
-
activeQuotaWait = null;
|
|
6761
6648
|
commandSelection = {};
|
|
6762
6649
|
/** Runners of a parallel group's steps, which a stop must reach too. */
|
|
6763
6650
|
forks = /* @__PURE__ */ new Set();
|
|
@@ -6772,15 +6659,15 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6772
6659
|
* must not hand a step's stdin to it, and must not `stty` or reset it
|
|
6773
6660
|
* afterwards, however cooperative the intent.
|
|
6774
6661
|
*/
|
|
6775
|
-
constructor(runtime, parser, logger,
|
|
6662
|
+
constructor(runtime, parser, logger, watchControlFile = runtime.fs.watch.bind(runtime.fs), runDirectoryService = new RunDirectoryService(runtime), ownsTerminal = true, stepExecutor, resolveSecrets) {
|
|
6776
6663
|
this.runtime = runtime;
|
|
6777
6664
|
this.parser = parser;
|
|
6778
6665
|
this.logger = logger;
|
|
6779
|
-
this.
|
|
6780
|
-
this.watchStatusFile = watchStatusFile;
|
|
6666
|
+
this.watchControlFile = watchControlFile;
|
|
6781
6667
|
this.runDirectoryService = runDirectoryService;
|
|
6782
6668
|
this.ownsTerminal = ownsTerminal;
|
|
6783
6669
|
this.stepExecutor = stepExecutor;
|
|
6670
|
+
this.resolveSecrets = resolveSecrets;
|
|
6784
6671
|
}
|
|
6785
6672
|
/**
|
|
6786
6673
|
* Use a workflow's command templates and choices, and what the launch
|
|
@@ -6797,7 +6684,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6797
6684
|
* Release it once its step has finished.
|
|
6798
6685
|
*/
|
|
6799
6686
|
fork(label) {
|
|
6800
|
-
const child = new StepRunnerService(this.runtime, this.parser, labelledLogger(this.logger, label), this.
|
|
6687
|
+
const child = new StepRunnerService(this.runtime, this.parser, labelledLogger(this.logger, label), this.watchControlFile, this.runDirectoryService, this.ownsTerminal, this.stepExecutor, this.resolveSecrets);
|
|
6801
6688
|
child.commandSelection = this.commandSelection;
|
|
6802
6689
|
child.interruptedSignal = this.interruptedSignal;
|
|
6803
6690
|
child.terminalLock = this.terminalLock;
|
|
@@ -6822,16 +6709,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6822
6709
|
for (const child of this.forks) child.stopActiveStep(signal);
|
|
6823
6710
|
return;
|
|
6824
6711
|
}
|
|
6825
|
-
if (this.activeQuotaWait) {
|
|
6826
|
-
if (this.activeQuotaWait.controller.signal.aborted) {
|
|
6827
|
-
this.logger.info(` ${DIM$3}${STATUS_SKIP}${RESET$3} ${this.activeQuotaWait.stepName} ${ALREADY_STOPPING_SUFFIX}`);
|
|
6828
|
-
return;
|
|
6829
|
-
}
|
|
6830
|
-
this.activeQuotaWait.signal = signal;
|
|
6831
|
-
this.activeQuotaWait.controller.abort();
|
|
6832
|
-
this.logger.info(` ${YELLOW$2}${STATUS_INTERRUPTED}${RESET$3} cancelling quota wait for ${this.activeQuotaWait.stepName}`);
|
|
6833
|
-
return;
|
|
6834
|
-
}
|
|
6835
6712
|
if (this.activeExternal) {
|
|
6836
6713
|
if (this.activeExternal.stopSignal) {
|
|
6837
6714
|
this.logger.info(` ${DIM$3}${STATUS_SKIP}${RESET$3} ${this.activeExternal.stepName} ${ALREADY_STOPPING_SUFFIX}`);
|
|
@@ -6930,7 +6807,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6930
6807
|
return false;
|
|
6931
6808
|
}
|
|
6932
6809
|
const { command, custom, inProcessOnly, interactive, template } = resolvedStepCommand;
|
|
6933
|
-
const isCodexCommand = this.quotaService.isCodexCommand(command, resolvedStepCommand.agentKey);
|
|
6934
6810
|
const shouldContinue = step["continue-on-error"] || options.continueOnError;
|
|
6935
6811
|
let timeoutMs;
|
|
6936
6812
|
try {
|
|
@@ -6964,7 +6840,12 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6964
6840
|
stepEnv[PROJECT_PATH_ENV_KEY] = workDir;
|
|
6965
6841
|
stepEnv[WORKFLOW_STEP_NAME_ENV_KEY] = stepName;
|
|
6966
6842
|
stepEnv[WORKFLOW_STEP_DISPLAY_ENV_KEY] = this.formatStepDisplay(stepEnv[WORKFLOW_JOB_NAME_ENV_KEY], stepName);
|
|
6967
|
-
const
|
|
6843
|
+
const stepRunConfig = resolvedStepCommand?.runConfig ?? step.runConfig;
|
|
6844
|
+
const launchProfile = this.commandSelection.profile;
|
|
6845
|
+
const runConfig = launchProfile === void 0 || stepRunConfig?.[RUN_CONFIG_PROFILE_KEY] !== void 0 ? stepRunConfig : {
|
|
6846
|
+
...stepRunConfig,
|
|
6847
|
+
[RUN_CONFIG_PROFILE_KEY]: launchProfile
|
|
6848
|
+
};
|
|
6968
6849
|
stepEnv[WORKFLOW_RUN_CONFIG_ENV_KEY] = JSON.stringify(runConfig ?? {});
|
|
6969
6850
|
if (step.if !== void 0 && !options.dryRun) {
|
|
6970
6851
|
const condition = await this.evaluateStepCondition(step.if, stepContext, workDir, stepEnv, stepName, timeoutMs);
|
|
@@ -7015,15 +6896,11 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7015
6896
|
}
|
|
7016
6897
|
const stepStartedAt = Date.now();
|
|
7017
6898
|
await this.logStepLifecycle("info", "workflow.step.started", stepEnv, { "workflow.step.interactive": interactive });
|
|
7018
|
-
|
|
7019
|
-
if (interactive) {
|
|
7020
|
-
statusFilePath = await this.createStatusFile();
|
|
7021
|
-
stepEnv[STATUS_FILE_ENV_KEY] = statusFilePath;
|
|
7022
|
-
this.logger.info(` ${DIM$3}status-file${RESET$3} ${statusFilePath}`);
|
|
7023
|
-
} else delete stepEnv[STATUS_FILE_ENV_KEY];
|
|
6899
|
+
delete stepEnv[STATUS_FILE_ENV_KEY];
|
|
7024
6900
|
if (options.dryRun) {
|
|
7025
6901
|
this.logger.info(` ${CYAN$2}${STATUS_DRY}${RESET$3} ${stepName}`);
|
|
7026
6902
|
this.logger.info(`${COMMAND_LOG_INDENT}${DIM$3}${COMMAND_LOG_PROMPT}${command.split(COMMAND_LINE_BREAK).join(COMMAND_LOG_CONTINUATION)}${RESET$3}`);
|
|
6903
|
+
if (step.secrets !== void 0 && step.secrets.length > 0) this.logger.info(`${COMMAND_LOG_INDENT}${DIM$3}${SECRETS_LOG_PREFIX}${step.secrets.join(", ")}${RESET$3}`);
|
|
7027
6904
|
await this.logStepLifecycle("info", "workflow.step.finished", stepEnv, {
|
|
7028
6905
|
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
7029
6906
|
"workflow.step.outcome": "dry-run"
|
|
@@ -7055,9 +6932,20 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7055
6932
|
this.logger.error(` ${RED$2}${STATUS_FAIL}${RESET$3} ${stepName}\n`);
|
|
7056
6933
|
return false;
|
|
7057
6934
|
}
|
|
7058
|
-
let
|
|
6935
|
+
let secretEnv;
|
|
6936
|
+
if (step.secrets !== void 0 && step.secrets.length > 0) {
|
|
6937
|
+
secretEnv = await this.resolveStepSecrets(step.secrets, runConfig, interactive || custom !== void 0 || inProcessOnly === true);
|
|
6938
|
+
if (secretEnv === void 0) {
|
|
6939
|
+
fail(`${SECRETS_UNAVAILABLE_MESSAGE} "${stepName}"`);
|
|
6940
|
+
if (shouldContinue) {
|
|
6941
|
+
this.logger.warn(` ${YELLOW$2}${STATUS_FAIL}${RESET$3} ${stepName} ${CONTINUE_ON_ERROR_SUFFIX}\n`);
|
|
6942
|
+
return true;
|
|
6943
|
+
}
|
|
6944
|
+
this.logger.error(` ${RED$2}${STATUS_FAIL}${RESET$3} ${stepName}\n`);
|
|
6945
|
+
return false;
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
7059
6948
|
for (let attempt = 0; attempt <= maxTimeoutRetries; attempt++) {
|
|
7060
|
-
await this.waitForCodexQuotaAvailability(stepName, command, isCodexCommand);
|
|
7061
6949
|
if (decisionFilePath && decisionIdentity) await resetDecisionFile(this.runtime, decisionFilePath, decisionIdentity);
|
|
7062
6950
|
if (attempt > 0) this.logger.warn(` ${YELLOW$2}${STATUS_RETRY}${RESET$3} ${STEP_TIMEOUT_RETRY_PREFIX} "${stepName}" (attempt ${attempt + 1}/${maxTimeoutRetries + 1})`);
|
|
7063
6951
|
else this.logger.info(` ${CYAN$2}${STATUS_RUN}${RESET$3} ${stepName}`);
|
|
@@ -7082,6 +6970,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7082
6970
|
interactive,
|
|
7083
6971
|
onExecutionStarted: options.onExecutionStarted,
|
|
7084
6972
|
runConfig,
|
|
6973
|
+
secretEnv,
|
|
7085
6974
|
stepEnv,
|
|
7086
6975
|
stepName,
|
|
7087
6976
|
jobEnvironment: this.definedEnv({
|
|
@@ -7093,7 +6982,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7093
6982
|
timeoutMs,
|
|
7094
6983
|
workDir
|
|
7095
6984
|
}));
|
|
7096
|
-
const executionResult = interactive
|
|
6985
|
+
const executionResult = interactive ? await this.raceInteractiveCompletion(executionPromise, stepName, options.stopRequestPath, step["pause-policy"] ?? "replay") : options.stopRequestPath ? await this.raceStopRequest(executionPromise, stepName, options.stopRequestPath, step["pause-policy"] ?? "replay") : await executionPromise;
|
|
7097
6986
|
if (executionResult.status === RESULT_STATUS_PAUSE_REQUESTED) {
|
|
7098
6987
|
await this.logStepLifecycle("info", "workflow.step.pause_requested", stepEnv, {
|
|
7099
6988
|
"workflow.step.outcome": pausePolicy === "replay" ? "cancelled_for_pause" : "protected_boundary",
|
|
@@ -7150,7 +7039,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7150
7039
|
}
|
|
7151
7040
|
const decision = decisionFilePath ? await readStepDecision(this.runtime, decisionFilePath) : void 0;
|
|
7152
7041
|
if (decision) {
|
|
7153
|
-
if (statusFilePath) await this.cleanupStatusFile(statusFilePath);
|
|
7154
7042
|
if (decision.decision === "complete") {
|
|
7155
7043
|
const artifactProblem = artifactSnapshots ? await this.describeArtifactWarnings(stepEnv, artifactSnapshots) : void 0;
|
|
7156
7044
|
if (!artifactProblem) {
|
|
@@ -7184,15 +7072,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7184
7072
|
}
|
|
7185
7073
|
if (executionResult.status === "timed_out") {
|
|
7186
7074
|
fail(`${STEP_TIMEOUT_FAILURE_PREFIX} ${this.formatTimeoutMs(executionResult.timeoutMs)} "${stepName}" (${command.split(COMMAND_LINE_BREAK)[0]})`);
|
|
7187
|
-
if (attempt < maxTimeoutRetries)
|
|
7188
|
-
if (statusFilePath) try {
|
|
7189
|
-
(0, _agimon_ai_po_core_platform.getOrThrow)(await this.runtime.fs.writeFile(statusFilePath, "", this.runtime.ioContext));
|
|
7190
|
-
} catch (error) {
|
|
7191
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file reset failed for ${stepName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
7192
|
-
}
|
|
7193
|
-
continue;
|
|
7194
|
-
}
|
|
7195
|
-
if (statusFilePath) await this.cleanupStatusFile(statusFilePath);
|
|
7075
|
+
if (attempt < maxTimeoutRetries) continue;
|
|
7196
7076
|
if (shouldContinue) {
|
|
7197
7077
|
await this.logStepLifecycle("warn", "workflow.step.finished", stepEnv, {
|
|
7198
7078
|
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
@@ -7209,7 +7089,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7209
7089
|
});
|
|
7210
7090
|
return false;
|
|
7211
7091
|
}
|
|
7212
|
-
if (statusFilePath) await this.cleanupStatusFile(statusFilePath);
|
|
7213
7092
|
if (decisionIdentity?.required && !(executionResult.status === "completed" && executionResult.failure !== void 0)) {
|
|
7214
7093
|
fail(`step "${stepName}" ended without a workflow decision (workflow-mcp step complete|fix|fail)`);
|
|
7215
7094
|
return this.failStep(stepName, stepEnv, stepStartedAt, shouldContinue, report);
|
|
@@ -7232,19 +7111,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7232
7111
|
});
|
|
7233
7112
|
return true;
|
|
7234
7113
|
}
|
|
7235
|
-
if (executionResult.status === "status_completed") {
|
|
7236
|
-
const artifactProblem = artifactSnapshots ? await this.describeArtifactWarnings(stepEnv, artifactSnapshots) : void 0;
|
|
7237
|
-
if (artifactProblem) {
|
|
7238
|
-
fail(`step "${stepName}" ${artifactProblem}`);
|
|
7239
|
-
return this.failStep(stepName, stepEnv, stepStartedAt, shouldContinue, report);
|
|
7240
|
-
}
|
|
7241
|
-
this.logger.info(`\n ${GREEN$2}${STATUS_DONE}${RESET$3} ${stepName} (status-file signaled completion)\n`);
|
|
7242
|
-
await this.logStepLifecycle("info", "workflow.step.finished", stepEnv, {
|
|
7243
|
-
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
7244
|
-
"workflow.step.outcome": "success"
|
|
7245
|
-
});
|
|
7246
|
-
return true;
|
|
7247
|
-
}
|
|
7248
7114
|
if (executionResult.status === "completed" && executionResult.exitCode === 0) {
|
|
7249
7115
|
const artifactProblem = artifactSnapshots ? await this.describeArtifactWarnings(stepEnv, artifactSnapshots) : void 0;
|
|
7250
7116
|
if (!artifactProblem) {
|
|
@@ -7258,12 +7124,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7258
7124
|
fail(`step "${stepName}" ${artifactProblem}`);
|
|
7259
7125
|
}
|
|
7260
7126
|
if (executionResult.status === "completed" && executionResult.exitCode !== 0) fail(executionResult.failure ? `step "${stepName}" failed: ${executionResult.failure}` : `${STEP_EXIT_FAILURE_PREFIX} "${stepName}" ${STEP_EXIT_FAILURE_MIDDLE} ${executionResult.exitCode} (${command.split(COMMAND_LINE_BREAK)[0]})`);
|
|
7261
|
-
if (!quotaFailureRetried && await this.shouldRetryForCodexQuota(stepName, isCodexCommand)) {
|
|
7262
|
-
quotaFailureRetried = true;
|
|
7263
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_RETRY}${RESET$3} ${QUOTA_RETRY_REASON}`);
|
|
7264
|
-
attempt -= 1;
|
|
7265
|
-
continue;
|
|
7266
|
-
}
|
|
7267
7127
|
if (shouldContinue) {
|
|
7268
7128
|
await this.logStepLifecycle("warn", "workflow.step.finished", stepEnv, {
|
|
7269
7129
|
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
@@ -7342,10 +7202,30 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7342
7202
|
};
|
|
7343
7203
|
}
|
|
7344
7204
|
/**
|
|
7205
|
+
* Resolve a run step's secrets for its child alone, or undefined when they
|
|
7206
|
+
* cannot be: this host has no resolver, the step is not a plain run, no
|
|
7207
|
+
* profile applies, or the resolver fails. The failure stays generic so no
|
|
7208
|
+
* value or alias detail reaches the log.
|
|
7209
|
+
*/
|
|
7210
|
+
async resolveStepSecrets(names, runConfig, hostedStep) {
|
|
7211
|
+
const profile = runConfig?.[RUN_CONFIG_PROFILE_KEY];
|
|
7212
|
+
if (this.resolveSecrets === void 0 || hostedStep || typeof profile !== "string" || profile === "") return;
|
|
7213
|
+
try {
|
|
7214
|
+
return await this.resolveSecrets({
|
|
7215
|
+
cwd: this.runtime.cwd,
|
|
7216
|
+
profile,
|
|
7217
|
+
names
|
|
7218
|
+
});
|
|
7219
|
+
} catch {
|
|
7220
|
+
return;
|
|
7221
|
+
}
|
|
7222
|
+
}
|
|
7223
|
+
/**
|
|
7345
7224
|
* Spawn a child shell for the step command and normalize its termination
|
|
7346
7225
|
* into a typed result.
|
|
7347
7226
|
*/
|
|
7348
|
-
async executeCommand(command, workDir, stepEnv, stepName, interactive, timeoutMs) {
|
|
7227
|
+
async executeCommand(command, workDir, stepEnv, stepName, interactive, timeoutMs, secretEnv) {
|
|
7228
|
+
const redact = secretEnv === void 0 ? void 0 : secretRedactor(Object.values(secretEnv));
|
|
7349
7229
|
if (interactive) this.logger.info(` ${DIM$3}${INTERACTIVE_OUTPUT_NOTICE}${RESET$3}`);
|
|
7350
7230
|
return await new Promise((resolveResult) => {
|
|
7351
7231
|
const terminalState = interactive ? this.captureTerminalState() : null;
|
|
@@ -7372,6 +7252,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7372
7252
|
detached: this.runtime.workflowHost.platform !== PLATFORM_WINDOWS,
|
|
7373
7253
|
env: {
|
|
7374
7254
|
...stepEnv,
|
|
7255
|
+
...secretEnv,
|
|
7375
7256
|
[FORCE_COLOR_KEY]: FORCE_COLOR_VALUE
|
|
7376
7257
|
},
|
|
7377
7258
|
shell: DEFAULT_SHELL
|
|
@@ -7439,18 +7320,30 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7439
7320
|
outputTail.push(line);
|
|
7440
7321
|
if (outputTail.length > OUTPUT_TAIL_LINES) outputTail.shift();
|
|
7441
7322
|
};
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7323
|
+
const lineReader = (emit) => {
|
|
7324
|
+
let pending = "";
|
|
7325
|
+
const show = (line) => {
|
|
7326
|
+
if (!line) return;
|
|
7327
|
+
const shown = redact === void 0 ? line : redact(line);
|
|
7328
|
+
keep(shown);
|
|
7329
|
+
emit(shown);
|
|
7330
|
+
};
|
|
7331
|
+
return {
|
|
7332
|
+
push: (data) => {
|
|
7333
|
+
const lines = (pending + data.toString()).split("\n");
|
|
7334
|
+
pending = redact === void 0 ? "" : lines.pop() ?? "";
|
|
7335
|
+
for (const line of lines) show(line);
|
|
7336
|
+
},
|
|
7337
|
+
flush: () => {
|
|
7338
|
+
show(pending);
|
|
7339
|
+
pending = "";
|
|
7340
|
+
}
|
|
7341
|
+
};
|
|
7342
|
+
};
|
|
7343
|
+
const stdout = lineReader((line) => this.logger.info(line));
|
|
7344
|
+
const stderr = lineReader((line) => this.logger.error(line));
|
|
7345
|
+
child.stdout?.on("data", stdout.push);
|
|
7346
|
+
child.stderr?.on("data", stderr.push);
|
|
7454
7347
|
child.on("error", (error) => {
|
|
7455
7348
|
settle({
|
|
7456
7349
|
status: "spawn_error",
|
|
@@ -7465,6 +7358,8 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7465
7358
|
child.on("exit", async (code, signal) => {
|
|
7466
7359
|
if (!interactive) await this.cleanupProcessGroup();
|
|
7467
7360
|
await outputDrained(child);
|
|
7361
|
+
stdout.flush();
|
|
7362
|
+
stderr.flush();
|
|
7468
7363
|
if (timedOut && timeoutMs !== null) {
|
|
7469
7364
|
settle({
|
|
7470
7365
|
status: "timed_out",
|
|
@@ -7506,6 +7401,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7506
7401
|
*/
|
|
7507
7402
|
startStepExecution(request) {
|
|
7508
7403
|
const { command, custom, inProcessOnly, interactive, stepEnv, stepName, template, timeoutMs, workDir } = request;
|
|
7404
|
+
if (request.secretEnv !== void 0) return this.executeCommand(command, workDir, stepEnv, stepName, false, timeoutMs, request.secretEnv);
|
|
7509
7405
|
const executor = this.stepExecutor;
|
|
7510
7406
|
const base = {
|
|
7511
7407
|
traceparent: request.traceparent,
|
|
@@ -7572,7 +7468,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7572
7468
|
/**
|
|
7573
7469
|
* Await a host-owned execution and normalize it like a child process.
|
|
7574
7470
|
*
|
|
7575
|
-
* The engine keeps ownership of the timeout; stop
|
|
7471
|
+
* The engine keeps ownership of the timeout; stop and pause
|
|
7576
7472
|
* completion reach the execution through `killActiveStep`, which calls its
|
|
7577
7473
|
* `stop`. A stopped execution reads as signalled so shutdown still interrupts
|
|
7578
7474
|
* the workflow, while the completion races report their own outcome.
|
|
@@ -7895,7 +7791,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7895
7791
|
return [...keys];
|
|
7896
7792
|
}
|
|
7897
7793
|
resolveRunner(options) {
|
|
7898
|
-
return options.runner
|
|
7794
|
+
return options.runner;
|
|
7899
7795
|
}
|
|
7900
7796
|
formatStepDisplay(jobName, stepName) {
|
|
7901
7797
|
return jobName ? `${jobName} > ${stepName}` : stepName;
|
|
@@ -7910,77 +7806,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7910
7806
|
escapeShellArg(value) {
|
|
7911
7807
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
7912
7808
|
}
|
|
7913
|
-
async shouldRetryForCodexQuota(stepName, isCodexCommand) {
|
|
7914
|
-
if (!isCodexCommand) return false;
|
|
7915
|
-
return (await this.readCodexQuotaStatus(stepName))?.blockingLimit != null;
|
|
7916
|
-
}
|
|
7917
|
-
async waitForCodexQuotaAvailability(stepName, command, isCodexCommand) {
|
|
7918
|
-
if (!isCodexCommand) return;
|
|
7919
|
-
while (true) {
|
|
7920
|
-
const quotaStatus = await this.readCodexQuotaStatus(stepName);
|
|
7921
|
-
const blockingLimit = quotaStatus?.blockingLimit;
|
|
7922
|
-
if (!blockingLimit) return;
|
|
7923
|
-
const waitTargetMs = blockingLimit.resetAt * 1e3 + QUOTA_WAIT_RESET_BUFFER_MS;
|
|
7924
|
-
const remainingMs = Math.max(waitTargetMs - Date.now(), QUOTA_WAIT_RESET_BUFFER_MS);
|
|
7925
|
-
const waitDescription = new Date(waitTargetMs).toLocaleString();
|
|
7926
|
-
const planSuffix = quotaStatus?.planType ? ` (${quotaStatus.planType})` : "";
|
|
7927
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WAIT}${RESET$3} codex quota ${blockingLimit.limitName}/${blockingLimit.window} is at ${blockingLimit.usedPercent}%${planSuffix}; waiting until ${waitDescription}`);
|
|
7928
|
-
await this.waitForQuotaDelay(stepName, command, remainingMs);
|
|
7929
|
-
}
|
|
7930
|
-
}
|
|
7931
|
-
async readCodexQuotaStatus(stepName) {
|
|
7932
|
-
try {
|
|
7933
|
-
return await this.quotaService.getQuotaStatus();
|
|
7934
|
-
} catch (error) {
|
|
7935
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} unable to read codex quota for "${stepName}" (${this.formatQuotaError(error)})`);
|
|
7936
|
-
return null;
|
|
7937
|
-
}
|
|
7938
|
-
}
|
|
7939
|
-
async waitForQuotaDelay(stepName, command, remainingMs) {
|
|
7940
|
-
const controller = new AbortController();
|
|
7941
|
-
this.activeQuotaWait = {
|
|
7942
|
-
controller,
|
|
7943
|
-
signal: null,
|
|
7944
|
-
stepName
|
|
7945
|
-
};
|
|
7946
|
-
try {
|
|
7947
|
-
let timeLeftMs = remainingMs;
|
|
7948
|
-
while (timeLeftMs > 0) {
|
|
7949
|
-
const sleepMs = Math.min(timeLeftMs, QUOTA_WAIT_POLL_INTERVAL_MS);
|
|
7950
|
-
await this.waitForDelay(sleepMs, controller.signal);
|
|
7951
|
-
timeLeftMs -= sleepMs;
|
|
7952
|
-
}
|
|
7953
|
-
} catch (error) {
|
|
7954
|
-
if (controller.signal.aborted) throw new WorkflowInterruptedError(this.activeQuotaWait?.signal ?? TERMINATE_SIGNAL$1, {
|
|
7955
|
-
cause: /* @__PURE__ */ new Error(`Interrupted while waiting for Codex quota reset`),
|
|
7956
|
-
context: {
|
|
7957
|
-
...this.createInterruptContext(stepName, command),
|
|
7958
|
-
phase: QUOTA_WAIT_SOURCE
|
|
7959
|
-
}
|
|
7960
|
-
});
|
|
7961
|
-
throw error;
|
|
7962
|
-
} finally {
|
|
7963
|
-
this.activeQuotaWait = null;
|
|
7964
|
-
}
|
|
7965
|
-
}
|
|
7966
|
-
async waitForDelay(delayMs, signal) {
|
|
7967
|
-
await new Promise((resolveDelay, rejectDelay) => {
|
|
7968
|
-
const timeout = setTimeout(() => {
|
|
7969
|
-
signal.removeEventListener("abort", onAbort);
|
|
7970
|
-
resolveDelay();
|
|
7971
|
-
}, delayMs);
|
|
7972
|
-
const onAbort = () => {
|
|
7973
|
-
clearTimeout(timeout);
|
|
7974
|
-
signal.removeEventListener("abort", onAbort);
|
|
7975
|
-
rejectDelay(/* @__PURE__ */ new Error("aborted"));
|
|
7976
|
-
};
|
|
7977
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
7978
|
-
});
|
|
7979
|
-
}
|
|
7980
|
-
formatQuotaError(error) {
|
|
7981
|
-
if (error instanceof Error && error.message.trim().length > 0) return error.message;
|
|
7982
|
-
return "unknown quota error";
|
|
7983
|
-
}
|
|
7984
7809
|
/**
|
|
7985
7810
|
* Resolve the per-step timeout from workflow YAML into milliseconds.
|
|
7986
7811
|
*/
|
|
@@ -8125,10 +7950,8 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8125
7950
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : PROCESS_EXIT_WAIT_TIMEOUT_MS;
|
|
8126
7951
|
}
|
|
8127
7952
|
/**
|
|
8128
|
-
*
|
|
8129
|
-
*
|
|
8130
|
-
* interactive agent can flush its final telemetry batch (e.g. Claude Code's
|
|
8131
|
-
* OTEL Stop-hook events) before SIGKILL. A fast graceful exit still settles
|
|
7953
|
+
* Grace for interactive stop and pause teardown, allowing telemetry to flush.
|
|
7954
|
+
* A fast graceful exit still settles
|
|
8132
7955
|
* immediately, so this only adds latency when a child lingers. Operator-tunable
|
|
8133
7956
|
* via `WORKFLOW_STEP_FORCE_KILL_GRACE_MS`; defaults to STEP_COMPLETION_KILL_GRACE_MS.
|
|
8134
7957
|
*/
|
|
@@ -8268,7 +8091,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8268
8091
|
* Interactive TUIs such as Claude Code make themselves process-group leaders
|
|
8269
8092
|
* (pid === pgid) and spawn descendants into that group. Reaping by pid alone
|
|
8270
8093
|
* leaves anything spawned after the one-shot tree snapshot alive, which keeps
|
|
8271
|
-
* the interactive session running after
|
|
8094
|
+
* the interactive session running after a stop or pause request.
|
|
8272
8095
|
*/
|
|
8273
8096
|
collectInteractiveProcessGroupIds(processIds) {
|
|
8274
8097
|
if (processIds.length === 0) return [];
|
|
@@ -8371,38 +8194,17 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8371
8194
|
return false;
|
|
8372
8195
|
}
|
|
8373
8196
|
}
|
|
8374
|
-
/**
|
|
8375
|
-
|
|
8376
|
-
* YES to when the agent finishes its turn. The path is injected into
|
|
8377
|
-
* WORKFLOW_STATUS_FILE so the hook can locate it directly — no fallback
|
|
8378
|
-
* marker file is used.
|
|
8379
|
-
*/
|
|
8380
|
-
async createStatusFile() {
|
|
8381
|
-
if (!this.runtime.temporaryDirectory) throw new Error("Workflow interactive status files require an admitted temporaryDirectory");
|
|
8382
|
-
const filePath = (0, node_path.join)(this.runtime.temporaryDirectory, `${STATUS_FILE_PREFIX}${(0, node_crypto.randomUUID)()}${STATUS_FILE_SUFFIX}`);
|
|
8383
|
-
(0, _agimon_ai_po_core_platform.getOrThrow)(await this.runtime.fs.writeFile(filePath, "", this.runtime.ioContext));
|
|
8384
|
-
return filePath;
|
|
8385
|
-
}
|
|
8386
|
-
/**
|
|
8387
|
-
* Race interactive step execution against agent completion and workflow stop files.
|
|
8388
|
-
* When the file contains YES, SIGTERM the step process and wait for
|
|
8389
|
-
* it to exit before returning `status_completed`. Escalates to SIGKILL
|
|
8390
|
-
* if the process ignores SIGTERM. The next job must not start until
|
|
8391
|
-
* the child process tree has fully exited.
|
|
8392
|
-
*/
|
|
8393
|
-
async raceInteractiveCompletion(executionPromise, statusFilePath, stepName, stopRequestPath, pausePolicy) {
|
|
8197
|
+
/** Race interactive execution against workflow stop and pause requests. */
|
|
8198
|
+
async raceInteractiveCompletion(executionPromise, stepName, stopRequestPath, pausePolicy) {
|
|
8394
8199
|
return new Promise((resolveRace) => {
|
|
8395
8200
|
let settled = false;
|
|
8396
|
-
let statusFileTriggered = false;
|
|
8397
8201
|
let stopRequestTriggered = false;
|
|
8398
8202
|
let pauseRequestTriggered = false;
|
|
8399
8203
|
const pauseRequestPath = stopRequestPath ? (0, node_path.join)((0, node_path.dirname)(stopRequestPath), PAUSE_REQUEST_FILENAME) : void 0;
|
|
8400
8204
|
let forceKillTimer = null;
|
|
8401
8205
|
let completionSettleTimer = null;
|
|
8402
|
-
let watcher = null;
|
|
8403
8206
|
let stopWatcher = null;
|
|
8404
8207
|
let pauseWatcher = null;
|
|
8405
|
-
let pollTimer = null;
|
|
8406
8208
|
let stopPollTimer = null;
|
|
8407
8209
|
let pausePollTimer = null;
|
|
8408
8210
|
let signalDelivered = false;
|
|
@@ -8410,7 +8212,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8410
8212
|
const resolveCompletionSource = (result) => {
|
|
8411
8213
|
if (stopRequestTriggered) return "stop-request";
|
|
8412
8214
|
if (pauseRequestTriggered) return "pause-request";
|
|
8413
|
-
if (statusFileTriggered) return "status-file";
|
|
8414
8215
|
switch (result.status) {
|
|
8415
8216
|
case RESULT_STATUS_TIMED_OUT: return "timed-out";
|
|
8416
8217
|
case RESULT_STATUS_SPAWN_ERROR: return "spawn-error";
|
|
@@ -8421,10 +8222,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8421
8222
|
const settle = async (result) => {
|
|
8422
8223
|
if (settled) return;
|
|
8423
8224
|
settled = true;
|
|
8424
|
-
if (watcher) {
|
|
8425
|
-
await watcher.close(this.runtime.ioContext).catch((error) => this.logger.warn(`Workflow watcher cleanup failed: ${String(error)}`));
|
|
8426
|
-
watcher = null;
|
|
8427
|
-
}
|
|
8428
8225
|
if (stopWatcher) {
|
|
8429
8226
|
await stopWatcher.close(this.runtime.ioContext).catch((error) => this.logger.warn(`Workflow watcher cleanup failed: ${String(error)}`));
|
|
8430
8227
|
stopWatcher = null;
|
|
@@ -8433,10 +8230,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8433
8230
|
await pauseWatcher.close(this.runtime.ioContext).catch((error) => this.logger.warn(`Workflow watcher cleanup failed: ${String(error)}`));
|
|
8434
8231
|
pauseWatcher = null;
|
|
8435
8232
|
}
|
|
8436
|
-
if (pollTimer) {
|
|
8437
|
-
clearInterval(pollTimer);
|
|
8438
|
-
pollTimer = null;
|
|
8439
|
-
}
|
|
8440
8233
|
if (stopPollTimer) {
|
|
8441
8234
|
clearInterval(stopPollTimer);
|
|
8442
8235
|
stopPollTimer = null;
|
|
@@ -8460,25 +8253,13 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8460
8253
|
await this.recordInteractiveCompletion({
|
|
8461
8254
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8462
8255
|
stepName,
|
|
8463
|
-
statusFilePath,
|
|
8464
8256
|
completionSource: resolveCompletionSource(settledResult),
|
|
8465
|
-
statusFileSignaled: statusFileTriggered,
|
|
8466
8257
|
sigkillEscalated: sigkillEscalated || (this.lastInteractiveReap?.sigkillEscalated ?? false),
|
|
8467
8258
|
survivors: this.lastInteractiveReap?.survivors ?? []
|
|
8468
8259
|
});
|
|
8469
8260
|
this.lastInteractiveReap = null;
|
|
8470
8261
|
resolveRace(settledResult);
|
|
8471
8262
|
};
|
|
8472
|
-
const statusFileHasCompletionValue = async () => {
|
|
8473
|
-
try {
|
|
8474
|
-
return await (0, _agimon_ai_po_core_platform.pathExists)(this.runtime.fs, statusFilePath, this.runtime.ioContext) && (0, _agimon_ai_po_core_platform.getOrThrow)(await this.runtime.fs.readTextFile(statusFilePath, this.runtime.ioContext)).trim() === STATUS_FILE_COMPLETION_VALUE;
|
|
8475
|
-
} catch (error) {
|
|
8476
|
-
const code = error.code;
|
|
8477
|
-
if (!code || !TRANSIENT_FS_ERROR_CODES.has(code)) this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file read failed for ${stepName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
8478
|
-
else this.logger.info(` ${DIM$3}status-file${RESET$3} transient FS error (${code}) polling ${stepName}`);
|
|
8479
|
-
return false;
|
|
8480
|
-
}
|
|
8481
|
-
};
|
|
8482
8263
|
const scheduleAbsoluteSettle = (result, delayMs) => {
|
|
8483
8264
|
if (settled || completionSettleTimer) return;
|
|
8484
8265
|
completionSettleTimer = setTimeout(() => {
|
|
@@ -8497,24 +8278,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8497
8278
|
settle(result);
|
|
8498
8279
|
}, delayMs);
|
|
8499
8280
|
};
|
|
8500
|
-
const checkFileContent = async () => {
|
|
8501
|
-
if (!await statusFileHasCompletionValue() || settled || statusFileTriggered) return;
|
|
8502
|
-
statusFileTriggered = true;
|
|
8503
|
-
const graceMs = this.stepCompletionKillGraceMs();
|
|
8504
|
-
signalDelivered = this.killActiveStep(TERMINATE_SIGNAL$1);
|
|
8505
|
-
if (!signalDelivered) {
|
|
8506
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} status-file: SIGTERM could not be delivered, process may have already exited`);
|
|
8507
|
-
scheduleAbsoluteSettle(STATUS_FILE_COMPLETED_RESULT, PROCESS_EXIT_WAIT_TIMEOUT_MS);
|
|
8508
|
-
return;
|
|
8509
|
-
}
|
|
8510
|
-
forceKillTimer = setTimeout(() => {
|
|
8511
|
-
if (settled) return;
|
|
8512
|
-
sigkillEscalated = true;
|
|
8513
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} did not exit after status-file SIGTERM, forcing SIGKILL`);
|
|
8514
|
-
this.killActiveStep(TERMINATE_FORCE_KILL_SIGNAL);
|
|
8515
|
-
}, graceMs);
|
|
8516
|
-
scheduleAbsoluteSettle(STATUS_FILE_COMPLETED_RESULT, graceMs + PROCESS_EXIT_WAIT_TIMEOUT_MS);
|
|
8517
|
-
};
|
|
8518
8281
|
const stopRequestExists = async () => Boolean(stopRequestPath && await this.hasCurrentStopRequest(stopRequestPath));
|
|
8519
8282
|
const pauseRequestExists = async () => Boolean(pauseRequestPath && await (0, _agimon_ai_po_core_platform.pathExists)(this.runtime.fs, pauseRequestPath, this.runtime.ioContext) && await this.readControlAction(pauseRequestPath) === "pause");
|
|
8520
8283
|
const checkStopRequest = async () => {
|
|
@@ -8554,23 +8317,9 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8554
8317
|
}, graceMs);
|
|
8555
8318
|
scheduleAbsoluteSettle({ status: RESULT_STATUS_PAUSE_REQUESTED }, graceMs + PROCESS_EXIT_WAIT_TIMEOUT_MS);
|
|
8556
8319
|
};
|
|
8557
|
-
try {
|
|
8558
|
-
this.watchStatusFile([{ path: statusFilePath }], () => {
|
|
8559
|
-
checkFileContent().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8560
|
-
}, this.runtime.ioContext).then(async (result) => {
|
|
8561
|
-
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
8562
|
-
if (settled) await admitted.close(this.runtime.ioContext);
|
|
8563
|
-
else watcher = admitted;
|
|
8564
|
-
}).catch((error) => this.logger.warn(`Workflow status-file watcher unavailable, polling instead: ${String(error)}`));
|
|
8565
|
-
} catch (error) {
|
|
8566
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file watcher setup failed for ${stepName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
8567
|
-
}
|
|
8568
|
-
pollTimer = setInterval(() => {
|
|
8569
|
-
checkFileContent().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8570
|
-
}, STATUS_FILE_POLL_INTERVAL_MS);
|
|
8571
8320
|
if (stopRequestPath) {
|
|
8572
8321
|
try {
|
|
8573
|
-
this.
|
|
8322
|
+
this.watchControlFile([{ path: stopRequestPath }], () => {
|
|
8574
8323
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8575
8324
|
}, this.runtime.ioContext).then(async (result) => {
|
|
8576
8325
|
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
@@ -8586,7 +8335,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8586
8335
|
}
|
|
8587
8336
|
if (pauseRequestPath) {
|
|
8588
8337
|
try {
|
|
8589
|
-
this.
|
|
8338
|
+
this.watchControlFile([{ path: pauseRequestPath }], () => {
|
|
8590
8339
|
checkPauseRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8591
8340
|
}, this.runtime.ioContext).then(async (result) => {
|
|
8592
8341
|
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
@@ -8600,7 +8349,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8600
8349
|
checkPauseRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8601
8350
|
}, STOP_REQUEST_POLL_INTERVAL_MS);
|
|
8602
8351
|
}
|
|
8603
|
-
checkFileContent().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8604
8352
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8605
8353
|
checkPauseRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8606
8354
|
executionPromise.then(async (result) => {
|
|
@@ -8609,42 +8357,9 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8609
8357
|
settle({ status: RESULT_STATUS_STOP_REQUESTED });
|
|
8610
8358
|
return;
|
|
8611
8359
|
}
|
|
8612
|
-
const
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
settle({ status: RESULT_STATUS_PAUSE_REQUESTED });
|
|
8616
|
-
return;
|
|
8617
|
-
}
|
|
8618
|
-
if (!completedViaStatusFile) {
|
|
8619
|
-
settle(result);
|
|
8620
|
-
return;
|
|
8621
|
-
}
|
|
8622
|
-
if (!statusFileTriggered) {
|
|
8623
|
-
statusFileTriggered = true;
|
|
8624
|
-
this.logger.info(` ${GREEN$2}${STATUS_DONE}${RESET$3} ${stepName} status-file observed during process exit handling`);
|
|
8625
|
-
}
|
|
8626
|
-
switch (result.status) {
|
|
8627
|
-
case RESULT_STATUS_SPAWN_ERROR:
|
|
8628
|
-
case RESULT_STATUS_TIMED_OUT:
|
|
8629
|
-
settle(result);
|
|
8630
|
-
return;
|
|
8631
|
-
case RESULT_STATUS_SIGNALED:
|
|
8632
|
-
if (sigkillEscalated) this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} required SIGKILL escalation (work completed via status-file)`);
|
|
8633
|
-
settle(STATUS_FILE_COMPLETED_RESULT);
|
|
8634
|
-
return;
|
|
8635
|
-
case RESULT_STATUS_COMPLETED:
|
|
8636
|
-
if (sigkillEscalated) this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} required SIGKILL escalation (work completed via status-file, exit code ${result.exitCode})`);
|
|
8637
|
-
settle(STATUS_FILE_COMPLETED_RESULT);
|
|
8638
|
-
return;
|
|
8639
|
-
case RESULT_STATUS_STATUS_COMPLETED:
|
|
8640
|
-
settle(result);
|
|
8641
|
-
return;
|
|
8642
|
-
case RESULT_STATUS_STOP_REQUESTED:
|
|
8643
|
-
case RESULT_STATUS_PAUSE_REQUESTED:
|
|
8644
|
-
settle(result);
|
|
8645
|
-
return;
|
|
8646
|
-
default: settle(result);
|
|
8647
|
-
}
|
|
8360
|
+
const protectedPauseEligible = result.status === RESULT_STATUS_COMPLETED && result.exitCode === 0;
|
|
8361
|
+
if (pauseRequestTriggered && (pausePolicy !== "protected" || protectedPauseEligible)) settle({ status: RESULT_STATUS_PAUSE_REQUESTED });
|
|
8362
|
+
else settle(result);
|
|
8648
8363
|
});
|
|
8649
8364
|
});
|
|
8650
8365
|
}
|
|
@@ -8693,7 +8408,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8693
8408
|
}, FORCE_KILL_GRACE_PERIOD_MS);
|
|
8694
8409
|
};
|
|
8695
8410
|
try {
|
|
8696
|
-
this.
|
|
8411
|
+
this.watchControlFile([{ path: stopRequestPath }], () => {
|
|
8697
8412
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8698
8413
|
}, this.runtime.ioContext).then(async (result) => {
|
|
8699
8414
|
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
@@ -8708,7 +8423,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8708
8423
|
}, STOP_REQUEST_POLL_INTERVAL_MS);
|
|
8709
8424
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8710
8425
|
executionPromise.then(async (result) => {
|
|
8711
|
-
const protectedPauseEligible = result.status ===
|
|
8426
|
+
const protectedPauseEligible = result.status === RESULT_STATUS_COMPLETED && result.exitCode === 0;
|
|
8712
8427
|
if (stopRequestTriggered) settle({ status: RESULT_STATUS_STOP_REQUESTED });
|
|
8713
8428
|
else if (pauseRequestTriggered && (pausePolicy !== "protected" || protectedPauseEligible)) settle({ status: RESULT_STATUS_PAUSE_REQUESTED });
|
|
8714
8429
|
else settle(result);
|
|
@@ -8818,16 +8533,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8818
8533
|
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} failed to restore terminal state: ${String(error)}`);
|
|
8819
8534
|
}
|
|
8820
8535
|
}
|
|
8821
|
-
/**
|
|
8822
|
-
* Remove the temp status file and the well-known marker file after step completion.
|
|
8823
|
-
*/
|
|
8824
|
-
async cleanupStatusFile(statusFilePath) {
|
|
8825
|
-
try {
|
|
8826
|
-
if (await (0, _agimon_ai_po_core_platform.pathExists)(this.runtime.fs, statusFilePath, this.runtime.ioContext)) (0, _agimon_ai_po_core_platform.getOrThrow)(await this.runtime.fs.remove(statusFilePath, { force: true }, this.runtime.ioContext));
|
|
8827
|
-
} catch (error) {
|
|
8828
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
8829
|
-
}
|
|
8830
|
-
}
|
|
8831
8536
|
};
|
|
8832
8537
|
//#endregion
|
|
8833
8538
|
//#region src/services/TriggerService/index.ts
|
|
@@ -9551,7 +9256,7 @@ var RunWorkflowService = class {
|
|
|
9551
9256
|
this.launcherMetadata = dependencies.launcherMetadata;
|
|
9552
9257
|
this.parser = dependencies.parser ?? new WorkflowParserService(this.runtime);
|
|
9553
9258
|
this.serviceManager = dependencies.serviceManager ?? new BackgroundServiceManager(this.runtime, this.logger);
|
|
9554
|
-
this.stepRunner = dependencies.stepRunner ?? new StepRunnerService(this.runtime, this.parser, this.logger, void 0, void 0,
|
|
9259
|
+
this.stepRunner = dependencies.stepRunner ?? new StepRunnerService(this.runtime, this.parser, this.logger, void 0, void 0, dependencies.ownsTerminal, dependencies.stepExecutor, dependencies.resolveSecrets);
|
|
9555
9260
|
this.registry = dependencies.registry ?? new WorkflowRegistryService(this.runtime);
|
|
9556
9261
|
this.runDirectoryService = dependencies.runDirectoryService ?? new RunDirectoryService(this.runtime, this.registry.writeCoordinator);
|
|
9557
9262
|
this.jobRunner = dependencies.jobRunner ?? new JobRunnerService(this.runtime, this.parser, this.stepRunner, this.logger, this.runDirectoryService);
|
|
@@ -9563,6 +9268,7 @@ var RunWorkflowService = class {
|
|
|
9563
9268
|
* Run the workflow from trigger preparation through cleanup.
|
|
9564
9269
|
*/
|
|
9565
9270
|
async run(input) {
|
|
9271
|
+
if ("cliAgent" in input) throw new Error("cliAgent is retired. Use runner explicitly.");
|
|
9566
9272
|
this.stepRunner.resetInterruption();
|
|
9567
9273
|
this.triggerService.resetInterruption();
|
|
9568
9274
|
this.outputLines = [];
|
|
@@ -9745,12 +9451,12 @@ var RunWorkflowService = class {
|
|
|
9745
9451
|
commands: workflow.commands,
|
|
9746
9452
|
choices: workflow.choices,
|
|
9747
9453
|
command: input.command,
|
|
9748
|
-
choice: input.choice
|
|
9454
|
+
choice: input.choice,
|
|
9455
|
+
profile: input.profile
|
|
9749
9456
|
});
|
|
9750
9457
|
}
|
|
9751
9458
|
resolveRunner(input, workflow) {
|
|
9752
|
-
|
|
9753
|
-
return input.runner ?? input.cliAgent ?? (workflow ? this.resolveWorkflowRunner(workflow) : void 0);
|
|
9459
|
+
return input.runner ?? (workflow ? this.resolveWorkflowRunner(workflow) : void 0);
|
|
9754
9460
|
}
|
|
9755
9461
|
/**
|
|
9756
9462
|
* Execute the workflow after signal handlers are installed.
|
|
@@ -9883,7 +9589,6 @@ var RunWorkflowService = class {
|
|
|
9883
9589
|
if (dryRun && input.recovery) registryRun = await this.createRecoveryDryRunHandle(input, resolvedWorkspace);
|
|
9884
9590
|
else registryRun = await this.registry.createRun({
|
|
9885
9591
|
activeRepairId: input.recovery?.activeRepairId,
|
|
9886
|
-
cliAgent: input.cliAgent,
|
|
9887
9592
|
continueOnError: input.continueOnError,
|
|
9888
9593
|
displayName: workflowName,
|
|
9889
9594
|
dryRun,
|
|
@@ -9897,6 +9602,7 @@ var RunWorkflowService = class {
|
|
|
9897
9602
|
runner,
|
|
9898
9603
|
command: input.command,
|
|
9899
9604
|
choice: input.choice,
|
|
9605
|
+
profile: input.profile,
|
|
9900
9606
|
runDirectory: workflow["run-directory"],
|
|
9901
9607
|
secretFile: input.secretFile,
|
|
9902
9608
|
skipLaunch: input.skipLaunch,
|
|
@@ -9975,7 +9681,6 @@ var RunWorkflowService = class {
|
|
|
9975
9681
|
}
|
|
9976
9682
|
if (!await this.triggerService.handleAgentDecision(workflow, workflowEnv, inputs, secrets, {
|
|
9977
9683
|
runner,
|
|
9978
|
-
cliAgent: input.cliAgent,
|
|
9979
9684
|
dryRun,
|
|
9980
9685
|
continueOnError,
|
|
9981
9686
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10014,7 +9719,6 @@ var RunWorkflowService = class {
|
|
|
10014
9719
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10015
9720
|
if (!await this.worktreeService.runHook(workflow.worktree.beforeCreate, workflowDir, workflowEnv, inputs, secrets, {
|
|
10016
9721
|
runner,
|
|
10017
|
-
cliAgent: input.cliAgent,
|
|
10018
9722
|
dryRun,
|
|
10019
9723
|
continueOnError,
|
|
10020
9724
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10046,7 +9750,6 @@ var RunWorkflowService = class {
|
|
|
10046
9750
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10047
9751
|
if (!await this.worktreeService.runHook(workflow.worktree.afterCreate, worktreePath, workflowEnv, inputs, secrets, {
|
|
10048
9752
|
runner,
|
|
10049
|
-
cliAgent: input.cliAgent,
|
|
10050
9753
|
dryRun,
|
|
10051
9754
|
continueOnError,
|
|
10052
9755
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10079,7 +9782,6 @@ var RunWorkflowService = class {
|
|
|
10079
9782
|
const preStopRequestPath = registryRun.stopRequestPath;
|
|
10080
9783
|
if (!await this.recordPhase(progress, PRE_PHASE_JOB, () => this.runPreBlock(preBlock, workflowEnv, inputs, secrets, {
|
|
10081
9784
|
runner,
|
|
10082
|
-
cliAgent: input.cliAgent,
|
|
10083
9785
|
dryRun,
|
|
10084
9786
|
continueOnError,
|
|
10085
9787
|
progress,
|
|
@@ -10157,7 +9859,6 @@ var RunWorkflowService = class {
|
|
|
10157
9859
|
runDirectory: workflow["run-directory"]
|
|
10158
9860
|
}, {
|
|
10159
9861
|
runner,
|
|
10160
|
-
cliAgent: input.cliAgent,
|
|
10161
9862
|
dryRun,
|
|
10162
9863
|
continueOnError,
|
|
10163
9864
|
stopRequestPath,
|
|
@@ -10264,7 +9965,6 @@ var RunWorkflowService = class {
|
|
|
10264
9965
|
} : void 0
|
|
10265
9966
|
}, {
|
|
10266
9967
|
runner,
|
|
10267
|
-
cliAgent: input.cliAgent,
|
|
10268
9968
|
dryRun,
|
|
10269
9969
|
continueOnError,
|
|
10270
9970
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10475,7 +10175,6 @@ var RunWorkflowService = class {
|
|
|
10475
10175
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10476
10176
|
if (!await this.worktreeService.runHook(workflow.worktree.beforeCompleted, worktreePath, workflowEnv, inputs, secrets, {
|
|
10477
10177
|
runner,
|
|
10478
|
-
cliAgent: input.cliAgent,
|
|
10479
10178
|
dryRun,
|
|
10480
10179
|
continueOnError
|
|
10481
10180
|
})) {
|
|
@@ -10500,7 +10199,6 @@ var RunWorkflowService = class {
|
|
|
10500
10199
|
try {
|
|
10501
10200
|
if (!await this.recordPhase(progress, POST_PHASE_JOB, () => this.runPostBlock(postBlock, workflowEnv, inputs, secrets, {
|
|
10502
10201
|
runner,
|
|
10503
|
-
cliAgent: input.cliAgent,
|
|
10504
10202
|
dryRun,
|
|
10505
10203
|
continueOnError,
|
|
10506
10204
|
progress,
|
|
@@ -10527,7 +10225,6 @@ var RunWorkflowService = class {
|
|
|
10527
10225
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10528
10226
|
if (!await this.worktreeService.runHook(workflow.worktree.afterCompleted, originalDir, workflowEnv, inputs, secrets, {
|
|
10529
10227
|
runner,
|
|
10530
|
-
cliAgent: input.cliAgent,
|
|
10531
10228
|
dryRun,
|
|
10532
10229
|
continueOnError
|
|
10533
10230
|
})) {
|
|
@@ -10888,6 +10585,7 @@ var RunWorkflowService = class {
|
|
|
10888
10585
|
if (runner) parts.push("--runner", require_workflowCommandTemplate.escapeShellArg(runner));
|
|
10889
10586
|
if (input.command) parts.push("--command", require_workflowCommandTemplate.escapeShellArg(input.command));
|
|
10890
10587
|
if (input.choice) parts.push("--choice", require_workflowCommandTemplate.escapeShellArg(input.choice));
|
|
10588
|
+
if (input.profile) parts.push("--profile", require_workflowCommandTemplate.escapeShellArg(input.profile));
|
|
10891
10589
|
if (input.dryRun) parts.push("--dry-run");
|
|
10892
10590
|
if (input.continueOnError) parts.push("--continue-on-error");
|
|
10893
10591
|
if (input.keepWorktree) parts.push("--keep-worktree");
|
|
@@ -11201,16 +10899,21 @@ var RecoverWorkflowService = class {
|
|
|
11201
10899
|
if (!recoveredJob) throw new Error(`Workflow run "${record.workspace}/${record.runKey}" does not include a recoverable failed job`);
|
|
11202
10900
|
if (record.worktreePath && !await (0, _agimon_ai_po_core_platform.pathExists)(this.runtime.fs, record.worktreePath, this.runtime.ioContext)) throw new Error(`Recoverable worktree not found: ${record.worktreePath}`);
|
|
11203
10901
|
const runner = input.runner ?? record.runner ?? record.cliAgent;
|
|
11204
|
-
|
|
10902
|
+
if ([runner, record.command].some((value) => value !== void 0 && [
|
|
10903
|
+
"claude",
|
|
10904
|
+
"claude-code",
|
|
10905
|
+
"codex",
|
|
10906
|
+
"antigravity"
|
|
10907
|
+
].includes(value))) throw new Error("Retired workflow execution cannot be replayed. Select a supported runner explicitly.");
|
|
11205
10908
|
const originalJob = fixRestartFrom && !activeRepair ? void 0 : record.job;
|
|
11206
10909
|
if (!this.parser.resolveJobOrder(workflow.jobs, originalJob ?? null).includes(recoveredJob)) throw new Error(`Workflow run "${record.workspace}/${record.runKey}" recovery target "${recoveredJob}" is not in the workflow job order`);
|
|
11207
10910
|
const ownerSessionId = claimedOwnerSessionId?.trim();
|
|
11208
10911
|
const envOverrides = ownerSessionId ? { [PI_SESSION_ENV]: ownerSessionId } : void 0;
|
|
11209
10912
|
return await this.runner.run({
|
|
11210
|
-
cliAgent,
|
|
11211
10913
|
runner,
|
|
11212
10914
|
command: record.command,
|
|
11213
10915
|
choice: record.choice,
|
|
10916
|
+
profile: record.profile,
|
|
11214
10917
|
workflowPath: record.workflowPath,
|
|
11215
10918
|
job: recoveredJob,
|
|
11216
10919
|
inputs: record.inputs,
|
|
@@ -11263,12 +10966,6 @@ var RecoverWorkflowService = class {
|
|
|
11263
10966
|
}
|
|
11264
10967
|
};
|
|
11265
10968
|
//#endregion
|
|
11266
|
-
Object.defineProperty(exports, "CodexQuotaService", {
|
|
11267
|
-
enumerable: true,
|
|
11268
|
-
get: function() {
|
|
11269
|
-
return CodexQuotaService;
|
|
11270
|
-
}
|
|
11271
|
-
});
|
|
11272
10969
|
Object.defineProperty(exports, "NativeTerminalService", {
|
|
11273
10970
|
enumerable: true,
|
|
11274
10971
|
get: function() {
|
|
@@ -11359,12 +11056,6 @@ Object.defineProperty(exports, "diagnoseWorkflows", {
|
|
|
11359
11056
|
return diagnoseWorkflows;
|
|
11360
11057
|
}
|
|
11361
11058
|
});
|
|
11362
|
-
Object.defineProperty(exports, "formatArtifactWarning", {
|
|
11363
|
-
enumerable: true,
|
|
11364
|
-
get: function() {
|
|
11365
|
-
return formatArtifactWarning;
|
|
11366
|
-
}
|
|
11367
|
-
});
|
|
11368
11059
|
Object.defineProperty(exports, "gateStepDecision", {
|
|
11369
11060
|
enumerable: true,
|
|
11370
11061
|
get: function() {
|
|
@@ -11456,4 +11147,4 @@ Object.defineProperty(exports, "workflowShellOutput", {
|
|
|
11456
11147
|
}
|
|
11457
11148
|
});
|
|
11458
11149
|
|
|
11459
|
-
//# sourceMappingURL=RecoverWorkflowService-
|
|
11150
|
+
//# sourceMappingURL=RecoverWorkflowService-CEYR10KF.cjs.map
|