@defai.digital/automatosx 11.2.8 → 11.3.0

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/mcp/index.js CHANGED
@@ -7,13 +7,13 @@ import { existsSync, readFileSync, promises, mkdirSync, createWriteStream, write
7
7
  import Database2 from 'better-sqlite3';
8
8
  import { glob } from 'glob';
9
9
  import { spawn, spawnSync } from 'child_process';
10
- import { z } from 'zod';
10
+ import { z, ZodError } from 'zod';
11
11
  import chalk4 from 'chalk';
12
12
  import ora2 from 'ora';
13
13
  import readline, { createInterface } from 'readline';
14
+ import { Mutex } from 'async-mutex';
14
15
  import Ajv from 'ajv';
15
16
  import addFormats from 'ajv-formats';
16
- import { Mutex } from 'async-mutex';
17
17
  import os2, { cpus } from 'os';
18
18
  import { load } from 'js-yaml';
19
19
  import { EventEmitter } from 'events';
@@ -2277,6 +2277,15 @@ var init_base_provider = __esm({
2277
2277
  "test-provider"
2278
2278
  // For unit tests
2279
2279
  ];
2280
+ /** Environment variables to force non-interactive CLI mode */
2281
+ static NON_INTERACTIVE_ENV = {
2282
+ TERM: "dumb",
2283
+ NO_COLOR: "1",
2284
+ FORCE_COLOR: "0",
2285
+ CI: "true",
2286
+ NO_UPDATE_NOTIFIER: "1",
2287
+ DEBIAN_FRONTEND: "noninteractive"
2288
+ };
2280
2289
  config;
2281
2290
  logger = logger;
2282
2291
  health;
@@ -2369,19 +2378,7 @@ var init_base_provider = __esm({
2369
2378
  shell: true,
2370
2379
  // Auto-detects: cmd.exe on Windows, /bin/sh on Unix
2371
2380
  timeout: this.config.timeout || 12e4,
2372
- env: {
2373
- ...process.env,
2374
- // Force non-interactive mode for CLIs
2375
- TERM: "dumb",
2376
- NO_COLOR: "1",
2377
- // Disable TTY checks for codex and other CLIs
2378
- FORCE_COLOR: "0",
2379
- CI: "true",
2380
- // Many CLIs disable TTY checks in CI mode
2381
- NO_UPDATE_NOTIFIER: "1",
2382
- // Disable interactive prompts
2383
- DEBIAN_FRONTEND: "noninteractive"
2384
- }
2381
+ env: { ...process.env, ..._BaseProvider.NON_INTERACTIVE_ENV }
2385
2382
  });
2386
2383
  let stdout = "";
2387
2384
  let stderr = "";
@@ -2531,22 +2528,14 @@ var init_base_provider = __esm({
2531
2528
  });
2532
2529
  const child = spawn(cliCommand, commandArgs, {
2533
2530
  timeout: this.config.timeout || 12e4,
2534
- env: {
2535
- ...process.env,
2536
- // Force non-interactive mode for CLIs
2537
- TERM: "dumb",
2538
- NO_COLOR: "1",
2539
- FORCE_COLOR: "0",
2540
- CI: "true",
2541
- NO_UPDATE_NOTIFIER: "1",
2542
- DEBIAN_FRONTEND: "noninteractive"
2543
- }
2531
+ env: { ...process.env, ..._BaseProvider.NON_INTERACTIVE_ENV }
2544
2532
  });
2545
2533
  let stdout = "";
2546
2534
  let stderr = "";
2547
2535
  let timeoutId = null;
2548
2536
  let forceKillTimer = null;
2549
2537
  let readlineInterface = null;
2538
+ let stderrInterface = null;
2550
2539
  const streamingEnabled = process.env.AUTOMATOSX_SHOW_PROVIDER_OUTPUT === "true";
2551
2540
  const debugMode = process.env.AUTOMATOSX_DEBUG === "true";
2552
2541
  const verbosity = VerbosityManager.getInstance();
@@ -2591,7 +2580,7 @@ var init_base_provider = __esm({
2591
2580
  });
2592
2581
  }
2593
2582
  if (child.stderr) {
2594
- const stderrInterface = readline.createInterface({
2583
+ stderrInterface = readline.createInterface({
2595
2584
  input: child.stderr,
2596
2585
  crlfDelay: Infinity
2597
2586
  });
@@ -2607,6 +2596,13 @@ var init_base_provider = __esm({
2607
2596
  }
2608
2597
  }
2609
2598
  });
2599
+ stderrInterface.on("error", (error) => {
2600
+ if (error.message !== "Readable stream already read") {
2601
+ logger.debug("Stderr readline error (non-fatal)", {
2602
+ error: error.message
2603
+ });
2604
+ }
2605
+ });
2610
2606
  }
2611
2607
  const cleanup = () => {
2612
2608
  if (timeoutId) {
@@ -2625,22 +2621,35 @@ var init_base_provider = __esm({
2625
2621
  readlineInterface = null;
2626
2622
  }
2627
2623
  }
2624
+ if (stderrInterface) {
2625
+ try {
2626
+ stderrInterface.close();
2627
+ } catch (error) {
2628
+ } finally {
2629
+ stderrInterface = null;
2630
+ }
2631
+ }
2628
2632
  };
2629
2633
  child.on("close", (code, signal) => {
2630
2634
  cleanup();
2631
2635
  if (stderr) {
2632
2636
  logger.debug(`${cliCommand} CLI stderr output`, { stderr: stderr.trim() });
2633
2637
  }
2634
- if (code === 0) {
2638
+ if ((code === 0 || code === null) && !signal) {
2635
2639
  if (progressParser) {
2636
2640
  progressParser.succeed(`${cliCommand} completed successfully`);
2637
2641
  }
2638
2642
  resolve5({ stdout, stderr });
2643
+ } else if (signal) {
2644
+ if (progressParser) {
2645
+ progressParser.fail(`${cliCommand} killed by signal ${signal}`);
2646
+ }
2647
+ reject(new Error(`${cliCommand} CLI killed by signal ${signal}. stderr: ${stderr || "none"}`));
2639
2648
  } else {
2640
2649
  if (progressParser) {
2641
2650
  progressParser.fail(`${cliCommand} failed with code ${code}`);
2642
2651
  }
2643
- reject(new Error(`${cliCommand} CLI exited with code ${code}${signal ? ` (signal: ${signal})` : ""}. stderr: ${stderr || "none"}`));
2652
+ reject(new Error(`${cliCommand} CLI exited with code ${code}. stderr: ${stderr || "none"}`));
2644
2653
  }
2645
2654
  });
2646
2655
  child.on("error", (error) => {
@@ -2676,8 +2685,18 @@ var init_base_provider = __esm({
2676
2685
  /**
2677
2686
  * Check if CLI is available - Template method pattern
2678
2687
  * Uses getCLICommand() to determine which CLI to check
2688
+ *
2689
+ * v11.2.9 Fix: Always return true in mock mode (AX_MOCK_PROVIDERS=true)
2690
+ * This allows integration tests in CI to run without installing actual provider CLIs
2679
2691
  */
2680
2692
  async checkCLIAvailable() {
2693
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
2694
+ logger.debug(`${this.getCLICommand()} CLI availability check (mock mode)`, {
2695
+ available: true,
2696
+ mockMode: true
2697
+ });
2698
+ return true;
2699
+ }
2681
2700
  try {
2682
2701
  const cliCommand = this.getCLICommand();
2683
2702
  const result = findOnPath(cliCommand);
@@ -3596,8 +3615,6 @@ var init_cli_wrapper = __esm({
3596
3615
  };
3597
3616
  }
3598
3617
  });
3599
-
3600
- // src/integrations/openai-codex/sdk-adapter.ts
3601
3618
  var CodexSdkAdapter;
3602
3619
  var init_sdk_adapter = __esm({
3603
3620
  "src/integrations/openai-codex/sdk-adapter.ts"() {
@@ -3610,6 +3627,8 @@ var init_sdk_adapter = __esm({
3610
3627
  sdkModule = null;
3611
3628
  options;
3612
3629
  initialized = false;
3630
+ initMutex = new Mutex();
3631
+ // v11.2.8: Prevent race condition in ensureInitialized
3613
3632
  constructor(options = {}) {
3614
3633
  this.options = {
3615
3634
  streamingEnabled: true,
@@ -3704,18 +3723,20 @@ var init_sdk_adapter = __esm({
3704
3723
  return this.activeThread;
3705
3724
  }
3706
3725
  async ensureInitialized() {
3707
- if (this.initialized) return;
3708
- try {
3709
- this.sdkModule = await import('@openai/codex-sdk');
3710
- this.codex = new this.sdkModule.Codex();
3711
- this.initialized = true;
3712
- logger.info("Codex SDK initialized");
3713
- } catch (error) {
3714
- throw new CodexError(
3715
- "CLI_NOT_FOUND" /* CLI_NOT_FOUND */,
3716
- "Codex SDK not available. Install with: npm install @openai/codex-sdk"
3717
- );
3718
- }
3726
+ return this.initMutex.runExclusive(async () => {
3727
+ if (this.initialized) return;
3728
+ try {
3729
+ this.sdkModule = await import('@openai/codex-sdk');
3730
+ this.codex = new this.sdkModule.Codex();
3731
+ this.initialized = true;
3732
+ logger.info("Codex SDK initialized");
3733
+ } catch (error) {
3734
+ throw new CodexError(
3735
+ "CLI_NOT_FOUND" /* CLI_NOT_FOUND */,
3736
+ "Codex SDK not available. Install with: npm install @openai/codex-sdk"
3737
+ );
3738
+ }
3739
+ });
3719
3740
  }
3720
3741
  async destroy() {
3721
3742
  this.activeThread = null;
@@ -5229,7 +5250,7 @@ var PRECOMPILED_CONFIG = {
5229
5250
  "enableFreeTierPrioritization": true,
5230
5251
  "enableWorkloadAwareRouting": true
5231
5252
  },
5232
- "version": "11.2.8"
5253
+ "version": "11.3.0"
5233
5254
  };
5234
5255
 
5235
5256
  // src/core/config/schemas.ts
@@ -6478,6 +6499,8 @@ var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
6478
6499
  getManualOverride() {
6479
6500
  if (this.manualOverride && this.manualOverride.expiresAtMs) {
6480
6501
  if (Date.now() >= this.manualOverride.expiresAtMs) {
6502
+ this.manualOverride;
6503
+ this.manualOverride = void 0;
6481
6504
  void this.clearManualOverride();
6482
6505
  return void 0;
6483
6506
  }
@@ -6972,19 +6995,33 @@ var ProviderMetricsTracker = class extends EventEmitter {
6972
6995
  const p50 = getPercentile(latencies, 50);
6973
6996
  const p95 = getPercentile(latencies, 95);
6974
6997
  const p99 = getPercentile(latencies, 99);
6975
- const successful = records.filter((r) => r.success);
6976
- const failed = records.filter((r) => !r.success);
6977
- const stopFinishes = successful.filter((r) => r.finishReason === "stop");
6978
- const lengthFinishes = successful.filter((r) => r.finishReason === "length");
6979
- const errorFinishes = records.filter((r) => r.finishReason === "error");
6980
- const successRate = successful.length / records.length;
6981
- const properStopRate = successful.length > 0 ? stopFinishes.length / successful.length : 0;
6998
+ let successCount = 0;
6999
+ let failCount = 0;
7000
+ let stopFinishCount = 0;
7001
+ let lengthFinishCount = 0;
7002
+ let errorFinishCount = 0;
7003
+ let lastSuccessTimestamp = 0;
7004
+ let lastFailureTimestamp = 0;
7005
+ for (const r of records) {
7006
+ if (r.success) {
7007
+ successCount++;
7008
+ lastSuccessTimestamp = r.timestamp;
7009
+ if (r.finishReason === "stop") stopFinishCount++;
7010
+ else if (r.finishReason === "length") lengthFinishCount++;
7011
+ } else {
7012
+ failCount++;
7013
+ lastFailureTimestamp = r.timestamp;
7014
+ }
7015
+ if (r.finishReason === "error") errorFinishCount++;
7016
+ }
7017
+ const successRate = successCount / records.length;
7018
+ const properStopRate = successCount > 0 ? stopFinishCount / successCount : 0;
6982
7019
  const totalCost = records.reduce((sum, r) => sum + r.costUsd, 0);
6983
7020
  const avgCostPerRequest = totalCost / records.length;
6984
7021
  const totalTokens = records.reduce((sum, r) => sum + r.totalTokens, 0);
6985
7022
  const avgCostPer1M = totalTokens > 0 ? totalCost / totalTokens * 1e6 : 0;
6986
- const lastSuccess = successful.length > 0 ? successful[successful.length - 1].timestamp : 0;
6987
- const lastFailure = failed.length > 0 ? failed[failed.length - 1].timestamp : 0;
7023
+ const lastSuccess = lastSuccessTimestamp;
7024
+ const lastFailure = lastFailureTimestamp;
6988
7025
  let consecutiveFailures = 0;
6989
7026
  for (let i = records.length - 1; i >= 0; i--) {
6990
7027
  if (!records[i].success) {
@@ -7007,12 +7044,12 @@ var ProviderMetricsTracker = class extends EventEmitter {
7007
7044
  },
7008
7045
  quality: {
7009
7046
  totalRequests: records.length,
7010
- successfulRequests: successful.length,
7011
- failedRequests: failed.length,
7047
+ successfulRequests: successCount,
7048
+ failedRequests: failCount,
7012
7049
  successRate,
7013
- stopFinishes: stopFinishes.length,
7014
- lengthFinishes: lengthFinishes.length,
7015
- errorFinishes: errorFinishes.length,
7050
+ stopFinishes: stopFinishCount,
7051
+ lengthFinishes: lengthFinishCount,
7052
+ errorFinishes: errorFinishCount,
7016
7053
  properStopRate
7017
7054
  },
7018
7055
  cost: {
@@ -7121,7 +7158,7 @@ var ProviderMetricsTracker = class extends EventEmitter {
7121
7158
  * v9.0.2: Added score caching to reduce redundant calculations
7122
7159
  */
7123
7160
  async calculateScore(provider, weights, allProviders, healthMultiplier = 1) {
7124
- const cacheKey = `${provider}-${JSON.stringify(weights)}-${healthMultiplier}`;
7161
+ const cacheKey = `${provider}-${weights.cost}-${weights.latency}-${weights.quality}-${weights.availability}-${healthMultiplier}`;
7125
7162
  const cached = this.scoreCache.get(cacheKey);
7126
7163
  const currentRequestCount = this.getRequestCount(provider);
7127
7164
  if (cached) {
@@ -8285,8 +8322,7 @@ var Router = class {
8285
8322
  }
8286
8323
  }
8287
8324
  if (limitedProviders2.length === allProviders2.length && limitedProviders2.length > 0) {
8288
- const soonestReset = Math.min(...limitedProviders2.map((p) => p.resetAtMs));
8289
- throw ProviderError.allProvidersLimited(limitedProviders2, soonestReset);
8325
+ throw ProviderError.allProvidersLimited(limitedProviders2, this.getSoonestLimitReset(limitedProviders2));
8290
8326
  }
8291
8327
  throw ProviderError.noAvailableProviders();
8292
8328
  }
@@ -8692,8 +8728,7 @@ var Router = class {
8692
8728
  }
8693
8729
  }
8694
8730
  if (limitedProviders.length === allProviders.length && limitedProviders.length > 0) {
8695
- const soonestReset = Math.min(...limitedProviders.map((p) => p.resetAtMs));
8696
- throw ProviderError.allProvidersLimited(limitedProviders, soonestReset);
8731
+ throw ProviderError.allProvidersLimited(limitedProviders, this.getSoonestLimitReset(limitedProviders));
8697
8732
  }
8698
8733
  const errorDetails = {
8699
8734
  lastError: lastError?.message,
@@ -8927,6 +8962,16 @@ Run 'ax doctor' to diagnose provider setup.` : "";
8927
8962
  })
8928
8963
  };
8929
8964
  }
8965
+ /**
8966
+ * Calculate the soonest reset time from limited providers
8967
+ * v11.2.8: Added guard against empty array (Math.min on empty array returns Infinity)
8968
+ */
8969
+ getSoonestLimitReset(limitedProviders) {
8970
+ if (limitedProviders.length === 0) {
8971
+ return Date.now() + 6e4;
8972
+ }
8973
+ return Math.min(...limitedProviders.map((p) => p.resetAtMs));
8974
+ }
8930
8975
  };
8931
8976
 
8932
8977
  // src/core/memory/lazy-manager.ts
@@ -10760,8 +10805,6 @@ z.object({
10760
10805
  limit: z.number().int().positive().max(1e4).optional(),
10761
10806
  offset: z.number().int().nonnegative().optional()
10762
10807
  }).strict();
10763
-
10764
- // src/core/session/manager.ts
10765
10808
  var SessionManager = class _SessionManager {
10766
10809
  /** Active sessions (in-memory, keyed by session ID) */
10767
10810
  activeSessions = /* @__PURE__ */ new Map();
@@ -10834,8 +10877,9 @@ var SessionManager = class _SessionManager {
10834
10877
  try {
10835
10878
  SessionManagerConfigSchema.parse(config);
10836
10879
  } catch (error) {
10880
+ const message = error instanceof ZodError ? error.message : String(error);
10837
10881
  throw new SessionError(
10838
- `Invalid session manager config: ${error.message}`,
10882
+ `Invalid session manager config: ${message}`,
10839
10883
  void 0,
10840
10884
  "invalid_configuration"
10841
10885
  );
@@ -12236,8 +12280,8 @@ var ProjectContextLoader = class {
12236
12280
  const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
12237
12281
  if (projectMatch && projectMatch[1]) {
12238
12282
  const parts = projectMatch[1].trim().split(/\s+v/);
12239
- metadata.name = parts[0];
12240
- if (parts[1]) {
12283
+ metadata.name = parts[0] || "";
12284
+ if (parts.length > 1 && parts[1]) {
12241
12285
  metadata.version = parts[1];
12242
12286
  }
12243
12287
  }
@@ -25,7 +25,7 @@
25
25
 
26
26
  **Rationale:**
27
27
 
28
- - Node.js 20+ has first-class ESM support
28
+ - Node.js 24+ has first-class ESM support
29
29
  - Better tree-shaking and bundle optimization
30
30
  - Modern standards compliance
31
31
 
@@ -137,7 +137,7 @@ import type { Provider } from '../types/provider.js';
137
137
  - `index.js.map` - Source map
138
138
  - `index.d.ts` - Type definitions
139
139
 
140
- **Bundle target:** ESM, Node 20+, <250KB target
140
+ **Bundle target:** ESM, Node 24+, <250KB target
141
141
 
142
142
  ## Workspace Structure
143
143
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defai.digital/automatosx",
3
- "version": "11.2.8",
3
+ "version": "11.3.0",
4
4
  "description": "Provider-agnostic AI orchestration platform with 20+ specialized agents, persistent memory, and multi-provider routing for Claude Code, Gemini CLI, Codex CLI, and ax-cli",
5
5
  "type": "module",
6
6
  "publishConfig": {