feat(09-01): install @libsql/client, schema, DB init, path helpers
- Install @libsql/client@^0.17.2 to server package - Create skill-registry-schema.ts with 4 sqliteTable definitions (skills, skillVersions, skillFiles, communityRatings) - Create skill-registry-db.ts with lazy singleton getSkillRegistryDb() and resetSkillRegistryDb() - Add resolveSkillRegistryDbPath() and resolveSkillCacheDir() to home-paths.ts - Add skill-registry-schema.test.ts with 8 passing tests (TDD green)
This commit is contained in:
parent
2e584fde19
commit
cf58f09085
6 changed files with 514 additions and 7 deletions
264
pnpm-lock.yaml
generated
264
pnpm-lock.yaml
generated
|
|
@ -78,7 +78,7 @@ importers:
|
|||
version: 17.3.1
|
||||
drizzle-orm:
|
||||
specifier: 0.38.4
|
||||
version: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
version: 0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
embedded-postgres:
|
||||
specifier: ^18.1.0-beta.16
|
||||
version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei)
|
||||
|
|
@ -236,7 +236,7 @@ importers:
|
|||
version: link:../shared
|
||||
drizzle-orm:
|
||||
specifier: ^0.38.4
|
||||
version: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
version: 0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
embedded-postgres:
|
||||
specifier: ^18.1.0-beta.16
|
||||
version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei)
|
||||
|
|
@ -449,6 +449,9 @@ importers:
|
|||
'@aws-sdk/client-s3':
|
||||
specifier: ^3.888.0
|
||||
version: 3.994.0
|
||||
'@libsql/client':
|
||||
specifier: ^0.17.2
|
||||
version: 0.17.2
|
||||
'@paperclipai/adapter-claude-local':
|
||||
specifier: workspace:*
|
||||
version: link:../packages/adapters/claude-local
|
||||
|
|
@ -490,7 +493,7 @@ importers:
|
|||
version: 3.0.1(ajv@8.18.0)
|
||||
better-auth:
|
||||
specifier: 1.4.18
|
||||
version: 1.4.18(drizzle-kit@0.31.9)(drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4))(pg@8.18.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@2.0.1))(lightningcss@1.30.2)(tsx@4.21.0))
|
||||
version: 1.4.18(drizzle-kit@0.31.9)(drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4))(pg@8.18.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@2.0.1))(lightningcss@1.30.2)(tsx@4.21.0))
|
||||
chokidar:
|
||||
specifier: ^4.0.3
|
||||
version: 4.0.3
|
||||
|
|
@ -505,7 +508,7 @@ importers:
|
|||
version: 17.3.1
|
||||
drizzle-orm:
|
||||
specifier: ^0.38.4
|
||||
version: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
version: 0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
embedded-postgres:
|
||||
specifier: ^18.1.0-beta.16
|
||||
version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei)
|
||||
|
|
@ -2020,6 +2023,63 @@ packages:
|
|||
'@lezer/yaml@1.0.4':
|
||||
resolution: {integrity: sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==}
|
||||
|
||||
'@libsql/client@0.17.2':
|
||||
resolution: {integrity: sha512-0aw0S3iQMHvOxfRt5j1atoCCPMT3gjsB2PS8/uxSM1DcDn39xqz6RlgSMxtP8I3JsxIXAFuw7S41baLEw0Zi+Q==}
|
||||
|
||||
'@libsql/core@0.17.2':
|
||||
resolution: {integrity: sha512-L8qv12HZ/jRBcETVR3rscP0uHNxh+K3EABSde6scCw7zfOdiLqO3MAkJaeE1WovPsjXzsN/JBoZED4+7EZVT3g==}
|
||||
|
||||
'@libsql/darwin-arm64@0.5.29':
|
||||
resolution: {integrity: sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@libsql/darwin-x64@0.5.29':
|
||||
resolution: {integrity: sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@libsql/hrana-client@0.9.0':
|
||||
resolution: {integrity: sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw==}
|
||||
|
||||
'@libsql/isomorphic-ws@0.1.5':
|
||||
resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==}
|
||||
|
||||
'@libsql/linux-arm-gnueabihf@0.5.29':
|
||||
resolution: {integrity: sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@libsql/linux-arm-musleabihf@0.5.29':
|
||||
resolution: {integrity: sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@libsql/linux-arm64-gnu@0.5.29':
|
||||
resolution: {integrity: sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@libsql/linux-arm64-musl@0.5.29':
|
||||
resolution: {integrity: sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@libsql/linux-x64-gnu@0.5.29':
|
||||
resolution: {integrity: sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@libsql/linux-x64-musl@0.5.29':
|
||||
resolution: {integrity: sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@libsql/win32-x64-msvc@0.5.29':
|
||||
resolution: {integrity: sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@marijn/find-cluster-break@1.0.2':
|
||||
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
|
||||
|
||||
|
|
@ -2040,6 +2100,9 @@ packages:
|
|||
'@mermaid-js/parser@1.0.0':
|
||||
resolution: {integrity: sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==}
|
||||
|
||||
'@neon-rs/load@0.0.4':
|
||||
resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==}
|
||||
|
||||
'@noble/ciphers@2.1.1':
|
||||
resolution: {integrity: sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==}
|
||||
engines: {node: '>= 20.19.0'}
|
||||
|
|
@ -3856,6 +3919,9 @@ packages:
|
|||
engines: {node: '>=20'}
|
||||
hasBin: true
|
||||
|
||||
cross-fetch@4.1.0:
|
||||
resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
|
@ -4036,6 +4102,10 @@ packages:
|
|||
dagre-d3-es@7.0.13:
|
||||
resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==}
|
||||
|
||||
data-uri-to-buffer@4.0.1:
|
||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
data-urls@7.0.0:
|
||||
resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
|
|
@ -4099,6 +4169,10 @@ packages:
|
|||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
detect-libc@2.0.2:
|
||||
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
detect-libc@2.1.2:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -4392,6 +4466,10 @@ packages:
|
|||
picomatch:
|
||||
optional: true
|
||||
|
||||
fetch-blob@3.2.0:
|
||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||
engines: {node: ^12.20 || >= 14.13}
|
||||
|
||||
finalhandler@2.1.1:
|
||||
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
|
||||
engines: {node: '>= 18.0.0'}
|
||||
|
|
@ -4404,6 +4482,10 @@ packages:
|
|||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
formidable@3.5.4:
|
||||
resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
|
@ -4602,6 +4684,9 @@ packages:
|
|||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
js-base64@3.7.8:
|
||||
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
|
||||
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
|
|
@ -4667,6 +4752,11 @@ packages:
|
|||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
|
||||
libsql@0.5.29:
|
||||
resolution: {integrity: sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg==}
|
||||
cpu: [x64, arm64, wasm32, arm]
|
||||
os: [darwin, linux, win32]
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
|
@ -5032,6 +5122,24 @@ packages:
|
|||
next-tick@1.1.0:
|
||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
deprecated: Use your platform's native DOMException instead
|
||||
|
||||
node-fetch@2.7.0:
|
||||
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
|
||||
node-fetch@3.3.2:
|
||||
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
node-releases@2.0.27:
|
||||
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
|
||||
|
||||
|
|
@ -5216,6 +5324,9 @@ packages:
|
|||
process-warning@5.0.0:
|
||||
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
|
||||
|
||||
promise-limit@2.7.0:
|
||||
resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
|
||||
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
|
|
@ -5631,6 +5742,9 @@ packages:
|
|||
resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
|
||||
tr46@6.0.0:
|
||||
resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
|
||||
engines: {node: '>=20'}
|
||||
|
|
@ -5909,6 +6023,13 @@ packages:
|
|||
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
web-streams-polyfill@3.3.3:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
|
||||
webidl-conversions@8.0.1:
|
||||
resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
|
@ -5921,6 +6042,9 @@ packages:
|
|||
resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
|
@ -7668,6 +7792,68 @@ snapshots:
|
|||
'@lezer/highlight': 1.2.3
|
||||
'@lezer/lr': 1.4.8
|
||||
|
||||
'@libsql/client@0.17.2':
|
||||
dependencies:
|
||||
'@libsql/core': 0.17.2
|
||||
'@libsql/hrana-client': 0.9.0
|
||||
js-base64: 3.7.8
|
||||
libsql: 0.5.29
|
||||
promise-limit: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- encoding
|
||||
- utf-8-validate
|
||||
|
||||
'@libsql/core@0.17.2':
|
||||
dependencies:
|
||||
js-base64: 3.7.8
|
||||
|
||||
'@libsql/darwin-arm64@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/darwin-x64@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/hrana-client@0.9.0':
|
||||
dependencies:
|
||||
'@libsql/isomorphic-ws': 0.1.5
|
||||
cross-fetch: 4.1.0
|
||||
js-base64: 3.7.8
|
||||
node-fetch: 3.3.2
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- encoding
|
||||
- utf-8-validate
|
||||
|
||||
'@libsql/isomorphic-ws@0.1.5':
|
||||
dependencies:
|
||||
'@types/ws': 8.18.1
|
||||
ws: 8.19.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@libsql/linux-arm-gnueabihf@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/linux-arm-musleabihf@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/linux-arm64-gnu@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/linux-arm64-musl@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/linux-x64-gnu@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/linux-x64-musl@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@libsql/win32-x64-msvc@0.5.29':
|
||||
optional: true
|
||||
|
||||
'@marijn/find-cluster-break@1.0.2': {}
|
||||
|
||||
'@mdxeditor/editor@3.52.4(@codemirror/language@6.12.1)(@lezer/highlight@1.2.3)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yjs@13.6.29)':
|
||||
|
|
@ -7747,6 +7933,8 @@ snapshots:
|
|||
dependencies:
|
||||
langium: 4.2.1
|
||||
|
||||
'@neon-rs/load@0.0.4': {}
|
||||
|
||||
'@noble/ciphers@2.1.1': {}
|
||||
|
||||
'@noble/hashes@1.8.0': {}
|
||||
|
|
@ -9449,7 +9637,7 @@ snapshots:
|
|||
|
||||
baseline-browser-mapping@2.9.19: {}
|
||||
|
||||
better-auth@1.4.18(drizzle-kit@0.31.9)(drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4))(pg@8.18.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@2.0.1))(lightningcss@1.30.2)(tsx@4.21.0)):
|
||||
better-auth@1.4.18(drizzle-kit@0.31.9)(drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4))(pg@8.18.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@2.0.1))(lightningcss@1.30.2)(tsx@4.21.0)):
|
||||
dependencies:
|
||||
'@better-auth/core': 1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@3.25.76))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)
|
||||
'@better-auth/telemetry': 1.4.18(@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@3.25.76))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0))
|
||||
|
|
@ -9465,7 +9653,7 @@ snapshots:
|
|||
zod: 4.3.6
|
||||
optionalDependencies:
|
||||
drizzle-kit: 0.31.9
|
||||
drizzle-orm: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
drizzle-orm: 0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4)
|
||||
pg: 8.18.0
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
|
@ -9672,6 +9860,12 @@ snapshots:
|
|||
'@epic-web/invariant': 1.0.0
|
||||
cross-spawn: 7.0.6
|
||||
|
||||
cross-fetch@4.1.0:
|
||||
dependencies:
|
||||
node-fetch: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
|
|
@ -9883,6 +10077,8 @@ snapshots:
|
|||
d3: 7.9.0
|
||||
lodash-es: 4.17.23
|
||||
|
||||
data-uri-to-buffer@4.0.1: {}
|
||||
|
||||
data-urls@7.0.0(@noble/hashes@2.0.1):
|
||||
dependencies:
|
||||
whatwg-mimetype: 5.0.0
|
||||
|
|
@ -9929,6 +10125,8 @@ snapshots:
|
|||
|
||||
dequal@2.0.3: {}
|
||||
|
||||
detect-libc@2.0.2: {}
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
detect-node-es@1.1.0: {}
|
||||
|
|
@ -9974,9 +10172,10 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4):
|
||||
drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@libsql/client@0.17.2)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4):
|
||||
optionalDependencies:
|
||||
'@electric-sql/pglite': 0.3.15
|
||||
'@libsql/client': 0.17.2
|
||||
'@types/react': 19.2.14
|
||||
kysely: 0.28.11
|
||||
pg: 8.18.0
|
||||
|
|
@ -10243,6 +10442,11 @@ snapshots:
|
|||
optionalDependencies:
|
||||
picomatch: 4.0.3
|
||||
|
||||
fetch-blob@3.2.0:
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 3.3.3
|
||||
|
||||
finalhandler@2.1.1:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
|
|
@ -10264,6 +10468,10 @@ snapshots:
|
|||
|
||||
format@0.2.2: {}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
|
||||
formidable@3.5.4:
|
||||
dependencies:
|
||||
'@paralleldrive/cuid2': 2.3.1
|
||||
|
|
@ -10454,6 +10662,8 @@ snapshots:
|
|||
|
||||
joycon@3.1.1: {}
|
||||
|
||||
js-base64@3.7.8: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-tokens@9.0.1: {}
|
||||
|
|
@ -10523,6 +10733,21 @@ snapshots:
|
|||
dependencies:
|
||||
isomorphic.js: 0.2.5
|
||||
|
||||
libsql@0.5.29:
|
||||
dependencies:
|
||||
'@neon-rs/load': 0.0.4
|
||||
detect-libc: 2.0.2
|
||||
optionalDependencies:
|
||||
'@libsql/darwin-arm64': 0.5.29
|
||||
'@libsql/darwin-x64': 0.5.29
|
||||
'@libsql/linux-arm-gnueabihf': 0.5.29
|
||||
'@libsql/linux-arm-musleabihf': 0.5.29
|
||||
'@libsql/linux-arm64-gnu': 0.5.29
|
||||
'@libsql/linux-arm64-musl': 0.5.29
|
||||
'@libsql/linux-x64-gnu': 0.5.29
|
||||
'@libsql/linux-x64-musl': 0.5.29
|
||||
'@libsql/win32-x64-msvc': 0.5.29
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
optional: true
|
||||
|
||||
|
|
@ -11168,6 +11393,18 @@ snapshots:
|
|||
|
||||
next-tick@1.1.0: {}
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
node-fetch@3.3.2:
|
||||
dependencies:
|
||||
data-uri-to-buffer: 4.0.1
|
||||
fetch-blob: 3.2.0
|
||||
formdata-polyfill: 4.0.10
|
||||
|
||||
node-releases@2.0.27: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
|
@ -11365,6 +11602,8 @@ snapshots:
|
|||
|
||||
process-warning@5.0.0: {}
|
||||
|
||||
promise-limit@2.7.0: {}
|
||||
|
||||
prop-types@15.8.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
|
@ -11908,6 +12147,8 @@ snapshots:
|
|||
dependencies:
|
||||
tldts: 7.0.26
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
tr46@6.0.0:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
|
@ -12256,6 +12497,10 @@ snapshots:
|
|||
dependencies:
|
||||
xml-name-validator: 5.0.0
|
||||
|
||||
web-streams-polyfill@3.3.3: {}
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
webidl-conversions@8.0.1: {}
|
||||
|
||||
whatwg-mimetype@5.0.0: {}
|
||||
|
|
@ -12268,6 +12513,11 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- '@noble/hashes'
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.888.0",
|
||||
"@libsql/client": "^0.17.2",
|
||||
"@paperclipai/adapter-claude-local": "workspace:*",
|
||||
"@paperclipai/adapter-codex-local": "workspace:*",
|
||||
"@paperclipai/adapter-cursor-local": "workspace:*",
|
||||
|
|
|
|||
136
server/src/__tests__/skill-registry-schema.test.ts
Normal file
136
server/src/__tests__/skill-registry-schema.test.ts
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
import { mkdtemp, rm } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
|
||||
// We reset the singleton between tests by calling resetSkillRegistryDb
|
||||
// and redirecting PAPERCLIP_HOME to an isolated temp dir
|
||||
|
||||
describe("skill-registry-schema", () => {
|
||||
let tmpDir: string;
|
||||
let originalPaperclipHome: string | undefined;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = await mkdtemp(path.join(os.tmpdir(), "skill-registry-test-"));
|
||||
originalPaperclipHome = process.env.PAPERCLIP_HOME;
|
||||
process.env.PAPERCLIP_HOME = tmpDir;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Reset the DB singleton so next test gets a fresh instance
|
||||
const { resetSkillRegistryDb } = await import("../services/skill-registry-db.js");
|
||||
resetSkillRegistryDb();
|
||||
|
||||
if (originalPaperclipHome === undefined) {
|
||||
delete process.env.PAPERCLIP_HOME;
|
||||
} else {
|
||||
process.env.PAPERCLIP_HOME = originalPaperclipHome;
|
||||
}
|
||||
await rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("Test 1: getSkillRegistryDb() creates registry.db at the resolved path and returns a drizzle instance", async () => {
|
||||
const { getSkillRegistryDb } = await import("../services/skill-registry-db.js");
|
||||
const db = await getSkillRegistryDb();
|
||||
expect(db).toBeDefined();
|
||||
expect(typeof db.select).toBe("function");
|
||||
expect(typeof db.insert).toBe("function");
|
||||
});
|
||||
|
||||
it("Test 2: skills table has correct columns", async () => {
|
||||
const { skills } = await import("../services/skill-registry-schema.js");
|
||||
const cols = Object.keys(skills);
|
||||
// Check the table has the expected name
|
||||
expect((skills as any)[Symbol.for("drizzle:Name") as any] ?? skills._.name).toBeDefined();
|
||||
const colNames = Object.keys(skills);
|
||||
// Drizzle table object has column accessors
|
||||
expect(skills.id).toBeDefined();
|
||||
expect(skills.sourceId).toBeDefined();
|
||||
expect(skills.name).toBeDefined();
|
||||
expect(skills.description).toBeDefined();
|
||||
expect(skills.sourceUrl).toBeDefined();
|
||||
expect(skills.activeVersionId).toBeDefined();
|
||||
expect(skills.removedAt).toBeDefined();
|
||||
expect(skills.createdAt).toBeDefined();
|
||||
expect(skills.updatedAt).toBeDefined();
|
||||
});
|
||||
|
||||
it("Test 3: skill_versions table has correct columns", async () => {
|
||||
const { skillVersions } = await import("../services/skill-registry-schema.js");
|
||||
expect(skillVersions.id).toBeDefined();
|
||||
expect(skillVersions.skillId).toBeDefined();
|
||||
expect(skillVersions.version).toBeDefined();
|
||||
expect(skillVersions.fetchedAt).toBeDefined();
|
||||
expect(skillVersions.cacheDir).toBeDefined();
|
||||
});
|
||||
|
||||
it("Test 4: skill_files table has correct columns", async () => {
|
||||
const { skillFiles } = await import("../services/skill-registry-schema.js");
|
||||
expect(skillFiles.id).toBeDefined();
|
||||
expect(skillFiles.versionId).toBeDefined();
|
||||
expect(skillFiles.path).toBeDefined();
|
||||
expect(skillFiles.kind).toBeDefined();
|
||||
expect(skillFiles.sizeBytes).toBeDefined();
|
||||
});
|
||||
|
||||
it("Test 5: community_ratings table has correct columns", async () => {
|
||||
const { communityRatings } = await import("../services/skill-registry-schema.js");
|
||||
expect(communityRatings.id).toBeDefined();
|
||||
expect(communityRatings.skillId).toBeDefined();
|
||||
expect(communityRatings.fetchedAt).toBeDefined();
|
||||
expect(communityRatings.averageRating).toBeDefined();
|
||||
expect(communityRatings.ratingCount).toBeDefined();
|
||||
expect(communityRatings.source).toBeDefined();
|
||||
});
|
||||
|
||||
it("Test 6: soft-delete — inserting a skill and setting removed_at keeps the row queryable with a WHERE filter", async () => {
|
||||
const { getSkillRegistryDb } = await import("../services/skill-registry-db.js");
|
||||
const { skills } = await import("../services/skill-registry-schema.js");
|
||||
const { eq, isNull, isNotNull } = await import("drizzle-orm");
|
||||
|
||||
const db = await getSkillRegistryDb();
|
||||
const now = Date.now();
|
||||
|
||||
await db.insert(skills).values({
|
||||
id: "test-skill-1",
|
||||
sourceId: "src-1",
|
||||
name: "Test Skill",
|
||||
description: "A test skill",
|
||||
sourceUrl: null,
|
||||
activeVersionId: null,
|
||||
removedAt: null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
||||
// Before soft-delete: row is visible
|
||||
const before = await db.select().from(skills).where(isNull(skills.removedAt));
|
||||
expect(before.length).toBe(1);
|
||||
|
||||
// Apply soft-delete
|
||||
await db.update(skills).set({ removedAt: now + 1000 }).where(eq(skills.id, "test-skill-1"));
|
||||
|
||||
// After soft-delete: not visible via active filter
|
||||
const activeAfter = await db.select().from(skills).where(isNull(skills.removedAt));
|
||||
expect(activeAfter.length).toBe(0);
|
||||
|
||||
// But still visible via removed filter
|
||||
const removedAfter = await db.select().from(skills).where(isNotNull(skills.removedAt));
|
||||
expect(removedAfter.length).toBe(1);
|
||||
expect(removedAfter[0]!.id).toBe("test-skill-1");
|
||||
});
|
||||
|
||||
it("Test 7: resolveSkillRegistryDbPath() returns path ending in skills/registry.db under instance root", async () => {
|
||||
const { resolveSkillRegistryDbPath } = await import("../home-paths.js");
|
||||
const dbPath = resolveSkillRegistryDbPath();
|
||||
expect(dbPath).toMatch(/skills[/\\]registry\.db$/);
|
||||
expect(dbPath.startsWith(tmpDir)).toBe(true);
|
||||
});
|
||||
|
||||
it("Test 8: resolveSkillCacheDir returns path ending in skills/cache/<skillId>/<versionId>", async () => {
|
||||
const { resolveSkillCacheDir } = await import("../home-paths.js");
|
||||
const cacheDir = resolveSkillCacheDir("my-skill", "abc123");
|
||||
expect(cacheDir).toMatch(/skills[/\\]cache[/\\]my-skill[/\\]abc123$/);
|
||||
expect(cacheDir.startsWith(tmpDir)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -113,3 +113,12 @@ export function resolveManagedProjectWorkspaceDir(input: {
|
|||
export function resolveHomeAwarePath(value: string): string {
|
||||
return path.resolve(expandHomePrefix(value));
|
||||
}
|
||||
|
||||
// [nexus] Skill registry paths
|
||||
export function resolveSkillRegistryDbPath(): string {
|
||||
return path.resolve(resolvePaperclipInstanceRoot(), "skills", "registry.db");
|
||||
}
|
||||
|
||||
export function resolveSkillCacheDir(skillId: string, versionId: string): string {
|
||||
return path.resolve(resolvePaperclipInstanceRoot(), "skills", "cache", skillId, versionId);
|
||||
}
|
||||
|
|
|
|||
73
server/src/services/skill-registry-db.ts
Normal file
73
server/src/services/skill-registry-db.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { mkdir } from "node:fs/promises";
|
||||
import { dirname } from "node:path";
|
||||
import { drizzle } from "drizzle-orm/libsql";
|
||||
import { createClient } from "@libsql/client";
|
||||
import * as schema from "./skill-registry-schema.js";
|
||||
import { resolveSkillRegistryDbPath } from "../home-paths.js";
|
||||
|
||||
export type SkillRegistryDb = ReturnType<typeof drizzle<typeof schema>>;
|
||||
|
||||
let _db: SkillRegistryDb | null = null;
|
||||
|
||||
const CREATE_SKILLS_TABLE = `
|
||||
CREATE TABLE IF NOT EXISTS skills (
|
||||
id TEXT PRIMARY KEY,
|
||||
source_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
source_url TEXT,
|
||||
active_version_id TEXT,
|
||||
removed_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)`;
|
||||
|
||||
const CREATE_SKILL_VERSIONS_TABLE = `
|
||||
CREATE TABLE IF NOT EXISTS skill_versions (
|
||||
id TEXT PRIMARY KEY,
|
||||
skill_id TEXT NOT NULL,
|
||||
version TEXT NOT NULL,
|
||||
fetched_at INTEGER NOT NULL,
|
||||
cache_dir TEXT
|
||||
)`;
|
||||
|
||||
const CREATE_SKILL_FILES_TABLE = `
|
||||
CREATE TABLE IF NOT EXISTS skill_files (
|
||||
id TEXT PRIMARY KEY,
|
||||
version_id TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
size_bytes INTEGER
|
||||
)`;
|
||||
|
||||
const CREATE_COMMUNITY_RATINGS_TABLE = `
|
||||
CREATE TABLE IF NOT EXISTS community_ratings (
|
||||
id TEXT PRIMARY KEY,
|
||||
skill_id TEXT NOT NULL,
|
||||
fetched_at INTEGER NOT NULL,
|
||||
average_rating REAL,
|
||||
rating_count INTEGER,
|
||||
source TEXT
|
||||
)`;
|
||||
|
||||
export async function getSkillRegistryDb(): Promise<SkillRegistryDb> {
|
||||
if (_db !== null) return _db;
|
||||
|
||||
const dbPath = resolveSkillRegistryDbPath();
|
||||
await mkdir(dirname(dbPath), { recursive: true });
|
||||
|
||||
const client = createClient({ url: `file:${dbPath}` });
|
||||
_db = drizzle({ client, schema });
|
||||
|
||||
await client.execute(CREATE_SKILLS_TABLE);
|
||||
await client.execute(CREATE_SKILL_VERSIONS_TABLE);
|
||||
await client.execute(CREATE_SKILL_FILES_TABLE);
|
||||
await client.execute(CREATE_COMMUNITY_RATINGS_TABLE);
|
||||
|
||||
return _db;
|
||||
}
|
||||
|
||||
/** Reset the singleton — used for test cleanup */
|
||||
export function resetSkillRegistryDb(): void {
|
||||
_db = null;
|
||||
}
|
||||
38
server/src/services/skill-registry-schema.ts
Normal file
38
server/src/services/skill-registry-schema.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { sqliteTable, text, integer, real } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const skills = sqliteTable("skills", {
|
||||
id: text("id").primaryKey(),
|
||||
sourceId: text("source_id").notNull(),
|
||||
name: text("name").notNull(),
|
||||
description: text("description"),
|
||||
sourceUrl: text("source_url"),
|
||||
activeVersionId: text("active_version_id"),
|
||||
removedAt: integer("removed_at"), // unix ms, nullable — soft-delete
|
||||
createdAt: integer("created_at").notNull(),
|
||||
updatedAt: integer("updated_at").notNull(),
|
||||
});
|
||||
|
||||
export const skillVersions = sqliteTable("skill_versions", {
|
||||
id: text("id").primaryKey(),
|
||||
skillId: text("skill_id").notNull(),
|
||||
version: text("version").notNull(),
|
||||
fetchedAt: integer("fetched_at").notNull(),
|
||||
cacheDir: text("cache_dir"),
|
||||
});
|
||||
|
||||
export const skillFiles = sqliteTable("skill_files", {
|
||||
id: text("id").primaryKey(),
|
||||
versionId: text("version_id").notNull(),
|
||||
path: text("path").notNull(),
|
||||
kind: text("kind").notNull(), // "skill" | "reference" | "script" | "asset"
|
||||
sizeBytes: integer("size_bytes"),
|
||||
});
|
||||
|
||||
export const communityRatings = sqliteTable("community_ratings", {
|
||||
id: text("id").primaryKey(),
|
||||
skillId: text("skill_id").notNull(),
|
||||
fetchedAt: integer("fetched_at").notNull(),
|
||||
averageRating: real("average_rating"),
|
||||
ratingCount: integer("rating_count"),
|
||||
source: text("source"),
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue