reasonix 0.12.6 → 0.12.8

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/README.md CHANGED
@@ -72,6 +72,28 @@ command list.
72
72
 
73
73
  ---
74
74
 
75
+ ## Web dashboard *(new in 0.12)*
76
+
77
+ Type `/dashboard` inside any session and Reasonix prints a localhost
78
+ URL with a one-time token. Open it for a 13-tab control surface that
79
+ mirrors the running TUI — chat (with live streaming), the editor (file
80
+ tree + CodeMirror, syntax highlighting + autocomplete + side-by-side
81
+ diff for pending edits), Usage / Sessions / Plans / Tools /
82
+ Permissions / System / MCP / Skills / Memory / Hooks / Settings.
83
+
84
+ ```
85
+ reasonix code › /dashboard
86
+ ▸ http://127.0.0.1:54219/?token=… (open in browser)
87
+ ```
88
+
89
+ 127.0.0.1 only, ephemeral token expires when the session ends, every
90
+ mutation is CSRF-checked. The TUI keeps working — modals (shell
91
+ confirms, plan reviews, edit gates) mirror to whichever surface you
92
+ look at first. No build step, no Electron, no separate process to
93
+ keep alive.
94
+
95
+ ---
96
+
75
97
  ## Why Reasonix? (vs Cursor / Claude Code / Cline / Aider)
76
98
 
77
99
  Three things you'd come to Reasonix for, that nothing else combines:
@@ -316,8 +338,9 @@ reasonix code › /commit "fix: findByEmail case-insensitive"
316
338
  session file.
317
339
  - `/effort high` — step down from the default `max` agent-class
318
340
  reasoning_effort for cheaper/faster turns on simple tasks.
319
- - `npx reasonix code --preset max` — v4-pro + 3-way self-consistency
320
- branching for gnarly refactors.
341
+ - `npx reasonix code --preset pro` — v4-pro for the whole session,
342
+ no auto-downgrade to flash. Pair with `--branch 3` if you want
343
+ 3-way self-consistency on gnarly refactors.
321
344
  - `npx reasonix code src/` — narrower sandbox (only `src/` is
322
345
  writable).
323
346
  - `npx reasonix code --no-session` — ephemeral; nothing saved.
@@ -348,8 +371,8 @@ in the file. No prompts, no completions, no tool arguments.
348
371
  ### Staying current
349
372
 
350
373
  The panel header shows the running version next to `Reasonix` (e.g.
351
- `Reasonix v0.5.21 · deepseek-v4-pro · harvest · max …`, the trailing
352
- `max` is the reasoning-effort badge — `/effort high` to step down).
374
+ `Reasonix 0.12.6 · v4-flash · AUTO · max …`, the trailing `max` is
375
+ the reasoning-effort badge — `/effort high` to step down).
353
376
  A quiet 24-hour background check against
354
377
  the npm registry surfaces a yellow `update: X.Y.Z` on the right side
355
378
  of the same row when a newer version has been published. No blocking,
@@ -535,7 +558,7 @@ your own MCP servers. Sessions persist per name under
535
558
 
536
559
  ```bash
537
560
  npx reasonix # uses saved config + wizard-selected MCP
538
- npx reasonix --preset smart # reasoner + R1 harvest for this run
561
+ npx reasonix --preset pro # pin v4-pro for the whole run (no auto-downgrade)
539
562
  npx reasonix --session design # named session — resume later with --session design
540
563
  ```
541
564
 
@@ -570,7 +593,7 @@ rendering, retries.
570
593
 
571
594
  | command | what it does |
572
595
  |---|---|
573
- | `/preset <fast\|smart\|max>` | one-tap bundle (model + harvest + branch) |
596
+ | `/preset <auto\|flash\|pro>` | model commitment `auto` = flash with escalation, `flash` = locked flash, `pro` = locked pro |
574
597
  | `/model <id>` | switch DeepSeek model (`deepseek-v4-flash`, `deepseek-v4-pro`, plus `deepseek-chat` / `deepseek-reasoner` compat aliases) |
575
598
  | `/models` | list live models from DeepSeek `/models` endpoint |
576
599
  | `/harvest [on\|off]` | toggle R1 plan-state extraction |
@@ -750,7 +773,7 @@ npx reasonix sessions # list saved sessions
750
773
  Common flags:
751
774
 
752
775
  ```bash
753
- --preset <fast|smart|max> # bundle (model + harvest + branch)
776
+ --preset <auto|flash|pro> # model commitment (auto / locked-flash / locked-pro)
754
777
  --model <id> # explicit model id
755
778
  --harvest / --no-harvest # R1 plan-state extraction
756
779
  --branch <N> # self-consistency budget
package/README.zh-CN.md CHANGED
@@ -69,6 +69,25 @@ Windows Terminal)。任何时候按 `Esc` 中断;`/help` 查看完整命令
69
69
 
70
70
  ---
71
71
 
72
+ ## Web 控制台 *(0.12 新功能)*
73
+
74
+ 会话内输入 `/dashboard`,Reasonix 会打印一个带一次性 token 的本地 URL。
75
+ 浏览器打开后是一个 13 个面板的控制面 —— 与正在运行的 TUI 实时双向同步:
76
+ 聊天(流式输出)、编辑器(文件树 + CodeMirror,语法高亮 + 自动补全 + 待
77
+ 审编辑的左右对比 diff)、Usage / Sessions / Plans / Tools / Permissions /
78
+ System / MCP / Skills / Memory / Hooks / Settings。
79
+
80
+ ```
81
+ reasonix code › /dashboard
82
+ ▸ http://127.0.0.1:54219/?token=… (open in browser)
83
+ ```
84
+
85
+ 仅监听 127.0.0.1,会话结束 token 立即失效,所有改动都走 CSRF 校验。
86
+ TUI 继续可用 —— 弹窗(shell 确认、plan 审阅、edit 闸门)会同步到先看到
87
+ 它的那一边,另一边自动消失。没有打包步骤,没有 Electron,没有额外进程。
88
+
89
+ ---
90
+
72
91
  ## 为什么选 Reasonix?(vs Cursor / Claude Code / Cline / Aider)
73
92
 
74
93
  三件事,别家不会同时都给你:
@@ -284,8 +303,8 @@ reasonix code › /commit "fix: findByEmail case-insensitive"
284
303
  - `/undo` —— 回滚上一批已应用的编辑。
285
304
  - `/new` —— 在同一目录开新会话,但不丢失旧会话文件。
286
305
  - `/effort high` —— 从默认 `max` agent 推理强度降一档,简单任务更省更快。
287
- - `npx reasonix code --preset max` —— v4-pro + 三路 self-consistency 分支,
288
- 适合疑难重构。
306
+ - `npx reasonix code --preset pro` —— 整轮锁定 v4-pro,不再自动降级到
307
+ flash。如果想要 self-consistency 分支,加 `--branch 3` 跑三路投票。
289
308
  - `npx reasonix code src/` —— 更窄的沙箱(只有 `src/` 可写)。
290
309
  - `npx reasonix code --no-session` —— 临时会话,什么都不存。
291
310
 
@@ -314,8 +333,8 @@ completion、没有工具参数。`reasonix stats <transcript>` 仍兼容老用
314
333
  ### 保持最新
315
334
 
316
335
  面板顶栏在 `Reasonix` 旁边显示当前版本(如
317
- `Reasonix v0.5.21 · deepseek-v4-pro · harvest · max …`,最后那个 `max`
318
- 推理强度徽章 —— `/effort high` 可降一档)。后台每 24 小时静默查询一次 npm
336
+ `Reasonix 0.12.6 · v4-flash · AUTO · max …`,最后那个 `max` 是推理强度
337
+ 徽章 —— `/effort high` 可降一档)。后台每 24 小时静默查询一次 npm
319
338
  registry,发现新版会在同一行右侧显示黄色 `update: X.Y.Z`。不阻塞、不烦人,
320
339
  每天最多查一次,离线 / 防火墙下静默失败。
321
340
 
@@ -479,7 +498,7 @@ schema 设计、架构讨论,或者驱动你自己的 MCP 服务器。会话
479
498
 
480
499
  ```bash
481
500
  npx reasonix # 用已保存配置 + 向导选过的 MCP
482
- npx reasonix --preset smart # 这次跑用 reasoner + R1 harvest
501
+ npx reasonix --preset pro # 整轮锁定 v4-pro(不自动降级)
483
502
  npx reasonix --session design # 命名会话 — 之后 --session design 续聊
484
503
  ```
485
504
 
@@ -513,7 +532,7 @@ MCP 工具走和原生工具一样的 Cache-First + 修复 + 上下文安全管
513
532
 
514
533
  | 命令 | 作用 |
515
534
  |---|---|
516
- | `/preset <fast\|smart\|max>` | 一键预设(model + harvest + branch) |
535
+ | `/preset <auto\|flash\|pro>` | 模型策略 —— `auto` = flash 自动升级、`flash` = 锁 flash、`pro` = 锁 pro |
517
536
  | `/model <id>` | 切换 DeepSeek 模型(`deepseek-v4-flash`、`deepseek-v4-pro`,加上 `deepseek-chat` / `deepseek-reasoner` 兼容别名) |
518
537
  | `/models` | 列出 DeepSeek `/models` 端点的可用模型 |
519
538
  | `/harvest [on\|off]` | 切换 R1 plan-state 提取 |
@@ -679,7 +698,7 @@ npx reasonix sessions # 列已保存会话
679
698
  常用 flag:
680
699
 
681
700
  ```bash
682
- --preset <fast|smart|max> # 预设组合(model + harvest + branch
701
+ --preset <auto|flash|pro> # 模型策略(auto / flash / 锁 pro
683
702
  --model <id> # 显式指定模型 ID
684
703
  --harvest / --no-harvest # R1 plan-state 提取
685
704
  --branch <N> # self-consistency 预算
package/dist/cli/index.js CHANGED
@@ -12727,7 +12727,8 @@ function StatsPanel({
12727
12727
  updateAvailable,
12728
12728
  busy,
12729
12729
  proArmed,
12730
- escalated
12730
+ escalated,
12731
+ dashboardUrl
12731
12732
  }) {
12732
12733
  const branchOn = (branchBudget ?? 1) > 1;
12733
12734
  const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model2] ?? DEFAULT_CONTEXT_TOKENS;
@@ -12755,7 +12756,7 @@ function StatsPanel({
12755
12756
  escalated: escalated ?? false,
12756
12757
  animate: false
12757
12758
  }
12758
- ), narrow ? /* @__PURE__ */ React21.createElement(
12759
+ ), dashboardUrl ? /* @__PURE__ */ React21.createElement(DashboardRow, { url: dashboardUrl, narrow }) : null, narrow ? /* @__PURE__ */ React21.createElement(
12759
12760
  StackedMetrics,
12760
12761
  {
12761
12762
  summary,
@@ -12797,6 +12798,14 @@ function Header({
12797
12798
  const showSecondary = animate && !narrow;
12798
12799
  return /* @__PURE__ */ React21.createElement(Box19, { justifyContent: "space-between" }, /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Wordmark, { busy, animate }), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, ` ${VERSION}`), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", bold: true }, model2.replace(/^deepseek-/, "")), modePill ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Pill, { label: modePill.label, bg: modePill.bg })) : null, proPill ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Pill, { label: proPill.label, bg: proPill.bg })) : null, showSecondary && harvestOn ? /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "magenta" }, "harvest")) : null, showSecondary && branchOn ? /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "blue" }, `branch\xD7${branchBudget}`)) : null, showSecondary && reasoningEffort === "max" ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "green", dimColor: true }, "max")) : null, showSecondary && reasoningEffort === "high" ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", dimColor: true }, "high")) : null), /* @__PURE__ */ React21.createElement(Text17, null, updateAvailable ? /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", bold: true }, `\u2191 ${updateAvailable} `) : null, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, narrow ? `t${turns}` : `turn ${turns} \xB7 /help`)));
12799
12800
  }
12801
+ function DashboardRow({ url, narrow }) {
12802
+ return /* @__PURE__ */ React21.createElement(Box19, { flexDirection: "column", marginTop: narrow ? 0 : 1 }, /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25C7 web "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "open the dashboard in a browser (chat \xB7 files \xB7 stats \xB7 settings)")), /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "cyan", bold: true }, hyperlink(url, url))));
12803
+ }
12804
+ function hyperlink(url, label) {
12805
+ const ESC = "\x1B";
12806
+ const ST = `${ESC}\\`;
12807
+ return `${ESC}]8;;${url}${ST}${label}${ESC}]8;;${ST}`;
12808
+ }
12800
12809
  function Pill({ label, bg }) {
12801
12810
  return /* @__PURE__ */ React21.createElement(Text17, { backgroundColor: bg, color: "white", bold: true }, ` ${label} `);
12802
12811
  }
@@ -16347,7 +16356,8 @@ function App({
16347
16356
  mcpSpecs,
16348
16357
  mcpServers,
16349
16358
  progressSink,
16350
- codeMode
16359
+ codeMode,
16360
+ noDashboard
16351
16361
  }) {
16352
16362
  const { exit: exit2 } = useApp();
16353
16363
  const [historical, setHistorical] = useState10([]);
@@ -17308,6 +17318,7 @@ function App({
17308
17318
  }
17309
17319
  });
17310
17320
  dashboardRef.current = handle;
17321
+ setDashboardUrlState(handle.url);
17311
17322
  return handle.url;
17312
17323
  }, [
17313
17324
  loop2,
@@ -17324,6 +17335,7 @@ function App({
17324
17335
  const h = dashboardRef.current;
17325
17336
  if (!h) return;
17326
17337
  dashboardRef.current = null;
17338
+ setDashboardUrlState(null);
17327
17339
  try {
17328
17340
  await h.close();
17329
17341
  } catch {
@@ -17336,6 +17348,13 @@ function App({
17336
17348
  const getDashboardUrl = useCallback4(() => {
17337
17349
  return dashboardRef.current?.url ?? null;
17338
17350
  }, []);
17351
+ const [dashboardUrl, setDashboardUrlState] = useState10(null);
17352
+ useEffect6(() => {
17353
+ if (noDashboard) return;
17354
+ if (dashboardRef.current) return;
17355
+ startDashboard().catch(() => {
17356
+ });
17357
+ }, [noDashboard, startDashboard]);
17339
17358
  useEffect6(() => {
17340
17359
  return () => {
17341
17360
  const h = dashboardRef.current;
@@ -18702,7 +18721,8 @@ Continue executing from the next pending step. Call mark_step_complete after eac
18702
18721
  busy,
18703
18722
  updateAvailable,
18704
18723
  proArmed,
18705
- escalated: turnOnPro
18724
+ escalated: turnOnPro,
18725
+ dashboardUrl
18706
18726
  }
18707
18727
  ), /* @__PURE__ */ React24.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React24.createElement(EventRow, { key: item.id, event: item, projectRoot: currentRootDir })), !historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React24.createElement(WelcomeBanner, { inCodeMode: !!codeMode }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React24.createElement(Box22, { marginY: 1 }, /* @__PURE__ */ React24.createElement(EventRow, { event: streaming, projectRoot: currentRootDir })) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React24.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React24.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React24.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React24.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React24.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React24.createElement(
18708
18728
  PlanRefineInput,
@@ -18978,7 +18998,8 @@ function Root({
18978
18998
  mcpSpecs,
18979
18999
  mcpServers,
18980
19000
  progressSink,
18981
- codeMode: appProps.codeMode
19001
+ codeMode: appProps.codeMode,
19002
+ noDashboard: appProps.noDashboard
18982
19003
  }
18983
19004
  ));
18984
19005
  }
@@ -19784,7 +19805,8 @@ async function codeCommand(opts = {}) {
19784
19805
  seedTools: tools,
19785
19806
  codeMode: { rootDir, jobs: jobs2, reregisterTools: registerRootedTools },
19786
19807
  forceResume: opts.forceResume,
19787
- forceNew: opts.forceNew
19808
+ forceNew: opts.forceNew,
19809
+ noDashboard: opts.noDashboard
19788
19810
  });
19789
19811
  }
19790
19812
 
@@ -21106,6 +21128,9 @@ program.command("code [dir]").description(
21106
21128
  ).option("-m, --model <id>", "Override default model (v4-flash)").option("--no-session", "Disable session persistence for this run").option("-r, --resume", "Skip the session picker \u2014 always continue prior messages").option("-n, --new", "Skip the session picker \u2014 always wipe prior messages and start fresh").option("--transcript <path>", "Write a JSONL transcript to this path").option(
21107
21129
  "--harvest",
21108
21130
  "Opt-in Pillar-2 plan-state extraction. Adds one flash call per turn; off by default (no preset enables it)."
21131
+ ).option(
21132
+ "--no-dashboard",
21133
+ "Suppress the auto-launched embedded web dashboard. Default behavior boots it on TUI mount and shows the URL in the status bar (clickable in OSC-8-aware terminals)."
21109
21134
  ).action(async (dir, opts) => {
21110
21135
  await codeCommand({
21111
21136
  dir,
@@ -21114,7 +21139,8 @@ program.command("code [dir]").description(
21114
21139
  transcript: opts.transcript,
21115
21140
  forceResume: !!opts.resume,
21116
21141
  forceNew: !!opts.new,
21117
- harvest: !!opts.harvest
21142
+ harvest: !!opts.harvest,
21143
+ noDashboard: opts.dashboard === false
21118
21144
  });
21119
21145
  });
21120
21146
  program.command("chat").description("Interactive Ink TUI with live cache/cost panel.").option("-m, --model <id>", "DeepSeek model id (overrides preset)").option("-s, --system <prompt>", "System prompt (pinned in the immutable prefix)", DEFAULT_SYSTEM).option("--transcript <path>", "Write a JSONL transcript to this path").option(
@@ -21138,7 +21164,10 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
21138
21164
  ).option(
21139
21165
  "--mcp-prefix <str>",
21140
21166
  "Global prefix applied to every MCP tool (only honored when no per-spec name is set; avoids collisions with a single anonymous server)"
21141
- ).option("--no-config", "Ignore `~/.reasonix/config.json` \u2014 useful for CI or reproducing issues").action(async (opts) => {
21167
+ ).option("--no-config", "Ignore `~/.reasonix/config.json` \u2014 useful for CI or reproducing issues").option(
21168
+ "--no-dashboard",
21169
+ "Suppress the auto-launched embedded web dashboard. Default behavior boots it on TUI mount and shows the URL in the status bar (clickable in OSC-8-aware terminals)."
21170
+ ).action(async (opts) => {
21142
21171
  const defaults = resolveDefaults({
21143
21172
  model: opts.model,
21144
21173
  harvest: opts.harvest,
@@ -21165,7 +21194,8 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
21165
21194
  mcp: defaults.mcp,
21166
21195
  mcpPrefix: opts.mcpPrefix,
21167
21196
  forceResume: continueOpts.forceResume,
21168
- forceNew: !!opts.new
21197
+ forceNew: !!opts.new,
21198
+ noDashboard: opts.dashboard === false
21169
21199
  });
21170
21200
  });
21171
21201
  program.command("run <task>").description("Run a single task non-interactively, streaming output.").option("-m, --model <id>", "DeepSeek model id (overrides preset)").option("-s, --system <prompt>", "System prompt", DEFAULT_SYSTEM).option("--preset <name>", "Bundle of model + harvest + branch: fast | smart | max").option("--harvest", "Extract typed plan state from R1 reasoning (Pillar 2)").option(