From cd3b45e2534faf4b6f84b663899c1185a0c31091 Mon Sep 17 00:00:00 2001 From: Tejas Kashinath Date: Thu, 26 Feb 2026 14:52:44 -0500 Subject: [PATCH] chore: remove web-harness and update rollup to fix vulnerability --- eslint.config.mjs | 1 - package-lock.json | 206 +- src/cli/AGENTS.md | 11 - web-harness/AGENTS.md | 44 - web-harness/README.md | 225 --- web-harness/browser-entry.tsx | 153 -- web-harness/cli-constants-mock.ts | 28 - web-harness/cli-mock.ts | 29 - web-harness/cli-schema-mock.ts | 32 - web-harness/external-mocks.ts | 318 --- web-harness/harness-env.ts | 41 - web-harness/index.html | 19 - web-harness/ink-browser-shim.tsx | 175 -- web-harness/ink-spinner-shim.tsx | 16 - web-harness/lib-mocks.ts | 245 --- web-harness/mock-fs-client.ts | 248 --- web-harness/mock-fs-server.ts | 200 -- .../mocks/demo-workspace/agentcore.json | 79 - .../mocks/demo-workspace/aws-targets.json | 14 - .../mocks/demo-workspace/deployed-state.json | 13 - .../mocks/demo-workspace/mcp-defs.json | 25 - web-harness/mocks/demo-workspace/mcp.json | 72 - .../mocks/empty-workspace/agentcore.json | 6 - .../mocks/empty-workspace/aws-targets.json | 1 - .../mocks/empty-workspace/deployed-state.json | 3 - .../mocks/empty-workspace/mcp-defs.json | 3 - web-harness/mocks/empty-workspace/mcp.json | 3 - web-harness/nl-edit-mock.ts | 90 - web-harness/node-mocks.ts | 445 ----- web-harness/package-lock.json | 1768 ----------------- web-harness/package.json | 23 - web-harness/schema-assets-mock.ts | 12 - web-harness/screenshot.png | Bin 40472 -> 0 bytes web-harness/shell-mock.ts | 65 - web-harness/template-root-mock.ts | 11 - web-harness/test-harness.mjs | 73 - web-harness/test-writable-fs.mjs | 117 -- web-harness/tsconfig.json | 29 - web-harness/tui-process-mock.ts | 9 - web-harness/vite.config.ts | 247 --- 40 files changed, 103 insertions(+), 4996 deletions(-) delete mode 100644 web-harness/AGENTS.md delete mode 100644 web-harness/README.md delete mode 100644 web-harness/browser-entry.tsx delete mode 100644 web-harness/cli-constants-mock.ts delete mode 100644 web-harness/cli-mock.ts delete mode 100644 web-harness/cli-schema-mock.ts delete mode 100644 web-harness/external-mocks.ts delete mode 100644 web-harness/harness-env.ts delete mode 100644 web-harness/index.html delete mode 100644 web-harness/ink-browser-shim.tsx delete mode 100644 web-harness/ink-spinner-shim.tsx delete mode 100644 web-harness/lib-mocks.ts delete mode 100644 web-harness/mock-fs-client.ts delete mode 100644 web-harness/mock-fs-server.ts delete mode 100644 web-harness/mocks/demo-workspace/agentcore.json delete mode 100644 web-harness/mocks/demo-workspace/aws-targets.json delete mode 100644 web-harness/mocks/demo-workspace/deployed-state.json delete mode 100644 web-harness/mocks/demo-workspace/mcp-defs.json delete mode 100644 web-harness/mocks/demo-workspace/mcp.json delete mode 100644 web-harness/mocks/empty-workspace/agentcore.json delete mode 100644 web-harness/mocks/empty-workspace/aws-targets.json delete mode 100644 web-harness/mocks/empty-workspace/deployed-state.json delete mode 100644 web-harness/mocks/empty-workspace/mcp-defs.json delete mode 100644 web-harness/mocks/empty-workspace/mcp.json delete mode 100644 web-harness/nl-edit-mock.ts delete mode 100644 web-harness/node-mocks.ts delete mode 100644 web-harness/package-lock.json delete mode 100644 web-harness/package.json delete mode 100644 web-harness/schema-assets-mock.ts delete mode 100644 web-harness/screenshot.png delete mode 100644 web-harness/shell-mock.ts delete mode 100644 web-harness/template-root-mock.ts delete mode 100644 web-harness/test-harness.mjs delete mode 100644 web-harness/test-writable-fs.mjs delete mode 100644 web-harness/tsconfig.json delete mode 100644 web-harness/tui-process-mock.ts delete mode 100644 web-harness/vite.config.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 77e3670f..27d45a4f 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -83,7 +83,6 @@ export default tseslint.config( 'node_modules', 'src/assets', 'src/schema/llm-compacted', - 'web-harness', '.agentcore', '**/.agentcore/**', '.venv', diff --git a/package-lock.json b/package-lock.json index eeadc553..eb36528f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4063,9 +4063,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -4077,9 +4077,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -4091,9 +4091,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -4105,9 +4105,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -4119,9 +4119,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -4133,9 +4133,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -4147,9 +4147,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -4161,9 +4161,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -4175,9 +4175,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -4189,9 +4189,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -4203,9 +4203,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", "cpu": [ "loong64" ], @@ -4217,9 +4217,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -4231,9 +4231,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", "cpu": [ "ppc64" ], @@ -4245,9 +4245,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -4259,9 +4259,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -4273,9 +4273,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -4287,9 +4287,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -4301,9 +4301,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -4315,9 +4315,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -4329,9 +4329,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", "cpu": [ "x64" ], @@ -4343,9 +4343,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -4357,9 +4357,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -4371,9 +4371,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -4385,9 +4385,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -4399,9 +4399,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -11934,9 +11934,9 @@ "license": "MIT" }, "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -11950,31 +11950,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, diff --git a/src/cli/AGENTS.md b/src/cli/AGENTS.md index d340b1a0..42f5ffff 100644 --- a/src/cli/AGENTS.md +++ b/src/cli/AGENTS.md @@ -56,17 +56,6 @@ The TUI is defined using ink, a library that converts React definitions to termi Ink supports a subset of React features and components should be directly imported from ink. -## Testing UI changes E2E - -At the top level `web-harness/` directory a shim over Ink, as well as a mock of Node API and CLI business logic is -defined. By running the vite local host dev server, a web app based on the same visual source of truth as the terminal -is hosted. Always launch a web-harness web server and use the browser MCP tool to test changes E2E. Create mocks as -appropriate to test the relevant surface area. - -If start up issues are encountered, read the console error to troubleshoot bugs and update the harness. - -## Dev Server Architecture - The `dev` command uses a strategy pattern with a `DevServer` base class and two implementations: - **CodeZipDevServer**: Runs uvicorn locally with Python venv hot-reload diff --git a/web-harness/AGENTS.md b/web-harness/AGENTS.md deleted file mode 100644 index e116f533..00000000 --- a/web-harness/AGENTS.md +++ /dev/null @@ -1,44 +0,0 @@ -# Web Harness Testing - -This directory contains a web-based harness for testing the CLI TUI components in a browser environment. - -## Usage - -1. Start the harness: `npm run dev` -2. Navigate to the URL shown in the terminal (usually http://localhost:5173 or similar) -3. Use playwright browser tools to interact with the TUI - -## CRITICAL: Console Error Protocol - -**BEFORE doing ANYTHING else after starting or restarting the harness, you MUST:** - -1. Open the browser or use playwright tools to check console errors -2. If ANY errors exist, STOP and FIX them before proceeding -3. Do NOT claim the harness is working until you have verified zero console errors - -### Checking for Errors - -Use playwright MCP tools to check console: - -``` -mcp__playwright__browser_console_messages with level: "error" -``` - -Or manually open http://localhost:5173 in a browser and check DevTools Console. - -### Common Errors and Fixes - -1. **"Invalid or unexpected token"** - Usually a missing mock in vite.config.ts -2. **Module not found / 404** - Add the module to the mocks in vite.config.ts -3. **React rendering errors** - Check component imports and props - -### After Making Code Changes - -After ANY code changes to TUI components: - -1. Rebuild packages: `npm run build:packages` (from repo root) -2. Restart harness: kill vite, run `npm run dev` -3. CHECK CONSOLE ERRORS before proceeding -4. Fix any errors that appear - -**This protocol is NON-NEGOTIABLE. Do not skip checking console errors.** diff --git a/web-harness/README.md b/web-harness/README.md deleted file mode 100644 index cee733a5..00000000 --- a/web-harness/README.md +++ /dev/null @@ -1,225 +0,0 @@ -# AgentCore CLI - Browser Test Harness - -A browser-based visual testing harness for the AgentCore CLI's Ink-based terminal UI. This allows you to render and -interact with the CLI interface in a web browser at multiple terminal sizes simultaneously. - -## Quick Start - -```bash -cd web-harness -npm install -npm run dev -# Opens http://localhost:5173 -``` - -## What is This? - -This harness renders the **real AgentCore CLI TUI components** in a browser environment by: - -1. **Shimming Ink** - Replacing Ink's terminal rendering with browser DOM elements -2. **Mocking Node.js APIs** - Providing browser-compatible stubs for `fs`, `path`, `child_process`, etc. -3. **Mocking CLI operations** - Simulating file I/O, shell commands, and AWS operations - -The result is a fully interactive UI that you can visually test without needing a real terminal or AWS infrastructure. - -## Intended Use: Visual Testing with Playwright MCP - -This harness is designed to be used with [Playwright MCP](https://github.com/anthropic/claude-code) for automated visual -testing via Claude Code. - -### Setup Playwright MCP - -```bash -claude mcp add playwright -- npx @playwright/mcp@latest -``` - -#### Headless Mode (no browser window) - -To run the browser invisibly in the background, edit the MCP config file: - -```bash -# Find and edit the config (location varies by installation) -~/.claude/plugins/.../playwright/.mcp.json -``` - -Add `--headless` to the args: - -```json -{ - "playwright": { - "command": "npx", - "args": ["@playwright/mcp@latest", "--headless"] - } -} -``` - -Then restart Claude Code or run `/mcp` to reconnect. - -### Example Usage with Claude - -Once the harness is running (`npm run dev`), you can ask Claude to: - -- "Navigate to http://localhost:5173 and screenshot the home screen" -- "Click on the 'init' option and verify the wizard renders correctly" -- "Test keyboard navigation through the menu" -- "Check how the UI looks at different terminal sizes" - -## Architecture - -### What's Real (from source) - -These are imported **directly from the CLI source code** - no mocking: - -| Component | Path | -| ------------------------- | --------------------------------------------- | -| `App` (main TUI) | `packages/agentcore-cli/src/tui/App.tsx` | -| All TUI screens | `packages/agentcore-cli/src/tui/screens/*` | -| All TUI components | `packages/agentcore-cli/src/tui/components/*` | -| TUI hooks | `packages/agentcore-cli/src/tui/hooks/*` | -| Schema types & validation | `packages/agentcore-schema/*` (via Zod) | - -### What's Mocked - -These are replaced with browser-compatible shims: - -| Module | Mock File | Purpose | -| ------------------------- | ---------------------- | -------------------------------------- | -| `ink` | `ink-browser-shim.tsx` | Box, Text, useInput, useApp, useStdout | -| `ink-spinner` | `ink-spinner-shim.tsx` | Animated spinner component | -| `fs`, `path`, `url`, etc. | `node-mocks.ts` | Node.js built-in modules | -| `child_process`, `net` | `node-mocks.ts` | Process/network operations | -| `@agentcore/lib` | `lib-mocks.ts` | ConfigIO, file utilities | -| `../cli` | `cli-mock.ts` | Commander program setup | -| `../shell` | `shell-mock.ts` | Shell command execution | -| AWS SDK clients | `external-mocks.ts` | CloudFormation, STS, Bedrock | -| `commander` | `external-mocks.ts` | CLI framework | -| `handlebars` | `external-mocks.ts` | Template rendering | - -### Mock Behavior - -- **File operations**: Return mock JSON data based on active scenario -- **Shell commands**: Simulate immediate success with mock output -- **ConfigIO**: Returns mock workspace data from scenario files -- **AWS operations**: Not executed, return mock responses - -## Mock Scenarios - -Configuration is centralized in `harness-env.ts`. Mock workspace data lives in `mocks/` with different scenarios: - -``` -mocks/ -├── demo-workspace/ # Full workspace with 2 agents, AWS targets, deployed state -│ ├── agentcore.json # DemoWorkspace with ResearchAssistant & CodeReviewer agents -│ ├── aws-targets.json # development (us-west-2) and production (us-east-1) -│ ├── mcp.json # main-gateway with ResearchAssistant -│ ├── mcp-defs.json # web-search and code-analyzer tools -│ └── deployed-state.json -└── empty-workspace/ # Fresh init state, no agents - ├── agentcore.json # EmptyWorkspace with no agents - ├── aws-targets.json # Empty array - ├── mcp.json # No gateways - ├── mcp-defs.json # No tools - └── deployed-state.json -``` - -### Switching Scenarios - -Edit `harness-env.ts` to change the active scenario: - -```typescript -// harness-env.ts -export const MOCK_SCENARIO: MockScenario = 'demo-workspace'; // or 'empty-workspace' -``` - -Then reload the browser to apply changes. - -### Adding New Scenarios - -1. Create a new directory under `mocks/` (e.g., `mocks/error-state/`) -2. Add the 5 schema JSON files: - - `agentcore.json` - Workspace spec with agents array - - `aws-targets.json` - AWS deployment targets - - `mcp.json` - MCP gateways configuration - - `mcp-defs.json` - MCP tool definitions - - `deployed-state.json` - Deployed resource state -3. Import the files in both `node-mocks.ts` and `lib-mocks.ts` -4. Add the scenario to the `MockScenario` type in `harness-env.ts` -5. Add the scenario data to `MOCK_FILES` in `node-mocks.ts` and `SCENARIO_DATA` in `lib-mocks.ts` - -## File Structure - -``` -web-harness/ -├── package.json # Dependencies (vite, react, zod) -├── vite.config.ts # Vite config with module aliasing -├── index.html # HTML entry point -├── tsconfig.json # TypeScript configuration -├── harness-env.ts # Harness configuration (scenario, paths, flags) -├── browser-entry.tsx # Main entry - VirtualTerminal wrapper -├── ink-browser-shim.tsx # Ink component/hook replacements -├── ink-spinner-shim.tsx # Spinner component -├── node-mocks.ts # fs, path, child_process, net, etc. -├── lib-mocks.ts # @agentcore/lib mocks (ConfigIO) -├── cli-mock.ts # Commander program mock -├── shell-mock.ts # Shell execution mock -├── external-mocks.ts # AWS SDK, commander, handlebars -├── cli-constants-mock.ts # CLI constants (uses Node.js 'module') -├── tui-process-mock.ts # TUI process utilities -├── template-root-mock.ts # Template path resolution -├── schema-text-mock.ts # Schema text file mock -└── mocks/ # Mock workspace data by scenario - ├── demo-workspace/ # Full workspace with agents - └── empty-workspace/ # Fresh init state -``` - -## Virtual Terminals - -The harness displays three terminal sizes simultaneously: - -| Name | Size | Use Case | -| -------- | ------ | ------------------------- | -| Standard | 80x24 | Default terminal size | -| Narrow | 50x20 | Split pane / small window | -| Large | 120x40 | Full HD terminal | - -Click a terminal to focus keyboard input to it. - -## Keyboard Navigation - -All standard Ink keyboard controls work: - -- **Arrow keys**: Navigate menus -- **Enter**: Select/confirm -- **Escape**: Go back/cancel -- **Tab**: Next field -- **Type**: Text input in forms - -## Limitations - -Since this runs in a browser with mocked backends: - -1. **No real file I/O** - Files aren't actually created/read -2. **No real shell commands** - Commands return mock output -3. **No AWS operations** - Deployments are simulated -4. **No persistent state** - Refreshing resets everything - -This is by design - the harness is for **visual/interaction testing**, not functional testing of backend operations. - -## Development - -### Adding New Mocks - -If you encounter a "Module externalized for browser compatibility" error: - -1. Identify the Node.js module in the error (e.g., `node:dns`) -2. Add it to the `mocks` object in `vite.config.ts` -3. Add stub exports to `node-mocks.ts` - -### Debugging Module Resolution - -The Vite plugin logs interceptions to the console. Check the terminal running `npm run dev` for: - -``` -[browser-mocks] INTERCEPTING cli import -> /path/to/cli-mock.ts -[browser-mocks] INTERCEPTING constants import -> /path/to/cli-constants-mock.ts -``` diff --git a/web-harness/browser-entry.tsx b/web-harness/browser-entry.tsx deleted file mode 100644 index 387ae0fe..00000000 --- a/web-harness/browser-entry.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { App } from '../src/cli/tui/App'; -import { TerminalContext } from './ink-browser-shim'; -import React, { Component, ErrorInfo, ReactNode, useState } from 'react'; -import ReactDOM from 'react-dom/client'; - -// Error boundary to catch and display render errors -class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean; error: Error | null }> { - constructor(props: { children: ReactNode }) { - super(props); - this.state = { hasError: false, error: null }; - } - - static getDerivedStateFromError(error: Error) { - return { hasError: true, error }; - } - - componentDidCatch(error: Error, errorInfo: ErrorInfo) { - console.error('React Error Boundary caught:', error, errorInfo); - } - - render() { - if (this.state.hasError) { - return ( -
-
Render Error:
-
{this.state.error?.message}
-
{this.state.error?.stack}
-
- ); - } - return this.props.children; - } -} - -interface VirtualTerminalProps { - columns: number; - rows: number; - label: string; - children: React.ReactNode; - isActive?: boolean; - onFocus?: () => void; -} - -const VirtualTerminal = ({ columns, rows, label, children, isActive, onFocus }: VirtualTerminalProps) => ( -
-
- {label} ({columns}x{rows}) {isActive && '← active'} -
-
- {children} -
-
-); - -function TestHarness() { - const [activeTerminal, setActiveTerminal] = useState('standard'); - - return ( -
-

AgentCore CLI - Browser Test Harness

-

- Click a terminal to focus keyboard input. Test responsive layouts at different sizes. -

- -
- setActiveTerminal('standard')} - > - {activeTerminal === 'standard' && ( - - - - )} - - - setActiveTerminal('narrow')} - > - {activeTerminal === 'narrow' && ( - - - - )} - - - setActiveTerminal('large')} - > - {activeTerminal === 'large' && ( - - - - )} - -
-
- ); -} - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - -); diff --git a/web-harness/cli-constants-mock.ts b/web-harness/cli-constants-mock.ts deleted file mode 100644 index 1fdd2054..00000000 --- a/web-harness/cli-constants-mock.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Mock for CLI constants that use Node.js 'module' built-in - -export const PACKAGE_VERSION = '0.0.0-browser'; -export const CDK_PROJECT_DIR = 'cdk'; -export const CDK_APP_ENTRY = 'dist/bin/cdk.js'; -export const DEV_MODE = true; -export const DEV_LINK_PACKAGES = ['@agentcore/cdk', '@agentcore/lib', '@agentcore/schema']; -export const SCHEMA_VERSION = 1; - -export type DistroMode = 'PROD_DISTRO' | 'PRIVATE_DEV_DISTRO'; -export const DISTRO_MODE: DistroMode = 'PROD_DISTRO'; - -export const DISTRO_CONFIG = { - PROD_DISTRO: { - packageName: '@aws/agentcore', - registryUrl: 'https://registry.npmjs.org', - installCommand: 'npm install -g @aws/agentcore@latest', - }, - PRIVATE_DEV_DISTRO: { - packageName: '@aws/agentcore', - registryUrl: 'https://npm.pkg.github.com', - installCommand: 'npm install -g @aws/agentcore@latest --registry=https://npm.pkg.github.com', - }, -} as const; - -export function getDistroConfig() { - return DISTRO_CONFIG[DISTRO_MODE]; -} diff --git a/web-harness/cli-mock.ts b/web-harness/cli-mock.ts deleted file mode 100644 index 0990e3e4..00000000 --- a/web-harness/cli-mock.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Mock for the CLI module that creates a Commander program -// This avoids importing the real cli.ts which has many Node.js dependencies - -// Mock CommandMeta type -export interface MockCommand { - name(): string; - description(): string; - commands: MockCommand[]; -} - -// Create a mock program with minimal commands for UI testing -export function createProgram(): MockCommand { - const mockCommands: MockCommand[] = [ - { name: () => 'init', description: () => 'Initialize a new AgentCore workspace', commands: [] }, - { name: () => 'create', description: () => 'Create a new agent or tool', commands: [] }, - { name: () => 'dev', description: () => 'Start local development server', commands: [] }, - { name: () => 'deploy', description: () => 'Deploy to AWS', commands: [] }, - { name: () => 'edit', description: () => 'Edit workspace configuration', commands: [] }, - { name: () => 'add', description: () => 'Add MCP tools or gateways', commands: [] }, - { name: () => 'status', description: () => 'Show workspace status', commands: [] }, - ]; - - return { - name: () => 'agentcore', - description: () => 'AgentCore CLI', - version: () => '0.0.0-browser', - commands: mockCommands, - } as MockCommand & { version: () => string }; -} diff --git a/web-harness/cli-schema-mock.ts b/web-harness/cli-schema-mock.ts deleted file mode 100644 index 2e406b84..00000000 --- a/web-harness/cli-schema-mock.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Mock for the CLI's schema document module (src/cli/schema). - * The real module uses fs/promises which is not available in browser. - */ - -export interface LoadDocumentResult { - content: string; - validationError?: string; -} - -export interface SaveDocumentResult { - ok: boolean; - content?: string; - error?: string; -} - -export async function loadSchemaDocument(_filePath: string, _schema: unknown): Promise { - console.log('[cli-schema-mock] loadSchemaDocument called'); - return { - content: '{}', - validationError: undefined, - }; -} - -export async function saveSchemaDocument( - _filePath: string, - content: string, - _schema: unknown -): Promise { - console.log('[cli-schema-mock] saveSchemaDocument called'); - return { ok: true, content }; -} diff --git a/web-harness/external-mocks.ts b/web-harness/external-mocks.ts deleted file mode 100644 index aec4873e..00000000 --- a/web-harness/external-mocks.ts +++ /dev/null @@ -1,318 +0,0 @@ -// Mock external packages that aren't needed for UI rendering - -// Mock terminal detection packages -export const supportsColor = { stdout: false, stderr: false }; -export const createSupportsColor = () => ({ stdout: false, stderr: false }); -export const supportsHyperlinks = { stdout: false, stderr: false }; - -// Mock @resvg/resvg-js -export class Resvg { - constructor(_svg: string, _options?: any) {} - render() { - return { asPng: () => new Uint8Array() }; - } -} - -// Mock commander -export class Command { - constructor() {} - name() { - return this; - } - description() { - return this; - } - version() { - return '0.0.0'; - } - option() { - return this; - } - action() { - return this; - } - command() { - return new Command(); - } - parse() {} - commands: Command[] = []; -} - -// Mock zod -export const z = { - string: () => ({ - min: () => z.string(), - max: () => z.string(), - regex: () => z.string(), - optional: () => z.string(), - default: () => z.string(), - describe: () => z.string(), - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), - number: () => ({ - min: () => z.number(), - max: () => z.number(), - optional: () => z.number(), - default: () => z.number(), - describe: () => z.number(), - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), - boolean: () => ({ - optional: () => z.boolean(), - default: () => z.boolean(), - describe: () => z.boolean(), - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), - object: (shape: any) => ({ - shape, - optional: () => z.object(shape), - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - extend: (ext: any) => z.object({ ...shape, ...ext }), - }), - array: (item: any) => ({ - element: item, - optional: () => z.array(item), - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), - enum: (values: string[]) => ({ - options: values, - optional: () => z.enum(values), - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), - union: (types: any[]) => ({ - options: types, - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), - literal: (value: any) => ({ - value, - parse: () => value, - safeParse: () => ({ success: true, data: value }), - }), - any: () => ({ - parse: (v: any) => v, - safeParse: (v: any) => ({ success: true, data: v }), - }), -}; - -// Mock AWS SDK clients -export class STSClient { - constructor(_config: any) {} - send(_command: any) { - return Promise.resolve({}); - } -} - -export class GetCallerIdentityCommand { - constructor(_input?: any) {} -} - -export class CloudFormationClient { - constructor(_config: any) {} - send(_command: any) { - return Promise.resolve({}); - } -} - -export class DescribeStacksCommand { - constructor(_input?: any) {} -} - -export class DescribeStackEventsCommand { - constructor(_input?: any) {} -} - -export class BedrockRuntimeClient { - constructor(_config: any) {} - send(_command: any) { - return Promise.resolve({}); - } -} - -export class InvokeModelCommand { - constructor(_input?: any) {} -} - -// Mock @aws-sdk/client-bedrock-agentcore -export class BedrockAgentCoreClient { - constructor(_config: any) {} - send(_command: any) { - return Promise.resolve({}); - } -} - -export class InvokeAgentRuntimeCommand { - constructor(_input?: any) {} -} - -// Mock @aws-sdk/client-bedrock-agentcore-control -export class BedrockAgentCoreControlClient { - constructor(_config: any) {} - send(_command: any) { - return Promise.resolve({}); - } -} - -export class GetAgentRuntimeCommand { - constructor(_input?: any) {} -} - -export class CreateApiKeyCredentialProviderCommand { - constructor(_input?: any) {} -} - -export class GetApiKeyCredentialProviderCommand { - constructor(_input?: any) {} -} - -// Mock AWS SDK exceptions -export class ResourceNotFoundException extends Error { - name = 'ResourceNotFoundException'; - constructor(message?: string) { - super(message || 'Resource not found'); - } -} - -// Mock credential providers -export const fromNodeProviderChain = () => async () => ({ - accessKeyId: 'mock', - secretAccessKey: 'mock', -}); - -export const fromEnv = () => async () => ({ - accessKeyId: 'mock', - secretAccessKey: 'mock', -}); - -// Mock shared ini file loader -export const loadSharedConfigFiles = async () => ({ - configFile: {}, - credentialsFile: {}, -}); - -// Mock @aws-sdk/client-resource-groups-tagging-api -export class ResourceGroupsTaggingAPIClient { - constructor(_config: any) {} - send(_command: any) { - return Promise.resolve({ ResourceTagMappingList: [] }); - } -} - -export class GetResourcesCommand { - constructor(_input?: any) {} -} - -// Mock CDK toolkit-lib -export const StackSelectionStrategy = { - ALL_STACKS: 'ALL_STACKS', - PATTERN_MUST_MATCH: 'PATTERN_MUST_MATCH', - PATTERN_MUST_MATCH_SINGLE: 'PATTERN_MUST_MATCH_SINGLE', - NONE: 'NONE', -}; - -export class Toolkit { - constructor(_options: any) {} - - async fromCdkApp(_command: string, _options?: any) { - // Return a mock ICloudAssemblySource - return { - produce: async () => ({ - cloudAssembly: { - directory: '/mock/cdk.out', - stacks: [{ stackName: 'MockStack' }], - }, - dispose: async () => {}, - }), - }; - } - - fromAssemblyDirectory(_directory: string) { - return { - produce: async () => ({ - cloudAssembly: { - directory: '/mock/cdk.out', - stacks: [{ stackName: 'MockStack' }], - }, - dispose: async () => {}, - }), - }; - } - - synth(_source: any, _options?: any) { - // Return a synth result that matches the expected interface - return Promise.resolve({ - produce: async () => ({ - cloudAssembly: { - directory: '/mock/cdk.out', - stacks: [{ stackName: 'AgentCoreStack-us-west-2' }, { stackName: 'AgentCoreStack-us-east-1' }], - }, - dispose: async () => {}, - }), - dispose: async () => {}, - }); - } - - deploy(_source: any, _options?: any) { - return Promise.resolve({}); - } - - destroy(_source: any, _options?: any) { - return Promise.resolve({}); - } - - diff(_source: any, _options?: any) { - return Promise.resolve({}); - } - - list(_source: any, _options?: any) { - return Promise.resolve([{ stackName: 'MockStack' }]); - } - - bootstrap(_environments: any) { - return Promise.resolve({}); - } -} - -export const BaseCredentials = { - awsCliCompatible: (_options?: any) => ({}), -}; -export const BootstrapEnvironments = { - fromList: (_environments: string[]) => ({}), -}; - -// Mock Handlebars -const Handlebars = { - compile: (template: string) => (context: any) => template, - parse: (template: string) => ({ type: 'Program', body: [] }), - precompile: (template: string) => 'function() { return ""; }', - registerHelper: () => {}, - registerPartial: () => {}, - SafeString: class SafeString { - constructor(public value: string) {} - toString() { - return this.value; - } - }, -}; - -export default Handlebars; -export { Handlebars }; -export const parse = Handlebars.parse; -export const compile = Handlebars.compile; - -// Mock @agentcore/cdk -export const logicalId = (name: string) => `Mock${name}`; -export const toPascalId = (name: string) => - name.replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : '')).replace(/^./, s => s.toUpperCase()); -export class AgentCoreApplication { - constructor(_scope: any, _id: string, _props: any) {} -} -export class AgentCoreMcp { - constructor(_scope: any, _id: string, _props: any) {} -} diff --git a/web-harness/harness-env.ts b/web-harness/harness-env.ts deleted file mode 100644 index 41c23292..00000000 --- a/web-harness/harness-env.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Harness Environment Configuration - * - * Central configuration for the browser test harness. - * Change these settings to test different scenarios. - */ - -// ============= Mock Scenario ============= -// Available scenarios (defined in mocks/ directory): -// - 'demo-workspace': Full workspace with 2 agents, AWS targets, deployed state -// - 'empty-workspace': Fresh init state, no agents - -export type MockScenario = 'demo-workspace' | 'empty-workspace'; - -/** - * The active mock scenario. - * Change this to test different workspace states. - */ -export const MOCK_SCENARIO: MockScenario = 'demo-workspace'; - -// ============= Mock Paths ============= -// These define where the mock workspace "lives" in the virtual filesystem -// NOTE: These must match the paths in mock-fs-server.ts and mock-fs-client.ts - -export const MOCK_WORKSPACE_ROOT = '/mock/workspace'; -export const MOCK_AGENTCORE_DIR = `${MOCK_WORKSPACE_ROOT}/agentcore`; -export const MOCK_CLI_DIR = `${MOCK_AGENTCORE_DIR}/.cli`; - -// ============= Feature Flags ============= -// Enable/disable features for testing - -export const HARNESS_CONFIG = { - /** Log mock operations to console */ - logMockOperations: false, - - /** Simulate network latency for async operations (ms) */ - simulatedLatency: 0, - - /** Show debug borders around Ink components */ - debugBorders: false, -} as const; diff --git a/web-harness/index.html b/web-harness/index.html deleted file mode 100644 index 27a2a60e..00000000 --- a/web-harness/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - AgentCore CLI - Browser Test - - - -
- - - diff --git a/web-harness/ink-browser-shim.tsx b/web-harness/ink-browser-shim.tsx deleted file mode 100644 index 41706bcd..00000000 --- a/web-harness/ink-browser-shim.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import React, { createContext, useContext, useEffect } from 'react'; - -// Terminal dimensions context -export const TerminalContext = createContext({ columns: 80, rows: 24 }); - -// Box component - flexbox container -// Ink uses character units: 1 padding = 1 character width -export const Box = ({ - children, - flexDirection = 'row', - borderStyle, - borderColor, - padding, - paddingX, - paddingY, - paddingLeft, - paddingRight, - paddingTop, - paddingBottom, - margin, - marginTop, - marginBottom, - marginLeft, - marginRight, - marginX, - marginY, - width, - height, - minWidth, - minHeight, - flexGrow, - flexShrink, - flexBasis, - justifyContent, - alignItems, - alignSelf, - gap, - overflowX, - overflowY, - ...rest -}: any) => { - // Calculate padding - specific overrides general - const pl = paddingLeft ?? paddingX ?? padding ?? 0; - const pr = paddingRight ?? paddingX ?? padding ?? 0; - const pt = paddingTop ?? paddingY ?? padding ?? 0; - const pb = paddingBottom ?? paddingY ?? padding ?? 0; - - // Calculate margin - specific overrides general - const ml = marginLeft ?? marginX ?? margin ?? 0; - const mr = marginRight ?? marginX ?? margin ?? 0; - const mt = marginTop ?? marginY ?? margin ?? 0; - const mb = marginBottom ?? marginY ?? margin ?? 0; - - const style: React.CSSProperties = { - display: 'flex', - flexDirection, - justifyContent, - alignItems, - alignSelf, - gap: gap ? `${gap}ch` : undefined, - paddingLeft: pl ? `${pl}ch` : undefined, - paddingRight: pr ? `${pr}ch` : undefined, - paddingTop: pt ? `${pt * 1.2}em` : undefined, - paddingBottom: pb ? `${pb * 1.2}em` : undefined, - marginLeft: ml ? `${ml}ch` : undefined, - marginRight: mr ? `${mr}ch` : undefined, - marginTop: mt ? `${mt * 1.2}em` : undefined, - marginBottom: mb ? `${mb * 1.2}em` : undefined, - width: width === '100%' ? '100%' : typeof width === 'number' ? `${width}ch` : width, - height: typeof height === 'number' ? `${height * 1.2}em` : height, - minWidth: typeof minWidth === 'number' ? `${minWidth}ch` : minWidth, - minHeight: typeof minHeight === 'number' ? `${minHeight * 1.2}em` : minHeight, - flexGrow, - flexShrink, - flexBasis, - border: borderStyle ? `1px solid ${borderColor || '#666'}` : undefined, - borderRadius: borderStyle === 'round' ? '4px' : undefined, - boxSizing: 'border-box', - overflowX, - overflowY, - }; - return
{children}
; -}; - -// Text component -export const Text = ({ children, color, bold, dimColor, underline, wrap, ...rest }: any) => { - const style: React.CSSProperties = { - color: color || 'inherit', - fontWeight: bold ? 'bold' : 'normal', - opacity: dimColor ? 0.5 : 1, - textDecoration: underline ? 'underline' : undefined, - fontFamily: 'monospace', - whiteSpace: wrap === 'truncate' ? 'nowrap' : 'pre-wrap', - overflow: wrap === 'truncate' ? 'hidden' : undefined, - textOverflow: wrap === 'truncate' ? 'ellipsis' : undefined, - }; - return {children}; -}; - -export const Newline = () =>
; - -// Transform component - transforms children text -export const Transform = ({ - children, - transform, -}: { - children?: React.ReactNode; - transform?: (text: string) => string; -}) => { - if (typeof children === 'string' && transform) { - return <>{transform(children)}; - } - return <>{children}; -}; - -// useInput hook - keyboard handling -export const useInput = (handler: (input: string, key: any) => void, options?: { isActive?: boolean }) => { - const isActive = options?.isActive ?? true; - - useEffect(() => { - if (!isActive) return; - - const listener = (e: KeyboardEvent) => { - if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Tab', ' '].includes(e.key)) { - e.preventDefault(); - } - - const key = { - return: e.key === 'Enter', - escape: e.key === 'Escape', - upArrow: e.key === 'ArrowUp', - downArrow: e.key === 'ArrowDown', - leftArrow: e.key === 'ArrowLeft', - rightArrow: e.key === 'ArrowRight', - backspace: e.key === 'Backspace', - delete: e.key === 'Delete', - tab: e.key === 'Tab', - ctrl: e.ctrlKey, - meta: e.metaKey, - }; - - const input = e.key.length === 1 ? e.key : ''; - handler(input, key); - }; - - window.addEventListener('keydown', listener); - return () => window.removeEventListener('keydown', listener); - }, [handler, isActive]); -}; - -// useApp hook -export const useApp = () => ({ - exit: () => console.log('[Browser] App exit called'), -}); - -// useStdout hook - reads from TerminalContext -export const useStdout = () => { - const { columns, rows } = useContext(TerminalContext); - return { - stdout: { - columns, - rows, - on: () => {}, // Resize event listener (no-op in browser) - off: () => {}, - }, - write: (str: string) => console.log('[stdout]', str), - }; -}; - -// render function (no-op, we use ReactDOM) -export const render = () => ({ - clear: () => {}, - unmount: () => {}, - waitUntilExit: () => Promise.resolve(), -}); diff --git a/web-harness/ink-spinner-shim.tsx b/web-harness/ink-spinner-shim.tsx deleted file mode 100644 index 685ea314..00000000 --- a/web-harness/ink-spinner-shim.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -const DOTS = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; - -export default function Spinner({ type = 'dots' }: { type?: string }) { - const [frame, setFrame] = useState(0); - - useEffect(() => { - const timer = setInterval(() => { - setFrame(f => (f + 1) % DOTS.length); - }, 80); - return () => clearInterval(timer); - }, []); - - return {DOTS[frame]}; -} diff --git a/web-harness/lib-mocks.ts b/web-harness/lib-mocks.ts deleted file mode 100644 index 22a40e18..00000000 --- a/web-harness/lib-mocks.ts +++ /dev/null @@ -1,245 +0,0 @@ -// Mock @agentcore/lib - only the parts that depend on Node.js -// The schema package is NOT mocked - it's pure TypeScript/Zod -// Configuration is centralized in harness-env.ts -import { MOCK_AGENTCORE_DIR, MOCK_SCENARIO } from './harness-env'; -import * as mockFs from './mock-fs-client'; - -// Define mock paths (must match mock-fs-server.ts and mock-fs-client.ts) -const MOCK_WORKSPACE = '/mock/workspace/agentcore'; -const MOCK_CLI_DIR = `${MOCK_WORKSPACE}/.cli`; - -// Virtual paths to schema files -const VIRTUAL_PATHS = { - agentcore: `${MOCK_WORKSPACE}/agentcore.json`, - awsTargets: `${MOCK_WORKSPACE}/aws-targets.json`, - mcp: `${MOCK_WORKSPACE}/mcp.json`, - mcpDefs: `${MOCK_WORKSPACE}/mcp-defs.json`, - deployedState: `${MOCK_CLI_DIR}/deployed-state.json`, -}; - -// Constants -export const CONFIG_DIR = 'agentcore'; -export const CLI_SYSTEM_DIR = '.cli'; -export const CLI_LOGS_DIR = '.cli/logs'; -export const CONFIG_FILES = {}; -export const UV_INSTALL_HINT = 'Install uv'; -export const DEFAULT_PYTHON_PLATFORM = 'linux'; -export const APP_DIR = 'app'; -export const MCP_APP_SUBDIR = 'mcp'; - -// Error class -export class NoProjectError extends Error { - constructor(message?: string) { - super(message || 'No project found'); - this.name = 'NoProjectError'; - } -} - -// Utility functions that use Node.js -export const isWindows = false; -export const findConfigRoot = () => MOCK_WORKSPACE; -export const findProjectRoot = () => '/mock/workspace'; -export const getWorkingDirectory = () => '/mock/workspace'; -export const requireConfigRoot = () => MOCK_WORKSPACE; -export const runSubprocess = async () => ({ stdout: '', stderr: '', code: 0 }); - -// Environment file utilities -export const readEnvFile = async (_path: string) => ({}); -export const setEnvVar = async (_path: string, _key: string, _value: string) => {}; - -// SecureCredentials class mock -export class SecureCredentials { - private creds: Record = {}; - - constructor(_agentName?: string) {} - - async get(key: string): Promise { - return this.creds[key]; - } - - async set(key: string, value: string): Promise { - this.creds[key] = value; - } - - async delete(key: string): Promise { - delete this.creds[key]; - } - - async list(): Promise { - return Object.keys(this.creds); - } -} - -// Mock subprocess capture - returns appropriate version info based on command -export const runSubprocessCapture = async (cmd: string, args?: string[]) => { - const fullCmd = args ? `${cmd} ${args.join(' ')}` : cmd; - // Node version check - if (fullCmd.includes('node') && fullCmd.includes('--version')) { - return { stdout: 'v20.0.0\n', stderr: '', code: 0 }; - } - // UV version check - if (fullCmd.includes('uv') && fullCmd.includes('--version')) { - return { stdout: 'uv 0.9.2\n', stderr: '', code: 0 }; - } - // NPM version check - if (fullCmd.includes('npm') && fullCmd.includes('--version')) { - return { stdout: '10.0.0\n', stderr: '', code: 0 }; - } - // CDK version check - if (fullCmd.includes('cdk') && fullCmd.includes('--version')) { - return { stdout: '2.150.0\n', stderr: '', code: 0 }; - } - return { stdout: '', stderr: '', code: 0 }; -}; - -export const runSubprocessCaptureSync = (cmd: string, args?: string[]) => { - const fullCmd = args ? `${cmd} ${args.join(' ')}` : cmd; - // Node version check - if (fullCmd.includes('node') && fullCmd.includes('--version')) { - return { stdout: 'v20.0.0\n', stderr: '', code: 0 }; - } - // UV version check - if (fullCmd.includes('uv') && fullCmd.includes('--version')) { - return { stdout: 'uv 0.9.2\n', stderr: '', code: 0 }; - } - // NPM version check - if (fullCmd.includes('npm') && fullCmd.includes('--version')) { - return { stdout: '10.0.0\n', stderr: '', code: 0 }; - } - // CDK version check - if (fullCmd.includes('cdk') && fullCmd.includes('--version')) { - return { stdout: '2.150.0\n', stderr: '', code: 0 }; - } - return { stdout: '', stderr: '', code: 0 }; -}; -export const checkSubprocess = async () => true; -export const packRuntime = async () => '/mock/artifact.zip'; -export const resolveCodeLocation = () => '/mock/code'; -export const validateAgentExists = () => true; -export const getArtifactZipName = () => 'artifact.zip'; -export const setSessionProjectRoot = () => {}; -export const getSessionProjectRoot = () => '/mock/workspace'; - -// Mock PathResolver class - mirrors all methods from agentcore-lib -export class PathResolver { - private baseDir = MOCK_WORKSPACE; - - getBaseDir() { - return this.baseDir; - } - getProjectRoot() { - return '/mock/workspace'; - } - getAgentConfigPath() { - return VIRTUAL_PATHS.agentcore; - } - getAWSTargetsConfigPath() { - return VIRTUAL_PATHS.awsTargets; - } - getCliSystemDir() { - return MOCK_CLI_DIR; - } - getLogsDir() { - return `${MOCK_CLI_DIR}/logs`; - } - getStatePath() { - return VIRTUAL_PATHS.deployedState; - } - getMcpConfigPath() { - return VIRTUAL_PATHS.mcp; - } - getMcpDefsPath() { - return VIRTUAL_PATHS.mcpDefs; - } - setBaseDir(baseDir: string) { - this.baseDir = baseDir; - } -} - -// Helper to read and parse JSON from mock filesystem -async function readJsonFile(virtualPath: string): Promise { - await mockFs.waitForInit(); - const content = mockFs.readFileSync(virtualPath); - return JSON.parse(content) as T; -} - -// Helper to write JSON to mock filesystem -async function writeJsonFile(virtualPath: string, data: unknown): Promise { - await mockFs.waitForInit(); - const content = JSON.stringify(data, null, 2); - await mockFs.writeFile(virtualPath, content); -} - -// Mock ConfigIO class (uses fs operations) -// Now reads/writes to the writable mock filesystem -export class ConfigIO { - private pathResolver = new PathResolver(); - - constructor(_opts?: any) {} - - configExists(configName: string): boolean { - // Return true for configs that have mock data - const existingConfigs = ['project', 'awsTargets', 'state', 'mcp', 'mcpDefs']; - return existingConfigs.includes(configName); - } - - getPathResolver(): PathResolver { - return this.pathResolver; - } - - getProjectRoot(): string { - return this.pathResolver.getProjectRoot(); - } - - getConfigRoot(): string { - return this.pathResolver.getBaseDir(); - } - - async readProjectSpec() { - return readJsonFile(VIRTUAL_PATHS.agentcore); - } - - async writeProjectSpec(data: unknown) { - await writeJsonFile(VIRTUAL_PATHS.agentcore, data); - } - - async readAWSDeploymentTargets() { - return readJsonFile(VIRTUAL_PATHS.awsTargets); - } - - async writeAWSDeploymentTargets(data: unknown) { - await writeJsonFile(VIRTUAL_PATHS.awsTargets, data); - } - - async readDeployedState() { - return readJsonFile(VIRTUAL_PATHS.deployedState); - } - - async writeDeployedState(data: unknown) { - await writeJsonFile(VIRTUAL_PATHS.deployedState, data); - } - - async readMcpSpec() { - return readJsonFile(VIRTUAL_PATHS.mcp); - } - - async writeMcpSpec(data: unknown) { - await writeJsonFile(VIRTUAL_PATHS.mcp, data); - } - - async readMcpDefs() { - return readJsonFile(VIRTUAL_PATHS.mcpDefs); - } - - async writeMcpDefs(data: unknown) { - await writeJsonFile(VIRTUAL_PATHS.mcpDefs, data); - } - - async initializeBaseDir() {} - - baseDirExists(): boolean { - return true; - } - - setBaseDir(_baseDir: string): void {} -} diff --git a/web-harness/mock-fs-client.ts b/web-harness/mock-fs-client.ts deleted file mode 100644 index c8008528..00000000 --- a/web-harness/mock-fs-client.ts +++ /dev/null @@ -1,248 +0,0 @@ -/** - * Mock Filesystem Client - * - * Browser-side mock filesystem that: - * - Loads initial state from the server on startup - * - Provides sync read/write operations (from in-memory cache) - * - Persists writes to the server (async, fire-and-forget) - * - * This allows the TUI to work with synchronous fs operations - * while changes are persisted to the dev server. - */ -import { MOCK_SCENARIO } from './harness-env'; - -// Types -export interface MockFile { - content: string; - lastModified: number; -} - -export interface MockFileStore { - [path: string]: MockFile; -} - -// In-memory file store (populated from server on init) -let fileStore: MockFileStore = {}; -let directories: Set = new Set(); -let initialized = false; -let initPromise: Promise | null = null; - -// Log flag -const LOG_OPERATIONS = false; - -function log(...args: unknown[]) { - if (LOG_OPERATIONS) { - console.log('[mock-fs-client]', ...args); - } -} - -/** - * Initialize the mock filesystem from the server. - * Call this early in the app lifecycle. - */ -export async function initializeMockFs(): Promise { - if (initialized) return; - if (initPromise) return initPromise; - - initPromise = (async () => { - try { - log('Initializing from server...'); - const response = await fetch('/__mock-fs-sync'); - if (!response.ok) { - throw new Error(`Failed to sync: ${response.status}`); - } - const data = await response.json(); - fileStore = data.files || {}; - directories = new Set(data.directories || []); - initialized = true; - log('Initialized with', Object.keys(fileStore).length, 'files'); - } catch (err) { - console.error('[mock-fs-client] Failed to initialize:', err); - // Initialize with empty state so app doesn't crash - fileStore = {}; - directories = new Set(); - initialized = true; - } - })(); - - return initPromise; -} - -/** - * Check if the mock filesystem is initialized. - */ -export function isInitialized(): boolean { - return initialized; -} - -/** - * Wait for initialization to complete. - */ -export async function waitForInit(): Promise { - if (initialized) return; - if (initPromise) return initPromise; - return initializeMockFs(); -} - -/** - * Check if a file exists (synchronous, from cache). - */ -export function existsSync(filePath: string): boolean { - if (!initialized) { - console.warn('[mock-fs-client] existsSync called before initialization'); - return false; - } - const exists = filePath in fileStore || directories.has(filePath); - log('existsSync', filePath, '->', exists); - return exists; -} - -/** - * Check if path is a directory. - */ -export function isDirectory(filePath: string): boolean { - return directories.has(filePath); -} - -/** - * Read file content (synchronous, from cache). - */ -export function readFileSync(filePath: string): string { - if (!initialized) { - console.warn('[mock-fs-client] readFileSync called before initialization'); - return '{}'; - } - const file = fileStore[filePath]; - if (!file) { - log('readFileSync', filePath, '-> NOT FOUND'); - return '{}'; - } - log('readFileSync', filePath, '->', file.content.length, 'bytes'); - return file.content; -} - -/** - * Write file content (synchronous write to cache, async persist to server). - */ -export function writeFileSync(filePath: string, content: string): void { - log('writeFileSync', filePath, content.length, 'bytes'); - - // Update local cache immediately - fileStore[filePath] = { - content, - lastModified: Date.now(), - }; - - // Persist to server asynchronously - fetch(`/__mock-fs${filePath}`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content }), - }).catch(err => { - console.error('[mock-fs-client] Failed to persist write:', err); - }); -} - -/** - * Async read file (returns Promise). - */ -export async function readFile(filePath: string): Promise { - await waitForInit(); - return readFileSync(filePath); -} - -/** - * Async write file (returns Promise when persisted to server). - */ -export async function writeFile(filePath: string, content: string): Promise { - await waitForInit(); - - // Update local cache - fileStore[filePath] = { - content, - lastModified: Date.now(), - }; - - // Persist to server - const response = await fetch(`/__mock-fs${filePath}`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content }), - }); - - if (!response.ok) { - throw new Error(`Failed to write file: ${response.status}`); - } -} - -/** - * Delete a file. - */ -export async function deleteFile(filePath: string): Promise { - await waitForInit(); - - delete fileStore[filePath]; - - const response = await fetch(`/__mock-fs${filePath}`, { - method: 'DELETE', - }); - - if (!response.ok && response.status !== 404) { - throw new Error(`Failed to delete file: ${response.status}`); - } -} - -/** - * List files in a directory. - */ -export function readdirSync(dirPath: string): string[] { - if (!initialized) { - console.warn('[mock-fs-client] readdirSync called before initialization'); - return []; - } - - const prefix = dirPath.endsWith('/') ? dirPath : dirPath + '/'; - const files = Object.keys(fileStore) - .filter(p => p.startsWith(prefix)) - .map(p => { - const rest = p.slice(prefix.length); - const firstSlash = rest.indexOf('/'); - return firstSlash === -1 ? rest : rest.slice(0, firstSlash); - }) - .filter((v, i, a) => a.indexOf(v) === i); // unique - - log('readdirSync', dirPath, '->', files); - return files; -} - -/** - * Reset the filesystem to initial state. - */ -export async function resetMockFs(): Promise { - const response = await fetch('/__mock-fs-reset', { method: 'POST' }); - if (!response.ok) { - throw new Error(`Failed to reset: ${response.status}`); - } - - // Re-sync from server - initialized = false; - initPromise = null; - await initializeMockFs(); -} - -/** - * Get the current file store (for debugging). - */ -export function getFileStore(): Readonly { - return fileStore; -} - -/** - * Get current scenario. - */ -export function getCurrentScenario(): string { - return MOCK_SCENARIO; -} - -// Auto-initialize when module loads (will be ready by the time React renders) -initializeMockFs(); diff --git a/web-harness/mock-fs-server.ts b/web-harness/mock-fs-server.ts deleted file mode 100644 index dd2c623b..00000000 --- a/web-harness/mock-fs-server.ts +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Mock Filesystem Server Plugin for Vite - * - * Provides a server-side file store that: - * - Initializes with mock JSON data on dev server start - * - Exposes REST API endpoints for reading/writing files - * - Persists changes in memory during the dev session - * - Resets to fresh mock data on server restart - */ -import fs from 'node:fs'; -import path from 'node:path'; -import type { Plugin, ViteDevServer } from 'vite'; - -// Types for mock filesystem -export interface MockFile { - content: string; - lastModified: number; -} - -export interface MockFileStore { - [path: string]: MockFile; -} - -// Define mock file paths -const MOCK_WORKSPACE = '/mock/workspace/agentcore'; -const MOCK_CLI_DIR = `${MOCK_WORKSPACE}/.cli`; - -// Map of virtual paths to their mock JSON source files -const MOCK_FILE_MAPPING: Record = { - [`${MOCK_WORKSPACE}/agentcore.json`]: 'agentcore.json', - [`${MOCK_WORKSPACE}/aws-targets.json`]: 'aws-targets.json', - [`${MOCK_WORKSPACE}/mcp.json`]: 'mcp.json', - [`${MOCK_WORKSPACE}/mcp-defs.json`]: 'mcp-defs.json', - [`${MOCK_CLI_DIR}/deployed-state.json`]: 'deployed-state.json', -}; - -// Known mock directories -const MOCK_DIRECTORIES = new Set([ - '/mock', - '/mock/workspace', - MOCK_WORKSPACE, - MOCK_CLI_DIR, - `${MOCK_CLI_DIR}/logs`, - `${MOCK_WORKSPACE}/cdk`, -]); - -export function createMockFsPlugin(scenario: 'demo-workspace' | 'empty-workspace' = 'demo-workspace'): Plugin { - // In-memory file store - const fileStore: MockFileStore = {}; - const mocksDir = path.resolve(__dirname, `./mocks/${scenario}`); - - // Initialize file store from mock JSON files - function initializeFileStore() { - console.log(`[mock-fs] Initializing file store from scenario: ${scenario}`); - - for (const [virtualPath, fileName] of Object.entries(MOCK_FILE_MAPPING)) { - const sourcePath = path.join(mocksDir, fileName); - try { - const content = fs.readFileSync(sourcePath, 'utf-8'); - fileStore[virtualPath] = { - content, - lastModified: Date.now(), - }; - console.log(`[mock-fs] Loaded: ${virtualPath}`); - } catch (err) { - console.warn(`[mock-fs] Failed to load ${sourcePath}:`, err); - // Initialize with empty object for missing files - fileStore[virtualPath] = { - content: '{}', - lastModified: Date.now(), - }; - } - } - } - - return { - name: 'mock-fs-server', - - configureServer(server: ViteDevServer) { - // Initialize file store on server start - initializeFileStore(); - - // Endpoint to get all files at once (for initial sync) - // MUST be registered BEFORE the generic /__mock-fs handler - server.middlewares.use((req, res, next) => { - if (req.url === '/__mock-fs-sync' && req.method === 'GET') { - res.setHeader('Content-Type', 'application/json'); - res.end( - JSON.stringify({ - files: fileStore, - directories: Array.from(MOCK_DIRECTORIES), - }) - ); - return; - } - next(); - }); - - // Endpoint to reset to initial state - // MUST be registered BEFORE the generic /__mock-fs handler - server.middlewares.use((req, res, next) => { - if (req.url === '/__mock-fs-reset' && req.method === 'POST') { - initializeFileStore(); - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ success: true, message: 'File store reset to initial state' })); - return; - } - next(); - }); - - // Add middleware for mock filesystem API (generic file operations) - server.middlewares.use((req, res, next) => { - // Only handle our mock-fs API endpoints - if (!req.url?.startsWith('/__mock-fs/')) { - return next(); - } - - const urlPath = req.url.replace('/__mock-fs', '') || '/'; - - // GET - Read file or list directory - if (req.method === 'GET') { - // Check if it's a directory - if (MOCK_DIRECTORIES.has(urlPath)) { - // List files in directory - const files = Object.keys(fileStore) - .filter(p => p.startsWith(urlPath + '/') && !p.slice(urlPath.length + 1).includes('/')) - .map(p => p.split('/').pop()); - - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ type: 'directory', files })); - return; - } - - // Read file - const file = fileStore[urlPath]; - if (file) { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ type: 'file', content: file.content, lastModified: file.lastModified })); - } else { - res.statusCode = 404; - res.end(JSON.stringify({ error: 'File not found', path: urlPath })); - } - return; - } - - // POST - Write file - if (req.method === 'POST') { - let body = ''; - req.on('data', chunk => { - body += chunk.toString(); - }); - req.on('end', () => { - try { - const { content } = JSON.parse(body); - fileStore[urlPath] = { - content: typeof content === 'string' ? content : JSON.stringify(content, null, 2), - lastModified: Date.now(), - }; - console.log(`[mock-fs] Written: ${urlPath} (${fileStore[urlPath].content.length} bytes)`); - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ success: true, path: urlPath })); - } catch (err) { - res.statusCode = 400; - res.end(JSON.stringify({ error: 'Invalid request body' })); - } - }); - return; - } - - // DELETE - Remove file - if (req.method === 'DELETE') { - if (fileStore[urlPath]) { - delete fileStore[urlPath]; - console.log(`[mock-fs] Deleted: ${urlPath}`); - res.end(JSON.stringify({ success: true })); - } else { - res.statusCode = 404; - res.end(JSON.stringify({ error: 'File not found' })); - } - return; - } - - // HEAD - Check if file exists - if (req.method === 'HEAD') { - if (fileStore[urlPath] || MOCK_DIRECTORIES.has(urlPath)) { - res.statusCode = 200; - } else { - res.statusCode = 404; - } - res.end(); - return; - } - - next(); - }); - }, - }; -} - -export default createMockFsPlugin; diff --git a/web-harness/mocks/demo-workspace/agentcore.json b/web-harness/mocks/demo-workspace/agentcore.json deleted file mode 100644 index ba6d1e27..00000000 --- a/web-harness/mocks/demo-workspace/agentcore.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "name": "DemoWorkspace", - "version": "0.1", - "description": "Demo AgentCore workspace for browser testing", - "agents": [ - { - "name": "ResearchAssistant", - "id": "research-assistant-001", - "sdkFramework": "Strands", - "targetLanguage": "python", - "modelProvider": "Bedrock", - "runtime": { - "artifact": "CodeZip", - "name": "ResearchAssistantRuntime", - "pythonVersion": "PYTHON_3_12", - "entrypoint": "main.py:agent", - "codeLocation": "./agents/research" - }, - "mcpProviders": [ - { - "type": "AgentCoreGateway", - "name": "MainTools", - "description": "Primary tool gateway", - "gatewayName": "main-gateway" - } - ], - "memoryProviders": [ - { - "type": "AgentCoreMemory", - "relation": "own", - "name": "SharedMemory", - "description": "Shared memory", - "config": { - "eventExpiryDuration": 30, - "memoryStrategies": [{ "type": "SEMANTIC", "name": "semantic_memory" }] - } - } - ], - "identityProviders": [], - "remoteTools": [] - }, - { - "name": "CodeReviewer", - "id": "code-reviewer-001", - "sdkFramework": "Strands", - "targetLanguage": "Typescript", - "modelProvider": "Bedrock", - "runtime": { - "artifact": "CodeZip", - "name": "CodeReviewerRuntime", - "pythonVersion": "PYTHON_3_12", - "entrypoint": "main.py:agent", - "codeLocation": "./agents/reviewer" - }, - "mcpProviders": [ - { - "type": "AgentCoreGateway", - "name": "MainTools", - "description": "Primary tool gateway", - "gatewayName": "main-gateway" - } - ], - "memoryProviders": [ - { - "type": "AgentCoreMemory", - "relation": "own", - "name": "SharedMemory", - "description": "Shared memory", - "config": { - "eventExpiryDuration": 30, - "memoryStrategies": [{ "type": "SEMANTIC", "name": "semantic_memory" }] - } - } - ], - "identityProviders": [], - "remoteTools": [] - } - ] -} diff --git a/web-harness/mocks/demo-workspace/aws-targets.json b/web-harness/mocks/demo-workspace/aws-targets.json deleted file mode 100644 index 87fa2da6..00000000 --- a/web-harness/mocks/demo-workspace/aws-targets.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "development", - "account": "123456789012", - "region": "us-west-2", - "stage": "dev" - }, - { - "name": "production", - "account": "123456789012", - "region": "us-east-1", - "stage": "prod" - } -] diff --git a/web-harness/mocks/demo-workspace/deployed-state.json b/web-harness/mocks/demo-workspace/deployed-state.json deleted file mode 100644 index 0888e097..00000000 --- a/web-harness/mocks/demo-workspace/deployed-state.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "targets": { - "development": { - "stackName": "AgentCore-DemoWorkspace-dev", - "stackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/AgentCore-DemoWorkspace-dev/abc123", - "lastDeployedAt": "2024-01-15T10:30:00Z", - "outputs": { - "ResearchAssistantRuntimeArn": "arn:aws:agentcore:us-west-2:123456789012:runtime/research-assistant", - "CodeReviewerRuntimeArn": "arn:aws:agentcore:us-west-2:123456789012:runtime/code-reviewer" - } - } - } -} diff --git a/web-harness/mocks/demo-workspace/mcp-defs.json b/web-harness/mocks/demo-workspace/mcp-defs.json deleted file mode 100644 index c0215003..00000000 --- a/web-harness/mocks/demo-workspace/mcp-defs.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "tools": { - "web-search": { - "name": "web-search", - "description": "Search the web for information", - "inputSchema": { - "type": "object", - "properties": { - "query": { "type": "string" } - } - } - }, - "code-analyzer": { - "name": "code-analyzer", - "description": "Analyze code for patterns and issues", - "inputSchema": { - "type": "object", - "properties": { - "code": { "type": "string" }, - "language": { "type": "string" } - } - } - } - } -} diff --git a/web-harness/mocks/demo-workspace/mcp.json b/web-harness/mocks/demo-workspace/mcp.json deleted file mode 100644 index eeca73a9..00000000 --- a/web-harness/mocks/demo-workspace/mcp.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "agentCoreGateways": [ - { - "name": "main-gateway", - "description": "Primary gateway for agent tools", - "targets": [ - { - "targetType": "lambda", - "toolDefinition": { - "name": "web-search", - "description": "Search the web for information", - "inputSchema": { "type": "object", "properties": { "query": { "type": "string" } } } - }, - "compute": { - "host": "Lambda", - "implementation": { - "path": "./tools/web-search", - "language": "python", - "handler": "handler.search" - }, - "pythonVersion": "PYTHON_3_12" - } - }, - { - "targetType": "lambda", - "toolDefinition": { - "name": "file-reader", - "description": "Read files from S3", - "inputSchema": { - "type": "object", - "properties": { "bucket": { "type": "string" }, "key": { "type": "string" } } - } - }, - "compute": { - "host": "Lambda", - "implementation": { - "path": "./tools/file-reader", - "language": "python", - "handler": "handler.read" - }, - "pythonVersion": "PYTHON_3_12" - } - } - ] - }, - { - "name": "internal-gateway", - "targets": [] - } - ], - "standaloneRuntimeTools": [ - { - "name": "code-executor", - "toolDefinition": { - "name": "execute-code", - "description": "Execute code in a sandbox", - "inputSchema": { - "type": "object", - "properties": { "code": { "type": "string" }, "language": { "type": "string" } } - } - }, - "compute": { - "host": "AgentCoreRuntime", - "implementation": { - "path": "./tools/code-executor", - "language": "python", - "handler": "handler.execute" - } - } - } - ] -} diff --git a/web-harness/mocks/empty-workspace/agentcore.json b/web-harness/mocks/empty-workspace/agentcore.json deleted file mode 100644 index af22878d..00000000 --- a/web-harness/mocks/empty-workspace/agentcore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "EmptyWorkspace", - "version": "0.1", - "description": "Empty workspace for testing initial state", - "agents": [] -} diff --git a/web-harness/mocks/empty-workspace/aws-targets.json b/web-harness/mocks/empty-workspace/aws-targets.json deleted file mode 100644 index fe51488c..00000000 --- a/web-harness/mocks/empty-workspace/aws-targets.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/web-harness/mocks/empty-workspace/deployed-state.json b/web-harness/mocks/empty-workspace/deployed-state.json deleted file mode 100644 index bf7bb6fa..00000000 --- a/web-harness/mocks/empty-workspace/deployed-state.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "targets": {} -} diff --git a/web-harness/mocks/empty-workspace/mcp-defs.json b/web-harness/mocks/empty-workspace/mcp-defs.json deleted file mode 100644 index 2f8e00f8..00000000 --- a/web-harness/mocks/empty-workspace/mcp-defs.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "tools": {} -} diff --git a/web-harness/mocks/empty-workspace/mcp.json b/web-harness/mocks/empty-workspace/mcp.json deleted file mode 100644 index 617139bc..00000000 --- a/web-harness/mocks/empty-workspace/mcp.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "agentCoreGateways": [] -} diff --git a/web-harness/nl-edit-mock.ts b/web-harness/nl-edit-mock.ts deleted file mode 100644 index 0c703dcf..00000000 --- a/web-harness/nl-edit-mock.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Mock for the nl-edit operations module. - * The real module uses Bun-specific `import ... with { type: 'text' }` syntax - * which is not supported by Vite/esbuild. - */ - -// Re-export types without importing from the schema package -export interface SchemaState { - workspace: unknown | null; - mcp: unknown | null; - mcpDefs: unknown | null; -} - -export interface OutOfDomainResponse { - status: 'OUT_OF_DOMAIN'; - reason: string; -} - -export interface AmbiguousInputResponse { - status: 'AMBIGUOUS_INPUT'; - reason: string; -} - -export interface SuccessResponse { - status: 'SUCCESS'; - diff_message: string; - changes: { - 'agentcore.json'?: unknown; - 'mcp.json'?: unknown; - 'mcp-defs.json'?: unknown; - }; -} - -export interface ResponseValidationIssue { - path: string; - message: string; -} - -export interface ResponseValidationError { - file: string; - issues: ResponseValidationIssue[]; -} - -export type NlEditResponse = OutOfDomainResponse | AmbiguousInputResponse | SuccessResponse; - -export interface NlEditResult { - success: boolean; - response?: NlEditResponse; - previewPaths?: Record; - error?: string; - validationError?: ResponseValidationError; -} - -export interface ValidationResult { - success: boolean; - response?: NlEditResponse; - error?: string; - validationError?: ResponseValidationError; -} - -// Mock functions -export async function executeNlEdit(_userInput: string, _cwd: string): Promise { - console.log('[nl-edit-mock] executeNlEdit called'); - return { - success: false, - error: 'NL Edit is not available in browser harness', - }; -} - -export async function applyNlEditChanges(_cwd: string, _response: SuccessResponse): Promise { - console.log('[nl-edit-mock] applyNlEditChanges called'); - throw new Error('NL Edit is not available in browser harness'); -} - -export async function buildPrompt( - _userInput: string, - _currentSchemas: SchemaState, - _fileTreeContext: string -): Promise { - console.log('[nl-edit-mock] buildPrompt called'); - return 'Mock prompt - NL Edit not available in browser'; -} - -export function parseAndValidateResponse(_rawContent: string): ValidationResult { - console.log('[nl-edit-mock] parseAndValidateResponse called'); - return { - success: false, - error: 'NL Edit is not available in browser harness', - }; -} diff --git a/web-harness/node-mocks.ts b/web-harness/node-mocks.ts deleted file mode 100644 index b02ce5ad..00000000 --- a/web-harness/node-mocks.ts +++ /dev/null @@ -1,445 +0,0 @@ -// Comprehensive mock for Node.js modules in browser -// ============= Mock Filesystem Integration ============= -// Uses the mock-fs-client for writable file operations that persist during dev session -import { HARNESS_CONFIG, MOCK_SCENARIO, type MockScenario } from './harness-env'; -import * as mockFs from './mock-fs-client'; - -// Re-export types and scenario getter for convenience -export type { MockScenario }; -export function getMockScenario(): MockScenario { - return MOCK_SCENARIO; -} - -// Define mock paths -const MOCK_WORKSPACE = '/mock/workspace/agentcore'; -const MOCK_CLI_DIR = `${MOCK_WORKSPACE}/.cli`; - -// Map of file names to their virtual paths -const FILE_NAME_TO_PATH: Record = { - 'agentcore.json': `${MOCK_WORKSPACE}/agentcore.json`, - 'aws-targets.json': `${MOCK_WORKSPACE}/aws-targets.json`, - 'mcp.json': `${MOCK_WORKSPACE}/mcp.json`, - 'mcp-defs.json': `${MOCK_WORKSPACE}/mcp-defs.json`, - 'deployed-state.json': `${MOCK_CLI_DIR}/deployed-state.json`, -}; - -// Known mock directories -const MOCK_DIRS = ['agentcore', '.cli', '.cli/logs', 'cdk']; - -// ============= fs module ============= - -// Helper to resolve file path to virtual path -function resolveToVirtualPath(filePath: string): string | null { - const normalizedPath = String(filePath); - const fileName = normalizedPath.split('/').pop() || ''; - - // Check if this is a known mock file by name - if (FILE_NAME_TO_PATH[fileName]) { - return FILE_NAME_TO_PATH[fileName]; - } - - // Check if the path is already a virtual path - if (normalizedPath.startsWith('/mock/')) { - return normalizedPath; - } - - return null; -} - -// Helper to return mock content based on file path -function getMockFileContent(filePath: string): string { - const virtualPath = resolveToVirtualPath(filePath); - - if (virtualPath) { - return mockFs.readFileSync(virtualPath); - } - - // Special case for package.json - if (filePath.endsWith('package.json')) { - return JSON.stringify({ name: 'mock-package', version: '1.0.0', dependencies: {} }); - } - - // Default for unknown JSON files - if (filePath.endsWith('.json')) { - return '{}'; - } - - return ''; -} - -export const existsSync = (path: string): boolean => { - const virtualPath = resolveToVirtualPath(path); - - // Check virtual file system - if (virtualPath && mockFs.existsSync(virtualPath)) { - return true; - } - - // Check if it's a package.json (needed for CDK project validation) - const fileName = String(path).split('/').pop() || ''; - if (fileName === 'package.json') return true; - - // Check if it's a known mock directory - const normalizedPath = String(path); - for (const dir of MOCK_DIRS) { - if (normalizedPath.endsWith(dir) || normalizedPath.endsWith(`/${dir}`)) { - return true; - } - } - - return false; -}; - -export const readdirSync = (path: string): string[] => { - const virtualPath = resolveToVirtualPath(path); - if (virtualPath) { - return mockFs.readdirSync(virtualPath); - } - return []; -}; - -export const statSync = (path: string) => { - const isDir = mockFs.isDirectory(path); - return { - isDirectory: () => isDir, - isFile: () => !isDir && mockFs.existsSync(path), - }; -}; - -export const readFileSync = (filePath: string): string => getMockFileContent(String(filePath)); - -export const writeFileSync = (filePath: string, content: string | object): void => { - const virtualPath = resolveToVirtualPath(filePath); - if (virtualPath) { - const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2); - mockFs.writeFileSync(virtualPath, contentStr); - } -}; - -export const mkdirSync = () => {}; -export const unlinkSync = () => {}; -export const copyFileSync = () => {}; -export const rmSync = () => {}; -export const appendFileSync = () => {}; -export const createReadStream = () => ({ pipe: () => {}, on: () => {} }); -export const createWriteStream = () => ({ write: () => {}, end: () => {}, on: () => {} }); - -export const promises = { - readFile: async (filePath: string): Promise => { - const virtualPath = resolveToVirtualPath(filePath); - if (virtualPath) { - return mockFs.readFile(virtualPath); - } - return getMockFileContent(String(filePath)); - }, - writeFile: async (filePath: string, content: string | object): Promise => { - const virtualPath = resolveToVirtualPath(filePath); - if (virtualPath) { - const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2); - await mockFs.writeFile(virtualPath, contentStr); - } - }, - mkdir: async () => {}, - readdir: async (path: string) => readdirSync(path), - stat: async (path: string) => statSync(path), - unlink: async () => {}, - rm: async () => {}, - copyFile: async () => {}, - access: async () => {}, - rename: async () => {}, -}; - -// Also export async functions at top level for fs/promises imports -export const readFile = promises.readFile; -export const writeFile = promises.writeFile; -export const mkdir = promises.mkdir; -export const readdir = promises.readdir; -export const stat = promises.stat; -export const access = promises.access; -export const copyFile = promises.copyFile; -export const rm = promises.rm; -export const rename = promises.rename; - -// ============= path module ============= -export const join = (...parts: string[]) => parts.filter(Boolean).join('/'); -export const resolve = (...parts: string[]) => '/' + parts.filter(Boolean).join('/'); -export const dirname = (p: string) => p.split('/').slice(0, -1).join('/') || '/'; -export const basename = (p: string, ext?: string) => { - const base = p.split('/').pop() || ''; - return ext && base.endsWith(ext) ? base.slice(0, -ext.length) : base; -}; -export const extname = (p: string) => { - const base = p.split('/').pop() || ''; - const idx = base.lastIndexOf('.'); - return idx > 0 ? base.slice(idx) : ''; -}; -export const relative = (_from: string, to: string) => to; -export const isAbsolute = (p: string) => p.startsWith('/'); -export const normalize = (p: string) => p; -export const sep = '/'; -export const delimiter = ':'; -export const parse = (p: string) => ({ - root: '/', - dir: dirname(p), - base: basename(p), - ext: extname(p), - name: basename(p, extname(p)), -}); - -// ============= url module ============= -export const fileURLToPath = (url: string | URL) => { - const urlStr = typeof url === 'string' ? url : url.href; - return urlStr.replace('file://', ''); -}; -export const pathToFileURL = (p: string) => new URL(`file://${p}`); - -// ============= child_process module ============= -export const spawn = () => ({ - stdout: { on: () => {}, pipe: () => {} }, - stderr: { on: () => {}, pipe: () => {} }, - stdin: { write: () => {}, end: () => {} }, - on: (_event: string, cb: (code: number) => void) => { - if (_event === 'close') setTimeout(() => cb(0), 10); - }, - kill: () => {}, -}); -export const execSync = () => ''; -export const exec = (_cmd: string, _opts: unknown, cb?: (err: null, stdout: string, stderr: string) => void) => { - const callback = typeof _opts === 'function' ? _opts : cb; - if (callback) setTimeout(() => callback(null, '', ''), 10); -}; -export const spawnSync = () => ({ stdout: '', stderr: '', status: 0 }); -export const fork = spawn; -export const execFile = exec; -export const execFileSync = execSync; - -// ============= os module ============= -export const platform = () => 'browser'; -export const homedir = () => '/home/user'; -export const tmpdir = () => '/tmp'; -export const hostname = () => 'localhost'; -export const type = () => 'Browser'; -export const release = () => '1.0.0'; -export const cpus = () => [{ model: 'Browser', speed: 0 }]; -export const totalmem = () => 0; -export const freemem = () => 0; -export const EOL = '\n'; -export const arch = () => 'x64'; -export const userInfo = () => ({ username: 'user', homedir: '/home/user' }); - -// ============= crypto module ============= -export const randomBytes = (size: number) => new Uint8Array(size); -export const randomUUID = () => crypto.randomUUID(); -export const createHash = () => ({ - update: function () { - return this; - }, - digest: () => 'mockhash', -}); -export const createHmac = createHash; - -// ============= events module ============= -export class EventEmitter { - private listeners: Record = {}; - on(event: string, listener: Function) { - this.listeners[event] = this.listeners[event] || []; - this.listeners[event].push(listener); - return this; - } - emit(event: string, ...args: unknown[]) { - (this.listeners[event] || []).forEach(fn => fn(...args)); - return true; - } - removeListener(event: string, listener: Function) { - this.listeners[event] = (this.listeners[event] || []).filter(fn => fn !== listener); - return this; - } - off = this.removeListener; - once(event: string, listener: Function) { - const wrapped = (...args: unknown[]) => { - this.removeListener(event, wrapped); - listener(...args); - }; - return this.on(event, wrapped); - } - addListener = this.on; - removeAllListeners(event?: string) { - if (event) delete this.listeners[event]; - else this.listeners = {}; - return this; - } - listenerCount(event: string) { - return (this.listeners[event] || []).length; - } -} - -// ============= stream module ============= -export class Readable extends EventEmitter { - pipe() { - return this; - } - read() { - return null; - } -} -export class Writable extends EventEmitter { - write() { - return true; - } - end() {} -} -export class Transform extends EventEmitter { - pipe() { - return this; - } - write() { - return true; - } - end() {} -} -export class PassThrough extends Transform {} -export class Duplex extends EventEmitter { - pipe() { - return this; - } - write() { - return true; - } - end() {} - read() { - return null; - } -} - -// stream/promises exports -export const pipeline = async (..._args: unknown[]) => { - // Mock pipeline - just resolve immediately - return Promise.resolve(); -}; -export const finished = async (_stream: unknown) => { - return Promise.resolve(); -}; - -// ============= util module ============= -export const promisify = (fn: Function) => fn; -export const inspect = (obj: unknown) => JSON.stringify(obj); -export const format = (fmt: string, ...args: unknown[]) => { - let i = 0; - return fmt.replace(/%[sdjO]/g, () => String(args[i++])); -}; -export const deprecate = (fn: Function) => fn; -export const inherits = () => {}; -export const types = { - isPromise: (v: unknown) => v instanceof Promise, -}; - -// ============= net module ============= -export const createServer = () => ({ - listen: () => {}, - close: () => {}, - on: () => {}, - address: () => ({ port: 0 }), -}); -export const createConnection = () => ({ - on: () => {}, - write: () => {}, - end: () => {}, - destroy: () => {}, -}); -export const connect = createConnection; -export const Socket = class { - on() { - return this; - } - write() { - return true; - } - end() {} - destroy() {} -}; -export const Server = class { - listen() { - return this; - } - close() {} - on() { - return this; - } - address() { - return { port: 0 }; - } -}; - -// ============= http/https module ============= -export const request = () => ({ - on: () => {}, - write: () => {}, - end: () => {}, -}); -export const get = request; -export const Agent = class {}; -export const globalAgent = {}; - -// ============= tty module ============= -export const isatty = () => false; -export const ReadStream = class extends Readable {}; -export const WriteStream = class extends Writable {}; - -// ============= readline module ============= -export const createInterface = () => ({ - on: () => {}, - question: (_q: string, cb: (a: string) => void) => cb(''), - close: () => {}, - prompt: () => {}, -}); - -// ============= buffer module ============= -export const Buffer = { - from: (data: unknown) => new Uint8Array(typeof data === 'string' ? data.split('').map(c => c.charCodeAt(0)) : []), - alloc: (size: number) => new Uint8Array(size), - allocUnsafe: (size: number) => new Uint8Array(size), - isBuffer: () => false, - concat: (list: Uint8Array[]) => { - const totalLength = list.reduce((acc, arr) => acc + arr.length, 0); - const result = new Uint8Array(totalLength); - let offset = 0; - for (const arr of list) { - result.set(arr, offset); - offset += arr.length; - } - return result; - }, -}; - -// ============= assert module ============= -export const ok = () => {}; -export const strictEqual = () => {}; -export const deepStrictEqual = () => {}; -export const notStrictEqual = () => {}; -export const throws = () => {}; -export const doesNotThrow = () => {}; -export const rejects = async () => {}; -export const doesNotReject = async () => {}; - -// ============= zlib module ============= -export const gzip = (_data: unknown, cb: (err: null, result: Uint8Array) => void) => cb(null, new Uint8Array()); -export const gunzip = gzip; -export const deflate = gzip; -export const inflate = gzip; -export const createGzip = () => new Transform(); -export const createGunzip = () => new Transform(); - -// Default export for path (commonly used as `import path from 'path'`) -export default { - join, - resolve, - dirname, - basename, - extname, - relative, - isAbsolute, - normalize, - sep, - delimiter, - parse, -}; diff --git a/web-harness/package-lock.json b/web-harness/package-lock.json deleted file mode 100644 index b72c3eb4..00000000 --- a/web-harness/package-lock.json +++ /dev/null @@ -1,1768 +0,0 @@ -{ - "name": "agentcore-web-harness", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "agentcore-web-harness", - "dependencies": { - "react": "^19.2.3", - "react-dom": "^19.2.3", - "zod": "^4.2.1" - }, - "devDependencies": { - "@types/react": "^19.2.7", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^4.4.0", - "playwright": "^1.58.0", - "typescript": "^5.0.0", - "vite": "^6.0.0" - } - }, - "../packages/agentcore-schema": { - "name": "@agentcore/schema", - "version": "0.1.0", - "extraneous": true, - "dependencies": { - "zod": "^4.2.1" - }, - "devDependencies": { - "@eslint/js": "^9.39.2", - "@types/node": "^25.0.3", - "@typescript-eslint/eslint-plugin": "^8.50.0", - "@typescript-eslint/parser": "^8.50.0", - "eslint": "^9.39.2", - "eslint-config-prettier": "^10.1.8", - "typescript": "^5" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true - }, - "node_modules/@types/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", - "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", - "dev": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "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" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.12.tgz", - "integrity": "sha512-Mij6Lij93pTAIsSYy5cyBQ975Qh9uLEc5rwGTpomiZeXZL9yIS6uORJakb3ScHgfs0serMMfIbXzokPMuEiRyw==", - "dev": true, - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001762", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", - "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true - }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "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" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/playwright": { - "version": "1.58.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.0.tgz", - "integrity": "sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ==", - "dev": true, - "dependencies": { - "playwright-core": "1.58.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.58.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.0.tgz", - "integrity": "sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw==", - "dev": true, - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.3" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", - "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", - "fsevents": "~2.3.2" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", - "dev": true, - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/zod": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", - "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/web-harness/package.json b/web-harness/package.json deleted file mode 100644 index 145a5c3b..00000000 --- a/web-harness/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "agentcore-web-harness", - "private": true, - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "react": "^19.2.3", - "react-dom": "^19.2.3", - "zod": "^4.2.1" - }, - "devDependencies": { - "@types/react": "^19.2.7", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^4.4.0", - "playwright": "^1.58.0", - "typescript": "^5.0.0", - "vite": "^6.0.0" - } -} diff --git a/web-harness/schema-assets-mock.ts b/web-harness/schema-assets-mock.ts deleted file mode 100644 index f88c0456..00000000 --- a/web-harness/schema-assets-mock.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Mock for templates/schema-assets.ts - browser mock -// These are raw text imports that don't work in the browser - -/** - * LLM-compacted schema files for AI coding context. - * Each file is self-contained and maps to a JSON config file. - */ -export const LLM_CONTEXT_FILES: Record = { - 'README.md': '# LLM Context Files\n\nMock content for browser testing.', - 'agentcore.ts': 'export const AgentCoreSchema = {};', - 'aws-targets.ts': 'export const AwsTargetsSchema = {};', -}; diff --git a/web-harness/screenshot.png b/web-harness/screenshot.png deleted file mode 100644 index 7ab22b1ddc51f566c7391fcfc5559a7c4170b4ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40472 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

>A)thZ)c?`sOy><7sgl^dRs z;BocaEZC`&EZ#@Haz}{YEBztOjlADUt~3t2$CZ}PRhWJMC~`XS!-u}vv%iL2Cn`1> zYIVKk2*$gML;~j+(&h8%V-HU@B__mJOiT#Y)Kb&MJF$+xICXoMAo~!;(X+%3SH<7a z(@!60w|u>LP&kY;N6{3HGq7eTF1epnx%7;5Xp0Kk68N=%DE;pV&cYM5=-mi78 zht*@IwV?;yy;8|jp>-QJ_t0CW0u>R#d$VG1H8ai&n~3-4=r>*UxUpV3_EGF0=-EGd z1hWv4*4Ki9WYMEatx~&28otwT2)Fr_OfAuG^ltz~(rXf;M705>hf{c0e&4a2*XiFmMLvIryQWoK3KX z(Oy3b#CE`kI19i+$TZqeTnDou0bEoAu{~h8vlr>Pd6jz5)oplJ5}kB%BAt-6mYp^WT8myFCKk z22RJk7cr&TYVGR6IGcn~=a)<5aq6^ukAI8-jfZ(u_<)ItiBqRY+Qpv42+hSj#Hm;I zLx`~o7`^zr_1=HKq)Z_GZf(|01E)4#FyO~PeT8`^h;#GW4sL}iiOR^z(%d#_0Fyev zkUq~;#4G`$W*Z#Dtwum9y&o^+!oa|weo3v|3Zk^vXObB-fKdmisvaLGo&cqC4Cvst z?t#7GXD2i<*jlVqp;yb20EVbk@iXjdW)r;Zfc!zu2(%x-Z2NSJ@$r=a898e^(>DI& zM{Yo?0!s&7Gm{a{ef62vR#$>D`a$_77(_2`BWNJb!A%Apt8al zG2^c<7^Q-b>l!(=?SO|mY>R=B5nxrfA+bg$=P5^03kWKk1N0oGzO}rzZf7;~lUZ+i zlIi!43yN}bvB2~NIMR|EfnaPaW9vkhu~U2+STEh&i`}0uQPc9<{S?x%cq!_$4}mNR zvb4Xe*7z{U9~r$8{|jm>bu0cOa|K+;)Cf*+NQH?z_jZ_8WI5D-9GXUZv2KkKm!%!CH~lr`4Fmek~cC zlVyYK;Jm%z$E-*lg*Hue9)RGx%SyfbDy)4d&Qf?%yeSUPLSd{WRqFN0GJ90st10sE zdr;<_Cu4)ByW0_1a+;@HYyF9s;sya{Tii*mR?GlnqX>Y?jAlGGZL?BAQfO>-B=t|&c+u^q+zo+1qs z75W2xk{W_JlkTqPmhwZx#@lN9YTX{d_g}~r>W6?pxE5f0sUK6426o~tl>S2t2)u-q zj(LVvZl8}Gq8js+5B1^=@vJ)R4e`=eplqNCOQR=jcMke@TBjM5!ThN#+7+5 z42&=_nNd(JO#_>OoV40|t{{6sKT|`(R}ELF`57hv*;}rDsXn$^3JSC0TdLZMUdx26 z!M!e2PcPTH%&PT>f&s9ZC1C(+U5@`mp+rs%FqYZU8+!%M$`U7K_z3d)TMRkr(BQiSpF;(*cIu|z^wFO)td z(yT;eD=%zn-4y)}>gY(|dTuX$k-XM_{lYWRbRjXo9oo<5wnq_=zgQBV1@^Hs{p|@e z;!*8MEKIS4t(3#dHE{&${tS@BG>>UMkqA)cb%@7w0re^NYyd~2rrO0KZ_Tq~;H=s) zk`=yA?C=-q18n~-!HkI<%Lz}t_hJ%y6l3Jyf99c-fuI?jmV^f@cfR*Kul$pI#Zryq z1fp8D1^*TWBCgw6|C!Am$GP4#2gxT+8tKL>%j#$J?(%+y5sx$P;_LZ-Kqm%ffT!@( zy0T>`Q*q~#sJVpvgw8CZywbAanM`u)TR95Wu0{A5v{oB&)ZNq?bA|=3$h)r$j0(%e z&HSA5{i7?Y28u(L5LX@_QNHM9h@{p!IRRc zk=8DR7!q?9;pBUm{=o^E1BP zOq9A~<5X2`nzYTHFOQ60Tj0q@qZ*CeMt)wZY4r)}B_Y#8jA`}7jZ4j@D6uVK;aR(v z{5%EpSxequ9P@BC6#fg}ceI~h+6Mr?`cI93!z+nkENd4%XR_+%WYk|_AYtEAzswTH zrIbKJT7}FjwdreLx?n5s#P0%+`*BR>BKlg=k5>%PQQ936{;G{wMXHg2Q~M-qQQ3kt zj7Pk5gkZ%O)Ci2q(uY!e27U!ScarpLu7580sK3E0w)Tj@#u9l$F`Bz^Ltj5LJDGbm zS>mnwSpuQE+_y(CZ$UpMdvZTpyO3>+(F4acm#C$Fg3X|^tXIe4WVW7~H8)j5%wqlK z>U#NZ@Ln(Q7|ZX-{S5#Rv69nz9&Pa{fom_ZK@ASqCaB&X}Lv!z4-k(a!pkDiOg6`42&5EEKGAyO} zM>L(2%l^$sz2wW;8x&(o}Psn3g0qs2PgP@-1mE=lQt+91&FeiOk;mT8^! zvMdIlQ&O$dO5mc?U?G8|D(42XIgRAJ#P>W1VZ${eL=W8mQ*0ymOp(U38C8y+x?E2GfHctREpExo8h_ zWtw7qRznUo%e+-KFr%YX6s4I+oF&I$@X;wS{SF?=qF~Z~rbCjcE>TonoWs-bdr-vy zqjm}&EtS`#xT&H+^1(b{k1-_de7J?asUEL4T?f+=Opm)TBMrVG%u~)`lZTsHbyWR{ zl)~Tx1A5!c8-E;KpY^n!T2J#%>?|a4}=bF!rm6HOJUuMn?*d zlJy?1*|MRTy^ndgezC#+Vax+hxCaee#lHq=U`*;OgVmTzb*cu3VRhwBjOdg0SNc|I zI~_;XQ#OXITZ0|ly{H~}UKUJo?})b`^xE+)WDJqO_;z$)JQO1>jveRYZCgCB%%p}-LlIgEz6iysIgWKD=_x4swAdEK}z1O z@PgL*^u(V-kb@*;B zl!(qec(N$2SsFv>_gYGoWGe3Q97%~cg@jYVJ=WiC{9`W?3iv8^G$HXy`#Ym!p$Fae z0J*ufG|(+C%L%bcUDh9@gR#xUosNaI_=kg#Re8y;Bwet2rsUbGA)}vezetP#|4k{g z2NJwacdV^k?3$~~N6Ja!&^*v>*uyD*1MTw8-DR(YGdqj{R*SWm%FxCTfDtNk9IJ1n!V zKTejQLp-h12xGviD=<$NZC-YkMH+Z!I??goKQquTHQy&671;w4hPDSipY%o- zGPxclB>y^mii#b?A>UpS)nb`wVGaX)89pyc1m z>P!#!;#AUvMs9l(_4)J%dQv{p#eT&B$40f!FTMXuGFBpyB%b!md|K>Q0GIEf`vC^B z2=m^()Q+1x4(1E%3hh*bhpdZQ>Celj8xC`bpn@T?Py6ZB#pjh94L5%v=jUE$s-(PJ z;3CrfPMRu9Omr}duY2$*6BnN@!;%-!>?QL&yb<$_!PGH2qk@n=C+Uv!Pb5^foL!Z-Ktb5UaE1-A< znqJ_Y$OV7kUuHfiP0rm+*TYOvc~h> zs)B+}!N?53JQht^z@XJl$4bv?WjiT{rzp9KOew7{(b$w z42=D6*Tvz^{|o%@KOgfSDfRlWkV4nlmCmt@E(#E-93tLw=ywX?#oVChYk?b`$zD6P z=9Ei}&fm|Ta%nXFmc0&GY8_4p`w+Q1DI#(_*9i}1+;rA9eP)debjsT3ts%}xN ztP<^f)qt^&tTpfErqQ?*gZ=PN@>mVt*`sxSYG zfW(rw`9uJopFiAge`CM&duwkg2n@&mJVRDzYbF2ZA{gNEw|LIO@XurDP#^*A1;5-8 z|Df#u2Q7EYgjnc5w19u<9Gmdy!?_~UdH=r;690vh@PEr!IBz#04*2urWp=kmdDG0&6GHS4ufUPsYp9NW1zHiOLMz7Rv1V|}A zL1+b;s;Ei{)D>D@>mpD>L0K$IJ5NoWIjslAGHdHB14>rZW1zCfK#}x=tpX4QLHJt+ zfC`|4i*NEWZj0;=JDog30}P3D(CTa&KwLjBmvNmygacrFtjC$FB3f!T1h%*N3>2{f z4h$Hk)}Zc$shJt!U>|t!Yjz}B0eS(gAS1bhaHN(duTl-zL?bAVuJ_z!W!M7(h)~*I z-L25P4d?(g7QDZok#Q&o?9>BD4=S?|sO59$X3X&l0D$K|YLXNeXC8a0^%9hBs0t~# z(*lKp%ADuB5`FjQD?K*D5<&dVzE=$e3t(C!tPc?W&jbrsh)^Z!_caO0qgy=LxXR@2Ghp0)}8ehrFR%U7O7%0_%B-$KYBuqFGN0VQ>aqy!s{7cQ@cF zdb$DYiLgWZ!pw&@IfTjxiz5(;JA`_-K&t%FKoPDG-6xL$aU103(dCppjP~LP$mAL+ ztQT#T2_ieTvx-g2SHi| z>wb+J1b`0IUqMGM>?A&h&T-Nhl1lK4*`J3Mk!x6EaB~<46Uc2A$-xdk)$i&(KVQ5!o+{p> z0xyZS&htRS*$Y%o$SOm=&hpj)63WplbrvL*u;O)|{^4-JMJYOTw!%;xsF_Ko1c#lh0|cY%4KwKzAIIu7}Ws+APW+9_ah0fwYd(0EnWJ_ zQWPfqZ21V+bxo-~TP`VlYky}MZECrP%t1!P;L|vCKv8adpk_EyVjJrrcZ^lYz-zg9 zM;!FxFM!*hHHDJVj~9v}Rqwf2( z>Vj}Pzuy^H{>A zAvTsVHxm*Zh^&&HUp<<6YFl7akg$g}N;V4O4TRZLSaEjEqR5yx@@Q&g` znzERXUX`~#a9$IA(uDOF>t&nY5YlF5kDX`cs$jTFxT0&hikmloV7;b8)Q)SgJ41$-NROR3t(@u!wU)B>tyN)cF$B^G>N7z7V+bW5BE&{%Ldo12jtrVA=PJeIoE*fluhf$JVvJ{qX-qGai~ik(2H>c7Ml@ zjEtO2I|k_rhu3ot4i37-Y{@rXLqR)xzn^GHzL4^*#CB$U?6)Pi zN{7+@dQihRU~JZdF#sBQ{1RKAM$#4 z^b_3gsgOq}4pee!-r#F`R=M!+&uv$fm+ygE@y<31?$z%*HS}Y`m|&@pt3ai2H3gd3 zIUtCM`S?yPn->m1?|xNrfEV+DB=M9Fy_l~E;WJr9te>|e{BRR{pY412%Q(-4TKMC} zUqA1Bx>?)W z+QKJ_XuYf)FIZeySm++($BAIac<&iu(|PSaVJ-On8exU@=iC3Z%%4v1=kfS668sq>|HtXT^g^pK0&&Jz zM*P0|KhyD_ndHx;dFoFm_|pmgbb>$2XT+aQ@TU{}=>&f^(xB7)SrhzEuL+EObO^4T zu`ypCV_J}Eyt6^QnGb0c$&L%yo_)+m8)E3YHw~Dp?ALq5zSU8$!VB{dq9P(!LcF}Z zE+G(k3^QczM6H1UHKMdK0py*)U1YrBR91_a$!hPA$dx@i84q9_k>wW1A* zj5mc6Q1Hh{+bg)d57h+2Kb%BVR9E9c@6yaQP{@n7uMI;Lo(pY4h7n7ok%49Dw(YzL6R)g z2_#5V{v8VcZ);R9ibF#~LCQqnm+>IR9UYMc=X$|EPY^a+#}N8cn)lLQX)VH65Hb>q K;yDkDp8bDl7_@o- diff --git a/web-harness/shell-mock.ts b/web-harness/shell-mock.ts deleted file mode 100644 index a82afa05..00000000 --- a/web-harness/shell-mock.ts +++ /dev/null @@ -1,65 +0,0 @@ -// Mock for shell module - no-op implementations for browser - -// Types -export type ShellMode = 'inactive' | 'input' | 'running' | 'done'; - -export interface ShellOutput { - lines: string[]; - exitCode: number | null; -} - -export interface ShellExecutorCallbacks { - onOutput: (lines: string[]) => void; - onComplete: (exitCode: number | null) => void; - onError: (error: string) => void; -} - -export interface ShellExecutor { - kill: (signal?: string) => void; -} - -// Functions -export function warmupShell(): void { - console.log('[browser mock] warmupShell called'); -} - -export function destroyShell(): void { - console.log('[browser mock] destroyShell called'); -} - -export function spawnPersistentShellCommand(command: string, callbacks: ShellExecutorCallbacks): ShellExecutor { - // Simulate command execution with mock output - setTimeout(() => { - callbacks.onOutput([`$ ${command}`, '(Commands are mocked in browser)']); - }, 50); - - setTimeout(() => { - callbacks.onComplete(0); - }, 150); - - return { - kill: (_signal?: string) => { - console.log('[browser mock] persistent shell kill called'); - callbacks.onComplete(130); - }, - }; -} - -export function spawnShellCommand(command: string, callbacks: ShellExecutorCallbacks): ShellExecutor { - // Simulate command execution with mock output - setTimeout(() => { - callbacks.onOutput([`$ ${command}`, '(Commands are mocked in browser)']); - }, 50); - - setTimeout(() => { - callbacks.onComplete(0); - }, 150); - - return { - kill: (_signal?: string) => console.log('[browser mock] shell kill called'), - }; -} - -export function truncateOutput(lines: string[], _maxLines: number = 500): string[] { - return lines; -} diff --git a/web-harness/template-root-mock.ts b/web-harness/template-root-mock.ts deleted file mode 100644 index 30518df0..00000000 --- a/web-harness/template-root-mock.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Mock for templates/templateRoot.ts - browser mock - -export const TEMPLATE_ROOT = '/mock/templates'; - -export function resolveTemplateRoot(): string { - return TEMPLATE_ROOT; -} - -export function getTemplatePath(relativePath: string): string { - return `${TEMPLATE_ROOT}/${relativePath}`; -} diff --git a/web-harness/test-harness.mjs b/web-harness/test-harness.mjs deleted file mode 100644 index 91899339..00000000 --- a/web-harness/test-harness.mjs +++ /dev/null @@ -1,73 +0,0 @@ -import { chromium } from 'playwright'; - -async function testHarness() { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - - // Collect console messages - const consoleLogs = []; - const consoleErrors = []; - - page.on('console', msg => { - if (msg.type() === 'error') { - consoleErrors.push(msg.text()); - } else { - consoleLogs.push(`[${msg.type()}] ${msg.text()}`); - } - }); - - page.on('pageerror', err => { - consoleErrors.push(`PAGE ERROR: ${err.message}`); - }); - - try { - console.log('Navigating to http://localhost:5173/...'); - await page.goto('http://localhost:5173/', { waitUntil: 'networkidle', timeout: 30000 }); - - // Wait a bit for React to render - await page.waitForTimeout(2000); - - // Get page title - const title = await page.title(); - console.log(`\nPage title: ${title}`); - - // Check if root has content - const rootContent = await page.$eval('#root', el => el.innerHTML.length); - console.log(`Root element content length: ${rootContent} chars`); - - // Look for terminal frames - const terminals = await page.$$('div[style*="background"]'); - console.log(`Found ${terminals.length} styled divs`); - - // Get visible text - const bodyText = await page.textContent('body'); - console.log(`\nVisible text preview: ${bodyText?.substring(0, 500)}...`); - - // Take a screenshot - await page.screenshot({ path: '/Users/owenkaplan/code/agentcore-cli/web-harness/screenshot.png', fullPage: true }); - console.log('\nScreenshot saved to web-harness/screenshot.png'); - - // Report errors - if (consoleErrors.length > 0) { - console.log('\n❌ CONSOLE ERRORS:'); - consoleErrors.forEach(e => console.log(` - ${e}`)); - } else { - console.log('\n✅ No console errors!'); - } - - // Report some logs - if (consoleLogs.length > 0) { - console.log(`\nConsole logs (${consoleLogs.length} total):`); - consoleLogs.slice(0, 10).forEach(l => console.log(` ${l}`)); - if (consoleLogs.length > 10) { - console.log(` ... and ${consoleLogs.length - 10} more`); - } - } - } catch (err) { - console.error('Error:', err.message); - } finally { - await browser.close(); - } -} - -testHarness(); diff --git a/web-harness/test-writable-fs.mjs b/web-harness/test-writable-fs.mjs deleted file mode 100644 index c840517d..00000000 --- a/web-harness/test-writable-fs.mjs +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env node -/** - * Test script to verify the writable mock filesystem works end-to-end. - * - * Tests: - * 1. Server API endpoints work (read/write/reset) - * 2. Changes persist until reset - * 3. Reset restores original data - */ - -const BASE_URL = 'http://localhost:5173'; - -async function testReadFile(path) { - const response = await fetch(`${BASE_URL}/__mock-fs${path}`); - if (!response.ok) { - throw new Error(`Failed to read ${path}: ${response.status}`); - } - const data = await response.json(); - return data.content; -} - -async function testWriteFile(path, content) { - const response = await fetch(`${BASE_URL}/__mock-fs${path}`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content }), - }); - if (!response.ok) { - throw new Error(`Failed to write ${path}: ${response.status}`); - } - return await response.json(); -} - -async function testReset() { - const response = await fetch(`${BASE_URL}/__mock-fs-reset`, { method: 'POST' }); - if (!response.ok) { - throw new Error(`Failed to reset: ${response.status}`); - } - return await response.json(); -} - -async function testSync() { - const response = await fetch(`${BASE_URL}/__mock-fs-sync`); - if (!response.ok) { - throw new Error(`Failed to sync: ${response.status}`); - } - return await response.json(); -} - -async function runTests() { - console.log('🧪 Testing Writable Mock Filesystem\n'); - - const agentcorePath = '/mock/workspace/agentcore/agentcore.json'; - - // Test 1: Read original file - console.log('1️⃣ Testing: Read original file...'); - const originalContent = await testReadFile(agentcorePath); - const original = JSON.parse(originalContent); - console.log(` ✅ Original workspace name: "${original.name}"`); - console.log(` ✅ Original has ${original.agents?.length || 0} agents`); - - // Test 2: Write modified content - console.log('\n2️⃣ Testing: Write modified content...'); - const modified = { - ...original, - name: 'ModifiedWorkspace', - description: 'This was modified by the test script!', - agents: original.agents?.slice(0, 1) || [], // Keep only first agent - }; - await testWriteFile(agentcorePath, JSON.stringify(modified, null, 2)); - console.log(' ✅ Write successful'); - - // Test 3: Read back modified content - console.log('\n3️⃣ Testing: Read back modified content...'); - const readBackContent = await testReadFile(agentcorePath); - const readBack = JSON.parse(readBackContent); - if (readBack.name !== 'ModifiedWorkspace') { - throw new Error(`Expected name "ModifiedWorkspace", got "${readBack.name}"`); - } - console.log(` ✅ Modified workspace name: "${readBack.name}"`); - console.log(` ✅ Modified has ${readBack.agents?.length || 0} agents`); - - // Test 4: Verify changes persist via sync endpoint - console.log('\n4️⃣ Testing: Verify changes via sync endpoint...'); - const syncData = await testSync(); - const syncedContent = syncData.files[agentcorePath]?.content; - if (!syncedContent?.includes('ModifiedWorkspace')) { - throw new Error('Sync endpoint did not return modified content'); - } - console.log(' ✅ Changes are visible in sync endpoint'); - - // Test 5: Reset filesystem - console.log('\n5️⃣ Testing: Reset filesystem...'); - await testReset(); - console.log(' ✅ Reset successful'); - - // Test 6: Verify reset restored original - console.log('\n6️⃣ Testing: Verify reset restored original...'); - const afterResetContent = await testReadFile(agentcorePath); - const afterReset = JSON.parse(afterResetContent); - if (afterReset.name !== original.name) { - throw new Error(`Expected name "${original.name}", got "${afterReset.name}"`); - } - console.log(` ✅ Reset restored workspace name: "${afterReset.name}"`); - console.log(` ✅ Reset restored ${afterReset.agents?.length || 0} agents`); - - console.log('\n🎉 All tests passed!\n'); - console.log('The writable mock filesystem is working correctly.'); - console.log('- Changes persist in memory during the dev session'); - console.log('- Reset restores the original mock data'); - console.log('- Refreshing the page will reload data from server memory'); -} - -runTests().catch(err => { - console.error('\n❌ Test failed:', err.message); - process.exit(1); -}); diff --git a/web-harness/tsconfig.json b/web-harness/tsconfig.json deleted file mode 100644 index feeccc4f..00000000 --- a/web-harness/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": false, - "noUnusedParameters": false, - "noFallthroughCasesInSwitch": true, - "paths": { - "@agentcore/lib": ["./lib-mocks.ts"], - "@agentcore/schema": ["./lib-mocks.ts"] - } - }, - "include": [ - "./**/*.ts", - "./**/*.tsx", - "../packages/agentcore-cli/src/**/*.ts", - "../packages/agentcore-cli/src/**/*.tsx" - ] -} diff --git a/web-harness/tui-process-mock.ts b/web-harness/tui-process-mock.ts deleted file mode 100644 index 8e46602b..00000000 --- a/web-harness/tui-process-mock.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Mock for tui/utils/process.ts - no-op implementations for browser - -export async function isProcessRunning(_pid: number): Promise { - return false; -} - -export async function cleanupStaleLockFiles(_cdkOutDir: string): Promise { - // No-op in browser -} diff --git a/web-harness/vite.config.ts b/web-harness/vite.config.ts deleted file mode 100644 index 833ab7c3..00000000 --- a/web-harness/vite.config.ts +++ /dev/null @@ -1,247 +0,0 @@ -import { MOCK_SCENARIO } from './harness-env'; -import { createMockFsPlugin } from './mock-fs-server'; -import react from '@vitejs/plugin-react'; -import path from 'path'; -import { Plugin, defineConfig } from 'vite'; - -// Custom plugin to handle module resolution for Node.js and workspace packages -function browserMocksPlugin(): Plugin { - const mocks: Record = { - // Node.js modules - 'node:fs': path.resolve(__dirname, './node-mocks.ts'), - 'node:fs/promises': path.resolve(__dirname, './node-mocks.ts'), - fs: path.resolve(__dirname, './node-mocks.ts'), - 'fs/promises': path.resolve(__dirname, './node-mocks.ts'), - 'node:path': path.resolve(__dirname, './node-mocks.ts'), - path: path.resolve(__dirname, './node-mocks.ts'), - 'node:url': path.resolve(__dirname, './node-mocks.ts'), - url: path.resolve(__dirname, './node-mocks.ts'), - 'node:child_process': path.resolve(__dirname, './node-mocks.ts'), - child_process: path.resolve(__dirname, './node-mocks.ts'), - 'node:os': path.resolve(__dirname, './node-mocks.ts'), - os: path.resolve(__dirname, './node-mocks.ts'), - 'node:crypto': path.resolve(__dirname, './node-mocks.ts'), - crypto: path.resolve(__dirname, './node-mocks.ts'), - 'node:events': path.resolve(__dirname, './node-mocks.ts'), - events: path.resolve(__dirname, './node-mocks.ts'), - 'node:stream': path.resolve(__dirname, './node-mocks.ts'), - stream: path.resolve(__dirname, './node-mocks.ts'), - 'stream/promises': path.resolve(__dirname, './node-mocks.ts'), - 'node:stream/promises': path.resolve(__dirname, './node-mocks.ts'), - 'node:util': path.resolve(__dirname, './node-mocks.ts'), - util: path.resolve(__dirname, './node-mocks.ts'), - 'node:net': path.resolve(__dirname, './node-mocks.ts'), - net: path.resolve(__dirname, './node-mocks.ts'), - 'node:http': path.resolve(__dirname, './node-mocks.ts'), - http: path.resolve(__dirname, './node-mocks.ts'), - 'node:https': path.resolve(__dirname, './node-mocks.ts'), - https: path.resolve(__dirname, './node-mocks.ts'), - 'node:tty': path.resolve(__dirname, './node-mocks.ts'), - tty: path.resolve(__dirname, './node-mocks.ts'), - 'node:readline': path.resolve(__dirname, './node-mocks.ts'), - readline: path.resolve(__dirname, './node-mocks.ts'), - 'node:buffer': path.resolve(__dirname, './node-mocks.ts'), - buffer: path.resolve(__dirname, './node-mocks.ts'), - 'node:assert': path.resolve(__dirname, './node-mocks.ts'), - assert: path.resolve(__dirname, './node-mocks.ts'), - 'node:zlib': path.resolve(__dirname, './node-mocks.ts'), - zlib: path.resolve(__dirname, './node-mocks.ts'), - - // Ink shims - ink: path.resolve(__dirname, './ink-browser-shim.tsx'), - 'ink-spinner': path.resolve(__dirname, './ink-spinner-shim.tsx'), - // Ink's Node.js dependencies - not needed when using our shim - 'yoga-layout': path.resolve(__dirname, './external-mocks.ts'), - '@resvg/resvg-js': path.resolve(__dirname, './external-mocks.ts'), - 'yoga-wasm-web': path.resolve(__dirname, './external-mocks.ts'), - // Terminal detection packages - not needed in browser - 'supports-color': path.resolve(__dirname, './external-mocks.ts'), - 'supports-hyperlinks': path.resolve(__dirname, './external-mocks.ts'), - - // Force zod to resolve from web-harness node_modules - zod: path.resolve(__dirname, './node_modules/zod/index.js'), - - // External package mocks - '@commander-js/extra-typings': path.resolve(__dirname, './external-mocks.ts'), - commander: path.resolve(__dirname, './external-mocks.ts'), - handlebars: path.resolve(__dirname, './external-mocks.ts'), - dotenv: path.resolve(__dirname, './external-mocks.ts'), - - // AWS SDK mocks - '@aws-sdk/client-cloudformation': path.resolve(__dirname, './external-mocks.ts'), - '@aws-sdk/client-sts': path.resolve(__dirname, './external-mocks.ts'), - '@aws-sdk/client-bedrock-runtime': path.resolve(__dirname, './external-mocks.ts'), - '@aws-sdk/client-bedrock-agentcore': path.resolve(__dirname, './external-mocks.ts'), - '@aws-sdk/client-bedrock-agentcore-control': path.resolve(__dirname, './external-mocks.ts'), - '@aws-sdk/credential-providers': path.resolve(__dirname, './external-mocks.ts'), - '@smithy/shared-ini-file-loader': path.resolve(__dirname, './external-mocks.ts'), - '@aws-cdk/toolkit-lib': path.resolve(__dirname, './external-mocks.ts'), - }; - - const cliMock = path.resolve(__dirname, './cli-mock.ts'); - const shellMock = path.resolve(__dirname, './shell-mock.ts'); - const cliConstantsMock = path.resolve(__dirname, './cli-constants-mock.ts'); - const tuiProcessMock = path.resolve(__dirname, './tui-process-mock.ts'); - const templateRootMock = path.resolve(__dirname, './template-root-mock.ts'); - const nlEditMock = path.resolve(__dirname, './nl-edit-mock.ts'); - - // Path to the main CLI constants (NOT the TUI constants) - const mainConstantsPath = path.resolve(__dirname, '../src/cli/constants.ts'); - - return { - name: 'browser-mocks', - enforce: 'pre', - resolveId(source, importer) { - // Handle exact matches - if (mocks[source]) { - return mocks[source]; - } - - // Mock the CLI module (has many Node.js dependencies including 'module' builtin) - if (source === '../cli' || source === './cli' || source.endsWith('/cli')) { - if (importer?.includes('src/cli')) { - return cliMock; - } - } - - // Mock the shell module - if (source === '../shell' || source === './shell' || source.endsWith('/shell')) { - if (importer?.includes('src/cli')) { - return shellMock; - } - } - - // Mock the lib module (uses Node.js APIs) - if ( - source === '../../lib' || - source === '../../../lib' || - source === '../../../../lib' || - source.match(/^\.\.\/.*\/lib$/) - ) { - if (importer?.includes('src/cli')) { - return path.resolve(__dirname, './lib-mocks.ts'); - } - } - - // Mock the CLI's internal schema module (uses fs/promises) - // Only mock imports that resolve to src/cli/schema (not src/schema) - // From screens/schema/*.tsx, '../../../schema' resolves to cli/schema - // From hooks/*.ts, '../../schema' resolves to cli/schema - if (source === '../../../schema') { - if (importer?.includes('src/cli/tui/screens')) { - return path.resolve(__dirname, './cli-schema-mock.ts'); - } - } - if (source === '../../schema') { - if (importer?.includes('src/cli/tui/hooks')) { - return path.resolve(__dirname, './cli-schema-mock.ts'); - } - } - - // Mock the TUI process utility (uses child_process) - if (source === './process' || source === '../process' || source.endsWith('/process')) { - if (importer?.includes('src/cli/tui')) { - return tuiProcessMock; - } - } - - // Mock templateRoot (uses node:url) - if (source === './templateRoot' || source.endsWith('/templateRoot')) { - if (importer?.includes('src/cli')) { - return templateRootMock; - } - } - - // Mock schema-assets (imports raw text files which need special handling) - if (source === './schema-assets' || source.endsWith('/schema-assets')) { - if (importer?.includes('src/cli')) { - return path.resolve(__dirname, './schema-assets-mock.ts'); - } - } - - // Mock the nl-edit operations module (uses Bun-specific import ... with { type: 'text' }) - if ( - source.includes('operations/nl-edit') || - source === '../../../operations/nl-edit' || - source === '../../operations/nl-edit' || - source === '../operations/nl-edit' || - source === './nl-edit' - ) { - if (importer?.includes('src/cli')) { - console.log(`[browser-mocks] INTERCEPTING nl-edit import -> ${nlEditMock}`); - return nlEditMock; - } - } - - // Mock the MAIN CLI constants.ts (uses Node.js 'module' builtin) - // Intercept imports that resolve to src/cli/constants.ts (not tui/constants.ts) - if (source.endsWith('/constants') || source.endsWith('/constants.ts')) { - // Check if this resolves to the MAIN cli constants (not tui constants) - // ../../../constants from tui/screens/update -> cli/constants (main - needs mock) - // ../../constants from tui/screens -> tui/constants (tui - don't mock) - // ../constants from tui/components -> tui/constants (tui - don't mock) - const isFromTui = importer?.includes('/tui/'); - const goesToMainConstants = - source === '../../../constants' || // from tui/screens/*/ - source === '../../../../constants'; // from tui/screens/*/*/ - - if (isFromTui && goesToMainConstants) { - console.log(`[browser-mocks] INTERCEPTING main constants import from TUI -> ${cliConstantsMock}`); - return cliConstantsMock; - } - - // Also mock non-TUI imports to main constants - const isCliSrc = importer?.includes('src/cli'); - const isNotTui = !isFromTui; - if (isCliSrc && isNotTui) { - console.log(`[browser-mocks] INTERCEPTING constants import -> ${cliConstantsMock}`); - return cliConstantsMock; - } - } - - return null; - }, - }; -} - -export default defineConfig({ - plugins: [createMockFsPlugin(MOCK_SCENARIO), browserMocksPlugin(), react()], - server: { - fs: { - // Allow serving files from parent directory (src/) - allow: ['..'], - }, - }, - define: { - 'process.env': JSON.stringify({}), - 'process.cwd': '() => "/mock/workspace"', - 'process.chdir': '() => {}', - 'process.platform': JSON.stringify('browser'), - // Signal handling no-ops for browser - 'process.on': '(() => {})', - 'process.off': '(() => {})', - 'process.once': '(() => {})', - 'process.removeListener': '(() => {})', - }, - assetsInclude: ['**/*.txt'], - optimizeDeps: { - include: ['zod'], - // Exclude packages that should be aliased to shims - don't let Vite try to pre-bundle them - exclude: ['ink', 'ink-spinner', 'yoga-layout', '@resvg/resvg-js', 'supports-color', 'supports-hyperlinks'], - esbuildOptions: { - platform: 'browser', - }, - }, - resolve: { - // Ensure we use the browser-compatible version - conditions: ['browser', 'module', 'import', 'default'], - // Force single copy of zod - dedupe: ['zod'], - }, - // Handle CommonJS modules from the schema package - build: { - commonjsOptions: { - transformMixedEsModules: true, - }, - }, -});