reasonix 0.3.1 → 0.4.1
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 +114 -77
- package/dist/cli/chunk-2P2MZLCE.js +81 -0
- package/dist/cli/chunk-2P2MZLCE.js.map +1 -0
- package/dist/cli/index.js +529 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompt-MMANQ36Z.js +10 -0
- package/dist/cli/prompt-MMANQ36Z.js.map +1 -0
- package/dist/index.d.ts +142 -3
- package/dist/index.js +308 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,20 +6,25 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/reasonix)
|
|
7
7
|
[](./package.json)
|
|
8
8
|
|
|
9
|
-
**
|
|
10
|
-
|
|
11
|
-
Reasonix is not another generic agent wrapper. Every abstraction is justified
|
|
12
|
-
by a DeepSeek-specific property — dirt-cheap tokens, R1 reasoning traces,
|
|
13
|
-
automatic prefix caching, JSON mode. Generic frameworks treat DeepSeek as
|
|
14
|
-
"OpenAI with a different base URL" and leave these advantages on the table.
|
|
15
|
-
Reasonix leans into them.
|
|
9
|
+
**A DeepSeek-native AI coding assistant in your terminal.** Ink TUI. MCP
|
|
10
|
+
first-class. No LangChain.
|
|
16
11
|
|
|
17
12
|
```bash
|
|
18
|
-
npx reasonix
|
|
19
|
-
# inside the TUI, type /help for everything else
|
|
13
|
+
npx reasonix
|
|
20
14
|
```
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
One command. First run walks you through a 30-second wizard (API key →
|
|
17
|
+
preset → pick MCP servers from a checklist); every run after that drops
|
|
18
|
+
straight into chat with your tools wired up. Inside the chat, type `/help`.
|
|
19
|
+
|
|
20
|
+
Why bother with yet another agent framework? Because every abstraction
|
|
21
|
+
here earns its weight against a DeepSeek-specific property — dirt-cheap
|
|
22
|
+
tokens, R1 reasoning traces, automatic prefix caching, JSON mode.
|
|
23
|
+
Generic wrappers treat DeepSeek as "OpenAI with a different base URL"
|
|
24
|
+
and leave these advantages on the table. Reasonix leans into them:
|
|
25
|
+
on the same τ-bench-lite workload,
|
|
26
|
+
[**94.4% cache hit, ~40% cheaper tokens, 100% pass rate**](#validated-numbers)
|
|
27
|
+
vs. a cache-hostile baseline.
|
|
23
28
|
|
|
24
29
|
---
|
|
25
30
|
|
|
@@ -27,12 +32,15 @@ No flag soup. All feature toggles live behind slash commands in the TUI.
|
|
|
27
32
|
|
|
28
33
|
| Feature | How it works | Opt in |
|
|
29
34
|
|---|---|---|
|
|
35
|
+
| **Setup wizard** | First run of `npx reasonix`: pick preset, multi-select MCP servers from a curated catalog, saved to config so the next run just launches chat | always on (first run) |
|
|
36
|
+
| **MCP (stdio + SSE)** | Multi-server bridge — every MCP tool inherits Cache-First + repair + context-safety automatically. `reasonix mcp list` shows the catalog | always on |
|
|
30
37
|
| **Cache-First Loop** | Immutable prefix + append-only log = prefix byte-stable across turns → DeepSeek's automatic prefix cache hits at 70–95% | always on |
|
|
31
|
-
| **
|
|
32
|
-
| **
|
|
38
|
+
| **Context safety net** | Tool results capped at 32k chars · oversized sessions auto-heal on load · `/compact` to shrink further · ctx gauge in the status bar · Esc to abort exploration and get a forced summary | always on |
|
|
39
|
+
| **R1 Thought Harvesting** | Parses `reasoning_content` into typed `{ subgoals, hypotheses, uncertainties, rejectedPaths }` via a cheap V3 call | `/preset smart` |
|
|
40
|
+
| **Self-Consistency Branching** | Runs N parallel samples at spread temperatures; picks the one with the fewest flagged uncertainties | `/preset max` / `/branch N` |
|
|
33
41
|
| **Tool-Call Repair** | Auto-flattens deep/wide schemas, scavenges tool calls leaked into `<think>`, repairs truncated JSON, breaks call-storms | always on |
|
|
34
42
|
| **Retry layer** | Exponential backoff + jitter on 408/429/500/502/503/504 and network errors. 4xx auth errors don't retry | always on |
|
|
35
|
-
| **Ink TUI** | Live cache-hit / cost panel. Streams R1 thinking to a compact preview. Renders Markdown (bold / lists / code / stripped LaTeX) | always on |
|
|
43
|
+
| **Ink TUI** | Live cache-hit / cost / context panel. Streams R1 thinking to a compact preview. Renders Markdown (bold / lists / code / stripped LaTeX) | always on |
|
|
36
44
|
|
|
37
45
|
---
|
|
38
46
|
|
|
@@ -91,10 +99,12 @@ with your own API key: `npx tsx benchmarks/tau-bench/runner.ts --repeats 3`.
|
|
|
91
99
|
|
|
92
100
|
[r]: ./benchmarks/tau-bench/report.md
|
|
93
101
|
|
|
94
|
-
###
|
|
102
|
+
### MCP — works out of the box
|
|
95
103
|
|
|
96
104
|
Any [MCP](https://spec.modelcontextprotocol.io/) server's tools inherit
|
|
97
|
-
|
|
105
|
+
Cache-First + repair + context-safety automatically. The wizard (`npx
|
|
106
|
+
reasonix`) lets you multi-select from a curated catalog — no flags, no
|
|
107
|
+
JSON-by-hand. Three live reference runs:
|
|
98
108
|
|
|
99
109
|
| server | turns | tool calls | cache hit | cost | vs Claude |
|
|
100
110
|
|---|---:|---:|---:|---:|---:|
|
|
@@ -103,40 +113,21 @@ the same Cache-First benefits. Two live runs, two data points:
|
|
|
103
113
|
| **both concurrently** (`demo_add` + `fs_write_file`) | 5 | 4 | **81.1%** | $0.001852 | −95.9% |
|
|
104
114
|
|
|
105
115
|
The third row is the ecosystem proof: two MCP servers running as
|
|
106
|
-
separate subprocesses, tools from both exercised in one conversation
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
turns** — byte-stability survives concurrent MCP subprocesses.
|
|
116
|
+
separate subprocesses, tools from both exercised in one conversation.
|
|
117
|
+
**One single prefix hash across all 5 turns** — byte-stability survives
|
|
118
|
+
concurrent MCP subprocesses.
|
|
110
119
|
|
|
111
|
-
|
|
120
|
+
Reproduce without an API key (replay the committed transcripts):
|
|
112
121
|
|
|
113
122
|
```bash
|
|
114
123
|
npx reasonix replay benchmarks/tau-bench/transcripts/mcp-demo.add.jsonl
|
|
115
124
|
npx reasonix replay benchmarks/tau-bench/transcripts/mcp-filesystem.jsonl
|
|
116
125
|
```
|
|
117
126
|
|
|
118
|
-
**
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
reasonix mcp list
|
|
123
|
-
# Prints a curated catalog (filesystem, fetch, github, sqlite, …) with
|
|
124
|
-
# ready-to-paste --mcp commands.
|
|
125
|
-
|
|
126
|
-
# One server:
|
|
127
|
-
reasonix chat --mcp "filesystem=npx -y @modelcontextprotocol/server-filesystem /tmp/safe"
|
|
128
|
-
|
|
129
|
-
# Multiple servers at once — each gets its own namespace prefix:
|
|
130
|
-
reasonix chat \
|
|
131
|
-
--mcp "fs=npx -y @modelcontextprotocol/server-filesystem /tmp/safe" \
|
|
132
|
-
--mcp "mem=npx -y @modelcontextprotocol/server-memory"
|
|
133
|
-
# Tools land in a shared registry as fs_read_file, mem_set, etc.
|
|
134
|
-
|
|
135
|
-
# Remote / hosted MCP server — pass an http(s) URL instead of a command.
|
|
136
|
-
# Reasonix opens an SSE stream and POSTs JSON-RPC to the endpoint the
|
|
137
|
-
# server advertises (MCP 2024-11-05 HTTP+SSE transport).
|
|
138
|
-
reasonix chat --mcp "kb=https://mcp.example.com/sse"
|
|
139
|
-
```
|
|
127
|
+
Supported transports: **stdio** (local `npx` or binary) and **HTTP+SSE**
|
|
128
|
+
(remote / hosted servers, MCP 2024-11-05 spec). Pass an `http(s)://`
|
|
129
|
+
URL to `--mcp` and Reasonix opens the SSE stream and POSTs JSON-RPC
|
|
130
|
+
to the endpoint the server advertises.
|
|
140
131
|
|
|
141
132
|
[mcp]: ./benchmarks/tau-bench/transcripts/mcp-demo.add.jsonl
|
|
142
133
|
|
|
@@ -144,55 +135,98 @@ reasonix chat --mcp "kb=https://mcp.example.com/sse"
|
|
|
144
135
|
|
|
145
136
|
## Usage
|
|
146
137
|
|
|
147
|
-
###
|
|
138
|
+
### One command
|
|
148
139
|
|
|
149
140
|
```bash
|
|
150
|
-
npx reasonix
|
|
151
|
-
npx reasonix chat --session work # use a different named session
|
|
152
|
-
npx reasonix chat --no-session # ephemeral — nothing persisted
|
|
153
|
-
npx reasonix run "ask anything" # one-shot, streams to stdout
|
|
154
|
-
npx reasonix stats session.jsonl # quick summary of a transcript
|
|
155
|
-
npx reasonix replay chat.jsonl # pretty-print a transcript + rebuild cost/cache offline
|
|
156
|
-
npx reasonix diff a.jsonl b.jsonl --md diff.md # compare two transcripts: cache/cost delta + first divergence
|
|
141
|
+
npx reasonix
|
|
157
142
|
```
|
|
158
143
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
144
|
+
First run: a wizard asks for your API key, lets you pick a preset
|
|
145
|
+
(fast / smart / max), then offers a multi-select checklist of MCP
|
|
146
|
+
servers — filesystem, memory, github, puppeteer, everything. Everything
|
|
147
|
+
is saved to `~/.reasonix/config.json`. Subsequent runs drop straight
|
|
148
|
+
into chat.
|
|
163
149
|
|
|
164
|
-
### Inside the chat
|
|
150
|
+
### Inside the chat
|
|
165
151
|
|
|
166
|
-
A
|
|
167
|
-
|
|
152
|
+
A status bar at the top shows cache hit %, cost, Claude-equivalent, and
|
|
153
|
+
the **context gauge** (`ctx 42k/131k (32%)` — yellow at 50%, red + a
|
|
154
|
+
`/compact` nudge at 80%). A command strip under the input lists the
|
|
155
|
+
slash commands:
|
|
168
156
|
|
|
169
157
|
```
|
|
170
|
-
/
|
|
171
|
-
/preset smart
|
|
172
|
-
/
|
|
158
|
+
/help full list + hints
|
|
159
|
+
/preset <fast|smart|max> one-tap bundles (model + harvest + branch)
|
|
160
|
+
/mcp list attached MCP servers and tools
|
|
161
|
+
/compact [cap] shrink oversized tool results in history
|
|
162
|
+
/sessions · /forget list / delete saved sessions
|
|
163
|
+
/setup reconfigure (exits and tells you to run `reasonix setup`)
|
|
164
|
+
/clear · /exit
|
|
173
165
|
```
|
|
174
166
|
|
|
175
|
-
|
|
176
|
-
|
|
167
|
+
**Esc while thinking** — abort the current exploration and force the
|
|
168
|
+
model to summarize what it already found. No more "model ran 24 tool
|
|
169
|
+
calls and gave up" — you get an answer every time.
|
|
170
|
+
|
|
171
|
+
Sessions live as JSONL under `~/.reasonix/sessions/<name>.jsonl` —
|
|
172
|
+
every message appended atomically, so killing the CLI never loses
|
|
173
|
+
context. Oversized tool results auto-heal on load, so poisoning a
|
|
174
|
+
session with one giant `read_file` doesn't brick your history.
|
|
175
|
+
|
|
176
|
+
### Code mode — `npx reasonix code`
|
|
177
|
+
|
|
178
|
+
A thin opinionated layer on top of chat: filesystem MCP bridged at
|
|
179
|
+
`cwd`, coding system prompt, reasoner preset, per-directory session.
|
|
180
|
+
The model proposes edits as **SEARCH/REPLACE blocks**:
|
|
177
181
|
|
|
178
182
|
```
|
|
179
|
-
/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
src/foo.ts
|
|
184
|
+
<<<<<<< SEARCH
|
|
185
|
+
const x = 1;
|
|
186
|
+
=======
|
|
187
|
+
const x = 2;
|
|
188
|
+
>>>>>>> REPLACE
|
|
185
189
|
```
|
|
186
190
|
|
|
187
|
-
|
|
188
|
-
the
|
|
191
|
+
Reasonix parses them out of each turn, applies them to disk, reports
|
|
192
|
+
`✓ applied src/foo.ts` in the TUI. SEARCH must match byte-for-byte;
|
|
193
|
+
we never fuzzy-match (silent wrong edits are worse than loud
|
|
194
|
+
rejections). Run `git diff` to review, `git checkout .` to undo.
|
|
189
195
|
|
|
190
|
-
|
|
196
|
+
```bash
|
|
197
|
+
cd my-project
|
|
198
|
+
npx reasonix code # default: cwd, reasoner, per-dir session
|
|
199
|
+
npx reasonix code src/ # scope the filesystem sandbox tighter
|
|
200
|
+
npx reasonix code --no-session # ephemeral
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
First-run sandbox: because code mode uses the filesystem MCP from
|
|
204
|
+
`@modelcontextprotocol/server-filesystem`, the model can only read
|
|
205
|
+
and write inside the directory you pointed at. It literally can't
|
|
206
|
+
touch files above that root.
|
|
207
|
+
|
|
208
|
+
### Advanced — CLI subcommands and flags
|
|
191
209
|
|
|
192
|
-
|
|
210
|
+
```bash
|
|
211
|
+
npx reasonix setup # reconfigure any time
|
|
212
|
+
npx reasonix chat --session work # a different named session
|
|
213
|
+
npx reasonix chat --no-session # ephemeral — nothing persisted
|
|
214
|
+
npx reasonix run "ask anything" # one-shot, streams to stdout
|
|
215
|
+
npx reasonix stats session.jsonl # summarize a transcript
|
|
216
|
+
npx reasonix replay chat.jsonl # scrub a transcript + rebuild cost/cache
|
|
217
|
+
npx reasonix diff a.jsonl b.jsonl --md # compare two transcripts
|
|
218
|
+
npx reasonix mcp list # curated MCP server catalog
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Power users can still bypass config and drive Reasonix with flags:
|
|
193
222
|
|
|
194
223
|
```bash
|
|
195
|
-
npx reasonix chat
|
|
224
|
+
npx reasonix chat \
|
|
225
|
+
--preset max \
|
|
226
|
+
--mcp "filesystem=npx -y @modelcontextprotocol/server-filesystem /tmp/safe" \
|
|
227
|
+
--mcp "kb=https://mcp.example.com/sse" \
|
|
228
|
+
--transcript session.jsonl \
|
|
229
|
+
--no-config # ignore ~/.reasonix/config.json (for CI / reproducing issues)
|
|
196
230
|
```
|
|
197
231
|
|
|
198
232
|
### Library
|
|
@@ -238,16 +272,19 @@ console.log(loop.stats.summary());
|
|
|
238
272
|
|
|
239
273
|
### Configuration
|
|
240
274
|
|
|
241
|
-
|
|
242
|
-
|
|
275
|
+
The wizard handles everything on first run. If you'd rather use env vars
|
|
276
|
+
(CI, shared boxes, etc.):
|
|
243
277
|
|
|
244
278
|
```bash
|
|
245
|
-
export DEEPSEEK_API_KEY=sk-... #
|
|
279
|
+
export DEEPSEEK_API_KEY=sk-... # wins over ~/.reasonix/config.json
|
|
246
280
|
export DEEPSEEK_BASE_URL=https://... # optional alternate endpoint
|
|
247
281
|
```
|
|
248
282
|
|
|
249
283
|
Get a key (free credit on signup): <https://platform.deepseek.com/api_keys>
|
|
250
284
|
|
|
285
|
+
Re-run `npx reasonix setup` any time to add/remove MCP servers or switch
|
|
286
|
+
preset — your existing selections are pre-checked.
|
|
287
|
+
|
|
251
288
|
---
|
|
252
289
|
|
|
253
290
|
## Non-goals
|
|
@@ -269,7 +306,7 @@ cd reasonix
|
|
|
269
306
|
npm install
|
|
270
307
|
npm run dev chat # run CLI from source via tsx
|
|
271
308
|
npm run build # tsup to dist/
|
|
272
|
-
npm test # vitest (
|
|
309
|
+
npm test # vitest (279 tests)
|
|
273
310
|
npm run lint # biome
|
|
274
311
|
npm run typecheck # tsc --noEmit
|
|
275
312
|
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/code/prompt.ts
|
|
4
|
+
import { existsSync, readFileSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
var CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, list_directory, search_files, etc.) rooted at the user's working directory.
|
|
7
|
+
|
|
8
|
+
# When to edit vs. when to explore
|
|
9
|
+
|
|
10
|
+
Only propose edits when the user explicitly asks you to change, fix, add, remove, refactor, or write something. Do NOT propose edits when the user asks you to:
|
|
11
|
+
- analyze, read, explore, describe, or summarize a project
|
|
12
|
+
- explain how something works
|
|
13
|
+
- answer a question about the code
|
|
14
|
+
|
|
15
|
+
In those cases, use tools to gather what you need, then reply in prose. No SEARCH/REPLACE blocks, no file changes. If you're unsure what the user wants, ask.
|
|
16
|
+
|
|
17
|
+
When you do propose edits, the user will review them and decide whether to \`/apply\` or \`/discard\`. Don't assume they'll accept \u2014 write as if each edit will be audited, because it will.
|
|
18
|
+
|
|
19
|
+
# Editing files
|
|
20
|
+
|
|
21
|
+
When you've been asked to change a file, output one or more SEARCH/REPLACE blocks in this exact format:
|
|
22
|
+
|
|
23
|
+
path/to/file.ext
|
|
24
|
+
<<<<<<< SEARCH
|
|
25
|
+
exact existing lines from the file, including whitespace
|
|
26
|
+
=======
|
|
27
|
+
the new lines
|
|
28
|
+
>>>>>>> REPLACE
|
|
29
|
+
|
|
30
|
+
Rules:
|
|
31
|
+
- Always read_file first so your SEARCH matches byte-for-byte. If it doesn't match, the edit is rejected and you'll have to retry with the exact current content.
|
|
32
|
+
- One edit per block. Multiple blocks in one response are fine.
|
|
33
|
+
- To create a new file, leave SEARCH empty:
|
|
34
|
+
path/to/new.ts
|
|
35
|
+
<<<<<<< SEARCH
|
|
36
|
+
=======
|
|
37
|
+
(whole file content here)
|
|
38
|
+
>>>>>>> REPLACE
|
|
39
|
+
- Do NOT use write_file to change existing files \u2014 the user reviews your edits as SEARCH/REPLACE. write_file is only for files you explicitly want to overwrite wholesale (rare).
|
|
40
|
+
- Paths are relative to the working directory. Don't use absolute paths.
|
|
41
|
+
|
|
42
|
+
# Exploration
|
|
43
|
+
|
|
44
|
+
- Avoid listing or reading inside these common dependency / build directories unless the user explicitly asks about them: node_modules, dist, build, out, .next, .nuxt, .svelte-kit, .git, .venv, venv, __pycache__, target, coverage, .turbo, .cache. They're expensive and usually irrelevant.
|
|
45
|
+
- Prefer search_files / grep over list_directory when you know roughly what you're looking for \u2014 it saves context and avoids enumerating huge trees.
|
|
46
|
+
|
|
47
|
+
# Style
|
|
48
|
+
|
|
49
|
+
- Show edits; don't narrate them in prose. "Here's the fix:" is enough.
|
|
50
|
+
- One short paragraph explaining *why*, then the blocks.
|
|
51
|
+
- If you need to explore first (list / grep / read), do it with tool calls before writing any prose \u2014 silence while exploring is fine.
|
|
52
|
+
`;
|
|
53
|
+
function codeSystemPrompt(rootDir) {
|
|
54
|
+
const gitignorePath = join(rootDir, ".gitignore");
|
|
55
|
+
if (!existsSync(gitignorePath)) return CODE_SYSTEM_PROMPT;
|
|
56
|
+
let content;
|
|
57
|
+
try {
|
|
58
|
+
content = readFileSync(gitignorePath, "utf8");
|
|
59
|
+
} catch {
|
|
60
|
+
return CODE_SYSTEM_PROMPT;
|
|
61
|
+
}
|
|
62
|
+
const MAX = 2e3;
|
|
63
|
+
const truncated = content.length > MAX ? `${content.slice(0, MAX)}
|
|
64
|
+
\u2026 (truncated ${content.length - MAX} chars)` : content;
|
|
65
|
+
return `${CODE_SYSTEM_PROMPT}
|
|
66
|
+
|
|
67
|
+
# Project .gitignore
|
|
68
|
+
|
|
69
|
+
The user's repo ships this .gitignore \u2014 treat every pattern as "don't traverse or edit inside these paths unless explicitly asked":
|
|
70
|
+
|
|
71
|
+
\`\`\`
|
|
72
|
+
${truncated}
|
|
73
|
+
\`\`\`
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
CODE_SYSTEM_PROMPT,
|
|
79
|
+
codeSystemPrompt
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=chunk-2P2MZLCE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/code/prompt.ts"],"sourcesContent":["/**\n * System prompt used by `reasonix code`. Teaches the model:\n *\n * 1. It has a filesystem MCP bridge rooted at the user's CWD.\n * 2. To modify files it emits SEARCH/REPLACE blocks (not\n * `write_file` — that would whole-file rewrite and kill diff\n * reviewability).\n * 3. Read first, edit second — SEARCH must match byte-for-byte.\n * 4. Be concise. The user can read a diff faster than prose.\n *\n * Kept short on purpose. Long system prompts eat context budget that\n * the Cache-First Loop is trying to conserve. The SEARCH/REPLACE spec\n * is the one unavoidable bloat; we trim everything else.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport const CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, list_directory, search_files, etc.) rooted at the user's working directory.\n\n# When to edit vs. when to explore\n\nOnly propose edits when the user explicitly asks you to change, fix, add, remove, refactor, or write something. Do NOT propose edits when the user asks you to:\n- analyze, read, explore, describe, or summarize a project\n- explain how something works\n- answer a question about the code\n\nIn those cases, use tools to gather what you need, then reply in prose. No SEARCH/REPLACE blocks, no file changes. If you're unsure what the user wants, ask.\n\nWhen you do propose edits, the user will review them and decide whether to \\`/apply\\` or \\`/discard\\`. Don't assume they'll accept — write as if each edit will be audited, because it will.\n\n# Editing files\n\nWhen you've been asked to change a file, output one or more SEARCH/REPLACE blocks in this exact format:\n\npath/to/file.ext\n<<<<<<< SEARCH\nexact existing lines from the file, including whitespace\n=======\nthe new lines\n>>>>>>> REPLACE\n\nRules:\n- Always read_file first so your SEARCH matches byte-for-byte. If it doesn't match, the edit is rejected and you'll have to retry with the exact current content.\n- One edit per block. Multiple blocks in one response are fine.\n- To create a new file, leave SEARCH empty:\n path/to/new.ts\n <<<<<<< SEARCH\n =======\n (whole file content here)\n >>>>>>> REPLACE\n- Do NOT use write_file to change existing files — the user reviews your edits as SEARCH/REPLACE. write_file is only for files you explicitly want to overwrite wholesale (rare).\n- Paths are relative to the working directory. Don't use absolute paths.\n\n# Exploration\n\n- Avoid listing or reading inside these common dependency / build directories unless the user explicitly asks about them: node_modules, dist, build, out, .next, .nuxt, .svelte-kit, .git, .venv, venv, __pycache__, target, coverage, .turbo, .cache. They're expensive and usually irrelevant.\n- Prefer search_files / grep over list_directory when you know roughly what you're looking for — it saves context and avoids enumerating huge trees.\n\n# Style\n\n- Show edits; don't narrate them in prose. \"Here's the fix:\" is enough.\n- One short paragraph explaining *why*, then the blocks.\n- If you need to explore first (list / grep / read), do it with tool calls before writing any prose — silence while exploring is fine.\n`;\n\n/**\n * Inject the project's `.gitignore` content into the system prompt as a\n * \"respect this on top of the built-in denylist\" hint. We don't parse\n * the file — we hand it to the model as-is. Truncate long ones so we\n * don't eat context budget on huge generated ignore lists.\n *\n * Missing or unreadable .gitignore → returns the base prompt unchanged.\n */\nexport function codeSystemPrompt(rootDir: string): string {\n const gitignorePath = join(rootDir, \".gitignore\");\n if (!existsSync(gitignorePath)) return CODE_SYSTEM_PROMPT;\n let content: string;\n try {\n content = readFileSync(gitignorePath, \"utf8\");\n } catch {\n return CODE_SYSTEM_PROMPT;\n }\n const MAX = 2000;\n const truncated =\n content.length > MAX\n ? `${content.slice(0, MAX)}\\n… (truncated ${content.length - MAX} chars)`\n : content;\n return `${CODE_SYSTEM_PROMPT}\n\n# Project .gitignore\n\nThe user's repo ships this .gitignore — treat every pattern as \"don't traverse or edit inside these paths unless explicitly asked\":\n\n\\`\\`\\`\n${truncated}\n\\`\\`\\`\n`;\n}\n"],"mappings":";;;AAeA,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AAEd,IAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwD3B,SAAS,iBAAiB,SAAyB;AACxD,QAAM,gBAAgB,KAAK,SAAS,YAAY;AAChD,MAAI,CAAC,WAAW,aAAa,EAAG,QAAO;AACvC,MAAI;AACJ,MAAI;AACF,cAAU,aAAa,eAAe,MAAM;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AACZ,QAAM,YACJ,QAAQ,SAAS,MACb,GAAG,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,oBAAkB,QAAQ,SAAS,GAAG,YAC9D;AACN,SAAO,GAAG,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO5B,SAAS;AAAA;AAAA;AAGX;","names":[]}
|