diff --git a/deno.lock b/deno.lock index a60c08d362..133b37518f 100644 --- a/deno.lock +++ b/deno.lock @@ -12,18 +12,18 @@ "jsr:@deno/cache-dir@0.22.2": "0.22.2", "jsr:@deno/esbuild-plugin@*": "1.2.0", "jsr:@deno/graph@0.86": "0.86.9", - "jsr:@deno/loader@~0.3.3": "0.3.5", + "jsr:@deno/loader@~0.3.3": "0.3.10", "jsr:@denosaurs/plug@1": "1.1.0", "jsr:@std/assert@0.217": "0.217.0", - "jsr:@std/assert@1": "1.0.14", - "jsr:@std/assert@^1.0.13": "1.0.14", - "jsr:@std/assert@^1.0.14": "1.0.14", - "jsr:@std/async@1": "1.0.14", - "jsr:@std/async@^1.0.13": "1.0.14", - "jsr:@std/bytes@^1.0.2": "1.0.6", - "jsr:@std/cli@1": "1.0.21", - "jsr:@std/cli@^1.0.12": "1.0.21", - "jsr:@std/cli@^1.0.21": "1.0.21", + "jsr:@std/assert@1": "1.0.16", + "jsr:@std/assert@^1.0.14": "1.0.16", + "jsr:@std/assert@^1.0.15": "1.0.16", + "jsr:@std/async@1": "1.0.15", + "jsr:@std/async@^1.0.15": "1.0.15", + "jsr:@std/bytes@^1.0.5": "1.0.6", + "jsr:@std/cli@1": "1.0.24", + "jsr:@std/cli@^1.0.12": "1.0.24", + "jsr:@std/cli@^1.0.24": "1.0.24", "jsr:@std/crypto@1": "1.0.5", "jsr:@std/data-structures@^1.0.9": "1.0.9", "jsr:@std/dotenv@~0.225.3": "0.225.5", @@ -36,48 +36,51 @@ "jsr:@std/fmt@^1.0.3": "1.0.8", "jsr:@std/fmt@^1.0.8": "1.0.8", "jsr:@std/fmt@~1.0.2": "1.0.8", - "jsr:@std/fs@1": "1.0.19", - "jsr:@std/fs@^1.0.19": "1.0.19", - "jsr:@std/fs@^1.0.6": "1.0.19", - "jsr:@std/html@^1.0.4": "1.0.4", - "jsr:@std/http@1": "1.0.20", - "jsr:@std/internal@^1.0.10": "1.0.10", - "jsr:@std/internal@^1.0.9": "1.0.10", - "jsr:@std/io@0.225": "0.225.0", + "jsr:@std/fs@1": "1.0.20", + "jsr:@std/fs@^1.0.19": "1.0.20", + "jsr:@std/fs@^1.0.20": "1.0.20", + "jsr:@std/fs@^1.0.6": "1.0.20", + "jsr:@std/html@^1.0.5": "1.0.5", + "jsr:@std/http@1": "1.0.22", + "jsr:@std/internal@^1.0.10": "1.0.12", + "jsr:@std/internal@^1.0.12": "1.0.12", + "jsr:@std/io@0.225": "0.225.2", "jsr:@std/io@0.225.0": "0.225.0", "jsr:@std/media-types@^1.1.0": "1.1.0", - "jsr:@std/net@^1.0.4": "1.0.5", + "jsr:@std/net@^1.0.6": "1.0.6", "jsr:@std/path@0.217": "0.217.0", - "jsr:@std/path@1": "1.1.2", - "jsr:@std/path@^1.0.8": "1.1.2", - "jsr:@std/path@^1.1.1": "1.1.2", - "jsr:@std/streams@^1.0.10": "1.0.11", - "jsr:@std/testing@1": "1.0.15", + "jsr:@std/path@1": "1.1.3", + "jsr:@std/path@^1.0.8": "1.1.3", + "jsr:@std/path@^1.1.1": "1.1.3", + "jsr:@std/path@^1.1.2": "1.1.3", + "jsr:@std/path@^1.1.3": "1.1.3", + "jsr:@std/streams@^1.0.14": "1.0.14", + "jsr:@std/testing@1": "1.0.16", "jsr:@std/text@~1.0.7": "1.0.16", - "jsr:@zip-js/zip-js@^2.7.52": "2.7.72", + "jsr:@zip-js/zip-js@^2.7.52": "2.8.8", "npm:@ai-sdk/anthropic@^1.1.6": "1.2.12_zod@3.25.76", - "npm:@ai-sdk/anthropic@^2.0.9": "2.0.35_zod@3.25.76", - "npm:@ai-sdk/google-vertex@^3.0.16": "3.0.51_zod@3.25.76", - "npm:@ai-sdk/groq@^2.0.16": "2.0.24_zod@3.25.76", + "npm:@ai-sdk/anthropic@^2.0.9": "2.0.50_zod@3.25.76", + "npm:@ai-sdk/google-vertex@^3.0.16": "3.0.82_zod@3.25.76", + "npm:@ai-sdk/groq@^2.0.16": "2.0.32_zod@3.25.76", "npm:@ai-sdk/openai@^1.1.9": "1.3.24_zod@3.25.76", - "npm:@ai-sdk/openai@^2.0.22": "2.0.53_zod@3.25.76", + "npm:@ai-sdk/openai@^2.0.22": "2.0.75_zod@3.25.76", "npm:@arizeai/openinference-semantic-conventions@^1.1.0": "1.1.0", - "npm:@arizeai/openinference-vercel@^2.0.1": "2.3.4_@opentelemetry+api@1.9.0", - "npm:@codemirror/autocomplete@^6.15.0": "6.19.0", - "npm:@codemirror/commands@^6.8.1": "6.9.0", + "npm:@arizeai/openinference-vercel@^2.0.1": "2.5.0_@opentelemetry+api@1.9.0", + "npm:@codemirror/autocomplete@^6.15.0": "6.20.0", + "npm:@codemirror/commands@^6.8.1": "6.10.0", "npm:@codemirror/lang-css@^6.3.1": "6.3.1", "npm:@codemirror/lang-html@^6.4.9": "6.4.11", "npm:@codemirror/lang-javascript@^6.2.2": "6.2.4", "npm:@codemirror/lang-json@^6.0.1": "6.0.2", - "npm:@codemirror/lang-markdown@^6.3.0": "6.4.0", + "npm:@codemirror/lang-markdown@^6.3.0": "6.5.0", "npm:@codemirror/language@^6.10.8": "6.11.3", "npm:@codemirror/state@^6.5.1": "6.5.2", "npm:@codemirror/theme-one-dark@^6.1.2": "6.1.3", - "npm:@codemirror/view@^6.26.0": "6.38.6", - "npm:@fal-ai/client@^1.2.2": "1.7.0", - "npm:@hono/sentry@^1.2.0": "1.2.2_hono@4.10.1", - "npm:@hono/zod-openapi@~0.18.3": "0.18.4_hono@4.10.1_zod@3.25.76", - "npm:@hono/zod-validator@~0.4.2": "0.4.3_hono@4.10.1_zod@3.25.76", + "npm:@codemirror/view@^6.26.0": "6.38.8", + "npm:@fal-ai/client@^1.2.2": "1.7.2", + "npm:@hono/sentry@^1.2.0": "1.2.2_hono@4.10.7", + "npm:@hono/zod-openapi@~0.18.3": "0.18.4_hono@4.10.7_zod@3.25.76", + "npm:@hono/zod-validator@~0.4.2": "0.4.3_hono@4.10.7_zod@3.25.76", "npm:@jitl/quickjs-singlefile-mjs-debug-sync@*": "0.31.0", "npm:@lit/context@^1.1.2": "1.1.6", "npm:@lit/context@^1.1.5": "1.1.6", @@ -85,25 +88,25 @@ "npm:@noble/ed25519@^2.2.3": "2.3.0", "npm:@opentelemetry/api@^1.7.0": "1.9.0", "npm:@opentelemetry/api@^1.9.0": "1.9.0", - "npm:@opentelemetry/context-async-hooks@^1.19.0": "1.30.1_@opentelemetry+api@1.9.0", - "npm:@opentelemetry/core@^1.19.0": "1.30.1_@opentelemetry+api@1.9.0", + "npm:@opentelemetry/context-async-hooks@^1.30.0": "1.30.1_@opentelemetry+api@1.9.0", + "npm:@opentelemetry/core@^1.30.0": "1.30.1_@opentelemetry+api@1.9.0", "npm:@opentelemetry/exporter-trace-otlp-proto@0.46": "0.46.0_@opentelemetry+api@1.9.0", - "npm:@opentelemetry/resources@^1.19.0": "1.30.1_@opentelemetry+api@1.9.0", - "npm:@opentelemetry/sdk-trace-base@^1.19.0": "1.30.1_@opentelemetry+api@1.9.0", - "npm:@opentelemetry/semantic-conventions@^1.19.0": "1.37.0", - "npm:@scalar/hono-api-reference@~0.5.165": "0.5.184_hono@4.10.1", + "npm:@opentelemetry/resources@^1.30.0": "1.30.1_@opentelemetry+api@1.9.0", + "npm:@opentelemetry/sdk-trace-base@^1.30.0": "1.30.1_@opentelemetry+api@1.9.0", + "npm:@opentelemetry/semantic-conventions@^1.30.0": "1.38.0", + "npm:@scalar/hono-api-reference@~0.5.165": "0.5.184_hono@4.10.7", "npm:@scure/bip39@^1.5.4": "1.6.0", - "npm:@sentry/deno@^9.3.0": "9.46.0", + "npm:@sentry/deno@^9.3.0": "9.47.1", "npm:@types/node@*": "24.2.0", - "npm:ai@^5.0.27": "5.0.76_zod@3.25.76", + "npm:ai@^5.0.27": "5.0.104_zod@3.25.76", "npm:ajv@^8.17.1": "8.17.1", "npm:codemirror@^6.0.1": "6.0.2", "npm:dom-serializer@*": "2.0.0", "npm:domhandler@*": "5.0.3", - "npm:esbuild@~0.25.5": "0.25.11", + "npm:esbuild@~0.25.5": "0.25.12", "npm:gcp-metadata@6.1.0": "6.1.0", - "npm:hono-pino@0.7": "0.7.2_hono@4.10.1_pino@9.14.0", - "npm:hono@^4.7.0": "4.10.1", + "npm:hono-pino@0.7": "0.7.2_hono@4.10.7_pino@9.14.0", + "npm:hono@^4.7.0": "4.10.7", "npm:htmlparser2@*": "10.0.0", "npm:json5@^2.2.3": "2.2.3", "npm:jsonschema@^1.5.0": "1.5.0", @@ -117,8 +120,8 @@ "npm:plaid@36": "36.0.0", "npm:quickjs-emscripten-core@*": "0.31.0", "npm:source-map-js@^1.2.1": "1.2.1", - "npm:stoker@^1.4.2": "1.4.3_@hono+zod-openapi@0.18.4__hono@4.10.1__zod@3.25.76_hono@4.10.1_zod@3.25.76", - "npm:turndown@^7.1.2": "7.2.1", + "npm:stoker@^1.4.2": "1.4.3_@hono+zod-openapi@0.18.4__hono@4.10.7__zod@3.25.76_hono@4.10.7_zod@3.25.76", + "npm:turndown@^7.1.2": "7.2.2", "npm:typescript@*": "5.9.3", "npm:zod@^3.24.1": "3.25.76" }, @@ -189,8 +192,8 @@ "@deno/graph@0.86.9": { "integrity": "c4f353a695bcc5246c099602977dabc6534eacea9999a35a8cb24e807192e6a1" }, - "@deno/loader@0.3.5": { - "integrity": "72f6ce9c6e7242c6e070705dbd8a838884dd236d5dd0bd907d08bece92db5722" + "@deno/loader@0.3.10": { + "integrity": "a9c0aa44a0499e7fecef52c29fbc206c1c8f8946388f25d9d0789a23313bfd43" }, "@denosaurs/plug@1.1.0": { "integrity": "eb2f0b7546c7bca2000d8b0282c54d50d91cf6d75cb26a80df25a6de8c4bc044", @@ -204,20 +207,23 @@ "@std/assert@0.217.0": { "integrity": "c98e279362ca6982d5285c3b89517b757c1e3477ee9f14eb2fdf80a45aaa9642" }, - "@std/assert@1.0.14": { - "integrity": "68d0d4a43b365abc927f45a9b85c639ea18a9fab96ad92281e493e4ed84abaa4", + "@std/assert@1.0.16": { + "integrity": "6a7272ed1eaa77defe76e5ff63ca705d9c495077e2d5fd0126d2b53fc5bd6532", "dependencies": [ - "jsr:@std/internal@^1.0.10" + "jsr:@std/internal@^1.0.12" ] }, - "@std/async@1.0.14": { - "integrity": "62e954a418652c704d37563a3e54a37d4cf0268a9dcaeac1660cc652880b5326" + "@std/async@1.0.15": { + "integrity": "55d1d9d04f99403fe5730ab16bdcc3c47f658a6bf054cafb38a50f046238116e" }, "@std/bytes@1.0.6": { "integrity": "f6ac6adbd8ccd99314045f5703e23af0a68d7f7e58364b47d2c7f408aeb5820a" }, - "@std/cli@1.0.21": { - "integrity": "cd25b050bdf6282e321854e3822bee624f07aca7636a3a76d95f77a3a919ca2a" + "@std/cli@1.0.24": { + "integrity": "b655a5beb26aa94f98add6bc8889f5fb9bc3ee2cc3fc954e151201f4c4200a5e", + "dependencies": [ + "jsr:@std/internal@^1.0.12" + ] }, "@std/crypto@1.0.5": { "integrity": "0dcfbb319fe0bba1bd3af904ceb4f948cde1b92979ec1614528380ed308a3b40" @@ -244,35 +250,38 @@ "@std/fmt@1.0.8": { "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" }, - "@std/fs@1.0.19": { - "integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06", + "@std/fs@1.0.20": { + "integrity": "e953206aae48d46ee65e8783ded459f23bec7dd1f3879512911c35e5484ea187", "dependencies": [ - "jsr:@std/internal@^1.0.9", - "jsr:@std/path@^1.1.1" + "jsr:@std/internal@^1.0.12", + "jsr:@std/path@^1.1.3" ] }, - "@std/html@1.0.4": { - "integrity": "eff3497c08164e6ada49b7f81a28b5108087033823153d065e3f89467dd3d50e" + "@std/html@1.0.5": { + "integrity": "4e2d693f474cae8c16a920fa5e15a3b72267b94b84667f11a50c6dd1cb18d35e" }, - "@std/http@1.0.20": { - "integrity": "b5cc33fc001bccce65ed4c51815668c9891c69ccd908295997e983d8f56070a1", + "@std/http@1.0.22": { + "integrity": "53f0bb70e23a2eec3e17c4240a85bb23d185b2e20635adb37ce0f03cc4ca012a", "dependencies": [ - "jsr:@std/cli@^1.0.21", + "jsr:@std/cli@^1.0.24", "jsr:@std/encoding@^1.0.10", "jsr:@std/fmt@^1.0.8", - "jsr:@std/fs@^1.0.19", + "jsr:@std/fs@^1.0.20", "jsr:@std/html", "jsr:@std/media-types", "jsr:@std/net", - "jsr:@std/path@^1.1.1", + "jsr:@std/path@^1.1.3", "jsr:@std/streams" ] }, - "@std/internal@1.0.10": { - "integrity": "e3be62ce42cab0e177c27698e5d9800122f67b766a0bea6ca4867886cbde8cf7" + "@std/internal@1.0.12": { + "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027" }, "@std/io@0.225.0": { - "integrity": "c1db7c5e5a231629b32d64b9a53139445b2ca640d828c26bf23e1c55f8c079b3", + "integrity": "c1db7c5e5a231629b32d64b9a53139445b2ca640d828c26bf23e1c55f8c079b3" + }, + "@std/io@0.225.2": { + "integrity": "3c740cd4ee4c082e6cfc86458f47e2ab7cb353dc6234d5e9b1f91a2de5f4d6c7", "dependencies": [ "jsr:@std/bytes" ] @@ -280,8 +289,8 @@ "@std/media-types@1.1.0": { "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" }, - "@std/net@1.0.5": { - "integrity": "b759d8c5e17d997e164af6379d57764668c6714f30109685eec0fd5e194d501a" + "@std/net@1.0.6": { + "integrity": "110735f93e95bb9feb95790a8b1d1bf69ec0dc74f3f97a00a76ea5efea25500c" }, "@std/path@0.217.0": { "integrity": "1217cc25534bca9a2f672d7fe7c6f356e4027df400c0e85c0ef3e4343bc67d11", @@ -289,31 +298,31 @@ "jsr:@std/assert@0.217" ] }, - "@std/path@1.1.2": { - "integrity": "c0b13b97dfe06546d5e16bf3966b1cadf92e1cc83e56ba5476ad8b498d9e3038", + "@std/path@1.1.3": { + "integrity": "b015962d82a5e6daea980c32b82d2c40142149639968549c649031a230b1afb3", "dependencies": [ - "jsr:@std/internal@^1.0.10" + "jsr:@std/internal@^1.0.12" ] }, - "@std/streams@1.0.11": { - "integrity": "db583d27e28d133f389f1eec318cffdf4998305e5134c1d4b1c56b361cee6018" + "@std/streams@1.0.14": { + "integrity": "c0df6cdd73bd4bbcbe4baa89e323b88418c90ceb2d926f95aa99bdcdbfca2411" }, - "@std/testing@1.0.15": { - "integrity": "a490169f5ccb0f3ae9c94fbc69d2cd43603f2cffb41713a85f99bbb0e3087cbc", + "@std/testing@1.0.16": { + "integrity": "a917ffdeb5924c9be436dc78bc32e511760e14d3a96e49c607fc5ecca86d0092", "dependencies": [ - "jsr:@std/assert@^1.0.13", - "jsr:@std/async@^1.0.13", + "jsr:@std/assert@^1.0.15", + "jsr:@std/async@^1.0.15", "jsr:@std/data-structures", "jsr:@std/fs@^1.0.19", - "jsr:@std/internal@^1.0.10", - "jsr:@std/path@^1.1.1" + "jsr:@std/internal@^1.0.12", + "jsr:@std/path@^1.1.2" ] }, "@std/text@1.0.16": { "integrity": "ddb9853b75119a2473857d691cf1ec02ad90793a2e8b4a4ac49d7354281a0cf8" }, - "@zip-js/zip-js@2.7.72": { - "integrity": "b72877f90aaefa1f1bd265d51f354bb58b6dd0d0e2799c865584acf49eae9115" + "@zip-js/zip-js@2.8.8": { + "integrity": "d02be7ef8707977e714cd24e045882f0b396dbcecfcabd7b591c5cdba40e47b7" } }, "npm": { @@ -325,47 +334,47 @@ "zod" ] }, - "@ai-sdk/anthropic@2.0.35_zod@3.25.76": { - "integrity": "sha512-R0HtYqnKhxH67qpfKJwPCzRJLeW6M/adFM0E4YyF2+m80UvaigmiVwEODcODHEhsA3hQdf1hLNXzq4AEbkz8xw==", + "@ai-sdk/anthropic@2.0.50_zod@3.25.76": { + "integrity": "sha512-21PaHfoLmouOXXNINTsZJsMw+wE5oLR2He/1kq/sKokTVKyq7ObGT1LDk6ahwxaz/GoaNaGankMh+EgVcdv2Cw==", "dependencies": [ "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "zod" ] }, - "@ai-sdk/gateway@2.0.0_zod@3.25.76": { - "integrity": "sha512-Gj0PuawK7NkZuyYgO/h5kDK/l6hFOjhLdTq3/Lli1FTl47iGmwhH1IZQpAL3Z09BeFYWakcwUmn02ovIm2wy9g==", + "@ai-sdk/gateway@2.0.17_zod@3.25.76": { + "integrity": "sha512-oVAG6q72KsjKlrYdLhWjRO7rcqAR8CjokAbYuyVZoCO4Uh2PH/VzZoxZav71w2ipwlXhHCNaInGYWNs889MMDA==", "dependencies": [ "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "@vercel/oidc", "zod" ] }, - "@ai-sdk/google-vertex@3.0.51_zod@3.25.76": { - "integrity": "sha512-0g/jGGm0nCSWZX8hXUWXYwDCYAd7gh12e0EVX5+BCHBJImk68Y80rjFGAgCr02I9qdFuQ9cH4Wf8dPtjwzizvA==", + "@ai-sdk/google-vertex@3.0.82_zod@3.25.76": { + "integrity": "sha512-G5drurtbYLdauF5ChNe5EnMnThrlM5qJoaW6RaBuuZbq1qR/kgaDZJ4A9ojx8RclHQ/t5hD6e9A+j447udskhw==", "dependencies": [ - "@ai-sdk/anthropic@2.0.35_zod@3.25.76", + "@ai-sdk/anthropic@2.0.50_zod@3.25.76", "@ai-sdk/google", "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "google-auth-library", "zod" ] }, - "@ai-sdk/google@2.0.23_zod@3.25.76": { - "integrity": "sha512-VbCnKR+6aWUVLkAiSW5gUEtST7KueEmlt+d6qwDikxlLnFG9pzy59je8MiDVeM5G2tuSXbvZQF78PGIfXDBmow==", + "@ai-sdk/google@2.0.44_zod@3.25.76": { + "integrity": "sha512-c5dck36FjqiVoeeMJQLTEmUheoURcGTU/nBT6iJu8/nZiKFT/y8pD85KMDRB7RerRYaaQOtslR2d6/5PditiRw==", "dependencies": [ "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "zod" ] }, - "@ai-sdk/groq@2.0.24_zod@3.25.76": { - "integrity": "sha512-PCtNwFsakxR6B/o+l3gtxlPIwN8lawK3vvOjRdC759Y8WtNxCv5RUs0JsxIKyAZxO+RBEy0AoL8xTQUy8fn3gw==", + "@ai-sdk/groq@2.0.32_zod@3.25.76": { + "integrity": "sha512-5kadf9Mjd4Ep6jVhrIy56UL7DV5HDisW8UakwB11IN7lSLi8Qwb1fB9uO34GT7JxYqE4w7qZXVuelOmTH9m2Mg==", "dependencies": [ "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "zod" ] }, @@ -377,11 +386,11 @@ "zod" ] }, - "@ai-sdk/openai@2.0.53_zod@3.25.76": { - "integrity": "sha512-GIkR3+Fyif516ftXv+YPSPstnAHhcZxNoR2s8uSHhQ1yBT7I7aQYTVwpjAuYoT3GR+TeP50q7onj2/nDRbT2FQ==", + "@ai-sdk/openai@2.0.75_zod@3.25.76": { + "integrity": "sha512-ThDHg1+Jes7S0AOXa01EyLBSzZiZwzB5do9vAlufNkoiRHGTH1BmoShrCyci/TUsg4ky1HwbK4hPK+Z0isiE6g==", "dependencies": [ "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "zod" ] }, @@ -394,8 +403,8 @@ "zod" ] }, - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76": { - "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76": { + "integrity": "sha512-ypv1xXMsgGcNKUP+hglKqtdDuMg68nWHucPPAhIENrbFAI+xCHiqPVN8Zllxyv1TNZwGWUghPxJXU+Mqps0YRQ==", "dependencies": [ "@ai-sdk/provider@2.0.0", "@standard-schema/spec", @@ -415,8 +424,8 @@ "json-schema" ] }, - "@arizeai/openinference-core@1.0.7_@opentelemetry+api@1.9.0": { - "integrity": "sha512-O9WYkrHNh/0mGTV+T9SWC3tkxVrT16gBrFiByG3aukBsqdOfSzoRj6QINk+Oi+VEDNIoQUzVQPFh81/gEL/thA==", + "@arizeai/openinference-core@2.0.0_@opentelemetry+api@1.9.0": { + "integrity": "sha512-H0INw5Yy0zHUe0HG0ZMVoexrBX/B1W6FJODmnIP7vbXHXOzzMtlBdjg0evxFY2HTSk+MRpVpDP05Ty+OSqfd0w==", "dependencies": [ "@arizeai/openinference-semantic-conventions@2.1.2", "@opentelemetry/api", @@ -429,8 +438,8 @@ "@arizeai/openinference-semantic-conventions@2.1.2": { "integrity": "sha512-u7UeuU9bJ1LxzHk0MPWb+1ZcotCcJwPnKDXi7Rl2cPs1pWMFg9Ogq7zzYZX+sDcibD2AEa1U+ElyOD8DwZc9gw==" }, - "@arizeai/openinference-vercel@2.3.4_@opentelemetry+api@1.9.0": { - "integrity": "sha512-oQY5dhXMmJev37yziHhTnzQaI2DO8YfRVQWsarh2o26EBKOdOir8rfOm0IjQXJuR9fGNj5sSiQ45obia7EdXXw==", + "@arizeai/openinference-vercel@2.5.0_@opentelemetry+api@1.9.0": { + "integrity": "sha512-7bAQnx6Gfr2mzSTcVFeErDyWQklVBRNOxz8B4izSnqxx5koNVgf035KMRmHAXHO5sKIfA4Z5gwtf6+Q3L9cYJw==", "dependencies": [ "@arizeai/openinference-core", "@arizeai/openinference-semantic-conventions@2.1.2", @@ -445,8 +454,8 @@ "zod" ] }, - "@codemirror/autocomplete@6.19.0": { - "integrity": "sha512-61Hfv3cF07XvUxNeC3E7jhG8XNi1Yom1G0lRC936oLnlF+jrbrv8rc/J98XlYzcsAoTVupfsf5fLej1aI8kyIg==", + "@codemirror/autocomplete@6.20.0": { + "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", "dependencies": [ "@codemirror/language", "@codemirror/state", @@ -454,8 +463,8 @@ "@lezer/common" ] }, - "@codemirror/commands@6.9.0": { - "integrity": "sha512-454TVgjhO6cMufsyyGN70rGIfJxJEjcqjBG2x2Y03Y/+Fm99d3O/Kv1QDYWuG6hvxsgmjXmBuATikIIYvERX+w==", + "@codemirror/commands@6.10.0": { + "integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==", "dependencies": [ "@codemirror/language", "@codemirror/state", @@ -506,8 +515,8 @@ "@lezer/json" ] }, - "@codemirror/lang-markdown@6.4.0": { - "integrity": "sha512-ZeArR54seh4laFbUTVy0ZmQgO+C/cxxlW4jEoQMhL3HALScBpZBeZcLzrQmJsTEx4is9GzOe0bFAke2B1KZqeA==", + "@codemirror/lang-markdown@6.5.0": { + "integrity": "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==", "dependencies": [ "@codemirror/autocomplete", "@codemirror/lang-html", @@ -529,8 +538,8 @@ "style-mod" ] }, - "@codemirror/lint@6.9.0": { - "integrity": "sha512-wZxW+9XDytH3SKvS8cQzMyQCaaazH8XL1EMHleHe00wVzsv7NBQKVW2yzEHrRhmM7ZOhVdItPbvlRBvMp9ej7A==", + "@codemirror/lint@6.9.2": { + "integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==", "dependencies": [ "@codemirror/state", "@codemirror/view", @@ -560,8 +569,8 @@ "@lezer/highlight" ] }, - "@codemirror/view@6.38.6": { - "integrity": "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==", + "@codemirror/view@6.38.8": { + "integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==", "dependencies": [ "@codemirror/state", "crelt", @@ -569,152 +578,152 @@ "w3c-keyname" ] }, - "@esbuild/aix-ppc64@0.25.11": { - "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "@esbuild/aix-ppc64@0.25.12": { + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "os": ["aix"], "cpu": ["ppc64"] }, - "@esbuild/android-arm64@0.25.11": { - "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "@esbuild/android-arm64@0.25.12": { + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "os": ["android"], "cpu": ["arm64"] }, - "@esbuild/android-arm@0.25.11": { - "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "@esbuild/android-arm@0.25.12": { + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "os": ["android"], "cpu": ["arm"] }, - "@esbuild/android-x64@0.25.11": { - "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "@esbuild/android-x64@0.25.12": { + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "os": ["android"], "cpu": ["x64"] }, - "@esbuild/darwin-arm64@0.25.11": { - "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "@esbuild/darwin-arm64@0.25.12": { + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "os": ["darwin"], "cpu": ["arm64"] }, - "@esbuild/darwin-x64@0.25.11": { - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "@esbuild/darwin-x64@0.25.12": { + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "os": ["darwin"], "cpu": ["x64"] }, - "@esbuild/freebsd-arm64@0.25.11": { - "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "@esbuild/freebsd-arm64@0.25.12": { + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "os": ["freebsd"], "cpu": ["arm64"] }, - "@esbuild/freebsd-x64@0.25.11": { - "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "@esbuild/freebsd-x64@0.25.12": { + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "os": ["freebsd"], "cpu": ["x64"] }, - "@esbuild/linux-arm64@0.25.11": { - "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "@esbuild/linux-arm64@0.25.12": { + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "os": ["linux"], "cpu": ["arm64"] }, - "@esbuild/linux-arm@0.25.11": { - "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "@esbuild/linux-arm@0.25.12": { + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "os": ["linux"], "cpu": ["arm"] }, - "@esbuild/linux-ia32@0.25.11": { - "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "@esbuild/linux-ia32@0.25.12": { + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "os": ["linux"], "cpu": ["ia32"] }, - "@esbuild/linux-loong64@0.25.11": { - "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "@esbuild/linux-loong64@0.25.12": { + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "os": ["linux"], "cpu": ["loong64"] }, - "@esbuild/linux-mips64el@0.25.11": { - "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "@esbuild/linux-mips64el@0.25.12": { + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "os": ["linux"], "cpu": ["mips64el"] }, - "@esbuild/linux-ppc64@0.25.11": { - "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "@esbuild/linux-ppc64@0.25.12": { + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "os": ["linux"], "cpu": ["ppc64"] }, - "@esbuild/linux-riscv64@0.25.11": { - "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "@esbuild/linux-riscv64@0.25.12": { + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "os": ["linux"], "cpu": ["riscv64"] }, - "@esbuild/linux-s390x@0.25.11": { - "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "@esbuild/linux-s390x@0.25.12": { + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "os": ["linux"], "cpu": ["s390x"] }, - "@esbuild/linux-x64@0.25.11": { - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "@esbuild/linux-x64@0.25.12": { + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "os": ["linux"], "cpu": ["x64"] }, - "@esbuild/netbsd-arm64@0.25.11": { - "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "@esbuild/netbsd-arm64@0.25.12": { + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "os": ["netbsd"], "cpu": ["arm64"] }, - "@esbuild/netbsd-x64@0.25.11": { - "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "@esbuild/netbsd-x64@0.25.12": { + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "os": ["netbsd"], "cpu": ["x64"] }, - "@esbuild/openbsd-arm64@0.25.11": { - "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "@esbuild/openbsd-arm64@0.25.12": { + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "os": ["openbsd"], "cpu": ["arm64"] }, - "@esbuild/openbsd-x64@0.25.11": { - "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "@esbuild/openbsd-x64@0.25.12": { + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "os": ["openbsd"], "cpu": ["x64"] }, - "@esbuild/openharmony-arm64@0.25.11": { - "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "@esbuild/openharmony-arm64@0.25.12": { + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "os": ["openharmony"], "cpu": ["arm64"] }, - "@esbuild/sunos-x64@0.25.11": { - "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "@esbuild/sunos-x64@0.25.12": { + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "os": ["sunos"], "cpu": ["x64"] }, - "@esbuild/win32-arm64@0.25.11": { - "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "@esbuild/win32-arm64@0.25.12": { + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "os": ["win32"], "cpu": ["arm64"] }, - "@esbuild/win32-ia32@0.25.11": { - "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "@esbuild/win32-ia32@0.25.12": { + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "os": ["win32"], "cpu": ["ia32"] }, - "@esbuild/win32-x64@0.25.11": { - "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "@esbuild/win32-x64@0.25.12": { + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "os": ["win32"], "cpu": ["x64"] }, - "@fal-ai/client@1.7.0": { - "integrity": "sha512-lZ1KuLc4iqBalIqwlQGJLBD2pfAmWQqM8pvT2clqhU8FjPrZxLBNnAWiQsaB3b7GXzItSA1C6k5W8TfUJPT5eA==", + "@fal-ai/client@1.7.2": { + "integrity": "sha512-RZ1Qz2Kza4ExKPy2D+2UUWthNApe+oZe8D1Wcxqleyn4F344MOm8ibgqG2JSVmybEcJAD4q44078WYfb6Q9c6w==", "dependencies": [ "@msgpack/msgpack", "eventsource-parser@1.1.2", "robot3" ] }, - "@hono/sentry@1.2.2_hono@4.10.1": { + "@hono/sentry@1.2.2_hono@4.10.7": { "integrity": "sha512-027grZBrRGDPor8mRd+QOBcSpUlF07YrTp/WFDXZhbvWZ+1LrZdERUqcdg1gBGDUTanHhd9ucblpNNN6+V1bxg==", "dependencies": [ "hono", "toucan-js" ] }, - "@hono/zod-openapi@0.18.4_hono@4.10.1_zod@3.25.76": { + "@hono/zod-openapi@0.18.4_hono@4.10.7_zod@3.25.76": { "integrity": "sha512-6NHMHU96Hh32B1yDhb94Z4Z5/POsmEu2AXpWLWcBq9arskRnOMt2752yEoXoADV8WUAc7H1IkNaQHGj1ytXbYw==", "dependencies": [ "@asteasolutions/zod-to-openapi", @@ -723,13 +732,24 @@ "zod" ] }, - "@hono/zod-validator@0.4.3_hono@4.10.1_zod@3.25.76": { + "@hono/zod-validator@0.4.3_hono@4.10.7_zod@3.25.76": { "integrity": "sha512-xIgMYXDyJ4Hj6ekm9T9Y27s080Nl9NXHcJkOvkXPhubOLj8hZkOL8pDnnXfvCf5xEE8Q4oMFenQUZZREUY2gqQ==", "dependencies": [ "hono", "zod" ] }, + "@isaacs/cliui@8.0.2": { + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": [ + "string-width@5.1.2", + "string-width-cjs@npm:string-width@4.2.3", + "strip-ansi@7.1.2", + "strip-ansi-cjs@npm:strip-ansi@6.0.1", + "wrap-ansi@8.1.0", + "wrap-ansi-cjs@npm:wrap-ansi@7.0.0" + ] + }, "@jitl/quickjs-ffi-types@0.31.0": { "integrity": "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw==" }, @@ -739,8 +759,8 @@ "@jitl/quickjs-ffi-types" ] }, - "@lezer/common@1.3.0": { - "integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==" + "@lezer/common@1.4.0": { + "integrity": "sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==" }, "@lezer/css@1.3.0": { "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", @@ -750,8 +770,8 @@ "@lezer/lr" ] }, - "@lezer/highlight@1.2.2": { - "integrity": "sha512-z8TQwaBXXQIvG6i2g3e9cgMwUUXu9Ib7jo2qRRggdhwKpM56Dw3PM3wmexn+EGaaOZ7az0K7sjc3/gcGW7sz7A==", + "@lezer/highlight@1.2.3": { + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", "dependencies": [ "@lezer/common" ] @@ -780,14 +800,14 @@ "@lezer/lr" ] }, - "@lezer/lr@1.4.2": { - "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "@lezer/lr@1.4.4": { + "integrity": "sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==", "dependencies": [ "@lezer/common" ] }, - "@lezer/markdown@1.5.1": { - "integrity": "sha512-F3ZFnIfNAOy/jPSk6Q0e3bs7e9grfK/n5zerkKoc5COH6Guy3Zb0vrJwXzdck79K16goBhYBRAvhf+ksqe0cMg==", + "@lezer/markdown@1.6.0": { + "integrity": "sha512-AXb98u3M6BEzTnreBnGtQaF7xFTiMA92Dsy5tqEjpacbjRxDSFdN4bKJo9uvU4cEEOS7D2B9MT7kvDgOEIzJSw==", "dependencies": [ "@lezer/common", "@lezer/highlight" @@ -960,12 +980,15 @@ "@opentelemetry/semantic-conventions@1.28.0": { "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==" }, - "@opentelemetry/semantic-conventions@1.37.0": { - "integrity": "sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==" + "@opentelemetry/semantic-conventions@1.38.0": { + "integrity": "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==" }, "@pinojs/redact@0.4.0": { "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" }, + "@pkgjs/parseargs@0.11.0": { + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" + }, "@protobufjs/aspromise@1.1.2": { "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" }, @@ -1006,7 +1029,7 @@ "@scalar/types" ] }, - "@scalar/hono-api-reference@0.5.184_hono@4.10.1": { + "@scalar/hono-api-reference@0.5.184_hono@4.10.7": { "integrity": "sha512-vRSRwJkN1Xo5dW9KYQJlGpKZ+Nh9qH+x1sn0qf6/Lx8QLPyyEpNm1EEddKaIN6qd5wrtVjDN6adQhfAfcYGHzw==", "dependencies": [ "@scalar/core", @@ -1041,13 +1064,13 @@ "@sentry/utils" ] }, - "@sentry/core@9.46.0": { - "integrity": "sha512-it7JMFqxVproAgEtbLgCVBYtQ9fIb+Bu0JD+cEplTN/Ukpe6GaolyYib5geZqslVxhp2sQgT+58aGvfd/k0N8Q==" + "@sentry/core@9.47.1": { + "integrity": "sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==" }, - "@sentry/deno@9.46.0": { - "integrity": "sha512-MuwYMsjVEdiREOze+t+PJeR2EQIaFSAGUGPedhFZAaiDYsRwQeqWJ2Rj2hmKWQPbwcp8NA7CphaHlctLPR+wpw==", + "@sentry/deno@9.47.1": { + "integrity": "sha512-PR73ajdXCX6nCpXB3WrimYZ+VAGHXkmLLmAMCFG4pmEJ3lLt+gmdHPSCX0n+hiK67R/8GVpYsNErcFp+IDP91w==", "dependencies": [ - "@sentry/core@9.46.0" + "@sentry/core@9.47.1" ] }, "@sentry/types@8.9.2": { @@ -1065,13 +1088,7 @@ "@types/node@24.2.0": { "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==", "dependencies": [ - "undici-types@7.10.0" - ] - }, - "@types/node@24.9.1": { - "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", - "dependencies": [ - "undici-types@7.16.0" + "undici-types" ] }, "@types/trusted-types@2.0.7": { @@ -1084,18 +1101,18 @@ "zhead" ] }, - "@vercel/oidc@3.0.3": { - "integrity": "sha512-yNEQvPcVrK9sIe637+I0jD6leluPxzwJKx/Haw6F4H77CdDsszUn5V3o96LPziXkSNE2B83+Z3mjqGKBK/R6Gg==" + "@vercel/oidc@3.0.5": { + "integrity": "sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==" }, "agent-base@7.1.4": { "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==" }, - "ai@5.0.76_zod@3.25.76": { - "integrity": "sha512-ZCxi1vrpyCUnDbtYrO/W8GLvyacV9689f00yshTIQ3mFFphbD7eIv40a2AOZBv3GGRA7SSRYIDnr56wcS/gyQg==", + "ai@5.0.104_zod@3.25.76": { + "integrity": "sha512-MZOkL9++nY5PfkpWKBR3Rv+Oygxpb9S16ctv8h91GvrSif7UnNEdPMVZe3bUyMd2djxf0AtBk/csBixP0WwWZQ==", "dependencies": [ "@ai-sdk/gateway", "@ai-sdk/provider@2.0.0", - "@ai-sdk/provider-utils@3.0.12_zod@3.25.76", + "@ai-sdk/provider-utils@3.0.18_zod@3.25.76", "@opentelemetry/api", "zod" ] @@ -1109,26 +1126,50 @@ "require-from-string" ] }, + "ansi-regex@5.0.1": { + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-regex@6.2.2": { + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==" + }, + "ansi-styles@4.3.0": { + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": [ + "color-convert" + ] + }, + "ansi-styles@6.2.3": { + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==" + }, "asynckit@0.4.0": { "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "atomic-sleep@1.0.0": { "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, - "axios@1.12.2": { - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "axios@1.13.2": { + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "dependencies": [ "follow-redirects", "form-data", "proxy-from-env" ] }, + "balanced-match@1.0.2": { + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "base64-js@1.5.1": { "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bignumber.js@9.3.1": { "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==" }, + "brace-expansion@2.0.2": { + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dependencies": [ + "balanced-match" + ] + }, "buffer-equal-constant-time@1.0.1": { "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, @@ -1151,6 +1192,15 @@ "@codemirror/view" ] }, + "color-convert@2.0.1": { + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": [ + "color-name" + ] + }, + "color-name@1.1.4": { + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "colorette@2.0.20": { "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" }, @@ -1163,6 +1213,17 @@ "crelt@1.0.6": { "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" }, + "cross-spawn@7.0.6": { + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dependencies": [ + "path-key", + "shebang-command", + "which" + ] + }, + "data-uri-to-buffer@4.0.1": { + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, "dateformat@4.6.3": { "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" }, @@ -1211,12 +1272,21 @@ "gopd" ] }, + "eastasianwidth@0.2.0": { + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "ecdsa-sig-formatter@1.0.11": { "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "dependencies": [ "safe-buffer" ] }, + "emoji-regex@8.0.0": { + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emoji-regex@9.2.2": { + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, "end-of-stream@1.4.5": { "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "dependencies": [ @@ -1250,8 +1320,8 @@ "hasown" ] }, - "esbuild@0.25.11": { - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "esbuild@0.25.12": { + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "optionalDependencies": [ "@esbuild/aix-ppc64", "@esbuild/android-arm", @@ -1304,11 +1374,25 @@ "fast-uri@3.1.0": { "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==" }, + "fetch-blob@3.2.0": { + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dependencies": [ + "node-domexception", + "web-streams-polyfill" + ] + }, "follow-redirects@1.15.11": { "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==" }, - "form-data@4.0.4": { - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "foreground-child@3.3.1": { + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dependencies": [ + "cross-spawn", + "signal-exit" + ] + }, + "form-data@4.0.5": { + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dependencies": [ "asynckit", "combined-stream", @@ -1317,6 +1401,12 @@ "mime-types" ] }, + "formdata-polyfill@4.0.10": { + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": [ + "fetch-blob" + ] + }, "function-bind@1.1.2": { "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, @@ -1326,14 +1416,31 @@ "extend", "https-proxy-agent", "is-stream", - "node-fetch", + "node-fetch@2.7.0", "uuid" ] }, + "gaxios@7.1.3": { + "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", + "dependencies": [ + "extend", + "https-proxy-agent", + "node-fetch@3.3.2", + "rimraf" + ] + }, "gcp-metadata@6.1.0": { "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", "dependencies": [ - "gaxios", + "gaxios@6.7.1", + "json-bigint" + ] + }, + "gcp-metadata@8.1.2": { + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "dependencies": [ + "gaxios@7.1.3", + "google-logging-utils", "json-bigint" ] }, @@ -1359,24 +1466,40 @@ "es-object-atoms" ] }, - "google-auth-library@9.15.1": { - "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "glob@10.5.0": { + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dependencies": [ + "foreground-child", + "jackspeak", + "minimatch", + "minipass", + "package-json-from-dist", + "path-scurry" + ], + "bin": true + }, + "google-auth-library@10.5.0": { + "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==", "dependencies": [ "base64-js", "ecdsa-sig-formatter", - "gaxios", - "gcp-metadata", + "gaxios@7.1.3", + "gcp-metadata@8.1.2", + "google-logging-utils", "gtoken", "jws" ] }, + "google-logging-utils@1.1.3": { + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==" + }, "gopd@1.2.0": { "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, - "gtoken@7.1.0": { - "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "gtoken@8.0.0": { + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", "dependencies": [ - "gaxios", + "gaxios@7.1.3", "jws" ] }, @@ -1398,7 +1521,7 @@ "help-me@5.0.0": { "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" }, - "hono-pino@0.7.2_hono@4.10.1_pino@9.14.0": { + "hono-pino@0.7.2_hono@4.10.7_pino@9.14.0": { "integrity": "sha512-uLJOngId4Ia2eHXnCPE8xpyMVkh+AGxAkHZKgvZk8YkmuTbcVDDUMe7aHMEz+YLqCDgd/Hk9ytVmmoQ8QTUXgQ==", "dependencies": [ "defu", @@ -1406,8 +1529,8 @@ "pino" ] }, - "hono@4.10.1": { - "integrity": "sha512-rpGNOfacO4WEPClfkEt1yfl8cbu10uB1lNpiI33AKoiAHwOS8lV748JiLx4b5ozO/u4qLjIvfpFsPXdY5Qjkmg==" + "hono@4.10.7": { + "integrity": "sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw==" }, "hookable@5.5.3": { "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" @@ -1428,9 +1551,24 @@ "debug" ] }, + "is-fullwidth-code-point@3.0.0": { + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, "is-stream@2.0.1": { "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, + "isexe@2.0.0": { + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "jackspeak@3.4.3": { + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": [ + "@isaacs/cliui" + ], + "optionalDependencies": [ + "@pkgjs/parseargs" + ] + }, "joycon@3.1.1": { "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" }, @@ -1499,6 +1637,9 @@ "lotto-draw@1.0.2": { "integrity": "sha512-1ih414A35BWpApfNlWAHBKOBLSxTj45crAJ+CMWF/kVY5nx6N22DA1OVF/FWW5WM5CGJbIMRh1O+xe8ukyoQ8Q==" }, + "lru-cache@10.4.3": { + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, "marked@4.3.0": { "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "bin": true @@ -1522,9 +1663,18 @@ "mime-db" ] }, + "minimatch@9.0.5": { + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": [ + "brace-expansion" + ] + }, "minimist@1.2.8": { "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, + "minipass@7.1.2": { + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" + }, "mistreevous@4.2.0": { "integrity": "sha512-ZlqX7Fp2O/wYG9QFIT/I1bRDBi6o2ko4S006/G17VT0YWgN1emVMJNAcNSxfD0u4Tg/HOfHziJe+J4L7Un7spA==", "dependencies": [ @@ -1541,12 +1691,24 @@ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "bin": true }, + "node-domexception@1.0.0": { + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": true + }, "node-fetch@2.7.0": { "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": [ "whatwg-url" ] }, + "node-fetch@3.3.2": { + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": [ + "data-uri-to-buffer", + "fetch-blob", + "formdata-polyfill" + ] + }, "on-exit-leak-free@2.1.2": { "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" }, @@ -1562,6 +1724,19 @@ "yaml" ] }, + "package-json-from-dist@1.0.1": { + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + }, + "path-key@3.1.1": { + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-scurry@1.11.1": { + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": [ + "lru-cache", + "minipass" + ] + }, "pino-abstract-transport@2.0.0": { "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", "dependencies": [ @@ -1629,7 +1804,7 @@ "@protobufjs/path", "@protobufjs/pool", "@protobufjs/utf8", - "@types/node@24.9.1", + "@types/node", "long" ], "scripts": true @@ -1659,6 +1834,13 @@ "require-from-string@2.0.2": { "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, + "rimraf@5.0.10": { + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dependencies": [ + "glob" + ], + "bin": true + }, "robot3@0.4.1": { "integrity": "sha512-hzjy826lrxzx8eRgv80idkf8ua1JAepRc9Efdtj03N3KNJuznQCPlyCJ7gnUmDFwZCLQjxy567mQVKmdv2BsXQ==" }, @@ -1674,6 +1856,18 @@ "secure-json-parse@4.1.0": { "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==" }, + "shebang-command@2.0.0": { + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": [ + "shebang-regex" + ] + }, + "shebang-regex@3.0.0": { + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit@4.1.0": { + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" + }, "sonic-boom@4.2.0": { "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", "dependencies": [ @@ -1686,7 +1880,7 @@ "split2@4.2.0": { "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" }, - "stoker@1.4.3_@hono+zod-openapi@0.18.4__hono@4.10.1__zod@3.25.76_hono@4.10.1_zod@3.25.76": { + "stoker@1.4.3_@hono+zod-openapi@0.18.4__hono@4.10.7__zod@3.25.76_hono@4.10.7_zod@3.25.76": { "integrity": "sha512-kijg+1PKUY6laFbNcY7hw5OPgg3QhWD+2wAZsk35IqiZfVwU3S/E3DYbemecRT7vdWbWrZ2mzewQrqD4zoJSeQ==", "dependencies": [ "@hono/zod-openapi", @@ -1696,6 +1890,34 @@ "@hono/zod-openapi" ] }, + "string-width@4.2.3": { + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": [ + "emoji-regex@8.0.0", + "is-fullwidth-code-point", + "strip-ansi@6.0.1" + ] + }, + "string-width@5.1.2": { + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": [ + "eastasianwidth", + "emoji-regex@9.2.2", + "strip-ansi@7.1.2" + ] + }, + "strip-ansi@6.0.1": { + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": [ + "ansi-regex@5.0.1" + ] + }, + "strip-ansi@7.1.2": { + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dependencies": [ + "ansi-regex@6.2.2" + ] + }, "strip-json-comments@5.0.3": { "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==" }, @@ -1719,8 +1941,8 @@ "tr46@0.0.3": { "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "turndown@7.2.1": { - "integrity": "sha512-7YiPJw6rLClQL3oUKN3KgMaXeJJ2lAyZItclgKDurqnH61so4k4IH/qwmMva0zpuJc/FhRExBBnk7EbeFANlgQ==", + "turndown@7.2.2": { + "integrity": "sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==", "dependencies": [ "@mixmark-io/domino" ] @@ -1732,9 +1954,6 @@ "undici-types@7.10.0": { "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==" }, - "undici-types@7.16.0": { - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" - }, "uuid@9.0.1": { "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "bin": true @@ -1742,6 +1961,9 @@ "w3c-keyname@2.2.8": { "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" }, + "web-streams-polyfill@3.3.3": { + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + }, "webidl-conversions@3.0.1": { "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, @@ -1752,11 +1974,34 @@ "webidl-conversions" ] }, + "which@2.0.2": { + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": [ + "isexe" + ], + "bin": true + }, + "wrap-ansi@7.0.0": { + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": [ + "ansi-styles@4.3.0", + "string-width@4.2.3", + "strip-ansi@6.0.1" + ] + }, + "wrap-ansi@8.1.0": { + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": [ + "ansi-styles@6.2.3", + "string-width@5.1.2", + "strip-ansi@7.1.2" + ] + }, "wrappy@1.0.2": { "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "yaml@2.8.1": { - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "yaml@2.8.2": { + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "bin": true }, "zhead@2.2.4": { @@ -1767,14 +2012,14 @@ } }, "redirects": { - "https://esm.sh/core-js/proposals/async-explicit-resource-management": "https://esm.sh/core-js@3.44.0/proposals/async-explicit-resource-management", - "https://esm.sh/core-js/proposals/explicit-resource-management": "https://esm.sh/core-js@3.44.0/proposals/explicit-resource-management" + "https://esm.sh/core-js/proposals/async-explicit-resource-management": "https://esm.sh/core-js@3.46.0/proposals/async-explicit-resource-management", + "https://esm.sh/core-js/proposals/explicit-resource-management": "https://esm.sh/core-js@3.46.0/proposals/explicit-resource-management" }, "remote": { - "https://esm.sh/core-js@3.44.0/denonext/proposals/async-explicit-resource-management.mjs": "8fc19e1aaec982c8920a598a2e5cdc01a865f65bee8421b04edd7e5bb6c45564", - "https://esm.sh/core-js@3.44.0/denonext/proposals/explicit-resource-management.mjs": "4850503a2650ba47368eb95b1aa2565b47bad32efe9738766811f6de75cf51e1", - "https://esm.sh/core-js@3.44.0/proposals/async-explicit-resource-management": "7298a78cddda0e6a5f0ee8cf6fd3ca963e7820daa5553469c2a52ead4be1cdb1", - "https://esm.sh/core-js@3.44.0/proposals/explicit-resource-management": "06969d679705ab37fd058cc66a50cd7648f79bf5fd86fb13b29cb93c2667ebc7" + "https://esm.sh/core-js@3.46.0/denonext/proposals/async-explicit-resource-management.mjs": "d75be20fbac6aec6a9c3f5f920641d135a9ece80b474fd17ff282e1288043d76", + "https://esm.sh/core-js@3.46.0/denonext/proposals/explicit-resource-management.mjs": "1936f377fc4661bb73186bb84ac36b5738292ce47a0d95d0c3319c76c14ac83a", + "https://esm.sh/core-js@3.46.0/proposals/async-explicit-resource-management": "d19beff9fe2de3d50ee7b1ca3bd3a6310a624bf5e9da1dbd1f33f35f3fd2d9e0", + "https://esm.sh/core-js@3.46.0/proposals/explicit-resource-management": "11d87cba9ddb54b26ccee520857be53bff360633550e74045896e4da1c6c9e61" }, "workspace": { "dependencies": [ @@ -1882,12 +2127,12 @@ "npm:@hono/zod-openapi@~0.18.3", "npm:@hono/zod-validator@~0.4.2", "npm:@opentelemetry/api@^1.7.0", - "npm:@opentelemetry/context-async-hooks@^1.19.0", - "npm:@opentelemetry/core@^1.19.0", + "npm:@opentelemetry/context-async-hooks@^1.30.0", + "npm:@opentelemetry/core@^1.30.0", "npm:@opentelemetry/exporter-trace-otlp-proto@0.46", - "npm:@opentelemetry/resources@^1.19.0", - "npm:@opentelemetry/sdk-trace-base@^1.19.0", - "npm:@opentelemetry/semantic-conventions@^1.19.0", + "npm:@opentelemetry/resources@^1.30.0", + "npm:@opentelemetry/sdk-trace-base@^1.30.0", + "npm:@opentelemetry/semantic-conventions@^1.30.0", "npm:@scalar/hono-api-reference@~0.5.165", "npm:@sentry/deno@^9.3.0", "npm:ai@^5.0.27", diff --git a/packages/charm/src/manager.ts b/packages/charm/src/manager.ts index 2979aafbe5..a4a290040f 100644 --- a/packages/charm/src/manager.ts +++ b/packages/charm/src/manager.ts @@ -157,7 +157,12 @@ export class CharmManager { ); // Use the space DID as the cause - it's derived from the space name // and consistently available everywhere - this.spaceCell = this.runtime.getSpaceCell(this.space); + // For home space (where space DID = user identity DID), getHomeSpaceCell() + // uses homeSpaceCellSchema which includes favorites for proper sync/query behavior. + const isHomeSpace = this.space === this.runtime.userIdentityDID; + this.spaceCell = isHomeSpace + ? this.runtime.getHomeSpaceCell() + : this.runtime.getSpaceCell(this.space); const syncSpaceCell = Promise.resolve(this.spaceCell.sync()); diff --git a/packages/html/src/jsx.d.ts b/packages/html/src/jsx.d.ts index ef4f2c8489..a000d574ad 100644 --- a/packages/html/src/jsx.d.ts +++ b/packages/html/src/jsx.d.ts @@ -2888,7 +2888,9 @@ interface CTToolbarElement extends CTHTMLElement {} interface CTKbdElement extends CTHTMLElement {} interface CTKeybindElement extends CTHTMLElement {} interface CTRenderElement extends CTHTMLElement {} +interface CTCellContextElement extends CTHTMLElement {} interface CTChatMessageElement extends CTHTMLElement {} +interface CTMarkdownElement extends CTHTMLElement {} interface CTVScrollElement extends CTHTMLElement {} interface CTSendMessageElement extends CTHTMLElement {} interface CTTextElement extends CTHTMLElement {} @@ -3107,6 +3109,13 @@ interface CTChatMessageAttributes extends CTHTMLAttributes { "pending"?: boolean; } +interface CTMarkdownAttributes extends CTHTMLAttributes { + "content"?: string; + "$content"?: CellLike; + "variant"?: "default" | "inverse"; + "streaming"?: boolean; +} + interface CTButtonAttributes extends CTHTMLAttributes { "variant"?: | "default" @@ -3148,6 +3157,12 @@ interface CTRenderAttributes extends CTHTMLAttributes { "$cell": CellLike; } +interface CTCellContextAttributes extends CTHTMLAttributes { + "$cell": CellLike; + "label"?: string; + "inline"?: boolean; +} + interface CTListAttributes extends CTHTMLAttributes { "$value": CellLike; /** setting this allows editing items inline */ @@ -3847,6 +3862,10 @@ declare global { CTChatMessageAttributes, CTChatMessageElement >; + "ct-markdown": CTDOM.DetailedHTMLProps< + CTMarkdownAttributes, + CTMarkdownElement + >; "ct-card": CTDOM.DetailedHTMLProps< CTHTMLAttributes, CTCardElement @@ -3867,6 +3886,10 @@ declare global { CTRenderAttributes, CTRenderElement >; + "ct-cell-context": CTDOM.DetailedHTMLProps< + CTCellContextAttributes, + CTCellContextElement + >; "ct-vscroll": CTDOM.DetailedHTMLProps< CTScrollAttributes, CTVScrollElement diff --git a/packages/html/src/render.ts b/packages/html/src/render.ts index 12881023d3..7a21592431 100644 --- a/packages/html/src/render.ts +++ b/packages/html/src/render.ts @@ -21,6 +21,8 @@ export type SetPropHandler = ( export interface RenderOptions { setProp?: SetPropHandler; document?: Document; + /** The root cell for auto-wrapping with ct-cell-context on [UI] traversal */ + rootCell?: Cell; } export const vdomSchema: JSONSchema = { @@ -63,13 +65,20 @@ export const render = ( ): Cancel => { // Initialize visited set with the original cell for cycle detection const visited = new Set(); + let rootCell: Cell | undefined; + if (isCell(view)) { visited.add(view); + rootCell = view; // Capture the original cell for ct-cell-context wrapping view = view.asSchema(vdomSchema); } + + // Pass rootCell through options if we have one + const optionsWithCell = rootCell ? { ...options, rootCell } : options; + return effect( view, - (view: VNode) => renderImpl(parent, view, options, visited), + (view: VNode) => renderImpl(parent, view, optionsWithCell, visited), ); }; @@ -141,6 +150,10 @@ const renderNode = ( const document = options.document ?? globalThis.document; + // Check if we should wrap with ct-cell-context (when traversing [UI] with a rootCell) + const shouldWrapWithContext = node[UI] && options.rootCell; + const cellForContext = shouldWrapWithContext ? options.rootCell : undefined; + // Follow `[UI]` to actual vdom. Do this before otherwise parsing the vnode, // so that if there are both, the `[UI]` annotation takes precedence (avoids // accidental collision with the otherwise quite generic property names) @@ -190,6 +203,16 @@ const renderNode = ( addCancel(cancelChildren); } + // Wrap with ct-cell-context if we traversed [UI] with a rootCell + if (cellForContext && element) { + const wrapper = document.createElement( + "ct-cell-context", + ) as HTMLElement & { cell?: Cell }; + wrapper.cell = cellForContext; + wrapper.appendChild(element); + return [wrapper, cancel]; + } + return [element, cancel]; }; diff --git a/packages/patterns/chatbot.tsx b/packages/patterns/chatbot.tsx index a9cc969032..20f8f5c09e 100644 --- a/packages/patterns/chatbot.tsx +++ b/packages/patterns/chatbot.tsx @@ -241,7 +241,9 @@ export default pattern( const attachmentsAndTools = ( - + + + ( [NAME]: "My First Compiler", [UI]: (
- - {ifElse( - error, - fix the error: {error}, - - Navigate To Charm - , - )} + + + + + {ifElse( + error, + fix the error: {error}, + + Navigate To Charm + , + )} +
), code, diff --git a/packages/patterns/counter.tsx b/packages/patterns/counter.tsx index c33da4bfbc..60aaa57549 100644 --- a/packages/patterns/counter.tsx +++ b/packages/patterns/counter.tsx @@ -20,9 +20,11 @@ export default recipe((state) => { dec to {previous(state.value)} - - Counter is the {nth(state.value)} number - + + + Counter is the {nth(state.value)} number + + inc to {(state.value ?? 0) + 1} diff --git a/packages/patterns/default-app.tsx b/packages/patterns/default-app.tsx index 60b863a258..6e1e1fdd8d 100644 --- a/packages/patterns/default-app.tsx +++ b/packages/patterns/default-app.tsx @@ -33,7 +33,7 @@ interface CharmsListOutput { fabUI: unknown; } -const visit = handler< +const _visit = handler< Record, { charm: Cell } >((_, state) => { @@ -177,12 +177,9 @@ export default recipe( {allCharms.map((charm) => ( - - {charm?.[NAME] || "Untitled Charm"} - + + + >((_) => { [UI]: (
{wishResult.result.map((item) => ( -
- - - Remove - -
{item.description}
-
+ +
+ + + Remove + +
{item.description}
+
+
))}
), diff --git a/packages/patterns/fetch-data.tsx b/packages/patterns/fetch-data.tsx index cced11c923..dd9151df2e 100644 --- a/packages/patterns/fetch-data.tsx +++ b/packages/patterns/fetch-data.tsx @@ -203,37 +203,39 @@ export default recipe< /> -
-

- {validData.name} -

-

- by {validData.owner.login} -

-

{validData.description}

+
+

+ {validData.name} +

+

+ by {validData.owner.login} +

+

{validData.description}

- - {validData.stargazers_count} stars -
-
- 🍴 - {validData.forks_count} forks -
-
- 🔤 - {validData.language} -
-
- - View on GitHub → - +
+ + {validData.stargazers_count} stars +
+
+ 🍴 + {validData.forks_count} forks +
+
+ 🔤 + {validData.language} +
+
-
+ ), repo: validData, diff --git a/packages/patterns/image-analysis.tsx b/packages/patterns/image-analysis.tsx index d73fb80852..28a247fef4 100644 --- a/packages/patterns/image-analysis.tsx +++ b/packages/patterns/image-analysis.tsx @@ -72,63 +72,72 @@ export default recipe( {/* Image Upload */} - - - Upload Images - - - + + + + Upload Images + + + + {/* Prompt Input */} - - - Your Question - - - + + + + Your Question + + + + {/* Response */} - {derive( - [result, pending, requestHash], - ( - [res, pend, _hash]: [ - string | undefined, - boolean | undefined, - string | undefined, - ], - ) => { - if (pend) { - return ( - -
Analyzing...
-
- ); - } - - if (res) { - return ( - - - Response -
{res}
-
-
- ); - } - - return null; - }, - )} + + {derive( + [result, pending, requestHash], + ( + [res, pend, _hash]: [ + string | undefined, + boolean | undefined, + string | undefined, + ], + ) => { + if (pend) { + return ( + +
Analyzing...
+
+ ); + } + + if (res) { + return ( + + + Response +
{res}
+
+
+ ); + } + + return null; + }, + )} +
diff --git a/packages/patterns/llm.tsx b/packages/patterns/llm.tsx index fc2a6bcb89..200c187d43 100644 --- a/packages/patterns/llm.tsx +++ b/packages/patterns/llm.tsx @@ -1,13 +1,11 @@ /// import { BuiltInLLMContent, - BuiltInLLMMessage, Cell, - cell, Default, derive, + generateText, handler, - llm, NAME, recipe, UI, @@ -33,17 +31,12 @@ const askQuestion = handler< }); export default recipe(({ title }) => { - // It is possible to make inline cells like this, but always consider whether it should just be part of the argument cell. - // These cells are effectively 'hidden state' from other recipes - const question = cell(""); + const question = Cell.of(""); - const llmResponse = llm({ + const llmResponse = generateText({ system: "You are a helpful assistant. Answer questions clearly and concisely.", - messages: derive( - question, - (q) => q ? [{ role: "user", content: q }] : [], - ), + prompt: question, }); return { @@ -61,29 +54,33 @@ export default recipe(({ title }) => { /> - {derive(question, (q) => - q - ? ( -
-

Your Question:

-
- {q} -
-
- ) - : null)} + + {derive(question, (q) => + q + ? ( +
+

Your Question:

+
+ {q} +
+
+ ) + : null)} +
- {derive(llmResponse.result, (r) => - r - ? ( -
-

LLM Response:

-
-                  {JSON.stringify(r, null, 2)}
-                
-
- ) - : null)} + + {derive(llmResponse.result, (r) => + r + ? ( +
+

LLM Response:

+
+                    {r}
+                  
+
+ ) + : null)} +
), question, diff --git a/packages/patterns/omnibox-fab.tsx b/packages/patterns/omnibox-fab.tsx index d94764a3e9..2348d862ef 100644 --- a/packages/patterns/omnibox-fab.tsx +++ b/packages/patterns/omnibox-fab.tsx @@ -134,7 +134,9 @@ export default pattern( {omnibot.ui.attachmentsAndTools}
- {omnibot.ui.chatLog} + + {omnibot.ui.chatLog} +
@@ -162,12 +164,14 @@ export default pattern( onClick={toggle({ value: showHistory })} style="cursor: pointer;" > - + + + , null, diff --git a/packages/patterns/suggestion.tsx b/packages/patterns/suggestion.tsx index 9ca406c54b..afb59603b9 100644 --- a/packages/patterns/suggestion.tsx +++ b/packages/patterns/suggestion.tsx @@ -62,14 +62,18 @@ export default pattern<{ title: Default }>(

Suggestion Tester

Counter

- {derive(suggestion, (s) => { - return s?.cell ?? "waiting..."; - })} + + {derive(suggestion, (s) => { + return s?.cell ?? "waiting..."; + })} +

Note

- {derive(suggestion2, (s) => { - return s?.cell ?? "waiting.."; - })} + + {derive(suggestion2, (s) => { + return s?.cell ?? "waiting.."; + })} +
), suggestion, diff --git a/packages/patterns/todo-list.tsx b/packages/patterns/todo-list.tsx index 09a5cda046..374a518a44 100644 --- a/packages/patterns/todo-list.tsx +++ b/packages/patterns/todo-list.tsx @@ -86,20 +86,22 @@ export default pattern(({ items }) => { {/* AI Suggestion */} -
-

AI Suggestion

- {derive(suggestion, (s) => - s?.cell ?? ( - Getting suggestion... - ))} -
+ +
+

AI Suggestion

+ {derive(suggestion, (s) => + s?.cell ?? ( + Getting suggestion... + ))} +
+
), items, diff --git a/packages/patterns/write-and-run.tsx b/packages/patterns/write-and-run.tsx index d366625cec..6594d5f8ee 100644 --- a/packages/patterns/write-and-run.tsx +++ b/packages/patterns/write-and-run.tsx @@ -164,32 +164,36 @@ export default pattern(({ prompt }) => { {ifElse( isReady, -
-

Generated Pattern

-
- {compiled.result} + +
+

Generated Pattern

+
+ {compiled.result} +
-
, + , , )} {ifElse( hasCode, -
-

Generated Code

- -
, + +
+

Generated Code

+ +
+
, , )}
diff --git a/packages/runner/src/index.ts b/packages/runner/src/index.ts index 1aa3bffece..d916e0bc8a 100644 --- a/packages/runner/src/index.ts +++ b/packages/runner/src/index.ts @@ -1,4 +1,4 @@ -export { Runtime, spaceCellSchema } from "./runtime.ts"; +export { homeSpaceCellSchema, Runtime, spaceCellSchema } from "./runtime.ts"; export type { CharmMetadata, ConsoleHandler, diff --git a/packages/runner/src/runtime.ts b/packages/runner/src/runtime.ts index 8f3d738a5b..dc89a176ec 100644 --- a/packages/runner/src/runtime.ts +++ b/packages/runner/src/runtime.ts @@ -95,7 +95,7 @@ export interface SpaceCellContents { * Home space contains user-specific data like favorites that persists across all spaces. * See docs/common/HOME_SPACE.md for more details. */ -export interface HomeSpaceCellContents { +export interface HomeSpaceCellContents extends SpaceCellContents { favorites: Cell<{ cell: Cell; tag: string }[]>; } @@ -128,6 +128,17 @@ export const spaceCellSchema: JSONSchema = { export const homeSpaceCellSchema: JSONSchema = { type: "object", properties: { + // Include all space cell properties + allCharms: { + type: "array", + items: { not: true, asCell: true }, + }, + recentCharms: { + type: "array", + items: { not: true, asCell: true }, + }, + defaultPattern: { not: true, asCell: true }, + // Plus home-space-specific properties favorites: { type: "array", items: { diff --git a/packages/shell/src/lib/debugger-controller.ts b/packages/shell/src/lib/debugger-controller.ts index 59149e82ef..d01b1439c9 100644 --- a/packages/shell/src/lib/debugger-controller.ts +++ b/packages/shell/src/lib/debugger-controller.ts @@ -1,10 +1,37 @@ import { ReactiveController, ReactiveControllerHost } from "lit"; import type { RuntimeInternals } from "./runtime.ts"; -import type { RuntimeTelemetryMarkerResult } from "@commontools/runner"; +import type { + Cell, + MemorySpace, + NormalizedLink, + RuntimeTelemetryMarkerResult, +} from "@commontools/runner"; const STORAGE_KEY = "showDebuggerView"; const MAX_TELEMETRY_EVENTS = 1000; // Limit memory usage +/** + * A normalized link with both id and space defined (suitable as a memory address) + */ +type NormalizedFullLink = NormalizedLink & { + id: string; + space: MemorySpace; +}; + +/** + * Represents a watched cell with subscription management + */ +export interface WatchedCell { + id: string; // Unique watch entry ID (e.g., "watch-{timestamp}-{random}") + cellLink: NormalizedFullLink; // The cell being watched (for display/persistence) + label?: string; // User-provided label + cell: Cell; // Live cell reference for subscription + cancel?: () => void; // Cleanup from cell.sink() + lastValue?: unknown; // Most recent value + lastUpdate?: number; // Timestamp of last update + updateCount: number; // Update counter +} + /** * Controller for managing Shell Debugger state and telemetry events. * @@ -12,6 +39,7 @@ const MAX_TELEMETRY_EVENTS = 1000; // Limit memory usage * - Debugger visibility state with localStorage persistence * - Runtime connection and telemetry event collection * - Memory management by limiting event history + * - Watched cell subscriptions with console logging */ export class DebuggerController implements ReactiveController { private host: ReactiveControllerHost; @@ -19,6 +47,7 @@ export class DebuggerController implements ReactiveController { private visible = false; private telemetryMarkers: RuntimeTelemetryMarkerResult[] = []; private updateVersion = 0; + private watchedCells = new Map(); constructor(host: ReactiveControllerHost) { this.host = host; @@ -38,6 +67,8 @@ export class DebuggerController implements ReactiveController { hostDisconnected() { globalThis.removeEventListener("storage", this.handleStorageChange); + // Clean up all watched cell subscriptions to prevent memory leaks + this.unwatchAll(); } /** @@ -49,6 +80,8 @@ export class DebuggerController implements ReactiveController { "telemetryupdate", this.handleTelemetryUpdate, ); + // Clean up all watched cell subscriptions when runtime disconnects + this.unwatchAll(); } this.runtime = runtime; @@ -188,4 +221,123 @@ export class DebuggerController implements ReactiveController { document.body.removeChild(a); URL.revokeObjectURL(url); } + + /** + * Watch a cell for changes. Subscribes to the cell and logs updates to console. + * @param cell - The cell to watch + * @param label - Optional label for identifying this watch + * @returns The watch ID (can be used to unwatch later) + */ + watchCell(cell: Cell, label?: string): string { + // Generate unique watch ID + const watchId = `watch-${Date.now()}-${ + Math.random().toString(36).slice(2, 8) + }`; + + // Get the cell link for display/persistence + const cellLink = cell.getAsNormalizedFullLink(); + + // Create identifier for logging (use label if provided, otherwise short ID) + const identifier = label ?? this.getCellShortId(cellLink); + + // Subscribe to cell changes + const cancel = cell.sink((value) => { + const watch = this.watchedCells.get(watchId); + if (!watch) return; + + watch.updateCount++; + watch.lastValue = value; + watch.lastUpdate = Date.now(); + + console.log( + `[DebuggerController] Watch update: ${identifier} (#${watch.updateCount}):`, + value, + ); + + // Request UI update + this.host.requestUpdate(); + }); + + // Store the watch entry + const watchedCell: WatchedCell = { + id: watchId, + cellLink, + label, + cell, + cancel, + lastValue: undefined, + lastUpdate: undefined, + updateCount: 0, + }; + + this.watchedCells.set(watchId, watchedCell); + + console.log(`[DebuggerController] Started watching: ${identifier}`); + + // Request UI update + this.host.requestUpdate(); + + return watchId; + } + + /** + * Stop watching a cell + * @param watchId - The watch ID returned by watchCell() + */ + unwatchCell(watchId: string): void { + const watch = this.watchedCells.get(watchId); + if (!watch) return; + + // Clean up subscription + if (watch.cancel) { + watch.cancel(); + } + + const identifier = watch.label ?? this.getCellShortId(watch.cellLink); + console.log(`[DebuggerController] Stopped watching: ${identifier}`); + + // Remove from map + this.watchedCells.delete(watchId); + + // Request UI update + this.host.requestUpdate(); + } + + /** + * Stop watching all cells + */ + unwatchAll(): void { + const hadWatches = this.watchedCells.size > 0; + + for (const watchId of this.watchedCells.keys()) { + const watch = this.watchedCells.get(watchId); + if (watch?.cancel) { + watch.cancel(); + } + } + + this.watchedCells.clear(); + + if (hadWatches) { + console.log("[DebuggerController] Stopped watching all cells"); + // Request UI update + this.host.requestUpdate(); + } + } + + /** + * Get all currently watched cells + */ + getWatchedCells(): WatchedCell[] { + return Array.from(this.watchedCells.values()); + } + + /** + * Generate a short ID from a cell link for display purposes + */ + private getCellShortId(link: NormalizedFullLink): string { + const id = link.id; + const shortId = id.split(":").pop()?.slice(-6) ?? "???"; + return `#${shortId}`; + } } diff --git a/packages/shell/src/views/AppView.ts b/packages/shell/src/views/AppView.ts index 292470ed91..5b52903682 100644 --- a/packages/shell/src/views/AppView.ts +++ b/packages/shell/src/views/AppView.ts @@ -78,6 +78,9 @@ export class XAppView extends BaseView { "sidebar-content-change", this.handleSidebarContentChange, ); + // Listen for cell watch/unwatch events from ct-cell-context + this.addEventListener("ct-cell-watch", this.handleCellWatch); + this.addEventListener("ct-cell-unwatch", this.handleCellUnwatch); // Register global shortcuts via keyboard router const isMac = navigator.platform.toLowerCase().includes("mac"); @@ -109,6 +112,8 @@ export class XAppView extends BaseView { "sidebar-content-change", this.handleSidebarContentChange, ); + this.removeEventListener("ct-cell-watch", this.handleCellWatch); + this.removeEventListener("ct-cell-unwatch", this.handleCellUnwatch); for (const off of this._unsubShortcuts) off(); this._unsubShortcuts = []; this.keyboard.dispose(); @@ -163,6 +168,28 @@ export class XAppView extends BaseView { }, args: () => [this.app, this.rt], }); + private handleCellWatch = (e: Event) => { + const event = e as CustomEvent<{ cell: unknown; label?: string }>; + const { cell, label } = event.detail; + // Cell type from @commontools/runner + if (cell && typeof (cell as any).sink === "function") { + this.debuggerController.watchCell(cell as any, label); + } + }; + + private handleCellUnwatch = (e: Event) => { + const event = e as CustomEvent<{ cell: unknown; label?: string }>; + const { cell } = event.detail; + // Find and remove the watch by matching the cell + if (cell && typeof (cell as any).getAsNormalizedFullLink === "function") { + const link = (cell as any).getAsNormalizedFullLink(); + const watches = this.debuggerController.getWatchedCells(); + const watch = watches.find((w) => w.cellLink.id === link.id); + if (watch) { + this.debuggerController.unwatchCell(watch.id); + } + } + }; // Do not make private, integration tests access this directly. _activeCharm = new Task(this, { @@ -289,6 +316,7 @@ export class XAppView extends BaseView { (); @@ -928,6 +1037,91 @@ export class XDebuggerView extends LitElement { return details; } + private formatValue(value: unknown): string { + if (value === null) return "null"; + if (value === undefined) return "undefined"; + if (typeof value === "string") return `"${value}"`; + if (typeof value === "number" || typeof value === "boolean") { + return String(value); + } + + // For objects/arrays, truncate JSON representation + const json = JSON.stringify(value); + if (json.length > 60) { + return json.slice(0, 57) + "..."; + } + return json; + } + + private getCellLabel( + watch: { label?: string; cellLink: { id: string } }, + ): string { + if (watch.label) return watch.label; + + // Generate short ID from full ID + const id = watch.cellLink.id; + const shortId = id.split(":").pop()?.slice(-6) ?? "???"; + return `#${shortId}`; + } + + private renderTabs() { + return html` +
+ + +
+ `; + } + + private renderWatchList() { + const watchedCells = this.debuggerController?.getWatchedCells() ?? []; + + if (watchedCells.length === 0) { + return html` +
+ No cells being watched.
+ Hold Alt and hover over a ct-cell-context to access watch controls. +
+ `; + } + + return html` +
+ ${watchedCells.map((watch) => + html` +
+
${this.getCellLabel(watch)}
+
${this.formatValue( + watch.lastValue, + )}
+
${watch.updateCount} updates
+ +
+ ` + )} +
+ `; + } + private renderEvents() { const events = this.getFilteredEvents(); @@ -1056,145 +1250,161 @@ export class XDebuggerView extends LitElement { -
-
- ${Object.entries(TOPIC_HIERARCHY).map(([key, topic]) => { - const topicKey = key as TopicKey; - const state = this.getTopicState(topicKey); - const subtopicKeys = Object.keys(topic.subtopics); - const hasDropdown = subtopicKeys.length > 0; // Show dropdown even for single subtopic - const isDropdownOpen = this.openDropdowns.has(topicKey); - - return html` -
- - ${hasDropdown - ? html` + ${this.renderTabs()} ${this._activeTab === "events" + ? html` +
+
+ ${Object.entries(TOPIC_HIERARCHY).map(([key, topic]) => { + const topicKey = key as TopicKey; + const state = this.getTopicState(topicKey); + const subtopicKeys = Object.keys(topic.subtopics); + const hasDropdown = subtopicKeys.length > 0; // Show dropdown even for single subtopic + const isDropdownOpen = this.openDropdowns.has(topicKey); + + return html` +
- ${isDropdownOpen + ${hasDropdown ? html` -
- ${Object.entries(topic.subtopics).map( - ([subKey, subtopic]) => { - const fullKey = `${topicKey}.${subKey}`; - const isChecked = this.activeSubtopics.has( - fullKey, - ); - return html` - - `; - }, - )} -
+ + ${isDropdownOpen + ? html` +
+ ${Object.entries(topic.subtopics).map( + ([subKey, subtopic]) => { + const fullKey = `${topicKey}.${subKey}`; + const isChecked = this.activeSubtopics + .has( + fullKey, + ); + return html` + + `; + }, + )} +
+ ` + : ""} ` : ""} +
+ `; + })} +
+ +
+
+ + ${this.searchText + ? html` + ` : ""}
- `; - })} -
-
-
- - ${this.searchText - ? html` - - ` - : ""} + + + + + +
- - - - - -
-
- -
- ${this.renderEvents()} -
+
+ ${this.renderEvents()} +
+ ` + : html` +
+ ${this.renderWatchList()} +
+ `}
` : ""} diff --git a/packages/toolshed/deno.json b/packages/toolshed/deno.json index 4074435178..007e990946 100644 --- a/packages/toolshed/deno.json +++ b/packages/toolshed/deno.json @@ -19,10 +19,10 @@ "@std/cli": "jsr:@std/cli@^1.0.12", "ajv": "npm:ajv@^8.17.1", "gcp-metadata": "npm:gcp-metadata@6.1.0", - "@opentelemetry/context-async-hooks": "npm:@opentelemetry/context-async-hooks@^1.19.0", - "@opentelemetry/core": "npm:@opentelemetry/core@^1.19.0", - "@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@^1.19.0", - "@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@^1.19.0", + "@opentelemetry/context-async-hooks": "npm:@opentelemetry/context-async-hooks@^1.30.0", + "@opentelemetry/core": "npm:@opentelemetry/core@^1.30.0", + "@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@^1.30.0", + "@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@^1.30.0", "@arizeai/openinference-semantic-conventions": "npm:@arizeai/openinference-semantic-conventions@^1.1.0", "@arizeai/openinference-vercel": "npm:@arizeai/openinference-vercel@^2.0.1", "@fal-ai/client": "npm:@fal-ai/client@^1.2.2", @@ -32,7 +32,7 @@ "@hono/zod-validator": "npm:@hono/zod-validator@^0.4.2", "@opentelemetry/api": "npm:@opentelemetry/api@^1.7.0", "@opentelemetry/exporter-trace-otlp-proto": "npm:@opentelemetry/exporter-trace-otlp-proto@^0.46.0", - "@opentelemetry/resources": "npm:@opentelemetry/resources@^1.19.0", + "@opentelemetry/resources": "npm:@opentelemetry/resources@^1.30.0", "@scalar/hono-api-reference": "npm:@scalar/hono-api-reference@^0.5.165", "@sentry/deno": "npm:@sentry/deno@^9.3.0", "jsonschema": "npm:jsonschema@^1.5.0", diff --git a/packages/ui/src/v2/components/ct-cell-context/ct-cell-context.ts b/packages/ui/src/v2/components/ct-cell-context/ct-cell-context.ts new file mode 100644 index 0000000000..83b97f800b --- /dev/null +++ b/packages/ui/src/v2/components/ct-cell-context/ct-cell-context.ts @@ -0,0 +1,287 @@ +import { css, html } from "lit"; +import { property, state } from "lit/decorators.js"; +import { BaseElement } from "../../core/base-element.ts"; +import type { Cell } from "@commontools/runner"; + +/** + * CTCellContext - Wraps page regions and associates them with a Cell + * + * Provides a debugging toolbar that appears when holding Alt and hovering. + * The toolbar allows inspecting cell values and addresses. + * + * @element ct-cell-context + * + * @property {Cell} cell - The Cell reference to associate with this context + * @property {string} label - Optional label for display in the toolbar + * + * @slot - Default slot for wrapped content + * + * @example + * + *
Content here
+ *
+ */ +export class CTCellContext extends BaseElement { + static override styles = [ + BaseElement.baseStyles, + css` + :host { + display: block; + position: relative; + } + + :host([inline]) { + display: inline; + } + + .container { + border: 1px dashed transparent; + transition: border-color 0.2s ease; + } + + .container.alt-held { + border-color: rgba(128, 128, 128, 0.25); + } + + .container.alt-held:hover { + border-color: rgba(128, 128, 128, 0.75); + } + + .toolbar { + position: absolute; + top: 0; + right: 0; + z-index: 1000; + display: flex; + border: 1px solid #000; + border-radius: 0; + background: rgba(255, 255, 255, 0.95); + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: 0.75rem; + overflow: hidden; + } + + .toolbar.hidden { + display: none; + } + + .toolbar button { + border: none; + border-right: 1px solid #000; + border-radius: 0; + padding: 0.25rem 0.5rem; + background: transparent; + cursor: pointer; + font-family: inherit; + font-size: inherit; + color: #000; + } + + .toolbar button:last-child { + border-right: none; + } + + .toolbar button:hover { + background: rgba(0, 0, 0, 0.05); + } + + .toolbar button:active { + background: rgba(0, 0, 0, 0.1); + } + + .toolbar button.watching { + background: #000; + color: #fff; + } + + .toolbar button.watching:hover { + background: #333; + color: #fff; + } + + .toolbar .label { + padding: 0.25rem 0.5rem; + border-right: 1px solid #000; + font-weight: 500; + color: #666; + } + `, + ]; + + @property({ attribute: false }) + cell?: Cell; + + @property({ type: String }) + label?: string; + + @property({ type: Boolean, reflect: true }) + inline?: boolean; + + @state() + private _modifierHeld: boolean = false; + + @state() + private _isHovered: boolean = false; + + @state() + private _isWatching: boolean = false; + + @state() + private _updateCount: number = 0; + + private _boundHandleKeyDown = this._handleKeyDown.bind(this); + private _boundHandleKeyUp = this._handleKeyUp.bind(this); + private _watchUnsubscribe?: () => void; + + override connectedCallback() { + super.connectedCallback(); + // Listen for Alt key at document level + document.addEventListener("keydown", this._boundHandleKeyDown); + document.addEventListener("keyup", this._boundHandleKeyUp); + } + + override disconnectedCallback() { + super.disconnectedCallback(); + // Clean up document-level listeners + document.removeEventListener("keydown", this._boundHandleKeyDown); + document.removeEventListener("keyup", this._boundHandleKeyUp); + // Clean up watch subscription if active + if (this._watchUnsubscribe) { + this._watchUnsubscribe(); + this._watchUnsubscribe = undefined; + } + } + + private _handleKeyDown(e: KeyboardEvent) { + if (e.key === "Alt") { + this._modifierHeld = true; + } + } + + private _handleKeyUp(e: KeyboardEvent) { + if (e.key === "Alt") { + this._modifierHeld = false; + } + } + + private _handleMouseEnter() { + this._isHovered = true; + } + + private _handleMouseLeave() { + this._isHovered = false; + } + + private _handleValClick() { + if (!this.cell) { + console.log("[ct-cell-context] No cell available"); + return; + } + // Set window.$cell for easy console access (like Chrome's $0 for elements) + (globalThis as unknown as { $cell: Cell }).$cell = this.cell; + console.log("$cell =", this.cell, "→", this.cell.get()); + } + + private _handleIdClick() { + if (!this.cell) { + console.log("[ct-cell-context] No cell available"); + return; + } + console.log( + "[ct-cell-context] Cell address:", + this.cell.getAsNormalizedFullLink(), + ); + } + + private _handleWatchClick() { + if (!this.cell) { + console.log("[ct-cell-context] No cell available"); + return; + } + + const identifier = this._getCellIdentifier(); + + if (this._isWatching) { + // Unwatch + if (this._watchUnsubscribe) { + this._watchUnsubscribe(); + this._watchUnsubscribe = undefined; + } + this._isWatching = false; + this._updateCount = 0; + console.log(`[ct-cell-context] Stopped watching: ${identifier}`); + // Emit event for debugger integration + this.emit("ct-cell-unwatch", { cell: this.cell, label: this.label }); + } else { + // Watch + this._updateCount = 0; + this._watchUnsubscribe = this.cell.sink((value) => { + this._updateCount++; + console.log( + `[ct-cell-context] Cell update #${this._updateCount}:`, + value, + ); + }); + this._isWatching = true; + console.log(`[ct-cell-context] Started watching: ${identifier}`); + // Emit event for debugger integration + this.emit("ct-cell-watch", { cell: this.cell, label: this.label }); + } + } + + private _getCellIdentifier(): string { + if (!this.cell) return "unknown"; + if (this.label) return this.label; + // Create short ID like ct-cell-link does + const link = this.cell.getAsNormalizedFullLink(); + const id = link.id; + const shortId = id.split(":").pop()?.slice(-6) ?? "???"; + return `#${shortId}`; + } + + private get _shouldShowToolbar(): boolean { + return this._modifierHeld && this._isHovered; + } + + override render() { + return html` +
+
+ ${this.label + ? html` +
${this.label}
+ ` + : ""} + + + +
+ +
+ `; + } +} + +globalThis.customElements.define("ct-cell-context", CTCellContext); + +declare global { + interface HTMLElementTagNameMap { + "ct-cell-context": CTCellContext; + } +} diff --git a/packages/ui/src/v2/components/ct-cell-context/index.ts b/packages/ui/src/v2/components/ct-cell-context/index.ts new file mode 100644 index 0000000000..e9bdd28424 --- /dev/null +++ b/packages/ui/src/v2/components/ct-cell-context/index.ts @@ -0,0 +1,7 @@ +import { CTCellContext } from "./ct-cell-context.ts"; + +if (!customElements.get("ct-cell-context")) { + customElements.define("ct-cell-context", CTCellContext); +} + +export { CTCellContext }; diff --git a/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.test.ts b/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.test.ts index 6d7ae0008c..fe574aa065 100644 --- a/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.test.ts +++ b/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.test.ts @@ -7,16 +7,51 @@ describe("ct-chat-message", () => { expect(CTChatMessage).toBeDefined(); }); - it("should replace LLM-friendly links with ct-cell-link in _renderMarkdown", () => { + it("should create element instance", () => { + const element = new CTChatMessage(); + expect(element).toBeInstanceOf(CTChatMessage); + }); + + it("should have default role of user", () => { + const element = new CTChatMessage(); + expect(element.role).toBe("user"); + }); + + it("should have streaming disabled by default", () => { + const element = new CTChatMessage(); + expect(element.streaming).toBe(false); + }); + + it("should extract text content from string", () => { const el = new CTChatMessage(); - const link = "/of:bafyabc123/path"; - const markdown = `Check this [Link](${link})`; + el.content = "Hello world"; - // Access private method - const rendered = (el as any)._renderMarkdown(markdown); + const text = (el as any)._extractTextContent(); - expect(rendered).toContain( - ``, - ); + expect(text).toBe("Hello world"); }); + + it("should extract text content from array with text parts", () => { + const el = new CTChatMessage(); + el.content = [ + { type: "text", text: "Hello" }, + { type: "text", text: "world" }, + ] as any; + + const text = (el as any)._extractTextContent(); + + expect(text).toBe("Hello world"); + }); + + it("should return empty string for empty content", () => { + const el = new CTChatMessage(); + el.content = ""; + + const text = (el as any)._extractTextContent(); + + expect(text).toBe(""); + }); + + // Note: Markdown rendering is now tested in ct-markdown.test.ts + // ct-chat-message delegates to ct-markdown component }); diff --git a/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.ts b/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.ts index 7048e9789f..7d920a5f44 100644 --- a/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.ts +++ b/packages/ui/src/v2/components/ct-chat-message/ct-chat-message.ts @@ -1,12 +1,11 @@ import { css, html } from "lit"; import { property } from "lit/decorators.js"; import { consume } from "@lit/context"; -import { unsafeHTML } from "lit/directives/unsafe-html.js"; -import { marked } from "marked"; import { BaseElement } from "../../core/base-element.ts"; import "../ct-tool-call/ct-tool-call.ts"; import "../ct-button/ct-button.ts"; import "../ct-copy-button/ct-copy-button.ts"; +import "../ct-markdown/ct-markdown.ts"; import type { BuiltInLLMContent, BuiltInLLMTextPart, @@ -18,7 +17,6 @@ import { type CTTheme, themeContext, } from "../theme-context.ts"; -import "../ct-cell-link/ct-cell-link.ts"; /** * CTChatMessage - Chat message component with markdown support @@ -114,28 +112,6 @@ export class CTChatMessage extends BaseElement { } } - /* Streaming text effect - can be triggered by adding 'streaming' class */ - .message.streaming .message-content { - animation: none; - opacity: 1; - } - - .message.streaming .message-content::after { - content: "▊"; - animation: blink 1s infinite; - margin-left: 2px; - color: currentColor; - } - - @keyframes blink { - 0%, 50% { - opacity: 1; - } - 51%, 100% { - opacity: 0; - } - } - .message-user { background-color: var(--ct-theme-color-primary, #3b82f6); color: var(--ct-theme-color-primary-foreground, #ffffff); @@ -145,9 +121,10 @@ export class CTChatMessage extends BaseElement { color: var(--ct-theme-color-text, #111827); } - .message-content { + /* ct-markdown inherits color from parent */ + ct-markdown { + color: inherit; line-height: 1.5; - animation: textFadeIn 0.4s ease-out 0.1s both; } /* Avatar styling */ @@ -215,81 +192,6 @@ export class CTChatMessage extends BaseElement { max-width: 500px; } - /* Markdown styling */ - .message-content p { - margin: 0; - } - - .message-content p:not(:last-child) { - margin-bottom: var(--ct-theme-spacing, var(--ct-spacing-2, 0.5rem)); - } - - .message-content code { - background-color: var(--ct-theme-color-surface, #f9fafb); - padding: var(--ct-theme-padding-code, var(--ct-spacing-1, 0.25rem)); - border-radius: var(--ct-theme-border-radius, 0.5rem); - font-family: var(--ct-theme-mono-font-family, ui-monospace, monospace); - font-size: 0.875em; - } - - .message-content pre { - background-color: var(--ct-theme-color-surface, #f9fafb); - padding: var(--ct-theme-padding-block, var(--ct-spacing-3, 0.75rem)); - border-radius: var(--ct-theme-border-radius, 0.5rem); - border: 1px solid var(--ct-theme-color-border, #e5e7eb); - overflow-x: auto; - margin: var(--ct-theme-spacing-normal, var(--ct-spacing-2, 0.5rem)) 0; - } - - .message-content pre code { - background-color: transparent; - padding: 0; - } - - .message-content ul, - .message-content ol { - margin: var(--ct-theme-spacing, var(--ct-spacing-2, 0.5rem)) 0; - padding-left: var(--ct-theme-padding, var(--ct-spacing-3, 0.75rem)); - } - - .message-content blockquote { - border-left: 4px solid var(--ct-theme-color-border, #e5e7eb); - margin: var(--ct-theme-spacing, var(--ct-spacing-2, 0.5rem)) 0; - padding-left: var(--ct-theme-padding, var(--ct-spacing-3, 0.75rem)); - font-style: italic; - color: var(--ct-theme-color-text-muted, #6b7280); - } - - /* Adjust colors for user messages */ - :host([role="user"]) .message-content code { - background-color: rgba(255, 255, 255, 0.2); - color: var( - --ct-theme-color-accent-foreground, - var(--ct-color-white, #ffffff) - ); - } - - :host([role="user"]) .message-content pre { - background-color: rgba(255, 255, 255, 0.2); - border: none; - } - - :host([role="user"]) .message-content pre code { - background-color: transparent; - color: var( - --ct-theme-color-accent-foreground, - var(--ct-color-white, #ffffff) - ); - } - - :host([role="user"]) .message-content blockquote { - border-left-color: rgba(255, 255, 255, 0.6); - color: var( - --ct-theme-color-accent-foreground, - var(--ct-color-white, #ffffff) - ); - } - /* Message actions */ .message-actions { display: flex; @@ -303,24 +205,6 @@ export class CTChatMessage extends BaseElement { opacity: 1; } - /* Code block copy button styles */ - .code-block-container { - position: relative; - } - - .code-copy-button { - position: absolute; - top: var(--ct-theme-spacing-normal, var(--ct-spacing-2, 0.5rem)); - right: var(--ct-theme-spacing-normal, var(--ct-spacing-2, 0.5rem)); - opacity: 0; - transition: opacity var(--ct-theme-animation-duration, 0.2s) ease; - z-index: 1; - } - - .code-block-container:hover .code-copy-button { - opacity: 1; - } - /* Compact mode styles */ :host([compact]) .message { padding: var(--ct-theme-padding-compact, var(--ct-spacing-2, 0.5rem)); @@ -343,13 +227,6 @@ export class CTChatMessage extends BaseElement { margin-top: var(--ct-theme-spacing-compact, var(--ct-spacing-1, 0.25rem)); gap: var(--ct-theme-spacing-compact, var(--ct-spacing-1, 0.25rem)); } - - :host([compact]) .message-content p:not(:last-child) { - margin-bottom: var( - --ct-theme-spacing-compact, - var(--ct-spacing-1, 0.25rem) - ); - } `, ]; @@ -382,77 +259,6 @@ export class CTChatMessage extends BaseElement { this.streaming = false; } - private _renderMarkdown(content: string): string { - if (!content) return ""; - - // Configure marked for safer rendering - marked.setOptions({ - breaks: true, - gfm: true, - }); - - let renderedHtml = marked(content) as string; - - // Wrap code blocks with copy buttons - renderedHtml = this._wrapCodeBlocksWithCopyButtons(renderedHtml); - - // Replace cell links with ct-cell-link - renderedHtml = this._replaceCellLinks(renderedHtml); - - return renderedHtml; - } - - private _replaceCellLinks(html: string): string { - // Matches Name - // We look for hrefs starting with /of: (or other schemes if generalized, but LLM links are /of:) - // The regex for LLM friendly links is roughly /^[a-zA-Z0-9]+:/ but we know they start with /of: usually. - // Let's use a broader regex for the scheme part to be safe: \/[a-zA-Z0-9]+: - return html.replace( - /([^<]*)<\/a>/g, - (_match, link, text) => { - // Pass the original link text as label to preserve author's intent - return ``; - }, - ); - } - - private _wrapCodeBlocksWithCopyButtons(html: string): string { - // Use a regex to find
...
blocks and wrap them - return html.replace( - /
]*)>([\s\S]*?)<\/code><\/pre>/g,
-      (_match, codeAttrs, codeContent) => {
-        // Decode HTML entities for the copy content
-        const decodedContent = this._decodeHtmlEntities(codeContent);
-
-        return `
-
${codeContent}
- -
`; - }, - ); - } - - private _decodeHtmlEntities(text: string): string { - const textarea = document.createElement("textarea"); - textarea.innerHTML = text; - return textarea.value; - } - - private _escapeForAttribute(text: string): string { - return text - .replace(/&/g, "&") - .replace(/"/g, """) - .replace(/'/g, "'") - .replace(//g, ">"); - } - private _renderToolAttachments() { // Extract tool calls and results from content array const contentArray = Array.isArray(this.content) ? this.content : []; @@ -571,21 +377,21 @@ export class CTChatMessage extends BaseElement { } override render() { - const messageClass = `message message-${this.role}${ - this.streaming ? " streaming" : "" - }`; - + const messageClass = `message message-${this.role}`; const textContent = this._extractTextContent(); - const renderedContent = this._renderMarkdown(textContent); + const variant = this.role === "user" ? "inverse" : "default"; return html`
${this._renderAvatar()}
-
- ${unsafeHTML(renderedContent)} -
+
${this._renderToolAttachments()} ${this._renderMessageActions()}
diff --git a/packages/ui/src/v2/components/ct-markdown/ct-markdown.test.ts b/packages/ui/src/v2/components/ct-markdown/ct-markdown.test.ts new file mode 100644 index 0000000000..89733c81db --- /dev/null +++ b/packages/ui/src/v2/components/ct-markdown/ct-markdown.test.ts @@ -0,0 +1,167 @@ +import { describe, it } from "@std/testing/bdd"; +import { expect } from "@std/expect"; +import { CTMarkdown } from "./ct-markdown.ts"; + +describe("ct-markdown", () => { + it("should be defined", () => { + expect(CTMarkdown).toBeDefined(); + }); + + it("should create element instance", () => { + const element = new CTMarkdown(); + expect(element).toBeInstanceOf(CTMarkdown); + }); + + it("should have default empty content", () => { + const element = new CTMarkdown(); + expect(element.content).toBe(""); + }); + + it("should have default variant", () => { + const element = new CTMarkdown(); + expect(element.variant).toBe("default"); + }); + + it("should have streaming disabled by default", () => { + const element = new CTMarkdown(); + expect(element.streaming).toBe(false); + }); + + it("should render basic markdown", () => { + const el = new CTMarkdown(); + const markdown = "Hello **world**"; + + const rendered = (el as any)._renderMarkdown(markdown); + + expect(rendered).toContain("world"); + }); + + it("should replace LLM-friendly links with ct-cell-link", () => { + const el = new CTMarkdown(); + const link = "/of:bafyabc123/path"; + const markdown = `Check this [Link](${link})`; + + const rendered = (el as any)._renderMarkdown(markdown); + + expect(rendered).toContain( + ``, + ); + }); + + it("should wrap code blocks with copy buttons", () => { + const el = new CTMarkdown(); + const markdown = "```js\nconsole.log('hello');\n```"; + + const rendered = (el as any)._renderMarkdown(markdown); + + expect(rendered).toContain("code-block-container"); + expect(rendered).toContain("ct-copy-button"); + }); + + it("should get content value from string", () => { + const el = new CTMarkdown(); + el.content = "test content"; + + const value = (el as any)._getContentValue(); + + expect(value).toBe("test content"); + }); + + it("should handle null/undefined content gracefully", () => { + const el = new CTMarkdown(); + el.content = null as any; + + const value = (el as any)._getContentValue(); + + expect(value).toBe(""); + }); + + describe("Cell integration", () => { + // Note: Full Cell integration testing requires real CellImpl instances + // which are complex to mock. These tests verify the component's + // subscription management logic with manual _unsubscribe manipulation. + + it("should have null _unsubscribe by default", () => { + const el = new CTMarkdown(); + expect((el as any)._unsubscribe).toBeNull(); + }); + + it("should cleanup subscription on disconnect", () => { + const el = new CTMarkdown(); + + // Simulate having a subscription + let cleaned = false; + (el as any)._unsubscribe = () => { + cleaned = true; + }; + + // Trigger disconnect + el.disconnectedCallback(); + + expect(cleaned).toBe(true); + expect((el as any)._unsubscribe).toBeNull(); + }); + + it("should cleanup old subscription when willUpdate is called with changed content", () => { + const el = new CTMarkdown(); + + // Simulate having an old subscription + let oldCleaned = false; + (el as any)._unsubscribe = () => { + oldCleaned = true; + }; + + // Trigger willUpdate with content change (string content, not Cell) + el.content = "new content"; + (el as any).willUpdate(new Map([["content", "old content"]])); + + // Old subscription should have been cleaned up + expect(oldCleaned).toBe(true); + // No new subscription for string content + expect((el as any)._unsubscribe).toBeNull(); + }); + }); + + describe("variant", () => { + it("should accept inverse variant", () => { + const el = new CTMarkdown(); + el.variant = "inverse"; + expect(el.variant).toBe("inverse"); + }); + }); + + describe("streaming", () => { + it("should accept streaming prop", () => { + const el = new CTMarkdown(); + el.streaming = true; + expect(el.streaming).toBe(true); + }); + }); + + describe("entity decoding", () => { + it("should decode basic HTML entities", () => { + const el = new CTMarkdown(); + + const decoded = (el as any)._decodeHtmlEntities("<div>&""); + + expect(decoded).toBe('
&"'); + }); + + it("should decode numeric entities in fallback mode", () => { + const el = new CTMarkdown(); + + // Force fallback mode (test environment has no document) + const decoded = (el as any)._decodeHtmlEntities("<>"); + + expect(decoded).toBe("<>"); + }); + + it("should decode hex entities in fallback mode", () => { + const el = new CTMarkdown(); + + const decoded = (el as any)._decodeHtmlEntities("<>"); + + expect(decoded).toBe("<>"); + }); + }); +}); diff --git a/packages/ui/src/v2/components/ct-markdown/ct-markdown.ts b/packages/ui/src/v2/components/ct-markdown/ct-markdown.ts new file mode 100644 index 0000000000..5848d1d632 --- /dev/null +++ b/packages/ui/src/v2/components/ct-markdown/ct-markdown.ts @@ -0,0 +1,576 @@ +import { css, html } from "lit"; +import { property } from "lit/decorators.js"; +import { consume } from "@lit/context"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { classMap } from "lit/directives/class-map.js"; +import { marked } from "marked"; +import { BaseElement } from "../../core/base-element.ts"; +import "../ct-copy-button/ct-copy-button.ts"; +import "../ct-cell-link/ct-cell-link.ts"; +import { + applyThemeToElement, + type CTTheme, + themeContext, +} from "../theme-context.ts"; +import { type Cell, isCell } from "@commontools/runner"; + +export type MarkdownVariant = "default" | "inverse"; + +/** + * CTMarkdown - Renders markdown content with syntax highlighting and copy buttons + * + * @element ct-markdown + * + * @attr {string} content - The markdown content to render (string or Cell) + * @attr {string} variant - Visual variant: "default" or "inverse" (for light text on dark bg) + * @attr {boolean} streaming - Shows a blinking cursor at the end (for streaming content) + * @attr {boolean} compact - Reduces paragraph spacing for more compact display + * + * @csspart content - The markdown content wrapper + * + * @cssprop [--ct-markdown-inverse-border=rgba(255,255,255,0.3)] - Border color for inverse variant + * @cssprop [--ct-markdown-inverse-surface=rgba(255,255,255,0.2)] - Surface color for inverse variant (code blocks) + * @cssprop [--ct-markdown-inverse-surface-subtle=rgba(255,255,255,0.1)] - Subtle surface for inverse (table headers) + * @cssprop [--ct-markdown-inverse-accent=rgba(255,255,255,0.6)] - Accent color for inverse (blockquote border) + * + * @example + * + * + * @example + * + * + * @example + * + * + * @example + * + */ +export class CTMarkdown extends BaseElement { + static override styles = [ + BaseElement.baseStyles, + css` + :host { + display: block; + box-sizing: border-box; + font-family: var( + --ct-theme-font-family, + system-ui, + -apple-system, + sans-serif + ); + line-height: 1.6; + color: var(--ct-theme-color-text, var(--ct-color-gray-900, #111827)); + } + + *, + *::before, + *::after { + box-sizing: inherit; + } + + .markdown-content { + word-wrap: break-word; + } + + /* Streaming cursor */ + .markdown-content.streaming::after { + content: "▊"; + animation: blink 1s infinite; + margin-left: 2px; + color: currentColor; + } + + @keyframes blink { + 0%, + 50% { + opacity: 1; + } + 51%, + 100% { + opacity: 0; + } + } + + /* Headings */ + .markdown-content h1, + .markdown-content h2, + .markdown-content h3, + .markdown-content h4, + .markdown-content h5, + .markdown-content h6 { + margin-top: 1.5em; + margin-bottom: 0.5em; + font-weight: 600; + line-height: 1.25; + } + + .markdown-content h1:first-child, + .markdown-content h2:first-child, + .markdown-content h3:first-child, + .markdown-content h4:first-child, + .markdown-content h5:first-child, + .markdown-content h6:first-child { + margin-top: 0; + } + + .markdown-content h1 { + font-size: 2em; + border-bottom: 1px solid var(--ct-theme-color-border, #e5e7eb); + padding-bottom: 0.3em; + } + + .markdown-content h2 { + font-size: 1.5em; + border-bottom: 1px solid var(--ct-theme-color-border, #e5e7eb); + padding-bottom: 0.3em; + } + + .markdown-content h3 { + font-size: 1.25em; + } + + .markdown-content h4 { + font-size: 1em; + } + + .markdown-content h5 { + font-size: 0.875em; + } + + .markdown-content h6 { + font-size: 0.85em; + color: var(--ct-theme-color-text-muted, #6b7280); + } + + /* Inverse variant heading adjustments */ + .markdown-content.inverse h1, + .markdown-content.inverse h2 { + border-bottom-color: var( + --ct-markdown-inverse-border, + rgba(255, 255, 255, 0.3) + ); + } + + .markdown-content.inverse h6 { + color: inherit; + opacity: 0.8; + } + + /* Paragraphs */ + .markdown-content p { + margin: 0; + } + + .markdown-content p:not(:last-child) { + margin-bottom: var(--ct-theme-spacing, var(--ct-spacing-3, 0.75rem)); + } + + /* Compact mode paragraph spacing */ + .markdown-content.compact p:not(:last-child) { + margin-bottom: var( + --ct-theme-spacing-compact, + var(--ct-spacing-1, 0.25rem) + ); + } + + /* Links */ + .markdown-content a { + color: var( + --ct-theme-color-accent, + var(--ct-color-blue-500, #3b82f6) + ); + text-decoration: none; + } + + .markdown-content a:hover { + text-decoration: underline; + } + + /* Inverse variant links */ + .markdown-content.inverse a { + color: inherit; + text-decoration: underline; + opacity: 0.9; + } + + /* Lists */ + .markdown-content ul, + .markdown-content ol { + margin: var(--ct-theme-spacing, var(--ct-spacing-3, 0.75rem)) 0; + padding-left: 2em; + } + + .markdown-content li { + margin-bottom: 0.25em; + } + + .markdown-content li > ul, + .markdown-content li > ol { + margin: 0.25em 0; + } + + /* Inline code */ + .markdown-content code { + background-color: var(--ct-theme-color-surface, #f9fafb); + padding: 0.2em 0.4em; + border-radius: var(--ct-theme-border-radius, 0.375rem); + font-family: var(--ct-theme-mono-font-family, ui-monospace, monospace); + font-size: 0.875em; + } + + /* Inverse variant inline code */ + .markdown-content.inverse code { + background-color: var( + --ct-markdown-inverse-surface, + rgba(255, 255, 255, 0.2) + ); + color: inherit; + } + + /* Code blocks */ + .markdown-content pre { + background-color: var(--ct-theme-color-surface, #f9fafb); + padding: var(--ct-theme-padding-block, var(--ct-spacing-3, 0.75rem)); + border-radius: var(--ct-theme-border-radius, 0.5rem); + border: 1px solid var(--ct-theme-color-border, #e5e7eb); + overflow-x: auto; + margin: var(--ct-theme-spacing, var(--ct-spacing-3, 0.75rem)) 0; + } + + .markdown-content pre code { + background-color: transparent; + padding: 0; + font-size: 0.875em; + } + + /* Inverse variant code blocks */ + .markdown-content.inverse pre { + background-color: var( + --ct-markdown-inverse-surface, + rgba(255, 255, 255, 0.2) + ); + border: none; + } + + .markdown-content.inverse pre code { + color: inherit; + } + + /* Code block container with copy button */ + .code-block-container { + position: relative; + } + + .code-copy-button { + position: absolute; + top: var(--ct-theme-spacing-normal, var(--ct-spacing-2, 0.5rem)); + right: var(--ct-theme-spacing-normal, var(--ct-spacing-2, 0.5rem)); + opacity: 0; + transition: opacity var(--ct-theme-animation-duration, 0.2s) ease; + z-index: 1; + } + + .code-block-container:hover .code-copy-button { + opacity: 1; + } + + /* Blockquotes */ + .markdown-content blockquote { + border-left: 4px solid var(--ct-theme-color-border, #e5e7eb); + margin: var(--ct-theme-spacing, var(--ct-spacing-3, 0.75rem)) 0; + padding-left: var(--ct-theme-padding, var(--ct-spacing-3, 0.75rem)); + font-style: italic; + color: var(--ct-theme-color-text-muted, #6b7280); + } + + .markdown-content blockquote p:last-child { + margin-bottom: 0; + } + + /* Inverse variant blockquotes */ + .markdown-content.inverse blockquote { + border-left-color: var( + --ct-markdown-inverse-accent, + rgba(255, 255, 255, 0.6) + ); + color: inherit; + opacity: 0.9; + } + + /* Horizontal rules */ + .markdown-content hr { + border: none; + border-top: 1px solid var(--ct-theme-color-border, #e5e7eb); + margin: 1.5em 0; + } + + .markdown-content.inverse hr { + border-top-color: var( + --ct-markdown-inverse-border, + rgba(255, 255, 255, 0.3) + ); + } + + /* Tables */ + .markdown-content table { + border-collapse: collapse; + width: 100%; + margin: var(--ct-theme-spacing, var(--ct-spacing-3, 0.75rem)) 0; + } + + .markdown-content th, + .markdown-content td { + border: 1px solid var(--ct-theme-color-border, #e5e7eb); + padding: 0.5em 1em; + text-align: left; + } + + .markdown-content th { + background-color: var(--ct-theme-color-surface, #f9fafb); + font-weight: 600; + } + + /* Inverse variant tables */ + .markdown-content.inverse th, + .markdown-content.inverse td { + border-color: var( + --ct-markdown-inverse-border, + rgba(255, 255, 255, 0.3) + ); + } + + .markdown-content.inverse th { + background-color: var( + --ct-markdown-inverse-surface-subtle, + rgba(255, 255, 255, 0.1) + ); + } + + /* Images */ + .markdown-content img { + max-width: 100%; + height: auto; + border-radius: var(--ct-theme-border-radius, 0.5rem); + } + + /* Strong and emphasis */ + .markdown-content strong { + font-weight: 600; + } + + .markdown-content em { + font-style: italic; + } + + /* Task lists */ + .markdown-content input[type="checkbox"] { + margin-right: 0.5em; + } + `, + ]; + + @property({ attribute: false }) + declare content: Cell | string; + + @property({ type: String, reflect: true }) + declare variant: MarkdownVariant; + + @property({ type: Boolean, reflect: true }) + declare streaming: boolean; + + @property({ type: Boolean, reflect: true }) + declare compact: boolean; + + @consume({ context: themeContext, subscribe: true }) + @property({ attribute: false }) + declare theme?: CTTheme; + + private _unsubscribe: (() => void) | null = null; + + constructor() { + super(); + this.content = ""; + this.variant = "default"; + this.streaming = false; + this.compact = false; + } + + private _getContentValue(): string { + if (isCell(this.content)) { + return this.content.get() ?? ""; + } + return this.content ?? ""; + } + + private _renderMarkdown(content: string): string { + if (!content) return ""; + + // Use marked.parse with options to avoid mutating global state + let renderedHtml = marked.parse(content, { + breaks: true, + gfm: true, + }) as string; + + // Wrap code blocks with copy buttons + renderedHtml = this._wrapCodeBlocksWithCopyButtons(renderedHtml); + + // Replace cell links with ct-cell-link + renderedHtml = this._replaceCellLinks(renderedHtml); + + // TODO(CT-1088): XSS VULNERABILITY - This component uses unsafeHTML without sanitization! + // + // We need to sanitize the HTML to prevent XSS attacks. Originally we used DOMPurify + // but it added a dependency (isomorphic-dompurify) that caused lockfile issues. + // + // Options to fix this: + // 1. Add DOMPurify back with proper lockfile management + // 2. Implement our own sanitizer that allows our custom elements (ct-cell-link, ct-copy-button) + // 3. Find an alternative sanitization library + // + // For now, only use this component with trusted markdown content! + // + // Security note: The _escapeForAttribute() method helps prevent attribute injection, + // but this doesn't protect against