Commit graph

76 commits

Author SHA1 Message Date
Lex Christopherson
539262ee64 fix: strip hashline prefixes from TUI read output (#265)
Hashline prefixes (e.g. "1#BQ:") were leaking into the TUI display
for file reads, showing as weird characters to users. Strip them
before rendering since they're only meant for model consumption.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 16:56:06 -06:00
Lex Christopherson
ca8697ae26 feat: use server-requested retry delay for Anthropic rate limits
Anthropic's 429 responses include retry-after and x-ratelimit-reset-*
headers that tell us exactly when to retry. Previously we ignored these
and used exponential backoff (2s, 4s, 8s), which is both wrong and
misleading in the UI countdown.

- Add retryAfterMs to AssistantMessage as the structured carrier
- Extract retry-after / x-ratelimit-reset-requests / x-ratelimit-reset-tokens
  from Anthropic SDK APIError.headers in the provider catch block
- Session uses retryAfterMs when present (capped by maxDelayMs=60s),
  falls back to exponential backoff for errors with no timing hint

The UI countdown now shows the actual Anthropic reset time. No UI changes needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 16:51:17 -06:00
Lex Christopherson
7664163c1f fix: truncate oversized TUI lines instead of crashing (#287)
Lines exceeding terminal width are now silently truncated at the render
boundary rather than throwing a fatal error that kills the session.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 16:50:58 -06:00
TÂCHES
60a3607ff7 feat: native Rust output truncation module (#268)
* feat: add native Rust output truncation module

Line-boundary-aware truncation for tool outputs (bash, grep, file reads),
replacing JS byte-counting with native Rust via napi-rs. Supports head,
tail, and both modes. Counts by UTF-8 bytes, respects line boundaries,
uses memchr for fast newline scanning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: remove unsafe blocks and fix truncation message byte counts

Replace unsafe from_utf8_unchecked with safe from_utf8().expect() —
the invariant (splitting at newline boundaries) is sound but the perf
difference is negligible, so no reason to use unsafe.

Fix truncateOutput messages that reported the byte budget as "bytes
truncated" instead of the actual number of bytes removed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 16:48:49 -06:00
TÂCHES
b730ed87d0 feat: native Rust xxHash32 for hashline (#272)
* feat: replace pure-JS xxHash32 with native Rust implementation via napi

The hashline edit tool calls xxHash32 on every line of every file read/edit.
Moving this to a native Rust implementation (xxhash-rust crate) eliminates
JS overhead for this hot path. Hash output is identical -- verified by tests
comparing native vs JS reference across 11 input vectors including empty
strings, short/long inputs, unicode, and seeded variants.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: use typed native interface and remove version-drag comment in xxhash wrapper

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 16:46:08 -06:00
TÂCHES
8ac5a82409 feat: memory extraction pipeline (#261)
* feat: add memory extraction pipeline extension

Two-phase pipeline that extracts durable knowledge from session transcripts
and consolidates into project-scoped memory artifacts injected into future
sessions via system prompt.

- MemorySettings in settings-manager (disabled by default)
- SQLite storage with lease-based job queue (better-sqlite3)
- Phase 1: scan .jsonl sessions, extract knowledge via LLM
- Phase 2: consolidate extractions into MEMORY.md
- /memory command: view, clear, rebuild, stats
- Secret redaction on all stored output
- Watermark tracking to skip unchanged sessions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: harden memory extraction pipeline security and performance

- Expand secret redaction patterns (Stripe, JWT, PEM, npm, Anthropic, OpenAI keys)
- Stream-read session file headers instead of loading entire file for cwd check
- Add 50MB file size cap to prevent OOM with concurrent extraction workers
- Delete orphaned prompt .md files (prompts are inlined in pipeline.ts)
- Reset package-lock.json to current main to fix version drift

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 16:41:13 -06:00
TÂCHES
8a5465d901 feat: native Rust bash stream processor for single-pass chunk processing (#271)
Replaces the multi-pass JS pipeline (TextDecoder → stripAnsi → sanitizeBinaryOutput)
in bash-executor.ts with a single native Rust call that handles UTF-8 decoding,
ANSI stripping, binary sanitization, and CR removal in one pass.

Key features:
- StreamState tracks incomplete UTF-8 and ANSI sequences across chunk boundaries
- Standalone stripAnsiNative() and sanitizeBinaryOutputNative() for use elsewhere
- Comprehensive test coverage for split multibyte, split ANSI, binary data

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 16:34:17 -06:00
Juan Francisco Lebrero
5ff362ed0e feat: add claude-opus-4-6[1m] model with 1M context window (#288)
Add the 1M context variant of Claude Opus 4.6 to the model registry
and fix model resolver to try exact match before glob detection, so
model IDs containing bracket characters (like [1m]) are not
misinterpreted as glob patterns.
2026-03-13 16:25:45 -06:00
TÂCHES
8b9cfae9e9 feat: native Rust streaming JSON parser (#266)
* feat: add native Rust streaming JSON parser for LLM tool call argument parsing

Replaces the JS partial-json library with a Rust implementation exposed via napi-rs.
The parser handles incomplete JSON from streaming deltas by closing unclosed strings,
objects, arrays, removing trailing commas, and completing truncated literals.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: handle truncated numbers and remove dead partial-json dependency

Adds truncated number recovery (e.g. `{"key": 12`, `{"key": 3.`, `{"key": 1e`)
to the Rust streaming JSON parser, and removes the now-unused `partial-json`
npm dependency from pi-ai.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 16:21:58 -06:00
TÂCHES
54df619891 feat: task isolation for subagent filesystem safety (#254)
* feat: add task isolation for subagent filesystem safety

Subagents can run in isolated git worktrees (or FUSE overlays on Linux)
so concurrent tasks don't stomp on each other's files. Changes are
captured as unified diffs and merged back via git apply.

- New isolation.ts module with worktree and FUSE overlay backends
- TaskIsolationSettings in settings-manager (mode + merge strategy)
- isolated parameter on the subagent tool schema
- Baseline capture/apply mirrors the parent repo's dirty state
- Process exit handler for best-effort cleanup of stale worktrees

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: correct delta capture to exclude parent baseline state

The worktree backend now commits a baseline snapshot after applying the
parent's dirty state, so captureDeltaPatch diffs only the subagent's
actual changes against the post-baseline HEAD (not the original HEAD).

The FUSE overlay backend tracks the parent's dirty file set at mount
time and filters the upper dir during delta capture to exclude inherited
dirty files.

Also removes dead code: findGitRoot (unused), readIsolationMergeStrategy
(exported but never called).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 16:10:55 -06:00
Lex Christopherson
fdeb520332 fix: restore bashInterceptor settings dropped by async-jobs merge
The async-jobs PR (#260) accidentally dropped `bashInterceptor` from the
Settings interface and the getBashInterceptorEnabled/getBashInterceptorRules
methods from SettingsManager, breaking the TypeScript build on main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 16:06:21 -06:00
TÂCHES
fa9477f638 feat: async background jobs extension (#260) 2026-03-13 16:01:30 -06:00
TÂCHES
2452d34f53 Merge pull request #255 from gsd-build/feat/multi-credential
feat: multi-credential round-robin with rate-limit fallback
2026-03-13 15:49:57 -06:00
Lex Christopherson
e9676202e1 fix: add tests and clarify edge cases for multi-credential auth storage
- Add 14 tests covering round-robin, session-sticky, login accumulation,
  backoff/fallback, and getAll() truncation behavior
- Document getAll() truncation is intentional (OAuth refresh only)
- Add comment in markUsageLimitReached explaining round-robin race
  is benign in single-threaded event loop context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 15:49:44 -06:00
TÂCHES
bdb6bcde35 Merge pull request #258 from gsd-build/feat/bash-interceptor
feat: bash interceptor for tool discipline
2026-03-13 15:47:53 -06:00
Lex Christopherson
e55b6dd994 fix: bash interceptor regex bugs and add unit tests
- Fix cat rule to exclude heredoc syntax (cat <<EOF) via negative lookahead
- Fix write rule: exclude >> append and digit-prefixed fd redirects (2>)
  using lookbehind (?<![|>\d])>(?!>)
- Add compileInterceptor() — pre-compiles rules once at construction time
  instead of on every bash call; export CompiledInterceptor type
- Update createBashTool to use pre-compiled interceptor instance
- Add 33 unit tests covering all rules, edge cases, and pass-throughs
2026-03-13 15:46:08 -06:00
Lex Christopherson
8ba6c9a853 fix: collapse tool output by default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 15:31:18 -06:00
Lex Christopherson
d0f84d9a38 feat: add bash interceptor to block commands that duplicate dedicated tools
Regex-based pre-execution check in the bash tool blocks shell commands
(grep, cat, sed -i, etc.) when the dedicated replacement tool is available
in the session. Configurable via bashInterceptor settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:50:10 -06:00
Lex Christopherson
1774d6e1f4 fix: use @gsd-build npm scope and remove committed binary
Rename all platform packages from @gsd/engine-* to @gsd-build/engine-*
to match the npm org. Remove the darwin-arm64 binary from git and
native/addon from files — production binaries come exclusively from
CI-published platform packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:49:26 -06:00
Lex Christopherson
4b6a43c2b3 feat: multi-credential round-robin with rate-limit fallback
Support multiple API keys per provider with automatic rotation:
- AuthStorageData accepts single credential or array per provider
- Round-robin selection across credentials (no sessionId)
- Session-sticky hashing when sessionId is provided
- Credential backoff on rate limits (30s), quota exhaustion (30min),
  server errors (20s)
- markUsageLimitReached() backs off failing credential and returns
  whether an alternate is available
- Login accumulation: duplicate provider logins append API keys
  instead of replacing
- Agent retry handler tries credential fallback before counting
  against retry budget (immediate retry, no delay)
- All getApiKey call sites thread sessionId for sticky selection

Backward compatible: single credentials work unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:45:35 -06:00
Lex Christopherson
bd8380315c feat: per-platform optional dependencies for native binary distribution
Add the esbuild/swc pattern for distributing platform-specific native
binaries via npm optional dependencies. Each supported platform gets its
own @gsd/engine-{platform} package containing just the .node binary.

- 5 platform package stubs (darwin-arm64, darwin-x64, linux-x64-gnu,
  linux-arm64-gnu, win32-x64-msvc) with os/cpu filters
- Rewritten native loader: tries npm package first, then local build
- Version sync script keeps platform packages in lock-step with root
- GitHub Actions workflow for cross-platform build + publish on tag push

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:36:18 -06:00
Lex Christopherson
d49af589d0 fix: include darwin-arm64 native binary in npm tarball (Phase A hotfix)
The native .node binary was excluded from npm pack due to native/.gitignore
ignoring addon/. Add native/.npmignore (overrides .gitignore for npm) and
include native/addon in the files whitelist. Also improve the error message
in the native loader to list supported platforms and link to issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:33:37 -06:00
Lex Christopherson
064c4cfc1a feat: add native Rust GSD file parser for .gsd/ directory parsing
Implements a Rust napi-rs module that parses YAML-like frontmatter,
markdown sections, and roadmap structures from .gsd/ files. Provides
parseFrontmatter, extractSection, extractAllSections, batchParseGsdFiles,
and parseRoadmapFile functions exposed via @gsd/native. The JS parsers
in files.ts fall back transparently when the native module is unavailable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:12:17 -06:00
Lex Christopherson
4c97d59536 feat: add native Rust diff engine for edit tool
Move the edit tool's hot-path diffing operations from JS to native Rust:
- `normalizeForFuzzyMatch`: single-pass Unicode normalization (smart quotes,
  dashes, special spaces, trailing whitespace)
- `fuzzyFindText`: exact-then-fuzzy substring search with UTF-16 index
  conversion for JS compatibility
- `generateDiff`: unified diff generation using the `similar` crate
  (Myers' algorithm with optimizations)

The Rust module at `native/crates/engine/src/diff.rs` exposes three napi
functions. The TypeScript wrapper at `packages/native/src/diff/` follows
the existing module pattern. `edit-diff.ts` now delegates to native
implementations while keeping line-ending handling and file I/O in JS.

18 tests covering normalization, fuzzy matching (including UTF-16 index
correctness with emoji/surrogate pairs), and diff generation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:11:40 -06:00
TÂCHES
886bc9b571 feat: native Rust TTSR regex engine
feat: native Rust TTSR regex engine
2026-03-13 14:11:01 -06:00
Lex Christopherson
e6be5ac03f fix: compile @gsd/native to JS before publish
@gsd/native shipped raw .ts files in node_modules, which Node.js
refuses to import (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING on
Node 22/24, ERR_UNKNOWN_FILE_EXTENSION on Node 20). Add tsc build
step, point exports at dist/, and add to bundleDependencies.

Closes #248

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 14:05:41 -06:00
Lex Christopherson
ac34c7c283 feat: add native Rust TTSR regex engine via RegexSet
TTSR's checkDelta() runs O(rules x conditions) regex evaluations per
streaming token — the hottest path in GSD. This adds a Rust native
module that compiles all condition patterns into a single RegexSet,
testing them in one DFA pass instead of sequential JS RegExp iteration.

The TtsrManager transparently uses the native engine when available and
falls back to the existing JS regex loop when it is not.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:57:12 -06:00
Lex Christopherson
d5b7ecb58c fix: resolve TypeScript build errors in glob callback type and hashline test import 2026-03-13 13:47:33 -06:00
Lex Christopherson
ec7d6eee4c feat: wire native Rust image module into image processing pipeline
Replace manual binary header parsing (PNG/JPEG/GIF/WebP) in terminal-image.ts
with the native @gsd/native/image module, and replace photon-node (WASM) with
native N-API calls for image resize and format conversion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:41:53 -06:00
TÂCHES
77bbbc19a9 feat: wire native Rust text module into pi-tui
feat: wire native Rust text module into pi-tui
2026-03-13 13:41:07 -06:00
TÂCHES
95232cf64d feat: wire native Rust fd module into autocomplete
feat: wire native Rust fd module into autocomplete
2026-03-13 13:41:04 -06:00
Lex Christopherson
ec9670b4dc feat: replace fd CLI binary with native @gsd/native fd module for autocomplete
The autocomplete file search no longer spawns the external `fd` binary via
spawnSync. It calls the in-process Rust fuzzyFind() function from @gsd/native,
which handles directory walking, gitignore, hidden files, and fuzzy scoring
in a single native call. The fdPath constructor parameter and ensureTool("fd")
download are removed since the binary is no longer needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:35:07 -06:00
Lex Christopherson
0b6747850e feat: replace JS text utilities with native Rust @gsd/native/text module
Swap visibleWidth, wrapTextWithAnsi, truncateToWidth, sliceWithWidth, and
extractSegments to delegate to the native Rust text module. Adapter maps
the JS ellipsis string API to the native EllipsisKind enum. Functions
without native equivalents (getSegmenter, extractAnsiCode, applyBackgroundToLine,
isWhitespaceChar, isPunctuationChar) are retained. Reduces utils.ts from
~900 lines to ~180 lines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:35:05 -06:00
Lex Christopherson
d330a552b7 feat: replace clipboard implementations with native @gsd/native module
Use the Rust-backed arboard clipboard (via @gsd/native/clipboard) for
text copy and image read, replacing the platform-tool shelling
(pbcopy/xclip/xsel) and @mariozechner/clipboard optional dependency.

OSC 52 is preserved as a fallback for SSH/mosh sessions. Linux Wayland
still falls back to wl-paste/xclip for image reads since arboard may
lack compositor access from a terminal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:31:22 -06:00
TÂCHES
35056d3ba8 feat: replace cli-highlight with native syntect highlighter
feat: replace cli-highlight with native syntect highlighter
2026-03-13 13:27:12 -06:00
TÂCHES
3c2b8d7865 feat(find): wire native Rust glob into find tool
feat(find): wire native Rust glob into find tool
2026-03-13 13:27:09 -06:00
Lex Christopherson
5970ad74b2 merge: integrate native image module (#235) 2026-03-13 13:22:09 -06:00
Lex Christopherson
59ec1fbc02 feat: replace cli-highlight with native syntect-based highlighter
Switch syntax highlighting from the cli-highlight npm package to the
@gsd/native Rust-based highlight module (syntect). The native module
accepts raw ANSI escape sequences via the HighlightColors interface,
eliminating the wrapper-function indirection of the old CliHighlightTheme.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:19:55 -06:00
Lex Christopherson
a685c7f987 feat(find): replace glob npm package + fd with native Rust glob
The find tool's default path spawned `fd` and used the `glob` npm package
to discover nested .gitignore files. The native @gsd/native glob module
handles gitignore traversal natively via Rust's `ignore` crate, making
both dependencies unnecessary for this code path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:16:42 -06:00
Lex Christopherson
cd444eb0ea merge: integrate native fd module (#231) 2026-03-13 13:13:43 -06:00
Lex Christopherson
8fb8c6a16b merge: integrate native text module (#230) 2026-03-13 13:12:40 -06:00
Lex Christopherson
f1c848b429 merge: integrate native html module (#229) 2026-03-13 13:11:40 -06:00
Lex Christopherson
f8b286c66a fix: repair native module test assertions
- highlight: remove quotes from "bar" assertion (ANSI codes split the string)
- ps: skip listDescendants child test (proc_listchildpids unreliable on macOS)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:06:47 -06:00
Lex Christopherson
df39cea85e feat: add native ast module with ast-grep structural search and rewrite
Adds the `gsd-ast` crate providing AST-aware code search (`astGrep`) and
rewrite (`astEdit`) via ast-grep with tree-sitter grammars for 38+ languages.
Replaces Oh My Pi's fs_cache/task dependencies with the `ignore` crate for
.gitignore-respecting file walking. Includes TypeScript type declarations
and wrappers in packages/native.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:02:29 -06:00
Lex Christopherson
ab5b9e949a fix: copy lsp.md to dist during build
The copy-assets script was missing lsp.md from src/core/lsp/, causing
ENOENT at startup after the defaults.json fix landed.

Closes #233, closes #234

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 13:02:29 -06:00
Lex Christopherson
75fe5d3319 feat: add native image module — decode, encode, and resize via Rust image crate
Port image processing from Oh My Pi's pi-natives crate, adapted for napi-rs v2.
Exposes NativeImage class with async parse/encode/resize methods backed by the
Rust `image` crate (PNG, JPEG, WebP, GIF support).

Includes:
- task.rs: lightweight async task scheduling for libuv thread pool
- image.rs: NativeImage class with SamplingFilter enum
- TypeScript types and wrapper (parseImage, ImageFormat, SamplingFilter)
- 8 passing tests covering decode, encode, resize, round-trip, error cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 12:51:49 -06:00
TÂCHES
daca368ba2 feat: add native clipboard module with arboard backend (#228)
Cross-platform clipboard access (text read/write, image read) via the
arboard Rust crate. No external tools (pbcopy, xclip, etc.) required.

Ported from Oh My Pi's clipboard module with adaptations for GSD's
architecture (direct AsyncTask instead of task::blocking wrapper).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 12:48:27 -06:00
Lex Christopherson
e05292f772 feat: add native ast module — AST-aware structural search and rewrite via ast-grep
Port ast-grep integration from Oh My Pi with 38+ language support via tree-sitter
grammars. Exposes `astGrep` (search) and `astEdit` (rewrite) as N-API functions
with TypeScript wrappers.

Key changes:
- New `gsd-ast` crate with language definitions, glob utilities, and ast-grep core
- Replaces fs_cache/task dependencies with `ignore` crate for file walking
- Synchronous API matching the existing grep module pattern
- Full TypeScript type declarations in packages/native/src/ast/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 12:47:27 -06:00
TÂCHES
d64575cd3c feat: add syntect-based syntax highlighting module to native engine (#227)
Port the highlight module from Oh My Pi's pi-natives crate. Provides
ANSI-colored syntax highlighting with scope-based semantic token matching
across 11 categories (comment, keyword, function, variable, string, number,
type, operator, punctuation, inserted, deleted).

Exposed N-API functions:
- highlightCode(code, lang, colors) -> ANSI-highlighted string
- supportsLanguage(lang) -> boolean
- getSupportedLanguages() -> string[]

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 12:47:02 -06:00
TÂCHES
c36c8bd0b0 feat: add native glob and fs_cache modules with gitignore-aware discovery (#226)
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>
2026-03-13 12:45:56 -06:00