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.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var fs3 = require('fs-extra');
|
|
5
5
|
var path3 = require('path');
|
|
6
6
|
var os4 = require('os');
|
|
7
7
|
var url = require('url');
|
|
@@ -52,7 +52,7 @@ function _interopNamespace(e) {
|
|
|
52
52
|
return Object.freeze(n);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
var
|
|
55
|
+
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
56
56
|
var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
|
|
57
57
|
var os4__namespace = /*#__PURE__*/_interopNamespace(os4);
|
|
58
58
|
var semver__default = /*#__PURE__*/_interopDefault(semver);
|
|
@@ -178,8 +178,8 @@ var init_types = __esm({
|
|
|
178
178
|
};
|
|
179
179
|
FileSystemError = class extends CLIError {
|
|
180
180
|
code = "FILESYSTEM_ERROR";
|
|
181
|
-
constructor(message,
|
|
182
|
-
super(
|
|
181
|
+
constructor(message, path24) {
|
|
182
|
+
super(path24 ? `${message}: ${path24}` : message);
|
|
183
183
|
this.suggestions = [
|
|
184
184
|
"Check file/directory permissions",
|
|
185
185
|
"Verify path exists and is accessible",
|
|
@@ -318,6 +318,13 @@ var init_default_hooks = __esm({
|
|
|
318
318
|
"src/templates/default-hooks.ts"() {
|
|
319
319
|
init_version();
|
|
320
320
|
DEFAULT_HOOKS = {
|
|
321
|
+
// Executes once at the beginning of a run (before all iterations)
|
|
322
|
+
// Use for: setup, environment checks, notifications, pre-run cleanup
|
|
323
|
+
START_RUN: {
|
|
324
|
+
commands: []
|
|
325
|
+
},
|
|
326
|
+
// Executes at the start of each iteration
|
|
327
|
+
// Use for: file monitoring, state checks, per-iteration setup
|
|
321
328
|
START_ITERATION: {
|
|
322
329
|
commands: [
|
|
323
330
|
// Monitor CLAUDE.md file size
|
|
@@ -326,6 +333,16 @@ var init_default_hooks = __esm({
|
|
|
326
333
|
'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',
|
|
327
334
|
"./.juno_task/scripts/cleanup_feedback.sh"
|
|
328
335
|
]
|
|
336
|
+
},
|
|
337
|
+
// Executes at the end of each iteration
|
|
338
|
+
// Use for: validation, logging, per-iteration cleanup, progress tracking
|
|
339
|
+
END_ITERATION: {
|
|
340
|
+
commands: []
|
|
341
|
+
},
|
|
342
|
+
// Executes once at the end of a run (after all iterations complete)
|
|
343
|
+
// Use for: final cleanup, notifications, reports, post-run actions
|
|
344
|
+
END_RUN: {
|
|
345
|
+
commands: []
|
|
329
346
|
}
|
|
330
347
|
};
|
|
331
348
|
}
|
|
@@ -341,8 +358,21 @@ var init_service_installer = __esm({
|
|
|
341
358
|
"src/utils/service-installer.ts"() {
|
|
342
359
|
init_version();
|
|
343
360
|
ServiceInstaller = class {
|
|
361
|
+
static REQUIRED_SCRIPTS = ["codex.py", "claude.py", "gemini.py"];
|
|
344
362
|
static SERVICES_DIR = path3__namespace.join(os4.homedir(), ".juno_code", "services");
|
|
345
363
|
static VERSION_FILE = path3__namespace.join(os4.homedir(), ".juno_code", "services", ".version");
|
|
364
|
+
static missingScripts(baseDir) {
|
|
365
|
+
return this.REQUIRED_SCRIPTS.filter((file) => !fs3__default.default.existsSync(path3__namespace.join(baseDir, file)));
|
|
366
|
+
}
|
|
367
|
+
static async missingScriptsAsync(baseDir) {
|
|
368
|
+
const results = await Promise.all(
|
|
369
|
+
this.REQUIRED_SCRIPTS.map(async (file) => ({
|
|
370
|
+
file,
|
|
371
|
+
exists: await fs3__default.default.pathExists(path3__namespace.join(baseDir, file))
|
|
372
|
+
}))
|
|
373
|
+
);
|
|
374
|
+
return results.filter((result) => !result.exists).map((result) => result.file);
|
|
375
|
+
}
|
|
346
376
|
/**
|
|
347
377
|
* Get the current package version
|
|
348
378
|
*/
|
|
@@ -351,12 +381,12 @@ var init_service_installer = __esm({
|
|
|
351
381
|
const __dirname2 = path3__namespace.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
|
|
352
382
|
const require3 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
353
383
|
let packageJsonPath = path3__namespace.join(__dirname2, "..", "..", "package.json");
|
|
354
|
-
if (
|
|
384
|
+
if (fs3__default.default.existsSync(packageJsonPath)) {
|
|
355
385
|
const packageJson2 = require3(packageJsonPath);
|
|
356
386
|
return packageJson2.version;
|
|
357
387
|
}
|
|
358
388
|
packageJsonPath = path3__namespace.join(__dirname2, "..", "..", "..", "package.json");
|
|
359
|
-
if (
|
|
389
|
+
if (fs3__default.default.existsSync(packageJsonPath)) {
|
|
360
390
|
const packageJson2 = require3(packageJsonPath);
|
|
361
391
|
return packageJson2.version;
|
|
362
392
|
}
|
|
@@ -370,11 +400,11 @@ var init_service_installer = __esm({
|
|
|
370
400
|
*/
|
|
371
401
|
static async getInstalledVersion() {
|
|
372
402
|
try {
|
|
373
|
-
const exists = await
|
|
403
|
+
const exists = await fs3__default.default.pathExists(this.VERSION_FILE);
|
|
374
404
|
if (!exists) {
|
|
375
405
|
return null;
|
|
376
406
|
}
|
|
377
|
-
const version3 = await
|
|
407
|
+
const version3 = await fs3__default.default.readFile(this.VERSION_FILE, "utf-8");
|
|
378
408
|
return version3.trim();
|
|
379
409
|
} catch {
|
|
380
410
|
return null;
|
|
@@ -385,7 +415,7 @@ var init_service_installer = __esm({
|
|
|
385
415
|
*/
|
|
386
416
|
static async saveVersion() {
|
|
387
417
|
const version3 = this.getPackageVersion();
|
|
388
|
-
await
|
|
418
|
+
await fs3__default.default.writeFile(this.VERSION_FILE, version3, "utf-8");
|
|
389
419
|
}
|
|
390
420
|
/**
|
|
391
421
|
* Check if services need to be updated based on version
|
|
@@ -397,7 +427,7 @@ var init_service_installer = __esm({
|
|
|
397
427
|
if (!installedVersion) {
|
|
398
428
|
return true;
|
|
399
429
|
}
|
|
400
|
-
const exists = await
|
|
430
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
401
431
|
if (!exists) {
|
|
402
432
|
return true;
|
|
403
433
|
}
|
|
@@ -405,32 +435,22 @@ var init_service_installer = __esm({
|
|
|
405
435
|
return true;
|
|
406
436
|
}
|
|
407
437
|
if (semver__default.default.eq(packageVersion, installedVersion)) {
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
const codexExists = await fs2__default.default.pathExists(installedCodex);
|
|
411
|
-
const claudeExists = await fs2__default.default.pathExists(installedClaude);
|
|
412
|
-
if (!codexExists || !claudeExists) {
|
|
438
|
+
const missingInstalled = await this.missingScriptsAsync(this.SERVICES_DIR);
|
|
439
|
+
if (missingInstalled.length > 0) {
|
|
413
440
|
return true;
|
|
414
441
|
}
|
|
415
442
|
try {
|
|
416
443
|
const packageServicesDir = this.getPackageServicesDir();
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const packageClaudeExists = await fs2__default.default.pathExists(packageClaude);
|
|
421
|
-
if (packageCodexExists) {
|
|
422
|
-
const [pkg, inst] = await Promise.all([
|
|
423
|
-
fs2__default.default.readFile(packageCodex, "utf-8"),
|
|
424
|
-
fs2__default.default.readFile(installedCodex, "utf-8")
|
|
425
|
-
]);
|
|
426
|
-
if (pkg !== inst) {
|
|
427
|
-
return true;
|
|
428
|
-
}
|
|
444
|
+
const missingPackageScripts = this.missingScripts(packageServicesDir);
|
|
445
|
+
if (missingPackageScripts.length > 0) {
|
|
446
|
+
throw new Error(`Missing required service scripts: ${missingPackageScripts.join(", ")}`);
|
|
429
447
|
}
|
|
430
|
-
|
|
448
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
449
|
+
const packageScript = path3__namespace.join(packageServicesDir, script);
|
|
450
|
+
const installedScript = path3__namespace.join(this.SERVICES_DIR, script);
|
|
431
451
|
const [pkg, inst] = await Promise.all([
|
|
432
|
-
|
|
433
|
-
|
|
452
|
+
fs3__default.default.readFile(packageScript, "utf-8"),
|
|
453
|
+
fs3__default.default.readFile(installedScript, "utf-8")
|
|
434
454
|
]);
|
|
435
455
|
if (pkg !== inst) {
|
|
436
456
|
return true;
|
|
@@ -454,15 +474,27 @@ var init_service_installer = __esm({
|
|
|
454
474
|
*/
|
|
455
475
|
static getPackageServicesDir() {
|
|
456
476
|
const __dirname2 = path3__namespace.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
477
|
+
const candidates = [
|
|
478
|
+
path3__namespace.join(__dirname2, "..", "..", "templates", "services"),
|
|
479
|
+
// dist (production)
|
|
480
|
+
path3__namespace.join(__dirname2, "..", "templates", "services")
|
|
481
|
+
// src (development)
|
|
482
|
+
];
|
|
483
|
+
for (const servicesPath of candidates) {
|
|
484
|
+
if (!fs3__default.default.existsSync(servicesPath)) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
const missing = this.missingScripts(servicesPath);
|
|
488
|
+
if (missing.length === 0) {
|
|
489
|
+
return servicesPath;
|
|
490
|
+
}
|
|
491
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
492
|
+
console.error(`[DEBUG] Services path missing required scripts (${servicesPath}): ${missing.join(", ")}`);
|
|
493
|
+
}
|
|
464
494
|
}
|
|
465
|
-
throw new Error(
|
|
495
|
+
throw new Error(
|
|
496
|
+
"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."
|
|
497
|
+
);
|
|
466
498
|
}
|
|
467
499
|
/**
|
|
468
500
|
* Install all service scripts to ~/.juno_code/services/
|
|
@@ -470,18 +502,22 @@ var init_service_installer = __esm({
|
|
|
470
502
|
*/
|
|
471
503
|
static async install(silent = false) {
|
|
472
504
|
try {
|
|
473
|
-
await
|
|
505
|
+
await fs3__default.default.ensureDir(this.SERVICES_DIR);
|
|
474
506
|
const packageServicesDir = this.getPackageServicesDir();
|
|
475
|
-
await
|
|
507
|
+
await fs3__default.default.copy(packageServicesDir, this.SERVICES_DIR, {
|
|
476
508
|
overwrite: true,
|
|
477
509
|
preserveTimestamps: true
|
|
478
510
|
});
|
|
479
|
-
const
|
|
511
|
+
const missingAfterCopy = await this.missingScriptsAsync(this.SERVICES_DIR);
|
|
512
|
+
if (missingAfterCopy.length > 0) {
|
|
513
|
+
throw new Error(`Installed services missing required service scripts: ${missingAfterCopy.join(", ")}`);
|
|
514
|
+
}
|
|
515
|
+
const files = await fs3__default.default.readdir(this.SERVICES_DIR);
|
|
480
516
|
for (const file of files) {
|
|
481
517
|
const filePath = path3__namespace.join(this.SERVICES_DIR, file);
|
|
482
|
-
const stat = await
|
|
518
|
+
const stat = await fs3__default.default.stat(filePath);
|
|
483
519
|
if (stat.isFile() && (file.endsWith(".py") || file.endsWith(".sh"))) {
|
|
484
|
-
await
|
|
520
|
+
await fs3__default.default.chmod(filePath, 493);
|
|
485
521
|
}
|
|
486
522
|
}
|
|
487
523
|
await this.saveVersion();
|
|
@@ -528,11 +564,11 @@ var init_service_installer = __esm({
|
|
|
528
564
|
*/
|
|
529
565
|
static async isInstalled() {
|
|
530
566
|
try {
|
|
531
|
-
const exists = await
|
|
567
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
532
568
|
if (!exists) {
|
|
533
569
|
return false;
|
|
534
570
|
}
|
|
535
|
-
const files = await
|
|
571
|
+
const files = await fs3__default.default.readdir(this.SERVICES_DIR);
|
|
536
572
|
return files.length > 0;
|
|
537
573
|
} catch {
|
|
538
574
|
return false;
|
|
@@ -555,11 +591,11 @@ var init_service_installer = __esm({
|
|
|
555
591
|
*/
|
|
556
592
|
static async listServices() {
|
|
557
593
|
try {
|
|
558
|
-
const exists = await
|
|
594
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
559
595
|
if (!exists) {
|
|
560
596
|
return [];
|
|
561
597
|
}
|
|
562
|
-
const files = await
|
|
598
|
+
const files = await fs3__default.default.readdir(this.SERVICES_DIR);
|
|
563
599
|
return files.filter((file) => file.endsWith(".py") || file.endsWith(".sh"));
|
|
564
600
|
} catch {
|
|
565
601
|
return [];
|
|
@@ -570,9 +606,9 @@ var init_service_installer = __esm({
|
|
|
570
606
|
*/
|
|
571
607
|
static async uninstall() {
|
|
572
608
|
try {
|
|
573
|
-
const exists = await
|
|
609
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
574
610
|
if (exists) {
|
|
575
|
-
await
|
|
611
|
+
await fs3__default.default.remove(this.SERVICES_DIR);
|
|
576
612
|
console.log("\u2713 Services uninstalled");
|
|
577
613
|
}
|
|
578
614
|
} catch (error) {
|
|
@@ -1148,17 +1184,17 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1148
1184
|
try {
|
|
1149
1185
|
const configDir = path3__namespace.join(baseDir, ".juno_task");
|
|
1150
1186
|
const configPath = path3__namespace.join(configDir, "config.json");
|
|
1151
|
-
await
|
|
1152
|
-
const configExists = await
|
|
1187
|
+
await fs3__default.default.ensureDir(configDir);
|
|
1188
|
+
const configExists = await fs3__default.default.pathExists(configPath);
|
|
1153
1189
|
const allHookTypes = getDefaultHooks();
|
|
1154
1190
|
if (!configExists) {
|
|
1155
1191
|
const defaultConfig = {
|
|
1156
1192
|
...DEFAULT_CONFIG,
|
|
1157
1193
|
hooks: allHookTypes
|
|
1158
1194
|
};
|
|
1159
|
-
await
|
|
1195
|
+
await fs3__default.default.writeJson(configPath, defaultConfig, { spaces: 2 });
|
|
1160
1196
|
} else {
|
|
1161
|
-
const existingConfig = await
|
|
1197
|
+
const existingConfig = await fs3__default.default.readJson(configPath);
|
|
1162
1198
|
let needsUpdate = false;
|
|
1163
1199
|
if (!existingConfig.hooks) {
|
|
1164
1200
|
existingConfig.hooks = allHookTypes;
|
|
@@ -1176,7 +1212,7 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1176
1212
|
needsUpdate = true;
|
|
1177
1213
|
}
|
|
1178
1214
|
if (needsUpdate) {
|
|
1179
|
-
await
|
|
1215
|
+
await fs3__default.default.writeJson(configPath, existingConfig, { spaces: 2 });
|
|
1180
1216
|
}
|
|
1181
1217
|
}
|
|
1182
1218
|
} catch (error) {
|
|
@@ -1786,6 +1822,12 @@ ${helpText}
|
|
|
1786
1822
|
}
|
|
1787
1823
|
}
|
|
1788
1824
|
if (options.maxIterations !== void 0) {
|
|
1825
|
+
if (Number.isNaN(options.maxIterations)) {
|
|
1826
|
+
throw new ValidationError(
|
|
1827
|
+
"Max iterations must be a valid number",
|
|
1828
|
+
["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1789
1831
|
if (options.maxIterations !== -1 && options.maxIterations < 1) {
|
|
1790
1832
|
throw new ValidationError(
|
|
1791
1833
|
"Max iterations must be -1 (unlimited) or a positive number",
|
|
@@ -1794,8 +1836,8 @@ ${helpText}
|
|
|
1794
1836
|
}
|
|
1795
1837
|
}
|
|
1796
1838
|
if (options.cwd) {
|
|
1797
|
-
const
|
|
1798
|
-
if (!await
|
|
1839
|
+
const fs22 = await import('fs-extra');
|
|
1840
|
+
if (!await fs22.pathExists(options.cwd)) {
|
|
1799
1841
|
throw new ValidationError(
|
|
1800
1842
|
`Working directory does not exist: ${options.cwd}`,
|
|
1801
1843
|
["Verify the path exists", "Use absolute paths to avoid ambiguity"]
|
|
@@ -3879,8 +3921,8 @@ var init_engine = __esm({
|
|
|
3879
3921
|
if (!request.workingDirectory?.trim()) {
|
|
3880
3922
|
throw new Error("Working directory is required");
|
|
3881
3923
|
}
|
|
3882
|
-
if (request.maxIterations < -1 || request.maxIterations === 0) {
|
|
3883
|
-
throw new Error("Max iterations must be positive or -1 for unlimited");
|
|
3924
|
+
if (Number.isNaN(request.maxIterations) || request.maxIterations < -1 || request.maxIterations === 0) {
|
|
3925
|
+
throw new Error("Max iterations must be a positive number or -1 for unlimited");
|
|
3884
3926
|
}
|
|
3885
3927
|
}
|
|
3886
3928
|
/**
|
|
@@ -4890,7 +4932,7 @@ var init_config2 = __esm({
|
|
|
4890
4932
|
return cached;
|
|
4891
4933
|
}
|
|
4892
4934
|
try {
|
|
4893
|
-
const configContent = await
|
|
4935
|
+
const configContent = await fs3__default.default.readFile(configPath, "utf-8");
|
|
4894
4936
|
const config = JSON.parse(configContent);
|
|
4895
4937
|
this.validateConfig(config);
|
|
4896
4938
|
const resolvedConfig = this.resolveConfigPaths(config, path3__namespace.dirname(configPath));
|
|
@@ -4912,7 +4954,7 @@ var init_config2 = __esm({
|
|
|
4912
4954
|
const rootDir = path3__namespace.parse(currentDir).root;
|
|
4913
4955
|
while (currentDir !== rootDir) {
|
|
4914
4956
|
const configPath = path3__namespace.join(currentDir, ".juno_task", "mcp.json");
|
|
4915
|
-
if (await
|
|
4957
|
+
if (await fs3__default.default.pathExists(configPath)) {
|
|
4916
4958
|
return configPath;
|
|
4917
4959
|
}
|
|
4918
4960
|
currentDir = path3__namespace.dirname(currentDir);
|
|
@@ -5098,7 +5140,7 @@ var init_logger = __esm({
|
|
|
5098
5140
|
* Matches Python's generate_log_file function
|
|
5099
5141
|
*/
|
|
5100
5142
|
async initialize(subagent = "mcp") {
|
|
5101
|
-
await
|
|
5143
|
+
await fs3__default.default.ensureDir(this.logDirectory);
|
|
5102
5144
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T");
|
|
5103
5145
|
const dateStr = timestamp[0];
|
|
5104
5146
|
const timeStr = timestamp[1].split("-")[0].substring(0, 6);
|
|
@@ -5107,7 +5149,7 @@ var init_logger = __esm({
|
|
|
5107
5149
|
this.logFilePath = path3__namespace.default.join(this.logDirectory, logFileName);
|
|
5108
5150
|
const header = `# Juno-Task TypeScript Log - Started ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
5109
5151
|
`;
|
|
5110
|
-
await
|
|
5152
|
+
await fs3__default.default.writeFile(this.logFilePath, header);
|
|
5111
5153
|
}
|
|
5112
5154
|
/**
|
|
5113
5155
|
* Format log message matching Python version format
|
|
@@ -5125,7 +5167,7 @@ var init_logger = __esm({
|
|
|
5125
5167
|
if (!this.logFilePath) {
|
|
5126
5168
|
throw new Error("Logger not initialized. Call initialize() first.");
|
|
5127
5169
|
}
|
|
5128
|
-
await
|
|
5170
|
+
await fs3__default.default.appendFile(this.logFilePath, message);
|
|
5129
5171
|
}
|
|
5130
5172
|
/**
|
|
5131
5173
|
* Log message at specified level
|
|
@@ -7136,7 +7178,7 @@ var init_shell_backend = __esm({
|
|
|
7136
7178
|
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");
|
|
7137
7179
|
const logDir = path3__namespace.join(this.config.workingDirectory, ".juno_task", "logs");
|
|
7138
7180
|
try {
|
|
7139
|
-
await
|
|
7181
|
+
await fs3__default.default.ensureDir(logDir);
|
|
7140
7182
|
} catch (error) {
|
|
7141
7183
|
if (this.config?.debug) {
|
|
7142
7184
|
engineLogger.warn(`Failed to create log directory: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7161,7 +7203,7 @@ var init_shell_backend = __esm({
|
|
|
7161
7203
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7162
7204
|
const logEntry = `[${timestamp}] ${message}
|
|
7163
7205
|
`;
|
|
7164
|
-
await
|
|
7206
|
+
await fs3__default.default.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
7165
7207
|
} catch (error) {
|
|
7166
7208
|
if (this.config?.debug) {
|
|
7167
7209
|
engineLogger.warn(`Failed to write to log file: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7235,6 +7277,7 @@ var init_shell_backend = __esm({
|
|
|
7235
7277
|
return new Promise(async (resolve9, reject) => {
|
|
7236
7278
|
const startTime = Date.now();
|
|
7237
7279
|
const isPython = scriptPath.endsWith(".py");
|
|
7280
|
+
const isGemini = subagentType === "gemini";
|
|
7238
7281
|
const env2 = {
|
|
7239
7282
|
...process.env,
|
|
7240
7283
|
...this.config.environment,
|
|
@@ -7245,6 +7288,9 @@ var init_shell_backend = __esm({
|
|
|
7245
7288
|
JUNO_ITERATION: String(request.arguments?.iteration || 1),
|
|
7246
7289
|
JUNO_TOOL_ID: toolId
|
|
7247
7290
|
};
|
|
7291
|
+
if (isGemini) {
|
|
7292
|
+
env2.GEMINI_OUTPUT_FORMAT = env2.GEMINI_OUTPUT_FORMAT || "stream-json";
|
|
7293
|
+
}
|
|
7248
7294
|
let captureDir = null;
|
|
7249
7295
|
let capturePath = null;
|
|
7250
7296
|
if (subagentType === "claude") {
|
|
@@ -7266,6 +7312,9 @@ var init_shell_backend = __esm({
|
|
|
7266
7312
|
if (isPython && request.arguments?.model) {
|
|
7267
7313
|
args.push("-m", request.arguments.model);
|
|
7268
7314
|
}
|
|
7315
|
+
if (isPython && isGemini) {
|
|
7316
|
+
args.push("--output-format", env2.GEMINI_OUTPUT_FORMAT || "stream-json");
|
|
7317
|
+
}
|
|
7269
7318
|
if (isPython && request.arguments?.agents) {
|
|
7270
7319
|
args.push("--agents", request.arguments.agents);
|
|
7271
7320
|
}
|
|
@@ -12810,12 +12859,18 @@ async function mainCommandHandler(args, options, command) {
|
|
|
12810
12859
|
console.error(chalk15__default.default.red("\n\u274C Error: --allowed-tools and --append-allowed-tools are mutually exclusive. Use one or the other."));
|
|
12811
12860
|
process.exit(1);
|
|
12812
12861
|
}
|
|
12862
|
+
if (options.maxIterations !== void 0 && Number.isNaN(options.maxIterations)) {
|
|
12863
|
+
throw new ValidationError(
|
|
12864
|
+
"Max iterations must be a valid number",
|
|
12865
|
+
["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
|
|
12866
|
+
);
|
|
12867
|
+
}
|
|
12813
12868
|
const executionRequest = createExecutionRequest({
|
|
12814
12869
|
instruction,
|
|
12815
12870
|
subagent: options.subagent,
|
|
12816
12871
|
backend: selectedBackend,
|
|
12817
12872
|
workingDirectory: config.workingDirectory,
|
|
12818
|
-
maxIterations: options.maxIterations
|
|
12873
|
+
maxIterations: options.maxIterations ?? config.defaultMaxIterations,
|
|
12819
12874
|
model: options.model || config.defaultModel,
|
|
12820
12875
|
agents: options.agents,
|
|
12821
12876
|
tools: options.tools,
|
|
@@ -12980,7 +13035,7 @@ var init_main = __esm({
|
|
|
12980
13035
|
return await this.collectInteractivePrompt();
|
|
12981
13036
|
} else {
|
|
12982
13037
|
const defaultPromptPath = path3__namespace.join(process.cwd(), ".juno_task", "prompt.md");
|
|
12983
|
-
if (await
|
|
13038
|
+
if (await fs3__default.default.pathExists(defaultPromptPath)) {
|
|
12984
13039
|
console.error(chalk15__default.default.blue(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
|
|
12985
13040
|
return await this.loadPromptFromFile(defaultPromptPath);
|
|
12986
13041
|
} else {
|
|
@@ -13008,7 +13063,7 @@ var init_main = __esm({
|
|
|
13008
13063
|
}
|
|
13009
13064
|
try {
|
|
13010
13065
|
const resolvedPath = path3__namespace.resolve(prompt);
|
|
13011
|
-
return await
|
|
13066
|
+
return await fs3__default.default.pathExists(resolvedPath);
|
|
13012
13067
|
} catch {
|
|
13013
13068
|
return false;
|
|
13014
13069
|
}
|
|
@@ -13016,7 +13071,7 @@ var init_main = __esm({
|
|
|
13016
13071
|
async loadPromptFromFile(filePath) {
|
|
13017
13072
|
try {
|
|
13018
13073
|
const resolvedPath = path3__namespace.resolve(filePath);
|
|
13019
|
-
const content = await
|
|
13074
|
+
const content = await fs3__default.default.readFile(resolvedPath, "utf-8");
|
|
13020
13075
|
if (!content.trim()) {
|
|
13021
13076
|
throw new FileSystemError(
|
|
13022
13077
|
"Prompt file is empty",
|
|
@@ -13338,6 +13393,342 @@ var init_main = __esm({
|
|
|
13338
13393
|
}
|
|
13339
13394
|
});
|
|
13340
13395
|
|
|
13396
|
+
// src/utils/script-installer.ts
|
|
13397
|
+
var script_installer_exports = {};
|
|
13398
|
+
__export(script_installer_exports, {
|
|
13399
|
+
ScriptInstaller: () => ScriptInstaller
|
|
13400
|
+
});
|
|
13401
|
+
var ScriptInstaller;
|
|
13402
|
+
var init_script_installer = __esm({
|
|
13403
|
+
"src/utils/script-installer.ts"() {
|
|
13404
|
+
init_version();
|
|
13405
|
+
ScriptInstaller = class {
|
|
13406
|
+
/**
|
|
13407
|
+
* Scripts that should be auto-installed if missing
|
|
13408
|
+
* These are critical scripts that users expect to be available
|
|
13409
|
+
*/
|
|
13410
|
+
/**
|
|
13411
|
+
* Required scripts include both standalone scripts and their dependencies.
|
|
13412
|
+
* kanban.sh depends on install_requirements.sh for Python venv setup.
|
|
13413
|
+
* Slack integration scripts allow fetching tasks from Slack and responding.
|
|
13414
|
+
*/
|
|
13415
|
+
static REQUIRED_SCRIPTS = [
|
|
13416
|
+
"run_until_completion.sh",
|
|
13417
|
+
"kanban.sh",
|
|
13418
|
+
"install_requirements.sh",
|
|
13419
|
+
// Required by kanban.sh for Python venv creation
|
|
13420
|
+
// Slack integration scripts
|
|
13421
|
+
"slack_state.py",
|
|
13422
|
+
// State management for Slack integration
|
|
13423
|
+
"slack_fetch.py",
|
|
13424
|
+
// Core logic for fetching Slack messages
|
|
13425
|
+
"slack_fetch.sh",
|
|
13426
|
+
// Wrapper script for Slack fetch
|
|
13427
|
+
"slack_respond.py",
|
|
13428
|
+
// Core logic for sending responses to Slack
|
|
13429
|
+
"slack_respond.sh"
|
|
13430
|
+
// Wrapper script for Slack respond
|
|
13431
|
+
];
|
|
13432
|
+
/**
|
|
13433
|
+
* Get the templates scripts directory from the package
|
|
13434
|
+
*/
|
|
13435
|
+
static getPackageScriptsDir() {
|
|
13436
|
+
const __dirname2 = path3__namespace.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
|
|
13437
|
+
const candidates = [
|
|
13438
|
+
path3__namespace.join(__dirname2, "..", "..", "templates", "scripts"),
|
|
13439
|
+
// dist (production)
|
|
13440
|
+
path3__namespace.join(__dirname2, "..", "templates", "scripts")
|
|
13441
|
+
// src (development)
|
|
13442
|
+
];
|
|
13443
|
+
for (const scriptsPath of candidates) {
|
|
13444
|
+
if (fs3__default.default.existsSync(scriptsPath)) {
|
|
13445
|
+
return scriptsPath;
|
|
13446
|
+
}
|
|
13447
|
+
}
|
|
13448
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13449
|
+
console.error("[DEBUG] ScriptInstaller: Could not find templates/scripts directory");
|
|
13450
|
+
console.error("[DEBUG] Tried:", candidates);
|
|
13451
|
+
}
|
|
13452
|
+
return null;
|
|
13453
|
+
}
|
|
13454
|
+
/**
|
|
13455
|
+
* Check if a specific script exists in the project's .juno_task/scripts/ directory
|
|
13456
|
+
*/
|
|
13457
|
+
static async scriptExists(projectDir, scriptName) {
|
|
13458
|
+
const scriptPath = path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13459
|
+
return fs3__default.default.pathExists(scriptPath);
|
|
13460
|
+
}
|
|
13461
|
+
/**
|
|
13462
|
+
* Install a specific script to the project's .juno_task/scripts/ directory
|
|
13463
|
+
* @param projectDir - The project root directory
|
|
13464
|
+
* @param scriptName - Name of the script to install (e.g., 'run_until_completion.sh')
|
|
13465
|
+
* @param silent - If true, suppresses console output
|
|
13466
|
+
* @returns true if script was installed, false if installation was skipped or failed
|
|
13467
|
+
*/
|
|
13468
|
+
static async installScript(projectDir, scriptName, silent = false) {
|
|
13469
|
+
try {
|
|
13470
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13471
|
+
if (!packageScriptsDir) {
|
|
13472
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13473
|
+
console.error("[DEBUG] ScriptInstaller: Package scripts directory not found");
|
|
13474
|
+
}
|
|
13475
|
+
return false;
|
|
13476
|
+
}
|
|
13477
|
+
const sourcePath = path3__namespace.join(packageScriptsDir, scriptName);
|
|
13478
|
+
if (!await fs3__default.default.pathExists(sourcePath)) {
|
|
13479
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13480
|
+
console.error(`[DEBUG] ScriptInstaller: Source script not found: ${sourcePath}`);
|
|
13481
|
+
}
|
|
13482
|
+
return false;
|
|
13483
|
+
}
|
|
13484
|
+
const destDir = path3__namespace.join(projectDir, ".juno_task", "scripts");
|
|
13485
|
+
await fs3__default.default.ensureDir(destDir);
|
|
13486
|
+
const destPath = path3__namespace.join(destDir, scriptName);
|
|
13487
|
+
await fs3__default.default.copy(sourcePath, destPath, { overwrite: true });
|
|
13488
|
+
if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
|
|
13489
|
+
await fs3__default.default.chmod(destPath, 493);
|
|
13490
|
+
}
|
|
13491
|
+
if (!silent) {
|
|
13492
|
+
console.log(`\u2713 Installed script: ${scriptName} to .juno_task/scripts/`);
|
|
13493
|
+
}
|
|
13494
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13495
|
+
console.error(`[DEBUG] ScriptInstaller: Installed ${scriptName} to ${destPath}`);
|
|
13496
|
+
}
|
|
13497
|
+
return true;
|
|
13498
|
+
} catch (error) {
|
|
13499
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13500
|
+
console.error(`[DEBUG] ScriptInstaller: Failed to install ${scriptName}:`, error);
|
|
13501
|
+
}
|
|
13502
|
+
return false;
|
|
13503
|
+
}
|
|
13504
|
+
}
|
|
13505
|
+
/**
|
|
13506
|
+
* Check which required scripts are missing from the project
|
|
13507
|
+
* @param projectDir - The project root directory
|
|
13508
|
+
* @returns Array of missing script names
|
|
13509
|
+
*/
|
|
13510
|
+
static async getMissingScripts(projectDir) {
|
|
13511
|
+
const missing = [];
|
|
13512
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13513
|
+
if (!await this.scriptExists(projectDir, script)) {
|
|
13514
|
+
missing.push(script);
|
|
13515
|
+
}
|
|
13516
|
+
}
|
|
13517
|
+
return missing;
|
|
13518
|
+
}
|
|
13519
|
+
/**
|
|
13520
|
+
* Auto-install any missing required scripts
|
|
13521
|
+
* This should be called on CLI startup for initialized projects
|
|
13522
|
+
* @param projectDir - The project root directory
|
|
13523
|
+
* @param silent - If true, suppresses console output
|
|
13524
|
+
* @returns true if any scripts were installed
|
|
13525
|
+
*/
|
|
13526
|
+
static async autoInstallMissing(projectDir, silent = true) {
|
|
13527
|
+
try {
|
|
13528
|
+
const junoTaskDir = path3__namespace.join(projectDir, ".juno_task");
|
|
13529
|
+
if (!await fs3__default.default.pathExists(junoTaskDir)) {
|
|
13530
|
+
return false;
|
|
13531
|
+
}
|
|
13532
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13533
|
+
if (missing.length === 0) {
|
|
13534
|
+
return false;
|
|
13535
|
+
}
|
|
13536
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13537
|
+
console.error(`[DEBUG] ScriptInstaller: Missing scripts: ${missing.join(", ")}`);
|
|
13538
|
+
}
|
|
13539
|
+
let installedAny = false;
|
|
13540
|
+
for (const script of missing) {
|
|
13541
|
+
const installed = await this.installScript(projectDir, script, silent);
|
|
13542
|
+
if (installed) {
|
|
13543
|
+
installedAny = true;
|
|
13544
|
+
}
|
|
13545
|
+
}
|
|
13546
|
+
if (installedAny && !silent) {
|
|
13547
|
+
console.log(`\u2713 Auto-installed ${missing.length} missing script(s)`);
|
|
13548
|
+
}
|
|
13549
|
+
return installedAny;
|
|
13550
|
+
} catch (error) {
|
|
13551
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13552
|
+
console.error("[DEBUG] ScriptInstaller: autoInstallMissing error:", error);
|
|
13553
|
+
}
|
|
13554
|
+
return false;
|
|
13555
|
+
}
|
|
13556
|
+
}
|
|
13557
|
+
/**
|
|
13558
|
+
* Update a script if the package version is newer (by content comparison)
|
|
13559
|
+
* @param projectDir - The project root directory
|
|
13560
|
+
* @param scriptName - Name of the script to update
|
|
13561
|
+
* @param silent - If true, suppresses console output
|
|
13562
|
+
* @returns true if script was updated
|
|
13563
|
+
*/
|
|
13564
|
+
static async updateScriptIfNewer(projectDir, scriptName, silent = true) {
|
|
13565
|
+
try {
|
|
13566
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13567
|
+
if (!packageScriptsDir) {
|
|
13568
|
+
return false;
|
|
13569
|
+
}
|
|
13570
|
+
const sourcePath = path3__namespace.join(packageScriptsDir, scriptName);
|
|
13571
|
+
const destPath = path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13572
|
+
if (!await fs3__default.default.pathExists(destPath)) {
|
|
13573
|
+
return this.installScript(projectDir, scriptName, silent);
|
|
13574
|
+
}
|
|
13575
|
+
const [sourceContent, destContent] = await Promise.all([
|
|
13576
|
+
fs3__default.default.readFile(sourcePath, "utf-8"),
|
|
13577
|
+
fs3__default.default.readFile(destPath, "utf-8")
|
|
13578
|
+
]);
|
|
13579
|
+
if (sourceContent !== destContent) {
|
|
13580
|
+
await fs3__default.default.copy(sourcePath, destPath, { overwrite: true });
|
|
13581
|
+
if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
|
|
13582
|
+
await fs3__default.default.chmod(destPath, 493);
|
|
13583
|
+
}
|
|
13584
|
+
if (!silent) {
|
|
13585
|
+
console.log(`\u2713 Updated script: ${scriptName}`);
|
|
13586
|
+
}
|
|
13587
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13588
|
+
console.error(`[DEBUG] ScriptInstaller: Updated ${scriptName} (content changed)`);
|
|
13589
|
+
}
|
|
13590
|
+
return true;
|
|
13591
|
+
}
|
|
13592
|
+
return false;
|
|
13593
|
+
} catch (error) {
|
|
13594
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13595
|
+
console.error(`[DEBUG] ScriptInstaller: updateScriptIfNewer error for ${scriptName}:`, error);
|
|
13596
|
+
}
|
|
13597
|
+
return false;
|
|
13598
|
+
}
|
|
13599
|
+
}
|
|
13600
|
+
/**
|
|
13601
|
+
* Get the path to a script in the project's .juno_task/scripts/ directory
|
|
13602
|
+
*/
|
|
13603
|
+
static getScriptPath(projectDir, scriptName) {
|
|
13604
|
+
return path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13605
|
+
}
|
|
13606
|
+
/**
|
|
13607
|
+
* List all required scripts and their installation status
|
|
13608
|
+
*/
|
|
13609
|
+
static async listRequiredScripts(projectDir) {
|
|
13610
|
+
const results = [];
|
|
13611
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13612
|
+
results.push({
|
|
13613
|
+
name: script,
|
|
13614
|
+
installed: await this.scriptExists(projectDir, script)
|
|
13615
|
+
});
|
|
13616
|
+
}
|
|
13617
|
+
return results;
|
|
13618
|
+
}
|
|
13619
|
+
/**
|
|
13620
|
+
* Get scripts that need updates based on content comparison
|
|
13621
|
+
* @param projectDir - The project root directory
|
|
13622
|
+
* @returns Array of script names that have different content from package version
|
|
13623
|
+
*/
|
|
13624
|
+
static async getOutdatedScripts(projectDir) {
|
|
13625
|
+
const outdated = [];
|
|
13626
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13627
|
+
if (!packageScriptsDir) {
|
|
13628
|
+
return outdated;
|
|
13629
|
+
}
|
|
13630
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13631
|
+
const sourcePath = path3__namespace.join(packageScriptsDir, script);
|
|
13632
|
+
const destPath = path3__namespace.join(projectDir, ".juno_task", "scripts", script);
|
|
13633
|
+
if (!await fs3__default.default.pathExists(sourcePath)) {
|
|
13634
|
+
continue;
|
|
13635
|
+
}
|
|
13636
|
+
if (!await fs3__default.default.pathExists(destPath)) {
|
|
13637
|
+
continue;
|
|
13638
|
+
}
|
|
13639
|
+
try {
|
|
13640
|
+
const [sourceContent, destContent] = await Promise.all([
|
|
13641
|
+
fs3__default.default.readFile(sourcePath, "utf-8"),
|
|
13642
|
+
fs3__default.default.readFile(destPath, "utf-8")
|
|
13643
|
+
]);
|
|
13644
|
+
if (sourceContent !== destContent) {
|
|
13645
|
+
outdated.push(script);
|
|
13646
|
+
}
|
|
13647
|
+
} catch {
|
|
13648
|
+
outdated.push(script);
|
|
13649
|
+
}
|
|
13650
|
+
}
|
|
13651
|
+
return outdated;
|
|
13652
|
+
}
|
|
13653
|
+
/**
|
|
13654
|
+
* Check if any scripts need installation or update
|
|
13655
|
+
* @param projectDir - The project root directory
|
|
13656
|
+
* @returns true if any scripts need to be installed or updated
|
|
13657
|
+
*/
|
|
13658
|
+
static async needsUpdate(projectDir) {
|
|
13659
|
+
try {
|
|
13660
|
+
const junoTaskDir = path3__namespace.join(projectDir, ".juno_task");
|
|
13661
|
+
if (!await fs3__default.default.pathExists(junoTaskDir)) {
|
|
13662
|
+
return false;
|
|
13663
|
+
}
|
|
13664
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13665
|
+
if (missing.length > 0) {
|
|
13666
|
+
return true;
|
|
13667
|
+
}
|
|
13668
|
+
const outdated = await this.getOutdatedScripts(projectDir);
|
|
13669
|
+
return outdated.length > 0;
|
|
13670
|
+
} catch {
|
|
13671
|
+
return false;
|
|
13672
|
+
}
|
|
13673
|
+
}
|
|
13674
|
+
/**
|
|
13675
|
+
* Automatically update scripts - installs missing AND updates outdated scripts
|
|
13676
|
+
* Similar to ServiceInstaller.autoUpdate(), this ensures project scripts
|
|
13677
|
+
* are always in sync with the package version.
|
|
13678
|
+
*
|
|
13679
|
+
* This should be called on every CLI run to ensure scripts are up-to-date.
|
|
13680
|
+
* @param projectDir - The project root directory
|
|
13681
|
+
* @param silent - If true, suppresses console output
|
|
13682
|
+
* @returns true if any scripts were installed or updated
|
|
13683
|
+
*/
|
|
13684
|
+
static async autoUpdate(projectDir, silent = true) {
|
|
13685
|
+
try {
|
|
13686
|
+
const debug = process.env.JUNO_CODE_DEBUG === "1";
|
|
13687
|
+
const junoTaskDir = path3__namespace.join(projectDir, ".juno_task");
|
|
13688
|
+
if (!await fs3__default.default.pathExists(junoTaskDir)) {
|
|
13689
|
+
return false;
|
|
13690
|
+
}
|
|
13691
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13692
|
+
const outdated = await this.getOutdatedScripts(projectDir);
|
|
13693
|
+
if (debug) {
|
|
13694
|
+
if (missing.length > 0) {
|
|
13695
|
+
console.error(`[DEBUG] ScriptInstaller: Missing scripts: ${missing.join(", ")}`);
|
|
13696
|
+
}
|
|
13697
|
+
if (outdated.length > 0) {
|
|
13698
|
+
console.error(`[DEBUG] ScriptInstaller: Outdated scripts: ${outdated.join(", ")}`);
|
|
13699
|
+
}
|
|
13700
|
+
}
|
|
13701
|
+
if (missing.length === 0 && outdated.length === 0) {
|
|
13702
|
+
return false;
|
|
13703
|
+
}
|
|
13704
|
+
const scriptsToUpdate = [.../* @__PURE__ */ new Set([...missing, ...outdated])];
|
|
13705
|
+
let updatedAny = false;
|
|
13706
|
+
for (const script of scriptsToUpdate) {
|
|
13707
|
+
const installed = await this.installScript(projectDir, script, silent);
|
|
13708
|
+
if (installed) {
|
|
13709
|
+
updatedAny = true;
|
|
13710
|
+
}
|
|
13711
|
+
}
|
|
13712
|
+
if (updatedAny) {
|
|
13713
|
+
if (debug) {
|
|
13714
|
+
console.error(`[DEBUG] ScriptInstaller: Updated ${scriptsToUpdate.length} script(s)`);
|
|
13715
|
+
}
|
|
13716
|
+
if (!silent) {
|
|
13717
|
+
console.log(`\u2713 Updated ${scriptsToUpdate.length} script(s) in .juno_task/scripts/`);
|
|
13718
|
+
}
|
|
13719
|
+
}
|
|
13720
|
+
return updatedAny;
|
|
13721
|
+
} catch (error) {
|
|
13722
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13723
|
+
console.error("[DEBUG] ScriptInstaller: autoUpdate error:", error);
|
|
13724
|
+
}
|
|
13725
|
+
return false;
|
|
13726
|
+
}
|
|
13727
|
+
}
|
|
13728
|
+
};
|
|
13729
|
+
}
|
|
13730
|
+
});
|
|
13731
|
+
|
|
13341
13732
|
// src/utils/startup-validation.ts
|
|
13342
13733
|
var startup_validation_exports = {};
|
|
13343
13734
|
__export(startup_validation_exports, {
|
|
@@ -13428,7 +13819,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13428
13819
|
const warnings = [];
|
|
13429
13820
|
const filePath = path3__namespace.default.join(baseDir, configSchema.file);
|
|
13430
13821
|
try {
|
|
13431
|
-
const exists = await
|
|
13822
|
+
const exists = await fs3__default.default.pathExists(filePath);
|
|
13432
13823
|
if (!exists) {
|
|
13433
13824
|
if (configSchema.required) {
|
|
13434
13825
|
errors.push({
|
|
@@ -13451,7 +13842,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13451
13842
|
return { isValid: !configSchema.required, errors, warnings };
|
|
13452
13843
|
}
|
|
13453
13844
|
try {
|
|
13454
|
-
await
|
|
13845
|
+
await fs3__default.default.access(filePath, fs3__default.default.constants.R_OK);
|
|
13455
13846
|
} catch (accessError) {
|
|
13456
13847
|
errors.push({
|
|
13457
13848
|
file: configSchema.file,
|
|
@@ -13467,7 +13858,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13467
13858
|
}
|
|
13468
13859
|
let jsonData;
|
|
13469
13860
|
try {
|
|
13470
|
-
const fileContent = await
|
|
13861
|
+
const fileContent = await fs3__default.default.readFile(filePath, "utf8");
|
|
13471
13862
|
jsonData = JSON.parse(fileContent);
|
|
13472
13863
|
} catch (parseError) {
|
|
13473
13864
|
const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
|
|
@@ -13602,7 +13993,7 @@ function displayValidationResults(result) {
|
|
|
13602
13993
|
}
|
|
13603
13994
|
async function logValidationResults(result, baseDir = process.cwd()) {
|
|
13604
13995
|
const logDir = path3__namespace.default.join(baseDir, ".juno_task", "logs");
|
|
13605
|
-
await
|
|
13996
|
+
await fs3__default.default.ensureDir(logDir);
|
|
13606
13997
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
13607
13998
|
const logFile = path3__namespace.default.join(logDir, `startup-validation-${timestamp}.log`);
|
|
13608
13999
|
const logContent = [
|
|
@@ -13645,7 +14036,7 @@ async function logValidationResults(result, baseDir = process.cwd()) {
|
|
|
13645
14036
|
logContent.push(``);
|
|
13646
14037
|
}
|
|
13647
14038
|
}
|
|
13648
|
-
await
|
|
14039
|
+
await fs3__default.default.writeFile(logFile, logContent.join("\n"));
|
|
13649
14040
|
return logFile;
|
|
13650
14041
|
}
|
|
13651
14042
|
async function validateStartupConfigs(baseDir = process.cwd(), verbose = false) {
|
|
@@ -13979,7 +14370,7 @@ var TemplateEngine = class {
|
|
|
13979
14370
|
let overallError;
|
|
13980
14371
|
try {
|
|
13981
14372
|
if (!options.dryRun) {
|
|
13982
|
-
await
|
|
14373
|
+
await fs3__default.default.ensureDir(targetDirectory);
|
|
13983
14374
|
}
|
|
13984
14375
|
for (const template of templates) {
|
|
13985
14376
|
try {
|
|
@@ -15329,7 +15720,7 @@ This directory contains specification documents for your project.
|
|
|
15329
15720
|
const fileName = this.getTemplateFileName(template);
|
|
15330
15721
|
const targetPath = path3__namespace.join(targetDirectory, fileName);
|
|
15331
15722
|
try {
|
|
15332
|
-
const fileExists = await
|
|
15723
|
+
const fileExists = await fs3__default.default.pathExists(targetPath);
|
|
15333
15724
|
if (fileExists && !options.force && options.onConflict !== "overwrite") {
|
|
15334
15725
|
return {
|
|
15335
15726
|
path: targetPath,
|
|
@@ -15351,10 +15742,10 @@ This directory contains specification documents for your project.
|
|
|
15351
15742
|
}
|
|
15352
15743
|
if (options.createBackup && fileExists) {
|
|
15353
15744
|
const backupPath = `${targetPath}.backup.${Date.now()}`;
|
|
15354
|
-
await
|
|
15745
|
+
await fs3__default.default.copy(targetPath, backupPath);
|
|
15355
15746
|
}
|
|
15356
|
-
await
|
|
15357
|
-
await
|
|
15747
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(targetPath));
|
|
15748
|
+
await fs3__default.default.writeFile(targetPath, renderedContent, "utf8");
|
|
15358
15749
|
return {
|
|
15359
15750
|
path: targetPath,
|
|
15360
15751
|
content: renderedContent,
|
|
@@ -15618,7 +16009,7 @@ var SimpleInitTUI = class {
|
|
|
15618
16009
|
}
|
|
15619
16010
|
async confirmSave(targetDirectory) {
|
|
15620
16011
|
const junoTaskPath = path3__namespace.join(targetDirectory, ".juno_task");
|
|
15621
|
-
if (await
|
|
16012
|
+
if (await fs3__default.default.pathExists(junoTaskPath)) {
|
|
15622
16013
|
console.log(chalk15__default.default.yellow(" \u26A0\uFE0F .juno_task directory already exists"));
|
|
15623
16014
|
console.log(chalk15__default.default.gray(" Would you like to:"));
|
|
15624
16015
|
console.log(chalk15__default.default.gray(" 1) Override existing files"));
|
|
@@ -15663,16 +16054,16 @@ var SimpleProjectGenerator = class {
|
|
|
15663
16054
|
async generate() {
|
|
15664
16055
|
const { targetDirectory, variables, force } = this.context;
|
|
15665
16056
|
console.log(chalk15__default.default.blue("\u{1F4C1} Creating project directory..."));
|
|
15666
|
-
await
|
|
16057
|
+
await fs3__default.default.ensureDir(targetDirectory);
|
|
15667
16058
|
const junoTaskDir = path3__namespace.join(targetDirectory, ".juno_task");
|
|
15668
|
-
const junoTaskExists = await
|
|
16059
|
+
const junoTaskExists = await fs3__default.default.pathExists(junoTaskDir);
|
|
15669
16060
|
if (junoTaskExists && !force) {
|
|
15670
16061
|
throw new ValidationError(
|
|
15671
16062
|
"Project already initialized. Directory .juno_task already exists.",
|
|
15672
16063
|
["Use --force flag to overwrite existing files", "Choose a different directory"]
|
|
15673
16064
|
);
|
|
15674
16065
|
}
|
|
15675
|
-
await
|
|
16066
|
+
await fs3__default.default.ensureDir(junoTaskDir);
|
|
15676
16067
|
console.log(chalk15__default.default.blue("\u2699\uFE0F Creating project configuration..."));
|
|
15677
16068
|
await this.createConfigFile(junoTaskDir, targetDirectory);
|
|
15678
16069
|
console.log(chalk15__default.default.blue("\u{1F527} Setting up MCP configuration..."));
|
|
@@ -15706,21 +16097,21 @@ var SimpleProjectGenerator = class {
|
|
|
15706
16097
|
const promptContent = await templateEngine.render(promptTemplate, templateContext);
|
|
15707
16098
|
const initContent = await templateEngine.render(initTemplate, templateContext);
|
|
15708
16099
|
const implementContent = await templateEngine.render(implementTemplate, templateContext);
|
|
15709
|
-
await
|
|
15710
|
-
await
|
|
15711
|
-
await
|
|
16100
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "prompt.md"), promptContent);
|
|
16101
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "init.md"), initContent);
|
|
16102
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "implement.md"), implementContent);
|
|
15712
16103
|
const userFeedbackTemplate = templateEngine.getBuiltInTemplate("USER_FEEDBACK.md");
|
|
15713
16104
|
if (userFeedbackTemplate) {
|
|
15714
16105
|
const userFeedbackContent = await templateEngine.render(userFeedbackTemplate, templateContext);
|
|
15715
|
-
await
|
|
16106
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
|
|
15716
16107
|
}
|
|
15717
16108
|
const planTemplate = templateEngine.getBuiltInTemplate("plan.md");
|
|
15718
16109
|
if (planTemplate) {
|
|
15719
16110
|
const planContent = await templateEngine.render(planTemplate, templateContext);
|
|
15720
|
-
await
|
|
16111
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
|
|
15721
16112
|
}
|
|
15722
16113
|
const specsDir = path3__namespace.join(junoTaskDir, "specs");
|
|
15723
|
-
await
|
|
16114
|
+
await fs3__default.default.ensureDir(specsDir);
|
|
15724
16115
|
const specsReadmeContent = `# Project Specifications
|
|
15725
16116
|
|
|
15726
16117
|
This directory contains detailed specifications for the project components.
|
|
@@ -15737,7 +16128,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15737
16128
|
- Avoid conflicts with existing file names
|
|
15738
16129
|
- Use \`.md\` extension for all specification files
|
|
15739
16130
|
`;
|
|
15740
|
-
await
|
|
16131
|
+
await fs3__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
|
|
15741
16132
|
const requirementsContent = `# Requirements Specification
|
|
15742
16133
|
|
|
15743
16134
|
## Functional Requirements
|
|
@@ -15784,7 +16175,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15784
16175
|
- Code quality: Clean, maintainable codebase
|
|
15785
16176
|
- Documentation: Complete and accurate documentation
|
|
15786
16177
|
`;
|
|
15787
|
-
await
|
|
16178
|
+
await fs3__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
|
|
15788
16179
|
const architectureContent = `# Architecture Specification
|
|
15789
16180
|
|
|
15790
16181
|
## System Overview
|
|
@@ -15866,7 +16257,7 @@ This project uses AI-assisted development with juno-code to achieve: ${variables
|
|
|
15866
16257
|
- Performance monitoring
|
|
15867
16258
|
- Security best practices
|
|
15868
16259
|
`;
|
|
15869
|
-
await
|
|
16260
|
+
await fs3__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
|
|
15870
16261
|
const claudeContent = `# Claude Development Session Learnings
|
|
15871
16262
|
|
|
15872
16263
|
## Project Overview
|
|
@@ -15938,7 +16329,7 @@ This file will be updated as development progresses to track:
|
|
|
15938
16329
|
- Solutions to complex problems
|
|
15939
16330
|
- Performance improvements and optimizations
|
|
15940
16331
|
`;
|
|
15941
|
-
await
|
|
16332
|
+
await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
|
|
15942
16333
|
const agentsContent = `# AI Agent Selection and Performance
|
|
15943
16334
|
|
|
15944
16335
|
## Available Agents
|
|
@@ -16002,7 +16393,7 @@ Track agent performance for:
|
|
|
16002
16393
|
4. **Feedback Loop**: Provide feedback to improve agent performance
|
|
16003
16394
|
5. **Performance Monitoring**: Track and optimize agent usage
|
|
16004
16395
|
`;
|
|
16005
|
-
await
|
|
16396
|
+
await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
|
|
16006
16397
|
const readmeContent = `# ${variables.PROJECT_NAME}
|
|
16007
16398
|
|
|
16008
16399
|
${variables.DESCRIPTION}
|
|
@@ -16099,7 +16490,7 @@ ${variables.GIT_URL}` : ""}
|
|
|
16099
16490
|
Created with juno-code on ${variables.CURRENT_DATE}
|
|
16100
16491
|
${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
16101
16492
|
`;
|
|
16102
|
-
await
|
|
16493
|
+
await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
|
|
16103
16494
|
console.log(chalk15__default.default.blue("\u{1F4E6} Installing utility scripts..."));
|
|
16104
16495
|
await this.copyScriptsFromTemplates(junoTaskDir);
|
|
16105
16496
|
console.log(chalk15__default.default.blue("\u{1F40D} Installing Python requirements..."));
|
|
@@ -16151,7 +16542,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16151
16542
|
hooks: getDefaultHooks()
|
|
16152
16543
|
};
|
|
16153
16544
|
const configPath = path3__namespace.join(junoTaskDir, "config.json");
|
|
16154
|
-
await
|
|
16545
|
+
await fs3__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
|
|
16155
16546
|
console.log(chalk15__default.default.green(` \u2713 Created .juno_task/config.json with ${this.context.subagent} as default subagent`));
|
|
16156
16547
|
}
|
|
16157
16548
|
async createMcpFile(junoTaskDir, targetDirectory) {
|
|
@@ -16205,7 +16596,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16205
16596
|
}
|
|
16206
16597
|
};
|
|
16207
16598
|
const mcpPath = path3__namespace.join(junoTaskDir, "mcp.json");
|
|
16208
|
-
await
|
|
16599
|
+
await fs3__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
|
|
16209
16600
|
console.log(chalk15__default.default.green(` \u2713 Created .juno_task/mcp.json with roundtable-ai server configuration`));
|
|
16210
16601
|
}
|
|
16211
16602
|
getDefaultModelForSubagent(subagent) {
|
|
@@ -16224,7 +16615,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16224
16615
|
async copyScriptsFromTemplates(junoTaskDir) {
|
|
16225
16616
|
try {
|
|
16226
16617
|
const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
|
|
16227
|
-
await
|
|
16618
|
+
await fs3__default.default.ensureDir(scriptsDir);
|
|
16228
16619
|
const __filename2 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
16229
16620
|
const __dirname2 = path3__namespace.dirname(__filename2);
|
|
16230
16621
|
let templatesScriptsDir;
|
|
@@ -16235,11 +16626,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16235
16626
|
} else {
|
|
16236
16627
|
templatesScriptsDir = path3__namespace.join(__dirname2, "../../templates/scripts");
|
|
16237
16628
|
}
|
|
16238
|
-
if (!await
|
|
16629
|
+
if (!await fs3__default.default.pathExists(templatesScriptsDir)) {
|
|
16239
16630
|
console.log(chalk15__default.default.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
|
|
16240
16631
|
return;
|
|
16241
16632
|
}
|
|
16242
|
-
const scriptFiles = await
|
|
16633
|
+
const scriptFiles = await fs3__default.default.readdir(templatesScriptsDir);
|
|
16243
16634
|
if (scriptFiles.length === 0) {
|
|
16244
16635
|
console.log(chalk15__default.default.gray(" \u2139\uFE0F No template scripts found to install"));
|
|
16245
16636
|
return;
|
|
@@ -16248,11 +16639,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16248
16639
|
for (const scriptFile of scriptFiles) {
|
|
16249
16640
|
const sourcePath = path3__namespace.join(templatesScriptsDir, scriptFile);
|
|
16250
16641
|
const destPath = path3__namespace.join(scriptsDir, scriptFile);
|
|
16251
|
-
const stats = await
|
|
16642
|
+
const stats = await fs3__default.default.stat(sourcePath);
|
|
16252
16643
|
if (stats.isFile()) {
|
|
16253
|
-
await
|
|
16644
|
+
await fs3__default.default.copy(sourcePath, destPath);
|
|
16254
16645
|
if (scriptFile.endsWith(".sh")) {
|
|
16255
|
-
await
|
|
16646
|
+
await fs3__default.default.chmod(destPath, 493);
|
|
16256
16647
|
}
|
|
16257
16648
|
copiedCount++;
|
|
16258
16649
|
console.log(chalk15__default.default.green(` \u2713 Installed script: ${scriptFile}`));
|
|
@@ -16275,7 +16666,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16275
16666
|
try {
|
|
16276
16667
|
const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
|
|
16277
16668
|
const installScript = path3__namespace.join(scriptsDir, "install_requirements.sh");
|
|
16278
|
-
if (!await
|
|
16669
|
+
if (!await fs3__default.default.pathExists(installScript)) {
|
|
16279
16670
|
console.log(chalk15__default.default.yellow(" \u26A0\uFE0F install_requirements.sh not found, skipping Python dependencies installation"));
|
|
16280
16671
|
console.log(chalk15__default.default.gray(" You can install dependencies manually: juno-kanban, roundtable-ai"));
|
|
16281
16672
|
return;
|
|
@@ -16572,20 +16963,20 @@ init_types();
|
|
|
16572
16963
|
async function loadInitPrompt(directory) {
|
|
16573
16964
|
const junoTaskDir = path3__namespace.join(directory, ".juno_task");
|
|
16574
16965
|
const initFile = path3__namespace.join(junoTaskDir, "init.md");
|
|
16575
|
-
if (!await
|
|
16966
|
+
if (!await fs3__default.default.pathExists(junoTaskDir)) {
|
|
16576
16967
|
throw new FileSystemError(
|
|
16577
16968
|
'No .juno_task directory found. Run "juno-code init" first.',
|
|
16578
16969
|
junoTaskDir
|
|
16579
16970
|
);
|
|
16580
16971
|
}
|
|
16581
|
-
if (!await
|
|
16972
|
+
if (!await fs3__default.default.pathExists(initFile)) {
|
|
16582
16973
|
throw new FileSystemError(
|
|
16583
16974
|
"No init.md file found in .juno_task directory",
|
|
16584
16975
|
initFile
|
|
16585
16976
|
);
|
|
16586
16977
|
}
|
|
16587
16978
|
try {
|
|
16588
|
-
const content = await
|
|
16979
|
+
const content = await fs3__default.default.readFile(initFile, "utf-8");
|
|
16589
16980
|
if (!content.trim()) {
|
|
16590
16981
|
throw new FileSystemError(
|
|
16591
16982
|
"init.md file is empty. Please add task instructions.",
|
|
@@ -17617,8 +18008,8 @@ Focus on ${request.intelligence === "basic" ? "basic functionality" : request.in
|
|
|
17617
18008
|
for (const scenario of scenarios) {
|
|
17618
18009
|
const testContent = await this.generateTestContent(request, scenario, template);
|
|
17619
18010
|
const testFilePath = this.resolveTestFilePath(request, scenario);
|
|
17620
|
-
await
|
|
17621
|
-
await
|
|
18011
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(testFilePath));
|
|
18012
|
+
await fs3__default.default.writeFile(testFilePath, testContent);
|
|
17622
18013
|
testFiles.push(testFilePath);
|
|
17623
18014
|
}
|
|
17624
18015
|
return testFiles;
|
|
@@ -17870,8 +18261,8 @@ var TestExecutionEngine = class {
|
|
|
17870
18261
|
async collectCoverage(request) {
|
|
17871
18262
|
const coverageFile = path3__namespace.join(request.workingDirectory, "coverage", "coverage-summary.json");
|
|
17872
18263
|
try {
|
|
17873
|
-
if (await
|
|
17874
|
-
const coverageData = await
|
|
18264
|
+
if (await fs3__default.default.pathExists(coverageFile)) {
|
|
18265
|
+
const coverageData = await fs3__default.default.readJson(coverageFile);
|
|
17875
18266
|
return {
|
|
17876
18267
|
lines: coverageData.total?.lines?.pct || 0,
|
|
17877
18268
|
functions: coverageData.total?.functions?.pct || 0,
|
|
@@ -18054,8 +18445,8 @@ var TestReportEngine = class {
|
|
|
18054
18445
|
suggestions: analysis.suggestions,
|
|
18055
18446
|
recommendations: analysis.recommendations
|
|
18056
18447
|
};
|
|
18057
|
-
await
|
|
18058
|
-
await
|
|
18448
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
|
|
18449
|
+
await fs3__default.default.writeJson(outputPath, report, { spaces: 2 });
|
|
18059
18450
|
return outputPath;
|
|
18060
18451
|
}
|
|
18061
18452
|
async generateHTMLReport(analysis, outputPath, includeVisualizations) {
|
|
@@ -18118,8 +18509,8 @@ var TestReportEngine = class {
|
|
|
18118
18509
|
</body>
|
|
18119
18510
|
</html>
|
|
18120
18511
|
`.trim();
|
|
18121
|
-
await
|
|
18122
|
-
await
|
|
18512
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
|
|
18513
|
+
await fs3__default.default.writeFile(outputPath, html);
|
|
18123
18514
|
return outputPath;
|
|
18124
18515
|
}
|
|
18125
18516
|
generateCharts(analysis) {
|
|
@@ -18176,8 +18567,8 @@ ${analysis.suggestions.map((suggestion) => `- ${suggestion}`).join("\n")}
|
|
|
18176
18567
|
|
|
18177
18568
|
${analysis.recommendations.map((rec) => `- ${rec}`).join("\n")}
|
|
18178
18569
|
`.trim();
|
|
18179
|
-
await
|
|
18180
|
-
await
|
|
18570
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
|
|
18571
|
+
await fs3__default.default.writeFile(outputPath, markdown);
|
|
18181
18572
|
return outputPath;
|
|
18182
18573
|
}
|
|
18183
18574
|
async displayConsoleReport(analysis) {
|
|
@@ -18517,16 +18908,16 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18517
18908
|
preserveDays = 30,
|
|
18518
18909
|
preservePatterns = []
|
|
18519
18910
|
} = options;
|
|
18520
|
-
const originalContent = await
|
|
18911
|
+
const originalContent = await fs3__default.default.readFile(filePath, "utf-8");
|
|
18521
18912
|
const originalSize = originalContent.length;
|
|
18522
18913
|
let backupPath = "";
|
|
18523
18914
|
if (createBackup && !dryRun) {
|
|
18524
18915
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18525
18916
|
const ext = path3__namespace.extname(filePath);
|
|
18526
18917
|
const basename11 = path3__namespace.basename(filePath, ext);
|
|
18527
|
-
const
|
|
18528
|
-
backupPath = path3__namespace.join(
|
|
18529
|
-
await
|
|
18918
|
+
const dirname13 = path3__namespace.dirname(filePath);
|
|
18919
|
+
backupPath = path3__namespace.join(dirname13, `${basename11}.backup.${timestamp}${ext}`);
|
|
18920
|
+
await fs3__default.default.writeFile(backupPath, originalContent, "utf-8");
|
|
18530
18921
|
}
|
|
18531
18922
|
const compactionAnalysis = analyzeMarkdownStructure(originalContent);
|
|
18532
18923
|
const compactedContent = compactMarkdownContent(
|
|
@@ -18541,7 +18932,7 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18541
18932
|
const compactedSize = finalContent.length;
|
|
18542
18933
|
const reductionPercentage = Math.round((originalSize - compactedSize) / originalSize * 100);
|
|
18543
18934
|
if (!dryRun) {
|
|
18544
|
-
await
|
|
18935
|
+
await fs3__default.default.writeFile(filePath, finalContent, "utf-8");
|
|
18545
18936
|
}
|
|
18546
18937
|
return {
|
|
18547
18938
|
originalSize,
|
|
@@ -18671,7 +19062,7 @@ function formatFileSize(bytes) {
|
|
|
18671
19062
|
}
|
|
18672
19063
|
async function shouldCompactFile(filePath, sizeThresholdKB = 50, ageThresholdDays = 30) {
|
|
18673
19064
|
try {
|
|
18674
|
-
const stats = await
|
|
19065
|
+
const stats = await fs3__default.default.stat(filePath);
|
|
18675
19066
|
const sizeKB = stats.size / 1024;
|
|
18676
19067
|
if (sizeKB > sizeThresholdKB) {
|
|
18677
19068
|
return true;
|
|
@@ -18693,19 +19084,19 @@ async function archiveResolvedIssues(options) {
|
|
|
18693
19084
|
feedbackFile,
|
|
18694
19085
|
archiveDir = path3__namespace.join(path3__namespace.dirname(feedbackFile), "archives"),
|
|
18695
19086
|
openIssuesThreshold = 10} = options;
|
|
18696
|
-
if (!await
|
|
19087
|
+
if (!await fs3__default.default.pathExists(feedbackFile)) {
|
|
18697
19088
|
throw new Error(`Feedback file does not exist: ${feedbackFile}`);
|
|
18698
19089
|
}
|
|
18699
|
-
const content = await
|
|
19090
|
+
const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
|
|
18700
19091
|
const parsed = parseUserFeedback(content);
|
|
18701
19092
|
const warningsGenerated = [];
|
|
18702
19093
|
if (parsed.openIssues.length > openIssuesThreshold) {
|
|
18703
19094
|
const warning = `Found ${parsed.openIssues.length} open issues (threshold: ${openIssuesThreshold}). Consider reviewing and prioritizing.`;
|
|
18704
19095
|
warningsGenerated.push(warning);
|
|
18705
19096
|
const logFile = path3__namespace.join(path3__namespace.dirname(feedbackFile), "logs", "feedback-warnings.log");
|
|
18706
|
-
await
|
|
19097
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(logFile));
|
|
18707
19098
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
18708
|
-
await
|
|
19099
|
+
await fs3__default.default.appendFile(logFile, `[${timestamp}] ${warning}
|
|
18709
19100
|
`);
|
|
18710
19101
|
}
|
|
18711
19102
|
if (parsed.resolvedIssues.length === 0) {
|
|
@@ -18722,10 +19113,10 @@ async function archiveResolvedIssues(options) {
|
|
|
18722
19113
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
18723
19114
|
const archiveFile = path3__namespace.join(archiveDir, `USER_FEEDBACK_archive_${currentYear}.md`);
|
|
18724
19115
|
{
|
|
18725
|
-
await
|
|
19116
|
+
await fs3__default.default.ensureDir(archiveDir);
|
|
18726
19117
|
await appendToArchive(archiveFile, parsed.resolvedIssues);
|
|
18727
19118
|
const compactedContent = generateCompactedFeedback(parsed.openIssues, parsed.metadata);
|
|
18728
|
-
await
|
|
19119
|
+
await fs3__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
|
|
18729
19120
|
}
|
|
18730
19121
|
{
|
|
18731
19122
|
console.log(chalk15__default.default.green(`\u2705 Archived ${parsed.resolvedIssues.length} resolved issues`));
|
|
@@ -18772,8 +19163,8 @@ function parseUserFeedback(content) {
|
|
|
18772
19163
|
async function appendToArchive(archiveFile, resolvedIssues) {
|
|
18773
19164
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
18774
19165
|
let archiveContent = "";
|
|
18775
|
-
if (await
|
|
18776
|
-
archiveContent = await
|
|
19166
|
+
if (await fs3__default.default.pathExists(archiveFile)) {
|
|
19167
|
+
archiveContent = await fs3__default.default.readFile(archiveFile, "utf-8");
|
|
18777
19168
|
} else {
|
|
18778
19169
|
const year = path3__namespace.basename(archiveFile).match(/(\d{4})/)?.[1] || (/* @__PURE__ */ new Date()).getFullYear();
|
|
18779
19170
|
archiveContent = `# User Feedback Archive ${year}
|
|
@@ -18807,7 +19198,7 @@ ${resolvedIssue}
|
|
|
18807
19198
|
`- Last updated: ${timestamp}`
|
|
18808
19199
|
);
|
|
18809
19200
|
}
|
|
18810
|
-
await
|
|
19201
|
+
await fs3__default.default.writeFile(archiveFile, archiveContent, "utf-8");
|
|
18811
19202
|
}
|
|
18812
19203
|
function generateCompactedFeedback(openIssues, metadata) {
|
|
18813
19204
|
let content = metadata.trim() + "\n";
|
|
@@ -18832,15 +19223,15 @@ async function shouldArchive(feedbackFile, options = {}) {
|
|
|
18832
19223
|
// 50KB
|
|
18833
19224
|
lineCountThreshold = 500
|
|
18834
19225
|
} = options;
|
|
18835
|
-
if (!await
|
|
19226
|
+
if (!await fs3__default.default.pathExists(feedbackFile)) {
|
|
18836
19227
|
return {
|
|
18837
19228
|
shouldArchive: false,
|
|
18838
19229
|
reasons: [],
|
|
18839
19230
|
stats: { openIssuesCount: 0, resolvedIssuesCount: 0, fileSizeBytes: 0, lineCount: 0 }
|
|
18840
19231
|
};
|
|
18841
19232
|
}
|
|
18842
|
-
const content = await
|
|
18843
|
-
const stats = await
|
|
19233
|
+
const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
|
|
19234
|
+
const stats = await fs3__default.default.stat(feedbackFile);
|
|
18844
19235
|
const parsed = parseUserFeedback(content);
|
|
18845
19236
|
const lineCount = content.split("\n").length;
|
|
18846
19237
|
const reasons = [];
|
|
@@ -18914,16 +19305,16 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18914
19305
|
this.feedbackFile = feedbackFile;
|
|
18915
19306
|
}
|
|
18916
19307
|
async ensureExists() {
|
|
18917
|
-
if (!await
|
|
19308
|
+
if (!await fs3__default.default.pathExists(this.feedbackFile)) {
|
|
18918
19309
|
await this.createInitialFile();
|
|
18919
19310
|
}
|
|
18920
19311
|
}
|
|
18921
19312
|
async addFeedback(issue, testCriteria) {
|
|
18922
19313
|
await this.ensureExists();
|
|
18923
19314
|
try {
|
|
18924
|
-
const content = await
|
|
19315
|
+
const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
|
|
18925
19316
|
const updatedContent = this.addIssueToContent(content, issue, testCriteria);
|
|
18926
|
-
await
|
|
19317
|
+
await fs3__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
|
|
18927
19318
|
} catch (error) {
|
|
18928
19319
|
throw new ValidationError(
|
|
18929
19320
|
`Failed to save feedback: ${error}`,
|
|
@@ -18936,12 +19327,12 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18936
19327
|
*/
|
|
18937
19328
|
async repairMalformedFile() {
|
|
18938
19329
|
try {
|
|
18939
|
-
const content = await
|
|
19330
|
+
const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
|
|
18940
19331
|
const hasOpenIssues = content.includes("<OPEN_ISSUES>");
|
|
18941
19332
|
const hasClosingTag = content.includes("</OPEN_ISSUES>");
|
|
18942
19333
|
if (!hasOpenIssues || !hasClosingTag) {
|
|
18943
19334
|
const backupPath = this.feedbackFile + ".backup." + Date.now();
|
|
18944
|
-
await
|
|
19335
|
+
await fs3__default.default.writeFile(backupPath, content, "utf-8");
|
|
18945
19336
|
const existingIssues = this.extractIssuesFromMalformedContent(content);
|
|
18946
19337
|
await this.createInitialFile(existingIssues);
|
|
18947
19338
|
}
|
|
@@ -18973,8 +19364,8 @@ List any features you'd like to see added or bugs you've encountered.
|
|
|
18973
19364
|
|
|
18974
19365
|
<!-- Resolved issues will be moved here -->
|
|
18975
19366
|
`;
|
|
18976
|
-
await
|
|
18977
|
-
await
|
|
19367
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(this.feedbackFile));
|
|
19368
|
+
await fs3__default.default.writeFile(this.feedbackFile, initialContent, "utf-8");
|
|
18978
19369
|
}
|
|
18979
19370
|
addIssueToContent(content, issue, testCriteria) {
|
|
18980
19371
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -19090,17 +19481,17 @@ async function handleCompactCommand(subArgs, options) {
|
|
|
19090
19481
|
if (subArgs.length > 0) {
|
|
19091
19482
|
for (const filePath of subArgs) {
|
|
19092
19483
|
const resolvedPath = path3__namespace.resolve(filePath);
|
|
19093
|
-
if (await
|
|
19484
|
+
if (await fs3__default.default.pathExists(resolvedPath)) {
|
|
19094
19485
|
filesToCompact.push(resolvedPath);
|
|
19095
19486
|
} else {
|
|
19096
19487
|
console.warn(chalk15__default.default.yellow(`\u26A0\uFE0F File not found: ${filePath}`));
|
|
19097
19488
|
}
|
|
19098
19489
|
}
|
|
19099
19490
|
} else {
|
|
19100
|
-
if (await
|
|
19491
|
+
if (await fs3__default.default.pathExists(defaultClaudeFile)) {
|
|
19101
19492
|
filesToCompact.push(defaultClaudeFile);
|
|
19102
19493
|
}
|
|
19103
|
-
if (await
|
|
19494
|
+
if (await fs3__default.default.pathExists(defaultAgentsFile)) {
|
|
19104
19495
|
filesToCompact.push(defaultAgentsFile);
|
|
19105
19496
|
}
|
|
19106
19497
|
}
|
|
@@ -20034,11 +20425,11 @@ var GitManager = class {
|
|
|
20034
20425
|
*/
|
|
20035
20426
|
async updateJunoTaskConfig(gitUrl) {
|
|
20036
20427
|
const configPath = path3__namespace.join(this.workingDirectory, ".juno_task", "init.md");
|
|
20037
|
-
if (!await
|
|
20428
|
+
if (!await fs3__default.default.pathExists(configPath)) {
|
|
20038
20429
|
return;
|
|
20039
20430
|
}
|
|
20040
20431
|
try {
|
|
20041
|
-
let content = await
|
|
20432
|
+
let content = await fs3__default.default.readFile(configPath, "utf-8");
|
|
20042
20433
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
20043
20434
|
if (frontmatterMatch) {
|
|
20044
20435
|
let frontmatter = frontmatterMatch[1];
|
|
@@ -20059,7 +20450,7 @@ GIT_URL: ${gitUrl}
|
|
|
20059
20450
|
`;
|
|
20060
20451
|
content = frontmatter + content;
|
|
20061
20452
|
}
|
|
20062
|
-
await
|
|
20453
|
+
await fs3__default.default.writeFile(configPath, content, "utf-8");
|
|
20063
20454
|
} catch (error) {
|
|
20064
20455
|
console.warn(`Warning: Failed to update juno-code configuration: ${error}`);
|
|
20065
20456
|
}
|
|
@@ -20991,7 +21382,7 @@ var LogViewer = ({
|
|
|
20991
21382
|
init_types();
|
|
20992
21383
|
async function exportLogs(logger2, filepath, options) {
|
|
20993
21384
|
try {
|
|
20994
|
-
const
|
|
21385
|
+
const fs22 = await import('fs-extra');
|
|
20995
21386
|
let entries = logger2.getRecentEntries(options.tail || 1e3);
|
|
20996
21387
|
if (options.level) {
|
|
20997
21388
|
const level = LogLevel[options.level.toUpperCase()];
|
|
@@ -21021,7 +21412,7 @@ async function exportLogs(logger2, filepath, options) {
|
|
|
21021
21412
|
},
|
|
21022
21413
|
entries
|
|
21023
21414
|
};
|
|
21024
|
-
await
|
|
21415
|
+
await fs22.writeFile(filepath, JSON.stringify(exportData, null, 2));
|
|
21025
21416
|
console.log(chalk15__default.default.green(`\u2705 Exported ${entries.length} log entries to: ${filepath}`));
|
|
21026
21417
|
} catch (error) {
|
|
21027
21418
|
console.error(chalk15__default.default.red(`\u274C Failed to export logs: ${error}`));
|
|
@@ -22565,7 +22956,7 @@ function createServicesCommand() {
|
|
|
22565
22956
|
const servicesCmd = new commander.Command("services").description("Manage juno-code service scripts").addHelpText("after", `
|
|
22566
22957
|
Examples:
|
|
22567
22958
|
$ juno-code services install Install service scripts to ~/.juno_code/services/
|
|
22568
|
-
$ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py)
|
|
22959
|
+
$ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py/gemini.py)
|
|
22569
22960
|
$ juno-code services list List installed service scripts
|
|
22570
22961
|
$ juno-code services status Check installation status
|
|
22571
22962
|
$ juno-code services uninstall Remove all service scripts
|
|
@@ -22822,10 +23213,10 @@ autoload -U compinit && compinit`;
|
|
|
22822
23213
|
*/
|
|
22823
23214
|
async isSourceCommandPresent(configPath, sourceCommand) {
|
|
22824
23215
|
try {
|
|
22825
|
-
if (!await
|
|
23216
|
+
if (!await fs3__default.default.pathExists(configPath)) {
|
|
22826
23217
|
return false;
|
|
22827
23218
|
}
|
|
22828
|
-
const content = await
|
|
23219
|
+
const content = await fs3__default.default.readFile(configPath, "utf-8");
|
|
22829
23220
|
return content.includes("juno-code completion");
|
|
22830
23221
|
} catch {
|
|
22831
23222
|
return false;
|
|
@@ -22847,15 +23238,15 @@ autoload -U compinit && compinit`;
|
|
|
22847
23238
|
continue;
|
|
22848
23239
|
}
|
|
22849
23240
|
try {
|
|
22850
|
-
const completionExists = await
|
|
22851
|
-
const configExists = await
|
|
23241
|
+
const completionExists = await fs3__default.default.pathExists(shell.completionPath);
|
|
23242
|
+
const configExists = await fs3__default.default.pathExists(shell.configPath);
|
|
22852
23243
|
const isSourced = configExists && await this.isSourceCommandPresent(
|
|
22853
23244
|
shell.configPath,
|
|
22854
23245
|
this.getSourceCommand(shell.name, shell.completionPath)
|
|
22855
23246
|
);
|
|
22856
23247
|
let lastInstalled;
|
|
22857
23248
|
if (completionExists) {
|
|
22858
|
-
const stats = await
|
|
23249
|
+
const stats = await fs3__default.default.stat(shell.completionPath);
|
|
22859
23250
|
lastInstalled = stats.mtime;
|
|
22860
23251
|
}
|
|
22861
23252
|
statuses.push({
|
|
@@ -22881,7 +23272,7 @@ autoload -U compinit && compinit`;
|
|
|
22881
23272
|
async ensureCompletionDirectory(shell) {
|
|
22882
23273
|
const completionPath = this.getCompletionPath(shell);
|
|
22883
23274
|
const completionDir = path3__namespace.dirname(completionPath);
|
|
22884
|
-
await
|
|
23275
|
+
await fs3__default.default.ensureDir(completionDir);
|
|
22885
23276
|
}
|
|
22886
23277
|
/**
|
|
22887
23278
|
* Ensure directory exists for shell configuration
|
|
@@ -22889,7 +23280,7 @@ autoload -U compinit && compinit`;
|
|
|
22889
23280
|
async ensureConfigDirectory(shell) {
|
|
22890
23281
|
const configPath = this.getConfigPath(shell);
|
|
22891
23282
|
const configDir = path3__namespace.dirname(configPath);
|
|
22892
|
-
await
|
|
23283
|
+
await fs3__default.default.ensureDir(configDir);
|
|
22893
23284
|
}
|
|
22894
23285
|
/**
|
|
22895
23286
|
* Get shell version information
|
|
@@ -22913,15 +23304,15 @@ autoload -U compinit && compinit`;
|
|
|
22913
23304
|
try {
|
|
22914
23305
|
const configPath = this.getConfigPath(shell);
|
|
22915
23306
|
const configDir = path3__namespace.dirname(configPath);
|
|
22916
|
-
await
|
|
23307
|
+
await fs3__default.default.access(configDir, fs3__default.default.constants.W_OK);
|
|
22917
23308
|
} catch {
|
|
22918
23309
|
issues.push(`Cannot write to ${shell} configuration directory`);
|
|
22919
23310
|
}
|
|
22920
23311
|
try {
|
|
22921
23312
|
const completionPath = this.getCompletionPath(shell);
|
|
22922
23313
|
const completionDir = path3__namespace.dirname(completionPath);
|
|
22923
|
-
await
|
|
22924
|
-
await
|
|
23314
|
+
await fs3__default.default.ensureDir(completionDir);
|
|
23315
|
+
await fs3__default.default.access(completionDir, fs3__default.default.constants.W_OK);
|
|
22925
23316
|
} catch {
|
|
22926
23317
|
issues.push(`Cannot write to ${shell} completion directory`);
|
|
22927
23318
|
}
|
|
@@ -22992,10 +23383,10 @@ var ContextAwareCompletion = class {
|
|
|
22992
23383
|
async getSessionIds() {
|
|
22993
23384
|
try {
|
|
22994
23385
|
const sessionDir = path3__namespace.join(process.cwd(), ".juno_task", "sessions");
|
|
22995
|
-
if (!await
|
|
23386
|
+
if (!await fs3__default.default.pathExists(sessionDir)) {
|
|
22996
23387
|
return [];
|
|
22997
23388
|
}
|
|
22998
|
-
const sessions = await
|
|
23389
|
+
const sessions = await fs3__default.default.readdir(sessionDir);
|
|
22999
23390
|
return sessions.filter((name) => name.match(/^session_\d+$/)).map((name) => name.replace("session_", "")).sort((a, b) => parseInt(b) - parseInt(a));
|
|
23000
23391
|
} catch {
|
|
23001
23392
|
return [];
|
|
@@ -23009,8 +23400,8 @@ var ContextAwareCompletion = class {
|
|
|
23009
23400
|
const builtinTemplates = ["basic", "advanced", "research", "development"];
|
|
23010
23401
|
const customTemplatesDir = path3__namespace.join(process.cwd(), ".juno_task", "templates");
|
|
23011
23402
|
let customTemplates = [];
|
|
23012
|
-
if (await
|
|
23013
|
-
const files = await
|
|
23403
|
+
if (await fs3__default.default.pathExists(customTemplatesDir)) {
|
|
23404
|
+
const files = await fs3__default.default.readdir(customTemplatesDir);
|
|
23014
23405
|
customTemplates = files.filter((name) => name.endsWith(".md") || name.endsWith(".hbs")).map((name) => path3__namespace.basename(name, path3__namespace.extname(name)));
|
|
23015
23406
|
}
|
|
23016
23407
|
return [...builtinTemplates, ...customTemplates].sort();
|
|
@@ -23087,7 +23478,7 @@ var CompletionInstaller = class {
|
|
|
23087
23478
|
await this.shellDetector.ensureConfigDirectory(shell);
|
|
23088
23479
|
const script = this.generateEnhancedCompletion(shell, "juno-code");
|
|
23089
23480
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23090
|
-
await
|
|
23481
|
+
await fs3__default.default.writeFile(completionPath, script, "utf-8");
|
|
23091
23482
|
const configPath = this.shellDetector.getConfigPath(shell);
|
|
23092
23483
|
const sourceCommand = this.shellDetector.getSourceCommand(shell, completionPath);
|
|
23093
23484
|
const warnings = [];
|
|
@@ -23095,7 +23486,7 @@ var CompletionInstaller = class {
|
|
|
23095
23486
|
const isPresent = await this.shellDetector.isSourceCommandPresent(configPath, sourceCommand);
|
|
23096
23487
|
if (!isPresent) {
|
|
23097
23488
|
try {
|
|
23098
|
-
await
|
|
23489
|
+
await fs3__default.default.appendFile(configPath, `
|
|
23099
23490
|
|
|
23100
23491
|
${sourceCommand}
|
|
23101
23492
|
`);
|
|
@@ -23126,8 +23517,8 @@ ${sourceCommand}
|
|
|
23126
23517
|
async uninstall(shell) {
|
|
23127
23518
|
try {
|
|
23128
23519
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23129
|
-
if (await
|
|
23130
|
-
await
|
|
23520
|
+
if (await fs3__default.default.pathExists(completionPath)) {
|
|
23521
|
+
await fs3__default.default.remove(completionPath);
|
|
23131
23522
|
return true;
|
|
23132
23523
|
}
|
|
23133
23524
|
return false;
|
|
@@ -23141,7 +23532,7 @@ ${sourceCommand}
|
|
|
23141
23532
|
async isInstalled(shell) {
|
|
23142
23533
|
try {
|
|
23143
23534
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23144
|
-
return await
|
|
23535
|
+
return await fs3__default.default.pathExists(completionPath);
|
|
23145
23536
|
} catch {
|
|
23146
23537
|
return false;
|
|
23147
23538
|
}
|
|
@@ -23942,11 +24333,11 @@ function setupMainCommand(program) {
|
|
|
23942
24333
|
);
|
|
23943
24334
|
const allOptions2 = { ...definedGlobalOptions, ...options };
|
|
23944
24335
|
if (!globalOptions.subagent && !options.prompt && !options.interactive && !options.interactivePrompt) {
|
|
23945
|
-
const
|
|
23946
|
-
const
|
|
24336
|
+
const fs22 = await import('fs-extra');
|
|
24337
|
+
const path24 = await import('path');
|
|
23947
24338
|
const cwd2 = process.cwd();
|
|
23948
|
-
const junoTaskDir =
|
|
23949
|
-
if (await
|
|
24339
|
+
const junoTaskDir = path24.join(cwd2, ".juno_task");
|
|
24340
|
+
if (await fs22.pathExists(junoTaskDir)) {
|
|
23950
24341
|
console.log(chalk15__default.default.blue.bold("\u{1F3AF} Juno Code - Auto-detected Initialized Project\n"));
|
|
23951
24342
|
try {
|
|
23952
24343
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -23963,12 +24354,12 @@ function setupMainCommand(program) {
|
|
|
23963
24354
|
allOptions2.subagent = config.defaultSubagent;
|
|
23964
24355
|
console.log(chalk15__default.default.gray(`\u{1F916} Using configured subagent: ${chalk15__default.default.cyan(config.defaultSubagent)}`));
|
|
23965
24356
|
}
|
|
23966
|
-
const promptFile =
|
|
23967
|
-
if (!allOptions2.prompt && await
|
|
24357
|
+
const promptFile = path24.join(junoTaskDir, "prompt.md");
|
|
24358
|
+
if (!allOptions2.prompt && await fs22.pathExists(promptFile)) {
|
|
23968
24359
|
allOptions2.prompt = promptFile;
|
|
23969
24360
|
console.log(chalk15__default.default.gray(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
|
|
23970
24361
|
}
|
|
23971
|
-
if (allOptions2.subagent && (allOptions2.prompt || await
|
|
24362
|
+
if (allOptions2.subagent && (allOptions2.prompt || await fs22.pathExists(promptFile))) {
|
|
23972
24363
|
console.log(chalk15__default.default.green("\u2713 Auto-detected project configuration\n"));
|
|
23973
24364
|
const { mainCommandHandler: mainCommandHandler3 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
23974
24365
|
await mainCommandHandler3([], allOptions2, command);
|
|
@@ -24125,6 +24516,17 @@ async function main() {
|
|
|
24125
24516
|
console.error("[DEBUG] Service auto-update failed:", error instanceof Error ? error.message : String(error));
|
|
24126
24517
|
}
|
|
24127
24518
|
}
|
|
24519
|
+
try {
|
|
24520
|
+
const { ScriptInstaller: ScriptInstaller2 } = await Promise.resolve().then(() => (init_script_installer(), script_installer_exports));
|
|
24521
|
+
const updated = await ScriptInstaller2.autoUpdate(process.cwd(), true);
|
|
24522
|
+
if (updated && (process.argv.includes("--verbose") || process.argv.includes("-v") || process.env.JUNO_CODE_DEBUG === "1")) {
|
|
24523
|
+
console.error("[DEBUG] Project scripts auto-updated in .juno_task/scripts/");
|
|
24524
|
+
}
|
|
24525
|
+
} catch (error) {
|
|
24526
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
24527
|
+
console.error("[DEBUG] Script auto-update failed:", error instanceof Error ? error.message : String(error));
|
|
24528
|
+
}
|
|
24529
|
+
}
|
|
24128
24530
|
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");
|
|
24129
24531
|
setupGlobalOptions(program);
|
|
24130
24532
|
const isVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");
|
|
@@ -24132,10 +24534,10 @@ async function main() {
|
|
|
24132
24534
|
const isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V");
|
|
24133
24535
|
const hasNoArguments = process.argv.length <= 2;
|
|
24134
24536
|
const isInitCommand = process.argv.includes("init");
|
|
24135
|
-
const
|
|
24136
|
-
const
|
|
24137
|
-
const junoTaskDir =
|
|
24138
|
-
const isInitialized = await
|
|
24537
|
+
const fs22 = await import('fs-extra');
|
|
24538
|
+
const path24 = await import('path');
|
|
24539
|
+
const junoTaskDir = path24.join(process.cwd(), ".juno_task");
|
|
24540
|
+
const isInitialized = await fs22.pathExists(junoTaskDir);
|
|
24139
24541
|
if (!isHelpOrVersion && !hasNoArguments && !isInitCommand && isInitialized) {
|
|
24140
24542
|
try {
|
|
24141
24543
|
const { validateStartupConfigs: validateStartupConfigs2 } = await Promise.resolve().then(() => (init_startup_validation(), startup_validation_exports));
|