nexrall-code 0.5.160 → 0.5.162
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 +534 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3186,7 +3186,7 @@ var require_auth = __commonJS({
|
|
|
3186
3186
|
}();
|
|
3187
3187
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
3188
3188
|
exports2.saveAuth = saveAuth2;
|
|
3189
|
-
exports2.loadAuth =
|
|
3189
|
+
exports2.loadAuth = loadAuth3;
|
|
3190
3190
|
exports2.clearAuth = clearAuth2;
|
|
3191
3191
|
exports2.isAuthenticated = isAuthenticated4;
|
|
3192
3192
|
exports2.getToken = getToken2;
|
|
@@ -3207,7 +3207,7 @@ var require_auth = __commonJS({
|
|
|
3207
3207
|
ensureConfigDir();
|
|
3208
3208
|
fs27.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
|
|
3209
3209
|
}
|
|
3210
|
-
function
|
|
3210
|
+
function loadAuth3() {
|
|
3211
3211
|
const envToken = process.env.NEXRALL_TOKEN;
|
|
3212
3212
|
if (envToken && envToken.trim().length > 0) {
|
|
3213
3213
|
return { token: envToken.trim() };
|
|
@@ -3235,19 +3235,19 @@ var require_auth = __commonJS({
|
|
|
3235
3235
|
}
|
|
3236
3236
|
}
|
|
3237
3237
|
function isAuthenticated4() {
|
|
3238
|
-
const
|
|
3239
|
-
return
|
|
3238
|
+
const auth2 = loadAuth3();
|
|
3239
|
+
return auth2 !== null && auth2.token.length > 0;
|
|
3240
3240
|
}
|
|
3241
3241
|
function getToken2() {
|
|
3242
|
-
const
|
|
3243
|
-
return
|
|
3242
|
+
const auth2 = loadAuth3();
|
|
3243
|
+
return auth2?.token ?? null;
|
|
3244
3244
|
}
|
|
3245
3245
|
function getRefreshToken() {
|
|
3246
3246
|
const envToken = process.env.NEXRALL_TOKEN;
|
|
3247
3247
|
if (envToken && envToken.trim().length > 0)
|
|
3248
3248
|
return null;
|
|
3249
|
-
const
|
|
3250
|
-
const rt =
|
|
3249
|
+
const auth2 = loadAuth3();
|
|
3250
|
+
const rt = auth2?.refreshToken;
|
|
3251
3251
|
return typeof rt === "string" && rt.length > 0 ? rt : null;
|
|
3252
3252
|
}
|
|
3253
3253
|
function updateTokens(token, refreshToken) {
|
|
@@ -10369,9 +10369,18 @@ var require_client = __commonJS({
|
|
|
10369
10369
|
const haveCompleteMessage = () => completedMessage !== null;
|
|
10370
10370
|
const partialInputs = {};
|
|
10371
10371
|
let heartbeatWatchdog;
|
|
10372
|
+
let onControllerAbort;
|
|
10372
10373
|
try {
|
|
10373
10374
|
await new Promise((resolve11, reject) => {
|
|
10374
10375
|
const stream = response.body;
|
|
10376
|
+
onControllerAbort = () => {
|
|
10377
|
+
stream.destroy?.();
|
|
10378
|
+
resolve11();
|
|
10379
|
+
};
|
|
10380
|
+
if (controller.signal.aborted)
|
|
10381
|
+
onControllerAbort();
|
|
10382
|
+
else
|
|
10383
|
+
controller.signal.addEventListener("abort", onControllerAbort, { once: true });
|
|
10375
10384
|
const HEARTBEAT_TIMEOUT_MS = 9e4;
|
|
10376
10385
|
const FIRST_EVENT_TIMEOUT_MS = Number(process.env.NEXRALL_FIRST_EVENT_TIMEOUT_MS) || 3e5;
|
|
10377
10386
|
const PROGRESS_TIMEOUT_MS = Number(process.env.NEXRALL_PROGRESS_TIMEOUT_MS) || 15e4;
|
|
@@ -10646,6 +10655,8 @@ var require_client = __commonJS({
|
|
|
10646
10655
|
} finally {
|
|
10647
10656
|
if (heartbeatWatchdog !== void 0)
|
|
10648
10657
|
clearInterval(heartbeatWatchdog);
|
|
10658
|
+
if (onControllerAbort)
|
|
10659
|
+
controller.signal.removeEventListener("abort", onControllerAbort);
|
|
10649
10660
|
}
|
|
10650
10661
|
if (completedMessage) {
|
|
10651
10662
|
return completedMessage;
|
|
@@ -12129,7 +12140,7 @@ var require_agentTypes = __commonJS({
|
|
|
12129
12140
|
exports2.parseAgentHooks = parseAgentHooks;
|
|
12130
12141
|
exports2.loadAgentTypes = loadAgentTypes;
|
|
12131
12142
|
exports2.loadAgentTypesWithWarnings = loadAgentTypesWithWarnings2;
|
|
12132
|
-
exports2.knownToolNames =
|
|
12143
|
+
exports2.knownToolNames = knownToolNames3;
|
|
12133
12144
|
exports2.builtinAgents = builtinAgents;
|
|
12134
12145
|
exports2.summariseAgents = summariseAgents;
|
|
12135
12146
|
exports2.findAgentType = findAgentType;
|
|
@@ -12695,7 +12706,7 @@ var require_agentTypes = __commonJS({
|
|
|
12695
12706
|
});
|
|
12696
12707
|
return { types: types3, warnings };
|
|
12697
12708
|
}
|
|
12698
|
-
function
|
|
12709
|
+
function knownToolNames3() {
|
|
12699
12710
|
return [...KNOWN_TOOL_NAMES].sort();
|
|
12700
12711
|
}
|
|
12701
12712
|
function builtinAgents() {
|
|
@@ -104661,6 +104672,8 @@ var require_rules = __commonJS({
|
|
|
104661
104672
|
}();
|
|
104662
104673
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
104663
104674
|
exports2.setSessionRules = setSessionRules2;
|
|
104675
|
+
exports2.setSessionSettings = setSessionSettings2;
|
|
104676
|
+
exports2.getSessionSettings = getSessionSettings;
|
|
104664
104677
|
exports2.loadSettings = loadSettings5;
|
|
104665
104678
|
exports2.evaluatePermission = evaluatePermission4;
|
|
104666
104679
|
var fs27 = __importStar(__require("fs"));
|
|
@@ -104689,6 +104702,13 @@ var require_rules = __commonJS({
|
|
|
104689
104702
|
function setSessionRules2(r2) {
|
|
104690
104703
|
sessionRules = { allow: [...r2.allow ?? []], ask: [...r2.ask ?? []], deny: [...r2.deny ?? []] };
|
|
104691
104704
|
}
|
|
104705
|
+
var sessionSettings = null;
|
|
104706
|
+
function setSessionSettings2(obj2) {
|
|
104707
|
+
sessionSettings = obj2;
|
|
104708
|
+
}
|
|
104709
|
+
function getSessionSettings() {
|
|
104710
|
+
return sessionSettings;
|
|
104711
|
+
}
|
|
104692
104712
|
function loadSettings5(workDir) {
|
|
104693
104713
|
const tiers = [
|
|
104694
104714
|
managedSettingsPath(),
|
|
@@ -104708,6 +104728,13 @@ var require_rules = __commonJS({
|
|
|
104708
104728
|
merged.ask.push(...r2.ask);
|
|
104709
104729
|
merged.deny.push(...r2.deny);
|
|
104710
104730
|
}
|
|
104731
|
+
if (sessionSettings) {
|
|
104732
|
+
Object.assign(raw, sessionSettings);
|
|
104733
|
+
const r2 = extractRules(sessionSettings);
|
|
104734
|
+
merged.allow.push(...r2.allow);
|
|
104735
|
+
merged.ask.push(...r2.ask);
|
|
104736
|
+
merged.deny.push(...r2.deny);
|
|
104737
|
+
}
|
|
104711
104738
|
merged.allow.push(...sessionRules.allow);
|
|
104712
104739
|
merged.ask.push(...sessionRules.ask);
|
|
104713
104740
|
merged.deny.push(...sessionRules.deny);
|
|
@@ -106876,7 +106903,9 @@ var require_loop = __commonJS({
|
|
|
106876
106903
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
106877
106904
|
exports2.VERIFY_CMD_RE = exports2.WRITE_TOOL_NAMES = exports2.ToolNotAllowedError = exports2.AGENT_MEMORY_TOOL_SCHEMA = exports2.AGENT_MEMORY_TOOL = exports2._stallLimits = exports2._emptyTurnRetry = exports2.bashNeedsRepoLock = void 0;
|
|
106878
106905
|
exports2.runLifecycleHooks = runLifecycleHooks;
|
|
106906
|
+
exports2.runPermissionRequestHooks = runPermissionRequestHooks2;
|
|
106879
106907
|
exports2.fireNotificationHooks = fireNotificationHooks2;
|
|
106908
|
+
exports2.fireManualPostCompactHook = fireManualPostCompactHook2;
|
|
106880
106909
|
exports2.fireManualPreCompactHook = fireManualPreCompactHook2;
|
|
106881
106910
|
exports2.emptyTurnBackoffMs = emptyTurnBackoffMs;
|
|
106882
106911
|
exports2.shouldRetryEmptyTurn = shouldRetryEmptyTurn;
|
|
@@ -106970,6 +106999,15 @@ var require_loop = __commonJS({
|
|
|
106970
106999
|
fromSettings = JSON.parse(fs27.readFileSync(p, "utf-8")).hooks ?? {};
|
|
106971
107000
|
} catch {
|
|
106972
107001
|
}
|
|
107002
|
+
const sess = (0, rules_1.getSessionSettings)()?.hooks;
|
|
107003
|
+
if (sess && typeof sess === "object") {
|
|
107004
|
+
const base = { ...fromSettings };
|
|
107005
|
+
for (const [phase, list] of Object.entries(sess)) {
|
|
107006
|
+
if (Array.isArray(list))
|
|
107007
|
+
base[phase] = [...base[phase] ?? [], ...list];
|
|
107008
|
+
}
|
|
107009
|
+
fromSettings = base;
|
|
107010
|
+
}
|
|
106973
107011
|
const fromPlugins = (0, index_1.pluginHooks)(workDir);
|
|
106974
107012
|
const merged = { ...fromSettings };
|
|
106975
107013
|
for (const phase of Object.keys(fromPlugins)) {
|
|
@@ -107121,6 +107159,15 @@ var require_loop = __commonJS({
|
|
|
107121
107159
|
if (out.startsWith("{")) {
|
|
107122
107160
|
try {
|
|
107123
107161
|
const j = JSON.parse(out);
|
|
107162
|
+
if (event === "PermissionRequest") {
|
|
107163
|
+
const d = j.hookSpecificOutput?.decision?.behavior ?? (typeof j.decision === "string" ? j.decision : j.decision?.behavior);
|
|
107164
|
+
if (d === "allow" || d === "approve")
|
|
107165
|
+
outcome.allow = true;
|
|
107166
|
+
else if (d === "deny" || d === "block") {
|
|
107167
|
+
outcome.block = true;
|
|
107168
|
+
outcome.reason = j.reason ?? j.hookSpecificOutput?.decision?.message ?? outcome.reason ?? "Denied by PermissionRequest hook";
|
|
107169
|
+
}
|
|
107170
|
+
}
|
|
107124
107171
|
if (j.decision === "block") {
|
|
107125
107172
|
outcome.block = true;
|
|
107126
107173
|
outcome.reason = j.reason ?? outcome.reason ?? `Blocked by ${event} hook`;
|
|
@@ -107139,6 +107186,20 @@ var require_loop = __commonJS({
|
|
|
107139
107186
|
}
|
|
107140
107187
|
return outcome;
|
|
107141
107188
|
}
|
|
107189
|
+
async function runPermissionRequestHooks2(workDir, tool, input, sessionId = "") {
|
|
107190
|
+
try {
|
|
107191
|
+
const items = loadHooks(workDir).PermissionRequest;
|
|
107192
|
+
if (!items?.length)
|
|
107193
|
+
return { answer: null };
|
|
107194
|
+
const o = await runLifecycleHooks(items, "PermissionRequest", workDir, { session_id: sessionId, tool_name: tool, tool_input: input }, tool);
|
|
107195
|
+
if (o.block)
|
|
107196
|
+
return { answer: "deny", reason: o.reason };
|
|
107197
|
+
if (o.allow)
|
|
107198
|
+
return { answer: "allow" };
|
|
107199
|
+
} catch {
|
|
107200
|
+
}
|
|
107201
|
+
return { answer: null };
|
|
107202
|
+
}
|
|
107142
107203
|
function fireNotificationHooks2(workDir, message, type = "permission_prompt") {
|
|
107143
107204
|
try {
|
|
107144
107205
|
const items = loadHooks(workDir).Notification;
|
|
@@ -107149,6 +107210,15 @@ var require_loop = __commonJS({
|
|
|
107149
107210
|
} catch {
|
|
107150
107211
|
}
|
|
107151
107212
|
}
|
|
107213
|
+
async function fireManualPostCompactHook2(workDir, sessionId, messagesSummarized) {
|
|
107214
|
+
try {
|
|
107215
|
+
const items = loadHooks(workDir).PostCompact;
|
|
107216
|
+
if (!items?.length)
|
|
107217
|
+
return;
|
|
107218
|
+
await runLifecycleHooks(items, "PostCompact", workDir, { trigger: "manual", session_id: sessionId, messages_summarized: messagesSummarized }, "manual");
|
|
107219
|
+
} catch {
|
|
107220
|
+
}
|
|
107221
|
+
}
|
|
107152
107222
|
async function fireManualPreCompactHook2(workDir, sessionId, messagesToSummarize) {
|
|
107153
107223
|
try {
|
|
107154
107224
|
const items = loadHooks(workDir).PreCompact;
|
|
@@ -107960,6 +108030,23 @@ ${stats}${isoNote}`;
|
|
|
107960
108030
|
try {
|
|
107961
108031
|
if (started)
|
|
107962
108032
|
started.value = true;
|
|
108033
|
+
{
|
|
108034
|
+
const subAgentName = agent?.name ?? (typeof input.subagent_type === "string" && input.subagent_type ? input.subagent_type : "general-purpose");
|
|
108035
|
+
const startItems = loadHooks(options.workDir).SubagentStart;
|
|
108036
|
+
if (startItems?.length) {
|
|
108037
|
+
const o = await runLifecycleHooks(startItems, "SubagentStart", options.workDir, { session_id: options.sessionId ?? "", agent_type: subAgentName, description: String(input.description ?? "") }, subAgentName).catch(() => ({ block: false }));
|
|
108038
|
+
if (o.context) {
|
|
108039
|
+
const last = subMessages[subMessages.length - 1];
|
|
108040
|
+
if (last && Array.isArray(last.content)) {
|
|
108041
|
+
subMessages[subMessages.length - 1] = { ...last, content: [...last.content, { type: "text", text: `
|
|
108042
|
+
|
|
108043
|
+
<hook-context>
|
|
108044
|
+
${o.context}
|
|
108045
|
+
</hook-context>` }] };
|
|
108046
|
+
}
|
|
108047
|
+
}
|
|
108048
|
+
}
|
|
108049
|
+
}
|
|
107963
108050
|
const childRun = runAgentLoop2(subMessages, {
|
|
107964
108051
|
...options,
|
|
107965
108052
|
_depth: depth + 1,
|
|
@@ -108511,6 +108598,11 @@ Do NOT call any tools and do NOT continue the task. Reply with text only: a conc
|
|
|
108511
108598
|
}
|
|
108512
108599
|
const toSummarize = messages.slice(0, cut);
|
|
108513
108600
|
const kept = messages.slice(cut);
|
|
108601
|
+
const firePostCompact = async () => {
|
|
108602
|
+
if ((options._depth ?? 0) !== 0)
|
|
108603
|
+
return;
|
|
108604
|
+
await runLifecycleHooks(loadHooks(options.workDir).PostCompact, "PostCompact", options.workDir, { trigger: "auto", session_id: options.sessionId ?? "", messages_summarized: cut }, "auto").catch(() => void 0);
|
|
108605
|
+
};
|
|
108514
108606
|
const originalTask = originalTaskText(toSummarize);
|
|
108515
108607
|
const summaryPrompt = `Summarize this coding-session transcript into concise bullet points the assistant needs to continue the work: key decisions, files changed (and how), commands run, unresolved problems, and user preferences. Max 400 words.
|
|
108516
108608
|
|
|
@@ -108579,6 +108671,7 @@ ${taskBlock}${ledgerBlock}Summary of the earlier conversation so far:
|
|
|
108579
108671
|
${summary}
|
|
108580
108672
|
|
|
108581
108673
|
Continue the work from here.` }] });
|
|
108674
|
+
await firePostCompact();
|
|
108582
108675
|
return true;
|
|
108583
108676
|
}
|
|
108584
108677
|
async function maybeCompactMemory(scope, options) {
|
|
@@ -108755,7 +108848,7 @@ Continue the work from here.` }] });
|
|
|
108755
108848
|
async function runAgentLoop2(initialMessages, options) {
|
|
108756
108849
|
const messages = [...initialMessages];
|
|
108757
108850
|
const model = options.model ?? "turbo";
|
|
108758
|
-
const hooks = withAgentHooks(loadHooks(options.workDir), options._agentHooks);
|
|
108851
|
+
const hooks = options.disableHooks ? withAgentHooks({}, options._agentHooks) : withAgentHooks(loadHooks(options.workDir), options._agentHooks);
|
|
108759
108852
|
const depth = options._depth ?? 0;
|
|
108760
108853
|
const agentScope = options._agentScope ?? "root";
|
|
108761
108854
|
const isMainAgent = depth === 0;
|
|
@@ -109292,6 +109385,15 @@ ${ctx}
|
|
|
109292
109385
|
void maybeCompactMemory(scope, options);
|
|
109293
109386
|
}
|
|
109294
109387
|
const post = await runToolHooks(hooks.PostToolUse, "PostToolUse", name, input, options.workDir, result);
|
|
109388
|
+
if (result.error !== void 0 && (hooks.PostToolUseFailure?.length ?? 0) > 0) {
|
|
109389
|
+
const f3 = await runLifecycleHooks(hooks.PostToolUseFailure, "PostToolUseFailure", options.workDir, { session_id: options.sessionId ?? "", tool_name: name, tool_input: input, error: String(result.error).slice(0, 4e3) }, name).catch(() => ({ block: false }));
|
|
109390
|
+
if (f3.context)
|
|
109391
|
+
post.context = [post.context, f3.context].filter(Boolean).join("\n");
|
|
109392
|
+
if (f3.block) {
|
|
109393
|
+
post.block = true;
|
|
109394
|
+
post.reason = [post.reason, f3.reason].filter(Boolean).join("; ");
|
|
109395
|
+
}
|
|
109396
|
+
}
|
|
109295
109397
|
const injected = [pre.context, post.context].filter(Boolean).join("\n");
|
|
109296
109398
|
if (injected) {
|
|
109297
109399
|
if (result.error !== void 0)
|
|
@@ -109419,6 +109521,9 @@ ${result.output}` : `Error: ${result.error}` : result.output ?? "",
|
|
|
109419
109521
|
throw err;
|
|
109420
109522
|
throw new types_1.AgentTurnError(err?.message || "The turn ended unexpectedly", trimToResumableBoundary(messages), completedRounds, err);
|
|
109421
109523
|
} finally {
|
|
109524
|
+
if (depth === 0 && (hooks.SessionEnd?.length ?? 0) > 0) {
|
|
109525
|
+
await runLifecycleHooks(hooks.SessionEnd, "SessionEnd", options.workDir, { session_id: options.sessionId ?? "", reason: stopReason }, stopReason).catch(() => void 0);
|
|
109526
|
+
}
|
|
109422
109527
|
if (depth === 0)
|
|
109423
109528
|
await runSimpleHooks(hooks.OnStop, options.workDir);
|
|
109424
109529
|
else
|
|
@@ -151562,6 +151667,13 @@ async function requestPermissionInner(req) {
|
|
|
151562
151667
|
console.error(paint.yellow(` \u2298 Plan mode \u2014 refused ${tool} (read-only until you switch mode).`));
|
|
151563
151668
|
return false;
|
|
151564
151669
|
}
|
|
151670
|
+
const hook = await (0, import_code_core5.runPermissionRequestHooks)(_workDir, tool, input);
|
|
151671
|
+
if (hook.answer === "allow")
|
|
151672
|
+
return true;
|
|
151673
|
+
if (hook.answer === "deny") {
|
|
151674
|
+
console.error(paint.red(` \u2716 Denied by PermissionRequest hook: ${hook.reason ?? tool}`));
|
|
151675
|
+
return false;
|
|
151676
|
+
}
|
|
151565
151677
|
return serialisePrompt(() => askFlow(req));
|
|
151566
151678
|
}
|
|
151567
151679
|
async function requestPermission(req) {
|
|
@@ -151897,6 +152009,8 @@ function checkHeadlessOnly(f3) {
|
|
|
151897
152009
|
return "--max-budget-usd only works with --output-format (a one-shot, non-interactive run).";
|
|
151898
152010
|
if (f3.noSessionPersistence)
|
|
151899
152011
|
return "--no-session-persistence only works with --output-format (a one-shot, non-interactive run).";
|
|
152012
|
+
if (f3.maxTurns !== void 0)
|
|
152013
|
+
return "--max-turns only works with --output-format (a one-shot, non-interactive run).";
|
|
151900
152014
|
return null;
|
|
151901
152015
|
}
|
|
151902
152016
|
function headlessVerdict(i2) {
|
|
@@ -152065,6 +152179,182 @@ function validateJsonSchema(value, schema, at = "$") {
|
|
|
152065
152179
|
}
|
|
152066
152180
|
return errs;
|
|
152067
152181
|
}
|
|
152182
|
+
function parseMaxTurns(raw) {
|
|
152183
|
+
const s2 = String(raw).trim();
|
|
152184
|
+
const n = Number(s2);
|
|
152185
|
+
if (!/^\d+$/.test(s2) || !Number.isSafeInteger(n) || n < 1) {
|
|
152186
|
+
return { ok: false, error: `Invalid --max-turns "${raw}". Use a whole number of 1 or more, e.g. 10` };
|
|
152187
|
+
}
|
|
152188
|
+
return { ok: true, value: n };
|
|
152189
|
+
}
|
|
152190
|
+
function readPromptFile(file, cwd2, flag = "--append-system-prompt-file") {
|
|
152191
|
+
const abs = path7.resolve(cwd2, file);
|
|
152192
|
+
let text;
|
|
152193
|
+
try {
|
|
152194
|
+
text = fs6.readFileSync(abs, "utf-8");
|
|
152195
|
+
} catch {
|
|
152196
|
+
return { ok: false, error: `${flag}: cannot read "${file}"` };
|
|
152197
|
+
}
|
|
152198
|
+
if (!text.trim())
|
|
152199
|
+
return { ok: false, error: `${flag}: "${file}" is empty` };
|
|
152200
|
+
return { ok: true, value: text.trim() };
|
|
152201
|
+
}
|
|
152202
|
+
var CLAUDE_TOOL_ALIASES = {
|
|
152203
|
+
Read: ["read_file", "list_directory", "search_files", "glob", "notebook_read"],
|
|
152204
|
+
Edit: ["edit_file", "multi_edit", "notebook_edit"],
|
|
152205
|
+
Write: ["write_file", "write_docx", "write_xlsx", "write_pptx"],
|
|
152206
|
+
Bash: ["bash", "bash_output", "kill_shell"],
|
|
152207
|
+
Glob: ["glob"],
|
|
152208
|
+
Grep: ["search_files"],
|
|
152209
|
+
WebFetch: ["fetch_url"],
|
|
152210
|
+
WebSearch: ["web_search"],
|
|
152211
|
+
Task: ["task"],
|
|
152212
|
+
TodoWrite: ["todo_write", "todo_read"],
|
|
152213
|
+
NotebookEdit: ["notebook_edit"]
|
|
152214
|
+
};
|
|
152215
|
+
function parseToolsFlag(raw, known) {
|
|
152216
|
+
const out = /* @__PURE__ */ new Set();
|
|
152217
|
+
const trimmed = String(raw).trim();
|
|
152218
|
+
if (trimmed === "")
|
|
152219
|
+
return { ok: true, value: [] };
|
|
152220
|
+
if (trimmed.toLowerCase() === "default")
|
|
152221
|
+
return { ok: true, value: [...known] };
|
|
152222
|
+
for (const piece of parseToolList(trimmed)) {
|
|
152223
|
+
if (CLAUDE_TOOL_ALIASES[piece]) {
|
|
152224
|
+
CLAUDE_TOOL_ALIASES[piece].forEach((t2) => out.add(t2));
|
|
152225
|
+
continue;
|
|
152226
|
+
}
|
|
152227
|
+
if (known.includes(piece) || piece.startsWith("mcp__")) {
|
|
152228
|
+
out.add(piece);
|
|
152229
|
+
continue;
|
|
152230
|
+
}
|
|
152231
|
+
return { ok: false, error: `--tools: unknown tool "${piece}". Known: ${[...Object.keys(CLAUDE_TOOL_ALIASES), ...known].join(", ")}` };
|
|
152232
|
+
}
|
|
152233
|
+
return { ok: true, value: [...out] };
|
|
152234
|
+
}
|
|
152235
|
+
function parseSessionId(raw) {
|
|
152236
|
+
const s2 = String(raw).trim();
|
|
152237
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(s2)) {
|
|
152238
|
+
return { ok: false, error: `Invalid --session-id "${raw}". Use letters, digits, "-" or "_" (max 64), e.g. a UUID` };
|
|
152239
|
+
}
|
|
152240
|
+
return { ok: true, value: s2 };
|
|
152241
|
+
}
|
|
152242
|
+
function parseSessionName(raw) {
|
|
152243
|
+
const s2 = String(raw).replace(/\s+/g, " ").trim();
|
|
152244
|
+
if (!s2)
|
|
152245
|
+
return { ok: false, error: "Invalid --name: it is empty" };
|
|
152246
|
+
return { ok: true, value: s2.slice(0, 80) };
|
|
152247
|
+
}
|
|
152248
|
+
function checkSessionIdentityFlags(f3) {
|
|
152249
|
+
const resuming = f3.resume !== void 0 || !!f3.continue;
|
|
152250
|
+
if (f3.fork && !resuming)
|
|
152251
|
+
return "--fork-session needs --resume <id> or --continue (there is nothing to fork otherwise).";
|
|
152252
|
+
if (f3.sessionId && resuming && !f3.fork)
|
|
152253
|
+
return "--session-id starts a new conversation; with --resume/--continue add --fork-session to branch it under that id.";
|
|
152254
|
+
return null;
|
|
152255
|
+
}
|
|
152256
|
+
function matchSessionByName(sessions, name) {
|
|
152257
|
+
const want = name.trim().toLowerCase();
|
|
152258
|
+
const hits = sessions.filter((s2) => s2.title.trim().toLowerCase() === want).sort((a, b) => b.updatedAt - a.updatedAt);
|
|
152259
|
+
return hits[0] ?? null;
|
|
152260
|
+
}
|
|
152261
|
+
function parseSettingsArg(spec, cwd2) {
|
|
152262
|
+
const s2 = String(spec).trim();
|
|
152263
|
+
let text = s2;
|
|
152264
|
+
if (!s2.startsWith("{")) {
|
|
152265
|
+
try {
|
|
152266
|
+
text = fs6.readFileSync(path7.resolve(cwd2, s2), "utf-8");
|
|
152267
|
+
} catch {
|
|
152268
|
+
return { ok: false, error: `--settings: cannot read "${s2}"` };
|
|
152269
|
+
}
|
|
152270
|
+
}
|
|
152271
|
+
let v;
|
|
152272
|
+
try {
|
|
152273
|
+
v = JSON.parse(text);
|
|
152274
|
+
} catch {
|
|
152275
|
+
return { ok: false, error: `--settings: ${s2.startsWith("{") ? "the inline value" : `"${s2}"`} is not valid JSON` };
|
|
152276
|
+
}
|
|
152277
|
+
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
152278
|
+
return { ok: false, error: "--settings: expected a JSON object" };
|
|
152279
|
+
return { ok: true, value: v };
|
|
152280
|
+
}
|
|
152281
|
+
function authStatusReport(a, env4) {
|
|
152282
|
+
if (!a || !a.token)
|
|
152283
|
+
return { loggedIn: false, source: null };
|
|
152284
|
+
const fromEnv = !!env4.NEXRALL_TOKEN && env4.NEXRALL_TOKEN.trim().length > 0;
|
|
152285
|
+
return { loggedIn: true, source: fromEnv ? "env" : "login", ...a.email ? { email: a.email } : {} };
|
|
152286
|
+
}
|
|
152287
|
+
function isFallbackWorthy(message) {
|
|
152288
|
+
const m2 = String(message);
|
|
152289
|
+
if (/\b(401|402|403|400|404|413|422)\b/.test(m2) && !/\b(429|5\d\d)\b/.test(m2))
|
|
152290
|
+
return false;
|
|
152291
|
+
return /\b(429|500|502|503|504|529)\b|overload|rate.?limit|ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|socket hang up|fetch failed|stream (failed|stalled|ended)|timed? ?out/i.test(m2);
|
|
152292
|
+
}
|
|
152293
|
+
function parseFallbackModel(raw, primary) {
|
|
152294
|
+
const s2 = String(raw).trim();
|
|
152295
|
+
if (!s2)
|
|
152296
|
+
return { ok: false, error: "Invalid --fallback-model: it is empty" };
|
|
152297
|
+
if (s2 === primary)
|
|
152298
|
+
return { ok: false, error: `--fallback-model "${s2}" is the same as the main model; pick a different one` };
|
|
152299
|
+
return { ok: true, value: s2 };
|
|
152300
|
+
}
|
|
152301
|
+
function resolveSystemPrompt(f3) {
|
|
152302
|
+
if (f3.text !== void 0 && f3.file !== void 0) {
|
|
152303
|
+
return { ok: false, error: "--system-prompt and --system-prompt-file are mutually exclusive \u2014 pick one." };
|
|
152304
|
+
}
|
|
152305
|
+
if (f3.file !== void 0) {
|
|
152306
|
+
const r2 = readPromptFile(f3.file, f3.cwd, "--system-prompt-file");
|
|
152307
|
+
if (!r2.ok)
|
|
152308
|
+
return r2;
|
|
152309
|
+
if (!r2.value.trim())
|
|
152310
|
+
return { ok: false, error: `--system-prompt-file: ${f3.file} is empty.` };
|
|
152311
|
+
return { ok: true, value: r2.value };
|
|
152312
|
+
}
|
|
152313
|
+
if (f3.text !== void 0) {
|
|
152314
|
+
if (!f3.text.trim())
|
|
152315
|
+
return { ok: false, error: "--system-prompt: the value is empty." };
|
|
152316
|
+
return { ok: true, value: f3.text };
|
|
152317
|
+
}
|
|
152318
|
+
return { ok: true, value: void 0 };
|
|
152319
|
+
}
|
|
152320
|
+
function checkPartialMessages(f3) {
|
|
152321
|
+
if (!f3.includePartial)
|
|
152322
|
+
return null;
|
|
152323
|
+
if (f3.outputFormat !== "stream-json") {
|
|
152324
|
+
return "--include-partial-messages needs --output-format stream-json (it streams model deltas as they arrive).";
|
|
152325
|
+
}
|
|
152326
|
+
return null;
|
|
152327
|
+
}
|
|
152328
|
+
function checkReplayUserMessages(f3) {
|
|
152329
|
+
if (!f3.replay)
|
|
152330
|
+
return null;
|
|
152331
|
+
if (f3.inputFormat !== "stream-json") {
|
|
152332
|
+
return "--replay-user-messages needs --input-format stream-json (there is nothing to replay otherwise).";
|
|
152333
|
+
}
|
|
152334
|
+
if (f3.outputFormat !== "stream-json") {
|
|
152335
|
+
return "--replay-user-messages needs --output-format stream-json (the echo is written as an output event).";
|
|
152336
|
+
}
|
|
152337
|
+
return null;
|
|
152338
|
+
}
|
|
152339
|
+
function streamEventPayload(kind, chunk, extra = {}) {
|
|
152340
|
+
const delta = kind === "text" ? { type: "text_delta", text: chunk } : kind === "thinking" ? { type: "thinking_delta", thinking: chunk } : { type: "input_json_delta", partial_json: chunk };
|
|
152341
|
+
return { type: "stream_event", event: { type: "content_block_delta", delta }, ...extra };
|
|
152342
|
+
}
|
|
152343
|
+
function initEventPayload(i2) {
|
|
152344
|
+
return {
|
|
152345
|
+
type: "system",
|
|
152346
|
+
subtype: "init",
|
|
152347
|
+
session_id: i2.sessionId ?? "",
|
|
152348
|
+
cwd: i2.cwd,
|
|
152349
|
+
model: i2.model,
|
|
152350
|
+
tools: i2.tools,
|
|
152351
|
+
...i2.mcpServers ? { mcp_servers: i2.mcpServers } : {},
|
|
152352
|
+
...i2.permissionMode ? { permission_mode: i2.permissionMode } : {}
|
|
152353
|
+
};
|
|
152354
|
+
}
|
|
152355
|
+
function userReplayPayload(text) {
|
|
152356
|
+
return { type: "user", message: { role: "user", content: [{ type: "text", text }] } };
|
|
152357
|
+
}
|
|
152068
152358
|
|
|
152069
152359
|
// src/commands/chat.ts
|
|
152070
152360
|
var import_code_core17 = __toESM(require_dist3(), 1);
|
|
@@ -167955,6 +168245,10 @@ function refreshEnvForTurn(env4, workDir) {
|
|
|
167955
168245
|
...collectGitEnv(workDir)
|
|
167956
168246
|
};
|
|
167957
168247
|
}
|
|
168248
|
+
var noDiscovery = false;
|
|
168249
|
+
function setNoDiscovery(v) {
|
|
168250
|
+
noDiscovery = v;
|
|
168251
|
+
}
|
|
167958
168252
|
var NEXRALL_MD_CANDIDATES = [
|
|
167959
168253
|
"nexrall.md",
|
|
167960
168254
|
"NEXRALL.md",
|
|
@@ -167969,6 +168263,8 @@ var tryRead = (p) => {
|
|
|
167969
168263
|
}
|
|
167970
168264
|
};
|
|
167971
168265
|
function readNexrallMd(workDir) {
|
|
168266
|
+
if (noDiscovery)
|
|
168267
|
+
return void 0;
|
|
167972
168268
|
const parts = [];
|
|
167973
168269
|
const memContent = (0, import_code_core15.readAllMemory)(workDir);
|
|
167974
168270
|
if (memContent)
|
|
@@ -168217,6 +168513,11 @@ var _mcpManager = null;
|
|
|
168217
168513
|
var _mcpConfig = null;
|
|
168218
168514
|
var sessionTouched = [];
|
|
168219
168515
|
async function initMcp(workDir, override, strict) {
|
|
168516
|
+
if (noDiscovery && !override) {
|
|
168517
|
+
_mcpConfig = { mcpServers: {} };
|
|
168518
|
+
_mcpManager = null;
|
|
168519
|
+
return;
|
|
168520
|
+
}
|
|
168220
168521
|
_mcpConfig = strict && override ? { mcpServers: {} } : import_code_core15.McpManager.loadConfig(workDir);
|
|
168221
168522
|
if (override)
|
|
168222
168523
|
Object.assign(_mcpConfig.mcpServers, override.mcpServers);
|
|
@@ -168588,6 +168889,7 @@ function printErrorReport(err, aborted) {
|
|
|
168588
168889
|
for (const l2 of errorReportLines(err, aborted))
|
|
168589
168890
|
console.error(l2);
|
|
168590
168891
|
}
|
|
168892
|
+
var activeSessionIdGetter = () => void 0;
|
|
168591
168893
|
async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrallMd, mode, effort, checkpointManager, onProgress, takePendingInput, worktreeState, peerCtx) {
|
|
168592
168894
|
let lastUsage;
|
|
168593
168895
|
turnStats = freshTurnStats();
|
|
@@ -168622,6 +168924,7 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrall
|
|
|
168622
168924
|
spinner.start("thinking\u2026", { hint: false, verbs: true });
|
|
168623
168925
|
const result = await (0, import_code_core15.runAgentLoop)(messages, {
|
|
168624
168926
|
workDir,
|
|
168927
|
+
sessionId: activeSessionIdGetter(),
|
|
168625
168928
|
model: modelAlias,
|
|
168626
168929
|
env: refreshEnvForTurn(env4, workDir),
|
|
168627
168930
|
nexrallMd,
|
|
@@ -168654,6 +168957,7 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env4, nexrall
|
|
|
168654
168957
|
onInjectedInput: () => {
|
|
168655
168958
|
},
|
|
168656
168959
|
backgroundAgents: cliBackgroundAgents,
|
|
168960
|
+
disableHooks: noDiscovery,
|
|
168657
168961
|
// The backend streams a cumulative output-token count (routes/code.js's
|
|
168658
168962
|
// sendProgress, throttled to ≤5/s) covering thinking, visible text AND
|
|
168659
168963
|
// tool-argument JSON. This used to be stored in a variable and rendered only
|
|
@@ -168947,13 +169251,27 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
168947
169251
|
let resultText = "";
|
|
168948
169252
|
let toolCallCount = 0;
|
|
168949
169253
|
let budgetHit = false;
|
|
169254
|
+
let turnsHit = false;
|
|
168950
169255
|
const emit = (obj2) => {
|
|
168951
169256
|
if (format === "stream-json")
|
|
168952
169257
|
process.stdout.write(JSON.stringify(obj2) + "\n");
|
|
168953
169258
|
};
|
|
169259
|
+
const verbose = (line) => {
|
|
169260
|
+
if (_headlessPolicy.verbose)
|
|
169261
|
+
process.stderr.write(line + "\n");
|
|
169262
|
+
};
|
|
169263
|
+
emit(initEventPayload({
|
|
169264
|
+
sessionId: activeSessionIdGetter(),
|
|
169265
|
+
cwd: workDir,
|
|
169266
|
+
model: modelAlias,
|
|
169267
|
+
tools: _headlessPolicy.onlyTools ? [..._headlessPolicy.onlyTools].sort() : (0, import_code_core15.knownToolNames)(),
|
|
169268
|
+
permissionMode: _headlessPolicy.permissionMode
|
|
169269
|
+
}));
|
|
168954
169270
|
emit({ type: "start", model: modelAlias, workDir });
|
|
169271
|
+
verbose(`[verbose] model=${modelAlias} cwd=${workDir} mode=${mode} session=${activeSessionIdGetter() ?? "-"}`);
|
|
168955
169272
|
const result = await (0, import_code_core15.runAgentLoop)(messages, {
|
|
168956
169273
|
workDir,
|
|
169274
|
+
sessionId: activeSessionIdGetter(),
|
|
168957
169275
|
model: modelAlias,
|
|
168958
169276
|
env: refreshEnvForTurn(env4, workDir),
|
|
168959
169277
|
nexrallMd,
|
|
@@ -168961,11 +169279,26 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
168961
169279
|
planMode: mode === "plan",
|
|
168962
169280
|
worktree: worktreeState,
|
|
168963
169281
|
backgroundAgents: cliBackgroundAgents,
|
|
169282
|
+
disableHooks: noDiscovery,
|
|
168964
169283
|
effort,
|
|
168965
169284
|
abortSignal: _abortSignal,
|
|
169285
|
+
// `--max-turns`: a hard round cap. autoContinue off, or the loop would extend it.
|
|
169286
|
+
..._headlessPolicy.maxTurns !== void 0 ? { maxIterations: _headlessPolicy.maxTurns, autoContinue: false } : {},
|
|
169287
|
+
// `--tools`: the allowlist is the same one sub-agents use, so removed tools are not even offered.
|
|
169288
|
+
..._headlessPolicy.onlyTools ? { _allowedTools: _headlessPolicy.onlyTools } : {},
|
|
169289
|
+
// Setting this callback makes the loop stop printing its own stop notice, so re-emit it —
|
|
169290
|
+
// otherwise every stop reason (stalled, no balance…) would go silent in headless runs.
|
|
169291
|
+
_onStopReason: (reason, notice) => {
|
|
169292
|
+
if (reason === "budget" && _headlessPolicy.maxTurns !== void 0)
|
|
169293
|
+
turnsHit = true;
|
|
169294
|
+
if (notice)
|
|
169295
|
+
emit({ type: "notice", text: notice });
|
|
169296
|
+
},
|
|
168966
169297
|
onText: (text) => {
|
|
168967
169298
|
resultText += text;
|
|
168968
169299
|
emit({ type: "text", text });
|
|
169300
|
+
if (_headlessPolicy.includePartial)
|
|
169301
|
+
emit(streamEventPayload("text", text));
|
|
168969
169302
|
},
|
|
168970
169303
|
// ── Reasoning-phase liveness ──────────────────────────────────────
|
|
168971
169304
|
// These used to be UNWIRED here while runTurn() (interactive) wired all
|
|
@@ -168996,6 +169329,8 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
168996
169329
|
// dropped on the floor for every headless run.
|
|
168997
169330
|
onThinking: (text) => {
|
|
168998
169331
|
emit({ type: "thinking", text });
|
|
169332
|
+
if (_headlessPolicy.includePartial)
|
|
169333
|
+
emit(streamEventPayload("thinking", text));
|
|
168999
169334
|
},
|
|
169000
169335
|
// onThinkingDelta is intentionally NOT wired. Its chunks concatenate to the
|
|
169001
169336
|
// same string `onThinking` emits in full above, so emitting both would
|
|
@@ -169012,6 +169347,7 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
169012
169347
|
onToolUse: (name, input, isSubTask, meta) => {
|
|
169013
169348
|
debugLog("tool_use", { tool: name, sub: !!isSubTask });
|
|
169014
169349
|
emit({ type: "tool_use", tool: name, input, ...toolIds(isSubTask, meta) });
|
|
169350
|
+
verbose(`[verbose] -> ${name}${isSubTask ? " (sub-agent)" : ""} ${toolTarget(name, input)}`);
|
|
169015
169351
|
},
|
|
169016
169352
|
// Live bash progress for scripted/CI consumers — lets a wrapper tail a
|
|
169017
169353
|
// long-running build/test command instead of blocking silently until
|
|
@@ -169019,12 +169355,15 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
169019
169355
|
// which is head/tail-capped), so a chatty command can emit many of these.
|
|
169020
169356
|
onToolStreamChunk: (name, chunk, isSubTask, meta) => {
|
|
169021
169357
|
emit({ type: "tool_stream", tool: name, chunk, ...toolIds(isSubTask, meta) });
|
|
169358
|
+
if (_headlessPolicy.includePartial)
|
|
169359
|
+
emit(streamEventPayload("tool", chunk, { tool: name, ...toolIds(isSubTask, meta) }));
|
|
169022
169360
|
},
|
|
169023
169361
|
onToolResult: (name, res, isSubTask, meta) => {
|
|
169024
169362
|
if (!isSubTask)
|
|
169025
169363
|
toolCallCount++;
|
|
169026
169364
|
debugLog("tool_result", { tool: name, ok: res.error === void 0, error: res.error, sub: !!isSubTask });
|
|
169027
169365
|
emit({ type: "tool_result", tool: name, ok: res.error === void 0, ...res.error ? { error: res.error } : {}, ...toolIds(isSubTask, meta) });
|
|
169366
|
+
verbose(`[verbose] <- ${name} ${res.error === void 0 ? "ok" : "FAILED: " + String(res.error).slice(0, 200)}`);
|
|
169028
169367
|
},
|
|
169029
169368
|
// Headless consumers get the partial report too — tagged, so a script can account
|
|
169030
169369
|
// for the real cost of a restarted turn — but it never becomes `lastUsage`, which
|
|
@@ -169065,6 +169404,10 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
169065
169404
|
// no human to confirm, they are denied unless NEXRALL_ALLOW_DESTRUCTIVE=1 is
|
|
169066
169405
|
// explicitly set for this CI run.
|
|
169067
169406
|
requestPermission: async ({ tool, input }) => {
|
|
169407
|
+
if (_headlessPolicy.onlyTools && !_headlessPolicy.onlyTools.has(tool) && !tool.startsWith("mcp__")) {
|
|
169408
|
+
emit({ type: "permission_denied", tool, reason: "tools" });
|
|
169409
|
+
return false;
|
|
169410
|
+
}
|
|
169068
169411
|
const d = (0, import_code_core15.isDestructiveBash)(tool, input);
|
|
169069
169412
|
const v = headlessVerdict({
|
|
169070
169413
|
rule: (0, import_code_core17.evaluatePermission)((0, import_code_core17.loadSettings)(workDir).permissions, tool, input, workDir),
|
|
@@ -169104,6 +169447,7 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
169104
169447
|
}
|
|
169105
169448
|
const extra = {
|
|
169106
169449
|
..._headlessPolicy.budgetUsd !== void 0 ? { cost_usd: _headlessPolicy.spent, ...budgetHit ? { stopped: "budget" } : {} } : {},
|
|
169450
|
+
...turnsHit ? { stopped: "max_turns", max_turns: _headlessPolicy.maxTurns } : {},
|
|
169107
169451
|
...structured ? { structured_output: structured.value } : {},
|
|
169108
169452
|
...schemaError ? { schema_error: schemaError } : {}
|
|
169109
169453
|
};
|
|
@@ -169126,6 +169470,8 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env4
|
|
|
169126
169470
|
}
|
|
169127
169471
|
if (budgetHit)
|
|
169128
169472
|
process.exitCode = 2;
|
|
169473
|
+
else if (turnsHit)
|
|
169474
|
+
process.exitCode = 4;
|
|
169129
169475
|
return { messages: result, usage: lastUsage };
|
|
169130
169476
|
}
|
|
169131
169477
|
function kbKey(action) {
|
|
@@ -169306,6 +169652,8 @@ function printSessions() {
|
|
|
169306
169652
|
console.log();
|
|
169307
169653
|
}
|
|
169308
169654
|
async function startChatSession(options) {
|
|
169655
|
+
if (options.bare)
|
|
169656
|
+
setNoDiscovery(true);
|
|
169309
169657
|
(0, import_code_core15.enableAgentTranscriptPersistence)();
|
|
169310
169658
|
const headless = options.outputFormat === "json" || options.outputFormat === "stream-json";
|
|
169311
169659
|
const requestedWorkDir = options.workDir;
|
|
@@ -169401,8 +169749,12 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169401
169749
|
});
|
|
169402
169750
|
}
|
|
169403
169751
|
const env4 = collectEnv(workDir);
|
|
169404
|
-
const
|
|
169405
|
-
|
|
169752
|
+
const briefBase = options.systemPrompt?.trim() ?? readNexrallMd(workDir);
|
|
169753
|
+
const nexrallMd = [briefBase, options.appendSystemPrompt?.trim(), addDirNote(options.addDirs ?? []), options.jsonSchema ? schemaInstruction(options.jsonSchema) : ""].filter(Boolean).join("\n\n") || void 0;
|
|
169754
|
+
_headlessPolicy = { strict: !!options.strictPermissions, budgetUsd: options.budgetUsd, spent: 0, schema: options.jsonSchema, maxTurns: options.maxTurns, onlyTools: options.onlyTools ? new Set(options.onlyTools) : void 0 };
|
|
169755
|
+
_headlessPolicy.verbose = !!options.verbose;
|
|
169756
|
+
_headlessPolicy.includePartial = !!options.includePartialMessages;
|
|
169757
|
+
_headlessPolicy.permissionMode = String(options.initialMode ?? "");
|
|
169406
169758
|
const saveSession2 = options.noSessionPersistence ? () => {
|
|
169407
169759
|
} : saveSession;
|
|
169408
169760
|
const interactive = !headless && !options.prompt && !options.stdinText;
|
|
@@ -169478,8 +169830,9 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169478
169830
|
));
|
|
169479
169831
|
}
|
|
169480
169832
|
let messages = [];
|
|
169481
|
-
let sessionId = crypto6.randomBytes(8).toString("hex");
|
|
169482
|
-
|
|
169833
|
+
let sessionId = options.newSessionId ?? crypto6.randomBytes(8).toString("hex");
|
|
169834
|
+
activeSessionIdGetter = () => sessionId;
|
|
169835
|
+
let sessionTitle = options.sessionName ?? "";
|
|
169483
169836
|
const modeLocked = options.lockMode === true;
|
|
169484
169837
|
let agentMode = modeLocked ? "plan" : options.initialMode ?? "auto";
|
|
169485
169838
|
const refuseIfLocked = (what) => {
|
|
@@ -169501,7 +169854,7 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169501
169854
|
for (const n of themeConfig.notes)
|
|
169502
169855
|
console.log(paint.dim(" theme: " + n));
|
|
169503
169856
|
}
|
|
169504
|
-
let skills = (0, import_code_core15.loadSkills)(workDir);
|
|
169857
|
+
let skills = noDiscovery ? [] : (0, import_code_core15.loadSkills)(workDir);
|
|
169505
169858
|
if (skills.length && !headless)
|
|
169506
169859
|
console.log(paint.dim(` ${skills.length} skill(s) loaded`));
|
|
169507
169860
|
let contextSet = loadContextSet(workDir);
|
|
@@ -169531,7 +169884,7 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169531
169884
|
process.exit(1);
|
|
169532
169885
|
}
|
|
169533
169886
|
if (options.debug) {
|
|
169534
|
-
const dbgPath = enableDebug();
|
|
169887
|
+
const dbgPath = enableDebug(options.debugFile);
|
|
169535
169888
|
if (dbgPath) {
|
|
169536
169889
|
debugLog("start", { version: CLI_VERSION, node: process.version, platform: process.platform, model: modelAlias, mode: agentMode, locked: modeLocked, headless, interactive });
|
|
169537
169890
|
if (!headless)
|
|
@@ -169544,7 +169897,7 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169544
169897
|
}
|
|
169545
169898
|
}
|
|
169546
169899
|
if (options.resume || options.continueLast) {
|
|
169547
|
-
const stored = options.continueLast ? lastSessionForDir(workDir) : options.resume === "last" ? lastSession() : loadSession(options.resume);
|
|
169900
|
+
const stored = options.continueLast ? lastSessionForDir(workDir) : options.resume === "last" ? lastSession() : loadSession(options.resume) ?? matchSessionByName(listSessions(), options.resume);
|
|
169548
169901
|
if (!stored) {
|
|
169549
169902
|
if (options.continueLast) {
|
|
169550
169903
|
console.error(paint.red(" No conversation to continue in this folder."));
|
|
@@ -169558,7 +169911,13 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169558
169911
|
messages = stored.messages;
|
|
169559
169912
|
sessionId = stored.id;
|
|
169560
169913
|
sessionTitle = stored.title;
|
|
169561
|
-
|
|
169914
|
+
if (options.forkSession) {
|
|
169915
|
+
sessionId = options.newSessionId ?? crypto6.randomBytes(8).toString("hex");
|
|
169916
|
+
sessionTitle = options.sessionName ?? forkTitle(stored.title, "");
|
|
169917
|
+
} else if (options.sessionName) {
|
|
169918
|
+
sessionTitle = options.sessionName;
|
|
169919
|
+
}
|
|
169920
|
+
startSessionLog(sessionId, true, options.forkSession ? { workDir, forkOf: stored.id } : { workDir });
|
|
169562
169921
|
try {
|
|
169563
169922
|
const compacted = await (0, import_code_core15.compactMessagesForResume)(messages, {
|
|
169564
169923
|
workDir,
|
|
@@ -169632,6 +169991,9 @@ Resume it with: nex --worktree ${worktreeState.name}
|
|
|
169632
169991
|
${text}` : "");
|
|
169633
169992
|
}
|
|
169634
169993
|
checkpoints.beginTurn(text, messages.length);
|
|
169994
|
+
if (options.replayUserMessages && options.inputFormatWasStreamJson && options.outputFormat === "stream-json") {
|
|
169995
|
+
process.stdout.write(JSON.stringify(userReplayPayload(text)) + "\n");
|
|
169996
|
+
}
|
|
169635
169997
|
messages.push({ role: "user", content: [{ type: "text", text }] });
|
|
169636
169998
|
const abortSignal2 = { aborted: false };
|
|
169637
169999
|
const onSigint = () => {
|
|
@@ -169640,8 +170002,31 @@ ${text}` : "");
|
|
|
169640
170002
|
process.once("SIGINT", onSigint);
|
|
169641
170003
|
try {
|
|
169642
170004
|
const fmt = options.outputFormat;
|
|
170005
|
+
const replay = (text2) => {
|
|
170006
|
+
if (options.replayUserMessages && fmt === "stream-json")
|
|
170007
|
+
process.stdout.write(JSON.stringify(userReplayPayload(text2)) + "\n");
|
|
170008
|
+
};
|
|
169643
170009
|
const runOnce = () => fmt === "json" || fmt === "stream-json" ? runTurnHeadless(messages, modelAlias, workDir, abortSignal2, env4, nexrallMd, agentMode, effortLevel, fmt, checkpoints, saveProgress, worktreeState) : runTurn(messages, modelAlias, workDir, abortSignal2, env4, nexrallMd, agentMode, effortLevel, checkpoints, saveProgress, void 0, worktreeState, peerCtx);
|
|
169644
|
-
|
|
170010
|
+
const runWithFallback = async () => {
|
|
170011
|
+
try {
|
|
170012
|
+
return await runOnce();
|
|
170013
|
+
} catch (e2) {
|
|
170014
|
+
if (!options.fallbackModel || modelAlias === options.fallbackModel || abortSignal2.aborted || !isFallbackWorthy(String(e2.message)))
|
|
170015
|
+
throw e2;
|
|
170016
|
+
const from = modelAlias;
|
|
170017
|
+
modelAlias = options.fallbackModel;
|
|
170018
|
+
const salvagedMsgs = (0, import_code_core15.salvageHistory)(e2);
|
|
170019
|
+
if (salvagedMsgs)
|
|
170020
|
+
messages = salvagedMsgs;
|
|
170021
|
+
const note = `Model ${from} failed (${String(e2.message).slice(0, 120)}); retrying on ${modelAlias}`;
|
|
170022
|
+
if (fmt === "stream-json")
|
|
170023
|
+
process.stdout.write(JSON.stringify({ type: "notice", text: note }) + "\n");
|
|
170024
|
+
else
|
|
170025
|
+
console.error(note);
|
|
170026
|
+
return await runOnce();
|
|
170027
|
+
}
|
|
170028
|
+
};
|
|
170029
|
+
let result = await runWithFallback();
|
|
169645
170030
|
messages = result.messages;
|
|
169646
170031
|
while (!abortSignal2.aborted && (cliBackgroundAgents.runningCount() > 0 || cliBackgroundAgents.hasPending())) {
|
|
169647
170032
|
if (!cliBackgroundAgents.hasPending()) {
|
|
@@ -169658,6 +170043,7 @@ ${text}` : "");
|
|
|
169658
170043
|
break;
|
|
169659
170044
|
commitCheckpoint();
|
|
169660
170045
|
checkpoints.beginTurn(follow, messages.length);
|
|
170046
|
+
replay(follow);
|
|
169661
170047
|
messages.push({ role: "user", content: [{ type: "text", text: follow }] });
|
|
169662
170048
|
result = await runOnce();
|
|
169663
170049
|
messages = result.messages;
|
|
@@ -170565,6 +170951,7 @@ ${summaryText}` }] },
|
|
|
170565
170951
|
saveSession2(sessionId, sessionTitle || "Untitled", workDir, messages);
|
|
170566
170952
|
console.log(paint.green(` Compacted ${toSummarize.length} messages \u2192 ${messages.length} messages.`));
|
|
170567
170953
|
emitEvent("context.compacted", { where: "manual", before: toSummarize.length + KEEP, after: messages.length });
|
|
170954
|
+
await (0, import_code_core16.fireManualPostCompactHook)(workDir, sessionId, toSummarize.length);
|
|
170568
170955
|
if (pin.attachments.length)
|
|
170569
170956
|
console.log(paint.dim(` ${pin.attachments.length} pinned file(s) re-attached.`));
|
|
170570
170957
|
for (const n of pin.notes)
|
|
@@ -172905,7 +173292,17 @@ var require3 = createRequire2(import.meta.url);
|
|
|
172905
173292
|
var NEX_VERSION = require3("../package.json").version;
|
|
172906
173293
|
var program2 = new Command();
|
|
172907
173294
|
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version(NEX_VERSION).enablePositionalOptions();
|
|
172908
|
-
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
173295
|
+
var auth = program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
173296
|
+
auth.command("status").description("Show whether you are logged in (exit 0 = yes, 1 = no). --json for scripts; the token is never printed").option("--json", "Machine-readable output").action((opts) => {
|
|
173297
|
+
const r2 = authStatusReport((0, import_code_core21.loadAuth)(), process.env);
|
|
173298
|
+
if (opts.json)
|
|
173299
|
+
console.log(JSON.stringify(r2));
|
|
173300
|
+
else if (!r2.loggedIn)
|
|
173301
|
+
console.log("Not logged in. Run: nex auth");
|
|
173302
|
+
else
|
|
173303
|
+
console.log(`Logged in${r2.email ? ` as ${r2.email}` : ""} (${r2.source === "env" ? "NEXRALL_TOKEN" : "saved login"})`);
|
|
173304
|
+
process.exit(r2.loggedIn ? 0 : 1);
|
|
173305
|
+
});
|
|
172909
173306
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
172910
173307
|
program2.command("doctor").description("Check Node, sign-in, network, terminal, MCP and storage, with a fix for each problem").option("-d, --dir <path>", "Project folder to check (default: current directory)").action(async (opts) => {
|
|
172911
173308
|
const workDir = opts.dir ? path26.resolve(opts.dir) : process.cwd();
|
|
@@ -173104,7 +173501,7 @@ program2.command("sessions").description("List, export, import, or delete saved
|
|
|
173104
173501
|
console.log(paint.dim(" nex sessions --events <id> [--json] to follow its event stream"));
|
|
173105
173502
|
console.log();
|
|
173106
173503
|
});
|
|
173107
|
-
program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, --turbo", "Use Claude Sonnet 5.5 (fast)").option("-u, --ultra", "Use Claude Fable 5.1 (most powerful)").option("-y, --yolo", "Auto-approve all tool calls (no permission prompts)").option("-d, --dir <path>", "Set working directory (default: current directory)").option("-m, --model <name>", "Explicit model, e.g. claude-opus-5-5 | gpt-5.4 | gpt-4.1").option("-r, --resume [id]", "Resume last session, or a specific session id").option("-c, --continue", "Continue the latest conversation in this folder").option("--plan", "Start in plan mode (read-only; /mode or Shift+Tab can leave it)").option("--readonly", "Read-only for the whole session: plan mode that cannot be switched off").option("--auto", "Start in auto mode (the default \u2014 edits and commands run without asking)").option("--mode <mode>", "Starting permission mode: ask | edit | auto | plan").option("--fullscreen", "Draw the whole session on the terminal's alternate screen: the transcript re-wraps on resize and PgUp/PgDn page through it (no terminal scrollback while it is on; /fullscreen toggles it)").option("--bg", "Run the prompt in the background (headless); returns a job id. See: nex jobs | logs | attach | kill").option("--debug", "Write request timing, retries and errors to a debug log file").option("--no-color", "Disable colored output (also honours NO_COLOR)").option("-w, --worktree [name]", "Isolate this session in its own worktree \u2014 a separate directory (and, in a git repo, its own branch) so it can never overwrite files another session (or you) are touching in the main checkout. Omit a name for an auto-generated one; pass an existing name to resume that same worktree.").option("-e, --effort <level>", "Thinking effort \u2014 real levels depend on the model (e.g. DeepSeek: low|high|max, Qwen: low|high); run `nex --model <id>` then `/effort` with no argument to see a model's scale").option("--no-banner", "Skip the ASCII banner (useful in scripts/pipes)").option("--output-format <fmt>", "One-shot output format: text | json | stream-json (implies auto-approve)").option("--audit [path]", "Log every tool call (and refusal) to a JSONL trail (default: .nexrall/audit/<session>.jsonl)").option("--permission-mode <mode>", "Permission mode: ask | edit | auto | plan (also Claude Code names: default | acceptEdits | bypassPermissions). With --output-format, anything that would prompt is DENIED instead of auto-approved").option("--allowedTools, --allowed-tools <tools...>", 'Tools/rules to allow without asking, e.g. "Bash(git *)" Edit (comma or space separated; put the prompt BEFORE this flag)').option("--disallowedTools, --disallowed-tools <tools...>", 'Tools/rules to deny, e.g. "Bash(rm *)" (deny always wins)').option("--append-system-prompt <text>", "Extra instructions appended to the project brief for this run").option("--max-budget-usd <amount>", "Stop a one-shot run once it has spent this many dollars (needs --output-format)").option("--mcp-config <configs...>", 'Load MCP servers from JSON files or inline JSON ({"mcpServers":{\u2026}}) for this run').option("--strict-mcp-config", "With --mcp-config: use ONLY those servers, ignoring ~/.nexrall/mcp.json and the project one").option("--add-dir <dirs...>", "Extra directories the agent may read and edit besides the project folder").option("--input-format <format>", "text (default) | stream-json \u2014 read the prompt as Claude-Code-style NDJSON user messages on stdin").option("--json-schema <schema>", 'JSON Schema (inline or file) the final answer must satisfy; needs --output-format. Result gains "structured_output"; exit 3 if it does not validate').option("--no-session-persistence", "Do not save this run to disk (needs --output-format; it cannot be resumed)").argument("[prompt...]", "One-shot prompt \u2014 if omitted, starts interactive mode").action(async (promptParts, options) => {
|
|
173504
|
+
program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, --turbo", "Use Claude Sonnet 5.5 (fast)").option("-u, --ultra", "Use Claude Fable 5.1 (most powerful)").option("-y, --yolo", "Auto-approve all tool calls (no permission prompts)").option("-d, --dir <path>", "Set working directory (default: current directory)").option("-m, --model <name>", "Explicit model, e.g. claude-opus-5-5 | gpt-5.4 | gpt-4.1").option("-r, --resume [id]", "Resume last session, or a specific session id").option("-c, --continue", "Continue the latest conversation in this folder").option("--plan", "Start in plan mode (read-only; /mode or Shift+Tab can leave it)").option("--readonly", "Read-only for the whole session: plan mode that cannot be switched off").option("--auto", "Start in auto mode (the default \u2014 edits and commands run without asking)").option("--mode <mode>", "Starting permission mode: ask | edit | auto | plan").option("--fullscreen", "Draw the whole session on the terminal's alternate screen: the transcript re-wraps on resize and PgUp/PgDn page through it (no terminal scrollback while it is on; /fullscreen toggles it)").option("--bg", "Run the prompt in the background (headless); returns a job id. See: nex jobs | logs | attach | kill").option("--debug", "Write request timing, retries and errors to a debug log file").option("--no-color", "Disable colored output (also honours NO_COLOR)").option("-w, --worktree [name]", "Isolate this session in its own worktree \u2014 a separate directory (and, in a git repo, its own branch) so it can never overwrite files another session (or you) are touching in the main checkout. Omit a name for an auto-generated one; pass an existing name to resume that same worktree.").option("-e, --effort <level>", "Thinking effort \u2014 real levels depend on the model (e.g. DeepSeek: low|high|max, Qwen: low|high); run `nex --model <id>` then `/effort` with no argument to see a model's scale").option("--no-banner", "Skip the ASCII banner (useful in scripts/pipes)").option("--output-format <fmt>", "One-shot output format: text | json | stream-json (implies auto-approve)").option("--audit [path]", "Log every tool call (and refusal) to a JSONL trail (default: .nexrall/audit/<session>.jsonl)").option("--permission-mode <mode>", "Permission mode: ask | edit | auto | plan (also Claude Code names: default | acceptEdits | bypassPermissions). With --output-format, anything that would prompt is DENIED instead of auto-approved").option("--allowedTools, --allowed-tools <tools...>", 'Tools/rules to allow without asking, e.g. "Bash(git *)" Edit (comma or space separated; put the prompt BEFORE this flag)').option("--disallowedTools, --disallowed-tools <tools...>", 'Tools/rules to deny, e.g. "Bash(rm *)" (deny always wins)').option("--append-system-prompt <text>", "Extra instructions appended to the project brief for this run").option("--max-budget-usd <amount>", "Stop a one-shot run once it has spent this many dollars (needs --output-format)").option("--mcp-config <configs...>", 'Load MCP servers from JSON files or inline JSON ({"mcpServers":{\u2026}}) for this run').option("--strict-mcp-config", "With --mcp-config: use ONLY those servers, ignoring ~/.nexrall/mcp.json and the project one").option("--add-dir <dirs...>", "Extra directories the agent may read and edit besides the project folder").option("--input-format <format>", "text (default) | stream-json \u2014 read the prompt as Claude-Code-style NDJSON user messages on stdin").option("--json-schema <schema>", 'JSON Schema (inline or file) the final answer must satisfy; needs --output-format. Result gains "structured_output"; exit 3 if it does not validate').option("--no-session-persistence", "Do not save this run to disk (needs --output-format; it cannot be resumed)").option("--max-turns <n>", "Stop a headless run after N agent rounds (needs --output-format; exit 4 when it hits the limit)").option("--append-system-prompt-file <path>", "Like --append-system-prompt, read from a file").option("--system-prompt <text>", "REPLACE the project brief (nexrall.md + memory + global instructions) with this text for this run").option("--system-prompt-file <path>", "Like --system-prompt, read from a file").option("--verbose", "Print progress detail (tool calls, timings, usage) to stderr while a one-shot run works").option("--include-partial-messages", "Stream model deltas as they arrive (needs --output-format stream-json)").option("--replay-user-messages", "Echo each stdin message back on stdout as it is consumed (needs --input-format stream-json --output-format stream-json)").option("--bare", "Start without discovery: no nexrall.md/memory, skills, plugins, hooks or MCP config files").option("--safe-mode", "Same as --bare (Claude Code's troubleshooting name)").option("--tools <list>", 'Exactly these built-in tools ("Bash,Read,Edit", "default", or "" for none); the rest are removed, not just unapproved').option("--session-id <id>", "Use this id for a NEW conversation (letters, digits, - _), so a script can find it again").option("-n, --name <name>", "Name the conversation; `nex -r <name>` resumes it by that name").option("--fork-session", "With --resume/--continue: branch into a new session instead of continuing the original").option("--fallback-model <name>", "If the main model is overloaded or unreachable, retry the turn once on this model (needs --output-format)").option("--settings <file|json>", "Settings (permissions, hooks\u2026) for this run only: a JSON file or an inline JSON object; merged over the user/project settings").option("--debug-file <path>", "Write the --debug diagnostics log to this file (implies --debug)").argument("[prompt...]", "One-shot prompt \u2014 if omitted, starts interactive mode").action(async (promptParts, options) => {
|
|
173108
173505
|
if (!(0, import_code_core20.isAuthenticated)()) {
|
|
173109
173506
|
console.error("Not logged in. Run: nex auth");
|
|
173110
173507
|
process.exit(1);
|
|
@@ -173136,8 +173533,43 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
|
|
|
173136
173533
|
console.error(sessErr);
|
|
173137
173534
|
process.exit(1);
|
|
173138
173535
|
}
|
|
173536
|
+
let newSessionId;
|
|
173537
|
+
let sessionName;
|
|
173538
|
+
if (options.sessionId !== void 0) {
|
|
173539
|
+
const r2 = parseSessionId(options.sessionId);
|
|
173540
|
+
if (!r2.ok) {
|
|
173541
|
+
console.error(r2.error);
|
|
173542
|
+
process.exit(1);
|
|
173543
|
+
}
|
|
173544
|
+
newSessionId = r2.value;
|
|
173545
|
+
}
|
|
173546
|
+
if (options.name !== void 0) {
|
|
173547
|
+
const r2 = parseSessionName(options.name);
|
|
173548
|
+
if (!r2.ok) {
|
|
173549
|
+
console.error(r2.error);
|
|
173550
|
+
process.exit(1);
|
|
173551
|
+
}
|
|
173552
|
+
sessionName = r2.value;
|
|
173553
|
+
}
|
|
173554
|
+
const identErr = checkSessionIdentityFlags({ sessionId: newSessionId, resume: options.resume, continue: options.continue, fork: options.forkSession });
|
|
173555
|
+
if (identErr) {
|
|
173556
|
+
console.error(identErr);
|
|
173557
|
+
process.exit(1);
|
|
173558
|
+
}
|
|
173559
|
+
if (newSessionId && loadSession(newSessionId) && !options.forkSession) {
|
|
173560
|
+
console.error(`--session-id "${newSessionId}" already exists. Resume it with: nex --resume ${newSessionId}`);
|
|
173561
|
+
process.exit(1);
|
|
173562
|
+
}
|
|
173139
173563
|
if (options.yolo || permBypass)
|
|
173140
173564
|
setAutoApprove("all");
|
|
173565
|
+
if (options.settings !== void 0) {
|
|
173566
|
+
const st = parseSettingsArg(options.settings, process.cwd());
|
|
173567
|
+
if (!st.ok) {
|
|
173568
|
+
console.error(st.error);
|
|
173569
|
+
process.exit(1);
|
|
173570
|
+
}
|
|
173571
|
+
(0, import_code_core21.setSessionSettings)(st.value);
|
|
173572
|
+
}
|
|
173141
173573
|
const allowRules = parseToolList(options.allowedTools);
|
|
173142
173574
|
const denyRules = parseToolList(options.disallowedTools);
|
|
173143
173575
|
(0, import_code_core21.setSessionRules)({ allow: allowRules, deny: denyRules });
|
|
@@ -173152,11 +173584,57 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
|
|
|
173152
173584
|
}
|
|
173153
173585
|
if (options.sessionPersistence === false)
|
|
173154
173586
|
process.env.NEXRALL_EVENTS = "off";
|
|
173155
|
-
|
|
173587
|
+
let maxTurns;
|
|
173588
|
+
if (options.maxTurns !== void 0) {
|
|
173589
|
+
const t2 = parseMaxTurns(options.maxTurns);
|
|
173590
|
+
if (!t2.ok) {
|
|
173591
|
+
console.error(t2.error);
|
|
173592
|
+
process.exit(1);
|
|
173593
|
+
}
|
|
173594
|
+
maxTurns = t2.value;
|
|
173595
|
+
}
|
|
173596
|
+
const headlessErr = checkHeadlessOnly({ outputFormat: options.outputFormat, budget: budgetUsd, noSessionPersistence: options.sessionPersistence === false, maxTurns });
|
|
173156
173597
|
if (headlessErr) {
|
|
173157
173598
|
console.error(headlessErr);
|
|
173158
173599
|
process.exit(1);
|
|
173159
173600
|
}
|
|
173601
|
+
const sysPrompt = resolveSystemPrompt({ text: typeof options.systemPrompt === "string" ? options.systemPrompt : void 0, file: options.systemPromptFile, cwd: process.cwd() });
|
|
173602
|
+
if (!sysPrompt.ok) {
|
|
173603
|
+
console.error(sysPrompt.error);
|
|
173604
|
+
process.exit(1);
|
|
173605
|
+
}
|
|
173606
|
+
let appendSystemPrompt = options.appendSystemPrompt;
|
|
173607
|
+
if (options.appendSystemPromptFile !== void 0) {
|
|
173608
|
+
const f3 = readPromptFile(options.appendSystemPromptFile, process.cwd());
|
|
173609
|
+
if (!f3.ok) {
|
|
173610
|
+
console.error(f3.error);
|
|
173611
|
+
process.exit(1);
|
|
173612
|
+
}
|
|
173613
|
+
appendSystemPrompt = [appendSystemPrompt, f3.value].filter(Boolean).join("\n\n");
|
|
173614
|
+
}
|
|
173615
|
+
let onlyTools;
|
|
173616
|
+
if (options.tools !== void 0) {
|
|
173617
|
+
const t2 = parseToolsFlag(options.tools === true ? "" : options.tools, (0, import_code_core21.knownToolNames)());
|
|
173618
|
+
if (!t2.ok) {
|
|
173619
|
+
console.error(t2.error);
|
|
173620
|
+
process.exit(1);
|
|
173621
|
+
}
|
|
173622
|
+
onlyTools = t2.value;
|
|
173623
|
+
}
|
|
173624
|
+
let fallbackModel;
|
|
173625
|
+
if (options.fallbackModel !== void 0) {
|
|
173626
|
+
if (!options.outputFormat) {
|
|
173627
|
+
console.error("--fallback-model only works with --output-format (a one-shot, non-interactive run).");
|
|
173628
|
+
process.exit(1);
|
|
173629
|
+
}
|
|
173630
|
+
const f3 = parseFallbackModel(options.fallbackModel, model);
|
|
173631
|
+
if (!f3.ok) {
|
|
173632
|
+
console.error(f3.error);
|
|
173633
|
+
process.exit(1);
|
|
173634
|
+
}
|
|
173635
|
+
fallbackModel = f3.value;
|
|
173636
|
+
}
|
|
173637
|
+
const debugFile = options.debugFile !== void 0 ? path26.resolve(String(options.debugFile)) : void 0;
|
|
173160
173638
|
let mcpOverride;
|
|
173161
173639
|
if (options.mcpConfig) {
|
|
173162
173640
|
const m2 = parseMcpConfigs(options.mcpConfig, process.cwd());
|
|
@@ -173169,24 +173647,6 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
|
|
|
173169
173647
|
console.error("--strict-mcp-config needs --mcp-config.");
|
|
173170
173648
|
process.exit(1);
|
|
173171
173649
|
}
|
|
173172
|
-
if (options.bg) {
|
|
173173
|
-
if (!promptParts.length) {
|
|
173174
|
-
console.error('--bg needs a prompt: nex --bg "your task"');
|
|
173175
|
-
process.exit(1);
|
|
173176
|
-
}
|
|
173177
|
-
if (process.env.NEXRALL_BG_JOB) {
|
|
173178
|
-
console.error("--bg cannot be nested inside a background job.");
|
|
173179
|
-
process.exit(1);
|
|
173180
|
-
}
|
|
173181
|
-
const args = stripBgFlag(process.argv.slice(2));
|
|
173182
|
-
if (!options.outputFormat)
|
|
173183
|
-
args.push("--output-format", "stream-json");
|
|
173184
|
-
const job = startJob({ script: process.argv[1], args, cwd: process.cwd(), prompt: promptParts.join(" ") });
|
|
173185
|
-
console.log(`Started background job ${job.id}`);
|
|
173186
|
-
console.log(` nex logs ${job.id} -f follow its output`);
|
|
173187
|
-
console.log(` nex jobs list jobs \xB7 nex kill ${job.id} stop it`);
|
|
173188
|
-
process.exit(0);
|
|
173189
|
-
}
|
|
173190
173650
|
const addDirs = parseAddDirs(options.addDir, process.cwd());
|
|
173191
173651
|
if (!addDirs.ok) {
|
|
173192
173652
|
console.error(addDirs.error);
|
|
@@ -173211,6 +173671,28 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
|
|
|
173211
173671
|
console.error(`Invalid --input-format "${options.inputFormat}". Use: text | stream-json`);
|
|
173212
173672
|
process.exit(1);
|
|
173213
173673
|
}
|
|
173674
|
+
if (options.bg) {
|
|
173675
|
+
if (!promptParts.length) {
|
|
173676
|
+
console.error('--bg needs a prompt: nex --bg "your task"');
|
|
173677
|
+
process.exit(1);
|
|
173678
|
+
}
|
|
173679
|
+
if (inFmt === "stream-json") {
|
|
173680
|
+
console.error("--bg cannot read stream-json from stdin (a background job has no stdin). Pass the prompt as an argument.");
|
|
173681
|
+
process.exit(1);
|
|
173682
|
+
}
|
|
173683
|
+
if (process.env.NEXRALL_BG_JOB) {
|
|
173684
|
+
console.error("--bg cannot be nested inside a background job.");
|
|
173685
|
+
process.exit(1);
|
|
173686
|
+
}
|
|
173687
|
+
const args = stripBgFlag(process.argv.slice(2));
|
|
173688
|
+
if (!options.outputFormat)
|
|
173689
|
+
args.push("--output-format", "stream-json");
|
|
173690
|
+
const job = startJob({ script: process.argv[1], args, cwd: process.cwd(), prompt: promptParts.join(" ") });
|
|
173691
|
+
console.log(`Started background job ${job.id}`);
|
|
173692
|
+
console.log(` nex logs ${job.id} -f follow its output`);
|
|
173693
|
+
console.log(` nex jobs list jobs \xB7 nex kill ${job.id} stop it`);
|
|
173694
|
+
process.exit(0);
|
|
173695
|
+
}
|
|
173214
173696
|
const resume = options.resume === true ? "last" : typeof options.resume === "string" ? options.resume : void 0;
|
|
173215
173697
|
const worktree = options.worktree === true ? true : typeof options.worktree === "string" ? options.worktree : void 0;
|
|
173216
173698
|
let stdinText;
|
|
@@ -173245,6 +173727,16 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
|
|
|
173245
173727
|
}
|
|
173246
173728
|
outputFormat = fmt;
|
|
173247
173729
|
}
|
|
173730
|
+
const partialErr = checkPartialMessages({ includePartial: !!options.includePartialMessages, outputFormat });
|
|
173731
|
+
if (partialErr) {
|
|
173732
|
+
console.error(partialErr);
|
|
173733
|
+
process.exit(1);
|
|
173734
|
+
}
|
|
173735
|
+
const replayErr = checkReplayUserMessages({ replay: !!options.replayUserMessages, inputFormat: options.inputFormat, outputFormat });
|
|
173736
|
+
if (replayErr) {
|
|
173737
|
+
console.error(replayErr);
|
|
173738
|
+
process.exit(1);
|
|
173739
|
+
}
|
|
173248
173740
|
const fsErr = checkFullscreenFlag({
|
|
173249
173741
|
fullscreen: !!options.fullscreen,
|
|
173250
173742
|
isTTY: !!process.stdout.isTTY,
|
|
@@ -173264,7 +173756,7 @@ program2.option("-p, --pro", "Use Claude Opus 5.5 (most capable)").option("-t, -
|
|
|
173264
173756
|
}
|
|
173265
173757
|
effort = lvl;
|
|
173266
173758
|
}
|
|
173267
|
-
await startChatSession({ model, workDir, prompt: prompt2, resume, continueLast: !!options.continue, initialMode: modeRes.mode, lockMode: modeRes.locked, debug: !!options.debug, stdinText, stdinFollowUps, showBanner, outputFormat, effort, audit: options.audit, worktree, fullscreen: !!options.fullscreen, strictPermissions: options.permissionMode !== void 0, budgetUsd, appendSystemPrompt: options.
|
|
173759
|
+
await startChatSession({ model, workDir, prompt: prompt2, resume, continueLast: !!options.continue, initialMode: modeRes.mode, lockMode: modeRes.locked, debug: !!options.debug || debugFile !== void 0, debugFile, fallbackModel, maxTurns, onlyTools, newSessionId, sessionName, forkSession: !!options.forkSession, stdinText, stdinFollowUps, showBanner, outputFormat, effort, audit: options.audit, worktree, fullscreen: !!options.fullscreen, strictPermissions: options.permissionMode !== void 0, budgetUsd, appendSystemPrompt, mcpOverride, strictMcp: !!options.strictMcpConfig, systemPrompt: sysPrompt.value, verbose: !!options.verbose, includePartialMessages: !!options.includePartialMessages, replayUserMessages: !!options.replayUserMessages, inputFormatWasStreamJson: options.inputFormat !== void 0 && String(options.inputFormat).toLowerCase() === "stream-json", bare: !!(options.bare || options.safeMode), noSessionPersistence: options.sessionPersistence === false, addDirs: addDirs.value, jsonSchema });
|
|
173268
173760
|
});
|
|
173269
173761
|
program2.parse();
|
|
173270
173762
|
/*! Bundled license information:
|