juno-code 1.0.35 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +534 -64
- package/dist/bin/cli.js +583 -181
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +582 -180
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +20 -3
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/clean_logs_folder.sh +0 -0
- package/dist/templates/scripts/install_requirements.sh +3 -0
- package/dist/templates/scripts/run_until_completion.sh +418 -0
- package/dist/templates/scripts/slack_fetch.py +717 -0
- package/dist/templates/scripts/slack_fetch.sh +269 -0
- package/dist/templates/scripts/slack_respond.py +691 -0
- package/dist/templates/scripts/slack_respond.sh +263 -0
- package/dist/templates/scripts/slack_state.py +383 -0
- package/dist/templates/services/README.md +43 -0
- package/dist/templates/services/claude.py +1 -1
- package/dist/templates/services/codex.py +4 -4
- package/dist/templates/services/gemini.py +473 -0
- package/package.json +10 -4
package/dist/bin/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import fs3 from 'fs-extra';
|
|
3
3
|
import * as path3 from 'path';
|
|
4
4
|
import path3__default, { dirname, join } from 'path';
|
|
5
5
|
import * as os4 from 'os';
|
|
@@ -142,8 +142,8 @@ var init_types = __esm({
|
|
|
142
142
|
};
|
|
143
143
|
FileSystemError = class extends CLIError {
|
|
144
144
|
code = "FILESYSTEM_ERROR";
|
|
145
|
-
constructor(message,
|
|
146
|
-
super(
|
|
145
|
+
constructor(message, path24) {
|
|
146
|
+
super(path24 ? `${message}: ${path24}` : message);
|
|
147
147
|
this.suggestions = [
|
|
148
148
|
"Check file/directory permissions",
|
|
149
149
|
"Verify path exists and is accessible",
|
|
@@ -282,6 +282,13 @@ var init_default_hooks = __esm({
|
|
|
282
282
|
"src/templates/default-hooks.ts"() {
|
|
283
283
|
init_version();
|
|
284
284
|
DEFAULT_HOOKS = {
|
|
285
|
+
// Executes once at the beginning of a run (before all iterations)
|
|
286
|
+
// Use for: setup, environment checks, notifications, pre-run cleanup
|
|
287
|
+
START_RUN: {
|
|
288
|
+
commands: []
|
|
289
|
+
},
|
|
290
|
+
// Executes at the start of each iteration
|
|
291
|
+
// Use for: file monitoring, state checks, per-iteration setup
|
|
285
292
|
START_ITERATION: {
|
|
286
293
|
commands: [
|
|
287
294
|
// Monitor CLAUDE.md file size
|
|
@@ -290,6 +297,16 @@ var init_default_hooks = __esm({
|
|
|
290
297
|
'file="AGENTS.md"; lines=$(wc -l < "$file" 2>/dev/null || echo 0); chars=$(wc -m < "$file" 2>/dev/null || echo 0); if [ "$lines" -gt 450 ] || [ "$chars" -gt 60000 ]; then juno-kanban "[Critical] file $file is too large, keep it lean and useful for every run of the agent."; fi',
|
|
291
298
|
"./.juno_task/scripts/cleanup_feedback.sh"
|
|
292
299
|
]
|
|
300
|
+
},
|
|
301
|
+
// Executes at the end of each iteration
|
|
302
|
+
// Use for: validation, logging, per-iteration cleanup, progress tracking
|
|
303
|
+
END_ITERATION: {
|
|
304
|
+
commands: []
|
|
305
|
+
},
|
|
306
|
+
// Executes once at the end of a run (after all iterations complete)
|
|
307
|
+
// Use for: final cleanup, notifications, reports, post-run actions
|
|
308
|
+
END_RUN: {
|
|
309
|
+
commands: []
|
|
293
310
|
}
|
|
294
311
|
};
|
|
295
312
|
}
|
|
@@ -305,8 +322,21 @@ var init_service_installer = __esm({
|
|
|
305
322
|
"src/utils/service-installer.ts"() {
|
|
306
323
|
init_version();
|
|
307
324
|
ServiceInstaller = class {
|
|
325
|
+
static REQUIRED_SCRIPTS = ["codex.py", "claude.py", "gemini.py"];
|
|
308
326
|
static SERVICES_DIR = path3.join(homedir(), ".juno_code", "services");
|
|
309
327
|
static VERSION_FILE = path3.join(homedir(), ".juno_code", "services", ".version");
|
|
328
|
+
static missingScripts(baseDir) {
|
|
329
|
+
return this.REQUIRED_SCRIPTS.filter((file) => !fs3.existsSync(path3.join(baseDir, file)));
|
|
330
|
+
}
|
|
331
|
+
static async missingScriptsAsync(baseDir) {
|
|
332
|
+
const results = await Promise.all(
|
|
333
|
+
this.REQUIRED_SCRIPTS.map(async (file) => ({
|
|
334
|
+
file,
|
|
335
|
+
exists: await fs3.pathExists(path3.join(baseDir, file))
|
|
336
|
+
}))
|
|
337
|
+
);
|
|
338
|
+
return results.filter((result) => !result.exists).map((result) => result.file);
|
|
339
|
+
}
|
|
310
340
|
/**
|
|
311
341
|
* Get the current package version
|
|
312
342
|
*/
|
|
@@ -315,12 +345,12 @@ var init_service_installer = __esm({
|
|
|
315
345
|
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
316
346
|
const require3 = createRequire(import.meta.url);
|
|
317
347
|
let packageJsonPath = path3.join(__dirname2, "..", "..", "package.json");
|
|
318
|
-
if (
|
|
348
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
319
349
|
const packageJson2 = require3(packageJsonPath);
|
|
320
350
|
return packageJson2.version;
|
|
321
351
|
}
|
|
322
352
|
packageJsonPath = path3.join(__dirname2, "..", "..", "..", "package.json");
|
|
323
|
-
if (
|
|
353
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
324
354
|
const packageJson2 = require3(packageJsonPath);
|
|
325
355
|
return packageJson2.version;
|
|
326
356
|
}
|
|
@@ -334,11 +364,11 @@ var init_service_installer = __esm({
|
|
|
334
364
|
*/
|
|
335
365
|
static async getInstalledVersion() {
|
|
336
366
|
try {
|
|
337
|
-
const exists = await
|
|
367
|
+
const exists = await fs3.pathExists(this.VERSION_FILE);
|
|
338
368
|
if (!exists) {
|
|
339
369
|
return null;
|
|
340
370
|
}
|
|
341
|
-
const version3 = await
|
|
371
|
+
const version3 = await fs3.readFile(this.VERSION_FILE, "utf-8");
|
|
342
372
|
return version3.trim();
|
|
343
373
|
} catch {
|
|
344
374
|
return null;
|
|
@@ -349,7 +379,7 @@ var init_service_installer = __esm({
|
|
|
349
379
|
*/
|
|
350
380
|
static async saveVersion() {
|
|
351
381
|
const version3 = this.getPackageVersion();
|
|
352
|
-
await
|
|
382
|
+
await fs3.writeFile(this.VERSION_FILE, version3, "utf-8");
|
|
353
383
|
}
|
|
354
384
|
/**
|
|
355
385
|
* Check if services need to be updated based on version
|
|
@@ -361,7 +391,7 @@ var init_service_installer = __esm({
|
|
|
361
391
|
if (!installedVersion) {
|
|
362
392
|
return true;
|
|
363
393
|
}
|
|
364
|
-
const exists = await
|
|
394
|
+
const exists = await fs3.pathExists(this.SERVICES_DIR);
|
|
365
395
|
if (!exists) {
|
|
366
396
|
return true;
|
|
367
397
|
}
|
|
@@ -369,32 +399,22 @@ var init_service_installer = __esm({
|
|
|
369
399
|
return true;
|
|
370
400
|
}
|
|
371
401
|
if (semver.eq(packageVersion, installedVersion)) {
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
const codexExists = await fs2.pathExists(installedCodex);
|
|
375
|
-
const claudeExists = await fs2.pathExists(installedClaude);
|
|
376
|
-
if (!codexExists || !claudeExists) {
|
|
402
|
+
const missingInstalled = await this.missingScriptsAsync(this.SERVICES_DIR);
|
|
403
|
+
if (missingInstalled.length > 0) {
|
|
377
404
|
return true;
|
|
378
405
|
}
|
|
379
406
|
try {
|
|
380
407
|
const packageServicesDir = this.getPackageServicesDir();
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
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) {
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
408
|
+
const missingPackageScripts = this.missingScripts(packageServicesDir);
|
|
409
|
+
if (missingPackageScripts.length > 0) {
|
|
410
|
+
throw new Error(`Missing required service scripts: ${missingPackageScripts.join(", ")}`);
|
|
393
411
|
}
|
|
394
|
-
|
|
412
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
413
|
+
const packageScript = path3.join(packageServicesDir, script);
|
|
414
|
+
const installedScript = path3.join(this.SERVICES_DIR, script);
|
|
395
415
|
const [pkg, inst] = await Promise.all([
|
|
396
|
-
|
|
397
|
-
|
|
416
|
+
fs3.readFile(packageScript, "utf-8"),
|
|
417
|
+
fs3.readFile(installedScript, "utf-8")
|
|
398
418
|
]);
|
|
399
419
|
if (pkg !== inst) {
|
|
400
420
|
return true;
|
|
@@ -418,15 +438,27 @@ var init_service_installer = __esm({
|
|
|
418
438
|
*/
|
|
419
439
|
static getPackageServicesDir() {
|
|
420
440
|
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
441
|
+
const candidates = [
|
|
442
|
+
path3.join(__dirname2, "..", "..", "templates", "services"),
|
|
443
|
+
// dist (production)
|
|
444
|
+
path3.join(__dirname2, "..", "templates", "services")
|
|
445
|
+
// src (development)
|
|
446
|
+
];
|
|
447
|
+
for (const servicesPath of candidates) {
|
|
448
|
+
if (!fs3.existsSync(servicesPath)) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const missing = this.missingScripts(servicesPath);
|
|
452
|
+
if (missing.length === 0) {
|
|
453
|
+
return servicesPath;
|
|
454
|
+
}
|
|
455
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
456
|
+
console.error(`[DEBUG] Services path missing required scripts (${servicesPath}): ${missing.join(", ")}`);
|
|
457
|
+
}
|
|
428
458
|
}
|
|
429
|
-
throw new Error(
|
|
459
|
+
throw new Error(
|
|
460
|
+
"Could not find services directory in package containing codex.py, claude.py, and gemini.py. Try reinstalling juno-code or re-running npm run build to refresh service scripts."
|
|
461
|
+
);
|
|
430
462
|
}
|
|
431
463
|
/**
|
|
432
464
|
* Install all service scripts to ~/.juno_code/services/
|
|
@@ -434,18 +466,22 @@ var init_service_installer = __esm({
|
|
|
434
466
|
*/
|
|
435
467
|
static async install(silent = false) {
|
|
436
468
|
try {
|
|
437
|
-
await
|
|
469
|
+
await fs3.ensureDir(this.SERVICES_DIR);
|
|
438
470
|
const packageServicesDir = this.getPackageServicesDir();
|
|
439
|
-
await
|
|
471
|
+
await fs3.copy(packageServicesDir, this.SERVICES_DIR, {
|
|
440
472
|
overwrite: true,
|
|
441
473
|
preserveTimestamps: true
|
|
442
474
|
});
|
|
443
|
-
const
|
|
475
|
+
const missingAfterCopy = await this.missingScriptsAsync(this.SERVICES_DIR);
|
|
476
|
+
if (missingAfterCopy.length > 0) {
|
|
477
|
+
throw new Error(`Installed services missing required service scripts: ${missingAfterCopy.join(", ")}`);
|
|
478
|
+
}
|
|
479
|
+
const files = await fs3.readdir(this.SERVICES_DIR);
|
|
444
480
|
for (const file of files) {
|
|
445
481
|
const filePath = path3.join(this.SERVICES_DIR, file);
|
|
446
|
-
const stat = await
|
|
482
|
+
const stat = await fs3.stat(filePath);
|
|
447
483
|
if (stat.isFile() && (file.endsWith(".py") || file.endsWith(".sh"))) {
|
|
448
|
-
await
|
|
484
|
+
await fs3.chmod(filePath, 493);
|
|
449
485
|
}
|
|
450
486
|
}
|
|
451
487
|
await this.saveVersion();
|
|
@@ -492,11 +528,11 @@ var init_service_installer = __esm({
|
|
|
492
528
|
*/
|
|
493
529
|
static async isInstalled() {
|
|
494
530
|
try {
|
|
495
|
-
const exists = await
|
|
531
|
+
const exists = await fs3.pathExists(this.SERVICES_DIR);
|
|
496
532
|
if (!exists) {
|
|
497
533
|
return false;
|
|
498
534
|
}
|
|
499
|
-
const files = await
|
|
535
|
+
const files = await fs3.readdir(this.SERVICES_DIR);
|
|
500
536
|
return files.length > 0;
|
|
501
537
|
} catch {
|
|
502
538
|
return false;
|
|
@@ -519,11 +555,11 @@ var init_service_installer = __esm({
|
|
|
519
555
|
*/
|
|
520
556
|
static async listServices() {
|
|
521
557
|
try {
|
|
522
|
-
const exists = await
|
|
558
|
+
const exists = await fs3.pathExists(this.SERVICES_DIR);
|
|
523
559
|
if (!exists) {
|
|
524
560
|
return [];
|
|
525
561
|
}
|
|
526
|
-
const files = await
|
|
562
|
+
const files = await fs3.readdir(this.SERVICES_DIR);
|
|
527
563
|
return files.filter((file) => file.endsWith(".py") || file.endsWith(".sh"));
|
|
528
564
|
} catch {
|
|
529
565
|
return [];
|
|
@@ -534,9 +570,9 @@ var init_service_installer = __esm({
|
|
|
534
570
|
*/
|
|
535
571
|
static async uninstall() {
|
|
536
572
|
try {
|
|
537
|
-
const exists = await
|
|
573
|
+
const exists = await fs3.pathExists(this.SERVICES_DIR);
|
|
538
574
|
if (exists) {
|
|
539
|
-
await
|
|
575
|
+
await fs3.remove(this.SERVICES_DIR);
|
|
540
576
|
console.log("\u2713 Services uninstalled");
|
|
541
577
|
}
|
|
542
578
|
} catch (error) {
|
|
@@ -1112,17 +1148,17 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1112
1148
|
try {
|
|
1113
1149
|
const configDir = path3.join(baseDir, ".juno_task");
|
|
1114
1150
|
const configPath = path3.join(configDir, "config.json");
|
|
1115
|
-
await
|
|
1116
|
-
const configExists = await
|
|
1151
|
+
await fs3.ensureDir(configDir);
|
|
1152
|
+
const configExists = await fs3.pathExists(configPath);
|
|
1117
1153
|
const allHookTypes = getDefaultHooks();
|
|
1118
1154
|
if (!configExists) {
|
|
1119
1155
|
const defaultConfig = {
|
|
1120
1156
|
...DEFAULT_CONFIG,
|
|
1121
1157
|
hooks: allHookTypes
|
|
1122
1158
|
};
|
|
1123
|
-
await
|
|
1159
|
+
await fs3.writeJson(configPath, defaultConfig, { spaces: 2 });
|
|
1124
1160
|
} else {
|
|
1125
|
-
const existingConfig = await
|
|
1161
|
+
const existingConfig = await fs3.readJson(configPath);
|
|
1126
1162
|
let needsUpdate = false;
|
|
1127
1163
|
if (!existingConfig.hooks) {
|
|
1128
1164
|
existingConfig.hooks = allHookTypes;
|
|
@@ -1140,7 +1176,7 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1140
1176
|
needsUpdate = true;
|
|
1141
1177
|
}
|
|
1142
1178
|
if (needsUpdate) {
|
|
1143
|
-
await
|
|
1179
|
+
await fs3.writeJson(configPath, existingConfig, { spaces: 2 });
|
|
1144
1180
|
}
|
|
1145
1181
|
}
|
|
1146
1182
|
} catch (error) {
|
|
@@ -1750,6 +1786,12 @@ ${helpText}
|
|
|
1750
1786
|
}
|
|
1751
1787
|
}
|
|
1752
1788
|
if (options.maxIterations !== void 0) {
|
|
1789
|
+
if (Number.isNaN(options.maxIterations)) {
|
|
1790
|
+
throw new ValidationError(
|
|
1791
|
+
"Max iterations must be a valid number",
|
|
1792
|
+
["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1753
1795
|
if (options.maxIterations !== -1 && options.maxIterations < 1) {
|
|
1754
1796
|
throw new ValidationError(
|
|
1755
1797
|
"Max iterations must be -1 (unlimited) or a positive number",
|
|
@@ -1758,8 +1800,8 @@ ${helpText}
|
|
|
1758
1800
|
}
|
|
1759
1801
|
}
|
|
1760
1802
|
if (options.cwd) {
|
|
1761
|
-
const
|
|
1762
|
-
if (!await
|
|
1803
|
+
const fs22 = await import('fs-extra');
|
|
1804
|
+
if (!await fs22.pathExists(options.cwd)) {
|
|
1763
1805
|
throw new ValidationError(
|
|
1764
1806
|
`Working directory does not exist: ${options.cwd}`,
|
|
1765
1807
|
["Verify the path exists", "Use absolute paths to avoid ambiguity"]
|
|
@@ -3843,8 +3885,8 @@ var init_engine = __esm({
|
|
|
3843
3885
|
if (!request.workingDirectory?.trim()) {
|
|
3844
3886
|
throw new Error("Working directory is required");
|
|
3845
3887
|
}
|
|
3846
|
-
if (request.maxIterations < -1 || request.maxIterations === 0) {
|
|
3847
|
-
throw new Error("Max iterations must be positive or -1 for unlimited");
|
|
3888
|
+
if (Number.isNaN(request.maxIterations) || request.maxIterations < -1 || request.maxIterations === 0) {
|
|
3889
|
+
throw new Error("Max iterations must be a positive number or -1 for unlimited");
|
|
3848
3890
|
}
|
|
3849
3891
|
}
|
|
3850
3892
|
/**
|
|
@@ -4854,7 +4896,7 @@ var init_config2 = __esm({
|
|
|
4854
4896
|
return cached;
|
|
4855
4897
|
}
|
|
4856
4898
|
try {
|
|
4857
|
-
const configContent = await
|
|
4899
|
+
const configContent = await fs3.readFile(configPath, "utf-8");
|
|
4858
4900
|
const config = JSON.parse(configContent);
|
|
4859
4901
|
this.validateConfig(config);
|
|
4860
4902
|
const resolvedConfig = this.resolveConfigPaths(config, path3.dirname(configPath));
|
|
@@ -4876,7 +4918,7 @@ var init_config2 = __esm({
|
|
|
4876
4918
|
const rootDir = path3.parse(currentDir).root;
|
|
4877
4919
|
while (currentDir !== rootDir) {
|
|
4878
4920
|
const configPath = path3.join(currentDir, ".juno_task", "mcp.json");
|
|
4879
|
-
if (await
|
|
4921
|
+
if (await fs3.pathExists(configPath)) {
|
|
4880
4922
|
return configPath;
|
|
4881
4923
|
}
|
|
4882
4924
|
currentDir = path3.dirname(currentDir);
|
|
@@ -5062,7 +5104,7 @@ var init_logger = __esm({
|
|
|
5062
5104
|
* Matches Python's generate_log_file function
|
|
5063
5105
|
*/
|
|
5064
5106
|
async initialize(subagent = "mcp") {
|
|
5065
|
-
await
|
|
5107
|
+
await fs3.ensureDir(this.logDirectory);
|
|
5066
5108
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T");
|
|
5067
5109
|
const dateStr = timestamp[0];
|
|
5068
5110
|
const timeStr = timestamp[1].split("-")[0].substring(0, 6);
|
|
@@ -5071,7 +5113,7 @@ var init_logger = __esm({
|
|
|
5071
5113
|
this.logFilePath = path3__default.join(this.logDirectory, logFileName);
|
|
5072
5114
|
const header = `# Juno-Task TypeScript Log - Started ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
5073
5115
|
`;
|
|
5074
|
-
await
|
|
5116
|
+
await fs3.writeFile(this.logFilePath, header);
|
|
5075
5117
|
}
|
|
5076
5118
|
/**
|
|
5077
5119
|
* Format log message matching Python version format
|
|
@@ -5089,7 +5131,7 @@ var init_logger = __esm({
|
|
|
5089
5131
|
if (!this.logFilePath) {
|
|
5090
5132
|
throw new Error("Logger not initialized. Call initialize() first.");
|
|
5091
5133
|
}
|
|
5092
|
-
await
|
|
5134
|
+
await fs3.appendFile(this.logFilePath, message);
|
|
5093
5135
|
}
|
|
5094
5136
|
/**
|
|
5095
5137
|
* Log message at specified level
|
|
@@ -7100,7 +7142,7 @@ var init_shell_backend = __esm({
|
|
|
7100
7142
|
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");
|
|
7101
7143
|
const logDir = path3.join(this.config.workingDirectory, ".juno_task", "logs");
|
|
7102
7144
|
try {
|
|
7103
|
-
await
|
|
7145
|
+
await fs3.ensureDir(logDir);
|
|
7104
7146
|
} catch (error) {
|
|
7105
7147
|
if (this.config?.debug) {
|
|
7106
7148
|
engineLogger.warn(`Failed to create log directory: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7125,7 +7167,7 @@ var init_shell_backend = __esm({
|
|
|
7125
7167
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7126
7168
|
const logEntry = `[${timestamp}] ${message}
|
|
7127
7169
|
`;
|
|
7128
|
-
await
|
|
7170
|
+
await fs3.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
7129
7171
|
} catch (error) {
|
|
7130
7172
|
if (this.config?.debug) {
|
|
7131
7173
|
engineLogger.warn(`Failed to write to log file: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7199,6 +7241,7 @@ var init_shell_backend = __esm({
|
|
|
7199
7241
|
return new Promise(async (resolve9, reject) => {
|
|
7200
7242
|
const startTime = Date.now();
|
|
7201
7243
|
const isPython = scriptPath.endsWith(".py");
|
|
7244
|
+
const isGemini = subagentType === "gemini";
|
|
7202
7245
|
const env2 = {
|
|
7203
7246
|
...process.env,
|
|
7204
7247
|
...this.config.environment,
|
|
@@ -7209,6 +7252,9 @@ var init_shell_backend = __esm({
|
|
|
7209
7252
|
JUNO_ITERATION: String(request.arguments?.iteration || 1),
|
|
7210
7253
|
JUNO_TOOL_ID: toolId
|
|
7211
7254
|
};
|
|
7255
|
+
if (isGemini) {
|
|
7256
|
+
env2.GEMINI_OUTPUT_FORMAT = env2.GEMINI_OUTPUT_FORMAT || "stream-json";
|
|
7257
|
+
}
|
|
7212
7258
|
let captureDir = null;
|
|
7213
7259
|
let capturePath = null;
|
|
7214
7260
|
if (subagentType === "claude") {
|
|
@@ -7230,6 +7276,9 @@ var init_shell_backend = __esm({
|
|
|
7230
7276
|
if (isPython && request.arguments?.model) {
|
|
7231
7277
|
args.push("-m", request.arguments.model);
|
|
7232
7278
|
}
|
|
7279
|
+
if (isPython && isGemini) {
|
|
7280
|
+
args.push("--output-format", env2.GEMINI_OUTPUT_FORMAT || "stream-json");
|
|
7281
|
+
}
|
|
7233
7282
|
if (isPython && request.arguments?.agents) {
|
|
7234
7283
|
args.push("--agents", request.arguments.agents);
|
|
7235
7284
|
}
|
|
@@ -12774,12 +12823,18 @@ async function mainCommandHandler(args, options, command) {
|
|
|
12774
12823
|
console.error(chalk15.red("\n\u274C Error: --allowed-tools and --append-allowed-tools are mutually exclusive. Use one or the other."));
|
|
12775
12824
|
process.exit(1);
|
|
12776
12825
|
}
|
|
12826
|
+
if (options.maxIterations !== void 0 && Number.isNaN(options.maxIterations)) {
|
|
12827
|
+
throw new ValidationError(
|
|
12828
|
+
"Max iterations must be a valid number",
|
|
12829
|
+
["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
|
|
12830
|
+
);
|
|
12831
|
+
}
|
|
12777
12832
|
const executionRequest = createExecutionRequest({
|
|
12778
12833
|
instruction,
|
|
12779
12834
|
subagent: options.subagent,
|
|
12780
12835
|
backend: selectedBackend,
|
|
12781
12836
|
workingDirectory: config.workingDirectory,
|
|
12782
|
-
maxIterations: options.maxIterations
|
|
12837
|
+
maxIterations: options.maxIterations ?? config.defaultMaxIterations,
|
|
12783
12838
|
model: options.model || config.defaultModel,
|
|
12784
12839
|
agents: options.agents,
|
|
12785
12840
|
tools: options.tools,
|
|
@@ -12944,7 +12999,7 @@ var init_main = __esm({
|
|
|
12944
12999
|
return await this.collectInteractivePrompt();
|
|
12945
13000
|
} else {
|
|
12946
13001
|
const defaultPromptPath = path3.join(process.cwd(), ".juno_task", "prompt.md");
|
|
12947
|
-
if (await
|
|
13002
|
+
if (await fs3.pathExists(defaultPromptPath)) {
|
|
12948
13003
|
console.error(chalk15.blue(`\u{1F4C4} Using default prompt: ${chalk15.cyan(".juno_task/prompt.md")}`));
|
|
12949
13004
|
return await this.loadPromptFromFile(defaultPromptPath);
|
|
12950
13005
|
} else {
|
|
@@ -12972,7 +13027,7 @@ var init_main = __esm({
|
|
|
12972
13027
|
}
|
|
12973
13028
|
try {
|
|
12974
13029
|
const resolvedPath = path3.resolve(prompt);
|
|
12975
|
-
return await
|
|
13030
|
+
return await fs3.pathExists(resolvedPath);
|
|
12976
13031
|
} catch {
|
|
12977
13032
|
return false;
|
|
12978
13033
|
}
|
|
@@ -12980,7 +13035,7 @@ var init_main = __esm({
|
|
|
12980
13035
|
async loadPromptFromFile(filePath) {
|
|
12981
13036
|
try {
|
|
12982
13037
|
const resolvedPath = path3.resolve(filePath);
|
|
12983
|
-
const content = await
|
|
13038
|
+
const content = await fs3.readFile(resolvedPath, "utf-8");
|
|
12984
13039
|
if (!content.trim()) {
|
|
12985
13040
|
throw new FileSystemError(
|
|
12986
13041
|
"Prompt file is empty",
|
|
@@ -13302,6 +13357,342 @@ var init_main = __esm({
|
|
|
13302
13357
|
}
|
|
13303
13358
|
});
|
|
13304
13359
|
|
|
13360
|
+
// src/utils/script-installer.ts
|
|
13361
|
+
var script_installer_exports = {};
|
|
13362
|
+
__export(script_installer_exports, {
|
|
13363
|
+
ScriptInstaller: () => ScriptInstaller
|
|
13364
|
+
});
|
|
13365
|
+
var ScriptInstaller;
|
|
13366
|
+
var init_script_installer = __esm({
|
|
13367
|
+
"src/utils/script-installer.ts"() {
|
|
13368
|
+
init_version();
|
|
13369
|
+
ScriptInstaller = class {
|
|
13370
|
+
/**
|
|
13371
|
+
* Scripts that should be auto-installed if missing
|
|
13372
|
+
* These are critical scripts that users expect to be available
|
|
13373
|
+
*/
|
|
13374
|
+
/**
|
|
13375
|
+
* Required scripts include both standalone scripts and their dependencies.
|
|
13376
|
+
* kanban.sh depends on install_requirements.sh for Python venv setup.
|
|
13377
|
+
* Slack integration scripts allow fetching tasks from Slack and responding.
|
|
13378
|
+
*/
|
|
13379
|
+
static REQUIRED_SCRIPTS = [
|
|
13380
|
+
"run_until_completion.sh",
|
|
13381
|
+
"kanban.sh",
|
|
13382
|
+
"install_requirements.sh",
|
|
13383
|
+
// Required by kanban.sh for Python venv creation
|
|
13384
|
+
// Slack integration scripts
|
|
13385
|
+
"slack_state.py",
|
|
13386
|
+
// State management for Slack integration
|
|
13387
|
+
"slack_fetch.py",
|
|
13388
|
+
// Core logic for fetching Slack messages
|
|
13389
|
+
"slack_fetch.sh",
|
|
13390
|
+
// Wrapper script for Slack fetch
|
|
13391
|
+
"slack_respond.py",
|
|
13392
|
+
// Core logic for sending responses to Slack
|
|
13393
|
+
"slack_respond.sh"
|
|
13394
|
+
// Wrapper script for Slack respond
|
|
13395
|
+
];
|
|
13396
|
+
/**
|
|
13397
|
+
* Get the templates scripts directory from the package
|
|
13398
|
+
*/
|
|
13399
|
+
static getPackageScriptsDir() {
|
|
13400
|
+
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
13401
|
+
const candidates = [
|
|
13402
|
+
path3.join(__dirname2, "..", "..", "templates", "scripts"),
|
|
13403
|
+
// dist (production)
|
|
13404
|
+
path3.join(__dirname2, "..", "templates", "scripts")
|
|
13405
|
+
// src (development)
|
|
13406
|
+
];
|
|
13407
|
+
for (const scriptsPath of candidates) {
|
|
13408
|
+
if (fs3.existsSync(scriptsPath)) {
|
|
13409
|
+
return scriptsPath;
|
|
13410
|
+
}
|
|
13411
|
+
}
|
|
13412
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13413
|
+
console.error("[DEBUG] ScriptInstaller: Could not find templates/scripts directory");
|
|
13414
|
+
console.error("[DEBUG] Tried:", candidates);
|
|
13415
|
+
}
|
|
13416
|
+
return null;
|
|
13417
|
+
}
|
|
13418
|
+
/**
|
|
13419
|
+
* Check if a specific script exists in the project's .juno_task/scripts/ directory
|
|
13420
|
+
*/
|
|
13421
|
+
static async scriptExists(projectDir, scriptName) {
|
|
13422
|
+
const scriptPath = path3.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13423
|
+
return fs3.pathExists(scriptPath);
|
|
13424
|
+
}
|
|
13425
|
+
/**
|
|
13426
|
+
* Install a specific script to the project's .juno_task/scripts/ directory
|
|
13427
|
+
* @param projectDir - The project root directory
|
|
13428
|
+
* @param scriptName - Name of the script to install (e.g., 'run_until_completion.sh')
|
|
13429
|
+
* @param silent - If true, suppresses console output
|
|
13430
|
+
* @returns true if script was installed, false if installation was skipped or failed
|
|
13431
|
+
*/
|
|
13432
|
+
static async installScript(projectDir, scriptName, silent = false) {
|
|
13433
|
+
try {
|
|
13434
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13435
|
+
if (!packageScriptsDir) {
|
|
13436
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13437
|
+
console.error("[DEBUG] ScriptInstaller: Package scripts directory not found");
|
|
13438
|
+
}
|
|
13439
|
+
return false;
|
|
13440
|
+
}
|
|
13441
|
+
const sourcePath = path3.join(packageScriptsDir, scriptName);
|
|
13442
|
+
if (!await fs3.pathExists(sourcePath)) {
|
|
13443
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13444
|
+
console.error(`[DEBUG] ScriptInstaller: Source script not found: ${sourcePath}`);
|
|
13445
|
+
}
|
|
13446
|
+
return false;
|
|
13447
|
+
}
|
|
13448
|
+
const destDir = path3.join(projectDir, ".juno_task", "scripts");
|
|
13449
|
+
await fs3.ensureDir(destDir);
|
|
13450
|
+
const destPath = path3.join(destDir, scriptName);
|
|
13451
|
+
await fs3.copy(sourcePath, destPath, { overwrite: true });
|
|
13452
|
+
if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
|
|
13453
|
+
await fs3.chmod(destPath, 493);
|
|
13454
|
+
}
|
|
13455
|
+
if (!silent) {
|
|
13456
|
+
console.log(`\u2713 Installed script: ${scriptName} to .juno_task/scripts/`);
|
|
13457
|
+
}
|
|
13458
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13459
|
+
console.error(`[DEBUG] ScriptInstaller: Installed ${scriptName} to ${destPath}`);
|
|
13460
|
+
}
|
|
13461
|
+
return true;
|
|
13462
|
+
} catch (error) {
|
|
13463
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13464
|
+
console.error(`[DEBUG] ScriptInstaller: Failed to install ${scriptName}:`, error);
|
|
13465
|
+
}
|
|
13466
|
+
return false;
|
|
13467
|
+
}
|
|
13468
|
+
}
|
|
13469
|
+
/**
|
|
13470
|
+
* Check which required scripts are missing from the project
|
|
13471
|
+
* @param projectDir - The project root directory
|
|
13472
|
+
* @returns Array of missing script names
|
|
13473
|
+
*/
|
|
13474
|
+
static async getMissingScripts(projectDir) {
|
|
13475
|
+
const missing = [];
|
|
13476
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13477
|
+
if (!await this.scriptExists(projectDir, script)) {
|
|
13478
|
+
missing.push(script);
|
|
13479
|
+
}
|
|
13480
|
+
}
|
|
13481
|
+
return missing;
|
|
13482
|
+
}
|
|
13483
|
+
/**
|
|
13484
|
+
* Auto-install any missing required scripts
|
|
13485
|
+
* This should be called on CLI startup for initialized projects
|
|
13486
|
+
* @param projectDir - The project root directory
|
|
13487
|
+
* @param silent - If true, suppresses console output
|
|
13488
|
+
* @returns true if any scripts were installed
|
|
13489
|
+
*/
|
|
13490
|
+
static async autoInstallMissing(projectDir, silent = true) {
|
|
13491
|
+
try {
|
|
13492
|
+
const junoTaskDir = path3.join(projectDir, ".juno_task");
|
|
13493
|
+
if (!await fs3.pathExists(junoTaskDir)) {
|
|
13494
|
+
return false;
|
|
13495
|
+
}
|
|
13496
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13497
|
+
if (missing.length === 0) {
|
|
13498
|
+
return false;
|
|
13499
|
+
}
|
|
13500
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13501
|
+
console.error(`[DEBUG] ScriptInstaller: Missing scripts: ${missing.join(", ")}`);
|
|
13502
|
+
}
|
|
13503
|
+
let installedAny = false;
|
|
13504
|
+
for (const script of missing) {
|
|
13505
|
+
const installed = await this.installScript(projectDir, script, silent);
|
|
13506
|
+
if (installed) {
|
|
13507
|
+
installedAny = true;
|
|
13508
|
+
}
|
|
13509
|
+
}
|
|
13510
|
+
if (installedAny && !silent) {
|
|
13511
|
+
console.log(`\u2713 Auto-installed ${missing.length} missing script(s)`);
|
|
13512
|
+
}
|
|
13513
|
+
return installedAny;
|
|
13514
|
+
} catch (error) {
|
|
13515
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13516
|
+
console.error("[DEBUG] ScriptInstaller: autoInstallMissing error:", error);
|
|
13517
|
+
}
|
|
13518
|
+
return false;
|
|
13519
|
+
}
|
|
13520
|
+
}
|
|
13521
|
+
/**
|
|
13522
|
+
* Update a script if the package version is newer (by content comparison)
|
|
13523
|
+
* @param projectDir - The project root directory
|
|
13524
|
+
* @param scriptName - Name of the script to update
|
|
13525
|
+
* @param silent - If true, suppresses console output
|
|
13526
|
+
* @returns true if script was updated
|
|
13527
|
+
*/
|
|
13528
|
+
static async updateScriptIfNewer(projectDir, scriptName, silent = true) {
|
|
13529
|
+
try {
|
|
13530
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13531
|
+
if (!packageScriptsDir) {
|
|
13532
|
+
return false;
|
|
13533
|
+
}
|
|
13534
|
+
const sourcePath = path3.join(packageScriptsDir, scriptName);
|
|
13535
|
+
const destPath = path3.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13536
|
+
if (!await fs3.pathExists(destPath)) {
|
|
13537
|
+
return this.installScript(projectDir, scriptName, silent);
|
|
13538
|
+
}
|
|
13539
|
+
const [sourceContent, destContent] = await Promise.all([
|
|
13540
|
+
fs3.readFile(sourcePath, "utf-8"),
|
|
13541
|
+
fs3.readFile(destPath, "utf-8")
|
|
13542
|
+
]);
|
|
13543
|
+
if (sourceContent !== destContent) {
|
|
13544
|
+
await fs3.copy(sourcePath, destPath, { overwrite: true });
|
|
13545
|
+
if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
|
|
13546
|
+
await fs3.chmod(destPath, 493);
|
|
13547
|
+
}
|
|
13548
|
+
if (!silent) {
|
|
13549
|
+
console.log(`\u2713 Updated script: ${scriptName}`);
|
|
13550
|
+
}
|
|
13551
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13552
|
+
console.error(`[DEBUG] ScriptInstaller: Updated ${scriptName} (content changed)`);
|
|
13553
|
+
}
|
|
13554
|
+
return true;
|
|
13555
|
+
}
|
|
13556
|
+
return false;
|
|
13557
|
+
} catch (error) {
|
|
13558
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13559
|
+
console.error(`[DEBUG] ScriptInstaller: updateScriptIfNewer error for ${scriptName}:`, error);
|
|
13560
|
+
}
|
|
13561
|
+
return false;
|
|
13562
|
+
}
|
|
13563
|
+
}
|
|
13564
|
+
/**
|
|
13565
|
+
* Get the path to a script in the project's .juno_task/scripts/ directory
|
|
13566
|
+
*/
|
|
13567
|
+
static getScriptPath(projectDir, scriptName) {
|
|
13568
|
+
return path3.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13569
|
+
}
|
|
13570
|
+
/**
|
|
13571
|
+
* List all required scripts and their installation status
|
|
13572
|
+
*/
|
|
13573
|
+
static async listRequiredScripts(projectDir) {
|
|
13574
|
+
const results = [];
|
|
13575
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13576
|
+
results.push({
|
|
13577
|
+
name: script,
|
|
13578
|
+
installed: await this.scriptExists(projectDir, script)
|
|
13579
|
+
});
|
|
13580
|
+
}
|
|
13581
|
+
return results;
|
|
13582
|
+
}
|
|
13583
|
+
/**
|
|
13584
|
+
* Get scripts that need updates based on content comparison
|
|
13585
|
+
* @param projectDir - The project root directory
|
|
13586
|
+
* @returns Array of script names that have different content from package version
|
|
13587
|
+
*/
|
|
13588
|
+
static async getOutdatedScripts(projectDir) {
|
|
13589
|
+
const outdated = [];
|
|
13590
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13591
|
+
if (!packageScriptsDir) {
|
|
13592
|
+
return outdated;
|
|
13593
|
+
}
|
|
13594
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13595
|
+
const sourcePath = path3.join(packageScriptsDir, script);
|
|
13596
|
+
const destPath = path3.join(projectDir, ".juno_task", "scripts", script);
|
|
13597
|
+
if (!await fs3.pathExists(sourcePath)) {
|
|
13598
|
+
continue;
|
|
13599
|
+
}
|
|
13600
|
+
if (!await fs3.pathExists(destPath)) {
|
|
13601
|
+
continue;
|
|
13602
|
+
}
|
|
13603
|
+
try {
|
|
13604
|
+
const [sourceContent, destContent] = await Promise.all([
|
|
13605
|
+
fs3.readFile(sourcePath, "utf-8"),
|
|
13606
|
+
fs3.readFile(destPath, "utf-8")
|
|
13607
|
+
]);
|
|
13608
|
+
if (sourceContent !== destContent) {
|
|
13609
|
+
outdated.push(script);
|
|
13610
|
+
}
|
|
13611
|
+
} catch {
|
|
13612
|
+
outdated.push(script);
|
|
13613
|
+
}
|
|
13614
|
+
}
|
|
13615
|
+
return outdated;
|
|
13616
|
+
}
|
|
13617
|
+
/**
|
|
13618
|
+
* Check if any scripts need installation or update
|
|
13619
|
+
* @param projectDir - The project root directory
|
|
13620
|
+
* @returns true if any scripts need to be installed or updated
|
|
13621
|
+
*/
|
|
13622
|
+
static async needsUpdate(projectDir) {
|
|
13623
|
+
try {
|
|
13624
|
+
const junoTaskDir = path3.join(projectDir, ".juno_task");
|
|
13625
|
+
if (!await fs3.pathExists(junoTaskDir)) {
|
|
13626
|
+
return false;
|
|
13627
|
+
}
|
|
13628
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13629
|
+
if (missing.length > 0) {
|
|
13630
|
+
return true;
|
|
13631
|
+
}
|
|
13632
|
+
const outdated = await this.getOutdatedScripts(projectDir);
|
|
13633
|
+
return outdated.length > 0;
|
|
13634
|
+
} catch {
|
|
13635
|
+
return false;
|
|
13636
|
+
}
|
|
13637
|
+
}
|
|
13638
|
+
/**
|
|
13639
|
+
* Automatically update scripts - installs missing AND updates outdated scripts
|
|
13640
|
+
* Similar to ServiceInstaller.autoUpdate(), this ensures project scripts
|
|
13641
|
+
* are always in sync with the package version.
|
|
13642
|
+
*
|
|
13643
|
+
* This should be called on every CLI run to ensure scripts are up-to-date.
|
|
13644
|
+
* @param projectDir - The project root directory
|
|
13645
|
+
* @param silent - If true, suppresses console output
|
|
13646
|
+
* @returns true if any scripts were installed or updated
|
|
13647
|
+
*/
|
|
13648
|
+
static async autoUpdate(projectDir, silent = true) {
|
|
13649
|
+
try {
|
|
13650
|
+
const debug = process.env.JUNO_CODE_DEBUG === "1";
|
|
13651
|
+
const junoTaskDir = path3.join(projectDir, ".juno_task");
|
|
13652
|
+
if (!await fs3.pathExists(junoTaskDir)) {
|
|
13653
|
+
return false;
|
|
13654
|
+
}
|
|
13655
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13656
|
+
const outdated = await this.getOutdatedScripts(projectDir);
|
|
13657
|
+
if (debug) {
|
|
13658
|
+
if (missing.length > 0) {
|
|
13659
|
+
console.error(`[DEBUG] ScriptInstaller: Missing scripts: ${missing.join(", ")}`);
|
|
13660
|
+
}
|
|
13661
|
+
if (outdated.length > 0) {
|
|
13662
|
+
console.error(`[DEBUG] ScriptInstaller: Outdated scripts: ${outdated.join(", ")}`);
|
|
13663
|
+
}
|
|
13664
|
+
}
|
|
13665
|
+
if (missing.length === 0 && outdated.length === 0) {
|
|
13666
|
+
return false;
|
|
13667
|
+
}
|
|
13668
|
+
const scriptsToUpdate = [.../* @__PURE__ */ new Set([...missing, ...outdated])];
|
|
13669
|
+
let updatedAny = false;
|
|
13670
|
+
for (const script of scriptsToUpdate) {
|
|
13671
|
+
const installed = await this.installScript(projectDir, script, silent);
|
|
13672
|
+
if (installed) {
|
|
13673
|
+
updatedAny = true;
|
|
13674
|
+
}
|
|
13675
|
+
}
|
|
13676
|
+
if (updatedAny) {
|
|
13677
|
+
if (debug) {
|
|
13678
|
+
console.error(`[DEBUG] ScriptInstaller: Updated ${scriptsToUpdate.length} script(s)`);
|
|
13679
|
+
}
|
|
13680
|
+
if (!silent) {
|
|
13681
|
+
console.log(`\u2713 Updated ${scriptsToUpdate.length} script(s) in .juno_task/scripts/`);
|
|
13682
|
+
}
|
|
13683
|
+
}
|
|
13684
|
+
return updatedAny;
|
|
13685
|
+
} catch (error) {
|
|
13686
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13687
|
+
console.error("[DEBUG] ScriptInstaller: autoUpdate error:", error);
|
|
13688
|
+
}
|
|
13689
|
+
return false;
|
|
13690
|
+
}
|
|
13691
|
+
}
|
|
13692
|
+
};
|
|
13693
|
+
}
|
|
13694
|
+
});
|
|
13695
|
+
|
|
13305
13696
|
// src/utils/startup-validation.ts
|
|
13306
13697
|
var startup_validation_exports = {};
|
|
13307
13698
|
__export(startup_validation_exports, {
|
|
@@ -13392,7 +13783,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13392
13783
|
const warnings = [];
|
|
13393
13784
|
const filePath = path3__default.join(baseDir, configSchema.file);
|
|
13394
13785
|
try {
|
|
13395
|
-
const exists = await
|
|
13786
|
+
const exists = await fs3.pathExists(filePath);
|
|
13396
13787
|
if (!exists) {
|
|
13397
13788
|
if (configSchema.required) {
|
|
13398
13789
|
errors.push({
|
|
@@ -13415,7 +13806,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13415
13806
|
return { isValid: !configSchema.required, errors, warnings };
|
|
13416
13807
|
}
|
|
13417
13808
|
try {
|
|
13418
|
-
await
|
|
13809
|
+
await fs3.access(filePath, fs3.constants.R_OK);
|
|
13419
13810
|
} catch (accessError) {
|
|
13420
13811
|
errors.push({
|
|
13421
13812
|
file: configSchema.file,
|
|
@@ -13431,7 +13822,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13431
13822
|
}
|
|
13432
13823
|
let jsonData;
|
|
13433
13824
|
try {
|
|
13434
|
-
const fileContent = await
|
|
13825
|
+
const fileContent = await fs3.readFile(filePath, "utf8");
|
|
13435
13826
|
jsonData = JSON.parse(fileContent);
|
|
13436
13827
|
} catch (parseError) {
|
|
13437
13828
|
const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
|
|
@@ -13566,7 +13957,7 @@ function displayValidationResults(result) {
|
|
|
13566
13957
|
}
|
|
13567
13958
|
async function logValidationResults(result, baseDir = process.cwd()) {
|
|
13568
13959
|
const logDir = path3__default.join(baseDir, ".juno_task", "logs");
|
|
13569
|
-
await
|
|
13960
|
+
await fs3.ensureDir(logDir);
|
|
13570
13961
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
13571
13962
|
const logFile = path3__default.join(logDir, `startup-validation-${timestamp}.log`);
|
|
13572
13963
|
const logContent = [
|
|
@@ -13609,7 +14000,7 @@ async function logValidationResults(result, baseDir = process.cwd()) {
|
|
|
13609
14000
|
logContent.push(``);
|
|
13610
14001
|
}
|
|
13611
14002
|
}
|
|
13612
|
-
await
|
|
14003
|
+
await fs3.writeFile(logFile, logContent.join("\n"));
|
|
13613
14004
|
return logFile;
|
|
13614
14005
|
}
|
|
13615
14006
|
async function validateStartupConfigs(baseDir = process.cwd(), verbose = false) {
|
|
@@ -13943,7 +14334,7 @@ var TemplateEngine = class {
|
|
|
13943
14334
|
let overallError;
|
|
13944
14335
|
try {
|
|
13945
14336
|
if (!options.dryRun) {
|
|
13946
|
-
await
|
|
14337
|
+
await fs3.ensureDir(targetDirectory);
|
|
13947
14338
|
}
|
|
13948
14339
|
for (const template of templates) {
|
|
13949
14340
|
try {
|
|
@@ -15293,7 +15684,7 @@ This directory contains specification documents for your project.
|
|
|
15293
15684
|
const fileName = this.getTemplateFileName(template);
|
|
15294
15685
|
const targetPath = path3.join(targetDirectory, fileName);
|
|
15295
15686
|
try {
|
|
15296
|
-
const fileExists = await
|
|
15687
|
+
const fileExists = await fs3.pathExists(targetPath);
|
|
15297
15688
|
if (fileExists && !options.force && options.onConflict !== "overwrite") {
|
|
15298
15689
|
return {
|
|
15299
15690
|
path: targetPath,
|
|
@@ -15315,10 +15706,10 @@ This directory contains specification documents for your project.
|
|
|
15315
15706
|
}
|
|
15316
15707
|
if (options.createBackup && fileExists) {
|
|
15317
15708
|
const backupPath = `${targetPath}.backup.${Date.now()}`;
|
|
15318
|
-
await
|
|
15709
|
+
await fs3.copy(targetPath, backupPath);
|
|
15319
15710
|
}
|
|
15320
|
-
await
|
|
15321
|
-
await
|
|
15711
|
+
await fs3.ensureDir(path3.dirname(targetPath));
|
|
15712
|
+
await fs3.writeFile(targetPath, renderedContent, "utf8");
|
|
15322
15713
|
return {
|
|
15323
15714
|
path: targetPath,
|
|
15324
15715
|
content: renderedContent,
|
|
@@ -15582,7 +15973,7 @@ var SimpleInitTUI = class {
|
|
|
15582
15973
|
}
|
|
15583
15974
|
async confirmSave(targetDirectory) {
|
|
15584
15975
|
const junoTaskPath = path3.join(targetDirectory, ".juno_task");
|
|
15585
|
-
if (await
|
|
15976
|
+
if (await fs3.pathExists(junoTaskPath)) {
|
|
15586
15977
|
console.log(chalk15.yellow(" \u26A0\uFE0F .juno_task directory already exists"));
|
|
15587
15978
|
console.log(chalk15.gray(" Would you like to:"));
|
|
15588
15979
|
console.log(chalk15.gray(" 1) Override existing files"));
|
|
@@ -15627,16 +16018,16 @@ var SimpleProjectGenerator = class {
|
|
|
15627
16018
|
async generate() {
|
|
15628
16019
|
const { targetDirectory, variables, force } = this.context;
|
|
15629
16020
|
console.log(chalk15.blue("\u{1F4C1} Creating project directory..."));
|
|
15630
|
-
await
|
|
16021
|
+
await fs3.ensureDir(targetDirectory);
|
|
15631
16022
|
const junoTaskDir = path3.join(targetDirectory, ".juno_task");
|
|
15632
|
-
const junoTaskExists = await
|
|
16023
|
+
const junoTaskExists = await fs3.pathExists(junoTaskDir);
|
|
15633
16024
|
if (junoTaskExists && !force) {
|
|
15634
16025
|
throw new ValidationError(
|
|
15635
16026
|
"Project already initialized. Directory .juno_task already exists.",
|
|
15636
16027
|
["Use --force flag to overwrite existing files", "Choose a different directory"]
|
|
15637
16028
|
);
|
|
15638
16029
|
}
|
|
15639
|
-
await
|
|
16030
|
+
await fs3.ensureDir(junoTaskDir);
|
|
15640
16031
|
console.log(chalk15.blue("\u2699\uFE0F Creating project configuration..."));
|
|
15641
16032
|
await this.createConfigFile(junoTaskDir, targetDirectory);
|
|
15642
16033
|
console.log(chalk15.blue("\u{1F527} Setting up MCP configuration..."));
|
|
@@ -15670,21 +16061,21 @@ var SimpleProjectGenerator = class {
|
|
|
15670
16061
|
const promptContent = await templateEngine.render(promptTemplate, templateContext);
|
|
15671
16062
|
const initContent = await templateEngine.render(initTemplate, templateContext);
|
|
15672
16063
|
const implementContent = await templateEngine.render(implementTemplate, templateContext);
|
|
15673
|
-
await
|
|
15674
|
-
await
|
|
15675
|
-
await
|
|
16064
|
+
await fs3.writeFile(path3.join(junoTaskDir, "prompt.md"), promptContent);
|
|
16065
|
+
await fs3.writeFile(path3.join(junoTaskDir, "init.md"), initContent);
|
|
16066
|
+
await fs3.writeFile(path3.join(junoTaskDir, "implement.md"), implementContent);
|
|
15676
16067
|
const userFeedbackTemplate = templateEngine.getBuiltInTemplate("USER_FEEDBACK.md");
|
|
15677
16068
|
if (userFeedbackTemplate) {
|
|
15678
16069
|
const userFeedbackContent = await templateEngine.render(userFeedbackTemplate, templateContext);
|
|
15679
|
-
await
|
|
16070
|
+
await fs3.writeFile(path3.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
|
|
15680
16071
|
}
|
|
15681
16072
|
const planTemplate = templateEngine.getBuiltInTemplate("plan.md");
|
|
15682
16073
|
if (planTemplate) {
|
|
15683
16074
|
const planContent = await templateEngine.render(planTemplate, templateContext);
|
|
15684
|
-
await
|
|
16075
|
+
await fs3.writeFile(path3.join(junoTaskDir, "plan.md"), planContent);
|
|
15685
16076
|
}
|
|
15686
16077
|
const specsDir = path3.join(junoTaskDir, "specs");
|
|
15687
|
-
await
|
|
16078
|
+
await fs3.ensureDir(specsDir);
|
|
15688
16079
|
const specsReadmeContent = `# Project Specifications
|
|
15689
16080
|
|
|
15690
16081
|
This directory contains detailed specifications for the project components.
|
|
@@ -15701,7 +16092,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15701
16092
|
- Avoid conflicts with existing file names
|
|
15702
16093
|
- Use \`.md\` extension for all specification files
|
|
15703
16094
|
`;
|
|
15704
|
-
await
|
|
16095
|
+
await fs3.writeFile(path3.join(specsDir, "README.md"), specsReadmeContent);
|
|
15705
16096
|
const requirementsContent = `# Requirements Specification
|
|
15706
16097
|
|
|
15707
16098
|
## Functional Requirements
|
|
@@ -15748,7 +16139,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15748
16139
|
- Code quality: Clean, maintainable codebase
|
|
15749
16140
|
- Documentation: Complete and accurate documentation
|
|
15750
16141
|
`;
|
|
15751
|
-
await
|
|
16142
|
+
await fs3.writeFile(path3.join(specsDir, "requirements.md"), requirementsContent);
|
|
15752
16143
|
const architectureContent = `# Architecture Specification
|
|
15753
16144
|
|
|
15754
16145
|
## System Overview
|
|
@@ -15830,7 +16221,7 @@ This project uses AI-assisted development with juno-code to achieve: ${variables
|
|
|
15830
16221
|
- Performance monitoring
|
|
15831
16222
|
- Security best practices
|
|
15832
16223
|
`;
|
|
15833
|
-
await
|
|
16224
|
+
await fs3.writeFile(path3.join(specsDir, "architecture.md"), architectureContent);
|
|
15834
16225
|
const claudeContent = `# Claude Development Session Learnings
|
|
15835
16226
|
|
|
15836
16227
|
## Project Overview
|
|
@@ -15902,7 +16293,7 @@ This file will be updated as development progresses to track:
|
|
|
15902
16293
|
- Solutions to complex problems
|
|
15903
16294
|
- Performance improvements and optimizations
|
|
15904
16295
|
`;
|
|
15905
|
-
await
|
|
16296
|
+
await fs3.writeFile(path3.join(targetDirectory, "CLAUDE.md"), claudeContent);
|
|
15906
16297
|
const agentsContent = `# AI Agent Selection and Performance
|
|
15907
16298
|
|
|
15908
16299
|
## Available Agents
|
|
@@ -15966,7 +16357,7 @@ Track agent performance for:
|
|
|
15966
16357
|
4. **Feedback Loop**: Provide feedback to improve agent performance
|
|
15967
16358
|
5. **Performance Monitoring**: Track and optimize agent usage
|
|
15968
16359
|
`;
|
|
15969
|
-
await
|
|
16360
|
+
await fs3.writeFile(path3.join(targetDirectory, "AGENTS.md"), agentsContent);
|
|
15970
16361
|
const readmeContent = `# ${variables.PROJECT_NAME}
|
|
15971
16362
|
|
|
15972
16363
|
${variables.DESCRIPTION}
|
|
@@ -16063,7 +16454,7 @@ ${variables.GIT_URL}` : ""}
|
|
|
16063
16454
|
Created with juno-code on ${variables.CURRENT_DATE}
|
|
16064
16455
|
${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
16065
16456
|
`;
|
|
16066
|
-
await
|
|
16457
|
+
await fs3.writeFile(path3.join(targetDirectory, "README.md"), readmeContent);
|
|
16067
16458
|
console.log(chalk15.blue("\u{1F4E6} Installing utility scripts..."));
|
|
16068
16459
|
await this.copyScriptsFromTemplates(junoTaskDir);
|
|
16069
16460
|
console.log(chalk15.blue("\u{1F40D} Installing Python requirements..."));
|
|
@@ -16115,7 +16506,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16115
16506
|
hooks: getDefaultHooks()
|
|
16116
16507
|
};
|
|
16117
16508
|
const configPath = path3.join(junoTaskDir, "config.json");
|
|
16118
|
-
await
|
|
16509
|
+
await fs3.writeFile(configPath, JSON.stringify(configContent, null, 2));
|
|
16119
16510
|
console.log(chalk15.green(` \u2713 Created .juno_task/config.json with ${this.context.subagent} as default subagent`));
|
|
16120
16511
|
}
|
|
16121
16512
|
async createMcpFile(junoTaskDir, targetDirectory) {
|
|
@@ -16169,7 +16560,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16169
16560
|
}
|
|
16170
16561
|
};
|
|
16171
16562
|
const mcpPath = path3.join(junoTaskDir, "mcp.json");
|
|
16172
|
-
await
|
|
16563
|
+
await fs3.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
|
|
16173
16564
|
console.log(chalk15.green(` \u2713 Created .juno_task/mcp.json with roundtable-ai server configuration`));
|
|
16174
16565
|
}
|
|
16175
16566
|
getDefaultModelForSubagent(subagent) {
|
|
@@ -16188,7 +16579,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16188
16579
|
async copyScriptsFromTemplates(junoTaskDir) {
|
|
16189
16580
|
try {
|
|
16190
16581
|
const scriptsDir = path3.join(junoTaskDir, "scripts");
|
|
16191
|
-
await
|
|
16582
|
+
await fs3.ensureDir(scriptsDir);
|
|
16192
16583
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
16193
16584
|
const __dirname2 = path3.dirname(__filename2);
|
|
16194
16585
|
let templatesScriptsDir;
|
|
@@ -16199,11 +16590,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16199
16590
|
} else {
|
|
16200
16591
|
templatesScriptsDir = path3.join(__dirname2, "../../templates/scripts");
|
|
16201
16592
|
}
|
|
16202
|
-
if (!await
|
|
16593
|
+
if (!await fs3.pathExists(templatesScriptsDir)) {
|
|
16203
16594
|
console.log(chalk15.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
|
|
16204
16595
|
return;
|
|
16205
16596
|
}
|
|
16206
|
-
const scriptFiles = await
|
|
16597
|
+
const scriptFiles = await fs3.readdir(templatesScriptsDir);
|
|
16207
16598
|
if (scriptFiles.length === 0) {
|
|
16208
16599
|
console.log(chalk15.gray(" \u2139\uFE0F No template scripts found to install"));
|
|
16209
16600
|
return;
|
|
@@ -16212,11 +16603,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16212
16603
|
for (const scriptFile of scriptFiles) {
|
|
16213
16604
|
const sourcePath = path3.join(templatesScriptsDir, scriptFile);
|
|
16214
16605
|
const destPath = path3.join(scriptsDir, scriptFile);
|
|
16215
|
-
const stats = await
|
|
16606
|
+
const stats = await fs3.stat(sourcePath);
|
|
16216
16607
|
if (stats.isFile()) {
|
|
16217
|
-
await
|
|
16608
|
+
await fs3.copy(sourcePath, destPath);
|
|
16218
16609
|
if (scriptFile.endsWith(".sh")) {
|
|
16219
|
-
await
|
|
16610
|
+
await fs3.chmod(destPath, 493);
|
|
16220
16611
|
}
|
|
16221
16612
|
copiedCount++;
|
|
16222
16613
|
console.log(chalk15.green(` \u2713 Installed script: ${scriptFile}`));
|
|
@@ -16239,7 +16630,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16239
16630
|
try {
|
|
16240
16631
|
const scriptsDir = path3.join(junoTaskDir, "scripts");
|
|
16241
16632
|
const installScript = path3.join(scriptsDir, "install_requirements.sh");
|
|
16242
|
-
if (!await
|
|
16633
|
+
if (!await fs3.pathExists(installScript)) {
|
|
16243
16634
|
console.log(chalk15.yellow(" \u26A0\uFE0F install_requirements.sh not found, skipping Python dependencies installation"));
|
|
16244
16635
|
console.log(chalk15.gray(" You can install dependencies manually: juno-kanban, roundtable-ai"));
|
|
16245
16636
|
return;
|
|
@@ -16536,20 +16927,20 @@ init_types();
|
|
|
16536
16927
|
async function loadInitPrompt(directory) {
|
|
16537
16928
|
const junoTaskDir = path3.join(directory, ".juno_task");
|
|
16538
16929
|
const initFile = path3.join(junoTaskDir, "init.md");
|
|
16539
|
-
if (!await
|
|
16930
|
+
if (!await fs3.pathExists(junoTaskDir)) {
|
|
16540
16931
|
throw new FileSystemError(
|
|
16541
16932
|
'No .juno_task directory found. Run "juno-code init" first.',
|
|
16542
16933
|
junoTaskDir
|
|
16543
16934
|
);
|
|
16544
16935
|
}
|
|
16545
|
-
if (!await
|
|
16936
|
+
if (!await fs3.pathExists(initFile)) {
|
|
16546
16937
|
throw new FileSystemError(
|
|
16547
16938
|
"No init.md file found in .juno_task directory",
|
|
16548
16939
|
initFile
|
|
16549
16940
|
);
|
|
16550
16941
|
}
|
|
16551
16942
|
try {
|
|
16552
|
-
const content = await
|
|
16943
|
+
const content = await fs3.readFile(initFile, "utf-8");
|
|
16553
16944
|
if (!content.trim()) {
|
|
16554
16945
|
throw new FileSystemError(
|
|
16555
16946
|
"init.md file is empty. Please add task instructions.",
|
|
@@ -17581,8 +17972,8 @@ Focus on ${request.intelligence === "basic" ? "basic functionality" : request.in
|
|
|
17581
17972
|
for (const scenario of scenarios) {
|
|
17582
17973
|
const testContent = await this.generateTestContent(request, scenario, template);
|
|
17583
17974
|
const testFilePath = this.resolveTestFilePath(request, scenario);
|
|
17584
|
-
await
|
|
17585
|
-
await
|
|
17975
|
+
await fs3.ensureDir(path3.dirname(testFilePath));
|
|
17976
|
+
await fs3.writeFile(testFilePath, testContent);
|
|
17586
17977
|
testFiles.push(testFilePath);
|
|
17587
17978
|
}
|
|
17588
17979
|
return testFiles;
|
|
@@ -17834,8 +18225,8 @@ var TestExecutionEngine = class {
|
|
|
17834
18225
|
async collectCoverage(request) {
|
|
17835
18226
|
const coverageFile = path3.join(request.workingDirectory, "coverage", "coverage-summary.json");
|
|
17836
18227
|
try {
|
|
17837
|
-
if (await
|
|
17838
|
-
const coverageData = await
|
|
18228
|
+
if (await fs3.pathExists(coverageFile)) {
|
|
18229
|
+
const coverageData = await fs3.readJson(coverageFile);
|
|
17839
18230
|
return {
|
|
17840
18231
|
lines: coverageData.total?.lines?.pct || 0,
|
|
17841
18232
|
functions: coverageData.total?.functions?.pct || 0,
|
|
@@ -18018,8 +18409,8 @@ var TestReportEngine = class {
|
|
|
18018
18409
|
suggestions: analysis.suggestions,
|
|
18019
18410
|
recommendations: analysis.recommendations
|
|
18020
18411
|
};
|
|
18021
|
-
await
|
|
18022
|
-
await
|
|
18412
|
+
await fs3.ensureDir(path3.dirname(outputPath));
|
|
18413
|
+
await fs3.writeJson(outputPath, report, { spaces: 2 });
|
|
18023
18414
|
return outputPath;
|
|
18024
18415
|
}
|
|
18025
18416
|
async generateHTMLReport(analysis, outputPath, includeVisualizations) {
|
|
@@ -18082,8 +18473,8 @@ var TestReportEngine = class {
|
|
|
18082
18473
|
</body>
|
|
18083
18474
|
</html>
|
|
18084
18475
|
`.trim();
|
|
18085
|
-
await
|
|
18086
|
-
await
|
|
18476
|
+
await fs3.ensureDir(path3.dirname(outputPath));
|
|
18477
|
+
await fs3.writeFile(outputPath, html);
|
|
18087
18478
|
return outputPath;
|
|
18088
18479
|
}
|
|
18089
18480
|
generateCharts(analysis) {
|
|
@@ -18140,8 +18531,8 @@ ${analysis.suggestions.map((suggestion) => `- ${suggestion}`).join("\n")}
|
|
|
18140
18531
|
|
|
18141
18532
|
${analysis.recommendations.map((rec) => `- ${rec}`).join("\n")}
|
|
18142
18533
|
`.trim();
|
|
18143
|
-
await
|
|
18144
|
-
await
|
|
18534
|
+
await fs3.ensureDir(path3.dirname(outputPath));
|
|
18535
|
+
await fs3.writeFile(outputPath, markdown);
|
|
18145
18536
|
return outputPath;
|
|
18146
18537
|
}
|
|
18147
18538
|
async displayConsoleReport(analysis) {
|
|
@@ -18481,16 +18872,16 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18481
18872
|
preserveDays = 30,
|
|
18482
18873
|
preservePatterns = []
|
|
18483
18874
|
} = options;
|
|
18484
|
-
const originalContent = await
|
|
18875
|
+
const originalContent = await fs3.readFile(filePath, "utf-8");
|
|
18485
18876
|
const originalSize = originalContent.length;
|
|
18486
18877
|
let backupPath = "";
|
|
18487
18878
|
if (createBackup && !dryRun) {
|
|
18488
18879
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18489
18880
|
const ext = path3.extname(filePath);
|
|
18490
18881
|
const basename11 = path3.basename(filePath, ext);
|
|
18491
|
-
const
|
|
18492
|
-
backupPath = path3.join(
|
|
18493
|
-
await
|
|
18882
|
+
const dirname13 = path3.dirname(filePath);
|
|
18883
|
+
backupPath = path3.join(dirname13, `${basename11}.backup.${timestamp}${ext}`);
|
|
18884
|
+
await fs3.writeFile(backupPath, originalContent, "utf-8");
|
|
18494
18885
|
}
|
|
18495
18886
|
const compactionAnalysis = analyzeMarkdownStructure(originalContent);
|
|
18496
18887
|
const compactedContent = compactMarkdownContent(
|
|
@@ -18505,7 +18896,7 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18505
18896
|
const compactedSize = finalContent.length;
|
|
18506
18897
|
const reductionPercentage = Math.round((originalSize - compactedSize) / originalSize * 100);
|
|
18507
18898
|
if (!dryRun) {
|
|
18508
|
-
await
|
|
18899
|
+
await fs3.writeFile(filePath, finalContent, "utf-8");
|
|
18509
18900
|
}
|
|
18510
18901
|
return {
|
|
18511
18902
|
originalSize,
|
|
@@ -18635,7 +19026,7 @@ function formatFileSize(bytes) {
|
|
|
18635
19026
|
}
|
|
18636
19027
|
async function shouldCompactFile(filePath, sizeThresholdKB = 50, ageThresholdDays = 30) {
|
|
18637
19028
|
try {
|
|
18638
|
-
const stats = await
|
|
19029
|
+
const stats = await fs3.stat(filePath);
|
|
18639
19030
|
const sizeKB = stats.size / 1024;
|
|
18640
19031
|
if (sizeKB > sizeThresholdKB) {
|
|
18641
19032
|
return true;
|
|
@@ -18657,19 +19048,19 @@ async function archiveResolvedIssues(options) {
|
|
|
18657
19048
|
feedbackFile,
|
|
18658
19049
|
archiveDir = path3.join(path3.dirname(feedbackFile), "archives"),
|
|
18659
19050
|
openIssuesThreshold = 10} = options;
|
|
18660
|
-
if (!await
|
|
19051
|
+
if (!await fs3.pathExists(feedbackFile)) {
|
|
18661
19052
|
throw new Error(`Feedback file does not exist: ${feedbackFile}`);
|
|
18662
19053
|
}
|
|
18663
|
-
const content = await
|
|
19054
|
+
const content = await fs3.readFile(feedbackFile, "utf-8");
|
|
18664
19055
|
const parsed = parseUserFeedback(content);
|
|
18665
19056
|
const warningsGenerated = [];
|
|
18666
19057
|
if (parsed.openIssues.length > openIssuesThreshold) {
|
|
18667
19058
|
const warning = `Found ${parsed.openIssues.length} open issues (threshold: ${openIssuesThreshold}). Consider reviewing and prioritizing.`;
|
|
18668
19059
|
warningsGenerated.push(warning);
|
|
18669
19060
|
const logFile = path3.join(path3.dirname(feedbackFile), "logs", "feedback-warnings.log");
|
|
18670
|
-
await
|
|
19061
|
+
await fs3.ensureDir(path3.dirname(logFile));
|
|
18671
19062
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
18672
|
-
await
|
|
19063
|
+
await fs3.appendFile(logFile, `[${timestamp}] ${warning}
|
|
18673
19064
|
`);
|
|
18674
19065
|
}
|
|
18675
19066
|
if (parsed.resolvedIssues.length === 0) {
|
|
@@ -18686,10 +19077,10 @@ async function archiveResolvedIssues(options) {
|
|
|
18686
19077
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
18687
19078
|
const archiveFile = path3.join(archiveDir, `USER_FEEDBACK_archive_${currentYear}.md`);
|
|
18688
19079
|
{
|
|
18689
|
-
await
|
|
19080
|
+
await fs3.ensureDir(archiveDir);
|
|
18690
19081
|
await appendToArchive(archiveFile, parsed.resolvedIssues);
|
|
18691
19082
|
const compactedContent = generateCompactedFeedback(parsed.openIssues, parsed.metadata);
|
|
18692
|
-
await
|
|
19083
|
+
await fs3.writeFile(feedbackFile, compactedContent, "utf-8");
|
|
18693
19084
|
}
|
|
18694
19085
|
{
|
|
18695
19086
|
console.log(chalk15.green(`\u2705 Archived ${parsed.resolvedIssues.length} resolved issues`));
|
|
@@ -18736,8 +19127,8 @@ function parseUserFeedback(content) {
|
|
|
18736
19127
|
async function appendToArchive(archiveFile, resolvedIssues) {
|
|
18737
19128
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
18738
19129
|
let archiveContent = "";
|
|
18739
|
-
if (await
|
|
18740
|
-
archiveContent = await
|
|
19130
|
+
if (await fs3.pathExists(archiveFile)) {
|
|
19131
|
+
archiveContent = await fs3.readFile(archiveFile, "utf-8");
|
|
18741
19132
|
} else {
|
|
18742
19133
|
const year = path3.basename(archiveFile).match(/(\d{4})/)?.[1] || (/* @__PURE__ */ new Date()).getFullYear();
|
|
18743
19134
|
archiveContent = `# User Feedback Archive ${year}
|
|
@@ -18771,7 +19162,7 @@ ${resolvedIssue}
|
|
|
18771
19162
|
`- Last updated: ${timestamp}`
|
|
18772
19163
|
);
|
|
18773
19164
|
}
|
|
18774
|
-
await
|
|
19165
|
+
await fs3.writeFile(archiveFile, archiveContent, "utf-8");
|
|
18775
19166
|
}
|
|
18776
19167
|
function generateCompactedFeedback(openIssues, metadata) {
|
|
18777
19168
|
let content = metadata.trim() + "\n";
|
|
@@ -18796,15 +19187,15 @@ async function shouldArchive(feedbackFile, options = {}) {
|
|
|
18796
19187
|
// 50KB
|
|
18797
19188
|
lineCountThreshold = 500
|
|
18798
19189
|
} = options;
|
|
18799
|
-
if (!await
|
|
19190
|
+
if (!await fs3.pathExists(feedbackFile)) {
|
|
18800
19191
|
return {
|
|
18801
19192
|
shouldArchive: false,
|
|
18802
19193
|
reasons: [],
|
|
18803
19194
|
stats: { openIssuesCount: 0, resolvedIssuesCount: 0, fileSizeBytes: 0, lineCount: 0 }
|
|
18804
19195
|
};
|
|
18805
19196
|
}
|
|
18806
|
-
const content = await
|
|
18807
|
-
const stats = await
|
|
19197
|
+
const content = await fs3.readFile(feedbackFile, "utf-8");
|
|
19198
|
+
const stats = await fs3.stat(feedbackFile);
|
|
18808
19199
|
const parsed = parseUserFeedback(content);
|
|
18809
19200
|
const lineCount = content.split("\n").length;
|
|
18810
19201
|
const reasons = [];
|
|
@@ -18878,16 +19269,16 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18878
19269
|
this.feedbackFile = feedbackFile;
|
|
18879
19270
|
}
|
|
18880
19271
|
async ensureExists() {
|
|
18881
|
-
if (!await
|
|
19272
|
+
if (!await fs3.pathExists(this.feedbackFile)) {
|
|
18882
19273
|
await this.createInitialFile();
|
|
18883
19274
|
}
|
|
18884
19275
|
}
|
|
18885
19276
|
async addFeedback(issue, testCriteria) {
|
|
18886
19277
|
await this.ensureExists();
|
|
18887
19278
|
try {
|
|
18888
|
-
const content = await
|
|
19279
|
+
const content = await fs3.readFile(this.feedbackFile, "utf-8");
|
|
18889
19280
|
const updatedContent = this.addIssueToContent(content, issue, testCriteria);
|
|
18890
|
-
await
|
|
19281
|
+
await fs3.writeFile(this.feedbackFile, updatedContent, "utf-8");
|
|
18891
19282
|
} catch (error) {
|
|
18892
19283
|
throw new ValidationError(
|
|
18893
19284
|
`Failed to save feedback: ${error}`,
|
|
@@ -18900,12 +19291,12 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18900
19291
|
*/
|
|
18901
19292
|
async repairMalformedFile() {
|
|
18902
19293
|
try {
|
|
18903
|
-
const content = await
|
|
19294
|
+
const content = await fs3.readFile(this.feedbackFile, "utf-8");
|
|
18904
19295
|
const hasOpenIssues = content.includes("<OPEN_ISSUES>");
|
|
18905
19296
|
const hasClosingTag = content.includes("</OPEN_ISSUES>");
|
|
18906
19297
|
if (!hasOpenIssues || !hasClosingTag) {
|
|
18907
19298
|
const backupPath = this.feedbackFile + ".backup." + Date.now();
|
|
18908
|
-
await
|
|
19299
|
+
await fs3.writeFile(backupPath, content, "utf-8");
|
|
18909
19300
|
const existingIssues = this.extractIssuesFromMalformedContent(content);
|
|
18910
19301
|
await this.createInitialFile(existingIssues);
|
|
18911
19302
|
}
|
|
@@ -18937,8 +19328,8 @@ List any features you'd like to see added or bugs you've encountered.
|
|
|
18937
19328
|
|
|
18938
19329
|
<!-- Resolved issues will be moved here -->
|
|
18939
19330
|
`;
|
|
18940
|
-
await
|
|
18941
|
-
await
|
|
19331
|
+
await fs3.ensureDir(path3.dirname(this.feedbackFile));
|
|
19332
|
+
await fs3.writeFile(this.feedbackFile, initialContent, "utf-8");
|
|
18942
19333
|
}
|
|
18943
19334
|
addIssueToContent(content, issue, testCriteria) {
|
|
18944
19335
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -19054,17 +19445,17 @@ async function handleCompactCommand(subArgs, options) {
|
|
|
19054
19445
|
if (subArgs.length > 0) {
|
|
19055
19446
|
for (const filePath of subArgs) {
|
|
19056
19447
|
const resolvedPath = path3.resolve(filePath);
|
|
19057
|
-
if (await
|
|
19448
|
+
if (await fs3.pathExists(resolvedPath)) {
|
|
19058
19449
|
filesToCompact.push(resolvedPath);
|
|
19059
19450
|
} else {
|
|
19060
19451
|
console.warn(chalk15.yellow(`\u26A0\uFE0F File not found: ${filePath}`));
|
|
19061
19452
|
}
|
|
19062
19453
|
}
|
|
19063
19454
|
} else {
|
|
19064
|
-
if (await
|
|
19455
|
+
if (await fs3.pathExists(defaultClaudeFile)) {
|
|
19065
19456
|
filesToCompact.push(defaultClaudeFile);
|
|
19066
19457
|
}
|
|
19067
|
-
if (await
|
|
19458
|
+
if (await fs3.pathExists(defaultAgentsFile)) {
|
|
19068
19459
|
filesToCompact.push(defaultAgentsFile);
|
|
19069
19460
|
}
|
|
19070
19461
|
}
|
|
@@ -19998,11 +20389,11 @@ var GitManager = class {
|
|
|
19998
20389
|
*/
|
|
19999
20390
|
async updateJunoTaskConfig(gitUrl) {
|
|
20000
20391
|
const configPath = path3.join(this.workingDirectory, ".juno_task", "init.md");
|
|
20001
|
-
if (!await
|
|
20392
|
+
if (!await fs3.pathExists(configPath)) {
|
|
20002
20393
|
return;
|
|
20003
20394
|
}
|
|
20004
20395
|
try {
|
|
20005
|
-
let content = await
|
|
20396
|
+
let content = await fs3.readFile(configPath, "utf-8");
|
|
20006
20397
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
20007
20398
|
if (frontmatterMatch) {
|
|
20008
20399
|
let frontmatter = frontmatterMatch[1];
|
|
@@ -20023,7 +20414,7 @@ GIT_URL: ${gitUrl}
|
|
|
20023
20414
|
`;
|
|
20024
20415
|
content = frontmatter + content;
|
|
20025
20416
|
}
|
|
20026
|
-
await
|
|
20417
|
+
await fs3.writeFile(configPath, content, "utf-8");
|
|
20027
20418
|
} catch (error) {
|
|
20028
20419
|
console.warn(`Warning: Failed to update juno-code configuration: ${error}`);
|
|
20029
20420
|
}
|
|
@@ -20955,7 +21346,7 @@ var LogViewer = ({
|
|
|
20955
21346
|
init_types();
|
|
20956
21347
|
async function exportLogs(logger2, filepath, options) {
|
|
20957
21348
|
try {
|
|
20958
|
-
const
|
|
21349
|
+
const fs22 = await import('fs-extra');
|
|
20959
21350
|
let entries = logger2.getRecentEntries(options.tail || 1e3);
|
|
20960
21351
|
if (options.level) {
|
|
20961
21352
|
const level = LogLevel[options.level.toUpperCase()];
|
|
@@ -20985,7 +21376,7 @@ async function exportLogs(logger2, filepath, options) {
|
|
|
20985
21376
|
},
|
|
20986
21377
|
entries
|
|
20987
21378
|
};
|
|
20988
|
-
await
|
|
21379
|
+
await fs22.writeFile(filepath, JSON.stringify(exportData, null, 2));
|
|
20989
21380
|
console.log(chalk15.green(`\u2705 Exported ${entries.length} log entries to: ${filepath}`));
|
|
20990
21381
|
} catch (error) {
|
|
20991
21382
|
console.error(chalk15.red(`\u274C Failed to export logs: ${error}`));
|
|
@@ -22529,7 +22920,7 @@ function createServicesCommand() {
|
|
|
22529
22920
|
const servicesCmd = new Command("services").description("Manage juno-code service scripts").addHelpText("after", `
|
|
22530
22921
|
Examples:
|
|
22531
22922
|
$ juno-code services install Install service scripts to ~/.juno_code/services/
|
|
22532
|
-
$ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py)
|
|
22923
|
+
$ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py/gemini.py)
|
|
22533
22924
|
$ juno-code services list List installed service scripts
|
|
22534
22925
|
$ juno-code services status Check installation status
|
|
22535
22926
|
$ juno-code services uninstall Remove all service scripts
|
|
@@ -22786,10 +23177,10 @@ autoload -U compinit && compinit`;
|
|
|
22786
23177
|
*/
|
|
22787
23178
|
async isSourceCommandPresent(configPath, sourceCommand) {
|
|
22788
23179
|
try {
|
|
22789
|
-
if (!await
|
|
23180
|
+
if (!await fs3.pathExists(configPath)) {
|
|
22790
23181
|
return false;
|
|
22791
23182
|
}
|
|
22792
|
-
const content = await
|
|
23183
|
+
const content = await fs3.readFile(configPath, "utf-8");
|
|
22793
23184
|
return content.includes("juno-code completion");
|
|
22794
23185
|
} catch {
|
|
22795
23186
|
return false;
|
|
@@ -22811,15 +23202,15 @@ autoload -U compinit && compinit`;
|
|
|
22811
23202
|
continue;
|
|
22812
23203
|
}
|
|
22813
23204
|
try {
|
|
22814
|
-
const completionExists = await
|
|
22815
|
-
const configExists = await
|
|
23205
|
+
const completionExists = await fs3.pathExists(shell.completionPath);
|
|
23206
|
+
const configExists = await fs3.pathExists(shell.configPath);
|
|
22816
23207
|
const isSourced = configExists && await this.isSourceCommandPresent(
|
|
22817
23208
|
shell.configPath,
|
|
22818
23209
|
this.getSourceCommand(shell.name, shell.completionPath)
|
|
22819
23210
|
);
|
|
22820
23211
|
let lastInstalled;
|
|
22821
23212
|
if (completionExists) {
|
|
22822
|
-
const stats = await
|
|
23213
|
+
const stats = await fs3.stat(shell.completionPath);
|
|
22823
23214
|
lastInstalled = stats.mtime;
|
|
22824
23215
|
}
|
|
22825
23216
|
statuses.push({
|
|
@@ -22845,7 +23236,7 @@ autoload -U compinit && compinit`;
|
|
|
22845
23236
|
async ensureCompletionDirectory(shell) {
|
|
22846
23237
|
const completionPath = this.getCompletionPath(shell);
|
|
22847
23238
|
const completionDir = path3.dirname(completionPath);
|
|
22848
|
-
await
|
|
23239
|
+
await fs3.ensureDir(completionDir);
|
|
22849
23240
|
}
|
|
22850
23241
|
/**
|
|
22851
23242
|
* Ensure directory exists for shell configuration
|
|
@@ -22853,7 +23244,7 @@ autoload -U compinit && compinit`;
|
|
|
22853
23244
|
async ensureConfigDirectory(shell) {
|
|
22854
23245
|
const configPath = this.getConfigPath(shell);
|
|
22855
23246
|
const configDir = path3.dirname(configPath);
|
|
22856
|
-
await
|
|
23247
|
+
await fs3.ensureDir(configDir);
|
|
22857
23248
|
}
|
|
22858
23249
|
/**
|
|
22859
23250
|
* Get shell version information
|
|
@@ -22877,15 +23268,15 @@ autoload -U compinit && compinit`;
|
|
|
22877
23268
|
try {
|
|
22878
23269
|
const configPath = this.getConfigPath(shell);
|
|
22879
23270
|
const configDir = path3.dirname(configPath);
|
|
22880
|
-
await
|
|
23271
|
+
await fs3.access(configDir, fs3.constants.W_OK);
|
|
22881
23272
|
} catch {
|
|
22882
23273
|
issues.push(`Cannot write to ${shell} configuration directory`);
|
|
22883
23274
|
}
|
|
22884
23275
|
try {
|
|
22885
23276
|
const completionPath = this.getCompletionPath(shell);
|
|
22886
23277
|
const completionDir = path3.dirname(completionPath);
|
|
22887
|
-
await
|
|
22888
|
-
await
|
|
23278
|
+
await fs3.ensureDir(completionDir);
|
|
23279
|
+
await fs3.access(completionDir, fs3.constants.W_OK);
|
|
22889
23280
|
} catch {
|
|
22890
23281
|
issues.push(`Cannot write to ${shell} completion directory`);
|
|
22891
23282
|
}
|
|
@@ -22956,10 +23347,10 @@ var ContextAwareCompletion = class {
|
|
|
22956
23347
|
async getSessionIds() {
|
|
22957
23348
|
try {
|
|
22958
23349
|
const sessionDir = path3.join(process.cwd(), ".juno_task", "sessions");
|
|
22959
|
-
if (!await
|
|
23350
|
+
if (!await fs3.pathExists(sessionDir)) {
|
|
22960
23351
|
return [];
|
|
22961
23352
|
}
|
|
22962
|
-
const sessions = await
|
|
23353
|
+
const sessions = await fs3.readdir(sessionDir);
|
|
22963
23354
|
return sessions.filter((name) => name.match(/^session_\d+$/)).map((name) => name.replace("session_", "")).sort((a, b) => parseInt(b) - parseInt(a));
|
|
22964
23355
|
} catch {
|
|
22965
23356
|
return [];
|
|
@@ -22973,8 +23364,8 @@ var ContextAwareCompletion = class {
|
|
|
22973
23364
|
const builtinTemplates = ["basic", "advanced", "research", "development"];
|
|
22974
23365
|
const customTemplatesDir = path3.join(process.cwd(), ".juno_task", "templates");
|
|
22975
23366
|
let customTemplates = [];
|
|
22976
|
-
if (await
|
|
22977
|
-
const files = await
|
|
23367
|
+
if (await fs3.pathExists(customTemplatesDir)) {
|
|
23368
|
+
const files = await fs3.readdir(customTemplatesDir);
|
|
22978
23369
|
customTemplates = files.filter((name) => name.endsWith(".md") || name.endsWith(".hbs")).map((name) => path3.basename(name, path3.extname(name)));
|
|
22979
23370
|
}
|
|
22980
23371
|
return [...builtinTemplates, ...customTemplates].sort();
|
|
@@ -23051,7 +23442,7 @@ var CompletionInstaller = class {
|
|
|
23051
23442
|
await this.shellDetector.ensureConfigDirectory(shell);
|
|
23052
23443
|
const script = this.generateEnhancedCompletion(shell, "juno-code");
|
|
23053
23444
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23054
|
-
await
|
|
23445
|
+
await fs3.writeFile(completionPath, script, "utf-8");
|
|
23055
23446
|
const configPath = this.shellDetector.getConfigPath(shell);
|
|
23056
23447
|
const sourceCommand = this.shellDetector.getSourceCommand(shell, completionPath);
|
|
23057
23448
|
const warnings = [];
|
|
@@ -23059,7 +23450,7 @@ var CompletionInstaller = class {
|
|
|
23059
23450
|
const isPresent = await this.shellDetector.isSourceCommandPresent(configPath, sourceCommand);
|
|
23060
23451
|
if (!isPresent) {
|
|
23061
23452
|
try {
|
|
23062
|
-
await
|
|
23453
|
+
await fs3.appendFile(configPath, `
|
|
23063
23454
|
|
|
23064
23455
|
${sourceCommand}
|
|
23065
23456
|
`);
|
|
@@ -23090,8 +23481,8 @@ ${sourceCommand}
|
|
|
23090
23481
|
async uninstall(shell) {
|
|
23091
23482
|
try {
|
|
23092
23483
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23093
|
-
if (await
|
|
23094
|
-
await
|
|
23484
|
+
if (await fs3.pathExists(completionPath)) {
|
|
23485
|
+
await fs3.remove(completionPath);
|
|
23095
23486
|
return true;
|
|
23096
23487
|
}
|
|
23097
23488
|
return false;
|
|
@@ -23105,7 +23496,7 @@ ${sourceCommand}
|
|
|
23105
23496
|
async isInstalled(shell) {
|
|
23106
23497
|
try {
|
|
23107
23498
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23108
|
-
return await
|
|
23499
|
+
return await fs3.pathExists(completionPath);
|
|
23109
23500
|
} catch {
|
|
23110
23501
|
return false;
|
|
23111
23502
|
}
|
|
@@ -23906,11 +24297,11 @@ function setupMainCommand(program) {
|
|
|
23906
24297
|
);
|
|
23907
24298
|
const allOptions2 = { ...definedGlobalOptions, ...options };
|
|
23908
24299
|
if (!globalOptions.subagent && !options.prompt && !options.interactive && !options.interactivePrompt) {
|
|
23909
|
-
const
|
|
23910
|
-
const
|
|
24300
|
+
const fs22 = await import('fs-extra');
|
|
24301
|
+
const path24 = await import('path');
|
|
23911
24302
|
const cwd2 = process.cwd();
|
|
23912
|
-
const junoTaskDir =
|
|
23913
|
-
if (await
|
|
24303
|
+
const junoTaskDir = path24.join(cwd2, ".juno_task");
|
|
24304
|
+
if (await fs22.pathExists(junoTaskDir)) {
|
|
23914
24305
|
console.log(chalk15.blue.bold("\u{1F3AF} Juno Code - Auto-detected Initialized Project\n"));
|
|
23915
24306
|
try {
|
|
23916
24307
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -23927,12 +24318,12 @@ function setupMainCommand(program) {
|
|
|
23927
24318
|
allOptions2.subagent = config.defaultSubagent;
|
|
23928
24319
|
console.log(chalk15.gray(`\u{1F916} Using configured subagent: ${chalk15.cyan(config.defaultSubagent)}`));
|
|
23929
24320
|
}
|
|
23930
|
-
const promptFile =
|
|
23931
|
-
if (!allOptions2.prompt && await
|
|
24321
|
+
const promptFile = path24.join(junoTaskDir, "prompt.md");
|
|
24322
|
+
if (!allOptions2.prompt && await fs22.pathExists(promptFile)) {
|
|
23932
24323
|
allOptions2.prompt = promptFile;
|
|
23933
24324
|
console.log(chalk15.gray(`\u{1F4C4} Using default prompt: ${chalk15.cyan(".juno_task/prompt.md")}`));
|
|
23934
24325
|
}
|
|
23935
|
-
if (allOptions2.subagent && (allOptions2.prompt || await
|
|
24326
|
+
if (allOptions2.subagent && (allOptions2.prompt || await fs22.pathExists(promptFile))) {
|
|
23936
24327
|
console.log(chalk15.green("\u2713 Auto-detected project configuration\n"));
|
|
23937
24328
|
const { mainCommandHandler: mainCommandHandler3 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
23938
24329
|
await mainCommandHandler3([], allOptions2, command);
|
|
@@ -24089,6 +24480,17 @@ async function main() {
|
|
|
24089
24480
|
console.error("[DEBUG] Service auto-update failed:", error instanceof Error ? error.message : String(error));
|
|
24090
24481
|
}
|
|
24091
24482
|
}
|
|
24483
|
+
try {
|
|
24484
|
+
const { ScriptInstaller: ScriptInstaller2 } = await Promise.resolve().then(() => (init_script_installer(), script_installer_exports));
|
|
24485
|
+
const updated = await ScriptInstaller2.autoUpdate(process.cwd(), true);
|
|
24486
|
+
if (updated && (process.argv.includes("--verbose") || process.argv.includes("-v") || process.env.JUNO_CODE_DEBUG === "1")) {
|
|
24487
|
+
console.error("[DEBUG] Project scripts auto-updated in .juno_task/scripts/");
|
|
24488
|
+
}
|
|
24489
|
+
} catch (error) {
|
|
24490
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
24491
|
+
console.error("[DEBUG] Script auto-update failed:", error instanceof Error ? error.message : String(error));
|
|
24492
|
+
}
|
|
24493
|
+
}
|
|
24092
24494
|
program.name("juno-code").description("TypeScript implementation of juno-code CLI tool for AI subagent orchestration").version(VERSION, "-V, --version", "Display version information").helpOption("-h, --help", "Display help information");
|
|
24093
24495
|
setupGlobalOptions(program);
|
|
24094
24496
|
const isVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");
|
|
@@ -24096,10 +24498,10 @@ async function main() {
|
|
|
24096
24498
|
const isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V");
|
|
24097
24499
|
const hasNoArguments = process.argv.length <= 2;
|
|
24098
24500
|
const isInitCommand = process.argv.includes("init");
|
|
24099
|
-
const
|
|
24100
|
-
const
|
|
24101
|
-
const junoTaskDir =
|
|
24102
|
-
const isInitialized = await
|
|
24501
|
+
const fs22 = await import('fs-extra');
|
|
24502
|
+
const path24 = await import('path');
|
|
24503
|
+
const junoTaskDir = path24.join(process.cwd(), ".juno_task");
|
|
24504
|
+
const isInitialized = await fs22.pathExists(junoTaskDir);
|
|
24103
24505
|
if (!isHelpOrVersion && !hasNoArguments && !isInitCommand && isInitialized) {
|
|
24104
24506
|
try {
|
|
24105
24507
|
const { validateStartupConfigs: validateStartupConfigs2 } = await Promise.resolve().then(() => (init_startup_validation(), startup_validation_exports));
|