feat(fixtures): add npm fixture shims

This commit is contained in:
Vincent Koc 2026-04-26 00:51:25 -07:00
parent ac38ebbd2a
commit e130cf4623
No known key found for this signature in database
20 changed files with 15162 additions and 47 deletions

View File

@ -12,3 +12,51 @@ updates:
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: "npm"
directory: "/plugins/memory-tencentdb"
schedule:
interval: "weekly"
day: "monday"
time: "09:10"
timezone: "Etc/UTC"
open-pull-requests-limit: 5
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: "npm"
directory: "/plugins/yuanbao"
schedule:
interval: "weekly"
day: "monday"
time: "09:20"
timezone: "Etc/UTC"
open-pull-requests-limit: 5
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: "npm"
directory: "/plugins/openclaw-weixin"
schedule:
interval: "weekly"
day: "monday"
time: "09:30"
timezone: "Etc/UTC"
open-pull-requests-limit: 5
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: "npm"
directory: "/plugins/lightclawbot"
schedule:
interval: "weekly"
day: "monday"
time: "09:40"
timezone: "Etc/UTC"
open-pull-requests-limit: 5
commit-message:
prefix: "chore"
include: "scope"

5
.gitignore vendored
View File

@ -7,7 +7,4 @@ coverage/
dist/
tmp/
.crabpot/
plugins/lightclawbot/
plugins/memory-tencentdb/
plugins/openclaw-weixin/
plugins/yuanbao/
plugins/*/.crabpot-package/

View File

@ -209,7 +209,6 @@
"name": "TencentDB Agent Memory",
"package": {
"name": "@tencentdb-agent-memory/memory-tencentdb",
"version": "0.2.3",
"tag": "latest"
},
"path": "plugins/memory-tencentdb",
@ -251,7 +250,6 @@
"name": "Tencent Yuanbao Bot",
"package": {
"name": "openclaw-plugin-yuanbao",
"version": "2.11.0",
"tag": "latest"
},
"path": "plugins/yuanbao",
@ -267,7 +265,6 @@
"name": "OpenClaw Weixin",
"package": {
"name": "@tencent-weixin/openclaw-weixin",
"version": "2.1.10",
"tag": "latest"
},
"path": "plugins/openclaw-weixin",
@ -283,7 +280,6 @@
"name": "LightClawBot",
"package": {
"name": "lightclawbot",
"version": "1.1.2",
"tag": "latest"
},
"path": "plugins/lightclawbot",

View File

@ -29,7 +29,7 @@
"repo": { "type": "string", "pattern": "^https://github.com/.+\\.git$" },
"package": {
"type": "object",
"required": ["name", "version"],
"required": ["name"],
"additionalProperties": false,
"properties": {
"name": { "type": "string", "minLength": 1 },

View File

@ -1,22 +1,25 @@
# Crabpot Plugin Fixtures
Crabpot keeps external plugins under `plugins/`. Most fixtures are git
submodules. Some npm-only fixtures are pinned by package version and unpacked on
demand into ignored `plugins/<id>` directories. The parent repo owns only pins,
fixture metadata, generated reports, and tests. Plugin source stays
upstream-owned.
submodules. Npm-only fixtures use committed `plugins/<id>/package.json` shim
packages with one exact dependency pin; `node scripts/sync-fixtures.mjs --materialize`
unpacks the package payload into ignored `plugins/<id>/.crabpot-package/`
directories for static inspection. The parent repo owns only pins, fixture
metadata, generated reports, and tests. Plugin source stays upstream-owned.
Dependabot watches `.gitmodules` with the `gitsubmodule` ecosystem and opens PRs
when a submodule has a newer upstream commit. Npm-sourced fixtures are pinned in
`crabpot.config.json` and are refreshed manually until we add package-update
automation. Update PRs should change only the relevant pin unless plugin behavior
requires reports or contract classifier changes.
Dependabot watches `.gitmodules` with the `gitsubmodule` ecosystem and the npm
shim package directories with the `npm` ecosystem. Update PRs should change only
the relevant pin unless plugin behavior requires report or contract classifier
changes. Dependabot PRs can be auto-merged after CI refreshes the generated
reports and dashboard.
The root `.github/dependabot.yml` owns this:
```yaml
package-ecosystem: "gitsubmodule"
directory: "/"
package-ecosystem: "npm"
directory: "/plugins/<id>"
```
## How It Works
@ -25,8 +28,9 @@ directory: "/"
- `crabpot.config.json` declares the fixture id, seam coverage, expected hooks,
expected registrations, source pin, and why the plugin belongs in Crabpot.
- The gitlink at `plugins/<id>` pins the exact upstream commit Crabpot tests.
- Npm fixtures use `package.name` + `package.version`; `node scripts/sync-fixtures.mjs --materialize`
unpacks them into ignored `plugins/<id>` directories.
- Npm fixtures use `crabpot.config.json` for package identity and
`plugins/<id>/package.json` for the exact dependency pin; materialization
unpacks the package into ignored `plugins/<id>/.crabpot-package/`.
- `scripts/inspect-fixtures.mjs` reads source statically and checks expected
hooks, registrations, manifests, packages, and SDK imports.
- `scripts/generate-report.mjs` compares observed plugin seams with the target
@ -83,15 +87,23 @@ directory: "/"
npm view <package> version
```
5. Add a fixture entry to `crabpot.config.json` with:
5. Create `plugins/<id>/package.json` with one exact dependency on the upstream
npm package and generate its lockfile:
```sh
npm install --package-lock-only --ignore-scripts --prefix plugins/<id>
```
6. Add a fixture entry to `crabpot.config.json` with:
- `id`, `name`, `path`, and optional `subdir`
- exactly one of `repo` or `package: { name, version, tag }`
- exactly one of `repo` or `package: { name, tag }`
- `priority`
- seam labels
- expected hooks, registrations, or manifest contracts
- a specific `why`
6. Add the fixture to the inventory table above.
7. Run:
7. Add an npm update block to `.github/dependabot.yml` for the new shim path.
8. Add the fixture to the inventory table above.
9. Run:
```sh
node scripts/sync-fixtures.mjs --materialize
@ -124,12 +136,13 @@ directory: "/"
rm -rf .git/modules/plugins/<id>
```
5. For an npm fixture, remove the ignored local unpacked directory.
5. For an npm fixture, remove `plugins/<id>/package.json`, `plugins/<id>/package-lock.json`,
its Dependabot npm block, and the ignored local `.crabpot-package/` directory.
6. Regenerate reports and run `npm run check`.
## Update A Pin Manually
Dependabot should handle routine updates. For a manual bump:
Dependabot should handle routine updates. For a manual repo-backed bump:
```sh
git submodule update --remote --depth 1 plugins/<id>
@ -140,3 +153,7 @@ npm run check
Commit the gitlink bump with any necessary fixture/report changes. Do not edit
upstream plugin source in this repository.
For an npm fixture, update the exact dependency in `plugins/<id>/package.json`,
regenerate `plugins/<id>/package-lock.json`, then run the same report/check
commands. Dependabot uses the same files.

6860
plugins/lightclawbot/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"name": "@crabpot/fixture-lightclawbot",
"version": "0.0.0",
"private": true,
"description": "Crabpot npm fixture shim for LightClawBot.",
"dependencies": {
"lightclawbot": "1.1.2"
},
"crabpot": {
"fixture": "lightclawbot",
"source": "npm",
"package": "lightclawbot"
}
}

488
plugins/memory-tencentdb/package-lock.json generated Normal file
View File

@ -0,0 +1,488 @@
{
"name": "@crabpot/fixture-memory-tencentdb",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@crabpot/fixture-memory-tencentdb",
"version": "0.0.0",
"dependencies": {
"@tencentdb-agent-memory/memory-tencentdb": "0.2.3"
}
},
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
"integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.4.3",
"@emnapi/runtime": "^1.4.3",
"@tybys/wasm-util": "^0.10.0"
}
},
"node_modules/@node-rs/jieba": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-2.0.1.tgz",
"integrity": "sha512-tnfzXOMqzVQF2dSKMhPC9HrHzzWmN6KheL/zYtGenhOpq/bCKHJWVASSggEnHlkmHgXGeIJHR2N/IuPzewz1BQ==",
"license": "MIT",
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"optionalDependencies": {
"@node-rs/jieba-android-arm-eabi": "2.0.1",
"@node-rs/jieba-android-arm64": "2.0.1",
"@node-rs/jieba-darwin-arm64": "2.0.1",
"@node-rs/jieba-darwin-x64": "2.0.1",
"@node-rs/jieba-freebsd-x64": "2.0.1",
"@node-rs/jieba-linux-arm-gnueabihf": "2.0.1",
"@node-rs/jieba-linux-arm64-gnu": "2.0.1",
"@node-rs/jieba-linux-arm64-musl": "2.0.1",
"@node-rs/jieba-linux-x64-gnu": "2.0.1",
"@node-rs/jieba-linux-x64-musl": "2.0.1",
"@node-rs/jieba-wasm32-wasi": "2.0.1",
"@node-rs/jieba-win32-arm64-msvc": "2.0.1",
"@node-rs/jieba-win32-ia32-msvc": "2.0.1",
"@node-rs/jieba-win32-x64-msvc": "2.0.1"
}
},
"node_modules/@node-rs/jieba-android-arm-eabi": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-2.0.1.tgz",
"integrity": "sha512-tavsIaxybnlA9tRbJ+oc3NW3zhx0d5rNiCGdpIdGWjflwS7HyeUTVAZmAFDlg58Mc6EjTdVKZH+RolBbAJtgcQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-android-arm64": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-2.0.1.tgz",
"integrity": "sha512-AwdyqKvVNuSDnDq3anUfq+nJ5J/kzXjkfbr/1WY6TfaAlTNuuGVskuQv72/wIx/jn7NoXfm/UPuJrWYG16NC6w==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-darwin-arm64": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-2.0.1.tgz",
"integrity": "sha512-10+nwGQ6KzXXJlIL/sELA6Fi6m7eJ7xJksBiKuw1kxKUgaJwtVfAG0iqRF+NRQv0Sdq7r3k5ew9K9y0+IYaEcA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-darwin-x64": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-2.0.1.tgz",
"integrity": "sha512-IJ5RK0X/uPQa1XRmTvwKSieya+w1IJeiKLw0EekoBFJKybXQdvo8/uqM/8z2eVJ8vQxW9X6K2vkVGFvYQa9dYA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-freebsd-x64": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-2.0.1.tgz",
"integrity": "sha512-yg7vyhqzP2weJu5DJ3q9q4pb0b4GWWRwcv54zK7MSSA6KNJ/uQv2a4R9/qmptLU/fZv14gWuJBEMFdL7y1Dv2w==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-linux-arm-gnueabihf": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-2.0.1.tgz",
"integrity": "sha512-fxQYunS7w2tv8XV9GigkWJPzHnbcw6tjrUdDu5/qU0FdQVEzGuEYG85DjlNf8lZTDGSUKHBVyAQs7bBIvq8yqg==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-linux-arm64-gnu": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-2.0.1.tgz",
"integrity": "sha512-VnLU630hQIyO/fwyxh2vqZi72mO+hXkVUC3jVLPfOAlppinmsGX9N81tpTPUK3840hbV8WLtbYTWN1XodI38eg==",
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-linux-arm64-musl": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-2.0.1.tgz",
"integrity": "sha512-K4EDyNixSLVdTNYnHwD+7I/ytvzpo7tt+vdCLqwQViiek2PMpL/FFRvA39uU2tk99jXIxvkczdxARG20BRZppg==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-linux-x64-gnu": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-2.0.1.tgz",
"integrity": "sha512-sq3J6L2ANTE25I9eVFq/nb57OtXcvUIeUD1CTKJxwgTKIVmcB2LyOZpWf20AjHRUfbMER9Klqg5dgyyO+Six+w==",
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-linux-x64-musl": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-2.0.1.tgz",
"integrity": "sha512-0zfP9Qy68yEXrhBFknfhF6WUJDPU/8eRuyIrkMGdMjfRpxhpSbr2fMfnsqhOQLvhuK4w3iDFvTy4t5d0s6JKMA==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-wasm32-wasi": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-wasm32-wasi/-/jieba-wasm32-wasi-2.0.1.tgz",
"integrity": "sha512-7I5rJya5rlQNJIhv8PvPzIVT1/gVc0vFzHmlfRGwCPGDJ3tHVxkSPW34dDx3OgDmbIeadNpmgIyC1RaS9djPJg==",
"cpu": [
"wasm32"
],
"license": "MIT",
"optional": true,
"dependencies": {
"@napi-rs/wasm-runtime": "^0.2.5"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@node-rs/jieba-win32-arm64-msvc": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-2.0.1.tgz",
"integrity": "sha512-Aj/2EwYSaPgAbKnSl+vKM/2kOaZNMZWnShiZzbSNyzlLy3eIOyOYVLbYRDno4547KngRxer8uzROhIQIwXwkvw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-win32-ia32-msvc": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-2.0.1.tgz",
"integrity": "sha512-tpJt3uuBlGrcOInQLTYvcgamQgfadl5cwExLYU+CX9rXKpXLDO31dIujUDBgNWoiQq3tOiU1/AKbT7ZdNd4lBQ==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@node-rs/jieba-win32-x64-msvc": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-2.0.1.tgz",
"integrity": "sha512-LDOyo2/2CO8UnpSGLJdgqtH8mOnsABPhNxkfIky7UT9cyLEzOaU44nbA5YzPGpBI3qzMbWcwJYQsjBcgK2VqAg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tencentdb-agent-memory/memory-tencentdb": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@tencentdb-agent-memory/memory-tencentdb/-/memory-tencentdb-0.2.3.tgz",
"integrity": "sha512-XQ9+H4k5zCN+jI8KfINhZ9ElNF53MtH4FTh2r7akr96tWdXYRMjk14RrW2h4/aNJuKUlmlgt5RkNxrJpLk40sg==",
"license": "MIT",
"dependencies": {
"@node-rs/jieba": "^2.0.1",
"@tencentdb-agent-memory/tcvdb-text": "^0.1.1",
"json5": "^2.2.3",
"sqlite-vec": "0.1.7-alpha.2",
"undici": "8.0.2"
},
"bin": {
"export-tencent-vdb": "bin/export-tencent-vdb.mjs",
"migrate-sqlite-to-tcvdb": "bin/migrate-sqlite-to-tcvdb.mjs",
"read-local-memory": "bin/read-local-memory.mjs"
},
"engines": {
"node": ">=22.16.0"
},
"peerDependencies": {
"node-llama-cpp": "^3.16.2",
"openclaw": ">=2026.3.7"
},
"peerDependenciesMeta": {
"node-llama-cpp": {
"optional": true
},
"openclaw": {
"optional": true
}
}
},
"node_modules/@tencentdb-agent-memory/tcvdb-text": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@tencentdb-agent-memory/tcvdb-text/-/tcvdb-text-0.1.1.tgz",
"integrity": "sha512-LoCiOFDL7tk0mu6+4X2MfKXyL/iVXsiVIAmbryKaA7DcGiT62h9I1wgoobnCHYU9vmghMjjReJ4gy3lIii+WvA==",
"license": "MIT",
"dependencies": {
"@node-rs/jieba": "^2.0.1",
"murmurhash": "^2.0.1"
}
},
"node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/murmurhash": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/murmurhash/-/murmurhash-2.0.1.tgz",
"integrity": "sha512-5vQEh3y+DG/lMPM0mCGPDnyV8chYg/g7rl6v3Gd8WMF9S429ox3Xk8qrk174kWhG767KQMqqxLD1WnGd77hiew==",
"license": "MIT"
},
"node_modules/sqlite-vec": {
"version": "0.1.7-alpha.2",
"resolved": "https://registry.npmjs.org/sqlite-vec/-/sqlite-vec-0.1.7-alpha.2.tgz",
"integrity": "sha512-rNgRCv+4V4Ed3yc33Qr+nNmjhtrMnnHzXfLVPeGb28Dx5mmDL3Ngw/Wk8vhCGjj76+oC6gnkmMG8y73BZWGBwQ==",
"license": "MIT OR Apache",
"optionalDependencies": {
"sqlite-vec-darwin-arm64": "0.1.7-alpha.2",
"sqlite-vec-darwin-x64": "0.1.7-alpha.2",
"sqlite-vec-linux-arm64": "0.1.7-alpha.2",
"sqlite-vec-linux-x64": "0.1.7-alpha.2",
"sqlite-vec-windows-x64": "0.1.7-alpha.2"
}
},
"node_modules/sqlite-vec-darwin-arm64": {
"version": "0.1.7-alpha.2",
"resolved": "https://registry.npmjs.org/sqlite-vec-darwin-arm64/-/sqlite-vec-darwin-arm64-0.1.7-alpha.2.tgz",
"integrity": "sha512-raIATOqFYkeCHhb/t3r7W7Cf2lVYdf4J3ogJ6GFc8PQEgHCPEsi+bYnm2JT84MzLfTlSTIdxr4/NKv+zF7oLPw==",
"cpu": [
"arm64"
],
"license": "MIT OR Apache",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/sqlite-vec-darwin-x64": {
"version": "0.1.7-alpha.2",
"resolved": "https://registry.npmjs.org/sqlite-vec-darwin-x64/-/sqlite-vec-darwin-x64-0.1.7-alpha.2.tgz",
"integrity": "sha512-jeZEELsQjjRsVojsvU5iKxOvkaVuE+JYC8Y4Ma8U45aAERrDYmqZoHvgSG7cg1PXL3bMlumFTAmHynf1y4pOzA==",
"cpu": [
"x64"
],
"license": "MIT OR Apache",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/sqlite-vec-linux-arm64": {
"version": "0.1.7-alpha.2",
"resolved": "https://registry.npmjs.org/sqlite-vec-linux-arm64/-/sqlite-vec-linux-arm64-0.1.7-alpha.2.tgz",
"integrity": "sha512-6Spj4Nfi7tG13jsUG+W7jnT0bCTWbyPImu2M8nWp20fNrd1SZ4g3CSlDAK8GBdavX7wRlbBHCZ+BDa++rbDewA==",
"cpu": [
"arm64"
],
"license": "MIT OR Apache",
"optional": true,
"os": [
"linux"
]
},
"node_modules/sqlite-vec-linux-x64": {
"version": "0.1.7-alpha.2",
"resolved": "https://registry.npmjs.org/sqlite-vec-linux-x64/-/sqlite-vec-linux-x64-0.1.7-alpha.2.tgz",
"integrity": "sha512-IcgrbHaDccTVhXDf8Orwdc2+hgDLAFORl6OBUhcvlmwswwBP1hqBTSEhovClG4NItwTOBNgpwOoQ7Qp3VDPWLg==",
"cpu": [
"x64"
],
"license": "MIT OR Apache",
"optional": true,
"os": [
"linux"
]
},
"node_modules/sqlite-vec-windows-x64": {
"version": "0.1.7-alpha.2",
"resolved": "https://registry.npmjs.org/sqlite-vec-windows-x64/-/sqlite-vec-windows-x64-0.1.7-alpha.2.tgz",
"integrity": "sha512-TRP6hTjAcwvQ6xpCZvjP00pdlda8J38ArFy1lMYhtQWXiIBmWnhMaMbq4kaeCYwvTTddfidatRS+TJrwIKB/oQ==",
"cpu": [
"x64"
],
"license": "MIT OR Apache",
"optional": true,
"os": [
"win32"
]
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD",
"optional": true
},
"node_modules/undici": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-8.0.2.tgz",
"integrity": "sha512-B9MeU5wuFhkFAuNeA19K2GDFcQXZxq33fL0nRy2Aq30wdufZbyyvxW3/ChaeipXVfy/wUweZyzovQGk39+9k2w==",
"license": "MIT",
"engines": {
"node": ">=22.19.0"
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "@crabpot/fixture-memory-tencentdb",
"version": "0.0.0",
"private": true,
"description": "Crabpot npm fixture shim for TencentDB Agent Memory.",
"dependencies": {
"@tencentdb-agent-memory/memory-tencentdb": "0.2.3"
},
"crabpot": {
"fixture": "memory-tencentdb",
"source": "npm",
"package": "@tencentdb-agent-memory/memory-tencentdb"
}
}

View File

@ -0,0 +1,45 @@
{
"name": "@crabpot/fixture-openclaw-weixin",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@crabpot/fixture-openclaw-weixin",
"version": "0.0.0",
"dependencies": {
"@tencent-weixin/openclaw-weixin": "2.1.10"
}
},
"node_modules/@tencent-weixin/openclaw-weixin": {
"version": "2.1.10",
"resolved": "https://registry.npmjs.org/@tencent-weixin/openclaw-weixin/-/openclaw-weixin-2.1.10.tgz",
"integrity": "sha512-cEG6Iw5g2qqlA+8/TcmV+E8aFUEX0ruxF0+a5LgVy5wv56/qP07KoapfRa7YTRPzhRW5UDaz6zsZQArt/4ZNnA==",
"license": "MIT",
"dependencies": {
"qrcode-terminal": "0.12.0",
"zod": "4.3.6"
},
"engines": {
"node": ">=22"
}
},
"node_modules/qrcode-terminal": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz",
"integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==",
"bin": {
"qrcode-terminal": "bin/qrcode-terminal.js"
}
},
"node_modules/zod": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "@crabpot/fixture-openclaw-weixin",
"version": "0.0.0",
"private": true,
"description": "Crabpot npm fixture shim for OpenClaw Weixin.",
"dependencies": {
"@tencent-weixin/openclaw-weixin": "2.1.10"
},
"crabpot": {
"fixture": "openclaw-weixin",
"source": "npm",
"package": "@tencent-weixin/openclaw-weixin"
}
}

7544
plugins/yuanbao/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"name": "@crabpot/fixture-yuanbao",
"version": "0.0.0",
"private": true,
"description": "Crabpot npm fixture shim for Tencent Yuanbao Bot.",
"dependencies": {
"openclaw-plugin-yuanbao": "2.11.0"
},
"crabpot": {
"fixture": "yuanbao",
"source": "npm",
"package": "openclaw-plugin-yuanbao"
}
}

View File

@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
import { readdir, readFile } from "node:fs/promises";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { readManifest, repoRoot } from "./manifest-lib.mjs";
import { fixtureCheckoutPath, fixtureSourceRoot, readManifest, repoRoot } from "./manifest-lib.mjs";
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
await main();
@ -61,8 +61,8 @@ export async function inspectManifest() {
}
export async function inspectFixture(fixture) {
const checkoutPath = path.join(repoRoot, fixture.path);
const sourceRoot = fixture.subdir ? path.join(checkoutPath, fixture.subdir) : checkoutPath;
const checkoutPath = fixtureCheckoutPath(fixture);
const sourceRoot = fixtureSourceRoot(fixture);
if (!existsSync(checkoutPath)) {
return emptyInspection(fixture, "missing");

View File

@ -3,6 +3,7 @@ import path from "node:path";
export const repoRoot = path.resolve(import.meta.dirname, "..");
export const manifestPath = path.join(repoRoot, "crabpot.config.json");
export const npmPackagePayloadDir = ".crabpot-package";
export async function readManifest() {
const raw = await readFile(manifestPath, "utf8");
@ -57,9 +58,6 @@ export function validateManifest(manifest) {
if (!fixture.package.name || typeof fixture.package.name !== "string") {
errors.push(`${fixture.id}: package.name must be set`);
}
if (!fixture.package.version || typeof fixture.package.version !== "string") {
errors.push(`${fixture.id}: package.version must be set`);
}
}
if (!["high", "medium", "low"].includes(fixture.priority)) {
errors.push(`${fixture.id}: priority must be high, medium, or low`);
@ -79,3 +77,18 @@ export function validateManifest(manifest) {
throw new Error(errors.join("\n"));
}
}
export function fixtureCheckoutPath(fixture) {
return path.join(repoRoot, fixture.path);
}
export function fixtureSourceRoot(fixture) {
const checkoutPath = fixtureCheckoutPath(fixture);
if (fixture.subdir) {
return path.join(checkoutPath, fixture.subdir);
}
if (fixture.package) {
return path.join(checkoutPath, npmPackagePayloadDir);
}
return checkoutPath;
}

View File

@ -4,7 +4,7 @@ import { existsSync, readFileSync } from "node:fs";
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
import path from "node:path";
import { inspectManifest } from "./inspect-fixtures.mjs";
import { readManifest, repoRoot } from "./manifest-lib.mjs";
import { fixtureCheckoutPath, fixtureSourceRoot, readManifest, repoRoot } from "./manifest-lib.mjs";
export const defaultReportDir = path.join(repoRoot, "reports");
export const defaultMarkdownReportPath = path.join(defaultReportDir, "crabpot-report.md");
@ -1401,8 +1401,8 @@ function classifyPackageContracts({ fixture, inspection, fixtureReport, warnings
}
async function buildFixtureReport(fixture, inspection) {
const checkoutPath = path.join(repoRoot, fixture.path);
const sourceRoot = fixture.subdir ? path.join(checkoutPath, fixture.subdir) : checkoutPath;
const checkoutPath = fixtureCheckoutPath(fixture);
const sourceRoot = fixtureSourceRoot(fixture);
const pluginManifests = await readPluginManifests(checkoutPath, sourceRoot);
const packageSummaries = await readPackageSummaries(checkoutPath, sourceRoot);

View File

@ -2,7 +2,7 @@
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import path from "node:path";
import { readManifest, repoRoot } from "./manifest-lib.mjs";
import { fixtureCheckoutPath, fixtureSourceRoot, readManifest, repoRoot } from "./manifest-lib.mjs";
const args = process.argv.slice(2);
const strict = args.includes("--strict");
@ -22,8 +22,8 @@ const rows = [];
const missing = [];
for (const fixture of manifest.fixtures) {
const checkoutPath = path.join(repoRoot, fixture.path);
const pluginRoot = fixture.subdir ? path.join(checkoutPath, fixture.subdir) : checkoutPath;
const checkoutPath = fixtureCheckoutPath(fixture);
const pluginRoot = fixtureSourceRoot(fixture);
if (!existsSync(checkoutPath)) {
rows.push(row(fixture, "missing", "not materialized"));
@ -88,4 +88,3 @@ async function readPackageName(filePath) {
return "invalid package.json";
}
}

View File

@ -4,7 +4,7 @@ import { mkdir, mkdtemp, readFile, readdir, rm } from "node:fs/promises";
import os from "node:os";
import { spawnSync } from "node:child_process";
import path from "node:path";
import { readManifest, repoRoot } from "./manifest-lib.mjs";
import { fixtureSourceRoot, readManifest, repoRoot } from "./manifest-lib.mjs";
const args = new Set(process.argv.slice(2));
const materialize = args.has("--materialize");
@ -14,6 +14,7 @@ const manifest = await readManifest();
if (check) {
await checkGitmodules(manifest);
await checkNpmFixtureShims(manifest);
console.log(`crabpot: manifest ok (${manifest.fixtures.length} fixtures)`);
process.exit(0);
}
@ -60,9 +61,25 @@ async function checkGitmodules(manifest) {
}
}
async function checkNpmFixtureShims(manifest) {
const errors = [];
for (const fixture of manifest.fixtures.filter((item) => item.package)) {
try {
await readNpmFixtureDependency(fixture);
} catch (error) {
errors.push(error.message);
}
}
if (errors.length > 0) {
throw new Error(`npm fixture shims are invalid:\n${errors.join("\n")}`);
}
}
async function materializeNpmFixture(fixture, target) {
const spec = `${fixture.package.name}@${fixture.package.version}`;
const dependency = await readNpmFixtureDependency(fixture);
const spec = `${dependency.name}@${dependency.version}`;
const tempDir = await mkdtemp(path.join(os.tmpdir(), "crabpot-npm-fixture-"));
const payloadDir = fixtureSourceRoot(fixture);
try {
const pack = spawnSync("npm", ["pack", spec, "--pack-destination", tempDir, "--json"], {
cwd: repoRoot,
@ -80,14 +97,37 @@ async function materializeNpmFixture(fixture, target) {
throw new Error(`npm pack ${spec} did not return a tarball filename`);
}
await rm(target, { recursive: true, force: true });
await mkdir(target, { recursive: true });
run("tar", ["-xzf", path.join(tempDir, packed.filename), "-C", target, "--strip-components", "1"]);
await rm(payloadDir, { recursive: true, force: true });
await mkdir(payloadDir, { recursive: true });
run("tar", ["-xzf", path.join(tempDir, packed.filename), "-C", payloadDir, "--strip-components", "1"]);
} finally {
await rm(tempDir, { recursive: true, force: true });
}
}
async function readNpmFixtureDependency(fixture) {
const shimPath = path.join(repoRoot, fixture.path, "package.json");
if (!existsSync(shimPath)) {
throw new Error(`${fixture.id}: missing npm shim ${path.relative(repoRoot, shimPath)}`);
}
const packageJson = JSON.parse(await readFile(shimPath, "utf8"));
const declared =
packageJson.dependencies?.[fixture.package.name] ??
packageJson.devDependencies?.[fixture.package.name] ??
packageJson.optionalDependencies?.[fixture.package.name];
if (typeof declared !== "string") {
throw new Error(`${fixture.id}: shim does not depend on ${fixture.package.name}`);
}
if (!/^\d+\.\d+\.\d+/.test(declared)) {
throw new Error(`${fixture.id}: ${fixture.package.name} must use an exact semver pin, got ${declared}`);
}
return {
name: fixture.package.name,
version: declared,
};
}
async function hasEntries(target) {
try {
return (await readdir(target)).length > 0;

View File

@ -54,7 +54,7 @@ test("manifest validation rejects invalid fixture contracts before CI materializ
"duplicate fixture path: ../outside",
"fixture must declare exactly one of repo or package",
"repo must be a GitHub HTTPS .git URL",
"package.version must be set",
"package.name must be set",
"priority must be high, medium, or low",
"seams must be non-empty",
"expect.hooks must be a non-empty array",
@ -74,9 +74,7 @@ function invalidManifest() {
id: "Bad_ID",
path: "../outside",
repo: "git@github.com:owner/repo",
package: {
name: "@scope/plugin",
},
package: {},
priority: "urgent",
seams: [],
expect: {

View File

@ -12,6 +12,18 @@ test("dependabot is configured to update plugin submodules", async () => {
assert.match(dependabot, /interval:\s*"weekly"/);
});
test("dependabot is configured to update npm fixture shims", async () => {
const manifest = await readManifest();
const dependabot = await readFile(".github/dependabot.yml", "utf8");
for (const fixture of manifest.fixtures.filter((item) => item.package)) {
assert.match(
dependabot,
new RegExp(`package-ecosystem:\\s*"npm"[\\s\\S]*directory:\\s*"\\/${escapeRegExp(fixture.path)}"`),
);
}
});
test("plugin submodule README stays aligned with manifest and gitmodules", async () => {
const manifest = await readManifest();
const gitmodules = await readFile(".gitmodules", "utf8");
@ -23,6 +35,8 @@ test("plugin submodule README stays aligned with manifest and gitmodules", async
assert.match(readme, /## Add A Plugin/);
assert.match(readme, /## Remove A Plugin/);
assert.match(readme, /package-ecosystem: "gitsubmodule"/);
assert.match(readme, /package-ecosystem: "npm"/);
assert.match(readme, /plugins\/<id>\/package\.json/);
for (const fixture of gitFixtures) {
const submodule = submodules.find((item) => item.path === fixture.path);