@defai.digital/automatosx 12.6.1 → 12.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +2001 -1392
- package/dist/mcp/index.js +1277 -371
- package/package.json +1 -1
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,
|
|
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
|
|
24
|
-
import
|
|
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
|
|
|
@@ -1418,6 +1417,119 @@ var init_path_resolver = __esm({
|
|
|
1418
1417
|
}
|
|
1419
1418
|
});
|
|
1420
1419
|
|
|
1420
|
+
// src/shared/utils/safe-timers.ts
|
|
1421
|
+
function createSafeInterval(callback, intervalMs, options = {}) {
|
|
1422
|
+
const { ref = false, name, signal, immediate = false } = options;
|
|
1423
|
+
if (signal?.aborted) {
|
|
1424
|
+
logger.debug("createSafeInterval: already aborted", { name });
|
|
1425
|
+
return () => {
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
let cleared = false;
|
|
1429
|
+
let intervalId = null;
|
|
1430
|
+
const safeCallback = async () => {
|
|
1431
|
+
if (cleared) return;
|
|
1432
|
+
try {
|
|
1433
|
+
await callback();
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
logger.error("Safe interval callback error", {
|
|
1436
|
+
name,
|
|
1437
|
+
error: error.message
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
if (immediate) {
|
|
1442
|
+
setImmediate(() => {
|
|
1443
|
+
if (!cleared) {
|
|
1444
|
+
safeCallback();
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
intervalId = setInterval(safeCallback, intervalMs);
|
|
1449
|
+
if (!ref && intervalId.unref) {
|
|
1450
|
+
intervalId.unref();
|
|
1451
|
+
}
|
|
1452
|
+
const cleanup = () => {
|
|
1453
|
+
if (cleared) return;
|
|
1454
|
+
cleared = true;
|
|
1455
|
+
if (intervalId !== null) {
|
|
1456
|
+
clearInterval(intervalId);
|
|
1457
|
+
intervalId = null;
|
|
1458
|
+
logger.debug("Safe interval cleared", { name });
|
|
1459
|
+
}
|
|
1460
|
+
};
|
|
1461
|
+
if (signal) {
|
|
1462
|
+
signal.addEventListener("abort", cleanup, { once: true });
|
|
1463
|
+
}
|
|
1464
|
+
logger.debug("Safe interval created", {
|
|
1465
|
+
name,
|
|
1466
|
+
intervalMs,
|
|
1467
|
+
ref,
|
|
1468
|
+
immediate
|
|
1469
|
+
});
|
|
1470
|
+
return cleanup;
|
|
1471
|
+
}
|
|
1472
|
+
function createSafeTimeout(callback, delayMs, options = {}) {
|
|
1473
|
+
const { ref = false, name, signal } = options;
|
|
1474
|
+
if (signal?.aborted) {
|
|
1475
|
+
logger.debug("createSafeTimeout: already aborted", { name });
|
|
1476
|
+
return () => {
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
let cleared = false;
|
|
1480
|
+
let timeoutId = null;
|
|
1481
|
+
const safeCallback = async () => {
|
|
1482
|
+
if (cleared) return;
|
|
1483
|
+
cleared = true;
|
|
1484
|
+
try {
|
|
1485
|
+
await callback();
|
|
1486
|
+
} catch (error) {
|
|
1487
|
+
logger.error("Safe timeout callback error", {
|
|
1488
|
+
name,
|
|
1489
|
+
error: error.message
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
timeoutId = setTimeout(safeCallback, delayMs);
|
|
1494
|
+
if (!ref && timeoutId.unref) {
|
|
1495
|
+
timeoutId.unref();
|
|
1496
|
+
}
|
|
1497
|
+
const cleanup = () => {
|
|
1498
|
+
if (cleared) return;
|
|
1499
|
+
cleared = true;
|
|
1500
|
+
if (timeoutId !== null) {
|
|
1501
|
+
clearTimeout(timeoutId);
|
|
1502
|
+
timeoutId = null;
|
|
1503
|
+
logger.debug("Safe timeout cleared", { name });
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
if (signal) {
|
|
1507
|
+
signal.addEventListener("abort", cleanup, { once: true });
|
|
1508
|
+
}
|
|
1509
|
+
logger.debug("Safe timeout created", {
|
|
1510
|
+
name,
|
|
1511
|
+
delayMs,
|
|
1512
|
+
ref
|
|
1513
|
+
});
|
|
1514
|
+
return cleanup;
|
|
1515
|
+
}
|
|
1516
|
+
async function sleep(ms, signal) {
|
|
1517
|
+
return new Promise((resolve13, reject) => {
|
|
1518
|
+
const timeoutId = setTimeout(() => {
|
|
1519
|
+
resolve13();
|
|
1520
|
+
}, ms);
|
|
1521
|
+
if (timeoutId.unref) {
|
|
1522
|
+
timeoutId.unref();
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
var init_safe_timers = __esm({
|
|
1527
|
+
"src/shared/utils/safe-timers.ts"() {
|
|
1528
|
+
init_esm_shims();
|
|
1529
|
+
init_logger();
|
|
1530
|
+
}
|
|
1531
|
+
});
|
|
1532
|
+
|
|
1421
1533
|
// src/core/workspace-indexer.ts
|
|
1422
1534
|
var workspace_indexer_exports = {};
|
|
1423
1535
|
__export(workspace_indexer_exports, {
|
|
@@ -2635,6 +2747,7 @@ function getRetryableErrors(provider) {
|
|
|
2635
2747
|
return [...baseErrors, ...CODEX_RETRYABLE_ERRORS];
|
|
2636
2748
|
case "glm":
|
|
2637
2749
|
case "grok":
|
|
2750
|
+
case "qwen":
|
|
2638
2751
|
return [...baseErrors, ...OPENAI_RETRYABLE_ERRORS];
|
|
2639
2752
|
case "base":
|
|
2640
2753
|
default:
|
|
@@ -2737,6 +2850,10 @@ var init_base_provider = __esm({
|
|
|
2737
2850
|
// v12.0.0: Native Grok provider (xAI)
|
|
2738
2851
|
"ax-grok",
|
|
2739
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
|
|
2740
2857
|
"test-provider"
|
|
2741
2858
|
// For unit tests
|
|
2742
2859
|
];
|
|
@@ -3099,7 +3216,7 @@ var init_base_provider = __esm({
|
|
|
3099
3216
|
if (readlineInterface) {
|
|
3100
3217
|
try {
|
|
3101
3218
|
readlineInterface.close();
|
|
3102
|
-
} catch
|
|
3219
|
+
} catch {
|
|
3103
3220
|
} finally {
|
|
3104
3221
|
readlineInterface = null;
|
|
3105
3222
|
}
|
|
@@ -3107,7 +3224,7 @@ var init_base_provider = __esm({
|
|
|
3107
3224
|
if (stderrInterface) {
|
|
3108
3225
|
try {
|
|
3109
3226
|
stderrInterface.close();
|
|
3110
|
-
} catch
|
|
3227
|
+
} catch {
|
|
3111
3228
|
} finally {
|
|
3112
3229
|
stderrInterface = null;
|
|
3113
3230
|
}
|
|
@@ -3301,7 +3418,7 @@ ${fullPrompt}
|
|
|
3301
3418
|
this.health.consecutiveSuccesses = 0;
|
|
3302
3419
|
}
|
|
3303
3420
|
return available;
|
|
3304
|
-
} catch
|
|
3421
|
+
} catch {
|
|
3305
3422
|
this.health.available = false;
|
|
3306
3423
|
this.health.errorRate = 1;
|
|
3307
3424
|
this.health.lastCheck = Date.now();
|
|
@@ -3477,6 +3594,8 @@ ${fullPrompt}
|
|
|
3477
3594
|
retryableProvider = "glm";
|
|
3478
3595
|
} else if (providerName === "grok" || providerName === "ax-grok") {
|
|
3479
3596
|
retryableProvider = "grok";
|
|
3597
|
+
} else if (providerName === "qwen" || providerName === "qwen-code") {
|
|
3598
|
+
retryableProvider = "qwen";
|
|
3480
3599
|
}
|
|
3481
3600
|
return shouldRetryError(error, retryableProvider);
|
|
3482
3601
|
}
|
|
@@ -5551,6 +5670,7 @@ var init_hybrid_adapter_base = __esm({
|
|
|
5551
5670
|
init_flags();
|
|
5552
5671
|
init_fallback_decision();
|
|
5553
5672
|
init_provider_metrics();
|
|
5673
|
+
init_safe_timers();
|
|
5554
5674
|
DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
5555
5675
|
failureThreshold: 3,
|
|
5556
5676
|
resetTimeout: 6e4,
|
|
@@ -5705,7 +5825,7 @@ var init_hybrid_adapter_base = __esm({
|
|
|
5705
5825
|
});
|
|
5706
5826
|
if (classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt < this.maxRetries) {
|
|
5707
5827
|
const delay = classification.retryDelayMs || 1e3;
|
|
5708
|
-
await
|
|
5828
|
+
await sleep(delay);
|
|
5709
5829
|
continue;
|
|
5710
5830
|
}
|
|
5711
5831
|
if (classification.decision === "use_cli" /* USE_CLI */ || classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt >= this.maxRetries) {
|
|
@@ -5880,12 +6000,6 @@ var init_hybrid_adapter_base = __esm({
|
|
|
5880
6000
|
} catch {
|
|
5881
6001
|
}
|
|
5882
6002
|
}
|
|
5883
|
-
/**
|
|
5884
|
-
* Sleep utility
|
|
5885
|
-
*/
|
|
5886
|
-
sleep(ms) {
|
|
5887
|
-
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
5888
|
-
}
|
|
5889
6003
|
/**
|
|
5890
6004
|
* Get current active mode
|
|
5891
6005
|
*/
|
|
@@ -5936,13 +6050,21 @@ var init_types2 = __esm({
|
|
|
5936
6050
|
"src/integrations/ax-glm/types.ts"() {
|
|
5937
6051
|
init_esm_shims();
|
|
5938
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)
|
|
5939
6059
|
"glm-4-plus": "glm-4.6",
|
|
5940
|
-
"glm-
|
|
6060
|
+
"glm-4.5v": "glm-4.6v",
|
|
6061
|
+
"glm-4v": "glm-4.6v",
|
|
6062
|
+
"glm-4": "glm-4.6",
|
|
5941
6063
|
"glm-4-air": "glm-4-flash",
|
|
5942
6064
|
"glm-4-airx": "glm-4-flash"
|
|
5943
6065
|
};
|
|
5944
6066
|
GLM_DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
5945
|
-
GLM_DEFAULT_MODEL = "glm-4";
|
|
6067
|
+
GLM_DEFAULT_MODEL = "glm-4.6";
|
|
5946
6068
|
GLM_DEFAULT_COMMAND = "ax-glm";
|
|
5947
6069
|
}
|
|
5948
6070
|
});
|
|
@@ -6098,14 +6220,14 @@ var init_sdk_adapter2 = __esm({
|
|
|
6098
6220
|
};
|
|
6099
6221
|
}
|
|
6100
6222
|
});
|
|
6101
|
-
var
|
|
6223
|
+
var execAsync4, GLMCliWrapper;
|
|
6102
6224
|
var init_cli_wrapper2 = __esm({
|
|
6103
6225
|
"src/integrations/ax-glm/cli-wrapper.ts"() {
|
|
6104
6226
|
init_esm_shims();
|
|
6105
6227
|
init_logger();
|
|
6106
6228
|
init_validation_limits();
|
|
6107
6229
|
init_types2();
|
|
6108
|
-
|
|
6230
|
+
execAsync4 = promisify(exec);
|
|
6109
6231
|
GLMCliWrapper = class {
|
|
6110
6232
|
config;
|
|
6111
6233
|
cliPath = null;
|
|
@@ -6126,13 +6248,13 @@ var init_cli_wrapper2 = __esm({
|
|
|
6126
6248
|
*/
|
|
6127
6249
|
async isAvailable() {
|
|
6128
6250
|
try {
|
|
6129
|
-
const { stdout } = await
|
|
6251
|
+
const { stdout } = await execAsync4(`which ${this.config.command}`, {
|
|
6130
6252
|
timeout: TIMEOUTS.PROVIDER_DETECTION
|
|
6131
6253
|
});
|
|
6132
6254
|
this.cliPath = stdout.trim();
|
|
6133
6255
|
if (this.cliPath) {
|
|
6134
6256
|
try {
|
|
6135
|
-
const { stdout: versionOutput } = await
|
|
6257
|
+
const { stdout: versionOutput } = await execAsync4(
|
|
6136
6258
|
`${this.config.command} --version`,
|
|
6137
6259
|
{ timeout: TIMEOUTS.PROVIDER_DETECTION }
|
|
6138
6260
|
);
|
|
@@ -6481,6 +6603,7 @@ var init_sdk_only_adapter = __esm({
|
|
|
6481
6603
|
"src/integrations/ax-glm/sdk-only-adapter.ts"() {
|
|
6482
6604
|
init_esm_shims();
|
|
6483
6605
|
init_logger();
|
|
6606
|
+
init_safe_timers();
|
|
6484
6607
|
init_sdk_adapter2();
|
|
6485
6608
|
init_types2();
|
|
6486
6609
|
GLMSdkOnlyAdapter = class {
|
|
@@ -6560,7 +6683,7 @@ var init_sdk_only_adapter = __esm({
|
|
|
6560
6683
|
attempt: attempt + 1,
|
|
6561
6684
|
delayMs: delay
|
|
6562
6685
|
});
|
|
6563
|
-
await
|
|
6686
|
+
await sleep(delay);
|
|
6564
6687
|
continue;
|
|
6565
6688
|
}
|
|
6566
6689
|
break;
|
|
@@ -6596,12 +6719,6 @@ var init_sdk_only_adapter = __esm({
|
|
|
6596
6719
|
}
|
|
6597
6720
|
return false;
|
|
6598
6721
|
}
|
|
6599
|
-
/**
|
|
6600
|
-
* Sleep utility
|
|
6601
|
-
*/
|
|
6602
|
-
sleep(ms) {
|
|
6603
|
-
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
6604
|
-
}
|
|
6605
6722
|
/**
|
|
6606
6723
|
* Get the configured model
|
|
6607
6724
|
*/
|
|
@@ -6896,10 +7013,18 @@ var init_types3 = __esm({
|
|
|
6896
7013
|
"src/integrations/ax-grok/types.ts"() {
|
|
6897
7014
|
init_esm_shims();
|
|
6898
7015
|
GROK_MODEL_MAPPING = {
|
|
6899
|
-
|
|
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"
|
|
6900
7025
|
};
|
|
6901
7026
|
GROK_DEFAULT_BASE_URL = "https://api.x.ai/v1";
|
|
6902
|
-
GROK_DEFAULT_MODEL = "grok-
|
|
7027
|
+
GROK_DEFAULT_MODEL = "grok-4-0709";
|
|
6903
7028
|
GROK_DEFAULT_COMMAND = "ax-grok";
|
|
6904
7029
|
}
|
|
6905
7030
|
});
|
|
@@ -7055,14 +7180,14 @@ var init_sdk_adapter3 = __esm({
|
|
|
7055
7180
|
};
|
|
7056
7181
|
}
|
|
7057
7182
|
});
|
|
7058
|
-
var
|
|
7183
|
+
var execAsync5, GrokCliWrapper;
|
|
7059
7184
|
var init_cli_wrapper3 = __esm({
|
|
7060
7185
|
"src/integrations/ax-grok/cli-wrapper.ts"() {
|
|
7061
7186
|
init_esm_shims();
|
|
7062
7187
|
init_logger();
|
|
7063
7188
|
init_validation_limits();
|
|
7064
7189
|
init_types3();
|
|
7065
|
-
|
|
7190
|
+
execAsync5 = promisify(exec);
|
|
7066
7191
|
GrokCliWrapper = class {
|
|
7067
7192
|
config;
|
|
7068
7193
|
cliPath = null;
|
|
@@ -7083,13 +7208,13 @@ var init_cli_wrapper3 = __esm({
|
|
|
7083
7208
|
*/
|
|
7084
7209
|
async isAvailable() {
|
|
7085
7210
|
try {
|
|
7086
|
-
const { stdout } = await
|
|
7211
|
+
const { stdout } = await execAsync5(`which ${this.config.command}`, {
|
|
7087
7212
|
timeout: TIMEOUTS.PROVIDER_DETECTION
|
|
7088
7213
|
});
|
|
7089
7214
|
this.cliPath = stdout.trim();
|
|
7090
7215
|
if (this.cliPath) {
|
|
7091
7216
|
try {
|
|
7092
|
-
const { stdout: versionOutput } = await
|
|
7217
|
+
const { stdout: versionOutput } = await execAsync5(
|
|
7093
7218
|
`${this.config.command} --version`,
|
|
7094
7219
|
{ timeout: TIMEOUTS.PROVIDER_DETECTION }
|
|
7095
7220
|
);
|
|
@@ -7438,6 +7563,7 @@ var init_sdk_only_adapter2 = __esm({
|
|
|
7438
7563
|
"src/integrations/ax-grok/sdk-only-adapter.ts"() {
|
|
7439
7564
|
init_esm_shims();
|
|
7440
7565
|
init_logger();
|
|
7566
|
+
init_safe_timers();
|
|
7441
7567
|
init_sdk_adapter3();
|
|
7442
7568
|
init_types3();
|
|
7443
7569
|
GrokSdkOnlyAdapter = class {
|
|
@@ -7517,7 +7643,7 @@ var init_sdk_only_adapter2 = __esm({
|
|
|
7517
7643
|
attempt: attempt + 1,
|
|
7518
7644
|
delayMs: delay
|
|
7519
7645
|
});
|
|
7520
|
-
await
|
|
7646
|
+
await sleep(delay);
|
|
7521
7647
|
continue;
|
|
7522
7648
|
}
|
|
7523
7649
|
break;
|
|
@@ -7553,12 +7679,6 @@ var init_sdk_only_adapter2 = __esm({
|
|
|
7553
7679
|
}
|
|
7554
7680
|
return false;
|
|
7555
7681
|
}
|
|
7556
|
-
/**
|
|
7557
|
-
* Sleep utility
|
|
7558
|
-
*/
|
|
7559
|
-
sleep(ms) {
|
|
7560
|
-
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
7561
|
-
}
|
|
7562
7682
|
/**
|
|
7563
7683
|
* Get the configured model
|
|
7564
7684
|
*/
|
|
@@ -7836,6 +7956,902 @@ Mode: ${this.grokConfig.mode || "auto"}`;
|
|
|
7836
7956
|
}
|
|
7837
7957
|
});
|
|
7838
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
|
+
|
|
7839
8855
|
// src/cli/index.ts
|
|
7840
8856
|
init_esm_shims();
|
|
7841
8857
|
init_logger();
|
|
@@ -8736,12 +9752,16 @@ init_logger();
|
|
|
8736
9752
|
|
|
8737
9753
|
// src/shared/helpers/deep-merge.ts
|
|
8738
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
|
+
}
|
|
8739
9758
|
function deepMerge(defaults, user) {
|
|
8740
9759
|
if (user === null || user === void 0) {
|
|
8741
|
-
return defaults;
|
|
9760
|
+
return { ...defaults };
|
|
8742
9761
|
}
|
|
8743
|
-
const result = {
|
|
8744
|
-
|
|
9762
|
+
const result = Object.assign({}, defaults);
|
|
9763
|
+
const userKeys = Object.keys(user);
|
|
9764
|
+
for (const key of userKeys) {
|
|
8745
9765
|
const userValue = user[key];
|
|
8746
9766
|
if (userValue === null) {
|
|
8747
9767
|
result[key] = void 0;
|
|
@@ -8751,8 +9771,11 @@ function deepMerge(defaults, user) {
|
|
|
8751
9771
|
continue;
|
|
8752
9772
|
}
|
|
8753
9773
|
const defaultValue = defaults[key];
|
|
8754
|
-
if (
|
|
8755
|
-
result[key] = deepMerge(
|
|
9774
|
+
if (isPlainObject(userValue) && isPlainObject(defaultValue)) {
|
|
9775
|
+
result[key] = deepMerge(
|
|
9776
|
+
defaultValue,
|
|
9777
|
+
userValue
|
|
9778
|
+
);
|
|
8756
9779
|
} else {
|
|
8757
9780
|
result[key] = userValue;
|
|
8758
9781
|
}
|
|
@@ -9394,7 +10417,7 @@ var PRECOMPILED_CONFIG = {
|
|
|
9394
10417
|
"enableFreeTierPrioritization": true,
|
|
9395
10418
|
"enableWorkloadAwareRouting": true
|
|
9396
10419
|
},
|
|
9397
|
-
"version": "12.6.
|
|
10420
|
+
"version": "12.6.3"
|
|
9398
10421
|
};
|
|
9399
10422
|
|
|
9400
10423
|
// src/core/config/schemas.ts
|
|
@@ -12417,7 +13440,11 @@ var ProfileLoader = class {
|
|
|
12417
13440
|
continue;
|
|
12418
13441
|
}
|
|
12419
13442
|
const data = load(content);
|
|
12420
|
-
|
|
13443
|
+
if (data && typeof data === "object" && !Array.isArray(data) && "displayName" in data) {
|
|
13444
|
+
const profile = data;
|
|
13445
|
+
return profile.displayName ?? null;
|
|
13446
|
+
}
|
|
13447
|
+
return null;
|
|
12421
13448
|
} catch (error) {
|
|
12422
13449
|
if (error.code === "ENOENT") {
|
|
12423
13450
|
continue;
|
|
@@ -12446,7 +13473,7 @@ var ProfileLoader = class {
|
|
|
12446
13473
|
});
|
|
12447
13474
|
return identifier;
|
|
12448
13475
|
} catch (error) {
|
|
12449
|
-
if (error.name === "AgentNotFoundError") {
|
|
13476
|
+
if (error instanceof Error && error.name === "AgentNotFoundError") {
|
|
12450
13477
|
logger.debug("Direct profile load failed, trying displayName lookup", { identifier });
|
|
12451
13478
|
await this.buildDisplayNameMap();
|
|
12452
13479
|
const resolved = this.displayNameMap.get(identifier.toLowerCase());
|
|
@@ -12775,7 +13802,7 @@ var ProfileLoader = class {
|
|
|
12775
13802
|
if (typeof orch !== "object" || orch === null || Array.isArray(orch)) {
|
|
12776
13803
|
throw new AgentValidationError("orchestration must be an object");
|
|
12777
13804
|
}
|
|
12778
|
-
if (orch.canDelegate !== void 0) {
|
|
13805
|
+
if ("canDelegate" in orch && orch.canDelegate !== void 0) {
|
|
12779
13806
|
logger.warn("orchestration.canDelegate is deprecated and ignored (v4.9.0+). All agents can delegate by default.", {
|
|
12780
13807
|
agent: profile.name
|
|
12781
13808
|
});
|
|
@@ -12821,17 +13848,18 @@ var ProfileLoader = class {
|
|
|
12821
13848
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
12822
13849
|
throw new AgentValidationError(`Invalid profile data for ${name}: expected object, got ${typeof data}`);
|
|
12823
13850
|
}
|
|
12824
|
-
|
|
12825
|
-
|
|
12826
|
-
|
|
12827
|
-
|
|
13851
|
+
const profileData = data;
|
|
13852
|
+
if (profileData.name && typeof profileData.name === "string") {
|
|
13853
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(profileData.name)) {
|
|
13854
|
+
if (!profileData.displayName) {
|
|
13855
|
+
profileData.displayName = profileData.name;
|
|
12828
13856
|
}
|
|
12829
|
-
|
|
13857
|
+
profileData.name = name;
|
|
12830
13858
|
}
|
|
12831
|
-
} else if (!
|
|
12832
|
-
|
|
13859
|
+
} else if (!profileData.name) {
|
|
13860
|
+
profileData.name = name;
|
|
12833
13861
|
}
|
|
12834
|
-
const validationResult = safeValidateAgentProfile(
|
|
13862
|
+
const validationResult = safeValidateAgentProfile(profileData);
|
|
12835
13863
|
if (!validationResult.success) {
|
|
12836
13864
|
const validationErrors = validationResult.error.issues.map(
|
|
12837
13865
|
(e) => `${e.path.join(".")}: ${e.message}`
|
|
@@ -12841,22 +13869,22 @@ var ProfileLoader = class {
|
|
|
12841
13869
|
);
|
|
12842
13870
|
}
|
|
12843
13871
|
let teamConfig;
|
|
12844
|
-
if (
|
|
13872
|
+
if (profileData.team && this.teamManager) {
|
|
12845
13873
|
try {
|
|
12846
|
-
teamConfig = await this.teamManager.loadTeam(
|
|
13874
|
+
teamConfig = await this.teamManager.loadTeam(profileData.team);
|
|
12847
13875
|
logger.debug("Team configuration loaded for agent", {
|
|
12848
13876
|
agent: name,
|
|
12849
|
-
team:
|
|
13877
|
+
team: profileData.team
|
|
12850
13878
|
});
|
|
12851
13879
|
} catch (error) {
|
|
12852
13880
|
logger.warn("Failed to load team configuration, using agent defaults", {
|
|
12853
13881
|
agent: name,
|
|
12854
|
-
team:
|
|
13882
|
+
team: profileData.team,
|
|
12855
13883
|
error: error.message
|
|
12856
13884
|
});
|
|
12857
13885
|
}
|
|
12858
13886
|
}
|
|
12859
|
-
const abilities =
|
|
13887
|
+
const abilities = profileData.abilities || [];
|
|
12860
13888
|
if (teamConfig?.sharedAbilities) {
|
|
12861
13889
|
const allAbilities = [.../* @__PURE__ */ new Set([...teamConfig.sharedAbilities, ...abilities])];
|
|
12862
13890
|
logger.debug("Merged abilities from team", {
|
|
@@ -12868,7 +13896,7 @@ var ProfileLoader = class {
|
|
|
12868
13896
|
});
|
|
12869
13897
|
abilities.splice(0, abilities.length, ...allAbilities);
|
|
12870
13898
|
}
|
|
12871
|
-
let orchestration =
|
|
13899
|
+
let orchestration = profileData.orchestration;
|
|
12872
13900
|
if (teamConfig?.orchestration && !orchestration) {
|
|
12873
13901
|
orchestration = teamConfig.orchestration;
|
|
12874
13902
|
logger.debug("Using team orchestration defaults", {
|
|
@@ -12877,32 +13905,32 @@ var ProfileLoader = class {
|
|
|
12877
13905
|
});
|
|
12878
13906
|
}
|
|
12879
13907
|
const profile = {
|
|
12880
|
-
name:
|
|
12881
|
-
displayName:
|
|
12882
|
-
role:
|
|
12883
|
-
description:
|
|
13908
|
+
name: profileData.name || name,
|
|
13909
|
+
displayName: profileData.displayName,
|
|
13910
|
+
role: profileData.role,
|
|
13911
|
+
description: profileData.description,
|
|
12884
13912
|
// v4.10.0+: Team field
|
|
12885
|
-
team:
|
|
12886
|
-
systemPrompt:
|
|
13913
|
+
team: profileData.team,
|
|
13914
|
+
systemPrompt: profileData.systemPrompt,
|
|
12887
13915
|
abilities,
|
|
12888
|
-
dependencies:
|
|
12889
|
-
parallel:
|
|
13916
|
+
dependencies: profileData.dependencies,
|
|
13917
|
+
parallel: profileData.parallel,
|
|
12890
13918
|
// Enhanced v4.1+ features
|
|
12891
|
-
stages:
|
|
12892
|
-
personality:
|
|
12893
|
-
thinking_patterns:
|
|
12894
|
-
abilitySelection:
|
|
13919
|
+
stages: profileData.stages,
|
|
13920
|
+
personality: profileData.personality,
|
|
13921
|
+
thinking_patterns: profileData.thinking_patterns,
|
|
13922
|
+
abilitySelection: profileData.abilitySelection,
|
|
12895
13923
|
// v5.7.0+: Agent Selection Metadata
|
|
12896
|
-
selectionMetadata:
|
|
13924
|
+
selectionMetadata: profileData.selectionMetadata,
|
|
12897
13925
|
// Provider preferences (deprecated, kept for backward compatibility)
|
|
12898
|
-
provider:
|
|
12899
|
-
model:
|
|
12900
|
-
temperature:
|
|
12901
|
-
maxTokens:
|
|
13926
|
+
provider: profileData.provider,
|
|
13927
|
+
model: profileData.model,
|
|
13928
|
+
temperature: profileData.temperature,
|
|
13929
|
+
maxTokens: profileData.maxTokens,
|
|
12902
13930
|
// Optional
|
|
12903
|
-
tags:
|
|
12904
|
-
version:
|
|
12905
|
-
metadata:
|
|
13931
|
+
tags: profileData.tags,
|
|
13932
|
+
version: profileData.version,
|
|
13933
|
+
metadata: profileData.metadata,
|
|
12906
13934
|
// v4.7.0+ Orchestration (merged with team defaults)
|
|
12907
13935
|
orchestration
|
|
12908
13936
|
};
|
|
@@ -13160,14 +14188,17 @@ init_validation_limits();
|
|
|
13160
14188
|
var execAsync2 = promisify(exec);
|
|
13161
14189
|
var ProviderDetector = class _ProviderDetector {
|
|
13162
14190
|
// v12.0.0: Removed ax-cli, added glm/grok (SDK-first providers)
|
|
14191
|
+
// v12.7.0: Added qwen (SDK-first with CLI fallback)
|
|
13163
14192
|
static PROVIDER_COMMANDS = {
|
|
13164
14193
|
"claude-code": "claude",
|
|
13165
14194
|
"gemini-cli": "gemini",
|
|
13166
14195
|
"codex": "codex",
|
|
13167
14196
|
"glm": "glm",
|
|
13168
14197
|
// v12.0.0: Native GLM provider (SDK-first)
|
|
13169
|
-
"grok": "grok"
|
|
14198
|
+
"grok": "grok",
|
|
13170
14199
|
// v12.0.0: Native Grok provider (SDK-first)
|
|
14200
|
+
"qwen": "qwen"
|
|
14201
|
+
// v12.7.0: Qwen Code provider (SDK-first with CLI fallback)
|
|
13171
14202
|
};
|
|
13172
14203
|
/**
|
|
13173
14204
|
* Detect all supported AI provider CLIs
|
|
@@ -13192,16 +14223,22 @@ var ProviderDetector = class _ProviderDetector {
|
|
|
13192
14223
|
const results = await Promise.all([
|
|
13193
14224
|
this.isCommandAvailable("claude-code"),
|
|
13194
14225
|
this.isCommandAvailable("gemini-cli"),
|
|
13195
|
-
this.isCommandAvailable("codex")
|
|
14226
|
+
this.isCommandAvailable("codex"),
|
|
14227
|
+
this.isCommandAvailable("qwen")
|
|
13196
14228
|
]);
|
|
14229
|
+
const qwenApiKeySet = !!(process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY);
|
|
14230
|
+
const qwenCliAvailable = results[3];
|
|
14231
|
+
const qwenAvailable = qwenApiKeySet || qwenCliAvailable;
|
|
13197
14232
|
const detected = {
|
|
13198
14233
|
"claude-code": results[0],
|
|
13199
14234
|
"gemini-cli": results[1],
|
|
13200
14235
|
"codex": results[2],
|
|
13201
14236
|
"glm": true,
|
|
13202
14237
|
// SDK-first: always available via SDK
|
|
13203
|
-
"grok": true
|
|
14238
|
+
"grok": true,
|
|
13204
14239
|
// SDK-first: always available via SDK
|
|
14240
|
+
"qwen": qwenAvailable
|
|
14241
|
+
// v12.7.0: SDK-first with CLI fallback
|
|
13205
14242
|
};
|
|
13206
14243
|
const foundProviders = Object.entries(detected).filter(([_, isInstalled]) => isInstalled).map(([provider]) => provider);
|
|
13207
14244
|
logger.info("Provider detection complete", {
|
|
@@ -13308,6 +14345,9 @@ var ProviderDetector = class _ProviderDetector {
|
|
|
13308
14345
|
if (provider === "grok") {
|
|
13309
14346
|
return this.getGrokVersion();
|
|
13310
14347
|
}
|
|
14348
|
+
if (provider === "qwen") {
|
|
14349
|
+
return this.getQwenVersion();
|
|
14350
|
+
}
|
|
13311
14351
|
const command = _ProviderDetector.PROVIDER_COMMANDS[provider];
|
|
13312
14352
|
try {
|
|
13313
14353
|
const { stdout } = await execAsync2(`${command} --version`, {
|
|
@@ -13348,6 +14388,19 @@ var ProviderDetector = class _ProviderDetector {
|
|
|
13348
14388
|
}
|
|
13349
14389
|
return "SDK v1 (grok-3, API key not set)";
|
|
13350
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
|
+
}
|
|
13351
14404
|
/**
|
|
13352
14405
|
* Get list of detected provider names
|
|
13353
14406
|
*
|
|
@@ -13381,7 +14434,9 @@ var ProviderDetector = class _ProviderDetector {
|
|
|
13381
14434
|
"gemini-cli": "Gemini CLI",
|
|
13382
14435
|
"codex": "Codex CLI",
|
|
13383
14436
|
"glm": "GLM (Zhipu AI)",
|
|
13384
|
-
"grok": "Grok (xAI)"
|
|
14437
|
+
"grok": "Grok (xAI)",
|
|
14438
|
+
"qwen": "Qwen (Alibaba Cloud)"
|
|
14439
|
+
// v12.7.0
|
|
13385
14440
|
};
|
|
13386
14441
|
return nameMap[provider] || provider;
|
|
13387
14442
|
}
|
|
@@ -13474,8 +14529,9 @@ var setupCommand = {
|
|
|
13474
14529
|
console.log(chalk5.gray(" - Claude Code"));
|
|
13475
14530
|
console.log(chalk5.gray(" - Gemini CLI"));
|
|
13476
14531
|
console.log(chalk5.gray(" - Codex CLI"));
|
|
13477
|
-
console.log(chalk5.gray(" - GLM (SDK-first, requires
|
|
14532
|
+
console.log(chalk5.gray(" - GLM (SDK-first, requires GLM_API_KEY)"));
|
|
13478
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)"));
|
|
13479
14535
|
console.log("");
|
|
13480
14536
|
console.log(chalk5.cyan(' \u{1F4A1} After installing, run "ax setup" again to configure.\n'));
|
|
13481
14537
|
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
@@ -13552,14 +14608,14 @@ var setupCommand = {
|
|
|
13552
14608
|
console.log(chalk5.cyan("\u{1F50C} Setting up Gemini CLI integration..."));
|
|
13553
14609
|
const geminiDir = join(projectDir, ".gemini");
|
|
13554
14610
|
const geminiDirExistedBefore = await checkExists2(geminiDir);
|
|
13555
|
-
geminiMcpStatus = await setupGeminiIntegration(projectDir, packageRoot);
|
|
14611
|
+
geminiMcpStatus = await setupGeminiIntegration(projectDir, packageRoot, argv.force);
|
|
13556
14612
|
if (!geminiDirExistedBefore) {
|
|
13557
14613
|
createdResources.push(geminiDir);
|
|
13558
14614
|
}
|
|
13559
14615
|
if (geminiMcpStatus === "configured") {
|
|
13560
|
-
console.log(chalk5.green(" \u2713 Gemini CLI MCP integration configured"));
|
|
14616
|
+
console.log(chalk5.green(" \u2713 Gemini CLI MCP integration configured (gemini mcp add)"));
|
|
13561
14617
|
} else if (geminiMcpStatus === "skipped") {
|
|
13562
|
-
console.log(chalk5.yellow(" \u26A0 Gemini CLI
|
|
14618
|
+
console.log(chalk5.yellow(" \u26A0 Gemini CLI not available, skipped MCP setup"));
|
|
13563
14619
|
console.log(chalk5.gray(" CLI integration still works via subprocess"));
|
|
13564
14620
|
} else {
|
|
13565
14621
|
console.log(chalk5.yellow(" \u26A0 Gemini CLI MCP configuration failed"));
|
|
@@ -13581,34 +14637,26 @@ var setupCommand = {
|
|
|
13581
14637
|
let codexMcpStatus = "skipped";
|
|
13582
14638
|
if (providers["codex"]) {
|
|
13583
14639
|
console.log(chalk5.cyan("\u{1F50C} Setting up Codex CLI MCP integration..."));
|
|
13584
|
-
codexMcpStatus = await setupCodexGlobalMCPConfig();
|
|
14640
|
+
codexMcpStatus = await setupCodexGlobalMCPConfig(argv.force);
|
|
13585
14641
|
if (codexMcpStatus === "configured") {
|
|
13586
|
-
console.log(chalk5.green(" \u2713 Codex CLI MCP integration configured"));
|
|
14642
|
+
console.log(chalk5.green(" \u2713 Codex CLI MCP integration configured (codex mcp add)"));
|
|
13587
14643
|
} else if (codexMcpStatus === "skipped") {
|
|
13588
|
-
console.log(chalk5.yellow(" \u26A0 Codex CLI MCP
|
|
14644
|
+
console.log(chalk5.yellow(" \u26A0 Codex CLI not available, skipped MCP setup"));
|
|
13589
14645
|
} else {
|
|
13590
14646
|
console.log(chalk5.yellow(" \u26A0 Codex CLI MCP configuration failed"));
|
|
13591
14647
|
console.log(chalk5.gray(" CLI integration still works via subprocess"));
|
|
13592
14648
|
}
|
|
13593
14649
|
}
|
|
13594
|
-
let
|
|
13595
|
-
if (providers["
|
|
13596
|
-
console.log(chalk5.cyan("\u{1F50C} Setting up
|
|
13597
|
-
|
|
13598
|
-
if (
|
|
13599
|
-
console.log(chalk5.green(" \u2713
|
|
13600
|
-
} else {
|
|
13601
|
-
console.log(chalk5.yellow(" \u26A0
|
|
13602
|
-
}
|
|
13603
|
-
}
|
|
13604
|
-
let grokMcpStatus = "skipped";
|
|
13605
|
-
if (providers["grok"]) {
|
|
13606
|
-
console.log(chalk5.cyan("\u{1F50C} Setting up Grok (ax-grok) MCP integration..."));
|
|
13607
|
-
grokMcpStatus = await setupGrokMCPConfig(projectDir);
|
|
13608
|
-
if (grokMcpStatus === "configured") {
|
|
13609
|
-
console.log(chalk5.green(" \u2713 Grok MCP integration configured (.ax-grok/.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"));
|
|
13610
14658
|
} else {
|
|
13611
|
-
console.log(chalk5.yellow(" \u26A0
|
|
14659
|
+
console.log(chalk5.yellow(" \u26A0 Qwen MCP configuration failed"));
|
|
13612
14660
|
}
|
|
13613
14661
|
}
|
|
13614
14662
|
console.log(chalk5.cyan("\u{1F4DD} Updating .gitignore..."));
|
|
@@ -13639,9 +14687,11 @@ var setupCommand = {
|
|
|
13639
14687
|
console.log(chalk5.gray(" This is fine - MCP discovery will work without manifests"));
|
|
13640
14688
|
}
|
|
13641
14689
|
}
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
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
|
+
}
|
|
13645
14695
|
console.log(chalk5.green.bold("\n\u2705 AutomatosX set up successfully!\n"));
|
|
13646
14696
|
if (foundProviders.length > 0) {
|
|
13647
14697
|
console.log(chalk5.cyan(`Configured for: ${foundProviders.join(", ")}
|
|
@@ -13650,14 +14700,15 @@ var setupCommand = {
|
|
|
13650
14700
|
console.log(chalk5.yellow("\u26A0\uFE0F No AI providers configured\n"));
|
|
13651
14701
|
}
|
|
13652
14702
|
console.log(chalk5.gray("Next steps:"));
|
|
13653
|
-
console.log(chalk5.gray(
|
|
13654
|
-
console.log(chalk5.gray(" 2.
|
|
13655
|
-
console.log(chalk5.gray(
|
|
13656
|
-
console.log(chalk5.
|
|
13657
|
-
console.log(chalk5.
|
|
13658
|
-
console.log(chalk5.gray(" \u2022
|
|
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"));
|
|
13659
14710
|
console.log(chalk5.gray(" \u2022 Use get_capabilities tool to discover agents dynamically"));
|
|
13660
|
-
console.log(chalk5.gray(" \u2022
|
|
14711
|
+
console.log(chalk5.gray(" \u2022 GLM/Grok are SDK-only (no MCP CLI setup needed)\n"));
|
|
13661
14712
|
if (claudeCodeSetupSucceeded) {
|
|
13662
14713
|
console.log(chalk5.yellow("Legacy Claude Code Manifests (deprecated):"));
|
|
13663
14714
|
console.log(chalk5.gray(" \u2022 Slash commands: /agent-<name> (will be removed in v14.0.0)"));
|
|
@@ -13707,7 +14758,7 @@ var setupCommand = {
|
|
|
13707
14758
|
console.log(chalk5.gray(' \u2022 Example: "Use ax agent backend to create a REST API"'));
|
|
13708
14759
|
console.log(chalk5.gray(" \u2022 No special commands needed - just ask naturally!\n"));
|
|
13709
14760
|
}
|
|
13710
|
-
if (providers["glm"] || providers["grok"]) {
|
|
14761
|
+
if (providers["glm"] || providers["grok"] || providers["qwen"]) {
|
|
13711
14762
|
console.log(chalk5.cyan("SDK-First Providers (MCP Client Mode):"));
|
|
13712
14763
|
if (providers["glm"]) {
|
|
13713
14764
|
console.log(chalk5.gray(" \u2022 GLM (Zhipu AI) - API key: GLM_API_KEY"));
|
|
@@ -13717,8 +14768,12 @@ var setupCommand = {
|
|
|
13717
14768
|
console.log(chalk5.gray(" \u2022 Grok (xAI) - API key: XAI_API_KEY"));
|
|
13718
14769
|
console.log(chalk5.gray(" MCP: AxGrokWithMcp class connects to AutomatosX MCP server"));
|
|
13719
14770
|
}
|
|
13720
|
-
|
|
13721
|
-
|
|
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"));
|
|
13722
14777
|
}
|
|
13723
14778
|
if (providers["codex"]) {
|
|
13724
14779
|
console.log(chalk5.cyan("Codex CLI Integration:"));
|
|
@@ -14240,9 +15295,9 @@ async function initializeGitRepository(projectDir) {
|
|
|
14240
15295
|
logger.info("Git repository already exists, skipping initialization");
|
|
14241
15296
|
return true;
|
|
14242
15297
|
}
|
|
14243
|
-
const { spawn:
|
|
15298
|
+
const { spawn: spawn13 } = await import('child_process');
|
|
14244
15299
|
await new Promise((resolve13, reject) => {
|
|
14245
|
-
const child =
|
|
15300
|
+
const child = spawn13("git", ["init"], {
|
|
14246
15301
|
cwd: projectDir,
|
|
14247
15302
|
stdio: "pipe",
|
|
14248
15303
|
shell: false
|
|
@@ -14323,143 +15378,71 @@ async function updateGitignore(projectDir) {
|
|
|
14323
15378
|
logger.warn("Failed to update .gitignore", { error: error.message });
|
|
14324
15379
|
}
|
|
14325
15380
|
}
|
|
14326
|
-
async function setupGeminiIntegration(
|
|
14327
|
-
const mcpStatus = await
|
|
15381
|
+
async function setupGeminiIntegration(projectDir, _packageRoot, force = false) {
|
|
15382
|
+
const mcpStatus = await setupGeminiMCPViaCLI(projectDir, force);
|
|
14328
15383
|
return mcpStatus;
|
|
14329
15384
|
}
|
|
14330
|
-
async function
|
|
14331
|
-
const
|
|
14332
|
-
|
|
14333
|
-
|
|
14334
|
-
return "skipped";
|
|
14335
|
-
}
|
|
14336
|
-
const settingsPath = join(homeDir, ".gemini", "settings.json");
|
|
14337
|
-
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);
|
|
14338
15389
|
try {
|
|
14339
|
-
await
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
settings = JSON.parse(existingContent);
|
|
14345
|
-
} catch (error) {
|
|
14346
|
-
logger.warn("Failed to parse existing Gemini settings, will merge carefully", {
|
|
14347
|
-
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(() => {
|
|
14348
15395
|
});
|
|
15396
|
+
} else {
|
|
15397
|
+
logger.info("Gemini CLI MCP server already configured");
|
|
15398
|
+
return "configured";
|
|
14349
15399
|
}
|
|
14350
15400
|
}
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
}
|
|
14355
|
-
mcpServers["automatosx"] = {
|
|
14356
|
-
command: "automatosx",
|
|
14357
|
-
args: ["mcp", "server"]
|
|
14358
|
-
};
|
|
14359
|
-
settings["mcpServers"] = mcpServers;
|
|
14360
|
-
await writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
14361
|
-
logger.info("Configured Gemini CLI MCP in global settings", {
|
|
14362
|
-
path: settingsPath
|
|
14363
|
-
});
|
|
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");
|
|
14364
15404
|
return "configured";
|
|
14365
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
|
+
}
|
|
14366
15411
|
logger.warn("Failed to setup Gemini CLI MCP configuration", {
|
|
14367
|
-
error:
|
|
14368
|
-
path: settingsPath
|
|
15412
|
+
error: errorMessage
|
|
14369
15413
|
});
|
|
14370
15414
|
return "failed";
|
|
14371
15415
|
}
|
|
14372
15416
|
}
|
|
14373
|
-
async function setupCodexGlobalMCPConfig() {
|
|
14374
|
-
const
|
|
14375
|
-
|
|
14376
|
-
|
|
14377
|
-
return "skipped";
|
|
14378
|
-
}
|
|
14379
|
-
const codexDir = join(homeDir, ".codex");
|
|
14380
|
-
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);
|
|
14381
15421
|
try {
|
|
14382
|
-
await
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
const mcpConfig = `
|
|
14392
|
-
# AutomatosX MCP Server - Added by ax setup v12.2.0
|
|
14393
|
-
# Increased timeouts for lazy initialization (15-20s on first tool call)
|
|
14394
|
-
[mcp_servers.automatosx]
|
|
14395
|
-
command = "automatosx"
|
|
14396
|
-
args = ["mcp", "server"]
|
|
14397
|
-
startup_timeout_sec = 60
|
|
14398
|
-
tool_timeout_sec = 120
|
|
14399
|
-
`;
|
|
14400
|
-
await writeFile(configPath, existingContent + mcpConfig, "utf-8");
|
|
14401
|
-
logger.info("Configured Codex CLI MCP in global config", {
|
|
14402
|
-
path: configPath
|
|
14403
|
-
});
|
|
14404
|
-
return "configured";
|
|
14405
|
-
} catch (error) {
|
|
14406
|
-
logger.warn("Failed to setup Codex CLI MCP configuration", {
|
|
14407
|
-
error: error.message,
|
|
14408
|
-
path: configPath
|
|
14409
|
-
});
|
|
14410
|
-
return "failed";
|
|
14411
|
-
}
|
|
14412
|
-
}
|
|
14413
|
-
async function setupGlmMCPConfig(projectDir) {
|
|
14414
|
-
const configDir = join(projectDir, ".ax-glm");
|
|
14415
|
-
const configPath = join(configDir, ".mcp.json");
|
|
14416
|
-
try {
|
|
14417
|
-
await mkdir(configDir, { recursive: true });
|
|
14418
|
-
const mcpConfig = {
|
|
14419
|
-
mcpServers: {
|
|
14420
|
-
automatosx: {
|
|
14421
|
-
command: "automatosx",
|
|
14422
|
-
args: ["mcp", "server"],
|
|
14423
|
-
env: {
|
|
14424
|
-
AUTOMATOSX_PROJECT_DIR: projectDir
|
|
14425
|
-
}
|
|
14426
|
-
}
|
|
14427
|
-
}
|
|
14428
|
-
};
|
|
14429
|
-
await writeFile(configPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
14430
|
-
logger.info("Configured GLM MCP integration", { path: configPath });
|
|
14431
|
-
return "configured";
|
|
14432
|
-
} catch (error) {
|
|
14433
|
-
logger.warn("Failed to setup GLM MCP configuration", {
|
|
14434
|
-
error: error.message,
|
|
14435
|
-
path: configPath
|
|
14436
|
-
});
|
|
14437
|
-
return "failed";
|
|
14438
|
-
}
|
|
14439
|
-
}
|
|
14440
|
-
async function setupGrokMCPConfig(projectDir) {
|
|
14441
|
-
const configDir = join(projectDir, ".ax-grok");
|
|
14442
|
-
const configPath = join(configDir, ".mcp.json");
|
|
14443
|
-
try {
|
|
14444
|
-
await mkdir(configDir, { recursive: true });
|
|
14445
|
-
const mcpConfig = {
|
|
14446
|
-
mcpServers: {
|
|
14447
|
-
automatosx: {
|
|
14448
|
-
command: "automatosx",
|
|
14449
|
-
args: ["mcp", "server"],
|
|
14450
|
-
env: {
|
|
14451
|
-
AUTOMATOSX_PROJECT_DIR: projectDir
|
|
14452
|
-
}
|
|
14453
|
-
}
|
|
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";
|
|
14454
15431
|
}
|
|
14455
|
-
}
|
|
14456
|
-
|
|
14457
|
-
|
|
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");
|
|
14458
15437
|
return "configured";
|
|
14459
15438
|
} catch (error) {
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
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
|
|
14463
15446
|
});
|
|
14464
15447
|
return "failed";
|
|
14465
15448
|
}
|
|
@@ -14508,41 +15491,66 @@ Created by AutomatosX for organized scratch work.
|
|
|
14508
15491
|
});
|
|
14509
15492
|
}
|
|
14510
15493
|
}
|
|
14511
|
-
async function createMcpConfig(projectDir) {
|
|
14512
|
-
const
|
|
14513
|
-
const
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
}
|
|
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;
|
|
14521
15508
|
}
|
|
14522
15509
|
}
|
|
14523
|
-
|
|
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);
|
|
14524
15528
|
try {
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
|
|
14531
|
-
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
}
|
|
14535
|
-
} catch {
|
|
14536
|
-
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";
|
|
14537
15538
|
}
|
|
14538
15539
|
}
|
|
14539
|
-
|
|
14540
|
-
|
|
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";
|
|
14541
15544
|
} catch (error) {
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
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
|
|
14545
15552
|
});
|
|
15553
|
+
return "failed";
|
|
14546
15554
|
}
|
|
14547
15555
|
}
|
|
14548
15556
|
async function cleanupForceMode(projectDir) {
|
|
@@ -14697,7 +15705,7 @@ async function parsePackageJson(projectDir, info) {
|
|
|
14697
15705
|
if (packageJson.workspaces || devDeps.includes("lerna") || devDeps.includes("nx") || devDeps.includes("turborepo") || existsSync(join(projectDir, "lerna.json")) || existsSync(join(projectDir, "nx.json"))) {
|
|
14698
15706
|
info.isMonorepo = true;
|
|
14699
15707
|
}
|
|
14700
|
-
} catch
|
|
15708
|
+
} catch {
|
|
14701
15709
|
}
|
|
14702
15710
|
}
|
|
14703
15711
|
async function parseReadmeDescription(projectDir, info) {
|
|
@@ -14758,10 +15766,10 @@ async function parseReadmeDescription(projectDir, info) {
|
|
|
14758
15766
|
info.teamSize = "Open source community";
|
|
14759
15767
|
}
|
|
14760
15768
|
}
|
|
14761
|
-
} catch
|
|
15769
|
+
} catch {
|
|
14762
15770
|
}
|
|
14763
15771
|
}
|
|
14764
|
-
function categorizeScripts(scripts,
|
|
15772
|
+
function categorizeScripts(scripts, _packageManager) {
|
|
14765
15773
|
const categorized = {
|
|
14766
15774
|
development: [],
|
|
14767
15775
|
building: [],
|
|
@@ -14871,7 +15879,7 @@ async function analyzeFileStructure(projectDir) {
|
|
|
14871
15879
|
if (name === "docs") {
|
|
14872
15880
|
structure.docsDirectory = name;
|
|
14873
15881
|
}
|
|
14874
|
-
} catch
|
|
15882
|
+
} catch {
|
|
14875
15883
|
}
|
|
14876
15884
|
}
|
|
14877
15885
|
}
|
|
@@ -14901,7 +15909,7 @@ async function countFilesRecursive(dirPath, depth = 0) {
|
|
|
14901
15909
|
}
|
|
14902
15910
|
return count;
|
|
14903
15911
|
}
|
|
14904
|
-
async function detectKeyComponents(projectDir,
|
|
15912
|
+
async function detectKeyComponents(projectDir, _info) {
|
|
14905
15913
|
const components = [];
|
|
14906
15914
|
const srcDir = join(projectDir, "src");
|
|
14907
15915
|
if (!existsSync(srcDir)) return components;
|
|
@@ -15200,7 +16208,7 @@ async function detectDatabaseSchema(projectDir, info) {
|
|
|
15200
16208
|
}
|
|
15201
16209
|
return void 0;
|
|
15202
16210
|
}
|
|
15203
|
-
async function detectPrismaSchema(projectDir, schemaPath,
|
|
16211
|
+
async function detectPrismaSchema(projectDir, schemaPath, _info) {
|
|
15204
16212
|
const models = [];
|
|
15205
16213
|
const migrations = await detectMigrations(projectDir, "prisma/migrations");
|
|
15206
16214
|
try {
|
|
@@ -15254,7 +16262,7 @@ async function detectPrismaSchema(projectDir, schemaPath, info) {
|
|
|
15254
16262
|
relations
|
|
15255
16263
|
});
|
|
15256
16264
|
}
|
|
15257
|
-
} catch
|
|
16265
|
+
} catch {
|
|
15258
16266
|
}
|
|
15259
16267
|
return {
|
|
15260
16268
|
orm: "Prisma",
|
|
@@ -15342,347 +16350,66 @@ async function detectNextJSAPIRoutes(projectDir) {
|
|
|
15342
16350
|
// Next.js API routes handle multiple methods
|
|
15343
16351
|
path: `/api/${routePath}`,
|
|
15344
16352
|
group: routePath.split("/")[0] || "api"
|
|
15345
|
-
});
|
|
15346
|
-
}
|
|
15347
|
-
}
|
|
15348
|
-
} catch {
|
|
15349
|
-
}
|
|
15350
|
-
}
|
|
15351
|
-
return endpoints;
|
|
15352
|
-
}
|
|
15353
|
-
async function detectExpressRoutes(projectDir) {
|
|
15354
|
-
const endpoints = [];
|
|
15355
|
-
const srcDir = join(projectDir, "src");
|
|
15356
|
-
if (!existsSync(srcDir)) return endpoints;
|
|
15357
|
-
try {
|
|
15358
|
-
const routeFiles = await findFilesRecursive(srcDir, /route|controller|api/i, 3);
|
|
15359
|
-
for (const file of routeFiles.slice(0, 10)) {
|
|
15360
|
-
try {
|
|
15361
|
-
const content = await readFile(file, "utf-8");
|
|
15362
|
-
const routeRegex = /(?:router|app)\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
15363
|
-
let match;
|
|
15364
|
-
while ((match = routeRegex.exec(content)) !== null) {
|
|
15365
|
-
if (match[1] && match[2]) {
|
|
15366
|
-
const method = match[1].toUpperCase();
|
|
15367
|
-
const path9 = match[2];
|
|
15368
|
-
endpoints.push({
|
|
15369
|
-
method,
|
|
15370
|
-
path: path9,
|
|
15371
|
-
group: path9.split("/")[1] || "api"
|
|
15372
|
-
});
|
|
15373
|
-
}
|
|
15374
|
-
}
|
|
15375
|
-
} catch {
|
|
15376
|
-
}
|
|
15377
|
-
}
|
|
15378
|
-
} catch {
|
|
15379
|
-
}
|
|
15380
|
-
return endpoints;
|
|
15381
|
-
}
|
|
15382
|
-
async function findFilesRecursive(dir, pattern, maxDepth = 3, currentDepth = 0) {
|
|
15383
|
-
if (currentDepth > maxDepth) return [];
|
|
15384
|
-
const files = [];
|
|
15385
|
-
try {
|
|
15386
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
15387
|
-
for (const entry of entries) {
|
|
15388
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
15389
|
-
const fullPath = join(dir, entry.name);
|
|
15390
|
-
if (entry.isFile() && pattern.test(entry.name)) {
|
|
15391
|
-
files.push(fullPath);
|
|
15392
|
-
} else if (entry.isDirectory()) {
|
|
15393
|
-
const subFiles = await findFilesRecursive(fullPath, pattern, maxDepth, currentDepth + 1);
|
|
15394
|
-
files.push(...subFiles);
|
|
15395
|
-
}
|
|
15396
|
-
}
|
|
15397
|
-
} catch {
|
|
15398
|
-
}
|
|
15399
|
-
return files;
|
|
15400
|
-
}
|
|
15401
|
-
|
|
15402
|
-
// src/cli/commands/init-parser.ts
|
|
15403
|
-
init_esm_shims();
|
|
15404
|
-
function parseAXMD(content) {
|
|
15405
|
-
const result = {
|
|
15406
|
-
dependencies: [],
|
|
15407
|
-
scripts: {},
|
|
15408
|
-
hasCustomContent: false,
|
|
15409
|
-
customSections: []
|
|
15410
|
-
};
|
|
15411
|
-
const versionMatch = content.match(/Project:.*?\(v([\d.]+)\)/);
|
|
15412
|
-
if (versionMatch) {
|
|
15413
|
-
result.version = versionMatch[1];
|
|
15414
|
-
}
|
|
15415
|
-
const nameMatch = content.match(/# Project Context for (.+)/);
|
|
15416
|
-
if (nameMatch) {
|
|
15417
|
-
result.projectName = nameMatch[1];
|
|
15418
|
-
}
|
|
15419
|
-
const descMatch = content.match(/## Project Overview\n\n\*\*(.+?)\*\*/);
|
|
15420
|
-
if (descMatch) {
|
|
15421
|
-
result.description = descMatch[1];
|
|
15422
|
-
}
|
|
15423
|
-
const archMatch = content.match(/\*\*Architecture:\*\* (.+)/);
|
|
15424
|
-
if (archMatch) {
|
|
15425
|
-
result.architecture = archMatch[1];
|
|
15426
|
-
}
|
|
15427
|
-
const stackMatch = content.match(/\*\*Stack:\*\* (.+)/);
|
|
15428
|
-
if (stackMatch && stackMatch[1]) {
|
|
15429
|
-
result.stack = stackMatch[1];
|
|
15430
|
-
result.dependencies = stackMatch[1].split(",").map((d) => d.trim().toLowerCase()).filter(Boolean);
|
|
15431
|
-
}
|
|
15432
|
-
const teamMatch = content.match(/\*\*Team:\*\* (.+)/);
|
|
15433
|
-
if (teamMatch) {
|
|
15434
|
-
result.team = teamMatch[1];
|
|
15435
|
-
}
|
|
15436
|
-
const testMatch = content.match(/- Framework: (.+)/);
|
|
15437
|
-
if (testMatch) {
|
|
15438
|
-
result.testFramework = testMatch[1];
|
|
15439
|
-
}
|
|
15440
|
-
const linterMatch = content.match(/- Linter: (.+)/);
|
|
15441
|
-
if (linterMatch) {
|
|
15442
|
-
result.linter = linterMatch[1];
|
|
15443
|
-
}
|
|
15444
|
-
const formatterMatch = content.match(/- Formatter: (.+)/);
|
|
15445
|
-
if (formatterMatch) {
|
|
15446
|
-
result.formatter = formatterMatch[1];
|
|
15447
|
-
}
|
|
15448
|
-
const commandsMatch = content.match(/## Canonical Commands\n\n```bash\n([\s\S]*?)```/);
|
|
15449
|
-
if (commandsMatch && commandsMatch[1]) {
|
|
15450
|
-
const commandsSection = commandsMatch[1];
|
|
15451
|
-
const lines = commandsSection.split("\n");
|
|
15452
|
-
for (const line of lines) {
|
|
15453
|
-
const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#/);
|
|
15454
|
-
if (cmdMatch && cmdMatch[1]) {
|
|
15455
|
-
const cmd = cmdMatch[1].trim();
|
|
15456
|
-
result.scripts[cmd] = cmd;
|
|
15457
|
-
}
|
|
15458
|
-
}
|
|
15459
|
-
}
|
|
15460
|
-
const customMarkers = [
|
|
15461
|
-
/<!-- USER-EDITED -->/,
|
|
15462
|
-
/## Our Custom/,
|
|
15463
|
-
/## Notes/,
|
|
15464
|
-
/## Team Guidelines/
|
|
15465
|
-
];
|
|
15466
|
-
for (const marker of customMarkers) {
|
|
15467
|
-
if (marker.test(content)) {
|
|
15468
|
-
result.hasCustomContent = true;
|
|
15469
|
-
break;
|
|
15470
|
-
}
|
|
15471
|
-
}
|
|
15472
|
-
const sections = content.split(/^## /m);
|
|
15473
|
-
const standardSections = [
|
|
15474
|
-
"Project Overview",
|
|
15475
|
-
"Agent Delegation Rules",
|
|
15476
|
-
"Coding Conventions",
|
|
15477
|
-
"Critical Guardrails",
|
|
15478
|
-
"Canonical Commands",
|
|
15479
|
-
"Useful Links"
|
|
15480
|
-
];
|
|
15481
|
-
for (const section of sections) {
|
|
15482
|
-
const sectionName = section.split("\n")[0] ?? "";
|
|
15483
|
-
if (sectionName && !standardSections.includes(sectionName)) {
|
|
15484
|
-
result.customSections.push(sectionName);
|
|
15485
|
-
}
|
|
15486
|
-
}
|
|
15487
|
-
return result;
|
|
15488
|
-
}
|
|
15489
|
-
function detectDetailedChanges(parsed, current) {
|
|
15490
|
-
const changes = [];
|
|
15491
|
-
if (parsed.version !== current.version && current.version) {
|
|
15492
|
-
changes.push({
|
|
15493
|
-
type: "version",
|
|
15494
|
-
field: "version",
|
|
15495
|
-
oldValue: parsed.version,
|
|
15496
|
-
newValue: current.version
|
|
15497
|
-
});
|
|
15498
|
-
}
|
|
15499
|
-
const currentDeps = current.dependencies.map((d) => d.toLowerCase());
|
|
15500
|
-
const addedDeps = currentDeps.filter((d) => !parsed.dependencies.includes(d));
|
|
15501
|
-
if (addedDeps.length > 0) {
|
|
15502
|
-
changes.push({
|
|
15503
|
-
type: "dependency-added",
|
|
15504
|
-
field: "dependencies",
|
|
15505
|
-
items: addedDeps
|
|
15506
|
-
});
|
|
15507
|
-
}
|
|
15508
|
-
const removedDeps = parsed.dependencies.filter((d) => !currentDeps.includes(d));
|
|
15509
|
-
if (removedDeps.length > 0) {
|
|
15510
|
-
changes.push({
|
|
15511
|
-
type: "dependency-removed",
|
|
15512
|
-
field: "dependencies",
|
|
15513
|
-
items: removedDeps
|
|
15514
|
-
});
|
|
15515
|
-
}
|
|
15516
|
-
const currentScriptKeys = Object.keys(current.scripts);
|
|
15517
|
-
const parsedScriptKeys = Object.keys(parsed.scripts);
|
|
15518
|
-
const addedScripts = currentScriptKeys.filter((s) => !parsedScriptKeys.includes(s));
|
|
15519
|
-
if (addedScripts.length > 0) {
|
|
15520
|
-
changes.push({
|
|
15521
|
-
type: "script-added",
|
|
15522
|
-
field: "scripts",
|
|
15523
|
-
items: addedScripts
|
|
15524
|
-
});
|
|
15525
|
-
}
|
|
15526
|
-
const removedScripts = parsedScriptKeys.filter((s) => !currentScriptKeys.includes(s));
|
|
15527
|
-
if (removedScripts.length > 0) {
|
|
15528
|
-
changes.push({
|
|
15529
|
-
type: "script-removed",
|
|
15530
|
-
field: "scripts",
|
|
15531
|
-
items: removedScripts
|
|
15532
|
-
});
|
|
15533
|
-
}
|
|
15534
|
-
if (current.linter && !parsed.linter) {
|
|
15535
|
-
changes.push({
|
|
15536
|
-
type: "tool-added",
|
|
15537
|
-
field: "linter",
|
|
15538
|
-
newValue: current.linter
|
|
15539
|
-
});
|
|
15540
|
-
}
|
|
15541
|
-
if (current.formatter && !parsed.formatter) {
|
|
15542
|
-
changes.push({
|
|
15543
|
-
type: "tool-added",
|
|
15544
|
-
field: "formatter",
|
|
15545
|
-
newValue: current.formatter
|
|
15546
|
-
});
|
|
15547
|
-
}
|
|
15548
|
-
if (current.testFramework && !parsed.testFramework) {
|
|
15549
|
-
changes.push({
|
|
15550
|
-
type: "tool-added",
|
|
15551
|
-
field: "test framework",
|
|
15552
|
-
newValue: current.testFramework
|
|
15553
|
-
});
|
|
15554
|
-
}
|
|
15555
|
-
if (parsed.architecture && parsed.architecture !== current.architecture) {
|
|
15556
|
-
changes.push({
|
|
15557
|
-
type: "architecture",
|
|
15558
|
-
field: "architecture",
|
|
15559
|
-
oldValue: parsed.architecture,
|
|
15560
|
-
newValue: current.architecture
|
|
15561
|
-
});
|
|
15562
|
-
}
|
|
15563
|
-
return changes;
|
|
15564
|
-
}
|
|
15565
|
-
function formatChangeSummary(changes) {
|
|
15566
|
-
if (changes.length === 0) return "";
|
|
15567
|
-
const summaries = [];
|
|
15568
|
-
for (const change of changes) {
|
|
15569
|
-
switch (change.type) {
|
|
15570
|
-
case "version":
|
|
15571
|
-
summaries.push(`version ${change.oldValue} \u2192 ${change.newValue}`);
|
|
15572
|
-
break;
|
|
15573
|
-
case "dependency-added":
|
|
15574
|
-
summaries.push(`+${change.items.length} dep${change.items.length > 1 ? "s" : ""}`);
|
|
15575
|
-
break;
|
|
15576
|
-
case "dependency-removed":
|
|
15577
|
-
summaries.push(`-${change.items.length} dep${change.items.length > 1 ? "s" : ""}`);
|
|
15578
|
-
break;
|
|
15579
|
-
case "script-added":
|
|
15580
|
-
summaries.push(`+${change.items.length} script${change.items.length > 1 ? "s" : ""}`);
|
|
15581
|
-
break;
|
|
15582
|
-
case "tool-added":
|
|
15583
|
-
summaries.push(`+${change.field}`);
|
|
15584
|
-
break;
|
|
15585
|
-
case "architecture":
|
|
15586
|
-
summaries.push("architecture");
|
|
15587
|
-
break;
|
|
15588
|
-
}
|
|
15589
|
-
}
|
|
15590
|
-
if (summaries.length === 0) return "";
|
|
15591
|
-
if (summaries.length === 1) return `(${summaries[0]})`;
|
|
15592
|
-
if (summaries.length === 2) return `(${summaries[0]}, ${summaries[1]})`;
|
|
15593
|
-
return `(${summaries.length} changes)`;
|
|
15594
|
-
}
|
|
15595
|
-
|
|
15596
|
-
// src/cli/commands/init.ts
|
|
15597
|
-
function generateAXMD(info) {
|
|
15598
|
-
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
15599
|
-
return `# Project Context for ${info.name}
|
|
15600
|
-
|
|
15601
|
-
> Last updated: ${today}
|
|
15602
|
-
> Project: ${info.name}${info.version ? ` (v${info.version})` : ""}
|
|
15603
|
-
|
|
15604
|
-
## Project Overview
|
|
15605
|
-
|
|
15606
|
-
${generateProjectOverview(info)}
|
|
15607
|
-
|
|
15608
|
-
## Architecture
|
|
15609
|
-
|
|
15610
|
-
${generateArchitecture(info)}
|
|
15611
|
-
|
|
15612
|
-
## File Structure
|
|
15613
|
-
|
|
15614
|
-
${generateFileStructure(info)}
|
|
15615
|
-
|
|
15616
|
-
${generateGettingStarted(info)}
|
|
15617
|
-
|
|
15618
|
-
${generateTroubleshooting(info)}
|
|
15619
|
-
|
|
15620
|
-
${generateDevWorkflow(info)}
|
|
15621
|
-
|
|
15622
|
-
${generateDatabaseSchema(info)}
|
|
15623
|
-
|
|
15624
|
-
${generateAPIDocumentation(info)}
|
|
15625
|
-
|
|
15626
|
-
${generateAgentRules(info)}
|
|
15627
|
-
|
|
15628
|
-
${generateCodingConventions(info)}
|
|
15629
|
-
|
|
15630
|
-
${generateCriticalGuardrails(info)}
|
|
15631
|
-
|
|
15632
|
-
${generateCommands(info)}
|
|
15633
|
-
|
|
15634
|
-
${generateUsefulLinks(info)}
|
|
15635
|
-
|
|
15636
|
-
---
|
|
15637
|
-
|
|
15638
|
-
**Generated by \`ax init\` \u2022 Run regularly to keep up-to-date**
|
|
15639
|
-
`;
|
|
15640
|
-
}
|
|
15641
|
-
function generateProjectOverview(info) {
|
|
15642
|
-
const sections = [];
|
|
15643
|
-
if (info.detailedDescription) {
|
|
15644
|
-
sections.push(info.detailedDescription);
|
|
15645
|
-
} else if (info.description) {
|
|
15646
|
-
sections.push(`**${info.description}**`);
|
|
15647
|
-
} else {
|
|
15648
|
-
sections.push(`**${info.framework || "Node.js"} project${info.hasTypeScript ? " with TypeScript" : ""}**`);
|
|
15649
|
-
}
|
|
15650
|
-
const keyInfo = [];
|
|
15651
|
-
keyInfo.push(`**Version:** ${info.version || "Not specified"}`);
|
|
15652
|
-
keyInfo.push(`**Language:** ${info.language}`);
|
|
15653
|
-
if (info.framework) keyInfo.push(`**Framework:** ${info.framework}`);
|
|
15654
|
-
if (info.buildTool) keyInfo.push(`**Build Tool:** ${info.buildTool}`);
|
|
15655
|
-
if (info.testFramework) keyInfo.push(`**Test Framework:** ${info.testFramework}`);
|
|
15656
|
-
if (info.isMonorepo) keyInfo.push(`**Type:** Monorepo`);
|
|
15657
|
-
sections.push("\n" + keyInfo.join(" \n"));
|
|
15658
|
-
sections.push(`
|
|
15659
|
-
**Stack:** ${info.stack}`);
|
|
15660
|
-
if (info.teamSize) {
|
|
15661
|
-
sections.push(`
|
|
15662
|
-
**Team:** ${info.teamSize}`);
|
|
16353
|
+
});
|
|
16354
|
+
}
|
|
16355
|
+
}
|
|
16356
|
+
} catch {
|
|
16357
|
+
}
|
|
15663
16358
|
}
|
|
15664
|
-
return
|
|
16359
|
+
return endpoints;
|
|
15665
16360
|
}
|
|
15666
|
-
function
|
|
15667
|
-
const
|
|
15668
|
-
|
|
15669
|
-
if (
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
16361
|
+
async function detectExpressRoutes(projectDir) {
|
|
16362
|
+
const endpoints = [];
|
|
16363
|
+
const srcDir = join(projectDir, "src");
|
|
16364
|
+
if (!existsSync(srcDir)) return endpoints;
|
|
16365
|
+
try {
|
|
16366
|
+
const routeFiles = await findFilesRecursive(srcDir, /route|controller|api/i, 3);
|
|
16367
|
+
for (const file of routeFiles.slice(0, 10)) {
|
|
16368
|
+
try {
|
|
16369
|
+
const content = await readFile(file, "utf-8");
|
|
16370
|
+
const routeRegex = /(?:router|app)\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
16371
|
+
let match;
|
|
16372
|
+
while ((match = routeRegex.exec(content)) !== null) {
|
|
16373
|
+
if (match[1] && match[2]) {
|
|
16374
|
+
const method = match[1].toUpperCase();
|
|
16375
|
+
const path9 = match[2];
|
|
16376
|
+
endpoints.push({
|
|
16377
|
+
method,
|
|
16378
|
+
path: path9,
|
|
16379
|
+
group: path9.split("/")[1] || "api"
|
|
16380
|
+
});
|
|
16381
|
+
}
|
|
16382
|
+
}
|
|
16383
|
+
} catch {
|
|
16384
|
+
}
|
|
16385
|
+
}
|
|
16386
|
+
} catch {
|
|
15673
16387
|
}
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
16388
|
+
return endpoints;
|
|
16389
|
+
}
|
|
16390
|
+
async function findFilesRecursive(dir, pattern, maxDepth = 3, currentDepth = 0) {
|
|
16391
|
+
if (currentDepth > maxDepth) return [];
|
|
16392
|
+
const files = [];
|
|
16393
|
+
try {
|
|
16394
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
16395
|
+
for (const entry of entries) {
|
|
16396
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
16397
|
+
const fullPath = join(dir, entry.name);
|
|
16398
|
+
if (entry.isFile() && pattern.test(entry.name)) {
|
|
16399
|
+
files.push(fullPath);
|
|
16400
|
+
} else if (entry.isDirectory()) {
|
|
16401
|
+
const subFiles = await findFilesRecursive(fullPath, pattern, maxDepth, currentDepth + 1);
|
|
16402
|
+
files.push(...subFiles);
|
|
15681
16403
|
}
|
|
15682
16404
|
}
|
|
16405
|
+
} catch {
|
|
15683
16406
|
}
|
|
15684
|
-
return
|
|
16407
|
+
return files;
|
|
15685
16408
|
}
|
|
16409
|
+
|
|
16410
|
+
// src/cli/commands/init.ts
|
|
16411
|
+
var execAsync3 = promisify(exec);
|
|
16412
|
+
var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
|
|
15686
16413
|
function detectArchitectureType(info) {
|
|
15687
16414
|
if (info.dependencies.includes("next") || info.dependencies.includes("nuxt")) {
|
|
15688
16415
|
return "Full-stack framework (SSR/SSG)";
|
|
@@ -15704,459 +16431,424 @@ function detectArchitectureType(info) {
|
|
|
15704
16431
|
}
|
|
15705
16432
|
return "Node.js application";
|
|
15706
16433
|
}
|
|
15707
|
-
function
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
sections.push(`- \`${dir.path}/\` - ${dir.purpose} (${dir.fileCount} files)`);
|
|
15719
|
-
} else {
|
|
15720
|
-
sections.push(`- \`${dir.path}/\` - ${dir.fileCount} files`);
|
|
15721
|
-
}
|
|
15722
|
-
}
|
|
15723
|
-
sections.push(`
|
|
15724
|
-
**Total Files:** ${info.fileStructure.totalFiles}`);
|
|
15725
|
-
return sections.join("\n");
|
|
15726
|
-
}
|
|
15727
|
-
function generateGettingStarted(info) {
|
|
15728
|
-
if (!info.gettingStarted) {
|
|
15729
|
-
return "";
|
|
15730
|
-
}
|
|
15731
|
-
const sections = ["## Getting Started", ""];
|
|
15732
|
-
if (info.gettingStarted.prerequisites.length > 0) {
|
|
15733
|
-
sections.push("### Prerequisites");
|
|
15734
|
-
for (const prereq of info.gettingStarted.prerequisites) {
|
|
15735
|
-
sections.push(`- ${prereq}`);
|
|
15736
|
-
}
|
|
15737
|
-
sections.push("");
|
|
15738
|
-
}
|
|
15739
|
-
if (info.gettingStarted.setupSteps.length > 0) {
|
|
15740
|
-
sections.push("### First Time Setup");
|
|
15741
|
-
for (const step of info.gettingStarted.setupSteps) {
|
|
15742
|
-
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
|
+
});
|
|
15743
16445
|
}
|
|
15744
|
-
sections.push("");
|
|
15745
16446
|
}
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
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
|
+
};
|
|
15768
16476
|
}
|
|
15769
|
-
sections.push("");
|
|
15770
16477
|
}
|
|
15771
16478
|
}
|
|
15772
|
-
|
|
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
|
+
};
|
|
15773
16513
|
}
|
|
15774
|
-
function
|
|
15775
|
-
const
|
|
15776
|
-
sections
|
|
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}`);
|
|
15777
16518
|
sections.push("");
|
|
15778
|
-
sections.push(
|
|
15779
|
-
sections.push(
|
|
16519
|
+
sections.push(`> Generated: ${today}`);
|
|
16520
|
+
sections.push(`> Project: ${info.name}${info.version ? ` v${info.version}` : ""}`);
|
|
15780
16521
|
sections.push("");
|
|
15781
|
-
|
|
15782
|
-
sections.push("**Problem**: Database connection refused");
|
|
15783
|
-
sections.push("**Solution**:");
|
|
15784
|
-
sections.push("1. Check Docker is running: `docker ps`");
|
|
15785
|
-
sections.push("2. Start services: `docker-compose up -d`");
|
|
15786
|
-
if (info.scripts["db:ping"]) {
|
|
15787
|
-
sections.push(`3. Verify connection: \`${info.packageManager} run db:ping\``);
|
|
15788
|
-
}
|
|
15789
|
-
sections.push("");
|
|
15790
|
-
}
|
|
15791
|
-
sections.push("**Problem**: Port already in use");
|
|
15792
|
-
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.");
|
|
15793
16523
|
sections.push("");
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
if (info.
|
|
15800
|
-
sections.push(
|
|
15801
|
-
|
|
15802
|
-
sections.push("");
|
|
15803
|
-
}
|
|
15804
|
-
sections.push("### Debug Mode");
|
|
15805
|
-
sections.push("Run with verbose logging:");
|
|
15806
|
-
sections.push("```bash");
|
|
15807
|
-
sections.push("DEBUG=* npm run dev");
|
|
15808
|
-
if (info.scripts.test) {
|
|
15809
|
-
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" : ""}`);
|
|
15810
16533
|
}
|
|
15811
|
-
sections.push("```");
|
|
15812
|
-
return sections.join("\n");
|
|
15813
|
-
}
|
|
15814
|
-
function generateDevWorkflow(info) {
|
|
15815
|
-
const sections = ["## Development Workflow", ""];
|
|
15816
|
-
sections.push("### Daily Workflow");
|
|
15817
|
-
sections.push("1. Pull latest: `git pull origin main`");
|
|
15818
|
-
sections.push("2. Create feature branch: `git checkout -b feature/my-feature`");
|
|
15819
|
-
sections.push("3. Make changes");
|
|
15820
|
-
if (info.scripts.test) {
|
|
15821
|
-
sections.push(`4. Run tests: \`${info.packageManager} test\``);
|
|
15822
|
-
}
|
|
15823
|
-
sections.push('5. Commit: `git commit -m "feat: add my feature"`');
|
|
15824
|
-
sections.push("6. Push: `git push origin feature/my-feature`");
|
|
15825
|
-
sections.push("7. Open PR on GitHub");
|
|
15826
|
-
sections.push("8. Wait for CI + reviews");
|
|
15827
|
-
sections.push("9. Merge to main (squash merge)");
|
|
15828
16534
|
sections.push("");
|
|
15829
|
-
sections.push("
|
|
15830
|
-
sections.push("- Minimum 1 approval required");
|
|
15831
|
-
sections.push("- CI must pass (tests + lint)");
|
|
15832
|
-
sections.push("- No merge conflicts");
|
|
16535
|
+
sections.push("## Critical Rules");
|
|
15833
16536
|
sections.push("");
|
|
15834
|
-
sections.push("###
|
|
15835
|
-
if (info.framework === "React" || info.framework === "Vue") {
|
|
15836
|
-
if (info.buildTool === "Vite") {
|
|
15837
|
-
sections.push("- Frontend: Vite HMR (instant)");
|
|
15838
|
-
} else {
|
|
15839
|
-
sections.push("- Frontend: Hot module replacement enabled");
|
|
15840
|
-
}
|
|
15841
|
-
}
|
|
15842
|
-
if (info.dependencies.includes("express") || info.dependencies.includes("fastify")) {
|
|
15843
|
-
sections.push("- Backend: Nodemon (restart on save)");
|
|
15844
|
-
}
|
|
15845
|
-
if (info.framework === "Next.js") {
|
|
15846
|
-
sections.push("- Next.js Fast Refresh (instant updates)");
|
|
15847
|
-
}
|
|
16537
|
+
sections.push("### DO");
|
|
15848
16538
|
sections.push("");
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
sections.push(`- Unit tests: \`${info.packageManager} run test:unit\` (fast, no DB)`);
|
|
15853
|
-
}
|
|
15854
|
-
if (info.scripts["test:integration"]) {
|
|
15855
|
-
sections.push(`- Integration tests: \`${info.packageManager} run test:integration\` (with test DB)`);
|
|
15856
|
-
}
|
|
15857
|
-
if (info.scripts["test:e2e"]) {
|
|
15858
|
-
sections.push(`- E2E tests: \`${info.packageManager} run test:e2e\` (full stack)`);
|
|
15859
|
-
}
|
|
15860
|
-
if (info.scripts.test) {
|
|
15861
|
-
sections.push(`- Run all: \`${info.packageManager} test\``);
|
|
15862
|
-
}
|
|
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`);
|
|
15863
16542
|
}
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
function generateDatabaseSchema(info) {
|
|
15867
|
-
if (!info.databaseSchema || info.databaseSchema.models.length === 0) {
|
|
15868
|
-
return "";
|
|
16543
|
+
if (info.hasTypeScript) {
|
|
16544
|
+
sections.push("- Use TypeScript strict mode conventions");
|
|
15869
16545
|
}
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
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");
|
|
15875
16556
|
}
|
|
15876
|
-
|
|
15877
|
-
|
|
16557
|
+
sections.push("");
|
|
16558
|
+
if (info.categorizedScripts) {
|
|
16559
|
+
sections.push("## Key Commands");
|
|
15878
16560
|
sections.push("");
|
|
15879
|
-
|
|
15880
|
-
|
|
15881
|
-
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15888
|
-
if (field.defaultValue) attrs.push(`default: ${field.defaultValue}`);
|
|
15889
|
-
if (attrs.length > 0) {
|
|
15890
|
-
fieldDesc += ` (${attrs.join(", ")})`;
|
|
15891
|
-
}
|
|
15892
|
-
sections.push(fieldDesc);
|
|
15893
|
-
}
|
|
15894
|
-
}
|
|
15895
|
-
if (model.relations.length > 0) {
|
|
15896
|
-
for (const rel of model.relations) {
|
|
15897
|
-
sections.push(`- \`${rel.name}\`: ${rel.type} \u2192 ${rel.relatedModel}`);
|
|
15898
|
-
}
|
|
15899
|
-
}
|
|
15900
|
-
sections.push("");
|
|
15901
|
-
}
|
|
15902
|
-
if (schema.models.length > 10) {
|
|
15903
|
-
sections.push(`*... and ${schema.models.length - 10} more models*`);
|
|
15904
|
-
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}`);
|
|
15905
16570
|
}
|
|
16571
|
+
sections.push("```");
|
|
16572
|
+
sections.push("");
|
|
15906
16573
|
}
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
|
|
15913
|
-
|
|
15914
|
-
}
|
|
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`);
|
|
15915
16582
|
sections.push("");
|
|
15916
16583
|
}
|
|
16584
|
+
sections.push("---");
|
|
16585
|
+
sections.push("");
|
|
16586
|
+
sections.push("*Generated by `ax init` \u2022 Edit this file to customize AI behavior*");
|
|
15917
16587
|
return sections.join("\n");
|
|
15918
16588
|
}
|
|
15919
|
-
function
|
|
15920
|
-
|
|
15921
|
-
|
|
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;
|
|
15922
16610
|
}
|
|
15923
|
-
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
|
|
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 {
|
|
15928
16634
|
}
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
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;
|
|
15932
16646
|
}
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
const
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
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;
|
|
15943
16676
|
}
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
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;
|
|
15952
16695
|
}
|
|
15953
|
-
if (
|
|
15954
|
-
|
|
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;
|
|
15955
16699
|
}
|
|
15956
|
-
sections.push(line);
|
|
15957
16700
|
}
|
|
15958
|
-
sections.push("");
|
|
15959
|
-
}
|
|
15960
|
-
if (api.endpoints.length > 20) {
|
|
15961
|
-
sections.push(`*... and ${api.endpoints.length - 20} more endpoints*`);
|
|
15962
|
-
sections.push("");
|
|
15963
16701
|
}
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
15975
|
-
|
|
15976
|
-
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
rules.push("- **Tests/QA** \u2192 @quality (Queenie)");
|
|
15986
|
-
rules.push("- **Security audits** \u2192 @security (Steve) - mandatory for: auth, payments, PII");
|
|
15987
|
-
rules.push("- **Architecture/ADR** \u2192 @architecture (Avery)");
|
|
15988
|
-
rules.push("");
|
|
15989
|
-
rules.push("### Documentation & Product");
|
|
15990
|
-
rules.push("- **Technical writing** \u2192 @writer (Wendy)");
|
|
15991
|
-
rules.push("- **Product management** \u2192 @product (Paris)");
|
|
15992
|
-
return rules.join("\n");
|
|
15993
|
-
}
|
|
15994
|
-
function generateCodingConventions(info) {
|
|
15995
|
-
const conventions = ["## Coding Conventions", ""];
|
|
15996
|
-
conventions.push("### Testing");
|
|
15997
|
-
if (info.testFramework) {
|
|
15998
|
-
conventions.push(`- **Framework:** ${info.testFramework}`);
|
|
15999
|
-
conventions.push("- **Coverage:** 80% minimum");
|
|
16000
|
-
conventions.push(`- **Run:** \`${info.packageManager} test\``);
|
|
16001
|
-
} else {
|
|
16002
|
-
conventions.push("- Run tests before pushing");
|
|
16003
|
-
}
|
|
16004
|
-
conventions.push("");
|
|
16005
|
-
conventions.push("### Code Style");
|
|
16006
|
-
if (info.linter) {
|
|
16007
|
-
conventions.push(`- **Linter:** ${info.linter}`);
|
|
16008
|
-
}
|
|
16009
|
-
if (info.formatter) {
|
|
16010
|
-
conventions.push(`- **Formatter:** ${info.formatter}`);
|
|
16011
|
-
}
|
|
16012
|
-
if (info.hasTypeScript) {
|
|
16013
|
-
conventions.push("- **TypeScript:** Strict mode enabled");
|
|
16014
|
-
}
|
|
16015
|
-
conventions.push("- **Indent:** 2 spaces");
|
|
16016
|
-
conventions.push("- **Max line:** 100 chars");
|
|
16017
|
-
conventions.push("");
|
|
16018
|
-
conventions.push("### Git Workflow");
|
|
16019
|
-
conventions.push("- **Branch naming:** `feature/description` or `fix/description`");
|
|
16020
|
-
conventions.push("- **Commits:** Conventional commits format (feat/fix/chore/docs)");
|
|
16021
|
-
conventions.push("- **PRs:** Review required before merge");
|
|
16022
|
-
return conventions.join("\n");
|
|
16023
|
-
}
|
|
16024
|
-
function generateCriticalGuardrails(info) {
|
|
16025
|
-
const guardrails = ["## Critical Guardrails", ""];
|
|
16026
|
-
guardrails.push("\u26A0\uFE0F **NEVER:**");
|
|
16027
|
-
guardrails.push("- Commit to main/production branches directly");
|
|
16028
|
-
guardrails.push("- Skip tests before pushing");
|
|
16029
|
-
guardrails.push("- Expose API keys or credentials in code");
|
|
16030
|
-
if (info.dependencies.includes("prisma") || info.dependencies.includes("typeorm")) {
|
|
16031
|
-
guardrails.push("- Modify database migrations without approval");
|
|
16032
|
-
}
|
|
16033
|
-
guardrails.push("");
|
|
16034
|
-
guardrails.push("\u2705 **ALWAYS:**");
|
|
16035
|
-
guardrails.push(`- Run \`${info.packageManager} test\` before pushing`);
|
|
16036
|
-
if (info.linter) {
|
|
16037
|
-
guardrails.push(`- Run \`${info.packageManager} run lint\` to check code style`);
|
|
16038
|
-
}
|
|
16039
|
-
if (info.formatter) {
|
|
16040
|
-
guardrails.push(`- Format code with ${info.formatter} before committing`);
|
|
16041
|
-
}
|
|
16042
|
-
guardrails.push("- Document breaking changes");
|
|
16043
|
-
guardrails.push("- Add tests for new features");
|
|
16044
|
-
return guardrails.join("\n");
|
|
16045
|
-
}
|
|
16046
|
-
function generateCommands(info) {
|
|
16047
|
-
const sections = ["## Canonical Commands", ""];
|
|
16048
|
-
if (!info.categorizedScripts) {
|
|
16049
|
-
return sections.join("\n") + "```bash\n# No scripts detected\n```";
|
|
16050
|
-
}
|
|
16051
|
-
const categories = [
|
|
16052
|
-
{ key: "development", title: "Development" },
|
|
16053
|
-
{ key: "building", title: "Building" },
|
|
16054
|
-
{ key: "testing", title: "Testing" },
|
|
16055
|
-
{ key: "quality", title: "Quality Checks" },
|
|
16056
|
-
{ key: "deployment", title: "Deployment" }
|
|
16057
|
-
];
|
|
16058
|
-
sections.push("```bash");
|
|
16059
|
-
for (const { key, title } of categories) {
|
|
16060
|
-
const scripts = info.categorizedScripts[key];
|
|
16061
|
-
if (scripts && scripts.length > 0) {
|
|
16062
|
-
sections.push(`# ${title}`);
|
|
16063
|
-
for (const script of scripts) {
|
|
16064
|
-
const cmd = `${info.packageManager} run ${script.name}`;
|
|
16065
|
-
const padding = " ".repeat(Math.max(35 - cmd.length, 1));
|
|
16066
|
-
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;
|
|
16067
16723
|
}
|
|
16068
|
-
sections.push("");
|
|
16069
|
-
}
|
|
16070
|
-
}
|
|
16071
|
-
const other = info.categorizedScripts.other;
|
|
16072
|
-
if (other && other.length > 0) {
|
|
16073
|
-
sections.push("# Other");
|
|
16074
|
-
for (const script of other) {
|
|
16075
|
-
const cmd = `${info.packageManager} run ${script.name}`;
|
|
16076
|
-
const padding = " ".repeat(Math.max(35 - cmd.length, 1));
|
|
16077
|
-
sections.push(`${cmd}${padding}# ${script.description}`);
|
|
16078
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;
|
|
16079
16737
|
}
|
|
16080
|
-
sections.push("```");
|
|
16081
|
-
return sections.join("\n");
|
|
16082
|
-
}
|
|
16083
|
-
function generateUsefulLinks(info) {
|
|
16084
|
-
const links = ["## Useful Links", ""];
|
|
16085
|
-
if (info.repository) {
|
|
16086
|
-
links.push(`- [Repository](${info.repository})`);
|
|
16087
|
-
}
|
|
16088
|
-
if (info.fileStructure?.docsDirectory) {
|
|
16089
|
-
links.push(`- [Documentation](${info.fileStructure.docsDirectory}/)`);
|
|
16090
|
-
}
|
|
16091
|
-
return links.join("\n");
|
|
16092
|
-
}
|
|
16093
|
-
async function atomicWrite(filePath, content) {
|
|
16094
|
-
const tempPath = `${filePath}.tmp`;
|
|
16095
|
-
await writeFile(tempPath, content, "utf-8");
|
|
16096
|
-
await rename(tempPath, filePath);
|
|
16097
16738
|
}
|
|
16098
16739
|
var initCommand = {
|
|
16099
16740
|
command: "init",
|
|
16100
|
-
describe: "Initialize
|
|
16741
|
+
describe: "Initialize project index (ax.index.json) and custom instructions",
|
|
16101
16742
|
builder: (yargs2) => {
|
|
16102
16743
|
return yargs2.option("force", {
|
|
16103
16744
|
alias: "f",
|
|
16104
|
-
describe: "Regenerate
|
|
16745
|
+
describe: "Regenerate all files including CUSTOM.md",
|
|
16746
|
+
type: "boolean",
|
|
16747
|
+
default: false
|
|
16748
|
+
}).option("skip-update", {
|
|
16749
|
+
describe: "Skip AutomatosX version check",
|
|
16105
16750
|
type: "boolean",
|
|
16106
16751
|
default: false
|
|
16107
16752
|
}).example([
|
|
16108
|
-
["$0 init", "Create or update
|
|
16109
|
-
["$0 init --force", "Regenerate
|
|
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"]
|
|
16110
16756
|
]);
|
|
16111
16757
|
},
|
|
16112
16758
|
handler: async (argv) => {
|
|
16113
16759
|
const projectDir = process.cwd();
|
|
16114
|
-
|
|
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");
|
|
16115
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
|
+
}
|
|
16116
16800
|
const projectInfo = await detectProjectInfo(projectDir);
|
|
16117
|
-
|
|
16118
|
-
if (
|
|
16119
|
-
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
linter: projectInfo.linter,
|
|
16128
|
-
formatter: projectInfo.formatter,
|
|
16129
|
-
testFramework: projectInfo.testFramework
|
|
16130
|
-
});
|
|
16131
|
-
if (changes.length === 0) {
|
|
16132
|
-
console.log(chalk5.green("\u2713 AX.md is up to date"));
|
|
16133
|
-
logger.info("AX.md unchanged", { projectName: projectInfo.name });
|
|
16134
|
-
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);
|
|
16135
16811
|
}
|
|
16136
|
-
const axMdContent = generateAXMD(projectInfo);
|
|
16137
|
-
await atomicWrite(axMdPath, axMdContent);
|
|
16138
|
-
const summary = formatChangeSummary(changes);
|
|
16139
|
-
console.log(chalk5.green(`\u2713 Updated AX.md ${summary}`));
|
|
16140
|
-
logger.info("AX.md updated", {
|
|
16141
|
-
projectName: projectInfo.name,
|
|
16142
|
-
changes: changes.length,
|
|
16143
|
-
changeTypes: changes.map((c) => c.type)
|
|
16144
|
-
});
|
|
16145
16812
|
} else {
|
|
16146
|
-
|
|
16147
|
-
|
|
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 {
|
|
16148
16821
|
const projectType = projectInfo.framework || projectInfo.language;
|
|
16149
|
-
console.log(chalk5.green(`\u2713 Created
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
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)"));
|
|
16156
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
|
+
});
|
|
16157
16849
|
} catch (error) {
|
|
16158
|
-
console.log(chalk5.red("\u2717 Error
|
|
16159
|
-
logger.error("
|
|
16850
|
+
console.log(chalk5.red("\u2717 Error initializing project"));
|
|
16851
|
+
logger.error("Project initialization failed", { error });
|
|
16160
16852
|
if (process.env.DEBUG || process.env.AUTOMATOSX_DEBUG) {
|
|
16161
16853
|
printError(error);
|
|
16162
16854
|
}
|
|
@@ -16677,107 +17369,7 @@ init_logger();
|
|
|
16677
17369
|
// src/shared/utils/disposable.ts
|
|
16678
17370
|
init_esm_shims();
|
|
16679
17371
|
init_logger();
|
|
16680
|
-
|
|
16681
|
-
// src/shared/utils/safe-timers.ts
|
|
16682
|
-
init_esm_shims();
|
|
16683
|
-
init_logger();
|
|
16684
|
-
function createSafeInterval(callback, intervalMs, options = {}) {
|
|
16685
|
-
const { ref = false, name, signal, immediate = false } = options;
|
|
16686
|
-
if (signal?.aborted) {
|
|
16687
|
-
logger.debug("createSafeInterval: already aborted", { name });
|
|
16688
|
-
return () => {
|
|
16689
|
-
};
|
|
16690
|
-
}
|
|
16691
|
-
let cleared = false;
|
|
16692
|
-
let intervalId = null;
|
|
16693
|
-
const safeCallback = async () => {
|
|
16694
|
-
if (cleared) return;
|
|
16695
|
-
try {
|
|
16696
|
-
await callback();
|
|
16697
|
-
} catch (error) {
|
|
16698
|
-
logger.error("Safe interval callback error", {
|
|
16699
|
-
name,
|
|
16700
|
-
error: error.message
|
|
16701
|
-
});
|
|
16702
|
-
}
|
|
16703
|
-
};
|
|
16704
|
-
if (immediate) {
|
|
16705
|
-
setImmediate(() => {
|
|
16706
|
-
if (!cleared) {
|
|
16707
|
-
safeCallback();
|
|
16708
|
-
}
|
|
16709
|
-
});
|
|
16710
|
-
}
|
|
16711
|
-
intervalId = setInterval(safeCallback, intervalMs);
|
|
16712
|
-
if (!ref && intervalId.unref) {
|
|
16713
|
-
intervalId.unref();
|
|
16714
|
-
}
|
|
16715
|
-
const cleanup = () => {
|
|
16716
|
-
if (cleared) return;
|
|
16717
|
-
cleared = true;
|
|
16718
|
-
if (intervalId !== null) {
|
|
16719
|
-
clearInterval(intervalId);
|
|
16720
|
-
intervalId = null;
|
|
16721
|
-
logger.debug("Safe interval cleared", { name });
|
|
16722
|
-
}
|
|
16723
|
-
};
|
|
16724
|
-
if (signal) {
|
|
16725
|
-
signal.addEventListener("abort", cleanup, { once: true });
|
|
16726
|
-
}
|
|
16727
|
-
logger.debug("Safe interval created", {
|
|
16728
|
-
name,
|
|
16729
|
-
intervalMs,
|
|
16730
|
-
ref,
|
|
16731
|
-
immediate
|
|
16732
|
-
});
|
|
16733
|
-
return cleanup;
|
|
16734
|
-
}
|
|
16735
|
-
function createSafeTimeout(callback, delayMs, options = {}) {
|
|
16736
|
-
const { ref = false, name, signal } = options;
|
|
16737
|
-
if (signal?.aborted) {
|
|
16738
|
-
logger.debug("createSafeTimeout: already aborted", { name });
|
|
16739
|
-
return () => {
|
|
16740
|
-
};
|
|
16741
|
-
}
|
|
16742
|
-
let cleared = false;
|
|
16743
|
-
let timeoutId = null;
|
|
16744
|
-
const safeCallback = async () => {
|
|
16745
|
-
if (cleared) return;
|
|
16746
|
-
cleared = true;
|
|
16747
|
-
try {
|
|
16748
|
-
await callback();
|
|
16749
|
-
} catch (error) {
|
|
16750
|
-
logger.error("Safe timeout callback error", {
|
|
16751
|
-
name,
|
|
16752
|
-
error: error.message
|
|
16753
|
-
});
|
|
16754
|
-
}
|
|
16755
|
-
};
|
|
16756
|
-
timeoutId = setTimeout(safeCallback, delayMs);
|
|
16757
|
-
if (!ref && timeoutId.unref) {
|
|
16758
|
-
timeoutId.unref();
|
|
16759
|
-
}
|
|
16760
|
-
const cleanup = () => {
|
|
16761
|
-
if (cleared) return;
|
|
16762
|
-
cleared = true;
|
|
16763
|
-
if (timeoutId !== null) {
|
|
16764
|
-
clearTimeout(timeoutId);
|
|
16765
|
-
timeoutId = null;
|
|
16766
|
-
logger.debug("Safe timeout cleared", { name });
|
|
16767
|
-
}
|
|
16768
|
-
};
|
|
16769
|
-
if (signal) {
|
|
16770
|
-
signal.addEventListener("abort", cleanup, { once: true });
|
|
16771
|
-
}
|
|
16772
|
-
logger.debug("Safe timeout created", {
|
|
16773
|
-
name,
|
|
16774
|
-
delayMs,
|
|
16775
|
-
ref
|
|
16776
|
-
});
|
|
16777
|
-
return cleanup;
|
|
16778
|
-
}
|
|
16779
|
-
|
|
16780
|
-
// src/shared/utils/disposable.ts
|
|
17372
|
+
init_safe_timers();
|
|
16781
17373
|
var DisposableEventEmitter = class extends EventEmitter {
|
|
16782
17374
|
/** Registered cleanup tasks */
|
|
16783
17375
|
cleanupTasks = [];
|
|
@@ -19968,7 +20560,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
19968
20560
|
if (this.db) {
|
|
19969
20561
|
try {
|
|
19970
20562
|
this.db.close();
|
|
19971
|
-
} catch
|
|
20563
|
+
} catch {
|
|
19972
20564
|
}
|
|
19973
20565
|
this.initialized = false;
|
|
19974
20566
|
this.entryCount = 0;
|
|
@@ -20722,9 +21314,9 @@ var MemoryManager = class _MemoryManager {
|
|
|
20722
21314
|
throw new MemoryError("Memory manager not initialized", "DATABASE_ERROR");
|
|
20723
21315
|
}
|
|
20724
21316
|
try {
|
|
20725
|
-
const { mkdir:
|
|
21317
|
+
const { mkdir: mkdir15 } = await import('fs/promises');
|
|
20726
21318
|
const destDir = dirname4(destPath);
|
|
20727
|
-
await
|
|
21319
|
+
await mkdir15(destDir, { recursive: true });
|
|
20728
21320
|
await this.db.backup(destPath);
|
|
20729
21321
|
logger.info("Database backup created", { destPath: normalizePath(destPath) });
|
|
20730
21322
|
} catch (error) {
|
|
@@ -20809,9 +21401,9 @@ var MemoryManager = class _MemoryManager {
|
|
|
20809
21401
|
}
|
|
20810
21402
|
}
|
|
20811
21403
|
const {
|
|
20812
|
-
includeEmbeddings = false,
|
|
21404
|
+
includeEmbeddings: _includeEmbeddings = false,
|
|
20813
21405
|
filters = {},
|
|
20814
|
-
batchSize = 1e3,
|
|
21406
|
+
batchSize: _batchSize = 1e3,
|
|
20815
21407
|
pretty = false
|
|
20816
21408
|
} = options || {};
|
|
20817
21409
|
try {
|
|
@@ -21969,7 +22561,7 @@ var SessionManager = class _SessionManager {
|
|
|
21969
22561
|
if (this.pendingSave) {
|
|
21970
22562
|
try {
|
|
21971
22563
|
await this.pendingSave;
|
|
21972
|
-
} catch
|
|
22564
|
+
} catch {
|
|
21973
22565
|
}
|
|
21974
22566
|
}
|
|
21975
22567
|
this.pendingSave = this.doSave().finally(() => {
|
|
@@ -22037,7 +22629,7 @@ var SessionManager = class _SessionManager {
|
|
|
22037
22629
|
}
|
|
22038
22630
|
try {
|
|
22039
22631
|
await unlink(tempPath);
|
|
22040
|
-
} catch
|
|
22632
|
+
} catch {
|
|
22041
22633
|
}
|
|
22042
22634
|
throw renameError;
|
|
22043
22635
|
}
|
|
@@ -22045,7 +22637,7 @@ var SessionManager = class _SessionManager {
|
|
|
22045
22637
|
const tempPath = `${this.persistencePath}.tmp`;
|
|
22046
22638
|
try {
|
|
22047
22639
|
await unlink(tempPath);
|
|
22048
|
-
} catch
|
|
22640
|
+
} catch {
|
|
22049
22641
|
}
|
|
22050
22642
|
logger.error("Failed to save sessions to persistence", {
|
|
22051
22643
|
path: normalizePath(this.persistencePath),
|
|
@@ -22584,6 +23176,7 @@ init_esm_shims();
|
|
|
22584
23176
|
init_logger();
|
|
22585
23177
|
var MAX_CONTEXT_SIZE = 100 * 1024;
|
|
22586
23178
|
var DEFAULT_CACHE_TTL = 3e5;
|
|
23179
|
+
var STALE_THRESHOLD_MS2 = 24 * 60 * 60 * 1e3;
|
|
22587
23180
|
var ProjectContextLoader = class {
|
|
22588
23181
|
constructor(projectRoot, options) {
|
|
22589
23182
|
this.projectRoot = projectRoot;
|
|
@@ -22607,76 +23200,79 @@ var ProjectContextLoader = class {
|
|
|
22607
23200
|
});
|
|
22608
23201
|
const context = {};
|
|
22609
23202
|
try {
|
|
22610
|
-
const
|
|
22611
|
-
const resolvedPath = await realpath$1(
|
|
23203
|
+
const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
|
|
23204
|
+
const resolvedPath = await realpath$1(indexPath).catch(() => null);
|
|
22612
23205
|
if (resolvedPath) {
|
|
22613
23206
|
const rel = path4__default.relative(this.projectRoot, resolvedPath);
|
|
22614
23207
|
if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
|
|
22615
23208
|
const stats = await stat(resolvedPath);
|
|
22616
23209
|
if (stats.size > MAX_CONTEXT_SIZE) {
|
|
22617
|
-
logger.warn("
|
|
23210
|
+
logger.warn("ax.index.json too large, ignoring", {
|
|
22618
23211
|
size: stats.size,
|
|
22619
23212
|
limit: MAX_CONTEXT_SIZE
|
|
22620
23213
|
});
|
|
22621
23214
|
} else {
|
|
22622
|
-
|
|
22623
|
-
|
|
22624
|
-
|
|
22625
|
-
|
|
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))
|
|
22626
23225
|
});
|
|
22627
|
-
|
|
22628
|
-
|
|
22629
|
-
|
|
22630
|
-
|
|
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
|
+
}
|
|
22631
23232
|
}
|
|
22632
23233
|
}
|
|
22633
23234
|
}
|
|
22634
23235
|
} catch (error) {
|
|
22635
23236
|
if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
|
|
22636
|
-
logger.warn("Error loading
|
|
23237
|
+
logger.warn("Error loading ax.index.json", { error });
|
|
22637
23238
|
}
|
|
22638
23239
|
}
|
|
22639
23240
|
try {
|
|
22640
|
-
const
|
|
22641
|
-
const resolvedPath = await realpath$1(
|
|
23241
|
+
const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
|
|
23242
|
+
const resolvedPath = await realpath$1(customMdPath).catch(() => null);
|
|
22642
23243
|
if (resolvedPath) {
|
|
22643
23244
|
const rel = path4__default.relative(this.projectRoot, resolvedPath);
|
|
22644
23245
|
if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
|
|
22645
23246
|
const stats = await stat(resolvedPath);
|
|
22646
23247
|
if (stats.size > MAX_CONTEXT_SIZE) {
|
|
22647
|
-
logger.warn("
|
|
23248
|
+
logger.warn("CUSTOM.md too large, ignoring", {
|
|
22648
23249
|
size: stats.size,
|
|
22649
23250
|
limit: MAX_CONTEXT_SIZE
|
|
22650
23251
|
});
|
|
22651
23252
|
} else {
|
|
22652
|
-
|
|
22653
|
-
|
|
22654
|
-
|
|
22655
|
-
|
|
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
|
|
22656
23257
|
});
|
|
22657
|
-
|
|
22658
|
-
context.commands = { ...context.commands, ...context.config.commands };
|
|
22659
|
-
}
|
|
22660
|
-
if (context.config.project) {
|
|
22661
|
-
context.metadata = { ...context.metadata, ...context.config.project };
|
|
22662
|
-
}
|
|
23258
|
+
context.guardrails = this.parseGuardrails(context.customInstructions);
|
|
22663
23259
|
}
|
|
22664
23260
|
}
|
|
22665
23261
|
}
|
|
22666
23262
|
} catch (error) {
|
|
22667
23263
|
if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
|
|
22668
|
-
logger.warn("Error loading
|
|
23264
|
+
logger.warn("Error loading CUSTOM.md", { error });
|
|
22669
23265
|
}
|
|
22670
23266
|
}
|
|
22671
23267
|
context.contextPrompt = this.buildContextPrompt(context);
|
|
22672
23268
|
this.cache = context;
|
|
22673
23269
|
this.cacheExpiry = Date.now() + this.cacheTTL;
|
|
22674
23270
|
logger.info("Project context loaded", {
|
|
22675
|
-
|
|
22676
|
-
|
|
22677
|
-
agentRules: context.agentRules?.length ?? 0,
|
|
23271
|
+
hasIndex: !!context.index,
|
|
23272
|
+
hasCustomInstructions: !!context.customInstructions,
|
|
22678
23273
|
guardrails: context.guardrails?.length ?? 0,
|
|
22679
|
-
commands: Object.keys(context.commands ?? {}).length
|
|
23274
|
+
commands: Object.keys(context.commands ?? {}).length,
|
|
23275
|
+
isStale: context.isStale
|
|
22680
23276
|
});
|
|
22681
23277
|
return context;
|
|
22682
23278
|
}
|
|
@@ -22692,8 +23288,8 @@ var ProjectContextLoader = class {
|
|
|
22692
23288
|
* Check if context exists (without loading)
|
|
22693
23289
|
*/
|
|
22694
23290
|
async exists() {
|
|
22695
|
-
const
|
|
22696
|
-
const
|
|
23291
|
+
const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
|
|
23292
|
+
const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
|
|
22697
23293
|
const checkExists3 = async (filePath) => {
|
|
22698
23294
|
try {
|
|
22699
23295
|
await access$1(filePath, constants.F_OK);
|
|
@@ -22702,57 +23298,48 @@ var ProjectContextLoader = class {
|
|
|
22702
23298
|
return false;
|
|
22703
23299
|
}
|
|
22704
23300
|
};
|
|
22705
|
-
const [
|
|
22706
|
-
checkExists3(
|
|
22707
|
-
checkExists3(
|
|
23301
|
+
const [indexExists, customMdExists] = await Promise.all([
|
|
23302
|
+
checkExists3(indexPath),
|
|
23303
|
+
checkExists3(customMdPath)
|
|
22708
23304
|
]);
|
|
22709
|
-
return
|
|
23305
|
+
return indexExists || customMdExists;
|
|
22710
23306
|
}
|
|
22711
23307
|
/**
|
|
22712
|
-
*
|
|
22713
|
-
*
|
|
22714
|
-
* Looks for patterns like:
|
|
22715
|
-
* - Backend changes → @backend
|
|
22716
|
-
* - API endpoints → @backend, @security
|
|
23308
|
+
* Check if ax.index.json is stale (older than 24 hours)
|
|
22717
23309
|
*/
|
|
22718
|
-
|
|
22719
|
-
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
return
|
|
22724
|
-
}
|
|
22725
|
-
|
|
22726
|
-
const lineRegex = /^[-*]\s+(.+?)\s+(?:→|->)+\s+(.+?)$/gm;
|
|
22727
|
-
let lineMatch;
|
|
22728
|
-
while ((lineMatch = lineRegex.exec(section)) !== null) {
|
|
22729
|
-
const taskType = lineMatch[1]?.trim() ?? "";
|
|
22730
|
-
const agentsText = lineMatch[2]?.trim() ?? "";
|
|
22731
|
-
const agents = agentsText.split(",").map((a) => a.trim()).filter(Boolean);
|
|
22732
|
-
const defaultAgent = agents[0];
|
|
22733
|
-
if (defaultAgent) {
|
|
22734
|
-
rules.push({
|
|
22735
|
-
taskType,
|
|
22736
|
-
patterns: [],
|
|
22737
|
-
// TODO: Parse file patterns if specified
|
|
22738
|
-
defaultAgent,
|
|
22739
|
-
autoReview: agents.length > 1
|
|
22740
|
-
});
|
|
22741
|
-
}
|
|
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;
|
|
22742
23318
|
}
|
|
22743
|
-
return rules;
|
|
22744
23319
|
}
|
|
22745
23320
|
/**
|
|
22746
|
-
* Parse guardrails
|
|
23321
|
+
* Parse guardrails from CUSTOM.md
|
|
22747
23322
|
*
|
|
22748
|
-
* Looks for
|
|
22749
|
-
* Extracts items marked with ⚠️ or under NEVER headings
|
|
23323
|
+
* Looks for DO/DON'T sections in ax-cli format
|
|
22750
23324
|
*/
|
|
22751
23325
|
parseGuardrails(markdown) {
|
|
22752
23326
|
const guardrails = [];
|
|
22753
|
-
const
|
|
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;
|
|
22754
23341
|
let match;
|
|
22755
|
-
while ((match =
|
|
23342
|
+
while ((match = criticalRegex.exec(markdown)) !== null) {
|
|
22756
23343
|
const section = match[2];
|
|
22757
23344
|
if (!section) continue;
|
|
22758
23345
|
const bulletRegex = /^[-*]\s+(.+?)$/gm;
|
|
@@ -22762,106 +23349,58 @@ var ProjectContextLoader = class {
|
|
|
22762
23349
|
rule = rule.replace(/^[⚠️❌✅✓⚡🔒]+\s*/, "");
|
|
22763
23350
|
rule = rule.replace(/\*\*(.+?)\*\*/g, "$1");
|
|
22764
23351
|
rule = rule.replace(/`(.+?)`/g, "$1");
|
|
22765
|
-
if (rule.length > 0) {
|
|
23352
|
+
if (rule.length > 0 && !guardrails.includes(rule)) {
|
|
22766
23353
|
guardrails.push(rule);
|
|
22767
23354
|
}
|
|
22768
23355
|
}
|
|
22769
23356
|
}
|
|
22770
23357
|
return guardrails;
|
|
22771
23358
|
}
|
|
22772
|
-
/**
|
|
22773
|
-
* Parse commands from markdown code blocks
|
|
22774
|
-
*
|
|
22775
|
-
* Looks for "## Commands" or "## Canonical Commands" section
|
|
22776
|
-
*/
|
|
22777
|
-
parseCommands(markdown) {
|
|
22778
|
-
const commands = {};
|
|
22779
|
-
const sectionRegex = /##\s+(Canonical\s+)?Commands[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
|
|
22780
|
-
const match = markdown.match(sectionRegex);
|
|
22781
|
-
if (!match) {
|
|
22782
|
-
return commands;
|
|
22783
|
-
}
|
|
22784
|
-
const section = match[2];
|
|
22785
|
-
if (!section) {
|
|
22786
|
-
return commands;
|
|
22787
|
-
}
|
|
22788
|
-
const codeBlockRegex = /```(?:bash|sh|shell)?\n([\s\S]*?)```/;
|
|
22789
|
-
const codeMatch = section.match(codeBlockRegex);
|
|
22790
|
-
if (codeMatch && codeMatch[1]) {
|
|
22791
|
-
const lines = codeMatch[1].split("\n");
|
|
22792
|
-
for (const line of lines) {
|
|
22793
|
-
const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#?\s*(.*)$/);
|
|
22794
|
-
if (cmdMatch && cmdMatch[1]) {
|
|
22795
|
-
const cmd = cmdMatch[1].trim();
|
|
22796
|
-
const desc = cmdMatch[2]?.trim() ?? "";
|
|
22797
|
-
const key = desc || cmd;
|
|
22798
|
-
commands[key] = cmd;
|
|
22799
|
-
}
|
|
22800
|
-
}
|
|
22801
|
-
}
|
|
22802
|
-
return commands;
|
|
22803
|
-
}
|
|
22804
|
-
/**
|
|
22805
|
-
* Parse project metadata from markdown frontmatter or first section
|
|
22806
|
-
*/
|
|
22807
|
-
parseMetadata(markdown) {
|
|
22808
|
-
const metadata = {};
|
|
22809
|
-
const lastUpdatedMatch = markdown.match(/>\s*Last\s+updated:\s*(.+?)$/im);
|
|
22810
|
-
if (lastUpdatedMatch && lastUpdatedMatch[1]) {
|
|
22811
|
-
metadata.lastUpdated = lastUpdatedMatch[1].trim();
|
|
22812
|
-
}
|
|
22813
|
-
const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
|
|
22814
|
-
if (projectMatch && projectMatch[1]) {
|
|
22815
|
-
const parts = projectMatch[1].trim().split(/\s+v/);
|
|
22816
|
-
metadata.name = parts[0] || "";
|
|
22817
|
-
if (parts.length > 1 && parts[1]) {
|
|
22818
|
-
metadata.version = parts[1];
|
|
22819
|
-
}
|
|
22820
|
-
}
|
|
22821
|
-
const h1Match = markdown.match(/^#\s+(.+?)$/m);
|
|
22822
|
-
if (h1Match && h1Match[1] && !metadata.name) {
|
|
22823
|
-
metadata.name = h1Match[1].replace(/Project Context for AutomatosX/i, "").trim();
|
|
22824
|
-
}
|
|
22825
|
-
return metadata;
|
|
22826
|
-
}
|
|
22827
23359
|
/**
|
|
22828
23360
|
* Build formatted context prompt for agent injection
|
|
22829
23361
|
*/
|
|
22830
23362
|
buildContextPrompt(context) {
|
|
22831
|
-
if (!context.
|
|
23363
|
+
if (!context.index && !context.customInstructions) {
|
|
22832
23364
|
return "";
|
|
22833
23365
|
}
|
|
22834
23366
|
let prompt = "\n# PROJECT CONTEXT\n\n";
|
|
22835
|
-
if (context.
|
|
22836
|
-
prompt +=
|
|
22837
|
-
context.guardrails.forEach((rule) => {
|
|
22838
|
-
prompt += `- ${rule}
|
|
23367
|
+
if (context.index) {
|
|
23368
|
+
prompt += `**Project:** ${context.index.projectName} v${context.index.version}
|
|
22839
23369
|
`;
|
|
22840
|
-
}
|
|
22841
|
-
prompt += "\n";
|
|
22842
|
-
}
|
|
22843
|
-
if (context.agentRules && context.agentRules.length > 0) {
|
|
22844
|
-
prompt += "## Agent Delegation Rules:\n\n";
|
|
22845
|
-
context.agentRules.forEach((rule) => {
|
|
22846
|
-
prompt += `- ${rule.taskType} \u2192 ${rule.defaultAgent}
|
|
23370
|
+
prompt += `**Type:** ${context.index.projectType}
|
|
22847
23371
|
`;
|
|
22848
|
-
}
|
|
22849
|
-
|
|
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
|
+
}
|
|
22850
23393
|
}
|
|
22851
|
-
if (context.
|
|
22852
|
-
prompt += "##
|
|
22853
|
-
|
|
22854
|
-
prompt += `- ${
|
|
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}
|
|
22855
23398
|
`;
|
|
22856
|
-
}
|
|
23399
|
+
}
|
|
22857
23400
|
prompt += "\n";
|
|
22858
23401
|
}
|
|
22859
|
-
if (context.
|
|
22860
|
-
|
|
22861
|
-
const contextToAdd = context.markdown.length > MAX_PROMPT_LENGTH ? context.markdown.substring(0, MAX_PROMPT_LENGTH) + "\n\n[... context truncated for length ...]" : context.markdown;
|
|
22862
|
-
prompt += "## Full Project Context:\n\n";
|
|
22863
|
-
prompt += contextToAdd;
|
|
22864
|
-
prompt += "\n";
|
|
23402
|
+
if (context.isStale) {
|
|
23403
|
+
prompt += "\u26A0\uFE0F **Note:** Project index is stale (>24h old). Run `ax init` to update.\n\n";
|
|
22865
23404
|
}
|
|
22866
23405
|
return prompt;
|
|
22867
23406
|
}
|
|
@@ -23285,10 +23824,10 @@ var ContextManager = class {
|
|
|
23285
23824
|
return provider;
|
|
23286
23825
|
}
|
|
23287
23826
|
/**
|
|
23288
|
-
* Load project context from
|
|
23827
|
+
* Load project context from ax.index.json (v12.9.0+)
|
|
23289
23828
|
*
|
|
23290
|
-
* Loads project-specific
|
|
23291
|
-
* Falls back gracefully if
|
|
23829
|
+
* Loads project-specific context from ax.index.json and CUSTOM.md.
|
|
23830
|
+
* Falls back gracefully if files don't exist.
|
|
23292
23831
|
*
|
|
23293
23832
|
* @param projectDir - Project root directory
|
|
23294
23833
|
* @returns Project context or null if not found
|
|
@@ -23301,15 +23840,15 @@ var ContextManager = class {
|
|
|
23301
23840
|
const loader = this.projectContextLoader;
|
|
23302
23841
|
const exists = await loader.exists();
|
|
23303
23842
|
if (!exists) {
|
|
23304
|
-
logger.debug("No
|
|
23843
|
+
logger.debug("No ax.index.json or CUSTOM.md found, skipping project context");
|
|
23305
23844
|
return null;
|
|
23306
23845
|
}
|
|
23307
23846
|
const context = await loader.load();
|
|
23308
|
-
logger.debug("Project context loaded
|
|
23309
|
-
|
|
23310
|
-
|
|
23311
|
-
|
|
23312
|
-
|
|
23847
|
+
logger.debug("Project context loaded", {
|
|
23848
|
+
hasIndex: !!context.index,
|
|
23849
|
+
hasCustomInstructions: !!context.customInstructions,
|
|
23850
|
+
guardrails: context.guardrails?.length ?? 0,
|
|
23851
|
+
isStale: context.isStale
|
|
23313
23852
|
});
|
|
23314
23853
|
return context;
|
|
23315
23854
|
} catch (error) {
|
|
@@ -26239,6 +26778,24 @@ ${context.task}`;
|
|
|
26239
26778
|
// src/agents/agent-selector.ts
|
|
26240
26779
|
init_esm_shims();
|
|
26241
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
|
+
}
|
|
26242
26799
|
function scoreAgent(task, profile) {
|
|
26243
26800
|
let score = 0;
|
|
26244
26801
|
const taskLower = task.toLowerCase();
|
|
@@ -26276,16 +26833,9 @@ function scoreAgent(task, profile) {
|
|
|
26276
26833
|
}
|
|
26277
26834
|
if (profile.selectionMetadata?.redirectWhen) {
|
|
26278
26835
|
for (const rule of profile.selectionMetadata.redirectWhen) {
|
|
26279
|
-
|
|
26280
|
-
|
|
26281
|
-
|
|
26282
|
-
score -= 15;
|
|
26283
|
-
}
|
|
26284
|
-
} catch (error) {
|
|
26285
|
-
logger.debug("Invalid regex pattern in redirectWhen rule", {
|
|
26286
|
-
pattern: rule.phrase,
|
|
26287
|
-
error: error instanceof Error ? error.message : String(error)
|
|
26288
|
-
});
|
|
26836
|
+
const regex = getCachedRegex(rule.phrase);
|
|
26837
|
+
if (regex && regex.test(task)) {
|
|
26838
|
+
score -= 15;
|
|
26289
26839
|
}
|
|
26290
26840
|
}
|
|
26291
26841
|
}
|
|
@@ -28643,7 +29193,7 @@ var BugDetector = class {
|
|
|
28643
29193
|
});
|
|
28644
29194
|
let files;
|
|
28645
29195
|
if (fileFilter && fileFilter.length > 0) {
|
|
28646
|
-
files = fileFilter.map((f) => f
|
|
29196
|
+
files = fileFilter.map((f) => isAbsolute(f) ? f : join(rootDir, f)).filter((f) => {
|
|
28647
29197
|
const ext = extname$1(f);
|
|
28648
29198
|
return [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"].includes(ext);
|
|
28649
29199
|
}).filter((f) => !this.isExcluded(relative(rootDir, f)));
|
|
@@ -28875,8 +29425,8 @@ var BugDetector = class {
|
|
|
28875
29425
|
async loadRulesFromFile(filePath) {
|
|
28876
29426
|
try {
|
|
28877
29427
|
const content = await readFile(filePath, "utf-8");
|
|
28878
|
-
const
|
|
28879
|
-
const parsed =
|
|
29428
|
+
const yaml4 = await import('js-yaml');
|
|
29429
|
+
const parsed = yaml4.load(content);
|
|
28880
29430
|
if (parsed.rules && Array.isArray(parsed.rules)) {
|
|
28881
29431
|
for (const rule of parsed.rules) {
|
|
28882
29432
|
this.addRule(rule);
|
|
@@ -29308,7 +29858,6 @@ var BugFixer = class {
|
|
|
29308
29858
|
}
|
|
29309
29859
|
const directSetIntervalPattern = /setInterval\s*\(/;
|
|
29310
29860
|
if (directSetIntervalPattern.test(line)) {
|
|
29311
|
-
line.match(/^(\s*)/)?.[1] || "";
|
|
29312
29861
|
const newLine = line.replace(
|
|
29313
29862
|
/(setInterval\s*\([^)]+\))/,
|
|
29314
29863
|
"const _interval = $1; if (_interval.unref) _interval.unref()"
|
|
@@ -29335,7 +29884,6 @@ var BugFixer = class {
|
|
|
29335
29884
|
const match = currentLine.match(classPattern);
|
|
29336
29885
|
if (match && match[1]) {
|
|
29337
29886
|
classStartLine = i;
|
|
29338
|
-
match[1];
|
|
29339
29887
|
break;
|
|
29340
29888
|
}
|
|
29341
29889
|
}
|
|
@@ -29387,7 +29935,7 @@ var BugFixer = class {
|
|
|
29387
29935
|
/**
|
|
29388
29936
|
* Apply use DisposableEventEmitter fix
|
|
29389
29937
|
*/
|
|
29390
|
-
applyUseDisposableEventEmitterFix(finding, originalContent,
|
|
29938
|
+
applyUseDisposableEventEmitterFix(finding, originalContent, _lines) {
|
|
29391
29939
|
let fixedContent = originalContent.replace(
|
|
29392
29940
|
/extends\s+EventEmitter\b/g,
|
|
29393
29941
|
"extends DisposableEventEmitter"
|
|
@@ -30309,7 +30857,7 @@ var DUPLICATION_RULES = [
|
|
|
30309
30857
|
suggestion: "Extract to a named constant"
|
|
30310
30858
|
}
|
|
30311
30859
|
];
|
|
30312
|
-
function detectDuplication(filePath, content, lines, ignoreState,
|
|
30860
|
+
function detectDuplication(filePath, content, lines, ignoreState, _config) {
|
|
30313
30861
|
const findings = [];
|
|
30314
30862
|
findings.push(...detectDuplicateBlocks(filePath, content, lines, ignoreState));
|
|
30315
30863
|
findings.push(...detectRepeatedConditionals(filePath, content, lines, ignoreState));
|
|
@@ -30336,7 +30884,7 @@ function detectDuplicateBlocks(filePath, content, lines, ignoreState) {
|
|
|
30336
30884
|
}
|
|
30337
30885
|
blockHashes.get(blockHash).push({ start: i + 1, end: i + MIN_BLOCK_SIZE });
|
|
30338
30886
|
}
|
|
30339
|
-
for (const [
|
|
30887
|
+
for (const [_hash, locations] of blockHashes) {
|
|
30340
30888
|
if (locations.length > 1) {
|
|
30341
30889
|
for (let i = 1; i < locations.length; i++) {
|
|
30342
30890
|
const loc = locations[i];
|
|
@@ -30385,7 +30933,7 @@ function detectRepeatedConditionals(filePath, content, lines, ignoreState) {
|
|
|
30385
30933
|
}
|
|
30386
30934
|
conditionPattern.lastIndex = 0;
|
|
30387
30935
|
}
|
|
30388
|
-
for (const [
|
|
30936
|
+
for (const [_condition, lineNums] of conditionalCounts) {
|
|
30389
30937
|
if (lineNums.length >= 2) {
|
|
30390
30938
|
const firstLine = lineNums[0];
|
|
30391
30939
|
const secondLine = lineNums[1];
|
|
@@ -30548,7 +31096,7 @@ var THRESHOLDS = {
|
|
|
30548
31096
|
maxCyclomaticComplexity: 10,
|
|
30549
31097
|
maxChainedCalls: 4
|
|
30550
31098
|
};
|
|
30551
|
-
function detectReadability(filePath, content, lines, ignoreState,
|
|
31099
|
+
function detectReadability(filePath, content, lines, ignoreState, _config) {
|
|
30552
31100
|
const findings = [];
|
|
30553
31101
|
findings.push(...detectLongFunctions(filePath, content, lines, ignoreState));
|
|
30554
31102
|
findings.push(...detectDeepNesting(filePath, content, lines, ignoreState));
|
|
@@ -30924,7 +31472,7 @@ var PERFORMANCE_RULES = [
|
|
|
30924
31472
|
suggestion: "Remove await - async functions automatically wrap return values in promises"
|
|
30925
31473
|
}
|
|
30926
31474
|
];
|
|
30927
|
-
function detectPerformance(filePath, content, lines, ignoreState,
|
|
31475
|
+
function detectPerformance(filePath, content, lines, ignoreState, _config) {
|
|
30928
31476
|
const findings = [];
|
|
30929
31477
|
findings.push(...detectSyncInAsync(filePath, content, lines, ignoreState));
|
|
30930
31478
|
findings.push(...detectNPlusOne(filePath, content, lines, ignoreState));
|
|
@@ -31339,7 +31887,7 @@ var HARDCODE_RULES = [
|
|
|
31339
31887
|
suggestion: "Extract timeout to a named constant or config"
|
|
31340
31888
|
}
|
|
31341
31889
|
];
|
|
31342
|
-
function detectHardcode(filePath, content, lines, ignoreState,
|
|
31890
|
+
function detectHardcode(filePath, content, lines, ignoreState, _config) {
|
|
31343
31891
|
const findings = [];
|
|
31344
31892
|
findings.push(...detectMagicNumbers(filePath, content, lines, ignoreState));
|
|
31345
31893
|
findings.push(...detectHardcodedUrls(filePath, content, lines, ignoreState));
|
|
@@ -31695,7 +32243,7 @@ var NAMING_RULES = [
|
|
|
31695
32243
|
suggestion: "Use is/has/can/should prefix for boolean variables"
|
|
31696
32244
|
}
|
|
31697
32245
|
];
|
|
31698
|
-
function detectNaming(filePath, content, lines, ignoreState,
|
|
32246
|
+
function detectNaming(filePath, content, lines, ignoreState, _config) {
|
|
31699
32247
|
const findings = [];
|
|
31700
32248
|
findings.push(...detectSingleLetterVariables(filePath, content, lines, ignoreState));
|
|
31701
32249
|
findings.push(...detectHungarianNotation(filePath, content, lines, ignoreState));
|
|
@@ -31978,7 +32526,7 @@ var CONDITIONAL_RULES = [
|
|
|
31978
32526
|
suggestion: "Use the condition directly (or negate it)"
|
|
31979
32527
|
}
|
|
31980
32528
|
];
|
|
31981
|
-
function detectConditionals(filePath, content, lines, ignoreState,
|
|
32529
|
+
function detectConditionals(filePath, content, lines, ignoreState, _config) {
|
|
31982
32530
|
const findings = [];
|
|
31983
32531
|
findings.push(...detectDeeplyNestedIf(filePath, content, lines, ignoreState));
|
|
31984
32532
|
findings.push(...detectComplexConditions(filePath, content, lines, ignoreState));
|
|
@@ -32291,7 +32839,7 @@ var DEAD_CODE_RULES = [
|
|
|
32291
32839
|
suggestion: "Implement function or add TODO comment"
|
|
32292
32840
|
}
|
|
32293
32841
|
];
|
|
32294
|
-
function detectDeadCode(filePath, content, lines, ignoreState,
|
|
32842
|
+
function detectDeadCode(filePath, content, lines, ignoreState, _config) {
|
|
32295
32843
|
const findings = [];
|
|
32296
32844
|
findings.push(...detectUnusedImports(filePath, content, lines, ignoreState));
|
|
32297
32845
|
findings.push(...detectUnusedVariables(filePath, content, lines, ignoreState));
|
|
@@ -32585,7 +33133,7 @@ var TYPE_SAFETY_RULES = [
|
|
|
32585
33133
|
fileExtensions: [".ts", ".tsx"]
|
|
32586
33134
|
}
|
|
32587
33135
|
];
|
|
32588
|
-
function detectTypeSafety(filePath, content, lines, ignoreState,
|
|
33136
|
+
function detectTypeSafety(filePath, content, lines, ignoreState, _config) {
|
|
32589
33137
|
const findings = [];
|
|
32590
33138
|
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
|
|
32591
33139
|
return findings;
|
|
@@ -33191,6 +33739,9 @@ function countAnyTypes(code) {
|
|
|
33191
33739
|
}
|
|
33192
33740
|
return count;
|
|
33193
33741
|
}
|
|
33742
|
+
function escapeRegex2(str) {
|
|
33743
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33744
|
+
}
|
|
33194
33745
|
function countUnusedImports(code) {
|
|
33195
33746
|
const importMatches = code.match(/import\s+{([^}]+)}\s+from/g);
|
|
33196
33747
|
if (!importMatches) return 0;
|
|
@@ -33200,10 +33751,17 @@ function countUnusedImports(code) {
|
|
|
33200
33751
|
const namedImports = importMatch.match(/{([^}]+)}/);
|
|
33201
33752
|
const namedImportContent = namedImports?.[1];
|
|
33202
33753
|
if (namedImportContent) {
|
|
33203
|
-
const names = namedImportContent.split(",").map((n) =>
|
|
33754
|
+
const names = namedImportContent.split(",").map((n) => {
|
|
33755
|
+
const trimmed = n.trim();
|
|
33756
|
+
const withoutType = trimmed.replace(/^type\s+/, "");
|
|
33757
|
+
return withoutType.split(/\s+as\s+/).pop()?.trim() ?? "";
|
|
33758
|
+
}).filter((name) => name.length > 0 && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name));
|
|
33204
33759
|
for (const name of names) {
|
|
33205
|
-
|
|
33206
|
-
|
|
33760
|
+
try {
|
|
33761
|
+
if (!new RegExp(`\\b${escapeRegex2(name)}\\b`).test(codeWithoutImports)) {
|
|
33762
|
+
unusedCount++;
|
|
33763
|
+
}
|
|
33764
|
+
} catch {
|
|
33207
33765
|
}
|
|
33208
33766
|
}
|
|
33209
33767
|
}
|
|
@@ -36659,6 +37217,7 @@ init_logger();
|
|
|
36659
37217
|
// src/core/task-engine/task-queue.ts
|
|
36660
37218
|
init_esm_shims();
|
|
36661
37219
|
init_logger();
|
|
37220
|
+
init_safe_timers();
|
|
36662
37221
|
|
|
36663
37222
|
// src/mcp/tools/task/create-task.ts
|
|
36664
37223
|
init_logger();
|
|
@@ -36783,7 +37342,7 @@ var createTaskSchema = {
|
|
|
36783
37342
|
// src/mcp/tools/task/run-task.ts
|
|
36784
37343
|
init_esm_shims();
|
|
36785
37344
|
init_logger();
|
|
36786
|
-
function createRunTaskHandler(
|
|
37345
|
+
function createRunTaskHandler(_deps) {
|
|
36787
37346
|
return async (input, context) => {
|
|
36788
37347
|
const startTime = Date.now();
|
|
36789
37348
|
if (context?.signal?.aborted) {
|
|
@@ -39333,6 +39892,17 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
39333
39892
|
mode: "sdk"
|
|
39334
39893
|
}));
|
|
39335
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
|
+
}
|
|
39336
39906
|
const healthCheckInterval = config.router?.healthCheckInterval;
|
|
39337
39907
|
this.router = new Router({
|
|
39338
39908
|
providers,
|
|
@@ -40894,6 +41464,7 @@ function createResourceEnforcer(config) {
|
|
|
40894
41464
|
|
|
40895
41465
|
// src/mcp/unified-manager.ts
|
|
40896
41466
|
init_validation_limits();
|
|
41467
|
+
init_safe_timers();
|
|
40897
41468
|
var UnifiedMCPManager = class {
|
|
40898
41469
|
constructor(config) {
|
|
40899
41470
|
this.config = config;
|
|
@@ -41013,7 +41584,7 @@ var UnifiedMCPManager = class {
|
|
|
41013
41584
|
};
|
|
41014
41585
|
this.setupProcessHandlers(config.name, childProcess, serverProcess);
|
|
41015
41586
|
this.servers.set(config.name, serverProcess);
|
|
41016
|
-
await
|
|
41587
|
+
await sleep(100);
|
|
41017
41588
|
if (childProcess.killed || childProcess.exitCode !== null) {
|
|
41018
41589
|
throw new Error(
|
|
41019
41590
|
`Server process exited immediately with code ${childProcess.exitCode}`
|
|
@@ -41124,7 +41695,7 @@ var UnifiedMCPManager = class {
|
|
|
41124
41695
|
async restartServer(serverName) {
|
|
41125
41696
|
logger.info("UnifiedMCPManager: Restarting server", { name: serverName });
|
|
41126
41697
|
await this.stopServer(serverName);
|
|
41127
|
-
await
|
|
41698
|
+
await sleep(1e3);
|
|
41128
41699
|
const serverConfig = this.config.servers.find((s) => s.name === serverName);
|
|
41129
41700
|
if (!serverConfig) {
|
|
41130
41701
|
throw new Error(`Server configuration not found: ${serverName}`);
|
|
@@ -42895,7 +43466,7 @@ var CheckpointManager = class {
|
|
|
42895
43466
|
if (checkpoint.schemaVersion === CURRENT_SCHEMA_VERSION) {
|
|
42896
43467
|
return checkpoint;
|
|
42897
43468
|
}
|
|
42898
|
-
|
|
43469
|
+
const migrated = { ...checkpoint };
|
|
42899
43470
|
if (checkpointVersion.major === 1 && checkpointVersion.minor === 0) ;
|
|
42900
43471
|
migrated.schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
42901
43472
|
migrated.checksum = this.calculateChecksum(migrated);
|
|
@@ -43001,7 +43572,7 @@ var CheckpointManager = class {
|
|
|
43001
43572
|
* @returns Hex-encoded checksum
|
|
43002
43573
|
*/
|
|
43003
43574
|
calculateChecksum(checkpoint) {
|
|
43004
|
-
const { checksum, updatedAt, ...dataForChecksum } = checkpoint;
|
|
43575
|
+
const { checksum: _checksum, updatedAt: _updatedAt, ...dataForChecksum } = checkpoint;
|
|
43005
43576
|
const hash = createHash("sha256");
|
|
43006
43577
|
hash.update(JSON.stringify(dataForChecksum));
|
|
43007
43578
|
return hash.digest("hex");
|
|
@@ -43650,6 +44221,7 @@ var ProgressRenderer = class {
|
|
|
43650
44221
|
|
|
43651
44222
|
// src/core/stage-execution-controller.ts
|
|
43652
44223
|
init_logger();
|
|
44224
|
+
init_safe_timers();
|
|
43653
44225
|
var StageExecutionController = class {
|
|
43654
44226
|
// Dependencies
|
|
43655
44227
|
agentExecutor;
|
|
@@ -44316,9 +44888,9 @@ ${action.modifications}`;
|
|
|
44316
44888
|
)
|
|
44317
44889
|
);
|
|
44318
44890
|
console.log(chalk5.gray(` Waiting ${delay}ms before retry...`));
|
|
44319
|
-
await
|
|
44891
|
+
await sleep(delay);
|
|
44320
44892
|
} else {
|
|
44321
|
-
await
|
|
44893
|
+
await sleep(delay);
|
|
44322
44894
|
}
|
|
44323
44895
|
}
|
|
44324
44896
|
const executionOptions = {
|
|
@@ -45744,7 +46316,7 @@ var IterateModeController = class {
|
|
|
45744
46316
|
}
|
|
45745
46317
|
});
|
|
45746
46318
|
const responseContents = [];
|
|
45747
|
-
|
|
46319
|
+
const totalTokensUsed = { prompt: 0, completion: 0, total: 0 };
|
|
45748
46320
|
let lastResponse;
|
|
45749
46321
|
try {
|
|
45750
46322
|
if (this.checkTimeBudget()) {
|
|
@@ -48023,7 +48595,7 @@ var runCommand = {
|
|
|
48023
48595
|
}
|
|
48024
48596
|
try {
|
|
48025
48597
|
const workflowContent = readFileSync(workflowPath, "utf-8");
|
|
48026
|
-
workflowConfig =
|
|
48598
|
+
workflowConfig = yaml3__default.load(workflowContent);
|
|
48027
48599
|
if (workflowConfig?.iterate?.enabled !== false) {
|
|
48028
48600
|
argv.iterate = true;
|
|
48029
48601
|
}
|
|
@@ -49244,7 +49816,7 @@ var statusCommand4 = {
|
|
|
49244
49816
|
const agentCount = await countFiles(agentsDir, [".yaml", ".yml"]);
|
|
49245
49817
|
const abilityCount = await countFiles(abilitiesDir, [".md"]);
|
|
49246
49818
|
const projectInfo = await getProjectInfo(detectedProjectDir);
|
|
49247
|
-
|
|
49819
|
+
const limitData = {
|
|
49248
49820
|
limits: [],
|
|
49249
49821
|
manualOverride: null,
|
|
49250
49822
|
envOverrides: []
|
|
@@ -49635,7 +50207,7 @@ function formatUptime2(seconds) {
|
|
|
49635
50207
|
// src/cli/commands/update.ts
|
|
49636
50208
|
init_esm_shims();
|
|
49637
50209
|
init_logger();
|
|
49638
|
-
var
|
|
50210
|
+
var execAsync6 = promisify(exec);
|
|
49639
50211
|
var updateCommand = {
|
|
49640
50212
|
command: "update",
|
|
49641
50213
|
describe: "Check for updates and upgrade AutomatosX to the latest version",
|
|
@@ -49654,17 +50226,17 @@ var updateCommand = {
|
|
|
49654
50226
|
handler: async (argv) => {
|
|
49655
50227
|
console.log(chalk5.blue.bold("\n\u{1F504} AutomatosX Update Checker\n"));
|
|
49656
50228
|
try {
|
|
49657
|
-
const currentVersion = await
|
|
50229
|
+
const currentVersion = await getCurrentVersion2();
|
|
49658
50230
|
console.log(chalk5.gray(`Current version: ${currentVersion}`));
|
|
49659
50231
|
console.log(chalk5.cyan("Checking for updates..."));
|
|
49660
|
-
const latestVersion = await
|
|
50232
|
+
const latestVersion = await getLatestVersion2();
|
|
49661
50233
|
console.log(chalk5.gray(`Latest version: ${latestVersion}
|
|
49662
50234
|
`));
|
|
49663
50235
|
if (currentVersion === latestVersion) {
|
|
49664
50236
|
console.log(chalk5.green("\u2705 You are already running the latest version!\n"));
|
|
49665
50237
|
return;
|
|
49666
50238
|
}
|
|
49667
|
-
if (
|
|
50239
|
+
if (isNewer2(latestVersion, currentVersion)) {
|
|
49668
50240
|
console.log(chalk5.yellow(`\u{1F4E6} New version available: ${currentVersion} \u2192 ${latestVersion}
|
|
49669
50241
|
`));
|
|
49670
50242
|
await showChangelog(currentVersion, latestVersion);
|
|
@@ -49709,28 +50281,28 @@ var updateCommand = {
|
|
|
49709
50281
|
}
|
|
49710
50282
|
}
|
|
49711
50283
|
};
|
|
49712
|
-
async function
|
|
50284
|
+
async function getCurrentVersion2() {
|
|
49713
50285
|
try {
|
|
49714
|
-
const { stdout } = await
|
|
50286
|
+
const { stdout } = await execAsync6("npm list -g @defai.digital/automatosx --depth=0 --json");
|
|
49715
50287
|
const result = JSON.parse(stdout);
|
|
49716
50288
|
return result.dependencies["@defai.digital/automatosx"]?.version || "unknown";
|
|
49717
50289
|
} catch (error) {
|
|
49718
50290
|
const { readFile: readFile24 } = await import('fs/promises');
|
|
49719
|
-
const { dirname:
|
|
50291
|
+
const { dirname: dirname16, join: join57 } = await import('path');
|
|
49720
50292
|
const { fileURLToPath: fileURLToPath5 } = await import('url');
|
|
49721
50293
|
const __filename3 = fileURLToPath5(import.meta.url);
|
|
49722
|
-
const __dirname4 =
|
|
50294
|
+
const __dirname4 = dirname16(__filename3);
|
|
49723
50295
|
const pkgPath = join57(__dirname4, "../../../package.json");
|
|
49724
50296
|
const content = await readFile24(pkgPath, "utf-8");
|
|
49725
50297
|
const pkg = JSON.parse(content);
|
|
49726
50298
|
return pkg.version;
|
|
49727
50299
|
}
|
|
49728
50300
|
}
|
|
49729
|
-
async function
|
|
49730
|
-
const { stdout } = await
|
|
50301
|
+
async function getLatestVersion2() {
|
|
50302
|
+
const { stdout } = await execAsync6("npm view @defai.digital/automatosx version");
|
|
49731
50303
|
return stdout.trim();
|
|
49732
50304
|
}
|
|
49733
|
-
function
|
|
50305
|
+
function isNewer2(a, b) {
|
|
49734
50306
|
const stripPrerelease = (v) => v.split("-")[0] || v;
|
|
49735
50307
|
const parseVersion = (v) => stripPrerelease(v).split(".").map(Number);
|
|
49736
50308
|
const [aMajor = 0, aMinor = 0, aPatch = 0] = parseVersion(a);
|
|
@@ -49742,7 +50314,7 @@ function isNewer(a, b) {
|
|
|
49742
50314
|
async function showChangelog(from, to) {
|
|
49743
50315
|
try {
|
|
49744
50316
|
console.log(chalk5.cyan("What's new:\n"));
|
|
49745
|
-
const { stdout } = await
|
|
50317
|
+
const { stdout } = await execAsync6(
|
|
49746
50318
|
`curl -s https://api.github.com/repos/defai-digital/automatosx/releases/tags/v${to}`
|
|
49747
50319
|
);
|
|
49748
50320
|
const release = JSON.parse(stdout);
|
|
@@ -49764,7 +50336,7 @@ async function showChangelog(from, to) {
|
|
|
49764
50336
|
}
|
|
49765
50337
|
async function installUpdate(version) {
|
|
49766
50338
|
try {
|
|
49767
|
-
const { stdout, stderr } = await
|
|
50339
|
+
const { stdout, stderr } = await execAsync6(
|
|
49768
50340
|
`npm install -g @defai.digital/automatosx@${version}`,
|
|
49769
50341
|
{ maxBuffer: 10 * 1024 * 1024 }
|
|
49770
50342
|
);
|
|
@@ -49922,6 +50494,7 @@ init_esm_shims();
|
|
|
49922
50494
|
// src/cli/commands/agent/helpers.ts
|
|
49923
50495
|
init_esm_shims();
|
|
49924
50496
|
init_logger();
|
|
50497
|
+
var YAML_EXT_REGEX = /\.(yaml|yml)$/;
|
|
49925
50498
|
var BUILTIN_TEMPLATE_METADATA = {
|
|
49926
50499
|
"basic-agent": {
|
|
49927
50500
|
name: "basic-agent",
|
|
@@ -49958,7 +50531,7 @@ async function listAvailableTemplates(baseDir) {
|
|
|
49958
50531
|
const files = await readdir(projectTemplatesDir);
|
|
49959
50532
|
for (const file of files) {
|
|
49960
50533
|
if (extname$1(file) === ".yaml" || extname$1(file) === ".yml") {
|
|
49961
|
-
const name = file.replace(
|
|
50534
|
+
const name = file.replace(YAML_EXT_REGEX, "");
|
|
49962
50535
|
templates.push({
|
|
49963
50536
|
name,
|
|
49964
50537
|
path: join(projectTemplatesDir, file),
|
|
@@ -49977,7 +50550,7 @@ async function listAvailableTemplates(baseDir) {
|
|
|
49977
50550
|
const files = await readdir(builtinTemplatesDir);
|
|
49978
50551
|
for (const file of files) {
|
|
49979
50552
|
if (extname$1(file) === ".yaml" || extname$1(file) === ".yml") {
|
|
49980
|
-
const name = file.replace(
|
|
50553
|
+
const name = file.replace(YAML_EXT_REGEX, "");
|
|
49981
50554
|
if (templates.find((t) => t.name === name)) {
|
|
49982
50555
|
continue;
|
|
49983
50556
|
}
|
|
@@ -52623,7 +53196,7 @@ var CommandTranslator = class {
|
|
|
52623
53196
|
if (baseDir === void 0) {
|
|
52624
53197
|
try {
|
|
52625
53198
|
baseDir = await realpath$1(dir);
|
|
52626
|
-
} catch
|
|
53199
|
+
} catch {
|
|
52627
53200
|
return commands;
|
|
52628
53201
|
}
|
|
52629
53202
|
}
|
|
@@ -52641,7 +53214,7 @@ var CommandTranslator = class {
|
|
|
52641
53214
|
let realPath;
|
|
52642
53215
|
try {
|
|
52643
53216
|
realPath = await realpath$1(fullPath);
|
|
52644
|
-
} catch
|
|
53217
|
+
} catch {
|
|
52645
53218
|
console.warn(`[Security] Cannot resolve path: ${fullPath}`);
|
|
52646
53219
|
continue;
|
|
52647
53220
|
}
|
|
@@ -52684,7 +53257,7 @@ var CommandTranslator = class {
|
|
|
52684
53257
|
}
|
|
52685
53258
|
}
|
|
52686
53259
|
}
|
|
52687
|
-
} catch
|
|
53260
|
+
} catch {
|
|
52688
53261
|
}
|
|
52689
53262
|
return commands;
|
|
52690
53263
|
}
|
|
@@ -53997,7 +54570,7 @@ async function handleSpecExplain(workspacePath, options) {
|
|
|
53997
54570
|
console.log(chalk5.blue.bold("\n\u{1F4D6} Spec-Kit: Explain Spec\n"));
|
|
53998
54571
|
try {
|
|
53999
54572
|
const specContent = readFileSync(options.file, "utf-8");
|
|
54000
|
-
const spec =
|
|
54573
|
+
const spec = yaml3.load(specContent);
|
|
54001
54574
|
const validation = validateSpec(spec);
|
|
54002
54575
|
if (!validation.valid) {
|
|
54003
54576
|
console.error(chalk5.red("\n\u2717 Spec validation failed:\n"));
|
|
@@ -56099,7 +56672,7 @@ async function handleGenPlan(specFile, argv) {
|
|
|
56099
56672
|
process.exit(1);
|
|
56100
56673
|
}
|
|
56101
56674
|
const specContent = readFileSync(specFile, "utf-8");
|
|
56102
|
-
const spec =
|
|
56675
|
+
const spec = yaml3.load(specContent);
|
|
56103
56676
|
const validation = validateSpec(spec);
|
|
56104
56677
|
if (!validation.valid) {
|
|
56105
56678
|
spinner.fail("Spec validation failed");
|
|
@@ -56157,7 +56730,7 @@ async function handleGenDag(specFile, argv) {
|
|
|
56157
56730
|
process.exit(1);
|
|
56158
56731
|
}
|
|
56159
56732
|
const specContent = readFileSync(specFile, "utf-8");
|
|
56160
|
-
const spec =
|
|
56733
|
+
const spec = yaml3.load(specContent);
|
|
56161
56734
|
const validation = validateSpec(spec);
|
|
56162
56735
|
if (!validation.valid) {
|
|
56163
56736
|
spinner.fail("Spec validation failed");
|
|
@@ -56244,7 +56817,7 @@ async function handleGenScaffold(specFile, argv) {
|
|
|
56244
56817
|
process.exit(1);
|
|
56245
56818
|
}
|
|
56246
56819
|
const specContent = readFileSync(specFile, "utf-8");
|
|
56247
|
-
const spec =
|
|
56820
|
+
const spec = yaml3.load(specContent);
|
|
56248
56821
|
const validation = validateSpec(spec);
|
|
56249
56822
|
if (!validation.valid) {
|
|
56250
56823
|
spinner.fail("Spec validation failed");
|
|
@@ -56316,7 +56889,7 @@ async function handleGenTests(specFile, argv) {
|
|
|
56316
56889
|
process.exit(1);
|
|
56317
56890
|
}
|
|
56318
56891
|
const specContent = readFileSync(specFile, "utf-8");
|
|
56319
|
-
const spec =
|
|
56892
|
+
const spec = yaml3.load(specContent);
|
|
56320
56893
|
const validation = validateSpec(spec);
|
|
56321
56894
|
if (!validation.valid) {
|
|
56322
56895
|
spinner.fail("Spec validation failed");
|
|
@@ -56551,7 +57124,7 @@ async function handleList(config, argv) {
|
|
|
56551
57124
|
});
|
|
56552
57125
|
}
|
|
56553
57126
|
}
|
|
56554
|
-
|
|
57127
|
+
const displayProviders2 = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
|
|
56555
57128
|
switch (argv.sort) {
|
|
56556
57129
|
case "cost":
|
|
56557
57130
|
displayProviders2.sort((a, b) => {
|
|
@@ -58194,8 +58767,8 @@ async function runMcpDiagnostics(verbose) {
|
|
|
58194
58767
|
let serverStarts = false;
|
|
58195
58768
|
if (cliAvailable) {
|
|
58196
58769
|
try {
|
|
58197
|
-
const { spawn:
|
|
58198
|
-
const proc =
|
|
58770
|
+
const { spawn: spawn13 } = await import('child_process');
|
|
58771
|
+
const proc = spawn13("automatosx", ["mcp", "server"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
58199
58772
|
const initResult = await new Promise((resolve13) => {
|
|
58200
58773
|
let output = "";
|
|
58201
58774
|
proc.stderr?.on("data", (data) => {
|
|
@@ -58294,7 +58867,8 @@ async function runMcpDiagnostics(verbose) {
|
|
|
58294
58867
|
// src/cli/commands/cleanup.ts
|
|
58295
58868
|
init_esm_shims();
|
|
58296
58869
|
init_logger();
|
|
58297
|
-
|
|
58870
|
+
init_safe_timers();
|
|
58871
|
+
var execAsync7 = promisify(exec);
|
|
58298
58872
|
var cleanupCommand2 = {
|
|
58299
58873
|
command: "cleanup [provider]",
|
|
58300
58874
|
describe: "Clean up orphaned provider processes (v6.0.7 Phase 3)",
|
|
@@ -58423,7 +58997,7 @@ async function findProcesses(processName, verbose) {
|
|
|
58423
58997
|
throw new Error(`Invalid process name: ${processName}. Only alphanumeric characters, dashes, and underscores are allowed.`);
|
|
58424
58998
|
}
|
|
58425
58999
|
try {
|
|
58426
|
-
const { stdout } = await
|
|
59000
|
+
const { stdout } = await execAsync7("ps -eo pid,comm,etime,rss");
|
|
58427
59001
|
if (!stdout.trim()) {
|
|
58428
59002
|
return processes;
|
|
58429
59003
|
}
|
|
@@ -58486,7 +59060,7 @@ async function killProcess(pid, verbose) {
|
|
|
58486
59060
|
});
|
|
58487
59061
|
proc.on("error", reject);
|
|
58488
59062
|
});
|
|
58489
|
-
await
|
|
59063
|
+
await sleep(1e3);
|
|
58490
59064
|
try {
|
|
58491
59065
|
await new Promise((resolve13, reject) => {
|
|
58492
59066
|
const proc = spawn("ps", ["-p", String(pid)], {
|
|
@@ -59737,6 +60311,7 @@ init_esm_shims();
|
|
|
59737
60311
|
init_flags();
|
|
59738
60312
|
init_logger();
|
|
59739
60313
|
init_validation_limits();
|
|
60314
|
+
init_safe_timers();
|
|
59740
60315
|
var flagsCommand = {
|
|
59741
60316
|
command: "flags <command>",
|
|
59742
60317
|
describe: "Manage feature flags",
|
|
@@ -59886,7 +60461,7 @@ async function handleKill(argv) {
|
|
|
59886
60461
|
`);
|
|
59887
60462
|
console.log(chalk5.yellow("This will immediately disable the feature for ALL users."));
|
|
59888
60463
|
console.log(chalk5.gray("Press Ctrl+C to cancel, or wait 5 seconds to confirm...\n"));
|
|
59889
|
-
await
|
|
60464
|
+
await sleep(TIMEOUTS.KILL_SWITCH_DELAY);
|
|
59890
60465
|
try {
|
|
59891
60466
|
await flagManager.killSwitch(flagName, reason);
|
|
59892
60467
|
console.log(chalk5.red("\u2713 Kill switch activated"));
|
|
@@ -61896,42 +62471,20 @@ var AgentInstructionInjector = class {
|
|
|
61896
62471
|
this.lastQualityCheckTurn = context.turnCount;
|
|
61897
62472
|
}
|
|
61898
62473
|
const taskText = this.extractTaskText(context);
|
|
61899
|
-
|
|
61900
|
-
|
|
61901
|
-
|
|
61902
|
-
|
|
61903
|
-
|
|
61904
|
-
|
|
61905
|
-
|
|
61906
|
-
priority: "high",
|
|
61907
|
-
content: delegationContent,
|
|
61908
|
-
source: INSTRUCTION_SOURCE,
|
|
61909
|
-
createdAt: Date.now(),
|
|
61910
|
-
createdAtTurn: context.turnCount,
|
|
61911
|
-
expiresAfter: 3,
|
|
61912
|
-
id: `agent-delegation-${Date.now()}`
|
|
61913
|
-
});
|
|
61914
|
-
}
|
|
61915
|
-
}
|
|
62474
|
+
const delegationInstruction = this.tryCreateDelegationInstruction(
|
|
62475
|
+
template,
|
|
62476
|
+
taskText,
|
|
62477
|
+
context.turnCount
|
|
62478
|
+
);
|
|
62479
|
+
if (delegationInstruction) {
|
|
62480
|
+
instructions.push(delegationInstruction);
|
|
61916
62481
|
}
|
|
61917
|
-
|
|
61918
|
-
|
|
61919
|
-
|
|
61920
|
-
|
|
61921
|
-
|
|
61922
|
-
|
|
61923
|
-
priority: "normal",
|
|
61924
|
-
content: contextBoostContent,
|
|
61925
|
-
source: INSTRUCTION_SOURCE,
|
|
61926
|
-
createdAt: Date.now(),
|
|
61927
|
-
createdAtTurn: context.turnCount,
|
|
61928
|
-
expiresAfter: 5,
|
|
61929
|
-
id: `agent-context-boost-${Date.now()}`
|
|
61930
|
-
});
|
|
61931
|
-
logger.debug("Context-aware boost applied", {
|
|
61932
|
-
categories: detectedCategories.map((c) => c.name)
|
|
61933
|
-
});
|
|
61934
|
-
}
|
|
62482
|
+
const contextInstruction = this.tryCreateContextBoostInstruction(
|
|
62483
|
+
taskText,
|
|
62484
|
+
context.turnCount
|
|
62485
|
+
);
|
|
62486
|
+
if (contextInstruction) {
|
|
62487
|
+
instructions.push(contextInstruction);
|
|
61935
62488
|
}
|
|
61936
62489
|
logger.debug("Agent instructions generated", {
|
|
61937
62490
|
domain,
|
|
@@ -62032,6 +62585,62 @@ var AgentInstructionInjector = class {
|
|
|
62032
62585
|
lines.push("Use `DELEGATE TO @agent: task` or `@agent task` syntax to delegate.");
|
|
62033
62586
|
return lines.join("\n");
|
|
62034
62587
|
}
|
|
62588
|
+
/**
|
|
62589
|
+
* Try to create a delegation instruction
|
|
62590
|
+
* Returns null if delegation detection is disabled or no delegation is needed
|
|
62591
|
+
* @since v12.6.1 - Extracted to reduce nesting
|
|
62592
|
+
*/
|
|
62593
|
+
tryCreateDelegationInstruction(template, taskText, turnCount) {
|
|
62594
|
+
if (!this.config.delegationDetection) {
|
|
62595
|
+
return null;
|
|
62596
|
+
}
|
|
62597
|
+
if (taskText === this.recentTaskText) {
|
|
62598
|
+
return null;
|
|
62599
|
+
}
|
|
62600
|
+
this.recentTaskText = taskText;
|
|
62601
|
+
const delegationContent = this.checkAndFormatDelegation(template, taskText);
|
|
62602
|
+
if (!delegationContent) {
|
|
62603
|
+
return null;
|
|
62604
|
+
}
|
|
62605
|
+
return {
|
|
62606
|
+
type: "delegation",
|
|
62607
|
+
priority: "high",
|
|
62608
|
+
content: delegationContent,
|
|
62609
|
+
source: INSTRUCTION_SOURCE,
|
|
62610
|
+
createdAt: Date.now(),
|
|
62611
|
+
createdAtTurn: turnCount,
|
|
62612
|
+
expiresAfter: 3,
|
|
62613
|
+
id: `agent-delegation-${Date.now()}`
|
|
62614
|
+
};
|
|
62615
|
+
}
|
|
62616
|
+
/**
|
|
62617
|
+
* Try to create a context boost instruction
|
|
62618
|
+
* Returns null if context boosting is disabled or no boost is needed
|
|
62619
|
+
* @since v12.6.1 - Extracted to reduce nesting
|
|
62620
|
+
*/
|
|
62621
|
+
tryCreateContextBoostInstruction(taskText, turnCount) {
|
|
62622
|
+
if (!this.config.contextAwareBoosting || !taskText) {
|
|
62623
|
+
return null;
|
|
62624
|
+
}
|
|
62625
|
+
const detectedCategories = this.detectContextCategories(taskText);
|
|
62626
|
+
const contextBoostContent = this.formatContextBoost(detectedCategories);
|
|
62627
|
+
if (!contextBoostContent) {
|
|
62628
|
+
return null;
|
|
62629
|
+
}
|
|
62630
|
+
logger.debug("Context-aware boost applied", {
|
|
62631
|
+
categories: detectedCategories.map((c) => c.name)
|
|
62632
|
+
});
|
|
62633
|
+
return {
|
|
62634
|
+
type: "context",
|
|
62635
|
+
priority: "normal",
|
|
62636
|
+
content: contextBoostContent,
|
|
62637
|
+
source: INSTRUCTION_SOURCE,
|
|
62638
|
+
createdAt: Date.now(),
|
|
62639
|
+
createdAtTurn: turnCount,
|
|
62640
|
+
expiresAfter: 5,
|
|
62641
|
+
id: `agent-context-boost-${Date.now()}`
|
|
62642
|
+
};
|
|
62643
|
+
}
|
|
62035
62644
|
/**
|
|
62036
62645
|
* Detect context categories from task text
|
|
62037
62646
|
* @since v11.3.1
|
|
@@ -62870,10 +63479,10 @@ init_esm_shims();
|
|
|
62870
63479
|
// src/core/bugfix/git-utils.ts
|
|
62871
63480
|
init_esm_shims();
|
|
62872
63481
|
init_logger();
|
|
62873
|
-
var
|
|
63482
|
+
var execAsync8 = promisify(exec);
|
|
62874
63483
|
async function isGitRepo(cwd) {
|
|
62875
63484
|
try {
|
|
62876
|
-
await
|
|
63485
|
+
await execAsync8("git rev-parse --is-inside-work-tree", { cwd });
|
|
62877
63486
|
return true;
|
|
62878
63487
|
} catch {
|
|
62879
63488
|
return false;
|
|
@@ -62891,14 +63500,14 @@ async function getChangedFiles(options) {
|
|
|
62891
63500
|
command = "git diff --cached --name-only --diff-filter=ACMR";
|
|
62892
63501
|
} else if (options.since) {
|
|
62893
63502
|
const mergeBaseCmd = `git merge-base HEAD ${options.since}`;
|
|
62894
|
-
const { stdout: mergeBase } = await
|
|
63503
|
+
const { stdout: mergeBase } = await execAsync8(mergeBaseCmd, { cwd });
|
|
62895
63504
|
command = `git diff --name-only ${mergeBase.trim()}..HEAD`;
|
|
62896
63505
|
} else if (options.changed) {
|
|
62897
63506
|
command = "git diff --name-only HEAD";
|
|
62898
63507
|
} else {
|
|
62899
63508
|
command = "git diff --name-only HEAD";
|
|
62900
63509
|
}
|
|
62901
|
-
const { stdout } = await
|
|
63510
|
+
const { stdout } = await execAsync8(command, { cwd });
|
|
62902
63511
|
const files = stdout.split("\n").map((f) => f.trim()).filter((f) => f.length > 0);
|
|
62903
63512
|
logger.debug("Git changed files", {
|
|
62904
63513
|
command,
|