@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.
Files changed (29) hide show
  1. package/dist/{RecoverWorkflowService-BLehH1qi.cjs → RecoverWorkflowService-CEYR10KF.cjs} +136 -445
  2. package/dist/RecoverWorkflowService-CEYR10KF.cjs.map +1 -0
  3. package/dist/{RecoverWorkflowService-BOCa93OS.mjs → RecoverWorkflowService-CY8wIc3A.mjs} +137 -434
  4. package/dist/RecoverWorkflowService-CY8wIc3A.mjs.map +1 -0
  5. package/dist/cli.cjs +94 -1592
  6. package/dist/cli.cjs.map +1 -1
  7. package/dist/cli.mjs +95 -1593
  8. package/dist/cli.mjs.map +1 -1
  9. package/dist/extensions/native.mjs +2 -0
  10. package/dist/extensions/native.mjs.map +1 -1
  11. package/dist/extensions/server.cjs +40 -25
  12. package/dist/extensions/server.cjs.map +1 -1
  13. package/dist/extensions/server.mjs +40 -25
  14. package/dist/extensions/server.mjs.map +1 -1
  15. package/dist/extensions/web.mjs +5 -3
  16. package/dist/extensions/web.mjs.map +1 -1
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.d.mts +2 -1
  19. package/dist/index.d.mts.map +1 -1
  20. package/dist/index.mjs +1 -1
  21. package/dist/{workflowLaunchCommand-GGqimmTC.mjs → workflowLaunchCommand-7WRoiOKJ.mjs} +5 -3
  22. package/dist/workflowLaunchCommand-7WRoiOKJ.mjs.map +1 -0
  23. package/dist/{workflowLaunchCommand-C69Nn3k5.cjs → workflowLaunchCommand-C7anFsDH.cjs} +5 -3
  24. package/dist/workflowLaunchCommand-C7anFsDH.cjs.map +1 -0
  25. package/package.json +20 -20
  26. package/dist/RecoverWorkflowService-BLehH1qi.cjs.map +0 -1
  27. package/dist/RecoverWorkflowService-BOCa93OS.mjs.map +0 -1
  28. package/dist/workflowLaunchCommand-C69Nn3k5.cjs.map +0 -1
  29. 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
- quotaService;
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, quotaService = new CodexQuotaService(runtime), watchStatusFile = runtime.fs.watch.bind(runtime.fs), runDirectoryService = new RunDirectoryService(runtime), ownsTerminal = true, stepExecutor) {
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.quotaService = quotaService;
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.quotaService, this.watchStatusFile, this.runDirectoryService, this.ownsTerminal, this.stepExecutor);
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 runConfig = resolvedStepCommand?.runConfig ?? step.runConfig;
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
- let statusFilePath;
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 quotaFailureRetried = false;
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 && statusFilePath ? await this.raceInteractiveCompletion(executionPromise, statusFilePath, stepName, options.stopRequestPath, step["pause-policy"] ?? "replay") : options.stopRequestPath ? await this.raceStopRequest(executionPromise, stepName, options.stopRequestPath, step["pause-policy"] ?? "replay") : await executionPromise;
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
- child.stdout?.on("data", (data) => {
7443
- for (const line of data.toString().split("\n")) if (line) {
7444
- keep(line);
7445
- this.logger.info(line);
7446
- }
7447
- });
7448
- child.stderr?.on("data", (data) => {
7449
- for (const line of data.toString().split("\n")) if (line) {
7450
- keep(line);
7451
- this.logger.error(line);
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, pause and status-file
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 ?? options.cliAgent;
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
- * SIGTERM→SIGKILL grace on the completion path (status file signalled `YES`).
8129
- * Deliberately longer than the timeout-path `FORCE_KILL_GRACE_PERIOD_MS` so an
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 the Stop hook signalled completion.
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
- * Create an empty temp file that the Claude Code Stop hook will write
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.watchStatusFile([{ path: stopRequestPath }], () => {
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.watchStatusFile([{ path: pauseRequestPath }], () => {
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 completedViaStatusFile = statusFileTriggered || await statusFileHasCompletionValue();
8613
- const protectedPauseEligible = result.status === RESULT_STATUS_STATUS_COMPLETED || result.status === RESULT_STATUS_COMPLETED && result.exitCode === 0;
8614
- if (pauseRequestTriggered && (pausePolicy !== "protected" || protectedPauseEligible) && (pausePolicy === "protected" || !statusFileTriggered)) {
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.watchStatusFile([{ path: stopRequestPath }], () => {
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 === RESULT_STATUS_STATUS_COMPLETED || result.status === RESULT_STATUS_COMPLETED && result.exitCode === 0;
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, void 0, dependencies.ownsTerminal, dependencies.stepExecutor);
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
- if (input.runner && input.cliAgent && input.runner !== input.cliAgent) throw new Error(`Conflicting runner selectors: runner="${input.runner}" cliAgent="${input.cliAgent}"`);
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
- const cliAgent = runner === record.cliAgent ? record.cliAgent : void 0;
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-BLehH1qi.cjs.map
11150
+ //# sourceMappingURL=RecoverWorkflowService-CEYR10KF.cjs.map