From 0250efa40427d3aa0b307fd374f231c40a8ae9bb Mon Sep 17 00:00:00 2001 From: Anthony Ronning <101225832+AnthonyRonning@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:55:26 +0000 Subject: [PATCH 01/14] Add Goose agent mode --- .gitignore | 1 + frontend/bun.lock | 224 +++++ frontend/package.json | 2 + frontend/src-tauri/Cargo.lock | 43 + frontend/src-tauri/Cargo.toml | 1 + frontend/src-tauri/build.rs | 108 +++ frontend/src-tauri/capabilities/default.json | 1 + frontend/src-tauri/src/agent.rs | 747 ++++++++++++++++ frontend/src-tauri/src/lib.rs | 13 + frontend/src-tauri/src/proxy.rs | 39 +- frontend/src-tauri/tauri.conf.json | 3 +- frontend/src/components/AgentMode.tsx | 893 +++++++++++++++++++ frontend/src/components/Sidebar.tsx | 28 +- frontend/src/routeTree.gen.ts | 21 + frontend/src/routes/agent.tsx | 26 + frontend/src/services/agentAcpClient.ts | 228 +++++ frontend/src/services/agentRuntimeService.ts | 79 ++ 17 files changed, 2446 insertions(+), 11 deletions(-) create mode 100644 frontend/src-tauri/src/agent.rs create mode 100644 frontend/src/components/AgentMode.tsx create mode 100644 frontend/src/routes/agent.tsx create mode 100644 frontend/src/services/agentAcpClient.ts create mode 100644 frontend/src/services/agentRuntimeService.ts diff --git a/.gitignore b/.gitignore index d8903e8fb..cea0bd9af 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,4 @@ frontend/*.local # iOS build backups frontend/src-tauri/gen/apple/maple.xcodeproj/project.pbxproj.backup +frontend/src-tauri/bin/goose* diff --git a/frontend/bun.lock b/frontend/bun.lock index 95f097c14..bac90f1f4 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -5,6 +5,8 @@ "": { "name": "maple", "dependencies": { + "@aaif/goose-sdk": "0.20.2", + "@agentclientprotocol/sdk": "0.19.0", "@opensecret/react": "3.2.0", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-avatar": "^1.1.11", @@ -86,6 +88,20 @@ "yaml": "^2.8.3", }, "packages": { + "@aaif/goose-binary-darwin-arm64": ["@aaif/goose-binary-darwin-arm64@0.20.2", "", { "os": "darwin", "cpu": "arm64", "bin": { "goose": "bin/goose" } }, "sha512-0wv6UcYxg/dZXRuIUBTL+64Hz0D50PfUA2mJiUEBhWkBmiBCgS/Iymore0gYuayxVV7MzQhKrHqdDPBoo0lqIg=="], + + "@aaif/goose-binary-darwin-x64": ["@aaif/goose-binary-darwin-x64@0.20.2", "", { "os": "darwin", "cpu": "x64", "bin": { "goose": "bin/goose" } }, "sha512-dZG6H1QF/lv/kVc1YmHVKRGJCZtoe9o0N2q4vgvDK0Lz+ZJp/ehKcIxUSqE/zebXDqLb4yWByDGelq5Ud2rnCw=="], + + "@aaif/goose-binary-linux-arm64": ["@aaif/goose-binary-linux-arm64@0.20.2", "", { "os": "linux", "cpu": "arm64", "bin": { "goose": "bin/goose" } }, "sha512-DLbm8r21v4c39dGbLepjXDmXNLsdWw0PFFpRbQtBd2m5Q+xIBgYOx1jNm3EygDQT9yGV9R3WS6SW3LvMJLA3xw=="], + + "@aaif/goose-binary-linux-x64": ["@aaif/goose-binary-linux-x64@0.20.2", "", { "os": "linux", "cpu": "x64", "bin": { "goose": "bin/goose" } }, "sha512-+TgB2+MKj18kbw5PBnDMAWvuy8ZijNxXQL4qRBeMebcx07W3dIf6zoy9xD5mSyce61ugG9vsLt9a+3Pm8qZaRw=="], + + "@aaif/goose-binary-win32-x64": ["@aaif/goose-binary-win32-x64@0.20.2", "", { "os": "win32", "cpu": "x64", "bin": { "goose": "bin/goose.exe" } }, "sha512-P0GrtagS0U/98XW4VuzQ77Fy02bw4wFhzyRWWbR9LDVwY+lLG+AkE5m0Ml/KGKgDWS6gd8BtkAqRxdFw3PM9RQ=="], + + "@aaif/goose-sdk": ["@aaif/goose-sdk@0.20.2", "", { "dependencies": { "@modelcontextprotocol/ext-apps": "^0.3.1", "@modelcontextprotocol/sdk": "^1.27.0", "zod": "^3.25.76" }, "optionalDependencies": { "@aaif/goose-binary-darwin-arm64": "0.20.2", "@aaif/goose-binary-darwin-x64": "0.20.2", "@aaif/goose-binary-linux-arm64": "0.20.2", "@aaif/goose-binary-linux-x64": "0.20.2", "@aaif/goose-binary-win32-x64": "0.20.2" }, "peerDependencies": { "@agentclientprotocol/sdk": "^0.19.0" } }, "sha512-HhsspN1OycRqgKgnUBWC/5xOpJ8zuKWmABax0Br0ZfND94AKKZbsBlya8e+pSM+CvztWLXHRz2KxPQuXYoGyBQ=="], + + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.19.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-U9I8ws9WTOk6jCBAWpXefGSDgVXn14/kV6HFzwWGcstQ02mOQgClMAROHmoIn9GqZbDBDEOkdIbP4P4TEMQdug=="], + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], @@ -208,6 +224,8 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.9", "", {}, "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="], + "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], @@ -230,6 +248,10 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@modelcontextprotocol/ext-apps": ["@modelcontextprotocol/ext-apps@0.3.1", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "^1.2.21", "@oven/bun-darwin-x64": "^1.2.21", "@oven/bun-darwin-x64-baseline": "^1.2.21", "@oven/bun-linux-aarch64": "^1.2.21", "@oven/bun-linux-aarch64-musl": "^1.2.21", "@oven/bun-linux-x64": "^1.2.21", "@oven/bun-linux-x64-baseline": "^1.2.21", "@oven/bun-linux-x64-musl": "^1.2.21", "@oven/bun-linux-x64-musl-baseline": "^1.2.21", "@oven/bun-windows-x64": "^1.2.21", "@oven/bun-windows-x64-baseline": "^1.2.21", "@rollup/rollup-darwin-arm64": "^4.53.3", "@rollup/rollup-darwin-x64": "^4.53.3", "@rollup/rollup-linux-arm64-gnu": "^4.53.3", "@rollup/rollup-linux-x64-gnu": "^4.53.3", "@rollup/rollup-win32-arm64-msvc": "^4.53.3", "@rollup/rollup-win32-x64-msvc": "^4.53.3" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.24.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-Iivz2KwWK8xlRbiWwFB/C4NXqE8VJBoRCbBkJCN98ST2UbQvA6kfyebcLsypiqylJS467XOOaBcI9DeQ3t+zqA=="], + + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], + "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], @@ -242,6 +264,28 @@ "@opensecret/react": ["@opensecret/react@3.2.0", "", { "dependencies": { "@peculiar/x509": "^1.12.2", "@stablelib/base64": "^2.0.0", "@stablelib/chacha20poly1305": "^2.0.0", "@stablelib/random": "^2.0.0", "cbor2": "^1.7.0", "tweetnacl": "^1.0.3", "zod": "^3.23.8" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-tmn52THsD3M3vzC2IErHJuAq9zKAXce16Y77YuaqEM9Vfg6u4ZU6lUIiR3Uvb7ObZSjUaJjxqhdEs6lSChW4iQ=="], + "@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Omj20SuiHBOUjUBIyqtkNjSUIjOtEOJwmbix/ZyFH4BaQ6OZTaaRWIR4TjHVz0yadHgli6lLTiAh1uarnvD49A=="], + + "@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-FFj3QdU/OhlDyZOJ8CWfN5eWLpRlT4qjZg7lMQi7jA6GuoY5ajlO1zWLP/MuHYRSbXQUvV52RejNi8DVnAp13w=="], + + "@oven/bun-darwin-x64-baseline": ["@oven/bun-darwin-x64-baseline@1.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-OSfsTZstc898HHElhU4NccaBGOSSDn5VfahiVTnidZ9B/+wb7WTyfZJaBeJcfjwJ9H2W9uTh2TGtl3UfcXgV9g=="], + + "@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-X5SsPZHs+iYO8R/efIcRtc7gT2Q2DgPfliCxEkx4cXBumwkw0c/EsHMNwH3EgGpCDaZ7IYVPhpCG/xBOQHEwZw=="], + + "@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmqOA92Cd1NL/1XBd4bFkJLxQ86K0RW7ohxS2qzzAvuitO4JiIxjjTeCspoU44zCozH72HpfZfUE2On31OjnWA=="], + + "@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-7OVTAKvwfPmSbIV1HpdOoVVx5VRc427GuPPne93N6vk4eQBPId9nXmZDh9/zGaKPdbVjVtQSZafWQoUjx38Utw=="], + + "@oven/bun-linux-x64-baseline": ["@oven/bun-linux-x64-baseline@1.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-q/8EdOC0yUE8FPeoOVq8/Pw5I9/tJaYmUfO/uDUAREx8IUnOJH1RJ5A3BjFqre8pvJoiZA9AovPJq5FnNNjSxA=="], + + "@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-GBCB/k/sIqcr06eTNgg7g46qiUv35Jasx4XiccJ/n7RGqrE4RWUD/XJBbWFprVPjvqd59+QtSnS99XGqvftHfg=="], + + "@oven/bun-linux-x64-musl-baseline": ["@oven/bun-linux-x64-musl-baseline@1.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-n6iE71G4lQE4XkrZhQQcL5YUlxDbnq6nqV7zeQi33PMsLT/0kYE+RvHOtBWZ3w0wMdXZfINmp63hIb9ijUBGtw=="], + + "@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-mUFWL3BoYkNpjd8e9PqROiFF/1Xeotq20mABJsiQH62jM1g5zqWh4khw1RZ6bX8Q8fWvlPaxG1PjofkmjUi3vg=="], + + "@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-uIjLUC1S9DWgICzuoMba7vurBJnBruE4S5CxnvmZkdqWVXRzx1Rgu636HoH+k0qeaQCFh3jeG3JQ1y6fRHv0sw=="], + "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.3.15", "", { "dependencies": { "@peculiar/asn1-schema": "^2.3.15", "@peculiar/asn1-x509": "^2.3.15", "@peculiar/asn1-x509-attr": "^2.3.15", "asn1js": "^3.0.5", "tslib": "^2.8.1" } }, "sha512-B+DoudF+TCrxoJSTjjcY8Mmu+lbv8e7pXGWrhNp2/EGJp9EEcpzjBCar7puU57sGifyzaRVM03oD5L7t7PghQg=="], "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.3.15", "", { "dependencies": { "@peculiar/asn1-schema": "^2.3.15", "@peculiar/asn1-x509": "^2.3.15", "asn1js": "^3.0.5", "tslib": "^2.8.1" } }, "sha512-caxAOrvw2hUZpxzhz8Kp8iBYKsHbGXZPl2KYRMIPvAfFateRebS3136+orUpcVwHRmpXWX2kzpb6COlIrqCumA=="], @@ -544,12 +588,16 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], "ajv": ["ajv@6.15.0", "", { "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-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -580,6 +628,8 @@ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + "body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="], + "brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -588,6 +638,12 @@ "bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="], + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], @@ -622,10 +678,20 @@ "commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], + "content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "cookie-es": ["cookie-es@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="], + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], @@ -638,6 +704,8 @@ "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], @@ -650,18 +718,32 @@ "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + "electron-to-chromium": ["electron-to-chromium@1.5.344", "", {}, "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg=="], "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "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.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], @@ -686,6 +768,16 @@ "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.1.0", "", {}, "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg=="], + + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + + "express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="], + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], @@ -696,6 +788,8 @@ "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + "fast-uri": ["fast-uri@3.1.3", "", {}, "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg=="], + "fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], @@ -704,6 +798,8 @@ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + "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=="], @@ -712,16 +808,24 @@ "foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="], + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], "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=="], @@ -732,10 +836,14 @@ "goober": ["goober@2.1.16", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "gpt-tokenizer": ["gpt-tokenizer@3.4.0", "", {}, "sha512-wxFLnhIXTDjYebd9A9pGl3e31ZpSypbpIJSOswbgop5jLte/AsZVDvjlbEuVFlsqZixVKqbcoNmRlFDf6pz/UQ=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "hast-util-from-dom": ["hast-util-from-dom@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hastscript": "^9.0.0", "web-namespaces": "^2.0.0" } }, "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q=="], @@ -762,16 +870,28 @@ "highlight.js": ["highlight.js@11.11.1", "", {}, "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w=="], + "hono": ["hono@4.12.27", "", {}, "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q=="], + "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "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=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], + "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], @@ -794,6 +914,8 @@ "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "isbot": ["isbot@5.1.39", "", {}, "sha512-obH0yYahGXdzNxo+djmHhBYThUKDkz565cxkIlt2L9hXfv1NlaLKoDBHo6KxXsYrIXx2RK3x5vY36CfZcobxEw=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -802,6 +924,8 @@ "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + "jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], @@ -812,6 +936,8 @@ "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], @@ -844,6 +970,8 @@ "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="], @@ -878,6 +1006,10 @@ "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "micromark": ["micromark@4.0.1", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw=="], @@ -940,6 +1072,10 @@ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], @@ -952,6 +1088,8 @@ "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + "node-releases": ["node-releases@2.0.38", "", {}, "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -960,6 +1098,12 @@ "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "openai": ["openai@5.20.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-Bmc2zLM/YWgFrDpXr9hwXqGGDdMmMpE9+qoZPsaHpn0Y/Qk1Vu26hNqXo7+nHdli+sLsXINvS1f8kR3NKhGKmA=="], "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=="], @@ -976,6 +1120,8 @@ "parse5": ["parse5@7.2.1", "", { "dependencies": { "entities": "^4.5.0" } }, "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -984,6 +1130,8 @@ "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -994,6 +1142,8 @@ "pirates": ["pirates@4.0.6", "", {}, "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="], + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + "postcss": ["postcss@8.5.10", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ=="], "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], @@ -1014,14 +1164,22 @@ "property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], "pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="], + "qs": ["qs@6.15.3", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "range-parser": ["range-parser@1.3.0", "", {}, "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw=="], + + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], @@ -1062,6 +1220,8 @@ "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], @@ -1072,26 +1232,46 @@ "rollup": ["rollup@4.60.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.2", "@rollup/rollup-android-arm64": "4.60.2", "@rollup/rollup-darwin-arm64": "4.60.2", "@rollup/rollup-darwin-x64": "4.60.2", "@rollup/rollup-freebsd-arm64": "4.60.2", "@rollup/rollup-freebsd-x64": "4.60.2", "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", "@rollup/rollup-linux-arm-musleabihf": "4.60.2", "@rollup/rollup-linux-arm64-gnu": "4.60.2", "@rollup/rollup-linux-arm64-musl": "4.60.2", "@rollup/rollup-linux-loong64-gnu": "4.60.2", "@rollup/rollup-linux-loong64-musl": "4.60.2", "@rollup/rollup-linux-ppc64-gnu": "4.60.2", "@rollup/rollup-linux-ppc64-musl": "4.60.2", "@rollup/rollup-linux-riscv64-gnu": "4.60.2", "@rollup/rollup-linux-riscv64-musl": "4.60.2", "@rollup/rollup-linux-s390x-gnu": "4.60.2", "@rollup/rollup-linux-x64-gnu": "4.60.2", "@rollup/rollup-linux-x64-musl": "4.60.2", "@rollup/rollup-openbsd-x64": "4.60.2", "@rollup/rollup-openharmony-arm64": "4.60.2", "@rollup/rollup-win32-arm64-msvc": "4.60.2", "@rollup/rollup-win32-ia32-msvc": "4.60.2", "@rollup/rollup-win32-x64-gnu": "4.60.2", "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ=="], + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + "seroval": ["seroval@1.5.2", "", {}, "sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q=="], "seroval-plugins": ["seroval-plugins@1.5.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-qpY0Cl+fKYFn4GOf3cMiq6l72CpuVaawb6ILjubOQ+diJ54LfOWaSSPsaswN8DRPIPW4Yq+tE1k5aKd7ILyaFg=="], + "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + "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=="], + "side-channel": ["side-channel@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4", "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ=="], + + "side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "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=="], "string-width-cjs": ["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=="], @@ -1126,6 +1306,8 @@ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], @@ -1144,6 +1326,8 @@ "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript-eslint": ["typescript-eslint@8.59.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.0", "@typescript-eslint/parser": "8.59.0", "@typescript-eslint/typescript-estree": "8.59.0", "@typescript-eslint/utils": "8.59.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-BU3ONW9X+v90EcCH9ZS6LMackcVtxRLlI3XrYyqZIwVSHIk7Qf7bFw1z0M9Q0IUxhTMZCf8piY9hTYaNEIASrw=="], @@ -1166,6 +1350,8 @@ "unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + "unplugin": ["unplugin@2.2.0", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw=="], "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], @@ -1182,6 +1368,8 @@ "uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], @@ -1202,6 +1390,8 @@ "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], @@ -1210,8 +1400,14 @@ "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], + "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + "@aaif/goose-sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@agentclientprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@babel/helper-compilation-targets/browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="], @@ -1230,6 +1426,12 @@ "@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + "@modelcontextprotocol/ext-apps/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@modelcontextprotocol/sdk/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], "@radix-ui/react-avatar/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="], @@ -1282,12 +1484,22 @@ "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + + "body-parser/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "espree/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + "express/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "finalhandler/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "hast-util-to-jsx-runtime/@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], @@ -1300,6 +1512,10 @@ "rehype-katex/katex": ["katex@0.16.21", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A=="], + "router/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "send/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -1312,12 +1528,16 @@ "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], "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=="], + "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@babel/generator/@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], "@babel/helper-compilation-targets/browserslist/caniuse-lite": ["caniuse-lite@1.0.30001700", "", {}, "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ=="], @@ -1330,6 +1550,8 @@ "@jridgewell/remapping/@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + "@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "@types/babel__core/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], "@types/babel__core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], @@ -1346,6 +1568,8 @@ "@types/babel__traverse/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], diff --git a/frontend/package.json b/frontend/package.json index d2cb5284e..0fd1b83a7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,6 +31,8 @@ "yaml": "^2.8.3" }, "dependencies": { + "@aaif/goose-sdk": "0.20.2", + "@agentclientprotocol/sdk": "0.19.0", "@opensecret/react": "3.2.0", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-avatar": "^1.1.11", diff --git a/frontend/src-tauri/Cargo.lock b/frontend/src-tauri/Cargo.lock index 937928d66..484d07f90 100644 --- a/frontend/src-tauri/Cargo.lock +++ b/frontend/src-tauri/Cargo.lock @@ -2993,6 +2993,7 @@ dependencies = [ "tauri-build", "tauri-plugin", "tauri-plugin-deep-link", + "tauri-plugin-dialog", "tauri-plugin-fs", "tauri-plugin-log", "tauri-plugin-opener", @@ -4596,6 +4597,30 @@ dependencies = [ "subtle", ] +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2 0.6.2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2 0.6.4", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + [[package]] name = "ring" version = "0.17.14" @@ -5656,6 +5681,24 @@ dependencies = [ "windows-result 0.3.4", ] +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65981abb771e74e571a38196c3baa11c459379164791eba0e67abc1a5fac9884" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.17", + "url", +] + [[package]] name = "tauri-plugin-fs" version = "2.5.1" diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml index 7f41a9eca..0ba133e4d 100644 --- a/frontend/src-tauri/Cargo.toml +++ b/frontend/src-tauri/Cargo.toml @@ -33,6 +33,7 @@ tauri-plugin-deep-link = "=2.4.7" tauri-plugin-single-instance = { version = "=2.4.0", features = ["deep-link"] } tauri-plugin-opener = "2.5.4" tauri-plugin-os = "2.3.2" +tauri-plugin-dialog = "2.4.1" tauri-plugin-sign-in-with-apple = "1.0.2" tokio = { version = "1.0", features = ["net", "sync", "rt-multi-thread", "macros", "time"] } once_cell = "1.18.0" diff --git a/frontend/src-tauri/build.rs b/frontend/src-tauri/build.rs index 038704a53..ed9ccc958 100644 --- a/frontend/src-tauri/build.rs +++ b/frontend/src-tauri/build.rs @@ -1,9 +1,14 @@ fn main() { let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); if target_os == "ios" { println!("cargo:rustc-link-lib=c++"); } + if target_os != "ios" && target_os != "android" { + stage_goose_binary(&target_os, &target_arch); + } + tauri_build::build(); // The deep-link plugin's build.rs overwrites CFBundleURLTypes in Info.plist @@ -14,6 +19,109 @@ fn main() { } } +fn stage_goose_binary(target_os: &str, target_arch: &str) { + println!("cargo:rerun-if-env-changed=MAPLE_GOOSE_BINARY"); + println!("cargo:rerun-if-env-changed=MAPLE_SKIP_STAGE_GOOSE_BINARY"); + + if std::env::var("MAPLE_SKIP_STAGE_GOOSE_BINARY").as_deref() == Ok("1") { + return; + } + + let binary_name = if target_os == "windows" { + "goose.exe" + } else { + "goose" + }; + let target_dir = std::path::Path::new("bin"); + if let Err(error) = std::fs::create_dir_all(target_dir) { + println!("cargo:warning=failed to create Goose staging dir: {error}"); + return; + } + + let destination = target_dir.join(binary_name); + let source = std::env::var("MAPLE_GOOSE_BINARY") + .ok() + .map(std::path::PathBuf::from) + .filter(|path| path.is_file()) + .or_else(|| goose_binary_package_source(target_os, target_arch, binary_name)); + + let Some(source) = source else { + println!( + "cargo:warning=Goose binary not staged; install @aaif/goose-sdk optional binary package or set MAPLE_GOOSE_BINARY" + ); + return; + }; + + println!("cargo:rerun-if-changed={}", source.display()); + if staged_binary_matches(&source, &destination) { + ensure_executable(&destination); + println!( + "cargo:warning=Goose binary already staged from {}", + source.display() + ); + return; + } + + match std::fs::copy(&source, &destination) { + Ok(_) => { + ensure_executable(&destination); + println!( + "cargo:warning=staged Goose binary from {}", + source.display() + ); + } + Err(error) => { + println!( + "cargo:warning=failed to stage Goose binary from {}: {error}", + source.display() + ); + } + } +} + +fn staged_binary_matches(source: &std::path::Path, destination: &std::path::Path) -> bool { + match (std::fs::metadata(source), std::fs::metadata(destination)) { + (Ok(source_meta), Ok(destination_meta)) => source_meta.len() == destination_meta.len(), + _ => false, + } +} + +fn ensure_executable(path: &std::path::Path) { + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o755)); + } + + #[cfg(not(unix))] + { + let _ = path; + } +} + +fn goose_binary_package_source( + target_os: &str, + target_arch: &str, + binary_name: &str, +) -> Option { + let package = match (target_os, target_arch) { + ("macos", "aarch64") => "goose-binary-darwin-arm64", + ("macos", "x86_64") => "goose-binary-darwin-x64", + ("linux", "aarch64") => "goose-binary-linux-arm64", + ("linux", "x86_64") => "goose-binary-linux-x64", + ("windows", "x86_64") => "goose-binary-win32-x64", + _ => return None, + }; + + let candidate = std::path::Path::new("..") + .join("node_modules") + .join("@aaif") + .join(package) + .join("bin") + .join(binary_name); + candidate.is_file().then_some(candidate) +} + #[allow(dead_code)] fn ensure_ios_custom_url_scheme() { let plist_path = std::path::Path::new("gen/apple/maple_iOS/Info.plist"); diff --git a/frontend/src-tauri/capabilities/default.json b/frontend/src-tauri/capabilities/default.json index 8695013b0..459ee757d 100644 --- a/frontend/src-tauri/capabilities/default.json +++ b/frontend/src-tauri/capabilities/default.json @@ -8,6 +8,7 @@ "permissions": [ "core:default", "updater:default", + "dialog:default", "fs:default", { "identifier": "fs:allow-read-file", diff --git a/frontend/src-tauri/src/agent.rs b/frontend/src-tauri/src/agent.rs new file mode 100644 index 000000000..03529be4a --- /dev/null +++ b/frontend/src-tauri/src/agent.rs @@ -0,0 +1,747 @@ +use crate::proxy; +use rand::{rngs::OsRng, RngCore}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::sync::Arc; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use tauri::{AppHandle, Manager, State}; +use tokio::sync::Mutex; + +const DEFAULT_AGENT_MODEL: &str = "auto:powerful"; +const DEFAULT_GOOSE_MODE: &str = "approve"; +const READINESS_TIMEOUT: Duration = Duration::from_secs(30); +const READINESS_INTERVAL: Duration = Duration::from_millis(100); + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AgentConfig { + pub default_project_root: Option, + pub default_model: String, + #[serde(default = "default_runtime_kind")] + pub runtime_kind: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub external_acp_url: Option, +} + +fn default_runtime_kind() -> String { + "goose".to_string() +} + +impl Default for AgentConfig { + fn default() -> Self { + Self { + default_project_root: None, + default_model: DEFAULT_AGENT_MODEL.to_string(), + runtime_kind: default_runtime_kind(), + external_acp_url: None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AgentStartRequest { + pub project_root: Option, + pub model: Option, + pub goose_binary: Option, + pub mode: Option, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AgentRuntimeStatus { + pub running: bool, + pub acp_url: Option, + pub redacted_acp_url: Option, + pub http_base_url: Option, + pub status_url: Option, + pub project_root: Option, + pub goose_binary: Option, + pub pid: Option, + pub model: Option, + pub mode: Option, + pub maple_proxy_base_url: Option, + pub config_dir: String, + pub goose_path_root: Option, + pub log_path: Option, + pub error: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RecentProjectRoot { + pub path: String, + pub name: String, + pub last_used_ms: u128, +} + +struct AgentRuntime { + child: Child, + acp_url: String, + redacted_acp_url: String, + http_base_url: String, + status_url: String, + project_root: PathBuf, + goose_binary: PathBuf, + model: String, + mode: String, + maple_proxy_base_url: String, + config_dir: PathBuf, + goose_path_root: PathBuf, + log_path: PathBuf, +} + +impl AgentRuntime { + fn status(&self, running: bool, error: Option) -> AgentRuntimeStatus { + AgentRuntimeStatus { + running, + acp_url: if running { + Some(self.acp_url.clone()) + } else { + None + }, + redacted_acp_url: Some(self.redacted_acp_url.clone()), + http_base_url: Some(self.http_base_url.clone()), + status_url: Some(self.status_url.clone()), + project_root: Some(path_string(&self.project_root)), + goose_binary: Some(path_string(&self.goose_binary)), + pid: Some(self.child.id()), + model: Some(self.model.clone()), + mode: Some(self.mode.clone()), + maple_proxy_base_url: Some(self.maple_proxy_base_url.clone()), + config_dir: path_string(&self.config_dir), + goose_path_root: Some(path_string(&self.goose_path_root)), + log_path: Some(path_string(&self.log_path)), + error, + } + } +} + +pub struct AgentRuntimeState { + inner: Arc>>, + session_log: Arc>, +} + +impl AgentRuntimeState { + pub fn new() -> Self { + Self { + inner: Arc::new(Mutex::new(None)), + session_log: Arc::new(Mutex::new(())), + } + } +} + +#[tauri::command] +pub async fn agent_get_runtime_status( + app_handle: AppHandle, + state: State<'_, AgentRuntimeState>, +) -> Result { + let config_dir = agent_config_dir(&app_handle).map_err(|e| e.to_string())?; + let mut runtime = state.inner.lock().await; + + if let Some(current) = runtime.as_mut() { + match current.child.try_wait() { + Ok(Some(exit_status)) => { + let status = current.status( + false, + Some(format!("Goose exited with status {exit_status}")), + ); + *runtime = None; + return Ok(status); + } + Ok(None) => return Ok(current.status(true, None)), + Err(e) => { + let status = current.status(false, Some(format!("Failed to inspect Goose: {e}"))); + *runtime = None; + return Ok(status); + } + } + } + + Ok(stopped_status(config_dir, None)) +} + +#[tauri::command] +pub async fn agent_start_runtime( + app_handle: AppHandle, + state: State<'_, AgentRuntimeState>, + proxy_state: State<'_, proxy::ProxyState>, + request: Option, +) -> Result { + clear_exited_runtime(&state).await; + + { + let runtime = state.inner.lock().await; + if let Some(current) = runtime.as_ref() { + return Ok(current.status(true, None)); + } + } + + let agent_config = load_agent_config_inner(&app_handle).unwrap_or_default(); + let request = request.unwrap_or(AgentStartRequest { + project_root: None, + model: None, + goose_binary: None, + mode: None, + }); + + let proxy_status = proxy::ensure_proxy_running(app_handle.clone(), proxy_state).await?; + let proxy_config = proxy_status.config; + let proxy_host = if proxy_config.host == "0.0.0.0" { + "127.0.0.1".to_string() + } else { + proxy_config.host.clone() + }; + let maple_proxy_base_url = format!("http://{}:{}", proxy_host, proxy_config.port); + + let project_root = + resolve_project_root(request.project_root.as_deref(), &agent_config).map_err(|e| { + format!("Failed to resolve Agent Mode project root: {e}") + })?; + let model = request + .model + .or_else(|| std::env::var("MAPLE_GOOSE_MODEL").ok()) + .unwrap_or(agent_config.default_model); + let mode = request + .mode + .or_else(|| std::env::var("MAPLE_GOOSE_MODE").ok()) + .unwrap_or_else(|| DEFAULT_GOOSE_MODE.to_string()); + let goose_binary = + resolve_goose_binary(&app_handle, request.goose_binary.as_deref()).map_err(|e| { + format!("Failed to resolve Goose binary: {e}") + })?; + + let config_dir = agent_config_dir(&app_handle).map_err(|e| e.to_string())?; + let goose_path_root = std::env::var("MAPLE_GOOSE_PATH_ROOT") + .map(PathBuf::from) + .unwrap_or_else(|_| config_dir.join("goose")); + let log_dir = config_dir.join("logs"); + fs::create_dir_all(&log_dir).map_err(|e| format!("Failed to create log dir: {e}"))?; + fs::create_dir_all(&goose_path_root) + .map_err(|e| format!("Failed to create Goose data dir: {e}"))?; + let log_path = log_dir.join("goose-serve.log"); + + let port = find_available_port().map_err(|e| format!("Failed to allocate Goose port: {e}"))?; + let token = secure_token(); + let http_base_url = format!("http://127.0.0.1:{port}"); + let status_url = format!("{http_base_url}/status"); + let acp_url = format!("ws://127.0.0.1:{port}/acp?token={token}"); + let redacted_acp_url = format!("ws://127.0.0.1:{port}/acp?token=REDACTED"); + + let log_file = OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + .map_err(|e| format!("Failed to open Goose log: {e}"))?; + set_owner_only_permissions(&log_path); + let stdout_file = log_file + .try_clone() + .map_err(|e| format!("Failed to clone Goose log handle: {e}"))?; + + let mut command = Command::new(&goose_binary); + let port_arg = port.to_string(); + command + .args([ + "serve", + "--host", + "127.0.0.1", + "--port", + &port_arg, + ]) + .current_dir(&project_root) + .env("GOOSE_SERVER__SECRET_KEY", &token) + .env("GOOSE_PROVIDER", "openai") + .env("GOOSE_MODEL", &model) + .env("GOOSE_FAST_MODEL", &model) + .env("GOOSE_MODE", &mode) + .env("GOOSE_DISABLE_KEYRING", "true") + .env("GOOSE_PATH_ROOT", &goose_path_root) + .env("OPENAI_BASE_URL", format!("{}/v1", maple_proxy_base_url)) + .env("OPENAI_API_KEY", proxy_config.api_key) + .stdout(Stdio::from(stdout_file)) + .stderr(Stdio::from(log_file)); + + if let Some(parent) = goose_binary.parent() { + prepend_path_env(&mut command, parent); + } + + log::info!( + "Starting Goose ACP runtime from {} in {} on {}", + goose_binary.display(), + project_root.display(), + redacted_acp_url + ); + + let mut child = command + .spawn() + .map_err(|e| format!("Failed to spawn Goose: {e}"))?; + + if let Err(e) = wait_for_goose_ready(&status_url, &mut child).await { + let _ = child.kill(); + let _ = child.wait(); + return Err(format!("{e}. See {}", log_path.display())); + } + + let runtime = AgentRuntime { + child, + acp_url, + redacted_acp_url, + http_base_url, + status_url, + project_root: project_root.clone(), + goose_binary, + model: model.clone(), + mode, + maple_proxy_base_url, + config_dir: config_dir.clone(), + goose_path_root, + log_path, + }; + + let status = runtime.status(true, None); + { + let mut guard = state.inner.lock().await; + *guard = Some(runtime); + } + + let _ = save_recent_project_root_inner(&app_handle, &project_root); + let mut next_config = load_agent_config_inner(&app_handle).unwrap_or_default(); + next_config.default_project_root = Some(path_string(&project_root)); + next_config.default_model = model; + let _ = save_agent_config_inner(&app_handle, &next_config); + + Ok(status) +} + +#[tauri::command] +pub async fn agent_stop_runtime( + app_handle: AppHandle, + state: State<'_, AgentRuntimeState>, +) -> Result { + let config_dir = agent_config_dir(&app_handle).map_err(|e| e.to_string())?; + stop_runtime_inner(&state).await?; + Ok(stopped_status(config_dir, None)) +} + +#[tauri::command] +pub async fn agent_restart_runtime( + app_handle: AppHandle, + state: State<'_, AgentRuntimeState>, + proxy_state: State<'_, proxy::ProxyState>, + request: Option, +) -> Result { + stop_runtime_inner(&state).await?; + agent_start_runtime(app_handle, state, proxy_state, request).await +} + +#[tauri::command] +pub async fn agent_load_config(app_handle: AppHandle) -> Result { + load_agent_config_inner(&app_handle).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn agent_save_config(app_handle: AppHandle, config: AgentConfig) -> Result<(), String> { + save_agent_config_inner(&app_handle, &config).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn agent_list_recent_project_roots( + app_handle: AppHandle, +) -> Result, String> { + load_recent_project_roots_inner(&app_handle).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn agent_save_recent_project_root( + app_handle: AppHandle, + path: String, +) -> Result, String> { + let project_root = normalize_project_root(Path::new(&path))?; + save_recent_project_root_inner(&app_handle, &project_root).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn agent_append_session_event( + app_handle: AppHandle, + state: State<'_, AgentRuntimeState>, + session_id: String, + event: Value, +) -> Result<(), String> { + let _guard = state.session_log.lock().await; + append_session_event_inner(&app_handle, &session_id, event).map_err(|e| e.to_string()) +} + +async fn clear_exited_runtime(state: &State<'_, AgentRuntimeState>) { + let mut runtime = state.inner.lock().await; + if let Some(current) = runtime.as_mut() { + if matches!(current.child.try_wait(), Ok(Some(_)) | Err(_)) { + *runtime = None; + } + } +} + +async fn stop_runtime_inner(state: &State<'_, AgentRuntimeState>) -> Result<(), String> { + let mut runtime = state.inner.lock().await; + if let Some(mut current) = runtime.take() { + log::info!("Stopping Goose ACP runtime"); + if let Err(e) = current.child.kill() { + log::warn!("Failed to kill Goose runtime: {e}"); + } + if let Err(e) = current.child.wait() { + log::warn!("Failed to wait for Goose runtime exit: {e}"); + } + } + Ok(()) +} + +async fn wait_for_goose_ready(status_url: &str, child: &mut Child) -> Result<(), String> { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(1)) + .build() + .map_err(|e| format!("Failed to build readiness client: {e}"))?; + let deadline = std::time::Instant::now() + READINESS_TIMEOUT; + + while std::time::Instant::now() < deadline { + match child.try_wait() { + Ok(Some(exit_status)) => { + return Err(format!("Goose exited before becoming ready: {exit_status}")); + } + Ok(None) => {} + Err(e) => return Err(format!("Failed to inspect Goose readiness: {e}")), + } + + if let Ok(response) = client.get(status_url).send().await { + if response.status().is_success() { + return Ok(()); + } + } + + tokio::time::sleep(READINESS_INTERVAL).await; + } + + Err(format!("Goose did not become ready on {status_url}")) +} + +fn stopped_status(config_dir: PathBuf, error: Option) -> AgentRuntimeStatus { + AgentRuntimeStatus { + running: false, + acp_url: None, + redacted_acp_url: None, + http_base_url: None, + status_url: None, + project_root: None, + goose_binary: None, + pid: None, + model: None, + mode: None, + maple_proxy_base_url: None, + config_dir: path_string(&config_dir), + goose_path_root: None, + log_path: None, + error, + } +} + +fn resolve_project_root( + requested: Option<&str>, + config: &AgentConfig, +) -> Result { + if let Some(path) = requested.filter(|value| !value.trim().is_empty()) { + return normalize_project_root(Path::new(path)); + } + + if let Some(path) = config + .default_project_root + .as_deref() + .filter(|value| !value.trim().is_empty()) + { + if let Ok(root) = normalize_project_root(Path::new(path)) { + return Ok(root); + } + } + + std::env::current_dir() + .map_err(|e| format!("Failed to read current directory: {e}")) + .and_then(|path| normalize_project_root(&path)) +} + +fn normalize_project_root(path: &Path) -> Result { + let canonical = path + .canonicalize() + .map_err(|e| format!("{}: {e}", path.display()))?; + if !canonical.is_dir() { + return Err(format!("{} is not a folder", canonical.display())); + } + Ok(canonical) +} + +fn resolve_goose_binary(app_handle: &AppHandle, requested: Option<&str>) -> Result { + let mut candidates = Vec::new(); + + if let Some(path) = requested.filter(|value| !value.trim().is_empty()) { + candidates.push(PathBuf::from(path)); + } + + if let Ok(path) = std::env::var("MAPLE_GOOSE_BINARY") { + candidates.push(PathBuf::from(path)); + } + + if let Ok(path) = std::env::var("GOOSE_BINARY") { + candidates.push(PathBuf::from(path)); + } + + if let Ok(resource_dir) = app_handle.path().resource_dir() { + candidates.push(resource_dir.join("bin").join(goose_binary_name())); + candidates.push(resource_dir.join(goose_binary_name())); + } + + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + candidates.push( + manifest_dir + .join("..") + .join("node_modules") + .join("@aaif") + .join(goose_binary_package_name()) + .join("bin") + .join(goose_binary_name()), + ); + candidates.push( + manifest_dir + .join("bin") + .join(goose_binary_name()), + ); + + if cfg!(debug_assertions) { + if let Some(path) = find_on_path(goose_binary_name()) { + candidates.push(path); + } + } + + for candidate in candidates { + let candidate = expand_home(candidate); + if candidate.is_file() { + return Ok(candidate); + } + } + + Err("Goose binary not found. Set MAPLE_GOOSE_BINARY in development or bundle bin/goose with Maple.".to_string()) +} + +fn goose_binary_name() -> &'static str { + if cfg!(target_os = "windows") { + "goose.exe" + } else { + "goose" + } +} + +fn goose_binary_package_name() -> &'static str { + if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + "goose-binary-darwin-arm64" + } else if cfg!(all(target_os = "macos", target_arch = "x86_64")) { + "goose-binary-darwin-x64" + } else if cfg!(all(target_os = "linux", target_arch = "aarch64")) { + "goose-binary-linux-arm64" + } else if cfg!(all(target_os = "linux", target_arch = "x86_64")) { + "goose-binary-linux-x64" + } else if cfg!(all(target_os = "windows", target_arch = "x86_64")) { + "goose-binary-win32-x64" + } else { + "goose-binary-unsupported" + } +} + +fn find_available_port() -> std::io::Result { + let listener = std::net::TcpListener::bind(("127.0.0.1", 0))?; + Ok(listener.local_addr()?.port()) +} + +fn secure_token() -> String { + let mut bytes = [0u8; 32]; + OsRng.fill_bytes(&mut bytes); + bytes.iter().map(|byte| format!("{byte:02x}")).collect() +} + +fn prepend_path_env(command: &mut Command, dir: &Path) { + let key = if cfg!(target_os = "windows") { + "Path" + } else { + "PATH" + }; + let current = std::env::var_os(key).unwrap_or_default(); + let mut paths = vec![dir.to_path_buf()]; + paths.extend(std::env::split_paths(¤t)); + if let Ok(joined) = std::env::join_paths(paths) { + command.env(key, joined); + } +} + +fn find_on_path(binary: &str) -> Option { + let path_var = std::env::var_os(if cfg!(target_os = "windows") { + "Path" + } else { + "PATH" + })?; + std::env::split_paths(&path_var) + .map(|dir| dir.join(binary)) + .find(|candidate| candidate.is_file()) +} + +fn expand_home(path: PathBuf) -> PathBuf { + let path_string = path.to_string_lossy(); + if path_string == "~" { + return home_dir().unwrap_or(path); + } + if let Some(rest) = path_string.strip_prefix("~/") { + if let Some(home) = home_dir() { + return home.join(rest); + } + } + path +} + +fn home_dir() -> Option { + std::env::var_os("HOME") + .map(PathBuf::from) + .or_else(|| std::env::var_os("USERPROFILE").map(PathBuf::from)) +} + +fn agent_config_dir(app_handle: &AppHandle) -> Result { + let base = if cfg!(target_os = "windows") { + app_handle + .path() + .app_config_dir() + .map_err(|e| anyhow::anyhow!("Failed to resolve app config dir: {e}"))? + } else { + let home = std::env::var("HOME") + .map_err(|_| anyhow::anyhow!("Failed to get home directory"))?; + PathBuf::from(home).join(".config").join("maple") + }; + let path = base.join("agent"); + fs::create_dir_all(&path)?; + Ok(path) +} + +fn load_agent_config_inner(app_handle: &AppHandle) -> Result { + let path = agent_config_dir(app_handle)?.join("config.json"); + if !path.exists() { + return Ok(AgentConfig::default()); + } + let contents = fs::read_to_string(path)?; + Ok(serde_json::from_str(&contents)?) +} + +fn save_agent_config_inner( + app_handle: &AppHandle, + config: &AgentConfig, +) -> Result<(), anyhow::Error> { + let path = agent_config_dir(app_handle)?.join("config.json"); + write_json_file(&path, config) +} + +fn load_recent_project_roots_inner( + app_handle: &AppHandle, +) -> Result, anyhow::Error> { + let path = agent_config_dir(app_handle)?.join("recent_roots.json"); + if !path.exists() { + return Ok(Vec::new()); + } + let contents = fs::read_to_string(path)?; + Ok(serde_json::from_str(&contents)?) +} + +fn save_recent_project_root_inner( + app_handle: &AppHandle, + project_root: &Path, +) -> Result, anyhow::Error> { + let mut roots = load_recent_project_roots_inner(app_handle).unwrap_or_default(); + let path = path_string(project_root); + roots.retain(|root| root.path != path); + roots.insert( + 0, + RecentProjectRoot { + name: project_root + .file_name() + .and_then(|value| value.to_str()) + .unwrap_or(&path) + .to_string(), + path, + last_used_ms: unix_ms(), + }, + ); + roots.truncate(20); + + let file_path = agent_config_dir(app_handle)?.join("recent_roots.json"); + write_json_file(&file_path, &roots)?; + Ok(roots) +} + +fn append_session_event_inner( + app_handle: &AppHandle, + session_id: &str, + event: Value, +) -> Result<(), anyhow::Error> { + let sessions_dir = agent_config_dir(app_handle)?.join("sessions"); + fs::create_dir_all(&sessions_dir)?; + let path = sessions_dir.join(format!("{}.jsonl", sanitize_file_id(session_id))); + let mut file = OpenOptions::new().create(true).append(true).open(&path)?; + set_owner_only_permissions(&path); + let row = serde_json::json!({ + "ts": unix_ms(), + "event": event, + }); + serde_json::to_writer(&mut file, &row)?; + file.write_all(b"\n")?; + Ok(()) +} + +fn write_json_file(path: &Path, value: &T) -> Result<(), anyhow::Error> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + fs::write(path, serde_json::to_string_pretty(value)?)?; + set_owner_only_permissions(path); + Ok(()) +} + +#[cfg(unix)] +fn set_owner_only_permissions(path: &Path) { + use std::os::unix::fs::PermissionsExt; + let _ = fs::set_permissions(path, fs::Permissions::from_mode(0o600)); +} + +#[cfg(not(unix))] +fn set_owner_only_permissions(_path: &Path) {} + +fn sanitize_file_id(value: &str) -> String { + let sanitized: String = value + .chars() + .map(|ch| { + if ch.is_ascii_alphanumeric() || ch == '-' || ch == '_' { + ch + } else { + '_' + } + }) + .collect(); + if sanitized.is_empty() { + "session".to_string() + } else { + sanitized + } +} + +fn unix_ms() -> u128 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_millis()) + .unwrap_or_default() +} + +fn path_string(path: &Path) -> String { + path.to_string_lossy().to_string() +} diff --git a/frontend/src-tauri/src/lib.rs b/frontend/src-tauri/src/lib.rs index 1749ede55..004fdd11f 100644 --- a/frontend/src-tauri/src/lib.rs +++ b/frontend/src-tauri/src/lib.rs @@ -3,6 +3,8 @@ use tauri_plugin_deep_link::DeepLinkExt; mod pdf_extractor; mod proxy; +#[cfg(desktop)] +mod agent; // TTS is available on desktop and iOS (not Android) #[cfg(any(desktop, target_os = "ios"))] mod tts; @@ -33,12 +35,23 @@ pub fn run() { })) .plugin(tauri_plugin_log::Builder::default().level(log::LevelFilter::Info).build()) .plugin(tauri_plugin_deep_link::init()) + .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_fs::init()) + .manage(agent::AgentRuntimeState::new()) .manage(proxy::ProxyState::new()) .manage(tts::TTSState::new()) .invoke_handler(tauri::generate_handler![ + agent::agent_get_runtime_status, + agent::agent_start_runtime, + agent::agent_stop_runtime, + agent::agent_restart_runtime, + agent::agent_load_config, + agent::agent_save_config, + agent::agent_list_recent_project_roots, + agent::agent_save_recent_project_root, + agent::agent_append_session_event, proxy::start_proxy, proxy::stop_proxy, proxy::get_proxy_status, diff --git a/frontend/src-tauri/src/proxy.rs b/frontend/src-tauri/src/proxy.rs index 0eb6345c1..1a5339c1c 100644 --- a/frontend/src-tauri/src/proxy.rs +++ b/frontend/src-tauri/src/proxy.rs @@ -60,6 +60,14 @@ impl ProxyState { running: Arc::new(Mutex::new(false)), } } + + pub async fn status(&self) -> ProxyStatus { + ProxyStatus { + running: *self.running.lock().await, + config: self.config.lock().await.clone(), + error: None, + } + } } // On Windows the proxy config lives in the roaming %APPDATA% profile, so a @@ -245,14 +253,7 @@ pub async fn stop_proxy(state: State<'_, ProxyState>) -> Result) -> Result { - let running = *state.running.lock().await; - let config = state.config.lock().await.clone(); - - Ok(ProxyStatus { - running, - config, - error: None, - }) + Ok(state.status().await) } #[tauri::command] @@ -354,7 +355,7 @@ async fn save_proxy_config(app_handle: &AppHandle, config: &ProxyConfig) -> Resu Ok(()) } -async fn load_saved_proxy_config(app_handle: &AppHandle) -> Result { +pub async fn load_saved_proxy_config(app_handle: &AppHandle) -> Result { let path = get_config_path(app_handle).await?; if !path.exists() { @@ -377,6 +378,26 @@ async fn load_saved_proxy_config(app_handle: &AppHandle) -> Result Ok(config) } +pub async fn ensure_proxy_running( + app_handle: AppHandle, + state: State<'_, ProxyState>, +) -> Result { + let current = state.status().await; + if current.running { + return Ok(current); + } + + let config = load_saved_proxy_config(&app_handle) + .await + .map_err(|e| format!("Failed to load proxy config: {e}"))?; + + if config.api_key.trim().is_empty() { + return Err("Maple proxy is not configured with an API key yet".to_string()); + } + + start_proxy(app_handle, state, config).await +} + // Initialize proxy on app startup if auto_start is enabled pub async fn init_proxy_on_startup_simple(app_handle: AppHandle) -> Result<()> { // Load saved config diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index d57d19f01..1a340e7fa 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -58,13 +58,14 @@ } ], "security": { - "csp": "default-src 'self'; connect-src 'self' https://opensecret.cloud https://*.opensecret.cloud https://trymaple.ai https://*.trymaple.ai https://secretgpt.ai https://*.secretgpt.ai https://*.maple-ca8.pages.dev https://raw.githubusercontent.com localhost:* http://localhost:* http://0.0.0.0:* http://127.0.0.1:*; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob: mediastream:" + "csp": "default-src 'self'; connect-src 'self' https://opensecret.cloud https://*.opensecret.cloud https://trymaple.ai https://*.trymaple.ai https://secretgpt.ai https://*.secretgpt.ai https://*.maple-ca8.pages.dev https://raw.githubusercontent.com localhost:* http://localhost:* http://0.0.0.0:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob: mediastream:" } }, "bundle": { "active": true, "targets": ["nsis", "deb", "appimage", "rpm", "dmg", "app"], "publisher": "OpenSecret", + "resources": ["bin/*"], "icon": [ "icons/32x32.png", "icons/128x128.png", diff --git a/frontend/src/components/AgentMode.tsx b/frontend/src/components/AgentMode.tsx new file mode 100644 index 000000000..ef209223e --- /dev/null +++ b/frontend/src/components/AgentMode.tsx @@ -0,0 +1,893 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { + AlertCircle, + Bot, + Check, + Circle, + FolderOpen, + Loader2, + Play, + RotateCcw, + Send, + Square, + Terminal, + X +} from "lucide-react"; +import { + type ContentBlock, + type PlanEntry, + type SessionNotification, + type ToolCall, + type ToolCallContent, + type ToolCallUpdate, + type UsageUpdate +} from "@agentclientprotocol/sdk"; +import { Button } from "@/components/ui/button"; +import { Textarea } from "@/components/ui/textarea"; +import { Badge } from "@/components/ui/badge"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from "@/components/ui/select"; +import { Input } from "@/components/ui/input"; +import { Sidebar, SidebarToggle } from "@/components/Sidebar"; +import { MapleWordmark } from "@/components/MapleWordmark"; +import { + AgentAcpClient, + type PermissionDecision, + type PermissionRequestHandle +} from "@/services/agentAcpClient"; +import { + agentRuntimeService, + type AgentRuntimeStatus, + type RecentProjectRoot +} from "@/services/agentRuntimeService"; +import { + SIDEBAR_GRID_COLUMNS_CLASS, + getSidebarLayoutStyle +} from "@/constants/layout"; +import { cn, useIsLandscapeMobile, useIsMobile } from "@/utils/utils"; +import { isDesktop } from "@/utils/platform"; + +type AgentMessageRole = "user" | "assistant" | "thought" | "system"; + +interface AgentMessage { + id: string; + role: AgentMessageRole; + text: string; +} + +interface AgentToolState { + id: string; + title: string; + kind?: string; + status?: string; + input?: unknown; + output?: unknown; + content?: ToolCallContent[]; +} + +const DEFAULT_MODEL = "auto:powerful"; + +export function AgentMode() { + const isMobile = useIsMobile(); + const isLandscapeMobile = useIsLandscapeMobile(); + const isCompactLayout = isMobile || isLandscapeMobile; + const [isSidebarOpen, setIsSidebarOpen] = useState(!isCompactLayout); + const [runtimeStatus, setRuntimeStatus] = useState(null); + const [recentRoots, setRecentRoots] = useState([]); + const [projectRoot, setProjectRoot] = useState(""); + const [model, setModel] = useState(DEFAULT_MODEL); + const [sessionId, setSessionId] = useState(null); + const [messages, setMessages] = useState([]); + const [tools, setTools] = useState([]); + const [planEntries, setPlanEntries] = useState([]); + const [usage, setUsage] = useState(null); + const [pendingPermissions, setPendingPermissions] = useState([]); + const [input, setInput] = useState(""); + const [error, setError] = useState(null); + const [isStarting, setIsStarting] = useState(false); + const [isSending, setIsSending] = useState(false); + const clientRef = useRef(null); + const sessionIdRef = useRef(null); + const messagesEndRef = useRef(null); + + useEffect(() => { + setIsSidebarOpen(!isCompactLayout); + }, [isCompactLayout]); + + useEffect(() => { + let cancelled = false; + async function loadInitialState() { + if (!isDesktop()) return; + try { + const [status, config, roots] = await Promise.all([ + agentRuntimeService.getRuntimeStatus(), + agentRuntimeService.loadConfig(), + agentRuntimeService.listRecentProjectRoots() + ]); + if (cancelled) return; + setRuntimeStatus(status); + setRecentRoots(roots); + const root = status.projectRoot || config.defaultProjectRoot || roots[0]?.path || ""; + setProjectRoot(root); + setModel(status.model || config.defaultModel || DEFAULT_MODEL); + } catch (loadError) { + if (!cancelled) setError(errorMessage(loadError)); + } + } + void loadInitialState(); + return () => { + cancelled = true; + clientRef.current?.close(); + clientRef.current = null; + }; + }, []); + + useEffect(() => { + sessionIdRef.current = sessionId; + }, [sessionId]); + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ block: "end" }); + }, [messages, tools, pendingPermissions, planEntries]); + + const activeRootLabel = useMemo(() => { + if (!projectRoot) return "Select folder"; + return recentRoots.find((root) => root.path === projectRoot)?.name || basename(projectRoot); + }, [projectRoot, recentRoots]); + + const toggleSidebar = useCallback(() => setIsSidebarOpen((prev) => !prev), []); + + const handleSessionUpdate = useCallback((notification: SessionNotification) => { + const update = notification.update; + void agentRuntimeService.appendSessionEvent(notification.sessionId, { + type: "sessionUpdate", + update + }); + + switch (update.sessionUpdate) { + case "agent_message_chunk": + appendMessageChunk("assistant", update.messageId, contentBlockText(update.content)); + break; + case "agent_thought_chunk": + appendMessageChunk("thought", update.messageId, contentBlockText(update.content)); + break; + case "tool_call": + mergeToolCall(update); + break; + case "tool_call_update": + mergeToolCall(update); + break; + case "plan": + setPlanEntries(update.entries); + break; + case "usage_update": + setUsage(update); + break; + case "user_message_chunk": + case "available_commands_update": + case "current_mode_update": + case "config_option_update": + case "session_info_update": + break; + } + }, []); + + const createClient = useCallback(() => { + return new AgentAcpClient({ + onSessionUpdate: handleSessionUpdate, + onPermissionRequest: (request) => { + setPendingPermissions((current) => [...current, request]); + }, + onClosed: () => { + clientRef.current = null; + } + }); + }, [handleSessionUpdate]); + + const refreshRuntimeStatus = useCallback(async () => { + if (!isDesktop()) return; + const status = await agentRuntimeService.getRuntimeStatus(); + setRuntimeStatus(status); + }, []); + + const chooseProjectRoot = useCallback(async () => { + try { + const { open } = await import("@tauri-apps/plugin-dialog"); + const selected = await open({ + directory: true, + multiple: false, + title: "Select project folder" + }); + if (typeof selected === "string") { + setProjectRoot(selected); + const roots = await agentRuntimeService.saveRecentProjectRoot(selected); + setRecentRoots(roots); + } + } catch (chooseError) { + setError(errorMessage(chooseError)); + } + }, []); + + const ensureConnectedSession = useCallback(async () => { + if (!projectRoot) { + throw new Error("Select a project folder first"); + } + + let status = await agentRuntimeService.getRuntimeStatus(); + if (!status.running || !status.acpUrl) { + setIsStarting(true); + status = await agentRuntimeService.startRuntime({ + projectRoot, + model: model || DEFAULT_MODEL, + mode: "approve" + }); + setRuntimeStatus(status); + setRecentRoots(await agentRuntimeService.listRecentProjectRoots()); + setIsStarting(false); + } + + if (!status.acpUrl) { + throw new Error("ACP endpoint is not available"); + } + + if (!clientRef.current) { + const nextClient = createClient(); + await nextClient.connect(status.acpUrl); + clientRef.current = nextClient; + } + + let activeSessionId = sessionIdRef.current; + if (!activeSessionId) { + activeSessionId = await clientRef.current.newSession(projectRoot); + setSessionId(activeSessionId); + sessionIdRef.current = activeSessionId; + await agentRuntimeService.appendSessionEvent(activeSessionId, { + type: "sessionStarted", + projectRoot, + model: model || DEFAULT_MODEL + }); + } + + return { client: clientRef.current, sessionId: activeSessionId }; + }, [createClient, model, projectRoot]); + + const startRuntime = useCallback(async () => { + setError(null); + setIsStarting(true); + try { + if (!projectRoot) { + throw new Error("Select a project folder first"); + } + const status = await agentRuntimeService.startRuntime({ + projectRoot: projectRoot || null, + model: model || DEFAULT_MODEL, + mode: "approve" + }); + setRuntimeStatus(status); + setProjectRoot(status.projectRoot || projectRoot); + setModel(status.model || model || DEFAULT_MODEL); + setRecentRoots(await agentRuntimeService.listRecentProjectRoots()); + } catch (startError) { + setError(errorMessage(startError)); + } finally { + setIsStarting(false); + } + }, [model, projectRoot]); + + const restartRuntime = useCallback(async () => { + setError(null); + setIsStarting(true); + clientRef.current?.close(); + clientRef.current = null; + setSessionId(null); + setTools([]); + setPlanEntries([]); + setUsage(null); + setPendingPermissions([]); + try { + const status = await agentRuntimeService.restartRuntime({ + projectRoot: projectRoot || null, + model: model || DEFAULT_MODEL, + mode: "approve" + }); + setRuntimeStatus(status); + setProjectRoot(status.projectRoot || projectRoot); + setModel(status.model || model || DEFAULT_MODEL); + } catch (restartError) { + setError(errorMessage(restartError)); + } finally { + setIsStarting(false); + } + }, [model, projectRoot]); + + const stopRuntime = useCallback(async () => { + clientRef.current?.close(); + clientRef.current = null; + setSessionId(null); + setPendingPermissions([]); + setRuntimeStatus(await agentRuntimeService.stopRuntime()); + }, []); + + const sendMessage = useCallback(async () => { + const text = input.trim(); + if (!text || isSending) return; + + setError(null); + setInput(""); + setIsSending(true); + const userMessage: AgentMessage = { id: crypto.randomUUID(), role: "user", text }; + setMessages((current) => [...current, userMessage]); + + try { + const active = await ensureConnectedSession(); + await agentRuntimeService.appendSessionEvent(active.sessionId, { + type: "userPrompt", + text + }); + await active.client.prompt(active.sessionId, text); + } catch (sendError) { + setError(errorMessage(sendError)); + setMessages((current) => [ + ...current, + { id: crypto.randomUUID(), role: "system", text: errorMessage(sendError) } + ]); + } finally { + setIsSending(false); + } + }, [ensureConnectedSession, input, isSending]); + + const cancelPrompt = useCallback(async () => { + if (!sessionId || !clientRef.current) return; + try { + await clientRef.current.cancel(sessionId); + } catch (cancelError) { + setError(errorMessage(cancelError)); + } + }, [sessionId]); + + const respondToPermission = useCallback((id: string, decision: PermissionDecision) => { + setPendingPermissions((current) => { + const request = current.find((candidate) => candidate.id === id); + request?.decide(decision); + return current.filter((candidate) => candidate.id !== id); + }); + }, []); + + const cancelPermission = useCallback((id: string) => { + setPendingPermissions((current) => { + const request = current.find((candidate) => candidate.id === id); + request?.cancel(); + return current.filter((candidate) => candidate.id !== id); + }); + }, []); + + const handleKeyDown = useCallback( + (event: React.KeyboardEvent) => { + if (event.key === "Enter" && !event.shiftKey && !isCompactLayout) { + event.preventDefault(); + void sendMessage(); + } + }, + [isCompactLayout, sendMessage] + ); + + const sidebarLayoutStyle = getSidebarLayoutStyle({ offsetContent: isSidebarOpen }); + + if (!isDesktop()) { + return ( +
+
+ +

Agent Mode is available in Maple Desktop.

+
+
+ ); + } + + return ( +
+ + +
+ {!isSidebarOpen && ( +
+ + +
+ )} + +
+
+
+ +
+
+
+

Agent Mode

+ +
+

+ {projectRoot ? projectRoot : "No project folder selected"} +

+
+
+
+ + {runtimeStatus?.running ? ( + + ) : ( + + )} +
+
+ + {error && ( +
+
+ + {error} +
+
+ )} + +
+
+
+ {messages.length === 0 && tools.length === 0 ? ( +
+
+

+ Work in a folder... +

+ +
+
+ ) : ( + <> + + {planEntries.length > 0 && } + {tools.length > 0 && } + {pendingPermissions.length > 0 && ( + + )} + {usage && } + + )} +
+
+
+ + {messages.length > 0 || tools.length > 0 ? ( +
+
+ +
+
+ ) : null} +
+
+
+ ); + + function appendMessageChunk(role: AgentMessageRole, messageId: string | null | undefined, text: string) { + if (!text) return; + const id = messageId || `${role}-${crypto.randomUUID()}`; + setMessages((current) => { + const index = current.findIndex((message) => message.id === id); + if (index >= 0) { + const next = [...current]; + next[index] = { ...next[index], text: next[index].text + text }; + return next; + } + return [...current, { id, role, text }]; + }); + } + + function mergeToolCall(update: (ToolCall | ToolCallUpdate) & { sessionUpdate: string }) { + setTools((current) => { + const index = current.findIndex((tool) => tool.id === update.toolCallId); + const previous = index >= 0 ? current[index] : null; + const nextTool: AgentToolState = { + id: update.toolCallId, + title: update.title ?? previous?.title ?? "Tool call", + kind: update.kind ?? previous?.kind, + status: update.status ?? previous?.status, + input: update.rawInput ?? previous?.input, + output: update.rawOutput ?? previous?.output, + content: update.content ?? previous?.content + }; + + if (index >= 0) { + const next = [...current]; + next[index] = nextTool; + return next; + } + return [...current, nextTool]; + }); + } +} + +interface AgentComposerProps { + activeRootLabel: string; + input: string; + isSending: boolean; + isStarting: boolean; + model: string; + projectRoot: string; + recentRoots: RecentProjectRoot[]; + onCancelPrompt: () => void; + onChooseProjectRoot: () => void; + onInputChange: (value: string) => void; + onKeyDown: (event: React.KeyboardEvent) => void; + onModelChange: (value: string) => void; + onProjectRootChange: (value: string) => void; + onRestartRuntime: () => void; + onSendMessage: () => void; +} + +function AgentComposer({ + activeRootLabel, + input, + isSending, + isStarting, + model, + projectRoot, + recentRoots, + onCancelPrompt, + onChooseProjectRoot, + onInputChange, + onKeyDown, + onModelChange, + onProjectRootChange, + onRestartRuntime, + onSendMessage +}: AgentComposerProps) { + return ( +
+
+ + + onModelChange(event.target.value)} + className="h-8 w-[11rem] rounded-md border-0 bg-muted/60 text-xs" + aria-label="Agent model" + /> + +
+
+