juno-code 1.0.35 → 1.0.36
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 +364 -64
- package/dist/bin/cli.js +445 -181
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +444 -180
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/clean_logs_folder.sh +0 -0
- package/dist/templates/scripts/run_until_completion.sh +202 -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 +3 -3
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",
|
|
@@ -341,8 +341,21 @@ var init_service_installer = __esm({
|
|
|
341
341
|
"src/utils/service-installer.ts"() {
|
|
342
342
|
init_version();
|
|
343
343
|
ServiceInstaller = class {
|
|
344
|
+
static REQUIRED_SCRIPTS = ["codex.py", "claude.py", "gemini.py"];
|
|
344
345
|
static SERVICES_DIR = path3__namespace.join(os4.homedir(), ".juno_code", "services");
|
|
345
346
|
static VERSION_FILE = path3__namespace.join(os4.homedir(), ".juno_code", "services", ".version");
|
|
347
|
+
static missingScripts(baseDir) {
|
|
348
|
+
return this.REQUIRED_SCRIPTS.filter((file) => !fs3__default.default.existsSync(path3__namespace.join(baseDir, file)));
|
|
349
|
+
}
|
|
350
|
+
static async missingScriptsAsync(baseDir) {
|
|
351
|
+
const results = await Promise.all(
|
|
352
|
+
this.REQUIRED_SCRIPTS.map(async (file) => ({
|
|
353
|
+
file,
|
|
354
|
+
exists: await fs3__default.default.pathExists(path3__namespace.join(baseDir, file))
|
|
355
|
+
}))
|
|
356
|
+
);
|
|
357
|
+
return results.filter((result) => !result.exists).map((result) => result.file);
|
|
358
|
+
}
|
|
346
359
|
/**
|
|
347
360
|
* Get the current package version
|
|
348
361
|
*/
|
|
@@ -351,12 +364,12 @@ var init_service_installer = __esm({
|
|
|
351
364
|
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
365
|
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
366
|
let packageJsonPath = path3__namespace.join(__dirname2, "..", "..", "package.json");
|
|
354
|
-
if (
|
|
367
|
+
if (fs3__default.default.existsSync(packageJsonPath)) {
|
|
355
368
|
const packageJson2 = require3(packageJsonPath);
|
|
356
369
|
return packageJson2.version;
|
|
357
370
|
}
|
|
358
371
|
packageJsonPath = path3__namespace.join(__dirname2, "..", "..", "..", "package.json");
|
|
359
|
-
if (
|
|
372
|
+
if (fs3__default.default.existsSync(packageJsonPath)) {
|
|
360
373
|
const packageJson2 = require3(packageJsonPath);
|
|
361
374
|
return packageJson2.version;
|
|
362
375
|
}
|
|
@@ -370,11 +383,11 @@ var init_service_installer = __esm({
|
|
|
370
383
|
*/
|
|
371
384
|
static async getInstalledVersion() {
|
|
372
385
|
try {
|
|
373
|
-
const exists = await
|
|
386
|
+
const exists = await fs3__default.default.pathExists(this.VERSION_FILE);
|
|
374
387
|
if (!exists) {
|
|
375
388
|
return null;
|
|
376
389
|
}
|
|
377
|
-
const version3 = await
|
|
390
|
+
const version3 = await fs3__default.default.readFile(this.VERSION_FILE, "utf-8");
|
|
378
391
|
return version3.trim();
|
|
379
392
|
} catch {
|
|
380
393
|
return null;
|
|
@@ -385,7 +398,7 @@ var init_service_installer = __esm({
|
|
|
385
398
|
*/
|
|
386
399
|
static async saveVersion() {
|
|
387
400
|
const version3 = this.getPackageVersion();
|
|
388
|
-
await
|
|
401
|
+
await fs3__default.default.writeFile(this.VERSION_FILE, version3, "utf-8");
|
|
389
402
|
}
|
|
390
403
|
/**
|
|
391
404
|
* Check if services need to be updated based on version
|
|
@@ -397,7 +410,7 @@ var init_service_installer = __esm({
|
|
|
397
410
|
if (!installedVersion) {
|
|
398
411
|
return true;
|
|
399
412
|
}
|
|
400
|
-
const exists = await
|
|
413
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
401
414
|
if (!exists) {
|
|
402
415
|
return true;
|
|
403
416
|
}
|
|
@@ -405,32 +418,22 @@ var init_service_installer = __esm({
|
|
|
405
418
|
return true;
|
|
406
419
|
}
|
|
407
420
|
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) {
|
|
421
|
+
const missingInstalled = await this.missingScriptsAsync(this.SERVICES_DIR);
|
|
422
|
+
if (missingInstalled.length > 0) {
|
|
413
423
|
return true;
|
|
414
424
|
}
|
|
415
425
|
try {
|
|
416
426
|
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
|
-
}
|
|
427
|
+
const missingPackageScripts = this.missingScripts(packageServicesDir);
|
|
428
|
+
if (missingPackageScripts.length > 0) {
|
|
429
|
+
throw new Error(`Missing required service scripts: ${missingPackageScripts.join(", ")}`);
|
|
429
430
|
}
|
|
430
|
-
|
|
431
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
432
|
+
const packageScript = path3__namespace.join(packageServicesDir, script);
|
|
433
|
+
const installedScript = path3__namespace.join(this.SERVICES_DIR, script);
|
|
431
434
|
const [pkg, inst] = await Promise.all([
|
|
432
|
-
|
|
433
|
-
|
|
435
|
+
fs3__default.default.readFile(packageScript, "utf-8"),
|
|
436
|
+
fs3__default.default.readFile(installedScript, "utf-8")
|
|
434
437
|
]);
|
|
435
438
|
if (pkg !== inst) {
|
|
436
439
|
return true;
|
|
@@ -454,15 +457,27 @@ var init_service_installer = __esm({
|
|
|
454
457
|
*/
|
|
455
458
|
static getPackageServicesDir() {
|
|
456
459
|
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
|
-
|
|
460
|
+
const candidates = [
|
|
461
|
+
path3__namespace.join(__dirname2, "..", "..", "templates", "services"),
|
|
462
|
+
// dist (production)
|
|
463
|
+
path3__namespace.join(__dirname2, "..", "templates", "services")
|
|
464
|
+
// src (development)
|
|
465
|
+
];
|
|
466
|
+
for (const servicesPath of candidates) {
|
|
467
|
+
if (!fs3__default.default.existsSync(servicesPath)) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
const missing = this.missingScripts(servicesPath);
|
|
471
|
+
if (missing.length === 0) {
|
|
472
|
+
return servicesPath;
|
|
473
|
+
}
|
|
474
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
475
|
+
console.error(`[DEBUG] Services path missing required scripts (${servicesPath}): ${missing.join(", ")}`);
|
|
476
|
+
}
|
|
464
477
|
}
|
|
465
|
-
throw new Error(
|
|
478
|
+
throw new Error(
|
|
479
|
+
"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."
|
|
480
|
+
);
|
|
466
481
|
}
|
|
467
482
|
/**
|
|
468
483
|
* Install all service scripts to ~/.juno_code/services/
|
|
@@ -470,18 +485,22 @@ var init_service_installer = __esm({
|
|
|
470
485
|
*/
|
|
471
486
|
static async install(silent = false) {
|
|
472
487
|
try {
|
|
473
|
-
await
|
|
488
|
+
await fs3__default.default.ensureDir(this.SERVICES_DIR);
|
|
474
489
|
const packageServicesDir = this.getPackageServicesDir();
|
|
475
|
-
await
|
|
490
|
+
await fs3__default.default.copy(packageServicesDir, this.SERVICES_DIR, {
|
|
476
491
|
overwrite: true,
|
|
477
492
|
preserveTimestamps: true
|
|
478
493
|
});
|
|
479
|
-
const
|
|
494
|
+
const missingAfterCopy = await this.missingScriptsAsync(this.SERVICES_DIR);
|
|
495
|
+
if (missingAfterCopy.length > 0) {
|
|
496
|
+
throw new Error(`Installed services missing required service scripts: ${missingAfterCopy.join(", ")}`);
|
|
497
|
+
}
|
|
498
|
+
const files = await fs3__default.default.readdir(this.SERVICES_DIR);
|
|
480
499
|
for (const file of files) {
|
|
481
500
|
const filePath = path3__namespace.join(this.SERVICES_DIR, file);
|
|
482
|
-
const stat = await
|
|
501
|
+
const stat = await fs3__default.default.stat(filePath);
|
|
483
502
|
if (stat.isFile() && (file.endsWith(".py") || file.endsWith(".sh"))) {
|
|
484
|
-
await
|
|
503
|
+
await fs3__default.default.chmod(filePath, 493);
|
|
485
504
|
}
|
|
486
505
|
}
|
|
487
506
|
await this.saveVersion();
|
|
@@ -528,11 +547,11 @@ var init_service_installer = __esm({
|
|
|
528
547
|
*/
|
|
529
548
|
static async isInstalled() {
|
|
530
549
|
try {
|
|
531
|
-
const exists = await
|
|
550
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
532
551
|
if (!exists) {
|
|
533
552
|
return false;
|
|
534
553
|
}
|
|
535
|
-
const files = await
|
|
554
|
+
const files = await fs3__default.default.readdir(this.SERVICES_DIR);
|
|
536
555
|
return files.length > 0;
|
|
537
556
|
} catch {
|
|
538
557
|
return false;
|
|
@@ -555,11 +574,11 @@ var init_service_installer = __esm({
|
|
|
555
574
|
*/
|
|
556
575
|
static async listServices() {
|
|
557
576
|
try {
|
|
558
|
-
const exists = await
|
|
577
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
559
578
|
if (!exists) {
|
|
560
579
|
return [];
|
|
561
580
|
}
|
|
562
|
-
const files = await
|
|
581
|
+
const files = await fs3__default.default.readdir(this.SERVICES_DIR);
|
|
563
582
|
return files.filter((file) => file.endsWith(".py") || file.endsWith(".sh"));
|
|
564
583
|
} catch {
|
|
565
584
|
return [];
|
|
@@ -570,9 +589,9 @@ var init_service_installer = __esm({
|
|
|
570
589
|
*/
|
|
571
590
|
static async uninstall() {
|
|
572
591
|
try {
|
|
573
|
-
const exists = await
|
|
592
|
+
const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
|
|
574
593
|
if (exists) {
|
|
575
|
-
await
|
|
594
|
+
await fs3__default.default.remove(this.SERVICES_DIR);
|
|
576
595
|
console.log("\u2713 Services uninstalled");
|
|
577
596
|
}
|
|
578
597
|
} catch (error) {
|
|
@@ -1148,17 +1167,17 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1148
1167
|
try {
|
|
1149
1168
|
const configDir = path3__namespace.join(baseDir, ".juno_task");
|
|
1150
1169
|
const configPath = path3__namespace.join(configDir, "config.json");
|
|
1151
|
-
await
|
|
1152
|
-
const configExists = await
|
|
1170
|
+
await fs3__default.default.ensureDir(configDir);
|
|
1171
|
+
const configExists = await fs3__default.default.pathExists(configPath);
|
|
1153
1172
|
const allHookTypes = getDefaultHooks();
|
|
1154
1173
|
if (!configExists) {
|
|
1155
1174
|
const defaultConfig = {
|
|
1156
1175
|
...DEFAULT_CONFIG,
|
|
1157
1176
|
hooks: allHookTypes
|
|
1158
1177
|
};
|
|
1159
|
-
await
|
|
1178
|
+
await fs3__default.default.writeJson(configPath, defaultConfig, { spaces: 2 });
|
|
1160
1179
|
} else {
|
|
1161
|
-
const existingConfig = await
|
|
1180
|
+
const existingConfig = await fs3__default.default.readJson(configPath);
|
|
1162
1181
|
let needsUpdate = false;
|
|
1163
1182
|
if (!existingConfig.hooks) {
|
|
1164
1183
|
existingConfig.hooks = allHookTypes;
|
|
@@ -1176,7 +1195,7 @@ async function ensureHooksConfig(baseDir) {
|
|
|
1176
1195
|
needsUpdate = true;
|
|
1177
1196
|
}
|
|
1178
1197
|
if (needsUpdate) {
|
|
1179
|
-
await
|
|
1198
|
+
await fs3__default.default.writeJson(configPath, existingConfig, { spaces: 2 });
|
|
1180
1199
|
}
|
|
1181
1200
|
}
|
|
1182
1201
|
} catch (error) {
|
|
@@ -1786,6 +1805,12 @@ ${helpText}
|
|
|
1786
1805
|
}
|
|
1787
1806
|
}
|
|
1788
1807
|
if (options.maxIterations !== void 0) {
|
|
1808
|
+
if (Number.isNaN(options.maxIterations)) {
|
|
1809
|
+
throw new ValidationError(
|
|
1810
|
+
"Max iterations must be a valid number",
|
|
1811
|
+
["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
|
|
1812
|
+
);
|
|
1813
|
+
}
|
|
1789
1814
|
if (options.maxIterations !== -1 && options.maxIterations < 1) {
|
|
1790
1815
|
throw new ValidationError(
|
|
1791
1816
|
"Max iterations must be -1 (unlimited) or a positive number",
|
|
@@ -1794,8 +1819,8 @@ ${helpText}
|
|
|
1794
1819
|
}
|
|
1795
1820
|
}
|
|
1796
1821
|
if (options.cwd) {
|
|
1797
|
-
const
|
|
1798
|
-
if (!await
|
|
1822
|
+
const fs22 = await import('fs-extra');
|
|
1823
|
+
if (!await fs22.pathExists(options.cwd)) {
|
|
1799
1824
|
throw new ValidationError(
|
|
1800
1825
|
`Working directory does not exist: ${options.cwd}`,
|
|
1801
1826
|
["Verify the path exists", "Use absolute paths to avoid ambiguity"]
|
|
@@ -3879,8 +3904,8 @@ var init_engine = __esm({
|
|
|
3879
3904
|
if (!request.workingDirectory?.trim()) {
|
|
3880
3905
|
throw new Error("Working directory is required");
|
|
3881
3906
|
}
|
|
3882
|
-
if (request.maxIterations < -1 || request.maxIterations === 0) {
|
|
3883
|
-
throw new Error("Max iterations must be positive or -1 for unlimited");
|
|
3907
|
+
if (Number.isNaN(request.maxIterations) || request.maxIterations < -1 || request.maxIterations === 0) {
|
|
3908
|
+
throw new Error("Max iterations must be a positive number or -1 for unlimited");
|
|
3884
3909
|
}
|
|
3885
3910
|
}
|
|
3886
3911
|
/**
|
|
@@ -4890,7 +4915,7 @@ var init_config2 = __esm({
|
|
|
4890
4915
|
return cached;
|
|
4891
4916
|
}
|
|
4892
4917
|
try {
|
|
4893
|
-
const configContent = await
|
|
4918
|
+
const configContent = await fs3__default.default.readFile(configPath, "utf-8");
|
|
4894
4919
|
const config = JSON.parse(configContent);
|
|
4895
4920
|
this.validateConfig(config);
|
|
4896
4921
|
const resolvedConfig = this.resolveConfigPaths(config, path3__namespace.dirname(configPath));
|
|
@@ -4912,7 +4937,7 @@ var init_config2 = __esm({
|
|
|
4912
4937
|
const rootDir = path3__namespace.parse(currentDir).root;
|
|
4913
4938
|
while (currentDir !== rootDir) {
|
|
4914
4939
|
const configPath = path3__namespace.join(currentDir, ".juno_task", "mcp.json");
|
|
4915
|
-
if (await
|
|
4940
|
+
if (await fs3__default.default.pathExists(configPath)) {
|
|
4916
4941
|
return configPath;
|
|
4917
4942
|
}
|
|
4918
4943
|
currentDir = path3__namespace.dirname(currentDir);
|
|
@@ -5098,7 +5123,7 @@ var init_logger = __esm({
|
|
|
5098
5123
|
* Matches Python's generate_log_file function
|
|
5099
5124
|
*/
|
|
5100
5125
|
async initialize(subagent = "mcp") {
|
|
5101
|
-
await
|
|
5126
|
+
await fs3__default.default.ensureDir(this.logDirectory);
|
|
5102
5127
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T");
|
|
5103
5128
|
const dateStr = timestamp[0];
|
|
5104
5129
|
const timeStr = timestamp[1].split("-")[0].substring(0, 6);
|
|
@@ -5107,7 +5132,7 @@ var init_logger = __esm({
|
|
|
5107
5132
|
this.logFilePath = path3__namespace.default.join(this.logDirectory, logFileName);
|
|
5108
5133
|
const header = `# Juno-Task TypeScript Log - Started ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
5109
5134
|
`;
|
|
5110
|
-
await
|
|
5135
|
+
await fs3__default.default.writeFile(this.logFilePath, header);
|
|
5111
5136
|
}
|
|
5112
5137
|
/**
|
|
5113
5138
|
* Format log message matching Python version format
|
|
@@ -5125,7 +5150,7 @@ var init_logger = __esm({
|
|
|
5125
5150
|
if (!this.logFilePath) {
|
|
5126
5151
|
throw new Error("Logger not initialized. Call initialize() first.");
|
|
5127
5152
|
}
|
|
5128
|
-
await
|
|
5153
|
+
await fs3__default.default.appendFile(this.logFilePath, message);
|
|
5129
5154
|
}
|
|
5130
5155
|
/**
|
|
5131
5156
|
* Log message at specified level
|
|
@@ -7136,7 +7161,7 @@ var init_shell_backend = __esm({
|
|
|
7136
7161
|
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
7162
|
const logDir = path3__namespace.join(this.config.workingDirectory, ".juno_task", "logs");
|
|
7138
7163
|
try {
|
|
7139
|
-
await
|
|
7164
|
+
await fs3__default.default.ensureDir(logDir);
|
|
7140
7165
|
} catch (error) {
|
|
7141
7166
|
if (this.config?.debug) {
|
|
7142
7167
|
engineLogger.warn(`Failed to create log directory: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7161,7 +7186,7 @@ var init_shell_backend = __esm({
|
|
|
7161
7186
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7162
7187
|
const logEntry = `[${timestamp}] ${message}
|
|
7163
7188
|
`;
|
|
7164
|
-
await
|
|
7189
|
+
await fs3__default.default.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
7165
7190
|
} catch (error) {
|
|
7166
7191
|
if (this.config?.debug) {
|
|
7167
7192
|
engineLogger.warn(`Failed to write to log file: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -7235,6 +7260,7 @@ var init_shell_backend = __esm({
|
|
|
7235
7260
|
return new Promise(async (resolve9, reject) => {
|
|
7236
7261
|
const startTime = Date.now();
|
|
7237
7262
|
const isPython = scriptPath.endsWith(".py");
|
|
7263
|
+
const isGemini = subagentType === "gemini";
|
|
7238
7264
|
const env2 = {
|
|
7239
7265
|
...process.env,
|
|
7240
7266
|
...this.config.environment,
|
|
@@ -7245,6 +7271,9 @@ var init_shell_backend = __esm({
|
|
|
7245
7271
|
JUNO_ITERATION: String(request.arguments?.iteration || 1),
|
|
7246
7272
|
JUNO_TOOL_ID: toolId
|
|
7247
7273
|
};
|
|
7274
|
+
if (isGemini) {
|
|
7275
|
+
env2.GEMINI_OUTPUT_FORMAT = env2.GEMINI_OUTPUT_FORMAT || "stream-json";
|
|
7276
|
+
}
|
|
7248
7277
|
let captureDir = null;
|
|
7249
7278
|
let capturePath = null;
|
|
7250
7279
|
if (subagentType === "claude") {
|
|
@@ -7266,6 +7295,9 @@ var init_shell_backend = __esm({
|
|
|
7266
7295
|
if (isPython && request.arguments?.model) {
|
|
7267
7296
|
args.push("-m", request.arguments.model);
|
|
7268
7297
|
}
|
|
7298
|
+
if (isPython && isGemini) {
|
|
7299
|
+
args.push("--output-format", env2.GEMINI_OUTPUT_FORMAT || "stream-json");
|
|
7300
|
+
}
|
|
7269
7301
|
if (isPython && request.arguments?.agents) {
|
|
7270
7302
|
args.push("--agents", request.arguments.agents);
|
|
7271
7303
|
}
|
|
@@ -12810,12 +12842,18 @@ async function mainCommandHandler(args, options, command) {
|
|
|
12810
12842
|
console.error(chalk15__default.default.red("\n\u274C Error: --allowed-tools and --append-allowed-tools are mutually exclusive. Use one or the other."));
|
|
12811
12843
|
process.exit(1);
|
|
12812
12844
|
}
|
|
12845
|
+
if (options.maxIterations !== void 0 && Number.isNaN(options.maxIterations)) {
|
|
12846
|
+
throw new ValidationError(
|
|
12847
|
+
"Max iterations must be a valid number",
|
|
12848
|
+
["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
|
|
12849
|
+
);
|
|
12850
|
+
}
|
|
12813
12851
|
const executionRequest = createExecutionRequest({
|
|
12814
12852
|
instruction,
|
|
12815
12853
|
subagent: options.subagent,
|
|
12816
12854
|
backend: selectedBackend,
|
|
12817
12855
|
workingDirectory: config.workingDirectory,
|
|
12818
|
-
maxIterations: options.maxIterations
|
|
12856
|
+
maxIterations: options.maxIterations ?? config.defaultMaxIterations,
|
|
12819
12857
|
model: options.model || config.defaultModel,
|
|
12820
12858
|
agents: options.agents,
|
|
12821
12859
|
tools: options.tools,
|
|
@@ -12980,7 +13018,7 @@ var init_main = __esm({
|
|
|
12980
13018
|
return await this.collectInteractivePrompt();
|
|
12981
13019
|
} else {
|
|
12982
13020
|
const defaultPromptPath = path3__namespace.join(process.cwd(), ".juno_task", "prompt.md");
|
|
12983
|
-
if (await
|
|
13021
|
+
if (await fs3__default.default.pathExists(defaultPromptPath)) {
|
|
12984
13022
|
console.error(chalk15__default.default.blue(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
|
|
12985
13023
|
return await this.loadPromptFromFile(defaultPromptPath);
|
|
12986
13024
|
} else {
|
|
@@ -13008,7 +13046,7 @@ var init_main = __esm({
|
|
|
13008
13046
|
}
|
|
13009
13047
|
try {
|
|
13010
13048
|
const resolvedPath = path3__namespace.resolve(prompt);
|
|
13011
|
-
return await
|
|
13049
|
+
return await fs3__default.default.pathExists(resolvedPath);
|
|
13012
13050
|
} catch {
|
|
13013
13051
|
return false;
|
|
13014
13052
|
}
|
|
@@ -13016,7 +13054,7 @@ var init_main = __esm({
|
|
|
13016
13054
|
async loadPromptFromFile(filePath) {
|
|
13017
13055
|
try {
|
|
13018
13056
|
const resolvedPath = path3__namespace.resolve(filePath);
|
|
13019
|
-
const content = await
|
|
13057
|
+
const content = await fs3__default.default.readFile(resolvedPath, "utf-8");
|
|
13020
13058
|
if (!content.trim()) {
|
|
13021
13059
|
throw new FileSystemError(
|
|
13022
13060
|
"Prompt file is empty",
|
|
@@ -13338,6 +13376,221 @@ var init_main = __esm({
|
|
|
13338
13376
|
}
|
|
13339
13377
|
});
|
|
13340
13378
|
|
|
13379
|
+
// src/utils/script-installer.ts
|
|
13380
|
+
var script_installer_exports = {};
|
|
13381
|
+
__export(script_installer_exports, {
|
|
13382
|
+
ScriptInstaller: () => ScriptInstaller
|
|
13383
|
+
});
|
|
13384
|
+
var ScriptInstaller;
|
|
13385
|
+
var init_script_installer = __esm({
|
|
13386
|
+
"src/utils/script-installer.ts"() {
|
|
13387
|
+
init_version();
|
|
13388
|
+
ScriptInstaller = class {
|
|
13389
|
+
/**
|
|
13390
|
+
* Scripts that should be auto-installed if missing
|
|
13391
|
+
* These are critical scripts that users expect to be available
|
|
13392
|
+
*/
|
|
13393
|
+
/**
|
|
13394
|
+
* Required scripts include both standalone scripts and their dependencies.
|
|
13395
|
+
* kanban.sh depends on install_requirements.sh for Python venv setup.
|
|
13396
|
+
*/
|
|
13397
|
+
static REQUIRED_SCRIPTS = [
|
|
13398
|
+
"run_until_completion.sh",
|
|
13399
|
+
"kanban.sh",
|
|
13400
|
+
"install_requirements.sh"
|
|
13401
|
+
// Required by kanban.sh for Python venv creation
|
|
13402
|
+
];
|
|
13403
|
+
/**
|
|
13404
|
+
* Get the templates scripts directory from the package
|
|
13405
|
+
*/
|
|
13406
|
+
static getPackageScriptsDir() {
|
|
13407
|
+
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))));
|
|
13408
|
+
const candidates = [
|
|
13409
|
+
path3__namespace.join(__dirname2, "..", "..", "templates", "scripts"),
|
|
13410
|
+
// dist (production)
|
|
13411
|
+
path3__namespace.join(__dirname2, "..", "templates", "scripts")
|
|
13412
|
+
// src (development)
|
|
13413
|
+
];
|
|
13414
|
+
for (const scriptsPath of candidates) {
|
|
13415
|
+
if (fs3__default.default.existsSync(scriptsPath)) {
|
|
13416
|
+
return scriptsPath;
|
|
13417
|
+
}
|
|
13418
|
+
}
|
|
13419
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13420
|
+
console.error("[DEBUG] ScriptInstaller: Could not find templates/scripts directory");
|
|
13421
|
+
console.error("[DEBUG] Tried:", candidates);
|
|
13422
|
+
}
|
|
13423
|
+
return null;
|
|
13424
|
+
}
|
|
13425
|
+
/**
|
|
13426
|
+
* Check if a specific script exists in the project's .juno_task/scripts/ directory
|
|
13427
|
+
*/
|
|
13428
|
+
static async scriptExists(projectDir, scriptName) {
|
|
13429
|
+
const scriptPath = path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13430
|
+
return fs3__default.default.pathExists(scriptPath);
|
|
13431
|
+
}
|
|
13432
|
+
/**
|
|
13433
|
+
* Install a specific script to the project's .juno_task/scripts/ directory
|
|
13434
|
+
* @param projectDir - The project root directory
|
|
13435
|
+
* @param scriptName - Name of the script to install (e.g., 'run_until_completion.sh')
|
|
13436
|
+
* @param silent - If true, suppresses console output
|
|
13437
|
+
* @returns true if script was installed, false if installation was skipped or failed
|
|
13438
|
+
*/
|
|
13439
|
+
static async installScript(projectDir, scriptName, silent = false) {
|
|
13440
|
+
try {
|
|
13441
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13442
|
+
if (!packageScriptsDir) {
|
|
13443
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13444
|
+
console.error("[DEBUG] ScriptInstaller: Package scripts directory not found");
|
|
13445
|
+
}
|
|
13446
|
+
return false;
|
|
13447
|
+
}
|
|
13448
|
+
const sourcePath = path3__namespace.join(packageScriptsDir, scriptName);
|
|
13449
|
+
if (!await fs3__default.default.pathExists(sourcePath)) {
|
|
13450
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13451
|
+
console.error(`[DEBUG] ScriptInstaller: Source script not found: ${sourcePath}`);
|
|
13452
|
+
}
|
|
13453
|
+
return false;
|
|
13454
|
+
}
|
|
13455
|
+
const destDir = path3__namespace.join(projectDir, ".juno_task", "scripts");
|
|
13456
|
+
await fs3__default.default.ensureDir(destDir);
|
|
13457
|
+
const destPath = path3__namespace.join(destDir, scriptName);
|
|
13458
|
+
await fs3__default.default.copy(sourcePath, destPath, { overwrite: true });
|
|
13459
|
+
if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
|
|
13460
|
+
await fs3__default.default.chmod(destPath, 493);
|
|
13461
|
+
}
|
|
13462
|
+
if (!silent) {
|
|
13463
|
+
console.log(`\u2713 Installed script: ${scriptName} to .juno_task/scripts/`);
|
|
13464
|
+
}
|
|
13465
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13466
|
+
console.error(`[DEBUG] ScriptInstaller: Installed ${scriptName} to ${destPath}`);
|
|
13467
|
+
}
|
|
13468
|
+
return true;
|
|
13469
|
+
} catch (error) {
|
|
13470
|
+
if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
|
|
13471
|
+
console.error(`[DEBUG] ScriptInstaller: Failed to install ${scriptName}:`, error);
|
|
13472
|
+
}
|
|
13473
|
+
return false;
|
|
13474
|
+
}
|
|
13475
|
+
}
|
|
13476
|
+
/**
|
|
13477
|
+
* Check which required scripts are missing from the project
|
|
13478
|
+
* @param projectDir - The project root directory
|
|
13479
|
+
* @returns Array of missing script names
|
|
13480
|
+
*/
|
|
13481
|
+
static async getMissingScripts(projectDir) {
|
|
13482
|
+
const missing = [];
|
|
13483
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13484
|
+
if (!await this.scriptExists(projectDir, script)) {
|
|
13485
|
+
missing.push(script);
|
|
13486
|
+
}
|
|
13487
|
+
}
|
|
13488
|
+
return missing;
|
|
13489
|
+
}
|
|
13490
|
+
/**
|
|
13491
|
+
* Auto-install any missing required scripts
|
|
13492
|
+
* This should be called on CLI startup for initialized projects
|
|
13493
|
+
* @param projectDir - The project root directory
|
|
13494
|
+
* @param silent - If true, suppresses console output
|
|
13495
|
+
* @returns true if any scripts were installed
|
|
13496
|
+
*/
|
|
13497
|
+
static async autoInstallMissing(projectDir, silent = true) {
|
|
13498
|
+
try {
|
|
13499
|
+
const junoTaskDir = path3__namespace.join(projectDir, ".juno_task");
|
|
13500
|
+
if (!await fs3__default.default.pathExists(junoTaskDir)) {
|
|
13501
|
+
return false;
|
|
13502
|
+
}
|
|
13503
|
+
const missing = await this.getMissingScripts(projectDir);
|
|
13504
|
+
if (missing.length === 0) {
|
|
13505
|
+
return false;
|
|
13506
|
+
}
|
|
13507
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13508
|
+
console.error(`[DEBUG] ScriptInstaller: Missing scripts: ${missing.join(", ")}`);
|
|
13509
|
+
}
|
|
13510
|
+
let installedAny = false;
|
|
13511
|
+
for (const script of missing) {
|
|
13512
|
+
const installed = await this.installScript(projectDir, script, silent);
|
|
13513
|
+
if (installed) {
|
|
13514
|
+
installedAny = true;
|
|
13515
|
+
}
|
|
13516
|
+
}
|
|
13517
|
+
if (installedAny && !silent) {
|
|
13518
|
+
console.log(`\u2713 Auto-installed ${missing.length} missing script(s)`);
|
|
13519
|
+
}
|
|
13520
|
+
return installedAny;
|
|
13521
|
+
} catch (error) {
|
|
13522
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13523
|
+
console.error("[DEBUG] ScriptInstaller: autoInstallMissing error:", error);
|
|
13524
|
+
}
|
|
13525
|
+
return false;
|
|
13526
|
+
}
|
|
13527
|
+
}
|
|
13528
|
+
/**
|
|
13529
|
+
* Update a script if the package version is newer (by content comparison)
|
|
13530
|
+
* @param projectDir - The project root directory
|
|
13531
|
+
* @param scriptName - Name of the script to update
|
|
13532
|
+
* @param silent - If true, suppresses console output
|
|
13533
|
+
* @returns true if script was updated
|
|
13534
|
+
*/
|
|
13535
|
+
static async updateScriptIfNewer(projectDir, scriptName, silent = true) {
|
|
13536
|
+
try {
|
|
13537
|
+
const packageScriptsDir = this.getPackageScriptsDir();
|
|
13538
|
+
if (!packageScriptsDir) {
|
|
13539
|
+
return false;
|
|
13540
|
+
}
|
|
13541
|
+
const sourcePath = path3__namespace.join(packageScriptsDir, scriptName);
|
|
13542
|
+
const destPath = path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13543
|
+
if (!await fs3__default.default.pathExists(destPath)) {
|
|
13544
|
+
return this.installScript(projectDir, scriptName, silent);
|
|
13545
|
+
}
|
|
13546
|
+
const [sourceContent, destContent] = await Promise.all([
|
|
13547
|
+
fs3__default.default.readFile(sourcePath, "utf-8"),
|
|
13548
|
+
fs3__default.default.readFile(destPath, "utf-8")
|
|
13549
|
+
]);
|
|
13550
|
+
if (sourceContent !== destContent) {
|
|
13551
|
+
await fs3__default.default.copy(sourcePath, destPath, { overwrite: true });
|
|
13552
|
+
if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
|
|
13553
|
+
await fs3__default.default.chmod(destPath, 493);
|
|
13554
|
+
}
|
|
13555
|
+
if (!silent) {
|
|
13556
|
+
console.log(`\u2713 Updated script: ${scriptName}`);
|
|
13557
|
+
}
|
|
13558
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13559
|
+
console.error(`[DEBUG] ScriptInstaller: Updated ${scriptName} (content changed)`);
|
|
13560
|
+
}
|
|
13561
|
+
return true;
|
|
13562
|
+
}
|
|
13563
|
+
return false;
|
|
13564
|
+
} catch (error) {
|
|
13565
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
13566
|
+
console.error(`[DEBUG] ScriptInstaller: updateScriptIfNewer error for ${scriptName}:`, error);
|
|
13567
|
+
}
|
|
13568
|
+
return false;
|
|
13569
|
+
}
|
|
13570
|
+
}
|
|
13571
|
+
/**
|
|
13572
|
+
* Get the path to a script in the project's .juno_task/scripts/ directory
|
|
13573
|
+
*/
|
|
13574
|
+
static getScriptPath(projectDir, scriptName) {
|
|
13575
|
+
return path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
|
|
13576
|
+
}
|
|
13577
|
+
/**
|
|
13578
|
+
* List all required scripts and their installation status
|
|
13579
|
+
*/
|
|
13580
|
+
static async listRequiredScripts(projectDir) {
|
|
13581
|
+
const results = [];
|
|
13582
|
+
for (const script of this.REQUIRED_SCRIPTS) {
|
|
13583
|
+
results.push({
|
|
13584
|
+
name: script,
|
|
13585
|
+
installed: await this.scriptExists(projectDir, script)
|
|
13586
|
+
});
|
|
13587
|
+
}
|
|
13588
|
+
return results;
|
|
13589
|
+
}
|
|
13590
|
+
};
|
|
13591
|
+
}
|
|
13592
|
+
});
|
|
13593
|
+
|
|
13341
13594
|
// src/utils/startup-validation.ts
|
|
13342
13595
|
var startup_validation_exports = {};
|
|
13343
13596
|
__export(startup_validation_exports, {
|
|
@@ -13428,7 +13681,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13428
13681
|
const warnings = [];
|
|
13429
13682
|
const filePath = path3__namespace.default.join(baseDir, configSchema.file);
|
|
13430
13683
|
try {
|
|
13431
|
-
const exists = await
|
|
13684
|
+
const exists = await fs3__default.default.pathExists(filePath);
|
|
13432
13685
|
if (!exists) {
|
|
13433
13686
|
if (configSchema.required) {
|
|
13434
13687
|
errors.push({
|
|
@@ -13451,7 +13704,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13451
13704
|
return { isValid: !configSchema.required, errors, warnings };
|
|
13452
13705
|
}
|
|
13453
13706
|
try {
|
|
13454
|
-
await
|
|
13707
|
+
await fs3__default.default.access(filePath, fs3__default.default.constants.R_OK);
|
|
13455
13708
|
} catch (accessError) {
|
|
13456
13709
|
errors.push({
|
|
13457
13710
|
file: configSchema.file,
|
|
@@ -13467,7 +13720,7 @@ async function validateJSONFile(configSchema, baseDir) {
|
|
|
13467
13720
|
}
|
|
13468
13721
|
let jsonData;
|
|
13469
13722
|
try {
|
|
13470
|
-
const fileContent = await
|
|
13723
|
+
const fileContent = await fs3__default.default.readFile(filePath, "utf8");
|
|
13471
13724
|
jsonData = JSON.parse(fileContent);
|
|
13472
13725
|
} catch (parseError) {
|
|
13473
13726
|
const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
|
|
@@ -13602,7 +13855,7 @@ function displayValidationResults(result) {
|
|
|
13602
13855
|
}
|
|
13603
13856
|
async function logValidationResults(result, baseDir = process.cwd()) {
|
|
13604
13857
|
const logDir = path3__namespace.default.join(baseDir, ".juno_task", "logs");
|
|
13605
|
-
await
|
|
13858
|
+
await fs3__default.default.ensureDir(logDir);
|
|
13606
13859
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
13607
13860
|
const logFile = path3__namespace.default.join(logDir, `startup-validation-${timestamp}.log`);
|
|
13608
13861
|
const logContent = [
|
|
@@ -13645,7 +13898,7 @@ async function logValidationResults(result, baseDir = process.cwd()) {
|
|
|
13645
13898
|
logContent.push(``);
|
|
13646
13899
|
}
|
|
13647
13900
|
}
|
|
13648
|
-
await
|
|
13901
|
+
await fs3__default.default.writeFile(logFile, logContent.join("\n"));
|
|
13649
13902
|
return logFile;
|
|
13650
13903
|
}
|
|
13651
13904
|
async function validateStartupConfigs(baseDir = process.cwd(), verbose = false) {
|
|
@@ -13979,7 +14232,7 @@ var TemplateEngine = class {
|
|
|
13979
14232
|
let overallError;
|
|
13980
14233
|
try {
|
|
13981
14234
|
if (!options.dryRun) {
|
|
13982
|
-
await
|
|
14235
|
+
await fs3__default.default.ensureDir(targetDirectory);
|
|
13983
14236
|
}
|
|
13984
14237
|
for (const template of templates) {
|
|
13985
14238
|
try {
|
|
@@ -15329,7 +15582,7 @@ This directory contains specification documents for your project.
|
|
|
15329
15582
|
const fileName = this.getTemplateFileName(template);
|
|
15330
15583
|
const targetPath = path3__namespace.join(targetDirectory, fileName);
|
|
15331
15584
|
try {
|
|
15332
|
-
const fileExists = await
|
|
15585
|
+
const fileExists = await fs3__default.default.pathExists(targetPath);
|
|
15333
15586
|
if (fileExists && !options.force && options.onConflict !== "overwrite") {
|
|
15334
15587
|
return {
|
|
15335
15588
|
path: targetPath,
|
|
@@ -15351,10 +15604,10 @@ This directory contains specification documents for your project.
|
|
|
15351
15604
|
}
|
|
15352
15605
|
if (options.createBackup && fileExists) {
|
|
15353
15606
|
const backupPath = `${targetPath}.backup.${Date.now()}`;
|
|
15354
|
-
await
|
|
15607
|
+
await fs3__default.default.copy(targetPath, backupPath);
|
|
15355
15608
|
}
|
|
15356
|
-
await
|
|
15357
|
-
await
|
|
15609
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(targetPath));
|
|
15610
|
+
await fs3__default.default.writeFile(targetPath, renderedContent, "utf8");
|
|
15358
15611
|
return {
|
|
15359
15612
|
path: targetPath,
|
|
15360
15613
|
content: renderedContent,
|
|
@@ -15618,7 +15871,7 @@ var SimpleInitTUI = class {
|
|
|
15618
15871
|
}
|
|
15619
15872
|
async confirmSave(targetDirectory) {
|
|
15620
15873
|
const junoTaskPath = path3__namespace.join(targetDirectory, ".juno_task");
|
|
15621
|
-
if (await
|
|
15874
|
+
if (await fs3__default.default.pathExists(junoTaskPath)) {
|
|
15622
15875
|
console.log(chalk15__default.default.yellow(" \u26A0\uFE0F .juno_task directory already exists"));
|
|
15623
15876
|
console.log(chalk15__default.default.gray(" Would you like to:"));
|
|
15624
15877
|
console.log(chalk15__default.default.gray(" 1) Override existing files"));
|
|
@@ -15663,16 +15916,16 @@ var SimpleProjectGenerator = class {
|
|
|
15663
15916
|
async generate() {
|
|
15664
15917
|
const { targetDirectory, variables, force } = this.context;
|
|
15665
15918
|
console.log(chalk15__default.default.blue("\u{1F4C1} Creating project directory..."));
|
|
15666
|
-
await
|
|
15919
|
+
await fs3__default.default.ensureDir(targetDirectory);
|
|
15667
15920
|
const junoTaskDir = path3__namespace.join(targetDirectory, ".juno_task");
|
|
15668
|
-
const junoTaskExists = await
|
|
15921
|
+
const junoTaskExists = await fs3__default.default.pathExists(junoTaskDir);
|
|
15669
15922
|
if (junoTaskExists && !force) {
|
|
15670
15923
|
throw new ValidationError(
|
|
15671
15924
|
"Project already initialized. Directory .juno_task already exists.",
|
|
15672
15925
|
["Use --force flag to overwrite existing files", "Choose a different directory"]
|
|
15673
15926
|
);
|
|
15674
15927
|
}
|
|
15675
|
-
await
|
|
15928
|
+
await fs3__default.default.ensureDir(junoTaskDir);
|
|
15676
15929
|
console.log(chalk15__default.default.blue("\u2699\uFE0F Creating project configuration..."));
|
|
15677
15930
|
await this.createConfigFile(junoTaskDir, targetDirectory);
|
|
15678
15931
|
console.log(chalk15__default.default.blue("\u{1F527} Setting up MCP configuration..."));
|
|
@@ -15706,21 +15959,21 @@ var SimpleProjectGenerator = class {
|
|
|
15706
15959
|
const promptContent = await templateEngine.render(promptTemplate, templateContext);
|
|
15707
15960
|
const initContent = await templateEngine.render(initTemplate, templateContext);
|
|
15708
15961
|
const implementContent = await templateEngine.render(implementTemplate, templateContext);
|
|
15709
|
-
await
|
|
15710
|
-
await
|
|
15711
|
-
await
|
|
15962
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "prompt.md"), promptContent);
|
|
15963
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "init.md"), initContent);
|
|
15964
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "implement.md"), implementContent);
|
|
15712
15965
|
const userFeedbackTemplate = templateEngine.getBuiltInTemplate("USER_FEEDBACK.md");
|
|
15713
15966
|
if (userFeedbackTemplate) {
|
|
15714
15967
|
const userFeedbackContent = await templateEngine.render(userFeedbackTemplate, templateContext);
|
|
15715
|
-
await
|
|
15968
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
|
|
15716
15969
|
}
|
|
15717
15970
|
const planTemplate = templateEngine.getBuiltInTemplate("plan.md");
|
|
15718
15971
|
if (planTemplate) {
|
|
15719
15972
|
const planContent = await templateEngine.render(planTemplate, templateContext);
|
|
15720
|
-
await
|
|
15973
|
+
await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
|
|
15721
15974
|
}
|
|
15722
15975
|
const specsDir = path3__namespace.join(junoTaskDir, "specs");
|
|
15723
|
-
await
|
|
15976
|
+
await fs3__default.default.ensureDir(specsDir);
|
|
15724
15977
|
const specsReadmeContent = `# Project Specifications
|
|
15725
15978
|
|
|
15726
15979
|
This directory contains detailed specifications for the project components.
|
|
@@ -15737,7 +15990,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15737
15990
|
- Avoid conflicts with existing file names
|
|
15738
15991
|
- Use \`.md\` extension for all specification files
|
|
15739
15992
|
`;
|
|
15740
|
-
await
|
|
15993
|
+
await fs3__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
|
|
15741
15994
|
const requirementsContent = `# Requirements Specification
|
|
15742
15995
|
|
|
15743
15996
|
## Functional Requirements
|
|
@@ -15784,7 +16037,7 @@ This directory contains detailed specifications for the project components.
|
|
|
15784
16037
|
- Code quality: Clean, maintainable codebase
|
|
15785
16038
|
- Documentation: Complete and accurate documentation
|
|
15786
16039
|
`;
|
|
15787
|
-
await
|
|
16040
|
+
await fs3__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
|
|
15788
16041
|
const architectureContent = `# Architecture Specification
|
|
15789
16042
|
|
|
15790
16043
|
## System Overview
|
|
@@ -15866,7 +16119,7 @@ This project uses AI-assisted development with juno-code to achieve: ${variables
|
|
|
15866
16119
|
- Performance monitoring
|
|
15867
16120
|
- Security best practices
|
|
15868
16121
|
`;
|
|
15869
|
-
await
|
|
16122
|
+
await fs3__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
|
|
15870
16123
|
const claudeContent = `# Claude Development Session Learnings
|
|
15871
16124
|
|
|
15872
16125
|
## Project Overview
|
|
@@ -15938,7 +16191,7 @@ This file will be updated as development progresses to track:
|
|
|
15938
16191
|
- Solutions to complex problems
|
|
15939
16192
|
- Performance improvements and optimizations
|
|
15940
16193
|
`;
|
|
15941
|
-
await
|
|
16194
|
+
await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
|
|
15942
16195
|
const agentsContent = `# AI Agent Selection and Performance
|
|
15943
16196
|
|
|
15944
16197
|
## Available Agents
|
|
@@ -16002,7 +16255,7 @@ Track agent performance for:
|
|
|
16002
16255
|
4. **Feedback Loop**: Provide feedback to improve agent performance
|
|
16003
16256
|
5. **Performance Monitoring**: Track and optimize agent usage
|
|
16004
16257
|
`;
|
|
16005
|
-
await
|
|
16258
|
+
await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
|
|
16006
16259
|
const readmeContent = `# ${variables.PROJECT_NAME}
|
|
16007
16260
|
|
|
16008
16261
|
${variables.DESCRIPTION}
|
|
@@ -16099,7 +16352,7 @@ ${variables.GIT_URL}` : ""}
|
|
|
16099
16352
|
Created with juno-code on ${variables.CURRENT_DATE}
|
|
16100
16353
|
${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
16101
16354
|
`;
|
|
16102
|
-
await
|
|
16355
|
+
await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
|
|
16103
16356
|
console.log(chalk15__default.default.blue("\u{1F4E6} Installing utility scripts..."));
|
|
16104
16357
|
await this.copyScriptsFromTemplates(junoTaskDir);
|
|
16105
16358
|
console.log(chalk15__default.default.blue("\u{1F40D} Installing Python requirements..."));
|
|
@@ -16151,7 +16404,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16151
16404
|
hooks: getDefaultHooks()
|
|
16152
16405
|
};
|
|
16153
16406
|
const configPath = path3__namespace.join(junoTaskDir, "config.json");
|
|
16154
|
-
await
|
|
16407
|
+
await fs3__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
|
|
16155
16408
|
console.log(chalk15__default.default.green(` \u2713 Created .juno_task/config.json with ${this.context.subagent} as default subagent`));
|
|
16156
16409
|
}
|
|
16157
16410
|
async createMcpFile(junoTaskDir, targetDirectory) {
|
|
@@ -16205,7 +16458,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16205
16458
|
}
|
|
16206
16459
|
};
|
|
16207
16460
|
const mcpPath = path3__namespace.join(junoTaskDir, "mcp.json");
|
|
16208
|
-
await
|
|
16461
|
+
await fs3__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
|
|
16209
16462
|
console.log(chalk15__default.default.green(` \u2713 Created .juno_task/mcp.json with roundtable-ai server configuration`));
|
|
16210
16463
|
}
|
|
16211
16464
|
getDefaultModelForSubagent(subagent) {
|
|
@@ -16224,7 +16477,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16224
16477
|
async copyScriptsFromTemplates(junoTaskDir) {
|
|
16225
16478
|
try {
|
|
16226
16479
|
const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
|
|
16227
|
-
await
|
|
16480
|
+
await fs3__default.default.ensureDir(scriptsDir);
|
|
16228
16481
|
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
16482
|
const __dirname2 = path3__namespace.dirname(__filename2);
|
|
16230
16483
|
let templatesScriptsDir;
|
|
@@ -16235,11 +16488,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16235
16488
|
} else {
|
|
16236
16489
|
templatesScriptsDir = path3__namespace.join(__dirname2, "../../templates/scripts");
|
|
16237
16490
|
}
|
|
16238
|
-
if (!await
|
|
16491
|
+
if (!await fs3__default.default.pathExists(templatesScriptsDir)) {
|
|
16239
16492
|
console.log(chalk15__default.default.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
|
|
16240
16493
|
return;
|
|
16241
16494
|
}
|
|
16242
|
-
const scriptFiles = await
|
|
16495
|
+
const scriptFiles = await fs3__default.default.readdir(templatesScriptsDir);
|
|
16243
16496
|
if (scriptFiles.length === 0) {
|
|
16244
16497
|
console.log(chalk15__default.default.gray(" \u2139\uFE0F No template scripts found to install"));
|
|
16245
16498
|
return;
|
|
@@ -16248,11 +16501,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16248
16501
|
for (const scriptFile of scriptFiles) {
|
|
16249
16502
|
const sourcePath = path3__namespace.join(templatesScriptsDir, scriptFile);
|
|
16250
16503
|
const destPath = path3__namespace.join(scriptsDir, scriptFile);
|
|
16251
|
-
const stats = await
|
|
16504
|
+
const stats = await fs3__default.default.stat(sourcePath);
|
|
16252
16505
|
if (stats.isFile()) {
|
|
16253
|
-
await
|
|
16506
|
+
await fs3__default.default.copy(sourcePath, destPath);
|
|
16254
16507
|
if (scriptFile.endsWith(".sh")) {
|
|
16255
|
-
await
|
|
16508
|
+
await fs3__default.default.chmod(destPath, 493);
|
|
16256
16509
|
}
|
|
16257
16510
|
copiedCount++;
|
|
16258
16511
|
console.log(chalk15__default.default.green(` \u2713 Installed script: ${scriptFile}`));
|
|
@@ -16275,7 +16528,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
|
|
|
16275
16528
|
try {
|
|
16276
16529
|
const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
|
|
16277
16530
|
const installScript = path3__namespace.join(scriptsDir, "install_requirements.sh");
|
|
16278
|
-
if (!await
|
|
16531
|
+
if (!await fs3__default.default.pathExists(installScript)) {
|
|
16279
16532
|
console.log(chalk15__default.default.yellow(" \u26A0\uFE0F install_requirements.sh not found, skipping Python dependencies installation"));
|
|
16280
16533
|
console.log(chalk15__default.default.gray(" You can install dependencies manually: juno-kanban, roundtable-ai"));
|
|
16281
16534
|
return;
|
|
@@ -16572,20 +16825,20 @@ init_types();
|
|
|
16572
16825
|
async function loadInitPrompt(directory) {
|
|
16573
16826
|
const junoTaskDir = path3__namespace.join(directory, ".juno_task");
|
|
16574
16827
|
const initFile = path3__namespace.join(junoTaskDir, "init.md");
|
|
16575
|
-
if (!await
|
|
16828
|
+
if (!await fs3__default.default.pathExists(junoTaskDir)) {
|
|
16576
16829
|
throw new FileSystemError(
|
|
16577
16830
|
'No .juno_task directory found. Run "juno-code init" first.',
|
|
16578
16831
|
junoTaskDir
|
|
16579
16832
|
);
|
|
16580
16833
|
}
|
|
16581
|
-
if (!await
|
|
16834
|
+
if (!await fs3__default.default.pathExists(initFile)) {
|
|
16582
16835
|
throw new FileSystemError(
|
|
16583
16836
|
"No init.md file found in .juno_task directory",
|
|
16584
16837
|
initFile
|
|
16585
16838
|
);
|
|
16586
16839
|
}
|
|
16587
16840
|
try {
|
|
16588
|
-
const content = await
|
|
16841
|
+
const content = await fs3__default.default.readFile(initFile, "utf-8");
|
|
16589
16842
|
if (!content.trim()) {
|
|
16590
16843
|
throw new FileSystemError(
|
|
16591
16844
|
"init.md file is empty. Please add task instructions.",
|
|
@@ -17617,8 +17870,8 @@ Focus on ${request.intelligence === "basic" ? "basic functionality" : request.in
|
|
|
17617
17870
|
for (const scenario of scenarios) {
|
|
17618
17871
|
const testContent = await this.generateTestContent(request, scenario, template);
|
|
17619
17872
|
const testFilePath = this.resolveTestFilePath(request, scenario);
|
|
17620
|
-
await
|
|
17621
|
-
await
|
|
17873
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(testFilePath));
|
|
17874
|
+
await fs3__default.default.writeFile(testFilePath, testContent);
|
|
17622
17875
|
testFiles.push(testFilePath);
|
|
17623
17876
|
}
|
|
17624
17877
|
return testFiles;
|
|
@@ -17870,8 +18123,8 @@ var TestExecutionEngine = class {
|
|
|
17870
18123
|
async collectCoverage(request) {
|
|
17871
18124
|
const coverageFile = path3__namespace.join(request.workingDirectory, "coverage", "coverage-summary.json");
|
|
17872
18125
|
try {
|
|
17873
|
-
if (await
|
|
17874
|
-
const coverageData = await
|
|
18126
|
+
if (await fs3__default.default.pathExists(coverageFile)) {
|
|
18127
|
+
const coverageData = await fs3__default.default.readJson(coverageFile);
|
|
17875
18128
|
return {
|
|
17876
18129
|
lines: coverageData.total?.lines?.pct || 0,
|
|
17877
18130
|
functions: coverageData.total?.functions?.pct || 0,
|
|
@@ -18054,8 +18307,8 @@ var TestReportEngine = class {
|
|
|
18054
18307
|
suggestions: analysis.suggestions,
|
|
18055
18308
|
recommendations: analysis.recommendations
|
|
18056
18309
|
};
|
|
18057
|
-
await
|
|
18058
|
-
await
|
|
18310
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
|
|
18311
|
+
await fs3__default.default.writeJson(outputPath, report, { spaces: 2 });
|
|
18059
18312
|
return outputPath;
|
|
18060
18313
|
}
|
|
18061
18314
|
async generateHTMLReport(analysis, outputPath, includeVisualizations) {
|
|
@@ -18118,8 +18371,8 @@ var TestReportEngine = class {
|
|
|
18118
18371
|
</body>
|
|
18119
18372
|
</html>
|
|
18120
18373
|
`.trim();
|
|
18121
|
-
await
|
|
18122
|
-
await
|
|
18374
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
|
|
18375
|
+
await fs3__default.default.writeFile(outputPath, html);
|
|
18123
18376
|
return outputPath;
|
|
18124
18377
|
}
|
|
18125
18378
|
generateCharts(analysis) {
|
|
@@ -18176,8 +18429,8 @@ ${analysis.suggestions.map((suggestion) => `- ${suggestion}`).join("\n")}
|
|
|
18176
18429
|
|
|
18177
18430
|
${analysis.recommendations.map((rec) => `- ${rec}`).join("\n")}
|
|
18178
18431
|
`.trim();
|
|
18179
|
-
await
|
|
18180
|
-
await
|
|
18432
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
|
|
18433
|
+
await fs3__default.default.writeFile(outputPath, markdown);
|
|
18181
18434
|
return outputPath;
|
|
18182
18435
|
}
|
|
18183
18436
|
async displayConsoleReport(analysis) {
|
|
@@ -18517,16 +18770,16 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18517
18770
|
preserveDays = 30,
|
|
18518
18771
|
preservePatterns = []
|
|
18519
18772
|
} = options;
|
|
18520
|
-
const originalContent = await
|
|
18773
|
+
const originalContent = await fs3__default.default.readFile(filePath, "utf-8");
|
|
18521
18774
|
const originalSize = originalContent.length;
|
|
18522
18775
|
let backupPath = "";
|
|
18523
18776
|
if (createBackup && !dryRun) {
|
|
18524
18777
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18525
18778
|
const ext = path3__namespace.extname(filePath);
|
|
18526
18779
|
const basename11 = path3__namespace.basename(filePath, ext);
|
|
18527
|
-
const
|
|
18528
|
-
backupPath = path3__namespace.join(
|
|
18529
|
-
await
|
|
18780
|
+
const dirname13 = path3__namespace.dirname(filePath);
|
|
18781
|
+
backupPath = path3__namespace.join(dirname13, `${basename11}.backup.${timestamp}${ext}`);
|
|
18782
|
+
await fs3__default.default.writeFile(backupPath, originalContent, "utf-8");
|
|
18530
18783
|
}
|
|
18531
18784
|
const compactionAnalysis = analyzeMarkdownStructure(originalContent);
|
|
18532
18785
|
const compactedContent = compactMarkdownContent(
|
|
@@ -18541,7 +18794,7 @@ async function compactConfigFile(filePath, options = {}) {
|
|
|
18541
18794
|
const compactedSize = finalContent.length;
|
|
18542
18795
|
const reductionPercentage = Math.round((originalSize - compactedSize) / originalSize * 100);
|
|
18543
18796
|
if (!dryRun) {
|
|
18544
|
-
await
|
|
18797
|
+
await fs3__default.default.writeFile(filePath, finalContent, "utf-8");
|
|
18545
18798
|
}
|
|
18546
18799
|
return {
|
|
18547
18800
|
originalSize,
|
|
@@ -18671,7 +18924,7 @@ function formatFileSize(bytes) {
|
|
|
18671
18924
|
}
|
|
18672
18925
|
async function shouldCompactFile(filePath, sizeThresholdKB = 50, ageThresholdDays = 30) {
|
|
18673
18926
|
try {
|
|
18674
|
-
const stats = await
|
|
18927
|
+
const stats = await fs3__default.default.stat(filePath);
|
|
18675
18928
|
const sizeKB = stats.size / 1024;
|
|
18676
18929
|
if (sizeKB > sizeThresholdKB) {
|
|
18677
18930
|
return true;
|
|
@@ -18693,19 +18946,19 @@ async function archiveResolvedIssues(options) {
|
|
|
18693
18946
|
feedbackFile,
|
|
18694
18947
|
archiveDir = path3__namespace.join(path3__namespace.dirname(feedbackFile), "archives"),
|
|
18695
18948
|
openIssuesThreshold = 10} = options;
|
|
18696
|
-
if (!await
|
|
18949
|
+
if (!await fs3__default.default.pathExists(feedbackFile)) {
|
|
18697
18950
|
throw new Error(`Feedback file does not exist: ${feedbackFile}`);
|
|
18698
18951
|
}
|
|
18699
|
-
const content = await
|
|
18952
|
+
const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
|
|
18700
18953
|
const parsed = parseUserFeedback(content);
|
|
18701
18954
|
const warningsGenerated = [];
|
|
18702
18955
|
if (parsed.openIssues.length > openIssuesThreshold) {
|
|
18703
18956
|
const warning = `Found ${parsed.openIssues.length} open issues (threshold: ${openIssuesThreshold}). Consider reviewing and prioritizing.`;
|
|
18704
18957
|
warningsGenerated.push(warning);
|
|
18705
18958
|
const logFile = path3__namespace.join(path3__namespace.dirname(feedbackFile), "logs", "feedback-warnings.log");
|
|
18706
|
-
await
|
|
18959
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(logFile));
|
|
18707
18960
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
18708
|
-
await
|
|
18961
|
+
await fs3__default.default.appendFile(logFile, `[${timestamp}] ${warning}
|
|
18709
18962
|
`);
|
|
18710
18963
|
}
|
|
18711
18964
|
if (parsed.resolvedIssues.length === 0) {
|
|
@@ -18722,10 +18975,10 @@ async function archiveResolvedIssues(options) {
|
|
|
18722
18975
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
18723
18976
|
const archiveFile = path3__namespace.join(archiveDir, `USER_FEEDBACK_archive_${currentYear}.md`);
|
|
18724
18977
|
{
|
|
18725
|
-
await
|
|
18978
|
+
await fs3__default.default.ensureDir(archiveDir);
|
|
18726
18979
|
await appendToArchive(archiveFile, parsed.resolvedIssues);
|
|
18727
18980
|
const compactedContent = generateCompactedFeedback(parsed.openIssues, parsed.metadata);
|
|
18728
|
-
await
|
|
18981
|
+
await fs3__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
|
|
18729
18982
|
}
|
|
18730
18983
|
{
|
|
18731
18984
|
console.log(chalk15__default.default.green(`\u2705 Archived ${parsed.resolvedIssues.length} resolved issues`));
|
|
@@ -18772,8 +19025,8 @@ function parseUserFeedback(content) {
|
|
|
18772
19025
|
async function appendToArchive(archiveFile, resolvedIssues) {
|
|
18773
19026
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
18774
19027
|
let archiveContent = "";
|
|
18775
|
-
if (await
|
|
18776
|
-
archiveContent = await
|
|
19028
|
+
if (await fs3__default.default.pathExists(archiveFile)) {
|
|
19029
|
+
archiveContent = await fs3__default.default.readFile(archiveFile, "utf-8");
|
|
18777
19030
|
} else {
|
|
18778
19031
|
const year = path3__namespace.basename(archiveFile).match(/(\d{4})/)?.[1] || (/* @__PURE__ */ new Date()).getFullYear();
|
|
18779
19032
|
archiveContent = `# User Feedback Archive ${year}
|
|
@@ -18807,7 +19060,7 @@ ${resolvedIssue}
|
|
|
18807
19060
|
`- Last updated: ${timestamp}`
|
|
18808
19061
|
);
|
|
18809
19062
|
}
|
|
18810
|
-
await
|
|
19063
|
+
await fs3__default.default.writeFile(archiveFile, archiveContent, "utf-8");
|
|
18811
19064
|
}
|
|
18812
19065
|
function generateCompactedFeedback(openIssues, metadata) {
|
|
18813
19066
|
let content = metadata.trim() + "\n";
|
|
@@ -18832,15 +19085,15 @@ async function shouldArchive(feedbackFile, options = {}) {
|
|
|
18832
19085
|
// 50KB
|
|
18833
19086
|
lineCountThreshold = 500
|
|
18834
19087
|
} = options;
|
|
18835
|
-
if (!await
|
|
19088
|
+
if (!await fs3__default.default.pathExists(feedbackFile)) {
|
|
18836
19089
|
return {
|
|
18837
19090
|
shouldArchive: false,
|
|
18838
19091
|
reasons: [],
|
|
18839
19092
|
stats: { openIssuesCount: 0, resolvedIssuesCount: 0, fileSizeBytes: 0, lineCount: 0 }
|
|
18840
19093
|
};
|
|
18841
19094
|
}
|
|
18842
|
-
const content = await
|
|
18843
|
-
const stats = await
|
|
19095
|
+
const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
|
|
19096
|
+
const stats = await fs3__default.default.stat(feedbackFile);
|
|
18844
19097
|
const parsed = parseUserFeedback(content);
|
|
18845
19098
|
const lineCount = content.split("\n").length;
|
|
18846
19099
|
const reasons = [];
|
|
@@ -18914,16 +19167,16 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18914
19167
|
this.feedbackFile = feedbackFile;
|
|
18915
19168
|
}
|
|
18916
19169
|
async ensureExists() {
|
|
18917
|
-
if (!await
|
|
19170
|
+
if (!await fs3__default.default.pathExists(this.feedbackFile)) {
|
|
18918
19171
|
await this.createInitialFile();
|
|
18919
19172
|
}
|
|
18920
19173
|
}
|
|
18921
19174
|
async addFeedback(issue, testCriteria) {
|
|
18922
19175
|
await this.ensureExists();
|
|
18923
19176
|
try {
|
|
18924
|
-
const content = await
|
|
19177
|
+
const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
|
|
18925
19178
|
const updatedContent = this.addIssueToContent(content, issue, testCriteria);
|
|
18926
|
-
await
|
|
19179
|
+
await fs3__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
|
|
18927
19180
|
} catch (error) {
|
|
18928
19181
|
throw new ValidationError(
|
|
18929
19182
|
`Failed to save feedback: ${error}`,
|
|
@@ -18936,12 +19189,12 @@ var EnhancedFeedbackFileManager = class {
|
|
|
18936
19189
|
*/
|
|
18937
19190
|
async repairMalformedFile() {
|
|
18938
19191
|
try {
|
|
18939
|
-
const content = await
|
|
19192
|
+
const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
|
|
18940
19193
|
const hasOpenIssues = content.includes("<OPEN_ISSUES>");
|
|
18941
19194
|
const hasClosingTag = content.includes("</OPEN_ISSUES>");
|
|
18942
19195
|
if (!hasOpenIssues || !hasClosingTag) {
|
|
18943
19196
|
const backupPath = this.feedbackFile + ".backup." + Date.now();
|
|
18944
|
-
await
|
|
19197
|
+
await fs3__default.default.writeFile(backupPath, content, "utf-8");
|
|
18945
19198
|
const existingIssues = this.extractIssuesFromMalformedContent(content);
|
|
18946
19199
|
await this.createInitialFile(existingIssues);
|
|
18947
19200
|
}
|
|
@@ -18973,8 +19226,8 @@ List any features you'd like to see added or bugs you've encountered.
|
|
|
18973
19226
|
|
|
18974
19227
|
<!-- Resolved issues will be moved here -->
|
|
18975
19228
|
`;
|
|
18976
|
-
await
|
|
18977
|
-
await
|
|
19229
|
+
await fs3__default.default.ensureDir(path3__namespace.dirname(this.feedbackFile));
|
|
19230
|
+
await fs3__default.default.writeFile(this.feedbackFile, initialContent, "utf-8");
|
|
18978
19231
|
}
|
|
18979
19232
|
addIssueToContent(content, issue, testCriteria) {
|
|
18980
19233
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -19090,17 +19343,17 @@ async function handleCompactCommand(subArgs, options) {
|
|
|
19090
19343
|
if (subArgs.length > 0) {
|
|
19091
19344
|
for (const filePath of subArgs) {
|
|
19092
19345
|
const resolvedPath = path3__namespace.resolve(filePath);
|
|
19093
|
-
if (await
|
|
19346
|
+
if (await fs3__default.default.pathExists(resolvedPath)) {
|
|
19094
19347
|
filesToCompact.push(resolvedPath);
|
|
19095
19348
|
} else {
|
|
19096
19349
|
console.warn(chalk15__default.default.yellow(`\u26A0\uFE0F File not found: ${filePath}`));
|
|
19097
19350
|
}
|
|
19098
19351
|
}
|
|
19099
19352
|
} else {
|
|
19100
|
-
if (await
|
|
19353
|
+
if (await fs3__default.default.pathExists(defaultClaudeFile)) {
|
|
19101
19354
|
filesToCompact.push(defaultClaudeFile);
|
|
19102
19355
|
}
|
|
19103
|
-
if (await
|
|
19356
|
+
if (await fs3__default.default.pathExists(defaultAgentsFile)) {
|
|
19104
19357
|
filesToCompact.push(defaultAgentsFile);
|
|
19105
19358
|
}
|
|
19106
19359
|
}
|
|
@@ -20034,11 +20287,11 @@ var GitManager = class {
|
|
|
20034
20287
|
*/
|
|
20035
20288
|
async updateJunoTaskConfig(gitUrl) {
|
|
20036
20289
|
const configPath = path3__namespace.join(this.workingDirectory, ".juno_task", "init.md");
|
|
20037
|
-
if (!await
|
|
20290
|
+
if (!await fs3__default.default.pathExists(configPath)) {
|
|
20038
20291
|
return;
|
|
20039
20292
|
}
|
|
20040
20293
|
try {
|
|
20041
|
-
let content = await
|
|
20294
|
+
let content = await fs3__default.default.readFile(configPath, "utf-8");
|
|
20042
20295
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
20043
20296
|
if (frontmatterMatch) {
|
|
20044
20297
|
let frontmatter = frontmatterMatch[1];
|
|
@@ -20059,7 +20312,7 @@ GIT_URL: ${gitUrl}
|
|
|
20059
20312
|
`;
|
|
20060
20313
|
content = frontmatter + content;
|
|
20061
20314
|
}
|
|
20062
|
-
await
|
|
20315
|
+
await fs3__default.default.writeFile(configPath, content, "utf-8");
|
|
20063
20316
|
} catch (error) {
|
|
20064
20317
|
console.warn(`Warning: Failed to update juno-code configuration: ${error}`);
|
|
20065
20318
|
}
|
|
@@ -20991,7 +21244,7 @@ var LogViewer = ({
|
|
|
20991
21244
|
init_types();
|
|
20992
21245
|
async function exportLogs(logger2, filepath, options) {
|
|
20993
21246
|
try {
|
|
20994
|
-
const
|
|
21247
|
+
const fs22 = await import('fs-extra');
|
|
20995
21248
|
let entries = logger2.getRecentEntries(options.tail || 1e3);
|
|
20996
21249
|
if (options.level) {
|
|
20997
21250
|
const level = LogLevel[options.level.toUpperCase()];
|
|
@@ -21021,7 +21274,7 @@ async function exportLogs(logger2, filepath, options) {
|
|
|
21021
21274
|
},
|
|
21022
21275
|
entries
|
|
21023
21276
|
};
|
|
21024
|
-
await
|
|
21277
|
+
await fs22.writeFile(filepath, JSON.stringify(exportData, null, 2));
|
|
21025
21278
|
console.log(chalk15__default.default.green(`\u2705 Exported ${entries.length} log entries to: ${filepath}`));
|
|
21026
21279
|
} catch (error) {
|
|
21027
21280
|
console.error(chalk15__default.default.red(`\u274C Failed to export logs: ${error}`));
|
|
@@ -22565,7 +22818,7 @@ function createServicesCommand() {
|
|
|
22565
22818
|
const servicesCmd = new commander.Command("services").description("Manage juno-code service scripts").addHelpText("after", `
|
|
22566
22819
|
Examples:
|
|
22567
22820
|
$ 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)
|
|
22821
|
+
$ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py/gemini.py)
|
|
22569
22822
|
$ juno-code services list List installed service scripts
|
|
22570
22823
|
$ juno-code services status Check installation status
|
|
22571
22824
|
$ juno-code services uninstall Remove all service scripts
|
|
@@ -22822,10 +23075,10 @@ autoload -U compinit && compinit`;
|
|
|
22822
23075
|
*/
|
|
22823
23076
|
async isSourceCommandPresent(configPath, sourceCommand) {
|
|
22824
23077
|
try {
|
|
22825
|
-
if (!await
|
|
23078
|
+
if (!await fs3__default.default.pathExists(configPath)) {
|
|
22826
23079
|
return false;
|
|
22827
23080
|
}
|
|
22828
|
-
const content = await
|
|
23081
|
+
const content = await fs3__default.default.readFile(configPath, "utf-8");
|
|
22829
23082
|
return content.includes("juno-code completion");
|
|
22830
23083
|
} catch {
|
|
22831
23084
|
return false;
|
|
@@ -22847,15 +23100,15 @@ autoload -U compinit && compinit`;
|
|
|
22847
23100
|
continue;
|
|
22848
23101
|
}
|
|
22849
23102
|
try {
|
|
22850
|
-
const completionExists = await
|
|
22851
|
-
const configExists = await
|
|
23103
|
+
const completionExists = await fs3__default.default.pathExists(shell.completionPath);
|
|
23104
|
+
const configExists = await fs3__default.default.pathExists(shell.configPath);
|
|
22852
23105
|
const isSourced = configExists && await this.isSourceCommandPresent(
|
|
22853
23106
|
shell.configPath,
|
|
22854
23107
|
this.getSourceCommand(shell.name, shell.completionPath)
|
|
22855
23108
|
);
|
|
22856
23109
|
let lastInstalled;
|
|
22857
23110
|
if (completionExists) {
|
|
22858
|
-
const stats = await
|
|
23111
|
+
const stats = await fs3__default.default.stat(shell.completionPath);
|
|
22859
23112
|
lastInstalled = stats.mtime;
|
|
22860
23113
|
}
|
|
22861
23114
|
statuses.push({
|
|
@@ -22881,7 +23134,7 @@ autoload -U compinit && compinit`;
|
|
|
22881
23134
|
async ensureCompletionDirectory(shell) {
|
|
22882
23135
|
const completionPath = this.getCompletionPath(shell);
|
|
22883
23136
|
const completionDir = path3__namespace.dirname(completionPath);
|
|
22884
|
-
await
|
|
23137
|
+
await fs3__default.default.ensureDir(completionDir);
|
|
22885
23138
|
}
|
|
22886
23139
|
/**
|
|
22887
23140
|
* Ensure directory exists for shell configuration
|
|
@@ -22889,7 +23142,7 @@ autoload -U compinit && compinit`;
|
|
|
22889
23142
|
async ensureConfigDirectory(shell) {
|
|
22890
23143
|
const configPath = this.getConfigPath(shell);
|
|
22891
23144
|
const configDir = path3__namespace.dirname(configPath);
|
|
22892
|
-
await
|
|
23145
|
+
await fs3__default.default.ensureDir(configDir);
|
|
22893
23146
|
}
|
|
22894
23147
|
/**
|
|
22895
23148
|
* Get shell version information
|
|
@@ -22913,15 +23166,15 @@ autoload -U compinit && compinit`;
|
|
|
22913
23166
|
try {
|
|
22914
23167
|
const configPath = this.getConfigPath(shell);
|
|
22915
23168
|
const configDir = path3__namespace.dirname(configPath);
|
|
22916
|
-
await
|
|
23169
|
+
await fs3__default.default.access(configDir, fs3__default.default.constants.W_OK);
|
|
22917
23170
|
} catch {
|
|
22918
23171
|
issues.push(`Cannot write to ${shell} configuration directory`);
|
|
22919
23172
|
}
|
|
22920
23173
|
try {
|
|
22921
23174
|
const completionPath = this.getCompletionPath(shell);
|
|
22922
23175
|
const completionDir = path3__namespace.dirname(completionPath);
|
|
22923
|
-
await
|
|
22924
|
-
await
|
|
23176
|
+
await fs3__default.default.ensureDir(completionDir);
|
|
23177
|
+
await fs3__default.default.access(completionDir, fs3__default.default.constants.W_OK);
|
|
22925
23178
|
} catch {
|
|
22926
23179
|
issues.push(`Cannot write to ${shell} completion directory`);
|
|
22927
23180
|
}
|
|
@@ -22992,10 +23245,10 @@ var ContextAwareCompletion = class {
|
|
|
22992
23245
|
async getSessionIds() {
|
|
22993
23246
|
try {
|
|
22994
23247
|
const sessionDir = path3__namespace.join(process.cwd(), ".juno_task", "sessions");
|
|
22995
|
-
if (!await
|
|
23248
|
+
if (!await fs3__default.default.pathExists(sessionDir)) {
|
|
22996
23249
|
return [];
|
|
22997
23250
|
}
|
|
22998
|
-
const sessions = await
|
|
23251
|
+
const sessions = await fs3__default.default.readdir(sessionDir);
|
|
22999
23252
|
return sessions.filter((name) => name.match(/^session_\d+$/)).map((name) => name.replace("session_", "")).sort((a, b) => parseInt(b) - parseInt(a));
|
|
23000
23253
|
} catch {
|
|
23001
23254
|
return [];
|
|
@@ -23009,8 +23262,8 @@ var ContextAwareCompletion = class {
|
|
|
23009
23262
|
const builtinTemplates = ["basic", "advanced", "research", "development"];
|
|
23010
23263
|
const customTemplatesDir = path3__namespace.join(process.cwd(), ".juno_task", "templates");
|
|
23011
23264
|
let customTemplates = [];
|
|
23012
|
-
if (await
|
|
23013
|
-
const files = await
|
|
23265
|
+
if (await fs3__default.default.pathExists(customTemplatesDir)) {
|
|
23266
|
+
const files = await fs3__default.default.readdir(customTemplatesDir);
|
|
23014
23267
|
customTemplates = files.filter((name) => name.endsWith(".md") || name.endsWith(".hbs")).map((name) => path3__namespace.basename(name, path3__namespace.extname(name)));
|
|
23015
23268
|
}
|
|
23016
23269
|
return [...builtinTemplates, ...customTemplates].sort();
|
|
@@ -23087,7 +23340,7 @@ var CompletionInstaller = class {
|
|
|
23087
23340
|
await this.shellDetector.ensureConfigDirectory(shell);
|
|
23088
23341
|
const script = this.generateEnhancedCompletion(shell, "juno-code");
|
|
23089
23342
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23090
|
-
await
|
|
23343
|
+
await fs3__default.default.writeFile(completionPath, script, "utf-8");
|
|
23091
23344
|
const configPath = this.shellDetector.getConfigPath(shell);
|
|
23092
23345
|
const sourceCommand = this.shellDetector.getSourceCommand(shell, completionPath);
|
|
23093
23346
|
const warnings = [];
|
|
@@ -23095,7 +23348,7 @@ var CompletionInstaller = class {
|
|
|
23095
23348
|
const isPresent = await this.shellDetector.isSourceCommandPresent(configPath, sourceCommand);
|
|
23096
23349
|
if (!isPresent) {
|
|
23097
23350
|
try {
|
|
23098
|
-
await
|
|
23351
|
+
await fs3__default.default.appendFile(configPath, `
|
|
23099
23352
|
|
|
23100
23353
|
${sourceCommand}
|
|
23101
23354
|
`);
|
|
@@ -23126,8 +23379,8 @@ ${sourceCommand}
|
|
|
23126
23379
|
async uninstall(shell) {
|
|
23127
23380
|
try {
|
|
23128
23381
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23129
|
-
if (await
|
|
23130
|
-
await
|
|
23382
|
+
if (await fs3__default.default.pathExists(completionPath)) {
|
|
23383
|
+
await fs3__default.default.remove(completionPath);
|
|
23131
23384
|
return true;
|
|
23132
23385
|
}
|
|
23133
23386
|
return false;
|
|
@@ -23141,7 +23394,7 @@ ${sourceCommand}
|
|
|
23141
23394
|
async isInstalled(shell) {
|
|
23142
23395
|
try {
|
|
23143
23396
|
const completionPath = this.shellDetector.getCompletionPath(shell);
|
|
23144
|
-
return await
|
|
23397
|
+
return await fs3__default.default.pathExists(completionPath);
|
|
23145
23398
|
} catch {
|
|
23146
23399
|
return false;
|
|
23147
23400
|
}
|
|
@@ -23942,11 +24195,11 @@ function setupMainCommand(program) {
|
|
|
23942
24195
|
);
|
|
23943
24196
|
const allOptions2 = { ...definedGlobalOptions, ...options };
|
|
23944
24197
|
if (!globalOptions.subagent && !options.prompt && !options.interactive && !options.interactivePrompt) {
|
|
23945
|
-
const
|
|
23946
|
-
const
|
|
24198
|
+
const fs22 = await import('fs-extra');
|
|
24199
|
+
const path24 = await import('path');
|
|
23947
24200
|
const cwd2 = process.cwd();
|
|
23948
|
-
const junoTaskDir =
|
|
23949
|
-
if (await
|
|
24201
|
+
const junoTaskDir = path24.join(cwd2, ".juno_task");
|
|
24202
|
+
if (await fs22.pathExists(junoTaskDir)) {
|
|
23950
24203
|
console.log(chalk15__default.default.blue.bold("\u{1F3AF} Juno Code - Auto-detected Initialized Project\n"));
|
|
23951
24204
|
try {
|
|
23952
24205
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -23963,12 +24216,12 @@ function setupMainCommand(program) {
|
|
|
23963
24216
|
allOptions2.subagent = config.defaultSubagent;
|
|
23964
24217
|
console.log(chalk15__default.default.gray(`\u{1F916} Using configured subagent: ${chalk15__default.default.cyan(config.defaultSubagent)}`));
|
|
23965
24218
|
}
|
|
23966
|
-
const promptFile =
|
|
23967
|
-
if (!allOptions2.prompt && await
|
|
24219
|
+
const promptFile = path24.join(junoTaskDir, "prompt.md");
|
|
24220
|
+
if (!allOptions2.prompt && await fs22.pathExists(promptFile)) {
|
|
23968
24221
|
allOptions2.prompt = promptFile;
|
|
23969
24222
|
console.log(chalk15__default.default.gray(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
|
|
23970
24223
|
}
|
|
23971
|
-
if (allOptions2.subagent && (allOptions2.prompt || await
|
|
24224
|
+
if (allOptions2.subagent && (allOptions2.prompt || await fs22.pathExists(promptFile))) {
|
|
23972
24225
|
console.log(chalk15__default.default.green("\u2713 Auto-detected project configuration\n"));
|
|
23973
24226
|
const { mainCommandHandler: mainCommandHandler3 } = await Promise.resolve().then(() => (init_main(), main_exports));
|
|
23974
24227
|
await mainCommandHandler3([], allOptions2, command);
|
|
@@ -24125,6 +24378,17 @@ async function main() {
|
|
|
24125
24378
|
console.error("[DEBUG] Service auto-update failed:", error instanceof Error ? error.message : String(error));
|
|
24126
24379
|
}
|
|
24127
24380
|
}
|
|
24381
|
+
try {
|
|
24382
|
+
const { ScriptInstaller: ScriptInstaller2 } = await Promise.resolve().then(() => (init_script_installer(), script_installer_exports));
|
|
24383
|
+
const installed = await ScriptInstaller2.autoInstallMissing(process.cwd(), true);
|
|
24384
|
+
if (installed && (process.argv.includes("--verbose") || process.argv.includes("-v") || process.env.JUNO_CODE_DEBUG === "1")) {
|
|
24385
|
+
console.error("[DEBUG] Project scripts auto-installed to .juno_task/scripts/");
|
|
24386
|
+
}
|
|
24387
|
+
} catch (error) {
|
|
24388
|
+
if (process.env.JUNO_CODE_DEBUG === "1") {
|
|
24389
|
+
console.error("[DEBUG] Script auto-install failed:", error instanceof Error ? error.message : String(error));
|
|
24390
|
+
}
|
|
24391
|
+
}
|
|
24128
24392
|
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
24393
|
setupGlobalOptions(program);
|
|
24130
24394
|
const isVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");
|
|
@@ -24132,10 +24396,10 @@ async function main() {
|
|
|
24132
24396
|
const isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V");
|
|
24133
24397
|
const hasNoArguments = process.argv.length <= 2;
|
|
24134
24398
|
const isInitCommand = process.argv.includes("init");
|
|
24135
|
-
const
|
|
24136
|
-
const
|
|
24137
|
-
const junoTaskDir =
|
|
24138
|
-
const isInitialized = await
|
|
24399
|
+
const fs22 = await import('fs-extra');
|
|
24400
|
+
const path24 = await import('path');
|
|
24401
|
+
const junoTaskDir = path24.join(process.cwd(), ".juno_task");
|
|
24402
|
+
const isInitialized = await fs22.pathExists(junoTaskDir);
|
|
24139
24403
|
if (!isHelpOrVersion && !hasNoArguments && !isInitCommand && isInitialized) {
|
|
24140
24404
|
try {
|
|
24141
24405
|
const { validateStartupConfigs: validateStartupConfigs2 } = await Promise.resolve().then(() => (init_startup_validation(), startup_validation_exports));
|