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.
- package/README.md +417 -203
- package/dist/bin/cli.d.mts +1 -1
- package/dist/bin/cli.d.ts +1 -1
- package/dist/bin/cli.js +1736 -976
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +1735 -975
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/bin/feedback-collector.js.map +1 -1
- package/dist/bin/feedback-collector.mjs.map +1 -1
- package/dist/index.d.mts +33 -7
- package/dist/index.d.ts +33 -7
- package/dist/index.js +202 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +202 -27
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/install_requirements.sh +41 -3
- package/dist/templates/scripts/kanban.sh +4 -0
- package/dist/templates/services/__pycache__/pi.cpython-313.pyc +0 -0
- package/dist/templates/services/pi.py +1281 -238
- package/dist/templates/skills/claude/kanban-workflow/SKILL.md +138 -0
- package/dist/templates/skills/claude/plan-kanban-tasks/SKILL.md +1 -1
- package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +4 -0
- package/dist/templates/skills/claude/understand-project/SKILL.md +1 -1
- package/dist/templates/skills/codex/kanban-workflow/SKILL.md +139 -0
- package/dist/templates/skills/codex/plan-kanban-tasks/SKILL.md +32 -0
- package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +4 -0
- package/dist/templates/skills/codex/understand-project/SKILL.md +46 -0
- package/dist/templates/skills/pi/kanban-workflow/SKILL.md +139 -0
- package/dist/templates/skills/pi/plan-kanban-tasks/SKILL.md +1 -1
- package/dist/templates/skills/pi/ralph-loop/SKILL.md +4 -0
- package/dist/templates/skills/pi/understand-project/SKILL.md +1 -1
- 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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
|
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.
|
|
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
|
-
|
|
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;
|