juno-code 1.0.34 → 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/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",
@@ -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 (fs2__default.default.existsSync(packageJsonPath)) {
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 (fs2__default.default.existsSync(packageJsonPath)) {
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 fs2__default.default.pathExists(this.VERSION_FILE);
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 fs2__default.default.readFile(this.VERSION_FILE, "utf-8");
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 fs2__default.default.writeFile(this.VERSION_FILE, version3, "utf-8");
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 fs2__default.default.pathExists(this.SERVICES_DIR);
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 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) {
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 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
- }
427
+ const missingPackageScripts = this.missingScripts(packageServicesDir);
428
+ if (missingPackageScripts.length > 0) {
429
+ throw new Error(`Missing required service scripts: ${missingPackageScripts.join(", ")}`);
429
430
  }
430
- if (packageClaudeExists) {
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
- fs2__default.default.readFile(packageClaude, "utf-8"),
433
- fs2__default.default.readFile(installedClaude, "utf-8")
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
- 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;
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("Could not find services directory in package");
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 fs2__default.default.ensureDir(this.SERVICES_DIR);
488
+ await fs3__default.default.ensureDir(this.SERVICES_DIR);
474
489
  const packageServicesDir = this.getPackageServicesDir();
475
- await fs2__default.default.copy(packageServicesDir, this.SERVICES_DIR, {
490
+ await fs3__default.default.copy(packageServicesDir, this.SERVICES_DIR, {
476
491
  overwrite: true,
477
492
  preserveTimestamps: true
478
493
  });
479
- const files = await fs2__default.default.readdir(this.SERVICES_DIR);
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 fs2__default.default.stat(filePath);
501
+ const stat = await fs3__default.default.stat(filePath);
483
502
  if (stat.isFile() && (file.endsWith(".py") || file.endsWith(".sh"))) {
484
- await fs2__default.default.chmod(filePath, 493);
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 fs2__default.default.pathExists(this.SERVICES_DIR);
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 fs2__default.default.readdir(this.SERVICES_DIR);
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 fs2__default.default.pathExists(this.SERVICES_DIR);
577
+ const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
559
578
  if (!exists) {
560
579
  return [];
561
580
  }
562
- const files = await fs2__default.default.readdir(this.SERVICES_DIR);
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 fs2__default.default.pathExists(this.SERVICES_DIR);
592
+ const exists = await fs3__default.default.pathExists(this.SERVICES_DIR);
574
593
  if (exists) {
575
- await fs2__default.default.remove(this.SERVICES_DIR);
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 fs2__default.default.ensureDir(configDir);
1152
- const configExists = await fs2__default.default.pathExists(configPath);
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 fs2__default.default.writeJson(configPath, defaultConfig, { spaces: 2 });
1178
+ await fs3__default.default.writeJson(configPath, defaultConfig, { spaces: 2 });
1160
1179
  } else {
1161
- const existingConfig = await fs2__default.default.readJson(configPath);
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 fs2__default.default.writeJson(configPath, existingConfig, { spaces: 2 });
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 fs21 = await import('fs-extra');
1798
- if (!await fs21.pathExists(options.cwd)) {
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 fs2__default.default.readFile(configPath, "utf-8");
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 fs2__default.default.pathExists(configPath)) {
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 fs2__default.default.ensureDir(this.logDirectory);
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 fs2__default.default.writeFile(this.logFilePath, header);
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 fs2__default.default.appendFile(this.logFilePath, message);
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 fs2__default.default.ensureDir(logDir);
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 fs2__default.default.appendFile(this.logFilePath, logEntry, "utf-8");
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
  }
@@ -7470,7 +7502,7 @@ var init_shell_backend = __esm({
7470
7502
  * Strategy:
7471
7503
  * 1. Try to parse each line as JSON first (for Claude)
7472
7504
  * 2. If JSON parsing fails, treat as TEXT streaming (for Codex and other text-based subagents)
7473
- * 3. Emit all non-empty lines as progress events for real-time display
7505
+ * 3. Emit all text lines (including whitespace-only) as progress events for real-time display
7474
7506
  */
7475
7507
  parseAndEmitStreamingEvents(data, sessionId) {
7476
7508
  if (!this.jsonBuffer) {
@@ -7480,14 +7512,35 @@ var init_shell_backend = __esm({
7480
7512
  const lines = this.jsonBuffer.split("\n");
7481
7513
  this.jsonBuffer = lines.pop() || "";
7482
7514
  for (const line of lines) {
7483
- const trimmedLine = line.trim();
7484
- if (!trimmedLine) continue;
7515
+ const rawLine = line.endsWith("\r") ? line.slice(0, -1) : line;
7516
+ if (!rawLine) continue;
7517
+ const hasNonWhitespace = rawLine.trim().length > 0;
7518
+ if (!hasNonWhitespace) {
7519
+ this.emitProgressEvent({
7520
+ sessionId,
7521
+ timestamp: /* @__PURE__ */ new Date(),
7522
+ backend: "shell",
7523
+ count: ++this.eventCounter,
7524
+ type: "thinking",
7525
+ content: rawLine,
7526
+ metadata: {
7527
+ format: "text",
7528
+ raw: true
7529
+ }
7530
+ }).catch((error) => {
7531
+ if (this.config?.debug) {
7532
+ engineLogger.warn(`Failed to emit whitespace-only streaming event: ${error instanceof Error ? error.message : String(error)}`);
7533
+ }
7534
+ });
7535
+ continue;
7536
+ }
7537
+ const trimmedLine = rawLine.trim();
7485
7538
  let isJsonParsed = false;
7486
7539
  try {
7487
7540
  const jsonEvent = JSON.parse(trimmedLine);
7488
7541
  let progressEvent;
7489
7542
  if (this.isClaudeCliEvent(jsonEvent)) {
7490
- progressEvent = this.convertClaudeEventToProgress(jsonEvent, sessionId, trimmedLine);
7543
+ progressEvent = this.convertClaudeEventToProgress(jsonEvent, sessionId, rawLine);
7491
7544
  isJsonParsed = true;
7492
7545
  } else if (this.isGenericStreamingEvent(jsonEvent)) {
7493
7546
  progressEvent = {
@@ -7522,7 +7575,7 @@ var init_shell_backend = __esm({
7522
7575
  backend: "shell",
7523
7576
  count: ++this.eventCounter,
7524
7577
  type: "thinking",
7525
- content: trimmedLine,
7578
+ content: rawLine,
7526
7579
  metadata: {
7527
7580
  format: "text",
7528
7581
  raw: true
@@ -12789,12 +12842,18 @@ async function mainCommandHandler(args, options, command) {
12789
12842
  console.error(chalk15__default.default.red("\n\u274C Error: --allowed-tools and --append-allowed-tools are mutually exclusive. Use one or the other."));
12790
12843
  process.exit(1);
12791
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
+ }
12792
12851
  const executionRequest = createExecutionRequest({
12793
12852
  instruction,
12794
12853
  subagent: options.subagent,
12795
12854
  backend: selectedBackend,
12796
12855
  workingDirectory: config.workingDirectory,
12797
- maxIterations: options.maxIterations || config.defaultMaxIterations,
12856
+ maxIterations: options.maxIterations ?? config.defaultMaxIterations,
12798
12857
  model: options.model || config.defaultModel,
12799
12858
  agents: options.agents,
12800
12859
  tools: options.tools,
@@ -12959,7 +13018,7 @@ var init_main = __esm({
12959
13018
  return await this.collectInteractivePrompt();
12960
13019
  } else {
12961
13020
  const defaultPromptPath = path3__namespace.join(process.cwd(), ".juno_task", "prompt.md");
12962
- if (await fs2__default.default.pathExists(defaultPromptPath)) {
13021
+ if (await fs3__default.default.pathExists(defaultPromptPath)) {
12963
13022
  console.error(chalk15__default.default.blue(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
12964
13023
  return await this.loadPromptFromFile(defaultPromptPath);
12965
13024
  } else {
@@ -12987,7 +13046,7 @@ var init_main = __esm({
12987
13046
  }
12988
13047
  try {
12989
13048
  const resolvedPath = path3__namespace.resolve(prompt);
12990
- return await fs2__default.default.pathExists(resolvedPath);
13049
+ return await fs3__default.default.pathExists(resolvedPath);
12991
13050
  } catch {
12992
13051
  return false;
12993
13052
  }
@@ -12995,7 +13054,7 @@ var init_main = __esm({
12995
13054
  async loadPromptFromFile(filePath) {
12996
13055
  try {
12997
13056
  const resolvedPath = path3__namespace.resolve(filePath);
12998
- const content = await fs2__default.default.readFile(resolvedPath, "utf-8");
13057
+ const content = await fs3__default.default.readFile(resolvedPath, "utf-8");
12999
13058
  if (!content.trim()) {
13000
13059
  throw new FileSystemError(
13001
13060
  "Prompt file is empty",
@@ -13317,6 +13376,221 @@ var init_main = __esm({
13317
13376
  }
13318
13377
  });
13319
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
+
13320
13594
  // src/utils/startup-validation.ts
13321
13595
  var startup_validation_exports = {};
13322
13596
  __export(startup_validation_exports, {
@@ -13407,7 +13681,7 @@ async function validateJSONFile(configSchema, baseDir) {
13407
13681
  const warnings = [];
13408
13682
  const filePath = path3__namespace.default.join(baseDir, configSchema.file);
13409
13683
  try {
13410
- const exists = await fs2__default.default.pathExists(filePath);
13684
+ const exists = await fs3__default.default.pathExists(filePath);
13411
13685
  if (!exists) {
13412
13686
  if (configSchema.required) {
13413
13687
  errors.push({
@@ -13430,7 +13704,7 @@ async function validateJSONFile(configSchema, baseDir) {
13430
13704
  return { isValid: !configSchema.required, errors, warnings };
13431
13705
  }
13432
13706
  try {
13433
- await fs2__default.default.access(filePath, fs2__default.default.constants.R_OK);
13707
+ await fs3__default.default.access(filePath, fs3__default.default.constants.R_OK);
13434
13708
  } catch (accessError) {
13435
13709
  errors.push({
13436
13710
  file: configSchema.file,
@@ -13446,7 +13720,7 @@ async function validateJSONFile(configSchema, baseDir) {
13446
13720
  }
13447
13721
  let jsonData;
13448
13722
  try {
13449
- const fileContent = await fs2__default.default.readFile(filePath, "utf8");
13723
+ const fileContent = await fs3__default.default.readFile(filePath, "utf8");
13450
13724
  jsonData = JSON.parse(fileContent);
13451
13725
  } catch (parseError) {
13452
13726
  const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
@@ -13581,7 +13855,7 @@ function displayValidationResults(result) {
13581
13855
  }
13582
13856
  async function logValidationResults(result, baseDir = process.cwd()) {
13583
13857
  const logDir = path3__namespace.default.join(baseDir, ".juno_task", "logs");
13584
- await fs2__default.default.ensureDir(logDir);
13858
+ await fs3__default.default.ensureDir(logDir);
13585
13859
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13586
13860
  const logFile = path3__namespace.default.join(logDir, `startup-validation-${timestamp}.log`);
13587
13861
  const logContent = [
@@ -13624,7 +13898,7 @@ async function logValidationResults(result, baseDir = process.cwd()) {
13624
13898
  logContent.push(``);
13625
13899
  }
13626
13900
  }
13627
- await fs2__default.default.writeFile(logFile, logContent.join("\n"));
13901
+ await fs3__default.default.writeFile(logFile, logContent.join("\n"));
13628
13902
  return logFile;
13629
13903
  }
13630
13904
  async function validateStartupConfigs(baseDir = process.cwd(), verbose = false) {
@@ -13958,7 +14232,7 @@ var TemplateEngine = class {
13958
14232
  let overallError;
13959
14233
  try {
13960
14234
  if (!options.dryRun) {
13961
- await fs2__default.default.ensureDir(targetDirectory);
14235
+ await fs3__default.default.ensureDir(targetDirectory);
13962
14236
  }
13963
14237
  for (const template of templates) {
13964
14238
  try {
@@ -15308,7 +15582,7 @@ This directory contains specification documents for your project.
15308
15582
  const fileName = this.getTemplateFileName(template);
15309
15583
  const targetPath = path3__namespace.join(targetDirectory, fileName);
15310
15584
  try {
15311
- const fileExists = await fs2__default.default.pathExists(targetPath);
15585
+ const fileExists = await fs3__default.default.pathExists(targetPath);
15312
15586
  if (fileExists && !options.force && options.onConflict !== "overwrite") {
15313
15587
  return {
15314
15588
  path: targetPath,
@@ -15330,10 +15604,10 @@ This directory contains specification documents for your project.
15330
15604
  }
15331
15605
  if (options.createBackup && fileExists) {
15332
15606
  const backupPath = `${targetPath}.backup.${Date.now()}`;
15333
- await fs2__default.default.copy(targetPath, backupPath);
15607
+ await fs3__default.default.copy(targetPath, backupPath);
15334
15608
  }
15335
- await fs2__default.default.ensureDir(path3__namespace.dirname(targetPath));
15336
- await fs2__default.default.writeFile(targetPath, renderedContent, "utf8");
15609
+ await fs3__default.default.ensureDir(path3__namespace.dirname(targetPath));
15610
+ await fs3__default.default.writeFile(targetPath, renderedContent, "utf8");
15337
15611
  return {
15338
15612
  path: targetPath,
15339
15613
  content: renderedContent,
@@ -15597,7 +15871,7 @@ var SimpleInitTUI = class {
15597
15871
  }
15598
15872
  async confirmSave(targetDirectory) {
15599
15873
  const junoTaskPath = path3__namespace.join(targetDirectory, ".juno_task");
15600
- if (await fs2__default.default.pathExists(junoTaskPath)) {
15874
+ if (await fs3__default.default.pathExists(junoTaskPath)) {
15601
15875
  console.log(chalk15__default.default.yellow(" \u26A0\uFE0F .juno_task directory already exists"));
15602
15876
  console.log(chalk15__default.default.gray(" Would you like to:"));
15603
15877
  console.log(chalk15__default.default.gray(" 1) Override existing files"));
@@ -15642,16 +15916,16 @@ var SimpleProjectGenerator = class {
15642
15916
  async generate() {
15643
15917
  const { targetDirectory, variables, force } = this.context;
15644
15918
  console.log(chalk15__default.default.blue("\u{1F4C1} Creating project directory..."));
15645
- await fs2__default.default.ensureDir(targetDirectory);
15919
+ await fs3__default.default.ensureDir(targetDirectory);
15646
15920
  const junoTaskDir = path3__namespace.join(targetDirectory, ".juno_task");
15647
- const junoTaskExists = await fs2__default.default.pathExists(junoTaskDir);
15921
+ const junoTaskExists = await fs3__default.default.pathExists(junoTaskDir);
15648
15922
  if (junoTaskExists && !force) {
15649
15923
  throw new ValidationError(
15650
15924
  "Project already initialized. Directory .juno_task already exists.",
15651
15925
  ["Use --force flag to overwrite existing files", "Choose a different directory"]
15652
15926
  );
15653
15927
  }
15654
- await fs2__default.default.ensureDir(junoTaskDir);
15928
+ await fs3__default.default.ensureDir(junoTaskDir);
15655
15929
  console.log(chalk15__default.default.blue("\u2699\uFE0F Creating project configuration..."));
15656
15930
  await this.createConfigFile(junoTaskDir, targetDirectory);
15657
15931
  console.log(chalk15__default.default.blue("\u{1F527} Setting up MCP configuration..."));
@@ -15685,21 +15959,21 @@ var SimpleProjectGenerator = class {
15685
15959
  const promptContent = await templateEngine.render(promptTemplate, templateContext);
15686
15960
  const initContent = await templateEngine.render(initTemplate, templateContext);
15687
15961
  const implementContent = await templateEngine.render(implementTemplate, templateContext);
15688
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "prompt.md"), promptContent);
15689
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "init.md"), initContent);
15690
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "implement.md"), implementContent);
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);
15691
15965
  const userFeedbackTemplate = templateEngine.getBuiltInTemplate("USER_FEEDBACK.md");
15692
15966
  if (userFeedbackTemplate) {
15693
15967
  const userFeedbackContent = await templateEngine.render(userFeedbackTemplate, templateContext);
15694
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
15968
+ await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "USER_FEEDBACK.md"), userFeedbackContent);
15695
15969
  }
15696
15970
  const planTemplate = templateEngine.getBuiltInTemplate("plan.md");
15697
15971
  if (planTemplate) {
15698
15972
  const planContent = await templateEngine.render(planTemplate, templateContext);
15699
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
15973
+ await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
15700
15974
  }
15701
15975
  const specsDir = path3__namespace.join(junoTaskDir, "specs");
15702
- await fs2__default.default.ensureDir(specsDir);
15976
+ await fs3__default.default.ensureDir(specsDir);
15703
15977
  const specsReadmeContent = `# Project Specifications
15704
15978
 
15705
15979
  This directory contains detailed specifications for the project components.
@@ -15716,7 +15990,7 @@ This directory contains detailed specifications for the project components.
15716
15990
  - Avoid conflicts with existing file names
15717
15991
  - Use \`.md\` extension for all specification files
15718
15992
  `;
15719
- await fs2__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
15993
+ await fs3__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
15720
15994
  const requirementsContent = `# Requirements Specification
15721
15995
 
15722
15996
  ## Functional Requirements
@@ -15763,7 +16037,7 @@ This directory contains detailed specifications for the project components.
15763
16037
  - Code quality: Clean, maintainable codebase
15764
16038
  - Documentation: Complete and accurate documentation
15765
16039
  `;
15766
- await fs2__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
16040
+ await fs3__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
15767
16041
  const architectureContent = `# Architecture Specification
15768
16042
 
15769
16043
  ## System Overview
@@ -15845,7 +16119,7 @@ This project uses AI-assisted development with juno-code to achieve: ${variables
15845
16119
  - Performance monitoring
15846
16120
  - Security best practices
15847
16121
  `;
15848
- await fs2__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
16122
+ await fs3__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
15849
16123
  const claudeContent = `# Claude Development Session Learnings
15850
16124
 
15851
16125
  ## Project Overview
@@ -15917,7 +16191,7 @@ This file will be updated as development progresses to track:
15917
16191
  - Solutions to complex problems
15918
16192
  - Performance improvements and optimizations
15919
16193
  `;
15920
- await fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
16194
+ await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
15921
16195
  const agentsContent = `# AI Agent Selection and Performance
15922
16196
 
15923
16197
  ## Available Agents
@@ -15981,7 +16255,7 @@ Track agent performance for:
15981
16255
  4. **Feedback Loop**: Provide feedback to improve agent performance
15982
16256
  5. **Performance Monitoring**: Track and optimize agent usage
15983
16257
  `;
15984
- await fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
16258
+ await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
15985
16259
  const readmeContent = `# ${variables.PROJECT_NAME}
15986
16260
 
15987
16261
  ${variables.DESCRIPTION}
@@ -16078,7 +16352,7 @@ ${variables.GIT_URL}` : ""}
16078
16352
  Created with juno-code on ${variables.CURRENT_DATE}
16079
16353
  ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16080
16354
  `;
16081
- await fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
16355
+ await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
16082
16356
  console.log(chalk15__default.default.blue("\u{1F4E6} Installing utility scripts..."));
16083
16357
  await this.copyScriptsFromTemplates(junoTaskDir);
16084
16358
  console.log(chalk15__default.default.blue("\u{1F40D} Installing Python requirements..."));
@@ -16130,7 +16404,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16130
16404
  hooks: getDefaultHooks()
16131
16405
  };
16132
16406
  const configPath = path3__namespace.join(junoTaskDir, "config.json");
16133
- await fs2__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
16407
+ await fs3__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
16134
16408
  console.log(chalk15__default.default.green(` \u2713 Created .juno_task/config.json with ${this.context.subagent} as default subagent`));
16135
16409
  }
16136
16410
  async createMcpFile(junoTaskDir, targetDirectory) {
@@ -16184,7 +16458,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16184
16458
  }
16185
16459
  };
16186
16460
  const mcpPath = path3__namespace.join(junoTaskDir, "mcp.json");
16187
- await fs2__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
16461
+ await fs3__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
16188
16462
  console.log(chalk15__default.default.green(` \u2713 Created .juno_task/mcp.json with roundtable-ai server configuration`));
16189
16463
  }
16190
16464
  getDefaultModelForSubagent(subagent) {
@@ -16203,7 +16477,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16203
16477
  async copyScriptsFromTemplates(junoTaskDir) {
16204
16478
  try {
16205
16479
  const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
16206
- await fs2__default.default.ensureDir(scriptsDir);
16480
+ await fs3__default.default.ensureDir(scriptsDir);
16207
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)));
16208
16482
  const __dirname2 = path3__namespace.dirname(__filename2);
16209
16483
  let templatesScriptsDir;
@@ -16214,11 +16488,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16214
16488
  } else {
16215
16489
  templatesScriptsDir = path3__namespace.join(__dirname2, "../../templates/scripts");
16216
16490
  }
16217
- if (!await fs2__default.default.pathExists(templatesScriptsDir)) {
16491
+ if (!await fs3__default.default.pathExists(templatesScriptsDir)) {
16218
16492
  console.log(chalk15__default.default.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
16219
16493
  return;
16220
16494
  }
16221
- const scriptFiles = await fs2__default.default.readdir(templatesScriptsDir);
16495
+ const scriptFiles = await fs3__default.default.readdir(templatesScriptsDir);
16222
16496
  if (scriptFiles.length === 0) {
16223
16497
  console.log(chalk15__default.default.gray(" \u2139\uFE0F No template scripts found to install"));
16224
16498
  return;
@@ -16227,11 +16501,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16227
16501
  for (const scriptFile of scriptFiles) {
16228
16502
  const sourcePath = path3__namespace.join(templatesScriptsDir, scriptFile);
16229
16503
  const destPath = path3__namespace.join(scriptsDir, scriptFile);
16230
- const stats = await fs2__default.default.stat(sourcePath);
16504
+ const stats = await fs3__default.default.stat(sourcePath);
16231
16505
  if (stats.isFile()) {
16232
- await fs2__default.default.copy(sourcePath, destPath);
16506
+ await fs3__default.default.copy(sourcePath, destPath);
16233
16507
  if (scriptFile.endsWith(".sh")) {
16234
- await fs2__default.default.chmod(destPath, 493);
16508
+ await fs3__default.default.chmod(destPath, 493);
16235
16509
  }
16236
16510
  copiedCount++;
16237
16511
  console.log(chalk15__default.default.green(` \u2713 Installed script: ${scriptFile}`));
@@ -16254,7 +16528,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16254
16528
  try {
16255
16529
  const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
16256
16530
  const installScript = path3__namespace.join(scriptsDir, "install_requirements.sh");
16257
- if (!await fs2__default.default.pathExists(installScript)) {
16531
+ if (!await fs3__default.default.pathExists(installScript)) {
16258
16532
  console.log(chalk15__default.default.yellow(" \u26A0\uFE0F install_requirements.sh not found, skipping Python dependencies installation"));
16259
16533
  console.log(chalk15__default.default.gray(" You can install dependencies manually: juno-kanban, roundtable-ai"));
16260
16534
  return;
@@ -16551,20 +16825,20 @@ init_types();
16551
16825
  async function loadInitPrompt(directory) {
16552
16826
  const junoTaskDir = path3__namespace.join(directory, ".juno_task");
16553
16827
  const initFile = path3__namespace.join(junoTaskDir, "init.md");
16554
- if (!await fs2__default.default.pathExists(junoTaskDir)) {
16828
+ if (!await fs3__default.default.pathExists(junoTaskDir)) {
16555
16829
  throw new FileSystemError(
16556
16830
  'No .juno_task directory found. Run "juno-code init" first.',
16557
16831
  junoTaskDir
16558
16832
  );
16559
16833
  }
16560
- if (!await fs2__default.default.pathExists(initFile)) {
16834
+ if (!await fs3__default.default.pathExists(initFile)) {
16561
16835
  throw new FileSystemError(
16562
16836
  "No init.md file found in .juno_task directory",
16563
16837
  initFile
16564
16838
  );
16565
16839
  }
16566
16840
  try {
16567
- const content = await fs2__default.default.readFile(initFile, "utf-8");
16841
+ const content = await fs3__default.default.readFile(initFile, "utf-8");
16568
16842
  if (!content.trim()) {
16569
16843
  throw new FileSystemError(
16570
16844
  "init.md file is empty. Please add task instructions.",
@@ -17596,8 +17870,8 @@ Focus on ${request.intelligence === "basic" ? "basic functionality" : request.in
17596
17870
  for (const scenario of scenarios) {
17597
17871
  const testContent = await this.generateTestContent(request, scenario, template);
17598
17872
  const testFilePath = this.resolveTestFilePath(request, scenario);
17599
- await fs2__default.default.ensureDir(path3__namespace.dirname(testFilePath));
17600
- await fs2__default.default.writeFile(testFilePath, testContent);
17873
+ await fs3__default.default.ensureDir(path3__namespace.dirname(testFilePath));
17874
+ await fs3__default.default.writeFile(testFilePath, testContent);
17601
17875
  testFiles.push(testFilePath);
17602
17876
  }
17603
17877
  return testFiles;
@@ -17849,8 +18123,8 @@ var TestExecutionEngine = class {
17849
18123
  async collectCoverage(request) {
17850
18124
  const coverageFile = path3__namespace.join(request.workingDirectory, "coverage", "coverage-summary.json");
17851
18125
  try {
17852
- if (await fs2__default.default.pathExists(coverageFile)) {
17853
- const coverageData = await fs2__default.default.readJson(coverageFile);
18126
+ if (await fs3__default.default.pathExists(coverageFile)) {
18127
+ const coverageData = await fs3__default.default.readJson(coverageFile);
17854
18128
  return {
17855
18129
  lines: coverageData.total?.lines?.pct || 0,
17856
18130
  functions: coverageData.total?.functions?.pct || 0,
@@ -18033,8 +18307,8 @@ var TestReportEngine = class {
18033
18307
  suggestions: analysis.suggestions,
18034
18308
  recommendations: analysis.recommendations
18035
18309
  };
18036
- await fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18037
- await fs2__default.default.writeJson(outputPath, report, { spaces: 2 });
18310
+ await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
18311
+ await fs3__default.default.writeJson(outputPath, report, { spaces: 2 });
18038
18312
  return outputPath;
18039
18313
  }
18040
18314
  async generateHTMLReport(analysis, outputPath, includeVisualizations) {
@@ -18097,8 +18371,8 @@ var TestReportEngine = class {
18097
18371
  </body>
18098
18372
  </html>
18099
18373
  `.trim();
18100
- await fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18101
- await fs2__default.default.writeFile(outputPath, html);
18374
+ await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
18375
+ await fs3__default.default.writeFile(outputPath, html);
18102
18376
  return outputPath;
18103
18377
  }
18104
18378
  generateCharts(analysis) {
@@ -18155,8 +18429,8 @@ ${analysis.suggestions.map((suggestion) => `- ${suggestion}`).join("\n")}
18155
18429
 
18156
18430
  ${analysis.recommendations.map((rec) => `- ${rec}`).join("\n")}
18157
18431
  `.trim();
18158
- await fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18159
- await fs2__default.default.writeFile(outputPath, markdown);
18432
+ await fs3__default.default.ensureDir(path3__namespace.dirname(outputPath));
18433
+ await fs3__default.default.writeFile(outputPath, markdown);
18160
18434
  return outputPath;
18161
18435
  }
18162
18436
  async displayConsoleReport(analysis) {
@@ -18496,16 +18770,16 @@ async function compactConfigFile(filePath, options = {}) {
18496
18770
  preserveDays = 30,
18497
18771
  preservePatterns = []
18498
18772
  } = options;
18499
- const originalContent = await fs2__default.default.readFile(filePath, "utf-8");
18773
+ const originalContent = await fs3__default.default.readFile(filePath, "utf-8");
18500
18774
  const originalSize = originalContent.length;
18501
18775
  let backupPath = "";
18502
18776
  if (createBackup && !dryRun) {
18503
18777
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
18504
18778
  const ext = path3__namespace.extname(filePath);
18505
18779
  const basename11 = path3__namespace.basename(filePath, ext);
18506
- const dirname12 = path3__namespace.dirname(filePath);
18507
- backupPath = path3__namespace.join(dirname12, `${basename11}.backup.${timestamp}${ext}`);
18508
- await fs2__default.default.writeFile(backupPath, originalContent, "utf-8");
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");
18509
18783
  }
18510
18784
  const compactionAnalysis = analyzeMarkdownStructure(originalContent);
18511
18785
  const compactedContent = compactMarkdownContent(
@@ -18520,7 +18794,7 @@ async function compactConfigFile(filePath, options = {}) {
18520
18794
  const compactedSize = finalContent.length;
18521
18795
  const reductionPercentage = Math.round((originalSize - compactedSize) / originalSize * 100);
18522
18796
  if (!dryRun) {
18523
- await fs2__default.default.writeFile(filePath, finalContent, "utf-8");
18797
+ await fs3__default.default.writeFile(filePath, finalContent, "utf-8");
18524
18798
  }
18525
18799
  return {
18526
18800
  originalSize,
@@ -18650,7 +18924,7 @@ function formatFileSize(bytes) {
18650
18924
  }
18651
18925
  async function shouldCompactFile(filePath, sizeThresholdKB = 50, ageThresholdDays = 30) {
18652
18926
  try {
18653
- const stats = await fs2__default.default.stat(filePath);
18927
+ const stats = await fs3__default.default.stat(filePath);
18654
18928
  const sizeKB = stats.size / 1024;
18655
18929
  if (sizeKB > sizeThresholdKB) {
18656
18930
  return true;
@@ -18672,19 +18946,19 @@ async function archiveResolvedIssues(options) {
18672
18946
  feedbackFile,
18673
18947
  archiveDir = path3__namespace.join(path3__namespace.dirname(feedbackFile), "archives"),
18674
18948
  openIssuesThreshold = 10} = options;
18675
- if (!await fs2__default.default.pathExists(feedbackFile)) {
18949
+ if (!await fs3__default.default.pathExists(feedbackFile)) {
18676
18950
  throw new Error(`Feedback file does not exist: ${feedbackFile}`);
18677
18951
  }
18678
- const content = await fs2__default.default.readFile(feedbackFile, "utf-8");
18952
+ const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
18679
18953
  const parsed = parseUserFeedback(content);
18680
18954
  const warningsGenerated = [];
18681
18955
  if (parsed.openIssues.length > openIssuesThreshold) {
18682
18956
  const warning = `Found ${parsed.openIssues.length} open issues (threshold: ${openIssuesThreshold}). Consider reviewing and prioritizing.`;
18683
18957
  warningsGenerated.push(warning);
18684
18958
  const logFile = path3__namespace.join(path3__namespace.dirname(feedbackFile), "logs", "feedback-warnings.log");
18685
- await fs2__default.default.ensureDir(path3__namespace.dirname(logFile));
18959
+ await fs3__default.default.ensureDir(path3__namespace.dirname(logFile));
18686
18960
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
18687
- await fs2__default.default.appendFile(logFile, `[${timestamp}] ${warning}
18961
+ await fs3__default.default.appendFile(logFile, `[${timestamp}] ${warning}
18688
18962
  `);
18689
18963
  }
18690
18964
  if (parsed.resolvedIssues.length === 0) {
@@ -18701,10 +18975,10 @@ async function archiveResolvedIssues(options) {
18701
18975
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
18702
18976
  const archiveFile = path3__namespace.join(archiveDir, `USER_FEEDBACK_archive_${currentYear}.md`);
18703
18977
  {
18704
- await fs2__default.default.ensureDir(archiveDir);
18978
+ await fs3__default.default.ensureDir(archiveDir);
18705
18979
  await appendToArchive(archiveFile, parsed.resolvedIssues);
18706
18980
  const compactedContent = generateCompactedFeedback(parsed.openIssues, parsed.metadata);
18707
- await fs2__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
18981
+ await fs3__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
18708
18982
  }
18709
18983
  {
18710
18984
  console.log(chalk15__default.default.green(`\u2705 Archived ${parsed.resolvedIssues.length} resolved issues`));
@@ -18751,8 +19025,8 @@ function parseUserFeedback(content) {
18751
19025
  async function appendToArchive(archiveFile, resolvedIssues) {
18752
19026
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
18753
19027
  let archiveContent = "";
18754
- if (await fs2__default.default.pathExists(archiveFile)) {
18755
- archiveContent = await fs2__default.default.readFile(archiveFile, "utf-8");
19028
+ if (await fs3__default.default.pathExists(archiveFile)) {
19029
+ archiveContent = await fs3__default.default.readFile(archiveFile, "utf-8");
18756
19030
  } else {
18757
19031
  const year = path3__namespace.basename(archiveFile).match(/(\d{4})/)?.[1] || (/* @__PURE__ */ new Date()).getFullYear();
18758
19032
  archiveContent = `# User Feedback Archive ${year}
@@ -18786,7 +19060,7 @@ ${resolvedIssue}
18786
19060
  `- Last updated: ${timestamp}`
18787
19061
  );
18788
19062
  }
18789
- await fs2__default.default.writeFile(archiveFile, archiveContent, "utf-8");
19063
+ await fs3__default.default.writeFile(archiveFile, archiveContent, "utf-8");
18790
19064
  }
18791
19065
  function generateCompactedFeedback(openIssues, metadata) {
18792
19066
  let content = metadata.trim() + "\n";
@@ -18811,15 +19085,15 @@ async function shouldArchive(feedbackFile, options = {}) {
18811
19085
  // 50KB
18812
19086
  lineCountThreshold = 500
18813
19087
  } = options;
18814
- if (!await fs2__default.default.pathExists(feedbackFile)) {
19088
+ if (!await fs3__default.default.pathExists(feedbackFile)) {
18815
19089
  return {
18816
19090
  shouldArchive: false,
18817
19091
  reasons: [],
18818
19092
  stats: { openIssuesCount: 0, resolvedIssuesCount: 0, fileSizeBytes: 0, lineCount: 0 }
18819
19093
  };
18820
19094
  }
18821
- const content = await fs2__default.default.readFile(feedbackFile, "utf-8");
18822
- const stats = await fs2__default.default.stat(feedbackFile);
19095
+ const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
19096
+ const stats = await fs3__default.default.stat(feedbackFile);
18823
19097
  const parsed = parseUserFeedback(content);
18824
19098
  const lineCount = content.split("\n").length;
18825
19099
  const reasons = [];
@@ -18893,16 +19167,16 @@ var EnhancedFeedbackFileManager = class {
18893
19167
  this.feedbackFile = feedbackFile;
18894
19168
  }
18895
19169
  async ensureExists() {
18896
- if (!await fs2__default.default.pathExists(this.feedbackFile)) {
19170
+ if (!await fs3__default.default.pathExists(this.feedbackFile)) {
18897
19171
  await this.createInitialFile();
18898
19172
  }
18899
19173
  }
18900
19174
  async addFeedback(issue, testCriteria) {
18901
19175
  await this.ensureExists();
18902
19176
  try {
18903
- const content = await fs2__default.default.readFile(this.feedbackFile, "utf-8");
19177
+ const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
18904
19178
  const updatedContent = this.addIssueToContent(content, issue, testCriteria);
18905
- await fs2__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
19179
+ await fs3__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
18906
19180
  } catch (error) {
18907
19181
  throw new ValidationError(
18908
19182
  `Failed to save feedback: ${error}`,
@@ -18915,12 +19189,12 @@ var EnhancedFeedbackFileManager = class {
18915
19189
  */
18916
19190
  async repairMalformedFile() {
18917
19191
  try {
18918
- const content = await fs2__default.default.readFile(this.feedbackFile, "utf-8");
19192
+ const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
18919
19193
  const hasOpenIssues = content.includes("<OPEN_ISSUES>");
18920
19194
  const hasClosingTag = content.includes("</OPEN_ISSUES>");
18921
19195
  if (!hasOpenIssues || !hasClosingTag) {
18922
19196
  const backupPath = this.feedbackFile + ".backup." + Date.now();
18923
- await fs2__default.default.writeFile(backupPath, content, "utf-8");
19197
+ await fs3__default.default.writeFile(backupPath, content, "utf-8");
18924
19198
  const existingIssues = this.extractIssuesFromMalformedContent(content);
18925
19199
  await this.createInitialFile(existingIssues);
18926
19200
  }
@@ -18952,8 +19226,8 @@ List any features you'd like to see added or bugs you've encountered.
18952
19226
 
18953
19227
  <!-- Resolved issues will be moved here -->
18954
19228
  `;
18955
- await fs2__default.default.ensureDir(path3__namespace.dirname(this.feedbackFile));
18956
- await fs2__default.default.writeFile(this.feedbackFile, initialContent, "utf-8");
19229
+ await fs3__default.default.ensureDir(path3__namespace.dirname(this.feedbackFile));
19230
+ await fs3__default.default.writeFile(this.feedbackFile, initialContent, "utf-8");
18957
19231
  }
18958
19232
  addIssueToContent(content, issue, testCriteria) {
18959
19233
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -19069,17 +19343,17 @@ async function handleCompactCommand(subArgs, options) {
19069
19343
  if (subArgs.length > 0) {
19070
19344
  for (const filePath of subArgs) {
19071
19345
  const resolvedPath = path3__namespace.resolve(filePath);
19072
- if (await fs2__default.default.pathExists(resolvedPath)) {
19346
+ if (await fs3__default.default.pathExists(resolvedPath)) {
19073
19347
  filesToCompact.push(resolvedPath);
19074
19348
  } else {
19075
19349
  console.warn(chalk15__default.default.yellow(`\u26A0\uFE0F File not found: ${filePath}`));
19076
19350
  }
19077
19351
  }
19078
19352
  } else {
19079
- if (await fs2__default.default.pathExists(defaultClaudeFile)) {
19353
+ if (await fs3__default.default.pathExists(defaultClaudeFile)) {
19080
19354
  filesToCompact.push(defaultClaudeFile);
19081
19355
  }
19082
- if (await fs2__default.default.pathExists(defaultAgentsFile)) {
19356
+ if (await fs3__default.default.pathExists(defaultAgentsFile)) {
19083
19357
  filesToCompact.push(defaultAgentsFile);
19084
19358
  }
19085
19359
  }
@@ -20013,11 +20287,11 @@ var GitManager = class {
20013
20287
  */
20014
20288
  async updateJunoTaskConfig(gitUrl) {
20015
20289
  const configPath = path3__namespace.join(this.workingDirectory, ".juno_task", "init.md");
20016
- if (!await fs2__default.default.pathExists(configPath)) {
20290
+ if (!await fs3__default.default.pathExists(configPath)) {
20017
20291
  return;
20018
20292
  }
20019
20293
  try {
20020
- let content = await fs2__default.default.readFile(configPath, "utf-8");
20294
+ let content = await fs3__default.default.readFile(configPath, "utf-8");
20021
20295
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
20022
20296
  if (frontmatterMatch) {
20023
20297
  let frontmatter = frontmatterMatch[1];
@@ -20038,7 +20312,7 @@ GIT_URL: ${gitUrl}
20038
20312
  `;
20039
20313
  content = frontmatter + content;
20040
20314
  }
20041
- await fs2__default.default.writeFile(configPath, content, "utf-8");
20315
+ await fs3__default.default.writeFile(configPath, content, "utf-8");
20042
20316
  } catch (error) {
20043
20317
  console.warn(`Warning: Failed to update juno-code configuration: ${error}`);
20044
20318
  }
@@ -20970,7 +21244,7 @@ var LogViewer = ({
20970
21244
  init_types();
20971
21245
  async function exportLogs(logger2, filepath, options) {
20972
21246
  try {
20973
- const fs21 = await import('fs-extra');
21247
+ const fs22 = await import('fs-extra');
20974
21248
  let entries = logger2.getRecentEntries(options.tail || 1e3);
20975
21249
  if (options.level) {
20976
21250
  const level = LogLevel[options.level.toUpperCase()];
@@ -21000,7 +21274,7 @@ async function exportLogs(logger2, filepath, options) {
21000
21274
  },
21001
21275
  entries
21002
21276
  };
21003
- await fs21.writeFile(filepath, JSON.stringify(exportData, null, 2));
21277
+ await fs22.writeFile(filepath, JSON.stringify(exportData, null, 2));
21004
21278
  console.log(chalk15__default.default.green(`\u2705 Exported ${entries.length} log entries to: ${filepath}`));
21005
21279
  } catch (error) {
21006
21280
  console.error(chalk15__default.default.red(`\u274C Failed to export logs: ${error}`));
@@ -22544,7 +22818,7 @@ function createServicesCommand() {
22544
22818
  const servicesCmd = new commander.Command("services").description("Manage juno-code service scripts").addHelpText("after", `
22545
22819
  Examples:
22546
22820
  $ juno-code services install Install service scripts to ~/.juno_code/services/
22547
- $ 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)
22548
22822
  $ juno-code services list List installed service scripts
22549
22823
  $ juno-code services status Check installation status
22550
22824
  $ juno-code services uninstall Remove all service scripts
@@ -22801,10 +23075,10 @@ autoload -U compinit && compinit`;
22801
23075
  */
22802
23076
  async isSourceCommandPresent(configPath, sourceCommand) {
22803
23077
  try {
22804
- if (!await fs2__default.default.pathExists(configPath)) {
23078
+ if (!await fs3__default.default.pathExists(configPath)) {
22805
23079
  return false;
22806
23080
  }
22807
- const content = await fs2__default.default.readFile(configPath, "utf-8");
23081
+ const content = await fs3__default.default.readFile(configPath, "utf-8");
22808
23082
  return content.includes("juno-code completion");
22809
23083
  } catch {
22810
23084
  return false;
@@ -22826,15 +23100,15 @@ autoload -U compinit && compinit`;
22826
23100
  continue;
22827
23101
  }
22828
23102
  try {
22829
- const completionExists = await fs2__default.default.pathExists(shell.completionPath);
22830
- const configExists = await fs2__default.default.pathExists(shell.configPath);
23103
+ const completionExists = await fs3__default.default.pathExists(shell.completionPath);
23104
+ const configExists = await fs3__default.default.pathExists(shell.configPath);
22831
23105
  const isSourced = configExists && await this.isSourceCommandPresent(
22832
23106
  shell.configPath,
22833
23107
  this.getSourceCommand(shell.name, shell.completionPath)
22834
23108
  );
22835
23109
  let lastInstalled;
22836
23110
  if (completionExists) {
22837
- const stats = await fs2__default.default.stat(shell.completionPath);
23111
+ const stats = await fs3__default.default.stat(shell.completionPath);
22838
23112
  lastInstalled = stats.mtime;
22839
23113
  }
22840
23114
  statuses.push({
@@ -22860,7 +23134,7 @@ autoload -U compinit && compinit`;
22860
23134
  async ensureCompletionDirectory(shell) {
22861
23135
  const completionPath = this.getCompletionPath(shell);
22862
23136
  const completionDir = path3__namespace.dirname(completionPath);
22863
- await fs2__default.default.ensureDir(completionDir);
23137
+ await fs3__default.default.ensureDir(completionDir);
22864
23138
  }
22865
23139
  /**
22866
23140
  * Ensure directory exists for shell configuration
@@ -22868,7 +23142,7 @@ autoload -U compinit && compinit`;
22868
23142
  async ensureConfigDirectory(shell) {
22869
23143
  const configPath = this.getConfigPath(shell);
22870
23144
  const configDir = path3__namespace.dirname(configPath);
22871
- await fs2__default.default.ensureDir(configDir);
23145
+ await fs3__default.default.ensureDir(configDir);
22872
23146
  }
22873
23147
  /**
22874
23148
  * Get shell version information
@@ -22892,15 +23166,15 @@ autoload -U compinit && compinit`;
22892
23166
  try {
22893
23167
  const configPath = this.getConfigPath(shell);
22894
23168
  const configDir = path3__namespace.dirname(configPath);
22895
- await fs2__default.default.access(configDir, fs2__default.default.constants.W_OK);
23169
+ await fs3__default.default.access(configDir, fs3__default.default.constants.W_OK);
22896
23170
  } catch {
22897
23171
  issues.push(`Cannot write to ${shell} configuration directory`);
22898
23172
  }
22899
23173
  try {
22900
23174
  const completionPath = this.getCompletionPath(shell);
22901
23175
  const completionDir = path3__namespace.dirname(completionPath);
22902
- await fs2__default.default.ensureDir(completionDir);
22903
- await fs2__default.default.access(completionDir, fs2__default.default.constants.W_OK);
23176
+ await fs3__default.default.ensureDir(completionDir);
23177
+ await fs3__default.default.access(completionDir, fs3__default.default.constants.W_OK);
22904
23178
  } catch {
22905
23179
  issues.push(`Cannot write to ${shell} completion directory`);
22906
23180
  }
@@ -22971,10 +23245,10 @@ var ContextAwareCompletion = class {
22971
23245
  async getSessionIds() {
22972
23246
  try {
22973
23247
  const sessionDir = path3__namespace.join(process.cwd(), ".juno_task", "sessions");
22974
- if (!await fs2__default.default.pathExists(sessionDir)) {
23248
+ if (!await fs3__default.default.pathExists(sessionDir)) {
22975
23249
  return [];
22976
23250
  }
22977
- const sessions = await fs2__default.default.readdir(sessionDir);
23251
+ const sessions = await fs3__default.default.readdir(sessionDir);
22978
23252
  return sessions.filter((name) => name.match(/^session_\d+$/)).map((name) => name.replace("session_", "")).sort((a, b) => parseInt(b) - parseInt(a));
22979
23253
  } catch {
22980
23254
  return [];
@@ -22988,8 +23262,8 @@ var ContextAwareCompletion = class {
22988
23262
  const builtinTemplates = ["basic", "advanced", "research", "development"];
22989
23263
  const customTemplatesDir = path3__namespace.join(process.cwd(), ".juno_task", "templates");
22990
23264
  let customTemplates = [];
22991
- if (await fs2__default.default.pathExists(customTemplatesDir)) {
22992
- const files = await fs2__default.default.readdir(customTemplatesDir);
23265
+ if (await fs3__default.default.pathExists(customTemplatesDir)) {
23266
+ const files = await fs3__default.default.readdir(customTemplatesDir);
22993
23267
  customTemplates = files.filter((name) => name.endsWith(".md") || name.endsWith(".hbs")).map((name) => path3__namespace.basename(name, path3__namespace.extname(name)));
22994
23268
  }
22995
23269
  return [...builtinTemplates, ...customTemplates].sort();
@@ -23066,7 +23340,7 @@ var CompletionInstaller = class {
23066
23340
  await this.shellDetector.ensureConfigDirectory(shell);
23067
23341
  const script = this.generateEnhancedCompletion(shell, "juno-code");
23068
23342
  const completionPath = this.shellDetector.getCompletionPath(shell);
23069
- await fs2__default.default.writeFile(completionPath, script, "utf-8");
23343
+ await fs3__default.default.writeFile(completionPath, script, "utf-8");
23070
23344
  const configPath = this.shellDetector.getConfigPath(shell);
23071
23345
  const sourceCommand = this.shellDetector.getSourceCommand(shell, completionPath);
23072
23346
  const warnings = [];
@@ -23074,7 +23348,7 @@ var CompletionInstaller = class {
23074
23348
  const isPresent = await this.shellDetector.isSourceCommandPresent(configPath, sourceCommand);
23075
23349
  if (!isPresent) {
23076
23350
  try {
23077
- await fs2__default.default.appendFile(configPath, `
23351
+ await fs3__default.default.appendFile(configPath, `
23078
23352
 
23079
23353
  ${sourceCommand}
23080
23354
  `);
@@ -23105,8 +23379,8 @@ ${sourceCommand}
23105
23379
  async uninstall(shell) {
23106
23380
  try {
23107
23381
  const completionPath = this.shellDetector.getCompletionPath(shell);
23108
- if (await fs2__default.default.pathExists(completionPath)) {
23109
- await fs2__default.default.remove(completionPath);
23382
+ if (await fs3__default.default.pathExists(completionPath)) {
23383
+ await fs3__default.default.remove(completionPath);
23110
23384
  return true;
23111
23385
  }
23112
23386
  return false;
@@ -23120,7 +23394,7 @@ ${sourceCommand}
23120
23394
  async isInstalled(shell) {
23121
23395
  try {
23122
23396
  const completionPath = this.shellDetector.getCompletionPath(shell);
23123
- return await fs2__default.default.pathExists(completionPath);
23397
+ return await fs3__default.default.pathExists(completionPath);
23124
23398
  } catch {
23125
23399
  return false;
23126
23400
  }
@@ -23921,11 +24195,11 @@ function setupMainCommand(program) {
23921
24195
  );
23922
24196
  const allOptions2 = { ...definedGlobalOptions, ...options };
23923
24197
  if (!globalOptions.subagent && !options.prompt && !options.interactive && !options.interactivePrompt) {
23924
- const fs21 = await import('fs-extra');
23925
- const path23 = await import('path');
24198
+ const fs22 = await import('fs-extra');
24199
+ const path24 = await import('path');
23926
24200
  const cwd2 = process.cwd();
23927
- const junoTaskDir = path23.join(cwd2, ".juno_task");
23928
- if (await fs21.pathExists(junoTaskDir)) {
24201
+ const junoTaskDir = path24.join(cwd2, ".juno_task");
24202
+ if (await fs22.pathExists(junoTaskDir)) {
23929
24203
  console.log(chalk15__default.default.blue.bold("\u{1F3AF} Juno Code - Auto-detected Initialized Project\n"));
23930
24204
  try {
23931
24205
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -23942,12 +24216,12 @@ function setupMainCommand(program) {
23942
24216
  allOptions2.subagent = config.defaultSubagent;
23943
24217
  console.log(chalk15__default.default.gray(`\u{1F916} Using configured subagent: ${chalk15__default.default.cyan(config.defaultSubagent)}`));
23944
24218
  }
23945
- const promptFile = path23.join(junoTaskDir, "prompt.md");
23946
- if (!allOptions2.prompt && await fs21.pathExists(promptFile)) {
24219
+ const promptFile = path24.join(junoTaskDir, "prompt.md");
24220
+ if (!allOptions2.prompt && await fs22.pathExists(promptFile)) {
23947
24221
  allOptions2.prompt = promptFile;
23948
24222
  console.log(chalk15__default.default.gray(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
23949
24223
  }
23950
- if (allOptions2.subagent && (allOptions2.prompt || await fs21.pathExists(promptFile))) {
24224
+ if (allOptions2.subagent && (allOptions2.prompt || await fs22.pathExists(promptFile))) {
23951
24225
  console.log(chalk15__default.default.green("\u2713 Auto-detected project configuration\n"));
23952
24226
  const { mainCommandHandler: mainCommandHandler3 } = await Promise.resolve().then(() => (init_main(), main_exports));
23953
24227
  await mainCommandHandler3([], allOptions2, command);
@@ -24104,6 +24378,17 @@ async function main() {
24104
24378
  console.error("[DEBUG] Service auto-update failed:", error instanceof Error ? error.message : String(error));
24105
24379
  }
24106
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
+ }
24107
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");
24108
24393
  setupGlobalOptions(program);
24109
24394
  const isVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");
@@ -24111,10 +24396,10 @@ async function main() {
24111
24396
  const isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V");
24112
24397
  const hasNoArguments = process.argv.length <= 2;
24113
24398
  const isInitCommand = process.argv.includes("init");
24114
- const fs21 = await import('fs-extra');
24115
- const path23 = await import('path');
24116
- const junoTaskDir = path23.join(process.cwd(), ".juno_task");
24117
- const isInitialized = await fs21.pathExists(junoTaskDir);
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);
24118
24403
  if (!isHelpOrVersion && !hasNoArguments && !isInitCommand && isInitialized) {
24119
24404
  try {
24120
24405
  const { validateStartupConfigs: validateStartupConfigs2 } = await Promise.resolve().then(() => (init_startup_validation(), startup_validation_exports));