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.js +151 -44
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +151 -45
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/templates/services/codex.py +11 -15
- package/package.json +1 -1
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
|
|
313
|
-
let servicesPath = path3.join(
|
|
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(
|
|
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
|
-
|
|
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
|
|
887
|
-
return
|
|
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(`
|
|
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
|
|
6644
|
-
* Handles both
|
|
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
|
-
|
|
6678
|
-
|
|
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
|
|
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
|
|
15674
|
-
const
|
|
15675
|
-
process.env.JUNO_TASK_MCP_SERVER_PATH || path3.join(
|
|
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
|
|
15742
|
-
const
|
|
15840
|
+
const __filename2 = fileURLToPath(import.meta.url);
|
|
15841
|
+
const __dirname2 = path3.dirname(__filename2);
|
|
15743
15842
|
let templatesScriptsDir;
|
|
15744
|
-
if (
|
|
15745
|
-
templatesScriptsDir = path3.join(
|
|
15746
|
-
} else if (
|
|
15747
|
-
templatesScriptsDir = path3.join(
|
|
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(
|
|
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
|
|
19438
|
-
backupPath = path3.join(
|
|
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
|
|
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");
|