juno-code 1.0.32 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +158 -139
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +157 -138
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/templates/services/__pycache__/codex.cpython-38.pyc +0 -0
- package/dist/templates/services/codex.py +254 -16
- package/package.json +1 -1
package/dist/bin/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import fs2 from 'fs-extra';
|
|
3
3
|
import * as path3 from 'path';
|
|
4
4
|
import path3__default, { dirname, join } from 'path';
|
|
5
5
|
import * as os3 from 'os';
|
|
@@ -315,12 +315,12 @@ var init_service_installer = __esm({
|
|
|
315
315
|
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
316
316
|
const require3 = createRequire(import.meta.url);
|
|
317
317
|
let packageJsonPath = path3.join(__dirname2, "..", "..", "package.json");
|
|
318
|
-
if (
|
|
318
|
+
if (fs2.existsSync(packageJsonPath)) {
|
|
319
319
|
const packageJson2 = require3(packageJsonPath);
|
|
320
320
|
return packageJson2.version;
|
|
321
321
|
}
|
|
322
322
|
packageJsonPath = path3.join(__dirname2, "..", "..", "..", "package.json");
|
|
323
|
-
if (
|
|
323
|
+
if (fs2.existsSync(packageJsonPath)) {
|
|
324
324
|
const packageJson2 = require3(packageJsonPath);
|
|
325
325
|
return packageJson2.version;
|
|
326
326
|
}
|
|
@@ -334,11 +334,11 @@ var init_service_installer = __esm({
|
|
|
334
334
|
*/
|
|
335
335
|
static async getInstalledVersion() {
|
|
336
336
|
try {
|
|
337
|
-
const exists = await
|
|
337
|
+
const exists = await fs2.pathExists(this.VERSION_FILE);
|
|
338
338
|
if (!exists) {
|
|
339
339
|
return null;
|
|
340
340
|
}
|
|
341
|
-
const version3 = await
|
|
341
|
+
const version3 = await fs2.readFile(this.VERSION_FILE, "utf-8");
|
|
342
342
|
return version3.trim();
|
|
343
343
|
} catch {
|
|
344
344
|
return null;
|
|
@@ -349,7 +349,7 @@ var init_service_installer = __esm({
|
|
|
349
349
|
*/
|
|
350
350
|
static async saveVersion() {
|
|
351
351
|
const version3 = this.getPackageVersion();
|
|
352
|
-
await
|
|
352
|
+
await fs2.writeFile(this.VERSION_FILE, version3, "utf-8");
|
|
353
353
|
}
|
|
354
354
|
/**
|
|
355
355
|
* Check if services need to be updated based on version
|
|
@@ -361,7 +361,7 @@ var init_service_installer = __esm({
|
|
|
361
361
|
if (!installedVersion) {
|
|
362
362
|
return true;
|
|
363
363
|
}
|
|
364
|
-
const exists = await
|
|
364
|
+
const exists = await fs2.pathExists(this.SERVICES_DIR);
|
|
365
365
|
if (!exists) {
|
|
366
366
|
return true;
|
|
367
367
|
}
|
|
@@ -369,8 +369,10 @@ var init_service_installer = __esm({
|
|
|
369
369
|
return true;
|
|
370
370
|
}
|
|
371
371
|
if (semver.eq(packageVersion, installedVersion)) {
|
|
372
|
-
const
|
|
373
|
-
const
|
|
372
|
+
const installedCodex = path3.join(this.SERVICES_DIR, "codex.py");
|
|
373
|
+
const installedClaude = path3.join(this.SERVICES_DIR, "claude.py");
|
|
374
|
+
const codexExists = await fs2.pathExists(installedCodex);
|
|
375
|
+
const claudeExists = await fs2.pathExists(installedClaude);
|
|
374
376
|
if (!codexExists || !claudeExists) {
|
|
375
377
|
return true;
|
|
376
378
|
}
|
|
@@ -378,15 +380,32 @@ var init_service_installer = __esm({
|
|
|
378
380
|
const packageServicesDir = this.getPackageServicesDir();
|
|
379
381
|
const packageCodex = path3.join(packageServicesDir, "codex.py");
|
|
380
382
|
const packageClaude = path3.join(packageServicesDir, "claude.py");
|
|
381
|
-
const packageCodexExists = await
|
|
382
|
-
const packageClaudeExists = await
|
|
383
|
-
if (packageCodexExists
|
|
384
|
-
const
|
|
385
|
-
|
|
383
|
+
const packageCodexExists = await fs2.pathExists(packageCodex);
|
|
384
|
+
const packageClaudeExists = await fs2.pathExists(packageClaude);
|
|
385
|
+
if (packageCodexExists) {
|
|
386
|
+
const [pkg, inst] = await Promise.all([
|
|
387
|
+
fs2.readFile(packageCodex, "utf-8"),
|
|
388
|
+
fs2.readFile(installedCodex, "utf-8")
|
|
389
|
+
]);
|
|
390
|
+
if (pkg !== inst) {
|
|
386
391
|
return true;
|
|
387
392
|
}
|
|
388
393
|
}
|
|
394
|
+
if (packageClaudeExists) {
|
|
395
|
+
const [pkg, inst] = await Promise.all([
|
|
396
|
+
fs2.readFile(packageClaude, "utf-8"),
|
|
397
|
+
fs2.readFile(installedClaude, "utf-8")
|
|
398
|
+
]);
|
|
399
|
+
if (pkg !== inst) {
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const isDevelopment2 = packageServicesDir.includes("/src/");
|
|
404
|
+
if (isDevelopment2) {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
389
407
|
} catch {
|
|
408
|
+
return true;
|
|
390
409
|
}
|
|
391
410
|
}
|
|
392
411
|
return false;
|
|
@@ -400,11 +419,11 @@ var init_service_installer = __esm({
|
|
|
400
419
|
static getPackageServicesDir() {
|
|
401
420
|
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
402
421
|
let servicesPath = path3.join(__dirname2, "..", "..", "templates", "services");
|
|
403
|
-
if (
|
|
422
|
+
if (fs2.existsSync(servicesPath)) {
|
|
404
423
|
return servicesPath;
|
|
405
424
|
}
|
|
406
425
|
servicesPath = path3.join(__dirname2, "..", "templates", "services");
|
|
407
|
-
if (
|
|
426
|
+
if (fs2.existsSync(servicesPath)) {
|
|
408
427
|
return servicesPath;
|
|
409
428
|
}
|
|
410
429
|
throw new Error("Could not find services directory in package");
|
|
@@ -415,18 +434,18 @@ var init_service_installer = __esm({
|
|
|
415
434
|
*/
|
|
416
435
|
static async install(silent = false) {
|
|
417
436
|
try {
|
|
418
|
-
await
|
|
437
|
+
await fs2.ensureDir(this.SERVICES_DIR);
|
|
419
438
|
const packageServicesDir = this.getPackageServicesDir();
|
|
420
|
-
await
|
|
439
|
+
await fs2.copy(packageServicesDir, this.SERVICES_DIR, {
|
|
421
440
|
overwrite: true,
|
|
422
441
|
preserveTimestamps: true
|
|
423
442
|
});
|
|
424
|
-
const files = await
|
|
443
|
+
const files = await fs2.readdir(this.SERVICES_DIR);
|
|
425
444
|
for (const file of files) {
|
|
426
445
|
const filePath = path3.join(this.SERVICES_DIR, file);
|
|
427
|
-
const stat = await
|
|
446
|
+
const stat = await fs2.stat(filePath);
|
|
428
447
|
if (stat.isFile() && (file.endsWith(".py") || file.endsWith(".sh"))) {
|
|
429
|
-
await
|
|
448
|
+
await fs2.chmod(filePath, 493);
|
|
430
449
|
}
|
|
431
450
|
}
|
|
432
451
|
await this.saveVersion();
|
|
@@ -473,11 +492,11 @@ var init_service_installer = __esm({
|
|
|
473
492
|
*/
|
|
474
493
|
static async isInstalled() {
|
|
475
494
|
try {
|
|
476
|
-
const exists = await
|
|
495
|
+
const exists = await fs2.pathExists(this.SERVICES_DIR);
|
|
477
496
|
if (!exists) {
|
|
478
497
|
return false;
|
|
479
498
|
}
|
|
480
|
-
const files = await
|
|
499
|
+
const files = await fs2.readdir(this.SERVICES_DIR);
|
|
481
500
|
return files.length > 0;
|
|
482
501
|
} catch {
|
|
483
502
|
return false;
|
|
@@ -500,11 +519,11 @@ var init_service_installer = __esm({
|
|
|
500
519
|
*/
|
|
501
520
|
static async listServices() {
|
|
502
521
|
try {
|
|
503
|
-
const exists = await
|
|
522
|
+
const exists = await fs2.pathExists(this.SERVICES_DIR);
|
|
504
523
|
if (!exists) {
|
|
505
524
|
return [];
|
|
506
525
|
}
|
|
507
|
-
const files = await
|
|
526
|
+
const files = await fs2.readdir(this.SERVICES_DIR);
|
|
508
527
|
return files.filter((file) => file.endsWith(".py") || file.endsWith(".sh"));
|
|
509
528
|
} catch {
|
|
510
529
|
return [];
|
|
@@ -515,9 +534,9 @@ var init_service_installer = __esm({
|
|
|
515
534
|
*/
|
|
516
535
|
static async uninstall() {
|
|
517
536
|
try {
|
|
518
|
-
const exists = await
|
|
537
|
+
const exists = await fs2.pathExists(this.SERVICES_DIR);
|
|
519
538
|
if (exists) {
|
|
520
|
-
await
|
|
539
|
+
await fs2.remove(this.SERVICES_DIR);
|
|
521
540
|
console.log("\u2713 Services uninstalled");
|
|
522
541
|
}
|
|
523
542
|
} catch (error) {
|
|
@@ -1093,17 +1112,17 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1093
1112
|
try {
|
|
1094
1113
|
const configDir = path3.join(baseDir, ".juno_task");
|
|
1095
1114
|
const configPath = path3.join(configDir, "config.json");
|
|
1096
|
-
await
|
|
1097
|
-
const configExists = await
|
|
1115
|
+
await fs2.ensureDir(configDir);
|
|
1116
|
+
const configExists = await fs2.pathExists(configPath);
|
|
1098
1117
|
const allHookTypes = getDefaultHooks();
|
|
1099
1118
|
if (!configExists) {
|
|
1100
1119
|
const defaultConfig = {
|
|
1101
1120
|
...DEFAULT_CONFIG,
|
|
1102
1121
|
hooks: allHookTypes
|
|
1103
1122
|
};
|
|
1104
|
-
await
|
|
1123
|
+
await fs2.writeJson(configPath, defaultConfig, { spaces: 2 });
|
|
1105
1124
|
} else {
|
|
1106
|
-
const existingConfig = await
|
|
1125
|
+
const existingConfig = await fs2.readJson(configPath);
|
|
1107
1126
|
let needsUpdate = false;
|
|
1108
1127
|
if (!existingConfig.hooks) {
|
|
1109
1128
|
existingConfig.hooks = allHookTypes;
|
|
@@ -1121,7 +1140,7 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1121
1140
|
needsUpdate = true;
|
|
1122
1141
|
}
|
|
1123
1142
|
if (needsUpdate) {
|
|
1124
|
-
await
|
|
1143
|
+
await fs2.writeJson(configPath, existingConfig, { spaces: 2 });
|
|
1125
1144
|
}
|
|
1126
1145
|
}
|
|
1127
1146
|
} catch (error) {
|
|
@@ -4839,7 +4858,7 @@ var init_config2 = __esm({
|
|
|
4839
4858
|
return cached;
|
|
4840
4859
|
}
|
|
4841
4860
|
try {
|
|
4842
|
-
const configContent = await
|
|
4861
|
+
const configContent = await fs2.readFile(configPath, "utf-8");
|
|
4843
4862
|
const config = JSON.parse(configContent);
|
|
4844
4863
|
this.validateConfig(config);
|
|
4845
4864
|
const resolvedConfig = this.resolveConfigPaths(config, path3.dirname(configPath));
|
|
@@ -4861,7 +4880,7 @@ var init_config2 = __esm({
|
|
|
4861
4880
|
const rootDir = path3.parse(currentDir).root;
|
|
4862
4881
|
while (currentDir !== rootDir) {
|
|
4863
4882
|
const configPath = path3.join(currentDir, ".juno_task", "mcp.json");
|
|
4864
|
-
if (await
|
|
4883
|
+
if (await fs2.pathExists(configPath)) {
|
|
4865
4884
|
return configPath;
|
|
4866
4885
|
}
|
|
4867
4886
|
currentDir = path3.dirname(currentDir);
|
|
@@ -5047,7 +5066,7 @@ var init_logger = __esm({
|
|
|
5047
5066
|
* Matches Python's generate_log_file function
|
|
5048
5067
|
*/
|
|
5049
5068
|
async initialize(subagent = "mcp") {
|
|
5050
|
-
await
|
|
5069
|
+
await fs2.ensureDir(this.logDirectory);
|
|
5051
5070
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T");
|
|
5052
5071
|
const dateStr = timestamp[0];
|
|
5053
5072
|
const timeStr = timestamp[1].split("-")[0].substring(0, 6);
|
|
@@ -5056,7 +5075,7 @@ var init_logger = __esm({
|
|
|
5056
5075
|
this.logFilePath = path3__default.join(this.logDirectory, logFileName);
|
|
5057
5076
|
const header = `# Juno-Task TypeScript Log - Started ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
5058
5077
|
`;
|
|
5059
|
-
await
|
|
5078
|
+
await fs2.writeFile(this.logFilePath, header);
|
|
5060
5079
|
}
|
|
5061
5080
|
/**
|
|
5062
5081
|
* Format log message matching Python version format
|
|
@@ -5074,7 +5093,7 @@ var init_logger = __esm({
|
|
|
5074
5093
|
if (!this.logFilePath) {
|
|
5075
5094
|
throw new Error("Logger not initialized. Call initialize() first.");
|
|
5076
5095
|
}
|
|
5077
|
-
await
|
|
5096
|
+
await fs2.appendFile(this.logFilePath, message);
|
|
5078
5097
|
}
|
|
5079
5098
|
/**
|
|
5080
5099
|
* Log message at specified level
|
|
@@ -7083,7 +7102,7 @@ var init_shell_backend = __esm({
|
|
|
7083
7102
|
const timestamp = now.getFullYear().toString() + (now.getMonth() + 1).toString().padStart(2, "0") + now.getDate().toString().padStart(2, "0") + "_" + now.getHours().toString().padStart(2, "0") + now.getMinutes().toString().padStart(2, "0") + now.getSeconds().toString().padStart(2, "0");
|
|
7084
7103
|
const logDir = path3.join(this.config.workingDirectory, ".juno_task", "logs");
|
|
7085
7104
|
try {
|
|
7086
|
-
await
|
|
7105
|
+
await fs2.ensureDir(logDir);
|
|
7087
7106
|
} catch (error) {
|
|
7088
7107
|
if (this.config?.debug) {
|
|
7089
7108
|
engineLogger.warn(`Failed to create log directory: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7108,7 +7127,7 @@ var init_shell_backend = __esm({
|
|
|
7108
7127
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7109
7128
|
const logEntry = `[${timestamp}] ${message}
|
|
7110
7129
|
`;
|
|
7111
|
-
await
|
|
7130
|
+
await fs2.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
7112
7131
|
} catch (error) {
|
|
7113
7132
|
if (this.config?.debug) {
|
|
7114
7133
|
engineLogger.warn(`Failed to write to log file: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -12807,7 +12826,7 @@ var init_main = __esm({
|
|
|
12807
12826
|
return await this.collectInteractivePrompt();
|
|
12808
12827
|
} else {
|
|
12809
12828
|
const defaultPromptPath = path3.join(process.cwd(), ".juno_task", "prompt.md");
|
|
12810
|
-
if (await
|
|
12829
|
+
if (await fs2.pathExists(defaultPromptPath)) {
|
|
12811
12830
|
console.error(chalk15.blue(`\u{1F4C4} Using default prompt: ${chalk15.cyan(".juno_task/prompt.md")}`));
|
|
12812
12831
|
return await this.loadPromptFromFile(defaultPromptPath);
|
|
12813
12832
|
} else {
|
|
@@ -12835,7 +12854,7 @@ var init_main = __esm({
|
|
|
12835
12854
|
}
|
|
12836
12855
|
try {
|
|
12837
12856
|
const resolvedPath = path3.resolve(prompt);
|
|
12838
|
-
return await
|
|
12857
|
+
return await fs2.pathExists(resolvedPath);
|
|
12839
12858
|
} catch {
|
|
12840
12859
|
return false;
|
|
12841
12860
|
}
|
|
@@ -12843,7 +12862,7 @@ var init_main = __esm({
|
|
|
12843
12862
|
async loadPromptFromFile(filePath) {
|
|
12844
12863
|
try {
|
|
12845
12864
|
const resolvedPath = path3.resolve(filePath);
|
|
12846
|
-
const content = await
|
|
12865
|
+
const content = await fs2.readFile(resolvedPath, "utf-8");
|
|
12847
12866
|
if (!content.trim()) {
|
|
12848
12867
|
throw new FileSystemError(
|
|
12849
12868
|
"Prompt file is empty",
|
|
@@ -13251,7 +13270,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13251
13270
|
const warnings = [];
|
|
13252
13271
|
const filePath = path3__default.join(baseDir, configSchema.file);
|
|
13253
13272
|
try {
|
|
13254
|
-
const exists = await
|
|
13273
|
+
const exists = await fs2.pathExists(filePath);
|
|
13255
13274
|
if (!exists) {
|
|
13256
13275
|
if (configSchema.required) {
|
|
13257
13276
|
errors.push({
|
|
@@ -13274,7 +13293,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13274
13293
|
return { isValid: !configSchema.required, errors, warnings };
|
|
13275
13294
|
}
|
|
13276
13295
|
try {
|
|
13277
|
-
await
|
|
13296
|
+
await fs2.access(filePath, fs2.constants.R_OK);
|
|
13278
13297
|
} catch (accessError) {
|
|
13279
13298
|
errors.push({
|
|
13280
13299
|
file: configSchema.file,
|
|
@@ -13290,7 +13309,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13290
13309
|
}
|
|
13291
13310
|
let jsonData;
|
|
13292
13311
|
try {
|
|
13293
|
-
const fileContent = await
|
|
13312
|
+
const fileContent = await fs2.readFile(filePath, "utf8");
|
|
13294
13313
|
jsonData = JSON.parse(fileContent);
|
|
13295
13314
|
} catch (parseError) {
|
|
13296
13315
|
const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
|
|
@@ -13425,7 +13444,7 @@ function displayValidationResults(result) {
|
|
|
13425
13444
|
}
|
|
13426
13445
|
async function logValidationResults(result, baseDir = process.cwd()) {
|
|
13427
13446
|
const logDir = path3__default.join(baseDir, ".juno_task", "logs");
|
|
13428
|
-
await
|
|
13447
|
+
await fs2.ensureDir(logDir);
|
|
13429
13448
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
13430
13449
|
const logFile = path3__default.join(logDir, `startup-validation-${timestamp}.log`);
|
|
13431
13450
|
const logContent = [
|
|
@@ -13468,7 +13487,7 @@ async function logValidationResults(result, baseDir = process.cwd()) {
|
|
|
13468
13487
|
logContent.push(``);
|
|
13469
13488
|
}
|
|
13470
13489
|
}
|
|
13471
|
-
await
|
|
13490
|
+
await fs2.writeFile(logFile, logContent.join("\n"));
|
|
13472
13491
|
return logFile;
|
|
13473
13492
|
}
|
|
13474
13493
|
async function validateStartupConfigs(baseDir = process.cwd(), verbose = false) {
|
|
@@ -13802,7 +13821,7 @@ var TemplateEngine = class {
|
|
|
13802
13821
|
let overallError;
|
|
13803
13822
|
try {
|
|
13804
13823
|
if (!options.dryRun) {
|
|
13805
|
-
await
|
|
13824
|
+
await fs2.ensureDir(targetDirectory);
|
|
13806
13825
|
}
|
|
13807
13826
|
for (const template of templates) {
|
|
13808
13827
|
try {
|
|
@@ -15152,7 +15171,7 @@ This directory contains specification documents for your project.
|
|
|
15152
15171
|
const fileName = this.getTemplateFileName(template);
|
|
15153
15172
|
const targetPath = path3.join(targetDirectory, fileName);
|
|
15154
15173
|
try {
|
|
15155
|
-
const fileExists = await
|
|
15174
|
+
const fileExists = await fs2.pathExists(targetPath);
|
|
15156
15175
|
if (fileExists && !options.force && options.onConflict !== "overwrite") {
|
|
15157
15176
|
return {
|
|
15158
15177
|
path: targetPath,
|
|
@@ -15174,10 +15193,10 @@ This directory contains specification documents for your project.
|
|
|
15174
15193
|
}
|
|
15175
15194
|
if (options.createBackup && fileExists) {
|
|
15176
15195
|
const backupPath = `${targetPath}.backup.${Date.now()}`;
|
|
15177
|
-
await
|
|
15196
|
+
await fs2.copy(targetPath, backupPath);
|
|
15178
15197
|
}
|
|
15179
|
-
await
|
|
15180
|
-
await
|
|
15198
|
+
await fs2.ensureDir(path3.dirname(targetPath));
|
|
15199
|
+
await fs2.writeFile(targetPath, renderedContent, "utf8");
|
|
15181
15200
|
return {
|
|
15182
15201
|
path: targetPath,
|
|
15183
15202
|
content: renderedContent,
|
|
@@ -15441,7 +15460,7 @@ var SimpleInitTUI = class {
|
|
|
15441
15460
|
}
|
|
15442
15461
|
async confirmSave(targetDirectory) {
|
|
15443
15462
|
const junoTaskPath = path3.join(targetDirectory, ".juno_task");
|
|
15444
|
-
if (await
|
|
15463
|
+
if (await fs2.pathExists(junoTaskPath)) {
|
|
15445
15464
|
console.log(chalk15.yellow(" \u26A0\uFE0F .juno_task directory already exists"));
|
|
15446
15465
|
console.log(chalk15.gray(" Would you like to:"));
|
|
15447
15466
|
console.log(chalk15.gray(" 1) Override existing files"));
|
|
@@ -15486,16 +15505,16 @@ var SimpleProjectGenerator = class {
|
|
|
15486
15505
|
async generate() {
|
|
15487
15506
|
const { targetDirectory, variables, force } = this.context;
|
|
15488
15507
|
console.log(chalk15.blue("\u{1F4C1} Creating project directory..."));
|
|
15489
|
-
await
|
|
15508
|
+
await fs2.ensureDir(targetDirectory);
|
|
15490
15509
|
const junoTaskDir = path3.join(targetDirectory, ".juno_task");
|
|
15491
|
-
const junoTaskExists = await
|
|
15510
|
+
const junoTaskExists = await fs2.pathExists(junoTaskDir);
|
|
15492
15511
|
if (junoTaskExists && !force) {
|
|
15493
15512
|
throw new ValidationError(
|
|
15494
15513
|
"Project already initialized. Directory .juno_task already exists.",
|
|
15495
15514
|
["Use --force flag to overwrite existing files", "Choose a different directory"]
|
|
15496
15515
|
);
|
|
15497
15516
|
}
|
|
15498
|
-
await
|
|
15517
|
+
await fs2.ensureDir(junoTaskDir);
|
|
15499
15518
|
console.log(chalk15.blue("\u2699\uFE0F Creating project configuration..."));
|
|
15500
15519
|
await this.createConfigFile(junoTaskDir, targetDirectory);
|
|
15501
15520
|
console.log(chalk15.blue("\u{1F527} Setting up MCP configuration..."));
|
|
@@ -15529,21 +15548,21 @@ var SimpleProjectGenerator = class {
|
|
|
15529
15548
|
const promptContent = await templateEngine.render(promptTemplate, templateContext);
|
|
15530
15549
|
const initContent = await templateEngine.render(initTemplate, templateContext);
|
|
15531
15550
|
const implementContent = await templateEngine.render(implementTemplate, templateContext);
|
|
15532
|
-
await
|
|
15533
|
-
await
|
|
15534
|
-
await
|
|
15551
|
+
await fs2.writeFile(path3.join(junoTaskDir, "prompt.md"), promptContent);
|
|
15552
|
+
await fs2.writeFile(path3.join(junoTaskDir, "init.md"), initContent);
|
|
15553
|
+
await fs2.writeFile(path3.join(junoTaskDir, "implement.md"), implementContent);
|
|
15535
15554
|
const userFeedbackTemplate = templateEngine.getBuiltInTemplate("USER_FEEDBACK.md");
|
|
15536
15555
|
if (userFeedbackTemplate) {
|
|
15537
15556
|
const userFeedbackContent = await templateEngine.render(userFeedbackTemplate, templateContext);
|
|
15538
|
-
await
|
|
15557
|
+
await fs2.writeFile(path3.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
|
|
15539
15558
|
}
|
|
15540
15559
|
const planTemplate = templateEngine.getBuiltInTemplate("plan.md");
|
|
15541
15560
|
if (planTemplate) {
|
|
15542
15561
|
const planContent = await templateEngine.render(planTemplate, templateContext);
|
|
15543
|
-
await
|
|
15562
|
+
await fs2.writeFile(path3.join(junoTaskDir, "plan.md"), planContent);
|
|
15544
15563
|
}
|
|
15545
15564
|
const specsDir = path3.join(junoTaskDir, "specs");
|
|
15546
|
-
await
|
|
15565
|
+
await fs2.ensureDir(specsDir);
|
|
15547
15566
|
const specsReadmeContent = `# Project Specifications
|
|
15548
15567
|
|
|
15549
15568
|
This directory contains detailed specifications for the project components.
|
|
@@ -15560,7 +15579,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15560
15579
|
- Avoid conflicts with existing file names
|
|
15561
15580
|
- Use \`.md\` extension for all specification files
|
|
15562
15581
|
`;
|
|
15563
|
-
await
|
|
15582
|
+
await fs2.writeFile(path3.join(specsDir, "README.md"), specsReadmeContent);
|
|
15564
15583
|
const requirementsContent = `# Requirements Specification
|
|
15565
15584
|
|
|
15566
15585
|
## Functional Requirements
|
|
@@ -15607,7 +15626,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15607
15626
|
- Code quality: Clean, maintainable codebase
|
|
15608
15627
|
- Documentation: Complete and accurate documentation
|
|
15609
15628
|
`;
|
|
15610
|
-
await
|
|
15629
|
+
await fs2.writeFile(path3.join(specsDir, "requirements.md"), requirementsContent);
|
|
15611
15630
|
const architectureContent = `# Architecture Specification
|
|
15612
15631
|
|
|
15613
15632
|
## System Overview
|
|
@@ -15689,7 +15708,7 @@ This project uses AI-assisted development with juno-code to achieve: ${variables
|
|
|
15689
15708
|
- Performance monitoring
|
|
15690
15709
|
- Security best practices
|
|
15691
15710
|
`;
|
|
15692
|
-
await
|
|
15711
|
+
await fs2.writeFile(path3.join(specsDir, "architecture.md"), architectureContent);
|
|
15693
15712
|
const claudeContent = `# Claude Development Session Learnings
|
|
15694
15713
|
|
|
15695
15714
|
## Project Overview
|
|
@@ -15761,7 +15780,7 @@ This file will be updated as development progresses to track:
|
|
|
15761
15780
|
- Solutions to complex problems
|
|
15762
15781
|
- Performance improvements and optimizations
|
|
15763
15782
|
`;
|
|
15764
|
-
await
|
|
15783
|
+
await fs2.writeFile(path3.join(targetDirectory, "CLAUDE.md"), claudeContent);
|
|
15765
15784
|
const agentsContent = `# AI Agent Selection and Performance
|
|
15766
15785
|
|
|
15767
15786
|
## Available Agents
|
|
@@ -15825,7 +15844,7 @@ Track agent performance for:
|
|
|
15825
15844
|
4. **Feedback Loop**: Provide feedback to improve agent performance
|
|
15826
15845
|
5. **Performance Monitoring**: Track and optimize agent usage
|
|
15827
15846
|
`;
|
|
15828
|
-
await
|
|
15847
|
+
await fs2.writeFile(path3.join(targetDirectory, "AGENTS.md"), agentsContent);
|
|
15829
15848
|
const readmeContent = `# ${variables.PROJECT_NAME}
|
|
15830
15849
|
|
|
15831
15850
|
${variables.DESCRIPTION}
|
|
@@ -15922,7 +15941,7 @@ ${variables.GIT_URL}` : ""}
|
|
|
15922
15941
|
Created with juno-code on ${variables.CURRENT_DATE}
|
|
15923
15942
|
${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
15924
15943
|
`;
|
|
15925
|
-
await
|
|
15944
|
+
await fs2.writeFile(path3.join(targetDirectory, "README.md"), readmeContent);
|
|
15926
15945
|
console.log(chalk15.blue("\u{1F4E6} Installing utility scripts..."));
|
|
15927
15946
|
await this.copyScriptsFromTemplates(junoTaskDir);
|
|
15928
15947
|
console.log(chalk15.blue("\u{1F40D} Installing Python requirements..."));
|
|
@@ -15974,7 +15993,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
15974
15993
|
hooks: getDefaultHooks()
|
|
15975
15994
|
};
|
|
15976
15995
|
const configPath = path3.join(junoTaskDir, "config.json");
|
|
15977
|
-
await
|
|
15996
|
+
await fs2.writeFile(configPath, JSON.stringify(configContent, null, 2));
|
|
15978
15997
|
console.log(chalk15.green(` \u2713 Created .juno_task/config.json with ${this.context.subagent} as default subagent`));
|
|
15979
15998
|
}
|
|
15980
15999
|
async createMcpFile(junoTaskDir, targetDirectory) {
|
|
@@ -16028,7 +16047,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16028
16047
|
}
|
|
16029
16048
|
};
|
|
16030
16049
|
const mcpPath = path3.join(junoTaskDir, "mcp.json");
|
|
16031
|
-
await
|
|
16050
|
+
await fs2.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
|
|
16032
16051
|
console.log(chalk15.green(` \u2713 Created .juno_task/mcp.json with roundtable-ai server configuration`));
|
|
16033
16052
|
}
|
|
16034
16053
|
getDefaultModelForSubagent(subagent) {
|
|
@@ -16047,7 +16066,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16047
16066
|
async copyScriptsFromTemplates(junoTaskDir) {
|
|
16048
16067
|
try {
|
|
16049
16068
|
const scriptsDir = path3.join(junoTaskDir, "scripts");
|
|
16050
|
-
await
|
|
16069
|
+
await fs2.ensureDir(scriptsDir);
|
|
16051
16070
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
16052
16071
|
const __dirname2 = path3.dirname(__filename2);
|
|
16053
16072
|
let templatesScriptsDir;
|
|
@@ -16058,11 +16077,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16058
16077
|
} else {
|
|
16059
16078
|
templatesScriptsDir = path3.join(__dirname2, "../../templates/scripts");
|
|
16060
16079
|
}
|
|
16061
|
-
if (!await
|
|
16080
|
+
if (!await fs2.pathExists(templatesScriptsDir)) {
|
|
16062
16081
|
console.log(chalk15.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
|
|
16063
16082
|
return;
|
|
16064
16083
|
}
|
|
16065
|
-
const scriptFiles = await
|
|
16084
|
+
const scriptFiles = await fs2.readdir(templatesScriptsDir);
|
|
16066
16085
|
if (scriptFiles.length === 0) {
|
|
16067
16086
|
console.log(chalk15.gray(" \u2139\uFE0F No template scripts found to install"));
|
|
16068
16087
|
return;
|
|
@@ -16071,11 +16090,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16071
16090
|
for (const scriptFile of scriptFiles) {
|
|
16072
16091
|
const sourcePath = path3.join(templatesScriptsDir, scriptFile);
|
|
16073
16092
|
const destPath = path3.join(scriptsDir, scriptFile);
|
|
16074
|
-
const stats = await
|
|
16093
|
+
const stats = await fs2.stat(sourcePath);
|
|
16075
16094
|
if (stats.isFile()) {
|
|
16076
|
-
await
|
|
16095
|
+
await fs2.copy(sourcePath, destPath);
|
|
16077
16096
|
if (scriptFile.endsWith(".sh")) {
|
|
16078
|
-
await
|
|
16097
|
+
await fs2.chmod(destPath, 493);
|
|
16079
16098
|
}
|
|
16080
16099
|
copiedCount++;
|
|
16081
16100
|
console.log(chalk15.green(` \u2713 Installed script: ${scriptFile}`));
|
|
@@ -16098,7 +16117,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16098
16117
|
try {
|
|
16099
16118
|
const scriptsDir = path3.join(junoTaskDir, "scripts");
|
|
16100
16119
|
const installScript = path3.join(scriptsDir, "install_requirements.sh");
|
|
16101
|
-
if (!await
|
|
16120
|
+
if (!await fs2.pathExists(installScript)) {
|
|
16102
16121
|
console.log(chalk15.yellow(" \u26A0\uFE0F install_requirements.sh not found, skipping Python dependencies installation"));
|
|
16103
16122
|
console.log(chalk15.gray(" You can install dependencies manually: juno-kanban, roundtable-ai"));
|
|
16104
16123
|
return;
|
|
@@ -16395,20 +16414,20 @@ init_types();
|
|
|
16395
16414
|
async function loadInitPrompt(directory) {
|
|
16396
16415
|
const junoTaskDir = path3.join(directory, ".juno_task");
|
|
16397
16416
|
const initFile = path3.join(junoTaskDir, "init.md");
|
|
16398
|
-
if (!await
|
|
16417
|
+
if (!await fs2.pathExists(junoTaskDir)) {
|
|
16399
16418
|
throw new FileSystemError(
|
|
16400
16419
|
'No .juno_task directory found. Run "juno-code init" first.',
|
|
16401
16420
|
junoTaskDir
|
|
16402
16421
|
);
|
|
16403
16422
|
}
|
|
16404
|
-
if (!await
|
|
16423
|
+
if (!await fs2.pathExists(initFile)) {
|
|
16405
16424
|
throw new FileSystemError(
|
|
16406
16425
|
"No init.md file found in .juno_task directory",
|
|
16407
16426
|
initFile
|
|
16408
16427
|
);
|
|
16409
16428
|
}
|
|
16410
16429
|
try {
|
|
16411
|
-
const content = await
|
|
16430
|
+
const content = await fs2.readFile(initFile, "utf-8");
|
|
16412
16431
|
if (!content.trim()) {
|
|
16413
16432
|
throw new FileSystemError(
|
|
16414
16433
|
"init.md file is empty. Please add task instructions.",
|
|
@@ -17440,8 +17459,8 @@ Focus on ${request.intelligence === "basic" ? "basic functionality" : request.in
|
|
|
17440
17459
|
for (const scenario of scenarios) {
|
|
17441
17460
|
const testContent = await this.generateTestContent(request, scenario, template);
|
|
17442
17461
|
const testFilePath = this.resolveTestFilePath(request, scenario);
|
|
17443
|
-
await
|
|
17444
|
-
await
|
|
17462
|
+
await fs2.ensureDir(path3.dirname(testFilePath));
|
|
17463
|
+
await fs2.writeFile(testFilePath, testContent);
|
|
17445
17464
|
testFiles.push(testFilePath);
|
|
17446
17465
|
}
|
|
17447
17466
|
return testFiles;
|
|
@@ -17693,8 +17712,8 @@ var TestExecutionEngine = class {
|
|
|
17693
17712
|
async collectCoverage(request) {
|
|
17694
17713
|
const coverageFile = path3.join(request.workingDirectory, "coverage", "coverage-summary.json");
|
|
17695
17714
|
try {
|
|
17696
|
-
if (await
|
|
17697
|
-
const coverageData = await
|
|
17715
|
+
if (await fs2.pathExists(coverageFile)) {
|
|
17716
|
+
const coverageData = await fs2.readJson(coverageFile);
|
|
17698
17717
|
return {
|
|
17699
17718
|
lines: coverageData.total?.lines?.pct || 0,
|
|
17700
17719
|
functions: coverageData.total?.functions?.pct || 0,
|
|
@@ -17877,8 +17896,8 @@ var TestReportEngine = class {
|
|
|
17877
17896
|
suggestions: analysis.suggestions,
|
|
17878
17897
|
recommendations: analysis.recommendations
|
|
17879
17898
|
};
|
|
17880
|
-
await
|
|
17881
|
-
await
|
|
17899
|
+
await fs2.ensureDir(path3.dirname(outputPath));
|
|
17900
|
+
await fs2.writeJson(outputPath, report, { spaces: 2 });
|
|
17882
17901
|
return outputPath;
|
|
17883
17902
|
}
|
|
17884
17903
|
async generateHTMLReport(analysis, outputPath, includeVisualizations) {
|
|
@@ -17941,8 +17960,8 @@ var TestReportEngine = class {
|
|
|
17941
17960
|
</body>
|
|
17942
17961
|
</html>
|
|
17943
17962
|
`.trim();
|
|
17944
|
-
await
|
|
17945
|
-
await
|
|
17963
|
+
await fs2.ensureDir(path3.dirname(outputPath));
|
|
17964
|
+
await fs2.writeFile(outputPath, html);
|
|
17946
17965
|
return outputPath;
|
|
17947
17966
|
}
|
|
17948
17967
|
generateCharts(analysis) {
|
|
@@ -17999,8 +18018,8 @@ ${analysis.suggestions.map((suggestion) => `- ${suggestion}`).join("\n")}
|
|
|
17999
18018
|
|
|
18000
18019
|
${analysis.recommendations.map((rec) => `- ${rec}`).join("\n")}
|
|
18001
18020
|
`.trim();
|
|
18002
|
-
await
|
|
18003
|
-
await
|
|
18021
|
+
await fs2.ensureDir(path3.dirname(outputPath));
|
|
18022
|
+
await fs2.writeFile(outputPath, markdown);
|
|
18004
18023
|
return outputPath;
|
|
18005
18024
|
}
|
|
18006
18025
|
async displayConsoleReport(analysis) {
|
|
@@ -18340,7 +18359,7 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18340
18359
|
preserveDays = 30,
|
|
18341
18360
|
preservePatterns = []
|
|
18342
18361
|
} = options;
|
|
18343
|
-
const originalContent = await
|
|
18362
|
+
const originalContent = await fs2.readFile(filePath, "utf-8");
|
|
18344
18363
|
const originalSize = originalContent.length;
|
|
18345
18364
|
let backupPath = "";
|
|
18346
18365
|
if (createBackup && !dryRun) {
|
|
@@ -18349,7 +18368,7 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18349
18368
|
const basename11 = path3.basename(filePath, ext);
|
|
18350
18369
|
const dirname12 = path3.dirname(filePath);
|
|
18351
18370
|
backupPath = path3.join(dirname12, `${basename11}.backup.${timestamp}${ext}`);
|
|
18352
|
-
await
|
|
18371
|
+
await fs2.writeFile(backupPath, originalContent, "utf-8");
|
|
18353
18372
|
}
|
|
18354
18373
|
const compactionAnalysis = analyzeMarkdownStructure(originalContent);
|
|
18355
18374
|
const compactedContent = compactMarkdownContent(
|
|
@@ -18364,7 +18383,7 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18364
18383
|
const compactedSize = finalContent.length;
|
|
18365
18384
|
const reductionPercentage = Math.round((originalSize - compactedSize) / originalSize * 100);
|
|
18366
18385
|
if (!dryRun) {
|
|
18367
|
-
await
|
|
18386
|
+
await fs2.writeFile(filePath, finalContent, "utf-8");
|
|
18368
18387
|
}
|
|
18369
18388
|
return {
|
|
18370
18389
|
originalSize,
|
|
@@ -18494,7 +18513,7 @@ function formatFileSize(bytes) {
|
|
|
18494
18513
|
}
|
|
18495
18514
|
async function shouldCompactFile(filePath, sizeThresholdKB = 50, ageThresholdDays = 30) {
|
|
18496
18515
|
try {
|
|
18497
|
-
const stats = await
|
|
18516
|
+
const stats = await fs2.stat(filePath);
|
|
18498
18517
|
const sizeKB = stats.size / 1024;
|
|
18499
18518
|
if (sizeKB > sizeThresholdKB) {
|
|
18500
18519
|
return true;
|
|
@@ -18516,19 +18535,19 @@ async function archiveResolvedIssues(options) {
|
|
|
18516
18535
|
feedbackFile,
|
|
18517
18536
|
archiveDir = path3.join(path3.dirname(feedbackFile), "archives"),
|
|
18518
18537
|
openIssuesThreshold = 10} = options;
|
|
18519
|
-
if (!await
|
|
18538
|
+
if (!await fs2.pathExists(feedbackFile)) {
|
|
18520
18539
|
throw new Error(`Feedback file does not exist: ${feedbackFile}`);
|
|
18521
18540
|
}
|
|
18522
|
-
const content = await
|
|
18541
|
+
const content = await fs2.readFile(feedbackFile, "utf-8");
|
|
18523
18542
|
const parsed = parseUserFeedback(content);
|
|
18524
18543
|
const warningsGenerated = [];
|
|
18525
18544
|
if (parsed.openIssues.length > openIssuesThreshold) {
|
|
18526
18545
|
const warning = `Found ${parsed.openIssues.length} open issues (threshold: ${openIssuesThreshold}). Consider reviewing and prioritizing.`;
|
|
18527
18546
|
warningsGenerated.push(warning);
|
|
18528
18547
|
const logFile = path3.join(path3.dirname(feedbackFile), "logs", "feedback-warnings.log");
|
|
18529
|
-
await
|
|
18548
|
+
await fs2.ensureDir(path3.dirname(logFile));
|
|
18530
18549
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
18531
|
-
await
|
|
18550
|
+
await fs2.appendFile(logFile, `[${timestamp}] ${warning}
|
|
18532
18551
|
`);
|
|
18533
18552
|
}
|
|
18534
18553
|
if (parsed.resolvedIssues.length === 0) {
|
|
@@ -18545,10 +18564,10 @@ async function archiveResolvedIssues(options) {
|
|
|
18545
18564
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
18546
18565
|
const archiveFile = path3.join(archiveDir, `USER_FEEDBACK_archive_${currentYear}.md`);
|
|
18547
18566
|
{
|
|
18548
|
-
await
|
|
18567
|
+
await fs2.ensureDir(archiveDir);
|
|
18549
18568
|
await appendToArchive(archiveFile, parsed.resolvedIssues);
|
|
18550
18569
|
const compactedContent = generateCompactedFeedback(parsed.openIssues, parsed.metadata);
|
|
18551
|
-
await
|
|
18570
|
+
await fs2.writeFile(feedbackFile, compactedContent, "utf-8");
|
|
18552
18571
|
}
|
|
18553
18572
|
{
|
|
18554
18573
|
console.log(chalk15.green(`\u2705 Archived ${parsed.resolvedIssues.length} resolved issues`));
|
|
@@ -18595,8 +18614,8 @@ function parseUserFeedback(content) {
|
|
|
18595
18614
|
async function appendToArchive(archiveFile, resolvedIssues) {
|
|
18596
18615
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
18597
18616
|
let archiveContent = "";
|
|
18598
|
-
if (await
|
|
18599
|
-
archiveContent = await
|
|
18617
|
+
if (await fs2.pathExists(archiveFile)) {
|
|
18618
|
+
archiveContent = await fs2.readFile(archiveFile, "utf-8");
|
|
18600
18619
|
} else {
|
|
18601
18620
|
const year = path3.basename(archiveFile).match(/(\d{4})/)?.[1] || (/* @__PURE__ */ new Date()).getFullYear();
|
|
18602
18621
|
archiveContent = `# User Feedback Archive ${year}
|
|
@@ -18630,7 +18649,7 @@ ${resolvedIssue}
|
|
|
18630
18649
|
`- Last updated: ${timestamp}`
|
|
18631
18650
|
);
|
|
18632
18651
|
}
|
|
18633
|
-
await
|
|
18652
|
+
await fs2.writeFile(archiveFile, archiveContent, "utf-8");
|
|
18634
18653
|
}
|
|
18635
18654
|
function generateCompactedFeedback(openIssues, metadata) {
|
|
18636
18655
|
let content = metadata.trim() + "\n";
|
|
@@ -18655,15 +18674,15 @@ async function shouldArchive(feedbackFile, options = {}) {
|
|
|
18655
18674
|
// 50KB
|
|
18656
18675
|
lineCountThreshold = 500
|
|
18657
18676
|
} = options;
|
|
18658
|
-
if (!await
|
|
18677
|
+
if (!await fs2.pathExists(feedbackFile)) {
|
|
18659
18678
|
return {
|
|
18660
18679
|
shouldArchive: false,
|
|
18661
18680
|
reasons: [],
|
|
18662
18681
|
stats: { openIssuesCount: 0, resolvedIssuesCount: 0, fileSizeBytes: 0, lineCount: 0 }
|
|
18663
18682
|
};
|
|
18664
18683
|
}
|
|
18665
|
-
const content = await
|
|
18666
|
-
const stats = await
|
|
18684
|
+
const content = await fs2.readFile(feedbackFile, "utf-8");
|
|
18685
|
+
const stats = await fs2.stat(feedbackFile);
|
|
18667
18686
|
const parsed = parseUserFeedback(content);
|
|
18668
18687
|
const lineCount = content.split("\n").length;
|
|
18669
18688
|
const reasons = [];
|
|
@@ -18737,16 +18756,16 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18737
18756
|
this.feedbackFile = feedbackFile;
|
|
18738
18757
|
}
|
|
18739
18758
|
async ensureExists() {
|
|
18740
|
-
if (!await
|
|
18759
|
+
if (!await fs2.pathExists(this.feedbackFile)) {
|
|
18741
18760
|
await this.createInitialFile();
|
|
18742
18761
|
}
|
|
18743
18762
|
}
|
|
18744
18763
|
async addFeedback(issue, testCriteria) {
|
|
18745
18764
|
await this.ensureExists();
|
|
18746
18765
|
try {
|
|
18747
|
-
const content = await
|
|
18766
|
+
const content = await fs2.readFile(this.feedbackFile, "utf-8");
|
|
18748
18767
|
const updatedContent = this.addIssueToContent(content, issue, testCriteria);
|
|
18749
|
-
await
|
|
18768
|
+
await fs2.writeFile(this.feedbackFile, updatedContent, "utf-8");
|
|
18750
18769
|
} catch (error) {
|
|
18751
18770
|
throw new ValidationError(
|
|
18752
18771
|
`Failed to save feedback: ${error}`,
|
|
@@ -18759,12 +18778,12 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18759
18778
|
*/
|
|
18760
18779
|
async repairMalformedFile() {
|
|
18761
18780
|
try {
|
|
18762
|
-
const content = await
|
|
18781
|
+
const content = await fs2.readFile(this.feedbackFile, "utf-8");
|
|
18763
18782
|
const hasOpenIssues = content.includes("<OPEN_ISSUES>");
|
|
18764
18783
|
const hasClosingTag = content.includes("</OPEN_ISSUES>");
|
|
18765
18784
|
if (!hasOpenIssues || !hasClosingTag) {
|
|
18766
18785
|
const backupPath = this.feedbackFile + ".backup." + Date.now();
|
|
18767
|
-
await
|
|
18786
|
+
await fs2.writeFile(backupPath, content, "utf-8");
|
|
18768
18787
|
const existingIssues = this.extractIssuesFromMalformedContent(content);
|
|
18769
18788
|
await this.createInitialFile(existingIssues);
|
|
18770
18789
|
}
|
|
@@ -18796,8 +18815,8 @@ List any features you'd like to see added or bugs you've encountered.
|
|
|
18796
18815
|
|
|
18797
18816
|
<!-- Resolved issues will be moved here -->
|
|
18798
18817
|
`;
|
|
18799
|
-
await
|
|
18800
|
-
await
|
|
18818
|
+
await fs2.ensureDir(path3.dirname(this.feedbackFile));
|
|
18819
|
+
await fs2.writeFile(this.feedbackFile, initialContent, "utf-8");
|
|
18801
18820
|
}
|
|
18802
18821
|
addIssueToContent(content, issue, testCriteria) {
|
|
18803
18822
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -18913,17 +18932,17 @@ async function handleCompactCommand(subArgs, options) {
|
|
|
18913
18932
|
if (subArgs.length > 0) {
|
|
18914
18933
|
for (const filePath of subArgs) {
|
|
18915
18934
|
const resolvedPath = path3.resolve(filePath);
|
|
18916
|
-
if (await
|
|
18935
|
+
if (await fs2.pathExists(resolvedPath)) {
|
|
18917
18936
|
filesToCompact.push(resolvedPath);
|
|
18918
18937
|
} else {
|
|
18919
18938
|
console.warn(chalk15.yellow(`\u26A0\uFE0F File not found: ${filePath}`));
|
|
18920
18939
|
}
|
|
18921
18940
|
}
|
|
18922
18941
|
} else {
|
|
18923
|
-
if (await
|
|
18942
|
+
if (await fs2.pathExists(defaultClaudeFile)) {
|
|
18924
18943
|
filesToCompact.push(defaultClaudeFile);
|
|
18925
18944
|
}
|
|
18926
|
-
if (await
|
|
18945
|
+
if (await fs2.pathExists(defaultAgentsFile)) {
|
|
18927
18946
|
filesToCompact.push(defaultAgentsFile);
|
|
18928
18947
|
}
|
|
18929
18948
|
}
|
|
@@ -19857,11 +19876,11 @@ var GitManager = class {
|
|
|
19857
19876
|
*/
|
|
19858
19877
|
async updateJunoTaskConfig(gitUrl) {
|
|
19859
19878
|
const configPath = path3.join(this.workingDirectory, ".juno_task", "init.md");
|
|
19860
|
-
if (!await
|
|
19879
|
+
if (!await fs2.pathExists(configPath)) {
|
|
19861
19880
|
return;
|
|
19862
19881
|
}
|
|
19863
19882
|
try {
|
|
19864
|
-
let content = await
|
|
19883
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
19865
19884
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
19866
19885
|
if (frontmatterMatch) {
|
|
19867
19886
|
let frontmatter = frontmatterMatch[1];
|
|
@@ -19882,7 +19901,7 @@ GIT_URL: ${gitUrl}
|
|
|
19882
19901
|
`;
|
|
19883
19902
|
content = frontmatter + content;
|
|
19884
19903
|
}
|
|
19885
|
-
await
|
|
19904
|
+
await fs2.writeFile(configPath, content, "utf-8");
|
|
19886
19905
|
} catch (error) {
|
|
19887
19906
|
console.warn(`Warning: Failed to update juno-code configuration: ${error}`);
|
|
19888
19907
|
}
|
|
@@ -22639,10 +22658,10 @@ autoload -U compinit && compinit`;
|
|
|
22639
22658
|
*/
|
|
22640
22659
|
async isSourceCommandPresent(configPath, sourceCommand) {
|
|
22641
22660
|
try {
|
|
22642
|
-
if (!await
|
|
22661
|
+
if (!await fs2.pathExists(configPath)) {
|
|
22643
22662
|
return false;
|
|
22644
22663
|
}
|
|
22645
|
-
const content = await
|
|
22664
|
+
const content = await fs2.readFile(configPath, "utf-8");
|
|
22646
22665
|
return content.includes("juno-code completion");
|
|
22647
22666
|
} catch {
|
|
22648
22667
|
return false;
|
|
@@ -22664,15 +22683,15 @@ autoload -U compinit && compinit`;
|
|
|
22664
22683
|
continue;
|
|
22665
22684
|
}
|
|
22666
22685
|
try {
|
|
22667
|
-
const completionExists = await
|
|
22668
|
-
const configExists = await
|
|
22686
|
+
const completionExists = await fs2.pathExists(shell.completionPath);
|
|
22687
|
+
const configExists = await fs2.pathExists(shell.configPath);
|
|
22669
22688
|
const isSourced = configExists && await this.isSourceCommandPresent(
|
|
22670
22689
|
shell.configPath,
|
|
22671
22690
|
this.getSourceCommand(shell.name, shell.completionPath)
|
|
22672
22691
|
);
|
|
22673
22692
|
let lastInstalled;
|
|
22674
22693
|
if (completionExists) {
|
|
22675
|
-
const stats = await
|
|
22694
|
+
const stats = await fs2.stat(shell.completionPath);
|
|
22676
22695
|
lastInstalled = stats.mtime;
|
|
22677
22696
|
}
|
|
22678
22697
|
statuses.push({
|
|
@@ -22698,7 +22717,7 @@ autoload -U compinit && compinit`;
|
|
|
22698
22717
|
async ensureCompletionDirectory(shell) {
|
|
22699
22718
|
const completionPath = this.getCompletionPath(shell);
|
|
22700
22719
|
const completionDir = path3.dirname(completionPath);
|
|
22701
|
-
await
|
|
22720
|
+
await fs2.ensureDir(completionDir);
|
|
22702
22721
|
}
|
|
22703
22722
|
/**
|
|
22704
22723
|
* Ensure directory exists for shell configuration
|
|
@@ -22706,7 +22725,7 @@ autoload -U compinit && compinit`;
|
|
|
22706
22725
|
async ensureConfigDirectory(shell) {
|
|
22707
22726
|
const configPath = this.getConfigPath(shell);
|
|
22708
22727
|
const configDir = path3.dirname(configPath);
|
|
22709
|
-
await
|
|
22728
|
+
await fs2.ensureDir(configDir);
|
|
22710
22729
|
}
|
|
22711
22730
|
/**
|
|
22712
22731
|
* Get shell version information
|
|
@@ -22730,15 +22749,15 @@ autoload -U compinit && compinit`;
|
|
|
22730
22749
|
try {
|
|
22731
22750
|
const configPath = this.getConfigPath(shell);
|
|
22732
22751
|
const configDir = path3.dirname(configPath);
|
|
22733
|
-
await
|
|
22752
|
+
await fs2.access(configDir, fs2.constants.W_OK);
|
|
22734
22753
|
} catch {
|
|
22735
22754
|
issues.push(`Cannot write to ${shell} configuration directory`);
|
|
22736
22755
|
}
|
|
22737
22756
|
try {
|
|
22738
22757
|
const completionPath = this.getCompletionPath(shell);
|
|
22739
22758
|
const completionDir = path3.dirname(completionPath);
|
|
22740
|
-
await
|
|
22741
|
-
await
|
|
22759
|
+
await fs2.ensureDir(completionDir);
|
|
22760
|
+
await fs2.access(completionDir, fs2.constants.W_OK);
|
|
22742
22761
|
} catch {
|
|
22743
22762
|
issues.push(`Cannot write to ${shell} completion directory`);
|
|
22744
22763
|
}
|
|
@@ -22809,10 +22828,10 @@ var ContextAwareCompletion = class {
|
|
|
22809
22828
|
async getSessionIds() {
|
|
22810
22829
|
try {
|
|
22811
22830
|
const sessionDir = path3.join(process.cwd(), ".juno_task", "sessions");
|
|
22812
|
-
if (!await
|
|
22831
|
+
if (!await fs2.pathExists(sessionDir)) {
|
|
22813
22832
|
return [];
|
|
22814
22833
|
}
|
|
22815
|
-
const sessions = await
|
|
22834
|
+
const sessions = await fs2.readdir(sessionDir);
|
|
22816
22835
|
return sessions.filter((name) => name.match(/^session_\d+$/)).map((name) => name.replace("session_", "")).sort((a, b) => parseInt(b) - parseInt(a));
|
|
22817
22836
|
} catch {
|
|
22818
22837
|
return [];
|
|
@@ -22826,8 +22845,8 @@ var ContextAwareCompletion = class {
|
|
|
22826
22845
|
const builtinTemplates = ["basic", "advanced", "research", "development"];
|
|
22827
22846
|
const customTemplatesDir = path3.join(process.cwd(), ".juno_task", "templates");
|
|
22828
22847
|
let customTemplates = [];
|
|
22829
|
-
if (await
|
|
22830
|
-
const files = await
|
|
22848
|
+
if (await fs2.pathExists(customTemplatesDir)) {
|
|
22849
|
+
const files = await fs2.readdir(customTemplatesDir);
|
|
22831
22850
|
customTemplates = files.filter((name) => name.endsWith(".md") || name.endsWith(".hbs")).map((name) => path3.basename(name, path3.extname(name)));
|
|
22832
22851
|
}
|
|
22833
22852
|
return [...builtinTemplates, ...customTemplates].sort();
|
|
@@ -22904,7 +22923,7 @@ var CompletionInstaller = class {
|
|
|
22904
22923
|
await this.shellDetector.ensureConfigDirectory(shell);
|
|
22905
22924
|
const script = this.generateEnhancedCompletion(shell, "juno-code");
|
|
22906
22925
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
22907
|
-
await
|
|
22926
|
+
await fs2.writeFile(completionPath, script, "utf-8");
|
|
22908
22927
|
const configPath = this.shellDetector.getConfigPath(shell);
|
|
22909
22928
|
const sourceCommand = this.shellDetector.getSourceCommand(shell, completionPath);
|
|
22910
22929
|
const warnings = [];
|
|
@@ -22912,7 +22931,7 @@ var CompletionInstaller = class {
|
|
|
22912
22931
|
const isPresent = await this.shellDetector.isSourceCommandPresent(configPath, sourceCommand);
|
|
22913
22932
|
if (!isPresent) {
|
|
22914
22933
|
try {
|
|
22915
|
-
await
|
|
22934
|
+
await fs2.appendFile(configPath, `
|
|
22916
22935
|
|
|
22917
22936
|
${sourceCommand}
|
|
22918
22937
|
`);
|
|
@@ -22943,8 +22962,8 @@ ${sourceCommand}
|
|
|
22943
22962
|
async uninstall(shell) {
|
|
22944
22963
|
try {
|
|
22945
22964
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
22946
|
-
if (await
|
|
22947
|
-
await
|
|
22965
|
+
if (await fs2.pathExists(completionPath)) {
|
|
22966
|
+
await fs2.remove(completionPath);
|
|
22948
22967
|
return true;
|
|
22949
22968
|
}
|
|
22950
22969
|
return false;
|
|
@@ -22958,7 +22977,7 @@ ${sourceCommand}
|
|
|
22958
22977
|
async isInstalled(shell) {
|
|
22959
22978
|
try {
|
|
22960
22979
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
22961
|
-
return await
|
|
22980
|
+
return await fs2.pathExists(completionPath);
|
|
22962
22981
|
} catch {
|
|
22963
22982
|
return false;
|
|
22964
22983
|
}
|