@defai.digital/automatosx 11.3.1 → 11.3.2
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 +728 -382
- package/dist/mcp/index.js +174 -144
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import * as path4 from 'path';
|
|
3
3
|
import path4__default, { dirname, join, isAbsolute, basename, resolve, extname as extname$1, relative, sep, normalize, parse as parse$1, delimiter } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
-
import * as
|
|
5
|
+
import * as fs5 from 'fs/promises';
|
|
6
6
|
import { mkdir, appendFile, access as access$1, readFile, stat, rm, readdir, copyFile, writeFile, rename, unlink, constants as constants$1, realpath as realpath$1 } from 'fs/promises';
|
|
7
|
+
import * as fs3 from 'fs';
|
|
7
8
|
import { access, realpath, existsSync, readFileSync, constants, writeFileSync, mkdirSync, promises, statSync, readdirSync, createWriteStream, unlinkSync } from 'fs';
|
|
8
9
|
import Database2 from 'better-sqlite3';
|
|
9
10
|
import os2, { homedir, cpus } from 'os';
|
|
@@ -17,9 +18,9 @@ import * as readline2 from 'readline';
|
|
|
17
18
|
import readline2__default, { createInterface } from 'readline';
|
|
18
19
|
import { Mutex } from 'async-mutex';
|
|
19
20
|
import { promisify } from 'util';
|
|
21
|
+
import crypto2, { randomUUID, createHash } from 'crypto';
|
|
20
22
|
import yargs from 'yargs';
|
|
21
23
|
import { hideBin } from 'yargs/helpers';
|
|
22
|
-
import crypto2, { randomUUID, createHash } from 'crypto';
|
|
23
24
|
import * as yaml4 from 'js-yaml';
|
|
24
25
|
import yaml4__default, { load, dump } from 'js-yaml';
|
|
25
26
|
import Table from 'cli-table3';
|
|
@@ -32,9 +33,7 @@ import yaml from 'yaml';
|
|
|
32
33
|
import { parse } from '@iarna/toml';
|
|
33
34
|
|
|
34
35
|
var __defProp = Object.defineProperty;
|
|
35
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
36
36
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
37
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
38
37
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
39
38
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
40
39
|
}) : x)(function(x) {
|
|
@@ -48,15 +47,6 @@ var __export = (target, all) => {
|
|
|
48
47
|
for (var name in all)
|
|
49
48
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
50
49
|
};
|
|
51
|
-
var __copyProps = (to, from, except, desc) => {
|
|
52
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
53
|
-
for (let key of __getOwnPropNames(from))
|
|
54
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
55
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
56
|
-
}
|
|
57
|
-
return to;
|
|
58
|
-
};
|
|
59
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
60
50
|
var init_esm_shims = __esm({
|
|
61
51
|
"node_modules/tsup/assets/esm_shims.js"() {
|
|
62
52
|
}
|
|
@@ -753,16 +743,16 @@ var init_errors = __esm({
|
|
|
753
743
|
constructor(message, code = "E1001" /* CONFIG_INVALID */, suggestions = [], context) {
|
|
754
744
|
super(message, code, suggestions, context);
|
|
755
745
|
}
|
|
756
|
-
static notFound(
|
|
746
|
+
static notFound(path8) {
|
|
757
747
|
return new _ConfigError(
|
|
758
|
-
`Configuration file not found: ${
|
|
748
|
+
`Configuration file not found: ${path8}`,
|
|
759
749
|
"E1000" /* CONFIG_NOT_FOUND */,
|
|
760
750
|
[
|
|
761
751
|
'Run "automatosx setup" to create a new configuration',
|
|
762
752
|
"Specify a custom config path with --config option",
|
|
763
753
|
"Check that you are in a valid AutomatosX project directory"
|
|
764
754
|
],
|
|
765
|
-
{ path:
|
|
755
|
+
{ path: path8 }
|
|
766
756
|
);
|
|
767
757
|
}
|
|
768
758
|
static invalid(reason, context) {
|
|
@@ -777,7 +767,7 @@ var init_errors = __esm({
|
|
|
777
767
|
context
|
|
778
768
|
);
|
|
779
769
|
}
|
|
780
|
-
static parseError(error,
|
|
770
|
+
static parseError(error, path8) {
|
|
781
771
|
return new _ConfigError(
|
|
782
772
|
`Failed to parse configuration: ${error.message}`,
|
|
783
773
|
"E1002" /* CONFIG_PARSE_ERROR */,
|
|
@@ -786,7 +776,7 @@ var init_errors = __esm({
|
|
|
786
776
|
"Use a JSON validator to find syntax errors",
|
|
787
777
|
'Reset to default with "automatosx setup --force"'
|
|
788
778
|
],
|
|
789
|
-
{ path:
|
|
779
|
+
{ path: path8, originalError: error.message }
|
|
790
780
|
);
|
|
791
781
|
}
|
|
792
782
|
};
|
|
@@ -1014,8 +1004,8 @@ __export(path_resolver_exports, {
|
|
|
1014
1004
|
PathResolver: () => PathResolver,
|
|
1015
1005
|
detectProjectRoot: () => detectProjectRoot
|
|
1016
1006
|
});
|
|
1017
|
-
function isWindowsPath(
|
|
1018
|
-
return /^[a-zA-Z]:[/\\]/.test(
|
|
1007
|
+
function isWindowsPath(path8) {
|
|
1008
|
+
return /^[a-zA-Z]:[/\\]/.test(path8);
|
|
1019
1009
|
}
|
|
1020
1010
|
async function detectProjectRoot(startDir = process.cwd()) {
|
|
1021
1011
|
if (process.env.AUTOMATOSX_PROJECT_ROOT) {
|
|
@@ -1121,8 +1111,8 @@ var init_path_resolver = __esm({
|
|
|
1121
1111
|
/**
|
|
1122
1112
|
* Validate path is within allowed base directory
|
|
1123
1113
|
*/
|
|
1124
|
-
validatePath(
|
|
1125
|
-
const normalized = normalizePath(resolvePath(
|
|
1114
|
+
validatePath(path8, baseDir) {
|
|
1115
|
+
const normalized = normalizePath(resolvePath(path8));
|
|
1126
1116
|
const base = normalizePath(resolvePath(baseDir));
|
|
1127
1117
|
const separator = "/";
|
|
1128
1118
|
const pathWithSep = normalized + separator;
|
|
@@ -1132,15 +1122,15 @@ var init_path_resolver = __esm({
|
|
|
1132
1122
|
/**
|
|
1133
1123
|
* Check if path is within allowed boundaries
|
|
1134
1124
|
*/
|
|
1135
|
-
isPathAllowed(
|
|
1136
|
-
const boundary = this.checkBoundaries(
|
|
1125
|
+
isPathAllowed(path8) {
|
|
1126
|
+
const boundary = this.checkBoundaries(path8);
|
|
1137
1127
|
return boundary === "agent_workspace" || boundary === "user_project";
|
|
1138
1128
|
}
|
|
1139
1129
|
/**
|
|
1140
1130
|
* Check which boundary a path belongs to
|
|
1141
1131
|
*/
|
|
1142
|
-
checkBoundaries(
|
|
1143
|
-
const normalized = resolvePath(
|
|
1132
|
+
checkBoundaries(path8) {
|
|
1133
|
+
const normalized = resolvePath(path8);
|
|
1144
1134
|
if (this.validatePath(normalized, this.config.agentWorkspace)) {
|
|
1145
1135
|
return "agent_workspace";
|
|
1146
1136
|
}
|
|
@@ -1158,15 +1148,15 @@ var init_path_resolver = __esm({
|
|
|
1158
1148
|
/**
|
|
1159
1149
|
* Get relative path from project root
|
|
1160
1150
|
*/
|
|
1161
|
-
getRelativeToProject(
|
|
1162
|
-
const normalized = resolvePath(
|
|
1151
|
+
getRelativeToProject(path8) {
|
|
1152
|
+
const normalized = resolvePath(path8);
|
|
1163
1153
|
return normalizePath(getRelativePath(this.config.projectDir, normalized));
|
|
1164
1154
|
}
|
|
1165
1155
|
/**
|
|
1166
1156
|
* Get relative path from working directory
|
|
1167
1157
|
*/
|
|
1168
|
-
getRelativeToWorking(
|
|
1169
|
-
const normalized = resolvePath(
|
|
1158
|
+
getRelativeToWorking(path8) {
|
|
1159
|
+
const normalized = resolvePath(path8);
|
|
1170
1160
|
return normalizePath(getRelativePath(this.config.workingDir, normalized));
|
|
1171
1161
|
}
|
|
1172
1162
|
/**
|
|
@@ -1185,11 +1175,11 @@ var init_path_resolver = __esm({
|
|
|
1185
1175
|
* Validate path is within project boundaries
|
|
1186
1176
|
* @throws PathError if outside project
|
|
1187
1177
|
*/
|
|
1188
|
-
validateInProject(
|
|
1189
|
-
const boundary = this.checkBoundaries(
|
|
1178
|
+
validateInProject(path8) {
|
|
1179
|
+
const boundary = this.checkBoundaries(path8);
|
|
1190
1180
|
if (boundary === "outside_boundaries" || boundary === "system_restricted") {
|
|
1191
1181
|
throw new PathError("Path outside project directory", {
|
|
1192
|
-
path:
|
|
1182
|
+
path: path8,
|
|
1193
1183
|
projectDir: this.config.projectDir,
|
|
1194
1184
|
boundary
|
|
1195
1185
|
});
|
|
@@ -1432,11 +1422,11 @@ var init_workspace_indexer = __esm({
|
|
|
1432
1422
|
/**
|
|
1433
1423
|
* Detect file type and language
|
|
1434
1424
|
*/
|
|
1435
|
-
detectTypeAndLanguage(
|
|
1436
|
-
if (
|
|
1425
|
+
detectTypeAndLanguage(path8, ext) {
|
|
1426
|
+
if (path8.match(/package\.json|tsconfig\.json|\.config\.(js|ts|json|yaml|yml)|\.eslintrc|\.prettierrc/)) {
|
|
1437
1427
|
return { type: "config", language: "json" };
|
|
1438
1428
|
}
|
|
1439
|
-
if (
|
|
1429
|
+
if (path8.match(/\.(test|spec)\.(ts|js|tsx|jsx)$/) || path8.includes("__tests__")) {
|
|
1440
1430
|
const lang = LANGUAGE_MAP[ext];
|
|
1441
1431
|
return { type: "test", language: lang };
|
|
1442
1432
|
}
|
|
@@ -1453,15 +1443,15 @@ var init_workspace_indexer = __esm({
|
|
|
1453
1443
|
*
|
|
1454
1444
|
* Higher score = more likely to be relevant
|
|
1455
1445
|
*/
|
|
1456
|
-
calculateImportance(
|
|
1446
|
+
calculateImportance(path8, type, size) {
|
|
1457
1447
|
let score = 0.5;
|
|
1458
|
-
if (
|
|
1459
|
-
if (
|
|
1460
|
-
if (
|
|
1448
|
+
if (path8.match(/^(index|main|app)\.(ts|js|tsx|jsx)$/)) score = 1;
|
|
1449
|
+
if (path8.match(/^src\/(index|main|app)\.(ts|js|tsx|jsx)$/)) score = 0.95;
|
|
1450
|
+
if (path8.match(/^src\/cli\/(index|main)\.(ts|js)$/)) score = 0.9;
|
|
1461
1451
|
if (type === "config") score = 0.85;
|
|
1462
|
-
if (
|
|
1463
|
-
if (
|
|
1464
|
-
if (
|
|
1452
|
+
if (path8.includes("/core/")) score += 0.15;
|
|
1453
|
+
if (path8.includes("/types/")) score += 0.1;
|
|
1454
|
+
if (path8.includes("/utils/")) score += 0.05;
|
|
1465
1455
|
if (type === "test") score = Math.max(0.3, score - 0.3);
|
|
1466
1456
|
if (type === "doc") score = Math.max(0.4, score - 0.2);
|
|
1467
1457
|
if (size > 1e4) score += 0.05;
|
|
@@ -1937,10 +1927,10 @@ function findOnPathUnix(cmdBase) {
|
|
|
1937
1927
|
try {
|
|
1938
1928
|
const which = spawnSync("which", [cmdBase], { timeout: 3e3 });
|
|
1939
1929
|
if (which.status === 0) {
|
|
1940
|
-
const
|
|
1941
|
-
if (
|
|
1942
|
-
logger.debug("Found via which", { cmdBase, path:
|
|
1943
|
-
return { found: true, path:
|
|
1930
|
+
const path8 = which.stdout.toString().trim();
|
|
1931
|
+
if (path8) {
|
|
1932
|
+
logger.debug("Found via which", { cmdBase, path: path8 });
|
|
1933
|
+
return { found: true, path: path8 };
|
|
1944
1934
|
}
|
|
1945
1935
|
}
|
|
1946
1936
|
} catch (error) {
|
|
@@ -2239,15 +2229,6 @@ var init_streaming_progress_parser = __esm({
|
|
|
2239
2229
|
});
|
|
2240
2230
|
|
|
2241
2231
|
// src/providers/error-patterns.ts
|
|
2242
|
-
var error_patterns_exports = {};
|
|
2243
|
-
__export(error_patterns_exports, {
|
|
2244
|
-
GENERIC_ERROR_PATTERNS: () => GENERIC_ERROR_PATTERNS,
|
|
2245
|
-
PROVIDER_ERROR_PATTERNS: () => PROVIDER_ERROR_PATTERNS,
|
|
2246
|
-
getProviderErrorPatterns: () => getProviderErrorPatterns,
|
|
2247
|
-
isLimitError: () => isLimitError,
|
|
2248
|
-
isQuotaError: () => isQuotaError,
|
|
2249
|
-
isRateLimitError: () => isRateLimitError
|
|
2250
|
-
});
|
|
2251
2232
|
function isQuotaError(error, providerName) {
|
|
2252
2233
|
const patterns = PROVIDER_ERROR_PATTERNS[providerName] || GENERIC_ERROR_PATTERNS;
|
|
2253
2234
|
const message = (error?.message || "").toLowerCase();
|
|
@@ -2289,9 +2270,6 @@ function isRateLimitError(error, providerName) {
|
|
|
2289
2270
|
function isLimitError(error, providerName) {
|
|
2290
2271
|
return isQuotaError(error, providerName) || isRateLimitError(error, providerName);
|
|
2291
2272
|
}
|
|
2292
|
-
function getProviderErrorPatterns(providerName) {
|
|
2293
|
-
return PROVIDER_ERROR_PATTERNS[providerName] || GENERIC_ERROR_PATTERNS;
|
|
2294
|
-
}
|
|
2295
2273
|
var PROVIDER_ERROR_PATTERNS, GENERIC_ERROR_PATTERNS;
|
|
2296
2274
|
var init_error_patterns = __esm({
|
|
2297
2275
|
"src/providers/error-patterns.ts"() {
|
|
@@ -2512,6 +2490,7 @@ var init_base_provider = __esm({
|
|
|
2512
2490
|
init_provider_schemas();
|
|
2513
2491
|
init_streaming_progress_parser();
|
|
2514
2492
|
init_verbosity_manager();
|
|
2493
|
+
init_error_patterns();
|
|
2515
2494
|
BaseProvider = class _BaseProvider {
|
|
2516
2495
|
/**
|
|
2517
2496
|
* Whitelist of allowed provider names for security
|
|
@@ -2544,6 +2523,10 @@ var init_base_provider = __esm({
|
|
|
2544
2523
|
NO_UPDATE_NOTIFIER: "1",
|
|
2545
2524
|
DEBIAN_FRONTEND: "noninteractive"
|
|
2546
2525
|
};
|
|
2526
|
+
/** Default CLI execution timeout in milliseconds */
|
|
2527
|
+
static DEFAULT_TIMEOUT_MS = 12e4;
|
|
2528
|
+
/** Time to wait after SIGTERM before escalating to SIGKILL */
|
|
2529
|
+
static SIGKILL_ESCALATION_MS = 5e3;
|
|
2547
2530
|
config;
|
|
2548
2531
|
logger = logger;
|
|
2549
2532
|
health;
|
|
@@ -2601,7 +2584,7 @@ var init_base_provider = __esm({
|
|
|
2601
2584
|
useStdin,
|
|
2602
2585
|
streaming: process.env.AUTOMATOSX_SHOW_PROVIDER_OUTPUT === "true"
|
|
2603
2586
|
});
|
|
2604
|
-
const result = useStdin ? await this.executeWithStdin(cliCommand2,
|
|
2587
|
+
const result = useStdin ? await this.executeWithStdin(cliCommand2, cliArgs, prompt) : await this.executeWithSpawn(fullCommand, cliCommand2);
|
|
2605
2588
|
if (!result.stdout) {
|
|
2606
2589
|
throw new Error(`${cliCommand2} CLI returned empty output. stderr: ${result.stderr || "none"}`);
|
|
2607
2590
|
}
|
|
@@ -2623,8 +2606,8 @@ var init_base_provider = __esm({
|
|
|
2623
2606
|
/**
|
|
2624
2607
|
* Execute command using spawn() with streaming support (v8.4.18)
|
|
2625
2608
|
*
|
|
2626
|
-
*
|
|
2627
|
-
*
|
|
2609
|
+
* Supports real-time line-by-line output streaming with proper timeout
|
|
2610
|
+
* and cleanup behaviors (SIGTERM → SIGKILL escalation pattern).
|
|
2628
2611
|
*
|
|
2629
2612
|
* @param command - Full command string to execute
|
|
2630
2613
|
* @param cliCommand - CLI command name (for logging)
|
|
@@ -2635,7 +2618,7 @@ var init_base_provider = __esm({
|
|
|
2635
2618
|
const child = spawn(command, [], {
|
|
2636
2619
|
shell: true,
|
|
2637
2620
|
// Auto-detects: cmd.exe on Windows, /bin/sh on Unix
|
|
2638
|
-
timeout: this.config.timeout ||
|
|
2621
|
+
timeout: this.config.timeout || _BaseProvider.DEFAULT_TIMEOUT_MS,
|
|
2639
2622
|
env: { ...process.env, ..._BaseProvider.NON_INTERACTIVE_ENV }
|
|
2640
2623
|
});
|
|
2641
2624
|
let stdout = "";
|
|
@@ -2746,7 +2729,7 @@ var init_base_provider = __esm({
|
|
|
2746
2729
|
});
|
|
2747
2730
|
reject(new Error(`Failed to spawn ${cliCommand2} CLI: ${error.message}`));
|
|
2748
2731
|
});
|
|
2749
|
-
const timeout = this.config.timeout ||
|
|
2732
|
+
const timeout = this.config.timeout || _BaseProvider.DEFAULT_TIMEOUT_MS;
|
|
2750
2733
|
timeoutId = setTimeout(() => {
|
|
2751
2734
|
if (child.pid && !child.killed) {
|
|
2752
2735
|
logger.warn("Killing child process due to timeout", {
|
|
@@ -2760,7 +2743,7 @@ var init_base_provider = __esm({
|
|
|
2760
2743
|
logger.warn("Force killing child process", { pid: child.pid });
|
|
2761
2744
|
child.kill("SIGKILL");
|
|
2762
2745
|
}
|
|
2763
|
-
},
|
|
2746
|
+
}, _BaseProvider.SIGKILL_ESCALATION_MS);
|
|
2764
2747
|
}
|
|
2765
2748
|
}, timeout);
|
|
2766
2749
|
});
|
|
@@ -2778,14 +2761,13 @@ var init_base_provider = __esm({
|
|
|
2778
2761
|
*/
|
|
2779
2762
|
async executeWithStdin(cliCommand2, cliArgs, prompt) {
|
|
2780
2763
|
return new Promise((resolve13, reject) => {
|
|
2781
|
-
const commandArgs = cliArgs ? cliArgs.split(" ").filter(Boolean) : [];
|
|
2782
2764
|
logger.debug(`Executing ${cliCommand2} CLI with stdin`, {
|
|
2783
2765
|
command: cliCommand2,
|
|
2784
|
-
args:
|
|
2766
|
+
args: cliArgs,
|
|
2785
2767
|
promptLength: prompt.length
|
|
2786
2768
|
});
|
|
2787
|
-
const child = spawn(cliCommand2,
|
|
2788
|
-
timeout: this.config.timeout ||
|
|
2769
|
+
const child = spawn(cliCommand2, cliArgs, {
|
|
2770
|
+
timeout: this.config.timeout || _BaseProvider.DEFAULT_TIMEOUT_MS,
|
|
2789
2771
|
env: { ...process.env, ..._BaseProvider.NON_INTERACTIVE_ENV }
|
|
2790
2772
|
});
|
|
2791
2773
|
let stdout = "";
|
|
@@ -2921,7 +2903,7 @@ var init_base_provider = __esm({
|
|
|
2921
2903
|
});
|
|
2922
2904
|
reject(new Error(`Failed to spawn ${cliCommand2} CLI: ${error.message}`));
|
|
2923
2905
|
});
|
|
2924
|
-
const timeout = this.config.timeout ||
|
|
2906
|
+
const timeout = this.config.timeout || _BaseProvider.DEFAULT_TIMEOUT_MS;
|
|
2925
2907
|
timeoutId = setTimeout(() => {
|
|
2926
2908
|
if (child.pid && !child.killed) {
|
|
2927
2909
|
logger.warn("Killing child process due to timeout", {
|
|
@@ -2935,7 +2917,7 @@ var init_base_provider = __esm({
|
|
|
2935
2917
|
logger.warn("Force killing child process", { pid: child.pid });
|
|
2936
2918
|
child.kill("SIGKILL");
|
|
2937
2919
|
}
|
|
2938
|
-
},
|
|
2920
|
+
}, _BaseProvider.SIGKILL_ESCALATION_MS);
|
|
2939
2921
|
}
|
|
2940
2922
|
}, timeout);
|
|
2941
2923
|
});
|
|
@@ -3001,10 +2983,8 @@ var init_base_provider = __esm({
|
|
|
3001
2983
|
${request.prompt}`;
|
|
3002
2984
|
}
|
|
3003
2985
|
if (process.env.AUTOMATOSX_DEBUG_PROMPT === "true") {
|
|
3004
|
-
const
|
|
3005
|
-
|
|
3006
|
-
const debugPath = path7.join(process.cwd(), "automatosx/tmp/debug-prompt.txt");
|
|
3007
|
-
fs7.writeFileSync(debugPath, `=== FULL PROMPT SENT TO ${this.getCLICommand()} ===
|
|
2986
|
+
const debugPath = path4.join(process.cwd(), "automatosx/tmp/debug-prompt.txt");
|
|
2987
|
+
fs3.writeFileSync(debugPath, `=== FULL PROMPT SENT TO ${this.getCLICommand()} ===
|
|
3008
2988
|
|
|
3009
2989
|
${fullPrompt}
|
|
3010
2990
|
|
|
@@ -3127,26 +3107,16 @@ ${fullPrompt}
|
|
|
3127
3107
|
* @returns true if this is a rate limit or quota error
|
|
3128
3108
|
*/
|
|
3129
3109
|
detectRateLimitError(error) {
|
|
3130
|
-
const
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
if (isLimited) {
|
|
3134
|
-
this.logger.debug("Rate limit error detected", {
|
|
3135
|
-
provider: this.config.name,
|
|
3136
|
-
message: error?.message,
|
|
3137
|
-
code: error?.code,
|
|
3138
|
-
status: error?.status || error?.statusCode
|
|
3139
|
-
});
|
|
3140
|
-
}
|
|
3141
|
-
return isLimited;
|
|
3142
|
-
} catch (detectionError) {
|
|
3143
|
-
this.logger.warn("Rate limit detection failed, using fallback", {
|
|
3110
|
+
const isLimited = isLimitError(error, this.config.name);
|
|
3111
|
+
if (isLimited) {
|
|
3112
|
+
this.logger.debug("Rate limit error detected", {
|
|
3144
3113
|
provider: this.config.name,
|
|
3145
|
-
|
|
3114
|
+
message: error?.message,
|
|
3115
|
+
code: error?.code,
|
|
3116
|
+
status: error?.status || error?.statusCode
|
|
3146
3117
|
});
|
|
3147
|
-
const message = (error?.message || "").toLowerCase();
|
|
3148
|
-
return message.includes("rate limit") || message.includes("quota") || message.includes("resource_exhausted") || message.includes("too many requests");
|
|
3149
3118
|
}
|
|
3119
|
+
return isLimited;
|
|
3150
3120
|
}
|
|
3151
3121
|
/**
|
|
3152
3122
|
* Escape shell command arguments to prevent injection
|
|
@@ -4874,24 +4844,25 @@ var init_token_estimator = __esm({
|
|
|
4874
4844
|
};
|
|
4875
4845
|
}
|
|
4876
4846
|
});
|
|
4877
|
-
|
|
4878
|
-
// src/integrations/ax-cli-sdk/subagent-adapter.ts
|
|
4879
|
-
var TOKEN_SPLIT, SubagentAdapter;
|
|
4847
|
+
var TOKEN_SPLIT, DEFAULT_MAX_PARALLEL, DEFAULT_TIMEOUT_MS, DEFAULT_SUBAGENT_MAX_TOOL_ROUNDS, SubagentAdapter;
|
|
4880
4848
|
var init_subagent_adapter = __esm({
|
|
4881
4849
|
"src/integrations/ax-cli-sdk/subagent-adapter.ts"() {
|
|
4882
4850
|
init_esm_shims();
|
|
4883
4851
|
init_logger();
|
|
4884
4852
|
TOKEN_SPLIT = { PROMPT: 0.3, COMPLETION: 0.7 };
|
|
4853
|
+
DEFAULT_MAX_PARALLEL = 4;
|
|
4854
|
+
DEFAULT_TIMEOUT_MS = 3e5;
|
|
4855
|
+
DEFAULT_SUBAGENT_MAX_TOOL_ROUNDS = 100;
|
|
4885
4856
|
SubagentAdapter = class {
|
|
4886
4857
|
orchestrator = null;
|
|
4887
4858
|
subagents = /* @__PURE__ */ new Map();
|
|
4859
|
+
busySubagents = /* @__PURE__ */ new Set();
|
|
4888
4860
|
sdkAvailable = null;
|
|
4889
4861
|
options;
|
|
4890
4862
|
constructor(options = {}) {
|
|
4891
4863
|
this.options = {
|
|
4892
|
-
maxParallel: options.maxParallel ??
|
|
4893
|
-
timeout: options.timeout ??
|
|
4894
|
-
// 5 minutes
|
|
4864
|
+
maxParallel: options.maxParallel ?? DEFAULT_MAX_PARALLEL,
|
|
4865
|
+
timeout: options.timeout ?? DEFAULT_TIMEOUT_MS,
|
|
4895
4866
|
sharedContext: options.sharedContext ?? true,
|
|
4896
4867
|
continueOnError: options.continueOnError ?? true,
|
|
4897
4868
|
events: options.events,
|
|
@@ -4946,23 +4917,41 @@ var init_subagent_adapter = __esm({
|
|
|
4946
4917
|
taskCount: tasks.length,
|
|
4947
4918
|
maxParallel: this.options.maxParallel
|
|
4948
4919
|
});
|
|
4949
|
-
const
|
|
4950
|
-
const
|
|
4920
|
+
const tasksWithIndex = tasks.map((task, index) => ({ task, index }));
|
|
4921
|
+
const sortedTasks = [...tasksWithIndex].sort(
|
|
4922
|
+
(a, b) => (a.task.priority ?? 0) - (b.task.priority ?? 0)
|
|
4923
|
+
);
|
|
4924
|
+
const results = new Array(tasks.length);
|
|
4951
4925
|
const batchSize = this.options.maxParallel;
|
|
4952
4926
|
for (let i = 0; i < sortedTasks.length; i += batchSize) {
|
|
4953
4927
|
const batch = sortedTasks.slice(i, i + batchSize);
|
|
4954
|
-
const batchResults = await this.executeBatch(batch);
|
|
4955
|
-
|
|
4928
|
+
const batchResults = await this.executeBatch(batch.map((item) => item.task));
|
|
4929
|
+
batch.forEach((item, idx) => {
|
|
4930
|
+
results[item.index] = batchResults[idx];
|
|
4931
|
+
});
|
|
4956
4932
|
if (this.options.sharedContext && i + batchSize < sortedTasks.length) {
|
|
4957
4933
|
await this.propagateContext(batchResults);
|
|
4958
4934
|
}
|
|
4959
4935
|
}
|
|
4936
|
+
const finalResults = results.map((result, index) => {
|
|
4937
|
+
if (result) {
|
|
4938
|
+
return result;
|
|
4939
|
+
}
|
|
4940
|
+
return {
|
|
4941
|
+
task: tasks[index]?.task ?? "unknown",
|
|
4942
|
+
role: tasks[index]?.config.role ?? "custom",
|
|
4943
|
+
content: "",
|
|
4944
|
+
success: false,
|
|
4945
|
+
error: "Subagent result missing",
|
|
4946
|
+
latencyMs: 0
|
|
4947
|
+
};
|
|
4948
|
+
});
|
|
4960
4949
|
logger.info("Parallel execution complete", {
|
|
4961
4950
|
taskCount: tasks.length,
|
|
4962
|
-
successCount:
|
|
4951
|
+
successCount: finalResults.filter((r) => r.success).length,
|
|
4963
4952
|
totalLatencyMs: Date.now() - startTime
|
|
4964
4953
|
});
|
|
4965
|
-
return
|
|
4954
|
+
return finalResults;
|
|
4966
4955
|
}
|
|
4967
4956
|
/**
|
|
4968
4957
|
* Execute tasks sequentially with context propagation
|
|
@@ -4980,18 +4969,27 @@ var init_subagent_adapter = __esm({
|
|
|
4980
4969
|
const results = [];
|
|
4981
4970
|
let accumulatedContext = "";
|
|
4982
4971
|
for (const task of tasks) {
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4972
|
+
let combinedContext;
|
|
4973
|
+
if (task.context && accumulatedContext) {
|
|
4974
|
+
combinedContext = `${task.context}
|
|
4986
4975
|
|
|
4987
4976
|
Previous results:
|
|
4988
|
-
${accumulatedContext}
|
|
4977
|
+
${accumulatedContext}`;
|
|
4978
|
+
} else if (task.context) {
|
|
4979
|
+
combinedContext = task.context;
|
|
4980
|
+
} else if (accumulatedContext) {
|
|
4981
|
+
combinedContext = accumulatedContext;
|
|
4982
|
+
}
|
|
4983
|
+
const taskWithContext = {
|
|
4984
|
+
...task,
|
|
4985
|
+
context: combinedContext
|
|
4989
4986
|
};
|
|
4990
4987
|
const result = await this.executeTask(taskWithContext);
|
|
4991
4988
|
results.push(result);
|
|
4992
4989
|
if (result.success && this.options.sharedContext) {
|
|
4990
|
+
const truncated = result.content.length > 500;
|
|
4993
4991
|
accumulatedContext += `
|
|
4994
|
-
[${result.role}]: ${result.content.substring(0, 500)}...
|
|
4992
|
+
[${result.role}]: ${result.content.substring(0, 500)}${truncated ? "..." : ""}
|
|
4995
4993
|
`;
|
|
4996
4994
|
}
|
|
4997
4995
|
if (!result.success && !this.options.continueOnError) {
|
|
@@ -5017,6 +5015,7 @@ ${accumulatedContext}` : accumulatedContext || void 0
|
|
|
5017
5015
|
const startTime = Date.now();
|
|
5018
5016
|
const subagentKey = this.getSubagentKey(task.config);
|
|
5019
5017
|
const taskId = `${subagentKey}:${Date.now()}`;
|
|
5018
|
+
let release = null;
|
|
5020
5019
|
this.emitEvent("task_start", task.task);
|
|
5021
5020
|
this.emitEvent("state_change", {
|
|
5022
5021
|
previousState: "idle",
|
|
@@ -5029,7 +5028,9 @@ ${accumulatedContext}` : accumulatedContext || void 0
|
|
|
5029
5028
|
message: `Starting ${task.config.role} task`
|
|
5030
5029
|
});
|
|
5031
5030
|
try {
|
|
5032
|
-
const
|
|
5031
|
+
const acquired = await this.acquireSubagent(task.config);
|
|
5032
|
+
const subagent = acquired.subagent;
|
|
5033
|
+
release = acquired.release;
|
|
5033
5034
|
const prompt = task.context ? `Context:
|
|
5034
5035
|
${task.context}
|
|
5035
5036
|
|
|
@@ -5120,6 +5121,10 @@ ${task.task}` : task.task;
|
|
|
5120
5121
|
error: errorMessage,
|
|
5121
5122
|
latencyMs
|
|
5122
5123
|
};
|
|
5124
|
+
} finally {
|
|
5125
|
+
if (release) {
|
|
5126
|
+
release();
|
|
5127
|
+
}
|
|
5123
5128
|
}
|
|
5124
5129
|
}
|
|
5125
5130
|
/**
|
|
@@ -5142,7 +5147,11 @@ ${task.task}` : task.task;
|
|
|
5142
5147
|
* Propagate context from completed tasks
|
|
5143
5148
|
*/
|
|
5144
5149
|
async propagateContext(results) {
|
|
5145
|
-
const contextSummary = results.filter((r) => r.success).map((r) =>
|
|
5150
|
+
const contextSummary = results.filter((r) => r.success).map((r) => {
|
|
5151
|
+
const truncated = r.content.length > 200;
|
|
5152
|
+
const summary = r.content.substring(0, 200);
|
|
5153
|
+
return `[${r.role}]: ${summary}${truncated ? "..." : ""}`;
|
|
5154
|
+
}).join("\n");
|
|
5146
5155
|
if (contextSummary && this.orchestrator?.setSharedContext) {
|
|
5147
5156
|
try {
|
|
5148
5157
|
await this.orchestrator.setSharedContext(contextSummary);
|
|
@@ -5168,7 +5177,7 @@ ${task.task}` : task.task;
|
|
|
5168
5177
|
const { createSubagent } = await import('@defai.digital/ax-cli/sdk');
|
|
5169
5178
|
const subagent = createSubagent(config.role, {
|
|
5170
5179
|
systemPrompt: config.instructions,
|
|
5171
|
-
maxToolRounds: config.maxToolRounds ??
|
|
5180
|
+
maxToolRounds: config.maxToolRounds ?? DEFAULT_SUBAGENT_MAX_TOOL_ROUNDS
|
|
5172
5181
|
});
|
|
5173
5182
|
this.subagents.set(key, subagent);
|
|
5174
5183
|
logger.debug("Created new subagent", {
|
|
@@ -5185,11 +5194,70 @@ ${task.task}` : task.task;
|
|
|
5185
5194
|
throw error;
|
|
5186
5195
|
}
|
|
5187
5196
|
}
|
|
5197
|
+
/**
|
|
5198
|
+
* Create a temporary subagent instance. Used when the cached subagent is busy.
|
|
5199
|
+
*/
|
|
5200
|
+
async createEphemeralSubagent(config) {
|
|
5201
|
+
const { createSubagent } = await import('@defai.digital/ax-cli/sdk');
|
|
5202
|
+
return createSubagent(config.role, {
|
|
5203
|
+
systemPrompt: config.instructions,
|
|
5204
|
+
maxToolRounds: config.maxToolRounds ?? DEFAULT_SUBAGENT_MAX_TOOL_ROUNDS
|
|
5205
|
+
});
|
|
5206
|
+
}
|
|
5207
|
+
/**
|
|
5208
|
+
* Acquire a subagent instance for a task. If a cached instance is already
|
|
5209
|
+
* running another task, create a short-lived one to avoid interleaved
|
|
5210
|
+
* streams from concurrent executions.
|
|
5211
|
+
*/
|
|
5212
|
+
async acquireSubagent(config) {
|
|
5213
|
+
const key = this.getSubagentKey(config);
|
|
5214
|
+
if (!this.busySubagents.has(key)) {
|
|
5215
|
+
this.busySubagents.add(key);
|
|
5216
|
+
let subagent;
|
|
5217
|
+
try {
|
|
5218
|
+
subagent = await this.getOrCreateSubagent(config);
|
|
5219
|
+
} catch (error) {
|
|
5220
|
+
this.busySubagents.delete(key);
|
|
5221
|
+
throw error;
|
|
5222
|
+
}
|
|
5223
|
+
return {
|
|
5224
|
+
subagent,
|
|
5225
|
+
release: () => this.releaseSubagent(key)
|
|
5226
|
+
};
|
|
5227
|
+
}
|
|
5228
|
+
logger.debug("Cached subagent busy, creating ephemeral instance", { key });
|
|
5229
|
+
const ephemeral = await this.createEphemeralSubagent(config);
|
|
5230
|
+
return {
|
|
5231
|
+
subagent: ephemeral,
|
|
5232
|
+
release: () => {
|
|
5233
|
+
try {
|
|
5234
|
+
if (ephemeral.dispose) {
|
|
5235
|
+
const result = ephemeral.dispose();
|
|
5236
|
+
if (result instanceof Promise) {
|
|
5237
|
+
result.catch((err) => logger.warn("Error disposing ephemeral subagent", { error: err instanceof Error ? err.message : String(err) }));
|
|
5238
|
+
}
|
|
5239
|
+
}
|
|
5240
|
+
} catch (error) {
|
|
5241
|
+
logger.warn("Error disposing ephemeral subagent", {
|
|
5242
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5243
|
+
});
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
};
|
|
5247
|
+
}
|
|
5248
|
+
/**
|
|
5249
|
+
* Release a cached subagent so it can be reused.
|
|
5250
|
+
*/
|
|
5251
|
+
releaseSubagent(key) {
|
|
5252
|
+
this.busySubagents.delete(key);
|
|
5253
|
+
}
|
|
5188
5254
|
/**
|
|
5189
5255
|
* Generate unique key for subagent config
|
|
5190
5256
|
*/
|
|
5191
5257
|
getSubagentKey(config) {
|
|
5192
|
-
|
|
5258
|
+
const instructionsHash = config.instructions ? createHash("sha256").update(config.instructions).digest("hex").slice(0, 12) : "noinstr";
|
|
5259
|
+
const maxToolRounds = config.maxToolRounds ?? DEFAULT_SUBAGENT_MAX_TOOL_ROUNDS;
|
|
5260
|
+
return `${config.role}:${config.specialization || "default"}:${maxToolRounds}:${instructionsHash}`;
|
|
5193
5261
|
}
|
|
5194
5262
|
/**
|
|
5195
5263
|
* Ensure orchestrator is initialized
|
|
@@ -5245,8 +5313,11 @@ ${task.task}` : task.task;
|
|
|
5245
5313
|
}
|
|
5246
5314
|
/**
|
|
5247
5315
|
* Cleanup all subagents
|
|
5316
|
+
* BUG FIX: Continue cleanup even if individual subagent disposal fails,
|
|
5317
|
+
* and report all errors at the end to ensure no resources are leaked.
|
|
5248
5318
|
*/
|
|
5249
5319
|
async destroy() {
|
|
5320
|
+
const errors = [];
|
|
5250
5321
|
for (const [key, subagent] of this.subagents) {
|
|
5251
5322
|
try {
|
|
5252
5323
|
if (subagent.dispose) {
|
|
@@ -5257,24 +5328,54 @@ ${task.task}` : task.task;
|
|
|
5257
5328
|
}
|
|
5258
5329
|
logger.debug("Subagent disposed", { key });
|
|
5259
5330
|
} catch (error) {
|
|
5331
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
5260
5332
|
logger.warn("Error disposing subagent", {
|
|
5261
5333
|
key,
|
|
5262
|
-
error:
|
|
5334
|
+
error: errorMsg
|
|
5263
5335
|
});
|
|
5336
|
+
errors.push({ key, error: errorMsg });
|
|
5264
5337
|
}
|
|
5265
5338
|
}
|
|
5339
|
+
const orchestrator = this.orchestrator;
|
|
5266
5340
|
this.subagents.clear();
|
|
5341
|
+
this.busySubagents.clear();
|
|
5342
|
+
if (orchestrator && typeof orchestrator.dispose === "function") {
|
|
5343
|
+
try {
|
|
5344
|
+
await orchestrator.dispose();
|
|
5345
|
+
} catch (error) {
|
|
5346
|
+
logger.warn("Error disposing subagent orchestrator", {
|
|
5347
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5348
|
+
});
|
|
5349
|
+
}
|
|
5350
|
+
} else if (orchestrator && typeof orchestrator.shutdown === "function") {
|
|
5351
|
+
try {
|
|
5352
|
+
await orchestrator.shutdown();
|
|
5353
|
+
} catch (error) {
|
|
5354
|
+
logger.warn("Error shutting down subagent orchestrator", {
|
|
5355
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5356
|
+
});
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5267
5359
|
this.orchestrator = null;
|
|
5360
|
+
if (errors.length > 0) {
|
|
5361
|
+
logger.error("SubagentAdapter cleanup had errors", {
|
|
5362
|
+
errorCount: errors.length,
|
|
5363
|
+
errors
|
|
5364
|
+
});
|
|
5365
|
+
}
|
|
5268
5366
|
logger.debug("SubagentAdapter destroyed");
|
|
5269
5367
|
}
|
|
5270
5368
|
};
|
|
5271
5369
|
}
|
|
5272
5370
|
});
|
|
5273
|
-
var CheckpointAdapter;
|
|
5371
|
+
var DEFAULT_CHECKPOINT_DIR, DEFAULT_MAX_CHECKPOINTS, FLUSH_TIMEOUT_MS, CheckpointAdapter;
|
|
5274
5372
|
var init_checkpoint_adapter = __esm({
|
|
5275
5373
|
"src/integrations/ax-cli-sdk/checkpoint-adapter.ts"() {
|
|
5276
5374
|
init_esm_shims();
|
|
5277
5375
|
init_logger();
|
|
5376
|
+
DEFAULT_CHECKPOINT_DIR = ".automatosx/checkpoints";
|
|
5377
|
+
DEFAULT_MAX_CHECKPOINTS = 10;
|
|
5378
|
+
FLUSH_TIMEOUT_MS = 5e3;
|
|
5278
5379
|
CheckpointAdapter = class {
|
|
5279
5380
|
checkpointDir;
|
|
5280
5381
|
sdkCheckpointManager = null;
|
|
@@ -5282,11 +5383,12 @@ var init_checkpoint_adapter = __esm({
|
|
|
5282
5383
|
options;
|
|
5283
5384
|
autoSaveTimer = null;
|
|
5284
5385
|
pendingCheckpoint = null;
|
|
5386
|
+
fsLock = Promise.resolve();
|
|
5285
5387
|
constructor(options = {}) {
|
|
5286
5388
|
this.options = {
|
|
5287
|
-
checkpointDir: options.checkpointDir ??
|
|
5389
|
+
checkpointDir: options.checkpointDir ?? DEFAULT_CHECKPOINT_DIR,
|
|
5288
5390
|
autoSaveInterval: options.autoSaveInterval ?? 0,
|
|
5289
|
-
maxCheckpoints: options.maxCheckpoints ??
|
|
5391
|
+
maxCheckpoints: options.maxCheckpoints ?? DEFAULT_MAX_CHECKPOINTS,
|
|
5290
5392
|
compress: options.compress ?? false
|
|
5291
5393
|
};
|
|
5292
5394
|
this.checkpointDir = this.options.checkpointDir;
|
|
@@ -5328,8 +5430,10 @@ var init_checkpoint_adapter = __esm({
|
|
|
5328
5430
|
});
|
|
5329
5431
|
}
|
|
5330
5432
|
}
|
|
5331
|
-
await this.
|
|
5332
|
-
|
|
5433
|
+
await this.withFsLock(async () => {
|
|
5434
|
+
await this.saveToFileSystem(checkpoint);
|
|
5435
|
+
await this.cleanupOldCheckpoints(workflowId);
|
|
5436
|
+
});
|
|
5333
5437
|
logger.info("Checkpoint saved", {
|
|
5334
5438
|
workflowId,
|
|
5335
5439
|
phase: checkpoint.phase,
|
|
@@ -5387,7 +5491,7 @@ var init_checkpoint_adapter = __esm({
|
|
|
5387
5491
|
});
|
|
5388
5492
|
}
|
|
5389
5493
|
}
|
|
5390
|
-
await this.deleteFromFileSystem(workflowId);
|
|
5494
|
+
await this.withFsLock(() => this.deleteFromFileSystem(workflowId));
|
|
5391
5495
|
logger.info("Checkpoints deleted", { workflowId });
|
|
5392
5496
|
}
|
|
5393
5497
|
/**
|
|
@@ -5395,15 +5499,15 @@ var init_checkpoint_adapter = __esm({
|
|
|
5395
5499
|
*/
|
|
5396
5500
|
async list(workflowId) {
|
|
5397
5501
|
try {
|
|
5398
|
-
await
|
|
5399
|
-
const files = await
|
|
5502
|
+
await fs5.mkdir(this.checkpointDir, { recursive: true });
|
|
5503
|
+
const files = await fs5.readdir(this.checkpointDir);
|
|
5400
5504
|
const matchingFiles = files.filter(
|
|
5401
|
-
(file) => file.startsWith(workflowId) && file.endsWith(".json")
|
|
5505
|
+
(file) => file.startsWith(`${workflowId}-`) && file.endsWith(".json")
|
|
5402
5506
|
);
|
|
5403
5507
|
const results = await Promise.all(
|
|
5404
5508
|
matchingFiles.map(async (file) => {
|
|
5405
5509
|
try {
|
|
5406
|
-
const content = await
|
|
5510
|
+
const content = await fs5.readFile(
|
|
5407
5511
|
path4.join(this.checkpointDir, file),
|
|
5408
5512
|
"utf-8"
|
|
5409
5513
|
);
|
|
@@ -5433,6 +5537,13 @@ var init_checkpoint_adapter = __esm({
|
|
|
5433
5537
|
async savePhase(workflowId, phaseId, result, workflow) {
|
|
5434
5538
|
let checkpoint = await this.load(workflowId);
|
|
5435
5539
|
const phaseIndex = workflow.phases.findIndex((p) => p.id === phaseId);
|
|
5540
|
+
if (phaseIndex === -1) {
|
|
5541
|
+
logger.warn("Phase not found in workflow", {
|
|
5542
|
+
workflowId,
|
|
5543
|
+
phaseId,
|
|
5544
|
+
availablePhases: workflow.phases.map((p) => p.id)
|
|
5545
|
+
});
|
|
5546
|
+
}
|
|
5436
5547
|
if (!checkpoint) {
|
|
5437
5548
|
checkpoint = {
|
|
5438
5549
|
id: `${workflowId}-${Date.now()}`,
|
|
@@ -5449,9 +5560,12 @@ var init_checkpoint_adapter = __esm({
|
|
|
5449
5560
|
}
|
|
5450
5561
|
if (result.success) {
|
|
5451
5562
|
checkpoint.completedTasks.push(phaseId);
|
|
5452
|
-
|
|
5563
|
+
if (phaseIndex >= 0) {
|
|
5564
|
+
checkpoint.phase = phaseIndex + 1;
|
|
5565
|
+
}
|
|
5566
|
+
const phaseLabel = phaseIndex >= 0 ? `Phase ${phaseIndex + 1}` : "Unknown Phase";
|
|
5453
5567
|
checkpoint.context += `
|
|
5454
|
-
[
|
|
5568
|
+
[${phaseLabel}: ${phaseId}]
|
|
5455
5569
|
${result.content.substring(0, 1e3)}
|
|
5456
5570
|
`;
|
|
5457
5571
|
if (result.tokensUsed && checkpoint.tokensUsed) {
|
|
@@ -5498,11 +5612,11 @@ ${result.content.substring(0, 1e3)}
|
|
|
5498
5612
|
await this.sdkCheckpointManager.delete(workflowId);
|
|
5499
5613
|
}
|
|
5500
5614
|
async saveToFileSystem(checkpoint) {
|
|
5501
|
-
await
|
|
5615
|
+
await fs5.mkdir(this.checkpointDir, { recursive: true });
|
|
5502
5616
|
const filename = `${checkpoint.workflowId}-${checkpoint.phase}.json`;
|
|
5503
5617
|
const filepath = path4.join(this.checkpointDir, filename);
|
|
5504
5618
|
const content = JSON.stringify(checkpoint, null, 2);
|
|
5505
|
-
await
|
|
5619
|
+
await this.atomicWrite(filepath, content);
|
|
5506
5620
|
}
|
|
5507
5621
|
async loadFromFileSystem(workflowId) {
|
|
5508
5622
|
try {
|
|
@@ -5514,10 +5628,10 @@ ${result.content.substring(0, 1e3)}
|
|
|
5514
5628
|
}
|
|
5515
5629
|
async deleteFromFileSystem(workflowId) {
|
|
5516
5630
|
try {
|
|
5517
|
-
const files = await
|
|
5631
|
+
const files = await fs5.readdir(this.checkpointDir);
|
|
5518
5632
|
for (const file of files) {
|
|
5519
|
-
if (file.startsWith(workflowId) && file.endsWith(".json")) {
|
|
5520
|
-
await
|
|
5633
|
+
if (file.startsWith(`${workflowId}-`) && file.endsWith(".json")) {
|
|
5634
|
+
await fs5.unlink(path4.join(this.checkpointDir, file));
|
|
5521
5635
|
}
|
|
5522
5636
|
}
|
|
5523
5637
|
} catch (error) {
|
|
@@ -5535,7 +5649,7 @@ ${result.content.substring(0, 1e3)}
|
|
|
5535
5649
|
for (const checkpoint of toDelete) {
|
|
5536
5650
|
try {
|
|
5537
5651
|
const filename = `${checkpoint.workflowId}-${checkpoint.phase}.json`;
|
|
5538
|
-
await
|
|
5652
|
+
await fs5.unlink(path4.join(this.checkpointDir, filename));
|
|
5539
5653
|
} catch {
|
|
5540
5654
|
}
|
|
5541
5655
|
}
|
|
@@ -5559,8 +5673,11 @@ ${result.content.substring(0, 1e3)}
|
|
|
5559
5673
|
}
|
|
5560
5674
|
}
|
|
5561
5675
|
setupAutoSave() {
|
|
5676
|
+
let autoSaveRunning = false;
|
|
5562
5677
|
this.autoSaveTimer = setInterval(async () => {
|
|
5678
|
+
if (autoSaveRunning) return;
|
|
5563
5679
|
if (this.pendingCheckpoint) {
|
|
5680
|
+
autoSaveRunning = true;
|
|
5564
5681
|
try {
|
|
5565
5682
|
await this.save(
|
|
5566
5683
|
this.pendingCheckpoint.workflowId,
|
|
@@ -5571,6 +5688,8 @@ ${result.content.substring(0, 1e3)}
|
|
|
5571
5688
|
logger.warn("Auto-save failed", {
|
|
5572
5689
|
error: error instanceof Error ? error.message : String(error)
|
|
5573
5690
|
});
|
|
5691
|
+
} finally {
|
|
5692
|
+
autoSaveRunning = false;
|
|
5574
5693
|
}
|
|
5575
5694
|
}
|
|
5576
5695
|
}, this.options.autoSaveInterval);
|
|
@@ -5584,6 +5703,7 @@ ${result.content.substring(0, 1e3)}
|
|
|
5584
5703
|
/**
|
|
5585
5704
|
* Cleanup resources
|
|
5586
5705
|
* BUG FIX: Flush pending checkpoint before destroying to prevent data loss
|
|
5706
|
+
* BUG FIX: Add timeout to prevent hanging during cleanup
|
|
5587
5707
|
*/
|
|
5588
5708
|
async destroy() {
|
|
5589
5709
|
if (this.autoSaveTimer) {
|
|
@@ -5592,10 +5712,15 @@ ${result.content.substring(0, 1e3)}
|
|
|
5592
5712
|
}
|
|
5593
5713
|
if (this.pendingCheckpoint) {
|
|
5594
5714
|
try {
|
|
5595
|
-
await
|
|
5596
|
-
this.
|
|
5597
|
-
|
|
5598
|
-
|
|
5715
|
+
await Promise.race([
|
|
5716
|
+
this.save(
|
|
5717
|
+
this.pendingCheckpoint.workflowId,
|
|
5718
|
+
this.pendingCheckpoint
|
|
5719
|
+
),
|
|
5720
|
+
new Promise(
|
|
5721
|
+
(_, reject) => setTimeout(() => reject(new Error("Checkpoint flush timed out")), FLUSH_TIMEOUT_MS)
|
|
5722
|
+
)
|
|
5723
|
+
]);
|
|
5599
5724
|
logger.debug("Pending checkpoint flushed on destroy", {
|
|
5600
5725
|
workflowId: this.pendingCheckpoint.workflowId
|
|
5601
5726
|
});
|
|
@@ -5609,12 +5734,44 @@ ${result.content.substring(0, 1e3)}
|
|
|
5609
5734
|
this.sdkCheckpointManager = null;
|
|
5610
5735
|
logger.debug("CheckpointAdapter destroyed");
|
|
5611
5736
|
}
|
|
5737
|
+
/**
|
|
5738
|
+
* Serialize filesystem operations to avoid race conditions between auto-save and manual saves.
|
|
5739
|
+
*/
|
|
5740
|
+
async withFsLock(fn) {
|
|
5741
|
+
const resultPromise = this.fsLock.then(fn, fn);
|
|
5742
|
+
this.fsLock = resultPromise.then(
|
|
5743
|
+
() => Promise.resolve(),
|
|
5744
|
+
() => Promise.resolve()
|
|
5745
|
+
);
|
|
5746
|
+
return resultPromise;
|
|
5747
|
+
}
|
|
5748
|
+
/**
|
|
5749
|
+
* Write checkpoint atomically to avoid partial files being read by list/load.
|
|
5750
|
+
* BUG FIX: Clean up temp file on rename failure to prevent resource leak.
|
|
5751
|
+
*/
|
|
5752
|
+
async atomicWrite(filepath, content) {
|
|
5753
|
+
const tempFile = `${filepath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
5754
|
+
await fs5.writeFile(tempFile, content, "utf-8");
|
|
5755
|
+
try {
|
|
5756
|
+
await fs5.rename(tempFile, filepath);
|
|
5757
|
+
} catch (renameError) {
|
|
5758
|
+
try {
|
|
5759
|
+
await fs5.unlink(tempFile);
|
|
5760
|
+
} catch {
|
|
5761
|
+
}
|
|
5762
|
+
throw renameError;
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5612
5765
|
};
|
|
5613
5766
|
}
|
|
5614
5767
|
});
|
|
5615
5768
|
function getInstructionsBridge(options) {
|
|
5616
5769
|
if (!defaultBridge) {
|
|
5617
5770
|
defaultBridge = new InstructionsBridge(options);
|
|
5771
|
+
} else if (options) {
|
|
5772
|
+
logger.warn("InstructionsBridge already initialized, ignoring new options", {
|
|
5773
|
+
hint: "Use resetInstructionsBridge() to recreate with new options"
|
|
5774
|
+
});
|
|
5618
5775
|
}
|
|
5619
5776
|
return defaultBridge;
|
|
5620
5777
|
}
|
|
@@ -5646,8 +5803,9 @@ var init_instructions_bridge = __esm({
|
|
|
5646
5803
|
* @returns Combined instructions from all sources
|
|
5647
5804
|
*/
|
|
5648
5805
|
async getInstructions(agentName, additionalContext) {
|
|
5806
|
+
const cacheSignature = await this.buildCacheSignature(agentName);
|
|
5649
5807
|
const cached = this.cache.get(agentName);
|
|
5650
|
-
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
|
|
5808
|
+
if (cached && cached.signature === cacheSignature && Date.now() - cached.timestamp < this.CACHE_TTL) {
|
|
5651
5809
|
logger.debug("Using cached instructions", { agentName });
|
|
5652
5810
|
if (additionalContext) {
|
|
5653
5811
|
return {
|
|
@@ -5685,7 +5843,11 @@ var init_instructions_bridge = __esm({
|
|
|
5685
5843
|
projectMemory: !!projectContext
|
|
5686
5844
|
}
|
|
5687
5845
|
};
|
|
5688
|
-
this.cache.set(agentName, {
|
|
5846
|
+
this.cache.set(agentName, {
|
|
5847
|
+
instructions: combined,
|
|
5848
|
+
timestamp: Date.now(),
|
|
5849
|
+
signature: cacheSignature
|
|
5850
|
+
});
|
|
5689
5851
|
logger.info("Instructions combined", {
|
|
5690
5852
|
agentName,
|
|
5691
5853
|
sources: combined.sources,
|
|
@@ -5726,7 +5888,7 @@ var init_instructions_bridge = __esm({
|
|
|
5726
5888
|
async loadAgentProfile(agentName) {
|
|
5727
5889
|
const profilePath = path4.join(this.options.agentsDir, `${agentName}.ax.yaml`);
|
|
5728
5890
|
try {
|
|
5729
|
-
const content = await
|
|
5891
|
+
const content = await fs5.readFile(profilePath, "utf-8");
|
|
5730
5892
|
const profile = this.parseYamlProfile(content);
|
|
5731
5893
|
logger.debug("Agent profile loaded", { agentName, profilePath });
|
|
5732
5894
|
return profile;
|
|
@@ -5761,7 +5923,7 @@ var init_instructions_bridge = __esm({
|
|
|
5761
5923
|
}
|
|
5762
5924
|
}
|
|
5763
5925
|
try {
|
|
5764
|
-
const content = await
|
|
5926
|
+
const content = await fs5.readFile(this.options.axCliCustomPath, "utf-8");
|
|
5765
5927
|
logger.debug("Custom instructions loaded from file", {
|
|
5766
5928
|
path: this.options.axCliCustomPath
|
|
5767
5929
|
});
|
|
@@ -5880,8 +6042,8 @@ ${profile.expertise.map((e) => `- ${e}`).join("\n")}
|
|
|
5880
6042
|
${profile.instructions}
|
|
5881
6043
|
`;
|
|
5882
6044
|
try {
|
|
5883
|
-
await
|
|
5884
|
-
await
|
|
6045
|
+
await fs5.mkdir(path4.dirname(this.options.axCliCustomPath), { recursive: true });
|
|
6046
|
+
await fs5.writeFile(this.options.axCliCustomPath, customContent, "utf-8");
|
|
5885
6047
|
logger.info("Agent synced to ax-cli custom instructions", {
|
|
5886
6048
|
agentName,
|
|
5887
6049
|
path: this.options.axCliCustomPath
|
|
@@ -5923,6 +6085,26 @@ ${profile.instructions}
|
|
|
5923
6085
|
this.cache.delete(agentName);
|
|
5924
6086
|
logger.debug("Agent cache cleared", { agentName });
|
|
5925
6087
|
}
|
|
6088
|
+
/**
|
|
6089
|
+
* Build a cache signature from underlying file mtimes to invalidate cache when
|
|
6090
|
+
* agent profiles or custom instructions change on disk.
|
|
6091
|
+
*/
|
|
6092
|
+
async buildCacheSignature(agentName) {
|
|
6093
|
+
const profilePath = path4.join(this.options.agentsDir, `${agentName}.ax.yaml`);
|
|
6094
|
+
const [profileSig, customSig] = await Promise.all([
|
|
6095
|
+
this.getFileSignature(profilePath),
|
|
6096
|
+
this.getFileSignature(this.options.axCliCustomPath)
|
|
6097
|
+
]);
|
|
6098
|
+
return [profileSig, customSig, this.options.includeProjectMemory ? "mem" : "nomem"].join("|");
|
|
6099
|
+
}
|
|
6100
|
+
async getFileSignature(filePath) {
|
|
6101
|
+
try {
|
|
6102
|
+
const stats = await fs5.stat(filePath);
|
|
6103
|
+
return `${stats.mtimeMs}:${stats.size}`;
|
|
6104
|
+
} catch {
|
|
6105
|
+
return "missing";
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
5926
6108
|
};
|
|
5927
6109
|
defaultBridge = null;
|
|
5928
6110
|
}
|
|
@@ -5932,14 +6114,19 @@ ${profile.instructions}
|
|
|
5932
6114
|
function getAxCliMCPManager(options) {
|
|
5933
6115
|
if (!defaultManager2) {
|
|
5934
6116
|
defaultManager2 = new AxCliMCPManager(options);
|
|
6117
|
+
} else if (options) {
|
|
6118
|
+
logger.warn("AxCliMCPManager already initialized, ignoring new options", {
|
|
6119
|
+
hint: "Use resetAxCliMCPManager() to recreate with new options"
|
|
6120
|
+
});
|
|
5935
6121
|
}
|
|
5936
6122
|
return defaultManager2;
|
|
5937
6123
|
}
|
|
5938
|
-
var AxCliMCPManager, defaultManager2;
|
|
6124
|
+
var SDK_NOT_AVAILABLE_ERROR, AxCliMCPManager, defaultManager2;
|
|
5939
6125
|
var init_mcp_manager = __esm({
|
|
5940
6126
|
"src/integrations/ax-cli-sdk/mcp-manager.ts"() {
|
|
5941
6127
|
init_esm_shims();
|
|
5942
6128
|
init_logger();
|
|
6129
|
+
SDK_NOT_AVAILABLE_ERROR = "ax-cli SDK not available";
|
|
5943
6130
|
AxCliMCPManager = class {
|
|
5944
6131
|
sdkAvailable = null;
|
|
5945
6132
|
mcpModule = null;
|
|
@@ -5976,7 +6163,7 @@ var init_mcp_manager = __esm({
|
|
|
5976
6163
|
async getTemplateNames() {
|
|
5977
6164
|
try {
|
|
5978
6165
|
if (!await this.isAvailable()) {
|
|
5979
|
-
return { ok: false, error: new Error(
|
|
6166
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
5980
6167
|
}
|
|
5981
6168
|
const { MCPManager } = this.mcpModule;
|
|
5982
6169
|
if (MCPManager?.getTemplateNames) {
|
|
@@ -6013,7 +6200,7 @@ var init_mcp_manager = __esm({
|
|
|
6013
6200
|
async getTemplate(name) {
|
|
6014
6201
|
try {
|
|
6015
6202
|
if (!await this.isAvailable()) {
|
|
6016
|
-
return { ok: false, error: new Error(
|
|
6203
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6017
6204
|
}
|
|
6018
6205
|
const { MCPManager } = this.mcpModule;
|
|
6019
6206
|
if (MCPManager?.getTemplate) {
|
|
@@ -6037,7 +6224,7 @@ var init_mcp_manager = __esm({
|
|
|
6037
6224
|
async getTemplatesByCategory(category) {
|
|
6038
6225
|
try {
|
|
6039
6226
|
if (!await this.isAvailable()) {
|
|
6040
|
-
return { ok: false, error: new Error(
|
|
6227
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6041
6228
|
}
|
|
6042
6229
|
const { MCPManager } = this.mcpModule;
|
|
6043
6230
|
if (MCPManager?.getTemplatesByCategory) {
|
|
@@ -6058,7 +6245,7 @@ var init_mcp_manager = __esm({
|
|
|
6058
6245
|
async searchTemplates(keyword) {
|
|
6059
6246
|
try {
|
|
6060
6247
|
if (!await this.isAvailable()) {
|
|
6061
|
-
return { ok: false, error: new Error(
|
|
6248
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6062
6249
|
}
|
|
6063
6250
|
const { MCPManager } = this.mcpModule;
|
|
6064
6251
|
if (MCPManager?.searchTemplates) {
|
|
@@ -6079,7 +6266,7 @@ var init_mcp_manager = __esm({
|
|
|
6079
6266
|
async generateConfigFromTemplate(templateName, env) {
|
|
6080
6267
|
try {
|
|
6081
6268
|
if (!await this.isAvailable()) {
|
|
6082
|
-
return { ok: false, error: new Error(
|
|
6269
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6083
6270
|
}
|
|
6084
6271
|
const { MCPManager } = this.mcpModule;
|
|
6085
6272
|
if (MCPManager?.generateConfigFromTemplate) {
|
|
@@ -6100,7 +6287,7 @@ var init_mcp_manager = __esm({
|
|
|
6100
6287
|
async loadConfig() {
|
|
6101
6288
|
try {
|
|
6102
6289
|
if (!await this.isAvailable()) {
|
|
6103
|
-
return { ok: false, error: new Error(
|
|
6290
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6104
6291
|
}
|
|
6105
6292
|
const { MCPManager } = this.mcpModule;
|
|
6106
6293
|
if (MCPManager?.loadMCPConfig) {
|
|
@@ -6121,7 +6308,7 @@ var init_mcp_manager = __esm({
|
|
|
6121
6308
|
async addServer(name, config) {
|
|
6122
6309
|
try {
|
|
6123
6310
|
if (!await this.isAvailable()) {
|
|
6124
|
-
return { ok: false, error: new Error(
|
|
6311
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6125
6312
|
}
|
|
6126
6313
|
const { MCPManager } = this.mcpModule;
|
|
6127
6314
|
if (MCPManager?.addMCPServer) {
|
|
@@ -6143,7 +6330,7 @@ var init_mcp_manager = __esm({
|
|
|
6143
6330
|
async removeServer(name) {
|
|
6144
6331
|
try {
|
|
6145
6332
|
if (!await this.isAvailable()) {
|
|
6146
|
-
return { ok: false, error: new Error(
|
|
6333
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6147
6334
|
}
|
|
6148
6335
|
const { MCPManager } = this.mcpModule;
|
|
6149
6336
|
if (MCPManager?.removeMCPServer) {
|
|
@@ -6165,7 +6352,7 @@ var init_mcp_manager = __esm({
|
|
|
6165
6352
|
async getPredefinedServers() {
|
|
6166
6353
|
try {
|
|
6167
6354
|
if (!await this.isAvailable()) {
|
|
6168
|
-
return { ok: false, error: new Error(
|
|
6355
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6169
6356
|
}
|
|
6170
6357
|
const { MCPManager } = this.mcpModule;
|
|
6171
6358
|
if (MCPManager?.PREDEFINED_SERVERS) {
|
|
@@ -6217,7 +6404,7 @@ var init_mcp_manager = __esm({
|
|
|
6217
6404
|
async getServerStatus(name) {
|
|
6218
6405
|
try {
|
|
6219
6406
|
if (!await this.isAvailable()) {
|
|
6220
|
-
return { ok: false, error: new Error(
|
|
6407
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6221
6408
|
}
|
|
6222
6409
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6223
6410
|
if (MCPManagerV2?.getServerStatus) {
|
|
@@ -6251,7 +6438,7 @@ var init_mcp_manager = __esm({
|
|
|
6251
6438
|
async getAllServerStatuses() {
|
|
6252
6439
|
try {
|
|
6253
6440
|
if (!await this.isAvailable()) {
|
|
6254
|
-
return { ok: false, error: new Error(
|
|
6441
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6255
6442
|
}
|
|
6256
6443
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6257
6444
|
if (MCPManagerV2?.getAllServerStatuses) {
|
|
@@ -6275,7 +6462,7 @@ var init_mcp_manager = __esm({
|
|
|
6275
6462
|
async healthCheck() {
|
|
6276
6463
|
try {
|
|
6277
6464
|
if (!await this.isAvailable()) {
|
|
6278
|
-
return { ok: false, error: new Error(
|
|
6465
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6279
6466
|
}
|
|
6280
6467
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6281
6468
|
if (MCPManagerV2?.healthCheck) {
|
|
@@ -6300,7 +6487,7 @@ var init_mcp_manager = __esm({
|
|
|
6300
6487
|
async startServer(name) {
|
|
6301
6488
|
try {
|
|
6302
6489
|
if (!await this.isAvailable()) {
|
|
6303
|
-
return { ok: false, error: new Error(
|
|
6490
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6304
6491
|
}
|
|
6305
6492
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6306
6493
|
if (MCPManagerV2?.startServer) {
|
|
@@ -6315,9 +6502,16 @@ var init_mcp_manager = __esm({
|
|
|
6315
6502
|
}
|
|
6316
6503
|
return { ok: false, error: new Error("startServer not available in SDK") };
|
|
6317
6504
|
} catch (error) {
|
|
6505
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6506
|
+
this.serverStatuses.set(name, {
|
|
6507
|
+
name,
|
|
6508
|
+
status: "error",
|
|
6509
|
+
lastHealthCheck: /* @__PURE__ */ new Date(),
|
|
6510
|
+
error: errorMessage
|
|
6511
|
+
});
|
|
6318
6512
|
return {
|
|
6319
6513
|
ok: false,
|
|
6320
|
-
error: error instanceof Error ? error : new Error(
|
|
6514
|
+
error: error instanceof Error ? error : new Error(errorMessage)
|
|
6321
6515
|
};
|
|
6322
6516
|
}
|
|
6323
6517
|
}
|
|
@@ -6327,7 +6521,7 @@ var init_mcp_manager = __esm({
|
|
|
6327
6521
|
async stopServer(name) {
|
|
6328
6522
|
try {
|
|
6329
6523
|
if (!await this.isAvailable()) {
|
|
6330
|
-
return { ok: false, error: new Error(
|
|
6524
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6331
6525
|
}
|
|
6332
6526
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6333
6527
|
if (MCPManagerV2?.stopServer) {
|
|
@@ -6342,9 +6536,16 @@ var init_mcp_manager = __esm({
|
|
|
6342
6536
|
}
|
|
6343
6537
|
return { ok: false, error: new Error("stopServer not available in SDK") };
|
|
6344
6538
|
} catch (error) {
|
|
6539
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6540
|
+
this.serverStatuses.set(name, {
|
|
6541
|
+
name,
|
|
6542
|
+
status: "error",
|
|
6543
|
+
lastHealthCheck: /* @__PURE__ */ new Date(),
|
|
6544
|
+
error: errorMessage
|
|
6545
|
+
});
|
|
6345
6546
|
return {
|
|
6346
6547
|
ok: false,
|
|
6347
|
-
error: error instanceof Error ? error : new Error(
|
|
6548
|
+
error: error instanceof Error ? error : new Error(errorMessage)
|
|
6348
6549
|
};
|
|
6349
6550
|
}
|
|
6350
6551
|
}
|
|
@@ -6354,7 +6555,7 @@ var init_mcp_manager = __esm({
|
|
|
6354
6555
|
async restartServer(name) {
|
|
6355
6556
|
try {
|
|
6356
6557
|
if (!await this.isAvailable()) {
|
|
6357
|
-
return { ok: false, error: new Error(
|
|
6558
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6358
6559
|
}
|
|
6359
6560
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6360
6561
|
if (MCPManagerV2?.restartServer) {
|
|
@@ -6373,9 +6574,16 @@ var init_mcp_manager = __esm({
|
|
|
6373
6574
|
}
|
|
6374
6575
|
return this.startServer(name);
|
|
6375
6576
|
} catch (error) {
|
|
6577
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6578
|
+
this.serverStatuses.set(name, {
|
|
6579
|
+
name,
|
|
6580
|
+
status: "error",
|
|
6581
|
+
lastHealthCheck: /* @__PURE__ */ new Date(),
|
|
6582
|
+
error: errorMessage
|
|
6583
|
+
});
|
|
6376
6584
|
return {
|
|
6377
6585
|
ok: false,
|
|
6378
|
-
error: error instanceof Error ? error : new Error(
|
|
6586
|
+
error: error instanceof Error ? error : new Error(errorMessage)
|
|
6379
6587
|
};
|
|
6380
6588
|
}
|
|
6381
6589
|
}
|
|
@@ -6385,7 +6593,7 @@ var init_mcp_manager = __esm({
|
|
|
6385
6593
|
async shutdown() {
|
|
6386
6594
|
try {
|
|
6387
6595
|
if (!await this.isAvailable()) {
|
|
6388
|
-
return { ok: false, error: new Error(
|
|
6596
|
+
return { ok: false, error: new Error(SDK_NOT_AVAILABLE_ERROR) };
|
|
6389
6597
|
}
|
|
6390
6598
|
const { MCPManagerV2 } = this.mcpModule;
|
|
6391
6599
|
if (MCPManagerV2?.shutdown) {
|
|
@@ -6420,7 +6628,7 @@ var init_mcp_manager = __esm({
|
|
|
6420
6628
|
});
|
|
6421
6629
|
|
|
6422
6630
|
// src/integrations/ax-cli-sdk/adapter.ts
|
|
6423
|
-
var AxCliSdkAdapter;
|
|
6631
|
+
var DEFAULT_MAX_TOOL_ROUNDS, AxCliSdkAdapter;
|
|
6424
6632
|
var init_adapter2 = __esm({
|
|
6425
6633
|
"src/integrations/ax-cli-sdk/adapter.ts"() {
|
|
6426
6634
|
init_esm_shims();
|
|
@@ -6431,10 +6639,13 @@ var init_adapter2 = __esm({
|
|
|
6431
6639
|
init_instructions_bridge();
|
|
6432
6640
|
init_mcp_manager();
|
|
6433
6641
|
init_mcp_manager();
|
|
6642
|
+
DEFAULT_MAX_TOOL_ROUNDS = 400;
|
|
6434
6643
|
AxCliSdkAdapter = class _AxCliSdkAdapter {
|
|
6435
6644
|
agent = null;
|
|
6436
6645
|
// Will type as LLMAgent after import
|
|
6437
6646
|
agentConfig = null;
|
|
6647
|
+
initPromise = null;
|
|
6648
|
+
executionLock = Promise.resolve();
|
|
6438
6649
|
reuseEnabled;
|
|
6439
6650
|
streamingEnabled;
|
|
6440
6651
|
sdkAvailable = null;
|
|
@@ -6457,6 +6668,9 @@ var init_adapter2 = __esm({
|
|
|
6457
6668
|
/**
|
|
6458
6669
|
* Get or create SubagentAdapter for parallel multi-agent execution
|
|
6459
6670
|
*
|
|
6671
|
+
* BUG FIX: Log warning when options are provided but adapter already exists,
|
|
6672
|
+
* as the options will be ignored.
|
|
6673
|
+
*
|
|
6460
6674
|
* @example
|
|
6461
6675
|
* ```typescript
|
|
6462
6676
|
* const subagents = adapter.getSubagentAdapter();
|
|
@@ -6470,6 +6684,10 @@ var init_adapter2 = __esm({
|
|
|
6470
6684
|
if (!this.subagentAdapter) {
|
|
6471
6685
|
this.subagentAdapter = new SubagentAdapter(options);
|
|
6472
6686
|
logger.debug("SubagentAdapter created");
|
|
6687
|
+
} else if (options) {
|
|
6688
|
+
logger.warn("SubagentAdapter already exists, ignoring new options", {
|
|
6689
|
+
hint: "Call destroy() first to recreate with new options"
|
|
6690
|
+
});
|
|
6473
6691
|
}
|
|
6474
6692
|
return this.subagentAdapter;
|
|
6475
6693
|
}
|
|
@@ -6495,6 +6713,9 @@ var init_adapter2 = __esm({
|
|
|
6495
6713
|
/**
|
|
6496
6714
|
* Get or create CheckpointAdapter for resumable workflows
|
|
6497
6715
|
*
|
|
6716
|
+
* BUG FIX: Log warning when options are provided but adapter already exists,
|
|
6717
|
+
* as the options will be ignored.
|
|
6718
|
+
*
|
|
6498
6719
|
* @example
|
|
6499
6720
|
* ```typescript
|
|
6500
6721
|
* const checkpoints = adapter.getCheckpointAdapter();
|
|
@@ -6506,6 +6727,10 @@ var init_adapter2 = __esm({
|
|
|
6506
6727
|
if (!this.checkpointAdapter) {
|
|
6507
6728
|
this.checkpointAdapter = new CheckpointAdapter(options);
|
|
6508
6729
|
logger.debug("CheckpointAdapter created");
|
|
6730
|
+
} else if (options) {
|
|
6731
|
+
logger.warn("CheckpointAdapter already exists, ignoring new options", {
|
|
6732
|
+
hint: "Call destroy() first to recreate with new options"
|
|
6733
|
+
});
|
|
6509
6734
|
}
|
|
6510
6735
|
return this.checkpointAdapter;
|
|
6511
6736
|
}
|
|
@@ -6545,6 +6770,9 @@ var init_adapter2 = __esm({
|
|
|
6545
6770
|
/**
|
|
6546
6771
|
* Get or create InstructionsBridge for unified agent instructions
|
|
6547
6772
|
*
|
|
6773
|
+
* BUG FIX: Log warning when options are provided but bridge already exists,
|
|
6774
|
+
* as the options will be ignored.
|
|
6775
|
+
*
|
|
6548
6776
|
* @example
|
|
6549
6777
|
* ```typescript
|
|
6550
6778
|
* const bridge = adapter.getInstructionsBridge();
|
|
@@ -6556,6 +6784,10 @@ var init_adapter2 = __esm({
|
|
|
6556
6784
|
if (!this.instructionsBridge) {
|
|
6557
6785
|
this.instructionsBridge = getInstructionsBridge(options);
|
|
6558
6786
|
logger.debug("InstructionsBridge created");
|
|
6787
|
+
} else if (options) {
|
|
6788
|
+
logger.warn("InstructionsBridge already exists, ignoring new options", {
|
|
6789
|
+
hint: "Call destroy() first to recreate with new options"
|
|
6790
|
+
});
|
|
6559
6791
|
}
|
|
6560
6792
|
return this.instructionsBridge;
|
|
6561
6793
|
}
|
|
@@ -6580,6 +6812,9 @@ var init_adapter2 = __esm({
|
|
|
6580
6812
|
/**
|
|
6581
6813
|
* Get or create MCP Manager for ax-cli MCP server management
|
|
6582
6814
|
*
|
|
6815
|
+
* BUG FIX: Log warning when options are provided but manager already exists,
|
|
6816
|
+
* as the options will be ignored.
|
|
6817
|
+
*
|
|
6583
6818
|
* @example
|
|
6584
6819
|
* ```typescript
|
|
6585
6820
|
* const mcp = adapter.getMCPManager();
|
|
@@ -6591,6 +6826,10 @@ var init_adapter2 = __esm({
|
|
|
6591
6826
|
if (!this.mcpManager) {
|
|
6592
6827
|
this.mcpManager = getAxCliMCPManager(options);
|
|
6593
6828
|
logger.debug("AxCliMCPManager created");
|
|
6829
|
+
} else if (options) {
|
|
6830
|
+
logger.warn("AxCliMCPManager already exists, ignoring new options", {
|
|
6831
|
+
hint: "Call destroy() first to recreate with new options"
|
|
6832
|
+
});
|
|
6594
6833
|
}
|
|
6595
6834
|
return this.mcpManager;
|
|
6596
6835
|
}
|
|
@@ -6636,15 +6875,28 @@ var init_adapter2 = __esm({
|
|
|
6636
6875
|
* Performance: ~5ms overhead vs ~50-200ms for CLI spawning
|
|
6637
6876
|
*/
|
|
6638
6877
|
async execute(prompt, options) {
|
|
6878
|
+
return this.runExclusive(() => this.executeInternal(prompt, options));
|
|
6879
|
+
}
|
|
6880
|
+
/**
|
|
6881
|
+
* Serialize executions to avoid chat history corruption and token mis-tracking
|
|
6882
|
+
* when the same adapter instance is used concurrently.
|
|
6883
|
+
*/
|
|
6884
|
+
async runExclusive(fn) {
|
|
6885
|
+
const resultPromise = this.executionLock.then(fn, fn);
|
|
6886
|
+
this.executionLock = resultPromise.then(
|
|
6887
|
+
() => Promise.resolve(),
|
|
6888
|
+
() => Promise.resolve()
|
|
6889
|
+
);
|
|
6890
|
+
return resultPromise;
|
|
6891
|
+
}
|
|
6892
|
+
async executeInternal(prompt, options) {
|
|
6639
6893
|
const startTime = Date.now();
|
|
6640
6894
|
let totalTokens = 0;
|
|
6641
6895
|
try {
|
|
6642
6896
|
if (!await this.ensureSDKAvailable()) {
|
|
6643
6897
|
throw new Error("ax-cli SDK not available. Install with: npm install @defai.digital/ax-cli");
|
|
6644
6898
|
}
|
|
6645
|
-
|
|
6646
|
-
await this.initializeAgent(options);
|
|
6647
|
-
}
|
|
6899
|
+
await this.ensureAgent(options);
|
|
6648
6900
|
logger.debug("Executing via SDK (streaming mode for token tracking)", {
|
|
6649
6901
|
promptLength: prompt.length,
|
|
6650
6902
|
userWantsCallbacks: !!(options.onStream || options.onTool),
|
|
@@ -6728,10 +6980,11 @@ var init_adapter2 = __esm({
|
|
|
6728
6980
|
* We do NOT pass credentials to the SDK - it manages its own configuration.
|
|
6729
6981
|
*/
|
|
6730
6982
|
async initializeAgent(options) {
|
|
6983
|
+
await this.destroyAgentInstance();
|
|
6731
6984
|
const { createAgent } = await import('@defai.digital/ax-cli/sdk');
|
|
6732
6985
|
try {
|
|
6733
6986
|
const config = {
|
|
6734
|
-
maxToolRounds: options.maxToolRounds ||
|
|
6987
|
+
maxToolRounds: options.maxToolRounds || DEFAULT_MAX_TOOL_ROUNDS
|
|
6735
6988
|
};
|
|
6736
6989
|
logger.debug("Creating SDK agent (credentials from ax-cli settings)", {
|
|
6737
6990
|
maxToolRounds: config.maxToolRounds,
|
|
@@ -6793,22 +7046,50 @@ var init_adapter2 = __esm({
|
|
|
6793
7046
|
*/
|
|
6794
7047
|
hasConfigChanged(options) {
|
|
6795
7048
|
if (!this.agentConfig) return true;
|
|
6796
|
-
const changed = this.agentConfig.maxToolRounds !== (options.maxToolRounds ||
|
|
7049
|
+
const changed = this.agentConfig.maxToolRounds !== (options.maxToolRounds || DEFAULT_MAX_TOOL_ROUNDS);
|
|
6797
7050
|
if (changed) {
|
|
6798
7051
|
logger.debug("Agent config changed, will reinitialize", {
|
|
6799
7052
|
oldMaxToolRounds: this.agentConfig.maxToolRounds,
|
|
6800
|
-
newMaxToolRounds: options.maxToolRounds ||
|
|
7053
|
+
newMaxToolRounds: options.maxToolRounds || DEFAULT_MAX_TOOL_ROUNDS,
|
|
6801
7054
|
note: "SDK credentials managed by ax-cli setup"
|
|
6802
7055
|
});
|
|
6803
7056
|
}
|
|
6804
7057
|
return changed;
|
|
6805
7058
|
}
|
|
7059
|
+
/**
|
|
7060
|
+
* Ensure agent is initialized exactly once even if execute() is called
|
|
7061
|
+
* concurrently. Reinitializes when config changes.
|
|
7062
|
+
*
|
|
7063
|
+
* BUG FIX: If config changes while initialization is in progress, we need to
|
|
7064
|
+
* wait for current init to complete, then reinitialize with new config.
|
|
7065
|
+
*/
|
|
7066
|
+
async ensureAgent(options) {
|
|
7067
|
+
if (this.agent && !this.hasConfigChanged(options)) {
|
|
7068
|
+
return;
|
|
7069
|
+
}
|
|
7070
|
+
if (this.initPromise) {
|
|
7071
|
+
await this.initPromise;
|
|
7072
|
+
if (this.agent && !this.hasConfigChanged(options)) {
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
7075
|
+
}
|
|
7076
|
+
this.initPromise = this.initializeAgent(options).finally(() => {
|
|
7077
|
+
this.initPromise = null;
|
|
7078
|
+
});
|
|
7079
|
+
await this.initPromise;
|
|
7080
|
+
}
|
|
6806
7081
|
/**
|
|
6807
7082
|
* Set up streaming event handlers (for initialization)
|
|
7083
|
+
*
|
|
7084
|
+
* BUG FIX: Remove existing listeners before adding new ones to prevent
|
|
7085
|
+
* listener accumulation when agent is reinitialized.
|
|
6808
7086
|
*/
|
|
6809
7087
|
setupEventHandlers() {
|
|
6810
7088
|
if (!this.agent) return;
|
|
6811
7089
|
try {
|
|
7090
|
+
this.agent.removeAllListeners("stream");
|
|
7091
|
+
this.agent.removeAllListeners("tool");
|
|
7092
|
+
this.agent.removeAllListeners("error");
|
|
6812
7093
|
this.agent.on("stream", (chunk) => {
|
|
6813
7094
|
logger.debug("Stream chunk received", {
|
|
6814
7095
|
type: chunk.type,
|
|
@@ -6831,50 +7112,6 @@ var init_adapter2 = __esm({
|
|
|
6831
7112
|
});
|
|
6832
7113
|
}
|
|
6833
7114
|
}
|
|
6834
|
-
/**
|
|
6835
|
-
* Set up streaming callbacks for execution
|
|
6836
|
-
*/
|
|
6837
|
-
setupStreamingCallbacks(options) {
|
|
6838
|
-
if (!this.agent) return;
|
|
6839
|
-
try {
|
|
6840
|
-
this.agent.removeAllListeners("stream");
|
|
6841
|
-
this.agent.removeAllListeners("tool");
|
|
6842
|
-
if (options.onStream) {
|
|
6843
|
-
this.agent.on("stream", (chunk) => {
|
|
6844
|
-
try {
|
|
6845
|
-
options.onStream({
|
|
6846
|
-
type: chunk.type || "content",
|
|
6847
|
-
content: chunk.content,
|
|
6848
|
-
tool: chunk.tool,
|
|
6849
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6850
|
-
});
|
|
6851
|
-
} catch (error) {
|
|
6852
|
-
logger.warn("Stream callback error", {
|
|
6853
|
-
error: error instanceof Error ? error.message : String(error)
|
|
6854
|
-
});
|
|
6855
|
-
}
|
|
6856
|
-
});
|
|
6857
|
-
}
|
|
6858
|
-
if (options.onTool) {
|
|
6859
|
-
this.agent.on("tool", (data) => {
|
|
6860
|
-
try {
|
|
6861
|
-
options.onTool({
|
|
6862
|
-
name: data.name,
|
|
6863
|
-
args: data.args
|
|
6864
|
-
});
|
|
6865
|
-
} catch (error) {
|
|
6866
|
-
logger.warn("Tool callback error", {
|
|
6867
|
-
error: error instanceof Error ? error.message : String(error)
|
|
6868
|
-
});
|
|
6869
|
-
}
|
|
6870
|
-
});
|
|
6871
|
-
}
|
|
6872
|
-
} catch (error) {
|
|
6873
|
-
logger.warn("Failed to setup streaming callbacks", {
|
|
6874
|
-
error: error instanceof Error ? error.message : String(error)
|
|
6875
|
-
});
|
|
6876
|
-
}
|
|
6877
|
-
}
|
|
6878
7115
|
/**
|
|
6879
7116
|
* Extract token usage from various sources with priority:
|
|
6880
7117
|
* 1. SDK events (token_count emissions) - most accurate
|
|
@@ -6898,9 +7135,9 @@ var init_adapter2 = __esm({
|
|
|
6898
7135
|
}
|
|
6899
7136
|
const usage = usageObject || {};
|
|
6900
7137
|
const actualTokens = {
|
|
6901
|
-
prompt: usage.prompt_tokens
|
|
6902
|
-
completion: usage.completion_tokens
|
|
6903
|
-
total: usage.total_tokens
|
|
7138
|
+
prompt: usage.prompt_tokens ?? usage.prompt ?? usage.input ?? usage.promptTokens ?? 0,
|
|
7139
|
+
completion: usage.completion_tokens ?? usage.completion ?? usage.output ?? usage.completionTokens ?? 0,
|
|
7140
|
+
total: usage.total_tokens ?? usage.total ?? usage.totalTokens ?? 0
|
|
6904
7141
|
};
|
|
6905
7142
|
if (actualTokens.total > 0) {
|
|
6906
7143
|
logger.info(`Using token counts from ${sourceName || "usage object"}`, {
|
|
@@ -7058,21 +7295,7 @@ var init_adapter2 = __esm({
|
|
|
7058
7295
|
* Cleanup resources
|
|
7059
7296
|
*/
|
|
7060
7297
|
async destroy() {
|
|
7061
|
-
|
|
7062
|
-
try {
|
|
7063
|
-
const result = this.agent.dispose();
|
|
7064
|
-
if (result instanceof Promise) {
|
|
7065
|
-
await result;
|
|
7066
|
-
}
|
|
7067
|
-
this.agent = null;
|
|
7068
|
-
this.agentConfig = null;
|
|
7069
|
-
logger.debug("SDK agent destroyed");
|
|
7070
|
-
} catch (error) {
|
|
7071
|
-
logger.warn("Error during agent cleanup", {
|
|
7072
|
-
error: error instanceof Error ? error.message : String(error)
|
|
7073
|
-
});
|
|
7074
|
-
}
|
|
7075
|
-
}
|
|
7298
|
+
await this.destroyAgentInstance();
|
|
7076
7299
|
if (this.subagentAdapter) {
|
|
7077
7300
|
try {
|
|
7078
7301
|
await this.subagentAdapter.destroy();
|
|
@@ -7110,8 +7333,41 @@ var init_adapter2 = __esm({
|
|
|
7110
7333
|
}
|
|
7111
7334
|
}
|
|
7112
7335
|
if (this.mcpManager) {
|
|
7113
|
-
|
|
7114
|
-
|
|
7336
|
+
try {
|
|
7337
|
+
const shutdownResult = await this.mcpManager.shutdown();
|
|
7338
|
+
if (!shutdownResult.ok) {
|
|
7339
|
+
logger.warn("Error while shutting down MCP servers", {
|
|
7340
|
+
error: shutdownResult.error instanceof Error ? shutdownResult.error.message : String(shutdownResult.error)
|
|
7341
|
+
});
|
|
7342
|
+
}
|
|
7343
|
+
} catch (error) {
|
|
7344
|
+
logger.warn("Error during MCP Manager cleanup", {
|
|
7345
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7346
|
+
});
|
|
7347
|
+
} finally {
|
|
7348
|
+
this.mcpManager = null;
|
|
7349
|
+
logger.debug("MCP Manager cleared");
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
}
|
|
7353
|
+
/**
|
|
7354
|
+
* Dispose the primary agent without touching ancillary adapters.
|
|
7355
|
+
*/
|
|
7356
|
+
async destroyAgentInstance() {
|
|
7357
|
+
if (!this.agent) return;
|
|
7358
|
+
try {
|
|
7359
|
+
const result = this.agent.dispose();
|
|
7360
|
+
if (result instanceof Promise) {
|
|
7361
|
+
await result;
|
|
7362
|
+
}
|
|
7363
|
+
} catch (error) {
|
|
7364
|
+
logger.warn("Error during agent cleanup", {
|
|
7365
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7366
|
+
});
|
|
7367
|
+
} finally {
|
|
7368
|
+
this.agent = null;
|
|
7369
|
+
this.agentConfig = null;
|
|
7370
|
+
logger.debug("SDK agent destroyed");
|
|
7115
7371
|
}
|
|
7116
7372
|
}
|
|
7117
7373
|
};
|
|
@@ -7158,10 +7414,13 @@ var init_hybrid_adapter2 = __esm({
|
|
|
7158
7414
|
}
|
|
7159
7415
|
throw new Error(`No adapter available for mode: ${this.mode}`);
|
|
7160
7416
|
} catch (error) {
|
|
7161
|
-
if (this.mode === "auto" && this.activeMode === "sdk"
|
|
7417
|
+
if (this.mode === "auto" && this.activeMode === "sdk") {
|
|
7162
7418
|
logger.warn("SDK execution failed, falling back to CLI", {
|
|
7163
7419
|
error: error instanceof Error ? error.message : String(error)
|
|
7164
7420
|
});
|
|
7421
|
+
if (!this.cliAdapter) {
|
|
7422
|
+
this.initializeCli();
|
|
7423
|
+
}
|
|
7165
7424
|
this.activeMode = "cli";
|
|
7166
7425
|
return await this.executeCli(prompt, options);
|
|
7167
7426
|
}
|
|
@@ -7303,6 +7562,9 @@ var init_hybrid_adapter2 = __esm({
|
|
|
7303
7562
|
}
|
|
7304
7563
|
/**
|
|
7305
7564
|
* Get command name
|
|
7565
|
+
*
|
|
7566
|
+
* BUG FIX: Handle 'auto' mode correctly - return 'ax-cli-auto' to indicate
|
|
7567
|
+
* the actual command hasn't been determined yet (will be sdk or cli after initialization)
|
|
7306
7568
|
*/
|
|
7307
7569
|
getCommand() {
|
|
7308
7570
|
if (this.activeMode === "sdk") {
|
|
@@ -7310,7 +7572,13 @@ var init_hybrid_adapter2 = __esm({
|
|
|
7310
7572
|
} else if (this.activeMode === "cli") {
|
|
7311
7573
|
return "ax-cli";
|
|
7312
7574
|
}
|
|
7313
|
-
|
|
7575
|
+
if (this.mode === "sdk") {
|
|
7576
|
+
return "ax-cli-sdk";
|
|
7577
|
+
} else if (this.mode === "cli") {
|
|
7578
|
+
return "ax-cli";
|
|
7579
|
+
} else {
|
|
7580
|
+
return "ax-cli-auto";
|
|
7581
|
+
}
|
|
7314
7582
|
}
|
|
7315
7583
|
/**
|
|
7316
7584
|
* Get display name
|
|
@@ -7331,9 +7599,22 @@ var init_hybrid_adapter2 = __esm({
|
|
|
7331
7599
|
}
|
|
7332
7600
|
/**
|
|
7333
7601
|
* Force switch to CLI mode (for debugging or fallback)
|
|
7602
|
+
*
|
|
7603
|
+
* BUG FIX: Destroy SDK adapter when switching to CLI to prevent resource leaks
|
|
7604
|
+
* (memory, event listeners) from the unused SDK adapter.
|
|
7334
7605
|
*/
|
|
7335
|
-
switchToCliMode() {
|
|
7606
|
+
async switchToCliMode() {
|
|
7336
7607
|
logger.info("Forcing switch to CLI mode");
|
|
7608
|
+
if (this.sdkAdapter) {
|
|
7609
|
+
try {
|
|
7610
|
+
await this.sdkAdapter.destroy();
|
|
7611
|
+
} catch (error) {
|
|
7612
|
+
logger.warn("Error destroying SDK adapter during mode switch", {
|
|
7613
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7614
|
+
});
|
|
7615
|
+
}
|
|
7616
|
+
this.sdkAdapter = null;
|
|
7617
|
+
}
|
|
7337
7618
|
this.initializeCli();
|
|
7338
7619
|
this.activeMode = "cli";
|
|
7339
7620
|
}
|
|
@@ -7353,13 +7634,22 @@ var init_hybrid_adapter2 = __esm({
|
|
|
7353
7634
|
}
|
|
7354
7635
|
/**
|
|
7355
7636
|
* Cleanup resources
|
|
7637
|
+
* BUG FIX: Use Promise.allSettled to ensure cleanup completes even if SDK destroy fails
|
|
7356
7638
|
*/
|
|
7357
7639
|
async destroy() {
|
|
7358
7640
|
const destroyPromises = [];
|
|
7359
7641
|
if (this.sdkAdapter) {
|
|
7360
7642
|
destroyPromises.push(this.sdkAdapter.destroy());
|
|
7361
7643
|
}
|
|
7362
|
-
await Promise.
|
|
7644
|
+
const results = await Promise.allSettled(destroyPromises);
|
|
7645
|
+
results.forEach((result, index) => {
|
|
7646
|
+
if (result.status === "rejected") {
|
|
7647
|
+
logger.warn("Adapter cleanup failed", {
|
|
7648
|
+
index,
|
|
7649
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
7650
|
+
});
|
|
7651
|
+
}
|
|
7652
|
+
});
|
|
7363
7653
|
this.sdkAdapter = null;
|
|
7364
7654
|
this.cliAdapter = null;
|
|
7365
7655
|
this.activeMode = null;
|
|
@@ -7375,7 +7665,7 @@ __export(ax_cli_provider_exports, {
|
|
|
7375
7665
|
AxCliProvider: () => AxCliProvider,
|
|
7376
7666
|
GlmProvider: () => GlmProvider
|
|
7377
7667
|
});
|
|
7378
|
-
var SDK_ADAPTER_UNAVAILABLE_ERROR, AxCliProvider, GlmProvider;
|
|
7668
|
+
var SDK_ADAPTER_UNAVAILABLE_ERROR, DEFAULT_MAX_TOOL_ROUNDS2, AxCliProvider, GlmProvider;
|
|
7379
7669
|
var init_ax_cli_provider = __esm({
|
|
7380
7670
|
"src/providers/ax-cli-provider.ts"() {
|
|
7381
7671
|
init_esm_shims();
|
|
@@ -7383,6 +7673,7 @@ var init_ax_cli_provider = __esm({
|
|
|
7383
7673
|
init_hybrid_adapter2();
|
|
7384
7674
|
init_logger();
|
|
7385
7675
|
SDK_ADAPTER_UNAVAILABLE_ERROR = 'SDK adapter not available. Ensure mode="sdk" or "auto" with SDK installed.';
|
|
7676
|
+
DEFAULT_MAX_TOOL_ROUNDS2 = 400;
|
|
7386
7677
|
AxCliProvider = class extends BaseProvider {
|
|
7387
7678
|
adapter;
|
|
7388
7679
|
config;
|
|
@@ -7413,7 +7704,7 @@ var init_ax_cli_provider = __esm({
|
|
|
7413
7704
|
const options = {
|
|
7414
7705
|
model: request.model || axCliConfig.model,
|
|
7415
7706
|
// Optional model override
|
|
7416
|
-
maxToolRounds: axCliConfig.maxToolRounds ||
|
|
7707
|
+
maxToolRounds: axCliConfig.maxToolRounds || DEFAULT_MAX_TOOL_ROUNDS2,
|
|
7417
7708
|
timeout: this.config.timeout,
|
|
7418
7709
|
// Note: apiKey and baseUrl are ignored by SDK adapter (v3.7.0+)
|
|
7419
7710
|
// SDK loads credentials from ax-cli setup (~/.ax-cli/config.json)
|
|
@@ -7499,9 +7790,11 @@ var init_ax_cli_provider = __esm({
|
|
|
7499
7790
|
}
|
|
7500
7791
|
/**
|
|
7501
7792
|
* Force switch to CLI mode (for debugging or fallback)
|
|
7793
|
+
*
|
|
7794
|
+
* This method is async because it needs to clean up SDK adapter resources.
|
|
7502
7795
|
*/
|
|
7503
|
-
switchToCliMode() {
|
|
7504
|
-
this.adapter.switchToCliMode();
|
|
7796
|
+
async switchToCliMode() {
|
|
7797
|
+
await this.adapter.switchToCliMode();
|
|
7505
7798
|
}
|
|
7506
7799
|
// ==========================================
|
|
7507
7800
|
// SDK Advanced Features (v10.4.0)
|
|
@@ -7520,7 +7813,7 @@ var init_ax_cli_provider = __esm({
|
|
|
7520
7813
|
* ]);
|
|
7521
7814
|
* ```
|
|
7522
7815
|
*/
|
|
7523
|
-
async executeParallelTasks(tasks
|
|
7816
|
+
async executeParallelTasks(tasks) {
|
|
7524
7817
|
const sdkAdapter = this.adapter.getSdkAdapter();
|
|
7525
7818
|
if (!sdkAdapter) {
|
|
7526
7819
|
throw new Error(SDK_ADAPTER_UNAVAILABLE_ERROR);
|
|
@@ -8626,11 +8919,11 @@ var VALIDATION_LIMITS = {
|
|
|
8626
8919
|
MAX_PORT: 65535
|
|
8627
8920
|
// Maximum port number
|
|
8628
8921
|
};
|
|
8629
|
-
function isValidRelativePath(
|
|
8630
|
-
if (!
|
|
8922
|
+
function isValidRelativePath(path8) {
|
|
8923
|
+
if (!path8 || typeof path8 !== "string") {
|
|
8631
8924
|
return false;
|
|
8632
8925
|
}
|
|
8633
|
-
const normalizedPath =
|
|
8926
|
+
const normalizedPath = path8.replace(/\\/g, "/");
|
|
8634
8927
|
if (normalizedPath.startsWith("/")) {
|
|
8635
8928
|
return false;
|
|
8636
8929
|
}
|
|
@@ -9260,11 +9553,16 @@ var PRECOMPILED_CONFIG = {
|
|
|
9260
9553
|
},
|
|
9261
9554
|
"advanced": {
|
|
9262
9555
|
"embedding": {
|
|
9556
|
+
"model": "text-embedding-3-small",
|
|
9263
9557
|
"timeout": 3e4,
|
|
9264
9558
|
"retryDelay": 1e3,
|
|
9265
9559
|
"dimensions": 1536,
|
|
9266
9560
|
"maxRetries": 3
|
|
9267
9561
|
},
|
|
9562
|
+
"projectContext": {
|
|
9563
|
+
"maxSizeBytes": 102400,
|
|
9564
|
+
"cacheTtlMs": 3e5
|
|
9565
|
+
},
|
|
9268
9566
|
"security": {
|
|
9269
9567
|
"enablePathValidation": true,
|
|
9270
9568
|
"allowedExtensions": [
|
|
@@ -9320,7 +9618,23 @@ var PRECOMPILED_CONFIG = {
|
|
|
9320
9618
|
"enableFreeTierPrioritization": true,
|
|
9321
9619
|
"enableWorkloadAwareRouting": true
|
|
9322
9620
|
},
|
|
9323
|
-
"
|
|
9621
|
+
"axCliSdk": {
|
|
9622
|
+
"maxToolRounds": 400,
|
|
9623
|
+
"checkpoint": {
|
|
9624
|
+
"maxCheckpoints": 10,
|
|
9625
|
+
"flushTimeoutMs": 5e3
|
|
9626
|
+
},
|
|
9627
|
+
"subagent": {
|
|
9628
|
+
"maxParallel": 4,
|
|
9629
|
+
"timeoutMs": 3e5,
|
|
9630
|
+
"maxToolRounds": 100
|
|
9631
|
+
},
|
|
9632
|
+
"instructions": {
|
|
9633
|
+
"cacheTtlMs": 3e5,
|
|
9634
|
+
"maxContextLength": 32e3
|
|
9635
|
+
}
|
|
9636
|
+
},
|
|
9637
|
+
"version": "11.3.2"
|
|
9324
9638
|
};
|
|
9325
9639
|
|
|
9326
9640
|
// src/core/config/schemas.ts
|
|
@@ -9347,7 +9661,7 @@ var safeNameSchema = z.string().min(1).max(VALIDATION_LIMITS.MAX_NAME_LENGTH).re
|
|
|
9347
9661
|
"Name must be alphanumeric with dash/underscore only"
|
|
9348
9662
|
).describe("Safe identifier name");
|
|
9349
9663
|
var relativePathSchema = z.string().min(1).refine(
|
|
9350
|
-
(
|
|
9664
|
+
(path8) => !path8.includes("..") && !path8.startsWith("/"),
|
|
9351
9665
|
"Path must be relative (no ../, no absolute paths)"
|
|
9352
9666
|
).describe("Relative path within project");
|
|
9353
9667
|
var fileExtensionSchema = z.string().regex(
|
|
@@ -9687,16 +10001,16 @@ async function loadConfigUncached(projectDir) {
|
|
|
9687
10001
|
});
|
|
9688
10002
|
return config;
|
|
9689
10003
|
}
|
|
9690
|
-
async function loadConfigFile(
|
|
10004
|
+
async function loadConfigFile(path8) {
|
|
9691
10005
|
try {
|
|
9692
|
-
const content = await readFile(
|
|
10006
|
+
const content = await readFile(path8, "utf-8");
|
|
9693
10007
|
if (content.length > VALIDATION_LIMITS.MAX_CONFIG_FILE_SIZE) {
|
|
9694
10008
|
throw ConfigError.parseError(
|
|
9695
10009
|
new Error(`Config file too large (max ${VALIDATION_LIMITS.MAX_CONFIG_FILE_SIZE / 1024}KB, got ${Math.ceil(content.length / 1024)}KB)`),
|
|
9696
|
-
|
|
10010
|
+
path8
|
|
9697
10011
|
);
|
|
9698
10012
|
}
|
|
9699
|
-
const ext = extname(
|
|
10013
|
+
const ext = extname(path8).toLowerCase();
|
|
9700
10014
|
let userConfig;
|
|
9701
10015
|
try {
|
|
9702
10016
|
if (ext === ".yaml" || ext === ".yml") {
|
|
@@ -9705,7 +10019,7 @@ async function loadConfigFile(path7) {
|
|
|
9705
10019
|
userConfig = JSON.parse(content);
|
|
9706
10020
|
}
|
|
9707
10021
|
} catch (parseError) {
|
|
9708
|
-
throw ConfigError.parseError(parseError,
|
|
10022
|
+
throw ConfigError.parseError(parseError, path8);
|
|
9709
10023
|
}
|
|
9710
10024
|
const config = mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
9711
10025
|
if (config.execution && userConfig.execution?.maxConcurrentAgents === void 0) {
|
|
@@ -9721,35 +10035,35 @@ async function loadConfigFile(path7) {
|
|
|
9721
10035
|
if (validationErrors.length > 0) {
|
|
9722
10036
|
throw ConfigError.invalid(
|
|
9723
10037
|
validationErrors.join("; "),
|
|
9724
|
-
{ path:
|
|
10038
|
+
{ path: path8, errors: validationErrors }
|
|
9725
10039
|
);
|
|
9726
10040
|
}
|
|
9727
|
-
logger.info("Config loaded successfully", { path: normalizePath(
|
|
10041
|
+
logger.info("Config loaded successfully", { path: normalizePath(path8), format: ext });
|
|
9728
10042
|
return config;
|
|
9729
10043
|
} catch (error) {
|
|
9730
10044
|
if (error instanceof ConfigError) {
|
|
9731
10045
|
throw error;
|
|
9732
10046
|
}
|
|
9733
10047
|
if (error.code === "ENOENT") {
|
|
9734
|
-
throw ConfigError.notFound(
|
|
10048
|
+
throw ConfigError.notFound(path8);
|
|
9735
10049
|
}
|
|
9736
10050
|
if (error.code === "EACCES") {
|
|
9737
10051
|
throw new ConfigError(
|
|
9738
|
-
`Permission denied reading config: ${
|
|
10052
|
+
`Permission denied reading config: ${path8}`,
|
|
9739
10053
|
"E1002" /* CONFIG_PARSE_ERROR */,
|
|
9740
10054
|
[
|
|
9741
10055
|
"Check file permissions",
|
|
9742
10056
|
"Run with appropriate user privileges",
|
|
9743
10057
|
"Verify the file is accessible"
|
|
9744
10058
|
],
|
|
9745
|
-
{ path:
|
|
10059
|
+
{ path: path8, error: error.message }
|
|
9746
10060
|
);
|
|
9747
10061
|
}
|
|
9748
10062
|
throw new ConfigError(
|
|
9749
10063
|
`Failed to load config: ${error.message}`,
|
|
9750
10064
|
"E1002" /* CONFIG_PARSE_ERROR */,
|
|
9751
10065
|
["Check file format and permissions"],
|
|
9752
|
-
{ path:
|
|
10066
|
+
{ path: path8, originalError: error.message }
|
|
9753
10067
|
);
|
|
9754
10068
|
}
|
|
9755
10069
|
}
|
|
@@ -9765,8 +10079,8 @@ function validateConfigWithZod(config) {
|
|
|
9765
10079
|
return ["Configuration validation failed with unknown error structure"];
|
|
9766
10080
|
}
|
|
9767
10081
|
return result.error.issues.map((err) => {
|
|
9768
|
-
const
|
|
9769
|
-
return `${
|
|
10082
|
+
const path8 = err.path.join(".");
|
|
10083
|
+
return `${path8}: ${err.message}`;
|
|
9770
10084
|
});
|
|
9771
10085
|
}
|
|
9772
10086
|
function validateConfig(config) {
|
|
@@ -10152,16 +10466,16 @@ function validateConfig(config) {
|
|
|
10152
10466
|
}
|
|
10153
10467
|
return errors;
|
|
10154
10468
|
}
|
|
10155
|
-
async function saveConfigFile(
|
|
10469
|
+
async function saveConfigFile(path8, config) {
|
|
10156
10470
|
try {
|
|
10157
10471
|
const validationErrors = validateConfig(config);
|
|
10158
10472
|
if (validationErrors.length > 0) {
|
|
10159
10473
|
throw ConfigError.invalid(
|
|
10160
10474
|
validationErrors.join("; "),
|
|
10161
|
-
{ path:
|
|
10475
|
+
{ path: path8, errors: validationErrors }
|
|
10162
10476
|
);
|
|
10163
10477
|
}
|
|
10164
|
-
const ext = extname(
|
|
10478
|
+
const ext = extname(path8).toLowerCase();
|
|
10165
10479
|
let content;
|
|
10166
10480
|
if (ext === ".yaml" || ext === ".yml") {
|
|
10167
10481
|
content = dump(config, {
|
|
@@ -10173,30 +10487,30 @@ async function saveConfigFile(path7, config) {
|
|
|
10173
10487
|
} else {
|
|
10174
10488
|
content = JSON.stringify(config, null, 2);
|
|
10175
10489
|
}
|
|
10176
|
-
await writeFile(
|
|
10490
|
+
await writeFile(path8, content, "utf-8");
|
|
10177
10491
|
configCache.clear();
|
|
10178
|
-
logger.info("Config saved successfully", { path: normalizePath(
|
|
10492
|
+
logger.info("Config saved successfully", { path: normalizePath(path8), format: ext });
|
|
10179
10493
|
} catch (error) {
|
|
10180
10494
|
if (error instanceof ConfigError) {
|
|
10181
10495
|
throw error;
|
|
10182
10496
|
}
|
|
10183
10497
|
if (error.code === "EACCES") {
|
|
10184
10498
|
throw new ConfigError(
|
|
10185
|
-
`Permission denied writing config: ${
|
|
10499
|
+
`Permission denied writing config: ${path8}`,
|
|
10186
10500
|
"E1002" /* CONFIG_PARSE_ERROR */,
|
|
10187
10501
|
[
|
|
10188
10502
|
"Check file permissions",
|
|
10189
10503
|
"Run with appropriate user privileges",
|
|
10190
10504
|
"Verify the directory is writable"
|
|
10191
10505
|
],
|
|
10192
|
-
{ path:
|
|
10506
|
+
{ path: path8, error: error.message }
|
|
10193
10507
|
);
|
|
10194
10508
|
}
|
|
10195
10509
|
throw new ConfigError(
|
|
10196
10510
|
`Failed to save config: ${error.message}`,
|
|
10197
10511
|
"E1002" /* CONFIG_PARSE_ERROR */,
|
|
10198
10512
|
["Check file path and permissions"],
|
|
10199
|
-
{ path:
|
|
10513
|
+
{ path: path8, originalError: error.message }
|
|
10200
10514
|
);
|
|
10201
10515
|
}
|
|
10202
10516
|
}
|
|
@@ -10946,10 +11260,10 @@ var configCommand = {
|
|
|
10946
11260
|
} else {
|
|
10947
11261
|
const projectConfig = resolve(process.cwd(), "ax.config.json");
|
|
10948
11262
|
const hiddenConfig = resolve(process.cwd(), ".automatosx", "config.json");
|
|
10949
|
-
const
|
|
10950
|
-
if (
|
|
11263
|
+
const fs8 = await import('fs');
|
|
11264
|
+
if (fs8.existsSync(projectConfig)) {
|
|
10951
11265
|
configPath = projectConfig;
|
|
10952
|
-
} else if (
|
|
11266
|
+
} else if (fs8.existsSync(hiddenConfig)) {
|
|
10953
11267
|
configPath = hiddenConfig;
|
|
10954
11268
|
} else {
|
|
10955
11269
|
configPath = projectConfig;
|
|
@@ -10996,9 +11310,9 @@ var configCommand = {
|
|
|
10996
11310
|
}
|
|
10997
11311
|
}
|
|
10998
11312
|
};
|
|
10999
|
-
async function checkExists(
|
|
11313
|
+
async function checkExists(path8) {
|
|
11000
11314
|
try {
|
|
11001
|
-
await access$1(
|
|
11315
|
+
await access$1(path8, constants.F_OK);
|
|
11002
11316
|
return true;
|
|
11003
11317
|
} catch {
|
|
11004
11318
|
return false;
|
|
@@ -11029,7 +11343,7 @@ async function validateConfigFile(config, verbose) {
|
|
|
11029
11343
|
}
|
|
11030
11344
|
console.log();
|
|
11031
11345
|
}
|
|
11032
|
-
async function resetConfig(
|
|
11346
|
+
async function resetConfig(path8, verbose) {
|
|
11033
11347
|
const { createRequire } = await import('module');
|
|
11034
11348
|
const require2 = createRequire(import.meta.url);
|
|
11035
11349
|
let version = "11.2.6";
|
|
@@ -11044,14 +11358,14 @@ async function resetConfig(path7, verbose) {
|
|
|
11044
11358
|
// Users should rely on IDE JSON Schema plugins that fetch from npm package
|
|
11045
11359
|
version
|
|
11046
11360
|
};
|
|
11047
|
-
await saveConfigFile(
|
|
11361
|
+
await saveConfigFile(path8, config);
|
|
11048
11362
|
printSuccess("Configuration reset to defaults");
|
|
11049
11363
|
if (verbose) {
|
|
11050
11364
|
console.log(chalk5.gray(`
|
|
11051
|
-
Config file: ${
|
|
11365
|
+
Config file: ${path8}
|
|
11052
11366
|
`));
|
|
11053
11367
|
}
|
|
11054
|
-
logger.info("Configuration reset", { path:
|
|
11368
|
+
logger.info("Configuration reset", { path: path8 });
|
|
11055
11369
|
}
|
|
11056
11370
|
async function listConfig(config, verbose) {
|
|
11057
11371
|
console.log(chalk5.bold.cyan("\n\u{1F4CB} AutomatosX Configuration\n"));
|
|
@@ -11130,7 +11444,7 @@ async function getConfig(config, key, verbose) {
|
|
|
11130
11444
|
}
|
|
11131
11445
|
}
|
|
11132
11446
|
}
|
|
11133
|
-
async function setConfig(
|
|
11447
|
+
async function setConfig(path8, config, key, value, verbose) {
|
|
11134
11448
|
let parsedValue = value;
|
|
11135
11449
|
try {
|
|
11136
11450
|
parsedValue = JSON.parse(value);
|
|
@@ -11149,21 +11463,21 @@ async function setConfig(path7, config, key, value, verbose) {
|
|
|
11149
11463
|
console.log();
|
|
11150
11464
|
process.exit(1);
|
|
11151
11465
|
}
|
|
11152
|
-
await saveConfigFile(
|
|
11466
|
+
await saveConfigFile(path8, config);
|
|
11153
11467
|
printSuccess(`Configuration updated: ${key} = ${value}`);
|
|
11154
11468
|
if (verbose) {
|
|
11155
11469
|
console.log(chalk5.gray(`
|
|
11156
|
-
Config file: ${
|
|
11470
|
+
Config file: ${path8}`));
|
|
11157
11471
|
console.log(chalk5.gray("Configuration validated successfully\n"));
|
|
11158
11472
|
}
|
|
11159
11473
|
logger.info("Configuration updated", { key, value });
|
|
11160
11474
|
}
|
|
11161
|
-
function getNestedValue(obj,
|
|
11162
|
-
if (!
|
|
11163
|
-
return
|
|
11475
|
+
function getNestedValue(obj, path8) {
|
|
11476
|
+
if (!path8 || !path8.trim()) return void 0;
|
|
11477
|
+
return path8.split(".").filter(Boolean).reduce((current, key) => current?.[key], obj);
|
|
11164
11478
|
}
|
|
11165
|
-
function setNestedValue(obj,
|
|
11166
|
-
const keys =
|
|
11479
|
+
function setNestedValue(obj, path8, value) {
|
|
11480
|
+
const keys = path8.split(".");
|
|
11167
11481
|
const lastKey = keys.pop();
|
|
11168
11482
|
if (!lastKey) return false;
|
|
11169
11483
|
const target = keys.reduce((current, key) => {
|
|
@@ -13263,7 +13577,7 @@ var setupCommand = {
|
|
|
13263
13577
|
let version = "11.2.6";
|
|
13264
13578
|
try {
|
|
13265
13579
|
const packageJson = JSON.parse(
|
|
13266
|
-
await import('fs/promises').then((
|
|
13580
|
+
await import('fs/promises').then((fs8) => fs8.readFile(join(packageRoot, "package.json"), "utf-8"))
|
|
13267
13581
|
);
|
|
13268
13582
|
version = packageJson.version;
|
|
13269
13583
|
} catch {
|
|
@@ -13583,9 +13897,9 @@ var setupCommand = {
|
|
|
13583
13897
|
}
|
|
13584
13898
|
}
|
|
13585
13899
|
};
|
|
13586
|
-
async function checkExists2(
|
|
13900
|
+
async function checkExists2(path8) {
|
|
13587
13901
|
try {
|
|
13588
|
-
await access$1(
|
|
13902
|
+
await access$1(path8, constants.F_OK);
|
|
13589
13903
|
return true;
|
|
13590
13904
|
} catch {
|
|
13591
13905
|
return false;
|
|
@@ -14932,11 +15246,11 @@ async function detectExpressRoutes(projectDir) {
|
|
|
14932
15246
|
while ((match = routeRegex.exec(content)) !== null) {
|
|
14933
15247
|
if (match[1] && match[2]) {
|
|
14934
15248
|
const method = match[1].toUpperCase();
|
|
14935
|
-
const
|
|
15249
|
+
const path8 = match[2];
|
|
14936
15250
|
endpoints.push({
|
|
14937
15251
|
method,
|
|
14938
|
-
path:
|
|
14939
|
-
group:
|
|
15252
|
+
path: path8,
|
|
15253
|
+
group: path8.split("/")[1] || "api"
|
|
14940
15254
|
});
|
|
14941
15255
|
}
|
|
14942
15256
|
}
|
|
@@ -17930,18 +18244,18 @@ var ProviderSessionManager = class {
|
|
|
17930
18244
|
};
|
|
17931
18245
|
var providerSessionInstances = /* @__PURE__ */ new Map();
|
|
17932
18246
|
async function getProviderSession(workspacePath) {
|
|
17933
|
-
let
|
|
18247
|
+
let path8;
|
|
17934
18248
|
{
|
|
17935
18249
|
if (process.env.NODE_ENV === "test" || process.env.VITEST) {
|
|
17936
|
-
|
|
18250
|
+
path8 = process.cwd();
|
|
17937
18251
|
} else {
|
|
17938
|
-
|
|
18252
|
+
path8 = await detectProjectRoot();
|
|
17939
18253
|
}
|
|
17940
18254
|
}
|
|
17941
|
-
if (!providerSessionInstances.has(
|
|
17942
|
-
providerSessionInstances.set(
|
|
18255
|
+
if (!providerSessionInstances.has(path8)) {
|
|
18256
|
+
providerSessionInstances.set(path8, new ProviderSessionManager(path8));
|
|
17943
18257
|
}
|
|
17944
|
-
return providerSessionInstances.get(
|
|
18258
|
+
return providerSessionInstances.get(path8);
|
|
17945
18259
|
}
|
|
17946
18260
|
|
|
17947
18261
|
// src/core/router/router.ts
|
|
@@ -19711,6 +20025,9 @@ var MemoryManager = class _MemoryManager {
|
|
|
19711
20025
|
if (!Number.isInteger(offsetValue) || offsetValue < 0) {
|
|
19712
20026
|
throw new Error(`Invalid offset value: ${options.offset}. Must be a non-negative integer.`);
|
|
19713
20027
|
}
|
|
20028
|
+
if (!limitClause) {
|
|
20029
|
+
limitClause = "LIMIT -1";
|
|
20030
|
+
}
|
|
19714
20031
|
offsetClause = `OFFSET ${offsetValue}`;
|
|
19715
20032
|
}
|
|
19716
20033
|
const sql = `
|
|
@@ -20056,14 +20373,21 @@ var MemoryManager = class _MemoryManager {
|
|
|
20056
20373
|
this.initialized = false;
|
|
20057
20374
|
this.entryCount = 0;
|
|
20058
20375
|
this.statements = {};
|
|
20059
|
-
const { rename:
|
|
20060
|
-
await
|
|
20376
|
+
const { rename: rename5 } = await import('fs/promises');
|
|
20377
|
+
await rename5(tempPath, this.config.dbPath);
|
|
20061
20378
|
this.db = new Database2(this.config.dbPath);
|
|
20062
20379
|
this.db.pragma("journal_mode = WAL");
|
|
20063
20380
|
this.db.pragma(`busy_timeout = ${this.config.busyTimeout}`);
|
|
20064
20381
|
await this.initialize();
|
|
20065
20382
|
logger.info("Database restored successfully (atomic operation)", { srcPath: normalizePath(srcPath) });
|
|
20066
20383
|
} catch (error) {
|
|
20384
|
+
try {
|
|
20385
|
+
DatabaseFactory.close(this.db);
|
|
20386
|
+
} finally {
|
|
20387
|
+
this.initialized = false;
|
|
20388
|
+
this.entryCount = 0;
|
|
20389
|
+
this.statements = {};
|
|
20390
|
+
}
|
|
20067
20391
|
throw new MemoryError(
|
|
20068
20392
|
`Failed to restore database: ${error.message}`,
|
|
20069
20393
|
"DATABASE_ERROR",
|
|
@@ -20614,6 +20938,10 @@ var SessionManager = class _SessionManager {
|
|
|
20614
20938
|
MAX_TASKS_PER_SESSION = 1e3;
|
|
20615
20939
|
/** UUID v4 validation regex (static for performance) */
|
|
20616
20940
|
static UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
20941
|
+
/** Tracks whether manager has been destroyed to prevent late saves */
|
|
20942
|
+
destroyed = false;
|
|
20943
|
+
/** Last persistence error (reported during flush) */
|
|
20944
|
+
lastSaveError;
|
|
20617
20945
|
/**
|
|
20618
20946
|
* Validate session ID format (must be valid UUID v4)
|
|
20619
20947
|
*
|
|
@@ -21208,6 +21536,7 @@ var SessionManager = class _SessionManager {
|
|
|
21208
21536
|
* ```
|
|
21209
21537
|
*/
|
|
21210
21538
|
async destroy() {
|
|
21539
|
+
this.destroyed = true;
|
|
21211
21540
|
if (this.saveTimeout) {
|
|
21212
21541
|
clearTimeout(this.saveTimeout);
|
|
21213
21542
|
this.saveTimeout = void 0;
|
|
@@ -21218,9 +21547,12 @@ var SessionManager = class _SessionManager {
|
|
|
21218
21547
|
logger.error("Error flushing save during destroy", {
|
|
21219
21548
|
error: error.message
|
|
21220
21549
|
});
|
|
21550
|
+
this.lastSaveError = void 0;
|
|
21221
21551
|
}
|
|
21552
|
+
const sessionCount = this.activeSessions.size;
|
|
21553
|
+
this.activeSessions.clear();
|
|
21222
21554
|
logger.debug("SessionManager destroyed", {
|
|
21223
|
-
sessions:
|
|
21555
|
+
sessions: sessionCount
|
|
21224
21556
|
});
|
|
21225
21557
|
}
|
|
21226
21558
|
/**
|
|
@@ -21245,11 +21577,21 @@ var SessionManager = class _SessionManager {
|
|
|
21245
21577
|
this.pendingSave = void 0;
|
|
21246
21578
|
});
|
|
21247
21579
|
await this.pendingSave;
|
|
21580
|
+
if (this.lastSaveError) {
|
|
21581
|
+
const err = this.lastSaveError;
|
|
21582
|
+
this.lastSaveError = void 0;
|
|
21583
|
+
throw err;
|
|
21584
|
+
}
|
|
21248
21585
|
return;
|
|
21249
21586
|
}
|
|
21250
21587
|
if (this.pendingSave) {
|
|
21251
21588
|
try {
|
|
21252
21589
|
await this.pendingSave;
|
|
21590
|
+
if (this.lastSaveError) {
|
|
21591
|
+
const err = this.lastSaveError;
|
|
21592
|
+
this.lastSaveError = void 0;
|
|
21593
|
+
throw err;
|
|
21594
|
+
}
|
|
21253
21595
|
} catch (err) {
|
|
21254
21596
|
throw err;
|
|
21255
21597
|
}
|
|
@@ -21414,7 +21756,7 @@ var SessionManager = class _SessionManager {
|
|
|
21414
21756
|
* @private
|
|
21415
21757
|
*/
|
|
21416
21758
|
saveToFile() {
|
|
21417
|
-
if (!this.persistencePath) {
|
|
21759
|
+
if (!this.persistencePath || this.destroyed) {
|
|
21418
21760
|
return;
|
|
21419
21761
|
}
|
|
21420
21762
|
if (this.saveTimeout) {
|
|
@@ -21427,18 +21769,18 @@ var SessionManager = class _SessionManager {
|
|
|
21427
21769
|
}
|
|
21428
21770
|
this.saveNeeded = false;
|
|
21429
21771
|
const executeNextSave = async () => {
|
|
21430
|
-
|
|
21772
|
+
try {
|
|
21773
|
+
await this.doSave();
|
|
21774
|
+
this.lastSaveError = void 0;
|
|
21775
|
+
} catch (err) {
|
|
21776
|
+
this.lastSaveError = err;
|
|
21777
|
+
}
|
|
21431
21778
|
if (this.saveNeeded) {
|
|
21432
21779
|
this.saveNeeded = false;
|
|
21433
21780
|
return executeNextSave();
|
|
21434
21781
|
}
|
|
21435
21782
|
};
|
|
21436
|
-
this.pendingSave = executeNextSave().
|
|
21437
|
-
logger.error("Debounced save failed", {
|
|
21438
|
-
error: err.message
|
|
21439
|
-
});
|
|
21440
|
-
throw err;
|
|
21441
|
-
}).finally(() => {
|
|
21783
|
+
this.pendingSave = executeNextSave().finally(() => {
|
|
21442
21784
|
this.pendingSave = void 0;
|
|
21443
21785
|
});
|
|
21444
21786
|
}, 100);
|
|
@@ -23759,9 +24101,9 @@ var DependencyGraphBuilder = class {
|
|
|
23759
24101
|
detectCycles(graph) {
|
|
23760
24102
|
const visiting = /* @__PURE__ */ new Set();
|
|
23761
24103
|
const visited = /* @__PURE__ */ new Set();
|
|
23762
|
-
const visit = (nodeName,
|
|
24104
|
+
const visit = (nodeName, path8) => {
|
|
23763
24105
|
if (visiting.has(nodeName)) {
|
|
23764
|
-
throw new Error(`Circular dependency detected: ${[...
|
|
24106
|
+
throw new Error(`Circular dependency detected: ${[...path8, nodeName].join(" \u2192 ")}`);
|
|
23765
24107
|
}
|
|
23766
24108
|
if (visited.has(nodeName)) {
|
|
23767
24109
|
return;
|
|
@@ -23776,7 +24118,7 @@ var DependencyGraphBuilder = class {
|
|
|
23776
24118
|
}
|
|
23777
24119
|
visiting.add(nodeName);
|
|
23778
24120
|
for (const dependency of node.dependencies) {
|
|
23779
|
-
visit(dependency, [...
|
|
24121
|
+
visit(dependency, [...path8, nodeName]);
|
|
23780
24122
|
}
|
|
23781
24123
|
visiting.delete(nodeName);
|
|
23782
24124
|
visited.add(nodeName);
|
|
@@ -25509,59 +25851,59 @@ var DANGEROUS_PATH_PATTERNS = [
|
|
|
25509
25851
|
// Common data drive (Windows, alt format)
|
|
25510
25852
|
];
|
|
25511
25853
|
var SUSPICIOUS_PATH_CHARS = /[<>:|"]/;
|
|
25512
|
-
function validatePathParameter(
|
|
25513
|
-
if (!
|
|
25854
|
+
function validatePathParameter(path8, paramName, projectRoot = process.cwd()) {
|
|
25855
|
+
if (!path8 || path8.trim() === "") {
|
|
25514
25856
|
throw new ValidationError(
|
|
25515
25857
|
`Invalid ${paramName}: path cannot be empty`,
|
|
25516
25858
|
-32602 /* InvalidParams */,
|
|
25517
|
-
{ path:
|
|
25859
|
+
{ path: path8, paramName }
|
|
25518
25860
|
);
|
|
25519
25861
|
}
|
|
25520
25862
|
for (const pattern of DANGEROUS_PATH_PATTERNS) {
|
|
25521
|
-
if (
|
|
25863
|
+
if (path8.includes(pattern)) {
|
|
25522
25864
|
throw new ValidationError(
|
|
25523
25865
|
`Invalid ${paramName}: path contains dangerous pattern "${pattern}"`,
|
|
25524
25866
|
-32602 /* InvalidParams */,
|
|
25525
|
-
{ path:
|
|
25867
|
+
{ path: path8, paramName, pattern }
|
|
25526
25868
|
);
|
|
25527
25869
|
}
|
|
25528
25870
|
}
|
|
25529
|
-
if (isAbsolute(
|
|
25871
|
+
if (isAbsolute(path8)) {
|
|
25530
25872
|
throw new ValidationError(
|
|
25531
25873
|
`Invalid ${paramName}: absolute paths are not allowed`,
|
|
25532
25874
|
-32602 /* InvalidParams */,
|
|
25533
|
-
{ path:
|
|
25875
|
+
{ path: path8, paramName }
|
|
25534
25876
|
);
|
|
25535
25877
|
}
|
|
25536
25878
|
try {
|
|
25537
|
-
const resolvedPath = resolve(projectRoot,
|
|
25879
|
+
const resolvedPath = resolve(projectRoot, path8);
|
|
25538
25880
|
const normalizedRoot = resolve(projectRoot);
|
|
25539
25881
|
if (!resolvedPath.startsWith(normalizedRoot + sep) && resolvedPath !== normalizedRoot) {
|
|
25540
25882
|
throw new ValidationError(
|
|
25541
25883
|
`Invalid ${paramName}: path escapes project boundary`,
|
|
25542
25884
|
-32602 /* InvalidParams */,
|
|
25543
|
-
{ path:
|
|
25885
|
+
{ path: path8, paramName, projectRoot, resolvedPath }
|
|
25544
25886
|
);
|
|
25545
25887
|
}
|
|
25546
25888
|
} catch (error) {
|
|
25547
25889
|
throw new ValidationError(
|
|
25548
25890
|
`Invalid ${paramName}: path resolution failed`,
|
|
25549
25891
|
-32602 /* InvalidParams */,
|
|
25550
|
-
{ path:
|
|
25892
|
+
{ path: path8, paramName, error: String(error) }
|
|
25551
25893
|
);
|
|
25552
25894
|
}
|
|
25553
|
-
if (
|
|
25895
|
+
if (path8.includes("\0")) {
|
|
25554
25896
|
throw new ValidationError(
|
|
25555
25897
|
`Invalid ${paramName}: path contains null byte`,
|
|
25556
25898
|
-32602 /* InvalidParams */,
|
|
25557
|
-
{ path:
|
|
25899
|
+
{ path: path8, paramName }
|
|
25558
25900
|
);
|
|
25559
25901
|
}
|
|
25560
|
-
if (SUSPICIOUS_PATH_CHARS.test(
|
|
25902
|
+
if (SUSPICIOUS_PATH_CHARS.test(path8)) {
|
|
25561
25903
|
throw new ValidationError(
|
|
25562
25904
|
`Invalid ${paramName}: path contains invalid characters`,
|
|
25563
25905
|
-32602 /* InvalidParams */,
|
|
25564
|
-
{ path:
|
|
25906
|
+
{ path: path8, paramName }
|
|
25565
25907
|
);
|
|
25566
25908
|
}
|
|
25567
25909
|
}
|
|
@@ -26257,8 +26599,8 @@ function createMemoryExportHandler(deps) {
|
|
|
26257
26599
|
return async (input) => {
|
|
26258
26600
|
logger.info("[MCP] memory_export called", { input });
|
|
26259
26601
|
try {
|
|
26260
|
-
const { path:
|
|
26261
|
-
const absolutePath = resolveExportPath(deps.pathResolver,
|
|
26602
|
+
const { path: path8 } = input;
|
|
26603
|
+
const absolutePath = resolveExportPath(deps.pathResolver, path8);
|
|
26262
26604
|
const exported = await deps.memoryManager.exportToJSON(absolutePath);
|
|
26263
26605
|
const result = {
|
|
26264
26606
|
success: true,
|
|
@@ -26294,8 +26636,8 @@ function createMemoryImportHandler(deps) {
|
|
|
26294
26636
|
return async (input) => {
|
|
26295
26637
|
logger.info("[MCP] memory_import called", { input });
|
|
26296
26638
|
try {
|
|
26297
|
-
const { path:
|
|
26298
|
-
const absolutePath = resolveImportPath(deps.pathResolver,
|
|
26639
|
+
const { path: path8 } = input;
|
|
26640
|
+
const absolutePath = resolveImportPath(deps.pathResolver, path8);
|
|
26299
26641
|
const imported = await deps.memoryManager.importFromJSON(absolutePath);
|
|
26300
26642
|
const result = {
|
|
26301
26643
|
success: true,
|
|
@@ -26870,7 +27212,18 @@ var McpClient = class extends EventEmitter {
|
|
|
26870
27212
|
timeout: timeoutHandle
|
|
26871
27213
|
});
|
|
26872
27214
|
const message = JSON.stringify(request) + "\n";
|
|
26873
|
-
|
|
27215
|
+
try {
|
|
27216
|
+
this.process.stdin.write(message);
|
|
27217
|
+
} catch (error) {
|
|
27218
|
+
const pending = this.pendingRequests.get(id);
|
|
27219
|
+
if (pending) {
|
|
27220
|
+
clearTimeout(pending.timeout);
|
|
27221
|
+
this.pendingRequests.delete(id);
|
|
27222
|
+
}
|
|
27223
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
27224
|
+
reject(err);
|
|
27225
|
+
return;
|
|
27226
|
+
}
|
|
26874
27227
|
logger.debug("[MCP Client] Sent request", {
|
|
26875
27228
|
id,
|
|
26876
27229
|
method,
|
|
@@ -29618,8 +29971,8 @@ var LifecycleLogger = class {
|
|
|
29618
29971
|
if (sizeMB > this.maxLogSizeMB) {
|
|
29619
29972
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
29620
29973
|
const archivePath = logPath.replace(".jsonl", `-${timestamp}.jsonl`);
|
|
29621
|
-
const { rename:
|
|
29622
|
-
await
|
|
29974
|
+
const { rename: rename5 } = await import('fs/promises');
|
|
29975
|
+
await rename5(logPath, archivePath);
|
|
29623
29976
|
logger.info("LifecycleLogger: Rotated log file", {
|
|
29624
29977
|
oldPath: logPath,
|
|
29625
29978
|
newPath: archivePath,
|
|
@@ -31402,9 +31755,9 @@ var ProgressIndicator = class {
|
|
|
31402
31755
|
// src/cli/commands/memory.ts
|
|
31403
31756
|
var DEFAULT_DB_PATH = ".automatosx/memory/memory.db";
|
|
31404
31757
|
function getMemoryManager(dbPath) {
|
|
31405
|
-
const
|
|
31758
|
+
const path8 = dbPath || DEFAULT_DB_PATH;
|
|
31406
31759
|
return new LazyMemoryManager({
|
|
31407
|
-
dbPath: resolve(
|
|
31760
|
+
dbPath: resolve(path8),
|
|
31408
31761
|
maxEntries: 1e5,
|
|
31409
31762
|
autoCleanup: false,
|
|
31410
31763
|
trackAccess: true
|
|
@@ -34405,14 +34758,14 @@ var IterateClassifier = class {
|
|
|
34405
34758
|
* **Phase 1 (Week 1)**: Skeleton only (no-op)
|
|
34406
34759
|
* **Phase 2 (Week 2)**: Full implementation with YAML loading and validation
|
|
34407
34760
|
*/
|
|
34408
|
-
async loadPatterns(
|
|
34409
|
-
logger.debug("Loading pattern library", { path:
|
|
34410
|
-
if (!existsSync(
|
|
34411
|
-
logger.warn("Pattern library file not found", { path:
|
|
34761
|
+
async loadPatterns(path8) {
|
|
34762
|
+
logger.debug("Loading pattern library", { path: path8 });
|
|
34763
|
+
if (!existsSync(path8)) {
|
|
34764
|
+
logger.warn("Pattern library file not found", { path: path8 });
|
|
34412
34765
|
return;
|
|
34413
34766
|
}
|
|
34414
34767
|
try {
|
|
34415
|
-
const fileContent = await readFile(
|
|
34768
|
+
const fileContent = await readFile(path8, "utf-8");
|
|
34416
34769
|
const parsed = load(fileContent);
|
|
34417
34770
|
if (!parsed || typeof parsed !== "object") {
|
|
34418
34771
|
throw new Error("Invalid pattern library format: not an object");
|
|
@@ -34455,7 +34808,7 @@ var IterateClassifier = class {
|
|
|
34455
34808
|
});
|
|
34456
34809
|
} catch (error) {
|
|
34457
34810
|
logger.error("Failed to load pattern library", {
|
|
34458
|
-
path:
|
|
34811
|
+
path: path8,
|
|
34459
34812
|
error: error.message
|
|
34460
34813
|
});
|
|
34461
34814
|
throw error;
|
|
@@ -34809,14 +35162,14 @@ var IterateAutoResponder = class {
|
|
|
34809
35162
|
* **Phase 1 (Week 1)**: Skeleton only (no-op)
|
|
34810
35163
|
* **Phase 3 (Week 3)**: Full implementation with YAML loading and validation
|
|
34811
35164
|
*/
|
|
34812
|
-
async loadTemplates(
|
|
34813
|
-
logger.debug("Loading template library", { path:
|
|
34814
|
-
if (!existsSync(
|
|
34815
|
-
logger.warn("Template library file not found", { path:
|
|
35165
|
+
async loadTemplates(path8) {
|
|
35166
|
+
logger.debug("Loading template library", { path: path8 });
|
|
35167
|
+
if (!existsSync(path8)) {
|
|
35168
|
+
logger.warn("Template library file not found", { path: path8 });
|
|
34816
35169
|
return;
|
|
34817
35170
|
}
|
|
34818
35171
|
try {
|
|
34819
|
-
const fileContent = await readFile(
|
|
35172
|
+
const fileContent = await readFile(path8, "utf-8");
|
|
34820
35173
|
const parsed = load(fileContent);
|
|
34821
35174
|
if (!parsed || typeof parsed !== "object") {
|
|
34822
35175
|
throw new Error("Invalid template library format: not an object");
|
|
@@ -34858,7 +35211,7 @@ var IterateAutoResponder = class {
|
|
|
34858
35211
|
});
|
|
34859
35212
|
} catch (error) {
|
|
34860
35213
|
logger.error("Failed to load template library", {
|
|
34861
|
-
path:
|
|
35214
|
+
path: path8,
|
|
34862
35215
|
error: error.message
|
|
34863
35216
|
});
|
|
34864
35217
|
throw error;
|
|
@@ -38670,11 +39023,11 @@ async function getCurrentVersion() {
|
|
|
38670
39023
|
return result.dependencies["@defai.digital/automatosx"]?.version || "unknown";
|
|
38671
39024
|
} catch (error) {
|
|
38672
39025
|
const { readFile: readFile24 } = await import('fs/promises');
|
|
38673
|
-
const { dirname: dirname15, join:
|
|
39026
|
+
const { dirname: dirname15, join: join51 } = await import('path');
|
|
38674
39027
|
const { fileURLToPath: fileURLToPath5 } = await import('url');
|
|
38675
39028
|
const __filename3 = fileURLToPath5(import.meta.url);
|
|
38676
39029
|
const __dirname4 = dirname15(__filename3);
|
|
38677
|
-
const pkgPath =
|
|
39030
|
+
const pkgPath = join51(__dirname4, "../../../package.json");
|
|
38678
39031
|
const content = await readFile24(pkgPath, "utf-8");
|
|
38679
39032
|
const pkg = JSON.parse(content);
|
|
38680
39033
|
return pkg.version;
|
|
@@ -40744,8 +41097,8 @@ var ConfigManager = class {
|
|
|
40744
41097
|
* @returns User configuration or empty object if not found
|
|
40745
41098
|
*/
|
|
40746
41099
|
async readUserConfig() {
|
|
40747
|
-
const
|
|
40748
|
-
return this.readConfig(
|
|
41100
|
+
const path8 = getUserConfigPath();
|
|
41101
|
+
return this.readConfig(path8, "user");
|
|
40749
41102
|
}
|
|
40750
41103
|
/**
|
|
40751
41104
|
* Read project-level Gemini CLI configuration
|
|
@@ -40753,8 +41106,8 @@ var ConfigManager = class {
|
|
|
40753
41106
|
* @returns Project configuration or empty object if not found
|
|
40754
41107
|
*/
|
|
40755
41108
|
async readProjectConfig() {
|
|
40756
|
-
const
|
|
40757
|
-
return this.readConfig(
|
|
41109
|
+
const path8 = getProjectConfigPath();
|
|
41110
|
+
return this.readConfig(path8, "project");
|
|
40758
41111
|
}
|
|
40759
41112
|
/**
|
|
40760
41113
|
* Read configuration from a specific path with caching
|
|
@@ -40764,7 +41117,7 @@ var ConfigManager = class {
|
|
|
40764
41117
|
* @returns Configuration object
|
|
40765
41118
|
* @private
|
|
40766
41119
|
*/
|
|
40767
|
-
async readConfig(
|
|
41120
|
+
async readConfig(path8, scope) {
|
|
40768
41121
|
const cached = this.cache.get(scope);
|
|
40769
41122
|
if (cached && Date.now() - cached.timestamp < this.ttl) {
|
|
40770
41123
|
return cached.data;
|
|
@@ -40775,13 +41128,13 @@ var ConfigManager = class {
|
|
|
40775
41128
|
}
|
|
40776
41129
|
const readOperation = (async () => {
|
|
40777
41130
|
try {
|
|
40778
|
-
const exists = await fileExists(
|
|
41131
|
+
const exists = await fileExists(path8);
|
|
40779
41132
|
if (!exists) {
|
|
40780
41133
|
const emptyConfig = {};
|
|
40781
41134
|
this.cache.set(scope, { data: emptyConfig, timestamp: Date.now() });
|
|
40782
41135
|
return emptyConfig;
|
|
40783
41136
|
}
|
|
40784
|
-
const config = await readJsonFile(
|
|
41137
|
+
const config = await readJsonFile(path8);
|
|
40785
41138
|
this.cache.set(scope, { data: config, timestamp: Date.now() });
|
|
40786
41139
|
return config;
|
|
40787
41140
|
} catch (error) {
|
|
@@ -40790,8 +41143,8 @@ var ConfigManager = class {
|
|
|
40790
41143
|
}
|
|
40791
41144
|
throw new GeminiCLIError(
|
|
40792
41145
|
"INVALID_CONFIG" /* INVALID_CONFIG */,
|
|
40793
|
-
`Failed to read configuration from ${
|
|
40794
|
-
{ path:
|
|
41146
|
+
`Failed to read configuration from ${path8}`,
|
|
41147
|
+
{ path: path8, originalError: error }
|
|
40795
41148
|
);
|
|
40796
41149
|
} finally {
|
|
40797
41150
|
this.pendingReads.delete(scope);
|
|
@@ -41461,8 +41814,8 @@ var CommandTranslator = class {
|
|
|
41461
41814
|
paths.push(getProjectCommandsPath());
|
|
41462
41815
|
}
|
|
41463
41816
|
}
|
|
41464
|
-
for (const
|
|
41465
|
-
const discovered = await this.scanDirectory(
|
|
41817
|
+
for (const path8 of paths) {
|
|
41818
|
+
const discovered = await this.scanDirectory(path8);
|
|
41466
41819
|
commands.push(...discovered);
|
|
41467
41820
|
}
|
|
41468
41821
|
return commands;
|
|
@@ -41503,8 +41856,8 @@ var CommandTranslator = class {
|
|
|
41503
41856
|
const results = [];
|
|
41504
41857
|
for (const name of commandNames) {
|
|
41505
41858
|
try {
|
|
41506
|
-
const
|
|
41507
|
-
results.push(
|
|
41859
|
+
const path8 = await this.importCommand(name, outputDir, options);
|
|
41860
|
+
results.push(path8);
|
|
41508
41861
|
} catch (error) {
|
|
41509
41862
|
if (error instanceof GeminiCLIError) {
|
|
41510
41863
|
console.error(`Failed to import ${name}: ${error.message}`);
|
|
@@ -42836,7 +43189,7 @@ var SpecSchemaValidator = class {
|
|
|
42836
43189
|
* Convert Ajv error to ValidationIssue
|
|
42837
43190
|
*/
|
|
42838
43191
|
convertAjvError(error) {
|
|
42839
|
-
const
|
|
43192
|
+
const path8 = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
|
|
42840
43193
|
const keyword = error.keyword;
|
|
42841
43194
|
let message = error.message || "Validation error";
|
|
42842
43195
|
let suggestion;
|
|
@@ -42887,7 +43240,7 @@ var SpecSchemaValidator = class {
|
|
|
42887
43240
|
ruleId: `SCHEMA-${keyword.toUpperCase()}`,
|
|
42888
43241
|
severity: "error",
|
|
42889
43242
|
message,
|
|
42890
|
-
path:
|
|
43243
|
+
path: path8 || void 0,
|
|
42891
43244
|
suggestion
|
|
42892
43245
|
};
|
|
42893
43246
|
}
|
|
@@ -45707,8 +46060,8 @@ async function handleReset() {
|
|
|
45707
46060
|
}
|
|
45708
46061
|
async function handleTrace(workspacePath, argv) {
|
|
45709
46062
|
const { existsSync: existsSync26, readFileSync: readFileSync9, watchFile } = await import('fs');
|
|
45710
|
-
const { join:
|
|
45711
|
-
const traceFile =
|
|
46063
|
+
const { join: join51 } = await import('path');
|
|
46064
|
+
const traceFile = join51(workspacePath, ".automatosx/logs/router.trace.jsonl");
|
|
45712
46065
|
if (!existsSync26(traceFile)) {
|
|
45713
46066
|
console.log(chalk5.yellow("\n\u26A0\uFE0F No trace log found\n"));
|
|
45714
46067
|
console.log(chalk5.gray(`Expected location: ${traceFile}
|
|
@@ -48617,13 +48970,13 @@ Time since last change: ${timeSinceLastChange}ms`
|
|
|
48617
48970
|
init_logger();
|
|
48618
48971
|
var flagManagerInstances = /* @__PURE__ */ new Map();
|
|
48619
48972
|
function getFlagManager(workspacePath) {
|
|
48620
|
-
const
|
|
48621
|
-
if (!flagManagerInstances.has(
|
|
48622
|
-
const manager = new FeatureFlagManager(
|
|
48973
|
+
const path8 = process.cwd();
|
|
48974
|
+
if (!flagManagerInstances.has(path8)) {
|
|
48975
|
+
const manager = new FeatureFlagManager(path8);
|
|
48623
48976
|
initializeFlags(manager);
|
|
48624
|
-
flagManagerInstances.set(
|
|
48977
|
+
flagManagerInstances.set(path8, manager);
|
|
48625
48978
|
}
|
|
48626
|
-
return flagManagerInstances.get(
|
|
48979
|
+
return flagManagerInstances.get(path8);
|
|
48627
48980
|
}
|
|
48628
48981
|
function initializeFlags(manager) {
|
|
48629
48982
|
if (!manager.hasStorage()) {
|
|
@@ -48944,9 +49297,9 @@ var cliCommand = {
|
|
|
48944
49297
|
// src/cli/commands/uninstall.ts
|
|
48945
49298
|
init_esm_shims();
|
|
48946
49299
|
init_logger();
|
|
48947
|
-
async function fileExists2(
|
|
49300
|
+
async function fileExists2(path8) {
|
|
48948
49301
|
try {
|
|
48949
|
-
await access$1(
|
|
49302
|
+
await access$1(path8);
|
|
48950
49303
|
return true;
|
|
48951
49304
|
} catch {
|
|
48952
49305
|
return false;
|
|
@@ -49519,7 +49872,6 @@ var OrchestrationInstructionInjector = class {
|
|
|
49519
49872
|
providers = /* @__PURE__ */ new Map();
|
|
49520
49873
|
budgetManager;
|
|
49521
49874
|
config;
|
|
49522
|
-
lastInjectionTime = 0;
|
|
49523
49875
|
constructor(config) {
|
|
49524
49876
|
this.config = {
|
|
49525
49877
|
...DEFAULT_ORCHESTRATION_CONFIG,
|
|
@@ -49612,7 +49964,6 @@ var OrchestrationInstructionInjector = class {
|
|
|
49612
49964
|
allocation = this.budgetManager.allocateBudget(activeInstructions);
|
|
49613
49965
|
}
|
|
49614
49966
|
const formattedText = this.formatInstructions(allocation.included);
|
|
49615
|
-
this.lastInjectionTime = Date.now();
|
|
49616
49967
|
const duration = Date.now() - startTime;
|
|
49617
49968
|
logger.debug("Instruction injection complete", {
|
|
49618
49969
|
providers: this.providers.size,
|
|
@@ -50226,7 +50577,7 @@ var SessionInstructionProvider = class {
|
|
|
50226
50577
|
if (!this.config.enabled) {
|
|
50227
50578
|
return false;
|
|
50228
50579
|
}
|
|
50229
|
-
if (!context.sessionId && !this.stateProvider) {
|
|
50580
|
+
if (!context.sessionId && !this.stateProvider && !context.parentAgent) {
|
|
50230
50581
|
return false;
|
|
50231
50582
|
}
|
|
50232
50583
|
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
@@ -50238,7 +50589,7 @@ var SessionInstructionProvider = class {
|
|
|
50238
50589
|
async getInstructions(context) {
|
|
50239
50590
|
const instructions = [];
|
|
50240
50591
|
const state = await this.getSessionState(context);
|
|
50241
|
-
if (!state && !context.sessionId) {
|
|
50592
|
+
if (!state && !context.sessionId && !context.parentAgent) {
|
|
50242
50593
|
return instructions;
|
|
50243
50594
|
}
|
|
50244
50595
|
const content = this.formatSessionContext(context, state);
|
|
@@ -51190,7 +51541,6 @@ var AgentInstructionInjector = class {
|
|
|
51190
51541
|
var OrchestrationService = class {
|
|
51191
51542
|
config;
|
|
51192
51543
|
injector;
|
|
51193
|
-
tokenBudgetManager;
|
|
51194
51544
|
workflowModeManager;
|
|
51195
51545
|
agentInjector;
|
|
51196
51546
|
todoProvider;
|
|
@@ -51204,7 +51554,6 @@ var OrchestrationService = class {
|
|
|
51204
51554
|
...serviceConfig
|
|
51205
51555
|
};
|
|
51206
51556
|
this.injector = new OrchestrationInstructionInjector(this.config);
|
|
51207
|
-
this.tokenBudgetManager = new TokenBudgetManager(this.config.tokenBudget);
|
|
51208
51557
|
this.workflowModeManager = new WorkflowModeManager();
|
|
51209
51558
|
this.agentInjector = new AgentInstructionInjector({
|
|
51210
51559
|
enabled: this.config.agentTemplates?.enabled ?? true,
|
|
@@ -51381,7 +51730,7 @@ ${content}
|
|
|
51381
51730
|
* Get debug information about current orchestration state
|
|
51382
51731
|
*/
|
|
51383
51732
|
getDebugInfo() {
|
|
51384
|
-
const budgetConfig = this.
|
|
51733
|
+
const budgetConfig = this.injector.getBudgetManager().getConfig();
|
|
51385
51734
|
const providers = this.injector.getProviders().map((p) => p.name);
|
|
51386
51735
|
return {
|
|
51387
51736
|
turnCount: this.turnCount,
|
|
@@ -51429,9 +51778,6 @@ ${content}
|
|
|
51429
51778
|
sessionIntegration: updates.sessionIntegration ? { ...this.config.sessionIntegration, ...updates.sessionIntegration } : this.config.sessionIntegration,
|
|
51430
51779
|
agentTemplates: updates.agentTemplates ? { ...this.config.agentTemplates, ...updates.agentTemplates } : this.config.agentTemplates
|
|
51431
51780
|
};
|
|
51432
|
-
if (updates.tokenBudget) {
|
|
51433
|
-
this.tokenBudgetManager.updateConfig(this.config.tokenBudget);
|
|
51434
|
-
}
|
|
51435
51781
|
this.injector.updateConfig(updates);
|
|
51436
51782
|
if (updates.todoIntegration && this.todoProvider) {
|
|
51437
51783
|
const current = this.todoProvider.getConfig();
|