v6.1.0
·
128 commits
to master
since this release
[6.1.0] - 2026-05-25
Added
tokensave tool <name>— schema-driven CLI dispatcher. Every MCP tool is now reachable from the command line through a single dynamic subcommand that introspects each tool's JSON schema and coerces--key valueflags accordingly.tokensave tool(no args) lists tools grouped by category;tokensave tool <name> --helpprints schema-derived parameters. Reserved flags:--json(raw response),--project <path>,--args <json>,-h/--help. Positional args bind to required string properties (e.g.tokensave tool search foo).@filevalues are read from disk for multi-line strings. Replaces seven hand-rolled subcommands (query,context,body,impact,callers,files,affected);queryis kept as an alias for the renamedsearch. New file:src/tool_command.rs(~729 LoC).tokensave_find_exact_symbolMCP tool. Bare-name lookup againstidx_nodes_name— a single O(log n) index probe with no BM25 ranking, no fuzzy match, no qualified-name suffix walk. Use this when the symbol name is already known; usetokensave_searchfor relevance-ranked discovery. ~30–200 µs per lookup vs. ~700 µs for the BM25 path.tokensave_call_chainMCP tool. Finds the shortest directed call chain between two node IDs along outgoingcallsedges only. Newfind_path_directedBFS ingraph/traversal.rs(the existingfind_pathis bidirectional and wrong for "how does A reach B" questions). Bounded bymax_depth(default 8, max 20).tokensave_file_dependentsMCP tool. Lists every indexed file that imports or otherwise depends on the given file. Thin wrapper around the existingTokenSave::get_file_dependentsthat was previously only reachable throughtokensave_affected's test-rollup path.tokensave_replace_symbolMCP tool. Symbol-aware body replacement: resolves a name via exact qualified-name match, narrows to callable kinds on ambiguity, and refuses the edit rather than picking the wrong site if more than one callable matches. Reads the file, splices the symbol'sstart_line..=end_linerange withnew_source, writes back, and reindexes the touched file. Plays the role of token-savior'sreplace_symbol_source.tokensave_insert_at_symbolMCP tool. Inserts content immediately before or after a named symbol's source range — same resolution semantics astokensave_replace_symbol.positionis"before"or"after"(default after). Plays the role of token-savior'sinsert_near_symbol.tokensave serve --timingsflag. When set, everytools/callresponse gains a_meta.duration_usfield reporting the handler's pure execution time in microseconds. Lets clients (and benchmarks) attribute latency to actual query work vs. JSON-RPC / stdio / Python-parse overhead. Toggleable at runtime through the newMcpServer::set_timings_enabledsetter so embedders can flip it per-session.- Indexer benchmark harness at
benchmarks/run_benchmarks.py— adaptsMibayy/token-savior'srun_benchmarks.pyto drive both tools side-by-side on the same clone of FastAPI, sharing a random symbol sample (seed=42) so per-query rows are directly comparable. tokensave is driven through a long-livedtokensave serve --timingsMCP session for the query column. Latest report (benchmarks/comparison-report.md): cold index 2.9× faster, impact analysis 43× faster than token-savior. - tsbench fork at
benchmarks/tsbench/— patch + reproduction README + per-run summary for runningMibayy/tsbench(token-savior's own 96-task agent benchmark) against tokensave. First-attempt untuned result: 184/192 = 95.8% vs. token-savior's audited 97.9%. The harness rewritesSYSTEM_PROMPT_TSto map each token-savior tool to its tokensave equivalent and relaxes the--disallowedToolslist to allowRead/Editfallback on the four task categories tokensave has no direct tool for. docs/TOKENSAVE-VS-TOKENSAVIOR.md— full capability + performance comparison document covering parsing strategy (regex annotators vs. tree-sitter grammars), the 11 health-analytics tools that have no token-savior equivalent, query-latency numbers (apples-to-apples find / body / impact), the tsbench 184/192 result with per-task failure analysis, and an honest "when to use which" guide.
Fixed
tokensave serveno longer blocks MCPinitializeon the watcher's filesystem walk (#84). Constructing the embeddednotify_debouncer_fullwatcher does a synchronouswalkdirover every registered subtree to seed its file-id map. On a large JS/TS monorepo with multi-gigabytenode_modules/.next/disttrees this can take 30+ seconds — long enough to blow the client'sinitializetimeout. Fix:ProjectWatcher::newnow runs insidetokio::task::spawn_blockingfrom a detachedtokio::spawn, soMcpServer::newreturns immediately and the MCP stdio loop can answerinitialize/tools/listin milliseconds. TheCancellationTokenis stored on the server up front soshutdowncan cancel mid-walk if the agent disconnects before the watcher finishes initialising. Reported by @ottob with a sample-trace and an FSEvents-sandbox repro that left zero ambiguity about root cause.tokensave serveno longer runs pre-serve maintenance work (#84).Commands::Servewas runningtry_flush(synchronous HTTP round-trip to the worldwide counter),check_install_stale, and the silent-reinstall loop over every tracked agent before the MCP stdio loop even started. All three are now gated behindshould_skip_agent_install_maintenance, alongsideInstall/Reinstall/Uninstall/Doctor. Same maintenance still runs on the user's next interactivetokensave …invocation.tokensave install --agent antigravitynow registers in both the IDE config and the CLI plugin directory (#85). Previously only~/.gemini/antigravity/mcp_config.jsonwas written, leaving the Antigravity CLI (agy) unable to see tokensave in/mcp. New: also writes~/.gemini/antigravity-cli/plugins/tokensave.jsonwith the same{"mcpServers": {"tokensave": {...}}}shape.uninstallremoves both,doctorreports both,is_detectedtriggers on either path. Reported by @ottob.- MCP
last synced N agowarning no longer fires after a no-change sync (#86). The warning was readingMAX(files.indexed_at), which only advances when a file is actually reindexed. On quiet repos a successfultokensave sync(0 added / 0 modified / 0 removed) leftindexed_atstuck and the warning fired forever. New: the warning is computed from thelast_sync_atmetadata key, whichsync()writes unconditionally on every successful invocation. Falls back toMAX(indexed_at)only when the metadata key is missing (e.g. a freshly-initialised project that has never been synced). NewTokenSave::last_sync_timestamp()helper exposes this for embedders. Reported by @uwe-sure. files_by_languagestatus output now uses real language names instead of bucketing everything asOther. The SQLCASEinDatabase::get_statsonly recognised four languages (Rust / Go / Java / Scala) and dumped everything else — Python, TypeScript, C, Swift, Kotlin, etc. — into"Other". Replaced with a Rust-side bucketing helper covering 46 extractor languages; Python files in the FastAPI benchmark now correctly report asPythoninstead ofOther. Includes special-case basename matching for extensionlessDockerfile/Makefile.- Pre-existing breakage in
tests/mcp_server_test.rsrepaired. The wholetest-transport-gated integration suite (31 tests) had been silently failing to compile sinceMcpServer::newswitched its return type toArc<McpServer>—setup_serverandrun_server_with_messagesstill expected bareMcpServer. Switched both helpers toArc<McpServer>and bumped the resource-count assertion (tokensave://status/files/overview/branches) from 4 to 5 to include the newertokensave://schemaresource. All 31 tests now pass.
Changed
- Seven hand-rolled CLI subcommands replaced by the unified
tokensave tool <name>dispatcher.query,context,body,impact,callers,files,affectedwere each ~50–150 LoC of clap glue duplicating what the MCP tool already declares in its schema. All seven are gone; the same operations are reached astokensave tool query …,tokensave tool body …, etc. Drops ~600 LoC of dispatch boilerplate fromsrc/main.rs.queryis kept as an alias for the renamedsearchso muscle memory still works.
Internal
- New methods on
TokenSave:get_call_chain,get_nodes_by_name,replace_symbol,insert_at_symbol, plus a privateresolve_symbol_for_edithelper that does qname-first resolution and refuses ambiguous matches rather than silently picking the wrong site. - New method on
GraphTraverser:find_path_directed(BFS that follows outgoing edges only, withmax_depthbound). McpServernow has atimings_enabled: AtomicBoolfield withset_timings_enabled/timings_enabledaccessors, toggleable per-session.- The dispatcher in
mcp/tools/handlers/mod.rswraps eachhandle_tool_callinvocation withInstant::now()whentimings_enabledis set and injects_meta.duration_usinto the JSON-RPC result.