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/dist/bin/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var fs2 = require('fs-extra');
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 fs2__default = /*#__PURE__*/_interopDefault(fs2);
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, path23) {
182
- super(path23 ? `${message}: ${path23}` : message);
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 (fs2__default.default.existsSync(packageJsonPath)) {
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 (fs2__default.default.existsSync(packageJsonPath)) {
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 fs2__default.default.pathExists(this.VERSION_FILE);
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 fs2__default.default.readFile(this.VERSION_FILE, "utf-8");
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 fs2__default.default.writeFile(this.VERSION_FILE, version3, "utf-8");
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 fs2__default.default.pathExists(this.SERVICES_DIR);
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 installedCodex = path3__namespace.join(this.SERVICES_DIR, "codex.py");
409
- const installedClaude = path3__namespace.join(this.SERVICES_DIR, "claude.py");
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 packageCodex = path3__namespace.join(packageServicesDir, "codex.py");
418
- const packageClaude = path3__namespace.join(packageServicesDir, "claude.py");
419
- const packageCodexExists = await fs2__default.default.pathExists(packageCodex);
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
- if (packageClaudeExists) {
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
- fs2__default.default.readFile(packageClaude, "utf-8"),
433
- fs2__default.default.readFile(installedClaude, "utf-8")
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
- let servicesPath = path3__namespace.join(__dirname2, "..", "..", "templates", "services");
458
- if (fs2__default.default.existsSync(servicesPath)) {
459
- return servicesPath;
460
- }
461
- servicesPath = path3__namespace.join(__dirname2, "..", "templates", "services");
462
- if (fs2__default.default.existsSync(servicesPath)) {
463
- return servicesPath;
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("Could not find services directory in package");
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 fs2__default.default.ensureDir(this.SERVICES_DIR);
505
+ await fs3__default.default.ensureDir(this.SERVICES_DIR);
474
506
  const packageServicesDir = this.getPackageServicesDir();
475
- await fs2__default.default.copy(packageServicesDir, this.SERVICES_DIR, {
507
+ await fs3__default.default.copy(packageServicesDir, this.SERVICES_DIR, {
476
508
  overwrite: true,
477
509
  preserveTimestamps: true
478
510
  });
479
- const files = await fs2__default.default.readdir(this.SERVICES_DIR);
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 fs2__default.default.stat(filePath);
518
+ const stat = await fs3__default.default.stat(filePath);
483
519
  if (stat.isFile() && (file.endsWith(".py") || file.endsWith(".sh"))) {
484
- await fs2__default.default.chmod(filePath, 493);
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 fs2__default.default.pathExists(this.SERVICES_DIR);
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 fs2__default.default.readdir(this.SERVICES_DIR);
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 fs2__default.default.pathExists(this.SERVICES_DIR);
594
+ const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
559
595
  if (!exists) {
560
596
  return [];
561
597
  }
562
- const files = await fs2__default.default.readdir(this.SERVICES_DIR);
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 fs2__default.default.pathExists(this.SERVICES_DIR);
609
+ const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
574
610
  if (exists) {
575
- await fs2__default.default.remove(this.SERVICES_DIR);
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 fs2__default.default.ensureDir(configDir);
1152
- const configExists = await fs2__default.default.pathExists(configPath);
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 fs2__default.default.writeJson(configPath, defaultConfig, { spaces: 2 });
1195
+ await fs3__default.default.writeJson(configPath, defaultConfig, { spaces: 2 });
1160
1196
  } else {
1161
- const existingConfig = await fs2__default.default.readJson(configPath);
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 fs2__default.default.writeJson(configPath, existingConfig, { spaces: 2 });
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 fs21 = await import('fs-extra');
1798
- if (!await fs21.pathExists(options.cwd)) {
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 fs2__default.default.readFile(configPath, "utf-8");
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 fs2__default.default.pathExists(configPath)) {
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 fs2__default.default.ensureDir(this.logDirectory);
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 fs2__default.default.writeFile(this.logFilePath, header);
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 fs2__default.default.appendFile(this.logFilePath, message);
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 fs2__default.default.ensureDir(logDir);
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 fs2__default.default.appendFile(this.logFilePath, logEntry, "utf-8");
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 || config.defaultMaxIterations,
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 fs2__default.default.pathExists(defaultPromptPath)) {
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 fs2__default.default.pathExists(resolvedPath);
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 fs2__default.default.readFile(resolvedPath, "utf-8");
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 fs2__default.default.pathExists(filePath);
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 fs2__default.default.access(filePath, fs2__default.default.constants.R_OK);
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 fs2__default.default.readFile(filePath, "utf8");
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 fs2__default.default.ensureDir(logDir);
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 fs2__default.default.writeFile(logFile, logContent.join("\n"));
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 fs2__default.default.ensureDir(targetDirectory);
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 fs2__default.default.pathExists(targetPath);
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 fs2__default.default.copy(targetPath, backupPath);
15745
+ await fs3__default.default.copy(targetPath, backupPath);
15355
15746
  }
15356
- await fs2__default.default.ensureDir(path3__namespace.dirname(targetPath));
15357
- await fs2__default.default.writeFile(targetPath, renderedContent, "utf8");
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 fs2__default.default.pathExists(junoTaskPath)) {
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 fs2__default.default.ensureDir(targetDirectory);
16057
+ await fs3__default.default.ensureDir(targetDirectory);
15667
16058
  const junoTaskDir = path3__namespace.join(targetDirectory, ".juno_task");
15668
- const junoTaskExists = await fs2__default.default.pathExists(junoTaskDir);
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 fs2__default.default.ensureDir(junoTaskDir);
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 fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "prompt.md"), promptContent);
15710
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "init.md"), initContent);
15711
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "implement.md"), implementContent);
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 fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
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 fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
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 fs2__default.default.ensureDir(specsDir);
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 fs2__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
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 fs2__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
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 fs2__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
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 fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
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 fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
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 fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
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 fs2__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
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 fs2__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
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 fs2__default.default.ensureDir(scriptsDir);
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 fs2__default.default.pathExists(templatesScriptsDir)) {
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 fs2__default.default.readdir(templatesScriptsDir);
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 fs2__default.default.stat(sourcePath);
16642
+ const stats = await fs3__default.default.stat(sourcePath);
16252
16643
  if (stats.isFile()) {
16253
- await fs2__default.default.copy(sourcePath, destPath);
16644
+ await fs3__default.default.copy(sourcePath, destPath);
16254
16645
  if (scriptFile.endsWith(".sh")) {
16255
- await fs2__default.default.chmod(destPath, 493);
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 fs2__default.default.pathExists(installScript)) {
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 fs2__default.default.pathExists(junoTaskDir)) {
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 fs2__default.default.pathExists(initFile)) {
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 fs2__default.default.readFile(initFile, "utf-8");
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 fs2__default.default.ensureDir(path3__namespace.dirname(testFilePath));
17621
- await fs2__default.default.writeFile(testFilePath, testContent);
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 fs2__default.default.pathExists(coverageFile)) {
17874
- const coverageData = await fs2__default.default.readJson(coverageFile);
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 fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18058
- await fs2__default.default.writeJson(outputPath, report, { spaces: 2 });
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 fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18122
- await fs2__default.default.writeFile(outputPath, html);
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 fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18180
- await fs2__default.default.writeFile(outputPath, markdown);
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 fs2__default.default.readFile(filePath, "utf-8");
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 dirname12 = path3__namespace.dirname(filePath);
18528
- backupPath = path3__namespace.join(dirname12, `${basename11}.backup.${timestamp}${ext}`);
18529
- await fs2__default.default.writeFile(backupPath, originalContent, "utf-8");
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 fs2__default.default.writeFile(filePath, finalContent, "utf-8");
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 fs2__default.default.stat(filePath);
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 fs2__default.default.pathExists(feedbackFile)) {
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 fs2__default.default.readFile(feedbackFile, "utf-8");
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 fs2__default.default.ensureDir(path3__namespace.dirname(logFile));
19097
+ await fs3__default.default.ensureDir(path3__namespace.dirname(logFile));
18707
19098
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
18708
- await fs2__default.default.appendFile(logFile, `[${timestamp}] ${warning}
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 fs2__default.default.ensureDir(archiveDir);
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 fs2__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
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 fs2__default.default.pathExists(archiveFile)) {
18776
- archiveContent = await fs2__default.default.readFile(archiveFile, "utf-8");
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 fs2__default.default.writeFile(archiveFile, archiveContent, "utf-8");
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 fs2__default.default.pathExists(feedbackFile)) {
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 fs2__default.default.readFile(feedbackFile, "utf-8");
18843
- const stats = await fs2__default.default.stat(feedbackFile);
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 fs2__default.default.pathExists(this.feedbackFile)) {
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 fs2__default.default.readFile(this.feedbackFile, "utf-8");
19315
+ const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
18925
19316
  const updatedContent = this.addIssueToContent(content, issue, testCriteria);
18926
- await fs2__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
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 fs2__default.default.readFile(this.feedbackFile, "utf-8");
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 fs2__default.default.writeFile(backupPath, content, "utf-8");
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 fs2__default.default.ensureDir(path3__namespace.dirname(this.feedbackFile));
18977
- await fs2__default.default.writeFile(this.feedbackFile, initialContent, "utf-8");
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 fs2__default.default.pathExists(resolvedPath)) {
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 fs2__default.default.pathExists(defaultClaudeFile)) {
19491
+ if (await fs3__default.default.pathExists(defaultClaudeFile)) {
19101
19492
  filesToCompact.push(defaultClaudeFile);
19102
19493
  }
19103
- if (await fs2__default.default.pathExists(defaultAgentsFile)) {
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 fs2__default.default.pathExists(configPath)) {
20428
+ if (!await fs3__default.default.pathExists(configPath)) {
20038
20429
  return;
20039
20430
  }
20040
20431
  try {
20041
- let content = await fs2__default.default.readFile(configPath, "utf-8");
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 fs2__default.default.writeFile(configPath, content, "utf-8");
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 fs21 = await import('fs-extra');
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 fs21.writeFile(filepath, JSON.stringify(exportData, null, 2));
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 fs2__default.default.pathExists(configPath)) {
23216
+ if (!await fs3__default.default.pathExists(configPath)) {
22826
23217
  return false;
22827
23218
  }
22828
- const content = await fs2__default.default.readFile(configPath, "utf-8");
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 fs2__default.default.pathExists(shell.completionPath);
22851
- const configExists = await fs2__default.default.pathExists(shell.configPath);
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 fs2__default.default.stat(shell.completionPath);
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 fs2__default.default.ensureDir(completionDir);
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 fs2__default.default.ensureDir(configDir);
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 fs2__default.default.access(configDir, fs2__default.default.constants.W_OK);
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 fs2__default.default.ensureDir(completionDir);
22924
- await fs2__default.default.access(completionDir, fs2__default.default.constants.W_OK);
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 fs2__default.default.pathExists(sessionDir)) {
23386
+ if (!await fs3__default.default.pathExists(sessionDir)) {
22996
23387
  return [];
22997
23388
  }
22998
- const sessions = await fs2__default.default.readdir(sessionDir);
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 fs2__default.default.pathExists(customTemplatesDir)) {
23013
- const files = await fs2__default.default.readdir(customTemplatesDir);
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 fs2__default.default.writeFile(completionPath, script, "utf-8");
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 fs2__default.default.appendFile(configPath, `
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 fs2__default.default.pathExists(completionPath)) {
23130
- await fs2__default.default.remove(completionPath);
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 fs2__default.default.pathExists(completionPath);
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 fs21 = await import('fs-extra');
23946
- const path23 = await import('path');
24336
+ const fs22 = await import('fs-extra');
24337
+ const path24 = await import('path');
23947
24338
  const cwd2 = process.cwd();
23948
- const junoTaskDir = path23.join(cwd2, ".juno_task");
23949
- if (await fs21.pathExists(junoTaskDir)) {
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 = path23.join(junoTaskDir, "prompt.md");
23967
- if (!allOptions2.prompt && await fs21.pathExists(promptFile)) {
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 fs21.pathExists(promptFile))) {
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 fs21 = await import('fs-extra');
24136
- const path23 = await import('path');
24137
- const junoTaskDir = path23.join(process.cwd(), ".juno_task");
24138
- const isInitialized = await fs21.pathExists(junoTaskDir);
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));