nexrall-code 0.5.166 → 0.5.168
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/index.js +518 -49
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11355,7 +11355,7 @@ var require_memory = __commonJS({
|
|
|
11355
11355
|
}();
|
|
11356
11356
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11357
11357
|
exports2.AGENT_MEMORY_MAX_BYTES = exports2.AGENT_MEMORY_INJECT_MAX = exports2.MEMORY_ARCHIVE_MAX_BYTES = exports2.MEMORY_HARD_CAP_BYTES = exports2.MEMORY_COMPACT_TRIGGER_BYTES = exports2.MEMORY_MAX_BYTES = exports2.MEMORY_ENTRY_MAX_CHARS = void 0;
|
|
11358
|
-
exports2.memoryFilePath =
|
|
11358
|
+
exports2.memoryFilePath = memoryFilePath2;
|
|
11359
11359
|
exports2.writeMemory = writeMemory2;
|
|
11360
11360
|
exports2.readMemory = readMemory2;
|
|
11361
11361
|
exports2.readAllMemory = readAllMemory2;
|
|
@@ -11374,7 +11374,7 @@ var require_memory = __commonJS({
|
|
|
11374
11374
|
var crypto9 = __importStar(__require("crypto"));
|
|
11375
11375
|
var MEMORY_ROOT = process.env.NEXRALL_MEMORY_DIR || path28.join(os17.homedir(), ".nexrall", "memory");
|
|
11376
11376
|
var GLOBAL_FILE = path28.join(MEMORY_ROOT, "global.md");
|
|
11377
|
-
function
|
|
11377
|
+
function memoryFilePath2(scope, workDir) {
|
|
11378
11378
|
if (scope === "global" || !workDir)
|
|
11379
11379
|
return GLOBAL_FILE;
|
|
11380
11380
|
const key = crypto9.createHash("sha1").update(path28.resolve(workDir)).digest("hex").slice(0, 16);
|
|
@@ -11468,7 +11468,7 @@ ${SUPERSEDED_HEADER}
|
|
|
11468
11468
|
trimmed = trimmed.slice(0, budget - 1).trimEnd() + "\u2026";
|
|
11469
11469
|
}
|
|
11470
11470
|
const body = prefix2 && budget > 0 ? prefix2 + trimmed : trimmed;
|
|
11471
|
-
const file =
|
|
11471
|
+
const file = memoryFilePath2(scope, workDir);
|
|
11472
11472
|
return withLock(file, async () => {
|
|
11473
11473
|
const existing = readMemoryFile(file);
|
|
11474
11474
|
let { active, archived } = parseSections(existing);
|
|
@@ -11503,7 +11503,7 @@ ${SUPERSEDED_HEADER}
|
|
|
11503
11503
|
});
|
|
11504
11504
|
}
|
|
11505
11505
|
function readMemory2(scope, workDir, opts = {}) {
|
|
11506
|
-
const file =
|
|
11506
|
+
const file = memoryFilePath2(scope, workDir);
|
|
11507
11507
|
const { active, archived } = parseSections(readMemoryFile(file));
|
|
11508
11508
|
if (!opts.includeArchived)
|
|
11509
11509
|
return active.length ? serializeSections(active, []).trim() : "";
|
|
@@ -11524,14 +11524,14 @@ ${projMem}`);
|
|
|
11524
11524
|
return parts.join("\n\n");
|
|
11525
11525
|
}
|
|
11526
11526
|
function clearMemory2(scope, workDir) {
|
|
11527
|
-
const file =
|
|
11527
|
+
const file = memoryFilePath2(scope, workDir);
|
|
11528
11528
|
try {
|
|
11529
11529
|
fs28.rmSync(file, { force: true });
|
|
11530
11530
|
} catch {
|
|
11531
11531
|
}
|
|
11532
11532
|
}
|
|
11533
11533
|
function memoryStats2(scope, workDir) {
|
|
11534
|
-
const file =
|
|
11534
|
+
const file = memoryFilePath2(scope, workDir);
|
|
11535
11535
|
const content = readMemoryFile(file);
|
|
11536
11536
|
const { active, archived } = parseSections(content);
|
|
11537
11537
|
return {
|
|
@@ -11545,7 +11545,7 @@ ${projMem}`);
|
|
|
11545
11545
|
return reply.split("\n").map((l2) => l2.trimEnd()).filter((l2) => /^-\s\[\d{4}-\d{2}-\d{2}\]\s*\S/.test(l2));
|
|
11546
11546
|
}
|
|
11547
11547
|
async function compactMemoryIfNeeded2(scope, workDir, summarize) {
|
|
11548
|
-
const file =
|
|
11548
|
+
const file = memoryFilePath2(scope, workDir);
|
|
11549
11549
|
return withLock(file, async () => {
|
|
11550
11550
|
const content = readMemoryFile(file);
|
|
11551
11551
|
if (Buffer.byteLength(content, "utf-8") <= exports2.MEMORY_COMPACT_TRIGGER_BYTES)
|
|
@@ -106910,6 +106910,9 @@ var require_loop = __commonJS({
|
|
|
106910
106910
|
}();
|
|
106911
106911
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
106912
106912
|
exports2.VERIFY_CMD_RE = exports2.WRITE_TOOL_NAMES = exports2.ToolNotAllowedError = exports2.AGENT_MEMORY_TOOL_SCHEMA = exports2.AGENT_MEMORY_TOOL = exports2._stallLimits = exports2._emptyTurnRetry = exports2.bashNeedsRepoLock = void 0;
|
|
106913
|
+
exports2.loadHooks = loadHooks;
|
|
106914
|
+
exports2.parsePromptHookReply = parsePromptHookReply;
|
|
106915
|
+
exports2.classifyStopFailure = classifyStopFailure;
|
|
106913
106916
|
exports2.runLifecycleHooks = runLifecycleHooks;
|
|
106914
106917
|
exports2.runPermissionRequestHooks = runPermissionRequestHooks2;
|
|
106915
106918
|
exports2.fireNotificationHooks = fireNotificationHooks2;
|
|
@@ -107098,8 +107101,206 @@ var require_loop = __commonJS({
|
|
|
107098
107101
|
async function runHookHandler(hook, payload, opts) {
|
|
107099
107102
|
if (hook.type === "http")
|
|
107100
107103
|
return httpHook(hook, payload, opts.timeoutMs);
|
|
107104
|
+
if (hook.type === "prompt" || hook.type === "agent") {
|
|
107105
|
+
return promptHook(hook, payload, { ...opts, envCtx: opts.hookEnv });
|
|
107106
|
+
}
|
|
107101
107107
|
return spawnHook(String(hook.command ?? ""), { cwd: opts.cwd, timeout: opts.timeoutMs, input: payload, env: opts.env });
|
|
107102
107108
|
}
|
|
107109
|
+
var HOOK_AGENT_TOOLS = [
|
|
107110
|
+
{
|
|
107111
|
+
name: "read_file",
|
|
107112
|
+
description: "Read a file from the working directory.",
|
|
107113
|
+
input_schema: {
|
|
107114
|
+
type: "object",
|
|
107115
|
+
properties: {
|
|
107116
|
+
path: { type: "string", description: "File path, relative to the working directory." },
|
|
107117
|
+
offset: { type: "number", description: "0-based line to start from." },
|
|
107118
|
+
limit: { type: "number", description: "Maximum number of lines." }
|
|
107119
|
+
},
|
|
107120
|
+
required: ["path"]
|
|
107121
|
+
}
|
|
107122
|
+
},
|
|
107123
|
+
{
|
|
107124
|
+
name: "search_files",
|
|
107125
|
+
description: "Search file contents (regex) or find files by name in the working directory.",
|
|
107126
|
+
input_schema: {
|
|
107127
|
+
type: "object",
|
|
107128
|
+
properties: {
|
|
107129
|
+
pattern: { type: "string", description: "Regex or literal string to search for." },
|
|
107130
|
+
path: { type: "string", description: "Directory to search in." },
|
|
107131
|
+
type: { type: "string", description: "files (paths only) | content (matching lines) | filename." }
|
|
107132
|
+
},
|
|
107133
|
+
required: ["pattern"]
|
|
107134
|
+
}
|
|
107135
|
+
},
|
|
107136
|
+
{
|
|
107137
|
+
name: "list_directory",
|
|
107138
|
+
description: "List the files and directories at a path.",
|
|
107139
|
+
input_schema: { type: "object", properties: { path: { type: "string" } } }
|
|
107140
|
+
},
|
|
107141
|
+
{
|
|
107142
|
+
name: "glob",
|
|
107143
|
+
description: 'Find files matching a glob pattern, e.g. "**/*.ts".',
|
|
107144
|
+
input_schema: { type: "object", properties: { pattern: { type: "string" }, path: { type: "string" } }, required: ["pattern"] }
|
|
107145
|
+
}
|
|
107146
|
+
];
|
|
107147
|
+
var NO_TOOLS_MARKER = "\0hook-no-tools";
|
|
107148
|
+
function parsePromptHookReply(reply) {
|
|
107149
|
+
const text = String(reply ?? "");
|
|
107150
|
+
const start = text.indexOf("{");
|
|
107151
|
+
const end = text.lastIndexOf("}");
|
|
107152
|
+
if (start < 0 || end <= start)
|
|
107153
|
+
return null;
|
|
107154
|
+
try {
|
|
107155
|
+
const j = JSON.parse(text.slice(start, end + 1));
|
|
107156
|
+
if (typeof j.ok !== "boolean" && typeof j.decision !== "string")
|
|
107157
|
+
return null;
|
|
107158
|
+
return {
|
|
107159
|
+
ok: typeof j.ok === "boolean" ? j.ok : void 0,
|
|
107160
|
+
reason: typeof j.reason === "string" ? j.reason : void 0,
|
|
107161
|
+
additionalContext: typeof j.additionalContext === "string" ? j.additionalContext : void 0,
|
|
107162
|
+
decision: typeof j.decision === "string" ? j.decision : void 0
|
|
107163
|
+
};
|
|
107164
|
+
} catch {
|
|
107165
|
+
return null;
|
|
107166
|
+
}
|
|
107167
|
+
}
|
|
107168
|
+
var PROMPT_HOOK_RULES = `You are a hook evaluator for a coding agent. The hook input JSON is given below, followed by the hook's own instruction. Decide whether the agent action described in the input should proceed. Reply with ONLY one JSON object and nothing else: {"ok":true} to allow, or {"ok":false,"reason":"short explanation"} to block.`;
|
|
107169
|
+
async function promptHook(hook, payload, opts) {
|
|
107170
|
+
const instruction = String(hook.prompt ?? "");
|
|
107171
|
+
if (!instruction)
|
|
107172
|
+
return { status: 1, stdout: "", stderr: 'prompt hook has no "prompt"' };
|
|
107173
|
+
const body = instruction.replace(/\\\$ARGUMENTS/g, "").replace(/\$ARGUMENTS/g, payload).replace(/\u0001/g, "$ARGUMENTS");
|
|
107174
|
+
const ctl = { aborted: false };
|
|
107175
|
+
const timer = setTimeout(() => {
|
|
107176
|
+
ctl.aborted = true;
|
|
107177
|
+
}, Math.max(1e3, opts.timeoutMs));
|
|
107178
|
+
const outerPoll = opts.abortSignal ? setInterval(() => {
|
|
107179
|
+
if (opts.abortSignal?.aborted)
|
|
107180
|
+
ctl.aborted = true;
|
|
107181
|
+
}, 100) : void 0;
|
|
107182
|
+
if (opts.abortSignal?.aborted) {
|
|
107183
|
+
clearTimeout(timer);
|
|
107184
|
+
if (outerPoll)
|
|
107185
|
+
clearInterval(outerPoll);
|
|
107186
|
+
return { status: 1, stdout: "", stderr: "aborted" };
|
|
107187
|
+
}
|
|
107188
|
+
try {
|
|
107189
|
+
return await runModel();
|
|
107190
|
+
} finally {
|
|
107191
|
+
clearTimeout(timer);
|
|
107192
|
+
if (outerPoll)
|
|
107193
|
+
clearInterval(outerPoll);
|
|
107194
|
+
}
|
|
107195
|
+
async function runModel() {
|
|
107196
|
+
const messages = [{
|
|
107197
|
+
role: "user",
|
|
107198
|
+
content: [{ type: "text", text: `${PROMPT_HOOK_RULES}
|
|
107199
|
+
|
|
107200
|
+
Hook input:
|
|
107201
|
+
${payload}
|
|
107202
|
+
|
|
107203
|
+
Hook instruction:
|
|
107204
|
+
${body}` }]
|
|
107205
|
+
}];
|
|
107206
|
+
const isAgent = hook.type === "agent";
|
|
107207
|
+
try {
|
|
107208
|
+
let replyText = "";
|
|
107209
|
+
for (let round = 0; round < (isAgent ? 6 : 1); round++) {
|
|
107210
|
+
const msg = await (0, client_1.streamChat)(messages, {
|
|
107211
|
+
model: hook.model ?? opts.model ?? "turbo",
|
|
107212
|
+
env: opts.envCtx ?? { cwd: opts.cwd },
|
|
107213
|
+
abortSignal: ctl,
|
|
107214
|
+
// Wire the tools by allowlist rather than a separate channel: the backend
|
|
107215
|
+
// filters builtins+extra against it, so an agent hook sees ONLY the four
|
|
107216
|
+
// read-only tools and a prompt hook sees none (the marker matches nothing).
|
|
107217
|
+
toolAllowlist: isAgent ? HOOK_AGENT_TOOLS.map((t2) => t2.name) : [NO_TOOLS_MARKER],
|
|
107218
|
+
extraTools: isAgent ? HOOK_AGENT_TOOLS : void 0
|
|
107219
|
+
}, () => {
|
|
107220
|
+
});
|
|
107221
|
+
const blocks = Array.isArray(msg.content) ? msg.content : [];
|
|
107222
|
+
const toolUses = blocks.filter((b) => b.type === "tool_use");
|
|
107223
|
+
if (!toolUses.length || !isAgent) {
|
|
107224
|
+
replyText = blocks.filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n");
|
|
107225
|
+
break;
|
|
107226
|
+
}
|
|
107227
|
+
messages.push({ role: "assistant", content: msg.content });
|
|
107228
|
+
const results = [];
|
|
107229
|
+
for (const tu of toolUses) {
|
|
107230
|
+
let out;
|
|
107231
|
+
try {
|
|
107232
|
+
out = getHookToolExecutors().includes(String(tu.name)) ? await (0, executor_1.executeTool)(String(tu.name), tu.input ?? {}, ctl, void 0, opts.cwd) : { error: `Tool ${String(tu.name)} is not available to a hook \u2014 only ${getHookToolExecutors().join(", ")}.` };
|
|
107233
|
+
} catch (err) {
|
|
107234
|
+
out = { error: err.message || "tool failed" };
|
|
107235
|
+
}
|
|
107236
|
+
results.push({
|
|
107237
|
+
type: "tool_result",
|
|
107238
|
+
tool_use_id: String(tu.id),
|
|
107239
|
+
content: out.error ? out.output ? `Error: ${out.error}
|
|
107240
|
+
|
|
107241
|
+
${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
107242
|
+
is_error: out.error !== void 0
|
|
107243
|
+
});
|
|
107244
|
+
}
|
|
107245
|
+
messages.push({ role: "user", content: results });
|
|
107246
|
+
}
|
|
107247
|
+
const parsed = parsePromptHookReply(replyText);
|
|
107248
|
+
if (!parsed) {
|
|
107249
|
+
return { status: 1, stdout: "", stderr: "prompt hook returned no decision" };
|
|
107250
|
+
}
|
|
107251
|
+
const decided = parsed.ok === false || parsed.decision === "block" || parsed.decision === "deny";
|
|
107252
|
+
if (decided)
|
|
107253
|
+
return { status: 2, stdout: "", stderr: parsed.reason || `Blocked by ${hook.type} hook` };
|
|
107254
|
+
const passthrough2 = parsed.additionalContext ? JSON.stringify({ additionalContext: parsed.additionalContext }) : "";
|
|
107255
|
+
return { status: 0, stdout: passthrough2, stderr: "" };
|
|
107256
|
+
} catch (err) {
|
|
107257
|
+
if (ctl.aborted)
|
|
107258
|
+
return { status: 1, stdout: "", stderr: "prompt hook timed out" };
|
|
107259
|
+
return { status: 1, stdout: "", stderr: `prompt hook failed: ${err.message}` };
|
|
107260
|
+
}
|
|
107261
|
+
}
|
|
107262
|
+
}
|
|
107263
|
+
function getHookToolExecutors() {
|
|
107264
|
+
return ["read_file", "search_files", "list_directory", "glob"];
|
|
107265
|
+
}
|
|
107266
|
+
function hookRunOptsFor(options) {
|
|
107267
|
+
return { model: options.model ?? "turbo", abortSignal: options.abortSignal, hookEnv: options.env };
|
|
107268
|
+
}
|
|
107269
|
+
function classifyStopFailure(err) {
|
|
107270
|
+
const status = err?.status;
|
|
107271
|
+
const code = err?.code;
|
|
107272
|
+
const details = [status ? `HTTP ${status}` : "", code ? String(code) : ""].filter(Boolean).join(" ") || void 0;
|
|
107273
|
+
if (status === 429)
|
|
107274
|
+
return { error: "rate_limit", error_details: details };
|
|
107275
|
+
if (status === 529)
|
|
107276
|
+
return { error: "overloaded", error_details: details };
|
|
107277
|
+
if (status === 401)
|
|
107278
|
+
return { error: "authentication_failed", error_details: details };
|
|
107279
|
+
if (status === 402)
|
|
107280
|
+
return { error: "billing_error", error_details: details };
|
|
107281
|
+
if (status === 403)
|
|
107282
|
+
return { error: "authentication_failed", error_details: details };
|
|
107283
|
+
if (status === 400 || status === 422)
|
|
107284
|
+
return { error: "invalid_request", error_details: details };
|
|
107285
|
+
if (status === 404)
|
|
107286
|
+
return { error: "model_not_found", error_details: details };
|
|
107287
|
+
if (typeof status === "number" && status >= 500)
|
|
107288
|
+
return { error: "server_error", error_details: details };
|
|
107289
|
+
return { error: "unknown", error_details: details };
|
|
107290
|
+
}
|
|
107291
|
+
function apiFailureForStopReason(stopReason) {
|
|
107292
|
+
if (stopReason === "output-limit")
|
|
107293
|
+
return { error: "max_output_tokens" };
|
|
107294
|
+
if (stopReason === "no-balance")
|
|
107295
|
+
return { error: "billing_error", error_details: "wallet empty (402)" };
|
|
107296
|
+
if (stopReason === "no-team-budget")
|
|
107297
|
+
return { error: "billing_error", error_details: "team pool empty (402)" };
|
|
107298
|
+
if (stopReason === "reported-elsewhere")
|
|
107299
|
+
return { error: "billing_error", error_details: "pre-flight 402" };
|
|
107300
|
+
if (stopReason === "team-unavailable")
|
|
107301
|
+
return { error: "account_on_hold", error_details: "team billing unusable (403)" };
|
|
107302
|
+
return null;
|
|
107303
|
+
}
|
|
107103
107304
|
function hookTimeoutMs(hook, fallbackMs = 6e4) {
|
|
107104
107305
|
if (typeof hook.timeout_ms === "number" && hook.timeout_ms > 0)
|
|
107105
107306
|
return Math.min(hook.timeout_ms, 6e5);
|
|
@@ -107115,7 +107316,7 @@ var require_loop = __commonJS({
|
|
|
107115
107316
|
return norm === toolName || norm === alt && toolName.includes(alt);
|
|
107116
107317
|
});
|
|
107117
107318
|
}
|
|
107118
|
-
async function runToolHooks(entries, phase, toolName, input, workDir, result) {
|
|
107319
|
+
async function runToolHooks(entries, phase, toolName, input, workDir, result, hookOpts) {
|
|
107119
107320
|
const outcome = { block: false };
|
|
107120
107321
|
if (!entries?.length)
|
|
107121
107322
|
return outcome;
|
|
@@ -107129,11 +107330,7 @@ var require_loop = __commonJS({
|
|
|
107129
107330
|
if (!hookMatches(entry.matcher, toolName))
|
|
107130
107331
|
continue;
|
|
107131
107332
|
for (const hook of entry.hooks ?? []) {
|
|
107132
|
-
if (hook
|
|
107133
|
-
continue;
|
|
107134
|
-
if (hook.type === "command" && !hook.command)
|
|
107135
|
-
continue;
|
|
107136
|
-
if (hook.type === "http" && !hook.url)
|
|
107333
|
+
if (!isRunnableHook(hook))
|
|
107137
107334
|
continue;
|
|
107138
107335
|
const hookTimeout = hookTimeoutMs(hook, 6e4);
|
|
107139
107336
|
const r2 = await runHookHandler(hook, payload, {
|
|
@@ -107144,7 +107341,8 @@ var require_loop = __commonJS({
|
|
|
107144
107341
|
NEXRALL_TOOL_NAME: toolName,
|
|
107145
107342
|
NEXRALL_TOOL_INPUT: JSON.stringify(input),
|
|
107146
107343
|
NEXRALL_HOOK_PHASE: phase
|
|
107147
|
-
}
|
|
107344
|
+
},
|
|
107345
|
+
...hookOpts
|
|
107148
107346
|
});
|
|
107149
107347
|
const out = (r2.stdout ?? "").toString().trim();
|
|
107150
107348
|
if (out.startsWith("{")) {
|
|
@@ -107169,17 +107367,13 @@ var require_loop = __commonJS({
|
|
|
107169
107367
|
}
|
|
107170
107368
|
return outcome;
|
|
107171
107369
|
}
|
|
107172
|
-
async function runSimpleHooks(defs, workDir, extraEnv) {
|
|
107370
|
+
async function runSimpleHooks(defs, workDir, extraEnv, hookOpts) {
|
|
107173
107371
|
if (!defs?.length)
|
|
107174
107372
|
return;
|
|
107175
107373
|
for (const hook of defs) {
|
|
107176
|
-
if (hook
|
|
107177
|
-
continue;
|
|
107178
|
-
if (hook.type === "command" && !hook.command)
|
|
107374
|
+
if (!isRunnableHook(hook))
|
|
107179
107375
|
continue;
|
|
107180
|
-
|
|
107181
|
-
continue;
|
|
107182
|
-
await runHookHandler(hook, "", { cwd: workDir, timeoutMs: hookTimeoutMs(hook, 1e4), env: extraEnv ? { ...process.env, ...extraEnv } : void 0 });
|
|
107376
|
+
await runHookHandler(hook, "", { cwd: workDir, timeoutMs: hookTimeoutMs(hook, 1e4), env: extraEnv ? { ...process.env, ...extraEnv } : void 0, ...hookOpts });
|
|
107183
107377
|
}
|
|
107184
107378
|
}
|
|
107185
107379
|
function flattenHookDefs(items, matchValue) {
|
|
@@ -107190,26 +107384,34 @@ var require_loop = __commonJS({
|
|
|
107190
107384
|
if (m2 && m2 !== "*" && matchValue !== void 0 && !m2.split("|").map((x2) => x2.trim()).includes(matchValue))
|
|
107191
107385
|
continue;
|
|
107192
107386
|
out.push(...it.hooks);
|
|
107193
|
-
} else if (it && (it.type
|
|
107387
|
+
} else if (it && isKnownHandlerType(it.type))
|
|
107194
107388
|
out.push(it);
|
|
107195
107389
|
}
|
|
107196
107390
|
return out;
|
|
107197
107391
|
}
|
|
107198
|
-
|
|
107392
|
+
function isKnownHandlerType(t2) {
|
|
107393
|
+
return t2 === "command" || t2 === "http" || t2 === "prompt" || t2 === "agent";
|
|
107394
|
+
}
|
|
107395
|
+
function isRunnableHook(hook) {
|
|
107396
|
+
if (!isKnownHandlerType(hook.type))
|
|
107397
|
+
return false;
|
|
107398
|
+
if (hook.type === "command")
|
|
107399
|
+
return !!hook.command;
|
|
107400
|
+
if (hook.type === "http")
|
|
107401
|
+
return !!hook.url;
|
|
107402
|
+
return !!hook.prompt;
|
|
107403
|
+
}
|
|
107404
|
+
async function runLifecycleHooks(items, event, workDir, payload, matchValue, hookOpts) {
|
|
107199
107405
|
const outcome = { block: false };
|
|
107200
107406
|
const defs = flattenHookDefs(items, matchValue);
|
|
107201
107407
|
if (!defs.length)
|
|
107202
107408
|
return outcome;
|
|
107203
107409
|
const input = JSON.stringify({ hook_event_name: event, cwd: workDir, ...payload });
|
|
107204
107410
|
for (const hook of defs) {
|
|
107205
|
-
if (hook
|
|
107206
|
-
continue;
|
|
107207
|
-
if (hook.type === "command" && !hook.command)
|
|
107411
|
+
if (!isRunnableHook(hook))
|
|
107208
107412
|
continue;
|
|
107209
|
-
|
|
107210
|
-
|
|
107211
|
-
const timeout = hookTimeoutMs(hook, 3e4);
|
|
107212
|
-
const r2 = await runHookHandler(hook, input, { cwd: workDir, timeoutMs: timeout, env: { ...process.env, NEXRALL_HOOK_PHASE: event } });
|
|
107413
|
+
const timeout = hookTimeoutMs(hook, hook.type === "agent" ? 6e4 : hook.type === "prompt" ? 3e4 : 3e4);
|
|
107414
|
+
const r2 = await runHookHandler(hook, input, { cwd: workDir, timeoutMs: timeout, env: { ...process.env, NEXRALL_HOOK_PHASE: event }, ...hookOpts });
|
|
107213
107415
|
const out = (r2.stdout ?? "").toString().trim();
|
|
107214
107416
|
if (out.startsWith("{")) {
|
|
107215
107417
|
try {
|
|
@@ -107229,6 +107431,10 @@ var require_loop = __commonJS({
|
|
|
107229
107431
|
}
|
|
107230
107432
|
if (typeof j.additionalContext === "string" && j.additionalContext)
|
|
107231
107433
|
outcome.context = (outcome.context ? outcome.context + "\n" : "") + j.additionalContext;
|
|
107434
|
+
if (event === "FileChanged" && Array.isArray(j.watchPaths))
|
|
107435
|
+
outcome.watchPaths = j.watchPaths.filter((p) => typeof p === "string");
|
|
107436
|
+
if (typeof j.systemMessage === "string" && j.systemMessage)
|
|
107437
|
+
outcome.systemMessage = j.systemMessage;
|
|
107232
107438
|
} catch {
|
|
107233
107439
|
}
|
|
107234
107440
|
} else if (out && (event === "SessionStart" || event === "UserPromptSubmit") && r2.status === 0) {
|
|
@@ -108089,7 +108295,7 @@ ${stats}${isoNote}`;
|
|
|
108089
108295
|
const subAgentName = agent?.name ?? (typeof input.subagent_type === "string" && input.subagent_type ? input.subagent_type : "general-purpose");
|
|
108090
108296
|
const startItems = loadHooks(options.workDir).SubagentStart;
|
|
108091
108297
|
if (startItems?.length) {
|
|
108092
|
-
const o = await runLifecycleHooks(startItems, "SubagentStart", options.workDir, { session_id: options.sessionId ?? "", agent_type: subAgentName, description: String(input.description ?? "") }, subAgentName).catch(() => ({ block: false }));
|
|
108298
|
+
const o = await runLifecycleHooks(startItems, "SubagentStart", options.workDir, { session_id: options.sessionId ?? "", agent_type: subAgentName, description: String(input.description ?? "") }, subAgentName, hookRunOptsFor(options)).catch(() => ({ block: false }));
|
|
108093
108299
|
if (o.context) {
|
|
108094
108300
|
const last = subMessages[subMessages.length - 1];
|
|
108095
108301
|
if (last && Array.isArray(last.content)) {
|
|
@@ -108649,7 +108855,7 @@ Do NOT call any tools and do NOT continue the task. Reply with text only: a conc
|
|
|
108649
108855
|
if (cut < 2)
|
|
108650
108856
|
return false;
|
|
108651
108857
|
if ((options._depth ?? 0) === 0) {
|
|
108652
|
-
await runLifecycleHooks(loadHooks(options.workDir).PreCompact, "PreCompact", options.workDir, { trigger: "auto", session_id: options.sessionId ?? "", messages_to_summarize: cut }, "auto").catch(() => void 0);
|
|
108858
|
+
await runLifecycleHooks(loadHooks(options.workDir).PreCompact, "PreCompact", options.workDir, { trigger: "auto", session_id: options.sessionId ?? "", messages_to_summarize: cut }, "auto", hookRunOptsFor(options)).catch(() => void 0);
|
|
108653
108859
|
}
|
|
108654
108860
|
const beforeCompact = messages.length;
|
|
108655
108861
|
const afterCompact = cut > 0 ? messages.length - cut + 1 : messages.length;
|
|
@@ -108662,7 +108868,7 @@ Do NOT call any tools and do NOT continue the task. Reply with text only: a conc
|
|
|
108662
108868
|
options.onCompact?.({ trigger: "auto", before: beforeCompact, after: afterCompact });
|
|
108663
108869
|
} catch {
|
|
108664
108870
|
}
|
|
108665
|
-
await runLifecycleHooks(loadHooks(options.workDir).PostCompact, "PostCompact", options.workDir, { trigger: "auto", session_id: options.sessionId ?? "", messages_summarized: cut }, "auto").catch(() => void 0);
|
|
108871
|
+
await runLifecycleHooks(loadHooks(options.workDir).PostCompact, "PostCompact", options.workDir, { trigger: "auto", session_id: options.sessionId ?? "", messages_summarized: cut }, "auto", hookRunOptsFor(options)).catch(() => void 0);
|
|
108666
108872
|
};
|
|
108667
108873
|
const originalTask = originalTaskText(toSummarize);
|
|
108668
108874
|
const summaryPrompt = `Summarize this coding-session transcript into concise bullet points the assistant needs to continue the work: key decisions, files changed (and how), commands run, unresolved problems, and user preferences. Max 400 words.
|
|
@@ -108910,6 +109116,26 @@ Continue the work from here.` }] });
|
|
|
108910
109116
|
const messages = [...initialMessages];
|
|
108911
109117
|
const model = options.model ?? "turbo";
|
|
108912
109118
|
const hooks = options.disableHooks ? withAgentHooks({}, options._agentHooks) : withAgentHooks(loadHooks(options.workDir), options._agentHooks);
|
|
109119
|
+
const fireStopFailure = async (failure) => {
|
|
109120
|
+
if (depth !== 0)
|
|
109121
|
+
return;
|
|
109122
|
+
const items = hooks.StopFailure;
|
|
109123
|
+
if (!items?.length)
|
|
109124
|
+
return;
|
|
109125
|
+
let last = "";
|
|
109126
|
+
for (let i2 = messages.length - 1; i2 >= 0 && !last; i2--) {
|
|
109127
|
+
const m2 = messages[i2];
|
|
109128
|
+
if (m2?.role === "assistant" && Array.isArray(m2.content)) {
|
|
109129
|
+
last = m2.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n").trim().slice(0, 2e3);
|
|
109130
|
+
}
|
|
109131
|
+
}
|
|
109132
|
+
await runLifecycleHooks(items, "StopFailure", options.workDir, {
|
|
109133
|
+
session_id: options.sessionId ?? "",
|
|
109134
|
+
error: failure.error,
|
|
109135
|
+
...failure.error_details ? { error_details: failure.error_details } : {},
|
|
109136
|
+
last_assistant_message: last
|
|
109137
|
+
}, failure.error, hookRunOptsFor(options)).catch(() => void 0);
|
|
109138
|
+
};
|
|
108913
109139
|
const depth = options._depth ?? 0;
|
|
108914
109140
|
const agentScope = options._agentScope ?? "root";
|
|
108915
109141
|
const isMainAgent = depth === 0;
|
|
@@ -108930,13 +109156,13 @@ ${ctx}
|
|
|
108930
109156
|
const sid = options.sessionId || PROCESS_BUDGET_KEY;
|
|
108931
109157
|
if (isPrompt && !_sessionStarted.has(sid) && (hooks.SessionStart?.length ?? 0) > 0) {
|
|
108932
109158
|
_sessionStarted.add(sid);
|
|
108933
|
-
const o = await runLifecycleHooks(hooks.SessionStart, "SessionStart", options.workDir, { session_id: options.sessionId ?? "", source: messages.length > 1 ? "resume" : "startup" }, messages.length > 1 ? "resume" : "startup");
|
|
109159
|
+
const o = await runLifecycleHooks(hooks.SessionStart, "SessionStart", options.workDir, { session_id: options.sessionId ?? "", source: messages.length > 1 ? "resume" : "startup" }, messages.length > 1 ? "resume" : "startup", hookRunOptsFor(options));
|
|
108934
109160
|
if (o.context)
|
|
108935
109161
|
addContext(o.context);
|
|
108936
109162
|
} else if (isPrompt)
|
|
108937
109163
|
_sessionStarted.add(sid);
|
|
108938
109164
|
if (isPrompt && (hooks.UserPromptSubmit?.length ?? 0) > 0) {
|
|
108939
|
-
const o = await runLifecycleHooks(hooks.UserPromptSubmit, "UserPromptSubmit", options.workDir, { session_id: options.sessionId ?? "", prompt: promptText });
|
|
109165
|
+
const o = await runLifecycleHooks(hooks.UserPromptSubmit, "UserPromptSubmit", options.workDir, { session_id: options.sessionId ?? "", prompt: promptText }, void 0, hookRunOptsFor(options));
|
|
108940
109166
|
if (o.block) {
|
|
108941
109167
|
options.onText(`
|
|
108942
109168
|
\u26D4 Prompt blocked by a UserPromptSubmit hook: ${o.reason ?? "no reason given"}
|
|
@@ -109204,7 +109430,8 @@ ${ctx}
|
|
|
109204
109430
|
stopReason = "team-unavailable";
|
|
109205
109431
|
break;
|
|
109206
109432
|
}
|
|
109207
|
-
await runSimpleHooks(hooks.OnError, options.workDir);
|
|
109433
|
+
await runSimpleHooks(hooks.OnError, options.workDir, void 0, hookRunOptsFor(options));
|
|
109434
|
+
await fireStopFailure(classifyStopFailure(err));
|
|
109208
109435
|
throw new types_1.AgentTurnError(`Stream failed: ${err.message}`, trimToResumableBoundary(messages), completedRounds, err);
|
|
109209
109436
|
}
|
|
109210
109437
|
if (options.abortSignal?.aborted) {
|
|
@@ -109245,7 +109472,7 @@ ${ctx}
|
|
|
109245
109472
|
continue;
|
|
109246
109473
|
}
|
|
109247
109474
|
if (depth === 0)
|
|
109248
|
-
await runSimpleHooks(hooks.PostMessageComplete, options.workDir);
|
|
109475
|
+
await runSimpleHooks(hooks.PostMessageComplete, options.workDir, void 0, hookRunOptsFor(options));
|
|
109249
109476
|
stopReason = assistantMessage.stopReason === "max_tokens" ? "output-limit" : "empty-response";
|
|
109250
109477
|
break;
|
|
109251
109478
|
}
|
|
@@ -109329,7 +109556,7 @@ ${ctx}
|
|
|
109329
109556
|
}
|
|
109330
109557
|
}
|
|
109331
109558
|
if (depth === 0)
|
|
109332
|
-
await runSimpleHooks(hooks.PostMessageComplete, options.workDir);
|
|
109559
|
+
await runSimpleHooks(hooks.PostMessageComplete, options.workDir, void 0, hookRunOptsFor(options));
|
|
109333
109560
|
stopReason = "clean";
|
|
109334
109561
|
break;
|
|
109335
109562
|
}
|
|
@@ -109377,12 +109604,12 @@ ${ctx}
|
|
|
109377
109604
|
} else if (name === "task") {
|
|
109378
109605
|
const wantsBackground = input.run_in_background === true || input.run_in_background !== false && !!(0, agentTypes_1.findAgentType)(agentTypes, String(input.subagent_type ?? ""))?.background;
|
|
109379
109606
|
const taskOptions = { ...auditOptions, _taskToolUseId: id };
|
|
109380
|
-
const preTask = await runToolHooks(hooks.PreToolUse, "PreToolUse", name, input, options.workDir);
|
|
109607
|
+
const preTask = await runToolHooks(hooks.PreToolUse, "PreToolUse", name, input, options.workDir, void 0, hookRunOptsFor(options));
|
|
109381
109608
|
if (preTask.block) {
|
|
109382
109609
|
result = { error: `Blocked by PreToolUse hook: ${preTask.reason}` };
|
|
109383
109610
|
} else {
|
|
109384
109611
|
result = wantsBackground && depth === 0 && options.backgroundAgents && !input.resume_agent_id ? dispatchBackgroundSubAgent(input, taskOptions, agentTypes, options.backgroundAgents) : await dispatchSubAgent(input, taskOptions, agentTypes);
|
|
109385
|
-
const postTask = await runToolHooks(hooks.PostToolUse, "PostToolUse", name, input, options.workDir, result);
|
|
109612
|
+
const postTask = await runToolHooks(hooks.PostToolUse, "PostToolUse", name, input, options.workDir, result, hookRunOptsFor(options));
|
|
109386
109613
|
const injectedTask = [preTask.context, postTask.context].filter(Boolean).join("\n");
|
|
109387
109614
|
if (injectedTask) {
|
|
109388
109615
|
if (result.error !== void 0)
|
|
@@ -109399,7 +109626,7 @@ ${ctx}
|
|
|
109399
109626
|
}
|
|
109400
109627
|
}
|
|
109401
109628
|
} else {
|
|
109402
|
-
const pre = await runToolHooks(hooks.PreToolUse, "PreToolUse", name, input, options.workDir);
|
|
109629
|
+
const pre = await runToolHooks(hooks.PreToolUse, "PreToolUse", name, input, options.workDir, void 0, hookRunOptsFor(options));
|
|
109403
109630
|
if (pre.block) {
|
|
109404
109631
|
result = { error: `Blocked by PreToolUse hook: ${pre.reason}` };
|
|
109405
109632
|
} else {
|
|
@@ -109445,9 +109672,9 @@ ${ctx}
|
|
|
109445
109672
|
const scope = input.scope === "global" ? "global" : "project";
|
|
109446
109673
|
void maybeCompactMemory(scope, options);
|
|
109447
109674
|
}
|
|
109448
|
-
const post = await runToolHooks(hooks.PostToolUse, "PostToolUse", name, input, options.workDir, result);
|
|
109675
|
+
const post = await runToolHooks(hooks.PostToolUse, "PostToolUse", name, input, options.workDir, result, hookRunOptsFor(options));
|
|
109449
109676
|
if (result.error !== void 0 && (hooks.PostToolUseFailure?.length ?? 0) > 0) {
|
|
109450
|
-
const f3 = await runLifecycleHooks(hooks.PostToolUseFailure, "PostToolUseFailure", options.workDir, { session_id: options.sessionId ?? "", tool_name: name, tool_input: input, error: String(result.error).slice(0, 4e3) }, name).catch(() => ({ block: false }));
|
|
109677
|
+
const f3 = await runLifecycleHooks(hooks.PostToolUseFailure, "PostToolUseFailure", options.workDir, { session_id: options.sessionId ?? "", tool_name: name, tool_input: input, error: String(result.error).slice(0, 4e3) }, name, hookRunOptsFor(options)).catch(() => ({ block: false }));
|
|
109451
109678
|
if (f3.context)
|
|
109452
109679
|
post.context = [post.context, f3.context].filter(Boolean).join("\n");
|
|
109453
109680
|
if (f3.block) {
|
|
@@ -109569,6 +109796,9 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
109569
109796
|
stopReason = "budget";
|
|
109570
109797
|
if (options.abortSignal?.aborted)
|
|
109571
109798
|
stopReason = "aborted";
|
|
109799
|
+
const apiFailure = apiFailureForStopReason(stopReason);
|
|
109800
|
+
if (apiFailure)
|
|
109801
|
+
await fireStopFailure(apiFailure);
|
|
109572
109802
|
const notice = stopReasonNotice(stopReason, { budget, repeatError: stalledRepeatError });
|
|
109573
109803
|
if (options._onStopReason)
|
|
109574
109804
|
options._onStopReason(stopReason, notice || null);
|
|
@@ -109583,12 +109813,12 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
109583
109813
|
throw new types_1.AgentTurnError(err?.message || "The turn ended unexpectedly", trimToResumableBoundary(messages), completedRounds, err);
|
|
109584
109814
|
} finally {
|
|
109585
109815
|
if (depth === 0 && (hooks.SessionEnd?.length ?? 0) > 0) {
|
|
109586
|
-
await runLifecycleHooks(hooks.SessionEnd, "SessionEnd", options.workDir, { session_id: options.sessionId ?? "", reason: stopReason }, stopReason).catch(() => void 0);
|
|
109816
|
+
await runLifecycleHooks(hooks.SessionEnd, "SessionEnd", options.workDir, { session_id: options.sessionId ?? "", reason: stopReason }, stopReason, hookRunOptsFor(options)).catch(() => void 0);
|
|
109587
109817
|
}
|
|
109588
109818
|
if (depth === 0)
|
|
109589
|
-
await runSimpleHooks(hooks.OnStop, options.workDir);
|
|
109819
|
+
await runSimpleHooks(hooks.OnStop, options.workDir, void 0, hookRunOptsFor(options));
|
|
109590
109820
|
else
|
|
109591
|
-
await runSimpleHooks(hooks.SubagentStop, options.workDir, { NEXRALL_AGENT_NAME: options._agentTypeName ?? "general-purpose" });
|
|
109821
|
+
await runSimpleHooks(hooks.SubagentStop, options.workDir, { NEXRALL_AGENT_NAME: options._agentTypeName ?? "general-purpose" }, hookRunOptsFor(options));
|
|
109592
109822
|
}
|
|
109593
109823
|
return messages;
|
|
109594
109824
|
}
|
|
@@ -109610,6 +109840,214 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
109610
109840
|
}
|
|
109611
109841
|
});
|
|
109612
109842
|
|
|
109843
|
+
// ../core/dist/agent/lifecycleHost.js
|
|
109844
|
+
var require_lifecycleHost = __commonJS({
|
|
109845
|
+
"../core/dist/agent/lifecycleHost.js"(exports2) {
|
|
109846
|
+
"use strict";
|
|
109847
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
|
|
109848
|
+
if (k2 === void 0)
|
|
109849
|
+
k2 = k;
|
|
109850
|
+
var desc = Object.getOwnPropertyDescriptor(m2, k);
|
|
109851
|
+
if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
|
|
109852
|
+
desc = { enumerable: true, get: function() {
|
|
109853
|
+
return m2[k];
|
|
109854
|
+
} };
|
|
109855
|
+
}
|
|
109856
|
+
Object.defineProperty(o, k2, desc);
|
|
109857
|
+
} : function(o, m2, k, k2) {
|
|
109858
|
+
if (k2 === void 0)
|
|
109859
|
+
k2 = k;
|
|
109860
|
+
o[k2] = m2[k];
|
|
109861
|
+
});
|
|
109862
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
109863
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
109864
|
+
} : function(o, v) {
|
|
109865
|
+
o["default"] = v;
|
|
109866
|
+
});
|
|
109867
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
109868
|
+
var ownKeys = function(o) {
|
|
109869
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
109870
|
+
var ar = [];
|
|
109871
|
+
for (var k in o2)
|
|
109872
|
+
if (Object.prototype.hasOwnProperty.call(o2, k))
|
|
109873
|
+
ar[ar.length] = k;
|
|
109874
|
+
return ar;
|
|
109875
|
+
};
|
|
109876
|
+
return ownKeys(o);
|
|
109877
|
+
};
|
|
109878
|
+
return function(mod) {
|
|
109879
|
+
if (mod && mod.__esModule)
|
|
109880
|
+
return mod;
|
|
109881
|
+
var result = {};
|
|
109882
|
+
if (mod != null) {
|
|
109883
|
+
for (var k = ownKeys(mod), i2 = 0; i2 < k.length; i2++)
|
|
109884
|
+
if (k[i2] !== "default")
|
|
109885
|
+
__createBinding(result, mod, k[i2]);
|
|
109886
|
+
}
|
|
109887
|
+
__setModuleDefault(result, mod);
|
|
109888
|
+
return result;
|
|
109889
|
+
};
|
|
109890
|
+
}();
|
|
109891
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
109892
|
+
exports2.fireInstructionsLoadedHooks = fireInstructionsLoadedHooks2;
|
|
109893
|
+
exports2.startFileChangedWatcher = startFileChangedWatcher2;
|
|
109894
|
+
var fs28 = __importStar(__require("fs"));
|
|
109895
|
+
var path28 = __importStar(__require("path"));
|
|
109896
|
+
var loop_1 = require_loop();
|
|
109897
|
+
async function fireInstructionsLoadedHooks2(workDir, sessionId, files) {
|
|
109898
|
+
if (!files.length)
|
|
109899
|
+
return;
|
|
109900
|
+
try {
|
|
109901
|
+
const items = (0, loop_1.loadHooks)(workDir).InstructionsLoaded;
|
|
109902
|
+
if (!items?.length)
|
|
109903
|
+
return;
|
|
109904
|
+
for (const f3 of files) {
|
|
109905
|
+
await (0, loop_1.runLifecycleHooks)(items, "InstructionsLoaded", workDir, {
|
|
109906
|
+
session_id: sessionId,
|
|
109907
|
+
file_path: f3.file_path,
|
|
109908
|
+
memory_type: f3.memory_type,
|
|
109909
|
+
load_reason: f3.load_reason,
|
|
109910
|
+
...f3.globs ? { globs: f3.globs } : {}
|
|
109911
|
+
}, f3.load_reason).catch(() => void 0);
|
|
109912
|
+
}
|
|
109913
|
+
} catch {
|
|
109914
|
+
}
|
|
109915
|
+
}
|
|
109916
|
+
function isWatchableName(name) {
|
|
109917
|
+
return !!name && !name.includes("/") && !name.includes("\\") && !name.includes("*") && !name.includes("?") && name !== "." && name !== "..";
|
|
109918
|
+
}
|
|
109919
|
+
function startFileChangedWatcher2(workDir, sessionId, opts) {
|
|
109920
|
+
let items;
|
|
109921
|
+
try {
|
|
109922
|
+
items = (0, loop_1.loadHooks)(workDir).FileChanged;
|
|
109923
|
+
} catch {
|
|
109924
|
+
items = void 0;
|
|
109925
|
+
}
|
|
109926
|
+
if (!items?.length)
|
|
109927
|
+
return null;
|
|
109928
|
+
const staticNames = /* @__PURE__ */ new Set();
|
|
109929
|
+
for (const it of items) {
|
|
109930
|
+
if (it && Array.isArray(it.hooks)) {
|
|
109931
|
+
const m2 = it.matcher;
|
|
109932
|
+
if (!m2 || m2 === "*")
|
|
109933
|
+
continue;
|
|
109934
|
+
for (const raw of m2.split("|")) {
|
|
109935
|
+
const name = raw.trim();
|
|
109936
|
+
if (isWatchableName(name))
|
|
109937
|
+
staticNames.add(name);
|
|
109938
|
+
}
|
|
109939
|
+
}
|
|
109940
|
+
}
|
|
109941
|
+
if (!staticNames.size)
|
|
109942
|
+
return null;
|
|
109943
|
+
const dynamicNames = /* @__PURE__ */ new Set();
|
|
109944
|
+
const watched = () => /* @__PURE__ */ new Set([...staticNames, ...dynamicNames]);
|
|
109945
|
+
const known = /* @__PURE__ */ new Set();
|
|
109946
|
+
const seedKnown = (names) => {
|
|
109947
|
+
for (const n of names) {
|
|
109948
|
+
try {
|
|
109949
|
+
if (fs28.existsSync(path28.join(workDir, n)))
|
|
109950
|
+
known.add(n);
|
|
109951
|
+
} catch {
|
|
109952
|
+
}
|
|
109953
|
+
}
|
|
109954
|
+
};
|
|
109955
|
+
seedKnown(staticNames);
|
|
109956
|
+
const pending = /* @__PURE__ */ new Map();
|
|
109957
|
+
let closed = false;
|
|
109958
|
+
let watcher = null;
|
|
109959
|
+
try {
|
|
109960
|
+
watcher = fs28.watch(workDir, { persistent: false }, (_eventType, filename) => {
|
|
109961
|
+
if (closed)
|
|
109962
|
+
return;
|
|
109963
|
+
const name = filename ? path28.basename(String(filename)) : "";
|
|
109964
|
+
if (!name || !watched().has(name))
|
|
109965
|
+
return;
|
|
109966
|
+
const prev = pending.get(name);
|
|
109967
|
+
if (prev)
|
|
109968
|
+
clearTimeout(prev);
|
|
109969
|
+
pending.set(name, setTimeout(() => {
|
|
109970
|
+
pending.delete(name);
|
|
109971
|
+
let exists = true;
|
|
109972
|
+
try {
|
|
109973
|
+
exists = fs28.existsSync(path28.join(workDir, name));
|
|
109974
|
+
} catch {
|
|
109975
|
+
exists = false;
|
|
109976
|
+
}
|
|
109977
|
+
const event = !exists ? "unlink" : known.has(name) ? "change" : "add";
|
|
109978
|
+
if (exists)
|
|
109979
|
+
known.add(name);
|
|
109980
|
+
else
|
|
109981
|
+
known.delete(name);
|
|
109982
|
+
void fireChanged(workDir, sessionId, name, event, items, dynamicNames.has(name)).then((o) => {
|
|
109983
|
+
if (!o)
|
|
109984
|
+
return;
|
|
109985
|
+
if (o.systemMessage && opts?.onSystemMessage) {
|
|
109986
|
+
try {
|
|
109987
|
+
opts.onSystemMessage(o.systemMessage);
|
|
109988
|
+
} catch {
|
|
109989
|
+
}
|
|
109990
|
+
}
|
|
109991
|
+
if (o.watchPaths) {
|
|
109992
|
+
dynamicNames.clear();
|
|
109993
|
+
for (const p of o.watchPaths) {
|
|
109994
|
+
const n = isWatchableName(path28.basename(p)) ? path28.basename(p) : "";
|
|
109995
|
+
if (n)
|
|
109996
|
+
dynamicNames.add(n);
|
|
109997
|
+
}
|
|
109998
|
+
seedKnown(dynamicNames);
|
|
109999
|
+
}
|
|
110000
|
+
}).catch(() => {
|
|
110001
|
+
});
|
|
110002
|
+
}, 250));
|
|
110003
|
+
});
|
|
110004
|
+
watcher.on("error", () => {
|
|
110005
|
+
});
|
|
110006
|
+
} catch {
|
|
110007
|
+
return null;
|
|
110008
|
+
}
|
|
110009
|
+
return {
|
|
110010
|
+
stop() {
|
|
110011
|
+
closed = true;
|
|
110012
|
+
for (const t2 of pending.values())
|
|
110013
|
+
clearTimeout(t2);
|
|
110014
|
+
pending.clear();
|
|
110015
|
+
try {
|
|
110016
|
+
watcher?.close();
|
|
110017
|
+
} catch {
|
|
110018
|
+
}
|
|
110019
|
+
watcher = null;
|
|
110020
|
+
},
|
|
110021
|
+
updateWatchPaths(paths) {
|
|
110022
|
+
dynamicNames.clear();
|
|
110023
|
+
for (const p of paths) {
|
|
110024
|
+
const n = isWatchableName(path28.basename(p)) ? path28.basename(p) : "";
|
|
110025
|
+
if (n)
|
|
110026
|
+
dynamicNames.add(n);
|
|
110027
|
+
}
|
|
110028
|
+
seedKnown(dynamicNames);
|
|
110029
|
+
},
|
|
110030
|
+
watchedFiles() {
|
|
110031
|
+
return [...watched()].sort();
|
|
110032
|
+
}
|
|
110033
|
+
};
|
|
110034
|
+
}
|
|
110035
|
+
async function fireChanged(workDir, sessionId, name, event, items, isDynamic) {
|
|
110036
|
+
const abs = path28.join(workDir, name);
|
|
110037
|
+
try {
|
|
110038
|
+
const o = await (0, loop_1.runLifecycleHooks)(items, "FileChanged", workDir, {
|
|
110039
|
+
session_id: sessionId,
|
|
110040
|
+
file_path: abs,
|
|
110041
|
+
event
|
|
110042
|
+
}, isDynamic ? void 0 : name);
|
|
110043
|
+
return { watchPaths: o.watchPaths, systemMessage: o.systemMessage };
|
|
110044
|
+
} catch {
|
|
110045
|
+
return null;
|
|
110046
|
+
}
|
|
110047
|
+
}
|
|
110048
|
+
}
|
|
110049
|
+
});
|
|
110050
|
+
|
|
109613
110051
|
// ../core/dist/mcp/client.js
|
|
109614
110052
|
var require_client2 = __commonJS({
|
|
109615
110053
|
"../core/dist/mcp/client.js"(exports2) {
|
|
@@ -111826,6 +112264,7 @@ var require_dist3 = __commonJS({
|
|
|
111826
112264
|
__exportStar(require_client(), exports2);
|
|
111827
112265
|
__exportStar(require_executor(), exports2);
|
|
111828
112266
|
__exportStar(require_loop(), exports2);
|
|
112267
|
+
__exportStar(require_lifecycleHost(), exports2);
|
|
111829
112268
|
__exportStar(require_modelCatalogue(), exports2);
|
|
111830
112269
|
__exportStar(require_testIntegrity(), exports2);
|
|
111831
112270
|
__exportStar(require_editCompleteness(), exports2);
|
|
@@ -169063,22 +169502,39 @@ var tryRead = (p) => {
|
|
|
169063
169502
|
return null;
|
|
169064
169503
|
}
|
|
169065
169504
|
};
|
|
169505
|
+
var lastLoadedInstructions = [];
|
|
169066
169506
|
function readNexrallMd(workDir) {
|
|
169507
|
+
lastLoadedInstructions = [];
|
|
169067
169508
|
if (noDiscovery)
|
|
169068
169509
|
return void 0;
|
|
169069
169510
|
const parts = [];
|
|
169511
|
+
const noteLoaded = (file, memoryType) => {
|
|
169512
|
+
try {
|
|
169513
|
+
if (fs25.existsSync(file))
|
|
169514
|
+
lastLoadedInstructions.push({ file_path: file, memory_type: memoryType, load_reason: "session_start" });
|
|
169515
|
+
} catch {
|
|
169516
|
+
}
|
|
169517
|
+
};
|
|
169070
169518
|
const memContent = (0, import_code_core16.readAllMemory)(workDir);
|
|
169071
|
-
if (memContent)
|
|
169519
|
+
if (memContent) {
|
|
169072
169520
|
parts.push(memContent);
|
|
169073
|
-
|
|
169074
|
-
|
|
169521
|
+
noteLoaded((0, import_code_core16.memoryFilePath)("global"), "User");
|
|
169522
|
+
if (workDir)
|
|
169523
|
+
noteLoaded((0, import_code_core16.memoryFilePath)("project", workDir), "Project");
|
|
169524
|
+
}
|
|
169525
|
+
const globalNexrall = path25.join(os15.homedir(), ".nexrall", "nexrall.md");
|
|
169526
|
+
const globalContent = tryRead(globalNexrall);
|
|
169527
|
+
if (globalContent) {
|
|
169075
169528
|
parts.push(`[Global instructions]
|
|
169076
169529
|
${globalContent}`);
|
|
169530
|
+
noteLoaded(globalNexrall, "User");
|
|
169531
|
+
}
|
|
169077
169532
|
for (const candidate of NEXRALL_MD_CANDIDATES) {
|
|
169078
169533
|
const content = tryRead(path25.join(workDir, candidate));
|
|
169079
169534
|
if (content) {
|
|
169080
169535
|
parts.push(`[Project instructions \u2014 ${candidate}]
|
|
169081
169536
|
${content}`);
|
|
169537
|
+
noteLoaded(path25.join(workDir, candidate), "Project");
|
|
169082
169538
|
break;
|
|
169083
169539
|
}
|
|
169084
169540
|
}
|
|
@@ -170646,6 +171102,18 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
170646
171102
|
let sessionId = options.newSessionId ?? crypto7.randomBytes(8).toString("hex");
|
|
170647
171103
|
activeSessionIdGetter = () => sessionId;
|
|
170648
171104
|
let sessionTitle = options.sessionName ?? "";
|
|
171105
|
+
const fileWatcher = noDiscovery ? null : (0, import_code_core16.startFileChangedWatcher)(workDir, sessionId, {
|
|
171106
|
+
// A hook's {"systemMessage":"…"} is the event's one user-visible field.
|
|
171107
|
+
onSystemMessage: (m2) => console.log(paint.dim(` ${m2}`))
|
|
171108
|
+
});
|
|
171109
|
+
if (fileWatcher) {
|
|
171110
|
+
const watching = fileWatcher.watchedFiles();
|
|
171111
|
+
if (watching.length && !headless)
|
|
171112
|
+
console.log(paint.dim(` FileChanged hook: watching ${watching.join(", ")}`));
|
|
171113
|
+
if (options.verbose)
|
|
171114
|
+
process.stderr.write("[verbose] FileChanged hook: " + watching.join(", ") + "\n");
|
|
171115
|
+
}
|
|
171116
|
+
void (0, import_code_core16.fireInstructionsLoadedHooks)(workDir, sessionId, lastLoadedInstructions);
|
|
170649
171117
|
const modeLocked = options.lockMode === true;
|
|
170650
171118
|
let agentMode = modeLocked ? "plan" : options.initialMode ?? "auto";
|
|
170651
171119
|
const refuseIfLocked = (what) => {
|
|
@@ -173400,6 +173868,7 @@ ${text}
|
|
|
173400
173868
|
deliverBackgroundWhenIdle();
|
|
173401
173869
|
});
|
|
173402
173870
|
rl.on("close", () => {
|
|
173871
|
+
fileWatcher?.stop();
|
|
173403
173872
|
updateTitle();
|
|
173404
173873
|
if (messages.length)
|
|
173405
173874
|
saveSession2(sessionId, sessionTitle || "Untitled", workDir, messages);
|