nexrall-code 0.5.116 → 0.5.117

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 CHANGED
@@ -12526,7 +12526,7 @@ var require_agentTypes = __commonJS({
12526
12526
  return t2;
12527
12527
  }
12528
12528
  exports2.VALID_MODELS = [
12529
- "claude-sonnet-5",
12529
+ "claude-sonnet-5-5",
12530
12530
  "claude-opus-5-5",
12531
12531
  "claude-fable-5-1",
12532
12532
  "gpt-5.4",
@@ -106306,8 +106306,8 @@ var require_modelCatalogue = __commonJS({
106306
106306
  }
106307
106307
  exports2.CHEAPEST_MODEL_ALIAS = "cheapest";
106308
106308
  var LEGACY_ALIAS_IDS = {
106309
- turbo: "claude-sonnet-5",
106310
- fast: "claude-sonnet-5",
106309
+ turbo: "claude-sonnet-5-5",
106310
+ fast: "claude-sonnet-5-5",
106311
106311
  pro: "claude-opus-5-5",
106312
106312
  ultra: "claude-fable-5-1"
106313
106313
  };
@@ -107626,7 +107626,7 @@ ${partial}` : "",
107626
107626
  ultra: 1e6,
107627
107627
  fast: 2e5,
107628
107628
  // Anthropic, by real model id.
107629
- "claude-sonnet-5": 1e6,
107629
+ "claude-sonnet-5-5": 1e6,
107630
107630
  "claude-opus-5-5": 1e6,
107631
107631
  "claude-fable-5-1": 1e6,
107632
107632
  "claude-haiku-4-5-20251001": 2e5,
@@ -156779,7 +156779,7 @@ var CLI_VERSION = (() => {
156779
156779
  return "unknown";
156780
156780
  })();
156781
156781
  var MODEL_LABELS = {
156782
- "claude-sonnet-5": "Claude Sonnet 5",
156782
+ "claude-sonnet-5-5": "Claude Sonnet 5.5",
156783
156783
  "claude-opus-5-5": "Claude Opus 5.5",
156784
156784
  "claude-fable-5-1": "Claude Fable 5.1",
156785
156785
  "claude-haiku-4-5-20251001": "Claude Haiku 4.5",
@@ -156794,15 +156794,15 @@ var MODEL_LABELS = {
156794
156794
  "glm-5.3": "GLM 5.3"
156795
156795
  };
156796
156796
  var LEGACY_MODEL_ALIASES = {
156797
- turbo: "claude-sonnet-5",
156798
- auto: "claude-sonnet-5",
156797
+ turbo: "claude-sonnet-5-5",
156798
+ auto: "claude-sonnet-5-5",
156799
156799
  pro: "claude-opus-5-5",
156800
156800
  power: "claude-opus-5-5",
156801
156801
  ultra: "claude-fable-5-1",
156802
156802
  fast: "claude-haiku-4-5-20251001"
156803
156803
  };
156804
156804
  var SELECTABLE_MODELS = [
156805
- "claude-sonnet-5",
156805
+ "claude-sonnet-5-5",
156806
156806
  "claude-opus-5-5",
156807
156807
  "claude-fable-5-1",
156808
156808
  "gpt-5.6-sol",
@@ -156822,7 +156822,7 @@ var SELECTABLE_MODELS = [
156822
156822
  "glm-5.3"
156823
156823
  ];
156824
156824
  var MODEL_COST_MULTIPLIER = {
156825
- "claude-sonnet-5": 1.5,
156825
+ "claude-sonnet-5-5": 1.5,
156826
156826
  "claude-opus-5-5": 3,
156827
156827
  "claude-fable-5-1": 5,
156828
156828
  // GPT-5.6 family (2026-07 launch, Terra/Luna repriced 2026-07-30) — same
@@ -158526,7 +158526,7 @@ ${caption}` : `[Attached: ${rel}]`;
158526
158526
  const content = [{ type: "text", text: label }];
158527
158527
  const needsSidecar = isPdf ? needsPdfSidecar(model) : needsVisionSidecar(model);
158528
158528
  if (needsSidecar) {
158529
- console.log(source_default.dim(` ${resolveModelLabel(modelAlias)} can't read ${isPdf ? "PDFs" : "images"} directly \u2014 describing ${rel} with Claude Sonnet 5 first\u2026`));
158529
+ console.log(source_default.dim(` ${resolveModelLabel(modelAlias)} can't read ${isPdf ? "PDFs" : "images"} directly \u2014 describing ${rel} with Claude Sonnet 5.5 first\u2026`));
158530
158530
  try {
158531
158531
  const { text } = await (0, import_code_core5.describeAttachment)(isPdf ? "pdf" : "image", data, mimeType, rel);
158532
158532
  content.push({ type: "text", text: `<attachment_description>
@@ -159219,12 +159219,12 @@ program2.command("sessions").description("List or delete saved chat sessions").o
159219
159219
  console.log(source_default.dim(" nex sessions --delete <id> to remove one"));
159220
159220
  console.log();
159221
159221
  });
159222
- program2.option("-p, --pro", "Use Claude Opus 5 (most capable)").option("-t, --turbo", "Use Claude Sonnet 5 (fast, default)").option("-u, --ultra", "Use Claude Fable 5 (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("-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)").argument("[prompt...]", "One-shot prompt \u2014 if omitted, starts interactive mode").action(async (promptParts, options) => {
159222
+ 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("-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)").argument("[prompt...]", "One-shot prompt \u2014 if omitted, starts interactive mode").action(async (promptParts, options) => {
159223
159223
  if (!(0, import_code_core8.isAuthenticated)()) {
159224
159224
  console.error("Not logged in. Run: nex auth");
159225
159225
  process.exit(1);
159226
159226
  }
159227
- const model = options.model ? options.model : options.ultra ? "claude-fable-5-1" : options.pro ? "claude-opus-5-5" : options.turbo ? "claude-sonnet-5" : "deepseek-flash";
159227
+ const model = options.model ? options.model : options.ultra ? "claude-fable-5-1" : options.pro ? "claude-opus-5-5" : options.turbo ? "claude-sonnet-5-5" : "deepseek-flash";
159228
159228
  const workDir = options.dir ? path7.resolve(options.dir) : process.cwd();
159229
159229
  if (options.yolo)
159230
159230
  setAutoApprove("all");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.116",
3
+ "version": "0.5.117",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",
@@ -12,11 +12,6 @@
12
12
  "ci"
13
13
  ],
14
14
  "homepage": "https://nexrall.com",
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/nexrall/nexrall-code.git",
18
- "directory": "packages/cli"
19
- },
20
15
  "license": "MIT",
21
16
  "type": "module",
22
17
  "bin": {
@@ -33,13 +28,6 @@
33
28
  "engines": {
34
29
  "node": ">=18"
35
30
  },
36
- "scripts": {
37
- "build": "node build.js",
38
- "dev": "tsx src/index.ts",
39
- "start": "node dist/index.js",
40
- "test": "tsc --noEmit && tsc --noEmit -p test/tsconfig.json && node --import tsx --test test/*.test.ts test/*.test.mts",
41
- "release": "node build.js && node scripts/upload-release.cjs"
42
- },
43
31
  "dependencies": {
44
32
  "chalk": "^5.3.0",
45
33
  "commander": "^12.0.0",
@@ -53,13 +41,20 @@
53
41
  },
54
42
  "devDependencies": {
55
43
  "@aws-sdk/client-s3": "^3.600.0",
56
- "@nexrall/code-core": "workspace:*",
57
44
  "@types/diff": "^5.2.1",
58
45
  "@types/node": "^20.0.0",
59
46
  "@types/prompts": "^2.4.9",
60
47
  "@types/react": "^19.2.18",
61
48
  "esbuild": "^0.20.0",
62
49
  "tsx": "^4.7.0",
63
- "typescript": "^6.0.3"
50
+ "typescript": "^6.0.3",
51
+ "@nexrall/code-core": "1.4.65"
52
+ },
53
+ "scripts": {
54
+ "build": "node build.js",
55
+ "dev": "tsx src/index.ts",
56
+ "start": "node dist/index.js",
57
+ "test": "tsc --noEmit && tsc --noEmit -p test/tsconfig.json && node --import tsx --test test/*.test.ts test/*.test.mts",
58
+ "release": "node build.js && node scripts/upload-release.cjs"
64
59
  }
65
- }
60
+ }
package/dist/audit.js DELETED
@@ -1,102 +0,0 @@
1
- /**
2
- * `--audit [path]` — the CLI's opt-in tool-call trail.
3
- *
4
- * WHY THE CLI HAS THIS AT ALL
5
- *
6
- * The trail was originally skipped here: an interactive terminal already has a
7
- * human watching every permission prompt, so the human IS the oversight layer,
8
- * and shipping a flag nobody asked for is just maintenance surface.
9
- *
10
- * Headless mode is what changes the answer. `--output-format json|stream-json`
11
- * auto-approves every tool call (there is no TTY to ask on) and is meant for CI
12
- * and scripted runs — i.e. an agent acting with nobody watching. That is where a
13
- * trail is worth MOST, not least: without one there is no way to answer "what
14
- * did last night's job actually touch?". The consumer that makes it useful also
15
- * already exists, since stream-json output is machine-readable by design.
16
- *
17
- * Still OPT-IN, including in headless: writing an unrequested file into a user's
18
- * working directory is not a default worth taking, and every other host
19
- * (code-core, the SDK, Desktop) keeps auditing off unless asked. Opt-in
20
- * consistency is itself a property worth having.
21
- *
22
- * State lives at module level rather than being threaded through runTurn()'s
23
- * parameter list, matching setMode()/setAutoApprove() in permissions/. That list
24
- * already carries ten positional parameters across six call sites; an eleventh
25
- * would have to be added correctly six times, and the failure mode of missing
26
- * one is a silently unaudited turn — the exact defect this feature exists to
27
- * prevent, and the one already hit once in @nexrall/agent.
28
- *
29
- * See docs/NEXRALL_AUDIT_TRAIL_LAYER.md in the Nexrall repo.
30
- */
31
- import * as path from 'path';
32
- import { createJsonlAuditSink, loadAuth } from '@nexrall/code-core';
33
- let _state;
34
- /**
35
- * One sink per resolved path.
36
- *
37
- * Cached because the default path is derived from the session id, so `/clear`
38
- * legitimately starts a NEW trail file, while an explicit `--audit <path>`
39
- * keeps appending to one. Re-creating a sink per turn would also re-run the
40
- * mkdir bookkeeping on every call for no benefit.
41
- */
42
- const _sinks = new Map();
43
- /** Default trail location when `--audit` is given with no path. */
44
- export function defaultAuditPath(workDir, sessionId) {
45
- return path.join(workDir, '.nexrall', 'audit', `${sessionId}.jsonl`);
46
- }
47
- /**
48
- * Resolve where this session's trail is written.
49
- *
50
- * An explicit path is resolved against the CWD the user invoked from, not
51
- * `workDir`: a CI job typically wants the trail in its artifacts directory,
52
- * which is usually not the repo being worked on.
53
- */
54
- export function resolveAuditPath(state) {
55
- return state.filePath
56
- ? path.resolve(state.filePath)
57
- : defaultAuditPath(state.workDir, state.getSessionId());
58
- }
59
- /** Enable auditing for this process. Returns the path used for the first session. */
60
- export function enableAudit(opts) {
61
- _state = opts;
62
- return resolveAuditPath(opts);
63
- }
64
- /**
65
- * The audit config for the CURRENT turn, or undefined when `--audit` was not
66
- * passed.
67
- *
68
- * Built per call (cheap: a map lookup plus an object literal) so a session id
69
- * changed by `/clear` or `/resume` is picked up on the very next turn.
70
- */
71
- export function currentAudit() {
72
- if (!_state)
73
- return undefined;
74
- const target = resolveAuditPath(_state);
75
- let sink = _sinks.get(target);
76
- if (!sink) {
77
- sink = createJsonlAuditSink(target);
78
- _sinks.set(target, sink);
79
- }
80
- const cfg = {
81
- sink,
82
- // Pinned per turn to the CLI's live session id, so a whole conversation —
83
- // every turn, and every sub-agent it delegates to — shares one session in
84
- // the trail. code-core mints an id per runAgentLoop() call and the REPL
85
- // calls it once PER TURN, so leaving this unset would make each turn look
86
- // like a separate session and break the link between a later write and the
87
- // request that caused it. Same trap as @nexrall/agent's and Desktop's.
88
- sessionId: _state.getSessionId(),
89
- };
90
- // The human half of dual attribution. Absent when the account has no email on
91
- // record — never substituted with a placeholder, because a fabricated
92
- // attribution in a compliance record is worse than a visibly missing one.
93
- const email = loadAuth()?.email;
94
- if (email)
95
- cfg.userId = email;
96
- return cfg;
97
- }
98
- /** Test seam — resets module state between cases. */
99
- export function resetAudit() {
100
- _state = undefined;
101
- _sinks.clear();
102
- }
@@ -1,134 +0,0 @@
1
- import * as readline from 'readline';
2
- import chalk from 'chalk';
3
- import { login, saveAuth, clearAuth, isAuthenticated, getBalance, revokeRefreshToken } from '@nexrall/code-core';
4
- // ─── Hidden Password Prompt ───────────────────────────────────────────────────
5
- function prompt(question, hidden = false) {
6
- return new Promise((resolve) => {
7
- const rl = readline.createInterface({
8
- input: process.stdin,
9
- output: process.stdout,
10
- terminal: true,
11
- });
12
- if (hidden) {
13
- // Temporarily suppress echoing for password input
14
- process.stdout.write(question);
15
- let value = '';
16
- const { stdin } = process;
17
- const wasRaw = stdin.isRaw;
18
- stdin.setRawMode(true);
19
- stdin.resume();
20
- stdin.setEncoding('utf8');
21
- const onData = (char) => {
22
- if (char === '\n' || char === '\r' || char === '') {
23
- // Enter or Ctrl+C
24
- stdin.setRawMode(wasRaw ?? false);
25
- stdin.pause();
26
- stdin.removeListener('data', onData);
27
- rl.close();
28
- process.stdout.write('\n');
29
- if (char === '') {
30
- process.exit(0);
31
- }
32
- resolve(value);
33
- }
34
- else if (char === '' || char === '\b') {
35
- // Backspace
36
- if (value.length > 0) {
37
- value = value.slice(0, -1);
38
- }
39
- }
40
- else {
41
- value += char;
42
- }
43
- };
44
- stdin.on('data', onData);
45
- }
46
- else {
47
- rl.question(question, (answer) => {
48
- rl.close();
49
- resolve(answer.trim());
50
- });
51
- }
52
- });
53
- }
54
- // ─── Auth Command ─────────────────────────────────────────────────────────────
55
- export async function authCommand() {
56
- console.log();
57
- console.log(chalk.bold.blue(' Nexrall Code — Login'));
58
- console.log(chalk.dim(' ─────────────────────'));
59
- console.log();
60
- if (isAuthenticated()) {
61
- const overwrite = await prompt(chalk.yellow(' Already logged in. Login again? ') + chalk.dim('[y/n] > '));
62
- if (overwrite !== 'y' && overwrite !== 'yes') {
63
- console.log(chalk.dim(' Cancelled.'));
64
- return;
65
- }
66
- console.log();
67
- }
68
- const email = await prompt(chalk.bold(' Email ') + chalk.dim('> '));
69
- const password = await prompt(chalk.bold(' Password ') + chalk.dim('> '), true);
70
- console.log();
71
- const spinner = startSpinner('Logging in…');
72
- try {
73
- const authConfig = await login(email, password);
74
- saveAuth(authConfig);
75
- stopSpinner(spinner);
76
- console.log(chalk.green(' ✓ Logged in as ') + chalk.bold(authConfig.email ?? email));
77
- console.log();
78
- // Show balance
79
- try {
80
- const balance = await getBalance();
81
- console.log(chalk.dim(' Wallet balance: ') + chalk.cyan(`$${balance.toFixed(4)}`));
82
- }
83
- catch {
84
- // Non-fatal — balance fetch can fail
85
- }
86
- console.log();
87
- console.log(chalk.dim(' Run ') + chalk.bold('nex') + chalk.dim(' to start coding.'));
88
- console.log();
89
- }
90
- catch (err) {
91
- stopSpinner(spinner);
92
- console.log();
93
- console.log(chalk.red(' ✗ Login failed: ') + String(err.message));
94
- console.log();
95
- process.exit(1);
96
- }
97
- }
98
- // ─── Logout Command ───────────────────────────────────────────────────────────
99
- export async function logoutCommand() {
100
- console.log();
101
- if (!isAuthenticated()) {
102
- console.log(chalk.dim(' Not logged in.'));
103
- console.log();
104
- return;
105
- }
106
- const confirm = await prompt(chalk.yellow(' Log out? ') + chalk.dim('[y/n] > '));
107
- if (confirm !== 'y' && confirm !== 'yes') {
108
- console.log(chalk.dim(' Cancelled.'));
109
- console.log();
110
- return;
111
- }
112
- // Revoke server-side BEFORE clearing the local file — the refresh token has to be
113
- // read from it. Without this, "logging out" only deleted the local copy while the
114
- // 60-day refresh token stayed valid and could keep minting access tokens for
115
- // anyone who recovered it (a synced dotfile, a backup, a shared machine).
116
- await revokeRefreshToken();
117
- clearAuth();
118
- console.log(chalk.green(' ✓ Logged out.'));
119
- console.log();
120
- }
121
- function startSpinner(text) {
122
- const frames = ['◐', '◓', '◑', '◒'];
123
- let i = 0;
124
- process.stdout.write(' ');
125
- const interval = setInterval(() => {
126
- process.stdout.write(`\r ${chalk.cyan(frames[i % frames.length])} ${chalk.dim(text)}`);
127
- i++;
128
- }, 120);
129
- return { interval };
130
- }
131
- function stopSpinner(handle) {
132
- clearInterval(handle.interval);
133
- process.stdout.write('\r\x1b[K'); // Clear the spinner line
134
- }