juno-code 1.0.49 → 1.0.50

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.
Files changed (32) hide show
  1. package/README.md +417 -203
  2. package/dist/bin/cli.d.mts +1 -1
  3. package/dist/bin/cli.d.ts +1 -1
  4. package/dist/bin/cli.js +1736 -976
  5. package/dist/bin/cli.js.map +1 -1
  6. package/dist/bin/cli.mjs +1735 -975
  7. package/dist/bin/cli.mjs.map +1 -1
  8. package/dist/bin/feedback-collector.js.map +1 -1
  9. package/dist/bin/feedback-collector.mjs.map +1 -1
  10. package/dist/index.d.mts +33 -7
  11. package/dist/index.d.ts +33 -7
  12. package/dist/index.js +202 -27
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +202 -27
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/templates/scripts/install_requirements.sh +41 -3
  17. package/dist/templates/scripts/kanban.sh +4 -0
  18. package/dist/templates/services/__pycache__/pi.cpython-313.pyc +0 -0
  19. package/dist/templates/services/pi.py +1281 -238
  20. package/dist/templates/skills/claude/kanban-workflow/SKILL.md +138 -0
  21. package/dist/templates/skills/claude/plan-kanban-tasks/SKILL.md +1 -1
  22. package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +4 -0
  23. package/dist/templates/skills/claude/understand-project/SKILL.md +1 -1
  24. package/dist/templates/skills/codex/kanban-workflow/SKILL.md +139 -0
  25. package/dist/templates/skills/codex/plan-kanban-tasks/SKILL.md +32 -0
  26. package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +4 -0
  27. package/dist/templates/skills/codex/understand-project/SKILL.md +46 -0
  28. package/dist/templates/skills/pi/kanban-workflow/SKILL.md +139 -0
  29. package/dist/templates/skills/pi/plan-kanban-tasks/SKILL.md +1 -1
  30. package/dist/templates/skills/pi/ralph-loop/SKILL.md +4 -0
  31. package/dist/templates/skills/pi/understand-project/SKILL.md +1 -1
  32. package/package.json +7 -5
package/dist/index.mjs CHANGED
@@ -34,7 +34,7 @@ var __export = (target, all) => {
34
34
  var version;
35
35
  var init_version = __esm({
36
36
  "src/version.ts"() {
37
- version = "1.0.49";
37
+ version = "1.0.50";
38
38
  }
39
39
  });
40
40
 
@@ -985,6 +985,9 @@ var init_shell_backend = __esm({
985
985
  args.push("--disallowedTools");
986
986
  args.push(...request.arguments.disallowedTools);
987
987
  }
988
+ if (isPython && request.arguments?.thinking) {
989
+ args.push("--thinking", String(request.arguments.thinking));
990
+ }
988
991
  if (isPython && request.arguments?.resume) {
989
992
  args.push("--resume", String(request.arguments.resume));
990
993
  }
@@ -1088,7 +1091,8 @@ var init_shell_backend = __esm({
1088
1091
  subAgentResponse = JSON.parse(captured);
1089
1092
  }
1090
1093
  } catch (error) {
1091
- if (this.config?.debug) {
1094
+ const isNotFound = error?.code === "ENOENT";
1095
+ if (!isNotFound && this.config?.debug) {
1092
1096
  engineLogger.warn(
1093
1097
  `Failed to read subagent capture: ${error instanceof Error ? error.message : String(error)}`
1094
1098
  );
@@ -1299,6 +1303,8 @@ var init_shell_backend = __esm({
1299
1303
  delete inner.type;
1300
1304
  sanitizedPiEvent.sub_agent_response = inner;
1301
1305
  }
1306
+ const usage = piEvent.usage;
1307
+ const totalCostUsd = typeof piEvent.total_cost_usd === "number" ? piEvent.total_cost_usd : typeof usage?.cost?.total === "number" ? usage.cost.total : void 0;
1302
1308
  const structuredPayload = {
1303
1309
  type: "result",
1304
1310
  subtype: piEvent.subtype || (isError ? "error" : "success"),
@@ -1309,7 +1315,8 @@ var init_shell_backend = __esm({
1309
1315
  session_id: piEvent.session_id,
1310
1316
  exit_code: result.exitCode,
1311
1317
  duration_ms: piEvent.duration_ms ?? result.duration,
1312
- usage: piEvent.usage,
1318
+ total_cost_usd: totalCostUsd,
1319
+ usage,
1313
1320
  sub_agent_response: sanitizedPiEvent
1314
1321
  };
1315
1322
  const metadata = {
@@ -1754,13 +1761,25 @@ var JunoTaskConfigSchema = z.object({
1754
1761
  // Logging settings
1755
1762
  logLevel: LogLevelSchema.describe("Logging level for the application"),
1756
1763
  logFile: z.string().optional().describe("Path to log file (optional)"),
1757
- verbose: z.boolean().describe("Enable verbose output"),
1764
+ verbose: z.preprocess(
1765
+ (val) => {
1766
+ if (val === true) return 1;
1767
+ if (val === false) return 0;
1768
+ if (typeof val === "string") {
1769
+ const lower = val.toLowerCase().trim();
1770
+ if (lower === "true" || lower === "yes") return 1;
1771
+ if (lower === "false" || lower === "no") return 0;
1772
+ }
1773
+ return val;
1774
+ },
1775
+ z.number().int().min(0).max(2)
1776
+ ).describe("Verbosity level: 0=quiet, 1=normal+helping texts (default), 2=debug+hooks"),
1758
1777
  quiet: z.boolean().describe("Enable quiet mode (minimal output)"),
1759
1778
  // MCP settings
1760
1779
  mcpTimeout: z.number().int().min(1e3).max(864e5).describe("MCP server timeout in milliseconds"),
1761
1780
  mcpRetries: z.number().int().min(0).max(10).describe("Number of retries for MCP operations"),
1762
1781
  mcpServerPath: z.string().optional().describe("Path to MCP server executable (auto-discovered if not specified)"),
1763
- mcpServerName: z.string().optional().describe('Named MCP server to connect to (e.g., "roundtable-ai")'),
1782
+ mcpServerName: z.string().optional().describe("Named MCP server to connect to"),
1764
1783
  // Hook settings
1765
1784
  hookCommandTimeout: z.number().int().min(1e3).max(36e5).optional().describe(
1766
1785
  "Timeout for individual hook commands in milliseconds (default: 300000 = 5 minutes)"
@@ -1775,6 +1794,11 @@ var JunoTaskConfigSchema = z.object({
1775
1794
  // Paths
1776
1795
  workingDirectory: z.string().describe("Working directory for task execution"),
1777
1796
  sessionDirectory: z.string().describe("Directory for storing session data"),
1797
+ // Project environment bootstrap
1798
+ envFilePath: z.string().optional().describe(
1799
+ "Path to the project env file loaded before execution (relative to project root or absolute)"
1800
+ ),
1801
+ envFileCopied: z.boolean().optional().describe("Tracks whether configured env file has been initialized from .env.juno"),
1778
1802
  // Hooks configuration
1779
1803
  hooks: HooksSchema.describe(
1780
1804
  "Hook system configuration for executing commands at specific lifecycle events"
@@ -1789,14 +1813,12 @@ var DEFAULT_CONFIG = {
1789
1813
  defaultMaxIterations: 1,
1790
1814
  // Logging settings
1791
1815
  logLevel: "info",
1792
- verbose: false,
1816
+ verbose: 1,
1793
1817
  quiet: false,
1794
1818
  // MCP settings (also used by shell backend)
1795
1819
  mcpTimeout: 432e5,
1796
1820
  // 43200 seconds (12 hours) - default for long-running shell backend operations
1797
1821
  mcpRetries: 3,
1798
- mcpServerName: "roundtable-ai",
1799
- // Default to roundtable-ai server
1800
1822
  // Quota/hourly limit settings
1801
1823
  onHourlyLimit: "raise",
1802
1824
  // Default to exit immediately when hourly limit is reached
@@ -1806,6 +1828,9 @@ var DEFAULT_CONFIG = {
1806
1828
  // Paths
1807
1829
  workingDirectory: process.cwd(),
1808
1830
  sessionDirectory: path4.join(process.cwd(), ".juno_task"),
1831
+ // Project environment bootstrap
1832
+ envFilePath: ".env.juno",
1833
+ envFileCopied: false,
1809
1834
  // Hooks configuration - populated with default hooks template
1810
1835
  hooks: getDefaultHooks()
1811
1836
  };
@@ -1818,6 +1843,7 @@ var GLOBAL_CONFIG_FILE_NAMES = [
1818
1843
  // Will look for 'junoCode' field
1819
1844
  ];
1820
1845
  var PROJECT_CONFIG_FILE = ".juno_task/config.json";
1846
+ var DEFAULT_PROJECT_ENV_FILE = ".env.juno";
1821
1847
  function resolvePath(inputPath, basePath = process.cwd()) {
1822
1848
  if (path4.isAbsolute(inputPath)) {
1823
1849
  return inputPath;
@@ -1839,7 +1865,12 @@ function loadConfigFromEnv() {
1839
1865
  for (const [envVar, configKey] of Object.entries(ENV_VAR_MAPPING)) {
1840
1866
  const value = process.env[envVar];
1841
1867
  if (value !== void 0) {
1842
- config[configKey] = parseEnvValue(value);
1868
+ let parsed = parseEnvValue(value);
1869
+ if (configKey === "verbose") {
1870
+ if (parsed === true) parsed = 1;
1871
+ else if (parsed === false) parsed = 0;
1872
+ }
1873
+ config[configKey] = parsed;
1843
1874
  }
1844
1875
  }
1845
1876
  return config;
@@ -2073,6 +2104,95 @@ function validateConfig(config) {
2073
2104
  throw error;
2074
2105
  }
2075
2106
  }
2107
+ function parseEnvFileContent(content) {
2108
+ const envVars = {};
2109
+ const lines = content.split(/\r?\n/);
2110
+ for (const rawLine of lines) {
2111
+ const trimmedLine = rawLine.trim();
2112
+ if (!trimmedLine || trimmedLine.startsWith("#")) {
2113
+ continue;
2114
+ }
2115
+ const line = trimmedLine.startsWith("export ") ? trimmedLine.slice(7).trim() : trimmedLine;
2116
+ const separatorIndex = line.indexOf("=");
2117
+ if (separatorIndex === -1) {
2118
+ continue;
2119
+ }
2120
+ const key = line.slice(0, separatorIndex).trim();
2121
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
2122
+ continue;
2123
+ }
2124
+ let value = line.slice(separatorIndex + 1).trim();
2125
+ if ((value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) && value.length >= 2) {
2126
+ const quote = value[0];
2127
+ value = value.slice(1, -1);
2128
+ if (quote === '"') {
2129
+ value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ");
2130
+ }
2131
+ } else {
2132
+ const inlineCommentIndex = value.indexOf(" #");
2133
+ if (inlineCommentIndex >= 0) {
2134
+ value = value.slice(0, inlineCommentIndex).trimEnd();
2135
+ }
2136
+ }
2137
+ envVars[key] = value;
2138
+ }
2139
+ return envVars;
2140
+ }
2141
+ async function loadEnvFileIntoProcess(envFilePath) {
2142
+ try {
2143
+ const content = await promises.readFile(envFilePath, "utf-8");
2144
+ const parsed = parseEnvFileContent(content);
2145
+ for (const [key, value] of Object.entries(parsed)) {
2146
+ process.env[key] = value;
2147
+ }
2148
+ } catch (error) {
2149
+ console.warn(`Warning: Failed to load env file ${envFilePath}: ${error}`);
2150
+ }
2151
+ }
2152
+ async function ensureAndLoadProjectEnv(baseDir) {
2153
+ const configPath = path4.join(baseDir, PROJECT_CONFIG_FILE);
2154
+ const defaultEnvPath = resolvePath(DEFAULT_PROJECT_ENV_FILE, baseDir);
2155
+ await fs.ensureFile(defaultEnvPath);
2156
+ let existingConfig = null;
2157
+ if (await fs.pathExists(configPath)) {
2158
+ try {
2159
+ existingConfig = await fs.readJson(configPath);
2160
+ } catch (error) {
2161
+ console.warn(`Warning: Failed to read ${configPath} for env bootstrap: ${error}`);
2162
+ }
2163
+ }
2164
+ const configuredEnvPathRaw = existingConfig && typeof existingConfig.envFilePath === "string" && existingConfig.envFilePath ? existingConfig.envFilePath : DEFAULT_PROJECT_ENV_FILE;
2165
+ const configuredEnvPath = resolvePath(configuredEnvPathRaw, baseDir);
2166
+ let envFileCopied = existingConfig && typeof existingConfig.envFileCopied === "boolean" ? existingConfig.envFileCopied : false;
2167
+ let needsConfigUpdate = false;
2168
+ if (configuredEnvPath !== defaultEnvPath) {
2169
+ const configuredExists = await fs.pathExists(configuredEnvPath);
2170
+ if (!configuredExists) {
2171
+ await fs.ensureDir(path4.dirname(configuredEnvPath));
2172
+ if (!envFileCopied) {
2173
+ await promises.copyFile(defaultEnvPath, configuredEnvPath);
2174
+ } else {
2175
+ await fs.ensureFile(configuredEnvPath);
2176
+ }
2177
+ }
2178
+ if (!envFileCopied) {
2179
+ envFileCopied = true;
2180
+ needsConfigUpdate = true;
2181
+ }
2182
+ }
2183
+ if (existingConfig && (needsConfigUpdate || typeof existingConfig.envFilePath !== "string" || typeof existingConfig.envFileCopied !== "boolean")) {
2184
+ const updatedConfig = {
2185
+ ...existingConfig,
2186
+ envFilePath: configuredEnvPathRaw,
2187
+ envFileCopied
2188
+ };
2189
+ await fs.writeJson(configPath, updatedConfig, { spaces: 2 });
2190
+ }
2191
+ await loadEnvFileIntoProcess(defaultEnvPath);
2192
+ if (configuredEnvPath !== defaultEnvPath) {
2193
+ await loadEnvFileIntoProcess(configuredEnvPath);
2194
+ }
2195
+ }
2076
2196
  async function ensureHooksConfig(baseDir) {
2077
2197
  try {
2078
2198
  const configDir = path4.join(baseDir, ".juno_task");
@@ -2108,6 +2228,14 @@ async function ensureHooksConfig(baseDir) {
2108
2228
  existingConfig.defaultMaxIterations = DEFAULT_CONFIG.defaultMaxIterations;
2109
2229
  needsUpdate = true;
2110
2230
  }
2231
+ if (!existingConfig.envFilePath) {
2232
+ existingConfig.envFilePath = DEFAULT_PROJECT_ENV_FILE;
2233
+ needsUpdate = true;
2234
+ }
2235
+ if (typeof existingConfig.envFileCopied !== "boolean") {
2236
+ existingConfig.envFileCopied = false;
2237
+ needsUpdate = true;
2238
+ }
2111
2239
  if (needsUpdate) {
2112
2240
  await fs.writeJson(configPath, existingConfig, { spaces: 2 });
2113
2241
  }
@@ -2119,6 +2247,7 @@ async function ensureHooksConfig(baseDir) {
2119
2247
  async function loadConfig(options = {}) {
2120
2248
  const { baseDir = process.cwd(), configFile, cliConfig } = options;
2121
2249
  await ensureHooksConfig(baseDir);
2250
+ await ensureAndLoadProjectEnv(baseDir);
2122
2251
  const loader = new ConfigLoader(baseDir);
2123
2252
  loader.fromEnvironment();
2124
2253
  if (configFile) {
@@ -2151,7 +2280,7 @@ async function executeHook(hookType, hooks, context = {}, options = {}) {
2151
2280
  logContext = "SYSTEM" /* SYSTEM */
2152
2281
  } = options;
2153
2282
  const contextLogger = logger.child(logContext);
2154
- contextLogger.info(`Starting hook execution: ${hookType}`, {
2283
+ contextLogger.debug(`Starting hook execution: ${hookType}`, {
2155
2284
  context,
2156
2285
  workingDirectory: context.workingDirectory || process.cwd(),
2157
2286
  commandTimeout,
@@ -2180,13 +2309,13 @@ async function executeHook(hookType, hooks, context = {}, options = {}) {
2180
2309
  commandsFailed: 0
2181
2310
  };
2182
2311
  }
2183
- contextLogger.info(`Executing ${hook.commands.length} commands for hook ${hookType}`);
2312
+ contextLogger.debug(`Executing ${hook.commands.length} commands for hook ${hookType}`);
2184
2313
  const commandResults = [];
2185
2314
  let commandsFailed = 0;
2186
2315
  for (let i = 0; i < hook.commands.length; i++) {
2187
2316
  const command = hook.commands[i];
2188
2317
  const commandStartTime = Date.now();
2189
- contextLogger.info(`Executing command ${i + 1}/${hook.commands.length}: ${command}`, {
2318
+ contextLogger.debug(`Executing command ${i + 1}/${hook.commands.length}: ${command}`, {
2190
2319
  commandIndex: i,
2191
2320
  totalCommands: hook.commands.length
2192
2321
  });
@@ -2234,7 +2363,7 @@ async function executeHook(hookType, hooks, context = {}, options = {}) {
2234
2363
  };
2235
2364
  commandResults.push(commandResult);
2236
2365
  if (success2) {
2237
- contextLogger.info(`Command completed successfully`, {
2366
+ contextLogger.debug(`Command completed successfully`, {
2238
2367
  command,
2239
2368
  exitCode: result2.exitCode,
2240
2369
  duration,
@@ -2315,7 +2444,7 @@ async function executeHook(hookType, hooks, context = {}, options = {}) {
2315
2444
  commandsExecuted,
2316
2445
  commandsFailed
2317
2446
  };
2318
- contextLogger.info(`Hook execution completed`, {
2447
+ contextLogger.debug(`Hook execution completed`, {
2319
2448
  hookType,
2320
2449
  totalDuration,
2321
2450
  commandsExecuted,
@@ -2326,7 +2455,7 @@ async function executeHook(hookType, hooks, context = {}, options = {}) {
2326
2455
  }
2327
2456
  async function executeHooks(hookTypes, hooks, context = {}, options = {}) {
2328
2457
  const results = [];
2329
- hookLogger.info(`Starting batch hook execution`, {
2458
+ hookLogger.debug(`Starting batch hook execution`, {
2330
2459
  hookTypes,
2331
2460
  context
2332
2461
  });
@@ -2337,7 +2466,7 @@ async function executeHooks(hookTypes, hooks, context = {}, options = {}) {
2337
2466
  const totalSuccess = results.every((r) => r.success);
2338
2467
  const totalCommands = results.reduce((sum, r) => sum + r.commandsExecuted, 0);
2339
2468
  const totalFailed = results.reduce((sum, r) => sum + r.commandsFailed, 0);
2340
- hookLogger.info(`Batch hook execution completed`, {
2469
+ hookLogger.debug(`Batch hook execution completed`, {
2341
2470
  hookTypes,
2342
2471
  totalHooks: results.length,
2343
2472
  totalCommands,
@@ -2629,6 +2758,30 @@ var ExecutionEngine = class extends EventEmitter {
2629
2758
  */
2630
2759
  setupProgressTracking() {
2631
2760
  }
2761
+ /**
2762
+ * Display hook execution output to stderr at verbose level 2 (debug+hooks).
2763
+ * At level 2: shows hook name, command stdout/stderr output.
2764
+ * At level 0-1: output is suppressed (hooks still execute).
2765
+ */
2766
+ displayHookOutput(hookResult) {
2767
+ if (this.engineConfig.config.verbose < 2) return;
2768
+ for (const cmdResult of hookResult.commandResults) {
2769
+ const prefix = `[hook:${hookResult.hookType}]`;
2770
+ if (cmdResult.stdout) {
2771
+ for (const line of cmdResult.stdout.split("\n")) {
2772
+ if (line.trim()) console.error(`${prefix} ${line}`);
2773
+ }
2774
+ }
2775
+ if (cmdResult.stderr) {
2776
+ for (const line of cmdResult.stderr.split("\n")) {
2777
+ if (line.trim()) console.error(`${prefix} ${line}`);
2778
+ }
2779
+ }
2780
+ if (!cmdResult.success) {
2781
+ console.error(`${prefix} command failed (exit ${cmdResult.exitCode}): ${cmdResult.command}`);
2782
+ }
2783
+ }
2784
+ }
2632
2785
  /**
2633
2786
  * Initialize backend for execution request.
2634
2787
  * Directly creates and configures a ShellBackend (no factory indirection).
@@ -2643,11 +2796,14 @@ var ExecutionEngine = class extends EventEmitter {
2643
2796
  backend.configure({
2644
2797
  workingDirectory: request.workingDirectory,
2645
2798
  servicesPath: `${process.env.HOME || process.env.USERPROFILE}/.juno_code/services`,
2646
- debug: this.engineConfig.config.verbose,
2799
+ debug: this.engineConfig.config.verbose >= 2,
2647
2800
  timeout: request.timeoutMs || this.engineConfig.config.mcpTimeout || 432e5,
2648
2801
  enableJsonStreaming: true,
2649
- outputRawJson: this.engineConfig.config.verbose,
2650
- environment: process.env,
2802
+ outputRawJson: this.engineConfig.config.verbose >= 1,
2803
+ environment: {
2804
+ ...process.env,
2805
+ JUNO_TASK_ROOT: process.env.JUNO_TASK_ROOT || request.workingDirectory
2806
+ },
2651
2807
  sessionId: request.requestId
2652
2808
  });
2653
2809
  await backend.initialize();
@@ -2669,7 +2825,7 @@ var ExecutionEngine = class extends EventEmitter {
2669
2825
  this.emit("progress:error", { event, error });
2670
2826
  }
2671
2827
  });
2672
- engineLogger.info(`Initialized ${backend.name} backend for execution`);
2828
+ engineLogger.debug(`Initialized ${backend.name} backend for execution`);
2673
2829
  }
2674
2830
  /**
2675
2831
  * Validate execution request parameters
@@ -2772,10 +2928,13 @@ var ExecutionEngine = class extends EventEmitter {
2772
2928
  async executeInternal(context) {
2773
2929
  context.status = "running" /* RUNNING */;
2774
2930
  context.sessionContext = { ...context.sessionContext, state: "active" };
2931
+ if (!process.env.JUNO_TASK_ROOT) {
2932
+ process.env.JUNO_TASK_ROOT = context.request.workingDirectory;
2933
+ }
2775
2934
  await this.initializeBackend(context.request);
2776
2935
  try {
2777
2936
  if (this.engineConfig.config.hooks && !this.engineConfig.config.skipHooks) {
2778
- await executeHook(
2937
+ const hookResult = await executeHook(
2779
2938
  "START_RUN",
2780
2939
  this.engineConfig.config.hooks,
2781
2940
  {
@@ -2795,6 +2954,7 @@ var ExecutionEngine = class extends EventEmitter {
2795
2954
  commandTimeout: this.engineConfig.config.hookCommandTimeout
2796
2955
  }
2797
2956
  );
2957
+ this.displayHookOutput(hookResult);
2798
2958
  }
2799
2959
  } catch (error) {
2800
2960
  engineLogger.warn("Hook START_RUN failed", { error });
@@ -2818,7 +2978,7 @@ var ExecutionEngine = class extends EventEmitter {
2818
2978
  }
2819
2979
  try {
2820
2980
  if (this.engineConfig.config.hooks && !this.engineConfig.config.skipHooks) {
2821
- await executeHook(
2981
+ const hookResult = await executeHook(
2822
2982
  "END_RUN",
2823
2983
  this.engineConfig.config.hooks,
2824
2984
  {
@@ -2840,6 +3000,7 @@ var ExecutionEngine = class extends EventEmitter {
2840
3000
  commandTimeout: this.engineConfig.config.hookCommandTimeout
2841
3001
  }
2842
3002
  );
3003
+ this.displayHookOutput(hookResult);
2843
3004
  }
2844
3005
  } catch (error) {
2845
3006
  engineLogger.warn("Hook END_RUN failed", { error });
@@ -2884,7 +3045,7 @@ var ExecutionEngine = class extends EventEmitter {
2884
3045
  const iterationStart = /* @__PURE__ */ new Date();
2885
3046
  try {
2886
3047
  if (this.engineConfig.config.hooks && !this.engineConfig.config.skipHooks) {
2887
- await executeHook(
3048
+ const hookResult = await executeHook(
2888
3049
  "START_ITERATION",
2889
3050
  this.engineConfig.config.hooks,
2890
3051
  {
@@ -2905,6 +3066,7 @@ var ExecutionEngine = class extends EventEmitter {
2905
3066
  commandTimeout: this.engineConfig.config.hookCommandTimeout
2906
3067
  }
2907
3068
  );
3069
+ this.displayHookOutput(hookResult);
2908
3070
  }
2909
3071
  } catch (error) {
2910
3072
  engineLogger.warn("Hook START_ITERATION failed", { error, iterationNumber });
@@ -2931,6 +3093,7 @@ var ExecutionEngine = class extends EventEmitter {
2931
3093
  ...context.request.continueConversation !== void 0 && {
2932
3094
  continueConversation: context.request.continueConversation
2933
3095
  },
3096
+ ...context.request.thinking !== void 0 && { thinking: context.request.thinking },
2934
3097
  iteration: iterationNumber
2935
3098
  },
2936
3099
  timeout: context.request.timeoutMs || this.engineConfig.config.mcpTimeout,
@@ -2967,7 +3130,7 @@ var ExecutionEngine = class extends EventEmitter {
2967
3130
  this.emit("iteration:complete", { context, iterationResult });
2968
3131
  try {
2969
3132
  if (this.engineConfig.config.hooks && !this.engineConfig.config.skipHooks) {
2970
- await executeHook(
3133
+ const hookResult = await executeHook(
2971
3134
  "END_ITERATION",
2972
3135
  this.engineConfig.config.hooks,
2973
3136
  {
@@ -2989,6 +3152,7 @@ var ExecutionEngine = class extends EventEmitter {
2989
3152
  commandTimeout: this.engineConfig.config.hookCommandTimeout
2990
3153
  }
2991
3154
  );
3155
+ this.displayHookOutput(hookResult);
2992
3156
  }
2993
3157
  } catch (error) {
2994
3158
  engineLogger.warn("Hook END_ITERATION failed", { error, iterationNumber });
@@ -3023,7 +3187,7 @@ var ExecutionEngine = class extends EventEmitter {
3023
3187
  this.emit("iteration:error", { context, iterationResult });
3024
3188
  try {
3025
3189
  if (this.engineConfig.config.hooks && !this.engineConfig.config.skipHooks) {
3026
- await executeHook(
3190
+ const hookResult = await executeHook(
3027
3191
  "END_ITERATION",
3028
3192
  this.engineConfig.config.hooks,
3029
3193
  {
@@ -3046,6 +3210,7 @@ var ExecutionEngine = class extends EventEmitter {
3046
3210
  commandTimeout: this.engineConfig.config.hookCommandTimeout
3047
3211
  }
3048
3212
  );
3213
+ this.displayHookOutput(hookResult);
3049
3214
  }
3050
3215
  } catch (hookError) {
3051
3216
  engineLogger.warn("Hook END_ITERATION failed", { error: hookError, iterationNumber });
@@ -3521,6 +3686,9 @@ function createExecutionRequest(options) {
3521
3686
  if (options.continueConversation !== void 0) {
3522
3687
  result.continueConversation = options.continueConversation;
3523
3688
  }
3689
+ if (options.thinking !== void 0) {
3690
+ result.thinking = options.thinking;
3691
+ }
3524
3692
  return result;
3525
3693
  }
3526
3694
 
@@ -4200,9 +4368,16 @@ function validateEnvironmentVars(envVars) {
4200
4368
  case "JUNO_TASK_DEFAULT_MAX_ITERATIONS":
4201
4369
  config.defaultMaxIterations = validateIterations(parseInt(value, 10));
4202
4370
  break;
4203
- case "JUNO_TASK_VERBOSE":
4204
- config.verbose = value.toLowerCase() === "true";
4371
+ case "JUNO_TASK_VERBOSE": {
4372
+ const lower = value.toLowerCase();
4373
+ if (lower === "true" || lower === "yes") config.verbose = 1;
4374
+ else if (lower === "false" || lower === "no") config.verbose = 0;
4375
+ else {
4376
+ const n = Number(value);
4377
+ config.verbose = !isNaN(n) && n >= 0 && n <= 2 ? Math.floor(n) : 1;
4378
+ }
4205
4379
  break;
4380
+ }
4206
4381
  case "JUNO_TASK_QUIET":
4207
4382
  config.quiet = value.toLowerCase() === "true";
4208
4383
  break;