@agimon-ai/po-workflow 0.0.0-alpha.105 → 0.0.0-alpha.107

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.
@@ -4501,7 +4501,6 @@ const INTERRUPT_SIGNAL$2 = "SIGINT";
4501
4501
  const HANGUP_SIGNAL$1 = "SIGHUP";
4502
4502
  const TERMINATE_SIGNAL$1 = "SIGTERM";
4503
4503
  const DEFAULT_STEP_NAME = "unnamed";
4504
- const DEFAULT_SHELL = "/bin/zsh";
4505
4504
  const FORCE_COLOR_KEY = "FORCE_COLOR";
4506
4505
  const FORCE_COLOR_VALUE = "1";
4507
4506
  const PROJECT_PATH_ENV_KEY = "PROJECT_PATH";
@@ -4670,7 +4669,7 @@ function secretRedactor(values) {
4670
4669
  *
4671
4670
  * Runtime configuration:
4672
4671
  * - Environment precedence is `runtime.baseEnvironment` -> workflow/job env -> step env.
4673
- * - Child commands run through `/bin/zsh` to match local workflow execution.
4672
+ * - Child commands use the host-selected shell, matching workflow panes and services.
4674
4673
  * - `FORCE_COLOR=1` is injected so tool output keeps ANSI formatting.
4675
4674
  */
4676
4675
  var StepRunnerService = class StepRunnerService {
@@ -5320,7 +5319,7 @@ var StepRunnerService = class StepRunnerService {
5320
5319
  ...stepEnv,
5321
5320
  [FORCE_COLOR_KEY]: FORCE_COLOR_VALUE
5322
5321
  },
5323
- shell: DEFAULT_SHELL
5322
+ shell: this.runtime.workflowHost.shellPath
5324
5323
  }) : this.runtime.workflowHost.spawn(command, [], {
5325
5324
  stdio: [
5326
5325
  this.ownsTerminal ? STDIO_INHERIT : STDIO_IGNORE,
@@ -5334,7 +5333,7 @@ var StepRunnerService = class StepRunnerService {
5334
5333
  ...secretEnv,
5335
5334
  [FORCE_COLOR_KEY]: FORCE_COLOR_VALUE
5336
5335
  },
5337
- shell: DEFAULT_SHELL
5336
+ shell: this.runtime.workflowHost.shellPath
5338
5337
  });
5339
5338
  this.activeStep = {
5340
5339
  command,
@@ -7245,7 +7244,11 @@ async function runWorkflowScript(runtime, request) {
7245
7244
  }
7246
7245
  }, PROCESS_GROUP_GRACE_MS);
7247
7246
  });
7248
- child.stdin?.on("error", () => stop("Workflow script could not receive its input."));
7247
+ const inputError = (error) => {
7248
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "EPIPE") return;
7249
+ stop("Workflow script could not receive its input.");
7250
+ };
7251
+ child.stdin?.on("error", inputError);
7249
7252
  child.stdout?.on("error", () => stop("Workflow script output stream failed."));
7250
7253
  child.stderr?.on("error", () => stop("Workflow script diagnostic stream failed."));
7251
7254
  child.stdout?.on("data", (chunk) => {
@@ -7288,8 +7291,8 @@ async function runWorkflowScript(runtime, request) {
7288
7291
  else if (!child.stdin || !child.stdout || !child.stderr) stop("Workflow script requires piped input and output.");
7289
7292
  else try {
7290
7293
  child.stdin.end(input);
7291
- } catch {
7292
- stop("Workflow script could not receive its input.");
7294
+ } catch (error) {
7295
+ inputError(error);
7293
7296
  }
7294
7297
  });
7295
7298
  }
@@ -7412,6 +7415,36 @@ function failedExecution(error) {
7412
7415
  stop: async () => void 0
7413
7416
  };
7414
7417
  }
7418
+ const INPUT_TEMPLATE = /(?:\$\{\{|\{\{)[^}]*\binputs(?:\.|\[|\s)/u;
7419
+ const ENV_TEMPLATE = /(?:\$\{\{|\{\{)[^}]*\benv\.([^.}\s]+)/gu;
7420
+ /** Whether `value` expands an input into its text, directly or through an env key in `tainted`. */
7421
+ function expandsInput(value, tainted) {
7422
+ const text = JSON.stringify(value ?? null);
7423
+ return INPUT_TEMPLATE.test(text) || [...text.matchAll(ENV_TEMPLATE)].some((match) => tainted.has(match[1] ?? ""));
7424
+ }
7425
+ /**
7426
+ * Refuses a child job whose shell text would carry an input: a `run` that expands `inputs.*`, or
7427
+ * an `env.*` key whose job or step value does. Env values reach a command as its process
7428
+ * environment, never as command text, so an input there is safe until a `run` expands it.
7429
+ */
7430
+ function assertStaticChildShell(definition) {
7431
+ const jobTainted = /* @__PURE__ */ new Set();
7432
+ for (const [key, value] of Object.entries(definition.env ?? {})) if (expandsInput(value, jobTainted)) jobTainted.add(key);
7433
+ const check = (steps) => {
7434
+ for (const step of steps) {
7435
+ if (step.parallel) check(step.parallel);
7436
+ if (step.run === void 0) continue;
7437
+ const tainted = new Set(jobTainted);
7438
+ for (const [key, value] of Object.entries(step.env ?? {})) if (expandsInput(value, jobTainted)) tainted.add(key);
7439
+ if (expandsInput(step.run, tainted)) throw new Error("Child script inputs must arrive on stdin, never through shell interpolation.");
7440
+ }
7441
+ };
7442
+ check([
7443
+ ...definition.preJob?.steps ?? [],
7444
+ ...definition.steps,
7445
+ ...definition.postJob?.steps ?? []
7446
+ ]);
7447
+ }
7415
7448
  /**
7416
7449
  * Runs workflow steps inside Po instead of a shell.
7417
7450
  *
@@ -7434,21 +7467,7 @@ function createStepExecutor(dependencies) {
7434
7467
  const runtime = dependencies.runtime;
7435
7468
  const workflow = child.context.config.workflow;
7436
7469
  const parser = new WorkflowParserService(runtime);
7437
- const staticShell = (steps) => {
7438
- for (const step of steps) {
7439
- if (step.parallel) staticShell(step.parallel);
7440
- if (step.run !== void 0 && /(?:\$\{\{|\{\{)[^}]*\binputs(?:\.|\[|\s)/u.test(JSON.stringify({
7441
- run: step.run,
7442
- env: step.env,
7443
- jobEnv: child.definition.env
7444
- }))) throw new Error("Child script inputs must arrive on stdin, never through shell interpolation.");
7445
- }
7446
- };
7447
- staticShell([
7448
- ...child.definition.preJob?.steps ?? [],
7449
- ...child.definition.steps,
7450
- ...child.definition.postJob?.steps ?? []
7451
- ]);
7470
+ assertStaticChildShell(child.definition);
7452
7471
  const usages = [];
7453
7472
  const evidence = [];
7454
7473
  const logger = {
@@ -7474,7 +7493,7 @@ function createStepExecutor(dependencies) {
7474
7493
  return {
7475
7494
  completionGuarded: true,
7476
7495
  completion: runWorkflowScript(runtime, {
7477
- command: "/bin/zsh",
7496
+ command: runtime.workflowHost.shellPath,
7478
7497
  args: ["-c", request.command],
7479
7498
  cwd: request.cwd,
7480
7499
  environment: {
@@ -7882,8 +7901,6 @@ function createStepExecutor(dependencies) {
7882
7901
  }
7883
7902
  };
7884
7903
  }
7885
- /** The shell a command step runs in, the same one the engine spawns it with. */
7886
- const STEP_SHELL = "/bin/zsh";
7887
7904
  /** Namespace for step pane sockets, apart from whole-run terminal sockets. */
7888
7905
  const STEP_PANE_SOCKET_SCOPE = "po-workflow-steps";
7889
7906
  const PANE_LOG_SUFFIX = ".log";
@@ -7919,7 +7936,7 @@ function createNativeStepPaneLauncher(runtime, service = new NativeTerminalServi
7919
7936
  if (runtime.temporaryDirectory === void 0) throw new Error("Workflow step panes require an admitted temporary directory.");
7920
7937
  if (!await service.available()) return void 0;
7921
7938
  await service.spawn({
7922
- command: STEP_SHELL,
7939
+ command: runtime.workflowHost.shellPath,
7923
7940
  args: ["-c", request.command],
7924
7941
  cwd: request.cwd,
7925
7942
  env: { ...request.env },
@@ -10446,10 +10463,16 @@ function createWorkflowHost(options) {
10446
10463
  ...options,
10447
10464
  environment: Object.freeze({ ...options.environment })
10448
10465
  };
10466
+ let shellPath = "/bin/sh";
10467
+ try {
10468
+ (0, node_fs.accessSync)("/bin/zsh", node_fs.constants.X_OK);
10469
+ shellPath = "/bin/zsh";
10470
+ } catch {}
10449
10471
  return Object.freeze({
10450
10472
  processId: process.pid,
10451
10473
  executablePath: process.execPath,
10452
10474
  platform: process.platform,
10475
+ shellPath,
10453
10476
  isElectron: Boolean(process.versions.electron),
10454
10477
  writeStdout: (text) => {
10455
10478
  process.stdout.write(text);
@@ -10830,7 +10853,7 @@ var BackgroundServiceManager = class {
10830
10853
  ...serviceEnv,
10831
10854
  FORCE_COLOR: "1"
10832
10855
  },
10833
- shell: "/bin/zsh",
10856
+ shell: this.runtime.workflowHost.shellPath,
10834
10857
  detached: true
10835
10858
  });
10836
10859
  } catch (error) {
@@ -10972,7 +10995,7 @@ var BackgroundServiceManager = class {
10972
10995
  while (Date.now() - start < timeout) {
10973
10996
  if (shouldAbort?.()) return false;
10974
10997
  try {
10975
- await workflowShellOutput(this.runtime, `/bin/zsh -c ${require_workflowCommandTemplate.escapeShellArg(checkCmd)}`, {
10998
+ await workflowShellOutput(this.runtime, `${require_workflowCommandTemplate.escapeShellArg(this.runtime.workflowHost.shellPath)} -c ${require_workflowCommandTemplate.escapeShellArg(checkCmd)}`, {
10976
10999
  cwd: workDir,
10977
11000
  environment: readyEnv,
10978
11001
  timeoutMs: 5e3
@@ -13569,4 +13592,4 @@ Object.defineProperty(exports, "workflowShellOutput", {
13569
13592
  }
13570
13593
  });
13571
13594
 
13572
- //# sourceMappingURL=RecoverWorkflowService-CFiF9ZBU.cjs.map
13595
+ //# sourceMappingURL=RecoverWorkflowService-2WMhxaZd.cjs.map