文件最后提交记录最后更新时间
feat(code-query): tree-sitter get_symbols + find_in_code (TS/JS/Python/Go/Rust/Java) (#1387) * feat(code-query): tree-sitter get_symbols + find_in_code tools for TS/TSX/JS Two grammar-aware tools for single-file code structure queries, scoped per the #556 RFC's "narrowly-scoped one-tier pilot" constraint. - get_symbols: outlines top-level + nested symbols (function, class, method, interface, type, enum, namespace) with 1-based positions - find_in_code: identifier search with role classification (call / definition / reference), AST-filtered so comments + string literals do not match; handles new X() and obj.X() as calls on X Bundles tree-sitter-typescript + tree-sitter-javascript wasm from the official npm packages (~3.4 MB in dist/grammars/). Non-TS/JS files return an "unsupported; use search_content" hint. Within-file only — cross-file resolution stays out of scope per the RFC. Closes #556 * feat(code-query): extend to Python / Go / Rust / Java Adds 4 grammars beyond the TS/TSX/JS/JSX pilot: tree-sitter-python, tree-sitter-go, tree-sitter-rust, tree-sitter-java. Total bundled grammar wasm now 5.5 MB. Per-language symbol queries land function / class / method / interface / type / enum / namespace / property kinds with consistent shape. Methods detected via post-process when a function_definition / function_item sits inside a class, impl, or trait container; Rust impl blocks set the parent name from impl's type field so impl Foo and `impl Trait for Foo` both attribute methods to Foo. find_in_code's classifier learns each language's call shape: - Python call, Java method_invocation, object_creation_expression - Go selector_expression, Rust field_expression, Python attribute, JS member_expression — all handled uniformly via field-name lookups so obj.X() is a call on X across languages --------- Co-authored-by: reasonix <reasonix@deepseek.com>9 天前
feat(acp): --transcript flag for headless cost capture (#766) * feat(acp): --transcript flag for headless cost capture Tees raw LoopEvents through writeRecord/recordFromLoopEvent during session/prompt so headless ACP callers can parse usage, cost, and prefixHash without driving the TUI. Reuses the JSONL shape chat and code already emit; zero changes to transcript helpers. Single-session-per-process — mirrors chat/code behavior; the JSONL stays cleanly seekable. Adds tests/fixtures/acp-driver.ndjson as scaffolding for future end-to-end ACP smoke tests, per maintainer ack on #765. Refs: #765 * test(acp): assert fixture sessionId is a placeholder Adversarial review noted that piping acp-driver.ndjson as-is into the binary produces ERR_INVALID_PARAMS "unknown session" with no hint about the substitution requirement. Lock in the placeholder contract so anyone editing the fixture sees the test fail with a clear comment instead of discovering the trap at runtime.16 天前
feat(scene): spawnInputSource — JS adapter for Rust --emit-input (#969) Stage 2 PR-2. spawnInputSource() runs the Rust binary with --emit-input, reads its JSONL stdout, parses each line into a KeyInputEvent, and dispatches to registered onKey handlers. No production callers wire it in yet — that's the next PR. API shape: const source = spawnInputSource(); source.onKey((event) => { ... }); // later: source.close() to signal + await, or source.wait() to // just await natural exit. Two methods, not one, because the use cases differ: - close() sends SIGINT and awaits exit. Production needs this so the child doesn't linger after JS shuts down — the Rust binary reads /dev/tty directly, so there's no stdin pipe to close. - wait() just awaits exit without signaling. Used by tests where the stub finishes naturally; without it, the SIGINT in close() would race against the stub's writes and kill it mid-emit. Line parser is forgiving: - Malformed JSON: skip and keep going. Don't drop later valid events. A Rust panic might emit a stderr trace that bleeds into stdout briefly; one bad byte shouldn't take down the input stream for the rest of the session. - JSON that isn't a key event: skip. Future event kinds (resize, mouse) ride on the same channel; isKeyEvent() narrows. Tests: 6 cases via a Node stub that replays a JSONL fixture file to stdout. Covers ordered delivery, multi-handler dispatch, unsubscribe, malformed-line tolerance, non-key-event filtering, empty-command rejection. The stub stands in for the binary so vitest stays Rust-toolchain-free. Refs #868 #947 Co-authored-by: reasonix <reasonix@deepseek.com>14 天前
feat(scene): spawn the Rust renderer as a child process (#960) JS-side plumbing for the REASONIX_RENDERER=rust runtime switch. spawnRenderer() starts the reasonix-render binary, returns an emit(frame) that writes one JSONL line to the child's stdin and a close() that resolves with the child's exit code. No app integration yet — this is the wire. The flip-the-flag PR that decides between Ink and the spawned Rust process lands once Ink can be mounted to a non-stdout backend, which is its own design problem (Stage 1's mid-cut). Why the test uses a Node stub: - The real binary takes over the terminal (alt screen + raw mode). Running it in a CI process would be hostile to the test runner. - The contract we want to test is the JS-side plumbing: spawn succeeds, frames pipe in order as JSONL, stdin closes cleanly, exit code surfaces, post-close emit is a no-op. None of that needs a real terminal — a Node script that echoes stdin lines to a file is sufficient. - This also keeps tests Rust-toolchain-free. Future CI doesn't need to build the crate just to run the JS suite. The DEFAULT_COMMAND points at cargo run --bin reasonix-render so that future smoke tests / dev usage works without installing the binary; release tooling will swap that to the installed binary path when distribution is wired up. Refs #868 #947 Co-authored-by: reasonix <reasonix@deepseek.com>14 天前