reasonix 0.36.2 → 0.37.0
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 +47 -75
- package/README.zh-CN.md +47 -32
- package/dist/cli/{chat-QSM6JKUA.js → chat-7257YAPG.js} +11 -11
- package/dist/cli/{chunk-DFP4YSVM.js → chunk-6CXT5JRM.js} +17 -2
- package/dist/cli/{chunk-DFP4YSVM.js.map → chunk-6CXT5JRM.js.map} +1 -1
- package/dist/cli/{chunk-G3XNWSFN.js → chunk-6NMWJSES.js} +2 -2
- package/dist/cli/{chunk-MLXUGPJE.js → chunk-GKZJXYMY.js} +79 -1
- package/dist/cli/chunk-GKZJXYMY.js.map +1 -0
- package/dist/cli/{chunk-IPCPEZWQ.js → chunk-JGZKTAOH.js} +2 -2
- package/dist/cli/{chunk-BJ376EN3.js → chunk-JULZ7JTO.js} +3 -3
- package/dist/cli/{chunk-NHV5YGTB.js → chunk-MSKUP6PD.js} +1372 -1012
- package/dist/cli/chunk-MSKUP6PD.js.map +1 -0
- package/dist/cli/{chunk-RNSZYYGB.js → chunk-SEFXUF24.js} +13 -13
- package/dist/cli/chunk-SEFXUF24.js.map +1 -0
- package/dist/cli/{chunk-C5543CRX.js → chunk-VF57YX2M.js} +2 -2
- package/dist/cli/{chunk-K6W64QVE.js → chunk-XOIDSPMQ.js} +27 -7
- package/dist/cli/chunk-XOIDSPMQ.js.map +1 -0
- package/dist/cli/{chunk-4D6TT2IB.js → chunk-YER7WCHF.js} +13 -6
- package/dist/cli/chunk-YER7WCHF.js.map +1 -0
- package/dist/cli/{code-6C5A2CY3.js → code-64EG5IU2.js} +14 -13
- package/dist/cli/code-64EG5IU2.js.map +1 -0
- package/dist/cli/{doctor-DKD34EFD.js → doctor-BW5HSQDW.js} +5 -5
- package/dist/cli/{events-P27CX7LN.js → events-SQXPVV7B.js} +3 -3
- package/dist/cli/index.js +27 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompt-KGIUONO3.js +13 -0
- package/dist/cli/{prune-sessions-ERL6B4G5.js → prune-sessions-FCFOYCBP.js} +2 -2
- package/dist/cli/{run-AG4Y45X7.js → run-RWCOA32G.js} +7 -7
- package/dist/cli/{server-GNHR5K3N.js → server-6ZW4TQUP.js} +94 -48
- package/dist/cli/{server-GNHR5K3N.js.map → server-6ZW4TQUP.js.map} +1 -1
- package/dist/cli/{sessions-MHRF3GU4.js → sessions-5ISNWFMU.js} +7 -7
- package/dist/cli/{setup-IIAJXHP4.js → setup-HJG23NKJ.js} +2 -2
- package/dist/cli/{version-7AL4JZ63.js → version-BXAN7Q4V.js} +7 -7
- package/dist/index.d.ts +6 -2
- package/dist/index.js +149 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-4D6TT2IB.js.map +0 -1
- package/dist/cli/chunk-K6W64QVE.js.map +0 -1
- package/dist/cli/chunk-MLXUGPJE.js.map +0 -1
- package/dist/cli/chunk-NHV5YGTB.js.map +0 -1
- package/dist/cli/chunk-RNSZYYGB.js.map +0 -1
- package/dist/cli/code-6C5A2CY3.js.map +0 -1
- package/dist/cli/prompt-QSEB7HNQ.js +0 -11
- /package/dist/cli/{chat-QSM6JKUA.js.map → chat-7257YAPG.js.map} +0 -0
- /package/dist/cli/{chunk-G3XNWSFN.js.map → chunk-6NMWJSES.js.map} +0 -0
- /package/dist/cli/{chunk-IPCPEZWQ.js.map → chunk-JGZKTAOH.js.map} +0 -0
- /package/dist/cli/{chunk-BJ376EN3.js.map → chunk-JULZ7JTO.js.map} +0 -0
- /package/dist/cli/{chunk-C5543CRX.js.map → chunk-VF57YX2M.js.map} +0 -0
- /package/dist/cli/{doctor-DKD34EFD.js.map → doctor-BW5HSQDW.js.map} +0 -0
- /package/dist/cli/{events-P27CX7LN.js.map → events-SQXPVV7B.js.map} +0 -0
- /package/dist/cli/{prompt-QSEB7HNQ.js.map → prompt-KGIUONO3.js.map} +0 -0
- /package/dist/cli/{prune-sessions-ERL6B4G5.js.map → prune-sessions-FCFOYCBP.js.map} +0 -0
- /package/dist/cli/{run-AG4Y45X7.js.map → run-RWCOA32G.js.map} +0 -0
- /package/dist/cli/{sessions-MHRF3GU4.js.map → sessions-5ISNWFMU.js.map} +0 -0
- /package/dist/cli/{setup-IIAJXHP4.js.map → setup-HJG23NKJ.js.map} +0 -0
- /package/dist/cli/{version-7AL4JZ63.js.map → version-BXAN7Q4V.js.map} +0 -0
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
·
|
|
10
10
|
<a href="https://esengine.github.io/DeepSeek-Reasonix/">Website</a>
|
|
11
11
|
·
|
|
12
|
+
<a href="https://esengine.github.io/DeepSeek-Reasonix/configuration.html">Guide</a>
|
|
13
|
+
·
|
|
12
14
|
<a href="./docs/ARCHITECTURE.md">Architecture</a>
|
|
13
15
|
·
|
|
14
16
|
<a href="./benchmarks/">Benchmarks</a>
|
|
@@ -46,49 +48,6 @@
|
|
|
46
48
|
|
|
47
49
|
<br/>
|
|
48
50
|
|
|
49
|
-
## Web search
|
|
50
|
-
|
|
51
|
-
Reasonix includes `web_search` and `web_fetch` tools. By default it uses **Mojeek** (no setup required). You can switch to a **self-hosted SearXNG** instance — a metasearch engine that aggregates whatever upstream engines your instance is configured for.
|
|
52
|
-
|
|
53
|
-
### Switching engines (persists to disk)
|
|
54
|
-
|
|
55
|
-
The `/search-engine` slash command (alias `/se`) writes your choice to `~/.reasonix/config.json` immediately — it survives restarts:
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
/search-engine mojeek # default, no external deps
|
|
59
|
-
/search-engine searxng # SearXNG at http://localhost:8080
|
|
60
|
-
/search-engine searxng http://192.168.1.100:8888 # custom endpoint
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Equivalent `~/.reasonix/config.json`:
|
|
64
|
-
|
|
65
|
-
```json
|
|
66
|
-
{
|
|
67
|
-
"webSearchEngine": "searxng",
|
|
68
|
-
"webSearchEndpoint": "http://localhost:8080"
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The tool picks up the change on the next call — no restart needed.
|
|
73
|
-
|
|
74
|
-
### Starting SearXNG
|
|
75
|
-
|
|
76
|
-
```sh
|
|
77
|
-
podman run -d --replace --name searxng -p 8080:8080 docker.io/searxng/searxng
|
|
78
|
-
# or: docker run -d -p 8080:8080 searxng/searxng
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Verify it's running:
|
|
82
|
-
|
|
83
|
-
```sh
|
|
84
|
-
curl http://localhost:8080/search?q=test
|
|
85
|
-
# → HTML search results page
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
> **Note:** The endpoint must include the protocol (`http://`). `localhost:8080` alone will fail — the tool will show a clear error telling you to install SearXNG if the server is unreachable.
|
|
89
|
-
|
|
90
|
-
<br/>
|
|
91
|
-
|
|
92
51
|
## Install
|
|
93
52
|
|
|
94
53
|
```bash
|
|
@@ -96,55 +55,68 @@ cd my-project
|
|
|
96
55
|
npx reasonix code # paste a DeepSeek API key on first run; persists after
|
|
97
56
|
```
|
|
98
57
|
|
|
99
|
-
Requires Node ≥ 22.
|
|
58
|
+
Requires Node ≥ 22. Works on macOS · Linux · Windows (PowerShell · Git Bash · Windows Terminal). Grab a [DeepSeek API key →](https://platform.deepseek.com/api_keys) · `reasonix code --help` for flags.
|
|
100
59
|
|
|
101
|
-
`npx` is the recommended path — no global install, always
|
|
60
|
+
`npx` is the recommended path — no global install, always latest. If you use Reasonix daily and want it on `PATH`, run `reasonix update` once.
|
|
102
61
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
| Command | When to use |
|
|
62
|
+
| Command | When |
|
|
106
63
|
|---|---|
|
|
107
|
-
| `reasonix code [dir]` |
|
|
108
|
-
| `reasonix chat` | Plain chat — no filesystem
|
|
109
|
-
| `reasonix run "task"` | One-shot, streams
|
|
110
|
-
| `reasonix doctor` |
|
|
64
|
+
| `reasonix code [dir]` | The coding agent. **Start here.** |
|
|
65
|
+
| `reasonix chat` | Plain chat — no filesystem or shell tools. |
|
|
66
|
+
| `reasonix run "task"` | One-shot, streams to stdout. Good for pipes. |
|
|
67
|
+
| `reasonix doctor` | Health check: Node, API key, MCP wiring. |
|
|
111
68
|
| `reasonix update` | Upgrade Reasonix itself. |
|
|
112
69
|
|
|
113
|
-
Other subcommands (`replay` · `diff` · `events` · `stats` · `index` · `mcp` · `prune-sessions`) are
|
|
70
|
+
Other subcommands (`replay` · `diff` · `events` · `stats` · `index` · `mcp` · `prune-sessions`) are in `reasonix --help` and the [CLI reference](https://esengine.github.io/DeepSeek-Reasonix/#cli).
|
|
114
71
|
|
|
115
|
-
|
|
72
|
+
<details>
|
|
73
|
+
<summary><strong>Working in another folder · chat vs. code · author a skill</strong></summary>
|
|
116
74
|
|
|
117
|
-
|
|
75
|
+
**Working in a different folder.** Reasonix scopes filesystem tools to the launch directory; pass `--dir` to retarget. Mid-session switching isn't supported by design (memory paths would tangle with stale roots) — quit and relaunch.
|
|
118
76
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
| SEARCH/REPLACE edit blocks → `/apply` review | ✓ | — |
|
|
123
|
-
| Shell tool (with confirm gate, `/mode yolo` to skip) | ✓ | — |
|
|
124
|
-
| Plan mode · `submit_plan` · `/todo` · `/skill new` · `/mcp add` scaffolding | ✓ | — |
|
|
125
|
-
| Memory tools (`remember` / `recall_memory`) | project + global | global only |
|
|
126
|
-
| Web search · `ask_choice` · MCP servers from config | ✓ | ✓ |
|
|
127
|
-
| Coding-focused system prompt (SEARCH/REPLACE, repo etiquette) | ✓ | generic |
|
|
128
|
-
| Session scope | per-directory (`code-<basename>`) | shared default |
|
|
77
|
+
```bash
|
|
78
|
+
npx reasonix code --dir /path/to/project
|
|
79
|
+
```
|
|
129
80
|
|
|
130
|
-
`chat`
|
|
81
|
+
**Picking `chat` vs `code`.** `code` is the default and the only mode with filesystem / shell tools and SEARCH/REPLACE review. `chat` is the lighter, tools-off shell — reach for it when you want a thinking partner with MCP attached but no disk access.
|
|
131
82
|
|
|
132
|
-
|
|
83
|
+
| What you get | `code` | `chat` |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| Filesystem tools + `edit_file` | ✓ | — |
|
|
86
|
+
| SEARCH/REPLACE → `/apply` review | ✓ | — |
|
|
87
|
+
| Shell tool (gated) | ✓ | — |
|
|
88
|
+
| Plan mode · `/todo` · `/skill new` · `/mcp add` | ✓ | — |
|
|
89
|
+
| Memory (`remember` / `recall_memory`) | project + global | global only |
|
|
90
|
+
| MCP servers from config · web search · `ask_choice` | ✓ | ✓ |
|
|
91
|
+
| Coding system prompt | ✓ | generic |
|
|
92
|
+
| Session scope | per-directory | shared default |
|
|
93
|
+
|
|
94
|
+
**Author your first skill.** No remote registry — write them directly. Edit the file (`description:` frontmatter + body), then `/skill list`. Add `runAs: subagent` to spawn an isolated subagent loop instead of inlining the body.
|
|
133
95
|
|
|
134
96
|
```bash
|
|
135
|
-
|
|
97
|
+
/skill new my-skill # <project>/.reasonix/skills/my-skill.md
|
|
98
|
+
/skill new my-skill --global # ~/.reasonix/skills for cross-project use
|
|
136
99
|
```
|
|
137
100
|
|
|
138
|
-
|
|
101
|
+
</details>
|
|
139
102
|
|
|
140
|
-
|
|
103
|
+
<br/>
|
|
141
104
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
/
|
|
145
|
-
```
|
|
105
|
+
## Configuration
|
|
106
|
+
|
|
107
|
+
One JSON file at `~/.reasonix/config.json` plus per-project overrides under `<project>/.reasonix/`. The full bilingual reference — every key, every slash command, the on-disk shape of skills/memory/hooks — lives at:
|
|
146
108
|
|
|
147
|
-
|
|
109
|
+
> 📘 **[Configuration Guide](https://esengine.github.io/DeepSeek-Reasonix/configuration.html)** · [中文](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh)
|
|
110
|
+
|
|
111
|
+
| Topic | Quick read |
|
|
112
|
+
|---|---|
|
|
113
|
+
| [MCP servers](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#mcp) | stdio · SSE · Streamable HTTP. One spec format works for both `config.json` and `--mcp`. |
|
|
114
|
+
| [Skills](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#skills) | Markdown playbooks the model can invoke. `inline` or `subagent` mode. |
|
|
115
|
+
| [Memory](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#memory) | User-private knowledge pinned into the prefix. `user` / `feedback` / `project` / `reference` types. |
|
|
116
|
+
| [Hooks](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#hooks) | Shell commands on lifecycle events. `PreToolUse` (gating) · `PostToolUse` · `UserPromptSubmit` · `Stop`. |
|
|
117
|
+
| [Permissions](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#permissions) | Per-workspace shell allowlist. Exact-prefix match. |
|
|
118
|
+
| [Web search](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#search) | Mojeek by default; switch to self-hosted SearXNG with `/search-engine`. |
|
|
119
|
+
| [Semantic index](https://esengine.github.io/DeepSeek-Reasonix/configuration.html#index) | `reasonix index` — local Ollama or any OpenAI-compatible embedding endpoint. |
|
|
148
120
|
|
|
149
121
|
<br/>
|
|
150
122
|
|
package/README.zh-CN.md
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
·
|
|
10
10
|
<a href="https://esengine.github.io/DeepSeek-Reasonix/">官方网站</a>
|
|
11
11
|
·
|
|
12
|
+
<a href="https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh">配置指南</a>
|
|
13
|
+
·
|
|
12
14
|
<a href="./docs/ARCHITECTURE.md">架构文档</a>
|
|
13
15
|
·
|
|
14
16
|
<a href="./benchmarks/">基准测试</a>
|
|
@@ -50,55 +52,68 @@ cd my-project
|
|
|
50
52
|
npx reasonix code # 首次运行粘贴 DeepSeek API Key,之后会记住
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
要求 Node ≥ 22
|
|
54
|
-
|
|
55
|
-
`npx` 是推荐路径 —— 不用全局安装,每次都拿到最新版本。如果你天天用、想把 `reasonix` 装到 `PATH` 上,跑一次 `reasonix update` 就行,它会替你跑 `npm install -g`。
|
|
55
|
+
要求 Node ≥ 22。在 macOS · Linux · Windows(PowerShell · Git Bash · Windows Terminal)都跑得顺。[去拿 DeepSeek API Key →](https://platform.deepseek.com/api_keys) · 完整 flag 看 `reasonix code --help`。
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
`npx` 是推荐路径 —— 不用全局安装,每次都拿最新版。如果你天天用、想把 `reasonix` 装到 `PATH`,跑一次 `reasonix update`。
|
|
58
58
|
|
|
59
|
-
| 命令 |
|
|
59
|
+
| 命令 | 何时用 |
|
|
60
60
|
|---|---|
|
|
61
|
-
| `reasonix code [dir]` |
|
|
62
|
-
| `reasonix chat` | 纯聊天 ——
|
|
63
|
-
| `reasonix run "task"` |
|
|
64
|
-
| `reasonix doctor` |
|
|
61
|
+
| `reasonix code [dir]` | 编码 agent。**先用这个。** |
|
|
62
|
+
| `reasonix chat` | 纯聊天 —— 不挂文件系统 / shell 工具。 |
|
|
63
|
+
| `reasonix run "task"` | 一次性,结果流到 stdout。适合 shell 管道。 |
|
|
64
|
+
| `reasonix doctor` | 体检:Node 版本、API Key、MCP 接线。 |
|
|
65
65
|
| `reasonix update` | 升级 Reasonix 本身。 |
|
|
66
66
|
|
|
67
|
-
其他子命令(`replay` · `diff` · `events` · `stats` · `index` · `mcp` · `prune-sessions
|
|
67
|
+
其他子命令(`replay` · `diff` · `events` · `stats` · `index` · `mcp` · `prune-sessions`)在 `reasonix --help` 和 [CLI 参考](https://esengine.github.io/DeepSeek-Reasonix/#cli)。
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
<details>
|
|
70
|
+
<summary><strong>切换工作区 · chat vs. code · 写第一个 Skill</strong></summary>
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
**切换工作区。** Reasonix 把文件系统工具作用域绑定在启动目录,传 `--dir` 可以指别处。中途切换是有意不支持的(消息日志和 memory 路径会和旧根目录混在一起)—— 退出再启动。
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| Plan 模式 · `submit_plan` · `/todo` · `/skill new` · `/mcp add` 脚手架 | ✓ | — |
|
|
79
|
-
| 记忆工具(`remember` / `recall_memory`) | 项目 + 全局 | 仅全局 |
|
|
80
|
-
| Web 搜索 · `ask_choice` · 从配置加载的 MCP 服务 | ✓ | ✓ |
|
|
81
|
-
| 编码导向系统提示词(SEARCH/REPLACE、仓库礼仪) | ✓ | 通用 |
|
|
82
|
-
| Session 作用域 | 按目录(`code-<basename>`) | 共享默认 |
|
|
74
|
+
```bash
|
|
75
|
+
npx reasonix code --dir /path/to/project
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**`chat` 还是 `code`?** `code` 是默认入口、唯一带文件系统 / shell 工具和 SEARCH/REPLACE 审阅的模式。`chat` 是更轻量的纯对话壳——想要一个挂着 MCP 但没有磁盘权限的“思路助手”时用它。
|
|
83
79
|
|
|
84
|
-
`
|
|
80
|
+
| 你拿到什么 | `code` | `chat` |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| 文件系统工具 + `edit_file` | ✓ | — |
|
|
83
|
+
| SEARCH/REPLACE → `/apply` 审阅 | ✓ | — |
|
|
84
|
+
| Shell 工具(带 gate) | ✓ | — |
|
|
85
|
+
| Plan 模式 · `/todo` · `/skill new` · `/mcp add` | ✓ | — |
|
|
86
|
+
| Memory(`remember` / `recall_memory`) | 项目 + 全局 | 仅全局 |
|
|
87
|
+
| 配置里的 MCP · web 搜索 · `ask_choice` | ✓ | ✓ |
|
|
88
|
+
| 编码导向系统提示词 | ✓ | 通用 |
|
|
89
|
+
| Session 作用域 | 按目录 | 共享默认 |
|
|
85
90
|
|
|
86
|
-
|
|
91
|
+
**写第一个 Skill。** 暂无在线市场——自己写。编辑文件(`description:` frontmatter + 正文),然后 `/skill list` 就能看到。frontmatter 加 `runAs: subagent` 会以隔离 subagent 跑,而不是把正文内联进父 prompt。
|
|
87
92
|
|
|
88
93
|
```bash
|
|
89
|
-
|
|
94
|
+
/skill new my-skill # <project>/.reasonix/skills/my-skill.md
|
|
95
|
+
/skill new my-skill --global # ~/.reasonix/skills,跨项目共用
|
|
90
96
|
```
|
|
91
97
|
|
|
92
|
-
|
|
98
|
+
</details>
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
<br/>
|
|
95
101
|
|
|
96
|
-
|
|
97
|
-
/skill new my-skill # 在 <project>/.reasonix/skills/my-skill.md 生成模板
|
|
98
|
-
/skill new my-skill --global # 或者放到 ~/.reasonix/skills,跨项目共用
|
|
99
|
-
```
|
|
102
|
+
## 配置
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
一个全局 JSON 文件 `~/.reasonix/config.json`,加上项目级 `<project>/.reasonix/` 下的覆盖。完整的双语参考 —— 每一个 key、每一条斜杠命令、skills / memory / hooks 在磁盘上的形状 —— 都在这里:
|
|
105
|
+
|
|
106
|
+
> 📘 **[配置指南](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh)** · [English](https://esengine.github.io/DeepSeek-Reasonix/configuration.html)
|
|
107
|
+
|
|
108
|
+
| 主题 | 速读 |
|
|
109
|
+
|---|---|
|
|
110
|
+
| [MCP 服务器](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#mcp) | stdio · SSE · Streamable HTTP。`config.json` 和 `--mcp` 共用同一种 spec 格式。 |
|
|
111
|
+
| [Skills](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#skills) | 模型可以调用的 markdown 剧本。`inline` 或 `subagent` 两种模式。 |
|
|
112
|
+
| [Memory](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#memory) | 用户私有的知识,钉进前缀。`user` / `feedback` / `project` / `reference` 四类。 |
|
|
113
|
+
| [Hooks](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#hooks) | 生命周期事件触发的 shell 命令。`PreToolUse`(拦截)· `PostToolUse` · `UserPromptSubmit` · `Stop`。 |
|
|
114
|
+
| [权限](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#permissions) | 按工作区的 shell 白名单,精确前缀匹配。 |
|
|
115
|
+
| [Web 搜索](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#search) | 默认 Mojeek;用 `/search-engine` 可切到自托管的 SearXNG。 |
|
|
116
|
+
| [语义索引](https://esengine.github.io/DeepSeek-Reasonix/configuration.html?lang=zh#index) | `reasonix index` —— 本地 Ollama,或任何 OpenAI 兼容的 embedding 接口。 |
|
|
102
117
|
|
|
103
118
|
<br/>
|
|
104
119
|
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
chatCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MSKUP6PD.js";
|
|
5
5
|
import "./chunk-BQNUJJN7.js";
|
|
6
6
|
import "./chunk-RFX7TYVV.js";
|
|
7
7
|
import "./chunk-MRLXEMZ7.js";
|
|
8
8
|
import "./chunk-CPOV2O73.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-SEFXUF24.js";
|
|
10
10
|
import "./chunk-UNMYFZPZ.js";
|
|
11
11
|
import "./chunk-XJLZ4HKU.js";
|
|
12
12
|
import "./chunk-XHQIK7B6.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-YER7WCHF.js";
|
|
14
14
|
import "./chunk-T52GAWPP.js";
|
|
15
15
|
import "./chunk-ZJR4QLXB.js";
|
|
16
16
|
import "./chunk-MHDNZXJJ.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-JULZ7JTO.js";
|
|
18
18
|
import "./chunk-DAEAAVDF.js";
|
|
19
19
|
import "./chunk-KMWKGPFZ.js";
|
|
20
20
|
import "./chunk-3Q3C4W66.js";
|
|
21
21
|
import "./chunk-4DCHFFEY.js";
|
|
22
22
|
import "./chunk-WJ3YX4PZ.js";
|
|
23
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-VF57YX2M.js";
|
|
24
24
|
import "./chunk-SOZE7V7V.js";
|
|
25
|
-
import "./chunk-
|
|
25
|
+
import "./chunk-6NMWJSES.js";
|
|
26
26
|
import "./chunk-S4GF3HPO.js";
|
|
27
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-XOIDSPMQ.js";
|
|
28
28
|
import "./chunk-FM57FNPJ.js";
|
|
29
29
|
import "./chunk-XQIFIB3U.js";
|
|
30
|
-
import "./chunk-
|
|
30
|
+
import "./chunk-JGZKTAOH.js";
|
|
31
31
|
import "./chunk-5X7LZJDE.js";
|
|
32
|
-
import "./chunk-
|
|
33
|
-
import "./chunk-
|
|
32
|
+
import "./chunk-6CXT5JRM.js";
|
|
33
|
+
import "./chunk-GKZJXYMY.js";
|
|
34
34
|
import "./chunk-BHLHOS5Y.js";
|
|
35
35
|
import "./chunk-WUI3P4RA.js";
|
|
36
36
|
import "./chunk-ZTLZO42A.js";
|
|
@@ -39,4 +39,4 @@ import "./chunk-CRPQUBP6.js";
|
|
|
39
39
|
export {
|
|
40
40
|
chatCommand
|
|
41
41
|
};
|
|
42
|
-
//# sourceMappingURL=chat-
|
|
42
|
+
//# sourceMappingURL=chat-7257YAPG.js.map
|
|
@@ -218,6 +218,20 @@ function rewriteSession(name, messages) {
|
|
|
218
218
|
} catch {
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
+
function archiveSession(name) {
|
|
222
|
+
const path = sessionPath(name);
|
|
223
|
+
if (!existsSync(path)) return null;
|
|
224
|
+
try {
|
|
225
|
+
if (statSync(path).size === 0) return null;
|
|
226
|
+
} catch {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
230
|
+
const target = `${name}__archive_${timestampSuffix()}${attempt > 0 ? `_${attempt}` : ""}`;
|
|
231
|
+
if (renameSession(name, target)) return target;
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
221
235
|
function countLines(path) {
|
|
222
236
|
try {
|
|
223
237
|
const raw = readFileSync(path, "utf8");
|
|
@@ -242,6 +256,7 @@ export {
|
|
|
242
256
|
renameSession,
|
|
243
257
|
pruneStaleSessions,
|
|
244
258
|
deleteSession,
|
|
245
|
-
rewriteSession
|
|
259
|
+
rewriteSession,
|
|
260
|
+
archiveSession
|
|
246
261
|
};
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
262
|
+
//# sourceMappingURL=chunk-6CXT5JRM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/memory/session.ts"],"sourcesContent":["/** JSONL append-only message log under `~/.reasonix/sessions/`; concurrent-write safe. */\n\nimport { execFileSync } from \"node:child_process\";\nimport {\n appendFileSync,\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { ChatMessage } from \"../types.js\";\n\n/** Best-effort git branch sniff; returns undefined if not a git repo or git missing. */\nexport function detectGitBranch(cwd: string): string | undefined {\n try {\n const out = execFileSync(\"git\", [\"branch\", \"--show-current\"], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 800,\n encoding: \"utf8\",\n }).trim();\n return out || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SessionInfo {\n name: string;\n path: string;\n size: number;\n messageCount: number;\n mtime: Date;\n meta: SessionMeta;\n}\n\nexport interface SessionMeta {\n branch?: string;\n summary?: string;\n totalCostUsd?: number;\n turnCount?: number;\n /** Absolute path of the workspace root the session was created/used in. */\n workspace?: string;\n /** Wallet currency at last save — used to format `totalCostUsd` in the picker without re-fetching balance. */\n balanceCurrency?: string;\n /** Cumulative cache hit / miss tokens across the session — survives resume so /status cache% isn't 0 on a fresh boot. */\n cacheHitTokens?: number;\n cacheMissTokens?: number;\n /** Last turn's promptTokens — lets /status render the context bar before the next turn fires. */\n lastPromptTokens?: number;\n}\n\nexport function sessionsDir(): string {\n return join(homedir(), \".reasonix\", \"sessions\");\n}\n\nexport function sessionPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.jsonl`);\n}\n\nexport function sanitizeName(name: string): string {\n const cleaned = name.replace(/[^\\w\\-\\u4e00-\\u9fa5]/g, \"_\").slice(0, 64);\n return cleaned || \"default\";\n}\n\n/** Sortable timestamp `YYYYMMDDHHmm` — used as a session-name suffix. */\nexport function timestampSuffix(): string {\n return new Date().toISOString().replace(/[^\\d]/g, \"\").slice(0, 12);\n}\n\n/** Names of `.jsonl` sessions starting with `prefix`, newest-first by filename. */\nexport function findSessionsByPrefix(prefix: string): string[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n try {\n const files = readdirSync(dir)\n .filter((f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\") && f.startsWith(prefix))\n .sort()\n .reverse();\n return files.map((f) => f.replace(/\\.jsonl$/, \"\"));\n } catch {\n return [];\n }\n}\n\nexport interface SessionPreview {\n messageCount: number;\n lastActive: Date;\n}\n\n/** Resolve launch-time session: forceNew → timestamped suffix; else latest `${name}-*` if any, else base. Preview returned only on the default branch when messages exist. */\nexport function resolveSession(\n sessionName: string | undefined,\n forceNew?: boolean,\n forceResume?: boolean,\n): { resolved: string | undefined; preview: SessionPreview | undefined } {\n let resolved = sessionName;\n let preview: SessionPreview | undefined;\n\n if (sessionName && forceNew) {\n resolved = `${sessionName}-${timestampSuffix()}`;\n } else if (sessionName && !forceResume) {\n let sessionToCheck = sessionName;\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n sessionToCheck = prefixed[0]!;\n }\n const prior = loadSessionMessages(sessionToCheck);\n if (prior.length > 0) {\n resolved = sessionToCheck;\n const p = sessionPath(sessionToCheck);\n const mtime = existsSync(p) ? statSync(p).mtime : new Date();\n preview = { messageCount: prior.length, lastActive: mtime };\n }\n } else if (sessionName && forceResume) {\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n resolved = prefixed[0]!;\n }\n }\n\n return { resolved, preview };\n}\n\nexport function loadSessionMessages(name: string): ChatMessage[] {\n const path = sessionPath(name);\n if (!existsSync(path)) return [];\n try {\n const raw = readFileSync(path, \"utf8\");\n const out: ChatMessage[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const msg = JSON.parse(trimmed) as ChatMessage;\n if (msg && typeof msg === \"object\" && \"role\" in msg) out.push(msg);\n } catch {\n /* skip malformed line */\n }\n }\n return out;\n } catch {\n return [];\n }\n}\n\nexport function appendSessionMessage(name: string, message: ChatMessage): void {\n const path = sessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n appendFileSync(path, `${JSON.stringify(message)}\\n`, \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported on this platform */\n }\n}\n\nexport function listSessions(): SessionInfo[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n try {\n // Exclude `.events.jsonl` sidecars — they share the .jsonl suffix.\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\"),\n );\n return files\n .map((file) => {\n const path = join(dir, file);\n const stat = statSync(path);\n const name = file.replace(/\\.jsonl$/, \"\");\n const messageCount = countLines(path);\n return {\n name,\n path,\n size: stat.size,\n messageCount,\n mtime: stat.mtime,\n meta: loadSessionMeta(name),\n };\n })\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n } catch {\n return [];\n }\n}\n\n/** Strict match — legacy sessions without meta.workspace are hidden; resume by name still works. */\nexport function listSessionsForWorkspace(workspace: string): SessionInfo[] {\n return listSessions().filter((s) => s.meta.workspace === workspace);\n}\n\nfunction metaPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.meta.json`);\n}\n\nexport function loadSessionMeta(name: string): SessionMeta {\n const p = metaPath(name);\n if (!existsSync(p)) return {};\n try {\n const raw = JSON.parse(readFileSync(p, \"utf8\")) as SessionMeta;\n return raw && typeof raw === \"object\" ? raw : {};\n } catch {\n return {};\n }\n}\n\nexport function patchSessionMeta(name: string, patch: Partial<SessionMeta>): SessionMeta {\n const cur = loadSessionMeta(name);\n const next: SessionMeta = { ...cur, ...patch };\n const p = metaPath(name);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(next), \"utf8\");\n try {\n chmodSync(p, 0o600);\n } catch {\n /* chmod not supported */\n }\n return next;\n}\n\n/** Renames the JSONL plus all known sidecars together; returns false if target already exists. */\nexport function renameSession(oldName: string, newName: string): boolean {\n const safeOld = sanitizeName(oldName);\n const safeNew = sanitizeName(newName);\n if (safeOld === safeNew) return false;\n const oldJsonl = sessionPath(oldName);\n const newJsonl = sessionPath(newName);\n if (!existsSync(oldJsonl) || existsSync(newJsonl)) return false;\n renameSync(oldJsonl, newJsonl);\n for (const ext of [\".events.jsonl\", \".meta.json\", \".pending.json\", \".plan.json\"]) {\n const oldP = oldJsonl.replace(/\\.jsonl$/, ext);\n const newP = newJsonl.replace(/\\.jsonl$/, ext);\n if (existsSync(oldP)) {\n try {\n renameSync(oldP, newP);\n } catch {\n /* sidecar rename failed — leave the jsonl rename in place */\n }\n }\n }\n return true;\n}\n\n/** Best-effort: per-file delete errors are swallowed so partial pruning still finishes. */\nexport function pruneStaleSessions(daysOld = 90): string[] {\n const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1000;\n const deleted: string[] = [];\n for (const s of listSessions()) {\n if (s.mtime.getTime() < cutoff) {\n if (deleteSession(s.name)) deleted.push(s.name);\n }\n }\n return deleted;\n}\n\nexport function deleteSession(name: string): boolean {\n const path = sessionPath(name);\n try {\n unlinkSync(path);\n for (const ext of [\".events.jsonl\", \".pending.json\", \".meta.json\", \".plan.json\"]) {\n const sidecar = path.replace(/\\.jsonl$/, ext);\n try {\n unlinkSync(sidecar);\n } catch {\n /* expected when the sidecar doesn't exist */\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/** Non-atomic truncate+write window is acceptable — concurrent crash here = `/forget`. */\nexport function rewriteSession(name: string, messages: ChatMessage[]): void {\n const path = sessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n const body = messages.map((m) => JSON.stringify(m)).join(\"\\n\");\n writeFileSync(path, body ? `${body}\\n` : \"\", \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported */\n }\n}\n\nfunction countLines(path: string): number {\n try {\n const raw = readFileSync(path, \"utf8\");\n return raw.split(/\\r?\\n/).filter((l) => l.trim()).length;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/memory/session.ts"],"sourcesContent":["/** JSONL append-only message log under `~/.reasonix/sessions/`; concurrent-write safe. */\n\nimport { execFileSync } from \"node:child_process\";\nimport {\n appendFileSync,\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { ChatMessage } from \"../types.js\";\n\n/** Best-effort git branch sniff; returns undefined if not a git repo or git missing. */\nexport function detectGitBranch(cwd: string): string | undefined {\n try {\n const out = execFileSync(\"git\", [\"branch\", \"--show-current\"], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 800,\n encoding: \"utf8\",\n }).trim();\n return out || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SessionInfo {\n name: string;\n path: string;\n size: number;\n messageCount: number;\n mtime: Date;\n meta: SessionMeta;\n}\n\nexport interface SessionMeta {\n branch?: string;\n summary?: string;\n totalCostUsd?: number;\n turnCount?: number;\n /** Absolute path of the workspace root the session was created/used in. */\n workspace?: string;\n /** Wallet currency at last save — used to format `totalCostUsd` in the picker without re-fetching balance. */\n balanceCurrency?: string;\n /** Cumulative cache hit / miss tokens across the session — survives resume so /status cache% isn't 0 on a fresh boot. */\n cacheHitTokens?: number;\n cacheMissTokens?: number;\n /** Last turn's promptTokens — lets /status render the context bar before the next turn fires. */\n lastPromptTokens?: number;\n}\n\nexport function sessionsDir(): string {\n return join(homedir(), \".reasonix\", \"sessions\");\n}\n\nexport function sessionPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.jsonl`);\n}\n\nexport function sanitizeName(name: string): string {\n const cleaned = name.replace(/[^\\w\\-\\u4e00-\\u9fa5]/g, \"_\").slice(0, 64);\n return cleaned || \"default\";\n}\n\n/** Sortable timestamp `YYYYMMDDHHmm` — used as a session-name suffix. */\nexport function timestampSuffix(): string {\n return new Date().toISOString().replace(/[^\\d]/g, \"\").slice(0, 12);\n}\n\n/** Names of `.jsonl` sessions starting with `prefix`, newest-first by filename. */\nexport function findSessionsByPrefix(prefix: string): string[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n try {\n const files = readdirSync(dir)\n .filter((f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\") && f.startsWith(prefix))\n .sort()\n .reverse();\n return files.map((f) => f.replace(/\\.jsonl$/, \"\"));\n } catch {\n return [];\n }\n}\n\nexport interface SessionPreview {\n messageCount: number;\n lastActive: Date;\n}\n\n/** Resolve launch-time session: forceNew → timestamped suffix; else latest `${name}-*` if any, else base. Preview returned only on the default branch when messages exist. */\nexport function resolveSession(\n sessionName: string | undefined,\n forceNew?: boolean,\n forceResume?: boolean,\n): { resolved: string | undefined; preview: SessionPreview | undefined } {\n let resolved = sessionName;\n let preview: SessionPreview | undefined;\n\n if (sessionName && forceNew) {\n resolved = `${sessionName}-${timestampSuffix()}`;\n } else if (sessionName && !forceResume) {\n let sessionToCheck = sessionName;\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n sessionToCheck = prefixed[0]!;\n }\n const prior = loadSessionMessages(sessionToCheck);\n if (prior.length > 0) {\n resolved = sessionToCheck;\n const p = sessionPath(sessionToCheck);\n const mtime = existsSync(p) ? statSync(p).mtime : new Date();\n preview = { messageCount: prior.length, lastActive: mtime };\n }\n } else if (sessionName && forceResume) {\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n resolved = prefixed[0]!;\n }\n }\n\n return { resolved, preview };\n}\n\nexport function loadSessionMessages(name: string): ChatMessage[] {\n const path = sessionPath(name);\n if (!existsSync(path)) return [];\n try {\n const raw = readFileSync(path, \"utf8\");\n const out: ChatMessage[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const msg = JSON.parse(trimmed) as ChatMessage;\n if (msg && typeof msg === \"object\" && \"role\" in msg) out.push(msg);\n } catch {\n /* skip malformed line */\n }\n }\n return out;\n } catch {\n return [];\n }\n}\n\nexport function appendSessionMessage(name: string, message: ChatMessage): void {\n const path = sessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n appendFileSync(path, `${JSON.stringify(message)}\\n`, \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported on this platform */\n }\n}\n\nexport function listSessions(): SessionInfo[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n try {\n // Exclude `.events.jsonl` sidecars — they share the .jsonl suffix.\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\"),\n );\n return files\n .map((file) => {\n const path = join(dir, file);\n const stat = statSync(path);\n const name = file.replace(/\\.jsonl$/, \"\");\n const messageCount = countLines(path);\n return {\n name,\n path,\n size: stat.size,\n messageCount,\n mtime: stat.mtime,\n meta: loadSessionMeta(name),\n };\n })\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n } catch {\n return [];\n }\n}\n\n/** Strict match — legacy sessions without meta.workspace are hidden; resume by name still works. */\nexport function listSessionsForWorkspace(workspace: string): SessionInfo[] {\n return listSessions().filter((s) => s.meta.workspace === workspace);\n}\n\nfunction metaPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.meta.json`);\n}\n\nexport function loadSessionMeta(name: string): SessionMeta {\n const p = metaPath(name);\n if (!existsSync(p)) return {};\n try {\n const raw = JSON.parse(readFileSync(p, \"utf8\")) as SessionMeta;\n return raw && typeof raw === \"object\" ? raw : {};\n } catch {\n return {};\n }\n}\n\nexport function patchSessionMeta(name: string, patch: Partial<SessionMeta>): SessionMeta {\n const cur = loadSessionMeta(name);\n const next: SessionMeta = { ...cur, ...patch };\n const p = metaPath(name);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(next), \"utf8\");\n try {\n chmodSync(p, 0o600);\n } catch {\n /* chmod not supported */\n }\n return next;\n}\n\n/** Renames the JSONL plus all known sidecars together; returns false if target already exists. */\nexport function renameSession(oldName: string, newName: string): boolean {\n const safeOld = sanitizeName(oldName);\n const safeNew = sanitizeName(newName);\n if (safeOld === safeNew) return false;\n const oldJsonl = sessionPath(oldName);\n const newJsonl = sessionPath(newName);\n if (!existsSync(oldJsonl) || existsSync(newJsonl)) return false;\n renameSync(oldJsonl, newJsonl);\n for (const ext of [\".events.jsonl\", \".meta.json\", \".pending.json\", \".plan.json\"]) {\n const oldP = oldJsonl.replace(/\\.jsonl$/, ext);\n const newP = newJsonl.replace(/\\.jsonl$/, ext);\n if (existsSync(oldP)) {\n try {\n renameSync(oldP, newP);\n } catch {\n /* sidecar rename failed — leave the jsonl rename in place */\n }\n }\n }\n return true;\n}\n\n/** Best-effort: per-file delete errors are swallowed so partial pruning still finishes. */\nexport function pruneStaleSessions(daysOld = 90): string[] {\n const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1000;\n const deleted: string[] = [];\n for (const s of listSessions()) {\n if (s.mtime.getTime() < cutoff) {\n if (deleteSession(s.name)) deleted.push(s.name);\n }\n }\n return deleted;\n}\n\nexport function deleteSession(name: string): boolean {\n const path = sessionPath(name);\n try {\n unlinkSync(path);\n for (const ext of [\".events.jsonl\", \".pending.json\", \".meta.json\", \".plan.json\"]) {\n const sidecar = path.replace(/\\.jsonl$/, ext);\n try {\n unlinkSync(sidecar);\n } catch {\n /* expected when the sidecar doesn't exist */\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/** Non-atomic truncate+write window is acceptable — concurrent crash here = `/forget`. */\nexport function rewriteSession(name: string, messages: ChatMessage[]): void {\n const path = sessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n const body = messages.map((m) => JSON.stringify(m)).join(\"\\n\");\n writeFileSync(path, body ? `${body}\\n` : \"\", \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported */\n }\n}\n\n/** Rotate the live jsonl + sidecars to `<name>__archive_<ts>` so /new doesn't destroy history. Returns the archive name, or null if there was nothing to archive. */\nexport function archiveSession(name: string): string | null {\n const path = sessionPath(name);\n if (!existsSync(path)) return null;\n try {\n if (statSync(path).size === 0) return null;\n } catch {\n return null;\n }\n for (let attempt = 0; attempt < 5; attempt++) {\n const target = `${name}__archive_${timestampSuffix()}${attempt > 0 ? `_${attempt}` : \"\"}`;\n if (renameSession(name, target)) return target;\n }\n return null;\n}\n\nfunction countLines(path: string): number {\n try {\n const raw = readFileSync(path, \"utf8\");\n return raw.split(/\\r?\\n/).filter((l) => l.trim()).length;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
sanitizeName,
|
|
4
4
|
sessionsDir
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6CXT5JRM.js";
|
|
6
6
|
|
|
7
7
|
// src/adapters/event-sink-jsonl.ts
|
|
8
8
|
import { chmodSync, createWriteStream, mkdirSync } from "fs";
|
|
@@ -50,4 +50,4 @@ export {
|
|
|
50
50
|
eventLogPath,
|
|
51
51
|
openEventSink
|
|
52
52
|
};
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-6NMWJSES.js.map
|
|
@@ -549,6 +549,7 @@ var EN = {
|
|
|
549
549
|
handlers: {
|
|
550
550
|
basic: {
|
|
551
551
|
newInfo: "\u25B8 new conversation \u2014 dropped {count} message(s) from context. Same session, fresh slate.",
|
|
552
|
+
newInfoArchived: '\u25B8 new conversation \u2014 dropped {count} message(s) from context. Prior transcript archived as "{archived}" (visible under Sessions).',
|
|
552
553
|
helpTitle: "Commands:",
|
|
553
554
|
helpShellTitle: "Shell shortcut:",
|
|
554
555
|
helpShell: " !<cmd> run <cmd> in the sandbox root; output goes into",
|
|
@@ -866,6 +867,44 @@ var EN = {
|
|
|
866
867
|
newError: "\u25B2 /skill new failed: {reason}"
|
|
867
868
|
}
|
|
868
869
|
},
|
|
870
|
+
statusBar: {
|
|
871
|
+
turn: "turn",
|
|
872
|
+
cache: "cache",
|
|
873
|
+
spent: "spent",
|
|
874
|
+
left: " left",
|
|
875
|
+
slow: "slow",
|
|
876
|
+
disconnect: "disconnect",
|
|
877
|
+
reconnecting: "reconnecting\u2026",
|
|
878
|
+
approvingIn: "approving in ",
|
|
879
|
+
escToInterrupt: "s \xB7 esc to interrupt",
|
|
880
|
+
recordingGlyph: "\u25CFREC",
|
|
881
|
+
mb: " MB",
|
|
882
|
+
evt: " evt"
|
|
883
|
+
},
|
|
884
|
+
editMode: {
|
|
885
|
+
plan: "PLAN MODE",
|
|
886
|
+
yolo: "YOLO",
|
|
887
|
+
auto: "AUTO",
|
|
888
|
+
review: "REVIEW",
|
|
889
|
+
writesGated: " writes gated \xB7 /plan off to leave",
|
|
890
|
+
editsShellAuto: "edits + shell auto \xB7 /undo to roll back",
|
|
891
|
+
editsLandNow: "edits land now \xB7 u to undo",
|
|
892
|
+
queuedApplyDiscard: "{count} queued \xB7 y apply \xB7 n discard",
|
|
893
|
+
editsQueued: "edits queued \xB7 y apply \xB7 n discard",
|
|
894
|
+
shiftTabFlip: " {mid} \xB7 Shift+Tab to flip",
|
|
895
|
+
queuedDots: "queued\u2026"
|
|
896
|
+
},
|
|
897
|
+
composer: {
|
|
898
|
+
placeholder: "ask anything \xB7 slash for commands \xB7 at-sign for files",
|
|
899
|
+
waitingForResponse: "\u2026waiting for response\u2026",
|
|
900
|
+
hintSend: "send",
|
|
901
|
+
hintNewline: "newline",
|
|
902
|
+
hintScroll: "scroll",
|
|
903
|
+
hintHistory: "history",
|
|
904
|
+
hintAbort: "abort",
|
|
905
|
+
hintQuit: "quit",
|
|
906
|
+
abortedHint: "turn aborted by user \xB7 esc again to clear \xB7 \u23CE to ask a follow-up"
|
|
907
|
+
},
|
|
869
908
|
cardTitles: {
|
|
870
909
|
usage: "usage",
|
|
871
910
|
context: "context",
|
|
@@ -1464,6 +1503,7 @@ var zhCN = {
|
|
|
1464
1503
|
handlers: {
|
|
1465
1504
|
basic: {
|
|
1466
1505
|
newInfo: "\u25B8 \u65B0\u5BF9\u8BDD \u2014 \u5DF2\u4ECE\u4E0A\u4E0B\u6587\u4E2D\u4E22\u5F03 {count} \u6761\u6D88\u606F\u3002\u540C\u4E00\u4F1A\u8BDD\uFF0C\u5168\u65B0\u5F00\u59CB\u3002",
|
|
1506
|
+
newInfoArchived: "\u25B8 \u65B0\u5BF9\u8BDD \u2014 \u5DF2\u4ECE\u4E0A\u4E0B\u6587\u4E2D\u4E22\u5F03 {count} \u6761\u6D88\u606F\u3002\u539F\u5BF9\u8BDD\u5DF2\u5F52\u6863\u4E3A\u300C{archived}\u300D\uFF0C\u53EF\u5728 Sessions \u9762\u677F\u67E5\u770B\u3002",
|
|
1467
1507
|
helpTitle: "\u547D\u4EE4\uFF1A",
|
|
1468
1508
|
helpShellTitle: "Shell \u5FEB\u6377\u65B9\u5F0F\uFF1A",
|
|
1469
1509
|
helpShell: " !<cmd> \u5728\u6C99\u7BB1\u6839\u76EE\u5F55\u8FD0\u884C <cmd>\uFF1B\u8F93\u51FA\u8FDB\u5165\u5BF9\u8BDD",
|
|
@@ -1781,6 +1821,44 @@ var zhCN = {
|
|
|
1781
1821
|
newError: "\u25B2 /skill new \u5931\u8D25\uFF1A{reason}"
|
|
1782
1822
|
}
|
|
1783
1823
|
},
|
|
1824
|
+
statusBar: {
|
|
1825
|
+
turn: "\u8F6E",
|
|
1826
|
+
cache: "\u7F13\u5B58",
|
|
1827
|
+
spent: "\u5DF2\u82B1\u8D39",
|
|
1828
|
+
left: " \u5269\u4F59",
|
|
1829
|
+
slow: "\u6162\u901F",
|
|
1830
|
+
disconnect: "\u65AD\u5F00",
|
|
1831
|
+
reconnecting: "\u91CD\u8FDE\u4E2D\u2026",
|
|
1832
|
+
approvingIn: "\u5373\u5C06\u6279\u51C6\uFF0C",
|
|
1833
|
+
escToInterrupt: "\u79D2 \xB7 Esc \u4E2D\u65AD",
|
|
1834
|
+
recordingGlyph: "\u25CFREC",
|
|
1835
|
+
mb: " MB",
|
|
1836
|
+
evt: " \u4E8B\u4EF6"
|
|
1837
|
+
},
|
|
1838
|
+
editMode: {
|
|
1839
|
+
plan: "\u8BA1\u5212",
|
|
1840
|
+
yolo: "\u81EA\u7531",
|
|
1841
|
+
auto: "\u81EA\u52A8",
|
|
1842
|
+
review: "\u5BA1\u6838",
|
|
1843
|
+
writesGated: " \u5199\u5165\u53D7\u9650 \xB7 /plan off \u89E3\u9664",
|
|
1844
|
+
editsShellAuto: "\u7F16\u8F91 + Shell \u81EA\u52A8 \xB7 /undo \u53EF\u56DE\u6EDA",
|
|
1845
|
+
editsLandNow: "\u7F16\u8F91\u7ACB\u5373\u751F\u6548 \xB7 \u6309 u \u64A4\u6D88",
|
|
1846
|
+
queuedApplyDiscard: "{count} \u4E2A\u5F85\u5904\u7406 \xB7 y \u5E94\u7528 \xB7 n \u4E22\u5F03",
|
|
1847
|
+
editsQueued: "\u7F16\u8F91\u5DF2\u6392\u961F \xB7 y \u5E94\u7528 \xB7 n \u4E22\u5F03",
|
|
1848
|
+
shiftTabFlip: " {mid} \xB7 Shift+Tab \u5207\u6362",
|
|
1849
|
+
queuedDots: "\u6392\u961F\u4E2D\u2026"
|
|
1850
|
+
},
|
|
1851
|
+
composer: {
|
|
1852
|
+
placeholder: "\u8F93\u5165\u4EFB\u4F55\u5185\u5BB9 \xB7 / \u4F7F\u7528\u547D\u4EE4 \xB7 @ \u5F15\u7528\u6587\u4EF6",
|
|
1853
|
+
waitingForResponse: "\u2026\u7B49\u5F85\u54CD\u5E94\u2026",
|
|
1854
|
+
hintSend: "\u53D1\u9001",
|
|
1855
|
+
hintNewline: "\u6362\u884C",
|
|
1856
|
+
hintScroll: "\u6EDA\u52A8",
|
|
1857
|
+
hintHistory: "\u5386\u53F2",
|
|
1858
|
+
hintAbort: "\u4E2D\u6B62",
|
|
1859
|
+
hintQuit: "\u9000\u51FA",
|
|
1860
|
+
abortedHint: "\u7528\u6237\u5DF2\u4E2D\u6B62\u672C\u8F6E \xB7 \u518D\u6309 Esc \u6E05\u9664 \xB7 \u23CE \u7EE7\u7EED\u63D0\u95EE"
|
|
1861
|
+
},
|
|
1784
1862
|
cardTitles: {
|
|
1785
1863
|
usage: "\u7528\u91CF",
|
|
1786
1864
|
context: "\u4E0A\u4E0B\u6587",
|
|
@@ -1920,4 +1998,4 @@ export {
|
|
|
1920
1998
|
tObj,
|
|
1921
1999
|
t
|
|
1922
2000
|
};
|
|
1923
|
-
//# sourceMappingURL=chunk-
|
|
2001
|
+
//# sourceMappingURL=chunk-GKZJXYMY.js.map
|