fix: restore lost delegation code, switch CI to Bun, and clean up unused files (#163)

* feat: add background agents and background bash processes (#161)

Add async background delegation system (delegate, delegation_read,
delegation_list) for read-only research that persists to disk and
notifies the session on completion. Extend bash tool with background
mode for long-running processes (dev servers, watchers) with companion
process_logs, process_stop, and process_list tools.

Cherry-picked from a10a337 — lost during merge of cursor/agent-new-architecture-b3d5.

* feat: add prompt queuing with follow-ups UI

Allow users to submit messages while the agent is processing. Queued
messages display in a follow-ups panel above the prompt and are
processed sequentially after the current response completes.

Cherry-picked from 299023b — lost during merge of cursor/agent-new-architecture-b3d5.

* chore: switch CI to Bun, remove unused files and dead code

- Update security workflow to use Bun instead of npm (fixes ERESOLVE peer dependency conflict)
- Delete unused files: hello.py, package-lock.json, .eslintrc.js
- Remove broken ESLint config and devDependencies (lint was non-functional)
- Remove unused exports: MODEL_GROUPS, Skill interface, formatDuration

* chore: update lockfile after removing ESLint dependencies

* fix: use ref for mode color to prevent stale closure in message borders

* feat: add Biome for linting and formatting, update CI workflow

- Add Biome as linter and formatter with project-appropriate config
- Add lint, format, format:fix, and lint:fix scripts to package.json
- Rename typecheck workflow to CI, switch from npm to Bun, add format
  and lint steps alongside typecheck
- Auto-fix formatting and import ordering across all source files

* fix: improve cancellation flow and queued message editing

* fix: improve cancellation flow and prompt footer context display

* chore: update Bun version and refresh lockfile
This commit is contained in:
Ismail Pelaseyed authored and GitHub committed 2026-03-19 15:22:43 +01:00
1 parent 85c2b7caf4
commit 92505acc66
22 files changed
+1334 -5751

No files matched your search

-16
View File
@@ -1,16 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
],
env: {
node: true,
es6: true,
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
};
+6 -7
View File
@@ -13,19 +13,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
node-version: '18'
cache: 'npm'
bun-version: 1.3.11
- name: Install Dependencies
run: npm ci
run: bun install --frozen-lockfile
- name: Run Security Audit
run: npm audit --audit-level=high
run: bun pm untrusted
- name: Scan for Secrets
uses: trufflesecurity/trufflehog@v3.90.1
+15 -10
View File
@@ -1,4 +1,4 @@
name: Type Check
name: CI
on:
push:
@@ -7,20 +7,25 @@ on:
branches: [ main, develop ]
jobs:
typecheck:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
node-version: '18'
cache: 'npm'
bun-version: 1.3.11
- name: Install Dependencies
run: npm ci
run: bun install --frozen-lockfile
- name: Run TypeScript Type Check
run: npm run typecheck
- name: Format Check
run: bun run format
- name: Lint
run: bun run lint
- name: Type Check
run: bun run typecheck
+51
View File
@@ -0,0 +1,51 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.8/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"includes": ["**", "!!**/dist"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 120
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "error",
"noArrayIndexKey": "warn"
},
"correctness": {
"noUnusedFunctionParameters": "warn"
},
"complexity": {
"noForEach": "off"
},
"style": {
"noNonNullAssertion": "off",
"useNodejsImportProtocol": "off"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"trailingCommas": "all"
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}
+20 -240
View File
@@ -15,12 +15,10 @@
"zod": "^4.3.6",
},
"devDependencies": {
"@biomejs/biome": "^2.4.8",
"@types/diff": "^8.0.0",
"@types/node": "^22.0.0",
"@types/react": "^19.1.0",
"@typescript-eslint/eslint-plugin": "^8.37.0",
"@typescript-eslint/parser": "^8.37.0",
"eslint": "^9.31.0",
"typescript": "^5.8.0",
},
},
@@ -36,34 +34,26 @@
"@ai-sdk/xai": ["@ai-sdk/xai@3.0.67", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.35", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-KQQIDc91dUA5IGFMnXBuvPBeraYNTdpDC1qUS+JG8vE+/299//5sZFafI1kKYUu3f3p7LaZrKXYgZ1Ni7QIRbw=="],
"@biomejs/biome": ["@biomejs/biome@2.4.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.8", "@biomejs/cli-darwin-x64": "2.4.8", "@biomejs/cli-linux-arm64": "2.4.8", "@biomejs/cli-linux-arm64-musl": "2.4.8", "@biomejs/cli-linux-x64": "2.4.8", "@biomejs/cli-linux-x64-musl": "2.4.8", "@biomejs/cli-win32-arm64": "2.4.8", "@biomejs/cli-win32-x64": "2.4.8" }, "bin": { "biome": "bin/biome" } }, "sha512-ponn0oKOky1oRXBV+rlSaUlixUxf1aZvWC19Z41zBfUOUesthrQqL3OtiAlSB1EjFjyWpn98Q64DHelhA6jNlA=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ARx0tECE8I7S2C2yjnWYLNbBdDoPdq3oyNLhMglmuctThwUsuzFWRKrHmIGwIRWKz0Mat9DuzLEDp52hGnrxGQ=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Jg9/PsB9vDCJlANE8uhG7qDhb5w0Ix69D7XIIc8IfZPUoiPrbLm33k2Ig3NOJ/7nb3UbesFz3D1aDKm9DvzjhQ=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-5CdrsJct76XG2hpKFwXnEtlT1p+4g4yV+XvvwBpzKsTNLO9c6iLlAxwcae2BJ7ekPGWjNGw9j09T5KGPKKxQig=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-Zo9OhBQDJ3IBGPlqHiTISloo5H0+FBIpemqIJdW/0edJ+gEcLR+MZeZozcUyz3o1nXkVA7++DdRKQT0599j9jA=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.8", "", { "os": "linux", "cpu": "x64" }, "sha512-PdKXspVEaMCQLjtZCn6vfSck/li4KX9KGwSDbZdgIqlrizJ2MnMcE3TvHa2tVfXNmbjMikzcfJpuPWH695yJrw=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.8", "", { "os": "linux", "cpu": "x64" }, "sha512-Gi8quv8MEuDdKaPFtS2XjEnMqODPsRg6POT6KhoP+VrkNb+T2ywunVB+TvOU0LX1jAZzfBr+3V1mIbBhzAMKvw=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-LoFatS0tnHv6KkCVpIy3qZCih+MxUMvdYiPWLHRri7mhi2vyOOs8OrbZBcLTUEWCS+ktO72nZMy4F96oMhkOHQ=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.8", "", { "os": "win32", "cpu": "x64" }, "sha512-vAn7iXDoUbqFXqVocuq1sMYAd33p8+mmurqJkWl6CtIhobd/O6moe4rY5AJvzbunn/qZCdiDVcveqtkFh1e7Hg=="],
"@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
"@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
"@eslint/js": ["@eslint/js@9.35.0", "", {}, "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@jimp/core": ["@jimp/core@1.6.0", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="],
"@jimp/diff": ["@jimp/diff@1.6.0", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="],
@@ -120,12 +110,6 @@
"@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@opentui/core": ["@opentui/core@0.1.88", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.88", "@opentui/core-darwin-x64": "0.1.88", "@opentui/core-linux-arm64": "0.1.88", "@opentui/core-linux-x64": "0.1.88", "@opentui/core-win32-arm64": "0.1.88", "@opentui/core-win32-x64": "0.1.88", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-eaDVZfAzZraddOIkgWSHMVkyaY0O20foYnPWKPQx1TY4t7G1oatIoan2zkytx67epW+4BZQ9vGib+61/uNM1MA=="],
@@ -150,66 +134,26 @@
"@types/diff": ["@types/diff@8.0.0", "", { "dependencies": { "diff": "*" } }, "sha512-o7jqJM04gfaYrdCecCVMbZhNdG6T1MHg/oQoRFdERLV+4d+V7FijhiEAbFu0Usww84Yijk9yH58U4Jk4HbtzZw=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.43.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/type-utils": "8.43.0", "@typescript-eslint/utils": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.43.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.43.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.43.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.43.0", "@typescript-eslint/types": "^8.43.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0" } }, "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.43.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/utils": "8.43.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.43.0", "", {}, "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.43.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.43.0", "@typescript-eslint/tsconfig-utils": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.43.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw=="],
"@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="],
"@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="],
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
"acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ai": ["ai@6.0.116", "", { "dependencies": { "@ai-sdk/gateway": "3.0.66", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"await-to-js": ["await-to-js@3.0.0", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"bun-ffi-structs": ["bun-ffi-structs@0.1.2", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-Lh1oQAYHDcnesJauieA4UNkWGXY9hYck7OA5IaRwE3Bp6K2F2pJSNYqq+hIy7P3uOvo3km3oxS8304g5gDMl/w=="],
@@ -224,48 +168,14 @@
"bun-webgpu-win32-x64": ["bun-webgpu-win32-x64@0.1.5", "", { "os": "win32", "cpu": "x64" }, "sha512-zvnUl4EAsQbKsmZVu+lEJcH8axQ7MiCfqg2OmnHd6uw1THABmHaX0GbpKiHshdgadNN2Nf+4zDyTJB5YMcAdrA=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="],
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.35.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.35.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": "bin/eslint.js" }, "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
@@ -274,132 +184,44 @@
"exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="],
"jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"parse-bmfont-ascii": ["parse-bmfont-ascii@1.0.6", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="],
"parse-bmfont-binary": ["parse-bmfont-binary@1.0.6", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="],
"parse-bmfont-xml": ["parse-bmfont-xml@1.1.6", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="],
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"pixelmatch": ["pixelmatch@5.3.0", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="],
"planck": ["planck@1.4.3", "", { "peerDependencies": { "stage-js": "^1.0.0-alpha.12" } }, "sha512-B+lHKhRSeg7vZOfEyEzyQVu7nx8JHcX3QgnAcHXrPW0j04XYKX5eXSiUrxH2Z5QR8OoqvjD6zKIaPMdMYAd0uA=="],
"pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-devtools-core": ["react-devtools-core@7.0.1", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-C3yNvRHaizlpiASzy7b9vbnBGLrhvdhl1CbdU6EnZgxPNbai60szdLtl+VL76UNOt5bOoVTOz5rNWZxgGt+Gsw=="],
@@ -410,24 +232,12 @@
"readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
"semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
"simple-xml-to-json": ["simple-xml-to-json@1.2.4", "", {}, "sha512-3MY16e0ocMHL7N1ufpdObURGyX+lCo0T/A+y6VCwosLdH1HSda4QZl1Sdt/O+2qWp48WFi26XEp5rF0LoaL0Dg=="],
@@ -436,38 +246,22 @@
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"three": ["three@0.177.0", "", {}, "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg=="],
"tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"token-types": ["token-types@4.2.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="],
"web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="],
@@ -476,16 +270,10 @@
"xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="],
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"@jimp/plugin-blit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"@jimp/plugin-circle/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
@@ -520,18 +308,10 @@
"@opentui/core/diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"image-q/@types/node": ["@types/node@16.9.1", "", {}, "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="],
"pixelmatch/pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="],
"react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
}
}
-5
View File
@@ -1,5 +0,0 @@
def hello_world():
print("Hello, World!")
if __name__ == "__main__":
hello_world()
-4787
View File
File diff suppressed because it is too large. Load diff
+12 -11
View File
@@ -17,8 +17,11 @@
"dev": "bun run src/index.ts",
"build": "tsc",
"start": "bun run dist/index.js",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"lint": "biome check src/",
"format": "biome format src/",
"format:fix": "biome format --write src/",
"lint:fix": "biome check --fix src/"
},
"keywords": [
"cli",
@@ -36,20 +39,18 @@
"@opentui/core": "^0.1.88",
"@opentui/react": "^0.1.88",
"ai": "^6.0.116",
"commander": "^12.0.0",
"commander": "^12.1.0",
"diff": "^8.0.3",
"dotenv": "^16.4.0",
"react": "^19.1.0",
"dotenv": "^16.6.1",
"react": "^19.2.4",
"zod": "^4.3.6"
},
"devDependencies": {
"@biomejs/biome": "^2.4.8",
"@types/diff": "^8.0.0",
"@types/node": "^22.0.0",
"@types/react": "^19.1.0",
"@typescript-eslint/eslint-plugin": "^8.37.0",
"@typescript-eslint/parser": "^8.37.0",
"eslint": "^9.31.0",
"typescript": "^5.8.0"
"@types/node": "^22.19.15",
"@types/react": "^19.2.14",
"typescript": "^5.9.3"
},
"engines": {
"node": ">=18.0.0"
+120 -23
View File
@@ -1,9 +1,7 @@
import { streamText, stepCountIs, type ModelMessage } from "ai";
import { DelegationManager } from "./delegations.js";
import { type ModelMessage, stepCountIs, streamText } from "ai";
import { createProvider, generateTitle as genTitle, type XaiProvider } from "../grok/client.js";
import { createTools } from "../grok/tools.js";
import { BashTool } from "../tools/bash.js";
import { loadCustomInstructions } from "../utils/instructions.js";
import type {
AgentMode,
Plan,
@@ -13,6 +11,8 @@ import type {
ToolCall,
ToolResult,
} from "../types/index.js";
import { loadCustomInstructions } from "../utils/instructions.js";
import { DelegationManager } from "./delegations.js";
const MAX_TOOL_ROUNDS = 400;
@@ -167,6 +167,7 @@ export class Agent {
private bash: BashTool;
private delegations: DelegationManager;
private messages: ModelMessage[] = [];
private recordedTokens = 0;
private abortController: AbortController | null = null;
private maxToolRounds: number;
private mode: AgentMode = "agent";
@@ -201,6 +202,7 @@ export class Agent {
if (mode !== this.mode) {
this.mode = mode;
this.messages = [];
this.recordedTokens = 0;
}
}
@@ -212,16 +214,42 @@ export class Agent {
return this.bash.getCwd();
}
getContextStats(
contextWindow: number,
inFlightText = "",
): {
contextWindow: number;
usedTokens: number;
remainingTokens: number;
ratioUsed: number;
ratioRemaining: number;
} {
const system = buildSystemPrompt(this.bash.getCwd(), this.mode, this.planContext);
const estimatedTokens = estimateTokens(`${system}\n${JSON.stringify(this.messages)}\n${inFlightText}`);
const usedTokens = Math.min(contextWindow, Math.max(estimatedTokens, this.recordedTokens));
const remainingTokens = Math.max(0, contextWindow - usedTokens);
return {
contextWindow,
usedTokens,
remainingTokens,
ratioUsed: usedTokens / contextWindow,
ratioRemaining: remainingTokens / contextWindow,
};
}
async generateTitle(userMessage: string): Promise<string> {
return genTitle(this.provider, userMessage);
}
abort(): void {
this.abortController?.abort();
this.emitSubagentStatus(null);
}
clearHistory(): void {
this.messages = [];
this.recordedTokens = 0;
}
onSubagentStatus(listener: (status: SubagentStatus | null) => void): () => void {
@@ -237,6 +265,21 @@ export class Agent {
}
}
private discardAbortedTurn(userMessage: ModelMessage): void {
const idx = this.messages.lastIndexOf(userMessage);
if (idx >= 0) {
this.messages.splice(idx, 1);
}
}
private recordUsage(usage?: { totalTokens?: number; inputTokens?: number; outputTokens?: number }): void {
if (!usage) return;
const total = usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
if (Number.isFinite(total) && total > 0) {
this.recordedTokens += total;
}
}
async consumeBackgroundNotifications(): Promise<string[]> {
try {
const notifications = await this.delegations.consumeNotifications();
@@ -252,7 +295,9 @@ export class Agent {
async runTaskRequest(
request: TaskRequest,
onActivity?: (detail: string) => void,
abortSignal?: AbortSignal,
): Promise<ToolResult> {
const signal = abortSignal;
const childMode: AgentMode = request.agent === "explore" ? "ask" : "agent";
const childBash = new BashTool(this.bash.getCwd());
const childTools = createTools(childBash, this.provider, childMode);
@@ -270,12 +315,19 @@ export class Agent {
tools: childTools,
stopWhen: stepCountIs(Math.min(this.maxToolRounds, request.agent === "explore" ? 60 : 120)),
maxRetries: 0,
abortSignal: this.abortController?.signal,
abortSignal: signal,
temperature: request.agent === "explore" ? 0.2 : 0.5,
maxOutputTokens: Math.min(this.maxTokens, 8_192),
onFinish: ({ totalUsage }) => {
this.recordUsage(totalUsage);
},
});
for await (const part of result.fullStream) {
if (signal?.aborted) {
break;
}
if (part.type === "text-delta") {
assistantText += part.text;
continue;
@@ -287,6 +339,10 @@ export class Agent {
}
}
if (signal?.aborted) {
return { success: false, output: "[Cancelled]" };
}
await result.response;
const output = assistantText.trim() || `Task completed. Last action: ${lastActivity}`;
@@ -301,6 +357,7 @@ export class Agent {
},
};
} catch (err: unknown) {
if (signal?.aborted) throw err;
const msg = err instanceof Error ? err.message : String(err);
const output = `Task failed: ${msg}`;
return {
@@ -316,28 +373,38 @@ export class Agent {
}
}
private async runTask(request: TaskRequest): Promise<ToolResult> {
private async runTask(request: TaskRequest, abortSignal?: AbortSignal): Promise<ToolResult> {
try {
return await this.runTaskRequest(request, (detail) => {
this.emitSubagentStatus({
agent: request.agent,
description: request.description,
detail,
});
});
return await this.runTaskRequest(
request,
(detail) => {
if (abortSignal?.aborted) return;
this.emitSubagentStatus({
agent: request.agent,
description: request.description,
detail,
});
},
abortSignal,
);
} finally {
this.emitSubagentStatus(null);
}
}
private async runDelegation(request: TaskRequest): Promise<ToolResult> {
private async runDelegation(request: TaskRequest, abortSignal?: AbortSignal): Promise<ToolResult> {
try {
if (abortSignal?.aborted) {
return { success: false, output: "[Cancelled]" };
}
return await this.delegations.start(request, {
model: this.modelId,
maxToolRounds: this.maxToolRounds,
maxTokens: this.maxTokens,
});
} catch (err: unknown) {
if (abortSignal?.aborted) throw err;
const msg = err instanceof Error ? err.message : String(err);
return {
success: false,
@@ -391,18 +458,20 @@ export class Agent {
async *processMessage(userMessage: string): AsyncGenerator<StreamChunk, void, unknown> {
this.abortController = new AbortController();
const signal = this.abortController.signal;
this.emitSubagentStatus(null);
await this.consumeBackgroundNotifications();
this.messages.push({ role: "user", content: userMessage });
const userModelMessage: ModelMessage = { role: "user", content: userMessage };
this.messages.push(userModelMessage);
let assistantText = "";
let streamOk = false;
try {
const tools = createTools(this.bash, this.provider, this.mode, {
runTask: (request) => this.runTask(request),
runDelegation: (request) => this.runDelegation(request),
runTask: (request, abortSignal) => this.runTask(request, abortSignal ?? signal),
runDelegation: (request, abortSignal) => this.runDelegation(request, abortSignal ?? signal),
readDelegation: (id) => this.readDelegation(id),
listDelegations: () => this.listDelegations(),
});
@@ -416,13 +485,16 @@ export class Agent {
tools,
stopWhen: stepCountIs(this.maxToolRounds),
maxRetries: 0,
abortSignal: this.abortController.signal,
abortSignal: signal,
temperature: 0.7,
maxOutputTokens: this.maxTokens,
onFinish: ({ totalUsage }) => {
this.recordUsage(totalUsage);
},
});
for await (const part of result.fullStream) {
if (this.abortController.signal.aborted) {
if (signal.aborted) {
yield { type: "content", content: "\n\n[Cancelled]" };
break;
}
@@ -457,35 +529,56 @@ export class Agent {
case "error":
yield { type: "error", content: String(part.error) };
break;
case "abort":
yield { type: "content", content: "\n\n[Cancelled]" };
break;
}
}
if (signal.aborted) {
this.discardAbortedTurn(userModelMessage);
yield { type: "done" };
return;
}
try {
const response = await result.response;
this.messages.push(...response.messages);
streamOk = true;
if (!signal.aborted) {
this.messages.push(...response.messages);
streamOk = true;
}
} catch {
// response promise can fail after stream errors — fall back to manual message
}
if (signal.aborted) {
this.discardAbortedTurn(userModelMessage);
yield { type: "done" };
return;
}
if (!streamOk && assistantText.trim()) {
this.messages.push({ role: "assistant", content: assistantText });
}
yield { type: "done" };
} catch (err: unknown) {
if (this.abortController.signal.aborted) {
if (signal.aborted) {
this.discardAbortedTurn(userModelMessage);
yield { type: "content", content: "\n\n[Cancelled]" };
} else {
const msg = err instanceof Error ? err.message : String(err);
yield { type: "error", content: `Error: ${msg}` };
}
if (assistantText.trim()) {
if (!signal.aborted && assistantText.trim()) {
this.messages.push({ role: "assistant", content: assistantText });
}
yield { type: "done" };
} finally {
this.abortController = null;
if (this.abortController?.signal === signal) {
this.abortController = null;
}
}
}
}
@@ -553,3 +646,7 @@ function firstLine(text: string): string {
function truncate(text: string, max: number): string {
return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
}
function estimateTokens(text: string): number {
return Math.ceil(text.length / 4);
}
+12 -51
View File
@@ -3,46 +3,13 @@ import { createHash } from "crypto";
import { promises as fs } from "fs";
import os from "os";
import path from "path";
import type { DelegationRun, DelegationStatus, TaskRequest, ToolResult } from "../types/index.js";
import type { DelegationRun, DelegationStatus, TaskRequest, ToolResult } from "../types/index";
const ID_ADJECTIVES = [
"brisk",
"calm",
"clever",
"eager",
"gentle",
"keen",
"lively",
"nimble",
"quiet",
"steady",
];
const ID_ADJECTIVES = ["brisk", "calm", "clever", "eager", "gentle", "keen", "lively", "nimble", "quiet", "steady"];
const ID_COLORS = [
"amber",
"blue",
"copper",
"emerald",
"indigo",
"ivory",
"silver",
"teal",
"violet",
"white",
];
const ID_COLORS = ["amber", "blue", "copper", "emerald", "indigo", "ivory", "silver", "teal", "violet", "white"];
const ID_ANIMALS = [
"badger",
"falcon",
"fox",
"heron",
"lynx",
"otter",
"owl",
"panda",
"sparrow",
"wolf",
];
const ID_ANIMALS = ["badger", "falcon", "fox", "heron", "lynx", "otter", "owl", "panda", "sparrow", "wolf"];
export interface StoredDelegation {
id: string;
@@ -217,11 +184,7 @@ export async function loadDelegation(jobPath: string): Promise<StoredDelegation>
return record;
}
export async function completeDelegation(
jobPath: string,
output: string,
fallbackSummary?: string,
): Promise<void> {
export async function completeDelegation(jobPath: string, output: string, fallbackSummary?: string): Promise<void> {
const record = await loadDelegation(jobPath);
record.status = "complete";
record.completedAt = new Date().toISOString();
@@ -306,7 +269,11 @@ function resolveCliArgs(): string[] {
}
function getProjectId(cwd: string): string {
const base = path.basename(cwd).replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "project";
const base =
path
.basename(cwd)
.replace(/[^a-zA-Z0-9._-]+/g, "-")
.replace(/^-+|-+$/g, "") || "project";
const hash = createHash("sha1").update(cwd).digest("hex").slice(0, 10);
return `${base}-${hash}`;
}
@@ -359,11 +326,7 @@ function formatNotification(record: StoredDelegation): string {
const title = record.title || record.description || record.id;
const summary = record.summary || (record.error ? createSummary(record.error) : "No summary available.");
const statusText = record.status === "complete" ? "complete" : "failed";
const lines = [
`Background agent ${statusText}: \`${record.id}\``,
`Title: ${title}`,
`Summary: ${summary}`,
];
const lines = [`Background agent ${statusText}: \`${record.id}\``, `Title: ${title}`, `Summary: ${summary}`];
if (record.error) {
lines.push(`Error: ${record.error}`);
@@ -378,9 +341,7 @@ function toDelegationRun(record: StoredDelegation): DelegationRun {
id: record.id,
agent: "explore",
description: record.description,
summary:
record.summary ||
(record.status === "running" ? "Running in the background." : "No summary available."),
summary: record.summary || (record.status === "running" ? "Running in the background." : "No summary available."),
status: record.status,
};
}
+1 -4
View File
@@ -10,10 +10,7 @@ export function createProvider(apiKey: string, baseURL?: string): XaiProvider {
});
}
export async function generateTitle(
provider: XaiProvider,
userMessage: string,
): Promise<string> {
export async function generateTitle(provider: XaiProvider, userMessage: string): Promise<string> {
try {
const { text } = await generateText({
model: provider("grok-3-mini-fast"),
+2 -17
View File
@@ -1,4 +1,4 @@
import type { ModelInfo } from "../types/index.js";
import type { ModelInfo } from "../types/index";
export const MODELS: ModelInfo[] = [
{
@@ -66,21 +66,6 @@ export const MODELS: ModelInfo[] = [
},
];
export const MODEL_GROUPS: { category: string; models: string[] }[] = [
{
category: "Grok 4",
models: ["grok-4-0709", "grok-4.20-beta-0309", "grok-4-fast", "grok-4-1-fast"],
},
{
category: "Grok Code",
models: ["grok-code-fast-1"],
},
{
category: "Grok 3",
models: ["grok-3", "grok-3-mini"],
},
];
export const DEFAULT_MODEL = "grok-4-1-fast";
export function getModelInfo(modelId: string): ModelInfo | undefined {
@@ -89,4 +74,4 @@ export function getModelInfo(modelId: string): ModelInfo | undefined {
export function getModelIds(): string[] {
return MODELS.map((m) => m.id);
}
}
+63 -91
View File
@@ -1,15 +1,15 @@
import { tool, generateText } from "ai";
import { generateText, type ToolSet, tool } from "ai";
import { z } from "zod";
import type { BashTool } from "../tools/bash.js";
import { readFile, writeFile, editFile } from "../tools/file.js";
import type { XaiProvider } from "./client.js";
import { editFile, readFile, writeFile } from "../tools/file.js";
import type { AgentMode, TaskRequest, ToolResult } from "../types/index.js";
import type { XaiProvider } from "./client.js";
const SEARCH_MODEL = "grok-3-mini-fast";
interface CreateToolsOptions {
runTask?: (request: TaskRequest) => Promise<ToolResult>;
runDelegation?: (request: TaskRequest) => Promise<ToolResult>;
runTask?: (request: TaskRequest, abortSignal?: AbortSignal) => Promise<ToolResult>;
runDelegation?: (request: TaskRequest, abortSignal?: AbortSignal) => Promise<ToolResult>;
readDelegation?: (id: string) => Promise<ToolResult>;
listDelegations?: () => Promise<ToolResult>;
}
@@ -60,10 +60,7 @@ export function createTools(
"View recent output (stdout + stderr) from a background process by its ID. Returns the last N lines of the log.",
inputSchema: z.object({
id: z.number().describe("The background process ID"),
tail: z
.number()
.optional()
.describe("Number of lines to return from the end (default: 50)"),
tail: z.number().optional().describe("Number of lines to return from the end (default: 50)"),
}),
execute: async ({ id, tail }) => {
return bash.getProcessLogs(id, tail);
@@ -82,8 +79,7 @@ export function createTools(
}),
process_list: tool({
description:
"List all background processes with their ID, status, PID, age, and command.",
description: "List all background processes with their ID, status, PID, age, and command.",
inputSchema: z.object({}),
execute: async () => {
return bash.listProcesses();
@@ -95,14 +91,8 @@ export function createTools(
"Read the contents of a file. Returns numbered lines with a header showing the range and total line count. Use start_line/end_line to read specific sections of large files iteratively.",
inputSchema: z.object({
path: z.string().describe("File path (relative to cwd or absolute)"),
start_line: z
.number()
.optional()
.describe("First line to read (1-indexed, default: 1)"),
end_line: z
.number()
.optional()
.describe("Last line to read (inclusive, default: end of file)"),
start_line: z.number().optional().describe("First line to read (1-indexed, default: 1)"),
end_line: z.number().optional().describe("Last line to read (inclusive, default: end of file)"),
}),
execute: async ({ path, start_line, end_line }) => {
return readFile(path, cwd(), start_line, end_line);
@@ -168,10 +158,9 @@ export function createTools(
}
},
}),
};
const tools: Record<string, any> = { ...base };
const tools: ToolSet = { ...base };
if (mode === "agent") {
tools.write_file = tool({
@@ -204,19 +193,14 @@ export function createTools(
description:
"Delegate a focused foreground task to a sub-agent. Prefer this proactively for review, research, investigation, and code quality work instead of waiting for the user to request a sub-agent. Use `general` for multi-step execution and `explore` for fast read-only investigation. Provide a short description plus a detailed prompt for the child agent.",
inputSchema: z.object({
agent: z
.enum(["general", "explore"])
.default("general")
.describe("Which sub-agent to use"),
agent: z.enum(["general", "explore"]).default("general").describe("Which sub-agent to use"),
description: z
.string()
.describe("A short label for the delegated task, such as 'Deep code quality analysis'"),
prompt: z
.string()
.describe("Detailed instructions for the sub-agent to complete"),
prompt: z.string().describe("Detailed instructions for the sub-agent to complete"),
}),
execute: async ({ agent, description, prompt }) => {
return options.runTask!({ agent, description, prompt });
execute: async ({ agent, description, prompt }, { abortSignal }) => {
return options.runTask!({ agent, description, prompt }, abortSignal);
},
});
}
@@ -230,15 +214,11 @@ export function createTools(
.enum(["explore"])
.default("explore")
.describe("Background delegations currently support only the read-only explore agent"),
description: z
.string()
.describe("A short label for the delegation, such as 'OAuth callback research'"),
prompt: z
.string()
.describe("Detailed instructions for the background agent to complete"),
description: z.string().describe("A short label for the delegation, such as 'OAuth callback research'"),
prompt: z.string().describe("Detailed instructions for the background agent to complete"),
}),
execute: async ({ agent, description, prompt }) => {
return options.runDelegation!({ agent, description, prompt });
execute: async ({ agent, description, prompt }, { abortSignal }) => {
return options.runDelegation!({ agent, description, prompt }, abortSignal);
},
});
}
@@ -271,59 +251,51 @@ export function createTools(
if (mode !== "plan") return tools;
tools.generate_plan = tool({
description:
"Generate an interactive implementation plan with steps and optional questions for the user. The plan is displayed in a structured UI where the user can review steps and answer questions. Always use this tool when creating plans.",
inputSchema: z.object({
title: z.string().describe("Plan title"),
summary: z.string().describe("Brief summary of what the plan accomplishes"),
steps: z
.array(
z.object({
title: z.string().describe("Step title"),
description: z
.string()
.describe("Detailed description of what this step involves"),
filePaths: z
.array(z.string())
.optional()
.describe("Files affected by this step"),
}),
)
.describe("Ordered list of implementation steps"),
questions: z
.array(
z.object({
id: z.string().describe("Unique question identifier"),
question: z.string().describe("The question to ask the user"),
header: z
.string()
.optional()
.describe("Single-word tab label (e.g. 'Format', 'Storage', 'Testing')"),
type: z
.enum(["select", "multiselect", "text"])
.describe("Question type: select (pick one), multiselect (pick many), or text (free-form)"),
options: z
.array(
z.object({
id: z.string().describe("Option identifier"),
label: z.string().describe("Option display text"),
}),
)
.optional()
.describe("Options for select/multiselect questions"),
}),
)
.optional()
.describe("Questions for the user to answer before proceeding"),
}),
execute: async ({ title, summary, steps, questions }) => {
return {
success: true,
output: `Plan "${title}" generated with ${steps.length} steps`,
plan: { title, summary, steps, questions },
};
},
});
description:
"Generate an interactive implementation plan with steps and optional questions for the user. The plan is displayed in a structured UI where the user can review steps and answer questions. Always use this tool when creating plans.",
inputSchema: z.object({
title: z.string().describe("Plan title"),
summary: z.string().describe("Brief summary of what the plan accomplishes"),
steps: z
.array(
z.object({
title: z.string().describe("Step title"),
description: z.string().describe("Detailed description of what this step involves"),
filePaths: z.array(z.string()).optional().describe("Files affected by this step"),
}),
)
.describe("Ordered list of implementation steps"),
questions: z
.array(
z.object({
id: z.string().describe("Unique question identifier"),
question: z.string().describe("The question to ask the user"),
header: z.string().optional().describe("Single-word tab label (e.g. 'Format', 'Storage', 'Testing')"),
type: z
.enum(["select", "multiselect", "text"])
.describe("Question type: select (pick one), multiselect (pick many), or text (free-form)"),
options: z
.array(
z.object({
id: z.string().describe("Option identifier"),
label: z.string().describe("Option display text"),
}),
)
.optional()
.describe("Options for select/multiselect questions"),
}),
)
.optional()
.describe("Questions for the user to answer before proceeding"),
}),
execute: async ({ title, summary, steps, questions }) => {
return {
success: true,
output: `Plan "${title}" generated with ${steps.length} steps`,
plan: { title, summary, steps, questions },
};
},
});
return tools;
}
+17 -24
View File
@@ -1,14 +1,14 @@
#!/usr/bin/env bun
import { program } from "commander";
import * as dotenv from "dotenv";
import { createCliRenderer } from "@opentui/core";
import { createRoot } from "@opentui/react";
import { program } from "commander";
import * as dotenv from "dotenv";
import { createElement } from "react";
import { Agent } from "./agent/agent.js";
import { completeDelegation, failDelegation, loadDelegation } from "./agent/delegations.js";
import { App } from "./ui/app.js";
import { getApiKey, getBaseURL, getCurrentModel, saveUserSettings } from "./utils/settings.js";
import { MODELS } from "./grok/models.js";
import { Agent } from "./agent/agent";
import { completeDelegation, failDelegation, loadDelegation } from "./agent/delegations";
import { MODELS } from "./grok/models";
import { App } from "./ui/app";
import { getApiKey, getBaseURL, getCurrentModel, saveUserSettings } from "./utils/settings";
dotenv.config();
@@ -39,18 +39,15 @@ async function startInteractive(
exitOnCtrlC: false,
});
const onExit = () => { renderer.destroy(); process.exit(0); };
const onExit = () => {
renderer.destroy();
process.exit(0);
};
createRoot(renderer).render(createElement(App, { agent, initialMessage, onExit }));
}
async function runHeadless(
prompt: string,
apiKey: string,
baseURL: string,
model: string,
maxToolRounds: number,
) {
async function runHeadless(prompt: string, apiKey: string, baseURL: string, model: string, maxToolRounds: number) {
const agent = new Agent(apiKey, baseURL, model, maxToolRounds);
process.stdout.write(`\x1b[36m⏳ Processing...\x1b[0m\n`);
@@ -91,15 +88,13 @@ async function runBackgroundDelegation(jobPath: string, options: Record<string,
const delegation = await loadDelegation(jobPath);
const apiKey = options.apiKey || getApiKey();
if (!apiKey) {
throw new Error(
"API key required. Set GROK_API_KEY, use --api-key, or save it to ~/.grok/user-settings.json.",
);
throw new Error("API key required. Set GROK_API_KEY, use --api-key, or save it to ~/.grok/user-settings.json.");
}
const baseURL = options.baseUrl || getBaseURL();
const model = options.model || delegation.model || getCurrentModel();
const maxToolRounds = parseInt(options.maxToolRounds || String(delegation.maxToolRounds), 10)
|| delegation.maxToolRounds;
const maxToolRounds =
parseInt(options.maxToolRounds || String(delegation.maxToolRounds), 10) || delegation.maxToolRounds;
const agent = new Agent(apiKey, baseURL, model, maxToolRounds);
const result = await agent.runTaskRequest({
agent: delegation.agent,
@@ -130,7 +125,7 @@ function resolveConfig(options: Record<string, string | undefined>) {
const apiKey = options.apiKey || getApiKey();
const baseURL = options.baseUrl || getBaseURL();
const model = options.model || getCurrentModel();
const maxToolRounds = parseInt(options.maxToolRounds || "400") || 400;
const maxToolRounds = parseInt(options.maxToolRounds || "400", 10) || 400;
if (!apiKey) {
console.error(
@@ -191,9 +186,7 @@ program
console.log("\nAvailable Grok Models:\n");
for (const m of MODELS) {
const reasoning = m.reasoning ? " (reasoning)" : "";
console.log(
` \x1b[36m${m.id}\x1b[0m — ${m.name}${reasoning}`,
);
console.log(` \x1b[36m${m.id}\x1b[0m — ${m.name}${reasoning}`);
console.log(
` ${m.description} | ${formatContext(m.contextWindow)} context | $${m.inputPrice}/$${m.outputPrice} per 1M tokens`,
);
+33 -12
View File
@@ -1,10 +1,10 @@
import { exec, spawn, type ChildProcess } from "child_process";
import { createWriteStream, createReadStream } from "fs";
import { stat, mkdtemp, readFile, unlink, rm } from "fs/promises";
import { type ChildProcess, exec, spawn } from "child_process";
import { createReadStream, createWriteStream } from "fs";
import { mkdtemp, rm, stat, unlink } from "fs/promises";
import os from "os";
import path from "path";
import { promisify } from "util";
import type { ToolResult } from "../types/index.js";
import type { ToolResult } from "../types/index";
const execAsync = promisify(exec);
@@ -44,7 +44,10 @@ export class BashTool {
async execute(command: string, timeout = 30_000): Promise<ToolResult> {
try {
if (command.startsWith("cd ")) {
const dir = command.substring(3).trim().replace(/^["']|["']$/g, "");
const dir = command
.substring(3)
.trim()
.replace(/^["']|["']$/g, "");
try {
const nextCwd = path.resolve(this.cwd, dir);
const info = await stat(nextCwd);
@@ -74,8 +77,7 @@ export class BashTool {
} catch (err: unknown) {
if (err && typeof err === "object" && "stdout" in err) {
const execErr = err as { stdout?: string; stderr?: string; message: string };
const output =
(execErr.stdout || "") + (execErr.stderr ? `\nSTDERR: ${execErr.stderr}` : "");
const output = (execErr.stdout || "") + (execErr.stderr ? `\nSTDERR: ${execErr.stderr}` : "");
if (output.trim()) {
return { success: false, error: output.trim() };
}
@@ -208,10 +210,17 @@ export class BashTool {
entry.child.kill("SIGTERM");
await new Promise<void>((resolve) => {
const timeout = setTimeout(() => {
try { entry.child.kill("SIGKILL"); } catch { /* already dead */ }
try {
entry.child.kill("SIGKILL");
} catch {
/* already dead */
}
resolve();
}, 3_000);
entry.child.on("exit", () => { clearTimeout(timeout); resolve(); });
entry.child.on("exit", () => {
clearTimeout(timeout);
resolve();
});
});
return {
@@ -245,13 +254,25 @@ export class BashTool {
async cleanup(): Promise<void> {
for (const entry of this.bgProcesses.values()) {
if (entry.alive) {
try { entry.child.kill("SIGTERM"); } catch { /* */ }
try {
entry.child.kill("SIGTERM");
} catch {
/* */
}
}
try {
await unlink(entry.logPath);
} catch {
/* */
}
try { await unlink(entry.logPath); } catch { /* */ }
}
this.bgProcesses.clear();
if (this.tmpDir) {
try { await rm(this.tmpDir, { recursive: true, force: true }); } catch { /* */ }
try {
await rm(this.tmpDir, { recursive: true, force: true });
} catch {
/* */
}
}
}
+3 -8
View File
@@ -1,6 +1,6 @@
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
import { dirname, resolve, isAbsolute } from "path";
import { createTwoFilesPatch } from "diff";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import { dirname, isAbsolute, resolve } from "path";
export interface FileDiff {
filePath: string;
@@ -79,12 +79,7 @@ export function writeFile(filePath: string, content: string, cwd: string): FileR
}
}
export function editFile(
filePath: string,
oldString: string,
newString: string,
cwd: string,
): FileResult {
export function editFile(filePath: string, oldString: string, newString: string, cwd: string): FileResult {
try {
const full = resolvePath(filePath, cwd);
if (!existsSync(full)) {
-7
View File
@@ -111,13 +111,6 @@ export interface ModelInfo {
description: string;
}
export interface Skill {
id: string;
title: string;
description: string;
executable?: boolean;
}
export type AgentMode = "agent" | "plan" | "ask";
export const MODES: { id: AgentMode; label: string; color: string }[] = [
+937 -327
View File
File diff suppressed because it is too large. Load diff
+4 -10
View File
@@ -1,6 +1,6 @@
import React, { useMemo } from "react";
import { SyntaxStyle, RGBA } from "@opentui/core";
import type { Theme } from "./theme.js";
import { RGBA, SyntaxStyle } from "@opentui/core";
import { useMemo } from "react";
import type { Theme } from "./theme";
function buildSyntaxStyle(t: Theme): SyntaxStyle {
return SyntaxStyle.fromStyles({
@@ -36,12 +36,6 @@ export function Markdown({ content, t }: { content: string; t: Theme }) {
const syntaxStyle = useMemo(() => buildSyntaxStyle(t), [t]);
return (
<markdown
content={content}
syntaxStyle={syntaxStyle}
conceal={true}
tableOptions={TABLE_OPTIONS}
flexShrink={0}
/>
<markdown content={content} syntaxStyle={syntaxStyle} conceal={true} tableOptions={TABLE_OPTIONS} flexShrink={0} />
);
}
+32 -90
View File
@@ -1,6 +1,5 @@
import React from "react";
import type { Plan, PlanQuestion } from "../types/index.js";
import type { Theme } from "./theme.js";
import type { Plan, PlanQuestion } from "../types/index";
import type { Theme } from "./theme";
export type PlanAnswers = Record<string, string | string[]>;
@@ -17,7 +16,10 @@ export function PlanView({ plan, t }: PlanViewProps) {
<box marginBottom={1}>
<text>
<span style={{ fg: t.planTitle }}>
<b>{"◆ "}{plan.title}</b>
<b>
{"◆ "}
{plan.title}
</b>
</span>
</text>
</box>
@@ -93,11 +95,7 @@ interface PlanQuestionsPanelProps {
state: PlanQuestionsState;
}
export function PlanQuestionsPanel({
t,
questions,
state,
}: PlanQuestionsPanelProps) {
export function PlanQuestionsPanel({ t, questions, state }: PlanQuestionsPanelProps) {
const isSingle = questions.length === 1 && questions[0]?.type !== "multiselect";
const isConfirmTab = !isSingle && state.tab === questions.length;
const q = questions[state.tab];
@@ -126,11 +124,7 @@ export function PlanQuestionsPanel({
<text key={q.id}>
<span
style={{
fg: isActive
? t.planTitle
: isAnswered
? t.planOptionCheck
: t.textMuted,
fg: isActive ? t.planTitle : isAnswered ? t.planOptionCheck : t.textMuted,
}}
>
{isActive ? <b>{label}</b> : label}
@@ -155,11 +149,7 @@ export function PlanQuestionsPanel({
{isConfirmTab ? (
<ConfirmView t={t} questions={questions} answers={state.answers} />
) : q ? (
<QuestionBody
t={t}
question={q}
state={state}
/>
<QuestionBody t={t} question={q} state={state} />
) : null}
{/* Footer hints */}
@@ -177,13 +167,7 @@ export function PlanQuestionsPanel({
<text>
<span style={{ fg: t.text }}>{"enter"}</span>
<span style={{ fg: t.planHint }}>
{isConfirmTab
? " submit"
: q?.type === "multiselect"
? " toggle"
: isSingle
? " submit"
: " confirm"}
{isConfirmTab ? " submit" : q?.type === "multiselect" ? " toggle" : isSingle ? " submit" : " confirm"}
</span>
</text>
<text>
@@ -197,15 +181,7 @@ export function PlanQuestionsPanel({
/* ── Question Body ────────────────────────────────────────── */
function QuestionBody({
t,
question: q,
state,
}: {
t: Theme;
question: PlanQuestion;
state: PlanQuestionsState;
}) {
function QuestionBody({ t, question: q, state }: { t: Theme; question: PlanQuestion; state: PlanQuestionsState }) {
const isMulti = q.type === "multiselect";
const options = q.options ?? [];
const showCustom = q.type !== "text";
@@ -227,9 +203,11 @@ function QuestionBody({
/* Free-form text input */
<box backgroundColor={t.planInputBg} paddingLeft={1} paddingRight={1}>
<text fg={t.planInputText}>
{state.editing || customText
? customText + (state.editing ? "▌" : "")
: <span style={{ fg: t.textMuted }}>{"Type your answer..."}</span>}
{state.editing || customText ? (
customText + (state.editing ? "▌" : "")
) : (
<span style={{ fg: t.textMuted }}>{"Type your answer..."}</span>
)}
</text>
</box>
) : (
@@ -246,25 +224,15 @@ function QuestionBody({
flexDirection="row"
>
<text>
<span style={{ fg: t.textMuted }}>
{`${i + 1}. `}
</span>
<span style={{ fg: t.textMuted }}>{`${i + 1}. `}</span>
<span
style={{
fg: isFocused
? t.selected
: isPicked
? t.planOptionCheck
: t.text,
fg: isFocused ? t.selected : isPicked ? t.planOptionCheck : t.text,
}}
>
{isMulti
? `[${isPicked ? "✓" : " "}] ${opt.label}`
: opt.label}
{isMulti ? `[${isPicked ? "✓" : " "}] ${opt.label}` : opt.label}
</span>
{isPicked && !isMulti ? (
<span style={{ fg: t.planOptionCheck }}>{" ✓"}</span>
) : null}
{isPicked && !isMulti ? <span style={{ fg: t.planOptionCheck }}>{" ✓"}</span> : null}
</text>
</box>
);
@@ -272,21 +240,14 @@ function QuestionBody({
{/* "Type your own answer" option */}
{showCustom && (
<box
backgroundColor={isOnCustom ? t.selectedBg : undefined}
paddingLeft={1}
>
<box backgroundColor={isOnCustom ? t.selectedBg : undefined} paddingLeft={1}>
{state.editing && isOnCustom ? (
<box backgroundColor={t.planInputBg} paddingLeft={1} paddingRight={1} flexGrow={1}>
<text fg={t.planInputText}>
{customText + "▌"}
</text>
<text fg={t.planInputText}>{`${customText}▌`}</text>
</box>
) : (
<text>
<span style={{ fg: t.textMuted }}>
{`${totalItems}. `}
</span>
<span style={{ fg: t.textMuted }}>{`${totalItems}. `}</span>
<span
style={{
fg: isOnCustom ? t.planOptionSelected : t.textMuted,
@@ -296,9 +257,7 @@ function QuestionBody({
? `[${customText && isOptionPicked(state.answers, q, customText) ? "✓" : " "}] Type your own answer`
: "Type your own answer"}
</span>
{customText ? (
<span style={{ fg: t.textDim }}>{` (${customText})`}</span>
) : null}
{customText ? <span style={{ fg: t.textDim }}>{` (${customText})`}</span> : null}
</text>
)}
</box>
@@ -311,15 +270,7 @@ function QuestionBody({
/* ── Confirm/Review Tab ───────────────────────────────────── */
function ConfirmView({
t,
questions,
answers,
}: {
t: Theme;
questions: PlanQuestion[];
answers: PlanAnswers;
}) {
function ConfirmView({ t, questions, answers }: { t: Theme; questions: PlanQuestion[]; answers: PlanAnswers }) {
return (
<box flexDirection="column">
<box marginBottom={1}>
@@ -336,9 +287,7 @@ function ConfirmView({
<span style={{ fg: t.text }}>
<b>{tabLabel(q)}:</b>
</span>
<span style={{ fg: answered ? t.planOptionCheck : t.textMuted }}>
{" "}{val}
</span>
<span style={{ fg: answered ? t.planOptionCheck : t.textMuted }}> {val}</span>
</text>
</box>
);
@@ -352,7 +301,9 @@ function ConfirmView({
function tabLabel(q: PlanQuestion): string {
if (q.header) return q.header;
const words = q.question.replace(/[?.,!:]+$/, "").split(/\s+/);
const key = words.find((w) => w.length > 2 && !/^(what|how|should|which|does|the|and|for|are|can|will|you|this|that|with|from)$/i.test(w));
const key = words.find(
(w) => w.length > 2 && !/^(what|how|should|which|does|the|and|for|are|can|will|you|this|that|with|from)$/i.test(w),
);
return key ?? words[0] ?? "Question";
}
@@ -363,11 +314,7 @@ function hasAnswer(answers: PlanAnswers, q: PlanQuestion): boolean {
return a.trim().length > 0;
}
function isOptionPicked(
answers: PlanAnswers,
q: PlanQuestion,
optionId: string,
): boolean {
function isOptionPicked(answers: PlanAnswers, q: PlanQuestion, optionId: string): boolean {
const a = answers[q.id];
if (!a) return false;
if (Array.isArray(a)) return a.includes(optionId);
@@ -384,15 +331,10 @@ function formatAnswer(q: PlanQuestion, answers: PlanAnswers): string {
}
const arr = a as string[];
if (arr.length === 0) return "(not answered)";
return arr
.map((id) => q.options?.find((o) => o.id === id)?.label ?? id)
.join(", ");
return arr.map((id) => q.options?.find((o) => o.id === id)?.label ?? id).join(", ");
}
export function formatPlanAnswers(
questions: PlanQuestion[],
answers: PlanAnswers,
): string {
export function formatPlanAnswers(questions: PlanQuestion[], answers: PlanAnswers): string {
const parts: string[] = ["Here are my answers to the plan questions:\n"];
for (const q of questions) {
+3 -8
View File
@@ -1,21 +1,16 @@
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import * as path from "path";
export function loadCustomInstructions(): string | null {
const candidates = [
path.join(process.cwd(), ".grok", "GROK.md"),
path.join(os.homedir(), ".grok", "GROK.md"),
];
const candidates = [path.join(process.cwd(), ".grok", "GROK.md"), path.join(os.homedir(), ".grok", "GROK.md")];
for (const p of candidates) {
try {
if (fs.existsSync(p)) {
return fs.readFileSync(p, "utf-8").trim();
}
} catch {
continue;
}
} catch {}
}
return null;
+3 -3
View File
@@ -1,7 +1,7 @@
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import { DEFAULT_MODEL, getModelIds } from "../grok/models.js";
import * as path from "path";
import { DEFAULT_MODEL, getModelIds } from "../grok/models";
export interface UserSettings {
apiKey?: string;
@@ -77,4 +77,4 @@ export function getCurrentModel(): string {
if (project.model) return project.model;
const user = loadUserSettings();
return user.defaultModel || DEFAULT_MODEL;
}
}