juno-code 1.0.41 → 1.0.43
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 +4245 -3670
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +4247 -3671
- 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/install_requirements.sh +3 -4
- package/dist/templates/scripts/kanban.sh +85 -3
- package/dist/templates/scripts/run_until_completion.sh +190 -14
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import * as
|
|
3
|
-
import
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
2
|
+
import * as os2 from 'os';
|
|
3
|
+
import os2__default, { totalmem, freemem, EOL } from 'os';
|
|
4
|
+
import * as path6 from 'path';
|
|
5
|
+
import path6__default from 'path';
|
|
6
6
|
import * as process2 from 'process';
|
|
7
7
|
import * as nodeFs from 'fs';
|
|
8
8
|
import { promises } from 'fs';
|
|
@@ -18,11 +18,11 @@ import { EventEmitter } from 'events';
|
|
|
18
18
|
import { execa } from 'execa';
|
|
19
19
|
import Table from 'cli-table3';
|
|
20
20
|
import supportsColor from 'supports-color';
|
|
21
|
+
import { spawn } from 'child_process';
|
|
21
22
|
import { v4 } from 'uuid';
|
|
22
23
|
import { PerformanceObserver, performance } from 'perf_hooks';
|
|
23
24
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
24
25
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
25
|
-
import { spawn } from 'child_process';
|
|
26
26
|
|
|
27
27
|
var __defProp = Object.defineProperty;
|
|
28
28
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -44,7 +44,7 @@ var __export = (target, all) => {
|
|
|
44
44
|
var version;
|
|
45
45
|
var init_version = __esm({
|
|
46
46
|
"src/version.ts"() {
|
|
47
|
-
version = "1.0.
|
|
47
|
+
version = "1.0.43";
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
function isHeadlessEnvironment() {
|
|
@@ -175,14 +175,14 @@ function isInDocker() {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
function getPlatform() {
|
|
178
|
-
return
|
|
178
|
+
return os2.platform();
|
|
179
179
|
}
|
|
180
180
|
function getArchitecture() {
|
|
181
|
-
return
|
|
181
|
+
return os2.arch();
|
|
182
182
|
}
|
|
183
183
|
function getShell() {
|
|
184
184
|
const shell = process2.env.SHELL || process2.env.ComSpec || "";
|
|
185
|
-
const shellName =
|
|
185
|
+
const shellName = path6.basename(shell).toLowerCase();
|
|
186
186
|
if (shellName.includes("bash")) return "bash";
|
|
187
187
|
if (shellName.includes("zsh")) return "zsh";
|
|
188
188
|
if (shellName.includes("fish")) return "fish";
|
|
@@ -191,21 +191,21 @@ function getShell() {
|
|
|
191
191
|
return "unknown";
|
|
192
192
|
}
|
|
193
193
|
function getHomeDirectory() {
|
|
194
|
-
return
|
|
194
|
+
return os2.homedir();
|
|
195
195
|
}
|
|
196
196
|
function getTempDirectory() {
|
|
197
|
-
return
|
|
197
|
+
return os2.tmpdir();
|
|
198
198
|
}
|
|
199
199
|
function getConfigDirectory(appName = "juno-task") {
|
|
200
200
|
const platform2 = getPlatform();
|
|
201
201
|
const home = getHomeDirectory();
|
|
202
202
|
switch (platform2) {
|
|
203
203
|
case "win32":
|
|
204
|
-
return
|
|
204
|
+
return path6.join(process2.env.APPDATA || path6.join(home, "AppData", "Roaming"), appName);
|
|
205
205
|
case "darwin":
|
|
206
|
-
return
|
|
206
|
+
return path6.join(home, "Library", "Application Support", appName);
|
|
207
207
|
default:
|
|
208
|
-
return
|
|
208
|
+
return path6.join(process2.env.XDG_CONFIG_HOME || path6.join(home, ".config"), appName);
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
function getDataDirectory(appName = "juno-task") {
|
|
@@ -213,11 +213,11 @@ function getDataDirectory(appName = "juno-task") {
|
|
|
213
213
|
const home = getHomeDirectory();
|
|
214
214
|
switch (platform2) {
|
|
215
215
|
case "win32":
|
|
216
|
-
return
|
|
216
|
+
return path6.join(process2.env.LOCALAPPDATA || path6.join(home, "AppData", "Local"), appName);
|
|
217
217
|
case "darwin":
|
|
218
|
-
return
|
|
218
|
+
return path6.join(home, "Library", "Application Support", appName);
|
|
219
219
|
default:
|
|
220
|
-
return
|
|
220
|
+
return path6.join(process2.env.XDG_DATA_HOME || path6.join(home, ".local", "share"), appName);
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
function getCacheDirectory(appName = "juno-task") {
|
|
@@ -225,11 +225,11 @@ function getCacheDirectory(appName = "juno-task") {
|
|
|
225
225
|
const home = getHomeDirectory();
|
|
226
226
|
switch (platform2) {
|
|
227
227
|
case "win32":
|
|
228
|
-
return
|
|
228
|
+
return path6.join(process2.env.TEMP || path6.join(home, "AppData", "Local", "Temp"), appName);
|
|
229
229
|
case "darwin":
|
|
230
|
-
return
|
|
230
|
+
return path6.join(home, "Library", "Caches", appName);
|
|
231
231
|
default:
|
|
232
|
-
return
|
|
232
|
+
return path6.join(process2.env.XDG_CACHE_HOME || path6.join(home, ".cache"), appName);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
async function createDirectoryIfNotExists(dirPath) {
|
|
@@ -279,26 +279,26 @@ async function findMCPServerPath(serverName = "mcp-server") {
|
|
|
279
279
|
const platform2 = getPlatform();
|
|
280
280
|
const searchPaths = [];
|
|
281
281
|
const pathEnv = process2.env.PATH || "";
|
|
282
|
-
searchPaths.push(...pathEnv.split(
|
|
282
|
+
searchPaths.push(...pathEnv.split(path6.delimiter));
|
|
283
283
|
if (platform2 === "win32") {
|
|
284
284
|
searchPaths.push(
|
|
285
285
|
"C:\\Program Files\\MCP\\bin",
|
|
286
286
|
"C:\\Program Files (x86)\\MCP\\bin",
|
|
287
|
-
|
|
287
|
+
path6.join(process2.env.LOCALAPPDATA || "", "Programs", "MCP", "bin")
|
|
288
288
|
);
|
|
289
289
|
} else {
|
|
290
290
|
searchPaths.push(
|
|
291
291
|
"/usr/local/bin",
|
|
292
292
|
"/usr/bin",
|
|
293
293
|
"/opt/mcp/bin",
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
path6.join(getHomeDirectory(), ".local", "bin"),
|
|
295
|
+
path6.join(getHomeDirectory(), "bin")
|
|
296
296
|
);
|
|
297
297
|
}
|
|
298
298
|
const executable = platform2 === "win32" ? `${serverName}.exe` : serverName;
|
|
299
299
|
for (const searchPath of searchPaths) {
|
|
300
300
|
if (!searchPath) continue;
|
|
301
|
-
const fullPath =
|
|
301
|
+
const fullPath = path6.join(searchPath, executable);
|
|
302
302
|
try {
|
|
303
303
|
await promises.access(fullPath, promises.constants.F_OK | promises.constants.X_OK);
|
|
304
304
|
return fullPath;
|
|
@@ -4020,6 +4020,13 @@ var DEFAULT_HOOKS = {
|
|
|
4020
4020
|
// Use for: final cleanup, notifications, reports, post-run actions
|
|
4021
4021
|
END_RUN: {
|
|
4022
4022
|
commands: []
|
|
4023
|
+
},
|
|
4024
|
+
// Executes when stale iteration is detected in run_until_completion.sh
|
|
4025
|
+
// Use for: alerts, notifications, logging when agent is not making progress
|
|
4026
|
+
ON_STALE: {
|
|
4027
|
+
commands: [
|
|
4028
|
+
`./.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`
|
|
4029
|
+
]
|
|
4023
4030
|
}
|
|
4024
4031
|
};
|
|
4025
4032
|
function getDefaultHooks() {
|
|
@@ -4073,9 +4080,9 @@ var ProfileManager = class {
|
|
|
4073
4080
|
profileCache = /* @__PURE__ */ new Map();
|
|
4074
4081
|
activeProfile = null;
|
|
4075
4082
|
constructor(configDir) {
|
|
4076
|
-
this.profilesDir =
|
|
4077
|
-
this.activeProfileFile =
|
|
4078
|
-
this.defaultConfigFile =
|
|
4083
|
+
this.profilesDir = path6.join(configDir, "profiles");
|
|
4084
|
+
this.activeProfileFile = path6.join(configDir, "active-profile.txt");
|
|
4085
|
+
this.defaultConfigFile = path6.join(configDir, "config.json");
|
|
4079
4086
|
}
|
|
4080
4087
|
/**
|
|
4081
4088
|
* Initialize the profile system
|
|
@@ -4182,7 +4189,7 @@ var ProfileManager = class {
|
|
|
4182
4189
|
profile,
|
|
4183
4190
|
version: "1.0.0"
|
|
4184
4191
|
};
|
|
4185
|
-
const profilePath =
|
|
4192
|
+
const profilePath = path6.join(this.profilesDir, `${profile.name}.json`);
|
|
4186
4193
|
await promises.writeFile(profilePath, JSON.stringify(storage, null, 2), "utf-8");
|
|
4187
4194
|
this.profileCache.delete(profile.name);
|
|
4188
4195
|
}
|
|
@@ -4335,7 +4342,7 @@ var ProfileManager = class {
|
|
|
4335
4342
|
async findProfileFile(name) {
|
|
4336
4343
|
const extensions = [".json", ".yaml", ".yml"];
|
|
4337
4344
|
for (const ext of extensions) {
|
|
4338
|
-
const filePath =
|
|
4345
|
+
const filePath = path6.join(this.profilesDir, `${name}${ext}`);
|
|
4339
4346
|
try {
|
|
4340
4347
|
await promises.access(filePath);
|
|
4341
4348
|
return filePath;
|
|
@@ -4404,7 +4411,7 @@ var ProfileManager = class {
|
|
|
4404
4411
|
headlessMode: false,
|
|
4405
4412
|
// Paths
|
|
4406
4413
|
workingDirectory: process.cwd(),
|
|
4407
|
-
sessionDirectory:
|
|
4414
|
+
sessionDirectory: path6.join(process.cwd(), ".juno_task", "sessions")
|
|
4408
4415
|
};
|
|
4409
4416
|
}
|
|
4410
4417
|
};
|
|
@@ -4456,6 +4463,8 @@ var ENV_VAR_MAPPING = {
|
|
|
4456
4463
|
JUNO_CODE_MCP_SERVER_NAME: "mcpServerName",
|
|
4457
4464
|
// Hook settings
|
|
4458
4465
|
JUNO_CODE_HOOK_COMMAND_TIMEOUT: "hookCommandTimeout",
|
|
4466
|
+
// Quota/hourly limit settings
|
|
4467
|
+
JUNO_CODE_ON_HOURLY_LIMIT: "onHourlyLimit",
|
|
4459
4468
|
// TUI settings
|
|
4460
4469
|
JUNO_CODE_INTERACTIVE: "interactive",
|
|
4461
4470
|
JUNO_CODE_HEADLESS_MODE: "headlessMode",
|
|
@@ -4481,6 +4490,8 @@ var LEGACY_ENV_VAR_MAPPING = {
|
|
|
4481
4490
|
JUNO_TASK_MCP_SERVER_NAME: "mcpServerName",
|
|
4482
4491
|
// Hook settings
|
|
4483
4492
|
JUNO_TASK_HOOK_COMMAND_TIMEOUT: "hookCommandTimeout",
|
|
4493
|
+
// Quota/hourly limit settings
|
|
4494
|
+
JUNO_TASK_ON_HOURLY_LIMIT: "onHourlyLimit",
|
|
4484
4495
|
// TUI settings
|
|
4485
4496
|
JUNO_TASK_INTERACTIVE: "interactive",
|
|
4486
4497
|
JUNO_TASK_HEADLESS_MODE: "headlessMode",
|
|
@@ -4491,7 +4502,8 @@ var LEGACY_ENV_VAR_MAPPING = {
|
|
|
4491
4502
|
var SubagentTypeSchema = z.enum(["claude", "cursor", "codex", "gemini"]);
|
|
4492
4503
|
var BackendTypeSchema = z.enum(["mcp", "shell"]);
|
|
4493
4504
|
var LogLevelSchema = z.enum(["error", "warn", "info", "debug", "trace"]);
|
|
4494
|
-
var
|
|
4505
|
+
var OnHourlyLimitSchema = z.enum(["wait", "raise"]);
|
|
4506
|
+
var HookTypeSchema = z.enum(["START_RUN", "START_ITERATION", "END_ITERATION", "END_RUN", "ON_STALE"]);
|
|
4495
4507
|
var HookSchema = z.object({
|
|
4496
4508
|
commands: z.array(z.string()).describe("List of bash commands to execute for this hook")
|
|
4497
4509
|
});
|
|
@@ -4514,6 +4526,8 @@ var JunoTaskConfigSchema = z.object({
|
|
|
4514
4526
|
mcpServerName: z.string().optional().describe('Named MCP server to connect to (e.g., "roundtable-ai")'),
|
|
4515
4527
|
// Hook settings
|
|
4516
4528
|
hookCommandTimeout: z.number().int().min(1e3).max(36e5).optional().describe("Timeout for individual hook commands in milliseconds (default: 300000 = 5 minutes)"),
|
|
4529
|
+
// Quota/hourly limit settings
|
|
4530
|
+
onHourlyLimit: OnHourlyLimitSchema.describe('Behavior when Claude hourly quota limit is reached: "wait" to sleep until reset, "raise" to exit immediately'),
|
|
4517
4531
|
// TUI settings
|
|
4518
4532
|
interactive: z.boolean().describe("Enable interactive mode"),
|
|
4519
4533
|
headlessMode: z.boolean().describe("Enable headless mode (no TUI)"),
|
|
@@ -4532,18 +4546,21 @@ var DEFAULT_CONFIG = {
|
|
|
4532
4546
|
logLevel: "info",
|
|
4533
4547
|
verbose: false,
|
|
4534
4548
|
quiet: false,
|
|
4535
|
-
// MCP settings
|
|
4536
|
-
mcpTimeout:
|
|
4537
|
-
//
|
|
4549
|
+
// MCP settings (also used by shell backend)
|
|
4550
|
+
mcpTimeout: 432e5,
|
|
4551
|
+
// 43200 seconds (12 hours) - default for long-running shell backend operations
|
|
4538
4552
|
mcpRetries: 3,
|
|
4539
4553
|
mcpServerName: "roundtable-ai",
|
|
4540
4554
|
// Default to roundtable-ai server
|
|
4555
|
+
// Quota/hourly limit settings
|
|
4556
|
+
onHourlyLimit: "raise",
|
|
4557
|
+
// Default to exit immediately when hourly limit is reached
|
|
4541
4558
|
// TUI settings
|
|
4542
4559
|
interactive: true,
|
|
4543
4560
|
headlessMode: false,
|
|
4544
4561
|
// Paths
|
|
4545
4562
|
workingDirectory: process.cwd(),
|
|
4546
|
-
sessionDirectory:
|
|
4563
|
+
sessionDirectory: path6.join(process.cwd(), ".juno_task"),
|
|
4547
4564
|
// Hooks configuration - populated with default hooks template
|
|
4548
4565
|
hooks: getDefaultHooks()
|
|
4549
4566
|
};
|
|
@@ -4557,10 +4574,10 @@ var GLOBAL_CONFIG_FILE_NAMES = [
|
|
|
4557
4574
|
];
|
|
4558
4575
|
var PROJECT_CONFIG_FILE = ".juno_task/config.json";
|
|
4559
4576
|
function resolvePath(inputPath, basePath = process.cwd()) {
|
|
4560
|
-
if (
|
|
4577
|
+
if (path6.isAbsolute(inputPath)) {
|
|
4561
4578
|
return inputPath;
|
|
4562
4579
|
}
|
|
4563
|
-
return
|
|
4580
|
+
return path6.resolve(basePath, inputPath);
|
|
4564
4581
|
}
|
|
4565
4582
|
function parseEnvValue(value) {
|
|
4566
4583
|
if (value === "") return value;
|
|
@@ -4615,7 +4632,7 @@ async function loadPackageJsonConfig(filePath) {
|
|
|
4615
4632
|
}
|
|
4616
4633
|
}
|
|
4617
4634
|
function getConfigFileFormat(filePath) {
|
|
4618
|
-
const ext =
|
|
4635
|
+
const ext = path6.extname(filePath).toLowerCase();
|
|
4619
4636
|
switch (ext) {
|
|
4620
4637
|
case ".json":
|
|
4621
4638
|
return "json";
|
|
@@ -4641,7 +4658,7 @@ async function loadConfigFromFile(filePath) {
|
|
|
4641
4658
|
}
|
|
4642
4659
|
switch (format) {
|
|
4643
4660
|
case "json":
|
|
4644
|
-
if (
|
|
4661
|
+
if (path6.basename(filePath) === "package.json") {
|
|
4645
4662
|
return loadPackageJsonConfig(resolvedPath);
|
|
4646
4663
|
}
|
|
4647
4664
|
return loadJsonConfig(resolvedPath);
|
|
@@ -4656,7 +4673,7 @@ async function loadConfigFromFile(filePath) {
|
|
|
4656
4673
|
}
|
|
4657
4674
|
}
|
|
4658
4675
|
async function findProjectConfigFile(searchDir = process.cwd()) {
|
|
4659
|
-
const filePath =
|
|
4676
|
+
const filePath = path6.join(searchDir, PROJECT_CONFIG_FILE);
|
|
4660
4677
|
try {
|
|
4661
4678
|
await promises.access(filePath, nodeFs.constants.R_OK);
|
|
4662
4679
|
return filePath;
|
|
@@ -4666,7 +4683,7 @@ async function findProjectConfigFile(searchDir = process.cwd()) {
|
|
|
4666
4683
|
}
|
|
4667
4684
|
async function findGlobalConfigFile(searchDir = process.cwd()) {
|
|
4668
4685
|
for (const fileName of GLOBAL_CONFIG_FILE_NAMES) {
|
|
4669
|
-
const filePath =
|
|
4686
|
+
const filePath = path6.join(searchDir, fileName);
|
|
4670
4687
|
try {
|
|
4671
4688
|
await promises.access(filePath, nodeFs.constants.R_OK);
|
|
4672
4689
|
return filePath;
|
|
@@ -4840,8 +4857,8 @@ function validateConfig(config) {
|
|
|
4840
4857
|
}
|
|
4841
4858
|
async function ensureHooksConfig(baseDir) {
|
|
4842
4859
|
try {
|
|
4843
|
-
const configDir =
|
|
4844
|
-
const configPath =
|
|
4860
|
+
const configDir = path6.join(baseDir, ".juno_task");
|
|
4861
|
+
const configPath = path6.join(configDir, "config.json");
|
|
4845
4862
|
await fs.ensureDir(configDir);
|
|
4846
4863
|
const configExists = await fs.pathExists(configPath);
|
|
4847
4864
|
const allHookTypes = getDefaultHooks();
|
|
@@ -6776,7 +6793,7 @@ async function executeHooks(hookTypes, hooks, context = {}, options = {}) {
|
|
|
6776
6793
|
function validateHooksConfig(hooks) {
|
|
6777
6794
|
const issues = [];
|
|
6778
6795
|
const warnings = [];
|
|
6779
|
-
const validHookTypes = ["START_RUN", "START_ITERATION", "END_ITERATION", "END_RUN"];
|
|
6796
|
+
const validHookTypes = ["START_RUN", "START_ITERATION", "END_ITERATION", "END_RUN", "ON_STALE"];
|
|
6780
6797
|
for (const [hookType, hook] of Object.entries(hooks)) {
|
|
6781
6798
|
if (!validHookTypes.includes(hookType)) {
|
|
6782
6799
|
warnings.push(`Unknown hook type: ${hookType}. Valid types are: ${validHookTypes.join(", ")}`);
|
|
@@ -6820,6 +6837,20 @@ function validateHooksConfig(hooks) {
|
|
|
6820
6837
|
};
|
|
6821
6838
|
}
|
|
6822
6839
|
|
|
6840
|
+
// src/core/backends/shell-backend.ts
|
|
6841
|
+
init_version();
|
|
6842
|
+
function formatDuration(ms) {
|
|
6843
|
+
const totalSeconds = Math.ceil(ms / 1e3);
|
|
6844
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
6845
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
6846
|
+
const seconds = totalSeconds % 60;
|
|
6847
|
+
const parts = [];
|
|
6848
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
6849
|
+
if (minutes > 0) parts.push(`${minutes}m`);
|
|
6850
|
+
if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
|
|
6851
|
+
return parts.join(" ");
|
|
6852
|
+
}
|
|
6853
|
+
|
|
6823
6854
|
// src/core/engine.ts
|
|
6824
6855
|
var ExecutionStatus = /* @__PURE__ */ ((ExecutionStatus2) => {
|
|
6825
6856
|
ExecutionStatus2["PENDING"] = "pending";
|
|
@@ -7119,6 +7150,8 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
7119
7150
|
totalProgressEvents: 0,
|
|
7120
7151
|
rateLimitEncounters: 0,
|
|
7121
7152
|
rateLimitWaitTime: 0,
|
|
7153
|
+
quotaLimitEncounters: 0,
|
|
7154
|
+
quotaLimitWaitTime: 0,
|
|
7122
7155
|
errorBreakdown: {},
|
|
7123
7156
|
performanceMetrics: {
|
|
7124
7157
|
cpuUsage: 0,
|
|
@@ -7223,7 +7256,13 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
7223
7256
|
while (!this.shouldStopIterating(context, iterationNumber)) {
|
|
7224
7257
|
this.checkAbortSignal(context);
|
|
7225
7258
|
try {
|
|
7226
|
-
await this.executeIteration(context, iterationNumber);
|
|
7259
|
+
const quotaLimitInfo = await this.executeIteration(context, iterationNumber);
|
|
7260
|
+
if (quotaLimitInfo?.detected) {
|
|
7261
|
+
const shouldRetry = await this.handleQuotaLimit(context, quotaLimitInfo);
|
|
7262
|
+
if (shouldRetry) {
|
|
7263
|
+
continue;
|
|
7264
|
+
}
|
|
7265
|
+
}
|
|
7227
7266
|
iterationNumber++;
|
|
7228
7267
|
} catch (error) {
|
|
7229
7268
|
if (error instanceof MCPRateLimitError) {
|
|
@@ -7241,6 +7280,7 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
7241
7280
|
}
|
|
7242
7281
|
/**
|
|
7243
7282
|
* Execute a single iteration
|
|
7283
|
+
* @returns QuotaLimitInfo if a quota limit was detected, null otherwise
|
|
7244
7284
|
*/
|
|
7245
7285
|
async executeIteration(context, iterationNumber) {
|
|
7246
7286
|
const iterationStart = /* @__PURE__ */ new Date();
|
|
@@ -7334,6 +7374,8 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
7334
7374
|
} catch (error) {
|
|
7335
7375
|
engineLogger.warn("Hook END_ITERATION failed", { error, iterationNumber });
|
|
7336
7376
|
}
|
|
7377
|
+
const quotaLimitInfo = this.extractQuotaLimitInfo(toolResult);
|
|
7378
|
+
return quotaLimitInfo;
|
|
7337
7379
|
} catch (error) {
|
|
7338
7380
|
const iterationEnd = /* @__PURE__ */ new Date();
|
|
7339
7381
|
const duration = iterationEnd.getTime() - iterationStart.getTime();
|
|
@@ -7427,6 +7469,100 @@ var ExecutionEngine = class extends EventEmitter {
|
|
|
7427
7469
|
}
|
|
7428
7470
|
return 6e4;
|
|
7429
7471
|
}
|
|
7472
|
+
/**
|
|
7473
|
+
* Handle Claude quota limit with automatic sleep and retry
|
|
7474
|
+
* @returns true if we should retry the iteration, false otherwise
|
|
7475
|
+
*/
|
|
7476
|
+
async handleQuotaLimit(context, quotaInfo) {
|
|
7477
|
+
if (!quotaInfo.detected || !quotaInfo.sleepDurationMs) {
|
|
7478
|
+
return false;
|
|
7479
|
+
}
|
|
7480
|
+
context.statistics.quotaLimitEncounters++;
|
|
7481
|
+
const onHourlyLimit = this.engineConfig.config.onHourlyLimit || "raise";
|
|
7482
|
+
if (onHourlyLimit === "raise") {
|
|
7483
|
+
const resetTimeStr2 = quotaInfo.resetTime ? quotaInfo.resetTime.toLocaleTimeString("en-US", {
|
|
7484
|
+
hour: "numeric",
|
|
7485
|
+
minute: "2-digit",
|
|
7486
|
+
hour12: true,
|
|
7487
|
+
timeZoneName: "short"
|
|
7488
|
+
}) : "unknown";
|
|
7489
|
+
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`);
|
|
7490
|
+
engineLogger.info(`\u2551 Claude Quota Limit Reached \u2551`);
|
|
7491
|
+
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`);
|
|
7492
|
+
engineLogger.info(`\u2551 Quota resets at: ${resetTimeStr2.padEnd(44)}\u2551`);
|
|
7493
|
+
engineLogger.info(`\u2551 Behavior: raise (exit immediately) \u2551`);
|
|
7494
|
+
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`);
|
|
7495
|
+
engineLogger.info(`\u2551 To auto-wait instead, use: --on-hourly-limit wait \u2551`);
|
|
7496
|
+
engineLogger.info(`\u2551 Or set: JUNO_CODE_ON_HOURLY_LIMIT=wait \u2551`);
|
|
7497
|
+
engineLogger.info(`\u2551 Or in config.json: { "onHourlyLimit": "wait" } \u2551`);
|
|
7498
|
+
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`);
|
|
7499
|
+
this.emit("quota-limit:raise", { context, quotaInfo });
|
|
7500
|
+
throw new Error(`Claude quota limit reached. Quota resets at ${resetTimeStr2}. Use --on-hourly-limit wait to auto-retry.`);
|
|
7501
|
+
}
|
|
7502
|
+
const waitTimeMs = quotaInfo.sleepDurationMs;
|
|
7503
|
+
const maxWaitTimeMs = 12 * 60 * 60 * 1e3;
|
|
7504
|
+
if (waitTimeMs > maxWaitTimeMs) {
|
|
7505
|
+
engineLogger.warn(`Quota limit wait time (${formatDuration(waitTimeMs)}) exceeds maximum allowed (12 hours). Will not auto-retry.`);
|
|
7506
|
+
return false;
|
|
7507
|
+
}
|
|
7508
|
+
context.statistics.quotaLimitWaitTime += waitTimeMs;
|
|
7509
|
+
const resetTimeStr = quotaInfo.resetTime ? quotaInfo.resetTime.toLocaleTimeString("en-US", {
|
|
7510
|
+
hour: "numeric",
|
|
7511
|
+
minute: "2-digit",
|
|
7512
|
+
hour12: true,
|
|
7513
|
+
timeZoneName: "short"
|
|
7514
|
+
}) : "unknown";
|
|
7515
|
+
const durationStr = formatDuration(waitTimeMs);
|
|
7516
|
+
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`);
|
|
7517
|
+
engineLogger.info(`\u2551 Claude Quota Limit Reached \u2551`);
|
|
7518
|
+
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`);
|
|
7519
|
+
engineLogger.info(`\u2551 Quota resets at: ${resetTimeStr.padEnd(44)}\u2551`);
|
|
7520
|
+
engineLogger.info(`\u2551 Sleeping for: ${durationStr.padEnd(44)}\u2551`);
|
|
7521
|
+
if (quotaInfo.timezone) {
|
|
7522
|
+
engineLogger.info(`\u2551 Timezone: ${quotaInfo.timezone.padEnd(44)}\u2551`);
|
|
7523
|
+
}
|
|
7524
|
+
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`);
|
|
7525
|
+
this.emit("quota-limit:start", { context, quotaInfo, waitTimeMs });
|
|
7526
|
+
await this.sleepWithProgress(waitTimeMs, (remaining) => {
|
|
7527
|
+
const remainingStr = formatDuration(remaining);
|
|
7528
|
+
engineLogger.info(`[Quota Wait] ${remainingStr} remaining until retry...`);
|
|
7529
|
+
});
|
|
7530
|
+
this.emit("quota-limit:end", { context });
|
|
7531
|
+
engineLogger.info(`Quota limit wait complete. Resuming execution...`);
|
|
7532
|
+
return true;
|
|
7533
|
+
}
|
|
7534
|
+
/**
|
|
7535
|
+
* Sleep with periodic progress updates
|
|
7536
|
+
*/
|
|
7537
|
+
async sleepWithProgress(totalMs, onProgress) {
|
|
7538
|
+
const updateIntervalMs = 6e4;
|
|
7539
|
+
let remaining = totalMs;
|
|
7540
|
+
while (remaining > 0) {
|
|
7541
|
+
const sleepTime = Math.min(remaining, updateIntervalMs);
|
|
7542
|
+
await this.sleep(sleepTime);
|
|
7543
|
+
remaining -= sleepTime;
|
|
7544
|
+
if (remaining > 0) {
|
|
7545
|
+
onProgress(remaining);
|
|
7546
|
+
}
|
|
7547
|
+
}
|
|
7548
|
+
}
|
|
7549
|
+
/**
|
|
7550
|
+
* Check if tool result indicates a quota limit error
|
|
7551
|
+
*/
|
|
7552
|
+
extractQuotaLimitInfo(toolResult) {
|
|
7553
|
+
const metadataQuotaInfo = toolResult.metadata?.quotaLimitInfo;
|
|
7554
|
+
if (metadataQuotaInfo?.detected) {
|
|
7555
|
+
return metadataQuotaInfo;
|
|
7556
|
+
}
|
|
7557
|
+
try {
|
|
7558
|
+
const content = typeof toolResult.content === "string" ? JSON.parse(toolResult.content) : toolResult.content;
|
|
7559
|
+
if (content?.quota_limit?.detected) {
|
|
7560
|
+
return content.quota_limit;
|
|
7561
|
+
}
|
|
7562
|
+
} catch {
|
|
7563
|
+
}
|
|
7564
|
+
return null;
|
|
7565
|
+
}
|
|
7430
7566
|
/**
|
|
7431
7567
|
* Handle iteration errors with recovery strategies
|
|
7432
7568
|
*/
|
|
@@ -7755,9 +7891,9 @@ var FileSessionStorage = class {
|
|
|
7755
7891
|
* @param baseDir - Base directory for session storage
|
|
7756
7892
|
*/
|
|
7757
7893
|
constructor(baseDir) {
|
|
7758
|
-
this.baseDir =
|
|
7759
|
-
this.sessionsDir =
|
|
7760
|
-
this.archiveDir =
|
|
7894
|
+
this.baseDir = path6.resolve(baseDir);
|
|
7895
|
+
this.sessionsDir = path6.join(this.baseDir, "sessions");
|
|
7896
|
+
this.archiveDir = path6.join(this.baseDir, "archive");
|
|
7761
7897
|
}
|
|
7762
7898
|
/**
|
|
7763
7899
|
* Initialize storage directories
|
|
@@ -7772,7 +7908,7 @@ var FileSessionStorage = class {
|
|
|
7772
7908
|
* @returns Full path to session file
|
|
7773
7909
|
*/
|
|
7774
7910
|
getSessionPath(sessionId) {
|
|
7775
|
-
return
|
|
7911
|
+
return path6.join(this.sessionsDir, `${sessionId}.json`);
|
|
7776
7912
|
}
|
|
7777
7913
|
/**
|
|
7778
7914
|
* Save session data to storage
|
|
@@ -7838,7 +7974,7 @@ var FileSessionStorage = class {
|
|
|
7838
7974
|
const sessions = [];
|
|
7839
7975
|
for (const file of sessionFiles) {
|
|
7840
7976
|
try {
|
|
7841
|
-
const sessionId =
|
|
7977
|
+
const sessionId = path6.basename(file, ".json");
|
|
7842
7978
|
const session = await this.loadSession(sessionId);
|
|
7843
7979
|
if (session) {
|
|
7844
7980
|
sessions.push(session.info);
|
|
@@ -7941,7 +8077,7 @@ var FileSessionStorage = class {
|
|
|
7941
8077
|
const session = await this.loadSession(sessionInfo.id);
|
|
7942
8078
|
if (!session) continue;
|
|
7943
8079
|
const archiveFileName = `${sessionInfo.id}_${sessionInfo.createdAt.toISOString().split("T")[0]}.json`;
|
|
7944
|
-
const archivePath =
|
|
8080
|
+
const archivePath = path6.join(this.archiveDir, archiveFileName);
|
|
7945
8081
|
if (options.includeData) {
|
|
7946
8082
|
await promises.writeFile(
|
|
7947
8083
|
archivePath,
|
|
@@ -9223,7 +9359,7 @@ var MetricsReporter = class {
|
|
|
9223
9359
|
default:
|
|
9224
9360
|
throw new Error(`Unsupported export format: ${options.format}`);
|
|
9225
9361
|
}
|
|
9226
|
-
await promises.mkdir(
|
|
9362
|
+
await promises.mkdir(path6.dirname(options.outputPath), { recursive: true });
|
|
9227
9363
|
await promises.writeFile(options.outputPath, exportData, "utf-8");
|
|
9228
9364
|
}
|
|
9229
9365
|
/**
|
|
@@ -9341,7 +9477,7 @@ var IterationsSchema = z.number().int("Iterations must be an integer").refine(
|
|
|
9341
9477
|
(value) => value === -1 || value > 0,
|
|
9342
9478
|
"Iterations must be a positive integer or -1 for infinite"
|
|
9343
9479
|
).transform((value) => value === -1 ? Infinity : value);
|
|
9344
|
-
var FilePathSchema = z.string().min(1, "File path cannot be empty").transform((value) =>
|
|
9480
|
+
var FilePathSchema = z.string().min(1, "File path cannot be empty").transform((value) => path6.resolve(value)).refine(async (filePath) => {
|
|
9345
9481
|
try {
|
|
9346
9482
|
const stats = await promises.stat(filePath);
|
|
9347
9483
|
return stats.isFile();
|
|
@@ -9349,7 +9485,7 @@ var FilePathSchema = z.string().min(1, "File path cannot be empty").transform((v
|
|
|
9349
9485
|
return false;
|
|
9350
9486
|
}
|
|
9351
9487
|
}, "File does not exist or is not accessible");
|
|
9352
|
-
var DirectoryPathSchema = z.string().min(1, "Directory path cannot be empty").transform((value) =>
|
|
9488
|
+
var DirectoryPathSchema = z.string().min(1, "Directory path cannot be empty").transform((value) => path6.resolve(value)).refine(async (dirPath) => {
|
|
9353
9489
|
try {
|
|
9354
9490
|
const stats = await promises.stat(dirPath);
|
|
9355
9491
|
return stats.isDirectory();
|
|
@@ -9505,7 +9641,7 @@ function isValidLogLevel(value) {
|
|
|
9505
9641
|
}
|
|
9506
9642
|
async function isValidPath(filePath, type = "file") {
|
|
9507
9643
|
try {
|
|
9508
|
-
const resolvedPath =
|
|
9644
|
+
const resolvedPath = path6.resolve(filePath);
|
|
9509
9645
|
const stats = await promises.stat(resolvedPath);
|
|
9510
9646
|
return type === "file" ? stats.isFile() : stats.isDirectory();
|
|
9511
9647
|
} catch {
|
|
@@ -9526,7 +9662,7 @@ function sanitizeFilePath(filePath) {
|
|
|
9526
9662
|
if (!cleaned) {
|
|
9527
9663
|
throw new ValidationError("File path cannot be empty after sanitization", "filePath", filePath);
|
|
9528
9664
|
}
|
|
9529
|
-
return
|
|
9665
|
+
return path6.resolve(cleaned);
|
|
9530
9666
|
}
|
|
9531
9667
|
function sanitizeGitUrl(url) {
|
|
9532
9668
|
if (typeof url !== "string") {
|
|
@@ -9657,8 +9793,8 @@ function validateCommandOptions(options) {
|
|
|
9657
9793
|
} catch (error) {
|
|
9658
9794
|
if (error instanceof z.ZodError) {
|
|
9659
9795
|
const errors = error.errors.map((err) => {
|
|
9660
|
-
const
|
|
9661
|
-
return `--${
|
|
9796
|
+
const path11 = err.path.length > 0 ? err.path.join(".") : "option";
|
|
9797
|
+
return `--${path11}: ${err.message}`;
|
|
9662
9798
|
});
|
|
9663
9799
|
const suggestions = [
|
|
9664
9800
|
"Check command line option syntax",
|
|
@@ -10959,7 +11095,7 @@ var MCPConfigLoader = class {
|
|
|
10959
11095
|
const configContent = await fs.readFile(configPath, "utf-8");
|
|
10960
11096
|
const config = JSON.parse(configContent);
|
|
10961
11097
|
this.validateConfig(config);
|
|
10962
|
-
const resolvedConfig = this.resolveConfigPaths(config,
|
|
11098
|
+
const resolvedConfig = this.resolveConfigPaths(config, path6.dirname(configPath));
|
|
10963
11099
|
this.configCache.set(configPath, resolvedConfig);
|
|
10964
11100
|
this.lastLoadTime.set(configPath, Date.now());
|
|
10965
11101
|
return resolvedConfig;
|
|
@@ -10974,14 +11110,14 @@ var MCPConfigLoader = class {
|
|
|
10974
11110
|
* Find the mcp.json configuration file
|
|
10975
11111
|
*/
|
|
10976
11112
|
static async findConfigFile(startDir) {
|
|
10977
|
-
let currentDir =
|
|
10978
|
-
const rootDir =
|
|
11113
|
+
let currentDir = path6.resolve(startDir);
|
|
11114
|
+
const rootDir = path6.parse(currentDir).root;
|
|
10979
11115
|
while (currentDir !== rootDir) {
|
|
10980
|
-
const configPath =
|
|
11116
|
+
const configPath = path6.join(currentDir, ".juno_task", "mcp.json");
|
|
10981
11117
|
if (await fs.pathExists(configPath)) {
|
|
10982
11118
|
return configPath;
|
|
10983
11119
|
}
|
|
10984
|
-
currentDir =
|
|
11120
|
+
currentDir = path6.dirname(currentDir);
|
|
10985
11121
|
}
|
|
10986
11122
|
throw new MCPConnectionError(
|
|
10987
11123
|
`MCP configuration not found. Please run 'juno-task init' to create .juno_task/mcp.json`
|
|
@@ -11047,16 +11183,16 @@ var MCPConfigLoader = class {
|
|
|
11047
11183
|
const resolvedConfig = JSON.parse(JSON.stringify(config));
|
|
11048
11184
|
for (const [serverName, serverConfig] of Object.entries(resolvedConfig.mcpServers)) {
|
|
11049
11185
|
serverConfig.args = serverConfig.args.map((arg) => {
|
|
11050
|
-
if (arg.includes("/") && !
|
|
11051
|
-
return
|
|
11186
|
+
if (arg.includes("/") && !path6.isAbsolute(arg)) {
|
|
11187
|
+
return path6.resolve(configDir, "..", arg);
|
|
11052
11188
|
}
|
|
11053
11189
|
return arg;
|
|
11054
11190
|
});
|
|
11055
11191
|
if (serverConfig.env) {
|
|
11056
11192
|
for (const [envKey, envValue] of Object.entries(serverConfig.env)) {
|
|
11057
11193
|
const isUrl = /^[a-z][a-z0-9+.-]*:\/\//i.test(envValue);
|
|
11058
|
-
if (!isUrl && envValue.includes("/") && !
|
|
11059
|
-
serverConfig.env[envKey] =
|
|
11194
|
+
if (!isUrl && envValue.includes("/") && !path6.isAbsolute(envValue)) {
|
|
11195
|
+
serverConfig.env[envKey] = path6.resolve(configDir, "..", envValue);
|
|
11060
11196
|
}
|
|
11061
11197
|
}
|
|
11062
11198
|
}
|
|
@@ -11123,7 +11259,7 @@ var JunoLogger = class {
|
|
|
11123
11259
|
enableConsoleLogging;
|
|
11124
11260
|
logFilePath;
|
|
11125
11261
|
constructor(options = {}) {
|
|
11126
|
-
this.logDirectory = options.logDirectory ||
|
|
11262
|
+
this.logDirectory = options.logDirectory || path6__default.join(process.cwd(), ".juno_task", "logs");
|
|
11127
11263
|
this.logLevel = options.logLevel || 1 /* INFO */;
|
|
11128
11264
|
this.enableConsoleLogging = options.enableConsoleLogging ?? true;
|
|
11129
11265
|
}
|
|
@@ -11138,7 +11274,7 @@ var JunoLogger = class {
|
|
|
11138
11274
|
const timeStr = timestamp[1].split("-")[0].substring(0, 6);
|
|
11139
11275
|
const fullTimestamp = `${dateStr}_${timeStr}`;
|
|
11140
11276
|
const logFileName = `subagent_loop_${subagent}_${fullTimestamp}.log`;
|
|
11141
|
-
this.logFilePath =
|
|
11277
|
+
this.logFilePath = path6__default.join(this.logDirectory, logFileName);
|
|
11142
11278
|
const header = `# Juno-Task TypeScript Log - Started ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
11143
11279
|
`;
|
|
11144
11280
|
await fs.writeFile(this.logFilePath, header);
|
|
@@ -12008,8 +12144,8 @@ var JunoMCPClient = class {
|
|
|
12008
12144
|
`${serverName}`,
|
|
12009
12145
|
// Assume it's in PATH
|
|
12010
12146
|
`/usr/local/bin/${serverName}`,
|
|
12011
|
-
|
|
12012
|
-
|
|
12147
|
+
path6__default.resolve(os2__default.homedir(), `.local/bin/${serverName}`),
|
|
12148
|
+
path6__default.resolve(this.options.workingDirectory || process.cwd(), `${serverName}`)
|
|
12013
12149
|
];
|
|
12014
12150
|
for (const serverPath of possiblePaths) {
|
|
12015
12151
|
try {
|
|
@@ -13935,8 +14071,8 @@ var IOError = class extends SystemError {
|
|
|
13935
14071
|
};
|
|
13936
14072
|
var InvalidPathError = class extends SystemError {
|
|
13937
14073
|
code = "SYSTEM_INVALID_PATH" /* SYSTEM_INVALID_PATH */;
|
|
13938
|
-
constructor(
|
|
13939
|
-
let message = `Invalid path: ${
|
|
14074
|
+
constructor(path11, reason, options) {
|
|
14075
|
+
let message = `Invalid path: ${path11}`;
|
|
13940
14076
|
if (reason) {
|
|
13941
14077
|
message += ` (${reason})`;
|
|
13942
14078
|
}
|
|
@@ -13945,7 +14081,7 @@ var InvalidPathError = class extends SystemError {
|
|
|
13945
14081
|
context: {
|
|
13946
14082
|
...options?.context,
|
|
13947
14083
|
metadata: {
|
|
13948
|
-
filePath:
|
|
14084
|
+
filePath: path11,
|
|
13949
14085
|
reason,
|
|
13950
14086
|
...options?.context?.metadata
|
|
13951
14087
|
},
|