Port glob, glob_util, and fs_cache modules from Oh My Pi's pi-natives crate,
adapted for napi-rs v2. Provides gitignore-respecting filesystem discovery
with a TTL-based scan cache, mtime sorting, file-type filtering, and
node_modules exclusion.
Includes a task module for async N-API work scheduling with cooperative
cancellation (timeout-based), TypeScript type declarations and wrapper,
and 12 integration tests covering pattern matching, recursion, gitignore,
maxResults, sortByMtime, fileType filtering, and cache invalidation.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Port Oh My Pi's ps module providing efficient process tree enumeration
and termination using platform-native APIs (libproc on macOS, /proc on
Linux, Toolhelp32 on Windows).
Exposes four napi functions: killTree, listDescendants, processGroupId,
and killProcessGroup.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Check if the destination file exists before performing a move in
hashline-edit. If it does, return an error instead of silently
overwriting the file.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The delete operation in hashline-edit.ts wrapped both access() and
unlink() in a single try/catch. If access succeeded but unlink failed
(e.g., permissions), the error was silently swallowed and "Deleted" was
falsely reported. Now access and unlink have separate error handling:
access failures indicate the file doesn't exist, while unlink failures
propagate to the caller.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: scaffold Rust native engine with grep module (napi-rs)
Adds a Rust N-API addon architecture inspired by Oh My Pi's pi-natives.
The grep module wraps ripgrep's core crates (grep-regex, grep-searcher,
grep-matcher) and exposes `search()` and `grep()` to Node.js via napi-rs.
Includes:
- Cargo workspace at native/ with engine (cdylib) and grep (lib) crates
- Build script (native/scripts/build.js) producing platform-tagged .node files
- TypeScript wrapper package (@gsd/native) with types and loader
- 6 Rust unit tests + 9 Node.js integration tests (all passing)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: audit fixes for rust native engine PR
- Fix repository URL to gsd-build/gsd-2
- Remove dead add_custom_ignore_filename("") call
- Unify error model: search() now returns Result<> (throws) matching grep()
- Remove error field from NapiSearchResult and SearchResult types
- Use t.after() in integration tests for reliable temp dir cleanup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement hashline edit mode inspired by Oh My Pi's approach. Each line
in a file is identified by a content hash (xxHash32, 2-char nibble
alphabet), enabling the model to reference lines by stable LINE#ID tags
instead of reproducing full line text. This eliminates the most common
edit failure mode (slightly misquoted original text) and reduces output
tokens.
New files:
- hashline.ts: core hash computation, formatting, parsing, validation,
and edit application engine (pure JS xxHash32, no native deps)
- hashline-edit.ts: AgentTool wrapper for hash-anchored file edits
- hashline-read.ts: read tool variant that outputs LINE#ID:CONTENT format
- hashline.test.ts: 54 tests covering all core operations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- config.ts: Replace execSync(`which ${command}`) with spawnSync("which", [command])
to prevent shell injection from malicious lsp.json config files
- client.ts: Wrap JSON.parse in parseMessage with try/catch and handle null messages
in the stream reader to prevent process crashes from malformed LSP output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests initialize, hover, go-to-definition, references, document symbols,
diagnostics (type error detection), and clean shutdown against a real
typescript-language-server instance with a temp TypeScript project.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All 10 LSP files ported and adapted. Wired into tools/index.ts.
Remaining work: fix TypeScript compilation errors (see below).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
In RPC mode, `ctx.ui.custom()` returns `undefined as never`, causing
`showInterviewRound` to return undefined and `Object.keys(result.answers)`
to throw TypeError.
When `showInterviewRound` returns undefined (RPC mode), fall back to
sequential `ctx.ui.select()` calls for each question, forwarding the
abort signal (#171) and supporting `allowMultiple` (#165).
- Add `allowMultiple` to `ExtensionUIDialogOptions`
- Widen `select()` return type to `string | string[] | undefined`
- Add `allowMultiple` to RPC select request and `values` array to response
- Update RPC `select()` to forward `allowMultiple` and parse array responses
- Guard existing `ctx.ui.select()` callers against the widened return type
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
After /login, if the current model has no valid API key, auto-switch to
a model from the newly authenticated provider. After /logout, if the
current model belongs to the logged-out provider, auto-switch to a
fallback model from a different provider.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Three locations used lastIndexOf("/") or includes("/") for path
manipulation, which fails on Windows where paths use backslashes.
- auto.ts: writeBlockerPlaceholder directory extraction → dirname()
- interactive-mode.ts: parent directory traversal → path.dirname() loop
- path-utils.ts: non-null assertion on MSYS drive letter access
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Windows, LLMs convert absolute paths like F:\Projects\.gsd\... to
Unix-style /f/Projects/.gsd/... which Node's path.resolve interprets
as drive-root-relative, creating F:\f\Projects\.gsd\... instead.
Replace all *AbsPath template variables in prompt templates with
relative .gsd/... paths that resolve correctly on all platforms.
Add MSYS path normalization in resolveToCwd as defense-in-depth.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LLM-generated commands with `> NUL` create undeletable files on Windows
because Git Bash treats NUL as a literal filename. Rewrite NUL redirects
to /dev/null at all three bash spawn sites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
External packages (pi-rtk, pi-context, pi-agent-browser, etc.) import from
the original @mariozechner/* scope which GSD forked to @gsd/*. Add aliases
in both jiti resolution paths (virtualModules for Bun, getAliases for Node)
so these packages resolve correctly without manual workarounds.
Closes#161
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add .gitignore negation for vendor path
- Restore marked.min.js from pi-mono upstream
- Restore highlight.min.js from pi-mono upstream
Fixes build failure in pi-coding-agent caused by
global vendor/ ignore rule excluding vendored libs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vendor all 4 Pi packages (tui, ai, agent-core, coding-agent) from
pi-mono v0.57.1 as @gsd/* workspace packages under packages/. This
replaces the compiled npm dependency (@mariozechner/pi-coding-agent)
and patch-package workflow, giving direct source access for
modifications.
- Copy Pi source from pi-mono v0.57.1 into packages/
- Create workspace package.json + tsconfig.json for each package
- Rename ~240 imports from @mariozechner/pi-* to @gsd/pi-*
- Apply existing patches as source edits (setModel persist, VT input)
- Remove @mariozechner/pi-coding-agent dep and patch-package
- Update build pipeline to build packages in dependency order
- Add pi-upstream git remote for future selective syncing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>