juno-code 1.0.50 → 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/README.md +157 -8
- package/dist/bin/cli.js +3103 -1356
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +3082 -1335
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.d.mts +26 -12
- package/dist/index.d.ts +26 -12
- package/dist/index.js +407 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +405 -65
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/__pycache__/parallel_runner.cpython-313.pyc +0 -0
- package/dist/templates/scripts/install_requirements.sh +35 -2
- package/dist/templates/scripts/kanban.sh +11 -0
- package/dist/templates/scripts/parallel_runner.sh +602 -131
- package/dist/templates/services/README.md +23 -4
- package/dist/templates/services/__pycache__/pi.cpython-313.pyc +0 -0
- package/dist/templates/services/__pycache__/pi.cpython-38.pyc +0 -0
- package/dist/templates/services/pi.py +1034 -39
- package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +11 -0
- package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +11 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chalk = require('chalk');
|
|
5
|
-
var
|
|
5
|
+
var childProcess = require('child_process');
|
|
6
6
|
var fs3 = require('fs');
|
|
7
7
|
var path4 = require('path');
|
|
8
8
|
var os2 = require('os');
|
|
@@ -11,6 +11,7 @@ var zod = require('zod');
|
|
|
11
11
|
var yaml = require('js-yaml');
|
|
12
12
|
var events = require('events');
|
|
13
13
|
var execa = require('execa');
|
|
14
|
+
var util = require('util');
|
|
14
15
|
var uuid = require('uuid');
|
|
15
16
|
var process2 = require('process');
|
|
16
17
|
|
|
@@ -35,6 +36,7 @@ function _interopNamespace(e) {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
39
|
+
var childProcess__namespace = /*#__PURE__*/_interopNamespace(childProcess);
|
|
38
40
|
var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
|
|
39
41
|
var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
|
|
40
42
|
var os2__namespace = /*#__PURE__*/_interopNamespace(os2);
|
|
@@ -62,7 +64,7 @@ var __export = (target, all) => {
|
|
|
62
64
|
exports.version = void 0;
|
|
63
65
|
var init_version = __esm({
|
|
64
66
|
"src/version.ts"() {
|
|
65
|
-
exports.version = "1.0.
|
|
67
|
+
exports.version = "1.0.53";
|
|
66
68
|
}
|
|
67
69
|
});
|
|
68
70
|
|
|
@@ -750,25 +752,28 @@ var init_shell_backend = __esm({
|
|
|
750
752
|
const scriptPath = await this.findScriptForSubagent(subagentType);
|
|
751
753
|
const result = await this.executeScript(scriptPath, request, toolId, subagentType);
|
|
752
754
|
const duration = Date.now() - startTime;
|
|
755
|
+
const structuredResult = this.buildStructuredOutput(subagentType, result);
|
|
756
|
+
const structuredPayload = this.parseStructuredResultPayload(structuredResult.content);
|
|
757
|
+
const structuredIndicatesError = structuredPayload?.is_error === true || structuredPayload?.subtype === "error";
|
|
758
|
+
const executionSucceeded = result.success && !structuredIndicatesError;
|
|
753
759
|
await this.emitProgressEvent({
|
|
754
760
|
sessionId: request.metadata?.sessionId || "unknown",
|
|
755
761
|
timestamp: /* @__PURE__ */ new Date(),
|
|
756
762
|
backend: "shell",
|
|
757
763
|
count: ++this.eventCounter,
|
|
758
764
|
type: "tool_result" /* TOOL_RESULT */,
|
|
759
|
-
content: `${request.toolName} completed successfully (${duration}ms)`,
|
|
765
|
+
content: executionSucceeded ? `${request.toolName} completed successfully (${duration}ms)` : `${request.toolName} completed with error (${duration}ms)`,
|
|
760
766
|
toolId,
|
|
761
767
|
metadata: {
|
|
762
768
|
toolName: request.toolName,
|
|
763
769
|
duration,
|
|
764
|
-
success:
|
|
770
|
+
success: executionSucceeded,
|
|
765
771
|
phase: "completion"
|
|
766
772
|
}
|
|
767
773
|
});
|
|
768
|
-
const structuredResult = this.buildStructuredOutput(subagentType, result);
|
|
769
774
|
const toolResult = {
|
|
770
775
|
content: structuredResult.content,
|
|
771
|
-
status:
|
|
776
|
+
status: executionSucceeded ? "completed" /* COMPLETED */ : "failed" /* FAILED */,
|
|
772
777
|
startTime: new Date(startTime),
|
|
773
778
|
endTime: /* @__PURE__ */ new Date(),
|
|
774
779
|
duration,
|
|
@@ -777,6 +782,9 @@ var init_shell_backend = __esm({
|
|
|
777
782
|
};
|
|
778
783
|
if (result.error) {
|
|
779
784
|
toolResult.error = new Error(result.error);
|
|
785
|
+
} else if (!executionSucceeded) {
|
|
786
|
+
const structuredErrorMessage = typeof structuredPayload?.error === "string" && structuredPayload.error || typeof structuredPayload?.result === "string" && structuredPayload.result || `${request.toolName} reported a structured error`;
|
|
787
|
+
toolResult.error = new Error(structuredErrorMessage);
|
|
780
788
|
}
|
|
781
789
|
if (structuredResult.metadata) {
|
|
782
790
|
toolResult.metadata = structuredResult.metadata;
|
|
@@ -1025,6 +1033,12 @@ var init_shell_backend = __esm({
|
|
|
1025
1033
|
if (isPython && subagentType === "pi" && request.arguments?.project_path) {
|
|
1026
1034
|
args.push("--cd", String(request.arguments.project_path));
|
|
1027
1035
|
}
|
|
1036
|
+
if (isPython && subagentType === "pi" && request.arguments?.live === true) {
|
|
1037
|
+
args.push("--live");
|
|
1038
|
+
}
|
|
1039
|
+
if (isPython && subagentType === "pi" && request.arguments?.liveInteractiveSession === true) {
|
|
1040
|
+
args.push("--live-manual");
|
|
1041
|
+
}
|
|
1028
1042
|
if (isPython && this.config.debug) {
|
|
1029
1043
|
args.push("--verbose");
|
|
1030
1044
|
}
|
|
@@ -1042,12 +1056,19 @@ var init_shell_backend = __esm({
|
|
|
1042
1056
|
`Environment variables: ${Object.keys(env2).filter((k) => k.startsWith("JUNO_") || k.startsWith("PI_")).join(", ")}`
|
|
1043
1057
|
);
|
|
1044
1058
|
}
|
|
1045
|
-
const
|
|
1059
|
+
const isPiLiveMode = isPython && subagentType === "pi" && request.arguments?.live === true;
|
|
1060
|
+
const shouldAttachLiveTerminal = isPiLiveMode && process.stdout.isTTY === true;
|
|
1061
|
+
if (this.config.debug && isPiLiveMode) {
|
|
1062
|
+
engineLogger.debug(
|
|
1063
|
+
`Pi live mode stdio: ${shouldAttachLiveTerminal ? "inherit (interactive TTY or stdout-tty fallback)" : "pipe (headless/non-TTY)"}`
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
const child = childProcess.spawn(command, args, {
|
|
1046
1067
|
env: env2,
|
|
1047
1068
|
cwd: this.config.workingDirectory,
|
|
1048
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1069
|
+
stdio: shouldAttachLiveTerminal ? "inherit" : ["pipe", "pipe", "pipe"]
|
|
1049
1070
|
});
|
|
1050
|
-
if (child.stdin) {
|
|
1071
|
+
if (!shouldAttachLiveTerminal && child.stdin) {
|
|
1051
1072
|
child.stdin.end();
|
|
1052
1073
|
}
|
|
1053
1074
|
let stdout2 = "";
|
|
@@ -1300,8 +1321,19 @@ var init_shell_backend = __esm({
|
|
|
1300
1321
|
if (subagentType === "pi") {
|
|
1301
1322
|
const piEvent = result.subAgentResponse ?? this.extractLastJsonEvent(result.output);
|
|
1302
1323
|
if (piEvent) {
|
|
1303
|
-
|
|
1304
|
-
|
|
1324
|
+
const piNestedEvent = typeof piEvent.sub_agent_response === "object" && piEvent.sub_agent_response ? piEvent.sub_agent_response : void 0;
|
|
1325
|
+
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;
|
|
1326
|
+
const sanitizedPiEvent = { ...piEvent };
|
|
1327
|
+
delete sanitizedPiEvent.messages;
|
|
1328
|
+
if (sanitizedPiEvent.sub_agent_response && typeof sanitizedPiEvent.sub_agent_response === "object") {
|
|
1329
|
+
const inner = { ...sanitizedPiEvent.sub_agent_response };
|
|
1330
|
+
delete inner.messages;
|
|
1331
|
+
delete inner.type;
|
|
1332
|
+
sanitizedPiEvent.sub_agent_response = inner;
|
|
1333
|
+
}
|
|
1334
|
+
const hasDirectResultText = typeof piEvent.result === "string";
|
|
1335
|
+
let resultText = hasDirectResultText ? piEvent.result : void 0;
|
|
1336
|
+
if (resultText === void 0 && Array.isArray(piEvent.messages)) {
|
|
1305
1337
|
for (let i = piEvent.messages.length - 1; i >= 0; i--) {
|
|
1306
1338
|
const msg = piEvent.messages[i];
|
|
1307
1339
|
if (msg?.role === "assistant") {
|
|
@@ -1321,16 +1353,11 @@ var init_shell_backend = __esm({
|
|
|
1321
1353
|
}
|
|
1322
1354
|
}
|
|
1323
1355
|
}
|
|
1324
|
-
if (resultText) {
|
|
1356
|
+
if (resultText === void 0 && typeof piEvent.error === "string") {
|
|
1357
|
+
resultText = piEvent.error;
|
|
1358
|
+
}
|
|
1359
|
+
if (resultText !== void 0) {
|
|
1325
1360
|
const isError = piEvent.is_error ?? !result.success;
|
|
1326
|
-
const sanitizedPiEvent = { ...piEvent };
|
|
1327
|
-
delete sanitizedPiEvent.messages;
|
|
1328
|
-
if (sanitizedPiEvent.sub_agent_response && typeof sanitizedPiEvent.sub_agent_response === "object") {
|
|
1329
|
-
const inner = { ...sanitizedPiEvent.sub_agent_response };
|
|
1330
|
-
delete inner.messages;
|
|
1331
|
-
delete inner.type;
|
|
1332
|
-
sanitizedPiEvent.sub_agent_response = inner;
|
|
1333
|
-
}
|
|
1334
1361
|
const usage = piEvent.usage;
|
|
1335
1362
|
const totalCostUsd = typeof piEvent.total_cost_usd === "number" ? piEvent.total_cost_usd : typeof usage?.cost?.total === "number" ? usage.cost.total : void 0;
|
|
1336
1363
|
const structuredPayload = {
|
|
@@ -1338,9 +1365,9 @@ var init_shell_backend = __esm({
|
|
|
1338
1365
|
subtype: piEvent.subtype || (isError ? "error" : "success"),
|
|
1339
1366
|
is_error: isError,
|
|
1340
1367
|
result: resultText,
|
|
1341
|
-
error: piEvent.error,
|
|
1368
|
+
error: isError ? piEvent.error ?? result.error ?? resultText : piEvent.error,
|
|
1342
1369
|
stderr: result.error,
|
|
1343
|
-
session_id:
|
|
1370
|
+
session_id: piSessionId,
|
|
1344
1371
|
exit_code: result.exitCode,
|
|
1345
1372
|
duration_ms: piEvent.duration_ms ?? result.duration,
|
|
1346
1373
|
total_cost_usd: totalCostUsd,
|
|
@@ -1358,6 +1385,57 @@ var init_shell_backend = __esm({
|
|
|
1358
1385
|
metadata
|
|
1359
1386
|
};
|
|
1360
1387
|
}
|
|
1388
|
+
const isSessionSnapshotOnly = piEvent.type === "session" || piEvent.subtype === "session";
|
|
1389
|
+
if (isSessionSnapshotOnly) {
|
|
1390
|
+
const errorMessage = result.error?.trim() || "Pi exited before emitting a terminal result event (session snapshot only).";
|
|
1391
|
+
const structuredPayload = {
|
|
1392
|
+
type: "result",
|
|
1393
|
+
subtype: "error",
|
|
1394
|
+
is_error: true,
|
|
1395
|
+
result: errorMessage,
|
|
1396
|
+
error: errorMessage,
|
|
1397
|
+
stderr: result.error,
|
|
1398
|
+
session_id: piSessionId,
|
|
1399
|
+
exit_code: result.exitCode,
|
|
1400
|
+
duration_ms: result.duration,
|
|
1401
|
+
sub_agent_response: sanitizedPiEvent
|
|
1402
|
+
};
|
|
1403
|
+
const metadata = {
|
|
1404
|
+
...piEvent ? { subAgentResponse: piEvent } : void 0,
|
|
1405
|
+
structuredOutput: true,
|
|
1406
|
+
contentType: "application/json",
|
|
1407
|
+
rawOutput: result.output
|
|
1408
|
+
};
|
|
1409
|
+
return {
|
|
1410
|
+
content: JSON.stringify(structuredPayload),
|
|
1411
|
+
metadata
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
if (!result.success) {
|
|
1415
|
+
const errorMessage = result.error?.trim() || result.output?.trim() || "Unknown error";
|
|
1416
|
+
const structuredPayload = {
|
|
1417
|
+
type: "result",
|
|
1418
|
+
subtype: "error",
|
|
1419
|
+
is_error: true,
|
|
1420
|
+
result: errorMessage,
|
|
1421
|
+
error: errorMessage,
|
|
1422
|
+
stderr: result.error,
|
|
1423
|
+
session_id: piSessionId,
|
|
1424
|
+
exit_code: result.exitCode,
|
|
1425
|
+
duration_ms: result.duration,
|
|
1426
|
+
sub_agent_response: sanitizedPiEvent
|
|
1427
|
+
};
|
|
1428
|
+
const metadata = {
|
|
1429
|
+
...piEvent ? { subAgentResponse: piEvent } : void 0,
|
|
1430
|
+
structuredOutput: true,
|
|
1431
|
+
contentType: "application/json",
|
|
1432
|
+
rawOutput: result.output
|
|
1433
|
+
};
|
|
1434
|
+
return {
|
|
1435
|
+
content: JSON.stringify(structuredPayload),
|
|
1436
|
+
metadata
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1361
1439
|
}
|
|
1362
1440
|
}
|
|
1363
1441
|
if (!result.success) {
|
|
@@ -1422,6 +1500,20 @@ var init_shell_backend = __esm({
|
|
|
1422
1500
|
}
|
|
1423
1501
|
return null;
|
|
1424
1502
|
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Parse JSON structured output payload emitted by shell service wrappers.
|
|
1505
|
+
*/
|
|
1506
|
+
parseStructuredResultPayload(content) {
|
|
1507
|
+
try {
|
|
1508
|
+
const parsed = JSON.parse(content);
|
|
1509
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1510
|
+
return null;
|
|
1511
|
+
}
|
|
1512
|
+
return parsed;
|
|
1513
|
+
} catch {
|
|
1514
|
+
return null;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1425
1517
|
/**
|
|
1426
1518
|
* Extract the last valid JSON object from a script's stdout to use as a structured payload fallback.
|
|
1427
1519
|
*/
|
|
@@ -1735,6 +1827,41 @@ function getDefaultHooksJson(indent = 2) {
|
|
|
1735
1827
|
return JSON.stringify(DEFAULT_HOOKS, null, indent);
|
|
1736
1828
|
}
|
|
1737
1829
|
|
|
1830
|
+
// src/core/subagent-models.ts
|
|
1831
|
+
init_version();
|
|
1832
|
+
var SUBAGENT_DEFAULT_MODELS = {
|
|
1833
|
+
claude: ":sonnet",
|
|
1834
|
+
codex: ":codex",
|
|
1835
|
+
gemini: ":pro",
|
|
1836
|
+
cursor: "auto",
|
|
1837
|
+
pi: ":pi"
|
|
1838
|
+
};
|
|
1839
|
+
function isModelCompatibleWithSubagent(model, subagent) {
|
|
1840
|
+
if (!model.startsWith(":")) {
|
|
1841
|
+
return true;
|
|
1842
|
+
}
|
|
1843
|
+
const claudeShorthands = [":sonnet", ":haiku", ":opus"];
|
|
1844
|
+
const codexShorthands = [":codex", ":codex-mini", ":gpt-5", ":mini"];
|
|
1845
|
+
const geminiShorthands = [":pro", ":flash"];
|
|
1846
|
+
const isClaudeModel = claudeShorthands.includes(model) || model.startsWith(":claude");
|
|
1847
|
+
const isCodexModel = codexShorthands.includes(model) || model.startsWith(":gpt");
|
|
1848
|
+
const isGeminiModel = geminiShorthands.includes(model) || model.startsWith(":gemini");
|
|
1849
|
+
switch (subagent) {
|
|
1850
|
+
case "claude":
|
|
1851
|
+
return isClaudeModel || !isCodexModel && !isGeminiModel;
|
|
1852
|
+
case "codex":
|
|
1853
|
+
return isCodexModel || !isClaudeModel && !isGeminiModel;
|
|
1854
|
+
case "gemini":
|
|
1855
|
+
return isGeminiModel || !isClaudeModel && !isCodexModel;
|
|
1856
|
+
case "cursor":
|
|
1857
|
+
return true;
|
|
1858
|
+
case "pi":
|
|
1859
|
+
return true;
|
|
1860
|
+
default:
|
|
1861
|
+
return true;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1738
1865
|
// src/core/config.ts
|
|
1739
1866
|
var ENV_VAR_MAPPING = {
|
|
1740
1867
|
// Core settings
|
|
@@ -1784,6 +1911,7 @@ var JunoTaskConfigSchema = zod.z.object({
|
|
|
1784
1911
|
defaultBackend: BackendTypeSchema.describe("Default backend to use for task execution"),
|
|
1785
1912
|
defaultMaxIterations: zod.z.number().int().min(1).max(1e3).describe("Default maximum number of iterations for task execution"),
|
|
1786
1913
|
defaultModel: zod.z.string().optional().describe("Default model to use for the subagent"),
|
|
1914
|
+
defaultModels: zod.z.record(SubagentTypeSchema, zod.z.string()).optional().describe("Optional per-subagent default model overrides"),
|
|
1787
1915
|
// Project metadata
|
|
1788
1916
|
mainTask: zod.z.string().optional().describe("Main task objective for the project"),
|
|
1789
1917
|
// Logging settings
|
|
@@ -1839,6 +1967,7 @@ var DEFAULT_CONFIG = {
|
|
|
1839
1967
|
defaultSubagent: "claude",
|
|
1840
1968
|
defaultBackend: "shell",
|
|
1841
1969
|
defaultMaxIterations: 1,
|
|
1970
|
+
defaultModels: { ...SUBAGENT_DEFAULT_MODELS },
|
|
1842
1971
|
// Logging settings
|
|
1843
1972
|
logLevel: "info",
|
|
1844
1973
|
verbose: 1,
|
|
@@ -2154,7 +2283,7 @@ function parseEnvFileContent(content) {
|
|
|
2154
2283
|
const quote = value[0];
|
|
2155
2284
|
value = value.slice(1, -1);
|
|
2156
2285
|
if (quote === '"') {
|
|
2157
|
-
value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ");
|
|
2286
|
+
value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
2158
2287
|
}
|
|
2159
2288
|
} else {
|
|
2160
2289
|
const inlineCommentIndex = value.indexOf(" #");
|
|
@@ -2243,13 +2372,23 @@ async function ensureHooksConfig(baseDir) {
|
|
|
2243
2372
|
}
|
|
2244
2373
|
if (!existingConfig.defaultModel) {
|
|
2245
2374
|
const subagent = existingConfig.defaultSubagent || "claude";
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
existingConfig.defaultModel
|
|
2375
|
+
existingConfig.defaultModel = SUBAGENT_DEFAULT_MODELS[subagent] || SUBAGENT_DEFAULT_MODELS.claude;
|
|
2376
|
+
needsUpdate = true;
|
|
2377
|
+
}
|
|
2378
|
+
if (!existingConfig.defaultModels || typeof existingConfig.defaultModels !== "object" || Array.isArray(existingConfig.defaultModels)) {
|
|
2379
|
+
const baseDefaults = { ...SUBAGENT_DEFAULT_MODELS };
|
|
2380
|
+
const subagent = existingConfig.defaultSubagent || "claude";
|
|
2381
|
+
if (typeof existingConfig.defaultModel === "string") {
|
|
2382
|
+
baseDefaults[subagent] = existingConfig.defaultModel;
|
|
2383
|
+
}
|
|
2384
|
+
existingConfig.defaultModels = baseDefaults;
|
|
2385
|
+
needsUpdate = true;
|
|
2386
|
+
}
|
|
2387
|
+
const selectedSubagentRaw = typeof existingConfig.defaultSubagent === "string" ? existingConfig.defaultSubagent : "claude";
|
|
2388
|
+
const selectedSubagent = selectedSubagentRaw in SUBAGENT_DEFAULT_MODELS ? selectedSubagentRaw : "claude";
|
|
2389
|
+
const selectedMapModel = existingConfig.defaultModels && typeof existingConfig.defaultModels === "object" ? existingConfig.defaultModels[selectedSubagent] : void 0;
|
|
2390
|
+
if (typeof selectedMapModel === "string" && isModelCompatibleWithSubagent(selectedMapModel, selectedSubagent) && existingConfig.defaultModel !== selectedMapModel) {
|
|
2391
|
+
existingConfig.defaultModel = selectedMapModel;
|
|
2253
2392
|
needsUpdate = true;
|
|
2254
2393
|
}
|
|
2255
2394
|
if (existingConfig.defaultMaxIterations === 50) {
|
|
@@ -2556,6 +2695,178 @@ function validateHooksConfig(hooks) {
|
|
|
2556
2695
|
// src/core/engine.ts
|
|
2557
2696
|
init_advanced_logger();
|
|
2558
2697
|
init_shell_backend();
|
|
2698
|
+
|
|
2699
|
+
// src/core/prompt-command-substitution.ts
|
|
2700
|
+
init_version();
|
|
2701
|
+
var SINGLE_QUOTED_MARKER = "!'";
|
|
2702
|
+
var TRIPLE_BACKTICK_MARKER = "!```";
|
|
2703
|
+
var TRIPLE_BACKTICK_CLOSER = "```";
|
|
2704
|
+
var DEFAULT_MAX_BUFFER_BYTES = 1024 * 1024;
|
|
2705
|
+
var DEFAULT_COMMAND_TIMEOUT_MS = 3e4;
|
|
2706
|
+
var COMMAND_TIMEOUT_ENV_KEY = "JUNO_CODE_PROMPT_SUBSTITUTION_TIMEOUT_MS";
|
|
2707
|
+
function findPromptCommandSubstitutions(prompt) {
|
|
2708
|
+
const matches = [];
|
|
2709
|
+
let cursor = 0;
|
|
2710
|
+
while (cursor < prompt.length) {
|
|
2711
|
+
const singleQuotedStart = prompt.indexOf(SINGLE_QUOTED_MARKER, cursor);
|
|
2712
|
+
const tripleBacktickStart = prompt.indexOf(TRIPLE_BACKTICK_MARKER, cursor);
|
|
2713
|
+
const markerStart = chooseNearestMarker(singleQuotedStart, tripleBacktickStart);
|
|
2714
|
+
if (markerStart === null) {
|
|
2715
|
+
break;
|
|
2716
|
+
}
|
|
2717
|
+
if (markerStart === singleQuotedStart) {
|
|
2718
|
+
const parsedSingleQuoted = parseSingleQuotedSubstitution(prompt, markerStart);
|
|
2719
|
+
if (!parsedSingleQuoted) {
|
|
2720
|
+
cursor = markerStart + SINGLE_QUOTED_MARKER.length;
|
|
2721
|
+
continue;
|
|
2722
|
+
}
|
|
2723
|
+
matches.push(parsedSingleQuoted);
|
|
2724
|
+
cursor = parsedSingleQuoted.endIndex;
|
|
2725
|
+
continue;
|
|
2726
|
+
}
|
|
2727
|
+
const parsedTripleBacktick = parseTripleBacktickSubstitution(prompt, markerStart);
|
|
2728
|
+
if (!parsedTripleBacktick) {
|
|
2729
|
+
cursor = markerStart + TRIPLE_BACKTICK_MARKER.length;
|
|
2730
|
+
continue;
|
|
2731
|
+
}
|
|
2732
|
+
matches.push(parsedTripleBacktick);
|
|
2733
|
+
cursor = parsedTripleBacktick.endIndex;
|
|
2734
|
+
}
|
|
2735
|
+
return matches;
|
|
2736
|
+
}
|
|
2737
|
+
async function resolvePromptCommandSubstitutions(prompt, options) {
|
|
2738
|
+
const matches = findPromptCommandSubstitutions(prompt);
|
|
2739
|
+
if (matches.length === 0) {
|
|
2740
|
+
return prompt;
|
|
2741
|
+
}
|
|
2742
|
+
const executor = options.executor ?? createDefaultPromptCommandExecutor(options);
|
|
2743
|
+
let result = "";
|
|
2744
|
+
let cursor = 0;
|
|
2745
|
+
for (const match of matches) {
|
|
2746
|
+
result += prompt.slice(cursor, match.startIndex);
|
|
2747
|
+
const commandOutput = await executor(match.command);
|
|
2748
|
+
result += normalizeCommandOutput(commandOutput);
|
|
2749
|
+
cursor = match.endIndex;
|
|
2750
|
+
}
|
|
2751
|
+
result += prompt.slice(cursor);
|
|
2752
|
+
return result;
|
|
2753
|
+
}
|
|
2754
|
+
function chooseNearestMarker(singleQuotedStart, tripleBacktickStart) {
|
|
2755
|
+
const singleExists = singleQuotedStart >= 0;
|
|
2756
|
+
const tripleExists = tripleBacktickStart >= 0;
|
|
2757
|
+
if (!singleExists && !tripleExists) {
|
|
2758
|
+
return null;
|
|
2759
|
+
}
|
|
2760
|
+
if (!singleExists) {
|
|
2761
|
+
return tripleBacktickStart;
|
|
2762
|
+
}
|
|
2763
|
+
if (!tripleExists) {
|
|
2764
|
+
return singleQuotedStart;
|
|
2765
|
+
}
|
|
2766
|
+
return Math.min(singleQuotedStart, tripleBacktickStart);
|
|
2767
|
+
}
|
|
2768
|
+
function parseSingleQuotedSubstitution(prompt, markerStart) {
|
|
2769
|
+
const contentStart = markerStart + SINGLE_QUOTED_MARKER.length;
|
|
2770
|
+
const closingQuote = findClosingSingleQuote(prompt, contentStart);
|
|
2771
|
+
if (closingQuote < 0) {
|
|
2772
|
+
return null;
|
|
2773
|
+
}
|
|
2774
|
+
const raw = prompt.slice(markerStart, closingQuote + 1);
|
|
2775
|
+
const command = prompt.slice(contentStart, closingQuote);
|
|
2776
|
+
return {
|
|
2777
|
+
syntax: "single-quoted",
|
|
2778
|
+
startIndex: markerStart,
|
|
2779
|
+
endIndex: closingQuote + 1,
|
|
2780
|
+
command,
|
|
2781
|
+
raw
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
function findClosingSingleQuote(prompt, startIndex) {
|
|
2785
|
+
let escaped = false;
|
|
2786
|
+
for (let index = startIndex; index < prompt.length; index++) {
|
|
2787
|
+
const char = prompt[index];
|
|
2788
|
+
if (char === "'" && !escaped) {
|
|
2789
|
+
return index;
|
|
2790
|
+
}
|
|
2791
|
+
if (char === "\\" && !escaped) {
|
|
2792
|
+
escaped = true;
|
|
2793
|
+
continue;
|
|
2794
|
+
}
|
|
2795
|
+
escaped = false;
|
|
2796
|
+
}
|
|
2797
|
+
return -1;
|
|
2798
|
+
}
|
|
2799
|
+
function parseTripleBacktickSubstitution(prompt, markerStart) {
|
|
2800
|
+
const contentStart = markerStart + TRIPLE_BACKTICK_MARKER.length;
|
|
2801
|
+
const closingBackticks = prompt.indexOf(TRIPLE_BACKTICK_CLOSER, contentStart);
|
|
2802
|
+
if (closingBackticks < 0) {
|
|
2803
|
+
return null;
|
|
2804
|
+
}
|
|
2805
|
+
const raw = prompt.slice(markerStart, closingBackticks + TRIPLE_BACKTICK_CLOSER.length);
|
|
2806
|
+
const command = prompt.slice(contentStart, closingBackticks);
|
|
2807
|
+
return {
|
|
2808
|
+
syntax: "triple-backtick",
|
|
2809
|
+
startIndex: markerStart,
|
|
2810
|
+
endIndex: closingBackticks + TRIPLE_BACKTICK_CLOSER.length,
|
|
2811
|
+
command,
|
|
2812
|
+
raw
|
|
2813
|
+
};
|
|
2814
|
+
}
|
|
2815
|
+
function createDefaultPromptCommandExecutor(options) {
|
|
2816
|
+
const execFile2 = util.promisify(childProcess__namespace.execFile);
|
|
2817
|
+
const maxBufferBytes = options.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;
|
|
2818
|
+
const commandTimeoutMs = resolvePromptCommandTimeoutMs(options.commandTimeoutMs);
|
|
2819
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
2820
|
+
return async (command) => {
|
|
2821
|
+
const normalizedCommand = command.trim();
|
|
2822
|
+
if (!normalizedCommand) {
|
|
2823
|
+
return "";
|
|
2824
|
+
}
|
|
2825
|
+
const commandForExecution = wrapCommandForNonInteractiveExecution(normalizedCommand);
|
|
2826
|
+
try {
|
|
2827
|
+
const result = await execFile2(shell, ["-lc", commandForExecution], {
|
|
2828
|
+
cwd: options.workingDirectory,
|
|
2829
|
+
env: options.environment ?? process.env,
|
|
2830
|
+
maxBuffer: maxBufferBytes,
|
|
2831
|
+
timeout: commandTimeoutMs
|
|
2832
|
+
});
|
|
2833
|
+
const stdout2 = typeof result === "string" || Buffer.isBuffer(result) ? String(result) : String(result.stdout ?? "");
|
|
2834
|
+
return stdout2;
|
|
2835
|
+
} catch (error) {
|
|
2836
|
+
const failedCommand = normalizedCommand.replace(/\s+/g, " ").trim();
|
|
2837
|
+
const details = error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "").trim() : "";
|
|
2838
|
+
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 ?? "")));
|
|
2839
|
+
if (timeoutDetected) {
|
|
2840
|
+
throw new Error(
|
|
2841
|
+
`Prompt command substitution timed out after ${commandTimeoutMs}ms for \`${failedCommand}\``
|
|
2842
|
+
);
|
|
2843
|
+
}
|
|
2844
|
+
const suffix = details ? `: ${details}` : "";
|
|
2845
|
+
throw new Error(`Prompt command substitution failed for \`${failedCommand}\`${suffix}`);
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
function resolvePromptCommandTimeoutMs(explicitTimeoutMs) {
|
|
2850
|
+
if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
|
|
2851
|
+
return explicitTimeoutMs;
|
|
2852
|
+
}
|
|
2853
|
+
const envValue = process.env[COMMAND_TIMEOUT_ENV_KEY];
|
|
2854
|
+
if (envValue !== void 0) {
|
|
2855
|
+
const parsed = Number(envValue);
|
|
2856
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
2857
|
+
return parsed;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
return DEFAULT_COMMAND_TIMEOUT_MS;
|
|
2861
|
+
}
|
|
2862
|
+
function wrapCommandForNonInteractiveExecution(command) {
|
|
2863
|
+
return `(${command}) </dev/null`;
|
|
2864
|
+
}
|
|
2865
|
+
function normalizeCommandOutput(output) {
|
|
2866
|
+
return output.replace(/\r?\n$/, "");
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
// src/core/engine.ts
|
|
2559
2870
|
var ExecutionStatus = /* @__PURE__ */ ((ExecutionStatus2) => {
|
|
2560
2871
|
ExecutionStatus2["PENDING"] = "pending";
|
|
2561
2872
|
ExecutionStatus2["RUNNING"] = "running";
|
|
@@ -2862,7 +3173,8 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
2862
3173
|
if (!request.requestId?.trim()) {
|
|
2863
3174
|
throw new Error("Request ID is required");
|
|
2864
3175
|
}
|
|
2865
|
-
|
|
3176
|
+
const allowEmptyInstructionForPiLiveInteractiveSession = request.subagent === "pi" && request.live === true && request.liveInteractiveSession === true && typeof request.resume === "string" && request.resume.trim().length > 0;
|
|
3177
|
+
if (!request.instruction?.trim() && !allowEmptyInstructionForPiLiveInteractiveSession) {
|
|
2866
3178
|
throw new Error("Instruction is required");
|
|
2867
3179
|
}
|
|
2868
3180
|
if (!request.subagent?.trim()) {
|
|
@@ -3100,43 +3412,62 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
3100
3412
|
engineLogger.warn("Hook START_ITERATION failed", { error, iterationNumber });
|
|
3101
3413
|
}
|
|
3102
3414
|
this.emit("iteration:start", { context, iterationNumber });
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3415
|
+
let toolRequest = null;
|
|
3416
|
+
try {
|
|
3417
|
+
const instructionTemplate = context.request.instruction;
|
|
3418
|
+
const resolvedInstruction = await resolvePromptCommandSubstitutions(instructionTemplate, {
|
|
3419
|
+
workingDirectory: context.request.workingDirectory,
|
|
3420
|
+
environment: {
|
|
3421
|
+
...process.env,
|
|
3422
|
+
JUNO_TASK_ROOT: process.env.JUNO_TASK_ROOT || context.request.workingDirectory
|
|
3423
|
+
}
|
|
3424
|
+
});
|
|
3425
|
+
this.emit("iteration:instruction-resolved", {
|
|
3426
|
+
context,
|
|
3427
|
+
iterationNumber,
|
|
3428
|
+
instruction: resolvedInstruction,
|
|
3429
|
+
templateInstruction: instructionTemplate
|
|
3430
|
+
});
|
|
3431
|
+
toolRequest = {
|
|
3432
|
+
toolName: this.getToolNameForSubagent(context.request.subagent),
|
|
3433
|
+
arguments: {
|
|
3434
|
+
instruction: resolvedInstruction,
|
|
3435
|
+
project_path: context.request.workingDirectory,
|
|
3436
|
+
...context.request.model !== void 0 && { model: context.request.model },
|
|
3437
|
+
...context.request.agents !== void 0 && { agents: context.request.agents },
|
|
3438
|
+
...context.request.tools !== void 0 && { tools: context.request.tools },
|
|
3439
|
+
...context.request.allowedTools !== void 0 && {
|
|
3440
|
+
allowedTools: context.request.allowedTools
|
|
3441
|
+
},
|
|
3442
|
+
...context.request.appendAllowedTools !== void 0 && {
|
|
3443
|
+
appendAllowedTools: context.request.appendAllowedTools
|
|
3444
|
+
},
|
|
3445
|
+
...context.request.disallowedTools !== void 0 && {
|
|
3446
|
+
disallowedTools: context.request.disallowedTools
|
|
3447
|
+
},
|
|
3448
|
+
...context.request.resume !== void 0 && { resume: context.request.resume },
|
|
3449
|
+
...context.request.continueConversation !== void 0 && {
|
|
3450
|
+
continueConversation: context.request.continueConversation
|
|
3451
|
+
},
|
|
3452
|
+
...context.request.thinking !== void 0 && { thinking: context.request.thinking },
|
|
3453
|
+
...context.request.live !== void 0 && { live: context.request.live },
|
|
3454
|
+
...context.request.liveInteractiveSession !== void 0 && {
|
|
3455
|
+
liveInteractiveSession: context.request.liveInteractiveSession
|
|
3456
|
+
},
|
|
3457
|
+
iteration: iterationNumber
|
|
3119
3458
|
},
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3459
|
+
timeout: context.request.timeoutMs || this.engineConfig.config.mcpTimeout,
|
|
3460
|
+
priority: context.request.priority || "normal",
|
|
3461
|
+
metadata: {
|
|
3462
|
+
sessionId: context.sessionContext.sessionId,
|
|
3463
|
+
iterationNumber
|
|
3123
3464
|
},
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
sessionId: context.sessionContext.sessionId,
|
|
3131
|
-
iterationNumber
|
|
3132
|
-
},
|
|
3133
|
-
progressCallback: async (event) => {
|
|
3134
|
-
context.progressEvents.push(event);
|
|
3135
|
-
context.statistics.totalProgressEvents++;
|
|
3136
|
-
await this.processProgressEvent(context, event);
|
|
3137
|
-
}
|
|
3138
|
-
};
|
|
3139
|
-
try {
|
|
3465
|
+
progressCallback: async (event) => {
|
|
3466
|
+
context.progressEvents.push(event);
|
|
3467
|
+
context.statistics.totalProgressEvents++;
|
|
3468
|
+
await this.processProgressEvent(context, event);
|
|
3469
|
+
}
|
|
3470
|
+
};
|
|
3140
3471
|
if (!this.currentBackend) {
|
|
3141
3472
|
throw new Error("No backend initialized. Call initializeBackend() first.");
|
|
3142
3473
|
}
|
|
@@ -3205,7 +3536,10 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
3205
3536
|
duration,
|
|
3206
3537
|
error: mcpError,
|
|
3207
3538
|
progressEvents: [],
|
|
3208
|
-
request: toolRequest
|
|
3539
|
+
request: toolRequest ?? {
|
|
3540
|
+
toolName: this.getToolNameForSubagent(context.request.subagent),
|
|
3541
|
+
arguments: {}
|
|
3542
|
+
}
|
|
3209
3543
|
},
|
|
3210
3544
|
progressEvents: [],
|
|
3211
3545
|
error: mcpError
|
|
@@ -3717,6 +4051,12 @@ function createExecutionRequest(options) {
|
|
|
3717
4051
|
if (options.thinking !== void 0) {
|
|
3718
4052
|
result.thinking = options.thinking;
|
|
3719
4053
|
}
|
|
4054
|
+
if (options.live !== void 0) {
|
|
4055
|
+
result.live = options.live;
|
|
4056
|
+
}
|
|
4057
|
+
if (options.liveInteractiveSession !== void 0) {
|
|
4058
|
+
result.liveInteractiveSession = options.liveInteractiveSession;
|
|
4059
|
+
}
|
|
3720
4060
|
return result;
|
|
3721
4061
|
}
|
|
3722
4062
|
|