Compare commits
10 Commits
eac2e4e009
...
142d9ddf9b
| Author | SHA1 | Date | |
|---|---|---|---|
| 142d9ddf9b | |||
| e5904927eb | |||
| e4b0ebc3e1 | |||
|
|
3fc9bfad4a | ||
| 8f8c70e10e | |||
| 329550f44a | |||
|
|
881ed132c0 | ||
|
|
5d7f27e296 | ||
| f20e280b19 | |||
|
|
c6977cd760 |
289
bun.lock
289
bun.lock
|
|
@ -4,19 +4,15 @@
|
|||
"": {
|
||||
"name": "workshop",
|
||||
},
|
||||
"packages/attache": {
|
||||
"name": "attache",
|
||||
"packages/arg-completer": {
|
||||
"name": "@workshop/arg-completer",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@workshop/shared": "workspace:*",
|
||||
"hono": "catalog:",
|
||||
"nanoid": "^5.1.5",
|
||||
"hono": "^4.9.7",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/cubby": {
|
||||
"name": "cubby",
|
||||
|
|
@ -52,7 +48,9 @@
|
|||
"@workshop/shared": "workspace:*",
|
||||
"@workshop/todo": "workspace:*",
|
||||
"hono": "catalog:",
|
||||
"luxon": "catalog:",
|
||||
"tailwind": "^4.0.0",
|
||||
"zod": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
|
|
@ -86,6 +84,33 @@
|
|||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/nose-bbs": {
|
||||
"name": "nose-bbs",
|
||||
"dependencies": {
|
||||
"hono": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/phantasm": {
|
||||
"name": "@workshop/phantasm",
|
||||
"dependencies": {
|
||||
"hono": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"eslint": "^9.31.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^5.5.1",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/query": {
|
||||
"name": "@workshop/query",
|
||||
"dependencies": {
|
||||
|
|
@ -108,18 +133,29 @@
|
|||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/sneaker": {
|
||||
"name": "sneaker",
|
||||
"dependencies": {
|
||||
"hono": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/spike": {
|
||||
"name": "@workshop/spike",
|
||||
"dependencies": {
|
||||
"@openai/agents": "^0.0.10",
|
||||
"@workshop/shared": "workspace:*",
|
||||
"discord.js": "^14.19.3",
|
||||
"luxon": "^3.6.1",
|
||||
"luxon": "catalog:",
|
||||
"zod": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@types/luxon": "^3.6.2",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
|
|
@ -139,7 +175,7 @@
|
|||
"@lezer/lr": "^1.4.2",
|
||||
"@workshop/nano-remix": "workspace:*",
|
||||
"hono": "catalog:",
|
||||
"luxon": "^3.6.1",
|
||||
"luxon": "catalog:",
|
||||
"zzfx": "^1.3.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -149,6 +185,18 @@
|
|||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/truism": {
|
||||
"name": "truism",
|
||||
"dependencies": {
|
||||
"hono": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
"packages/werewolf-ui": {
|
||||
"name": "@workshop/werewolf-ui",
|
||||
"version": "0.1.0",
|
||||
|
|
@ -172,7 +220,7 @@
|
|||
"@workshop/nano-remix": "workspace:*",
|
||||
"@workshop/shared": "workspace:*",
|
||||
"hono": "catalog:",
|
||||
"luxon": "^3.7.1",
|
||||
"luxon": "catalog:",
|
||||
"pixabay-api": "^1.0.4",
|
||||
"pngjs": "^7.0.0",
|
||||
"tailwind": "^4.0.0",
|
||||
|
|
@ -185,6 +233,7 @@
|
|||
},
|
||||
"catalog": {
|
||||
"hono": "^4.8.0",
|
||||
"luxon": "^3.7.1",
|
||||
"zod": "3.25.67",
|
||||
},
|
||||
"packages": {
|
||||
|
|
@ -214,8 +263,34 @@
|
|||
|
||||
"@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="],
|
||||
|
||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
|
||||
|
||||
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
|
||||
|
||||
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
|
||||
|
||||
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
|
||||
|
||||
"@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
|
||||
|
||||
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
|
||||
|
||||
"@eslint/js": ["@eslint/js@9.36.0", "", {}, "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw=="],
|
||||
|
||||
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
|
||||
|
||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="],
|
||||
|
||||
"@google/genai": ["@google/genai@1.9.0", "", { "dependencies": { "google-auth-library": "^9.14.2", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.11.0" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-w9P93OXKPMs9H1mfAx9+p3zJqQGrWBGdvK/SVc7cLZEXNHr/3+vW2eif7ZShA6wU24rNLn9z9MK2vQFUvNRI2Q=="],
|
||||
|
||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||
|
||||
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
|
||||
|
||||
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
|
||||
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||
|
||||
"@lezer/common": ["@lezer/common@1.2.3", "", {}, "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="],
|
||||
|
||||
"@lezer/generator": ["@lezer/generator@1.8.0", "", { "dependencies": { "@lezer/common": "^1.1.0", "@lezer/lr": "^1.3.0" }, "bin": { "lezer-generator": "src/lezer-generator.cjs" } }, "sha512-/SF4EDWowPqV1jOgoGSGTIFsE7Ezdr7ZYxyihl5eMKVO5tlnpIhFcDavgm1hHY5GEonoOAEnJ0CU0x+tvuAuUg=="],
|
||||
|
|
@ -238,6 +313,8 @@
|
|||
|
||||
"@openai/zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="],
|
||||
|
||||
"@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
|
||||
|
||||
"@planetscale/database": ["@planetscale/database@1.19.0", "", {}, "sha512-Tv4jcFUFAFjOWrGSio49H6R2ijALv0ZzVBfJKIdm+kl9X046Fh4LLawrF9OMsglVbK6ukqMJsUCeucGAFTBcMA=="],
|
||||
|
||||
"@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="],
|
||||
|
|
@ -248,9 +325,11 @@
|
|||
|
||||
"@techstark/opencv-js": ["@techstark/opencv-js@4.11.0-release.1", "", {}, "sha512-d5h8cMiSbbnme5+I1ta4++EJ3mkca1zkVNh0A4+5ASJYOmO5OhVPRX3oPnNzs9I3KyGVX7QeFU8gVoI7I0w8RQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||
"@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="],
|
||||
|
||||
"@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="],
|
||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
"@types/node": ["@types/node@24.0.13", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ=="],
|
||||
|
||||
|
|
@ -262,6 +341,8 @@
|
|||
|
||||
"@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.6", "", {}, "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="],
|
||||
|
||||
"@workshop/arg-completer": ["@workshop/arg-completer@workspace:packages/arg-completer"],
|
||||
|
||||
"@workshop/glyph": ["@workshop/glyph@workspace:packages/glyph"],
|
||||
|
||||
"@workshop/http": ["@workshop/http@workspace:packages/http"],
|
||||
|
|
@ -270,6 +351,8 @@
|
|||
|
||||
"@workshop/nano-remix": ["@workshop/nano-remix@workspace:packages/nano-remix"],
|
||||
|
||||
"@workshop/phantasm": ["@workshop/phantasm@workspace:packages/phantasm"],
|
||||
|
||||
"@workshop/query": ["@workshop/query@workspace:packages/query"],
|
||||
|
||||
"@workshop/shared": ["@workshop/shared@workspace:packages/shared"],
|
||||
|
|
@ -284,16 +367,22 @@
|
|||
|
||||
"accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
|
||||
|
||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
|
||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||
|
||||
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
||||
"ajv": ["ajv@6.10.0", "", { "dependencies": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg=="],
|
||||
|
||||
"amqplib": ["amqplib@0.5.2", "", { "dependencies": { "bitsyntax": "~0.0.4", "bluebird": "^3.4.6", "buffer-more-ints": "0.0.2", "readable-stream": "1.x >=1.1.9", "safe-buffer": "^5.0.1" } }, "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"app-root-path": ["app-root-path@2.1.0", "", {}, "sha512-z5BqVjscbjmJBybKlICogJR2jCr2q/Ixu7Pvui5D4y97i7FLsJlvEG9XOR/KJRlkxxZz7UaaS2TMwQh1dRJ2dA=="],
|
||||
|
||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
|
||||
"array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="],
|
||||
|
||||
"array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="],
|
||||
|
|
@ -310,14 +399,14 @@
|
|||
|
||||
"async-retry": ["async-retry@1.2.3", "", { "dependencies": { "retry": "0.12.0" } }, "sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q=="],
|
||||
|
||||
"attache": ["attache@workspace:packages/attache"],
|
||||
|
||||
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
|
||||
|
||||
"axios": ["axios@0.16.2", "", { "dependencies": { "follow-redirects": "^1.2.3", "is-buffer": "^1.1.5" } }, "sha512-IMYFDrcVbUksQhsMYtWCM6KdNaDpr1NY56dpzaIgj92ecPVI29bf2sOgAf8aGTiq8UoixJD61Pj0Ahej5DPv7w=="],
|
||||
|
||||
"babel-runtime": ["babel-runtime@6.26.0", "", { "dependencies": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" } }, "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"basic-auth": ["basic-auth@2.0.1", "", { "dependencies": { "safe-buffer": "5.1.2" } }, "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg=="],
|
||||
|
|
@ -330,13 +419,15 @@
|
|||
|
||||
"body-parser": ["body-parser@1.18.3", "", { "dependencies": { "bytes": "3.0.0", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", "http-errors": "~1.6.3", "iconv-lite": "0.4.23", "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", "type-is": "~1.6.16" } }, "sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||
|
||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||
|
||||
"buffer-more-ints": ["buffer-more-ints@0.0.2", "", {}, "sha512-PDgX2QJgUc5+Jb2xAoBFP5MxhtVUmZHR33ak+m/SDxRdCrbnX1BggRIaxiW7ImwfmO4iJeCQKN18ToSXWGjYkA=="],
|
||||
|
||||
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.0.15", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-qtAXMNGG4R0UGGI8zWrqm2B7BdXqx48vunJXBPzfDOHPA5WkRUZdTSbE7TFwO4jLhYqSE23YMWsM9NhE6ovobw=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
||||
"bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="],
|
||||
|
||||
"bytes": ["bytes@3.0.0", "", {}, "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="],
|
||||
|
||||
|
|
@ -346,11 +437,13 @@
|
|||
|
||||
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
||||
|
||||
"chalk": ["chalk@2.4.1", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ=="],
|
||||
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||
|
||||
"color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"commands-events": ["commands-events@1.0.4", "", { "dependencies": { "@babel/runtime": "7.2.0", "formats": "1.0.0", "uuidv4": "2.0.0" } }, "sha512-HdP/+1Anoc7z+6L2h7nd4Imz54+LW+BjMGt30riBZrZ3ZeP/8el93wD8Jj8ltAaqVslqNgjX6qlhSBJwuDSmpg=="],
|
||||
|
||||
|
|
@ -360,6 +453,8 @@
|
|||
|
||||
"compression": ["compression@1.7.3", "", { "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", "compressible": "~2.0.14", "debug": "2.6.9", "on-headers": "~1.0.1", "safe-buffer": "5.1.2", "vary": "~1.1.2" } }, "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"content-disposition": ["content-disposition@0.5.2", "", {}, "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA=="],
|
||||
|
||||
"content-type": ["content-type@1.0.4", "", {}, "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="],
|
||||
|
|
@ -394,6 +489,8 @@
|
|||
|
||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||
|
||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||
|
||||
"define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
|
||||
|
||||
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
||||
|
|
@ -434,7 +531,27 @@
|
|||
|
||||
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"eslint": ["eslint@9.36.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.36.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ=="],
|
||||
|
||||
"eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="],
|
||||
|
||||
"eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.4", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
|
||||
|
||||
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
|
||||
|
||||
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
|
||||
|
||||
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
|
||||
|
||||
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
|
||||
|
||||
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||
|
||||
|
|
@ -452,14 +569,26 @@
|
|||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
||||
|
||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||
|
||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||
|
||||
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
||||
|
||||
"finalhandler": ["finalhandler@1.1.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", "parseurl": "~1.3.2", "statuses": "~1.4.0", "unpipe": "~1.0.0" } }, "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg=="],
|
||||
|
||||
"find-root": ["find-root@1.1.0", "", {}, "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="],
|
||||
|
||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||
|
||||
"flaschenpost": ["flaschenpost@1.1.3", "", { "dependencies": { "@babel/runtime": "7.2.0", "app-root-path": "2.1.0", "babel-runtime": "6.26.0", "chalk": "2.4.1", "find-root": "1.1.0", "lodash": "4.17.11", "moment": "2.22.2", "processenv": "1.1.0", "split2": "3.0.0", "stack-trace": "0.0.10", "stringify-object": "3.3.0", "untildify": "3.0.3", "util.promisify": "1.0.0", "varname": "2.0.3" }, "bin": { "flaschenpost-uncork": "dist/bin/flaschenpost-uncork.js", "flaschenpost-normalize": "dist/bin/flaschenpost-normalize.js" } }, "sha512-1VAYPvDsVBGFJyUrOa/6clnJwZYC3qVq9nJLcypy6lvaaNbo1wOQiH8HQ+4Fw/k51pVG7JHzSf5epb8lmIW86g=="],
|
||||
|
||||
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
||||
|
||||
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
|
||||
|
||||
"follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="],
|
||||
|
||||
"for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="],
|
||||
|
|
@ -488,6 +617,10 @@
|
|||
|
||||
"get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="],
|
||||
|
||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||
|
||||
"globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
||||
|
||||
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
|
||||
|
||||
"google-auth-library": ["google-auth-library@9.15.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^6.1.1", "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" } }, "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng=="],
|
||||
|
|
@ -500,7 +633,7 @@
|
|||
|
||||
"has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="],
|
||||
|
||||
"has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
|
||||
|
||||
|
|
@ -514,7 +647,7 @@
|
|||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"hono": ["hono@4.8.5", "", {}, "sha512-Up2cQbtNz1s111qpnnECdTGqSIUIhZJMLikdKkshebQSEBcoUKq6XJayLGqSZWidiH0zfHRCJqFu062Mz5UuRA=="],
|
||||
"hono": ["hono@4.9.8", "", {}, "sha512-JW8Bb4RFWD9iOKxg5PbUarBYGM99IcxFl2FPBo2gSJO11jjUDqlP1Bmfyqt8Z/dGhIQ63PMA9LdcLefXyIasyg=="],
|
||||
|
||||
"http-errors": ["http-errors@1.6.3", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", "statuses": ">= 1.4.0 < 2" } }, "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A=="],
|
||||
|
||||
|
|
@ -522,6 +655,12 @@
|
|||
|
||||
"iconv-lite": ["iconv-lite@0.4.23", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA=="],
|
||||
|
||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"inherits": ["inherits@2.0.3", "", {}, "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="],
|
||||
|
||||
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
|
||||
|
|
@ -544,10 +683,14 @@
|
|||
|
||||
"is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="],
|
||||
|
||||
"is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
|
||||
|
||||
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
|
||||
|
|
@ -584,20 +727,32 @@
|
|||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||
|
||||
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
|
||||
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-lines": ["json-lines@1.0.0", "", { "dependencies": { "timer2": "1.0.0" } }, "sha512-ytuLZb4RBQb3bTRsG/QBenyIo5oHLpjeCVph3s2NnoAsZE9K6h+uR+OWpEOWV1UeHdX63tYctGppBpGAc+JNMA=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
||||
|
||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||
|
||||
"jsonwebtoken": ["jsonwebtoken@8.5.0", "", { "dependencies": { "jws": "^3.2.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^5.6.0" } }, "sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA=="],
|
||||
|
||||
"jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
|
||||
|
||||
"jws": ["jws@4.0.0", "", { "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="],
|
||||
|
||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||
|
||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||
|
||||
"limes": ["limes@2.0.0", "", { "dependencies": { "@babel/runtime": "7.3.4", "jsonwebtoken": "8.5.0" } }, "sha512-evWD0pnTgPX7QueaSoJl5JBUL30T1ZVzo34ke97tIKmeagqhBTYK/JkKL0vtG3MpNApw8ZY9TlbybfwEz9knBA=="],
|
||||
|
||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||
|
||||
"lodash": ["lodash@4.17.11", "", {}, "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="],
|
||||
|
||||
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
|
||||
|
|
@ -612,6 +767,8 @@
|
|||
|
||||
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
|
||||
|
||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||
|
||||
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
|
||||
|
||||
"lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
|
||||
|
|
@ -640,13 +797,15 @@
|
|||
|
||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||
|
||||
"moment": ["moment@2.22.2", "", {}, "sha512-LRvkBHaJGnrcWvqsElsOhHCzj8mU39wLx5pQ0pc6s153GynCTsPdGdqsVNKAQD9sKnWj11iF7TZx9fpLwdD3fw=="],
|
||||
|
||||
"morgan": ["morgan@1.9.1", "", { "dependencies": { "basic-auth": "~2.0.0", "debug": "2.6.9", "depd": "~1.1.2", "on-finished": "~2.3.0", "on-headers": "~1.0.1" } }, "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="],
|
||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||
|
||||
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||
|
||||
|
|
@ -658,6 +817,8 @@
|
|||
|
||||
"node-statsd": ["node-statsd@0.1.1", "", {}, "sha512-QDf6R8VXF56QVe1boek8an/Rb3rSNaxoFWb7Elpsv2m1+Noua1yy0F1FpKpK5VluF8oymWM4w764A4KsYL4pDg=="],
|
||||
|
||||
"nose-bbs": ["nose-bbs@workspace:packages/nose-bbs"],
|
||||
|
||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||
|
||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||
|
|
@ -676,14 +837,24 @@
|
|||
|
||||
"openai": ["openai@5.9.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-cmLC0pfqLLhBGxE4aZPyRPjydgYCncppV2ClQkKmW79hNjCvmzkfhz8rN5/YVDmjVQlFV+UsF1JIuNjNgeagyQ=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
|
||||
"own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
|
||||
|
||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||
|
||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||
|
||||
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
|
||||
|
||||
"parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="],
|
||||
|
||||
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||
|
||||
"partof": ["partof@1.0.0", "", {}, "sha512-+TXdhKCySpJDynCxgAPoGVyAkiK3QPusQ63/BdU5t68QcYzyU6zkP/T7F3gkMQBVUYqdWEADKa6Kx5zg8QIKrg=="],
|
||||
|
||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-to-regexp": ["path-to-regexp@0.1.7", "", {}, "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="],
|
||||
|
|
@ -700,6 +871,12 @@
|
|||
|
||||
"preact-render-to-string": ["preact-render-to-string@6.5.13", "", { "peerDependencies": { "preact": ">=10" } }, "sha512-iGPd+hKPMFKsfpR2vL4kJ6ZPcFIoWZEcBf0Dpm3zOpdVvj77aY8RlLiQji5OMrngEyaxGogeakTb54uS2FvA6w=="],
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
|
||||
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
||||
|
||||
"processenv": ["processenv@1.1.0", "", { "dependencies": { "babel-runtime": "6.26.0" } }, "sha512-SymqIsn8GjEUy8nG7HiyEjgbfk1xFosRIakUX1NHLpriq3vVpKniGrr9RdMWCaGYWByIovbRt2f/WvmP/IOApQ=="],
|
||||
|
||||
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||
|
|
@ -722,6 +899,8 @@
|
|||
|
||||
"regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="],
|
||||
|
||||
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
||||
|
||||
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
|
||||
|
||||
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||
|
|
@ -764,6 +943,8 @@
|
|||
|
||||
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||
|
||||
"sneaker": ["sneaker@workspace:packages/sneaker"],
|
||||
|
||||
"split2": ["split2@3.0.0", "", { "dependencies": { "readable-stream": "^3.0.0" } }, "sha512-Cp7G+nUfKJyHCrAI8kze3Q00PFGEG1pMgrAlTFlDbn+GW24evSZHJuMl+iUJx1w/NTRDeBiTgvwnf6YOt94FMw=="],
|
||||
|
||||
"stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="],
|
||||
|
|
@ -784,9 +965,13 @@
|
|||
|
||||
"stringify-object": ["stringify-object@3.3.0", "", { "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", "is-regexp": "^1.0.0" } }, "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw=="],
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||
|
||||
"style-mod": ["style-mod@4.1.2", "", {}, "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="],
|
||||
|
||||
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
|
||||
"synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="],
|
||||
|
||||
"tailwind": ["tailwind@4.0.0", "", { "dependencies": { "@babel/runtime": "7.3.4", "ajv": "6.10.0", "app-root-path": "2.1.0", "async-retry": "1.2.3", "body-parser": "1.18.3", "commands-events": "1.0.4", "compression": "1.7.3", "content-type": "1.0.4", "cors": "2.8.5", "crypto2": "2.0.0", "datasette": "1.0.1", "draht": "1.0.1", "express": "4.16.4 ", "flaschenpost": "1.1.3", "hase": "2.0.0", "json-lines": "1.0.0", "limes": "2.0.0", "lodash": "4.17.11", "lusca": "1.6.1", "morgan": "1.9.1", "nocache": "2.0.0", "partof": "1.0.0", "processenv": "1.1.0", "stethoskop": "1.0.0", "timer2": "1.0.0", "uuidv4": "3.0.1", "ws": "6.2.0" } }, "sha512-LlUNoD/5maFG1h5kQ6/hXfFPdcnYw+1Z7z+kUD/W/E71CUMwcnrskxiBM8c3G8wmPsD1VvCuqGYMHviI8+yrmg=="],
|
||||
|
||||
|
|
@ -798,12 +983,16 @@
|
|||
|
||||
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
"truism": ["truism@workspace:packages/truism"],
|
||||
|
||||
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"tsscmp": ["tsscmp@1.0.6", "", {}, "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="],
|
||||
|
||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||
|
||||
"type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
|
||||
|
||||
"typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
|
||||
|
|
@ -858,10 +1047,14 @@
|
|||
|
||||
"which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="],
|
||||
|
||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"ws": ["ws@6.2.0", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-deZYUNlt2O4buFCa3t5bKLf8A7FPP/TVjwOeVNpw818Ma5nk4MLXls2eoEGS39o8119QIYxTrTDoPQ5B/gTD6w=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="],
|
||||
|
||||
"zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="],
|
||||
|
|
@ -874,6 +1067,10 @@
|
|||
|
||||
"@discordjs/ws/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
||||
"@eslint/eslintrc/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
"@google/genai/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
|
@ -888,24 +1085,28 @@
|
|||
|
||||
"@sapphire/shapeshift/lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"@workshop/http/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
"@workshop/glyph/@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||
|
||||
"@workshop/http/hono": ["hono@4.8.5", "", {}, "sha512-Up2cQbtNz1s111qpnnECdTGqSIUIhZJMLikdKkshebQSEBcoUKq6XJayLGqSZWidiH0zfHRCJqFu062Mz5UuRA=="],
|
||||
|
||||
"@workshop/iago/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@workshop/query/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@workshop/todo/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
"@workshop/todo/hono": ["hono@4.8.5", "", {}, "sha512-Up2cQbtNz1s111qpnnECdTGqSIUIhZJMLikdKkshebQSEBcoUKq6XJayLGqSZWidiH0zfHRCJqFu062Mz5UuRA=="],
|
||||
|
||||
"@workshop/werewolf-ui/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@workshop/werewolf-ui/hono": ["hono@4.8.5", "", {}, "sha512-Up2cQbtNz1s111qpnnECdTGqSIUIhZJMLikdKkshebQSEBcoUKq6XJayLGqSZWidiH0zfHRCJqFu062Mz5UuRA=="],
|
||||
|
||||
"@workshop/whiteboard/@openai/agents": ["@openai/agents@0.0.11", "", { "dependencies": { "@openai/agents-core": "0.0.11", "@openai/agents-openai": "0.0.11", "@openai/agents-realtime": "0.0.11", "debug": "^4.4.0", "openai": "^5.0.1" } }, "sha512-MYSuQ0PptjryTb/BzrqoZB+cajv/p31uF42uXeqkI3s9PihqRttnQBJ1YCTJS/xQCl4f5R9cIradh/o5PpbDkA=="],
|
||||
|
||||
"@workshop/whiteboard/hono": ["hono@4.8.5", "", {}, "sha512-Up2cQbtNz1s111qpnnECdTGqSIUIhZJMLikdKkshebQSEBcoUKq6XJayLGqSZWidiH0zfHRCJqFu062Mz5UuRA=="],
|
||||
|
||||
"ajv/fast-deep-equal": ["fast-deep-equal@2.0.1", "", {}, "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w=="],
|
||||
|
||||
"amqplib/readable-stream": ["readable-stream@1.1.14", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ=="],
|
||||
|
||||
"attache/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"babel-runtime/regenerator-runtime": ["regenerator-runtime@0.11.1", "", {}, "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="],
|
||||
|
||||
"body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
|
@ -916,14 +1117,22 @@
|
|||
|
||||
"compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"cubby/@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||
|
||||
"cubby/hono": ["hono@4.8.5", "", {}, "sha512-Up2cQbtNz1s111qpnnECdTGqSIUIhZJMLikdKkshebQSEBcoUKq6XJayLGqSZWidiH0zfHRCJqFu062Mz5UuRA=="],
|
||||
|
||||
"datasette/lodash": ["lodash@4.17.5", "", {}, "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="],
|
||||
|
||||
"eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
"express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"flaschenpost/@babel/runtime": ["@babel/runtime@7.2.0", "", { "dependencies": { "regenerator-runtime": "^0.12.0" } }, "sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg=="],
|
||||
|
||||
"flaschenpost/chalk": ["chalk@2.4.1", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ=="],
|
||||
|
||||
"gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||
|
||||
"hase/@babel/runtime": ["@babel/runtime@7.1.2", "", { "dependencies": { "regenerator-runtime": "^0.12.0" } }, "sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg=="],
|
||||
|
|
@ -992,14 +1201,12 @@
|
|||
|
||||
"@modelcontextprotocol/sdk/raw-body/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||
|
||||
"@workshop/http/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
"@workshop/glyph/@types/bun/bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
||||
|
||||
"@workshop/iago/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@workshop/query/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@workshop/todo/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@workshop/werewolf-ui/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@workshop/whiteboard/@openai/agents/@openai/agents-core": ["@openai/agents-core@0.0.11", "", { "dependencies": { "@openai/zod": "npm:zod@3.25.40 - 3.25.67", "debug": "^4.4.0", "openai": "^5.0.1" }, "optionalDependencies": { "@modelcontextprotocol/sdk": "^1.12.0" }, "peerDependencies": { "zod": "3.25.40 - 3.25.67" }, "optionalPeers": ["zod"] }, "sha512-kMG/B620fsFAwUe/ounmXty4FuAmWbMWgql4z/gCoER3S6h5tBqNTxffN0MAOFHV3EuPLiqTxA0kGiSdTpDwyA=="],
|
||||
|
|
@ -1010,16 +1217,22 @@
|
|||
|
||||
"amqplib/readable-stream/string_decoder": ["string_decoder@0.10.31", "", {}, "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="],
|
||||
|
||||
"attache/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"cubby/@types/bun/bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
||||
|
||||
"express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"flaschenpost/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||
|
||||
"flaschenpost/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
||||
|
||||
"flaschenpost/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
||||
|
||||
"jsonwebtoken/jws/jwa": ["jwa@1.4.2", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw=="],
|
||||
|
||||
"morgan/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
|
@ -1049,5 +1262,11 @@
|
|||
"@modelcontextprotocol/sdk/raw-body/http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
||||
|
||||
"@workshop/whiteboard/@openai/agents/@openai/agents-realtime/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"flaschenpost/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||
|
||||
"flaschenpost/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
||||
|
||||
"flaschenpost/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
packages/arg-completer/.gitattributes
vendored
Normal file
2
packages/arg-completer/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
34
packages/arg-completer/.gitignore
vendored
Normal file
34
packages/arg-completer/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# dependencies (bun install)
|
||||
node_modules
|
||||
|
||||
# output
|
||||
out
|
||||
dist
|
||||
*.tgz
|
||||
|
||||
# code coverage
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# logs
|
||||
logs
|
||||
_.log
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# caches
|
||||
.eslintcache
|
||||
.cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
106
packages/arg-completer/CLAUDE.md
Normal file
106
packages/arg-completer/CLAUDE.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
Default to using Bun instead of Node.js.
|
||||
|
||||
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
||||
- Use `bun test` instead of `jest` or `vitest`
|
||||
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
||||
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
||||
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
||||
- Bun automatically loads .env, so don't use dotenv.
|
||||
|
||||
## APIs
|
||||
|
||||
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
||||
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
||||
- `Bun.redis` for Redis. Don't use `ioredis`.
|
||||
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
||||
- `WebSocket` is built-in. Don't use `ws`.
|
||||
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
||||
- Bun.$`ls` instead of execa.
|
||||
|
||||
## Testing
|
||||
|
||||
Use `bun test` to run tests.
|
||||
|
||||
```ts#index.test.ts
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("hello world", () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
## Frontend
|
||||
|
||||
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
||||
|
||||
Server:
|
||||
|
||||
```ts#index.ts
|
||||
import index from "./index.html"
|
||||
|
||||
Bun.serve({
|
||||
routes: {
|
||||
"/": index,
|
||||
"/api/users/:id": {
|
||||
GET: (req) => {
|
||||
return new Response(JSON.stringify({ id: req.params.id }));
|
||||
},
|
||||
},
|
||||
},
|
||||
// optional websocket support
|
||||
websocket: {
|
||||
open: (ws) => {
|
||||
ws.send("Hello, world!");
|
||||
},
|
||||
message: (ws, message) => {
|
||||
ws.send(message);
|
||||
},
|
||||
close: (ws) => {
|
||||
// handle close
|
||||
}
|
||||
},
|
||||
development: {
|
||||
hmr: true,
|
||||
console: true,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
||||
|
||||
```html#index.html
|
||||
<html>
|
||||
<body>
|
||||
<h1>Hello, world!</h1>
|
||||
<script type="module" src="./frontend.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
With the following `frontend.tsx`:
|
||||
|
||||
```tsx#frontend.tsx
|
||||
import React from "react";
|
||||
|
||||
// import .css files directly and it works
|
||||
import './index.css';
|
||||
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
const root = createRoot(document.body);
|
||||
|
||||
export default function Frontend() {
|
||||
return <h1>Hello, world!</h1>;
|
||||
}
|
||||
|
||||
root.render(<Frontend />);
|
||||
```
|
||||
|
||||
Then, run index.ts
|
||||
|
||||
```sh
|
||||
bun --hot ./index.ts
|
||||
```
|
||||
|
||||
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.
|
||||
17
packages/arg-completer/bun-env.d.ts
vendored
Normal file
17
packages/arg-completer/bun-env.d.ts
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Generated by `bun init`
|
||||
|
||||
declare module "*.svg" {
|
||||
/**
|
||||
* A path to the SVG file
|
||||
*/
|
||||
const path: `${string}.svg`;
|
||||
export = path;
|
||||
}
|
||||
|
||||
declare module "*.module.css" {
|
||||
/**
|
||||
* A record of class names to their corresponding CSS module classes
|
||||
*/
|
||||
const classes: { readonly [key: string]: string };
|
||||
export = classes;
|
||||
}
|
||||
29
packages/arg-completer/bun.lock
Normal file
29
packages/arg-completer/bun.lock
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "bun-react-template",
|
||||
"dependencies": {
|
||||
"hono": "^4.9.7",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="],
|
||||
|
||||
"@types/node": ["@types/node@24.5.0", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"hono": ["hono@4.9.7", "", {}, "sha512-t4Te6ERzIaC48W3x4hJmBwgNlLhmiEdEE5ViYb02ffw4ignHNHa5IBtPjmbKstmtKa8X6C35iWwK4HaqvrzG9w=="],
|
||||
|
||||
"undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="],
|
||||
}
|
||||
}
|
||||
2
packages/arg-completer/bunfig.toml
Normal file
2
packages/arg-completer/bunfig.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[serve.static]
|
||||
env = "BUN_PUBLIC_*"
|
||||
19
packages/arg-completer/package.json
Normal file
19
packages/arg-completer/package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "@workshop/arg-completer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun --hot src/server.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"hono": "^4.9.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 100
|
||||
}
|
||||
}
|
||||
BIN
packages/arg-completer/public/img/cow.jpeg
Normal file
BIN
packages/arg-completer/public/img/cow.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
BIN
packages/arg-completer/public/vendor/C64_Pro-STYLE.woff2
vendored
Normal file
BIN
packages/arg-completer/public/vendor/C64_Pro-STYLE.woff2
vendored
Normal file
Binary file not shown.
BIN
packages/arg-completer/public/vendor/C64_Pro_Mono-STYLE.woff2
vendored
Normal file
BIN
packages/arg-completer/public/vendor/C64_Pro_Mono-STYLE.woff2
vendored
Normal file
Binary file not shown.
4
packages/arg-completer/public/vendor/pico.fuchsia.css
vendored
Normal file
4
packages/arg-completer/public/vendor/pico.fuchsia.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
packages/arg-completer/readme.md
Normal file
4
packages/arg-completer/readme.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
bun install
|
||||
bun --filter=@workshop/arg-completer dev
|
||||
|
||||
go to http://localhost:3000
|
||||
30
packages/arg-completer/src/components/prompt.tsx
Normal file
30
packages/arg-completer/src/components/prompt.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import type { FC } from "hono/jsx"
|
||||
|
||||
export const Prompt: FC = async () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Completion demo!</h1>
|
||||
<div id="command-line">
|
||||
<textarea
|
||||
id="command-prompt"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck={false}
|
||||
rows={1}
|
||||
autofocus
|
||||
></textarea>
|
||||
<div id="command-error">{/* tail follow=<span class="error">fsd</span> */}</div>
|
||||
<textarea
|
||||
id="command-hint"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck={false}
|
||||
readonly
|
||||
></textarea>
|
||||
<div id="command-suggestion-list"></div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
166
packages/arg-completer/src/css/index.css
Normal file
166
packages/arg-completer/src/css/index.css
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
@font-face {
|
||||
font-family: 'C64ProMono';
|
||||
src: url('/vendor/C64_Pro_Mono-STYLE.woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
:root {
|
||||
--font-family: 'C64ProMono', monospace;
|
||||
--black: #000000;
|
||||
--white: #E0E0E0;
|
||||
--grey: #aaa;
|
||||
--dark-grey: #666;
|
||||
--cyan: #00A8C8;
|
||||
--red: #C62828;
|
||||
--green: green;
|
||||
--yellow: #C4A000;
|
||||
--purple: #7C3AED;
|
||||
--blue: #1565C0;
|
||||
--magenta: #ff66cc;
|
||||
}
|
||||
|
||||
.black {
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.white {
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.cyan {
|
||||
color: var(--cyan);
|
||||
}
|
||||
|
||||
.red {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.green {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.yellow {
|
||||
color: var(--yellow);
|
||||
}
|
||||
|
||||
.purple {
|
||||
color: var(--purple);
|
||||
}
|
||||
|
||||
.blue {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.magenta {
|
||||
color: var(--magenta);
|
||||
}
|
||||
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: var(--font-family);
|
||||
color: var(--pico-h3-color);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
|
||||
#command-line {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
#command-line textarea {
|
||||
width: 100%;
|
||||
min-height: 2em;
|
||||
resize: none;
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#command-prompt {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#command-error {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
right: 0;
|
||||
z-index: 0;
|
||||
color: white;
|
||||
padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);
|
||||
}
|
||||
|
||||
#command-error .error {
|
||||
border-bottom: 3px groove red;
|
||||
}
|
||||
|
||||
#command-hint {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
color: #666;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.command-suggestion {
|
||||
display: flex;
|
||||
padding: 0.25em 0.5em;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.command-suggestion:nth-child(odd) {
|
||||
background-color: var(--white);
|
||||
}
|
||||
|
||||
/* #command-promp {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
background: transparent;
|
||||
padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);
|
||||
font: inherit;
|
||||
letter-spacing: inherit;
|
||||
line-height: inherit;
|
||||
height: auto;
|
||||
min-height: 1.2em;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#command-hin {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
border: var(--pico-border-width) solid transparent;
|
||||
pointer-events: none;
|
||||
padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);
|
||||
font: inherit;
|
||||
letter-spacing: inherit;
|
||||
line-height: inherit;
|
||||
color: #666;
|
||||
background: transparent;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
min-height: 1.2em;
|
||||
height: auto;
|
||||
} */
|
||||
116
packages/arg-completer/src/js/command.test.ts
Normal file
116
packages/arg-completer/src/js/command.test.ts
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import { type CommandShape, Command } from "./command"
|
||||
import { ParseError } from "./errors"
|
||||
import { expect, test } from "bun:test"
|
||||
|
||||
const fetchShape: CommandShape = {
|
||||
command: "fetch",
|
||||
description: "Fetch a URL and display the response",
|
||||
args: [
|
||||
{ name: "url", type: "string" },
|
||||
{ name: "raw", type: "boolean", named: true, default: false },
|
||||
{ name: "timeout", type: "number", named: true, default: 30 },
|
||||
],
|
||||
}
|
||||
|
||||
test("parseArgs with valid args", () => {
|
||||
const cmd = new Command(fetchShape)
|
||||
const { args, error } = cmd.parse("fetch https://example.com raw=true timeout=10")
|
||||
expect(error).toBeUndefined()
|
||||
expect(args).toMatchObject([
|
||||
{ name: "url", value: "https://example.com" },
|
||||
{ name: "raw", value: true },
|
||||
{ name: "timeout", value: 10 },
|
||||
])
|
||||
})
|
||||
|
||||
test("parseArgs without some named args", () => {
|
||||
const cmd = new Command(fetchShape)
|
||||
const { args, error } = cmd.parse("fetch https://example.com raw=true")
|
||||
expect(error).toBeUndefined()
|
||||
expect(args).toEqual([
|
||||
{ name: "url", value: "https://example.com" },
|
||||
{ name: "raw", value: true },
|
||||
])
|
||||
})
|
||||
|
||||
test("parseArgs with too many named args", () => {
|
||||
const cmd = new Command(fetchShape)
|
||||
const { error } = cmd.parse("fetch https://example.com meow")
|
||||
expect(error).toBeDefined()
|
||||
expect(error?.message).toEqual("Expected 1 positional argument(s) but got 2.")
|
||||
expect(error?.start).toEqual(30)
|
||||
expect(error?.end).toEqual(30)
|
||||
})
|
||||
|
||||
test("parseArgs with not enough positional args", () => {
|
||||
const cmd = new Command(fetchShape)
|
||||
const { error } = cmd.parse("fetch")
|
||||
expect(error).toBeDefined()
|
||||
expect(error?.message).toEqual("Expected 1 positional argument(s) but got 0.")
|
||||
expect(error?.start).toEqual(5)
|
||||
expect(error?.end).toEqual(5)
|
||||
})
|
||||
|
||||
const typeShape: CommandShape = {
|
||||
command: "type",
|
||||
description: "Fetch a URL and display the response",
|
||||
args: [
|
||||
{ name: "theBoolean", type: "boolean", named: true, default: false },
|
||||
{ name: "theNumber", type: "number", named: true, default: 30 },
|
||||
],
|
||||
}
|
||||
|
||||
test("parseArgs incorrect number type", () => {
|
||||
const cmd = new Command(typeShape)
|
||||
const { error } = cmd.parse("type theNumber=notanumber")
|
||||
expect(error).toBeDefined()
|
||||
|
||||
expect(error?.message).toEqual("Expected a number but got 'notanumber'.")
|
||||
expect(error?.start).toEqual(5)
|
||||
expect(error?.end).toEqual(25)
|
||||
})
|
||||
|
||||
test("parseArgs incorrect boolean type", () => {
|
||||
const cmd = new Command(typeShape)
|
||||
const { error } = cmd.parse("type theBoolean=notaboolean")
|
||||
expect(error).toBeDefined()
|
||||
|
||||
expect(error?.message).toEqual("Expected a boolean but got 'notaboolean'.")
|
||||
expect(error?.start).toEqual(5)
|
||||
expect(error?.end).toEqual(27)
|
||||
})
|
||||
|
||||
test("argSuggestions for positional and named args", () => {
|
||||
const cmd = new Command(fetchShape)
|
||||
|
||||
const expectNames = (input: string) => {
|
||||
const names = cmd.getSuggestions(input).suggestions.map((a) => a.name + (a.named ? "=" : ""))
|
||||
return expect(names, `from input "${input}"`)
|
||||
}
|
||||
|
||||
expectNames("fetch ").toEqual(["url"])
|
||||
expectNames("fetch path r").toEqual(["raw="])
|
||||
expectNames("fetch path raw").toEqual(["raw="])
|
||||
expectNames("fetch path raw=true ").toEqual(["timeout="])
|
||||
expectNames("fetch path raw=true t").toEqual(["timeout="])
|
||||
})
|
||||
|
||||
test("argSuggestions throw errors for unmatched patterns", () => {
|
||||
const cmd = new Command(fetchShape)
|
||||
|
||||
const expectError = (input: string) => {
|
||||
const error = cmd.getSuggestions(input).error
|
||||
return expect(error, `from input "${input}"`)
|
||||
}
|
||||
|
||||
expectError("fetch path f").toBeInstanceOf(ParseError)
|
||||
expectError("fetch path raw=asdf ").toBeInstanceOf(ParseError)
|
||||
expectError("fetch path raw=true").toBeUndefined()
|
||||
})
|
||||
|
||||
/*
|
||||
/*
|
||||
# Ignored problems
|
||||
|
||||
what if a positional arg looks like a named arg? For example echo verbose=32. If we want to echo verbose=32 it is ambiguous.
|
||||
*/
|
||||
171
packages/arg-completer/src/js/command.ts
Normal file
171
packages/arg-completer/src/js/command.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
import { Tokenizer, type Token } from "./tokenizer"
|
||||
import { ParseError } from "./errors"
|
||||
|
||||
export class Command {
|
||||
shape: CommandShape
|
||||
|
||||
constructor(shape: CommandShape) {
|
||||
this.shape = shape
|
||||
}
|
||||
|
||||
getSuggestions(input: string): { suggestions: ArgShape[]; token?: Token } {
|
||||
const tokens = Tokenizer.tokens(input)
|
||||
if (tokens[0]?.value !== this.shape.command) {
|
||||
return { suggestions: [] }
|
||||
}
|
||||
|
||||
const argTokens = tokens.slice(1)
|
||||
const hasTrailingSpace = input.endsWith(" ")
|
||||
const lastToken = argTokens.at(-1)
|
||||
const isCompletingPartialArg = !hasTrailingSpace && lastToken
|
||||
|
||||
const completedTokens = isCompletingPartialArg ? argTokens.slice(0, -1) : argTokens
|
||||
|
||||
const usedArgs = new Set<string>()
|
||||
completedTokens.forEach((token, index) => {
|
||||
const parsedArg = this.#convertTokenToArg(token, index, completedTokens)
|
||||
if (usedArgs.has(parsedArg.name)) {
|
||||
const message = `Argument '${parsedArg.name}' was provided more than once.`
|
||||
throw new ParseError(message, token.start, token.end)
|
||||
}
|
||||
usedArgs.add(parsedArg.name)
|
||||
})
|
||||
|
||||
const availableArgs = this.shape.args.filter((arg) => !usedArgs.has(arg.name))
|
||||
|
||||
if (isCompletingPartialArg) {
|
||||
const positionalShapes = this.shape.args.filter((a) => !a.named)
|
||||
const parsingPositionalArgs = completedTokens.length < positionalShapes.length
|
||||
if (parsingPositionalArgs)
|
||||
return { suggestions: [positionalShapes[completedTokens.length]!], token: lastToken }
|
||||
|
||||
const prefix = lastToken.type === "named" ? lastToken.name : lastToken.value
|
||||
const suggestions = availableArgs.filter((arg) => arg.named && arg.name.startsWith(prefix))
|
||||
if (suggestions.length > 0) {
|
||||
return { suggestions, token: lastToken }
|
||||
} else {
|
||||
throw new ParseError(`No matches for '${prefix}'`, lastToken.start, lastToken.end)
|
||||
}
|
||||
}
|
||||
|
||||
// If we still need positional args, only suggest the next positional arg
|
||||
const positionalShapes = this.shape.args.filter((a) => !a.named)
|
||||
const positionalCount = completedTokens.filter((t) => t.type === "positional").length
|
||||
if (positionalCount < positionalShapes.length) {
|
||||
const nextPositionalArg = positionalShapes[positionalCount]!
|
||||
return { suggestions: [nextPositionalArg], token: lastToken }
|
||||
}
|
||||
|
||||
// Otherwise suggest available named args
|
||||
return { suggestions: availableArgs.filter((arg) => arg.named), token: lastToken }
|
||||
}
|
||||
|
||||
parse(input: string): ParsedArg[] {
|
||||
const parsedArgs: ParsedArg[] = []
|
||||
const tokens = Tokenizer.tokens(input)
|
||||
const [command, ...argTokens] = tokens
|
||||
|
||||
if (!command) {
|
||||
throw new ParseError(`Expected command "${this.shape.command}" but got nothing.`, 0, 0)
|
||||
} else if (command.value !== this.shape.command) {
|
||||
const message = `Expected command "${this.shape.command}" but got "${command.value}."`
|
||||
throw new ParseError(message, command.start, command.end)
|
||||
}
|
||||
|
||||
// Convert each token to a parsed arg
|
||||
const usedArgs = new Set<string>()
|
||||
argTokens.forEach((token, index) => {
|
||||
const parsedArg = this.#convertTokenToArg(token, index, argTokens)
|
||||
if (usedArgs.has(parsedArg.name)) {
|
||||
const message = `Argument '${parsedArg.name}' was provided more than once.`
|
||||
throw new ParseError(message, token.start, token.end)
|
||||
}
|
||||
usedArgs.add(parsedArg.name)
|
||||
parsedArgs.push(parsedArg)
|
||||
})
|
||||
|
||||
// Check that we have the right number of positional args
|
||||
const positionalShapes = this.shape.args.filter((a) => !a.named)
|
||||
const positionalCount = argTokens.filter((t) => t.type === "positional").length
|
||||
if (positionalCount !== positionalShapes.length) {
|
||||
const message = `Expected ${positionalShapes.length} positional argument(s) but got ${positionalCount}.`
|
||||
const lastToken = argTokens.at(-1)
|
||||
const end = lastToken ? lastToken.end : command.end
|
||||
throw new ParseError(message, end, end)
|
||||
}
|
||||
|
||||
return parsedArgs
|
||||
}
|
||||
|
||||
#convertTokenToArg(token: Token, tokenIndex: number, allTokens: Token[]): ParsedArg {
|
||||
if (token.type === "positional") {
|
||||
const positionalShapes = this.shape.args.filter((a) => !a.named)
|
||||
|
||||
// If we're past the positional args, this is out of order
|
||||
const shape = positionalShapes[tokenIndex]
|
||||
if (!shape) {
|
||||
const message = `Positional arguments must come before named arguments`
|
||||
throw new ParseError(message, token.start, token.end)
|
||||
}
|
||||
|
||||
return { name: shape.name, value: this.#castArgValue(token, shape.type), token }
|
||||
} else if (token.type === "named") {
|
||||
const namedShapes = this.shape.args.filter((a) => a.named)
|
||||
const shape = namedShapes.find((a) => a.name === token.name)
|
||||
if (!shape) {
|
||||
throw new ParseError(`Unknown named argument '${token.name}'`, token.start, token.end)
|
||||
}
|
||||
|
||||
return { name: token.name, value: this.#castArgValue(token, shape.type), token }
|
||||
}
|
||||
|
||||
throw new ParseError(`Unknown token type`, token.start, token.end)
|
||||
}
|
||||
|
||||
#castArgValue<T extends ArgShape["type"]>(token: Token, type: T): ArgTypeMap[T] {
|
||||
if (type === "string") {
|
||||
return token.value as ArgTypeMap[T]
|
||||
} else if (type === "number") {
|
||||
const number = Number(token.value)
|
||||
if (isNaN(number))
|
||||
throw new ParseError(`Expected a number but got '${token.value}'.`, token.start, token.end)
|
||||
|
||||
return number as ArgTypeMap[T]
|
||||
} else if (type === "boolean") {
|
||||
if (token.value.match(/^(true|1|t)$/i)) return true as ArgTypeMap[T]
|
||||
if (token.value.match(/^(false|0|f)$/i)) return false as ArgTypeMap[T]
|
||||
throw new ParseError(`Expected a boolean but got '${token.value}'.`, token.start, token.end)
|
||||
}
|
||||
|
||||
throw new ParseError(`Unknown arg type: ${type}.`, token.start, token.end)
|
||||
}
|
||||
}
|
||||
|
||||
type ArgTypeMap = {
|
||||
string: string
|
||||
number: number
|
||||
boolean: boolean
|
||||
}
|
||||
|
||||
type ArgShape<T extends keyof ArgTypeMap = keyof ArgTypeMap> =
|
||||
| {
|
||||
name: string
|
||||
type: T
|
||||
description?: string
|
||||
named?: false
|
||||
}
|
||||
| {
|
||||
name: string
|
||||
type: T
|
||||
description?: string
|
||||
named: true
|
||||
default: ArgTypeMap[T]
|
||||
}
|
||||
|
||||
export type CommandShape = {
|
||||
command: string
|
||||
description: string
|
||||
args: ArgShape[]
|
||||
}
|
||||
|
||||
type ParsedArg = { name: string; value: ArgTypeMap[keyof ArgTypeMap]; token: Token }
|
||||
449
packages/arg-completer/src/js/commands.ts
Normal file
449
packages/arg-completer/src/js/commands.ts
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
import { Command, type CommandShape } from "./command"
|
||||
|
||||
export const commandsShapes = {
|
||||
ls: {
|
||||
command: "ls",
|
||||
description: "List the contents of a directory",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "The path to list", named: false },
|
||||
{
|
||||
name: "all",
|
||||
type: "boolean",
|
||||
description: "Show hidden files",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "long",
|
||||
type: "boolean",
|
||||
description: "List in long format",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "short-names",
|
||||
type: "boolean",
|
||||
description: "Only print file names",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "full-paths",
|
||||
type: "boolean",
|
||||
description: "Display full paths",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
cd: {
|
||||
command: "cd",
|
||||
description: "Change the current working directory",
|
||||
args: [{ name: "path", type: "string", description: "The path to change to", named: false }],
|
||||
},
|
||||
|
||||
cp: {
|
||||
command: "cp",
|
||||
description: "Copy files or directories",
|
||||
args: [
|
||||
{ name: "source", type: "string", description: "Source file or directory" },
|
||||
{ name: "destination", type: "string", description: "Destination path" },
|
||||
{
|
||||
name: "recursive",
|
||||
type: "boolean",
|
||||
description: "Copy recursively",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "verbose",
|
||||
type: "boolean",
|
||||
description: "Verbose output",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
mv: {
|
||||
command: "mv",
|
||||
description: "Move files or directories",
|
||||
args: [
|
||||
{ name: "source", type: "string", description: "Source file or directory" },
|
||||
{ name: "destination", type: "string", description: "Destination path" },
|
||||
{
|
||||
name: "verbose",
|
||||
type: "boolean",
|
||||
description: "Verbose output",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
rm: {
|
||||
command: "rm",
|
||||
description: "Remove files or directories",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "Path to remove" },
|
||||
{
|
||||
name: "recursive",
|
||||
type: "boolean",
|
||||
description: "Remove recursively",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{ name: "force", type: "boolean", description: "Force removal", named: true, default: false },
|
||||
{
|
||||
name: "verbose",
|
||||
type: "boolean",
|
||||
description: "Verbose output",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
mkdir: {
|
||||
command: "mkdir",
|
||||
description: "Create directories",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "Directory path to create" },
|
||||
{
|
||||
name: "verbose",
|
||||
type: "boolean",
|
||||
description: "Verbose output",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
touch: {
|
||||
command: "touch",
|
||||
description: "Create empty files or update timestamps",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "File path to touch" },
|
||||
{
|
||||
name: "access",
|
||||
type: "boolean",
|
||||
description: "Update access time only",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "modified",
|
||||
type: "boolean",
|
||||
description: "Update modified time only",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Text operations
|
||||
echo: {
|
||||
command: "echo",
|
||||
description: "Display a string",
|
||||
args: [
|
||||
{ name: "text", type: "string", description: "Text to display" },
|
||||
{
|
||||
name: "no-newline",
|
||||
type: "boolean",
|
||||
description: "Don't append newline",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
cat: {
|
||||
command: "cat",
|
||||
description: "Display file contents",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "File to display" },
|
||||
{
|
||||
name: "numbered",
|
||||
type: "boolean",
|
||||
description: "Show line numbers",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
head: {
|
||||
command: "head",
|
||||
description: "Show first lines of input",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "File to read from", named: false },
|
||||
{ name: "lines", type: "number", description: "Number of lines", named: true, default: 10 },
|
||||
],
|
||||
},
|
||||
|
||||
tail: {
|
||||
command: "tail",
|
||||
description: "Show last lines of input",
|
||||
args: [
|
||||
{ name: "path", type: "string", description: "File to read from", named: false },
|
||||
{ name: "lines", type: "number", description: "Number of lines", named: true, default: 10 },
|
||||
{
|
||||
name: "follow",
|
||||
type: "boolean",
|
||||
description: "Follow file changes",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
grep: {
|
||||
command: "grep",
|
||||
description: "Search for patterns in text",
|
||||
args: [
|
||||
{ name: "pattern", type: "string", description: "Pattern to search for" },
|
||||
{
|
||||
name: "ignore-case",
|
||||
type: "boolean",
|
||||
description: "Case insensitive search",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "invert-match",
|
||||
type: "boolean",
|
||||
description: "Invert match",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "line-number",
|
||||
type: "boolean",
|
||||
description: "Show line numbers",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
sort: {
|
||||
command: "sort",
|
||||
description: "Sort input",
|
||||
args: [
|
||||
{
|
||||
name: "reverse",
|
||||
type: "boolean",
|
||||
description: "Sort in reverse order",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "ignore-case",
|
||||
type: "boolean",
|
||||
description: "Case insensitive sort",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "numeric",
|
||||
type: "boolean",
|
||||
description: "Numeric sort",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
uniq: {
|
||||
command: "uniq",
|
||||
description: "Filter out repeated lines",
|
||||
args: [
|
||||
{
|
||||
name: "count",
|
||||
type: "boolean",
|
||||
description: "Show count of occurrences",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "repeated",
|
||||
type: "boolean",
|
||||
description: "Show only repeated lines",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
name: "unique",
|
||||
type: "boolean",
|
||||
description: "Show only unique lines",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Data manipulation
|
||||
select: {
|
||||
command: "select",
|
||||
description: "Select specific columns from data",
|
||||
args: [{ name: "columns", type: "string", description: "Columns to select" }],
|
||||
},
|
||||
|
||||
where: {
|
||||
command: "where",
|
||||
description: "Filter data based on conditions",
|
||||
args: [{ name: "condition", type: "string", description: "Filter condition" }],
|
||||
},
|
||||
|
||||
group_by: {
|
||||
command: "group-by",
|
||||
description: "Group data by column values",
|
||||
args: [{ name: "column", type: "string", description: "Column to group by" }],
|
||||
},
|
||||
|
||||
// // Network operations
|
||||
// http_get: {
|
||||
// command: "http get",
|
||||
// description: "Fetch data from a URL via GET request",
|
||||
// args: [
|
||||
// { name: "url", type: "string", description: "URL to fetch" },
|
||||
// { name: "headers", type: "string", description: "HTTP headers", named: true, default: "" },
|
||||
// {
|
||||
// name: "raw",
|
||||
// type: "boolean",
|
||||
// description: "Return raw response",
|
||||
// named: true,
|
||||
// default: false,
|
||||
// },
|
||||
// {
|
||||
// name: "insecure",
|
||||
// type: "boolean",
|
||||
// description: "Allow insecure connections",
|
||||
// named: true,
|
||||
// default: false,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
|
||||
// http_post: {
|
||||
// command: "http post",
|
||||
// description: "Send data via POST request",
|
||||
// args: [
|
||||
// { name: "url", type: "string", description: "URL to post to" },
|
||||
// { name: "data", type: "string", description: "Data to send", named: false },
|
||||
// {
|
||||
// name: "content-type",
|
||||
// type: "string",
|
||||
// description: "Content type",
|
||||
// named: true,
|
||||
// default: "application/json",
|
||||
// },
|
||||
// { name: "headers", type: "string", description: "HTTP headers", named: true, default: "" },
|
||||
// ],
|
||||
// },
|
||||
|
||||
// System operations
|
||||
ps: {
|
||||
command: "ps",
|
||||
description: "List running processes",
|
||||
args: [
|
||||
{
|
||||
name: "long",
|
||||
type: "boolean",
|
||||
description: "Show detailed information",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
sys: {
|
||||
command: "sys",
|
||||
description: "Show system information",
|
||||
args: [],
|
||||
},
|
||||
|
||||
which: {
|
||||
command: "which",
|
||||
description: "Find the location of a command",
|
||||
args: [
|
||||
{ name: "command", type: "string", description: "Command to locate" },
|
||||
{
|
||||
name: "all",
|
||||
type: "boolean",
|
||||
description: "Show all matches",
|
||||
named: true,
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// // Conversion operations
|
||||
// to_json: {
|
||||
// command: "to json",
|
||||
// description: "Convert data to JSON",
|
||||
// args: [
|
||||
// { name: "indent", type: "number", description: "JSON indentation", named: true, default: 2 },
|
||||
// { name: "raw", type: "boolean", description: "Output raw JSON", named: true, default: false },
|
||||
// ],
|
||||
// },
|
||||
|
||||
// from_json: {
|
||||
// command: "from json",
|
||||
// description: "Parse JSON data",
|
||||
// args: [
|
||||
// {
|
||||
// name: "objects",
|
||||
// type: "boolean",
|
||||
// description: "Parse multiple objects",
|
||||
// named: true,
|
||||
// default: false,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
|
||||
// to_csv: {
|
||||
// command: "to csv",
|
||||
// description: "Convert data to CSV",
|
||||
// args: [
|
||||
// {
|
||||
// name: "separator",
|
||||
// type: "string",
|
||||
// description: "Field separator",
|
||||
// named: true,
|
||||
// default: ",",
|
||||
// },
|
||||
// {
|
||||
// name: "no-headers",
|
||||
// type: "boolean",
|
||||
// description: "Don't include headers",
|
||||
// named: true,
|
||||
// default: false,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
|
||||
// from_csv: {
|
||||
// command: "from csv",
|
||||
// description: "Parse CSV data",
|
||||
// args: [
|
||||
// {
|
||||
// name: "separator",
|
||||
// type: "string",
|
||||
// description: "Field separator",
|
||||
// named: true,
|
||||
// default: ",",
|
||||
// },
|
||||
// {
|
||||
// name: "no-headers",
|
||||
// type: "boolean",
|
||||
// description: "No header row",
|
||||
// named: true,
|
||||
// default: false,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
} as const satisfies Record<string, CommandShape>
|
||||
|
||||
export const commands: Command[] = Object.values(commandsShapes).map((shape) => new Command(shape))
|
||||
12
packages/arg-completer/src/js/dom.ts
Normal file
12
packages/arg-completer/src/js/dom.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
export const $ = (id: string): HTMLElement | null => document.getElementById(id)
|
||||
|
||||
export const $$ = (tag: string, html = ""): HTMLElement => {
|
||||
const el = document.createElement(tag)
|
||||
el.innerHTML = html
|
||||
return el
|
||||
}
|
||||
|
||||
export const cmdPrompt = $("command-prompt") as HTMLTextAreaElement
|
||||
export const cmdHint = $("command-hint") as HTMLTextAreaElement
|
||||
export const cmdSuggestionList = $("command-suggestion-list") as HTMLUListElement
|
||||
export const cmdError = $("command-error") as HTMLDivElement
|
||||
5
packages/arg-completer/src/js/errors.ts
Normal file
5
packages/arg-completer/src/js/errors.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export class ParseError extends Error {
|
||||
constructor(message: string, public start: number, public end: number) {
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
133
packages/arg-completer/src/js/index.tsx
Normal file
133
packages/arg-completer/src/js/index.tsx
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import { commands } from "./commands"
|
||||
import { cmdPrompt, cmdHint, cmdSuggestionList, cmdError } from "./dom"
|
||||
import { ParseError } from "./errors"
|
||||
|
||||
let tabCompletion = ""
|
||||
|
||||
cmdPrompt.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
console.log("ENTER")
|
||||
e.preventDefault
|
||||
} else if (e.key === "Tab") {
|
||||
e.preventDefault()
|
||||
cmdPrompt.value = tabCompletion
|
||||
updateSuggestionList(cmdPrompt.value)
|
||||
}
|
||||
})
|
||||
|
||||
cmdPrompt.addEventListener("input", (e) => {
|
||||
updateSuggestionList(cmdPrompt.value)
|
||||
})
|
||||
|
||||
// Corey hates this
|
||||
const updateSuggestionList = (input: string) => {
|
||||
if (input.trim() == "") return
|
||||
|
||||
cmdSuggestionList.innerHTML = ""
|
||||
cmdError.innerHTML = ""
|
||||
tabCompletion = ""
|
||||
|
||||
const { commandSuggestions, argSuggestions, error } = getSuggestions(input)
|
||||
|
||||
if (error) {
|
||||
const beforeError = input.slice(0, error.start)
|
||||
const errorText = input.slice(error.start, error.end)
|
||||
const afterError = input.slice(error.end)
|
||||
cmdError.innerHTML = `${beforeError}<span class='error'>${errorText}</span>${afterError}`
|
||||
}
|
||||
|
||||
// Show command suggestions
|
||||
commandSuggestions.forEach((cmdShape) => {
|
||||
const div = createSuggestionElement(cmdShape.command, cmdShape.description)
|
||||
cmdSuggestionList.appendChild(div)
|
||||
})
|
||||
|
||||
// Show arg suggestions
|
||||
argSuggestions?.forEach((arg) => {
|
||||
let name = arg.name
|
||||
if (arg.named) {
|
||||
name = `${name}=${arg.default}`
|
||||
}
|
||||
const description = `<${arg.type}>` + (arg.description ? ` - ${arg.description}` : "")
|
||||
const div = createSuggestionElement(name, description)
|
||||
cmdSuggestionList.appendChild(div)
|
||||
})
|
||||
|
||||
cmdHint.value = ""
|
||||
tabCompletion = ""
|
||||
|
||||
// Tab completion
|
||||
if (commandSuggestions.length > 0) {
|
||||
cmdHint.value = commandSuggestions[0]!.command
|
||||
tabCompletion = cmdHint.value + " "
|
||||
} else if (argSuggestions?.length > 0) {
|
||||
const suggestion = argSuggestions[0]!
|
||||
|
||||
const lastArg = input.trimStart().split(" ").pop() ?? ""
|
||||
if (suggestion?.named) {
|
||||
if (lastArg.match(/^[\w-]+=/)) {
|
||||
const afterEquals = lastArg.split("=")[1] ?? ""
|
||||
if (!afterEquals) {
|
||||
const suggestionText = `<${suggestion.type}>`
|
||||
tabCompletion = input + suggestionText
|
||||
cmdHint.value = tabCompletion
|
||||
}
|
||||
} else {
|
||||
const suggestionText = suggestion.name.slice(lastArg.length) + "="
|
||||
tabCompletion = input + suggestionText
|
||||
cmdHint.value = tabCompletion
|
||||
}
|
||||
} else if (!lastArg) {
|
||||
tabCompletion = ""
|
||||
cmdHint.value = input + suggestion?.name + " "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getSuggestions = (input: string) => {
|
||||
try {
|
||||
const commandInput = input.trimStart().split(" ")[0] ?? ""
|
||||
const matchingCommands = commands.filter((cmd) => cmd.shape.command.startsWith(commandInput))
|
||||
const hasCommand = input.trimStart().match(/\w+\s+/)
|
||||
|
||||
if (!hasCommand) {
|
||||
return {
|
||||
commandSuggestions: matchingCommands.map((cmd) => cmd.shape),
|
||||
argSuggestions: [],
|
||||
command: null,
|
||||
}
|
||||
} else if (matchingCommands.length === 1) {
|
||||
const command = matchingCommands[0]!
|
||||
const { suggestions } = command.getSuggestions(input)
|
||||
return {
|
||||
commandSuggestions: [],
|
||||
argSuggestions: suggestions,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
commandSuggestions: [],
|
||||
argSuggestions: [],
|
||||
error: new ParseError(`Unknown command: "${commandInput}."`, 0, commandInput.length),
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof ParseError) {
|
||||
return { commandSuggestions: [], argSuggestions: [], error }
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const createSuggestionElement = (title: string, description: string) => {
|
||||
const div = document.createElement("div")
|
||||
div.className = "command-suggestion"
|
||||
const commandDiv = document.createElement("div")
|
||||
commandDiv.textContent = title
|
||||
commandDiv.className = "command-name"
|
||||
const descriptionDiv = document.createElement("div")
|
||||
descriptionDiv.textContent = description
|
||||
descriptionDiv.className = "command-description"
|
||||
div.appendChild(commandDiv)
|
||||
div.appendChild(descriptionDiv)
|
||||
return div
|
||||
}
|
||||
105
packages/arg-completer/src/js/tokenizer.test.ts
Normal file
105
packages/arg-completer/src/js/tokenizer.test.ts
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import { Tokenizer } from "./tokenizer.js"
|
||||
import { expect, test } from "bun:test"
|
||||
|
||||
test("parse 'fetch url' into command and positional tokens", () => {
|
||||
const { tokens, error } = Tokenizer.tokens("fetch https://example.com/path true")
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "https://example.com/path", start: 6, end: 30 },
|
||||
{ type: "positional", value: "true", start: 31, end: 35 },
|
||||
])
|
||||
})
|
||||
|
||||
test("parse 'fetch \"quoted url\"' and strip quotes from value", () => {
|
||||
const { tokens, error } = Tokenizer.tokens('fetch "https://example.com/path"')
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "https://example.com/path", start: 6, end: 32 },
|
||||
])
|
||||
})
|
||||
|
||||
test("parse 'fetch url timeout=30' with named argument", () => {
|
||||
const { tokens, error } = Tokenizer.tokens("fetch https://example.com/path timeout=30")
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "https://example.com/path", start: 6, end: 30 },
|
||||
{ type: "named", name: "timeout", value: "30", start: 31, end: 41 },
|
||||
])
|
||||
})
|
||||
|
||||
test("parse mixed args 'fetch url timeout=30 raw=true'", () => {
|
||||
const { tokens, error } = Tokenizer.tokens("fetch https://example.com/path timeout=30 raw=true")
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "https://example.com/path", start: 6, end: 30 },
|
||||
{ type: "named", name: "timeout", value: "30", start: 31, end: 41 },
|
||||
{ type: "named", name: "raw", value: "true", start: 42, end: 50 },
|
||||
])
|
||||
})
|
||||
|
||||
test("return error for unclosed quote in 'fetch \"unterminated'", () => {
|
||||
const { tokens, error } = Tokenizer.tokens('fetch "https://example.com/path')
|
||||
expect(tokens).toEqual([])
|
||||
expect(error).toBeDefined()
|
||||
expect(error?.message).toBe("Unclosed quote")
|
||||
expect(error?.start).toBe(6)
|
||||
expect(error?.end).toBe(31)
|
||||
})
|
||||
|
||||
test("return error for escape char at end", () => {
|
||||
const { tokens, error } = Tokenizer.tokens("fetch https://example.com/path\\")
|
||||
expect(tokens).toEqual([])
|
||||
expect(error).toBeDefined()
|
||||
expect(error?.message).toBe("Trailing backslash")
|
||||
expect(error?.start).toBe(30)
|
||||
expect(error?.end).toBe(31)
|
||||
})
|
||||
|
||||
test('handle escaped quotes in \'fetch "url with \\"quotes\\""\'', () => {
|
||||
const { tokens, error } = Tokenizer.tokens('fetch "url with \\"quotes\\""')
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: 'url with "quotes"', start: 6, end: 27 },
|
||||
])
|
||||
expect(error).toBeUndefined()
|
||||
})
|
||||
|
||||
test("handle escaped quotes in in named arg", () => {
|
||||
const { tokens, error } = Tokenizer.tokens('fetch url timeout="30 seconds" raw=true')
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "url", start: 6, end: 9 },
|
||||
{ type: "named", name: "timeout", value: "30 seconds", start: 10, end: 30 },
|
||||
{ type: "named", name: "raw", value: "true", start: 31, end: 39 },
|
||||
])
|
||||
expect(error).toBeUndefined()
|
||||
})
|
||||
|
||||
test("ignore multiple spaces between arguments", () => {
|
||||
const { tokens, error } = Tokenizer.tokens(
|
||||
"fetch https://example.com/path timeout=30 raw=true"
|
||||
)
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "https://example.com/path", start: 9, end: 33 },
|
||||
{ type: "named", name: "timeout", value: "30", start: 36, end: 46 },
|
||||
{ type: "named", name: "raw", value: "true", start: 49, end: 57 },
|
||||
])
|
||||
expect(error).toBeUndefined()
|
||||
})
|
||||
|
||||
test("return empty array for empty string input", () => {
|
||||
const { tokens, error } = Tokenizer.tokens("")
|
||||
expect(tokens).toEqual([])
|
||||
expect(error).toBeUndefined()
|
||||
})
|
||||
|
||||
test("handle quote immediately followed by text 'fetch \"url\"more'", () => {
|
||||
const { tokens, error } = Tokenizer.tokens('fetch "url"more timeout=30')
|
||||
expect(tokens).toEqual([
|
||||
{ type: "command", value: "fetch", start: 0, end: 5 },
|
||||
{ type: "positional", value: "urlmore", start: 6, end: 15 },
|
||||
{ type: "named", name: "timeout", value: "30", start: 16, end: 26 },
|
||||
])
|
||||
expect(error).toBeUndefined()
|
||||
})
|
||||
122
packages/arg-completer/src/js/tokenizer.ts
Normal file
122
packages/arg-completer/src/js/tokenizer.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import { ParseError } from "./errors.js"
|
||||
|
||||
export class Tokenizer {
|
||||
pos: number
|
||||
tokens: Token[]
|
||||
input: string
|
||||
|
||||
constructor(input: string) {
|
||||
this.pos = 0
|
||||
this.tokens = []
|
||||
this.input = input
|
||||
}
|
||||
|
||||
static tokens(input: string): Token[] {
|
||||
const tokenizer = new Tokenizer(input)
|
||||
return tokenizer.tokenize()
|
||||
}
|
||||
|
||||
tokenize(): Token[] {
|
||||
while (this.pos < this.input.length) {
|
||||
if (this.#skipWhitespace(this.input)) continue
|
||||
|
||||
const rawTokenStart = this.pos
|
||||
const rawToken = this.#readRawToken()
|
||||
const token = this.#analyzeToken(rawToken, rawTokenStart, this.pos)
|
||||
this.tokens.push(token)
|
||||
}
|
||||
|
||||
return this.tokens
|
||||
}
|
||||
|
||||
#analyzeToken(value: string, start: number, end: number): Token {
|
||||
if (!value) throw new ParseError("Unexpected empty argument", start, end)
|
||||
|
||||
if (this.tokens.length === 0) {
|
||||
return { type: "command", value, start, end }
|
||||
}
|
||||
|
||||
const namedMatch = value.match(/^([\w-]+)=(.*)$/)
|
||||
if (namedMatch) {
|
||||
const [, name, argValue] = namedMatch
|
||||
if (!name) {
|
||||
throw new ParseError("Named argument missing name", start, end)
|
||||
}
|
||||
|
||||
return { type: "named", name, value: argValue, start, end }
|
||||
} else {
|
||||
return { type: "positional", value, start, end }
|
||||
}
|
||||
}
|
||||
|
||||
#readRawToken(): string {
|
||||
let token = ""
|
||||
let inQuotes = false
|
||||
let escapeNext = false
|
||||
|
||||
while (!this.#eol()) {
|
||||
const char = this.input[this.pos]
|
||||
|
||||
if (escapeNext) {
|
||||
if (char === '"') {
|
||||
token += char // unescape the quote
|
||||
} else {
|
||||
token += "\\" + char // keep the backslash for non-quotes
|
||||
}
|
||||
escapeNext = false
|
||||
} else if (char === "\\") {
|
||||
escapeNext = true
|
||||
} else if (char === '"') {
|
||||
inQuotes = !inQuotes
|
||||
} else if (char === " " && !inQuotes) {
|
||||
break
|
||||
} else {
|
||||
token += char
|
||||
}
|
||||
|
||||
this.pos++
|
||||
}
|
||||
|
||||
if (inQuotes) {
|
||||
throw new ParseError("Unclosed quote", this.pos - token.length - 1, this.pos)
|
||||
} else if (escapeNext) {
|
||||
throw new ParseError("Trailing backslash", this.pos - 1, this.pos)
|
||||
}
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
#skipWhitespace(input: string): boolean {
|
||||
const match = input.slice(this.pos).match(/^\s+/)
|
||||
if (!match) return false
|
||||
|
||||
const offset = match[0].length
|
||||
this.pos += offset
|
||||
return true
|
||||
}
|
||||
|
||||
#eol(): boolean {
|
||||
return this.pos >= this.input.length
|
||||
}
|
||||
}
|
||||
|
||||
export type Token =
|
||||
| {
|
||||
type: "command"
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
| {
|
||||
type: "positional"
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
| {
|
||||
type: "named"
|
||||
name: string
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
17
packages/arg-completer/src/layout.tsx
Normal file
17
packages/arg-completer/src/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { html } from "hono/html"
|
||||
|
||||
export const Layout = (children: any) => html`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Completion test</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<link rel="stylesheet" href="/vendor/pico.fuchsia.css" />
|
||||
<link rel="stylesheet" href="/css/index.css" />
|
||||
<script src="/js/index.js" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
${children}
|
||||
</body>
|
||||
</html>`
|
||||
32
packages/arg-completer/src/server.tsx
Normal file
32
packages/arg-completer/src/server.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { Hono } from "hono"
|
||||
import { Prompt } from "./components/prompt"
|
||||
import { serveStatic } from "hono/bun"
|
||||
import { Layout } from "./layout"
|
||||
import { isFile, transpile } from "./utils"
|
||||
|
||||
const app = new Hono()
|
||||
|
||||
app.get("/", (c) => c.html(Layout(<Prompt />)))
|
||||
app.use("/vendor/*", serveStatic({ root: "./public" }))
|
||||
app.use("/css/*", serveStatic({ root: "./src" }))
|
||||
|
||||
app.get("/js/:path{.+}", async (c) => {
|
||||
const path = "./src/js/" + c.req.param("path")
|
||||
const ts = path.endsWith(".js") ? path.replace(".js", ".ts") : path + ".ts"
|
||||
const tsx = path.endsWith(".js") ? path.replace(".js", ".tsx") : path + ".tsx"
|
||||
let javascript = ""
|
||||
|
||||
if (isFile(ts)) {
|
||||
javascript = await transpile(ts)
|
||||
} else if (isFile(tsx)) {
|
||||
javascript = await transpile(tsx)
|
||||
} else if (isFile(path)) {
|
||||
javascript = await Bun.file(path).text()
|
||||
} else {
|
||||
return c.text("File not found", 404)
|
||||
}
|
||||
|
||||
return new Response(javascript, { headers: { "Content-Type": "text/javascript" } })
|
||||
})
|
||||
|
||||
export default app
|
||||
58
packages/arg-completer/src/utils.tsx
Normal file
58
packages/arg-completer/src/utils.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { statSync } from "node:fs"
|
||||
import { stat } from "node:fs/promises"
|
||||
|
||||
const transpiler = new Bun.Transpiler({ loader: 'tsx' })
|
||||
|
||||
export function css(strings: TemplateStringsArray, ...values: any[]) {
|
||||
return <style dangerouslySetInnerHTML={{
|
||||
__html: strings.reduce((result, str, i) => {
|
||||
return result + str + (values[i] || '')
|
||||
}, '')
|
||||
}} />
|
||||
}
|
||||
|
||||
export function js(strings: TemplateStringsArray, ...values: any[]) {
|
||||
return <script dangerouslySetInnerHTML={{
|
||||
__html: strings.reduce((result, str, i) => {
|
||||
return transpiler.transformSync(result + str + (values[i] || ''))
|
||||
}, '')
|
||||
}} />
|
||||
}
|
||||
|
||||
export function isFile(path: string): boolean {
|
||||
try {
|
||||
const stats = statSync(path)
|
||||
return stats.isFile()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function isDir(path: string): boolean {
|
||||
try {
|
||||
const stats = statSync(path)
|
||||
return stats.isDirectory()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function randomID(): string {
|
||||
return Math.random().toString(36).slice(2)
|
||||
}
|
||||
|
||||
const transpileCache: Record<string, string> = {}
|
||||
export async function transpile(path: string): Promise<string> {
|
||||
const code = await Bun.file(path).text()
|
||||
|
||||
const { mtime } = await stat(path)
|
||||
const key = `${path}?${mtime}`
|
||||
|
||||
let cached = transpileCache[key]
|
||||
if (!cached) {
|
||||
cached = transpiler.transformSync(code)
|
||||
transpileCache[key] = cached
|
||||
}
|
||||
|
||||
return cached
|
||||
}
|
||||
34
packages/arg-completer/tsconfig.json
Normal file
34
packages/arg-completer/tsconfig.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "hono/jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
"baseUrl": ".",
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
},
|
||||
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
1
packages/cubby/.env.example
Normal file
1
packages/cubby/.env.example
Normal file
|
|
@ -0,0 +1 @@
|
|||
GITHUB_TOKEN=your_github_token_here
|
||||
111
packages/cubby/CLAUDE.md
Normal file
111
packages/cubby/CLAUDE.md
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
description: Use Bun instead of Node.js, npm, pnpm, or vite.
|
||||
globs: "*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json"
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
Default to using Bun instead of Node.js.
|
||||
|
||||
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
||||
- Use `bun test` instead of `jest` or `vitest`
|
||||
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
||||
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
||||
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
||||
- Bun automatically loads .env, so don't use dotenv.
|
||||
|
||||
## APIs
|
||||
|
||||
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
||||
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
||||
- `Bun.redis` for Redis. Don't use `ioredis`.
|
||||
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
||||
- `WebSocket` is built-in. Don't use `ws`.
|
||||
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
||||
- Bun.$`ls` instead of execa.
|
||||
|
||||
## Testing
|
||||
|
||||
Use `bun test` to run tests.
|
||||
|
||||
```ts#index.test.ts
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test("hello world", () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
```
|
||||
|
||||
## Frontend
|
||||
|
||||
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
||||
|
||||
Server:
|
||||
|
||||
```ts#index.ts
|
||||
import index from "./index.html"
|
||||
|
||||
Bun.serve({
|
||||
routes: {
|
||||
"/": index,
|
||||
"/api/users/:id": {
|
||||
GET: (req) => {
|
||||
return new Response(JSON.stringify({ id: req.params.id }));
|
||||
},
|
||||
},
|
||||
},
|
||||
// optional websocket support
|
||||
websocket: {
|
||||
open: (ws) => {
|
||||
ws.send("Hello, world!");
|
||||
},
|
||||
message: (ws, message) => {
|
||||
ws.send(message);
|
||||
},
|
||||
close: (ws) => {
|
||||
// handle close
|
||||
}
|
||||
},
|
||||
development: {
|
||||
hmr: true,
|
||||
console: true,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
||||
|
||||
```html#index.html
|
||||
<html>
|
||||
<body>
|
||||
<h1>Hello, world!</h1>
|
||||
<script type="module" src="./frontend.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
With the following `frontend.tsx`:
|
||||
|
||||
```tsx#frontend.tsx
|
||||
import React from "react";
|
||||
|
||||
// import .css files directly and it works
|
||||
import './index.css';
|
||||
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
const root = createRoot(document.body);
|
||||
|
||||
export default function Frontend() {
|
||||
return <h1>Hello, world!</h1>;
|
||||
}
|
||||
|
||||
root.render(<Frontend />);
|
||||
```
|
||||
|
||||
Then, run index.ts
|
||||
|
||||
```sh
|
||||
bun --hot ./index.ts
|
||||
```
|
||||
|
||||
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import { Hono } from "hono"
|
||||
import { serveStatic } from "hono/bun"
|
||||
import { render } from "preact-render-to-string"
|
||||
import { $ } from "bun"
|
||||
import { readdirSync } from "fs"
|
||||
import { Glob } from "bun"
|
||||
import { mkdir, readdir } from 'node:fs/promises'
|
||||
import { basename, join } from 'path'
|
||||
import { basename, resolve, join } from 'path'
|
||||
import { Layout } from "./components/Layout"
|
||||
import { Project } from "./components/Project"
|
||||
import { Projects } from "./components/Projects"
|
||||
|
|
@ -64,7 +64,17 @@ app.get("/p/:name", async (c) => {
|
|||
const project = await projectsWithMetadata().then(projects => projects.find(p => p.name === name))
|
||||
if (!project) return c.json({ error: 'Project not found' }, 404)
|
||||
|
||||
const readme = await Bun.file(`${PROJECTS_DIR}/${name}/README.md`).text()
|
||||
let readme = ""
|
||||
const glob = new Glob("*.md")
|
||||
const projectDir = join(PROJECTS_DIR, name)
|
||||
|
||||
for (const file of glob.scanSync(projectDir)) {
|
||||
if (/readme\.md/i.test(file)) {
|
||||
readme = await Bun.file(join(projectDir, file)).text()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const cubbyPath = join(CUBBY_DIR, `project_${name}`)
|
||||
let files: string[] = []
|
||||
|
||||
|
|
@ -141,7 +151,15 @@ app.delete('/p/:id/delete/:filename', async c => {
|
|||
async function projects(): Promise<string[]> {
|
||||
const subdirs = readdirSync(PROJECTS_DIR, { withFileTypes: true })
|
||||
.filter((entry: any) => entry.isDirectory())
|
||||
.map((entry: any) => entry.name).sort()
|
||||
.map((entry: any) => entry.name)
|
||||
.filter(name => {
|
||||
try {
|
||||
return Bun.file(`${PROJECTS_DIR}/${name}/package.json`).size > 0
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})
|
||||
.sort()
|
||||
|
||||
return subdirs
|
||||
}
|
||||
|
|
@ -162,24 +180,102 @@ async function isWorkshopApp(projectName: string): Promise<boolean> {
|
|||
return json.scripts && json.scripts["subdomain:start"] !== undefined
|
||||
}
|
||||
|
||||
async function projectsWithDates(): Promise<{ name: string, mtime: Date, status: "recent" | "active" | "inactive" }[]> {
|
||||
type ProjectDate = {
|
||||
name: string
|
||||
mtime: Date
|
||||
status: "recent" | "active" | "inactive"
|
||||
}
|
||||
|
||||
async function projectsWithDates(): Promise<ProjectDate[]> {
|
||||
const names = await projects()
|
||||
const projectsWithDates = await Promise.all(names.map(async name => {
|
||||
const lastModified = await mtime(name)
|
||||
|
||||
// Try to batch GitHub API calls for better performance
|
||||
const dates = await batchedMtimes(names)
|
||||
|
||||
const projectsWithDates = names.map((name, index) => {
|
||||
const lastModified = dates[index] || new Date(0)
|
||||
const daysSince = (Date.now() - lastModified.getTime()) / (24 * 60 * 60 * 1000)
|
||||
const status: "recent" | "active" | "inactive" = daysSince <= 14 ? "recent" : daysSince <= 30 ? "active" : "inactive"
|
||||
const status: ProjectDate["status"] = daysSince <= 14 ? "recent" : daysSince <= 30 ? "active" : "inactive"
|
||||
return { name, mtime: lastModified, status }
|
||||
}))
|
||||
}).filter((project): project is ProjectDate => project.mtime instanceof Date)
|
||||
|
||||
const sorted = projectsWithDates.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())
|
||||
return sorted
|
||||
}
|
||||
|
||||
async function mtime(project: string): Promise<Date> {
|
||||
const proc = await $`cd ${PROJECTS_DIR} && git log -1 --format=%ct -- ${project}`.quiet()
|
||||
if (proc.exitCode !== 0) return new Date(0)
|
||||
return new Date(parseInt(proc.stdout.toString().trim()) * 1000)
|
||||
// Cache to avoid redundant API calls
|
||||
const mtimeCache = new Map<string, { date: Date, timestamp: number }>()
|
||||
const CACHE_TTL = 5 * 60 * 1000 // 5 minutes
|
||||
|
||||
async function batchedMtimes(projects: string[]): Promise<Date[]> {
|
||||
const token = process.env.GITHUB_TOKEN
|
||||
if (!token) {
|
||||
console.warn('GITHUB_TOKEN not set, returning default dates')
|
||||
return projects.map(() => new Date(0))
|
||||
}
|
||||
|
||||
// Check cache for all projects first
|
||||
const results: (Date | null)[] = new Array(projects.length).fill(null)
|
||||
const uncachedProjects: { index: number, name: string }[] = []
|
||||
|
||||
projects.forEach((project, index) => {
|
||||
const cached = mtimeCache.get(project)
|
||||
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
|
||||
results[index] = cached.date
|
||||
} else {
|
||||
uncachedProjects.push({ index, name: project })
|
||||
}
|
||||
})
|
||||
|
||||
if (uncachedProjects.length === 0) {
|
||||
return results as Date[]
|
||||
}
|
||||
|
||||
try {
|
||||
// Batch API calls with Promise.all for parallel execution
|
||||
const apiResults = await Promise.all(uncachedProjects.map(async ({ index, name }) => {
|
||||
try {
|
||||
console.log(`Fetching GitHub API for ${name}`)
|
||||
const response = await fetch(`https://api.github.com/repos/probablycorey/the-workshop/commits?path=packages/${encodeURIComponent(name)}&per_page=1`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'cubby-workshop-app'
|
||||
}
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
console.warn(`GitHub API error for ${name}: ${response.status}`)
|
||||
return { index, date: new Date(0) }
|
||||
}
|
||||
|
||||
const commits = await response.json()
|
||||
if (!commits || commits.length === 0) {
|
||||
return { index, date: new Date(0) }
|
||||
}
|
||||
|
||||
const date = new Date(commits[0].commit.committer.date)
|
||||
mtimeCache.set(name, { date, timestamp: Date.now() })
|
||||
return { index, date }
|
||||
} catch (error) {
|
||||
console.warn(`Error fetching GitHub data for ${name}:`, error)
|
||||
return { index, date: new Date(0) }
|
||||
}
|
||||
}))
|
||||
|
||||
// Fill in the results array
|
||||
apiResults.forEach(({ index, date }) => {
|
||||
results[index] = date
|
||||
})
|
||||
|
||||
return results as Date[]
|
||||
} catch (error) {
|
||||
console.warn('Batch GitHub API call failed, returning default dates:', error)
|
||||
return projects.map(() => new Date(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function tsx(node: any) {
|
||||
return "<!DOCTYPE html>" + render(<Layout>{node}</Layout>)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@ export const requireAuth = (handler: (req: Request) => Response | Promise<Respon
|
|||
const url = new URL(req.url)
|
||||
const cookieDomain = `.${url.hostname.split(".").slice(-2).join(".")}`
|
||||
|
||||
const oneYearInSeconds = 60 * 60 * 24 * 365
|
||||
const authCookie = new Bun.Cookie({
|
||||
name: "auth",
|
||||
value: "authenticated",
|
||||
domain: cookieDomain,
|
||||
path: "/",
|
||||
maxAge: 86400,
|
||||
maxAge: oneYearInSeconds,
|
||||
httpOnly: true,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
../../CLAUDE.md
|
||||
36
packages/nose-bbs/.gitignore
vendored
Normal file
36
packages/nose-bbs/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
bbs.sqlite
|
||||
|
||||
# dependencies (bun install)
|
||||
node_modules
|
||||
|
||||
# output
|
||||
out
|
||||
dist
|
||||
*.tgz
|
||||
|
||||
# code coverage
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# logs
|
||||
logs
|
||||
_.log
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# caches
|
||||
.eslintcache
|
||||
.cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
6
packages/nose-bbs/README.md
Normal file
6
packages/nose-bbs/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# nose-bbs
|
||||
|
||||
## Quickstart
|
||||
|
||||
bun install
|
||||
bun dev
|
||||
20
packages/nose-bbs/package.json
Normal file
20
packages/nose-bbs/package.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "nose-bbs",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "bun subdomain:dev",
|
||||
"subdomain:start": "bun run src/server.tsx",
|
||||
"subdomain:dev": "bun run --hot src/server.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"hono": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
99
packages/nose-bbs/src/server.tsx
Normal file
99
packages/nose-bbs/src/server.tsx
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import { Hono } from "hono"
|
||||
import { Database } from "bun:sqlite"
|
||||
import { join } from "path"
|
||||
|
||||
export const DATA_DIR = process.env.DATA_DIR || "."
|
||||
const api = new Hono()
|
||||
const db = new Database(join(DATA_DIR, "bbs.sqlite"))
|
||||
|
||||
api.use("*", async (c, next) => {
|
||||
const method = c.req.method
|
||||
const url = c.req.url
|
||||
|
||||
let body = ""
|
||||
if (method === "POST" || method === "PUT" || method === "PATCH") {
|
||||
try {
|
||||
const clonedRequest = c.req.raw.clone()
|
||||
body = await clonedRequest.text()
|
||||
console.log(`${method} ${url} - Body: ${body}`)
|
||||
} catch (error) {
|
||||
console.log(`${method} ${url} - Body: [unable to parse]`)
|
||||
}
|
||||
} else {
|
||||
console.log(`${method} ${url}`)
|
||||
}
|
||||
|
||||
await next()
|
||||
})
|
||||
|
||||
db.run(`
|
||||
CREATE TABLE IF NOT EXISTS topics (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
author TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS replies (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
topic_id INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
author TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
`)
|
||||
|
||||
api.get("/topics", async c => {
|
||||
const topics = db.query("SELECT * FROM topics ORDER BY id DESC").all()
|
||||
return c.json(topics)
|
||||
})
|
||||
|
||||
api.post("/topics", async c => {
|
||||
const { title, content, author } = await c.req.json()
|
||||
|
||||
if (!title || !content || !author) {
|
||||
return c.json({ error: "title, content and author are required" }, 400)
|
||||
}
|
||||
|
||||
const topic = db.query(`
|
||||
INSERT INTO
|
||||
topics(title, content, author, created_at)
|
||||
VALUES($title, $content, $author, $created_at)
|
||||
`).run({ $title: title, $content: content, $author: author, $created_at: new Date().toISOString() })
|
||||
return c.json({ id: topic.lastInsertRowid, ok: true })
|
||||
})
|
||||
|
||||
api.get("/topics/:id", async c => {
|
||||
const id = c.req.param("id")
|
||||
if (!id) {
|
||||
return c.json({ error: "id is required" }, 400)
|
||||
}
|
||||
|
||||
let topic = db.query("SELECT * FROM topics WHERE id = $id").get({ $id: id })
|
||||
if (!topic) {
|
||||
return c.json({ error: "topic not found" }, 404)
|
||||
}
|
||||
const replies = db.query("SELECT * FROM replies WHERE topic_id = $id").all({ $id: id })
|
||||
; (topic as any).replies = replies
|
||||
|
||||
return c.json(topic)
|
||||
})
|
||||
|
||||
api.post("/topics/:id/reply", async c => {
|
||||
const id = c.req.param("id")
|
||||
if (!id) {
|
||||
return c.json({ error: "id is required" }, 400)
|
||||
}
|
||||
const { content, author } = await c.req.json()
|
||||
const reply = db.query(`
|
||||
INSERT INTO replies (topic_id, content, author, created_at)
|
||||
VALUES ($topic_id, $content, $author, $created_at)
|
||||
`).run({ $topic_id: id, $content: content, $author: author, $created_at: new Date().toISOString() })
|
||||
return c.json({ id: reply.lastInsertRowid, ok: true })
|
||||
})
|
||||
|
||||
export default {
|
||||
port: process.env.PORT || 3001,
|
||||
fetch: api.fetch,
|
||||
}
|
||||
29
packages/nose-bbs/tsconfig.json
Normal file
29
packages/nose-bbs/tsconfig.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user