Skip to content

Releases: DFKHelper/token-goat

v2.6.15

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 13 Jul 02:25

v2.6.15

v2.6.14

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 11 Jul 22:06

Fixed

  • Bumped the declared Node.js floor from >=18.0.0 to >=22.0.0 (and the esbuild target from node18 to node22), matching what CI, publish, and the tarball smoke test have actually exercised all along.
  • token-goat stats rendered the colorized rich box-table in CI instead of plain text. Non-interactive CI runners were misread as Claude Code's own terminal by the TTY heuristic; now excluded via the CI env var.
  • saveSessionState could silently drop a concurrent hook process's update under real machine load: a lock-wait timeout fell back to an unprotected write, recreating the exact clobber the lock exists to prevent. The lock-wait budget for this hot, contended call site is now much larger, so only a genuinely wedged holder or a hard failure reaches the unprotected fallback.

See CHANGELOG.md for full details.

v2.6.13

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 10 Jul 22:19

[2.6.13] - 2026-07-10 — CHANGELOG.md:7-42 (redirected from: '[2.6.13]')

[2.6.13] - 2026-07-10

Security

  • xlsx (SheetJS) has unpatched HIGH-severity CVEs (prototype pollution / ReDoS). Replaced with exceljs for the xlsx-sheets/xlsx-head/xlsx-range/xlsx-query commands. Output format (CSV-formatted sheet/range/query text) is unchanged. The module doc comment's claim of .xls/.ods support was dropped — ExcelJS, like the SheetJS build actually in use, only reads .xlsx. See src/xlsx_extract.ts; regression-tested in tests/xlsx_extract.test.ts and tests/command_matrix_e2e.test.ts.
  • global.db is a single machine-wide index shared across every project ever indexed, and five read paths queried it with no project scope — leaking or misattributing data across unrelated projects sharing the same machine. token-goat map (fetchTopSymbols in baseline.ts), token-goat semantic (searchSemantic's sqlite-vec KNN scan), token-goat find (querySymbols), token-goat dead/types/coverage-gaps (runDead/runTypes/runCoverageGaps in graph_commands.ts), and outline --stats/skeleton --stats (queryRefCounts) all ran unscoped: token-goat semantic/map/find run from project A could surface chunks, symbols, or files from unrelated project B; dead could misreport a function as ALIVE off a same-named symbol's reference in a different project; and --stats reference counts could be inflated by cross-project name collisions. All five now scope to the invoking project root via a new shared projectScopeClause helper — a LIKE-based path-prefix predicate with escaped wildcards and boundary correctness (/proj no longer matches /proj-other/file.ts). sqlite-vec's chunk_vectors vec0 table has no partition column to scope the ANN query itself against, so searchSemantic over-fetches KNN candidates, post-filters each candidate by project root, and retries once with a larger k if too few survive (fetchScopedHits, BACKFILL_MULTIPLIER) — a deliberate latency/correctness tradeoff: at most one extra query round-trip, in exchange for never leaking a chunk across projects. See src/sql_path.ts, src/baseline.ts, src/embeddings.ts, src/read_commands.ts, src/index_reader.ts, src/graph_commands.ts; regression-tested in tests/sql_path.test.ts, tests/baseline.test.ts, tests/semantic_project_scope.test.ts, tests/find_project_scope.test.ts, tests/graph_commands.test.ts, tests/index_reader.test.ts, tests/read_commands.test.ts, and tests/semantic_overflow_guard.test.ts.

Changed

  • Removed the unused USE_COLOR export from src/render/ansi.ts. Computed once at module load and never read anywhere in the codebase; live callers already check colorStdout()/colorStderr() directly for the stream in question. See src/render/ansi.ts, src/render/index.ts.
  • BREAKING (JSON output): symbol/refs/skeleton/outline --json now share one envelope shape. All four commands previously emitted inconsistent JSON — a bare array in some cases, an object wrapped under differently-named keys (symbols, references) in others, depending on whether overflow_guard truncated the result. They now always return {items, truncated, totalCount}, whether or not truncation occurred, so scripts consuming --json output no longer need to branch on shape. See src/read_commands.ts; updated in tests/read_commands.test.ts.
  • sharp and @modelcontextprotocol/sdk moved to optionalDependencies. Both were already lazy-imported with a try/catch degrade path (image shrinking silently passes through when sharp is unavailable; mcp-serve now reports a clear "install @modelcontextprotocol/sdk" error and exits instead of crashing the whole CLI when the SDK is missing), but sat in dependencies, forcing every install to pull @modelcontextprotocol/sdk's ~17 transitive packages even for users who never touch mcp-serve. @modelcontextprotocol/sdk is now lazy-import()ed only inside the mcp-serve command handler via type-only imports, so no other CLI command's startup path loads it. See src/cli.ts, package.json; regression-tested in tests/cli_mcp_server_lazy_load.test.ts and tests/image_shrink_sharp_unavailable.test.ts.

Added

  • token-goat doctor now warns when the index has indexed files but zero symbols. Guards against the worker-draining-to-a-stub-callback failure mode documented in this repo's own CLAUDE.md ("Critical path" section): files can be marked indexed in the files table while the parser never actually ran, silently leaving symbol/read/skeleton/outline/semantic permanently empty with no other signal. See src/cli_doctor.ts; regression-tested in tests/cli_doctor.test.ts.
  • semantic's query embedding now carries BGE's retrieval instruction prefix. The bge-small-en-v1.5 model this project embeds with is asymmetric: query text is meant to carry a "Represent this sentence for searching relevant passages: " prefix that document/chunk text never gets. searchSemantic now applies it to the query side only, leaving chunk/document embedding unprefixed. See src/embeddings.ts; regression-tested in tests/semantic_project_scope.test.ts.
  • image_shrink.enabled config toggle. Defaults to true; setting it to false (token-goat config set image_shrink.enabled false) skips the shrink-on-Read intercept entirely and passes large images through unshrunk, for users who want the raw image regardless of size. See src/config.ts, src/image_shrink.ts; regression-tested in tests/image_shrink.test.ts.
  • Diagnostic for languages with no symbol extractor at all. Swift, Scala, Lua, Elixir, Dart, and Zig/R files previously indexed to zero symbols indistinguishably from a genuinely empty file. outline/skeleton now report e.g. "Swift has no symbol extractor yet, so this file always indexes to 0 symbols regardless of its contents" instead of the generic "no symbols found" message for these languages. See src/parser_types.ts, src/read_commands.ts; regression-tested in tests/read_commands.test.ts.

Fixed

  • write-file/replace dropped the destination file's mode on every rewrite. atomicWriteBuffer (cli.ts) and atomicWriteCore (util.ts) both created their temp file at 0o600 and renamed it over the destination, so the new inode always carried 0o600 regardless of the file's actual mode -- on POSIX, rewriting a committed executable (a chmod +x hook script, a binary) via write-file or replace silently dropped the exec bit, and git would record it as a 100755->100644 mode change. Both now stat the existing destination and chmod the temp file to match before the rename, falling back to the 0o600 default only when the destination doesn't exist yet. No effect on Windows, which has no POSIX mode bits. See src/cli.ts, src/util.ts; regression-tested (platform-gated) in tests/cli.test.ts.
  • replace could silently clobber a concurrent write to the rest of the file. cmdReplace read the whole target file, computed the snippet replacement in memory, then rewrote the WHOLE file via atomicWriteBuffer. The snippet match only protected the matched region -- a concurrent write to any OTHER part of the file between the initial read and the final rename was silently lost (last-writer-wins over the entire file), even though the snippet match itself succeeded and reported no error. cmdReplace now captures the target's mtimeMs/size right after the initial read and re-checks them immediately before the rename, aborting with a clear error ("changed on disk ... replace was NOT applied") instead of overwriting the concurrent change. Best-effort, not a lock: a race between the re-check and the rename itself is accepted residual risk, consistent with this codebase's other optimistic-concurrency patterns (e.g. config set's withFileLock). See src/cli.ts; regression-tested in tests/cli.test.ts.
  • The MCP semantic tool had no way to override the server process's own (often opaque) cwd. semantic is the only MCP-exposed tool among the just-scoped project-root commands (map/semantic/find/dead/stats -- the rest of that set are CLI-only, not MCP tools); it always scoped searches to process.cwd(), which for an MCP client can be a cwd unrelated to the actual workspace root, silently returning empty or wrong-project results. The tool now accepts an optional projectRoot argument (matching runChanged's existing projectRoot naming convention) that overrides the default process.cwd() scope. See src/mcp_server.ts, src/read_commands.ts; regression-tested against the real MCP protocol layer in tests/mcp_server_semantic_scope.test.ts.
  • The markdown large-file hint suggested sections that don't exist in the file. The per-basename "well-known sections" shortcut list (e.g. README → Installation/Us...
Read more

v2.6.12

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 10 Jul 07:24

Full Changelog: v2.6.11...v2.6.12

v2.6.11

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 10 Jul 03:36

See CHANGELOG.md for full details.

Highlights

  • Indexer/worker critical-path fixes: BOM handling on the worker's real shipping path, index exit-code correctness, embedding pipeline memoization, unchanged-file skip on bulk index, embed-freshness gate, folded-path SQL indexes (full-table-scan fix), and a cross-process retry-count persistence fix.
  • Multi-line string masking fix across the C#, PHP, Kotlin, and PowerShell language adapters.
  • Session/hooks correctness: harness-detection priority fix, build-command cache fingerprinting, curl re-download existence check, Grok session-id fallback, overflow-guard coverage on symbol/refs/skeleton/outline, multi-file cat deny, cross-agent false-deny fix, task-output size gating, and scoped git status/diff recall-dedup.
  • Gemini bridge deny-contract verified against its own hook docs (previously assumed, now tested).
  • New Windows CI job, unified env pins between pre-push and CI, and a real tarball smoke test gating npm publish.
  • token-goat stats (bare command) now renders with the same rich TTY header/KPI section as --full.

v2.6.10

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 09 Jul 21:05

Added

  • Salesforce Apex and metadata-XML symbol indexing. New regex adapters index .cls/.trigger Apex source (classes, interfaces, triggers, methods) and Salesforce metadata XML (.object, .field-meta.xml, .validationRule-meta.xml, .permissionset-meta.xml, .profile-meta.xml, .md-meta.xml, and related suffixes) for CustomObject, CustomField, ValidationRule, PermissionSet, Profile, and CustomMetadata symbols. Metadata files above 512 KB, and all .profile-meta.xml files, are excluded from embeddings to avoid low-signal vector noise. Contributed by @krzysztofwojt.

Fixed

  • token-goat symbol returned an empty body preview for Salesforce metadata symbols. Fixed by mirroring token-goat read's disk-reconstruction fallback in runSymbol. Also replaced a 19-branch if/else if dispatch chain for non-tree-sitter language extraction with a lookup table, so adding a new regex adapter is one map entry instead of a new branch.

Full changelog: https://github.com/DFKHelper/token-goat/blob/main/CHANGELOG.md#2610---2026-07-09

v2.6.9

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 09 Jul 07:32

Fixes 16 bugs found and verified across three rounds of independent bugcheck plus a Codex CLI peer review, spanning the core symbol resolver, SQL/JS path case-folding, MCP tool classification, and Windows hook invocation across the Gemini/OpenClaw/OpenCode bridges.

See CHANGELOG.md for the full list.

v2.6.8

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 08 Jul 02:57

Fixed

  • Overflow-guard hint for line-range reads suggested wrong syntax (:: instead of @). Fixed by updating the hint text to use the correct separator (file.py@100-150).
  • skeleton/outline --min-lines with a non-numeric value silently returned zero symbols instead of erroring. Now validated with requireNonNegativeInt like other numeric flags.
  • parseDiffHunks misattributed a deleted file's hunk to the previous file. currentFile is now reset on +++ /dev/null.
  • extractMarkdownHeadings advertised sections inside fenced code blocks as real headings. Now skips fence content via eachUnfencedLine, matching its sibling extractors.
  • The Codex CLI and pi bridges had the same bare-PATH single-point-of-failure the Copilot CLI bridge was fixed for. Both now resolve the token-goat entry via process.execPath and a baked-in entry path instead of depending on PATH resolution, with a PATH-based fallback for older cached installs.

Full changelog: https://github.com/DFKHelper/token-goat/blob/main/CHANGELOG.md#268---2026-07-07

v2.6.7

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 08 Jul 01:22

Fixed

  • token-goat stats showed events as happening "tomorrow" once UTC crossed midnight, ahead of the local calendar day. summarize()'s day-bucket key and the rich stats renderer's header date were both derived via toISOString(), which always renders in UTC -- so any event recorded in the evening in a negative-UTC-offset zone (where UTC has already rolled to the next day) got bucketed and displayed under tomorrow's date. Both now derive the calendar day from local Date getters via a shared toLocalDateKey helper; skill-history's timestamp column got the same local-time treatment via a new formatLocalTimestamp helper. See src/stats.ts, src/render/stats_renderer.ts, and src/cli.ts; regression-tested in tests/stats.test.ts against a fixed UTC-5 timezone so the day-boundary crossing is deterministic regardless of the host machine's real timezone.
  • The Copilot CLI hook shim's inner call still depended on PATH resolution, unlike its already-hardened outer command. The outer hook command invokes the shim via a baked process.execPath, but the shim's own inner token-goat hook <event> call shelled out to a bare token-goat (shell: true), which depends on the npm global bin being on whatever PATH Copilot spawns the hook subprocess with -- and Copilot's preToolUse fails closed on a non-zero exit or crash, denying every tool call for the rest of the session with no mid-session recovery (Copilot caches hook configs at startup, so renaming/reinstalling the config has no effect until a full restart). token-goat install --copilot now bakes the running token-goat entry's absolute path into the generated hook command as a third argument, and the shim invokes it directly via process.execPath for the inner call too, falling back to the old PATH-based lookup only when that argument is absent (an older cached config). Every generated hook entry also now sets an explicit timeoutSec: 60, doubling Copilot's own 30s default as headroom for a cold first invocation (bundle load + DB open) on the four events that lack preToolUse's documented fail-open-on-timeout carve-out -- per GitHub's hooks reference, a preToolUse timeout itself already fails open, so this is not what causes the deny-all class, just cheap insurance for the other events. token-goat doctor gained a checkCopilotCli check that runs the exact installed preToolUse command end-to-end with a synthetic payload (through a shell, the same path Copilot uses) and separately verifies the baked node binary still exists on disk, since an nvm/fnm/volta node upgrade can silently make it stale. See src/bridges/copilot_cli.ts, src/bridges/copilot_cli_install.ts, src/cli_doctor.ts, and README.md (documents the rename-and-restart recovery path); regression-tested in tests/install_copilot_cli.test.ts and tests/cli_doctor.test.ts.

Full Changelog: https://github.com/DFKHelper/token-goat/blob/main/CHANGELOG.md

v2.6.6

Choose a tag to compare

@Zelys-DFKH Zelys-DFKH released this 08 Jul 00:14

Fixed

  • Three indexer bugs found by a Fable bugcheck: PowerShell block comments could be opened mid-line by a <# sitting inside a # line comment; token-goat read/brief couldn't resolve a symbol whose indexed name literally contains a dot (TOML sections, CSS selectors); the SQL/Protobuf block-comment stripper could close a comment against its own opening asterisk.
  • Copilot CLI recorded zero read/edit activity in any session. The view/edit/create tools send the file path under path, but every token-goat handler these tools reach only looks for file_path. The shim now adds file_path alongside the original key.

Full changelog: https://github.com/DFKHelper/token-goat/blob/main/CHANGELOG.md#266---2026-07-07