Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28fce4145a | |||
| d5b4abd2ac | |||
| e6df25388a | |||
| 611dd873a3 | |||
| d7c0ddc374 | |||
| be2dd8d568 | |||
| f4def12a1c | |||
| 459ebcdbdb | |||
| f565d37175 | |||
| 0d8c257a5d | |||
| d01cc483ca | |||
| cf2130090e | |||
| 232288c60b | |||
| 2c9cae2e0f | |||
| a166255d8f |
@@ -23,12 +23,23 @@ env:
|
||||
CARGO_PROFILE_RELEASE_LTO: thin
|
||||
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 16
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
lua-tests:
|
||||
name: e2e (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
# e2e tests could be flaky on CI so we do not block release creation if they failed
|
||||
continue-on-error: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
|
||||
# alpine-musl installs rust via apk and has no sccache, so keep this scoped.
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: sccache
|
||||
# fff-search alone exceeds the 600s default on windows, and the server
|
||||
# sees no new requests while it compiles, so it would idle out mid-unit.
|
||||
SCCACHE_IDLE_TIMEOUT: "0"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -53,9 +64,19 @@ jobs:
|
||||
cache-key: "v2-lua-e2e"
|
||||
rustflags: ""
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Build Rust binary
|
||||
shell: bash
|
||||
run: make build
|
||||
run: make build-e2e
|
||||
|
||||
- name: sccache stats
|
||||
if: always()
|
||||
shell: bash
|
||||
run: sccache --show-stats
|
||||
|
||||
- name: Verify Windows DLL has no unexpected dependencies
|
||||
if: matrix.os == 'windows-latest'
|
||||
@@ -127,7 +148,7 @@ jobs:
|
||||
|
||||
- name: Install node dependencies
|
||||
shell: bash
|
||||
run: cd packages/fff-node && npm install
|
||||
run: cd packages && npm ci
|
||||
|
||||
- name: Run node tests
|
||||
shell: bash
|
||||
@@ -177,12 +198,14 @@ jobs:
|
||||
run: cargo build --release -p fff-c
|
||||
|
||||
- name: Install workspace npm deps
|
||||
run: npm install --no-package-lock
|
||||
working-directory: packages
|
||||
run: npm ci
|
||||
|
||||
# Upstream @yuuang/ffi-rs-linux-x64-musl ships with libc:"glibc" in
|
||||
# its package.json (a publishing bug in ffi-rs), so npm filters it
|
||||
# out. Force-install it so the FFI runtime is present on Alpine.
|
||||
- name: Install ffi-rs musl runtime
|
||||
working-directory: packages
|
||||
run: |
|
||||
FFI_RS_VERSION=$(node -p "require('ffi-rs/package.json').version")
|
||||
npm install --no-package-lock --no-save --force \
|
||||
@@ -193,7 +216,7 @@ jobs:
|
||||
# this is what exercises detectLinuxLibc().
|
||||
- name: Stage musl bin package
|
||||
run: |
|
||||
PKG_DIR=node_modules/@ff-labs/fff-bin-linux-x64-musl
|
||||
PKG_DIR=packages/node_modules/@ff-labs/fff-bin-linux-x64-musl
|
||||
mkdir -p "$PKG_DIR"
|
||||
cp target/release/libfff_c.so "$PKG_DIR/libfff_c.so"
|
||||
cat >"$PKG_DIR/package.json" <<'JSON'
|
||||
|
||||
@@ -12,6 +12,10 @@ on:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
lua-ls:
|
||||
name: lua-language-server type check
|
||||
|
||||
@@ -12,6 +12,10 @@ on:
|
||||
- '**.md'
|
||||
- 'doc/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Oxc
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "packages/**"
|
||||
- .github/workflows/oxc.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- "packages/**"
|
||||
- .github/workflows/oxc.yml
|
||||
|
||||
env:
|
||||
CLICOLOR: 1
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
oxc:
|
||||
name: Check packages with oxfmt and oxlint
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: oxfmt
|
||||
run: bun run format:check
|
||||
|
||||
- name: oxlint
|
||||
run: bun run lint -- -f github --deny-warnings
|
||||
@@ -15,6 +15,17 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
MACOSX_DEPLOYMENT_TARGET: "13.0"
|
||||
CARGO_PROFILE_RELEASE_LTO: thin
|
||||
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 16
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: sccache
|
||||
# fff-search alone exceeds the 600s default on windows, and the server sees
|
||||
# no new requests while it compiles, so it would idle out mid-unit.
|
||||
SCCACHE_IDLE_TIMEOUT: "0"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -31,7 +42,16 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.15.4
|
||||
with:
|
||||
cache: true
|
||||
cache-on-failure: true
|
||||
cache-key: "v1-rust-python"
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Setup uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
@@ -43,6 +63,8 @@ jobs:
|
||||
working-directory: packages/fff-python
|
||||
shell: bash
|
||||
run: |
|
||||
uv sync --all-extras
|
||||
# --no-install-project: uv would otherwise build the wheel via
|
||||
# maturin's PEP 517 backend, then `maturin develop` builds it again.
|
||||
uv sync --all-extras --no-install-project
|
||||
uv run maturin develop --release
|
||||
uv run pytest -v
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, fix/use-trusted-publishing]
|
||||
branches: [main, fix/npm-pulish]
|
||||
tags:
|
||||
- "v*"
|
||||
pull_request:
|
||||
@@ -17,10 +17,18 @@ on:
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
build-nvim:
|
||||
name: Build Neovim ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_IDLE_TIMEOUT: "0"
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -91,6 +99,11 @@ jobs:
|
||||
with:
|
||||
key: nvim-${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Install Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
with:
|
||||
@@ -146,6 +159,10 @@ jobs:
|
||||
build-c:
|
||||
name: Build C FFI ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_IDLE_TIMEOUT: "0"
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
@@ -228,6 +245,11 @@ jobs:
|
||||
with:
|
||||
key: c-${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Install Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
with:
|
||||
@@ -294,6 +316,10 @@ jobs:
|
||||
build-mcp:
|
||||
name: Build MCP ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_IDLE_TIMEOUT: "0"
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
@@ -344,6 +370,11 @@ jobs:
|
||||
with:
|
||||
key: mcp-${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Install Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
with:
|
||||
@@ -478,7 +509,7 @@ jobs:
|
||||
name: Release
|
||||
needs: [build-nvim, build-c, build-mcp, build-python, build-python-sdist]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/fix/use-trusted-publishing' || startsWith(github.ref, 'refs/tags/v'))
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -638,7 +669,7 @@ jobs:
|
||||
name: Publish Python wheels to PyPI
|
||||
needs: [build-python, build-python-sdist]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/fix/use-trusted-publishing' || startsWith(github.ref, 'refs/tags/v'))
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
environment:
|
||||
name: pypi
|
||||
url: https://pypi.org/p/fff-search
|
||||
@@ -663,7 +694,7 @@ jobs:
|
||||
name: Publish Rust crates
|
||||
needs: [build-nvim, build-c, build-mcp]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/fix/use-trusted-publishing' || startsWith(github.ref, 'refs/tags/v'))
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -694,7 +725,7 @@ jobs:
|
||||
name: Publish npm packages
|
||||
needs: [build-c]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/fix/use-trusted-publishing' || startsWith(github.ref, 'refs/tags/v'))
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/fix/npm-pulish' || startsWith(github.ref, 'refs/tags/v'))
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -740,6 +771,16 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
# Every install must happen before the first set-npm-version: the bump
|
||||
# injects platform optionalDependencies that only resolve once published,
|
||||
# and npm ci validates the whole workspace against the lockfile.
|
||||
- name: Install and build JS packages
|
||||
working-directory: packages
|
||||
run: |
|
||||
npm ci
|
||||
(cd fff-bun && npm run build)
|
||||
(cd fff-node && npm run build)
|
||||
|
||||
- name: Publish bun package
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
@@ -749,8 +790,6 @@ jobs:
|
||||
make set-npm-version PKG=packages/fff-bun VERSION="$VERSION"
|
||||
|
||||
cd packages/fff-bun
|
||||
bun install --frozen-lockfile
|
||||
bun run build
|
||||
npm publish --tag "$TAG" --access public --provenance
|
||||
|
||||
- name: Publish Node.js package
|
||||
@@ -762,8 +801,6 @@ jobs:
|
||||
make set-npm-version PKG=packages/fff-node VERSION="$VERSION"
|
||||
|
||||
cd packages/fff-node
|
||||
npm install
|
||||
npm run build
|
||||
npm publish --tag "$TAG" --access public --provenance
|
||||
|
||||
- name: Publish pi-fff package
|
||||
|
||||
@@ -17,6 +17,15 @@ env:
|
||||
# Ensure consistent macOS deployment target across all compiled objects
|
||||
# (Rust, cc-compiled C code, and Zig-compiled zlob) to avoid linker warnings
|
||||
MACOSX_DEPLOYMENT_TARGET: "13"
|
||||
# RUSTC_WRAPPER is set per job, since cargo fmt runs without sccache.
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
# fff-search alone exceeds the 600s default on windows, and the server sees
|
||||
# no new requests while it compiles, so it would idle out mid-unit.
|
||||
SCCACHE_IDLE_TIMEOUT: "0"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -46,8 +55,16 @@ jobs:
|
||||
cache-key: "v1-rust"
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --no-default-features --features zlob --workspace --exclude fff-nvim
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
# fff-python requires full python o3 machinery which is very slow
|
||||
run: cargo test --no-default-features --features zlob --workspace --exclude fff-nvim --exclude fff-python
|
||||
|
||||
stress-test:
|
||||
name: Fuzz Tests
|
||||
@@ -65,6 +82,7 @@ jobs:
|
||||
FFF_STRESS_CASES: "5"
|
||||
FFF_STRESS_MIN_OPS: "30"
|
||||
FFF_STRESS_MAX_OPS: "60"
|
||||
RUSTC_WRAPPER: sccache
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
@@ -81,6 +99,11 @@ jobs:
|
||||
cache-key: "v1-rust-stress-${{ matrix.os }}"
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Stress test seeded
|
||||
shell: bash
|
||||
run: make test-stress-seeded
|
||||
@@ -124,7 +147,14 @@ jobs:
|
||||
cache-on-failure: true
|
||||
cache-key: "v1-rust-i686"
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Build fff-search for i686
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
run: cargo build -p fff-search --target i686-unknown-linux-gnu
|
||||
|
||||
fmt:
|
||||
@@ -157,6 +187,13 @@ jobs:
|
||||
with:
|
||||
toolchain: stable
|
||||
components: clippy
|
||||
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
with:
|
||||
version: v0.17.0
|
||||
|
||||
- name: Run clippy
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
run: cargo clippy --no-default-features --features zlob -- -D warnings
|
||||
|
||||
@@ -12,6 +12,10 @@ on:
|
||||
env:
|
||||
CLICOLOR: 1
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
spelling:
|
||||
name: Spell Check with Typos
|
||||
|
||||
@@ -20,6 +20,10 @@ on:
|
||||
env:
|
||||
CLICOLOR: 1
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
jobs:
|
||||
stylua:
|
||||
name: Check lua files using Stylua
|
||||
|
||||
Generated
+7
-7
@@ -633,7 +633,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fff-c"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"fff-query-parser",
|
||||
"fff-search",
|
||||
@@ -643,7 +643,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-grep"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"memchr",
|
||||
@@ -651,7 +651,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-mcp"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fff-query-parser",
|
||||
@@ -684,7 +684,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-nvim"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"chrono",
|
||||
@@ -705,7 +705,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-python"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"fff-query-parser",
|
||||
"fff-search",
|
||||
@@ -715,7 +715,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-query-parser"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"zlob",
|
||||
@@ -723,7 +723,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-search"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"aho-corasick",
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ resolver = "2"
|
||||
module_inception = "allow"
|
||||
|
||||
[workspace.dependencies]
|
||||
fff-grep = { version = "0.10.3", path = "crates/fff-grep" }
|
||||
fff-query-parser = { version = "0.10.3", path = "crates/fff-query-parser", default-features = false }
|
||||
fff-grep = { version = "0.10.5", path = "crates/fff-grep" }
|
||||
fff-query-parser = { version = "0.10.5", path = "crates/fff-query-parser", default-features = false }
|
||||
|
||||
# Shared dependencies
|
||||
ahash = "0.8"
|
||||
|
||||
+5
-5
@@ -4,7 +4,7 @@ class FffMcp < Formula
|
||||
desc "Fast file search toolkit for AI agents (MCP server)"
|
||||
homepage "https://github.com/dmtrKovalenko/fff"
|
||||
license "MIT"
|
||||
version "0.10.3"
|
||||
version "0.10.5"
|
||||
|
||||
LIVECHECK_REPO = "dmtrKovalenko/fff".freeze
|
||||
RELEASE_BASE = "https://github.com/dmtrKovalenko/fff/releases/download".freeze
|
||||
@@ -12,24 +12,24 @@ class FffMcp < Formula
|
||||
on_macos do
|
||||
on_arm do
|
||||
url "#{RELEASE_BASE}/v#{version}/fff-mcp-aarch64-apple-darwin"
|
||||
sha256 "8c52acf1e95540f02cf55579126ebf580cf48af15c76e1c90301c2c8c5acbcf9"
|
||||
sha256 "2f1a75c2401e5df7f5a10827f9ce9fe8401f290ff99c3f3f1423c7d7b156d849"
|
||||
end
|
||||
|
||||
on_intel do
|
||||
url "#{RELEASE_BASE}/v#{version}/fff-mcp-x86_64-apple-darwin"
|
||||
sha256 "f72c31c7f3355d37ec526ba56fd716341bd7186a15a399910cf3f2b46fef2099"
|
||||
sha256 "c81e22a7fb657731a7441be877c622a110eb7e7dbc94e3b57d79c9cea91f38db"
|
||||
end
|
||||
end
|
||||
|
||||
on_linux do
|
||||
on_arm do
|
||||
url "#{RELEASE_BASE}/v#{version}/fff-mcp-aarch64-unknown-linux-gnu"
|
||||
sha256 "ed2db5b7268c76619178594c31e400b0973668acfa42fe6b9a06a28ad459b667"
|
||||
sha256 "48f5af0d9e6ef4506c5cccd3f4571da4f0acc9b9c0967832167e49fe651f8ee5"
|
||||
end
|
||||
|
||||
on_intel do
|
||||
url "#{RELEASE_BASE}/v#{version}/fff-mcp-x86_64-unknown-linux-gnu"
|
||||
sha256 "2692bc567f8c5609a179795f5ee95555d783a678acdad9c9883e6730654a057e"
|
||||
sha256 "0408cbac06303b3bf2041181089d8b4974b527883242bdcf8ba599b41c003973"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -45,6 +45,11 @@ sync-js-api-check:
|
||||
build:
|
||||
cargo build --release --no-default-features --features zlob
|
||||
|
||||
# Only the crates the e2e suites load (nvim lua tests + C/bun/node FFI tests),
|
||||
# skipping fff-python (pyo3) and fff-mcp (tokio/rmcp) which e2e never touches.
|
||||
build-e2e:
|
||||
cargo build --release -p fff-nvim -p fff-c --no-default-features --features zlob
|
||||
|
||||
build-c-lib:
|
||||
cargo build --release -p fff-c --no-default-features --features zlob
|
||||
|
||||
@@ -90,7 +95,7 @@ test-setup:
|
||||
fi
|
||||
|
||||
test-rust:
|
||||
cargo test --workspace --no-default-features --features zlob --exclude fff-nvim
|
||||
cargo test --workspace --no-default-features --features zlob --exclude fff-nvim --exclude fff-python
|
||||
|
||||
# Watcher rescan harness: asserts that editing, build output, git activity and
|
||||
# preview reads all stay on the incremental path instead of re-walking the tree.
|
||||
@@ -118,7 +123,7 @@ SMOKE_BIN := $(TARGET_DIR)/fff_c_smoke
|
||||
SMOKE_SRC := crates/fff-c/tests/smoke.c
|
||||
SMOKE_INCLUDE := crates/fff-c/include
|
||||
|
||||
test-c-smoke: build
|
||||
test-c-smoke: build-e2e
|
||||
$(CC) $(CFLAGS) -I $(SMOKE_INCLUDE) -L $(TARGET_DIR) \
|
||||
-Wl,-rpath,@loader_path/../target/release \
|
||||
-Wl,-rpath,$$(pwd)/$(TARGET_DIR) \
|
||||
@@ -131,7 +136,7 @@ test-c-api: test-c-smoke
|
||||
# neovim instance swallows internal crashes and doesn't rise the the error exiting silently
|
||||
# so check the stdout in case the sigsegv coming out of fff was printed (actual regression).
|
||||
# Output is streamed live via `tee`; pipefail (set above) propagates nvim's exit.
|
||||
test-lua: test-setup build
|
||||
test-lua: test-setup build-e2e
|
||||
@logfile=$$(mktemp); \
|
||||
trap 'rm -f "$$logfile"' EXIT; \
|
||||
nvim --headless -u tests/minimal_init.lua \
|
||||
@@ -143,7 +148,7 @@ test-lua: test-setup build
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
test-lua-snap: test-setup build
|
||||
test-lua-snap: test-setup build-e2e
|
||||
@logfile=$$(mktemp); \
|
||||
trap 'rm -f "$$logfile"' EXIT; \
|
||||
nvim --headless -u tests/minimal_init.lua \
|
||||
@@ -159,13 +164,13 @@ test-version: test-setup
|
||||
nvim --headless -u tests/minimal_init.lua \
|
||||
-c "PlenaryBustedFile tests/version_spec.lua" 2>&1
|
||||
|
||||
prepare-bun: build sync-js-api
|
||||
prepare-bun: build-e2e sync-js-api
|
||||
mkdir -p packages/fff-bun/bin
|
||||
cp target/release/libfff_c.dylib packages/fff-bun/bin/ 2>/dev/null || true; \
|
||||
cp target/release/libfff_c.so packages/fff-bun/bin/ 2>/dev/null || true; \
|
||||
cp target/release/fff_c.dll packages/fff-bun/bin/ 2>/dev/null || true
|
||||
|
||||
prepare-node: build sync-js-api
|
||||
prepare-node: build-e2e sync-js-api
|
||||
mkdir -p packages/fff-node/bin
|
||||
cp target/release/libfff_c.dylib packages/fff-node/bin/ 2>/dev/null || true; \
|
||||
cp target/release/libfff_c.so packages/fff-node/bin/ 2>/dev/null || true; \
|
||||
@@ -269,20 +274,7 @@ test-stress: test-stress-seeded test-stress-random test-stress-regressions test-
|
||||
set-npm-version:
|
||||
@test -n "$(PKG)" || (echo "PKG is required" && exit 1)
|
||||
@test -n "$(VERSION)" || (echo "VERSION is required" && exit 1)
|
||||
node -e " \
|
||||
const fs = require('fs'); \
|
||||
const pkg = JSON.parse(fs.readFileSync('$(PKG)/package.json', 'utf8')); \
|
||||
pkg.version = '$(VERSION)'; \
|
||||
if (pkg.optionalDependencies) { \
|
||||
for (const dep of Object.keys(pkg.optionalDependencies)) { \
|
||||
pkg.optionalDependencies[dep] = '$(VERSION)'; \
|
||||
} \
|
||||
} \
|
||||
for (const dep of ['@ff-labs/fff-bun', '@ff-labs/fff-node']) { \
|
||||
if (pkg.dependencies?.[dep]) pkg.dependencies[dep] = '$(VERSION)'; \
|
||||
} \
|
||||
fs.writeFileSync('$(PKG)/package.json', JSON.stringify(pkg, null, 2) + '\n'); \
|
||||
"
|
||||
node scripts/set-npm-version.mjs "$(PKG)" "$(VERSION)"
|
||||
@echo "Set $(PKG) to $(VERSION)"
|
||||
|
||||
format-rust:
|
||||
@@ -290,7 +282,7 @@ format-rust:
|
||||
format-lua:
|
||||
stylua .
|
||||
format-ts:
|
||||
bun format
|
||||
cd packages && bun format
|
||||
|
||||
format: format-rust format-lua format-ts
|
||||
|
||||
@@ -299,7 +291,7 @@ lint-rust:
|
||||
lint-lua:
|
||||
~/.luarocks/bin/luacheck .
|
||||
lint-ts:
|
||||
bun lint
|
||||
cd packages && bun lint
|
||||
|
||||
lint: lint-rust lint-lua lint-ts
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ Three operating modes, switchable at runtime with `/fff-mode`:
|
||||
| `tools-only` | Only tool injection. Keeps pi's native editor autocomplete. |
|
||||
| `override` | Replaces pi's built-in `grep`, `find`, and `multi_grep` with FFF implementations. |
|
||||
|
||||
Env vars: `PI_FFF_MODE`, `FFF_FRECENCY_DB`, `FFF_HISTORY_DB`. Flags: `--fff-mode`, `--fff-frecency-db`, `--fff-history-db`.
|
||||
Env vars: `PI_FFF_MODE`, `FFF_FRECENCY_DB`, `FFF_HISTORY_DB`. Flags: `--fff-mode`, `--fff-frecency-db`, `--fff-history-db`. The databases default to your existing fff.nvim ones when present, otherwise `~/.pi/agent/fff/`.
|
||||
|
||||
### Agent-facing tools
|
||||
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.4.7/schema.json",
|
||||
"files": {
|
||||
"includes": ["packages/**/*.ts", "!packages/*/dist"],
|
||||
"ignoreUnknown": true
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 90
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "always"
|
||||
}
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"style": {
|
||||
"noNonNullAssertion": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off"
|
||||
},
|
||||
"complexity": {
|
||||
"noForEach": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,414 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.4.4",
|
||||
},
|
||||
},
|
||||
"packages/fff-bun": {
|
||||
"name": "@ff-labs/fff-bun",
|
||||
"version": "0.1.37",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.8",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ff-labs/fff-bin-darwin-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-darwin-x64": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-x64": "0.0.0",
|
||||
},
|
||||
},
|
||||
"packages/fff-node": {
|
||||
"name": "@ff-labs/fff-node",
|
||||
"version": "0.1.37",
|
||||
"dependencies": {
|
||||
"ffi-rs": "^1.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ff-labs/fff-bin-darwin-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-darwin-x64": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-x64": "0.0.0",
|
||||
},
|
||||
},
|
||||
"packages/pi-fff": {
|
||||
"name": "@ff-labs/pi-fff",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"@ff-labs/fff-bun": "*",
|
||||
"@ff-labs/fff-node": "*",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@earendil-works/pi-coding-agent": "*",
|
||||
"@earendil-works/pi-tui": "*",
|
||||
"@sinclair/typebox": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.91.1", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw=="],
|
||||
|
||||
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
|
||||
|
||||
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
||||
|
||||
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
|
||||
|
||||
"@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
|
||||
|
||||
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
|
||||
|
||||
"@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/eventstream-handler-node": "^3.972.16", "@aws-sdk/middleware-eventstream": "^3.972.12", "@aws-sdk/middleware-websocket": "^3.972.19", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ=="],
|
||||
|
||||
"@aws-sdk/core": ["@aws-sdk/core@3.974.18", "", { "dependencies": { "@aws-sdk/types": "^3.973.11", "@aws-sdk/xml-builder": "^3.972.28", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.6", "@smithy/signature-v4": "^5.4.6", "@smithy/types": "^4.14.3", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-JDYCPI0j7zGrzXTDFsLB346cxss7J/AxH7+O0MzWlqppJBEyB9Qe6TQXRL6iwLUo/xZkNv9KFmBL2hqElmwW0g=="],
|
||||
|
||||
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.44", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-3hKJVrZ7bqXzDAXCQp+OaQ1ASN+vWstaNuEH418wQVl//cRZhqhfR9Bjk1qIWmgUGe8/D3gdO73PgidRj378EQ=="],
|
||||
|
||||
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.46", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-VhwC9pGAZHhiQ2xSViyOPDFqvr9aRxGCAXZtADsUhU3R65nad7y//CwynE6mQnWNR+suRlqE79W36IVayL+m1g=="],
|
||||
|
||||
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.50", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/credential-provider-env": "^3.972.44", "@aws-sdk/credential-provider-http": "^3.972.46", "@aws-sdk/credential-provider-login": "^3.972.49", "@aws-sdk/credential-provider-process": "^3.972.44", "@aws-sdk/credential-provider-sso": "^3.972.49", "@aws-sdk/credential-provider-web-identity": "^3.972.49", "@aws-sdk/nested-clients": "^3.997.17", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-09Xi6ovxiK42+De/qBGF71sT5F2bWgYM+1fFyDwSOpy1xpsQ5R/naIu7MVDpH6Dic36QNc8dAv4KADtMGK2JYg=="],
|
||||
|
||||
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.49", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/nested-clients": "^3.997.17", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-EfJF/1Fh9mI4pZyoheU2RY9xUhTcugIZNkD63+orXMkYj/QXacJNbKVDUK90Yv5hE+aX+rt9J/EZ9Qr3vKOa7g=="],
|
||||
|
||||
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.52", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.44", "@aws-sdk/credential-provider-http": "^3.972.46", "@aws-sdk/credential-provider-ini": "^3.972.50", "@aws-sdk/credential-provider-process": "^3.972.44", "@aws-sdk/credential-provider-sso": "^3.972.49", "@aws-sdk/credential-provider-web-identity": "^3.972.49", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-7QX+PbyiWBEOVipJq8Nke/TqXT6lAPLE7fvTaopa39/IVWuLfS+Fzdy71sZJONf/mLGgmtj6aU17+REw3+aRrw=="],
|
||||
|
||||
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.44", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-V+UUhZpRP7QDRhi+qgBDisM9tUBnYmMje8Bk77A6MZsfeGeGdMsQXmaHP1CDYFcept0o/Rz5g2Y0TMeVlG9dzg=="],
|
||||
|
||||
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.49", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/nested-clients": "^3.997.17", "@aws-sdk/token-providers": "3.1063.0", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-9QqOYGuh5tZ76OzaT68kwI78AH+5lS/uZGGvkfxb3fc8FzRrIz2jOufNTliEBEeSAwmgK2rWLNsK+IB3zbtNPA=="],
|
||||
|
||||
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.49", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/nested-clients": "^3.997.17", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-IYx1lN38MnnPXv+NBLpuATu0cZakbZ321TAfjW+aVkw7HIJF38YnEwdeEO55MSl3pl7hIX1IvvnD6EmnAzmAJw=="],
|
||||
|
||||
"@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.20", "", { "dependencies": { "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-qr/S1iFCDIXlZwlZPaCqjKcHbJFr9scIFUhbh2+SrwPXZvRhyOUWjVDJpp8xoU4qrrMR0PqK1Yw5C2sSj7xAyw=="],
|
||||
|
||||
"@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.16", "", { "dependencies": { "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-KR2Gdui/QLbkdG9FxW3vk/vIa8KiDP5vQBNERo7MmlPHjn23GXJ53Cq5P/ok7/ALbTUiYZ78DiBHoDcvzPWvgQ=="],
|
||||
|
||||
"@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.26", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/signature-v4": "^5.4.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-foM3KvxGBHY9lRIm6C9JJJ5haodtXfJPPgJQcv5/c4A2pN4I7tlnOjh1o2d8Il1Y/j6GWOw3YeIYc2/VYjtGVQ=="],
|
||||
|
||||
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.17", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.18", "@aws-sdk/signature-v4-multi-region": "^3.996.32", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-lDRgraoTfKRawUyc176Ow93mrNrOho/x+EoK4C+lKU+vKkHWhNhzvSMVAx0WEJUJoeQxxDN5ZdKMfiGEyNejig=="],
|
||||
|
||||
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.32", "", { "dependencies": { "@aws-sdk/types": "^3.973.11", "@smithy/signature-v4": "^5.4.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-llvApLcsWtmRFhG2wT3WIp1CmDeRaIYutqty1ZZXoMzK7TiJ6MOLOimk9eXUS8PwgG4ew4pa4QAbt0lfhn++1w=="],
|
||||
|
||||
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="],
|
||||
|
||||
"@aws-sdk/types": ["@aws-sdk/types@3.973.11", "", { "dependencies": { "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-YjS0qFuECClRh4qhEyW8XagW0fwEPBeZ1cfsW/gU73Kh/ExFILxbzxOfPCmzF/2DwEvhvsHYt0b0qnvStwKYrg=="],
|
||||
|
||||
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.6", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ZfHjfwSzeXj+Lg9AK5ZNmeDkXev6V+w2tn1t4kgDdRtUaRCthepTQiFwbD06EF9oNGH4LaLg+Mb6U16Ypv5bSw=="],
|
||||
|
||||
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.28", "", { "dependencies": { "@smithy/types": "^4.14.3", "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" } }, "sha512-lI/l3c/vPvsxmspzV63NfS3x9q4CkMmdhJy4QiM+NThAufVkDvi/PZZQ6xETnICL0UD7jI808pY83gllf86RFg=="],
|
||||
|
||||
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="],
|
||||
|
||||
"@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
|
||||
|
||||
"@biomejs/biome": ["@biomejs/biome@2.4.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.4", "@biomejs/cli-darwin-x64": "2.4.4", "@biomejs/cli-linux-arm64": "2.4.4", "@biomejs/cli-linux-arm64-musl": "2.4.4", "@biomejs/cli-linux-x64": "2.4.4", "@biomejs/cli-linux-x64-musl": "2.4.4", "@biomejs/cli-win32-arm64": "2.4.4", "@biomejs/cli-win32-x64": "2.4.4" }, "bin": { "biome": "bin/biome" } }, "sha512-tigwWS5KfJf0cABVd52NVaXyAVv4qpUXOWJ1rxFL8xF1RVoeS2q/LK+FHgYoKMclJCuRoCWAPy1IXaN9/mS61Q=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-jZ+Xc6qvD6tTH5jM6eKX44dcbyNqJHssfl2nnwT6vma6B1sj7ZLTGIk6N5QwVBs5xGN52r3trk5fgd3sQ9We9A=="],
|
||||
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-Dh1a/+W+SUCXhEdL7TiX3ArPTFCQKJTI1mGncZNWfO+6suk+gYA4lNyJcBB+pwvF49uw0pEbUS49BgYOY4hzUg=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+sPAXq3bxmFwhVFJnSwkSF5Rw2ZAJMH3MF6C9IveAEOdSpgajPhoQhbbAK12SehN9j2QrHpk4J/cHsa/HqWaYQ=="],
|
||||
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg=="],
|
||||
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g=="],
|
||||
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q=="],
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.4", "", { "os": "win32", "cpu": "x64" }, "sha512-gnOHKVPFAAPrpoPt2t+Q6FZ7RPry/FDV3GcpU53P3PtLNnQjBmKyN2Vh/JtqXet+H4pme8CC76rScwdjDcT1/A=="],
|
||||
|
||||
"@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.78.1", "", { "dependencies": { "@earendil-works/pi-ai": "^0.78.1", "ignore": "7.0.5", "typebox": "1.1.38", "yaml": "2.9.0" } }, "sha512-oPwVRkkAvyKPWyM7E4k+EaTNmynbYn7ZLG/LBh9BUnMNb2gvpMp+VQ420R6JCJ20uogSqrHnWTyosSa/rU8lVw=="],
|
||||
|
||||
"@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.78.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.91.1", "@aws-sdk/client-bedrock-runtime": "3.1048.0", "@google/genai": "1.52.0", "@mistralai/mistralai": "2.2.1", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "openai": "6.26.0", "partial-json": "0.1.7", "typebox": "1.1.38" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-CM2pkTs1iupG/maw381lC9Q/Y/aQaMGK7GILc28ttImD0ci3LDwKroDsGkWbly5JIy3iqxdRxB9JlG7vvzCzTg=="],
|
||||
|
||||
"@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@0.78.1", "", { "dependencies": { "@earendil-works/pi-agent-core": "^0.78.1", "@earendil-works/pi-ai": "^0.78.1", "@earendil-works/pi-tui": "^0.78.1", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", "diff": "8.0.4", "glob": "13.0.6", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.5", "jiti": "2.7.0", "minimatch": "10.2.5", "proper-lockfile": "4.1.2", "typebox": "1.1.38", "undici": "8.3.0", "yaml": "2.9.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "pi": "dist/cli.js" } }, "sha512-Syjf6Ib8UoY5t9ZdKjp0BRrQZuFkFBc8j2KEU9zG/ZnmYPcAxYeioofdv2Q3MEXnHEX2U8sKQptkSnJIdMsd0g=="],
|
||||
|
||||
"@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.78.1", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "15.0.12" } }, "sha512-07GVQo/38a0yvIPlWDr3RJn1B8gk3ZuIX9h2oIQ+Biyu3JN0KppWmgWHfaWRydQgse5JtC++KDw5MWaIRnV0mw=="],
|
||||
|
||||
"@ff-labs/fff-bun": ["@ff-labs/fff-bun@workspace:packages/fff-bun"],
|
||||
|
||||
"@ff-labs/fff-node": ["@ff-labs/fff-node@workspace:packages/fff-node"],
|
||||
|
||||
"@ff-labs/pi-fff": ["@ff-labs/pi-fff@workspace:packages/pi-fff"],
|
||||
|
||||
"@google/genai": ["@google/genai@1.52.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q=="],
|
||||
|
||||
"@mariozechner/clipboard": ["@mariozechner/clipboard@0.3.9", "", { "optionalDependencies": { "@mariozechner/clipboard-darwin-arm64": "0.3.9", "@mariozechner/clipboard-darwin-universal": "0.3.9", "@mariozechner/clipboard-darwin-x64": "0.3.9", "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-musl": "0.3.9", "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" } }, "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA=="],
|
||||
|
||||
"@mariozechner/clipboard-darwin-arm64": ["@mariozechner/clipboard-darwin-arm64@0.3.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ=="],
|
||||
|
||||
"@mariozechner/clipboard-darwin-universal": ["@mariozechner/clipboard-darwin-universal@0.3.9", "", { "os": "darwin" }, "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ=="],
|
||||
|
||||
"@mariozechner/clipboard-darwin-x64": ["@mariozechner/clipboard-darwin-x64@0.3.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-arm64-gnu": ["@mariozechner/clipboard-linux-arm64-gnu@0.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-arm64-musl": ["@mariozechner/clipboard-linux-arm64-musl@0.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-riscv64-gnu": ["@mariozechner/clipboard-linux-riscv64-gnu@0.3.9", "", { "os": "linux", "cpu": "none" }, "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-x64-gnu": ["@mariozechner/clipboard-linux-x64-gnu@0.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-x64-musl": ["@mariozechner/clipboard-linux-x64-musl@0.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ=="],
|
||||
|
||||
"@mariozechner/clipboard-win32-arm64-msvc": ["@mariozechner/clipboard-win32-arm64-msvc@0.3.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ=="],
|
||||
|
||||
"@mariozechner/clipboard-win32-x64-msvc": ["@mariozechner/clipboard-win32-x64-msvc@0.3.9", "", { "os": "win32", "cpu": "x64" }, "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA=="],
|
||||
|
||||
"@mistralai/mistralai": ["@mistralai/mistralai@2.2.1", "", { "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.25.0" } }, "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ=="],
|
||||
|
||||
"@nodable/entities": ["@nodable/entities@2.1.1", "", {}, "sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg=="],
|
||||
|
||||
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
||||
|
||||
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
||||
|
||||
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="],
|
||||
|
||||
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="],
|
||||
|
||||
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="],
|
||||
|
||||
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
|
||||
|
||||
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.2", "", {}, "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw=="],
|
||||
|
||||
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
|
||||
|
||||
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
|
||||
|
||||
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.1", "", {}, "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg=="],
|
||||
|
||||
"@silvia-odwyer/photon-node": ["@silvia-odwyer/photon-node@0.3.4", "", {}, "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA=="],
|
||||
|
||||
"@sinclair/typebox": ["@sinclair/typebox@0.34.49", "", {}, "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A=="],
|
||||
|
||||
"@smithy/core": ["@smithy/core@3.24.6", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-wBXDRup6UU97VKyaiRo8AssnfStPtG0oAAfpq/bC0a1YYau8pM86YB4kM6ccoVi1mS8l/UHbn9oDM+7uozr/ug=="],
|
||||
|
||||
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.8", "", { "dependencies": { "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-5cAM+KZC02sTqDt6NaLXyu50M/GNMd1eTzDVR8Lb0BBsVtu7RWHo47VPPEEv1vt3Yub6uzr+M5FHC+GtoT0USg=="],
|
||||
|
||||
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.4.6", "", { "dependencies": { "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-FEwEYJ1jlBKdhe9TPzfghEi1bP55ZeEImlDkEa62bBBYzUcnB6RUCyuiS2mqKt6ZVjUbBgcNhzfIctH+Hevx9g=="],
|
||||
|
||||
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||
|
||||
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="],
|
||||
|
||||
"@smithy/signature-v4": ["@smithy/signature-v4@5.4.6", "", { "dependencies": { "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-Ojg4B6oIDlIr1R86xCDJt1zJWnYa0VINmqdjfe9qxWjdRivHalZ3iSlQgVqYbW0MdpFOC5XfHEWsnbmdnpIILQ=="],
|
||||
|
||||
"@smithy/types": ["@smithy/types@4.14.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YupL0ZWmFtJexUN2cHzkvvF/b9pKrtAIfT1o7/oY/Ppu8IYeZ+lDPM5vZdQJaSeA132dJCqojjGC9NhXeF71VQ=="],
|
||||
|
||||
"@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||
|
||||
"@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
||||
|
||||
"@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
|
||||
|
||||
"@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="],
|
||||
|
||||
"@yuuang/ffi-rs-android-arm64": ["@yuuang/ffi-rs-android-arm64@1.3.1", "", { "os": "android", "cpu": "arm64" }, "sha512-V4nmlXdOYZEa7GOxSExVG95SLp8FE0iTq2yKeN54UlfNMr3Sik+1Ff57LcCv7qYcn4TBqnBAt5rT3FAM6T6caQ=="],
|
||||
|
||||
"@yuuang/ffi-rs-darwin-arm64": ["@yuuang/ffi-rs-darwin-arm64@1.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YlnTMIyzfW3mAULC5ZA774nzQfFlYXM0rrfq/8ZzWt+IMbYk55a++jrI+6JeKV+1EqlDS3TFBEFtjdBNG94KzQ=="],
|
||||
|
||||
"@yuuang/ffi-rs-darwin-x64": ["@yuuang/ffi-rs-darwin-x64@1.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-sI3LpQQ34SX4nyOHc5yxA7FSqs9qPEUMqW/y/wWo9cuyPpaHMFsi/BeOVYsnC0syp3FrY7gzn6RnD6PlXCktXg=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-arm-gnueabihf": ["@yuuang/ffi-rs-linux-arm-gnueabihf@1.3.1", "", { "os": "linux", "cpu": "arm" }, "sha512-1WkcGkJTlwh4ZA59htKI+RXhiL3oKiYwLv7PO8LUf6FuADK73s5GcXp67iakKu243uYu+qGYr4RHco4ySddYhQ=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-arm64-gnu": ["@yuuang/ffi-rs-linux-arm64-gnu@1.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-J2PwqviycZxaEVA0Bwv38LqGDGSB9A1DPN4iYginYJZSvTvKW8kh7Tis0HbZrX1YDKnY8hi3lt0N0tCTNPDH5Q=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-arm64-musl": ["@yuuang/ffi-rs-linux-arm64-musl@1.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Hn1W1hBPssTaqikU1Bqp1XUdDdOgbnYVIOtR++LVx66hhrtjf/xrIUQOhTm+NmOFDG16JUKXe1skfM4gpaqYwg=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-x64-gnu": ["@yuuang/ffi-rs-linux-x64-gnu@1.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-kW6e+oCYZPvpH2ppPsffA18e1aLowtmWTRjVlyHtY04g/nQDepQvDUkkcvInh9fW5jLna7PjHvktW1tVgYIj2A=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-x64-musl": ["@yuuang/ffi-rs-linux-x64-musl@1.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HTwblAzruUS16nQPrez3ozvEHm1Xxh8J8w7rZYrpmAcNl1hzyOT8z/hY70M9Rt9fOqQ4Ovgor9qVy/U3ZJo0ZA=="],
|
||||
|
||||
"@yuuang/ffi-rs-win32-arm64-msvc": ["@yuuang/ffi-rs-win32-arm64-msvc@1.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-WeZkGl2BP1U4tRhEQH+FXLQS52N8obp74smK5AAGOfzPAT1pHkq6+dVkC1QCSIt7dHJs7SPtlnQw+5DkdZYlWA=="],
|
||||
|
||||
"@yuuang/ffi-rs-win32-ia32-msvc": ["@yuuang/ffi-rs-win32-ia32-msvc@1.3.1", "", { "os": "win32", "cpu": [ "x64", "ia32", ] }, "sha512-rNGgMeCH5mdeHiMiJgt7wWXovZ+FHEfXhU9p4zZBH4n8M1/QnEsRUwlapISPLpILSGpoYS6iBuq9/fUlZY8Mhg=="],
|
||||
|
||||
"@yuuang/ffi-rs-win32-x64-msvc": ["@yuuang/ffi-rs-win32-x64-msvc@1.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-dr2LcLD2CXo2a7BktlOpV68QhayqiI112KxIJC9tBgQO/Dkdg4CPsdqmvzzLhFo64iC5RLl2BT7M5lJImrfUWw=="],
|
||||
|
||||
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
||||
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
|
||||
|
||||
"bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="],
|
||||
|
||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="],
|
||||
|
||||
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||
|
||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||
|
||||
"fast-xml-builder": ["fast-xml-builder@1.2.0", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="],
|
||||
|
||||
"fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
|
||||
|
||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||
|
||||
"ffi-rs": ["ffi-rs@1.3.1", "", { "optionalDependencies": { "@yuuang/ffi-rs-android-arm64": "1.3.1", "@yuuang/ffi-rs-darwin-arm64": "1.3.1", "@yuuang/ffi-rs-darwin-x64": "1.3.1", "@yuuang/ffi-rs-linux-arm-gnueabihf": "1.3.1", "@yuuang/ffi-rs-linux-arm64-gnu": "1.3.1", "@yuuang/ffi-rs-linux-arm64-musl": "1.3.1", "@yuuang/ffi-rs-linux-x64-gnu": "1.3.1", "@yuuang/ffi-rs-linux-x64-musl": "1.3.1", "@yuuang/ffi-rs-win32-arm64-msvc": "1.3.1", "@yuuang/ffi-rs-win32-ia32-msvc": "1.3.1", "@yuuang/ffi-rs-win32-x64-msvc": "1.3.1" } }, "sha512-ZyNXL9fnclnZV+waQmWB9JrfbIEyxQa1OWtMrHOrAgcC04PgP5hBMG5TdhVN8N4uT/eul8zCFMVnJUukAFFlXA=="],
|
||||
|
||||
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
||||
|
||||
"gaxios": ["gaxios@7.1.5", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg=="],
|
||||
|
||||
"gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
|
||||
|
||||
"glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
|
||||
|
||||
"google-auth-library": ["google-auth-library@10.7.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ=="],
|
||||
|
||||
"google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
|
||||
|
||||
"hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
|
||||
|
||||
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
||||
|
||||
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
||||
|
||||
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
|
||||
|
||||
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
|
||||
|
||||
"json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
|
||||
|
||||
"jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
|
||||
|
||||
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
|
||||
|
||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="],
|
||||
|
||||
"marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
|
||||
|
||||
"minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||
|
||||
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
||||
|
||||
"openai": ["openai@6.26.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA=="],
|
||||
|
||||
"p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="],
|
||||
|
||||
"partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="],
|
||||
|
||||
"path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||
|
||||
"proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="],
|
||||
|
||||
"protobufjs": ["protobufjs@7.6.2", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-N9EiLovGEQOJSPF26Ij7qUGvahfEnq0eeYZ02aigIedkmz1qZSwjnP9SBITHJuF/6MYbIW4HDN8zdYjsjqJKXQ=="],
|
||||
|
||||
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="],
|
||||
|
||||
"ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typebox": ["typebox@1.1.38", "", {}, "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici": ["undici@8.3.0", "", {}, "sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="],
|
||||
|
||||
"xml-naming": ["xml-naming@0.1.0", "", {}, "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="],
|
||||
|
||||
"yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
|
||||
|
||||
"zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
|
||||
|
||||
"zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
||||
|
||||
"@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.7", "", { "dependencies": { "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-ZAFvHXrEk6K180EVhmZVg8GU5pUH5BSFqRs27JW3j1qEFx9YyYwWFx17x/MHcjALYimGAji7qEOlF1++be+G5A=="],
|
||||
|
||||
"@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1063.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.18", "@aws-sdk/nested-clients": "^3.997.17", "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-nYDaWWdzjKiDP5xj8k4oUgcYd4WPgzfAOgdU5vJsaqH/07Dfvm7ffisHCFJ+NEl7kUC9JEIUxh0kznvenbo3NQ=="],
|
||||
|
||||
"@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.7", "", { "dependencies": { "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-ZAFvHXrEk6K180EVhmZVg8GU5pUH5BSFqRs27JW3j1qEFx9YyYwWFx17x/MHcjALYimGAji7qEOlF1++be+G5A=="],
|
||||
|
||||
"bun-types/@types/node": ["@types/node@25.3.3", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ=="],
|
||||
|
||||
"p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
|
||||
|
||||
"protobufjs/@types/node": ["@types/node@25.3.3", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ=="],
|
||||
|
||||
"bun-types/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||
|
||||
"protobufjs/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fff-c"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
description = "Raw C api of FFF file finder"
|
||||
license = "MIT"
|
||||
@@ -19,6 +19,6 @@ zlob = ["fff/zlob", "fff-query-parser/zlob"]
|
||||
[dependencies]
|
||||
git2.workspace = true
|
||||
|
||||
fff = { package = "fff-search", path = "../fff-core", version = "0.10.3", default-features = false }
|
||||
fff-query-parser = { path = "../fff-query-parser", version = "0.10.3", default-features = false }
|
||||
fff = { package = "fff-search", path = "../fff-core", version = "0.10.5", default-features = false }
|
||||
fff-query-parser = { path = "../fff-query-parser", version = "0.10.5", default-features = false }
|
||||
serde_json = "1.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fff-search"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
authors = ["Dmitriy Kovalenko <dmtr.kovalenko@outlook.com>"]
|
||||
@@ -11,7 +11,7 @@ workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["rlib", "staticlib", "cdylib"]
|
||||
crate-type = ["rlib"]
|
||||
|
||||
[[bench]]
|
||||
name = "parse_bench"
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct DbHealth {
|
||||
}
|
||||
|
||||
pub trait DbHealthChecker {
|
||||
fn get_env(&self) -> &heed::Env;
|
||||
fn get_env(&self) -> &heed::Env<heed::WithoutTls>;
|
||||
fn is_healthy(&self) -> bool;
|
||||
/// Entries per database, each group has a static string label
|
||||
fn count_entries(&self) -> Result<Vec<(&'static str, u64)>>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use heed::{Env, EnvOpenOptions};
|
||||
use heed::{Env, EnvOpenOptions, WithoutTls};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::ops::Deref;
|
||||
@@ -19,7 +19,7 @@ pub(crate) struct EnvSpec {
|
||||
}
|
||||
|
||||
pub(crate) struct PooledEnv {
|
||||
env: Env,
|
||||
env: Env<WithoutTls>,
|
||||
key: PathBuf,
|
||||
/// lmdb's env spec label
|
||||
label: &'static str,
|
||||
@@ -47,8 +47,8 @@ impl Drop for PooledEnv {
|
||||
pub(crate) struct SharedEnv(Arc<PooledEnv>);
|
||||
|
||||
impl Deref for SharedEnv {
|
||||
type Target = Env;
|
||||
fn deref(&self) -> &Env {
|
||||
type Target = Env<WithoutTls>;
|
||||
fn deref(&self) -> &Env<WithoutTls> {
|
||||
&self.0.env
|
||||
}
|
||||
}
|
||||
@@ -92,8 +92,11 @@ impl SharedEnv {
|
||||
|
||||
erase_if_oversized(&path, spec);
|
||||
let result = unsafe {
|
||||
let mut opts = EnvOpenOptions::new();
|
||||
// MDB_NOTLS: reader slots are tied to txn objects (freed on
|
||||
// commit/abort) instead of pinned per thread for its lifetime (#783).
|
||||
let mut opts = EnvOpenOptions::new().read_txn_without_tls();
|
||||
opts.map_size(spec.map_size);
|
||||
opts.max_readers(max_readers());
|
||||
if spec.max_dbs > 0 {
|
||||
opts.max_dbs(spec.max_dbs);
|
||||
}
|
||||
@@ -219,6 +222,23 @@ const MAX_TRANSIENT_RETRIES: u32 = 8;
|
||||
|
||||
// Concurrent mdb_env_open calls on the same path can race on macOS
|
||||
// this is for some reason fixable by simple retry of the open
|
||||
// heed's default reader table is 126 slots. In TLS mode each thread pins a slot
|
||||
// for its lifetime, so long-lived embedders (Neovim, node agents) that share one
|
||||
// lock file across many processes/threads exhaust it (#783). Reader slots are
|
||||
// tiny (~64B), so raise the ceiling; `FFF_LMDB_MAX_READERS` lets hosts tune it.
|
||||
const DEFAULT_MAX_READERS: u32 = 1024;
|
||||
|
||||
fn max_readers() -> u32 {
|
||||
parse_max_readers(std::env::var("FFF_LMDB_MAX_READERS").ok())
|
||||
}
|
||||
|
||||
// Never drop below heed's default 126; ignore missing/garbage/too-small values.
|
||||
fn parse_max_readers(raw: Option<String>) -> u32 {
|
||||
raw.and_then(|v| v.trim().parse::<u32>().ok())
|
||||
.filter(|&n| n >= 126)
|
||||
.unwrap_or(DEFAULT_MAX_READERS)
|
||||
}
|
||||
|
||||
fn is_transient_env_open_error(err: &heed::Error) -> bool {
|
||||
match err {
|
||||
heed::Error::Io(io) => matches!(
|
||||
@@ -248,3 +268,17 @@ fn erase_if_oversized(db_path: &Path, spec: &EnvSpec) {
|
||||
let _ = fs::remove_file(&data);
|
||||
let _ = fs::remove_file(db_path.join("lock.mdb"));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{DEFAULT_MAX_READERS, parse_max_readers};
|
||||
|
||||
#[test]
|
||||
fn max_readers_parsing() {
|
||||
assert_eq!(parse_max_readers(None), DEFAULT_MAX_READERS);
|
||||
assert_eq!(parse_max_readers(Some("nan".into())), DEFAULT_MAX_READERS);
|
||||
assert_eq!(parse_max_readers(Some("64".into())), DEFAULT_MAX_READERS); // below 126 floor
|
||||
assert_eq!(parse_max_readers(Some(" 512 ".into())), 512);
|
||||
assert_eq!(parse_max_readers(Some("126".into())), 126);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ const AI_MODIFICATION_THRESHOLDS: [(i64, u64); 5] = [
|
||||
];
|
||||
|
||||
impl DbHealthChecker for FrecencyTracker {
|
||||
fn get_env(&self) -> &heed::Env {
|
||||
fn get_env(&self) -> &heed::Env<heed::WithoutTls> {
|
||||
&self.env
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use heed::{Database, Env};
|
||||
use heed::{Database, Env, WithoutTls};
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
@@ -124,7 +124,7 @@ pub(crate) trait LmdbStore: Sized + Send + Sync + 'static {
|
||||
fn health(&self) -> &DbHealth;
|
||||
|
||||
/// Borrow the raw heed env.
|
||||
fn env(&self) -> &Env {
|
||||
fn env(&self) -> &Env<WithoutTls> {
|
||||
self.shared_env()
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ pub struct QueryTracker {
|
||||
}
|
||||
|
||||
impl DbHealthChecker for QueryTracker {
|
||||
fn get_env(&self) -> &Env {
|
||||
fn get_env(&self) -> &Env<heed::WithoutTls> {
|
||||
&self.env
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ impl QueryTracker {
|
||||
/// offset=0 returns most recent, offset=1 returns 2nd most recent, etc.
|
||||
fn read_history_at_offset(
|
||||
db: &Database<Bytes, SerdeBincode<VecDeque<HistoryEntry>>>,
|
||||
env: &Env,
|
||||
env: &Env<heed::WithoutTls>,
|
||||
project_key: &[u8; 32],
|
||||
offset: usize,
|
||||
) -> Result<Option<String>, Error> {
|
||||
|
||||
@@ -264,7 +264,8 @@ impl BigramIndexBuilder {
|
||||
fn flush_seen(&self, seen: &[u64; SEEN_WORDS], word_idx: usize, bit_mask: u64) {
|
||||
let col_base = self.col_data_ptr();
|
||||
let words = self.words;
|
||||
for (blk, block) in seen.chunks_exact(8).enumerate() {
|
||||
// SEEN_WORDS is a multiple of 8, so the remainder is always empty.
|
||||
for (blk, block) in seen.as_chunks::<8>().0.iter().enumerate() {
|
||||
// OR-test whole blocks so the mostly-empty bitmap scans fast.
|
||||
if block.iter().fold(0u64, |a, &w| a | w) == 0 {
|
||||
continue;
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
// Repro for #783: fff opens LMDB envs with only map_size set, leaving heed's
|
||||
// default max_readers (126) and default TLS mode. Long-lived threads each pin a
|
||||
// reader slot for the thread's lifetime, so >126 live reader threads exhaust the
|
||||
// table with MDB_READERS_FULL.
|
||||
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Barrier, mpsc};
|
||||
use std::time::Duration;
|
||||
|
||||
use heed::EnvOpenOptions;
|
||||
|
||||
// This binary links heed directly without the fff lib, so nothing pulls in
|
||||
// advapi32 for lmdb's security-descriptor calls in mdb_env_setup_locks.
|
||||
#[cfg(windows)]
|
||||
#[link(name = "advapi32")]
|
||||
unsafe extern "C" {}
|
||||
|
||||
fn temp_env_dir(name: &str) -> std::path::PathBuf {
|
||||
let dir = std::env::temp_dir().join(format!("fff-readers-{name}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
dir
|
||||
}
|
||||
|
||||
// Regression for #783: with only map_size set (pre-fix), heed's default 126
|
||||
// reader slots are exhausted once >126 live threads each hold a read txn. fff now
|
||||
// raises max_readers, so this many live readers must all get a slot.
|
||||
const FFF_MAX_READERS: u32 = 1024;
|
||||
|
||||
#[test]
|
||||
fn raised_max_readers_admits_more_than_126_live_readers() {
|
||||
let dir = temp_env_dir("raised");
|
||||
let env = unsafe {
|
||||
EnvOpenOptions::new()
|
||||
.map_size(10 * 1024 * 1024)
|
||||
.max_readers(FFF_MAX_READERS)
|
||||
.open(&dir)
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
const THREADS: usize = 200;
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
let ready = Arc::new(Barrier::new(THREADS + 1));
|
||||
let readers_full = Arc::new(AtomicBool::new(false));
|
||||
let (tx, rx) = mpsc::channel::<bool>(); // true = read txn acquired
|
||||
|
||||
let mut handles = Vec::new();
|
||||
for _ in 0..THREADS {
|
||||
let env = env.clone();
|
||||
let stop = stop.clone();
|
||||
let ready = ready.clone();
|
||||
let readers_full = readers_full.clone();
|
||||
let tx = tx.clone();
|
||||
handles.push(std::thread::spawn(move || {
|
||||
match env.read_txn() {
|
||||
Ok(txn) => {
|
||||
tx.send(true).ok();
|
||||
ready.wait();
|
||||
while !stop.load(Ordering::Relaxed) {
|
||||
std::thread::park_timeout(Duration::from_millis(5));
|
||||
}
|
||||
drop(txn); // hold the slot for the whole test
|
||||
}
|
||||
Err(e) => {
|
||||
if e.to_string().contains("MDB_READERS_FULL") {
|
||||
readers_full.store(true, Ordering::Relaxed);
|
||||
}
|
||||
tx.send(false).ok();
|
||||
ready.wait();
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
drop(tx);
|
||||
|
||||
// Collect exactly one result per thread; parked threads keep their tx clone
|
||||
// alive, so we must not wait for the channel to close.
|
||||
let acquired = AtomicUsize::new(0);
|
||||
for _ in 0..THREADS {
|
||||
if rx.recv().unwrap() {
|
||||
acquired.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
ready.wait();
|
||||
|
||||
let acquired = acquired.load(Ordering::Relaxed);
|
||||
stop.store(true, Ordering::Relaxed);
|
||||
for h in handles {
|
||||
h.join().unwrap();
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
|
||||
// With max_readers raised, all 200 live reader threads must get a slot and
|
||||
// none may see MDB_READERS_FULL. On the pre-fix default of 126 this plateaus
|
||||
// at 126 and the rest fail.
|
||||
assert!(
|
||||
!readers_full.load(Ordering::Relaxed),
|
||||
"MDB_READERS_FULL hit: only {acquired}/{THREADS} live reader threads got a slot"
|
||||
);
|
||||
assert_eq!(
|
||||
acquired, THREADS,
|
||||
"all {THREADS} live reader threads should get a slot; got {acquired}"
|
||||
);
|
||||
}
|
||||
|
||||
// Structural fix for #783: with MDB_NOTLS a reader slot is tied to the txn
|
||||
// object and freed on drop, not pinned per thread. 200 long-lived threads each
|
||||
// open+drop a txn against the *default* 126-slot table; in TLS mode this
|
||||
// plateaus at 126, in NOTLS mode every thread must succeed.
|
||||
#[test]
|
||||
fn notls_releases_slots_of_live_threads() {
|
||||
let dir = temp_env_dir("notls");
|
||||
let env = unsafe {
|
||||
EnvOpenOptions::new()
|
||||
.read_txn_without_tls()
|
||||
.map_size(10 * 1024 * 1024)
|
||||
.open(&dir)
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
const THREADS: usize = 200;
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
let ready = Arc::new(Barrier::new(THREADS + 1));
|
||||
// Serialize txns so the test measures slot *release*, not concurrency.
|
||||
let txn_gate = Arc::new(std::sync::Mutex::new(()));
|
||||
let acquired = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let mut handles = Vec::new();
|
||||
for _ in 0..THREADS {
|
||||
let env = env.clone();
|
||||
let stop = stop.clone();
|
||||
let ready = ready.clone();
|
||||
let txn_gate = txn_gate.clone();
|
||||
let acquired = acquired.clone();
|
||||
handles.push(std::thread::spawn(move || {
|
||||
{
|
||||
let _gate = txn_gate.lock().unwrap();
|
||||
if let Ok(txn) = env.read_txn() {
|
||||
acquired.fetch_add(1, Ordering::Relaxed);
|
||||
drop(txn); // NOTLS: slot returns to the pool here
|
||||
}
|
||||
}
|
||||
// Stay alive: in TLS mode this thread would keep its slot pinned.
|
||||
ready.wait();
|
||||
while !stop.load(Ordering::Relaxed) {
|
||||
std::thread::park_timeout(Duration::from_millis(5));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
ready.wait();
|
||||
let got = acquired.load(Ordering::Relaxed);
|
||||
stop.store(true, Ordering::Relaxed);
|
||||
for h in handles {
|
||||
h.join().unwrap();
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
|
||||
assert_eq!(
|
||||
got, THREADS,
|
||||
"NOTLS must free slots on txn drop; only {got}/{THREADS} live threads got one"
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ name = "fff-grep"
|
||||
description = "File grepping logic for fff"
|
||||
license = "MIT"
|
||||
authors = ["Dmitriy Kovalenko <dmtr.kovalenko@outlok.com>"]
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fff-mcp"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
description = "MCP server for FFF file finder - drop-in replacement for AI code assistant search tools"
|
||||
license = "MIT"
|
||||
@@ -19,8 +19,8 @@ ripgrep = ["fff/ripgrep", "fff-query-parser/ripgrep"]
|
||||
zlob = ["fff/zlob", "fff-query-parser/zlob"]
|
||||
|
||||
[dependencies]
|
||||
fff = { package = "fff-search", path = "../fff-core", default-features = false , version = "0.10.3", features = ["definitions"] }
|
||||
fff-query-parser = { path = "../fff-query-parser", default-features = false , version = "0.10.3" }
|
||||
fff = { package = "fff-search", path = "../fff-core", default-features = false , version = "0.10.5", features = ["definitions"] }
|
||||
fff-query-parser = { path = "../fff-query-parser", default-features = false , version = "0.10.5" }
|
||||
mimalloc = { workspace = true }
|
||||
rmcp = { version = "1.7.0", features = ["server", "transport-io"] }
|
||||
schemars = "1.0"
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
use rmcp::model::{ClientRequest, ErrorCode, ErrorData, JsonRpcMessage};
|
||||
use rmcp::service::{RoleServer, RxJsonRpcMessage, TxJsonRpcMessage};
|
||||
use rmcp::transport::Transport;
|
||||
|
||||
/// rmcp aborts startup on any pre-`initialize` request except `ping`, which kills the process
|
||||
/// before the client can retry. Answer such probes with `-32601` and keep waiting for the legacy
|
||||
/// handshake, so clients speaking the stateless spec (`server/discover`, SEP-1442) can fall back.
|
||||
/// @see https://github.com/dmtrKovalenko/fff/issues/797
|
||||
pub(crate) struct ProbeTolerantTransport<T> {
|
||||
inner: T,
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl<T> ProbeTolerantTransport<T> {
|
||||
pub(crate) fn new(inner: T) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Transport<RoleServer> for ProbeTolerantTransport<T>
|
||||
where
|
||||
T: Transport<RoleServer>,
|
||||
{
|
||||
type Error = T::Error;
|
||||
|
||||
fn send(
|
||||
&mut self,
|
||||
item: TxJsonRpcMessage<RoleServer>,
|
||||
) -> impl Future<Output = Result<(), Self::Error>> + Send + 'static {
|
||||
self.inner.send(item)
|
||||
}
|
||||
|
||||
async fn receive(&mut self) -> Option<RxJsonRpcMessage<RoleServer>> {
|
||||
loop {
|
||||
let msg = self.inner.receive().await?;
|
||||
if self.initialized {
|
||||
return Some(msg);
|
||||
}
|
||||
|
||||
let JsonRpcMessage::Request(request) = &msg else {
|
||||
return Some(msg);
|
||||
};
|
||||
|
||||
match &request.request {
|
||||
ClientRequest::InitializeRequest(_) => {
|
||||
self.initialized = true;
|
||||
return Some(msg);
|
||||
}
|
||||
// rmcp answers pre-init pings itself
|
||||
ClientRequest::PingRequest(_) => return Some(msg),
|
||||
unsupported => {
|
||||
let error = unsupported_probe_error(unsupported.method());
|
||||
tracing::warn!(
|
||||
method = unsupported.method(),
|
||||
"rejecting pre-initialize request, awaiting initialize"
|
||||
);
|
||||
let id = request.id.clone();
|
||||
self.inner
|
||||
.send(JsonRpcMessage::error(error, Some(id)))
|
||||
.await
|
||||
.ok()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&mut self) -> impl Future<Output = Result<(), Self::Error>> + Send {
|
||||
self.inner.close()
|
||||
}
|
||||
}
|
||||
|
||||
fn unsupported_probe_error(method: &str) -> ErrorData {
|
||||
ErrorData::new(
|
||||
ErrorCode::METHOD_NOT_FOUND,
|
||||
format!(
|
||||
"{method} is not supported before initialize; this server uses the initialize handshake"
|
||||
),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rmcp::model::{
|
||||
ClientCapabilities, ClientJsonRpcMessage, CustomRequest, Implementation, InitializeRequest,
|
||||
InitializeRequestParams, NumberOrString, ServerJsonRpcMessage,
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Default)]
|
||||
struct MockTransport {
|
||||
incoming: VecDeque<ClientJsonRpcMessage>,
|
||||
sent: Vec<ServerJsonRpcMessage>,
|
||||
}
|
||||
|
||||
impl Transport<RoleServer> for MockTransport {
|
||||
type Error = std::io::Error;
|
||||
|
||||
fn send(
|
||||
&mut self,
|
||||
item: ServerJsonRpcMessage,
|
||||
) -> impl Future<Output = Result<(), Self::Error>> + Send + 'static {
|
||||
self.sent.push(item);
|
||||
async { Ok(()) }
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> impl Future<Output = Option<ClientJsonRpcMessage>> + Send {
|
||||
let next = self.incoming.pop_front();
|
||||
async move { next }
|
||||
}
|
||||
|
||||
async fn close(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn custom_request(id: i64, method: &str) -> ClientJsonRpcMessage {
|
||||
ClientJsonRpcMessage::request(
|
||||
ClientRequest::CustomRequest(CustomRequest::new(method, Some(serde_json::json!({})))),
|
||||
NumberOrString::Number(id),
|
||||
)
|
||||
}
|
||||
|
||||
fn initialize_request(id: i64) -> ClientJsonRpcMessage {
|
||||
ClientJsonRpcMessage::request(
|
||||
ClientRequest::InitializeRequest(InitializeRequest::new(InitializeRequestParams::new(
|
||||
ClientCapabilities::default(),
|
||||
Implementation::new("probe", "1"),
|
||||
))),
|
||||
NumberOrString::Number(id),
|
||||
)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn pre_init_probe_is_rejected_and_initialize_still_arrives() {
|
||||
let inner = MockTransport {
|
||||
incoming: VecDeque::from(vec![
|
||||
custom_request(1, "server/discover"),
|
||||
initialize_request(2),
|
||||
]),
|
||||
sent: Vec::new(),
|
||||
};
|
||||
let mut transport = ProbeTolerantTransport::new(inner);
|
||||
|
||||
let received = transport.receive().await.expect("initialize forwarded");
|
||||
assert!(matches!(
|
||||
received,
|
||||
JsonRpcMessage::Request(req)
|
||||
if matches!(req.request, ClientRequest::InitializeRequest(_))
|
||||
));
|
||||
|
||||
let JsonRpcMessage::Error(err) = &transport.inner.sent[0] else {
|
||||
panic!("expected an error response for the probe");
|
||||
};
|
||||
assert_eq!(err.id, Some(NumberOrString::Number(1)));
|
||||
assert_eq!(err.error.code, ErrorCode::METHOD_NOT_FOUND);
|
||||
assert!(err.error.message.contains("server/discover"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn post_init_requests_pass_through_untouched() {
|
||||
let inner = MockTransport {
|
||||
incoming: VecDeque::from(vec![
|
||||
initialize_request(1),
|
||||
custom_request(2, "server/discover"),
|
||||
]),
|
||||
sent: Vec::new(),
|
||||
};
|
||||
let mut transport = ProbeTolerantTransport::new(inner);
|
||||
|
||||
transport.receive().await.expect("initialize forwarded");
|
||||
let received = transport.receive().await.expect("custom request forwarded");
|
||||
assert!(matches!(
|
||||
received,
|
||||
JsonRpcMessage::Request(req)
|
||||
if matches!(req.request, ClientRequest::CustomRequest(_))
|
||||
));
|
||||
assert!(transport.inner.sent.is_empty());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod cursor;
|
||||
mod handshake;
|
||||
mod healthcheck;
|
||||
mod output;
|
||||
mod parent;
|
||||
@@ -12,8 +13,10 @@ use fff::file_picker::FilePicker;
|
||||
use fff::frecency::FrecencyTracker;
|
||||
use fff::{FFFMode, SharedFilePicker, SharedFrecency};
|
||||
use git2::Repository;
|
||||
use handshake::ProbeTolerantTransport;
|
||||
use mimalloc::MiMalloc;
|
||||
use rmcp::{ServiceExt, transport::stdio};
|
||||
use rmcp::ServiceExt;
|
||||
use rmcp::transport::async_rw::AsyncRwTransport;
|
||||
use server::FffServer;
|
||||
|
||||
#[global_allocator]
|
||||
@@ -340,7 +343,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
});
|
||||
|
||||
const STARTUP_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60);
|
||||
let service = match tokio::time::timeout(STARTUP_TIMEOUT, server.serve(stdio())).await {
|
||||
let stdio = AsyncRwTransport::new_server(tokio::io::stdin(), tokio::io::stdout());
|
||||
let transport = ProbeTolerantTransport::new(stdio);
|
||||
let service = match tokio::time::timeout(STARTUP_TIMEOUT, server.serve(transport)).await {
|
||||
Ok(res) => res.map_err(|e| format!("Failed to start MCP server: {}", e))?,
|
||||
Err(_) => {
|
||||
return Err("MCP initialize handshake did not complete within 60s".into());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fff-nvim"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
@@ -24,10 +24,10 @@ ahash = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
# Local crates
|
||||
fff = { package = "fff-search", path = "../fff-core", version = "0.10.3", default-features = false, features = [
|
||||
fff = { package = "fff-search", path = "../fff-core", version = "0.10.5", default-features = false, features = [
|
||||
"mimalloc-collect",
|
||||
] }
|
||||
fff-query-parser = { path = "../fff-query-parser", version = "0.10.3", default-features = false }
|
||||
fff-query-parser = { path = "../fff-query-parser", version = "0.10.5", default-features = false }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
ctrlc = "3.4.2"
|
||||
git2 = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fff-python"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
@@ -17,7 +17,7 @@ ripgrep = ["fff/ripgrep", "fff-query-parser/ripgrep"]
|
||||
zlob = ["fff/zlob", "fff-query-parser/zlob"]
|
||||
|
||||
[dependencies]
|
||||
fff = { package = "fff-search", path = "../fff-core", version = "0.10.3", default-features = false }
|
||||
fff-query-parser = { path = "../fff-query-parser", version = "0.10.3", default-features = false }
|
||||
fff = { package = "fff-search", path = "../fff-core", version = "0.10.5", default-features = false }
|
||||
fff-query-parser = { path = "../fff-query-parser", version = "0.10.5", default-features = false }
|
||||
git2 = { workspace = true }
|
||||
pyo3 = { version = "0.24.0", features = ["extension-module", "abi3-py310"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fff-query-parser"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
edition = "2024"
|
||||
description = "Query parser for fff file finder - includes specific syntax for various constraints like globs, extensions, regex etc"
|
||||
license = "MIT"
|
||||
|
||||
+7
-7
@@ -8,14 +8,14 @@ REPO="dmtrKovalenko/fff"
|
||||
BINARY_NAME="fff-mcp"
|
||||
INSTALL_DIR="${FFF_MCP_INSTALL_DIR:-$HOME/.local/bin}"
|
||||
|
||||
PINNED_RELEASE_TAG="v0.10.3"
|
||||
PINNED_RELEASE_TAG="v0.10.5"
|
||||
|
||||
SHA256_X86_64_UNKNOWN_LINUX_MUSL="8823476699977f3dbfe351862f083163810f66656522007cbb65be140c71994c"
|
||||
SHA256_AARCH64_UNKNOWN_LINUX_MUSL="f2092d02c26523476b19361c3fbe2e82033232efdd2e0bee9e7cdbbb31e9436a"
|
||||
SHA256_X86_64_APPLE_DARWIN="f72c31c7f3355d37ec526ba56fd716341bd7186a15a399910cf3f2b46fef2099"
|
||||
SHA256_AARCH64_APPLE_DARWIN="8c52acf1e95540f02cf55579126ebf580cf48af15c76e1c90301c2c8c5acbcf9"
|
||||
SHA256_X86_64_PC_WINDOWS_MSVC="7e4d5c007e65e70f7070b3fa39867cd48827873acebf981d933eef7b339759ce"
|
||||
SHA256_AARCH64_PC_WINDOWS_MSVC="ef677422bf5344b3e4c5952c6b5885f3e9b4d0e7608684de1f5fd56bcd3d22ad"
|
||||
SHA256_X86_64_UNKNOWN_LINUX_MUSL="6ab4f411eeee83e7e3900450b23bb50172e4f93d24dc720265126f0c3a1b1f23"
|
||||
SHA256_AARCH64_UNKNOWN_LINUX_MUSL="e5e315a57dc9b282e2105172fb299883e1cf9bb63c2a36dd493f23763c8fdd4d"
|
||||
SHA256_X86_64_APPLE_DARWIN="c81e22a7fb657731a7441be877c622a110eb7e7dbc94e3b57d79c9cea91f38db"
|
||||
SHA256_AARCH64_APPLE_DARWIN="2f1a75c2401e5df7f5a10827f9ce9fe8401f290ff99c3f3f1423c7d7b156d849"
|
||||
SHA256_X86_64_PC_WINDOWS_MSVC="3fa325ab186e331d4e0e04c38272931b5877f18016e6eb847cdb80dc9a5465c4"
|
||||
SHA256_AARCH64_PC_WINDOWS_MSVC="c5415532417aa0594f5e9ebcf80904f9c6503be995f055788aa022b8353a48b1"
|
||||
|
||||
expected_sha_for() {
|
||||
case "$1" in
|
||||
|
||||
+1
-4
@@ -167,10 +167,7 @@ M.ensure_initialized = function()
|
||||
end
|
||||
end
|
||||
|
||||
local frecency_db_path = config.frecency.db_path or (vim.fn.stdpath('cache') .. '/fff_frecency')
|
||||
local history_db_path = config.history.db_path or (vim.fn.stdpath('data') .. '/fff_history')
|
||||
|
||||
local ok, result = pcall(fuzzy.init_db, frecency_db_path, history_db_path, true)
|
||||
local ok, result = pcall(fuzzy.init_db, config.frecency.db_path, config.history.db_path, true)
|
||||
if not ok then vim.notify('Failed to databases: ' .. tostring(result), vim.log.levels.WARN) end
|
||||
|
||||
setup_global_autocmds(config)
|
||||
|
||||
Generated
-4246
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": ["packages/fff-bun", "packages/fff-node", "packages/pi-fff"],
|
||||
"pi": {
|
||||
"extensions": ["./packages/pi-fff/src/index.ts"]
|
||||
},
|
||||
"scripts": {
|
||||
"format": "biome format --write packages",
|
||||
"format:check": "biome format packages",
|
||||
"lint": "biome lint packages",
|
||||
"check": "biome check --write packages",
|
||||
"check:ci": "biome check packages"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"printWidth": 90,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"ignorePatterns": [
|
||||
"*/dist",
|
||||
"fff-bin-*",
|
||||
"**/*.js",
|
||||
"**/*.cjs",
|
||||
"**/*.mjs",
|
||||
"**/*.json",
|
||||
"**/*.md",
|
||||
"**/*.toml"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript", "unicorn", "oxc"],
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
},
|
||||
"env": {
|
||||
"builtin": true
|
||||
},
|
||||
"ignorePatterns": ["*/dist", "fff-bin-*", "**/*.mjs", "**/*.cjs", "**/*.js"],
|
||||
"rules": {
|
||||
"typescript/no-explicit-any": "off",
|
||||
"typescript/no-non-null-assertion": "off",
|
||||
"unicorn/no-array-for-each": "off"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,635 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"oxfmt": "0.63.0",
|
||||
"oxlint": "1.78.0",
|
||||
},
|
||||
},
|
||||
"fff-bun": {
|
||||
"name": "@ff-labs/fff-bun",
|
||||
"version": "0.1.37",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.8",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
},
|
||||
"fff-node": {
|
||||
"name": "@ff-labs/fff-node",
|
||||
"version": "0.1.37",
|
||||
"dependencies": {
|
||||
"ffi-rs": "^1.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"tsup": "^8.5.0",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
},
|
||||
"pi-fff": {
|
||||
"name": "@ff-labs/pi-fff",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"@ff-labs/fff-bun": "*",
|
||||
"@ff-labs/fff-node": "*",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.8",
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@earendil-works/pi-coding-agent": "*",
|
||||
"@earendil-works/pi-tui": "*",
|
||||
"@sinclair/typebox": "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.91.1", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw=="],
|
||||
|
||||
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
||||
|
||||
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
|
||||
|
||||
"@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
|
||||
|
||||
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
|
||||
|
||||
"@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/eventstream-handler-node": "^3.972.16", "@aws-sdk/middleware-eventstream": "^3.972.12", "@aws-sdk/middleware-websocket": "^3.972.19", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ=="],
|
||||
|
||||
"@aws-sdk/core": ["@aws-sdk/core@3.977.8", "", { "dependencies": { "@aws-sdk/types": "^3.974.4", "@aws-sdk/xml-builder": "^3.972.39", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.31.1", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.16.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-7+Kcrkvrk9lM/m7jRhHpT4jCdvzGHsuaSRbF8TdzzkY1mRzp/Ogwf9c7H29k4gGhey0BBWhCWr16+t0J61gwmg=="],
|
||||
|
||||
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.69", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-AreCFzcB4kH2HF9031Ot0jSJr3KXvRg6e8uDeub20JEVdZU3Bv0sTq1plc7VsT3KiqutlzH7l0j50UcCWHUioA=="],
|
||||
|
||||
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.71", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/fetch-http-handler": "^5.6.13", "@smithy/node-http-handler": "^4.9.13", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-A8ObcqVmDMnk4F9NozZ7JwmUu9Q4xyBJkmyq1C5U+wNM9ht9J7+EuuyabsLWXZnOoTqFaJuYBYTKf5CTipkEjA=="],
|
||||
|
||||
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.14", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/credential-provider-env": "^3.972.69", "@aws-sdk/credential-provider-http": "^3.972.71", "@aws-sdk/credential-provider-login": "^3.972.76", "@aws-sdk/credential-provider-process": "^3.972.69", "@aws-sdk/credential-provider-sso": "^3.973.13", "@aws-sdk/credential-provider-web-identity": "^3.972.75", "@aws-sdk/nested-clients": "^3.997.43", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-7c+Wti2LsERNWMfm7ySz3/6RPopFW3Nmn7s63Xpcq6R/tRuY5hpvkHA2xVgi5ukJbvok9l0IDtVEvqTtg+X7dw=="],
|
||||
|
||||
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.76", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/nested-clients": "^3.997.43", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-LVixwOnEJfrrfKHeZjBA8pIMTZjNDq8ak8VpcoWUuCJDrSnBNU8POJksULMgvN089P0MXtQYH2Zs627/MK1K0g=="],
|
||||
|
||||
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.80", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.69", "@aws-sdk/credential-provider-http": "^3.972.71", "@aws-sdk/credential-provider-ini": "^3.973.14", "@aws-sdk/credential-provider-process": "^3.972.69", "@aws-sdk/credential-provider-sso": "^3.973.13", "@aws-sdk/credential-provider-web-identity": "^3.972.75", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-bE2qh8ww4iClO1jHsBXdOE8FUgzDbdxbyorNjSCoPSkQd51k3jODItuPZfuwcLHZqDXsH+bI4AMHhqtuyR7mSg=="],
|
||||
|
||||
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.69", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-9kpTNdZTrcqXTfhxM7fgl9Z68ek3Fu5oe3Yf+A/pJGibEqpgZxz2tSY7SinmyCIU2PJ+ygY4FPoBBnLpocMtrQ=="],
|
||||
|
||||
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.13", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/nested-clients": "^3.997.43", "@aws-sdk/token-providers": "3.1111.0", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Oc81qauMPzUoTnAS2YKpNwY6sY/LUyQTEeaf6yP197WMxkEBQfcKLR1MFpD7+pNTubXnfkH6gwpji+Gc7iyD2Q=="],
|
||||
|
||||
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.75", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/nested-clients": "^3.997.43", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-YPN6uoGDgjjjeVFZrcOeCJqmB6zpXoeeNgIjqe+DexJaWqdjVfCCe+VAZwli9Z2h8KhFW8oxkO39emQ1tyz/Mw=="],
|
||||
|
||||
"@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.33", "", { "dependencies": { "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-1Dd5WyEE2Kb3HvY44u7Ob16ST2W6iutOqsQ8Y2hUmsL2mAH/STlGS1dS9h3IOE6L7Ld3AR2HzKJ6XeCMOw8Peg=="],
|
||||
|
||||
"@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.28", "", { "dependencies": { "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-Z1EDXnS01P7H5jVrUx+/dBqV0m7dta7bSxLclkOuDuS93pNNQm0IcT4YLUbuvWKPYNxbI8aTG0p5Br30GSKDgA=="],
|
||||
|
||||
"@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.51", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/fetch-http-handler": "^5.6.13", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-jdgP3jR5Q96j1jjZ98GGwpGg1CBNFIO2YE+vXg8cg8PvNY4NvgQNYJsqDaRX2PYv5gSUX/+C0D58Fhspj9ELMQ=="],
|
||||
|
||||
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.43", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/signature-v4-multi-region": "^3.996.45", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/fetch-http-handler": "^5.6.13", "@smithy/node-http-handler": "^4.9.13", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-bit+VpqWNyi3wHxFoTsTliNXimCSL2r2OeDTm7ZrG+YsTZ2D7ofDJ6r/t9PVBn80i6/v0X2h9Tgw6QP2MAKfPw=="],
|
||||
|
||||
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.45", "", { "dependencies": { "@aws-sdk/types": "^3.974.4", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-bBuyztukzXq6plzFGHAWiQt0QXo+HL8b8lX5cFTzkez/74PtS1c0qPFCIVuHkyoT+miH2qOjAcm1/yoro2ESPA=="],
|
||||
|
||||
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="],
|
||||
|
||||
"@aws-sdk/types": ["@aws-sdk/types@3.974.4", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-dSFDNG00MEz0/xl5gxL62giLd1iYyJsTxZ1I1DOj6lC+bbgLB4TRsYClJg3b62dhXT1uATzsTNXPnC+33EJV3A=="],
|
||||
|
||||
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.10", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g=="],
|
||||
|
||||
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.39", "", { "dependencies": { "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-FTti8DS5MMWXNUWiRwXAJeYS+0GHHiMy0+7XOhcwk63ILHmfS2UFy2z/HNpZCSOJJ3P3dnWY6hfYNW3DF0nXUA=="],
|
||||
|
||||
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="],
|
||||
|
||||
"@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
|
||||
|
||||
"@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.84.2", "", { "dependencies": { "@earendil-works/pi-ai": "^0.84.2", "@earendil-works/pi-telemetry": "^0.84.2", "diff": "8.0.4", "ignore": "7.0.5", "typebox": "1.3.7", "yaml": "2.9.0" } }, "sha512-8Pn3wSCxj0cfo5I6jxQYVB/3uuQRmHhAlEclyjqpOuMEdQMIODHizRogv56FLdbU+dTiGnybeHQ2N+sV1/L2YA=="],
|
||||
|
||||
"@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.84.2", "", { "dependencies": { "@anthropic-ai/sdk": "0.91.1", "@aws-sdk/client-bedrock-runtime": "3.1048.0", "@earendil-works/pi-telemetry": "^0.84.2", "@google/genai": "1.52.0", "@opentelemetry/api": "1.9.0", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "openai": "6.40.0", "partial-json": "0.1.7", "typebox": "1.3.7" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-6MzsrYIYNVlE7SfpbL2yYb67Qo58p/7Q+xWG1RZvoX1P80aRCHSod2/13aFpxkow1lPO2LEh3c495J0Gwmyjig=="],
|
||||
|
||||
"@earendil-works/pi-client": ["@earendil-works/pi-client@0.84.2", "", { "dependencies": { "@earendil-works/pi-protocol": "^0.84.2" } }, "sha512-/RFSPhD/bZbpOp1oJj+UneSUFSgZhWxzcSENUY+8+8xhoBrWXMYI2t77XNx4Yf+c8YK2qTHquForhNcelYpXvg=="],
|
||||
|
||||
"@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@0.84.2", "", { "dependencies": { "@earendil-works/pi-agent-core": "^0.84.2", "@earendil-works/pi-ai": "^0.84.2", "@earendil-works/pi-client": "^0.84.2", "@earendil-works/pi-protocol": "^0.84.2", "@earendil-works/pi-tui": "^0.84.2", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", "diff": "8.0.4", "glob": "13.0.6", "grok-mermaid": "0.2.2", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.5", "jiti": "2.7.0", "minimatch": "10.2.5", "proper-lockfile": "4.1.2", "semver": "7.8.0", "typebox": "1.3.7", "undici": "8.9.0", "yaml": "2.9.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "pi": "dist/cli.js" } }, "sha512-l4E+B7hgXKWddRo8bC/eSue2aWZjEgJ9xIpf5p0Og+lq8a2TArCwJ0HCoCPCgaBP/tN4zbYH/wOwvx9pJpeLCA=="],
|
||||
|
||||
"@earendil-works/pi-protocol": ["@earendil-works/pi-protocol@0.84.2", "", { "dependencies": { "typebox": "1.3.7" } }, "sha512-jbBh03fkeckWEroHpcZBr4w5/Ibat8WwdXFlXHivYQImrQNFtLpDeL0t1cku4hmK0q3pceIRQHkw4fwbM4YILQ=="],
|
||||
|
||||
"@earendil-works/pi-telemetry": ["@earendil-works/pi-telemetry@0.84.2", "", {}, "sha512-wg5caea7uIv1BHRBm2Y116RvFG4oSAiP5qk9tA2463PDGIr4K8M1Ceyyg5DOpF/shUUl0gk826yQJAeAcHYB9g=="],
|
||||
|
||||
"@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.84.2", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.5" } }, "sha512-ds2TLihOnM5sLJB3VpXV6y0uR5efVuHf4MN7yDpsty6hA2DUO/EDVzjp/0od0G2JslzVLMjT8T8zavtxVb+qbg=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="],
|
||||
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
|
||||
|
||||
"@ff-labs/fff-bun": ["@ff-labs/fff-bun@workspace:fff-bun"],
|
||||
|
||||
"@ff-labs/fff-node": ["@ff-labs/fff-node@workspace:fff-node"],
|
||||
|
||||
"@ff-labs/pi-fff": ["@ff-labs/pi-fff@workspace:pi-fff"],
|
||||
|
||||
"@google/genai": ["@google/genai@1.52.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@mariozechner/clipboard": ["@mariozechner/clipboard@0.3.9", "", { "optionalDependencies": { "@mariozechner/clipboard-darwin-arm64": "0.3.9", "@mariozechner/clipboard-darwin-universal": "0.3.9", "@mariozechner/clipboard-darwin-x64": "0.3.9", "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", "@mariozechner/clipboard-linux-x64-musl": "0.3.9", "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" } }, "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA=="],
|
||||
|
||||
"@mariozechner/clipboard-darwin-arm64": ["@mariozechner/clipboard-darwin-arm64@0.3.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ=="],
|
||||
|
||||
"@mariozechner/clipboard-darwin-universal": ["@mariozechner/clipboard-darwin-universal@0.3.9", "", { "os": "darwin" }, "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ=="],
|
||||
|
||||
"@mariozechner/clipboard-darwin-x64": ["@mariozechner/clipboard-darwin-x64@0.3.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-arm64-gnu": ["@mariozechner/clipboard-linux-arm64-gnu@0.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-arm64-musl": ["@mariozechner/clipboard-linux-arm64-musl@0.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-riscv64-gnu": ["@mariozechner/clipboard-linux-riscv64-gnu@0.3.9", "", { "os": "linux", "cpu": "none" }, "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-x64-gnu": ["@mariozechner/clipboard-linux-x64-gnu@0.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw=="],
|
||||
|
||||
"@mariozechner/clipboard-linux-x64-musl": ["@mariozechner/clipboard-linux-x64-musl@0.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ=="],
|
||||
|
||||
"@mariozechner/clipboard-win32-arm64-msvc": ["@mariozechner/clipboard-win32-arm64-msvc@0.3.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ=="],
|
||||
|
||||
"@mariozechner/clipboard-win32-x64-msvc": ["@mariozechner/clipboard-win32-x64-msvc@0.3.9", "", { "os": "win32", "cpu": "x64" }, "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA=="],
|
||||
|
||||
"@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.63.0", "", { "os": "android", "cpu": "arm" }, "sha512-YmRth4ZPGgEXcgmkhvANbC9uD67dxmSobW7DQuyt5tOBOKvPnIpk5SVHBj88E+7wMNRI2FhqaDbOhQFBix+b8A=="],
|
||||
|
||||
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.63.0", "", { "os": "android", "cpu": "arm64" }, "sha512-icbahX8X2X3sRamOMecvdYeZXWjPDazRDIfvWfy7Ca1nc/ZDT2Y9k5Nt7s46EqFd7NQPdgk+CM3/SgIT5LPCaQ=="],
|
||||
|
||||
"@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.63.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WV+Ze5v5gI2qoj8jpAovt8KBTW8pjEz/AiMXXjeTQS+Bmf/MmZXTS40S8xNPDszX+W8WDv2Bbk6qKrMTtUGu1A=="],
|
||||
|
||||
"@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.63.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJGSBdDxXOWIpoFXHpverimCvz084KA7L483rqJ44c3jDtzv6d4qOSoR/V9ywSHfV+Ks1lwIj2P49BFhunLNAA=="],
|
||||
|
||||
"@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.63.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BDfKY+KhL2078cgswBBFQPAYuxCy93bS/iC5frdSeSbTLcGrR6VC2hsuPTanoJmg84+wSyWl0wWC1eR+uTnkRg=="],
|
||||
|
||||
"@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.63.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Ov1cQEXT4mj7cojAokWSS1eoxkoyvbDfAbxNsGIKY2o36kvdAaFzPxRN6NxFRk9fD72B8oCoTTX/NuYTUWlpsg=="],
|
||||
|
||||
"@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.63.0", "", { "os": "linux", "cpu": "arm" }, "sha512-0LE7ro3+6L79jcMANycAZfRaC7zxr9YZ2+vEL5uMD9QlEep+rS/r1kSJsnuLl991NXJZD60euh0PC1GHrR20vw=="],
|
||||
|
||||
"@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.63.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-izPk+2Z4gjuZK32Fqh5qXoMpT/2NXzLh++ob57HiEiVSQZ1iYXu8EKMzb+K5AvWyIEXhdDIt7ADjGGtFhkT9Bw=="],
|
||||
|
||||
"@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.63.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-alPmbOuWXFXiSo+lOtv6X71C7SYMEDW2WVvywOvf9BwKgEhSNGhMTLeFVSjKUMCamcjbbgVdsWF8GN1uy8xshg=="],
|
||||
|
||||
"@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.63.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BdzCPvolJc4AWZ+YMzgUDJcDzbQWrFjYuqBHoNHNqP1aCaluQRJNs4k3vNU5IG7vTpjf9zeD73D7MFM1TecZpg=="],
|
||||
|
||||
"@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-7sIgfLzqtNKSkMGsGVyRpHwpjNezRg2XONvUOheFZs95TSZpM0JAuPpA8KrQFsWc4wPU95roX2O69JgH8igOgw=="],
|
||||
|
||||
"@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-9Tcg0y0WcVa6Mm9AgcgFMseDS+VkFJZpKZ8We9SpDY4gg5jewSwln+0sO04QLcTS1BtfDl9MwR+NfID8L7PUTg=="],
|
||||
|
||||
"@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.63.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-qWKC1pEOpx1qYhXaugPhHUeXwSfqEOk2wJH2LqVXGPV5iQYfdAZdt+d2XDiX4DTSWA2QDMUcFB+wEORh3Xn/sA=="],
|
||||
|
||||
"@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.63.0", "", { "os": "linux", "cpu": "x64" }, "sha512-S9wXYOiGSqYGS4Fx/TFsY+xDd/7dE5s+rUgbA4TsHiVF9e8J3ZcKmP7dsP/7iqLI9Wz7Ic7TzEr3mdthRCTdrA=="],
|
||||
|
||||
"@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.63.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5eGyTJuMZNwBSHCivXt8Yuta6GeTYksOPXRk2MIhajiyFGQx7bjaHIwY+ZusAoFHhT157A9x6sktLjYo9D5oMQ=="],
|
||||
|
||||
"@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.63.0", "", { "os": "none", "cpu": "arm64" }, "sha512-Rz7hx+Dv3DoW/S6pwVAyjfFXp7/trdQ1zg+vNmsdsdDNlUccugp4XNqambSuEAeP0DaG9k72AtNyfDXCEg0AGw=="],
|
||||
|
||||
"@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.63.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-T/IuizKN9mr4Xw6YYnptkXRNdLkyIlUZ7c8zfTOBpoytZyJ1BAsMUvsMDEx0X4YvSMpaivm+DR8112rQfzC25g=="],
|
||||
|
||||
"@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.63.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-XjrO5FJ5Wl9vsAxtCP1G/eaeT6y1K2s9CICUHGE42cEjou32/J6S+B1KnrOAboj6E7uhJnwPbRSvznWcxNdA0g=="],
|
||||
|
||||
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.63.0", "", { "os": "win32", "cpu": "x64" }, "sha512-sgsHCQy432OTQH4Ikk3tZptp3GqwnhwUDuY0loBH41zyHWfMZY9v8Dy78wsnSofHejvFozZGgJgBB1A0LQRwMQ=="],
|
||||
|
||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.78.0", "", { "os": "android", "cpu": "arm" }, "sha512-Bu819lmAfZMUHErrpe0cEWj3iaefuUODHSU8+UbXy67V/r7/7f4K3FL0NmbD85E+wiFLDYuhP8Zlv0XnVeXshw=="],
|
||||
|
||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.78.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CDfxZgB61B7buRdY2FJoAYYPPXCZ1EoC1LKscnC5dg3kjobdxiconvAvvN1BmHyW4PyFT3jRLDag/BY/roSNBQ=="],
|
||||
|
||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.78.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2Y2U9Ahrz+OO0Ej88f9SJYq51/jUBp1Mc7iZu0ukrbeeZ3gpRGfzIFnoqfHDY96xr0GEfNrPUBFEy0nN5aD7HA=="],
|
||||
|
||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.78.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-rpych6eJq6m9jDRypTEaPD1xysaEW5h9+xuxhGK/QhOg+/xaqPZrCrTNoIl/f3nEjuJeCEmstNDlrE9rJi/3/g=="],
|
||||
|
||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.78.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IcMGrQT3QizkOESUJd5et+rOhVqSkNDfNik1cvrKDqIbzqx9KMtRswpFgkCuNTSwylCFLKhGUu8KmqY1ZnC0Dg=="],
|
||||
|
||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.78.0", "", { "os": "linux", "cpu": "arm" }, "sha512-/uLdoJ0IXE6vo/0f0LKjinQAp+re+VMaCWaNT8ENIv2EOCkSsc8SGaflXAuW0Jua2dq5+GLVWm1NQK7P3UFSNQ=="],
|
||||
|
||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.78.0", "", { "os": "linux", "cpu": "arm" }, "sha512-7xi4Wb/O8NRJhLoUXmDJMUVpNYvB5kefdhFU1Jb8rtae4QoXlTiLwI14X4YvAXVZLNZChP8m5qO9SQAlWQTbkQ=="],
|
||||
|
||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.78.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-4hFW0+fVXa3OIh1Y4A5SPkmvI4wuuBSrCVKzOyE7PTjhc7yEqZ1pmvEEeS5Lj/MaqvegFxXyF33N+6jkehxdyg=="],
|
||||
|
||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.78.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oC0mvsgBJjlMijSDEhx9KuvR9zYeHXceA9MjbuXB1F8NSR78Yj2unOBrstEvTVaq+pko+kuue6DajC00eqvTdg=="],
|
||||
|
||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.78.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-XAllT5SUZS+ohjuZ3/5S0cwe0r7eboiuigeStCZ5DXRYx/2KVM2UvQXvAfyzXEimtQjAB7cDQ2YxDe2Zl2WNQQ=="],
|
||||
|
||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.78.0", "", { "os": "linux", "cpu": "none" }, "sha512-trucMER/0QtecoXvc1y/UVqE3kwJipDwrx4oHfj+nNm3dq2zjP44WT0CfHNDPM3G1DXIkx/gY6lAD21NSCZVhA=="],
|
||||
|
||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.78.0", "", { "os": "linux", "cpu": "none" }, "sha512-cm3O4F/HQbdzOUX5mKHqG5KDL6E5w0pnlZ+fbBy2rmLryPOowkuLagFHTopQsEIpjcaZoPOrL+BmmAytAG9HFg=="],
|
||||
|
||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.78.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-33wRf6HqGNsybJ3qX4cGaQN2ODPxNmc1rMa0mrTmx3eFq1VzOnvQooi9bIGVYakW8a/wmqVx1mgsUm8R2xfTiw=="],
|
||||
|
||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.78.0", "", { "os": "linux", "cpu": "x64" }, "sha512-rRdISSYegj6VganMZ9tjRjijowfHJ09IZU01i0toBAqr6n5LEtwHq2IeS4FjW2RoskOHlb6efB26H5izYb3GEQ=="],
|
||||
|
||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.78.0", "", { "os": "linux", "cpu": "x64" }, "sha512-GmsP4rW0xTL6u5CVdcDsaN5Fbc7hBc382Wmar1kttbnwSEviM+rSINKOMQ+UQ6iH+AGwC+8gaAiwu134Tgh6Lg=="],
|
||||
|
||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.78.0", "", { "os": "none", "cpu": "arm64" }, "sha512-sy9yeYuADc8a+n4TLBayzMCZiHPW78DcIFVpOXTmdKHWQeM9xe5uzkqIIZmi326D5hY9XVwacipEB1p7tQjPAg=="],
|
||||
|
||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.78.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-rjc2hF1KfMi8fZj1X/m3AmnHbdsF3rL0v6KQg0Uc880Yb2khjz+3U14sfdZ7jWTpRnN1m1NQa/TT7uU9lJWPrA=="],
|
||||
|
||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.78.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-zcuXFVrEFHIafRfkCQT8w/Xe41o07ozl/vwHq7p94vB29xVzsB0sZGYORU1jhcYKv3Lr0J3HbJ2T4fHH5rWmvA=="],
|
||||
|
||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.78.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Sb5ocmLSuYeOuXd+CFOToGKp/gjXUEWDnvIGwhnh8aq8wY4TMmEnKnvbogSW7RdMZv77JSARduS7/gv+khYEjA=="],
|
||||
|
||||
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
||||
|
||||
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
||||
|
||||
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="],
|
||||
|
||||
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="],
|
||||
|
||||
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="],
|
||||
|
||||
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
|
||||
|
||||
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
|
||||
|
||||
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
|
||||
|
||||
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.2", "", {}, "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.4", "", { "os": "android", "cpu": "arm" }, "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.4", "", { "os": "android", "cpu": "arm64" }, "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.62.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.62.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.62.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.62.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.62.4", "", { "os": "linux", "cpu": "arm" }, "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.62.4", "", { "os": "linux", "cpu": "arm" }, "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.62.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.62.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.62.4", "", { "os": "linux", "cpu": "none" }, "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.62.4", "", { "os": "linux", "cpu": "none" }, "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.62.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.62.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.62.4", "", { "os": "linux", "cpu": "none" }, "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.62.4", "", { "os": "linux", "cpu": "none" }, "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.62.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.62.4", "", { "os": "linux", "cpu": "x64" }, "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.62.4", "", { "os": "linux", "cpu": "x64" }, "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA=="],
|
||||
|
||||
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.62.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ=="],
|
||||
|
||||
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.62.4", "", { "os": "none", "cpu": "arm64" }, "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.62.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.62.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.62.4", "", { "os": "win32", "cpu": "x64" }, "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.4", "", { "os": "win32", "cpu": "x64" }, "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q=="],
|
||||
|
||||
"@silvia-odwyer/photon-node": ["@silvia-odwyer/photon-node@0.3.4", "", {}, "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA=="],
|
||||
|
||||
"@sinclair/typebox": ["@sinclair/typebox@0.34.52", "", {}, "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw=="],
|
||||
|
||||
"@smithy/core": ["@smithy/core@3.33.2", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-CUGXpnPkVdjUCbix+83sWLW9VFgQOm44MDOx/ihITJMAnOZKvL8YYIc7DR9pP/tZ8CIRvMiON/TucvygqbHO3w=="],
|
||||
|
||||
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.5.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg=="],
|
||||
|
||||
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.7.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw=="],
|
||||
|
||||
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||
|
||||
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="],
|
||||
|
||||
"@smithy/signature-v4": ["@smithy/signature-v4@5.7.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-P7Ki6px6OOrxVtx8K7nLmyx4SlXUW/uTKDdMG44UHefmPGSRMBKe2v+TM59WdLcpUIrBrnuCsIqiM2MbsZjmhw=="],
|
||||
|
||||
"@smithy/types": ["@smithy/types@4.17.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA=="],
|
||||
|
||||
"@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||
|
||||
"@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
|
||||
|
||||
"@types/node": ["@types/node@22.20.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q=="],
|
||||
|
||||
"@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="],
|
||||
|
||||
"@yuuang/ffi-rs-android-arm64": ["@yuuang/ffi-rs-android-arm64@1.3.7", "", { "os": "android", "cpu": "arm64" }, "sha512-t6Wx3Xll6c07Nuk0k3xnZsxKFxlshm92i0U/BiTHc6kQbvu+fMJF+gKsj4yEj886jH51CM3EqZT9Xdhq9CdUVw=="],
|
||||
|
||||
"@yuuang/ffi-rs-darwin-arm64": ["@yuuang/ffi-rs-darwin-arm64@1.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OueBlUFBT9IwD9pQnoYs0UszRBEySskfrEPXXfvKfGjL/DXnfn6kUheQ3oIP6sSmshVGNQUwrTCPo6feAa4QjA=="],
|
||||
|
||||
"@yuuang/ffi-rs-darwin-x64": ["@yuuang/ffi-rs-darwin-x64@1.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-x4mxXOKwSgwYx6OBAKrW+Ocp8um2KoPpUwaD0Z2tmR6EekoRvFGN7s/eEK1avqCxcsLN7/MzGOnCCFyGpOVfPA=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-arm-gnueabihf": ["@yuuang/ffi-rs-linux-arm-gnueabihf@1.3.7", "", { "os": "linux", "cpu": "arm" }, "sha512-9r//Z022QYVoIAY458Dpk8HWkisk/y4NJC3d52RlkdsLD+9p0zn0cKKSoMF/xUsOWDFSmOf+cwU/Xadi/wxFMQ=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-arm64-gnu": ["@yuuang/ffi-rs-linux-arm64-gnu@1.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-nrW4MlFlyQInfxTsI5wtcIpbV4KlHLWo2BCk4CHIETlUT+PUspNFqDg+Byy7My3hpCZlXp0WsMVP/3N0LlybNw=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-arm64-musl": ["@yuuang/ffi-rs-linux-arm64-musl@1.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-eLLx4P8DzNnuPif19nAvKPaf88lSf6KFbDetH3nAIRZvI495h0jigN835Ayr7uAADssohGfO9MPMH33DXmFErA=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-x64-gnu": ["@yuuang/ffi-rs-linux-x64-gnu@1.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-upEz1Q98T51x2In872fsjgHCJbE3e8r9JxhJD+5NvSMk6BpieYWRodTbsMxV6oKWmfl12loKwF2j4OBSWKl0lA=="],
|
||||
|
||||
"@yuuang/ffi-rs-linux-x64-musl": ["@yuuang/ffi-rs-linux-x64-musl@1.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-YOcOkIwVvIhpwuGJ428h15vpE0KnT3teFG0g2J31FrBxrVh9IH4HeTGXjelI3l9SI5gyiZDnD4PQnQ1U6oqTcA=="],
|
||||
|
||||
"@yuuang/ffi-rs-win32-arm64-msvc": ["@yuuang/ffi-rs-win32-arm64-msvc@1.3.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZfYzLV1w7Mhzh9XRScEMpw9oazIEiwO+0+TYHHRL882d5oD0Q99YikmRhdifsoHCCQefKmWF/4BXCeFkzg8NFA=="],
|
||||
|
||||
"@yuuang/ffi-rs-win32-ia32-msvc": ["@yuuang/ffi-rs-win32-ia32-msvc@1.3.7", "", { "os": "win32", "cpu": [ "x64", "ia32", ] }, "sha512-ifYz+f+giKpT39lKWDru+om6QnA9J7J953ns60xHgB46ESZvPd/Y2W5+PesRNC9U+vnFEiLZ9CNC+R3fBWC1pg=="],
|
||||
|
||||
"@yuuang/ffi-rs-win32-x64-msvc": ["@yuuang/ffi-rs-win32-x64-msvc@1.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-H3s4wOLtZtKtmuPjUNE+bhnSKxxpXcuxG70jRC8dUMHqIm5iCvdoZ4XYDeq7/uUYlySerXFmRL4dAVCX/TUNTg=="],
|
||||
|
||||
"acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="],
|
||||
|
||||
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
||||
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
||||
|
||||
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
|
||||
|
||||
"bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
|
||||
|
||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||
|
||||
"bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
|
||||
|
||||
"cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
||||
|
||||
"confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
|
||||
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="],
|
||||
|
||||
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||
|
||||
"esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
|
||||
|
||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||
|
||||
"ffi-rs": ["ffi-rs@1.3.7", "", { "optionalDependencies": { "@yuuang/ffi-rs-android-arm64": "1.3.7", "@yuuang/ffi-rs-darwin-arm64": "1.3.7", "@yuuang/ffi-rs-darwin-x64": "1.3.7", "@yuuang/ffi-rs-linux-arm-gnueabihf": "1.3.7", "@yuuang/ffi-rs-linux-arm64-gnu": "1.3.7", "@yuuang/ffi-rs-linux-arm64-musl": "1.3.7", "@yuuang/ffi-rs-linux-x64-gnu": "1.3.7", "@yuuang/ffi-rs-linux-x64-musl": "1.3.7", "@yuuang/ffi-rs-win32-arm64-msvc": "1.3.7", "@yuuang/ffi-rs-win32-ia32-msvc": "1.3.7", "@yuuang/ffi-rs-win32-x64-msvc": "1.3.7" } }, "sha512-5MMZQS2t/6f/ec3sx0f51gBcKGZPGfolPAW04lvLOSYnr7gmOKs8YzH1Rh+34WGO+VtcgcTuxaUUoJLcR4Tirg=="],
|
||||
|
||||
"fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="],
|
||||
|
||||
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"gaxios": ["gaxios@7.3.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ=="],
|
||||
|
||||
"gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
|
||||
|
||||
"glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
|
||||
|
||||
"google-auth-library": ["google-auth-library@10.9.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw=="],
|
||||
|
||||
"google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"grok-mermaid": ["grok-mermaid@0.2.2", "", {}, "sha512-XcJEP5dDC8liHBh52mlLjU18fNvu1ckFsu0QpIG3+APZ270fsj9wxpiA6cOURmbUEuoMVgjbC2+UYgTdCqqgzA=="],
|
||||
|
||||
"highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
|
||||
|
||||
"hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
|
||||
|
||||
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
|
||||
|
||||
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
||||
|
||||
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
|
||||
|
||||
"joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
|
||||
|
||||
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
|
||||
|
||||
"json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
|
||||
|
||||
"jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
|
||||
|
||||
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
|
||||
|
||||
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||
|
||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||
|
||||
"load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="],
|
||||
|
||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
|
||||
"marked": ["marked@18.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w=="],
|
||||
|
||||
"minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||
|
||||
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||
|
||||
"mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
||||
|
||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||
|
||||
"openai": ["openai@6.40.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"] }, "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA=="],
|
||||
|
||||
"oxfmt": ["oxfmt@0.63.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.63.0", "@oxfmt/binding-android-arm64": "0.63.0", "@oxfmt/binding-darwin-arm64": "0.63.0", "@oxfmt/binding-darwin-x64": "0.63.0", "@oxfmt/binding-freebsd-x64": "0.63.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.63.0", "@oxfmt/binding-linux-arm-musleabihf": "0.63.0", "@oxfmt/binding-linux-arm64-gnu": "0.63.0", "@oxfmt/binding-linux-arm64-musl": "0.63.0", "@oxfmt/binding-linux-ppc64-gnu": "0.63.0", "@oxfmt/binding-linux-riscv64-gnu": "0.63.0", "@oxfmt/binding-linux-riscv64-musl": "0.63.0", "@oxfmt/binding-linux-s390x-gnu": "0.63.0", "@oxfmt/binding-linux-x64-gnu": "0.63.0", "@oxfmt/binding-linux-x64-musl": "0.63.0", "@oxfmt/binding-openharmony-arm64": "0.63.0", "@oxfmt/binding-win32-arm64-msvc": "0.63.0", "@oxfmt/binding-win32-ia32-msvc": "0.63.0", "@oxfmt/binding-win32-x64-msvc": "0.63.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-kgdDwv35wvVf6554U2Ab8Jnd0zTM+TsEQWwaB70RAjK3gICFAFGO+2Hd3Be27GMoXj3XRL9IKSNRVl7KBQL6iw=="],
|
||||
|
||||
"oxlint": ["oxlint@1.78.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.78.0", "@oxlint/binding-android-arm64": "1.78.0", "@oxlint/binding-darwin-arm64": "1.78.0", "@oxlint/binding-darwin-x64": "1.78.0", "@oxlint/binding-freebsd-x64": "1.78.0", "@oxlint/binding-linux-arm-gnueabihf": "1.78.0", "@oxlint/binding-linux-arm-musleabihf": "1.78.0", "@oxlint/binding-linux-arm64-gnu": "1.78.0", "@oxlint/binding-linux-arm64-musl": "1.78.0", "@oxlint/binding-linux-ppc64-gnu": "1.78.0", "@oxlint/binding-linux-riscv64-gnu": "1.78.0", "@oxlint/binding-linux-riscv64-musl": "1.78.0", "@oxlint/binding-linux-s390x-gnu": "1.78.0", "@oxlint/binding-linux-x64-gnu": "1.78.0", "@oxlint/binding-linux-x64-musl": "1.78.0", "@oxlint/binding-openharmony-arm64": "1.78.0", "@oxlint/binding-win32-arm64-msvc": "1.78.0", "@oxlint/binding-win32-ia32-msvc": "1.78.0", "@oxlint/binding-win32-x64-msvc": "1.78.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-QgQePuxIqKOzo1KSjG2EnITEeWvWnKAm77eq8nrMtf6AGoA+zyGc4PFYtDNJSD25g/ibOwfQ851hZ4/SPkMVoA=="],
|
||||
|
||||
"p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="],
|
||||
|
||||
"partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||
|
||||
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="],
|
||||
|
||||
"pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
|
||||
|
||||
"pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
|
||||
"postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="],
|
||||
|
||||
"proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="],
|
||||
|
||||
"protobufjs": ["protobufjs@7.6.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
||||
|
||||
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
|
||||
|
||||
"rollup": ["rollup@4.62.4", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@napi-rs/lzma-linux-x64-gnu": "1.5.1", "@rollup/rollup-android-arm-eabi": "4.62.4", "@rollup/rollup-android-arm64": "4.62.4", "@rollup/rollup-darwin-arm64": "4.62.4", "@rollup/rollup-darwin-x64": "4.62.4", "@rollup/rollup-freebsd-arm64": "4.62.4", "@rollup/rollup-freebsd-x64": "4.62.4", "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", "@rollup/rollup-linux-arm-musleabihf": "4.62.4", "@rollup/rollup-linux-arm64-gnu": "4.62.4", "@rollup/rollup-linux-arm64-musl": "4.62.4", "@rollup/rollup-linux-loong64-gnu": "4.62.4", "@rollup/rollup-linux-loong64-musl": "4.62.4", "@rollup/rollup-linux-ppc64-gnu": "4.62.4", "@rollup/rollup-linux-ppc64-musl": "4.62.4", "@rollup/rollup-linux-riscv64-gnu": "4.62.4", "@rollup/rollup-linux-riscv64-musl": "4.62.4", "@rollup/rollup-linux-s390x-gnu": "4.62.4", "@rollup/rollup-linux-x64-gnu": "4.62.4", "@rollup/rollup-linux-x64-musl": "4.62.4", "@rollup/rollup-openbsd-x64": "4.62.4", "@rollup/rollup-openharmony-arm64": "4.62.4", "@rollup/rollup-win32-arm64-msvc": "4.62.4", "@rollup/rollup-win32-ia32-msvc": "4.62.4", "@rollup/rollup-win32-x64-gnu": "4.62.4", "@rollup/rollup-win32-x64-msvc": "4.62.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="],
|
||||
|
||||
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
|
||||
|
||||
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
|
||||
|
||||
"tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
||||
|
||||
"tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
|
||||
|
||||
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
|
||||
|
||||
"ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
|
||||
|
||||
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="],
|
||||
|
||||
"typebox": ["typebox@1.3.7", "", {}, "sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="],
|
||||
|
||||
"undici": ["undici@8.9.0", "", {}, "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="],
|
||||
|
||||
"yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
|
||||
|
||||
"@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.11.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g=="],
|
||||
|
||||
"@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1111.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.8", "@aws-sdk/nested-clients": "^3.997.43", "@aws-sdk/types": "^3.974.4", "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-JfljgoVtl+s3Qy21n9a7Z48uCQaOXcN74KJ3TEQfPoB293GrXFSt6HSQJF1sTZ8c/5QedEvd3NjJQMO4u9qa5A=="],
|
||||
|
||||
"@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.11.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g=="],
|
||||
|
||||
"p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "fff",
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.8",
|
||||
"typescript": "^5.0.0",
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ff-labs/fff-bun-darwin-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bun-darwin-x64": "0.0.0",
|
||||
"@ff-labs/fff-bun-linux-arm64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bun-linux-arm64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bun-linux-x64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bun-linux-x64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bun-win32-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bun-win32-x64": "0.0.0",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bun": ">=1.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-df7smckMWSUfaT5mzwN9Lfpd3ZGkOqo+vmQ8VV2a32gl14v6uZ/qeeo+1RlANXn8M0uzXPWWCkrKZIWSZUR0qw=="],
|
||||
|
||||
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-YiLxfsPzQqaVvT2a+nxH9do0YfUjrlxF3tKP0b1DDgvfgCcVKGsrQH3Wa82qHgL4dnT8h2bqi94JxXESEuPmcA=="],
|
||||
|
||||
"@oven/bun-darwin-x64-baseline": ["@oven/bun-darwin-x64-baseline@1.3.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-XbhsA2XAFzvFr0vPSV6SNqGxab4xHKdPmVTLqoSHAx9tffrSq/012BDptOskulwnD+YNsrJUx2D2Ve1xvfgGcg=="],
|
||||
|
||||
"@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-VaNQTu0Up4gnwZLQ6/Hmho6jAlLxTQ1PwxEth8EsXHf82FOXXPV5OCQ6KC9mmmocjKlmWFaIGebThrOy8DUo4g=="],
|
||||
|
||||
"@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.3.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-t8uimCVBTw5f9K2QTZE5wN6UOrFETNrh/Xr7qtXT9nAOzaOnIFvYA+HcHbGfi31fRlCVfTxqm/EiCwJ1gEw9YQ=="],
|
||||
|
||||
"@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-oQyAW3+ugulvXTZ+XYeUMmNPR94sJeMokfHQoKwPvVwhVkgRuMhcLGV2ZesHCADVu30Oz2MFXbgdC8x4/o9dRg=="],
|
||||
|
||||
"@oven/bun-linux-x64-baseline": ["@oven/bun-linux-x64-baseline@1.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-nZ12g22cy7pEOBwAxz2tp0wVqekaCn9QRKuGTHqOdLlyAqR4SCdErDvDhUWd51bIyHTQoCmj72TegGTgG0WNPw=="],
|
||||
|
||||
"@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-4ZjIUgCxEyKwcKXideB5sX0KJpnHTZtu778w73VNq2uNH2fNpMZv98+DBgJyQ9OfFoRhmKn1bmLmSefvnHzI9w=="],
|
||||
|
||||
"@oven/bun-linux-x64-musl-baseline": ["@oven/bun-linux-x64-musl-baseline@1.3.9", "", { "os": "linux", "cpu": "x64" }, "sha512-3FXQgtYFsT0YOmAdMcJn56pLM5kzSl6y942rJJIl5l2KummB9Ea3J/vMJMzQk7NCAGhleZGWU/pJSS/uXKGa7w=="],
|
||||
|
||||
"@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.3.9", "", { "os": "win32", "cpu": "x64" }, "sha512-/d6vAmgKvkoYlsGPsRPlPmOK1slPis/F40UG02pYwypTH0wmY0smgzdFqR4YmryxFh17XrW1kITv+U99Oajk9Q=="],
|
||||
|
||||
"@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.3.9", "", { "os": "win32", "cpu": "x64" }, "sha512-a/+hSrrDpMD7THyXvE2KJy1skxzAD0cnW4K1WjuI/91VqsphjNzvf5t/ZgxEVL4wb6f+hKrSJ5J3aH47zPr61g=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
|
||||
|
||||
"@types/node": ["@types/node@25.2.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ=="],
|
||||
|
||||
"bun": ["bun@1.3.9", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.3.9", "@oven/bun-darwin-x64": "1.3.9", "@oven/bun-darwin-x64-baseline": "1.3.9", "@oven/bun-linux-aarch64": "1.3.9", "@oven/bun-linux-aarch64-musl": "1.3.9", "@oven/bun-linux-x64": "1.3.9", "@oven/bun-linux-x64-baseline": "1.3.9", "@oven/bun-linux-x64-musl": "1.3.9", "@oven/bun-linux-x64-musl-baseline": "1.3.9", "@oven/bun-windows-x64": "1.3.9", "@oven/bun-windows-x64-baseline": "1.3.9" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-v5hkh1us7sMNjfimWE70flYbD5I1/qWQaqmJ45q2qk5H/7muQVa478LSVRSFyGTBUBog2LsPQnfIRdjyWJRY+A=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
}
|
||||
}
|
||||
@@ -63,17 +63,6 @@
|
||||
"url": "https://github.com/dmtrKovalenko/fff/issues"
|
||||
},
|
||||
"homepage": "https://github.com/dmtrKovalenko/fff#readme",
|
||||
"optionalDependencies": {
|
||||
"@ff-labs/fff-bin-darwin-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-darwin-x64": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-x64": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-android-arm64": "0.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.8",
|
||||
"typescript": "^5.0.0"
|
||||
|
||||
@@ -153,6 +153,7 @@ function startSession(
|
||||
const events = new Map<string, EventHandler>();
|
||||
const tools = new Map<string, RegisteredTool>();
|
||||
const notifications: Array<{ message: string; level?: string }> = [];
|
||||
let activeTools: string[] = [];
|
||||
|
||||
const flags: Record<string, unknown> = {
|
||||
"fff-frecency-db": dbs.frecencyDbPath,
|
||||
@@ -165,6 +166,10 @@ function startSession(
|
||||
registerCommand: () => undefined,
|
||||
registerFlag: () => undefined,
|
||||
registerTool: (tool: RegisteredTool) => tools.set(tool.name, tool),
|
||||
getActiveTools: () => activeTools,
|
||||
setActiveTools: (names: string[]) => {
|
||||
activeTools = names;
|
||||
},
|
||||
appendEntry: () => undefined,
|
||||
};
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run build:esm && npm run build:cjs && npm run build:types",
|
||||
"build:esm": "bun build ./src/index.ts --format=esm --target=node --external ffi-rs --sourcemap=external --outdir dist",
|
||||
"build:cjs": "bun build ./src/index.ts --format=cjs --target=node --external ffi-rs --sourcemap=external --outdir dist --entry-naming \"[name].cjs\"",
|
||||
"build": "npm run build:bundle && npm run build:types",
|
||||
"build:bundle": "tsup src/index.ts --format esm,cjs --platform node --target node18 --external ffi-rs --sourcemap",
|
||||
"build:types": "tsc -p tsconfig.build.json",
|
||||
"test": "node test/e2e.mjs && node test/watch.mjs",
|
||||
"typecheck": "tsc --noEmit"
|
||||
@@ -67,19 +66,9 @@
|
||||
"dependencies": {
|
||||
"ffi-rs": "^1.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ff-labs/fff-bin-darwin-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-darwin-x64": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-gnu": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-x64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-linux-arm64-musl": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-x64": "0.0.0",
|
||||
"@ff-labs/fff-bin-win32-arm64": "0.0.0",
|
||||
"@ff-labs/fff-bin-android-arm64": "0.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.0.0",
|
||||
"@types/node": "^22.0.0"
|
||||
"@types/node": "^22.0.0",
|
||||
"tsup": "^8.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,7 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export {
|
||||
binaryExists,
|
||||
findBinary,
|
||||
} from "./binary.js";
|
||||
export { binaryExists, findBinary } from "./binary.js";
|
||||
export { closeLibrary } from "./ffi.js";
|
||||
export type {
|
||||
DbHealth,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "fff-search"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
description = "Python bindings for FFF (Fast File Finder)"
|
||||
readme = "README.md"
|
||||
license = { text = "MIT" }
|
||||
|
||||
@@ -50,7 +50,7 @@ class FileFinder(_FileFinder):
|
||||
return True
|
||||
|
||||
|
||||
__version__ = "0.10.3"
|
||||
__version__ = "0.10.5"
|
||||
|
||||
__all__ = [
|
||||
"FFFException",
|
||||
|
||||
Generated
+1
-1
@@ -34,7 +34,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "fff-search"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
source = { editable = "." }
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
||||
Generated
+4608
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": ["fff-bun", "fff-node", "pi-fff"],
|
||||
"scripts": {
|
||||
"format": "oxfmt .",
|
||||
"format:check": "oxfmt --check .",
|
||||
"lint": "oxlint .",
|
||||
"check": "oxfmt . && oxlint --fix .",
|
||||
"check:ci": "oxfmt --check . && oxlint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"oxfmt": "0.63.0",
|
||||
"oxlint": "1.78.0"
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ Parameters:
|
||||
|
||||
- `/fff-health` — show FFF status (indexed files, git info, frecency/history DB status)
|
||||
- `/fff-rescan` — trigger a file rescan
|
||||
- `/fff-mode <mode>` — switch mode (tool name change requires restart)
|
||||
- `/fff-mode <mode>` — switch mode (tool name changes require `/reload`)
|
||||
|
||||
## Modes
|
||||
|
||||
@@ -124,24 +124,70 @@ Parameters:
|
||||
- `tools-only`: additional tools only; keep pi's default `@` autocomplete
|
||||
- `override`: replaces pi's built-in `find`, `grep` and adds `multi_grep` + FFF-backed `@` autocomplete
|
||||
|
||||
Mode precedence:
|
||||
Startup mode precedence:
|
||||
1. `--fff-mode <mode>` CLI flag
|
||||
2. `PI_FFF_MODE=<mode>` environment variable
|
||||
3. default (`tools-and-ui`)
|
||||
3. `mode` in the global config file
|
||||
4. default (`tools-and-ui`)
|
||||
|
||||
When a session resumes, its most recent `/fff-mode` selection takes precedence over the startup resolution above. Switching to or from `override` takes effect after `/reload`, when the tools are registered again.
|
||||
|
||||
## Configuration
|
||||
|
||||
For persistent global configuration, create `pi-fff.json` in pi's agent directory (`~/.pi/agent/pi-fff.json` by default; `PI_CODING_AGENT_DIR` is respected):
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/dmtrKovalenko/fff/main/packages/pi-fff/pi-fff.schema.json",
|
||||
"mode": "override",
|
||||
"frecencyDbPath": "/path/to/frecency",
|
||||
"historyDbPath": "/path/to/history",
|
||||
"enableFsRootScanning": false,
|
||||
"enableHomeDirScanning": true
|
||||
}
|
||||
```
|
||||
|
||||
All fields are optional:
|
||||
|
||||
| Field | Type | Default |
|
||||
|---|---|---|
|
||||
| `$schema` | non-empty string | none |
|
||||
| `mode` | `tools-and-ui`, `tools-only`, or `override` | `tools-and-ui` |
|
||||
| `frecencyDbPath` | non-empty string | See [Data](#data) |
|
||||
| `historyDbPath` | non-empty string | See [Data](#data) |
|
||||
| `enableFsRootScanning` | boolean | `false` |
|
||||
| `enableHomeDirScanning` | boolean | `true` |
|
||||
|
||||
CLI flags take precedence over environment variables, which take precedence over this file. A missing file is ignored. Malformed JSON, unknown fields, and invalid values stop the extension from loading and report the file path and error. `/fff-mode` changes the current session; it does not edit this file.
|
||||
|
||||
The file is global only. Project-level config cannot safely control tool names because pi decides which tools an extension registers before project configuration can be trusted.
|
||||
|
||||
## Flags
|
||||
|
||||
- `--fff-mode <mode>` — set mode (see above)
|
||||
- `--fff-frecency-db <path>` — path to frecency database (also: `FFF_FRECENCY_DB` env)
|
||||
- `--fff-history-db <path>` — path to query history database (also: `FFF_HISTORY_DB` env)
|
||||
- `--fff-frecency-db <path>` — path to frecency database (also: `FFF_FRECENCY_DB` env). Optional; see [Data](#data) for the default.
|
||||
- `--fff-history-db <path>` — path to query history database (also: `FFF_HISTORY_DB` env). Optional; see [Data](#data) for the default.
|
||||
- `--fff-enable-root-scan` — allow indexing when launched from `/` (also: `FFF_ENABLE_ROOT_SCAN=1` env). FFF refuses to init at the filesystem root by default.
|
||||
- `--fff-enable-home-scan` — index the home directory when launched from `$HOME` (also: `FFF_ENABLE_HOME_SCAN` env). Enabled by default. Disable with `--fff-enable-home-scan=false` or `FFF_ENABLE_HOME_SCAN=0` if your `$HOME` contains huge trees (toolchains, kernel sources, build outputs) that make the background index run for a long time. When launched from `$HOME` with this enabled, pi shows a warning that the whole home tree is being indexed.
|
||||
|
||||
## Data
|
||||
|
||||
When database paths are provided, FFF stores:
|
||||
- frecency database — file access frequency/recency
|
||||
- history database — query-to-file selection history
|
||||
FFF uses two LMDB databases:
|
||||
- frecency database - file access frequency/recency, used to rank results
|
||||
- history database - query-to-file selection history
|
||||
|
||||
Each path is resolved independently, in this order:
|
||||
|
||||
1. CLI flag — `--fff-frecency-db` / `--fff-history-db`
|
||||
2. Env var — `FFF_FRECENCY_DB` / `FFF_HISTORY_DB`
|
||||
3. Global config — `frecencyDbPath` / `historyDbPath`
|
||||
4. An existing [fff.nvim](https://github.com/dmtrKovalenko/fff.nvim) database, so pi reuses the frecency you built up in your editor:
|
||||
- frecency: `$XDG_CACHE_HOME/nvim/fff_nvim`
|
||||
- history: `$XDG_DATA_HOME/nvim/fff_queries`
|
||||
- `XDG_CACHE_HOME` defaults to `~/.cache` and `XDG_DATA_HOME` to `~/.local/share`; on Windows both fall back under `%LOCALAPPDATA%\nvim-data`. Only directories count — a plain file at those paths is ignored.
|
||||
5. pi-local directory, created on demand — `$PI_CODING_AGENT_DIR/fff/{frecency,history}`, defaulting to `~/.pi/agent/fff/{frecency,history}`
|
||||
|
||||
The extension only reads these databases; it never records the agent's own searches into your Neovim history. If a database cannot be opened, the finder starts without persistence and pi shows a warning instead of failing.
|
||||
|
||||
No project files are uploaded anywhere by this extension. It runs locally and only uses the configured LLM through pi itself.
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src"
|
||||
"src",
|
||||
"pi-fff.schema.json"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -49,6 +50,7 @@
|
||||
"@sinclair/typebox": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.8",
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://raw.githubusercontent.com/dmtrKovalenko/fff/main/packages/pi-fff/pi-fff.schema.json",
|
||||
"title": "pi-fff configuration",
|
||||
"description": "Global startup configuration for the pi-fff extension.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Schema URL used by editors for validation and completion."
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["tools-and-ui", "tools-only", "override"],
|
||||
"default": "tools-and-ui",
|
||||
"description": "Controls which FFF tools and autocomplete integrations are enabled."
|
||||
},
|
||||
"frecencyDbPath": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Path to the frecency database."
|
||||
},
|
||||
"historyDbPath": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Path to the query history database."
|
||||
},
|
||||
"enableFsRootScanning": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Allows indexing when pi is launched from the filesystem root."
|
||||
},
|
||||
"enableHomeDirScanning": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Allows indexing when pi is launched from the home directory."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { FileFinderApi } from "@ff-labs/fff-node";
|
||||
import type { FilePickerFactory } from "./file-picker";
|
||||
import { HOME_DIR } from "./paths";
|
||||
import { loadSdk, SCAN_TIMEOUT_MS } from "./sdk";
|
||||
|
||||
export const MAX_AUX = 3;
|
||||
export const IDLE_TTL_MS = 5 * 60 * 1000;
|
||||
@@ -16,10 +16,9 @@ interface AuxPicker {
|
||||
export interface AuxOpts {
|
||||
enableFsRootScanning: boolean;
|
||||
enableHomeDirScanning?: boolean;
|
||||
pickers: FilePickerFactory;
|
||||
// Called before a newly spawned aux picker starts a scan that covers $HOME.
|
||||
onHomeDirScan?: (root: string) => void;
|
||||
frecencyDbPath?: string;
|
||||
historyDbPath?: string;
|
||||
}
|
||||
|
||||
export class AuxFinderPool {
|
||||
@@ -101,26 +100,13 @@ export class AuxFinderPool {
|
||||
this.opts.onHomeDirScan?.(root);
|
||||
}
|
||||
|
||||
const { FileFinder } = await loadSdk();
|
||||
const result = FileFinder.create({
|
||||
const finder = await this.opts.pickers.create({
|
||||
basePath: root,
|
||||
frecencyDbPath: this.opts.frecencyDbPath,
|
||||
historyDbPath: this.opts.historyDbPath,
|
||||
aiMode: true,
|
||||
enableHomeDirScanning,
|
||||
enableFsRootScanning: this.opts.enableFsRootScanning,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
throw new Error(`Failed to create aux file finder for ${root}: ${result.error}`);
|
||||
}
|
||||
|
||||
await result.value.waitForScan(SCAN_TIMEOUT_MS);
|
||||
const entry: AuxPicker = {
|
||||
root,
|
||||
finder: result.value,
|
||||
lastUsed: Date.now(),
|
||||
};
|
||||
const entry: AuxPicker = { root, finder, lastUsed: Date.now() };
|
||||
this.entries.push(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { piDataDir } from "./paths";
|
||||
|
||||
export const CONFIG_FILE_NAME = "pi-fff.json";
|
||||
export const VALID_MODES = ["tools-and-ui", "tools-only", "override"] as const;
|
||||
|
||||
export type FffMode = (typeof VALID_MODES)[number];
|
||||
|
||||
export interface FffConfig {
|
||||
$schema?: string;
|
||||
mode?: FffMode;
|
||||
frecencyDbPath?: string;
|
||||
historyDbPath?: string;
|
||||
enableFsRootScanning?: boolean;
|
||||
enableHomeDirScanning?: boolean;
|
||||
}
|
||||
|
||||
const CONFIG_KEYS = new Set<keyof FffConfig>([
|
||||
"$schema",
|
||||
"mode",
|
||||
"frecencyDbPath",
|
||||
"historyDbPath",
|
||||
"enableFsRootScanning",
|
||||
"enableHomeDirScanning",
|
||||
]);
|
||||
|
||||
export function loadConfig(agentDir = piDataDir()): FffConfig {
|
||||
const configPath = join(agentDir, CONFIG_FILE_NAME);
|
||||
let contents: string;
|
||||
|
||||
try {
|
||||
contents = readFileSync(configPath, "utf8");
|
||||
} catch (error: unknown) {
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") return {};
|
||||
throw new Error(
|
||||
`Could not read pi-fff config at ${configPath}: ${errorMessage(error)}`,
|
||||
);
|
||||
}
|
||||
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(contents);
|
||||
} catch (error: unknown) {
|
||||
throw invalidConfig(configPath, `not valid JSON (${errorMessage(error)})`);
|
||||
}
|
||||
|
||||
if (!isRecord(parsed)) {
|
||||
throw invalidConfig(configPath, "expected a JSON object");
|
||||
}
|
||||
|
||||
for (const key of Object.keys(parsed)) {
|
||||
if (!CONFIG_KEYS.has(key as keyof FffConfig)) {
|
||||
throw invalidConfig(configPath, `unknown option "${key}"`);
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed.mode !== undefined && !VALID_MODES.includes(parsed.mode as FffMode)) {
|
||||
throw invalidConfig(configPath, `"mode" must be one of ${VALID_MODES.join(", ")}`);
|
||||
}
|
||||
|
||||
validateString(configPath, parsed, "$schema");
|
||||
validateString(configPath, parsed, "frecencyDbPath");
|
||||
validateString(configPath, parsed, "historyDbPath");
|
||||
validateBoolean(configPath, parsed, "enableFsRootScanning");
|
||||
validateBoolean(configPath, parsed, "enableHomeDirScanning");
|
||||
|
||||
return parsed as FffConfig;
|
||||
}
|
||||
|
||||
function invalidConfig(configPath: string, reason: string): Error {
|
||||
return new Error(`Invalid pi-fff config at ${configPath}: ${reason}`);
|
||||
}
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function validateString(
|
||||
configPath: string,
|
||||
config: Record<string, unknown>,
|
||||
key: "$schema" | "frecencyDbPath" | "historyDbPath",
|
||||
): void {
|
||||
const value = config[key];
|
||||
if (value !== undefined && (typeof value !== "string" || value.length === 0)) {
|
||||
throw invalidConfig(configPath, `"${key}" must be a non-empty string`);
|
||||
}
|
||||
}
|
||||
|
||||
function validateBoolean(
|
||||
configPath: string,
|
||||
config: Record<string, unknown>,
|
||||
key: "enableFsRootScanning" | "enableHomeDirScanning",
|
||||
): void {
|
||||
const value = config[key];
|
||||
if (value !== undefined && typeof value !== "boolean") {
|
||||
throw invalidConfig(configPath, `"${key}" must be a boolean`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { FileFinderApi, InitOptions, Result } from "@ff-labs/fff-node";
|
||||
import { type FileFinderStatic, loadSdk, SCAN_TIMEOUT_MS } from "./sdk";
|
||||
|
||||
export interface PickerOptions {
|
||||
basePath: string;
|
||||
enableHomeDirScanning?: boolean;
|
||||
enableFsRootScanning?: boolean;
|
||||
}
|
||||
|
||||
/** Opens every picker in this pi process — the cwd picker and the aux pickers —
|
||||
* on the same frecency/history databases. */
|
||||
export class FilePickerFactory {
|
||||
private dbDisabled = false;
|
||||
private readonly frecencyDbPath: string;
|
||||
private readonly historyDbPath: string;
|
||||
private readonly onDbFailure?: (error: string) => void;
|
||||
|
||||
constructor(opts: {
|
||||
frecencyDbPath: string;
|
||||
historyDbPath: string;
|
||||
onDbFailure?: (error: string) => void;
|
||||
}) {
|
||||
this.frecencyDbPath = opts.frecencyDbPath;
|
||||
this.historyDbPath = opts.historyDbPath;
|
||||
this.onDbFailure = opts.onDbFailure;
|
||||
}
|
||||
|
||||
/** True once the databases were given up on, so pickers open without them. */
|
||||
get databasesDisabled(): boolean {
|
||||
return this.dbDisabled;
|
||||
}
|
||||
|
||||
/** Opens a scanned, ready-to-use picker. Throws if it cannot be created. */
|
||||
async create(options: PickerOptions): Promise<FileFinderApi> {
|
||||
const { FileFinder } = await loadSdk();
|
||||
const result = this.openWithDbFallback(FileFinder, options);
|
||||
|
||||
if (!result.ok) {
|
||||
throw new Error(
|
||||
`Failed to create FFF file picker for ${options.basePath}: ${result.error}`,
|
||||
);
|
||||
}
|
||||
|
||||
// waitForScan() also resolves on timeout, so this bounds startup rather
|
||||
// than guaranteeing a complete index.
|
||||
await result.value.waitForScan(SCAN_TIMEOUT_MS);
|
||||
return result.value;
|
||||
}
|
||||
|
||||
private openWithDbFallback(
|
||||
FileFinder: FileFinderStatic,
|
||||
options: PickerOptions,
|
||||
): Result<FileFinderApi> {
|
||||
const init: InitOptions = { ...options, aiMode: true };
|
||||
if (this.dbDisabled) return FileFinder.create(init);
|
||||
|
||||
const result = FileFinder.create({
|
||||
...init,
|
||||
frecencyDbPath: this.frecencyDbPath,
|
||||
historyDbPath: this.historyDbPath,
|
||||
});
|
||||
if (result.ok) return result;
|
||||
|
||||
// A failure here is usually transient (broken lock, corruption) and self-heals
|
||||
// on restart, so drop the databases instead of leaving pi without a picker
|
||||
const dbLess = FileFinder.create(init);
|
||||
if (!dbLess.ok) return result; // db error is the more useful one to report
|
||||
|
||||
this.dbDisabled = true;
|
||||
this.onDbFailure?.(result.error);
|
||||
return dbLess;
|
||||
}
|
||||
}
|
||||
+254
-144
@@ -6,7 +6,11 @@
|
||||
*/
|
||||
|
||||
import nodePath from "node:path";
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import type {
|
||||
ExtensionAPI,
|
||||
ExtensionContext,
|
||||
ToolDefinition,
|
||||
} from "@earendil-works/pi-coding-agent";
|
||||
import {
|
||||
type AutocompleteItem,
|
||||
type AutocompleteProvider,
|
||||
@@ -20,11 +24,12 @@ import type {
|
||||
MixedItem,
|
||||
SearchResult,
|
||||
} from "@ff-labs/fff-node";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { Type, type TSchema } from "@sinclair/typebox";
|
||||
import { AuxFinderPool, routePathConstraint } from "./aux-finders";
|
||||
import { type FffMode, loadConfig, VALID_MODES } from "./config";
|
||||
import { FilePickerFactory } from "./file-picker";
|
||||
import { isHomeDir, resolveDbPaths } from "./paths";
|
||||
import { buildQuery } from "./query";
|
||||
import { isHomeDir } from "./paths";
|
||||
import { loadSdk, SCAN_TIMEOUT_MS } from "./sdk";
|
||||
|
||||
export { SCAN_TIMEOUT_MS } from "./sdk";
|
||||
|
||||
@@ -45,11 +50,7 @@ const GREP_TIME_BUDGET_MS = 10_000;
|
||||
const HOME_SCAN_STATUS_KEY = "fff";
|
||||
const HOME_SCAN_POLL_MS = 1_000;
|
||||
const HOME_SCAN_DISABLE_HINT =
|
||||
"You can prevent home dir indexing with --fff-enable-home-scan=false (or FFF_ENABLE_HOME_SCAN=0).";
|
||||
|
||||
type FffMode = "tools-and-ui" | "tools-only" | "override";
|
||||
|
||||
const VALID_MODES: FffMode[] = ["tools-and-ui", "tools-only", "override"];
|
||||
"You can prevent home dir indexing with --fff-enable-home-scan=false, FFF_ENABLE_HOME_SCAN=0, or enableHomeDirScanning in pi-fff.json.";
|
||||
|
||||
interface ToolNames {
|
||||
grep: string;
|
||||
@@ -162,16 +163,7 @@ export function fffFileAnnotation(item: {
|
||||
return "";
|
||||
}
|
||||
|
||||
// fff-core native definition classifier (byte-level scanner in Rust) is enabled
|
||||
// via GrepOptions.classifyDefinitions. Each GrepMatch carries isDefinition for
|
||||
// downstream consumers; pi-fff does NOT use it to re-sort.
|
||||
//
|
||||
// Ordering policy: NO CUSTOM SORTING. The engine already returns items in
|
||||
// frecency order (most-accessed files first). pi-fff only groups consecutive
|
||||
// matches into per-file blocks and preserves whatever order the engine
|
||||
// provided — inside a file we keep matches in source-line order because the
|
||||
// engine emits them that way.
|
||||
|
||||
// DO NOT ATTEMPT TO RESORT OUTPUT HERE IT ONLY CONFUSES MODELS
|
||||
function formatGrepOutput(result: GrepResult): string {
|
||||
if (result.items.length === 0) return "No matches found";
|
||||
|
||||
@@ -179,7 +171,6 @@ function formatGrepOutput(result: GrepResult): string {
|
||||
// This preserves native frecency ordering across files without re-sorting.
|
||||
const lines: string[] = [];
|
||||
let currentFile = "";
|
||||
let shown = 0;
|
||||
|
||||
for (const match of result.items) {
|
||||
if (match.relativePath !== currentFile) {
|
||||
@@ -194,7 +185,6 @@ function formatGrepOutput(result: GrepResult): string {
|
||||
});
|
||||
|
||||
lines.push(` ${match.lineNumber}: ${truncateLine(match.lineContent)}`);
|
||||
shown++;
|
||||
|
||||
match.contextAfter?.forEach((line: string, i: number) => {
|
||||
const lineNum = match.lineNumber + 1 + i;
|
||||
@@ -310,53 +300,95 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
let finderPromise: Promise<FileFinderApi> | null = null;
|
||||
let activeCwd = process.cwd();
|
||||
|
||||
// Mode resolution: flag > env > default
|
||||
let currentMode: FffMode =
|
||||
(pi.getFlag("fff-mode") as FffMode) ??
|
||||
(process.env.PI_FFF_MODE as FffMode) ??
|
||||
"tools-and-ui";
|
||||
const config = loadConfig();
|
||||
|
||||
const toolNames = resolveToolNames(currentMode);
|
||||
// All startup options use the same flag > env > file > fallback order.
|
||||
function getConfigValue<T>(
|
||||
flagName: string,
|
||||
envName: string,
|
||||
fileValue: T | undefined,
|
||||
fallback: T,
|
||||
parse: (value: unknown) => T | undefined = (value) => value as T,
|
||||
): T {
|
||||
const flagValue = pi.getFlag(flagName);
|
||||
if (flagValue !== undefined) {
|
||||
const value = parse(flagValue);
|
||||
if (value !== undefined) return value;
|
||||
}
|
||||
|
||||
// DB path resolution: flag > env > undefined (no persistent DBs)
|
||||
const frecencyDbPath =
|
||||
(pi.getFlag("fff-frecency-db") as string | undefined) ??
|
||||
process.env.FFF_FRECENCY_DB ??
|
||||
undefined;
|
||||
const historyDbPath =
|
||||
(pi.getFlag("fff-history-db") as string | undefined) ??
|
||||
process.env.FFF_HISTORY_DB ??
|
||||
undefined;
|
||||
const envValue = process.env[envName];
|
||||
if (envValue !== undefined) {
|
||||
const value = parse(envValue);
|
||||
if (value !== undefined) return value;
|
||||
}
|
||||
|
||||
// flag (boolean) > env ("1"/"true", or "0"/"false") > default.
|
||||
function resolveBoolOpt(flagName: string, envName: string, fallback = false): boolean {
|
||||
const flag = pi.getFlag(flagName);
|
||||
if (typeof flag === "boolean") return flag;
|
||||
if (typeof flag === "string") return flag === "true" || flag === "1";
|
||||
const env = process.env[envName];
|
||||
if (env === "1" || env === "true") return true;
|
||||
if (env === "0" || env === "false") return false;
|
||||
return fallback;
|
||||
return fileValue ?? fallback;
|
||||
}
|
||||
// Root scanning opt-in: FFF refuses to init at / unless this is set.
|
||||
const enableFsRootScanning = resolveBoolOpt(
|
||||
"fff-enable-root-scan",
|
||||
"FFF_ENABLE_ROOT_SCAN",
|
||||
);
|
||||
// Home dir scanning is on by default (launching pi from $HOME is a normal
|
||||
// flow), but configurable so users with huge $HOME trees can opt out.
|
||||
const enableHomeDirScanning = resolveBoolOpt(
|
||||
"fff-enable-home-scan",
|
||||
"FFF_ENABLE_HOME_SCAN",
|
||||
true,
|
||||
);
|
||||
|
||||
function getMode(): FffMode {
|
||||
return currentMode;
|
||||
function parseBoolean(value: unknown): boolean | undefined {
|
||||
if (typeof value === "boolean") return value;
|
||||
if (value === "1" || value === "true") return true;
|
||||
if (value === "0" || value === "false") return false;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseMode(value: unknown): FffMode | undefined {
|
||||
return typeof value === "string" && VALID_MODES.includes(value as FffMode)
|
||||
? (value as FffMode)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
let currentMode: FffMode = "tools-and-ui";
|
||||
let toolNames = resolveToolNames(currentMode);
|
||||
let resolvedDbPaths: ReturnType<typeof resolveDbPaths>;
|
||||
let enableFsRootScanning = false;
|
||||
let enableHomeDirScanning = true;
|
||||
|
||||
function setMode(mode: FffMode): void {
|
||||
currentMode = mode;
|
||||
toolNames = resolveToolNames(mode);
|
||||
}
|
||||
|
||||
function resolveStartupConfig(): void {
|
||||
setMode(
|
||||
getConfigValue("fff-mode", "PI_FFF_MODE", config.mode, "tools-and-ui", parseMode),
|
||||
);
|
||||
resolvedDbPaths = resolveDbPaths({
|
||||
frecency: getConfigValue(
|
||||
"fff-frecency-db",
|
||||
"FFF_FRECENCY_DB",
|
||||
config.frecencyDbPath,
|
||||
undefined,
|
||||
),
|
||||
history: getConfigValue(
|
||||
"fff-history-db",
|
||||
"FFF_HISTORY_DB",
|
||||
config.historyDbPath,
|
||||
undefined,
|
||||
),
|
||||
});
|
||||
|
||||
// Root scanning opt-in: FFF refuses to init at / unless this is set.
|
||||
enableFsRootScanning = getConfigValue(
|
||||
"fff-enable-root-scan",
|
||||
"FFF_ENABLE_ROOT_SCAN",
|
||||
config.enableFsRootScanning,
|
||||
false,
|
||||
parseBoolean,
|
||||
);
|
||||
// Home dir scanning is on by default (launching pi from $HOME is a normal
|
||||
// flow), but configurable so users with huge $HOME trees can opt out.
|
||||
enableHomeDirScanning = getConfigValue(
|
||||
"fff-enable-home-scan",
|
||||
"FFF_ENABLE_HOME_SCAN",
|
||||
config.enableHomeDirScanning,
|
||||
true,
|
||||
parseBoolean,
|
||||
);
|
||||
}
|
||||
|
||||
function getMode(): FffMode {
|
||||
return currentMode;
|
||||
}
|
||||
|
||||
function shouldEnableMentions(): boolean {
|
||||
@@ -380,13 +412,28 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
);
|
||||
}
|
||||
|
||||
const auxPool = new AuxFinderPool({
|
||||
enableFsRootScanning,
|
||||
enableHomeDirScanning,
|
||||
onHomeDirScan: warnHomeDirScan,
|
||||
frecencyDbPath,
|
||||
historyDbPath,
|
||||
});
|
||||
let pickers: FilePickerFactory | null = null;
|
||||
let auxPool: AuxFinderPool | null = null;
|
||||
|
||||
function initializeFinderFactories(): void {
|
||||
if (pickers) return;
|
||||
|
||||
pickers = new FilePickerFactory({
|
||||
frecencyDbPath: resolvedDbPaths.frecency,
|
||||
historyDbPath: resolvedDbPaths.history,
|
||||
onDbFailure: (error) =>
|
||||
uiCtx?.ui.notify(
|
||||
`(fff): Failed to open frecency/history database (${error}). Continuing without frecency persistence.`,
|
||||
"error",
|
||||
),
|
||||
});
|
||||
auxPool = new AuxFinderPool({
|
||||
enableFsRootScanning,
|
||||
enableHomeDirScanning,
|
||||
onHomeDirScan: warnHomeDirScan,
|
||||
pickers,
|
||||
});
|
||||
}
|
||||
|
||||
// in case cwd changes we need to figure this out
|
||||
function ensureFinder(cwd: string): Promise<FileFinderApi> {
|
||||
@@ -402,22 +449,15 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
finderCwd = null;
|
||||
}
|
||||
|
||||
const { FileFinder } = await loadSdk();
|
||||
const result = FileFinder.create({
|
||||
// if the dbs can't be opened the factory falls back to a db-less picker,
|
||||
// e.g. when some other process corrupts the lock
|
||||
if (!pickers) throw new Error("FFF picker factory is not initialized");
|
||||
mainFinder = await pickers.create({
|
||||
basePath: cwd,
|
||||
frecencyDbPath,
|
||||
historyDbPath,
|
||||
aiMode: true,
|
||||
enableHomeDirScanning,
|
||||
enableFsRootScanning,
|
||||
});
|
||||
|
||||
if (!result.ok)
|
||||
throw new Error(`Failed to create FFF file finder: ${result.error}`);
|
||||
|
||||
mainFinder = result.value;
|
||||
finderCwd = cwd;
|
||||
await mainFinder.waitForScan(SCAN_TIMEOUT_MS);
|
||||
return mainFinder;
|
||||
})().finally(() => {
|
||||
finderPromise = null;
|
||||
@@ -466,9 +506,9 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
finderCwd = null;
|
||||
}
|
||||
|
||||
if (auxPool) {
|
||||
auxPool.destroy();
|
||||
}
|
||||
auxPool?.destroy();
|
||||
auxPool = null;
|
||||
pickers = null;
|
||||
}
|
||||
|
||||
async function resolveFinderForPath(
|
||||
@@ -478,6 +518,7 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
): Promise<{ finder: FileFinderApi; query: string; root: string } | null> {
|
||||
const route = routePathConstraint(pathParam, activeCwd);
|
||||
if (!route) return null;
|
||||
if (!auxPool) throw new Error("FFF auxiliary finder pool is not initialized");
|
||||
const aux = await auxPool.acquire(route.root);
|
||||
// A broader covering picker may have been reused; rebase the suffix so the
|
||||
// constraint stays relative to the picker's actual root.
|
||||
@@ -558,6 +599,45 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
});
|
||||
}
|
||||
|
||||
type PendingToolDefinition<
|
||||
TParams extends TSchema,
|
||||
TDetails = unknown,
|
||||
TState = any,
|
||||
> = Omit<
|
||||
ToolDefinition<TParams, TDetails, TState>,
|
||||
"name" | "label" | "promptGuidelines"
|
||||
> & {
|
||||
promptGuidelines?: (names: ToolNames) => string[];
|
||||
};
|
||||
|
||||
const pendingTools: (() => string)[] = [];
|
||||
let toolsRegistered = false;
|
||||
|
||||
function queueTool<TParams extends TSchema, TDetails = unknown, TState = any>(
|
||||
resolveName: () => string,
|
||||
definition: PendingToolDefinition<TParams, TDetails, TState>,
|
||||
): void {
|
||||
pendingTools.push(() => {
|
||||
const { promptGuidelines, ...tool } = definition;
|
||||
const resolvedName = resolveName();
|
||||
pi.registerTool({
|
||||
...tool,
|
||||
name: resolvedName,
|
||||
label: resolvedName,
|
||||
promptGuidelines: promptGuidelines?.(toolNames),
|
||||
});
|
||||
return resolvedName;
|
||||
});
|
||||
}
|
||||
|
||||
function registerPendingTools(): void {
|
||||
if (toolsRegistered) return;
|
||||
|
||||
const registeredNames = pendingTools.map((register) => register());
|
||||
pi.setActiveTools([...new Set([...pi.getActiveTools(), ...registeredNames])]);
|
||||
toolsRegistered = true;
|
||||
}
|
||||
|
||||
// --- Flags / lifecycle ---
|
||||
|
||||
pi.registerFlag("fff-mode", {
|
||||
@@ -587,34 +667,48 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
type: "boolean",
|
||||
});
|
||||
|
||||
function reportInitFailure(ctx: ExtensionContext, error: unknown): void {
|
||||
ctx.ui.notify(
|
||||
`FFF init failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
"error",
|
||||
);
|
||||
}
|
||||
|
||||
function prepareSession(ctx: ExtensionContext): void {
|
||||
activeCwd = ctx.cwd;
|
||||
uiCtx = ctx;
|
||||
if (toolsRegistered) return;
|
||||
|
||||
// Pi populates extension flag values after loading extensions.
|
||||
resolveStartupConfig();
|
||||
|
||||
// Restore persisted mode before registering tools so a saved override
|
||||
// can safely change their names after /reload or session resume.
|
||||
const entries = ctx.sessionManager?.getEntries();
|
||||
if (entries) {
|
||||
const modeEntry = [...entries]
|
||||
.reverse()
|
||||
.find(
|
||||
(e: { type: string; customType?: string }) =>
|
||||
e.type === "custom" && e.customType === "fff-mode",
|
||||
);
|
||||
if (
|
||||
modeEntry &&
|
||||
typeof (modeEntry as any).data?.mode === "string" &&
|
||||
VALID_MODES.includes((modeEntry as any).data.mode as FffMode)
|
||||
) {
|
||||
const restored = (modeEntry as any).data.mode as FffMode;
|
||||
if (restored !== currentMode) setMode(restored);
|
||||
}
|
||||
}
|
||||
|
||||
initializeFinderFactories();
|
||||
registerPendingTools();
|
||||
}
|
||||
|
||||
pi.on("session_start", async (_event, ctx) => {
|
||||
try {
|
||||
activeCwd = ctx.cwd;
|
||||
uiCtx = ctx as unknown as typeof uiCtx;
|
||||
|
||||
// Restore persisted mode from session entries. This handles session
|
||||
// resume after process restart where env vars are lost, and ensures
|
||||
// the env var is set for the next /reload in the same session.
|
||||
const entries = ctx.sessionManager?.getEntries();
|
||||
if (entries) {
|
||||
const modeEntry = [...entries]
|
||||
.reverse()
|
||||
.find(
|
||||
(e: { type: string; customType?: string }) =>
|
||||
e.type === "custom" && e.customType === "fff-mode",
|
||||
);
|
||||
if (
|
||||
modeEntry &&
|
||||
typeof (modeEntry as any).data?.mode === "string" &&
|
||||
VALID_MODES.includes((modeEntry as any).data.mode as FffMode)
|
||||
) {
|
||||
const restored = (modeEntry as any).data.mode as FffMode;
|
||||
if (restored !== currentMode) {
|
||||
currentMode = restored;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prepareSession(ctx);
|
||||
registerAutocompleteProvider(ctx);
|
||||
await ensureFinder(activeCwd);
|
||||
|
||||
@@ -632,11 +726,19 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
// waitForScan() also resolves on timeout, so poll until the scan really
|
||||
// settles before clearing the footer.
|
||||
if (atHome) trackHomeScanStatus();
|
||||
} catch (e: unknown) {
|
||||
ctx.ui.notify(
|
||||
`FFF init failed: ${e instanceof Error ? e.message : String(e)}`,
|
||||
"error",
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
reportInitFailure(ctx, error);
|
||||
}
|
||||
});
|
||||
|
||||
// SDK callers can prompt without binding session_start. Prepare on the first
|
||||
// agent turn as a fallback so the tools still reach that turn's tool set.
|
||||
pi.on("before_agent_start", (_event, ctx) => {
|
||||
if (toolsRegistered) return;
|
||||
try {
|
||||
prepareSession(ctx);
|
||||
} catch (error: unknown) {
|
||||
reportInitFailure(ctx, error);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -712,16 +814,14 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
),
|
||||
});
|
||||
|
||||
pi.registerTool({
|
||||
name: toolNames.grep,
|
||||
label: toolNames.grep,
|
||||
queueTool(() => toolNames.grep, {
|
||||
description: `Grep file contents. Smart-case, auto-detects regex vs literal, git-aware. Results are ranked by frecency (most-accessed files first); matches within a file stay in source order. Default limit ${DEFAULT_GREP_LIMIT}.`,
|
||||
promptSnippet: "Grep contents",
|
||||
promptGuidelines: [
|
||||
`${toolNames.grep}: prefer bare identifiers as patterns. Literal queries are most efficient.`,
|
||||
`${toolNames.grep}: use path for include ('src/', '*.ts') and exclude for noise ('test/,*.min.js').`,
|
||||
`${toolNames.grep}: caseSensitive: true when you need exact case (smart-case otherwise).`,
|
||||
`${toolNames.grep}: after 1-2 greps, read the top match instead of more greps.`,
|
||||
promptGuidelines: (names) => [
|
||||
`${names.grep}: prefer bare identifiers as patterns. Literal queries are most efficient.`,
|
||||
`${names.grep}: use path for include ('src/', '*.ts') and exclude for noise ('test/,*.min.js').`,
|
||||
`${names.grep}: caseSensitive: true when you need exact case (smart-case otherwise).`,
|
||||
`${names.grep}: after 1-2 greps, read the top match instead of more greps.`,
|
||||
],
|
||||
parameters: grepSchema,
|
||||
|
||||
@@ -903,18 +1003,16 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
),
|
||||
});
|
||||
|
||||
pi.registerTool({
|
||||
name: toolNames.find,
|
||||
label: toolNames.find,
|
||||
queueTool(() => toolNames.find, {
|
||||
description: `Fuzzy path search and glob search. Matches against the whole repo-relative path, not just the filename. Frecency-ranked, git-aware. Multi-word = narrower (AND). Default limit ${DEFAULT_FIND_LIMIT}.`,
|
||||
promptSnippet: "Find files by path or glob",
|
||||
promptGuidelines: [
|
||||
`${toolNames.find}: matches the WHOLE path, not just the filename — \`profile\` hits \`chrome/browser/profiles/x.cc\` too.`,
|
||||
`${toolNames.find}: keep queries to 1-2 terms; extra words narrow.`,
|
||||
`${toolNames.find}: use for paths, not content. Use ${toolNames.grep} for content.`,
|
||||
`${toolNames.find}: for exact path matches use a glob in \`path\` — e.g. path: '**/profile.h' for exact filename, or path: 'src/**/profile.h' scoped to a subtree. Bare patterns are fuzzy.`,
|
||||
`${toolNames.find}: to list everything inside a directory, pass path: 'dir/**' with an empty or wildcard pattern instead of using pattern alone.`,
|
||||
`${toolNames.find}: use exclude: 'test/,*.min.js' to cut noise in large repos.`,
|
||||
promptGuidelines: (names) => [
|
||||
`${names.find}: matches the WHOLE path, not just the filename — \`profile\` hits \`chrome/browser/profiles/x.cc\` too.`,
|
||||
`${names.find}: keep queries to 1-2 terms; extra words narrow.`,
|
||||
`${names.find}: use for paths, not content. Use ${names.grep} for content.`,
|
||||
`${names.find}: for exact path matches use a glob in \`path\` — e.g. path: '**/profile.h' for exact filename, or path: 'src/**/profile.h' scoped to a subtree. Bare patterns are fuzzy.`,
|
||||
`${names.find}: to list everything inside a directory, pass path: 'dir/**' with an empty or wildcard pattern instead of using pattern alone.`,
|
||||
`${names.find}: use exclude: 'test/,*.min.js' to cut noise in large repos.`,
|
||||
],
|
||||
parameters: findSchema,
|
||||
|
||||
@@ -923,10 +1021,12 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
|
||||
// if resumed we use the same picker as before
|
||||
const resumed = params.cursor ? getFindCursor(params.cursor) : undefined;
|
||||
const pool = auxPool;
|
||||
if (!pool) throw new Error("FFF auxiliary finder pool is not initialized");
|
||||
const aux = resumed
|
||||
? resumed.auxRoot
|
||||
? {
|
||||
finder: (await auxPool.acquire(resumed.auxRoot, { exact: true })).finder,
|
||||
finder: (await pool.acquire(resumed.auxRoot, { exact: true })).finder,
|
||||
root: resumed.auxRoot,
|
||||
}
|
||||
: null
|
||||
@@ -1043,16 +1143,14 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
cursor: Type.Optional(Type.String({ description: "Pagination cursor" })),
|
||||
});
|
||||
|
||||
pi.registerTool({
|
||||
name: toolNames.multiGrep,
|
||||
label: toolNames.multiGrep,
|
||||
queueTool(() => toolNames.multiGrep, {
|
||||
description:
|
||||
"Search file contents for ANY of multiple literal patterns (OR, SIMD Aho-Corasick). Faster than regex alternation.",
|
||||
promptSnippet: "Multi-pattern OR content search",
|
||||
promptGuidelines: [
|
||||
`${toolNames.multiGrep}: use when searching for several identifiers at once.`,
|
||||
`${toolNames.multiGrep}: include all naming-convention variants (snake/camel/Pascal).`,
|
||||
`${toolNames.multiGrep}: patterns are literal. Use constraints for file filters.`,
|
||||
promptGuidelines: (names) => [
|
||||
`${names.multiGrep}: use when searching for several identifiers at once.`,
|
||||
`${names.multiGrep}: include all naming-convention variants (snake/camel/Pascal).`,
|
||||
`${names.multiGrep}: patterns are literal. Use constraints for file filters.`,
|
||||
],
|
||||
parameters: multiGrepSchema,
|
||||
|
||||
@@ -1127,6 +1225,15 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
pi.registerCommand("fff-mode", {
|
||||
description: "Show or set FFF mode: /fff-mode [tools-and-ui | tools-only | override]",
|
||||
handler: async (args, ctx) => {
|
||||
if (!toolsRegistered) {
|
||||
try {
|
||||
prepareSession(ctx);
|
||||
} catch (error: unknown) {
|
||||
reportInitFailure(ctx, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const arg = (args || "").trim();
|
||||
|
||||
// No args - show current mode
|
||||
@@ -1145,15 +1252,18 @@ export default function fffExtension(pi: ExtensionAPI) {
|
||||
|
||||
const newMode = arg as FffMode;
|
||||
const oldMode = getMode();
|
||||
setMode(newMode);
|
||||
|
||||
pi.appendEntry("fff-mode", { mode: newMode });
|
||||
|
||||
const note =
|
||||
(oldMode === "override") !== (newMode === "override")
|
||||
? " (tool name change requires /reload)"
|
||||
: "";
|
||||
ctx.ui.notify(`Mode changed: '${oldMode}' → '${newMode}'${note}`, "info");
|
||||
if ((oldMode === "override") !== (newMode === "override")) {
|
||||
ctx.ui.notify(
|
||||
`Mode '${newMode}' saved. Run /reload to apply the tool name change.`,
|
||||
"info",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setMode(newMode);
|
||||
ctx.ui.notify(`Mode changed: '${oldMode}' → '${newMode}'`, "info");
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,67 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
// Resolved once per process: os.homedir() hits the env/passwd on every call.
|
||||
export const HOME_DIR = path.resolve(os.homedir());
|
||||
|
||||
// fff.nvim db dir names (`frecency.db_path` / `history.db_path` in lua/fff/conf.lua).
|
||||
const NVIM_FRECENCY_DIR = "fff_nvim";
|
||||
const NVIM_HISTORY_DIR = "fff_queries";
|
||||
|
||||
export interface DbPaths {
|
||||
frecency: string;
|
||||
history: string;
|
||||
}
|
||||
|
||||
export function isHomeDir(dir: string): boolean {
|
||||
return path.resolve(dir) === HOME_DIR;
|
||||
}
|
||||
|
||||
// Resolution order: explicit override > existing fff.nvim db > pi-local data dir.
|
||||
// Reusing the nvim db lets pi rank files by the frecency the user built in their editor.
|
||||
export function resolveDbPaths(overrides: {
|
||||
frecency?: string;
|
||||
history?: string;
|
||||
}): DbPaths {
|
||||
return {
|
||||
frecency:
|
||||
overrides.frecency ??
|
||||
existingDir(nvimCacheDir(), NVIM_FRECENCY_DIR) ??
|
||||
path.join(piDataDir(), "fff", "frecency"),
|
||||
history:
|
||||
overrides.history ??
|
||||
existingDir(nvimDataDir(), NVIM_HISTORY_DIR) ??
|
||||
path.join(piDataDir(), "fff", "history"),
|
||||
};
|
||||
}
|
||||
|
||||
function nvimCacheDir(): string {
|
||||
const xdg = process.env.XDG_CACHE_HOME;
|
||||
if (xdg) return path.join(xdg, "nvim");
|
||||
if (process.platform === "win32" && process.env.LOCALAPPDATA)
|
||||
return path.join(process.env.LOCALAPPDATA, "nvim-data", "cache");
|
||||
return path.join(HOME_DIR, ".cache", "nvim");
|
||||
}
|
||||
|
||||
function nvimDataDir(): string {
|
||||
const xdg = process.env.XDG_DATA_HOME;
|
||||
if (xdg) return path.join(xdg, "nvim");
|
||||
if (process.platform === "win32" && process.env.LOCALAPPDATA)
|
||||
return path.join(process.env.LOCALAPPDATA, "nvim-data");
|
||||
return path.join(HOME_DIR, ".local", "share", "nvim");
|
||||
}
|
||||
|
||||
export function piDataDir(): string {
|
||||
return process.env.PI_CODING_AGENT_DIR ?? path.join(HOME_DIR, ".pi", "agent");
|
||||
}
|
||||
|
||||
// LMDB environments are directories, so a stray file at the same path is not a db.
|
||||
function existingDir(parent: string, name: string): string | undefined {
|
||||
const candidate = path.join(parent, name);
|
||||
try {
|
||||
return fs.statSync(candidate).isDirectory() ? candidate : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,22 @@ mock.module("@ff-labs/fff-node", () => finderModule);
|
||||
mock.module("@ff-labs/fff-bun", () => finderModule);
|
||||
|
||||
const { AuxFinderPool } = await import("../src/aux-finders");
|
||||
const { FilePickerFactory } = await import("../src/file-picker");
|
||||
|
||||
function makePickers() {
|
||||
return new FilePickerFactory({
|
||||
frecencyDbPath: "/dbs/frecency",
|
||||
historyDbPath: "/dbs/history",
|
||||
});
|
||||
}
|
||||
|
||||
describe("AuxFinderPool concurrent dedup (#746)", () => {
|
||||
test("two concurrent acquires for same root share one finder", async () => {
|
||||
created.length = 0;
|
||||
const pool = new AuxFinderPool({ enableFsRootScanning: false });
|
||||
const pool = new AuxFinderPool({
|
||||
enableFsRootScanning: false,
|
||||
pickers: makePickers(),
|
||||
});
|
||||
const [a, b] = await Promise.all([
|
||||
pool.acquire("/Users/x"),
|
||||
pool.acquire("/Users/x"),
|
||||
@@ -51,7 +62,10 @@ describe("AuxFinderPool concurrent dedup (#746)", () => {
|
||||
|
||||
test("sequential acquire after in-flight one resolves still reuses", async () => {
|
||||
created.length = 0;
|
||||
const pool = new AuxFinderPool({ enableFsRootScanning: false });
|
||||
const pool = new AuxFinderPool({
|
||||
enableFsRootScanning: false,
|
||||
pickers: makePickers(),
|
||||
});
|
||||
const first = pool.acquire("/Users/x");
|
||||
const second = pool.acquire("/Users/x");
|
||||
await Promise.all([first, second]);
|
||||
|
||||
@@ -25,10 +25,19 @@ function createMockFinder(basePath: string): MockFinder {
|
||||
return finder;
|
||||
}
|
||||
|
||||
// Set to make db-backed creates fail, mimicking a corrupt/locked LMDB.
|
||||
let failDbCreates = false;
|
||||
// Set to make every create fail, db-backed or not.
|
||||
let failAllCreates = false;
|
||||
|
||||
const finderModule = {
|
||||
FileFinder: {
|
||||
create: (options: Record<string, unknown>) => {
|
||||
createOptions.push(options);
|
||||
if (failAllCreates || (failDbCreates && options.frecencyDbPath !== undefined)) {
|
||||
return { ok: false as const, error: "db locked" };
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
value: createMockFinder(options.basePath as string),
|
||||
@@ -41,11 +50,26 @@ mock.module("@ff-labs/fff-node", () => finderModule);
|
||||
mock.module("@ff-labs/fff-bun", () => finderModule);
|
||||
|
||||
const { AuxFinderPool } = await import("../src/aux-finders");
|
||||
const { FilePickerFactory } = await import("../src/file-picker");
|
||||
|
||||
function makePool(opts: Record<string, unknown> = {}) {
|
||||
created.length = 0;
|
||||
createOptions.length = 0;
|
||||
return new AuxFinderPool({ enableFsRootScanning: false, ...opts });
|
||||
failDbCreates = false;
|
||||
failAllCreates = false;
|
||||
return new AuxFinderPool({
|
||||
enableFsRootScanning: false,
|
||||
pickers: makePickers(),
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
function makePickers(onDbFailure?: (error: string) => void) {
|
||||
return new FilePickerFactory({
|
||||
frecencyDbPath: "/dbs/frecency",
|
||||
historyDbPath: "/dbs/history",
|
||||
onDbFailure,
|
||||
});
|
||||
}
|
||||
|
||||
describe("AuxFinderPool covering reuse", () => {
|
||||
@@ -97,7 +121,7 @@ describe("AuxFinderPool covering reuse", () => {
|
||||
// Regression for #743: the agent spawning an aux picker over $HOME must warn
|
||||
// the user every time, not silently walk the home tree.
|
||||
test("notifies on every aux picker that covers $HOME", async () => {
|
||||
const onHomeDirScan = mock(() => undefined);
|
||||
const onHomeDirScan = mock((_root: string) => undefined);
|
||||
const pool = makePool({ onHomeDirScan });
|
||||
const home = os.homedir();
|
||||
|
||||
@@ -122,10 +146,7 @@ describe("AuxFinderPool covering reuse", () => {
|
||||
// #700 is fixed by the process-wide LMDB env pool: same-path opens share one
|
||||
// env, so aux finders now reuse the session's frecency/history DBs.
|
||||
test("aux finders receive the pool's frecency/history db paths", async () => {
|
||||
const pool = makePool({
|
||||
frecencyDbPath: "/dbs/frecency",
|
||||
historyDbPath: "/dbs/history",
|
||||
});
|
||||
const pool = makePool();
|
||||
await pool.acquire("/a/b/c");
|
||||
await pool.acquire("/x/y");
|
||||
expect(createOptions.length).toBe(2);
|
||||
@@ -135,10 +156,50 @@ describe("AuxFinderPool covering reuse", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("aux finders stay db-less when the session has no db paths", async () => {
|
||||
const pool = makePool();
|
||||
test("aux finder falls back to no dbs when opening them fails", async () => {
|
||||
const failures: string[] = [];
|
||||
const pool = makePool({ pickers: makePickers((e) => failures.push(e)) });
|
||||
failDbCreates = true;
|
||||
|
||||
const entry = await pool.acquire("/a/b/c");
|
||||
|
||||
expect(entry.root).toBe("/a/b/c");
|
||||
expect(createOptions.length).toBe(2);
|
||||
expect(createOptions[0].frecencyDbPath).toBe("/dbs/frecency");
|
||||
expect(createOptions[1].frecencyDbPath).toBeUndefined();
|
||||
expect(failures).toEqual(["db locked"]);
|
||||
});
|
||||
|
||||
test("a db failure on the main finder keeps later aux finders db-less", async () => {
|
||||
const failures: string[] = [];
|
||||
const pickers = makePickers((e) => failures.push(e));
|
||||
const pool = makePool({ pickers });
|
||||
failDbCreates = true;
|
||||
|
||||
// Stands in for the main cwd picker hitting the broken db first.
|
||||
// The SDK is mocked, so create() hands back a MockFinder, not a real finder.
|
||||
const main = (await pickers.create({
|
||||
basePath: "/workspace",
|
||||
})) as unknown as MockFinder;
|
||||
expect(main.basePath).toBe("/workspace");
|
||||
expect(pickers.databasesDisabled).toBe(true);
|
||||
|
||||
createOptions.length = 0;
|
||||
await pool.acquire("/a/b/c");
|
||||
|
||||
// No retry: the factory already gave up on the dbs, so one db-less create.
|
||||
expect(createOptions.length).toBe(1);
|
||||
expect(createOptions[0].frecencyDbPath).toBeUndefined();
|
||||
expect(createOptions[0].historyDbPath).toBeUndefined();
|
||||
expect(failures).toEqual(["db locked"]);
|
||||
});
|
||||
|
||||
test("create throws when the picker cannot be opened at all", async () => {
|
||||
makePool();
|
||||
failAllCreates = true;
|
||||
|
||||
expect(makePickers().create({ basePath: "/nope" })).rejects.toThrow(
|
||||
"Failed to create FFF file picker for /nope: db locked",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { CONFIG_FILE_NAME, loadConfig } from "../src/config";
|
||||
|
||||
describe("loadConfig", () => {
|
||||
let agentDir: string;
|
||||
let configPath: string;
|
||||
|
||||
beforeEach(() => {
|
||||
agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fff-config-"));
|
||||
configPath = path.join(agentDir, CONFIG_FILE_NAME);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(agentDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("returns an empty config when the file does not exist", () => {
|
||||
expect(loadConfig(agentDir)).toEqual({});
|
||||
});
|
||||
|
||||
test("loads every supported option", () => {
|
||||
const config = {
|
||||
$schema:
|
||||
"https://raw.githubusercontent.com/dmtrKovalenko/fff/main/packages/pi-fff/pi-fff.schema.json",
|
||||
mode: "override" as const,
|
||||
frecencyDbPath: "/data/frecency",
|
||||
historyDbPath: "/data/history",
|
||||
enableFsRootScanning: true,
|
||||
enableHomeDirScanning: false,
|
||||
};
|
||||
writeConfig(config);
|
||||
|
||||
expect(loadConfig(agentDir)).toEqual(config);
|
||||
});
|
||||
|
||||
test("rejects malformed JSON", () => {
|
||||
fs.writeFileSync(configPath, '{"mode":');
|
||||
|
||||
expect(() => loadConfig(agentDir)).toThrow(
|
||||
`Invalid pi-fff config at ${configPath}: not valid JSON`,
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects non-object config", () => {
|
||||
writeConfig(["override"]);
|
||||
|
||||
expect(() => loadConfig(agentDir)).toThrow("expected a JSON object");
|
||||
});
|
||||
|
||||
test("rejects unknown options", () => {
|
||||
writeConfig({ mode: "override", typo: true });
|
||||
|
||||
expect(() => loadConfig(agentDir)).toThrow('unknown option "typo"');
|
||||
});
|
||||
|
||||
test("rejects invalid option values", () => {
|
||||
const cases: [Record<string, unknown>, string][] = [
|
||||
[{ $schema: false }, '"$schema" must be a non-empty string'],
|
||||
[{ $schema: "" }, '"$schema" must be a non-empty string'],
|
||||
[{ mode: "replace" }, '"mode" must be one of'],
|
||||
[{ frecencyDbPath: "" }, '"frecencyDbPath" must be a non-empty string'],
|
||||
[{ historyDbPath: false }, '"historyDbPath" must be a non-empty string'],
|
||||
[{ enableFsRootScanning: 1 }, '"enableFsRootScanning" must be a boolean'],
|
||||
[{ enableHomeDirScanning: "false" }, '"enableHomeDirScanning" must be a boolean'],
|
||||
];
|
||||
|
||||
for (const [config, message] of cases) {
|
||||
writeConfig(config);
|
||||
expect(() => loadConfig(agentDir)).toThrow(message);
|
||||
}
|
||||
});
|
||||
|
||||
test("reports file read failures", () => {
|
||||
fs.mkdirSync(configPath);
|
||||
|
||||
expect(() => loadConfig(agentDir)).toThrow(
|
||||
`Could not read pi-fff config at ${configPath}`,
|
||||
);
|
||||
});
|
||||
|
||||
function writeConfig(config: unknown): void {
|
||||
fs.writeFileSync(configPath, JSON.stringify(config));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { resolveDbPaths } from "../src/paths";
|
||||
|
||||
const ENV_KEYS = ["XDG_CACHE_HOME", "XDG_DATA_HOME", "PI_CODING_AGENT_DIR"] as const;
|
||||
|
||||
describe("resolveDbPaths", () => {
|
||||
let tmpRoot: string;
|
||||
let piDir: string;
|
||||
let saved: Record<string, string | undefined>;
|
||||
|
||||
beforeEach(() => {
|
||||
saved = {};
|
||||
for (const key of ENV_KEYS) saved[key] = process.env[key];
|
||||
|
||||
tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "fff-db-paths-"));
|
||||
piDir = path.join(tmpRoot, "pi-agent");
|
||||
|
||||
process.env.XDG_CACHE_HOME = path.join(tmpRoot, "cache");
|
||||
process.env.XDG_DATA_HOME = path.join(tmpRoot, "data");
|
||||
process.env.PI_CODING_AGENT_DIR = piDir;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
for (const key of ENV_KEYS) {
|
||||
const value = saved[key];
|
||||
if (value === undefined) delete process.env[key];
|
||||
else process.env[key] = value;
|
||||
}
|
||||
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("overrides win over discovery and fallback", () => {
|
||||
mkNvimDir("cache", "fff_nvim");
|
||||
mkNvimDir("data", "fff_queries");
|
||||
|
||||
const paths = resolveDbPaths({
|
||||
frecency: "/explicit/frecency",
|
||||
history: "/explicit/history",
|
||||
});
|
||||
|
||||
expect(paths.frecency).toBe("/explicit/frecency");
|
||||
expect(paths.history).toBe("/explicit/history");
|
||||
});
|
||||
|
||||
test("picks existing fff.nvim databases", () => {
|
||||
const frecency = mkNvimDir("cache", "fff_nvim");
|
||||
const history = mkNvimDir("data", "fff_queries");
|
||||
|
||||
expect(resolveDbPaths({})).toEqual({ frecency, history });
|
||||
});
|
||||
|
||||
test("uses the pi data dir when no nvim databases exist", () => {
|
||||
expect(resolveDbPaths({})).toEqual({
|
||||
frecency: path.join(piDir, "fff", "frecency"),
|
||||
history: path.join(piDir, "fff", "history"),
|
||||
});
|
||||
});
|
||||
|
||||
test("ignores a plain file at the nvim candidate path", () => {
|
||||
const cacheDir = path.join(tmpRoot, "cache", "nvim");
|
||||
fs.mkdirSync(cacheDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(cacheDir, "fff_nvim"), "not a db");
|
||||
|
||||
expect(resolveDbPaths({}).frecency).toBe(path.join(piDir, "fff", "frecency"));
|
||||
});
|
||||
|
||||
test("resolves each database independently", () => {
|
||||
const history = mkNvimDir("data", "fff_queries");
|
||||
const paths = resolveDbPaths({ frecency: "/explicit/frecency" });
|
||||
|
||||
expect(paths.frecency).toBe("/explicit/frecency");
|
||||
expect(paths.history).toBe(history);
|
||||
});
|
||||
|
||||
function mkNvimDir(kind: "cache" | "data", name: string): string {
|
||||
const dir = path.join(tmpRoot, kind, "nvim", name);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
return dir;
|
||||
}
|
||||
});
|
||||
@@ -1,5 +1,7 @@
|
||||
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
||||
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
type MockFinder = {
|
||||
isDestroyed: boolean;
|
||||
@@ -87,7 +89,7 @@ mock.module("@sinclair/typebox", () => ({
|
||||
properties,
|
||||
options,
|
||||
}),
|
||||
Optional: (value: unknown) => ({ ...value, optional: true }),
|
||||
Optional: (value: Record<string, unknown>) => ({ ...value, optional: true }),
|
||||
String: schema("string"),
|
||||
Union: (items: unknown[], options?: unknown) => ({ type: "union", items, options }),
|
||||
},
|
||||
@@ -97,20 +99,38 @@ const { default: fffExtension } = await import("../src/index");
|
||||
|
||||
type EventHandler = (...args: any[]) => unknown;
|
||||
|
||||
function createPi(mode?: string) {
|
||||
function createPi(mode?: string, flags: Record<string, unknown> = {}) {
|
||||
const events = new Map<string, EventHandler>();
|
||||
const commands = new Map<string, any>();
|
||||
const registeredFlags = new Set<string>();
|
||||
let flagsReady = false;
|
||||
|
||||
const pi = {
|
||||
getFlag: mock((name: string) => (name === "fff-mode" ? mode : undefined)),
|
||||
getFlag: mock((name: string) => {
|
||||
if (!flagsReady || !registeredFlags.has(name)) return undefined;
|
||||
return name === "fff-mode" && mode !== undefined ? mode : flags[name];
|
||||
}),
|
||||
on: mock((event: string, handler: EventHandler) => {
|
||||
events.set(event, handler);
|
||||
events.set(event, (...args) => {
|
||||
flagsReady = true;
|
||||
return handler(...args);
|
||||
});
|
||||
}),
|
||||
registerCommand: mock((name: string, command: any) => {
|
||||
commands.set(name, command);
|
||||
commands.set(name, {
|
||||
...command,
|
||||
handler: (...args: any[]) => {
|
||||
flagsReady = true;
|
||||
return command.handler(...args);
|
||||
},
|
||||
});
|
||||
}),
|
||||
registerFlag: mock(() => undefined),
|
||||
registerTool: mock(() => undefined),
|
||||
registerFlag: mock((name: string) => {
|
||||
registeredFlags.add(name);
|
||||
}),
|
||||
registerTool: mock((_tool: any) => undefined),
|
||||
getActiveTools: mock(() => ["read"] as string[]),
|
||||
setActiveTools: mock((_names: string[]) => undefined),
|
||||
appendEntry: mock(() => undefined),
|
||||
};
|
||||
|
||||
@@ -120,17 +140,21 @@ function createPi(mode?: string) {
|
||||
function createContext(cwd = "/tmp/workspace") {
|
||||
return {
|
||||
cwd,
|
||||
sessionManager: {
|
||||
getEntries: mock(() => [] as any[]),
|
||||
},
|
||||
// Signatures mirror the real pi UI surface so mock.calls stays typed.
|
||||
ui: {
|
||||
addAutocompleteProvider: mock(() => undefined),
|
||||
notify: mock(() => undefined),
|
||||
addAutocompleteProvider: mock((_factory: (current: any) => any) => undefined),
|
||||
notify: mock((_message: string, _level?: string) => undefined),
|
||||
setEditorComponent: mock(() => undefined),
|
||||
setStatus: mock(() => undefined),
|
||||
setStatus: mock((_key: string, _text?: string) => undefined),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function start(mode?: string, cwd?: string) {
|
||||
const setup = createPi(mode);
|
||||
async function start(mode?: string, cwd?: string, flags: Record<string, unknown> = {}) {
|
||||
const setup = createPi(mode, flags);
|
||||
const ctx = createContext(cwd);
|
||||
fffExtension(setup.pi as any);
|
||||
|
||||
@@ -159,13 +183,186 @@ function abortOptions() {
|
||||
return { signal: new AbortController().signal };
|
||||
}
|
||||
|
||||
const CONFIG_ENV_KEYS = [
|
||||
"PI_CODING_AGENT_DIR",
|
||||
"PI_FFF_MODE",
|
||||
"FFF_FRECENCY_DB",
|
||||
"FFF_HISTORY_DB",
|
||||
"FFF_ENABLE_ROOT_SCAN",
|
||||
"FFF_ENABLE_HOME_SCAN",
|
||||
] as const;
|
||||
|
||||
const savedEnv: Record<string, string | undefined> = {};
|
||||
for (const key of CONFIG_ENV_KEYS) savedEnv[key] = process.env[key];
|
||||
|
||||
const agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fff-extension-"));
|
||||
const configPath = path.join(agentDir, "pi-fff.json");
|
||||
|
||||
beforeEach(() => {
|
||||
createCalls.length = 0;
|
||||
finders = [];
|
||||
mixedSearchImpl = undefined;
|
||||
scanProgressImpl = undefined;
|
||||
delete process.env.PI_FFF_MODE;
|
||||
delete process.env.FFF_ENABLE_HOME_SCAN;
|
||||
|
||||
for (const key of CONFIG_ENV_KEYS) delete process.env[key];
|
||||
process.env.PI_CODING_AGENT_DIR = agentDir;
|
||||
fs.rmSync(configPath, { force: true });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const key of CONFIG_ENV_KEYS) {
|
||||
const value = savedEnv[key];
|
||||
if (value === undefined) delete process.env[key];
|
||||
else process.env[key] = value;
|
||||
}
|
||||
fs.rmSync(agentDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe("pi-fff global config", () => {
|
||||
test("applies every supported startup option", async () => {
|
||||
writeConfig({
|
||||
mode: "override",
|
||||
frecencyDbPath: "/config/frecency",
|
||||
historyDbPath: "/config/history",
|
||||
enableFsRootScanning: true,
|
||||
enableHomeDirScanning: false,
|
||||
});
|
||||
|
||||
const setup = await start();
|
||||
const toolNames = setup.pi.registerTool.mock.calls.map(([tool]) => tool.name);
|
||||
|
||||
expect(toolNames).toContain("grep");
|
||||
expect(toolNames).toContain("find");
|
||||
expect(toolNames).not.toContain("ffgrep");
|
||||
expect(createCalls[0]).toEqual({
|
||||
basePath: "/tmp/workspace",
|
||||
frecencyDbPath: "/config/frecency",
|
||||
historyDbPath: "/config/history",
|
||||
aiMode: true,
|
||||
enableHomeDirScanning: false,
|
||||
enableFsRootScanning: true,
|
||||
});
|
||||
await shutdown(setup);
|
||||
});
|
||||
|
||||
test("keeps flag and environment precedence", async () => {
|
||||
writeConfig({
|
||||
mode: "tools-only",
|
||||
frecencyDbPath: "/config/frecency",
|
||||
historyDbPath: "/config/history",
|
||||
enableFsRootScanning: true,
|
||||
enableHomeDirScanning: false,
|
||||
});
|
||||
process.env.PI_FFF_MODE = "override";
|
||||
process.env.FFF_FRECENCY_DB = "/env/frecency";
|
||||
process.env.FFF_HISTORY_DB = "/env/history";
|
||||
process.env.FFF_ENABLE_ROOT_SCAN = "1";
|
||||
process.env.FFF_ENABLE_HOME_SCAN = "1";
|
||||
|
||||
const setup = await start("tools-and-ui", undefined, {
|
||||
"fff-frecency-db": "/flag/frecency",
|
||||
"fff-enable-root-scan": false,
|
||||
});
|
||||
const toolNames = setup.pi.registerTool.mock.calls.map(([tool]) => tool.name);
|
||||
|
||||
expect(toolNames).toContain("ffgrep");
|
||||
expect(toolNames).toContain("fffind");
|
||||
expect(createCalls[0]).toEqual({
|
||||
basePath: "/tmp/workspace",
|
||||
frecencyDbPath: "/flag/frecency",
|
||||
historyDbPath: "/env/history",
|
||||
aiMode: true,
|
||||
enableHomeDirScanning: true,
|
||||
enableFsRootScanning: false,
|
||||
});
|
||||
await shutdown(setup);
|
||||
});
|
||||
|
||||
test("falls through invalid flag and environment modes", async () => {
|
||||
writeConfig({ mode: "override" });
|
||||
process.env.PI_FFF_MODE = "invalid-env-mode";
|
||||
|
||||
const setup = await start("invalid-flag-mode");
|
||||
const toolNames = setup.pi.registerTool.mock.calls.map(([tool]) => tool.name);
|
||||
|
||||
expect(toolNames).toContain("grep");
|
||||
expect(toolNames).toContain("find");
|
||||
expect(toolNames).not.toContain("ffgrep");
|
||||
await shutdown(setup);
|
||||
});
|
||||
});
|
||||
|
||||
function writeConfig(config: Record<string, unknown>): void {
|
||||
fs.writeFileSync(configPath, JSON.stringify(config));
|
||||
}
|
||||
|
||||
describe("pi-fff session mode", () => {
|
||||
test("registers tools only after restoring the saved mode", async () => {
|
||||
const setup = createPi("tools-and-ui");
|
||||
const ctx = createContext();
|
||||
ctx.sessionManager.getEntries.mockReturnValue([
|
||||
{ type: "custom", customType: "fff-mode", data: { mode: "override" } },
|
||||
]);
|
||||
fffExtension(setup.pi as any);
|
||||
|
||||
expect(setup.pi.registerTool).not.toHaveBeenCalled();
|
||||
await setup.events.get("session_start")?.({ reason: "startup" }, ctx);
|
||||
|
||||
const tools = setup.pi.registerTool.mock.calls.map(([tool]) => tool);
|
||||
const toolNames = tools.map((tool) => tool.name);
|
||||
expect(toolNames).toContain("grep");
|
||||
expect(toolNames).toContain("find");
|
||||
expect(toolNames).not.toContain("ffgrep");
|
||||
expect(toolNames).not.toContain("fffind");
|
||||
const grepTool = tools.find((tool) => tool.name === "grep");
|
||||
expect(grepTool.promptGuidelines[0].startsWith("grep:")).toBe(true);
|
||||
expect(setup.pi.setActiveTools).toHaveBeenCalledWith(
|
||||
expect.arrayContaining(["read", "grep", "find"]),
|
||||
);
|
||||
|
||||
await setup.commands.get("fff-mode").handler("", ctx);
|
||||
expect(ctx.ui.notify).toHaveBeenLastCalledWith(
|
||||
"Current mode: 'override' (flag: tools-and-ui)",
|
||||
"info",
|
||||
);
|
||||
await shutdown(setup);
|
||||
});
|
||||
|
||||
test("registers tools before an unbound SDK session's first agent turn", async () => {
|
||||
const setup = createPi("override");
|
||||
const ctx = createContext();
|
||||
fffExtension(setup.pi as any);
|
||||
|
||||
expect(setup.pi.registerTool).not.toHaveBeenCalled();
|
||||
await setup.events.get("before_agent_start")?.({}, ctx);
|
||||
|
||||
const toolNames = setup.pi.registerTool.mock.calls.map(([tool]) => tool.name);
|
||||
expect(toolNames).toContain("grep");
|
||||
expect(toolNames).toContain("find");
|
||||
expect(createCalls).toHaveLength(0);
|
||||
await shutdown(setup);
|
||||
});
|
||||
|
||||
test("keeps the active mode unchanged until a tool-name switch is reloaded", async () => {
|
||||
const setup = await start();
|
||||
|
||||
await setup.commands.get("fff-mode").handler("override", setup.ctx);
|
||||
|
||||
expect(setup.pi.appendEntry).toHaveBeenCalledWith("fff-mode", {
|
||||
mode: "override",
|
||||
});
|
||||
expect(setup.ctx.ui.notify).toHaveBeenLastCalledWith(
|
||||
"Mode 'override' saved. Run /reload to apply the tool name change.",
|
||||
"info",
|
||||
);
|
||||
|
||||
await setup.commands.get("fff-mode").handler("", setup.ctx);
|
||||
expect(setup.ctx.ui.notify).toHaveBeenLastCalledWith(
|
||||
"Current mode: 'tools-and-ui' (flag: unset)",
|
||||
"info",
|
||||
);
|
||||
await shutdown(setup);
|
||||
});
|
||||
});
|
||||
|
||||
// Regression for #743: launching from $HOME must be visible and interruptible.
|
||||
@@ -211,9 +408,9 @@ describe("pi-fff $HOME scan warning", () => {
|
||||
});
|
||||
const setup = await start(undefined, os.homedir());
|
||||
|
||||
const [key, text] = setup.ctx.ui.setStatus.mock.calls.at(-1) as [string, string];
|
||||
expect(key).toBe("fff");
|
||||
expect(text).toContain("12345 files");
|
||||
const lastStatus = setup.ctx.ui.setStatus.mock.calls.at(-1);
|
||||
expect(lastStatus?.[0]).toBe("fff");
|
||||
expect(lastStatus?.[1]).toContain("12345 files");
|
||||
|
||||
// session_shutdown must stop the poller and clear the footer.
|
||||
await shutdown(setup);
|
||||
@@ -239,8 +436,9 @@ describe("pi-fff autocomplete registration", () => {
|
||||
expect(createCalls).toEqual([
|
||||
{
|
||||
basePath: "/tmp/workspace",
|
||||
frecencyDbPath: undefined,
|
||||
historyDbPath: undefined,
|
||||
// Resolved defaults are host-dependent; covered by test/db-paths.test.ts.
|
||||
frecencyDbPath: expect.any(String),
|
||||
historyDbPath: expect.any(String),
|
||||
aiMode: true,
|
||||
enableHomeDirScanning: true,
|
||||
enableFsRootScanning: false,
|
||||
@@ -380,7 +578,7 @@ describe("pi-fff autocomplete registration", () => {
|
||||
});
|
||||
|
||||
test("/fff-mode changes mention behavior without touching the editor", async () => {
|
||||
const { commands, ctx } = await start();
|
||||
const { commands, ctx, pi } = await start();
|
||||
const factory = ctx.ui.addAutocompleteProvider.mock.calls[0][0];
|
||||
const current = currentProvider();
|
||||
const provider = factory(current);
|
||||
@@ -388,6 +586,7 @@ describe("pi-fff autocomplete registration", () => {
|
||||
await commands.get("fff-mode").handler("tools-only", ctx);
|
||||
await provider.getSuggestions(["@src"], 0, 4, abortOptions());
|
||||
|
||||
expect(pi.appendEntry).toHaveBeenCalledWith("fff-mode", { mode: "tools-only" });
|
||||
expect(current.getSuggestions).toHaveBeenCalledTimes(1);
|
||||
expect(finders[0].mixedSearch).not.toHaveBeenCalled();
|
||||
expect(ctx.ui.setEditorComponent).not.toHaveBeenCalled();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"types": ["node"]
|
||||
"types": ["node", "bun"]
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src", "test"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const [pkgDir, version] = process.argv.slice(2);
|
||||
if (!pkgDir || !version) {
|
||||
console.error("usage: set-npm-version.mjs <pkg-dir> <version>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// fff-bun/fff-node pull their native binary from a platform package at runtime.
|
||||
// Those are only resolvable once published, so they are injected here instead of
|
||||
// living in the manifests where they would break `npm ci` and bun installs.
|
||||
const PLATFORM_DEP_CONSUMERS = ["@ff-labs/fff-bun", "@ff-labs/fff-node"];
|
||||
const WORKSPACE_DEPS = ["@ff-labs/fff-bun", "@ff-labs/fff-node"];
|
||||
|
||||
const manifestPath = join(pkgDir, "package.json");
|
||||
const pkg = JSON.parse(readFileSync(manifestPath, "utf8"));
|
||||
|
||||
pkg.version = version;
|
||||
|
||||
if (pkg.optionalDependencies) {
|
||||
for (const dep of Object.keys(pkg.optionalDependencies)) {
|
||||
pkg.optionalDependencies[dep] = version;
|
||||
}
|
||||
}
|
||||
|
||||
for (const dep of WORKSPACE_DEPS) {
|
||||
if (pkg.dependencies?.[dep]) pkg.dependencies[dep] = version;
|
||||
}
|
||||
|
||||
if (PLATFORM_DEP_CONSUMERS.includes(pkg.name)) {
|
||||
const platformDeps = {};
|
||||
for (const name of platformPackageNames()) platformDeps[name] = version;
|
||||
if (Object.keys(platformDeps).length === 0) {
|
||||
console.error(`no platform packages found under packages/, refusing to publish ${pkg.name}`);
|
||||
process.exit(1);
|
||||
}
|
||||
pkg.optionalDependencies = { ...platformDeps, ...pkg.optionalDependencies };
|
||||
}
|
||||
|
||||
writeFileSync(manifestPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
||||
console.log(`Set ${pkgDir} to ${version}`);
|
||||
|
||||
function platformPackageNames() {
|
||||
return readdirSync("packages")
|
||||
.filter((entry) => entry.startsWith("fff-bin-"))
|
||||
.map((entry) => JSON.parse(readFileSync(join("packages", entry, "package.json"), "utf8")).name)
|
||||
.sort();
|
||||
}
|
||||
@@ -218,7 +218,13 @@ describe('programmatic search APIs', function()
|
||||
local before = fff.content_search(marker)
|
||||
assert.are.equal(0, #before.items, 'marker leaked into primary fff tree')
|
||||
|
||||
local result = fff.content_search(marker, { cwd = sandbox_root })
|
||||
-- Poll instead of asserting on the first grep: the index of the new root
|
||||
-- can lag a mkdir by a few ms on CI, which flaked on linux too.
|
||||
local result
|
||||
vim.wait(2000, function()
|
||||
result = fff.content_search(marker, { cwd = sandbox_root })
|
||||
return #result.items > 0
|
||||
end, 50)
|
||||
assert.is_true(#result.items > 0, 'cwd switch did not surface match from the new root')
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user