@defai.digital/automatosx 12.6.2 → 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/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import * as path4 from 'path';
3
3
  import path4__default, { dirname, join, isAbsolute, basename, resolve, extname as extname$1, relative, sep, delimiter, normalize, parse as parse$1 } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
- import { mkdir, appendFile, access as access$1, readFile, stat, rm, readdir, copyFile, writeFile, rename, unlink, constants as constants$1, realpath as realpath$1 } from 'fs/promises';
5
+ import { mkdir, appendFile, access as access$1, stat, readFile, rm, readdir, copyFile, writeFile, rename, unlink, constants as constants$1, realpath as realpath$1 } from 'fs/promises';
6
6
  import * as fs4 from 'fs';
7
7
  import { access, realpath, existsSync, readFileSync, constants, writeFileSync, promises, mkdirSync, statSync, readdirSync, createWriteStream, unlinkSync } from 'fs';
8
8
  import Database2 from 'better-sqlite3';
@@ -20,15 +20,14 @@ import { promisify } from 'util';
20
20
  import yargs from 'yargs';
21
21
  import { hideBin } from 'yargs/helpers';
22
22
  import crypto4, { randomUUID, createHash, randomBytes } from 'crypto';
23
- import * as yaml4 from 'js-yaml';
24
- import yaml4__default, { load, dump } from 'js-yaml';
23
+ import * as yaml3 from 'js-yaml';
24
+ import yaml3__default, { load, dump } from 'js-yaml';
25
25
  import Table from 'cli-table3';
26
26
  import inquirer from 'inquirer';
27
27
  import Ajv from 'ajv';
28
28
  import addFormats from 'ajv-formats';
29
29
  import { EventEmitter } from 'events';
30
30
  import * as sqliteVec from 'sqlite-vec';
31
- import yaml from 'yaml';
32
31
  import { gzipSync, gunzipSync } from 'zlib';
33
32
  import { parse } from '@iarna/toml';
34
33
 
@@ -2748,6 +2747,7 @@ function getRetryableErrors(provider) {
2748
2747
  return [...baseErrors, ...CODEX_RETRYABLE_ERRORS];
2749
2748
  case "glm":
2750
2749
  case "grok":
2750
+ case "qwen":
2751
2751
  return [...baseErrors, ...OPENAI_RETRYABLE_ERRORS];
2752
2752
  case "base":
2753
2753
  default:
@@ -2850,6 +2850,10 @@ var init_base_provider = __esm({
2850
2850
  // v12.0.0: Native Grok provider (xAI)
2851
2851
  "ax-grok",
2852
2852
  // v12.0.0: Alias for grok
2853
+ "qwen",
2854
+ // v12.7.0: Qwen Code provider (Alibaba Cloud)
2855
+ "qwen-code",
2856
+ // v12.7.0: Alias for qwen
2853
2857
  "test-provider"
2854
2858
  // For unit tests
2855
2859
  ];
@@ -3212,7 +3216,7 @@ var init_base_provider = __esm({
3212
3216
  if (readlineInterface) {
3213
3217
  try {
3214
3218
  readlineInterface.close();
3215
- } catch (error) {
3219
+ } catch {
3216
3220
  } finally {
3217
3221
  readlineInterface = null;
3218
3222
  }
@@ -3220,7 +3224,7 @@ var init_base_provider = __esm({
3220
3224
  if (stderrInterface) {
3221
3225
  try {
3222
3226
  stderrInterface.close();
3223
- } catch (error) {
3227
+ } catch {
3224
3228
  } finally {
3225
3229
  stderrInterface = null;
3226
3230
  }
@@ -3414,7 +3418,7 @@ ${fullPrompt}
3414
3418
  this.health.consecutiveSuccesses = 0;
3415
3419
  }
3416
3420
  return available;
3417
- } catch (error) {
3421
+ } catch {
3418
3422
  this.health.available = false;
3419
3423
  this.health.errorRate = 1;
3420
3424
  this.health.lastCheck = Date.now();
@@ -3590,6 +3594,8 @@ ${fullPrompt}
3590
3594
  retryableProvider = "glm";
3591
3595
  } else if (providerName === "grok" || providerName === "ax-grok") {
3592
3596
  retryableProvider = "grok";
3597
+ } else if (providerName === "qwen" || providerName === "qwen-code") {
3598
+ retryableProvider = "qwen";
3593
3599
  }
3594
3600
  return shouldRetryError(error, retryableProvider);
3595
3601
  }
@@ -6044,13 +6050,21 @@ var init_types2 = __esm({
6044
6050
  "src/integrations/ax-glm/types.ts"() {
6045
6051
  init_esm_shims();
6046
6052
  GLM_MODEL_MAPPING = {
6053
+ // Convenience aliases (ax-cli v4.3.15)
6054
+ "glm-latest": "glm-4.6",
6055
+ "glm-vision": "glm-4.6v",
6056
+ "glm-fast": "glm-4-flash",
6057
+ "glm-image": "cogview-4",
6058
+ // Legacy aliases (deprecated)
6047
6059
  "glm-4-plus": "glm-4.6",
6048
- "glm-4v": "glm-4.5v",
6060
+ "glm-4.5v": "glm-4.6v",
6061
+ "glm-4v": "glm-4.6v",
6062
+ "glm-4": "glm-4.6",
6049
6063
  "glm-4-air": "glm-4-flash",
6050
6064
  "glm-4-airx": "glm-4-flash"
6051
6065
  };
6052
6066
  GLM_DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
6053
- GLM_DEFAULT_MODEL = "glm-4";
6067
+ GLM_DEFAULT_MODEL = "glm-4.6";
6054
6068
  GLM_DEFAULT_COMMAND = "ax-glm";
6055
6069
  }
6056
6070
  });
@@ -6206,14 +6220,14 @@ var init_sdk_adapter2 = __esm({
6206
6220
  };
6207
6221
  }
6208
6222
  });
6209
- var execAsync3, GLMCliWrapper;
6223
+ var execAsync4, GLMCliWrapper;
6210
6224
  var init_cli_wrapper2 = __esm({
6211
6225
  "src/integrations/ax-glm/cli-wrapper.ts"() {
6212
6226
  init_esm_shims();
6213
6227
  init_logger();
6214
6228
  init_validation_limits();
6215
6229
  init_types2();
6216
- execAsync3 = promisify(exec);
6230
+ execAsync4 = promisify(exec);
6217
6231
  GLMCliWrapper = class {
6218
6232
  config;
6219
6233
  cliPath = null;
@@ -6234,13 +6248,13 @@ var init_cli_wrapper2 = __esm({
6234
6248
  */
6235
6249
  async isAvailable() {
6236
6250
  try {
6237
- const { stdout } = await execAsync3(`which ${this.config.command}`, {
6251
+ const { stdout } = await execAsync4(`which ${this.config.command}`, {
6238
6252
  timeout: TIMEOUTS.PROVIDER_DETECTION
6239
6253
  });
6240
6254
  this.cliPath = stdout.trim();
6241
6255
  if (this.cliPath) {
6242
6256
  try {
6243
- const { stdout: versionOutput } = await execAsync3(
6257
+ const { stdout: versionOutput } = await execAsync4(
6244
6258
  `${this.config.command} --version`,
6245
6259
  { timeout: TIMEOUTS.PROVIDER_DETECTION }
6246
6260
  );
@@ -6999,10 +7013,18 @@ var init_types3 = __esm({
6999
7013
  "src/integrations/ax-grok/types.ts"() {
7000
7014
  init_esm_shims();
7001
7015
  GROK_MODEL_MAPPING = {
7002
- "grok-beta": "grok-3"
7016
+ // Convenience aliases (ax-cli v4.3.15)
7017
+ "grok-latest": "grok-4-0709",
7018
+ "grok-fast": "grok-4.1-fast",
7019
+ "grok-mini": "grok-3-mini",
7020
+ "grok-vision": "grok-2-vision-1212",
7021
+ "grok-image": "grok-2-image-1212",
7022
+ // Legacy aliases (deprecated)
7023
+ "grok-beta": "grok-3",
7024
+ "grok-2-vision": "grok-2-vision-1212"
7003
7025
  };
7004
7026
  GROK_DEFAULT_BASE_URL = "https://api.x.ai/v1";
7005
- GROK_DEFAULT_MODEL = "grok-3";
7027
+ GROK_DEFAULT_MODEL = "grok-4-0709";
7006
7028
  GROK_DEFAULT_COMMAND = "ax-grok";
7007
7029
  }
7008
7030
  });
@@ -7158,14 +7180,14 @@ var init_sdk_adapter3 = __esm({
7158
7180
  };
7159
7181
  }
7160
7182
  });
7161
- var execAsync4, GrokCliWrapper;
7183
+ var execAsync5, GrokCliWrapper;
7162
7184
  var init_cli_wrapper3 = __esm({
7163
7185
  "src/integrations/ax-grok/cli-wrapper.ts"() {
7164
7186
  init_esm_shims();
7165
7187
  init_logger();
7166
7188
  init_validation_limits();
7167
7189
  init_types3();
7168
- execAsync4 = promisify(exec);
7190
+ execAsync5 = promisify(exec);
7169
7191
  GrokCliWrapper = class {
7170
7192
  config;
7171
7193
  cliPath = null;
@@ -7186,13 +7208,13 @@ var init_cli_wrapper3 = __esm({
7186
7208
  */
7187
7209
  async isAvailable() {
7188
7210
  try {
7189
- const { stdout } = await execAsync4(`which ${this.config.command}`, {
7211
+ const { stdout } = await execAsync5(`which ${this.config.command}`, {
7190
7212
  timeout: TIMEOUTS.PROVIDER_DETECTION
7191
7213
  });
7192
7214
  this.cliPath = stdout.trim();
7193
7215
  if (this.cliPath) {
7194
7216
  try {
7195
- const { stdout: versionOutput } = await execAsync4(
7217
+ const { stdout: versionOutput } = await execAsync5(
7196
7218
  `${this.config.command} --version`,
7197
7219
  { timeout: TIMEOUTS.PROVIDER_DETECTION }
7198
7220
  );
@@ -7934,6 +7956,902 @@ Mode: ${this.grokConfig.mode || "auto"}`;
7934
7956
  }
7935
7957
  });
7936
7958
 
7959
+ // src/integrations/qwen-code/types.ts
7960
+ function normalizeQwenModel(model) {
7961
+ return QWEN_MODEL_MAPPING[model] || model;
7962
+ }
7963
+ function isVisionModel(model) {
7964
+ return model.includes("qwen3-coder") || model.includes("qwen-max");
7965
+ }
7966
+ function getModelContextWindow(model) {
7967
+ const normalizedModel = normalizeQwenModel(model);
7968
+ if (normalizedModel.includes("480b")) return 128e3;
7969
+ if (normalizedModel.includes("30b")) return 64e3;
7970
+ if (normalizedModel.includes("qwen-max")) return 128e3;
7971
+ if (normalizedModel.includes("qwen-plus")) return 128e3;
7972
+ if (normalizedModel.includes("qwen-turbo")) return 128e3;
7973
+ return 64e3;
7974
+ }
7975
+ var QWEN_DEFAULT_BASE_URL, QWEN_DEFAULT_MODEL, QWEN_DEFAULT_COMMAND, QWEN_MODEL_MAPPING;
7976
+ var init_types4 = __esm({
7977
+ "src/integrations/qwen-code/types.ts"() {
7978
+ init_esm_shims();
7979
+ QWEN_DEFAULT_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
7980
+ QWEN_DEFAULT_MODEL = "qwen-turbo";
7981
+ QWEN_DEFAULT_COMMAND = "qwen";
7982
+ QWEN_MODEL_MAPPING = {
7983
+ // Normalize common aliases
7984
+ "qwen-coder": "qwen3-coder-480b-a35b-instruct",
7985
+ "qwen-coder-480b": "qwen3-coder-480b-a35b-instruct",
7986
+ "qwen-coder-30b": "qwen3-coder-30b-a3b-instruct",
7987
+ "qwen2.5-coder": "qwen2.5-coder-32b-instruct"
7988
+ };
7989
+ }
7990
+ });
7991
+
7992
+ // src/integrations/qwen-code/sdk-adapter.ts
7993
+ var QwenSdkAdapter;
7994
+ var init_sdk_adapter4 = __esm({
7995
+ "src/integrations/qwen-code/sdk-adapter.ts"() {
7996
+ init_esm_shims();
7997
+ init_logger();
7998
+ init_validation_limits();
7999
+ init_types4();
8000
+ QwenSdkAdapter = class {
8001
+ client = null;
8002
+ config;
8003
+ initialized = false;
8004
+ constructor(config = {}) {
8005
+ const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
8006
+ this.config = {
8007
+ apiKey,
8008
+ baseUrl: config.baseUrl || QWEN_DEFAULT_BASE_URL,
8009
+ model: config.model || QWEN_DEFAULT_MODEL,
8010
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
8011
+ };
8012
+ logger.debug("[Qwen SDK] Adapter created", {
8013
+ model: this.config.model,
8014
+ baseUrl: this.config.baseUrl,
8015
+ hasApiKey: !!this.config.apiKey
8016
+ });
8017
+ }
8018
+ /**
8019
+ * Check if SDK is available (OpenAI package installed and API key configured)
8020
+ */
8021
+ async isAvailable() {
8022
+ try {
8023
+ if (!this.config.apiKey) {
8024
+ logger.debug("[Qwen SDK] No API key configured (set DASHSCOPE_API_KEY or QWEN_API_KEY)");
8025
+ return false;
8026
+ }
8027
+ await import('openai');
8028
+ return true;
8029
+ } catch (error) {
8030
+ logger.debug("[Qwen SDK] OpenAI SDK not available", {
8031
+ error: error instanceof Error ? error.message : String(error)
8032
+ });
8033
+ return false;
8034
+ }
8035
+ }
8036
+ /**
8037
+ * Initialize the SDK client
8038
+ */
8039
+ async initialize() {
8040
+ if (this.initialized) {
8041
+ return;
8042
+ }
8043
+ try {
8044
+ const OpenAI = (await import('openai')).default;
8045
+ this.client = new OpenAI({
8046
+ apiKey: this.config.apiKey,
8047
+ baseURL: this.config.baseUrl,
8048
+ timeout: this.config.timeout
8049
+ });
8050
+ this.initialized = true;
8051
+ logger.debug("[Qwen SDK] Client initialized", {
8052
+ model: this.config.model
8053
+ });
8054
+ } catch (error) {
8055
+ throw new Error(
8056
+ `Failed to initialize Qwen SDK: ${error instanceof Error ? error.message : String(error)}`
8057
+ );
8058
+ }
8059
+ }
8060
+ /**
8061
+ * Execute a request using the Qwen SDK
8062
+ */
8063
+ async execute(request) {
8064
+ if (!this.initialized) {
8065
+ await this.initialize();
8066
+ }
8067
+ const startTime = Date.now();
8068
+ try {
8069
+ const messages = [];
8070
+ if (request.systemPrompt) {
8071
+ messages.push({
8072
+ role: "system",
8073
+ content: request.systemPrompt
8074
+ });
8075
+ }
8076
+ messages.push({
8077
+ role: "user",
8078
+ content: request.prompt
8079
+ });
8080
+ const model = normalizeQwenModel(request.model || this.config.model);
8081
+ logger.debug("[Qwen SDK] Executing request", {
8082
+ model,
8083
+ messageCount: messages.length,
8084
+ promptLength: request.prompt.length
8085
+ });
8086
+ const openaiClient = this.client;
8087
+ const response = await openaiClient.chat.completions.create({
8088
+ model,
8089
+ messages,
8090
+ max_tokens: request.maxTokens,
8091
+ temperature: request.temperature,
8092
+ stream: false
8093
+ });
8094
+ const latencyMs = Date.now() - startTime;
8095
+ if (!response.choices || response.choices.length === 0) {
8096
+ throw new Error("Qwen API returned empty choices array");
8097
+ }
8098
+ const choice = response.choices[0];
8099
+ const content = choice?.message?.content || "";
8100
+ const finishReason = choice?.finish_reason || "unknown";
8101
+ logger.debug("[Qwen SDK] Request completed", {
8102
+ model: response.model,
8103
+ latencyMs,
8104
+ tokensUsed: response.usage?.total_tokens
8105
+ });
8106
+ return {
8107
+ content,
8108
+ model: response.model,
8109
+ tokensUsed: response.usage ? {
8110
+ prompt: response.usage.prompt_tokens,
8111
+ completion: response.usage.completion_tokens,
8112
+ total: response.usage.total_tokens
8113
+ } : { prompt: 0, completion: 0, total: 0 },
8114
+ latencyMs,
8115
+ finishReason,
8116
+ cached: false
8117
+ };
8118
+ } catch (error) {
8119
+ const latencyMs = Date.now() - startTime;
8120
+ logger.error("[Qwen SDK] Request failed", {
8121
+ error: error instanceof Error ? error.message : String(error),
8122
+ latencyMs
8123
+ });
8124
+ throw error;
8125
+ }
8126
+ }
8127
+ /**
8128
+ * Get the configured model
8129
+ */
8130
+ getModel() {
8131
+ return this.config.model;
8132
+ }
8133
+ /**
8134
+ * Clean up resources
8135
+ */
8136
+ async destroy() {
8137
+ this.client = null;
8138
+ this.initialized = false;
8139
+ logger.debug("[Qwen SDK] Adapter destroyed");
8140
+ }
8141
+ };
8142
+ }
8143
+ });
8144
+ var NON_INTERACTIVE_ENV, SIGKILL_ESCALATION_MS, QwenCliWrapper;
8145
+ var init_cli_wrapper4 = __esm({
8146
+ "src/integrations/qwen-code/cli-wrapper.ts"() {
8147
+ init_esm_shims();
8148
+ init_logger();
8149
+ init_validation_limits();
8150
+ init_cli_provider_detector();
8151
+ init_types4();
8152
+ NON_INTERACTIVE_ENV = {
8153
+ TERM: "dumb",
8154
+ NO_COLOR: "1",
8155
+ FORCE_COLOR: "0",
8156
+ CI: "true",
8157
+ NO_UPDATE_NOTIFIER: "1",
8158
+ DEBIAN_FRONTEND: "noninteractive"
8159
+ };
8160
+ SIGKILL_ESCALATION_MS = 5e3;
8161
+ QwenCliWrapper = class {
8162
+ config;
8163
+ constructor(config = {}) {
8164
+ this.config = {
8165
+ command: config.command || QWEN_DEFAULT_COMMAND,
8166
+ vlmSwitchMode: config.vlmSwitchMode || "once",
8167
+ yolo: config.yolo || false,
8168
+ timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
8169
+ };
8170
+ logger.debug("[Qwen CLI] Wrapper created", {
8171
+ command: this.config.command,
8172
+ timeout: this.config.timeout
8173
+ });
8174
+ }
8175
+ /**
8176
+ * Check if Qwen CLI is available on PATH
8177
+ */
8178
+ async isAvailable() {
8179
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
8180
+ return true;
8181
+ }
8182
+ try {
8183
+ const result = findOnPath(this.config.command);
8184
+ logger.debug("[Qwen CLI] Availability check", {
8185
+ available: result.found,
8186
+ path: result.path
8187
+ });
8188
+ return result.found;
8189
+ } catch (error) {
8190
+ logger.debug("[Qwen CLI] Availability check failed", {
8191
+ error: error instanceof Error ? error.message : String(error)
8192
+ });
8193
+ return false;
8194
+ }
8195
+ }
8196
+ /**
8197
+ * Execute a prompt using the Qwen CLI
8198
+ *
8199
+ * Since Qwen CLI is interactive, we:
8200
+ * 1. Spawn the process
8201
+ * 2. Send the prompt via stdin
8202
+ * 3. Capture output until we detect completion
8203
+ * 4. Return the response
8204
+ */
8205
+ async execute(request) {
8206
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
8207
+ return this.createMockResponse(request.prompt);
8208
+ }
8209
+ const startTime = Date.now();
8210
+ return new Promise((resolve13, reject) => {
8211
+ const args = [];
8212
+ if (this.config.vlmSwitchMode !== "once") {
8213
+ args.push("--vlm-switch-mode", this.config.vlmSwitchMode);
8214
+ }
8215
+ if (this.config.yolo) {
8216
+ args.push("--yolo");
8217
+ }
8218
+ logger.debug("[Qwen CLI] Spawning process", {
8219
+ command: this.config.command,
8220
+ args,
8221
+ promptLength: request.prompt.length
8222
+ });
8223
+ const child = spawn(this.config.command, args, {
8224
+ env: { ...process.env, ...NON_INTERACTIVE_ENV }
8225
+ });
8226
+ let stdout = "";
8227
+ let stderr = "";
8228
+ let timeoutId = null;
8229
+ let forceKillTimer = null;
8230
+ let readlineInterface = null;
8231
+ let responseStarted = false;
8232
+ const cleanup = () => {
8233
+ if (timeoutId) {
8234
+ clearTimeout(timeoutId);
8235
+ timeoutId = null;
8236
+ }
8237
+ if (forceKillTimer) {
8238
+ clearTimeout(forceKillTimer);
8239
+ forceKillTimer = null;
8240
+ }
8241
+ if (readlineInterface) {
8242
+ try {
8243
+ readlineInterface.close();
8244
+ } catch {
8245
+ }
8246
+ readlineInterface = null;
8247
+ }
8248
+ };
8249
+ if (child.stdout) {
8250
+ readlineInterface = readline2__default.createInterface({
8251
+ input: child.stdout,
8252
+ crlfDelay: Infinity
8253
+ });
8254
+ readlineInterface.on("line", (line) => {
8255
+ if (line.startsWith(">") && !responseStarted) {
8256
+ responseStarted = true;
8257
+ return;
8258
+ }
8259
+ if (responseStarted) {
8260
+ stdout += line + "\n";
8261
+ }
8262
+ });
8263
+ readlineInterface.on("error", (error) => {
8264
+ logger.debug("[Qwen CLI] Readline error", {
8265
+ error: error.message
8266
+ });
8267
+ });
8268
+ }
8269
+ if (child.stderr) {
8270
+ child.stderr.on("data", (data) => {
8271
+ stderr += data.toString();
8272
+ });
8273
+ }
8274
+ if (child.stdin) {
8275
+ try {
8276
+ let fullPrompt = request.prompt;
8277
+ if (request.systemPrompt) {
8278
+ fullPrompt = `${request.systemPrompt}
8279
+
8280
+ ${request.prompt}`;
8281
+ }
8282
+ child.stdin.write(fullPrompt);
8283
+ child.stdin.write("\n");
8284
+ child.stdin.end();
8285
+ } catch (error) {
8286
+ cleanup();
8287
+ child.kill("SIGTERM");
8288
+ reject(new Error(`Failed to write to Qwen stdin: ${error instanceof Error ? error.message : String(error)}`));
8289
+ return;
8290
+ }
8291
+ } else {
8292
+ cleanup();
8293
+ reject(new Error("Qwen CLI stdin not available"));
8294
+ return;
8295
+ }
8296
+ child.on("close", (code, signal) => {
8297
+ cleanup();
8298
+ const latencyMs = Date.now() - startTime;
8299
+ if (stderr) {
8300
+ logger.debug("[Qwen CLI] stderr output", { stderr: stderr.trim() });
8301
+ }
8302
+ if ((code === 0 || code === null) && !signal) {
8303
+ const content = this.parseResponse(stdout);
8304
+ resolve13({
8305
+ content: content.trim(),
8306
+ model: "qwen-code-cli",
8307
+ tokensUsed: {
8308
+ prompt: this.estimateTokens(request.prompt),
8309
+ completion: this.estimateTokens(content),
8310
+ total: this.estimateTokens(request.prompt) + this.estimateTokens(content)
8311
+ },
8312
+ latencyMs,
8313
+ finishReason: "stop",
8314
+ cached: false
8315
+ });
8316
+ } else if (signal) {
8317
+ reject(new Error(`Qwen CLI killed by signal ${signal}. stderr: ${stderr || "none"}`));
8318
+ } else {
8319
+ reject(new Error(`Qwen CLI exited with code ${code}. stderr: ${stderr || "none"}`));
8320
+ }
8321
+ });
8322
+ child.on("error", (error) => {
8323
+ cleanup();
8324
+ logger.error("[Qwen CLI] Process error", {
8325
+ error: error.message
8326
+ });
8327
+ reject(new Error(`Failed to spawn Qwen CLI: ${error.message}`));
8328
+ });
8329
+ timeoutId = setTimeout(() => {
8330
+ if (child.pid && !child.killed) {
8331
+ logger.warn("[Qwen CLI] Killing process due to timeout", {
8332
+ pid: child.pid,
8333
+ timeout: this.config.timeout
8334
+ });
8335
+ child.kill("SIGTERM");
8336
+ forceKillTimer = setTimeout(() => {
8337
+ if (child.pid) {
8338
+ try {
8339
+ process.kill(child.pid, 0);
8340
+ logger.warn("[Qwen CLI] Force killing process", { pid: child.pid });
8341
+ child.kill("SIGKILL");
8342
+ } catch {
8343
+ }
8344
+ }
8345
+ }, SIGKILL_ESCALATION_MS);
8346
+ }
8347
+ }, this.config.timeout);
8348
+ });
8349
+ }
8350
+ /**
8351
+ * Parse response from CLI output
8352
+ *
8353
+ * Qwen CLI outputs include prompts and formatting that we need to strip.
8354
+ */
8355
+ parseResponse(output) {
8356
+ let content = output.trim();
8357
+ content = content.replace(/\x1B\[[0-9;]*[mGKH]/g, "");
8358
+ content = content.replace(/^>\s*/gm, "").replace(/\n{3,}/g, "\n\n").trim();
8359
+ return content;
8360
+ }
8361
+ /**
8362
+ * Estimate token count
8363
+ */
8364
+ estimateTokens(text) {
8365
+ return Math.ceil(text.length / 4);
8366
+ }
8367
+ /**
8368
+ * Create mock response for testing
8369
+ */
8370
+ createMockResponse(prompt) {
8371
+ return {
8372
+ content: `[Mock Qwen Response]
8373
+
8374
+ This is a mock response from Qwen Code CLI.
8375
+ Prompt length: ${prompt.length} characters.`,
8376
+ model: "qwen-code-cli-mock",
8377
+ tokensUsed: {
8378
+ prompt: this.estimateTokens(prompt),
8379
+ completion: 50,
8380
+ total: this.estimateTokens(prompt) + 50
8381
+ },
8382
+ latencyMs: 10,
8383
+ finishReason: "stop",
8384
+ cached: false
8385
+ };
8386
+ }
8387
+ /**
8388
+ * Get CLI command
8389
+ */
8390
+ getCommand() {
8391
+ return this.config.command;
8392
+ }
8393
+ };
8394
+ }
8395
+ });
8396
+
8397
+ // src/integrations/qwen-code/hybrid-adapter.ts
8398
+ var QwenHybridAdapter;
8399
+ var init_hybrid_adapter4 = __esm({
8400
+ "src/integrations/qwen-code/hybrid-adapter.ts"() {
8401
+ init_esm_shims();
8402
+ init_logger();
8403
+ init_sdk_adapter4();
8404
+ init_cli_wrapper4();
8405
+ QwenHybridAdapter = class {
8406
+ sdkAdapter = null;
8407
+ cliWrapper = null;
8408
+ options;
8409
+ activeMode = null;
8410
+ // Circuit breakers for each mode
8411
+ sdkCircuitBreaker = {
8412
+ failures: 0,
8413
+ lastFailure: 0,
8414
+ isOpen: false
8415
+ };
8416
+ cliCircuitBreaker = {
8417
+ failures: 0,
8418
+ lastFailure: 0,
8419
+ isOpen: false
8420
+ };
8421
+ // Circuit breaker configuration
8422
+ FAILURE_THRESHOLD = 3;
8423
+ RECOVERY_TIMEOUT_MS = 6e4;
8424
+ // 1 minute
8425
+ constructor(options = {}) {
8426
+ this.options = {
8427
+ mode: options.mode || "auto",
8428
+ model: options.model || "qwen-turbo",
8429
+ apiKey: options.apiKey,
8430
+ baseUrl: options.baseUrl,
8431
+ command: options.command || "qwen",
8432
+ timeout: options.timeout
8433
+ };
8434
+ logger.debug("[Qwen Hybrid] Adapter created", {
8435
+ mode: this.options.mode,
8436
+ model: this.options.model
8437
+ });
8438
+ }
8439
+ /**
8440
+ * Get or create SDK adapter
8441
+ */
8442
+ getSdkAdapter() {
8443
+ if (!this.sdkAdapter) {
8444
+ const config = {
8445
+ apiKey: this.options.apiKey,
8446
+ baseUrl: this.options.baseUrl,
8447
+ model: this.options.model,
8448
+ timeout: this.options.timeout
8449
+ };
8450
+ this.sdkAdapter = new QwenSdkAdapter(config);
8451
+ }
8452
+ return this.sdkAdapter;
8453
+ }
8454
+ /**
8455
+ * Get or create CLI wrapper
8456
+ */
8457
+ getCliWrapper() {
8458
+ if (!this.cliWrapper) {
8459
+ const config = {
8460
+ command: this.options.command,
8461
+ timeout: this.options.timeout
8462
+ };
8463
+ this.cliWrapper = new QwenCliWrapper(config);
8464
+ }
8465
+ return this.cliWrapper;
8466
+ }
8467
+ /**
8468
+ * Check if a circuit breaker should allow requests
8469
+ */
8470
+ isCircuitClosed(breaker) {
8471
+ if (!breaker.isOpen) {
8472
+ return true;
8473
+ }
8474
+ if (Date.now() - breaker.lastFailure > this.RECOVERY_TIMEOUT_MS) {
8475
+ breaker.isOpen = false;
8476
+ breaker.failures = 0;
8477
+ return true;
8478
+ }
8479
+ return false;
8480
+ }
8481
+ /**
8482
+ * Record a failure on a circuit breaker
8483
+ */
8484
+ recordFailure(breaker) {
8485
+ breaker.failures++;
8486
+ breaker.lastFailure = Date.now();
8487
+ if (breaker.failures >= this.FAILURE_THRESHOLD) {
8488
+ breaker.isOpen = true;
8489
+ logger.warn("[Qwen Hybrid] Circuit breaker opened", {
8490
+ failures: breaker.failures
8491
+ });
8492
+ }
8493
+ }
8494
+ /**
8495
+ * Record a success on a circuit breaker
8496
+ */
8497
+ recordSuccess(breaker) {
8498
+ breaker.failures = 0;
8499
+ breaker.isOpen = false;
8500
+ }
8501
+ /**
8502
+ * Execute a request using the appropriate mode
8503
+ */
8504
+ async execute(request) {
8505
+ const mode = this.options.mode;
8506
+ if (mode === "sdk") {
8507
+ return this.executeWithSdk(request);
8508
+ }
8509
+ if (mode === "cli") {
8510
+ return this.executeWithCli(request);
8511
+ }
8512
+ return this.executeWithAuto(request);
8513
+ }
8514
+ /**
8515
+ * Execute with SDK only
8516
+ */
8517
+ async executeWithSdk(request) {
8518
+ const adapter = this.getSdkAdapter();
8519
+ if (!await adapter.isAvailable()) {
8520
+ throw new Error("Qwen SDK is not available. Check DASHSCOPE_API_KEY or QWEN_API_KEY.");
8521
+ }
8522
+ this.activeMode = "sdk";
8523
+ return adapter.execute(request);
8524
+ }
8525
+ /**
8526
+ * Execute with CLI only
8527
+ */
8528
+ async executeWithCli(request) {
8529
+ const wrapper = this.getCliWrapper();
8530
+ if (!await wrapper.isAvailable()) {
8531
+ throw new Error("Qwen CLI is not available. Run: npm install -g @qwen-code/qwen-code@latest");
8532
+ }
8533
+ this.activeMode = "cli";
8534
+ return wrapper.execute(request);
8535
+ }
8536
+ /**
8537
+ * Execute with automatic mode selection
8538
+ */
8539
+ async executeWithAuto(request) {
8540
+ if (this.isCircuitClosed(this.sdkCircuitBreaker)) {
8541
+ const adapter = this.getSdkAdapter();
8542
+ try {
8543
+ if (await adapter.isAvailable()) {
8544
+ logger.debug("[Qwen Hybrid] Using SDK mode");
8545
+ this.activeMode = "sdk";
8546
+ const response = await adapter.execute(request);
8547
+ this.recordSuccess(this.sdkCircuitBreaker);
8548
+ return response;
8549
+ }
8550
+ } catch (error) {
8551
+ logger.warn("[Qwen Hybrid] SDK execution failed, trying CLI", {
8552
+ error: error instanceof Error ? error.message : String(error)
8553
+ });
8554
+ this.recordFailure(this.sdkCircuitBreaker);
8555
+ }
8556
+ }
8557
+ if (this.isCircuitClosed(this.cliCircuitBreaker)) {
8558
+ const wrapper = this.getCliWrapper();
8559
+ try {
8560
+ if (await wrapper.isAvailable()) {
8561
+ logger.debug("[Qwen Hybrid] Using CLI mode (fallback)");
8562
+ this.activeMode = "cli";
8563
+ const response = await wrapper.execute(request);
8564
+ this.recordSuccess(this.cliCircuitBreaker);
8565
+ return response;
8566
+ }
8567
+ } catch (error) {
8568
+ logger.error("[Qwen Hybrid] CLI execution also failed", {
8569
+ error: error instanceof Error ? error.message : String(error)
8570
+ });
8571
+ this.recordFailure(this.cliCircuitBreaker);
8572
+ throw error;
8573
+ }
8574
+ }
8575
+ throw new Error(
8576
+ "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."
8577
+ );
8578
+ }
8579
+ /**
8580
+ * Get the currently active execution mode
8581
+ */
8582
+ getActiveMode() {
8583
+ return this.activeMode;
8584
+ }
8585
+ /**
8586
+ * Reset circuit breakers
8587
+ */
8588
+ resetCircuitBreakers() {
8589
+ this.sdkCircuitBreaker = { failures: 0, lastFailure: 0, isOpen: false };
8590
+ this.cliCircuitBreaker = { failures: 0, lastFailure: 0, isOpen: false };
8591
+ logger.debug("[Qwen Hybrid] Circuit breakers reset");
8592
+ }
8593
+ /**
8594
+ * Clean up resources
8595
+ */
8596
+ async destroy() {
8597
+ if (this.sdkAdapter) {
8598
+ await this.sdkAdapter.destroy();
8599
+ this.sdkAdapter = null;
8600
+ }
8601
+ this.cliWrapper = null;
8602
+ this.activeMode = null;
8603
+ logger.debug("[Qwen Hybrid] Adapter destroyed");
8604
+ }
8605
+ };
8606
+ }
8607
+ });
8608
+
8609
+ // src/integrations/qwen-code/index.ts
8610
+ var init_qwen_code = __esm({
8611
+ "src/integrations/qwen-code/index.ts"() {
8612
+ init_esm_shims();
8613
+ init_hybrid_adapter4();
8614
+ init_sdk_adapter4();
8615
+ init_cli_wrapper4();
8616
+ init_types4();
8617
+ }
8618
+ });
8619
+
8620
+ // src/providers/qwen-provider.ts
8621
+ var qwen_provider_exports = {};
8622
+ __export(qwen_provider_exports, {
8623
+ QwenProvider: () => QwenProvider,
8624
+ default: () => QwenProvider
8625
+ });
8626
+ var SUPPORTED_MODELS, QwenProvider;
8627
+ var init_qwen_provider = __esm({
8628
+ "src/providers/qwen-provider.ts"() {
8629
+ init_esm_shims();
8630
+ init_base_provider();
8631
+ init_logger();
8632
+ init_qwen_code();
8633
+ SUPPORTED_MODELS = [
8634
+ "qwen3-coder-480b-a35b-instruct",
8635
+ "qwen3-coder-30b-a3b-instruct",
8636
+ "qwen2.5-coder-32b-instruct",
8637
+ "qwen-max",
8638
+ "qwen-plus",
8639
+ "qwen-turbo"
8640
+ ];
8641
+ QwenProvider = class extends BaseProvider {
8642
+ /** Selected model */
8643
+ model;
8644
+ /** SDK adapter for direct execution */
8645
+ sdkAdapter = null;
8646
+ /** Hybrid adapter for 'auto' mode */
8647
+ hybridAdapter = null;
8648
+ /** Provider configuration */
8649
+ qwenConfig;
8650
+ /** Supported models */
8651
+ static SUPPORTED_MODELS = SUPPORTED_MODELS;
8652
+ constructor(config) {
8653
+ super({
8654
+ ...config,
8655
+ command: "qwen"
8656
+ });
8657
+ this.qwenConfig = config;
8658
+ const requestedModel = config.model || QWEN_DEFAULT_MODEL;
8659
+ if (!SUPPORTED_MODELS.includes(requestedModel)) {
8660
+ logger.warn(`[Qwen] Unknown model: ${requestedModel}. Using ${QWEN_DEFAULT_MODEL}.`);
8661
+ this.model = QWEN_DEFAULT_MODEL;
8662
+ } else {
8663
+ this.model = requestedModel;
8664
+ }
8665
+ logger.debug("[Qwen Provider] Initialized", {
8666
+ model: this.model,
8667
+ mode: config.mode || "sdk"
8668
+ });
8669
+ }
8670
+ /**
8671
+ * Get the normalized model name
8672
+ */
8673
+ getNormalizedModel() {
8674
+ return normalizeQwenModel(this.model);
8675
+ }
8676
+ /**
8677
+ * Get or create SDK adapter
8678
+ */
8679
+ getSdkAdapter() {
8680
+ if (!this.sdkAdapter) {
8681
+ this.sdkAdapter = new QwenSdkAdapter({
8682
+ model: this.model,
8683
+ apiKey: this.qwenConfig.apiKey,
8684
+ baseUrl: this.qwenConfig.baseUrl,
8685
+ timeout: this.qwenConfig.timeout
8686
+ });
8687
+ }
8688
+ return this.sdkAdapter;
8689
+ }
8690
+ /**
8691
+ * Get or create hybrid adapter
8692
+ */
8693
+ getHybridAdapter() {
8694
+ if (!this.hybridAdapter) {
8695
+ const options = {
8696
+ mode: this.qwenConfig.mode || "auto",
8697
+ model: this.model,
8698
+ apiKey: this.qwenConfig.apiKey,
8699
+ baseUrl: this.qwenConfig.baseUrl,
8700
+ command: "qwen",
8701
+ timeout: this.qwenConfig.timeout
8702
+ };
8703
+ this.hybridAdapter = new QwenHybridAdapter(options);
8704
+ }
8705
+ return this.hybridAdapter;
8706
+ }
8707
+ /**
8708
+ * Execute a task using Qwen
8709
+ *
8710
+ * Execution flow:
8711
+ * 1. Mock mode → return mock response
8712
+ * 2. mode='sdk' (default) → use SDK adapter
8713
+ * 3. mode='auto' → use hybrid adapter (SDK with CLI fallback)
8714
+ * 4. mode='cli' → use CLI via BaseProvider
8715
+ */
8716
+ async execute(request) {
8717
+ if (process.env.AX_MOCK_PROVIDERS === "true") {
8718
+ return this.createMockResponse(request.prompt);
8719
+ }
8720
+ const effectiveMode = this.qwenConfig.mode || "sdk";
8721
+ if (effectiveMode === "cli") {
8722
+ logger.debug("[Qwen Provider] Executing via CLI", {
8723
+ model: this.model
8724
+ });
8725
+ return super.execute(request);
8726
+ }
8727
+ if (effectiveMode === "auto") {
8728
+ logger.debug("[Qwen Provider] Executing via hybrid adapter", {
8729
+ promptLength: request.prompt.length,
8730
+ model: this.model
8731
+ });
8732
+ const adapter2 = this.getHybridAdapter();
8733
+ return adapter2.execute(request);
8734
+ }
8735
+ logger.debug("[Qwen Provider] Executing via SDK adapter", {
8736
+ promptLength: request.prompt.length,
8737
+ model: this.model
8738
+ });
8739
+ const adapter = this.getSdkAdapter();
8740
+ if (!await adapter.isAvailable()) {
8741
+ throw new Error(
8742
+ 'Qwen SDK is not available. Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable, or use mode: "cli" to use Qwen Code CLI.'
8743
+ );
8744
+ }
8745
+ return adapter.execute(request);
8746
+ }
8747
+ /**
8748
+ * Get CLI command
8749
+ */
8750
+ getCLICommand() {
8751
+ const activeMode = this.hybridAdapter?.getActiveMode();
8752
+ if (activeMode === "sdk") {
8753
+ return "qwen-sdk";
8754
+ }
8755
+ return "qwen";
8756
+ }
8757
+ /**
8758
+ * Get CLI arguments for Qwen Code CLI
8759
+ *
8760
+ * Note: Qwen Code CLI is interactive by default.
8761
+ * We pass the prompt via stdin instead of command-line args.
8762
+ */
8763
+ getCLIArgs() {
8764
+ return [];
8765
+ }
8766
+ /**
8767
+ * Create mock response for testing
8768
+ */
8769
+ createMockResponse(prompt) {
8770
+ return {
8771
+ content: this.getMockResponse(),
8772
+ model: this.getNormalizedModel(),
8773
+ tokensUsed: {
8774
+ prompt: this.estimateTokens(prompt),
8775
+ completion: 50,
8776
+ total: this.estimateTokens(prompt) + 50
8777
+ },
8778
+ latencyMs: 10,
8779
+ finishReason: "stop",
8780
+ cached: false
8781
+ };
8782
+ }
8783
+ /**
8784
+ * Estimate token count
8785
+ */
8786
+ estimateTokens(text) {
8787
+ return Math.ceil(text.length / 4);
8788
+ }
8789
+ /**
8790
+ * Get mock response for testing
8791
+ */
8792
+ getMockResponse() {
8793
+ return `[Mock Qwen Response]
8794
+
8795
+ This is a mock response from the Qwen provider (${this.getNormalizedModel()}).
8796
+ In production, this would be a response from ${this.qwenConfig.mode === "sdk" ? "Qwen SDK" : "Qwen Code CLI"}.
8797
+
8798
+ Model: ${this.getNormalizedModel()}
8799
+ Provider: Qwen (Alibaba Cloud)
8800
+ Mode: ${this.qwenConfig.mode || "sdk"}`;
8801
+ }
8802
+ /**
8803
+ * Get provider capabilities
8804
+ */
8805
+ get capabilities() {
8806
+ const model = this.getNormalizedModel();
8807
+ const hasVision = isVisionModel(model);
8808
+ const maxContextTokens = getModelContextWindow(model);
8809
+ const activeMode = this.hybridAdapter?.getActiveMode();
8810
+ const integrationMode = activeMode === "sdk" ? "sdk" : "cli";
8811
+ return {
8812
+ ...super.capabilities,
8813
+ supportsStreaming: true,
8814
+ supportsVision: hasVision,
8815
+ maxContextTokens,
8816
+ supportedModels: SUPPORTED_MODELS,
8817
+ integrationMode
8818
+ };
8819
+ }
8820
+ /**
8821
+ * Get the active execution mode
8822
+ */
8823
+ getActiveMode() {
8824
+ return this.hybridAdapter?.getActiveMode() || null;
8825
+ }
8826
+ /**
8827
+ * Reset circuit breakers
8828
+ */
8829
+ resetCircuitBreakers() {
8830
+ this.hybridAdapter?.resetCircuitBreakers();
8831
+ }
8832
+ /**
8833
+ * Clean up resources
8834
+ */
8835
+ async destroy() {
8836
+ if (this.sdkAdapter) {
8837
+ await this.sdkAdapter.destroy();
8838
+ this.sdkAdapter = null;
8839
+ }
8840
+ if (this.hybridAdapter) {
8841
+ await this.hybridAdapter.destroy();
8842
+ this.hybridAdapter = null;
8843
+ }
8844
+ }
8845
+ /**
8846
+ * Get the list of supported models
8847
+ */
8848
+ static getSupportedModels() {
8849
+ return [...SUPPORTED_MODELS];
8850
+ }
8851
+ };
8852
+ }
8853
+ });
8854
+
7937
8855
  // src/cli/index.ts
7938
8856
  init_esm_shims();
7939
8857
  init_logger();
@@ -8834,12 +9752,16 @@ init_logger();
8834
9752
 
8835
9753
  // src/shared/helpers/deep-merge.ts
8836
9754
  init_esm_shims();
9755
+ function isPlainObject(value) {
9756
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
9757
+ }
8837
9758
  function deepMerge(defaults, user) {
8838
9759
  if (user === null || user === void 0) {
8839
- return defaults;
9760
+ return { ...defaults };
8840
9761
  }
8841
- const result = { ...defaults };
8842
- for (const key in user) {
9762
+ const result = Object.assign({}, defaults);
9763
+ const userKeys = Object.keys(user);
9764
+ for (const key of userKeys) {
8843
9765
  const userValue = user[key];
8844
9766
  if (userValue === null) {
8845
9767
  result[key] = void 0;
@@ -8849,8 +9771,11 @@ function deepMerge(defaults, user) {
8849
9771
  continue;
8850
9772
  }
8851
9773
  const defaultValue = defaults[key];
8852
- if (typeof userValue === "object" && typeof defaultValue === "object" && !Array.isArray(userValue) && !Array.isArray(defaultValue) && userValue !== null && defaultValue !== null) {
8853
- result[key] = deepMerge(defaultValue, userValue);
9774
+ if (isPlainObject(userValue) && isPlainObject(defaultValue)) {
9775
+ result[key] = deepMerge(
9776
+ defaultValue,
9777
+ userValue
9778
+ );
8854
9779
  } else {
8855
9780
  result[key] = userValue;
8856
9781
  }
@@ -9492,7 +10417,7 @@ var PRECOMPILED_CONFIG = {
9492
10417
  "enableFreeTierPrioritization": true,
9493
10418
  "enableWorkloadAwareRouting": true
9494
10419
  },
9495
- "version": "12.6.1"
10420
+ "version": "12.6.3"
9496
10421
  };
9497
10422
 
9498
10423
  // src/core/config/schemas.ts
@@ -13263,14 +14188,17 @@ init_validation_limits();
13263
14188
  var execAsync2 = promisify(exec);
13264
14189
  var ProviderDetector = class _ProviderDetector {
13265
14190
  // v12.0.0: Removed ax-cli, added glm/grok (SDK-first providers)
14191
+ // v12.7.0: Added qwen (SDK-first with CLI fallback)
13266
14192
  static PROVIDER_COMMANDS = {
13267
14193
  "claude-code": "claude",
13268
14194
  "gemini-cli": "gemini",
13269
14195
  "codex": "codex",
13270
14196
  "glm": "glm",
13271
14197
  // v12.0.0: Native GLM provider (SDK-first)
13272
- "grok": "grok"
14198
+ "grok": "grok",
13273
14199
  // v12.0.0: Native Grok provider (SDK-first)
14200
+ "qwen": "qwen"
14201
+ // v12.7.0: Qwen Code provider (SDK-first with CLI fallback)
13274
14202
  };
13275
14203
  /**
13276
14204
  * Detect all supported AI provider CLIs
@@ -13295,16 +14223,22 @@ var ProviderDetector = class _ProviderDetector {
13295
14223
  const results = await Promise.all([
13296
14224
  this.isCommandAvailable("claude-code"),
13297
14225
  this.isCommandAvailable("gemini-cli"),
13298
- this.isCommandAvailable("codex")
14226
+ this.isCommandAvailable("codex"),
14227
+ this.isCommandAvailable("qwen")
13299
14228
  ]);
14229
+ const qwenApiKeySet = !!(process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY);
14230
+ const qwenCliAvailable = results[3];
14231
+ const qwenAvailable = qwenApiKeySet || qwenCliAvailable;
13300
14232
  const detected = {
13301
14233
  "claude-code": results[0],
13302
14234
  "gemini-cli": results[1],
13303
14235
  "codex": results[2],
13304
14236
  "glm": true,
13305
14237
  // SDK-first: always available via SDK
13306
- "grok": true
14238
+ "grok": true,
13307
14239
  // SDK-first: always available via SDK
14240
+ "qwen": qwenAvailable
14241
+ // v12.7.0: SDK-first with CLI fallback
13308
14242
  };
13309
14243
  const foundProviders = Object.entries(detected).filter(([_, isInstalled]) => isInstalled).map(([provider]) => provider);
13310
14244
  logger.info("Provider detection complete", {
@@ -13411,6 +14345,9 @@ var ProviderDetector = class _ProviderDetector {
13411
14345
  if (provider === "grok") {
13412
14346
  return this.getGrokVersion();
13413
14347
  }
14348
+ if (provider === "qwen") {
14349
+ return this.getQwenVersion();
14350
+ }
13414
14351
  const command = _ProviderDetector.PROVIDER_COMMANDS[provider];
13415
14352
  try {
13416
14353
  const { stdout } = await execAsync2(`${command} --version`, {
@@ -13451,6 +14388,19 @@ var ProviderDetector = class _ProviderDetector {
13451
14388
  }
13452
14389
  return "SDK v1 (grok-3, API key not set)";
13453
14390
  }
14391
+ /**
14392
+ * Get Qwen provider version info (SDK-first with CLI fallback)
14393
+ *
14394
+ * v12.7.0: Qwen is an SDK-first provider using OpenAI-compatible API (DashScope).
14395
+ * Returns SDK info with API key status or CLI availability.
14396
+ */
14397
+ getQwenVersion() {
14398
+ const apiKey = process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
14399
+ if (apiKey) {
14400
+ return "SDK v1 (qwen-turbo, API ready)";
14401
+ }
14402
+ return "SDK v1 (qwen-turbo, CLI fallback)";
14403
+ }
13454
14404
  /**
13455
14405
  * Get list of detected provider names
13456
14406
  *
@@ -13484,7 +14434,9 @@ var ProviderDetector = class _ProviderDetector {
13484
14434
  "gemini-cli": "Gemini CLI",
13485
14435
  "codex": "Codex CLI",
13486
14436
  "glm": "GLM (Zhipu AI)",
13487
- "grok": "Grok (xAI)"
14437
+ "grok": "Grok (xAI)",
14438
+ "qwen": "Qwen (Alibaba Cloud)"
14439
+ // v12.7.0
13488
14440
  };
13489
14441
  return nameMap[provider] || provider;
13490
14442
  }
@@ -13577,8 +14529,9 @@ var setupCommand = {
13577
14529
  console.log(chalk5.gray(" - Claude Code"));
13578
14530
  console.log(chalk5.gray(" - Gemini CLI"));
13579
14531
  console.log(chalk5.gray(" - Codex CLI"));
13580
- console.log(chalk5.gray(" - GLM (SDK-first, requires ZAI_API_KEY)"));
14532
+ console.log(chalk5.gray(" - GLM (SDK-first, requires GLM_API_KEY)"));
13581
14533
  console.log(chalk5.gray(" - Grok (SDK-first, requires XAI_API_KEY)"));
14534
+ console.log(chalk5.gray(" - Qwen (SDK-first, requires DASHSCOPE_API_KEY or qwen CLI)"));
13582
14535
  console.log("");
13583
14536
  console.log(chalk5.cyan(' \u{1F4A1} After installing, run "ax setup" again to configure.\n'));
13584
14537
  if (process.stdout.isTTY && process.stdin.isTTY) {
@@ -13655,14 +14608,14 @@ var setupCommand = {
13655
14608
  console.log(chalk5.cyan("\u{1F50C} Setting up Gemini CLI integration..."));
13656
14609
  const geminiDir = join(projectDir, ".gemini");
13657
14610
  const geminiDirExistedBefore = await checkExists2(geminiDir);
13658
- geminiMcpStatus = await setupGeminiIntegration(projectDir, packageRoot);
14611
+ geminiMcpStatus = await setupGeminiIntegration(projectDir, packageRoot, argv.force);
13659
14612
  if (!geminiDirExistedBefore) {
13660
14613
  createdResources.push(geminiDir);
13661
14614
  }
13662
14615
  if (geminiMcpStatus === "configured") {
13663
- console.log(chalk5.green(" \u2713 Gemini CLI MCP integration configured"));
14616
+ console.log(chalk5.green(" \u2713 Gemini CLI MCP integration configured (gemini mcp add)"));
13664
14617
  } else if (geminiMcpStatus === "skipped") {
13665
- console.log(chalk5.yellow(" \u26A0 Gemini CLI MCP skipped (MCP server not found)"));
14618
+ console.log(chalk5.yellow(" \u26A0 Gemini CLI not available, skipped MCP setup"));
13666
14619
  console.log(chalk5.gray(" CLI integration still works via subprocess"));
13667
14620
  } else {
13668
14621
  console.log(chalk5.yellow(" \u26A0 Gemini CLI MCP configuration failed"));
@@ -13684,34 +14637,26 @@ var setupCommand = {
13684
14637
  let codexMcpStatus = "skipped";
13685
14638
  if (providers["codex"]) {
13686
14639
  console.log(chalk5.cyan("\u{1F50C} Setting up Codex CLI MCP integration..."));
13687
- codexMcpStatus = await setupCodexGlobalMCPConfig();
14640
+ codexMcpStatus = await setupCodexGlobalMCPConfig(argv.force);
13688
14641
  if (codexMcpStatus === "configured") {
13689
- console.log(chalk5.green(" \u2713 Codex CLI MCP integration configured"));
14642
+ console.log(chalk5.green(" \u2713 Codex CLI MCP integration configured (codex mcp add)"));
13690
14643
  } else if (codexMcpStatus === "skipped") {
13691
- console.log(chalk5.yellow(" \u26A0 Codex CLI MCP skipped"));
14644
+ console.log(chalk5.yellow(" \u26A0 Codex CLI not available, skipped MCP setup"));
13692
14645
  } else {
13693
14646
  console.log(chalk5.yellow(" \u26A0 Codex CLI MCP configuration failed"));
13694
14647
  console.log(chalk5.gray(" CLI integration still works via subprocess"));
13695
14648
  }
13696
14649
  }
13697
- let glmMcpStatus = "skipped";
13698
- if (providers["glm"]) {
13699
- console.log(chalk5.cyan("\u{1F50C} Setting up GLM (ax-glm) MCP integration..."));
13700
- glmMcpStatus = await setupGlmMCPConfig(projectDir);
13701
- if (glmMcpStatus === "configured") {
13702
- console.log(chalk5.green(" \u2713 GLM MCP integration configured (.ax-glm/.mcp.json)"));
14650
+ let qwenMcpStatus = "skipped";
14651
+ if (providers["qwen"]) {
14652
+ console.log(chalk5.cyan("\u{1F50C} Setting up Qwen MCP integration..."));
14653
+ qwenMcpStatus = await setupQwenMCPConfig(projectDir, argv.force);
14654
+ if (qwenMcpStatus === "configured") {
14655
+ console.log(chalk5.green(" \u2713 Qwen MCP integration configured (qwen mcp add)"));
14656
+ } else if (qwenMcpStatus === "skipped") {
14657
+ console.log(chalk5.yellow(" \u26A0 Qwen CLI not available, skipped MCP setup"));
13703
14658
  } else {
13704
- console.log(chalk5.yellow(" \u26A0 GLM MCP configuration failed"));
13705
- }
13706
- }
13707
- let grokMcpStatus = "skipped";
13708
- if (providers["grok"]) {
13709
- console.log(chalk5.cyan("\u{1F50C} Setting up Grok (ax-grok) MCP integration..."));
13710
- grokMcpStatus = await setupGrokMCPConfig(projectDir);
13711
- if (grokMcpStatus === "configured") {
13712
- console.log(chalk5.green(" \u2713 Grok MCP integration configured (.ax-grok/.mcp.json)"));
13713
- } else {
13714
- console.log(chalk5.yellow(" \u26A0 Grok MCP configuration failed"));
14659
+ console.log(chalk5.yellow(" \u26A0 Qwen MCP configuration failed"));
13715
14660
  }
13716
14661
  }
13717
14662
  console.log(chalk5.cyan("\u{1F4DD} Updating .gitignore..."));
@@ -13742,9 +14687,11 @@ var setupCommand = {
13742
14687
  console.log(chalk5.gray(" This is fine - MCP discovery will work without manifests"));
13743
14688
  }
13744
14689
  }
13745
- console.log(chalk5.cyan("\u{1F50C} Creating MCP server configuration..."));
13746
- await createMcpConfig(projectDir);
13747
- console.log(chalk5.green(" \u2713 .mcp.json created for MCP discovery"));
14690
+ if (providers["claude-code"]) {
14691
+ console.log(chalk5.cyan("\u{1F50C} Setting up Claude Code MCP integration..."));
14692
+ await createMcpConfig(projectDir, argv.force);
14693
+ console.log(chalk5.green(" \u2713 Claude Code MCP integration configured (claude mcp add)"));
14694
+ }
13748
14695
  console.log(chalk5.green.bold("\n\u2705 AutomatosX set up successfully!\n"));
13749
14696
  if (foundProviders.length > 0) {
13750
14697
  console.log(chalk5.cyan(`Configured for: ${foundProviders.join(", ")}
@@ -13753,14 +14700,15 @@ var setupCommand = {
13753
14700
  console.log(chalk5.yellow("\u26A0\uFE0F No AI providers configured\n"));
13754
14701
  }
13755
14702
  console.log(chalk5.gray("Next steps:"));
13756
- console.log(chalk5.gray(" 1. Review ax.config.json"));
13757
- console.log(chalk5.gray(" 2. List agents: automatosx list agents"));
13758
- console.log(chalk5.gray(' 3. Run an agent: automatosx run backend "Hello!"\n'));
13759
- console.log(chalk5.cyan("MCP Integration (v13.0.0):"));
13760
- console.log(chalk5.gray(" \u2022 .mcp.json created for automatic MCP server discovery"));
13761
- console.log(chalk5.gray(" \u2022 Claude Code/Gemini CLI will auto-connect to AutomatosX"));
14703
+ console.log(chalk5.gray(' 1. Run "ax init" to create project context files (AX.md, CUSTOM.md)'));
14704
+ console.log(chalk5.gray(" 2. Review ax.config.json"));
14705
+ console.log(chalk5.gray(" 3. List agents: automatosx list agents"));
14706
+ console.log(chalk5.gray(' 4. Run an agent: automatosx run backend "Hello!"\n'));
14707
+ console.log(chalk5.cyan("MCP Integration (v12.8.0):"));
14708
+ console.log(chalk5.gray(" \u2022 Native CLI commands used: claude/gemini/codex/qwen mcp add"));
14709
+ console.log(chalk5.gray(" \u2022 View configured servers: <cli> mcp list"));
13762
14710
  console.log(chalk5.gray(" \u2022 Use get_capabilities tool to discover agents dynamically"));
13763
- console.log(chalk5.gray(" \u2022 No manual registration required\n"));
14711
+ console.log(chalk5.gray(" \u2022 GLM/Grok are SDK-only (no MCP CLI setup needed)\n"));
13764
14712
  if (claudeCodeSetupSucceeded) {
13765
14713
  console.log(chalk5.yellow("Legacy Claude Code Manifests (deprecated):"));
13766
14714
  console.log(chalk5.gray(" \u2022 Slash commands: /agent-<name> (will be removed in v14.0.0)"));
@@ -13810,7 +14758,7 @@ var setupCommand = {
13810
14758
  console.log(chalk5.gray(' \u2022 Example: "Use ax agent backend to create a REST API"'));
13811
14759
  console.log(chalk5.gray(" \u2022 No special commands needed - just ask naturally!\n"));
13812
14760
  }
13813
- if (providers["glm"] || providers["grok"]) {
14761
+ if (providers["glm"] || providers["grok"] || providers["qwen"]) {
13814
14762
  console.log(chalk5.cyan("SDK-First Providers (MCP Client Mode):"));
13815
14763
  if (providers["glm"]) {
13816
14764
  console.log(chalk5.gray(" \u2022 GLM (Zhipu AI) - API key: GLM_API_KEY"));
@@ -13820,8 +14768,12 @@ var setupCommand = {
13820
14768
  console.log(chalk5.gray(" \u2022 Grok (xAI) - API key: XAI_API_KEY"));
13821
14769
  console.log(chalk5.gray(" MCP: AxGrokWithMcp class connects to AutomatosX MCP server"));
13822
14770
  }
13823
- console.log(chalk5.gray(' \u2022 CLI: ax run <agent> "your task" --engine glm|grok'));
13824
- console.log(chalk5.gray(" \u2022 SDK: Import AxGlmWithMcp / AxGrokWithMcp for direct MCP integration\n"));
14771
+ if (providers["qwen"]) {
14772
+ console.log(chalk5.gray(" \u2022 Qwen (Alibaba Cloud) - API key: DASHSCOPE_API_KEY or QWEN_API_KEY"));
14773
+ console.log(chalk5.gray(" Or install Qwen Code CLI: npm install -g @qwen-code/qwen-code"));
14774
+ }
14775
+ console.log(chalk5.gray(' \u2022 CLI: ax run <agent> "your task" --engine glm|grok|qwen'));
14776
+ console.log(chalk5.gray(" \u2022 SDK: Import provider adapters for direct MCP integration\n"));
13825
14777
  }
13826
14778
  if (providers["codex"]) {
13827
14779
  console.log(chalk5.cyan("Codex CLI Integration:"));
@@ -14343,9 +15295,9 @@ async function initializeGitRepository(projectDir) {
14343
15295
  logger.info("Git repository already exists, skipping initialization");
14344
15296
  return true;
14345
15297
  }
14346
- const { spawn: spawn12 } = await import('child_process');
15298
+ const { spawn: spawn13 } = await import('child_process');
14347
15299
  await new Promise((resolve13, reject) => {
14348
- const child = spawn12("git", ["init"], {
15300
+ const child = spawn13("git", ["init"], {
14349
15301
  cwd: projectDir,
14350
15302
  stdio: "pipe",
14351
15303
  shell: false
@@ -14426,143 +15378,71 @@ async function updateGitignore(projectDir) {
14426
15378
  logger.warn("Failed to update .gitignore", { error: error.message });
14427
15379
  }
14428
15380
  }
14429
- async function setupGeminiIntegration(_projectDir, _packageRoot) {
14430
- const mcpStatus = await setupGeminiGlobalMCPConfig();
15381
+ async function setupGeminiIntegration(projectDir, _packageRoot, force = false) {
15382
+ const mcpStatus = await setupGeminiMCPViaCLI(projectDir, force);
14431
15383
  return mcpStatus;
14432
15384
  }
14433
- async function setupGeminiGlobalMCPConfig() {
14434
- const homeDir = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
14435
- if (!homeDir) {
14436
- logger.warn("Could not determine home directory for Gemini CLI MCP configuration");
14437
- return "skipped";
14438
- }
14439
- const settingsPath = join(homeDir, ".gemini", "settings.json");
14440
- const geminiDir = join(homeDir, ".gemini");
15385
+ async function setupGeminiMCPViaCLI(projectDir, force = false) {
15386
+ const { exec: exec9 } = await import('child_process');
15387
+ const { promisify: promisify10 } = await import('util');
15388
+ const execAsync9 = promisify10(exec9);
14441
15389
  try {
14442
- await mkdir(geminiDir, { recursive: true });
14443
- let settings = {};
14444
- if (await checkExists2(settingsPath)) {
14445
- const existingContent = await readFile(settingsPath, "utf-8");
14446
- try {
14447
- settings = JSON.parse(existingContent);
14448
- } catch (error) {
14449
- logger.warn("Failed to parse existing Gemini settings, will merge carefully", {
14450
- error: error.message
15390
+ const { stdout: listOutput } = await execAsync9("gemini mcp list", { timeout: 1e4 });
15391
+ if (listOutput.includes("automatosx")) {
15392
+ if (force) {
15393
+ logger.info("Force mode: removing existing Gemini MCP server");
15394
+ await execAsync9("gemini mcp remove automatosx", { timeout: 1e4 }).catch(() => {
14451
15395
  });
15396
+ } else {
15397
+ logger.info("Gemini CLI MCP server already configured");
15398
+ return "configured";
14452
15399
  }
14453
15400
  }
14454
- let mcpServers = settings["mcpServers"];
14455
- if (!mcpServers || typeof mcpServers !== "object") {
14456
- mcpServers = {};
14457
- }
14458
- mcpServers["automatosx"] = {
14459
- command: "automatosx",
14460
- args: ["mcp", "server"]
14461
- };
14462
- settings["mcpServers"] = mcpServers;
14463
- await writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
14464
- logger.info("Configured Gemini CLI MCP in global settings", {
14465
- path: settingsPath
14466
- });
15401
+ const addCommand2 = `gemini mcp add automatosx automatosx mcp server -s project -e "AUTOMATOSX_PROJECT_DIR=${projectDir}"`;
15402
+ await execAsync9(addCommand2, { timeout: 3e4 });
15403
+ logger.info("Configured Gemini CLI MCP via gemini mcp add");
14467
15404
  return "configured";
14468
15405
  } catch (error) {
15406
+ const errorMessage = error.message;
15407
+ if (errorMessage.includes("command not found") || errorMessage.includes("not recognized")) {
15408
+ logger.debug("Gemini CLI not available, skipping MCP setup");
15409
+ return "skipped";
15410
+ }
14469
15411
  logger.warn("Failed to setup Gemini CLI MCP configuration", {
14470
- error: error.message,
14471
- path: settingsPath
15412
+ error: errorMessage
14472
15413
  });
14473
15414
  return "failed";
14474
15415
  }
14475
15416
  }
14476
- async function setupCodexGlobalMCPConfig() {
14477
- const homeDir = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
14478
- if (!homeDir) {
14479
- logger.warn("Could not determine home directory for Codex CLI MCP configuration");
14480
- return "skipped";
14481
- }
14482
- const codexDir = join(homeDir, ".codex");
14483
- const configPath = join(codexDir, "config.toml");
15417
+ async function setupCodexGlobalMCPConfig(force = false) {
15418
+ const { exec: exec9 } = await import('child_process');
15419
+ const { promisify: promisify10 } = await import('util');
15420
+ const execAsync9 = promisify10(exec9);
14484
15421
  try {
14485
- await mkdir(codexDir, { recursive: true });
14486
- let existingContent = "";
14487
- if (await checkExists2(configPath)) {
14488
- existingContent = await readFile(configPath, "utf-8");
14489
- }
14490
- if (existingContent.includes("[mcp_servers.automatosx]")) {
14491
- logger.info("Codex CLI MCP already configured for automatosx");
14492
- return "configured";
14493
- }
14494
- const mcpConfig = `
14495
- # AutomatosX MCP Server - Added by ax setup v12.2.0
14496
- # Increased timeouts for lazy initialization (15-20s on first tool call)
14497
- [mcp_servers.automatosx]
14498
- command = "automatosx"
14499
- args = ["mcp", "server"]
14500
- startup_timeout_sec = 60
14501
- tool_timeout_sec = 120
14502
- `;
14503
- await writeFile(configPath, existingContent + mcpConfig, "utf-8");
14504
- logger.info("Configured Codex CLI MCP in global config", {
14505
- path: configPath
14506
- });
14507
- return "configured";
14508
- } catch (error) {
14509
- logger.warn("Failed to setup Codex CLI MCP configuration", {
14510
- error: error.message,
14511
- path: configPath
14512
- });
14513
- return "failed";
14514
- }
14515
- }
14516
- async function setupGlmMCPConfig(projectDir) {
14517
- const configDir = join(projectDir, ".ax-glm");
14518
- const configPath = join(configDir, ".mcp.json");
14519
- try {
14520
- await mkdir(configDir, { recursive: true });
14521
- const mcpConfig = {
14522
- mcpServers: {
14523
- automatosx: {
14524
- command: "automatosx",
14525
- args: ["mcp", "server"],
14526
- env: {
14527
- AUTOMATOSX_PROJECT_DIR: projectDir
14528
- }
14529
- }
14530
- }
14531
- };
14532
- await writeFile(configPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
14533
- logger.info("Configured GLM MCP integration", { path: configPath });
14534
- return "configured";
14535
- } catch (error) {
14536
- logger.warn("Failed to setup GLM MCP configuration", {
14537
- error: error.message,
14538
- path: configPath
14539
- });
14540
- return "failed";
14541
- }
14542
- }
14543
- async function setupGrokMCPConfig(projectDir) {
14544
- const configDir = join(projectDir, ".ax-grok");
14545
- const configPath = join(configDir, ".mcp.json");
14546
- try {
14547
- await mkdir(configDir, { recursive: true });
14548
- const mcpConfig = {
14549
- mcpServers: {
14550
- automatosx: {
14551
- command: "automatosx",
14552
- args: ["mcp", "server"],
14553
- env: {
14554
- AUTOMATOSX_PROJECT_DIR: projectDir
14555
- }
14556
- }
15422
+ const { stdout: listOutput } = await execAsync9("codex mcp list", { timeout: 1e4 });
15423
+ if (listOutput.includes("automatosx")) {
15424
+ if (force) {
15425
+ logger.info("Force mode: removing existing Codex MCP server");
15426
+ await execAsync9("codex mcp remove automatosx", { timeout: 1e4 }).catch(() => {
15427
+ });
15428
+ } else {
15429
+ logger.info("Codex CLI MCP server already configured");
15430
+ return "configured";
14557
15431
  }
14558
- };
14559
- await writeFile(configPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
14560
- logger.info("Configured Grok MCP integration", { path: configPath });
15432
+ }
15433
+ const cwd = process.cwd();
15434
+ const addCommand2 = `codex mcp add automatosx --env "AUTOMATOSX_PROJECT_DIR=${cwd}" -- automatosx mcp server`;
15435
+ await execAsync9(addCommand2, { timeout: 3e4 });
15436
+ logger.info("Configured Codex CLI MCP via codex mcp add");
14561
15437
  return "configured";
14562
15438
  } catch (error) {
14563
- logger.warn("Failed to setup Grok MCP configuration", {
14564
- error: error.message,
14565
- path: configPath
15439
+ const errorMessage = error.message;
15440
+ if (errorMessage.includes("command not found") || errorMessage.includes("not recognized")) {
15441
+ logger.debug("Codex CLI not available, skipping MCP setup");
15442
+ return "skipped";
15443
+ }
15444
+ logger.warn("Failed to setup Codex CLI MCP configuration", {
15445
+ error: errorMessage
14566
15446
  });
14567
15447
  return "failed";
14568
15448
  }
@@ -14611,41 +15491,66 @@ Created by AutomatosX for organized scratch work.
14611
15491
  });
14612
15492
  }
14613
15493
  }
14614
- async function createMcpConfig(projectDir) {
14615
- const mcpConfigPath = join(projectDir, ".mcp.json");
14616
- const mcpConfig = {
14617
- mcpServers: {
14618
- automatosx: {
14619
- command: "automatosx",
14620
- args: ["mcp", "server"],
14621
- env: {
14622
- AUTOMATOSX_PROJECT_DIR: projectDir
14623
- }
15494
+ async function createMcpConfig(projectDir, force = false) {
15495
+ const { exec: exec9 } = await import('child_process');
15496
+ const { promisify: promisify10 } = await import('util');
15497
+ const execAsync9 = promisify10(exec9);
15498
+ try {
15499
+ const { stdout: listOutput } = await execAsync9("claude mcp list", { timeout: 1e4 });
15500
+ if (listOutput.includes("automatosx")) {
15501
+ if (force) {
15502
+ logger.info("Force mode: removing existing Claude Code MCP server");
15503
+ await execAsync9("claude mcp remove automatosx", { timeout: 1e4 }).catch(() => {
15504
+ });
15505
+ } else {
15506
+ logger.info("Claude Code MCP server already configured");
15507
+ return;
14624
15508
  }
14625
15509
  }
14626
- };
15510
+ const addCommand2 = `claude mcp add automatosx -s local -e "AUTOMATOSX_PROJECT_DIR=${projectDir}" -- automatosx mcp server`;
15511
+ await execAsync9(addCommand2, { timeout: 3e4 });
15512
+ logger.info("Configured Claude Code MCP via claude mcp add");
15513
+ } catch (error) {
15514
+ const errorMessage = error.message;
15515
+ if (errorMessage.includes("command not found") || errorMessage.includes("not recognized")) {
15516
+ logger.debug("Claude Code not available, skipping MCP setup");
15517
+ return;
15518
+ }
15519
+ logger.warn("Failed to setup Claude Code MCP configuration", {
15520
+ error: errorMessage
15521
+ });
15522
+ }
15523
+ }
15524
+ async function setupQwenMCPConfig(projectDir, force = false) {
15525
+ const { exec: exec9 } = await import('child_process');
15526
+ const { promisify: promisify10 } = await import('util');
15527
+ const execAsync9 = promisify10(exec9);
14627
15528
  try {
14628
- if (await checkExists2(mcpConfigPath)) {
14629
- const existingContent = await readFile(mcpConfigPath, "utf-8");
14630
- try {
14631
- const existingConfig = JSON.parse(existingContent);
14632
- if (existingConfig.mcpServers) {
14633
- existingConfig.mcpServers["automatosx"] = mcpConfig.mcpServers.automatosx;
14634
- await writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
14635
- logger.info("Updated existing .mcp.json with AutomatosX server", { path: mcpConfigPath });
14636
- return;
14637
- }
14638
- } catch {
14639
- logger.warn("Failed to parse existing .mcp.json, will overwrite", { path: mcpConfigPath });
15529
+ const { stdout: listOutput } = await execAsync9("qwen mcp list", { timeout: 1e4 });
15530
+ if (listOutput.includes("automatosx")) {
15531
+ if (force) {
15532
+ logger.info("Force mode: removing existing Qwen MCP server");
15533
+ await execAsync9("qwen mcp remove automatosx", { timeout: 1e4 }).catch(() => {
15534
+ });
15535
+ } else {
15536
+ logger.info("Qwen MCP server already configured");
15537
+ return "configured";
14640
15538
  }
14641
15539
  }
14642
- await writeFile(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
14643
- logger.info("Created .mcp.json for MCP discovery", { path: mcpConfigPath });
15540
+ const addCommand2 = `qwen mcp add automatosx automatosx mcp server -s project -e "AUTOMATOSX_PROJECT_DIR=${projectDir}"`;
15541
+ await execAsync9(addCommand2, { timeout: 3e4 });
15542
+ logger.info("Configured Qwen MCP integration via qwen mcp add");
15543
+ return "configured";
14644
15544
  } catch (error) {
14645
- logger.warn("Failed to create .mcp.json", {
14646
- error: error.message,
14647
- path: mcpConfigPath
15545
+ const errorMessage = error.message;
15546
+ if (errorMessage.includes("command not found") || errorMessage.includes("not recognized")) {
15547
+ logger.debug("Qwen CLI not available, skipping MCP setup");
15548
+ return "skipped";
15549
+ }
15550
+ logger.warn("Failed to setup Qwen MCP configuration", {
15551
+ error: errorMessage
14648
15552
  });
15553
+ return "failed";
14649
15554
  }
14650
15555
  }
14651
15556
  async function cleanupForceMode(projectDir) {
@@ -14800,7 +15705,7 @@ async function parsePackageJson(projectDir, info) {
14800
15705
  if (packageJson.workspaces || devDeps.includes("lerna") || devDeps.includes("nx") || devDeps.includes("turborepo") || existsSync(join(projectDir, "lerna.json")) || existsSync(join(projectDir, "nx.json"))) {
14801
15706
  info.isMonorepo = true;
14802
15707
  }
14803
- } catch (error) {
15708
+ } catch {
14804
15709
  }
14805
15710
  }
14806
15711
  async function parseReadmeDescription(projectDir, info) {
@@ -14861,10 +15766,10 @@ async function parseReadmeDescription(projectDir, info) {
14861
15766
  info.teamSize = "Open source community";
14862
15767
  }
14863
15768
  }
14864
- } catch (error) {
15769
+ } catch {
14865
15770
  }
14866
15771
  }
14867
- function categorizeScripts(scripts, packageManager) {
15772
+ function categorizeScripts(scripts, _packageManager) {
14868
15773
  const categorized = {
14869
15774
  development: [],
14870
15775
  building: [],
@@ -14974,7 +15879,7 @@ async function analyzeFileStructure(projectDir) {
14974
15879
  if (name === "docs") {
14975
15880
  structure.docsDirectory = name;
14976
15881
  }
14977
- } catch (error) {
15882
+ } catch {
14978
15883
  }
14979
15884
  }
14980
15885
  }
@@ -15004,7 +15909,7 @@ async function countFilesRecursive(dirPath, depth = 0) {
15004
15909
  }
15005
15910
  return count;
15006
15911
  }
15007
- async function detectKeyComponents(projectDir, info) {
15912
+ async function detectKeyComponents(projectDir, _info) {
15008
15913
  const components = [];
15009
15914
  const srcDir = join(projectDir, "src");
15010
15915
  if (!existsSync(srcDir)) return components;
@@ -15303,7 +16208,7 @@ async function detectDatabaseSchema(projectDir, info) {
15303
16208
  }
15304
16209
  return void 0;
15305
16210
  }
15306
- async function detectPrismaSchema(projectDir, schemaPath, info) {
16211
+ async function detectPrismaSchema(projectDir, schemaPath, _info) {
15307
16212
  const models = [];
15308
16213
  const migrations = await detectMigrations(projectDir, "prisma/migrations");
15309
16214
  try {
@@ -15357,7 +16262,7 @@ async function detectPrismaSchema(projectDir, schemaPath, info) {
15357
16262
  relations
15358
16263
  });
15359
16264
  }
15360
- } catch (error) {
16265
+ } catch {
15361
16266
  }
15362
16267
  return {
15363
16268
  orm: "Prisma",
@@ -15502,290 +16407,9 @@ async function findFilesRecursive(dir, pattern, maxDepth = 3, currentDepth = 0)
15502
16407
  return files;
15503
16408
  }
15504
16409
 
15505
- // src/cli/commands/init-parser.ts
15506
- init_esm_shims();
15507
- function parseAXMD(content) {
15508
- const result = {
15509
- dependencies: [],
15510
- scripts: {},
15511
- hasCustomContent: false,
15512
- customSections: []
15513
- };
15514
- const versionMatch = content.match(/Project:.*?\(v([\d.]+)\)/);
15515
- if (versionMatch) {
15516
- result.version = versionMatch[1];
15517
- }
15518
- const nameMatch = content.match(/# Project Context for (.+)/);
15519
- if (nameMatch) {
15520
- result.projectName = nameMatch[1];
15521
- }
15522
- const descMatch = content.match(/## Project Overview\n\n\*\*(.+?)\*\*/);
15523
- if (descMatch) {
15524
- result.description = descMatch[1];
15525
- }
15526
- const archMatch = content.match(/\*\*Architecture:\*\* (.+)/);
15527
- if (archMatch) {
15528
- result.architecture = archMatch[1];
15529
- }
15530
- const stackMatch = content.match(/\*\*Stack:\*\* (.+)/);
15531
- if (stackMatch && stackMatch[1]) {
15532
- result.stack = stackMatch[1];
15533
- result.dependencies = stackMatch[1].split(",").map((d) => d.trim().toLowerCase()).filter(Boolean);
15534
- }
15535
- const teamMatch = content.match(/\*\*Team:\*\* (.+)/);
15536
- if (teamMatch) {
15537
- result.team = teamMatch[1];
15538
- }
15539
- const testMatch = content.match(/- Framework: (.+)/);
15540
- if (testMatch) {
15541
- result.testFramework = testMatch[1];
15542
- }
15543
- const linterMatch = content.match(/- Linter: (.+)/);
15544
- if (linterMatch) {
15545
- result.linter = linterMatch[1];
15546
- }
15547
- const formatterMatch = content.match(/- Formatter: (.+)/);
15548
- if (formatterMatch) {
15549
- result.formatter = formatterMatch[1];
15550
- }
15551
- const commandsMatch = content.match(/## Canonical Commands\n\n```bash\n([\s\S]*?)```/);
15552
- if (commandsMatch && commandsMatch[1]) {
15553
- const commandsSection = commandsMatch[1];
15554
- const lines = commandsSection.split("\n");
15555
- for (const line of lines) {
15556
- const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#/);
15557
- if (cmdMatch && cmdMatch[1]) {
15558
- const cmd = cmdMatch[1].trim();
15559
- result.scripts[cmd] = cmd;
15560
- }
15561
- }
15562
- }
15563
- const customMarkers = [
15564
- /<!-- USER-EDITED -->/,
15565
- /## Our Custom/,
15566
- /## Notes/,
15567
- /## Team Guidelines/
15568
- ];
15569
- for (const marker of customMarkers) {
15570
- if (marker.test(content)) {
15571
- result.hasCustomContent = true;
15572
- break;
15573
- }
15574
- }
15575
- const sections = content.split(/^## /m);
15576
- const standardSections = [
15577
- "Project Overview",
15578
- "Agent Delegation Rules",
15579
- "Coding Conventions",
15580
- "Critical Guardrails",
15581
- "Canonical Commands",
15582
- "Useful Links"
15583
- ];
15584
- for (const section of sections) {
15585
- const sectionName = section.split("\n")[0] ?? "";
15586
- if (sectionName && !standardSections.includes(sectionName)) {
15587
- result.customSections.push(sectionName);
15588
- }
15589
- }
15590
- return result;
15591
- }
15592
- function detectDetailedChanges(parsed, current) {
15593
- const changes = [];
15594
- if (parsed.version !== current.version && current.version) {
15595
- changes.push({
15596
- type: "version",
15597
- field: "version",
15598
- oldValue: parsed.version,
15599
- newValue: current.version
15600
- });
15601
- }
15602
- const currentDeps = current.dependencies.map((d) => d.toLowerCase());
15603
- const addedDeps = currentDeps.filter((d) => !parsed.dependencies.includes(d));
15604
- if (addedDeps.length > 0) {
15605
- changes.push({
15606
- type: "dependency-added",
15607
- field: "dependencies",
15608
- items: addedDeps
15609
- });
15610
- }
15611
- const removedDeps = parsed.dependencies.filter((d) => !currentDeps.includes(d));
15612
- if (removedDeps.length > 0) {
15613
- changes.push({
15614
- type: "dependency-removed",
15615
- field: "dependencies",
15616
- items: removedDeps
15617
- });
15618
- }
15619
- const currentScriptKeys = Object.keys(current.scripts);
15620
- const parsedScriptKeys = Object.keys(parsed.scripts);
15621
- const addedScripts = currentScriptKeys.filter((s) => !parsedScriptKeys.includes(s));
15622
- if (addedScripts.length > 0) {
15623
- changes.push({
15624
- type: "script-added",
15625
- field: "scripts",
15626
- items: addedScripts
15627
- });
15628
- }
15629
- const removedScripts = parsedScriptKeys.filter((s) => !currentScriptKeys.includes(s));
15630
- if (removedScripts.length > 0) {
15631
- changes.push({
15632
- type: "script-removed",
15633
- field: "scripts",
15634
- items: removedScripts
15635
- });
15636
- }
15637
- if (current.linter && !parsed.linter) {
15638
- changes.push({
15639
- type: "tool-added",
15640
- field: "linter",
15641
- newValue: current.linter
15642
- });
15643
- }
15644
- if (current.formatter && !parsed.formatter) {
15645
- changes.push({
15646
- type: "tool-added",
15647
- field: "formatter",
15648
- newValue: current.formatter
15649
- });
15650
- }
15651
- if (current.testFramework && !parsed.testFramework) {
15652
- changes.push({
15653
- type: "tool-added",
15654
- field: "test framework",
15655
- newValue: current.testFramework
15656
- });
15657
- }
15658
- if (parsed.architecture && parsed.architecture !== current.architecture) {
15659
- changes.push({
15660
- type: "architecture",
15661
- field: "architecture",
15662
- oldValue: parsed.architecture,
15663
- newValue: current.architecture
15664
- });
15665
- }
15666
- return changes;
15667
- }
15668
- function formatChangeSummary(changes) {
15669
- if (changes.length === 0) return "";
15670
- const summaries = [];
15671
- for (const change of changes) {
15672
- switch (change.type) {
15673
- case "version":
15674
- summaries.push(`version ${change.oldValue} \u2192 ${change.newValue}`);
15675
- break;
15676
- case "dependency-added":
15677
- summaries.push(`+${change.items.length} dep${change.items.length > 1 ? "s" : ""}`);
15678
- break;
15679
- case "dependency-removed":
15680
- summaries.push(`-${change.items.length} dep${change.items.length > 1 ? "s" : ""}`);
15681
- break;
15682
- case "script-added":
15683
- summaries.push(`+${change.items.length} script${change.items.length > 1 ? "s" : ""}`);
15684
- break;
15685
- case "tool-added":
15686
- summaries.push(`+${change.field}`);
15687
- break;
15688
- case "architecture":
15689
- summaries.push("architecture");
15690
- break;
15691
- }
15692
- }
15693
- if (summaries.length === 0) return "";
15694
- if (summaries.length === 1) return `(${summaries[0]})`;
15695
- if (summaries.length === 2) return `(${summaries[0]}, ${summaries[1]})`;
15696
- return `(${summaries.length} changes)`;
15697
- }
15698
-
15699
16410
  // src/cli/commands/init.ts
15700
- function generateAXMD(info) {
15701
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
15702
- return `# Project Context for ${info.name}
15703
-
15704
- > Last updated: ${today}
15705
- > Project: ${info.name}${info.version ? ` (v${info.version})` : ""}
15706
-
15707
- ## Project Overview
15708
-
15709
- ${generateProjectOverview(info)}
15710
-
15711
- ## Architecture
15712
-
15713
- ${generateArchitecture(info)}
15714
-
15715
- ## File Structure
15716
-
15717
- ${generateFileStructure(info)}
15718
-
15719
- ${generateGettingStarted(info)}
15720
-
15721
- ${generateTroubleshooting(info)}
15722
-
15723
- ${generateDevWorkflow(info)}
15724
-
15725
- ${generateDatabaseSchema(info)}
15726
-
15727
- ${generateAPIDocumentation(info)}
15728
-
15729
- ${generateAgentRules(info)}
15730
-
15731
- ${generateCodingConventions(info)}
15732
-
15733
- ${generateCriticalGuardrails(info)}
15734
-
15735
- ${generateCommands(info)}
15736
-
15737
- ${generateUsefulLinks(info)}
15738
-
15739
- ---
15740
-
15741
- **Generated by \`ax init\` \u2022 Run regularly to keep up-to-date**
15742
- `;
15743
- }
15744
- function generateProjectOverview(info) {
15745
- const sections = [];
15746
- if (info.detailedDescription) {
15747
- sections.push(info.detailedDescription);
15748
- } else if (info.description) {
15749
- sections.push(`**${info.description}**`);
15750
- } else {
15751
- sections.push(`**${info.framework || "Node.js"} project${info.hasTypeScript ? " with TypeScript" : ""}**`);
15752
- }
15753
- const keyInfo = [];
15754
- keyInfo.push(`**Version:** ${info.version || "Not specified"}`);
15755
- keyInfo.push(`**Language:** ${info.language}`);
15756
- if (info.framework) keyInfo.push(`**Framework:** ${info.framework}`);
15757
- if (info.buildTool) keyInfo.push(`**Build Tool:** ${info.buildTool}`);
15758
- if (info.testFramework) keyInfo.push(`**Test Framework:** ${info.testFramework}`);
15759
- if (info.isMonorepo) keyInfo.push(`**Type:** Monorepo`);
15760
- sections.push("\n" + keyInfo.join(" \n"));
15761
- sections.push(`
15762
- **Stack:** ${info.stack}`);
15763
- if (info.teamSize) {
15764
- sections.push(`
15765
- **Team:** ${info.teamSize}`);
15766
- }
15767
- return sections.join("\n");
15768
- }
15769
- function generateArchitecture(info) {
15770
- const sections = [];
15771
- sections.push(`**Type:** ${detectArchitectureType(info)}`);
15772
- if (info.architectureFlow) {
15773
- sections.push("\n**Flow:**\n```");
15774
- sections.push(info.architectureFlow.trim());
15775
- sections.push("```");
15776
- }
15777
- if (info.keyComponents && info.keyComponents.length > 0) {
15778
- sections.push("\n**Key Components:**");
15779
- for (const comp of info.keyComponents) {
15780
- if (comp.purpose) {
15781
- sections.push(`- \`${comp.path}\` - ${comp.purpose}`);
15782
- } else {
15783
- sections.push(`- \`${comp.path}\``);
15784
- }
15785
- }
15786
- }
15787
- return sections.join("\n");
15788
- }
16411
+ var execAsync3 = promisify(exec);
16412
+ var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
15789
16413
  function detectArchitectureType(info) {
15790
16414
  if (info.dependencies.includes("next") || info.dependencies.includes("nuxt")) {
15791
16415
  return "Full-stack framework (SSR/SSG)";
@@ -15807,459 +16431,424 @@ function detectArchitectureType(info) {
15807
16431
  }
15808
16432
  return "Node.js application";
15809
16433
  }
15810
- function generateFileStructure(info) {
15811
- if (!info.fileStructure || info.fileStructure.directories.length === 0) {
15812
- return "";
15813
- }
15814
- const sections = [];
15815
- if (info.fileStructure.entryPoint) {
15816
- sections.push(`**Entry Point:** \`${info.fileStructure.entryPoint}\``);
15817
- }
15818
- sections.push("\n**Directories:**");
15819
- for (const dir of info.fileStructure.directories) {
15820
- if (dir.purpose) {
15821
- sections.push(`- \`${dir.path}/\` - ${dir.purpose} (${dir.fileCount} files)`);
15822
- } else {
15823
- sections.push(`- \`${dir.path}/\` - ${dir.fileCount} files`);
15824
- }
15825
- }
15826
- sections.push(`
15827
- **Total Files:** ${info.fileStructure.totalFiles}`);
15828
- return sections.join("\n");
15829
- }
15830
- function generateGettingStarted(info) {
15831
- if (!info.gettingStarted) {
15832
- return "";
15833
- }
15834
- const sections = ["## Getting Started", ""];
15835
- if (info.gettingStarted.prerequisites.length > 0) {
15836
- sections.push("### Prerequisites");
15837
- for (const prereq of info.gettingStarted.prerequisites) {
15838
- sections.push(`- ${prereq}`);
15839
- }
15840
- sections.push("");
15841
- }
15842
- if (info.gettingStarted.setupSteps.length > 0) {
15843
- sections.push("### First Time Setup");
15844
- for (const step of info.gettingStarted.setupSteps) {
15845
- sections.push(step);
16434
+ function generateAxIndex(info) {
16435
+ const now = (/* @__PURE__ */ new Date()).toISOString();
16436
+ const modules = [];
16437
+ if (info.fileStructure?.directories) {
16438
+ for (const dir of info.fileStructure.directories) {
16439
+ modules.push({
16440
+ path: dir.path,
16441
+ purpose: dir.purpose || `Contains ${dir.fileCount} files`,
16442
+ patterns: [],
16443
+ exports: []
16444
+ });
15846
16445
  }
15847
- sections.push("");
15848
16446
  }
15849
- if (info.gettingStarted.envVars.length > 0) {
15850
- sections.push("### Environment Variables");
15851
- sections.push("");
15852
- const required = info.gettingStarted.envVars.filter((v) => v.required);
15853
- const optional = info.gettingStarted.envVars.filter((v) => !v.required);
15854
- if (required.length > 0) {
15855
- sections.push("**Required:**");
15856
- for (const envVar of required) {
15857
- sections.push(`- \`${envVar.name}\`${envVar.description ? ` - ${envVar.description}` : ""}`);
15858
- if (envVar.example) {
15859
- sections.push(` - Example: \`${envVar.example}\``);
15860
- }
15861
- }
15862
- sections.push("");
15863
- }
15864
- if (optional.length > 0) {
15865
- sections.push("**Optional:**");
15866
- for (const envVar of optional) {
15867
- sections.push(`- \`${envVar.name}\`${envVar.description ? ` - ${envVar.description}` : ""}`);
15868
- if (envVar.example) {
15869
- sections.push(` - Example: \`${envVar.example}\``);
15870
- }
16447
+ const abstractions = [];
16448
+ if (info.keyComponents) {
16449
+ for (const comp of info.keyComponents) {
16450
+ abstractions.push({
16451
+ name: comp.path.split("/").pop() || comp.path,
16452
+ type: "pattern",
16453
+ location: comp.path,
16454
+ description: comp.purpose
16455
+ });
16456
+ }
16457
+ }
16458
+ const commands = {};
16459
+ if (info.categorizedScripts) {
16460
+ const categoryMap = {
16461
+ development: "development",
16462
+ testing: "testing",
16463
+ building: "building",
16464
+ quality: "quality",
16465
+ deployment: "deployment",
16466
+ other: "other"
16467
+ };
16468
+ for (const [category, scripts] of Object.entries(info.categorizedScripts)) {
16469
+ if (!scripts) continue;
16470
+ for (const script of scripts) {
16471
+ commands[script.name] = {
16472
+ script: `${info.packageManager} run ${script.name}`,
16473
+ description: script.description,
16474
+ category: categoryMap[category] || "other"
16475
+ };
15871
16476
  }
15872
- sections.push("");
15873
16477
  }
15874
16478
  }
15875
- return sections.join("\n");
16479
+ const prodDeps = info.dependencies.filter((d) => !d.startsWith("@types/"));
16480
+ const devDeps = info.dependencies.filter((d) => d.startsWith("@types/"));
16481
+ return {
16482
+ projectName: info.name,
16483
+ version: info.version || "0.0.0",
16484
+ projectType: detectArchitectureType(info),
16485
+ language: info.language,
16486
+ framework: info.framework,
16487
+ buildTool: info.buildTool,
16488
+ testFramework: info.testFramework,
16489
+ packageManager: info.packageManager,
16490
+ hasTypeScript: info.hasTypeScript,
16491
+ isMonorepo: info.isMonorepo || false,
16492
+ entryPoint: info.fileStructure?.entryPoint,
16493
+ sourceDirectory: info.fileStructure?.directories.find((d) => d.path === "src")?.path,
16494
+ testDirectory: info.fileStructure?.directories.find(
16495
+ (d) => d.path === "tests" || d.path === "test" || d.path === "__tests__"
16496
+ )?.path,
16497
+ modules,
16498
+ abstractions,
16499
+ commands,
16500
+ dependencies: {
16501
+ production: prodDeps.slice(0, 20),
16502
+ // Limit to top 20
16503
+ development: devDeps.slice(0, 10),
16504
+ // Limit to top 10
16505
+ total: info.dependencies.length
16506
+ },
16507
+ repository: info.repository,
16508
+ createdAt: now,
16509
+ updatedAt: now,
16510
+ analysisTier: 3
16511
+ // Default to comprehensive analysis
16512
+ };
15876
16513
  }
15877
- function generateTroubleshooting(info) {
15878
- const sections = ["## Troubleshooting", ""];
15879
- sections.push("### Common Issues");
16514
+ function generateCustomMD(info) {
16515
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
16516
+ const sections = [];
16517
+ sections.push(`# Custom Instructions for ${info.name}`);
15880
16518
  sections.push("");
15881
- sections.push("**Problem**: `npm install` fails with EACCES");
15882
- sections.push("**Solution**: Fix npm permissions: `sudo chown -R $USER ~/.npm`");
16519
+ sections.push(`> Generated: ${today}`);
16520
+ sections.push(`> Project: ${info.name}${info.version ? ` v${info.version}` : ""}`);
15883
16521
  sections.push("");
15884
- if (info.dependencies.includes("prisma") || info.dependencies.includes("typeorm") || info.dependencies.includes("pg") || info.dependencies.includes("mongodb")) {
15885
- sections.push("**Problem**: Database connection refused");
15886
- sections.push("**Solution**:");
15887
- sections.push("1. Check Docker is running: `docker ps`");
15888
- sections.push("2. Start services: `docker-compose up -d`");
15889
- if (info.scripts["db:ping"]) {
15890
- sections.push(`3. Verify connection: \`${info.packageManager} run db:ping\``);
15891
- }
15892
- sections.push("");
15893
- }
15894
- sections.push("**Problem**: Port already in use");
15895
- sections.push("**Solution**: Kill process: `lsof -ti:3000 | xargs kill`");
16522
+ sections.push("> **Note:** This file is protected from auto-rebuild. Edit freely to customize AI behavior.");
15896
16523
  sections.push("");
15897
- if (info.hasTypeScript) {
15898
- sections.push("**Problem**: TypeScript errors after `git pull`");
15899
- sections.push("**Solution**: Clean install: `rm -rf node_modules && npm install`");
15900
- sections.push("");
15901
- }
15902
- if (info.framework === "React" || info.framework === "Next.js" || info.framework === "Vue") {
15903
- sections.push("**Problem**: Hot reload not working");
15904
- sections.push("**Solution**: Check file watcher limits: `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf`");
15905
- sections.push("");
15906
- }
15907
- sections.push("### Debug Mode");
15908
- sections.push("Run with verbose logging:");
15909
- sections.push("```bash");
15910
- sections.push("DEBUG=* npm run dev");
15911
- if (info.scripts.test) {
15912
- sections.push("LOG_LEVEL=debug npm test");
16524
+ sections.push("## Project Overview");
16525
+ sections.push("");
16526
+ if (info.detailedDescription) {
16527
+ const firstParagraph = info.detailedDescription.split("\n\n")[0];
16528
+ sections.push(firstParagraph ?? "");
16529
+ } else if (info.description) {
16530
+ sections.push(info.description);
16531
+ } else {
16532
+ sections.push(`${info.framework || info.language} project${info.hasTypeScript ? " with TypeScript" : ""}`);
15913
16533
  }
15914
- sections.push("```");
15915
- return sections.join("\n");
15916
- }
15917
- function generateDevWorkflow(info) {
15918
- const sections = ["## Development Workflow", ""];
15919
- sections.push("### Daily Workflow");
15920
- sections.push("1. Pull latest: `git pull origin main`");
15921
- sections.push("2. Create feature branch: `git checkout -b feature/my-feature`");
15922
- sections.push("3. Make changes");
15923
- if (info.scripts.test) {
15924
- sections.push(`4. Run tests: \`${info.packageManager} test\``);
15925
- }
15926
- sections.push('5. Commit: `git commit -m "feat: add my feature"`');
15927
- sections.push("6. Push: `git push origin feature/my-feature`");
15928
- sections.push("7. Open PR on GitHub");
15929
- sections.push("8. Wait for CI + reviews");
15930
- sections.push("9. Merge to main (squash merge)");
15931
16534
  sections.push("");
15932
- sections.push("### Code Review Process");
15933
- sections.push("- Minimum 1 approval required");
15934
- sections.push("- CI must pass (tests + lint)");
15935
- sections.push("- No merge conflicts");
16535
+ sections.push("## Critical Rules");
15936
16536
  sections.push("");
15937
- sections.push("### Hot Reload");
15938
- if (info.framework === "React" || info.framework === "Vue") {
15939
- if (info.buildTool === "Vite") {
15940
- sections.push("- Frontend: Vite HMR (instant)");
15941
- } else {
15942
- sections.push("- Frontend: Hot module replacement enabled");
15943
- }
15944
- }
15945
- if (info.dependencies.includes("express") || info.dependencies.includes("fastify")) {
15946
- sections.push("- Backend: Nodemon (restart on save)");
15947
- }
15948
- if (info.framework === "Next.js") {
15949
- sections.push("- Next.js Fast Refresh (instant updates)");
15950
- }
16537
+ sections.push("### DO");
15951
16538
  sections.push("");
15952
- if (info.testFramework) {
15953
- sections.push("### Testing Strategy");
15954
- if (info.scripts["test:unit"]) {
15955
- sections.push(`- Unit tests: \`${info.packageManager} run test:unit\` (fast, no DB)`);
15956
- }
15957
- if (info.scripts["test:integration"]) {
15958
- sections.push(`- Integration tests: \`${info.packageManager} run test:integration\` (with test DB)`);
15959
- }
15960
- if (info.scripts["test:e2e"]) {
15961
- sections.push(`- E2E tests: \`${info.packageManager} run test:e2e\` (full stack)`);
15962
- }
15963
- if (info.scripts.test) {
15964
- sections.push(`- Run all: \`${info.packageManager} test\``);
15965
- }
16539
+ sections.push(`- Run \`${info.packageManager} test\` before pushing`);
16540
+ if (info.linter) {
16541
+ sections.push(`- Run \`${info.packageManager} run lint\` to check code style`);
15966
16542
  }
15967
- return sections.join("\n");
15968
- }
15969
- function generateDatabaseSchema(info) {
15970
- if (!info.databaseSchema || info.databaseSchema.models.length === 0) {
15971
- return "";
16543
+ if (info.hasTypeScript) {
16544
+ sections.push("- Use TypeScript strict mode conventions");
15972
16545
  }
15973
- const sections = ["## Database Schema", ""];
15974
- const schema = info.databaseSchema;
15975
- if (schema.orm) {
15976
- sections.push(`**ORM:** ${schema.orm}`);
15977
- sections.push("");
16546
+ sections.push("- Follow conventional commits (feat/fix/chore/docs)");
16547
+ sections.push("- Add tests for new features");
16548
+ sections.push("");
16549
+ sections.push("### DON'T");
16550
+ sections.push("");
16551
+ sections.push("- Commit directly to main/production branches");
16552
+ sections.push("- Skip tests before pushing");
16553
+ sections.push("- Expose API keys or credentials in code");
16554
+ if (info.dependencies.includes("prisma") || info.dependencies.includes("typeorm")) {
16555
+ sections.push("- Modify database migrations without approval");
15978
16556
  }
15979
- if (schema.models.length > 0) {
15980
- sections.push("### Models");
16557
+ sections.push("");
16558
+ if (info.categorizedScripts) {
16559
+ sections.push("## Key Commands");
15981
16560
  sections.push("");
15982
- for (const model of schema.models.slice(0, 10)) {
15983
- sections.push(`**${model.name}**`);
15984
- if (model.fields.length > 0) {
15985
- for (const field of model.fields) {
15986
- let fieldDesc = `- \`${field.name}\`: ${field.type}`;
15987
- const attrs = [];
15988
- if (field.isPrimaryKey) attrs.push("PK");
15989
- if (field.isUnique) attrs.push("unique");
15990
- if (field.isOptional) attrs.push("optional");
15991
- if (field.defaultValue) attrs.push(`default: ${field.defaultValue}`);
15992
- if (attrs.length > 0) {
15993
- fieldDesc += ` (${attrs.join(", ")})`;
15994
- }
15995
- sections.push(fieldDesc);
15996
- }
15997
- }
15998
- if (model.relations.length > 0) {
15999
- for (const rel of model.relations) {
16000
- sections.push(`- \`${rel.name}\`: ${rel.type} \u2192 ${rel.relatedModel}`);
16001
- }
16002
- }
16003
- sections.push("");
16004
- }
16005
- if (schema.models.length > 10) {
16006
- sections.push(`*... and ${schema.models.length - 10} more models*`);
16007
- sections.push("");
16561
+ sections.push("```bash");
16562
+ const allScripts = [
16563
+ ...info.categorizedScripts.development || [],
16564
+ ...info.categorizedScripts.testing || [],
16565
+ ...info.categorizedScripts.building || [],
16566
+ ...info.categorizedScripts.quality || []
16567
+ ].slice(0, 5);
16568
+ for (const script of allScripts) {
16569
+ sections.push(`${info.packageManager} run ${script.name} # ${script.description}`);
16008
16570
  }
16571
+ sections.push("```");
16572
+ sections.push("");
16009
16573
  }
16010
- if (schema.migrations.directory && schema.migrations.files.length > 0) {
16011
- sections.push("### Migrations");
16012
- sections.push(`- Location: \`${schema.migrations.directory}\``);
16013
- sections.push(`- Total: ${schema.migrations.files.length} migrations`);
16014
- if (info.scripts["db:migrate"] || info.scripts["migrate"] || info.scripts["prisma:migrate"]) {
16015
- const migrateCmd = info.scripts["db:migrate"] ? "db:migrate" : info.scripts["migrate"] ? "migrate" : "prisma:migrate";
16016
- sections.push(`- Run: \`${info.packageManager} run ${migrateCmd}\``);
16017
- }
16574
+ sections.push("## Troubleshooting");
16575
+ sections.push("");
16576
+ sections.push(`**Build fails**: Run \`rm -rf node_modules && ${info.packageManager} install\``);
16577
+ sections.push("");
16578
+ sections.push("**Tests fail**: Check for missing environment variables");
16579
+ sections.push("");
16580
+ if (info.hasTypeScript) {
16581
+ sections.push(`**Type errors**: Run \`${info.packageManager} run typecheck\` for details`);
16018
16582
  sections.push("");
16019
16583
  }
16584
+ sections.push("---");
16585
+ sections.push("");
16586
+ sections.push("*Generated by `ax init` \u2022 Edit this file to customize AI behavior*");
16020
16587
  return sections.join("\n");
16021
16588
  }
16022
- function generateAPIDocumentation(info) {
16023
- if (!info.apiDocumentation) {
16024
- return "";
16589
+ async function atomicWrite(filePath, content) {
16590
+ const tempPath = `${filePath}.tmp`;
16591
+ await writeFile(tempPath, content, "utf-8");
16592
+ await rename(tempPath, filePath);
16593
+ }
16594
+ function formatAge(ms) {
16595
+ const hours = Math.floor(ms / (1e3 * 60 * 60));
16596
+ if (hours < 24) return `${hours}h`;
16597
+ const days = Math.floor(hours / 24);
16598
+ return `${days}d`;
16599
+ }
16600
+ function getVersionCachePath() {
16601
+ return join(homedir(), ".automatosx", "version-cache.json");
16602
+ }
16603
+ async function readVersionCache() {
16604
+ try {
16605
+ const cachePath = getVersionCachePath();
16606
+ const content = await readFile(cachePath, "utf-8");
16607
+ return JSON.parse(content);
16608
+ } catch {
16609
+ return null;
16025
16610
  }
16026
- const sections = ["## API Documentation", ""];
16027
- const api = info.apiDocumentation;
16028
- if (api.framework) {
16029
- sections.push(`**Framework:** ${api.framework}`);
16030
- sections.push("");
16611
+ }
16612
+ async function writeVersionCache(cache) {
16613
+ const cachePath = getVersionCachePath();
16614
+ const cacheDir = join(homedir(), ".automatosx");
16615
+ await mkdir(cacheDir, { recursive: true });
16616
+ await writeFile(cachePath, JSON.stringify(cache, null, 2), "utf-8");
16617
+ }
16618
+ function isNewer(a, b) {
16619
+ const stripPrerelease = (v) => v.split("-")[0] || v;
16620
+ const parseVersion = (v) => stripPrerelease(v).split(".").map(Number);
16621
+ const [aMajor = 0, aMinor = 0, aPatch = 0] = parseVersion(a);
16622
+ const [bMajor = 0, bMinor = 0, bPatch = 0] = parseVersion(b);
16623
+ if (aMajor !== bMajor) return aMajor > bMajor;
16624
+ if (aMinor !== bMinor) return aMinor > bMinor;
16625
+ return aPatch > bPatch;
16626
+ }
16627
+ async function getCurrentVersion() {
16628
+ try {
16629
+ const { stdout } = await execAsync3("npm list -g @defai.digital/automatosx --depth=0 --json 2>/dev/null");
16630
+ const result = JSON.parse(stdout);
16631
+ const version = result.dependencies?.["@defai.digital/automatosx"]?.version;
16632
+ if (version) return version;
16633
+ } catch {
16031
16634
  }
16032
- if (api.hasOpenAPI && api.openAPIPath) {
16033
- sections.push(`**OpenAPI Spec:** \`${api.openAPIPath}\``);
16034
- sections.push("");
16635
+ try {
16636
+ const { dirname: dirname16 } = await import('path');
16637
+ const { fileURLToPath: fileURLToPath5 } = await import('url');
16638
+ const __filename3 = fileURLToPath5(import.meta.url);
16639
+ const __dirname4 = dirname16(__filename3);
16640
+ const pkgPath = join(__dirname4, "../../../package.json");
16641
+ const content = await readFile(pkgPath, "utf-8");
16642
+ const pkg = JSON.parse(content);
16643
+ return pkg.version || null;
16644
+ } catch {
16645
+ return null;
16035
16646
  }
16036
- if (api.endpoints.length > 0) {
16037
- sections.push("### Endpoints");
16038
- sections.push("");
16039
- const grouped = /* @__PURE__ */ new Map();
16040
- for (const endpoint of api.endpoints) {
16041
- const group = endpoint.group || "other";
16042
- if (!grouped.has(group)) {
16043
- grouped.set(group, []);
16044
- }
16045
- grouped.get(group)?.push(endpoint);
16647
+ }
16648
+ async function getLatestVersion() {
16649
+ try {
16650
+ const { stdout } = await execAsync3("npm view @defai.digital/automatosx version 2>/dev/null");
16651
+ return stdout.trim() || null;
16652
+ } catch {
16653
+ return null;
16654
+ }
16655
+ }
16656
+ async function updateAutomatosx(version) {
16657
+ try {
16658
+ console.log(chalk5.cyan(`\u{1F4E5} Updating AutomatosX to v${version}...`));
16659
+ await execAsync3(`npm install -g @defai.digital/automatosx@${version}`, {
16660
+ maxBuffer: 10 * 1024 * 1024
16661
+ });
16662
+ console.log(chalk5.green(`\u2713 AutomatosX updated to v${version}`));
16663
+ return true;
16664
+ } catch (error) {
16665
+ logger.warn("Failed to update AutomatosX", { error: error.message });
16666
+ console.log(chalk5.yellow(`\u26A0 Could not update AutomatosX: ${error.message}`));
16667
+ return false;
16668
+ }
16669
+ }
16670
+ async function checkAutomatosxUpdate() {
16671
+ try {
16672
+ const currentVersion = await getCurrentVersion();
16673
+ if (!currentVersion) {
16674
+ logger.debug("Could not determine current AutomatosX version");
16675
+ return false;
16046
16676
  }
16047
- for (const [group, endpoints] of grouped) {
16048
- if (group !== "other") {
16049
- sections.push(`**${group.charAt(0).toUpperCase() + group.slice(1)}**`);
16050
- }
16051
- for (const endpoint of endpoints.slice(0, 20)) {
16052
- let line = `- \`${endpoint.method} ${endpoint.path}\``;
16053
- if (endpoint.description) {
16054
- line += ` - ${endpoint.description}`;
16677
+ const cache = await readVersionCache();
16678
+ const now = Date.now();
16679
+ let latestVersion = null;
16680
+ let cacheIsValid = false;
16681
+ if (cache) {
16682
+ const lastCheckTime = new Date(cache.lastCheck).getTime();
16683
+ const age = now - lastCheckTime;
16684
+ if (age < STALE_THRESHOLD_MS && cache.currentVersion === currentVersion) {
16685
+ cacheIsValid = true;
16686
+ latestVersion = cache.latestVersion;
16687
+ logger.debug("AutomatosX version check using cache", {
16688
+ currentVersion,
16689
+ latestVersion,
16690
+ cacheAge: formatAge(age),
16691
+ updateAttempted: cache.updateAttempted
16692
+ });
16693
+ if (!isNewer(latestVersion, currentVersion)) {
16694
+ return false;
16055
16695
  }
16056
- if (endpoint.auth) {
16057
- line += " \u{1F512}";
16696
+ if (cache.updateAttempted) {
16697
+ console.log(chalk5.gray(`AutomatosX update available: ${currentVersion} \u2192 ${latestVersion} (run 'npm i -g @defai.digital/automatosx' to update)`));
16698
+ return false;
16058
16699
  }
16059
- sections.push(line);
16060
16700
  }
16061
- sections.push("");
16062
16701
  }
16063
- if (api.endpoints.length > 20) {
16064
- sections.push(`*... and ${api.endpoints.length - 20} more endpoints*`);
16065
- sections.push("");
16066
- }
16067
- }
16068
- return sections.join("\n");
16069
- }
16070
- function generateAgentRules(info) {
16071
- const rules = ["## Agent Delegation Rules", ""];
16072
- rules.push("### Development");
16073
- if (info.framework === "React" || info.framework === "Vue" || info.framework === "Next.js") {
16074
- rules.push(`- **Frontend/UI (${info.framework})** \u2192 @frontend (Frank)`);
16075
- }
16076
- if (info.dependencies.includes("express") || info.dependencies.includes("fastify") || info.dependencies.includes("koa")) {
16077
- rules.push("- **Backend/API** \u2192 @backend (Bob) or @fullstack (Felix)");
16078
- }
16079
- if (info.hasTypeScript) {
16080
- rules.push("- **TypeScript issues** \u2192 @fullstack (Felix)");
16081
- }
16082
- if (info.dependencies.some((d) => d.includes("react-native") || d.includes("expo"))) {
16083
- rules.push("- **Mobile** \u2192 @mobile (Maya)");
16084
- }
16085
- rules.push("- **Infrastructure/DevOps** \u2192 @devops (Oliver)");
16086
- rules.push("");
16087
- rules.push("### Quality & Architecture");
16088
- rules.push("- **Tests/QA** \u2192 @quality (Queenie)");
16089
- rules.push("- **Security audits** \u2192 @security (Steve) - mandatory for: auth, payments, PII");
16090
- rules.push("- **Architecture/ADR** \u2192 @architecture (Avery)");
16091
- rules.push("");
16092
- rules.push("### Documentation & Product");
16093
- rules.push("- **Technical writing** \u2192 @writer (Wendy)");
16094
- rules.push("- **Product management** \u2192 @product (Paris)");
16095
- return rules.join("\n");
16096
- }
16097
- function generateCodingConventions(info) {
16098
- const conventions = ["## Coding Conventions", ""];
16099
- conventions.push("### Testing");
16100
- if (info.testFramework) {
16101
- conventions.push(`- **Framework:** ${info.testFramework}`);
16102
- conventions.push("- **Coverage:** 80% minimum");
16103
- conventions.push(`- **Run:** \`${info.packageManager} test\``);
16104
- } else {
16105
- conventions.push("- Run tests before pushing");
16106
- }
16107
- conventions.push("");
16108
- conventions.push("### Code Style");
16109
- if (info.linter) {
16110
- conventions.push(`- **Linter:** ${info.linter}`);
16111
- }
16112
- if (info.formatter) {
16113
- conventions.push(`- **Formatter:** ${info.formatter}`);
16114
- }
16115
- if (info.hasTypeScript) {
16116
- conventions.push("- **TypeScript:** Strict mode enabled");
16117
- }
16118
- conventions.push("- **Indent:** 2 spaces");
16119
- conventions.push("- **Max line:** 100 chars");
16120
- conventions.push("");
16121
- conventions.push("### Git Workflow");
16122
- conventions.push("- **Branch naming:** `feature/description` or `fix/description`");
16123
- conventions.push("- **Commits:** Conventional commits format (feat/fix/chore/docs)");
16124
- conventions.push("- **PRs:** Review required before merge");
16125
- return conventions.join("\n");
16126
- }
16127
- function generateCriticalGuardrails(info) {
16128
- const guardrails = ["## Critical Guardrails", ""];
16129
- guardrails.push("\u26A0\uFE0F **NEVER:**");
16130
- guardrails.push("- Commit to main/production branches directly");
16131
- guardrails.push("- Skip tests before pushing");
16132
- guardrails.push("- Expose API keys or credentials in code");
16133
- if (info.dependencies.includes("prisma") || info.dependencies.includes("typeorm")) {
16134
- guardrails.push("- Modify database migrations without approval");
16135
- }
16136
- guardrails.push("");
16137
- guardrails.push("\u2705 **ALWAYS:**");
16138
- guardrails.push(`- Run \`${info.packageManager} test\` before pushing`);
16139
- if (info.linter) {
16140
- guardrails.push(`- Run \`${info.packageManager} run lint\` to check code style`);
16141
- }
16142
- if (info.formatter) {
16143
- guardrails.push(`- Format code with ${info.formatter} before committing`);
16144
- }
16145
- guardrails.push("- Document breaking changes");
16146
- guardrails.push("- Add tests for new features");
16147
- return guardrails.join("\n");
16148
- }
16149
- function generateCommands(info) {
16150
- const sections = ["## Canonical Commands", ""];
16151
- if (!info.categorizedScripts) {
16152
- return sections.join("\n") + "```bash\n# No scripts detected\n```";
16153
- }
16154
- const categories = [
16155
- { key: "development", title: "Development" },
16156
- { key: "building", title: "Building" },
16157
- { key: "testing", title: "Testing" },
16158
- { key: "quality", title: "Quality Checks" },
16159
- { key: "deployment", title: "Deployment" }
16160
- ];
16161
- sections.push("```bash");
16162
- for (const { key, title } of categories) {
16163
- const scripts = info.categorizedScripts[key];
16164
- if (scripts && scripts.length > 0) {
16165
- sections.push(`# ${title}`);
16166
- for (const script of scripts) {
16167
- const cmd = `${info.packageManager} run ${script.name}`;
16168
- const padding = " ".repeat(Math.max(35 - cmd.length, 1));
16169
- sections.push(`${cmd}${padding}# ${script.description}`);
16702
+ if (!cacheIsValid) {
16703
+ console.log(chalk5.gray("Checking for AutomatosX updates..."));
16704
+ latestVersion = await getLatestVersion();
16705
+ if (!latestVersion) {
16706
+ logger.debug("Could not fetch latest AutomatosX version");
16707
+ return false;
16708
+ }
16709
+ await writeVersionCache({
16710
+ lastCheck: (/* @__PURE__ */ new Date()).toISOString(),
16711
+ currentVersion,
16712
+ latestVersion,
16713
+ updateAttempted: false
16714
+ });
16715
+ logger.info("AutomatosX version check completed", {
16716
+ currentVersion,
16717
+ latestVersion,
16718
+ updateAvailable: isNewer(latestVersion, currentVersion)
16719
+ });
16720
+ if (!isNewer(latestVersion, currentVersion)) {
16721
+ console.log(chalk5.gray(`AutomatosX is up to date (v${currentVersion})`));
16722
+ return false;
16170
16723
  }
16171
- sections.push("");
16172
- }
16173
- }
16174
- const other = info.categorizedScripts.other;
16175
- if (other && other.length > 0) {
16176
- sections.push("# Other");
16177
- for (const script of other) {
16178
- const cmd = `${info.packageManager} run ${script.name}`;
16179
- const padding = " ".repeat(Math.max(35 - cmd.length, 1));
16180
- sections.push(`${cmd}${padding}# ${script.description}`);
16181
16724
  }
16725
+ console.log(chalk5.yellow(`\u{1F4E6} AutomatosX update available: ${currentVersion} \u2192 ${latestVersion}`));
16726
+ const updated = await updateAutomatosx(latestVersion);
16727
+ await writeVersionCache({
16728
+ lastCheck: cache?.lastCheck || (/* @__PURE__ */ new Date()).toISOString(),
16729
+ currentVersion: updated ? latestVersion : currentVersion,
16730
+ latestVersion,
16731
+ updateAttempted: true
16732
+ });
16733
+ return updated;
16734
+ } catch (error) {
16735
+ logger.debug("AutomatosX version check failed", { error: error.message });
16736
+ return false;
16182
16737
  }
16183
- sections.push("```");
16184
- return sections.join("\n");
16185
- }
16186
- function generateUsefulLinks(info) {
16187
- const links = ["## Useful Links", ""];
16188
- if (info.repository) {
16189
- links.push(`- [Repository](${info.repository})`);
16190
- }
16191
- if (info.fileStructure?.docsDirectory) {
16192
- links.push(`- [Documentation](${info.fileStructure.docsDirectory}/)`);
16193
- }
16194
- return links.join("\n");
16195
- }
16196
- async function atomicWrite(filePath, content) {
16197
- const tempPath = `${filePath}.tmp`;
16198
- await writeFile(tempPath, content, "utf-8");
16199
- await rename(tempPath, filePath);
16200
16738
  }
16201
16739
  var initCommand = {
16202
16740
  command: "init",
16203
- describe: "Initialize AX.md project context file",
16741
+ describe: "Initialize project index (ax.index.json) and custom instructions",
16204
16742
  builder: (yargs2) => {
16205
16743
  return yargs2.option("force", {
16206
16744
  alias: "f",
16207
- describe: "Regenerate AX.md from scratch",
16745
+ describe: "Regenerate all files including CUSTOM.md",
16746
+ type: "boolean",
16747
+ default: false
16748
+ }).option("skip-update", {
16749
+ describe: "Skip AutomatosX version check",
16208
16750
  type: "boolean",
16209
16751
  default: false
16210
16752
  }).example([
16211
- ["$0 init", "Create or update AX.md with current project info"],
16212
- ["$0 init --force", "Regenerate AX.md from scratch"]
16753
+ ["$0 init", "Create or update ax.index.json (auto-rebuilds if >24h old)"],
16754
+ ["$0 init --force", "Regenerate all files including CUSTOM.md"],
16755
+ ["$0 init --skip-update", "Skip AutomatosX version check"]
16213
16756
  ]);
16214
16757
  },
16215
16758
  handler: async (argv) => {
16216
16759
  const projectDir = process.cwd();
16217
- const axMdPath = join(projectDir, "AX.md");
16760
+ if (!argv.skipUpdate) {
16761
+ const wasUpdated = await checkAutomatosxUpdate();
16762
+ if (wasUpdated) {
16763
+ console.log(chalk5.cyan("\n\u{1F504} Re-running ax init --force with updated AutomatosX...\n"));
16764
+ try {
16765
+ const { stdout } = await execAsync3("automatosx init --force --skip-update");
16766
+ console.log(stdout);
16767
+ return;
16768
+ } catch (error) {
16769
+ try {
16770
+ const { stdout } = await execAsync3("ax init --force --skip-update");
16771
+ console.log(stdout);
16772
+ return;
16773
+ } catch {
16774
+ logger.warn("Could not re-run init with updated version, continuing with current process");
16775
+ argv.force = true;
16776
+ }
16777
+ }
16778
+ }
16779
+ }
16780
+ const indexPath = join(projectDir, "ax.index.json");
16781
+ const automatosxDir = join(projectDir, ".automatosx");
16782
+ const customMdPath = join(automatosxDir, "CUSTOM.md");
16218
16783
  try {
16784
+ const indexExists = await access$1(indexPath, constants.F_OK).then(() => true).catch(() => false);
16785
+ let indexAge = null;
16786
+ if (indexExists) {
16787
+ try {
16788
+ const stats = await stat(indexPath);
16789
+ indexAge = Date.now() - stats.mtime.getTime();
16790
+ } catch {
16791
+ }
16792
+ }
16793
+ const isStale = indexAge !== null && indexAge > STALE_THRESHOLD_MS;
16794
+ const shouldRebuildIndex = !indexExists || isStale || argv.force;
16795
+ if (!shouldRebuildIndex && !argv.force) {
16796
+ console.log(chalk5.green(`\u2713 ax.index.json is up to date (${indexAge ? formatAge(indexAge) : "0h"} old)`));
16797
+ console.log(chalk5.gray(" Use --force to regenerate"));
16798
+ return;
16799
+ }
16219
16800
  const projectInfo = await detectProjectInfo(projectDir);
16220
- const axMdExists = await access$1(axMdPath, constants.F_OK).then(() => true).catch(() => false);
16221
- if (axMdExists && !argv.force) {
16222
- const existingContent = await readFile(axMdPath, "utf-8");
16223
- const parsed = parseAXMD(existingContent);
16224
- const changes = detectDetailedChanges(parsed, {
16225
- version: projectInfo.version,
16226
- dependencies: projectInfo.dependencies,
16227
- scripts: projectInfo.scripts,
16228
- framework: projectInfo.framework,
16229
- architecture: detectArchitectureType(projectInfo),
16230
- linter: projectInfo.linter,
16231
- formatter: projectInfo.formatter,
16232
- testFramework: projectInfo.testFramework
16233
- });
16234
- if (changes.length === 0) {
16235
- console.log(chalk5.green("\u2713 AX.md is up to date"));
16236
- logger.info("AX.md unchanged", { projectName: projectInfo.name });
16237
- return;
16801
+ let indexContent;
16802
+ if (indexExists && !argv.force) {
16803
+ try {
16804
+ const existingIndex = JSON.parse(await readFile(indexPath, "utf-8"));
16805
+ indexContent = {
16806
+ ...generateAxIndex(projectInfo),
16807
+ createdAt: existingIndex.createdAt || (/* @__PURE__ */ new Date()).toISOString()
16808
+ };
16809
+ } catch {
16810
+ indexContent = generateAxIndex(projectInfo);
16238
16811
  }
16239
- const axMdContent = generateAXMD(projectInfo);
16240
- await atomicWrite(axMdPath, axMdContent);
16241
- const summary = formatChangeSummary(changes);
16242
- console.log(chalk5.green(`\u2713 Updated AX.md ${summary}`));
16243
- logger.info("AX.md updated", {
16244
- projectName: projectInfo.name,
16245
- changes: changes.length,
16246
- changeTypes: changes.map((c) => c.type)
16247
- });
16248
16812
  } else {
16249
- const axMdContent = generateAXMD(projectInfo);
16250
- await atomicWrite(axMdPath, axMdContent);
16813
+ indexContent = generateAxIndex(projectInfo);
16814
+ }
16815
+ await atomicWrite(indexPath, JSON.stringify(indexContent, null, 2));
16816
+ if (isStale) {
16817
+ console.log(chalk5.green(`\u2713 Rebuilt ax.index.json (was ${formatAge(indexAge)} old)`));
16818
+ } else if (indexExists) {
16819
+ console.log(chalk5.green("\u2713 Updated ax.index.json"));
16820
+ } else {
16251
16821
  const projectType = projectInfo.framework || projectInfo.language;
16252
- console.log(chalk5.green(`\u2713 Created AX.md (${projectType} project)`));
16253
- logger.info("AX.md created", {
16254
- projectName: projectInfo.name,
16255
- framework: projectInfo.framework,
16256
- language: projectInfo.language,
16257
- forced: argv.force
16258
- });
16822
+ console.log(chalk5.green(`\u2713 Created ax.index.json (${projectType} project)`));
16823
+ }
16824
+ await mkdir(automatosxDir, { recursive: true });
16825
+ const customMdExists = await access$1(customMdPath, constants.F_OK).then(() => true).catch(() => false);
16826
+ if (!customMdExists || argv.force) {
16827
+ const customMdContent = generateCustomMD(projectInfo);
16828
+ await atomicWrite(customMdPath, customMdContent);
16829
+ if (argv.force && customMdExists) {
16830
+ console.log(chalk5.yellow("\u2713 Regenerated .automatosx/CUSTOM.md (--force)"));
16831
+ } else {
16832
+ console.log(chalk5.green("\u2713 Created .automatosx/CUSTOM.md"));
16833
+ }
16834
+ } else {
16835
+ console.log(chalk5.gray(" .automatosx/CUSTOM.md preserved (use --force to regenerate)"));
16259
16836
  }
16837
+ console.log("");
16838
+ console.log(chalk5.cyan("Project initialized:"));
16839
+ console.log(chalk5.gray(" \u2022 ax.index.json - Shared project index (auto-rebuilds after 24h)"));
16840
+ console.log(chalk5.gray(" \u2022 CUSTOM.md - Custom AI instructions (edit to customize)"));
16841
+ console.log("");
16842
+ console.log(chalk5.gray("Agents will use ax.index.json to understand your project."));
16843
+ logger.info("Project initialized", {
16844
+ projectName: projectInfo.name,
16845
+ indexRebuilt: shouldRebuildIndex,
16846
+ wasStale: isStale,
16847
+ force: argv.force
16848
+ });
16260
16849
  } catch (error) {
16261
- console.log(chalk5.red("\u2717 Error with AX.md"));
16262
- logger.error("AX.md initialization failed", { error });
16850
+ console.log(chalk5.red("\u2717 Error initializing project"));
16851
+ logger.error("Project initialization failed", { error });
16263
16852
  if (process.env.DEBUG || process.env.AUTOMATOSX_DEBUG) {
16264
16853
  printError(error);
16265
16854
  }
@@ -19971,7 +20560,7 @@ var MemoryManager = class _MemoryManager {
19971
20560
  if (this.db) {
19972
20561
  try {
19973
20562
  this.db.close();
19974
- } catch (closeError) {
20563
+ } catch {
19975
20564
  }
19976
20565
  this.initialized = false;
19977
20566
  this.entryCount = 0;
@@ -20725,9 +21314,9 @@ var MemoryManager = class _MemoryManager {
20725
21314
  throw new MemoryError("Memory manager not initialized", "DATABASE_ERROR");
20726
21315
  }
20727
21316
  try {
20728
- const { mkdir: mkdir14 } = await import('fs/promises');
21317
+ const { mkdir: mkdir15 } = await import('fs/promises');
20729
21318
  const destDir = dirname4(destPath);
20730
- await mkdir14(destDir, { recursive: true });
21319
+ await mkdir15(destDir, { recursive: true });
20731
21320
  await this.db.backup(destPath);
20732
21321
  logger.info("Database backup created", { destPath: normalizePath(destPath) });
20733
21322
  } catch (error) {
@@ -20812,9 +21401,9 @@ var MemoryManager = class _MemoryManager {
20812
21401
  }
20813
21402
  }
20814
21403
  const {
20815
- includeEmbeddings = false,
21404
+ includeEmbeddings: _includeEmbeddings = false,
20816
21405
  filters = {},
20817
- batchSize = 1e3,
21406
+ batchSize: _batchSize = 1e3,
20818
21407
  pretty = false
20819
21408
  } = options || {};
20820
21409
  try {
@@ -21972,7 +22561,7 @@ var SessionManager = class _SessionManager {
21972
22561
  if (this.pendingSave) {
21973
22562
  try {
21974
22563
  await this.pendingSave;
21975
- } catch (err) {
22564
+ } catch {
21976
22565
  }
21977
22566
  }
21978
22567
  this.pendingSave = this.doSave().finally(() => {
@@ -22040,7 +22629,7 @@ var SessionManager = class _SessionManager {
22040
22629
  }
22041
22630
  try {
22042
22631
  await unlink(tempPath);
22043
- } catch (unlinkError) {
22632
+ } catch {
22044
22633
  }
22045
22634
  throw renameError;
22046
22635
  }
@@ -22048,7 +22637,7 @@ var SessionManager = class _SessionManager {
22048
22637
  const tempPath = `${this.persistencePath}.tmp`;
22049
22638
  try {
22050
22639
  await unlink(tempPath);
22051
- } catch (unlinkError) {
22640
+ } catch {
22052
22641
  }
22053
22642
  logger.error("Failed to save sessions to persistence", {
22054
22643
  path: normalizePath(this.persistencePath),
@@ -22587,6 +23176,7 @@ init_esm_shims();
22587
23176
  init_logger();
22588
23177
  var MAX_CONTEXT_SIZE = 100 * 1024;
22589
23178
  var DEFAULT_CACHE_TTL = 3e5;
23179
+ var STALE_THRESHOLD_MS2 = 24 * 60 * 60 * 1e3;
22590
23180
  var ProjectContextLoader = class {
22591
23181
  constructor(projectRoot, options) {
22592
23182
  this.projectRoot = projectRoot;
@@ -22610,76 +23200,79 @@ var ProjectContextLoader = class {
22610
23200
  });
22611
23201
  const context = {};
22612
23202
  try {
22613
- const mdPath = path4__default.join(this.projectRoot, "AX.md");
22614
- const resolvedPath = await realpath$1(mdPath).catch(() => null);
23203
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
23204
+ const resolvedPath = await realpath$1(indexPath).catch(() => null);
22615
23205
  if (resolvedPath) {
22616
23206
  const rel = path4__default.relative(this.projectRoot, resolvedPath);
22617
23207
  if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
22618
23208
  const stats = await stat(resolvedPath);
22619
23209
  if (stats.size > MAX_CONTEXT_SIZE) {
22620
- logger.warn("AX.md too large, ignoring", {
23210
+ logger.warn("ax.index.json too large, ignoring", {
22621
23211
  size: stats.size,
22622
23212
  limit: MAX_CONTEXT_SIZE
22623
23213
  });
22624
23214
  } else {
22625
- context.markdown = await readFile(resolvedPath, "utf-8");
22626
- logger.info("Loaded AX.md", {
22627
- size: stats.size,
22628
- lines: context.markdown.split("\n").length
23215
+ const indexContent = await readFile(resolvedPath, "utf-8");
23216
+ context.index = JSON.parse(indexContent);
23217
+ context.lastUpdated = stats.mtime;
23218
+ const age = Date.now() - stats.mtime.getTime();
23219
+ context.isStale = age > STALE_THRESHOLD_MS2;
23220
+ logger.info("Loaded ax.index.json", {
23221
+ projectName: context.index.projectName,
23222
+ projectType: context.index.projectType,
23223
+ isStale: context.isStale,
23224
+ ageHours: Math.floor(age / (1e3 * 60 * 60))
22629
23225
  });
22630
- context.agentRules = this.parseAgentRules(context.markdown);
22631
- context.guardrails = this.parseGuardrails(context.markdown);
22632
- context.commands = this.parseCommands(context.markdown);
22633
- context.metadata = this.parseMetadata(context.markdown);
23226
+ if (context.index.commands) {
23227
+ context.commands = {};
23228
+ for (const [name, cmd] of Object.entries(context.index.commands)) {
23229
+ context.commands[name] = cmd.script;
23230
+ }
23231
+ }
22634
23232
  }
22635
23233
  }
22636
23234
  }
22637
23235
  } catch (error) {
22638
23236
  if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
22639
- logger.warn("Error loading AX.md", { error });
23237
+ logger.warn("Error loading ax.index.json", { error });
22640
23238
  }
22641
23239
  }
22642
23240
  try {
22643
- const ymlPath = path4__default.join(this.projectRoot, "ax.config.yml");
22644
- const resolvedPath = await realpath$1(ymlPath).catch(() => null);
23241
+ const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
23242
+ const resolvedPath = await realpath$1(customMdPath).catch(() => null);
22645
23243
  if (resolvedPath) {
22646
23244
  const rel = path4__default.relative(this.projectRoot, resolvedPath);
22647
23245
  if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
22648
23246
  const stats = await stat(resolvedPath);
22649
23247
  if (stats.size > MAX_CONTEXT_SIZE) {
22650
- logger.warn("ax.config.yml too large, ignoring", {
23248
+ logger.warn("CUSTOM.md too large, ignoring", {
22651
23249
  size: stats.size,
22652
23250
  limit: MAX_CONTEXT_SIZE
22653
23251
  });
22654
23252
  } else {
22655
- const ymlContent = await readFile(resolvedPath, "utf-8");
22656
- context.config = yaml.parse(ymlContent);
22657
- logger.info("Loaded ax.config.yml", {
22658
- size: stats.size
23253
+ context.customInstructions = await readFile(resolvedPath, "utf-8");
23254
+ logger.info("Loaded CUSTOM.md", {
23255
+ size: stats.size,
23256
+ lines: context.customInstructions.split("\n").length
22659
23257
  });
22660
- if (context.config.commands) {
22661
- context.commands = { ...context.commands, ...context.config.commands };
22662
- }
22663
- if (context.config.project) {
22664
- context.metadata = { ...context.metadata, ...context.config.project };
22665
- }
23258
+ context.guardrails = this.parseGuardrails(context.customInstructions);
22666
23259
  }
22667
23260
  }
22668
23261
  }
22669
23262
  } catch (error) {
22670
23263
  if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
22671
- logger.warn("Error loading ax.config.yml", { error });
23264
+ logger.warn("Error loading CUSTOM.md", { error });
22672
23265
  }
22673
23266
  }
22674
23267
  context.contextPrompt = this.buildContextPrompt(context);
22675
23268
  this.cache = context;
22676
23269
  this.cacheExpiry = Date.now() + this.cacheTTL;
22677
23270
  logger.info("Project context loaded", {
22678
- hasMarkdown: !!context.markdown,
22679
- hasConfig: !!context.config,
22680
- agentRules: context.agentRules?.length ?? 0,
23271
+ hasIndex: !!context.index,
23272
+ hasCustomInstructions: !!context.customInstructions,
22681
23273
  guardrails: context.guardrails?.length ?? 0,
22682
- commands: Object.keys(context.commands ?? {}).length
23274
+ commands: Object.keys(context.commands ?? {}).length,
23275
+ isStale: context.isStale
22683
23276
  });
22684
23277
  return context;
22685
23278
  }
@@ -22695,8 +23288,8 @@ var ProjectContextLoader = class {
22695
23288
  * Check if context exists (without loading)
22696
23289
  */
22697
23290
  async exists() {
22698
- const mdPath = path4__default.join(this.projectRoot, "AX.md");
22699
- const ymlPath = path4__default.join(this.projectRoot, "ax.config.yml");
23291
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
23292
+ const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
22700
23293
  const checkExists3 = async (filePath) => {
22701
23294
  try {
22702
23295
  await access$1(filePath, constants.F_OK);
@@ -22705,57 +23298,48 @@ var ProjectContextLoader = class {
22705
23298
  return false;
22706
23299
  }
22707
23300
  };
22708
- const [mdExists, ymlExists] = await Promise.all([
22709
- checkExists3(mdPath),
22710
- checkExists3(ymlPath)
23301
+ const [indexExists, customMdExists] = await Promise.all([
23302
+ checkExists3(indexPath),
23303
+ checkExists3(customMdPath)
22711
23304
  ]);
22712
- return mdExists || ymlExists;
23305
+ return indexExists || customMdExists;
22713
23306
  }
22714
23307
  /**
22715
- * Parse agent delegation rules from markdown
22716
- *
22717
- * Looks for patterns like:
22718
- * - Backend changes → @backend
22719
- * - API endpoints → @backend, @security
23308
+ * Check if ax.index.json is stale (older than 24 hours)
22720
23309
  */
22721
- parseAgentRules(markdown) {
22722
- const rules = [];
22723
- const sectionRegex = /##\s+Agent\s+Delegation\s+Rules[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
22724
- const match = markdown.match(sectionRegex);
22725
- if (!match || !match[1]) {
22726
- return rules;
22727
- }
22728
- const section = match[1];
22729
- const lineRegex = /^[-*]\s+(.+?)\s+(?:→|->)+\s+(.+?)$/gm;
22730
- let lineMatch;
22731
- while ((lineMatch = lineRegex.exec(section)) !== null) {
22732
- const taskType = lineMatch[1]?.trim() ?? "";
22733
- const agentsText = lineMatch[2]?.trim() ?? "";
22734
- const agents = agentsText.split(",").map((a) => a.trim()).filter(Boolean);
22735
- const defaultAgent = agents[0];
22736
- if (defaultAgent) {
22737
- rules.push({
22738
- taskType,
22739
- patterns: [],
22740
- // TODO: Parse file patterns if specified
22741
- defaultAgent,
22742
- autoReview: agents.length > 1
22743
- });
22744
- }
23310
+ async isStale() {
23311
+ try {
23312
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
23313
+ const stats = await stat(indexPath);
23314
+ const age = Date.now() - stats.mtime.getTime();
23315
+ return age > STALE_THRESHOLD_MS2;
23316
+ } catch {
23317
+ return true;
22745
23318
  }
22746
- return rules;
22747
23319
  }
22748
23320
  /**
22749
- * Parse guardrails/prohibitions from markdown
23321
+ * Parse guardrails from CUSTOM.md
22750
23322
  *
22751
- * Looks for "## Critical Guardrails" or "## Critical Rules" section
22752
- * Extracts items marked with ⚠️ or under NEVER headings
23323
+ * Looks for DO/DON'T sections in ax-cli format
22753
23324
  */
22754
23325
  parseGuardrails(markdown) {
22755
23326
  const guardrails = [];
22756
- const sectionRegex = /##\s+(Critical\s+Guardrails|Critical\s+Rules|Never)[^\n]*\n([\s\S]*?)(?=\n##|$)/gi;
23327
+ const dontRegex = /###\s+DON'T[^\n]*\n([\s\S]*?)(?=\n###|$)/i;
23328
+ const dontMatch = markdown.match(dontRegex);
23329
+ if (dontMatch && dontMatch[1]) {
23330
+ const section = dontMatch[1];
23331
+ const bulletRegex = /^[-*]\s+(.+?)$/gm;
23332
+ let bulletMatch;
23333
+ while ((bulletMatch = bulletRegex.exec(section)) !== null) {
23334
+ const rule = bulletMatch[1]?.trim();
23335
+ if (rule) {
23336
+ guardrails.push(rule);
23337
+ }
23338
+ }
23339
+ }
23340
+ const criticalRegex = /##\s+(Critical\s+Guardrails|Critical\s+Rules|Never)[^\n]*\n([\s\S]*?)(?=\n##|$)/gi;
22757
23341
  let match;
22758
- while ((match = sectionRegex.exec(markdown)) !== null) {
23342
+ while ((match = criticalRegex.exec(markdown)) !== null) {
22759
23343
  const section = match[2];
22760
23344
  if (!section) continue;
22761
23345
  const bulletRegex = /^[-*]\s+(.+?)$/gm;
@@ -22765,106 +23349,58 @@ var ProjectContextLoader = class {
22765
23349
  rule = rule.replace(/^[⚠️❌✅✓⚡🔒]+\s*/, "");
22766
23350
  rule = rule.replace(/\*\*(.+?)\*\*/g, "$1");
22767
23351
  rule = rule.replace(/`(.+?)`/g, "$1");
22768
- if (rule.length > 0) {
23352
+ if (rule.length > 0 && !guardrails.includes(rule)) {
22769
23353
  guardrails.push(rule);
22770
23354
  }
22771
23355
  }
22772
23356
  }
22773
23357
  return guardrails;
22774
23358
  }
22775
- /**
22776
- * Parse commands from markdown code blocks
22777
- *
22778
- * Looks for "## Commands" or "## Canonical Commands" section
22779
- */
22780
- parseCommands(markdown) {
22781
- const commands = {};
22782
- const sectionRegex = /##\s+(Canonical\s+)?Commands[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
22783
- const match = markdown.match(sectionRegex);
22784
- if (!match) {
22785
- return commands;
22786
- }
22787
- const section = match[2];
22788
- if (!section) {
22789
- return commands;
22790
- }
22791
- const codeBlockRegex = /```(?:bash|sh|shell)?\n([\s\S]*?)```/;
22792
- const codeMatch = section.match(codeBlockRegex);
22793
- if (codeMatch && codeMatch[1]) {
22794
- const lines = codeMatch[1].split("\n");
22795
- for (const line of lines) {
22796
- const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#?\s*(.*)$/);
22797
- if (cmdMatch && cmdMatch[1]) {
22798
- const cmd = cmdMatch[1].trim();
22799
- const desc = cmdMatch[2]?.trim() ?? "";
22800
- const key = desc || cmd;
22801
- commands[key] = cmd;
22802
- }
22803
- }
22804
- }
22805
- return commands;
22806
- }
22807
- /**
22808
- * Parse project metadata from markdown frontmatter or first section
22809
- */
22810
- parseMetadata(markdown) {
22811
- const metadata = {};
22812
- const lastUpdatedMatch = markdown.match(/>\s*Last\s+updated:\s*(.+?)$/im);
22813
- if (lastUpdatedMatch && lastUpdatedMatch[1]) {
22814
- metadata.lastUpdated = lastUpdatedMatch[1].trim();
22815
- }
22816
- const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
22817
- if (projectMatch && projectMatch[1]) {
22818
- const parts = projectMatch[1].trim().split(/\s+v/);
22819
- metadata.name = parts[0] || "";
22820
- if (parts.length > 1 && parts[1]) {
22821
- metadata.version = parts[1];
22822
- }
22823
- }
22824
- const h1Match = markdown.match(/^#\s+(.+?)$/m);
22825
- if (h1Match && h1Match[1] && !metadata.name) {
22826
- metadata.name = h1Match[1].replace(/Project Context for AutomatosX/i, "").trim();
22827
- }
22828
- return metadata;
22829
- }
22830
23359
  /**
22831
23360
  * Build formatted context prompt for agent injection
22832
23361
  */
22833
23362
  buildContextPrompt(context) {
22834
- if (!context.markdown && !context.config) {
23363
+ if (!context.index && !context.customInstructions) {
22835
23364
  return "";
22836
23365
  }
22837
23366
  let prompt = "\n# PROJECT CONTEXT\n\n";
22838
- if (context.guardrails && context.guardrails.length > 0) {
22839
- prompt += "## CRITICAL RULES (NEVER VIOLATE):\n\n";
22840
- context.guardrails.forEach((rule) => {
22841
- prompt += `- ${rule}
23367
+ if (context.index) {
23368
+ prompt += `**Project:** ${context.index.projectName} v${context.index.version}
22842
23369
  `;
22843
- });
22844
- prompt += "\n";
22845
- }
22846
- if (context.agentRules && context.agentRules.length > 0) {
22847
- prompt += "## Agent Delegation Rules:\n\n";
22848
- context.agentRules.forEach((rule) => {
22849
- prompt += `- ${rule.taskType} \u2192 ${rule.defaultAgent}
23370
+ prompt += `**Type:** ${context.index.projectType}
22850
23371
  `;
22851
- });
22852
- prompt += "\n";
23372
+ prompt += `**Language:** ${context.index.language}`;
23373
+ if (context.index.framework) {
23374
+ prompt += ` + ${context.index.framework}`;
23375
+ }
23376
+ prompt += "\n\n";
23377
+ if (context.index.modules.length > 0) {
23378
+ prompt += "## Project Structure:\n\n";
23379
+ for (const mod of context.index.modules.slice(0, 10)) {
23380
+ prompt += `- \`${mod.path}/\` - ${mod.purpose}
23381
+ `;
23382
+ }
23383
+ prompt += "\n";
23384
+ }
23385
+ if (context.commands && Object.keys(context.commands).length > 0) {
23386
+ prompt += "## Available Commands:\n\n";
23387
+ for (const [name, script] of Object.entries(context.commands).slice(0, 10)) {
23388
+ prompt += `- ${name}: \`${script}\`
23389
+ `;
23390
+ }
23391
+ prompt += "\n";
23392
+ }
22853
23393
  }
22854
- if (context.commands && Object.keys(context.commands).length > 0) {
22855
- prompt += "## Available Commands:\n\n";
22856
- Object.entries(context.commands).forEach(([desc, cmd]) => {
22857
- prompt += `- ${desc}: \`${cmd}\`
23394
+ if (context.guardrails && context.guardrails.length > 0) {
23395
+ prompt += "## CRITICAL RULES (NEVER VIOLATE):\n\n";
23396
+ for (const rule of context.guardrails) {
23397
+ prompt += `- ${rule}
22858
23398
  `;
22859
- });
23399
+ }
22860
23400
  prompt += "\n";
22861
23401
  }
22862
- if (context.markdown) {
22863
- const MAX_PROMPT_LENGTH = 1e4;
22864
- const contextToAdd = context.markdown.length > MAX_PROMPT_LENGTH ? context.markdown.substring(0, MAX_PROMPT_LENGTH) + "\n\n[... context truncated for length ...]" : context.markdown;
22865
- prompt += "## Full Project Context:\n\n";
22866
- prompt += contextToAdd;
22867
- prompt += "\n";
23402
+ if (context.isStale) {
23403
+ prompt += "\u26A0\uFE0F **Note:** Project index is stale (>24h old). Run `ax init` to update.\n\n";
22868
23404
  }
22869
23405
  return prompt;
22870
23406
  }
@@ -23288,10 +23824,10 @@ var ContextManager = class {
23288
23824
  return provider;
23289
23825
  }
23290
23826
  /**
23291
- * Load project context from AX.md (v7.1.0+)
23827
+ * Load project context from ax.index.json (v12.9.0+)
23292
23828
  *
23293
- * Loads project-specific instructions from AX.md file if it exists.
23294
- * Falls back gracefully if file doesn't exist.
23829
+ * Loads project-specific context from ax.index.json and CUSTOM.md.
23830
+ * Falls back gracefully if files don't exist.
23295
23831
  *
23296
23832
  * @param projectDir - Project root directory
23297
23833
  * @returns Project context or null if not found
@@ -23304,15 +23840,15 @@ var ContextManager = class {
23304
23840
  const loader = this.projectContextLoader;
23305
23841
  const exists = await loader.exists();
23306
23842
  if (!exists) {
23307
- logger.debug("No AX.md found, skipping project context");
23843
+ logger.debug("No ax.index.json or CUSTOM.md found, skipping project context");
23308
23844
  return null;
23309
23845
  }
23310
23846
  const context = await loader.load();
23311
- logger.debug("Project context loaded from AX.md", {
23312
- hasMarkdown: !!context.markdown,
23313
- hasConfig: !!context.config,
23314
- agentRules: context.agentRules?.length ?? 0,
23315
- guardrails: context.guardrails?.length ?? 0
23847
+ logger.debug("Project context loaded", {
23848
+ hasIndex: !!context.index,
23849
+ hasCustomInstructions: !!context.customInstructions,
23850
+ guardrails: context.guardrails?.length ?? 0,
23851
+ isStale: context.isStale
23316
23852
  });
23317
23853
  return context;
23318
23854
  } catch (error) {
@@ -26242,6 +26778,24 @@ ${context.task}`;
26242
26778
  // src/agents/agent-selector.ts
26243
26779
  init_esm_shims();
26244
26780
  init_logger();
26781
+ var regexCache = /* @__PURE__ */ new Map();
26782
+ function getCachedRegex(pattern) {
26783
+ if (regexCache.has(pattern)) {
26784
+ return regexCache.get(pattern) ?? null;
26785
+ }
26786
+ try {
26787
+ const regex = new RegExp(pattern, "i");
26788
+ regexCache.set(pattern, regex);
26789
+ return regex;
26790
+ } catch (error) {
26791
+ logger.debug("Invalid regex pattern cached as null", {
26792
+ pattern,
26793
+ error: error instanceof Error ? error.message : String(error)
26794
+ });
26795
+ regexCache.set(pattern, null);
26796
+ return null;
26797
+ }
26798
+ }
26245
26799
  function scoreAgent(task, profile) {
26246
26800
  let score = 0;
26247
26801
  const taskLower = task.toLowerCase();
@@ -26279,16 +26833,9 @@ function scoreAgent(task, profile) {
26279
26833
  }
26280
26834
  if (profile.selectionMetadata?.redirectWhen) {
26281
26835
  for (const rule of profile.selectionMetadata.redirectWhen) {
26282
- try {
26283
- const regex = new RegExp(rule.phrase, "i");
26284
- if (regex.test(task)) {
26285
- score -= 15;
26286
- }
26287
- } catch (error) {
26288
- logger.debug("Invalid regex pattern in redirectWhen rule", {
26289
- pattern: rule.phrase,
26290
- error: error instanceof Error ? error.message : String(error)
26291
- });
26836
+ const regex = getCachedRegex(rule.phrase);
26837
+ if (regex && regex.test(task)) {
26838
+ score -= 15;
26292
26839
  }
26293
26840
  }
26294
26841
  }
@@ -28878,8 +29425,8 @@ var BugDetector = class {
28878
29425
  async loadRulesFromFile(filePath) {
28879
29426
  try {
28880
29427
  const content = await readFile(filePath, "utf-8");
28881
- const yaml5 = await import('js-yaml');
28882
- const parsed = yaml5.load(content);
29428
+ const yaml4 = await import('js-yaml');
29429
+ const parsed = yaml4.load(content);
28883
29430
  if (parsed.rules && Array.isArray(parsed.rules)) {
28884
29431
  for (const rule of parsed.rules) {
28885
29432
  this.addRule(rule);
@@ -29311,7 +29858,6 @@ var BugFixer = class {
29311
29858
  }
29312
29859
  const directSetIntervalPattern = /setInterval\s*\(/;
29313
29860
  if (directSetIntervalPattern.test(line)) {
29314
- line.match(/^(\s*)/)?.[1] || "";
29315
29861
  const newLine = line.replace(
29316
29862
  /(setInterval\s*\([^)]+\))/,
29317
29863
  "const _interval = $1; if (_interval.unref) _interval.unref()"
@@ -29338,7 +29884,6 @@ var BugFixer = class {
29338
29884
  const match = currentLine.match(classPattern);
29339
29885
  if (match && match[1]) {
29340
29886
  classStartLine = i;
29341
- match[1];
29342
29887
  break;
29343
29888
  }
29344
29889
  }
@@ -29390,7 +29935,7 @@ var BugFixer = class {
29390
29935
  /**
29391
29936
  * Apply use DisposableEventEmitter fix
29392
29937
  */
29393
- applyUseDisposableEventEmitterFix(finding, originalContent, lines) {
29938
+ applyUseDisposableEventEmitterFix(finding, originalContent, _lines) {
29394
29939
  let fixedContent = originalContent.replace(
29395
29940
  /extends\s+EventEmitter\b/g,
29396
29941
  "extends DisposableEventEmitter"
@@ -30312,7 +30857,7 @@ var DUPLICATION_RULES = [
30312
30857
  suggestion: "Extract to a named constant"
30313
30858
  }
30314
30859
  ];
30315
- function detectDuplication(filePath, content, lines, ignoreState, config) {
30860
+ function detectDuplication(filePath, content, lines, ignoreState, _config) {
30316
30861
  const findings = [];
30317
30862
  findings.push(...detectDuplicateBlocks(filePath, content, lines, ignoreState));
30318
30863
  findings.push(...detectRepeatedConditionals(filePath, content, lines, ignoreState));
@@ -30339,7 +30884,7 @@ function detectDuplicateBlocks(filePath, content, lines, ignoreState) {
30339
30884
  }
30340
30885
  blockHashes.get(blockHash).push({ start: i + 1, end: i + MIN_BLOCK_SIZE });
30341
30886
  }
30342
- for (const [hash, locations] of blockHashes) {
30887
+ for (const [_hash, locations] of blockHashes) {
30343
30888
  if (locations.length > 1) {
30344
30889
  for (let i = 1; i < locations.length; i++) {
30345
30890
  const loc = locations[i];
@@ -30388,7 +30933,7 @@ function detectRepeatedConditionals(filePath, content, lines, ignoreState) {
30388
30933
  }
30389
30934
  conditionPattern.lastIndex = 0;
30390
30935
  }
30391
- for (const [condition, lineNums] of conditionalCounts) {
30936
+ for (const [_condition, lineNums] of conditionalCounts) {
30392
30937
  if (lineNums.length >= 2) {
30393
30938
  const firstLine = lineNums[0];
30394
30939
  const secondLine = lineNums[1];
@@ -30551,7 +31096,7 @@ var THRESHOLDS = {
30551
31096
  maxCyclomaticComplexity: 10,
30552
31097
  maxChainedCalls: 4
30553
31098
  };
30554
- function detectReadability(filePath, content, lines, ignoreState, config) {
31099
+ function detectReadability(filePath, content, lines, ignoreState, _config) {
30555
31100
  const findings = [];
30556
31101
  findings.push(...detectLongFunctions(filePath, content, lines, ignoreState));
30557
31102
  findings.push(...detectDeepNesting(filePath, content, lines, ignoreState));
@@ -30927,7 +31472,7 @@ var PERFORMANCE_RULES = [
30927
31472
  suggestion: "Remove await - async functions automatically wrap return values in promises"
30928
31473
  }
30929
31474
  ];
30930
- function detectPerformance(filePath, content, lines, ignoreState, config) {
31475
+ function detectPerformance(filePath, content, lines, ignoreState, _config) {
30931
31476
  const findings = [];
30932
31477
  findings.push(...detectSyncInAsync(filePath, content, lines, ignoreState));
30933
31478
  findings.push(...detectNPlusOne(filePath, content, lines, ignoreState));
@@ -31342,7 +31887,7 @@ var HARDCODE_RULES = [
31342
31887
  suggestion: "Extract timeout to a named constant or config"
31343
31888
  }
31344
31889
  ];
31345
- function detectHardcode(filePath, content, lines, ignoreState, config) {
31890
+ function detectHardcode(filePath, content, lines, ignoreState, _config) {
31346
31891
  const findings = [];
31347
31892
  findings.push(...detectMagicNumbers(filePath, content, lines, ignoreState));
31348
31893
  findings.push(...detectHardcodedUrls(filePath, content, lines, ignoreState));
@@ -31698,7 +32243,7 @@ var NAMING_RULES = [
31698
32243
  suggestion: "Use is/has/can/should prefix for boolean variables"
31699
32244
  }
31700
32245
  ];
31701
- function detectNaming(filePath, content, lines, ignoreState, config) {
32246
+ function detectNaming(filePath, content, lines, ignoreState, _config) {
31702
32247
  const findings = [];
31703
32248
  findings.push(...detectSingleLetterVariables(filePath, content, lines, ignoreState));
31704
32249
  findings.push(...detectHungarianNotation(filePath, content, lines, ignoreState));
@@ -31981,7 +32526,7 @@ var CONDITIONAL_RULES = [
31981
32526
  suggestion: "Use the condition directly (or negate it)"
31982
32527
  }
31983
32528
  ];
31984
- function detectConditionals(filePath, content, lines, ignoreState, config) {
32529
+ function detectConditionals(filePath, content, lines, ignoreState, _config) {
31985
32530
  const findings = [];
31986
32531
  findings.push(...detectDeeplyNestedIf(filePath, content, lines, ignoreState));
31987
32532
  findings.push(...detectComplexConditions(filePath, content, lines, ignoreState));
@@ -32294,7 +32839,7 @@ var DEAD_CODE_RULES = [
32294
32839
  suggestion: "Implement function or add TODO comment"
32295
32840
  }
32296
32841
  ];
32297
- function detectDeadCode(filePath, content, lines, ignoreState, config) {
32842
+ function detectDeadCode(filePath, content, lines, ignoreState, _config) {
32298
32843
  const findings = [];
32299
32844
  findings.push(...detectUnusedImports(filePath, content, lines, ignoreState));
32300
32845
  findings.push(...detectUnusedVariables(filePath, content, lines, ignoreState));
@@ -32588,7 +33133,7 @@ var TYPE_SAFETY_RULES = [
32588
33133
  fileExtensions: [".ts", ".tsx"]
32589
33134
  }
32590
33135
  ];
32591
- function detectTypeSafety(filePath, content, lines, ignoreState, config) {
33136
+ function detectTypeSafety(filePath, content, lines, ignoreState, _config) {
32592
33137
  const findings = [];
32593
33138
  if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
32594
33139
  return findings;
@@ -36797,7 +37342,7 @@ var createTaskSchema = {
36797
37342
  // src/mcp/tools/task/run-task.ts
36798
37343
  init_esm_shims();
36799
37344
  init_logger();
36800
- function createRunTaskHandler(deps) {
37345
+ function createRunTaskHandler(_deps) {
36801
37346
  return async (input, context) => {
36802
37347
  const startTime = Date.now();
36803
37348
  if (context?.signal?.aborted) {
@@ -39347,6 +39892,17 @@ Use this tool first to understand what AutomatosX offers.`,
39347
39892
  mode: "sdk"
39348
39893
  }));
39349
39894
  }
39895
+ if (config.providers["qwen"]?.enabled) {
39896
+ const { QwenProvider: QwenProvider2 } = await Promise.resolve().then(() => (init_qwen_provider(), qwen_provider_exports));
39897
+ const qwenConfig = config.providers["qwen"];
39898
+ providers.push(new QwenProvider2({
39899
+ name: "qwen",
39900
+ enabled: true,
39901
+ priority: qwenConfig.priority,
39902
+ timeout: qwenConfig.timeout,
39903
+ mode: qwenConfig.mode || "sdk"
39904
+ }));
39905
+ }
39350
39906
  const healthCheckInterval = config.router?.healthCheckInterval;
39351
39907
  this.router = new Router({
39352
39908
  providers,
@@ -42910,7 +43466,7 @@ var CheckpointManager = class {
42910
43466
  if (checkpoint.schemaVersion === CURRENT_SCHEMA_VERSION) {
42911
43467
  return checkpoint;
42912
43468
  }
42913
- let migrated = { ...checkpoint };
43469
+ const migrated = { ...checkpoint };
42914
43470
  if (checkpointVersion.major === 1 && checkpointVersion.minor === 0) ;
42915
43471
  migrated.schemaVersion = CURRENT_SCHEMA_VERSION;
42916
43472
  migrated.checksum = this.calculateChecksum(migrated);
@@ -43016,7 +43572,7 @@ var CheckpointManager = class {
43016
43572
  * @returns Hex-encoded checksum
43017
43573
  */
43018
43574
  calculateChecksum(checkpoint) {
43019
- const { checksum, updatedAt, ...dataForChecksum } = checkpoint;
43575
+ const { checksum: _checksum, updatedAt: _updatedAt, ...dataForChecksum } = checkpoint;
43020
43576
  const hash = createHash("sha256");
43021
43577
  hash.update(JSON.stringify(dataForChecksum));
43022
43578
  return hash.digest("hex");
@@ -45760,7 +46316,7 @@ var IterateModeController = class {
45760
46316
  }
45761
46317
  });
45762
46318
  const responseContents = [];
45763
- let totalTokensUsed = { prompt: 0, completion: 0, total: 0 };
46319
+ const totalTokensUsed = { prompt: 0, completion: 0, total: 0 };
45764
46320
  let lastResponse;
45765
46321
  try {
45766
46322
  if (this.checkTimeBudget()) {
@@ -48039,7 +48595,7 @@ var runCommand = {
48039
48595
  }
48040
48596
  try {
48041
48597
  const workflowContent = readFileSync(workflowPath, "utf-8");
48042
- workflowConfig = yaml4__default.load(workflowContent);
48598
+ workflowConfig = yaml3__default.load(workflowContent);
48043
48599
  if (workflowConfig?.iterate?.enabled !== false) {
48044
48600
  argv.iterate = true;
48045
48601
  }
@@ -49260,7 +49816,7 @@ var statusCommand4 = {
49260
49816
  const agentCount = await countFiles(agentsDir, [".yaml", ".yml"]);
49261
49817
  const abilityCount = await countFiles(abilitiesDir, [".md"]);
49262
49818
  const projectInfo = await getProjectInfo(detectedProjectDir);
49263
- let limitData = {
49819
+ const limitData = {
49264
49820
  limits: [],
49265
49821
  manualOverride: null,
49266
49822
  envOverrides: []
@@ -49651,7 +50207,7 @@ function formatUptime2(seconds) {
49651
50207
  // src/cli/commands/update.ts
49652
50208
  init_esm_shims();
49653
50209
  init_logger();
49654
- var execAsync5 = promisify(exec);
50210
+ var execAsync6 = promisify(exec);
49655
50211
  var updateCommand = {
49656
50212
  command: "update",
49657
50213
  describe: "Check for updates and upgrade AutomatosX to the latest version",
@@ -49670,17 +50226,17 @@ var updateCommand = {
49670
50226
  handler: async (argv) => {
49671
50227
  console.log(chalk5.blue.bold("\n\u{1F504} AutomatosX Update Checker\n"));
49672
50228
  try {
49673
- const currentVersion = await getCurrentVersion();
50229
+ const currentVersion = await getCurrentVersion2();
49674
50230
  console.log(chalk5.gray(`Current version: ${currentVersion}`));
49675
50231
  console.log(chalk5.cyan("Checking for updates..."));
49676
- const latestVersion = await getLatestVersion();
50232
+ const latestVersion = await getLatestVersion2();
49677
50233
  console.log(chalk5.gray(`Latest version: ${latestVersion}
49678
50234
  `));
49679
50235
  if (currentVersion === latestVersion) {
49680
50236
  console.log(chalk5.green("\u2705 You are already running the latest version!\n"));
49681
50237
  return;
49682
50238
  }
49683
- if (isNewer(latestVersion, currentVersion)) {
50239
+ if (isNewer2(latestVersion, currentVersion)) {
49684
50240
  console.log(chalk5.yellow(`\u{1F4E6} New version available: ${currentVersion} \u2192 ${latestVersion}
49685
50241
  `));
49686
50242
  await showChangelog(currentVersion, latestVersion);
@@ -49725,28 +50281,28 @@ var updateCommand = {
49725
50281
  }
49726
50282
  }
49727
50283
  };
49728
- async function getCurrentVersion() {
50284
+ async function getCurrentVersion2() {
49729
50285
  try {
49730
- const { stdout } = await execAsync5("npm list -g @defai.digital/automatosx --depth=0 --json");
50286
+ const { stdout } = await execAsync6("npm list -g @defai.digital/automatosx --depth=0 --json");
49731
50287
  const result = JSON.parse(stdout);
49732
50288
  return result.dependencies["@defai.digital/automatosx"]?.version || "unknown";
49733
50289
  } catch (error) {
49734
50290
  const { readFile: readFile24 } = await import('fs/promises');
49735
- const { dirname: dirname18, join: join57 } = await import('path');
50291
+ const { dirname: dirname16, join: join57 } = await import('path');
49736
50292
  const { fileURLToPath: fileURLToPath5 } = await import('url');
49737
50293
  const __filename3 = fileURLToPath5(import.meta.url);
49738
- const __dirname4 = dirname18(__filename3);
50294
+ const __dirname4 = dirname16(__filename3);
49739
50295
  const pkgPath = join57(__dirname4, "../../../package.json");
49740
50296
  const content = await readFile24(pkgPath, "utf-8");
49741
50297
  const pkg = JSON.parse(content);
49742
50298
  return pkg.version;
49743
50299
  }
49744
50300
  }
49745
- async function getLatestVersion() {
49746
- const { stdout } = await execAsync5("npm view @defai.digital/automatosx version");
50301
+ async function getLatestVersion2() {
50302
+ const { stdout } = await execAsync6("npm view @defai.digital/automatosx version");
49747
50303
  return stdout.trim();
49748
50304
  }
49749
- function isNewer(a, b) {
50305
+ function isNewer2(a, b) {
49750
50306
  const stripPrerelease = (v) => v.split("-")[0] || v;
49751
50307
  const parseVersion = (v) => stripPrerelease(v).split(".").map(Number);
49752
50308
  const [aMajor = 0, aMinor = 0, aPatch = 0] = parseVersion(a);
@@ -49758,7 +50314,7 @@ function isNewer(a, b) {
49758
50314
  async function showChangelog(from, to) {
49759
50315
  try {
49760
50316
  console.log(chalk5.cyan("What's new:\n"));
49761
- const { stdout } = await execAsync5(
50317
+ const { stdout } = await execAsync6(
49762
50318
  `curl -s https://api.github.com/repos/defai-digital/automatosx/releases/tags/v${to}`
49763
50319
  );
49764
50320
  const release = JSON.parse(stdout);
@@ -49780,7 +50336,7 @@ async function showChangelog(from, to) {
49780
50336
  }
49781
50337
  async function installUpdate(version) {
49782
50338
  try {
49783
- const { stdout, stderr } = await execAsync5(
50339
+ const { stdout, stderr } = await execAsync6(
49784
50340
  `npm install -g @defai.digital/automatosx@${version}`,
49785
50341
  { maxBuffer: 10 * 1024 * 1024 }
49786
50342
  );
@@ -49938,6 +50494,7 @@ init_esm_shims();
49938
50494
  // src/cli/commands/agent/helpers.ts
49939
50495
  init_esm_shims();
49940
50496
  init_logger();
50497
+ var YAML_EXT_REGEX = /\.(yaml|yml)$/;
49941
50498
  var BUILTIN_TEMPLATE_METADATA = {
49942
50499
  "basic-agent": {
49943
50500
  name: "basic-agent",
@@ -49974,7 +50531,7 @@ async function listAvailableTemplates(baseDir) {
49974
50531
  const files = await readdir(projectTemplatesDir);
49975
50532
  for (const file of files) {
49976
50533
  if (extname$1(file) === ".yaml" || extname$1(file) === ".yml") {
49977
- const name = file.replace(/\.(yaml|yml)$/, "");
50534
+ const name = file.replace(YAML_EXT_REGEX, "");
49978
50535
  templates.push({
49979
50536
  name,
49980
50537
  path: join(projectTemplatesDir, file),
@@ -49993,7 +50550,7 @@ async function listAvailableTemplates(baseDir) {
49993
50550
  const files = await readdir(builtinTemplatesDir);
49994
50551
  for (const file of files) {
49995
50552
  if (extname$1(file) === ".yaml" || extname$1(file) === ".yml") {
49996
- const name = file.replace(/\.(yaml|yml)$/, "");
50553
+ const name = file.replace(YAML_EXT_REGEX, "");
49997
50554
  if (templates.find((t) => t.name === name)) {
49998
50555
  continue;
49999
50556
  }
@@ -52639,7 +53196,7 @@ var CommandTranslator = class {
52639
53196
  if (baseDir === void 0) {
52640
53197
  try {
52641
53198
  baseDir = await realpath$1(dir);
52642
- } catch (error) {
53199
+ } catch {
52643
53200
  return commands;
52644
53201
  }
52645
53202
  }
@@ -52657,7 +53214,7 @@ var CommandTranslator = class {
52657
53214
  let realPath;
52658
53215
  try {
52659
53216
  realPath = await realpath$1(fullPath);
52660
- } catch (error) {
53217
+ } catch {
52661
53218
  console.warn(`[Security] Cannot resolve path: ${fullPath}`);
52662
53219
  continue;
52663
53220
  }
@@ -52700,7 +53257,7 @@ var CommandTranslator = class {
52700
53257
  }
52701
53258
  }
52702
53259
  }
52703
- } catch (error) {
53260
+ } catch {
52704
53261
  }
52705
53262
  return commands;
52706
53263
  }
@@ -54013,7 +54570,7 @@ async function handleSpecExplain(workspacePath, options) {
54013
54570
  console.log(chalk5.blue.bold("\n\u{1F4D6} Spec-Kit: Explain Spec\n"));
54014
54571
  try {
54015
54572
  const specContent = readFileSync(options.file, "utf-8");
54016
- const spec = yaml4.load(specContent);
54573
+ const spec = yaml3.load(specContent);
54017
54574
  const validation = validateSpec(spec);
54018
54575
  if (!validation.valid) {
54019
54576
  console.error(chalk5.red("\n\u2717 Spec validation failed:\n"));
@@ -56115,7 +56672,7 @@ async function handleGenPlan(specFile, argv) {
56115
56672
  process.exit(1);
56116
56673
  }
56117
56674
  const specContent = readFileSync(specFile, "utf-8");
56118
- const spec = yaml4.load(specContent);
56675
+ const spec = yaml3.load(specContent);
56119
56676
  const validation = validateSpec(spec);
56120
56677
  if (!validation.valid) {
56121
56678
  spinner.fail("Spec validation failed");
@@ -56173,7 +56730,7 @@ async function handleGenDag(specFile, argv) {
56173
56730
  process.exit(1);
56174
56731
  }
56175
56732
  const specContent = readFileSync(specFile, "utf-8");
56176
- const spec = yaml4.load(specContent);
56733
+ const spec = yaml3.load(specContent);
56177
56734
  const validation = validateSpec(spec);
56178
56735
  if (!validation.valid) {
56179
56736
  spinner.fail("Spec validation failed");
@@ -56260,7 +56817,7 @@ async function handleGenScaffold(specFile, argv) {
56260
56817
  process.exit(1);
56261
56818
  }
56262
56819
  const specContent = readFileSync(specFile, "utf-8");
56263
- const spec = yaml4.load(specContent);
56820
+ const spec = yaml3.load(specContent);
56264
56821
  const validation = validateSpec(spec);
56265
56822
  if (!validation.valid) {
56266
56823
  spinner.fail("Spec validation failed");
@@ -56332,7 +56889,7 @@ async function handleGenTests(specFile, argv) {
56332
56889
  process.exit(1);
56333
56890
  }
56334
56891
  const specContent = readFileSync(specFile, "utf-8");
56335
- const spec = yaml4.load(specContent);
56892
+ const spec = yaml3.load(specContent);
56336
56893
  const validation = validateSpec(spec);
56337
56894
  if (!validation.valid) {
56338
56895
  spinner.fail("Spec validation failed");
@@ -56567,7 +57124,7 @@ async function handleList(config, argv) {
56567
57124
  });
56568
57125
  }
56569
57126
  }
56570
- let displayProviders2 = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
57127
+ const displayProviders2 = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
56571
57128
  switch (argv.sort) {
56572
57129
  case "cost":
56573
57130
  displayProviders2.sort((a, b) => {
@@ -58210,8 +58767,8 @@ async function runMcpDiagnostics(verbose) {
58210
58767
  let serverStarts = false;
58211
58768
  if (cliAvailable) {
58212
58769
  try {
58213
- const { spawn: spawn12 } = await import('child_process');
58214
- const proc = spawn12("automatosx", ["mcp", "server"], { stdio: ["pipe", "pipe", "pipe"] });
58770
+ const { spawn: spawn13 } = await import('child_process');
58771
+ const proc = spawn13("automatosx", ["mcp", "server"], { stdio: ["pipe", "pipe", "pipe"] });
58215
58772
  const initResult = await new Promise((resolve13) => {
58216
58773
  let output = "";
58217
58774
  proc.stderr?.on("data", (data) => {
@@ -58311,7 +58868,7 @@ async function runMcpDiagnostics(verbose) {
58311
58868
  init_esm_shims();
58312
58869
  init_logger();
58313
58870
  init_safe_timers();
58314
- var execAsync6 = promisify(exec);
58871
+ var execAsync7 = promisify(exec);
58315
58872
  var cleanupCommand2 = {
58316
58873
  command: "cleanup [provider]",
58317
58874
  describe: "Clean up orphaned provider processes (v6.0.7 Phase 3)",
@@ -58440,7 +58997,7 @@ async function findProcesses(processName, verbose) {
58440
58997
  throw new Error(`Invalid process name: ${processName}. Only alphanumeric characters, dashes, and underscores are allowed.`);
58441
58998
  }
58442
58999
  try {
58443
- const { stdout } = await execAsync6("ps -eo pid,comm,etime,rss");
59000
+ const { stdout } = await execAsync7("ps -eo pid,comm,etime,rss");
58444
59001
  if (!stdout.trim()) {
58445
59002
  return processes;
58446
59003
  }
@@ -62922,10 +63479,10 @@ init_esm_shims();
62922
63479
  // src/core/bugfix/git-utils.ts
62923
63480
  init_esm_shims();
62924
63481
  init_logger();
62925
- var execAsync7 = promisify(exec);
63482
+ var execAsync8 = promisify(exec);
62926
63483
  async function isGitRepo(cwd) {
62927
63484
  try {
62928
- await execAsync7("git rev-parse --is-inside-work-tree", { cwd });
63485
+ await execAsync8("git rev-parse --is-inside-work-tree", { cwd });
62929
63486
  return true;
62930
63487
  } catch {
62931
63488
  return false;
@@ -62943,14 +63500,14 @@ async function getChangedFiles(options) {
62943
63500
  command = "git diff --cached --name-only --diff-filter=ACMR";
62944
63501
  } else if (options.since) {
62945
63502
  const mergeBaseCmd = `git merge-base HEAD ${options.since}`;
62946
- const { stdout: mergeBase } = await execAsync7(mergeBaseCmd, { cwd });
63503
+ const { stdout: mergeBase } = await execAsync8(mergeBaseCmd, { cwd });
62947
63504
  command = `git diff --name-only ${mergeBase.trim()}..HEAD`;
62948
63505
  } else if (options.changed) {
62949
63506
  command = "git diff --name-only HEAD";
62950
63507
  } else {
62951
63508
  command = "git diff --name-only HEAD";
62952
63509
  }
62953
- const { stdout } = await execAsync7(command, { cwd });
63510
+ const { stdout } = await execAsync8(command, { cwd });
62954
63511
  const files = stdout.split("\n").map((f) => f.trim()).filter((f) => f.length > 0);
62955
63512
  logger.debug("Git changed files", {
62956
63513
  command,