@defai.digital/automatosx 8.3.0 → 8.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/CHANGELOG.md +16 -0
- package/README.md +120 -2
- package/dist/index.js +1145 -333
- package/examples/grok/GROK_INTEGRATION.md +511 -0
- package/examples/grok/settings.json +43 -0
- package/examples/providers/README.md +228 -0
- package/examples/providers/grok-with-mcp.yaml +86 -0
- package/examples/providers/grok-x-ai.yaml +46 -0
- package/examples/providers/grok-z-ai.yaml +50 -0
- package/examples/providers/grok.yaml +120 -0
- package/package.json +4 -2
- package/templates/providers/README.md +117 -0
- package/templates/providers/grok-zai.yaml.template +61 -0
- package/templates/providers/grok.yaml.template +71 -0
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { realpathSync as realpathSync$1, access, realpath, existsSync, readFileS
|
|
|
8
8
|
import os2, { homedir, cpus } from 'os';
|
|
9
9
|
import { findUp } from 'find-up';
|
|
10
10
|
import { exec, spawn, execSync, spawnSync } from 'child_process';
|
|
11
|
+
import { z } from 'zod';
|
|
11
12
|
import { promisify } from 'util';
|
|
12
13
|
import yargs from 'yargs';
|
|
13
14
|
import { hideBin } from 'yargs/helpers';
|
|
@@ -1031,22 +1032,207 @@ var init_path_resolver = __esm({
|
|
|
1031
1032
|
};
|
|
1032
1033
|
}
|
|
1033
1034
|
});
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1035
|
+
function findOnPath(cmdBase) {
|
|
1036
|
+
const isWindows2 = process.platform === "win32";
|
|
1037
|
+
if (isWindows2) {
|
|
1038
|
+
return findOnPathWindows(cmdBase);
|
|
1039
|
+
}
|
|
1040
|
+
return findOnPathUnix(cmdBase);
|
|
1041
|
+
}
|
|
1042
|
+
function findOnPathWindows(cmdBase) {
|
|
1043
|
+
try {
|
|
1044
|
+
const where = spawnSync("where", [cmdBase], {
|
|
1045
|
+
windowsHide: true,
|
|
1046
|
+
timeout: 3e3
|
|
1047
|
+
});
|
|
1048
|
+
if (where.status === 0) {
|
|
1049
|
+
const lines = where.stdout.toString().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
1050
|
+
const firstPath = lines[0];
|
|
1051
|
+
if (firstPath) {
|
|
1052
|
+
logger.debug("Found via where.exe", { cmdBase, path: firstPath });
|
|
1053
|
+
return { found: true, path: firstPath };
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
logger.debug("where.exe failed, falling back to PATH scan", { error });
|
|
1058
|
+
}
|
|
1059
|
+
const pathext = (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").toUpperCase().split(";").filter(Boolean);
|
|
1060
|
+
const pathEntries = (process.env.PATH || "").split(delimiter).filter(Boolean);
|
|
1061
|
+
for (const dir of pathEntries) {
|
|
1062
|
+
for (const ext2 of pathext) {
|
|
1063
|
+
const fullPath = `${dir}\\${cmdBase}${ext2}`;
|
|
1064
|
+
if (existsSync(fullPath)) {
|
|
1065
|
+
logger.debug("Found via PATH \xD7 PATHEXT", { cmdBase, path: fullPath });
|
|
1066
|
+
return { found: true, path: fullPath };
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
const pathWithoutExt = `${dir}\\${cmdBase}`;
|
|
1070
|
+
if (existsSync(pathWithoutExt)) {
|
|
1071
|
+
logger.debug("Found via PATH (no ext)", { cmdBase, path: pathWithoutExt });
|
|
1072
|
+
return { found: true, path: pathWithoutExt };
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return { found: false };
|
|
1076
|
+
}
|
|
1077
|
+
function findOnPathUnix(cmdBase) {
|
|
1078
|
+
try {
|
|
1079
|
+
const which = spawnSync("which", [cmdBase], { timeout: 3e3 });
|
|
1080
|
+
if (which.status === 0) {
|
|
1081
|
+
const path6 = which.stdout.toString().trim();
|
|
1082
|
+
if (path6) {
|
|
1083
|
+
logger.debug("Found via which", { cmdBase, path: path6 });
|
|
1084
|
+
return { found: true, path: path6 };
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
logger.debug("which failed", { cmdBase, error });
|
|
1089
|
+
}
|
|
1090
|
+
return { found: false };
|
|
1091
|
+
}
|
|
1092
|
+
var init_cli_provider_detector = __esm({
|
|
1093
|
+
"src/core/cli-provider-detector.ts"() {
|
|
1094
|
+
init_esm_shims();
|
|
1095
|
+
init_logger();
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
function safeValidateExecutionRequest(request) {
|
|
1099
|
+
return executionRequestSchema.safeParse(request);
|
|
1100
|
+
}
|
|
1101
|
+
function safeValidateExecutionResponse(response) {
|
|
1102
|
+
return executionResponseSchema.safeParse(response);
|
|
1103
|
+
}
|
|
1104
|
+
var executionRequestSchema, tokenUsageSchema, finishReasonSchema, executionResponseSchema, costBreakdownSchema, providerErrorTypeSchema;
|
|
1105
|
+
var init_provider_schemas = __esm({
|
|
1106
|
+
"src/providers/provider-schemas.ts"() {
|
|
1107
|
+
init_esm_shims();
|
|
1108
|
+
executionRequestSchema = z.object({
|
|
1109
|
+
prompt: z.string().min(1, "Prompt cannot be empty"),
|
|
1110
|
+
systemPrompt: z.string().optional(),
|
|
1111
|
+
model: z.string().optional(),
|
|
1112
|
+
maxTokens: z.number().int().positive().optional(),
|
|
1113
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
1114
|
+
topP: z.number().min(0).max(1).optional(),
|
|
1115
|
+
topK: z.number().int().positive().optional(),
|
|
1116
|
+
stopSequences: z.array(z.string()).optional(),
|
|
1117
|
+
stream: z.boolean().optional(),
|
|
1118
|
+
metadata: z.record(z.string(), z.any()).optional()
|
|
1119
|
+
}).describe("Provider execution request");
|
|
1120
|
+
tokenUsageSchema = z.object({
|
|
1121
|
+
prompt: z.number().int().nonnegative(),
|
|
1122
|
+
completion: z.number().int().nonnegative(),
|
|
1123
|
+
total: z.number().int().nonnegative()
|
|
1124
|
+
}).refine(
|
|
1125
|
+
(data) => data.total === data.prompt + data.completion,
|
|
1126
|
+
"Total tokens must equal prompt + completion"
|
|
1127
|
+
).describe("Token usage information");
|
|
1128
|
+
finishReasonSchema = z.enum([
|
|
1129
|
+
"stop",
|
|
1130
|
+
// Natural completion
|
|
1131
|
+
"length",
|
|
1132
|
+
// Max tokens reached
|
|
1133
|
+
"content_filter",
|
|
1134
|
+
// Content filtered
|
|
1135
|
+
"tool_calls",
|
|
1136
|
+
// Function/tool called
|
|
1137
|
+
"error"
|
|
1138
|
+
// Error occurred
|
|
1139
|
+
]).describe("Response finish reason");
|
|
1140
|
+
executionResponseSchema = z.object({
|
|
1141
|
+
content: z.string(),
|
|
1142
|
+
model: z.string(),
|
|
1143
|
+
tokensUsed: tokenUsageSchema,
|
|
1144
|
+
latencyMs: z.number().nonnegative(),
|
|
1145
|
+
finishReason: finishReasonSchema,
|
|
1146
|
+
cached: z.boolean().default(false),
|
|
1147
|
+
metadata: z.record(z.string(), z.any()).optional()
|
|
1148
|
+
}).describe("Provider execution response");
|
|
1149
|
+
z.object({
|
|
1150
|
+
available: z.boolean(),
|
|
1151
|
+
latencyMs: z.number().nonnegative(),
|
|
1152
|
+
errorRate: z.number().min(0).max(1),
|
|
1153
|
+
consecutiveFailures: z.number().int().nonnegative(),
|
|
1154
|
+
lastCheckTime: z.number().int().nonnegative().optional()
|
|
1155
|
+
}).describe("Provider health status");
|
|
1156
|
+
z.object({
|
|
1157
|
+
supportsStreaming: z.boolean().default(false),
|
|
1158
|
+
supportsEmbedding: z.boolean().default(false),
|
|
1159
|
+
supportsVision: z.boolean().default(false),
|
|
1160
|
+
supportsFunctionCalling: z.boolean().default(false),
|
|
1161
|
+
maxContextTokens: z.number().int().positive(),
|
|
1162
|
+
supportedModels: z.array(z.string()).min(1)
|
|
1163
|
+
}).describe("Provider capabilities");
|
|
1164
|
+
z.object({
|
|
1165
|
+
hasCapacity: z.boolean(),
|
|
1166
|
+
requestsRemaining: z.number().int().nonnegative(),
|
|
1167
|
+
tokensRemaining: z.number().int().nonnegative(),
|
|
1168
|
+
resetAtMs: z.number().int().positive()
|
|
1169
|
+
}).describe("Rate limit status");
|
|
1170
|
+
costBreakdownSchema = z.object({
|
|
1171
|
+
prompt: z.number().nonnegative(),
|
|
1172
|
+
completion: z.number().nonnegative(),
|
|
1173
|
+
embedding: z.number().nonnegative().optional(),
|
|
1174
|
+
other: z.number().nonnegative().optional()
|
|
1175
|
+
}).describe("Cost breakdown");
|
|
1176
|
+
z.object({
|
|
1177
|
+
amount: z.number().nonnegative(),
|
|
1178
|
+
currency: z.string().length(3).default("USD"),
|
|
1179
|
+
breakdown: costBreakdownSchema
|
|
1180
|
+
}).describe("Cost estimate");
|
|
1181
|
+
z.object({
|
|
1182
|
+
totalRequests: z.number().int().nonnegative(),
|
|
1183
|
+
totalTokens: z.number().int().nonnegative(),
|
|
1184
|
+
totalCost: z.number().nonnegative(),
|
|
1185
|
+
successRate: z.number().min(0).max(1),
|
|
1186
|
+
averageLatencyMs: z.number().nonnegative().optional(),
|
|
1187
|
+
lastRequestTime: z.number().int().nonnegative().optional()
|
|
1188
|
+
}).describe("Provider usage statistics");
|
|
1189
|
+
providerErrorTypeSchema = z.enum([
|
|
1190
|
+
"not_found",
|
|
1191
|
+
"timeout",
|
|
1192
|
+
"rate_limit",
|
|
1193
|
+
"auth_error",
|
|
1194
|
+
"invalid_request",
|
|
1195
|
+
"api_error",
|
|
1196
|
+
"network_error",
|
|
1197
|
+
"config_error",
|
|
1198
|
+
"exec_error",
|
|
1199
|
+
"unknown"
|
|
1200
|
+
]).describe("Provider error type");
|
|
1201
|
+
z.object({
|
|
1202
|
+
type: providerErrorTypeSchema,
|
|
1203
|
+
message: z.string(),
|
|
1204
|
+
code: z.string().optional(),
|
|
1205
|
+
retryable: z.boolean().default(false),
|
|
1206
|
+
details: z.record(z.string(), z.any()).optional()
|
|
1207
|
+
}).describe("Provider error");
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
var execAsync, BaseProvider;
|
|
1037
1211
|
var init_base_provider = __esm({
|
|
1038
1212
|
"src/providers/base-provider.ts"() {
|
|
1039
1213
|
init_esm_shims();
|
|
1040
1214
|
init_logger();
|
|
1041
1215
|
init_errors();
|
|
1216
|
+
init_cli_provider_detector();
|
|
1217
|
+
init_provider_schemas();
|
|
1218
|
+
execAsync = promisify(exec);
|
|
1042
1219
|
BaseProvider = class _BaseProvider {
|
|
1043
1220
|
/**
|
|
1044
1221
|
* Whitelist of allowed provider names for security
|
|
1222
|
+
* v8.3.0: Support both old (claude-code, gemini-cli) and new (claude, gemini) names for backward compatibility
|
|
1223
|
+
* v8.3.1: Added 'grok' for Grok CLI integration
|
|
1045
1224
|
*/
|
|
1046
1225
|
static ALLOWED_PROVIDER_NAMES = [
|
|
1047
1226
|
"claude",
|
|
1227
|
+
"claude-code",
|
|
1228
|
+
// Backward compatibility - maps to claude CLI
|
|
1048
1229
|
"gemini",
|
|
1230
|
+
"gemini-cli",
|
|
1231
|
+
// Backward compatibility - maps to gemini CLI
|
|
1232
|
+
"openai",
|
|
1049
1233
|
"codex",
|
|
1234
|
+
"grok",
|
|
1235
|
+
// Grok CLI (Z.AI GLM 4.6 or X.AI Grok)
|
|
1050
1236
|
"test-provider"
|
|
1051
1237
|
// For unit tests
|
|
1052
1238
|
];
|
|
@@ -1060,7 +1246,7 @@ var init_base_provider = __esm({
|
|
|
1060
1246
|
"E1001" /* CONFIG_INVALID */
|
|
1061
1247
|
);
|
|
1062
1248
|
}
|
|
1063
|
-
this.config = config;
|
|
1249
|
+
this.config = { ...config, name: providerName };
|
|
1064
1250
|
this.health = {
|
|
1065
1251
|
available: false,
|
|
1066
1252
|
latencyMs: 0,
|
|
@@ -1069,6 +1255,78 @@ var init_base_provider = __esm({
|
|
|
1069
1255
|
lastCheck: Date.now()
|
|
1070
1256
|
};
|
|
1071
1257
|
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Execute CLI command - Template method pattern
|
|
1260
|
+
* Common logic here, provider-specific parts via getCLICommand() and getMockResponse()
|
|
1261
|
+
*/
|
|
1262
|
+
async executeCLI(prompt) {
|
|
1263
|
+
if (process.env.AUTOMATOSX_MOCK_PROVIDERS === "true") {
|
|
1264
|
+
logger.debug("Mock mode: returning test response");
|
|
1265
|
+
return this.getMockResponse();
|
|
1266
|
+
}
|
|
1267
|
+
try {
|
|
1268
|
+
const escapedPrompt = this.escapeShellArg(prompt);
|
|
1269
|
+
const cliCommand = this.getCLICommand();
|
|
1270
|
+
logger.debug(`Executing ${cliCommand} CLI`, {
|
|
1271
|
+
command: cliCommand,
|
|
1272
|
+
promptLength: prompt.length
|
|
1273
|
+
});
|
|
1274
|
+
const { stdout, stderr } = await execAsync(
|
|
1275
|
+
`${cliCommand} ${escapedPrompt}`,
|
|
1276
|
+
{
|
|
1277
|
+
timeout: this.config.timeout || 12e4,
|
|
1278
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1279
|
+
shell: "/bin/bash",
|
|
1280
|
+
// Enable shell to support complex commands
|
|
1281
|
+
env: {
|
|
1282
|
+
...process.env,
|
|
1283
|
+
// Force non-interactive mode for CLIs
|
|
1284
|
+
TERM: "dumb",
|
|
1285
|
+
NO_COLOR: "1",
|
|
1286
|
+
// Disable TTY checks for codex and other CLIs
|
|
1287
|
+
FORCE_COLOR: "0",
|
|
1288
|
+
CI: "true",
|
|
1289
|
+
// Many CLIs disable TTY checks in CI mode
|
|
1290
|
+
NO_UPDATE_NOTIFIER: "1",
|
|
1291
|
+
// Disable interactive prompts
|
|
1292
|
+
DEBIAN_FRONTEND: "noninteractive"
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
);
|
|
1296
|
+
if (stderr) {
|
|
1297
|
+
logger.warn(`${cliCommand} CLI stderr output`, { stderr: stderr.trim() });
|
|
1298
|
+
}
|
|
1299
|
+
if (!stdout) {
|
|
1300
|
+
throw new Error(`${cliCommand} CLI returned empty output. stderr: ${stderr || "none"}`);
|
|
1301
|
+
}
|
|
1302
|
+
logger.debug(`${cliCommand} CLI execution successful`, {
|
|
1303
|
+
responseLength: stdout.trim().length
|
|
1304
|
+
});
|
|
1305
|
+
return stdout.trim();
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
logger.error(`${this.getCLICommand()} CLI execution failed`, { error });
|
|
1308
|
+
throw this.handleError(error);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Check if CLI is available - Template method pattern
|
|
1313
|
+
* Uses getCLICommand() to determine which CLI to check
|
|
1314
|
+
*/
|
|
1315
|
+
async checkCLIAvailable() {
|
|
1316
|
+
try {
|
|
1317
|
+
const cliCommand = this.getCLICommand();
|
|
1318
|
+
const path6 = await findOnPath(cliCommand);
|
|
1319
|
+
const available = path6 !== null;
|
|
1320
|
+
logger.debug(`${cliCommand} CLI availability check`, {
|
|
1321
|
+
available,
|
|
1322
|
+
path: path6 || "not found"
|
|
1323
|
+
});
|
|
1324
|
+
return available;
|
|
1325
|
+
} catch (error) {
|
|
1326
|
+
logger.debug(`${this.getCLICommand()} CLI availability check failed`, { error });
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1072
1330
|
/**
|
|
1073
1331
|
* Get provider name
|
|
1074
1332
|
*/
|
|
@@ -1081,6 +1339,16 @@ var init_base_provider = __esm({
|
|
|
1081
1339
|
async execute(request) {
|
|
1082
1340
|
const startTime = Date.now();
|
|
1083
1341
|
try {
|
|
1342
|
+
const requestValidation = safeValidateExecutionRequest(request);
|
|
1343
|
+
if (!requestValidation.success) {
|
|
1344
|
+
const validationErrors = requestValidation.error.issues.map(
|
|
1345
|
+
(e) => `${e.path.join(".")}: ${e.message}`
|
|
1346
|
+
).join("; ");
|
|
1347
|
+
throw new ProviderError(
|
|
1348
|
+
`Invalid execution request: ${validationErrors}`,
|
|
1349
|
+
"E1305" /* PROVIDER_EXEC_ERROR */
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1084
1352
|
logger.debug(`Executing request with ${this.config.name}`, {
|
|
1085
1353
|
prompt: request.prompt.substring(0, 100) + "..."
|
|
1086
1354
|
});
|
|
@@ -1093,7 +1361,7 @@ ${request.prompt}`;
|
|
|
1093
1361
|
const result = await this.executeCLI(fullPrompt);
|
|
1094
1362
|
this.health.consecutiveFailures = 0;
|
|
1095
1363
|
this.health.available = true;
|
|
1096
|
-
|
|
1364
|
+
const response = {
|
|
1097
1365
|
content: result,
|
|
1098
1366
|
model: "default",
|
|
1099
1367
|
// v8.3.0: CLI determines model
|
|
@@ -1107,6 +1375,14 @@ ${request.prompt}`;
|
|
|
1107
1375
|
finishReason: "stop",
|
|
1108
1376
|
cached: false
|
|
1109
1377
|
};
|
|
1378
|
+
const responseValidation = safeValidateExecutionResponse(response);
|
|
1379
|
+
if (!responseValidation.success) {
|
|
1380
|
+
logger.error("Invalid execution response generated", {
|
|
1381
|
+
errors: responseValidation.error.issues,
|
|
1382
|
+
response
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
return response;
|
|
1110
1386
|
} catch (error) {
|
|
1111
1387
|
this.health.consecutiveFailures++;
|
|
1112
1388
|
this.health.available = false;
|
|
@@ -1164,9 +1440,15 @@ ${request.prompt}`;
|
|
|
1164
1440
|
}
|
|
1165
1441
|
/**
|
|
1166
1442
|
* Escape shell command arguments to prevent injection
|
|
1443
|
+
*
|
|
1444
|
+
* v8.3.0 Security Fix: Use POSIX shell single-quote escaping
|
|
1445
|
+
* Wraps argument in single quotes and escapes any existing single quotes
|
|
1446
|
+
* This prevents command injection by ensuring the entire string is treated as a literal.
|
|
1447
|
+
*
|
|
1448
|
+
* Example: hello'world becomes 'hello'\''world'
|
|
1167
1449
|
*/
|
|
1168
1450
|
escapeShellArg(arg) {
|
|
1169
|
-
return arg.replace(/
|
|
1451
|
+
return "'" + arg.replace(/'/g, "'\\''") + "'";
|
|
1170
1452
|
}
|
|
1171
1453
|
// v8.3.0: Stub implementations for backward compatibility with Provider interface
|
|
1172
1454
|
// These will be removed when we update the interface in Phase 4
|
|
@@ -1267,128 +1549,28 @@ ${request.prompt}`;
|
|
|
1267
1549
|
};
|
|
1268
1550
|
}
|
|
1269
1551
|
});
|
|
1270
|
-
function findOnPath(cmdBase) {
|
|
1271
|
-
const isWindows2 = process.platform === "win32";
|
|
1272
|
-
if (isWindows2) {
|
|
1273
|
-
return findOnPathWindows(cmdBase);
|
|
1274
|
-
}
|
|
1275
|
-
return findOnPathUnix(cmdBase);
|
|
1276
|
-
}
|
|
1277
|
-
function findOnPathWindows(cmdBase) {
|
|
1278
|
-
try {
|
|
1279
|
-
const where = spawnSync("where", [cmdBase], {
|
|
1280
|
-
windowsHide: true,
|
|
1281
|
-
timeout: 3e3
|
|
1282
|
-
});
|
|
1283
|
-
if (where.status === 0) {
|
|
1284
|
-
const lines = where.stdout.toString().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
1285
|
-
const firstPath = lines[0];
|
|
1286
|
-
if (firstPath) {
|
|
1287
|
-
logger.debug("Found via where.exe", { cmdBase, path: firstPath });
|
|
1288
|
-
return { found: true, path: firstPath };
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
} catch (error) {
|
|
1292
|
-
logger.debug("where.exe failed, falling back to PATH scan", { error });
|
|
1293
|
-
}
|
|
1294
|
-
const pathext = (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").toUpperCase().split(";").filter(Boolean);
|
|
1295
|
-
const pathEntries = (process.env.PATH || "").split(delimiter).filter(Boolean);
|
|
1296
|
-
for (const dir of pathEntries) {
|
|
1297
|
-
for (const ext2 of pathext) {
|
|
1298
|
-
const fullPath = `${dir}\\${cmdBase}${ext2}`;
|
|
1299
|
-
if (existsSync(fullPath)) {
|
|
1300
|
-
logger.debug("Found via PATH \xD7 PATHEXT", { cmdBase, path: fullPath });
|
|
1301
|
-
return { found: true, path: fullPath };
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
const pathWithoutExt = `${dir}\\${cmdBase}`;
|
|
1305
|
-
if (existsSync(pathWithoutExt)) {
|
|
1306
|
-
logger.debug("Found via PATH (no ext)", { cmdBase, path: pathWithoutExt });
|
|
1307
|
-
return { found: true, path: pathWithoutExt };
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
return { found: false };
|
|
1311
|
-
}
|
|
1312
|
-
function findOnPathUnix(cmdBase) {
|
|
1313
|
-
try {
|
|
1314
|
-
const which = spawnSync("which", [cmdBase], { timeout: 3e3 });
|
|
1315
|
-
if (which.status === 0) {
|
|
1316
|
-
const path6 = which.stdout.toString().trim();
|
|
1317
|
-
if (path6) {
|
|
1318
|
-
logger.debug("Found via which", { cmdBase, path: path6 });
|
|
1319
|
-
return { found: true, path: path6 };
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
} catch (error) {
|
|
1323
|
-
logger.debug("which failed", { cmdBase, error });
|
|
1324
|
-
}
|
|
1325
|
-
return { found: false };
|
|
1326
|
-
}
|
|
1327
|
-
var init_cli_provider_detector = __esm({
|
|
1328
|
-
"src/core/cli-provider-detector.ts"() {
|
|
1329
|
-
init_esm_shims();
|
|
1330
|
-
init_logger();
|
|
1331
|
-
}
|
|
1332
|
-
});
|
|
1333
1552
|
|
|
1334
1553
|
// src/providers/claude-provider.ts
|
|
1335
1554
|
var claude_provider_exports = {};
|
|
1336
1555
|
__export(claude_provider_exports, {
|
|
1337
1556
|
ClaudeProvider: () => ClaudeProvider
|
|
1338
1557
|
});
|
|
1339
|
-
var
|
|
1558
|
+
var ClaudeProvider;
|
|
1340
1559
|
var init_claude_provider = __esm({
|
|
1341
1560
|
"src/providers/claude-provider.ts"() {
|
|
1342
1561
|
init_esm_shims();
|
|
1343
1562
|
init_base_provider();
|
|
1344
|
-
init_logger();
|
|
1345
|
-
init_cli_provider_detector();
|
|
1346
|
-
execAsync = promisify(exec);
|
|
1347
1563
|
ClaudeProvider = class extends BaseProvider {
|
|
1348
1564
|
constructor(config) {
|
|
1349
1565
|
super(config);
|
|
1350
1566
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
*/
|
|
1354
|
-
async executeCLI(prompt) {
|
|
1355
|
-
if (process.env.AUTOMATOSX_MOCK_PROVIDERS === "true") {
|
|
1356
|
-
return `[Mock Claude Response]
|
|
1357
|
-
|
|
1358
|
-
${prompt.substring(0, 100)}...
|
|
1359
|
-
|
|
1360
|
-
Mock response.`;
|
|
1361
|
-
}
|
|
1362
|
-
try {
|
|
1363
|
-
const escapedPrompt = this.escapeShellArg(prompt);
|
|
1364
|
-
const { stdout, stderr } = await execAsync(
|
|
1365
|
-
`claude "${escapedPrompt}"`,
|
|
1366
|
-
{
|
|
1367
|
-
timeout: this.config.timeout || 12e4,
|
|
1368
|
-
// 2 min default
|
|
1369
|
-
maxBuffer: 10 * 1024 * 1024
|
|
1370
|
-
// 10MB
|
|
1371
|
-
}
|
|
1372
|
-
);
|
|
1373
|
-
if (stderr && !stdout) {
|
|
1374
|
-
throw new Error(`Claude CLI error: ${stderr}`);
|
|
1375
|
-
}
|
|
1376
|
-
return stdout.trim();
|
|
1377
|
-
} catch (error) {
|
|
1378
|
-
logger.error("Claude CLI execution failed", { error });
|
|
1379
|
-
throw this.handleError(error);
|
|
1380
|
-
}
|
|
1567
|
+
getCLICommand() {
|
|
1568
|
+
return "claude";
|
|
1381
1569
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
try {
|
|
1387
|
-
const path6 = await findOnPath("claude");
|
|
1388
|
-
return path6 !== null;
|
|
1389
|
-
} catch {
|
|
1390
|
-
return false;
|
|
1391
|
-
}
|
|
1570
|
+
getMockResponse() {
|
|
1571
|
+
return `[Mock Claude Response]
|
|
1572
|
+
|
|
1573
|
+
This is a mock response for testing purposes.`;
|
|
1392
1574
|
}
|
|
1393
1575
|
};
|
|
1394
1576
|
}
|
|
@@ -1399,134 +1581,44 @@ var gemini_provider_exports = {};
|
|
|
1399
1581
|
__export(gemini_provider_exports, {
|
|
1400
1582
|
GeminiProvider: () => GeminiProvider
|
|
1401
1583
|
});
|
|
1402
|
-
var
|
|
1584
|
+
var GeminiProvider;
|
|
1403
1585
|
var init_gemini_provider = __esm({
|
|
1404
1586
|
"src/providers/gemini-provider.ts"() {
|
|
1405
1587
|
init_esm_shims();
|
|
1406
1588
|
init_base_provider();
|
|
1407
|
-
init_logger();
|
|
1408
|
-
init_cli_provider_detector();
|
|
1409
|
-
execAsync2 = promisify(exec);
|
|
1410
1589
|
GeminiProvider = class extends BaseProvider {
|
|
1411
1590
|
constructor(config) {
|
|
1412
1591
|
super(config);
|
|
1413
1592
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
*/
|
|
1417
|
-
async executeCLI(prompt) {
|
|
1418
|
-
if (process.env.AUTOMATOSX_MOCK_PROVIDERS === "true") {
|
|
1419
|
-
logger.debug("Using mock Gemini provider");
|
|
1420
|
-
return `[Mock Gemini Response]
|
|
1421
|
-
|
|
1422
|
-
Received: ${prompt.substring(0, 100)}...
|
|
1423
|
-
|
|
1424
|
-
This is a mock response.`;
|
|
1425
|
-
}
|
|
1426
|
-
try {
|
|
1427
|
-
const escapedPrompt = this.escapeShellArg(prompt);
|
|
1428
|
-
logger.debug("Executing Gemini CLI", {
|
|
1429
|
-
command: "gemini",
|
|
1430
|
-
promptLength: prompt.length
|
|
1431
|
-
});
|
|
1432
|
-
const { stdout, stderr } = await execAsync2(
|
|
1433
|
-
`gemini "${escapedPrompt}"`,
|
|
1434
|
-
{
|
|
1435
|
-
timeout: this.config.timeout || 12e4,
|
|
1436
|
-
// 2 min default
|
|
1437
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
1438
|
-
// 10MB buffer
|
|
1439
|
-
env: { ...process.env }
|
|
1440
|
-
}
|
|
1441
|
-
);
|
|
1442
|
-
if (stderr && !stdout) {
|
|
1443
|
-
throw new Error(`Gemini CLI error: ${stderr}`);
|
|
1444
|
-
}
|
|
1445
|
-
const result = stdout.trim();
|
|
1446
|
-
logger.debug("Gemini CLI execution successful", {
|
|
1447
|
-
responseLength: result.length
|
|
1448
|
-
});
|
|
1449
|
-
return result;
|
|
1450
|
-
} catch (error) {
|
|
1451
|
-
logger.error("Gemini CLI execution failed", {
|
|
1452
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1453
|
-
});
|
|
1454
|
-
throw this.handleError(error);
|
|
1455
|
-
}
|
|
1593
|
+
getCLICommand() {
|
|
1594
|
+
return "gemini";
|
|
1456
1595
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
try {
|
|
1462
|
-
const path6 = await findOnPath("gemini");
|
|
1463
|
-
const available = path6 !== null;
|
|
1464
|
-
logger.debug("Gemini CLI availability check", {
|
|
1465
|
-
available,
|
|
1466
|
-
path: path6 || "not found"
|
|
1467
|
-
});
|
|
1468
|
-
return available;
|
|
1469
|
-
} catch (error) {
|
|
1470
|
-
logger.debug("Gemini CLI availability check failed", { error });
|
|
1471
|
-
return false;
|
|
1472
|
-
}
|
|
1596
|
+
getMockResponse() {
|
|
1597
|
+
return `[Mock Gemini Response]
|
|
1598
|
+
|
|
1599
|
+
This is a mock response for testing purposes.`;
|
|
1473
1600
|
}
|
|
1474
1601
|
};
|
|
1475
1602
|
}
|
|
1476
1603
|
});
|
|
1477
|
-
|
|
1604
|
+
|
|
1605
|
+
// src/providers/openai-provider.ts
|
|
1606
|
+
var OpenAIProvider;
|
|
1478
1607
|
var init_openai_provider = __esm({
|
|
1479
1608
|
"src/providers/openai-provider.ts"() {
|
|
1480
1609
|
init_esm_shims();
|
|
1481
1610
|
init_base_provider();
|
|
1482
|
-
init_logger();
|
|
1483
|
-
init_cli_provider_detector();
|
|
1484
|
-
execAsync3 = promisify(exec);
|
|
1485
1611
|
OpenAIProvider = class extends BaseProvider {
|
|
1486
1612
|
constructor(config) {
|
|
1487
1613
|
super(config);
|
|
1488
1614
|
}
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
*/
|
|
1492
|
-
async executeCLI(prompt) {
|
|
1493
|
-
if (process.env.AUTOMATOSX_MOCK_PROVIDERS === "true") {
|
|
1494
|
-
return `[Mock OpenAI/Codex Response]
|
|
1495
|
-
|
|
1496
|
-
${prompt.substring(0, 100)}...
|
|
1497
|
-
|
|
1498
|
-
Mock response.`;
|
|
1499
|
-
}
|
|
1500
|
-
try {
|
|
1501
|
-
const escapedPrompt = this.escapeShellArg(prompt);
|
|
1502
|
-
const { stdout, stderr } = await execAsync3(
|
|
1503
|
-
`codex "${escapedPrompt}"`,
|
|
1504
|
-
{
|
|
1505
|
-
timeout: this.config.timeout || 12e4,
|
|
1506
|
-
// 2 min default
|
|
1507
|
-
maxBuffer: 10 * 1024 * 1024
|
|
1508
|
-
// 10MB
|
|
1509
|
-
}
|
|
1510
|
-
);
|
|
1511
|
-
if (stderr && !stdout) {
|
|
1512
|
-
throw new Error(`Codex CLI error: ${stderr}`);
|
|
1513
|
-
}
|
|
1514
|
-
return stdout.trim();
|
|
1515
|
-
} catch (error) {
|
|
1516
|
-
logger.error("Codex CLI execution failed", { error });
|
|
1517
|
-
throw this.handleError(error);
|
|
1518
|
-
}
|
|
1615
|
+
getCLICommand() {
|
|
1616
|
+
return "codex";
|
|
1519
1617
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
try {
|
|
1525
|
-
const path6 = await findOnPath("codex");
|
|
1526
|
-
return path6 !== null;
|
|
1527
|
-
} catch {
|
|
1528
|
-
return false;
|
|
1529
|
-
}
|
|
1618
|
+
getMockResponse() {
|
|
1619
|
+
return `[Mock OpenAI/Codex Response]
|
|
1620
|
+
|
|
1621
|
+
This is a mock response for testing purposes.`;
|
|
1530
1622
|
}
|
|
1531
1623
|
};
|
|
1532
1624
|
}
|
|
@@ -2498,6 +2590,25 @@ var DEFAULT_CONFIG = {
|
|
|
2498
2590
|
limitTracking: GLOBAL_PROVIDER_DEFAULTS.limitTracking
|
|
2499
2591
|
// OpenAI: daily limits
|
|
2500
2592
|
// v5.0.5: Removed defaults - let provider CLI use optimal defaults
|
|
2593
|
+
},
|
|
2594
|
+
"grok": {
|
|
2595
|
+
enabled: true,
|
|
2596
|
+
priority: 4,
|
|
2597
|
+
timeout: 27e5,
|
|
2598
|
+
// 45 minutes
|
|
2599
|
+
command: "grok",
|
|
2600
|
+
healthCheck: {
|
|
2601
|
+
enabled: true,
|
|
2602
|
+
interval: 3e5,
|
|
2603
|
+
// 5 minutes
|
|
2604
|
+
timeout: 5e3
|
|
2605
|
+
},
|
|
2606
|
+
// v8.3.2: Grok provider defaults
|
|
2607
|
+
circuitBreaker: GLOBAL_PROVIDER_DEFAULTS.circuitBreaker,
|
|
2608
|
+
processManagement: GLOBAL_PROVIDER_DEFAULTS.processManagement,
|
|
2609
|
+
versionDetection: GLOBAL_PROVIDER_DEFAULTS.versionDetection,
|
|
2610
|
+
limitTracking: GLOBAL_PROVIDER_DEFAULTS.limitTracking
|
|
2611
|
+
// Grok: daily limits
|
|
2501
2612
|
}
|
|
2502
2613
|
},
|
|
2503
2614
|
execution: {
|
|
@@ -3332,6 +3443,36 @@ var PRECOMPILED_CONFIG = {
|
|
|
3332
3443
|
"window": "daily",
|
|
3333
3444
|
"resetHourUtc": 0
|
|
3334
3445
|
}
|
|
3446
|
+
},
|
|
3447
|
+
"grok": {
|
|
3448
|
+
"enabled": true,
|
|
3449
|
+
"priority": 4,
|
|
3450
|
+
"timeout": 27e5,
|
|
3451
|
+
"command": "grok",
|
|
3452
|
+
"healthCheck": {
|
|
3453
|
+
"enabled": true,
|
|
3454
|
+
"interval": 3e5,
|
|
3455
|
+
"timeout": 5e3
|
|
3456
|
+
},
|
|
3457
|
+
"circuitBreaker": {
|
|
3458
|
+
"enabled": true,
|
|
3459
|
+
"failureThreshold": 3,
|
|
3460
|
+
"recoveryTimeout": 6e4
|
|
3461
|
+
},
|
|
3462
|
+
"processManagement": {
|
|
3463
|
+
"gracefulShutdownTimeout": 5e3,
|
|
3464
|
+
"forceKillDelay": 1e3
|
|
3465
|
+
},
|
|
3466
|
+
"versionDetection": {
|
|
3467
|
+
"timeout": 5e3,
|
|
3468
|
+
"forceKillDelay": 1e3,
|
|
3469
|
+
"cacheEnabled": true
|
|
3470
|
+
},
|
|
3471
|
+
"limitTracking": {
|
|
3472
|
+
"enabled": true,
|
|
3473
|
+
"window": "daily",
|
|
3474
|
+
"resetHourUtc": 0
|
|
3475
|
+
}
|
|
3335
3476
|
}
|
|
3336
3477
|
},
|
|
3337
3478
|
"execution": {
|
|
@@ -3538,11 +3679,311 @@ var PRECOMPILED_CONFIG = {
|
|
|
3538
3679
|
},
|
|
3539
3680
|
"router": {
|
|
3540
3681
|
"healthCheckInterval": 6e4,
|
|
3541
|
-
"providerCooldownMs": 3e4
|
|
3682
|
+
"providerCooldownMs": 3e4,
|
|
3683
|
+
"enableFreeTierPrioritization": true,
|
|
3684
|
+
"enableWorkloadAwareRouting": true
|
|
3542
3685
|
},
|
|
3543
|
-
"version": "8.3.
|
|
3686
|
+
"version": "8.3.1"
|
|
3544
3687
|
};
|
|
3545
3688
|
|
|
3689
|
+
// src/core/config-schemas.ts
|
|
3690
|
+
init_esm_shims();
|
|
3691
|
+
z.enum([
|
|
3692
|
+
"claude",
|
|
3693
|
+
"claude-code",
|
|
3694
|
+
"gemini",
|
|
3695
|
+
"gemini-cli",
|
|
3696
|
+
"openai",
|
|
3697
|
+
"codex",
|
|
3698
|
+
"grok",
|
|
3699
|
+
"test-provider"
|
|
3700
|
+
]).describe("Provider name (whitelisted for security)");
|
|
3701
|
+
var commandSchema = z.string().min(1, "command is required").max(VALIDATION_LIMITS.MAX_COMMAND_LENGTH).regex(
|
|
3702
|
+
/^[a-zA-Z0-9_-]+$/,
|
|
3703
|
+
"Command must be alphanumeric with dash/underscore only (prevents command injection)"
|
|
3704
|
+
).describe("CLI command name");
|
|
3705
|
+
var safeNameSchema = z.string().min(1).max(VALIDATION_LIMITS.MAX_NAME_LENGTH).regex(
|
|
3706
|
+
/^[a-zA-Z0-9_-]+$/,
|
|
3707
|
+
"Name must be alphanumeric with dash/underscore only"
|
|
3708
|
+
).describe("Safe identifier name");
|
|
3709
|
+
var relativePathSchema = z.string().min(1).refine(
|
|
3710
|
+
(path6) => !path6.includes("..") && !path6.startsWith("/"),
|
|
3711
|
+
"Path must be relative (no ../, no absolute paths)"
|
|
3712
|
+
).describe("Relative path within project");
|
|
3713
|
+
var fileExtensionSchema = z.string().regex(
|
|
3714
|
+
/^\.[a-zA-Z0-9]{1,10}$/,
|
|
3715
|
+
"Extension must start with dot and be alphanumeric (max 10 chars)"
|
|
3716
|
+
).describe("File extension");
|
|
3717
|
+
var positiveIntSchema = z.number().int().positive("must be a positive integer").describe("Positive integer");
|
|
3718
|
+
var nonNegativeIntSchema = z.number().int().nonnegative().describe("Non-negative integer");
|
|
3719
|
+
var timeoutSchema = z.number().int().min(VALIDATION_LIMITS.MIN_TIMEOUT, `Timeout must be >= ${VALIDATION_LIMITS.MIN_TIMEOUT}ms`).max(VALIDATION_LIMITS.MAX_TIMEOUT, `Timeout must be <= ${VALIDATION_LIMITS.MAX_TIMEOUT}ms`).describe("Timeout in milliseconds");
|
|
3720
|
+
var intervalSchema = z.number().int().min(VALIDATION_LIMITS.MIN_INTERVAL, `Interval must be >= ${VALIDATION_LIMITS.MIN_INTERVAL}ms`).max(VALIDATION_LIMITS.MAX_TIMEOUT, `Interval must be <= ${VALIDATION_LIMITS.MAX_TIMEOUT}ms`).describe("Interval in milliseconds");
|
|
3721
|
+
var healthCheckConfigSchema = z.object({
|
|
3722
|
+
enabled: z.boolean().default(true),
|
|
3723
|
+
interval: intervalSchema,
|
|
3724
|
+
timeout: timeoutSchema.min(100, "Health check timeout must be >= 100ms")
|
|
3725
|
+
}).describe("Health check configuration");
|
|
3726
|
+
var circuitBreakerConfigSchema = z.object({
|
|
3727
|
+
enabled: z.boolean().default(true),
|
|
3728
|
+
failureThreshold: z.number().int().min(1).max(10).default(3),
|
|
3729
|
+
recoveryTimeout: timeoutSchema
|
|
3730
|
+
}).describe("Circuit breaker configuration");
|
|
3731
|
+
var processManagementConfigSchema = z.object({
|
|
3732
|
+
gracefulShutdownTimeout: timeoutSchema,
|
|
3733
|
+
forceKillDelay: positiveIntSchema
|
|
3734
|
+
}).describe("Process management configuration");
|
|
3735
|
+
var versionDetectionConfigSchema = z.object({
|
|
3736
|
+
timeout: timeoutSchema,
|
|
3737
|
+
forceKillDelay: positiveIntSchema,
|
|
3738
|
+
cacheEnabled: z.boolean().default(true)
|
|
3739
|
+
}).describe("Version detection configuration");
|
|
3740
|
+
var limitTrackingConfigSchema = z.object({
|
|
3741
|
+
enabled: z.boolean().default(true),
|
|
3742
|
+
window: z.enum(["daily", "weekly", "custom"]).default("daily"),
|
|
3743
|
+
resetHourUtc: z.number().int().min(0).max(23).default(0),
|
|
3744
|
+
customResetMs: positiveIntSchema.optional()
|
|
3745
|
+
}).describe("Provider limit tracking configuration");
|
|
3746
|
+
var providerConfigSchema = z.object({
|
|
3747
|
+
enabled: z.boolean().default(true),
|
|
3748
|
+
priority: positiveIntSchema,
|
|
3749
|
+
timeout: timeoutSchema,
|
|
3750
|
+
command: commandSchema,
|
|
3751
|
+
healthCheck: healthCheckConfigSchema.optional(),
|
|
3752
|
+
circuitBreaker: circuitBreakerConfigSchema.optional(),
|
|
3753
|
+
processManagement: processManagementConfigSchema.optional(),
|
|
3754
|
+
versionDetection: versionDetectionConfigSchema.optional(),
|
|
3755
|
+
limitTracking: limitTrackingConfigSchema.optional()
|
|
3756
|
+
}).describe("Provider configuration");
|
|
3757
|
+
var providersConfigSchema = z.record(
|
|
3758
|
+
safeNameSchema,
|
|
3759
|
+
providerConfigSchema
|
|
3760
|
+
).describe("Providers configuration map");
|
|
3761
|
+
var retryConfigSchema = z.object({
|
|
3762
|
+
maxAttempts: z.number().int().min(1).max(10).default(3),
|
|
3763
|
+
initialDelay: nonNegativeIntSchema.max(VALIDATION_LIMITS.MAX_TIMEOUT),
|
|
3764
|
+
maxDelay: timeoutSchema,
|
|
3765
|
+
backoffFactor: z.number().min(VALIDATION_LIMITS.MIN_BACKOFF_FACTOR).max(VALIDATION_LIMITS.MAX_BACKOFF_FACTOR).default(2),
|
|
3766
|
+
retryableErrors: z.array(z.string()).max(VALIDATION_LIMITS.MAX_ARRAY_LENGTH).optional()
|
|
3767
|
+
}).refine(
|
|
3768
|
+
(data) => data.maxDelay >= data.initialDelay,
|
|
3769
|
+
"maxDelay must be >= initialDelay"
|
|
3770
|
+
).describe("Retry configuration");
|
|
3771
|
+
var providerExecutionConfigSchema = z.object({
|
|
3772
|
+
maxWaitMs: timeoutSchema
|
|
3773
|
+
}).describe("Provider execution configuration");
|
|
3774
|
+
var concurrencyConfigSchema = z.object({
|
|
3775
|
+
maxConcurrentAgents: z.number().int().min(1).max(VALIDATION_LIMITS.MAX_CONCURRENT_AGENTS).optional(),
|
|
3776
|
+
autoDetect: z.boolean().default(false),
|
|
3777
|
+
cpuMultiplier: z.number().min(0.1).max(10).default(1),
|
|
3778
|
+
minConcurrency: positiveIntSchema.default(2),
|
|
3779
|
+
maxConcurrency: positiveIntSchema.max(VALIDATION_LIMITS.MAX_CONCURRENT_AGENTS).default(16)
|
|
3780
|
+
}).describe("Concurrency configuration");
|
|
3781
|
+
var stagesConfigSchema = z.object({
|
|
3782
|
+
enabled: z.boolean().default(true),
|
|
3783
|
+
defaultTimeout: timeoutSchema.default(18e5),
|
|
3784
|
+
checkpointPath: relativePathSchema.default(".automatosx/checkpoints"),
|
|
3785
|
+
autoSaveCheckpoint: z.boolean().default(true),
|
|
3786
|
+
cleanupAfterDays: positiveIntSchema.max(365).default(7),
|
|
3787
|
+
retry: z.object({
|
|
3788
|
+
defaultMaxRetries: nonNegativeIntSchema.default(1),
|
|
3789
|
+
defaultRetryDelay: positiveIntSchema.default(2e3)
|
|
3790
|
+
}).optional(),
|
|
3791
|
+
prompts: z.object({
|
|
3792
|
+
timeout: timeoutSchema.default(6e5),
|
|
3793
|
+
autoConfirm: z.boolean().default(false),
|
|
3794
|
+
locale: z.string().default("en")
|
|
3795
|
+
}).optional(),
|
|
3796
|
+
progress: z.object({
|
|
3797
|
+
updateInterval: positiveIntSchema.default(2e3),
|
|
3798
|
+
syntheticProgress: z.boolean().default(true)
|
|
3799
|
+
}).optional()
|
|
3800
|
+
}).describe("Stages configuration");
|
|
3801
|
+
var executionConfigSchema = z.object({
|
|
3802
|
+
defaultTimeout: timeoutSchema,
|
|
3803
|
+
concurrency: concurrencyConfigSchema.optional(),
|
|
3804
|
+
retry: retryConfigSchema,
|
|
3805
|
+
provider: providerExecutionConfigSchema,
|
|
3806
|
+
stages: stagesConfigSchema.optional()
|
|
3807
|
+
}).describe("Execution configuration");
|
|
3808
|
+
var sessionConfigSchema = z.object({
|
|
3809
|
+
maxSessions: positiveIntSchema.max(VALIDATION_LIMITS.MAX_SESSIONS),
|
|
3810
|
+
maxMetadataSize: positiveIntSchema.min(VALIDATION_LIMITS.MIN_BYTES).max(VALIDATION_LIMITS.MAX_FILE_SIZE),
|
|
3811
|
+
saveDebounce: nonNegativeIntSchema.max(VALIDATION_LIMITS.MAX_TIMEOUT),
|
|
3812
|
+
cleanupAfterDays: positiveIntSchema.max(365),
|
|
3813
|
+
maxUuidAttempts: positiveIntSchema.max(1e3),
|
|
3814
|
+
persistPath: relativePathSchema
|
|
3815
|
+
}).describe("Session configuration");
|
|
3816
|
+
var delegationConfigSchema = z.object({
|
|
3817
|
+
maxDepth: positiveIntSchema.max(5, "Delegation depth limited to 5 to prevent deep chains"),
|
|
3818
|
+
timeout: timeoutSchema,
|
|
3819
|
+
enableCycleDetection: z.boolean().default(true)
|
|
3820
|
+
}).describe("Delegation configuration");
|
|
3821
|
+
var orchestrationConfigSchema = z.object({
|
|
3822
|
+
session: sessionConfigSchema,
|
|
3823
|
+
delegation: delegationConfigSchema
|
|
3824
|
+
}).describe("Orchestration configuration");
|
|
3825
|
+
var memorySearchConfigSchema = z.object({
|
|
3826
|
+
defaultLimit: positiveIntSchema.max(1e3),
|
|
3827
|
+
maxLimit: positiveIntSchema.max(1e4),
|
|
3828
|
+
timeout: timeoutSchema.min(100)
|
|
3829
|
+
}).refine(
|
|
3830
|
+
(data) => data.maxLimit >= data.defaultLimit,
|
|
3831
|
+
"maxLimit must be >= defaultLimit"
|
|
3832
|
+
).describe("Memory search configuration");
|
|
3833
|
+
var memoryConfigSchema = z.object({
|
|
3834
|
+
maxEntries: positiveIntSchema.max(VALIDATION_LIMITS.MAX_ENTRIES),
|
|
3835
|
+
persistPath: relativePathSchema.default(".automatosx/memory"),
|
|
3836
|
+
autoCleanup: z.boolean().default(true),
|
|
3837
|
+
cleanupDays: positiveIntSchema.max(365).default(30),
|
|
3838
|
+
busyTimeout: positiveIntSchema.default(5e3),
|
|
3839
|
+
search: memorySearchConfigSchema.optional()
|
|
3840
|
+
}).describe("Memory configuration");
|
|
3841
|
+
var abilitiesCacheConfigSchema = z.object({
|
|
3842
|
+
enabled: z.boolean().default(true),
|
|
3843
|
+
maxEntries: positiveIntSchema.max(1e3),
|
|
3844
|
+
ttl: intervalSchema.max(VALIDATION_LIMITS.MAX_TTL),
|
|
3845
|
+
maxSize: positiveIntSchema.min(VALIDATION_LIMITS.MIN_BYTES).max(VALIDATION_LIMITS.MAX_CACHE_SIZE),
|
|
3846
|
+
cleanupInterval: intervalSchema
|
|
3847
|
+
}).describe("Abilities cache configuration");
|
|
3848
|
+
var abilitiesLimitsConfigSchema = z.object({
|
|
3849
|
+
maxFileSize: positiveIntSchema.min(VALIDATION_LIMITS.MIN_FILE_SIZE).max(VALIDATION_LIMITS.MAX_FILE_SIZE)
|
|
3850
|
+
}).describe("Abilities limits configuration");
|
|
3851
|
+
var abilitiesConfigSchema = z.object({
|
|
3852
|
+
basePath: relativePathSchema,
|
|
3853
|
+
fallbackPath: relativePathSchema,
|
|
3854
|
+
cache: abilitiesCacheConfigSchema,
|
|
3855
|
+
limits: abilitiesLimitsConfigSchema
|
|
3856
|
+
}).describe("Abilities configuration");
|
|
3857
|
+
var workspaceConfigSchema = z.object({
|
|
3858
|
+
prdPath: z.string().min(1),
|
|
3859
|
+
tmpPath: z.string().min(1),
|
|
3860
|
+
autoCleanupTmp: z.boolean().default(true),
|
|
3861
|
+
tmpCleanupDays: positiveIntSchema.max(365)
|
|
3862
|
+
}).describe("Workspace configuration");
|
|
3863
|
+
var loggingRetentionConfigSchema = z.object({
|
|
3864
|
+
maxSizeBytes: positiveIntSchema.min(VALIDATION_LIMITS.MIN_BYTES).max(VALIDATION_LIMITS.MAX_FILE_SIZE * 10),
|
|
3865
|
+
maxAgeDays: positiveIntSchema.max(365),
|
|
3866
|
+
compress: z.boolean().default(true)
|
|
3867
|
+
}).describe("Logging retention configuration");
|
|
3868
|
+
var loggingConfigSchema = z.object({
|
|
3869
|
+
level: z.enum(["debug", "info", "warn", "error"]).default("info"),
|
|
3870
|
+
path: relativePathSchema,
|
|
3871
|
+
console: z.boolean().default(true),
|
|
3872
|
+
retention: loggingRetentionConfigSchema.optional()
|
|
3873
|
+
}).describe("Logging configuration");
|
|
3874
|
+
var cacheConfigSchema = z.object({
|
|
3875
|
+
enabled: z.boolean().default(true),
|
|
3876
|
+
maxEntries: positiveIntSchema.max(1e4),
|
|
3877
|
+
ttl: intervalSchema.max(VALIDATION_LIMITS.MAX_TTL),
|
|
3878
|
+
cleanupInterval: intervalSchema
|
|
3879
|
+
}).describe("Cache configuration");
|
|
3880
|
+
var adaptiveCacheConfigSchema = z.object({
|
|
3881
|
+
maxEntries: positiveIntSchema.max(1e4),
|
|
3882
|
+
baseTTL: intervalSchema,
|
|
3883
|
+
minTTL: intervalSchema,
|
|
3884
|
+
maxTTL: intervalSchema.max(VALIDATION_LIMITS.MAX_TTL),
|
|
3885
|
+
adaptiveMultiplier: z.number().min(1).max(10),
|
|
3886
|
+
lowFreqDivisor: z.number().min(1).max(10),
|
|
3887
|
+
frequencyThreshold: positiveIntSchema,
|
|
3888
|
+
cleanupInterval: intervalSchema
|
|
3889
|
+
}).refine(
|
|
3890
|
+
(data) => data.maxTTL >= data.baseTTL && data.baseTTL >= data.minTTL,
|
|
3891
|
+
"TTL order must be: minTTL <= baseTTL <= maxTTL"
|
|
3892
|
+
).describe("Adaptive cache configuration");
|
|
3893
|
+
var responseCacheConfigSchema = z.object({
|
|
3894
|
+
enabled: z.boolean().default(false),
|
|
3895
|
+
ttl: positiveIntSchema,
|
|
3896
|
+
maxSize: positiveIntSchema,
|
|
3897
|
+
maxMemorySize: positiveIntSchema,
|
|
3898
|
+
dbPath: relativePathSchema
|
|
3899
|
+
}).describe("Response cache configuration");
|
|
3900
|
+
var rateLimitConfigSchema = z.object({
|
|
3901
|
+
enabled: z.boolean().default(false),
|
|
3902
|
+
requestsPerMinute: positiveIntSchema.max(1e3),
|
|
3903
|
+
burstSize: positiveIntSchema.max(100)
|
|
3904
|
+
}).describe("Rate limit configuration");
|
|
3905
|
+
var performanceConfigSchema = z.object({
|
|
3906
|
+
profileCache: cacheConfigSchema,
|
|
3907
|
+
teamCache: cacheConfigSchema,
|
|
3908
|
+
providerCache: cacheConfigSchema,
|
|
3909
|
+
adaptiveCache: adaptiveCacheConfigSchema,
|
|
3910
|
+
responseCache: responseCacheConfigSchema.optional(),
|
|
3911
|
+
rateLimit: rateLimitConfigSchema.optional()
|
|
3912
|
+
}).describe("Performance configuration");
|
|
3913
|
+
var embeddingConfigSchema = z.object({
|
|
3914
|
+
timeout: timeoutSchema,
|
|
3915
|
+
retryDelay: positiveIntSchema,
|
|
3916
|
+
dimensions: positiveIntSchema.max(1e4),
|
|
3917
|
+
maxRetries: nonNegativeIntSchema.max(10)
|
|
3918
|
+
}).describe("Embedding configuration");
|
|
3919
|
+
var securityConfigSchema = z.object({
|
|
3920
|
+
enablePathValidation: z.boolean().default(true),
|
|
3921
|
+
allowedExtensions: z.array(fileExtensionSchema).max(VALIDATION_LIMITS.MAX_ARRAY_LENGTH).optional()
|
|
3922
|
+
}).describe("Security configuration");
|
|
3923
|
+
var developmentConfigSchema = z.object({
|
|
3924
|
+
mockProviders: z.boolean().default(false),
|
|
3925
|
+
profileMode: z.boolean().default(false)
|
|
3926
|
+
}).describe("Development configuration");
|
|
3927
|
+
var advancedConfigSchema = z.object({
|
|
3928
|
+
embedding: embeddingConfigSchema.optional(),
|
|
3929
|
+
security: securityConfigSchema.optional(),
|
|
3930
|
+
development: developmentConfigSchema.optional()
|
|
3931
|
+
}).describe("Advanced configuration");
|
|
3932
|
+
var vscodeConfigSchema = z.object({
|
|
3933
|
+
enabled: z.boolean().default(false),
|
|
3934
|
+
apiPort: z.number().int().min(VALIDATION_LIMITS.MIN_PORT).max(VALIDATION_LIMITS.MAX_PORT),
|
|
3935
|
+
autoStart: z.boolean().default(true),
|
|
3936
|
+
outputPanel: z.boolean().default(true),
|
|
3937
|
+
notifications: z.boolean().default(true)
|
|
3938
|
+
}).describe("VSCode integration configuration");
|
|
3939
|
+
var integrationConfigSchema = z.object({
|
|
3940
|
+
vscode: vscodeConfigSchema.optional()
|
|
3941
|
+
}).describe("Integration configuration");
|
|
3942
|
+
var cliRunConfigSchema = z.object({
|
|
3943
|
+
defaultMemory: z.boolean().default(true),
|
|
3944
|
+
defaultSaveMemory: z.boolean().default(true),
|
|
3945
|
+
defaultFormat: z.enum(["text", "json"]).default("text"),
|
|
3946
|
+
defaultVerbose: z.boolean().default(false)
|
|
3947
|
+
}).describe("CLI run configuration");
|
|
3948
|
+
var cliSessionConfigSchema = z.object({
|
|
3949
|
+
defaultShowAgents: z.boolean().default(true)
|
|
3950
|
+
}).describe("CLI session configuration");
|
|
3951
|
+
var cliMemoryConfigSchema = z.object({
|
|
3952
|
+
defaultLimit: positiveIntSchema.default(10)
|
|
3953
|
+
}).describe("CLI memory configuration");
|
|
3954
|
+
var cliConfigSchema = z.object({
|
|
3955
|
+
run: cliRunConfigSchema.optional(),
|
|
3956
|
+
session: cliSessionConfigSchema.optional(),
|
|
3957
|
+
memory: cliMemoryConfigSchema.optional()
|
|
3958
|
+
}).describe("CLI configuration");
|
|
3959
|
+
var routerConfigSchema = z.object({
|
|
3960
|
+
healthCheckInterval: intervalSchema,
|
|
3961
|
+
providerCooldownMs: positiveIntSchema,
|
|
3962
|
+
circuitBreakerThreshold: positiveIntSchema.max(10).optional(),
|
|
3963
|
+
// v8.3.2: Make optional to match interface
|
|
3964
|
+
enableFreeTierPrioritization: z.boolean().default(true),
|
|
3965
|
+
enableWorkloadAwareRouting: z.boolean().default(true)
|
|
3966
|
+
}).describe("Router configuration");
|
|
3967
|
+
var automatosXConfigSchema = z.object({
|
|
3968
|
+
providers: providersConfigSchema.optional(),
|
|
3969
|
+
execution: executionConfigSchema.optional(),
|
|
3970
|
+
orchestration: orchestrationConfigSchema.optional(),
|
|
3971
|
+
memory: memoryConfigSchema.optional(),
|
|
3972
|
+
abilities: abilitiesConfigSchema.optional(),
|
|
3973
|
+
workspace: workspaceConfigSchema.optional(),
|
|
3974
|
+
logging: loggingConfigSchema.optional(),
|
|
3975
|
+
performance: performanceConfigSchema.optional(),
|
|
3976
|
+
advanced: advancedConfigSchema.optional(),
|
|
3977
|
+
integration: integrationConfigSchema.optional(),
|
|
3978
|
+
cli: cliConfigSchema.optional(),
|
|
3979
|
+
router: routerConfigSchema.optional(),
|
|
3980
|
+
version: z.string().regex(/^\d+\.\d+\.\d+$/, "Version must be semver format (x.y.z)").optional()
|
|
3981
|
+
}).describe("AutomatosX configuration");
|
|
3982
|
+
function safeValidateConfig(config) {
|
|
3983
|
+
return automatosXConfigSchema.safeParse(config);
|
|
3984
|
+
}
|
|
3985
|
+
automatosXConfigSchema.partial().passthrough();
|
|
3986
|
+
|
|
3546
3987
|
// src/core/config.ts
|
|
3547
3988
|
var configCache = new TTLCache({
|
|
3548
3989
|
ttl: 6e4,
|
|
@@ -3667,7 +4108,21 @@ async function loadConfigFile(path6) {
|
|
|
3667
4108
|
function mergeConfig(defaults2, user) {
|
|
3668
4109
|
return deepMerge(defaults2, user);
|
|
3669
4110
|
}
|
|
4111
|
+
function validateConfigWithZod(config) {
|
|
4112
|
+
const result = safeValidateConfig(config);
|
|
4113
|
+
if (result.success) {
|
|
4114
|
+
return [];
|
|
4115
|
+
}
|
|
4116
|
+
return result.error.issues.map((err) => {
|
|
4117
|
+
const path6 = err.path.join(".");
|
|
4118
|
+
return `${path6}: ${err.message}`;
|
|
4119
|
+
});
|
|
4120
|
+
}
|
|
3670
4121
|
function validateConfig(config) {
|
|
4122
|
+
const zodErrors = validateConfigWithZod(config);
|
|
4123
|
+
if (zodErrors.length > 0) {
|
|
4124
|
+
return zodErrors;
|
|
4125
|
+
}
|
|
3671
4126
|
const errors = [];
|
|
3672
4127
|
for (const [name, provider] of Object.entries(config.providers)) {
|
|
3673
4128
|
if (!isValidName(name)) {
|
|
@@ -5211,6 +5666,17 @@ var setupCommand = {
|
|
|
5211
5666
|
console.log(chalk5.cyan("\u{1F4D6} Setting up GEMINI.md with AutomatosX integration..."));
|
|
5212
5667
|
await setupProjectGeminiMd(projectDir, packageRoot, argv.force ?? false);
|
|
5213
5668
|
console.log(chalk5.green(" \u2713 GEMINI.md configured"));
|
|
5669
|
+
console.log(chalk5.cyan("\u{1F50C} Setting up Grok CLI integration..."));
|
|
5670
|
+
const grokDir = join(projectDir, ".grok");
|
|
5671
|
+
const grokDirExistedBefore = await checkExists2(grokDir);
|
|
5672
|
+
await setupGrokIntegration(projectDir, packageRoot);
|
|
5673
|
+
if (!grokDirExistedBefore) {
|
|
5674
|
+
createdResources.push(grokDir);
|
|
5675
|
+
}
|
|
5676
|
+
console.log(chalk5.green(" \u2713 Grok CLI integration configured"));
|
|
5677
|
+
console.log(chalk5.cyan("\u{1F4D6} Setting up GROK.md with AutomatosX integration..."));
|
|
5678
|
+
await setupProjectGrokMd(projectDir, packageRoot, argv.force ?? false);
|
|
5679
|
+
console.log(chalk5.green(" \u2713 GROK.md configured"));
|
|
5214
5680
|
console.log(chalk5.cyan("\u{1F4D6} Setting up AGENTS.md with AutomatosX integration..."));
|
|
5215
5681
|
await setupProjectAgentsMd(projectDir, packageRoot, argv.force ?? false);
|
|
5216
5682
|
console.log(chalk5.green(" \u2713 AGENTS.md configured"));
|
|
@@ -5273,6 +5739,11 @@ var setupCommand = {
|
|
|
5273
5739
|
console.log(chalk5.gray(" \u2022 Use natural language to work with ax agents"));
|
|
5274
5740
|
console.log(chalk5.gray(' \u2022 Example: "Use ax agent backend to create a REST API"'));
|
|
5275
5741
|
console.log(chalk5.gray(" \u2022 No special commands needed - just ask naturally!\n"));
|
|
5742
|
+
console.log(chalk5.cyan("Grok CLI Integration:"));
|
|
5743
|
+
console.log(chalk5.gray(" \u2022 Configure .grok/settings.json with your API key"));
|
|
5744
|
+
console.log(chalk5.gray(" \u2022 Supports X.AI (grok-3-fast) and Z.AI (glm-4.6)"));
|
|
5745
|
+
console.log(chalk5.gray(' \u2022 Enable in automatosx.config.json: "grok": { "enabled": true }'));
|
|
5746
|
+
console.log(chalk5.gray(" \u2022 See GROK.md for setup instructions\n"));
|
|
5276
5747
|
console.log(chalk5.cyan("OpenAI Codex Provider:"));
|
|
5277
5748
|
console.log(chalk5.gray(" \u2022 Use natural language to work with ax agents"));
|
|
5278
5749
|
console.log(chalk5.gray(' \u2022 Or use terminal: ax run <agent> "task"'));
|
|
@@ -5829,6 +6300,104 @@ async function setupProjectGeminiMd(projectDir, packageRoot, force) {
|
|
|
5829
6300
|
});
|
|
5830
6301
|
}
|
|
5831
6302
|
}
|
|
6303
|
+
async function setupGrokIntegration(projectDir, packageRoot) {
|
|
6304
|
+
const examplesBaseDir = join(packageRoot, "examples/grok");
|
|
6305
|
+
const templatesDir = join(packageRoot, "templates/providers");
|
|
6306
|
+
const grokDir = join(projectDir, ".grok");
|
|
6307
|
+
await mkdir(grokDir, { recursive: true });
|
|
6308
|
+
try {
|
|
6309
|
+
const settingsSource = join(examplesBaseDir, "settings.json");
|
|
6310
|
+
const settingsTarget = join(grokDir, "settings.json");
|
|
6311
|
+
const exists = await checkExists2(settingsTarget);
|
|
6312
|
+
if (!exists) {
|
|
6313
|
+
await copyFile(settingsSource, settingsTarget);
|
|
6314
|
+
logger.info("Created .grok/settings.json template", { path: settingsTarget });
|
|
6315
|
+
} else {
|
|
6316
|
+
logger.info(".grok/settings.json already exists, skipping", { path: settingsTarget });
|
|
6317
|
+
}
|
|
6318
|
+
} catch (error) {
|
|
6319
|
+
logger.warn("Failed to copy Grok settings template", {
|
|
6320
|
+
error: error.message
|
|
6321
|
+
});
|
|
6322
|
+
}
|
|
6323
|
+
try {
|
|
6324
|
+
const providersDir = join(projectDir, ".automatosx/providers");
|
|
6325
|
+
await mkdir(providersDir, { recursive: true });
|
|
6326
|
+
const xaiTemplateSource = join(templatesDir, "grok.yaml.template");
|
|
6327
|
+
const xaiTemplateTarget = join(providersDir, "grok.yaml.template");
|
|
6328
|
+
const xaiExists = await checkExists2(xaiTemplateTarget);
|
|
6329
|
+
if (!xaiExists) {
|
|
6330
|
+
await copyFile(xaiTemplateSource, xaiTemplateTarget);
|
|
6331
|
+
logger.info("Created .automatosx/providers/grok.yaml.template (X.AI Grok)", { path: xaiTemplateTarget });
|
|
6332
|
+
}
|
|
6333
|
+
const zaiTemplateSource = join(templatesDir, "grok-zai.yaml.template");
|
|
6334
|
+
const zaiTemplateTarget = join(providersDir, "grok-zai.yaml.template");
|
|
6335
|
+
const zaiExists = await checkExists2(zaiTemplateTarget);
|
|
6336
|
+
if (!zaiExists) {
|
|
6337
|
+
await copyFile(zaiTemplateSource, zaiTemplateTarget);
|
|
6338
|
+
logger.info("Created .automatosx/providers/grok-zai.yaml.template (Z.AI GLM 4.6)", { path: zaiTemplateTarget });
|
|
6339
|
+
}
|
|
6340
|
+
const readmeSource = join(templatesDir, "README.md");
|
|
6341
|
+
const readmeTarget = join(providersDir, "README.md");
|
|
6342
|
+
const readmeExists = await checkExists2(readmeTarget);
|
|
6343
|
+
if (!readmeExists) {
|
|
6344
|
+
await copyFile(readmeSource, readmeTarget);
|
|
6345
|
+
logger.info("Created .automatosx/providers/README.md", { path: readmeTarget });
|
|
6346
|
+
}
|
|
6347
|
+
} catch (error) {
|
|
6348
|
+
logger.warn("Failed to copy Grok provider YAML templates", {
|
|
6349
|
+
error: error.message
|
|
6350
|
+
});
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
6353
|
+
async function setupProjectGrokMd(projectDir, packageRoot, force) {
|
|
6354
|
+
const grokMdPath = join(projectDir, "GROK.md");
|
|
6355
|
+
const templatePath = join(packageRoot, "examples/grok/GROK_INTEGRATION.md");
|
|
6356
|
+
try {
|
|
6357
|
+
const { readFile: readFile14 } = await import('fs/promises');
|
|
6358
|
+
const template = await readFile14(templatePath, "utf-8");
|
|
6359
|
+
const exists = await checkExists2(grokMdPath);
|
|
6360
|
+
if (!exists) {
|
|
6361
|
+
const content = [
|
|
6362
|
+
"# GROK.md",
|
|
6363
|
+
"",
|
|
6364
|
+
"This file provides guidance for Grok CLI integration with AutomatosX.",
|
|
6365
|
+
"",
|
|
6366
|
+
"---",
|
|
6367
|
+
"",
|
|
6368
|
+
template
|
|
6369
|
+
].join("\n");
|
|
6370
|
+
await writeFile(grokMdPath, content, "utf-8");
|
|
6371
|
+
logger.info("Created GROK.md with AutomatosX integration", { path: grokMdPath });
|
|
6372
|
+
} else {
|
|
6373
|
+
const existingContent = await readFile14(grokMdPath, "utf-8");
|
|
6374
|
+
if (existingContent.includes("# Grok CLI Integration")) {
|
|
6375
|
+
if (!force) {
|
|
6376
|
+
logger.info("GROK.md already contains AutomatosX integration", { path: grokMdPath });
|
|
6377
|
+
return;
|
|
6378
|
+
}
|
|
6379
|
+
const updatedContent = replaceAutomatosXSection(existingContent, template);
|
|
6380
|
+
await writeFile(grokMdPath, updatedContent, "utf-8");
|
|
6381
|
+
logger.info("Updated AutomatosX integration in GROK.md", { path: grokMdPath });
|
|
6382
|
+
} else {
|
|
6383
|
+
const updatedContent = [
|
|
6384
|
+
existingContent.trimEnd(),
|
|
6385
|
+
"",
|
|
6386
|
+
"---",
|
|
6387
|
+
"",
|
|
6388
|
+
template
|
|
6389
|
+
].join("\n");
|
|
6390
|
+
await writeFile(grokMdPath, updatedContent, "utf-8");
|
|
6391
|
+
logger.info("Added AutomatosX integration to existing GROK.md", { path: grokMdPath });
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
} catch (error) {
|
|
6395
|
+
logger.warn("Failed to setup GROK.md", {
|
|
6396
|
+
error: error.message,
|
|
6397
|
+
path: grokMdPath
|
|
6398
|
+
});
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
5832
6401
|
async function setupProjectAgentsMd(projectDir, packageRoot, force) {
|
|
5833
6402
|
const agentsMdPath = join(projectDir, "AGENTS.md");
|
|
5834
6403
|
const templatePath = join(packageRoot, "examples/agents/AGENTS_INTEGRATION.md");
|
|
@@ -6263,8 +6832,8 @@ var initCommand = {
|
|
|
6263
6832
|
console.log(chalk5.white(" Using backend agent to analyze your project..."));
|
|
6264
6833
|
console.log(chalk5.dim(" This will take 1-2 minutes\n"));
|
|
6265
6834
|
const { spawn: spawn5 } = await import('child_process');
|
|
6266
|
-
const { promisify:
|
|
6267
|
-
const execFile =
|
|
6835
|
+
const { promisify: promisify5 } = await import('util');
|
|
6836
|
+
const execFile = promisify5((await import('child_process')).execFile);
|
|
6268
6837
|
try {
|
|
6269
6838
|
const analysisTask = `Analyze this project and create a comprehensive ax.md file:
|
|
6270
6839
|
|
|
@@ -8480,8 +9049,6 @@ var Router = class {
|
|
|
8480
9049
|
providers;
|
|
8481
9050
|
fallbackEnabled;
|
|
8482
9051
|
healthCheckInterval;
|
|
8483
|
-
penalizedProviders;
|
|
8484
|
-
// provider name -> penalty expiry timestamp
|
|
8485
9052
|
providerCooldownMs;
|
|
8486
9053
|
cache;
|
|
8487
9054
|
routerConfig;
|
|
@@ -8500,14 +9067,15 @@ var Router = class {
|
|
|
8500
9067
|
tracer;
|
|
8501
9068
|
// v8.3.0: Circuit breaker for simple failover
|
|
8502
9069
|
circuitState = /* @__PURE__ */ new Map();
|
|
9070
|
+
circuitBreakerThreshold;
|
|
8503
9071
|
constructor(config) {
|
|
8504
9072
|
this.routerConfig = config;
|
|
8505
9073
|
this.providers = [...config.providers].sort((a, b) => {
|
|
8506
9074
|
return a.priority - b.priority;
|
|
8507
9075
|
});
|
|
8508
9076
|
this.fallbackEnabled = config.fallbackEnabled;
|
|
8509
|
-
this.penalizedProviders = /* @__PURE__ */ new Map();
|
|
8510
9077
|
this.providerCooldownMs = config.providerCooldownMs ?? 3e4;
|
|
9078
|
+
this.circuitBreakerThreshold = config.circuitBreakerThreshold ?? 3;
|
|
8511
9079
|
this.cache = config.cache;
|
|
8512
9080
|
const limitManager = getProviderLimitManager();
|
|
8513
9081
|
void limitManager.initialize().catch((err) => {
|
|
@@ -8643,8 +9211,8 @@ var Router = class {
|
|
|
8643
9211
|
const providerNames = providersToTry.map((p) => p.name);
|
|
8644
9212
|
const healthMultipliers = /* @__PURE__ */ new Map();
|
|
8645
9213
|
for (const provider of providersToTry) {
|
|
8646
|
-
const
|
|
8647
|
-
healthMultipliers.set(provider.name,
|
|
9214
|
+
const isCircuitOpen = this.isCircuitOpen(provider.name);
|
|
9215
|
+
healthMultipliers.set(provider.name, isCircuitOpen ? 0.5 : 1);
|
|
8648
9216
|
}
|
|
8649
9217
|
const scores = await getProviderMetricsTracker().getAllScores(
|
|
8650
9218
|
providerNames,
|
|
@@ -8736,21 +9304,20 @@ var Router = class {
|
|
|
8736
9304
|
modelParams
|
|
8737
9305
|
);
|
|
8738
9306
|
}
|
|
8739
|
-
this.
|
|
9307
|
+
this.recordSuccess(provider.name);
|
|
8740
9308
|
if (this.tracer) {
|
|
8741
|
-
const estimatedCost = this.estimateCost(provider.name, response.tokensUsed);
|
|
8742
9309
|
this.tracer.logExecution(
|
|
8743
9310
|
provider.name,
|
|
8744
9311
|
true,
|
|
8745
9312
|
// success
|
|
8746
9313
|
response.latencyMs,
|
|
8747
|
-
|
|
9314
|
+
0,
|
|
9315
|
+
// v8.3.0: No cost tracking in CLI-only mode
|
|
8748
9316
|
response.tokensUsed
|
|
8749
9317
|
);
|
|
8750
9318
|
}
|
|
8751
9319
|
if (this.useMultiFactorRouting) {
|
|
8752
9320
|
const metricsTracker = getProviderMetricsTracker();
|
|
8753
|
-
const estimatedCost = this.estimateCost(provider.name, response.tokensUsed);
|
|
8754
9321
|
void metricsTracker.recordRequest(
|
|
8755
9322
|
provider.name,
|
|
8756
9323
|
response.latencyMs,
|
|
@@ -8762,7 +9329,8 @@ var Router = class {
|
|
|
8762
9329
|
completion: response.tokensUsed.completion,
|
|
8763
9330
|
total: response.tokensUsed.total
|
|
8764
9331
|
},
|
|
8765
|
-
|
|
9332
|
+
0,
|
|
9333
|
+
// v8.3.0: No cost tracking in CLI-only mode
|
|
8766
9334
|
response.model
|
|
8767
9335
|
).catch((error) => {
|
|
8768
9336
|
logger.warn("Metrics recording failed (non-critical)", {
|
|
@@ -8820,9 +9388,7 @@ var Router = class {
|
|
|
8820
9388
|
error: lastError.message,
|
|
8821
9389
|
willFallback: this.fallbackEnabled && attemptNumber < availableProviders.length
|
|
8822
9390
|
});
|
|
8823
|
-
|
|
8824
|
-
this.penalizedProviders.set(provider.name, penaltyExpiry);
|
|
8825
|
-
logger.debug(`Provider ${provider.name} penalized until ${new Date(penaltyExpiry).toISOString()}`);
|
|
9391
|
+
this.recordFailure(provider.name);
|
|
8826
9392
|
if (this.tracer) {
|
|
8827
9393
|
const nextProvider = providersToTry[attemptNumber]?.name;
|
|
8828
9394
|
this.tracer.logDegradation(
|
|
@@ -8910,17 +9476,12 @@ var Router = class {
|
|
|
8910
9476
|
/**
|
|
8911
9477
|
* Get available providers sorted by priority
|
|
8912
9478
|
* v5.7.0: Enhanced with provider limit detection
|
|
8913
|
-
*
|
|
9479
|
+
* v8.3.0: Uses circuit breaker state instead of separate penalty tracking
|
|
9480
|
+
* Filters out providers with open circuit breakers and limited providers (quota exceeded)
|
|
8914
9481
|
*/
|
|
8915
9482
|
async getAvailableProviders() {
|
|
8916
9483
|
const now = Date.now();
|
|
8917
9484
|
const limitManager = getProviderLimitManager();
|
|
8918
|
-
for (const [providerName, expiryTime] of this.penalizedProviders.entries()) {
|
|
8919
|
-
if (now >= expiryTime) {
|
|
8920
|
-
this.penalizedProviders.delete(providerName);
|
|
8921
|
-
logger.debug(`Provider ${providerName} penalty expired`);
|
|
8922
|
-
}
|
|
8923
|
-
}
|
|
8924
9485
|
const checks = this.providers.map(async (provider) => {
|
|
8925
9486
|
try {
|
|
8926
9487
|
const limitCheck = limitManager.isProviderLimited(provider.name, now);
|
|
@@ -8930,10 +9491,8 @@ var Router = class {
|
|
|
8930
9491
|
logger.debug(`Skipping limited provider ${provider.name} (resets in ${remainingHours}h)`);
|
|
8931
9492
|
return null;
|
|
8932
9493
|
}
|
|
8933
|
-
if (this.
|
|
8934
|
-
|
|
8935
|
-
const remainingMs = expiryTime - now;
|
|
8936
|
-
logger.debug(`Skipping penalized provider ${provider.name} (${Math.ceil(remainingMs / 1e3)}s remaining)`);
|
|
9494
|
+
if (this.isCircuitOpen(provider.name)) {
|
|
9495
|
+
logger.debug(`Skipping provider ${provider.name} (circuit breaker open)`);
|
|
8937
9496
|
return null;
|
|
8938
9497
|
}
|
|
8939
9498
|
const isAvailable = await provider.isAvailable();
|
|
@@ -9080,7 +9639,7 @@ var Router = class {
|
|
|
9080
9639
|
clearInterval(this.healthCheckInterval);
|
|
9081
9640
|
this.healthCheckInterval = void 0;
|
|
9082
9641
|
}
|
|
9083
|
-
this.
|
|
9642
|
+
this.circuitState.clear();
|
|
9084
9643
|
if (this.tracer) {
|
|
9085
9644
|
this.tracer.close();
|
|
9086
9645
|
logger.debug("Router trace logger closed");
|
|
@@ -9114,10 +9673,49 @@ var Router = class {
|
|
|
9114
9673
|
};
|
|
9115
9674
|
}
|
|
9116
9675
|
/**
|
|
9117
|
-
* v8.3.0:
|
|
9676
|
+
* v8.3.0: Check if circuit breaker is open for a provider
|
|
9118
9677
|
*/
|
|
9119
|
-
|
|
9120
|
-
|
|
9678
|
+
isCircuitOpen(providerName) {
|
|
9679
|
+
const state = this.circuitState.get(providerName);
|
|
9680
|
+
if (!state || !state.isOpen) return false;
|
|
9681
|
+
const cooldownMs = this.providerCooldownMs || 6e4;
|
|
9682
|
+
if (Date.now() - state.lastFailure > cooldownMs) {
|
|
9683
|
+
state.isOpen = false;
|
|
9684
|
+
state.failures = 0;
|
|
9685
|
+
this.circuitState.set(providerName, state);
|
|
9686
|
+
logger.info(`Circuit breaker closed for ${providerName} after cooldown`);
|
|
9687
|
+
return false;
|
|
9688
|
+
}
|
|
9689
|
+
return true;
|
|
9690
|
+
}
|
|
9691
|
+
/**
|
|
9692
|
+
* v8.3.0: Record provider success - resets circuit breaker
|
|
9693
|
+
*/
|
|
9694
|
+
recordSuccess(providerName) {
|
|
9695
|
+
const state = this.circuitState.get(providerName);
|
|
9696
|
+
if (state) {
|
|
9697
|
+
state.failures = 0;
|
|
9698
|
+
state.isOpen = false;
|
|
9699
|
+
this.circuitState.set(providerName, state);
|
|
9700
|
+
logger.debug(`Circuit breaker reset for ${providerName} after success`);
|
|
9701
|
+
}
|
|
9702
|
+
}
|
|
9703
|
+
/**
|
|
9704
|
+
* v8.3.0: Record provider failure - opens circuit after threshold
|
|
9705
|
+
*/
|
|
9706
|
+
recordFailure(providerName) {
|
|
9707
|
+
const state = this.circuitState.get(providerName) || {
|
|
9708
|
+
failures: 0,
|
|
9709
|
+
lastFailure: 0,
|
|
9710
|
+
isOpen: false
|
|
9711
|
+
};
|
|
9712
|
+
state.failures++;
|
|
9713
|
+
state.lastFailure = Date.now();
|
|
9714
|
+
if (state.failures >= this.circuitBreakerThreshold) {
|
|
9715
|
+
state.isOpen = true;
|
|
9716
|
+
logger.warn(`Circuit breaker opened for ${providerName} after ${state.failures} failures (threshold: ${this.circuitBreakerThreshold})`);
|
|
9717
|
+
}
|
|
9718
|
+
this.circuitState.set(providerName, state);
|
|
9121
9719
|
}
|
|
9122
9720
|
};
|
|
9123
9721
|
|
|
@@ -12474,6 +13072,155 @@ var AgentNotFoundError = class extends Error {
|
|
|
12474
13072
|
|
|
12475
13073
|
// src/agents/profile-loader.ts
|
|
12476
13074
|
init_logger();
|
|
13075
|
+
|
|
13076
|
+
// src/agents/agent-schemas.ts
|
|
13077
|
+
init_esm_shims();
|
|
13078
|
+
var stageSchema = z.object({
|
|
13079
|
+
name: z.string().min(1),
|
|
13080
|
+
description: z.string().min(1),
|
|
13081
|
+
key_questions: z.array(z.string()).optional(),
|
|
13082
|
+
outputs: z.array(z.string()).optional(),
|
|
13083
|
+
// Deprecated but still accepted for backward compatibility
|
|
13084
|
+
model: z.string().optional(),
|
|
13085
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
13086
|
+
// Advanced stage features
|
|
13087
|
+
dependencies: z.array(z.string()).optional(),
|
|
13088
|
+
condition: z.string().optional(),
|
|
13089
|
+
parallel: z.boolean().optional(),
|
|
13090
|
+
streaming: z.boolean().optional(),
|
|
13091
|
+
saveToMemory: z.boolean().optional(),
|
|
13092
|
+
// Checkpoint and retry
|
|
13093
|
+
checkpoint: z.boolean().optional(),
|
|
13094
|
+
timeout: z.number().int().positive().optional(),
|
|
13095
|
+
maxRetries: z.number().int().nonnegative().max(10).optional(),
|
|
13096
|
+
retryDelay: z.number().int().nonnegative().optional()
|
|
13097
|
+
}).describe("Agent workflow stage");
|
|
13098
|
+
var personalitySchema = z.object({
|
|
13099
|
+
traits: z.array(z.string()).optional(),
|
|
13100
|
+
catchphrase: z.string().optional(),
|
|
13101
|
+
communication_style: z.string().optional(),
|
|
13102
|
+
decision_making: z.string().optional()
|
|
13103
|
+
}).describe("Agent personality");
|
|
13104
|
+
var abilitySelectionSchema = z.object({
|
|
13105
|
+
core: z.array(z.string()).optional(),
|
|
13106
|
+
taskBased: z.record(z.string(), z.array(z.string())).optional(),
|
|
13107
|
+
loadAll: z.boolean().optional()
|
|
13108
|
+
}).describe("Ability selection strategy");
|
|
13109
|
+
var redirectRuleSchema = z.object({
|
|
13110
|
+
phrase: z.string().regex(/.+/, "Redirect phrase must be a valid regex pattern"),
|
|
13111
|
+
suggest: z.string().min(1)
|
|
13112
|
+
}).describe("Agent redirect rule");
|
|
13113
|
+
var selectionMetadataSchema = z.object({
|
|
13114
|
+
primaryIntents: z.array(z.string()).optional(),
|
|
13115
|
+
secondarySignals: z.array(z.string()).optional(),
|
|
13116
|
+
negativeIntents: z.array(z.string()).optional(),
|
|
13117
|
+
redirectWhen: z.array(redirectRuleSchema).optional(),
|
|
13118
|
+
keywords: z.array(z.string()).optional(),
|
|
13119
|
+
antiKeywords: z.array(z.string()).optional()
|
|
13120
|
+
}).describe("Agent selection metadata");
|
|
13121
|
+
var agentProfileSchema = z.object({
|
|
13122
|
+
// Basic information
|
|
13123
|
+
name: z.string().min(1).max(50).regex(/^[a-zA-Z0-9_-]+$/, "Agent name must be alphanumeric with dash/underscore only").optional(),
|
|
13124
|
+
// Optional - uses filename if not provided
|
|
13125
|
+
displayName: z.string().max(100).optional().or(z.literal("")).transform((val) => val === "" ? void 0 : val),
|
|
13126
|
+
version: z.string().regex(/^\d+\.\d+\.\d+$/, "Version must be semver format").optional(),
|
|
13127
|
+
description: z.string().min(1),
|
|
13128
|
+
// Role and expertise
|
|
13129
|
+
role: z.string().min(1).optional(),
|
|
13130
|
+
expertise: z.array(z.string()).min(1).optional(),
|
|
13131
|
+
capabilities: z.array(z.string()).optional(),
|
|
13132
|
+
// System prompt (required by profile-loader validateProfile, but optional here for flexibility)
|
|
13133
|
+
systemPrompt: z.string().min(1).optional(),
|
|
13134
|
+
// Workflow
|
|
13135
|
+
workflow: z.array(stageSchema).min(1).optional(),
|
|
13136
|
+
// Personality
|
|
13137
|
+
personality: personalitySchema.optional(),
|
|
13138
|
+
// Abilities - accepts both array (legacy) and object (new) formats
|
|
13139
|
+
abilities: z.union([
|
|
13140
|
+
z.array(z.string()),
|
|
13141
|
+
// Legacy format: ['ability1', 'ability2']
|
|
13142
|
+
abilitySelectionSchema
|
|
13143
|
+
// New format: { core: [...], taskBased: {...}, loadAll: true }
|
|
13144
|
+
]).optional(),
|
|
13145
|
+
// Ability selection strategy (v4.5.8+)
|
|
13146
|
+
abilitySelection: abilitySelectionSchema.optional(),
|
|
13147
|
+
// Thinking patterns
|
|
13148
|
+
thinking_patterns: z.array(z.string()).optional(),
|
|
13149
|
+
// Dependencies
|
|
13150
|
+
dependencies: z.array(z.string()).optional(),
|
|
13151
|
+
// Parallel execution
|
|
13152
|
+
parallel: z.boolean().optional(),
|
|
13153
|
+
// Model parameters (deprecated but still accepted)
|
|
13154
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
13155
|
+
maxTokens: z.number().int().positive().optional(),
|
|
13156
|
+
// Orchestration (v4.7.0+)
|
|
13157
|
+
orchestration: z.object({
|
|
13158
|
+
maxDelegationDepth: z.number().int().nonnegative().optional(),
|
|
13159
|
+
canReadWorkspaces: z.array(z.string()).optional(),
|
|
13160
|
+
canWriteToShared: z.boolean().optional()
|
|
13161
|
+
}).optional(),
|
|
13162
|
+
// Selection metadata (v5.7.0+)
|
|
13163
|
+
selectionMetadata: selectionMetadataSchema.optional(),
|
|
13164
|
+
// Team and collaboration
|
|
13165
|
+
team: z.string().optional(),
|
|
13166
|
+
collaboratesWith: z.array(z.string()).optional(),
|
|
13167
|
+
// Deprecated fields (accepted but ignored)
|
|
13168
|
+
model: z.string().optional(),
|
|
13169
|
+
provider: z.string().optional(),
|
|
13170
|
+
fallbackProvider: z.string().optional(),
|
|
13171
|
+
// Additional metadata
|
|
13172
|
+
tags: z.array(z.string()).optional(),
|
|
13173
|
+
priority: z.number().int().min(1).max(100).optional(),
|
|
13174
|
+
enabled: z.boolean().default(true),
|
|
13175
|
+
// Custom metadata
|
|
13176
|
+
metadata: z.record(z.string(), z.any()).optional()
|
|
13177
|
+
}).describe("Agent profile");
|
|
13178
|
+
z.object({
|
|
13179
|
+
memory: z.boolean().optional(),
|
|
13180
|
+
saveMemory: z.boolean().optional(),
|
|
13181
|
+
session: z.string().optional(),
|
|
13182
|
+
sessionCreate: z.boolean().optional(),
|
|
13183
|
+
provider: z.string().optional(),
|
|
13184
|
+
format: z.enum(["text", "json"]).optional(),
|
|
13185
|
+
verbose: z.boolean().optional(),
|
|
13186
|
+
debug: z.boolean().optional(),
|
|
13187
|
+
quiet: z.boolean().optional(),
|
|
13188
|
+
config: z.string().optional(),
|
|
13189
|
+
parallel: z.boolean().optional(),
|
|
13190
|
+
streaming: z.boolean().optional(),
|
|
13191
|
+
resumable: z.boolean().optional(),
|
|
13192
|
+
checkpoint: z.boolean().optional()
|
|
13193
|
+
}).describe("Agent run command options");
|
|
13194
|
+
z.object({
|
|
13195
|
+
template: z.string().optional(),
|
|
13196
|
+
interactive: z.boolean().optional(),
|
|
13197
|
+
force: z.boolean().optional(),
|
|
13198
|
+
description: z.string().optional(),
|
|
13199
|
+
role: z.string().optional(),
|
|
13200
|
+
expertise: z.array(z.string()).optional(),
|
|
13201
|
+
displayName: z.string().optional()
|
|
13202
|
+
}).describe("Agent create command options");
|
|
13203
|
+
z.object({
|
|
13204
|
+
limit: z.number().int().positive().max(1e4).optional(),
|
|
13205
|
+
agent: z.string().optional(),
|
|
13206
|
+
session: z.string().optional(),
|
|
13207
|
+
format: z.enum(["text", "json"]).optional(),
|
|
13208
|
+
before: z.string().optional(),
|
|
13209
|
+
// ISO date string
|
|
13210
|
+
after: z.string().optional()
|
|
13211
|
+
// ISO date string
|
|
13212
|
+
}).describe("Memory search options");
|
|
13213
|
+
z.object({
|
|
13214
|
+
agents: z.array(z.string()).min(1),
|
|
13215
|
+
description: z.string().optional(),
|
|
13216
|
+
metadata: z.record(z.string(), z.any()).optional()
|
|
13217
|
+
}).describe("Session create options");
|
|
13218
|
+
function safeValidateAgentProfile(profile) {
|
|
13219
|
+
return agentProfileSchema.safeParse(profile);
|
|
13220
|
+
}
|
|
13221
|
+
agentProfileSchema.partial();
|
|
13222
|
+
|
|
13223
|
+
// src/agents/profile-loader.ts
|
|
12477
13224
|
var __filename3 = fileURLToPath(import.meta.url);
|
|
12478
13225
|
var __dirname4 = dirname(__filename3);
|
|
12479
13226
|
function getPackageRoot2() {
|
|
@@ -13004,6 +13751,25 @@ var ProfileLoader = class {
|
|
|
13004
13751
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
13005
13752
|
throw new AgentValidationError(`Invalid profile data for ${name}: expected object, got ${typeof data}`);
|
|
13006
13753
|
}
|
|
13754
|
+
if (data.name && typeof data.name === "string") {
|
|
13755
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(data.name)) {
|
|
13756
|
+
if (!data.displayName) {
|
|
13757
|
+
data.displayName = data.name;
|
|
13758
|
+
}
|
|
13759
|
+
data.name = name;
|
|
13760
|
+
}
|
|
13761
|
+
} else if (!data.name) {
|
|
13762
|
+
data.name = name;
|
|
13763
|
+
}
|
|
13764
|
+
const validationResult = safeValidateAgentProfile(data);
|
|
13765
|
+
if (!validationResult.success) {
|
|
13766
|
+
const validationErrors = validationResult.error.issues.map(
|
|
13767
|
+
(e) => `${e.path.join(".")}: ${e.message}`
|
|
13768
|
+
).join("; ");
|
|
13769
|
+
throw new AgentValidationError(
|
|
13770
|
+
`Invalid profile for ${name}: ${validationErrors}`
|
|
13771
|
+
);
|
|
13772
|
+
}
|
|
13007
13773
|
let teamConfig;
|
|
13008
13774
|
if (data.team && this.teamManager) {
|
|
13009
13775
|
try {
|
|
@@ -21340,6 +22106,55 @@ init_esm_shims();
|
|
|
21340
22106
|
init_path_resolver();
|
|
21341
22107
|
init_claude_provider();
|
|
21342
22108
|
init_gemini_provider();
|
|
22109
|
+
|
|
22110
|
+
// src/providers/grok-provider.ts
|
|
22111
|
+
init_esm_shims();
|
|
22112
|
+
init_base_provider();
|
|
22113
|
+
init_logger();
|
|
22114
|
+
var GrokProvider = class extends BaseProvider {
|
|
22115
|
+
constructor(config) {
|
|
22116
|
+
super(config);
|
|
22117
|
+
logger.debug("GrokProvider initialized", {
|
|
22118
|
+
name: config.name,
|
|
22119
|
+
enabled: config.enabled,
|
|
22120
|
+
priority: config.priority,
|
|
22121
|
+
command: config.command || "grok"
|
|
22122
|
+
});
|
|
22123
|
+
}
|
|
22124
|
+
/**
|
|
22125
|
+
* Get the CLI command name for Grok
|
|
22126
|
+
* Returns 'grok' which can point to either:
|
|
22127
|
+
* - Z.AI GLM 4.6 CLI
|
|
22128
|
+
* - X.AI Official Grok CLI
|
|
22129
|
+
*/
|
|
22130
|
+
getCLICommand() {
|
|
22131
|
+
return this.config.command || "grok";
|
|
22132
|
+
}
|
|
22133
|
+
/**
|
|
22134
|
+
* Get mock response for testing
|
|
22135
|
+
* Returns a realistic Grok-style response
|
|
22136
|
+
*/
|
|
22137
|
+
getMockResponse() {
|
|
22138
|
+
return `[Mock Grok Response]
|
|
22139
|
+
|
|
22140
|
+
This is a mock response from Grok for testing purposes.
|
|
22141
|
+
|
|
22142
|
+
Grok is designed to provide helpful, accurate, and witty responses to your queries. This mock response simulates the typical output you would receive from the Grok CLI.
|
|
22143
|
+
|
|
22144
|
+
Key features:
|
|
22145
|
+
- Direct and informative answers
|
|
22146
|
+
- Occasional humor and personality
|
|
22147
|
+
- Factual accuracy
|
|
22148
|
+
- Clear formatting
|
|
22149
|
+
|
|
22150
|
+
For actual Grok responses, ensure:
|
|
22151
|
+
1. Grok CLI is installed (grok --version)
|
|
22152
|
+
2. API credentials are configured (if using X.AI)
|
|
22153
|
+
3. AUTOMATOSX_MOCK_PROVIDERS is not set to 'true'`;
|
|
22154
|
+
}
|
|
22155
|
+
};
|
|
22156
|
+
|
|
22157
|
+
// src/cli/commands/status.ts
|
|
21343
22158
|
init_openai_provider_factory();
|
|
21344
22159
|
init_logger();
|
|
21345
22160
|
var VERSION = getVersion();
|
|
@@ -21426,6 +22241,15 @@ var statusCommand3 = {
|
|
|
21426
22241
|
);
|
|
21427
22242
|
providers.push(provider);
|
|
21428
22243
|
}
|
|
22244
|
+
if (providerConfigs["grok"]?.enabled) {
|
|
22245
|
+
providers.push(new GrokProvider({
|
|
22246
|
+
name: "grok",
|
|
22247
|
+
enabled: true,
|
|
22248
|
+
priority: providerConfigs["grok"].priority,
|
|
22249
|
+
timeout: providerConfigs["grok"].timeout,
|
|
22250
|
+
command: providerConfigs["grok"].command
|
|
22251
|
+
}));
|
|
22252
|
+
}
|
|
21429
22253
|
const providerHealth = await Promise.all(
|
|
21430
22254
|
providers.map(async (p) => ({
|
|
21431
22255
|
name: p.name,
|
|
@@ -21776,7 +22600,7 @@ function formatUptime(seconds) {
|
|
|
21776
22600
|
// src/cli/commands/update.ts
|
|
21777
22601
|
init_esm_shims();
|
|
21778
22602
|
init_logger();
|
|
21779
|
-
var
|
|
22603
|
+
var execAsync2 = promisify(exec);
|
|
21780
22604
|
var updateCommand = {
|
|
21781
22605
|
command: "update",
|
|
21782
22606
|
describe: "Check for updates and upgrade AutomatosX to the latest version",
|
|
@@ -21855,7 +22679,7 @@ var updateCommand = {
|
|
|
21855
22679
|
};
|
|
21856
22680
|
async function getCurrentVersion() {
|
|
21857
22681
|
try {
|
|
21858
|
-
const { stdout } = await
|
|
22682
|
+
const { stdout } = await execAsync2("npm list -g @defai.digital/automatosx --depth=0 --json");
|
|
21859
22683
|
const result = JSON.parse(stdout);
|
|
21860
22684
|
return result.dependencies["@defai.digital/automatosx"]?.version || "unknown";
|
|
21861
22685
|
} catch (error) {
|
|
@@ -21871,7 +22695,7 @@ async function getCurrentVersion() {
|
|
|
21871
22695
|
}
|
|
21872
22696
|
}
|
|
21873
22697
|
async function getLatestVersion() {
|
|
21874
|
-
const { stdout } = await
|
|
22698
|
+
const { stdout } = await execAsync2("npm view @defai.digital/automatosx version");
|
|
21875
22699
|
return stdout.trim();
|
|
21876
22700
|
}
|
|
21877
22701
|
function isNewer(a, b) {
|
|
@@ -21886,7 +22710,7 @@ function isNewer(a, b) {
|
|
|
21886
22710
|
async function showChangelog(from, to) {
|
|
21887
22711
|
try {
|
|
21888
22712
|
console.log(chalk5.cyan("What's new:\n"));
|
|
21889
|
-
const { stdout } = await
|
|
22713
|
+
const { stdout } = await execAsync2(
|
|
21890
22714
|
`curl -s https://api.github.com/repos/defai-digital/automatosx/releases/tags/v${to}`
|
|
21891
22715
|
);
|
|
21892
22716
|
const release = JSON.parse(stdout);
|
|
@@ -21908,7 +22732,7 @@ async function showChangelog(from, to) {
|
|
|
21908
22732
|
}
|
|
21909
22733
|
async function installUpdate(version) {
|
|
21910
22734
|
try {
|
|
21911
|
-
const { stdout, stderr } = await
|
|
22735
|
+
const { stdout, stderr } = await execAsync2(
|
|
21912
22736
|
`npm install -g @defai.digital/automatosx@${version}`,
|
|
21913
22737
|
{ maxBuffer: 10 * 1024 * 1024 }
|
|
21914
22738
|
);
|
|
@@ -23900,11 +24724,11 @@ function expand_(str, isTop) {
|
|
|
23900
24724
|
if (pad) {
|
|
23901
24725
|
const need = width - c.length;
|
|
23902
24726
|
if (need > 0) {
|
|
23903
|
-
const
|
|
24727
|
+
const z4 = new Array(need + 1).join("0");
|
|
23904
24728
|
if (i < 0) {
|
|
23905
|
-
c = "-" +
|
|
24729
|
+
c = "-" + z4 + c.slice(1);
|
|
23906
24730
|
} else {
|
|
23907
|
-
c =
|
|
24731
|
+
c = z4 + c;
|
|
23908
24732
|
}
|
|
23909
24733
|
}
|
|
23910
24734
|
}
|
|
@@ -40600,9 +41424,9 @@ var doctorCommand2 = {
|
|
|
40600
41424
|
describe: "Run diagnostic checks and validate system setup",
|
|
40601
41425
|
builder: (yargs2) => {
|
|
40602
41426
|
return yargs2.positional("provider", {
|
|
40603
|
-
describe: "Check specific provider (openai, gemini, claude) or all if omitted",
|
|
41427
|
+
describe: "Check specific provider (openai, gemini, claude, grok) or all if omitted",
|
|
40604
41428
|
type: "string",
|
|
40605
|
-
choices: ["openai", "gemini", "claude"]
|
|
41429
|
+
choices: ["openai", "gemini", "claude", "grok"]
|
|
40606
41430
|
}).option("verbose", {
|
|
40607
41431
|
describe: "Show detailed diagnostic information",
|
|
40608
41432
|
type: "boolean",
|
|
@@ -40638,7 +41462,7 @@ var doctorCommand2 = {
|
|
|
40638
41462
|
details: error.message
|
|
40639
41463
|
});
|
|
40640
41464
|
}
|
|
40641
|
-
const providersToCheck = argv.provider ? [argv.provider] : ["openai", "gemini", "claude"];
|
|
41465
|
+
const providersToCheck = argv.provider ? [argv.provider] : ["openai", "gemini", "claude", "grok"];
|
|
40642
41466
|
const verbose = argv.verbose ?? false;
|
|
40643
41467
|
for (const provider of providersToCheck) {
|
|
40644
41468
|
if (config && !config.providers[provider]?.enabled) {
|
|
@@ -40655,6 +41479,8 @@ ${getProviderEmoji(provider)} ${capitalize(provider)} Provider`));
|
|
|
40655
41479
|
results.push(...await checkGeminiProvider(verbose));
|
|
40656
41480
|
} else if (provider === "claude") {
|
|
40657
41481
|
results.push(...await checkClaudeProvider(verbose));
|
|
41482
|
+
} else if (provider === "grok") {
|
|
41483
|
+
results.push(...await checkGrokProvider(verbose));
|
|
40658
41484
|
}
|
|
40659
41485
|
}
|
|
40660
41486
|
console.log(chalk5.bold("\n\u{1F4C1} File System"));
|
|
@@ -40702,17 +41528,6 @@ async function checkOpenAIProvider(verbose) {
|
|
|
40702
41528
|
details: verbose ? authCheck.details : void 0
|
|
40703
41529
|
});
|
|
40704
41530
|
}
|
|
40705
|
-
if (cliCheck.success) {
|
|
40706
|
-
const connCheck = await checkAPIConnectivity2("https://api.openai.com/v1/models");
|
|
40707
|
-
results.push({
|
|
40708
|
-
name: "API Connectivity",
|
|
40709
|
-
category: "OpenAI",
|
|
40710
|
-
passed: connCheck.success,
|
|
40711
|
-
message: connCheck.message,
|
|
40712
|
-
fix: connCheck.success ? void 0 : "Check firewall/proxy settings\n OR: export AUTOMATOSX_CLI_ONLY=true (for CLI-only mode)",
|
|
40713
|
-
details: verbose ? connCheck.details : void 0
|
|
40714
|
-
});
|
|
40715
|
-
}
|
|
40716
41531
|
results.forEach((r) => displayCheck(r));
|
|
40717
41532
|
return results;
|
|
40718
41533
|
}
|
|
@@ -40728,14 +41543,14 @@ async function checkGeminiProvider(verbose) {
|
|
|
40728
41543
|
details: verbose ? cliCheck.error : void 0
|
|
40729
41544
|
});
|
|
40730
41545
|
if (cliCheck.success) {
|
|
40731
|
-
const
|
|
41546
|
+
const helpCheck = await checkCommand("gemini", "--help");
|
|
40732
41547
|
results.push({
|
|
40733
|
-
name: "
|
|
41548
|
+
name: "CLI Ready",
|
|
40734
41549
|
category: "Gemini",
|
|
40735
|
-
passed:
|
|
40736
|
-
message:
|
|
40737
|
-
fix:
|
|
40738
|
-
details: verbose ?
|
|
41550
|
+
passed: helpCheck.success,
|
|
41551
|
+
message: helpCheck.success ? "CLI is functional" : "CLI not responding",
|
|
41552
|
+
fix: helpCheck.success ? void 0 : "Check Gemini CLI installation: npm install -g @google/generative-ai-cli",
|
|
41553
|
+
details: verbose ? helpCheck.success ? "Gemini CLI uses API keys from environment or config" : helpCheck.error : void 0
|
|
40739
41554
|
});
|
|
40740
41555
|
}
|
|
40741
41556
|
results.forEach((r) => displayCheck(r));
|
|
@@ -40753,14 +41568,39 @@ async function checkClaudeProvider(verbose) {
|
|
|
40753
41568
|
details: verbose ? cliCheck.error : void 0
|
|
40754
41569
|
});
|
|
40755
41570
|
if (cliCheck.success) {
|
|
40756
|
-
const
|
|
41571
|
+
const helpCheck = await checkCommand("claude", "--help");
|
|
40757
41572
|
results.push({
|
|
40758
|
-
name: "
|
|
41573
|
+
name: "CLI Ready",
|
|
40759
41574
|
category: "Claude",
|
|
40760
|
-
passed:
|
|
40761
|
-
message:
|
|
40762
|
-
fix:
|
|
40763
|
-
details: verbose ?
|
|
41575
|
+
passed: helpCheck.success,
|
|
41576
|
+
message: helpCheck.success ? "CLI is functional" : "CLI not responding",
|
|
41577
|
+
fix: helpCheck.success ? void 0 : "Check Claude Code CLI installation",
|
|
41578
|
+
details: verbose ? helpCheck.success ? "Claude Code CLI authenticated via desktop app" : helpCheck.error : void 0
|
|
41579
|
+
});
|
|
41580
|
+
}
|
|
41581
|
+
results.forEach((r) => displayCheck(r));
|
|
41582
|
+
return results;
|
|
41583
|
+
}
|
|
41584
|
+
async function checkGrokProvider(verbose) {
|
|
41585
|
+
const results = [];
|
|
41586
|
+
const cliCheck = await checkCommand("grok", "--version");
|
|
41587
|
+
results.push({
|
|
41588
|
+
name: "CLI Installation",
|
|
41589
|
+
category: "Grok",
|
|
41590
|
+
passed: cliCheck.success,
|
|
41591
|
+
message: cliCheck.success ? `Installed: ${cliCheck.output?.trim() || "version unknown"}` : "Grok CLI not found",
|
|
41592
|
+
fix: cliCheck.success ? void 0 : "npm install -g @vibe-kit/grok-cli",
|
|
41593
|
+
details: verbose ? cliCheck.error : void 0
|
|
41594
|
+
});
|
|
41595
|
+
if (cliCheck.success) {
|
|
41596
|
+
const helpCheck = await checkCommand("grok", "--help");
|
|
41597
|
+
results.push({
|
|
41598
|
+
name: "CLI Ready",
|
|
41599
|
+
category: "Grok",
|
|
41600
|
+
passed: helpCheck.success,
|
|
41601
|
+
message: helpCheck.success ? "CLI is functional" : "CLI not responding",
|
|
41602
|
+
fix: helpCheck.success ? void 0 : "Check Grok CLI installation: npm install -g @vibe-kit/grok-cli",
|
|
41603
|
+
details: verbose ? helpCheck.success ? "Grok CLI uses API keys from environment (GROK_API_KEY) or config files" : helpCheck.error : void 0
|
|
40764
41604
|
});
|
|
40765
41605
|
}
|
|
40766
41606
|
results.forEach((r) => displayCheck(r));
|
|
@@ -40828,69 +41668,39 @@ async function checkCommand(command, args) {
|
|
|
40828
41668
|
}
|
|
40829
41669
|
}
|
|
40830
41670
|
async function checkOpenAIAuth() {
|
|
40831
|
-
if (process.env.OPENAI_API_KEY) {
|
|
40832
|
-
return {
|
|
40833
|
-
success: true,
|
|
40834
|
-
message: "API key configured",
|
|
40835
|
-
details: "OPENAI_API_KEY environment variable is set"
|
|
40836
|
-
};
|
|
40837
|
-
}
|
|
40838
41671
|
try {
|
|
40839
|
-
execSync(
|
|
41672
|
+
const output = execSync("codex login status 2>&1", {
|
|
40840
41673
|
encoding: "utf-8",
|
|
40841
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
40842
41674
|
timeout: 1e4
|
|
40843
41675
|
});
|
|
40844
|
-
|
|
40845
|
-
|
|
40846
|
-
message: "Authenticated via CLI",
|
|
40847
|
-
details: "Successfully executed test command"
|
|
40848
|
-
};
|
|
40849
|
-
} catch (error) {
|
|
40850
|
-
const errorMsg = error.message.toLowerCase();
|
|
40851
|
-
if (errorMsg.includes("unauthorized") || errorMsg.includes("401")) {
|
|
41676
|
+
const statusText = output.toLowerCase();
|
|
41677
|
+
if (statusText.includes("logged in") || statusText.includes("authenticated")) {
|
|
40852
41678
|
return {
|
|
40853
|
-
success:
|
|
40854
|
-
message: "
|
|
40855
|
-
|
|
40856
|
-
details: "Test command returned unauthorized"
|
|
41679
|
+
success: true,
|
|
41680
|
+
message: "Authenticated via CLI",
|
|
41681
|
+
details: output.trim()
|
|
40857
41682
|
};
|
|
40858
41683
|
}
|
|
40859
41684
|
return {
|
|
40860
41685
|
success: false,
|
|
40861
|
-
message: "
|
|
40862
|
-
fix:
|
|
40863
|
-
details:
|
|
40864
|
-
};
|
|
40865
|
-
}
|
|
40866
|
-
}
|
|
40867
|
-
async function checkAPIConnectivity2(url) {
|
|
40868
|
-
try {
|
|
40869
|
-
const controller = new AbortController();
|
|
40870
|
-
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
40871
|
-
const response = await fetch(url, {
|
|
40872
|
-
method: "HEAD",
|
|
40873
|
-
signal: controller.signal
|
|
40874
|
-
});
|
|
40875
|
-
clearTimeout(timeout);
|
|
40876
|
-
return {
|
|
40877
|
-
success: response.ok || response.status === 401,
|
|
40878
|
-
// 401 means we reached API
|
|
40879
|
-
message: response.ok || response.status === 401 ? "Connected" : `HTTP ${response.status}`,
|
|
40880
|
-
details: `Status: ${response.status} ${response.statusText}`
|
|
41686
|
+
message: "Not authenticated",
|
|
41687
|
+
fix: "Run: codex login",
|
|
41688
|
+
details: output.trim()
|
|
40881
41689
|
};
|
|
40882
41690
|
} catch (error) {
|
|
40883
|
-
const errorMsg = error.message;
|
|
40884
|
-
if (errorMsg.includes("
|
|
41691
|
+
const errorMsg = error.message.toLowerCase();
|
|
41692
|
+
if (errorMsg.includes("not logged in") || errorMsg.includes("not authenticated")) {
|
|
40885
41693
|
return {
|
|
40886
41694
|
success: false,
|
|
40887
|
-
message: "
|
|
40888
|
-
|
|
41695
|
+
message: "Not authenticated",
|
|
41696
|
+
fix: "Run: codex login",
|
|
41697
|
+
details: "codex login status: not logged in"
|
|
40889
41698
|
};
|
|
40890
41699
|
}
|
|
40891
41700
|
return {
|
|
40892
41701
|
success: false,
|
|
40893
|
-
message: "Cannot
|
|
41702
|
+
message: "Cannot verify authentication",
|
|
41703
|
+
fix: "Run: codex login",
|
|
40894
41704
|
details: errorMsg
|
|
40895
41705
|
};
|
|
40896
41706
|
}
|
|
@@ -40943,6 +41753,8 @@ function getProviderEmoji(provider) {
|
|
|
40943
41753
|
return "\u2728";
|
|
40944
41754
|
case "claude":
|
|
40945
41755
|
return "\u{1F9E0}";
|
|
41756
|
+
case "grok":
|
|
41757
|
+
return "\u{1F680}";
|
|
40946
41758
|
default:
|
|
40947
41759
|
return "\u{1F527}";
|
|
40948
41760
|
}
|
|
@@ -40954,7 +41766,7 @@ function capitalize(str) {
|
|
|
40954
41766
|
// src/cli/commands/cleanup.ts
|
|
40955
41767
|
init_esm_shims();
|
|
40956
41768
|
init_logger();
|
|
40957
|
-
var
|
|
41769
|
+
var execAsync3 = promisify(exec);
|
|
40958
41770
|
var cleanupCommand2 = {
|
|
40959
41771
|
command: "cleanup [provider]",
|
|
40960
41772
|
describe: "Clean up orphaned provider processes (v6.0.7 Phase 3)",
|
|
@@ -41083,7 +41895,7 @@ async function findProcesses(processName, verbose) {
|
|
|
41083
41895
|
throw new Error(`Invalid process name: ${processName}. Only alphanumeric characters, dashes, and underscores are allowed.`);
|
|
41084
41896
|
}
|
|
41085
41897
|
try {
|
|
41086
|
-
const { stdout } = await
|
|
41898
|
+
const { stdout } = await execAsync3("ps -eo pid,comm,etime,rss");
|
|
41087
41899
|
if (!stdout.trim()) {
|
|
41088
41900
|
return processes;
|
|
41089
41901
|
}
|