@agimon-ai/po-workflow 0.0.0-alpha.38 → 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-CbyTPDY-.cjs → RecoverWorkflowService-CEYR10KF.cjs} +32 -430
- package/dist/RecoverWorkflowService-CEYR10KF.cjs.map +1 -0
- package/dist/{RecoverWorkflowService-DZZmRtBJ.mjs → RecoverWorkflowService-CY8wIc3A.mjs} +33 -419
- package/dist/RecoverWorkflowService-CY8wIc3A.mjs.map +1 -0
- package/dist/cli.cjs +90 -1592
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +91 -1593
- package/dist/cli.mjs.map +1 -1
- package/dist/extensions/server.cjs +7 -10
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.mjs +7 -10
- package/dist/extensions/server.mjs.map +1 -1
- package/package.json +9 -9
- package/dist/RecoverWorkflowService-CbyTPDY-.cjs.map +0 -1
- package/dist/RecoverWorkflowService-DZZmRtBJ.mjs.map +0 -1
|
@@ -756,6 +756,7 @@ const WorkflowLauncherMetadataSchema = zod.z.discriminatedUnion("type", [
|
|
|
756
756
|
]);
|
|
757
757
|
const WorkflowRunRecordSchema = zod.z.object({
|
|
758
758
|
activeRepairId: zod.z.string().regex(/^\d+$/).optional(),
|
|
759
|
+
/** Read-only legacy metadata. New runs only write runner. */
|
|
759
760
|
cliAgent: zod.z.string().optional(),
|
|
760
761
|
continueOnError: zod.z.boolean().optional(),
|
|
761
762
|
displayName: zod.z.string(),
|
|
@@ -4752,7 +4753,6 @@ var WorkflowRegistryService = class {
|
|
|
4752
4753
|
const runId = (0, node_crypto.randomUUID)();
|
|
4753
4754
|
const runRecord = {
|
|
4754
4755
|
activeRepairId: input.activeRepairId,
|
|
4755
|
-
cliAgent: input.cliAgent,
|
|
4756
4756
|
continueOnError: input.continueOnError,
|
|
4757
4757
|
displayName: input.displayName,
|
|
4758
4758
|
dryRun: input.dryRun,
|
|
@@ -6433,127 +6433,6 @@ const MAX_STEP_TIMEOUT_MINUTES = Math.floor(2147483647 / 6e4);
|
|
|
6433
6433
|
const StepTimeoutMinutesSchema = zod.z.number().positive().finite().max(MAX_STEP_TIMEOUT_MINUTES);
|
|
6434
6434
|
const StepTimeoutRetriesSchema = zod.z.number().int().min(0).max(STEP_TIMEOUT_RETRIES_LIMIT).default(STEP_TIMEOUT_MAX_RETRIES);
|
|
6435
6435
|
//#endregion
|
|
6436
|
-
//#region src/services/CodexQuotaService/index.ts
|
|
6437
|
-
/**
|
|
6438
|
-
* CodexQuotaService
|
|
6439
|
-
*
|
|
6440
|
-
* DESIGN PATTERNS:
|
|
6441
|
-
* - Service pattern for business logic encapsulation
|
|
6442
|
-
* - Single responsibility principle
|
|
6443
|
-
*
|
|
6444
|
-
* CODING STANDARDS:
|
|
6445
|
-
* - Use async/await for asynchronous operations
|
|
6446
|
-
* - Throw descriptive errors for error cases
|
|
6447
|
-
* - Keep methods focused and well-named
|
|
6448
|
-
* - Document complex logic with comments
|
|
6449
|
-
*
|
|
6450
|
-
* AVOID:
|
|
6451
|
-
* - Mixing concerns (keep focused on single domain)
|
|
6452
|
-
* - Direct tool implementation (services should be tool-agnostic)
|
|
6453
|
-
*/
|
|
6454
|
-
const DEFAULT_CODEX_HOME_DIRNAME = ".codex";
|
|
6455
|
-
const AUTH_FILENAME = "auth.json";
|
|
6456
|
-
const CONFIG_FILENAME = "config.toml";
|
|
6457
|
-
const DEFAULT_CHATGPT_BASE_URL = "https://chatgpt.com/backend-api/";
|
|
6458
|
-
const CHATGPT_HOST = "https://chatgpt.com";
|
|
6459
|
-
const CHAT_OPENAI_HOST = "https://chat.openai.com";
|
|
6460
|
-
const BACKEND_API_SEGMENT = "/backend-api";
|
|
6461
|
-
const QUOTA_USER_AGENT = "codex-cli";
|
|
6462
|
-
const PRIMARY_WINDOW = "primary";
|
|
6463
|
-
const SECONDARY_WINDOW = "secondary";
|
|
6464
|
-
const QUOTA_REACHED_PERCENT = 100;
|
|
6465
|
-
var CodexQuotaService = class {
|
|
6466
|
-
codexHome;
|
|
6467
|
-
fetchFn;
|
|
6468
|
-
now;
|
|
6469
|
-
readTextFile;
|
|
6470
|
-
constructor(runtime, deps = {}) {
|
|
6471
|
-
this.codexHome = deps.codexHome ?? runtime.baseEnvironment.CODEX_HOME ?? (0, node_path.join)(runtime.homeDirectory, DEFAULT_CODEX_HOME_DIRNAME);
|
|
6472
|
-
this.fetchFn = deps.fetchFn ?? fetch;
|
|
6473
|
-
this.now = deps.now ?? (() => Date.now());
|
|
6474
|
-
this.readTextFile = deps.readTextFile ?? (async (path) => (0, _agimon_ai_po_core_platform.getOrThrow)(await runtime.fs.readTextFile(path, runtime.ioContext)));
|
|
6475
|
-
}
|
|
6476
|
-
isCodexCommand(command, _sourceAgentKey) {
|
|
6477
|
-
const trimmed = command.trim();
|
|
6478
|
-
return trimmed === "codex" || trimmed.startsWith("codex ");
|
|
6479
|
-
}
|
|
6480
|
-
async getQuotaStatus() {
|
|
6481
|
-
const auth = await this.readAuthFile();
|
|
6482
|
-
const accessToken = auth?.tokens?.access_token?.trim();
|
|
6483
|
-
const accountId = auth?.tokens?.account_id?.trim();
|
|
6484
|
-
if (!accessToken || !accountId) return null;
|
|
6485
|
-
const baseUrl = await this.readChatgptBaseUrl();
|
|
6486
|
-
const response = await this.fetchFn(this.buildUsageUrl(baseUrl), { headers: {
|
|
6487
|
-
Authorization: `Bearer ${accessToken}`,
|
|
6488
|
-
"ChatGPT-Account-Id": accountId,
|
|
6489
|
-
"User-Agent": QUOTA_USER_AGENT
|
|
6490
|
-
} });
|
|
6491
|
-
if (!response.ok) throw new Error(`codex quota request failed with HTTP ${response.status}`);
|
|
6492
|
-
const payload = await response.json();
|
|
6493
|
-
return {
|
|
6494
|
-
blockingLimit: this.findBlockingLimit(payload),
|
|
6495
|
-
planType: payload.plan_type ?? null
|
|
6496
|
-
};
|
|
6497
|
-
}
|
|
6498
|
-
async readAuthFile() {
|
|
6499
|
-
const raw = await this.readOptionalTextFile((0, node_path.join)(this.codexHome, AUTH_FILENAME));
|
|
6500
|
-
if (!raw) return null;
|
|
6501
|
-
return JSON.parse(raw);
|
|
6502
|
-
}
|
|
6503
|
-
async readChatgptBaseUrl() {
|
|
6504
|
-
const match = (await this.readOptionalTextFile((0, node_path.join)(this.codexHome, CONFIG_FILENAME)))?.match(/^\s*chatgpt_base_url\s*=\s*"([^"]+)"/m);
|
|
6505
|
-
return this.normalizeBaseUrl(match?.[1] ?? DEFAULT_CHATGPT_BASE_URL);
|
|
6506
|
-
}
|
|
6507
|
-
buildUsageUrl(baseUrl) {
|
|
6508
|
-
return baseUrl.includes(BACKEND_API_SEGMENT) ? `${baseUrl}/wham/usage` : `${baseUrl}/api/codex/usage`;
|
|
6509
|
-
}
|
|
6510
|
-
normalizeBaseUrl(baseUrl) {
|
|
6511
|
-
let normalized = baseUrl.trim().replace(/\/+$/, "");
|
|
6512
|
-
if ((normalized.startsWith(CHATGPT_HOST) || normalized.startsWith(CHAT_OPENAI_HOST)) && !normalized.includes(BACKEND_API_SEGMENT)) normalized = `${normalized}${BACKEND_API_SEGMENT}`;
|
|
6513
|
-
return normalized;
|
|
6514
|
-
}
|
|
6515
|
-
async readOptionalTextFile(path) {
|
|
6516
|
-
try {
|
|
6517
|
-
return await this.readTextFile(path);
|
|
6518
|
-
} catch (error) {
|
|
6519
|
-
if (error.code === "ENOENT") return null;
|
|
6520
|
-
throw error;
|
|
6521
|
-
}
|
|
6522
|
-
}
|
|
6523
|
-
findBlockingLimit(payload) {
|
|
6524
|
-
const blocks = [];
|
|
6525
|
-
this.collectBlockingLimit(blocks, "codex", "codex", payload.rate_limit);
|
|
6526
|
-
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);
|
|
6527
|
-
blocks.sort((left, right) => left.resetAt - right.resetAt || right.usedPercent - left.usedPercent);
|
|
6528
|
-
return blocks[0] ?? null;
|
|
6529
|
-
}
|
|
6530
|
-
collectBlockingLimit(blocks, limitId, limitName, limit) {
|
|
6531
|
-
if (!limit) return;
|
|
6532
|
-
const windows = [{
|
|
6533
|
-
payload: limit.primary_window,
|
|
6534
|
-
window: PRIMARY_WINDOW
|
|
6535
|
-
}, {
|
|
6536
|
-
payload: limit.secondary_window,
|
|
6537
|
-
window: SECONDARY_WINDOW
|
|
6538
|
-
}];
|
|
6539
|
-
for (const { payload, window } of windows) {
|
|
6540
|
-
const resetAt = payload?.reset_at;
|
|
6541
|
-
const usedPercent = payload?.used_percent ?? 0;
|
|
6542
|
-
if (typeof resetAt !== "number") continue;
|
|
6543
|
-
if (!(usedPercent >= QUOTA_REACHED_PERCENT || limit.limit_reached === true && resetAt * 1e3 > this.now() || limit.allowed === false && resetAt * 1e3 > this.now())) continue;
|
|
6544
|
-
blocks.push({
|
|
6545
|
-
limitId,
|
|
6546
|
-
limitName,
|
|
6547
|
-
resetAfterSeconds: payload?.reset_after_seconds ?? null,
|
|
6548
|
-
resetAt,
|
|
6549
|
-
usedPercent,
|
|
6550
|
-
window,
|
|
6551
|
-
windowSeconds: payload?.limit_window_seconds ?? null
|
|
6552
|
-
});
|
|
6553
|
-
}
|
|
6554
|
-
}
|
|
6555
|
-
};
|
|
6556
|
-
//#endregion
|
|
6557
6436
|
//#region src/services/StepRunnerService/index.ts
|
|
6558
6437
|
/**
|
|
6559
6438
|
* StepRunnerService
|
|
@@ -6716,33 +6595,15 @@ const WORKFLOW_STEP_NAME_ENV_KEY = "WORKFLOW_STEP_NAME";
|
|
|
6716
6595
|
const WORKFLOW_STEP_DISPLAY_ENV_KEY = "WORKFLOW_STEP_DISPLAY";
|
|
6717
6596
|
const WORKFLOW_STEP_ARTIFACTS_ENV_KEY = "WORKFLOW_STEP_ARTIFACTS";
|
|
6718
6597
|
const WORKFLOW_TERMINAL_TITLE = "workflow-mcp";
|
|
6719
|
-
const STATUS_FILE_PREFIX = "workflow-step-";
|
|
6720
|
-
const STATUS_FILE_SUFFIX = ".status";
|
|
6721
|
-
const STATUS_FILE_COMPLETION_VALUE = "YES";
|
|
6722
|
-
const STATUS_FILE_COMPLETED_RESULT = { status: "status_completed" };
|
|
6723
|
-
const TRANSIENT_FS_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
6724
|
-
"ENOENT",
|
|
6725
|
-
"EBUSY",
|
|
6726
|
-
"EAGAIN",
|
|
6727
|
-
"EPERM",
|
|
6728
|
-
"not_found"
|
|
6729
|
-
]);
|
|
6730
|
-
const STATUS_FILE_POLL_INTERVAL_MS = 1e3;
|
|
6731
6598
|
const STOP_REQUEST_POLL_INTERVAL_MS = 1e3;
|
|
6732
|
-
const STATUS_DONE = "done";
|
|
6733
6599
|
const STATUS_STOP = "stop";
|
|
6734
6600
|
const EXPLICIT_RUNNER_MISSING_PREFIX = "runner";
|
|
6735
6601
|
const EXPLICIT_RUNNER_MISSING_MIDDLE = "not found for step";
|
|
6736
6602
|
const EXPLICIT_RUNNER_AVAILABLE_PREFIX = "available runner keys:";
|
|
6737
|
-
const QUOTA_WAIT_POLL_INTERVAL_MS = 3e4;
|
|
6738
|
-
const QUOTA_WAIT_RESET_BUFFER_MS = 1e3;
|
|
6739
|
-
const QUOTA_WAIT_SOURCE = "StepRunnerService.waitForCodexQuota";
|
|
6740
|
-
const QUOTA_RETRY_REASON = "codex quota reached after failed step, retrying after reset";
|
|
6741
6603
|
const RESULT_STATUS_COMPLETED = "completed";
|
|
6742
6604
|
const RESULT_STATUS_SPAWN_ERROR = "spawn_error";
|
|
6743
6605
|
const RESULT_STATUS_SIGNALED = "signaled";
|
|
6744
6606
|
const RESULT_STATUS_TIMED_OUT = "timed_out";
|
|
6745
|
-
const RESULT_STATUS_STATUS_COMPLETED = "status_completed";
|
|
6746
6607
|
const RESULT_STATUS_STOP_REQUESTED = "stop_requested";
|
|
6747
6608
|
const RESULT_STATUS_PAUSE_REQUESTED = "pause_requested";
|
|
6748
6609
|
/** The reason a step failure carries when nothing more specific was recorded. */
|
|
@@ -6775,8 +6636,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6775
6636
|
runtime;
|
|
6776
6637
|
parser;
|
|
6777
6638
|
logger;
|
|
6778
|
-
|
|
6779
|
-
watchStatusFile;
|
|
6639
|
+
watchControlFile;
|
|
6780
6640
|
runDirectoryService;
|
|
6781
6641
|
ownsTerminal;
|
|
6782
6642
|
stepExecutor;
|
|
@@ -6785,7 +6645,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6785
6645
|
activeExternal = null;
|
|
6786
6646
|
lastInteractiveReap = null;
|
|
6787
6647
|
interruptedSignal = null;
|
|
6788
|
-
activeQuotaWait = null;
|
|
6789
6648
|
commandSelection = {};
|
|
6790
6649
|
/** Runners of a parallel group's steps, which a stop must reach too. */
|
|
6791
6650
|
forks = /* @__PURE__ */ new Set();
|
|
@@ -6800,12 +6659,11 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6800
6659
|
* must not hand a step's stdin to it, and must not `stty` or reset it
|
|
6801
6660
|
* afterwards, however cooperative the intent.
|
|
6802
6661
|
*/
|
|
6803
|
-
constructor(runtime, parser, logger,
|
|
6662
|
+
constructor(runtime, parser, logger, watchControlFile = runtime.fs.watch.bind(runtime.fs), runDirectoryService = new RunDirectoryService(runtime), ownsTerminal = true, stepExecutor, resolveSecrets) {
|
|
6804
6663
|
this.runtime = runtime;
|
|
6805
6664
|
this.parser = parser;
|
|
6806
6665
|
this.logger = logger;
|
|
6807
|
-
this.
|
|
6808
|
-
this.watchStatusFile = watchStatusFile;
|
|
6666
|
+
this.watchControlFile = watchControlFile;
|
|
6809
6667
|
this.runDirectoryService = runDirectoryService;
|
|
6810
6668
|
this.ownsTerminal = ownsTerminal;
|
|
6811
6669
|
this.stepExecutor = stepExecutor;
|
|
@@ -6826,7 +6684,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6826
6684
|
* Release it once its step has finished.
|
|
6827
6685
|
*/
|
|
6828
6686
|
fork(label) {
|
|
6829
|
-
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);
|
|
6830
6688
|
child.commandSelection = this.commandSelection;
|
|
6831
6689
|
child.interruptedSignal = this.interruptedSignal;
|
|
6832
6690
|
child.terminalLock = this.terminalLock;
|
|
@@ -6851,16 +6709,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6851
6709
|
for (const child of this.forks) child.stopActiveStep(signal);
|
|
6852
6710
|
return;
|
|
6853
6711
|
}
|
|
6854
|
-
if (this.activeQuotaWait) {
|
|
6855
|
-
if (this.activeQuotaWait.controller.signal.aborted) {
|
|
6856
|
-
this.logger.info(` ${DIM$3}${STATUS_SKIP}${RESET$3} ${this.activeQuotaWait.stepName} ${ALREADY_STOPPING_SUFFIX}`);
|
|
6857
|
-
return;
|
|
6858
|
-
}
|
|
6859
|
-
this.activeQuotaWait.signal = signal;
|
|
6860
|
-
this.activeQuotaWait.controller.abort();
|
|
6861
|
-
this.logger.info(` ${YELLOW$2}${STATUS_INTERRUPTED}${RESET$3} cancelling quota wait for ${this.activeQuotaWait.stepName}`);
|
|
6862
|
-
return;
|
|
6863
|
-
}
|
|
6864
6712
|
if (this.activeExternal) {
|
|
6865
6713
|
if (this.activeExternal.stopSignal) {
|
|
6866
6714
|
this.logger.info(` ${DIM$3}${STATUS_SKIP}${RESET$3} ${this.activeExternal.stepName} ${ALREADY_STOPPING_SUFFIX}`);
|
|
@@ -6959,7 +6807,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
6959
6807
|
return false;
|
|
6960
6808
|
}
|
|
6961
6809
|
const { command, custom, inProcessOnly, interactive, template } = resolvedStepCommand;
|
|
6962
|
-
const isCodexCommand = this.quotaService.isCodexCommand(command, resolvedStepCommand.agentKey);
|
|
6963
6810
|
const shouldContinue = step["continue-on-error"] || options.continueOnError;
|
|
6964
6811
|
let timeoutMs;
|
|
6965
6812
|
try {
|
|
@@ -7049,12 +6896,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7049
6896
|
}
|
|
7050
6897
|
const stepStartedAt = Date.now();
|
|
7051
6898
|
await this.logStepLifecycle("info", "workflow.step.started", stepEnv, { "workflow.step.interactive": interactive });
|
|
7052
|
-
|
|
7053
|
-
if (interactive) {
|
|
7054
|
-
statusFilePath = await this.createStatusFile();
|
|
7055
|
-
stepEnv[STATUS_FILE_ENV_KEY] = statusFilePath;
|
|
7056
|
-
this.logger.info(` ${DIM$3}status-file${RESET$3} ${statusFilePath}`);
|
|
7057
|
-
} else delete stepEnv[STATUS_FILE_ENV_KEY];
|
|
6899
|
+
delete stepEnv[STATUS_FILE_ENV_KEY];
|
|
7058
6900
|
if (options.dryRun) {
|
|
7059
6901
|
this.logger.info(` ${CYAN$2}${STATUS_DRY}${RESET$3} ${stepName}`);
|
|
7060
6902
|
this.logger.info(`${COMMAND_LOG_INDENT}${DIM$3}${COMMAND_LOG_PROMPT}${command.split(COMMAND_LINE_BREAK).join(COMMAND_LOG_CONTINUATION)}${RESET$3}`);
|
|
@@ -7103,9 +6945,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7103
6945
|
return false;
|
|
7104
6946
|
}
|
|
7105
6947
|
}
|
|
7106
|
-
let quotaFailureRetried = false;
|
|
7107
6948
|
for (let attempt = 0; attempt <= maxTimeoutRetries; attempt++) {
|
|
7108
|
-
await this.waitForCodexQuotaAvailability(stepName, command, isCodexCommand);
|
|
7109
6949
|
if (decisionFilePath && decisionIdentity) await resetDecisionFile(this.runtime, decisionFilePath, decisionIdentity);
|
|
7110
6950
|
if (attempt > 0) this.logger.warn(` ${YELLOW$2}${STATUS_RETRY}${RESET$3} ${STEP_TIMEOUT_RETRY_PREFIX} "${stepName}" (attempt ${attempt + 1}/${maxTimeoutRetries + 1})`);
|
|
7111
6951
|
else this.logger.info(` ${CYAN$2}${STATUS_RUN}${RESET$3} ${stepName}`);
|
|
@@ -7142,7 +6982,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7142
6982
|
timeoutMs,
|
|
7143
6983
|
workDir
|
|
7144
6984
|
}));
|
|
7145
|
-
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;
|
|
7146
6986
|
if (executionResult.status === RESULT_STATUS_PAUSE_REQUESTED) {
|
|
7147
6987
|
await this.logStepLifecycle("info", "workflow.step.pause_requested", stepEnv, {
|
|
7148
6988
|
"workflow.step.outcome": pausePolicy === "replay" ? "cancelled_for_pause" : "protected_boundary",
|
|
@@ -7199,7 +7039,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7199
7039
|
}
|
|
7200
7040
|
const decision = decisionFilePath ? await readStepDecision(this.runtime, decisionFilePath) : void 0;
|
|
7201
7041
|
if (decision) {
|
|
7202
|
-
if (statusFilePath) await this.cleanupStatusFile(statusFilePath);
|
|
7203
7042
|
if (decision.decision === "complete") {
|
|
7204
7043
|
const artifactProblem = artifactSnapshots ? await this.describeArtifactWarnings(stepEnv, artifactSnapshots) : void 0;
|
|
7205
7044
|
if (!artifactProblem) {
|
|
@@ -7233,15 +7072,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7233
7072
|
}
|
|
7234
7073
|
if (executionResult.status === "timed_out") {
|
|
7235
7074
|
fail(`${STEP_TIMEOUT_FAILURE_PREFIX} ${this.formatTimeoutMs(executionResult.timeoutMs)} "${stepName}" (${command.split(COMMAND_LINE_BREAK)[0]})`);
|
|
7236
|
-
if (attempt < maxTimeoutRetries)
|
|
7237
|
-
if (statusFilePath) try {
|
|
7238
|
-
(0, _agimon_ai_po_core_platform.getOrThrow)(await this.runtime.fs.writeFile(statusFilePath, "", this.runtime.ioContext));
|
|
7239
|
-
} catch (error) {
|
|
7240
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file reset failed for ${stepName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
7241
|
-
}
|
|
7242
|
-
continue;
|
|
7243
|
-
}
|
|
7244
|
-
if (statusFilePath) await this.cleanupStatusFile(statusFilePath);
|
|
7075
|
+
if (attempt < maxTimeoutRetries) continue;
|
|
7245
7076
|
if (shouldContinue) {
|
|
7246
7077
|
await this.logStepLifecycle("warn", "workflow.step.finished", stepEnv, {
|
|
7247
7078
|
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
@@ -7258,7 +7089,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7258
7089
|
});
|
|
7259
7090
|
return false;
|
|
7260
7091
|
}
|
|
7261
|
-
if (statusFilePath) await this.cleanupStatusFile(statusFilePath);
|
|
7262
7092
|
if (decisionIdentity?.required && !(executionResult.status === "completed" && executionResult.failure !== void 0)) {
|
|
7263
7093
|
fail(`step "${stepName}" ended without a workflow decision (workflow-mcp step complete|fix|fail)`);
|
|
7264
7094
|
return this.failStep(stepName, stepEnv, stepStartedAt, shouldContinue, report);
|
|
@@ -7281,19 +7111,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7281
7111
|
});
|
|
7282
7112
|
return true;
|
|
7283
7113
|
}
|
|
7284
|
-
if (executionResult.status === "status_completed") {
|
|
7285
|
-
const artifactProblem = artifactSnapshots ? await this.describeArtifactWarnings(stepEnv, artifactSnapshots) : void 0;
|
|
7286
|
-
if (artifactProblem) {
|
|
7287
|
-
fail(`step "${stepName}" ${artifactProblem}`);
|
|
7288
|
-
return this.failStep(stepName, stepEnv, stepStartedAt, shouldContinue, report);
|
|
7289
|
-
}
|
|
7290
|
-
this.logger.info(`\n ${GREEN$2}${STATUS_DONE}${RESET$3} ${stepName} (status-file signaled completion)\n`);
|
|
7291
|
-
await this.logStepLifecycle("info", "workflow.step.finished", stepEnv, {
|
|
7292
|
-
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
7293
|
-
"workflow.step.outcome": "success"
|
|
7294
|
-
});
|
|
7295
|
-
return true;
|
|
7296
|
-
}
|
|
7297
7114
|
if (executionResult.status === "completed" && executionResult.exitCode === 0) {
|
|
7298
7115
|
const artifactProblem = artifactSnapshots ? await this.describeArtifactWarnings(stepEnv, artifactSnapshots) : void 0;
|
|
7299
7116
|
if (!artifactProblem) {
|
|
@@ -7307,12 +7124,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7307
7124
|
fail(`step "${stepName}" ${artifactProblem}`);
|
|
7308
7125
|
}
|
|
7309
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]})`);
|
|
7310
|
-
if (!quotaFailureRetried && await this.shouldRetryForCodexQuota(stepName, isCodexCommand)) {
|
|
7311
|
-
quotaFailureRetried = true;
|
|
7312
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_RETRY}${RESET$3} ${QUOTA_RETRY_REASON}`);
|
|
7313
|
-
attempt -= 1;
|
|
7314
|
-
continue;
|
|
7315
|
-
}
|
|
7316
7127
|
if (shouldContinue) {
|
|
7317
7128
|
await this.logStepLifecycle("warn", "workflow.step.finished", stepEnv, {
|
|
7318
7129
|
"workflow.step.duration_ms": Date.now() - stepStartedAt,
|
|
@@ -7657,7 +7468,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7657
7468
|
/**
|
|
7658
7469
|
* Await a host-owned execution and normalize it like a child process.
|
|
7659
7470
|
*
|
|
7660
|
-
* The engine keeps ownership of the timeout; stop
|
|
7471
|
+
* The engine keeps ownership of the timeout; stop and pause
|
|
7661
7472
|
* completion reach the execution through `killActiveStep`, which calls its
|
|
7662
7473
|
* `stop`. A stopped execution reads as signalled so shutdown still interrupts
|
|
7663
7474
|
* the workflow, while the completion races report their own outcome.
|
|
@@ -7980,7 +7791,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7980
7791
|
return [...keys];
|
|
7981
7792
|
}
|
|
7982
7793
|
resolveRunner(options) {
|
|
7983
|
-
return options.runner
|
|
7794
|
+
return options.runner;
|
|
7984
7795
|
}
|
|
7985
7796
|
formatStepDisplay(jobName, stepName) {
|
|
7986
7797
|
return jobName ? `${jobName} > ${stepName}` : stepName;
|
|
@@ -7995,77 +7806,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
7995
7806
|
escapeShellArg(value) {
|
|
7996
7807
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
7997
7808
|
}
|
|
7998
|
-
async shouldRetryForCodexQuota(stepName, isCodexCommand) {
|
|
7999
|
-
if (!isCodexCommand) return false;
|
|
8000
|
-
return (await this.readCodexQuotaStatus(stepName))?.blockingLimit != null;
|
|
8001
|
-
}
|
|
8002
|
-
async waitForCodexQuotaAvailability(stepName, command, isCodexCommand) {
|
|
8003
|
-
if (!isCodexCommand) return;
|
|
8004
|
-
while (true) {
|
|
8005
|
-
const quotaStatus = await this.readCodexQuotaStatus(stepName);
|
|
8006
|
-
const blockingLimit = quotaStatus?.blockingLimit;
|
|
8007
|
-
if (!blockingLimit) return;
|
|
8008
|
-
const waitTargetMs = blockingLimit.resetAt * 1e3 + QUOTA_WAIT_RESET_BUFFER_MS;
|
|
8009
|
-
const remainingMs = Math.max(waitTargetMs - Date.now(), QUOTA_WAIT_RESET_BUFFER_MS);
|
|
8010
|
-
const waitDescription = new Date(waitTargetMs).toLocaleString();
|
|
8011
|
-
const planSuffix = quotaStatus?.planType ? ` (${quotaStatus.planType})` : "";
|
|
8012
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WAIT}${RESET$3} codex quota ${blockingLimit.limitName}/${blockingLimit.window} is at ${blockingLimit.usedPercent}%${planSuffix}; waiting until ${waitDescription}`);
|
|
8013
|
-
await this.waitForQuotaDelay(stepName, command, remainingMs);
|
|
8014
|
-
}
|
|
8015
|
-
}
|
|
8016
|
-
async readCodexQuotaStatus(stepName) {
|
|
8017
|
-
try {
|
|
8018
|
-
return await this.quotaService.getQuotaStatus();
|
|
8019
|
-
} catch (error) {
|
|
8020
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} unable to read codex quota for "${stepName}" (${this.formatQuotaError(error)})`);
|
|
8021
|
-
return null;
|
|
8022
|
-
}
|
|
8023
|
-
}
|
|
8024
|
-
async waitForQuotaDelay(stepName, command, remainingMs) {
|
|
8025
|
-
const controller = new AbortController();
|
|
8026
|
-
this.activeQuotaWait = {
|
|
8027
|
-
controller,
|
|
8028
|
-
signal: null,
|
|
8029
|
-
stepName
|
|
8030
|
-
};
|
|
8031
|
-
try {
|
|
8032
|
-
let timeLeftMs = remainingMs;
|
|
8033
|
-
while (timeLeftMs > 0) {
|
|
8034
|
-
const sleepMs = Math.min(timeLeftMs, QUOTA_WAIT_POLL_INTERVAL_MS);
|
|
8035
|
-
await this.waitForDelay(sleepMs, controller.signal);
|
|
8036
|
-
timeLeftMs -= sleepMs;
|
|
8037
|
-
}
|
|
8038
|
-
} catch (error) {
|
|
8039
|
-
if (controller.signal.aborted) throw new WorkflowInterruptedError(this.activeQuotaWait?.signal ?? TERMINATE_SIGNAL$1, {
|
|
8040
|
-
cause: /* @__PURE__ */ new Error(`Interrupted while waiting for Codex quota reset`),
|
|
8041
|
-
context: {
|
|
8042
|
-
...this.createInterruptContext(stepName, command),
|
|
8043
|
-
phase: QUOTA_WAIT_SOURCE
|
|
8044
|
-
}
|
|
8045
|
-
});
|
|
8046
|
-
throw error;
|
|
8047
|
-
} finally {
|
|
8048
|
-
this.activeQuotaWait = null;
|
|
8049
|
-
}
|
|
8050
|
-
}
|
|
8051
|
-
async waitForDelay(delayMs, signal) {
|
|
8052
|
-
await new Promise((resolveDelay, rejectDelay) => {
|
|
8053
|
-
const timeout = setTimeout(() => {
|
|
8054
|
-
signal.removeEventListener("abort", onAbort);
|
|
8055
|
-
resolveDelay();
|
|
8056
|
-
}, delayMs);
|
|
8057
|
-
const onAbort = () => {
|
|
8058
|
-
clearTimeout(timeout);
|
|
8059
|
-
signal.removeEventListener("abort", onAbort);
|
|
8060
|
-
rejectDelay(/* @__PURE__ */ new Error("aborted"));
|
|
8061
|
-
};
|
|
8062
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
8063
|
-
});
|
|
8064
|
-
}
|
|
8065
|
-
formatQuotaError(error) {
|
|
8066
|
-
if (error instanceof Error && error.message.trim().length > 0) return error.message;
|
|
8067
|
-
return "unknown quota error";
|
|
8068
|
-
}
|
|
8069
7809
|
/**
|
|
8070
7810
|
* Resolve the per-step timeout from workflow YAML into milliseconds.
|
|
8071
7811
|
*/
|
|
@@ -8210,10 +7950,8 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8210
7950
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : PROCESS_EXIT_WAIT_TIMEOUT_MS;
|
|
8211
7951
|
}
|
|
8212
7952
|
/**
|
|
8213
|
-
*
|
|
8214
|
-
*
|
|
8215
|
-
* interactive agent can flush its final telemetry batch (e.g. Claude Code's
|
|
8216
|
-
* 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
|
|
8217
7955
|
* immediately, so this only adds latency when a child lingers. Operator-tunable
|
|
8218
7956
|
* via `WORKFLOW_STEP_FORCE_KILL_GRACE_MS`; defaults to STEP_COMPLETION_KILL_GRACE_MS.
|
|
8219
7957
|
*/
|
|
@@ -8353,7 +8091,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8353
8091
|
* Interactive TUIs such as Claude Code make themselves process-group leaders
|
|
8354
8092
|
* (pid === pgid) and spawn descendants into that group. Reaping by pid alone
|
|
8355
8093
|
* leaves anything spawned after the one-shot tree snapshot alive, which keeps
|
|
8356
|
-
* the interactive session running after
|
|
8094
|
+
* the interactive session running after a stop or pause request.
|
|
8357
8095
|
*/
|
|
8358
8096
|
collectInteractiveProcessGroupIds(processIds) {
|
|
8359
8097
|
if (processIds.length === 0) return [];
|
|
@@ -8456,38 +8194,17 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8456
8194
|
return false;
|
|
8457
8195
|
}
|
|
8458
8196
|
}
|
|
8459
|
-
/**
|
|
8460
|
-
|
|
8461
|
-
* YES to when the agent finishes its turn. The path is injected into
|
|
8462
|
-
* WORKFLOW_STATUS_FILE so the hook can locate it directly — no fallback
|
|
8463
|
-
* marker file is used.
|
|
8464
|
-
*/
|
|
8465
|
-
async createStatusFile() {
|
|
8466
|
-
if (!this.runtime.temporaryDirectory) throw new Error("Workflow interactive status files require an admitted temporaryDirectory");
|
|
8467
|
-
const filePath = (0, node_path.join)(this.runtime.temporaryDirectory, `${STATUS_FILE_PREFIX}${(0, node_crypto.randomUUID)()}${STATUS_FILE_SUFFIX}`);
|
|
8468
|
-
(0, _agimon_ai_po_core_platform.getOrThrow)(await this.runtime.fs.writeFile(filePath, "", this.runtime.ioContext));
|
|
8469
|
-
return filePath;
|
|
8470
|
-
}
|
|
8471
|
-
/**
|
|
8472
|
-
* Race interactive step execution against agent completion and workflow stop files.
|
|
8473
|
-
* When the file contains YES, SIGTERM the step process and wait for
|
|
8474
|
-
* it to exit before returning `status_completed`. Escalates to SIGKILL
|
|
8475
|
-
* if the process ignores SIGTERM. The next job must not start until
|
|
8476
|
-
* the child process tree has fully exited.
|
|
8477
|
-
*/
|
|
8478
|
-
async raceInteractiveCompletion(executionPromise, statusFilePath, stepName, stopRequestPath, pausePolicy) {
|
|
8197
|
+
/** Race interactive execution against workflow stop and pause requests. */
|
|
8198
|
+
async raceInteractiveCompletion(executionPromise, stepName, stopRequestPath, pausePolicy) {
|
|
8479
8199
|
return new Promise((resolveRace) => {
|
|
8480
8200
|
let settled = false;
|
|
8481
|
-
let statusFileTriggered = false;
|
|
8482
8201
|
let stopRequestTriggered = false;
|
|
8483
8202
|
let pauseRequestTriggered = false;
|
|
8484
8203
|
const pauseRequestPath = stopRequestPath ? (0, node_path.join)((0, node_path.dirname)(stopRequestPath), PAUSE_REQUEST_FILENAME) : void 0;
|
|
8485
8204
|
let forceKillTimer = null;
|
|
8486
8205
|
let completionSettleTimer = null;
|
|
8487
|
-
let watcher = null;
|
|
8488
8206
|
let stopWatcher = null;
|
|
8489
8207
|
let pauseWatcher = null;
|
|
8490
|
-
let pollTimer = null;
|
|
8491
8208
|
let stopPollTimer = null;
|
|
8492
8209
|
let pausePollTimer = null;
|
|
8493
8210
|
let signalDelivered = false;
|
|
@@ -8495,7 +8212,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8495
8212
|
const resolveCompletionSource = (result) => {
|
|
8496
8213
|
if (stopRequestTriggered) return "stop-request";
|
|
8497
8214
|
if (pauseRequestTriggered) return "pause-request";
|
|
8498
|
-
if (statusFileTriggered) return "status-file";
|
|
8499
8215
|
switch (result.status) {
|
|
8500
8216
|
case RESULT_STATUS_TIMED_OUT: return "timed-out";
|
|
8501
8217
|
case RESULT_STATUS_SPAWN_ERROR: return "spawn-error";
|
|
@@ -8506,10 +8222,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8506
8222
|
const settle = async (result) => {
|
|
8507
8223
|
if (settled) return;
|
|
8508
8224
|
settled = true;
|
|
8509
|
-
if (watcher) {
|
|
8510
|
-
await watcher.close(this.runtime.ioContext).catch((error) => this.logger.warn(`Workflow watcher cleanup failed: ${String(error)}`));
|
|
8511
|
-
watcher = null;
|
|
8512
|
-
}
|
|
8513
8225
|
if (stopWatcher) {
|
|
8514
8226
|
await stopWatcher.close(this.runtime.ioContext).catch((error) => this.logger.warn(`Workflow watcher cleanup failed: ${String(error)}`));
|
|
8515
8227
|
stopWatcher = null;
|
|
@@ -8518,10 +8230,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8518
8230
|
await pauseWatcher.close(this.runtime.ioContext).catch((error) => this.logger.warn(`Workflow watcher cleanup failed: ${String(error)}`));
|
|
8519
8231
|
pauseWatcher = null;
|
|
8520
8232
|
}
|
|
8521
|
-
if (pollTimer) {
|
|
8522
|
-
clearInterval(pollTimer);
|
|
8523
|
-
pollTimer = null;
|
|
8524
|
-
}
|
|
8525
8233
|
if (stopPollTimer) {
|
|
8526
8234
|
clearInterval(stopPollTimer);
|
|
8527
8235
|
stopPollTimer = null;
|
|
@@ -8545,25 +8253,13 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8545
8253
|
await this.recordInteractiveCompletion({
|
|
8546
8254
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8547
8255
|
stepName,
|
|
8548
|
-
statusFilePath,
|
|
8549
8256
|
completionSource: resolveCompletionSource(settledResult),
|
|
8550
|
-
statusFileSignaled: statusFileTriggered,
|
|
8551
8257
|
sigkillEscalated: sigkillEscalated || (this.lastInteractiveReap?.sigkillEscalated ?? false),
|
|
8552
8258
|
survivors: this.lastInteractiveReap?.survivors ?? []
|
|
8553
8259
|
});
|
|
8554
8260
|
this.lastInteractiveReap = null;
|
|
8555
8261
|
resolveRace(settledResult);
|
|
8556
8262
|
};
|
|
8557
|
-
const statusFileHasCompletionValue = async () => {
|
|
8558
|
-
try {
|
|
8559
|
-
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;
|
|
8560
|
-
} catch (error) {
|
|
8561
|
-
const code = error.code;
|
|
8562
|
-
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)}`);
|
|
8563
|
-
else this.logger.info(` ${DIM$3}status-file${RESET$3} transient FS error (${code}) polling ${stepName}`);
|
|
8564
|
-
return false;
|
|
8565
|
-
}
|
|
8566
|
-
};
|
|
8567
8263
|
const scheduleAbsoluteSettle = (result, delayMs) => {
|
|
8568
8264
|
if (settled || completionSettleTimer) return;
|
|
8569
8265
|
completionSettleTimer = setTimeout(() => {
|
|
@@ -8582,24 +8278,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8582
8278
|
settle(result);
|
|
8583
8279
|
}, delayMs);
|
|
8584
8280
|
};
|
|
8585
|
-
const checkFileContent = async () => {
|
|
8586
|
-
if (!await statusFileHasCompletionValue() || settled || statusFileTriggered) return;
|
|
8587
|
-
statusFileTriggered = true;
|
|
8588
|
-
const graceMs = this.stepCompletionKillGraceMs();
|
|
8589
|
-
signalDelivered = this.killActiveStep(TERMINATE_SIGNAL$1);
|
|
8590
|
-
if (!signalDelivered) {
|
|
8591
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} status-file: SIGTERM could not be delivered, process may have already exited`);
|
|
8592
|
-
scheduleAbsoluteSettle(STATUS_FILE_COMPLETED_RESULT, PROCESS_EXIT_WAIT_TIMEOUT_MS);
|
|
8593
|
-
return;
|
|
8594
|
-
}
|
|
8595
|
-
forceKillTimer = setTimeout(() => {
|
|
8596
|
-
if (settled) return;
|
|
8597
|
-
sigkillEscalated = true;
|
|
8598
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} did not exit after status-file SIGTERM, forcing SIGKILL`);
|
|
8599
|
-
this.killActiveStep(TERMINATE_FORCE_KILL_SIGNAL);
|
|
8600
|
-
}, graceMs);
|
|
8601
|
-
scheduleAbsoluteSettle(STATUS_FILE_COMPLETED_RESULT, graceMs + PROCESS_EXIT_WAIT_TIMEOUT_MS);
|
|
8602
|
-
};
|
|
8603
8281
|
const stopRequestExists = async () => Boolean(stopRequestPath && await this.hasCurrentStopRequest(stopRequestPath));
|
|
8604
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");
|
|
8605
8283
|
const checkStopRequest = async () => {
|
|
@@ -8639,23 +8317,9 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8639
8317
|
}, graceMs);
|
|
8640
8318
|
scheduleAbsoluteSettle({ status: RESULT_STATUS_PAUSE_REQUESTED }, graceMs + PROCESS_EXIT_WAIT_TIMEOUT_MS);
|
|
8641
8319
|
};
|
|
8642
|
-
try {
|
|
8643
|
-
this.watchStatusFile([{ path: statusFilePath }], () => {
|
|
8644
|
-
checkFileContent().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8645
|
-
}, this.runtime.ioContext).then(async (result) => {
|
|
8646
|
-
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
8647
|
-
if (settled) await admitted.close(this.runtime.ioContext);
|
|
8648
|
-
else watcher = admitted;
|
|
8649
|
-
}).catch((error) => this.logger.warn(`Workflow status-file watcher unavailable, polling instead: ${String(error)}`));
|
|
8650
|
-
} catch (error) {
|
|
8651
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file watcher setup failed for ${stepName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
8652
|
-
}
|
|
8653
|
-
pollTimer = setInterval(() => {
|
|
8654
|
-
checkFileContent().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8655
|
-
}, STATUS_FILE_POLL_INTERVAL_MS);
|
|
8656
8320
|
if (stopRequestPath) {
|
|
8657
8321
|
try {
|
|
8658
|
-
this.
|
|
8322
|
+
this.watchControlFile([{ path: stopRequestPath }], () => {
|
|
8659
8323
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8660
8324
|
}, this.runtime.ioContext).then(async (result) => {
|
|
8661
8325
|
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
@@ -8671,7 +8335,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8671
8335
|
}
|
|
8672
8336
|
if (pauseRequestPath) {
|
|
8673
8337
|
try {
|
|
8674
|
-
this.
|
|
8338
|
+
this.watchControlFile([{ path: pauseRequestPath }], () => {
|
|
8675
8339
|
checkPauseRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8676
8340
|
}, this.runtime.ioContext).then(async (result) => {
|
|
8677
8341
|
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
@@ -8685,7 +8349,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8685
8349
|
checkPauseRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8686
8350
|
}, STOP_REQUEST_POLL_INTERVAL_MS);
|
|
8687
8351
|
}
|
|
8688
|
-
checkFileContent().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8689
8352
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8690
8353
|
checkPauseRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8691
8354
|
executionPromise.then(async (result) => {
|
|
@@ -8694,42 +8357,9 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8694
8357
|
settle({ status: RESULT_STATUS_STOP_REQUESTED });
|
|
8695
8358
|
return;
|
|
8696
8359
|
}
|
|
8697
|
-
const
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
settle({ status: RESULT_STATUS_PAUSE_REQUESTED });
|
|
8701
|
-
return;
|
|
8702
|
-
}
|
|
8703
|
-
if (!completedViaStatusFile) {
|
|
8704
|
-
settle(result);
|
|
8705
|
-
return;
|
|
8706
|
-
}
|
|
8707
|
-
if (!statusFileTriggered) {
|
|
8708
|
-
statusFileTriggered = true;
|
|
8709
|
-
this.logger.info(` ${GREEN$2}${STATUS_DONE}${RESET$3} ${stepName} status-file observed during process exit handling`);
|
|
8710
|
-
}
|
|
8711
|
-
switch (result.status) {
|
|
8712
|
-
case RESULT_STATUS_SPAWN_ERROR:
|
|
8713
|
-
case RESULT_STATUS_TIMED_OUT:
|
|
8714
|
-
settle(result);
|
|
8715
|
-
return;
|
|
8716
|
-
case RESULT_STATUS_SIGNALED:
|
|
8717
|
-
if (sigkillEscalated) this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} required SIGKILL escalation (work completed via status-file)`);
|
|
8718
|
-
settle(STATUS_FILE_COMPLETED_RESULT);
|
|
8719
|
-
return;
|
|
8720
|
-
case RESULT_STATUS_COMPLETED:
|
|
8721
|
-
if (sigkillEscalated) this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} ${stepName} required SIGKILL escalation (work completed via status-file, exit code ${result.exitCode})`);
|
|
8722
|
-
settle(STATUS_FILE_COMPLETED_RESULT);
|
|
8723
|
-
return;
|
|
8724
|
-
case RESULT_STATUS_STATUS_COMPLETED:
|
|
8725
|
-
settle(result);
|
|
8726
|
-
return;
|
|
8727
|
-
case RESULT_STATUS_STOP_REQUESTED:
|
|
8728
|
-
case RESULT_STATUS_PAUSE_REQUESTED:
|
|
8729
|
-
settle(result);
|
|
8730
|
-
return;
|
|
8731
|
-
default: settle(result);
|
|
8732
|
-
}
|
|
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);
|
|
8733
8363
|
});
|
|
8734
8364
|
});
|
|
8735
8365
|
}
|
|
@@ -8778,7 +8408,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8778
8408
|
}, FORCE_KILL_GRACE_PERIOD_MS);
|
|
8779
8409
|
};
|
|
8780
8410
|
try {
|
|
8781
|
-
this.
|
|
8411
|
+
this.watchControlFile([{ path: stopRequestPath }], () => {
|
|
8782
8412
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8783
8413
|
}, this.runtime.ioContext).then(async (result) => {
|
|
8784
8414
|
const admitted = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
@@ -8793,7 +8423,7 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8793
8423
|
}, STOP_REQUEST_POLL_INTERVAL_MS);
|
|
8794
8424
|
checkStopRequest().catch((error) => this.logger.warn(`Workflow control check failed: ${String(error)}`));
|
|
8795
8425
|
executionPromise.then(async (result) => {
|
|
8796
|
-
const protectedPauseEligible = result.status ===
|
|
8426
|
+
const protectedPauseEligible = result.status === RESULT_STATUS_COMPLETED && result.exitCode === 0;
|
|
8797
8427
|
if (stopRequestTriggered) settle({ status: RESULT_STATUS_STOP_REQUESTED });
|
|
8798
8428
|
else if (pauseRequestTriggered && (pausePolicy !== "protected" || protectedPauseEligible)) settle({ status: RESULT_STATUS_PAUSE_REQUESTED });
|
|
8799
8429
|
else settle(result);
|
|
@@ -8903,16 +8533,6 @@ var StepRunnerService = class StepRunnerService {
|
|
|
8903
8533
|
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} failed to restore terminal state: ${String(error)}`);
|
|
8904
8534
|
}
|
|
8905
8535
|
}
|
|
8906
|
-
/**
|
|
8907
|
-
* Remove the temp status file and the well-known marker file after step completion.
|
|
8908
|
-
*/
|
|
8909
|
-
async cleanupStatusFile(statusFilePath) {
|
|
8910
|
-
try {
|
|
8911
|
-
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));
|
|
8912
|
-
} catch (error) {
|
|
8913
|
-
this.logger.warn(` ${YELLOW$2}${STATUS_WARN}${RESET$3} status-file cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
8914
|
-
}
|
|
8915
|
-
}
|
|
8916
8536
|
};
|
|
8917
8537
|
//#endregion
|
|
8918
8538
|
//#region src/services/TriggerService/index.ts
|
|
@@ -9636,7 +9256,7 @@ var RunWorkflowService = class {
|
|
|
9636
9256
|
this.launcherMetadata = dependencies.launcherMetadata;
|
|
9637
9257
|
this.parser = dependencies.parser ?? new WorkflowParserService(this.runtime);
|
|
9638
9258
|
this.serviceManager = dependencies.serviceManager ?? new BackgroundServiceManager(this.runtime, this.logger);
|
|
9639
|
-
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);
|
|
9640
9260
|
this.registry = dependencies.registry ?? new WorkflowRegistryService(this.runtime);
|
|
9641
9261
|
this.runDirectoryService = dependencies.runDirectoryService ?? new RunDirectoryService(this.runtime, this.registry.writeCoordinator);
|
|
9642
9262
|
this.jobRunner = dependencies.jobRunner ?? new JobRunnerService(this.runtime, this.parser, this.stepRunner, this.logger, this.runDirectoryService);
|
|
@@ -9648,6 +9268,7 @@ var RunWorkflowService = class {
|
|
|
9648
9268
|
* Run the workflow from trigger preparation through cleanup.
|
|
9649
9269
|
*/
|
|
9650
9270
|
async run(input) {
|
|
9271
|
+
if ("cliAgent" in input) throw new Error("cliAgent is retired. Use runner explicitly.");
|
|
9651
9272
|
this.stepRunner.resetInterruption();
|
|
9652
9273
|
this.triggerService.resetInterruption();
|
|
9653
9274
|
this.outputLines = [];
|
|
@@ -9835,8 +9456,7 @@ var RunWorkflowService = class {
|
|
|
9835
9456
|
});
|
|
9836
9457
|
}
|
|
9837
9458
|
resolveRunner(input, workflow) {
|
|
9838
|
-
|
|
9839
|
-
return input.runner ?? input.cliAgent ?? (workflow ? this.resolveWorkflowRunner(workflow) : void 0);
|
|
9459
|
+
return input.runner ?? (workflow ? this.resolveWorkflowRunner(workflow) : void 0);
|
|
9840
9460
|
}
|
|
9841
9461
|
/**
|
|
9842
9462
|
* Execute the workflow after signal handlers are installed.
|
|
@@ -9969,7 +9589,6 @@ var RunWorkflowService = class {
|
|
|
9969
9589
|
if (dryRun && input.recovery) registryRun = await this.createRecoveryDryRunHandle(input, resolvedWorkspace);
|
|
9970
9590
|
else registryRun = await this.registry.createRun({
|
|
9971
9591
|
activeRepairId: input.recovery?.activeRepairId,
|
|
9972
|
-
cliAgent: input.cliAgent,
|
|
9973
9592
|
continueOnError: input.continueOnError,
|
|
9974
9593
|
displayName: workflowName,
|
|
9975
9594
|
dryRun,
|
|
@@ -10062,7 +9681,6 @@ var RunWorkflowService = class {
|
|
|
10062
9681
|
}
|
|
10063
9682
|
if (!await this.triggerService.handleAgentDecision(workflow, workflowEnv, inputs, secrets, {
|
|
10064
9683
|
runner,
|
|
10065
|
-
cliAgent: input.cliAgent,
|
|
10066
9684
|
dryRun,
|
|
10067
9685
|
continueOnError,
|
|
10068
9686
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10101,7 +9719,6 @@ var RunWorkflowService = class {
|
|
|
10101
9719
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10102
9720
|
if (!await this.worktreeService.runHook(workflow.worktree.beforeCreate, workflowDir, workflowEnv, inputs, secrets, {
|
|
10103
9721
|
runner,
|
|
10104
|
-
cliAgent: input.cliAgent,
|
|
10105
9722
|
dryRun,
|
|
10106
9723
|
continueOnError,
|
|
10107
9724
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10133,7 +9750,6 @@ var RunWorkflowService = class {
|
|
|
10133
9750
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10134
9751
|
if (!await this.worktreeService.runHook(workflow.worktree.afterCreate, worktreePath, workflowEnv, inputs, secrets, {
|
|
10135
9752
|
runner,
|
|
10136
|
-
cliAgent: input.cliAgent,
|
|
10137
9753
|
dryRun,
|
|
10138
9754
|
continueOnError,
|
|
10139
9755
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10166,7 +9782,6 @@ var RunWorkflowService = class {
|
|
|
10166
9782
|
const preStopRequestPath = registryRun.stopRequestPath;
|
|
10167
9783
|
if (!await this.recordPhase(progress, PRE_PHASE_JOB, () => this.runPreBlock(preBlock, workflowEnv, inputs, secrets, {
|
|
10168
9784
|
runner,
|
|
10169
|
-
cliAgent: input.cliAgent,
|
|
10170
9785
|
dryRun,
|
|
10171
9786
|
continueOnError,
|
|
10172
9787
|
progress,
|
|
@@ -10244,7 +9859,6 @@ var RunWorkflowService = class {
|
|
|
10244
9859
|
runDirectory: workflow["run-directory"]
|
|
10245
9860
|
}, {
|
|
10246
9861
|
runner,
|
|
10247
|
-
cliAgent: input.cliAgent,
|
|
10248
9862
|
dryRun,
|
|
10249
9863
|
continueOnError,
|
|
10250
9864
|
stopRequestPath,
|
|
@@ -10351,7 +9965,6 @@ var RunWorkflowService = class {
|
|
|
10351
9965
|
} : void 0
|
|
10352
9966
|
}, {
|
|
10353
9967
|
runner,
|
|
10354
|
-
cliAgent: input.cliAgent,
|
|
10355
9968
|
dryRun,
|
|
10356
9969
|
continueOnError,
|
|
10357
9970
|
stopRequestPath: registryRun.stopRequestPath,
|
|
@@ -10562,7 +10175,6 @@ var RunWorkflowService = class {
|
|
|
10562
10175
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10563
10176
|
if (!await this.worktreeService.runHook(workflow.worktree.beforeCompleted, worktreePath, workflowEnv, inputs, secrets, {
|
|
10564
10177
|
runner,
|
|
10565
|
-
cliAgent: input.cliAgent,
|
|
10566
10178
|
dryRun,
|
|
10567
10179
|
continueOnError
|
|
10568
10180
|
})) {
|
|
@@ -10587,7 +10199,6 @@ var RunWorkflowService = class {
|
|
|
10587
10199
|
try {
|
|
10588
10200
|
if (!await this.recordPhase(progress, POST_PHASE_JOB, () => this.runPostBlock(postBlock, workflowEnv, inputs, secrets, {
|
|
10589
10201
|
runner,
|
|
10590
|
-
cliAgent: input.cliAgent,
|
|
10591
10202
|
dryRun,
|
|
10592
10203
|
continueOnError,
|
|
10593
10204
|
progress,
|
|
@@ -10614,7 +10225,6 @@ var RunWorkflowService = class {
|
|
|
10614
10225
|
this.logger.info(` ${"─".repeat(50)}`);
|
|
10615
10226
|
if (!await this.worktreeService.runHook(workflow.worktree.afterCompleted, originalDir, workflowEnv, inputs, secrets, {
|
|
10616
10227
|
runner,
|
|
10617
|
-
cliAgent: input.cliAgent,
|
|
10618
10228
|
dryRun,
|
|
10619
10229
|
continueOnError
|
|
10620
10230
|
})) {
|
|
@@ -11289,13 +10899,17 @@ var RecoverWorkflowService = class {
|
|
|
11289
10899
|
if (!recoveredJob) throw new Error(`Workflow run "${record.workspace}/${record.runKey}" does not include a recoverable failed job`);
|
|
11290
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}`);
|
|
11291
10901
|
const runner = input.runner ?? record.runner ?? record.cliAgent;
|
|
11292
|
-
|
|
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.");
|
|
11293
10908
|
const originalJob = fixRestartFrom && !activeRepair ? void 0 : record.job;
|
|
11294
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`);
|
|
11295
10910
|
const ownerSessionId = claimedOwnerSessionId?.trim();
|
|
11296
10911
|
const envOverrides = ownerSessionId ? { [PI_SESSION_ENV]: ownerSessionId } : void 0;
|
|
11297
10912
|
return await this.runner.run({
|
|
11298
|
-
cliAgent,
|
|
11299
10913
|
runner,
|
|
11300
10914
|
command: record.command,
|
|
11301
10915
|
choice: record.choice,
|
|
@@ -11352,12 +10966,6 @@ var RecoverWorkflowService = class {
|
|
|
11352
10966
|
}
|
|
11353
10967
|
};
|
|
11354
10968
|
//#endregion
|
|
11355
|
-
Object.defineProperty(exports, "CodexQuotaService", {
|
|
11356
|
-
enumerable: true,
|
|
11357
|
-
get: function() {
|
|
11358
|
-
return CodexQuotaService;
|
|
11359
|
-
}
|
|
11360
|
-
});
|
|
11361
10969
|
Object.defineProperty(exports, "NativeTerminalService", {
|
|
11362
10970
|
enumerable: true,
|
|
11363
10971
|
get: function() {
|
|
@@ -11448,12 +11056,6 @@ Object.defineProperty(exports, "diagnoseWorkflows", {
|
|
|
11448
11056
|
return diagnoseWorkflows;
|
|
11449
11057
|
}
|
|
11450
11058
|
});
|
|
11451
|
-
Object.defineProperty(exports, "formatArtifactWarning", {
|
|
11452
|
-
enumerable: true,
|
|
11453
|
-
get: function() {
|
|
11454
|
-
return formatArtifactWarning;
|
|
11455
|
-
}
|
|
11456
|
-
});
|
|
11457
11059
|
Object.defineProperty(exports, "gateStepDecision", {
|
|
11458
11060
|
enumerable: true,
|
|
11459
11061
|
get: function() {
|
|
@@ -11545,4 +11147,4 @@ Object.defineProperty(exports, "workflowShellOutput", {
|
|
|
11545
11147
|
}
|
|
11546
11148
|
});
|
|
11547
11149
|
|
|
11548
|
-
//# sourceMappingURL=RecoverWorkflowService-
|
|
11150
|
+
//# sourceMappingURL=RecoverWorkflowService-CEYR10KF.cjs.map
|