This commit is contained in:
iamlukethedev
2026-04-07 11:42:35 -05:00
parent 834501a625
commit f8531ee7b0
23 changed files with 141 additions and 286 deletions
+16 -231
View File
@@ -1,18 +1,17 @@
{
"name": "claw3d",
"version": "0.1.0",
"version": "0.1.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claw3d",
"version": "0.1.0",
"version": "0.1.5",
"license": "MIT",
"dependencies": {
"@noble/ed25519": "^3.0.0",
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.5.0",
"@vercel/otel": "^2.1.0",
"canvas-confetti": "^1.9.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -163,7 +162,6 @@
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/generator": "^7.28.6",
@@ -470,7 +468,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
},
@@ -511,7 +508,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
}
@@ -1959,141 +1955,6 @@
"node": ">=12.4.0"
}
},
"node_modules/@opentelemetry/api": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@opentelemetry/api-logs": {
"version": "0.211.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.211.0.tgz",
"integrity": "sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/api": "^1.3.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@opentelemetry/core": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.5.0.tgz",
"integrity": "sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/semantic-conventions": "^1.29.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/instrumentation": {
"version": "0.211.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.211.0.tgz",
"integrity": "sha512-h0nrZEC/zvI994nhg7EgQ8URIHt0uDTwN90r3qQUdZORS455bbx+YebnGeEuFghUT0HlJSrLF4iHw67f+odY+Q==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/api-logs": "0.211.0",
"import-in-the-middle": "^2.0.0",
"require-in-the-middle": "^8.0.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/resources": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.5.0.tgz",
"integrity": "sha512-F8W52ApePshpoSrfsSk1H2yJn9aKjCrbpQF1M9Qii0GHzbfVeFUB+rc3X4aggyZD8x9Gu3Slua+s6krmq6Dt8g==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "2.5.0",
"@opentelemetry/semantic-conventions": "^1.29.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.3.0 <1.10.0"
}
},
"node_modules/@opentelemetry/sdk-logs": {
"version": "0.211.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.211.0.tgz",
"integrity": "sha512-O5nPwzgg2JHzo59kpQTPUOTzFi0Nv5LxryG27QoXBciX3zWM3z83g+SNOHhiQVYRWFSxoWn1JM2TGD5iNjOwdA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/api-logs": "0.211.0",
"@opentelemetry/core": "2.5.0",
"@opentelemetry/resources": "2.5.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.4.0 <1.10.0"
}
},
"node_modules/@opentelemetry/sdk-metrics": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.5.0.tgz",
"integrity": "sha512-BeJLtU+f5Gf905cJX9vXFQorAr6TAfK3SPvTFqP+scfIpDQEJfRaGJWta7sJgP+m4dNtBf9y3yvBKVAZZtJQVA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "2.5.0",
"@opentelemetry/resources": "2.5.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.9.0 <1.10.0"
}
},
"node_modules/@opentelemetry/sdk-trace-base": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.5.0.tgz",
"integrity": "sha512-VzRf8LzotASEyNDUxTdaJ9IRJ1/h692WyArDBInf5puLCjxbICD6XkHgpuudis56EndyS7LYFmtTMny6UABNdQ==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "2.5.0",
"@opentelemetry/resources": "2.5.0",
"@opentelemetry/semantic-conventions": "^1.29.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.3.0 <1.10.0"
}
},
"node_modules/@opentelemetry/semantic-conventions": {
"version": "1.39.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.39.0.tgz",
"integrity": "sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==",
"license": "Apache-2.0",
"engines": {
"node": ">=14"
}
},
"node_modules/@peculiar/asn1-cms": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz",
@@ -2259,7 +2120,6 @@
"integrity": "sha512-fWza+Lpbj6SkQKCrU6si4iu+fD2dD3gxNHFhUPxsfXBPhnv3rRSQVd0NtBUT9Z/RhF/boCBcuUaMUSTRTopjZg==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"playwright": "1.58.0"
},
@@ -2315,7 +2175,6 @@
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.5.0.tgz",
"integrity": "sha512-FiUzfYW4wB1+PpmsE47UM+mCads7j2+giRBltfwH7SNhah95rqJs3ltEs9V3pP8rYdS0QlNne+9Aj8dS/SiaIA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.17.8",
"@types/webxr": "*",
@@ -3069,6 +2928,7 @@
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -3089,6 +2949,7 @@
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -3170,7 +3031,8 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@types/canvas-confetti": {
"version": "1.9.0",
@@ -3286,7 +3148,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.9.tgz",
"integrity": "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -3297,7 +3158,6 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"dev": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -3322,7 +3182,6 @@
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz",
"integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@dimforge/rapier3d-compat": "~0.12.0",
"@tweenjs/tween.js": "~23.1.3",
@@ -3400,7 +3259,6 @@
"integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.53.1",
"@typescript-eslint/types": "8.53.1",
@@ -3918,24 +3776,6 @@
"react": ">= 16.8.0"
}
},
"node_modules/@vercel/otel": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@vercel/otel/-/otel-2.1.0.tgz",
"integrity": "sha512-Zwu2Cu4t46DzBnY1DQSTxZ4MBLVfYsOjnlWuZuLRWnmVPX+SNrVHbs3ssiJ6uvY1J1JJswor4zSn8mHYxzYeBA==",
"license": "MIT",
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.9.0 <2.0.0",
"@opentelemetry/api-logs": ">=0.200.0 <0.300.0",
"@opentelemetry/instrumentation": ">=0.200.0 <0.300.0",
"@opentelemetry/resources": ">=2.0.0 <3.0.0",
"@opentelemetry/sdk-logs": ">=0.200.0 <0.300.0",
"@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0",
"@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0"
}
},
"node_modules/@vitest/expect": {
"version": "4.0.18",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz",
@@ -4057,8 +3897,8 @@
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -4066,15 +3906,6 @@
"node": ">=0.4.0"
}
},
"node_modules/acorn-import-attributes": {
"version": "1.9.5",
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
"license": "MIT",
"peerDependencies": {
"acorn": "^8"
}
},
"node_modules/acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -4118,6 +3949,7 @@
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=8"
}
@@ -4495,7 +4327,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -4724,18 +4555,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/cjs-module-lexer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz",
"integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==",
"license": "MIT"
},
"node_modules/class-variance-authority": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"clsx": "^2.1.1"
},
@@ -4754,7 +4578,6 @@
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6"
}
@@ -5112,7 +4935,8 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/draco3d": {
"version": "1.5.7",
@@ -5431,7 +5255,6 @@
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -5633,7 +5456,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -6532,18 +6354,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/import-in-the-middle": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.5.tgz",
"integrity": "sha512-0InH9/4oDCBRzWXhpOqusspLBrVfK1vPvbn9Wxl8DAQ8yyx5fWJRETICSwkiAMaYntjJAMBP1R4B6cQnEUYVEA==",
"license": "Apache-2.0",
"dependencies": {
"acorn": "^8.15.0",
"acorn-import-attributes": "^1.9.5",
"cjs-module-lexer": "^2.2.0",
"module-details-from-path": "^1.0.4"
}
},
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -7148,7 +6958,6 @@
"integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@acemir/cssom": "^0.9.28",
"@asamuzakjp/dom-selector": "^6.7.6",
@@ -7631,6 +7440,7 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -8599,12 +8409,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/module-details-from-path": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz",
"integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==",
"license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -9178,6 +8982,7 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -9193,6 +8998,7 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
},
@@ -9205,7 +9011,8 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/promise-worker-transferable": {
"version": "1.0.4",
@@ -9295,7 +9102,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -9305,7 +9111,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -9518,19 +9323,6 @@
"node": ">=0.10.0"
}
},
"node_modules/require-in-the-middle": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz",
"integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.5",
"module-details-from-path": "^1.0.3"
},
"engines": {
"node": ">=9.3.0 || >=8.10.0 <9.0.0"
}
},
"node_modules/resolve": {
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
@@ -10292,7 +10084,6 @@
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
"integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
@@ -10323,8 +10114,7 @@
"version": "0.183.2",
"resolved": "https://registry.npmjs.org/three/-/three-0.183.2.tgz",
"integrity": "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/three-mesh-bvh": {
"version": "0.8.3",
@@ -10416,7 +10206,6 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -10752,7 +10541,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -11026,7 +10814,6 @@
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -11135,7 +10922,6 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -11487,7 +11273,6 @@
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"dev": true,
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+3 -4
View File
@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { GatewayClient } from "@/lib/gateway/GatewayClient";
import { NodeGatewayClient } from "@/lib/gateway/nodeGatewayClient";
import {
generatePictureModelViaGateway,
MAX_PICTURE_MODEL_UPLOAD_BYTES,
@@ -8,7 +8,7 @@ import {
export const runtime = "nodejs";
export async function POST(request: Request) {
const gatewayClient = new GatewayClient();
const gatewayClient = new NodeGatewayClient();
try {
const MULTIPART_OVERHEAD_ALLOWANCE = 1024;
const contentLengthHeader = request.headers.get("content-length");
@@ -85,7 +85,6 @@ export async function POST(request: Request) {
disableDeviceAuth: false,
});
Buffer.from(arrayBuffer).toString("base64");
const result = await generatePictureModelViaGateway({
client: gatewayClient,
summary: {
@@ -107,6 +106,6 @@ export async function POST(request: Request) {
: "Failed to generate the 3D model from the uploaded image.";
return NextResponse.json({ error: message }, { status: 500 });
} finally {
gatewayClient.disconnect();
gatewayClient.close();
}
}
@@ -1,7 +1,7 @@
import {
buildAgentMainSessionKey,
isSameSessionKey,
} from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import { type GatewayModelPolicySnapshot } from "@/lib/gateway/models";
import {
isTemporarySkillAgentName,
@@ -1,4 +1,4 @@
import { buildAgentMainSessionKey } from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import { createDefaultAgentAvatarProfile } from "@/lib/avatars/profile";
import { resolveConfiguredModelKey, type GatewayModelPolicySnapshot } from "@/lib/gateway/models";
import {
@@ -1,4 +1,4 @@
import { parseAgentIdFromSessionKey } from "@/lib/gateway/GatewayClient";
import { parseAgentIdFromSessionKey } from "@/lib/gateway/sessionKeys";
export type LatestUpdateKind = "heartbeat" | "cron" | null;
@@ -1363,7 +1363,6 @@ const AgentsPageScreen = () => {
(!connectPromptReady ||
(gatewayUrl.trim().length > 0 &&
!shouldPromptForConnect &&
token.trim().length > 0 &&
(!didAttemptGatewayConnect || status === "connecting")))
) {
return (
@@ -1,6 +1,7 @@
import { resolveExecApprovalEventEffects, type ExecApprovalEventEffects } from "@/features/agents/approvals/execApprovalLifecycleWorkflow";
import type { AgentState } from "@/features/agents/state/store";
import { parseAgentIdFromSessionKey, type EventFrame } from "@/lib/gateway/GatewayClient";
import type { EventFrame } from "@/lib/gateway/GatewayClient";
import { parseAgentIdFromSessionKey } from "@/lib/gateway/sessionKeys";
export type CronTranscriptIntent = {
agentId: string;
@@ -25,8 +25,8 @@ import {
import {
type EventFrame,
isSameSessionKey,
parseAgentIdFromSessionKey,
} from "@/lib/gateway/GatewayClient";
import { parseAgentIdFromSessionKey } from "@/lib/gateway/sessionKeys";
import { normalizeAssistantDisplayText } from "@/lib/text/assistantText";
import {
extractText,
@@ -6,10 +6,10 @@ import type {
SummaryStatusSnapshot,
} from "@/features/agents/state/runtimeEventBridge";
import {
buildAgentMainSessionKey,
GatewayClient,
isGatewayDisconnectLikeError,
} from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import { buildOfficePresenceSnapshotFromGateway } from "@/lib/office/gatewayPresence";
import type { OfficePresenceSnapshot } from "@/lib/office/presence";
+4 -2
View File
@@ -17,11 +17,13 @@ import { GatewayConnectScreen } from "@/features/agents/components/GatewayConnec
import { useAgentStore, type AgentState } from "@/features/agents/state/store";
import {
GatewayClient,
buildAgentMainSessionKey,
type EventFrame,
isSameSessionKey,
parseAgentIdFromSessionKey,
} from "@/lib/gateway/GatewayClient";
import {
buildAgentMainSessionKey,
parseAgentIdFromSessionKey,
} from "@/lib/gateway/sessionKeys";
import { useRuntimeConnection } from "@/lib/runtime/useRuntimeConnection";
import {
createStudioSettingsCoordinator,
@@ -32,11 +32,11 @@ import {
type CronJobSummary,
} from "@/lib/cron/types";
import {
parseAgentIdFromSessionKey,
type EventFrame,
type GatewayClient,
type GatewayStatus,
} from "@/lib/gateway/GatewayClient";
import { parseAgentIdFromSessionKey } from "@/lib/gateway/sessionKeys";
import {
resolveTaskBoardPreference,
type StudioTaskBoardPreference,
+4 -14
View File
@@ -3,7 +3,6 @@
import { useCallback, useEffect, useRef, useState } from "react";
import {
GatewayBrowserClient,
clearGatewayBrowserSessionStorage,
type GatewayHelloOk,
} from "./openclaw/GatewayBrowserClient";
import type {
@@ -34,6 +33,10 @@ const gatewayDebugLog = (message: string, details?: Record<string, unknown>) =>
console.info("[gateway-client]", message);
};
import { probeCustomRuntime } from "@/lib/runtime/custom/http";
export {
buildAgentMainSessionKey,
parseAgentIdFromSessionKey,
} from "@/lib/gateway/sessionKeys";
export type ReqFrame = {
type: "req";
@@ -79,17 +82,6 @@ export const parseGatewayFrame = (raw: string): GatewayFrame | null => {
}
};
export const buildAgentMainSessionKey = (agentId: string, mainKey: string) => {
const trimmedAgent = agentId.trim();
const trimmedKey = mainKey.trim() || "main";
return `agent:${trimmedAgent}:${trimmedKey}`;
};
export const parseAgentIdFromSessionKey = (sessionKey: string): string | null => {
const match = sessionKey.match(/^agent:([^:]+):/);
return match ? match[1] : null;
};
export const isSameSessionKey = (a: string, b: string) => {
const left = a.trim();
const right = b.trim();
@@ -1181,7 +1173,6 @@ export const useGatewayConnection = (
return;
}
client.disconnect();
clearGatewayBrowserSessionStorage();
}, [client, selectedAdapterType]);
const clearError = useCallback(() => {
@@ -1198,7 +1189,6 @@ export const useGatewayConnection = (
(selectedAdapterType === "custom" ||
!hasLastKnownGoodState ||
!gatewayUrl.trim() ||
(selectedAdapterType === "openclaw" && !token.trim()) ||
wasManualDisconnectRef.current ||
Boolean(error));
+2 -1
View File
@@ -1,4 +1,5 @@
import { GatewayResponseError, type GatewayClient } from "@/lib/gateway/GatewayClient";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import { GatewayResponseError } from "@/lib/gateway/errors";
export type AgentHeartbeatActiveHours = {
start: string;
+9 -6
View File
@@ -1,6 +1,7 @@
import { createHash, randomUUID } from "node:crypto";
import { getPublicKeyAsync, signAsync, utils } from "@noble/ed25519";
import { GatewayResponseError } from "@/lib/gateway/errors";
export { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
type GatewayResponseFrame = {
type: "res";
@@ -172,12 +173,6 @@ const withTimeout = async <T>(
}
};
export const buildAgentMainSessionKey = (agentId: string, mainKey: string) => {
const trimmedAgent = agentId.trim();
const trimmedKey = mainKey.trim() || "main";
return `agent:${trimmedAgent}:${trimmedKey}`;
};
export class NodeGatewayClient {
private socket: WebSocket | null = null;
private pending = new Map<string, PendingRequest>();
@@ -365,6 +360,10 @@ export class NodeGatewayClient {
return response;
}
async call<T = unknown>(method: string, params: unknown): Promise<T> {
return this.request<T>(method, params);
}
close() {
this.closed = true;
this.rejectAllPending(new Error("Remote gateway client closed."));
@@ -377,6 +376,10 @@ export class NodeGatewayClient {
}
}
disconnect() {
this.close();
}
private rejectAllPending(error: Error) {
const entries = [...this.pending.values()];
this.pending.clear();
+10
View File
@@ -0,0 +1,10 @@
export const buildAgentMainSessionKey = (agentId: string, mainKey: string) => {
const trimmedAgent = agentId.trim();
const trimmedKey = mainKey.trim() || "main";
return `agent:${trimmedAgent}:${trimmedKey}`;
};
export const parseAgentIdFromSessionKey = (sessionKey: string): string | null => {
const match = sessionKey.match(/^agent:([^:]+):/);
return match ? match[1] : null;
};
+1 -1
View File
@@ -16,8 +16,8 @@ import {
import type { EventFrame } from "@/lib/gateway/GatewayClient";
import {
isSameSessionKey,
parseAgentIdFromSessionKey,
} from "@/lib/gateway/GatewayClient";
import { parseAgentIdFromSessionKey } from "@/lib/gateway/sessionKeys";
import type {
OfficeCleaningCue,
SessionEpochSnapshot,
+1 -1
View File
@@ -2,7 +2,7 @@ import type {
SummaryPreviewSnapshot,
SummaryStatusSnapshot,
} from "@/features/agents/state/runtimeEventBridge";
import { buildAgentMainSessionKey } from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import type { OfficeAgentPresence, OfficePresenceSnapshot } from "@/lib/office/presence";
type GatewayAgentsListEntry = {
+12 -6
View File
@@ -1,4 +1,5 @@
import { buildAgentMainSessionKey, type GatewayClient } from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import {
createGatewayAgent,
removeGatewayAgentFromConfigOnly,
@@ -12,6 +13,10 @@ import type {
const PICTURE_MODEL_AGENT_NAME = "Picture Modeler";
export const MAX_PICTURE_MODEL_UPLOAD_BYTES = 12 * 1024 * 1024;
type GatewayLikeClient = {
call<T = unknown>(method: string, params: unknown): Promise<T>;
};
const isRecord = (value: unknown): value is Record<string, unknown> =>
Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -26,7 +31,7 @@ const resolveRunId = (payload: unknown): string => {
return runId;
};
const resolveMainKey = async (client: GatewayClient): Promise<string> => {
const resolveMainKey = async (client: GatewayLikeClient): Promise<string> => {
const result = (await client.call("agents.list", {})) as { mainKey?: unknown };
return typeof result?.mainKey === "string" && result.mainKey.trim()
? result.mainKey.trim()
@@ -227,7 +232,7 @@ const parseRecipeFromHistory = (
};
export const generatePictureModelViaGateway = async (params: {
client: GatewayClient;
client: GatewayLikeClient;
summary: {
fileName: string;
aspectRatio: number;
@@ -239,15 +244,16 @@ export const generatePictureModelViaGateway = async (params: {
};
}): Promise<Picture3dRecipe> => {
let helperAgentId: string | null = null;
const configClient = params.client as unknown as GatewayClient;
try {
const created = await createGatewayAgent({
client: params.client,
client: configClient,
name: `${PICTURE_MODEL_AGENT_NAME} ${Date.now()}`,
});
helperAgentId = created.id;
await updateGatewayAgentOverrides({
client: params.client,
client: configClient,
agentId: helperAgentId,
overrides: {
tools: {
@@ -276,7 +282,7 @@ export const generatePictureModelViaGateway = async (params: {
if (helperAgentId) {
try {
await removeGatewayAgentFromConfigOnly({
client: params.client,
client: configClient,
agentId: helperAgentId,
});
} catch {
+1 -4
View File
@@ -5,10 +5,7 @@ import type {
GatewayStatus,
} from "@/lib/gateway/GatewayClient";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import {
buildAgentMainSessionKey,
parseAgentIdFromSessionKey,
} from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey, parseAgentIdFromSessionKey } from "@/lib/gateway/sessionKeys";
import {
fetchCustomRuntimeJson,
normalizeCustomBaseUrl,
+2 -1
View File
@@ -1,4 +1,5 @@
import { buildAgentMainSessionKey, type GatewayClient } from "@/lib/gateway/GatewayClient";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import {
removeGatewayAgentFromConfigOnly,
updateGatewayAgentOverrides,
+2 -1
View File
@@ -1,4 +1,5 @@
import { buildAgentMainSessionKey, type GatewayClient } from "@/lib/gateway/GatewayClient";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import { buildAgentMainSessionKey } from "@/lib/gateway/sessionKeys";
import {
removeGatewayAgentFromConfigOnly,
updateGatewayAgentOverrides,
+6 -6
View File
@@ -1,16 +1,16 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const connectMock = vi.fn(async function connect() {});
const disconnectMock = vi.fn(function disconnect() {});
const gatewayClientCtorMock = vi.fn(function GatewayClientMock(
const closeMock = vi.fn(function close() {});
const gatewayClientCtorMock = vi.fn(function NodeGatewayClientMock(
this: Record<string, unknown>,
) {
this.connect = connectMock;
this.disconnect = disconnectMock;
this.close = closeMock;
});
vi.mock("@/lib/gateway/GatewayClient", () => ({
GatewayClient: gatewayClientCtorMock,
vi.mock("@/lib/gateway/nodeGatewayClient", () => ({
NodeGatewayClient: gatewayClientCtorMock,
}));
vi.mock("@/lib/office/pictureModelGeneration", () => ({
@@ -164,7 +164,7 @@ describe("POST /api/office/picture-model", () => {
expect(gatewayClientCtorMock).toHaveBeenCalledTimes(1);
expect(connectMock).toHaveBeenCalledTimes(1);
expect(disconnectMock).toHaveBeenCalledTimes(1);
expect(closeMock).toHaveBeenCalledTimes(1);
expect(response.status).toBe(200);
await expect(response.json()).resolves.toMatchObject({
fileName: "demo.png",
+60
View File
@@ -78,6 +78,7 @@ const setupAndImportHook = async (gatewayUrl: string | null) => {
schedulePatch: (patch: unknown) => void;
flushPending: () => Promise<void>;
}) => {
status: "disconnected" | "connecting" | "connected";
gatewayUrl: string;
token: string;
selectedAdapterType: "openclaw" | "hermes" | "demo" | "custom";
@@ -242,6 +243,65 @@ describe("useGatewayConnection", () => {
expect(captured.clientName).toBe("webchat-ui");
});
it("auto_reconnects_openclaw_with_last_known_good_without_a_browser_token", async () => {
const { useGatewayConnection, captured } = await setupAndImportHook(null);
const coordinator = {
loadSettings: async () => null,
loadSettingsEnvelope: async () => ({
settings: {
version: 1,
gateway: {
url: "wss://pi5.myth-coho.ts.net",
token: "",
adapterType: "openclaw",
lastKnownGood: {
url: "wss://pi5.myth-coho.ts.net",
token: "",
adapterType: "openclaw",
},
},
focused: {},
avatars: {},
analytics: {},
voiceReplies: {},
office: {},
deskAssignments: {},
standup: {},
taskBoard: {},
},
localGatewayDefaults: null,
}),
schedulePatch: () => {},
flushPending: async () => {},
};
const Probe = () => {
const state = useGatewayConnection(coordinator);
return createElement(
"div",
null,
createElement("div", { "data-testid": "status" }, state.status),
createElement("div", { "data-testid": "token" }, state.token),
createElement(
"div",
{ "data-testid": "shouldPromptForConnect" },
state.shouldPromptForConnect ? "yes" : "no"
)
);
};
render(createElement(Probe));
await waitFor(() => {
expect(captured.url).toBe("ws://localhost:3000/api/gateway/ws");
});
await waitFor(() => {
expect(screen.getByTestId("status")).toHaveTextContent("connected");
});
expect(screen.getByTestId("token")).toHaveTextContent("");
expect(screen.getByTestId("shouldPromptForConnect")).toHaveTextContent("no");
});
it("keeps_control_ui_identity_for_local_openclaw_connections", async () => {
const { useGatewayConnection, captured } = await setupAndImportHook(null);
const coordinator = {