@seawork/server 1.0.21 → 1.0.22-rc.2

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 (62) hide show
  1. package/dist/scripts/supervisor-entrypoint.js +22 -0
  2. package/dist/scripts/supervisor-entrypoint.js.map +1 -1
  3. package/dist/scripts/supervisor-native-classifier.js +60 -0
  4. package/dist/scripts/supervisor-native-classifier.js.map +1 -0
  5. package/dist/server/client/daemon-client.d.ts +7 -1
  6. package/dist/server/client/daemon-client.d.ts.map +1 -1
  7. package/dist/server/client/daemon-client.js +13 -0
  8. package/dist/server/client/daemon-client.js.map +1 -1
  9. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  10. package/dist/server/server/agent/agent-manager.js +14 -0
  11. package/dist/server/server/agent/agent-manager.js.map +1 -1
  12. package/dist/server/server/agent/install-state.d.ts +248 -0
  13. package/dist/server/server/agent/install-state.d.ts.map +1 -0
  14. package/dist/server/server/agent/install-state.js +126 -0
  15. package/dist/server/server/agent/install-state.js.map +1 -0
  16. package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
  17. package/dist/server/server/agent/providers/claude-agent.js +8 -8
  18. package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
  19. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  20. package/dist/server/server/agent/providers/codex-app-server-agent.js +96 -29
  21. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  22. package/dist/server/server/agent/providers/codex-binary-resolver.d.ts +23 -0
  23. package/dist/server/server/agent/providers/codex-binary-resolver.d.ts.map +1 -0
  24. package/dist/server/server/agent/providers/codex-binary-resolver.js +175 -0
  25. package/dist/server/server/agent/providers/codex-binary-resolver.js.map +1 -0
  26. package/dist/server/server/agent/providers/codex-health-probe.d.ts +16 -0
  27. package/dist/server/server/agent/providers/codex-health-probe.d.ts.map +1 -0
  28. package/dist/server/server/agent/providers/codex-health-probe.js +161 -0
  29. package/dist/server/server/agent/providers/codex-health-probe.js.map +1 -0
  30. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +5 -1
  31. package/dist/server/server/agent/providers/diagnostic-utils.d.ts.map +1 -1
  32. package/dist/server/server/agent/providers/diagnostic-utils.js +105 -8
  33. package/dist/server/server/agent/providers/diagnostic-utils.js.map +1 -1
  34. package/dist/server/server/exports.d.ts +4 -1
  35. package/dist/server/server/exports.d.ts.map +1 -1
  36. package/dist/server/server/exports.js +7 -1
  37. package/dist/server/server/exports.js.map +1 -1
  38. package/dist/server/server/file-explorer/service.d.ts +8 -0
  39. package/dist/server/server/file-explorer/service.d.ts.map +1 -1
  40. package/dist/server/server/file-explorer/service.js +43 -0
  41. package/dist/server/server/file-explorer/service.js.map +1 -1
  42. package/dist/server/server/latency-tracker.d.ts +9 -0
  43. package/dist/server/server/latency-tracker.d.ts.map +1 -1
  44. package/dist/server/server/latency-tracker.js +111 -0
  45. package/dist/server/server/latency-tracker.js.map +1 -1
  46. package/dist/server/server/session.d.ts +1 -0
  47. package/dist/server/server/session.d.ts.map +1 -1
  48. package/dist/server/server/session.js +53 -2
  49. package/dist/server/server/session.js.map +1 -1
  50. package/dist/server/shared/messages.d.ts +964 -0
  51. package/dist/server/shared/messages.d.ts.map +1 -1
  52. package/dist/server/shared/messages.js +34 -0
  53. package/dist/server/shared/messages.js.map +1 -1
  54. package/dist/server/utils/electron-helper.d.ts +16 -0
  55. package/dist/server/utils/electron-helper.d.ts.map +1 -1
  56. package/dist/server/utils/electron-helper.js +34 -0
  57. package/dist/server/utils/electron-helper.js.map +1 -1
  58. package/dist/server/utils/executable.d.ts +3 -1
  59. package/dist/server/utils/executable.d.ts.map +1 -1
  60. package/dist/server/utils/executable.js +112 -2
  61. package/dist/server/utils/executable.js.map +1 -1
  62. package/package.json +3 -3
@@ -1,23 +1,22 @@
1
- import { execFile, execSync } from "node:child_process";
1
+ import { execSync } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
- import { existsSync, realpathSync } from "node:fs";
3
+ import { realpathSync } from "node:fs";
4
4
  import fs from "node:fs/promises";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  import readline from "node:readline";
8
- import { promisify } from "node:util";
9
8
  import { z } from "zod";
10
9
  import { loadCodexPersistedTimeline } from "./codex-rollout-timeline.js";
11
10
  import { mapCodexRolloutToolCall, mapCodexToolCallFromThreadItem, } from "./codex/tool-call-mapper.js";
12
11
  import { applyProviderEnv, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
13
12
  import { resolveElectronNodeRuntime } from "../../../utils/electron-helper.js";
14
13
  import { getLatencyProxyUrlSync } from "../../latency-proxy.js";
15
- import { findExecutable } from "../../../utils/executable.js";
14
+ import { selectCodexBinary, selectEffectiveCodexBinary, verifyCommandAvailable, } from "./codex-binary-resolver.js";
16
15
  import { getSeaworkModels } from "./seawork-models.js";
17
16
  import { spawnProcess } from "../../../utils/spawn.js";
18
17
  import { extractCodexTerminalSessionId, nonEmptyString } from "./tool-call-mapper-utils.js";
19
18
  import { buildCodexFeatures, codexModelSupportsFastMode } from "./codex-feature-definitions.js";
20
- import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
19
+ import { collectStdout, formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
21
20
  const DEFAULT_TIMEOUT_MS = 14 * 24 * 60 * 60 * 1000;
22
21
  const TURN_START_TIMEOUT_MS = 90 * 1000;
23
22
  // issue #259: window after turn/interrupt during which the next turn/start
@@ -39,7 +38,6 @@ const CODEX_APP_SERVER_CAPABILITIES = {
39
38
  supportsReasoningStream: true,
40
39
  supportsToolInvocations: true,
41
40
  };
42
- const execFileAsync = promisify(execFile);
43
41
  const CODEX_MODES = [
44
42
  {
45
43
  id: "auto",
@@ -209,15 +207,17 @@ function mergeCodexConfiguredDefaults(primary, fallback) {
209
207
  thinkingOptionId: primary.thinkingOptionId ?? fallback.thinkingOptionId,
210
208
  };
211
209
  }
212
- async function resolveCodexBinary() {
213
- const found = await findExecutable("codex");
214
- if (found) {
215
- return found;
216
- }
217
- throw new Error("Codex binary not found. Install the Codex CLI (https://github.com/openai/codex) and ensure it is available in your shell PATH.");
210
+ async function resolveCodexBinary(runtimeSettings, logger) {
211
+ // Pass the same env daemon would spawn with so default/append resolution
212
+ // honors `agents.providers.codex.env.PATH` — matches actual launch
213
+ // behavior. `command.replace` bypasses this (resolveProviderCommandPrefix
214
+ // takes argv[0] directly).
215
+ const spawnEnv = buildCodexAppServerEnv(runtimeSettings);
216
+ const selection = await selectCodexBinary({ logger, spawnEnv });
217
+ return selection.binary;
218
218
  }
219
- async function resolveCodexLaunchPrefix(runtimeSettings) {
220
- return resolveProviderCommandPrefix(runtimeSettings?.command, resolveCodexBinary);
219
+ async function resolveCodexLaunchPrefix(runtimeSettings, logger) {
220
+ return resolveProviderCommandPrefix(runtimeSettings?.command, () => resolveCodexBinary(runtimeSettings, logger));
221
221
  }
222
222
  function resolveCodexHomeDir() {
223
223
  return process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex");
@@ -3594,7 +3594,7 @@ export class CodexAppServerAgentClient {
3594
3594
  this.capabilities = CODEX_APP_SERVER_CAPABILITIES;
3595
3595
  }
3596
3596
  async spawnAppServer(options) {
3597
- const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
3597
+ const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings, this.logger);
3598
3598
  this.logger.trace({
3599
3599
  launchPrefix,
3600
3600
  }, "Spawning Codex app server");
@@ -3664,7 +3664,7 @@ export class CodexAppServerAgentClient {
3664
3664
  let binaryPath = null;
3665
3665
  let probeError = null;
3666
3666
  try {
3667
- const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
3667
+ const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings, this.logger);
3668
3668
  binaryPath = launchPrefix.command;
3669
3669
  let command = launchPrefix.command;
3670
3670
  let args = [...launchPrefix.args, "--version"];
@@ -3682,10 +3682,11 @@ export class CodexAppServerAgentClient {
3682
3682
  args = [resolvedCommand, ...args];
3683
3683
  }
3684
3684
  }
3685
- const { stdout } = await execFileAsync(command, args, {
3686
- encoding: "utf8",
3687
- timeout: 5000,
3688
- windowsHide: true,
3685
+ // Route via spawnProcess so Windows `.cmd`/`.bat` (e.g. corp shims
3686
+ // pointed at by `agents.providers.codex.command`) launch correctly
3687
+ // — execFileAsync can't spawn batch wrappers directly.
3688
+ const stdout = await collectStdout(command, args, {
3689
+ timeoutMs: 5000,
3689
3690
  env: {
3690
3691
  ...buildCodexAppServerEnv(this.runtimeSettings),
3691
3692
  ...(command === electronRuntime ? { ELECTRON_RUN_AS_NODE: "1" } : {}),
@@ -3701,9 +3702,13 @@ export class CodexAppServerAgentClient {
3701
3702
  probeError = err instanceof Error ? err.message : String(err);
3702
3703
  }
3703
3704
  try {
3704
- const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
3705
+ const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings, this.logger);
3705
3706
  binaryPath = binaryPath ?? launchPrefix.command;
3706
- const version = await resolveBinaryVersion(launchPrefix.command);
3707
+ // Pass through the full launch args AND the same env daemon would
3708
+ // spawn with, so wrapper overrides resolve via provider env.PATH
3709
+ // and the version probe stays consistent with the actual launch
3710
+ // path (the primary attempt above already does this).
3711
+ const version = await resolveBinaryVersion(launchPrefix.command, [...launchPrefix.args, "--version"], buildCodexAppServerEnv(this.runtimeSettings));
3707
3712
  return { version, binaryPath, probeError };
3708
3713
  }
3709
3714
  catch (err) {
@@ -4001,26 +4006,88 @@ export class CodexAppServerAgentClient {
4001
4006
  return getSeaworkModels("codex");
4002
4007
  }
4003
4008
  async isAvailable() {
4004
- const command = this.runtimeSettings?.command;
4005
- if (command?.mode === "replace") {
4006
- return existsSync(command.argv[0]);
4009
+ try {
4010
+ // Same selector daemon spawn uses, so UI availability matches actual
4011
+ // launch behavior. We always run `verifyCommandAvailable` against
4012
+ // the resolved binary — without that check `install-state-stale`
4013
+ // (recorded path that's now missing/broken) and unhealthy PATH
4014
+ // candidates would still report Available even though daemon spawn
4015
+ // would fail immediately. The bare-name semantics of
4016
+ // `verifyCommandAvailable` cover `command-override` cases like
4017
+ // `argv=["docker", ...]` while still rejecting paths that don't
4018
+ // exist or aren't executable.
4019
+ //
4020
+ // `installStateRejected` is set by the resolver when an unhealthy
4021
+ // recorded install OR an unhealthy PATH candidate was selected as
4022
+ // a last-resort. Trust the probe verdict and report unavailable
4023
+ // rather than letting `verifyCommandAvailable` (file-existence
4024
+ // only) accept a fake/stale shim that just happens to be
4025
+ // launchable. Diagnostic still surfaces the path + reason for
4026
+ // troubleshooting.
4027
+ const spawnEnv = buildCodexAppServerEnv(this.runtimeSettings);
4028
+ const selection = await selectEffectiveCodexBinary(this.runtimeSettings, { spawnEnv });
4029
+ if (selection.installStateRejected) {
4030
+ return false;
4031
+ }
4032
+ return await verifyCommandAvailable(selection.binary, { spawnEnv });
4033
+ }
4034
+ catch {
4035
+ return false;
4007
4036
  }
4008
- return (await findExecutable("codex")) !== null;
4009
4037
  }
4010
4038
  async getDiagnostic() {
4011
4039
  try {
4012
4040
  const available = await this.isAvailable();
4013
- const resolvedBinary = await findExecutable("codex");
4041
+ let resolvedBinary = null;
4042
+ let selectionSource = "unknown";
4043
+ let installStateRejected;
4044
+ try {
4045
+ const selection = await selectEffectiveCodexBinary(this.runtimeSettings, {
4046
+ spawnEnv: buildCodexAppServerEnv(this.runtimeSettings),
4047
+ });
4048
+ resolvedBinary = selection.binary;
4049
+ selectionSource = selection.source;
4050
+ installStateRejected = selection.installStateRejected;
4051
+ }
4052
+ catch {
4053
+ // Throws only when there's no override AND neither install-state
4054
+ // nor PATH has anything; leave resolvedBinary=null.
4055
+ }
4014
4056
  const entries = [
4015
4057
  {
4016
4058
  label: "Binary",
4017
4059
  value: resolvedBinary ?? "not found",
4018
4060
  },
4019
4061
  {
4020
- label: "Version",
4021
- value: resolvedBinary ? await resolveBinaryVersion(resolvedBinary) : "unknown",
4062
+ label: "Source",
4063
+ value: selectionSource,
4022
4064
  },
4023
4065
  ];
4066
+ if (installStateRejected) {
4067
+ entries.push({
4068
+ label: "Install-state rejected",
4069
+ value: installStateRejected,
4070
+ });
4071
+ }
4072
+ // Version probe must run the FULL daemon command (program + args),
4073
+ // not just the program. For a wrapper override like
4074
+ // `["docker","run","--rm","my-wrapper","codex"]` the version of
4075
+ // interest is codex's, not docker's. `resolveCodexLaunchPrefix` is
4076
+ // already the source of truth for what spawn uses, so reuse it.
4077
+ let versionValue = "unknown";
4078
+ if (resolvedBinary) {
4079
+ try {
4080
+ const { command, args } = await resolveCodexLaunchPrefix(this.runtimeSettings, this.logger);
4081
+ // Same env daemon would spawn with so `env.PATH` overrides
4082
+ // resolve `command` (e.g. "docker") the same way.
4083
+ versionValue = await resolveBinaryVersion(command, [...args, "--version"], buildCodexAppServerEnv(this.runtimeSettings));
4084
+ }
4085
+ catch {
4086
+ // Resolver shouldn't fail here if we got resolvedBinary above,
4087
+ // but stay defensive — keep "unknown".
4088
+ }
4089
+ }
4090
+ entries.push({ label: "Version", value: versionValue });
4024
4091
  let status = formatDiagnosticStatus(available);
4025
4092
  if (!available) {
4026
4093
  entries.push({ label: "Models", value: "Not checked" });