juno-code 1.0.42 → 1.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +4254 -3819
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +4256 -3820
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +219 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +211 -75
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/kanban.sh +85 -3
- package/dist/templates/scripts/run_until_completion.sh +43 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var os2 = require('os');
|
|
5
|
+
var path6 = require('path');
|
|
6
6
|
var process2 = require('process');
|
|
7
7
|
var nodeFs = require('fs');
|
|
8
8
|
var React4 = require('react');
|
|
@@ -17,11 +17,11 @@ var events = require('events');
|
|
|
17
17
|
var execa = require('execa');
|
|
18
18
|
var Table = require('cli-table3');
|
|
19
19
|
var supportsColor = require('supports-color');
|
|
20
|
+
var child_process = require('child_process');
|
|
20
21
|
var uuid = require('uuid');
|
|
21
22
|
var perf_hooks = require('perf_hooks');
|
|
22
23
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
23
24
|
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
24
|
-
var child_process = require('child_process');
|
|
25
25
|
|
|
26
26
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
27
|
|
|
@@ -43,8 +43,8 @@ function _interopNamespace(e) {
|
|
|
43
43
|
return Object.freeze(n);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
var
|
|
47
|
-
var
|
|
46
|
+
var os2__namespace = /*#__PURE__*/_interopNamespace(os2);
|
|
47
|
+
var path6__namespace = /*#__PURE__*/_interopNamespace(path6);
|
|
48
48
|
var process2__namespace = /*#__PURE__*/_interopNamespace(process2);
|
|
49
49
|
var nodeFs__namespace = /*#__PURE__*/_interopNamespace(nodeFs);
|
|
50
50
|
var React4__default = /*#__PURE__*/_interopDefault(React4);
|
|
@@ -75,7 +75,7 @@ var __export = (target, all) => {
|
|
|
75
75
|
exports.version = void 0;
|
|
76
76
|
var init_version = __esm({
|
|
77
77
|
"src/version.ts"() {
|
|
78
|
-
exports.version = "1.0.
|
|
78
|
+
exports.version = "1.0.44";
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
function isHeadlessEnvironment() {
|
|
@@ -206,14 +206,14 @@ function isInDocker() {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
function getPlatform() {
|
|
209
|
-
return
|
|
209
|
+
return os2__namespace.platform();
|
|
210
210
|
}
|
|
211
211
|
function getArchitecture() {
|
|
212
|
-
return
|
|
212
|
+
return os2__namespace.arch();
|
|
213
213
|
}
|
|
214
214
|
function getShell() {
|
|
215
215
|
const shell = process2__namespace.env.SHELL || process2__namespace.env.ComSpec || "";
|
|
216
|
-
const shellName =
|
|
216
|
+
const shellName = path6__namespace.basename(shell).toLowerCase();
|
|
217
217
|
if (shellName.includes("bash")) return "bash";
|
|
218
218
|
if (shellName.includes("zsh")) return "zsh";
|
|
219
219
|
if (shellName.includes("fish")) return "fish";
|
|
@@ -222,21 +222,21 @@ function getShell() {
|
|
|
222
222
|
return "unknown";
|
|
223
223
|
}
|
|
224
224
|
function getHomeDirectory() {
|
|
225
|
-
return
|
|
225
|
+
return os2__namespace.homedir();
|
|
226
226
|
}
|
|
227
227
|
function getTempDirectory() {
|
|
228
|
-
return
|
|
228
|
+
return os2__namespace.tmpdir();
|
|
229
229
|
}
|
|
230
230
|
function getConfigDirectory(appName = "juno-task") {
|
|
231
231
|
const platform2 = getPlatform();
|
|
232
232
|
const home = getHomeDirectory();
|
|
233
233
|
switch (platform2) {
|
|
234
234
|
case "win32":
|
|
235
|
-
return
|
|
235
|
+
return path6__namespace.join(process2__namespace.env.APPDATA || path6__namespace.join(home, "AppData", "Roaming"), appName);
|
|
236
236
|
case "darwin":
|
|
237
|
-
return
|
|
237
|
+
return path6__namespace.join(home, "Library", "Application Support", appName);
|
|
238
238
|
default:
|
|
239
|
-
return
|
|
239
|
+
return path6__namespace.join(process2__namespace.env.XDG_CONFIG_HOME || path6__namespace.join(home, ".config"), appName);
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
function getDataDirectory(appName = "juno-task") {
|
|
@@ -244,11 +244,11 @@ function getDataDirectory(appName = "juno-task") {
|
|
|
244
244
|
const home = getHomeDirectory();
|
|
245
245
|
switch (platform2) {
|
|
246
246
|
case "win32":
|
|
247
|
-
return
|
|
247
|
+
return path6__namespace.join(process2__namespace.env.LOCALAPPDATA || path6__namespace.join(home, "AppData", "Local"), appName);
|
|
248
248
|
case "darwin":
|
|
249
|
-
return
|
|
249
|
+
return path6__namespace.join(home, "Library", "Application Support", appName);
|
|
250
250
|
default:
|
|
251
|
-
return
|
|
251
|
+
return path6__namespace.join(process2__namespace.env.XDG_DATA_HOME || path6__namespace.join(home, ".local", "share"), appName);
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
function getCacheDirectory(appName = "juno-task") {
|
|
@@ -256,11 +256,11 @@ function getCacheDirectory(appName = "juno-task") {
|
|
|
256
256
|
const home = getHomeDirectory();
|
|
257
257
|
switch (platform2) {
|
|
258
258
|
case "win32":
|
|
259
|
-
return
|
|
259
|
+
return path6__namespace.join(process2__namespace.env.TEMP || path6__namespace.join(home, "AppData", "Local", "Temp"), appName);
|
|
260
260
|
case "darwin":
|
|
261
|
-
return
|
|
261
|
+
return path6__namespace.join(home, "Library", "Caches", appName);
|
|
262
262
|
default:
|
|
263
|
-
return
|
|
263
|
+
return path6__namespace.join(process2__namespace.env.XDG_CACHE_HOME || path6__namespace.join(home, ".cache"), appName);
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
async function createDirectoryIfNotExists(dirPath) {
|
|
@@ -310,26 +310,26 @@ async function findMCPServerPath(serverName = "mcp-server") {
|
|
|
310
310
|
const platform2 = getPlatform();
|
|
311
311
|
const searchPaths = [];
|
|
312
312
|
const pathEnv = process2__namespace.env.PATH || "";
|
|
313
|
-
searchPaths.push(...pathEnv.split(
|
|
313
|
+
searchPaths.push(...pathEnv.split(path6__namespace.delimiter));
|
|
314
314
|
if (platform2 === "win32") {
|
|
315
315
|
searchPaths.push(
|
|
316
316
|
"C:\\Program Files\\MCP\\bin",
|
|
317
317
|
"C:\\Program Files (x86)\\MCP\\bin",
|
|
318
|
-
|
|
318
|
+
path6__namespace.join(process2__namespace.env.LOCALAPPDATA || "", "Programs", "MCP", "bin")
|
|
319
319
|
);
|
|
320
320
|
} else {
|
|
321
321
|
searchPaths.push(
|
|
322
322
|
"/usr/local/bin",
|
|
323
323
|
"/usr/bin",
|
|
324
324
|
"/opt/mcp/bin",
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
path6__namespace.join(getHomeDirectory(), ".local", "bin"),
|
|
326
|
+
path6__namespace.join(getHomeDirectory(), "bin")
|
|
327
327
|
);
|
|
328
328
|
}
|
|
329
329
|
const executable = platform2 === "win32" ? `${serverName}.exe` : serverName;
|
|
330
330
|
for (const searchPath of searchPaths) {
|
|
331
331
|
if (!searchPath) continue;
|
|
332
|
-
const fullPath =
|
|
332
|
+
const fullPath = path6__namespace.join(searchPath, executable);
|
|
333
333
|
try {
|
|
334
334
|
await nodeFs.promises.access(fullPath, nodeFs.promises.constants.F_OK | nodeFs.promises.constants.X_OK);
|
|
335
335
|
return fullPath;
|
|
@@ -4051,6 +4051,13 @@ var DEFAULT_HOOKS = {
|
|
|
4051
4051
|
// Use for: final cleanup, notifications, reports, post-run actions
|
|
4052
4052
|
END_RUN: {
|
|
4053
4053
|
commands: []
|
|
4054
|
+
},
|
|
4055
|
+
// Executes when stale iteration is detected in run_until_completion.sh
|
|
4056
|
+
// Use for: alerts, notifications, logging when agent is not making progress
|
|
4057
|
+
ON_STALE: {
|
|
4058
|
+
commands: [
|
|
4059
|
+
`./.juno_task/scripts/kanban.sh create "Warning: You haven't done anything on the kanban in the past run. You need to process a task, or if you find it unsuitable or unresolvable, you need to archive the task" --status todo`
|
|
4060
|
+
]
|
|
4054
4061
|
}
|
|
4055
4062
|
};
|
|
4056
4063
|
function getDefaultHooks() {
|
|
@@ -4104,9 +4111,9 @@ var ProfileManager = class {
|
|
|
4104
4111
|
profileCache = /* @__PURE__ */ new Map();
|
|
4105
4112
|
activeProfile = null;
|
|
4106
4113
|
constructor(configDir) {
|
|
4107
|
-
this.profilesDir =
|
|
4108
|
-
this.activeProfileFile =
|
|
4109
|
-
this.defaultConfigFile =
|
|
4114
|
+
this.profilesDir = path6__namespace.join(configDir, "profiles");
|
|
4115
|
+
this.activeProfileFile = path6__namespace.join(configDir, "active-profile.txt");
|
|
4116
|
+
this.defaultConfigFile = path6__namespace.join(configDir, "config.json");
|
|
4110
4117
|
}
|
|
4111
4118
|
/**
|
|
4112
4119
|
* Initialize the profile system
|
|
@@ -4213,7 +4220,7 @@ var ProfileManager = class {
|
|
|
4213
4220
|
profile,
|
|
4214
4221
|
version: "1.0.0"
|
|
4215
4222
|
};
|
|
4216
|
-
const profilePath =
|
|
4223
|
+
const profilePath = path6__namespace.join(this.profilesDir, `${profile.name}.json`);
|
|
4217
4224
|
await nodeFs.promises.writeFile(profilePath, JSON.stringify(storage, null, 2), "utf-8");
|
|
4218
4225
|
this.profileCache.delete(profile.name);
|
|
4219
4226
|
}
|
|
@@ -4366,7 +4373,7 @@ var ProfileManager = class {
|
|
|
4366
4373
|
async findProfileFile(name) {
|
|
4367
4374
|
const extensions = [".json", ".yaml", ".yml"];
|
|
4368
4375
|
for (const ext of extensions) {
|
|
4369
|
-
const filePath =
|
|
4376
|
+
const filePath = path6__namespace.join(this.profilesDir, `${name}${ext}`);
|
|
4370
4377
|
try {
|
|
4371
4378
|
await nodeFs.promises.access(filePath);
|
|
4372
4379
|
return filePath;
|
|
@@ -4435,7 +4442,7 @@ var ProfileManager = class {
|
|
|
4435
4442
|
headlessMode: false,
|
|
4436
4443
|
// Paths
|
|
4437
4444
|
workingDirectory: process.cwd(),
|
|
4438
|
-
sessionDirectory:
|
|
4445
|
+
sessionDirectory: path6__namespace.join(process.cwd(), ".juno_task", "sessions")
|
|
4439
4446
|
};
|
|
4440
4447
|
}
|
|
4441
4448
|
};
|
|
@@ -4487,6 +4494,8 @@ var ENV_VAR_MAPPING = {
|
|
|
4487
4494
|
JUNO_CODE_MCP_SERVER_NAME: "mcpServerName",
|
|
4488
4495
|
// Hook settings
|
|
4489
4496
|
JUNO_CODE_HOOK_COMMAND_TIMEOUT: "hookCommandTimeout",
|
|
4497
|
+
// Quota/hourly limit settings
|
|
4498
|
+
JUNO_CODE_ON_HOURLY_LIMIT: "onHourlyLimit",
|
|
4490
4499
|
// TUI settings
|
|
4491
4500
|
JUNO_CODE_INTERACTIVE: "interactive",
|
|
4492
4501
|
JUNO_CODE_HEADLESS_MODE: "headlessMode",
|
|
@@ -4512,6 +4521,8 @@ var LEGACY_ENV_VAR_MAPPING = {
|
|
|
4512
4521
|
JUNO_TASK_MCP_SERVER_NAME: "mcpServerName",
|
|
4513
4522
|
// Hook settings
|
|
4514
4523
|
JUNO_TASK_HOOK_COMMAND_TIMEOUT: "hookCommandTimeout",
|
|
4524
|
+
// Quota/hourly limit settings
|
|
4525
|
+
JUNO_TASK_ON_HOURLY_LIMIT: "onHourlyLimit",
|
|
4515
4526
|
// TUI settings
|
|
4516
4527
|
JUNO_TASK_INTERACTIVE: "interactive",
|
|
4517
4528
|
JUNO_TASK_HEADLESS_MODE: "headlessMode",
|
|
@@ -4522,7 +4533,8 @@ var LEGACY_ENV_VAR_MAPPING = {
|
|
|
4522
4533
|
var SubagentTypeSchema = zod.z.enum(["claude", "cursor", "codex", "gemini"]);
|
|
4523
4534
|
var BackendTypeSchema = zod.z.enum(["mcp", "shell"]);
|
|
4524
4535
|
var LogLevelSchema = zod.z.enum(["error", "warn", "info", "debug", "trace"]);
|
|
4525
|
-
var
|
|
4536
|
+
var OnHourlyLimitSchema = zod.z.enum(["wait", "raise"]);
|
|
4537
|
+
var HookTypeSchema = zod.z.enum(["START_RUN", "START_ITERATION", "END_ITERATION", "END_RUN", "ON_STALE"]);
|
|
4526
4538
|
var HookSchema = zod.z.object({
|
|
4527
4539
|
commands: zod.z.array(zod.z.string()).describe("List of bash commands to execute for this hook")
|
|
4528
4540
|
});
|
|
@@ -4545,6 +4557,8 @@ var JunoTaskConfigSchema = zod.z.object({
|
|
|
4545
4557
|
mcpServerName: zod.z.string().optional().describe('Named MCP server to connect to (e.g., "roundtable-ai")'),
|
|
4546
4558
|
// Hook settings
|
|
4547
4559
|
hookCommandTimeout: zod.z.number().int().min(1e3).max(36e5).optional().describe("Timeout for individual hook commands in milliseconds (default: 300000 = 5 minutes)"),
|
|
4560
|
+
// Quota/hourly limit settings
|
|
4561
|
+
onHourlyLimit: OnHourlyLimitSchema.describe('Behavior when Claude hourly quota limit is reached: "wait" to sleep until reset, "raise" to exit immediately'),
|
|
4548
4562
|
// TUI settings
|
|
4549
4563
|
interactive: zod.z.boolean().describe("Enable interactive mode"),
|
|
4550
4564
|
headlessMode: zod.z.boolean().describe("Enable headless mode (no TUI)"),
|
|
@@ -4563,18 +4577,21 @@ var DEFAULT_CONFIG = {
|
|
|
4563
4577
|
logLevel: "info",
|
|
4564
4578
|
verbose: false,
|
|
4565
4579
|
quiet: false,
|
|
4566
|
-
// MCP settings
|
|
4567
|
-
mcpTimeout:
|
|
4568
|
-
//
|
|
4580
|
+
// MCP settings (also used by shell backend)
|
|
4581
|
+
mcpTimeout: 432e5,
|
|
4582
|
+
// 43200 seconds (12 hours) - default for long-running shell backend operations
|
|
4569
4583
|
mcpRetries: 3,
|
|
4570
4584
|
mcpServerName: "roundtable-ai",
|
|
4571
4585
|
// Default to roundtable-ai server
|
|
4586
|
+
// Quota/hourly limit settings
|
|
4587
|
+
onHourlyLimit: "raise",
|
|
4588
|
+
// Default to exit immediately when hourly limit is reached
|
|
4572
4589
|
// TUI settings
|
|
4573
4590
|
interactive: true,
|
|
4574
4591
|
headlessMode: false,
|
|
4575
4592
|
// Paths
|
|
4576
4593
|
workingDirectory: process.cwd(),
|
|
4577
|
-
sessionDirectory:
|
|
4594
|
+
sessionDirectory: path6__namespace.join(process.cwd(), ".juno_task"),
|
|
4578
4595
|
// Hooks configuration - populated with default hooks template
|
|
4579
4596
|
hooks: getDefaultHooks()
|
|
4580
4597
|
};
|
|
@@ -4588,10 +4605,10 @@ var GLOBAL_CONFIG_FILE_NAMES = [
|
|
|
4588
4605
|
];
|
|
4589
4606
|
var PROJECT_CONFIG_FILE = ".juno_task/config.json";
|
|
4590
4607
|
function resolvePath(inputPath, basePath = process.cwd()) {
|
|
4591
|
-
if (
|
|
4608
|
+
if (path6__namespace.isAbsolute(inputPath)) {
|
|
4592
4609
|
return inputPath;
|
|
4593
4610
|
}
|
|
4594
|
-
return
|
|
4611
|
+
return path6__namespace.resolve(basePath, inputPath);
|
|
4595
4612
|
}
|
|
4596
4613
|
function parseEnvValue(value) {
|
|
4597
4614
|
if (value === "") return value;
|
|
@@ -4646,7 +4663,7 @@ async function loadPackageJsonConfig(filePath) {
|
|
|
4646
4663
|
}
|
|
4647
4664
|
}
|
|
4648
4665
|
function getConfigFileFormat(filePath) {
|
|
4649
|
-
const ext =
|
|
4666
|
+
const ext = path6__namespace.extname(filePath).toLowerCase();
|
|
4650
4667
|
switch (ext) {
|
|
4651
4668
|
case ".json":
|
|
4652
4669
|
return "json";
|
|
@@ -4672,7 +4689,7 @@ async function loadConfigFromFile(filePath) {
|
|
|
4672
4689
|
}
|
|
4673
4690
|
switch (format) {
|
|
4674
4691
|
case "json":
|
|
4675
|
-
if (
|
|
4692
|
+
if (path6__namespace.basename(filePath) === "package.json") {
|
|
4676
4693
|
return loadPackageJsonConfig(resolvedPath);
|
|
4677
4694
|
}
|
|
4678
4695
|
return loadJsonConfig(resolvedPath);
|
|
@@ -4687,7 +4704,7 @@ async function loadConfigFromFile(filePath) {
|
|
|
4687
4704
|
}
|
|
4688
4705
|
}
|
|
4689
4706
|
async function findProjectConfigFile(searchDir = process.cwd()) {
|
|
4690
|
-
const filePath =
|
|
4707
|
+
const filePath = path6__namespace.join(searchDir, PROJECT_CONFIG_FILE);
|
|
4691
4708
|
try {
|
|
4692
4709
|
await nodeFs.promises.access(filePath, nodeFs__namespace.constants.R_OK);
|
|
4693
4710
|
return filePath;
|
|
@@ -4697,7 +4714,7 @@ async function findProjectConfigFile(searchDir = process.cwd()) {
|
|
|
4697
4714
|
}
|
|
4698
4715
|
async function findGlobalConfigFile(searchDir = process.cwd()) {
|
|
4699
4716
|
for (const fileName of GLOBAL_CONFIG_FILE_NAMES) {
|
|
4700
|
-
const filePath =
|
|
4717
|
+
const filePath = path6__namespace.join(searchDir, fileName);
|
|
4701
4718
|
try {
|
|
4702
4719
|
await nodeFs.promises.access(filePath, nodeFs__namespace.constants.R_OK);
|
|
4703
4720
|
return filePath;
|
|
@@ -4871,8 +4888,8 @@ function validateConfig(config) {
|
|
|
4871
4888
|
}
|
|
4872
4889
|
async function ensureHooksConfig(baseDir) {
|
|
4873
4890
|
try {
|
|
4874
|
-
const configDir =
|
|
4875
|
-
const configPath =
|
|
4891
|
+
const configDir = path6__namespace.join(baseDir, ".juno_task");
|
|
4892
|
+
const configPath = path6__namespace.join(configDir, "config.json");
|
|
4876
4893
|
await fs__default.default.ensureDir(configDir);
|
|
4877
4894
|
const configExists = await fs__default.default.pathExists(configPath);
|
|
4878
4895
|
const allHookTypes = getDefaultHooks();
|
|
@@ -6807,7 +6824,7 @@ async function executeHooks(hookTypes, hooks, context = {}, options = {}) {
|
|
|
6807
6824
|
function validateHooksConfig(hooks) {
|
|
6808
6825
|
const issues = [];
|
|
6809
6826
|
const warnings = [];
|
|
6810
|
-
const validHookTypes = ["START_RUN", "START_ITERATION", "END_ITERATION", "END_RUN"];
|
|
6827
|
+
const validHookTypes = ["START_RUN", "START_ITERATION", "END_ITERATION", "END_RUN", "ON_STALE"];
|
|
6811
6828
|
for (const [hookType, hook] of Object.entries(hooks)) {
|
|
6812
6829
|
if (!validHookTypes.includes(hookType)) {
|
|
6813
6830
|
warnings.push(`Unknown hook type: ${hookType}. Valid types are: ${validHookTypes.join(", ")}`);
|
|
@@ -6851,6 +6868,20 @@ function validateHooksConfig(hooks) {
|
|
|
6851
6868
|
};
|
|
6852
6869
|
}
|
|
6853
6870
|
|
|
6871
|
+
// src/core/backends/shell-backend.ts
|
|
6872
|
+
init_version();
|
|
6873
|
+
function formatDuration(ms) {
|
|
6874
|
+
const totalSeconds = Math.ceil(ms / 1e3);
|
|
6875
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
6876
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
6877
|
+
const seconds = totalSeconds % 60;
|
|
6878
|
+
const parts = [];
|
|
6879
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
6880
|
+
if (minutes > 0) parts.push(`${minutes}m`);
|
|
6881
|
+
if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
|
|
6882
|
+
return parts.join(" ");
|
|
6883
|
+
}
|
|
6884
|
+
|
|
6854
6885
|
// src/core/engine.ts
|
|
6855
6886
|
var ExecutionStatus = /* @__PURE__ */ ((ExecutionStatus2) => {
|
|
6856
6887
|
ExecutionStatus2["PENDING"] = "pending";
|
|
@@ -7150,6 +7181,8 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
7150
7181
|
totalProgressEvents: 0,
|
|
7151
7182
|
rateLimitEncounters: 0,
|
|
7152
7183
|
rateLimitWaitTime: 0,
|
|
7184
|
+
quotaLimitEncounters: 0,
|
|
7185
|
+
quotaLimitWaitTime: 0,
|
|
7153
7186
|
errorBreakdown: {},
|
|
7154
7187
|
performanceMetrics: {
|
|
7155
7188
|
cpuUsage: 0,
|
|
@@ -7254,7 +7287,13 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
7254
7287
|
while (!this.shouldStopIterating(context, iterationNumber)) {
|
|
7255
7288
|
this.checkAbortSignal(context);
|
|
7256
7289
|
try {
|
|
7257
|
-
await this.executeIteration(context, iterationNumber);
|
|
7290
|
+
const quotaLimitInfo = await this.executeIteration(context, iterationNumber);
|
|
7291
|
+
if (quotaLimitInfo?.detected) {
|
|
7292
|
+
const shouldRetry = await this.handleQuotaLimit(context, quotaLimitInfo);
|
|
7293
|
+
if (shouldRetry) {
|
|
7294
|
+
continue;
|
|
7295
|
+
}
|
|
7296
|
+
}
|
|
7258
7297
|
iterationNumber++;
|
|
7259
7298
|
} catch (error) {
|
|
7260
7299
|
if (error instanceof MCPRateLimitError) {
|
|
@@ -7272,6 +7311,7 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
7272
7311
|
}
|
|
7273
7312
|
/**
|
|
7274
7313
|
* Execute a single iteration
|
|
7314
|
+
* @returns QuotaLimitInfo if a quota limit was detected, null otherwise
|
|
7275
7315
|
*/
|
|
7276
7316
|
async executeIteration(context, iterationNumber) {
|
|
7277
7317
|
const iterationStart = /* @__PURE__ */ new Date();
|
|
@@ -7365,6 +7405,8 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
7365
7405
|
} catch (error) {
|
|
7366
7406
|
engineLogger.warn("Hook END_ITERATION failed", { error, iterationNumber });
|
|
7367
7407
|
}
|
|
7408
|
+
const quotaLimitInfo = this.extractQuotaLimitInfo(toolResult);
|
|
7409
|
+
return quotaLimitInfo;
|
|
7368
7410
|
} catch (error) {
|
|
7369
7411
|
const iterationEnd = /* @__PURE__ */ new Date();
|
|
7370
7412
|
const duration = iterationEnd.getTime() - iterationStart.getTime();
|
|
@@ -7458,6 +7500,100 @@ var ExecutionEngine = class extends events.EventEmitter {
|
|
|
7458
7500
|
}
|
|
7459
7501
|
return 6e4;
|
|
7460
7502
|
}
|
|
7503
|
+
/**
|
|
7504
|
+
* Handle Claude quota limit with automatic sleep and retry
|
|
7505
|
+
* @returns true if we should retry the iteration, false otherwise
|
|
7506
|
+
*/
|
|
7507
|
+
async handleQuotaLimit(context, quotaInfo) {
|
|
7508
|
+
if (!quotaInfo.detected || !quotaInfo.sleepDurationMs) {
|
|
7509
|
+
return false;
|
|
7510
|
+
}
|
|
7511
|
+
context.statistics.quotaLimitEncounters++;
|
|
7512
|
+
const onHourlyLimit = this.engineConfig.config.onHourlyLimit || "raise";
|
|
7513
|
+
if (onHourlyLimit === "raise") {
|
|
7514
|
+
const resetTimeStr2 = quotaInfo.resetTime ? quotaInfo.resetTime.toLocaleTimeString("en-US", {
|
|
7515
|
+
hour: "numeric",
|
|
7516
|
+
minute: "2-digit",
|
|
7517
|
+
hour12: true,
|
|
7518
|
+
timeZoneName: "short"
|
|
7519
|
+
}) : "unknown";
|
|
7520
|
+
engineLogger.info(`\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`);
|
|
7521
|
+
engineLogger.info(`\u2551 Claude Quota Limit Reached \u2551`);
|
|
7522
|
+
engineLogger.info(`\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`);
|
|
7523
|
+
engineLogger.info(`\u2551 Quota resets at: ${resetTimeStr2.padEnd(44)}\u2551`);
|
|
7524
|
+
engineLogger.info(`\u2551 Behavior: raise (exit immediately) \u2551`);
|
|
7525
|
+
engineLogger.info(`\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`);
|
|
7526
|
+
engineLogger.info(`\u2551 To auto-wait instead, use: --on-hourly-limit wait \u2551`);
|
|
7527
|
+
engineLogger.info(`\u2551 Or set: JUNO_CODE_ON_HOURLY_LIMIT=wait \u2551`);
|
|
7528
|
+
engineLogger.info(`\u2551 Or in config.json: { "onHourlyLimit": "wait" } \u2551`);
|
|
7529
|
+
engineLogger.info(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`);
|
|
7530
|
+
this.emit("quota-limit:raise", { context, quotaInfo });
|
|
7531
|
+
throw new Error(`Claude quota limit reached. Quota resets at ${resetTimeStr2}. Use --on-hourly-limit wait to auto-retry.`);
|
|
7532
|
+
}
|
|
7533
|
+
const waitTimeMs = quotaInfo.sleepDurationMs;
|
|
7534
|
+
const maxWaitTimeMs = 12 * 60 * 60 * 1e3;
|
|
7535
|
+
if (waitTimeMs > maxWaitTimeMs) {
|
|
7536
|
+
engineLogger.warn(`Quota limit wait time (${formatDuration(waitTimeMs)}) exceeds maximum allowed (12 hours). Will not auto-retry.`);
|
|
7537
|
+
return false;
|
|
7538
|
+
}
|
|
7539
|
+
context.statistics.quotaLimitWaitTime += waitTimeMs;
|
|
7540
|
+
const resetTimeStr = quotaInfo.resetTime ? quotaInfo.resetTime.toLocaleTimeString("en-US", {
|
|
7541
|
+
hour: "numeric",
|
|
7542
|
+
minute: "2-digit",
|
|
7543
|
+
hour12: true,
|
|
7544
|
+
timeZoneName: "short"
|
|
7545
|
+
}) : "unknown";
|
|
7546
|
+
const durationStr = formatDuration(waitTimeMs);
|
|
7547
|
+
engineLogger.info(`\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`);
|
|
7548
|
+
engineLogger.info(`\u2551 Claude Quota Limit Reached \u2551`);
|
|
7549
|
+
engineLogger.info(`\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563`);
|
|
7550
|
+
engineLogger.info(`\u2551 Quota resets at: ${resetTimeStr.padEnd(44)}\u2551`);
|
|
7551
|
+
engineLogger.info(`\u2551 Sleeping for: ${durationStr.padEnd(44)}\u2551`);
|
|
7552
|
+
if (quotaInfo.timezone) {
|
|
7553
|
+
engineLogger.info(`\u2551 Timezone: ${quotaInfo.timezone.padEnd(44)}\u2551`);
|
|
7554
|
+
}
|
|
7555
|
+
engineLogger.info(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`);
|
|
7556
|
+
this.emit("quota-limit:start", { context, quotaInfo, waitTimeMs });
|
|
7557
|
+
await this.sleepWithProgress(waitTimeMs, (remaining) => {
|
|
7558
|
+
const remainingStr = formatDuration(remaining);
|
|
7559
|
+
engineLogger.info(`[Quota Wait] ${remainingStr} remaining until retry...`);
|
|
7560
|
+
});
|
|
7561
|
+
this.emit("quota-limit:end", { context });
|
|
7562
|
+
engineLogger.info(`Quota limit wait complete. Resuming execution...`);
|
|
7563
|
+
return true;
|
|
7564
|
+
}
|
|
7565
|
+
/**
|
|
7566
|
+
* Sleep with periodic progress updates
|
|
7567
|
+
*/
|
|
7568
|
+
async sleepWithProgress(totalMs, onProgress) {
|
|
7569
|
+
const updateIntervalMs = 6e4;
|
|
7570
|
+
let remaining = totalMs;
|
|
7571
|
+
while (remaining > 0) {
|
|
7572
|
+
const sleepTime = Math.min(remaining, updateIntervalMs);
|
|
7573
|
+
await this.sleep(sleepTime);
|
|
7574
|
+
remaining -= sleepTime;
|
|
7575
|
+
if (remaining > 0) {
|
|
7576
|
+
onProgress(remaining);
|
|
7577
|
+
}
|
|
7578
|
+
}
|
|
7579
|
+
}
|
|
7580
|
+
/**
|
|
7581
|
+
* Check if tool result indicates a quota limit error
|
|
7582
|
+
*/
|
|
7583
|
+
extractQuotaLimitInfo(toolResult) {
|
|
7584
|
+
const metadataQuotaInfo = toolResult.metadata?.quotaLimitInfo;
|
|
7585
|
+
if (metadataQuotaInfo?.detected) {
|
|
7586
|
+
return metadataQuotaInfo;
|
|
7587
|
+
}
|
|
7588
|
+
try {
|
|
7589
|
+
const content = typeof toolResult.content === "string" ? JSON.parse(toolResult.content) : toolResult.content;
|
|
7590
|
+
if (content?.quota_limit?.detected) {
|
|
7591
|
+
return content.quota_limit;
|
|
7592
|
+
}
|
|
7593
|
+
} catch {
|
|
7594
|
+
}
|
|
7595
|
+
return null;
|
|
7596
|
+
}
|
|
7461
7597
|
/**
|
|
7462
7598
|
* Handle iteration errors with recovery strategies
|
|
7463
7599
|
*/
|
|
@@ -7786,9 +7922,9 @@ var FileSessionStorage = class {
|
|
|
7786
7922
|
* @param baseDir - Base directory for session storage
|
|
7787
7923
|
*/
|
|
7788
7924
|
constructor(baseDir) {
|
|
7789
|
-
this.baseDir =
|
|
7790
|
-
this.sessionsDir =
|
|
7791
|
-
this.archiveDir =
|
|
7925
|
+
this.baseDir = path6__namespace.resolve(baseDir);
|
|
7926
|
+
this.sessionsDir = path6__namespace.join(this.baseDir, "sessions");
|
|
7927
|
+
this.archiveDir = path6__namespace.join(this.baseDir, "archive");
|
|
7792
7928
|
}
|
|
7793
7929
|
/**
|
|
7794
7930
|
* Initialize storage directories
|
|
@@ -7803,7 +7939,7 @@ var FileSessionStorage = class {
|
|
|
7803
7939
|
* @returns Full path to session file
|
|
7804
7940
|
*/
|
|
7805
7941
|
getSessionPath(sessionId) {
|
|
7806
|
-
return
|
|
7942
|
+
return path6__namespace.join(this.sessionsDir, `${sessionId}.json`);
|
|
7807
7943
|
}
|
|
7808
7944
|
/**
|
|
7809
7945
|
* Save session data to storage
|
|
@@ -7869,7 +8005,7 @@ var FileSessionStorage = class {
|
|
|
7869
8005
|
const sessions = [];
|
|
7870
8006
|
for (const file of sessionFiles) {
|
|
7871
8007
|
try {
|
|
7872
|
-
const sessionId =
|
|
8008
|
+
const sessionId = path6__namespace.basename(file, ".json");
|
|
7873
8009
|
const session = await this.loadSession(sessionId);
|
|
7874
8010
|
if (session) {
|
|
7875
8011
|
sessions.push(session.info);
|
|
@@ -7972,7 +8108,7 @@ var FileSessionStorage = class {
|
|
|
7972
8108
|
const session = await this.loadSession(sessionInfo.id);
|
|
7973
8109
|
if (!session) continue;
|
|
7974
8110
|
const archiveFileName = `${sessionInfo.id}_${sessionInfo.createdAt.toISOString().split("T")[0]}.json`;
|
|
7975
|
-
const archivePath =
|
|
8111
|
+
const archivePath = path6__namespace.join(this.archiveDir, archiveFileName);
|
|
7976
8112
|
if (options.includeData) {
|
|
7977
8113
|
await nodeFs.promises.writeFile(
|
|
7978
8114
|
archivePath,
|
|
@@ -8780,8 +8916,8 @@ var MetricsCollector = class extends events.EventEmitter {
|
|
|
8780
8916
|
*/
|
|
8781
8917
|
initializeSystemMetrics() {
|
|
8782
8918
|
const memoryUsage2 = process.memoryUsage();
|
|
8783
|
-
const totalMem =
|
|
8784
|
-
const freeMem =
|
|
8919
|
+
const totalMem = os2.totalmem();
|
|
8920
|
+
const freeMem = os2.freemem();
|
|
8785
8921
|
const usedMem = totalMem - freeMem;
|
|
8786
8922
|
return {
|
|
8787
8923
|
timestamp: /* @__PURE__ */ new Date(),
|
|
@@ -8855,8 +8991,8 @@ var MetricsCollector = class extends events.EventEmitter {
|
|
|
8855
8991
|
*/
|
|
8856
8992
|
updateSystemMetrics() {
|
|
8857
8993
|
const memoryUsage2 = process.memoryUsage();
|
|
8858
|
-
const totalMem =
|
|
8859
|
-
const freeMem =
|
|
8994
|
+
const totalMem = os2.totalmem();
|
|
8995
|
+
const freeMem = os2.freemem();
|
|
8860
8996
|
const usedMem = totalMem - freeMem;
|
|
8861
8997
|
this.systemMetrics = {
|
|
8862
8998
|
...this.systemMetrics,
|
|
@@ -9254,7 +9390,7 @@ var MetricsReporter = class {
|
|
|
9254
9390
|
default:
|
|
9255
9391
|
throw new Error(`Unsupported export format: ${options.format}`);
|
|
9256
9392
|
}
|
|
9257
|
-
await nodeFs.promises.mkdir(
|
|
9393
|
+
await nodeFs.promises.mkdir(path6__namespace.dirname(options.outputPath), { recursive: true });
|
|
9258
9394
|
await nodeFs.promises.writeFile(options.outputPath, exportData, "utf-8");
|
|
9259
9395
|
}
|
|
9260
9396
|
/**
|
|
@@ -9372,7 +9508,7 @@ var IterationsSchema = zod.z.number().int("Iterations must be an integer").refin
|
|
|
9372
9508
|
(value) => value === -1 || value > 0,
|
|
9373
9509
|
"Iterations must be a positive integer or -1 for infinite"
|
|
9374
9510
|
).transform((value) => value === -1 ? Infinity : value);
|
|
9375
|
-
var FilePathSchema = zod.z.string().min(1, "File path cannot be empty").transform((value) =>
|
|
9511
|
+
var FilePathSchema = zod.z.string().min(1, "File path cannot be empty").transform((value) => path6__namespace.resolve(value)).refine(async (filePath) => {
|
|
9376
9512
|
try {
|
|
9377
9513
|
const stats = await nodeFs.promises.stat(filePath);
|
|
9378
9514
|
return stats.isFile();
|
|
@@ -9380,7 +9516,7 @@ var FilePathSchema = zod.z.string().min(1, "File path cannot be empty").transfor
|
|
|
9380
9516
|
return false;
|
|
9381
9517
|
}
|
|
9382
9518
|
}, "File does not exist or is not accessible");
|
|
9383
|
-
var DirectoryPathSchema = zod.z.string().min(1, "Directory path cannot be empty").transform((value) =>
|
|
9519
|
+
var DirectoryPathSchema = zod.z.string().min(1, "Directory path cannot be empty").transform((value) => path6__namespace.resolve(value)).refine(async (dirPath) => {
|
|
9384
9520
|
try {
|
|
9385
9521
|
const stats = await nodeFs.promises.stat(dirPath);
|
|
9386
9522
|
return stats.isDirectory();
|
|
@@ -9536,7 +9672,7 @@ function isValidLogLevel(value) {
|
|
|
9536
9672
|
}
|
|
9537
9673
|
async function isValidPath(filePath, type = "file") {
|
|
9538
9674
|
try {
|
|
9539
|
-
const resolvedPath =
|
|
9675
|
+
const resolvedPath = path6__namespace.resolve(filePath);
|
|
9540
9676
|
const stats = await nodeFs.promises.stat(resolvedPath);
|
|
9541
9677
|
return type === "file" ? stats.isFile() : stats.isDirectory();
|
|
9542
9678
|
} catch {
|
|
@@ -9557,7 +9693,7 @@ function sanitizeFilePath(filePath) {
|
|
|
9557
9693
|
if (!cleaned) {
|
|
9558
9694
|
throw new ValidationError("File path cannot be empty after sanitization", "filePath", filePath);
|
|
9559
9695
|
}
|
|
9560
|
-
return
|
|
9696
|
+
return path6__namespace.resolve(cleaned);
|
|
9561
9697
|
}
|
|
9562
9698
|
function sanitizeGitUrl(url) {
|
|
9563
9699
|
if (typeof url !== "string") {
|
|
@@ -9688,8 +9824,8 @@ function validateCommandOptions(options) {
|
|
|
9688
9824
|
} catch (error) {
|
|
9689
9825
|
if (error instanceof zod.z.ZodError) {
|
|
9690
9826
|
const errors = error.errors.map((err) => {
|
|
9691
|
-
const
|
|
9692
|
-
return `--${
|
|
9827
|
+
const path11 = err.path.length > 0 ? err.path.join(".") : "option";
|
|
9828
|
+
return `--${path11}: ${err.message}`;
|
|
9693
9829
|
});
|
|
9694
9830
|
const suggestions = [
|
|
9695
9831
|
"Check command line option syntax",
|
|
@@ -10990,7 +11126,7 @@ var MCPConfigLoader = class {
|
|
|
10990
11126
|
const configContent = await fs__default.default.readFile(configPath, "utf-8");
|
|
10991
11127
|
const config = JSON.parse(configContent);
|
|
10992
11128
|
this.validateConfig(config);
|
|
10993
|
-
const resolvedConfig = this.resolveConfigPaths(config,
|
|
11129
|
+
const resolvedConfig = this.resolveConfigPaths(config, path6__namespace.dirname(configPath));
|
|
10994
11130
|
this.configCache.set(configPath, resolvedConfig);
|
|
10995
11131
|
this.lastLoadTime.set(configPath, Date.now());
|
|
10996
11132
|
return resolvedConfig;
|
|
@@ -11005,14 +11141,14 @@ var MCPConfigLoader = class {
|
|
|
11005
11141
|
* Find the mcp.json configuration file
|
|
11006
11142
|
*/
|
|
11007
11143
|
static async findConfigFile(startDir) {
|
|
11008
|
-
let currentDir =
|
|
11009
|
-
const rootDir =
|
|
11144
|
+
let currentDir = path6__namespace.resolve(startDir);
|
|
11145
|
+
const rootDir = path6__namespace.parse(currentDir).root;
|
|
11010
11146
|
while (currentDir !== rootDir) {
|
|
11011
|
-
const configPath =
|
|
11147
|
+
const configPath = path6__namespace.join(currentDir, ".juno_task", "mcp.json");
|
|
11012
11148
|
if (await fs__default.default.pathExists(configPath)) {
|
|
11013
11149
|
return configPath;
|
|
11014
11150
|
}
|
|
11015
|
-
currentDir =
|
|
11151
|
+
currentDir = path6__namespace.dirname(currentDir);
|
|
11016
11152
|
}
|
|
11017
11153
|
throw new MCPConnectionError(
|
|
11018
11154
|
`MCP configuration not found. Please run 'juno-task init' to create .juno_task/mcp.json`
|
|
@@ -11078,16 +11214,16 @@ var MCPConfigLoader = class {
|
|
|
11078
11214
|
const resolvedConfig = JSON.parse(JSON.stringify(config));
|
|
11079
11215
|
for (const [serverName, serverConfig] of Object.entries(resolvedConfig.mcpServers)) {
|
|
11080
11216
|
serverConfig.args = serverConfig.args.map((arg) => {
|
|
11081
|
-
if (arg.includes("/") && !
|
|
11082
|
-
return
|
|
11217
|
+
if (arg.includes("/") && !path6__namespace.isAbsolute(arg)) {
|
|
11218
|
+
return path6__namespace.resolve(configDir, "..", arg);
|
|
11083
11219
|
}
|
|
11084
11220
|
return arg;
|
|
11085
11221
|
});
|
|
11086
11222
|
if (serverConfig.env) {
|
|
11087
11223
|
for (const [envKey, envValue] of Object.entries(serverConfig.env)) {
|
|
11088
11224
|
const isUrl = /^[a-z][a-z0-9+.-]*:\/\//i.test(envValue);
|
|
11089
|
-
if (!isUrl && envValue.includes("/") && !
|
|
11090
|
-
serverConfig.env[envKey] =
|
|
11225
|
+
if (!isUrl && envValue.includes("/") && !path6__namespace.isAbsolute(envValue)) {
|
|
11226
|
+
serverConfig.env[envKey] = path6__namespace.resolve(configDir, "..", envValue);
|
|
11091
11227
|
}
|
|
11092
11228
|
}
|
|
11093
11229
|
}
|
|
@@ -11154,7 +11290,7 @@ var JunoLogger = class {
|
|
|
11154
11290
|
enableConsoleLogging;
|
|
11155
11291
|
logFilePath;
|
|
11156
11292
|
constructor(options = {}) {
|
|
11157
|
-
this.logDirectory = options.logDirectory ||
|
|
11293
|
+
this.logDirectory = options.logDirectory || path6__namespace.default.join(process.cwd(), ".juno_task", "logs");
|
|
11158
11294
|
this.logLevel = options.logLevel || 1 /* INFO */;
|
|
11159
11295
|
this.enableConsoleLogging = options.enableConsoleLogging ?? true;
|
|
11160
11296
|
}
|
|
@@ -11169,7 +11305,7 @@ var JunoLogger = class {
|
|
|
11169
11305
|
const timeStr = timestamp[1].split("-")[0].substring(0, 6);
|
|
11170
11306
|
const fullTimestamp = `${dateStr}_${timeStr}`;
|
|
11171
11307
|
const logFileName = `subagent_loop_${subagent}_${fullTimestamp}.log`;
|
|
11172
|
-
this.logFilePath =
|
|
11308
|
+
this.logFilePath = path6__namespace.default.join(this.logDirectory, logFileName);
|
|
11173
11309
|
const header = `# Juno-Task TypeScript Log - Started ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
11174
11310
|
`;
|
|
11175
11311
|
await fs__default.default.writeFile(this.logFilePath, header);
|
|
@@ -11456,8 +11592,8 @@ var TerminalProgressWriter = class {
|
|
|
11456
11592
|
this.options.stream.write("\r\x1B[K");
|
|
11457
11593
|
if (typeof content === "string") {
|
|
11458
11594
|
this.options.stream.write(content);
|
|
11459
|
-
if (!content.endsWith("\n") && !content.endsWith(
|
|
11460
|
-
this.options.stream.write(
|
|
11595
|
+
if (!content.endsWith("\n") && !content.endsWith(os2.EOL)) {
|
|
11596
|
+
this.options.stream.write(os2.EOL);
|
|
11461
11597
|
}
|
|
11462
11598
|
} else {
|
|
11463
11599
|
console.error(content);
|
|
@@ -11465,8 +11601,8 @@ var TerminalProgressWriter = class {
|
|
|
11465
11601
|
} else {
|
|
11466
11602
|
if (typeof content === "string") {
|
|
11467
11603
|
this.options.stream.write(content);
|
|
11468
|
-
if (!content.endsWith("\n") && !content.endsWith(
|
|
11469
|
-
this.options.stream.write(
|
|
11604
|
+
if (!content.endsWith("\n") && !content.endsWith(os2.EOL)) {
|
|
11605
|
+
this.options.stream.write(os2.EOL);
|
|
11470
11606
|
}
|
|
11471
11607
|
} else {
|
|
11472
11608
|
console.error(content);
|
|
@@ -12039,8 +12175,8 @@ var JunoMCPClient = class {
|
|
|
12039
12175
|
`${serverName}`,
|
|
12040
12176
|
// Assume it's in PATH
|
|
12041
12177
|
`/usr/local/bin/${serverName}`,
|
|
12042
|
-
|
|
12043
|
-
|
|
12178
|
+
path6__namespace.default.resolve(os2__namespace.default.homedir(), `.local/bin/${serverName}`),
|
|
12179
|
+
path6__namespace.default.resolve(this.options.workingDirectory || process.cwd(), `${serverName}`)
|
|
12044
12180
|
];
|
|
12045
12181
|
for (const serverPath of possiblePaths) {
|
|
12046
12182
|
try {
|
|
@@ -13966,8 +14102,8 @@ var IOError = class extends SystemError {
|
|
|
13966
14102
|
};
|
|
13967
14103
|
var InvalidPathError = class extends SystemError {
|
|
13968
14104
|
code = "SYSTEM_INVALID_PATH" /* SYSTEM_INVALID_PATH */;
|
|
13969
|
-
constructor(
|
|
13970
|
-
let message = `Invalid path: ${
|
|
14105
|
+
constructor(path11, reason, options) {
|
|
14106
|
+
let message = `Invalid path: ${path11}`;
|
|
13971
14107
|
if (reason) {
|
|
13972
14108
|
message += ` (${reason})`;
|
|
13973
14109
|
}
|
|
@@ -13976,7 +14112,7 @@ var InvalidPathError = class extends SystemError {
|
|
|
13976
14112
|
context: {
|
|
13977
14113
|
...options?.context,
|
|
13978
14114
|
metadata: {
|
|
13979
|
-
filePath:
|
|
14115
|
+
filePath: path11,
|
|
13980
14116
|
reason,
|
|
13981
14117
|
...options?.context?.metadata
|
|
13982
14118
|
},
|