juno-code 1.0.33 → 1.0.34

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
@@ -2,8 +2,8 @@
2
2
  import fs2 from 'fs-extra';
3
3
  import * as path3 from 'path';
4
4
  import path3__default, { dirname, join } from 'path';
5
- import * as os3 from 'os';
6
- import os3__default, { homedir, EOL } from 'os';
5
+ import * as os4 from 'os';
6
+ import os4__default, { homedir, EOL } from 'os';
7
7
  import { fileURLToPath } from 'url';
8
8
  import { createRequire } from 'module';
9
9
  import semver from 'semver';
@@ -3295,13 +3295,9 @@ var init_advanced_logger = __esm({
3295
3295
  /**
3296
3296
  * Output formatted log
3297
3297
  */
3298
- output(formatted, level) {
3298
+ output(formatted, _level) {
3299
3299
  if (this.options.output === "console" || this.options.output === "both") {
3300
- if (level >= 3 /* WARN */) {
3301
- console.error(formatted);
3302
- } else {
3303
- console.log(formatted);
3304
- }
3300
+ console.error(formatted);
3305
3301
  }
3306
3302
  if (this.options.output === "file" || this.options.output === "both") {
3307
3303
  this.writeToFile(formatted);
@@ -5997,7 +5993,7 @@ var init_client = __esm({
5997
5993
  `${serverName}`,
5998
5994
  // Assume it's in PATH
5999
5995
  `/usr/local/bin/${serverName}`,
6000
- path3__default.resolve(os3__default.homedir(), `.local/bin/${serverName}`),
5996
+ path3__default.resolve(os4__default.homedir(), `.local/bin/${serverName}`),
6001
5997
  path3__default.resolve(this.options.workingDirectory || process.cwd(), `${serverName}`)
6002
5998
  ];
6003
5999
  for (const serverPath of possiblePaths) {
@@ -7006,7 +7002,7 @@ var init_shell_backend = __esm({
7006
7002
  });
7007
7003
  try {
7008
7004
  const scriptPath = await this.findScriptForSubagent(subagentType);
7009
- const result = await this.executeScript(scriptPath, request, toolId);
7005
+ const result = await this.executeScript(scriptPath, request, toolId, subagentType);
7010
7006
  const duration = Date.now() - startTime;
7011
7007
  await this.emitProgressEvent({
7012
7008
  sessionId: request.metadata?.sessionId || "unknown",
@@ -7023,8 +7019,9 @@ var init_shell_backend = __esm({
7023
7019
  phase: "completion"
7024
7020
  }
7025
7021
  });
7022
+ const structuredResult = this.buildStructuredOutput(subagentType, result);
7026
7023
  return {
7027
- content: result.output,
7024
+ content: structuredResult.content,
7028
7025
  status: result.success ? "completed" : "failed",
7029
7026
  startTime: new Date(startTime),
7030
7027
  endTime: /* @__PURE__ */ new Date(),
@@ -7032,6 +7029,7 @@ var init_shell_backend = __esm({
7032
7029
  error: result.error ? { type: "shell_execution", message: result.error, timestamp: /* @__PURE__ */ new Date() } : void 0,
7033
7030
  progressEvents: [],
7034
7031
  // Progress events are handled via callbacks
7032
+ ...structuredResult.metadata ? { metadata: structuredResult.metadata } : void 0,
7035
7033
  request
7036
7034
  };
7037
7035
  } catch (error) {
@@ -7197,8 +7195,8 @@ var init_shell_backend = __esm({
7197
7195
  /**
7198
7196
  * Execute a shell script
7199
7197
  */
7200
- async executeScript(scriptPath, request, toolId) {
7201
- return new Promise((resolve9, reject) => {
7198
+ async executeScript(scriptPath, request, toolId, subagentType) {
7199
+ return new Promise(async (resolve9, reject) => {
7202
7200
  const startTime = Date.now();
7203
7201
  const isPython = scriptPath.endsWith(".py");
7204
7202
  const env2 = {
@@ -7211,6 +7209,19 @@ var init_shell_backend = __esm({
7211
7209
  JUNO_ITERATION: String(request.arguments?.iteration || 1),
7212
7210
  JUNO_TOOL_ID: toolId
7213
7211
  };
7212
+ let captureDir = null;
7213
+ let capturePath = null;
7214
+ if (subagentType === "claude") {
7215
+ try {
7216
+ captureDir = await promises.mkdtemp(path3.join(os4__default.tmpdir(), "juno-shell-"));
7217
+ capturePath = path3.join(captureDir, `subagent_${toolId}.json`);
7218
+ env2.JUNO_SUBAGENT_CAPTURE_PATH = capturePath;
7219
+ } catch (error) {
7220
+ if (this.config?.debug) {
7221
+ engineLogger.warn(`Failed to prepare subagent capture path: ${error instanceof Error ? error.message : String(error)}`);
7222
+ }
7223
+ }
7224
+ }
7214
7225
  const command = isPython ? "python3" : "bash";
7215
7226
  const args = [scriptPath];
7216
7227
  if (isPython && request.arguments?.instruction) {
@@ -7285,20 +7296,46 @@ var init_shell_backend = __esm({
7285
7296
  }
7286
7297
  });
7287
7298
  child.on("close", (exitCode) => {
7288
- if (isProcessKilled) return;
7289
- const duration = Date.now() - startTime;
7290
- const success = exitCode === 0;
7291
- if (this.config.debug) {
7292
- engineLogger.debug(`Script execution completed with exit code: ${exitCode}, duration: ${duration}ms`);
7293
- engineLogger.debug(`Stdout length: ${stdout2.length}, Stderr length: ${stderr.length}`);
7294
- }
7295
- resolve9({
7296
- success,
7297
- output: stdout2,
7298
- error: stderr || void 0,
7299
- exitCode: exitCode || 0,
7300
- duration
7301
- });
7299
+ void (async () => {
7300
+ if (isProcessKilled) return;
7301
+ const duration = Date.now() - startTime;
7302
+ const success = exitCode === 0;
7303
+ let subAgentResponse;
7304
+ if (capturePath) {
7305
+ try {
7306
+ const captured = await promises.readFile(capturePath, "utf-8");
7307
+ if (captured.trim()) {
7308
+ subAgentResponse = JSON.parse(captured);
7309
+ }
7310
+ } catch (error) {
7311
+ if (this.config?.debug) {
7312
+ engineLogger.warn(`Failed to read subagent capture: ${error instanceof Error ? error.message : String(error)}`);
7313
+ }
7314
+ } finally {
7315
+ if (captureDir) {
7316
+ try {
7317
+ await promises.rm(captureDir, { recursive: true, force: true });
7318
+ } catch (cleanupError) {
7319
+ if (this.config?.debug) {
7320
+ engineLogger.warn(`Failed to clean capture directory: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
7321
+ }
7322
+ }
7323
+ }
7324
+ }
7325
+ }
7326
+ if (this.config.debug) {
7327
+ engineLogger.debug(`Script execution completed with exit code: ${exitCode}, duration: ${duration}ms`);
7328
+ engineLogger.debug(`Stdout length: ${stdout2.length}, Stderr length: ${stderr.length}`);
7329
+ }
7330
+ resolve9({
7331
+ success,
7332
+ output: stdout2,
7333
+ error: stderr || void 0,
7334
+ exitCode: exitCode || 0,
7335
+ duration,
7336
+ ...subAgentResponse ? { subAgentResponse } : void 0
7337
+ });
7338
+ })();
7302
7339
  });
7303
7340
  child.on("error", (error) => {
7304
7341
  if (isProcessKilled) return;
@@ -7330,6 +7367,66 @@ var init_shell_backend = __esm({
7330
7367
  });
7331
7368
  });
7332
7369
  }
7370
+ /**
7371
+ * Build a structured, JSON-parsable result payload for programmatic capture while
7372
+ * preserving the shell backend's existing on-screen streaming behavior.
7373
+ */
7374
+ buildStructuredOutput(subagentType, result) {
7375
+ if (subagentType === "claude") {
7376
+ const claudeEvent = result.subAgentResponse ?? this.extractLastJsonEvent(result.output);
7377
+ const isError = claudeEvent?.is_error ?? claudeEvent?.subtype === "error" ?? !result.success;
7378
+ const structuredPayload = {
7379
+ type: "result",
7380
+ subtype: claudeEvent?.subtype || (isError ? "error" : "success"),
7381
+ is_error: isError,
7382
+ result: claudeEvent?.result ?? claudeEvent?.error ?? claudeEvent?.content ?? result.output,
7383
+ error: claudeEvent?.error,
7384
+ stderr: result.error,
7385
+ datetime: claudeEvent?.datetime,
7386
+ counter: claudeEvent?.counter,
7387
+ session_id: claudeEvent?.session_id,
7388
+ num_turns: claudeEvent?.num_turns,
7389
+ duration_ms: claudeEvent?.duration_ms ?? result.duration,
7390
+ exit_code: result.exitCode,
7391
+ total_cost_usd: claudeEvent?.total_cost_usd,
7392
+ usage: claudeEvent?.usage,
7393
+ modelUsage: claudeEvent?.modelUsage || claudeEvent?.model_usage || {},
7394
+ permission_denials: claudeEvent?.permission_denials || [],
7395
+ uuid: claudeEvent?.uuid,
7396
+ sub_agent_response: claudeEvent
7397
+ };
7398
+ const metadata = {
7399
+ ...claudeEvent ? { subAgentResponse: claudeEvent } : void 0,
7400
+ structuredOutput: true,
7401
+ contentType: "application/json",
7402
+ rawOutput: result.output
7403
+ };
7404
+ return {
7405
+ content: JSON.stringify(structuredPayload),
7406
+ metadata
7407
+ };
7408
+ }
7409
+ return { content: result.output, metadata: result.metadata };
7410
+ }
7411
+ /**
7412
+ * Extract the last valid JSON object from a script's stdout to use as a structured payload fallback.
7413
+ */
7414
+ extractLastJsonEvent(output) {
7415
+ if (!output) {
7416
+ return null;
7417
+ }
7418
+ const lines = output.split("\n").map((line) => line.trim()).filter(Boolean);
7419
+ for (let i = lines.length - 1; i >= 0; i--) {
7420
+ try {
7421
+ const parsed = JSON.parse(lines[i]);
7422
+ if (parsed && typeof parsed === "object") {
7423
+ return parsed;
7424
+ }
7425
+ } catch {
7426
+ }
7427
+ }
7428
+ return null;
7429
+ }
7333
7430
  /**
7334
7431
  * Parse streaming events from script output
7335
7432
  * Handles both JSON format (Claude) and TEXT format (Codex)
@@ -13069,7 +13166,11 @@ var init_main = __esm({
13069
13166
  \u274C Execution failed (${elapsed})`));
13070
13167
  }
13071
13168
  const lastIteration = result.iterations[result.iterations.length - 1];
13072
- if (lastIteration && lastIteration.toolResult.content && !this.hasStreamedJsonOutput) {
13169
+ const structuredOutput = lastIteration?.toolResult.metadata?.structuredOutput === true;
13170
+ const shouldPrintResult = Boolean(
13171
+ lastIteration && lastIteration.toolResult.content && (!this.hasStreamedJsonOutput || structuredOutput)
13172
+ );
13173
+ if (shouldPrintResult) {
13073
13174
  console.error(chalk15.blue("\n\u{1F4C4} Result:"));
13074
13175
  console.log(lastIteration.toolResult.content);
13075
13176
  }
@@ -13407,7 +13508,7 @@ async function validateJSONConfigs(baseDir = process.cwd(), backendType = "mcp")
13407
13508
  }
13408
13509
  function displayValidationResults(result) {
13409
13510
  if (result.isValid && result.warnings.length === 0) {
13410
- console.log(chalk15.green("\u2705 All configuration files are valid\n"));
13511
+ console.error(chalk15.green("\u2705 All configuration files are valid\n"));
13411
13512
  return;
13412
13513
  }
13413
13514
  if (result.errors.length > 0) {
@@ -21833,6 +21934,11 @@ var QUICK_REFERENCE = [
21833
21934
  description: "Shell completion setup",
21834
21935
  usage: "juno-code completion <install|uninstall>"
21835
21936
  },
21937
+ {
21938
+ name: "services",
21939
+ description: "Manage service scripts (use --force to refresh codex.py/claude.py)",
21940
+ usage: "juno-code services install --force"
21941
+ },
21836
21942
  {
21837
21943
  name: "help",
21838
21944
  description: "Show help information",
@@ -22401,11 +22507,12 @@ init_service_installer();
22401
22507
  function createServicesCommand() {
22402
22508
  const servicesCmd = new Command("services").description("Manage juno-code service scripts").addHelpText("after", `
22403
22509
  Examples:
22404
- $ juno-code services install Install service scripts to ~/.juno_code/services/
22405
- $ juno-code services list List installed service scripts
22406
- $ juno-code services status Check installation status
22407
- $ juno-code services uninstall Remove all service scripts
22408
- $ juno-code services path Show services directory path
22510
+ $ juno-code services install Install service scripts to ~/.juno_code/services/
22511
+ $ juno-code services install --force Reinstall/refresh service scripts (codex.py/claude.py)
22512
+ $ juno-code services list List installed service scripts
22513
+ $ juno-code services status Check installation status
22514
+ $ juno-code services uninstall Remove all service scripts
22515
+ $ juno-code services path Show services directory path
22409
22516
 
22410
22517
  Service scripts are Python/shell scripts that provide additional functionality
22411
22518
  and can be customized by users. They are installed to ~/.juno_code/services/
@@ -22579,7 +22686,7 @@ var ShellDetector = class _ShellDetector {
22579
22686
  * Get shell configuration file path
22580
22687
  */
22581
22688
  getConfigPath(shell) {
22582
- const homeDir = os3.homedir();
22689
+ const homeDir = os4.homedir();
22583
22690
  switch (shell) {
22584
22691
  case "bash":
22585
22692
  if (process.platform === "darwin") {
@@ -22603,7 +22710,7 @@ var ShellDetector = class _ShellDetector {
22603
22710
  * Get shell completion script installation path
22604
22711
  */
22605
22712
  getCompletionPath(shell) {
22606
- const homeDir = os3.homedir();
22713
+ const homeDir = os4.homedir();
22607
22714
  switch (shell) {
22608
22715
  case "bash":
22609
22716
  if (process.platform === "darwin") {
@@ -22881,7 +22988,7 @@ var ContextAwareCompletion = class {
22881
22988
  */
22882
22989
  expandPath(inputPath) {
22883
22990
  if (inputPath.startsWith("~/")) {
22884
- return path3.join(os3.homedir(), inputPath.slice(2));
22991
+ return path3.join(os4.homedir(), inputPath.slice(2));
22885
22992
  }
22886
22993
  if (inputPath.startsWith("./") || inputPath.startsWith("../")) {
22887
22994
  return path3.resolve(inputPath);