@defai.digital/automatosx 12.3.0 → 12.4.1

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
@@ -1,18 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import * as path4 from 'path';
3
- import path4__default, { dirname, join, extname as extname$1, basename, resolve, relative, isAbsolute, sep, parse, delimiter } from 'path';
3
+ import path4__default, { dirname, join, extname as extname$1, basename, resolve, relative, isAbsolute, sep, delimiter, parse } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { mkdir, appendFile, readFile, readdir, writeFile, rename, unlink, copyFile, access, stat, realpath } from 'fs/promises';
6
6
  import * as fs4 from 'fs';
7
7
  import { existsSync, readFileSync, promises, mkdirSync, createWriteStream, writeFileSync, unlinkSync, constants } from 'fs';
8
8
  import Database2 from 'better-sqlite3';
9
9
  import { glob } from 'glob';
10
- import { spawn, spawnSync } from 'child_process';
10
+ import { spawn, exec, spawnSync } from 'child_process';
11
11
  import { z, ZodError } from 'zod';
12
12
  import chalk4 from 'chalk';
13
13
  import ora2 from 'ora';
14
14
  import readline, { createInterface } from 'readline';
15
15
  import { Mutex } from 'async-mutex';
16
+ import { promisify } from 'util';
16
17
  import Ajv from 'ajv';
17
18
  import addFormats from 'ajv-formats';
18
19
  import os2, { cpus } from 'os';
@@ -37,6 +38,226 @@ var init_esm_shims = __esm({
37
38
  "node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js"() {
38
39
  }
39
40
  });
41
+
42
+ // src/core/validation-limits.ts
43
+ function isValidRelativePath(path7) {
44
+ if (!path7 || typeof path7 !== "string") {
45
+ return false;
46
+ }
47
+ const normalizedPath = path7.replace(/\\/g, "/");
48
+ if (normalizedPath.startsWith("/")) {
49
+ return false;
50
+ }
51
+ if (normalizedPath.includes("..")) {
52
+ return false;
53
+ }
54
+ if (/^[a-zA-Z]:/.test(normalizedPath)) {
55
+ return false;
56
+ }
57
+ if (normalizedPath.startsWith("//")) {
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+ function isValidCommand(command) {
63
+ if (!command || typeof command !== "string") {
64
+ return false;
65
+ }
66
+ if (command.length > VALIDATION_LIMITS.MAX_COMMAND_LENGTH) {
67
+ return false;
68
+ }
69
+ if (!/^[a-z0-9_-]+$/i.test(command)) {
70
+ return false;
71
+ }
72
+ return true;
73
+ }
74
+ function isValidName(name) {
75
+ if (!name || typeof name !== "string") {
76
+ return false;
77
+ }
78
+ if (name.length > VALIDATION_LIMITS.MAX_NAME_LENGTH) {
79
+ return false;
80
+ }
81
+ if (!/^[a-z0-9][a-z0-9-_]*$/i.test(name)) {
82
+ return false;
83
+ }
84
+ return true;
85
+ }
86
+ function isValidExtension(ext) {
87
+ if (!ext || typeof ext !== "string") {
88
+ return false;
89
+ }
90
+ const normalized = ext.startsWith(".") ? ext : `.${ext}`;
91
+ if (normalized.length > 10 || normalized.length < 2) {
92
+ return false;
93
+ }
94
+ if (!/^\.[a-z0-9]+$/i.test(normalized)) {
95
+ return false;
96
+ }
97
+ return true;
98
+ }
99
+ function isPositiveInteger(value) {
100
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
101
+ }
102
+ function isNonNegativeInteger(value) {
103
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
104
+ }
105
+ var AX_PATHS, TIMEOUTS, DATABASE, VALIDATION_LIMITS;
106
+ var init_validation_limits = __esm({
107
+ "src/core/validation-limits.ts"() {
108
+ init_esm_shims();
109
+ AX_PATHS = {
110
+ /** Root directory for AutomatosX data */
111
+ ROOT: ".automatosx",
112
+ /** Log files directory */
113
+ LOGS: ".automatosx/logs",
114
+ /** Memory/database directory */
115
+ MEMORY: ".automatosx/memory",
116
+ /** Agent workspaces directory */
117
+ WORKSPACES: ".automatosx/workspaces",
118
+ /** Session data directory */
119
+ SESSIONS: ".automatosx/sessions",
120
+ /** Team configurations directory */
121
+ TEAMS: ".automatosx/teams",
122
+ /** Agent profiles directory */
123
+ AGENTS: ".automatosx/agents",
124
+ /** Workflow definitions directory */
125
+ WORKFLOWS: ".automatosx/workflows",
126
+ /** Abilities/skills directory */
127
+ ABILITIES: ".automatosx/abilities",
128
+ /** Checkpoints directory */
129
+ CHECKPOINTS: ".automatosx/checkpoints",
130
+ /** Cache directory */
131
+ CACHE: ".automatosx/cache",
132
+ /** Task database directory */
133
+ TASKS: ".automatosx/tasks",
134
+ /** Status files directory */
135
+ STATUS: ".automatosx/status",
136
+ /** Provider configurations directory */
137
+ PROVIDERS: ".automatosx/providers",
138
+ /** Iterate mode directory */
139
+ ITERATE: ".automatosx/iterate",
140
+ /** State directory (mode, provider overrides) */
141
+ STATE: ".automatosx/state",
142
+ /** Usage tracking directory */
143
+ USAGE: ".automatosx/usage",
144
+ /** Context store directory */
145
+ CONTEXT: ".automatosx/context",
146
+ /** Telemetry directory */
147
+ TELEMETRY: ".automatosx/telemetry",
148
+ /** Workspace index directory */
149
+ WORKSPACE: ".automatosx/workspace",
150
+ /** Config file paths */
151
+ CONFIG_YAML: ".automatosx/config.yaml",
152
+ CONFIG_JSON: ".automatosx/config.json"
153
+ };
154
+ TIMEOUTS = {
155
+ /** Default provider execution timeout (2 minutes) */
156
+ PROVIDER_DEFAULT: 12e4,
157
+ /** Provider detection/health check timeout (5 seconds) */
158
+ PROVIDER_DETECTION: 5e3,
159
+ /** Database busy timeout (5 seconds) */
160
+ DATABASE_BUSY: 5e3,
161
+ /** Provider cooldown after failure (30 seconds) */
162
+ PROVIDER_COOLDOWN: 3e4,
163
+ /** Circuit breaker recovery timeout (1 minute) */
164
+ CIRCUIT_BREAKER_RECOVERY: 6e4,
165
+ /** Circuit breaker failure window (5 minutes) */
166
+ CIRCUIT_BREAKER_WINDOW: 3e5,
167
+ /** Health check interval (5 minutes) */
168
+ HEALTH_CHECK_INTERVAL: 3e5,
169
+ /** Idle connection timeout (5 minutes) */
170
+ IDLE_CONNECTION: 3e5,
171
+ /** User decision/prompt timeout (10 minutes) */
172
+ USER_DECISION: 6e5,
173
+ /** Maximum execution timeout (1 hour) */
174
+ MAX_EXECUTION: 36e5,
175
+ /** Default global timeout (25 minutes) */
176
+ GLOBAL_DEFAULT: 15e5,
177
+ /** Config cache TTL (1 minute) */
178
+ CONFIG_CACHE_TTL: 6e4,
179
+ /** Score cache TTL (5 minutes) */
180
+ SCORE_CACHE_TTL: 3e5,
181
+ /** MCP health check interval (30 seconds) */
182
+ MCP_HEALTH_CHECK: 3e4,
183
+ /** CLI command confirmation delay (5 seconds) */
184
+ CLI_CONFIRM_DELAY: 5e3,
185
+ /** Kill switch confirmation delay (5 seconds) */
186
+ KILL_SWITCH_DELAY: 5e3,
187
+ /** Minimum rollout duration (1 hour) */
188
+ MIN_ROLLOUT_DURATION: 36e5,
189
+ /** Graceful shutdown timeout (30 seconds) */
190
+ GRACEFUL_SHUTDOWN: 3e4,
191
+ /** Package installation timeout (1 minute) */
192
+ PACKAGE_INSTALL: 6e4,
193
+ /** Quick CLI command timeout (3 seconds) */
194
+ QUICK_COMMAND: 3e3,
195
+ /** CLI version check timeout (10 seconds) */
196
+ VERSION_CHECK: 1e4
197
+ };
198
+ DATABASE = {
199
+ /** SQLite busy timeout in milliseconds */
200
+ BUSY_TIMEOUT: 5e3,
201
+ /** Maximum database connections in pool */
202
+ MAX_CONNECTIONS: 10,
203
+ /** Connection idle timeout (5 minutes) */
204
+ IDLE_TIMEOUT: 3e5,
205
+ /** Default query limit */
206
+ DEFAULT_QUERY_LIMIT: 1e3,
207
+ /** Maximum query limit */
208
+ MAX_QUERY_LIMIT: 1e4
209
+ };
210
+ VALIDATION_LIMITS = {
211
+ // Resource limits (prevent DoS)
212
+ MAX_ENTRIES: 1e6,
213
+ // 1 million entries (memory, cache)
214
+ MAX_TIMEOUT: 36e5,
215
+ // 1 hour (execution, delegation)
216
+ MAX_FILE_SIZE: 104857600,
217
+ // 100 MB (workspace, abilities)
218
+ MAX_CACHE_SIZE: 524288e3,
219
+ // 500 MB (cache storage)
220
+ MAX_SESSIONS: 1e4,
221
+ // 10k concurrent sessions
222
+ // Performance limits (prevent resource exhaustion)
223
+ MAX_CONCURRENT_AGENTS: 100,
224
+ // Maximum concurrent agents
225
+ MAX_CPU_PERCENT: 80,
226
+ // Maximum CPU usage percent
227
+ MAX_MEMORY_MB: 2048,
228
+ // Maximum memory usage in MB
229
+ // Config validation limits
230
+ MAX_CONFIG_FILE_SIZE: 1048576,
231
+ // 1MB max config file size
232
+ MAX_NAME_LENGTH: 50,
233
+ // Max name length for agents/providers
234
+ MAX_COMMAND_LENGTH: 100,
235
+ // Max command length
236
+ MAX_ARRAY_LENGTH: 1e4,
237
+ // Max array elements in config
238
+ // Path and file limits
239
+ MIN_FILE_SIZE: 1,
240
+ // Minimum file size in bytes
241
+ MIN_TIMEOUT: 1e3,
242
+ // Minimum timeout in ms (1 second)
243
+ MIN_INTERVAL: 100,
244
+ // Minimum interval in ms
245
+ MIN_BACKOFF_FACTOR: 1,
246
+ // Minimum backoff multiplier
247
+ MAX_BACKOFF_FACTOR: 5,
248
+ // Maximum backoff multiplier
249
+ MAX_TTL: 864e5,
250
+ // Maximum TTL in ms (24 hours)
251
+ MIN_BYTES: 1,
252
+ // Minimum bytes for file sizes
253
+ // Network limits
254
+ MIN_PORT: 1024,
255
+ // Minimum port number
256
+ MAX_PORT: 65535
257
+ // Maximum port number
258
+ };
259
+ }
260
+ });
40
261
  function sanitizeObject(obj, maxDepth = 5, currentDepth = 0) {
41
262
  if (currentDepth > maxDepth) {
42
263
  return "[Max Depth Reached]";
@@ -581,7 +802,7 @@ function installExitHandlers() {
581
802
  if (process.stderr.writable) {
582
803
  process.stderr.end();
583
804
  }
584
- } catch (error) {
805
+ } catch (_error) {
585
806
  }
586
807
  process.exit(signal === "SIGTERM" || signal === "SIGINT" ? 0 : 1);
587
808
  };
@@ -602,6 +823,7 @@ var init_process_manager = __esm({
602
823
  "src/shared/process/process-manager.ts"() {
603
824
  init_esm_shims();
604
825
  init_logger();
826
+ init_validation_limits();
605
827
  ProcessManager = class {
606
828
  childProcesses = /* @__PURE__ */ new Set();
607
829
  isShuttingDown = false;
@@ -638,7 +860,7 @@ var init_process_manager = __esm({
638
860
  *
639
861
  * @param timeout Maximum time to wait for graceful shutdown (ms)
640
862
  */
641
- async shutdown(timeout = 5e3) {
863
+ async shutdown(timeout = TIMEOUTS.PROVIDER_DETECTION) {
642
864
  if (this.isShuttingDown) {
643
865
  return;
644
866
  }
@@ -767,9 +989,10 @@ var init_factory = __esm({
767
989
  "src/core/database/factory.ts"() {
768
990
  init_esm_shims();
769
991
  init_logger();
992
+ init_validation_limits();
770
993
  DEFAULT_OPTIONS = {
771
994
  readonly: false,
772
- busyTimeout: 5e3,
995
+ busyTimeout: DATABASE.BUSY_TIMEOUT,
773
996
  verbose: false,
774
997
  enableWal: true,
775
998
  createDir: true
@@ -1615,8 +1838,8 @@ var init_verbosity_manager = __esm({
1615
1838
  }
1616
1839
  });
1617
1840
  function findOnPath(cmdBase) {
1618
- const isWindows2 = process.platform === "win32";
1619
- if (isWindows2) {
1841
+ const isWindows = process.platform === "win32";
1842
+ if (isWindows) {
1620
1843
  return findOnPathWindows(cmdBase);
1621
1844
  }
1622
1845
  return findOnPathUnix(cmdBase);
@@ -1964,9 +2187,10 @@ var init_streaming_progress_parser = __esm({
1964
2187
  // src/providers/error-patterns.ts
1965
2188
  function isQuotaError(error, providerName) {
1966
2189
  const patterns = PROVIDER_ERROR_PATTERNS[providerName] || GENERIC_ERROR_PATTERNS;
1967
- const message = (error?.message || "").toLowerCase();
1968
- const code = error?.code || "";
1969
- const statusCode = error?.status || error?.statusCode;
2190
+ const errorObj = error;
2191
+ const message = (errorObj?.message || "").toLowerCase();
2192
+ const code = errorObj?.code || "";
2193
+ const statusCode = errorObj?.status || errorObj?.statusCode;
1970
2194
  if (patterns.quota.some((pattern) => message.includes(pattern.toLowerCase()))) {
1971
2195
  return true;
1972
2196
  }
@@ -1983,9 +2207,10 @@ function isQuotaError(error, providerName) {
1983
2207
  }
1984
2208
  function isRateLimitError(error, providerName) {
1985
2209
  const patterns = PROVIDER_ERROR_PATTERNS[providerName] || GENERIC_ERROR_PATTERNS;
1986
- const message = (error?.message || "").toLowerCase();
1987
- const code = error?.code || "";
1988
- const statusCode = error?.status || error?.statusCode;
2210
+ const errorObj = error;
2211
+ const message = (errorObj?.message || "").toLowerCase();
2212
+ const code = errorObj?.code || "";
2213
+ const statusCode = errorObj?.status || errorObj?.statusCode;
1989
2214
  if (patterns.rateLimit.some((pattern) => message.includes(pattern.toLowerCase()))) {
1990
2215
  return true;
1991
2216
  }
@@ -2224,6 +2449,7 @@ var init_base_provider = __esm({
2224
2449
  init_esm_shims();
2225
2450
  init_logger();
2226
2451
  init_errors();
2452
+ init_validation_limits();
2227
2453
  init_cli_provider_detector();
2228
2454
  init_provider_schemas();
2229
2455
  init_streaming_progress_parser();
@@ -2266,15 +2492,16 @@ var init_base_provider = __esm({
2266
2492
  DEBIAN_FRONTEND: "noninteractive"
2267
2493
  };
2268
2494
  /** Default CLI execution timeout in milliseconds */
2269
- static DEFAULT_TIMEOUT_MS = 12e4;
2495
+ static DEFAULT_TIMEOUT_MS = TIMEOUTS.PROVIDER_DEFAULT;
2270
2496
  /** Time to wait after SIGTERM before escalating to SIGKILL */
2271
- static SIGKILL_ESCALATION_MS = 5e3;
2497
+ static SIGKILL_ESCALATION_MS = TIMEOUTS.PROVIDER_DETECTION;
2272
2498
  config;
2273
2499
  logger = logger;
2274
2500
  health;
2275
2501
  constructor(config) {
2276
2502
  const providerName = config.name.toLowerCase();
2277
- if (!_BaseProvider.ALLOWED_PROVIDER_NAMES.includes(providerName)) {
2503
+ const allowedNames = _BaseProvider.ALLOWED_PROVIDER_NAMES;
2504
+ if (!allowedNames.includes(providerName)) {
2278
2505
  throw new ProviderError(
2279
2506
  `Invalid provider name: ${config.name}. Allowed: ${_BaseProvider.ALLOWED_PROVIDER_NAMES.join(", ")}`,
2280
2507
  "E1001" /* CONFIG_INVALID */
@@ -2319,8 +2546,8 @@ var init_base_provider = __esm({
2319
2546
  const escapedPrompt = this.escapeShellArg(prompt);
2320
2547
  const fullCommand = `${cliCommand} ${argsString}${escapedPrompt}`;
2321
2548
  const commandLength = fullCommand.length;
2322
- const isWindows2 = process.platform === "win32";
2323
- const useStdin = isWindows2 && commandLength > 7e3;
2549
+ const isWindows = process.platform === "win32";
2550
+ const useStdin = isWindows && commandLength > 7e3;
2324
2551
  logger.debug(`Executing ${cliCommand} CLI with streaming support`, {
2325
2552
  command: cliCommand,
2326
2553
  promptLength: prompt.length,
@@ -2909,8 +3136,8 @@ ${fullPrompt}
2909
3136
  * - Windows: hello"world → "hello\"world"
2910
3137
  */
2911
3138
  escapeShellArg(arg) {
2912
- const isWindows2 = process.platform === "win32";
2913
- if (isWindows2) {
3139
+ const isWindows = process.platform === "win32";
3140
+ if (isWindows) {
2914
3141
  return '"' + arg.replace(/"/g, '\\"').replace(/%/g, "%%") + '"';
2915
3142
  } else {
2916
3143
  return "'" + arg.replace(/'/g, "'\\''") + "'";
@@ -3778,7 +4005,7 @@ var init_sdk_adapter = __esm({
3778
4005
  this.codex = new this.sdkModule.Codex();
3779
4006
  this.initialized = true;
3780
4007
  logger.info("Codex SDK initialized");
3781
- } catch (error) {
4008
+ } catch (_error) {
3782
4009
  throw new CodexError(
3783
4010
  "CLI_NOT_FOUND" /* CLI_NOT_FOUND */,
3784
4011
  "Codex SDK not available. Install with: npm install @openai/codex-sdk"
@@ -4129,7 +4356,7 @@ async function isCLIModeAvailable() {
4129
4356
  execSync("codex --version", {
4130
4357
  encoding: "utf-8",
4131
4358
  stdio: ["pipe", "pipe", "pipe"],
4132
- timeout: 3e3
4359
+ timeout: TIMEOUTS.QUICK_COMMAND
4133
4360
  });
4134
4361
  return true;
4135
4362
  } catch {
@@ -4141,6 +4368,3205 @@ var init_openai_provider_factory = __esm({
4141
4368
  init_esm_shims();
4142
4369
  init_openai_provider();
4143
4370
  init_logger();
4371
+ init_validation_limits();
4372
+ }
4373
+ });
4374
+ var FeatureFlagManager;
4375
+ var init_flag_manager = __esm({
4376
+ "src/core/feature-flags/flag-manager.ts"() {
4377
+ init_esm_shims();
4378
+ init_logger();
4379
+ FeatureFlagManager = class {
4380
+ flags = /* @__PURE__ */ new Map();
4381
+ storagePath;
4382
+ flagsDir;
4383
+ workspacePath;
4384
+ constructor(workspacePath = process.cwd()) {
4385
+ this.workspacePath = workspacePath;
4386
+ this.flagsDir = join(workspacePath, ".automatosx");
4387
+ this.storagePath = join(this.flagsDir, "feature-flags.json");
4388
+ this.loadFlags();
4389
+ }
4390
+ /**
4391
+ * Check if workspace has a storage directory
4392
+ */
4393
+ hasStorage() {
4394
+ return existsSync(this.flagsDir);
4395
+ }
4396
+ /**
4397
+ * Get workspace path for diagnostics
4398
+ */
4399
+ getWorkspacePath() {
4400
+ return this.workspacePath;
4401
+ }
4402
+ /**
4403
+ * Load flags from storage
4404
+ */
4405
+ loadFlags() {
4406
+ try {
4407
+ if (!this.hasStorage()) {
4408
+ logger.debug("Feature flag storage not initialized", {
4409
+ workspacePath: this.workspacePath
4410
+ });
4411
+ return;
4412
+ }
4413
+ if (existsSync(this.storagePath)) {
4414
+ const data = readFileSync(this.storagePath, "utf-8");
4415
+ const flags = JSON.parse(data);
4416
+ for (const flag of flags) {
4417
+ this.flags.set(flag.name, flag);
4418
+ }
4419
+ logger.info("Feature flags loaded", {
4420
+ count: flags.length,
4421
+ path: this.storagePath
4422
+ });
4423
+ } else {
4424
+ logger.info("No feature flags file found, starting fresh");
4425
+ }
4426
+ } catch (error) {
4427
+ logger.error("Failed to load feature flags", {
4428
+ error: error.message
4429
+ });
4430
+ }
4431
+ }
4432
+ /**
4433
+ * Save flags to storage
4434
+ */
4435
+ saveFlags() {
4436
+ try {
4437
+ this.ensureStorageDir();
4438
+ const flagsArray = Array.from(this.flags.values());
4439
+ const data = JSON.stringify(flagsArray, null, 2);
4440
+ writeFileSync(this.storagePath, data, "utf-8");
4441
+ } catch (error) {
4442
+ logger.error("Failed to save feature flags", {
4443
+ error: error.message
4444
+ });
4445
+ }
4446
+ }
4447
+ /**
4448
+ * Ensure storage directory exists before writing
4449
+ */
4450
+ ensureStorageDir() {
4451
+ if (!existsSync(this.flagsDir)) {
4452
+ mkdirSync(this.flagsDir, { recursive: true });
4453
+ }
4454
+ }
4455
+ /**
4456
+ * Define a feature flag
4457
+ */
4458
+ defineFlag(flag) {
4459
+ this.flags.set(flag.name, flag);
4460
+ this.saveFlags();
4461
+ logger.info("Feature flag defined", { name: flag.name });
4462
+ }
4463
+ /**
4464
+ * Check if flag is enabled
4465
+ */
4466
+ isEnabled(flagName, context) {
4467
+ const flag = this.flags.get(flagName);
4468
+ if (!flag) return false;
4469
+ if (flag.killSwitch?.enabled) {
4470
+ logger.warn(`Feature flag ${flagName} killed`, {
4471
+ reason: flag.killSwitch.reason,
4472
+ timestamp: flag.killSwitch.timestamp
4473
+ });
4474
+ return false;
4475
+ }
4476
+ const envOverride = process.env[`FEATURE_${flagName.toUpperCase()}`];
4477
+ if (envOverride === "false" || envOverride === "0") {
4478
+ logger.warn(`Feature flag ${flagName} disabled by env var`);
4479
+ return false;
4480
+ }
4481
+ if (flag.rolloutPercentage !== void 0) {
4482
+ const hash = this.hashContext(context);
4483
+ const bucket = hash % 100;
4484
+ const enabled = bucket < flag.rolloutPercentage;
4485
+ return enabled;
4486
+ }
4487
+ return flag.enabled;
4488
+ }
4489
+ /**
4490
+ * Gradually increase rollout percentage
4491
+ */
4492
+ async increaseRollout(flagName, newPercentage, options) {
4493
+ const flag = this.flags.get(flagName);
4494
+ if (!flag) throw new Error(`Flag ${flagName} not found`);
4495
+ const currentPercentage = flag.rolloutPercentage || 0;
4496
+ if (newPercentage > currentPercentage * 5 && newPercentage !== 100 && currentPercentage > 0) {
4497
+ throw new Error(
4498
+ `Rollout increase too aggressive: ${currentPercentage}% \u2192 ${newPercentage}%
4499
+ Maximum safe increase: ${currentPercentage * 5}%`
4500
+ );
4501
+ }
4502
+ if (options?.minimumDuration && flag.lastUpdated) {
4503
+ const timeSinceLastChange = Date.now() - flag.lastUpdated;
4504
+ if (timeSinceLastChange < options.minimumDuration) {
4505
+ throw new Error(
4506
+ `Must wait ${options.minimumDuration}ms before increasing rollout
4507
+ Time since last change: ${timeSinceLastChange}ms`
4508
+ );
4509
+ }
4510
+ }
4511
+ flag.rolloutPercentage = newPercentage;
4512
+ flag.lastUpdated = Date.now();
4513
+ this.flags.set(flagName, flag);
4514
+ this.saveFlags();
4515
+ logger.info(`Feature flag ${flagName} rollout increased`, {
4516
+ from: currentPercentage,
4517
+ to: newPercentage,
4518
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4519
+ });
4520
+ }
4521
+ /**
4522
+ * Emergency kill switch
4523
+ */
4524
+ async killSwitch(flagName, reason) {
4525
+ const flag = this.flags.get(flagName);
4526
+ if (!flag) throw new Error(`Flag ${flagName} not found`);
4527
+ flag.killSwitch = {
4528
+ enabled: true,
4529
+ reason,
4530
+ timestamp: Date.now(),
4531
+ by: process.env.USER || "unknown"
4532
+ };
4533
+ this.flags.set(flagName, flag);
4534
+ this.saveFlags();
4535
+ logger.error(`\u{1F6A8} KILL SWITCH ACTIVATED: ${flagName}`, {
4536
+ reason,
4537
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4538
+ });
4539
+ }
4540
+ /**
4541
+ * Get all flags
4542
+ */
4543
+ getAllFlags() {
4544
+ return Array.from(this.flags.values());
4545
+ }
4546
+ /**
4547
+ * Get a specific flag
4548
+ */
4549
+ getFlag(flagName) {
4550
+ return this.flags.get(flagName);
4551
+ }
4552
+ /**
4553
+ * Hash context for deterministic bucketing
4554
+ */
4555
+ hashContext(context) {
4556
+ const str = JSON.stringify(context || {});
4557
+ let hash = 0;
4558
+ for (let i = 0; i < str.length; i++) {
4559
+ const char = str.charCodeAt(i);
4560
+ hash = (hash << 5) - hash + char;
4561
+ hash = hash & hash;
4562
+ }
4563
+ return hash >>> 0;
4564
+ }
4565
+ };
4566
+ }
4567
+ });
4568
+
4569
+ // src/core/feature-flags/flags.ts
4570
+ function getFlagManager(workspacePath) {
4571
+ const path7 = process.cwd();
4572
+ if (!flagManagerInstances.has(path7)) {
4573
+ const manager = new FeatureFlagManager(path7);
4574
+ initializeFlags(manager);
4575
+ flagManagerInstances.set(path7, manager);
4576
+ }
4577
+ return flagManagerInstances.get(path7);
4578
+ }
4579
+ function initializeFlags(manager) {
4580
+ if (!manager.hasStorage()) {
4581
+ logger.debug("Skipping feature flag initialization; workspace not initialized", {
4582
+ workspacePath: manager.getWorkspacePath()
4583
+ });
4584
+ return;
4585
+ }
4586
+ initializeGeminiStreamingFlag(manager);
4587
+ initializeProviderArchitectureFlags(manager);
4588
+ }
4589
+ function initializeGeminiStreamingFlag(manager) {
4590
+ const existingFlag = manager.getFlag("gemini_streaming");
4591
+ if (!existingFlag) {
4592
+ manager.defineFlag({
4593
+ name: "gemini_streaming",
4594
+ description: "Enable Gemini as a valid option for streaming workloads",
4595
+ enabled: true,
4596
+ rolloutPercentage: 0,
4597
+ metadata: {
4598
+ owner: "platform-team",
4599
+ jiraTicket: "AUTO-1234",
4600
+ expectedImpact: "96% cost reduction on streaming tasks"
4601
+ }
4602
+ });
4603
+ logger.info("Feature flag gemini_streaming initialized at 0%");
4604
+ }
4605
+ }
4606
+ function initializeProviderArchitectureFlags(manager) {
4607
+ for (const flagDef of DEFAULT_PROVIDER_FLAGS) {
4608
+ const existingFlag = manager.getFlag(flagDef.name);
4609
+ if (!existingFlag) {
4610
+ manager.defineFlag(flagDef);
4611
+ logger.info(`Feature flag ${flagDef.name} initialized`, {
4612
+ enabled: flagDef.enabled,
4613
+ rolloutPercentage: flagDef.rolloutPercentage
4614
+ });
4615
+ }
4616
+ }
4617
+ }
4618
+ function isSDKFirstModeEnabled(context) {
4619
+ const manager = getFlagManager();
4620
+ return manager.isEnabled(PROVIDER_ARCHITECTURE_FLAGS.SDK_FIRST_MODE, context);
4621
+ }
4622
+ function isSDKFallbackEnabled() {
4623
+ const manager = getFlagManager();
4624
+ return manager.isEnabled(PROVIDER_ARCHITECTURE_FLAGS.SDK_FALLBACK_ENABLED);
4625
+ }
4626
+ function shouldCollectProviderMetrics() {
4627
+ const manager = getFlagManager();
4628
+ return manager.isEnabled(PROVIDER_ARCHITECTURE_FLAGS.PROVIDER_METRICS);
4629
+ }
4630
+ var flagManagerInstances, PROVIDER_ARCHITECTURE_FLAGS, DEFAULT_PROVIDER_FLAGS;
4631
+ var init_flags = __esm({
4632
+ "src/core/feature-flags/flags.ts"() {
4633
+ init_esm_shims();
4634
+ init_flag_manager();
4635
+ init_logger();
4636
+ flagManagerInstances = /* @__PURE__ */ new Map();
4637
+ PROVIDER_ARCHITECTURE_FLAGS = {
4638
+ /** Enable SDK-first execution pattern (SDK primary, CLI fallback) */
4639
+ SDK_FIRST_MODE: "sdk_first_mode",
4640
+ /** Enable MCP bidirectional communication for agentic providers */
4641
+ MCP_BIDIRECTIONAL: "mcp_bidirectional",
4642
+ /** Auto-inject MCP server config into provider config files */
4643
+ AUTO_INJECT_MCP_CONFIG: "auto_inject_mcp_config",
4644
+ /** Allow CLI fallback when SDK fails */
4645
+ SDK_FALLBACK_ENABLED: "sdk_fallback_enabled",
4646
+ /** Show deprecation warnings (legacy providers, etc.) */
4647
+ DEPRECATION_WARNINGS: "deprecation_warnings",
4648
+ /** Enable provider metrics collection */
4649
+ PROVIDER_METRICS: "provider_metrics"
4650
+ };
4651
+ DEFAULT_PROVIDER_FLAGS = [
4652
+ {
4653
+ name: PROVIDER_ARCHITECTURE_FLAGS.SDK_FIRST_MODE,
4654
+ description: "Enable SDK-first execution pattern (SDK primary, CLI fallback) for GLM, Grok, and Codex providers",
4655
+ enabled: false,
4656
+ // Disabled by default, enable in v11.7.0
4657
+ rolloutPercentage: 0,
4658
+ metadata: {
4659
+ owner: "platform-team",
4660
+ expectedImpact: "Lower latency (~5ms vs ~200ms), better type safety"
4661
+ }
4662
+ },
4663
+ {
4664
+ name: PROVIDER_ARCHITECTURE_FLAGS.MCP_BIDIRECTIONAL,
4665
+ description: "Enable MCP bidirectional communication for Claude and Gemini agents",
4666
+ enabled: false,
4667
+ // Disabled by default, enable in v11.8.0
4668
+ rolloutPercentage: 0,
4669
+ metadata: {
4670
+ owner: "platform-team",
4671
+ expectedImpact: "Faster agent communication via MCP instead of stdout parsing"
4672
+ }
4673
+ },
4674
+ {
4675
+ name: PROVIDER_ARCHITECTURE_FLAGS.AUTO_INJECT_MCP_CONFIG,
4676
+ description: "Automatically inject AutomatosX MCP server config into provider config files",
4677
+ enabled: false,
4678
+ // Disabled by default, requires careful testing
4679
+ rolloutPercentage: 0,
4680
+ metadata: {
4681
+ owner: "platform-team",
4682
+ expectedImpact: "Seamless MCP setup for agents"
4683
+ }
4684
+ },
4685
+ {
4686
+ name: PROVIDER_ARCHITECTURE_FLAGS.SDK_FALLBACK_ENABLED,
4687
+ description: "Allow CLI fallback when SDK execution fails",
4688
+ enabled: true,
4689
+ // Enabled by default for safety
4690
+ rolloutPercentage: 100,
4691
+ metadata: {
4692
+ owner: "platform-team",
4693
+ expectedImpact: "Graceful degradation when SDK unavailable"
4694
+ }
4695
+ },
4696
+ {
4697
+ name: PROVIDER_ARCHITECTURE_FLAGS.DEPRECATION_WARNINGS,
4698
+ description: "Show deprecation warnings for legacy features",
4699
+ enabled: true,
4700
+ // Enabled by default to warn users
4701
+ rolloutPercentage: 100,
4702
+ metadata: {
4703
+ owner: "platform-team",
4704
+ expectedImpact: "v13.0.0: ax-cli removed, GLM/Grok are SDK-first"
4705
+ }
4706
+ },
4707
+ {
4708
+ name: PROVIDER_ARCHITECTURE_FLAGS.PROVIDER_METRICS,
4709
+ description: "Enable provider metrics collection (SDK/CLI usage, fallback rate, MCP connections)",
4710
+ enabled: true,
4711
+ // Enabled by default for observability
4712
+ rolloutPercentage: 100,
4713
+ metadata: {
4714
+ owner: "platform-team",
4715
+ expectedImpact: "Better visibility into provider performance"
4716
+ }
4717
+ }
4718
+ ];
4719
+ }
4720
+ });
4721
+
4722
+ // src/providers/fallback-decision.ts
4723
+ function decideFallback(error, providerName) {
4724
+ const errorMessage = getErrorMessage(error).toLowerCase();
4725
+ const errorCode = getErrorCode(error);
4726
+ const statusCode = getStatusCode(error);
4727
+ logger.debug("Classifying error for fallback decision", {
4728
+ provider: providerName,
4729
+ message: errorMessage.substring(0, 100),
4730
+ code: errorCode,
4731
+ statusCode
4732
+ });
4733
+ if (matchesPatterns(errorMessage, SDK_UNAVAILABLE_PATTERNS)) {
4734
+ return {
4735
+ decision: "use_cli" /* USE_CLI */,
4736
+ reason: "SDK not available or not installed",
4737
+ severity: "warn"
4738
+ };
4739
+ }
4740
+ if (matchesPatterns(errorMessage, AUTH_ERROR_PATTERNS) || statusCode === 401 || statusCode === 403) {
4741
+ return {
4742
+ decision: "propagate" /* PROPAGATE */,
4743
+ reason: "Authentication error - CLI would fail with same credentials",
4744
+ severity: "error"
4745
+ };
4746
+ }
4747
+ if (matchesPatterns(errorMessage, RATE_LIMIT_PATTERNS) || statusCode === 429) {
4748
+ return {
4749
+ decision: "retry_sdk" /* RETRY_SDK */,
4750
+ reason: "Rate limited - retrying with backoff",
4751
+ severity: "warn",
4752
+ retryDelayMs: 5e3
4753
+ // Longer delay for rate limits
4754
+ };
4755
+ }
4756
+ if (matchesPatterns(errorMessage, TRANSIENT_ERROR_PATTERNS)) {
4757
+ return {
4758
+ decision: "retry_sdk" /* RETRY_SDK */,
4759
+ reason: "Transient network error - retrying",
4760
+ severity: "warn",
4761
+ retryDelayMs: 1e3
4762
+ };
4763
+ }
4764
+ if (matchesPatterns(errorMessage, SERVER_ERROR_PATTERNS) || statusCode && statusCode >= 500 && statusCode < 600) {
4765
+ return {
4766
+ decision: "retry_sdk" /* RETRY_SDK */,
4767
+ reason: "Server error - retrying",
4768
+ severity: "warn",
4769
+ retryDelayMs: 2e3
4770
+ };
4771
+ }
4772
+ if (matchesPatterns(errorMessage, CLIENT_ERROR_PATTERNS) || statusCode && statusCode >= 400 && statusCode < 500) {
4773
+ return {
4774
+ decision: "propagate" /* PROPAGATE */,
4775
+ reason: "Client error - request is invalid",
4776
+ severity: "error"
4777
+ };
4778
+ }
4779
+ if (isSDKFallbackEnabled()) {
4780
+ return {
4781
+ decision: "use_cli" /* USE_CLI */,
4782
+ reason: "Unknown error - falling back to CLI",
4783
+ severity: "warn"
4784
+ };
4785
+ }
4786
+ return {
4787
+ decision: "propagate" /* PROPAGATE */,
4788
+ reason: "Unknown error and fallback is disabled",
4789
+ severity: "error"
4790
+ };
4791
+ }
4792
+ function getErrorMessage(error) {
4793
+ if (error instanceof Error) {
4794
+ return error.message;
4795
+ }
4796
+ if (typeof error === "string") {
4797
+ return error;
4798
+ }
4799
+ if (error && typeof error === "object") {
4800
+ const obj = error;
4801
+ if (typeof obj.message === "string") {
4802
+ return obj.message;
4803
+ }
4804
+ if (typeof obj.error === "string") {
4805
+ return obj.error;
4806
+ }
4807
+ if (obj.error && typeof obj.error === "object") {
4808
+ const innerError = obj.error;
4809
+ if (typeof innerError.message === "string") {
4810
+ return innerError.message;
4811
+ }
4812
+ }
4813
+ }
4814
+ return String(error);
4815
+ }
4816
+ function getErrorCode(error) {
4817
+ if (error && typeof error === "object") {
4818
+ const obj = error;
4819
+ if (typeof obj.code === "string") {
4820
+ return obj.code;
4821
+ }
4822
+ if (typeof obj.errorCode === "string") {
4823
+ return obj.errorCode;
4824
+ }
4825
+ }
4826
+ return void 0;
4827
+ }
4828
+ function getStatusCode(error) {
4829
+ if (error && typeof error === "object") {
4830
+ const obj = error;
4831
+ if (typeof obj.status === "number") {
4832
+ return obj.status;
4833
+ }
4834
+ if (typeof obj.statusCode === "number") {
4835
+ return obj.statusCode;
4836
+ }
4837
+ if (obj.response && typeof obj.response === "object") {
4838
+ const response = obj.response;
4839
+ if (typeof response.status === "number") {
4840
+ return response.status;
4841
+ }
4842
+ }
4843
+ }
4844
+ return void 0;
4845
+ }
4846
+ function matchesPatterns(message, patterns) {
4847
+ return patterns.some((pattern) => message.includes(pattern.toLowerCase()));
4848
+ }
4849
+ var SDK_UNAVAILABLE_PATTERNS, AUTH_ERROR_PATTERNS, TRANSIENT_ERROR_PATTERNS, RATE_LIMIT_PATTERNS, SERVER_ERROR_PATTERNS, CLIENT_ERROR_PATTERNS;
4850
+ var init_fallback_decision = __esm({
4851
+ "src/providers/fallback-decision.ts"() {
4852
+ init_esm_shims();
4853
+ init_logger();
4854
+ init_flags();
4855
+ SDK_UNAVAILABLE_PATTERNS = [
4856
+ "module not found",
4857
+ "cannot find module",
4858
+ "sdk not available",
4859
+ "sdk not installed",
4860
+ "failed to initialize sdk",
4861
+ "sdk initialization failed",
4862
+ "package not found",
4863
+ "@zhipuai/sdk",
4864
+ "@xai-org/grok-sdk",
4865
+ "@openai/codex-sdk",
4866
+ "enoent",
4867
+ // File not found (npm module missing)
4868
+ "cannot resolve",
4869
+ "dynamic import failed"
4870
+ ];
4871
+ AUTH_ERROR_PATTERNS = [
4872
+ "authentication failed",
4873
+ "invalid api key",
4874
+ "invalid_api_key",
4875
+ "unauthorized",
4876
+ "api key not found",
4877
+ "api_key_invalid",
4878
+ "invalid credentials",
4879
+ "authentication required",
4880
+ "access denied",
4881
+ "401",
4882
+ "403",
4883
+ "forbidden",
4884
+ "invalid_grant",
4885
+ "token expired",
4886
+ "invalid token"
4887
+ ];
4888
+ TRANSIENT_ERROR_PATTERNS = [
4889
+ "timeout",
4890
+ "etimedout",
4891
+ "econnreset",
4892
+ "econnrefused",
4893
+ "enotfound",
4894
+ "network error",
4895
+ "socket hang up",
4896
+ "connection reset",
4897
+ "temporary failure",
4898
+ "service unavailable",
4899
+ "503",
4900
+ "504",
4901
+ "gateway timeout",
4902
+ "bad gateway",
4903
+ "502"
4904
+ ];
4905
+ RATE_LIMIT_PATTERNS = [
4906
+ "rate limit",
4907
+ "rate_limit",
4908
+ "too many requests",
4909
+ "429",
4910
+ "throttled",
4911
+ "quota exceeded",
4912
+ "resource_exhausted",
4913
+ "overloaded"
4914
+ ];
4915
+ SERVER_ERROR_PATTERNS = [
4916
+ "500",
4917
+ "502",
4918
+ "503",
4919
+ "504",
4920
+ "internal server error",
4921
+ "internal error",
4922
+ "server error"
4923
+ ];
4924
+ CLIENT_ERROR_PATTERNS = [
4925
+ "400",
4926
+ "bad request",
4927
+ "invalid request",
4928
+ "validation error",
4929
+ "invalid parameter",
4930
+ "missing parameter",
4931
+ "malformed request"
4932
+ ];
4933
+ }
4934
+ });
4935
+
4936
+ // src/core/metrics/provider-metrics.ts
4937
+ function getProviderMetrics() {
4938
+ return ProviderMetricsCollector.getInstance();
4939
+ }
4940
+ var ProviderMetricsCollector;
4941
+ var init_provider_metrics = __esm({
4942
+ "src/core/metrics/provider-metrics.ts"() {
4943
+ init_esm_shims();
4944
+ init_logger();
4945
+ init_flags();
4946
+ ProviderMetricsCollector = class _ProviderMetricsCollector {
4947
+ static instance = null;
4948
+ // Per-provider metrics
4949
+ providerMetrics = /* @__PURE__ */ new Map();
4950
+ // MCP metrics
4951
+ mcpMetrics = {
4952
+ totalConnections: 0,
4953
+ activeConnections: 0,
4954
+ failedConnections: 0,
4955
+ totalToolCalls: 0,
4956
+ avgToolCallLatencyMs: 0,
4957
+ sessionsByProvider: {}
4958
+ };
4959
+ // Latency tracking (for averages)
4960
+ sdkLatencies = /* @__PURE__ */ new Map();
4961
+ cliLatencies = /* @__PURE__ */ new Map();
4962
+ mcpLatencies = [];
4963
+ // Max samples to keep for latency averaging
4964
+ MAX_LATENCY_SAMPLES = 100;
4965
+ constructor() {
4966
+ }
4967
+ /**
4968
+ * Get singleton instance
4969
+ */
4970
+ static getInstance() {
4971
+ if (!_ProviderMetricsCollector.instance) {
4972
+ _ProviderMetricsCollector.instance = new _ProviderMetricsCollector();
4973
+ }
4974
+ return _ProviderMetricsCollector.instance;
4975
+ }
4976
+ /**
4977
+ * Reset singleton instance (for testing)
4978
+ */
4979
+ static resetInstance() {
4980
+ _ProviderMetricsCollector.instance = null;
4981
+ }
4982
+ /**
4983
+ * Check if metrics collection is enabled
4984
+ */
4985
+ isEnabled() {
4986
+ return shouldCollectProviderMetrics();
4987
+ }
4988
+ /**
4989
+ * Get or create provider metrics data
4990
+ */
4991
+ getOrCreateProviderMetrics(providerName) {
4992
+ if (!this.providerMetrics.has(providerName)) {
4993
+ this.providerMetrics.set(providerName, {
4994
+ providerName,
4995
+ executionMode: "cli",
4996
+ // Default mode
4997
+ circuitBreakerState: "closed",
4998
+ metrics: {
4999
+ sdkExecutions: 0,
5000
+ cliExecutions: 0,
5001
+ mcpToolCalls: 0,
5002
+ sdkFallbacks: 0,
5003
+ sdkErrors: 0,
5004
+ cliErrors: 0,
5005
+ mcpConnectionFailures: 0,
5006
+ avgSdkLatencyMs: 0,
5007
+ avgCliLatencyMs: 0,
5008
+ avgMcpLatencyMs: 0,
5009
+ fallbackRate: 0,
5010
+ sdkSuccessRate: 1,
5011
+ cliSuccessRate: 1,
5012
+ mcpSuccessRate: 1
5013
+ },
5014
+ lastUpdated: Date.now()
5015
+ });
5016
+ }
5017
+ return this.providerMetrics.get(providerName);
5018
+ }
5019
+ /**
5020
+ * Record SDK execution
5021
+ */
5022
+ recordSDKExecution(providerName, latencyMs, success) {
5023
+ if (!this.isEnabled()) return;
5024
+ const data = this.getOrCreateProviderMetrics(providerName);
5025
+ data.metrics.sdkExecutions++;
5026
+ if (!success) {
5027
+ data.metrics.sdkErrors++;
5028
+ }
5029
+ this.addLatencySample(this.sdkLatencies, providerName, latencyMs);
5030
+ data.metrics.avgSdkLatencyMs = this.calculateAverageLatency(
5031
+ this.sdkLatencies.get(providerName) || []
5032
+ );
5033
+ data.metrics.sdkSuccessRate = this.calculateSuccessRate(
5034
+ data.metrics.sdkExecutions,
5035
+ data.metrics.sdkErrors
5036
+ );
5037
+ data.lastUpdated = Date.now();
5038
+ logger.debug("SDK execution recorded", {
5039
+ provider: providerName,
5040
+ latencyMs,
5041
+ success,
5042
+ totalExecutions: data.metrics.sdkExecutions
5043
+ });
5044
+ }
5045
+ /**
5046
+ * Record CLI execution
5047
+ */
5048
+ recordCLIExecution(providerName, latencyMs, success) {
5049
+ if (!this.isEnabled()) return;
5050
+ const data = this.getOrCreateProviderMetrics(providerName);
5051
+ data.metrics.cliExecutions++;
5052
+ if (!success) {
5053
+ data.metrics.cliErrors++;
5054
+ }
5055
+ this.addLatencySample(this.cliLatencies, providerName, latencyMs);
5056
+ data.metrics.avgCliLatencyMs = this.calculateAverageLatency(
5057
+ this.cliLatencies.get(providerName) || []
5058
+ );
5059
+ data.metrics.cliSuccessRate = this.calculateSuccessRate(
5060
+ data.metrics.cliExecutions,
5061
+ data.metrics.cliErrors
5062
+ );
5063
+ data.lastUpdated = Date.now();
5064
+ logger.debug("CLI execution recorded", {
5065
+ provider: providerName,
5066
+ latencyMs,
5067
+ success,
5068
+ totalExecutions: data.metrics.cliExecutions
5069
+ });
5070
+ }
5071
+ /**
5072
+ * Record SDK fallback to CLI
5073
+ */
5074
+ recordSDKFallback(providerName, reason) {
5075
+ if (!this.isEnabled()) return;
5076
+ const data = this.getOrCreateProviderMetrics(providerName);
5077
+ data.metrics.sdkFallbacks++;
5078
+ if (data.metrics.sdkExecutions > 0) {
5079
+ data.metrics.fallbackRate = data.metrics.sdkFallbacks / data.metrics.sdkExecutions;
5080
+ }
5081
+ data.lastUpdated = Date.now();
5082
+ logger.info("SDK fallback recorded", {
5083
+ provider: providerName,
5084
+ reason,
5085
+ fallbackRate: data.metrics.fallbackRate
5086
+ });
5087
+ }
5088
+ /**
5089
+ * Record MCP connection
5090
+ */
5091
+ recordMCPConnection(providerName, success) {
5092
+ if (!this.isEnabled()) return;
5093
+ this.mcpMetrics.totalConnections++;
5094
+ if (success) {
5095
+ this.mcpMetrics.activeConnections++;
5096
+ this.mcpMetrics.sessionsByProvider[providerName] = (this.mcpMetrics.sessionsByProvider[providerName] || 0) + 1;
5097
+ } else {
5098
+ this.mcpMetrics.failedConnections++;
5099
+ const data = this.getOrCreateProviderMetrics(providerName);
5100
+ data.metrics.mcpConnectionFailures++;
5101
+ data.lastUpdated = Date.now();
5102
+ }
5103
+ logger.debug("MCP connection recorded", {
5104
+ provider: providerName,
5105
+ success,
5106
+ activeConnections: this.mcpMetrics.activeConnections
5107
+ });
5108
+ }
5109
+ /**
5110
+ * Record MCP connection closed
5111
+ */
5112
+ recordMCPDisconnection(providerName) {
5113
+ if (!this.isEnabled()) return;
5114
+ if (this.mcpMetrics.activeConnections > 0) {
5115
+ this.mcpMetrics.activeConnections--;
5116
+ }
5117
+ const currentCount = this.mcpMetrics.sessionsByProvider[providerName];
5118
+ if (currentCount !== void 0 && currentCount > 0) {
5119
+ this.mcpMetrics.sessionsByProvider[providerName] = currentCount - 1;
5120
+ }
5121
+ logger.debug("MCP disconnection recorded", {
5122
+ provider: providerName,
5123
+ activeConnections: this.mcpMetrics.activeConnections
5124
+ });
5125
+ }
5126
+ /**
5127
+ * Record MCP tool call
5128
+ */
5129
+ recordMCPToolCall(providerName, toolName, latencyMs, success) {
5130
+ if (!this.isEnabled()) return;
5131
+ const data = this.getOrCreateProviderMetrics(providerName);
5132
+ data.metrics.mcpToolCalls++;
5133
+ this.mcpMetrics.totalToolCalls++;
5134
+ this.mcpLatencies.push(latencyMs);
5135
+ if (this.mcpLatencies.length > this.MAX_LATENCY_SAMPLES) {
5136
+ this.mcpLatencies.shift();
5137
+ }
5138
+ data.metrics.avgMcpLatencyMs = this.calculateAverageLatency(this.mcpLatencies);
5139
+ this.mcpMetrics.avgToolCallLatencyMs = data.metrics.avgMcpLatencyMs;
5140
+ data.lastUpdated = Date.now();
5141
+ logger.debug("MCP tool call recorded", {
5142
+ provider: providerName,
5143
+ tool: toolName,
5144
+ latencyMs,
5145
+ success
5146
+ });
5147
+ }
5148
+ /**
5149
+ * Update circuit breaker state
5150
+ */
5151
+ updateCircuitBreakerState(providerName, state) {
5152
+ if (!this.isEnabled()) return;
5153
+ const data = this.getOrCreateProviderMetrics(providerName);
5154
+ const previousState = data.circuitBreakerState;
5155
+ data.circuitBreakerState = state;
5156
+ data.lastUpdated = Date.now();
5157
+ if (previousState !== state) {
5158
+ logger.info("Circuit breaker state changed", {
5159
+ provider: providerName,
5160
+ from: previousState,
5161
+ to: state
5162
+ });
5163
+ }
5164
+ }
5165
+ /**
5166
+ * Update execution mode
5167
+ */
5168
+ updateExecutionMode(providerName, mode) {
5169
+ if (!this.isEnabled()) return;
5170
+ const data = this.getOrCreateProviderMetrics(providerName);
5171
+ data.executionMode = mode;
5172
+ data.lastUpdated = Date.now();
5173
+ }
5174
+ /**
5175
+ * Get metrics for a specific provider
5176
+ */
5177
+ getProviderMetrics(providerName) {
5178
+ return this.providerMetrics.get(providerName);
5179
+ }
5180
+ /**
5181
+ * Get all provider metrics
5182
+ */
5183
+ getAllProviderMetrics() {
5184
+ return Array.from(this.providerMetrics.values());
5185
+ }
5186
+ /**
5187
+ * Get MCP session metrics
5188
+ */
5189
+ getMCPMetrics() {
5190
+ return { ...this.mcpMetrics };
5191
+ }
5192
+ /**
5193
+ * Get aggregated metrics summary
5194
+ */
5195
+ getMetricsSummary() {
5196
+ let totalSDK = 0;
5197
+ let totalCLI = 0;
5198
+ let totalFallbacks = 0;
5199
+ let sdkLatencySum = 0;
5200
+ let cliLatencySum = 0;
5201
+ let sdkCount = 0;
5202
+ let cliCount = 0;
5203
+ const openCircuitBreakers = [];
5204
+ for (const data of this.providerMetrics.values()) {
5205
+ totalSDK += data.metrics.sdkExecutions;
5206
+ totalCLI += data.metrics.cliExecutions;
5207
+ totalFallbacks += data.metrics.sdkFallbacks;
5208
+ if (data.metrics.avgSdkLatencyMs > 0) {
5209
+ sdkLatencySum += data.metrics.avgSdkLatencyMs;
5210
+ sdkCount++;
5211
+ }
5212
+ if (data.metrics.avgCliLatencyMs > 0) {
5213
+ cliLatencySum += data.metrics.avgCliLatencyMs;
5214
+ cliCount++;
5215
+ }
5216
+ if (data.circuitBreakerState === "open") {
5217
+ openCircuitBreakers.push(data.providerName);
5218
+ }
5219
+ }
5220
+ return {
5221
+ totalSDKExecutions: totalSDK,
5222
+ totalCLIExecutions: totalCLI,
5223
+ totalMCPConnections: this.mcpMetrics.totalConnections,
5224
+ overallFallbackRate: totalSDK > 0 ? totalFallbacks / totalSDK : 0,
5225
+ avgSDKLatencyMs: sdkCount > 0 ? sdkLatencySum / sdkCount : 0,
5226
+ avgCLILatencyMs: cliCount > 0 ? cliLatencySum / cliCount : 0,
5227
+ providersWithOpenCircuitBreaker: openCircuitBreakers
5228
+ };
5229
+ }
5230
+ /**
5231
+ * Reset all metrics (for testing)
5232
+ */
5233
+ reset() {
5234
+ this.providerMetrics.clear();
5235
+ this.sdkLatencies.clear();
5236
+ this.cliLatencies.clear();
5237
+ this.mcpLatencies = [];
5238
+ this.mcpMetrics = {
5239
+ totalConnections: 0,
5240
+ activeConnections: 0,
5241
+ failedConnections: 0,
5242
+ totalToolCalls: 0,
5243
+ avgToolCallLatencyMs: 0,
5244
+ sessionsByProvider: {}
5245
+ };
5246
+ }
5247
+ /**
5248
+ * Add latency sample to provider's latency array
5249
+ */
5250
+ addLatencySample(latencyMap, providerName, latencyMs) {
5251
+ if (!latencyMap.has(providerName)) {
5252
+ latencyMap.set(providerName, []);
5253
+ }
5254
+ const latencies = latencyMap.get(providerName);
5255
+ latencies.push(latencyMs);
5256
+ if (latencies.length > this.MAX_LATENCY_SAMPLES) {
5257
+ latencies.shift();
5258
+ }
5259
+ }
5260
+ /**
5261
+ * Calculate average latency from samples
5262
+ */
5263
+ calculateAverageLatency(latencies) {
5264
+ if (latencies.length === 0) return 0;
5265
+ const sum = latencies.reduce((a, b) => a + b, 0);
5266
+ return Math.round(sum / latencies.length);
5267
+ }
5268
+ /**
5269
+ * Calculate success rate
5270
+ */
5271
+ calculateSuccessRate(total, errors) {
5272
+ if (total === 0) return 1;
5273
+ return Math.max(0, (total - errors) / total);
5274
+ }
5275
+ };
5276
+ }
5277
+ });
5278
+
5279
+ // src/providers/hybrid-adapter-base.ts
5280
+ var DEFAULT_CIRCUIT_BREAKER_CONFIG, CircuitBreaker2, HybridAdapterBase;
5281
+ var init_hybrid_adapter_base = __esm({
5282
+ "src/providers/hybrid-adapter-base.ts"() {
5283
+ init_esm_shims();
5284
+ init_logger();
5285
+ init_flags();
5286
+ init_fallback_decision();
5287
+ init_provider_metrics();
5288
+ DEFAULT_CIRCUIT_BREAKER_CONFIG = {
5289
+ failureThreshold: 3,
5290
+ resetTimeout: 6e4,
5291
+ // 1 minute
5292
+ halfOpenSuccessThreshold: 2
5293
+ };
5294
+ CircuitBreaker2 = class {
5295
+ state = "closed";
5296
+ failures = 0;
5297
+ successes = 0;
5298
+ lastFailureTime = 0;
5299
+ config;
5300
+ constructor(config = {}) {
5301
+ this.config = { ...DEFAULT_CIRCUIT_BREAKER_CONFIG, ...config };
5302
+ }
5303
+ /**
5304
+ * Check if circuit is open (requests should not be attempted)
5305
+ */
5306
+ isOpen() {
5307
+ if (this.state === "open") {
5308
+ if (Date.now() - this.lastFailureTime >= this.config.resetTimeout) {
5309
+ this.state = "half-open";
5310
+ this.successes = 0;
5311
+ logger.debug("Circuit breaker transitioning to half-open");
5312
+ return false;
5313
+ }
5314
+ return true;
5315
+ }
5316
+ return false;
5317
+ }
5318
+ /**
5319
+ * Get current state
5320
+ */
5321
+ getState() {
5322
+ if (this.state === "open" && Date.now() - this.lastFailureTime >= this.config.resetTimeout) {
5323
+ this.state = "half-open";
5324
+ this.successes = 0;
5325
+ }
5326
+ return this.state;
5327
+ }
5328
+ /**
5329
+ * Record successful execution
5330
+ */
5331
+ recordSuccess() {
5332
+ if (this.state === "half-open") {
5333
+ this.successes++;
5334
+ if (this.successes >= this.config.halfOpenSuccessThreshold) {
5335
+ this.state = "closed";
5336
+ this.failures = 0;
5337
+ this.successes = 0;
5338
+ logger.debug("Circuit breaker closed after recovery");
5339
+ }
5340
+ } else if (this.state === "closed") {
5341
+ this.failures = 0;
5342
+ }
5343
+ }
5344
+ /**
5345
+ * Record failed execution
5346
+ */
5347
+ recordFailure() {
5348
+ this.failures++;
5349
+ this.lastFailureTime = Date.now();
5350
+ if (this.state === "half-open") {
5351
+ this.state = "open";
5352
+ logger.warn("Circuit breaker opened after half-open failure");
5353
+ } else if (this.failures >= this.config.failureThreshold) {
5354
+ this.state = "open";
5355
+ logger.warn("Circuit breaker opened after consecutive failures", {
5356
+ failures: this.failures,
5357
+ threshold: this.config.failureThreshold
5358
+ });
5359
+ }
5360
+ }
5361
+ /**
5362
+ * Reset circuit breaker to closed state
5363
+ */
5364
+ reset() {
5365
+ this.state = "closed";
5366
+ this.failures = 0;
5367
+ this.successes = 0;
5368
+ this.lastFailureTime = 0;
5369
+ }
5370
+ };
5371
+ HybridAdapterBase = class {
5372
+ mode;
5373
+ activeMode = null;
5374
+ providerName;
5375
+ sdkCircuitBreaker;
5376
+ cliCircuitBreaker;
5377
+ maxRetries;
5378
+ // Track initialization state
5379
+ sdkInitialized = false;
5380
+ cliInitialized = false;
5381
+ initPromise = null;
5382
+ constructor(options) {
5383
+ this.mode = options.mode || "auto";
5384
+ this.providerName = options.providerName;
5385
+ this.maxRetries = options.maxRetries ?? 1;
5386
+ this.sdkCircuitBreaker = new CircuitBreaker2(options.sdkCircuitBreaker);
5387
+ this.cliCircuitBreaker = new CircuitBreaker2(options.cliCircuitBreaker);
5388
+ logger.debug("HybridAdapterBase initialized", {
5389
+ provider: this.providerName,
5390
+ mode: this.mode,
5391
+ maxRetries: this.maxRetries
5392
+ });
5393
+ }
5394
+ /**
5395
+ * Execute a request using the appropriate mode
5396
+ *
5397
+ * Mode selection logic:
5398
+ * 1. If mode is 'cli' or SDK-first is disabled → use CLI directly
5399
+ * 2. If mode is 'sdk' → use SDK only (throw if unavailable)
5400
+ * 3. If mode is 'auto' → try SDK first, fallback to CLI
5401
+ */
5402
+ async execute(request) {
5403
+ await this.ensureInitialized();
5404
+ const useSDKFirst = this.shouldUseSDKFirst();
5405
+ if (!useSDKFirst || this.mode === "cli") {
5406
+ return this.executeWithCLI(request);
5407
+ }
5408
+ if (this.mode === "sdk") {
5409
+ return this.executeWithSDK(request);
5410
+ }
5411
+ return this.executeWithFallback(request);
5412
+ }
5413
+ /**
5414
+ * Execute with SDK-first and CLI fallback
5415
+ */
5416
+ async executeWithFallback(request) {
5417
+ if (this.sdkCircuitBreaker.isOpen()) {
5418
+ logger.debug("SDK circuit breaker is open, using CLI", {
5419
+ provider: this.providerName
5420
+ });
5421
+ return this.executeWithCLI(request);
5422
+ }
5423
+ const startTime = Date.now();
5424
+ let lastError;
5425
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
5426
+ try {
5427
+ const result = await this.executeViaSDK(request);
5428
+ this.sdkCircuitBreaker.recordSuccess();
5429
+ this.recordSDKMetrics(Date.now() - startTime, true);
5430
+ return result;
5431
+ } catch (error) {
5432
+ lastError = error;
5433
+ const classification = decideFallback(error, this.providerName);
5434
+ logger.debug("SDK execution failed", {
5435
+ provider: this.providerName,
5436
+ attempt: attempt + 1,
5437
+ decision: classification.decision,
5438
+ reason: classification.reason
5439
+ });
5440
+ if (classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt < this.maxRetries) {
5441
+ const delay = classification.retryDelayMs || 1e3;
5442
+ await this.sleep(delay);
5443
+ continue;
5444
+ }
5445
+ if (classification.decision === "use_cli" /* USE_CLI */ || classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt >= this.maxRetries) {
5446
+ this.sdkCircuitBreaker.recordFailure();
5447
+ this.recordSDKMetrics(Date.now() - startTime, false);
5448
+ this.recordFallbackMetrics(classification.reason || "max retries exceeded");
5449
+ if (isSDKFallbackEnabled()) {
5450
+ logger.info("Falling back to CLI execution", {
5451
+ provider: this.providerName,
5452
+ reason: classification.reason || "max retries exceeded"
5453
+ });
5454
+ return this.executeWithCLI(request);
5455
+ }
5456
+ }
5457
+ this.sdkCircuitBreaker.recordFailure();
5458
+ this.recordSDKMetrics(Date.now() - startTime, false);
5459
+ throw error;
5460
+ }
5461
+ }
5462
+ this.sdkCircuitBreaker.recordFailure();
5463
+ this.recordSDKMetrics(Date.now() - startTime, false);
5464
+ if (isSDKFallbackEnabled()) {
5465
+ this.recordFallbackMetrics("max retries exceeded");
5466
+ return this.executeWithCLI(request);
5467
+ }
5468
+ throw lastError || new Error(`SDK execution failed after ${this.maxRetries + 1} attempts`);
5469
+ }
5470
+ /**
5471
+ * Execute using SDK only
5472
+ */
5473
+ async executeWithSDK(request) {
5474
+ if (this.sdkCircuitBreaker.isOpen()) {
5475
+ throw new Error(`SDK circuit breaker is open for ${this.providerName}`);
5476
+ }
5477
+ const startTime = Date.now();
5478
+ try {
5479
+ const result = await this.executeViaSDK(request);
5480
+ this.sdkCircuitBreaker.recordSuccess();
5481
+ this.recordSDKMetrics(Date.now() - startTime, true);
5482
+ return result;
5483
+ } catch (error) {
5484
+ this.sdkCircuitBreaker.recordFailure();
5485
+ this.recordSDKMetrics(Date.now() - startTime, false);
5486
+ throw error;
5487
+ }
5488
+ }
5489
+ /**
5490
+ * Execute using CLI only
5491
+ */
5492
+ async executeWithCLI(request) {
5493
+ if (this.cliCircuitBreaker.isOpen()) {
5494
+ throw new Error(`CLI circuit breaker is open for ${this.providerName}`);
5495
+ }
5496
+ const startTime = Date.now();
5497
+ try {
5498
+ const result = await this.executeViaCLI(request);
5499
+ this.cliCircuitBreaker.recordSuccess();
5500
+ this.recordCLIMetrics(Date.now() - startTime, true);
5501
+ return result;
5502
+ } catch (error) {
5503
+ this.cliCircuitBreaker.recordFailure();
5504
+ this.recordCLIMetrics(Date.now() - startTime, false);
5505
+ throw error;
5506
+ }
5507
+ }
5508
+ /**
5509
+ * Check if SDK-first mode should be used
5510
+ */
5511
+ shouldUseSDKFirst() {
5512
+ if (!isSDKFirstModeEnabled()) {
5513
+ return false;
5514
+ }
5515
+ if (this.mode === "cli") {
5516
+ return false;
5517
+ }
5518
+ return true;
5519
+ }
5520
+ /**
5521
+ * Ensure adapters are initialized
5522
+ */
5523
+ async ensureInitialized() {
5524
+ if (this.initPromise) {
5525
+ return this.initPromise;
5526
+ }
5527
+ this.initPromise = this.initialize();
5528
+ return this.initPromise;
5529
+ }
5530
+ /**
5531
+ * Initialize adapters based on mode
5532
+ */
5533
+ async initialize() {
5534
+ const useSDKFirst = this.shouldUseSDKFirst();
5535
+ if (this.mode === "cli" || !useSDKFirst) {
5536
+ if (!this.cliInitialized) {
5537
+ const available = await this.isCLIAvailable();
5538
+ if (!available) {
5539
+ throw new Error(`CLI not available for ${this.providerName}`);
5540
+ }
5541
+ await this.initializeCLI();
5542
+ this.cliInitialized = true;
5543
+ this.activeMode = "cli";
5544
+ }
5545
+ return;
5546
+ }
5547
+ if (this.mode === "sdk") {
5548
+ if (!this.sdkInitialized) {
5549
+ const available = await this.isSDKAvailable();
5550
+ if (!available) {
5551
+ throw new Error(`SDK not available for ${this.providerName}`);
5552
+ }
5553
+ await this.initializeSDK();
5554
+ this.sdkInitialized = true;
5555
+ this.activeMode = "sdk";
5556
+ }
5557
+ return;
5558
+ }
5559
+ if (!this.sdkInitialized) {
5560
+ const sdkAvailable = await this.isSDKAvailable();
5561
+ if (sdkAvailable) {
5562
+ try {
5563
+ await this.initializeSDK();
5564
+ this.sdkInitialized = true;
5565
+ this.activeMode = "sdk";
5566
+ } catch (error) {
5567
+ logger.warn("SDK initialization failed, will use CLI", {
5568
+ provider: this.providerName,
5569
+ error: error instanceof Error ? error.message : String(error)
5570
+ });
5571
+ }
5572
+ }
5573
+ }
5574
+ if (!this.cliInitialized) {
5575
+ const cliAvailable = await this.isCLIAvailable();
5576
+ if (cliAvailable) {
5577
+ await this.initializeCLI();
5578
+ this.cliInitialized = true;
5579
+ if (!this.sdkInitialized) {
5580
+ this.activeMode = "cli";
5581
+ }
5582
+ } else if (!this.sdkInitialized) {
5583
+ throw new Error(`Neither SDK nor CLI available for ${this.providerName}`);
5584
+ }
5585
+ }
5586
+ }
5587
+ /**
5588
+ * Record SDK execution metrics
5589
+ */
5590
+ recordSDKMetrics(latencyMs, success) {
5591
+ try {
5592
+ const collector = getProviderMetrics();
5593
+ collector.recordSDKExecution(this.providerName, latencyMs, success);
5594
+ } catch {
5595
+ }
5596
+ }
5597
+ /**
5598
+ * Record CLI execution metrics
5599
+ */
5600
+ recordCLIMetrics(latencyMs, success) {
5601
+ try {
5602
+ const collector = getProviderMetrics();
5603
+ collector.recordCLIExecution(this.providerName, latencyMs, success);
5604
+ } catch {
5605
+ }
5606
+ }
5607
+ /**
5608
+ * Record fallback event metrics
5609
+ */
5610
+ recordFallbackMetrics(reason) {
5611
+ try {
5612
+ const collector = getProviderMetrics();
5613
+ collector.recordSDKFallback(this.providerName, reason);
5614
+ } catch {
5615
+ }
5616
+ }
5617
+ /**
5618
+ * Sleep utility
5619
+ */
5620
+ sleep(ms) {
5621
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
5622
+ }
5623
+ /**
5624
+ * Get current active mode
5625
+ */
5626
+ getActiveMode() {
5627
+ return this.activeMode;
5628
+ }
5629
+ /**
5630
+ * Get SDK circuit breaker state
5631
+ */
5632
+ getSDKCircuitBreakerState() {
5633
+ return this.sdkCircuitBreaker.getState();
5634
+ }
5635
+ /**
5636
+ * Get CLI circuit breaker state
5637
+ */
5638
+ getCLICircuitBreakerState() {
5639
+ return this.cliCircuitBreaker.getState();
5640
+ }
5641
+ /**
5642
+ * Reset both circuit breakers
5643
+ */
5644
+ resetCircuitBreakers() {
5645
+ this.sdkCircuitBreaker.reset();
5646
+ this.cliCircuitBreaker.reset();
5647
+ logger.debug("Circuit breakers reset", { provider: this.providerName });
5648
+ }
5649
+ /**
5650
+ * Clean up resources
5651
+ */
5652
+ async destroy() {
5653
+ await this.destroySDK();
5654
+ await this.destroyCLI();
5655
+ this.sdkInitialized = false;
5656
+ this.cliInitialized = false;
5657
+ this.activeMode = null;
5658
+ this.initPromise = null;
5659
+ }
5660
+ };
5661
+ }
5662
+ });
5663
+
5664
+ // src/integrations/ax-glm/types.ts
5665
+ function normalizeGLMModel(model) {
5666
+ return GLM_MODEL_MAPPING[model] || model;
5667
+ }
5668
+ var GLM_MODEL_MAPPING, GLM_DEFAULT_BASE_URL, GLM_DEFAULT_MODEL, GLM_DEFAULT_COMMAND;
5669
+ var init_types2 = __esm({
5670
+ "src/integrations/ax-glm/types.ts"() {
5671
+ init_esm_shims();
5672
+ GLM_MODEL_MAPPING = {
5673
+ "glm-4-plus": "glm-4.6",
5674
+ "glm-4v": "glm-4.5v",
5675
+ "glm-4-air": "glm-4-flash",
5676
+ "glm-4-airx": "glm-4-flash"
5677
+ };
5678
+ GLM_DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
5679
+ GLM_DEFAULT_MODEL = "glm-4";
5680
+ GLM_DEFAULT_COMMAND = "ax-glm";
5681
+ }
5682
+ });
5683
+
5684
+ // src/integrations/ax-glm/sdk-adapter.ts
5685
+ var GLMSdkAdapter;
5686
+ var init_sdk_adapter2 = __esm({
5687
+ "src/integrations/ax-glm/sdk-adapter.ts"() {
5688
+ init_esm_shims();
5689
+ init_logger();
5690
+ init_validation_limits();
5691
+ init_types2();
5692
+ GLMSdkAdapter = class {
5693
+ client = null;
5694
+ config;
5695
+ initialized = false;
5696
+ constructor(config = {}) {
5697
+ this.config = {
5698
+ apiKey: config.apiKey || process.env.ZAI_API_KEY || "",
5699
+ baseUrl: config.baseUrl || GLM_DEFAULT_BASE_URL,
5700
+ model: config.model || GLM_DEFAULT_MODEL,
5701
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
5702
+ };
5703
+ logger.debug("[GLM SDK] Adapter created", {
5704
+ model: this.config.model,
5705
+ baseUrl: this.config.baseUrl,
5706
+ hasApiKey: !!this.config.apiKey
5707
+ });
5708
+ }
5709
+ /**
5710
+ * Check if SDK is available (OpenAI package installed)
5711
+ */
5712
+ async isAvailable() {
5713
+ try {
5714
+ if (!this.config.apiKey) {
5715
+ logger.debug("[GLM SDK] No API key configured");
5716
+ return false;
5717
+ }
5718
+ await import('openai');
5719
+ return true;
5720
+ } catch (error) {
5721
+ logger.debug("[GLM SDK] OpenAI SDK not available", {
5722
+ error: error instanceof Error ? error.message : String(error)
5723
+ });
5724
+ return false;
5725
+ }
5726
+ }
5727
+ /**
5728
+ * Initialize the SDK client
5729
+ */
5730
+ async initialize() {
5731
+ if (this.initialized) {
5732
+ return;
5733
+ }
5734
+ try {
5735
+ const OpenAI = (await import('openai')).default;
5736
+ this.client = new OpenAI({
5737
+ apiKey: this.config.apiKey,
5738
+ baseURL: this.config.baseUrl,
5739
+ timeout: this.config.timeout
5740
+ });
5741
+ this.initialized = true;
5742
+ logger.debug("[GLM SDK] Client initialized", {
5743
+ model: this.config.model
5744
+ });
5745
+ } catch (error) {
5746
+ throw new Error(
5747
+ `Failed to initialize GLM SDK: ${error instanceof Error ? error.message : String(error)}`
5748
+ );
5749
+ }
5750
+ }
5751
+ /**
5752
+ * Execute a request using the GLM SDK
5753
+ */
5754
+ async execute(request) {
5755
+ if (!this.initialized) {
5756
+ await this.initialize();
5757
+ }
5758
+ const startTime = Date.now();
5759
+ try {
5760
+ const messages = [];
5761
+ if (request.systemPrompt) {
5762
+ messages.push({
5763
+ role: "system",
5764
+ content: request.systemPrompt
5765
+ });
5766
+ }
5767
+ messages.push({
5768
+ role: "user",
5769
+ content: request.prompt
5770
+ });
5771
+ const model = normalizeGLMModel(this.config.model);
5772
+ logger.debug("[GLM SDK] Executing request", {
5773
+ model,
5774
+ messageCount: messages.length,
5775
+ promptLength: request.prompt.length
5776
+ });
5777
+ const openaiClient = this.client;
5778
+ const response = await openaiClient.chat.completions.create({
5779
+ model,
5780
+ messages,
5781
+ max_tokens: request.maxTokens,
5782
+ temperature: request.temperature,
5783
+ stream: false
5784
+ });
5785
+ const latencyMs = Date.now() - startTime;
5786
+ if (!response.choices || response.choices.length === 0) {
5787
+ throw new Error("GLM API returned empty choices array");
5788
+ }
5789
+ const choice = response.choices[0];
5790
+ const content = choice?.message?.content || "";
5791
+ const finishReason = choice?.finish_reason || "unknown";
5792
+ logger.debug("[GLM SDK] Request completed", {
5793
+ model: response.model,
5794
+ latencyMs,
5795
+ tokensUsed: response.usage?.total_tokens
5796
+ });
5797
+ return {
5798
+ content,
5799
+ model: response.model,
5800
+ tokensUsed: response.usage ? {
5801
+ prompt: response.usage.prompt_tokens,
5802
+ completion: response.usage.completion_tokens,
5803
+ total: response.usage.total_tokens
5804
+ } : { prompt: 0, completion: 0, total: 0 },
5805
+ latencyMs,
5806
+ finishReason,
5807
+ cached: false
5808
+ };
5809
+ } catch (error) {
5810
+ const latencyMs = Date.now() - startTime;
5811
+ logger.error("[GLM SDK] Request failed", {
5812
+ error: error instanceof Error ? error.message : String(error),
5813
+ latencyMs
5814
+ });
5815
+ throw error;
5816
+ }
5817
+ }
5818
+ /**
5819
+ * Get the configured model
5820
+ */
5821
+ getModel() {
5822
+ return this.config.model;
5823
+ }
5824
+ /**
5825
+ * Clean up resources
5826
+ */
5827
+ async destroy() {
5828
+ this.client = null;
5829
+ this.initialized = false;
5830
+ logger.debug("[GLM SDK] Adapter destroyed");
5831
+ }
5832
+ };
5833
+ }
5834
+ });
5835
+ var execAsync, GLMCliWrapper;
5836
+ var init_cli_wrapper2 = __esm({
5837
+ "src/integrations/ax-glm/cli-wrapper.ts"() {
5838
+ init_esm_shims();
5839
+ init_logger();
5840
+ init_validation_limits();
5841
+ init_types2();
5842
+ execAsync = promisify(exec);
5843
+ GLMCliWrapper = class {
5844
+ config;
5845
+ cliPath = null;
5846
+ cliVersion = null;
5847
+ constructor(config = {}) {
5848
+ this.config = {
5849
+ command: config.command || GLM_DEFAULT_COMMAND,
5850
+ model: config.model || GLM_DEFAULT_MODEL,
5851
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
5852
+ };
5853
+ logger.debug("[GLM CLI] Wrapper created", {
5854
+ command: this.config.command,
5855
+ model: this.config.model
5856
+ });
5857
+ }
5858
+ /**
5859
+ * Check if CLI is available
5860
+ */
5861
+ async isAvailable() {
5862
+ try {
5863
+ const { stdout } = await execAsync(`which ${this.config.command}`, {
5864
+ timeout: TIMEOUTS.PROVIDER_DETECTION
5865
+ });
5866
+ this.cliPath = stdout.trim();
5867
+ if (this.cliPath) {
5868
+ try {
5869
+ const { stdout: versionOutput } = await execAsync(
5870
+ `${this.config.command} --version`,
5871
+ { timeout: TIMEOUTS.PROVIDER_DETECTION }
5872
+ );
5873
+ this.cliVersion = versionOutput.trim();
5874
+ } catch {
5875
+ this.cliVersion = "unknown";
5876
+ }
5877
+ logger.debug("[GLM CLI] CLI available", {
5878
+ path: this.cliPath,
5879
+ version: this.cliVersion
5880
+ });
5881
+ return true;
5882
+ }
5883
+ return false;
5884
+ } catch (error) {
5885
+ logger.debug("[GLM CLI] CLI not available", {
5886
+ error: error instanceof Error ? error.message : String(error)
5887
+ });
5888
+ return false;
5889
+ }
5890
+ }
5891
+ /**
5892
+ * Initialize the CLI wrapper
5893
+ */
5894
+ async initialize() {
5895
+ const available = await this.isAvailable();
5896
+ if (!available) {
5897
+ throw new Error(`${this.config.command} CLI is not installed or not in PATH`);
5898
+ }
5899
+ }
5900
+ /**
5901
+ * Execute a request using the CLI
5902
+ */
5903
+ async execute(request) {
5904
+ const startTime = Date.now();
5905
+ try {
5906
+ const args2 = this.buildArgs(request);
5907
+ logger.debug("[GLM CLI] Executing", {
5908
+ command: this.config.command,
5909
+ args: args2,
5910
+ promptLength: request.prompt.length
5911
+ });
5912
+ const result = await this.spawnCLI(args2, request.prompt);
5913
+ const latencyMs = Date.now() - startTime;
5914
+ const response = this.parseResponse(result);
5915
+ logger.debug("[GLM CLI] Request completed", {
5916
+ latencyMs,
5917
+ contentLength: response.content.length
5918
+ });
5919
+ return {
5920
+ ...response,
5921
+ latencyMs,
5922
+ cached: false
5923
+ };
5924
+ } catch (error) {
5925
+ const latencyMs = Date.now() - startTime;
5926
+ logger.error("[GLM CLI] Request failed", {
5927
+ error: error instanceof Error ? error.message : String(error),
5928
+ latencyMs
5929
+ });
5930
+ throw error;
5931
+ }
5932
+ }
5933
+ /**
5934
+ * Build CLI arguments
5935
+ */
5936
+ buildArgs(request) {
5937
+ const args2 = ["-p"];
5938
+ const model = normalizeGLMModel(this.config.model);
5939
+ if (model !== "glm-4") {
5940
+ args2.push("--model", model);
5941
+ }
5942
+ if (request.systemPrompt) {
5943
+ args2.push("--system", request.systemPrompt);
5944
+ }
5945
+ if (request.maxTokens) {
5946
+ args2.push("--max-tokens", String(request.maxTokens));
5947
+ }
5948
+ if (request.temperature !== void 0) {
5949
+ args2.push("--temperature", String(request.temperature));
5950
+ }
5951
+ return args2;
5952
+ }
5953
+ /**
5954
+ * Spawn CLI process and get output
5955
+ */
5956
+ spawnCLI(args2, prompt) {
5957
+ return new Promise((resolve5, reject) => {
5958
+ const process2 = spawn(this.config.command, args2, {
5959
+ stdio: ["pipe", "pipe", "pipe"],
5960
+ timeout: this.config.timeout
5961
+ });
5962
+ let stdout = "";
5963
+ let stderr = "";
5964
+ process2.stdout.on("data", (data) => {
5965
+ stdout += data.toString();
5966
+ });
5967
+ process2.stderr.on("data", (data) => {
5968
+ stderr += data.toString();
5969
+ });
5970
+ process2.on("error", (error) => {
5971
+ reject(new Error(`CLI process error: ${error.message}`));
5972
+ });
5973
+ process2.on("close", (code) => {
5974
+ if (code === 0) {
5975
+ resolve5(stdout);
5976
+ } else {
5977
+ reject(new Error(
5978
+ `CLI exited with code ${code}: ${stderr || "No error message"}`
5979
+ ));
5980
+ }
5981
+ });
5982
+ process2.stdin.write(prompt);
5983
+ process2.stdin.end();
5984
+ });
5985
+ }
5986
+ /**
5987
+ * Parse CLI response
5988
+ */
5989
+ parseResponse(output) {
5990
+ try {
5991
+ const parsed = JSON.parse(output.trim());
5992
+ if (parsed.content || parsed.message) {
5993
+ return {
5994
+ content: parsed.content || parsed.message || "",
5995
+ model: parsed.model || normalizeGLMModel(this.config.model),
5996
+ tokensUsed: parsed.usage ? {
5997
+ prompt: parsed.usage.prompt_tokens || 0,
5998
+ completion: parsed.usage.completion_tokens || 0,
5999
+ total: parsed.usage.total_tokens || 0
6000
+ } : { prompt: 0, completion: 0, total: 0 },
6001
+ finishReason: parsed.finish_reason || "stop"
6002
+ };
6003
+ }
6004
+ } catch {
6005
+ }
6006
+ return {
6007
+ content: output.trim(),
6008
+ model: normalizeGLMModel(this.config.model),
6009
+ tokensUsed: { prompt: 0, completion: 0, total: 0 },
6010
+ finishReason: "stop"
6011
+ };
6012
+ }
6013
+ /**
6014
+ * Get the configured model
6015
+ */
6016
+ getModel() {
6017
+ return this.config.model;
6018
+ }
6019
+ /**
6020
+ * Get CLI version
6021
+ */
6022
+ getVersion() {
6023
+ return this.cliVersion;
6024
+ }
6025
+ /**
6026
+ * Get CLI command
6027
+ */
6028
+ getCommand() {
6029
+ return this.config.command;
6030
+ }
6031
+ /**
6032
+ * Clean up resources
6033
+ */
6034
+ async destroy() {
6035
+ logger.debug("[GLM CLI] Wrapper destroyed");
6036
+ }
6037
+ };
6038
+ }
6039
+ });
6040
+
6041
+ // src/integrations/ax-glm/hybrid-adapter.ts
6042
+ var GLMHybridAdapter;
6043
+ var init_hybrid_adapter2 = __esm({
6044
+ "src/integrations/ax-glm/hybrid-adapter.ts"() {
6045
+ init_esm_shims();
6046
+ init_hybrid_adapter_base();
6047
+ init_sdk_adapter2();
6048
+ init_cli_wrapper2();
6049
+ init_types2();
6050
+ init_logger();
6051
+ GLMHybridAdapter = class extends HybridAdapterBase {
6052
+ sdkAdapter = null;
6053
+ cliWrapper = null;
6054
+ model;
6055
+ sdkConfig;
6056
+ cliConfig;
6057
+ constructor(options = {}) {
6058
+ const baseOptions = {
6059
+ mode: options.mode || "auto",
6060
+ providerName: "glm",
6061
+ maxRetries: options.maxRetries ?? 1
6062
+ };
6063
+ super(baseOptions);
6064
+ this.model = options.model || GLM_DEFAULT_MODEL;
6065
+ this.sdkConfig = {
6066
+ apiKey: options.apiKey,
6067
+ baseUrl: options.baseUrl,
6068
+ timeout: options.timeout
6069
+ };
6070
+ this.cliConfig = {
6071
+ command: options.command,
6072
+ timeout: options.timeout
6073
+ };
6074
+ logger.debug("[GLM Hybrid] Adapter created", {
6075
+ mode: this.mode,
6076
+ model: this.model
6077
+ });
6078
+ }
6079
+ /**
6080
+ * Execute request via SDK
6081
+ */
6082
+ async executeViaSDK(request) {
6083
+ if (!this.sdkAdapter) {
6084
+ throw new Error("GLM SDK adapter not initialized");
6085
+ }
6086
+ return this.sdkAdapter.execute(request);
6087
+ }
6088
+ /**
6089
+ * Execute request via CLI
6090
+ */
6091
+ async executeViaCLI(request) {
6092
+ if (!this.cliWrapper) {
6093
+ throw new Error("GLM CLI wrapper not initialized");
6094
+ }
6095
+ return this.cliWrapper.execute(request);
6096
+ }
6097
+ /**
6098
+ * Check if SDK is available
6099
+ */
6100
+ async isSDKAvailable() {
6101
+ try {
6102
+ const adapter = new GLMSdkAdapter({
6103
+ ...this.sdkConfig,
6104
+ model: this.model
6105
+ });
6106
+ const available = await adapter.isAvailable();
6107
+ if (!available) {
6108
+ return false;
6109
+ }
6110
+ this.sdkAdapter = adapter;
6111
+ return true;
6112
+ } catch (error) {
6113
+ logger.debug("[GLM Hybrid] SDK availability check failed", {
6114
+ error: error instanceof Error ? error.message : String(error)
6115
+ });
6116
+ return false;
6117
+ }
6118
+ }
6119
+ /**
6120
+ * Check if CLI is available
6121
+ */
6122
+ async isCLIAvailable() {
6123
+ try {
6124
+ const wrapper = new GLMCliWrapper({
6125
+ ...this.cliConfig,
6126
+ model: this.model
6127
+ });
6128
+ const available = await wrapper.isAvailable();
6129
+ if (!available) {
6130
+ return false;
6131
+ }
6132
+ this.cliWrapper = wrapper;
6133
+ return true;
6134
+ } catch (error) {
6135
+ logger.debug("[GLM Hybrid] CLI availability check failed", {
6136
+ error: error instanceof Error ? error.message : String(error)
6137
+ });
6138
+ return false;
6139
+ }
6140
+ }
6141
+ /**
6142
+ * Initialize SDK adapter
6143
+ */
6144
+ async initializeSDK() {
6145
+ if (!this.sdkAdapter) {
6146
+ this.sdkAdapter = new GLMSdkAdapter({
6147
+ ...this.sdkConfig,
6148
+ model: this.model
6149
+ });
6150
+ }
6151
+ await this.sdkAdapter.initialize();
6152
+ logger.debug("[GLM Hybrid] SDK initialized", {
6153
+ model: this.model
6154
+ });
6155
+ }
6156
+ /**
6157
+ * Initialize CLI wrapper
6158
+ */
6159
+ async initializeCLI() {
6160
+ if (!this.cliWrapper) {
6161
+ this.cliWrapper = new GLMCliWrapper({
6162
+ ...this.cliConfig,
6163
+ model: this.model
6164
+ });
6165
+ }
6166
+ await this.cliWrapper.initialize();
6167
+ logger.debug("[GLM Hybrid] CLI initialized", {
6168
+ model: this.model,
6169
+ version: this.cliWrapper.getVersion()
6170
+ });
6171
+ }
6172
+ /**
6173
+ * Clean up SDK resources
6174
+ */
6175
+ async destroySDK() {
6176
+ if (this.sdkAdapter) {
6177
+ await this.sdkAdapter.destroy();
6178
+ this.sdkAdapter = null;
6179
+ }
6180
+ }
6181
+ /**
6182
+ * Clean up CLI resources
6183
+ */
6184
+ async destroyCLI() {
6185
+ if (this.cliWrapper) {
6186
+ await this.cliWrapper.destroy();
6187
+ this.cliWrapper = null;
6188
+ }
6189
+ }
6190
+ /**
6191
+ * Get the configured model
6192
+ */
6193
+ getModel() {
6194
+ return this.model;
6195
+ }
6196
+ /**
6197
+ * Get the CLI command being used
6198
+ */
6199
+ getCommand() {
6200
+ return this.cliWrapper?.getCommand() || this.cliConfig.command || "ax-glm";
6201
+ }
6202
+ /**
6203
+ * Get CLI version
6204
+ */
6205
+ getCLIVersion() {
6206
+ return this.cliWrapper?.getVersion() || null;
6207
+ }
6208
+ };
6209
+ }
6210
+ });
6211
+
6212
+ // src/integrations/ax-glm/sdk-only-adapter.ts
6213
+ var GLMSdkOnlyAdapter;
6214
+ var init_sdk_only_adapter = __esm({
6215
+ "src/integrations/ax-glm/sdk-only-adapter.ts"() {
6216
+ init_esm_shims();
6217
+ init_logger();
6218
+ init_sdk_adapter2();
6219
+ init_types2();
6220
+ GLMSdkOnlyAdapter = class {
6221
+ sdkAdapter;
6222
+ initialized = false;
6223
+ model;
6224
+ maxRetries;
6225
+ retryDelayMs;
6226
+ constructor(options = {}) {
6227
+ this.model = options.model || GLM_DEFAULT_MODEL;
6228
+ this.maxRetries = options.maxRetries ?? 2;
6229
+ this.retryDelayMs = options.retryDelayMs ?? 1e3;
6230
+ this.sdkAdapter = new GLMSdkAdapter({
6231
+ model: this.model,
6232
+ apiKey: options.apiKey,
6233
+ baseUrl: options.baseUrl,
6234
+ timeout: options.timeout
6235
+ });
6236
+ logger.debug("[GLM SDK-Only] Adapter created", {
6237
+ model: this.model,
6238
+ maxRetries: this.maxRetries
6239
+ });
6240
+ }
6241
+ /**
6242
+ * Check if SDK is available
6243
+ */
6244
+ async isAvailable() {
6245
+ return this.sdkAdapter.isAvailable();
6246
+ }
6247
+ /**
6248
+ * Initialize the adapter
6249
+ */
6250
+ async initialize() {
6251
+ if (this.initialized) {
6252
+ return;
6253
+ }
6254
+ const available = await this.sdkAdapter.isAvailable();
6255
+ if (!available) {
6256
+ throw new Error("GLM SDK not available - check API key and openai package");
6257
+ }
6258
+ await this.sdkAdapter.initialize();
6259
+ this.initialized = true;
6260
+ logger.debug("[GLM SDK-Only] Initialized", { model: this.model });
6261
+ }
6262
+ /**
6263
+ * Execute a request using GLM SDK
6264
+ *
6265
+ * Retries transient errors up to maxRetries times with exponential backoff.
6266
+ * Does NOT fall back to CLI - throws on persistent failure.
6267
+ */
6268
+ async execute(request) {
6269
+ if (!this.initialized) {
6270
+ await this.initialize();
6271
+ }
6272
+ const startTime = Date.now();
6273
+ let lastError;
6274
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
6275
+ try {
6276
+ const response = await this.sdkAdapter.execute(request);
6277
+ logger.debug("[GLM SDK-Only] Execution succeeded", {
6278
+ model: this.model,
6279
+ attempt: attempt + 1,
6280
+ latencyMs: response.latencyMs
6281
+ });
6282
+ return response;
6283
+ } catch (error) {
6284
+ lastError = error;
6285
+ logger.warn("[GLM SDK-Only] Execution failed", {
6286
+ model: this.model,
6287
+ attempt: attempt + 1,
6288
+ maxRetries: this.maxRetries,
6289
+ error: lastError.message
6290
+ });
6291
+ if (attempt < this.maxRetries && this.isRetryableError(lastError)) {
6292
+ const delay = this.retryDelayMs * Math.pow(2, attempt);
6293
+ logger.debug("[GLM SDK-Only] Retrying after delay", {
6294
+ attempt: attempt + 1,
6295
+ delayMs: delay
6296
+ });
6297
+ await this.sleep(delay);
6298
+ continue;
6299
+ }
6300
+ break;
6301
+ }
6302
+ }
6303
+ const totalTime = Date.now() - startTime;
6304
+ logger.error("[GLM SDK-Only] All retries exhausted", {
6305
+ model: this.model,
6306
+ totalAttempts: this.maxRetries + 1,
6307
+ totalTimeMs: totalTime,
6308
+ lastError: lastError?.message
6309
+ });
6310
+ throw new Error(
6311
+ `GLM SDK execution failed after ${this.maxRetries + 1} attempts: ${lastError?.message || "Unknown error"}`
6312
+ );
6313
+ }
6314
+ /**
6315
+ * Check if error is retryable
6316
+ */
6317
+ isRetryableError(error) {
6318
+ const message = error.message.toLowerCase();
6319
+ if (message.includes("rate limit") || message.includes("429")) {
6320
+ return true;
6321
+ }
6322
+ if (message.includes("500") || message.includes("502") || message.includes("503") || message.includes("504")) {
6323
+ return true;
6324
+ }
6325
+ if (message.includes("timeout") || message.includes("etimedout")) {
6326
+ return true;
6327
+ }
6328
+ if (message.includes("econnreset") || message.includes("econnrefused")) {
6329
+ return true;
6330
+ }
6331
+ return false;
6332
+ }
6333
+ /**
6334
+ * Sleep utility
6335
+ */
6336
+ sleep(ms) {
6337
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
6338
+ }
6339
+ /**
6340
+ * Get the configured model
6341
+ */
6342
+ getModel() {
6343
+ return this.model;
6344
+ }
6345
+ /**
6346
+ * Clean up resources
6347
+ */
6348
+ async destroy() {
6349
+ await this.sdkAdapter.destroy();
6350
+ this.initialized = false;
6351
+ logger.debug("[GLM SDK-Only] Adapter destroyed");
6352
+ }
6353
+ };
6354
+ }
6355
+ });
6356
+
6357
+ // src/integrations/ax-glm/mcp-client-mode.ts
6358
+ var init_mcp_client_mode = __esm({
6359
+ "src/integrations/ax-glm/mcp-client-mode.ts"() {
6360
+ init_esm_shims();
6361
+ init_logger();
6362
+ init_sdk_adapter2();
6363
+ }
6364
+ });
6365
+
6366
+ // src/integrations/ax-glm/index.ts
6367
+ var init_ax_glm = __esm({
6368
+ "src/integrations/ax-glm/index.ts"() {
6369
+ init_esm_shims();
6370
+ init_hybrid_adapter2();
6371
+ init_sdk_adapter2();
6372
+ init_cli_wrapper2();
6373
+ init_sdk_only_adapter();
6374
+ init_mcp_client_mode();
6375
+ init_types2();
6376
+ }
6377
+ });
6378
+
6379
+ // src/providers/glm-provider.ts
6380
+ var glm_provider_exports = {};
6381
+ __export(glm_provider_exports, {
6382
+ GLMProvider: () => GLMProvider,
6383
+ default: () => GLMProvider
6384
+ });
6385
+ var MODEL_MAPPING, GLMProvider;
6386
+ var init_glm_provider = __esm({
6387
+ "src/providers/glm-provider.ts"() {
6388
+ init_esm_shims();
6389
+ init_base_provider();
6390
+ init_logger();
6391
+ init_ax_glm();
6392
+ MODEL_MAPPING = {
6393
+ "glm-4-plus": "glm-4.6",
6394
+ "glm-4v": "glm-4.5v",
6395
+ "glm-4-air": "glm-4-flash",
6396
+ "glm-4-airx": "glm-4-flash"
6397
+ };
6398
+ GLMProvider = class _GLMProvider extends BaseProvider {
6399
+ /** Selected model */
6400
+ model;
6401
+ /** SDK-only adapter for direct execution (v13.0.0) */
6402
+ sdkOnlyAdapter = null;
6403
+ /** Legacy hybrid adapter for 'auto' mode (backwards compatibility) */
6404
+ hybridAdapter = null;
6405
+ /** Provider configuration */
6406
+ glmConfig;
6407
+ /** Supported models */
6408
+ static SUPPORTED_MODELS = [
6409
+ "glm-4.6",
6410
+ "glm-4.5v",
6411
+ "glm-4",
6412
+ "glm-4-flash",
6413
+ // Legacy aliases
6414
+ "glm-4-plus",
6415
+ "glm-4v",
6416
+ "glm-4-air",
6417
+ "glm-4-airx"
6418
+ ];
6419
+ constructor(config) {
6420
+ super({
6421
+ ...config,
6422
+ command: "ax-glm"
6423
+ });
6424
+ this.glmConfig = config;
6425
+ const requestedModel = config.model || "glm-4";
6426
+ if (!_GLMProvider.SUPPORTED_MODELS.includes(requestedModel)) {
6427
+ logger.warn(`[GLM] Unknown model: ${requestedModel}. Using glm-4.`);
6428
+ this.model = "glm-4";
6429
+ } else {
6430
+ this.model = requestedModel;
6431
+ }
6432
+ logger.debug("[GLM Provider] Initialized", {
6433
+ model: this.model,
6434
+ mode: config.mode || "auto"
6435
+ });
6436
+ }
6437
+ /**
6438
+ * Get the normalized model name
6439
+ */
6440
+ getNormalizedModel() {
6441
+ return MODEL_MAPPING[this.model] || this.model;
6442
+ }
6443
+ /**
6444
+ * Get or create SDK-only adapter (v13.0.0 default)
6445
+ */
6446
+ getSdkOnlyAdapter() {
6447
+ if (!this.sdkOnlyAdapter) {
6448
+ this.sdkOnlyAdapter = new GLMSdkOnlyAdapter({
6449
+ model: this.model,
6450
+ apiKey: this.glmConfig.apiKey,
6451
+ baseUrl: this.glmConfig.baseUrl,
6452
+ timeout: this.glmConfig.timeout
6453
+ });
6454
+ }
6455
+ return this.sdkOnlyAdapter;
6456
+ }
6457
+ /**
6458
+ * Get or create hybrid adapter (legacy, for 'auto' mode only)
6459
+ */
6460
+ getHybridAdapter() {
6461
+ if (!this.hybridAdapter) {
6462
+ const options = {
6463
+ mode: this.glmConfig.mode || "auto",
6464
+ model: this.model,
6465
+ apiKey: this.glmConfig.apiKey,
6466
+ baseUrl: this.glmConfig.baseUrl,
6467
+ command: "ax-glm",
6468
+ timeout: this.glmConfig.timeout
6469
+ };
6470
+ this.hybridAdapter = new GLMHybridAdapter(options);
6471
+ }
6472
+ return this.hybridAdapter;
6473
+ }
6474
+ /**
6475
+ * Execute a task using GLM
6476
+ *
6477
+ * Execution flow (v13.0.0):
6478
+ * 1. Mock mode → return mock response
6479
+ * 2. mode='sdk' (default) → use SDK-only adapter (NO CLI fallback)
6480
+ * 3. mode='auto' (legacy) → use hybrid adapter (SDK with CLI fallback)
6481
+ * 4. mode='cli' → use CLI via BaseProvider (deprecated for GLM)
6482
+ */
6483
+ async execute(request) {
6484
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
6485
+ return this.createMockResponse(request.prompt);
6486
+ }
6487
+ const effectiveMode = this.glmConfig.mode || "sdk";
6488
+ if (effectiveMode === "cli") {
6489
+ logger.warn("[GLM Provider] CLI mode is deprecated for GLM. Consider using SDK mode.", {
6490
+ model: this.model
6491
+ });
6492
+ return super.execute(request);
6493
+ }
6494
+ if (effectiveMode === "auto") {
6495
+ logger.debug("[GLM Provider] Executing via hybrid adapter (legacy auto mode)", {
6496
+ promptLength: request.prompt.length,
6497
+ model: this.model
6498
+ });
6499
+ const adapter2 = this.getHybridAdapter();
6500
+ return adapter2.execute(request);
6501
+ }
6502
+ logger.debug("[GLM Provider] Executing via SDK-only adapter", {
6503
+ promptLength: request.prompt.length,
6504
+ model: this.model
6505
+ });
6506
+ const adapter = this.getSdkOnlyAdapter();
6507
+ return adapter.execute(request);
6508
+ }
6509
+ /**
6510
+ * Get CLI command
6511
+ */
6512
+ getCLICommand() {
6513
+ const adapter = this.hybridAdapter;
6514
+ if (adapter) {
6515
+ const activeMode = adapter.getActiveMode();
6516
+ if (activeMode === "sdk") {
6517
+ return "glm-sdk";
6518
+ }
6519
+ }
6520
+ return "ax-glm";
6521
+ }
6522
+ /**
6523
+ * Get CLI arguments for ax-glm headless mode
6524
+ */
6525
+ getCLIArgs() {
6526
+ const args2 = ["-p"];
6527
+ const normalizedModel = this.getNormalizedModel();
6528
+ if (normalizedModel !== "glm-4") {
6529
+ args2.push("--model", normalizedModel);
6530
+ }
6531
+ return args2;
6532
+ }
6533
+ /**
6534
+ * Create mock response for testing
6535
+ */
6536
+ createMockResponse(prompt) {
6537
+ return {
6538
+ content: this.getMockResponse(),
6539
+ model: this.getNormalizedModel(),
6540
+ tokensUsed: {
6541
+ prompt: this.estimateTokens(prompt),
6542
+ completion: 50,
6543
+ total: this.estimateTokens(prompt) + 50
6544
+ },
6545
+ latencyMs: 10,
6546
+ finishReason: "stop",
6547
+ cached: false
6548
+ };
6549
+ }
6550
+ /**
6551
+ * Estimate token count
6552
+ */
6553
+ estimateTokens(text) {
6554
+ return Math.ceil(text.length / 4);
6555
+ }
6556
+ /**
6557
+ * Get mock response for testing
6558
+ */
6559
+ getMockResponse() {
6560
+ return `[Mock GLM Response]
6561
+
6562
+ This is a mock response from the GLM provider (${this.getNormalizedModel()}).
6563
+ In production, this would be a response from ${this.glmConfig.mode === "sdk" ? "GLM SDK" : "ax-glm CLI"}.
6564
+
6565
+ Model: ${this.getNormalizedModel()}
6566
+ Provider: GLM (Zhipu AI)
6567
+ Mode: ${this.glmConfig.mode || "auto"}`;
6568
+ }
6569
+ /**
6570
+ * Get provider capabilities
6571
+ */
6572
+ get capabilities() {
6573
+ const model = this.getNormalizedModel();
6574
+ const isVision = model.includes("v") || model === "glm-4.5v";
6575
+ let maxContextTokens = 128e3;
6576
+ if (model === "glm-4.6") maxContextTokens = 2e5;
6577
+ if (model === "glm-4.5v") maxContextTokens = 64e3;
6578
+ const activeMode = this.hybridAdapter?.getActiveMode();
6579
+ const integrationMode = activeMode === "sdk" ? "sdk" : "cli";
6580
+ return {
6581
+ ...super.capabilities,
6582
+ supportsStreaming: true,
6583
+ supportsVision: isVision,
6584
+ maxContextTokens,
6585
+ supportedModels: _GLMProvider.SUPPORTED_MODELS,
6586
+ integrationMode
6587
+ };
6588
+ }
6589
+ /**
6590
+ * Get the active execution mode
6591
+ */
6592
+ getActiveMode() {
6593
+ return this.hybridAdapter?.getActiveMode() || null;
6594
+ }
6595
+ /**
6596
+ * Reset circuit breakers
6597
+ */
6598
+ resetCircuitBreakers() {
6599
+ this.hybridAdapter?.resetCircuitBreakers();
6600
+ }
6601
+ /**
6602
+ * Clean up resources
6603
+ */
6604
+ async destroy() {
6605
+ if (this.sdkOnlyAdapter) {
6606
+ await this.sdkOnlyAdapter.destroy();
6607
+ this.sdkOnlyAdapter = null;
6608
+ }
6609
+ if (this.hybridAdapter) {
6610
+ await this.hybridAdapter.destroy();
6611
+ this.hybridAdapter = null;
6612
+ }
6613
+ }
6614
+ /**
6615
+ * Get the list of supported models
6616
+ */
6617
+ static getSupportedModels() {
6618
+ return [..._GLMProvider.SUPPORTED_MODELS];
6619
+ }
6620
+ };
6621
+ }
6622
+ });
6623
+
6624
+ // src/integrations/ax-grok/types.ts
6625
+ function normalizeGrokModel(model) {
6626
+ return GROK_MODEL_MAPPING[model] || model;
6627
+ }
6628
+ var GROK_MODEL_MAPPING, GROK_DEFAULT_BASE_URL, GROK_DEFAULT_MODEL, GROK_DEFAULT_COMMAND;
6629
+ var init_types3 = __esm({
6630
+ "src/integrations/ax-grok/types.ts"() {
6631
+ init_esm_shims();
6632
+ GROK_MODEL_MAPPING = {
6633
+ "grok-beta": "grok-3"
6634
+ };
6635
+ GROK_DEFAULT_BASE_URL = "https://api.x.ai/v1";
6636
+ GROK_DEFAULT_MODEL = "grok-3";
6637
+ GROK_DEFAULT_COMMAND = "ax-grok";
6638
+ }
6639
+ });
6640
+
6641
+ // src/integrations/ax-grok/sdk-adapter.ts
6642
+ var GrokSdkAdapter;
6643
+ var init_sdk_adapter3 = __esm({
6644
+ "src/integrations/ax-grok/sdk-adapter.ts"() {
6645
+ init_esm_shims();
6646
+ init_logger();
6647
+ init_validation_limits();
6648
+ init_types3();
6649
+ GrokSdkAdapter = class {
6650
+ client = null;
6651
+ config;
6652
+ initialized = false;
6653
+ constructor(config = {}) {
6654
+ this.config = {
6655
+ apiKey: config.apiKey || process.env.XAI_API_KEY || "",
6656
+ baseUrl: config.baseUrl || GROK_DEFAULT_BASE_URL,
6657
+ model: config.model || GROK_DEFAULT_MODEL,
6658
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
6659
+ };
6660
+ logger.debug("[Grok SDK] Adapter created", {
6661
+ model: this.config.model,
6662
+ baseUrl: this.config.baseUrl,
6663
+ hasApiKey: !!this.config.apiKey
6664
+ });
6665
+ }
6666
+ /**
6667
+ * Check if SDK is available (OpenAI package installed and API key present)
6668
+ */
6669
+ async isAvailable() {
6670
+ try {
6671
+ if (!this.config.apiKey) {
6672
+ logger.debug("[Grok SDK] No API key configured");
6673
+ return false;
6674
+ }
6675
+ await import('openai');
6676
+ return true;
6677
+ } catch (error) {
6678
+ logger.debug("[Grok SDK] OpenAI SDK not available", {
6679
+ error: error instanceof Error ? error.message : String(error)
6680
+ });
6681
+ return false;
6682
+ }
6683
+ }
6684
+ /**
6685
+ * Initialize the SDK client
6686
+ */
6687
+ async initialize() {
6688
+ if (this.initialized) {
6689
+ return;
6690
+ }
6691
+ try {
6692
+ const OpenAI = (await import('openai')).default;
6693
+ this.client = new OpenAI({
6694
+ apiKey: this.config.apiKey,
6695
+ baseURL: this.config.baseUrl,
6696
+ timeout: this.config.timeout
6697
+ });
6698
+ this.initialized = true;
6699
+ logger.debug("[Grok SDK] Client initialized", {
6700
+ model: this.config.model
6701
+ });
6702
+ } catch (error) {
6703
+ throw new Error(
6704
+ `Failed to initialize Grok SDK: ${error instanceof Error ? error.message : String(error)}`
6705
+ );
6706
+ }
6707
+ }
6708
+ /**
6709
+ * Execute a request using the Grok SDK
6710
+ */
6711
+ async execute(request) {
6712
+ if (!this.initialized) {
6713
+ await this.initialize();
6714
+ }
6715
+ const startTime = Date.now();
6716
+ try {
6717
+ const messages = [];
6718
+ if (request.systemPrompt) {
6719
+ messages.push({
6720
+ role: "system",
6721
+ content: request.systemPrompt
6722
+ });
6723
+ }
6724
+ messages.push({
6725
+ role: "user",
6726
+ content: request.prompt
6727
+ });
6728
+ const model = normalizeGrokModel(this.config.model);
6729
+ logger.debug("[Grok SDK] Executing request", {
6730
+ model,
6731
+ messageCount: messages.length,
6732
+ promptLength: request.prompt.length
6733
+ });
6734
+ const openaiClient = this.client;
6735
+ const response = await openaiClient.chat.completions.create({
6736
+ model,
6737
+ messages,
6738
+ max_tokens: request.maxTokens,
6739
+ temperature: request.temperature,
6740
+ stream: false
6741
+ });
6742
+ const latencyMs = Date.now() - startTime;
6743
+ if (!response.choices || response.choices.length === 0) {
6744
+ throw new Error("Grok API returned empty choices array");
6745
+ }
6746
+ const choice = response.choices[0];
6747
+ const content = choice?.message?.content || "";
6748
+ const finishReason = choice?.finish_reason || "unknown";
6749
+ logger.debug("[Grok SDK] Request completed", {
6750
+ model: response.model,
6751
+ latencyMs,
6752
+ tokensUsed: response.usage?.total_tokens
6753
+ });
6754
+ return {
6755
+ content,
6756
+ model: response.model,
6757
+ tokensUsed: response.usage ? {
6758
+ prompt: response.usage.prompt_tokens,
6759
+ completion: response.usage.completion_tokens,
6760
+ total: response.usage.total_tokens
6761
+ } : { prompt: 0, completion: 0, total: 0 },
6762
+ latencyMs,
6763
+ finishReason,
6764
+ cached: false
6765
+ };
6766
+ } catch (error) {
6767
+ const latencyMs = Date.now() - startTime;
6768
+ logger.error("[Grok SDK] Request failed", {
6769
+ error: error instanceof Error ? error.message : String(error),
6770
+ latencyMs
6771
+ });
6772
+ throw error;
6773
+ }
6774
+ }
6775
+ /**
6776
+ * Get the configured model
6777
+ */
6778
+ getModel() {
6779
+ return this.config.model;
6780
+ }
6781
+ /**
6782
+ * Clean up resources
6783
+ */
6784
+ async destroy() {
6785
+ this.client = null;
6786
+ this.initialized = false;
6787
+ logger.debug("[Grok SDK] Adapter destroyed");
6788
+ }
6789
+ };
6790
+ }
6791
+ });
6792
+ var execAsync2, GrokCliWrapper;
6793
+ var init_cli_wrapper3 = __esm({
6794
+ "src/integrations/ax-grok/cli-wrapper.ts"() {
6795
+ init_esm_shims();
6796
+ init_logger();
6797
+ init_validation_limits();
6798
+ init_types3();
6799
+ execAsync2 = promisify(exec);
6800
+ GrokCliWrapper = class {
6801
+ config;
6802
+ cliPath = null;
6803
+ cliVersion = null;
6804
+ constructor(config = {}) {
6805
+ this.config = {
6806
+ command: config.command || GROK_DEFAULT_COMMAND,
6807
+ model: config.model || GROK_DEFAULT_MODEL,
6808
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
6809
+ };
6810
+ logger.debug("[Grok CLI] Wrapper created", {
6811
+ command: this.config.command,
6812
+ model: this.config.model
6813
+ });
6814
+ }
6815
+ /**
6816
+ * Check if CLI is available
6817
+ */
6818
+ async isAvailable() {
6819
+ try {
6820
+ const { stdout } = await execAsync2(`which ${this.config.command}`, {
6821
+ timeout: TIMEOUTS.PROVIDER_DETECTION
6822
+ });
6823
+ this.cliPath = stdout.trim();
6824
+ if (this.cliPath) {
6825
+ try {
6826
+ const { stdout: versionOutput } = await execAsync2(
6827
+ `${this.config.command} --version`,
6828
+ { timeout: TIMEOUTS.PROVIDER_DETECTION }
6829
+ );
6830
+ this.cliVersion = versionOutput.trim();
6831
+ } catch {
6832
+ this.cliVersion = "unknown";
6833
+ }
6834
+ logger.debug("[Grok CLI] CLI available", {
6835
+ path: this.cliPath,
6836
+ version: this.cliVersion
6837
+ });
6838
+ return true;
6839
+ }
6840
+ return false;
6841
+ } catch (error) {
6842
+ logger.debug("[Grok CLI] CLI not available", {
6843
+ error: error instanceof Error ? error.message : String(error)
6844
+ });
6845
+ return false;
6846
+ }
6847
+ }
6848
+ /**
6849
+ * Initialize the CLI wrapper
6850
+ */
6851
+ async initialize() {
6852
+ const available = await this.isAvailable();
6853
+ if (!available) {
6854
+ throw new Error(`${this.config.command} CLI is not installed or not in PATH`);
6855
+ }
6856
+ }
6857
+ /**
6858
+ * Execute a request using the CLI
6859
+ */
6860
+ async execute(request) {
6861
+ const startTime = Date.now();
6862
+ try {
6863
+ const args2 = this.buildArgs(request);
6864
+ logger.debug("[Grok CLI] Executing", {
6865
+ command: this.config.command,
6866
+ args: args2,
6867
+ promptLength: request.prompt.length
6868
+ });
6869
+ const result = await this.spawnCLI(args2, request.prompt);
6870
+ const latencyMs = Date.now() - startTime;
6871
+ const response = this.parseResponse(result);
6872
+ logger.debug("[Grok CLI] Request completed", {
6873
+ latencyMs,
6874
+ contentLength: response.content.length
6875
+ });
6876
+ return {
6877
+ ...response,
6878
+ latencyMs,
6879
+ cached: false
6880
+ };
6881
+ } catch (error) {
6882
+ const latencyMs = Date.now() - startTime;
6883
+ logger.error("[Grok CLI] Request failed", {
6884
+ error: error instanceof Error ? error.message : String(error),
6885
+ latencyMs
6886
+ });
6887
+ throw error;
6888
+ }
6889
+ }
6890
+ /**
6891
+ * Build CLI arguments
6892
+ */
6893
+ buildArgs(request) {
6894
+ const args2 = ["-p"];
6895
+ const model = normalizeGrokModel(this.config.model);
6896
+ if (model !== "grok-3") {
6897
+ args2.push("--model", model);
6898
+ }
6899
+ if (request.systemPrompt) {
6900
+ args2.push("--system", request.systemPrompt);
6901
+ }
6902
+ if (request.maxTokens) {
6903
+ args2.push("--max-tokens", String(request.maxTokens));
6904
+ }
6905
+ if (request.temperature !== void 0) {
6906
+ args2.push("--temperature", String(request.temperature));
6907
+ }
6908
+ return args2;
6909
+ }
6910
+ /**
6911
+ * Spawn CLI process and get output
6912
+ */
6913
+ spawnCLI(args2, prompt) {
6914
+ return new Promise((resolve5, reject) => {
6915
+ const process2 = spawn(this.config.command, args2, {
6916
+ stdio: ["pipe", "pipe", "pipe"],
6917
+ timeout: this.config.timeout
6918
+ });
6919
+ let stdout = "";
6920
+ let stderr = "";
6921
+ process2.stdout.on("data", (data) => {
6922
+ stdout += data.toString();
6923
+ });
6924
+ process2.stderr.on("data", (data) => {
6925
+ stderr += data.toString();
6926
+ });
6927
+ process2.on("error", (error) => {
6928
+ reject(new Error(`CLI process error: ${error.message}`));
6929
+ });
6930
+ process2.on("close", (code) => {
6931
+ if (code === 0) {
6932
+ resolve5(stdout);
6933
+ } else {
6934
+ reject(new Error(
6935
+ `CLI exited with code ${code}: ${stderr || "No error message"}`
6936
+ ));
6937
+ }
6938
+ });
6939
+ process2.stdin.write(prompt);
6940
+ process2.stdin.end();
6941
+ });
6942
+ }
6943
+ /**
6944
+ * Parse CLI response
6945
+ */
6946
+ parseResponse(output) {
6947
+ try {
6948
+ const parsed = JSON.parse(output.trim());
6949
+ if (parsed.content || parsed.message) {
6950
+ return {
6951
+ content: parsed.content || parsed.message || "",
6952
+ model: parsed.model || normalizeGrokModel(this.config.model),
6953
+ tokensUsed: parsed.usage ? {
6954
+ prompt: parsed.usage.prompt_tokens || 0,
6955
+ completion: parsed.usage.completion_tokens || 0,
6956
+ total: parsed.usage.total_tokens || 0
6957
+ } : { prompt: 0, completion: 0, total: 0 },
6958
+ finishReason: parsed.finish_reason || "stop"
6959
+ };
6960
+ }
6961
+ } catch {
6962
+ }
6963
+ return {
6964
+ content: output.trim(),
6965
+ model: normalizeGrokModel(this.config.model),
6966
+ tokensUsed: { prompt: 0, completion: 0, total: 0 },
6967
+ finishReason: "stop"
6968
+ };
6969
+ }
6970
+ /**
6971
+ * Get the configured model
6972
+ */
6973
+ getModel() {
6974
+ return this.config.model;
6975
+ }
6976
+ /**
6977
+ * Get CLI version
6978
+ */
6979
+ getVersion() {
6980
+ return this.cliVersion;
6981
+ }
6982
+ /**
6983
+ * Get CLI command
6984
+ */
6985
+ getCommand() {
6986
+ return this.config.command;
6987
+ }
6988
+ /**
6989
+ * Clean up resources
6990
+ */
6991
+ async destroy() {
6992
+ logger.debug("[Grok CLI] Wrapper destroyed");
6993
+ }
6994
+ };
6995
+ }
6996
+ });
6997
+
6998
+ // src/integrations/ax-grok/hybrid-adapter.ts
6999
+ var GrokHybridAdapter;
7000
+ var init_hybrid_adapter3 = __esm({
7001
+ "src/integrations/ax-grok/hybrid-adapter.ts"() {
7002
+ init_esm_shims();
7003
+ init_hybrid_adapter_base();
7004
+ init_sdk_adapter3();
7005
+ init_cli_wrapper3();
7006
+ init_types3();
7007
+ init_logger();
7008
+ GrokHybridAdapter = class extends HybridAdapterBase {
7009
+ sdkAdapter = null;
7010
+ cliWrapper = null;
7011
+ model;
7012
+ sdkConfig;
7013
+ cliConfig;
7014
+ constructor(options = {}) {
7015
+ const baseOptions = {
7016
+ mode: options.mode || "auto",
7017
+ providerName: "grok",
7018
+ maxRetries: options.maxRetries ?? 1
7019
+ };
7020
+ super(baseOptions);
7021
+ this.model = options.model || GROK_DEFAULT_MODEL;
7022
+ this.sdkConfig = {
7023
+ apiKey: options.apiKey,
7024
+ baseUrl: options.baseUrl,
7025
+ timeout: options.timeout
7026
+ };
7027
+ this.cliConfig = {
7028
+ command: options.command,
7029
+ timeout: options.timeout
7030
+ };
7031
+ logger.debug("[Grok Hybrid] Adapter created", {
7032
+ mode: this.mode,
7033
+ model: this.model
7034
+ });
7035
+ }
7036
+ /**
7037
+ * Execute request via SDK
7038
+ */
7039
+ async executeViaSDK(request) {
7040
+ if (!this.sdkAdapter) {
7041
+ throw new Error("Grok SDK adapter not initialized");
7042
+ }
7043
+ return this.sdkAdapter.execute(request);
7044
+ }
7045
+ /**
7046
+ * Execute request via CLI
7047
+ */
7048
+ async executeViaCLI(request) {
7049
+ if (!this.cliWrapper) {
7050
+ throw new Error("Grok CLI wrapper not initialized");
7051
+ }
7052
+ return this.cliWrapper.execute(request);
7053
+ }
7054
+ /**
7055
+ * Check if SDK is available
7056
+ */
7057
+ async isSDKAvailable() {
7058
+ try {
7059
+ const adapter = new GrokSdkAdapter({
7060
+ ...this.sdkConfig,
7061
+ model: this.model
7062
+ });
7063
+ const available = await adapter.isAvailable();
7064
+ if (!available) {
7065
+ return false;
7066
+ }
7067
+ this.sdkAdapter = adapter;
7068
+ return true;
7069
+ } catch (error) {
7070
+ logger.debug("[Grok Hybrid] SDK availability check failed", {
7071
+ error: error instanceof Error ? error.message : String(error)
7072
+ });
7073
+ return false;
7074
+ }
7075
+ }
7076
+ /**
7077
+ * Check if CLI is available
7078
+ */
7079
+ async isCLIAvailable() {
7080
+ try {
7081
+ const wrapper = new GrokCliWrapper({
7082
+ ...this.cliConfig,
7083
+ model: this.model
7084
+ });
7085
+ const available = await wrapper.isAvailable();
7086
+ if (!available) {
7087
+ return false;
7088
+ }
7089
+ this.cliWrapper = wrapper;
7090
+ return true;
7091
+ } catch (error) {
7092
+ logger.debug("[Grok Hybrid] CLI availability check failed", {
7093
+ error: error instanceof Error ? error.message : String(error)
7094
+ });
7095
+ return false;
7096
+ }
7097
+ }
7098
+ /**
7099
+ * Initialize SDK adapter
7100
+ */
7101
+ async initializeSDK() {
7102
+ if (!this.sdkAdapter) {
7103
+ this.sdkAdapter = new GrokSdkAdapter({
7104
+ ...this.sdkConfig,
7105
+ model: this.model
7106
+ });
7107
+ }
7108
+ await this.sdkAdapter.initialize();
7109
+ logger.debug("[Grok Hybrid] SDK initialized", {
7110
+ model: this.model
7111
+ });
7112
+ }
7113
+ /**
7114
+ * Initialize CLI wrapper
7115
+ */
7116
+ async initializeCLI() {
7117
+ if (!this.cliWrapper) {
7118
+ this.cliWrapper = new GrokCliWrapper({
7119
+ ...this.cliConfig,
7120
+ model: this.model
7121
+ });
7122
+ }
7123
+ await this.cliWrapper.initialize();
7124
+ logger.debug("[Grok Hybrid] CLI initialized", {
7125
+ model: this.model,
7126
+ version: this.cliWrapper.getVersion()
7127
+ });
7128
+ }
7129
+ /**
7130
+ * Clean up SDK resources
7131
+ */
7132
+ async destroySDK() {
7133
+ if (this.sdkAdapter) {
7134
+ await this.sdkAdapter.destroy();
7135
+ this.sdkAdapter = null;
7136
+ }
7137
+ }
7138
+ /**
7139
+ * Clean up CLI resources
7140
+ */
7141
+ async destroyCLI() {
7142
+ if (this.cliWrapper) {
7143
+ await this.cliWrapper.destroy();
7144
+ this.cliWrapper = null;
7145
+ }
7146
+ }
7147
+ /**
7148
+ * Get the configured model
7149
+ */
7150
+ getModel() {
7151
+ return this.model;
7152
+ }
7153
+ /**
7154
+ * Get the CLI command being used
7155
+ */
7156
+ getCommand() {
7157
+ return this.cliWrapper?.getCommand() || this.cliConfig.command || "ax-grok";
7158
+ }
7159
+ /**
7160
+ * Get CLI version
7161
+ */
7162
+ getCLIVersion() {
7163
+ return this.cliWrapper?.getVersion() || null;
7164
+ }
7165
+ };
7166
+ }
7167
+ });
7168
+
7169
+ // src/integrations/ax-grok/sdk-only-adapter.ts
7170
+ var GrokSdkOnlyAdapter;
7171
+ var init_sdk_only_adapter2 = __esm({
7172
+ "src/integrations/ax-grok/sdk-only-adapter.ts"() {
7173
+ init_esm_shims();
7174
+ init_logger();
7175
+ init_sdk_adapter3();
7176
+ init_types3();
7177
+ GrokSdkOnlyAdapter = class {
7178
+ sdkAdapter;
7179
+ initialized = false;
7180
+ model;
7181
+ maxRetries;
7182
+ retryDelayMs;
7183
+ constructor(options = {}) {
7184
+ this.model = options.model || GROK_DEFAULT_MODEL;
7185
+ this.maxRetries = options.maxRetries ?? 2;
7186
+ this.retryDelayMs = options.retryDelayMs ?? 1e3;
7187
+ this.sdkAdapter = new GrokSdkAdapter({
7188
+ model: this.model,
7189
+ apiKey: options.apiKey,
7190
+ baseUrl: options.baseUrl,
7191
+ timeout: options.timeout
7192
+ });
7193
+ logger.debug("[Grok SDK-Only] Adapter created", {
7194
+ model: this.model,
7195
+ maxRetries: this.maxRetries
7196
+ });
7197
+ }
7198
+ /**
7199
+ * Check if SDK is available
7200
+ */
7201
+ async isAvailable() {
7202
+ return this.sdkAdapter.isAvailable();
7203
+ }
7204
+ /**
7205
+ * Initialize the adapter
7206
+ */
7207
+ async initialize() {
7208
+ if (this.initialized) {
7209
+ return;
7210
+ }
7211
+ const available = await this.sdkAdapter.isAvailable();
7212
+ if (!available) {
7213
+ throw new Error("Grok SDK not available - check API key and openai package");
7214
+ }
7215
+ await this.sdkAdapter.initialize();
7216
+ this.initialized = true;
7217
+ logger.debug("[Grok SDK-Only] Initialized", { model: this.model });
7218
+ }
7219
+ /**
7220
+ * Execute a request using Grok SDK
7221
+ *
7222
+ * Retries transient errors up to maxRetries times with exponential backoff.
7223
+ * Does NOT fall back to CLI - throws on persistent failure.
7224
+ */
7225
+ async execute(request) {
7226
+ if (!this.initialized) {
7227
+ await this.initialize();
7228
+ }
7229
+ const startTime = Date.now();
7230
+ let lastError;
7231
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
7232
+ try {
7233
+ const response = await this.sdkAdapter.execute(request);
7234
+ logger.debug("[Grok SDK-Only] Execution succeeded", {
7235
+ model: this.model,
7236
+ attempt: attempt + 1,
7237
+ latencyMs: response.latencyMs
7238
+ });
7239
+ return response;
7240
+ } catch (error) {
7241
+ lastError = error;
7242
+ logger.warn("[Grok SDK-Only] Execution failed", {
7243
+ model: this.model,
7244
+ attempt: attempt + 1,
7245
+ maxRetries: this.maxRetries,
7246
+ error: lastError.message
7247
+ });
7248
+ if (attempt < this.maxRetries && this.isRetryableError(lastError)) {
7249
+ const delay = this.retryDelayMs * Math.pow(2, attempt);
7250
+ logger.debug("[Grok SDK-Only] Retrying after delay", {
7251
+ attempt: attempt + 1,
7252
+ delayMs: delay
7253
+ });
7254
+ await this.sleep(delay);
7255
+ continue;
7256
+ }
7257
+ break;
7258
+ }
7259
+ }
7260
+ const totalTime = Date.now() - startTime;
7261
+ logger.error("[Grok SDK-Only] All retries exhausted", {
7262
+ model: this.model,
7263
+ totalAttempts: this.maxRetries + 1,
7264
+ totalTimeMs: totalTime,
7265
+ lastError: lastError?.message
7266
+ });
7267
+ throw new Error(
7268
+ `Grok SDK execution failed after ${this.maxRetries + 1} attempts: ${lastError?.message || "Unknown error"}`
7269
+ );
7270
+ }
7271
+ /**
7272
+ * Check if error is retryable
7273
+ */
7274
+ isRetryableError(error) {
7275
+ const message = error.message.toLowerCase();
7276
+ if (message.includes("rate limit") || message.includes("429")) {
7277
+ return true;
7278
+ }
7279
+ if (message.includes("500") || message.includes("502") || message.includes("503") || message.includes("504")) {
7280
+ return true;
7281
+ }
7282
+ if (message.includes("timeout") || message.includes("etimedout")) {
7283
+ return true;
7284
+ }
7285
+ if (message.includes("econnreset") || message.includes("econnrefused")) {
7286
+ return true;
7287
+ }
7288
+ return false;
7289
+ }
7290
+ /**
7291
+ * Sleep utility
7292
+ */
7293
+ sleep(ms) {
7294
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
7295
+ }
7296
+ /**
7297
+ * Get the configured model
7298
+ */
7299
+ getModel() {
7300
+ return this.model;
7301
+ }
7302
+ /**
7303
+ * Clean up resources
7304
+ */
7305
+ async destroy() {
7306
+ await this.sdkAdapter.destroy();
7307
+ this.initialized = false;
7308
+ logger.debug("[Grok SDK-Only] Adapter destroyed");
7309
+ }
7310
+ };
7311
+ }
7312
+ });
7313
+
7314
+ // src/integrations/ax-grok/mcp-client-mode.ts
7315
+ var init_mcp_client_mode2 = __esm({
7316
+ "src/integrations/ax-grok/mcp-client-mode.ts"() {
7317
+ init_esm_shims();
7318
+ init_logger();
7319
+ init_sdk_adapter3();
7320
+ }
7321
+ });
7322
+
7323
+ // src/integrations/ax-grok/index.ts
7324
+ var init_ax_grok = __esm({
7325
+ "src/integrations/ax-grok/index.ts"() {
7326
+ init_esm_shims();
7327
+ init_hybrid_adapter3();
7328
+ init_sdk_adapter3();
7329
+ init_cli_wrapper3();
7330
+ init_sdk_only_adapter2();
7331
+ init_mcp_client_mode2();
7332
+ init_types3();
7333
+ }
7334
+ });
7335
+
7336
+ // src/providers/grok-provider.ts
7337
+ var grok_provider_exports = {};
7338
+ __export(grok_provider_exports, {
7339
+ GrokProvider: () => GrokProvider,
7340
+ default: () => GrokProvider
7341
+ });
7342
+ var MODEL_MAPPING2, GrokProvider;
7343
+ var init_grok_provider = __esm({
7344
+ "src/providers/grok-provider.ts"() {
7345
+ init_esm_shims();
7346
+ init_base_provider();
7347
+ init_logger();
7348
+ init_ax_grok();
7349
+ MODEL_MAPPING2 = {
7350
+ "grok-beta": "grok-3"
7351
+ };
7352
+ GrokProvider = class _GrokProvider extends BaseProvider {
7353
+ /** Selected model */
7354
+ model;
7355
+ /** SDK-only adapter for direct execution (v13.0.0) */
7356
+ sdkOnlyAdapter = null;
7357
+ /** Legacy hybrid adapter for 'auto' mode (backwards compatibility) */
7358
+ hybridAdapter = null;
7359
+ /** Provider configuration */
7360
+ grokConfig;
7361
+ /** Supported models */
7362
+ static SUPPORTED_MODELS = [
7363
+ "grok-3",
7364
+ "grok-3-mini",
7365
+ "grok-2-vision",
7366
+ "grok-2",
7367
+ // Legacy alias
7368
+ "grok-beta"
7369
+ ];
7370
+ constructor(config) {
7371
+ super({
7372
+ ...config,
7373
+ command: "ax-grok"
7374
+ });
7375
+ this.grokConfig = config;
7376
+ const requestedModel = config.model || "grok-3";
7377
+ if (!_GrokProvider.SUPPORTED_MODELS.includes(requestedModel)) {
7378
+ logger.warn(`[Grok] Unknown model: ${requestedModel}. Using grok-3.`);
7379
+ this.model = "grok-3";
7380
+ } else {
7381
+ this.model = requestedModel;
7382
+ }
7383
+ logger.debug("[Grok Provider] Initialized", {
7384
+ model: this.model,
7385
+ mode: config.mode || "auto"
7386
+ });
7387
+ }
7388
+ /**
7389
+ * Get the normalized model name
7390
+ */
7391
+ getNormalizedModel() {
7392
+ return MODEL_MAPPING2[this.model] || this.model;
7393
+ }
7394
+ /**
7395
+ * Get or create SDK-only adapter (v13.0.0 default)
7396
+ */
7397
+ getSdkOnlyAdapter() {
7398
+ if (!this.sdkOnlyAdapter) {
7399
+ this.sdkOnlyAdapter = new GrokSdkOnlyAdapter({
7400
+ model: this.model,
7401
+ apiKey: this.grokConfig.apiKey,
7402
+ baseUrl: this.grokConfig.baseUrl,
7403
+ timeout: this.grokConfig.timeout
7404
+ });
7405
+ }
7406
+ return this.sdkOnlyAdapter;
7407
+ }
7408
+ /**
7409
+ * Get or create hybrid adapter (legacy, for 'auto' mode only)
7410
+ */
7411
+ getHybridAdapter() {
7412
+ if (!this.hybridAdapter) {
7413
+ const options = {
7414
+ mode: this.grokConfig.mode || "auto",
7415
+ model: this.model,
7416
+ apiKey: this.grokConfig.apiKey,
7417
+ baseUrl: this.grokConfig.baseUrl,
7418
+ command: "ax-grok",
7419
+ timeout: this.grokConfig.timeout
7420
+ };
7421
+ this.hybridAdapter = new GrokHybridAdapter(options);
7422
+ }
7423
+ return this.hybridAdapter;
7424
+ }
7425
+ /**
7426
+ * Execute a task using Grok
7427
+ *
7428
+ * Execution flow (v13.0.0):
7429
+ * 1. Mock mode → return mock response
7430
+ * 2. mode='sdk' (default) → use SDK-only adapter (NO CLI fallback)
7431
+ * 3. mode='auto' (legacy) → use hybrid adapter (SDK with CLI fallback)
7432
+ * 4. mode='cli' → use CLI via BaseProvider (deprecated for Grok)
7433
+ */
7434
+ async execute(request) {
7435
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
7436
+ return this.createMockResponse(request.prompt);
7437
+ }
7438
+ const effectiveMode = this.grokConfig.mode || "sdk";
7439
+ if (effectiveMode === "cli") {
7440
+ logger.warn("[Grok Provider] CLI mode is deprecated for Grok. Consider using SDK mode.", {
7441
+ model: this.model
7442
+ });
7443
+ return super.execute(request);
7444
+ }
7445
+ if (effectiveMode === "auto") {
7446
+ logger.debug("[Grok Provider] Executing via hybrid adapter (legacy auto mode)", {
7447
+ promptLength: request.prompt.length,
7448
+ model: this.model
7449
+ });
7450
+ const adapter2 = this.getHybridAdapter();
7451
+ return adapter2.execute(request);
7452
+ }
7453
+ logger.debug("[Grok Provider] Executing via SDK-only adapter", {
7454
+ promptLength: request.prompt.length,
7455
+ model: this.model
7456
+ });
7457
+ const adapter = this.getSdkOnlyAdapter();
7458
+ return adapter.execute(request);
7459
+ }
7460
+ /**
7461
+ * Get CLI command
7462
+ */
7463
+ getCLICommand() {
7464
+ const adapter = this.hybridAdapter;
7465
+ if (adapter) {
7466
+ const activeMode = adapter.getActiveMode();
7467
+ if (activeMode === "sdk") {
7468
+ return "grok-sdk";
7469
+ }
7470
+ }
7471
+ return "ax-grok";
7472
+ }
7473
+ /**
7474
+ * Get CLI arguments for ax-grok headless mode
7475
+ */
7476
+ getCLIArgs() {
7477
+ const args2 = ["-p"];
7478
+ const normalizedModel = this.getNormalizedModel();
7479
+ if (normalizedModel !== "grok-3") {
7480
+ args2.push("--model", normalizedModel);
7481
+ }
7482
+ return args2;
7483
+ }
7484
+ /**
7485
+ * Create mock response for testing
7486
+ */
7487
+ createMockResponse(prompt) {
7488
+ return {
7489
+ content: this.getMockResponse(),
7490
+ model: this.getNormalizedModel(),
7491
+ tokensUsed: {
7492
+ prompt: this.estimateTokens(prompt),
7493
+ completion: 50,
7494
+ total: this.estimateTokens(prompt) + 50
7495
+ },
7496
+ latencyMs: 10,
7497
+ finishReason: "stop",
7498
+ cached: false
7499
+ };
7500
+ }
7501
+ /**
7502
+ * Estimate token count
7503
+ */
7504
+ estimateTokens(text) {
7505
+ return Math.ceil(text.length / 4);
7506
+ }
7507
+ /**
7508
+ * Get mock response for testing
7509
+ */
7510
+ getMockResponse() {
7511
+ return `[Mock Grok Response]
7512
+
7513
+ This is a mock response from the Grok provider (${this.getNormalizedModel()}).
7514
+ In production, this would be a response from ${this.grokConfig.mode === "sdk" ? "Grok SDK" : "ax-grok CLI"}.
7515
+
7516
+ Model: ${this.getNormalizedModel()}
7517
+ Provider: Grok (xAI)
7518
+ Mode: ${this.grokConfig.mode || "auto"}`;
7519
+ }
7520
+ /**
7521
+ * Get provider capabilities
7522
+ */
7523
+ get capabilities() {
7524
+ const model = this.getNormalizedModel();
7525
+ const isVision = model.includes("vision") || model === "grok-2-vision";
7526
+ const maxContextTokens = 131072;
7527
+ const activeMode = this.hybridAdapter?.getActiveMode();
7528
+ const integrationMode = activeMode === "sdk" ? "sdk" : "cli";
7529
+ return {
7530
+ ...super.capabilities,
7531
+ supportsStreaming: true,
7532
+ supportsVision: isVision,
7533
+ maxContextTokens,
7534
+ supportedModels: _GrokProvider.SUPPORTED_MODELS,
7535
+ integrationMode
7536
+ };
7537
+ }
7538
+ /**
7539
+ * Get the active execution mode
7540
+ */
7541
+ getActiveMode() {
7542
+ return this.hybridAdapter?.getActiveMode() || null;
7543
+ }
7544
+ /**
7545
+ * Reset circuit breakers
7546
+ */
7547
+ resetCircuitBreakers() {
7548
+ this.hybridAdapter?.resetCircuitBreakers();
7549
+ }
7550
+ /**
7551
+ * Clean up resources
7552
+ */
7553
+ async destroy() {
7554
+ if (this.sdkOnlyAdapter) {
7555
+ await this.sdkOnlyAdapter.destroy();
7556
+ this.sdkOnlyAdapter = null;
7557
+ }
7558
+ if (this.hybridAdapter) {
7559
+ await this.hybridAdapter.destroy();
7560
+ this.hybridAdapter = null;
7561
+ }
7562
+ }
7563
+ /**
7564
+ * Get the list of supported models
7565
+ */
7566
+ static getSupportedModels() {
7567
+ return [..._GrokProvider.SUPPORTED_MODELS];
7568
+ }
7569
+ };
4144
7570
  }
4145
7571
  });
4146
7572
 
@@ -4149,18 +7575,19 @@ init_esm_shims();
4149
7575
 
4150
7576
  // src/mcp/server.ts
4151
7577
  init_esm_shims();
7578
+ init_validation_limits();
4152
7579
 
4153
7580
  // src/shared/helpers/version.ts
4154
7581
  init_esm_shims();
4155
- var __dirname$1 = dirname(fileURLToPath(import.meta.url));
7582
+ var __dirname2 = dirname(fileURLToPath(import.meta.url));
4156
7583
  function getVersion() {
4157
7584
  try {
4158
7585
  const possiblePaths = [
4159
- join(__dirname$1, "../../../package.json"),
7586
+ join(__dirname2, "../../../package.json"),
4160
7587
  // From src/shared/helpers
4161
- join(__dirname$1, "../../package.json"),
7588
+ join(__dirname2, "../../package.json"),
4162
7589
  // From dist/mcp (bundled MCP entry)
4163
- join(__dirname$1, "../package.json")
7590
+ join(__dirname2, "../package.json")
4164
7591
  // From dist
4165
7592
  ];
4166
7593
  for (const pkgPath of possiblePaths) {
@@ -4182,7 +7609,8 @@ function getVersion() {
4182
7609
 
4183
7610
  // src/mcp/types.ts
4184
7611
  init_esm_shims();
4185
- var MCP_PROTOCOL_VERSION = "2024-11-05";
7612
+ var MCP_PROTOCOL_VERSION = "2025-11-25";
7613
+ var MCP_SUPPORTED_VERSIONS = ["2025-11-25", "2024-12-05", "2024-11-05"];
4186
7614
 
4187
7615
  // src/mcp/server.ts
4188
7616
  init_logger();
@@ -4618,119 +8046,8 @@ function deepMerge(defaults, user) {
4618
8046
  return result;
4619
8047
  }
4620
8048
 
4621
- // src/core/validation-limits.ts
4622
- init_esm_shims();
4623
- var VALIDATION_LIMITS = {
4624
- // Resource limits (prevent DoS)
4625
- MAX_ENTRIES: 1e6,
4626
- // 1 million entries (memory, cache)
4627
- MAX_TIMEOUT: 36e5,
4628
- // 1 hour (execution, delegation)
4629
- MAX_FILE_SIZE: 104857600,
4630
- // 100 MB (workspace, abilities)
4631
- MAX_CACHE_SIZE: 524288e3,
4632
- // 500 MB (cache storage)
4633
- MAX_SESSIONS: 1e4,
4634
- // 10k concurrent sessions
4635
- // Performance limits (prevent resource exhaustion)
4636
- MAX_CONCURRENT_AGENTS: 100,
4637
- // Maximum concurrent agents
4638
- MAX_CPU_PERCENT: 80,
4639
- // Maximum CPU usage percent
4640
- MAX_MEMORY_MB: 2048,
4641
- // Maximum memory usage in MB
4642
- // Config validation limits
4643
- MAX_CONFIG_FILE_SIZE: 1048576,
4644
- // 1MB max config file size
4645
- MAX_NAME_LENGTH: 50,
4646
- // Max name length for agents/providers
4647
- MAX_COMMAND_LENGTH: 100,
4648
- // Max command length
4649
- MAX_ARRAY_LENGTH: 1e4,
4650
- // Max array elements in config
4651
- // Path and file limits
4652
- MIN_FILE_SIZE: 1,
4653
- // Minimum file size in bytes
4654
- MIN_TIMEOUT: 1e3,
4655
- // Minimum timeout in ms (1 second)
4656
- MIN_INTERVAL: 100,
4657
- // Minimum interval in ms
4658
- MIN_BACKOFF_FACTOR: 1,
4659
- // Minimum backoff multiplier
4660
- MAX_BACKOFF_FACTOR: 5,
4661
- // Maximum backoff multiplier
4662
- MAX_TTL: 864e5,
4663
- // Maximum TTL in ms (24 hours)
4664
- MIN_BYTES: 1,
4665
- // Minimum bytes for file sizes
4666
- // Network limits
4667
- MIN_PORT: 1024,
4668
- // Minimum port number
4669
- MAX_PORT: 65535
4670
- // Maximum port number
4671
- };
4672
- function isValidRelativePath(path7) {
4673
- if (!path7 || typeof path7 !== "string") {
4674
- return false;
4675
- }
4676
- const normalizedPath = path7.replace(/\\/g, "/");
4677
- if (normalizedPath.startsWith("/")) {
4678
- return false;
4679
- }
4680
- if (normalizedPath.includes("..")) {
4681
- return false;
4682
- }
4683
- if (/^[a-zA-Z]:/.test(normalizedPath)) {
4684
- return false;
4685
- }
4686
- if (normalizedPath.startsWith("//")) {
4687
- return false;
4688
- }
4689
- return true;
4690
- }
4691
- function isValidCommand(command) {
4692
- if (!command || typeof command !== "string") {
4693
- return false;
4694
- }
4695
- if (command.length > VALIDATION_LIMITS.MAX_COMMAND_LENGTH) {
4696
- return false;
4697
- }
4698
- if (!/^[a-z0-9_-]+$/i.test(command)) {
4699
- return false;
4700
- }
4701
- return true;
4702
- }
4703
- function isValidName(name) {
4704
- if (!name || typeof name !== "string") {
4705
- return false;
4706
- }
4707
- if (name.length > VALIDATION_LIMITS.MAX_NAME_LENGTH) {
4708
- return false;
4709
- }
4710
- if (!/^[a-z0-9][a-z0-9-_]*$/i.test(name)) {
4711
- return false;
4712
- }
4713
- return true;
4714
- }
4715
- function isValidExtension(ext) {
4716
- if (!ext || typeof ext !== "string") {
4717
- return false;
4718
- }
4719
- const normalized = ext.startsWith(".") ? ext : `.${ext}`;
4720
- if (normalized.length > 10 || normalized.length < 2) {
4721
- return false;
4722
- }
4723
- if (!/^\.[a-z0-9]+$/i.test(normalized)) {
4724
- return false;
4725
- }
4726
- return true;
4727
- }
4728
- function isPositiveInteger(value) {
4729
- return typeof value === "number" && Number.isInteger(value) && value > 0;
4730
- }
4731
- function isNonNegativeInteger(value) {
4732
- return typeof value === "number" && Number.isInteger(value) && value >= 0;
4733
- }
8049
+ // src/core/config/loader.ts
8050
+ init_validation_limits();
4734
8051
 
4735
8052
  // src/core/cache/cache.ts
4736
8053
  init_esm_shims();
@@ -4806,7 +8123,7 @@ var TTLCache = class {
4806
8123
  * @param value Value to cache
4807
8124
  * @param customTTL Optional custom TTL for this entry (ms)
4808
8125
  */
4809
- set(key, value, customTTL) {
8126
+ set(key, value, _customTTL) {
4810
8127
  const size = this.estimateSize(value);
4811
8128
  if (this.config.maxSize > 0 && size > this.config.maxSize) {
4812
8129
  logger.warn("Entry too large for cache", {
@@ -5063,11 +8380,12 @@ function calculateMaxConcurrentAgents(staticLimit) {
5063
8380
  init_esm_shims();
5064
8381
  var PRECOMPILED_CONFIG = {
5065
8382
  "providers": {
5066
- "claude-code": {
8383
+ "gemini-cli": {
5067
8384
  "enabled": true,
5068
- "priority": 3,
8385
+ "priority": 1,
5069
8386
  "timeout": 27e5,
5070
- "command": "claude",
8387
+ "command": "gemini",
8388
+ "description": "#1 Frontend/Design, multimodal, free tier, WebDev Arena leader",
5071
8389
  "healthCheck": {
5072
8390
  "enabled": true,
5073
8391
  "interval": 3e5,
@@ -5089,15 +8407,16 @@ var PRECOMPILED_CONFIG = {
5089
8407
  },
5090
8408
  "limitTracking": {
5091
8409
  "enabled": true,
5092
- "window": "weekly",
8410
+ "window": "daily",
5093
8411
  "resetHourUtc": 0
5094
8412
  }
5095
8413
  },
5096
- "gemini-cli": {
8414
+ "openai": {
5097
8415
  "enabled": true,
5098
- "priority": 2,
8416
+ "priority": 3,
5099
8417
  "timeout": 27e5,
5100
- "command": "gemini",
8418
+ "command": "codex",
8419
+ "description": "Best reasoning (o3), strategy, 75% accuracy, 192k context",
5101
8420
  "healthCheck": {
5102
8421
  "enabled": true,
5103
8422
  "interval": 3e5,
@@ -5123,11 +8442,12 @@ var PRECOMPILED_CONFIG = {
5123
8442
  "resetHourUtc": 0
5124
8443
  }
5125
8444
  },
5126
- "openai": {
8445
+ "claude-code": {
5127
8446
  "enabled": true,
5128
- "priority": 1,
8447
+ "priority": 2,
5129
8448
  "timeout": 27e5,
5130
- "command": "codex",
8449
+ "command": "claude",
8450
+ "description": "#1 Coding model, agentic workflows, security, 0% edit error rate",
5131
8451
  "healthCheck": {
5132
8452
  "enabled": true,
5133
8453
  "interval": 3e5,
@@ -5147,6 +8467,50 @@ var PRECOMPILED_CONFIG = {
5147
8467
  "forceKillDelay": 1e3,
5148
8468
  "cacheEnabled": true
5149
8469
  },
8470
+ "limitTracking": {
8471
+ "enabled": true,
8472
+ "window": "weekly",
8473
+ "resetHourUtc": 0
8474
+ }
8475
+ },
8476
+ "glm": {
8477
+ "enabled": true,
8478
+ "priority": 4,
8479
+ "timeout": 27e5,
8480
+ "type": "sdk",
8481
+ "description": "Near Claude coding (48.6%), low cost $3/mo, 200k context, agentic",
8482
+ "healthCheck": {
8483
+ "enabled": true,
8484
+ "interval": 3e5,
8485
+ "timeout": 5e3
8486
+ },
8487
+ "circuitBreaker": {
8488
+ "enabled": true,
8489
+ "failureThreshold": 3,
8490
+ "recoveryTimeout": 6e4
8491
+ },
8492
+ "limitTracking": {
8493
+ "enabled": true,
8494
+ "window": "daily",
8495
+ "resetHourUtc": 0
8496
+ }
8497
+ },
8498
+ "grok": {
8499
+ "enabled": true,
8500
+ "priority": 5,
8501
+ "timeout": 27e5,
8502
+ "type": "sdk",
8503
+ "description": "Fastest (67ms), reasoning (93% AIME), 1M context, DeepSearch",
8504
+ "healthCheck": {
8505
+ "enabled": true,
8506
+ "interval": 3e5,
8507
+ "timeout": 5e3
8508
+ },
8509
+ "circuitBreaker": {
8510
+ "enabled": true,
8511
+ "failureThreshold": 3,
8512
+ "recoveryTimeout": 6e4
8513
+ },
5150
8514
  "limitTracking": {
5151
8515
  "enabled": true,
5152
8516
  "window": "daily",
@@ -5363,11 +8727,12 @@ var PRECOMPILED_CONFIG = {
5363
8727
  "enableFreeTierPrioritization": true,
5364
8728
  "enableWorkloadAwareRouting": true
5365
8729
  },
5366
- "version": "12.3.0"
8730
+ "version": "12.4.1"
5367
8731
  };
5368
8732
 
5369
8733
  // src/core/config/schemas.ts
5370
8734
  init_esm_shims();
8735
+ init_validation_limits();
5371
8736
  z.enum([
5372
8737
  "claude",
5373
8738
  "claude-code",
@@ -5430,17 +8795,35 @@ var limitTrackingConfigSchema = z.object({
5430
8795
  resetHourUtc: z.number().int().min(0).max(23).default(0),
5431
8796
  customResetMs: positiveIntSchema.optional()
5432
8797
  }).describe("Provider limit tracking configuration");
8798
+ var providerTypeSchema = z.enum(["cli", "sdk", "hybrid"]).default("cli");
5433
8799
  var providerConfigSchema = z.object({
5434
8800
  enabled: z.boolean().default(true),
5435
8801
  priority: positiveIntSchema,
5436
8802
  timeout: timeoutSchema,
5437
- command: commandSchema,
8803
+ type: providerTypeSchema.optional(),
8804
+ command: commandSchema.optional(),
8805
+ // Optional for SDK providers (glm, grok)
8806
+ description: z.string().optional(),
8807
+ // Provider description
8808
+ model: z.string().optional(),
8809
+ // Model name override
5438
8810
  healthCheck: healthCheckConfigSchema.optional(),
5439
8811
  circuitBreaker: circuitBreakerConfigSchema.optional(),
5440
8812
  processManagement: processManagementConfigSchema.optional(),
5441
8813
  versionDetection: versionDetectionConfigSchema.optional(),
5442
8814
  limitTracking: limitTrackingConfigSchema.optional()
5443
- }).describe("Provider configuration");
8815
+ }).refine(
8816
+ (data) => {
8817
+ if (data.type === "sdk") {
8818
+ return true;
8819
+ }
8820
+ return data.command !== void 0;
8821
+ },
8822
+ {
8823
+ message: "CLI and hybrid providers require a command field",
8824
+ path: ["command"]
8825
+ }
8826
+ ).describe("Provider configuration");
5444
8827
  var providersConfigSchema = z.record(
5445
8828
  safeNameSchema,
5446
8829
  providerConfigSchema
@@ -5826,9 +9209,15 @@ function validateConfig(config) {
5826
9209
  if (!isValidName(name)) {
5827
9210
  errors.push(`Provider "${name}": name invalid (use alphanumeric, dash, underscore only, max 50 chars)`);
5828
9211
  }
5829
- if (!provider.command) {
5830
- errors.push(`Provider ${name}: command is required`);
5831
- } else if (!isValidCommand(provider.command)) {
9212
+ const providerType = provider.type;
9213
+ const isSDKProvider = providerType === "sdk";
9214
+ if (!isSDKProvider) {
9215
+ if (!provider.command) {
9216
+ errors.push(`Provider ${name}: command is required for CLI/hybrid providers`);
9217
+ } else if (!isValidCommand(provider.command)) {
9218
+ errors.push(`Provider ${name}: command invalid (alphanumeric, dash, underscore only, max 100 chars, no shell metacharacters)`);
9219
+ }
9220
+ } else if (provider.command && !isValidCommand(provider.command)) {
5832
9221
  errors.push(`Provider ${name}: command invalid (alphanumeric, dash, underscore only, max 100 chars, no shell metacharacters)`);
5833
9222
  }
5834
9223
  if (!isPositiveInteger(provider.priority)) {
@@ -6204,6 +9593,7 @@ function validateConfig(config) {
6204
9593
  init_esm_shims();
6205
9594
  init_logger();
6206
9595
  init_errors();
9596
+ init_validation_limits();
6207
9597
 
6208
9598
  // src/core/provider-limit-manager.ts
6209
9599
  init_esm_shims();
@@ -6414,6 +9804,9 @@ var PathResolver = class {
6414
9804
  }
6415
9805
  }
6416
9806
  };
9807
+
9808
+ // src/core/provider-limit-manager.ts
9809
+ init_validation_limits();
6417
9810
  var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
6418
9811
  static instance = null;
6419
9812
  stateFilePath;
@@ -6439,7 +9832,7 @@ var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
6439
9832
  /**
6440
9833
  * Get singleton instance
6441
9834
  */
6442
- static getInstance(stateDirectory = ".automatosx/state") {
9835
+ static getInstance(stateDirectory = AX_PATHS.STATE) {
6443
9836
  if (!_ProviderLimitManager.instance) {
6444
9837
  _ProviderLimitManager.instance = new _ProviderLimitManager(stateDirectory);
6445
9838
  }
@@ -6527,7 +9920,9 @@ var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
6527
9920
  return { isLimited: false };
6528
9921
  }
6529
9922
  if (now >= state.resetAtMs) {
6530
- void this.clearLimit(providerName, "expired");
9923
+ void this.clearLimit(providerName, "expired").catch((err) => {
9924
+ logger.warn("Failed to clear expired limit", { provider: providerName, error: err.message });
9925
+ });
6531
9926
  return { isLimited: false };
6532
9927
  }
6533
9928
  const remainingMs = state.resetAtMs - now;
@@ -6616,9 +10011,10 @@ var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
6616
10011
  getManualOverride() {
6617
10012
  if (this.manualOverride && this.manualOverride.expiresAtMs) {
6618
10013
  if (Date.now() >= this.manualOverride.expiresAtMs) {
6619
- this.manualOverride;
6620
10014
  this.manualOverride = void 0;
6621
- void this.clearManualOverride();
10015
+ void this.clearManualOverride().catch((err) => {
10016
+ logger.warn("Failed to clear expired manual override", { error: err.message });
10017
+ });
6622
10018
  return void 0;
6623
10019
  }
6624
10020
  }
@@ -6755,10 +10151,10 @@ var ProviderLimitManager = class _ProviderLimitManager extends EventEmitter {
6755
10151
  async function getProviderLimitManager(stateDirectory) {
6756
10152
  if (!stateDirectory) {
6757
10153
  if (process.env.NODE_ENV === "test" || process.env.VITEST) {
6758
- stateDirectory = ".automatosx/state";
10154
+ stateDirectory = AX_PATHS.STATE;
6759
10155
  } else {
6760
10156
  const projectRoot = await detectProjectRoot();
6761
- stateDirectory = path4.join(projectRoot, ".automatosx", "state");
10157
+ stateDirectory = path4.join(projectRoot, AX_PATHS.STATE);
6762
10158
  }
6763
10159
  }
6764
10160
  return ProviderLimitManager.getInstance(stateDirectory);
@@ -7741,13 +11137,12 @@ function getRoutingStrategyManager(config) {
7741
11137
  // src/core/router/circuit-breaker.ts
7742
11138
  init_esm_shims();
7743
11139
  init_logger();
11140
+ init_validation_limits();
7744
11141
  var DEFAULT_CONFIG2 = {
7745
11142
  failureThreshold: 3,
7746
- cooldownMs: 6e4,
7747
- // 1 minute
11143
+ cooldownMs: TIMEOUTS.CIRCUIT_BREAKER_RECOVERY,
7748
11144
  successThreshold: 2,
7749
- failureWindowMs: 3e5
7750
- // v11.1.0: 5 minutes - failures outside this window don't count
11145
+ failureWindowMs: TIMEOUTS.CIRCUIT_BREAKER_WINDOW
7751
11146
  };
7752
11147
  var CircuitBreaker = class {
7753
11148
  config;
@@ -7904,6 +11299,7 @@ var CircuitBreaker = class {
7904
11299
  // src/core/router/trace-logger.ts
7905
11300
  init_esm_shims();
7906
11301
  init_logger();
11302
+ init_validation_limits();
7907
11303
  var RouterTraceLogger = class {
7908
11304
  traceFile;
7909
11305
  stream;
@@ -7915,7 +11311,7 @@ var RouterTraceLogger = class {
7915
11311
  sigintHandler = () => this.close();
7916
11312
  sigtermHandler = () => this.close();
7917
11313
  constructor(options) {
7918
- this.traceFile = join(options.workspacePath, ".automatosx/logs/router.trace.jsonl");
11314
+ this.traceFile = join(options.workspacePath, AX_PATHS.LOGS, "router.trace.jsonl");
7919
11315
  this.enabled = options.enabled ?? true;
7920
11316
  this.autoFlush = options.autoFlush ?? true;
7921
11317
  if (this.enabled) {
@@ -8302,13 +11698,12 @@ var Router = class {
8302
11698
  return a.priority - b.priority;
8303
11699
  });
8304
11700
  this.fallbackEnabled = config.fallbackEnabled;
8305
- this.providerCooldownMs = config.providerCooldownMs ?? 3e4;
11701
+ this.providerCooldownMs = config.providerCooldownMs ?? TIMEOUTS.PROVIDER_COOLDOWN;
8306
11702
  this.cache = config.cache;
8307
11703
  this.circuitBreaker = new CircuitBreaker({
8308
11704
  failureThreshold: config.circuitBreakerThreshold ?? 3,
8309
- cooldownMs: config.providerCooldownMs ?? 3e4,
8310
- failureWindowMs: config.circuitBreakerWindowMs ?? 3e5
8311
- // 5 min default
11705
+ cooldownMs: config.providerCooldownMs ?? TIMEOUTS.PROVIDER_COOLDOWN,
11706
+ failureWindowMs: config.circuitBreakerWindowMs ?? TIMEOUTS.CIRCUIT_BREAKER_WINDOW
8312
11707
  });
8313
11708
  void (async () => {
8314
11709
  try {
@@ -8352,6 +11747,13 @@ var Router = class {
8352
11747
  }
8353
11748
  }
8354
11749
  }
11750
+ /**
11751
+ * Get the number of configured providers.
11752
+ * @returns Number of providers registered with this router
11753
+ */
11754
+ get providerCount() {
11755
+ return this.providers.length;
11756
+ }
8355
11757
  /**
8356
11758
  * Warm up provider availability caches immediately.
8357
11759
  * Phase 3 (v5.6.3): Eliminates cold-start latency on first request.
@@ -10337,9 +13739,9 @@ var MemoryManager = class _MemoryManager {
10337
13739
  throw new MemoryError("Memory manager not initialized", "DATABASE_ERROR");
10338
13740
  }
10339
13741
  try {
10340
- const { mkdir: mkdir5 } = await import('fs/promises');
13742
+ const { mkdir: mkdir4 } = await import('fs/promises');
10341
13743
  const destDir = dirname3(destPath);
10342
- await mkdir5(destDir, { recursive: true });
13744
+ await mkdir4(destDir, { recursive: true });
10343
13745
  await this.db.backup(destPath);
10344
13746
  logger.info("Database backup created", { destPath: normalizePath(destPath) });
10345
13747
  } catch (error) {
@@ -10787,7 +14189,7 @@ var LazyMemoryManager = class {
10787
14189
  /**
10788
14190
  * Backup database to destination path (lazy initialization on first call)
10789
14191
  */
10790
- async backup(destPath, onProgress) {
14192
+ async backup(destPath, _onProgress) {
10791
14193
  const manager = await this.ensureInitialized();
10792
14194
  return manager.backup(destPath);
10793
14195
  }
@@ -11681,12 +15083,13 @@ var SessionManager = class _SessionManager {
11681
15083
  */
11682
15084
  async getStats() {
11683
15085
  const sessions = Array.from(this.activeSessions.values());
11684
- return {
11685
- total: sessions.length,
11686
- active: sessions.filter((s) => s.status === "active").length,
11687
- completed: sessions.filter((s) => s.status === "completed").length,
11688
- failed: sessions.filter((s) => s.status === "failed").length
11689
- };
15086
+ let active = 0, completed = 0, failed = 0;
15087
+ for (const s of sessions) {
15088
+ if (s.status === "active") active++;
15089
+ else if (s.status === "completed") completed++;
15090
+ else if (s.status === "failed") failed++;
15091
+ }
15092
+ return { total: sessions.length, active, completed, failed };
11690
15093
  }
11691
15094
  /**
11692
15095
  * Load sessions from persistence file
@@ -12967,11 +16370,13 @@ var ContextManager = class {
12967
16370
  * Cleanup context
12968
16371
  *
12969
16372
  * v5.2: No cleanup needed - agent workspaces no longer created
16373
+ * Note: Returns Promise for interface compatibility
12970
16374
  */
12971
- async cleanup(context) {
16375
+ cleanup(context) {
12972
16376
  logger.debug("Context cleanup (no-op in v5.2)", {
12973
16377
  agent: context.agent.name
12974
16378
  });
16379
+ return Promise.resolve();
12975
16380
  }
12976
16381
  };
12977
16382
 
@@ -12995,6 +16400,7 @@ var AgentNotFoundError = class extends Error {
12995
16400
 
12996
16401
  // src/agents/profile-loader.ts
12997
16402
  init_logger();
16403
+ init_validation_limits();
12998
16404
 
12999
16405
  // src/agents/agent-schemas.ts
13000
16406
  init_esm_shims();
@@ -13395,7 +16801,7 @@ var ProfileLoader = class {
13395
16801
  const files = await readdir(this.fallbackProfilesDir);
13396
16802
  const profiles = files.filter((file) => extname$1(file) === ".yaml" || extname$1(file) === ".yml").map((file) => basename(file, extname$1(file)));
13397
16803
  profiles.forEach((p) => profileSet.add(p));
13398
- } catch (error) {
16804
+ } catch (_error) {
13399
16805
  logger.debug("Fallback profiles directory not found", {
13400
16806
  dir: this.fallbackProfilesDir
13401
16807
  });
@@ -13672,7 +17078,7 @@ var ProfileLoader = class {
13672
17078
  * Protected by mutex to prevent race conditions
13673
17079
  */
13674
17080
  async clearCache() {
13675
- await this.initMutex.runExclusive(async () => {
17081
+ await this.initMutex.runExclusive(() => {
13676
17082
  this.cache.clear();
13677
17083
  this.displayNameMap.clear();
13678
17084
  this.mapInitialized = false;
@@ -14447,7 +17853,7 @@ var DelegationParser = class _DelegationParser {
14447
17853
  await this.extractMatches(_DelegationParser.DELEGATION_PATTERNS.chineseRequest, response, fromAgent, delegations, "\u8ACB", resolvedNameCache);
14448
17854
  await this.extractMatches(_DelegationParser.DELEGATION_PATTERNS.chineseFormal, response, fromAgent, delegations, "\u59D4\u6D3E\u7D66", resolvedNameCache);
14449
17855
  delegations.sort((a, b) => a.position - b.position);
14450
- const result = delegations.map(({ position, ...rest }) => rest);
17856
+ const result = delegations.map(({ position: _position, ...rest }) => rest);
14451
17857
  logger.info(`Parsed ${delegations.length} delegation(s)`, {
14452
17858
  fromAgent,
14453
17859
  delegations: result.map((d) => ({ toAgent: d.toAgent, taskPreview: d.task.substring(0, 50) }))
@@ -15487,7 +18893,7 @@ var ParallelAgentExecutor = class {
15487
18893
  /**
15488
18894
  * Execute a batch of agents in parallel
15489
18895
  */
15490
- async executeBatchParallel(batch, graph, context, options, results, timeline, executionStartTime) {
18896
+ async executeBatchParallel(batch, graph, context, options, results, timeline, _executionStartTime) {
15491
18897
  logger.info("Executing batch in parallel", { agents: batch });
15492
18898
  const promises = batch.map(async (agentName) => {
15493
18899
  const node = graph.nodes.get(agentName);
@@ -15721,7 +19127,7 @@ var ParallelAgentExecutor = class {
15721
19127
  /**
15722
19128
  * Mark batch as cancelled
15723
19129
  */
15724
- markBatchAsCancelled(batch, graph, timeline, executionStartTime) {
19130
+ markBatchAsCancelled(batch, graph, timeline, _executionStartTime) {
15725
19131
  const now = Date.now();
15726
19132
  for (const agentName of batch) {
15727
19133
  const node = graph.nodes.get(agentName);
@@ -15861,6 +19267,9 @@ var ParallelAgentExecutor = class {
15861
19267
  };
15862
19268
 
15863
19269
  // src/agents/executor.ts
19270
+ function isErrorLike(error) {
19271
+ return typeof error === "object" && error !== null;
19272
+ }
15864
19273
  var AgentExecutor = class {
15865
19274
  sessionManager;
15866
19275
  workspaceManager;
@@ -15990,7 +19399,7 @@ Retry attempt ${attempt}/${maxAttempts}...`));
15990
19399
  }
15991
19400
  return await this.executeInternal(context, options);
15992
19401
  } catch (error) {
15993
- lastError = error;
19402
+ lastError = error instanceof Error ? error : new Error(String(error));
15994
19403
  const isRetryable = this.isRetryableError(error, retryableErrors);
15995
19404
  if (!isRetryable || attempt >= maxAttempts) {
15996
19405
  throw error;
@@ -16000,7 +19409,8 @@ Retry attempt ${attempt}/${maxAttempts}...`));
16000
19409
  maxDelay
16001
19410
  );
16002
19411
  if (verbose) {
16003
- console.log(chalk4.yellow(`Retryable error occurred: ${error.message}`));
19412
+ const errorMessage = error instanceof Error ? error.message : String(error);
19413
+ console.log(chalk4.yellow(`Retryable error occurred: ${errorMessage}`));
16004
19414
  console.log(chalk4.gray(`Waiting ${delay}ms before retry...`));
16005
19415
  }
16006
19416
  await this.sleep(delay, signal);
@@ -16015,7 +19425,7 @@ Retry attempt ${attempt}/${maxAttempts}...`));
16015
19425
  */
16016
19426
  async executeWithTimeout(context, options) {
16017
19427
  const timeout = options.timeout;
16018
- const { verbose = false } = options;
19428
+ const { verbose: _verbose = false } = options;
16019
19429
  let timeoutId = null;
16020
19430
  const controller = new AbortController();
16021
19431
  const executionOptions = {
@@ -16713,7 +20123,12 @@ ${context.task}`;
16713
20123
  */
16714
20124
  isRetryableError(error, retryableErrors) {
16715
20125
  const patterns = retryableErrors || this.defaultRetryConfig.retryableErrors;
16716
- const errorString = (error.message || error.code || "").toLowerCase();
20126
+ let errorString = "";
20127
+ if (isErrorLike(error)) {
20128
+ errorString = (error.message || error.code || "").toLowerCase();
20129
+ } else if (typeof error === "string") {
20130
+ errorString = error.toLowerCase();
20131
+ }
16717
20132
  return patterns.some(
16718
20133
  (pattern) => errorString.includes(pattern.toLowerCase())
16719
20134
  );
@@ -18141,7 +21556,7 @@ function categorizeTools(name) {
18141
21556
  if (name.includes("context")) return "context";
18142
21557
  return "execution";
18143
21558
  }
18144
- function getExecutionMode(providerName, providerConfig) {
21559
+ function getExecutionMode(providerName, _providerConfig) {
18145
21560
  if (providerName === "glm" || providerName === "grok") {
18146
21561
  return "sdk";
18147
21562
  }
@@ -18600,13 +22015,14 @@ function compressWithInfo(payload, options = {}) {
18600
22015
  init_esm_shims();
18601
22016
  init_factory();
18602
22017
  init_logger();
22018
+ init_validation_limits();
18603
22019
  var NATIVE_MODULE_ERROR_PATTERNS = [
18604
22020
  "NODE_MODULE_VERSION",
18605
22021
  "was compiled against a different Node.js version",
18606
22022
  "better_sqlite3.node"
18607
22023
  ];
18608
22024
  var DEFAULT_CONFIG3 = {
18609
- dbPath: ".automatosx/tasks/tasks.db",
22025
+ dbPath: `${AX_PATHS.TASKS}/tasks.db`,
18610
22026
  maxPayloadBytes: 1024 * 1024,
18611
22027
  // 1MB
18612
22028
  compressionEnabled: true,
@@ -18614,7 +22030,7 @@ var DEFAULT_CONFIG3 = {
18614
22030
  defaultTtlHours: 24,
18615
22031
  maxTtlHours: 168,
18616
22032
  // 7 days
18617
- busyTimeout: 5e3
22033
+ busyTimeout: DATABASE.BUSY_TIMEOUT
18618
22034
  };
18619
22035
  var SQL = {
18620
22036
  CREATE_TABLE: `
@@ -20133,7 +23549,6 @@ function createRunTaskHandler(deps) {
20133
23549
  });
20134
23550
  try {
20135
23551
  const taskEngine = getTaskEngine();
20136
- const session = deps.getSession();
20137
23552
  const options = {
20138
23553
  engineOverride: input.engine_override,
20139
23554
  timeoutMs: input.timeout_ms,
@@ -20627,7 +24042,11 @@ var McpClient = class _McpClient extends EventEmitter {
20627
24042
  const params = {
20628
24043
  protocolVersion: MCP_PROTOCOL_VERSION,
20629
24044
  capabilities: {
20630
- tools: {}
24045
+ tools: {},
24046
+ resources: {},
24047
+ prompts: {},
24048
+ resourceTemplates: {},
24049
+ experimental: {}
20631
24050
  },
20632
24051
  clientInfo: {
20633
24052
  name: "automatosx",
@@ -22386,7 +25805,6 @@ var CodexEventNormalizer = class extends BaseEventNormalizer {
22386
25805
  const inputTokens = event.inputTokens ?? 0;
22387
25806
  const outputTokens = event.outputTokens ?? 0;
22388
25807
  this.tokenCount = inputTokens + outputTokens;
22389
- Date.now() - this.startTime;
22390
25808
  return this.createEvent("execution.progress", {
22391
25809
  agent: "codex",
22392
25810
  progress: 100,
@@ -22433,6 +25851,93 @@ var CodexEventNormalizer = class extends BaseEventNormalizer {
22433
25851
  }
22434
25852
  };
22435
25853
 
25854
+ // src/mcp/resource-templates.ts
25855
+ init_esm_shims();
25856
+ var AGENT_TEMPLATE_NAME = "agent_profile";
25857
+ var AGENT_URI_TEMPLATE = "agent/{agent}";
25858
+ var WORKSPACE_PRD_TEMPLATE_NAME = "workspace_prd_file";
25859
+ var WORKSPACE_PRD_URI_TEMPLATE = "workspace/prd/{path}";
25860
+ var WORKSPACE_TMP_TEMPLATE_NAME = "workspace_tmp_file";
25861
+ var WORKSPACE_TMP_URI_TEMPLATE = "workspace/tmp/{path}";
25862
+ var RESOURCE_TEMPLATES = [
25863
+ {
25864
+ name: AGENT_TEMPLATE_NAME,
25865
+ uriTemplate: AGENT_URI_TEMPLATE,
25866
+ description: "Render an AutomatosX agent profile by name",
25867
+ mimeType: "text/markdown",
25868
+ variableDefinitions: [
25869
+ { name: "agent", description: "Agent name", required: true }
25870
+ ]
25871
+ },
25872
+ {
25873
+ name: WORKSPACE_PRD_TEMPLATE_NAME,
25874
+ uriTemplate: WORKSPACE_PRD_URI_TEMPLATE,
25875
+ description: "Read a PRD workspace file (automatosx/PRD)",
25876
+ mimeType: "text/markdown",
25877
+ variableDefinitions: [
25878
+ { name: "path", description: "Relative path under automatosx/PRD", required: true }
25879
+ ]
25880
+ },
25881
+ {
25882
+ name: WORKSPACE_TMP_TEMPLATE_NAME,
25883
+ uriTemplate: WORKSPACE_TMP_URI_TEMPLATE,
25884
+ description: "Read a temporary workspace file (automatosx/tmp)",
25885
+ mimeType: "text/markdown",
25886
+ variableDefinitions: [
25887
+ { name: "path", description: "Relative path under automatosx/tmp", required: true }
25888
+ ]
25889
+ }
25890
+ ];
25891
+ function listResourceTemplates() {
25892
+ return RESOURCE_TEMPLATES;
25893
+ }
25894
+ async function resolveResourceTemplate(uri, variables, profileLoader, workspaceManager) {
25895
+ if (uri === AGENT_URI_TEMPLATE) {
25896
+ const agent = variables?.agent;
25897
+ if (!agent) {
25898
+ throw new Error("Missing required variable: agent");
25899
+ }
25900
+ const profile = await profileLoader.loadProfile(agent);
25901
+ const summary = [
25902
+ `# ${agent}`,
25903
+ profile.role ? `**Role:** ${profile.role}` : "",
25904
+ profile.abilities?.length ? `**Abilities:** ${profile.abilities.join(", ")}` : "",
25905
+ "",
25906
+ profile.systemPrompt || "No system prompt defined."
25907
+ ].filter(Boolean).join("\n");
25908
+ return {
25909
+ uri: `agent/${agent}`,
25910
+ name: `Agent: ${agent}`,
25911
+ description: `AutomatosX agent profile for ${agent}`,
25912
+ mimeType: "text/markdown",
25913
+ contents: [
25914
+ { type: "text", text: summary },
25915
+ { type: "application/json", json: profile }
25916
+ ]
25917
+ };
25918
+ }
25919
+ if (uri === WORKSPACE_PRD_URI_TEMPLATE || uri === WORKSPACE_TMP_URI_TEMPLATE) {
25920
+ const path7 = variables?.path;
25921
+ if (!path7) {
25922
+ throw new Error("Missing required variable: path");
25923
+ }
25924
+ const isPrd = uri === WORKSPACE_PRD_URI_TEMPLATE;
25925
+ const readFn = isPrd ? workspaceManager.readPRD.bind(workspaceManager) : workspaceManager.readTmp.bind(workspaceManager);
25926
+ const content = await readFn(path7);
25927
+ return {
25928
+ uri: `${isPrd ? "prd" : "tmp"}/${path7}`,
25929
+ name: `${isPrd ? "PRD" : "Tmp"}: ${path7}`,
25930
+ description: `Workspace ${isPrd ? "PRD" : "tmp"} file`,
25931
+ mimeType: "text/markdown",
25932
+ contents: [
25933
+ { type: "text", text: content },
25934
+ { type: "application/json", json: { path: path7, content, workspace: isPrd ? "PRD" : "tmp" } }
25935
+ ]
25936
+ };
25937
+ }
25938
+ throw new Error(`Unknown resource template: ${uri}`);
25939
+ }
25940
+
22436
25941
  // src/mcp/server.ts
22437
25942
  var CLIENT_PATTERNS = [
22438
25943
  [["claude"], "claude"],
@@ -22468,6 +25973,8 @@ var McpServer = class _McpServer {
22468
25973
  // Track client-initiated cancellations
22469
25974
  requestControllers = /* @__PURE__ */ new Map();
22470
25975
  // Abort long-running handlers
25976
+ toolAllowlist;
25977
+ authToken;
22471
25978
  // v10.5.0: MCP Session for Smart Routing
22472
25979
  session = null;
22473
25980
  // v10.6.0: MCP Client Pool for cross-provider execution
@@ -22476,6 +25983,7 @@ var McpServer = class _McpServer {
22476
25983
  eventBridge = null;
22477
25984
  streamingNotifier = null;
22478
25985
  enableStreamingNotifications = true;
25986
+ negotiatedProtocolVersion = MCP_PROTOCOL_VERSION;
22479
25987
  // Shared services (initialized once per server)
22480
25988
  router;
22481
25989
  memoryManager;
@@ -22489,6 +25997,12 @@ var McpServer = class _McpServer {
22489
25997
  if (options.debug) {
22490
25998
  setLogLevel("debug");
22491
25999
  }
26000
+ if (options.toolAllowlist?.length) {
26001
+ this.toolAllowlist = new Set(options.toolAllowlist);
26002
+ }
26003
+ if (options.authToken) {
26004
+ this.authToken = options.authToken;
26005
+ }
22492
26006
  this.enableStreamingNotifications = options.enableStreamingNotifications ?? true;
22493
26007
  this.version = getVersion();
22494
26008
  this.ajv = new Ajv({ allErrors: true });
@@ -22498,6 +26012,24 @@ var McpServer = class _McpServer {
22498
26012
  streamingNotifications: this.enableStreamingNotifications
22499
26013
  });
22500
26014
  }
26015
+ /** Determine if negotiated protocol is v2 */
26016
+ isV2Protocol() {
26017
+ return this.negotiatedProtocolVersion === MCP_SUPPORTED_VERSIONS[0];
26018
+ }
26019
+ /** Build capability set based on negotiated protocol */
26020
+ buildCapabilities() {
26021
+ const base = { tools: {} };
26022
+ if (this.isV2Protocol()) {
26023
+ return {
26024
+ ...base,
26025
+ resources: {},
26026
+ prompts: {},
26027
+ resourceTemplates: {},
26028
+ experimental: {}
26029
+ };
26030
+ }
26031
+ return base;
26032
+ }
22501
26033
  /**
22502
26034
  * Get static tool schemas (no initialization required)
22503
26035
  * Returns tool schemas that can be provided during MCP handshake
@@ -22657,36 +26189,61 @@ Use this tool first to understand what AutomatosX offers.`,
22657
26189
  const projectDir = process.cwd();
22658
26190
  const config = await loadConfig(projectDir);
22659
26191
  const teamManager = new TeamManager(
22660
- join(projectDir, ".automatosx", "teams")
26192
+ join(projectDir, AX_PATHS.TEAMS)
22661
26193
  );
22662
26194
  this.profileLoader = new ProfileLoader(
22663
- join(projectDir, ".automatosx", "agents"),
26195
+ join(projectDir, AX_PATHS.AGENTS),
22664
26196
  void 0,
22665
26197
  teamManager
22666
26198
  );
22667
26199
  const abilitiesManager = new AbilitiesManager(
22668
- join(projectDir, ".automatosx", "abilities")
26200
+ join(projectDir, AX_PATHS.ABILITIES)
22669
26201
  );
22670
26202
  this.memoryManager = new LazyMemoryManager({
22671
- dbPath: join(projectDir, ".automatosx", "memory", "memory.db")
26203
+ dbPath: join(projectDir, AX_PATHS.MEMORY, "memory.db")
22672
26204
  });
22673
26205
  this.pathResolver = new PathResolver({
22674
26206
  projectDir,
22675
26207
  workingDir: process.cwd(),
22676
- agentWorkspace: join(projectDir, ".automatosx", "workspaces")
26208
+ agentWorkspace: join(projectDir, AX_PATHS.WORKSPACES)
22677
26209
  });
22678
26210
  const providers = [];
22679
26211
  if (config.providers["claude-code"]?.enabled) {
22680
26212
  const { ClaudeProvider: ClaudeProvider2 } = await Promise.resolve().then(() => (init_claude_provider(), claude_provider_exports));
22681
- providers.push(new ClaudeProvider2({ ...config.providers["claude-code"], name: "claude-code" }));
26213
+ const claudeConfig = config.providers["claude-code"];
26214
+ providers.push(new ClaudeProvider2({ ...claudeConfig, name: "claude-code", command: claudeConfig.command || "claude" }));
22682
26215
  }
22683
26216
  if (config.providers["gemini-cli"]?.enabled) {
22684
26217
  const { GeminiProvider: GeminiProvider2 } = await Promise.resolve().then(() => (init_gemini_provider(), gemini_provider_exports));
22685
- providers.push(new GeminiProvider2({ ...config.providers["gemini-cli"], name: "gemini-cli" }));
26218
+ const geminiConfig = config.providers["gemini-cli"];
26219
+ providers.push(new GeminiProvider2({ ...geminiConfig, name: "gemini-cli", command: geminiConfig.command || "gemini" }));
22686
26220
  }
22687
26221
  if (config.providers["openai"]?.enabled) {
22688
26222
  const { createOpenAIProviderSync: createOpenAIProviderSync2 } = await Promise.resolve().then(() => (init_openai_provider_factory(), openai_provider_factory_exports));
22689
- providers.push(createOpenAIProviderSync2({ ...config.providers["openai"], name: "openai" }, config.providers["openai"].integration));
26223
+ const openaiConfig = config.providers["openai"];
26224
+ providers.push(createOpenAIProviderSync2({ ...openaiConfig, name: "openai", command: openaiConfig.command || "codex" }, openaiConfig.integration));
26225
+ }
26226
+ if (config.providers["glm"]?.enabled) {
26227
+ const { GLMProvider: GLMProvider2 } = await Promise.resolve().then(() => (init_glm_provider(), glm_provider_exports));
26228
+ const glmConfig = config.providers["glm"];
26229
+ providers.push(new GLMProvider2({
26230
+ name: "glm",
26231
+ enabled: true,
26232
+ priority: glmConfig.priority,
26233
+ timeout: glmConfig.timeout,
26234
+ mode: "sdk"
26235
+ }));
26236
+ }
26237
+ if (config.providers["grok"]?.enabled) {
26238
+ const { GrokProvider: GrokProvider2 } = await Promise.resolve().then(() => (init_grok_provider(), grok_provider_exports));
26239
+ const grokConfig = config.providers["grok"];
26240
+ providers.push(new GrokProvider2({
26241
+ name: "grok",
26242
+ enabled: true,
26243
+ priority: grokConfig.priority,
26244
+ timeout: grokConfig.timeout,
26245
+ mode: "sdk"
26246
+ }));
22690
26247
  }
22691
26248
  const healthCheckInterval = config.router?.healthCheckInterval;
22692
26249
  this.router = new Router({
@@ -22840,9 +26397,7 @@ Use this tool first to understand what AutomatosX offers.`,
22840
26397
  register("create_task", createCreateTaskHandler({
22841
26398
  getSession: () => this.session
22842
26399
  }));
22843
- register("run_task", createRunTaskHandler({
22844
- getSession: () => this.session
22845
- }));
26400
+ register("run_task", createRunTaskHandler());
22846
26401
  register("get_task_result", createGetTaskResultHandler());
22847
26402
  register("list_tasks", createListTasksHandler());
22848
26403
  register("delete_task", createDeleteTaskHandler());
@@ -22877,6 +26432,14 @@ Use this tool first to understand what AutomatosX offers.`,
22877
26432
  return await this.handleResourcesList(request, responseId);
22878
26433
  case "resources/read":
22879
26434
  return await this.handleResourceRead(request, responseId);
26435
+ case "resources/templates/list":
26436
+ return await this.handleResourceTemplatesList(request, responseId);
26437
+ case "resources/templates/read":
26438
+ return await this.handleResourceTemplateRead(request, responseId);
26439
+ case "prompts/list":
26440
+ return await this.handlePromptsList(request, responseId);
26441
+ case "prompts/get":
26442
+ return await this.handlePromptGet(request, responseId);
22880
26443
  case "$/cancelRequest":
22881
26444
  return this.handleCancelRequest(request, responseId);
22882
26445
  default:
@@ -22915,9 +26478,12 @@ Use this tool first to understand what AutomatosX offers.`,
22915
26478
  clientName: clientInfo.name,
22916
26479
  normalizedProvider: this.session.normalizedProvider
22917
26480
  });
26481
+ const requestedProtocol = request.params?.protocolVersion;
26482
+ const negotiated = MCP_SUPPORTED_VERSIONS.find((version) => version === requestedProtocol) ?? "2024-11-05";
26483
+ this.negotiatedProtocolVersion = negotiated;
22918
26484
  const response = {
22919
- protocolVersion: MCP_PROTOCOL_VERSION,
22920
- capabilities: { tools: {} },
26485
+ protocolVersion: negotiated,
26486
+ capabilities: this.buildCapabilities(),
22921
26487
  serverInfo: { name: "automatosx", version: this.version }
22922
26488
  };
22923
26489
  logger.info("[MCP Server] Initialize handshake complete (< 1ms)");
@@ -22931,7 +26497,11 @@ Use this tool first to understand what AutomatosX offers.`,
22931
26497
  */
22932
26498
  handleToolsList(_request, id) {
22933
26499
  logger.debug("[MCP Server] Tools list requested (static schemas)");
22934
- const tools = _McpServer.getStaticToolSchemas();
26500
+ const tools = _McpServer.getStaticToolSchemas().map((schema) => ({
26501
+ ...schema,
26502
+ // If allowlist is set, hide tools not allowed
26503
+ ...this.toolAllowlist && !this.toolAllowlist.has(schema.name) ? { hidden: true } : {}
26504
+ }));
22935
26505
  return { jsonrpc: "2.0", id, result: { tools } };
22936
26506
  }
22937
26507
  /**
@@ -22948,6 +26518,81 @@ Use this tool first to understand what AutomatosX offers.`,
22948
26518
  }));
22949
26519
  return { jsonrpc: "2.0", id, result: { resources } };
22950
26520
  }
26521
+ /**
26522
+ * Handle resources/templates/list request (v2 capability)
26523
+ */
26524
+ async handleResourceTemplatesList(_request, id) {
26525
+ if (!this.isV2Protocol()) {
26526
+ return this.createErrorResponse(id, -32601 /* MethodNotFound */, "resources/templates/list is only available in MCP v2");
26527
+ }
26528
+ await this.ensureInitialized();
26529
+ const resourceTemplates = listResourceTemplates();
26530
+ return { jsonrpc: "2.0", id, result: { resourceTemplates } };
26531
+ }
26532
+ /**
26533
+ * Handle prompts/list request (expose common starter prompts)
26534
+ */
26535
+ async handlePromptsList(_request, id) {
26536
+ await this.ensureInitialized();
26537
+ const prompts = [
26538
+ {
26539
+ name: "agent_context",
26540
+ description: "Get agent context and system prompt for a given agent name",
26541
+ arguments: [{ name: "agent", required: true, description: "Agent name" }]
26542
+ },
26543
+ {
26544
+ name: "status",
26545
+ description: "Get AutomatosX MCP status summary"
26546
+ }
26547
+ ];
26548
+ return { jsonrpc: "2.0", id, result: { prompts } };
26549
+ }
26550
+ /**
26551
+ * Handle prompts/get request
26552
+ */
26553
+ async handlePromptGet(request, id) {
26554
+ await this.ensureInitialized();
26555
+ const name = request.params?.name;
26556
+ if (!name) {
26557
+ return this.createErrorResponse(id, -32602 /* InvalidParams */, "Prompt name is required");
26558
+ }
26559
+ switch (name) {
26560
+ case "agent_context": {
26561
+ const agent = request.params?.arguments?.agent;
26562
+ if (!agent) {
26563
+ return this.createErrorResponse(id, -32602 /* InvalidParams */, "agent argument is required");
26564
+ }
26565
+ try {
26566
+ const profile = await this.profileLoader.loadProfile(agent);
26567
+ const content = [
26568
+ { type: "text", text: `System prompt for ${agent}:
26569
+ ${profile.systemPrompt || "No system prompt defined."}` },
26570
+ { type: "application/json", json: profile }
26571
+ ];
26572
+ return { jsonrpc: "2.0", id, result: { prompt: { name, description: "Agent context", arguments: [{ name: "agent", required: true }] }, content } };
26573
+ } catch (error) {
26574
+ return this.createErrorResponse(id, -32603 /* InternalError */, `Failed to load agent: ${error.message}`);
26575
+ }
26576
+ }
26577
+ case "status": {
26578
+ const summary = {
26579
+ version: this.version,
26580
+ providerCount: this.router?.providerCount ?? 0,
26581
+ streamingNotifications: this.enableStreamingNotifications
26582
+ };
26583
+ const content = [
26584
+ { type: "text", text: `AutomatosX MCP status:
26585
+ Version: ${summary.version}
26586
+ Providers: ${summary.providerCount}
26587
+ Streaming: ${summary.streamingNotifications}` },
26588
+ { type: "application/json", json: summary }
26589
+ ];
26590
+ return { jsonrpc: "2.0", id, result: { prompt: { name, description: "AutomatosX status" }, content } };
26591
+ }
26592
+ default:
26593
+ return this.createErrorResponse(id, -32601 /* MethodNotFound */, `Prompt not found: ${name}`);
26594
+ }
26595
+ }
22951
26596
  /**
22952
26597
  * Handle resources/read request
22953
26598
  */
@@ -22976,6 +26621,30 @@ Use this tool first to understand what AutomatosX offers.`,
22976
26621
  return this.createErrorResponse(id, -32603 /* InternalError */, `Failed to read resource: ${error.message}`);
22977
26622
  }
22978
26623
  }
26624
+ /**
26625
+ * Handle resources/templates/read request (v2 capability)
26626
+ */
26627
+ async handleResourceTemplateRead(request, id) {
26628
+ if (!this.isV2Protocol()) {
26629
+ return this.createErrorResponse(id, -32601 /* MethodNotFound */, "resources/templates/read is only available in MCP v2");
26630
+ }
26631
+ await this.ensureInitialized();
26632
+ const uri = request.params?.uri;
26633
+ try {
26634
+ if (!uri) {
26635
+ return this.createErrorResponse(id, -32602 /* InvalidParams */, "Missing resource template URI");
26636
+ }
26637
+ const resolved = await resolveResourceTemplate(
26638
+ uri,
26639
+ request.params?.variables,
26640
+ this.profileLoader,
26641
+ this.workspaceManager
26642
+ );
26643
+ return { jsonrpc: "2.0", id, result: resolved };
26644
+ } catch (error) {
26645
+ return this.createErrorResponse(id, -32603 /* InternalError */, `Failed to read resource template: ${error.message}`);
26646
+ }
26647
+ }
22979
26648
  /**
22980
26649
  * Validate tool input against its JSON schema.
22981
26650
  * Returns null if valid, or error message string if invalid.
@@ -23050,6 +26719,16 @@ Use this tool first to understand what AutomatosX offers.`,
23050
26719
  const { name, arguments: args2 } = request.params;
23051
26720
  logger.info("[MCP Server] Tool call", { tool: name });
23052
26721
  const requestId = id ?? null;
26722
+ if (this.toolAllowlist && !this.toolAllowlist.has(name)) {
26723
+ return this.createErrorResponse(id, -32600 /* InvalidRequest */, `Tool not allowed: ${name}`);
26724
+ }
26725
+ const schema = this.toolSchemas.find((t) => t.name === name);
26726
+ if (schema?.requiresAuth && this.authToken) {
26727
+ const provided = args2?.auth_token;
26728
+ if (provided !== this.authToken) {
26729
+ return this.createErrorResponse(id, -32600 /* InvalidRequest */, "Unauthorized: invalid auth token");
26730
+ }
26731
+ }
23053
26732
  const abortController = requestId !== null ? new AbortController() : null;
23054
26733
  if (requestId !== null && abortController) {
23055
26734
  this.requestControllers.set(requestId, abortController);
@@ -23113,20 +26792,21 @@ Use this tool first to understand what AutomatosX offers.`,
23113
26792
  logger.debug("[MCP Server] Response sent", { id: response.id, length: json.length });
23114
26793
  }
23115
26794
  /**
23116
- * Start stdio server with newline-delimited framing
26795
+ * Start stdio server with hybrid framing support
23117
26796
  *
23118
- * v12.2.0: Changed from Content-Length to newline-delimited framing
23119
- * per official MCP specification: https://spec.modelcontextprotocol.io/specification/basic/transports/
26797
+ * v12.3.1: Supports BOTH framing formats for maximum compatibility:
26798
+ * 1. Newline-delimited (official MCP spec, used by Claude Code, @modelcontextprotocol/sdk)
26799
+ * 2. Content-Length (LSP-style, used by ax-glm, ax-grok, some older clients)
23120
26800
  *
23121
- * Format: Each JSON-RPC message is terminated by a newline character.
23122
- * Messages MUST NOT contain embedded newlines.
23123
- * Reference: @modelcontextprotocol/sdk ReadBuffer uses: buffer.indexOf('\n')
26801
+ * Detection: If first line starts with "Content-Length:", use LSP framing.
26802
+ * Otherwise, use newline-delimited framing.
23124
26803
  *
23125
26804
  * BUG FIX (v9.0.1): Added iteration limit and buffer size checks to prevent infinite loops
23126
26805
  */
23127
26806
  async start() {
23128
26807
  logger.info("[MCP Server] Starting stdio JSON-RPC server...");
23129
26808
  let buffer = "";
26809
+ let detectedFraming = null;
23130
26810
  process.stdin.on("data", (chunk) => {
23131
26811
  void this.stdinMutex.runExclusive(async () => {
23132
26812
  buffer += chunk.toString("utf-8");
@@ -23138,17 +26818,49 @@ Use this tool first to understand what AutomatosX offers.`,
23138
26818
  buffer = "";
23139
26819
  return;
23140
26820
  }
26821
+ if (detectedFraming === null) {
26822
+ if (buffer.startsWith("Content-Length:")) {
26823
+ detectedFraming = "content-length";
26824
+ logger.info("[MCP Server] Detected Content-Length framing (LSP-style)");
26825
+ } else if (buffer.includes("{")) {
26826
+ detectedFraming = "newline";
26827
+ logger.info("[MCP Server] Detected newline-delimited framing (MCP spec)");
26828
+ }
26829
+ }
23141
26830
  let iterations = 0;
23142
26831
  while (iterations < STDIO_MAX_ITERATIONS) {
23143
26832
  iterations++;
23144
- const newlineIndex = buffer.indexOf("\n");
23145
- if (newlineIndex === -1) break;
23146
- let jsonMessage = buffer.slice(0, newlineIndex);
23147
- if (jsonMessage.endsWith("\r")) {
23148
- jsonMessage = jsonMessage.slice(0, -1);
26833
+ let jsonMessage = null;
26834
+ if (detectedFraming === "content-length") {
26835
+ const headerEnd = buffer.indexOf("\r\n\r\n");
26836
+ if (headerEnd === -1) break;
26837
+ const headers = buffer.slice(0, headerEnd);
26838
+ const contentLengthMatch = headers.match(/Content-Length:\s*(\d+)/i);
26839
+ if (!contentLengthMatch) {
26840
+ const lineEnd = buffer.indexOf("\n");
26841
+ if (lineEnd !== -1) {
26842
+ buffer = buffer.slice(lineEnd + 1);
26843
+ continue;
26844
+ }
26845
+ break;
26846
+ }
26847
+ const contentLength = parseInt(contentLengthMatch[1], 10);
26848
+ const bodyStart = headerEnd + 4;
26849
+ const bodyEnd = bodyStart + contentLength;
26850
+ if (buffer.length < bodyEnd) break;
26851
+ jsonMessage = buffer.slice(bodyStart, bodyEnd);
26852
+ buffer = buffer.slice(bodyEnd);
26853
+ } else {
26854
+ const newlineIndex = buffer.indexOf("\n");
26855
+ if (newlineIndex === -1) break;
26856
+ jsonMessage = buffer.slice(0, newlineIndex);
26857
+ if (jsonMessage.endsWith("\r")) {
26858
+ jsonMessage = jsonMessage.slice(0, -1);
26859
+ }
26860
+ buffer = buffer.slice(newlineIndex + 1);
26861
+ if (jsonMessage.trim() === "") continue;
23149
26862
  }
23150
- buffer = buffer.slice(newlineIndex + 1);
23151
- if (jsonMessage.trim() === "") continue;
26863
+ if (!jsonMessage) break;
23152
26864
  if (jsonMessage.length > STDIO_MAX_MESSAGE_SIZE) {
23153
26865
  logger.error("[MCP Server] Message size exceeded maximum", {
23154
26866
  messageSize: jsonMessage.length,
@@ -23191,7 +26903,7 @@ Use this tool first to understand what AutomatosX offers.`,
23191
26903
  process.stdin.on("end", () => shutdown("Server stopped (stdin closed)"));
23192
26904
  process.on("SIGINT", () => shutdown("Received SIGINT, shutting down..."));
23193
26905
  process.on("SIGTERM", () => shutdown("Received SIGTERM, shutting down..."));
23194
- logger.info("[MCP Server] Server started successfully (newline-delimited framing)");
26906
+ logger.info("[MCP Server] Server started successfully (hybrid framing: newline + Content-Length)");
23195
26907
  }
23196
26908
  };
23197
26909