@defai.digital/automatosx 12.6.1 → 12.6.3

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
@@ -22,7 +22,6 @@ import { EventEmitter } from 'events';
22
22
  import { findUp } from 'find-up';
23
23
  import * as sqliteVec from 'sqlite-vec';
24
24
  import { randomUUID, randomBytes, createHash } from 'crypto';
25
- import yaml from 'yaml';
26
25
  import { gzipSync, gunzipSync } from 'zlib';
27
26
 
28
27
  var __defProp = Object.defineProperty;
@@ -772,6 +771,119 @@ var init_errors = __esm({
772
771
  }
773
772
  });
774
773
 
774
+ // src/shared/utils/safe-timers.ts
775
+ function createSafeInterval(callback, intervalMs, options = {}) {
776
+ const { ref = false, name, signal, immediate = false } = options;
777
+ if (signal?.aborted) {
778
+ logger.debug("createSafeInterval: already aborted", { name });
779
+ return () => {
780
+ };
781
+ }
782
+ let cleared = false;
783
+ let intervalId = null;
784
+ const safeCallback = async () => {
785
+ if (cleared) return;
786
+ try {
787
+ await callback();
788
+ } catch (error) {
789
+ logger.error("Safe interval callback error", {
790
+ name,
791
+ error: error.message
792
+ });
793
+ }
794
+ };
795
+ if (immediate) {
796
+ setImmediate(() => {
797
+ if (!cleared) {
798
+ safeCallback();
799
+ }
800
+ });
801
+ }
802
+ intervalId = setInterval(safeCallback, intervalMs);
803
+ if (!ref && intervalId.unref) {
804
+ intervalId.unref();
805
+ }
806
+ const cleanup = () => {
807
+ if (cleared) return;
808
+ cleared = true;
809
+ if (intervalId !== null) {
810
+ clearInterval(intervalId);
811
+ intervalId = null;
812
+ logger.debug("Safe interval cleared", { name });
813
+ }
814
+ };
815
+ if (signal) {
816
+ signal.addEventListener("abort", cleanup, { once: true });
817
+ }
818
+ logger.debug("Safe interval created", {
819
+ name,
820
+ intervalMs,
821
+ ref,
822
+ immediate
823
+ });
824
+ return cleanup;
825
+ }
826
+ function createSafeTimeout(callback, delayMs, options = {}) {
827
+ const { ref = false, name, signal } = options;
828
+ if (signal?.aborted) {
829
+ logger.debug("createSafeTimeout: already aborted", { name });
830
+ return () => {
831
+ };
832
+ }
833
+ let cleared = false;
834
+ let timeoutId = null;
835
+ const safeCallback = async () => {
836
+ if (cleared) return;
837
+ cleared = true;
838
+ try {
839
+ await callback();
840
+ } catch (error) {
841
+ logger.error("Safe timeout callback error", {
842
+ name,
843
+ error: error.message
844
+ });
845
+ }
846
+ };
847
+ timeoutId = setTimeout(safeCallback, delayMs);
848
+ if (!ref && timeoutId.unref) {
849
+ timeoutId.unref();
850
+ }
851
+ const cleanup = () => {
852
+ if (cleared) return;
853
+ cleared = true;
854
+ if (timeoutId !== null) {
855
+ clearTimeout(timeoutId);
856
+ timeoutId = null;
857
+ logger.debug("Safe timeout cleared", { name });
858
+ }
859
+ };
860
+ if (signal) {
861
+ signal.addEventListener("abort", cleanup, { once: true });
862
+ }
863
+ logger.debug("Safe timeout created", {
864
+ name,
865
+ delayMs,
866
+ ref
867
+ });
868
+ return cleanup;
869
+ }
870
+ async function sleep(ms, signal) {
871
+ return new Promise((resolve5, reject) => {
872
+ const timeoutId = setTimeout(() => {
873
+ resolve5();
874
+ }, ms);
875
+ if (timeoutId.unref) {
876
+ timeoutId.unref();
877
+ }
878
+ });
879
+ }
880
+ var init_safe_timers = __esm({
881
+ "src/shared/utils/safe-timers.ts"() {
882
+ init_esm_shims();
883
+ init_logger();
884
+ }
885
+ });
886
+
775
887
  // src/shared/process/process-manager.ts
776
888
  var process_manager_exports = {};
777
889
  __export(process_manager_exports, {
@@ -2379,6 +2491,7 @@ function getRetryableErrors(provider) {
2379
2491
  return [...baseErrors, ...CODEX_RETRYABLE_ERRORS];
2380
2492
  case "glm":
2381
2493
  case "grok":
2494
+ case "qwen":
2382
2495
  return [...baseErrors, ...OPENAI_RETRYABLE_ERRORS];
2383
2496
  case "base":
2384
2497
  default:
@@ -2481,6 +2594,10 @@ var init_base_provider = __esm({
2481
2594
  // v12.0.0: Native Grok provider (xAI)
2482
2595
  "ax-grok",
2483
2596
  // v12.0.0: Alias for grok
2597
+ "qwen",
2598
+ // v12.7.0: Qwen Code provider (Alibaba Cloud)
2599
+ "qwen-code",
2600
+ // v12.7.0: Alias for qwen
2484
2601
  "test-provider"
2485
2602
  // For unit tests
2486
2603
  ];
@@ -2843,7 +2960,7 @@ var init_base_provider = __esm({
2843
2960
  if (readlineInterface) {
2844
2961
  try {
2845
2962
  readlineInterface.close();
2846
- } catch (error) {
2963
+ } catch {
2847
2964
  } finally {
2848
2965
  readlineInterface = null;
2849
2966
  }
@@ -2851,7 +2968,7 @@ var init_base_provider = __esm({
2851
2968
  if (stderrInterface) {
2852
2969
  try {
2853
2970
  stderrInterface.close();
2854
- } catch (error) {
2971
+ } catch {
2855
2972
  } finally {
2856
2973
  stderrInterface = null;
2857
2974
  }
@@ -3045,7 +3162,7 @@ ${fullPrompt}
3045
3162
  this.health.consecutiveSuccesses = 0;
3046
3163
  }
3047
3164
  return available;
3048
- } catch (error) {
3165
+ } catch {
3049
3166
  this.health.available = false;
3050
3167
  this.health.errorRate = 1;
3051
3168
  this.health.lastCheck = Date.now();
@@ -3221,6 +3338,8 @@ ${fullPrompt}
3221
3338
  retryableProvider = "glm";
3222
3339
  } else if (providerName === "grok" || providerName === "ax-grok") {
3223
3340
  retryableProvider = "grok";
3341
+ } else if (providerName === "qwen" || providerName === "qwen-code") {
3342
+ retryableProvider = "qwen";
3224
3343
  }
3225
3344
  return shouldRetryError(error, retryableProvider);
3226
3345
  }
@@ -5295,6 +5414,7 @@ var init_hybrid_adapter_base = __esm({
5295
5414
  init_flags();
5296
5415
  init_fallback_decision();
5297
5416
  init_provider_metrics();
5417
+ init_safe_timers();
5298
5418
  DEFAULT_CIRCUIT_BREAKER_CONFIG = {
5299
5419
  failureThreshold: 3,
5300
5420
  resetTimeout: 6e4,
@@ -5449,7 +5569,7 @@ var init_hybrid_adapter_base = __esm({
5449
5569
  });
5450
5570
  if (classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt < this.maxRetries) {
5451
5571
  const delay = classification.retryDelayMs || 1e3;
5452
- await this.sleep(delay);
5572
+ await sleep(delay);
5453
5573
  continue;
5454
5574
  }
5455
5575
  if (classification.decision === "use_cli" /* USE_CLI */ || classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt >= this.maxRetries) {
@@ -5624,12 +5744,6 @@ var init_hybrid_adapter_base = __esm({
5624
5744
  } catch {
5625
5745
  }
5626
5746
  }
5627
- /**
5628
- * Sleep utility
5629
- */
5630
- sleep(ms) {
5631
- return new Promise((resolve5) => setTimeout(resolve5, ms));
5632
- }
5633
5747
  /**
5634
5748
  * Get current active mode
5635
5749
  */
@@ -5680,13 +5794,21 @@ var init_types2 = __esm({
5680
5794
  "src/integrations/ax-glm/types.ts"() {
5681
5795
  init_esm_shims();
5682
5796
  GLM_MODEL_MAPPING = {
5797
+ // Convenience aliases (ax-cli v4.3.15)
5798
+ "glm-latest": "glm-4.6",
5799
+ "glm-vision": "glm-4.6v",
5800
+ "glm-fast": "glm-4-flash",
5801
+ "glm-image": "cogview-4",
5802
+ // Legacy aliases (deprecated)
5683
5803
  "glm-4-plus": "glm-4.6",
5684
- "glm-4v": "glm-4.5v",
5804
+ "glm-4.5v": "glm-4.6v",
5805
+ "glm-4v": "glm-4.6v",
5806
+ "glm-4": "glm-4.6",
5685
5807
  "glm-4-air": "glm-4-flash",
5686
5808
  "glm-4-airx": "glm-4-flash"
5687
5809
  };
5688
5810
  GLM_DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
5689
- GLM_DEFAULT_MODEL = "glm-4";
5811
+ GLM_DEFAULT_MODEL = "glm-4.6";
5690
5812
  GLM_DEFAULT_COMMAND = "ax-glm";
5691
5813
  }
5692
5814
  });
@@ -6225,6 +6347,7 @@ var init_sdk_only_adapter = __esm({
6225
6347
  "src/integrations/ax-glm/sdk-only-adapter.ts"() {
6226
6348
  init_esm_shims();
6227
6349
  init_logger();
6350
+ init_safe_timers();
6228
6351
  init_sdk_adapter2();
6229
6352
  init_types2();
6230
6353
  GLMSdkOnlyAdapter = class {
@@ -6304,7 +6427,7 @@ var init_sdk_only_adapter = __esm({
6304
6427
  attempt: attempt + 1,
6305
6428
  delayMs: delay
6306
6429
  });
6307
- await this.sleep(delay);
6430
+ await sleep(delay);
6308
6431
  continue;
6309
6432
  }
6310
6433
  break;
@@ -6340,12 +6463,6 @@ var init_sdk_only_adapter = __esm({
6340
6463
  }
6341
6464
  return false;
6342
6465
  }
6343
- /**
6344
- * Sleep utility
6345
- */
6346
- sleep(ms) {
6347
- return new Promise((resolve5) => setTimeout(resolve5, ms));
6348
- }
6349
6466
  /**
6350
6467
  * Get the configured model
6351
6468
  */
@@ -6640,10 +6757,18 @@ var init_types3 = __esm({
6640
6757
  "src/integrations/ax-grok/types.ts"() {
6641
6758
  init_esm_shims();
6642
6759
  GROK_MODEL_MAPPING = {
6643
- "grok-beta": "grok-3"
6760
+ // Convenience aliases (ax-cli v4.3.15)
6761
+ "grok-latest": "grok-4-0709",
6762
+ "grok-fast": "grok-4.1-fast",
6763
+ "grok-mini": "grok-3-mini",
6764
+ "grok-vision": "grok-2-vision-1212",
6765
+ "grok-image": "grok-2-image-1212",
6766
+ // Legacy aliases (deprecated)
6767
+ "grok-beta": "grok-3",
6768
+ "grok-2-vision": "grok-2-vision-1212"
6644
6769
  };
6645
6770
  GROK_DEFAULT_BASE_URL = "https://api.x.ai/v1";
6646
- GROK_DEFAULT_MODEL = "grok-3";
6771
+ GROK_DEFAULT_MODEL = "grok-4-0709";
6647
6772
  GROK_DEFAULT_COMMAND = "ax-grok";
6648
6773
  }
6649
6774
  });
@@ -7182,6 +7307,7 @@ var init_sdk_only_adapter2 = __esm({
7182
7307
  "src/integrations/ax-grok/sdk-only-adapter.ts"() {
7183
7308
  init_esm_shims();
7184
7309
  init_logger();
7310
+ init_safe_timers();
7185
7311
  init_sdk_adapter3();
7186
7312
  init_types3();
7187
7313
  GrokSdkOnlyAdapter = class {
@@ -7261,7 +7387,7 @@ var init_sdk_only_adapter2 = __esm({
7261
7387
  attempt: attempt + 1,
7262
7388
  delayMs: delay
7263
7389
  });
7264
- await this.sleep(delay);
7390
+ await sleep(delay);
7265
7391
  continue;
7266
7392
  }
7267
7393
  break;
@@ -7297,12 +7423,6 @@ var init_sdk_only_adapter2 = __esm({
7297
7423
  }
7298
7424
  return false;
7299
7425
  }
7300
- /**
7301
- * Sleep utility
7302
- */
7303
- sleep(ms) {
7304
- return new Promise((resolve5) => setTimeout(resolve5, ms));
7305
- }
7306
7426
  /**
7307
7427
  * Get the configured model
7308
7428
  */
@@ -7580,6 +7700,902 @@ Mode: ${this.grokConfig.mode || "auto"}`;
7580
7700
  }
7581
7701
  });
7582
7702
 
7703
+ // src/integrations/qwen-code/types.ts
7704
+ function normalizeQwenModel(model) {
7705
+ return QWEN_MODEL_MAPPING[model] || model;
7706
+ }
7707
+ function isVisionModel(model) {
7708
+ return model.includes("qwen3-coder") || model.includes("qwen-max");
7709
+ }
7710
+ function getModelContextWindow(model) {
7711
+ const normalizedModel = normalizeQwenModel(model);
7712
+ if (normalizedModel.includes("480b")) return 128e3;
7713
+ if (normalizedModel.includes("30b")) return 64e3;
7714
+ if (normalizedModel.includes("qwen-max")) return 128e3;
7715
+ if (normalizedModel.includes("qwen-plus")) return 128e3;
7716
+ if (normalizedModel.includes("qwen-turbo")) return 128e3;
7717
+ return 64e3;
7718
+ }
7719
+ var QWEN_DEFAULT_BASE_URL, QWEN_DEFAULT_MODEL, QWEN_DEFAULT_COMMAND, QWEN_MODEL_MAPPING;
7720
+ var init_types4 = __esm({
7721
+ "src/integrations/qwen-code/types.ts"() {
7722
+ init_esm_shims();
7723
+ QWEN_DEFAULT_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
7724
+ QWEN_DEFAULT_MODEL = "qwen-turbo";
7725
+ QWEN_DEFAULT_COMMAND = "qwen";
7726
+ QWEN_MODEL_MAPPING = {
7727
+ // Normalize common aliases
7728
+ "qwen-coder": "qwen3-coder-480b-a35b-instruct",
7729
+ "qwen-coder-480b": "qwen3-coder-480b-a35b-instruct",
7730
+ "qwen-coder-30b": "qwen3-coder-30b-a3b-instruct",
7731
+ "qwen2.5-coder": "qwen2.5-coder-32b-instruct"
7732
+ };
7733
+ }
7734
+ });
7735
+
7736
+ // src/integrations/qwen-code/sdk-adapter.ts
7737
+ var QwenSdkAdapter;
7738
+ var init_sdk_adapter4 = __esm({
7739
+ "src/integrations/qwen-code/sdk-adapter.ts"() {
7740
+ init_esm_shims();
7741
+ init_logger();
7742
+ init_validation_limits();
7743
+ init_types4();
7744
+ QwenSdkAdapter = class {
7745
+ client = null;
7746
+ config;
7747
+ initialized = false;
7748
+ constructor(config = {}) {
7749
+ const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
7750
+ this.config = {
7751
+ apiKey,
7752
+ baseUrl: config.baseUrl || QWEN_DEFAULT_BASE_URL,
7753
+ model: config.model || QWEN_DEFAULT_MODEL,
7754
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
7755
+ };
7756
+ logger.debug("[Qwen SDK] Adapter created", {
7757
+ model: this.config.model,
7758
+ baseUrl: this.config.baseUrl,
7759
+ hasApiKey: !!this.config.apiKey
7760
+ });
7761
+ }
7762
+ /**
7763
+ * Check if SDK is available (OpenAI package installed and API key configured)
7764
+ */
7765
+ async isAvailable() {
7766
+ try {
7767
+ if (!this.config.apiKey) {
7768
+ logger.debug("[Qwen SDK] No API key configured (set DASHSCOPE_API_KEY or QWEN_API_KEY)");
7769
+ return false;
7770
+ }
7771
+ await import('openai');
7772
+ return true;
7773
+ } catch (error) {
7774
+ logger.debug("[Qwen SDK] OpenAI SDK not available", {
7775
+ error: error instanceof Error ? error.message : String(error)
7776
+ });
7777
+ return false;
7778
+ }
7779
+ }
7780
+ /**
7781
+ * Initialize the SDK client
7782
+ */
7783
+ async initialize() {
7784
+ if (this.initialized) {
7785
+ return;
7786
+ }
7787
+ try {
7788
+ const OpenAI = (await import('openai')).default;
7789
+ this.client = new OpenAI({
7790
+ apiKey: this.config.apiKey,
7791
+ baseURL: this.config.baseUrl,
7792
+ timeout: this.config.timeout
7793
+ });
7794
+ this.initialized = true;
7795
+ logger.debug("[Qwen SDK] Client initialized", {
7796
+ model: this.config.model
7797
+ });
7798
+ } catch (error) {
7799
+ throw new Error(
7800
+ `Failed to initialize Qwen SDK: ${error instanceof Error ? error.message : String(error)}`
7801
+ );
7802
+ }
7803
+ }
7804
+ /**
7805
+ * Execute a request using the Qwen SDK
7806
+ */
7807
+ async execute(request) {
7808
+ if (!this.initialized) {
7809
+ await this.initialize();
7810
+ }
7811
+ const startTime = Date.now();
7812
+ try {
7813
+ const messages = [];
7814
+ if (request.systemPrompt) {
7815
+ messages.push({
7816
+ role: "system",
7817
+ content: request.systemPrompt
7818
+ });
7819
+ }
7820
+ messages.push({
7821
+ role: "user",
7822
+ content: request.prompt
7823
+ });
7824
+ const model = normalizeQwenModel(request.model || this.config.model);
7825
+ logger.debug("[Qwen SDK] Executing request", {
7826
+ model,
7827
+ messageCount: messages.length,
7828
+ promptLength: request.prompt.length
7829
+ });
7830
+ const openaiClient = this.client;
7831
+ const response = await openaiClient.chat.completions.create({
7832
+ model,
7833
+ messages,
7834
+ max_tokens: request.maxTokens,
7835
+ temperature: request.temperature,
7836
+ stream: false
7837
+ });
7838
+ const latencyMs = Date.now() - startTime;
7839
+ if (!response.choices || response.choices.length === 0) {
7840
+ throw new Error("Qwen API returned empty choices array");
7841
+ }
7842
+ const choice = response.choices[0];
7843
+ const content = choice?.message?.content || "";
7844
+ const finishReason = choice?.finish_reason || "unknown";
7845
+ logger.debug("[Qwen SDK] Request completed", {
7846
+ model: response.model,
7847
+ latencyMs,
7848
+ tokensUsed: response.usage?.total_tokens
7849
+ });
7850
+ return {
7851
+ content,
7852
+ model: response.model,
7853
+ tokensUsed: response.usage ? {
7854
+ prompt: response.usage.prompt_tokens,
7855
+ completion: response.usage.completion_tokens,
7856
+ total: response.usage.total_tokens
7857
+ } : { prompt: 0, completion: 0, total: 0 },
7858
+ latencyMs,
7859
+ finishReason,
7860
+ cached: false
7861
+ };
7862
+ } catch (error) {
7863
+ const latencyMs = Date.now() - startTime;
7864
+ logger.error("[Qwen SDK] Request failed", {
7865
+ error: error instanceof Error ? error.message : String(error),
7866
+ latencyMs
7867
+ });
7868
+ throw error;
7869
+ }
7870
+ }
7871
+ /**
7872
+ * Get the configured model
7873
+ */
7874
+ getModel() {
7875
+ return this.config.model;
7876
+ }
7877
+ /**
7878
+ * Clean up resources
7879
+ */
7880
+ async destroy() {
7881
+ this.client = null;
7882
+ this.initialized = false;
7883
+ logger.debug("[Qwen SDK] Adapter destroyed");
7884
+ }
7885
+ };
7886
+ }
7887
+ });
7888
+ var NON_INTERACTIVE_ENV, SIGKILL_ESCALATION_MS, QwenCliWrapper;
7889
+ var init_cli_wrapper4 = __esm({
7890
+ "src/integrations/qwen-code/cli-wrapper.ts"() {
7891
+ init_esm_shims();
7892
+ init_logger();
7893
+ init_validation_limits();
7894
+ init_cli_provider_detector();
7895
+ init_types4();
7896
+ NON_INTERACTIVE_ENV = {
7897
+ TERM: "dumb",
7898
+ NO_COLOR: "1",
7899
+ FORCE_COLOR: "0",
7900
+ CI: "true",
7901
+ NO_UPDATE_NOTIFIER: "1",
7902
+ DEBIAN_FRONTEND: "noninteractive"
7903
+ };
7904
+ SIGKILL_ESCALATION_MS = 5e3;
7905
+ QwenCliWrapper = class {
7906
+ config;
7907
+ constructor(config = {}) {
7908
+ this.config = {
7909
+ command: config.command || QWEN_DEFAULT_COMMAND,
7910
+ vlmSwitchMode: config.vlmSwitchMode || "once",
7911
+ yolo: config.yolo || false,
7912
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
7913
+ };
7914
+ logger.debug("[Qwen CLI] Wrapper created", {
7915
+ command: this.config.command,
7916
+ timeout: this.config.timeout
7917
+ });
7918
+ }
7919
+ /**
7920
+ * Check if Qwen CLI is available on PATH
7921
+ */
7922
+ async isAvailable() {
7923
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
7924
+ return true;
7925
+ }
7926
+ try {
7927
+ const result = findOnPath(this.config.command);
7928
+ logger.debug("[Qwen CLI] Availability check", {
7929
+ available: result.found,
7930
+ path: result.path
7931
+ });
7932
+ return result.found;
7933
+ } catch (error) {
7934
+ logger.debug("[Qwen CLI] Availability check failed", {
7935
+ error: error instanceof Error ? error.message : String(error)
7936
+ });
7937
+ return false;
7938
+ }
7939
+ }
7940
+ /**
7941
+ * Execute a prompt using the Qwen CLI
7942
+ *
7943
+ * Since Qwen CLI is interactive, we:
7944
+ * 1. Spawn the process
7945
+ * 2. Send the prompt via stdin
7946
+ * 3. Capture output until we detect completion
7947
+ * 4. Return the response
7948
+ */
7949
+ async execute(request) {
7950
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
7951
+ return this.createMockResponse(request.prompt);
7952
+ }
7953
+ const startTime = Date.now();
7954
+ return new Promise((resolve5, reject) => {
7955
+ const args2 = [];
7956
+ if (this.config.vlmSwitchMode !== "once") {
7957
+ args2.push("--vlm-switch-mode", this.config.vlmSwitchMode);
7958
+ }
7959
+ if (this.config.yolo) {
7960
+ args2.push("--yolo");
7961
+ }
7962
+ logger.debug("[Qwen CLI] Spawning process", {
7963
+ command: this.config.command,
7964
+ args: args2,
7965
+ promptLength: request.prompt.length
7966
+ });
7967
+ const child = spawn(this.config.command, args2, {
7968
+ env: { ...process.env, ...NON_INTERACTIVE_ENV }
7969
+ });
7970
+ let stdout = "";
7971
+ let stderr = "";
7972
+ let timeoutId = null;
7973
+ let forceKillTimer = null;
7974
+ let readlineInterface = null;
7975
+ let responseStarted = false;
7976
+ const cleanup = () => {
7977
+ if (timeoutId) {
7978
+ clearTimeout(timeoutId);
7979
+ timeoutId = null;
7980
+ }
7981
+ if (forceKillTimer) {
7982
+ clearTimeout(forceKillTimer);
7983
+ forceKillTimer = null;
7984
+ }
7985
+ if (readlineInterface) {
7986
+ try {
7987
+ readlineInterface.close();
7988
+ } catch {
7989
+ }
7990
+ readlineInterface = null;
7991
+ }
7992
+ };
7993
+ if (child.stdout) {
7994
+ readlineInterface = readline.createInterface({
7995
+ input: child.stdout,
7996
+ crlfDelay: Infinity
7997
+ });
7998
+ readlineInterface.on("line", (line) => {
7999
+ if (line.startsWith(">") && !responseStarted) {
8000
+ responseStarted = true;
8001
+ return;
8002
+ }
8003
+ if (responseStarted) {
8004
+ stdout += line + "\n";
8005
+ }
8006
+ });
8007
+ readlineInterface.on("error", (error) => {
8008
+ logger.debug("[Qwen CLI] Readline error", {
8009
+ error: error.message
8010
+ });
8011
+ });
8012
+ }
8013
+ if (child.stderr) {
8014
+ child.stderr.on("data", (data) => {
8015
+ stderr += data.toString();
8016
+ });
8017
+ }
8018
+ if (child.stdin) {
8019
+ try {
8020
+ let fullPrompt = request.prompt;
8021
+ if (request.systemPrompt) {
8022
+ fullPrompt = `${request.systemPrompt}
8023
+
8024
+ ${request.prompt}`;
8025
+ }
8026
+ child.stdin.write(fullPrompt);
8027
+ child.stdin.write("\n");
8028
+ child.stdin.end();
8029
+ } catch (error) {
8030
+ cleanup();
8031
+ child.kill("SIGTERM");
8032
+ reject(new Error(`Failed to write to Qwen stdin: ${error instanceof Error ? error.message : String(error)}`));
8033
+ return;
8034
+ }
8035
+ } else {
8036
+ cleanup();
8037
+ reject(new Error("Qwen CLI stdin not available"));
8038
+ return;
8039
+ }
8040
+ child.on("close", (code, signal) => {
8041
+ cleanup();
8042
+ const latencyMs = Date.now() - startTime;
8043
+ if (stderr) {
8044
+ logger.debug("[Qwen CLI] stderr output", { stderr: stderr.trim() });
8045
+ }
8046
+ if ((code === 0 || code === null) && !signal) {
8047
+ const content = this.parseResponse(stdout);
8048
+ resolve5({
8049
+ content: content.trim(),
8050
+ model: "qwen-code-cli",
8051
+ tokensUsed: {
8052
+ prompt: this.estimateTokens(request.prompt),
8053
+ completion: this.estimateTokens(content),
8054
+ total: this.estimateTokens(request.prompt) + this.estimateTokens(content)
8055
+ },
8056
+ latencyMs,
8057
+ finishReason: "stop",
8058
+ cached: false
8059
+ });
8060
+ } else if (signal) {
8061
+ reject(new Error(`Qwen CLI killed by signal ${signal}. stderr: ${stderr || "none"}`));
8062
+ } else {
8063
+ reject(new Error(`Qwen CLI exited with code ${code}. stderr: ${stderr || "none"}`));
8064
+ }
8065
+ });
8066
+ child.on("error", (error) => {
8067
+ cleanup();
8068
+ logger.error("[Qwen CLI] Process error", {
8069
+ error: error.message
8070
+ });
8071
+ reject(new Error(`Failed to spawn Qwen CLI: ${error.message}`));
8072
+ });
8073
+ timeoutId = setTimeout(() => {
8074
+ if (child.pid && !child.killed) {
8075
+ logger.warn("[Qwen CLI] Killing process due to timeout", {
8076
+ pid: child.pid,
8077
+ timeout: this.config.timeout
8078
+ });
8079
+ child.kill("SIGTERM");
8080
+ forceKillTimer = setTimeout(() => {
8081
+ if (child.pid) {
8082
+ try {
8083
+ process.kill(child.pid, 0);
8084
+ logger.warn("[Qwen CLI] Force killing process", { pid: child.pid });
8085
+ child.kill("SIGKILL");
8086
+ } catch {
8087
+ }
8088
+ }
8089
+ }, SIGKILL_ESCALATION_MS);
8090
+ }
8091
+ }, this.config.timeout);
8092
+ });
8093
+ }
8094
+ /**
8095
+ * Parse response from CLI output
8096
+ *
8097
+ * Qwen CLI outputs include prompts and formatting that we need to strip.
8098
+ */
8099
+ parseResponse(output) {
8100
+ let content = output.trim();
8101
+ content = content.replace(/\x1B\[[0-9;]*[mGKH]/g, "");
8102
+ content = content.replace(/^>\s*/gm, "").replace(/\n{3,}/g, "\n\n").trim();
8103
+ return content;
8104
+ }
8105
+ /**
8106
+ * Estimate token count
8107
+ */
8108
+ estimateTokens(text) {
8109
+ return Math.ceil(text.length / 4);
8110
+ }
8111
+ /**
8112
+ * Create mock response for testing
8113
+ */
8114
+ createMockResponse(prompt) {
8115
+ return {
8116
+ content: `[Mock Qwen Response]
8117
+
8118
+ This is a mock response from Qwen Code CLI.
8119
+ Prompt length: ${prompt.length} characters.`,
8120
+ model: "qwen-code-cli-mock",
8121
+ tokensUsed: {
8122
+ prompt: this.estimateTokens(prompt),
8123
+ completion: 50,
8124
+ total: this.estimateTokens(prompt) + 50
8125
+ },
8126
+ latencyMs: 10,
8127
+ finishReason: "stop",
8128
+ cached: false
8129
+ };
8130
+ }
8131
+ /**
8132
+ * Get CLI command
8133
+ */
8134
+ getCommand() {
8135
+ return this.config.command;
8136
+ }
8137
+ };
8138
+ }
8139
+ });
8140
+
8141
+ // src/integrations/qwen-code/hybrid-adapter.ts
8142
+ var QwenHybridAdapter;
8143
+ var init_hybrid_adapter4 = __esm({
8144
+ "src/integrations/qwen-code/hybrid-adapter.ts"() {
8145
+ init_esm_shims();
8146
+ init_logger();
8147
+ init_sdk_adapter4();
8148
+ init_cli_wrapper4();
8149
+ QwenHybridAdapter = class {
8150
+ sdkAdapter = null;
8151
+ cliWrapper = null;
8152
+ options;
8153
+ activeMode = null;
8154
+ // Circuit breakers for each mode
8155
+ sdkCircuitBreaker = {
8156
+ failures: 0,
8157
+ lastFailure: 0,
8158
+ isOpen: false
8159
+ };
8160
+ cliCircuitBreaker = {
8161
+ failures: 0,
8162
+ lastFailure: 0,
8163
+ isOpen: false
8164
+ };
8165
+ // Circuit breaker configuration
8166
+ FAILURE_THRESHOLD = 3;
8167
+ RECOVERY_TIMEOUT_MS = 6e4;
8168
+ // 1 minute
8169
+ constructor(options = {}) {
8170
+ this.options = {
8171
+ mode: options.mode || "auto",
8172
+ model: options.model || "qwen-turbo",
8173
+ apiKey: options.apiKey,
8174
+ baseUrl: options.baseUrl,
8175
+ command: options.command || "qwen",
8176
+ timeout: options.timeout
8177
+ };
8178
+ logger.debug("[Qwen Hybrid] Adapter created", {
8179
+ mode: this.options.mode,
8180
+ model: this.options.model
8181
+ });
8182
+ }
8183
+ /**
8184
+ * Get or create SDK adapter
8185
+ */
8186
+ getSdkAdapter() {
8187
+ if (!this.sdkAdapter) {
8188
+ const config = {
8189
+ apiKey: this.options.apiKey,
8190
+ baseUrl: this.options.baseUrl,
8191
+ model: this.options.model,
8192
+ timeout: this.options.timeout
8193
+ };
8194
+ this.sdkAdapter = new QwenSdkAdapter(config);
8195
+ }
8196
+ return this.sdkAdapter;
8197
+ }
8198
+ /**
8199
+ * Get or create CLI wrapper
8200
+ */
8201
+ getCliWrapper() {
8202
+ if (!this.cliWrapper) {
8203
+ const config = {
8204
+ command: this.options.command,
8205
+ timeout: this.options.timeout
8206
+ };
8207
+ this.cliWrapper = new QwenCliWrapper(config);
8208
+ }
8209
+ return this.cliWrapper;
8210
+ }
8211
+ /**
8212
+ * Check if a circuit breaker should allow requests
8213
+ */
8214
+ isCircuitClosed(breaker) {
8215
+ if (!breaker.isOpen) {
8216
+ return true;
8217
+ }
8218
+ if (Date.now() - breaker.lastFailure > this.RECOVERY_TIMEOUT_MS) {
8219
+ breaker.isOpen = false;
8220
+ breaker.failures = 0;
8221
+ return true;
8222
+ }
8223
+ return false;
8224
+ }
8225
+ /**
8226
+ * Record a failure on a circuit breaker
8227
+ */
8228
+ recordFailure(breaker) {
8229
+ breaker.failures++;
8230
+ breaker.lastFailure = Date.now();
8231
+ if (breaker.failures >= this.FAILURE_THRESHOLD) {
8232
+ breaker.isOpen = true;
8233
+ logger.warn("[Qwen Hybrid] Circuit breaker opened", {
8234
+ failures: breaker.failures
8235
+ });
8236
+ }
8237
+ }
8238
+ /**
8239
+ * Record a success on a circuit breaker
8240
+ */
8241
+ recordSuccess(breaker) {
8242
+ breaker.failures = 0;
8243
+ breaker.isOpen = false;
8244
+ }
8245
+ /**
8246
+ * Execute a request using the appropriate mode
8247
+ */
8248
+ async execute(request) {
8249
+ const mode = this.options.mode;
8250
+ if (mode === "sdk") {
8251
+ return this.executeWithSdk(request);
8252
+ }
8253
+ if (mode === "cli") {
8254
+ return this.executeWithCli(request);
8255
+ }
8256
+ return this.executeWithAuto(request);
8257
+ }
8258
+ /**
8259
+ * Execute with SDK only
8260
+ */
8261
+ async executeWithSdk(request) {
8262
+ const adapter = this.getSdkAdapter();
8263
+ if (!await adapter.isAvailable()) {
8264
+ throw new Error("Qwen SDK is not available. Check DASHSCOPE_API_KEY or QWEN_API_KEY.");
8265
+ }
8266
+ this.activeMode = "sdk";
8267
+ return adapter.execute(request);
8268
+ }
8269
+ /**
8270
+ * Execute with CLI only
8271
+ */
8272
+ async executeWithCli(request) {
8273
+ const wrapper = this.getCliWrapper();
8274
+ if (!await wrapper.isAvailable()) {
8275
+ throw new Error("Qwen CLI is not available. Run: npm install -g @qwen-code/qwen-code@latest");
8276
+ }
8277
+ this.activeMode = "cli";
8278
+ return wrapper.execute(request);
8279
+ }
8280
+ /**
8281
+ * Execute with automatic mode selection
8282
+ */
8283
+ async executeWithAuto(request) {
8284
+ if (this.isCircuitClosed(this.sdkCircuitBreaker)) {
8285
+ const adapter = this.getSdkAdapter();
8286
+ try {
8287
+ if (await adapter.isAvailable()) {
8288
+ logger.debug("[Qwen Hybrid] Using SDK mode");
8289
+ this.activeMode = "sdk";
8290
+ const response = await adapter.execute(request);
8291
+ this.recordSuccess(this.sdkCircuitBreaker);
8292
+ return response;
8293
+ }
8294
+ } catch (error) {
8295
+ logger.warn("[Qwen Hybrid] SDK execution failed, trying CLI", {
8296
+ error: error instanceof Error ? error.message : String(error)
8297
+ });
8298
+ this.recordFailure(this.sdkCircuitBreaker);
8299
+ }
8300
+ }
8301
+ if (this.isCircuitClosed(this.cliCircuitBreaker)) {
8302
+ const wrapper = this.getCliWrapper();
8303
+ try {
8304
+ if (await wrapper.isAvailable()) {
8305
+ logger.debug("[Qwen Hybrid] Using CLI mode (fallback)");
8306
+ this.activeMode = "cli";
8307
+ const response = await wrapper.execute(request);
8308
+ this.recordSuccess(this.cliCircuitBreaker);
8309
+ return response;
8310
+ }
8311
+ } catch (error) {
8312
+ logger.error("[Qwen Hybrid] CLI execution also failed", {
8313
+ error: error instanceof Error ? error.message : String(error)
8314
+ });
8315
+ this.recordFailure(this.cliCircuitBreaker);
8316
+ throw error;
8317
+ }
8318
+ }
8319
+ throw new Error(
8320
+ "Qwen execution failed: Both SDK and CLI modes are unavailable or have failed too many times. Ensure DASHSCOPE_API_KEY is set or Qwen CLI is installed."
8321
+ );
8322
+ }
8323
+ /**
8324
+ * Get the currently active execution mode
8325
+ */
8326
+ getActiveMode() {
8327
+ return this.activeMode;
8328
+ }
8329
+ /**
8330
+ * Reset circuit breakers
8331
+ */
8332
+ resetCircuitBreakers() {
8333
+ this.sdkCircuitBreaker = { failures: 0, lastFailure: 0, isOpen: false };
8334
+ this.cliCircuitBreaker = { failures: 0, lastFailure: 0, isOpen: false };
8335
+ logger.debug("[Qwen Hybrid] Circuit breakers reset");
8336
+ }
8337
+ /**
8338
+ * Clean up resources
8339
+ */
8340
+ async destroy() {
8341
+ if (this.sdkAdapter) {
8342
+ await this.sdkAdapter.destroy();
8343
+ this.sdkAdapter = null;
8344
+ }
8345
+ this.cliWrapper = null;
8346
+ this.activeMode = null;
8347
+ logger.debug("[Qwen Hybrid] Adapter destroyed");
8348
+ }
8349
+ };
8350
+ }
8351
+ });
8352
+
8353
+ // src/integrations/qwen-code/index.ts
8354
+ var init_qwen_code = __esm({
8355
+ "src/integrations/qwen-code/index.ts"() {
8356
+ init_esm_shims();
8357
+ init_hybrid_adapter4();
8358
+ init_sdk_adapter4();
8359
+ init_cli_wrapper4();
8360
+ init_types4();
8361
+ }
8362
+ });
8363
+
8364
+ // src/providers/qwen-provider.ts
8365
+ var qwen_provider_exports = {};
8366
+ __export(qwen_provider_exports, {
8367
+ QwenProvider: () => QwenProvider,
8368
+ default: () => QwenProvider
8369
+ });
8370
+ var SUPPORTED_MODELS, QwenProvider;
8371
+ var init_qwen_provider = __esm({
8372
+ "src/providers/qwen-provider.ts"() {
8373
+ init_esm_shims();
8374
+ init_base_provider();
8375
+ init_logger();
8376
+ init_qwen_code();
8377
+ SUPPORTED_MODELS = [
8378
+ "qwen3-coder-480b-a35b-instruct",
8379
+ "qwen3-coder-30b-a3b-instruct",
8380
+ "qwen2.5-coder-32b-instruct",
8381
+ "qwen-max",
8382
+ "qwen-plus",
8383
+ "qwen-turbo"
8384
+ ];
8385
+ QwenProvider = class extends BaseProvider {
8386
+ /** Selected model */
8387
+ model;
8388
+ /** SDK adapter for direct execution */
8389
+ sdkAdapter = null;
8390
+ /** Hybrid adapter for 'auto' mode */
8391
+ hybridAdapter = null;
8392
+ /** Provider configuration */
8393
+ qwenConfig;
8394
+ /** Supported models */
8395
+ static SUPPORTED_MODELS = SUPPORTED_MODELS;
8396
+ constructor(config) {
8397
+ super({
8398
+ ...config,
8399
+ command: "qwen"
8400
+ });
8401
+ this.qwenConfig = config;
8402
+ const requestedModel = config.model || QWEN_DEFAULT_MODEL;
8403
+ if (!SUPPORTED_MODELS.includes(requestedModel)) {
8404
+ logger.warn(`[Qwen] Unknown model: ${requestedModel}. Using ${QWEN_DEFAULT_MODEL}.`);
8405
+ this.model = QWEN_DEFAULT_MODEL;
8406
+ } else {
8407
+ this.model = requestedModel;
8408
+ }
8409
+ logger.debug("[Qwen Provider] Initialized", {
8410
+ model: this.model,
8411
+ mode: config.mode || "sdk"
8412
+ });
8413
+ }
8414
+ /**
8415
+ * Get the normalized model name
8416
+ */
8417
+ getNormalizedModel() {
8418
+ return normalizeQwenModel(this.model);
8419
+ }
8420
+ /**
8421
+ * Get or create SDK adapter
8422
+ */
8423
+ getSdkAdapter() {
8424
+ if (!this.sdkAdapter) {
8425
+ this.sdkAdapter = new QwenSdkAdapter({
8426
+ model: this.model,
8427
+ apiKey: this.qwenConfig.apiKey,
8428
+ baseUrl: this.qwenConfig.baseUrl,
8429
+ timeout: this.qwenConfig.timeout
8430
+ });
8431
+ }
8432
+ return this.sdkAdapter;
8433
+ }
8434
+ /**
8435
+ * Get or create hybrid adapter
8436
+ */
8437
+ getHybridAdapter() {
8438
+ if (!this.hybridAdapter) {
8439
+ const options = {
8440
+ mode: this.qwenConfig.mode || "auto",
8441
+ model: this.model,
8442
+ apiKey: this.qwenConfig.apiKey,
8443
+ baseUrl: this.qwenConfig.baseUrl,
8444
+ command: "qwen",
8445
+ timeout: this.qwenConfig.timeout
8446
+ };
8447
+ this.hybridAdapter = new QwenHybridAdapter(options);
8448
+ }
8449
+ return this.hybridAdapter;
8450
+ }
8451
+ /**
8452
+ * Execute a task using Qwen
8453
+ *
8454
+ * Execution flow:
8455
+ * 1. Mock mode → return mock response
8456
+ * 2. mode='sdk' (default) → use SDK adapter
8457
+ * 3. mode='auto' → use hybrid adapter (SDK with CLI fallback)
8458
+ * 4. mode='cli' → use CLI via BaseProvider
8459
+ */
8460
+ async execute(request) {
8461
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
8462
+ return this.createMockResponse(request.prompt);
8463
+ }
8464
+ const effectiveMode = this.qwenConfig.mode || "sdk";
8465
+ if (effectiveMode === "cli") {
8466
+ logger.debug("[Qwen Provider] Executing via CLI", {
8467
+ model: this.model
8468
+ });
8469
+ return super.execute(request);
8470
+ }
8471
+ if (effectiveMode === "auto") {
8472
+ logger.debug("[Qwen Provider] Executing via hybrid adapter", {
8473
+ promptLength: request.prompt.length,
8474
+ model: this.model
8475
+ });
8476
+ const adapter2 = this.getHybridAdapter();
8477
+ return adapter2.execute(request);
8478
+ }
8479
+ logger.debug("[Qwen Provider] Executing via SDK adapter", {
8480
+ promptLength: request.prompt.length,
8481
+ model: this.model
8482
+ });
8483
+ const adapter = this.getSdkAdapter();
8484
+ if (!await adapter.isAvailable()) {
8485
+ throw new Error(
8486
+ 'Qwen SDK is not available. Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable, or use mode: "cli" to use Qwen Code CLI.'
8487
+ );
8488
+ }
8489
+ return adapter.execute(request);
8490
+ }
8491
+ /**
8492
+ * Get CLI command
8493
+ */
8494
+ getCLICommand() {
8495
+ const activeMode = this.hybridAdapter?.getActiveMode();
8496
+ if (activeMode === "sdk") {
8497
+ return "qwen-sdk";
8498
+ }
8499
+ return "qwen";
8500
+ }
8501
+ /**
8502
+ * Get CLI arguments for Qwen Code CLI
8503
+ *
8504
+ * Note: Qwen Code CLI is interactive by default.
8505
+ * We pass the prompt via stdin instead of command-line args.
8506
+ */
8507
+ getCLIArgs() {
8508
+ return [];
8509
+ }
8510
+ /**
8511
+ * Create mock response for testing
8512
+ */
8513
+ createMockResponse(prompt) {
8514
+ return {
8515
+ content: this.getMockResponse(),
8516
+ model: this.getNormalizedModel(),
8517
+ tokensUsed: {
8518
+ prompt: this.estimateTokens(prompt),
8519
+ completion: 50,
8520
+ total: this.estimateTokens(prompt) + 50
8521
+ },
8522
+ latencyMs: 10,
8523
+ finishReason: "stop",
8524
+ cached: false
8525
+ };
8526
+ }
8527
+ /**
8528
+ * Estimate token count
8529
+ */
8530
+ estimateTokens(text) {
8531
+ return Math.ceil(text.length / 4);
8532
+ }
8533
+ /**
8534
+ * Get mock response for testing
8535
+ */
8536
+ getMockResponse() {
8537
+ return `[Mock Qwen Response]
8538
+
8539
+ This is a mock response from the Qwen provider (${this.getNormalizedModel()}).
8540
+ In production, this would be a response from ${this.qwenConfig.mode === "sdk" ? "Qwen SDK" : "Qwen Code CLI"}.
8541
+
8542
+ Model: ${this.getNormalizedModel()}
8543
+ Provider: Qwen (Alibaba Cloud)
8544
+ Mode: ${this.qwenConfig.mode || "sdk"}`;
8545
+ }
8546
+ /**
8547
+ * Get provider capabilities
8548
+ */
8549
+ get capabilities() {
8550
+ const model = this.getNormalizedModel();
8551
+ const hasVision = isVisionModel(model);
8552
+ const maxContextTokens = getModelContextWindow(model);
8553
+ const activeMode = this.hybridAdapter?.getActiveMode();
8554
+ const integrationMode = activeMode === "sdk" ? "sdk" : "cli";
8555
+ return {
8556
+ ...super.capabilities,
8557
+ supportsStreaming: true,
8558
+ supportsVision: hasVision,
8559
+ maxContextTokens,
8560
+ supportedModels: SUPPORTED_MODELS,
8561
+ integrationMode
8562
+ };
8563
+ }
8564
+ /**
8565
+ * Get the active execution mode
8566
+ */
8567
+ getActiveMode() {
8568
+ return this.hybridAdapter?.getActiveMode() || null;
8569
+ }
8570
+ /**
8571
+ * Reset circuit breakers
8572
+ */
8573
+ resetCircuitBreakers() {
8574
+ this.hybridAdapter?.resetCircuitBreakers();
8575
+ }
8576
+ /**
8577
+ * Clean up resources
8578
+ */
8579
+ async destroy() {
8580
+ if (this.sdkAdapter) {
8581
+ await this.sdkAdapter.destroy();
8582
+ this.sdkAdapter = null;
8583
+ }
8584
+ if (this.hybridAdapter) {
8585
+ await this.hybridAdapter.destroy();
8586
+ this.hybridAdapter = null;
8587
+ }
8588
+ }
8589
+ /**
8590
+ * Get the list of supported models
8591
+ */
8592
+ static getSupportedModels() {
8593
+ return [...SUPPORTED_MODELS];
8594
+ }
8595
+ };
8596
+ }
8597
+ });
8598
+
7583
8599
  // src/mcp/index.ts
7584
8600
  init_esm_shims();
7585
8601
 
@@ -8032,12 +9048,16 @@ init_logger();
8032
9048
 
8033
9049
  // src/shared/helpers/deep-merge.ts
8034
9050
  init_esm_shims();
9051
+ function isPlainObject(value) {
9052
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
9053
+ }
8035
9054
  function deepMerge(defaults, user) {
8036
9055
  if (user === null || user === void 0) {
8037
- return defaults;
9056
+ return { ...defaults };
8038
9057
  }
8039
- const result = { ...defaults };
8040
- for (const key in user) {
9058
+ const result = Object.assign({}, defaults);
9059
+ const userKeys = Object.keys(user);
9060
+ for (const key of userKeys) {
8041
9061
  const userValue = user[key];
8042
9062
  if (userValue === null) {
8043
9063
  result[key] = void 0;
@@ -8047,8 +9067,11 @@ function deepMerge(defaults, user) {
8047
9067
  continue;
8048
9068
  }
8049
9069
  const defaultValue = defaults[key];
8050
- if (typeof userValue === "object" && typeof defaultValue === "object" && !Array.isArray(userValue) && !Array.isArray(defaultValue) && userValue !== null && defaultValue !== null) {
8051
- result[key] = deepMerge(defaultValue, userValue);
9070
+ if (isPlainObject(userValue) && isPlainObject(defaultValue)) {
9071
+ result[key] = deepMerge(
9072
+ defaultValue,
9073
+ userValue
9074
+ );
8052
9075
  } else {
8053
9076
  result[key] = userValue;
8054
9077
  }
@@ -8690,7 +9713,7 @@ var PRECOMPILED_CONFIG = {
8690
9713
  "enableFreeTierPrioritization": true,
8691
9714
  "enableWorkloadAwareRouting": true
8692
9715
  },
8693
- "version": "12.6.1"
9716
+ "version": "12.6.3"
8694
9717
  };
8695
9718
 
8696
9719
  // src/core/config/schemas.ts
@@ -9565,107 +10588,7 @@ init_logger();
9565
10588
  // src/shared/utils/disposable.ts
9566
10589
  init_esm_shims();
9567
10590
  init_logger();
9568
-
9569
- // src/shared/utils/safe-timers.ts
9570
- init_esm_shims();
9571
- init_logger();
9572
- function createSafeInterval(callback, intervalMs, options = {}) {
9573
- const { ref = false, name, signal, immediate = false } = options;
9574
- if (signal?.aborted) {
9575
- logger.debug("createSafeInterval: already aborted", { name });
9576
- return () => {
9577
- };
9578
- }
9579
- let cleared = false;
9580
- let intervalId = null;
9581
- const safeCallback = async () => {
9582
- if (cleared) return;
9583
- try {
9584
- await callback();
9585
- } catch (error) {
9586
- logger.error("Safe interval callback error", {
9587
- name,
9588
- error: error.message
9589
- });
9590
- }
9591
- };
9592
- if (immediate) {
9593
- setImmediate(() => {
9594
- if (!cleared) {
9595
- safeCallback();
9596
- }
9597
- });
9598
- }
9599
- intervalId = setInterval(safeCallback, intervalMs);
9600
- if (!ref && intervalId.unref) {
9601
- intervalId.unref();
9602
- }
9603
- const cleanup = () => {
9604
- if (cleared) return;
9605
- cleared = true;
9606
- if (intervalId !== null) {
9607
- clearInterval(intervalId);
9608
- intervalId = null;
9609
- logger.debug("Safe interval cleared", { name });
9610
- }
9611
- };
9612
- if (signal) {
9613
- signal.addEventListener("abort", cleanup, { once: true });
9614
- }
9615
- logger.debug("Safe interval created", {
9616
- name,
9617
- intervalMs,
9618
- ref,
9619
- immediate
9620
- });
9621
- return cleanup;
9622
- }
9623
- function createSafeTimeout(callback, delayMs, options = {}) {
9624
- const { ref = false, name, signal } = options;
9625
- if (signal?.aborted) {
9626
- logger.debug("createSafeTimeout: already aborted", { name });
9627
- return () => {
9628
- };
9629
- }
9630
- let cleared = false;
9631
- let timeoutId = null;
9632
- const safeCallback = async () => {
9633
- if (cleared) return;
9634
- cleared = true;
9635
- try {
9636
- await callback();
9637
- } catch (error) {
9638
- logger.error("Safe timeout callback error", {
9639
- name,
9640
- error: error.message
9641
- });
9642
- }
9643
- };
9644
- timeoutId = setTimeout(safeCallback, delayMs);
9645
- if (!ref && timeoutId.unref) {
9646
- timeoutId.unref();
9647
- }
9648
- const cleanup = () => {
9649
- if (cleared) return;
9650
- cleared = true;
9651
- if (timeoutId !== null) {
9652
- clearTimeout(timeoutId);
9653
- timeoutId = null;
9654
- logger.debug("Safe timeout cleared", { name });
9655
- }
9656
- };
9657
- if (signal) {
9658
- signal.addEventListener("abort", cleanup, { once: true });
9659
- }
9660
- logger.debug("Safe timeout created", {
9661
- name,
9662
- delayMs,
9663
- ref
9664
- });
9665
- return cleanup;
9666
- }
9667
-
9668
- // src/shared/utils/disposable.ts
10591
+ init_safe_timers();
9669
10592
  var DisposableEventEmitter = class extends EventEmitter {
9670
10593
  /** Registered cleanup tasks */
9671
10594
  cleanupTasks = [];
@@ -13213,7 +14136,7 @@ var MemoryManager = class _MemoryManager {
13213
14136
  if (this.db) {
13214
14137
  try {
13215
14138
  this.db.close();
13216
- } catch (closeError) {
14139
+ } catch {
13217
14140
  }
13218
14141
  this.initialized = false;
13219
14142
  this.entryCount = 0;
@@ -14054,9 +14977,9 @@ var MemoryManager = class _MemoryManager {
14054
14977
  }
14055
14978
  }
14056
14979
  const {
14057
- includeEmbeddings = false,
14980
+ includeEmbeddings: _includeEmbeddings = false,
14058
14981
  filters = {},
14059
- batchSize = 1e3,
14982
+ batchSize: _batchSize = 1e3,
14060
14983
  pretty = false
14061
14984
  } = options || {};
14062
14985
  try {
@@ -15213,7 +16136,7 @@ var SessionManager = class _SessionManager {
15213
16136
  if (this.pendingSave) {
15214
16137
  try {
15215
16138
  await this.pendingSave;
15216
- } catch (err) {
16139
+ } catch {
15217
16140
  }
15218
16141
  }
15219
16142
  this.pendingSave = this.doSave().finally(() => {
@@ -15281,7 +16204,7 @@ var SessionManager = class _SessionManager {
15281
16204
  }
15282
16205
  try {
15283
16206
  await unlink(tempPath);
15284
- } catch (unlinkError) {
16207
+ } catch {
15285
16208
  }
15286
16209
  throw renameError;
15287
16210
  }
@@ -15289,7 +16212,7 @@ var SessionManager = class _SessionManager {
15289
16212
  const tempPath = `${this.persistencePath}.tmp`;
15290
16213
  try {
15291
16214
  await unlink(tempPath);
15292
- } catch (unlinkError) {
16215
+ } catch {
15293
16216
  }
15294
16217
  logger.error("Failed to save sessions to persistence", {
15295
16218
  path: normalizePath(this.persistencePath),
@@ -15827,6 +16750,7 @@ init_esm_shims();
15827
16750
  init_logger();
15828
16751
  var MAX_CONTEXT_SIZE = 100 * 1024;
15829
16752
  var DEFAULT_CACHE_TTL = 3e5;
16753
+ var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
15830
16754
  var ProjectContextLoader = class {
15831
16755
  constructor(projectRoot, options) {
15832
16756
  this.projectRoot = projectRoot;
@@ -15850,76 +16774,79 @@ var ProjectContextLoader = class {
15850
16774
  });
15851
16775
  const context = {};
15852
16776
  try {
15853
- const mdPath = path4__default.join(this.projectRoot, "AX.md");
15854
- const resolvedPath = await realpath(mdPath).catch(() => null);
16777
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
16778
+ const resolvedPath = await realpath(indexPath).catch(() => null);
15855
16779
  if (resolvedPath) {
15856
16780
  const rel = path4__default.relative(this.projectRoot, resolvedPath);
15857
16781
  if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
15858
16782
  const stats = await stat(resolvedPath);
15859
16783
  if (stats.size > MAX_CONTEXT_SIZE) {
15860
- logger.warn("AX.md too large, ignoring", {
16784
+ logger.warn("ax.index.json too large, ignoring", {
15861
16785
  size: stats.size,
15862
16786
  limit: MAX_CONTEXT_SIZE
15863
16787
  });
15864
16788
  } else {
15865
- context.markdown = await readFile(resolvedPath, "utf-8");
15866
- logger.info("Loaded AX.md", {
15867
- size: stats.size,
15868
- lines: context.markdown.split("\n").length
16789
+ const indexContent = await readFile(resolvedPath, "utf-8");
16790
+ context.index = JSON.parse(indexContent);
16791
+ context.lastUpdated = stats.mtime;
16792
+ const age = Date.now() - stats.mtime.getTime();
16793
+ context.isStale = age > STALE_THRESHOLD_MS;
16794
+ logger.info("Loaded ax.index.json", {
16795
+ projectName: context.index.projectName,
16796
+ projectType: context.index.projectType,
16797
+ isStale: context.isStale,
16798
+ ageHours: Math.floor(age / (1e3 * 60 * 60))
15869
16799
  });
15870
- context.agentRules = this.parseAgentRules(context.markdown);
15871
- context.guardrails = this.parseGuardrails(context.markdown);
15872
- context.commands = this.parseCommands(context.markdown);
15873
- context.metadata = this.parseMetadata(context.markdown);
16800
+ if (context.index.commands) {
16801
+ context.commands = {};
16802
+ for (const [name, cmd] of Object.entries(context.index.commands)) {
16803
+ context.commands[name] = cmd.script;
16804
+ }
16805
+ }
15874
16806
  }
15875
16807
  }
15876
16808
  }
15877
16809
  } catch (error) {
15878
16810
  if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
15879
- logger.warn("Error loading AX.md", { error });
16811
+ logger.warn("Error loading ax.index.json", { error });
15880
16812
  }
15881
16813
  }
15882
16814
  try {
15883
- const ymlPath = path4__default.join(this.projectRoot, "ax.config.yml");
15884
- const resolvedPath = await realpath(ymlPath).catch(() => null);
16815
+ const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
16816
+ const resolvedPath = await realpath(customMdPath).catch(() => null);
15885
16817
  if (resolvedPath) {
15886
16818
  const rel = path4__default.relative(this.projectRoot, resolvedPath);
15887
16819
  if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
15888
16820
  const stats = await stat(resolvedPath);
15889
16821
  if (stats.size > MAX_CONTEXT_SIZE) {
15890
- logger.warn("ax.config.yml too large, ignoring", {
16822
+ logger.warn("CUSTOM.md too large, ignoring", {
15891
16823
  size: stats.size,
15892
16824
  limit: MAX_CONTEXT_SIZE
15893
16825
  });
15894
16826
  } else {
15895
- const ymlContent = await readFile(resolvedPath, "utf-8");
15896
- context.config = yaml.parse(ymlContent);
15897
- logger.info("Loaded ax.config.yml", {
15898
- size: stats.size
16827
+ context.customInstructions = await readFile(resolvedPath, "utf-8");
16828
+ logger.info("Loaded CUSTOM.md", {
16829
+ size: stats.size,
16830
+ lines: context.customInstructions.split("\n").length
15899
16831
  });
15900
- if (context.config.commands) {
15901
- context.commands = { ...context.commands, ...context.config.commands };
15902
- }
15903
- if (context.config.project) {
15904
- context.metadata = { ...context.metadata, ...context.config.project };
15905
- }
16832
+ context.guardrails = this.parseGuardrails(context.customInstructions);
15906
16833
  }
15907
16834
  }
15908
16835
  }
15909
16836
  } catch (error) {
15910
16837
  if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
15911
- logger.warn("Error loading ax.config.yml", { error });
16838
+ logger.warn("Error loading CUSTOM.md", { error });
15912
16839
  }
15913
16840
  }
15914
16841
  context.contextPrompt = this.buildContextPrompt(context);
15915
16842
  this.cache = context;
15916
16843
  this.cacheExpiry = Date.now() + this.cacheTTL;
15917
16844
  logger.info("Project context loaded", {
15918
- hasMarkdown: !!context.markdown,
15919
- hasConfig: !!context.config,
15920
- agentRules: context.agentRules?.length ?? 0,
16845
+ hasIndex: !!context.index,
16846
+ hasCustomInstructions: !!context.customInstructions,
15921
16847
  guardrails: context.guardrails?.length ?? 0,
15922
- commands: Object.keys(context.commands ?? {}).length
16848
+ commands: Object.keys(context.commands ?? {}).length,
16849
+ isStale: context.isStale
15923
16850
  });
15924
16851
  return context;
15925
16852
  }
@@ -15935,8 +16862,8 @@ var ProjectContextLoader = class {
15935
16862
  * Check if context exists (without loading)
15936
16863
  */
15937
16864
  async exists() {
15938
- const mdPath = path4__default.join(this.projectRoot, "AX.md");
15939
- const ymlPath = path4__default.join(this.projectRoot, "ax.config.yml");
16865
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
16866
+ const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
15940
16867
  const checkExists = async (filePath) => {
15941
16868
  try {
15942
16869
  await access(filePath, constants.F_OK);
@@ -15945,57 +16872,48 @@ var ProjectContextLoader = class {
15945
16872
  return false;
15946
16873
  }
15947
16874
  };
15948
- const [mdExists, ymlExists] = await Promise.all([
15949
- checkExists(mdPath),
15950
- checkExists(ymlPath)
16875
+ const [indexExists, customMdExists] = await Promise.all([
16876
+ checkExists(indexPath),
16877
+ checkExists(customMdPath)
15951
16878
  ]);
15952
- return mdExists || ymlExists;
16879
+ return indexExists || customMdExists;
15953
16880
  }
15954
16881
  /**
15955
- * Parse agent delegation rules from markdown
15956
- *
15957
- * Looks for patterns like:
15958
- * - Backend changes → @backend
15959
- * - API endpoints → @backend, @security
15960
- */
15961
- parseAgentRules(markdown) {
15962
- const rules = [];
15963
- const sectionRegex = /##\s+Agent\s+Delegation\s+Rules[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
15964
- const match = markdown.match(sectionRegex);
15965
- if (!match || !match[1]) {
15966
- return rules;
15967
- }
15968
- const section = match[1];
15969
- const lineRegex = /^[-*]\s+(.+?)\s+(?:→|->)+\s+(.+?)$/gm;
15970
- let lineMatch;
15971
- while ((lineMatch = lineRegex.exec(section)) !== null) {
15972
- const taskType = lineMatch[1]?.trim() ?? "";
15973
- const agentsText = lineMatch[2]?.trim() ?? "";
15974
- const agents = agentsText.split(",").map((a) => a.trim()).filter(Boolean);
15975
- const defaultAgent = agents[0];
15976
- if (defaultAgent) {
15977
- rules.push({
15978
- taskType,
15979
- patterns: [],
15980
- // TODO: Parse file patterns if specified
15981
- defaultAgent,
15982
- autoReview: agents.length > 1
15983
- });
15984
- }
16882
+ * Check if ax.index.json is stale (older than 24 hours)
16883
+ */
16884
+ async isStale() {
16885
+ try {
16886
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
16887
+ const stats = await stat(indexPath);
16888
+ const age = Date.now() - stats.mtime.getTime();
16889
+ return age > STALE_THRESHOLD_MS;
16890
+ } catch {
16891
+ return true;
15985
16892
  }
15986
- return rules;
15987
16893
  }
15988
16894
  /**
15989
- * Parse guardrails/prohibitions from markdown
16895
+ * Parse guardrails from CUSTOM.md
15990
16896
  *
15991
- * Looks for "## Critical Guardrails" or "## Critical Rules" section
15992
- * Extracts items marked with ⚠️ or under NEVER headings
16897
+ * Looks for DO/DON'T sections in ax-cli format
15993
16898
  */
15994
16899
  parseGuardrails(markdown) {
15995
16900
  const guardrails = [];
15996
- const sectionRegex = /##\s+(Critical\s+Guardrails|Critical\s+Rules|Never)[^\n]*\n([\s\S]*?)(?=\n##|$)/gi;
16901
+ const dontRegex = /###\s+DON'T[^\n]*\n([\s\S]*?)(?=\n###|$)/i;
16902
+ const dontMatch = markdown.match(dontRegex);
16903
+ if (dontMatch && dontMatch[1]) {
16904
+ const section = dontMatch[1];
16905
+ const bulletRegex = /^[-*]\s+(.+?)$/gm;
16906
+ let bulletMatch;
16907
+ while ((bulletMatch = bulletRegex.exec(section)) !== null) {
16908
+ const rule = bulletMatch[1]?.trim();
16909
+ if (rule) {
16910
+ guardrails.push(rule);
16911
+ }
16912
+ }
16913
+ }
16914
+ const criticalRegex = /##\s+(Critical\s+Guardrails|Critical\s+Rules|Never)[^\n]*\n([\s\S]*?)(?=\n##|$)/gi;
15997
16915
  let match;
15998
- while ((match = sectionRegex.exec(markdown)) !== null) {
16916
+ while ((match = criticalRegex.exec(markdown)) !== null) {
15999
16917
  const section = match[2];
16000
16918
  if (!section) continue;
16001
16919
  const bulletRegex = /^[-*]\s+(.+?)$/gm;
@@ -16005,106 +16923,58 @@ var ProjectContextLoader = class {
16005
16923
  rule = rule.replace(/^[⚠️❌✅✓⚡🔒]+\s*/, "");
16006
16924
  rule = rule.replace(/\*\*(.+?)\*\*/g, "$1");
16007
16925
  rule = rule.replace(/`(.+?)`/g, "$1");
16008
- if (rule.length > 0) {
16926
+ if (rule.length > 0 && !guardrails.includes(rule)) {
16009
16927
  guardrails.push(rule);
16010
16928
  }
16011
16929
  }
16012
16930
  }
16013
16931
  return guardrails;
16014
16932
  }
16015
- /**
16016
- * Parse commands from markdown code blocks
16017
- *
16018
- * Looks for "## Commands" or "## Canonical Commands" section
16019
- */
16020
- parseCommands(markdown) {
16021
- const commands = {};
16022
- const sectionRegex = /##\s+(Canonical\s+)?Commands[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
16023
- const match = markdown.match(sectionRegex);
16024
- if (!match) {
16025
- return commands;
16026
- }
16027
- const section = match[2];
16028
- if (!section) {
16029
- return commands;
16030
- }
16031
- const codeBlockRegex = /```(?:bash|sh|shell)?\n([\s\S]*?)```/;
16032
- const codeMatch = section.match(codeBlockRegex);
16033
- if (codeMatch && codeMatch[1]) {
16034
- const lines = codeMatch[1].split("\n");
16035
- for (const line of lines) {
16036
- const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#?\s*(.*)$/);
16037
- if (cmdMatch && cmdMatch[1]) {
16038
- const cmd = cmdMatch[1].trim();
16039
- const desc = cmdMatch[2]?.trim() ?? "";
16040
- const key = desc || cmd;
16041
- commands[key] = cmd;
16042
- }
16043
- }
16044
- }
16045
- return commands;
16046
- }
16047
- /**
16048
- * Parse project metadata from markdown frontmatter or first section
16049
- */
16050
- parseMetadata(markdown) {
16051
- const metadata = {};
16052
- const lastUpdatedMatch = markdown.match(/>\s*Last\s+updated:\s*(.+?)$/im);
16053
- if (lastUpdatedMatch && lastUpdatedMatch[1]) {
16054
- metadata.lastUpdated = lastUpdatedMatch[1].trim();
16055
- }
16056
- const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
16057
- if (projectMatch && projectMatch[1]) {
16058
- const parts = projectMatch[1].trim().split(/\s+v/);
16059
- metadata.name = parts[0] || "";
16060
- if (parts.length > 1 && parts[1]) {
16061
- metadata.version = parts[1];
16062
- }
16063
- }
16064
- const h1Match = markdown.match(/^#\s+(.+?)$/m);
16065
- if (h1Match && h1Match[1] && !metadata.name) {
16066
- metadata.name = h1Match[1].replace(/Project Context for AutomatosX/i, "").trim();
16067
- }
16068
- return metadata;
16069
- }
16070
16933
  /**
16071
16934
  * Build formatted context prompt for agent injection
16072
16935
  */
16073
16936
  buildContextPrompt(context) {
16074
- if (!context.markdown && !context.config) {
16937
+ if (!context.index && !context.customInstructions) {
16075
16938
  return "";
16076
16939
  }
16077
16940
  let prompt = "\n# PROJECT CONTEXT\n\n";
16078
- if (context.guardrails && context.guardrails.length > 0) {
16079
- prompt += "## CRITICAL RULES (NEVER VIOLATE):\n\n";
16080
- context.guardrails.forEach((rule) => {
16081
- prompt += `- ${rule}
16941
+ if (context.index) {
16942
+ prompt += `**Project:** ${context.index.projectName} v${context.index.version}
16082
16943
  `;
16083
- });
16084
- prompt += "\n";
16085
- }
16086
- if (context.agentRules && context.agentRules.length > 0) {
16087
- prompt += "## Agent Delegation Rules:\n\n";
16088
- context.agentRules.forEach((rule) => {
16089
- prompt += `- ${rule.taskType} \u2192 ${rule.defaultAgent}
16944
+ prompt += `**Type:** ${context.index.projectType}
16090
16945
  `;
16091
- });
16092
- prompt += "\n";
16946
+ prompt += `**Language:** ${context.index.language}`;
16947
+ if (context.index.framework) {
16948
+ prompt += ` + ${context.index.framework}`;
16949
+ }
16950
+ prompt += "\n\n";
16951
+ if (context.index.modules.length > 0) {
16952
+ prompt += "## Project Structure:\n\n";
16953
+ for (const mod of context.index.modules.slice(0, 10)) {
16954
+ prompt += `- \`${mod.path}/\` - ${mod.purpose}
16955
+ `;
16956
+ }
16957
+ prompt += "\n";
16958
+ }
16959
+ if (context.commands && Object.keys(context.commands).length > 0) {
16960
+ prompt += "## Available Commands:\n\n";
16961
+ for (const [name, script] of Object.entries(context.commands).slice(0, 10)) {
16962
+ prompt += `- ${name}: \`${script}\`
16963
+ `;
16964
+ }
16965
+ prompt += "\n";
16966
+ }
16093
16967
  }
16094
- if (context.commands && Object.keys(context.commands).length > 0) {
16095
- prompt += "## Available Commands:\n\n";
16096
- Object.entries(context.commands).forEach(([desc, cmd]) => {
16097
- prompt += `- ${desc}: \`${cmd}\`
16968
+ if (context.guardrails && context.guardrails.length > 0) {
16969
+ prompt += "## CRITICAL RULES (NEVER VIOLATE):\n\n";
16970
+ for (const rule of context.guardrails) {
16971
+ prompt += `- ${rule}
16098
16972
  `;
16099
- });
16973
+ }
16100
16974
  prompt += "\n";
16101
16975
  }
16102
- if (context.markdown) {
16103
- const MAX_PROMPT_LENGTH = 1e4;
16104
- const contextToAdd = context.markdown.length > MAX_PROMPT_LENGTH ? context.markdown.substring(0, MAX_PROMPT_LENGTH) + "\n\n[... context truncated for length ...]" : context.markdown;
16105
- prompt += "## Full Project Context:\n\n";
16106
- prompt += contextToAdd;
16107
- prompt += "\n";
16976
+ if (context.isStale) {
16977
+ prompt += "\u26A0\uFE0F **Note:** Project index is stale (>24h old). Run `ax init` to update.\n\n";
16108
16978
  }
16109
16979
  return prompt;
16110
16980
  }
@@ -16528,10 +17398,10 @@ var ContextManager = class {
16528
17398
  return provider;
16529
17399
  }
16530
17400
  /**
16531
- * Load project context from AX.md (v7.1.0+)
17401
+ * Load project context from ax.index.json (v12.9.0+)
16532
17402
  *
16533
- * Loads project-specific instructions from AX.md file if it exists.
16534
- * Falls back gracefully if file doesn't exist.
17403
+ * Loads project-specific context from ax.index.json and CUSTOM.md.
17404
+ * Falls back gracefully if files don't exist.
16535
17405
  *
16536
17406
  * @param projectDir - Project root directory
16537
17407
  * @returns Project context or null if not found
@@ -16544,15 +17414,15 @@ var ContextManager = class {
16544
17414
  const loader = this.projectContextLoader;
16545
17415
  const exists = await loader.exists();
16546
17416
  if (!exists) {
16547
- logger.debug("No AX.md found, skipping project context");
17417
+ logger.debug("No ax.index.json or CUSTOM.md found, skipping project context");
16548
17418
  return null;
16549
17419
  }
16550
17420
  const context = await loader.load();
16551
- logger.debug("Project context loaded from AX.md", {
16552
- hasMarkdown: !!context.markdown,
16553
- hasConfig: !!context.config,
16554
- agentRules: context.agentRules?.length ?? 0,
16555
- guardrails: context.guardrails?.length ?? 0
17421
+ logger.debug("Project context loaded", {
17422
+ hasIndex: !!context.index,
17423
+ hasCustomInstructions: !!context.customInstructions,
17424
+ guardrails: context.guardrails?.length ?? 0,
17425
+ isStale: context.isStale
16556
17426
  });
16557
17427
  return context;
16558
17428
  } catch (error) {
@@ -16922,7 +17792,11 @@ var ProfileLoader = class {
16922
17792
  continue;
16923
17793
  }
16924
17794
  const data = load(content);
16925
- return data && typeof data === "object" && !Array.isArray(data) && "displayName" in data ? data.displayName || null : null;
17795
+ if (data && typeof data === "object" && !Array.isArray(data) && "displayName" in data) {
17796
+ const profile = data;
17797
+ return profile.displayName ?? null;
17798
+ }
17799
+ return null;
16926
17800
  } catch (error) {
16927
17801
  if (error.code === "ENOENT") {
16928
17802
  continue;
@@ -16951,7 +17825,7 @@ var ProfileLoader = class {
16951
17825
  });
16952
17826
  return identifier;
16953
17827
  } catch (error) {
16954
- if (error.name === "AgentNotFoundError") {
17828
+ if (error instanceof Error && error.name === "AgentNotFoundError") {
16955
17829
  logger.debug("Direct profile load failed, trying displayName lookup", { identifier });
16956
17830
  await this.buildDisplayNameMap();
16957
17831
  const resolved = this.displayNameMap.get(identifier.toLowerCase());
@@ -17280,7 +18154,7 @@ var ProfileLoader = class {
17280
18154
  if (typeof orch !== "object" || orch === null || Array.isArray(orch)) {
17281
18155
  throw new AgentValidationError("orchestration must be an object");
17282
18156
  }
17283
- if (orch.canDelegate !== void 0) {
18157
+ if ("canDelegate" in orch && orch.canDelegate !== void 0) {
17284
18158
  logger.warn("orchestration.canDelegate is deprecated and ignored (v4.9.0+). All agents can delegate by default.", {
17285
18159
  agent: profile.name
17286
18160
  });
@@ -17326,17 +18200,18 @@ var ProfileLoader = class {
17326
18200
  if (!data || typeof data !== "object" || Array.isArray(data)) {
17327
18201
  throw new AgentValidationError(`Invalid profile data for ${name}: expected object, got ${typeof data}`);
17328
18202
  }
17329
- if (data.name && typeof data.name === "string") {
17330
- if (!/^[a-zA-Z0-9_-]+$/.test(data.name)) {
17331
- if (!data.displayName) {
17332
- data.displayName = data.name;
18203
+ const profileData = data;
18204
+ if (profileData.name && typeof profileData.name === "string") {
18205
+ if (!/^[a-zA-Z0-9_-]+$/.test(profileData.name)) {
18206
+ if (!profileData.displayName) {
18207
+ profileData.displayName = profileData.name;
17333
18208
  }
17334
- data.name = name;
18209
+ profileData.name = name;
17335
18210
  }
17336
- } else if (!data.name) {
17337
- data.name = name;
18211
+ } else if (!profileData.name) {
18212
+ profileData.name = name;
17338
18213
  }
17339
- const validationResult = safeValidateAgentProfile(data);
18214
+ const validationResult = safeValidateAgentProfile(profileData);
17340
18215
  if (!validationResult.success) {
17341
18216
  const validationErrors = validationResult.error.issues.map(
17342
18217
  (e) => `${e.path.join(".")}: ${e.message}`
@@ -17346,22 +18221,22 @@ var ProfileLoader = class {
17346
18221
  );
17347
18222
  }
17348
18223
  let teamConfig;
17349
- if (data.team && this.teamManager) {
18224
+ if (profileData.team && this.teamManager) {
17350
18225
  try {
17351
- teamConfig = await this.teamManager.loadTeam(data.team);
18226
+ teamConfig = await this.teamManager.loadTeam(profileData.team);
17352
18227
  logger.debug("Team configuration loaded for agent", {
17353
18228
  agent: name,
17354
- team: data.team
18229
+ team: profileData.team
17355
18230
  });
17356
18231
  } catch (error) {
17357
18232
  logger.warn("Failed to load team configuration, using agent defaults", {
17358
18233
  agent: name,
17359
- team: data.team,
18234
+ team: profileData.team,
17360
18235
  error: error.message
17361
18236
  });
17362
18237
  }
17363
18238
  }
17364
- const abilities = data.abilities || [];
18239
+ const abilities = profileData.abilities || [];
17365
18240
  if (teamConfig?.sharedAbilities) {
17366
18241
  const allAbilities = [.../* @__PURE__ */ new Set([...teamConfig.sharedAbilities, ...abilities])];
17367
18242
  logger.debug("Merged abilities from team", {
@@ -17373,7 +18248,7 @@ var ProfileLoader = class {
17373
18248
  });
17374
18249
  abilities.splice(0, abilities.length, ...allAbilities);
17375
18250
  }
17376
- let orchestration = data.orchestration;
18251
+ let orchestration = profileData.orchestration;
17377
18252
  if (teamConfig?.orchestration && !orchestration) {
17378
18253
  orchestration = teamConfig.orchestration;
17379
18254
  logger.debug("Using team orchestration defaults", {
@@ -17382,32 +18257,32 @@ var ProfileLoader = class {
17382
18257
  });
17383
18258
  }
17384
18259
  const profile = {
17385
- name: data.name || name,
17386
- displayName: data.displayName,
17387
- role: data.role,
17388
- description: data.description,
18260
+ name: profileData.name || name,
18261
+ displayName: profileData.displayName,
18262
+ role: profileData.role,
18263
+ description: profileData.description,
17389
18264
  // v4.10.0+: Team field
17390
- team: data.team,
17391
- systemPrompt: data.systemPrompt,
18265
+ team: profileData.team,
18266
+ systemPrompt: profileData.systemPrompt,
17392
18267
  abilities,
17393
- dependencies: data.dependencies,
17394
- parallel: data.parallel,
18268
+ dependencies: profileData.dependencies,
18269
+ parallel: profileData.parallel,
17395
18270
  // Enhanced v4.1+ features
17396
- stages: data.stages,
17397
- personality: data.personality,
17398
- thinking_patterns: data.thinking_patterns,
17399
- abilitySelection: data.abilitySelection,
18271
+ stages: profileData.stages,
18272
+ personality: profileData.personality,
18273
+ thinking_patterns: profileData.thinking_patterns,
18274
+ abilitySelection: profileData.abilitySelection,
17400
18275
  // v5.7.0+: Agent Selection Metadata
17401
- selectionMetadata: data.selectionMetadata,
18276
+ selectionMetadata: profileData.selectionMetadata,
17402
18277
  // Provider preferences (deprecated, kept for backward compatibility)
17403
- provider: data.provider,
17404
- model: data.model,
17405
- temperature: data.temperature,
17406
- maxTokens: data.maxTokens,
18278
+ provider: profileData.provider,
18279
+ model: profileData.model,
18280
+ temperature: profileData.temperature,
18281
+ maxTokens: profileData.maxTokens,
17407
18282
  // Optional
17408
- tags: data.tags,
17409
- version: data.version,
17410
- metadata: data.metadata,
18283
+ tags: profileData.tags,
18284
+ version: profileData.version,
18285
+ metadata: profileData.metadata,
17411
18286
  // v4.7.0+ Orchestration (merged with team defaults)
17412
18287
  orchestration
17413
18288
  };
@@ -20579,6 +21454,24 @@ ${context.task}`;
20579
21454
  // src/agents/agent-selector.ts
20580
21455
  init_esm_shims();
20581
21456
  init_logger();
21457
+ var regexCache = /* @__PURE__ */ new Map();
21458
+ function getCachedRegex(pattern) {
21459
+ if (regexCache.has(pattern)) {
21460
+ return regexCache.get(pattern) ?? null;
21461
+ }
21462
+ try {
21463
+ const regex = new RegExp(pattern, "i");
21464
+ regexCache.set(pattern, regex);
21465
+ return regex;
21466
+ } catch (error) {
21467
+ logger.debug("Invalid regex pattern cached as null", {
21468
+ pattern,
21469
+ error: error instanceof Error ? error.message : String(error)
21470
+ });
21471
+ regexCache.set(pattern, null);
21472
+ return null;
21473
+ }
21474
+ }
20582
21475
  function scoreAgent(task, profile) {
20583
21476
  let score = 0;
20584
21477
  const taskLower = task.toLowerCase();
@@ -20616,16 +21509,9 @@ function scoreAgent(task, profile) {
20616
21509
  }
20617
21510
  if (profile.selectionMetadata?.redirectWhen) {
20618
21511
  for (const rule of profile.selectionMetadata.redirectWhen) {
20619
- try {
20620
- const regex = new RegExp(rule.phrase, "i");
20621
- if (regex.test(task)) {
20622
- score -= 15;
20623
- }
20624
- } catch (error) {
20625
- logger.debug("Invalid regex pattern in redirectWhen rule", {
20626
- pattern: rule.phrase,
20627
- error: error instanceof Error ? error.message : String(error)
20628
- });
21512
+ const regex = getCachedRegex(rule.phrase);
21513
+ if (regex && regex.test(task)) {
21514
+ score -= 15;
20629
21515
  }
20630
21516
  }
20631
21517
  }
@@ -22983,7 +23869,7 @@ var BugDetector = class {
22983
23869
  });
22984
23870
  let files;
22985
23871
  if (fileFilter && fileFilter.length > 0) {
22986
- files = fileFilter.map((f) => f.startsWith("/") ? f : join(rootDir, f)).filter((f) => {
23872
+ files = fileFilter.map((f) => isAbsolute(f) ? f : join(rootDir, f)).filter((f) => {
22987
23873
  const ext = extname$1(f);
22988
23874
  return [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"].includes(ext);
22989
23875
  }).filter((f) => !this.isExcluded(relative(rootDir, f)));
@@ -23215,8 +24101,8 @@ var BugDetector = class {
23215
24101
  async loadRulesFromFile(filePath) {
23216
24102
  try {
23217
24103
  const content = await readFile(filePath, "utf-8");
23218
- const yaml2 = await import('js-yaml');
23219
- const parsed = yaml2.load(content);
24104
+ const yaml = await import('js-yaml');
24105
+ const parsed = yaml.load(content);
23220
24106
  if (parsed.rules && Array.isArray(parsed.rules)) {
23221
24107
  for (const rule of parsed.rules) {
23222
24108
  this.addRule(rule);
@@ -23648,7 +24534,6 @@ var BugFixer = class {
23648
24534
  }
23649
24535
  const directSetIntervalPattern = /setInterval\s*\(/;
23650
24536
  if (directSetIntervalPattern.test(line)) {
23651
- line.match(/^(\s*)/)?.[1] || "";
23652
24537
  const newLine = line.replace(
23653
24538
  /(setInterval\s*\([^)]+\))/,
23654
24539
  "const _interval = $1; if (_interval.unref) _interval.unref()"
@@ -23675,7 +24560,6 @@ var BugFixer = class {
23675
24560
  const match = currentLine.match(classPattern);
23676
24561
  if (match && match[1]) {
23677
24562
  classStartLine = i;
23678
- match[1];
23679
24563
  break;
23680
24564
  }
23681
24565
  }
@@ -23727,7 +24611,7 @@ var BugFixer = class {
23727
24611
  /**
23728
24612
  * Apply use DisposableEventEmitter fix
23729
24613
  */
23730
- applyUseDisposableEventEmitterFix(finding, originalContent, lines) {
24614
+ applyUseDisposableEventEmitterFix(finding, originalContent, _lines) {
23731
24615
  let fixedContent = originalContent.replace(
23732
24616
  /extends\s+EventEmitter\b/g,
23733
24617
  "extends DisposableEventEmitter"
@@ -24649,7 +25533,7 @@ var DUPLICATION_RULES = [
24649
25533
  suggestion: "Extract to a named constant"
24650
25534
  }
24651
25535
  ];
24652
- function detectDuplication(filePath, content, lines, ignoreState, config) {
25536
+ function detectDuplication(filePath, content, lines, ignoreState, _config) {
24653
25537
  const findings = [];
24654
25538
  findings.push(...detectDuplicateBlocks(filePath, content, lines, ignoreState));
24655
25539
  findings.push(...detectRepeatedConditionals(filePath, content, lines, ignoreState));
@@ -24676,7 +25560,7 @@ function detectDuplicateBlocks(filePath, content, lines, ignoreState) {
24676
25560
  }
24677
25561
  blockHashes.get(blockHash).push({ start: i + 1, end: i + MIN_BLOCK_SIZE });
24678
25562
  }
24679
- for (const [hash, locations] of blockHashes) {
25563
+ for (const [_hash, locations] of blockHashes) {
24680
25564
  if (locations.length > 1) {
24681
25565
  for (let i = 1; i < locations.length; i++) {
24682
25566
  const loc = locations[i];
@@ -24725,7 +25609,7 @@ function detectRepeatedConditionals(filePath, content, lines, ignoreState) {
24725
25609
  }
24726
25610
  conditionPattern.lastIndex = 0;
24727
25611
  }
24728
- for (const [condition, lineNums] of conditionalCounts) {
25612
+ for (const [_condition, lineNums] of conditionalCounts) {
24729
25613
  if (lineNums.length >= 2) {
24730
25614
  const firstLine = lineNums[0];
24731
25615
  const secondLine = lineNums[1];
@@ -24888,7 +25772,7 @@ var THRESHOLDS = {
24888
25772
  maxCyclomaticComplexity: 10,
24889
25773
  maxChainedCalls: 4
24890
25774
  };
24891
- function detectReadability(filePath, content, lines, ignoreState, config) {
25775
+ function detectReadability(filePath, content, lines, ignoreState, _config) {
24892
25776
  const findings = [];
24893
25777
  findings.push(...detectLongFunctions(filePath, content, lines, ignoreState));
24894
25778
  findings.push(...detectDeepNesting(filePath, content, lines, ignoreState));
@@ -25264,7 +26148,7 @@ var PERFORMANCE_RULES = [
25264
26148
  suggestion: "Remove await - async functions automatically wrap return values in promises"
25265
26149
  }
25266
26150
  ];
25267
- function detectPerformance(filePath, content, lines, ignoreState, config) {
26151
+ function detectPerformance(filePath, content, lines, ignoreState, _config) {
25268
26152
  const findings = [];
25269
26153
  findings.push(...detectSyncInAsync(filePath, content, lines, ignoreState));
25270
26154
  findings.push(...detectNPlusOne(filePath, content, lines, ignoreState));
@@ -25679,7 +26563,7 @@ var HARDCODE_RULES = [
25679
26563
  suggestion: "Extract timeout to a named constant or config"
25680
26564
  }
25681
26565
  ];
25682
- function detectHardcode(filePath, content, lines, ignoreState, config) {
26566
+ function detectHardcode(filePath, content, lines, ignoreState, _config) {
25683
26567
  const findings = [];
25684
26568
  findings.push(...detectMagicNumbers(filePath, content, lines, ignoreState));
25685
26569
  findings.push(...detectHardcodedUrls(filePath, content, lines, ignoreState));
@@ -26035,7 +26919,7 @@ var NAMING_RULES = [
26035
26919
  suggestion: "Use is/has/can/should prefix for boolean variables"
26036
26920
  }
26037
26921
  ];
26038
- function detectNaming(filePath, content, lines, ignoreState, config) {
26922
+ function detectNaming(filePath, content, lines, ignoreState, _config) {
26039
26923
  const findings = [];
26040
26924
  findings.push(...detectSingleLetterVariables(filePath, content, lines, ignoreState));
26041
26925
  findings.push(...detectHungarianNotation(filePath, content, lines, ignoreState));
@@ -26318,7 +27202,7 @@ var CONDITIONAL_RULES = [
26318
27202
  suggestion: "Use the condition directly (or negate it)"
26319
27203
  }
26320
27204
  ];
26321
- function detectConditionals(filePath, content, lines, ignoreState, config) {
27205
+ function detectConditionals(filePath, content, lines, ignoreState, _config) {
26322
27206
  const findings = [];
26323
27207
  findings.push(...detectDeeplyNestedIf(filePath, content, lines, ignoreState));
26324
27208
  findings.push(...detectComplexConditions(filePath, content, lines, ignoreState));
@@ -26631,7 +27515,7 @@ var DEAD_CODE_RULES = [
26631
27515
  suggestion: "Implement function or add TODO comment"
26632
27516
  }
26633
27517
  ];
26634
- function detectDeadCode(filePath, content, lines, ignoreState, config) {
27518
+ function detectDeadCode(filePath, content, lines, ignoreState, _config) {
26635
27519
  const findings = [];
26636
27520
  findings.push(...detectUnusedImports(filePath, content, lines, ignoreState));
26637
27521
  findings.push(...detectUnusedVariables(filePath, content, lines, ignoreState));
@@ -26925,7 +27809,7 @@ var TYPE_SAFETY_RULES = [
26925
27809
  fileExtensions: [".ts", ".tsx"]
26926
27810
  }
26927
27811
  ];
26928
- function detectTypeSafety(filePath, content, lines, ignoreState, config) {
27812
+ function detectTypeSafety(filePath, content, lines, ignoreState, _config) {
26929
27813
  const findings = [];
26930
27814
  if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
26931
27815
  return findings;
@@ -27531,6 +28415,9 @@ function countAnyTypes(code) {
27531
28415
  }
27532
28416
  return count;
27533
28417
  }
28418
+ function escapeRegex2(str) {
28419
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28420
+ }
27534
28421
  function countUnusedImports(code) {
27535
28422
  const importMatches = code.match(/import\s+{([^}]+)}\s+from/g);
27536
28423
  if (!importMatches) return 0;
@@ -27540,10 +28427,17 @@ function countUnusedImports(code) {
27540
28427
  const namedImports = importMatch.match(/{([^}]+)}/);
27541
28428
  const namedImportContent = namedImports?.[1];
27542
28429
  if (namedImportContent) {
27543
- const names = namedImportContent.split(",").map((n) => n.trim().split(/\s+as\s+/).pop()?.trim() ?? "");
28430
+ const names = namedImportContent.split(",").map((n) => {
28431
+ const trimmed = n.trim();
28432
+ const withoutType = trimmed.replace(/^type\s+/, "");
28433
+ return withoutType.split(/\s+as\s+/).pop()?.trim() ?? "";
28434
+ }).filter((name) => name.length > 0 && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name));
27544
28435
  for (const name of names) {
27545
- if (name && !new RegExp(`\\b${name}\\b`).test(codeWithoutImports)) {
27546
- unusedCount++;
28436
+ try {
28437
+ if (!new RegExp(`\\b${escapeRegex2(name)}\\b`).test(codeWithoutImports)) {
28438
+ unusedCount++;
28439
+ }
28440
+ } catch {
27547
28441
  }
27548
28442
  }
27549
28443
  }
@@ -30999,6 +31893,7 @@ init_logger();
30999
31893
  // src/core/task-engine/task-queue.ts
31000
31894
  init_esm_shims();
31001
31895
  init_logger();
31896
+ init_safe_timers();
31002
31897
 
31003
31898
  // src/mcp/tools/task/create-task.ts
31004
31899
  init_logger();
@@ -31123,7 +32018,7 @@ var createTaskSchema = {
31123
32018
  // src/mcp/tools/task/run-task.ts
31124
32019
  init_esm_shims();
31125
32020
  init_logger();
31126
- function createRunTaskHandler(deps) {
32021
+ function createRunTaskHandler(_deps) {
31127
32022
  return async (input, context) => {
31128
32023
  const startTime = Date.now();
31129
32024
  if (context?.signal?.aborted) {
@@ -33673,6 +34568,17 @@ Use this tool first to understand what AutomatosX offers.`,
33673
34568
  mode: "sdk"
33674
34569
  }));
33675
34570
  }
34571
+ if (config.providers["qwen"]?.enabled) {
34572
+ const { QwenProvider: QwenProvider2 } = await Promise.resolve().then(() => (init_qwen_provider(), qwen_provider_exports));
34573
+ const qwenConfig = config.providers["qwen"];
34574
+ providers.push(new QwenProvider2({
34575
+ name: "qwen",
34576
+ enabled: true,
34577
+ priority: qwenConfig.priority,
34578
+ timeout: qwenConfig.timeout,
34579
+ mode: qwenConfig.mode || "sdk"
34580
+ }));
34581
+ }
33676
34582
  const healthCheckInterval = config.router?.healthCheckInterval;
33677
34583
  this.router = new Router({
33678
34584
  providers,