nexrall-code 0.5.176 → 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 +1083 -84
- 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)
|
|
@@ -110527,6 +110895,7 @@ var require_client2 = __commonJS({
|
|
|
110527
110895
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
110528
110896
|
exports2.McpClient = void 0;
|
|
110529
110897
|
exports2.flattenResourceContents = flattenResourceContents;
|
|
110898
|
+
exports2.flattenPromptMessages = flattenPromptMessages;
|
|
110530
110899
|
var child_process_1 = __require("child_process");
|
|
110531
110900
|
function flattenResourceContents(result, maxChars = 1e5) {
|
|
110532
110901
|
const contents = result?.contents ?? [];
|
|
@@ -110539,6 +110908,31 @@ var require_client2 = __commonJS({
|
|
|
110539
110908
|
}).filter(Boolean);
|
|
110540
110909
|
const text = parts.join("\n");
|
|
110541
110910
|
return text.length > maxChars ? text.slice(0, maxChars) + `
|
|
110911
|
+
\u2026 [truncated, ${text.length - maxChars} more characters]` : text;
|
|
110912
|
+
}
|
|
110913
|
+
function flattenPromptMessages(result, maxChars = 1e5) {
|
|
110914
|
+
const messages = result?.messages ?? [];
|
|
110915
|
+
const parts = messages.map((m2) => {
|
|
110916
|
+
const content = m2?.content;
|
|
110917
|
+
const items = Array.isArray(content) ? content : content ? [content] : [];
|
|
110918
|
+
return items.map((c) => {
|
|
110919
|
+
const item = c;
|
|
110920
|
+
if (item?.type === "text" && typeof item.text === "string")
|
|
110921
|
+
return item.text;
|
|
110922
|
+
if (item?.type === "image")
|
|
110923
|
+
return `[image prompt content (${item.mimeType ?? "unknown type"}) not shown]`;
|
|
110924
|
+
if (item?.type === "audio")
|
|
110925
|
+
return `[audio prompt content (${item.mimeType ?? "unknown type"}) not shown]`;
|
|
110926
|
+
if (item?.type === "resource") {
|
|
110927
|
+
if (typeof item.resource?.text === "string")
|
|
110928
|
+
return item.resource.text;
|
|
110929
|
+
return `[resource prompt content (${item.resource?.uri ?? "unknown uri"}) not shown]`;
|
|
110930
|
+
}
|
|
110931
|
+
return "";
|
|
110932
|
+
}).filter(Boolean).join("\n");
|
|
110933
|
+
}).filter(Boolean);
|
|
110934
|
+
const text = parts.join("\n\n");
|
|
110935
|
+
return text.length > maxChars ? text.slice(0, maxChars) + `
|
|
110542
110936
|
\u2026 [truncated, ${text.length - maxChars} more characters]` : text;
|
|
110543
110937
|
}
|
|
110544
110938
|
var McpClient = class {
|
|
@@ -110599,6 +110993,20 @@ var require_client2 = __commonJS({
|
|
|
110599
110993
|
async readResource(uri) {
|
|
110600
110994
|
return flattenResourceContents(await this._request("resources/read", { uri }));
|
|
110601
110995
|
}
|
|
110996
|
+
async listPrompts() {
|
|
110997
|
+
try {
|
|
110998
|
+
const res = await this._request("prompts/list", {});
|
|
110999
|
+
return Array.isArray(res?.prompts) ? res.prompts : [];
|
|
111000
|
+
} catch {
|
|
111001
|
+
return [];
|
|
111002
|
+
}
|
|
111003
|
+
}
|
|
111004
|
+
async getPrompt(name, args) {
|
|
111005
|
+
const params = { name };
|
|
111006
|
+
if (Object.keys(args).length)
|
|
111007
|
+
params.arguments = args;
|
|
111008
|
+
return flattenPromptMessages(await this._request("prompts/get", params));
|
|
111009
|
+
}
|
|
110602
111010
|
async callTool(name, args) {
|
|
110603
111011
|
const result = await this._request("tools/call", { name, arguments: args });
|
|
110604
111012
|
if (!result)
|
|
@@ -110726,6 +111134,20 @@ var require_httpClient = __commonJS({
|
|
|
110726
111134
|
async readResource(uri) {
|
|
110727
111135
|
return (0, client_1.flattenResourceContents)(await this._rpc("resources/read", { uri }));
|
|
110728
111136
|
}
|
|
111137
|
+
async listPrompts() {
|
|
111138
|
+
try {
|
|
111139
|
+
const res = await this._rpc("prompts/list", {});
|
|
111140
|
+
return Array.isArray(res?.prompts) ? res.prompts : [];
|
|
111141
|
+
} catch {
|
|
111142
|
+
return [];
|
|
111143
|
+
}
|
|
111144
|
+
}
|
|
111145
|
+
async getPrompt(name, args) {
|
|
111146
|
+
const params = { name };
|
|
111147
|
+
if (Object.keys(args).length)
|
|
111148
|
+
params.arguments = args;
|
|
111149
|
+
return (0, client_1.flattenPromptMessages)(await this._rpc("prompts/get", params));
|
|
111150
|
+
}
|
|
110729
111151
|
async callTool(name, args) {
|
|
110730
111152
|
const result = await this._rpc("tools/call", { name, arguments: args });
|
|
110731
111153
|
if (!result)
|
|
@@ -110872,6 +111294,20 @@ var require_sseClient = __commonJS({
|
|
|
110872
111294
|
async readResource(uri) {
|
|
110873
111295
|
return (0, client_1.flattenResourceContents)(await this._rpc("resources/read", { uri }));
|
|
110874
111296
|
}
|
|
111297
|
+
async listPrompts() {
|
|
111298
|
+
try {
|
|
111299
|
+
const res = await this._rpc("prompts/list", {});
|
|
111300
|
+
return Array.isArray(res?.prompts) ? res.prompts : [];
|
|
111301
|
+
} catch {
|
|
111302
|
+
return [];
|
|
111303
|
+
}
|
|
111304
|
+
}
|
|
111305
|
+
async getPrompt(name, args) {
|
|
111306
|
+
const params = { name };
|
|
111307
|
+
if (Object.keys(args).length)
|
|
111308
|
+
params.arguments = args;
|
|
111309
|
+
return (0, client_1.flattenPromptMessages)(await this._rpc("prompts/get", params));
|
|
111310
|
+
}
|
|
110875
111311
|
async callTool(name, args) {
|
|
110876
111312
|
const result = await this._rpc("tools/call", { name, arguments: args });
|
|
110877
111313
|
if (!result)
|
|
@@ -111216,6 +111652,7 @@ var require_manager = __commonJS({
|
|
|
111216
111652
|
constructor() {
|
|
111217
111653
|
this._clients = /* @__PURE__ */ new Map();
|
|
111218
111654
|
this._toolMap = /* @__PURE__ */ new Map();
|
|
111655
|
+
this._promptCache = /* @__PURE__ */ new Map();
|
|
111219
111656
|
this._configs = /* @__PURE__ */ new Map();
|
|
111220
111657
|
this._errors = /* @__PURE__ */ new Map();
|
|
111221
111658
|
this._needsAuth = /* @__PURE__ */ new Map();
|
|
@@ -111383,6 +111820,75 @@ var require_manager = __commonJS({
|
|
|
111383
111820
|
clearTimeout(timer);
|
|
111384
111821
|
}
|
|
111385
111822
|
}
|
|
111823
|
+
/**
|
|
111824
|
+
* Prompt metadata for one connected server. Fetched once per connection and
|
|
111825
|
+
* cached — including an empty list (server has no prompts capability), so the
|
|
111826
|
+
* `/` menu does not re-ask a server on every keystroke; reconnecting clears
|
|
111827
|
+
* the entry. Returns [] for a server that is not connected.
|
|
111828
|
+
*/
|
|
111829
|
+
async promptsFor(server) {
|
|
111830
|
+
const cached = this._promptCache.get(server);
|
|
111831
|
+
if (cached)
|
|
111832
|
+
return cached;
|
|
111833
|
+
const client = this._clients.get(server);
|
|
111834
|
+
if (!client)
|
|
111835
|
+
return [];
|
|
111836
|
+
const list = await client.listPrompts();
|
|
111837
|
+
this._promptCache.set(server, list);
|
|
111838
|
+
return list;
|
|
111839
|
+
}
|
|
111840
|
+
/** Prompts across connected, enabled servers, tagged with the server they came from. */
|
|
111841
|
+
async listPrompts(server) {
|
|
111842
|
+
const out = [];
|
|
111843
|
+
for (const name of this._clients.keys()) {
|
|
111844
|
+
if (server && name !== server)
|
|
111845
|
+
continue;
|
|
111846
|
+
for (const p of await this.promptsFor(name))
|
|
111847
|
+
out.push({ ...p, server: name });
|
|
111848
|
+
}
|
|
111849
|
+
return out;
|
|
111850
|
+
}
|
|
111851
|
+
/**
|
|
111852
|
+
* Expand one prompt to text. Positional values map, in order, onto the
|
|
111853
|
+
* arguments the server declared in prompts/list — the same positional form
|
|
111854
|
+
* Claude Code accepts (`/mcp__server__prompt first second`). Validation runs
|
|
111855
|
+
* here, before the request, so mistakes read as sentences instead of raw
|
|
111856
|
+
* JSON-RPC errors; the request itself is bounded by the same 60s timeout the
|
|
111857
|
+
* resource reader uses.
|
|
111858
|
+
*/
|
|
111859
|
+
async getPrompt(server, name, values = []) {
|
|
111860
|
+
const client = this._clients.get(server);
|
|
111861
|
+
if (!client)
|
|
111862
|
+
throw new Error(`No connected MCP server named "${server}". Connected: ${[...this._clients.keys()].join(", ") || "(none)"}`);
|
|
111863
|
+
const list = await this.promptsFor(server);
|
|
111864
|
+
const meta = list.find((p) => p.name === name);
|
|
111865
|
+
if (!meta) {
|
|
111866
|
+
throw new Error(`No MCP prompt named "${name}" on server "${server}"${list.length ? ` (it offers: ${list.map((p) => p.name).join(", ")})` : ""}.`);
|
|
111867
|
+
}
|
|
111868
|
+
const declared = meta.arguments ?? [];
|
|
111869
|
+
if (values.length > declared.length) {
|
|
111870
|
+
throw new Error(`MCP prompt "${server}:${name}" takes ${declared.length} argument(s)${declared.length ? ` (${declared.map((a) => a.name).join(", ")})` : ""} \u2014 got ${values.length}.`);
|
|
111871
|
+
}
|
|
111872
|
+
const args = {};
|
|
111873
|
+
declared.forEach((a, i2) => {
|
|
111874
|
+
const v = values[i2];
|
|
111875
|
+
if (v !== void 0 && v !== "")
|
|
111876
|
+
args[a.name] = v;
|
|
111877
|
+
});
|
|
111878
|
+
const missing = declared.filter((a) => a.required && args[a.name] === void 0);
|
|
111879
|
+
if (missing.length)
|
|
111880
|
+
throw new Error(`MCP prompt "${server}:${name}" is missing required argument(s): ${missing.map((a) => a.name).join(", ")}.`);
|
|
111881
|
+
let timer;
|
|
111882
|
+
const timeout = new Promise((_2, rej) => {
|
|
111883
|
+
timer = setTimeout(() => rej(new Error(`MCP prompt ${server}:${name} timed out after 60s`)), 6e4);
|
|
111884
|
+
});
|
|
111885
|
+
try {
|
|
111886
|
+
return await Promise.race([client.getPrompt(name, args), timeout]);
|
|
111887
|
+
} finally {
|
|
111888
|
+
if (timer)
|
|
111889
|
+
clearTimeout(timer);
|
|
111890
|
+
}
|
|
111891
|
+
}
|
|
111386
111892
|
/** True if this tool name belongs to an MCP server. */
|
|
111387
111893
|
isMcpTool(name) {
|
|
111388
111894
|
return this._toolMap.has(name);
|
|
@@ -111493,6 +111999,7 @@ var require_manager = __commonJS({
|
|
|
111493
111999
|
if (this._toolMap.get(key) === name)
|
|
111494
112000
|
this._toolMap.delete(key);
|
|
111495
112001
|
}
|
|
112002
|
+
this._promptCache.delete(name);
|
|
111496
112003
|
this.stats.reset();
|
|
111497
112004
|
}
|
|
111498
112005
|
// ─── Config file persistence (for the management UI) ──────────────────────────
|
|
@@ -141804,8 +142311,8 @@ var require_strip = __commonJS({
|
|
|
141804
142311
|
var require_src4 = __commonJS({
|
|
141805
142312
|
"../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js"(exports2, module2) {
|
|
141806
142313
|
"use strict";
|
|
141807
|
-
var
|
|
141808
|
-
var CSI2 = `${
|
|
142314
|
+
var ESC4 = "\x1B";
|
|
142315
|
+
var CSI2 = `${ESC4}[`;
|
|
141809
142316
|
var beep2 = "\x07";
|
|
141810
142317
|
var cursor = {
|
|
141811
142318
|
to(x2, y) {
|
|
@@ -141834,8 +142341,8 @@ var require_src4 = __commonJS({
|
|
|
141834
142341
|
left: `${CSI2}G`,
|
|
141835
142342
|
hide: `${CSI2}?25l`,
|
|
141836
142343
|
show: `${CSI2}?25h`,
|
|
141837
|
-
save: `${
|
|
141838
|
-
restore: `${
|
|
142344
|
+
save: `${ESC4}7`,
|
|
142345
|
+
restore: `${ESC4}8`
|
|
141839
142346
|
};
|
|
141840
142347
|
var scroll = {
|
|
141841
142348
|
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
@@ -155147,7 +155654,7 @@ import * as os18 from "os";
|
|
|
155147
155654
|
import * as crypto7 from "crypto";
|
|
155148
155655
|
import { createRequire } from "module";
|
|
155149
155656
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
155150
|
-
import {
|
|
155657
|
+
import { execFile as execFile2, execFileSync as execFileSync5 } from "child_process";
|
|
155151
155658
|
|
|
155152
155659
|
// src/permissions/handler.ts
|
|
155153
155660
|
import * as readline2 from "readline";
|
|
@@ -166671,6 +167178,208 @@ function askForTrust(workDir, signals) {
|
|
|
166671
167178
|
});
|
|
166672
167179
|
}
|
|
166673
167180
|
|
|
167181
|
+
// src/ui/inputReports.ts
|
|
167182
|
+
var ESC3 = "\x1B";
|
|
167183
|
+
var BEL3 = "\x07";
|
|
167184
|
+
var REPORT_DEADLINE_MS = 120;
|
|
167185
|
+
var OSC_CAP = 4096;
|
|
167186
|
+
function newInputReportState() {
|
|
167187
|
+
return { pending: "", oscSkipLeft: 0 };
|
|
167188
|
+
}
|
|
167189
|
+
function filterInput(state, chunk, opts = {}) {
|
|
167190
|
+
const s2 = state.pending + chunk;
|
|
167191
|
+
state.pending = "";
|
|
167192
|
+
let out = "";
|
|
167193
|
+
let i2 = 0;
|
|
167194
|
+
if (state.oscSkipLeft > 0) {
|
|
167195
|
+
let j = i2;
|
|
167196
|
+
let terminated = false;
|
|
167197
|
+
while (j < s2.length) {
|
|
167198
|
+
if (s2[j] === BEL3) {
|
|
167199
|
+
terminated = true;
|
|
167200
|
+
j += 1;
|
|
167201
|
+
break;
|
|
167202
|
+
}
|
|
167203
|
+
if (s2[j] === ESC3 && s2[j + 1] === "\\") {
|
|
167204
|
+
terminated = true;
|
|
167205
|
+
j += 2;
|
|
167206
|
+
break;
|
|
167207
|
+
}
|
|
167208
|
+
if (s2[j] === ESC3 && j === s2.length - 1)
|
|
167209
|
+
break;
|
|
167210
|
+
j += 1;
|
|
167211
|
+
}
|
|
167212
|
+
const split = !terminated && j < s2.length && s2[j] === ESC3;
|
|
167213
|
+
if (terminated)
|
|
167214
|
+
state.oscSkipLeft = 0;
|
|
167215
|
+
else
|
|
167216
|
+
state.oscSkipLeft = Math.max(0, state.oscSkipLeft - (j - i2));
|
|
167217
|
+
if (split) {
|
|
167218
|
+
state.pending = s2.slice(j);
|
|
167219
|
+
return out;
|
|
167220
|
+
}
|
|
167221
|
+
i2 = j;
|
|
167222
|
+
}
|
|
167223
|
+
while (i2 < s2.length) {
|
|
167224
|
+
if (s2[i2] !== ESC3) {
|
|
167225
|
+
out += s2[i2];
|
|
167226
|
+
i2 += 1;
|
|
167227
|
+
continue;
|
|
167228
|
+
}
|
|
167229
|
+
if (i2 === s2.length - 1) {
|
|
167230
|
+
out += ESC3;
|
|
167231
|
+
i2 += 1;
|
|
167232
|
+
continue;
|
|
167233
|
+
}
|
|
167234
|
+
const next = s2[i2 + 1];
|
|
167235
|
+
if (next === "]") {
|
|
167236
|
+
const end = oscEnd(s2, i2 + 2);
|
|
167237
|
+
if (end >= 0) {
|
|
167238
|
+
i2 = end;
|
|
167239
|
+
continue;
|
|
167240
|
+
}
|
|
167241
|
+
if (s2.length - (i2 + 2) > OSC_CAP) {
|
|
167242
|
+
state.oscSkipLeft = OSC_CAP;
|
|
167243
|
+
i2 = s2.length;
|
|
167244
|
+
continue;
|
|
167245
|
+
}
|
|
167246
|
+
state.pending = s2.slice(i2);
|
|
167247
|
+
break;
|
|
167248
|
+
}
|
|
167249
|
+
if (next === "[") {
|
|
167250
|
+
const r2 = scanCsi(s2, i2, opts);
|
|
167251
|
+
if (r2.kind === "hold") {
|
|
167252
|
+
state.pending = s2.slice(i2);
|
|
167253
|
+
break;
|
|
167254
|
+
}
|
|
167255
|
+
if (r2.kind === "pass")
|
|
167256
|
+
out += s2.slice(i2, r2.end);
|
|
167257
|
+
i2 = r2.end;
|
|
167258
|
+
continue;
|
|
167259
|
+
}
|
|
167260
|
+
out += ESC3 + next;
|
|
167261
|
+
i2 += 2;
|
|
167262
|
+
}
|
|
167263
|
+
return out;
|
|
167264
|
+
}
|
|
167265
|
+
function releasePendingOnDeadline(state, _opts = {}) {
|
|
167266
|
+
const held = state.pending;
|
|
167267
|
+
state.pending = "";
|
|
167268
|
+
if (held === "")
|
|
167269
|
+
return "";
|
|
167270
|
+
if (held.startsWith(ESC3 + "]"))
|
|
167271
|
+
return "";
|
|
167272
|
+
if (held.startsWith(ESC3 + "[")) {
|
|
167273
|
+
const rest = held.slice(2);
|
|
167274
|
+
if (rest.startsWith("M") || rest.startsWith("<"))
|
|
167275
|
+
return "";
|
|
167276
|
+
return ESC3;
|
|
167277
|
+
}
|
|
167278
|
+
return "";
|
|
167279
|
+
}
|
|
167280
|
+
function scanCsi(s2, start, opts) {
|
|
167281
|
+
let j = start + 2;
|
|
167282
|
+
while (j < s2.length) {
|
|
167283
|
+
const c = s2.charCodeAt(j);
|
|
167284
|
+
if (c >= 64 && c <= 126)
|
|
167285
|
+
break;
|
|
167286
|
+
if (c >= 48 && c <= 63) {
|
|
167287
|
+
j += 1;
|
|
167288
|
+
continue;
|
|
167289
|
+
}
|
|
167290
|
+
if (c >= 32 && c <= 47) {
|
|
167291
|
+
j += 1;
|
|
167292
|
+
continue;
|
|
167293
|
+
}
|
|
167294
|
+
return { kind: "drop", end: start + 2 };
|
|
167295
|
+
}
|
|
167296
|
+
if (j >= s2.length)
|
|
167297
|
+
return { kind: "hold" };
|
|
167298
|
+
const final = s2[j];
|
|
167299
|
+
const body = s2.slice(start + 2, j);
|
|
167300
|
+
const seqEnd = j + 1;
|
|
167301
|
+
if (final === "M" && body === "") {
|
|
167302
|
+
if (s2.length < seqEnd + 3)
|
|
167303
|
+
return { kind: "hold" };
|
|
167304
|
+
return opts.passMouse ? { kind: "pass", end: seqEnd + 3 } : { kind: "drop", end: seqEnd + 3 };
|
|
167305
|
+
}
|
|
167306
|
+
if (body.startsWith("<")) {
|
|
167307
|
+
return opts.passMouse ? { kind: "pass", end: seqEnd } : { kind: "drop", end: seqEnd };
|
|
167308
|
+
}
|
|
167309
|
+
if (/^[?>=!]/.test(body))
|
|
167310
|
+
return { kind: "drop", end: seqEnd };
|
|
167311
|
+
if (body === "" && (final === "I" || final === "O"))
|
|
167312
|
+
return { kind: "drop", end: seqEnd };
|
|
167313
|
+
if (final === "R" && /^\d+;\d+$/.test(body))
|
|
167314
|
+
return { kind: "drop", end: seqEnd };
|
|
167315
|
+
return { kind: "pass", end: seqEnd };
|
|
167316
|
+
}
|
|
167317
|
+
function oscEnd(s2, from) {
|
|
167318
|
+
for (let i2 = from; i2 < s2.length; i2 += 1) {
|
|
167319
|
+
if (s2[i2] === BEL3)
|
|
167320
|
+
return i2 + 1;
|
|
167321
|
+
if (s2[i2] === ESC3 && s2[i2 + 1] === "\\")
|
|
167322
|
+
return i2 + 2;
|
|
167323
|
+
}
|
|
167324
|
+
return -1;
|
|
167325
|
+
}
|
|
167326
|
+
var mousePassthrough = () => false;
|
|
167327
|
+
var installed = false;
|
|
167328
|
+
function setMousePassthrough(fn) {
|
|
167329
|
+
mousePassthrough = fn;
|
|
167330
|
+
}
|
|
167331
|
+
function installInputReportFilter(stream = process.stdin) {
|
|
167332
|
+
const isDefault = stream === process.stdin;
|
|
167333
|
+
if (isDefault && installed)
|
|
167334
|
+
return () => {
|
|
167335
|
+
};
|
|
167336
|
+
if (isDefault)
|
|
167337
|
+
installed = true;
|
|
167338
|
+
const stdin = stream;
|
|
167339
|
+
const origRead = stdin.read.bind(stdin);
|
|
167340
|
+
const state = newInputReportState();
|
|
167341
|
+
let outbox = "";
|
|
167342
|
+
let timer = null;
|
|
167343
|
+
const clearTimer = () => {
|
|
167344
|
+
if (timer) {
|
|
167345
|
+
clearTimeout(timer);
|
|
167346
|
+
timer = null;
|
|
167347
|
+
}
|
|
167348
|
+
};
|
|
167349
|
+
const onDeadline = () => {
|
|
167350
|
+
timer = null;
|
|
167351
|
+
outbox += releasePendingOnDeadline(state, { passMouse: mousePassthrough() });
|
|
167352
|
+
stdin.emit("readable");
|
|
167353
|
+
};
|
|
167354
|
+
stdin.read = function patchedRead(...args) {
|
|
167355
|
+
if (args.length > 0)
|
|
167356
|
+
return origRead(...args);
|
|
167357
|
+
let chunk;
|
|
167358
|
+
while ((chunk = origRead()) !== null && chunk !== void 0) {
|
|
167359
|
+
const s2 = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
167360
|
+
outbox += filterInput(state, s2, { passMouse: mousePassthrough() });
|
|
167361
|
+
}
|
|
167362
|
+
if (state.pending !== "") {
|
|
167363
|
+
clearTimer();
|
|
167364
|
+
timer = setTimeout(onDeadline, REPORT_DEADLINE_MS);
|
|
167365
|
+
timer.unref?.();
|
|
167366
|
+
} else {
|
|
167367
|
+
clearTimer();
|
|
167368
|
+
}
|
|
167369
|
+
if (outbox === "")
|
|
167370
|
+
return null;
|
|
167371
|
+
const out = outbox;
|
|
167372
|
+
outbox = "";
|
|
167373
|
+
return out;
|
|
167374
|
+
};
|
|
167375
|
+
return () => {
|
|
167376
|
+
clearTimer();
|
|
167377
|
+
stdin.read = origRead;
|
|
167378
|
+
if (isDefault)
|
|
167379
|
+
installed = false;
|
|
167380
|
+
};
|
|
167381
|
+
}
|
|
167382
|
+
|
|
166674
167383
|
// src/ui/inkTerminal.tsx
|
|
166675
167384
|
var import_react36 = __toESM(require_react(), 1);
|
|
166676
167385
|
|
|
@@ -166908,6 +167617,32 @@ function skillEntries(skills, builtins = BUILTIN_SLASH_COMMANDS) {
|
|
|
166908
167617
|
}
|
|
166909
167618
|
return out;
|
|
166910
167619
|
}
|
|
167620
|
+
function promptEntries(prompts2, builtins = BUILTIN_SLASH_COMMANDS) {
|
|
167621
|
+
const taken = /* @__PURE__ */ new Set();
|
|
167622
|
+
for (const b of builtins) {
|
|
167623
|
+
taken.add(b.name);
|
|
167624
|
+
for (const a of b.aliases ?? [])
|
|
167625
|
+
taken.add(a);
|
|
167626
|
+
}
|
|
167627
|
+
const out = [];
|
|
167628
|
+
for (const p of prompts2) {
|
|
167629
|
+
const name = `${p.server}:${p.name}`;
|
|
167630
|
+
if (taken.has(name))
|
|
167631
|
+
continue;
|
|
167632
|
+
taken.add(name);
|
|
167633
|
+
const args = p.arguments ?? [];
|
|
167634
|
+
const description = (p.description ?? "").replace(/\s+/g, " ").trim() || `MCP prompt from ${p.server}`;
|
|
167635
|
+
out.push({
|
|
167636
|
+
name,
|
|
167637
|
+
description,
|
|
167638
|
+
argHint: args.length ? args.map((a) => a.required ? `<${a.name}>` : `[${a.name}]`).join(" ") : void 0,
|
|
167639
|
+
requiresArg: args.some((a) => a.required) || void 0,
|
|
167640
|
+
kind: "mcp",
|
|
167641
|
+
source: p.server
|
|
167642
|
+
});
|
|
167643
|
+
}
|
|
167644
|
+
return out;
|
|
167645
|
+
}
|
|
166911
167646
|
function matchScore(query, name, aliases, description) {
|
|
166912
167647
|
if (!query)
|
|
166913
167648
|
return 0;
|
|
@@ -166948,7 +167683,7 @@ function slashQuery(line, cursor) {
|
|
|
166948
167683
|
return null;
|
|
166949
167684
|
if (line.includes("\n"))
|
|
166950
167685
|
return null;
|
|
166951
|
-
const m2 = /^\/([\w
|
|
167686
|
+
const m2 = /^\/([\w:-]*)$/.exec(line);
|
|
166952
167687
|
if (!m2)
|
|
166953
167688
|
return null;
|
|
166954
167689
|
if (cursor < 1)
|
|
@@ -167758,7 +168493,7 @@ function describeOpen(spec, target, cwd2) {
|
|
|
167758
168493
|
// src/ui/fileMention.ts
|
|
167759
168494
|
import * as fs26 from "fs";
|
|
167760
168495
|
import * as path26 from "path";
|
|
167761
|
-
import { execFileSync as execFileSync4 } from "child_process";
|
|
168496
|
+
import { execFile, execFileSync as execFileSync4 } from "child_process";
|
|
167762
168497
|
|
|
167763
168498
|
// src/ui/contextFiles.ts
|
|
167764
168499
|
import * as fs25 from "fs";
|
|
@@ -167973,6 +168708,9 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
|
167973
168708
|
]);
|
|
167974
168709
|
var MAX_INDEXED = 5e4;
|
|
167975
168710
|
function listProjectFiles(cwd2) {
|
|
168711
|
+
return listProjectFilesFrom(cwd2).files;
|
|
168712
|
+
}
|
|
168713
|
+
function listProjectFilesFrom(cwd2) {
|
|
167976
168714
|
let files = null;
|
|
167977
168715
|
try {
|
|
167978
168716
|
const out = execFileSync4("git", ["-C", cwd2, "ls-files", "-co", "--exclude-standard", "-z"], {
|
|
@@ -167984,34 +168722,41 @@ function listProjectFiles(cwd2) {
|
|
|
167984
168722
|
files = [...new Set(out.split("\0").filter(Boolean))];
|
|
167985
168723
|
} catch {
|
|
167986
168724
|
}
|
|
168725
|
+
const source2 = files ? "git" : "walk";
|
|
167987
168726
|
if (!files)
|
|
167988
168727
|
files = walk(cwd2);
|
|
167989
|
-
return files.filter((f3) => !/\s/.test(f3)).slice(0, MAX_INDEXED);
|
|
168728
|
+
return { files: files.filter((f3) => !/\s/.test(f3)).slice(0, MAX_INDEXED), source: source2 };
|
|
167990
168729
|
}
|
|
167991
|
-
function
|
|
167992
|
-
const
|
|
167993
|
-
|
|
167994
|
-
|
|
167995
|
-
|
|
168730
|
+
function* walkEntries(root) {
|
|
168731
|
+
const queue = [{ dir: root, depth: 0 }];
|
|
168732
|
+
for (let i2 = 0; i2 < queue.length; i2++) {
|
|
168733
|
+
const { dir, depth } = queue[i2];
|
|
168734
|
+
if (depth > 8)
|
|
168735
|
+
continue;
|
|
167996
168736
|
let entries;
|
|
167997
168737
|
try {
|
|
167998
168738
|
entries = fs26.readdirSync(dir, { withFileTypes: true });
|
|
167999
168739
|
} catch {
|
|
168000
|
-
|
|
168740
|
+
continue;
|
|
168001
168741
|
}
|
|
168002
168742
|
for (const e2 of entries) {
|
|
168003
|
-
if (out.length >= MAX_INDEXED)
|
|
168004
|
-
return;
|
|
168005
168743
|
const full = path26.join(dir, e2.name);
|
|
168006
168744
|
if (e2.isDirectory()) {
|
|
168007
168745
|
if (!IGNORED_DIRS.has(e2.name) && !e2.isSymbolicLink())
|
|
168008
|
-
|
|
168746
|
+
queue.push({ dir: full, depth: depth + 1 });
|
|
168009
168747
|
} else if (e2.isFile()) {
|
|
168010
|
-
|
|
168748
|
+
yield path26.relative(root, full).split(path26.sep).join("/");
|
|
168011
168749
|
}
|
|
168012
168750
|
}
|
|
168013
|
-
}
|
|
168014
|
-
|
|
168751
|
+
}
|
|
168752
|
+
}
|
|
168753
|
+
function walk(root) {
|
|
168754
|
+
const out = [];
|
|
168755
|
+
for (const f3 of walkEntries(root)) {
|
|
168756
|
+
out.push(f3);
|
|
168757
|
+
if (out.length >= MAX_INDEXED)
|
|
168758
|
+
break;
|
|
168759
|
+
}
|
|
168015
168760
|
return out;
|
|
168016
168761
|
}
|
|
168017
168762
|
function buildIndex(files) {
|
|
@@ -168023,20 +168768,111 @@ function buildIndex(files) {
|
|
|
168023
168768
|
}
|
|
168024
168769
|
return [...dirs, ...files].sort();
|
|
168025
168770
|
}
|
|
168771
|
+
var GIT_CACHE_MS = 5e3;
|
|
168772
|
+
var WALK_CACHE_MS = 6e4;
|
|
168026
168773
|
var cache3 = null;
|
|
168027
|
-
var CACHE_MS = 5e3;
|
|
168028
168774
|
var excludedPatterns = [];
|
|
168775
|
+
var excludedKey = "[]";
|
|
168029
168776
|
function setExcludedPatterns(patterns) {
|
|
168030
168777
|
excludedPatterns = [...patterns];
|
|
168031
|
-
|
|
168778
|
+
excludedKey = JSON.stringify(excludedPatterns);
|
|
168779
|
+
}
|
|
168780
|
+
function derivedIndex(raw) {
|
|
168781
|
+
return buildIndex(raw.filter((f3) => !isExcluded(f3, excludedPatterns)));
|
|
168032
168782
|
}
|
|
168033
168783
|
function projectIndex(cwd2, now = Date.now()) {
|
|
168034
|
-
if (cache3 && cache3.cwd === cwd2 && now - cache3.at <
|
|
168784
|
+
if (cache3 && cache3.cwd === cwd2 && now - cache3.at < cache3.ttl) {
|
|
168785
|
+
if (cache3.patterns !== excludedKey)
|
|
168786
|
+
cache3 = { ...cache3, patterns: excludedKey, index: derivedIndex(cache3.raw) };
|
|
168035
168787
|
return cache3.index;
|
|
168036
|
-
|
|
168037
|
-
const
|
|
168038
|
-
cache3 = {
|
|
168039
|
-
|
|
168788
|
+
}
|
|
168789
|
+
const { files, source: source2 } = listProjectFilesFrom(cwd2);
|
|
168790
|
+
cache3 = {
|
|
168791
|
+
cwd: cwd2,
|
|
168792
|
+
at: now,
|
|
168793
|
+
ttl: source2 === "git" ? GIT_CACHE_MS : WALK_CACHE_MS,
|
|
168794
|
+
raw: files,
|
|
168795
|
+
patterns: excludedKey,
|
|
168796
|
+
index: derivedIndex(files)
|
|
168797
|
+
};
|
|
168798
|
+
return cache3.index;
|
|
168799
|
+
}
|
|
168800
|
+
var WALK_SLICE_MS = 8;
|
|
168801
|
+
var indexListener = null;
|
|
168802
|
+
function setMentionIndexListener(cb) {
|
|
168803
|
+
indexListener = cb;
|
|
168804
|
+
}
|
|
168805
|
+
var building = null;
|
|
168806
|
+
function walkInSlices(root, job, done) {
|
|
168807
|
+
const entries = walkEntries(root);
|
|
168808
|
+
const out = [];
|
|
168809
|
+
const step = () => {
|
|
168810
|
+
if (job.cancelled)
|
|
168811
|
+
return;
|
|
168812
|
+
const t0 = Date.now();
|
|
168813
|
+
for (; ; ) {
|
|
168814
|
+
if (out.length >= MAX_INDEXED)
|
|
168815
|
+
return done(out);
|
|
168816
|
+
const next = entries.next();
|
|
168817
|
+
if (next.done)
|
|
168818
|
+
return done(out);
|
|
168819
|
+
out.push(next.value);
|
|
168820
|
+
if (Date.now() - t0 >= WALK_SLICE_MS)
|
|
168821
|
+
break;
|
|
168822
|
+
}
|
|
168823
|
+
setImmediate(step);
|
|
168824
|
+
};
|
|
168825
|
+
setImmediate(step);
|
|
168826
|
+
}
|
|
168827
|
+
function finishBuild(job, files, source2) {
|
|
168828
|
+
if (job.cancelled)
|
|
168829
|
+
return;
|
|
168830
|
+
if (building === job)
|
|
168831
|
+
building = null;
|
|
168832
|
+
const raw = files.filter((f3) => !/\s/.test(f3)).slice(0, MAX_INDEXED);
|
|
168833
|
+
cache3 = {
|
|
168834
|
+
cwd: job.cwd,
|
|
168835
|
+
at: Date.now(),
|
|
168836
|
+
ttl: source2 === "git" ? GIT_CACHE_MS : WALK_CACHE_MS,
|
|
168837
|
+
raw,
|
|
168838
|
+
patterns: excludedKey,
|
|
168839
|
+
index: derivedIndex(raw)
|
|
168840
|
+
};
|
|
168841
|
+
indexListener?.();
|
|
168842
|
+
}
|
|
168843
|
+
function primeMentionIndex(cwd2) {
|
|
168844
|
+
if (cache3 && cache3.cwd === cwd2 && Date.now() - cache3.at < cache3.ttl)
|
|
168845
|
+
return;
|
|
168846
|
+
if (building && building.cwd === cwd2 && !building.cancelled)
|
|
168847
|
+
return;
|
|
168848
|
+
if (building)
|
|
168849
|
+
building.cancelled = true;
|
|
168850
|
+
const job = { cwd: cwd2, cancelled: false };
|
|
168851
|
+
building = job;
|
|
168852
|
+
execFile("git", ["-C", cwd2, "ls-files", "-co", "--exclude-standard", "-z"], {
|
|
168853
|
+
encoding: "utf-8",
|
|
168854
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
168855
|
+
timeout: 5e3
|
|
168856
|
+
}, (err, stdout) => {
|
|
168857
|
+
if (job.cancelled)
|
|
168858
|
+
return;
|
|
168859
|
+
if (!err) {
|
|
168860
|
+
finishBuild(job, [...new Set(stdout.split("\0").filter(Boolean))], "git");
|
|
168861
|
+
return;
|
|
168862
|
+
}
|
|
168863
|
+
walkInSlices(cwd2, job, (files) => finishBuild(job, files, "walk"));
|
|
168864
|
+
});
|
|
168865
|
+
}
|
|
168866
|
+
function mentionIndexForRender(cwd2) {
|
|
168867
|
+
if (!cache3 || cache3.cwd !== cwd2) {
|
|
168868
|
+
primeMentionIndex(cwd2);
|
|
168869
|
+
return [];
|
|
168870
|
+
}
|
|
168871
|
+
if (cache3.patterns !== excludedKey)
|
|
168872
|
+
cache3 = { ...cache3, patterns: excludedKey, index: derivedIndex(cache3.raw) };
|
|
168873
|
+
if (Date.now() - cache3.at >= cache3.ttl)
|
|
168874
|
+
primeMentionIndex(cwd2);
|
|
168875
|
+
return cache3.index;
|
|
168040
168876
|
}
|
|
168041
168877
|
function subsequence(hay, needle) {
|
|
168042
168878
|
let i2 = 0;
|
|
@@ -168079,13 +168915,13 @@ function rankMentions(query, index, limit = 200) {
|
|
|
168079
168915
|
}
|
|
168080
168916
|
return index.map((p, i2) => ({ p, i: i2, s: score(p, q) })).filter((x2) => x2.s !== Infinity).sort((a, b) => a.s - b.s || a.p.length - b.p.length || a.i - b.i).slice(0, limit).map((x2) => x2.p);
|
|
168081
168917
|
}
|
|
168082
|
-
function computeMention(line, cursor,
|
|
168918
|
+
function computeMention(line, cursor, getIndex, dismissedFor) {
|
|
168083
168919
|
if (dismissedFor !== null && dismissedFor === line)
|
|
168084
168920
|
return null;
|
|
168085
168921
|
const at = mentionAt(line, cursor);
|
|
168086
168922
|
if (!at)
|
|
168087
168923
|
return null;
|
|
168088
|
-
const items = rankMentions(at.query,
|
|
168924
|
+
const items = rankMentions(at.query, getIndex());
|
|
168089
168925
|
return items.length ? { at, items } : null;
|
|
168090
168926
|
}
|
|
168091
168927
|
function decideMentionEnter(query, pick) {
|
|
@@ -168562,7 +169398,7 @@ function slashMenuView(p) {
|
|
|
168562
169398
|
return {
|
|
168563
169399
|
rows: shown.map((e2, i2) => {
|
|
168564
169400
|
const label = `/${e2.name}${e2.argHint ? " " + e2.argHint : ""}`;
|
|
168565
|
-
const tag = e2.kind === "skill" ? ` (${e2.source === "project" || !e2.source ? "skill" : e2.source + " skill"})` : "";
|
|
169401
|
+
const tag = e2.kind === "mcp" ? " (MCP)" : e2.kind === "skill" ? ` (${e2.source === "project" || !e2.source ? "skill" : e2.source + " skill"})` : "";
|
|
168566
169402
|
const alias = e2.aliases?.length ? ` (${e2.aliases.map((a) => "/" + a).join(", ")})` : "";
|
|
168567
169403
|
const seen = e2.recent ? " \xB7 recent" : "";
|
|
168568
169404
|
return {
|
|
@@ -168617,7 +169453,7 @@ function fullscreenView(p) {
|
|
|
168617
169453
|
function mentionMenuView(p) {
|
|
168618
169454
|
if (p.blocked)
|
|
168619
169455
|
return null;
|
|
168620
|
-
const m2 = computeMention(p.line, p.cursorPos,
|
|
169456
|
+
const m2 = computeMention(p.line, p.cursorPos, () => mentionIndexForRender(p.root), p.dismissedFor);
|
|
168621
169457
|
if (!m2)
|
|
168622
169458
|
return null;
|
|
168623
169459
|
const sel = Math.min(p.sel.query === m2.at.query ? p.sel.idx : 0, m2.items.length - 1);
|
|
@@ -168806,12 +169642,12 @@ var App2 = ({ onReady }) => {
|
|
|
168806
169642
|
const mentionRootRef = (0, import_react36.useRef)(process.cwd());
|
|
168807
169643
|
const setMentionRoot = (0, import_react36.useCallback)((dir) => {
|
|
168808
169644
|
mentionRootRef.current = dir;
|
|
168809
|
-
|
|
168810
|
-
|
|
168811
|
-
|
|
168812
|
-
|
|
168813
|
-
|
|
168814
|
-
|
|
169645
|
+
primeMentionIndex(dir);
|
|
169646
|
+
}, []);
|
|
169647
|
+
const [, bumpMentionIndex] = (0, import_react36.useState)(0);
|
|
169648
|
+
import_react36.default.useEffect(() => {
|
|
169649
|
+
setMentionIndexListener(() => bumpMentionIndex((n) => n + 1));
|
|
169650
|
+
return () => setMentionIndexListener(null);
|
|
168815
169651
|
}, []);
|
|
168816
169652
|
const setSlashEntries = (0, import_react36.useCallback)((entries) => {
|
|
168817
169653
|
slashEntriesRef.current = entries;
|
|
@@ -169254,7 +170090,7 @@ var App2 = ({ onReady }) => {
|
|
|
169254
170090
|
}
|
|
169255
170091
|
}
|
|
169256
170092
|
}
|
|
169257
|
-
const mention = askResolverRef.current || choiceRef.current || searchRef.current || historyRef.current.browsing || busyRef.current ? null : computeMention(lineRef.current, cursorRef.current,
|
|
170093
|
+
const mention = askResolverRef.current || choiceRef.current || searchRef.current || historyRef.current.browsing || busyRef.current ? null : computeMention(lineRef.current, cursorRef.current, () => mentionIndexForRender(mentionRootRef.current), mentionDismissedRef.current);
|
|
169258
170094
|
if (mention) {
|
|
169259
170095
|
const sel = mentionSelRef.current.query === mention.at.query ? mentionSelRef.current.idx : 0;
|
|
169260
170096
|
const pick = mention.items[Math.min(sel, mention.items.length - 1)];
|
|
@@ -169626,6 +170462,9 @@ var App2 = ({ onReady }) => {
|
|
|
169626
170462
|
if (fullscreenRef.current)
|
|
169627
170463
|
process.stdout.write(on ? MOUSE_ON : MOUSE_OFF);
|
|
169628
170464
|
}, []);
|
|
170465
|
+
import_react36.default.useEffect(() => {
|
|
170466
|
+
setMousePassthrough(() => fullscreenRef.current && mouseRef.current);
|
|
170467
|
+
}, []);
|
|
169629
170468
|
import_react36.default.useEffect(() => () => {
|
|
169630
170469
|
if (fullscreenRef.current) {
|
|
169631
170470
|
fullscreenRef.current = false;
|
|
@@ -169982,6 +170821,38 @@ var InkReadlineAdapter = class extends EventEmitter3 {
|
|
|
169982
170821
|
}
|
|
169983
170822
|
};
|
|
169984
170823
|
|
|
170824
|
+
// src/ui/mcpPrompt.ts
|
|
170825
|
+
function parseMcpPromptRef(cmd, serverNames) {
|
|
170826
|
+
const bare = cmd.startsWith("/") ? cmd.slice(1) : cmd;
|
|
170827
|
+
if (bare.startsWith("mcp__")) {
|
|
170828
|
+
const rest = bare.slice("mcp__".length);
|
|
170829
|
+
const candidates = serverNames.filter((s2) => rest.startsWith(s2 + "__")).sort((a, b) => b.length - a.length);
|
|
170830
|
+
const server = candidates[0];
|
|
170831
|
+
if (!server)
|
|
170832
|
+
return null;
|
|
170833
|
+
const name = rest.slice(server.length + 2);
|
|
170834
|
+
return name ? { server, name } : null;
|
|
170835
|
+
}
|
|
170836
|
+
const colon = bare.indexOf(":");
|
|
170837
|
+
if (colon > 0) {
|
|
170838
|
+
const server = bare.slice(0, colon);
|
|
170839
|
+
const name = bare.slice(colon + 1);
|
|
170840
|
+
if (name && serverNames.includes(server))
|
|
170841
|
+
return { server, name };
|
|
170842
|
+
}
|
|
170843
|
+
return null;
|
|
170844
|
+
}
|
|
170845
|
+
function splitPromptArgs(arg) {
|
|
170846
|
+
const out = [];
|
|
170847
|
+
const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
170848
|
+
let m2;
|
|
170849
|
+
while (m2 = re.exec(arg)) {
|
|
170850
|
+
const v = m2[1] ?? m2[2] ?? m2[3];
|
|
170851
|
+
out.push(v);
|
|
170852
|
+
}
|
|
170853
|
+
return out;
|
|
170854
|
+
}
|
|
170855
|
+
|
|
169985
170856
|
// src/ui/recents.ts
|
|
169986
170857
|
import fs27 from "node:fs";
|
|
169987
170858
|
import os17 from "node:os";
|
|
@@ -171845,12 +172716,16 @@ function resolveModelLabel(alias) {
|
|
|
171845
172716
|
const id = normaliseModelId(alias);
|
|
171846
172717
|
return (0, import_code_core18.liveLabelFor)(id, MODEL_LABELS[id] ?? id);
|
|
171847
172718
|
}
|
|
171848
|
-
function
|
|
171849
|
-
|
|
171850
|
-
|
|
171851
|
-
|
|
171852
|
-
|
|
171853
|
-
|
|
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
|
+
});
|
|
171854
172729
|
}
|
|
171855
172730
|
var BILLING_URL = "https://app.nexrall.com/?settings=billing";
|
|
171856
172731
|
function hyperlink(label, url) {
|
|
@@ -171878,28 +172753,29 @@ function currentUserLabel() {
|
|
|
171878
172753
|
return "there";
|
|
171879
172754
|
}
|
|
171880
172755
|
}
|
|
171881
|
-
function collectEnv(workDir) {
|
|
172756
|
+
async function collectEnv(workDir) {
|
|
171882
172757
|
return {
|
|
171883
172758
|
cwd: workDir,
|
|
171884
172759
|
platform: `${os18.platform()} ${os18.release()}`,
|
|
171885
172760
|
shell: process.env.SHELL ?? process.env.ComSpec ?? "unknown",
|
|
171886
172761
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
171887
|
-
...collectGitEnv(workDir)
|
|
172762
|
+
...await collectGitEnv(workDir)
|
|
171888
172763
|
};
|
|
171889
172764
|
}
|
|
171890
|
-
function collectGitEnv(workDir) {
|
|
171891
|
-
|
|
171892
|
-
|
|
171893
|
-
|
|
171894
|
-
|
|
171895
|
-
|
|
171896
|
-
|
|
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 };
|
|
171897
172773
|
}
|
|
171898
|
-
function refreshEnvForTurn(env4, workDir) {
|
|
172774
|
+
async function refreshEnvForTurn(env4, workDir) {
|
|
171899
172775
|
return {
|
|
171900
172776
|
...env4,
|
|
171901
172777
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
171902
|
-
...collectGitEnv(workDir)
|
|
172778
|
+
...await collectGitEnv(workDir)
|
|
171903
172779
|
};
|
|
171904
172780
|
}
|
|
171905
172781
|
var noDiscovery = false;
|
|
@@ -172083,6 +172959,10 @@ var Spinner = class {
|
|
|
172083
172959
|
verbIdx = 0;
|
|
172084
172960
|
thinkTokens = 0;
|
|
172085
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 = "";
|
|
172086
172966
|
start(text, opts) {
|
|
172087
172967
|
this.stop();
|
|
172088
172968
|
this.baseText = text;
|
|
@@ -172137,13 +173017,24 @@ var Spinner = class {
|
|
|
172137
173017
|
return;
|
|
172138
173018
|
this.baseText = text;
|
|
172139
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
|
+
}
|
|
172140
173031
|
render() {
|
|
172141
173032
|
const elapsedSec = Math.floor((Date.now() - this.startedAt) / 1e3);
|
|
172142
173033
|
if (this.verbs && elapsedSec > 0 && elapsedSec % VERB_ROTATE_SEC === 0 && this.lastRotateSec !== elapsedSec) {
|
|
172143
173034
|
this.lastRotateSec = elapsedSec;
|
|
172144
173035
|
this.verbIdx++;
|
|
172145
173036
|
}
|
|
172146
|
-
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);
|
|
172147
173038
|
const status = composeStatusLine({
|
|
172148
173039
|
frame: this.frames[this.i % this.frames.length],
|
|
172149
173040
|
text: label,
|
|
@@ -172192,6 +173083,7 @@ async function initMcp(workDir, override, strict) {
|
|
|
172192
173083
|
if (noDiscovery && !override) {
|
|
172193
173084
|
_mcpConfig = { mcpServers: {} };
|
|
172194
173085
|
_mcpManager = null;
|
|
173086
|
+
wireHookMcpCaller();
|
|
172195
173087
|
return;
|
|
172196
173088
|
}
|
|
172197
173089
|
_mcpConfig = strict && override ? { mcpServers: {} } : import_code_core18.McpManager.loadConfig(workDir);
|
|
@@ -172199,6 +173091,7 @@ async function initMcp(workDir, override, strict) {
|
|
|
172199
173091
|
Object.assign(_mcpConfig.mcpServers, override.mcpServers);
|
|
172200
173092
|
if (Object.keys(_mcpConfig.mcpServers).length === 0) {
|
|
172201
173093
|
_mcpManager = null;
|
|
173094
|
+
wireHookMcpCaller();
|
|
172202
173095
|
return;
|
|
172203
173096
|
}
|
|
172204
173097
|
try {
|
|
@@ -172208,6 +173101,18 @@ async function initMcp(workDir, override, strict) {
|
|
|
172208
173101
|
const manager = new import_code_core18.McpManager();
|
|
172209
173102
|
await manager.connectAll(_mcpConfig);
|
|
172210
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
|
+
});
|
|
172211
173116
|
}
|
|
172212
173117
|
function formatAgentsList(workDir) {
|
|
172213
173118
|
const { types: types3, warnings } = (0, import_code_core18.loadAgentTypesWithWarnings)(workDir);
|
|
@@ -172583,6 +173488,7 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrall
|
|
|
172583
173488
|
const turnStart = Date.now();
|
|
172584
173489
|
userActiveThisTurn = false;
|
|
172585
173490
|
const spinner = new Spinner();
|
|
173491
|
+
(0, import_code_core19.setHookStatusListener)((m2) => spinner.setHookStatus(m2));
|
|
172586
173492
|
const mdRender = new MarkdownStreamRenderer();
|
|
172587
173493
|
const toolStream = new ToolStreamPrinter(PREVIEW_LINES);
|
|
172588
173494
|
let toolStartTime = 0;
|
|
@@ -172609,7 +173515,7 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrall
|
|
|
172609
173515
|
workDir,
|
|
172610
173516
|
sessionId: activeSessionIdGetter(),
|
|
172611
173517
|
model: modelAlias,
|
|
172612
|
-
env: refreshEnvForTurn(env4, workDir),
|
|
173518
|
+
env: await refreshEnvForTurn(env4, workDir),
|
|
172613
173519
|
nexrallMd,
|
|
172614
173520
|
mode,
|
|
172615
173521
|
// `/mode plan` previously only hinted to the backend — the footer said "plan
|
|
@@ -172962,7 +173868,7 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
172962
173868
|
workDir,
|
|
172963
173869
|
sessionId: activeSessionIdGetter(),
|
|
172964
173870
|
model: modelAlias,
|
|
172965
|
-
env: refreshEnvForTurn(env4, workDir),
|
|
173871
|
+
env: await refreshEnvForTurn(env4, workDir),
|
|
172966
173872
|
nexrallMd,
|
|
172967
173873
|
mode,
|
|
172968
173874
|
planMode: mode === "plan",
|
|
@@ -173254,7 +174160,7 @@ function printHelp() {
|
|
|
173254
174160
|
["/skills", "List skills (.nexrall/skills/<name>/SKILL.md or .nexrall/commands/*.md) \u2014 the model can also auto-invoke these"],
|
|
173255
174161
|
["/commands", "List your custom commands (.nexrall/commands/*.md)"],
|
|
173256
174162
|
["/plugins", "List installed plugins (.nexrall/plugins/)"],
|
|
173257
|
-
["/mcp [name|verb]", "List servers; <name> inspects tools/latency; enable|disable persists, connect|disconnect lasts the session"],
|
|
174163
|
+
["/mcp [name|verb]", "List servers; <name> inspects tools/latency; enable|disable persists, connect|disconnect lasts the session; prompts lists /server:prompt templates"],
|
|
173258
174164
|
["/open <path[:line]>", 'Open a file in your editor (bare /open picks from files this session touched; finds "auth.ts" anywhere)'],
|
|
173259
174165
|
["/doctor", "Check Node, sign-in, network, terminal, MCP and storage; shows how to fix each problem"],
|
|
173260
174166
|
["/fullscreen", "Draw the session on the terminal's alternate screen: it re-wraps on resize and PgUp/PgDn page through it"],
|
|
@@ -173383,6 +174289,7 @@ function printSessions() {
|
|
|
173383
174289
|
console.log();
|
|
173384
174290
|
}
|
|
173385
174291
|
async function startChatSession(options) {
|
|
174292
|
+
installInputReportFilter();
|
|
173386
174293
|
if (options.bare)
|
|
173387
174294
|
setNoDiscovery(true);
|
|
173388
174295
|
_cliAgentTypes = (options.agents ?? []).map((a) => ({ ...a, source: "programmatic" }));
|
|
@@ -173487,7 +174394,7 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
173487
174394
|
void (0, import_code_core19.fireObserverHook)(requestedWorkDir, "WorktreeRemove", { name: worktreeState.name, path: worktreeState.worktreePath }, worktreeState.name);
|
|
173488
174395
|
});
|
|
173489
174396
|
}
|
|
173490
|
-
const env4 = collectEnv(workDir);
|
|
174397
|
+
const env4 = await collectEnv(workDir);
|
|
173491
174398
|
let briefBase = options.systemPrompt?.trim() ?? readNexrallMd(workDir);
|
|
173492
174399
|
const agentPrefix = options.selectedAgent?.prompt?.trim();
|
|
173493
174400
|
const briefParts = [agentPrefix, briefBase, options.appendSystemPrompt?.trim(), addDirNote(options.addDirs ?? []), options.jsonSchema ? schemaInstruction(options.jsonSchema) : ""];
|
|
@@ -173952,13 +174859,32 @@ ${text}` : "");
|
|
|
173952
174859
|
console.log(paint.green(` \u2713 Saved to ${saved.scope} memory`) + paint.dim(` \u2014 ${saved.file}`) + (saved.superseded ? paint.dim(" (the older fact moved to Superseded)") : ""));
|
|
173953
174860
|
}
|
|
173954
174861
|
};
|
|
173955
|
-
|
|
174862
|
+
let mcpPromptList = [];
|
|
174863
|
+
const allSlashEntries = () => {
|
|
174864
|
+
const base = [...BUILTIN_SLASH_COMMANDS, ...skillEntries((0, import_code_core18.userInvokableSkills)(skills))];
|
|
174865
|
+
return [...base, ...promptEntries(mcpPromptList, base)];
|
|
174866
|
+
};
|
|
173956
174867
|
let slashRecents = loadRecents();
|
|
173957
174868
|
const syncSlashMenu = () => {
|
|
173958
174869
|
if (interactive)
|
|
173959
174870
|
getInkTerminal().setSlashEntries(orderByRecents(allSlashEntries(), slashRecents));
|
|
173960
174871
|
};
|
|
174872
|
+
const refreshMcpPrompts = async () => {
|
|
174873
|
+
if (!_mcpManager)
|
|
174874
|
+
return;
|
|
174875
|
+
let list;
|
|
174876
|
+
try {
|
|
174877
|
+
list = await _mcpManager.listPrompts();
|
|
174878
|
+
} catch {
|
|
174879
|
+
return;
|
|
174880
|
+
}
|
|
174881
|
+
if (JSON.stringify(list) === JSON.stringify(mcpPromptList))
|
|
174882
|
+
return;
|
|
174883
|
+
mcpPromptList = list;
|
|
174884
|
+
syncSlashMenu();
|
|
174885
|
+
};
|
|
173961
174886
|
syncSlashMenu();
|
|
174887
|
+
void mcpStarted.then(() => refreshMcpPrompts());
|
|
173962
174888
|
if (interactive)
|
|
173963
174889
|
getInkTerminal().setMentionRoot(workDir);
|
|
173964
174890
|
const doRewind = (id) => {
|
|
@@ -174251,6 +175177,7 @@ ${text}` : "");
|
|
|
174251
175177
|
}
|
|
174252
175178
|
}
|
|
174253
175179
|
}
|
|
175180
|
+
void refreshMcpPrompts();
|
|
174254
175181
|
const outcome = {};
|
|
174255
175182
|
if (error !== void 0)
|
|
174256
175183
|
outcome.error = error;
|
|
@@ -174590,6 +175517,7 @@ ${text}` : "");
|
|
|
174590
175517
|
activeGoal = null;
|
|
174591
175518
|
criteriaLastLine = "";
|
|
174592
175519
|
cliBackgroundAgents.stopAll({ dropPending: true });
|
|
175520
|
+
(0, import_code_core19.resetHookOnceState)();
|
|
174593
175521
|
inputBuffer = "";
|
|
174594
175522
|
if (interactive)
|
|
174595
175523
|
await getInkTerminal().clearTranscript();
|
|
@@ -174796,7 +175724,7 @@ ${summaryText}` }] },
|
|
|
174796
175724
|
}
|
|
174797
175725
|
const readme = tryRead(path29.join(workDir, "README.md"))?.slice(0, 2e3) ?? "";
|
|
174798
175726
|
const pkgJson = tryRead(path29.join(workDir, "package.json"))?.slice(0, 1e3) ?? "";
|
|
174799
|
-
const dirList =
|
|
175727
|
+
const dirList = (await tryExecAsync("ls", ["-la"], workDir))?.slice(0, 500) ?? "";
|
|
174800
175728
|
const initPrompt = `Analyze this project and write a concise nexrall.md (project-specific instructions for an AI coding assistant).
|
|
174801
175729
|
Include: project overview, tech stack, coding conventions, important files/folders, what to avoid.
|
|
174802
175730
|
Keep it under 400 words. Use markdown. Be specific and actionable.
|
|
@@ -176134,6 +177062,26 @@ ${text}
|
|
|
176134
177062
|
rl.prompt();
|
|
176135
177063
|
return;
|
|
176136
177064
|
}
|
|
177065
|
+
const promptArg = /^prompts?(?:\s+(\S+))?$/i.exec(arg.trim());
|
|
177066
|
+
if (promptArg) {
|
|
177067
|
+
await refreshMcpPrompts();
|
|
177068
|
+
const rows = promptArg[1] ? mcpPromptList.filter((p) => p.server === promptArg[1]) : mcpPromptList;
|
|
177069
|
+
console.log(paint.bold(" MCP prompts:"));
|
|
177070
|
+
if (!rows.length) {
|
|
177071
|
+
console.log(" " + paint.dim(promptArg[1] ? `No prompts offered by "${promptArg[1]}".` : "No prompts offered by the connected servers."));
|
|
177072
|
+
} else {
|
|
177073
|
+
const width = Math.max(...rows.map((p) => `${p.server}:${p.name}`.length));
|
|
177074
|
+
for (const p of rows) {
|
|
177075
|
+
const args = (p.arguments ?? []).map((a) => a.required ? `<${a.name}>` : `[${a.name}]`).join(" ");
|
|
177076
|
+
console.log(" " + paint.cyan(`/${p.server}:${p.name}`.padEnd(width + 1)) + " " + (args ? paint.yellow(args) + " " : "") + paint.dim((p.description ?? "").replace(/\s+/g, " ").trim() || `MCP prompt from ${p.server}`));
|
|
177077
|
+
}
|
|
177078
|
+
console.log();
|
|
177079
|
+
console.log(" " + paint.dim("Run one: type /server:prompt with its arguments (positional; quotes keep spaces together)."));
|
|
177080
|
+
}
|
|
177081
|
+
console.log();
|
|
177082
|
+
rl.prompt();
|
|
177083
|
+
return;
|
|
177084
|
+
}
|
|
176137
177085
|
console.log(paint.bold(" MCP servers:"));
|
|
176138
177086
|
await handleMcp(arg);
|
|
176139
177087
|
console.log();
|
|
@@ -176572,7 +177520,43 @@ ${text}
|
|
|
176572
177520
|
return;
|
|
176573
177521
|
}
|
|
176574
177522
|
default: {
|
|
177523
|
+
const bare = cmd.slice(1);
|
|
177524
|
+
if (bare.startsWith("mcp__") || bare.includes(":"))
|
|
177525
|
+
await mcpReady();
|
|
176575
177526
|
const custom = (0, import_code_core18.findSkill)(skills, cmd);
|
|
177527
|
+
const mcpRef = custom && !bare.startsWith("mcp__") ? null : parseMcpPromptRef(bare, _mcpManager?.serverNames ?? []);
|
|
177528
|
+
if (mcpRef && _mcpManager) {
|
|
177529
|
+
let promptText;
|
|
177530
|
+
try {
|
|
177531
|
+
promptText = await _mcpManager.getPrompt(mcpRef.server, mcpRef.name, splitPromptArgs(arg));
|
|
177532
|
+
} catch (err) {
|
|
177533
|
+
console.log(paint.red(` ${err.message}`));
|
|
177534
|
+
rl.prompt();
|
|
177535
|
+
return;
|
|
177536
|
+
}
|
|
177537
|
+
console.log(paint.dim(` Running /${cmd} (MCP prompt from ${mcpRef.server})...`));
|
|
177538
|
+
checkpoints.beginTurn(`/${cmd} ${arg}`.trim(), messages.length);
|
|
177539
|
+
messages.push({ role: "user", content: [{ type: "text", text: promptText }] });
|
|
177540
|
+
rl.pause();
|
|
177541
|
+
abortSignal.aborted = false;
|
|
177542
|
+
agentRunning = true;
|
|
177543
|
+
try {
|
|
177544
|
+
const result = await runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrallMd, agentMode, effortLevel, checkpoints, saveProgress, takePendingInput, worktreeState, peerCtx);
|
|
177545
|
+
messages = result.messages;
|
|
177546
|
+
updateTitle();
|
|
177547
|
+
saveSession2(sessionId, sessionTitle, workDir, messages);
|
|
177548
|
+
} catch (err) {
|
|
177549
|
+
messages = recoverTurn(err, messages);
|
|
177550
|
+
updateTitle();
|
|
177551
|
+
saveSession2(sessionId, sessionTitle || "Untitled", workDir, messages);
|
|
177552
|
+
} finally {
|
|
177553
|
+
agentRunning = false;
|
|
177554
|
+
commitCheckpoint();
|
|
177555
|
+
}
|
|
177556
|
+
rl.resume();
|
|
177557
|
+
rl.prompt();
|
|
177558
|
+
return;
|
|
177559
|
+
}
|
|
176576
177560
|
if (!custom) {
|
|
176577
177561
|
console.log(paint.red(` Unknown command: ${cmd}`));
|
|
176578
177562
|
console.log(paint.dim(" Type /help for built-ins or /skills for custom ones."));
|
|
@@ -176666,6 +177650,7 @@ ${text}
|
|
|
176666
177650
|
rl.resume();
|
|
176667
177651
|
rl.prompt();
|
|
176668
177652
|
deliverBackgroundWhenIdle();
|
|
177653
|
+
deliverHookWakeWhenIdle();
|
|
176669
177654
|
});
|
|
176670
177655
|
async function runGoalLoop() {
|
|
176671
177656
|
while (activeGoal) {
|
|
@@ -176746,6 +177731,20 @@ ${text}
|
|
|
176746
177731
|
bgLastCount = n;
|
|
176747
177732
|
deliverBackgroundWhenIdle();
|
|
176748
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);
|
|
176749
177748
|
const loopTimer = setInterval(() => {
|
|
176750
177749
|
if (loopScheduler.size === 0)
|
|
176751
177750
|
return;
|