juno-code 1.0.17 → 1.0.20

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.mjs CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import fs3 from 'fs-extra';
3
3
  import * as path3 from 'path';
4
- import path3__default from 'path';
4
+ import path3__default, { dirname, join } from 'path';
5
5
  import * as os2 from 'os';
6
6
  import os2__default, { homedir, EOL } from 'os';
7
7
  import { fileURLToPath } from 'url';
8
+ import { createRequire } from 'module';
9
+ import semver from 'semver';
8
10
  import { z } from 'zod';
9
11
  import * as nodeFs from 'fs';
10
12
  import { promises } from 'fs';
@@ -305,16 +307,80 @@ var init_service_installer = __esm({
305
307
  init_version();
306
308
  ServiceInstaller = class {
307
309
  static SERVICES_DIR = path3.join(homedir(), ".juno_code", "services");
310
+ static VERSION_FILE = path3.join(homedir(), ".juno_code", "services", ".version");
311
+ /**
312
+ * Get the current package version
313
+ */
314
+ static getPackageVersion() {
315
+ try {
316
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
317
+ const require3 = createRequire(import.meta.url);
318
+ let packageJsonPath = path3.join(__dirname2, "..", "..", "package.json");
319
+ if (fs3.existsSync(packageJsonPath)) {
320
+ const packageJson2 = require3(packageJsonPath);
321
+ return packageJson2.version;
322
+ }
323
+ packageJsonPath = path3.join(__dirname2, "..", "..", "..", "package.json");
324
+ if (fs3.existsSync(packageJsonPath)) {
325
+ const packageJson2 = require3(packageJsonPath);
326
+ return packageJson2.version;
327
+ }
328
+ return "0.0.0";
329
+ } catch {
330
+ return "0.0.0";
331
+ }
332
+ }
333
+ /**
334
+ * Get the installed services version
335
+ */
336
+ static async getInstalledVersion() {
337
+ try {
338
+ const exists = await fs3.pathExists(this.VERSION_FILE);
339
+ if (!exists) {
340
+ return null;
341
+ }
342
+ const version3 = await fs3.readFile(this.VERSION_FILE, "utf-8");
343
+ return version3.trim();
344
+ } catch {
345
+ return null;
346
+ }
347
+ }
348
+ /**
349
+ * Save the current package version to the version file
350
+ */
351
+ static async saveVersion() {
352
+ const version3 = this.getPackageVersion();
353
+ await fs3.writeFile(this.VERSION_FILE, version3, "utf-8");
354
+ }
355
+ /**
356
+ * Check if services need to be updated based on version
357
+ */
358
+ static async needsUpdate() {
359
+ try {
360
+ const packageVersion = this.getPackageVersion();
361
+ const installedVersion = await this.getInstalledVersion();
362
+ if (!installedVersion) {
363
+ return true;
364
+ }
365
+ const exists = await fs3.pathExists(this.SERVICES_DIR);
366
+ if (!exists) {
367
+ return true;
368
+ }
369
+ return semver.gt(packageVersion, installedVersion);
370
+ } catch {
371
+ return true;
372
+ }
373
+ }
308
374
  /**
309
375
  * Get the path to the services directory in the package
310
376
  */
311
377
  static getPackageServicesDir() {
312
- const __dirname = path3.dirname(fileURLToPath(import.meta.url));
313
- let servicesPath = path3.join(__dirname, "..", "..", "templates", "services");
378
+ const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
379
+ let servicesPath = path3.join(__dirname2, "..", "..", "templates", "services");
314
380
  if (fs3.existsSync(servicesPath)) {
315
381
  return servicesPath;
316
382
  }
317
- servicesPath = path3.join(__dirname, "..", "templates", "services");
383
+ servicesPath = path3.join(__dirname2, "..", "templates", "services");
318
384
  if (fs3.existsSync(servicesPath)) {
319
385
  return servicesPath;
320
386
  }
@@ -322,8 +388,9 @@ var init_service_installer = __esm({
322
388
  }
323
389
  /**
324
390
  * Install all service scripts to ~/.juno_code/services/
391
+ * @param silent - If true, suppresses console output
325
392
  */
326
- static async install() {
393
+ static async install(silent = false) {
327
394
  try {
328
395
  await fs3.ensureDir(this.SERVICES_DIR);
329
396
  const packageServicesDir = this.getPackageServicesDir();
@@ -339,11 +406,30 @@ var init_service_installer = __esm({
339
406
  await fs3.chmod(filePath, 493);
340
407
  }
341
408
  }
342
- console.log(`\u2713 Services installed to: ${this.SERVICES_DIR}`);
409
+ await this.saveVersion();
410
+ if (!silent) {
411
+ console.log(`\u2713 Services installed to: ${this.SERVICES_DIR}`);
412
+ }
343
413
  } catch (error) {
344
414
  throw new Error(`Failed to install services: ${error instanceof Error ? error.message : String(error)}`);
345
415
  }
346
416
  }
417
+ /**
418
+ * Automatically update services if needed (silent operation)
419
+ * This should be called on every CLI run to ensure services are up-to-date
420
+ */
421
+ static async autoUpdate() {
422
+ try {
423
+ const needsUpdate = await this.needsUpdate();
424
+ if (needsUpdate) {
425
+ await this.install(true);
426
+ return true;
427
+ }
428
+ return false;
429
+ } catch {
430
+ return false;
431
+ }
432
+ }
347
433
  /**
348
434
  * Check if services are installed
349
435
  */
@@ -883,8 +969,8 @@ async function loadYamlConfig(filePath) {
883
969
  async function loadPackageJsonConfig(filePath) {
884
970
  try {
885
971
  const content = await promises.readFile(filePath, "utf-8");
886
- const packageJson = JSON.parse(content);
887
- return packageJson.junoCode || {};
972
+ const packageJson2 = JSON.parse(content);
973
+ return packageJson2.junoCode || {};
888
974
  } catch (error) {
889
975
  throw new Error(`Failed to load package.json config from ${filePath}: ${error}`);
890
976
  }
@@ -6581,7 +6667,7 @@ var init_shell_backend = __esm({
6581
6667
  this.parseAndEmitStreamingEvents(data, request.metadata?.sessionId || "unknown");
6582
6668
  } catch (error) {
6583
6669
  if (this.config.debug) {
6584
- engineLogger.warn(`JSON streaming parse error: ${error instanceof Error ? error.message : String(error)}`);
6670
+ engineLogger.warn(`Streaming parse error: ${error instanceof Error ? error.message : String(error)}`);
6585
6671
  }
6586
6672
  }
6587
6673
  }
@@ -6640,8 +6726,13 @@ var init_shell_backend = __esm({
6640
6726
  });
6641
6727
  }
6642
6728
  /**
6643
- * Parse JSON streaming events from script output
6644
- * Handles both generic StreamingEvent format and Claude CLI specific format
6729
+ * Parse streaming events from script output
6730
+ * Handles both JSON format (Claude) and TEXT format (Codex)
6731
+ *
6732
+ * Strategy:
6733
+ * 1. Try to parse each line as JSON first (for Claude)
6734
+ * 2. If JSON parsing fails, treat as TEXT streaming (for Codex and other text-based subagents)
6735
+ * 3. Emit all non-empty lines as progress events for real-time display
6645
6736
  */
6646
6737
  parseAndEmitStreamingEvents(data, sessionId) {
6647
6738
  if (!this.jsonBuffer) {
@@ -6653,11 +6744,13 @@ var init_shell_backend = __esm({
6653
6744
  for (const line of lines) {
6654
6745
  const trimmedLine = line.trim();
6655
6746
  if (!trimmedLine) continue;
6747
+ let isJsonParsed = false;
6656
6748
  try {
6657
6749
  const jsonEvent = JSON.parse(trimmedLine);
6658
6750
  let progressEvent;
6659
6751
  if (this.isClaudeCliEvent(jsonEvent)) {
6660
6752
  progressEvent = this.convertClaudeEventToProgress(jsonEvent, sessionId, trimmedLine);
6753
+ isJsonParsed = true;
6661
6754
  } else if (this.isGenericStreamingEvent(jsonEvent)) {
6662
6755
  progressEvent = {
6663
6756
  sessionId,
@@ -6668,33 +6761,39 @@ var init_shell_backend = __esm({
6668
6761
  content: jsonEvent.content,
6669
6762
  metadata: jsonEvent.metadata
6670
6763
  };
6764
+ isJsonParsed = true;
6671
6765
  } else {
6672
6766
  if (this.config?.debug) {
6673
- engineLogger.debug(`Unknown JSON format: ${trimmedLine}`);
6767
+ engineLogger.debug(`Unknown JSON format, treating as text: ${trimmedLine}`);
6674
6768
  }
6675
- continue;
6676
6769
  }
6677
- this.emitProgressEvent(progressEvent).catch((error) => {
6678
- if (this.config?.debug) {
6679
- engineLogger.warn(`Failed to emit progress event: ${error instanceof Error ? error.message : String(error)}`);
6680
- }
6681
- });
6682
- } catch (error) {
6683
- if (trimmedLine.length > 0 && !trimmedLine.startsWith("#")) {
6684
- this.emitProgressEvent({
6685
- sessionId,
6686
- timestamp: /* @__PURE__ */ new Date(),
6687
- backend: "shell",
6688
- count: ++this.eventCounter,
6689
- type: "thinking",
6690
- content: trimmedLine,
6691
- metadata: { raw: true, parseError: true }
6692
- }).catch((error2) => {
6770
+ if (isJsonParsed) {
6771
+ this.emitProgressEvent(progressEvent).catch((error) => {
6693
6772
  if (this.config?.debug) {
6694
- engineLogger.warn(`Failed to emit thinking event: ${error2 instanceof Error ? error2.message : String(error2)}`);
6773
+ engineLogger.warn(`Failed to emit progress event: ${error instanceof Error ? error.message : String(error)}`);
6695
6774
  }
6696
6775
  });
6697
6776
  }
6777
+ } catch (error) {
6778
+ isJsonParsed = false;
6779
+ }
6780
+ if (!isJsonParsed && trimmedLine.length > 0) {
6781
+ this.emitProgressEvent({
6782
+ sessionId,
6783
+ timestamp: /* @__PURE__ */ new Date(),
6784
+ backend: "shell",
6785
+ count: ++this.eventCounter,
6786
+ type: "thinking",
6787
+ content: trimmedLine,
6788
+ metadata: {
6789
+ format: "text",
6790
+ raw: true
6791
+ }
6792
+ }).catch((error) => {
6793
+ if (this.config?.debug) {
6794
+ engineLogger.warn(`Failed to emit text streaming event: ${error instanceof Error ? error.message : String(error)}`);
6795
+ }
6796
+ });
6698
6797
  }
6699
6798
  }
6700
6799
  }
@@ -15670,9 +15769,9 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
15670
15769
  async createMcpFile(junoTaskDir, targetDirectory) {
15671
15770
  const projectName = path3.basename(targetDirectory);
15672
15771
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
15673
- const __filename = fileURLToPath(import.meta.url);
15674
- const __dirname = path3.dirname(__filename);
15675
- process.env.JUNO_TASK_MCP_SERVER_PATH || path3.join(__dirname, "../../../roundtable_mcp_server/roundtable_mcp_server/server.py");
15772
+ const __filename2 = fileURLToPath(import.meta.url);
15773
+ const __dirname2 = path3.dirname(__filename2);
15774
+ process.env.JUNO_TASK_MCP_SERVER_PATH || path3.join(__dirname2, "../../../roundtable_mcp_server/roundtable_mcp_server/server.py");
15676
15775
  const mcpContent = {
15677
15776
  mcpServers: {
15678
15777
  "roundtable-ai": {
@@ -15738,15 +15837,15 @@ ${variables.EDITOR ? `using ${variables.EDITOR} as primary AI subagent` : ""}
15738
15837
  try {
15739
15838
  const scriptsDir = path3.join(junoTaskDir, "scripts");
15740
15839
  await fs3.ensureDir(scriptsDir);
15741
- const __filename = fileURLToPath(import.meta.url);
15742
- const __dirname = path3.dirname(__filename);
15840
+ const __filename2 = fileURLToPath(import.meta.url);
15841
+ const __dirname2 = path3.dirname(__filename2);
15743
15842
  let templatesScriptsDir;
15744
- if (__dirname.includes("/dist/bin") || __dirname.includes("\\dist\\bin")) {
15745
- templatesScriptsDir = path3.join(__dirname, "../templates/scripts");
15746
- } else if (__dirname.includes("/src/cli/commands") || __dirname.includes("\\src\\cli\\commands")) {
15747
- templatesScriptsDir = path3.join(__dirname, "../../templates/scripts");
15843
+ if (__dirname2.includes("/dist/bin") || __dirname2.includes("\\dist\\bin")) {
15844
+ templatesScriptsDir = path3.join(__dirname2, "../templates/scripts");
15845
+ } else if (__dirname2.includes("/src/cli/commands") || __dirname2.includes("\\src\\cli\\commands")) {
15846
+ templatesScriptsDir = path3.join(__dirname2, "../../templates/scripts");
15748
15847
  } else {
15749
- templatesScriptsDir = path3.join(__dirname, "../../templates/scripts");
15848
+ templatesScriptsDir = path3.join(__dirname2, "../../templates/scripts");
15750
15849
  }
15751
15850
  if (!await fs3.pathExists(templatesScriptsDir)) {
15752
15851
  console.log(chalk12.yellow(" \u26A0\uFE0F Template scripts directory not found, skipping script installation"));
@@ -19434,8 +19533,8 @@ async function compactConfigFile(filePath, options = {}) {
19434
19533
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19435
19534
  const ext = path3.extname(filePath);
19436
19535
  const basename11 = path3.basename(filePath, ext);
19437
- const dirname11 = path3.dirname(filePath);
19438
- backupPath = path3.join(dirname11, `${basename11}.backup.${timestamp}${ext}`);
19536
+ const dirname12 = path3.dirname(filePath);
19537
+ backupPath = path3.join(dirname12, `${basename11}.backup.${timestamp}${ext}`);
19439
19538
  await fs3.writeFile(backupPath, originalContent, "utf-8");
19440
19539
  }
19441
19540
  const compactionAnalysis = analyzeMarkdownStructure(originalContent);
@@ -24782,11 +24881,13 @@ var CompletionCommand = class {
24782
24881
  }
24783
24882
  };
24784
24883
  var completion_default = CompletionCommand;
24785
-
24786
- // src/bin/cli.ts
24787
24884
  inspect.defaultOptions.maxStringLength = Infinity;
24788
24885
  inspect.defaultOptions.breakLength = Infinity;
24789
- var VERSION = "1.0.0";
24886
+ var __filename = fileURLToPath(import.meta.url);
24887
+ var __dirname = dirname(__filename);
24888
+ var require2 = createRequire(import.meta.url);
24889
+ var packageJson = require2(join(__dirname, "../../package.json"));
24890
+ var VERSION = packageJson.version;
24790
24891
  function isConnectionLikeError(err) {
24791
24892
  const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
24792
24893
  const lower = msg.toLowerCase();
@@ -25011,6 +25112,11 @@ function configureEnvironment() {
25011
25112
  async function main() {
25012
25113
  const program = new Command();
25013
25114
  configureEnvironment();
25115
+ try {
25116
+ const { ServiceInstaller: ServiceInstaller2 } = await Promise.resolve().then(() => (init_service_installer(), service_installer_exports));
25117
+ await ServiceInstaller2.autoUpdate();
25118
+ } catch {
25119
+ }
25014
25120
  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");
25015
25121
  setupGlobalOptions(program);
25016
25122
  const isVerbose = process.argv.includes("--verbose") || process.argv.includes("-v");