juno-code 1.0.51 → 1.0.53

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
@@ -13,9 +13,9 @@ var yaml = require('js-yaml');
13
13
  var crypto = require('crypto');
14
14
  var chalk21 = require('chalk');
15
15
  var execa = require('execa');
16
- var child_process = require('child_process');
17
- var events = require('events');
16
+ var childProcess = require('child_process');
18
17
  var util = require('util');
18
+ var events = require('events');
19
19
  var commander = require('commander');
20
20
  var readline = require('readline');
21
21
  var uuid = require('uuid');
@@ -54,6 +54,7 @@ var semver__default = /*#__PURE__*/_interopDefault(semver);
54
54
  var fs8__namespace = /*#__PURE__*/_interopNamespace(fs8);
55
55
  var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
56
56
  var chalk21__default = /*#__PURE__*/_interopDefault(chalk21);
57
+ var childProcess__namespace = /*#__PURE__*/_interopNamespace(childProcess);
57
58
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
58
59
  var process2__namespace = /*#__PURE__*/_interopNamespace(process2);
59
60
  var Table__default = /*#__PURE__*/_interopDefault(Table);
@@ -292,14 +293,14 @@ function isModelCompatibleWithSubagent(model, subagent) {
292
293
  }
293
294
  }
294
295
  function getConfiguredDefaultModelForSubagent(config, subagent) {
295
- const legacyDefaultModel = config.defaultSubagent === subagent && typeof config.defaultModel === "string" && isModelCompatibleWithSubagent(config.defaultModel, subagent) ? config.defaultModel : void 0;
296
- if (legacyDefaultModel) {
297
- return legacyDefaultModel;
298
- }
299
296
  const modelFromMap = config.defaultModels?.[subagent];
300
297
  if (typeof modelFromMap === "string" && isModelCompatibleWithSubagent(modelFromMap, subagent)) {
301
298
  return modelFromMap;
302
299
  }
300
+ const legacyDefaultModel = config.defaultSubagent === subagent && typeof config.defaultModel === "string" && isModelCompatibleWithSubagent(config.defaultModel, subagent) ? config.defaultModel : void 0;
301
+ if (legacyDefaultModel) {
302
+ return legacyDefaultModel;
303
+ }
303
304
  return void 0;
304
305
  }
305
306
  var SUBAGENT_DEFAULT_MODELS;
@@ -867,6 +868,13 @@ async function ensureHooksConfig(baseDir) {
867
868
  existingConfig.defaultModels = baseDefaults;
868
869
  needsUpdate = true;
869
870
  }
871
+ const selectedSubagentRaw = typeof existingConfig.defaultSubagent === "string" ? existingConfig.defaultSubagent : "claude";
872
+ const selectedSubagent = selectedSubagentRaw in SUBAGENT_DEFAULT_MODELS ? selectedSubagentRaw : "claude";
873
+ const selectedMapModel = existingConfig.defaultModels && typeof existingConfig.defaultModels === "object" ? existingConfig.defaultModels[selectedSubagent] : void 0;
874
+ if (typeof selectedMapModel === "string" && isModelCompatibleWithSubagent(selectedMapModel, selectedSubagent) && existingConfig.defaultModel !== selectedMapModel) {
875
+ existingConfig.defaultModel = selectedMapModel;
876
+ needsUpdate = true;
877
+ }
870
878
  if (existingConfig.defaultMaxIterations === 50) {
871
879
  existingConfig.defaultMaxIterations = DEFAULT_CONFIG.defaultMaxIterations;
872
880
  needsUpdate = true;
@@ -2391,25 +2399,28 @@ var init_shell_backend = __esm({
2391
2399
  const scriptPath = await this.findScriptForSubagent(subagentType);
2392
2400
  const result = await this.executeScript(scriptPath, request, toolId, subagentType);
2393
2401
  const duration = Date.now() - startTime;
2402
+ const structuredResult = this.buildStructuredOutput(subagentType, result);
2403
+ const structuredPayload = this.parseStructuredResultPayload(structuredResult.content);
2404
+ const structuredIndicatesError = structuredPayload?.is_error === true || structuredPayload?.subtype === "error";
2405
+ const executionSucceeded = result.success && !structuredIndicatesError;
2394
2406
  await this.emitProgressEvent({
2395
2407
  sessionId: request.metadata?.sessionId || "unknown",
2396
2408
  timestamp: /* @__PURE__ */ new Date(),
2397
2409
  backend: "shell",
2398
2410
  count: ++this.eventCounter,
2399
2411
  type: "tool_result" /* TOOL_RESULT */,
2400
- content: `${request.toolName} completed successfully (${duration}ms)`,
2412
+ content: executionSucceeded ? `${request.toolName} completed successfully (${duration}ms)` : `${request.toolName} completed with error (${duration}ms)`,
2401
2413
  toolId,
2402
2414
  metadata: {
2403
2415
  toolName: request.toolName,
2404
2416
  duration,
2405
- success: result.success,
2417
+ success: executionSucceeded,
2406
2418
  phase: "completion"
2407
2419
  }
2408
2420
  });
2409
- const structuredResult = this.buildStructuredOutput(subagentType, result);
2410
2421
  const toolResult = {
2411
2422
  content: structuredResult.content,
2412
- status: result.success ? "completed" /* COMPLETED */ : "failed" /* FAILED */,
2423
+ status: executionSucceeded ? "completed" /* COMPLETED */ : "failed" /* FAILED */,
2413
2424
  startTime: new Date(startTime),
2414
2425
  endTime: /* @__PURE__ */ new Date(),
2415
2426
  duration,
@@ -2418,6 +2429,9 @@ var init_shell_backend = __esm({
2418
2429
  };
2419
2430
  if (result.error) {
2420
2431
  toolResult.error = new Error(result.error);
2432
+ } else if (!executionSucceeded) {
2433
+ const structuredErrorMessage = typeof structuredPayload?.error === "string" && structuredPayload.error || typeof structuredPayload?.result === "string" && structuredPayload.result || `${request.toolName} reported a structured error`;
2434
+ toolResult.error = new Error(structuredErrorMessage);
2421
2435
  }
2422
2436
  if (structuredResult.metadata) {
2423
2437
  toolResult.metadata = structuredResult.metadata;
@@ -2669,6 +2683,9 @@ var init_shell_backend = __esm({
2669
2683
  if (isPython && subagentType === "pi" && request.arguments?.live === true) {
2670
2684
  args.push("--live");
2671
2685
  }
2686
+ if (isPython && subagentType === "pi" && request.arguments?.liveInteractiveSession === true) {
2687
+ args.push("--live-manual");
2688
+ }
2672
2689
  if (isPython && this.config.debug) {
2673
2690
  args.push("--verbose");
2674
2691
  }
@@ -2693,7 +2710,7 @@ var init_shell_backend = __esm({
2693
2710
  `Pi live mode stdio: ${shouldAttachLiveTerminal ? "inherit (interactive TTY or stdout-tty fallback)" : "pipe (headless/non-TTY)"}`
2694
2711
  );
2695
2712
  }
2696
- const child = child_process.spawn(command, args, {
2713
+ const child = childProcess.spawn(command, args, {
2697
2714
  env: env2,
2698
2715
  cwd: this.config.workingDirectory,
2699
2716
  stdio: shouldAttachLiveTerminal ? "inherit" : ["pipe", "pipe", "pipe"]
@@ -2951,8 +2968,19 @@ var init_shell_backend = __esm({
2951
2968
  if (subagentType === "pi") {
2952
2969
  const piEvent = result.subAgentResponse ?? this.extractLastJsonEvent(result.output);
2953
2970
  if (piEvent) {
2954
- let resultText = piEvent.result;
2955
- if (!resultText && Array.isArray(piEvent.messages)) {
2971
+ const piNestedEvent = typeof piEvent.sub_agent_response === "object" && piEvent.sub_agent_response ? piEvent.sub_agent_response : void 0;
2972
+ const piSessionId = typeof piEvent.session_id === "string" && piEvent.session_id ? piEvent.session_id : typeof piEvent.sessionId === "string" && piEvent.sessionId ? piEvent.sessionId : typeof piEvent.id === "string" && piEvent.type === "session" ? piEvent.id : typeof piNestedEvent?.session_id === "string" && piNestedEvent.session_id ? piNestedEvent.session_id : typeof piNestedEvent?.sessionId === "string" && piNestedEvent.sessionId ? piNestedEvent.sessionId : typeof piNestedEvent?.id === "string" && piNestedEvent.type === "session" ? piNestedEvent.id : typeof piEvent.sub_agent_response?.session_id === "string" && piEvent.sub_agent_response.session_id ? piEvent.sub_agent_response.session_id : void 0;
2973
+ const sanitizedPiEvent = { ...piEvent };
2974
+ delete sanitizedPiEvent.messages;
2975
+ if (sanitizedPiEvent.sub_agent_response && typeof sanitizedPiEvent.sub_agent_response === "object") {
2976
+ const inner = { ...sanitizedPiEvent.sub_agent_response };
2977
+ delete inner.messages;
2978
+ delete inner.type;
2979
+ sanitizedPiEvent.sub_agent_response = inner;
2980
+ }
2981
+ const hasDirectResultText = typeof piEvent.result === "string";
2982
+ let resultText = hasDirectResultText ? piEvent.result : void 0;
2983
+ if (resultText === void 0 && Array.isArray(piEvent.messages)) {
2956
2984
  for (let i = piEvent.messages.length - 1; i >= 0; i--) {
2957
2985
  const msg = piEvent.messages[i];
2958
2986
  if (msg?.role === "assistant") {
@@ -2972,16 +3000,11 @@ var init_shell_backend = __esm({
2972
3000
  }
2973
3001
  }
2974
3002
  }
2975
- if (resultText) {
3003
+ if (resultText === void 0 && typeof piEvent.error === "string") {
3004
+ resultText = piEvent.error;
3005
+ }
3006
+ if (resultText !== void 0) {
2976
3007
  const isError = piEvent.is_error ?? !result.success;
2977
- const sanitizedPiEvent = { ...piEvent };
2978
- delete sanitizedPiEvent.messages;
2979
- if (sanitizedPiEvent.sub_agent_response && typeof sanitizedPiEvent.sub_agent_response === "object") {
2980
- const inner = { ...sanitizedPiEvent.sub_agent_response };
2981
- delete inner.messages;
2982
- delete inner.type;
2983
- sanitizedPiEvent.sub_agent_response = inner;
2984
- }
2985
3008
  const usage = piEvent.usage;
2986
3009
  const totalCostUsd = typeof piEvent.total_cost_usd === "number" ? piEvent.total_cost_usd : typeof usage?.cost?.total === "number" ? usage.cost.total : void 0;
2987
3010
  const structuredPayload = {
@@ -2989,9 +3012,9 @@ var init_shell_backend = __esm({
2989
3012
  subtype: piEvent.subtype || (isError ? "error" : "success"),
2990
3013
  is_error: isError,
2991
3014
  result: resultText,
2992
- error: piEvent.error,
3015
+ error: isError ? piEvent.error ?? result.error ?? resultText : piEvent.error,
2993
3016
  stderr: result.error,
2994
- session_id: piEvent.session_id,
3017
+ session_id: piSessionId,
2995
3018
  exit_code: result.exitCode,
2996
3019
  duration_ms: piEvent.duration_ms ?? result.duration,
2997
3020
  total_cost_usd: totalCostUsd,
@@ -3009,6 +3032,57 @@ var init_shell_backend = __esm({
3009
3032
  metadata
3010
3033
  };
3011
3034
  }
3035
+ const isSessionSnapshotOnly = piEvent.type === "session" || piEvent.subtype === "session";
3036
+ if (isSessionSnapshotOnly) {
3037
+ const errorMessage = result.error?.trim() || "Pi exited before emitting a terminal result event (session snapshot only).";
3038
+ const structuredPayload = {
3039
+ type: "result",
3040
+ subtype: "error",
3041
+ is_error: true,
3042
+ result: errorMessage,
3043
+ error: errorMessage,
3044
+ stderr: result.error,
3045
+ session_id: piSessionId,
3046
+ exit_code: result.exitCode,
3047
+ duration_ms: result.duration,
3048
+ sub_agent_response: sanitizedPiEvent
3049
+ };
3050
+ const metadata = {
3051
+ ...piEvent ? { subAgentResponse: piEvent } : void 0,
3052
+ structuredOutput: true,
3053
+ contentType: "application/json",
3054
+ rawOutput: result.output
3055
+ };
3056
+ return {
3057
+ content: JSON.stringify(structuredPayload),
3058
+ metadata
3059
+ };
3060
+ }
3061
+ if (!result.success) {
3062
+ const errorMessage = result.error?.trim() || result.output?.trim() || "Unknown error";
3063
+ const structuredPayload = {
3064
+ type: "result",
3065
+ subtype: "error",
3066
+ is_error: true,
3067
+ result: errorMessage,
3068
+ error: errorMessage,
3069
+ stderr: result.error,
3070
+ session_id: piSessionId,
3071
+ exit_code: result.exitCode,
3072
+ duration_ms: result.duration,
3073
+ sub_agent_response: sanitizedPiEvent
3074
+ };
3075
+ const metadata = {
3076
+ ...piEvent ? { subAgentResponse: piEvent } : void 0,
3077
+ structuredOutput: true,
3078
+ contentType: "application/json",
3079
+ rawOutput: result.output
3080
+ };
3081
+ return {
3082
+ content: JSON.stringify(structuredPayload),
3083
+ metadata
3084
+ };
3085
+ }
3012
3086
  }
3013
3087
  }
3014
3088
  if (!result.success) {
@@ -3073,6 +3147,20 @@ var init_shell_backend = __esm({
3073
3147
  }
3074
3148
  return null;
3075
3149
  }
3150
+ /**
3151
+ * Parse JSON structured output payload emitted by shell service wrappers.
3152
+ */
3153
+ parseStructuredResultPayload(content) {
3154
+ try {
3155
+ const parsed = JSON.parse(content);
3156
+ if (!parsed || typeof parsed !== "object") {
3157
+ return null;
3158
+ }
3159
+ return parsed;
3160
+ } catch {
3161
+ return null;
3162
+ }
3163
+ }
3076
3164
  /**
3077
3165
  * Extract the last valid JSON object from a script's stdout to use as a structured payload fallback.
3078
3166
  */
@@ -3331,6 +3419,179 @@ var init_shell_backend = __esm({
3331
3419
  };
3332
3420
  }
3333
3421
  });
3422
+ function findPromptCommandSubstitutions(prompt) {
3423
+ const matches = [];
3424
+ let cursor = 0;
3425
+ while (cursor < prompt.length) {
3426
+ const singleQuotedStart = prompt.indexOf(SINGLE_QUOTED_MARKER, cursor);
3427
+ const tripleBacktickStart = prompt.indexOf(TRIPLE_BACKTICK_MARKER, cursor);
3428
+ const markerStart = chooseNearestMarker(singleQuotedStart, tripleBacktickStart);
3429
+ if (markerStart === null) {
3430
+ break;
3431
+ }
3432
+ if (markerStart === singleQuotedStart) {
3433
+ const parsedSingleQuoted = parseSingleQuotedSubstitution(prompt, markerStart);
3434
+ if (!parsedSingleQuoted) {
3435
+ cursor = markerStart + SINGLE_QUOTED_MARKER.length;
3436
+ continue;
3437
+ }
3438
+ matches.push(parsedSingleQuoted);
3439
+ cursor = parsedSingleQuoted.endIndex;
3440
+ continue;
3441
+ }
3442
+ const parsedTripleBacktick = parseTripleBacktickSubstitution(prompt, markerStart);
3443
+ if (!parsedTripleBacktick) {
3444
+ cursor = markerStart + TRIPLE_BACKTICK_MARKER.length;
3445
+ continue;
3446
+ }
3447
+ matches.push(parsedTripleBacktick);
3448
+ cursor = parsedTripleBacktick.endIndex;
3449
+ }
3450
+ return matches;
3451
+ }
3452
+ async function resolvePromptCommandSubstitutions(prompt, options) {
3453
+ const matches = findPromptCommandSubstitutions(prompt);
3454
+ if (matches.length === 0) {
3455
+ return prompt;
3456
+ }
3457
+ const executor = options.executor ?? createDefaultPromptCommandExecutor(options);
3458
+ let result = "";
3459
+ let cursor = 0;
3460
+ for (const match of matches) {
3461
+ result += prompt.slice(cursor, match.startIndex);
3462
+ const commandOutput = await executor(match.command);
3463
+ result += normalizeCommandOutput(commandOutput);
3464
+ cursor = match.endIndex;
3465
+ }
3466
+ result += prompt.slice(cursor);
3467
+ return result;
3468
+ }
3469
+ function chooseNearestMarker(singleQuotedStart, tripleBacktickStart) {
3470
+ const singleExists = singleQuotedStart >= 0;
3471
+ const tripleExists = tripleBacktickStart >= 0;
3472
+ if (!singleExists && !tripleExists) {
3473
+ return null;
3474
+ }
3475
+ if (!singleExists) {
3476
+ return tripleBacktickStart;
3477
+ }
3478
+ if (!tripleExists) {
3479
+ return singleQuotedStart;
3480
+ }
3481
+ return Math.min(singleQuotedStart, tripleBacktickStart);
3482
+ }
3483
+ function parseSingleQuotedSubstitution(prompt, markerStart) {
3484
+ const contentStart = markerStart + SINGLE_QUOTED_MARKER.length;
3485
+ const closingQuote = findClosingSingleQuote(prompt, contentStart);
3486
+ if (closingQuote < 0) {
3487
+ return null;
3488
+ }
3489
+ const raw = prompt.slice(markerStart, closingQuote + 1);
3490
+ const command = prompt.slice(contentStart, closingQuote);
3491
+ return {
3492
+ syntax: "single-quoted",
3493
+ startIndex: markerStart,
3494
+ endIndex: closingQuote + 1,
3495
+ command,
3496
+ raw
3497
+ };
3498
+ }
3499
+ function findClosingSingleQuote(prompt, startIndex) {
3500
+ let escaped = false;
3501
+ for (let index = startIndex; index < prompt.length; index++) {
3502
+ const char = prompt[index];
3503
+ if (char === "'" && !escaped) {
3504
+ return index;
3505
+ }
3506
+ if (char === "\\" && !escaped) {
3507
+ escaped = true;
3508
+ continue;
3509
+ }
3510
+ escaped = false;
3511
+ }
3512
+ return -1;
3513
+ }
3514
+ function parseTripleBacktickSubstitution(prompt, markerStart) {
3515
+ const contentStart = markerStart + TRIPLE_BACKTICK_MARKER.length;
3516
+ const closingBackticks = prompt.indexOf(TRIPLE_BACKTICK_CLOSER, contentStart);
3517
+ if (closingBackticks < 0) {
3518
+ return null;
3519
+ }
3520
+ const raw = prompt.slice(markerStart, closingBackticks + TRIPLE_BACKTICK_CLOSER.length);
3521
+ const command = prompt.slice(contentStart, closingBackticks);
3522
+ return {
3523
+ syntax: "triple-backtick",
3524
+ startIndex: markerStart,
3525
+ endIndex: closingBackticks + TRIPLE_BACKTICK_CLOSER.length,
3526
+ command,
3527
+ raw
3528
+ };
3529
+ }
3530
+ function createDefaultPromptCommandExecutor(options) {
3531
+ const execFile3 = util.promisify(childProcess__namespace.execFile);
3532
+ const maxBufferBytes = options.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;
3533
+ const commandTimeoutMs = resolvePromptCommandTimeoutMs(options.commandTimeoutMs);
3534
+ const shell = process.env.SHELL || "/bin/bash";
3535
+ return async (command) => {
3536
+ const normalizedCommand = command.trim();
3537
+ if (!normalizedCommand) {
3538
+ return "";
3539
+ }
3540
+ const commandForExecution = wrapCommandForNonInteractiveExecution(normalizedCommand);
3541
+ try {
3542
+ const result = await execFile3(shell, ["-lc", commandForExecution], {
3543
+ cwd: options.workingDirectory,
3544
+ env: options.environment ?? process.env,
3545
+ maxBuffer: maxBufferBytes,
3546
+ timeout: commandTimeoutMs
3547
+ });
3548
+ const stdout2 = typeof result === "string" || Buffer.isBuffer(result) ? String(result) : String(result.stdout ?? "");
3549
+ return stdout2;
3550
+ } catch (error) {
3551
+ const failedCommand = normalizedCommand.replace(/\s+/g, " ").trim();
3552
+ const details = error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "").trim() : "";
3553
+ const timeoutDetected = error && typeof error === "object" && (("code" in error ? String(error.code ?? "").toUpperCase() === "ETIMEDOUT" : false) || "killed" in error && Boolean(error.killed) && String(error.signal ?? "").toUpperCase() === "SIGTERM" || "message" in error && /timed?\s*out/i.test(String(error.message ?? "")));
3554
+ if (timeoutDetected) {
3555
+ throw new Error(
3556
+ `Prompt command substitution timed out after ${commandTimeoutMs}ms for \`${failedCommand}\``
3557
+ );
3558
+ }
3559
+ const suffix = details ? `: ${details}` : "";
3560
+ throw new Error(`Prompt command substitution failed for \`${failedCommand}\`${suffix}`);
3561
+ }
3562
+ };
3563
+ }
3564
+ function resolvePromptCommandTimeoutMs(explicitTimeoutMs) {
3565
+ if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
3566
+ return explicitTimeoutMs;
3567
+ }
3568
+ const envValue = process.env[COMMAND_TIMEOUT_ENV_KEY];
3569
+ if (envValue !== void 0) {
3570
+ const parsed = Number(envValue);
3571
+ if (Number.isFinite(parsed) && parsed > 0) {
3572
+ return parsed;
3573
+ }
3574
+ }
3575
+ return DEFAULT_COMMAND_TIMEOUT_MS;
3576
+ }
3577
+ function wrapCommandForNonInteractiveExecution(command) {
3578
+ return `(${command}) </dev/null`;
3579
+ }
3580
+ function normalizeCommandOutput(output) {
3581
+ return output.replace(/\r?\n$/, "");
3582
+ }
3583
+ var SINGLE_QUOTED_MARKER, TRIPLE_BACKTICK_MARKER, TRIPLE_BACKTICK_CLOSER, DEFAULT_MAX_BUFFER_BYTES, DEFAULT_COMMAND_TIMEOUT_MS, COMMAND_TIMEOUT_ENV_KEY;
3584
+ var init_prompt_command_substitution = __esm({
3585
+ "src/core/prompt-command-substitution.ts"() {
3586
+ init_version();
3587
+ SINGLE_QUOTED_MARKER = "!'";
3588
+ TRIPLE_BACKTICK_MARKER = "!```";
3589
+ TRIPLE_BACKTICK_CLOSER = "```";
3590
+ DEFAULT_MAX_BUFFER_BYTES = 1024 * 1024;
3591
+ DEFAULT_COMMAND_TIMEOUT_MS = 3e4;
3592
+ COMMAND_TIMEOUT_ENV_KEY = "JUNO_CODE_PROMPT_SUBSTITUTION_TIMEOUT_MS";
3593
+ }
3594
+ });
3334
3595
  function createExecutionEngine(config) {
3335
3596
  return new ExecutionEngine({
3336
3597
  config,
@@ -3381,6 +3642,9 @@ function createExecutionRequest(options) {
3381
3642
  if (options.live !== void 0) {
3382
3643
  result.live = options.live;
3383
3644
  }
3645
+ if (options.liveInteractiveSession !== void 0) {
3646
+ result.liveInteractiveSession = options.liveInteractiveSession;
3647
+ }
3384
3648
  return result;
3385
3649
  }
3386
3650
  var DEFAULT_ERROR_RECOVERY_CONFIG, DEFAULT_RATE_LIMIT_CONFIG, DEFAULT_PROGRESS_CONFIG, ExecutionEngine;
@@ -3391,6 +3655,7 @@ var init_engine = __esm({
3391
3655
  init_hooks();
3392
3656
  init_advanced_logger();
3393
3657
  init_shell_backend();
3658
+ init_prompt_command_substitution();
3394
3659
  DEFAULT_ERROR_RECOVERY_CONFIG = {
3395
3660
  maxAttempts: {
3396
3661
  connection: 3,
@@ -3687,7 +3952,8 @@ var init_engine = __esm({
3687
3952
  if (!request.requestId?.trim()) {
3688
3953
  throw new Error("Request ID is required");
3689
3954
  }
3690
- if (!request.instruction?.trim()) {
3955
+ const allowEmptyInstructionForPiLiveInteractiveSession = request.subagent === "pi" && request.live === true && request.liveInteractiveSession === true && typeof request.resume === "string" && request.resume.trim().length > 0;
3956
+ if (!request.instruction?.trim() && !allowEmptyInstructionForPiLiveInteractiveSession) {
3691
3957
  throw new Error("Instruction is required");
3692
3958
  }
3693
3959
  if (!request.subagent?.trim()) {
@@ -3925,44 +4191,62 @@ var init_engine = __esm({
3925
4191
  engineLogger.warn("Hook START_ITERATION failed", { error, iterationNumber });
3926
4192
  }
3927
4193
  this.emit("iteration:start", { context, iterationNumber });
3928
- const toolRequest = {
3929
- toolName: this.getToolNameForSubagent(context.request.subagent),
3930
- arguments: {
3931
- instruction: context.request.instruction,
3932
- project_path: context.request.workingDirectory,
3933
- ...context.request.model !== void 0 && { model: context.request.model },
3934
- ...context.request.agents !== void 0 && { agents: context.request.agents },
3935
- ...context.request.tools !== void 0 && { tools: context.request.tools },
3936
- ...context.request.allowedTools !== void 0 && {
3937
- allowedTools: context.request.allowedTools
3938
- },
3939
- ...context.request.appendAllowedTools !== void 0 && {
3940
- appendAllowedTools: context.request.appendAllowedTools
3941
- },
3942
- ...context.request.disallowedTools !== void 0 && {
3943
- disallowedTools: context.request.disallowedTools
4194
+ let toolRequest = null;
4195
+ try {
4196
+ const instructionTemplate = context.request.instruction;
4197
+ const resolvedInstruction = await resolvePromptCommandSubstitutions(instructionTemplate, {
4198
+ workingDirectory: context.request.workingDirectory,
4199
+ environment: {
4200
+ ...process.env,
4201
+ JUNO_TASK_ROOT: process.env.JUNO_TASK_ROOT || context.request.workingDirectory
4202
+ }
4203
+ });
4204
+ this.emit("iteration:instruction-resolved", {
4205
+ context,
4206
+ iterationNumber,
4207
+ instruction: resolvedInstruction,
4208
+ templateInstruction: instructionTemplate
4209
+ });
4210
+ toolRequest = {
4211
+ toolName: this.getToolNameForSubagent(context.request.subagent),
4212
+ arguments: {
4213
+ instruction: resolvedInstruction,
4214
+ project_path: context.request.workingDirectory,
4215
+ ...context.request.model !== void 0 && { model: context.request.model },
4216
+ ...context.request.agents !== void 0 && { agents: context.request.agents },
4217
+ ...context.request.tools !== void 0 && { tools: context.request.tools },
4218
+ ...context.request.allowedTools !== void 0 && {
4219
+ allowedTools: context.request.allowedTools
4220
+ },
4221
+ ...context.request.appendAllowedTools !== void 0 && {
4222
+ appendAllowedTools: context.request.appendAllowedTools
4223
+ },
4224
+ ...context.request.disallowedTools !== void 0 && {
4225
+ disallowedTools: context.request.disallowedTools
4226
+ },
4227
+ ...context.request.resume !== void 0 && { resume: context.request.resume },
4228
+ ...context.request.continueConversation !== void 0 && {
4229
+ continueConversation: context.request.continueConversation
4230
+ },
4231
+ ...context.request.thinking !== void 0 && { thinking: context.request.thinking },
4232
+ ...context.request.live !== void 0 && { live: context.request.live },
4233
+ ...context.request.liveInteractiveSession !== void 0 && {
4234
+ liveInteractiveSession: context.request.liveInteractiveSession
4235
+ },
4236
+ iteration: iterationNumber
3944
4237
  },
3945
- ...context.request.resume !== void 0 && { resume: context.request.resume },
3946
- ...context.request.continueConversation !== void 0 && {
3947
- continueConversation: context.request.continueConversation
4238
+ timeout: context.request.timeoutMs || this.engineConfig.config.mcpTimeout,
4239
+ priority: context.request.priority || "normal",
4240
+ metadata: {
4241
+ sessionId: context.sessionContext.sessionId,
4242
+ iterationNumber
3948
4243
  },
3949
- ...context.request.thinking !== void 0 && { thinking: context.request.thinking },
3950
- ...context.request.live !== void 0 && { live: context.request.live },
3951
- iteration: iterationNumber
3952
- },
3953
- timeout: context.request.timeoutMs || this.engineConfig.config.mcpTimeout,
3954
- priority: context.request.priority || "normal",
3955
- metadata: {
3956
- sessionId: context.sessionContext.sessionId,
3957
- iterationNumber
3958
- },
3959
- progressCallback: async (event) => {
3960
- context.progressEvents.push(event);
3961
- context.statistics.totalProgressEvents++;
3962
- await this.processProgressEvent(context, event);
3963
- }
3964
- };
3965
- try {
4244
+ progressCallback: async (event) => {
4245
+ context.progressEvents.push(event);
4246
+ context.statistics.totalProgressEvents++;
4247
+ await this.processProgressEvent(context, event);
4248
+ }
4249
+ };
3966
4250
  if (!this.currentBackend) {
3967
4251
  throw new Error("No backend initialized. Call initializeBackend() first.");
3968
4252
  }
@@ -4031,7 +4315,10 @@ var init_engine = __esm({
4031
4315
  duration,
4032
4316
  error: mcpError,
4033
4317
  progressEvents: [],
4034
- request: toolRequest
4318
+ request: toolRequest ?? {
4319
+ toolName: this.getToolNameForSubagent(context.request.subagent),
4320
+ arguments: {}
4321
+ }
4035
4322
  },
4036
4323
  progressEvents: [],
4037
4324
  error: mcpError
@@ -4970,7 +5257,7 @@ var init_concurrent_feedback_collector = __esm({
4970
5257
  );
4971
5258
  }
4972
5259
  return new Promise((resolve7) => {
4973
- const child = child_process.spawn(this.options.command, this.options.commandArgs, {
5260
+ const child = childProcess.spawn(this.options.command, this.options.commandArgs, {
4974
5261
  stdio: ["pipe", "pipe", "pipe"]
4975
5262
  });
4976
5263
  child.stdout?.on("data", (d) => {
@@ -5103,10 +5390,13 @@ var init_terminal_progress_writer = __esm({
5103
5390
  // src/cli/commands/main.ts
5104
5391
  var main_exports = {};
5105
5392
  __export(main_exports, {
5393
+ expandKanbanTaskReferencesInPrompt: () => expandKanbanTaskReferencesInPrompt,
5106
5394
  getActiveSessionId: () => getActiveSessionId,
5107
5395
  getDefaultModelForSubagent: () => getDefaultModelForSubagent,
5108
5396
  isModelCompatibleWithSubagent: () => isModelCompatibleWithSubagent,
5109
- mainCommandHandler: () => mainCommandHandler
5397
+ mainCommandHandler: () => mainCommandHandler,
5398
+ normalizeLeadingPromptDirectiveArtifacts: () => normalizeLeadingPromptDirectiveArtifacts,
5399
+ rewriteLeadingPromptShortcut: () => rewriteLeadingPromptShortcut
5110
5400
  });
5111
5401
  function normalizeVerboseLevel(verbose, quiet) {
5112
5402
  if (quiet) return 0;
@@ -5173,6 +5463,169 @@ function toStringArray(value) {
5173
5463
  const normalized = value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter((entry) => entry.length > 0);
5174
5464
  return normalized.length > 0 ? normalized : void 0;
5175
5465
  }
5466
+ function extractReferencedKanbanTaskIds(prompt) {
5467
+ const taskIds = [];
5468
+ const seen = /* @__PURE__ */ new Set();
5469
+ for (const match of prompt.matchAll(KANBAN_TASK_REFERENCE_REGEX)) {
5470
+ const taskId = match[1];
5471
+ if (!taskId || seen.has(taskId)) {
5472
+ continue;
5473
+ }
5474
+ seen.add(taskId);
5475
+ taskIds.push(taskId);
5476
+ }
5477
+ return taskIds;
5478
+ }
5479
+ function normalizeKanbanTaskArray(payload) {
5480
+ if (Array.isArray(payload)) {
5481
+ return payload.filter((entry) => Boolean(entry) && typeof entry === "object");
5482
+ }
5483
+ if (payload && typeof payload === "object") {
5484
+ return [payload];
5485
+ }
5486
+ return [];
5487
+ }
5488
+ async function runKanbanGetCommand(command, args, workingDirectory) {
5489
+ try {
5490
+ const execFile3 = util.promisify(childProcess__namespace.execFile);
5491
+ const result = await execFile3(command, args, {
5492
+ cwd: workingDirectory,
5493
+ env: {
5494
+ ...process.env,
5495
+ JUNO_TASK_ROOT: process.env.JUNO_TASK_ROOT || workingDirectory
5496
+ },
5497
+ maxBuffer: 1024 * 1024
5498
+ });
5499
+ const stdout2 = typeof result === "string" || Buffer.isBuffer(result) ? String(result) : String(result.stdout ?? "");
5500
+ const parsed = JSON.parse(stdout2);
5501
+ return normalizeKanbanTaskArray(parsed);
5502
+ } catch {
5503
+ return null;
5504
+ }
5505
+ }
5506
+ async function fetchKanbanTasksForCommand(command, taskIds, workingDirectory) {
5507
+ const tasksById = /* @__PURE__ */ new Map();
5508
+ if (taskIds.length === 0) {
5509
+ return tasksById;
5510
+ }
5511
+ const requestedTaskIds = new Set(taskIds);
5512
+ const addFetchedTasks = (fetchedTasks) => {
5513
+ if (!fetchedTasks) {
5514
+ return;
5515
+ }
5516
+ for (const task of fetchedTasks) {
5517
+ const taskId = typeof task.id === "string" ? task.id : void 0;
5518
+ if (!taskId || !requestedTaskIds.has(taskId)) {
5519
+ continue;
5520
+ }
5521
+ tasksById.set(taskId, task);
5522
+ }
5523
+ };
5524
+ addFetchedTasks(await runKanbanGetCommand(command, ["get", ...taskIds], workingDirectory));
5525
+ const unresolvedTaskIds = taskIds.filter((taskId) => !tasksById.has(taskId));
5526
+ for (const taskId of unresolvedTaskIds) {
5527
+ addFetchedTasks(await runKanbanGetCommand(command, ["get", taskId], workingDirectory));
5528
+ }
5529
+ return tasksById;
5530
+ }
5531
+ async function fetchReferencedKanbanTasks(taskIds, workingDirectory) {
5532
+ const tasksById = /* @__PURE__ */ new Map();
5533
+ if (taskIds.length === 0) {
5534
+ return tasksById;
5535
+ }
5536
+ const kanbanScriptPath = path15__namespace.join(workingDirectory, KANBAN_TASK_SCRIPT_RELATIVE_PATH);
5537
+ const hasKanbanScript = await fs16__default.default.pathExists(kanbanScriptPath);
5538
+ const commandAttempts = [];
5539
+ if (hasKanbanScript) {
5540
+ commandAttempts.push(kanbanScriptPath);
5541
+ }
5542
+ commandAttempts.push("juno-kanban");
5543
+ let unresolvedTaskIds = [...taskIds];
5544
+ for (const command of commandAttempts) {
5545
+ if (unresolvedTaskIds.length === 0) {
5546
+ break;
5547
+ }
5548
+ const fetchedTasks = await fetchKanbanTasksForCommand(command, unresolvedTaskIds, workingDirectory);
5549
+ if (fetchedTasks.size === 0) {
5550
+ continue;
5551
+ }
5552
+ for (const [taskId, task] of fetchedTasks.entries()) {
5553
+ tasksById.set(taskId, task);
5554
+ }
5555
+ unresolvedTaskIds = unresolvedTaskIds.filter((taskId) => !tasksById.has(taskId));
5556
+ }
5557
+ return tasksById;
5558
+ }
5559
+ async function expandKanbanTaskReferencesInPrompt(prompt, workingDirectory) {
5560
+ const referencedTaskIds = extractReferencedKanbanTaskIds(prompt);
5561
+ if (referencedTaskIds.length === 0) {
5562
+ return prompt;
5563
+ }
5564
+ const tasksById = await fetchReferencedKanbanTasks(referencedTaskIds, workingDirectory);
5565
+ if (tasksById.size === 0) {
5566
+ return prompt;
5567
+ }
5568
+ return prompt.replace(KANBAN_TASK_REFERENCE_REGEX, (fullMatch, taskId) => {
5569
+ const task = tasksById.get(taskId);
5570
+ if (!task) {
5571
+ return fullMatch;
5572
+ }
5573
+ return `
5574
+ [kanban_task:${taskId}]
5575
+ ${JSON.stringify(task, null, 2)}
5576
+ [/kanban_task]`;
5577
+ });
5578
+ }
5579
+ function normalizeLeadingPromptDirectiveArtifacts(prompt) {
5580
+ const lines = prompt.split(/\r?\n/);
5581
+ if (lines.length === 0) {
5582
+ return prompt;
5583
+ }
5584
+ let index = 0;
5585
+ while (index < lines.length && lines[index].trim() === "") {
5586
+ index += 1;
5587
+ }
5588
+ if (index >= lines.length) {
5589
+ return prompt;
5590
+ }
5591
+ const firstMeaningfulLine = lines[index].trim();
5592
+ if (!LEADING_PROMPT_DELIMITER_MARKERS.has(firstMeaningfulLine)) {
5593
+ return prompt;
5594
+ }
5595
+ let directiveIndex = index + 1;
5596
+ while (directiveIndex < lines.length && lines[directiveIndex].trim() === "") {
5597
+ directiveIndex += 1;
5598
+ }
5599
+ if (directiveIndex >= lines.length) {
5600
+ return prompt;
5601
+ }
5602
+ const directiveCandidate = lines[directiveIndex].trimStart();
5603
+ if (!LEADING_DIRECTIVE_LINE_REGEX.test(directiveCandidate)) {
5604
+ return prompt;
5605
+ }
5606
+ return lines.slice(directiveIndex).join("\n");
5607
+ }
5608
+ function rewriteLeadingPromptShortcut(prompt, subagent) {
5609
+ const match = prompt.match(LEADING_PROMPT_SHORTCUT_REGEX);
5610
+ if (!match) {
5611
+ return prompt;
5612
+ }
5613
+ const shortcut = match[1] ?? match[2];
5614
+ if (!shortcut) {
5615
+ return prompt;
5616
+ }
5617
+ const remaining = match[3] ?? "";
5618
+ switch (subagent) {
5619
+ case "claude":
5620
+ return `/${shortcut}${remaining}`;
5621
+ case "pi":
5622
+ return `/skill:${shortcut}${remaining}`;
5623
+ case "codex":
5624
+ return `$${shortcut}${remaining}`;
5625
+ default:
5626
+ return prompt;
5627
+ }
5628
+ }
5176
5629
  function resolveContinueEnvFilePath(workingDirectory, configuredPath) {
5177
5630
  const candidate = configuredPath && configuredPath.trim() ? configuredPath.trim() : DEFAULT_ENV_FILE_NAME;
5178
5631
  return path15__namespace.isAbsolute(candidate) ? candidate : path15__namespace.join(workingDirectory, candidate);
@@ -5575,7 +6028,13 @@ async function mainCommandHandler(_args, options, _command) {
5575
6028
  ]);
5576
6029
  }
5577
6030
  const promptProcessor = new PromptProcessor(options);
5578
- const instruction = await promptProcessor.processPrompt();
6031
+ const rawInstruction = await promptProcessor.processPrompt();
6032
+ const normalizedInstruction = normalizeLeadingPromptDirectiveArtifacts(rawInstruction);
6033
+ const rewrittenInstruction = rewriteLeadingPromptShortcut(normalizedInstruction, options.subagent);
6034
+ const instruction = await expandKanbanTaskReferencesInPrompt(
6035
+ rewrittenInstruction,
6036
+ config.workingDirectory
6037
+ );
5579
6038
  const selectedBackend = "shell";
5580
6039
  if (options.allowedTools && options.appendAllowedTools) {
5581
6040
  console.error(
@@ -5594,6 +6053,7 @@ async function mainCommandHandler(_args, options, _command) {
5594
6053
  }
5595
6054
  const configuredModel = getConfiguredDefaultModelForSubagent(config, options.subagent);
5596
6055
  const resolvedModel = options.model || configuredModel || getDefaultModelForSubagent(options.subagent);
6056
+ const liveInteractiveSession = options.continueFromLatest === true && options.subagent === "pi" && options.live === true && instruction.length === 0 && typeof options.resume === "string" && options.resume.trim().length > 0;
5597
6057
  const executionRequest = createExecutionRequest({
5598
6058
  instruction,
5599
6059
  subagent: options.subagent,
@@ -5609,7 +6069,8 @@ async function mainCommandHandler(_args, options, _command) {
5609
6069
  ...options.resume !== void 0 ? { resume: options.resume } : {},
5610
6070
  ...options.continue !== void 0 ? { continueConversation: options.continue } : {},
5611
6071
  ...options.thinking !== void 0 ? { thinking: options.thinking } : {},
5612
- ...options.live !== void 0 ? { live: options.live } : {}
6072
+ ...options.live !== void 0 ? { live: options.live } : {},
6073
+ ...liveInteractiveSession ? { liveInteractiveSession: true } : {}
5613
6074
  });
5614
6075
  const coordinator = new MainExecutionCoordinator(
5615
6076
  config,
@@ -5687,7 +6148,7 @@ async function mainCommandHandler(_args, options, _command) {
5687
6148
  }
5688
6149
  }
5689
6150
  }
5690
- var SESSION_HISTORY_VERSION, SESSION_HISTORY_FILE_NAME, CONTINUE_SETTINGS_VERSION, DEFAULT_ENV_FILE_NAME, PromptProcessor, _activeSessionId, MainProgressDisplay, MainExecutionCoordinator;
6151
+ var SESSION_HISTORY_VERSION, SESSION_HISTORY_FILE_NAME, CONTINUE_SETTINGS_VERSION, DEFAULT_ENV_FILE_NAME, LEADING_PROMPT_SHORTCUT_REGEX, LEADING_PROMPT_DELIMITER_MARKERS, LEADING_DIRECTIVE_LINE_REGEX, KANBAN_TASK_REFERENCE_REGEX, KANBAN_TASK_SCRIPT_RELATIVE_PATH, PromptProcessor, _activeSessionId, MainProgressDisplay, MainExecutionCoordinator;
5691
6152
  var init_main = __esm({
5692
6153
  "src/cli/commands/main.ts"() {
5693
6154
  init_version();
@@ -5704,6 +6165,11 @@ var init_main = __esm({
5704
6165
  SESSION_HISTORY_FILE_NAME = "session_history.json";
5705
6166
  CONTINUE_SETTINGS_VERSION = 1;
5706
6167
  DEFAULT_ENV_FILE_NAME = ".env.juno";
6168
+ LEADING_PROMPT_SHORTCUT_REGEX = /^%(?:\{([^\s{}]+)\}|([^\s%][^\s]*))(.*)$/s;
6169
+ LEADING_PROMPT_DELIMITER_MARKERS = /* @__PURE__ */ new Set(["---", "***", "___"]);
6170
+ LEADING_DIRECTIVE_LINE_REGEX = /^(?:%(?:\{[^\s{}]+\}|[^\s%][^\s]*)|\/skill:[^\s]+|\/[^\s]+|\$[^\s]+)/;
6171
+ KANBAN_TASK_REFERENCE_REGEX = /(?<!#)##\s*\{?([A-Za-z0-9]{6})\}?(?![A-Za-z0-9])/g;
6172
+ KANBAN_TASK_SCRIPT_RELATIVE_PATH = path15__namespace.join(".juno_task", "scripts", "kanban.sh");
5707
6173
  PromptProcessor = class {
5708
6174
  constructor(options) {
5709
6175
  this.options = options;
@@ -5721,6 +6187,9 @@ var init_main = __esm({
5721
6187
  if (this.hasRedirectedStdin()) {
5722
6188
  return await this.readPipedStdin();
5723
6189
  }
6190
+ if (this.shouldOpenLiveContinueSessionWithoutPrompt()) {
6191
+ return "";
6192
+ }
5724
6193
  if (this.options.interactive) {
5725
6194
  return await this.collectInteractivePrompt();
5726
6195
  } else {
@@ -5759,6 +6228,9 @@ var init_main = __esm({
5759
6228
  return false;
5760
6229
  }
5761
6230
  }
6231
+ shouldOpenLiveContinueSessionWithoutPrompt() {
6232
+ return this.options.continueFromLatest === true && this.options.subagent === "pi" && this.options.live === true && !this.options.promptFile && this.options.prompt !== true && !this.options.interactive && !this.options.interactivePrompt;
6233
+ }
5762
6234
  async isFilePath(prompt) {
5763
6235
  if (prompt.includes("\n") || prompt.length > 500) {
5764
6236
  return false;
@@ -5867,6 +6339,7 @@ var init_main = __esm({
5867
6339
  // iteration# → sub-agent session_id
5868
6340
  latestSessionId = null;
5869
6341
  // most recent session_id seen
6342
+ lastResolvedInstructionByIteration = /* @__PURE__ */ new Map();
5870
6343
  constructor(verboseLevel = 1) {
5871
6344
  this.verboseLevel = verboseLevel;
5872
6345
  }
@@ -5893,9 +6366,18 @@ var init_main = __esm({
5893
6366
  console.error(chalk21__default.default.gray(` Request ID: ${request.requestId}`));
5894
6367
  console.error(chalk21__default.default.gray(` Working Directory: ${request.workingDirectory}`));
5895
6368
  }
5896
- console.error(chalk21__default.default.blue("\n\u{1F4CB} Task:"));
5897
- const preview = request.instruction.length > 200 ? request.instruction.substring(0, 200) + "..." : request.instruction;
5898
- console.error(chalk21__default.default.white(` ${preview}`));
6369
+ const hasPromptSubstitutionSyntax = this.hasPromptCommandSubstitutionSyntax(request.instruction);
6370
+ if (hasPromptSubstitutionSyntax) {
6371
+ console.error(chalk21__default.default.blue("\n\u{1F4CB} Task Template:"));
6372
+ } else {
6373
+ console.error(chalk21__default.default.blue("\n\u{1F4CB} Task:"));
6374
+ }
6375
+ console.error(chalk21__default.default.white(` ${this.buildInstructionPreview(request.instruction)}`));
6376
+ if (hasPromptSubstitutionSyntax) {
6377
+ console.error(
6378
+ chalk21__default.default.gray(" Prompt-time substitutions are resolved immediately before each subagent call.")
6379
+ );
6380
+ }
5899
6381
  console.error("");
5900
6382
  }
5901
6383
  getSelectedExecutionOptions(request) {
@@ -5929,6 +6411,32 @@ var init_main = __esm({
5929
6411
  if (value.length <= maxLength) return value;
5930
6412
  return `${value.substring(0, maxLength - 3)}...`;
5931
6413
  }
6414
+ buildInstructionPreview(instruction, maxLength = 200) {
6415
+ if (instruction.length <= maxLength) {
6416
+ return instruction;
6417
+ }
6418
+ return `${instruction.substring(0, maxLength)}...`;
6419
+ }
6420
+ hasPromptCommandSubstitutionSyntax(instruction) {
6421
+ return instruction.includes("!'") || instruction.includes("!```");
6422
+ }
6423
+ onInstructionResolved(iteration, resolvedInstruction, templateInstruction) {
6424
+ const previousInstruction = this.lastResolvedInstructionByIteration.get(iteration);
6425
+ if (previousInstruction === resolvedInstruction) {
6426
+ return;
6427
+ }
6428
+ this.lastResolvedInstructionByIteration.set(iteration, resolvedInstruction);
6429
+ if (this.verboseLevel === 0) {
6430
+ return;
6431
+ }
6432
+ if (templateInstruction !== void 0 && resolvedInstruction === templateInstruction) {
6433
+ return;
6434
+ }
6435
+ const heading = iteration === 1 ? "\n\u{1F9E9} Resolved Task (iteration 1):" : `
6436
+ \u{1F9E9} Resolved Task (iteration ${iteration}):`;
6437
+ console.error(chalk21__default.default.blue(heading));
6438
+ console.error(chalk21__default.default.white(` ${this.buildInstructionPreview(resolvedInstruction)}`));
6439
+ }
5932
6440
  onProgress(event) {
5933
6441
  const timestamp = event.timestamp.toLocaleTimeString();
5934
6442
  if (event.metadata?.sessionId && typeof event.metadata.sessionId === "string") {
@@ -6006,7 +6514,10 @@ var init_main = __esm({
6006
6514
  if (this.verboseLevel === 0) {
6007
6515
  const lastIteration2 = result.iterations[result.iterations.length - 1];
6008
6516
  if (lastIteration2?.toolResult.content && !this.hasStreamedJsonOutput) {
6009
- console.log(lastIteration2.toolResult.content);
6517
+ const displayContent = this.getDisplayResultContent(lastIteration2.toolResult.content);
6518
+ if (displayContent.trim().length > 0) {
6519
+ console.log(displayContent);
6520
+ }
6010
6521
  }
6011
6522
  return;
6012
6523
  }
@@ -6019,12 +6530,14 @@ var init_main = __esm({
6019
6530
  }
6020
6531
  const lastIteration = result.iterations[result.iterations.length - 1];
6021
6532
  const structuredOutput = lastIteration?.toolResult.metadata?.structuredOutput === true;
6533
+ const rawResultContent = lastIteration?.toolResult.content || "";
6534
+ const displayResultContent = rawResultContent ? this.getDisplayResultContent(rawResultContent) : "";
6022
6535
  const shouldPrintResult = Boolean(
6023
- lastIteration && lastIteration.toolResult.content && (!this.hasStreamedJsonOutput || structuredOutput)
6536
+ lastIteration && displayResultContent && (!this.hasStreamedJsonOutput || structuredOutput)
6024
6537
  );
6025
6538
  if (shouldPrintResult) {
6026
6539
  console.error(chalk21__default.default.blue("\n\u{1F4C4} Result:"));
6027
- console.log(lastIteration.toolResult.content);
6540
+ console.log(displayResultContent);
6028
6541
  }
6029
6542
  const iterationCosts = this.extractIterationCosts(result);
6030
6543
  const totalCostUsd = [...iterationCosts.values()].reduce((sum, cost) => sum + cost, 0);
@@ -6094,6 +6607,26 @@ var init_main = __esm({
6094
6607
  console.error(chalk21__default.default.gray("\n\u{1F511} Session ID: could not be extracted"));
6095
6608
  }
6096
6609
  }
6610
+ getDisplayResultContent(content) {
6611
+ if (this.verboseLevel >= 2) {
6612
+ return content;
6613
+ }
6614
+ try {
6615
+ const payload = JSON.parse(content);
6616
+ if (payload?.type === "result" && Object.prototype.hasOwnProperty.call(payload, "result")) {
6617
+ const resultValue = payload.result;
6618
+ if (typeof resultValue === "string") {
6619
+ return resultValue;
6620
+ }
6621
+ if (resultValue === null || resultValue === void 0) {
6622
+ return "";
6623
+ }
6624
+ return JSON.stringify(resultValue, null, 2);
6625
+ }
6626
+ } catch {
6627
+ }
6628
+ return content;
6629
+ }
6097
6630
  /**
6098
6631
  * Extract session IDs from iteration results' structured payloads
6099
6632
  */
@@ -6242,6 +6775,13 @@ var init_main = __esm({
6242
6775
  engine.on("iteration:start", ({ iterationNumber }) => {
6243
6776
  this.progressDisplay.onIterationStart(iterationNumber);
6244
6777
  });
6778
+ engine.on("iteration:instruction-resolved", ({ iterationNumber, instruction, templateInstruction }) => {
6779
+ this.progressDisplay.onInstructionResolved(
6780
+ iterationNumber,
6781
+ typeof instruction === "string" ? instruction : "",
6782
+ typeof templateInstruction === "string" ? templateInstruction : void 0
6783
+ );
6784
+ });
6245
6785
  engine.on("iteration:complete", ({ iterationResult }) => {
6246
6786
  this.progressDisplay.onIterationComplete(iterationResult.success, iterationResult.duration);
6247
6787
  });
@@ -14807,6 +15347,26 @@ function normalizeVerbose(value) {
14807
15347
  if (!isNaN(num) && num >= 0 && num <= 2) return Math.floor(num);
14808
15348
  return 1;
14809
15349
  }
15350
+ function extractOptionValueFromArgv(argv2, longOption, shortOption) {
15351
+ for (let i = 0; i < argv2.length; i++) {
15352
+ const token = argv2[i];
15353
+ if (!token) continue;
15354
+ if (token === longOption || token === shortOption) {
15355
+ const next = argv2[i + 1];
15356
+ if (next && !next.startsWith("-")) {
15357
+ return next;
15358
+ }
15359
+ continue;
15360
+ }
15361
+ if (token.startsWith(`${longOption}=`)) {
15362
+ return token.slice(longOption.length + 1);
15363
+ }
15364
+ if (token.startsWith(`${shortOption}=`)) {
15365
+ return token.slice(shortOption.length + 1);
15366
+ }
15367
+ }
15368
+ return void 0;
15369
+ }
14810
15370
  function isConnectionLikeError(err) {
14811
15371
  const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
14812
15372
  const lower = msg.toLowerCase();
@@ -14937,6 +15497,15 @@ function getForwardedUntilCompletionArgs() {
14937
15497
  if (arg.startsWith("--pre-run-hook=")) {
14938
15498
  continue;
14939
15499
  }
15500
+ if (arg === "--cwd" || arg === "-w") {
15501
+ if (i + 1 < args.length && args[i + 1] && !args[i + 1].startsWith("-")) {
15502
+ i += 1;
15503
+ }
15504
+ continue;
15505
+ }
15506
+ if (arg.startsWith("--cwd=") || arg.startsWith("-w=")) {
15507
+ continue;
15508
+ }
14940
15509
  forwardedArgs.push(arg);
14941
15510
  }
14942
15511
  return forwardedArgs;
@@ -14948,7 +15517,9 @@ async function runUntilCompletionScriptIfRequested(options) {
14948
15517
  const { spawn: spawn3 } = await import('child_process');
14949
15518
  const path21 = await import('path');
14950
15519
  const fs22 = await import('fs-extra');
14951
- const scriptPath = path21.join(process.cwd(), ".juno_task", "scripts", "run_until_completion.sh");
15520
+ const optionCwd = typeof options.cwd === "string" && options.cwd.trim().length > 0 ? options.cwd.trim() : extractOptionValueFromArgv(process.argv.slice(2), "--cwd", "-w");
15521
+ const invocationCwd = typeof optionCwd === "string" && optionCwd.trim().length > 0 ? path21.resolve(process.cwd(), optionCwd) : process.cwd();
15522
+ const scriptPath = path21.join(invocationCwd, ".juno_task", "scripts", "run_until_completion.sh");
14952
15523
  if (!await fs22.pathExists(scriptPath)) {
14953
15524
  console.error(chalk21__default.default.red.bold("\n\u274C Error: run_until_completion.sh not found"));
14954
15525
  console.error(chalk21__default.default.red(` Expected location: ${scriptPath}`));
@@ -14965,7 +15536,7 @@ async function runUntilCompletionScriptIfRequested(options) {
14965
15536
  scriptArgs.push(...getForwardedUntilCompletionArgs());
14966
15537
  const child = spawn3(scriptPath, scriptArgs, {
14967
15538
  stdio: "inherit",
14968
- cwd: process.cwd()
15539
+ cwd: invocationCwd
14969
15540
  });
14970
15541
  process.removeAllListeners("SIGINT");
14971
15542
  process.removeAllListeners("SIGTERM");
@@ -14997,9 +15568,9 @@ async function runUntilCompletionScriptIfRequested(options) {
14997
15568
  return true;
14998
15569
  }
14999
15570
  function setupContinueCommand(program) {
15000
- const continueCommand = program.command("continue").description("Continue the most recent juno-code session with saved settings").argument("[prompt_text...]", "Prompt text (positional, alternative to -p)").option(
15571
+ const continueCommand = program.command("continue").alias("contiue").description("Continue the most recent juno-code session with saved settings").argument("[prompt_text...]", "Prompt text (positional, alternative to -p)").option(
15001
15572
  "-p, --prompt [text]",
15002
- "Prompt input (inline text, file path, or use with heredoc/stdin; prefer single quotes for shell metacharacters)"
15573
+ "Prompt input (inline text, file path, or heredoc/stdin; supports !'cmd' and !```cmd``` substitutions, prefer single quotes for shell metacharacters)"
15003
15574
  ).option("-f, --prompt-file <path>", "Read prompt from a file (shell-safe for backticks/$())").option("-w, --cwd <path>", "Working directory").option("-i, --max-iterations <number>", "Override max iterations for this continue run", parseInt).option("-m, --model <name>", "Override model for this continue run").option("-s, --subagent <name>", "Override subagent for this continue run").option("-I, --interactive", "Interactive mode for typing prompts").option("--live", "Run Pi subagent in interactive live TUI mode (pi only)").option("--thinking <level>", "Override thinking level for this continue run").action(async (promptArgs, options, command) => {
15004
15575
  if (promptArgs.length > 0 && options.prompt === void 0) {
15005
15576
  options.prompt = promptArgs.join(" ");
@@ -15074,7 +15645,7 @@ function setupContinueScopeCommand(program) {
15074
15645
  function setupMainCommand(program) {
15075
15646
  program.argument("[prompt_text...]", "Prompt text (positional, alternative to -p)").option(
15076
15647
  "-p, --prompt [text]",
15077
- "Prompt input (inline text, file path, or use with heredoc/stdin; prefer single quotes for shell metacharacters)"
15648
+ "Prompt input (inline text, file path, or heredoc/stdin; supports !'cmd' and !```cmd``` substitutions, prefer single quotes for shell metacharacters)"
15078
15649
  ).option("-f, --prompt-file <path>", "Read prompt from a file (shell-safe for backticks/$())").option("-w, --cwd <path>", "Working directory").option("-i, --max-iterations <number>", "Maximum iterations (-1 for unlimited)", parseInt).option("-I, --interactive", "Interactive mode for typing prompts").option("--live", "Run Pi subagent in interactive live TUI mode (pi only)").option("-ip, --interactive-prompt", "Launch interactive prompt editor").action(async (promptArgs, options, command) => {
15079
15650
  if (promptArgs.length > 0 && options.prompt === void 0) {
15080
15651
  options.prompt = promptArgs.join(" ");
@@ -15248,6 +15819,11 @@ ${chalk21__default.default.blue("Examples:")}
15248
15819
 
15249
15820
  ${chalk21__default.default.gray("# Shell safety")}
15250
15821
  ${chalk21__default.default.gray("Use single quotes (or -f/stdin) when prompts contain backticks or $()")}
15822
+
15823
+ ${chalk21__default.default.gray("# Prompt-time substitutions (refreshed each iteration)")}
15824
+ juno-code claude -p "Status: !'git status --short'"
15825
+ juno-code claude -i 3 -p "Recent commits:
15826
+ !\`\`\`git log -n 5 --oneline\`\`\`"
15251
15827
  `
15252
15828
  },
15253
15829
  pi: {
@@ -15436,7 +16012,7 @@ function setupAliases(program) {
15436
16012
  if (!help) continue;
15437
16013
  const cmd = program.command(subagent).description(help.description).argument("[prompt...]", "Prompt text or file path").option(
15438
16014
  "-p, --prompt [text]",
15439
- "Prompt input (inline text, or use with heredoc/stdin; prefer single quotes for shell metacharacters)"
16015
+ "Prompt input (inline text, or heredoc/stdin; supports !'cmd' and !```cmd``` substitutions, prefer single quotes for shell metacharacters)"
15440
16016
  ).option("-f, --prompt-file <path>", "Read prompt from a file (shell-safe for backticks/$())").option("-w, --cwd <path>", "Working directory").option("-i, --max-iterations <number>", "Maximum iterations (-1 for unlimited)", parseInt).option("-m, --model <name>", "Model to use (see model shorthands below)").option("-r, --resume <sessionId>", "Resume a conversation by session ID").option("--continue", "Continue the most recent conversation").option("-I, --interactive", "Interactive mode for typing prompts").option("--live", "Run Pi subagent in interactive live TUI mode (pi only)").addHelpText("after", help.helpText).action(async (promptArgs, options, command) => {
15441
16017
  if (promptArgs.length > 0 && options.prompt === void 0) {
15442
16018
  options.prompt = promptArgs.join(" ");
@@ -15461,9 +16037,24 @@ function setupAliases(program) {
15461
16037
  handleCLIError(error, normalizeVerbose(options.verbose));
15462
16038
  }
15463
16039
  });
15464
- cmd.command("set-default-model <model>").description(`Set default model for the ${subagent} subagent in .juno_task/config.json`).option("-w, --cwd <path>", "Working directory").action(async (model, commandOptions) => {
16040
+ cmd.command("set-default-model <model>").description(`Set default model for the ${subagent} subagent in .juno_task/config.json`).option("-w, --cwd <path>", "Working directory").action(async (model, commandOptions, command) => {
16041
+ const mergedOptions = (() => {
16042
+ const commandWithGlobals = command;
16043
+ if (typeof commandWithGlobals.optsWithGlobals === "function") {
16044
+ return {
16045
+ ...commandWithGlobals.optsWithGlobals(),
16046
+ ...commandOptions
16047
+ };
16048
+ }
16049
+ const parentOptions = command.parent?.opts ? command.parent.opts() : {};
16050
+ return {
16051
+ ...parentOptions,
16052
+ ...commandOptions
16053
+ };
16054
+ })();
15465
16055
  try {
15466
- const workingDirectory = typeof commandOptions.cwd === "string" && commandOptions.cwd.trim().length > 0 ? commandOptions.cwd.trim() : process.cwd();
16056
+ const optionCwd = typeof mergedOptions.cwd === "string" && mergedOptions.cwd.trim().length > 0 ? mergedOptions.cwd.trim() : extractOptionValueFromArgv(process.argv.slice(2), "--cwd", "-w");
16057
+ const workingDirectory = typeof optionCwd === "string" && optionCwd.trim().length > 0 ? optionCwd.trim() : process.cwd();
15467
16058
  const [{ loadConfig: loadConfig2 }, subagentModels, fsExtra2, nodePath] = await Promise.all([
15468
16059
  Promise.resolve().then(() => (init_config(), config_exports)),
15469
16060
  Promise.resolve().then(() => (init_subagent_models(), subagent_models_exports)),
@@ -15504,7 +16095,7 @@ function setupAliases(program) {
15504
16095
  )
15505
16096
  );
15506
16097
  } catch (error) {
15507
- handleCLIError(error, normalizeVerbose(commandOptions.verbose));
16098
+ handleCLIError(error, normalizeVerbose(mergedOptions.verbose));
15508
16099
  }
15509
16100
  });
15510
16101
  cmd.allowUnknownOption(true);
@@ -15701,6 +16292,11 @@ ${chalk21__default.default.blue.bold("Examples:")}
15701
16292
  ${chalk21__default.default.gray("# Shell safety")}
15702
16293
  ${chalk21__default.default.gray("Use single quotes or -f/stdin when prompts include backticks or $()")}
15703
16294
 
16295
+ ${chalk21__default.default.gray("# Prompt-time command substitution (per iteration)")}
16296
+ juno-code claude -p "Status: !'git status --short'"
16297
+ juno-code claude -i 3 -p "Recent commits:
16298
+ !\`\`\`git log -n 5 --oneline\`\`\`"
16299
+
15704
16300
  ${chalk21__default.default.gray("# Interactive project setup")}
15705
16301
  juno-code init --interactive
15706
16302