nexrall-code 0.5.177 → 0.5.178
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 +464 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14343,6 +14343,7 @@ var require_sharedTasks = __commonJS({
|
|
|
14343
14343
|
exports2.createSharedTask = createSharedTask;
|
|
14344
14344
|
exports2.claimTask = claimTask;
|
|
14345
14345
|
exports2.updateSharedTaskStatus = updateSharedTaskStatus;
|
|
14346
|
+
exports2.deleteSharedTask = deleteSharedTask;
|
|
14346
14347
|
var fs32 = __importStar(__require("fs"));
|
|
14347
14348
|
var os20 = __importStar(__require("os"));
|
|
14348
14349
|
var path32 = __importStar(__require("path"));
|
|
@@ -14476,6 +14477,14 @@ var require_sharedTasks = __commonJS({
|
|
|
14476
14477
|
}, workDir);
|
|
14477
14478
|
}
|
|
14478
14479
|
exports2._sharedTasksInternal = { tasksRoot, scopeDir, taskPath, isClaimAbandoned, isUnblocked, CLAIM_STALE_MS, MIN_CLAIM_AGE_FOR_DEATH_CHECK_MS };
|
|
14480
|
+
function deleteSharedTask(workDir, taskId) {
|
|
14481
|
+
try {
|
|
14482
|
+
fs32.unlinkSync(taskPath(workDir, taskId));
|
|
14483
|
+
return true;
|
|
14484
|
+
} catch {
|
|
14485
|
+
return false;
|
|
14486
|
+
}
|
|
14487
|
+
}
|
|
14479
14488
|
}
|
|
14480
14489
|
});
|
|
14481
14490
|
|
|
@@ -106697,6 +106706,14 @@ var require_hooks = __commonJS({
|
|
|
106697
106706
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
106698
106707
|
exports2.withAgentHooks = withAgentHooks;
|
|
106699
106708
|
exports2.loadHooks = loadHooks2;
|
|
106709
|
+
exports2.setHookWakeListener = setHookWakeListener2;
|
|
106710
|
+
exports2.setHookStatusListener = setHookStatusListener2;
|
|
106711
|
+
exports2.drainHookDeliveries = drainHookDeliveries;
|
|
106712
|
+
exports2.takeHookWakes = takeHookWakes2;
|
|
106713
|
+
exports2.hasPendingHookWake = hasPendingHookWake2;
|
|
106714
|
+
exports2.formatHookDeliveries = formatHookDeliveries2;
|
|
106715
|
+
exports2.resetHookOnceState = resetHookOnceState2;
|
|
106716
|
+
exports2.setHookMcpCaller = setHookMcpCaller2;
|
|
106700
106717
|
exports2.parsePromptHookReply = parsePromptHookReply;
|
|
106701
106718
|
exports2.hookRunOptsFor = hookRunOptsFor;
|
|
106702
106719
|
exports2.classifyStopFailure = classifyStopFailure;
|
|
@@ -106786,7 +106803,10 @@ var require_hooks = __commonJS({
|
|
|
106786
106803
|
"ConfigChange",
|
|
106787
106804
|
"WorktreeCreate",
|
|
106788
106805
|
"WorktreeRemove",
|
|
106789
|
-
"Setup"
|
|
106806
|
+
"Setup",
|
|
106807
|
+
"PostToolBatch",
|
|
106808
|
+
"TaskCreated",
|
|
106809
|
+
"TaskCompleted"
|
|
106790
106810
|
];
|
|
106791
106811
|
function toHookEntries(list) {
|
|
106792
106812
|
return list.map((it) => {
|
|
@@ -106795,11 +106815,117 @@ var require_hooks = __commonJS({
|
|
|
106795
106815
|
return { matcher: e2.matcher, hooks: e2.hooks };
|
|
106796
106816
|
const { matcher, ...rest } = e2;
|
|
106797
106817
|
const hook = { ...rest };
|
|
106798
|
-
if (!isKnownHandlerType(hook.type))
|
|
106799
|
-
hook.type = "command";
|
|
106818
|
+
if (!isKnownHandlerType(hook.type)) {
|
|
106819
|
+
hook.type = !hook.command && !hook.url && !hook.prompt && hook.server && hook.tool ? "mcp_tool" : "command";
|
|
106820
|
+
}
|
|
106800
106821
|
return { matcher, hooks: [hook] };
|
|
106801
106822
|
});
|
|
106802
106823
|
}
|
|
106824
|
+
var _hookDeliveries = [];
|
|
106825
|
+
var _hookWakeListener = null;
|
|
106826
|
+
var _hookStatusListener = null;
|
|
106827
|
+
function setHookWakeListener2(fn) {
|
|
106828
|
+
_hookWakeListener = fn;
|
|
106829
|
+
}
|
|
106830
|
+
function setHookStatusListener2(fn) {
|
|
106831
|
+
_hookStatusListener = fn;
|
|
106832
|
+
}
|
|
106833
|
+
function drainHookDeliveries() {
|
|
106834
|
+
return _hookDeliveries.splice(0);
|
|
106835
|
+
}
|
|
106836
|
+
function takeHookWakes2() {
|
|
106837
|
+
const out = _hookDeliveries.filter((d) => d.kind === "wake");
|
|
106838
|
+
for (let i2 = _hookDeliveries.length - 1; i2 >= 0; i2--)
|
|
106839
|
+
if (_hookDeliveries[i2].kind === "wake")
|
|
106840
|
+
_hookDeliveries.splice(i2, 1);
|
|
106841
|
+
return out;
|
|
106842
|
+
}
|
|
106843
|
+
function hasPendingHookWake2() {
|
|
106844
|
+
return _hookDeliveries.some((d) => d.kind === "wake");
|
|
106845
|
+
}
|
|
106846
|
+
function formatHookDeliveries2(list) {
|
|
106847
|
+
return list.map((d) => `<hook-context source="${d.source}">
|
|
106848
|
+
${d.text}
|
|
106849
|
+
</hook-context>`).join("\n\n");
|
|
106850
|
+
}
|
|
106851
|
+
var _hookOnceDone = /* @__PURE__ */ new Set();
|
|
106852
|
+
function hookIdentity(event, hook, matcher, dir) {
|
|
106853
|
+
const body = hook.command ?? hook.url ?? hook.prompt ?? `${hook.server ?? ""}__${hook.tool ?? ""}`;
|
|
106854
|
+
return `${dir ?? ""}|${event}|${matcher ?? ""}|${body}`;
|
|
106855
|
+
}
|
|
106856
|
+
function resetHookOnceState2() {
|
|
106857
|
+
_hookOnceDone.clear();
|
|
106858
|
+
}
|
|
106859
|
+
var _activeStatuses = /* @__PURE__ */ new Map();
|
|
106860
|
+
var _statusSeq = 0;
|
|
106861
|
+
function hookStatusBegin(message) {
|
|
106862
|
+
const id = ++_statusSeq;
|
|
106863
|
+
_activeStatuses.set(id, message);
|
|
106864
|
+
_hookStatusListener?.(message);
|
|
106865
|
+
return id;
|
|
106866
|
+
}
|
|
106867
|
+
function hookStatusEnd(id) {
|
|
106868
|
+
if (!_activeStatuses.delete(id))
|
|
106869
|
+
return;
|
|
106870
|
+
if (!_activeStatuses.size) {
|
|
106871
|
+
_hookStatusListener?.(null);
|
|
106872
|
+
return;
|
|
106873
|
+
}
|
|
106874
|
+
_hookStatusListener?.([..._activeStatuses.values()].pop() ?? null);
|
|
106875
|
+
}
|
|
106876
|
+
var _hookMcpCaller = null;
|
|
106877
|
+
function setHookMcpCaller2(fn) {
|
|
106878
|
+
_hookMcpCaller = fn;
|
|
106879
|
+
}
|
|
106880
|
+
function isBackgroundHook(hook) {
|
|
106881
|
+
return hook.type === "command" && (hook.async === true || hook.asyncRewake === true);
|
|
106882
|
+
}
|
|
106883
|
+
function hookGate(hook, event, matcher, dir) {
|
|
106884
|
+
const key = hook.once ? hookIdentity(event, hook, matcher, dir) : void 0;
|
|
106885
|
+
if (key && _hookOnceDone.has(key))
|
|
106886
|
+
return { skip: true };
|
|
106887
|
+
if (isBackgroundHook(hook))
|
|
106888
|
+
return { background: true, key };
|
|
106889
|
+
return { key, statusId: hook.statusMessage ? hookStatusBegin(hook.statusMessage) : void 0 };
|
|
106890
|
+
}
|
|
106891
|
+
function startBackgroundHook(hook, payload, opts) {
|
|
106892
|
+
const statusId = hook.statusMessage ? hookStatusBegin(hook.statusMessage) : void 0;
|
|
106893
|
+
const done = (r2) => {
|
|
106894
|
+
if (statusId !== void 0)
|
|
106895
|
+
hookStatusEnd(statusId);
|
|
106896
|
+
if (r2.status === 0 && opts.key)
|
|
106897
|
+
_hookOnceDone.add(opts.key);
|
|
106898
|
+
const out = (r2.stdout ?? "").toString().trim();
|
|
106899
|
+
if (hook.asyncRewake && r2.status === 2) {
|
|
106900
|
+
const text = (r2.stderr ?? "").toString().trim() || out;
|
|
106901
|
+
_hookDeliveries.push({ kind: "wake", text: text || "Hook asked the session to wake (exit 2).", source: opts.eventLabel });
|
|
106902
|
+
try {
|
|
106903
|
+
_hookWakeListener?.();
|
|
106904
|
+
} catch {
|
|
106905
|
+
}
|
|
106906
|
+
return;
|
|
106907
|
+
}
|
|
106908
|
+
const context = directiveContext(out);
|
|
106909
|
+
if (context)
|
|
106910
|
+
_hookDeliveries.push({ kind: "context", text: context, source: opts.eventLabel });
|
|
106911
|
+
};
|
|
106912
|
+
void spawnHook(String(hook.command ?? ""), { cwd: opts.cwd, timeout: opts.timeoutMs, input: payload, env: opts.env }).then(done, () => done({ status: null, stdout: "", stderr: "" }));
|
|
106913
|
+
}
|
|
106914
|
+
function directiveContext(out) {
|
|
106915
|
+
if (!out.startsWith("{"))
|
|
106916
|
+
return "";
|
|
106917
|
+
try {
|
|
106918
|
+
const j = JSON.parse(out);
|
|
106919
|
+
const parts = [];
|
|
106920
|
+
if (typeof j.additionalContext === "string" && j.additionalContext)
|
|
106921
|
+
parts.push(j.additionalContext);
|
|
106922
|
+
if (typeof j.systemMessage === "string" && j.systemMessage)
|
|
106923
|
+
parts.push(j.systemMessage);
|
|
106924
|
+
return parts.join("\n");
|
|
106925
|
+
} catch {
|
|
106926
|
+
return "";
|
|
106927
|
+
}
|
|
106928
|
+
}
|
|
106803
106929
|
function spawnHook(command, opts) {
|
|
106804
106930
|
return new Promise((resolve12) => {
|
|
106805
106931
|
let stdout = "";
|
|
@@ -106809,7 +106935,8 @@ var require_hooks = __commonJS({
|
|
|
106809
106935
|
if (settled)
|
|
106810
106936
|
return;
|
|
106811
106937
|
settled = true;
|
|
106812
|
-
|
|
106938
|
+
if (timer)
|
|
106939
|
+
clearTimeout(timer);
|
|
106813
106940
|
resolve12({ status, stdout, stderr });
|
|
106814
106941
|
};
|
|
106815
106942
|
let child;
|
|
@@ -106819,7 +106946,7 @@ var require_hooks = __commonJS({
|
|
|
106819
106946
|
resolve12({ status: null, stdout: "", stderr: "" });
|
|
106820
106947
|
return;
|
|
106821
106948
|
}
|
|
106822
|
-
const timer = setTimeout(() => {
|
|
106949
|
+
const timer = opts.timeout === null ? null : setTimeout(() => {
|
|
106823
106950
|
try {
|
|
106824
106951
|
child.kill("SIGTERM");
|
|
106825
106952
|
} catch {
|
|
@@ -106866,9 +106993,85 @@ var require_hooks = __commonJS({
|
|
|
106866
106993
|
return { status: 1, stdout: "", stderr: `hook request failed: ${err.message}` };
|
|
106867
106994
|
}
|
|
106868
106995
|
}
|
|
106996
|
+
async function mcpToolHook(hook, payload) {
|
|
106997
|
+
const caller = _hookMcpCaller;
|
|
106998
|
+
const server = String(hook.server ?? "");
|
|
106999
|
+
const tool = String(hook.tool ?? "");
|
|
107000
|
+
if (!caller) {
|
|
107001
|
+
return { status: 1, stdout: "", stderr: `mcp_tool hook "${server}:${tool}" needs a connected MCP client` };
|
|
107002
|
+
}
|
|
107003
|
+
try {
|
|
107004
|
+
const res = await caller(server, tool, mcpHookInput(hook.input, payload));
|
|
107005
|
+
if ("error" in res)
|
|
107006
|
+
return { status: 1, stdout: "", stderr: res.error };
|
|
107007
|
+
const text = (res.text ?? "").trim();
|
|
107008
|
+
if (!text)
|
|
107009
|
+
return { status: 0, stdout: "", stderr: "" };
|
|
107010
|
+
return { status: 0, stdout: text.startsWith("{") ? text : JSON.stringify({ additionalContext: text }), stderr: "" };
|
|
107011
|
+
} catch (err) {
|
|
107012
|
+
return { status: 1, stdout: "", stderr: `mcp_tool hook ${server}:${tool} failed: ${err.message}` };
|
|
107013
|
+
}
|
|
107014
|
+
}
|
|
107015
|
+
function mcpHookInput(input, payload) {
|
|
107016
|
+
if (!input)
|
|
107017
|
+
return {};
|
|
107018
|
+
let root = {};
|
|
107019
|
+
try {
|
|
107020
|
+
const j = JSON.parse(payload);
|
|
107021
|
+
if (j && typeof j === "object" && !Array.isArray(j))
|
|
107022
|
+
root = j;
|
|
107023
|
+
} catch {
|
|
107024
|
+
}
|
|
107025
|
+
const nav = (parts) => {
|
|
107026
|
+
let cur = root;
|
|
107027
|
+
for (const p of parts) {
|
|
107028
|
+
if (cur === null || typeof cur !== "object")
|
|
107029
|
+
return void 0;
|
|
107030
|
+
cur = cur[p];
|
|
107031
|
+
}
|
|
107032
|
+
return cur;
|
|
107033
|
+
};
|
|
107034
|
+
const lookup = (path33) => {
|
|
107035
|
+
const parts = path33.split(".").map((s2) => s2.trim()).filter(Boolean);
|
|
107036
|
+
if (!parts.length)
|
|
107037
|
+
return void 0;
|
|
107038
|
+
const candidates = [parts];
|
|
107039
|
+
if (parts[0] === "tool_input" || parts[0] === "input") {
|
|
107040
|
+
const rest = parts.slice(1);
|
|
107041
|
+
candidates.unshift(rest, ["input", ...rest], ["tool_input", ...rest]);
|
|
107042
|
+
}
|
|
107043
|
+
for (const c of candidates) {
|
|
107044
|
+
const v = nav(c);
|
|
107045
|
+
if (v !== void 0)
|
|
107046
|
+
return v;
|
|
107047
|
+
}
|
|
107048
|
+
return void 0;
|
|
107049
|
+
};
|
|
107050
|
+
const subst = (v) => {
|
|
107051
|
+
if (typeof v !== "string")
|
|
107052
|
+
return v;
|
|
107053
|
+
const whole = v.match(/^\$\{([^}]+)\}$/);
|
|
107054
|
+
if (whole) {
|
|
107055
|
+
const hit = lookup(whole[1]);
|
|
107056
|
+
return hit === void 0 ? "" : hit;
|
|
107057
|
+
}
|
|
107058
|
+
return v.replace(/\$\{([^}]+)\}/g, (_m, p) => {
|
|
107059
|
+
const hit = lookup(p);
|
|
107060
|
+
if (hit === void 0)
|
|
107061
|
+
return "";
|
|
107062
|
+
return typeof hit === "string" ? hit : JSON.stringify(hit);
|
|
107063
|
+
});
|
|
107064
|
+
};
|
|
107065
|
+
const out = {};
|
|
107066
|
+
for (const [k, val] of Object.entries(input))
|
|
107067
|
+
out[k] = subst(val);
|
|
107068
|
+
return out;
|
|
107069
|
+
}
|
|
106869
107070
|
async function runHookHandler(hook, payload, opts) {
|
|
106870
107071
|
if (hook.type === "http")
|
|
106871
107072
|
return httpHook(hook, payload, opts.timeoutMs);
|
|
107073
|
+
if (hook.type === "mcp_tool")
|
|
107074
|
+
return mcpToolHook(hook, payload);
|
|
106872
107075
|
if (hook.type === "prompt" || hook.type === "agent") {
|
|
106873
107076
|
return promptHook(hook, payload, { ...opts, envCtx: opts.hookEnv });
|
|
106874
107077
|
}
|
|
@@ -107094,22 +107297,36 @@ ${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
|
107094
107297
|
input,
|
|
107095
107298
|
...result ? { result: { output: result.output, error: result.error } } : {}
|
|
107096
107299
|
});
|
|
107300
|
+
const eventLabel = `${phase} (${toolName})`;
|
|
107301
|
+
const hookEnv = {
|
|
107302
|
+
...process.env,
|
|
107303
|
+
NEXRALL_TOOL_NAME: toolName,
|
|
107304
|
+
NEXRALL_TOOL_INPUT: JSON.stringify(input),
|
|
107305
|
+
NEXRALL_HOOK_PHASE: phase
|
|
107306
|
+
};
|
|
107097
107307
|
for (const entry of entries) {
|
|
107098
107308
|
if (!hookMatches(entry.matcher, toolName))
|
|
107099
107309
|
continue;
|
|
107100
107310
|
for (const hook of entry.hooks ?? []) {
|
|
107101
107311
|
if (!isRunnableHook(hook))
|
|
107102
107312
|
continue;
|
|
107103
|
-
const
|
|
107313
|
+
const gate = hookGate(hook, phase, entry.matcher, workDir);
|
|
107314
|
+
if (gate.skip)
|
|
107315
|
+
continue;
|
|
107316
|
+
if (gate.background) {
|
|
107317
|
+
startBackgroundHook(hook, payload, {
|
|
107318
|
+
cwd: workDir,
|
|
107319
|
+
env: hookEnv,
|
|
107320
|
+
eventLabel,
|
|
107321
|
+
timeoutMs: hook.asyncRewake ? hookTimeoutMs(hook, 6e4) : null,
|
|
107322
|
+
key: gate.key
|
|
107323
|
+
});
|
|
107324
|
+
continue;
|
|
107325
|
+
}
|
|
107104
107326
|
const r2 = await runHookHandler(hook, payload, {
|
|
107105
107327
|
cwd: workDir,
|
|
107106
|
-
timeoutMs:
|
|
107107
|
-
env:
|
|
107108
|
-
...process.env,
|
|
107109
|
-
NEXRALL_TOOL_NAME: toolName,
|
|
107110
|
-
NEXRALL_TOOL_INPUT: JSON.stringify(input),
|
|
107111
|
-
NEXRALL_HOOK_PHASE: phase
|
|
107112
|
-
},
|
|
107328
|
+
timeoutMs: hookTimeoutMs(hook, 6e4),
|
|
107329
|
+
env: hookEnv,
|
|
107113
107330
|
...hookOpts
|
|
107114
107331
|
});
|
|
107115
107332
|
const out = (r2.stdout ?? "").toString().trim();
|
|
@@ -107131,17 +107348,33 @@ ${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
|
107131
107348
|
const err = (r2.stderr ?? "").toString().trim();
|
|
107132
107349
|
outcome.reason = err || outcome.reason || `Blocked by ${phase} hook`;
|
|
107133
107350
|
}
|
|
107351
|
+
if (gate.statusId !== void 0)
|
|
107352
|
+
hookStatusEnd(gate.statusId);
|
|
107353
|
+
if (r2.status === 0 && gate.key)
|
|
107354
|
+
_hookOnceDone.add(gate.key);
|
|
107134
107355
|
}
|
|
107135
107356
|
}
|
|
107136
107357
|
return outcome;
|
|
107137
107358
|
}
|
|
107138
|
-
async function runSimpleHooks(defs, workDir, extraEnv, hookOpts) {
|
|
107359
|
+
async function runSimpleHooks(defs, workDir, extraEnv, hookOpts, event = "hook") {
|
|
107139
107360
|
if (!defs?.length)
|
|
107140
107361
|
return;
|
|
107362
|
+
const env4 = extraEnv ? { ...process.env, ...extraEnv } : void 0;
|
|
107141
107363
|
for (const hook of defs) {
|
|
107142
107364
|
if (!isRunnableHook(hook))
|
|
107143
107365
|
continue;
|
|
107144
|
-
|
|
107366
|
+
const gate = hookGate(hook, event, void 0, workDir);
|
|
107367
|
+
if (gate.skip)
|
|
107368
|
+
continue;
|
|
107369
|
+
if (gate.background) {
|
|
107370
|
+
startBackgroundHook(hook, "", { cwd: workDir, env: env4, eventLabel: event, timeoutMs: hook.asyncRewake ? hookTimeoutMs(hook, 1e4) : null, key: gate.key });
|
|
107371
|
+
continue;
|
|
107372
|
+
}
|
|
107373
|
+
const r2 = await runHookHandler(hook, "", { cwd: workDir, timeoutMs: hookTimeoutMs(hook, 1e4), env: env4, ...hookOpts });
|
|
107374
|
+
if (gate.statusId !== void 0)
|
|
107375
|
+
hookStatusEnd(gate.statusId);
|
|
107376
|
+
if (r2.status === 0 && gate.key)
|
|
107377
|
+
_hookOnceDone.add(gate.key);
|
|
107145
107378
|
}
|
|
107146
107379
|
}
|
|
107147
107380
|
function flattenHookDefs(items, matchValue) {
|
|
@@ -107158,7 +107391,7 @@ ${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
|
107158
107391
|
return out;
|
|
107159
107392
|
}
|
|
107160
107393
|
function isKnownHandlerType(t2) {
|
|
107161
|
-
return t2 === "command" || t2 === "http" || t2 === "prompt" || t2 === "agent";
|
|
107394
|
+
return t2 === "command" || t2 === "http" || t2 === "prompt" || t2 === "agent" || t2 === "mcp_tool";
|
|
107162
107395
|
}
|
|
107163
107396
|
function isRunnableHook(hook) {
|
|
107164
107397
|
if (!isKnownHandlerType(hook.type))
|
|
@@ -107167,6 +107400,8 @@ ${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
|
107167
107400
|
return !!hook.command;
|
|
107168
107401
|
if (hook.type === "http")
|
|
107169
107402
|
return !!hook.url;
|
|
107403
|
+
if (hook.type === "mcp_tool")
|
|
107404
|
+
return !!hook.server && !!hook.tool;
|
|
107170
107405
|
return !!hook.prompt;
|
|
107171
107406
|
}
|
|
107172
107407
|
async function runLifecycleHooks(items, event, workDir, payload, matchValue, hookOpts) {
|
|
@@ -107178,6 +107413,19 @@ ${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
|
107178
107413
|
for (const hook of defs) {
|
|
107179
107414
|
if (!isRunnableHook(hook))
|
|
107180
107415
|
continue;
|
|
107416
|
+
const gate = hookGate(hook, event, matchValue, workDir);
|
|
107417
|
+
if (gate.skip)
|
|
107418
|
+
continue;
|
|
107419
|
+
if (gate.background) {
|
|
107420
|
+
startBackgroundHook(hook, input, {
|
|
107421
|
+
cwd: workDir,
|
|
107422
|
+
env: { ...process.env, NEXRALL_HOOK_PHASE: event },
|
|
107423
|
+
eventLabel: event,
|
|
107424
|
+
timeoutMs: hook.asyncRewake ? hookTimeoutMs(hook, 6e4) : null,
|
|
107425
|
+
key: gate.key
|
|
107426
|
+
});
|
|
107427
|
+
continue;
|
|
107428
|
+
}
|
|
107181
107429
|
const timeout = hookTimeoutMs(hook, hook.type === "agent" ? 6e4 : hook.type === "prompt" ? 3e4 : 3e4);
|
|
107182
107430
|
const r2 = await runHookHandler(hook, input, { cwd: workDir, timeoutMs: timeout, env: { ...process.env, NEXRALL_HOOK_PHASE: event }, ...hookOpts });
|
|
107183
107431
|
const out = (r2.stdout ?? "").toString().trim();
|
|
@@ -107212,6 +107460,10 @@ ${out.output}` : `Error: ${out.error}` : out.output ?? "",
|
|
|
107212
107460
|
outcome.block = true;
|
|
107213
107461
|
outcome.reason = (r2.stderr ?? "").toString().trim() || outcome.reason || `Blocked by ${event} hook`;
|
|
107214
107462
|
}
|
|
107463
|
+
if (gate.statusId !== void 0)
|
|
107464
|
+
hookStatusEnd(gate.statusId);
|
|
107465
|
+
if (r2.status === 0 && gate.key)
|
|
107466
|
+
_hookOnceDone.add(gate.key);
|
|
107215
107467
|
}
|
|
107216
107468
|
return outcome;
|
|
107217
107469
|
}
|
|
@@ -107923,6 +108175,11 @@ var require_iterationPolicy = __commonJS({
|
|
|
107923
108175
|
\u{1F6D1} Stopped: the same tool error repeated ${exports2.REPEAT_STALL_LIMIT} rounds in a row, so the agent was looping without making progress.` + (ctx.repeatError ? ` The recurring error was:
|
|
107924
108176
|
${ctx.repeatError}
|
|
107925
108177
|
` : "\n") + `Fix that underlying cause (or grant the needed permission) and send "continue".
|
|
108178
|
+
`;
|
|
108179
|
+
case "hook-blocked":
|
|
108180
|
+
return `
|
|
108181
|
+
\u26D4 A PostToolBatch hook stopped the turn before the next model call` + (ctx.hookReason ? `: ${ctx.hookReason}` : ".") + `
|
|
108182
|
+
The reason is in the conversation, so send "continue" once the cause is handled.
|
|
107926
108183
|
`;
|
|
107927
108184
|
case "budget":
|
|
107928
108185
|
return `
|
|
@@ -108523,7 +108780,10 @@ ${body}`);
|
|
|
108523
108780
|
"no-balance",
|
|
108524
108781
|
"no-team-budget",
|
|
108525
108782
|
"team-unavailable",
|
|
108526
|
-
"reported-elsewhere"
|
|
108783
|
+
"reported-elsewhere",
|
|
108784
|
+
// A hook stopping the batch means the sub-agent stopped short of its report, so the
|
|
108785
|
+
// parent must not read the result as a finished one.
|
|
108786
|
+
"hook-blocked"
|
|
108527
108787
|
]);
|
|
108528
108788
|
exports2.SUBAGENT_PREAMBLE = [
|
|
108529
108789
|
"# You are a sub-agent",
|
|
@@ -109232,8 +109492,8 @@ var require_loop = __commonJS({
|
|
|
109232
109492
|
"../core/dist/agent/loop.js"(exports2) {
|
|
109233
109493
|
"use strict";
|
|
109234
109494
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
109235
|
-
exports2.
|
|
109236
|
-
exports2.lastToolResults = exports2.summariseSubTaskProgress = exports2.capSubTaskText = exports2.extractSubTaskText = exports2.ToolNotAllowedError = void 0;
|
|
109495
|
+
exports2.createLimiter = exports2.resolveMaxSubagentsPerSession = exports2.resolveMaxConcurrentSubtasks = exports2.lockPathsFor = exports2.resolveMaxIterations = exports2.stopReasonNotice = exports2.executeAgentMemoryWrite = exports2.AGENT_MEMORY_TOOL_SCHEMA = exports2.AGENT_MEMORY_TOOL = exports2._stallLimits = exports2.errorRoundSignature = exports2._emptyTurnRetry = exports2.shouldRetryEmptyTurn = exports2.emptyTurnBackoffMs = exports2.compactMessagesForResume = exports2.estimateTokensRough = exports2.makeCachedSummarizer = exports2.pruneOldToolResults = exports2.ledgerSummary = exports2.ledgerRecord = exports2.createLedger = exports2.transcriptOf = exports2.persistRuntimeContext = exports2.findSafeCutIndex = exports2.VERIFY_CMD_RE = exports2.allowsTestOnlyWrite = exports2.WRITE_TOOL_NAMES = exports2.estimateBodyBytes = exports2.pruneReclaimFloor = exports2.compactionThresholds = exports2.compactionLimits = exports2.contextWindowFor = exports2.resetHookOnceState = exports2.setHookMcpCaller = exports2.setHookStatusListener = exports2.setHookWakeListener = exports2.formatHookDeliveries = exports2.hasPendingHookWake = exports2.takeHookWakes = exports2.drainHookDeliveries = exports2.fireObserverHook = exports2.fireManualPreCompactHook = exports2.fireManualPostCompactHook = exports2.fireNotificationHooks = exports2.runPermissionRequestHooks = exports2.runLifecycleHooks = exports2.classifyStopFailure = exports2.parsePromptHookReply = exports2.loadHooks = exports2.bashNeedsRepoLock = void 0;
|
|
109496
|
+
exports2.lastToolResults = exports2.summariseSubTaskProgress = exports2.capSubTaskText = exports2.extractSubTaskText = exports2.ToolNotAllowedError = exports2.resolveSubtaskTimeoutMs = exports2.canSpawnSubAgents = exports2.intersectAllowlists = exports2.noSpawnReason = exports2.resolveMaxSubagentDepth = exports2._sessionSubAgentCount = exports2.resetSessionSubAgentBudget = exports2._resetSubTaskLimiter = void 0;
|
|
109237
109497
|
exports2.dispatchSubAgent = dispatchSubAgent;
|
|
109238
109498
|
exports2.dispatchBackgroundSubAgent = dispatchBackgroundSubAgent;
|
|
109239
109499
|
exports2.runAgentLoop = runAgentLoop2;
|
|
@@ -109244,6 +109504,7 @@ var require_loop = __commonJS({
|
|
|
109244
109504
|
var types_1 = require_types();
|
|
109245
109505
|
var client_1 = require_client();
|
|
109246
109506
|
var executor_1 = require_executor();
|
|
109507
|
+
var sharedTasks_1 = require_sharedTasks();
|
|
109247
109508
|
var agentTypes_1 = require_agentTypes();
|
|
109248
109509
|
var skills_1 = require_skills();
|
|
109249
109510
|
var rules_1 = require_rules();
|
|
@@ -109291,6 +109552,30 @@ var require_loop = __commonJS({
|
|
|
109291
109552
|
Object.defineProperty(exports2, "fireObserverHook", { enumerable: true, get: function() {
|
|
109292
109553
|
return hooks_2.fireObserverHook;
|
|
109293
109554
|
} });
|
|
109555
|
+
Object.defineProperty(exports2, "drainHookDeliveries", { enumerable: true, get: function() {
|
|
109556
|
+
return hooks_2.drainHookDeliveries;
|
|
109557
|
+
} });
|
|
109558
|
+
Object.defineProperty(exports2, "takeHookWakes", { enumerable: true, get: function() {
|
|
109559
|
+
return hooks_2.takeHookWakes;
|
|
109560
|
+
} });
|
|
109561
|
+
Object.defineProperty(exports2, "hasPendingHookWake", { enumerable: true, get: function() {
|
|
109562
|
+
return hooks_2.hasPendingHookWake;
|
|
109563
|
+
} });
|
|
109564
|
+
Object.defineProperty(exports2, "formatHookDeliveries", { enumerable: true, get: function() {
|
|
109565
|
+
return hooks_2.formatHookDeliveries;
|
|
109566
|
+
} });
|
|
109567
|
+
Object.defineProperty(exports2, "setHookWakeListener", { enumerable: true, get: function() {
|
|
109568
|
+
return hooks_2.setHookWakeListener;
|
|
109569
|
+
} });
|
|
109570
|
+
Object.defineProperty(exports2, "setHookStatusListener", { enumerable: true, get: function() {
|
|
109571
|
+
return hooks_2.setHookStatusListener;
|
|
109572
|
+
} });
|
|
109573
|
+
Object.defineProperty(exports2, "setHookMcpCaller", { enumerable: true, get: function() {
|
|
109574
|
+
return hooks_2.setHookMcpCaller;
|
|
109575
|
+
} });
|
|
109576
|
+
Object.defineProperty(exports2, "resetHookOnceState", { enumerable: true, get: function() {
|
|
109577
|
+
return hooks_2.resetHookOnceState;
|
|
109578
|
+
} });
|
|
109294
109579
|
var compaction_1 = require_compaction();
|
|
109295
109580
|
var compaction_2 = require_compaction();
|
|
109296
109581
|
Object.defineProperty(exports2, "contextWindowFor", { enumerable: true, get: function() {
|
|
@@ -109465,6 +109750,27 @@ var require_loop = __commonJS({
|
|
|
109465
109750
|
subAgentBudget_1._inFlightByDepth.delete(childDepth);
|
|
109466
109751
|
}
|
|
109467
109752
|
}
|
|
109753
|
+
async function taskHookVeto(entries, event, input, options, extra = {}) {
|
|
109754
|
+
if (!entries?.length)
|
|
109755
|
+
return null;
|
|
109756
|
+
const taskId = typeof input.task_id === "string" ? input.task_id : "";
|
|
109757
|
+
const task = extra.task_subject ? null : (0, sharedTasks_1.listSharedTasks)(options.workDir).find((t2) => t2.id === taskId);
|
|
109758
|
+
const payload = {
|
|
109759
|
+
session_id: options.sessionId ?? "",
|
|
109760
|
+
...taskId ? { task_id: taskId } : {},
|
|
109761
|
+
...task ? { task_subject: task.content, task_description: task.content } : {},
|
|
109762
|
+
...extra,
|
|
109763
|
+
tool_input: input
|
|
109764
|
+
};
|
|
109765
|
+
try {
|
|
109766
|
+
const outcome = await (0, hooks_1.runLifecycleHooks)(entries, event, options.workDir, payload, void 0, (0, hooks_1.hookRunOptsFor)(options));
|
|
109767
|
+
if (!outcome.block)
|
|
109768
|
+
return null;
|
|
109769
|
+
return `Refused by ${event} hook${outcome.reason ? `: ${outcome.reason}` : ""}`;
|
|
109770
|
+
} catch {
|
|
109771
|
+
return null;
|
|
109772
|
+
}
|
|
109773
|
+
}
|
|
109468
109774
|
function dispatchBackgroundSubAgent(input, options, agentTypes, hub) {
|
|
109469
109775
|
const overBudget = (0, subAgentBudget_1.claimSessionSubAgentSlot)(options.workDir, options.onNotice ?? options.onText, options.sessionId);
|
|
109470
109776
|
if (overBudget)
|
|
@@ -109668,6 +109974,7 @@ ${ctx}
|
|
|
109668
109974
|
let repeatedErrorRounds = 0;
|
|
109669
109975
|
let lastErrorSignature = "";
|
|
109670
109976
|
let stalledRepeatError = null;
|
|
109977
|
+
let hookBlockedReason = null;
|
|
109671
109978
|
let budget = maxIterations;
|
|
109672
109979
|
let iteration = 0;
|
|
109673
109980
|
let emptyTurnRetries = 0;
|
|
@@ -109851,7 +110158,8 @@ ${ctx}
|
|
|
109851
110158
|
const queued = options.takePendingInput?.() ?? [];
|
|
109852
110159
|
const peerMsgs = options.drainPeerMessages?.() ?? [];
|
|
109853
110160
|
const bgDone = drainBackgroundNotifications();
|
|
109854
|
-
|
|
110161
|
+
const hookMsgs = (0, hooks_1.drainHookDeliveries)();
|
|
110162
|
+
if (queued.length || peerMsgs.length || bgDone.length || hookMsgs.length) {
|
|
109855
110163
|
const parts = [];
|
|
109856
110164
|
if (queued.length) {
|
|
109857
110165
|
parts.push(queued.join("\n\n"));
|
|
@@ -109863,6 +110171,8 @@ ${ctx}
|
|
|
109863
110171
|
}
|
|
109864
110172
|
if (bgDone.length)
|
|
109865
110173
|
parts.push((0, backgroundAgents_1.formatBackgroundNotifications)(bgDone));
|
|
110174
|
+
if (hookMsgs.length)
|
|
110175
|
+
parts.push((0, hooks_1.formatHookDeliveries)(hookMsgs));
|
|
109866
110176
|
messages.push({ role: "user", content: [{ type: "text", text: parts.join("\n\n") }] });
|
|
109867
110177
|
continue;
|
|
109868
110178
|
}
|
|
@@ -109895,7 +110205,8 @@ ${ctx}
|
|
|
109895
110205
|
const queued = options.takePendingInput?.() ?? [];
|
|
109896
110206
|
const peerMsgs = options.drainPeerMessages?.() ?? [];
|
|
109897
110207
|
const bgDone = drainBackgroundNotifications();
|
|
109898
|
-
|
|
110208
|
+
const hookMsgs = (0, hooks_1.drainHookDeliveries)();
|
|
110209
|
+
if (queued.length || peerMsgs.length || bgDone.length || hookMsgs.length) {
|
|
109899
110210
|
const parts = [];
|
|
109900
110211
|
if (queued.length) {
|
|
109901
110212
|
parts.push(queued.join("\n\n"));
|
|
@@ -109907,6 +110218,8 @@ ${ctx}
|
|
|
109907
110218
|
}
|
|
109908
110219
|
if (bgDone.length)
|
|
109909
110220
|
parts.push((0, backgroundAgents_1.formatBackgroundNotifications)(bgDone));
|
|
110221
|
+
if (hookMsgs.length)
|
|
110222
|
+
parts.push((0, hooks_1.formatHookDeliveries)(hookMsgs));
|
|
109910
110223
|
messages.push({ role: "user", content: [{ type: "text", text: parts.join("\n\n") }] });
|
|
109911
110224
|
continue;
|
|
109912
110225
|
}
|
|
@@ -110065,7 +110378,16 @@ ${ctx}
|
|
|
110065
110378
|
if (pre.block) {
|
|
110066
110379
|
result = { error: `Blocked by PreToolUse hook: ${pre.reason}` };
|
|
110067
110380
|
} else {
|
|
110381
|
+
const taskIdsBefore = name === "create_shared_task" ? new Set((0, sharedTasks_1.listSharedTasks)(options.workDir).map((t2) => t2.id)) : null;
|
|
110068
110382
|
try {
|
|
110383
|
+
if (name === "update_shared_task_status" && String(input.status ?? "") === "completed") {
|
|
110384
|
+
const veto = await taskHookVeto(hooks.TaskCompleted, "TaskCompleted", input, options);
|
|
110385
|
+
if (veto) {
|
|
110386
|
+
result = { error: veto };
|
|
110387
|
+
options.onToolResult(name, result, void 0, toolMeta);
|
|
110388
|
+
return { block: { ...block, id }, result };
|
|
110389
|
+
}
|
|
110390
|
+
}
|
|
110069
110391
|
if (name === iterationPolicy_1.AGENT_MEMORY_TOOL) {
|
|
110070
110392
|
result = await (0, iterationPolicy_1.executeAgentMemoryWrite)(input, options._agentMemory, options.workDir);
|
|
110071
110393
|
options.onToolResult(name, result, void 0, toolMeta);
|
|
@@ -110103,6 +110425,21 @@ ${ctx}
|
|
|
110103
110425
|
} catch (err) {
|
|
110104
110426
|
result = { error: `Tool execution failed: ${err.message}` };
|
|
110105
110427
|
}
|
|
110428
|
+
if (name === "create_shared_task" && result.error === void 0 && taskIdsBefore) {
|
|
110429
|
+
const created = (0, sharedTasks_1.listSharedTasks)(options.workDir).filter((t2) => !taskIdsBefore.has(t2.id) && typeof input.content === "string" && t2.content === input.content);
|
|
110430
|
+
const task = created[created.length - 1];
|
|
110431
|
+
if (task) {
|
|
110432
|
+
const veto = await taskHookVeto(hooks.TaskCreated, "TaskCreated", input, options, {
|
|
110433
|
+
task_id: task.id,
|
|
110434
|
+
task_subject: task.content,
|
|
110435
|
+
task_description: task.content
|
|
110436
|
+
});
|
|
110437
|
+
if (veto) {
|
|
110438
|
+
(0, sharedTasks_1.deleteSharedTask)(options.workDir, task.id);
|
|
110439
|
+
result = { error: veto };
|
|
110440
|
+
}
|
|
110441
|
+
}
|
|
110442
|
+
}
|
|
110106
110443
|
if (name === "memory_write" && result.error === void 0) {
|
|
110107
110444
|
const scope = input.scope === "global" ? "global" : "project";
|
|
110108
110445
|
void (0, compaction_1.maybeCompactMemory)(scope, options);
|
|
@@ -110194,6 +110531,32 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
110194
110531
|
if (bgFinished.length) {
|
|
110195
110532
|
toolResultContent.push({ type: "text", text: (0, backgroundAgents_1.formatBackgroundNotifications)(bgFinished) });
|
|
110196
110533
|
}
|
|
110534
|
+
const hookDeliveries = (0, hooks_1.drainHookDeliveries)();
|
|
110535
|
+
if (hookDeliveries.length) {
|
|
110536
|
+
toolResultContent.push({ type: "text", text: (0, hooks_1.formatHookDeliveries)(hookDeliveries) });
|
|
110537
|
+
}
|
|
110538
|
+
let postBatchStop = null;
|
|
110539
|
+
if (hooks.PostToolBatch?.length) {
|
|
110540
|
+
const batch = await (0, hooks_1.runLifecycleHooks)(hooks.PostToolBatch, "PostToolBatch", options.workDir, {
|
|
110541
|
+
tool_calls: toolResults.map(({ block: b, result: r2 }) => ({
|
|
110542
|
+
tool_name: b.name,
|
|
110543
|
+
tool_input: b.input,
|
|
110544
|
+
tool_use_id: b.id,
|
|
110545
|
+
tool_response: r2.error !== void 0 ? r2.output ? `Error: ${r2.error}
|
|
110546
|
+
|
|
110547
|
+
${r2.output}` : `Error: ${r2.error}` : r2.output ?? ""
|
|
110548
|
+
}))
|
|
110549
|
+
}, void 0, (0, hooks_1.hookRunOptsFor)(options));
|
|
110550
|
+
if (batch.context)
|
|
110551
|
+
toolResultContent.push({ type: "text", text: batch.context });
|
|
110552
|
+
if (batch.block) {
|
|
110553
|
+
postBatchStop = batch.reason?.trim() || "a PostToolBatch hook stopped the turn";
|
|
110554
|
+
toolResultContent.push({
|
|
110555
|
+
type: "text",
|
|
110556
|
+
text: `A PostToolBatch hook stopped the turn before the next model call: ${postBatchStop}`
|
|
110557
|
+
});
|
|
110558
|
+
}
|
|
110559
|
+
}
|
|
110197
110560
|
const toolResultMessage = {
|
|
110198
110561
|
role: "user",
|
|
110199
110562
|
content: toolResultContent
|
|
@@ -110201,6 +110564,11 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
110201
110564
|
messages.push(toolResultMessage);
|
|
110202
110565
|
completedRounds++;
|
|
110203
110566
|
options.onProgress?.(messages);
|
|
110567
|
+
if (postBatchStop) {
|
|
110568
|
+
stopReason = "hook-blocked";
|
|
110569
|
+
hookBlockedReason = postBatchStop;
|
|
110570
|
+
break;
|
|
110571
|
+
}
|
|
110204
110572
|
const errored = toolResults.filter(({ result }) => result.error !== void 0);
|
|
110205
110573
|
const allErrored = toolResults.length > 0 && errored.length === toolResults.length;
|
|
110206
110574
|
consecutiveErrorRounds = allErrored ? consecutiveErrorRounds + 1 : 0;
|
|
@@ -110234,7 +110602,7 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
110234
110602
|
const apiFailure = (0, hooks_1.apiFailureForStopReason)(stopReason);
|
|
110235
110603
|
if (apiFailure)
|
|
110236
110604
|
await fireStopFailure(apiFailure);
|
|
110237
|
-
const notice = (0, iterationPolicy_1.stopReasonNotice)(stopReason, { budget, repeatError: stalledRepeatError });
|
|
110605
|
+
const notice = (0, iterationPolicy_1.stopReasonNotice)(stopReason, { budget, repeatError: stalledRepeatError, hookReason: hookBlockedReason });
|
|
110238
110606
|
if (options._onStopReason)
|
|
110239
110607
|
options._onStopReason(stopReason, notice || null);
|
|
110240
110608
|
else if (notice)
|
|
@@ -155286,7 +155654,7 @@ import * as os18 from "os";
|
|
|
155286
155654
|
import * as crypto7 from "crypto";
|
|
155287
155655
|
import { createRequire } from "module";
|
|
155288
155656
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
155289
|
-
import {
|
|
155657
|
+
import { execFile as execFile2, execFileSync as execFileSync5 } from "child_process";
|
|
155290
155658
|
|
|
155291
155659
|
// src/permissions/handler.ts
|
|
155292
155660
|
import * as readline2 from "readline";
|
|
@@ -172348,12 +172716,16 @@ function resolveModelLabel(alias) {
|
|
|
172348
172716
|
const id = normaliseModelId(alias);
|
|
172349
172717
|
return (0, import_code_core18.liveLabelFor)(id, MODEL_LABELS[id] ?? id);
|
|
172350
172718
|
}
|
|
172351
|
-
function
|
|
172352
|
-
|
|
172353
|
-
|
|
172354
|
-
|
|
172355
|
-
|
|
172356
|
-
|
|
172719
|
+
async function tryExecAsync(file, args, cwd2) {
|
|
172720
|
+
return new Promise((resolve12) => {
|
|
172721
|
+
try {
|
|
172722
|
+
execFile2(file, args, { cwd: cwd2, encoding: "utf-8" }, (err, stdout) => {
|
|
172723
|
+
resolve12(err ? void 0 : String(stdout).trim() || void 0);
|
|
172724
|
+
});
|
|
172725
|
+
} catch {
|
|
172726
|
+
resolve12(void 0);
|
|
172727
|
+
}
|
|
172728
|
+
});
|
|
172357
172729
|
}
|
|
172358
172730
|
var BILLING_URL = "https://app.nexrall.com/?settings=billing";
|
|
172359
172731
|
function hyperlink(label, url) {
|
|
@@ -172381,28 +172753,29 @@ function currentUserLabel() {
|
|
|
172381
172753
|
return "there";
|
|
172382
172754
|
}
|
|
172383
172755
|
}
|
|
172384
|
-
function collectEnv(workDir) {
|
|
172756
|
+
async function collectEnv(workDir) {
|
|
172385
172757
|
return {
|
|
172386
172758
|
cwd: workDir,
|
|
172387
172759
|
platform: `${os18.platform()} ${os18.release()}`,
|
|
172388
172760
|
shell: process.env.SHELL ?? process.env.ComSpec ?? "unknown",
|
|
172389
172761
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
172390
|
-
...collectGitEnv(workDir)
|
|
172762
|
+
...await collectGitEnv(workDir)
|
|
172391
172763
|
};
|
|
172392
172764
|
}
|
|
172393
|
-
function collectGitEnv(workDir) {
|
|
172394
|
-
|
|
172395
|
-
|
|
172396
|
-
|
|
172397
|
-
|
|
172398
|
-
|
|
172399
|
-
|
|
172765
|
+
async function collectGitEnv(workDir) {
|
|
172766
|
+
const [gitBranch2, gitStatus, gitDiff, recentCommits] = await Promise.all([
|
|
172767
|
+
tryExecAsync("git", ["branch", "--show-current"], workDir),
|
|
172768
|
+
tryExecAsync("git", ["status", "--short"], workDir),
|
|
172769
|
+
tryExecAsync("git", ["diff", "--stat", "HEAD"], workDir),
|
|
172770
|
+
tryExecAsync("git", ["log", "--oneline", "-5"], workDir)
|
|
172771
|
+
]);
|
|
172772
|
+
return { gitBranch: gitBranch2, gitStatus, gitDiff, recentCommits };
|
|
172400
172773
|
}
|
|
172401
|
-
function refreshEnvForTurn(env4, workDir) {
|
|
172774
|
+
async function refreshEnvForTurn(env4, workDir) {
|
|
172402
172775
|
return {
|
|
172403
172776
|
...env4,
|
|
172404
172777
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
172405
|
-
...collectGitEnv(workDir)
|
|
172778
|
+
...await collectGitEnv(workDir)
|
|
172406
172779
|
};
|
|
172407
172780
|
}
|
|
172408
172781
|
var noDiscovery = false;
|
|
@@ -172586,6 +172959,10 @@ var Spinner = class {
|
|
|
172586
172959
|
verbIdx = 0;
|
|
172587
172960
|
thinkTokens = 0;
|
|
172588
172961
|
thinkText = "";
|
|
172962
|
+
// A running hook's `statusMessage` (Claude Code). While set it REPLACES the label —
|
|
172963
|
+
// the whole point is telling the user which hook is producing the wait — and the
|
|
172964
|
+
// normal label returns the moment the hook finishes (listener sends null).
|
|
172965
|
+
hookStatus = "";
|
|
172589
172966
|
start(text, opts) {
|
|
172590
172967
|
this.stop();
|
|
172591
172968
|
this.baseText = text;
|
|
@@ -172640,13 +173017,24 @@ var Spinner = class {
|
|
|
172640
173017
|
return;
|
|
172641
173018
|
this.baseText = text;
|
|
172642
173019
|
}
|
|
173020
|
+
/**
|
|
173021
|
+
* A hook with `statusMessage` started (message) or finished (null). Renders immediately
|
|
173022
|
+
* rather than on the next tick: the whole point of the message is that a long hook is
|
|
173023
|
+
* RUNNING, and waiting up to 100ms to admit that is the kind of silence it exists to fix.
|
|
173024
|
+
* No-op while the spinner is stopped — an idle session keeps its prompt, not a status line.
|
|
173025
|
+
*/
|
|
173026
|
+
setHookStatus(message) {
|
|
173027
|
+
this.hookStatus = message ?? "";
|
|
173028
|
+
if (this.interval !== null)
|
|
173029
|
+
this.render();
|
|
173030
|
+
}
|
|
172643
173031
|
render() {
|
|
172644
173032
|
const elapsedSec = Math.floor((Date.now() - this.startedAt) / 1e3);
|
|
172645
173033
|
if (this.verbs && elapsedSec > 0 && elapsedSec % VERB_ROTATE_SEC === 0 && this.lastRotateSec !== elapsedSec) {
|
|
172646
173034
|
this.lastRotateSec = elapsedSec;
|
|
172647
173035
|
this.verbIdx++;
|
|
172648
173036
|
}
|
|
172649
|
-
const label = this.verbs ? `${WORKING_VERBS[this.verbIdx % WORKING_VERBS.length]}\u2026` : this.baseText;
|
|
173037
|
+
const label = this.hookStatus || (this.verbs ? `${WORKING_VERBS[this.verbIdx % WORKING_VERBS.length]}\u2026` : this.baseText);
|
|
172650
173038
|
const status = composeStatusLine({
|
|
172651
173039
|
frame: this.frames[this.i % this.frames.length],
|
|
172652
173040
|
text: label,
|
|
@@ -172695,6 +173083,7 @@ async function initMcp(workDir, override, strict) {
|
|
|
172695
173083
|
if (noDiscovery && !override) {
|
|
172696
173084
|
_mcpConfig = { mcpServers: {} };
|
|
172697
173085
|
_mcpManager = null;
|
|
173086
|
+
wireHookMcpCaller();
|
|
172698
173087
|
return;
|
|
172699
173088
|
}
|
|
172700
173089
|
_mcpConfig = strict && override ? { mcpServers: {} } : import_code_core18.McpManager.loadConfig(workDir);
|
|
@@ -172702,6 +173091,7 @@ async function initMcp(workDir, override, strict) {
|
|
|
172702
173091
|
Object.assign(_mcpConfig.mcpServers, override.mcpServers);
|
|
172703
173092
|
if (Object.keys(_mcpConfig.mcpServers).length === 0) {
|
|
172704
173093
|
_mcpManager = null;
|
|
173094
|
+
wireHookMcpCaller();
|
|
172705
173095
|
return;
|
|
172706
173096
|
}
|
|
172707
173097
|
try {
|
|
@@ -172711,6 +173101,18 @@ async function initMcp(workDir, override, strict) {
|
|
|
172711
173101
|
const manager = new import_code_core18.McpManager();
|
|
172712
173102
|
await manager.connectAll(_mcpConfig);
|
|
172713
173103
|
_mcpManager = manager;
|
|
173104
|
+
wireHookMcpCaller();
|
|
173105
|
+
}
|
|
173106
|
+
function wireHookMcpCaller() {
|
|
173107
|
+
const mgr = _mcpManager;
|
|
173108
|
+
if (!mgr) {
|
|
173109
|
+
(0, import_code_core19.setHookMcpCaller)(null);
|
|
173110
|
+
return;
|
|
173111
|
+
}
|
|
173112
|
+
(0, import_code_core19.setHookMcpCaller)(async (server, tool, input) => {
|
|
173113
|
+
const text = await mgr.callTool(`${server}__${tool}`, input);
|
|
173114
|
+
return text === null ? { error: `MCP server "${server}" has no tool "${tool}" (or the server is not connected)` } : { text };
|
|
173115
|
+
});
|
|
172714
173116
|
}
|
|
172715
173117
|
function formatAgentsList(workDir) {
|
|
172716
173118
|
const { types: types3, warnings } = (0, import_code_core18.loadAgentTypesWithWarnings)(workDir);
|
|
@@ -173086,6 +173488,7 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrall
|
|
|
173086
173488
|
const turnStart = Date.now();
|
|
173087
173489
|
userActiveThisTurn = false;
|
|
173088
173490
|
const spinner = new Spinner();
|
|
173491
|
+
(0, import_code_core19.setHookStatusListener)((m2) => spinner.setHookStatus(m2));
|
|
173089
173492
|
const mdRender = new MarkdownStreamRenderer();
|
|
173090
173493
|
const toolStream = new ToolStreamPrinter(PREVIEW_LINES);
|
|
173091
173494
|
let toolStartTime = 0;
|
|
@@ -173112,7 +173515,7 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrall
|
|
|
173112
173515
|
workDir,
|
|
173113
173516
|
sessionId: activeSessionIdGetter(),
|
|
173114
173517
|
model: modelAlias,
|
|
173115
|
-
env: refreshEnvForTurn(env4, workDir),
|
|
173518
|
+
env: await refreshEnvForTurn(env4, workDir),
|
|
173116
173519
|
nexrallMd,
|
|
173117
173520
|
mode,
|
|
173118
173521
|
// `/mode plan` previously only hinted to the backend — the footer said "plan
|
|
@@ -173465,7 +173868,7 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
173465
173868
|
workDir,
|
|
173466
173869
|
sessionId: activeSessionIdGetter(),
|
|
173467
173870
|
model: modelAlias,
|
|
173468
|
-
env: refreshEnvForTurn(env4, workDir),
|
|
173871
|
+
env: await refreshEnvForTurn(env4, workDir),
|
|
173469
173872
|
nexrallMd,
|
|
173470
173873
|
mode,
|
|
173471
173874
|
planMode: mode === "plan",
|
|
@@ -173991,7 +174394,7 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
173991
174394
|
void (0, import_code_core19.fireObserverHook)(requestedWorkDir, "WorktreeRemove", { name: worktreeState.name, path: worktreeState.worktreePath }, worktreeState.name);
|
|
173992
174395
|
});
|
|
173993
174396
|
}
|
|
173994
|
-
const env4 = collectEnv(workDir);
|
|
174397
|
+
const env4 = await collectEnv(workDir);
|
|
173995
174398
|
let briefBase = options.systemPrompt?.trim() ?? readNexrallMd(workDir);
|
|
173996
174399
|
const agentPrefix = options.selectedAgent?.prompt?.trim();
|
|
173997
174400
|
const briefParts = [agentPrefix, briefBase, options.appendSystemPrompt?.trim(), addDirNote(options.addDirs ?? []), options.jsonSchema ? schemaInstruction(options.jsonSchema) : ""];
|
|
@@ -175114,6 +175517,7 @@ ${text}` : "");
|
|
|
175114
175517
|
activeGoal = null;
|
|
175115
175518
|
criteriaLastLine = "";
|
|
175116
175519
|
cliBackgroundAgents.stopAll({ dropPending: true });
|
|
175520
|
+
(0, import_code_core19.resetHookOnceState)();
|
|
175117
175521
|
inputBuffer = "";
|
|
175118
175522
|
if (interactive)
|
|
175119
175523
|
await getInkTerminal().clearTranscript();
|
|
@@ -175320,7 +175724,7 @@ ${summaryText}` }] },
|
|
|
175320
175724
|
}
|
|
175321
175725
|
const readme = tryRead(path29.join(workDir, "README.md"))?.slice(0, 2e3) ?? "";
|
|
175322
175726
|
const pkgJson = tryRead(path29.join(workDir, "package.json"))?.slice(0, 1e3) ?? "";
|
|
175323
|
-
const dirList =
|
|
175727
|
+
const dirList = (await tryExecAsync("ls", ["-la"], workDir))?.slice(0, 500) ?? "";
|
|
175324
175728
|
const initPrompt = `Analyze this project and write a concise nexrall.md (project-specific instructions for an AI coding assistant).
|
|
175325
175729
|
Include: project overview, tech stack, coding conventions, important files/folders, what to avoid.
|
|
175326
175730
|
Keep it under 400 words. Use markdown. Be specific and actionable.
|
|
@@ -177246,6 +177650,7 @@ ${text}
|
|
|
177246
177650
|
rl.resume();
|
|
177247
177651
|
rl.prompt();
|
|
177248
177652
|
deliverBackgroundWhenIdle();
|
|
177653
|
+
deliverHookWakeWhenIdle();
|
|
177249
177654
|
});
|
|
177250
177655
|
async function runGoalLoop() {
|
|
177251
177656
|
while (activeGoal) {
|
|
@@ -177326,6 +177731,20 @@ ${text}
|
|
|
177326
177731
|
bgLastCount = n;
|
|
177327
177732
|
deliverBackgroundWhenIdle();
|
|
177328
177733
|
});
|
|
177734
|
+
let hookWakeTimer = null;
|
|
177735
|
+
function deliverHookWakeWhenIdle() {
|
|
177736
|
+
if (hookWakeTimer || agentRunning || !(0, import_code_core19.hasPendingHookWake)())
|
|
177737
|
+
return;
|
|
177738
|
+
hookWakeTimer = setTimeout(() => {
|
|
177739
|
+
hookWakeTimer = null;
|
|
177740
|
+
if (agentRunning || !(0, import_code_core19.hasPendingHookWake)())
|
|
177741
|
+
return;
|
|
177742
|
+
const wakes = (0, import_code_core19.takeHookWakes)();
|
|
177743
|
+
console.log(paint.dim(` \u2699 hook wake \u2014 continuing`));
|
|
177744
|
+
rl.emit("line", (0, import_code_core19.formatHookDeliveries)(wakes));
|
|
177745
|
+
}, 400);
|
|
177746
|
+
}
|
|
177747
|
+
(0, import_code_core19.setHookWakeListener)(deliverHookWakeWhenIdle);
|
|
177329
177748
|
const loopTimer = setInterval(() => {
|
|
177330
177749
|
if (loopScheduler.size === 0)
|
|
177331
177750
|
return;
|