@defai.digital/automatosx 5.3.3 → 5.3.4

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/index.js CHANGED
@@ -802,8 +802,77 @@ var init_path_resolver = __esm({
802
802
  }
803
803
  });
804
804
 
805
- // src/providers/base-provider.ts
805
+ // src/core/cli-provider-detector.ts
806
806
  import { existsSync as existsSync5 } from "fs";
807
+ import { delimiter } from "path";
808
+ import { spawn, spawnSync } from "child_process";
809
+ function findOnPath(cmdBase) {
810
+ const isWindows = process.platform === "win32";
811
+ if (isWindows) {
812
+ return findOnPathWindows(cmdBase);
813
+ }
814
+ return findOnPathUnix(cmdBase);
815
+ }
816
+ function findOnPathWindows(cmdBase) {
817
+ try {
818
+ const where = spawnSync("where", [cmdBase], {
819
+ windowsHide: true,
820
+ timeout: 3e3
821
+ });
822
+ if (where.status === 0) {
823
+ const lines = where.stdout.toString().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
824
+ const firstPath = lines[0];
825
+ if (firstPath) {
826
+ logger.debug("Found via where.exe", { cmdBase, path: firstPath });
827
+ return { found: true, path: firstPath };
828
+ }
829
+ }
830
+ } catch (error) {
831
+ logger.debug("where.exe failed, falling back to PATH scan", { error });
832
+ }
833
+ const pathext = (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").toUpperCase().split(";").filter(Boolean);
834
+ const pathEntries = (process.env.PATH || "").split(delimiter).filter(Boolean);
835
+ for (const dir of pathEntries) {
836
+ for (const ext of pathext) {
837
+ const fullPath = `${dir}\\${cmdBase}${ext}`;
838
+ if (existsSync5(fullPath)) {
839
+ logger.debug("Found via PATH \xD7 PATHEXT", { cmdBase, path: fullPath });
840
+ return { found: true, path: fullPath };
841
+ }
842
+ }
843
+ const pathWithoutExt = `${dir}\\${cmdBase}`;
844
+ if (existsSync5(pathWithoutExt)) {
845
+ logger.debug("Found via PATH (no ext)", { cmdBase, path: pathWithoutExt });
846
+ return { found: true, path: pathWithoutExt };
847
+ }
848
+ }
849
+ return { found: false };
850
+ }
851
+ function findOnPathUnix(cmdBase) {
852
+ try {
853
+ const which = spawnSync("which", [cmdBase], { timeout: 3e3 });
854
+ if (which.status === 0) {
855
+ const path3 = which.stdout.toString().trim();
856
+ if (path3) {
857
+ logger.debug("Found via which", { cmdBase, path: path3 });
858
+ return { found: true, path: path3 };
859
+ }
860
+ }
861
+ } catch (error) {
862
+ logger.debug("which failed", { cmdBase, error });
863
+ }
864
+ return { found: false };
865
+ }
866
+ var init_cli_provider_detector = __esm({
867
+ "src/core/cli-provider-detector.ts"() {
868
+ "use strict";
869
+ init_esm_shims();
870
+ init_logger();
871
+ }
872
+ });
873
+
874
+ // src/providers/base-provider.ts
875
+ import { existsSync as existsSync6 } from "fs";
807
876
  var BaseProvider;
808
877
  var init_base_provider = __esm({
809
878
  "src/providers/base-provider.ts"() {
@@ -811,6 +880,7 @@ var init_base_provider = __esm({
811
880
  init_esm_shims();
812
881
  init_logger();
813
882
  init_cache();
883
+ init_cli_provider_detector();
814
884
  BaseProvider = class {
815
885
  config;
816
886
  health;
@@ -962,7 +1032,7 @@ var init_base_provider = __esm({
962
1032
  logger.warn("Home directory shortcut detected (~)", { path: path3 });
963
1033
  return false;
964
1034
  }
965
- return existsSync5(path3);
1035
+ return existsSync6(path3);
966
1036
  } catch (error) {
967
1037
  logger.debug(`Error checking path existence`, {
968
1038
  path: path3,
@@ -1022,8 +1092,8 @@ var init_base_provider = __esm({
1022
1092
  */
1023
1093
  async getProviderVersion(command) {
1024
1094
  try {
1025
- const { spawnSync } = await import("child_process");
1026
- const result = spawnSync(command, ["--version"], {
1095
+ const { spawnSync: spawnSync2 } = await import("child_process");
1096
+ const result = spawnSync2(command, ["--version"], {
1027
1097
  encoding: "utf8",
1028
1098
  timeout: 5e3,
1029
1099
  stdio: "pipe"
@@ -1041,41 +1111,20 @@ var init_base_provider = __esm({
1041
1111
  }
1042
1112
  /**
1043
1113
  * Check if the CLI command is available in the system (standard PATH detection)
1114
+ * Uses cross-platform detection from cli-provider-detector for Windows compatibility
1044
1115
  */
1045
1116
  async checkCLIAvailability() {
1046
1117
  try {
1047
- const { spawn } = await import("child_process");
1048
- return new Promise((resolve10) => {
1049
- const child = spawn(this.config.command, ["--version"], {
1050
- stdio: "ignore",
1051
- timeout: 5e3
1052
- });
1053
- let resolved = false;
1054
- child.on("close", (code) => {
1055
- if (!resolved) {
1056
- resolved = true;
1057
- resolve10(code === 0 || code === 1);
1058
- }
1059
- });
1060
- child.on("error", (error) => {
1061
- if (!resolved) {
1062
- resolved = true;
1063
- if (error.code === "ENOENT") {
1064
- logger.warn(`CLI command not found: ${this.config.command}`);
1065
- resolve10(false);
1066
- } else {
1067
- resolve10(true);
1068
- }
1069
- }
1070
- });
1071
- setTimeout(() => {
1072
- if (!resolved) {
1073
- resolved = true;
1074
- child.kill();
1075
- resolve10(false);
1076
- }
1077
- }, 5e3);
1118
+ const result = findOnPath(this.config.command);
1119
+ if (!result.found) {
1120
+ logger.warn(`CLI command not found: ${this.config.command}`);
1121
+ return false;
1122
+ }
1123
+ logger.debug(`Provider ${this.config.name} found on PATH`, {
1124
+ command: this.config.command,
1125
+ path: result.path
1078
1126
  });
1127
+ return true;
1079
1128
  } catch (error) {
1080
1129
  logger.error(`Error checking CLI availability: ${error.message}`);
1081
1130
  return false;
@@ -1419,7 +1468,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
1419
1468
  * Model selection is delegated to CLI's own defaults
1420
1469
  */
1421
1470
  async executeRealCLI(prompt, request) {
1422
- const { spawn } = await import("child_process");
1471
+ const { spawn: spawn2 } = await import("child_process");
1423
1472
  return new Promise((resolve10, reject) => {
1424
1473
  let stdout = "";
1425
1474
  let stderr = "";
@@ -1427,7 +1476,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
1427
1476
  const args = this.buildCLIArgs(request);
1428
1477
  let child;
1429
1478
  try {
1430
- child = spawn(this.config.command, args, {
1479
+ child = spawn2(this.config.command, args, {
1431
1480
  stdio: ["pipe", "pipe", "pipe"],
1432
1481
  // Use pipe for stdin
1433
1482
  env: process.env
@@ -1720,7 +1769,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
1720
1769
  * Model selection is delegated to CLI's own defaults
1721
1770
  */
1722
1771
  async executeRealCLI(prompt, request) {
1723
- const { spawn } = await import("child_process");
1772
+ const { spawn: spawn2 } = await import("child_process");
1724
1773
  return new Promise((resolve10, reject) => {
1725
1774
  let stdout = "";
1726
1775
  let stderr = "";
@@ -1728,7 +1777,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
1728
1777
  const args = [];
1729
1778
  args.push("--approval-mode", "auto_edit");
1730
1779
  args.push(prompt);
1731
- const child = spawn(this.config.command, args, {
1780
+ const child = spawn2(this.config.command, args, {
1732
1781
  stdio: ["pipe", "pipe", "pipe"],
1733
1782
  env: process.env
1734
1783
  });
@@ -1951,14 +2000,14 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
1951
2000
  * Model and other parameters are passed via -c (config override) or specific flags
1952
2001
  */
1953
2002
  async executeRealCLI(prompt, request) {
1954
- const { spawn } = await import("child_process");
2003
+ const { spawn: spawn2 } = await import("child_process");
1955
2004
  return new Promise((resolve10, reject) => {
1956
2005
  let stdout = "";
1957
2006
  let stderr = "";
1958
2007
  let hasTimedOut = false;
1959
2008
  const args = this.buildCLIArgs(request);
1960
2009
  args.push(prompt);
1961
- const child = spawn(this.config.command, args, {
2010
+ const child = spawn2(this.config.command, args, {
1962
2011
  stdio: ["pipe", "pipe", "pipe"],
1963
2012
  env: process.env
1964
2013
  });
@@ -2116,7 +2165,7 @@ This is a placeholder streaming response.`;
2116
2165
  * Execute real streaming CLI
2117
2166
  */
2118
2167
  async executeStreamingCLI(prompt, request, options) {
2119
- const { spawn } = await import("child_process");
2168
+ const { spawn: spawn2 } = await import("child_process");
2120
2169
  const startTime = Date.now();
2121
2170
  return new Promise((resolve10, reject) => {
2122
2171
  let fullOutput = "";
@@ -2126,7 +2175,7 @@ This is a placeholder streaming response.`;
2126
2175
  const args = this.buildCLIArgs(request);
2127
2176
  args.push("--stream");
2128
2177
  args.push(prompt);
2129
- const child = spawn(this.config.command, args, {
2178
+ const child = spawn2(this.config.command, args, {
2130
2179
  stdio: ["pipe", "pipe", "pipe"],
2131
2180
  env: process.env
2132
2181
  });
@@ -4417,9 +4466,9 @@ async function initializeGitRepository(projectDir) {
4417
4466
  logger.info("Git repository already exists, skipping initialization");
4418
4467
  return;
4419
4468
  }
4420
- const { spawn } = await import("child_process");
4469
+ const { spawn: spawn2 } = await import("child_process");
4421
4470
  await new Promise((resolve10, reject) => {
4422
- const child = spawn("git", ["init"], {
4471
+ const child = spawn2("git", ["init"], {
4423
4472
  cwd: projectDir,
4424
4473
  stdio: "pipe"
4425
4474
  });
@@ -4531,12 +4580,12 @@ var listCommand = {
4531
4580
  };
4532
4581
  async function listAgents(pathResolver) {
4533
4582
  const agentsDir = pathResolver.getAgentsDirectory();
4534
- const { existsSync: existsSync11 } = await import("fs");
4583
+ const { existsSync: existsSync12 } = await import("fs");
4535
4584
  const projectDir = await detectProjectRoot();
4536
4585
  const examplesDir = join3(projectDir, "examples", "agents");
4537
4586
  try {
4538
4587
  const agentFiles = [];
4539
- if (existsSync11(agentsDir)) {
4588
+ if (existsSync12(agentsDir)) {
4540
4589
  const files = await readdir2(agentsDir);
4541
4590
  for (const file of files) {
4542
4591
  if (file.endsWith(".yaml") || file.endsWith(".yml")) {
@@ -4548,7 +4597,7 @@ async function listAgents(pathResolver) {
4548
4597
  }
4549
4598
  }
4550
4599
  }
4551
- if (existsSync11(examplesDir)) {
4600
+ if (existsSync12(examplesDir)) {
4552
4601
  const files = await readdir2(examplesDir);
4553
4602
  for (const file of files) {
4554
4603
  if (file.endsWith(".yaml") || file.endsWith(".yml")) {
@@ -8490,6 +8539,377 @@ var DelegationParser = class {
8490
8539
  }
8491
8540
  };
8492
8541
 
8542
+ // src/core/timeout-manager.ts
8543
+ init_esm_shims();
8544
+
8545
+ // src/core/warning-emitter.ts
8546
+ init_esm_shims();
8547
+ init_logger();
8548
+ import { EventEmitter } from "events";
8549
+ var WarningEmitter = class extends EventEmitter {
8550
+ constructor() {
8551
+ super();
8552
+ this.setupDefaultHandler();
8553
+ }
8554
+ /**
8555
+ * Setup default warning handler
8556
+ *
8557
+ * Registers a default handler that logs timeout warnings to console.
8558
+ * This handler is always registered and cannot be removed.
8559
+ *
8560
+ * @private
8561
+ */
8562
+ setupDefaultHandler() {
8563
+ this.on("timeout-warning", (event) => {
8564
+ this.logWarning(event);
8565
+ });
8566
+ }
8567
+ /**
8568
+ * Log timeout warning
8569
+ *
8570
+ * Formats and logs a timeout warning message with relevant details.
8571
+ *
8572
+ * @param event - Timeout warning event data
8573
+ * @private
8574
+ */
8575
+ logWarning(event) {
8576
+ const elapsedSeconds = Math.floor(event.elapsedMs / 1e3);
8577
+ const remainingSeconds = Math.floor(event.remainingMs / 1e3);
8578
+ const totalSeconds = Math.floor(event.timeoutMs / 1e3);
8579
+ const message = [
8580
+ `\u26A0\uFE0F Timeout Warning: Agent "${event.agentName}" has been running for ${elapsedSeconds}s`,
8581
+ ` Task: ${this.truncateTask(event.taskDescription)}`,
8582
+ ` Remaining time: ${remainingSeconds}s (${this.formatTime(remainingSeconds)})`,
8583
+ ` Total timeout: ${totalSeconds}s (${this.formatTime(totalSeconds)})`
8584
+ ].join("\n");
8585
+ logger.warn(message);
8586
+ }
8587
+ /**
8588
+ * Truncate task description
8589
+ *
8590
+ * Truncates long task descriptions to keep warning messages concise.
8591
+ *
8592
+ * @param task - Task description
8593
+ * @param maxLength - Maximum length (default: 80)
8594
+ * @returns Truncated task description
8595
+ * @private
8596
+ */
8597
+ truncateTask(task, maxLength = 80) {
8598
+ if (task.length <= maxLength) {
8599
+ return task;
8600
+ }
8601
+ return task.substring(0, maxLength - 3) + "...";
8602
+ }
8603
+ /**
8604
+ * Format time in human-readable format
8605
+ *
8606
+ * Converts seconds to a human-readable format (e.g., "5m 30s", "1h 15m").
8607
+ *
8608
+ * @param seconds - Time in seconds
8609
+ * @returns Formatted time string
8610
+ * @private
8611
+ */
8612
+ formatTime(seconds) {
8613
+ if (seconds < 60) {
8614
+ return `${seconds}s`;
8615
+ }
8616
+ const minutes = Math.floor(seconds / 60);
8617
+ const remainingSeconds = seconds % 60;
8618
+ if (minutes < 60) {
8619
+ return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
8620
+ }
8621
+ const hours = Math.floor(minutes / 60);
8622
+ const remainingMinutes = minutes % 60;
8623
+ return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
8624
+ }
8625
+ /**
8626
+ * Emit timeout warning
8627
+ *
8628
+ * Convenience method to emit a timeout warning event.
8629
+ *
8630
+ * @param event - Timeout warning event data
8631
+ */
8632
+ emitWarning(event) {
8633
+ this.emit("timeout-warning", event);
8634
+ }
8635
+ };
8636
+
8637
+ // src/core/timeout-manager.ts
8638
+ init_logger();
8639
+ var DEFAULT_TIMEOUT = 15e5;
8640
+ var DEFAULT_WARNING_THRESHOLD = 0.8;
8641
+ var MIN_WARNING_THRESHOLD = 0.5;
8642
+ var MAX_WARNING_THRESHOLD = 0.95;
8643
+ var TimeoutManager = class {
8644
+ config;
8645
+ warningEmitter;
8646
+ /**
8647
+ * Create a timeout manager
8648
+ *
8649
+ * @param config - Timeout configuration
8650
+ */
8651
+ constructor(config) {
8652
+ this.config = this.validateConfig(config);
8653
+ this.warningEmitter = new WarningEmitter();
8654
+ }
8655
+ /**
8656
+ * Validate timeout configuration
8657
+ *
8658
+ * Ensures configuration values are valid and within acceptable ranges.
8659
+ *
8660
+ * @param config - Timeout configuration to validate
8661
+ * @returns Validated configuration
8662
+ * @throws Error if configuration is invalid
8663
+ * @private
8664
+ */
8665
+ validateConfig(config) {
8666
+ if (config.warningThreshold !== void 0) {
8667
+ if (config.warningThreshold < MIN_WARNING_THRESHOLD || config.warningThreshold > MAX_WARNING_THRESHOLD) {
8668
+ throw new Error(
8669
+ `Warning threshold must be between ${MIN_WARNING_THRESHOLD} and ${MAX_WARNING_THRESHOLD}`
8670
+ );
8671
+ }
8672
+ }
8673
+ if (config.global !== void 0 && config.global <= 0) {
8674
+ throw new Error("Global timeout must be positive");
8675
+ }
8676
+ if (config.teams) {
8677
+ for (const [team, timeout] of Object.entries(config.teams)) {
8678
+ if (timeout <= 0) {
8679
+ throw new Error(`Team timeout for '${team}' must be positive`);
8680
+ }
8681
+ }
8682
+ }
8683
+ if (config.agents) {
8684
+ for (const [agent, timeout] of Object.entries(config.agents)) {
8685
+ if (timeout <= 0) {
8686
+ throw new Error(`Agent timeout for '${agent}' must be positive`);
8687
+ }
8688
+ }
8689
+ }
8690
+ return config;
8691
+ }
8692
+ /**
8693
+ * Resolve final timeout value
8694
+ *
8695
+ * Resolves the final timeout value based on the priority chain:
8696
+ * 1. Runtime override (CLI flag)
8697
+ * 2. Agent-level config (agent YAML)
8698
+ * 3. Team-level config (team config)
8699
+ * 4. Global config (config file)
8700
+ * 5. Default value (hardcoded)
8701
+ *
8702
+ * @param context - Timeout resolution context
8703
+ * @returns Resolved timeout configuration
8704
+ *
8705
+ * @example
8706
+ * ```typescript
8707
+ * const resolved = manager.resolve({
8708
+ * agentName: 'backend',
8709
+ * teamName: 'engineering',
8710
+ * runtimeTimeout: 1800000
8711
+ * });
8712
+ * ```
8713
+ */
8714
+ resolve(context) {
8715
+ if (context.runtimeTimeout !== void 0) {
8716
+ logger.debug("Timeout resolved from runtime override", {
8717
+ value: context.runtimeTimeout,
8718
+ source: "runtime"
8719
+ });
8720
+ return this.buildResolved(context.runtimeTimeout, "runtime");
8721
+ }
8722
+ const agentTimeout = this.config.agents?.[context.agentName];
8723
+ if (agentTimeout !== void 0) {
8724
+ logger.debug("Timeout resolved from agent config", {
8725
+ agent: context.agentName,
8726
+ value: agentTimeout,
8727
+ source: "agent"
8728
+ });
8729
+ return this.buildResolved(agentTimeout, "agent");
8730
+ }
8731
+ const teamTimeout = this.config.teams?.[context.teamName];
8732
+ if (teamTimeout !== void 0) {
8733
+ logger.debug("Timeout resolved from team config", {
8734
+ team: context.teamName,
8735
+ value: teamTimeout,
8736
+ source: "team"
8737
+ });
8738
+ return this.buildResolved(teamTimeout, "team");
8739
+ }
8740
+ if (this.config.global !== void 0) {
8741
+ logger.debug("Timeout resolved from global config", {
8742
+ value: this.config.global,
8743
+ source: "global"
8744
+ });
8745
+ return this.buildResolved(this.config.global, "global");
8746
+ }
8747
+ logger.debug("Timeout resolved from default", {
8748
+ value: DEFAULT_TIMEOUT,
8749
+ source: "default"
8750
+ });
8751
+ return this.buildResolved(DEFAULT_TIMEOUT, "default");
8752
+ }
8753
+ /**
8754
+ * Build resolved timeout configuration
8755
+ *
8756
+ * Constructs a resolved timeout configuration object with warning threshold.
8757
+ *
8758
+ * @param value - Timeout value in milliseconds
8759
+ * @param source - Configuration source
8760
+ * @returns Resolved timeout configuration
8761
+ * @private
8762
+ */
8763
+ buildResolved(value, source) {
8764
+ const threshold = this.config.warningThreshold ?? DEFAULT_WARNING_THRESHOLD;
8765
+ return {
8766
+ value,
8767
+ source,
8768
+ warningAt: Math.floor(value * threshold),
8769
+ warningsEnabled: true
8770
+ };
8771
+ }
8772
+ /**
8773
+ * Start timeout monitoring
8774
+ *
8775
+ * Starts monitoring an execution with the resolved timeout configuration.
8776
+ * Emits a warning event when the threshold is reached.
8777
+ *
8778
+ * @param resolved - Resolved timeout configuration
8779
+ * @param context - Execution context
8780
+ * @returns Timeout monitor handle
8781
+ *
8782
+ * @example
8783
+ * ```typescript
8784
+ * const monitor = manager.startMonitoring(resolved, {
8785
+ * agentName: 'backend',
8786
+ * taskDescription: 'Implement feature X'
8787
+ * });
8788
+ *
8789
+ * // Later, stop monitoring
8790
+ * monitor.stop();
8791
+ * ```
8792
+ */
8793
+ startMonitoring(resolved, context) {
8794
+ const startTime = Date.now();
8795
+ let warningTimer;
8796
+ if (resolved.warningsEnabled) {
8797
+ warningTimer = setTimeout(() => {
8798
+ const event = {
8799
+ agentName: context.agentName,
8800
+ taskDescription: context.taskDescription,
8801
+ elapsedMs: resolved.warningAt,
8802
+ remainingMs: resolved.value - resolved.warningAt,
8803
+ timeoutMs: resolved.value
8804
+ };
8805
+ this.warningEmitter.emitWarning(event);
8806
+ }, resolved.warningAt);
8807
+ }
8808
+ return {
8809
+ resolved,
8810
+ warningTimer,
8811
+ startTime,
8812
+ stop: () => {
8813
+ if (warningTimer) {
8814
+ clearTimeout(warningTimer);
8815
+ }
8816
+ }
8817
+ };
8818
+ }
8819
+ /**
8820
+ * Get warning emitter
8821
+ *
8822
+ * Returns the warning emitter instance for custom event handling.
8823
+ *
8824
+ * @returns Warning emitter instance
8825
+ */
8826
+ getWarningEmitter() {
8827
+ return this.warningEmitter;
8828
+ }
8829
+ /**
8830
+ * Get configuration
8831
+ *
8832
+ * Returns the current timeout configuration.
8833
+ *
8834
+ * @returns Timeout configuration
8835
+ */
8836
+ getConfig() {
8837
+ return { ...this.config };
8838
+ }
8839
+ };
8840
+
8841
+ // src/utils/timeout-validator.ts
8842
+ init_esm_shims();
8843
+ var MIN_WARNING_THRESHOLD2 = 0.5;
8844
+ var MAX_WARNING_THRESHOLD2 = 0.95;
8845
+ function validateTimeoutConfig(config) {
8846
+ if (config.warningThreshold !== void 0) {
8847
+ if (config.warningThreshold < MIN_WARNING_THRESHOLD2 || config.warningThreshold > MAX_WARNING_THRESHOLD2) {
8848
+ throw new ConfigError(
8849
+ `Timeout warning threshold must be between ${MIN_WARNING_THRESHOLD2} and ${MAX_WARNING_THRESHOLD2}`,
8850
+ "E1003" /* CONFIG_VALIDATION_ERROR */,
8851
+ [],
8852
+ { warningThreshold: config.warningThreshold }
8853
+ );
8854
+ }
8855
+ }
8856
+ if (config.global !== void 0) {
8857
+ if (!isPositiveInteger2(config.global)) {
8858
+ throw new ConfigError(
8859
+ "Global timeout must be a positive integer",
8860
+ "E1003" /* CONFIG_VALIDATION_ERROR */,
8861
+ [],
8862
+ { global: config.global }
8863
+ );
8864
+ }
8865
+ }
8866
+ if (config.teams) {
8867
+ for (const [team, timeout] of Object.entries(config.teams)) {
8868
+ if (!isPositiveInteger2(timeout)) {
8869
+ throw new ConfigError(
8870
+ `Team timeout for '${team}' must be a positive integer`,
8871
+ "E1003" /* CONFIG_VALIDATION_ERROR */,
8872
+ [],
8873
+ { team, timeout }
8874
+ );
8875
+ }
8876
+ }
8877
+ }
8878
+ if (config.agents) {
8879
+ for (const [agent, timeout] of Object.entries(config.agents)) {
8880
+ if (!isPositiveInteger2(timeout)) {
8881
+ throw new ConfigError(
8882
+ `Agent timeout for '${agent}' must be a positive integer`,
8883
+ "E1003" /* CONFIG_VALIDATION_ERROR */,
8884
+ [],
8885
+ { agent, timeout }
8886
+ );
8887
+ }
8888
+ }
8889
+ }
8890
+ }
8891
+ function isPositiveInteger2(value) {
8892
+ return Number.isInteger(value) && value > 0;
8893
+ }
8894
+ function buildTimeoutConfig(executionConfig) {
8895
+ if (executionConfig.timeouts) {
8896
+ return executionConfig.timeouts;
8897
+ }
8898
+ if (executionConfig.defaultTimeout !== void 0) {
8899
+ return {
8900
+ global: executionConfig.defaultTimeout
8901
+ };
8902
+ }
8903
+ return {};
8904
+ }
8905
+ function validateAndBuildTimeoutConfig(executionConfig) {
8906
+ const config = buildTimeoutConfig(executionConfig);
8907
+ if (Object.keys(config).length > 0) {
8908
+ validateTimeoutConfig(config);
8909
+ }
8910
+ return config;
8911
+ }
8912
+
8493
8913
  // src/agents/executor.ts
8494
8914
  init_logger();
8495
8915
  import { randomUUID as randomUUID2 } from "crypto";
@@ -8505,6 +8925,14 @@ var AgentExecutor = class {
8505
8925
  * Default retry configuration (v5.0: from config instead of hardcoded)
8506
8926
  */
8507
8927
  defaultRetryConfig;
8928
+ /**
8929
+ * Timeout manager for layered timeout configuration (v5.4.0+)
8930
+ */
8931
+ timeoutManager;
8932
+ /**
8933
+ * Configuration (v5.4.0+)
8934
+ */
8935
+ config;
8508
8936
  /**
8509
8937
  * Create AgentExecutor with optional delegation support
8510
8938
  *
@@ -8516,6 +8944,7 @@ var AgentExecutor = class {
8516
8944
  this.contextManager = config?.contextManager;
8517
8945
  this.profileLoader = config?.profileLoader;
8518
8946
  this.delegationParser = new DelegationParser(config?.profileLoader);
8947
+ this.config = config?.config;
8519
8948
  this.defaultRetryConfig = config?.defaultRetryConfig ?? {
8520
8949
  maxAttempts: 3,
8521
8950
  initialDelay: 1e3,
@@ -8530,11 +8959,48 @@ var AgentExecutor = class {
8530
8959
  "timeout"
8531
8960
  ]
8532
8961
  };
8962
+ if (this.config?.execution) {
8963
+ try {
8964
+ const timeoutConfig = validateAndBuildTimeoutConfig(this.config.execution);
8965
+ if (Object.keys(timeoutConfig).length > 0) {
8966
+ this.timeoutManager = new TimeoutManager(timeoutConfig);
8967
+ logger.debug("TimeoutManager initialized", { timeoutConfig });
8968
+ }
8969
+ } catch (error) {
8970
+ logger.warn("Failed to initialize TimeoutManager", {
8971
+ error: error.message
8972
+ });
8973
+ }
8974
+ }
8533
8975
  }
8534
8976
  /**
8535
8977
  * Execute an agent with the given context
8536
8978
  */
8537
8979
  async execute(context, options = {}) {
8980
+ if (!options.timeout && this.timeoutManager) {
8981
+ try {
8982
+ const resolved = this.timeoutManager.resolve({
8983
+ agentName: context.agent.name,
8984
+ teamName: context.agent.team || "unknown",
8985
+ runtimeTimeout: options.timeout
8986
+ });
8987
+ options = { ...options, timeout: resolved.value };
8988
+ logger.debug("Timeout resolved", {
8989
+ agent: context.agent.name,
8990
+ team: context.agent.team,
8991
+ timeout: resolved.value,
8992
+ source: resolved.source
8993
+ });
8994
+ this.timeoutManager.startMonitoring(resolved, {
8995
+ agentName: context.agent.name,
8996
+ taskDescription: context.task
8997
+ });
8998
+ } catch (error) {
8999
+ logger.warn("Failed to resolve timeout", {
9000
+ error: error.message
9001
+ });
9002
+ }
9003
+ }
8538
9004
  if (options.retry && options.timeout) {
8539
9005
  return this.executeWithTimeout(context, {
8540
9006
  ...options,
@@ -9026,7 +9492,9 @@ ${context.task}`;
9026
9492
  "cycle"
9027
9493
  );
9028
9494
  }
9029
- const maxDepth = fromAgentProfile.orchestration?.maxDelegationDepth ?? 2;
9495
+ const initiatorName = delegationChain.length > 0 ? delegationChain[0] ?? request.fromAgent : request.fromAgent;
9496
+ const initiatorProfile = await this.profileLoader.loadProfile(initiatorName);
9497
+ const maxDepth = initiatorProfile.orchestration?.maxDelegationDepth ?? 2;
9030
9498
  if (delegationChain.length >= maxDepth) {
9031
9499
  throw new DelegationError(
9032
9500
  `Max delegation depth (${maxDepth}) exceeded. Chain: ${delegationChain.join(" -> ")} (length ${delegationChain.length})`,
@@ -15162,7 +15630,7 @@ init_gemini_provider();
15162
15630
  init_openai_provider();
15163
15631
  init_logger();
15164
15632
  import chalk16 from "chalk";
15165
- import { existsSync as existsSync6 } from "fs";
15633
+ import { existsSync as existsSync7 } from "fs";
15166
15634
  import { readdir as readdir6, stat as stat2 } from "fs/promises";
15167
15635
  import { join as join12 } from "path";
15168
15636
  import { createRequire as createRequire3 } from "module";
@@ -15280,25 +15748,25 @@ var statusCommand2 = {
15280
15748
  project: projectInfo,
15281
15749
  configuration: {
15282
15750
  configFile: join12(detectedProjectDir, "automatosx.config.json"),
15283
- configExists: existsSync6(join12(detectedProjectDir, "automatosx.config.json")),
15751
+ configExists: existsSync7(join12(detectedProjectDir, "automatosx.config.json")),
15284
15752
  logLevel: config.logging.level,
15285
15753
  memoryMaxEntries: config.memory.maxEntries,
15286
15754
  memoryRetentionDays: config.memory.cleanupDays
15287
15755
  },
15288
15756
  directories: {
15289
- automatosx: { path: automatosxDir, exists: existsSync6(automatosxDir) },
15290
- agents: { path: agentsDir, exists: existsSync6(agentsDir), count: agentCount },
15291
- abilities: { path: abilitiesDir, exists: existsSync6(abilitiesDir), count: abilityCount },
15292
- memory: { path: memoryDir, exists: existsSync6(memoryDir), ...memoryStats },
15757
+ automatosx: { path: automatosxDir, exists: existsSync7(automatosxDir) },
15758
+ agents: { path: agentsDir, exists: existsSync7(agentsDir), count: agentCount },
15759
+ abilities: { path: abilitiesDir, exists: existsSync7(abilitiesDir), count: abilityCount },
15760
+ memory: { path: memoryDir, exists: existsSync7(memoryDir), ...memoryStats },
15293
15761
  prd: {
15294
15762
  path: prdDir,
15295
- exists: existsSync6(prdDir),
15763
+ exists: existsSync7(prdDir),
15296
15764
  files: workspaceStats.prdFiles,
15297
15765
  sizeBytes: workspaceStats.prdSizeBytes
15298
15766
  },
15299
15767
  tmp: {
15300
15768
  path: tmpDir,
15301
- exists: existsSync6(tmpDir),
15769
+ exists: existsSync7(tmpDir),
15302
15770
  files: workspaceStats.tmpFiles,
15303
15771
  sizeBytes: workspaceStats.tmpSizeBytes
15304
15772
  }
@@ -15396,7 +15864,7 @@ var statusCommand2 = {
15396
15864
  const value = process.env[name];
15397
15865
  if (value) {
15398
15866
  hasAnyEnvVar = true;
15399
- const exists = existsSync6(value);
15867
+ const exists = existsSync7(value);
15400
15868
  const icon = exists ? chalk16.green("\u2713") : chalk16.yellow("\u26A0");
15401
15869
  const statusMsg = exists ? chalk16.green("valid") : chalk16.yellow("path not found");
15402
15870
  console.log(` ${icon} ${name}: ${statusMsg}`);
@@ -15451,7 +15919,7 @@ var statusCommand2 = {
15451
15919
  }
15452
15920
  };
15453
15921
  async function getMemoryStatistics(memoryDir) {
15454
- if (!existsSync6(memoryDir)) {
15922
+ if (!existsSync7(memoryDir)) {
15455
15923
  return { files: 0, sizeBytes: 0 };
15456
15924
  }
15457
15925
  try {
@@ -15487,7 +15955,7 @@ async function getDirectoryStats(dirPath) {
15487
15955
  return { size: totalSize, files: totalFiles };
15488
15956
  }
15489
15957
  async function countFiles(dirPath, extensions) {
15490
- if (!existsSync6(dirPath)) {
15958
+ if (!existsSync7(dirPath)) {
15491
15959
  return 0;
15492
15960
  }
15493
15961
  try {
@@ -15500,7 +15968,7 @@ async function countFiles(dirPath, extensions) {
15500
15968
  }
15501
15969
  async function getProjectInfo(projectDir) {
15502
15970
  const packageJsonPath = join12(projectDir, "package.json");
15503
- if (!existsSync6(packageJsonPath)) {
15971
+ if (!existsSync7(packageJsonPath)) {
15504
15972
  return {};
15505
15973
  }
15506
15974
  try {
@@ -15823,7 +16291,7 @@ init_esm_shims();
15823
16291
  init_esm_shims();
15824
16292
  import { readdir as readdir7 } from "fs/promises";
15825
16293
  import { join as join13 } from "path";
15826
- import { existsSync as existsSync7 } from "fs";
16294
+ import { existsSync as existsSync8 } from "fs";
15827
16295
  import chalk19 from "chalk";
15828
16296
  var TEMPLATE_DESCRIPTIONS = {
15829
16297
  "basic-agent": {
@@ -15859,9 +16327,9 @@ var templatesCommand = {
15859
16327
  try {
15860
16328
  console.log(chalk19.blue.bold("\n\u{1F4CB} Available Agent Templates\n"));
15861
16329
  const projectTemplatesDir = join13(process.cwd(), ".automatosx", "templates");
15862
- const hasProjectTemplates = existsSync7(projectTemplatesDir);
16330
+ const hasProjectTemplates = existsSync8(projectTemplatesDir);
15863
16331
  const defaultTemplatesDir = join13(__dirname, "../examples/templates");
15864
- const hasDefaultTemplates = existsSync7(defaultTemplatesDir);
16332
+ const hasDefaultTemplates = existsSync8(defaultTemplatesDir);
15865
16333
  if (!hasProjectTemplates && !hasDefaultTemplates) {
15866
16334
  console.log(chalk19.yellow("\u26A0 No templates found."));
15867
16335
  console.log(chalk19.gray('\nRun "ax init" to set up default templates.\n'));
@@ -15919,7 +16387,7 @@ var templatesCommand = {
15919
16387
  // src/cli/commands/agent/create.ts
15920
16388
  init_esm_shims();
15921
16389
  import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
15922
- import { existsSync as existsSync9 } from "fs";
16390
+ import { existsSync as existsSync10 } from "fs";
15923
16391
  import { join as join15 } from "path";
15924
16392
  import { load as loadYaml2 } from "js-yaml";
15925
16393
  import chalk20 from "chalk";
@@ -16060,7 +16528,7 @@ var templateEngine = new TemplateEngine();
16060
16528
  // src/cli/commands/agent/helpers.ts
16061
16529
  init_esm_shims();
16062
16530
  import { readdir as readdir8 } from "fs/promises";
16063
- import { existsSync as existsSync8 } from "fs";
16531
+ import { existsSync as existsSync9 } from "fs";
16064
16532
  import { join as join14, extname as extname5, dirname as dirname9 } from "path";
16065
16533
  import { fileURLToPath as fileURLToPath5 } from "url";
16066
16534
  init_logger();
@@ -16069,7 +16537,7 @@ var __dirname5 = dirname9(__filename5);
16069
16537
  async function listAvailableTemplates() {
16070
16538
  const templates = [];
16071
16539
  const projectTemplatesDir = join14(process.cwd(), ".automatosx", "templates");
16072
- if (existsSync8(projectTemplatesDir)) {
16540
+ if (existsSync9(projectTemplatesDir)) {
16073
16541
  try {
16074
16542
  const files = await readdir8(projectTemplatesDir);
16075
16543
  for (const file of files) {
@@ -16087,7 +16555,7 @@ async function listAvailableTemplates() {
16087
16555
  }
16088
16556
  }
16089
16557
  const builtinTemplatesDir = join14(__dirname5, "../../../../examples/templates");
16090
- if (existsSync8(builtinTemplatesDir)) {
16558
+ if (existsSync9(builtinTemplatesDir)) {
16091
16559
  try {
16092
16560
  const files = await readdir8(builtinTemplatesDir);
16093
16561
  for (const file of files) {
@@ -16282,7 +16750,7 @@ var createCommand2 = {
16282
16750
  console.log(chalk20.gray(" \u2022 Not contain consecutive hyphens\n"));
16283
16751
  process.exit(1);
16284
16752
  }
16285
- if (existsSync9(agentFile)) {
16753
+ if (existsSync10(agentFile)) {
16286
16754
  console.log(chalk20.red.bold(`
16287
16755
  \u2717 Agent already exists: ${argv2.agent}
16288
16756
  `));
@@ -16368,11 +16836,11 @@ var createCommand2 = {
16368
16836
  };
16369
16837
  async function findTemplate(name) {
16370
16838
  const projectTemplate = join15(process.cwd(), ".automatosx", "templates", `${name}.yaml`);
16371
- if (existsSync9(projectTemplate)) {
16839
+ if (existsSync10(projectTemplate)) {
16372
16840
  return projectTemplate;
16373
16841
  }
16374
16842
  const defaultTemplate = join15(__dirname, "../examples/templates", `${name}.yaml`);
16375
- if (existsSync9(defaultTemplate)) {
16843
+ if (existsSync10(defaultTemplate)) {
16376
16844
  return defaultTemplate;
16377
16845
  }
16378
16846
  throw new Error(`Template not found: ${name}
@@ -16627,7 +17095,7 @@ var showCommand = {
16627
17095
  // src/cli/commands/agent/remove.ts
16628
17096
  init_esm_shims();
16629
17097
  import { unlink as unlink2 } from "fs/promises";
16630
- import { existsSync as existsSync10 } from "fs";
17098
+ import { existsSync as existsSync11 } from "fs";
16631
17099
  import { join as join18 } from "path";
16632
17100
  import chalk23 from "chalk";
16633
17101
  import * as readline3 from "readline";
@@ -16680,7 +17148,7 @@ var removeCommand = {
16680
17148
  process.exit(1);
16681
17149
  }
16682
17150
  const agentFile = join18(agentsDir, `${resolvedName}.yaml`);
16683
- if (!existsSync10(agentFile)) {
17151
+ if (!existsSync11(agentFile)) {
16684
17152
  console.log(chalk23.red.bold(`
16685
17153
  \u2717 Agent file not found: ${resolvedName}
16686
17154
  `));