juno-code 1.0.35 → 1.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
  }
@@ -12810,12 +12842,18 @@ async function mainCommandHandler(args, options, command) {
12810
12842
  console.error(chalk15__default.default.red("\n\u274C Error: --allowed-tools and --append-allowed-tools are mutually exclusive. Use one or the other."));
12811
12843
  process.exit(1);
12812
12844
  }
12845
+ if (options.maxIterations !== void 0 && Number.isNaN(options.maxIterations)) {
12846
+ throw new ValidationError(
12847
+ "Max iterations must be a valid number",
12848
+ ["Use -1 for unlimited iterations", "Use positive integers like 1, 5, or 10", "Example: -i 5"]
12849
+ );
12850
+ }
12813
12851
  const executionRequest = createExecutionRequest({
12814
12852
  instruction,
12815
12853
  subagent: options.subagent,
12816
12854
  backend: selectedBackend,
12817
12855
  workingDirectory: config.workingDirectory,
12818
- maxIterations: options.maxIterations || config.defaultMaxIterations,
12856
+ maxIterations: options.maxIterations ?? config.defaultMaxIterations,
12819
12857
  model: options.model || config.defaultModel,
12820
12858
  agents: options.agents,
12821
12859
  tools: options.tools,
@@ -12980,7 +13018,7 @@ var init_main = __esm({
12980
13018
  return await this.collectInteractivePrompt();
12981
13019
  } else {
12982
13020
  const defaultPromptPath = path3__namespace.join(process.cwd(), ".juno_task", "prompt.md");
12983
- if (await fs2__default.default.pathExists(defaultPromptPath)) {
13021
+ if (await fs3__default.default.pathExists(defaultPromptPath)) {
12984
13022
  console.error(chalk15__default.default.blue(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
12985
13023
  return await this.loadPromptFromFile(defaultPromptPath);
12986
13024
  } else {
@@ -13008,7 +13046,7 @@ var init_main = __esm({
13008
13046
  }
13009
13047
  try {
13010
13048
  const resolvedPath = path3__namespace.resolve(prompt);
13011
- return await fs2__default.default.pathExists(resolvedPath);
13049
+ return await fs3__default.default.pathExists(resolvedPath);
13012
13050
  } catch {
13013
13051
  return false;
13014
13052
  }
@@ -13016,7 +13054,7 @@ var init_main = __esm({
13016
13054
  async loadPromptFromFile(filePath) {
13017
13055
  try {
13018
13056
  const resolvedPath = path3__namespace.resolve(filePath);
13019
- const content = await fs2__default.default.readFile(resolvedPath, "utf-8");
13057
+ const content = await fs3__default.default.readFile(resolvedPath, "utf-8");
13020
13058
  if (!content.trim()) {
13021
13059
  throw new FileSystemError(
13022
13060
  "Prompt file is empty",
@@ -13338,6 +13376,221 @@ var init_main = __esm({
13338
13376
  }
13339
13377
  });
13340
13378
 
13379
+ // src/utils/script-installer.ts
13380
+ var script_installer_exports = {};
13381
+ __export(script_installer_exports, {
13382
+ ScriptInstaller: () => ScriptInstaller
13383
+ });
13384
+ var ScriptInstaller;
13385
+ var init_script_installer = __esm({
13386
+ "src/utils/script-installer.ts"() {
13387
+ init_version();
13388
+ ScriptInstaller = class {
13389
+ /**
13390
+ * Scripts that should be auto-installed if missing
13391
+ * These are critical scripts that users expect to be available
13392
+ */
13393
+ /**
13394
+ * Required scripts include both standalone scripts and their dependencies.
13395
+ * kanban.sh depends on install_requirements.sh for Python venv setup.
13396
+ */
13397
+ static REQUIRED_SCRIPTS = [
13398
+ "run_until_completion.sh",
13399
+ "kanban.sh",
13400
+ "install_requirements.sh"
13401
+ // Required by kanban.sh for Python venv creation
13402
+ ];
13403
+ /**
13404
+ * Get the templates scripts directory from the package
13405
+ */
13406
+ static getPackageScriptsDir() {
13407
+ const __dirname2 = path3__namespace.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href))));
13408
+ const candidates = [
13409
+ path3__namespace.join(__dirname2, "..", "..", "templates", "scripts"),
13410
+ // dist (production)
13411
+ path3__namespace.join(__dirname2, "..", "templates", "scripts")
13412
+ // src (development)
13413
+ ];
13414
+ for (const scriptsPath of candidates) {
13415
+ if (fs3__default.default.existsSync(scriptsPath)) {
13416
+ return scriptsPath;
13417
+ }
13418
+ }
13419
+ if (process.env.JUNO_CODE_DEBUG === "1") {
13420
+ console.error("[DEBUG] ScriptInstaller: Could not find templates/scripts directory");
13421
+ console.error("[DEBUG] Tried:", candidates);
13422
+ }
13423
+ return null;
13424
+ }
13425
+ /**
13426
+ * Check if a specific script exists in the project's .juno_task/scripts/ directory
13427
+ */
13428
+ static async scriptExists(projectDir, scriptName) {
13429
+ const scriptPath = path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
13430
+ return fs3__default.default.pathExists(scriptPath);
13431
+ }
13432
+ /**
13433
+ * Install a specific script to the project's .juno_task/scripts/ directory
13434
+ * @param projectDir - The project root directory
13435
+ * @param scriptName - Name of the script to install (e.g., 'run_until_completion.sh')
13436
+ * @param silent - If true, suppresses console output
13437
+ * @returns true if script was installed, false if installation was skipped or failed
13438
+ */
13439
+ static async installScript(projectDir, scriptName, silent = false) {
13440
+ try {
13441
+ const packageScriptsDir = this.getPackageScriptsDir();
13442
+ if (!packageScriptsDir) {
13443
+ if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
13444
+ console.error("[DEBUG] ScriptInstaller: Package scripts directory not found");
13445
+ }
13446
+ return false;
13447
+ }
13448
+ const sourcePath = path3__namespace.join(packageScriptsDir, scriptName);
13449
+ if (!await fs3__default.default.pathExists(sourcePath)) {
13450
+ if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
13451
+ console.error(`[DEBUG] ScriptInstaller: Source script not found: ${sourcePath}`);
13452
+ }
13453
+ return false;
13454
+ }
13455
+ const destDir = path3__namespace.join(projectDir, ".juno_task", "scripts");
13456
+ await fs3__default.default.ensureDir(destDir);
13457
+ const destPath = path3__namespace.join(destDir, scriptName);
13458
+ await fs3__default.default.copy(sourcePath, destPath, { overwrite: true });
13459
+ if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
13460
+ await fs3__default.default.chmod(destPath, 493);
13461
+ }
13462
+ if (!silent) {
13463
+ console.log(`\u2713 Installed script: ${scriptName} to .juno_task/scripts/`);
13464
+ }
13465
+ if (process.env.JUNO_CODE_DEBUG === "1") {
13466
+ console.error(`[DEBUG] ScriptInstaller: Installed ${scriptName} to ${destPath}`);
13467
+ }
13468
+ return true;
13469
+ } catch (error) {
13470
+ if (!silent && process.env.JUNO_CODE_DEBUG === "1") {
13471
+ console.error(`[DEBUG] ScriptInstaller: Failed to install ${scriptName}:`, error);
13472
+ }
13473
+ return false;
13474
+ }
13475
+ }
13476
+ /**
13477
+ * Check which required scripts are missing from the project
13478
+ * @param projectDir - The project root directory
13479
+ * @returns Array of missing script names
13480
+ */
13481
+ static async getMissingScripts(projectDir) {
13482
+ const missing = [];
13483
+ for (const script of this.REQUIRED_SCRIPTS) {
13484
+ if (!await this.scriptExists(projectDir, script)) {
13485
+ missing.push(script);
13486
+ }
13487
+ }
13488
+ return missing;
13489
+ }
13490
+ /**
13491
+ * Auto-install any missing required scripts
13492
+ * This should be called on CLI startup for initialized projects
13493
+ * @param projectDir - The project root directory
13494
+ * @param silent - If true, suppresses console output
13495
+ * @returns true if any scripts were installed
13496
+ */
13497
+ static async autoInstallMissing(projectDir, silent = true) {
13498
+ try {
13499
+ const junoTaskDir = path3__namespace.join(projectDir, ".juno_task");
13500
+ if (!await fs3__default.default.pathExists(junoTaskDir)) {
13501
+ return false;
13502
+ }
13503
+ const missing = await this.getMissingScripts(projectDir);
13504
+ if (missing.length === 0) {
13505
+ return false;
13506
+ }
13507
+ if (process.env.JUNO_CODE_DEBUG === "1") {
13508
+ console.error(`[DEBUG] ScriptInstaller: Missing scripts: ${missing.join(", ")}`);
13509
+ }
13510
+ let installedAny = false;
13511
+ for (const script of missing) {
13512
+ const installed = await this.installScript(projectDir, script, silent);
13513
+ if (installed) {
13514
+ installedAny = true;
13515
+ }
13516
+ }
13517
+ if (installedAny && !silent) {
13518
+ console.log(`\u2713 Auto-installed ${missing.length} missing script(s)`);
13519
+ }
13520
+ return installedAny;
13521
+ } catch (error) {
13522
+ if (process.env.JUNO_CODE_DEBUG === "1") {
13523
+ console.error("[DEBUG] ScriptInstaller: autoInstallMissing error:", error);
13524
+ }
13525
+ return false;
13526
+ }
13527
+ }
13528
+ /**
13529
+ * Update a script if the package version is newer (by content comparison)
13530
+ * @param projectDir - The project root directory
13531
+ * @param scriptName - Name of the script to update
13532
+ * @param silent - If true, suppresses console output
13533
+ * @returns true if script was updated
13534
+ */
13535
+ static async updateScriptIfNewer(projectDir, scriptName, silent = true) {
13536
+ try {
13537
+ const packageScriptsDir = this.getPackageScriptsDir();
13538
+ if (!packageScriptsDir) {
13539
+ return false;
13540
+ }
13541
+ const sourcePath = path3__namespace.join(packageScriptsDir, scriptName);
13542
+ const destPath = path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
13543
+ if (!await fs3__default.default.pathExists(destPath)) {
13544
+ return this.installScript(projectDir, scriptName, silent);
13545
+ }
13546
+ const [sourceContent, destContent] = await Promise.all([
13547
+ fs3__default.default.readFile(sourcePath, "utf-8"),
13548
+ fs3__default.default.readFile(destPath, "utf-8")
13549
+ ]);
13550
+ if (sourceContent !== destContent) {
13551
+ await fs3__default.default.copy(sourcePath, destPath, { overwrite: true });
13552
+ if (scriptName.endsWith(".sh") || scriptName.endsWith(".py")) {
13553
+ await fs3__default.default.chmod(destPath, 493);
13554
+ }
13555
+ if (!silent) {
13556
+ console.log(`\u2713 Updated script: ${scriptName}`);
13557
+ }
13558
+ if (process.env.JUNO_CODE_DEBUG === "1") {
13559
+ console.error(`[DEBUG] ScriptInstaller: Updated ${scriptName} (content changed)`);
13560
+ }
13561
+ return true;
13562
+ }
13563
+ return false;
13564
+ } catch (error) {
13565
+ if (process.env.JUNO_CODE_DEBUG === "1") {
13566
+ console.error(`[DEBUG] ScriptInstaller: updateScriptIfNewer error for ${scriptName}:`, error);
13567
+ }
13568
+ return false;
13569
+ }
13570
+ }
13571
+ /**
13572
+ * Get the path to a script in the project's .juno_task/scripts/ directory
13573
+ */
13574
+ static getScriptPath(projectDir, scriptName) {
13575
+ return path3__namespace.join(projectDir, ".juno_task", "scripts", scriptName);
13576
+ }
13577
+ /**
13578
+ * List all required scripts and their installation status
13579
+ */
13580
+ static async listRequiredScripts(projectDir) {
13581
+ const results = [];
13582
+ for (const script of this.REQUIRED_SCRIPTS) {
13583
+ results.push({
13584
+ name: script,
13585
+ installed: await this.scriptExists(projectDir, script)
13586
+ });
13587
+ }
13588
+ return results;
13589
+ }
13590
+ };
13591
+ }
13592
+ });
13593
+
13341
13594
  // src/utils/startup-validation.ts
13342
13595
  var startup_validation_exports = {};
13343
13596
  __export(startup_validation_exports, {
@@ -13428,7 +13681,7 @@ async function validateJSONFile(configSchema, baseDir) {
13428
13681
  const warnings = [];
13429
13682
  const filePath = path3__namespace.default.join(baseDir, configSchema.file);
13430
13683
  try {
13431
- const exists = await fs2__default.default.pathExists(filePath);
13684
+ const exists = await fs3__default.default.pathExists(filePath);
13432
13685
  if (!exists) {
13433
13686
  if (configSchema.required) {
13434
13687
  errors.push({
@@ -13451,7 +13704,7 @@ async function validateJSONFile(configSchema, baseDir) {
13451
13704
  return { isValid: !configSchema.required, errors, warnings };
13452
13705
  }
13453
13706
  try {
13454
- await fs2__default.default.access(filePath, fs2__default.default.constants.R_OK);
13707
+ await fs3__default.default.access(filePath, fs3__default.default.constants.R_OK);
13455
13708
  } catch (accessError) {
13456
13709
  errors.push({
13457
13710
  file: configSchema.file,
@@ -13467,7 +13720,7 @@ async function validateJSONFile(configSchema, baseDir) {
13467
13720
  }
13468
13721
  let jsonData;
13469
13722
  try {
13470
- const fileContent = await fs2__default.default.readFile(filePath, "utf8");
13723
+ const fileContent = await fs3__default.default.readFile(filePath, "utf8");
13471
13724
  jsonData = JSON.parse(fileContent);
13472
13725
  } catch (parseError) {
13473
13726
  const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
@@ -13602,7 +13855,7 @@ function displayValidationResults(result) {
13602
13855
  }
13603
13856
  async function logValidationResults(result, baseDir = process.cwd()) {
13604
13857
  const logDir = path3__namespace.default.join(baseDir, ".juno_task", "logs");
13605
- await fs2__default.default.ensureDir(logDir);
13858
+ await fs3__default.default.ensureDir(logDir);
13606
13859
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13607
13860
  const logFile = path3__namespace.default.join(logDir, `startup-validation-${timestamp}.log`);
13608
13861
  const logContent = [
@@ -13645,7 +13898,7 @@ async function logValidationResults(result, baseDir = process.cwd()) {
13645
13898
  logContent.push(``);
13646
13899
  }
13647
13900
  }
13648
- await fs2__default.default.writeFile(logFile, logContent.join("\n"));
13901
+ await fs3__default.default.writeFile(logFile, logContent.join("\n"));
13649
13902
  return logFile;
13650
13903
  }
13651
13904
  async function validateStartupConfigs(baseDir = process.cwd(), verbose = false) {
@@ -13979,7 +14232,7 @@ var TemplateEngine = class {
13979
14232
  let overallError;
13980
14233
  try {
13981
14234
  if (!options.dryRun) {
13982
- await fs2__default.default.ensureDir(targetDirectory);
14235
+ await fs3__default.default.ensureDir(targetDirectory);
13983
14236
  }
13984
14237
  for (const template of templates) {
13985
14238
  try {
@@ -15329,7 +15582,7 @@ This directory contains specification documents for your project.
15329
15582
  const fileName = this.getTemplateFileName(template);
15330
15583
  const targetPath = path3__namespace.join(targetDirectory, fileName);
15331
15584
  try {
15332
- const fileExists = await fs2__default.default.pathExists(targetPath);
15585
+ const fileExists = await fs3__default.default.pathExists(targetPath);
15333
15586
  if (fileExists && !options.force && options.onConflict !== "overwrite") {
15334
15587
  return {
15335
15588
  path: targetPath,
@@ -15351,10 +15604,10 @@ This directory contains specification documents for your project.
15351
15604
  }
15352
15605
  if (options.createBackup && fileExists) {
15353
15606
  const backupPath = `${targetPath}.backup.${Date.now()}`;
15354
- await fs2__default.default.copy(targetPath, backupPath);
15607
+ await fs3__default.default.copy(targetPath, backupPath);
15355
15608
  }
15356
- await fs2__default.default.ensureDir(path3__namespace.dirname(targetPath));
15357
- 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");
15358
15611
  return {
15359
15612
  path: targetPath,
15360
15613
  content: renderedContent,
@@ -15618,7 +15871,7 @@ var SimpleInitTUI = class {
15618
15871
  }
15619
15872
  async confirmSave(targetDirectory) {
15620
15873
  const junoTaskPath = path3__namespace.join(targetDirectory, ".juno_task");
15621
- if (await fs2__default.default.pathExists(junoTaskPath)) {
15874
+ if (await fs3__default.default.pathExists(junoTaskPath)) {
15622
15875
  console.log(chalk15__default.default.yellow(" \u26A0\uFE0F .juno_task directory already exists"));
15623
15876
  console.log(chalk15__default.default.gray(" Would you like to:"));
15624
15877
  console.log(chalk15__default.default.gray(" 1) Override existing files"));
@@ -15663,16 +15916,16 @@ var SimpleProjectGenerator = class {
15663
15916
  async generate() {
15664
15917
  const { targetDirectory, variables, force } = this.context;
15665
15918
  console.log(chalk15__default.default.blue("\u{1F4C1} Creating project directory..."));
15666
- await fs2__default.default.ensureDir(targetDirectory);
15919
+ await fs3__default.default.ensureDir(targetDirectory);
15667
15920
  const junoTaskDir = path3__namespace.join(targetDirectory, ".juno_task");
15668
- const junoTaskExists = await fs2__default.default.pathExists(junoTaskDir);
15921
+ const junoTaskExists = await fs3__default.default.pathExists(junoTaskDir);
15669
15922
  if (junoTaskExists && !force) {
15670
15923
  throw new ValidationError(
15671
15924
  "Project already initialized. Directory .juno_task already exists.",
15672
15925
  ["Use --force flag to overwrite existing files", "Choose a different directory"]
15673
15926
  );
15674
15927
  }
15675
- await fs2__default.default.ensureDir(junoTaskDir);
15928
+ await fs3__default.default.ensureDir(junoTaskDir);
15676
15929
  console.log(chalk15__default.default.blue("\u2699\uFE0F Creating project configuration..."));
15677
15930
  await this.createConfigFile(junoTaskDir, targetDirectory);
15678
15931
  console.log(chalk15__default.default.blue("\u{1F527} Setting up MCP configuration..."));
@@ -15706,21 +15959,21 @@ var SimpleProjectGenerator = class {
15706
15959
  const promptContent = await templateEngine.render(promptTemplate, templateContext);
15707
15960
  const initContent = await templateEngine.render(initTemplate, templateContext);
15708
15961
  const implementContent = await templateEngine.render(implementTemplate, templateContext);
15709
- await 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);
15962
+ await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "prompt.md"), promptContent);
15963
+ await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "init.md"), initContent);
15964
+ await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "implement.md"), implementContent);
15712
15965
  const userFeedbackTemplate = templateEngine.getBuiltInTemplate("USER_FEEDBACK.md");
15713
15966
  if (userFeedbackTemplate) {
15714
15967
  const userFeedbackContent = await templateEngine.render(userFeedbackTemplate, templateContext);
15715
- await 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);
15716
15969
  }
15717
15970
  const planTemplate = templateEngine.getBuiltInTemplate("plan.md");
15718
15971
  if (planTemplate) {
15719
15972
  const planContent = await templateEngine.render(planTemplate, templateContext);
15720
- await fs2__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
15973
+ await fs3__default.default.writeFile(path3__namespace.join(junoTaskDir, "plan.md"), planContent);
15721
15974
  }
15722
15975
  const specsDir = path3__namespace.join(junoTaskDir, "specs");
15723
- await fs2__default.default.ensureDir(specsDir);
15976
+ await fs3__default.default.ensureDir(specsDir);
15724
15977
  const specsReadmeContent = `# Project Specifications
15725
15978
 
15726
15979
  This directory contains detailed specifications for the project components.
@@ -15737,7 +15990,7 @@ This directory contains detailed specifications for the project components.
15737
15990
  - Avoid conflicts with existing file names
15738
15991
  - Use \`.md\` extension for all specification files
15739
15992
  `;
15740
- await fs2__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
15993
+ await fs3__default.default.writeFile(path3__namespace.join(specsDir, "README.md"), specsReadmeContent);
15741
15994
  const requirementsContent = `# Requirements Specification
15742
15995
 
15743
15996
  ## Functional Requirements
@@ -15784,7 +16037,7 @@ This directory contains detailed specifications for the project components.
15784
16037
  - Code quality: Clean, maintainable codebase
15785
16038
  - Documentation: Complete and accurate documentation
15786
16039
  `;
15787
- await fs2__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
16040
+ await fs3__default.default.writeFile(path3__namespace.join(specsDir, "requirements.md"), requirementsContent);
15788
16041
  const architectureContent = `# Architecture Specification
15789
16042
 
15790
16043
  ## System Overview
@@ -15866,7 +16119,7 @@ This project uses AI-assisted development with juno-code to achieve: ${variables
15866
16119
  - Performance monitoring
15867
16120
  - Security best practices
15868
16121
  `;
15869
- await fs2__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
16122
+ await fs3__default.default.writeFile(path3__namespace.join(specsDir, "architecture.md"), architectureContent);
15870
16123
  const claudeContent = `# Claude Development Session Learnings
15871
16124
 
15872
16125
  ## Project Overview
@@ -15938,7 +16191,7 @@ This file will be updated as development progresses to track:
15938
16191
  - Solutions to complex problems
15939
16192
  - Performance improvements and optimizations
15940
16193
  `;
15941
- await fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
16194
+ await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "CLAUDE.md"), claudeContent);
15942
16195
  const agentsContent = `# AI Agent Selection and Performance
15943
16196
 
15944
16197
  ## Available Agents
@@ -16002,7 +16255,7 @@ Track agent performance for:
16002
16255
  4. **Feedback Loop**: Provide feedback to improve agent performance
16003
16256
  5. **Performance Monitoring**: Track and optimize agent usage
16004
16257
  `;
16005
- await fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
16258
+ await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "AGENTS.md"), agentsContent);
16006
16259
  const readmeContent = `# ${variables.PROJECT_NAME}
16007
16260
 
16008
16261
  ${variables.DESCRIPTION}
@@ -16099,7 +16352,7 @@ ${variables.GIT_URL}` : ""}
16099
16352
  Created with juno-code on ${variables.CURRENT_DATE}
16100
16353
  ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16101
16354
  `;
16102
- await fs2__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
16355
+ await fs3__default.default.writeFile(path3__namespace.join(targetDirectory, "README.md"), readmeContent);
16103
16356
  console.log(chalk15__default.default.blue("\u{1F4E6} Installing utility scripts..."));
16104
16357
  await this.copyScriptsFromTemplates(junoTaskDir);
16105
16358
  console.log(chalk15__default.default.blue("\u{1F40D} Installing Python requirements..."));
@@ -16151,7 +16404,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16151
16404
  hooks: getDefaultHooks()
16152
16405
  };
16153
16406
  const configPath = path3__namespace.join(junoTaskDir, "config.json");
16154
- await fs2__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
16407
+ await fs3__default.default.writeFile(configPath, JSON.stringify(configContent, null, 2));
16155
16408
  console.log(chalk15__default.default.green(` \u2713 Created .juno_task/config.json with ${this.context.subagent} as default subagent`));
16156
16409
  }
16157
16410
  async createMcpFile(junoTaskDir, targetDirectory) {
@@ -16205,7 +16458,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16205
16458
  }
16206
16459
  };
16207
16460
  const mcpPath = path3__namespace.join(junoTaskDir, "mcp.json");
16208
- await fs2__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
16461
+ await fs3__default.default.writeFile(mcpPath, JSON.stringify(mcpContent, null, 2));
16209
16462
  console.log(chalk15__default.default.green(` \u2713 Created .juno_task/mcp.json with roundtable-ai server configuration`));
16210
16463
  }
16211
16464
  getDefaultModelForSubagent(subagent) {
@@ -16224,7 +16477,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16224
16477
  async copyScriptsFromTemplates(junoTaskDir) {
16225
16478
  try {
16226
16479
  const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
16227
- await fs2__default.default.ensureDir(scriptsDir);
16480
+ await fs3__default.default.ensureDir(scriptsDir);
16228
16481
  const __filename2 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
16229
16482
  const __dirname2 = path3__namespace.dirname(__filename2);
16230
16483
  let templatesScriptsDir;
@@ -16235,11 +16488,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16235
16488
  } else {
16236
16489
  templatesScriptsDir = path3__namespace.join(__dirname2, "../../templates/scripts");
16237
16490
  }
16238
- if (!await fs2__default.default.pathExists(templatesScriptsDir)) {
16491
+ if (!await fs3__default.default.pathExists(templatesScriptsDir)) {
16239
16492
  console.log(chalk15__default.default.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
16240
16493
  return;
16241
16494
  }
16242
- const scriptFiles = await fs2__default.default.readdir(templatesScriptsDir);
16495
+ const scriptFiles = await fs3__default.default.readdir(templatesScriptsDir);
16243
16496
  if (scriptFiles.length === 0) {
16244
16497
  console.log(chalk15__default.default.gray(" \u2139\uFE0F No template scripts found to install"));
16245
16498
  return;
@@ -16248,11 +16501,11 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16248
16501
  for (const scriptFile of scriptFiles) {
16249
16502
  const sourcePath = path3__namespace.join(templatesScriptsDir, scriptFile);
16250
16503
  const destPath = path3__namespace.join(scriptsDir, scriptFile);
16251
- const stats = await fs2__default.default.stat(sourcePath);
16504
+ const stats = await fs3__default.default.stat(sourcePath);
16252
16505
  if (stats.isFile()) {
16253
- await fs2__default.default.copy(sourcePath, destPath);
16506
+ await fs3__default.default.copy(sourcePath, destPath);
16254
16507
  if (scriptFile.endsWith(".sh")) {
16255
- await fs2__default.default.chmod(destPath, 493);
16508
+ await fs3__default.default.chmod(destPath, 493);
16256
16509
  }
16257
16510
  copiedCount++;
16258
16511
  console.log(chalk15__default.default.green(` \u2713 Installed script: ${scriptFile}`));
@@ -16275,7 +16528,7 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
16275
16528
  try {
16276
16529
  const scriptsDir = path3__namespace.join(junoTaskDir, "scripts");
16277
16530
  const installScript = path3__namespace.join(scriptsDir, "install_requirements.sh");
16278
- if (!await fs2__default.default.pathExists(installScript)) {
16531
+ if (!await fs3__default.default.pathExists(installScript)) {
16279
16532
  console.log(chalk15__default.default.yellow(" \u26A0\uFE0F install_requirements.sh not found, skipping Python dependencies installation"));
16280
16533
  console.log(chalk15__default.default.gray(" You can install dependencies manually: juno-kanban, roundtable-ai"));
16281
16534
  return;
@@ -16572,20 +16825,20 @@ init_types();
16572
16825
  async function loadInitPrompt(directory) {
16573
16826
  const junoTaskDir = path3__namespace.join(directory, ".juno_task");
16574
16827
  const initFile = path3__namespace.join(junoTaskDir, "init.md");
16575
- if (!await fs2__default.default.pathExists(junoTaskDir)) {
16828
+ if (!await fs3__default.default.pathExists(junoTaskDir)) {
16576
16829
  throw new FileSystemError(
16577
16830
  'No .juno_task directory found. Run "juno-code init" first.',
16578
16831
  junoTaskDir
16579
16832
  );
16580
16833
  }
16581
- if (!await fs2__default.default.pathExists(initFile)) {
16834
+ if (!await fs3__default.default.pathExists(initFile)) {
16582
16835
  throw new FileSystemError(
16583
16836
  "No init.md file found in .juno_task directory",
16584
16837
  initFile
16585
16838
  );
16586
16839
  }
16587
16840
  try {
16588
- const content = await fs2__default.default.readFile(initFile, "utf-8");
16841
+ const content = await fs3__default.default.readFile(initFile, "utf-8");
16589
16842
  if (!content.trim()) {
16590
16843
  throw new FileSystemError(
16591
16844
  "init.md file is empty. Please add task instructions.",
@@ -17617,8 +17870,8 @@ Focus on ${request.intelligence === "basic" ? "basic functionality" : request.in
17617
17870
  for (const scenario of scenarios) {
17618
17871
  const testContent = await this.generateTestContent(request, scenario, template);
17619
17872
  const testFilePath = this.resolveTestFilePath(request, scenario);
17620
- await fs2__default.default.ensureDir(path3__namespace.dirname(testFilePath));
17621
- 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);
17622
17875
  testFiles.push(testFilePath);
17623
17876
  }
17624
17877
  return testFiles;
@@ -17870,8 +18123,8 @@ var TestExecutionEngine = class {
17870
18123
  async collectCoverage(request) {
17871
18124
  const coverageFile = path3__namespace.join(request.workingDirectory, "coverage", "coverage-summary.json");
17872
18125
  try {
17873
- if (await fs2__default.default.pathExists(coverageFile)) {
17874
- 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);
17875
18128
  return {
17876
18129
  lines: coverageData.total?.lines?.pct || 0,
17877
18130
  functions: coverageData.total?.functions?.pct || 0,
@@ -18054,8 +18307,8 @@ var TestReportEngine = class {
18054
18307
  suggestions: analysis.suggestions,
18055
18308
  recommendations: analysis.recommendations
18056
18309
  };
18057
- await fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18058
- 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 });
18059
18312
  return outputPath;
18060
18313
  }
18061
18314
  async generateHTMLReport(analysis, outputPath, includeVisualizations) {
@@ -18118,8 +18371,8 @@ var TestReportEngine = class {
18118
18371
  </body>
18119
18372
  </html>
18120
18373
  `.trim();
18121
- await fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18122
- 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);
18123
18376
  return outputPath;
18124
18377
  }
18125
18378
  generateCharts(analysis) {
@@ -18176,8 +18429,8 @@ ${analysis.suggestions.map((suggestion) => `- ${suggestion}`).join("\n")}
18176
18429
 
18177
18430
  ${analysis.recommendations.map((rec) => `- ${rec}`).join("\n")}
18178
18431
  `.trim();
18179
- await fs2__default.default.ensureDir(path3__namespace.dirname(outputPath));
18180
- 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);
18181
18434
  return outputPath;
18182
18435
  }
18183
18436
  async displayConsoleReport(analysis) {
@@ -18517,16 +18770,16 @@ async function compactConfigFile(filePath, options = {}) {
18517
18770
  preserveDays = 30,
18518
18771
  preservePatterns = []
18519
18772
  } = options;
18520
- const originalContent = await fs2__default.default.readFile(filePath, "utf-8");
18773
+ const originalContent = await fs3__default.default.readFile(filePath, "utf-8");
18521
18774
  const originalSize = originalContent.length;
18522
18775
  let backupPath = "";
18523
18776
  if (createBackup && !dryRun) {
18524
18777
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
18525
18778
  const ext = path3__namespace.extname(filePath);
18526
18779
  const basename11 = path3__namespace.basename(filePath, ext);
18527
- const 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");
18780
+ const dirname13 = path3__namespace.dirname(filePath);
18781
+ backupPath = path3__namespace.join(dirname13, `${basename11}.backup.${timestamp}${ext}`);
18782
+ await fs3__default.default.writeFile(backupPath, originalContent, "utf-8");
18530
18783
  }
18531
18784
  const compactionAnalysis = analyzeMarkdownStructure(originalContent);
18532
18785
  const compactedContent = compactMarkdownContent(
@@ -18541,7 +18794,7 @@ async function compactConfigFile(filePath, options = {}) {
18541
18794
  const compactedSize = finalContent.length;
18542
18795
  const reductionPercentage = Math.round((originalSize - compactedSize) / originalSize * 100);
18543
18796
  if (!dryRun) {
18544
- await fs2__default.default.writeFile(filePath, finalContent, "utf-8");
18797
+ await fs3__default.default.writeFile(filePath, finalContent, "utf-8");
18545
18798
  }
18546
18799
  return {
18547
18800
  originalSize,
@@ -18671,7 +18924,7 @@ function formatFileSize(bytes) {
18671
18924
  }
18672
18925
  async function shouldCompactFile(filePath, sizeThresholdKB = 50, ageThresholdDays = 30) {
18673
18926
  try {
18674
- const stats = await fs2__default.default.stat(filePath);
18927
+ const stats = await fs3__default.default.stat(filePath);
18675
18928
  const sizeKB = stats.size / 1024;
18676
18929
  if (sizeKB > sizeThresholdKB) {
18677
18930
  return true;
@@ -18693,19 +18946,19 @@ async function archiveResolvedIssues(options) {
18693
18946
  feedbackFile,
18694
18947
  archiveDir = path3__namespace.join(path3__namespace.dirname(feedbackFile), "archives"),
18695
18948
  openIssuesThreshold = 10} = options;
18696
- if (!await fs2__default.default.pathExists(feedbackFile)) {
18949
+ if (!await fs3__default.default.pathExists(feedbackFile)) {
18697
18950
  throw new Error(`Feedback file does not exist: ${feedbackFile}`);
18698
18951
  }
18699
- const content = await fs2__default.default.readFile(feedbackFile, "utf-8");
18952
+ const content = await fs3__default.default.readFile(feedbackFile, "utf-8");
18700
18953
  const parsed = parseUserFeedback(content);
18701
18954
  const warningsGenerated = [];
18702
18955
  if (parsed.openIssues.length > openIssuesThreshold) {
18703
18956
  const warning = `Found ${parsed.openIssues.length} open issues (threshold: ${openIssuesThreshold}). Consider reviewing and prioritizing.`;
18704
18957
  warningsGenerated.push(warning);
18705
18958
  const logFile = path3__namespace.join(path3__namespace.dirname(feedbackFile), "logs", "feedback-warnings.log");
18706
- await fs2__default.default.ensureDir(path3__namespace.dirname(logFile));
18959
+ await fs3__default.default.ensureDir(path3__namespace.dirname(logFile));
18707
18960
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
18708
- await fs2__default.default.appendFile(logFile, `[${timestamp}] ${warning}
18961
+ await fs3__default.default.appendFile(logFile, `[${timestamp}] ${warning}
18709
18962
  `);
18710
18963
  }
18711
18964
  if (parsed.resolvedIssues.length === 0) {
@@ -18722,10 +18975,10 @@ async function archiveResolvedIssues(options) {
18722
18975
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
18723
18976
  const archiveFile = path3__namespace.join(archiveDir, `USER_FEEDBACK_archive_${currentYear}.md`);
18724
18977
  {
18725
- await fs2__default.default.ensureDir(archiveDir);
18978
+ await fs3__default.default.ensureDir(archiveDir);
18726
18979
  await appendToArchive(archiveFile, parsed.resolvedIssues);
18727
18980
  const compactedContent = generateCompactedFeedback(parsed.openIssues, parsed.metadata);
18728
- await fs2__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
18981
+ await fs3__default.default.writeFile(feedbackFile, compactedContent, "utf-8");
18729
18982
  }
18730
18983
  {
18731
18984
  console.log(chalk15__default.default.green(`\u2705 Archived ${parsed.resolvedIssues.length} resolved issues`));
@@ -18772,8 +19025,8 @@ function parseUserFeedback(content) {
18772
19025
  async function appendToArchive(archiveFile, resolvedIssues) {
18773
19026
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
18774
19027
  let archiveContent = "";
18775
- if (await fs2__default.default.pathExists(archiveFile)) {
18776
- 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");
18777
19030
  } else {
18778
19031
  const year = path3__namespace.basename(archiveFile).match(/(\d{4})/)?.[1] || (/* @__PURE__ */ new Date()).getFullYear();
18779
19032
  archiveContent = `# User Feedback Archive ${year}
@@ -18807,7 +19060,7 @@ ${resolvedIssue}
18807
19060
  `- Last updated: ${timestamp}`
18808
19061
  );
18809
19062
  }
18810
- await fs2__default.default.writeFile(archiveFile, archiveContent, "utf-8");
19063
+ await fs3__default.default.writeFile(archiveFile, archiveContent, "utf-8");
18811
19064
  }
18812
19065
  function generateCompactedFeedback(openIssues, metadata) {
18813
19066
  let content = metadata.trim() + "\n";
@@ -18832,15 +19085,15 @@ async function shouldArchive(feedbackFile, options = {}) {
18832
19085
  // 50KB
18833
19086
  lineCountThreshold = 500
18834
19087
  } = options;
18835
- if (!await fs2__default.default.pathExists(feedbackFile)) {
19088
+ if (!await fs3__default.default.pathExists(feedbackFile)) {
18836
19089
  return {
18837
19090
  shouldArchive: false,
18838
19091
  reasons: [],
18839
19092
  stats: { openIssuesCount: 0, resolvedIssuesCount: 0, fileSizeBytes: 0, lineCount: 0 }
18840
19093
  };
18841
19094
  }
18842
- const content = await fs2__default.default.readFile(feedbackFile, "utf-8");
18843
- 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);
18844
19097
  const parsed = parseUserFeedback(content);
18845
19098
  const lineCount = content.split("\n").length;
18846
19099
  const reasons = [];
@@ -18914,16 +19167,16 @@ var EnhancedFeedbackFileManager = class {
18914
19167
  this.feedbackFile = feedbackFile;
18915
19168
  }
18916
19169
  async ensureExists() {
18917
- if (!await fs2__default.default.pathExists(this.feedbackFile)) {
19170
+ if (!await fs3__default.default.pathExists(this.feedbackFile)) {
18918
19171
  await this.createInitialFile();
18919
19172
  }
18920
19173
  }
18921
19174
  async addFeedback(issue, testCriteria) {
18922
19175
  await this.ensureExists();
18923
19176
  try {
18924
- const content = await fs2__default.default.readFile(this.feedbackFile, "utf-8");
19177
+ const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
18925
19178
  const updatedContent = this.addIssueToContent(content, issue, testCriteria);
18926
- await fs2__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
19179
+ await fs3__default.default.writeFile(this.feedbackFile, updatedContent, "utf-8");
18927
19180
  } catch (error) {
18928
19181
  throw new ValidationError(
18929
19182
  `Failed to save feedback: ${error}`,
@@ -18936,12 +19189,12 @@ var EnhancedFeedbackFileManager = class {
18936
19189
  */
18937
19190
  async repairMalformedFile() {
18938
19191
  try {
18939
- const content = await fs2__default.default.readFile(this.feedbackFile, "utf-8");
19192
+ const content = await fs3__default.default.readFile(this.feedbackFile, "utf-8");
18940
19193
  const hasOpenIssues = content.includes("<OPEN_ISSUES>");
18941
19194
  const hasClosingTag = content.includes("</OPEN_ISSUES>");
18942
19195
  if (!hasOpenIssues || !hasClosingTag) {
18943
19196
  const backupPath = this.feedbackFile + ".backup." + Date.now();
18944
- await fs2__default.default.writeFile(backupPath, content, "utf-8");
19197
+ await fs3__default.default.writeFile(backupPath, content, "utf-8");
18945
19198
  const existingIssues = this.extractIssuesFromMalformedContent(content);
18946
19199
  await this.createInitialFile(existingIssues);
18947
19200
  }
@@ -18973,8 +19226,8 @@ List any features you'd like to see added or bugs you've encountered.
18973
19226
 
18974
19227
  <!-- Resolved issues will be moved here -->
18975
19228
  `;
18976
- await fs2__default.default.ensureDir(path3__namespace.dirname(this.feedbackFile));
18977
- 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");
18978
19231
  }
18979
19232
  addIssueToContent(content, issue, testCriteria) {
18980
19233
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -19090,17 +19343,17 @@ async function handleCompactCommand(subArgs, options) {
19090
19343
  if (subArgs.length > 0) {
19091
19344
  for (const filePath of subArgs) {
19092
19345
  const resolvedPath = path3__namespace.resolve(filePath);
19093
- if (await fs2__default.default.pathExists(resolvedPath)) {
19346
+ if (await fs3__default.default.pathExists(resolvedPath)) {
19094
19347
  filesToCompact.push(resolvedPath);
19095
19348
  } else {
19096
19349
  console.warn(chalk15__default.default.yellow(`\u26A0\uFE0F File not found: ${filePath}`));
19097
19350
  }
19098
19351
  }
19099
19352
  } else {
19100
- if (await fs2__default.default.pathExists(defaultClaudeFile)) {
19353
+ if (await fs3__default.default.pathExists(defaultClaudeFile)) {
19101
19354
  filesToCompact.push(defaultClaudeFile);
19102
19355
  }
19103
- if (await fs2__default.default.pathExists(defaultAgentsFile)) {
19356
+ if (await fs3__default.default.pathExists(defaultAgentsFile)) {
19104
19357
  filesToCompact.push(defaultAgentsFile);
19105
19358
  }
19106
19359
  }
@@ -20034,11 +20287,11 @@ var GitManager = class {
20034
20287
  */
20035
20288
  async updateJunoTaskConfig(gitUrl) {
20036
20289
  const configPath = path3__namespace.join(this.workingDirectory, ".juno_task", "init.md");
20037
- if (!await fs2__default.default.pathExists(configPath)) {
20290
+ if (!await fs3__default.default.pathExists(configPath)) {
20038
20291
  return;
20039
20292
  }
20040
20293
  try {
20041
- let content = await fs2__default.default.readFile(configPath, "utf-8");
20294
+ let content = await fs3__default.default.readFile(configPath, "utf-8");
20042
20295
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
20043
20296
  if (frontmatterMatch) {
20044
20297
  let frontmatter = frontmatterMatch[1];
@@ -20059,7 +20312,7 @@ GIT_URL: ${gitUrl}
20059
20312
  `;
20060
20313
  content = frontmatter + content;
20061
20314
  }
20062
- await fs2__default.default.writeFile(configPath, content, "utf-8");
20315
+ await fs3__default.default.writeFile(configPath, content, "utf-8");
20063
20316
  } catch (error) {
20064
20317
  console.warn(`Warning: Failed to update juno-code configuration: ${error}`);
20065
20318
  }
@@ -20991,7 +21244,7 @@ var LogViewer = ({
20991
21244
  init_types();
20992
21245
  async function exportLogs(logger2, filepath, options) {
20993
21246
  try {
20994
- const fs21 = await import('fs-extra');
21247
+ const fs22 = await import('fs-extra');
20995
21248
  let entries = logger2.getRecentEntries(options.tail || 1e3);
20996
21249
  if (options.level) {
20997
21250
  const level = LogLevel[options.level.toUpperCase()];
@@ -21021,7 +21274,7 @@ async function exportLogs(logger2, filepath, options) {
21021
21274
  },
21022
21275
  entries
21023
21276
  };
21024
- await fs21.writeFile(filepath, JSON.stringify(exportData, null, 2));
21277
+ await fs22.writeFile(filepath, JSON.stringify(exportData, null, 2));
21025
21278
  console.log(chalk15__default.default.green(`\u2705 Exported ${entries.length} log entries to: ${filepath}`));
21026
21279
  } catch (error) {
21027
21280
  console.error(chalk15__default.default.red(`\u274C Failed to export logs: ${error}`));
@@ -22565,7 +22818,7 @@ function createServicesCommand() {
22565
22818
  const servicesCmd = new commander.Command("services").description("Manage juno-code service scripts").addHelpText("after", `
22566
22819
  Examples:
22567
22820
  $ juno-code services install Install service scripts to ~/.juno_code/services/
22568
- $ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py)
22821
+ $ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py/gemini.py)
22569
22822
  $ juno-code services list List installed service scripts
22570
22823
  $ juno-code services status Check installation status
22571
22824
  $ juno-code services uninstall Remove all service scripts
@@ -22822,10 +23075,10 @@ autoload -U compinit && compinit`;
22822
23075
  */
22823
23076
  async isSourceCommandPresent(configPath, sourceCommand) {
22824
23077
  try {
22825
- if (!await fs2__default.default.pathExists(configPath)) {
23078
+ if (!await fs3__default.default.pathExists(configPath)) {
22826
23079
  return false;
22827
23080
  }
22828
- const content = await fs2__default.default.readFile(configPath, "utf-8");
23081
+ const content = await fs3__default.default.readFile(configPath, "utf-8");
22829
23082
  return content.includes("juno-code completion");
22830
23083
  } catch {
22831
23084
  return false;
@@ -22847,15 +23100,15 @@ autoload -U compinit && compinit`;
22847
23100
  continue;
22848
23101
  }
22849
23102
  try {
22850
- const completionExists = await fs2__default.default.pathExists(shell.completionPath);
22851
- 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);
22852
23105
  const isSourced = configExists && await this.isSourceCommandPresent(
22853
23106
  shell.configPath,
22854
23107
  this.getSourceCommand(shell.name, shell.completionPath)
22855
23108
  );
22856
23109
  let lastInstalled;
22857
23110
  if (completionExists) {
22858
- const stats = await fs2__default.default.stat(shell.completionPath);
23111
+ const stats = await fs3__default.default.stat(shell.completionPath);
22859
23112
  lastInstalled = stats.mtime;
22860
23113
  }
22861
23114
  statuses.push({
@@ -22881,7 +23134,7 @@ autoload -U compinit && compinit`;
22881
23134
  async ensureCompletionDirectory(shell) {
22882
23135
  const completionPath = this.getCompletionPath(shell);
22883
23136
  const completionDir = path3__namespace.dirname(completionPath);
22884
- await fs2__default.default.ensureDir(completionDir);
23137
+ await fs3__default.default.ensureDir(completionDir);
22885
23138
  }
22886
23139
  /**
22887
23140
  * Ensure directory exists for shell configuration
@@ -22889,7 +23142,7 @@ autoload -U compinit && compinit`;
22889
23142
  async ensureConfigDirectory(shell) {
22890
23143
  const configPath = this.getConfigPath(shell);
22891
23144
  const configDir = path3__namespace.dirname(configPath);
22892
- await fs2__default.default.ensureDir(configDir);
23145
+ await fs3__default.default.ensureDir(configDir);
22893
23146
  }
22894
23147
  /**
22895
23148
  * Get shell version information
@@ -22913,15 +23166,15 @@ autoload -U compinit && compinit`;
22913
23166
  try {
22914
23167
  const configPath = this.getConfigPath(shell);
22915
23168
  const configDir = path3__namespace.dirname(configPath);
22916
- await fs2__default.default.access(configDir, fs2__default.default.constants.W_OK);
23169
+ await fs3__default.default.access(configDir, fs3__default.default.constants.W_OK);
22917
23170
  } catch {
22918
23171
  issues.push(`Cannot write to ${shell} configuration directory`);
22919
23172
  }
22920
23173
  try {
22921
23174
  const completionPath = this.getCompletionPath(shell);
22922
23175
  const completionDir = path3__namespace.dirname(completionPath);
22923
- await fs2__default.default.ensureDir(completionDir);
22924
- 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);
22925
23178
  } catch {
22926
23179
  issues.push(`Cannot write to ${shell} completion directory`);
22927
23180
  }
@@ -22992,10 +23245,10 @@ var ContextAwareCompletion = class {
22992
23245
  async getSessionIds() {
22993
23246
  try {
22994
23247
  const sessionDir = path3__namespace.join(process.cwd(), ".juno_task", "sessions");
22995
- if (!await fs2__default.default.pathExists(sessionDir)) {
23248
+ if (!await fs3__default.default.pathExists(sessionDir)) {
22996
23249
  return [];
22997
23250
  }
22998
- const sessions = await fs2__default.default.readdir(sessionDir);
23251
+ const sessions = await fs3__default.default.readdir(sessionDir);
22999
23252
  return sessions.filter((name) => name.match(/^session_\d+$/)).map((name) => name.replace("session_", "")).sort((a, b) => parseInt(b) - parseInt(a));
23000
23253
  } catch {
23001
23254
  return [];
@@ -23009,8 +23262,8 @@ var ContextAwareCompletion = class {
23009
23262
  const builtinTemplates = ["basic", "advanced", "research", "development"];
23010
23263
  const customTemplatesDir = path3__namespace.join(process.cwd(), ".juno_task", "templates");
23011
23264
  let customTemplates = [];
23012
- if (await fs2__default.default.pathExists(customTemplatesDir)) {
23013
- 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);
23014
23267
  customTemplates = files.filter((name) => name.endsWith(".md") || name.endsWith(".hbs")).map((name) => path3__namespace.basename(name, path3__namespace.extname(name)));
23015
23268
  }
23016
23269
  return [...builtinTemplates, ...customTemplates].sort();
@@ -23087,7 +23340,7 @@ var CompletionInstaller = class {
23087
23340
  await this.shellDetector.ensureConfigDirectory(shell);
23088
23341
  const script = this.generateEnhancedCompletion(shell, "juno-code");
23089
23342
  const completionPath = this.shellDetector.getCompletionPath(shell);
23090
- await fs2__default.default.writeFile(completionPath, script, "utf-8");
23343
+ await fs3__default.default.writeFile(completionPath, script, "utf-8");
23091
23344
  const configPath = this.shellDetector.getConfigPath(shell);
23092
23345
  const sourceCommand = this.shellDetector.getSourceCommand(shell, completionPath);
23093
23346
  const warnings = [];
@@ -23095,7 +23348,7 @@ var CompletionInstaller = class {
23095
23348
  const isPresent = await this.shellDetector.isSourceCommandPresent(configPath, sourceCommand);
23096
23349
  if (!isPresent) {
23097
23350
  try {
23098
- await fs2__default.default.appendFile(configPath, `
23351
+ await fs3__default.default.appendFile(configPath, `
23099
23352
 
23100
23353
  ${sourceCommand}
23101
23354
  `);
@@ -23126,8 +23379,8 @@ ${sourceCommand}
23126
23379
  async uninstall(shell) {
23127
23380
  try {
23128
23381
  const completionPath = this.shellDetector.getCompletionPath(shell);
23129
- if (await fs2__default.default.pathExists(completionPath)) {
23130
- await fs2__default.default.remove(completionPath);
23382
+ if (await fs3__default.default.pathExists(completionPath)) {
23383
+ await fs3__default.default.remove(completionPath);
23131
23384
  return true;
23132
23385
  }
23133
23386
  return false;
@@ -23141,7 +23394,7 @@ ${sourceCommand}
23141
23394
  async isInstalled(shell) {
23142
23395
  try {
23143
23396
  const completionPath = this.shellDetector.getCompletionPath(shell);
23144
- return await fs2__default.default.pathExists(completionPath);
23397
+ return await fs3__default.default.pathExists(completionPath);
23145
23398
  } catch {
23146
23399
  return false;
23147
23400
  }
@@ -23942,11 +24195,11 @@ function setupMainCommand(program) {
23942
24195
  );
23943
24196
  const allOptions2 = { ...definedGlobalOptions, ...options };
23944
24197
  if (!globalOptions.subagent && !options.prompt && !options.interactive && !options.interactivePrompt) {
23945
- const fs21 = await import('fs-extra');
23946
- const path23 = await import('path');
24198
+ const fs22 = await import('fs-extra');
24199
+ const path24 = await import('path');
23947
24200
  const cwd2 = process.cwd();
23948
- const junoTaskDir = path23.join(cwd2, ".juno_task");
23949
- if (await fs21.pathExists(junoTaskDir)) {
24201
+ const junoTaskDir = path24.join(cwd2, ".juno_task");
24202
+ if (await fs22.pathExists(junoTaskDir)) {
23950
24203
  console.log(chalk15__default.default.blue.bold("\u{1F3AF} Juno Code - Auto-detected Initialized Project\n"));
23951
24204
  try {
23952
24205
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -23963,12 +24216,12 @@ function setupMainCommand(program) {
23963
24216
  allOptions2.subagent = config.defaultSubagent;
23964
24217
  console.log(chalk15__default.default.gray(`\u{1F916} Using configured subagent: ${chalk15__default.default.cyan(config.defaultSubagent)}`));
23965
24218
  }
23966
- const promptFile = path23.join(junoTaskDir, "prompt.md");
23967
- if (!allOptions2.prompt && await fs21.pathExists(promptFile)) {
24219
+ const promptFile = path24.join(junoTaskDir, "prompt.md");
24220
+ if (!allOptions2.prompt && await fs22.pathExists(promptFile)) {
23968
24221
  allOptions2.prompt = promptFile;
23969
24222
  console.log(chalk15__default.default.gray(`\u{1F4C4} Using default prompt: ${chalk15__default.default.cyan(".juno_task/prompt.md")}`));
23970
24223
  }
23971
- if (allOptions2.subagent && (allOptions2.prompt || await fs21.pathExists(promptFile))) {
24224
+ if (allOptions2.subagent && (allOptions2.prompt || await fs22.pathExists(promptFile))) {
23972
24225
  console.log(chalk15__default.default.green("\u2713 Auto-detected project configuration\n"));
23973
24226
  const { mainCommandHandler: mainCommandHandler3 } = await Promise.resolve().then(() => (init_main(), main_exports));
23974
24227
  await mainCommandHandler3([], allOptions2, command);
@@ -24125,6 +24378,17 @@ async function main() {
24125
24378
  console.error("[DEBUG] Service auto-update failed:", error instanceof Error ? error.message : String(error));
24126
24379
  }
24127
24380
  }
24381
+ try {
24382
+ const { ScriptInstaller: ScriptInstaller2 } = await Promise.resolve().then(() => (init_script_installer(), script_installer_exports));
24383
+ const installed = await ScriptInstaller2.autoInstallMissing(process.cwd(), true);
24384
+ if (installed && (process.argv.includes("--verbose") || process.argv.includes("-v") || process.env.JUNO_CODE_DEBUG === "1")) {
24385
+ console.error("[DEBUG] Project scripts auto-installed to .juno_task/scripts/");
24386
+ }
24387
+ } catch (error) {
24388
+ if (process.env.JUNO_CODE_DEBUG === "1") {
24389
+ console.error("[DEBUG] Script auto-install failed:", error instanceof Error ? error.message : String(error));
24390
+ }
24391
+ }
24128
24392
  program.name("juno-code").description("TypeScript implementation of juno-code CLI tool for AI subagent orchestration").version(VERSION, "-V, --version", "Display version information").helpOption("-h, --help", "Display help information");
24129
24393
  setupGlobalOptions(program);
24130
24394
  const isVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");
@@ -24132,10 +24396,10 @@ async function main() {
24132
24396
  const isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V");
24133
24397
  const hasNoArguments = process.argv.length <= 2;
24134
24398
  const isInitCommand = process.argv.includes("init");
24135
- const 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);
24399
+ const fs22 = await import('fs-extra');
24400
+ const path24 = await import('path');
24401
+ const junoTaskDir = path24.join(process.cwd(), ".juno_task");
24402
+ const isInitialized = await fs22.pathExists(junoTaskDir);
24139
24403
  if (!isHelpOrVersion && !hasNoArguments && !isInitCommand && isInitialized) {
24140
24404
  try {
24141
24405
  const { validateStartupConfigs: validateStartupConfigs2 } = await Promise.resolve().then(() => (init_startup_validation(), startup_validation_exports));