Compare commits

..
Author SHA1 Message Date
StanPonomarev 513d51f702 stricter checks
CI / verify (pull_request) Successful in 12s
2026-10-10 15:16:53 +02:00
StanPonomarev ced43fbb11 chore: reorg files 2026-10-10 15:00:15 +02:00
StanPonomarev c853cca9cf Merge pull request 'Feat/remove optchat add planning prompt' (#24) from feat/remove_optchat_add_planning_prompt into main
Reviewed-on: #24
2026-10-10 14:55:51 +02:00
40 changed files with 1019 additions and 502 deletions
+62
View File
@@ -0,0 +1,62 @@
/** @type {import('dependency-cruiser').IConfiguration} */
module.exports = {
forbidden: [
{
name: "no-circular",
severity: "error",
from: {},
to: { circular: true },
},
{
name: "no-orphans",
severity: "error",
from: { orphan: true, pathNot: ["\\.d\\.ts$"] },
to: {},
},
{
name: "not-to-unresolvable",
severity: "error",
from: {},
to: { couldNotResolve: true, pathNot: ["^bun:"] },
},
{
name: "quota-is-standalone",
comment: "Quota ships independently of Agents and Multi-work.",
severity: "error",
from: { path: "^src/quota/" },
to: { path: "^src/(agents|multi-work)/" },
},
{
name: "agents-is-standalone",
comment: "Agents must load without Quota or Multi-work.",
severity: "error",
from: { path: "^src/agents/" },
to: { path: "^src/(quota|multi-work)/" },
},
{
name: "multi-work-not-to-quota",
comment: "Multi-work may build on Agents but not on Quota.",
severity: "error",
from: { path: "^src/multi-work/" },
to: { path: "^src/quota/" },
},
{
name: "src-not-to-scripts-or-tests",
severity: "error",
from: { path: "^src/" },
to: { path: "^(scripts|tests)/" },
},
],
options: {
doNotFollow: { path: "node_modules" },
tsConfig: { fileName: "tsconfig.json" },
tsPreCompilationDeps: true,
// TypeScript 7 has no compiler API yet; swc parses TS/TSX for the cruise.
parser: "swc",
enhancedResolveOptions: {
exportsFields: ["exports"],
conditionNames: ["import", "types", "bun", "default"],
extensions: [".ts", ".tsx", ".js", ".d.ts"],
},
},
};
+1 -4
View File
@@ -22,8 +22,5 @@ jobs:
- name: Verify and build - name: Verify and build
run: | run: |
bun install --frozen-lockfile bun install --frozen-lockfile
bun run check bun run verify
bun run lint
bun run format:check
bun run test
bun run build bun run build
+1 -4
View File
@@ -28,10 +28,7 @@ jobs:
- name: Verify and build - name: Verify and build
run: | run: |
bun install --frozen-lockfile bun install --frozen-lockfile
bun run check bun run verify
bun run lint
bun run format:check
bun run test
bun run build bun run build
- name: Pack distributable - name: Pack distributable
run: | run: |
+8
View File
@@ -0,0 +1,8 @@
{
"path": ["src", "scripts", "tests"],
"format": ["typescript", "tsx"],
"threshold": 1,
"minTokens": 50,
"reporters": ["console"],
"gitignore": true
}
+1 -1
View File
@@ -16,7 +16,7 @@
".roo/**", ".roo/**",
".windsurf/**", ".windsurf/**",
"tools/oxlint/anti-slop/**", "tools/oxlint/anti-slop/**",
"src/anti-overengineering.md", "src/skills/anti-overengineering.md",
"node_modules/**", "node_modules/**",
"dist/**", "dist/**",
"coverage/**", "coverage/**",
+76 -1
View File
@@ -24,6 +24,34 @@
} }
], ],
"rules": { "rules": {
"typescript/no-explicit-any": "error",
"typescript/ban-ts-comment": "error",
"typescript/no-non-null-assertion": "error",
"max-lines": [
"error",
{
"max": 600,
"skipBlankLines": true,
"skipComments": true
}
],
"max-lines-per-function": "off",
"complexity": ["error", 20],
"max-depth": ["error", 4],
"max-params": ["error", 5],
"typescript/no-floating-promises": "error",
"typescript/no-misused-promises": "error",
"typescript/no-unsafe-argument": "error",
"typescript/no-unsafe-assignment": "error",
"typescript/no-unsafe-call": "error",
"typescript/no-unsafe-member-access": "error",
"typescript/no-unsafe-return": "error",
"typescript/no-unsafe-enum-comparison": "error",
"typescript/no-unsafe-unary-minus": "error",
"typescript/no-unsafe-type-assertion": "error",
"typescript/no-unnecessary-condition": "error",
"typescript/strict-boolean-expressions": "error",
"typescript/switch-exhaustiveness-check": "error",
"anti-slop/no-chained-type-assertions": "error", "anti-slop/no-chained-type-assertions": "error",
"anti-slop/no-conditional-empty-object-spread": "error", "anti-slop/no-conditional-empty-object-spread": "error",
"anti-slop/no-known-value-widening": "error", "anti-slop/no-known-value-widening": "error",
@@ -38,6 +66,53 @@
"anti-slop/no-unknown-type-aliases": "error", "anti-slop/no-unknown-type-aliases": "error",
"anti-slop/no-unsafe-dictionary-type": "error", "anti-slop/no-unsafe-dictionary-type": "error",
"anti-slop/no-widen-then-assert": "error", "anti-slop/no-widen-then-assert": "error",
"anti-slop/require-safety-comment-for-type-assertion": "error" "anti-slop/require-safety-comment-for-type-assertion": "error",
"typescript/prefer-readonly-parameter-types": "off",
"eslint/require-await": "off",
"eslint/no-await-in-loop": "off",
"import/max-dependencies": [
"error",
{
"max": 15
}
],
"typescript/require-await": "off",
"typescript/consistent-return": "off",
"eslint/no-underscore-dangle": "off",
"unicorn/prefer-top-level-await": "off",
"unicorn/no-useless-undefined": [
"error",
{
"checkArguments": false,
"checkArrowFunctionBody": false
}
],
"oxc/no-map-spread": "off",
"eslint/no-useless-return": "off"
},
"plugins": ["typescript", "unicorn", "oxc", "import", "promise"],
"categories": {
"correctness": "error",
"suspicious": "error",
"pedantic": "error",
"perf": "error"
},
"overrides": [
{
"files": ["tests/**"],
"rules": {
"typescript/no-unsafe-type-assertion": "off",
"typescript/await-thenable": "off",
"typescript/no-confusing-void-expression": "off"
}
},
{
"files": ["**/*.tsx", "tests/tui.test.ts"],
"rules": {
"typescript/no-unsafe-return": "off",
"typescript/no-unsafe-assignment": "off",
"typescript/no-unsafe-member-access": "off"
} }
} }
]
}
+249 -24
View File
@@ -15,9 +15,14 @@
"@opentui/core": "0.5.14", "@opentui/core": "0.5.14",
"@opentui/solid": "0.5.14", "@opentui/solid": "0.5.14",
"@oxlint/plugins": "1.86.0", "@oxlint/plugins": "1.86.0",
"@swc/core": "1.16.13",
"@types/bun": "1.4.2", "@types/bun": "1.4.2",
"dependency-cruiser": "18.5.0",
"jscpd": "5.4.1",
"knip": "6.41.0",
"oxfmt": "0.71.0", "oxfmt": "0.71.0",
"oxlint": "1.86.0", "oxlint": "1.86.0",
"oxlint-tsgolint": "7.0.2004",
"solid-js": "1.9.15", "solid-js": "1.9.15",
"typescript": "7.0.2", "typescript": "7.0.2",
}, },
@@ -144,6 +149,12 @@
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="], "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="],
"@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="], "@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
@@ -172,6 +183,8 @@
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA=="],
"@npmcli/agent": ["@npmcli/agent@4.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg=="], "@npmcli/agent": ["@npmcli/agent@4.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg=="],
"@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="], "@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="],
@@ -260,6 +273,84 @@
"@opentui/solid": ["@opentui/solid@0.5.14", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.14", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-bBRl34mZ0wFGhjHX6y1VNiZmJ3DSm2DVPm0PNSVDpvq9qxRHuywEPTCn/Lgte0C9450tgf11cDqcE3pR9cZwVA=="], "@opentui/solid": ["@opentui/solid@0.5.14", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.14", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-bBRl34mZ0wFGhjHX6y1VNiZmJ3DSm2DVPm0PNSVDpvq9qxRHuywEPTCn/Lgte0C9450tgf11cDqcE3pR9cZwVA=="],
"@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.153.0", "", { "os": "android", "cpu": "arm" }, "sha512-BcWu25dMwMjHpaDCEidmpAi7rGg1qZoihJeUUH9bD55pVZ0z4Wa5CQgqSTo0R41H81oozisQKW3WqvAN2m77IQ=="],
"@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.153.0", "", { "os": "android", "cpu": "arm64" }, "sha512-9l5rdp2DhRqVriBHsNpu5cEf+hizZ4B58rt93HzyQEBUgZiC6qe2oFpaAAnXGCxHGnQExI1s7S2G0QhFacUZ6w=="],
"@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.153.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EcpsyRXHhENDpekpG4QNaSZj2F/BAz4Gh4o89zZwNss86R8KyRSQ6sXbAj74Xyeb4z3j/yBZZ6joQZhraIWyfw=="],
"@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.153.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-hlj80HUQy07/2lYp6rmxH+3u+H2ik3rjLR52CUdPApxmZCNxASDUf/+ykTzAHS/fehftmVMATKvPaWmuLHuasg=="],
"@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.153.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fWRcv2pMSh1qtez46MOu8vuUJ5fiaQZPHSphbWulbL7SHBMKfRgZl2PzjXZYQJbq7NEXyXbgIuIuUm+/Rmkv8w=="],
"@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.153.0", "", { "os": "linux", "cpu": "arm" }, "sha512-paZeUK1GXShl/bOJQET1/8AQxayFeuN4SIWAkgTRxE7ZQwv9uYSB2n0648smygP22N7jcI3zxAm0Z+ALNiIKxg=="],
"@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.153.0", "", { "os": "linux", "cpu": "arm" }, "sha512-qFPp5NwMf4K1C0O+DCVGmcbOaYyYAq98Rvv9p4VSfb777iUwlJCqMUxf6QG9N5f5ls4TEX6LitOZHi+6GL6rYQ=="],
"@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.153.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oufEhZCX7saeo27Logra8cvBR1jQ/yw2zUI2hHmWw3qA/XYqEW31FOvLQBv7DWN32NjVdlcaP11WBBZTJo4k9g=="],
"@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.153.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-zXYzuAqng85h6+LI3iRm0zeMLX1/K2z41ZAMWxVRgt0D10VvZUaV5q+TEB46KDhoKBpdexoTLC6QoB/EiP2oqQ=="],
"@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.153.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-J7+NLwLEzdkKM9cKyPHH/AjXXstWOs98KYgLrPPnO4N9MO8EZRBfPNnBcS3S67uMOBkRpUmCl2FhRnWdQ5CbBA=="],
"@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.153.0", "", { "os": "linux", "cpu": "none" }, "sha512-sD0K11GQTLWylln54nPMMTtgmBbQrR5It/vMpZpy/fogiw8O2AvIE+9LuWUXddrWk9zvFIHGRcSgFn4IHOfoYg=="],
"@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.153.0", "", { "os": "linux", "cpu": "none" }, "sha512-7L66uql2BhvSz51LwfExjOdn6et/ydTiQxl23VApdKzJhTc3TczA1Qt6VR/UcvlQrL2ZbytIJb447vh7p5wmUw=="],
"@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.153.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hXV3T7mNyrPR19rbPYkglkQJtoM/UNo/xwbZeeqdAxEg8PXgb4LXXuxPpGgI4bzRRCWwLUxdDSS58xIyC2u1TA=="],
"@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.153.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Da8Vqs1xdtoDYtEjmozD7wGgJeLBQkMbR0WUBECOSxodyX5DXy8ySlvJWbukyO2Q0+TM9EK+4LT6tbq0jCg4hQ=="],
"@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.153.0", "", { "os": "linux", "cpu": "x64" }, "sha512-zGAPxNTIIw6X5WyTRscIFE/oDjpdNtrrl32ing6NOXdGjzRucadnxBilexLdeYQ9YxixF93GujpXyQ0jw7ddSg=="],
"@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.153.0", "", { "os": "none", "cpu": "arm64" }, "sha512-GoHzpqP5XyPIp9DHokoEdCp+K4UPl/h1neFj1uXnUB3pJYyOQ7NOhFVOttNUgCGcj2eywAvu5cRivTOSq4S10g=="],
"@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.153.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xGcy12tO9k7zFbeyQzEuilfWfQpyRq23/fLPfN3wjSWuWv58k46fQT1hsO1KFNykZuVGW9xSJE/z592TmAoSDA=="],
"@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.153.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-o1ykUjWncvXX6N5a4KebgLjtD8zRui+f1llMhSGoSC9oP2KOqapRpdwmZ3NcNG0axFouwVKmhGBjd+IhA8BksA=="],
"@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.153.0", "", { "os": "win32", "cpu": "x64" }, "sha512-gxQz7G96Up136fd+2zWrP+o6FYGs9NO4Dyv55IoeJFJUDwLFHcLYY11hhA5wQKs0HoM57Q8esQ3nEVhnCdsjAQ=="],
"@oxc-project/types": ["@oxc-project/types@0.153.0", "", {}, "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw=="],
"@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA=="],
"@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg=="],
"@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w=="],
"@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q=="],
"@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw=="],
"@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg=="],
"@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA=="],
"@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA=="],
"@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw=="],
"@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA=="],
"@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw=="],
"@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w=="],
"@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ=="],
"@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg=="],
"@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw=="],
"@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg=="],
"@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.24.2", "", { "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q=="],
"@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg=="],
"@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw=="],
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.71.0", "", { "os": "android", "cpu": "arm" }, "sha512-l31EyBfB4egJeFua11aQFEUE9nnDtfpWCadqQovm0WL30t/yUHtdFl/5HyFXvd5xT8Ewh3U4TI9f30GowrQ1fw=="], "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.71.0", "", { "os": "android", "cpu": "arm" }, "sha512-l31EyBfB4egJeFua11aQFEUE9nnDtfpWCadqQovm0WL30t/yUHtdFl/5HyFXvd5xT8Ewh3U4TI9f30GowrQ1fw=="],
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.71.0", "", { "os": "android", "cpu": "arm64" }, "sha512-E8q39SUZzSXQ08oZoFoTkxRADkdBNgL6De4qgZYr2O4JCunwqrZwAyCebxIF3yVHBafHM30WUkhTkDi+jNYZOw=="], "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.71.0", "", { "os": "android", "cpu": "arm64" }, "sha512-E8q39SUZzSXQ08oZoFoTkxRADkdBNgL6De4qgZYr2O4JCunwqrZwAyCebxIF3yVHBafHM30WUkhTkDi+jNYZOw=="],
@@ -298,6 +389,18 @@
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.71.0", "", { "os": "win32", "cpu": "x64" }, "sha512-L06SVp7Hu1EQTkh3+PHnKK26dxVbEpOG2InMwCooTE4MA437b5FgfTleCCiGn4ykISHnHU6UHaIg7SiMO7rBHA=="], "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.71.0", "", { "os": "win32", "cpu": "x64" }, "sha512-L06SVp7Hu1EQTkh3+PHnKK26dxVbEpOG2InMwCooTE4MA437b5FgfTleCCiGn4ykISHnHU6UHaIg7SiMO7rBHA=="],
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@7.0.2004", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJk3ttju7Lz+Nv8WG4CsLyewoL1qf/Ny8S8OksJ7Bm/F14Tc9gMfW6arM1PCc57IzH/X/I79YsCWTgxX1FKibQ=="],
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@7.0.2004", "", { "os": "darwin", "cpu": "x64" }, "sha512-0BFfHTzDxNDFPcu0UZAXT6CyCJHAXM0dZveyDb4KEHa2qF/DSnOKOrmvK/wFuFol9kvijbGM9JfuOsor+zWXRw=="],
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@7.0.2004", "", { "os": "linux", "cpu": "arm64" }, "sha512-TAehQc+qdRXyDN3nl/r/3/oPrBVrbtrDeGMkFyG6mf+XphpoJ2lAMVFLclyvrVZCw02RbKROjyw8h72XwQQHcw=="],
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@7.0.2004", "", { "os": "linux", "cpu": "x64" }, "sha512-LPunZvm6ZbWPfHMAyfZf9ci3HHvNEzLejO8zdqO3GoVGoSEHqqufHUD7+OgeatVSaJP7uXDJ2HaNOHIoH7go4Q=="],
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@7.0.2004", "", { "os": "win32", "cpu": "arm64" }, "sha512-FVWplzDImWhiuawnIZVETaQecv4GWom6Jv4Fx2xj7hhXXDZ5okEgiw1gTCImHTIQsi2ycC5oSxVwrn69bMh7iw=="],
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@7.0.2004", "", { "os": "win32", "cpu": "x64" }, "sha512-7PsxuUx11Ry9DYTWcljTzRbmZY9B6O9fFFfZV+aodQEMy6pfRT3fhoQRv9PtGN/89z1pPz3nFKrsFm6WqNtX7w=="],
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.86.0", "", { "os": "android", "cpu": "arm" }, "sha512-63Ozq6yQn79B2UxjSZ9huJmI+3/ZPI7hxAe6TyFh9oQL447KnIMoffOdtog+h4KILbQr61ZRvFPW5gYbAUgpgQ=="], "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.86.0", "", { "os": "android", "cpu": "arm" }, "sha512-63Ozq6yQn79B2UxjSZ9huJmI+3/ZPI7hxAe6TyFh9oQL447KnIMoffOdtog+h4KILbQr61ZRvFPW5gYbAUgpgQ=="],
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.86.0", "", { "os": "android", "cpu": "arm64" }, "sha512-JdLGp44phbf/0Du236Dt06yfK6Qw8xhTFeDvHJdjk167r59OfP5+BL31mgMYVnswS8e+j6tFuccSY0QDC/lgCw=="], "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.86.0", "", { "os": "android", "cpu": "arm64" }, "sha512-JdLGp44phbf/0Du236Dt06yfK6Qw8xhTFeDvHJdjk167r59OfP5+BL31mgMYVnswS8e+j6tFuccSY0QDC/lgCw=="],
@@ -386,10 +489,42 @@
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@swc/core": ["@swc/core@1.16.13", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.28" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.16.13", "@swc/core-darwin-x64": "1.16.13", "@swc/core-linux-arm-gnueabihf": "1.16.13", "@swc/core-linux-arm64-gnu": "1.16.13", "@swc/core-linux-arm64-musl": "1.16.13", "@swc/core-linux-ppc64-gnu": "1.16.13", "@swc/core-linux-s390x-gnu": "1.16.13", "@swc/core-linux-x64-gnu": "1.16.13", "@swc/core-linux-x64-musl": "1.16.13", "@swc/core-win32-arm64-msvc": "1.16.13", "@swc/core-win32-ia32-msvc": "1.16.13", "@swc/core-win32-x64-msvc": "1.16.13" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-k4uUsIMS0IwOKVsrQs48IZK75O4roV3FnuJEdL7ES+DFESftdgvz73QBqN3VUAbUmUr78We4tzG0kgYj36M22Q=="],
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.16.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JrMH2h7ohd4mOIneNRx/diqTmCDSdWfp9uOdQ8VJ2V2CA7jOJ1jWb+qp8RoZLqgiVmwDDC7eySKB1kbvZ+jVXQ=="],
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.16.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-HauZMRxpOImRxgY6GXjw5gbD8ts2NcPZuLMM8htY8Mic7j1Izt/lxkXrKYUwqyU56YLwQZ4dHRT+6jFHkztcag=="],
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.16.13", "", { "os": "linux", "cpu": "arm" }, "sha512-tUSojGIythnHJKrElDM9OvuhBnK+FF39eM9iIBgj9kdfbAm6PhAM7dKbaSDcnX2gOLG2slkasjD0Z8m/YUlzOA=="],
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.16.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-qS3bk/ezRrLXGn1b764S/EG3/oKj6uRhnTNRAALpnuu8d9I0YwSiUkQghnX7lOH9X/yRr+qrFI3R0wAruO47Tg=="],
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.16.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-aeoYoG6fQsOS3mFOuTKvnJo1aaaxYNI0aRRlhdHaGP4q1YQx4XOc5Hkd35IFduWCBG3eZl3fPTjRuYvxpl7eTA=="],
"@swc/core-linux-ppc64-gnu": ["@swc/core-linux-ppc64-gnu@1.16.13", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eEFoueZXWZ2S1lsqL8Ve2C8RjhzH9+Ktj8U4IGTUQL6CNG04+VhQiYQWJOf5xfVBU6I+PbH80yvsYegqZOOSZQ=="],
"@swc/core-linux-s390x-gnu": ["@swc/core-linux-s390x-gnu@1.16.13", "", { "os": "linux", "cpu": "s390x" }, "sha512-K0q1ReVXL3d5bzBgZxS+yJq5q2xRjg4k2XXGj9yiCEpE5ZqJGQ4Gtk1sRrk8W2lo3KY0DCJD3Myt6x2SMvGArQ=="],
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.16.13", "", { "os": "linux", "cpu": "x64" }, "sha512-Qvpihw30irhIjy2f91BR1pamcJBCgf8hmr9XWenztAX1YLkneRkkTB/PFGWQubhaBqQhY2uZKViMj/xV61uMBQ=="],
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.16.13", "", { "os": "linux", "cpu": "x64" }, "sha512-iCGxHbh3Cq5vqRvCPlw3XkkDz4RlkPSyQwfFKbOKTMj5tiEuojY/rLmf4BMfI9Z8yPJTf9VB07t3NbKInoC97g=="],
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.16.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-iOabn6cd+hg3cnoKlAC8j3Yufv8nQHBVU5OIDX8dCPA95PjAZ0B0TlDn9sWivk8ezo/cLJux7p9n0B9vRej+1Q=="],
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.16.13", "", { "os": "win32", "cpu": "ia32" }, "sha512-+1b/3xBNuVbpnJIZUCAaSdscOPYRWq85eohKx44y/3qbPp56UMiCJWBiWtyr7K5F1nf1JENXm2IBSEJaLgWq6Q=="],
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.16.13", "", { "os": "win32", "cpu": "x64" }, "sha512-6kEJhYshk7OVoVIWryiHqjCNuwZeOlPTS6et+bKV/WhtHs8fLA01wyTLrQGi+4ultgRe/o0M4b25K/KKdvl0dQ=="],
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
"@swc/types": ["@swc/types@0.1.28", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw=="],
"@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="],
"@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], "@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A=="],
"@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="], "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="],
"@types/node": ["@types/node@26.5.0", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A=="], "@types/node": ["@types/node@26.5.0", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A=="],
@@ -438,11 +573,21 @@
"abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="],
"acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"acorn-jsx-walk": ["acorn-jsx-walk@2.0.0", "", {}, "sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA=="],
"acorn-loose": ["acorn-loose@8.5.2", "", { "dependencies": { "acorn": "^8.15.0" } }, "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A=="],
"acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="],
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="],
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
@@ -480,6 +625,8 @@
"caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="], "caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
"ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="],
@@ -492,6 +639,8 @@
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="],
"common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], "common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="],
"content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], "content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="],
@@ -514,6 +663,8 @@
"define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="],
"dependency-cruiser": ["dependency-cruiser@18.5.0", "", { "dependencies": { "acorn": "8.18.0", "acorn-jsx": "5.3.2", "acorn-jsx-walk": "2.0.0", "acorn-loose": "8.5.2", "acorn-walk": "8.3.5", "commander": "15.0.0", "enhanced-resolve": "5.26.0", "ignore": "7.0.11", "interpret": "3.1.1", "is-installed-globally": "1.0.1", "json5": "2.2.3", "picomatch": "4.0.7", "prompts": "2.4.2", "rechoir": "0.8.0", "safe-regex": "2.1.1", "semver": "7.8.5", "tsconfig-paths-webpack-plugin": "4.2.0", "watskeburt": "6.0.0" }, "bin": { "depcruise": "bin/dependency-cruiser.mjs", "depcruise-fmt": "bin/depcruise-fmt.mjs", "dependency-cruise": "bin/dependency-cruiser.mjs", "depcruise-baseline": "bin/depcruise-baseline.mjs", "dependency-cruiser": "bin/dependency-cruiser.mjs", "depcruise-wrap-stream-in-html": "bin/wrap-stream-in-html.mjs" } }, "sha512-LFvJOvufjQ7XTucSI40NHqse0gcQBevDGkZabLAKcGwO+VWOywTqZ5EyFRYWSokNxvLOO7v6EXyNi+9I72oWUA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="],
@@ -528,6 +679,8 @@
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"enhanced-resolve": ["enhanced-resolve@5.26.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw=="],
"entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
"env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
@@ -542,6 +695,8 @@
"fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], "fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="],
"fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "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=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
@@ -552,6 +707,8 @@
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
"formatly": ["formatly@0.11.4", "", { "dependencies": { "fd-package-json": "^2.0.0", "package-manager-detector": "^1.8.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-TeCC10lP8KCgoX+Fe5lryILIT0/Dy+nP0OSVnsuB5CwXoLuOdqxCYlPFF1inR8S/zTy1ec7TjhS2TeRKWzzImA=="],
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
"fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="],
@@ -568,8 +725,12 @@
"get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
"get-tsconfig": ["get-tsconfig@4.14.3", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA=="],
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
"global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="],
"google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="], "google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="],
"google-logging-utils": ["google-logging-utils@1.2.0", "", {}, "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A=="], "google-logging-utils": ["google-logging-utils@1.2.0", "", {}, "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A=="],
@@ -578,6 +739,8 @@
"gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="],
"hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="],
@@ -592,10 +755,14 @@
"iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], "iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="],
"ignore": ["ignore@7.0.11", "", {}, "sha512-YChdK5txDjwGUvgR7oCJcLGkwi3LDh8Zx8tS7ndYciLEg/oOCL26VUBSUEtgS7EjiybcBqFxh5j0rAdDX7/bbg=="],
"ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="],
"ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], "ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="],
"interpret": ["interpret@3.1.1", "", {}, "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ=="],
"ip-address": ["ip-address@10.7.0", "", {}, "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA=="], "ip-address": ["ip-address@10.7.0", "", {}, "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA=="],
"is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="],
@@ -608,14 +775,38 @@
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
"is-installed-globally": ["is-installed-globally@1.0.1", "", { "dependencies": { "global-directory": "^4.0.1", "is-path-inside": "^4.0.0" } }, "sha512-li88H4QGRoNMX27jEmY8nR515oJVspAgC/WFMlhHfFV8RJ4QyGpHhXnwAe9gH5RIgKmdYRUmrOhQobcgEjIdSw=="],
"is-path-inside": ["is-path-inside@4.0.0", "", {}, "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA=="],
"is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"jscpd": ["jscpd@5.4.1", "", { "optionalDependencies": { "jscpd-darwin-arm64": "5.4.1", "jscpd-darwin-x64": "5.4.1", "jscpd-linux-arm64-gnu": "5.4.1", "jscpd-linux-arm64-musl": "5.4.1", "jscpd-linux-x64-gnu": "5.4.1", "jscpd-linux-x64-musl": "5.4.1", "jscpd-windows-arm64-msvc": "5.4.1", "jscpd-windows-x64-msvc": "5.4.1" }, "bin": { "jscpd": "run-jscpd.js" } }, "sha512-afUt+LSQMmzSPYrWZlNGTwj8X4tmwVJbMNmr92qxPf4uUF/naLwG7SQyMPEZtrHqGgzGxmAzNjiwlVdjls2MyQ=="],
"jscpd-darwin-arm64": ["jscpd-darwin-arm64@5.4.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LXHVeH60C9BsozcVIMPmXWvj97KqFKbCJYmYG4hDwfwIwS1kz+uF7yiObckP6h2xo12pD88nI4XjWTB5frjZUw=="],
"jscpd-darwin-x64": ["jscpd-darwin-x64@5.4.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Gqck4tcMZjv4IvYHU2Vcikb885zTADo5T/YfEqeu1i5W5tfFpLdViiTYrh5wbrW+uxBqC33gHpG1hy0xbGYknQ=="],
"jscpd-linux-arm64-gnu": ["jscpd-linux-arm64-gnu@5.4.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-XUYZJZVxSY7JIBEoyOOMTgvJwmymkns4wG55tu6I/vRKXnS5QtaTESQfRLt6xj1+62aflAvr01FAhPAy+du6tA=="],
"jscpd-linux-arm64-musl": ["jscpd-linux-arm64-musl@5.4.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-h2sH8Bk++yBxWqq2QAy4fvPzXkw1vecDSyOmzLwPfnRQoQ2Q/EWxCNOrgJSb+SNMLWoHLLzfqx8m9wt2GG6a8w=="],
"jscpd-linux-x64-gnu": ["jscpd-linux-x64-gnu@5.4.1", "", { "os": "linux", "cpu": "x64" }, "sha512-UiC4YoGAVVLy6hPVz8A6cndo7W5br4FAO2hADnFeinhBPnXPu0QFh1q/s/8B3ldeQHQkpYd/l5cjqNBMrbm78w=="],
"jscpd-linux-x64-musl": ["jscpd-linux-x64-musl@5.4.1", "", { "os": "linux", "cpu": "x64" }, "sha512-toAafl5roqfFotPrDJNMY9noNVZ9dReBqcO/nT5pJ8+7aq+opbscaLUcV4+8jxTq5btUD6CiO72+Fu+TyUZv3Q=="],
"jscpd-windows-arm64-msvc": ["jscpd-windows-arm64-msvc@5.4.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-JLMga/NIwv/OPurPsXA2/d5OdWfdwrsBk2D4NhyKnrV/uNjo1BIi2zXztzDyTQVKMK/TEK6GPgLD143GG1fZ0A=="],
"jscpd-windows-x64-msvc": ["jscpd-windows-x64-msvc@5.4.1", "", { "os": "win32", "cpu": "x64" }, "sha512-sN57Y9YP3ijrqc1IsWDceOFHUwbukg9/mU2NSDHTryKKc5CUvWz+o9GId8uKTiJIhkKfR/Ce5GKkCepTwB6kaw=="],
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
@@ -638,6 +829,10 @@
"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=="], "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=="],
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"knip": ["knip@6.41.0", "", { "dependencies": { "formatly": "^0.11.4", "get-tsconfig": "4.14.3", "jiti": "^2.7.0", "oxc-parser": "^0.153.0", "oxc-resolver": "11.24.2", "picomatch": "^4.0.7", "smol-toml": "^1.9.0", "strip-json-comments": "5.0.3", "tinyglobby": "^0.2.17", "unbash": "^5.0.0", "yaml": "^2.9.1", "zod": "^4.6.5" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-DrhQlIuV6xScd5Q+WTF1znd1w41QzxFGCtAHXCajsH/ndGMotHoNYbdXbuFtzW3mIOmniHtZ7zCtvnQkUmJtQQ=="],
"locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], "locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
"lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], "lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="],
@@ -654,6 +849,8 @@
"minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
"minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="],
@@ -704,10 +901,16 @@
"open": ["open@11.0.4", "", { "dependencies": { "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.1", "wsl-utils": "^1.0.0" } }, "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg=="], "open": ["open@11.0.4", "", { "dependencies": { "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.1", "wsl-utils": "^1.0.0" } }, "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg=="],
"oxc-parser": ["oxc-parser@0.153.0", "", { "dependencies": { "@oxc-project/types": "^0.153.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.153.0", "@oxc-parser/binding-android-arm64": "0.153.0", "@oxc-parser/binding-darwin-arm64": "0.153.0", "@oxc-parser/binding-darwin-x64": "0.153.0", "@oxc-parser/binding-freebsd-x64": "0.153.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.153.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.153.0", "@oxc-parser/binding-linux-arm64-gnu": "0.153.0", "@oxc-parser/binding-linux-arm64-musl": "0.153.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.153.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.153.0", "@oxc-parser/binding-linux-riscv64-musl": "0.153.0", "@oxc-parser/binding-linux-s390x-gnu": "0.153.0", "@oxc-parser/binding-linux-x64-gnu": "0.153.0", "@oxc-parser/binding-linux-x64-musl": "0.153.0", "@oxc-parser/binding-openharmony-arm64": "0.153.0", "@oxc-parser/binding-win32-arm64-msvc": "0.153.0", "@oxc-parser/binding-win32-ia32-msvc": "0.153.0", "@oxc-parser/binding-win32-x64-msvc": "0.153.0" } }, "sha512-cEnpyyV1OJRXv++SFNw0z8i+2o/cr88rVLaOYJafELDoHM5yHvCAbwGRLvxuany6SNLcbblSMUyZaGzH+quSYg=="],
"oxc-resolver": ["oxc-resolver@11.24.2", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.24.2", "@oxc-resolver/binding-android-arm64": "11.24.2", "@oxc-resolver/binding-darwin-arm64": "11.24.2", "@oxc-resolver/binding-darwin-x64": "11.24.2", "@oxc-resolver/binding-freebsd-x64": "11.24.2", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-musl": "11.24.2", "@oxc-resolver/binding-openharmony-arm64": "11.24.2", "@oxc-resolver/binding-wasm32-wasi": "11.24.2", "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" } }, "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw=="],
"oxfmt": ["oxfmt@0.71.0", "", { "dependencies": { "tinypool": "2.2.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.71.0", "@oxfmt/binding-android-arm64": "0.71.0", "@oxfmt/binding-darwin-arm64": "0.71.0", "@oxfmt/binding-darwin-x64": "0.71.0", "@oxfmt/binding-freebsd-x64": "0.71.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.71.0", "@oxfmt/binding-linux-arm-musleabihf": "0.71.0", "@oxfmt/binding-linux-arm64-gnu": "0.71.0", "@oxfmt/binding-linux-arm64-musl": "0.71.0", "@oxfmt/binding-linux-ppc64-gnu": "0.71.0", "@oxfmt/binding-linux-riscv64-gnu": "0.71.0", "@oxfmt/binding-linux-riscv64-musl": "0.71.0", "@oxfmt/binding-linux-s390x-gnu": "0.71.0", "@oxfmt/binding-linux-x64-gnu": "0.71.0", "@oxfmt/binding-linux-x64-musl": "0.71.0", "@oxfmt/binding-openharmony-arm64": "0.71.0", "@oxfmt/binding-win32-arm64-msvc": "0.71.0", "@oxfmt/binding-win32-ia32-msvc": "0.71.0", "@oxfmt/binding-win32-x64-msvc": "0.71.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-lUPUl0d/+Io5pDrsPXWs6rB4N/bpB78oj9CTDpnbulfDz+0r3XXcHPlQ7kRPJ2GjIT4nX+/mcqunOeP9BvsEtg=="], "oxfmt": ["oxfmt@0.71.0", "", { "dependencies": { "tinypool": "2.2.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.71.0", "@oxfmt/binding-android-arm64": "0.71.0", "@oxfmt/binding-darwin-arm64": "0.71.0", "@oxfmt/binding-darwin-x64": "0.71.0", "@oxfmt/binding-freebsd-x64": "0.71.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.71.0", "@oxfmt/binding-linux-arm-musleabihf": "0.71.0", "@oxfmt/binding-linux-arm64-gnu": "0.71.0", "@oxfmt/binding-linux-arm64-musl": "0.71.0", "@oxfmt/binding-linux-ppc64-gnu": "0.71.0", "@oxfmt/binding-linux-riscv64-gnu": "0.71.0", "@oxfmt/binding-linux-riscv64-musl": "0.71.0", "@oxfmt/binding-linux-s390x-gnu": "0.71.0", "@oxfmt/binding-linux-x64-gnu": "0.71.0", "@oxfmt/binding-linux-x64-musl": "0.71.0", "@oxfmt/binding-openharmony-arm64": "0.71.0", "@oxfmt/binding-win32-arm64-msvc": "0.71.0", "@oxfmt/binding-win32-ia32-msvc": "0.71.0", "@oxfmt/binding-win32-x64-msvc": "0.71.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-lUPUl0d/+Io5pDrsPXWs6rB4N/bpB78oj9CTDpnbulfDz+0r3XXcHPlQ7kRPJ2GjIT4nX+/mcqunOeP9BvsEtg=="],
"oxlint": ["oxlint@1.86.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.86.0", "@oxlint/binding-android-arm64": "1.86.0", "@oxlint/binding-darwin-arm64": "1.86.0", "@oxlint/binding-darwin-x64": "1.86.0", "@oxlint/binding-freebsd-x64": "1.86.0", "@oxlint/binding-linux-arm-gnueabihf": "1.86.0", "@oxlint/binding-linux-arm-musleabihf": "1.86.0", "@oxlint/binding-linux-arm64-gnu": "1.86.0", "@oxlint/binding-linux-arm64-musl": "1.86.0", "@oxlint/binding-linux-ppc64-gnu": "1.86.0", "@oxlint/binding-linux-riscv64-gnu": "1.86.0", "@oxlint/binding-linux-riscv64-musl": "1.86.0", "@oxlint/binding-linux-s390x-gnu": "1.86.0", "@oxlint/binding-linux-x64-gnu": "1.86.0", "@oxlint/binding-linux-x64-musl": "1.86.0", "@oxlint/binding-openharmony-arm64": "1.86.0", "@oxlint/binding-win32-arm64-msvc": "1.86.0", "@oxlint/binding-win32-ia32-msvc": "1.86.0", "@oxlint/binding-win32-x64-msvc": "1.86.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2003", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-og0lhgvZfgGF//gOOmZXvtr+GmBbAGEnbEhv/QUg7UW2Wi4wHMnJbnMD+zuHgPdJxdklfgpPupdlAaAySyxrZg=="], "oxlint": ["oxlint@1.86.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.86.0", "@oxlint/binding-android-arm64": "1.86.0", "@oxlint/binding-darwin-arm64": "1.86.0", "@oxlint/binding-darwin-x64": "1.86.0", "@oxlint/binding-freebsd-x64": "1.86.0", "@oxlint/binding-linux-arm-gnueabihf": "1.86.0", "@oxlint/binding-linux-arm-musleabihf": "1.86.0", "@oxlint/binding-linux-arm64-gnu": "1.86.0", "@oxlint/binding-linux-arm64-musl": "1.86.0", "@oxlint/binding-linux-ppc64-gnu": "1.86.0", "@oxlint/binding-linux-riscv64-gnu": "1.86.0", "@oxlint/binding-linux-riscv64-musl": "1.86.0", "@oxlint/binding-linux-s390x-gnu": "1.86.0", "@oxlint/binding-linux-x64-gnu": "1.86.0", "@oxlint/binding-linux-x64-musl": "1.86.0", "@oxlint/binding-openharmony-arm64": "1.86.0", "@oxlint/binding-win32-arm64-msvc": "1.86.0", "@oxlint/binding-win32-ia32-msvc": "1.86.0", "@oxlint/binding-win32-x64-msvc": "1.86.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2003", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-og0lhgvZfgGF//gOOmZXvtr+GmBbAGEnbEhv/QUg7UW2Wi4wHMnJbnMD+zuHgPdJxdklfgpPupdlAaAySyxrZg=="],
"oxlint-tsgolint": ["oxlint-tsgolint@7.0.2004", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "7.0.2004", "@oxlint-tsgolint/darwin-x64": "7.0.2004", "@oxlint-tsgolint/linux-arm64": "7.0.2004", "@oxlint-tsgolint/linux-x64": "7.0.2004", "@oxlint-tsgolint/win32-arm64": "7.0.2004", "@oxlint-tsgolint/win32-x64": "7.0.2004" }, "bin": { "tsgolint": "./bin/tsgolint.js" } }, "sha512-vQ9WDF3fiZJvRdSDosNOflerOCOpwol6vWzVDxW76RcU19cjTh7engvkHLvmv+tzedR8fAiJUVUGr6IVZdkzXQ=="],
"p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], "p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="],
@@ -718,6 +921,8 @@
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
"package-manager-detector": ["package-manager-detector@1.9.0", "", {}, "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA=="],
"pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="], "pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="],
"parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], "parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="],
@@ -750,16 +955,24 @@
"promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="], "promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="],
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
"pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="], "pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="],
"read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="], "read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="],
"rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="],
"redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="], "redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="],
"regexp-tree": ["regexp-tree@0.1.27", "", { "bin": { "regexp-tree": "bin/regexp-tree" } }, "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA=="],
"reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="], "reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="],
"resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], "resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
"run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="],
@@ -768,9 +981,11 @@
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"safe-regex": ["safe-regex@2.1.1", "", { "dependencies": { "regexp-tree": "~0.1.1" } }, "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A=="],
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"seroval": ["seroval@1.5.6", "", {}, "sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA=="], "seroval": ["seroval@1.5.6", "", {}, "sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA=="],
@@ -784,8 +999,12 @@
"sigstore": ["sigstore@4.1.1", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.1.1", "@sigstore/tuf": "^4.0.2", "@sigstore/verify": "^3.1.1" } }, "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w=="], "sigstore": ["sigstore@4.1.1", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.1.1", "@sigstore/tuf": "^4.0.2", "@sigstore/verify": "^3.1.1" } }, "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w=="],
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
"smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
"smol-toml": ["smol-toml@1.9.1", "", {}, "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ=="],
"socks": ["socks@2.8.10", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ=="], "socks": ["socks@2.8.10", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ=="],
"socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
@@ -808,8 +1027,16 @@
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
"strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
"tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], "tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="],
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
@@ -818,12 +1045,18 @@
"treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="],
"tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="],
"tsconfig-paths-webpack-plugin": ["tsconfig-paths-webpack-plugin@4.2.0", "", { "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.7.0", "tapable": "^2.2.1", "tsconfig-paths": "^4.1.2" } }, "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="], "tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="],
"typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="],
"unbash": ["unbash@5.0.0", "", {}, "sha512-RYNm/ISFtflWpIcXTPHHLJZ0mqzInav+L9ke9PcL+hHsSf9+Fd/syPb614Mlqs/O3AYgjnvxDOFl0a+zVqi1/w=="],
"undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="], "undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="],
"undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="], "undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="],
@@ -836,6 +1069,8 @@
"walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="],
"watskeburt": ["watskeburt@6.0.0", "", { "bin": { "watskeburt": "dist/run-cli.js" } }, "sha512-jfiuDABaxSkC71T6oZ3vCS99roYkSHm/+As+G0Dz8taAHQb+SJBvLEm5RlsgG71XdfAj3rv7eudUBTgwcQUPlQ=="],
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
"web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="], "web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="],
@@ -854,32 +1089,28 @@
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
"yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="],
"zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="], "zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="],
"@aws-crypto/sha256-browser/@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=="], "@aws-crypto/sha256-browser/@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=="],
"@aws-crypto/util/@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=="], "@aws-crypto/util/@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=="],
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], "@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"@npmcli/arborist/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"@npmcli/config/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"@npmcli/fs/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"@npmcli/git/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
"@npmcli/metavuln-calculator/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"@npmcli/package-json/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
"@opencode/plugin/zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], "@opencode/plugin/zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
@@ -892,22 +1123,16 @@
"gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], "gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
"global-directory/ini": ["ini@4.1.1", "", {}, "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g=="],
"minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"node-gyp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="], "node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="],
"node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
"npm-install-checks/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"npm-package-arg/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"npm-pick-manifest/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
@@ -920,12 +1145,12 @@
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], "wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
+15
View File
@@ -0,0 +1,15 @@
{
"$schema": "https://unpkg.com/knip@6/schema.json",
"entry": [
"src/agents/agents.ts",
"src/multi-work/multi-work.ts",
"src/quota/quota-plugin.ts",
"src/quota/quota-rpc.ts",
"src/quota/tui.tsx",
"scripts/*.ts",
"tests/**/*.test.ts",
"tests/fixtures/*.ts"
],
"project": ["src/**/*.{ts,tsx}", "scripts/**/*.ts", "tests/**/*.ts"],
"ignoreDependencies": ["@swc/core"]
}
+17 -8
View File
@@ -5,27 +5,27 @@
"type": "module", "type": "module",
"exports": { "exports": {
"./agents": { "./agents": {
"types": "./dist/agents.d.ts", "types": "./dist/agents/agents.d.ts",
"import": "./dist/agents.js" "import": "./dist/agents.js"
}, },
"./multi-work": { "./multi-work": {
"types": "./dist/multi-work.d.ts", "types": "./dist/multi-work/multi-work.d.ts",
"import": "./dist/multi-work.js" "import": "./dist/multi-work.js"
}, },
"./quota": { "./quota": {
"types": "./dist/quota-plugin.d.ts", "types": "./dist/quota/quota-plugin.d.ts",
"import": "./dist/quota-plugin.js" "import": "./dist/quota-plugin.js"
}, },
"./tui": { "./tui": {
"types": "./dist/tui.d.ts", "types": "./dist/quota/tui.d.ts",
"import": "./dist/tui.js" "import": "./dist/tui.js"
}, },
"./quota/tui": { "./quota/tui": {
"types": "./dist/tui.d.ts", "types": "./dist/quota/tui.d.ts",
"import": "./dist/tui.js" "import": "./dist/tui.js"
}, },
"./quota-rpc": { "./quota-rpc": {
"types": "./dist/quota-rpc.d.ts", "types": "./dist/quota/quota-rpc.d.ts",
"import": "./dist/quota-rpc.js" "import": "./dist/quota-rpc.js"
} }
}, },
@@ -39,11 +39,15 @@
}, },
"scripts": { "scripts": {
"check": "tsc --noEmit", "check": "tsc --noEmit",
"lint": "oxlint --deny-warnings .", "lint": "oxlint --type-aware --deny-warnings .",
"format": "oxfmt --write .", "format": "oxfmt --write .",
"format:check": "oxfmt --check .", "format:check": "oxfmt --check .",
"test": "bun test --conditions=browser", "test": "bun test --conditions=browser",
"build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly" "build": "bun scripts/build.ts && tsc --project tsconfig.build.json --emitDeclarationOnly",
"knip": "knip",
"duplicates": "jscpd",
"deps": "depcruise src scripts tests",
"verify": "bun run lint && bun run check && bun run knip && bun run duplicates && bun run deps && bun run format:check && bun run test"
}, },
"devDependencies": { "devDependencies": {
"@opencode/client": "2.0.22", "@opencode/client": "2.0.22",
@@ -52,9 +56,14 @@
"@opentui/core": "0.5.14", "@opentui/core": "0.5.14",
"@opentui/solid": "0.5.14", "@opentui/solid": "0.5.14",
"@oxlint/plugins": "1.86.0", "@oxlint/plugins": "1.86.0",
"@swc/core": "1.16.13",
"@types/bun": "1.4.2", "@types/bun": "1.4.2",
"dependency-cruiser": "18.5.0",
"jscpd": "5.4.1",
"knip": "6.41.0",
"oxfmt": "0.71.0", "oxfmt": "0.71.0",
"oxlint": "1.86.0", "oxlint": "1.86.0",
"oxlint-tsgolint": "7.0.2004",
"solid-js": "1.9.15", "solid-js": "1.9.15",
"typescript": "7.0.2" "typescript": "7.0.2"
}, },
+8 -5
View File
@@ -7,24 +7,27 @@ export async function build() {
const results = await Promise.all([ const results = await Promise.all([
Bun.build({ Bun.build({
entrypoints: [ entrypoints: [
"src/agents.ts", "src/agents/agents.ts",
"src/multi-work.ts", "src/multi-work/multi-work.ts",
"src/quota-plugin.ts", "src/quota/quota-plugin.ts",
"src/quota-rpc.ts", "src/quota/quota-rpc.ts",
], ],
outdir: "dist", outdir: "dist",
naming: "[name].[ext]",
target: "bun", target: "bun",
format: "esm", format: "esm",
}), }),
Bun.build({ Bun.build({
entrypoints: ["scripts/install.ts"], entrypoints: ["scripts/install.ts"],
outdir: "dist", outdir: "dist",
naming: "[name].[ext]",
target: "bun", target: "bun",
format: "esm", format: "esm",
}), }),
Bun.build({ Bun.build({
entrypoints: ["src/tui.tsx"], entrypoints: ["src/quota/tui.tsx"],
outdir: "dist", outdir: "dist",
naming: "[name].[ext]",
target: "bun", target: "bun",
format: "esm", format: "esm",
external: ["@opencode/plugin/tui", "@opentui/solid", "solid-js"], external: ["@opencode/plugin/tui", "@opentui/solid", "solid-js"],
+115 -102
View File
@@ -50,126 +50,45 @@ const nativePlugin = z.union([
z.object({ id: z.string(), effect: z.function() }), z.object({ id: z.string(), effect: z.function() }),
]); ]);
type DirectoryExports = { ".": string; "./tui"?: string }; type DirectoryExports = { ".": string; "./tui"?: string };
type Name = (typeof names)[number];
export async function install(source: string, config: string, selection?: string) { async function prompt(retained: Name[]) {
const absoluteBase = join(config, "plugins", "stanp-opencode");
const monolith = (target: string) =>
target === base || target === absoluteBase || /^stanp-opencode(?:@[^/]+)?$/.test(target);
const owned = new Set(
names.flatMap((name) => [
`${base}/${name}`,
`${absoluteBase}/${name}`,
`stanp-opencode/${name}`,
]),
);
const isOwned = (target: string) => monolith(target) || owned.has(target);
const configFile = join(config, "opencode.json");
const current = configSchema.parse(
(await Bun.file(configFile).exists()) ? await Bun.file(configFile).json() : {},
);
const entries = current.plugins ?? [];
// Normalize only the lookup view; unrelated entries retain their original representation.
const configured = entries.map((entry) => registrationSchema.parse(entry));
const previous = configured.filter((entry) => isOwned(entry.package));
const oldMonolith = previous.some((entry) => monolith(entry.package));
const retained = oldMonolith
? [...names]
: names.filter((name) =>
previous.some(
(entry) =>
entry.package === `${base}/${name}` ||
entry.package === `${absoluteBase}/${name}` ||
entry.package === `stanp-opencode/${name}`,
),
);
let chosen: string[];
if (selection !== undefined) chosen = selection.split(",");
else if (process.stdin.isTTY) {
const input = createInterface({ input: process.stdin, output: process.stdout }); const input = createInterface({ input: process.stdin, output: process.stdout });
try { try {
const defaults = retained.length ? retained : names; const defaults = retained.length > 0 ? retained : names;
chosen = ( const chosen = (
( (
await input.question( await input.question(`Plugins (agents,multi-work,quota) [${defaults.join(",")}]: `)
`Plugins (agents,multi-work,quota) [${defaults.join(",")}]: `,
)
).trim() || defaults.join(",") ).trim() || defaults.join(",")
).split(","); ).split(",");
if (chosen.includes("multi-work") && !chosen.includes("agents")) {
if ( if (
/^(y|yes)?$/i.test( chosen.includes("multi-work") &&
( !chosen.includes("agents") &&
await input.question("Multi-work requires Agents. Add Agents? [Y/n]: ") /^(y|yes)?$/iu.test(
).trim(), (await input.question("Multi-work requires Agents. Add Agents? [Y/n]: ")).trim(),
) )
) )
chosen.push("agents"); chosen.push("agents");
} return chosen;
} finally { } finally {
input.close(); input.close();
} }
} else { }
if (!retained.length)
async function choose(retained: Name[], selection?: string) {
if (selection !== undefined) return selection.split(",");
if (process.stdin.isTTY) return prompt(retained);
if (retained.length === 0)
throw new Error( throw new Error(
"Noninteractive installation requires --plugins agents,multi-work,quota (or a valid subset)", "Noninteractive installation requires --plugins agents,multi-work,quota (or a valid subset)",
); );
chosen = [...retained]; return [...retained];
} }
if (
!z.array(z.enum(names)).min(1).safeParse(chosen).success || async function stage(source: string, staged: string, name: Name) {
new Set(chosen).size !== chosen.length
)
throw new Error("Invalid --plugins selection; use unique names: agents,multi-work,quota");
if (chosen.includes("multi-work") && !chosen.includes("agents"))
throw new Error("Multi-work requires Agents; select agents,multi-work");
const selected = names.filter((name) => chosen.includes(name));
const registrations: Entry[] = selected.map((name) => {
const prior = previous.find(
(entry) =>
entry.package === `${base}/${name}` ||
entry.package === `${absoluteBase}/${name}` ||
entry.package === `stanp-opencode/${name}` ||
(name === "agents" && monolith(entry.package)),
);
const options: NonNullable<Entry["options"]> = {};
Object.assign(options, prior?.options);
delete options.playwright;
fill(options, skeleton(name));
const entry = entrySchema.parse({ ...prior, package: `${base}/${name}` });
delete entry.options;
if (Object.keys(options).length) entry.options = options;
return entry;
});
const first = configured.findIndex((entry) => isOwned(entry.package));
const next = entries.filter((_entry, index) => !isOwned(configured[index]!.package));
next.splice(first < 0 ? next.length : first, 0, ...registrations);
const updated: z.infer<typeof configSchema> = {
...current,
$schema: current.$schema ?? "https://opencode.ai/config.json",
plugins: next,
};
// Coordinate delegates to workers from Multi-work children, so routing needs depth >= 2.
const experimental = experimentalSchema.safeParse(current.experimental ?? {});
if (selected.includes("agents") && experimental.success)
updated.experimental = {
...experimental.data,
subagent_depth: Math.max(experimental.data.subagent_depth ?? 0, 2),
};
const parent = join(config, "plugins");
await mkdir(parent, { recursive: true });
const staged = join(parent, `.stanp-opencode.new.${process.pid}`);
const backup = join(parent, `.stanp-opencode.old.${process.pid}`);
const target = join(parent, "stanp-opencode");
const configStage = join(config, `.stanp-opencode.config.${process.pid}`);
let saved = false;
let activated = false;
try {
await mkdir(staged);
for (const name of selected) {
const file = name === "quota" ? "quota-plugin" : name; const file = name === "quota" ? "quota-plugin" : name;
const entrypoint = join(source, "dist", `${file}.js`); const entrypoint = join(source, "dist", `${file}.js`);
const { default: definition } = await import(entrypoint); const { default: plugin } = z.object({ default: nativePlugin }).parse(await import(entrypoint));
const plugin = nativePlugin.parse(definition);
if (plugin.id !== `stanp-opencode.${name}`) if (plugin.id !== `stanp-opencode.${name}`)
throw new Error(`Invalid native OpenCode plugin: ${name}`); throw new Error(`Invalid native OpenCode plugin: ${name}`);
const directory = join(staged, name); const directory = join(staged, name);
@@ -197,6 +116,25 @@ export async function install(source: string, config: string, selection?: string
}), }),
); );
} }
async function activate(
source: string,
config: string,
selected: Name[],
updated: z.infer<typeof configSchema>,
) {
const configFile = join(config, "opencode.json");
const parent = join(config, "plugins");
await mkdir(parent, { recursive: true });
const staged = join(parent, `.stanp-opencode.new.${process.pid}`);
const backup = join(parent, `.stanp-opencode.old.${process.pid}`);
const target = join(parent, "stanp-opencode");
const configStage = join(config, `.stanp-opencode.config.${process.pid}`);
let saved = false;
let activated = false;
try {
await mkdir(staged);
for (const name of selected) await stage(source, staged, name);
await Bun.write(configStage, JSON.stringify(updated, null, 4) + "\n"); await Bun.write(configStage, JSON.stringify(updated, null, 4) + "\n");
try { try {
await rename(target, backup); await rename(target, backup);
@@ -218,6 +156,80 @@ export async function install(source: string, config: string, selection?: string
} }
if (saved) await rm(backup, { recursive: true, force: true }); if (saved) await rm(backup, { recursive: true, force: true });
await rm(join(parent, "stanp-opencode.js"), { force: true }); await rm(join(parent, "stanp-opencode.js"), { force: true });
}
export async function install(source: string, config: string, selection?: string) {
const absoluteBase = join(config, "plugins", "stanp-opencode");
const monolith = (target: string) =>
target === base || target === absoluteBase || /^stanp-opencode(?:@[^/]+)?$/u.test(target);
const owned = new Set(
names.flatMap((name) => [
`${base}/${name}`,
`${absoluteBase}/${name}`,
`stanp-opencode/${name}`,
]),
);
const isOwned = (target: string) => monolith(target) || owned.has(target);
const configFile = join(config, "opencode.json");
const current = configSchema.parse(
(await Bun.file(configFile).exists()) ? await Bun.file(configFile).json() : {},
);
const entries = current.plugins ?? [];
// Normalize only the lookup view; unrelated entries retain their original representation.
const configured = entries.map((entry) => registrationSchema.parse(entry));
const previous = configured.filter((entry) => isOwned(entry.package));
const oldMonolith = previous.some((entry) => monolith(entry.package));
const retained = oldMonolith
? [...names]
: names.filter((name) =>
previous.some(
(entry) =>
entry.package === `${base}/${name}` ||
entry.package === `${absoluteBase}/${name}` ||
entry.package === `stanp-opencode/${name}`,
),
);
const chosen = await choose(retained, selection);
if (
!z.array(z.enum(names)).min(1).safeParse(chosen).success ||
new Set(chosen).size !== chosen.length
)
throw new Error("Invalid --plugins selection; use unique names: agents,multi-work,quota");
if (chosen.includes("multi-work") && !chosen.includes("agents"))
throw new Error("Multi-work requires Agents; select agents,multi-work");
const selected = names.filter((name) => chosen.includes(name));
const registrations: Entry[] = selected.map((name) => {
const prior = previous.find(
(entry) =>
entry.package === `${base}/${name}` ||
entry.package === `${absoluteBase}/${name}` ||
entry.package === `stanp-opencode/${name}` ||
(name === "agents" && monolith(entry.package)),
);
const options: NonNullable<Entry["options"]> = { ...prior?.options };
delete options["playwright"];
fill(options, skeleton(name));
const entry = entrySchema.parse({ ...prior, package: `${base}/${name}` });
delete entry.options;
if (Object.keys(options).length > 0) entry.options = options;
return entry;
});
const first = configured.findIndex((entry) => isOwned(entry.package));
const next = entries.filter((_entry, index) => !isOwned(configured[index]?.package ?? ""));
next.splice(first < 0 ? next.length : first, 0, ...registrations);
const updated: z.infer<typeof configSchema> = {
...current,
$schema: current.$schema ?? "https://opencode.ai/config.json",
plugins: next,
};
// Coordinate delegates to workers from Multi-work children, so routing needs depth >= 2.
const experimental = experimentalSchema.safeParse(current["experimental"] ?? {});
if (selected.includes("agents") && experimental.success)
updated["experimental"] = {
...experimental.data,
subagent_depth: Math.max(experimental.data.subagent_depth ?? 0, 2),
};
await activate(source, config, selected, updated);
console.log(`Installed ${selected.join(", ")}. Restart OpenCode.`); console.log(`Installed ${selected.join(", ")}. Restart OpenCode.`);
if (oldMonolith) if (oldMonolith)
console.log( console.log(
@@ -227,6 +239,7 @@ export async function install(source: string, config: string, selection?: string
if (import.meta.main) { if (import.meta.main) {
const [source, config, selection] = process.argv.slice(2); const [source, config, selection] = process.argv.slice(2);
if (!source || !config) throw new Error("Expected package directory and config directory"); if (source === undefined || source === "" || config === undefined || config === "")
throw new Error("Expected package directory and config directory");
await install(source, config, selection); await install(source, config, selection);
} }
+50 -39
View File
@@ -5,17 +5,18 @@ import { tmpdir } from "node:os";
import { join, resolve } from "node:path"; import { join, resolve } from "node:path";
import { createServer } from "node:net"; import { createServer } from "node:net";
import { OpenCode } from "@opencode/client"; import { OpenCode } from "@opencode/client";
import { command } from "../src/herdr.js"; import { command } from "../src/multi-work/herdr.js";
import { z } from "zod"; import { z } from "zod";
const binary = process.env.OPENCODE_2022; const binary = process.env["OPENCODE_2022"];
if (!binary) throw new Error("Set OPENCODE_2022 to an isolated OpenCode 2.0.22 binary"); if (binary === undefined || binary === "")
throw new Error("Set OPENCODE_2022 to an isolated OpenCode 2.0.22 binary");
const temp = await mkdtemp(join(tmpdir(), "native-multi-work-")); const temp = await mkdtemp(join(tmpdir(), "native-multi-work-"));
try { try {
const root = join(temp, "root"), const root = join(temp, "root");
destination = join(temp, "child"), const destination = join(temp, "child");
bin = join(temp, "bin"), const bin = join(temp, "bin");
config = join(temp, "config"); const config = join(temp, "config");
const herdrCreation = join(temp, "herdr-creation.txt"); const herdrCreation = join(temp, "herdr-creation.txt");
for (const path of [root, bin, config, join(temp, "plugin")]) await mkdir(path); for (const path of [root, bin, config, join(temp, "plugin")]) await mkdir(path);
const signal = AbortSignal.timeout(120_000); const signal = AbortSignal.timeout(120_000);
@@ -82,7 +83,7 @@ try {
target: "bun", target: "bun",
format: "esm", format: "esm",
}); });
if (!built.success) throw new Error(String(built.logs)); if (!built.success) throw new Error(built.logs.map((log) => log.message).join(","));
} }
await writeFile( await writeFile(
join(config, "opencode.json"), join(config, "opencode.json"),
@@ -134,12 +135,18 @@ try {
}, },
}); });
const socket = createServer(); const socket = createServer();
await new Promise<void>((done) => socket.listen(0, "127.0.0.1", done)); await new Promise<void>((done) => {
socket.listen(0, "127.0.0.1", done);
});
const { port } = z.object({ port: z.number() }).parse(socket.address()); const { port } = z.object({ port: z.number() }).parse(socket.address());
await new Promise<void>((done) => socket.close(() => done())); await new Promise<void>((done) => {
socket.close(() => {
done();
});
});
// Do not inherit user credentials, discovery URLs, Herdr identity, or config overrides. // Do not inherit user credentials, discovery URLs, Herdr identity, or config overrides.
const env = { const env = {
PATH: `${bin}:${process.env.PATH}`, PATH: `${bin}:${process.env["PATH"]}`,
HOME: join(temp, "home"), HOME: join(temp, "home"),
XDG_CONFIG_HOME: config, XDG_CONFIG_HOME: config,
XDG_DATA_HOME: join(temp, "data"), XDG_DATA_HOME: join(temp, "data"),
@@ -160,13 +167,13 @@ try {
let server = start(); let server = start();
const headers = { authorization: "" }; const headers = { authorization: "" };
const client = OpenCode.make({ baseUrl: `http://127.0.0.1:${port}`, headers }); const client = OpenCode.make({ baseUrl: `http://127.0.0.1:${port}`, headers });
async function ready() { const ready = async () => {
for (let attempt = 0; attempt < 200; attempt++) { for (let attempt = 0; attempt < 200; attempt++) {
try { try {
const password = (await readFile(join(temp, "server.log"), "utf8")).match( const password = (await readFile(join(temp, "server.log"), "utf8")).match(
/server password (\S+)/, /server password (\S+)/u,
)?.[1]; )?.[1];
if (password) if (password !== undefined)
headers.authorization = `Basic ${Buffer.from(`opencode:${password}`).toString("base64")}`; headers.authorization = `Basic ${Buffer.from(`opencode:${password}`).toString("base64")}`;
await client.server.info(); await client.server.info();
return; return;
@@ -177,7 +184,7 @@ try {
throw new Error( throw new Error(
`Host did not start: ${await readFile(join(temp, "server-errors.log"), "utf8")}`, `Host did not start: ${await readFile(join(temp, "server-errors.log"), "utf8")}`,
); );
} };
try { try {
await ready(); await ready();
const location = { directory: root }; const location = { directory: root };
@@ -228,7 +235,7 @@ try {
(await readFile(env.FIXTURE_TRACE, "utf8")) (await readFile(env.FIXTURE_TRACE, "utf8"))
.trim() .trim()
.split("\n") .split("\n")
.map((line) => JSON.parse(line)), .map((line) => z.json().parse(JSON.parse(line))),
); );
if ( if (
!admission.some((entry) => entry.id === child.id && entry.directory === destination) || !admission.some((entry) => entry.id === child.id && entry.directory === destination) ||
@@ -305,21 +312,21 @@ try {
pending.then(() => { pending.then(() => {
throw new Error("Foreground unexpectedly finished before cancellation"); throw new Error("Foreground unexpectedly finished before cancellation");
}), }),
new Promise<never>((_resolve, reject) => new Promise<never>((_resolve, reject) => {
deadline.addEventListener( deadline.addEventListener(
"abort", "abort",
() => reject(new Error("Model was not reached")), () => {
{ reject(new Error("Model was not reached"));
once: true,
}, },
), { once: true },
), );
}),
]); ]);
cancel.abort(); cancel.abort();
let rejected = false; const rejected = await pending.then(
await pending.catch(() => { () => false,
rejected = true; () => true,
}); );
if (!rejected) throw new Error("Cancelled RPC did not reject"); if (!rejected) throw new Error("Cancelled RPC did not reject");
for (let attempt = 0; attempt < 100; attempt++) { for (let attempt = 0; attempt < 100; attempt++) {
if ((await client.session.get({ sessionID: child.id })).outcome === "interrupted") if ((await client.session.get({ sessionID: child.id })).outcome === "interrupted")
@@ -329,6 +336,18 @@ try {
} }
releaseModel.resolve(); releaseModel.resolve();
holdModel = false; holdModel = false;
const multiWorkFailed = async () => {
for (let attempt = 0; attempt < 100; attempt++) {
const { data } = await client.plugin.list({ location });
const multi = data.find((plugin) => plugin.id === "stanp-opencode.multi-work");
if (multi?.state.status === "failed") return;
if (attempt === 99 || multi?.state.status === "active")
throw new Error(
`Missing or late Agents did not fail Multi-work activation: ${JSON.stringify(data)}`,
);
await Bun.sleep(100);
}
};
for (const plugins of [ for (const plugins of [
[{ package: join(temp, "plugin", "multi-work") }], [{ package: join(temp, "plugin", "multi-work") }],
[ [
@@ -344,27 +363,19 @@ try {
); );
server = start(); server = start();
await ready(); await ready();
for (let attempt = 0; attempt < 100; attempt++) { await multiWorkFailed();
const { data } = await client.plugin.list({ location });
const multi = data.find((plugin) => plugin.id === "stanp-opencode.multi-work");
if (multi?.state.status === "failed") break;
if (attempt === 99 || multi?.state.status === "active")
throw new Error(
`Missing or late Agents did not fail Multi-work activation: ${JSON.stringify(data)}`,
);
await Bun.sleep(100);
}
} }
server.kill(); server.kill();
await server.exited; await server.exited;
const quotaBuild = await Bun.build({ const quotaBuild = await Bun.build({
entrypoints: [resolve("src/quota-plugin.ts")], entrypoints: [resolve("src/quota/quota-plugin.ts")],
outdir: join(temp, "plugin", "quota"), outdir: join(temp, "plugin", "quota"),
naming: "index.js", naming: "index.js",
target: "bun", target: "bun",
format: "esm", format: "esm",
}); });
if (!quotaBuild.success) throw new Error(String(quotaBuild.logs)); if (!quotaBuild.success)
throw new Error(quotaBuild.logs.map((log) => log.message).join(","));
await writeFile( await writeFile(
join(config, "opencode.json"), join(config, "opencode.json"),
JSON.stringify({ JSON.stringify({
@@ -409,7 +420,7 @@ try {
releaseModel.resolve(); releaseModel.resolve();
server.kill(); server.kill();
await server.exited; await server.exited;
model.stop(true); void model.stop(true);
} }
} finally { } finally {
await rm(temp, { recursive: true, force: true }); await rm(temp, { recursive: true, force: true });
+63 -63
View File
@@ -1,4 +1,5 @@
import { Agent, Model, Plugin, Provider } from "@opencode/plugin"; import { Agent, Model, Plugin, Provider } from "@opencode/plugin";
import type { DeepMutable } from "@opencode/plugin/promise/types";
import type { ModelInfo } from "@opencode/client"; import type { ModelInfo } from "@opencode/client";
import { z } from "zod"; import { z } from "zod";
import { settings, workerNames } from "./config.js"; import { settings, workerNames } from "./config.js";
@@ -7,18 +8,38 @@ import { discover, modelKey } from "./provider.js";
import { descriptions, routingGuide } from "./routing.js"; import { descriptions, routingGuide } from "./routing.js";
import { Skill } from "@opencode/schema/skill"; import { Skill } from "@opencode/schema/skill";
import { AbsolutePath } from "@opencode/schema/schema"; import { AbsolutePath } from "@opencode/schema/schema";
import { fileURLToPath } from "node:url"; import antiOverengineering from "../skills/anti-overengineering.md" with { type: "text" };
import antiOverengineering from "./anti-overengineering.md" with { type: "text" }; import taskPlanning from "../skills/task-planning.md" with { type: "text" };
import taskPlanning from "./task-planning.md" with { type: "text" };
import { AgentsRpc } from "./agents-rpc.js"; import { AgentsRpc } from "./agents-rpc.js";
import { matches } from "./wildcard.js";
// Permission actions use wildcards, not filesystem globs. // Assignments use "" as unset.
function matches(value: string, pattern: string) { function assigned(value: string | undefined): value is string {
const escaped = pattern return value !== undefined && value !== "";
.replace(/[.+^${}()|[\]\\]/g, "\\$&") }
.replace(/\*/g, ".*")
.replace(/\?/g, "."); /** Points the agent at the available model, using the variant or a reasoning-effort fallback. */
return new RegExp(`^${escaped}$`, "s").test(value); function useModel(
agent: DeepMutable<Agent.Info>,
assignment: ReturnType<typeof model>,
available: ModelInfo,
) {
const hasVariant =
assignment.variant !== undefined &&
available.variants.some(({ id }) => id === assignment.variant);
agent.model = {
providerID: Provider.ID.make(available.providerID),
id: Model.ID.make(available.id),
};
if (hasVariant) agent.model.variant = Model.VariantID.make(assignment.variant);
agent.request = {
settings:
hasVariant || assignment.variant === undefined
? {}
: { reasoningEffort: assignment.variant },
headers: {},
body: {},
};
} }
const reading = [ const reading = [
@@ -40,12 +61,12 @@ export default Plugin.define({
id: "stanp-opencode.agents", id: "stanp-opencode.agents",
async setup(context) { async setup(context) {
const { agents } = settings.parse(context.options); const { agents } = settings.parse(context.options);
if (!workerNames.some((name) => agents?.[name])) return; if (!workerNames.some((name) => assigned(agents?.[name]))) return;
const assignments: Partial<Record<(typeof workerNames)[number], ReturnType<typeof model>>> = const assignments: Partial<Record<(typeof workerNames)[number], ReturnType<typeof model>>> =
{}; {};
for (const name of workerNames) { for (const name of workerNames) {
const reference = agents?.[name]; const reference = agents?.[name];
if (reference) assignments[name] = model(reference, `agents ${name}`); if (assigned(reference)) assignments[name] = model(reference, `agents ${name}`);
else if (!name.startsWith("deep-")) throw new Error(`agents ${name} is required`); else if (!name.startsWith("deep-")) throw new Error(`agents ${name} is required`);
} }
let models = new Map<string, ModelInfo>(); let models = new Map<string, ModelInfo>();
@@ -106,13 +127,14 @@ export default Plugin.define({
["task-planning", taskPlanning], ["task-planning", taskPlanning],
] as const) { ] as const) {
if (editor.get(name)) continue; if (editor.get(name)) continue;
const description = content.match(/^description: "?(.+?)"?$/m)?.[1]; const description = content.match(/^description: "?(.+?)"?$/mu)?.[1];
if (!description) throw new Error(`${name} skill has no description`); if (description === undefined || description === "")
throw new Error(`${name} skill has no description`);
editor.add({ editor.add({
id: Skill.ID.make(name), id: Skill.ID.make(name),
name: Skill.Name.make(name), name: Skill.Name.make(name),
description, description,
path: AbsolutePath.make(fileURLToPath(import.meta.url)), path: AbsolutePath.make(import.meta.filename),
content, content,
}); });
} }
@@ -123,22 +145,20 @@ export default Plugin.define({
.list() .list()
.map((tool) => tool.id) .map((tool) => tool.id)
.filter((id) => id.startsWith("codegraph_")) .filter((id) => id.startsWith("codegraph_"))
.sort(); .toSorted();
if (JSON.stringify(next) === JSON.stringify(codegraphTools)) return; if (JSON.stringify(next) === JSON.stringify(codegraphTools)) return;
codegraphTools = next; codegraphTools = next;
if (agentTransformReady) if (agentTransformReady)
queueMicrotask(() => { queueMicrotask(() => {
void context.agent void context.agent.reload().catch((error) => {
.reload() console.error("stanp-opencode agent reload failed", error);
.catch((error) => });
console.error("stanp-opencode agent reload failed", error),
);
}); });
}); });
await context.agent.transform((editor) => {
const availableFor = (assignment: { providerID: string; id: string }) => const availableFor = (assignment: { providerID: string; id: string }) =>
models.get(modelKey(assignment.providerID, assignment.id)); models.get(modelKey(assignment.providerID, assignment.id));
await context.agent.transform((editor) => {
const deepLo = assignments["deep-lo"]; const deepLo = assignments["deep-lo"];
const deep = const deep =
deepLo !== undefined && deepLo !== undefined &&
@@ -154,59 +174,37 @@ export default Plugin.define({
active.clear(); active.clear();
for (const name of workers) active.add(name); for (const name of workers) active.add(name);
if (workers.length === 0 || coordinate === undefined) return; if (workers.length === 0 || coordinate === undefined) return;
for (const name of workers) { const configureWorker = (
const assignment = assignments[name]!; name: (typeof workerNames)[number],
const available = availableFor(assignment)!; assignment: ReturnType<typeof model>,
available: ModelInfo,
) => {
editor.update(name, (agent) => { editor.update(name, (agent) => {
const hasVariant =
assignment.variant !== undefined &&
available.variants.some(({ id }) => id === assignment.variant);
agent.name = Agent.Name.make(name); agent.name = Agent.Name.make(name);
agent.mode = "subagent"; agent.mode = "subagent";
agent.hidden = false; agent.hidden = false;
agent.description = descriptions[name]; agent.description = descriptions[name];
agent.model = { useModel(agent, assignment, available);
providerID: Provider.ID.make(available.providerID),
id: Model.ID.make(available.id),
};
if (hasVariant) agent.model.variant = Model.VariantID.make(assignment.variant!);
agent.request = {
settings:
hasVariant || assignment.variant === undefined
? {}
: { reasoningEffort: assignment.variant },
headers: {},
body: {},
};
agent.permissions = [ agent.permissions = [
...structuredClone(inherited), ...structuredClone(inherited),
{ action: "subagent", resource: "*", effect: "deny" }, { action: "subagent", resource: "*", effect: "deny" },
]; ];
}); });
};
for (const name of workers) {
const assignment = assignments[name];
const available = assignment && availableFor(assignment);
if (assignment && available) configureWorker(name, assignment, available);
} }
const available = availableFor(coordinate);
if (!available) return;
editor.update("coordinate", (agent) => { editor.update("coordinate", (agent) => {
const available = availableFor(coordinate)!;
const hasVariant =
coordinate.variant !== undefined &&
available.variants.some(({ id }) => id === coordinate.variant);
agent.name = Agent.Name.make("coordinate"); agent.name = Agent.Name.make("coordinate");
agent.mode = "primary"; agent.mode = "primary";
agent.hidden = false; agent.hidden = false;
agent.description = agent.description =
"Read, plan, and coordinate specialist workers; never implement directly."; "Read, plan, and coordinate specialist workers; never implement directly.";
agent.model = { useModel(agent, coordinate, available);
providerID: Provider.ID.make(available.providerID),
id: Model.ID.make(available.id),
};
if (hasVariant) agent.model.variant = Model.VariantID.make(coordinate.variant!);
agent.request = {
settings:
hasVariant || coordinate.variant === undefined
? {}
: { reasoningEffort: coordinate.variant },
headers: {},
body: {},
};
agent.system = routingGuide(deep); agent.system = routingGuide(deep);
agent.permissions = [ agent.permissions = [
{ action: "*", resource: "*", effect: "deny" }, { action: "*", resource: "*", effect: "deny" },
@@ -242,18 +240,20 @@ export default Plugin.define({
} }
await context.session.hook("context", (event) => { await context.session.hook("context", (event) => {
if (workerNames.some((name) => name === event.agent)) { if (workerNames.some((name) => name === event.agent)) {
delete event.tools.subagent; delete event.tools["subagent"];
return; return;
} }
const tool = event.tools.subagent; const tool = event.tools["subagent"];
if (event.agent === "coordinate" && workers.length === 0) { if (event.agent === "coordinate" && workers.length === 0) {
delete event.tools.subagent; delete event.tools["subagent"];
return; return;
} }
if (event.agent !== "coordinate" || !tool) return; if (event.agent !== "coordinate" || !tool) return;
tool.description = `Delegate a self-contained assignment to one of these workers:\n${workers.map((name) => `- ${name}: ${descriptions[name]}`).join("\n")}`; tool.description = `Delegate a self-contained assignment to one of these workers:\n${workers.map((name) => `- ${name}: ${descriptions[name]}`).join("\n")}`;
// The executable definition remains native; constrain only this request's schema. // The executable definition remains native; constrain only this request's schema.
const properties = z.record(z.string(), z.unknown()).parse(tool.input.properties ?? {}); const properties = z
.record(z.string(), z.unknown())
.parse(tool.input["properties"] ?? {});
tool.input = { tool.input = {
...tool.input, ...tool.input,
properties: { ...properties, agent: { type: "string", enum: workers } }, properties: { ...properties, agent: { type: "string", enum: workers } },
@@ -273,7 +273,7 @@ export default Plugin.define({
// Commands can create child sessions without going through the subagent tool. // Commands can create child sessions without going through the subagent tool.
await context.session.hook("prompt", async (event) => { await context.session.hook("prompt", async (event) => {
const child = await context.session.get({ sessionID: event.sessionID }); const child = await context.session.get({ sessionID: event.sessionID });
if (!child.parentID) return; if (child.parentID === undefined || child.parentID === "") return;
const parent = await context.session.get({ sessionID: child.parentID }); const parent = await context.session.get({ sessionID: child.parentID });
if (child.agent === "coordinate" && parent.agent !== "multi-work") if (child.agent === "coordinate" && parent.agent !== "multi-work")
throw new Error("coordinate cannot run as a subagent without Multi-work"); throw new Error("coordinate cannot run as a subagent without Multi-work");
+3 -1
View File
@@ -5,5 +5,7 @@ export function model(reference: string, name: string) {
if (slash <= 0) throw new Error(`${name} must be provider/model[#variant]: ${reference}`); if (slash <= 0) throw new Error(`${name} must be provider/model[#variant]: ${reference}`);
const providerID = path.slice(0, slash); const providerID = path.slice(0, slash);
const id = path.slice(slash + 1); const id = path.slice(slash + 1);
return variant ? { providerID, id, variant } : { providerID, id }; return variant !== undefined && variant !== ""
? { providerID, id, variant }
: { providerID, id };
} }
+8
View File
@@ -0,0 +1,8 @@
// Permission actions use wildcards, not filesystem globs.
export function matches(value: string, pattern: string) {
const escaped = pattern
.replaceAll(/[.+^${}()|[\]\\]/gu, "\\$&")
.replaceAll("*", ".*")
.replaceAll("?", ".");
return new RegExp(`^${escaped}$`, "su").test(value);
}
+5 -3
View File
@@ -3,13 +3,15 @@ import { realpath } from "node:fs/promises";
import { z } from "zod"; import { z } from "zod";
export async function command(args: string[], cwd: string, signal: AbortSignal) { export async function command(args: string[], cwd: string, signal: AbortSignal) {
const [file, ...rest] = args;
if (file === undefined) throw new Error("Missing command");
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
execFile( execFile(
args[0]!, file,
args.slice(1), rest,
{ cwd, signal, timeout: 30_000, maxBuffer: 2_000_000 }, { cwd, signal, timeout: 30_000, maxBuffer: 2_000_000 },
(error, stdout, stderr) => { (error, stdout, stderr) => {
if (error) reject(new Error(`${args[0]} failed: ${stderr || error.message}`)); if (error) reject(new Error(`${file} failed: ${stderr || error.message}`));
else resolve(stdout.trim()); else resolve(stdout.trim());
}, },
); );
@@ -4,12 +4,13 @@ import { Session } from "@opencode/schema/session";
import { AbsolutePath } from "@opencode/schema/schema"; import { AbsolutePath } from "@opencode/schema/schema";
import type { Context } from "@opencode/plugin/effect/plugin"; import type { Context } from "@opencode/plugin/effect/plugin";
import { Plugin } from "@opencode/plugin/effect"; import { Plugin } from "@opencode/plugin/effect";
import { AgentsRpc } from "./agents-rpc.js"; import { AgentsRpc } from "../agents/agents-rpc.js";
import { Cause, Effect, Schedule, Stream } from "effect"; import { Cause, Effect, Schedule, Stream } from "effect";
import { z } from "zod"; import { z } from "zod";
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { Herdr, rootSchema } from "./herdr.js"; import { Herdr, rootSchema } from "./herdr.js";
import { multiWorkGuide } from "./routing.js"; import { multiWorkGuide } from "../agents/routing.js";
import { matches } from "../agents/wildcard.js";
export const bindingSchema = z export const bindingSchema = z
.object({ .object({
@@ -62,14 +63,8 @@ const readTools = new Set([
export const childProtocol = export const childProtocol =
"Bound child sessions use stanp-opencode multi-work protocol 1 and must remain in their assigned worktree."; "Bound child sessions use stanp-opencode multi-work protocol 1 and must remain in their assigned worktree.";
function matches(value: string, pattern: string) { function present(value: string | undefined): value is string {
return new RegExp( return value !== undefined && value !== "";
`^${pattern
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
.replace(/\*/g, ".*")
.replace(/\?/g, ".")}$`,
"s",
).test(value);
} }
export const installMultiWork = ( export const installMultiWork = (
@@ -158,6 +153,20 @@ export const installMultiWork = (
return binding; return binding;
}); });
const verifyLocalChild = (
sessionID: Session.ID,
parent: { id: string; location: { directory: string } },
) =>
Effect.gen(function* () {
const child = yield* context.session.get({ sessionID });
if (
child.parentID !== parent.id ||
child.agent !== "fast-lo" ||
child.location.directory !== parent.location.directory
)
throw new Error("Local fast-lo child binding changed");
});
// Commands can create children without going through the subagent tool. // Commands can create children without going through the subagent tool.
yield* context.session.hook("prompt", (event) => yield* context.session.hook("prompt", (event) =>
Effect.gen(function* () { Effect.gen(function* () {
@@ -192,12 +201,12 @@ export const installMultiWork = (
if (event.agent === "coordinate" && session.parentID) if (event.agent === "coordinate" && session.parentID)
yield* validate(event.sessionID); yield* validate(event.sessionID);
if (event.agent !== "multi-work") { if (event.agent !== "multi-work") {
const tool = event.tools.subagent; const tool = event.tools["subagent"];
if (tool) { if (tool) {
const properties = z const properties = z
.record(z.string(), z.unknown()) .record(z.string(), z.unknown())
.parse(tool.input.properties ?? {}); .parse(tool.input["properties"] ?? {});
delete properties.worktree; delete properties["worktree"];
tool.input = { ...tool.input, properties }; tool.input = { ...tool.input, properties };
} }
return; return;
@@ -211,13 +220,13 @@ export const installMultiWork = (
); );
if (!root) if (!root)
throw new Error("multi-work requires a live, unambiguous Herdr root checkout"); throw new Error("multi-work requires a live, unambiguous Herdr root checkout");
const tool = event.tools.subagent; const tool = event.tools["subagent"];
if (tool) { if (tool) {
tool.input = z.toJSONSchema(inputSchema); tool.input = z.toJSONSchema(inputSchema);
const properties = z const properties = z
.record(z.string(), z.unknown()) .record(z.string(), z.unknown())
.parse(tool.input.properties); .parse(tool.input["properties"]);
tool.input.properties = { tool.input["properties"] = {
...properties, ...properties,
agent: { type: "string", enum: ["fast-lo", "coordinate"] }, agent: { type: "string", enum: ["fast-lo", "coordinate"] },
}; };
@@ -238,7 +247,7 @@ export const installMultiWork = (
if (input.agent === "multi-work") if (input.agent === "multi-work")
throw new Error("multi-work is primary only"); throw new Error("multi-work is primary only");
if ( if (
input.sessionID && present(input.sessionID) &&
(yield* context.storage.get(bindingKey(input.sessionID))) !== (yield* context.storage.get(bindingKey(input.sessionID))) !==
undefined && undefined &&
(call.agent !== "multi-work" || input.agent !== "coordinate") (call.agent !== "multi-work" || input.agent !== "coordinate")
@@ -261,22 +270,13 @@ export const installMultiWork = (
); );
if (input.agent === "fast-lo") { if (input.agent === "fast-lo") {
if (input.worktree) throw new Error("fast-lo is local retrieval only"); if (input.worktree) throw new Error("fast-lo is local retrieval only");
if (input.sessionID) { if (present(input.sessionID))
const child = yield* context.session.get({ yield* verifyLocalChild(Session.ID.make(input.sessionID), parent);
sessionID: Session.ID.make(input.sessionID),
});
if (
child.parentID !== parent.id ||
child.agent !== "fast-lo" ||
child.location.directory !== parent.location.directory
)
throw new Error("Local fast-lo child binding changed");
}
return yield* native.execute(input, call); return yield* native.execute(input, call);
} }
if (input.agent !== "coordinate") if (input.agent !== "coordinate")
throw new Error("multi-work delegates only to fast-lo or coordinate"); throw new Error("multi-work delegates only to fast-lo or coordinate");
if (input.sessionID && input.worktree !== undefined) if (present(input.sessionID) && input.worktree !== undefined)
throw new Error( throw new Error(
"Coordinate resumes require only sessionID; worktree is create-only", "Coordinate resumes require only sessionID; worktree is create-only",
); );
@@ -287,7 +287,7 @@ export const installMultiWork = (
return yield* Effect.gen(function* () { return yield* Effect.gen(function* () {
let initialized = false; let initialized = false;
let placement: z.infer<typeof bindingSchema> | undefined; let placement: z.infer<typeof bindingSchema> | undefined;
if (input.sessionID) { if (present(input.sessionID)) {
const binding = yield* validate(Session.ID.make(input.sessionID)); const binding = yield* validate(Session.ID.make(input.sessionID));
if (binding.owner !== call.sessionID) if (binding.owner !== call.sessionID)
throw new Error("Cannot resume another parent's binding"); throw new Error("Cannot resume another parent's binding");
@@ -336,7 +336,7 @@ export const installMultiWork = (
} }
const { worktree, ...args } = input; const { worktree, ...args } = input;
const callKey = `multi-work-call:${call.sessionID}:${call.id}`; const callKey = `multi-work-call:${call.sessionID}:${call.id}`;
if (!input.sessionID) { if (!present(input.sessionID)) {
const previous = yield* context.storage.get(callKey); const previous = yield* context.storage.get(callKey);
if (previous !== undefined) if (previous !== undefined)
throw new Error( throw new Error(
@@ -350,7 +350,7 @@ export const installMultiWork = (
// Native 2.0.22 awaits this update after creation and before prompt admission. // Native 2.0.22 awaits this update after creation and before prompt admission.
yield* call.progress(metadata); yield* call.progress(metadata);
if (initialized) return; if (initialized) return;
const id = z.string().parse(metadata.sessionID); const id = z.string().parse(metadata["sessionID"]);
if (busy.has(id)) if (busy.has(id))
throw new Error( throw new Error(
"This child is already being delegated", "This child is already being delegated",
@@ -433,7 +433,7 @@ export const installMultiWork = (
coordinator?.mode === "all" && coordinator?.mode === "all" &&
coordinator.system?.includes( coordinator.system?.includes(
childProtocol, childProtocol,
) && ) === true &&
[ [
"coordinate", "coordinate",
"fast-lo", "fast-lo",
@@ -503,7 +503,7 @@ export const installMultiWork = (
Effect.ensuring( Effect.ensuring(
Effect.sync(() => { Effect.sync(() => {
busy.delete(lock); busy.delete(lock);
if (childLock) busy.delete(childLock); if (present(childLock)) busy.delete(childLock);
}), }),
), ),
); );
@@ -11,11 +11,15 @@ const TIMEOUT_MS = 5_000;
const RETRY_MS = 2_000; const RETRY_MS = 2_000;
const RETRIES = 4; const RETRIES = 4;
const WEEK = 604_800; const WEEK = 604_800;
const jsonValue = z.json();
type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>; type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
export function claudeCredentialsPath() { function claudeCredentialsPath() {
return join(process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude"), ".credentials.json"); return join(
process.env["CLAUDE_CONFIG_DIR"] ?? join(homedir(), ".claude"),
".credentials.json",
);
} }
const credentials = z.object({ const credentials = z.object({
@@ -27,7 +31,7 @@ const credentials = z.object({
}); });
const usageWindow = z const usageWindow = z
.object({ utilization: z.number().finite(), resets_at: z.string().nullish() }) .object({ utilization: z.number(), resets_at: z.string().nullish() })
.nullish(); .nullish();
const usagePayload = z.object({ const usagePayload = z.object({
five_hour: usageWindow, five_hour: usageWindow,
@@ -38,7 +42,7 @@ const usagePayload = z.object({
.array( .array(
z.object({ z.object({
kind: z.string(), kind: z.string(),
percent: z.number().finite(), percent: z.number(),
resets_at: z.string().nullish(), resets_at: z.string().nullish(),
scope: z scope: z
.object({ .object({
@@ -63,7 +67,7 @@ function window(
label, label,
seconds, seconds,
used: Math.max(0, Math.min(100, used)), used: Math.max(0, Math.min(100, used)),
resetsAt: resetsAt ? Date.parse(resetsAt) : Number.NaN, resetsAt: resetsAt === null || resetsAt === undefined ? Number.NaN : Date.parse(resetsAt),
}; };
} }
@@ -173,14 +177,33 @@ export class ClaudeQuotaTracker {
const credential = parsed.data.claudeAiOauth; const credential = parsed.data.claudeAiOauth;
if (this.disposed) return true; if (this.disposed) return true;
if (credential.expiresAt <= Date.now()) return false; if (credential.expiresAt <= Date.now()) return false;
const response = await this.fetchUsage(credential.accessToken);
if (!response.ok) return false;
const payload = jsonValue.parse(await response.json());
const snapshot = normalizeClaudeQuota(
payload,
credential.subscriptionType ?? "unknown",
);
if (this.isDisposed()) return true;
if (!snapshot) return false;
this.latest = snapshot;
} catch {
return false;
}
await this.changed().catch(() => {});
return true;
}
private async fetchUsage(accessToken: string) {
const controller = new AbortController(); const controller = new AbortController();
this.controller = controller; this.controller = controller;
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS); const timeout = setTimeout(() => {
let response: Response; controller.abort();
}, TIMEOUT_MS);
try { try {
response = await this.fetcher(USAGE_URL, { return await this.fetcher(USAGE_URL, {
headers: { headers: {
Authorization: `Bearer ${credential.accessToken}`, Authorization: `Bearer ${accessToken}`,
"anthropic-beta": "oauth-2025-04-20", "anthropic-beta": "oauth-2025-04-20",
Accept: "application/json", Accept: "application/json",
}, },
@@ -190,21 +213,11 @@ export class ClaudeQuotaTracker {
clearTimeout(timeout); clearTimeout(timeout);
if (this.controller === controller) this.controller = undefined; if (this.controller === controller) this.controller = undefined;
} }
if (!response.ok) return false;
// SAFETY: Response.json yields JSON values; usagePayload validates fields used.
const payload = (await response.json()) as Schema.Json;
const snapshot = normalizeClaudeQuota(
payload,
credential.subscriptionType ?? "unknown",
);
if (this.disposed) return true;
if (!snapshot) return false;
this.latest = snapshot;
} catch {
return false;
} }
await this.changed().catch(() => {});
return true; /** Reads the flag through a call so checks after `await` are not narrowed away. */
private isDisposed() {
return this.disposed;
} }
status(): QuotaStatus | undefined { status(): QuotaStatus | undefined {
@@ -40,7 +40,7 @@ export default Plugin.define({
await quota.authChanged(); await quota.authChanged();
} else if ( } else if (
event.type === "credential.switched" && event.type === "credential.switched" &&
String(event.data.integrationID) === "openai" event.data.integrationID === "openai"
) { ) {
await quota.authChanged(true); await quota.authChanged(true);
} }
+63 -39
View File
@@ -8,24 +8,30 @@ const USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
const POLL_MS = 60_000; const POLL_MS = 60_000;
const TIMEOUT_MS = 5_000; const TIMEOUT_MS = 5_000;
const STORAGE_KEY = "chatgpt-quota"; const STORAGE_KEY = "chatgpt-quota";
const jsonValue = z.json();
function compactLimitIdentity(value: string) { function compactLimitIdentity(value: string) {
return value.toLowerCase().replace(/[^a-z0-9]+/g, ""); return value.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "");
} }
function isSparkLimit(meteredFeature?: string, limitName?: string | null) { function isSparkLimit(meteredFeature?: string, limitName?: string | null) {
return ( return (
(meteredFeature !== undefined && (meteredFeature !== undefined &&
compactLimitIdentity(meteredFeature) === "codexbengalfox") || compactLimitIdentity(meteredFeature) === "codexbengalfox") ||
(limitName != null && compactLimitIdentity(limitName) === "gpt53codexspark") (limitName !== null &&
limitName !== undefined &&
compactLimitIdentity(limitName) === "gpt53codexspark")
); );
} }
function hasReserveToken(value: string) {
return /(^|[^a-z0-9])reserve($|[^a-z0-9])/iu.test(value);
}
function isReserveLimit(meteredFeature?: string, limitName?: string | null) { function isReserveLimit(meteredFeature?: string, limitName?: string | null) {
const hasReserveToken = (value: string) => /(^|[^a-z0-9])reserve($|[^a-z0-9])/i.test(value);
return ( return (
(meteredFeature !== undefined && hasReserveToken(meteredFeature)) || (meteredFeature !== undefined && hasReserveToken(meteredFeature)) ||
(limitName != null && hasReserveToken(limitName)) (limitName !== null && limitName !== undefined && hasReserveToken(limitName))
); );
} }
@@ -81,7 +87,10 @@ function withoutExcludedState(state: StoredState): StoredState {
const windows = state.latest?.windows.filter((window) => !isExcludedWindow(window)); const windows = state.latest?.windows.filter((window) => !isExcludedWindow(window));
return { return {
...state, ...state,
latest: state.latest && windows?.length ? { ...state.latest, windows } : undefined, latest:
state.latest && windows !== undefined && windows.length > 0
? { ...state.latest, windows }
: undefined,
}; };
} }
@@ -89,9 +98,9 @@ type QuotaContext = Pick<Plugin.Context, "integration" | "storage">;
type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>; type QuotaFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
const quotaWindow = z.object({ const quotaWindow = z.object({
limit_window_seconds: z.number().finite().positive(), limit_window_seconds: z.number().positive(),
used_percent: z.number().finite(), used_percent: z.number(),
reset_at: z.number().finite(), reset_at: z.number(),
}); });
const additionalRateLimitIdentity = z.object({ const additionalRateLimitIdentity = z.object({
limit_name: z.string().optional(), limit_name: z.string().optional(),
@@ -187,7 +196,7 @@ export function normalizeQuota(
function accountID(credential: Credential.OAuth) { function accountID(credential: Credential.OAuth) {
const metadataID = z const metadataID = z
.string() .string()
.safeParse(credential.metadata?.accountID ?? credential.metadata?.accountId); .safeParse(credential.metadata?.["accountID"] ?? credential.metadata?.["accountId"]);
if (metadataID.success) return metadataID.data; if (metadataID.success) return metadataID.data;
const parts = credential.access.split("."); const parts = credential.access.split(".");
if (parts.length !== 3) return; if (parts.length !== 3) return;
@@ -200,7 +209,7 @@ function accountID(credential: Credential.OAuth) {
.optional(), .optional(),
organizations: z.array(z.object({ id: z.string() })).optional(), organizations: z.array(z.object({ id: z.string() })).optional(),
}) })
.safeParse(JSON.parse(Buffer.from(parts[1]!, "base64url").toString())); .safeParse(JSON.parse(Buffer.from(parts[1] ?? "", "base64url").toString()));
if (!claims.success) return; if (!claims.success) return;
return ( return (
claims.data.chatgpt_account_id ?? claims.data.chatgpt_account_id ??
@@ -250,21 +259,28 @@ export class QuotaTracker {
return; return;
} }
const id = accountID(credential); const id = accountID(credential);
const account = id const account =
id !== undefined && id !== ""
? await fingerprint(`account:${id}`) ? await fingerprint(`account:${id}`)
: (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`))); : (this.state?.account ?? (await fingerprint(`credential:${credential.refresh}`)));
if (generation !== this.generation) return; if (generation !== this.generation) return;
if (this.state?.account !== account) { if (this.state?.account !== account) await this.load(account, generation);
if (generation !== this.generation) return;
this.timer ??= setInterval(() => void this.refresh(), this.pollMs);
return credential;
}
private async load(account: string, generation: number) {
const value = await this.context.storage.get(STORAGE_KEY); const value = await this.context.storage.get(STORAGE_KEY);
const parsed = storedState.safeParse(value); const parsed = storedState.safeParse(value);
if (generation !== this.generation) return; if (generation !== this.generation) return;
const stored = parsed.success ? parsed.data : undefined; const stored = parsed.success ? parsed.data : undefined;
if (generation !== this.generation) return;
this.state = stored?.account === account ? withoutExcludedState(stored) : { account }; this.state = stored?.account === account ? withoutExcludedState(stored) : { account };
} }
if (generation !== this.generation) return;
if (!this.timer) this.timer = setInterval(() => void this.refresh(), this.pollMs); /** Reads state through a call so checks after `await` are not narrowed away. */
return credential; private current(): StoredState | undefined {
return this.state;
} }
private async clear() { private async clear() {
@@ -297,32 +313,20 @@ export class QuotaTracker {
try { try {
const credential = await this.resolveCredential(generation); const credential = await this.resolveCredential(generation);
if (!credential || !this.state || generation !== this.generation) return; if (!credential || !this.state || generation !== this.generation) return;
const controller = new AbortController(); const response = await this.fetchUsage(credential);
this.controller = controller;
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
let response: Response;
try {
const headers = new Headers({
Authorization: `Bearer ${credential.access}`,
Accept: "application/json",
});
const id = accountID(credential);
if (id) headers.set("ChatGPT-Account-Id", id);
response = await this.fetcher(USAGE_URL, { headers, signal: controller.signal });
} finally {
clearTimeout(timeout);
if (this.controller === controller) this.controller = undefined;
}
if (!response.ok || generation !== this.generation) return; if (!response.ok || generation !== this.generation) return;
// SAFETY: JSON.parse semantics from Response.json produce only JSON values; const payload = jsonValue.parse(await response.json());
// quotaPayload validates all fields used below. if (generation !== this.generation || !this.current()) return;
const payload = (await response.json()) as Schema.Json;
if (generation !== this.generation || !this.state) return;
const parsed = quotaPayload.safeParse(payload); const parsed = quotaPayload.safeParse(payload);
if (parsed.success && parsed.data.account_id) { if (
parsed.success &&
parsed.data.account_id !== undefined &&
parsed.data.account_id !== ""
) {
const account = await fingerprint(`account:${parsed.data.account_id}`); const account = await fingerprint(`account:${parsed.data.account_id}`);
if (generation !== this.generation || !this.state) return; const state = this.current();
if (account !== this.state.account) this.state = { account }; if (generation !== this.generation || !state) return;
if (account !== state.account) this.state = { account };
} }
const snapshot = normalizeQuota(payload); const snapshot = normalizeQuota(payload);
if (!snapshot) return; if (!snapshot) return;
@@ -335,6 +339,26 @@ export class QuotaTracker {
} }
} }
private async fetchUsage(credential: Credential.OAuth) {
const controller = new AbortController();
this.controller = controller;
const timeout = setTimeout(() => {
controller.abort();
}, TIMEOUT_MS);
try {
const headers = new Headers({
Authorization: `Bearer ${credential.access}`,
Accept: "application/json",
});
const id = accountID(credential);
if (id !== undefined && id !== "") headers.set("ChatGPT-Account-Id", id);
return await this.fetcher(USAGE_URL, { headers, signal: controller.signal });
} finally {
clearTimeout(timeout);
if (this.controller === controller) this.controller = undefined;
}
}
private apply(snapshot: QuotaSnapshot) { private apply(snapshot: QuotaSnapshot) {
if (!this.state) return; if (!this.state) return;
this.state.latest = snapshot; this.state.latest = snapshot;
+15 -14
View File
@@ -34,7 +34,8 @@ function resetTiming(resetsAt: number, now: number) {
} }
export function formatQuotaWindow(window: QuotaWindow & { remaining: number }, now = Date.now()) { export function formatQuotaWindow(window: QuotaWindow & { remaining: number }, now = Date.now()) {
const label = window.label const label =
window.label !== null && window.label !== ""
? `${window.label} ${duration(window.seconds)}` ? `${window.label} ${duration(window.seconds)}`
: duration(window.seconds); : duration(window.seconds);
return `${label}: ${percent(window.remaining)}% · ${resetTiming(window.resetsAt, now)}`; return `${label}: ${percent(window.remaining)}% · ${resetTiming(window.resetsAt, now)}`;
@@ -60,17 +61,6 @@ export default Plugin.define({
setRevision((value) => value + 1); setRevision((value) => value + 1);
}); });
const Slot = (props: { instance: string; centered?: boolean; visible?: () => boolean }) => {
const [statuses] = createResource(
() => (props.visible?.() === false ? false : `${props.instance}:${revision()}`),
async () => {
const [chatgpt, claude] = await Promise.all([
loadQuotaStatus(() => quota.status({})),
loadQuotaStatus(() => quota.claude({})),
]);
return chatgpt || claude ? { chatgpt, claude } : null;
},
);
const Section = (section: { title: string; status: QuotaStatus | null }) => ( const Section = (section: { title: string; status: QuotaStatus | null }) => (
<Show when={section.status}> <Show when={section.status}>
{(status: () => QuotaStatus) => ( {(status: () => QuotaStatus) => (
@@ -91,10 +81,21 @@ export default Plugin.define({
)} )}
</Show> </Show>
); );
const Slot = (props: { instance: string; centered?: boolean; visible?: () => boolean }) => {
const [statuses] = createResource(
() => (props.visible?.() === false ? false : `${props.instance}:${revision()}`),
async () => {
const [chatgpt, claude] = await Promise.all([
loadQuotaStatus(() => quota.status({})),
loadQuotaStatus(() => quota.claude({})),
]);
return chatgpt || claude ? { chatgpt, claude } : null;
},
);
const Content = () => ( const Content = () => (
<box flexDirection="column"> <box flexDirection="column">
<Section title="ChatGPT" status={statuses()!.chatgpt} /> <Section title="ChatGPT" status={statuses()?.chatgpt ?? null} />
<Section title="Claude" status={statuses()!.claude} /> <Section title="Claude" status={statuses()?.claude ?? null} />
</box> </box>
); );
return ( return (
+11 -6
View File
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, expect, test } from "bun:test";
import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ClaudeQuotaTracker, normalizeClaudeQuota } from "../src/claude-quota.js"; import { ClaudeQuotaTracker, normalizeClaudeQuota } from "../src/quota/claude-quota.js";
const payload = { const payload = {
five_hour: { utilization: 12.5, resets_at: "2026-10-07T12:00:00+00:00" }, five_hour: { utilization: 12.5, resets_at: "2026-10-07T12:00:00+00:00" },
@@ -97,7 +97,10 @@ test("reads credentials file and sends OAuth usage request", async () => {
changed++; changed++;
}, },
async (input, init) => { async (input, init) => {
calls.push({ url: String(input), headers: new Headers(init?.headers) }); calls.push({
url: input instanceof Request ? input.url : String(input),
headers: new Headers(init?.headers),
});
return Response.json(payload); return Response.json(payload);
}, },
60_000, 60_000,
@@ -105,10 +108,12 @@ test("reads credentials file and sends OAuth usage request", async () => {
); );
await tracker.init(); await tracker.init();
expect(calls).toHaveLength(1); expect(calls).toHaveLength(1);
expect(calls[0]!.url).toBe("https://api.anthropic.com/api/oauth/usage"); const [call] = calls;
expect(calls[0]!.headers.get("authorization")).toBe("Bearer token-123"); if (!call) throw new Error("Missing usage request");
expect(calls[0]!.headers.get("anthropic-beta")).toBe("oauth-2025-04-20"); expect(call.url).toBe("https://api.anthropic.com/api/oauth/usage");
expect(calls[0]!.headers.get("accept")).toBe("application/json"); expect(call.headers.get("authorization")).toBe("Bearer token-123");
expect(call.headers.get("anthropic-beta")).toBe("oauth-2025-04-20");
expect(call.headers.get("accept")).toBe("application/json");
expect(tracker.status()?.plan).toBe("max"); expect(tracker.status()?.plan).toBe("max");
expect(tracker.status()?.windows[0]?.remaining).toBe(87.5); expect(tracker.status()?.windows[0]?.remaining).toBe(87.5);
expect(changed).toBe(1); expect(changed).toBe(1);
+6 -6
View File
@@ -1,7 +1,7 @@
import { Plugin, Model, Provider } from "@opencode/plugin/effect"; import { Plugin, Model, Provider } from "@opencode/plugin/effect";
import { fromPromise } from "@opencode/plugin/promise/adapter"; import { fromPromise } from "@opencode/plugin/promise/adapter";
import { Effect } from "effect"; import { Effect } from "effect";
import agents from "../../src/agents.js"; import agents from "../../src/agents/agents.js";
export default Plugin.define({ export default Plugin.define({
id: agents.id, id: agents.id,
@@ -10,13 +10,13 @@ export default Plugin.define({
const providerID = Provider.ID.make("fixture"); const providerID = Provider.ID.make("fixture");
yield* context.provider.transform((editor) => yield* context.provider.transform((editor) =>
editor.add({ editor.add({
info: { // Copy own fields like the former spread; the editor accepts plain info.
...Provider.Info.empty(providerID), info: Object.assign({}, Provider.Info.empty(providerID), {
name: "Isolated fixture", name: "Isolated fixture",
activation: "enabled", activation: "enabled" as const,
package: "@opencode/ai/providers/openai-compatible", package: "@opencode/ai/providers/openai-compatible",
settings: { baseURL: process.env.FIXTURE_MODEL_URL! }, settings: { baseURL: process.env["FIXTURE_MODEL_URL"] ?? "" },
}, }),
models: ["gpt-6-luna", "gpt-6.1-sol", "gpt-6-astra"].map((id) => models: ["gpt-6-luna", "gpt-6.1-sol", "gpt-6-astra"].map((id) =>
Model.Info.default(providerID, Model.ID.make(id)), Model.Info.default(providerID, Model.ID.make(id)),
), ),
+3 -3
View File
@@ -6,7 +6,7 @@ import { Tool } from "@opencode/schema/tool";
import { Cause, Effect } from "effect"; import { Cause, Effect } from "effect";
import { z } from "zod"; import { z } from "zod";
import { appendFile } from "node:fs/promises"; import { appendFile } from "node:fs/promises";
import multiWork from "../../src/multi-work.js"; import multiWork from "../../src/multi-work/multi-work.js";
const probe = Rpc.define({ const probe = Rpc.define({
id: "multi-work-test", id: "multi-work-test",
@@ -37,7 +37,7 @@ export default Plugin.define({
const child = yield* context.session.get({ sessionID: event.sessionID }); const child = yield* context.session.get({ sessionID: event.sessionID });
yield* Effect.promise(() => yield* Effect.promise(() =>
appendFile( appendFile(
process.env.FIXTURE_TRACE!, process.env["FIXTURE_TRACE"] ?? "",
JSON.stringify({ JSON.stringify({
id: child.id, id: child.id,
parent: child.parentID, parent: child.parentID,
@@ -59,7 +59,7 @@ export default Plugin.define({
description: "native host proof", description: "native host proof",
prompt: "Reply with FIXTURE_COMPLETE", prompt: "Reply with FIXTURE_COMPLETE",
background: input.background, background: input.background,
...(input.child ...(input.child !== undefined && input.child !== ""
? { sessionID: input.child } ? { sessionID: input.child }
: { : {
worktree: { worktree: {
+9 -8
View File
@@ -2,7 +2,7 @@ import { afterEach, expect, test } from "bun:test";
import { mkdir, mkdtemp, rm } from "node:fs/promises"; import { mkdir, mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { command, Herdr } from "../src/herdr.js"; import { command, Herdr } from "../src/multi-work/herdr.js";
const directories: string[] = []; const directories: string[] = [];
afterEach(async () => { afterEach(async () => {
@@ -45,9 +45,9 @@ async function fixture() {
let childWorkspaceIDOverride: string | undefined; let childWorkspaceIDOverride: string | undefined;
let childPathOverride: string | undefined; let childPathOverride: string | undefined;
let repoOverride: string | undefined; let repoOverride: string | undefined;
const run = async (args: string[], cwd: string, signal: AbortSignal) => { const run = async (args: string[], cwd: string, abort: AbortSignal) => {
calls.push(args); calls.push(args);
if (args[0] !== "herdr") return command(args, cwd, signal); if (args[0] !== "herdr") return command(args, cwd, abort);
if (args[1] === "workspace") if (args[1] === "workspace")
return JSON.stringify({ return JSON.stringify({
result: { result: {
@@ -57,7 +57,7 @@ async function fixture() {
}, },
}); });
if (args[2] === "list") { if (args[2] === "list") {
const id = args[4]!; const id = args[4] ?? "";
const path = id === "w2" ? destination : root; const path = id === "w2" ? destination : root;
const sourceWorkspaceID = sourceWorkspaceIDOverride ?? (id === "w2" ? "w1" : id); const sourceWorkspaceID = sourceWorkspaceIDOverride ?? (id === "w2" ? "w1" : id);
const sourcePath = sourcePathOverride ?? root; const sourcePath = sourcePathOverride ?? root;
@@ -93,10 +93,10 @@ async function fixture() {
expect(args[2]).toBe("create"); expect(args[2]).toBe("create");
expect(args.slice(3, 5)).toEqual(["--cwd", root]); expect(args.slice(3, 5)).toEqual(["--cwd", root]);
expect(args.at(-1)).toBe("--no-focus"); expect(args.at(-1)).toBe("--no-focus");
branch = args[args.indexOf("--branch") + 1]!; branch = args[args.indexOf("--branch") + 1] ?? "";
const labelIndex = args.indexOf("--label"); const labelIndex = args.indexOf("--label");
label = labelIndex === -1 ? undefined : args[labelIndex + 1]; label = labelIndex === -1 ? undefined : args[labelIndex + 1];
const base = args[args.indexOf("--base") + 1]!; const base = args[args.indexOf("--base") + 1] ?? "";
// Real Git worktree behavior, but only in an isolated temporary repository. // Real Git worktree behavior, but only in an isolated temporary repository.
await command(["git", "worktree", "add", "-b", branch, destination, base], root, signal); await command(["git", "worktree", "add", "-b", branch, destination, base], root, signal);
return JSON.stringify({ return JSON.stringify({
@@ -144,14 +144,15 @@ test("create verifies a linked workspace whose inventory source remains the pare
const f = await fixture(); const f = await fixture();
const root = await f.herdr.root(f.root, f.signal); const root = await f.herdr.root(f.root, f.signal);
expect(root?.workspaceID).toBe("w1"); expect(root?.workspaceID).toBe("w1");
const destination = await f.herdr.create(root!, "other", "multi-work/fixture", f.signal); if (!root) throw new Error("Missing Herdr root");
const destination = await f.herdr.create(root, "other", "multi-work/fixture", f.signal);
expect(destination.directory).toBe(f.destination); expect(destination.directory).toBe(f.destination);
expect(destination.branch).toStartWith("multi-work/"); expect(destination.branch).toStartWith("multi-work/");
expect(await command(["git", "branch", "--show-current"], f.root, f.signal)).toBe("main"); expect(await command(["git", "branch", "--show-current"], f.root, f.signal)).toBe("main");
await f.herdr.verify( await f.herdr.verify(
destination.directory, destination.directory,
destination.workspaceID, destination.workspaceID,
root!, root,
destination.branch, destination.branch,
f.signal, f.signal,
); );
+51 -27
View File
@@ -3,6 +3,7 @@ import { chmod, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { dirname, join } from "node:path"; import { dirname, join } from "node:path";
import { createHash } from "node:crypto"; import { createHash } from "node:crypto";
import { z } from "zod";
import { install } from "../scripts/install.js"; import { install } from "../scripts/install.js";
const directories: string[] = []; const directories: string[] = [];
@@ -34,6 +35,15 @@ const empty = {
"deep-hi": "", "deep-hi": "",
}, },
}; };
const pluginEntry = z
.object({ package: z.string(), options: z.record(z.string(), z.json()).optional() })
.loose();
const configFile = z
.object({ plugins: z.array(z.json()), experimental: z.json().optional() })
.loose();
const manifestFile = z.object({ exports: z.record(z.string(), z.json()) }).loose();
const entries = (plugins: z.infer<typeof configFile>["plugins"]) =>
z.array(pluginEntry).parse(plugins);
const helper = new URL("../scripts/install.ts", import.meta.url); const helper = new URL("../scripts/install.ts", import.meta.url);
async function run( async function run(
command: string[], command: string[],
@@ -50,8 +60,8 @@ async function run(
timeout: 30_000, timeout: 30_000,
}); });
if (input !== undefined && process.stdin) { if (input !== undefined && process.stdin) {
process.stdin.write(input); void process.stdin.write(input);
process.stdin.end(); void process.stdin.end();
} }
const [exitCode, stdout, stderr] = await Promise.all([ const [exitCode, stdout, stderr] = await Promise.all([
process.exited, process.exited,
@@ -83,7 +93,9 @@ async function fixture() {
format: "esm", format: "esm",
}); });
expect(built.success).toBe(true); expect(built.success).toBe(true);
await Bun.write(join(source, "dist", "install.js"), built.outputs[0]!); const [output] = built.outputs;
if (output === undefined) throw new Error("Missing installer build output");
await Bun.write(join(source, "dist", "install.js"), output);
await writeFile(join(source, "package.json"), '{"type":"module"}'); await writeFile(join(source, "package.json"), '{"type":"module"}');
await writeFile( await writeFile(
join(config, "opencode.json"), join(config, "opencode.json"),
@@ -96,7 +108,7 @@ async function fixture() {
return { directory, source, config }; return { directory, source, config };
} }
async function contents(config: string) { async function contents(config: string) {
return JSON.parse(await readFile(join(config, "opencode.json"), "utf8")); return configFile.parse(JSON.parse(await readFile(join(config, "opencode.json"), "utf8")));
} }
for (const selection of ["quota", "agents,multi-work,quota"]) { for (const selection of ["quota", "agents,multi-work,quota"]) {
@@ -106,14 +118,16 @@ for (const selection of ["quota", "agents,multi-work,quota"]) {
const result = await contents(f.config); const result = await contents(f.config);
expect(result).toMatchObject(unrelated); expect(result).toMatchObject(unrelated);
expect(result.experimental === undefined).toBe(selection === "quota"); expect(result.experimental === undefined).toBe(selection === "quota");
expect(result.plugins.map((entry: { package: string }) => entry.package)).toEqual([ expect(entries(result.plugins).map((entry) => entry.package)).toEqual([
"before", "before",
...selection.split(",").map((name) => `./plugins/stanp-opencode/${name}`), ...selection.split(",").map((name) => `./plugins/stanp-opencode/${name}`),
]); ]);
const target = join(f.config, "plugins", "stanp-opencode"); const target = join(f.config, "plugins", "stanp-opencode");
expect((await readdir(target)).sort()).toEqual(selection.split(",").sort()); expect((await readdir(target)).toSorted()).toEqual(selection.split(",").toSorted());
for (const name of selection.split(",")) { for (const name of selection.split(",")) {
const manifest = await Bun.file(join(target, name, "package.json")).json(); const manifest = manifestFile.parse(
await Bun.file(join(target, name, "package.json")).json(),
);
expect(manifest.exports["./tui"] !== undefined).toBe(name === "quota"); expect(manifest.exports["./tui"] !== undefined).toBe(name === "quota");
expect(await Bun.file(join(target, name, "tui.js")).exists()).toBe(name === "quota"); expect(await Bun.file(join(target, name, "tui.js")).exists()).toBe(name === "quota");
} }
@@ -127,18 +141,23 @@ test("upgrades retain selection and options; explicit selection replaces only ow
const f = await fixture(); const f = await fixture();
await install(f.source, f.config, "agents,quota"); await install(f.source, f.config, "agents,quota");
const current = await contents(f.config); const current = await contents(f.config);
current.plugins[1].options = { const [before, agents, quota] = entries(current.plugins);
agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" }, if (!before || !agents || !quota) throw new Error("Missing installed plugins");
}; const after = { package: "after", options: { untouched: 1 } };
current.plugins.push({ package: "after", options: { untouched: 1 } }); const plugins = [
await writeFile(join(f.config, "opencode.json"), JSON.stringify(current)); before,
{ ...agents, options: { agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" } } },
quota,
after,
];
await writeFile(join(f.config, "opencode.json"), JSON.stringify({ ...current, plugins }));
await install(f.source, f.config); await install(f.source, f.config);
expect((await contents(f.config)).plugins).toEqual(current.plugins); expect(entries((await contents(f.config)).plugins)).toEqual(plugins);
await install(f.source, f.config, "quota"); await install(f.source, f.config, "quota");
expect((await contents(f.config)).plugins).toEqual([ expect(entries((await contents(f.config)).plugins)).toEqual([
current.plugins[0], before,
{ package: "./plugins/stanp-opencode/quota" }, { package: "./plugins/stanp-opencode/quota" },
current.plugins[3], after,
]); ]);
}); });
@@ -152,14 +171,17 @@ test("installer writes empty option skeletons and subagent_depth, fills only mis
{ package: "./plugins/stanp-opencode/quota" }, { package: "./plugins/stanp-opencode/quota" },
]); ]);
expect(fresh.experimental).toEqual({ subagent_depth: 2 }); expect(fresh.experimental).toEqual({ subagent_depth: 2 });
fresh.plugins[1].options = { const [before, agents, ...rest] = entries(fresh.plugins);
agents: { "fast-lo": "openai/gpt-6-luna#low" }, if (!before || !agents) throw new Error("Missing installed plugins");
extra: 1, const plugins = [
}; before,
await writeFile(join(f.config, "opencode.json"), JSON.stringify(fresh)); { ...agents, options: { agents: { "fast-lo": "openai/gpt-6-luna#low" }, extra: 1 } },
...rest,
];
await writeFile(join(f.config, "opencode.json"), JSON.stringify({ ...fresh, plugins }));
await install(f.source, f.config); await install(f.source, f.config);
const filled = await contents(f.config); const filled = await contents(f.config);
expect(filled.plugins[1].options).toEqual({ expect(entries(filled.plugins)[1]?.options).toEqual({
agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" }, agents: { ...empty.agents, "fast-lo": "openai/gpt-6-luna#low" },
extra: 1, extra: 1,
}); });
@@ -169,7 +191,7 @@ test("installer writes empty option skeletons and subagent_depth, fills only mis
for (const [depth, expected] of [ for (const [depth, expected] of [
[1, 2], [1, 2],
[3, 3], [3, 3],
]) { ] as const) {
await writeFile( await writeFile(
join(f.config, "opencode.json"), join(f.config, "opencode.json"),
JSON.stringify({ JSON.stringify({
@@ -214,12 +236,14 @@ test("replaces the legacy monolith without duplicates and retains Agents options
await writeFile(join(f.config, "plugins", "stanp-opencode.js"), "legacy"); await writeFile(join(f.config, "plugins", "stanp-opencode.js"), "legacy");
await install(f.source, f.config); await install(f.source, f.config);
const result = await contents(f.config); const result = await contents(f.config);
expect(result.plugins.map((entry: { package: string }) => entry.package)).toEqual([ expect(entries(result.plugins).map((entry) => entry.package)).toEqual([
"before", "before",
...names.map((name) => `./plugins/stanp-opencode/${name}`), ...names.map((name) => `./plugins/stanp-opencode/${name}`),
"after", "after",
]); ]);
expect(result.plugins[1].options.agents["fast-lo"]).toBe("openai/gpt-6-luna#low"); expect(result.plugins[1]).toMatchObject({
options: { agents: { "fast-lo": "openai/gpt-6-luna#low" } },
});
expect(await Bun.file(join(f.config, "plugins", "stanp-opencode.js")).exists()).toBe(false); expect(await Bun.file(join(f.config, "plugins", "stanp-opencode.js")).exists()).toBe(false);
expect(result).toMatchObject(unrelated); expect(result).toMatchObject(unrelated);
}); });
@@ -283,7 +307,7 @@ test("local shell installer builds its checkout and upgrades mixed entries witho
await chmod(join(bin, "bun"), 0o755); await chmod(join(bin, "bun"), 0o755);
const env = { const env = {
...Bun.env, ...Bun.env,
PATH: `${bin}:${dirname(process.execPath)}:${Bun.env.PATH}`, PATH: `${bin}:${dirname(process.execPath)}:${Bun.env["PATH"]}`,
REAL_BUN: process.execPath, REAL_BUN: process.execPath,
CALLS: join(f.directory, "calls"), CALLS: join(f.directory, "calls"),
OPENCODE_CONFIG_DIR: f.config, OPENCODE_CONFIG_DIR: f.config,
@@ -357,7 +381,7 @@ for (const validChecksum of [true, false])
f.directory, f.directory,
{ {
...Bun.env, ...Bun.env,
PATH: `${bin}:${dirname(process.execPath)}:${Bun.env.PATH}`, PATH: `${bin}:${dirname(process.execPath)}:${Bun.env["PATH"]}`,
ARCHIVE: archive, ARCHIVE: archive,
CHECKSUM: checksum, CHECKSUM: checksum,
RELEASE: release, RELEASE: release,
+31 -22
View File
@@ -9,8 +9,8 @@ import type { ToolEditor, ToolHooks } from "@opencode/plugin/effect/tool";
import type { AgentEditor } from "@opencode/plugin/effect/agent"; import type { AgentEditor } from "@opencode/plugin/effect/agent";
import type { SessionContext } from "@opencode/plugin/effect/session"; import type { SessionContext } from "@opencode/plugin/effect/session";
import { z } from "zod"; import { z } from "zod";
import { Herdr, type HerdrRoot } from "../src/herdr.js"; import { Herdr, type HerdrRoot } from "../src/multi-work/herdr.js";
import { bindingKey, bindingSchema, installMultiWork } from "../src/multi-work.js"; import { bindingKey, bindingSchema, installMultiWork } from "../src/multi-work/multi-work.js";
class FixtureHerdr extends Herdr { class FixtureHerdr extends Herdr {
eligible = true; eligible = true;
@@ -70,6 +70,19 @@ interface FixtureSession {
permissions: Agent.Info["permissions"]; permissions: Agent.Info["permissions"];
} }
const defaultInput = {
agent: "coordinate",
description: "test",
prompt: "work",
worktree: { base: "main" },
};
function required<T>(map: Map<string, T>, key: string) {
const value = map.get(key);
if (value === undefined) throw new Error(`Missing fixture entry ${key}`);
return value;
}
function fixture() { function fixture() {
const herdr = new FixtureHerdr(); const herdr = new FixtureHerdr();
const storage = new Map<string, Parameters<Context["storage"]["set"]>[1]>(); const storage = new Map<string, Parameters<Context["storage"]["set"]>[1]>();
@@ -112,7 +125,7 @@ function fixture() {
}) })
.parse(raw); .parse(raw);
const id = Session.ID.make(input.sessionID ?? `ses_child${++serial}`); const id = Session.ID.make(input.sessionID ?? `ses_child${++serial}`);
if (!input.sessionID) if (input.sessionID === undefined || input.sessionID === "")
sessions.set(id, { sessions.set(id, {
...parent, ...parent,
id, id,
@@ -122,7 +135,7 @@ function fixture() {
}); });
order.push("create"); order.push("create");
yield* call.progress({ sessionID: id, status: "running" }); yield* call.progress({ sessionID: id, status: "running" });
order.push(`prompt:${sessions.get(id)!.location.directory}`); order.push(`prompt:${required(sessions, id).location.directory}`);
prompts++; prompts++;
entered.resolve(); entered.resolve();
if (hold) if (hold)
@@ -135,7 +148,10 @@ function fixture() {
); );
return { return {
content: "native result", content: "native result",
metadata: { sessionID: id, status: input.background ? "running" : "completed" }, metadata: {
sessionID: id,
status: input.background === true ? "running" : "completed",
},
}; };
}), }),
}; };
@@ -144,7 +160,7 @@ function fixture() {
[]; [];
const hooks: ((event: SessionContext) => Effect.Effect<void>)[] = []; const hooks: ((event: SessionContext) => Effect.Effect<void>)[] = [];
let prompt!: (event: Pick<SessionContext, "sessionID">) => Effect.Effect<void>; let prompt!: (event: Pick<SessionContext, "sessionID">) => Effect.Effect<void>;
let transform!: (editor: AgentEditor) => void; let transform: ((editor: AgentEditor) => void) | undefined;
const registration = Effect.succeed({ dispose: Effect.void }); const registration = Effect.succeed({ dispose: Effect.void });
const editAgents = (): AgentEditor => ({ const editAgents = (): AgentEditor => ({
get: (id) => agents.get(id), get: (id) => agents.get(id),
@@ -185,16 +201,16 @@ function fixture() {
}), }),
}, },
agent: { agent: {
transform: (callback: typeof transform) => transform: (callback: (editor: AgentEditor) => void) =>
Effect.sync(() => { Effect.sync(() => {
transform = callback; transform = callback;
callback(editAgents()); callback(editAgents());
}).pipe(Effect.andThen(registration)), }).pipe(Effect.andThen(registration)),
reload: () => reload: () =>
Effect.sync(() => { Effect.sync(() => {
if (transform) transform(editAgents()); transform?.(editAgents());
}), }),
get: () => Effect.succeed({ data: agents.get("multi-work")! }), get: () => Effect.succeed({ data: required(agents, "multi-work") }),
list: () => list: () =>
Effect.sync(() => { Effect.sync(() => {
agentReads++; agentReads++;
@@ -204,14 +220,15 @@ function fixture() {
}, },
session: { session: {
get: ({ sessionID }: { sessionID: string }) => get: ({ sessionID }: { sessionID: string }) =>
Effect.sync(() => sessions.get(sessionID)!), Effect.sync(() => required(sessions, sessionID)),
move: ({ sessionID, directory }: { sessionID: string; directory: string }) => move: ({ sessionID, directory }: { sessionID: string; directory: string }) =>
Effect.sync(() => { Effect.sync(() => {
order.push("move-request"); order.push("move-request");
if (!delayMove) { if (!delayMove) {
sessions.get(sessionID)!.location.directory = directory; required(sessions, sessionID).location.directory = directory;
order.push("moved"); order.push("moved");
if (crossProject) sessions.get(sessionID)!.projectID = "another-project"; if (crossProject)
required(sessions, sessionID).projectID = "another-project";
} }
entered.resolve(); entered.resolve();
}), }),
@@ -272,15 +289,7 @@ function fixture() {
Agent.Info.default(Agent.ID.make("build")).permissions, Agent.Info.default(Agent.ID.make("build")).permissions,
herdr, herdr,
), ),
invoke: ( invoke: (input = defaultInput, caller = call) => tool.execute(input, caller),
input = {
agent: "coordinate",
description: "test",
prompt: "work",
worktree: { base: "main" },
},
caller = call,
) => tool.execute(input, caller),
execute: (input: z.infer<typeof request>, caller = call) => tool.execute(input, caller), execute: (input: z.infer<typeof request>, caller = call) => tool.execute(input, caller),
hold() { hold() {
hold = true; hold = true;
@@ -381,7 +390,7 @@ test("root-local resume rejects location, binding, and live-root changes", async
prompt: "work", prompt: "work",
}); });
if (tamper === "session") if (tamper === "session")
f.sessions.get("ses_child1")!.location.directory = "/other"; required(f.sessions, "ses_child1").location.directory = "/other";
else if (tamper === "live-root") f.herdr.rootWorkspaceID = "foreign"; else if (tamper === "live-root") f.herdr.rootWorkspaceID = "foreign";
else { else {
const binding = bindingSchema.parse( const binding = bindingSchema.parse(
+13 -4
View File
@@ -3,6 +3,7 @@ import { mkdir, mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { Host } from "@opencode/plugin/host"; import { Host } from "@opencode/plugin/host";
import { z } from "zod";
import { build } from "../scripts/build.js"; import { build } from "../scripts/build.js";
import { install } from "../scripts/install.js"; import { install } from "../scripts/install.js";
@@ -23,13 +24,19 @@ test("packed package has independent native plugins and quota-only TUI discovery
}); });
expect(await unpack.exited).toBe(0); expect(await unpack.exited).toBe(0);
const source = join(directory, "package"); const source = join(directory, "package");
const manifest = await Bun.file(join(source, "package.json")).json(); const manifest = z
.object({ exports: z.record(z.string(), z.object({ import: z.string() }).loose()) })
.loose()
.parse(await Bun.file(join(source, "package.json")).json());
const entrypoint = (name: string) =>
join(source, z.string().parse(manifest.exports[name]?.import));
expect(manifest.exports["."]).toBeUndefined(); expect(manifest.exports["."]).toBeUndefined();
expect(await Bun.file(join(source, "index.js")).exists()).toBe(false); expect(await Bun.file(join(source, "index.js")).exists()).toBe(false);
expect(await Bun.file(join(source, "dist", "index.js")).exists()).toBe(false); expect(await Bun.file(join(source, "dist", "index.js")).exists()).toBe(false);
for (const name of ["agents", "multi-work", "quota"]) { for (const name of ["agents", "multi-work", "quota"]) {
const entrypoint = join(source, manifest.exports[`./${name}`].import); const { default: plugin } = z
const { default: plugin } = await import(entrypoint); .object({ default: z.object({ id: z.string() }).loose() })
.parse(await import(entrypoint(`./${name}`)));
expect(plugin.id).toBe(`stanp-opencode.${name}`); expect(plugin.id).toBe(`stanp-opencode.${name}`);
} }
const config = join(directory, "config"); const config = join(directory, "config");
@@ -42,7 +49,9 @@ test("packed package has independent native plugins and quota-only TUI discovery
expect(entries.server).toBeDefined(); expect(entries.server).toBeDefined();
expect(entries.tui !== undefined).toBe(name === "quota"); expect(entries.tui !== undefined).toBe(name === "quota");
} }
const { QuotaRpc } = await import(join(source, manifest.exports["./quota-rpc"].import)); const { QuotaRpc } = z
.object({ QuotaRpc: z.object({ id: z.string() }).loose() })
.parse(await import(entrypoint("./quota-rpc")));
expect(QuotaRpc.id).toBe("stanp-opencode.quota"); expect(QuotaRpc.id).toBe("stanp-opencode.quota");
} finally { } finally {
await rm(directory, { recursive: true, force: true }); await rm(directory, { recursive: true, force: true });
+27 -25
View File
@@ -7,10 +7,10 @@ import type { SkillEditor } from "@opencode/plugin/promise/skill";
import type { DeepMutable } from "@opencode/plugin/promise/types"; import type { DeepMutable } from "@opencode/plugin/promise/types";
import type { Skill } from "@opencode/schema/skill"; import type { Skill } from "@opencode/schema/skill";
import type { ModelInfo } from "@opencode/client"; import type { ModelInfo } from "@opencode/client";
import plugin from "../src/agents.js"; import plugin from "../src/agents/agents.js";
import { model } from "../src/model.js"; import { model } from "../src/agents/model.js";
import { z } from "zod"; import { z } from "zod";
import { AgentsRpc } from "../src/agents-rpc.js"; import { AgentsRpc } from "../src/agents/agents-rpc.js";
const cleanups: Plugin.Cleanup[] = []; const cleanups: Plugin.Cleanup[] = [];
afterEach(async () => { afterEach(async () => {
@@ -31,24 +31,29 @@ const agents = {
"deep-lo": "test/gpt-6-astra#low", "deep-lo": "test/gpt-6-astra#low",
"deep-hi": "test/gpt-6-astra#high", "deep-hi": "test/gpt-6-astra#high",
}; };
const defaultOptions = { agents };
const defaultLocation = { directory: "/fixture" };
async function flush() {
await Bun.sleep(10);
}
async function host( async function host(
catalog: ModelInfo[] = models, catalog: ModelInfo[] = models,
options: Plugin.Context["options"] = { agents }, options: Plugin.Context["options"] = defaultOptions,
existingSkill?: Skill.Info, existingSkill?: Skill.Info,
) { ) {
const agents = new Map<string, DeepMutable<Agent.Info>>(); const registry = new Map<string, DeepMutable<Agent.Info>>();
let build: DeepMutable<Agent.Info> = Agent.Info.default(Agent.ID.make("build")); let build: DeepMutable<Agent.Info> = Agent.Info.default(Agent.ID.make("build"));
const skills = new Map<string, Skill.Info>( const skills = new Map<string, Skill.Info>(
existingSkill ? [[existingSkill.id, existingSkill]] : [], existingSkill ? [[existingSkill.id, existingSkill]] : [],
); );
let transform: (editor: AgentEditor) => void; let transform: ((editor: AgentEditor) => void) | undefined;
let contextHook: (event: Pick<SessionContext, "agent" | "tools">) => Promise<void> | void; let contextHook: (event: Pick<SessionContext, "agent" | "tools">) => Promise<void> | void;
let promptHook: (event: { sessionID: string }) => Promise<void> | void; let promptHook: (event: { sessionID: string }) => Promise<void> | void;
let before: (event: { tool: string; agent: string; input: unknown }) => Promise<void> | void; let before: (event: { tool: string; agent: string; input: unknown }) => Promise<void> | void;
let parent = "build"; let parent = "build";
let child = "fast-lo"; let child = "fast-lo";
let tools: string[] = []; let tools: string[] = [];
let toolTransform: (editor: ToolEditor) => void; let toolTransform: ((editor: ToolEditor) => void) | undefined;
let permissions: () => Promise<Agent.Info["permissions"]>; let permissions: () => Promise<Agent.Info["permissions"]>;
let controller: ReadableStreamDefaultController<unknown>; let controller: ReadableStreamDefaultController<unknown>;
const stream = new ReadableStream({ const stream = new ReadableStream({
@@ -58,20 +63,20 @@ async function host(
}); });
const registration = { async dispose() {} }; const registration = { async dispose() {} };
const replay = () => { const replay = () => {
agents.clear(); registry.clear();
agents.set("build", structuredClone(build)); registry.set("build", structuredClone(build));
transform?.({ transform?.({
get: (id) => agents.get(id), get: (id) => registry.get(id),
list: () => [...agents.values()], list: () => [...registry.values()],
default() {}, default() {},
remove: (id) => { remove: (id) => {
agents.delete(id); registry.delete(id);
}, },
update(id, update) { update(id, update) {
const draft = const draft =
agents.get(id) ?? structuredClone(Agent.Info.default(Agent.ID.make(id))); registry.get(id) ?? structuredClone(Agent.Info.default(Agent.ID.make(id)));
update(draft); update(draft);
agents.set(id, draft); registry.set(id, draft);
}, },
}); });
}; };
@@ -110,7 +115,7 @@ async function host(
}, },
agent: { agent: {
async list() { async list() {
return { data: [...agents.values()] }; return { data: [...registry.values()] };
}, },
async reload() { async reload() {
replay(); replay();
@@ -182,11 +187,8 @@ async function host(
replay(); replay();
const cleanup = await setup(context); const cleanup = await setup(context);
if (cleanup) cleanups.push(cleanup); if (cleanup) cleanups.push(cleanup);
const flush = async () => {
await Bun.sleep(10);
};
return { return {
agents, agents: registry,
skills, skills,
permissions: () => permissions(), permissions: () => permissions(),
async configure(rules: Agent.Info["permissions"]) { async configure(rules: Agent.Info["permissions"]) {
@@ -195,7 +197,7 @@ async function host(
controller.enqueue({ type: "agent.updated" }); controller.enqueue({ type: "agent.updated" });
await flush(); await flush();
}, },
async models(next: ModelInfo[], location = { directory: "/fixture" }) { async models(next: ModelInfo[], location = defaultLocation) {
catalog = next; catalog = next;
controller.enqueue({ type: "model.updated", location }); controller.enqueue({ type: "model.updated", location });
await flush(); await flush();
@@ -205,10 +207,10 @@ async function host(
replayTools(); replayTools();
await flush(); await flush();
}, },
async delegate(agent: string, target: string) { delegate: async (agent: string, target: string) => {
await before({ tool: "subagent", agent, input: { agent: target } }); await before({ tool: "subagent", agent, input: { agent: target } });
}, },
async command(owner: string, target: string) { command: async (owner: string, target: string) => {
parent = owner; parent = owner;
child = target; child = target;
await promptHook({ sessionID: "child" }); await promptHook({ sessionID: "child" });
@@ -231,7 +233,7 @@ async function host(
test("worker availability, deep fallback, and model refresh remain provider aware", async () => { test("worker availability, deep fallback, and model refresh remain provider aware", async () => {
const h = await host(); const h = await host();
expect([...h.skills.keys()].sort()).toEqual(["anti-overengineering", "task-planning"]); expect([...h.skills.keys()].toSorted()).toEqual(["anti-overengineering", "task-planning"]);
expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra"); expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra");
await h.models(models.slice(0, 2)); await h.models(models.slice(0, 2));
expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol"); expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol");
@@ -256,7 +258,7 @@ test("assignments are provider-qualified with optional deep pair and variant; pa
const shallow = Object.fromEntries( const shallow = Object.fromEntries(
Object.entries(agents).filter(([name]) => !name.startsWith("deep-")), Object.entries(agents).filter(([name]) => !name.startsWith("deep-")),
); );
const duplicate = models.map((model) => ({ ...model, providerID: Provider.ID.make("other") })); const duplicate = models.map((entry) => ({ ...entry, providerID: Provider.ID.make("other") }));
const h = await host([...duplicate, ...models], { agents: shallow }); const h = await host([...duplicate, ...models], { agents: shallow });
expect(String(h.agents.get("coordinate")?.model?.providerID)).toBe("test"); expect(String(h.agents.get("coordinate")?.model?.providerID)).toBe("test");
expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol"); expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol");
@@ -295,6 +297,6 @@ test("native tool and command paths retain core delegation restrictions", async
expect( expect(
z z
.object({ agent: z.object({ type: z.string(), enum: z.array(z.string()) }) }) .object({ agent: z.object({ type: z.string(), enum: z.array(z.string()) }) })
.parse((await h.request("coordinate")).subagent?.input.properties).agent, .parse((await h.request("coordinate"))["subagent"]?.input["properties"]).agent,
).toEqual({ type: "string", enum: ["fast-lo", "fast-hi", "good-lo", "good-hi"] }); ).toEqual({ type: "string", enum: ["fast-lo", "fast-hi", "good-lo", "good-hi"] });
}); });
+4 -6
View File
@@ -1,7 +1,7 @@
import { expect, test } from "bun:test"; import { expect, test } from "bun:test";
import type { Plugin } from "@opencode/plugin"; import type { Plugin } from "@opencode/plugin";
import quota from "../src/quota-plugin.js"; import quota from "../src/quota/quota-plugin.js";
import { QuotaRpc } from "../src/quota-rpc.js"; import { QuotaRpc } from "../src/quota/quota-rpc.js";
test("Quota loads independently and retains its RPC ID and nullable status", async () => { test("Quota loads independently and retains its RPC ID and nullable status", async () => {
let controller: ReadableStreamDefaultController<unknown>; let controller: ReadableStreamDefaultController<unknown>;
@@ -18,9 +18,7 @@ test("Quota loads independently and retains its RPC ID and nullable status", asy
location: { directory: "/fixture" }, location: { directory: "/fixture" },
integration: { integration: {
connection: { connection: {
async active() { async active() {},
return undefined;
},
}, },
}, },
event: { event: {
@@ -56,7 +54,7 @@ test("Quota loads independently and retains its RPC ID and nullable status", asy
) => ReturnType<typeof quota.setup>; ) => ReturnType<typeof quota.setup>;
const cleanup = await setup(context); const cleanup = await setup(context);
expect(quota.id).toBe("stanp-opencode.quota"); expect(quota.id).toBe("stanp-opencode.quota");
expect(await status!()).toBeNull(); expect(await status?.()).toBeNull();
expect(modelHook).toBe(true); expect(modelHook).toBe(true);
if (cleanup) await cleanup(); if (cleanup) await cleanup();
expect(disposed).toBe(true); expect(disposed).toBe(true);
+3 -3
View File
@@ -1,6 +1,6 @@
import { expect, test } from "bun:test"; import { expect, test } from "bun:test";
import type { Schema } from "effect"; import type { Schema } from "effect";
import { normalizeQuota, QuotaTracker } from "../src/quota.js"; import { normalizeQuota, QuotaTracker } from "../src/quota/quota.js";
const plus = { const plus = {
plan_type: "plus", plan_type: "plus",
@@ -186,8 +186,8 @@ function fixture(
changes: () => changes, changes: () => changes,
headers, headers,
stored, stored,
switch(credential: typeof current) { switch(next: typeof current) {
current = credential; current = next;
}, },
logout: () => { logout: () => {
current = undefined; current = undefined;
+2 -2
View File
@@ -4,7 +4,7 @@ import type { Route, SlotMap } from "@opencode/plugin/tui/context";
import { testRender, type JSX } from "@opentui/solid"; import { testRender, type JSX } from "@opentui/solid";
import { createSignal } from "solid-js"; import { createSignal } from "solid-js";
import { build } from "../scripts/build.js"; import { build } from "../scripts/build.js";
import type { QuotaStatus } from "../src/quota.js"; import type { QuotaStatus } from "../src/quota/quota.js";
type SidebarSlotRender = (input: { readonly sessionID: string }) => JSX.Element; type SidebarSlotRender = (input: { readonly sessionID: string }) => JSX.Element;
type HomeSlotRender = (input: SlotMap["prompt.footer"]) => JSX.Element; type HomeSlotRender = (input: SlotMap["prompt.footer"]) => JSX.Element;
@@ -27,7 +27,7 @@ const status = (plan: string, remaining: number): QuotaStatus => ({
test("built quota slot stays reactive across pending, empty, failure, update, and session states", async () => { test("built quota slot stays reactive across pending, empty, failure, update, and session states", async () => {
await build(); await build();
// Resolve the built bundle at runtime; tsc runs before build creates dist/tui.js. // Resolve the built bundle at runtime; tsc runs before build creates dist/tui.js.
const tui: typeof import("../src/tui.js") = await import( const tui: typeof import("../src/quota/tui.js") = await import(
new URL("../dist/tui.js", import.meta.url).href new URL("../dist/tui.js", import.meta.url).href
); );
const { default: plugin } = tui; const { default: plugin } = tui;
+4
View File
@@ -9,6 +9,10 @@
"noUncheckedIndexedAccess": true, "noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true, "exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"allowUnreachableCode": false,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"verbatimModuleSyntax": true, "verbatimModuleSyntax": true,