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/README.md +57 -0
- package/dist/bin/cli.js +678 -82
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +675 -79
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +369 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +367 -56
- 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 +21 -0
- package/dist/templates/scripts/kanban.sh +6 -2
- package/dist/templates/scripts/parallel_runner.sh +602 -131
- 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 +418 -51
- package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +6 -2
- package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +6 -2
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import * as childProcess from 'child_process';
|
|
3
4
|
import { spawn } from 'child_process';
|
|
4
5
|
import * as fs3 from 'fs';
|
|
5
6
|
import { promises } from 'fs';
|
|
@@ -11,6 +12,7 @@ import { z } from 'zod';
|
|
|
11
12
|
import * as yaml from 'js-yaml';
|
|
12
13
|
import { EventEmitter } from 'events';
|
|
13
14
|
import { execa } from 'execa';
|
|
15
|
+
import { promisify } from 'util';
|
|
14
16
|
import { v4 } from 'uuid';
|
|
15
17
|
import * as process2 from 'process';
|
|
16
18
|
|
|
@@ -34,7 +36,7 @@ var __export = (target, all) => {
|
|
|
34
36
|
var version;
|
|
35
37
|
var init_version = __esm({
|
|
36
38
|
"src/version.ts"() {
|
|
37
|
-
version = "1.0.
|
|
39
|
+
version = "1.0.53";
|
|
38
40
|
}
|
|
39
41
|
});
|
|
40
42
|
|
|
@@ -722,25 +724,28 @@ var init_shell_backend = __esm({
|
|
|
722
724
|
const scriptPath = await this.findScriptForSubagent(subagentType);
|
|
723
725
|
const result = await this.executeScript(scriptPath, request, toolId, subagentType);
|
|
724
726
|
const duration = Date.now() - startTime;
|
|
727
|
+
const structuredResult = this.buildStructuredOutput(subagentType, result);
|
|
728
|
+
const structuredPayload = this.parseStructuredResultPayload(structuredResult.content);
|
|
729
|
+
const structuredIndicatesError = structuredPayload?.is_error === true || structuredPayload?.subtype === "error";
|
|
730
|
+
const executionSucceeded = result.success && !structuredIndicatesError;
|
|
725
731
|
await this.emitProgressEvent({
|
|
726
732
|
sessionId: request.metadata?.sessionId || "unknown",
|
|
727
733
|
timestamp: /* @__PURE__ */ new Date(),
|
|
728
734
|
backend: "shell",
|
|
729
735
|
count: ++this.eventCounter,
|
|
730
736
|
type: "tool_result" /* TOOL_RESULT */,
|
|
731
|
-
content: `${request.toolName} completed successfully (${duration}ms)`,
|
|
737
|
+
content: executionSucceeded ? `${request.toolName} completed successfully (${duration}ms)` : `${request.toolName} completed with error (${duration}ms)`,
|
|
732
738
|
toolId,
|
|
733
739
|
metadata: {
|
|
734
740
|
toolName: request.toolName,
|
|
735
741
|
duration,
|
|
736
|
-
success:
|
|
742
|
+
success: executionSucceeded,
|
|
737
743
|
phase: "completion"
|
|
738
744
|
}
|
|
739
745
|
});
|
|
740
|
-
const structuredResult = this.buildStructuredOutput(subagentType, result);
|
|
741
746
|
const toolResult = {
|
|
742
747
|
content: structuredResult.content,
|
|
743
|
-
status:
|
|
748
|
+
status: executionSucceeded ? "completed" /* COMPLETED */ : "failed" /* FAILED */,
|
|
744
749
|
startTime: new Date(startTime),
|
|
745
750
|
endTime: /* @__PURE__ */ new Date(),
|
|
746
751
|
duration,
|
|
@@ -749,6 +754,9 @@ var init_shell_backend = __esm({
|
|
|
749
754
|
};
|
|
750
755
|
if (result.error) {
|
|
751
756
|
toolResult.error = new Error(result.error);
|
|
757
|
+
} else if (!executionSucceeded) {
|
|
758
|
+
const structuredErrorMessage = typeof structuredPayload?.error === "string" && structuredPayload.error || typeof structuredPayload?.result === "string" && structuredPayload.result || `${request.toolName} reported a structured error`;
|
|
759
|
+
toolResult.error = new Error(structuredErrorMessage);
|
|
752
760
|
}
|
|
753
761
|
if (structuredResult.metadata) {
|
|
754
762
|
toolResult.metadata = structuredResult.metadata;
|
|
@@ -1000,6 +1008,9 @@ var init_shell_backend = __esm({
|
|
|
1000
1008
|
if (isPython && subagentType === "pi" && request.arguments?.live === true) {
|
|
1001
1009
|
args.push("--live");
|
|
1002
1010
|
}
|
|
1011
|
+
if (isPython && subagentType === "pi" && request.arguments?.liveInteractiveSession === true) {
|
|
1012
|
+
args.push("--live-manual");
|
|
1013
|
+
}
|
|
1003
1014
|
if (isPython && this.config.debug) {
|
|
1004
1015
|
args.push("--verbose");
|
|
1005
1016
|
}
|
|
@@ -1282,8 +1293,19 @@ var init_shell_backend = __esm({
|
|
|
1282
1293
|
if (subagentType === "pi") {
|
|
1283
1294
|
const piEvent = result.subAgentResponse ?? this.extractLastJsonEvent(result.output);
|
|
1284
1295
|
if (piEvent) {
|
|
1285
|
-
|
|
1286
|
-
|
|
1296
|
+
const piNestedEvent = typeof piEvent.sub_agent_response === "object" && piEvent.sub_agent_response ? piEvent.sub_agent_response : void 0;
|
|
1297
|
+
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;
|
|
1298
|
+
const sanitizedPiEvent = { ...piEvent };
|
|
1299
|
+
delete sanitizedPiEvent.messages;
|
|
1300
|
+
if (sanitizedPiEvent.sub_agent_response && typeof sanitizedPiEvent.sub_agent_response === "object") {
|
|
1301
|
+
const inner = { ...sanitizedPiEvent.sub_agent_response };
|
|
1302
|
+
delete inner.messages;
|
|
1303
|
+
delete inner.type;
|
|
1304
|
+
sanitizedPiEvent.sub_agent_response = inner;
|
|
1305
|
+
}
|
|
1306
|
+
const hasDirectResultText = typeof piEvent.result === "string";
|
|
1307
|
+
let resultText = hasDirectResultText ? piEvent.result : void 0;
|
|
1308
|
+
if (resultText === void 0 && Array.isArray(piEvent.messages)) {
|
|
1287
1309
|
for (let i = piEvent.messages.length - 1; i >= 0; i--) {
|
|
1288
1310
|
const msg = piEvent.messages[i];
|
|
1289
1311
|
if (msg?.role === "assistant") {
|
|
@@ -1303,16 +1325,11 @@ var init_shell_backend = __esm({
|
|
|
1303
1325
|
}
|
|
1304
1326
|
}
|
|
1305
1327
|
}
|
|
1306
|
-
if (resultText) {
|
|
1328
|
+
if (resultText === void 0 && typeof piEvent.error === "string") {
|
|
1329
|
+
resultText = piEvent.error;
|
|
1330
|
+
}
|
|
1331
|
+
if (resultText !== void 0) {
|
|
1307
1332
|
const isError = piEvent.is_error ?? !result.success;
|
|
1308
|
-
const sanitizedPiEvent = { ...piEvent };
|
|
1309
|
-
delete sanitizedPiEvent.messages;
|
|
1310
|
-
if (sanitizedPiEvent.sub_agent_response && typeof sanitizedPiEvent.sub_agent_response === "object") {
|
|
1311
|
-
const inner = { ...sanitizedPiEvent.sub_agent_response };
|
|
1312
|
-
delete inner.messages;
|
|
1313
|
-
delete inner.type;
|
|
1314
|
-
sanitizedPiEvent.sub_agent_response = inner;
|
|
1315
|
-
}
|
|
1316
1333
|
const usage = piEvent.usage;
|
|
1317
1334
|
const totalCostUsd = typeof piEvent.total_cost_usd === "number" ? piEvent.total_cost_usd : typeof usage?.cost?.total === "number" ? usage.cost.total : void 0;
|
|
1318
1335
|
const structuredPayload = {
|
|
@@ -1320,9 +1337,9 @@ var init_shell_backend = __esm({
|
|
|
1320
1337
|
subtype: piEvent.subtype || (isError ? "error" : "success"),
|
|
1321
1338
|
is_error: isError,
|
|
1322
1339
|
result: resultText,
|
|
1323
|
-
error: piEvent.error,
|
|
1340
|
+
error: isError ? piEvent.error ?? result.error ?? resultText : piEvent.error,
|
|
1324
1341
|
stderr: result.error,
|
|
1325
|
-
session_id:
|
|
1342
|
+
session_id: piSessionId,
|
|
1326
1343
|
exit_code: result.exitCode,
|
|
1327
1344
|
duration_ms: piEvent.duration_ms ?? result.duration,
|
|
1328
1345
|
total_cost_usd: totalCostUsd,
|
|
@@ -1340,6 +1357,57 @@ var init_shell_backend = __esm({
|
|
|
1340
1357
|
metadata
|
|
1341
1358
|
};
|
|
1342
1359
|
}
|
|
1360
|
+
const isSessionSnapshotOnly = piEvent.type === "session" || piEvent.subtype === "session";
|
|
1361
|
+
if (isSessionSnapshotOnly) {
|
|
1362
|
+
const errorMessage = result.error?.trim() || "Pi exited before emitting a terminal result event (session snapshot only).";
|
|
1363
|
+
const structuredPayload = {
|
|
1364
|
+
type: "result",
|
|
1365
|
+
subtype: "error",
|
|
1366
|
+
is_error: true,
|
|
1367
|
+
result: errorMessage,
|
|
1368
|
+
error: errorMessage,
|
|
1369
|
+
stderr: result.error,
|
|
1370
|
+
session_id: piSessionId,
|
|
1371
|
+
exit_code: result.exitCode,
|
|
1372
|
+
duration_ms: result.duration,
|
|
1373
|
+
sub_agent_response: sanitizedPiEvent
|
|
1374
|
+
};
|
|
1375
|
+
const metadata = {
|
|
1376
|
+
...piEvent ? { subAgentResponse: piEvent } : void 0,
|
|
1377
|
+
structuredOutput: true,
|
|
1378
|
+
contentType: "application/json",
|
|
1379
|
+
rawOutput: result.output
|
|
1380
|
+
};
|
|
1381
|
+
return {
|
|
1382
|
+
content: JSON.stringify(structuredPayload),
|
|
1383
|
+
metadata
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
if (!result.success) {
|
|
1387
|
+
const errorMessage = result.error?.trim() || result.output?.trim() || "Unknown error";
|
|
1388
|
+
const structuredPayload = {
|
|
1389
|
+
type: "result",
|
|
1390
|
+
subtype: "error",
|
|
1391
|
+
is_error: true,
|
|
1392
|
+
result: errorMessage,
|
|
1393
|
+
error: errorMessage,
|
|
1394
|
+
stderr: result.error,
|
|
1395
|
+
session_id: piSessionId,
|
|
1396
|
+
exit_code: result.exitCode,
|
|
1397
|
+
duration_ms: result.duration,
|
|
1398
|
+
sub_agent_response: sanitizedPiEvent
|
|
1399
|
+
};
|
|
1400
|
+
const metadata = {
|
|
1401
|
+
...piEvent ? { subAgentResponse: piEvent } : void 0,
|
|
1402
|
+
structuredOutput: true,
|
|
1403
|
+
contentType: "application/json",
|
|
1404
|
+
rawOutput: result.output
|
|
1405
|
+
};
|
|
1406
|
+
return {
|
|
1407
|
+
content: JSON.stringify(structuredPayload),
|
|
1408
|
+
metadata
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1343
1411
|
}
|
|
1344
1412
|
}
|
|
1345
1413
|
if (!result.success) {
|
|
@@ -1404,6 +1472,20 @@ var init_shell_backend = __esm({
|
|
|
1404
1472
|
}
|
|
1405
1473
|
return null;
|
|
1406
1474
|
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Parse JSON structured output payload emitted by shell service wrappers.
|
|
1477
|
+
*/
|
|
1478
|
+
parseStructuredResultPayload(content) {
|
|
1479
|
+
try {
|
|
1480
|
+
const parsed = JSON.parse(content);
|
|
1481
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1482
|
+
return null;
|
|
1483
|
+
}
|
|
1484
|
+
return parsed;
|
|
1485
|
+
} catch {
|
|
1486
|
+
return null;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1407
1489
|
/**
|
|
1408
1490
|
* Extract the last valid JSON object from a script's stdout to use as a structured payload fallback.
|
|
1409
1491
|
*/
|
|
@@ -1726,6 +1808,31 @@ var SUBAGENT_DEFAULT_MODELS = {
|
|
|
1726
1808
|
cursor: "auto",
|
|
1727
1809
|
pi: ":pi"
|
|
1728
1810
|
};
|
|
1811
|
+
function isModelCompatibleWithSubagent(model, subagent) {
|
|
1812
|
+
if (!model.startsWith(":")) {
|
|
1813
|
+
return true;
|
|
1814
|
+
}
|
|
1815
|
+
const claudeShorthands = [":sonnet", ":haiku", ":opus"];
|
|
1816
|
+
const codexShorthands = [":codex", ":codex-mini", ":gpt-5", ":mini"];
|
|
1817
|
+
const geminiShorthands = [":pro", ":flash"];
|
|
1818
|
+
const isClaudeModel = claudeShorthands.includes(model) || model.startsWith(":claude");
|
|
1819
|
+
const isCodexModel = codexShorthands.includes(model) || model.startsWith(":gpt");
|
|
1820
|
+
const isGeminiModel = geminiShorthands.includes(model) || model.startsWith(":gemini");
|
|
1821
|
+
switch (subagent) {
|
|
1822
|
+
case "claude":
|
|
1823
|
+
return isClaudeModel || !isCodexModel && !isGeminiModel;
|
|
1824
|
+
case "codex":
|
|
1825
|
+
return isCodexModel || !isClaudeModel && !isGeminiModel;
|
|
1826
|
+
case "gemini":
|
|
1827
|
+
return isGeminiModel || !isClaudeModel && !isCodexModel;
|
|
1828
|
+
case "cursor":
|
|
1829
|
+
return true;
|
|
1830
|
+
case "pi":
|
|
1831
|
+
return true;
|
|
1832
|
+
default:
|
|
1833
|
+
return true;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1729
1836
|
|
|
1730
1837
|
// src/core/config.ts
|
|
1731
1838
|
var ENV_VAR_MAPPING = {
|
|
@@ -2249,6 +2356,13 @@ async function ensureHooksConfig(baseDir) {
|
|
|
2249
2356
|
existingConfig.defaultModels = baseDefaults;
|
|
2250
2357
|
needsUpdate = true;
|
|
2251
2358
|
}
|
|
2359
|
+
const selectedSubagentRaw = typeof existingConfig.defaultSubagent === "string" ? existingConfig.defaultSubagent : "claude";
|
|
2360
|
+
const selectedSubagent = selectedSubagentRaw in SUBAGENT_DEFAULT_MODELS ? selectedSubagentRaw : "claude";
|
|
2361
|
+
const selectedMapModel = existingConfig.defaultModels && typeof existingConfig.defaultModels === "object" ? existingConfig.defaultModels[selectedSubagent] : void 0;
|
|
2362
|
+
if (typeof selectedMapModel === "string" && isModelCompatibleWithSubagent(selectedMapModel, selectedSubagent) && existingConfig.defaultModel !== selectedMapModel) {
|
|
2363
|
+
existingConfig.defaultModel = selectedMapModel;
|
|
2364
|
+
needsUpdate = true;
|
|
2365
|
+
}
|
|
2252
2366
|
if (existingConfig.defaultMaxIterations === 50) {
|
|
2253
2367
|
existingConfig.defaultMaxIterations = DEFAULT_CONFIG.defaultMaxIterations;
|
|
2254
2368
|
needsUpdate = true;
|
|
@@ -2553,6 +2667,178 @@ function validateHooksConfig(hooks) {
|
|
|
2553
2667
|
// src/core/engine.ts
|
|
2554
2668
|
init_advanced_logger();
|
|
2555
2669
|
init_shell_backend();
|
|
2670
|
+
|
|
2671
|
+
// src/core/prompt-command-substitution.ts
|
|
2672
|
+
init_version();
|
|
2673
|
+
var SINGLE_QUOTED_MARKER = "!'";
|
|
2674
|
+
var TRIPLE_BACKTICK_MARKER = "!```";
|
|
2675
|
+
var TRIPLE_BACKTICK_CLOSER = "```";
|
|
2676
|
+
var DEFAULT_MAX_BUFFER_BYTES = 1024 * 1024;
|
|
2677
|
+
var DEFAULT_COMMAND_TIMEOUT_MS = 3e4;
|
|
2678
|
+
var COMMAND_TIMEOUT_ENV_KEY = "JUNO_CODE_PROMPT_SUBSTITUTION_TIMEOUT_MS";
|
|
2679
|
+
function findPromptCommandSubstitutions(prompt) {
|
|
2680
|
+
const matches = [];
|
|
2681
|
+
let cursor = 0;
|
|
2682
|
+
while (cursor < prompt.length) {
|
|
2683
|
+
const singleQuotedStart = prompt.indexOf(SINGLE_QUOTED_MARKER, cursor);
|
|
2684
|
+
const tripleBacktickStart = prompt.indexOf(TRIPLE_BACKTICK_MARKER, cursor);
|
|
2685
|
+
const markerStart = chooseNearestMarker(singleQuotedStart, tripleBacktickStart);
|
|
2686
|
+
if (markerStart === null) {
|
|
2687
|
+
break;
|
|
2688
|
+
}
|
|
2689
|
+
if (markerStart === singleQuotedStart) {
|
|
2690
|
+
const parsedSingleQuoted = parseSingleQuotedSubstitution(prompt, markerStart);
|
|
2691
|
+
if (!parsedSingleQuoted) {
|
|
2692
|
+
cursor = markerStart + SINGLE_QUOTED_MARKER.length;
|
|
2693
|
+
continue;
|
|
2694
|
+
}
|
|
2695
|
+
matches.push(parsedSingleQuoted);
|
|
2696
|
+
cursor = parsedSingleQuoted.endIndex;
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
const parsedTripleBacktick = parseTripleBacktickSubstitution(prompt, markerStart);
|
|
2700
|
+
if (!parsedTripleBacktick) {
|
|
2701
|
+
cursor = markerStart + TRIPLE_BACKTICK_MARKER.length;
|
|
2702
|
+
continue;
|
|
2703
|
+
}
|
|
2704
|
+
matches.push(parsedTripleBacktick);
|
|
2705
|
+
cursor = parsedTripleBacktick.endIndex;
|
|
2706
|
+
}
|
|
2707
|
+
return matches;
|
|
2708
|
+
}
|
|
2709
|
+
async function resolvePromptCommandSubstitutions(prompt, options) {
|
|
2710
|
+
const matches = findPromptCommandSubstitutions(prompt);
|
|
2711
|
+
if (matches.length === 0) {
|
|
2712
|
+
return prompt;
|
|
2713
|
+
}
|
|
2714
|
+
const executor = options.executor ?? createDefaultPromptCommandExecutor(options);
|
|
2715
|
+
let result = "";
|
|
2716
|
+
let cursor = 0;
|
|
2717
|
+
for (const match of matches) {
|
|
2718
|
+
result += prompt.slice(cursor, match.startIndex);
|
|
2719
|
+
const commandOutput = await executor(match.command);
|
|
2720
|
+
result += normalizeCommandOutput(commandOutput);
|
|
2721
|
+
cursor = match.endIndex;
|
|
2722
|
+
}
|
|
2723
|
+
result += prompt.slice(cursor);
|
|
2724
|
+
return result;
|
|
2725
|
+
}
|
|
2726
|
+
function chooseNearestMarker(singleQuotedStart, tripleBacktickStart) {
|
|
2727
|
+
const singleExists = singleQuotedStart >= 0;
|
|
2728
|
+
const tripleExists = tripleBacktickStart >= 0;
|
|
2729
|
+
if (!singleExists && !tripleExists) {
|
|
2730
|
+
return null;
|
|
2731
|
+
}
|
|
2732
|
+
if (!singleExists) {
|
|
2733
|
+
return tripleBacktickStart;
|
|
2734
|
+
}
|
|
2735
|
+
if (!tripleExists) {
|
|
2736
|
+
return singleQuotedStart;
|
|
2737
|
+
}
|
|
2738
|
+
return Math.min(singleQuotedStart, tripleBacktickStart);
|
|
2739
|
+
}
|
|
2740
|
+
function parseSingleQuotedSubstitution(prompt, markerStart) {
|
|
2741
|
+
const contentStart = markerStart + SINGLE_QUOTED_MARKER.length;
|
|
2742
|
+
const closingQuote = findClosingSingleQuote(prompt, contentStart);
|
|
2743
|
+
if (closingQuote < 0) {
|
|
2744
|
+
return null;
|
|
2745
|
+
}
|
|
2746
|
+
const raw = prompt.slice(markerStart, closingQuote + 1);
|
|
2747
|
+
const command = prompt.slice(contentStart, closingQuote);
|
|
2748
|
+
return {
|
|
2749
|
+
syntax: "single-quoted",
|
|
2750
|
+
startIndex: markerStart,
|
|
2751
|
+
endIndex: closingQuote + 1,
|
|
2752
|
+
command,
|
|
2753
|
+
raw
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
function findClosingSingleQuote(prompt, startIndex) {
|
|
2757
|
+
let escaped = false;
|
|
2758
|
+
for (let index = startIndex; index < prompt.length; index++) {
|
|
2759
|
+
const char = prompt[index];
|
|
2760
|
+
if (char === "'" && !escaped) {
|
|
2761
|
+
return index;
|
|
2762
|
+
}
|
|
2763
|
+
if (char === "\\" && !escaped) {
|
|
2764
|
+
escaped = true;
|
|
2765
|
+
continue;
|
|
2766
|
+
}
|
|
2767
|
+
escaped = false;
|
|
2768
|
+
}
|
|
2769
|
+
return -1;
|
|
2770
|
+
}
|
|
2771
|
+
function parseTripleBacktickSubstitution(prompt, markerStart) {
|
|
2772
|
+
const contentStart = markerStart + TRIPLE_BACKTICK_MARKER.length;
|
|
2773
|
+
const closingBackticks = prompt.indexOf(TRIPLE_BACKTICK_CLOSER, contentStart);
|
|
2774
|
+
if (closingBackticks < 0) {
|
|
2775
|
+
return null;
|
|
2776
|
+
}
|
|
2777
|
+
const raw = prompt.slice(markerStart, closingBackticks + TRIPLE_BACKTICK_CLOSER.length);
|
|
2778
|
+
const command = prompt.slice(contentStart, closingBackticks);
|
|
2779
|
+
return {
|
|
2780
|
+
syntax: "triple-backtick",
|
|
2781
|
+
startIndex: markerStart,
|
|
2782
|
+
endIndex: closingBackticks + TRIPLE_BACKTICK_CLOSER.length,
|
|
2783
|
+
command,
|
|
2784
|
+
raw
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
function createDefaultPromptCommandExecutor(options) {
|
|
2788
|
+
const execFile2 = promisify(childProcess.execFile);
|
|
2789
|
+
const maxBufferBytes = options.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;
|
|
2790
|
+
const commandTimeoutMs = resolvePromptCommandTimeoutMs(options.commandTimeoutMs);
|
|
2791
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
2792
|
+
return async (command) => {
|
|
2793
|
+
const normalizedCommand = command.trim();
|
|
2794
|
+
if (!normalizedCommand) {
|
|
2795
|
+
return "";
|
|
2796
|
+
}
|
|
2797
|
+
const commandForExecution = wrapCommandForNonInteractiveExecution(normalizedCommand);
|
|
2798
|
+
try {
|
|
2799
|
+
const result = await execFile2(shell, ["-lc", commandForExecution], {
|
|
2800
|
+
cwd: options.workingDirectory,
|
|
2801
|
+
env: options.environment ?? process.env,
|
|
2802
|
+
maxBuffer: maxBufferBytes,
|
|
2803
|
+
timeout: commandTimeoutMs
|
|
2804
|
+
});
|
|
2805
|
+
const stdout2 = typeof result === "string" || Buffer.isBuffer(result) ? String(result) : String(result.stdout ?? "");
|
|
2806
|
+
return stdout2;
|
|
2807
|
+
} catch (error) {
|
|
2808
|
+
const failedCommand = normalizedCommand.replace(/\s+/g, " ").trim();
|
|
2809
|
+
const details = error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "").trim() : "";
|
|
2810
|
+
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 ?? "")));
|
|
2811
|
+
if (timeoutDetected) {
|
|
2812
|
+
throw new Error(
|
|
2813
|
+
`Prompt command substitution timed out after ${commandTimeoutMs}ms for \`${failedCommand}\``
|
|
2814
|
+
);
|
|
2815
|
+
}
|
|
2816
|
+
const suffix = details ? `: ${details}` : "";
|
|
2817
|
+
throw new Error(`Prompt command substitution failed for \`${failedCommand}\`${suffix}`);
|
|
2818
|
+
}
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
function resolvePromptCommandTimeoutMs(explicitTimeoutMs) {
|
|
2822
|
+
if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
|
|
2823
|
+
return explicitTimeoutMs;
|
|
2824
|
+
}
|
|
2825
|
+
const envValue = process.env[COMMAND_TIMEOUT_ENV_KEY];
|
|
2826
|
+
if (envValue !== void 0) {
|
|
2827
|
+
const parsed = Number(envValue);
|
|
2828
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
2829
|
+
return parsed;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
return DEFAULT_COMMAND_TIMEOUT_MS;
|
|
2833
|
+
}
|
|
2834
|
+
function wrapCommandForNonInteractiveExecution(command) {
|
|
2835
|
+
return `(${command}) </dev/null`;
|
|
2836
|
+
}
|
|
2837
|
+
function normalizeCommandOutput(output) {
|
|
2838
|
+
return output.replace(/\r?\n$/, "");
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
// src/core/engine.ts
|
|
2556
2842
|
var ExecutionStatus = /* @__PURE__ */ ((ExecutionStatus2) => {
|
|
2557
2843
|
ExecutionStatus2["PENDING"] = "pending";
|
|
2558
2844
|
ExecutionStatus2["RUNNING"] = "running";
|
|
@@ -2859,7 +3145,8 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
2859
3145
|
if (!request.requestId?.trim()) {
|
|
2860
3146
|
throw new Error("Request ID is required");
|
|
2861
3147
|
}
|
|
2862
|
-
|
|
3148
|
+
const allowEmptyInstructionForPiLiveInteractiveSession = request.subagent === "pi" && request.live === true && request.liveInteractiveSession === true && typeof request.resume === "string" && request.resume.trim().length > 0;
|
|
3149
|
+
if (!request.instruction?.trim() && !allowEmptyInstructionForPiLiveInteractiveSession) {
|
|
2863
3150
|
throw new Error("Instruction is required");
|
|
2864
3151
|
}
|
|
2865
3152
|
if (!request.subagent?.trim()) {
|
|
@@ -3097,44 +3384,62 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
3097
3384
|
engineLogger.warn("Hook START_ITERATION failed", { error, iterationNumber });
|
|
3098
3385
|
}
|
|
3099
3386
|
this.emit("iteration:start", { context, iterationNumber });
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3387
|
+
let toolRequest = null;
|
|
3388
|
+
try {
|
|
3389
|
+
const instructionTemplate = context.request.instruction;
|
|
3390
|
+
const resolvedInstruction = await resolvePromptCommandSubstitutions(instructionTemplate, {
|
|
3391
|
+
workingDirectory: context.request.workingDirectory,
|
|
3392
|
+
environment: {
|
|
3393
|
+
...process.env,
|
|
3394
|
+
JUNO_TASK_ROOT: process.env.JUNO_TASK_ROOT || context.request.workingDirectory
|
|
3395
|
+
}
|
|
3396
|
+
});
|
|
3397
|
+
this.emit("iteration:instruction-resolved", {
|
|
3398
|
+
context,
|
|
3399
|
+
iterationNumber,
|
|
3400
|
+
instruction: resolvedInstruction,
|
|
3401
|
+
templateInstruction: instructionTemplate
|
|
3402
|
+
});
|
|
3403
|
+
toolRequest = {
|
|
3404
|
+
toolName: this.getToolNameForSubagent(context.request.subagent),
|
|
3405
|
+
arguments: {
|
|
3406
|
+
instruction: resolvedInstruction,
|
|
3407
|
+
project_path: context.request.workingDirectory,
|
|
3408
|
+
...context.request.model !== void 0 && { model: context.request.model },
|
|
3409
|
+
...context.request.agents !== void 0 && { agents: context.request.agents },
|
|
3410
|
+
...context.request.tools !== void 0 && { tools: context.request.tools },
|
|
3411
|
+
...context.request.allowedTools !== void 0 && {
|
|
3412
|
+
allowedTools: context.request.allowedTools
|
|
3413
|
+
},
|
|
3414
|
+
...context.request.appendAllowedTools !== void 0 && {
|
|
3415
|
+
appendAllowedTools: context.request.appendAllowedTools
|
|
3416
|
+
},
|
|
3417
|
+
...context.request.disallowedTools !== void 0 && {
|
|
3418
|
+
disallowedTools: context.request.disallowedTools
|
|
3419
|
+
},
|
|
3420
|
+
...context.request.resume !== void 0 && { resume: context.request.resume },
|
|
3421
|
+
...context.request.continueConversation !== void 0 && {
|
|
3422
|
+
continueConversation: context.request.continueConversation
|
|
3423
|
+
},
|
|
3424
|
+
...context.request.thinking !== void 0 && { thinking: context.request.thinking },
|
|
3425
|
+
...context.request.live !== void 0 && { live: context.request.live },
|
|
3426
|
+
...context.request.liveInteractiveSession !== void 0 && {
|
|
3427
|
+
liveInteractiveSession: context.request.liveInteractiveSession
|
|
3428
|
+
},
|
|
3429
|
+
iteration: iterationNumber
|
|
3116
3430
|
},
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3431
|
+
timeout: context.request.timeoutMs || this.engineConfig.config.mcpTimeout,
|
|
3432
|
+
priority: context.request.priority || "normal",
|
|
3433
|
+
metadata: {
|
|
3434
|
+
sessionId: context.sessionContext.sessionId,
|
|
3435
|
+
iterationNumber
|
|
3120
3436
|
},
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
metadata: {
|
|
3128
|
-
sessionId: context.sessionContext.sessionId,
|
|
3129
|
-
iterationNumber
|
|
3130
|
-
},
|
|
3131
|
-
progressCallback: async (event) => {
|
|
3132
|
-
context.progressEvents.push(event);
|
|
3133
|
-
context.statistics.totalProgressEvents++;
|
|
3134
|
-
await this.processProgressEvent(context, event);
|
|
3135
|
-
}
|
|
3136
|
-
};
|
|
3137
|
-
try {
|
|
3437
|
+
progressCallback: async (event) => {
|
|
3438
|
+
context.progressEvents.push(event);
|
|
3439
|
+
context.statistics.totalProgressEvents++;
|
|
3440
|
+
await this.processProgressEvent(context, event);
|
|
3441
|
+
}
|
|
3442
|
+
};
|
|
3138
3443
|
if (!this.currentBackend) {
|
|
3139
3444
|
throw new Error("No backend initialized. Call initializeBackend() first.");
|
|
3140
3445
|
}
|
|
@@ -3203,7 +3508,10 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
3203
3508
|
duration,
|
|
3204
3509
|
error: mcpError,
|
|
3205
3510
|
progressEvents: [],
|
|
3206
|
-
request: toolRequest
|
|
3511
|
+
request: toolRequest ?? {
|
|
3512
|
+
toolName: this.getToolNameForSubagent(context.request.subagent),
|
|
3513
|
+
arguments: {}
|
|
3514
|
+
}
|
|
3207
3515
|
},
|
|
3208
3516
|
progressEvents: [],
|
|
3209
3517
|
error: mcpError
|
|
@@ -3718,6 +4026,9 @@ function createExecutionRequest(options) {
|
|
|
3718
4026
|
if (options.live !== void 0) {
|
|
3719
4027
|
result.live = options.live;
|
|
3720
4028
|
}
|
|
4029
|
+
if (options.liveInteractiveSession !== void 0) {
|
|
4030
|
+
result.liveInteractiveSession = options.liveInteractiveSession;
|
|
4031
|
+
}
|
|
3721
4032
|
return result;
|
|
3722
4033
|
}
|
|
3723
4034
|
|