@defai.digital/automatosx 5.1.2 → 5.2.0
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 +185 -0
- package/README.md +8 -7
- package/dist/index.js +640 -796
- package/dist/index.js.map +1 -1
- package/dist/version.json +2 -2
- package/examples/abilities/our-architecture-decisions.md +3 -3
- package/examples/abilities/our-code-review-checklist.md +4 -4
- package/examples/abilities/our-project-structure.md +17 -9
- package/package.json +1 -1
- package/version.json +2 -2
package/dist/index.js
CHANGED
|
@@ -583,12 +583,12 @@ var init_cache = __esm({
|
|
|
583
583
|
});
|
|
584
584
|
|
|
585
585
|
// src/types/path.ts
|
|
586
|
-
var
|
|
586
|
+
var PathError;
|
|
587
587
|
var init_path = __esm({
|
|
588
588
|
"src/types/path.ts"() {
|
|
589
589
|
"use strict";
|
|
590
590
|
init_esm_shims();
|
|
591
|
-
|
|
591
|
+
PathError = class extends Error {
|
|
592
592
|
constructor(message, context) {
|
|
593
593
|
super(message);
|
|
594
594
|
this.context = context;
|
|
@@ -669,7 +669,7 @@ var init_path_resolver = __esm({
|
|
|
669
669
|
*/
|
|
670
670
|
resolveUserPath(userPath) {
|
|
671
671
|
if (process.platform !== "win32" && isWindowsPath(userPath)) {
|
|
672
|
-
throw new
|
|
672
|
+
throw new PathError(
|
|
673
673
|
`Windows paths are not supported on ${process.platform}`,
|
|
674
674
|
{ path: userPath, type: "invalid_path" }
|
|
675
675
|
);
|
|
@@ -776,7 +776,7 @@ var init_path_resolver = __esm({
|
|
|
776
776
|
validateInProject(path3) {
|
|
777
777
|
const boundary = this.checkBoundaries(path3);
|
|
778
778
|
if (boundary === "outside_boundaries" || boundary === "system_restricted") {
|
|
779
|
-
throw new
|
|
779
|
+
throw new PathError("Path outside project directory", {
|
|
780
780
|
path: path3,
|
|
781
781
|
projectDir: this.config.projectDir,
|
|
782
782
|
boundary
|
|
@@ -868,7 +868,7 @@ var init_base_provider = __esm({
|
|
|
868
868
|
async checkCLIAvailability() {
|
|
869
869
|
try {
|
|
870
870
|
const { spawn } = await import("child_process");
|
|
871
|
-
return new Promise((
|
|
871
|
+
return new Promise((resolve9) => {
|
|
872
872
|
const child = spawn(this.config.command, ["--version"], {
|
|
873
873
|
stdio: "ignore",
|
|
874
874
|
timeout: 5e3
|
|
@@ -877,7 +877,7 @@ var init_base_provider = __esm({
|
|
|
877
877
|
child.on("close", (code) => {
|
|
878
878
|
if (!resolved) {
|
|
879
879
|
resolved = true;
|
|
880
|
-
|
|
880
|
+
resolve9(code === 0 || code === 1);
|
|
881
881
|
}
|
|
882
882
|
});
|
|
883
883
|
child.on("error", (error) => {
|
|
@@ -885,9 +885,9 @@ var init_base_provider = __esm({
|
|
|
885
885
|
resolved = true;
|
|
886
886
|
if (error.code === "ENOENT") {
|
|
887
887
|
logger.warn(`CLI command not found: ${this.config.command}`);
|
|
888
|
-
|
|
888
|
+
resolve9(false);
|
|
889
889
|
} else {
|
|
890
|
-
|
|
890
|
+
resolve9(true);
|
|
891
891
|
}
|
|
892
892
|
}
|
|
893
893
|
});
|
|
@@ -895,7 +895,7 @@ var init_base_provider = __esm({
|
|
|
895
895
|
if (!resolved) {
|
|
896
896
|
resolved = true;
|
|
897
897
|
child.kill();
|
|
898
|
-
|
|
898
|
+
resolve9(false);
|
|
899
899
|
}
|
|
900
900
|
}, 5e3);
|
|
901
901
|
});
|
|
@@ -1098,7 +1098,7 @@ var init_base_provider = __esm({
|
|
|
1098
1098
|
return Math.ceil(text.length / 4);
|
|
1099
1099
|
}
|
|
1100
1100
|
sleep(ms) {
|
|
1101
|
-
return new Promise((
|
|
1101
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
1102
1102
|
}
|
|
1103
1103
|
/**
|
|
1104
1104
|
* Convert ExecutionRequest to messages array for cache key generation
|
|
@@ -1243,7 +1243,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
|
|
|
1243
1243
|
*/
|
|
1244
1244
|
async executeRealCLI(prompt, request) {
|
|
1245
1245
|
const { spawn } = await import("child_process");
|
|
1246
|
-
return new Promise((
|
|
1246
|
+
return new Promise((resolve9, reject) => {
|
|
1247
1247
|
let stdout = "";
|
|
1248
1248
|
let stderr = "";
|
|
1249
1249
|
let hasTimedOut = false;
|
|
@@ -1321,7 +1321,7 @@ Details: ${errorMsg}`
|
|
|
1321
1321
|
if (!stdout.trim()) {
|
|
1322
1322
|
reject(new Error("Claude CLI returned empty response"));
|
|
1323
1323
|
} else {
|
|
1324
|
-
|
|
1324
|
+
resolve9({ content: stdout.trim() });
|
|
1325
1325
|
}
|
|
1326
1326
|
}
|
|
1327
1327
|
});
|
|
@@ -1515,7 +1515,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
|
|
|
1515
1515
|
*/
|
|
1516
1516
|
async executeRealCLI(prompt, request) {
|
|
1517
1517
|
const { spawn } = await import("child_process");
|
|
1518
|
-
return new Promise((
|
|
1518
|
+
return new Promise((resolve9, reject) => {
|
|
1519
1519
|
let stdout = "";
|
|
1520
1520
|
let stderr = "";
|
|
1521
1521
|
let hasTimedOut = false;
|
|
@@ -1551,7 +1551,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
|
|
|
1551
1551
|
if (code !== 0) {
|
|
1552
1552
|
reject(new Error(`Gemini CLI exited with code ${code}: ${stderr}`));
|
|
1553
1553
|
} else {
|
|
1554
|
-
|
|
1554
|
+
resolve9({ content: stdout.trim() });
|
|
1555
1555
|
}
|
|
1556
1556
|
});
|
|
1557
1557
|
child.on("error", (error) => {
|
|
@@ -1716,7 +1716,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
|
|
|
1716
1716
|
*/
|
|
1717
1717
|
async executeRealCLI(prompt, request) {
|
|
1718
1718
|
const { spawn } = await import("child_process");
|
|
1719
|
-
return new Promise((
|
|
1719
|
+
return new Promise((resolve9, reject) => {
|
|
1720
1720
|
let stdout = "";
|
|
1721
1721
|
let stderr = "";
|
|
1722
1722
|
let hasTimedOut = false;
|
|
@@ -1751,7 +1751,7 @@ This is a placeholder response. Set AUTOMATOSX_MOCK_PROVIDERS=false to use real
|
|
|
1751
1751
|
if (code !== 0) {
|
|
1752
1752
|
reject(new Error(`OpenAI CLI exited with code ${code}: ${stderr}`));
|
|
1753
1753
|
} else {
|
|
1754
|
-
|
|
1754
|
+
resolve9({ content: stdout.trim() });
|
|
1755
1755
|
}
|
|
1756
1756
|
});
|
|
1757
1757
|
child.on("error", (error) => {
|
|
@@ -2014,16 +2014,8 @@ var DEFAULT_CONFIG = {
|
|
|
2014
2014
|
timeout: 15e5,
|
|
2015
2015
|
// 25 minutes (v5.1.0: increased from 15 min based on user feedback)
|
|
2016
2016
|
enableCycleDetection: true
|
|
2017
|
-
},
|
|
2018
|
-
workspace: {
|
|
2019
|
-
maxFileSize: 10485760,
|
|
2020
|
-
// 10 MB
|
|
2021
|
-
maxFiles: 100,
|
|
2022
|
-
cleanupAfterDays: 7,
|
|
2023
|
-
autoCleanup: true,
|
|
2024
|
-
permissions: 448,
|
|
2025
|
-
basePath: ".automatosx/workspaces"
|
|
2026
2017
|
}
|
|
2018
|
+
// v5.2: workspace moved to root level
|
|
2027
2019
|
},
|
|
2028
2020
|
memory: {
|
|
2029
2021
|
maxEntries: 1e4,
|
|
@@ -2056,10 +2048,10 @@ var DEFAULT_CONFIG = {
|
|
|
2056
2048
|
}
|
|
2057
2049
|
},
|
|
2058
2050
|
workspace: {
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2051
|
+
prdPath: "automatosx/PRD",
|
|
2052
|
+
tmpPath: "automatosx/tmp",
|
|
2053
|
+
autoCleanupTmp: true,
|
|
2054
|
+
tmpCleanupDays: 7
|
|
2063
2055
|
},
|
|
2064
2056
|
logging: {
|
|
2065
2057
|
level: "info",
|
|
@@ -2256,37 +2248,6 @@ var ConfigError = class _ConfigError extends BaseError {
|
|
|
2256
2248
|
);
|
|
2257
2249
|
}
|
|
2258
2250
|
};
|
|
2259
|
-
var PathError = class _PathError extends BaseError {
|
|
2260
|
-
constructor(message, code = "E1103" /* PATH_INVALID */, suggestions = [], context, isOperational = true) {
|
|
2261
|
-
super(message, code, suggestions, context, isOperational);
|
|
2262
|
-
}
|
|
2263
|
-
static traversal(path3) {
|
|
2264
|
-
return new _PathError(
|
|
2265
|
-
`Path traversal attempt detected: ${path3}`,
|
|
2266
|
-
"E1100" /* PATH_TRAVERSAL */,
|
|
2267
|
-
[
|
|
2268
|
-
"Use relative paths within the project directory",
|
|
2269
|
-
'Avoid using ".." in file paths',
|
|
2270
|
-
"Check your file path for security issues"
|
|
2271
|
-
],
|
|
2272
|
-
{ path: path3 },
|
|
2273
|
-
false
|
|
2274
|
-
// Security error, not operational
|
|
2275
|
-
);
|
|
2276
|
-
}
|
|
2277
|
-
static notFound(path3, type = "Path") {
|
|
2278
|
-
return new _PathError(
|
|
2279
|
-
`${type} not found: ${path3}`,
|
|
2280
|
-
"E1101" /* PATH_NOT_FOUND */,
|
|
2281
|
-
[
|
|
2282
|
-
"Check that the path exists and is accessible",
|
|
2283
|
-
"Verify you have the correct permissions",
|
|
2284
|
-
`Use "automatosx list" to see available ${type.toLowerCase()}s`
|
|
2285
|
-
],
|
|
2286
|
-
{ path: path3, type }
|
|
2287
|
-
);
|
|
2288
|
-
}
|
|
2289
|
-
};
|
|
2290
2251
|
var ProviderError = class _ProviderError extends BaseError {
|
|
2291
2252
|
constructor(message, code = "E1301" /* PROVIDER_UNAVAILABLE */, suggestions = [], context) {
|
|
2292
2253
|
super(message, code, suggestions, context);
|
|
@@ -2653,50 +2614,50 @@ function validateWorkspace(workspace) {
|
|
|
2653
2614
|
});
|
|
2654
2615
|
return errors;
|
|
2655
2616
|
}
|
|
2656
|
-
if (typeof workspace.
|
|
2617
|
+
if (typeof workspace.prdPath !== "string") {
|
|
2657
2618
|
errors.push({
|
|
2658
|
-
path: `${basePath}.
|
|
2659
|
-
message: "
|
|
2660
|
-
value: workspace.
|
|
2619
|
+
path: `${basePath}.prdPath`,
|
|
2620
|
+
message: "prdPath must be a string",
|
|
2621
|
+
value: workspace.prdPath
|
|
2661
2622
|
});
|
|
2662
|
-
} else if (workspace.
|
|
2623
|
+
} else if (workspace.prdPath.trim() === "") {
|
|
2663
2624
|
errors.push({
|
|
2664
|
-
path: `${basePath}.
|
|
2665
|
-
message: "
|
|
2666
|
-
value: workspace.
|
|
2625
|
+
path: `${basePath}.prdPath`,
|
|
2626
|
+
message: "prdPath cannot be empty",
|
|
2627
|
+
value: workspace.prdPath
|
|
2667
2628
|
});
|
|
2668
2629
|
}
|
|
2669
|
-
if (typeof workspace.
|
|
2630
|
+
if (typeof workspace.tmpPath !== "string") {
|
|
2670
2631
|
errors.push({
|
|
2671
|
-
path: `${basePath}.
|
|
2672
|
-
message: "
|
|
2673
|
-
value: workspace.
|
|
2632
|
+
path: `${basePath}.tmpPath`,
|
|
2633
|
+
message: "tmpPath must be a string",
|
|
2634
|
+
value: workspace.tmpPath
|
|
2674
2635
|
});
|
|
2675
|
-
}
|
|
2676
|
-
if (typeof workspace.cleanupDays !== "number") {
|
|
2636
|
+
} else if (workspace.tmpPath.trim() === "") {
|
|
2677
2637
|
errors.push({
|
|
2678
|
-
path: `${basePath}.
|
|
2679
|
-
message: "
|
|
2680
|
-
value: workspace.
|
|
2638
|
+
path: `${basePath}.tmpPath`,
|
|
2639
|
+
message: "tmpPath cannot be empty",
|
|
2640
|
+
value: workspace.tmpPath
|
|
2681
2641
|
});
|
|
2682
|
-
}
|
|
2642
|
+
}
|
|
2643
|
+
if (typeof workspace.autoCleanupTmp !== "boolean") {
|
|
2683
2644
|
errors.push({
|
|
2684
|
-
path: `${basePath}.
|
|
2685
|
-
message: "
|
|
2686
|
-
value: workspace.
|
|
2645
|
+
path: `${basePath}.autoCleanupTmp`,
|
|
2646
|
+
message: "autoCleanupTmp must be a boolean",
|
|
2647
|
+
value: workspace.autoCleanupTmp
|
|
2687
2648
|
});
|
|
2688
2649
|
}
|
|
2689
|
-
if (typeof workspace.
|
|
2650
|
+
if (typeof workspace.tmpCleanupDays !== "number") {
|
|
2690
2651
|
errors.push({
|
|
2691
|
-
path: `${basePath}.
|
|
2692
|
-
message: "
|
|
2693
|
-
value: workspace.
|
|
2652
|
+
path: `${basePath}.tmpCleanupDays`,
|
|
2653
|
+
message: "tmpCleanupDays must be a number",
|
|
2654
|
+
value: workspace.tmpCleanupDays
|
|
2694
2655
|
});
|
|
2695
|
-
} else if (workspace.
|
|
2656
|
+
} else if (workspace.tmpCleanupDays < 1) {
|
|
2696
2657
|
errors.push({
|
|
2697
|
-
path: `${basePath}.
|
|
2698
|
-
message: "
|
|
2699
|
-
value: workspace.
|
|
2658
|
+
path: `${basePath}.tmpCleanupDays`,
|
|
2659
|
+
message: "tmpCleanupDays must be >= 1",
|
|
2660
|
+
value: workspace.tmpCleanupDays
|
|
2700
2661
|
});
|
|
2701
2662
|
}
|
|
2702
2663
|
return errors;
|
|
@@ -3160,26 +3121,6 @@ function validateConfig2(config) {
|
|
|
3160
3121
|
errors.push(`Orchestration: delegation.timeout must be <= ${VALIDATION_LIMITS.MAX_TIMEOUT}ms`);
|
|
3161
3122
|
}
|
|
3162
3123
|
}
|
|
3163
|
-
if (!isPositiveInteger(config.orchestration.workspace.maxFileSize)) {
|
|
3164
|
-
errors.push("Orchestration: workspace.maxFileSize must be a positive integer");
|
|
3165
|
-
} else {
|
|
3166
|
-
if (config.orchestration.workspace.maxFileSize < VALIDATION_LIMITS.MIN_FILE_SIZE) {
|
|
3167
|
-
errors.push(`Orchestration: workspace.maxFileSize must be >= ${VALIDATION_LIMITS.MIN_FILE_SIZE} bytes`);
|
|
3168
|
-
}
|
|
3169
|
-
if (config.orchestration.workspace.maxFileSize > VALIDATION_LIMITS.MAX_FILE_SIZE) {
|
|
3170
|
-
errors.push(`Orchestration: workspace.maxFileSize must be <= ${VALIDATION_LIMITS.MAX_FILE_SIZE} bytes (100MB max)`);
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
if (!isPositiveInteger(config.orchestration.workspace.maxFiles)) {
|
|
3174
|
-
errors.push("Orchestration: workspace.maxFiles must be a positive integer");
|
|
3175
|
-
} else if (config.orchestration.workspace.maxFiles > 1e4) {
|
|
3176
|
-
errors.push("Orchestration: workspace.maxFiles must be <= 10000");
|
|
3177
|
-
}
|
|
3178
|
-
if (!isPositiveInteger(config.orchestration.workspace.cleanupAfterDays)) {
|
|
3179
|
-
errors.push("Orchestration: workspace.cleanupAfterDays must be a positive integer");
|
|
3180
|
-
} else if (config.orchestration.workspace.cleanupAfterDays > 365) {
|
|
3181
|
-
errors.push("Orchestration: workspace.cleanupAfterDays must be <= 365 days");
|
|
3182
|
-
}
|
|
3183
3124
|
}
|
|
3184
3125
|
if (!isPositiveInteger(config.memory.maxEntries)) {
|
|
3185
3126
|
errors.push("Memory: maxEntries must be a positive integer");
|
|
@@ -3257,15 +3198,16 @@ function validateConfig2(config) {
|
|
|
3257
3198
|
}
|
|
3258
3199
|
}
|
|
3259
3200
|
}
|
|
3260
|
-
if (!
|
|
3261
|
-
errors.push("Workspace:
|
|
3262
|
-
}
|
|
3263
|
-
|
|
3201
|
+
if (typeof config.workspace.prdPath !== "string" || !config.workspace.prdPath.trim()) {
|
|
3202
|
+
errors.push("Workspace: prdPath must be a non-empty string");
|
|
3203
|
+
}
|
|
3204
|
+
if (typeof config.workspace.tmpPath !== "string" || !config.workspace.tmpPath.trim()) {
|
|
3205
|
+
errors.push("Workspace: tmpPath must be a non-empty string");
|
|
3264
3206
|
}
|
|
3265
|
-
if (!isPositiveInteger(config.workspace.
|
|
3266
|
-
errors.push("Workspace:
|
|
3267
|
-
} else if (config.workspace.
|
|
3268
|
-
errors.push("Workspace:
|
|
3207
|
+
if (!isPositiveInteger(config.workspace.tmpCleanupDays)) {
|
|
3208
|
+
errors.push("Workspace: tmpCleanupDays must be a positive integer");
|
|
3209
|
+
} else if (config.workspace.tmpCleanupDays > 365) {
|
|
3210
|
+
errors.push("Workspace: tmpCleanupDays must be <= 365 days");
|
|
3269
3211
|
}
|
|
3270
3212
|
if (config.logging?.retention) {
|
|
3271
3213
|
if (!isPositiveInteger(config.logging.retention.maxSizeBytes)) {
|
|
@@ -3365,8 +3307,9 @@ function validateConfig2(config) {
|
|
|
3365
3307
|
{ name: "Abilities: basePath", value: config.abilities?.basePath },
|
|
3366
3308
|
{ name: "Abilities: fallbackPath", value: config.abilities?.fallbackPath },
|
|
3367
3309
|
{ name: "Orchestration: session.persistPath", value: config.orchestration?.session.persistPath },
|
|
3368
|
-
|
|
3369
|
-
{ name: "Workspace:
|
|
3310
|
+
// v5.2: Workspace moved to root level
|
|
3311
|
+
{ name: "Workspace: prdPath", value: config.workspace.prdPath },
|
|
3312
|
+
{ name: "Workspace: tmpPath", value: config.workspace.tmpPath }
|
|
3370
3313
|
];
|
|
3371
3314
|
for (const { name, value } of pathFields) {
|
|
3372
3315
|
if (value && typeof value === "string" && !isValidRelativePath(value)) {
|
|
@@ -3631,11 +3574,11 @@ async function listConfig(config, verbose) {
|
|
|
3631
3574
|
console.log(chalk3.bold.white("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
3632
3575
|
console.log(chalk3.bold.white("\u2502 ") + chalk3.bold.cyan("Workspace"));
|
|
3633
3576
|
console.log(chalk3.bold.white("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n"));
|
|
3634
|
-
console.log(formatKeyValue("
|
|
3635
|
-
console.log(formatKeyValue("
|
|
3577
|
+
console.log(formatKeyValue(" PRD Path ", chalk3.blue(config.workspace.prdPath)));
|
|
3578
|
+
console.log(formatKeyValue(" Tmp Path ", chalk3.blue(config.workspace.tmpPath)));
|
|
3579
|
+
console.log(formatKeyValue(" Auto Cleanup ", config.workspace.autoCleanupTmp ? chalk3.green("\u2713 Enabled") : chalk3.gray("\u2717 Disabled")));
|
|
3636
3580
|
if (verbose) {
|
|
3637
|
-
console.log(formatKeyValue(" Cleanup Days ", chalk3.yellow(config.workspace.
|
|
3638
|
-
console.log(formatKeyValue(" Max Files ", chalk3.yellow(config.workspace.maxFiles.toString())));
|
|
3581
|
+
console.log(formatKeyValue(" Cleanup Days ", chalk3.yellow(config.workspace.tmpCleanupDays.toString())));
|
|
3639
3582
|
}
|
|
3640
3583
|
console.log(chalk3.bold.white("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
3641
3584
|
console.log(chalk3.bold.white("\u2502 ") + chalk3.bold.cyan("Logging"));
|
|
@@ -3725,21 +3668,24 @@ function setNestedValue(obj, path3, value) {
|
|
|
3725
3668
|
|
|
3726
3669
|
// src/cli/commands/init.ts
|
|
3727
3670
|
init_esm_shims();
|
|
3728
|
-
import { mkdir as mkdir2, writeFile as writeFile3, access as access2 } from "fs/promises";
|
|
3671
|
+
import { mkdir as mkdir2, writeFile as writeFile3, access as access2, readdir, copyFile, rm, stat } from "fs/promises";
|
|
3729
3672
|
import { resolve as resolve3, join as join2, dirname as dirname2 } from "path";
|
|
3730
3673
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3731
|
-
import { constants as constants2 } from "fs";
|
|
3674
|
+
import { constants as constants2, existsSync as existsSync3 } from "fs";
|
|
3732
3675
|
import chalk4 from "chalk";
|
|
3733
3676
|
init_logger();
|
|
3734
3677
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
3735
3678
|
var __dirname2 = dirname2(__filename2);
|
|
3736
3679
|
function getPackageRoot() {
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3680
|
+
let current = __dirname2;
|
|
3681
|
+
const root = "/";
|
|
3682
|
+
while (current !== root) {
|
|
3683
|
+
if (existsSync3(join2(current, "package.json"))) {
|
|
3684
|
+
return current;
|
|
3685
|
+
}
|
|
3686
|
+
current = dirname2(current);
|
|
3742
3687
|
}
|
|
3688
|
+
throw new Error("Could not find package root (no package.json found)");
|
|
3743
3689
|
}
|
|
3744
3690
|
var initCommand = {
|
|
3745
3691
|
command: "init [path]",
|
|
@@ -3759,8 +3705,25 @@ var initCommand = {
|
|
|
3759
3705
|
handler: async (argv2) => {
|
|
3760
3706
|
const projectDir = resolve3(argv2.path || ".");
|
|
3761
3707
|
const automatosxDir = join2(projectDir, ".automatosx");
|
|
3762
|
-
|
|
3708
|
+
const configPath = join2(projectDir, "automatosx.config.json");
|
|
3709
|
+
const packageRoot = getPackageRoot();
|
|
3710
|
+
let version = "5.1.2";
|
|
3763
3711
|
try {
|
|
3712
|
+
const packageJson = JSON.parse(
|
|
3713
|
+
await import("fs/promises").then((fs2) => fs2.readFile(join2(packageRoot, "package.json"), "utf-8"))
|
|
3714
|
+
);
|
|
3715
|
+
version = packageJson.version;
|
|
3716
|
+
} catch {
|
|
3717
|
+
}
|
|
3718
|
+
console.log(chalk4.blue.bold(`
|
|
3719
|
+
\u{1F916} AutomatosX v${version} - Project Initialization
|
|
3720
|
+
`));
|
|
3721
|
+
const createdResources = [];
|
|
3722
|
+
let shouldRollback = false;
|
|
3723
|
+
try {
|
|
3724
|
+
console.log(chalk4.cyan("\u{1F50D} Validating environment..."));
|
|
3725
|
+
await validateEnvironment(packageRoot);
|
|
3726
|
+
console.log(chalk4.green(" \u2713 Environment validation passed"));
|
|
3764
3727
|
const exists = await checkExists2(automatosxDir);
|
|
3765
3728
|
if (exists && !argv2.force) {
|
|
3766
3729
|
console.log(chalk4.yellow("\u26A0\uFE0F AutomatosX is already initialized in this directory"));
|
|
@@ -3773,23 +3736,31 @@ var initCommand = {
|
|
|
3773
3736
|
}
|
|
3774
3737
|
console.log(chalk4.cyan("\u{1F4C1} Creating directory structure..."));
|
|
3775
3738
|
await createDirectoryStructure(automatosxDir);
|
|
3739
|
+
createdResources.push(automatosxDir);
|
|
3776
3740
|
console.log(chalk4.green(" \u2713 Directories created"));
|
|
3741
|
+
console.log(chalk4.cyan("\u{1F465} Installing team configurations..."));
|
|
3742
|
+
const teamCount = await copyExampleTeams(automatosxDir, packageRoot);
|
|
3743
|
+
console.log(chalk4.green(` \u2713 ${teamCount} team configurations installed`));
|
|
3777
3744
|
console.log(chalk4.cyan("\u{1F916} Installing example agents..."));
|
|
3778
|
-
await copyExampleAgents(automatosxDir);
|
|
3779
|
-
console.log(chalk4.green(
|
|
3745
|
+
const agentCount = await copyExampleAgents(automatosxDir, packageRoot);
|
|
3746
|
+
console.log(chalk4.green(` \u2713 ${agentCount} example agents installed`));
|
|
3780
3747
|
console.log(chalk4.cyan("\u26A1 Installing example abilities..."));
|
|
3781
|
-
await copyExampleAbilities(automatosxDir);
|
|
3782
|
-
console.log(chalk4.green(
|
|
3748
|
+
const abilityCount = await copyExampleAbilities(automatosxDir, packageRoot);
|
|
3749
|
+
console.log(chalk4.green(` \u2713 ${abilityCount} example abilities installed`));
|
|
3783
3750
|
console.log(chalk4.cyan("\u{1F4CB} Installing agent templates..."));
|
|
3784
|
-
await copyExampleTemplates(automatosxDir);
|
|
3785
|
-
console.log(chalk4.green(
|
|
3751
|
+
const templateCount = await copyExampleTemplates(automatosxDir, packageRoot);
|
|
3752
|
+
console.log(chalk4.green(` \u2713 ${templateCount} agent templates installed`));
|
|
3786
3753
|
console.log(chalk4.cyan("\u2699\uFE0F Generating configuration..."));
|
|
3787
|
-
const configPath = join2(projectDir, "automatosx.config.json");
|
|
3788
3754
|
await createDefaultConfig(configPath, argv2.force ?? false);
|
|
3755
|
+
createdResources.push(configPath);
|
|
3789
3756
|
console.log(chalk4.green(" \u2713 Configuration created"));
|
|
3790
3757
|
console.log(chalk4.cyan("\u{1F50C} Setting up Claude Code integration..."));
|
|
3791
|
-
await setupClaudeIntegration(projectDir);
|
|
3758
|
+
await setupClaudeIntegration(projectDir, packageRoot);
|
|
3759
|
+
createdResources.push(join2(projectDir, ".claude"));
|
|
3792
3760
|
console.log(chalk4.green(" \u2713 Claude Code integration configured"));
|
|
3761
|
+
console.log(chalk4.cyan("\u{1F527} Initializing git repository..."));
|
|
3762
|
+
await initializeGitRepository(projectDir);
|
|
3763
|
+
console.log(chalk4.green(" \u2713 Git repository initialized"));
|
|
3793
3764
|
console.log(chalk4.cyan("\u{1F4DD} Updating .gitignore..."));
|
|
3794
3765
|
await updateGitignore(projectDir);
|
|
3795
3766
|
console.log(chalk4.green(" \u2713 .gitignore updated"));
|
|
@@ -3815,15 +3786,28 @@ var initCommand = {
|
|
|
3815
3786
|
console.log(chalk4.gray(" \u2022 Use /ax command in Claude Code"));
|
|
3816
3787
|
console.log(chalk4.gray(' \u2022 Example: /ax assistant "Explain this code"'));
|
|
3817
3788
|
console.log(chalk4.gray(" \u2022 MCP tools available in .claude/mcp/\n"));
|
|
3818
|
-
logger.info("AutomatosX initialized", {
|
|
3789
|
+
logger.info("AutomatosX initialized", {
|
|
3790
|
+
projectDir,
|
|
3791
|
+
automatosxDir,
|
|
3792
|
+
counts: { teams: teamCount, agents: agentCount, abilities: abilityCount, templates: templateCount }
|
|
3793
|
+
});
|
|
3819
3794
|
} catch (error) {
|
|
3795
|
+
shouldRollback = true;
|
|
3796
|
+
if (createdResources.length > 0 && !argv2.force) {
|
|
3797
|
+
console.log(chalk4.yellow("\n\u26A0\uFE0F Initialization failed. Rolling back changes..."));
|
|
3798
|
+
await rollbackCreatedResources(createdResources);
|
|
3799
|
+
console.log(chalk4.green(" \u2713 Rollback completed"));
|
|
3800
|
+
}
|
|
3820
3801
|
printError(error, {
|
|
3821
3802
|
verbose: false,
|
|
3822
3803
|
showCode: true,
|
|
3823
3804
|
showSuggestions: true,
|
|
3824
3805
|
colors: true
|
|
3825
3806
|
});
|
|
3826
|
-
logger.error("Initialization failed", {
|
|
3807
|
+
logger.error("Initialization failed", {
|
|
3808
|
+
error: error.message,
|
|
3809
|
+
rolledBack: shouldRollback && createdResources.length > 0
|
|
3810
|
+
});
|
|
3827
3811
|
process.exit(1);
|
|
3828
3812
|
}
|
|
3829
3813
|
}
|
|
@@ -3849,57 +3833,116 @@ async function createDirectoryStructure(baseDir) {
|
|
|
3849
3833
|
// v5.1: MCP memory export directory
|
|
3850
3834
|
join2(baseDir, "sessions"),
|
|
3851
3835
|
// v5.1: Session persistence
|
|
3852
|
-
|
|
3836
|
+
// v5.2: Removed 'workspaces' - automatosx/PRD and automatosx/tmp created on-demand
|
|
3853
3837
|
join2(baseDir, "logs")
|
|
3854
3838
|
];
|
|
3855
3839
|
for (const dir of dirs) {
|
|
3856
3840
|
await mkdir2(dir, { recursive: true });
|
|
3857
3841
|
}
|
|
3858
3842
|
}
|
|
3859
|
-
async function
|
|
3860
|
-
const
|
|
3861
|
-
|
|
3843
|
+
async function validateEnvironment(packageRoot) {
|
|
3844
|
+
const requiredDirs = [
|
|
3845
|
+
"examples/agents",
|
|
3846
|
+
"examples/abilities",
|
|
3847
|
+
"examples/templates",
|
|
3848
|
+
"examples/teams"
|
|
3849
|
+
];
|
|
3850
|
+
const errors = [];
|
|
3851
|
+
for (const dir of requiredDirs) {
|
|
3852
|
+
const fullPath = join2(packageRoot, dir);
|
|
3853
|
+
try {
|
|
3854
|
+
await stat(fullPath);
|
|
3855
|
+
} catch {
|
|
3856
|
+
errors.push(`Missing required directory: ${dir}`);
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
if (errors.length > 0) {
|
|
3860
|
+
throw new Error(
|
|
3861
|
+
`Environment validation failed:
|
|
3862
|
+
${errors.map((e) => ` \u2022 ${e}`).join("\n")}
|
|
3863
|
+
|
|
3864
|
+
This usually means the package is corrupted. Try reinstalling:
|
|
3865
|
+
npm uninstall -g @defai.digital/automatosx
|
|
3866
|
+
npm install -g @defai.digital/automatosx`
|
|
3867
|
+
);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
async function rollbackCreatedResources(resources) {
|
|
3871
|
+
for (const resource of resources.reverse()) {
|
|
3872
|
+
try {
|
|
3873
|
+
await rm(resource, { recursive: true, force: true });
|
|
3874
|
+
logger.info("Rolled back resource", { resource });
|
|
3875
|
+
} catch (error) {
|
|
3876
|
+
logger.warn("Failed to rollback resource", {
|
|
3877
|
+
resource,
|
|
3878
|
+
error: error.message
|
|
3879
|
+
});
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
async function copyExampleTeams(baseDir, packageRoot) {
|
|
3884
|
+
const examplesDir = join2(packageRoot, "examples/teams");
|
|
3885
|
+
const targetDir = join2(baseDir, "teams");
|
|
3886
|
+
const files = await readdir(examplesDir);
|
|
3887
|
+
let count = 0;
|
|
3888
|
+
for (const file of files) {
|
|
3889
|
+
if (file.endsWith(".yaml")) {
|
|
3890
|
+
await copyFile(join2(examplesDir, file), join2(targetDir, file));
|
|
3891
|
+
count++;
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
if (count === 0) {
|
|
3895
|
+
throw new Error(`No team configuration files found in ${examplesDir}`);
|
|
3896
|
+
}
|
|
3897
|
+
return count;
|
|
3898
|
+
}
|
|
3899
|
+
async function copyExampleAgents(baseDir, packageRoot) {
|
|
3900
|
+
const examplesDir = join2(packageRoot, "examples/agents");
|
|
3862
3901
|
const targetDir = join2(baseDir, "agents");
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3902
|
+
const files = await readdir(examplesDir);
|
|
3903
|
+
let count = 0;
|
|
3904
|
+
for (const file of files) {
|
|
3905
|
+
if (file.endsWith(".yaml")) {
|
|
3906
|
+
await copyFile(join2(examplesDir, file), join2(targetDir, file));
|
|
3907
|
+
count++;
|
|
3869
3908
|
}
|
|
3870
|
-
} catch (error) {
|
|
3871
|
-
logger.warn("Could not copy example agents", { error: error.message });
|
|
3872
3909
|
}
|
|
3910
|
+
if (count === 0) {
|
|
3911
|
+
throw new Error(`No agent files found in ${examplesDir}`);
|
|
3912
|
+
}
|
|
3913
|
+
return count;
|
|
3873
3914
|
}
|
|
3874
|
-
async function copyExampleAbilities(baseDir) {
|
|
3875
|
-
const
|
|
3876
|
-
const examplesDir = join2(getPackageRoot(), "examples/abilities");
|
|
3915
|
+
async function copyExampleAbilities(baseDir, packageRoot) {
|
|
3916
|
+
const examplesDir = join2(packageRoot, "examples/abilities");
|
|
3877
3917
|
const targetDir = join2(baseDir, "abilities");
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3918
|
+
const files = await readdir(examplesDir);
|
|
3919
|
+
let count = 0;
|
|
3920
|
+
for (const file of files) {
|
|
3921
|
+
if (file.endsWith(".md")) {
|
|
3922
|
+
await copyFile(join2(examplesDir, file), join2(targetDir, file));
|
|
3923
|
+
count++;
|
|
3884
3924
|
}
|
|
3885
|
-
} catch (error) {
|
|
3886
|
-
logger.warn("Could not copy example abilities", { error: error.message });
|
|
3887
3925
|
}
|
|
3926
|
+
if (count === 0) {
|
|
3927
|
+
throw new Error(`No ability files found in ${examplesDir}`);
|
|
3928
|
+
}
|
|
3929
|
+
return count;
|
|
3888
3930
|
}
|
|
3889
|
-
async function copyExampleTemplates(baseDir) {
|
|
3890
|
-
const
|
|
3891
|
-
const examplesDir = join2(getPackageRoot(), "examples/templates");
|
|
3931
|
+
async function copyExampleTemplates(baseDir, packageRoot) {
|
|
3932
|
+
const examplesDir = join2(packageRoot, "examples/templates");
|
|
3892
3933
|
const targetDir = join2(baseDir, "templates");
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3934
|
+
const files = await readdir(examplesDir);
|
|
3935
|
+
let count = 0;
|
|
3936
|
+
for (const file of files) {
|
|
3937
|
+
if (file.endsWith(".yaml")) {
|
|
3938
|
+
await copyFile(join2(examplesDir, file), join2(targetDir, file));
|
|
3939
|
+
count++;
|
|
3899
3940
|
}
|
|
3900
|
-
} catch (error) {
|
|
3901
|
-
logger.warn("Could not copy agent templates", { error: error.message });
|
|
3902
3941
|
}
|
|
3942
|
+
if (count === 0) {
|
|
3943
|
+
throw new Error(`No template files found in ${examplesDir}`);
|
|
3944
|
+
}
|
|
3945
|
+
return count;
|
|
3903
3946
|
}
|
|
3904
3947
|
async function createDefaultConfig(configPath, force) {
|
|
3905
3948
|
const exists = await checkExists2(configPath);
|
|
@@ -3915,31 +3958,73 @@ async function createDefaultConfig(configPath, force) {
|
|
|
3915
3958
|
const content = JSON.stringify(config, null, 2);
|
|
3916
3959
|
await writeFile3(configPath, content, "utf-8");
|
|
3917
3960
|
}
|
|
3918
|
-
async function setupClaudeIntegration(projectDir) {
|
|
3919
|
-
const
|
|
3920
|
-
const examplesBaseDir = join2(getPackageRoot(), "examples/claude");
|
|
3961
|
+
async function setupClaudeIntegration(projectDir, packageRoot) {
|
|
3962
|
+
const examplesBaseDir = join2(packageRoot, "examples/claude");
|
|
3921
3963
|
const claudeDir = join2(projectDir, ".claude");
|
|
3922
3964
|
const commandsDir = join2(claudeDir, "commands");
|
|
3923
3965
|
const mcpDir = join2(claudeDir, "mcp");
|
|
3924
3966
|
await mkdir2(commandsDir, { recursive: true });
|
|
3925
3967
|
await mkdir2(mcpDir, { recursive: true });
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
await copyFile2(join2(commandsSourceDir, file), join2(commandsDir, file));
|
|
3932
|
-
}
|
|
3968
|
+
const commandsSourceDir = join2(examplesBaseDir, "commands");
|
|
3969
|
+
const commandFiles = await readdir(commandsSourceDir);
|
|
3970
|
+
for (const file of commandFiles) {
|
|
3971
|
+
if (file.endsWith(".md")) {
|
|
3972
|
+
await copyFile(join2(commandsSourceDir, file), join2(commandsDir, file));
|
|
3933
3973
|
}
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3974
|
+
}
|
|
3975
|
+
const mcpSourceDir = join2(examplesBaseDir, "mcp");
|
|
3976
|
+
const mcpFiles = await readdir(mcpSourceDir);
|
|
3977
|
+
for (const file of mcpFiles) {
|
|
3978
|
+
if (file.endsWith(".json")) {
|
|
3979
|
+
await copyFile(join2(mcpSourceDir, file), join2(mcpDir, file));
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
async function initializeGitRepository(projectDir) {
|
|
3984
|
+
const gitDir = join2(projectDir, ".git");
|
|
3985
|
+
try {
|
|
3986
|
+
const isGitRepo = await checkExists2(gitDir);
|
|
3987
|
+
if (isGitRepo) {
|
|
3988
|
+
logger.info("Git repository already exists, skipping initialization");
|
|
3989
|
+
return;
|
|
3940
3990
|
}
|
|
3991
|
+
const { spawn } = await import("child_process");
|
|
3992
|
+
await new Promise((resolve9, reject) => {
|
|
3993
|
+
const child = spawn("git", ["init"], {
|
|
3994
|
+
cwd: projectDir,
|
|
3995
|
+
stdio: "pipe"
|
|
3996
|
+
});
|
|
3997
|
+
let stderr = "";
|
|
3998
|
+
child.stderr?.on("data", (data) => {
|
|
3999
|
+
stderr += data.toString();
|
|
4000
|
+
});
|
|
4001
|
+
child.on("close", (code) => {
|
|
4002
|
+
if (code !== 0) {
|
|
4003
|
+
reject(new Error(`git init failed with code ${code}: ${stderr}`));
|
|
4004
|
+
} else {
|
|
4005
|
+
logger.info("Git repository initialized successfully");
|
|
4006
|
+
resolve9();
|
|
4007
|
+
}
|
|
4008
|
+
});
|
|
4009
|
+
child.on("error", (error) => {
|
|
4010
|
+
reject(error);
|
|
4011
|
+
});
|
|
4012
|
+
});
|
|
3941
4013
|
} catch (error) {
|
|
3942
|
-
|
|
4014
|
+
const errorMessage = error.message;
|
|
4015
|
+
if (errorMessage.includes("ENOENT") || errorMessage.includes("spawn git")) {
|
|
4016
|
+
console.log(chalk4.yellow(" \u26A0\uFE0F Git is not installed - skipping repository initialization"));
|
|
4017
|
+
console.log(chalk4.gray(" Note: Codex CLI requires git. Install git to use Codex provider."));
|
|
4018
|
+
logger.warn("Git not found, skipping repository initialization", {
|
|
4019
|
+
error: errorMessage
|
|
4020
|
+
});
|
|
4021
|
+
} else {
|
|
4022
|
+
console.log(chalk4.yellow(" \u26A0\uFE0F Failed to initialize git repository"));
|
|
4023
|
+
console.log(chalk4.gray(` ${errorMessage}`));
|
|
4024
|
+
logger.warn("Git initialization failed", {
|
|
4025
|
+
error: errorMessage
|
|
4026
|
+
});
|
|
4027
|
+
}
|
|
3943
4028
|
}
|
|
3944
4029
|
}
|
|
3945
4030
|
async function updateGitignore(projectDir) {
|
|
@@ -3948,8 +4033,8 @@ async function updateGitignore(projectDir) {
|
|
|
3948
4033
|
"",
|
|
3949
4034
|
"# AutomatosX",
|
|
3950
4035
|
".automatosx/memory/",
|
|
3951
|
-
".automatosx/workspaces/",
|
|
3952
4036
|
".automatosx/logs/",
|
|
4037
|
+
"automatosx/tmp/ # v5.2: Temporary files",
|
|
3953
4038
|
"automatosx.config.json # Optional: remove to track config",
|
|
3954
4039
|
""
|
|
3955
4040
|
].join("\n");
|
|
@@ -3974,7 +4059,7 @@ async function updateGitignore(projectDir) {
|
|
|
3974
4059
|
init_esm_shims();
|
|
3975
4060
|
init_logger();
|
|
3976
4061
|
init_path_resolver();
|
|
3977
|
-
import { readdir } from "fs/promises";
|
|
4062
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
3978
4063
|
import { join as join3 } from "path";
|
|
3979
4064
|
import chalk5 from "chalk";
|
|
3980
4065
|
var listCommand = {
|
|
@@ -4017,13 +4102,13 @@ var listCommand = {
|
|
|
4017
4102
|
};
|
|
4018
4103
|
async function listAgents(pathResolver) {
|
|
4019
4104
|
const agentsDir = pathResolver.getAgentsDirectory();
|
|
4020
|
-
const { existsSync:
|
|
4105
|
+
const { existsSync: existsSync10 } = await import("fs");
|
|
4021
4106
|
const projectDir = await detectProjectRoot();
|
|
4022
4107
|
const examplesDir = join3(projectDir, "examples", "agents");
|
|
4023
4108
|
try {
|
|
4024
4109
|
const agentFiles = [];
|
|
4025
|
-
if (
|
|
4026
|
-
const files = await
|
|
4110
|
+
if (existsSync10(agentsDir)) {
|
|
4111
|
+
const files = await readdir2(agentsDir);
|
|
4027
4112
|
for (const file of files) {
|
|
4028
4113
|
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
4029
4114
|
agentFiles.push({
|
|
@@ -4034,8 +4119,8 @@ async function listAgents(pathResolver) {
|
|
|
4034
4119
|
}
|
|
4035
4120
|
}
|
|
4036
4121
|
}
|
|
4037
|
-
if (
|
|
4038
|
-
const files = await
|
|
4122
|
+
if (existsSync10(examplesDir)) {
|
|
4123
|
+
const files = await readdir2(examplesDir);
|
|
4039
4124
|
for (const file of files) {
|
|
4040
4125
|
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
4041
4126
|
const alreadyLoaded = agentFiles.some((a) => a.file === file);
|
|
@@ -4090,7 +4175,7 @@ async function listAgents(pathResolver) {
|
|
|
4090
4175
|
async function listAbilities(pathResolver) {
|
|
4091
4176
|
const abilitiesDir = pathResolver.getAbilitiesDirectory();
|
|
4092
4177
|
try {
|
|
4093
|
-
const files = await
|
|
4178
|
+
const files = await readdir2(abilitiesDir);
|
|
4094
4179
|
const abilityFiles = files.filter((f) => f.endsWith(".md"));
|
|
4095
4180
|
if (abilityFiles.length === 0) {
|
|
4096
4181
|
console.log(chalk5.yellow("\n\u26A0\uFE0F No abilities found\n"));
|
|
@@ -4338,7 +4423,7 @@ var Router = class {
|
|
|
4338
4423
|
init_esm_shims();
|
|
4339
4424
|
import Database from "better-sqlite3";
|
|
4340
4425
|
import * as sqliteVec from "sqlite-vec";
|
|
4341
|
-
import { existsSync as
|
|
4426
|
+
import { existsSync as existsSync4, mkdirSync } from "fs";
|
|
4342
4427
|
import { dirname as dirname4 } from "path";
|
|
4343
4428
|
|
|
4344
4429
|
// src/types/memory.ts
|
|
@@ -4391,7 +4476,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
4391
4476
|
};
|
|
4392
4477
|
this.validateCleanupConfig();
|
|
4393
4478
|
const dir = dirname4(this.config.dbPath);
|
|
4394
|
-
if (!
|
|
4479
|
+
if (!existsSync4(dir)) {
|
|
4395
4480
|
mkdirSync(dir, { recursive: true });
|
|
4396
4481
|
}
|
|
4397
4482
|
this.db = new Database(this.config.dbPath);
|
|
@@ -5147,9 +5232,9 @@ var MemoryManager = class _MemoryManager {
|
|
|
5147
5232
|
}
|
|
5148
5233
|
try {
|
|
5149
5234
|
const { dirname: dirname9 } = await import("path");
|
|
5150
|
-
const { mkdir:
|
|
5235
|
+
const { mkdir: mkdir6 } = await import("fs/promises");
|
|
5151
5236
|
const destDir = dirname9(destPath);
|
|
5152
|
-
await
|
|
5237
|
+
await mkdir6(destDir, { recursive: true });
|
|
5153
5238
|
await this.db.backup(destPath);
|
|
5154
5239
|
logger.info("Database backup created", { destPath });
|
|
5155
5240
|
} catch (error) {
|
|
@@ -5165,7 +5250,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
5165
5250
|
throw new MemoryError("Memory manager not initialized", "DATABASE_ERROR");
|
|
5166
5251
|
}
|
|
5167
5252
|
try {
|
|
5168
|
-
if (!
|
|
5253
|
+
if (!existsSync4(srcPath)) {
|
|
5169
5254
|
throw new MemoryError(
|
|
5170
5255
|
`Backup file not found: ${srcPath}`,
|
|
5171
5256
|
"DATABASE_ERROR",
|
|
@@ -5206,7 +5291,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
5206
5291
|
} = options || {};
|
|
5207
5292
|
try {
|
|
5208
5293
|
const destDir = dirname4(filePath);
|
|
5209
|
-
if (!
|
|
5294
|
+
if (!existsSync4(destDir)) {
|
|
5210
5295
|
mkdirSync(destDir, { recursive: true });
|
|
5211
5296
|
}
|
|
5212
5297
|
let query = "SELECT e.* FROM memory_entries e";
|
|
@@ -5304,7 +5389,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
5304
5389
|
clearExisting = false
|
|
5305
5390
|
} = options || {};
|
|
5306
5391
|
try {
|
|
5307
|
-
if (!
|
|
5392
|
+
if (!existsSync4(filePath)) {
|
|
5308
5393
|
throw new MemoryError(
|
|
5309
5394
|
`Import file not found: ${filePath}`,
|
|
5310
5395
|
"DATABASE_ERROR",
|
|
@@ -5410,7 +5495,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
5410
5495
|
// src/core/session-manager.ts
|
|
5411
5496
|
init_esm_shims();
|
|
5412
5497
|
import { randomUUID } from "crypto";
|
|
5413
|
-
import { readFile as readFile2, writeFile as writeFile4, mkdir as mkdir3, rename, copyFile, unlink } from "fs/promises";
|
|
5498
|
+
import { readFile as readFile2, writeFile as writeFile4, mkdir as mkdir3, rename, copyFile as copyFile2, unlink } from "fs/promises";
|
|
5414
5499
|
import { dirname as dirname5 } from "path";
|
|
5415
5500
|
|
|
5416
5501
|
// src/types/orchestration.ts
|
|
@@ -5432,14 +5517,6 @@ var SessionError = class extends Error {
|
|
|
5432
5517
|
this.name = "SessionError";
|
|
5433
5518
|
}
|
|
5434
5519
|
};
|
|
5435
|
-
var WorkspaceError = class extends Error {
|
|
5436
|
-
constructor(message, workspacePath, reason) {
|
|
5437
|
-
super(message);
|
|
5438
|
-
this.workspacePath = workspacePath;
|
|
5439
|
-
this.reason = reason;
|
|
5440
|
-
this.name = "WorkspaceError";
|
|
5441
|
-
}
|
|
5442
|
-
};
|
|
5443
5520
|
|
|
5444
5521
|
// src/core/session-manager.ts
|
|
5445
5522
|
init_logger();
|
|
@@ -5874,8 +5951,8 @@ var SessionManager = class _SessionManager {
|
|
|
5874
5951
|
* const result = await sessionManager.cleanupOldSessions();
|
|
5875
5952
|
* console.log(`Removed ${result.removedCount} sessions`);
|
|
5876
5953
|
*
|
|
5877
|
-
* //
|
|
5878
|
-
*
|
|
5954
|
+
* // v5.2: Session workspaces no longer exist
|
|
5955
|
+
* // All agents share automatosx/PRD and automatosx/tmp
|
|
5879
5956
|
* ```
|
|
5880
5957
|
*/
|
|
5881
5958
|
async cleanupOldSessions(maxAgeDays = 7) {
|
|
@@ -6101,7 +6178,7 @@ var SessionManager = class _SessionManager {
|
|
|
6101
6178
|
}
|
|
6102
6179
|
try {
|
|
6103
6180
|
const backupPath = `${this.persistencePath}.corrupted.${Date.now()}`;
|
|
6104
|
-
await
|
|
6181
|
+
await copyFile2(this.persistencePath, backupPath);
|
|
6105
6182
|
logger.error("Corrupted sessions file backed up, starting fresh", {
|
|
6106
6183
|
path: this.persistencePath,
|
|
6107
6184
|
backupPath,
|
|
@@ -6141,488 +6218,291 @@ var SessionManager = class _SessionManager {
|
|
|
6141
6218
|
|
|
6142
6219
|
// src/core/workspace-manager.ts
|
|
6143
6220
|
init_esm_shims();
|
|
6221
|
+
init_logger();
|
|
6144
6222
|
import { promises as fs } from "fs";
|
|
6145
6223
|
import path2 from "path";
|
|
6146
|
-
init_logger();
|
|
6147
6224
|
var WorkspaceManager = class _WorkspaceManager {
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
/** Maximum file size
|
|
6153
|
-
|
|
6154
|
-
/** UUID v4 validation regex (static for performance) */
|
|
6155
|
-
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;
|
|
6225
|
+
projectDir;
|
|
6226
|
+
prdDir;
|
|
6227
|
+
tmpDir;
|
|
6228
|
+
directoriesEnsured = false;
|
|
6229
|
+
/** Maximum file size in bytes (10MB) */
|
|
6230
|
+
static MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
6156
6231
|
/**
|
|
6157
6232
|
* Create WorkspaceManager
|
|
6158
6233
|
*
|
|
6159
6234
|
* @param projectDir - Project directory path
|
|
6160
|
-
* @param config -
|
|
6235
|
+
* @param config - Optional workspace configuration
|
|
6161
6236
|
*/
|
|
6162
6237
|
constructor(projectDir, config) {
|
|
6163
|
-
this.
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
this.
|
|
6167
|
-
this.
|
|
6168
|
-
}
|
|
6169
|
-
/**
|
|
6170
|
-
* Initialize workspace structure
|
|
6171
|
-
*
|
|
6172
|
-
* Creates all necessary directories for workspace management.
|
|
6173
|
-
*
|
|
6174
|
-
* @example
|
|
6175
|
-
* ```typescript
|
|
6176
|
-
* await workspaceManager.initialize();
|
|
6177
|
-
* ```
|
|
6178
|
-
*/
|
|
6179
|
-
async initialize() {
|
|
6180
|
-
await fs.mkdir(this.workspacesRoot, { recursive: true });
|
|
6181
|
-
await fs.mkdir(this.sharedRoot, { recursive: true });
|
|
6182
|
-
await fs.mkdir(this.sessionsRoot, { recursive: true });
|
|
6183
|
-
await fs.mkdir(this.persistentRoot, { recursive: true });
|
|
6184
|
-
logger.debug("Workspace structure initialized", {
|
|
6185
|
-
workspacesRoot: this.workspacesRoot
|
|
6186
|
-
});
|
|
6238
|
+
this.projectDir = projectDir;
|
|
6239
|
+
const prdPath = config?.prdPath ?? "automatosx/PRD";
|
|
6240
|
+
const tmpPath = config?.tmpPath ?? "automatosx/tmp";
|
|
6241
|
+
this.prdDir = path2.join(projectDir, prdPath);
|
|
6242
|
+
this.tmpDir = path2.join(projectDir, tmpPath);
|
|
6187
6243
|
}
|
|
6188
6244
|
/**
|
|
6189
|
-
*
|
|
6245
|
+
* Ensure PRD/tmp directories exist (lazy initialization with caching)
|
|
6190
6246
|
*
|
|
6191
|
-
*
|
|
6192
|
-
*
|
|
6193
|
-
*
|
|
6194
|
-
* @example
|
|
6195
|
-
* ```typescript
|
|
6196
|
-
* await workspaceManager.createSessionWorkspace('session-123');
|
|
6197
|
-
* ```
|
|
6247
|
+
* Creates directories only when needed, not during init.
|
|
6248
|
+
* Uses caching to avoid repeated filesystem checks.
|
|
6198
6249
|
*/
|
|
6199
|
-
async
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
const outputsDir = path2.join(sessionDir, "outputs");
|
|
6203
|
-
try {
|
|
6204
|
-
await fs.mkdir(sessionDir, { recursive: true });
|
|
6205
|
-
await fs.mkdir(specsDir, { recursive: true });
|
|
6206
|
-
await fs.mkdir(outputsDir, { recursive: true });
|
|
6207
|
-
logger.info("Session workspace created", {
|
|
6208
|
-
sessionId,
|
|
6209
|
-
path: sessionDir
|
|
6210
|
-
});
|
|
6211
|
-
} catch (error) {
|
|
6212
|
-
throw new WorkspaceError(
|
|
6213
|
-
`Failed to create session workspace: ${error.message}`,
|
|
6214
|
-
sessionDir,
|
|
6215
|
-
"creation_failed"
|
|
6216
|
-
);
|
|
6250
|
+
async ensureDirectories() {
|
|
6251
|
+
if (this.directoriesEnsured) {
|
|
6252
|
+
return;
|
|
6217
6253
|
}
|
|
6254
|
+
await fs.mkdir(this.prdDir, { recursive: true });
|
|
6255
|
+
await fs.mkdir(this.tmpDir, { recursive: true });
|
|
6256
|
+
this.directoriesEnsured = true;
|
|
6257
|
+
logger.debug("Workspace directories ensured", {
|
|
6258
|
+
prdDir: this.prdDir,
|
|
6259
|
+
tmpDir: this.tmpDir
|
|
6260
|
+
});
|
|
6218
6261
|
}
|
|
6219
6262
|
/**
|
|
6220
|
-
*
|
|
6221
|
-
*
|
|
6222
|
-
* @param sessionId - Session ID
|
|
6223
|
-
* @param agentName - Agent name
|
|
6224
|
-
* @returns Path to agent's output directory
|
|
6225
|
-
*/
|
|
6226
|
-
getAgentOutputDir(sessionId, agentName) {
|
|
6227
|
-
return path2.join(this.getSessionDir(sessionId), "outputs", agentName);
|
|
6228
|
-
}
|
|
6229
|
-
/**
|
|
6230
|
-
* Validate session ID format (must be valid UUID v4)
|
|
6263
|
+
* Validate file size
|
|
6231
6264
|
*
|
|
6232
|
-
* @param
|
|
6233
|
-
* @throws {
|
|
6265
|
+
* @param content - File content
|
|
6266
|
+
* @throws {Error} If file size exceeds MAX_FILE_SIZE
|
|
6234
6267
|
*/
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
"invalid_session_id"
|
|
6268
|
+
validateFileSize(content) {
|
|
6269
|
+
const sizeInBytes = Buffer.byteLength(content, "utf-8");
|
|
6270
|
+
if (sizeInBytes > _WorkspaceManager.MAX_FILE_SIZE) {
|
|
6271
|
+
throw new Error(
|
|
6272
|
+
`File too large: ${sizeInBytes} bytes (max: ${_WorkspaceManager.MAX_FILE_SIZE} bytes)`
|
|
6241
6273
|
);
|
|
6242
6274
|
}
|
|
6243
6275
|
}
|
|
6244
6276
|
/**
|
|
6245
|
-
*
|
|
6277
|
+
* Validate path security (prevent path traversal attacks)
|
|
6246
6278
|
*
|
|
6247
|
-
*
|
|
6248
|
-
*
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
this.validateSessionId(sessionId);
|
|
6252
|
-
return path2.join(this.sessionsRoot, sessionId);
|
|
6253
|
-
}
|
|
6254
|
-
/**
|
|
6255
|
-
* Validate that a file path is safe (prevents path traversal attacks)
|
|
6279
|
+
* Security checks:
|
|
6280
|
+
* 1. Reject absolute paths
|
|
6281
|
+
* 2. Normalize path and check for '..' at start
|
|
6282
|
+
* 3. Verify resolved path is within base directory
|
|
6256
6283
|
*
|
|
6257
6284
|
* @param baseDir - Base directory that file must be within
|
|
6258
6285
|
* @param filePath - Relative file path to validate
|
|
6259
6286
|
* @returns Resolved absolute path
|
|
6260
|
-
* @throws {
|
|
6261
|
-
*
|
|
6262
|
-
* Security checks:
|
|
6263
|
-
* 1. Normalize path to resolve '..' and '.'
|
|
6264
|
-
* 2. Resolve to absolute path
|
|
6265
|
-
* 3. Verify resolved path is within base directory
|
|
6266
|
-
* 4. Prevent symlink attacks by checking real path
|
|
6287
|
+
* @throws {Error} If path is unsafe
|
|
6267
6288
|
*/
|
|
6268
|
-
|
|
6289
|
+
validatePath(baseDir, filePath) {
|
|
6290
|
+
if (!filePath || !filePath.trim()) {
|
|
6291
|
+
throw new Error("File path cannot be empty");
|
|
6292
|
+
}
|
|
6269
6293
|
if (path2.isAbsolute(filePath)) {
|
|
6270
|
-
throw new
|
|
6271
|
-
`Absolute paths not allowed: ${filePath}`,
|
|
6272
|
-
filePath,
|
|
6273
|
-
"permission_denied"
|
|
6274
|
-
);
|
|
6294
|
+
throw new Error(`Absolute paths not allowed: ${filePath}`);
|
|
6275
6295
|
}
|
|
6276
6296
|
const normalized = path2.normalize(filePath);
|
|
6277
6297
|
if (normalized.startsWith("..")) {
|
|
6278
|
-
throw new
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
);
|
|
6298
|
+
throw new Error(`Path traversal detected: ${filePath}`);
|
|
6299
|
+
}
|
|
6300
|
+
if (normalized === "." || normalized === "./") {
|
|
6301
|
+
throw new Error("Cannot write to base directory itself");
|
|
6283
6302
|
}
|
|
6284
6303
|
const resolved = path2.resolve(baseDir, normalized);
|
|
6285
6304
|
const resolvedBase = path2.resolve(baseDir);
|
|
6286
6305
|
if (!resolved.startsWith(resolvedBase + path2.sep) && resolved !== resolvedBase) {
|
|
6287
|
-
throw new
|
|
6288
|
-
`Path outside workspace: ${filePath}`,
|
|
6289
|
-
filePath,
|
|
6290
|
-
"permission_denied"
|
|
6291
|
-
);
|
|
6306
|
+
throw new Error(`Path outside workspace: ${filePath}`);
|
|
6292
6307
|
}
|
|
6293
6308
|
return resolved;
|
|
6294
6309
|
}
|
|
6295
6310
|
/**
|
|
6296
|
-
*
|
|
6311
|
+
* Write PRD document
|
|
6297
6312
|
*
|
|
6298
|
-
*
|
|
6299
|
-
*
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
return path2.join(this.workspacesRoot, agentName);
|
|
6303
|
-
}
|
|
6304
|
-
/**
|
|
6305
|
-
* Write file to session workspace (agent's output area)
|
|
6313
|
+
* PRD documents are permanent and should contain:
|
|
6314
|
+
* - Feature designs (feature-*.md)
|
|
6315
|
+
* - Workflow plans (workflow-*.md)
|
|
6316
|
+
* - Architecture proposals (proposal-*.md)
|
|
6306
6317
|
*
|
|
6307
|
-
* @param
|
|
6308
|
-
* @param agentName - Agent writing the file
|
|
6309
|
-
* @param filePath - Relative file path within agent's output
|
|
6318
|
+
* @param fileName - Relative file path within PRD/
|
|
6310
6319
|
* @param content - File content
|
|
6311
|
-
* @
|
|
6312
|
-
* @throws {WorkspaceError} If write fails, path is invalid, or permission denied
|
|
6320
|
+
* @throws {Error} If path is invalid, file too large, or write fails
|
|
6313
6321
|
*
|
|
6314
6322
|
* @example
|
|
6315
6323
|
* ```typescript
|
|
6316
|
-
* await workspaceManager.
|
|
6317
|
-
* 'session-123',
|
|
6318
|
-
* 'backend',
|
|
6319
|
-
* 'api/users.ts',
|
|
6320
|
-
* 'export interface User { ... }',
|
|
6321
|
-
* backendProfile // Verify caller is actually 'backend'
|
|
6322
|
-
* );
|
|
6324
|
+
* await workspaceManager.writePRD('feature-auth.md', '# Authentication Feature...');
|
|
6323
6325
|
* ```
|
|
6324
6326
|
*/
|
|
6325
|
-
async
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
}
|
|
6333
|
-
const agentOutputDir = this.getAgentOutputDir(sessionId, agentName);
|
|
6334
|
-
const fullPath = await this.validatePath(agentOutputDir, filePath);
|
|
6335
|
-
const fileSize = Buffer.byteLength(content, "utf-8");
|
|
6336
|
-
if (fileSize > this.maxFileSize) {
|
|
6337
|
-
throw new WorkspaceError(
|
|
6338
|
-
`File too large: ${fileSize} bytes (max: ${this.maxFileSize} bytes)`,
|
|
6339
|
-
fullPath,
|
|
6340
|
-
"quota_exceeded"
|
|
6341
|
-
);
|
|
6342
|
-
}
|
|
6343
|
-
try {
|
|
6344
|
-
await fs.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
6345
|
-
await fs.writeFile(fullPath, content, "utf-8");
|
|
6346
|
-
logger.debug("File written to session workspace", {
|
|
6347
|
-
sessionId,
|
|
6348
|
-
agentName,
|
|
6349
|
-
filePath,
|
|
6350
|
-
size: content.length
|
|
6351
|
-
});
|
|
6352
|
-
} catch (error) {
|
|
6353
|
-
throw new WorkspaceError(
|
|
6354
|
-
`Failed to write file: ${error.message}`,
|
|
6355
|
-
fullPath,
|
|
6356
|
-
"permission_denied"
|
|
6357
|
-
);
|
|
6358
|
-
}
|
|
6327
|
+
async writePRD(fileName, content) {
|
|
6328
|
+
await this.ensureDirectories();
|
|
6329
|
+
this.validateFileSize(content);
|
|
6330
|
+
const fullPath = this.validatePath(this.prdDir, fileName);
|
|
6331
|
+
await fs.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
6332
|
+
await fs.writeFile(fullPath, content, "utf-8");
|
|
6333
|
+
logger.info("PRD document created", { fileName, size: content.length });
|
|
6359
6334
|
}
|
|
6360
6335
|
/**
|
|
6361
|
-
*
|
|
6336
|
+
* Write temporary file
|
|
6362
6337
|
*
|
|
6363
|
-
*
|
|
6364
|
-
*
|
|
6338
|
+
* Temporary files should contain:
|
|
6339
|
+
* - Test scripts
|
|
6340
|
+
* - Analysis tools
|
|
6341
|
+
* - Temporary reports
|
|
6365
6342
|
*
|
|
6366
|
-
*
|
|
6367
|
-
*
|
|
6368
|
-
* @param
|
|
6369
|
-
* @param
|
|
6370
|
-
* @
|
|
6371
|
-
* @throws {WorkspaceError} If permission denied or file not found
|
|
6343
|
+
* These files can be cleaned up anytime.
|
|
6344
|
+
*
|
|
6345
|
+
* @param fileName - Relative file path within tmp/
|
|
6346
|
+
* @param content - File content
|
|
6347
|
+
* @throws {Error} If path is invalid, file too large, or write fails
|
|
6372
6348
|
*
|
|
6373
6349
|
* @example
|
|
6374
6350
|
* ```typescript
|
|
6375
|
-
*
|
|
6376
|
-
* frontendProfile,
|
|
6377
|
-
* 'backend',
|
|
6378
|
-
* 'session-123',
|
|
6379
|
-
* 'api-spec.md'
|
|
6380
|
-
* );
|
|
6351
|
+
* await workspaceManager.writeTmp('test.sh', '#!/bin/bash\necho "test"');
|
|
6381
6352
|
* ```
|
|
6382
6353
|
*/
|
|
6383
|
-
async
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
);
|
|
6391
|
-
}
|
|
6392
|
-
const agentOutputDir = this.getAgentOutputDir(sessionId, targetAgent);
|
|
6393
|
-
const fullPath = await this.validatePath(agentOutputDir, filePath);
|
|
6394
|
-
try {
|
|
6395
|
-
const content = await fs.readFile(fullPath, "utf-8");
|
|
6396
|
-
logger.debug("File read from agent workspace", {
|
|
6397
|
-
requestingAgent: requestingAgent.name,
|
|
6398
|
-
targetAgent,
|
|
6399
|
-
sessionId,
|
|
6400
|
-
filePath
|
|
6401
|
-
});
|
|
6402
|
-
return content;
|
|
6403
|
-
} catch (error) {
|
|
6404
|
-
const err = error;
|
|
6405
|
-
if (err.code === "ENOENT") {
|
|
6406
|
-
throw new WorkspaceError(
|
|
6407
|
-
`File not found: ${filePath}`,
|
|
6408
|
-
fullPath,
|
|
6409
|
-
"not_found"
|
|
6410
|
-
);
|
|
6411
|
-
}
|
|
6412
|
-
throw new WorkspaceError(
|
|
6413
|
-
`Failed to read file: ${err.message}`,
|
|
6414
|
-
fullPath,
|
|
6415
|
-
"permission_denied"
|
|
6416
|
-
);
|
|
6417
|
-
}
|
|
6354
|
+
async writeTmp(fileName, content) {
|
|
6355
|
+
await this.ensureDirectories();
|
|
6356
|
+
this.validateFileSize(content);
|
|
6357
|
+
const fullPath = this.validatePath(this.tmpDir, fileName);
|
|
6358
|
+
await fs.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
6359
|
+
await fs.writeFile(fullPath, content, "utf-8");
|
|
6360
|
+
logger.debug("Temporary file created", { fileName, size: content.length });
|
|
6418
6361
|
}
|
|
6419
6362
|
/**
|
|
6420
|
-
*
|
|
6421
|
-
*
|
|
6422
|
-
* Requires permission check: agent must have canWriteToShared enabled.
|
|
6363
|
+
* Read PRD document
|
|
6423
6364
|
*
|
|
6424
|
-
* @param
|
|
6425
|
-
* @
|
|
6426
|
-
* @
|
|
6427
|
-
* @throws {WorkspaceError} If permission denied or write fails
|
|
6365
|
+
* @param fileName - Relative file path within PRD/
|
|
6366
|
+
* @returns File content
|
|
6367
|
+
* @throws {Error} If path is invalid or file not found
|
|
6428
6368
|
*
|
|
6429
6369
|
* @example
|
|
6430
6370
|
* ```typescript
|
|
6431
|
-
* await workspaceManager.
|
|
6432
|
-
* agentProfile,
|
|
6433
|
-
* 'templates/api-template.ts',
|
|
6434
|
-
* 'export const template = ...'
|
|
6435
|
-
* );
|
|
6371
|
+
* const content = await workspaceManager.readPRD('feature-auth.md');
|
|
6436
6372
|
* ```
|
|
6437
6373
|
*/
|
|
6438
|
-
async
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
`Agent '${agent.name}' is not authorized to write to shared workspace`,
|
|
6442
|
-
void 0,
|
|
6443
|
-
"permission_denied"
|
|
6444
|
-
);
|
|
6445
|
-
}
|
|
6446
|
-
const fullPath = await this.validatePath(this.persistentRoot, filePath);
|
|
6447
|
-
const fileSize = Buffer.byteLength(content, "utf-8");
|
|
6448
|
-
if (fileSize > this.maxFileSize) {
|
|
6449
|
-
throw new WorkspaceError(
|
|
6450
|
-
`File too large: ${fileSize} bytes (max: ${this.maxFileSize} bytes)`,
|
|
6451
|
-
fullPath,
|
|
6452
|
-
"quota_exceeded"
|
|
6453
|
-
);
|
|
6454
|
-
}
|
|
6455
|
-
try {
|
|
6456
|
-
await fs.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
6457
|
-
await fs.writeFile(fullPath, content, "utf-8");
|
|
6458
|
-
logger.info("File written to persistent shared workspace", {
|
|
6459
|
-
agentName: agent.name,
|
|
6460
|
-
filePath,
|
|
6461
|
-
size: fileSize
|
|
6462
|
-
});
|
|
6463
|
-
} catch (error) {
|
|
6464
|
-
throw new WorkspaceError(
|
|
6465
|
-
`Failed to write to shared workspace: ${error.message}`,
|
|
6466
|
-
fullPath,
|
|
6467
|
-
"permission_denied"
|
|
6468
|
-
);
|
|
6469
|
-
}
|
|
6374
|
+
async readPRD(fileName) {
|
|
6375
|
+
const fullPath = this.validatePath(this.prdDir, fileName);
|
|
6376
|
+
return await fs.readFile(fullPath, "utf-8");
|
|
6470
6377
|
}
|
|
6471
6378
|
/**
|
|
6472
|
-
*
|
|
6379
|
+
* Read temporary file
|
|
6380
|
+
*
|
|
6381
|
+
* @param fileName - Relative file path within tmp/
|
|
6382
|
+
* @returns File content
|
|
6383
|
+
* @throws {Error} If path is invalid or file not found
|
|
6384
|
+
*/
|
|
6385
|
+
async readTmp(fileName) {
|
|
6386
|
+
const fullPath = this.validatePath(this.tmpDir, fileName);
|
|
6387
|
+
return await fs.readFile(fullPath, "utf-8");
|
|
6388
|
+
}
|
|
6389
|
+
/**
|
|
6390
|
+
* List all PRD documents
|
|
6473
6391
|
*
|
|
6474
|
-
* @param sessionId - Session ID
|
|
6475
|
-
* @param agentName - Agent name
|
|
6476
6392
|
* @returns Array of relative file paths
|
|
6477
|
-
* @throws {WorkspaceError} If listing fails
|
|
6478
6393
|
*
|
|
6479
6394
|
* @example
|
|
6480
6395
|
* ```typescript
|
|
6481
|
-
* const
|
|
6482
|
-
*
|
|
6396
|
+
* const prdFiles = await workspaceManager.listPRD();
|
|
6397
|
+
* // ['feature-auth.md', 'workflow-ci-cd.md']
|
|
6483
6398
|
* ```
|
|
6484
6399
|
*/
|
|
6485
|
-
async
|
|
6486
|
-
const agentOutputDir = this.getAgentOutputDir(sessionId, agentName);
|
|
6400
|
+
async listPRD() {
|
|
6487
6401
|
try {
|
|
6488
|
-
|
|
6489
|
-
await this.
|
|
6490
|
-
return files;
|
|
6402
|
+
await this.ensureDirectories();
|
|
6403
|
+
return await this.listFiles(this.prdDir);
|
|
6491
6404
|
} catch (error) {
|
|
6492
6405
|
const err = error;
|
|
6493
6406
|
if (err.code === "ENOENT") {
|
|
6494
6407
|
return [];
|
|
6495
6408
|
}
|
|
6496
|
-
throw
|
|
6497
|
-
`Failed to list files: ${err.message}`,
|
|
6498
|
-
agentOutputDir,
|
|
6499
|
-
"permission_denied"
|
|
6500
|
-
);
|
|
6409
|
+
throw error;
|
|
6501
6410
|
}
|
|
6502
6411
|
}
|
|
6503
6412
|
/**
|
|
6504
|
-
*
|
|
6413
|
+
* List all temporary files
|
|
6505
6414
|
*
|
|
6506
|
-
* @
|
|
6507
|
-
* @param baseDir - Base directory for relative paths
|
|
6508
|
-
* @param files - Array to collect file paths
|
|
6415
|
+
* @returns Array of relative file paths
|
|
6509
6416
|
*/
|
|
6510
|
-
async
|
|
6417
|
+
async listTmp() {
|
|
6511
6418
|
try {
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
} else {
|
|
6519
|
-
const relativePath = path2.relative(baseDir, fullPath);
|
|
6520
|
-
files.push(relativePath);
|
|
6521
|
-
}
|
|
6522
|
-
} catch (err) {
|
|
6523
|
-
const error = err;
|
|
6524
|
-
if (error.code === "ENOENT") {
|
|
6525
|
-
logger.debug("File removed during traversal", { path: fullPath });
|
|
6526
|
-
continue;
|
|
6527
|
-
}
|
|
6528
|
-
throw err;
|
|
6529
|
-
}
|
|
6530
|
-
}
|
|
6531
|
-
} catch (err) {
|
|
6532
|
-
const error = err;
|
|
6533
|
-
if (error.code === "ENOENT") {
|
|
6534
|
-
logger.debug("Directory removed during traversal", { path: dir });
|
|
6535
|
-
return;
|
|
6419
|
+
await this.ensureDirectories();
|
|
6420
|
+
return await this.listFiles(this.tmpDir);
|
|
6421
|
+
} catch (error) {
|
|
6422
|
+
const err = error;
|
|
6423
|
+
if (err.code === "ENOENT") {
|
|
6424
|
+
return [];
|
|
6536
6425
|
}
|
|
6537
|
-
throw
|
|
6426
|
+
throw error;
|
|
6538
6427
|
}
|
|
6539
6428
|
}
|
|
6540
6429
|
/**
|
|
6541
|
-
*
|
|
6542
|
-
*
|
|
6543
|
-
* Removes session workspaces older than specified days.
|
|
6544
|
-
* Should be called in sync with SessionManager cleanup.
|
|
6430
|
+
* Clean up temporary files (recursively)
|
|
6545
6431
|
*
|
|
6546
|
-
* @param
|
|
6547
|
-
* @returns Number of
|
|
6432
|
+
* @param olderThanDays - Optional: Only remove files older than N days
|
|
6433
|
+
* @returns Number of files removed
|
|
6548
6434
|
*
|
|
6549
6435
|
* @example
|
|
6550
6436
|
* ```typescript
|
|
6551
|
-
*
|
|
6552
|
-
*
|
|
6553
|
-
*
|
|
6437
|
+
* // Remove all temporary files
|
|
6438
|
+
* await workspaceManager.cleanupTmp();
|
|
6439
|
+
*
|
|
6440
|
+
* // Remove files older than 7 days
|
|
6441
|
+
* await workspaceManager.cleanupTmp(7);
|
|
6554
6442
|
* ```
|
|
6555
6443
|
*/
|
|
6556
|
-
async
|
|
6444
|
+
async cleanupTmp(olderThanDays) {
|
|
6557
6445
|
try {
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
let removed = 0;
|
|
6561
|
-
for (const sessionId of sessionDirs) {
|
|
6562
|
-
if (!activeSet.has(sessionId)) {
|
|
6563
|
-
try {
|
|
6564
|
-
const sessionDir = this.getSessionDir(sessionId);
|
|
6565
|
-
await fs.rm(sessionDir, { recursive: true, force: true });
|
|
6566
|
-
removed++;
|
|
6567
|
-
logger.debug("Session workspace removed", { sessionId });
|
|
6568
|
-
} catch (err) {
|
|
6569
|
-
if (err instanceof WorkspaceError && err.reason === "invalid_session_id") {
|
|
6570
|
-
logger.warn("Skipping invalid session directory", { sessionId });
|
|
6571
|
-
continue;
|
|
6572
|
-
}
|
|
6573
|
-
throw err;
|
|
6574
|
-
}
|
|
6575
|
-
}
|
|
6576
|
-
}
|
|
6577
|
-
if (removed > 0) {
|
|
6578
|
-
logger.info("Session workspaces cleaned up", { removed });
|
|
6579
|
-
}
|
|
6580
|
-
return removed;
|
|
6446
|
+
await this.ensureDirectories();
|
|
6447
|
+
return await this.cleanupDirectory(this.tmpDir, olderThanDays);
|
|
6581
6448
|
} catch (error) {
|
|
6582
|
-
|
|
6583
|
-
|
|
6449
|
+
const err = error;
|
|
6450
|
+
if (err.code === "ENOENT") {
|
|
6451
|
+
return 0;
|
|
6452
|
+
}
|
|
6453
|
+
logger.warn("Failed to cleanup temporary files", {
|
|
6454
|
+
error: err.message
|
|
6584
6455
|
});
|
|
6585
6456
|
return 0;
|
|
6586
6457
|
}
|
|
6587
6458
|
}
|
|
6588
6459
|
/**
|
|
6589
|
-
*
|
|
6460
|
+
* Helper: Clean up directory recursively
|
|
6590
6461
|
*
|
|
6591
|
-
*
|
|
6592
|
-
*
|
|
6593
|
-
*
|
|
6594
|
-
* @param sessionIds - Session IDs to remove
|
|
6595
|
-
* @returns Number of workspaces removed
|
|
6596
|
-
*
|
|
6597
|
-
* @example
|
|
6598
|
-
* ```typescript
|
|
6599
|
-
* const result = await sessionManager.cleanupOldSessions(7);
|
|
6600
|
-
* await workspaceManager.cleanupSessionWorkspaces(result.removedSessionIds);
|
|
6601
|
-
* ```
|
|
6462
|
+
* @param dir - Directory to clean
|
|
6463
|
+
* @param olderThanDays - Optional: Only remove files older than N days
|
|
6464
|
+
* @returns Number of files removed
|
|
6602
6465
|
*/
|
|
6603
|
-
async
|
|
6466
|
+
async cleanupDirectory(dir, olderThanDays) {
|
|
6604
6467
|
let removed = 0;
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
if (
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6468
|
+
try {
|
|
6469
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
6470
|
+
for (const entry of entries) {
|
|
6471
|
+
const filePath = path2.join(dir, entry.name);
|
|
6472
|
+
if (entry.isDirectory()) {
|
|
6473
|
+
removed += await this.cleanupDirectory(filePath, olderThanDays);
|
|
6474
|
+
continue;
|
|
6475
|
+
}
|
|
6476
|
+
if (olderThanDays !== void 0) {
|
|
6477
|
+
try {
|
|
6478
|
+
const stats = await fs.stat(filePath);
|
|
6479
|
+
const ageInDays = (Date.now() - stats.mtimeMs) / (1e3 * 60 * 60 * 24);
|
|
6480
|
+
if (ageInDays < olderThanDays) {
|
|
6481
|
+
continue;
|
|
6482
|
+
}
|
|
6483
|
+
} catch (statError) {
|
|
6484
|
+
continue;
|
|
6485
|
+
}
|
|
6486
|
+
}
|
|
6487
|
+
try {
|
|
6488
|
+
await fs.unlink(filePath);
|
|
6489
|
+
removed++;
|
|
6490
|
+
} catch (rmError) {
|
|
6491
|
+
logger.warn("Failed to remove temporary file", {
|
|
6492
|
+
path: path2.relative(this.tmpDir, filePath),
|
|
6493
|
+
error: rmError.message
|
|
6617
6494
|
});
|
|
6618
6495
|
}
|
|
6619
6496
|
}
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6497
|
+
if (removed > 0) {
|
|
6498
|
+
logger.info("Temporary files cleaned up", { removed, olderThanDays });
|
|
6499
|
+
}
|
|
6500
|
+
} catch (error) {
|
|
6501
|
+
const err = error;
|
|
6502
|
+
if (err.code === "ENOENT") {
|
|
6503
|
+
return removed;
|
|
6504
|
+
}
|
|
6505
|
+
throw error;
|
|
6626
6506
|
}
|
|
6627
6507
|
return removed;
|
|
6628
6508
|
}
|
|
@@ -6634,70 +6514,95 @@ var WorkspaceManager = class _WorkspaceManager {
|
|
|
6634
6514
|
* @example
|
|
6635
6515
|
* ```typescript
|
|
6636
6516
|
* const stats = await workspaceManager.getStats();
|
|
6637
|
-
* console.log(
|
|
6517
|
+
* console.log(`PRD files: ${stats.prdFiles}, Tmp files: ${stats.tmpFiles}`);
|
|
6638
6518
|
* ```
|
|
6639
6519
|
*/
|
|
6640
6520
|
async getStats() {
|
|
6641
6521
|
try {
|
|
6642
|
-
|
|
6643
|
-
const
|
|
6644
|
-
const
|
|
6645
|
-
|
|
6646
|
-
)
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6522
|
+
await this.ensureDirectories();
|
|
6523
|
+
const prdFiles = await this.listFiles(this.prdDir);
|
|
6524
|
+
const tmpFiles = await this.listFiles(this.tmpDir);
|
|
6525
|
+
let prdSize = 0;
|
|
6526
|
+
for (const file of prdFiles) {
|
|
6527
|
+
try {
|
|
6528
|
+
const stats = await fs.stat(path2.join(this.prdDir, file));
|
|
6529
|
+
prdSize += stats.size;
|
|
6530
|
+
} catch {
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
let tmpSize = 0;
|
|
6534
|
+
for (const file of tmpFiles) {
|
|
6535
|
+
try {
|
|
6536
|
+
const stats = await fs.stat(path2.join(this.tmpDir, file));
|
|
6537
|
+
tmpSize += stats.size;
|
|
6538
|
+
} catch {
|
|
6539
|
+
}
|
|
6540
|
+
}
|
|
6541
|
+
return {
|
|
6542
|
+
prdFiles: prdFiles.length,
|
|
6543
|
+
tmpFiles: tmpFiles.length,
|
|
6544
|
+
totalSizeBytes: prdSize + tmpSize,
|
|
6545
|
+
prdSizeBytes: prdSize,
|
|
6546
|
+
tmpSizeBytes: tmpSize
|
|
6651
6547
|
};
|
|
6652
|
-
return stats;
|
|
6653
6548
|
} catch (error) {
|
|
6654
6549
|
logger.warn("Failed to get workspace stats", {
|
|
6655
6550
|
error: error.message
|
|
6656
6551
|
});
|
|
6657
6552
|
return {
|
|
6658
|
-
|
|
6553
|
+
prdFiles: 0,
|
|
6554
|
+
tmpFiles: 0,
|
|
6659
6555
|
totalSizeBytes: 0,
|
|
6660
|
-
|
|
6556
|
+
prdSizeBytes: 0,
|
|
6557
|
+
tmpSizeBytes: 0
|
|
6661
6558
|
};
|
|
6662
6559
|
}
|
|
6663
6560
|
}
|
|
6664
6561
|
/**
|
|
6665
|
-
*
|
|
6562
|
+
* Helper: List files recursively in a directory
|
|
6666
6563
|
*
|
|
6667
|
-
* @param
|
|
6668
|
-
*
|
|
6669
|
-
* @example
|
|
6670
|
-
* ```typescript
|
|
6671
|
-
* await workspaceManager.createAgentWorkspace('backend');
|
|
6672
|
-
* ```
|
|
6564
|
+
* @param dir - Directory to scan
|
|
6565
|
+
* @returns Array of relative file paths
|
|
6673
6566
|
*/
|
|
6674
|
-
async
|
|
6675
|
-
const
|
|
6676
|
-
const draftsDir = path2.join(agentDir, "drafts");
|
|
6677
|
-
const tempDir = path2.join(agentDir, "temp");
|
|
6567
|
+
async listFiles(dir) {
|
|
6568
|
+
const files = [];
|
|
6678
6569
|
try {
|
|
6679
|
-
await fs.
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6570
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
6571
|
+
for (const entry of entries) {
|
|
6572
|
+
const fullPath = path2.join(dir, entry.name);
|
|
6573
|
+
const relativePath = path2.relative(dir, fullPath);
|
|
6574
|
+
try {
|
|
6575
|
+
if (entry.isDirectory()) {
|
|
6576
|
+
const subFiles = await this.listFiles(fullPath);
|
|
6577
|
+
files.push(...subFiles.map((f) => path2.join(relativePath, f)));
|
|
6578
|
+
} else {
|
|
6579
|
+
files.push(relativePath);
|
|
6580
|
+
}
|
|
6581
|
+
} catch (err) {
|
|
6582
|
+
const error = err;
|
|
6583
|
+
if (error.code === "ENOENT") {
|
|
6584
|
+
logger.debug("File removed during traversal", { path: relativePath });
|
|
6585
|
+
continue;
|
|
6586
|
+
}
|
|
6587
|
+
throw err;
|
|
6588
|
+
}
|
|
6589
|
+
}
|
|
6590
|
+
} catch (err) {
|
|
6591
|
+
const error = err;
|
|
6592
|
+
if (error.code === "ENOENT") {
|
|
6593
|
+
logger.debug("Directory removed during traversal", { path: dir });
|
|
6594
|
+
return files;
|
|
6595
|
+
}
|
|
6596
|
+
throw err;
|
|
6692
6597
|
}
|
|
6598
|
+
return files;
|
|
6693
6599
|
}
|
|
6694
6600
|
};
|
|
6695
6601
|
|
|
6696
6602
|
// src/agents/context-manager.ts
|
|
6697
6603
|
init_esm_shims();
|
|
6698
6604
|
init_logger();
|
|
6699
|
-
import {
|
|
6700
|
-
import { join as join4, resolve as resolve5 } from "path";
|
|
6605
|
+
import { join as join4 } from "path";
|
|
6701
6606
|
var PROVIDER_ALIASES = {
|
|
6702
6607
|
"claude": "claude-code",
|
|
6703
6608
|
"gemini": "gemini-cli",
|
|
@@ -6734,16 +6639,7 @@ var ContextManager = class {
|
|
|
6734
6639
|
const workingDir = process.cwd();
|
|
6735
6640
|
const agentDirName = agent.name.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
6736
6641
|
const agentWorkspace = join4(projectDir, ".automatosx", "workspaces", agentDirName);
|
|
6737
|
-
|
|
6738
|
-
const resolvedProject = resolve5(projectDir);
|
|
6739
|
-
if (!resolvedWorkspace.startsWith(resolvedProject)) {
|
|
6740
|
-
throw PathError.traversal(agentWorkspace);
|
|
6741
|
-
}
|
|
6742
|
-
await mkdir4(agentWorkspace, { recursive: true });
|
|
6743
|
-
if (process.platform !== "win32") {
|
|
6744
|
-
await chmod(agentWorkspace, 448);
|
|
6745
|
-
}
|
|
6746
|
-
logger.debug("Agent workspace created", { workspace: agentWorkspace });
|
|
6642
|
+
logger.debug("Agent workspace path defined (not created)", { workspace: agentWorkspace });
|
|
6747
6643
|
let session;
|
|
6748
6644
|
if (options?.sessionId) {
|
|
6749
6645
|
if (!this.config.sessionManager) {
|
|
@@ -6763,7 +6659,7 @@ var ContextManager = class {
|
|
|
6763
6659
|
if (this.config.workspaceManager && this.config.profileLoader) {
|
|
6764
6660
|
const allAgents = await this.config.profileLoader.listProfiles();
|
|
6765
6661
|
const availableAgents = allAgents.filter((a) => a !== agent.name);
|
|
6766
|
-
const sharedWorkspace =
|
|
6662
|
+
const sharedWorkspace = join4(projectDir, "automatosx", "PRD");
|
|
6767
6663
|
const maxDelegationDepth = agent.orchestration?.maxDelegationDepth ?? 2;
|
|
6768
6664
|
orchestration = {
|
|
6769
6665
|
isDelegationEnabled: true,
|
|
@@ -7016,19 +6912,20 @@ var ContextManager = class {
|
|
|
7016
6912
|
return provider;
|
|
7017
6913
|
}
|
|
7018
6914
|
/**
|
|
7019
|
-
* Cleanup context
|
|
6915
|
+
* Cleanup context
|
|
6916
|
+
*
|
|
6917
|
+
* v5.2: No cleanup needed - agent workspaces no longer created
|
|
7020
6918
|
*/
|
|
7021
6919
|
async cleanup(context) {
|
|
7022
|
-
logger.debug("Context cleanup", {
|
|
7023
|
-
agent: context.agent.name
|
|
7024
|
-
workspace: context.agentWorkspace
|
|
6920
|
+
logger.debug("Context cleanup (no-op in v5.2)", {
|
|
6921
|
+
agent: context.agent.name
|
|
7025
6922
|
});
|
|
7026
6923
|
}
|
|
7027
6924
|
};
|
|
7028
6925
|
|
|
7029
6926
|
// src/agents/profile-loader.ts
|
|
7030
6927
|
init_esm_shims();
|
|
7031
|
-
import { readFile as readFile3, readdir as
|
|
6928
|
+
import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
|
|
7032
6929
|
import { join as join5, extname as extname2, basename, dirname as dirname6 } from "path";
|
|
7033
6930
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7034
6931
|
import { load as load2 } from "js-yaml";
|
|
@@ -7150,7 +7047,7 @@ var ProfileLoader = class {
|
|
|
7150
7047
|
*/
|
|
7151
7048
|
async listProfilesFromDir(dir) {
|
|
7152
7049
|
try {
|
|
7153
|
-
const files = await
|
|
7050
|
+
const files = await readdir3(dir);
|
|
7154
7051
|
return files.filter((file) => extname2(file) === ".yaml" || extname2(file) === ".yml").map((file) => basename(file, extname2(file)));
|
|
7155
7052
|
} catch (error) {
|
|
7156
7053
|
if (error.code === "ENOENT") {
|
|
@@ -7244,7 +7141,7 @@ var ProfileLoader = class {
|
|
|
7244
7141
|
async listProfiles() {
|
|
7245
7142
|
const profileSet = /* @__PURE__ */ new Set();
|
|
7246
7143
|
try {
|
|
7247
|
-
const files = await
|
|
7144
|
+
const files = await readdir3(this.profilesDir);
|
|
7248
7145
|
const profiles = files.filter((file) => extname2(file) === ".yaml" || extname2(file) === ".yml").map((file) => basename(file, extname2(file)));
|
|
7249
7146
|
profiles.forEach((p) => profileSet.add(p));
|
|
7250
7147
|
} catch (error) {
|
|
@@ -7253,7 +7150,7 @@ var ProfileLoader = class {
|
|
|
7253
7150
|
}
|
|
7254
7151
|
}
|
|
7255
7152
|
try {
|
|
7256
|
-
const files = await
|
|
7153
|
+
const files = await readdir3(this.fallbackProfilesDir);
|
|
7257
7154
|
const profiles = files.filter((file) => extname2(file) === ".yaml" || extname2(file) === ".yml").map((file) => basename(file, extname2(file)));
|
|
7258
7155
|
profiles.forEach((p) => profileSet.add(p));
|
|
7259
7156
|
} catch (error) {
|
|
@@ -7493,19 +7390,6 @@ var ProfileLoader = class {
|
|
|
7493
7390
|
throw new AgentValidationError("orchestration.maxDelegationDepth must be a non-negative integer (0 = no delegation allowed)");
|
|
7494
7391
|
}
|
|
7495
7392
|
}
|
|
7496
|
-
if (orch.canReadWorkspaces !== void 0) {
|
|
7497
|
-
if (!Array.isArray(orch.canReadWorkspaces)) {
|
|
7498
|
-
throw new AgentValidationError("orchestration.canReadWorkspaces must be an array");
|
|
7499
|
-
}
|
|
7500
|
-
orch.canReadWorkspaces.forEach((workspace, i) => {
|
|
7501
|
-
if (typeof workspace !== "string") {
|
|
7502
|
-
throw new AgentValidationError(`orchestration.canReadWorkspaces[${i}] must be a string`);
|
|
7503
|
-
}
|
|
7504
|
-
});
|
|
7505
|
-
}
|
|
7506
|
-
if (orch.canWriteToShared !== void 0 && typeof orch.canWriteToShared !== "boolean") {
|
|
7507
|
-
throw new AgentValidationError("orchestration.canWriteToShared must be a boolean");
|
|
7508
|
-
}
|
|
7509
7393
|
}
|
|
7510
7394
|
return true;
|
|
7511
7395
|
}
|
|
@@ -7628,7 +7512,7 @@ var ProfileLoader = class {
|
|
|
7628
7512
|
init_esm_shims();
|
|
7629
7513
|
init_logger();
|
|
7630
7514
|
init_cache();
|
|
7631
|
-
import { readFile as readFile4, readdir as
|
|
7515
|
+
import { readFile as readFile4, readdir as readdir4 } from "fs/promises";
|
|
7632
7516
|
import { join as join6, extname as extname3, basename as basename2, dirname as dirname7 } from "path";
|
|
7633
7517
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7634
7518
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
@@ -7729,7 +7613,7 @@ ${content}`);
|
|
|
7729
7613
|
*/
|
|
7730
7614
|
async listAbilities() {
|
|
7731
7615
|
try {
|
|
7732
|
-
const files = await
|
|
7616
|
+
const files = await readdir4(this.abilitiesDir);
|
|
7733
7617
|
const abilities = files.filter((file) => extname3(file) === ".md").map((file) => basename2(file, extname3(file)));
|
|
7734
7618
|
return abilities.sort();
|
|
7735
7619
|
} catch (error) {
|
|
@@ -7749,7 +7633,7 @@ ${content}`);
|
|
|
7749
7633
|
|
|
7750
7634
|
// src/core/team-manager.ts
|
|
7751
7635
|
init_esm_shims();
|
|
7752
|
-
import { readFile as readFile5, readdir as
|
|
7636
|
+
import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
|
|
7753
7637
|
import { join as join7, extname as extname4, basename as basename3 } from "path";
|
|
7754
7638
|
import { load as load3 } from "js-yaml";
|
|
7755
7639
|
|
|
@@ -7817,7 +7701,7 @@ var TeamManager = class {
|
|
|
7817
7701
|
async getAllTeams() {
|
|
7818
7702
|
logger.debug("Loading all teams");
|
|
7819
7703
|
try {
|
|
7820
|
-
const files = await
|
|
7704
|
+
const files = await readdir5(this.teamsDir);
|
|
7821
7705
|
const teamFiles = files.filter((f) => extname4(f) === ".yaml" || extname4(f) === ".yml");
|
|
7822
7706
|
const teams = [];
|
|
7823
7707
|
for (const file of teamFiles) {
|
|
@@ -7844,7 +7728,7 @@ var TeamManager = class {
|
|
|
7844
7728
|
*/
|
|
7845
7729
|
async listTeams() {
|
|
7846
7730
|
try {
|
|
7847
|
-
const files = await
|
|
7731
|
+
const files = await readdir5(this.teamsDir);
|
|
7848
7732
|
return files.filter((f) => extname4(f) === ".yaml" || extname4(f) === ".yml").map((f) => basename3(f, extname4(f)));
|
|
7849
7733
|
} catch (error) {
|
|
7850
7734
|
if (error.code === "ENOENT") {
|
|
@@ -7919,9 +7803,6 @@ var TeamManager = class {
|
|
|
7919
7803
|
if (team.sharedAbilities && !Array.isArray(team.sharedAbilities)) {
|
|
7920
7804
|
throw new TeamValidationError("sharedAbilities must be an array");
|
|
7921
7805
|
}
|
|
7922
|
-
if (team.orchestration?.canReadWorkspaces && !Array.isArray(team.orchestration.canReadWorkspaces)) {
|
|
7923
|
-
throw new TeamValidationError("orchestration.canReadWorkspaces must be an array");
|
|
7924
|
-
}
|
|
7925
7806
|
logger.debug("Team validation passed", { name: team.name });
|
|
7926
7807
|
}
|
|
7927
7808
|
};
|
|
@@ -8646,7 +8527,7 @@ ${context.task}`;
|
|
|
8646
8527
|
* Sleep for specified milliseconds
|
|
8647
8528
|
*/
|
|
8648
8529
|
sleep(ms) {
|
|
8649
|
-
return new Promise((
|
|
8530
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
8650
8531
|
}
|
|
8651
8532
|
/**
|
|
8652
8533
|
* Delegate a task to another agent
|
|
@@ -8738,7 +8619,6 @@ ${context.task}`;
|
|
|
8738
8619
|
session = await this.sessionManager.createSession(request.task, request.fromAgent);
|
|
8739
8620
|
sessionId = session.id;
|
|
8740
8621
|
await this.sessionManager.addAgent(sessionId, request.toAgent);
|
|
8741
|
-
await this.workspaceManager.createSessionWorkspace(sessionId);
|
|
8742
8622
|
}
|
|
8743
8623
|
} else {
|
|
8744
8624
|
logger.debug("Text-only delegation mode (no SessionManager/WorkspaceManager)", {
|
|
@@ -8761,13 +8641,7 @@ ${context.task}`;
|
|
|
8761
8641
|
verbose: false,
|
|
8762
8642
|
showProgress: true
|
|
8763
8643
|
});
|
|
8764
|
-
|
|
8765
|
-
if (this.workspaceManager && sessionId) {
|
|
8766
|
-
files = await this.workspaceManager.listSessionFiles(
|
|
8767
|
-
sessionId,
|
|
8768
|
-
request.toAgent
|
|
8769
|
-
);
|
|
8770
|
-
}
|
|
8644
|
+
const files = [];
|
|
8771
8645
|
const memoryIds = [];
|
|
8772
8646
|
const endTime = /* @__PURE__ */ new Date();
|
|
8773
8647
|
const duration = endTime.getTime() - startTime.getTime();
|
|
@@ -8828,7 +8702,7 @@ init_logger();
|
|
|
8828
8702
|
|
|
8829
8703
|
// src/mcp/utils/validation.ts
|
|
8830
8704
|
init_esm_shims();
|
|
8831
|
-
import { resolve as
|
|
8705
|
+
import { resolve as resolve5, isAbsolute as isAbsolute2, sep as sep2 } from "path";
|
|
8832
8706
|
var ValidationError = class extends Error {
|
|
8833
8707
|
constructor(message, code = -32602 /* InvalidParams */, details) {
|
|
8834
8708
|
super(message);
|
|
@@ -8888,8 +8762,8 @@ function validatePathParameter(path3, paramName, projectRoot = process.cwd()) {
|
|
|
8888
8762
|
);
|
|
8889
8763
|
}
|
|
8890
8764
|
try {
|
|
8891
|
-
const resolvedPath =
|
|
8892
|
-
const normalizedRoot =
|
|
8765
|
+
const resolvedPath = resolve5(projectRoot, path3);
|
|
8766
|
+
const normalizedRoot = resolve5(projectRoot);
|
|
8893
8767
|
if (!resolvedPath.startsWith(normalizedRoot + sep2) && resolvedPath !== normalizedRoot) {
|
|
8894
8768
|
throw new ValidationError(
|
|
8895
8769
|
`Invalid ${paramName}: path escapes project boundary`,
|
|
@@ -9423,12 +9297,12 @@ function createMemoryDeleteHandler(deps) {
|
|
|
9423
9297
|
// src/mcp/tools/memory-export.ts
|
|
9424
9298
|
init_esm_shims();
|
|
9425
9299
|
init_logger();
|
|
9426
|
-
import { resolve as
|
|
9300
|
+
import { resolve as resolve6, basename as basename4 } from "path";
|
|
9427
9301
|
function resolveExportPath(pathResolver, userPath) {
|
|
9428
9302
|
const exportsDir = pathResolver.resolveProjectPath(".automatosx/memory/exports");
|
|
9429
9303
|
validatePathParameter(userPath, "export path", exportsDir);
|
|
9430
9304
|
const filename = basename4(userPath);
|
|
9431
|
-
const absolutePath =
|
|
9305
|
+
const absolutePath = resolve6(exportsDir, filename);
|
|
9432
9306
|
if (!pathResolver.validatePath(absolutePath, exportsDir)) {
|
|
9433
9307
|
throw new Error("Export path must be within .automatosx/memory/exports directory");
|
|
9434
9308
|
}
|
|
@@ -9461,12 +9335,12 @@ function createMemoryExportHandler(deps) {
|
|
|
9461
9335
|
// src/mcp/tools/memory-import.ts
|
|
9462
9336
|
init_esm_shims();
|
|
9463
9337
|
init_logger();
|
|
9464
|
-
import { resolve as
|
|
9338
|
+
import { resolve as resolve7, basename as basename5 } from "path";
|
|
9465
9339
|
function resolveImportPath(pathResolver, userPath) {
|
|
9466
9340
|
const exportsDir = pathResolver.resolveProjectPath(".automatosx/memory/exports");
|
|
9467
9341
|
validatePathParameter(userPath, "import path", exportsDir);
|
|
9468
9342
|
const filename = basename5(userPath);
|
|
9469
|
-
const absolutePath =
|
|
9343
|
+
const absolutePath = resolve7(exportsDir, filename);
|
|
9470
9344
|
if (!pathResolver.validatePath(absolutePath, exportsDir)) {
|
|
9471
9345
|
throw new Error("Import path must be within .automatosx/memory/exports directory");
|
|
9472
9346
|
}
|
|
@@ -9663,7 +9537,6 @@ var McpServer = class {
|
|
|
9663
9537
|
});
|
|
9664
9538
|
await this.sessionManager.initialize();
|
|
9665
9539
|
this.workspaceManager = new WorkspaceManager(projectDir);
|
|
9666
|
-
await this.workspaceManager.initialize();
|
|
9667
9540
|
this.contextManager = new ContextManager({
|
|
9668
9541
|
profileLoader: this.profileLoader,
|
|
9669
9542
|
abilitiesManager,
|
|
@@ -10372,7 +10245,7 @@ var mcpCommand = {
|
|
|
10372
10245
|
|
|
10373
10246
|
// src/cli/commands/memory.ts
|
|
10374
10247
|
init_esm_shims();
|
|
10375
|
-
import { resolve as
|
|
10248
|
+
import { resolve as resolve8 } from "path";
|
|
10376
10249
|
import chalk8 from "chalk";
|
|
10377
10250
|
import Table from "cli-table3";
|
|
10378
10251
|
|
|
@@ -10493,7 +10366,7 @@ var DEFAULT_DB_PATH = ".automatosx/memory/memory.db";
|
|
|
10493
10366
|
async function getMemoryManager(dbPath) {
|
|
10494
10367
|
const path3 = dbPath || DEFAULT_DB_PATH;
|
|
10495
10368
|
return await MemoryManager.create({
|
|
10496
|
-
dbPath:
|
|
10369
|
+
dbPath: resolve8(path3),
|
|
10497
10370
|
maxEntries: 1e5,
|
|
10498
10371
|
autoCleanup: false,
|
|
10499
10372
|
trackAccess: true
|
|
@@ -10810,8 +10683,8 @@ var deleteCommand = {
|
|
|
10810
10683
|
input: process.stdin,
|
|
10811
10684
|
output: process.stdout
|
|
10812
10685
|
});
|
|
10813
|
-
const answer = await new Promise((
|
|
10814
|
-
rl.question(chalk8.yellow("\nAre you sure you want to delete this entry? (y/N): "),
|
|
10686
|
+
const answer = await new Promise((resolve9) => {
|
|
10687
|
+
rl.question(chalk8.yellow("\nAre you sure you want to delete this entry? (y/N): "), resolve9);
|
|
10815
10688
|
});
|
|
10816
10689
|
rl.close();
|
|
10817
10690
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
@@ -11885,7 +11758,7 @@ init_logger();
|
|
|
11885
11758
|
import chalk12 from "chalk";
|
|
11886
11759
|
import { join as join9 } from "path";
|
|
11887
11760
|
import { writeFileSync } from "fs";
|
|
11888
|
-
import { mkdir as
|
|
11761
|
+
import { mkdir as mkdir4 } from "fs/promises";
|
|
11889
11762
|
|
|
11890
11763
|
// src/utils/output-formatter.ts
|
|
11891
11764
|
init_esm_shims();
|
|
@@ -12146,7 +12019,6 @@ var runCommand = {
|
|
|
12146
12019
|
});
|
|
12147
12020
|
await sessionManager.initialize();
|
|
12148
12021
|
workspaceManager = new WorkspaceManager(projectDir);
|
|
12149
|
-
await workspaceManager.initialize();
|
|
12150
12022
|
if (argv2.session) {
|
|
12151
12023
|
const session = await sessionManager.getSession(argv2.session);
|
|
12152
12024
|
if (!session) {
|
|
@@ -12292,7 +12164,7 @@ var runCommand = {
|
|
|
12292
12164
|
try {
|
|
12293
12165
|
const savePath = argv2.save;
|
|
12294
12166
|
const saveDir = join9(savePath, "..");
|
|
12295
|
-
await
|
|
12167
|
+
await mkdir4(saveDir, { recursive: true });
|
|
12296
12168
|
let outputData;
|
|
12297
12169
|
if (argv2.format === "json") {
|
|
12298
12170
|
outputData = JSON.stringify({
|
|
@@ -12390,7 +12262,7 @@ Result: ${multiStageResult.finalOutput}`;
|
|
|
12390
12262
|
try {
|
|
12391
12263
|
const savePath = argv2.save;
|
|
12392
12264
|
const saveDir = join9(savePath, "..");
|
|
12393
|
-
await
|
|
12265
|
+
await mkdir4(saveDir, { recursive: true });
|
|
12394
12266
|
const outputData = formatForSave(result, argv2.format || "text", {
|
|
12395
12267
|
agent: resolvedAgentName,
|
|
12396
12268
|
task: argv2.task
|
|
@@ -12437,7 +12309,7 @@ Response: ${result.response.content}`;
|
|
|
12437
12309
|
if (router) {
|
|
12438
12310
|
router.destroy();
|
|
12439
12311
|
}
|
|
12440
|
-
await new Promise((
|
|
12312
|
+
await new Promise((resolve9) => setImmediate(resolve9));
|
|
12441
12313
|
console.log(chalk12.green.bold("\u2705 Complete\n"));
|
|
12442
12314
|
process.exit(0);
|
|
12443
12315
|
} catch (error) {
|
|
@@ -12464,7 +12336,7 @@ Response: ${result.response.content}`;
|
|
|
12464
12336
|
logger.debug("Context cleanup error", { error: errMsg });
|
|
12465
12337
|
});
|
|
12466
12338
|
}
|
|
12467
|
-
await new Promise((
|
|
12339
|
+
await new Promise((resolve9) => setImmediate(resolve9));
|
|
12468
12340
|
} catch (cleanupError) {
|
|
12469
12341
|
const errMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
12470
12342
|
logger.debug("Cleanup error ignored", { error: errMsg });
|
|
@@ -12717,8 +12589,8 @@ init_gemini_provider();
|
|
|
12717
12589
|
init_openai_provider();
|
|
12718
12590
|
init_logger();
|
|
12719
12591
|
import chalk14 from "chalk";
|
|
12720
|
-
import { existsSync as
|
|
12721
|
-
import { readdir as
|
|
12592
|
+
import { existsSync as existsSync5 } from "fs";
|
|
12593
|
+
import { readdir as readdir6, stat as stat2 } from "fs/promises";
|
|
12722
12594
|
import { join as join11 } from "path";
|
|
12723
12595
|
import { createRequire as createRequire3 } from "module";
|
|
12724
12596
|
import os from "os";
|
|
@@ -12833,17 +12705,17 @@ var statusCommand2 = {
|
|
|
12833
12705
|
project: projectInfo,
|
|
12834
12706
|
configuration: {
|
|
12835
12707
|
configFile: join11(detectedProjectDir, "automatosx.config.json"),
|
|
12836
|
-
configExists:
|
|
12708
|
+
configExists: existsSync5(join11(detectedProjectDir, "automatosx.config.json")),
|
|
12837
12709
|
logLevel: config.logging.level,
|
|
12838
12710
|
memoryMaxEntries: config.memory.maxEntries,
|
|
12839
12711
|
memoryRetentionDays: config.memory.cleanupDays
|
|
12840
12712
|
},
|
|
12841
12713
|
directories: {
|
|
12842
|
-
automatosx: { path: automatosxDir, exists:
|
|
12843
|
-
agents: { path: agentsDir, exists:
|
|
12844
|
-
abilities: { path: abilitiesDir, exists:
|
|
12845
|
-
memory: { path: memoryDir, exists:
|
|
12846
|
-
workspaces: { path: workspacesDir, exists:
|
|
12714
|
+
automatosx: { path: automatosxDir, exists: existsSync5(automatosxDir) },
|
|
12715
|
+
agents: { path: agentsDir, exists: existsSync5(agentsDir), count: agentCount },
|
|
12716
|
+
abilities: { path: abilitiesDir, exists: existsSync5(abilitiesDir), count: abilityCount },
|
|
12717
|
+
memory: { path: memoryDir, exists: existsSync5(memoryDir), ...memoryStats },
|
|
12718
|
+
workspaces: { path: workspacesDir, exists: existsSync5(workspacesDir), ...workspaceStats }
|
|
12847
12719
|
},
|
|
12848
12720
|
providers: providerHealth,
|
|
12849
12721
|
router: {
|
|
@@ -12966,11 +12838,11 @@ var statusCommand2 = {
|
|
|
12966
12838
|
}
|
|
12967
12839
|
};
|
|
12968
12840
|
async function getWorkspaceStatistics(workspacesDir) {
|
|
12969
|
-
if (!
|
|
12841
|
+
if (!existsSync5(workspacesDir)) {
|
|
12970
12842
|
return { workspaces: 0, totalSizeBytes: 0, files: 0 };
|
|
12971
12843
|
}
|
|
12972
12844
|
try {
|
|
12973
|
-
const entries = await
|
|
12845
|
+
const entries = await readdir6(workspacesDir, { withFileTypes: true });
|
|
12974
12846
|
const workspaces = entries.filter((e) => e.isDirectory());
|
|
12975
12847
|
let totalSizeBytes = 0;
|
|
12976
12848
|
let files = 0;
|
|
@@ -12991,7 +12863,7 @@ async function getWorkspaceStatistics(workspacesDir) {
|
|
|
12991
12863
|
}
|
|
12992
12864
|
}
|
|
12993
12865
|
async function getMemoryStatistics(memoryDir) {
|
|
12994
|
-
if (!
|
|
12866
|
+
if (!existsSync5(memoryDir)) {
|
|
12995
12867
|
return { files: 0, sizeBytes: 0 };
|
|
12996
12868
|
}
|
|
12997
12869
|
try {
|
|
@@ -13009,7 +12881,7 @@ async function getDirectoryStats(dirPath) {
|
|
|
13009
12881
|
let totalSize = 0;
|
|
13010
12882
|
let totalFiles = 0;
|
|
13011
12883
|
try {
|
|
13012
|
-
const entries = await
|
|
12884
|
+
const entries = await readdir6(dirPath, { withFileTypes: true });
|
|
13013
12885
|
for (const entry of entries) {
|
|
13014
12886
|
const fullPath = join11(dirPath, entry.name);
|
|
13015
12887
|
if (entry.isDirectory()) {
|
|
@@ -13017,7 +12889,7 @@ async function getDirectoryStats(dirPath) {
|
|
|
13017
12889
|
totalSize += subStats.size;
|
|
13018
12890
|
totalFiles += subStats.files;
|
|
13019
12891
|
} else if (entry.isFile()) {
|
|
13020
|
-
const stats = await
|
|
12892
|
+
const stats = await stat2(fullPath);
|
|
13021
12893
|
totalSize += stats.size;
|
|
13022
12894
|
totalFiles++;
|
|
13023
12895
|
}
|
|
@@ -13027,11 +12899,11 @@ async function getDirectoryStats(dirPath) {
|
|
|
13027
12899
|
return { size: totalSize, files: totalFiles };
|
|
13028
12900
|
}
|
|
13029
12901
|
async function countFiles(dirPath, extensions) {
|
|
13030
|
-
if (!
|
|
12902
|
+
if (!existsSync5(dirPath)) {
|
|
13031
12903
|
return 0;
|
|
13032
12904
|
}
|
|
13033
12905
|
try {
|
|
13034
|
-
const files = await
|
|
12906
|
+
const files = await readdir6(dirPath);
|
|
13035
12907
|
return files.filter((f) => extensions.some((ext) => f.endsWith(ext))).length;
|
|
13036
12908
|
} catch (error) {
|
|
13037
12909
|
logger.warn("Failed to count files", { dirPath, error: error.message });
|
|
@@ -13040,7 +12912,7 @@ async function countFiles(dirPath, extensions) {
|
|
|
13040
12912
|
}
|
|
13041
12913
|
async function getProjectInfo(projectDir) {
|
|
13042
12914
|
const packageJsonPath = join11(projectDir, "package.json");
|
|
13043
|
-
if (!
|
|
12915
|
+
if (!existsSync5(packageJsonPath)) {
|
|
13044
12916
|
return {};
|
|
13045
12917
|
}
|
|
13046
12918
|
try {
|
|
@@ -13126,8 +12998,8 @@ var updateCommand = {
|
|
|
13126
12998
|
input: process.stdin,
|
|
13127
12999
|
output: process.stdout
|
|
13128
13000
|
});
|
|
13129
|
-
const answer = await new Promise((
|
|
13130
|
-
rl.question(chalk15.yellow("Would you like to update now? (y/N) "),
|
|
13001
|
+
const answer = await new Promise((resolve9) => {
|
|
13002
|
+
rl.question(chalk15.yellow("Would you like to update now? (y/N) "), resolve9);
|
|
13131
13003
|
});
|
|
13132
13004
|
rl.close();
|
|
13133
13005
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
@@ -13230,11 +13102,13 @@ init_esm_shims();
|
|
|
13230
13102
|
import chalk16 from "chalk";
|
|
13231
13103
|
var listCommand4 = {
|
|
13232
13104
|
command: "list",
|
|
13233
|
-
describe: "List workspace files",
|
|
13105
|
+
describe: "List workspace files (PRD or tmp)",
|
|
13234
13106
|
builder: (yargs2) => {
|
|
13235
|
-
return yargs2.option("
|
|
13236
|
-
describe: "
|
|
13237
|
-
type: "string"
|
|
13107
|
+
return yargs2.option("type", {
|
|
13108
|
+
describe: "Workspace type to list",
|
|
13109
|
+
type: "string",
|
|
13110
|
+
choices: ["prd", "tmp"],
|
|
13111
|
+
default: "prd"
|
|
13238
13112
|
}).option("json", {
|
|
13239
13113
|
describe: "Output as JSON",
|
|
13240
13114
|
type: "boolean",
|
|
@@ -13246,42 +13120,23 @@ var listCommand4 = {
|
|
|
13246
13120
|
const { detectProjectRoot: detectProjectRoot2 } = await Promise.resolve().then(() => (init_path_resolver(), path_resolver_exports));
|
|
13247
13121
|
const projectDir = await detectProjectRoot2(process.cwd());
|
|
13248
13122
|
const workspaceManager = new WorkspaceManager(projectDir);
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
process.exit(1);
|
|
13257
|
-
}
|
|
13258
|
-
console.log(chalk16.blue.bold(`
|
|
13259
|
-
\u{1F4C1} Session Workspace Files
|
|
13260
|
-
`));
|
|
13261
|
-
console.log(chalk16.gray(`Session: ${argv2.session}`));
|
|
13262
|
-
console.log(chalk16.gray(`Task: ${session.task}
|
|
13123
|
+
const files = argv2.type === "tmp" ? await workspaceManager.listTmp() : await workspaceManager.listPRD();
|
|
13124
|
+
if (argv2.json) {
|
|
13125
|
+
console.log(JSON.stringify({ type: argv2.type, files }, null, 2));
|
|
13126
|
+
process.exit(0);
|
|
13127
|
+
}
|
|
13128
|
+
console.log(chalk16.blue.bold(`
|
|
13129
|
+
\u{1F4C1} ${argv2.type === "tmp" ? "Temporary" : "PRD"} Files
|
|
13263
13130
|
`));
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
if (files.length > 0) {
|
|
13267
|
-
console.log(chalk16.cyan(`
|
|
13268
|
-
${agentName}:`));
|
|
13269
|
-
files.forEach((file) => {
|
|
13270
|
-
console.log(chalk16.gray(` - ${file}`));
|
|
13271
|
-
});
|
|
13272
|
-
}
|
|
13273
|
-
}
|
|
13274
|
-
console.log();
|
|
13131
|
+
if (files.length === 0) {
|
|
13132
|
+
console.log(chalk16.gray(" (No files)\n"));
|
|
13275
13133
|
} else {
|
|
13276
|
-
|
|
13277
|
-
|
|
13278
|
-
|
|
13279
|
-
|
|
13280
|
-
|
|
13281
|
-
|
|
13282
|
-
console.log(chalk16.gray(`Session workspaces: ${chalk16.white(stats.totalSessions)}`));
|
|
13283
|
-
console.log(chalk16.gray(`Agent workspaces: ${chalk16.white(stats.agentWorkspaces)}`));
|
|
13284
|
-
console.log();
|
|
13134
|
+
files.forEach((file) => {
|
|
13135
|
+
console.log(chalk16.gray(` - ${file}`));
|
|
13136
|
+
});
|
|
13137
|
+
console.log(chalk16.gray(`
|
|
13138
|
+
Total: ${files.length} file(s)
|
|
13139
|
+
`));
|
|
13285
13140
|
}
|
|
13286
13141
|
process.exit(0);
|
|
13287
13142
|
} catch (error) {
|
|
@@ -13312,9 +13167,9 @@ var statsCommand2 = {
|
|
|
13312
13167
|
process.exit(0);
|
|
13313
13168
|
}
|
|
13314
13169
|
console.log(chalk16.blue.bold("\n\u{1F4CA} Workspace Statistics\n"));
|
|
13315
|
-
console.log(chalk16.gray(`
|
|
13316
|
-
console.log(chalk16.gray(`
|
|
13317
|
-
console.log(chalk16.gray(`Total size:
|
|
13170
|
+
console.log(chalk16.gray(`PRD files: ${chalk16.white(stats.prdFiles)}`));
|
|
13171
|
+
console.log(chalk16.gray(`Temporary files: ${chalk16.white(stats.tmpFiles)}`));
|
|
13172
|
+
console.log(chalk16.gray(`Total size: ${chalk16.white((stats.totalSizeBytes / 1024 / 1024).toFixed(2))} MB`));
|
|
13318
13173
|
console.log();
|
|
13319
13174
|
process.exit(0);
|
|
13320
13175
|
} catch (error) {
|
|
@@ -13326,10 +13181,10 @@ var statsCommand2 = {
|
|
|
13326
13181
|
};
|
|
13327
13182
|
var cleanupCommand = {
|
|
13328
13183
|
command: "cleanup",
|
|
13329
|
-
describe: "Clean up
|
|
13184
|
+
describe: "Clean up temporary files",
|
|
13330
13185
|
builder: (yargs2) => {
|
|
13331
13186
|
return yargs2.option("older-than", {
|
|
13332
|
-
describe: "Clean up
|
|
13187
|
+
describe: "Clean up files older than N days",
|
|
13333
13188
|
type: "number",
|
|
13334
13189
|
default: 7
|
|
13335
13190
|
}).option("confirm", {
|
|
@@ -13343,22 +13198,17 @@ var cleanupCommand = {
|
|
|
13343
13198
|
const { detectProjectRoot: detectProjectRoot2 } = await Promise.resolve().then(() => (init_path_resolver(), path_resolver_exports));
|
|
13344
13199
|
const projectDir = await detectProjectRoot2(process.cwd());
|
|
13345
13200
|
const workspaceManager = new WorkspaceManager(projectDir);
|
|
13346
|
-
const sessionManager = await createSessionManager();
|
|
13347
|
-
const activeSessions = await sessionManager.getActiveSessions();
|
|
13348
|
-
const activeIds = activeSessions.map((s) => s.id);
|
|
13349
13201
|
if (!argv2.confirm) {
|
|
13350
13202
|
console.log(chalk16.yellow(`
|
|
13351
|
-
\u26A0 This will remove
|
|
13352
|
-
console.log(chalk16.gray(`Active sessions (${activeIds.length}) will be kept
|
|
13353
|
-
`));
|
|
13203
|
+
\u26A0 This will remove temporary files older than ${argv2.olderThan} days`));
|
|
13354
13204
|
console.log(chalk16.gray("Run with --confirm to proceed\n"));
|
|
13355
13205
|
process.exit(0);
|
|
13356
13206
|
}
|
|
13357
|
-
const removed = await workspaceManager.
|
|
13207
|
+
const removed = await workspaceManager.cleanupTmp(argv2.olderThan);
|
|
13358
13208
|
console.log(chalk16.green.bold(`
|
|
13359
13209
|
\u2713 Cleanup complete
|
|
13360
13210
|
`));
|
|
13361
|
-
console.log(chalk16.gray(`Removed ${removed}
|
|
13211
|
+
console.log(chalk16.gray(`Removed ${removed} temporary file(s)
|
|
13362
13212
|
`));
|
|
13363
13213
|
process.exit(0);
|
|
13364
13214
|
} catch (error) {
|
|
@@ -13383,9 +13233,9 @@ init_esm_shims();
|
|
|
13383
13233
|
|
|
13384
13234
|
// src/cli/commands/agent/templates.ts
|
|
13385
13235
|
init_esm_shims();
|
|
13386
|
-
import { readdir as
|
|
13236
|
+
import { readdir as readdir7 } from "fs/promises";
|
|
13387
13237
|
import { join as join12 } from "path";
|
|
13388
|
-
import { existsSync as
|
|
13238
|
+
import { existsSync as existsSync6 } from "fs";
|
|
13389
13239
|
import chalk17 from "chalk";
|
|
13390
13240
|
var TEMPLATE_DESCRIPTIONS = {
|
|
13391
13241
|
"basic-agent": {
|
|
@@ -13421,9 +13271,9 @@ var templatesCommand = {
|
|
|
13421
13271
|
try {
|
|
13422
13272
|
console.log(chalk17.blue.bold("\n\u{1F4CB} Available Agent Templates\n"));
|
|
13423
13273
|
const projectTemplatesDir = join12(process.cwd(), ".automatosx", "templates");
|
|
13424
|
-
const hasProjectTemplates =
|
|
13274
|
+
const hasProjectTemplates = existsSync6(projectTemplatesDir);
|
|
13425
13275
|
const defaultTemplatesDir = join12(__dirname, "../../../../examples/templates");
|
|
13426
|
-
const hasDefaultTemplates =
|
|
13276
|
+
const hasDefaultTemplates = existsSync6(defaultTemplatesDir);
|
|
13427
13277
|
if (!hasProjectTemplates && !hasDefaultTemplates) {
|
|
13428
13278
|
console.log(chalk17.yellow("\u26A0 No templates found."));
|
|
13429
13279
|
console.log(chalk17.gray('\nRun "ax init" to set up default templates.\n'));
|
|
@@ -13431,7 +13281,7 @@ var templatesCommand = {
|
|
|
13431
13281
|
}
|
|
13432
13282
|
const templatesDir = hasProjectTemplates ? projectTemplatesDir : defaultTemplatesDir;
|
|
13433
13283
|
const templateSource = hasProjectTemplates ? "Project" : "Default";
|
|
13434
|
-
const files = await
|
|
13284
|
+
const files = await readdir7(templatesDir);
|
|
13435
13285
|
const templates = files.filter((f) => f.endsWith(".yaml")).map((f) => f.replace(".yaml", ""));
|
|
13436
13286
|
if (templates.length === 0) {
|
|
13437
13287
|
console.log(chalk17.yellow("\u26A0 No templates found.\n"));
|
|
@@ -13480,8 +13330,8 @@ var templatesCommand = {
|
|
|
13480
13330
|
|
|
13481
13331
|
// src/cli/commands/agent/create.ts
|
|
13482
13332
|
init_esm_shims();
|
|
13483
|
-
import { readFile as readFile6, writeFile as writeFile5, mkdir as
|
|
13484
|
-
import { existsSync as
|
|
13333
|
+
import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
13334
|
+
import { existsSync as existsSync8 } from "fs";
|
|
13485
13335
|
import { join as join14 } from "path";
|
|
13486
13336
|
import { load as loadYaml2 } from "js-yaml";
|
|
13487
13337
|
import chalk18 from "chalk";
|
|
@@ -13621,8 +13471,8 @@ var templateEngine = new TemplateEngine();
|
|
|
13621
13471
|
|
|
13622
13472
|
// src/cli/commands/agent/helpers.ts
|
|
13623
13473
|
init_esm_shims();
|
|
13624
|
-
import { readdir as
|
|
13625
|
-
import { existsSync as
|
|
13474
|
+
import { readdir as readdir8 } from "fs/promises";
|
|
13475
|
+
import { existsSync as existsSync7 } from "fs";
|
|
13626
13476
|
import { join as join13, extname as extname5, dirname as dirname8 } from "path";
|
|
13627
13477
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13628
13478
|
init_logger();
|
|
@@ -13631,9 +13481,9 @@ var __dirname5 = dirname8(__filename5);
|
|
|
13631
13481
|
async function listAvailableTemplates() {
|
|
13632
13482
|
const templates = [];
|
|
13633
13483
|
const projectTemplatesDir = join13(process.cwd(), ".automatosx", "templates");
|
|
13634
|
-
if (
|
|
13484
|
+
if (existsSync7(projectTemplatesDir)) {
|
|
13635
13485
|
try {
|
|
13636
|
-
const files = await
|
|
13486
|
+
const files = await readdir8(projectTemplatesDir);
|
|
13637
13487
|
for (const file of files) {
|
|
13638
13488
|
if (extname5(file) === ".yaml" || extname5(file) === ".yml") {
|
|
13639
13489
|
const name = file.replace(/\.(yaml|yml)$/, "");
|
|
@@ -13649,9 +13499,9 @@ async function listAvailableTemplates() {
|
|
|
13649
13499
|
}
|
|
13650
13500
|
}
|
|
13651
13501
|
const builtinTemplatesDir = join13(__dirname5, "../../../../examples/templates");
|
|
13652
|
-
if (
|
|
13502
|
+
if (existsSync7(builtinTemplatesDir)) {
|
|
13653
13503
|
try {
|
|
13654
|
-
const files = await
|
|
13504
|
+
const files = await readdir8(builtinTemplatesDir);
|
|
13655
13505
|
for (const file of files) {
|
|
13656
13506
|
if (extname5(file) === ".yaml" || extname5(file) === ".yml") {
|
|
13657
13507
|
const name = file.replace(/\.(yaml|yml)$/, "");
|
|
@@ -13844,14 +13694,14 @@ var createCommand2 = {
|
|
|
13844
13694
|
console.log(chalk18.gray(" \u2022 Not contain consecutive hyphens\n"));
|
|
13845
13695
|
process.exit(1);
|
|
13846
13696
|
}
|
|
13847
|
-
if (
|
|
13697
|
+
if (existsSync8(agentFile)) {
|
|
13848
13698
|
console.log(chalk18.red.bold(`
|
|
13849
13699
|
\u2717 Agent already exists: ${argv2.agent}
|
|
13850
13700
|
`));
|
|
13851
13701
|
console.log(chalk18.gray("Use a different name or remove the existing agent first.\n"));
|
|
13852
13702
|
process.exit(1);
|
|
13853
13703
|
}
|
|
13854
|
-
await
|
|
13704
|
+
await mkdir5(agentsDir, { recursive: true });
|
|
13855
13705
|
let templateName = argv2.template;
|
|
13856
13706
|
if (!templateName) {
|
|
13857
13707
|
if (argv2.interactive) {
|
|
@@ -13939,11 +13789,11 @@ var createCommand2 = {
|
|
|
13939
13789
|
};
|
|
13940
13790
|
async function findTemplate(name) {
|
|
13941
13791
|
const projectTemplate = join14(process.cwd(), ".automatosx", "templates", `${name}.yaml`);
|
|
13942
|
-
if (
|
|
13792
|
+
if (existsSync8(projectTemplate)) {
|
|
13943
13793
|
return projectTemplate;
|
|
13944
13794
|
}
|
|
13945
13795
|
const defaultTemplate = join14(__dirname, "../../../../examples/templates", `${name}.yaml`);
|
|
13946
|
-
if (
|
|
13796
|
+
if (existsSync8(defaultTemplate)) {
|
|
13947
13797
|
return defaultTemplate;
|
|
13948
13798
|
}
|
|
13949
13799
|
throw new Error(`Template not found: ${name}
|
|
@@ -13997,10 +13847,10 @@ function ask(question, defaultValue) {
|
|
|
13997
13847
|
output: process.stdout
|
|
13998
13848
|
});
|
|
13999
13849
|
const prompt = defaultValue ? `${question} [${chalk18.gray(defaultValue)}]: ` : `${question}: `;
|
|
14000
|
-
return new Promise((
|
|
13850
|
+
return new Promise((resolve9) => {
|
|
14001
13851
|
rl.question(prompt, (answer) => {
|
|
14002
13852
|
rl.close();
|
|
14003
|
-
|
|
13853
|
+
resolve9(answer.trim() || defaultValue || "");
|
|
14004
13854
|
});
|
|
14005
13855
|
});
|
|
14006
13856
|
}
|
|
@@ -14158,12 +14008,6 @@ var showCommand = {
|
|
|
14158
14008
|
if (orch.maxDelegationDepth !== void 0) {
|
|
14159
14009
|
console.log(chalk20.white(` Max Delegation Depth: ${orch.maxDelegationDepth}`));
|
|
14160
14010
|
}
|
|
14161
|
-
if (orch.canReadWorkspaces && orch.canReadWorkspaces.length > 0) {
|
|
14162
|
-
console.log(chalk20.white(` Can Read Workspaces: ${orch.canReadWorkspaces.join(", ")}`));
|
|
14163
|
-
}
|
|
14164
|
-
if (orch.canWriteToShared !== void 0) {
|
|
14165
|
-
console.log(chalk20.white(` Can Write to Shared: ${orch.canWriteToShared ? "Yes" : "No"}`));
|
|
14166
|
-
}
|
|
14167
14011
|
console.log();
|
|
14168
14012
|
}
|
|
14169
14013
|
const filePath = join16(agentsDir, `${argv2.agent}.yaml`);
|
|
@@ -14204,7 +14048,7 @@ var showCommand = {
|
|
|
14204
14048
|
// src/cli/commands/agent/remove.ts
|
|
14205
14049
|
init_esm_shims();
|
|
14206
14050
|
import { unlink as unlink2 } from "fs/promises";
|
|
14207
|
-
import { existsSync as
|
|
14051
|
+
import { existsSync as existsSync9 } from "fs";
|
|
14208
14052
|
import { join as join17 } from "path";
|
|
14209
14053
|
import chalk21 from "chalk";
|
|
14210
14054
|
import * as readline2 from "readline";
|
|
@@ -14257,7 +14101,7 @@ var removeCommand = {
|
|
|
14257
14101
|
process.exit(1);
|
|
14258
14102
|
}
|
|
14259
14103
|
const agentFile = join17(agentsDir, `${resolvedName}.yaml`);
|
|
14260
|
-
if (!
|
|
14104
|
+
if (!existsSync9(agentFile)) {
|
|
14261
14105
|
console.log(chalk21.red.bold(`
|
|
14262
14106
|
\u2717 Agent file not found: ${resolvedName}
|
|
14263
14107
|
`));
|
|
@@ -14293,11 +14137,11 @@ function askConfirmation(question) {
|
|
|
14293
14137
|
input: process.stdin,
|
|
14294
14138
|
output: process.stdout
|
|
14295
14139
|
});
|
|
14296
|
-
return new Promise((
|
|
14140
|
+
return new Promise((resolve9) => {
|
|
14297
14141
|
rl.question(chalk21.yellow(`
|
|
14298
14142
|
${question} (y/N): `), (answer) => {
|
|
14299
14143
|
rl.close();
|
|
14300
|
-
|
|
14144
|
+
resolve9(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
14301
14145
|
});
|
|
14302
14146
|
});
|
|
14303
14147
|
}
|