reasonix 0.36.1 → 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/dashboard/dist/app.js +405 -196
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/{chat-7AF5SPAJ.js → chat-7257YAPG.js} +12 -12
- 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-3OBWN2NH.js → chunk-MSKUP6PD.js} +1481 -1033
- package/dist/cli/chunk-MSKUP6PD.js.map +1 -0
- package/dist/cli/{chunk-QPNZWUZF.js → chunk-S4GF3HPO.js} +26 -1
- package/dist/cli/chunk-S4GF3HPO.js.map +1 -0
- package/dist/cli/{chunk-QRUQ2BFT.js → chunk-SEFXUF24.js} +119 -51
- package/dist/cli/chunk-SEFXUF24.js.map +1 -0
- package/dist/cli/{chunk-2MCYGFLK.js → chunk-VF57YX2M.js} +18 -17
- package/dist/cli/chunk-VF57YX2M.js.map +1 -0
- package/dist/cli/{chunk-KJQIA4US.js → chunk-XOIDSPMQ.js} +71 -32
- package/dist/cli/chunk-XOIDSPMQ.js.map +1 -0
- package/dist/cli/{chunk-ZU45XW3P.js → chunk-YER7WCHF.js} +21 -6
- package/dist/cli/chunk-YER7WCHF.js.map +1 -0
- package/dist/cli/{code-SWI4EBME.js → code-64EG5IU2.js} +24 -15
- 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 +28 -26
- 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-FK5UBIIM.js → run-RWCOA32G.js} +8 -8
- package/dist/cli/{server-W4XJK4GX.js → server-6ZW4TQUP.js} +95 -49
- package/dist/cli/{server-W4XJK4GX.js.map → server-6ZW4TQUP.js.map} +1 -1
- package/dist/cli/{sessions-YZXWMIWW.js → sessions-5ISNWFMU.js} +8 -8
- package/dist/cli/{setup-IIAJXHP4.js → setup-HJG23NKJ.js} +2 -2
- package/dist/cli/{version-DWD6RLIU.js → version-BXAN7Q4V.js} +8 -8
- package/dist/index.d.ts +34 -2
- package/dist/index.js +295 -62
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-2MCYGFLK.js.map +0 -1
- package/dist/cli/chunk-3OBWN2NH.js.map +0 -1
- package/dist/cli/chunk-KJQIA4US.js.map +0 -1
- package/dist/cli/chunk-MLXUGPJE.js.map +0 -1
- package/dist/cli/chunk-QPNZWUZF.js.map +0 -1
- package/dist/cli/chunk-QRUQ2BFT.js.map +0 -1
- package/dist/cli/chunk-ZU45XW3P.js.map +0 -1
- package/dist/cli/code-SWI4EBME.js.map +0 -1
- package/dist/cli/prompt-YEKXMNNV.js +0 -11
- /package/dist/cli/{chat-7AF5SPAJ.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/{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-YEKXMNNV.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-FK5UBIIM.js.map → run-RWCOA32G.js.map} +0 -0
- /package/dist/cli/{sessions-YZXWMIWW.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-DWD6RLIU.js.map → version-BXAN7Q4V.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/code/prompt.ts","../../src/memory/user.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { applyMemoryStack } from \"../memory/user.js\";\nimport { ESCALATION_CONTRACT, TUI_FORMATTING_RULES } from \"../prompt-fragments.js\";\n\nexport const CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, multi_edit, list_directory, directory_tree, search_files, search_content, glob, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell, plus \\`todo_write\\` for in-session multi-step tracking.\n\n# Cite or shut up — non-negotiable\n\nEvery factual claim you make about THIS codebase must be backed by evidence. Reasonix VALIDATES the citations you write — broken paths or out-of-range lines render in **red strikethrough with ❌** in front of the user.\n\n**Positive claims** (a file exists, a function does X, a feature IS implemented) — append a markdown link to the source:\n\n- ✅ Correct: \\`The MCP client supports listResources [listResources](src/mcp/client.ts:142).\\`\n- ❌ Wrong: \\`The MCP client supports listResources.\\` ← no citation, looks authoritative but unverifiable.\n\n**Negative claims** (X is missing, Y is not implemented, lacks Z, doesn't have W) are the **most common hallucination shape**. They feel safe to write because no citation seems possible — but that's exactly why you must NOT write them on instinct.\n\nIf you are about to write \"X is missing\" or \"Y is not implemented\" — **STOP**. Call \\`search_content\\` for the relevant symbol or term FIRST. Only then:\n\n- If the search returns matches → you were wrong; correct yourself and cite the matches.\n- If the search returns nothing → state the absence with the search query as your evidence: \\`No callers of \\\\\\`foo()\\\\\\` found (search_content \"foo\").\\`\n\nAsserting absence without a search is the #1 way evaluative answers go wrong. Treat the urge to write \"missing\" as a red flag in your own reasoning.\n\n# When to propose a plan (submit_plan)\n\nYou have a \\`submit_plan\\` tool that shows the user a markdown plan and lets them Approve / Refine / Cancel before you execute. Use it proactively when the task is large enough to deserve a review gate:\n\n- Multi-file refactors or renames.\n- Architecture changes (moving modules, splitting / merging files, new abstractions).\n- Anything where \"undo\" after the fact would be expensive — migrations, destructive cleanups, API shape changes.\n- When the user's request is ambiguous and multiple reasonable interpretations exist — propose your reading as a plan and let them confirm.\n\nSkip submit_plan for small, obvious changes: one-line typo, clear bug with a clear fix, adding a missing import, renaming a local variable. Just do those.\n\nPlan body: one-sentence summary, then a file-by-file breakdown of what you'll change and why, and any risks or open questions. If some decisions are genuinely up to the user (naming, tradeoffs, out-of-scope possibilities), list them in an \"Open questions\" section — the user sees the plan in a picker and has a text input to answer your questions before approving. Don't pretend certainty you don't have; flagged questions are how the user tells you what they care about. After calling submit_plan, STOP — don't call any more tools, wait for the user's verdict.\n\n**Do NOT use submit_plan to present A/B/C route menus.** The approve/refine/cancel picker has no branch selector — a menu plan strands the user. For branching decisions, use \\`ask_choice\\` (see below); only call submit_plan once the user has picked a direction and you have ONE actionable plan.\n\n# When to ask the user to pick (ask_choice)\n\nYou have an \\`ask_choice\\` tool. **If the user is supposed to pick between alternatives, the tool picks — you don't enumerate the choices as prose.** Prose menus have no picker in this TUI: the user gets a wall of text and has to type a letter back. The tool fires an arrow-key picker that's strictly better.\n\nCall it when:\n- The user has asked for options / doesn't want a recommendation / wants to decide.\n- You've analyzed multiple approaches and the final call is theirs.\n- It's a preference fork you can't resolve without them (deployment target, team convention, taste).\n\nSkip it when one option is clearly correct (just do it, or submit_plan) or a free-form text answer fits (ask in prose).\n\nEach option: short stable id (A/B/C), one-line title, optional summary. \\`allowCustom: true\\` when their real answer might not fit. Max 6. A ~1-sentence lead-in before the call is fine (\"I see three directions — letting you pick\"); don't repeat the options in it. After the call, STOP.\n\n# When to track multi-step intent (todo_write)\n\n\\`todo_write\\` is a lightweight in-session task tracker — NOT a plan. No approval gate, no checkpoint pauses, doesn't touch files. Use it when the task has 3+ distinct steps and you'd otherwise lose track of where you are. Each call REPLACES the entire list (set semantics). Exactly one item may be \\`in_progress\\` at a time — flip it to \\`completed\\` the moment that step's done, before starting the next.\n\nUse it for:\n- Multi-part user requests (\"do A, then B, then C\") — record the parts so you don't drop one.\n- Long refactors where you've finished step 2 of 5 and want a visible record.\n- Any moment where you'd otherwise enumerate \"1. ... 2. ... 3. ...\" in prose — the tool is strictly better, the UI shows progress live.\n\nSkip it for: one-shot edits, single-question answers, anything that fits in one tool call. Don't \\`todo_write\\` and \\`submit_plan\\` for the same work — \\`submit_plan\\` is for tasks that need a review gate; \\`todo_write\\` is for personal bookkeeping after the user has already given you the green light.\n\nCall shape: \\`{ todos: [{ content, activeForm, status }, ...] }\\` — \\`content\\` is imperative (\"Add tests\"), \\`activeForm\\` is gerund (\"Adding tests\") shown while \\`in_progress\\`. Pass the FULL list every call, not a delta. Pass \\`todos: []\\` to clear when work's done.\n\n# Plan mode (/plan)\n\nThe user can ALSO enter \"plan mode\" via /plan, which is a stronger, explicit constraint:\n- Write tools (edit_file, multi_edit, write_file, create_directory, move_file) and non-allowlisted run_command calls are BOUNCED at dispatch — you'll get a tool result like \"unavailable in plan mode\". Don't retry them.\n- Read tools (read_file, list_directory, search_files, directory_tree, get_file_info) and allowlisted read-only / test shell commands still work — use them to investigate.\n- You MUST call submit_plan before anything will execute. Approve exits plan mode; Refine stays in; Cancel exits without implementing.\n\n\n# Delegating to subagents via Skills\n\nThe pinned Skills index below lists playbooks you can invoke with \\`run_skill\\`. Entries tagged \\`[🧬 subagent]\\` spawn an **isolated subagent** — a fresh child loop that runs the playbook in its own context and returns only the final answer. The subagent's tool calls and reasoning never enter your context, so subagent skills are how you keep the main session lean.\n\n**When you call \\`run_skill\\`, the \\`name\\` is ONLY the identifier before the tag** — e.g. \\`run_skill({ name: \"explore\", arguments: \"...\" })\\`, NOT \\`\"[🧬 subagent] explore\"\\` and NOT \\`\"explore [🧬 subagent]\"\\`. The tag is display sugar; the name argument is just the bare identifier.\n\nTwo built-ins ship by default:\n- **explore** \\`[🧬 subagent]\\` — read-only investigation across the codebase. Use when the user says things like \"find all places that...\", \"how does X work across the project\", \"survey the code for Y\". Pass \\`arguments\\` describing the concrete question.\n- **research** \\`[🧬 subagent]\\` — combines web search + code reading. Use for \"is X supported by lib Y\", \"what's the canonical way to Z\", \"compare our impl to the spec\".\n\nWhen to delegate (call \\`run_skill\\` with a subagent skill):\n- The task would otherwise need >5 file reads or searches.\n- You only need the conclusion, not the exploration trail.\n- The work is self-contained (you can describe it in one paragraph).\n\nWhen NOT to delegate:\n- Direct, narrow questions answerable in 1-2 tool calls — just do them.\n- Anything where you need to track intermediate results yourself (planning, multi-step edits).\n- Anything that requires user interaction (subagents can't submit plans or ask you for clarification).\n\nAlways pass a clear, self-contained \\`arguments\\` — that text is the **only** context the subagent gets.\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\nReasonix runs an **edit gate**. The user's current mode (\\`review\\` or \\`auto\\`) decides what happens to your writes; you DO NOT see which mode is active, and you SHOULD NOT ask. Write the same way in both cases.\n\n- In \\`auto\\` mode \\`edit_file\\` / \\`write_file\\` calls land on disk immediately with an undo window — you'll get the normal \"edit blocks: 1/1 applied\" style response.\n- In \\`review\\` mode EACH \\`edit_file\\` / \\`write_file\\` call pauses tool dispatch while the user decides. You'll get one of these responses:\n - \\`\"edit blocks: 1/1 applied\"\\` — user approved it. Continue as normal.\n - \\`\"User rejected this edit to <path>. Don't retry the same SEARCH/REPLACE…\"\\` — user said no to THIS specific edit. Do NOT re-emit the same block, do NOT switch tools to sneak it past the gate (write_file → edit_file, or text-form SEARCH/REPLACE). Either take a clearly different approach or stop and ask the user what they want instead.\n - Text-form SEARCH/REPLACE blocks in your assistant reply queue for end-of-turn /apply — same \"don't retry on rejection\" rule.\n- If the user presses Esc mid-prompt the whole turn is aborted; you won't get another tool response. Don't keep spamming tool calls after an abort.\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- For multi-site changes — same file or across files — prefer \\`multi_edit\\` over N \\`edit_file\\` calls. Shape: \\`{ edits: [{ path, search, replace }, ...] }\\`. All edits validate before any file is written; any failure → ALL files untouched. Per-file edits run in array order, so a later edit can match text inserted by an earlier one.\n\n# Trust what you already know\n\nBefore exploring the filesystem to answer a factual question, check whether the answer is already in context: the user's current message, earlier turns in this conversation (including prior tool results from \\`remember\\`), and the pinned memory blocks at the top of this prompt. When the user has stated a fact or you have remembered one, it outranks what the files say — don't re-derive from code what the user already told you. Explore when you genuinely don't know.\n\n# Exploration\n\n- Skip dependency, build, and VCS directories unless the user explicitly asks. The pinned .gitignore block (if any, below) is your authoritative denylist.\n- Prefer \\`search_files\\` over \\`list_directory\\` when you know roughly what you're looking for — it saves context and avoids enumerating huge trees. Note: \\`search_files\\` matches file NAMES; for searching file CONTENTS use \\`search_content\\`.\n- Available exploration tools: \\`read_file\\`, \\`list_directory\\`, \\`directory_tree\\`, \\`search_files\\` (filename match), \\`glob\\` (mtime-sorted glob — use for \"what changed lately\", \"all *.ts under src/\"), \\`search_content\\` (content grep — use for \"where is X called\", \"find all references to Y\"; pass \\`context:N\\` for grep -C N around hits), \\`get_file_info\\`. Don't call \\`grep\\` or other tools that aren't in this list — they don't exist as functions.\n\n# Path conventions\n\nTwo different rules depending on which tool:\n\n- **Filesystem tools** (\\`read_file\\`, \\`list_directory\\`, \\`search_files\\`, \\`edit_file\\`, etc.): paths are sandbox-relative. \\`/\\` means the project root, \\`/src/foo.ts\\` means \\`<project>/src/foo.ts\\`. Both relative (\\`src/foo.ts\\`) and POSIX-absolute (\\`/src/foo.ts\\`) forms work.\n- **\\`run_command\\`**: the command runs in a real OS shell with cwd pinned to the project root. Paths inside the shell command are interpreted by THAT shell, not by us. **Never use leading \\`/\\` in run_command arguments** — Windows treats \\`/tests\\` as drive-root \\`F:\\\\tests\\` (non-existent), POSIX shells treat it as filesystem root. Use plain relative paths (\\`tests\\`, \\`./tests\\`, \\`src/loop.ts\\`) instead.\n\n# When the user wants to switch project / working directory\n\nYou can't. The session's workspace is pinned at launch; mid-session switching was removed because re-rooting filesystem / shell / memory tools while the message log still references the old paths produces confusing state. Tell the user to quit and relaunch with the new directory (e.g. \\`cd ../other-project && reasonix code\\`).\n\nDo NOT try to switch via \\`run_command\\` (\\`cd\\`, \\`pushd\\`, etc.) — your tool sandbox is pinned and \\`cd\\` inside one shell call doesn't carry to the next.\n\n# Foreground vs. background commands\n\nYou have TWO tools for running shell commands, and picking the right one is non-negotiable:\n\n- \\`run_command\\` — blocks until the process exits. Use for: **tests, builds, lints, typechecks, git operations, one-shot scripts**. Anything that naturally returns in under a minute.\n- \\`run_background\\` — spawns and detaches after a brief startup window. Use for: **dev servers, watchers, any command with \"dev\" / \"serve\" / \"watch\" / \"start\" in the name**. Examples: \\`npm run dev\\`, \\`pnpm dev\\`, \\`yarn start\\`, \\`vite\\`, \\`next dev\\`, \\`uvicorn app:app --reload\\`, \\`flask run\\`, \\`python -m http.server\\`, \\`cargo watch\\`, \\`tsc --watch\\`, \\`webpack serve\\`.\n\n**Never use run_command for a dev server.** It will block for 60s, time out, and the user will see a frozen tool call while the server was actually running fine. Always \\`run_background\\`, then \\`job_output\\` to peek at the logs when you need to verify something.\n\nAfter \\`run_background\\`, tools available to you:\n- \\`job_output(jobId, tailLines?)\\` — read recent logs to verify startup / debug errors.\n- \\`wait_for_job(jobId, timeoutMs?)\\` — block until the job exits or emits new output. Prefer this over repeating identical \\`job_output\\` calls while you're intentionally waiting.\n- \\`list_jobs\\` — see every job this session (running + exited).\n- \\`stop_job(jobId)\\` — SIGTERM → SIGKILL after grace. Stop before switching port / config.\n\nDon't re-start an already-running dev server — call \\`list_jobs\\` first when in doubt.\n\n# Scope discipline on \"run it\" / \"start it\" requests\n\nWhen the user's request is to **run / start / launch / serve / boot up** something, your job is ONLY:\n\n1. Start it (\\`run_background\\` for dev servers, \\`run_command\\` for one-shots).\n2. Verify it came up (read a ready signal via \\`job_output\\`, or fetch the URL with \\`web_fetch\\` if they want you to confirm).\n3. Report what's running, where (URL / port / pid), and STOP.\n\nDo NOT, in the same turn:\n- Run \\`tsc\\` / type-checkers / linters unless the user asked for it.\n- Scan for bugs to \"proactively\" fix. The page rendering is success.\n- Clean up unused imports, dead code, or refactor \"while you're here.\"\n- Edit files to improve anything the user didn't mention.\n\nIf you notice an obvious issue, MENTION it in one sentence and wait for the user to say \"fix it.\" The cost of over-eagerness is real: you burn tokens, make surprise edits the user didn't want, and chain into cascading \"fix the new error I just introduced\" loops. The storm-breaker will cut you off, but the user still sees the mess.\n\n\"It works\" is the end state. Resist the urge to polish.\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 / read / search), do it with tool calls before writing any prose — silence while exploring is fine.\n\n${ESCALATION_CONTRACT}\n\n${TUI_FORMATTING_RULES}\n`;\n\n/** Stack order (stable for cache prefix): base → REASONIX.md → global → project → .gitignore. */\nconst SEMANTIC_SEARCH_ROUTING = `\n\n# Search routing\n\nYou have BOTH \\`semantic_search\\` (vector index) and \\`search_content\\` (literal grep).\n\n- **Descriptive queries** (\"where do we handle X\", \"which file owns Y\", \"how does Z work\", \"find the logic that does …\", \"the code responsible for …\") → call \\`semantic_search\\` FIRST. It indexes the project by meaning, so it finds the right file even when your phrasing shares no tokens with the code.\n- **Exact-token queries** (a specific identifier, regex, or \"find every call to foo\") → call \\`search_content\\`.\n\nIf \\`semantic_search\\` returns nothing useful (low scores, off-topic), THEN fall back to \\`search_content\\`. Don't go the other way — grepping a paraphrased question wastes turns.`;\n\nexport interface CodeSystemPromptOptions {\n /** True when semantic_search is registered for this run. Adds an\n * explicit routing fragment so the model picks it for intent-style\n * queries instead of defaulting to grep. */\n hasSemanticSearch?: boolean;\n /** Inline string appended after the generated code system prompt.\n * Preserves the default prompt — this is append-only, not a replacement. */\n systemAppend?: string;\n /** UTF-8 file contents appended after the generated code system prompt.\n * Preserves the default prompt — this is append-only, not a replacement. */\n systemAppendFile?: string;\n}\n\nexport function codeSystemPrompt(rootDir: string, opts: CodeSystemPromptOptions = {}): string {\n const base = opts.hasSemanticSearch\n ? `${CODE_SYSTEM_PROMPT}${SEMANTIC_SEARCH_ROUTING}`\n : CODE_SYSTEM_PROMPT;\n const withMemory = applyMemoryStack(base, rootDir);\n const gitignorePath = join(rootDir, \".gitignore\");\n let result = withMemory;\n if (existsSync(gitignorePath)) {\n let content: string | undefined;\n try {\n content = readFileSync(gitignorePath, \"utf8\");\n } catch {}\n if (content !== undefined) {\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 result = `${result}\\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 }\n const appendParts = [opts.systemAppend, opts.systemAppendFile].filter(Boolean);\n if (appendParts.length > 0) {\n result = `${result}\\n\\n# User System Append\\n\\n${appendParts.join(\"\\n\\n\")}`;\n }\n return result;\n}\n","/** User-private memory pinned into the immutable prefix; distinct from committable REASONIX.md. */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { applySkillsIndex } from \"../skills.js\";\nimport { applyProjectMemory, memoryEnabled } from \"./project.js\";\n\nexport const USER_MEMORY_DIR = \"memory\";\nexport const MEMORY_INDEX_FILE = \"MEMORY.md\";\n/** Cap on the index file content loaded into the prefix, per scope. */\nexport const MEMORY_INDEX_MAX_CHARS = 4000;\n\nexport type MemoryType = \"user\" | \"feedback\" | \"project\" | \"reference\";\nexport type MemoryScope = \"global\" | \"project\";\n\nexport interface MemoryEntry {\n name: string;\n type: MemoryType;\n scope: MemoryScope;\n description: string;\n body: string;\n /** ISO date string (YYYY-MM-DD). */\n createdAt: string;\n}\n\nexport interface MemoryStoreOptions {\n /** Override `~/.reasonix` — tests set this to a tmpdir. */\n homeDir?: string;\n /** Absolute sandbox root. Required to use `scope: \"project\"`. */\n projectRoot?: string;\n}\n\nexport interface WriteInput {\n name: string;\n type: MemoryType;\n scope: MemoryScope;\n description: string;\n body: string;\n}\n\nconst VALID_NAME = /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]{1,38}[a-zA-Z0-9]$/;\n\n/** Throws on path-injection (../, /, leading dot). Allowed: 3-40 chars, alnum/_/-, interior `.`. */\nexport function sanitizeMemoryName(raw: string): string {\n const trimmed = String(raw ?? \"\").trim();\n if (!VALID_NAME.test(trimmed)) {\n throw new Error(\n `invalid memory name: ${JSON.stringify(raw)} — must be 3-40 chars, alnum/_/-, no path separators`,\n );\n }\n return trimmed;\n}\n\n/** Stable 16-hex-char hash of an absolute sandbox root path. */\nexport function projectHash(rootDir: string): string {\n const abs = resolve(rootDir);\n return createHash(\"sha1\").update(abs).digest(\"hex\").slice(0, 16);\n}\n\nfunction scopeDir(opts: { homeDir: string; scope: MemoryScope; projectRoot?: string }): string {\n if (opts.scope === \"global\") {\n return join(opts.homeDir, USER_MEMORY_DIR, \"global\");\n }\n if (!opts.projectRoot) {\n throw new Error(\"scope=project requires a projectRoot on MemoryStore\");\n }\n return join(opts.homeDir, USER_MEMORY_DIR, projectHash(opts.projectRoot));\n}\n\nfunction ensureDir(p: string): void {\n if (!existsSync(p)) mkdirSync(p, { recursive: true });\n}\n\nfunction parseFrontmatter(raw: string): { data: Record<string, string>; body: string } {\n const lines = raw.split(/\\r?\\n/);\n if (lines[0] !== \"---\") return { data: {}, body: raw };\n const end = lines.indexOf(\"---\", 1);\n if (end < 0) return { data: {}, body: raw };\n const data: Record<string, string> = {};\n for (let i = 1; i < end; i++) {\n const line = lines[i];\n if (!line) continue;\n const m = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/);\n if (m?.[1]) data[m[1]] = (m[2] ?? \"\").trim();\n }\n return {\n data,\n body: lines\n .slice(end + 1)\n .join(\"\\n\")\n .replace(/^\\n+/, \"\"),\n };\n}\n\nfunction formatFrontmatter(e: WriteInput & { createdAt: string }): string {\n return [\n \"---\",\n `name: ${e.name}`,\n `description: ${e.description.replace(/\\n/g, \" \")}`,\n `type: ${e.type}`,\n `scope: ${e.scope}`,\n `created: ${e.createdAt}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction todayIso(): string {\n const d = new Date();\n return d.toISOString().slice(0, 10);\n}\n\nfunction indexLine(e: Pick<MemoryEntry, \"name\" | \"description\">): string {\n const safeDesc = e.description.replace(/\\n/g, \" \").trim();\n const max = 130 - e.name.length;\n const clipped = safeDesc.length > max ? `${safeDesc.slice(0, Math.max(1, max - 1))}…` : safeDesc;\n return `- [${e.name}](${e.name}.md) — ${clipped}`;\n}\n\nexport class MemoryStore {\n private readonly homeDir: string;\n private readonly projectRoot: string | undefined;\n\n constructor(opts: MemoryStoreOptions = {}) {\n this.homeDir = opts.homeDir ?? join(homedir(), \".reasonix\");\n this.projectRoot = opts.projectRoot ? resolve(opts.projectRoot) : undefined;\n }\n\n /** Directory this store writes `scope` files into, creating it if needed. */\n dir(scope: MemoryScope): string {\n const d = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });\n ensureDir(d);\n return d;\n }\n\n /** Absolute path to a memory file (no existence check). */\n pathFor(scope: MemoryScope, name: string): string {\n return join(this.dir(scope), `${sanitizeMemoryName(name)}.md`);\n }\n\n /** True iff this store is configured with a project scope available. */\n hasProjectScope(): boolean {\n return this.projectRoot !== undefined;\n }\n\n loadIndex(\n scope: MemoryScope,\n ): { content: string; originalChars: number; truncated: boolean } | null {\n if (scope === \"project\" && !this.projectRoot) return null;\n const file = join(\n scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot }),\n MEMORY_INDEX_FILE,\n );\n if (!existsSync(file)) return null;\n let raw: string;\n try {\n raw = readFileSync(file, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const originalChars = trimmed.length;\n const truncated = originalChars > MEMORY_INDEX_MAX_CHARS;\n const content = truncated\n ? `${trimmed.slice(0, MEMORY_INDEX_MAX_CHARS)}\\n… (truncated ${originalChars - MEMORY_INDEX_MAX_CHARS} chars)`\n : trimmed;\n return { content, originalChars, truncated };\n }\n\n /** Read one memory file's body (frontmatter stripped). Throws if missing. */\n read(scope: MemoryScope, name: string): MemoryEntry {\n const file = this.pathFor(scope, name);\n if (!existsSync(file)) {\n throw new Error(`memory not found: scope=${scope} name=${name}`);\n }\n const raw = readFileSync(file, \"utf8\");\n const { data, body } = parseFrontmatter(raw);\n return {\n name: data.name ?? name,\n type: (data.type as MemoryType) ?? \"project\",\n scope: (data.scope as MemoryScope) ?? scope,\n description: data.description ?? \"\",\n body: body.trim(),\n createdAt: data.created ?? \"\",\n };\n }\n\n /** Skips malformed files — index stays queryable even if one file is hand-edited into nonsense. */\n list(): MemoryEntry[] {\n const out: MemoryEntry[] = [];\n const scopes: MemoryScope[] = this.projectRoot ? [\"global\", \"project\"] : [\"global\"];\n for (const scope of scopes) {\n const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });\n if (!existsSync(dir)) continue;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry === MEMORY_INDEX_FILE) continue;\n if (!entry.endsWith(\".md\")) continue;\n const name = entry.slice(0, -3);\n try {\n out.push(this.read(scope, name));\n } catch {\n // malformed file — skip rather than fail the whole list\n }\n }\n }\n return out;\n }\n\n write(input: WriteInput): string {\n if (input.scope === \"project\" && !this.projectRoot) {\n throw new Error(\"cannot write project-scoped memory: no projectRoot configured\");\n }\n const name = sanitizeMemoryName(input.name);\n const desc = String(input.description ?? \"\").trim();\n if (!desc) throw new Error(\"memory description cannot be empty\");\n const body = String(input.body ?? \"\").trim();\n if (!body) throw new Error(\"memory body cannot be empty\");\n const entry: WriteInput & { createdAt: string } = {\n ...input,\n name,\n description: desc,\n body,\n createdAt: todayIso(),\n };\n const dir = this.dir(input.scope);\n const file = join(dir, `${name}.md`);\n const content = `${formatFrontmatter(entry)}${body}\\n`;\n writeFileSync(file, content, \"utf8\");\n this.regenerateIndex(input.scope);\n return file;\n }\n\n /** Delete one memory + its index line. No-op if the file is already gone. */\n delete(scope: MemoryScope, rawName: string): boolean {\n if (scope === \"project\" && !this.projectRoot) {\n throw new Error(\"cannot delete project-scoped memory: no projectRoot configured\");\n }\n const file = this.pathFor(scope, rawName);\n if (!existsSync(file)) return false;\n unlinkSync(file);\n this.regenerateIndex(scope);\n return true;\n }\n\n /** Sorted by name — same file set must produce byte-identical MEMORY.md for stable prefix hashing. */\n private regenerateIndex(scope: MemoryScope): void {\n const dir = scopeDir({ homeDir: this.homeDir, scope, projectRoot: this.projectRoot });\n if (!existsSync(dir)) return;\n let files: string[];\n try {\n files = readdirSync(dir);\n } catch {\n return;\n }\n const mdFiles = files\n .filter((f) => f !== MEMORY_INDEX_FILE && f.endsWith(\".md\"))\n .sort((a, b) => a.localeCompare(b));\n const indexPath = join(dir, MEMORY_INDEX_FILE);\n if (mdFiles.length === 0) {\n if (existsSync(indexPath)) unlinkSync(indexPath);\n return;\n }\n const lines: string[] = [];\n for (const f of mdFiles) {\n const name = f.slice(0, -3);\n try {\n const entry = this.read(scope, name);\n lines.push(indexLine({ name: entry.name || name, description: entry.description }));\n } catch {\n // Malformed: still surface it in the index so the user notices.\n lines.push(`- [${name}](${name}.md) — (malformed, check frontmatter)`);\n }\n }\n writeFileSync(indexPath, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n }\n}\n\n/** Freeform `#g` destination, distinct from MEMORY.md's curated index of named files. */\nexport function readGlobalReasonixMemory(\n homeDir: string = join(homedir(), \".reasonix\"),\n): { path: string; content: string; originalChars: number; truncated: boolean } | null {\n const path = join(homeDir, \"REASONIX.md\");\n if (!existsSync(path)) return null;\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const originalChars = trimmed.length;\n // Reuse the project-memory cap so both freeform files have the same\n // headroom (8000 chars ≈ 2k tokens). They serve the same purpose at\n // different scopes.\n const truncated = originalChars > 8000;\n const content = truncated\n ? `${trimmed.slice(0, 8000)}\\n… (truncated ${originalChars - 8000} chars)`\n : trimmed;\n return { path, content, originalChars, truncated };\n}\n\nexport function applyGlobalReasonixMemory(basePrompt: string, homeDir?: string): string {\n if (!memoryEnabled()) return basePrompt;\n const dir = homeDir ?? join(homedir(), \".reasonix\");\n const mem = readGlobalReasonixMemory(dir);\n if (!mem) return basePrompt;\n return [\n basePrompt,\n \"\",\n \"# Global memory (~/.reasonix/REASONIX.md)\",\n \"\",\n \"Cross-project notes the user pinned via the `#g` prompt prefix. Treat as authoritative — same level of trust as project memory.\",\n \"\",\n \"```\",\n mem.content,\n \"```\",\n ].join(\"\\n\");\n}\n\n/** Empty index → omit the whole block (otherwise we'd add bytes to the prefix hash for nothing). */\nexport function applyUserMemory(\n basePrompt: string,\n opts: { homeDir?: string; projectRoot?: string } = {},\n): string {\n if (!memoryEnabled()) return basePrompt;\n const store = new MemoryStore(opts);\n const global = store.loadIndex(\"global\");\n const project = store.hasProjectScope() ? store.loadIndex(\"project\") : null;\n if (!global && !project) return basePrompt;\n const parts: string[] = [basePrompt];\n if (global) {\n parts.push(\n \"\",\n \"# User memory — global (~/.reasonix/memory/global/MEMORY.md)\",\n \"\",\n \"Cross-project facts and preferences the user has told you in prior sessions. TREAT AS AUTHORITATIVE — don't re-verify via filesystem or web. One-liners index detail files; call `recall_memory` for full bodies only when the one-liner isn't enough.\",\n \"\",\n \"```\",\n global.content,\n \"```\",\n );\n }\n if (project) {\n parts.push(\n \"\",\n \"# User memory — this project\",\n \"\",\n \"Per-project facts the user established in prior sessions (not committed to the repo). TREAT AS AUTHORITATIVE. Same recall pattern as global memory.\",\n \"\",\n \"```\",\n project.content,\n \"```\",\n );\n }\n return parts.join(\"\\n\");\n}\n\nexport function applyMemoryStack(basePrompt: string, rootDir: string): string {\n const withProject = applyProjectMemory(basePrompt, rootDir);\n const withGlobal = applyGlobalReasonixMemory(withProject);\n const withMemory = applyUserMemory(withGlobal, { projectRoot: rootDir });\n return applySkillsIndex(withMemory, { projectRoot: rootDir });\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","join","existsSync","readFileSync"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/code.tsx","../../src/tools/scaffold.ts"],"sourcesContent":["/**\n * `reasonix code [dir]` — opinionated wrapper around `reasonix chat` for\n * code-editing workflows.\n *\n * What it does differently from plain chat:\n * - Registers native filesystem tools rooted at the given directory\n * (CWD by default). No subprocess, no `npx install` step, R1-\n * friendly schemas. Replaced the old `@modelcontextprotocol/server-filesystem`\n * subprocess in 0.4.9 because its `edit_file` argv shape was the\n * biggest driver of R1 DSML hallucinations.\n * - Uses a coding-focused system prompt (src/code/prompt.ts) that\n * teaches the model to propose edits as SEARCH/REPLACE blocks.\n * - Defaults to the `smart` preset (reasoner + harvest) because\n * coding tasks pay back R1 thinking.\n * - Scopes its session to the directory so projects don't share\n * conversation history.\n * - Hooks `codeMode` into the TUI so assistant replies get parsed\n * for SEARCH/REPLACE blocks and applied on disk after each turn.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { loadEditMode, loadProjectShellAllowed, readConfig } from \"../../config.js\";\nimport { bootstrapSemanticSearchInCodeMode } from \"../../index/semantic/tool.js\";\nimport { sanitizeName } from \"../../memory/session.js\";\nimport { ToolRegistry } from \"../../tools.js\";\nimport { registerChoiceTool } from \"../../tools/choice.js\";\nimport { registerFilesystemTools } from \"../../tools/filesystem.js\";\nimport { JobRegistry } from \"../../tools/jobs.js\";\nimport { registerMemoryTools } from \"../../tools/memory.js\";\nimport { registerPlanTool } from \"../../tools/plan.js\";\nimport { registerScaffoldTools } from \"../../tools/scaffold.js\";\nimport { registerShellTools } from \"../../tools/shell.js\";\nimport { registerTodoTool } from \"../../tools/todo.js\";\nimport { markPhase } from \"../startup-profile.js\";\nimport { chatCommand } from \"./chat.js\";\n\nexport interface CodeOptions {\n /** Directory to root the filesystem tools at. Defaults to process.cwd(). */\n dir?: string;\n /** Override the default `smart` model. */\n model?: string;\n /** Disable session persistence. */\n noSession?: boolean;\n /** Transcript file for replay/diff. */\n transcript?: string;\n /** Skip the session picker — always resume prior messages. */\n forceResume?: boolean;\n /** Skip the session picker — always wipe prior messages and start fresh. */\n forceNew?: boolean;\n /**\n * Soft USD spend cap. Off by default. Same semantics as `chat`:\n * warns at 80%, refuses next turn at 100%. Mid-session adjustable\n * via `/budget <usd>` slash command.\n */\n budgetUsd?: number;\n /** Suppress the auto-launched embedded web dashboard. */\n noDashboard?: boolean;\n /** Inline string appended to the code system prompt after the generated base prompt. */\n systemAppend?: string;\n /** Path to a UTF-8 text file whose contents are appended to the code system prompt. */\n systemAppendFile?: string;\n /** Default true. Pass false (CLI: `--no-alt-screen`) to keep chat output in shell scrollback. */\n altScreen?: boolean;\n /** Default true. Pass false (CLI: `--no-mouse`) to keep terminal-native drag-select unmodified. */\n mouse?: boolean;\n}\n\nexport async function codeCommand(opts: CodeOptions = {}): Promise<void> {\n markPhase(\"code_command_enter\");\n const { codeSystemPrompt } = await import(\"../../code/prompt.js\");\n const rootDir = resolve(opts.dir ?? process.cwd());\n // Per-directory session so switching projects doesn't mix histories.\n // `code-<sanitized-basename>` fits the session name rules without\n // truncating most project names.\n const session = opts.noSession ? undefined : `code-${sanitizeName(basename(rootDir))}`;\n\n // Native filesystem tools. No subprocess, ~50-200 ms faster per call\n // than the MCP server was, and `edit_file` takes a flat SEARCH/REPLACE\n // shape instead of the `string=\"false\"` JSON-in-string array that\n // triggered R1's DSML hallucinations all through 0.4.x.\n const tools = new ToolRegistry();\n // Background-process registry shared between the shell tools and the\n // TUI's /jobs + /kill slashes + exit cleanup. One per `reasonix code`\n // run — orphan prevention on SIGINT / process exit kills everything\n // it owns, so dev servers don't outlive the Reasonix process.\n const jobs = new JobRegistry();\n // Bundled re-registration so `/cwd <path>` can swap every rootDir-\n // dependent tool atomically. ToolRegistry.register is keyed by name\n // and overwrites in-place, so re-calling these against the existing\n // registry replaces the closures cleanly without disturbing tool\n // specs (names/descriptions/params don't reference rootDir, so the\n // prefix cache survives).\n const registerRootedTools = (root: string): void => {\n registerFilesystemTools(tools, { rootDir: root });\n registerShellTools(tools, {\n rootDir: root,\n // Per-project \"always allow\" list persisted from prior ShellConfirm\n // choices; merged on top of the built-in allowlist in shell.ts.\n // GETTER form — re-read every dispatch so a prefix the user adds\n // via ShellConfirm mid-session takes effect on the next shell call\n // instead of waiting for `/new` or a relaunch.\n extraAllowed: () => loadProjectShellAllowed(root),\n // `yolo` edit-mode disables shell confirmations entirely. Re-read\n // from config on each dispatch so /mode yolo (or Shift+Tab cycling\n // through to it) flips the gate live without forcing a relaunch.\n allowAll: () => loadEditMode() === \"yolo\",\n jobs,\n });\n // `remember` / `forget` / `recall_memory` — cross-session user memory.\n // Project scope hashes off rootDir so switching projects gets a fresh\n // per-project memory store; the global scope is shared across runs.\n registerMemoryTools(tools, { projectRoot: root });\n };\n // Async tail to `registerRootedTools`. Kept separate because the FS /\n // shell / memory re-registration above is sync and must happen before\n // the next tool dispatch, while semantic-index probing reads disk and\n // can race ahead in the background. On `/cwd`, App.tsx fires this\n // after the sync swap and surfaces the result via postInfo.\n const reBootstrapSemantic = async (root: string): Promise<{ enabled: boolean }> => {\n const result = await bootstrapSemanticSearchInCodeMode(tools, root);\n if (!result.enabled) tools.unregister(\"semantic_search\");\n return result;\n };\n registerRootedTools(rootDir);\n // `submit_plan` is always in the spec list so the prefix cache stays\n // stable across plan-mode toggles (Pillar 1). The tool itself is a\n // no-op outside plan mode and throws `PlanProposedError` when the\n // user has `/plan`-enabled the session.\n registerPlanTool(tools);\n // `ask_choice` — branching primitive. Independent of plan mode: the\n // model uses it to put a 2–4 way choice in front of the user\n // (strategy, style, library pick) without trying to squeeze the\n // menu into a submit_plan body. Keeping it always-registered\n // preserves the prefix cache across plan-mode toggles.\n registerChoiceTool(tools);\n // `todo_write` — lightweight in-session task tracker, no approval gate.\n // Independent of plan mode (readOnly=true so it stays callable in /plan).\n registerTodoTool(tools);\n // `create_skill` / `add_mcp_server` — let the model scaffold from chat.\n // Both writes go through the same paths the wizard / `/skill new` use,\n // so the on-disk shape stays one source of truth. New servers take\n // effect on next launch (no live client churn).\n registerScaffoldTools(tools, { projectRoot: rootDir });\n // `run_skill` is intentionally NOT registered here — App.tsx wires it\n // up with the subagent runner attached, so `runAs: subagent` skills\n // can spawn isolated child loops. Doing it here would mean the App's\n // re-registration would shadow the no-runner version, which works\n // (last write wins) but obscures the wiring.\n\n // Bootstrap semantic_search. Silent: registers the tool when an\n // on-disk index already exists, skips entirely otherwise. Setup\n // happens via the explicit `reasonix index` command — never\n // by surprise on launch.\n markPhase(\"semantic_bootstrap_start\");\n const semantic = await reBootstrapSemantic(rootDir);\n markPhase(\n semantic.enabled ? \"semantic_bootstrap_done_enabled\" : \"semantic_bootstrap_done_skipped\",\n );\n\n process.stderr.write(\n `▸ reasonix code: rooted at ${rootDir}, session \"${session ?? \"(ephemeral)\"}\" · ${tools.size} native tool(s)${\n semantic.enabled ? \" · semantic_search on\" : \"\"\n }\\n`,\n );\n\n // Belt-and-suspenders cleanup: even though spawn(detached:false)\n // should tie child processes to the parent's lifetime, Windows cmd.exe\n // wrappers occasionally leak. We DON'T install SIGINT/SIGTERM\n // handlers here — that overrode Node's default \"exit on Ctrl+C\" with\n // a silent no-op, which made Ctrl+C feel broken in the TUI. App.tsx\n // owns the SIGINT path now (it shows the quit-armed banner and calls\n // exit() on confirmation); this 'exit' hook just guarantees the job\n // registry is drained on the way out, regardless of which exit path\n // fired.\n process.once(\"exit\", () => {\n void jobs.shutdown();\n });\n\n let systemAppendFileContents: string | undefined;\n if (opts.systemAppend !== undefined && opts.systemAppend.trim().length === 0) {\n process.stderr.write(\"--system-append is empty — no prompt text will be appended\\n\");\n }\n if (opts.systemAppendFile) {\n const filePath = resolve(opts.systemAppendFile);\n try {\n systemAppendFileContents = readFileSync(filePath, \"utf8\");\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n process.stderr.write(\n `Error: cannot read --system-append-file \"${filePath}\": ${e.code ? `[${e.code}] ` : \"\"}${e.message}\\n`,\n );\n process.exit(1);\n }\n }\n\n await chatCommand({\n model: opts.model ?? \"deepseek-v4-flash\",\n budgetUsd: opts.budgetUsd,\n system: codeSystemPrompt(rootDir, {\n hasSemanticSearch: semantic.enabled,\n systemAppend: opts.systemAppend,\n systemAppendFile: systemAppendFileContents,\n }),\n transcript: opts.transcript,\n session,\n seedTools: tools,\n codeMode: {\n rootDir,\n jobs,\n reregisterTools: registerRootedTools,\n reBootstrapSemantic,\n },\n mcp: readConfig().mcp,\n forceResume: opts.forceResume,\n forceNew: opts.forceNew,\n noDashboard: opts.noDashboard,\n altScreen: opts.altScreen,\n mouse: opts.mouse,\n });\n}\n","/** Agent-facing tools for scaffolding skills + MCP servers from chat. Persists via the same paths the wizard / `/skill new` use. */\n\nimport { defaultConfigPath, readConfig, writeConfig } from \"../config.js\";\nimport { MCP_CATALOG } from \"../mcp/catalog.js\";\nimport { preflightStdioSpec } from \"../mcp/preflight.js\";\nimport { type McpSpec, parseMcpSpec } from \"../mcp/spec.js\";\nimport { SkillStore } from \"../skills.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\nexport interface ScaffoldToolsOptions {\n homeDir?: string;\n projectRoot?: string;\n /** Override config path — tests point this at a tmp file. */\n configPath?: string;\n}\n\nconst VALID_SKILL_NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;\nconst VALID_SERVER_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$/;\nconst VALID_TOOL_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;\n\nexport function registerScaffoldTools(\n registry: ToolRegistry,\n opts: ScaffoldToolsOptions = {},\n): ToolRegistry {\n const configPath = opts.configPath ?? defaultConfigPath();\n\n registry.register({\n name: \"create_skill\",\n description:\n 'Scaffold a new skill (`SKILL.md` in `.reasonix/skills/<name>.md`) the user can invoke later via `/skill <name>`. Use this when the user asks the agent to add a playbook, automate a recurring workflow, or capture a multi-step recipe as a named skill. The frontmatter is filled from the structured args here (description / allowed_tools / run_as / model) so the model never has to write raw YAML. Use `run_as: \"subagent\"` for read-and-synthesize playbooks where only the final answer should come back; default `\"inline\"` appends the body to the parent log so the user sees the steps. Refuses to overwrite an existing skill — pick a different name or ask the user to delete the old one.',\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Skill identifier — letters/digits/`_`/`-`/`.`, 1–64 chars. Becomes the `name` frontmatter and the `<name>.md` filename.\",\n },\n description: {\n type: \"string\",\n description:\n 'One-line summary shown in the pinned skills index. Lead with the verb (\"Run X and …\") so the parent agent can scan it.',\n },\n body: {\n type: \"string\",\n description:\n \"Markdown body of the skill — the playbook the model follows when invoked. Plain prose + bullets; reference tools by name.\",\n },\n scope: {\n type: \"string\",\n enum: [\"project\", \"global\"],\n description:\n \"`project` = `.reasonix/skills/` under the workspace (default, requires `reasonix code`); `global` = `~/.reasonix/skills/` shared across all repos.\",\n },\n allowed_tools: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Optional whitelist of tool names the subagent registry is scoped to (only meaningful for `run_as: subagent`). Common values: `read_file`, `search_content`, `directory_tree`, `run_command`. Omit to give the subagent the full inherited toolset.\",\n },\n run_as: {\n type: \"string\",\n enum: [\"inline\", \"subagent\"],\n description:\n \"`inline` (default) appends the body to the parent log as a tool result. `subagent` spawns an isolated child loop and only the final answer comes back — use for read-and-synthesize playbooks (explore, research, review).\",\n },\n model: {\n type: \"string\",\n enum: [\"deepseek-v4-flash\", \"deepseek-v4-pro\"],\n description:\n \"Subagent model override (only meaningful for `run_as: subagent`). Default is the same as `spawn_subagent` — `deepseek-v4-flash`. Set to `deepseek-v4-pro` only when the playbook empirically needs the stronger model.\",\n },\n },\n required: [\"name\", \"description\", \"body\"],\n },\n fn: async (args: {\n name?: unknown;\n description?: unknown;\n body?: unknown;\n scope?: unknown;\n allowed_tools?: unknown;\n run_as?: unknown;\n model?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!VALID_SKILL_NAME.test(name)) {\n return JSON.stringify({\n error: `invalid skill name: ${JSON.stringify(name)} — use letters, digits, _, -, .`,\n });\n }\n const description =\n typeof args.description === \"string\" ? args.description.trim().replace(/\\n+/g, \" \") : \"\";\n if (!description) {\n return JSON.stringify({\n error: \"create_skill requires a non-empty 'description'\",\n });\n }\n const body = typeof args.body === \"string\" ? args.body : \"\";\n if (!body.trim()) {\n return JSON.stringify({ error: \"create_skill requires a non-empty 'body'\" });\n }\n const scope: \"project\" | \"global\" =\n args.scope === \"global\" ? \"global\" : opts.projectRoot ? \"project\" : \"global\";\n const runAs: \"inline\" | \"subagent\" = args.run_as === \"subagent\" ? \"subagent\" : \"inline\";\n const allowedTools = parseAllowedTools(args.allowed_tools);\n if (allowedTools && \"error\" in allowedTools) {\n return JSON.stringify({ error: allowedTools.error });\n }\n const model =\n typeof args.model === \"string\" && args.model.startsWith(\"deepseek-\")\n ? args.model\n : undefined;\n\n const content = serializeSkill({\n name,\n description,\n runAs,\n allowedTools: allowedTools ?? undefined,\n model,\n body,\n });\n\n const store = new SkillStore({\n homeDir: opts.homeDir,\n projectRoot: opts.projectRoot,\n });\n const result = store.createWithContent(name, scope, content);\n if (\"error\" in result) {\n return JSON.stringify({ error: result.error });\n }\n return JSON.stringify({\n success: true,\n path: result.path,\n scope,\n name,\n run_as: runAs,\n });\n },\n });\n\n registry.register({\n name: \"add_mcp_server\",\n description:\n 'Register a new MCP server in the user\\'s Reasonix config (`mcp` array). Takes effect on the next session — does NOT spawn the server now. Use stdio for local commands (npx packages, local binaries), `sse` or `streamable-http` for remote endpoints. Pass `from_catalog: \"<name>\"` (e.g. `\"filesystem\"`, `\"memory\"`, `\"github\"`) to auto-fill `command` + `args` from the bundled catalog — the user still has to supply user-args (filesystem: a sandbox dir; github: GITHUB_PERSONAL_ACCESS_TOKEN in env). Refuses to add a server whose name collides with an existing entry.',\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Server name — used as the namespace prefix on every tool the server exposes. Letters/digits/`_`/`-`, must start with a letter or `_`.\",\n },\n transport: {\n type: \"string\",\n enum: [\"stdio\", \"sse\", \"streamable-http\"],\n description:\n \"`stdio` = spawn a local command and pipe MCP over stdin/stdout. `sse` = HTTP+SSE remote. `streamable-http` = Streamable HTTP remote. Required unless `from_catalog` is set.\",\n },\n command: {\n type: \"string\",\n description:\n 'Argv[0] for stdio servers — typically `npx` or a binary path. Required when `transport: \"stdio\"` (and no `from_catalog`).',\n },\n args: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n 'Remaining argv for stdio servers — e.g. `[\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/dir\"]`. The dir at the tail is enforced to exist by the preflight check.',\n },\n url: {\n type: \"string\",\n description:\n \"Endpoint URL for `sse` / `streamable-http` transports. Must be `http://` or `https://`.\",\n },\n from_catalog: {\n type: \"string\",\n description:\n \"Optional shortcut — name out of the bundled catalog (`filesystem`, `memory`, `github`, `puppeteer`, `everything`). When set, fills `command` + `args` from the catalog entry; you still supply `name` (defaults to the catalog name) and any user-args via `args`.\",\n },\n },\n required: [\"name\"],\n },\n fn: async (args: {\n name?: unknown;\n transport?: unknown;\n command?: unknown;\n args?: unknown;\n url?: unknown;\n from_catalog?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!VALID_SERVER_NAME.test(name)) {\n return JSON.stringify({\n error: `invalid server name: ${JSON.stringify(name)} — must match [a-zA-Z_][a-zA-Z0-9_-]*`,\n });\n }\n\n const specStr = buildSpecString({\n name,\n transport: typeof args.transport === \"string\" ? args.transport : undefined,\n command: typeof args.command === \"string\" ? args.command : undefined,\n argv: Array.isArray(args.args)\n ? (args.args.filter((a) => typeof a === \"string\") as string[])\n : undefined,\n url: typeof args.url === \"string\" ? args.url : undefined,\n fromCatalog: typeof args.from_catalog === \"string\" ? args.from_catalog : undefined,\n });\n if (\"error\" in specStr) {\n return JSON.stringify({ error: specStr.error });\n }\n\n let parsed: McpSpec;\n try {\n parsed = parseMcpSpec(specStr.spec);\n } catch (err) {\n return JSON.stringify({ error: (err as Error).message });\n }\n if (parsed.transport === \"stdio\") {\n try {\n preflightStdioSpec(parsed);\n } catch (err) {\n return JSON.stringify({ error: (err as Error).message });\n }\n }\n\n const cfg = readConfig(configPath);\n const existing = cfg.mcp ?? [];\n const collision = existing.find((s) => parseSpecName(s) === name);\n if (collision) {\n return JSON.stringify({\n error: `MCP server ${JSON.stringify(name)} already registered: ${collision}`,\n });\n }\n cfg.mcp = [...existing, specStr.spec];\n writeConfig(cfg, configPath);\n return JSON.stringify({\n success: true,\n name,\n transport: parsed.transport,\n spec: specStr.spec,\n config_path: configPath,\n active_on_next_launch: true,\n });\n },\n });\n\n return registry;\n}\n\ninterface SerializeSkillArgs {\n name: string;\n description: string;\n runAs: \"inline\" | \"subagent\";\n allowedTools?: readonly string[];\n model?: string;\n body: string;\n}\n\nexport function serializeSkill(args: SerializeSkillArgs): string {\n const lines: string[] = [\"---\", `name: ${args.name}`, `description: ${args.description}`];\n if (args.runAs === \"subagent\") {\n lines.push(\"runAs: subagent\");\n }\n if (args.allowedTools && args.allowedTools.length > 0) {\n lines.push(`allowed-tools: ${args.allowedTools.join(\", \")}`);\n }\n if (args.model) {\n lines.push(`model: ${args.model}`);\n }\n lines.push(\"---\", \"\");\n return `${lines.join(\"\\n\")}\\n${args.body.trim()}\\n`;\n}\n\nfunction parseAllowedTools(raw: unknown): readonly string[] | { error: string } | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (!Array.isArray(raw)) {\n return { error: \"'allowed_tools' must be an array of tool-name strings\" };\n }\n const out: string[] = [];\n for (const v of raw) {\n if (typeof v !== \"string\") {\n return { error: \"'allowed_tools' entries must be strings\" };\n }\n const trimmed = v.trim();\n if (!trimmed) continue;\n if (!VALID_TOOL_NAME.test(trimmed)) {\n return { error: `invalid tool name in allowed_tools: ${JSON.stringify(trimmed)}` };\n }\n out.push(trimmed);\n }\n return out.length > 0 ? out : undefined;\n}\n\ninterface BuildSpecInput {\n name: string;\n transport?: string;\n command?: string;\n argv?: string[];\n url?: string;\n fromCatalog?: string;\n}\n\nfunction buildSpecString(input: BuildSpecInput): { spec: string } | { error: string } {\n if (input.fromCatalog) {\n const entry = MCP_CATALOG.find((e) => e.name === input.fromCatalog);\n if (!entry) {\n const known = MCP_CATALOG.map((e) => e.name).join(\", \");\n return {\n error: `unknown catalog entry: ${JSON.stringify(input.fromCatalog)} — known: ${known}`,\n };\n }\n const userArgs = input.argv ?? [];\n if (entry.userArgs && userArgs.length === 0) {\n return {\n error: `catalog entry \"${entry.name}\" needs ${entry.userArgs} — pass it via the 'args' parameter`,\n };\n }\n const tail = userArgs.map(quoteIfNeeded).join(\" \");\n const body = `npx -y ${entry.package}${tail ? ` ${tail}` : \"\"}`;\n return { spec: `${input.name}=${body}` };\n }\n\n const transport = input.transport;\n if (!transport) {\n return { error: \"add_mcp_server requires 'transport' (or 'from_catalog')\" };\n }\n if (transport === \"stdio\") {\n if (!input.command || !input.command.trim()) {\n return { error: \"stdio transport requires 'command'\" };\n }\n const tail = (input.argv ?? []).map(quoteIfNeeded).join(\" \");\n const body = `${quoteIfNeeded(input.command.trim())}${tail ? ` ${tail}` : \"\"}`;\n return { spec: `${input.name}=${body}` };\n }\n if (transport === \"sse\" || transport === \"streamable-http\") {\n if (!input.url || !/^https?:\\/\\//i.test(input.url)) {\n return { error: `${transport} transport requires an http(s):// 'url'` };\n }\n const prefix = transport === \"streamable-http\" ? \"streamable+\" : \"\";\n return { spec: `${input.name}=${prefix}${input.url.trim()}` };\n }\n return { error: `unknown transport: ${JSON.stringify(transport)}` };\n}\n\nfunction parseSpecName(spec: string): string | null {\n const m = spec.trim().match(/^([a-zA-Z_][a-zA-Z0-9_-]*)=/);\n return m ? (m[1] ?? null) : null;\n}\n\nfunction quoteIfNeeded(s: string): string {\n return /\\s|\"/.test(s) ? `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"` : s;\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|