From 029379684a0cc0edfe688c7e58ad6b4d58a5f8c6 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:30:31 +0000 Subject: [PATCH 01/28] feat(slack): add @v2bot Slack integration via Bolt Socket Mode - Single-message replies formatted for Slack mrkdwn - DMs and channel @mentions supported (reply in thread) - Uses Bun; add scripts and Prettier format Co-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- .gitignore | 1 + package.json | 8 +++- slack.ts | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 slack.ts diff --git a/.gitignore b/.gitignore index 95e8d9f9..04d99caf 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +node_modules/ /.env.local \ No newline at end of file diff --git a/package.json b/package.json index 484a98ca..74b214cf 100644 --- a/package.json +++ b/package.json @@ -6,17 +6,21 @@ "scripts": { "test": "vitest run", "test:core": "vitest run tests/contract.spec.ts tests/scenario.spec.ts", - "test:e2e": "vitest run tests/e2e_nl_sql.spec.ts" + "test:e2e": "vitest run tests/e2e_nl_sql.spec.ts", + "start:slack": "bun slack.ts", + "format": "prettier --write ." }, "dependencies": { "ai": "^5.0.44", "blink": "^0.1.19", "esbuild": "^0.25.9", "pg": "^8.13.0", - "zod": "^4.1.8" + "zod": "^4.1.8", + "@slack/bolt": "^3.22.0" }, "devDependencies": { "@types/node": "^24.4.0", + "prettier": "^3.3.3", "vitest": "^2.0.0" } } diff --git a/slack.ts b/slack.ts new file mode 100644 index 00000000..50a8d5f7 --- /dev/null +++ b/slack.ts @@ -0,0 +1,118 @@ +import { App, LogLevel } from "@slack/bolt"; +import { z } from "zod"; +import { generateText, tool } from "ai"; +import { buildSystemPrompt } from "./prompt.js"; +import { getSchema, runQuery } from "./db.js"; + +const appToken = process.env.SLACK_APP_TOKEN; // xapp-*** (Socket Mode) +const botToken = process.env.SLACK_BOT_TOKEN; // xoxb-*** + +if (!appToken || !botToken) { + console.warn( + "SLACK_APP_TOKEN and SLACK_BOT_TOKEN are required to run Slack Socket Mode.", + ); +} + +const app = new App({ + socketMode: true, + appToken, + token: botToken, + logLevel: LogLevel.INFO, +}); + +async function runAgentOnce(userText: string): Promise { + const res = await generateText({ + model: "anthropic/claude-sonnet-4", + system: buildSystemPrompt(), + messages: [{ role: "user", content: userText }], + tools: { + db_schema: tool({ + description: + "Return the schema and usage notes for the Neon database backing GitHub Project insights. Includes tables, columns, indexes, and a concise guide for common queries using project_name.", + inputSchema: z.object({}), + execute: async () => { + const schema = await getSchema(); + return schema; + }, + }), + db_query: tool({ + description: + "Execute a read-only SQL SELECT against the Neon database. Use project_name for scoping; default lookback is the last 7 days for 'what's new' queries. Returns rows with enforced LIMIT/OFFSET (max 2000).", + inputSchema: z.object({ + sql: z + .string() + .describe("A single SELECT (or WITH ... SELECT) statement."), + params: z.array(z.any()).optional().default([]), + limit: z.number().int().min(1).max(2000).optional().default(200), + offset: z.number().int().min(0).optional().default(0), + timeoutMs: z + .number() + .int() + .min(1000) + .max(60000) + .optional() + .default(15000), + }), + execute: async ({ sql, params, limit, offset, timeoutMs }) => { + const result = await runQuery({ sql, params, limit, offset, timeoutMs }); + return result; + }, + }), + }, + }); + const text = res.text || "_No response._"; + return `🧐 ${text}`; +} + +function cleanMention(text: string, botUserId?: string): string { + let t = text || ""; + if (botUserId) { + const mention = new RegExp(`<@${botUserId}>`, "g"); + t = t.replace(mention, "").trim(); + } + return t; +} + +app.event("app_mention", async ({ event, client, logger, context }) => { + try { + const botUserId = context.botUserId as string | undefined; + const userText = cleanMention((event as any).text || "", botUserId); + const answer = await runAgentOnce(userText); + await client.chat.postMessage({ + channel: event.channel, + text: answer, + mrkdwn: true as any, + thread_ts: (event as any).thread_ts || (event as any).ts, + }); + } catch (err) { + logger.error(err); + } +}); + +app.event("message", async ({ event, client, logger }) => { + try { + const e: any = event; + if (e.channel_type !== "im" || e.subtype) return; + const answer = await runAgentOnce(e.text || ""); + await client.chat.postMessage({ + channel: e.channel, + text: answer, + mrkdwn: true as any, + thread_ts: e.thread_ts || e.ts, + }); + } catch (err) { + logger.error(err); + } +}); + +export async function startSlack() { + await app.start(); + console.log("Slack app (@v2bot) running in Socket Mode"); +} + +if (import.meta.main) { + startSlack().catch((err) => { + console.error(err); + process.exit(1); + }); +} From 9e807c364f8277b44fe0bfb9ee00e22375851812 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:31:58 +0000 Subject: [PATCH 02/28] feat(slack): add thinking reaction while processing\n\n- Add :face_with_monocle: reaction on receipt and remove after reply for DMs and mentions\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/slack.ts b/slack.ts index 50a8d5f7..4639a24c 100644 --- a/slack.ts +++ b/slack.ts @@ -20,6 +20,8 @@ const app = new App({ logLevel: LogLevel.INFO, }); +const REACTION = "face_with_monocle"; // 🧐 + async function runAgentOnce(userText: string): Promise { const res = await generateText({ model: "anthropic/claude-sonnet-4", @@ -54,7 +56,13 @@ async function runAgentOnce(userText: string): Promise { .default(15000), }), execute: async ({ sql, params, limit, offset, timeoutMs }) => { - const result = await runQuery({ sql, params, limit, offset, timeoutMs }); + const result = await runQuery({ + sql, + params, + limit, + offset, + timeoutMs, + }); return result; }, }), @@ -77,6 +85,13 @@ app.event("app_mention", async ({ event, client, logger, context }) => { try { const botUserId = context.botUserId as string | undefined; const userText = cleanMention((event as any).text || "", botUserId); + const channel = event.channel; + const ts = (event as any).ts; + try { + await client.reactions.add({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_add_reaction"); + } const answer = await runAgentOnce(userText); await client.chat.postMessage({ channel: event.channel, @@ -84,6 +99,11 @@ app.event("app_mention", async ({ event, client, logger, context }) => { mrkdwn: true as any, thread_ts: (event as any).thread_ts || (event as any).ts, }); + try { + await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_remove_reaction"); + } } catch (err) { logger.error(err); } @@ -93,6 +113,13 @@ app.event("message", async ({ event, client, logger }) => { try { const e: any = event; if (e.channel_type !== "im" || e.subtype) return; + const channel = e.channel; + const ts = e.ts; + try { + await client.reactions.add({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_add_reaction"); + } const answer = await runAgentOnce(e.text || ""); await client.chat.postMessage({ channel: e.channel, @@ -100,6 +127,11 @@ app.event("message", async ({ event, client, logger }) => { mrkdwn: true as any, thread_ts: e.thread_ts || e.ts, }); + try { + await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_remove_reaction"); + } } catch (err) { logger.error(err); } From 339fee0a771e053042ede2d7fc611919941f7cd7 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:34:10 +0000 Subject: [PATCH 03/28] chore(ci): update package-lock.json to reflect Slack deps for npm ci\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- package-lock.json | 3121 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 2951 insertions(+), 170 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f8ab242..9e21e7f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "name": "github-project-agent", "dependencies": { + "@slack/bolt": "^3.22.0", "ai": "^5.0.44", "blink": "^0.1.19", "esbuild": "^0.25.9", @@ -14,6 +15,7 @@ }, "devDependencies": { "@types/node": "^24.4.0", + "prettier": "^3.3.3", "vitest": "^2.0.0" } }, @@ -797,10 +799,183 @@ "win32" ] }, + "node_modules/@slack/bolt": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@slack/bolt/-/bolt-3.22.0.tgz", + "integrity": "sha512-iKDqGPEJDnrVwxSVlFW6OKTkijd7s4qLBeSufoBsTM0reTyfdp/5izIQVkxNfzjHi3o6qjdYbRXkYad5HBsBog==", + "license": "MIT", + "dependencies": { + "@slack/logger": "^4.0.0", + "@slack/oauth": "^2.6.3", + "@slack/socket-mode": "^1.3.6", + "@slack/types": "^2.13.0", + "@slack/web-api": "^6.13.0", + "@types/express": "^4.16.1", + "@types/promise.allsettled": "^1.0.3", + "@types/tsscmp": "^1.0.0", + "axios": "^1.7.4", + "express": "^4.21.0", + "path-to-regexp": "^8.1.0", + "promise.allsettled": "^1.0.2", + "raw-body": "^2.3.3", + "tsscmp": "^1.0.6" + }, + "engines": { + "node": ">=14.21.3", + "npm": ">=6.14.18" + } + }, + "node_modules/@slack/logger": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@slack/logger/-/logger-4.0.0.tgz", + "integrity": "sha512-Wz7QYfPAlG/DR+DfABddUZeNgoeY7d1J39OCR2jR+v7VBsB8ezulDK5szTnDDPDwLH5IWhLvXIHlCFZV7MSKgA==", + "license": "MIT", + "dependencies": { + "@types/node": ">=18.0.0" + }, + "engines": { + "node": ">= 18", + "npm": ">= 8.6.0" + } + }, + "node_modules/@slack/oauth": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@slack/oauth/-/oauth-2.6.3.tgz", + "integrity": "sha512-1amXs6xRkJpoH6zSgjVPgGEJXCibKNff9WNDijcejIuVy1HFAl1adh7lehaGNiHhTWfQkfKxBiF+BGn56kvoFw==", + "license": "MIT", + "dependencies": { + "@slack/logger": "^3.0.0", + "@slack/web-api": "^6.12.1", + "@types/jsonwebtoken": "^8.3.7", + "@types/node": ">=12", + "jsonwebtoken": "^9.0.0", + "lodash.isstring": "^4.0.1" + }, + "engines": { + "node": ">=12.13.0", + "npm": ">=6.12.0" + } + }, + "node_modules/@slack/oauth/node_modules/@slack/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@slack/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA==", + "license": "MIT", + "dependencies": { + "@types/node": ">=12.0.0" + }, + "engines": { + "node": ">= 12.13.0", + "npm": ">= 6.12.0" + } + }, + "node_modules/@slack/socket-mode": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@slack/socket-mode/-/socket-mode-1.3.6.tgz", + "integrity": "sha512-G+im7OP7jVqHhiNSdHgv2VVrnN5U7KY845/5EZimZkrD4ZmtV0P3BiWkgeJhPtdLuM7C7i6+M6h6Bh+S4OOalA==", + "license": "MIT", + "dependencies": { + "@slack/logger": "^3.0.0", + "@slack/web-api": "^6.12.1", + "@types/node": ">=12.0.0", + "@types/ws": "^7.4.7", + "eventemitter3": "^5", + "finity": "^0.5.4", + "ws": "^7.5.3" + }, + "engines": { + "node": ">=12.13.0", + "npm": ">=6.12.0" + } + }, + "node_modules/@slack/socket-mode/node_modules/@slack/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@slack/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA==", + "license": "MIT", + "dependencies": { + "@types/node": ">=12.0.0" + }, + "engines": { + "node": ">= 12.13.0", + "npm": ">= 6.12.0" + } + }, + "node_modules/@slack/types": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@slack/types/-/types-2.16.0.tgz", + "integrity": "sha512-bICnyukvdklXhwxprR3uF1+ZFkTvWTZge4evlCS4G1H1HU6QLY68AcjqzQRymf7/5gNt6Y4OBb4NdviheyZcAg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0", + "npm": ">= 6.12.0" + } + }, + "node_modules/@slack/web-api": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-6.13.0.tgz", + "integrity": "sha512-dv65crIgdh9ZYHrevLU6XFHTQwTyDmNqEqzuIrV+Vqe/vgiG6w37oex5ePDU1RGm2IJ90H8iOvHFvzdEO/vB+g==", + "license": "MIT", + "dependencies": { + "@slack/logger": "^3.0.0", + "@slack/types": "^2.11.0", + "@types/is-stream": "^1.1.0", + "@types/node": ">=12.0.0", + "axios": "^1.7.4", + "eventemitter3": "^3.1.0", + "form-data": "^2.5.0", + "is-electron": "2.2.2", + "is-stream": "^1.1.0", + "p-queue": "^6.6.1", + "p-retry": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0", + "npm": ">= 6.12.0" + } + }, + "node_modules/@slack/web-api/node_modules/@slack/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@slack/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA==", + "license": "MIT", + "dependencies": { + "@types/node": ">=12.0.0" + }, + "engines": { + "node": ">= 12.13.0", + "npm": ">= 6.12.0" + } + }, + "node_modules/@slack/web-api/node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "license": "MIT" + }, "node_modules/@standard-schema/spec": { "version": "1.0.0", "license": "MIT" }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -808,16 +983,129 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/express": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", + "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "24.4.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.4.0.tgz", "integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.11.0" } }, + "node_modules/@types/promise.allsettled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/promise.allsettled/-/promise.allsettled-1.0.6.tgz", + "integrity": "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/tsscmp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/tsscmp/-/tsscmp-1.0.2.tgz", + "integrity": "sha512-cy7BRSU8GYYgxjcx0Py+8lo5MthuDhlyu076KUcYzVNXL23luYgRHkMG2fIFEc6neckeh/ntP82mw+U4QjZq+g==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@vitest/expect": { "version": "2.1.9", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", @@ -931,6 +1219,19 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/ai": { "version": "5.0.44", "license": "Apache-2.0", @@ -947,6 +1248,70 @@ "zod": "^3.25.76 || ^4" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array.prototype.map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.8.tgz", + "integrity": "sha512-YocPM7bYYu2hXGxWpb5vwZ8cMeudNHYtYBcUDY4Z1GWa53qcnQMWSl25jeBHNzitjl9HW2AWW4ro/S/nftUaOQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-array-method-boxes-properly": "^1.0.0", + "es-object-atoms": "^1.0.0", + "is-string": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -957,6 +1322,63 @@ "node": ">=12" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/blink": { "version": "0.1.19", "dependencies": { @@ -970,6 +1392,60 @@ "esbuild": "^0.25.9" } }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -980,6 +1456,53 @@ "node": ">=8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/chai": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", @@ -1007,59 +1530,414 @@ "node": ">= 16" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=6.0" + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "engines": { + "node": ">= 0.6" } }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, - "node_modules/esbuild": { - "version": "0.25.9", - "hasInstallScript": true, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.25.9", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", @@ -1417,6 +2295,12 @@ "node": ">=18" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -1427,6 +2311,21 @@ "@types/estree": "^1.0.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/eventsource-parser": { "version": "3.0.6", "license": "MIT", @@ -1444,82 +2343,1200 @@ "node": ">=12.0.0" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/json-schema": { - "version": "0.4.0", - "license": "(AFL-2.1 OR BSD-3-Clause)" + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "dev": true, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, + "node_modules/finity": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/finity/-/finity-0.5.4.tgz", + "integrity": "sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" } ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "dev": true, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "license": "MIT", - "engines": { + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-electron": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz", + "integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==", + "license": "MIT" + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/iterate-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", + "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "license": "MIT", + "dependencies": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { "node": ">= 14.16" } }, @@ -1589,119 +3606,550 @@ "node": ">=4" } }, - "node_modules/pgpass": { - "version": "1.0.5", + "node_modules/pgpass": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/promise.allsettled": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.7.tgz", + "integrity": "sha512-hezvKvQQmsFkOdrZfYxUxkyxl8mgFQeT259Ajj9PXdbg9VzBCWrItOev72JyWxkCD5VSSqAeHmlN3tWx4DlmsA==", + "license": "MIT", + "dependencies": { + "array.prototype.map": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "iterate-value": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rollup": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz", + "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.50.2", + "@rollup/rollup-android-arm64": "4.50.2", + "@rollup/rollup-darwin-arm64": "4.50.2", + "@rollup/rollup-darwin-x64": "4.50.2", + "@rollup/rollup-freebsd-arm64": "4.50.2", + "@rollup/rollup-freebsd-x64": "4.50.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.2", + "@rollup/rollup-linux-arm-musleabihf": "4.50.2", + "@rollup/rollup-linux-arm64-gnu": "4.50.2", + "@rollup/rollup-linux-arm64-musl": "4.50.2", + "@rollup/rollup-linux-loong64-gnu": "4.50.2", + "@rollup/rollup-linux-ppc64-gnu": "4.50.2", + "@rollup/rollup-linux-riscv64-gnu": "4.50.2", + "@rollup/rollup-linux-riscv64-musl": "4.50.2", + "@rollup/rollup-linux-s390x-gnu": "4.50.2", + "@rollup/rollup-linux-x64-gnu": "4.50.2", + "@rollup/rollup-linux-x64-musl": "4.50.2", + "@rollup/rollup-openharmony-arm64": "4.50.2", + "@rollup/rollup-win32-arm64-msvc": "4.50.2", + "@rollup/rollup-win32-ia32-msvc": "4.50.2", + "@rollup/rollup-win32-x64-msvc": "4.50.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "license": "MIT", "dependencies": { - "split2": "^4.1.0" + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 0.4" } }, - "node_modules/postgres-array": { - "version": "2.0.0", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/postgres-bytea": { + "node_modules/set-proto": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/postgres-date": { - "version": "1.0.7", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postgres-interval": { - "version": "1.2.0", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { - "xtend": "^4.0.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup": { - "version": "4.50.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz", - "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==", - "dev": true, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" }, - "bin": { - "rollup": "dist/bin/rollup" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.2", - "@rollup/rollup-android-arm64": "4.50.2", - "@rollup/rollup-darwin-arm64": "4.50.2", - "@rollup/rollup-darwin-x64": "4.50.2", - "@rollup/rollup-freebsd-arm64": "4.50.2", - "@rollup/rollup-freebsd-x64": "4.50.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.2", - "@rollup/rollup-linux-arm-musleabihf": "4.50.2", - "@rollup/rollup-linux-arm64-gnu": "4.50.2", - "@rollup/rollup-linux-arm64-musl": "4.50.2", - "@rollup/rollup-linux-loong64-gnu": "4.50.2", - "@rollup/rollup-linux-ppc64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-gnu": "4.50.2", - "@rollup/rollup-linux-riscv64-musl": "4.50.2", - "@rollup/rollup-linux-s390x-gnu": "4.50.2", - "@rollup/rollup-linux-x64-gnu": "4.50.2", - "@rollup/rollup-linux-x64-musl": "4.50.2", - "@rollup/rollup-openharmony-arm64": "4.50.2", - "@rollup/rollup-win32-arm64-msvc": "4.50.2", - "@rollup/rollup-win32-ia32-msvc": "4.50.2", - "@rollup/rollup-win32-x64-msvc": "4.50.2", - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/siginfo": { @@ -1735,6 +4183,15 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/std-env": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", @@ -1742,6 +4199,75 @@ "dev": true, "license": "MIT" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -1786,13 +4312,162 @@ "node": ">=14.0.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "license": "MIT", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici-types": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.11.0.tgz", "integrity": "sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==", - "dev": true, "license": "MIT" }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { "version": "5.4.20", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", @@ -2015,6 +4690,91 @@ } } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -2032,6 +4792,27 @@ "node": ">=8" } }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "license": "MIT", From 496540f3c6f946cea61accfea2920a496e5853d5 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:37:40 +0000 Subject: [PATCH 04/28] chore(slack): update runtime log name to ProjectBot\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack.ts b/slack.ts index 4639a24c..a700985a 100644 --- a/slack.ts +++ b/slack.ts @@ -139,7 +139,7 @@ app.event("message", async ({ event, client, logger }) => { export async function startSlack() { await app.start(); - console.log("Slack app (@v2bot) running in Socket Mode"); + console.log("Slack app (ProjectBot) running in Socket Mode"); } if (import.meta.main) { From 14d4a9dbca6af581526b4b96a177c4a44ec05720 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:50:08 +0000 Subject: [PATCH 05/28] fix(slack): handle empty messages to avoid blank content errors\n\n- If the user message is empty (e.g., only @mention), return a help prompt instead of calling the LLM\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/slack.ts b/slack.ts index a700985a..6d2555f4 100644 --- a/slack.ts +++ b/slack.ts @@ -23,6 +23,9 @@ const app = new App({ const REACTION = "face_with_monocle"; // 🧐 async function runAgentOnce(userText: string): Promise { + if (!userText || userText.trim().length === 0) { + return "🧐 Ask me about your GitHub Projects. Examples:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X"; + } const res = await generateText({ model: "anthropic/claude-sonnet-4", system: buildSystemPrompt(), From 375e90c95f3c4d2f37c0a1199710fabf343cc0e4 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:56:11 +0000 Subject: [PATCH 06/28] =?UTF-8?q?chore(slack):=20use=20monocle=20only=20as?= =?UTF-8?q?=20reaction;=20remove=20emoji=20prefix=20from=20replies\n\n-=20?= =?UTF-8?q?Replies=20no=20longer=20include=20the=20=F0=9F=A7=90=20emoji\n-?= =?UTF-8?q?=20Still=20add/remove=20:face=5Fwith=5Fmonocle:=20as=20a=20thin?= =?UTF-8?q?king=20reaction\n\nCo-authored-by:=20mattvollmer=20<95866673+ma?= =?UTF-8?q?ttvollmer@users.noreply.github.com>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slack.ts b/slack.ts index 6d2555f4..7bacfcff 100644 --- a/slack.ts +++ b/slack.ts @@ -98,7 +98,7 @@ app.event("app_mention", async ({ event, client, logger, context }) => { const answer = await runAgentOnce(userText); await client.chat.postMessage({ channel: event.channel, - text: answer, + text: answer.replace(/:face_with_monocle:/g, ""), // Remove monocle emoji before sending message mrkdwn: true as any, thread_ts: (event as any).thread_ts || (event as any).ts, }); From a89cc6bca42f4cc8bd8c57f22a6e54c02b64ba1f Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:09:32 +0000 Subject: [PATCH 07/28] fix(slack): remove monocle from replies reliably - Strip :face_with_monocle: and U+1F9D0 (with VS16) from all generated text - Remove emoji prefix in runAgentOnce and sanitize before posting - Keep monocle only as a temporary reaction Co-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/slack.ts b/slack.ts index 7bacfcff..952e7d0f 100644 --- a/slack.ts +++ b/slack.ts @@ -22,9 +22,17 @@ const app = new App({ const REACTION = "face_with_monocle"; // 🧐 +function stripMonocle(input: string): string { + return (input || "") + .replace(/:face_with_monocle:|:monocle_face:/g, "") + .replace(/\u{1F9D0}\uFE0F?/gu, "") + .replace(/^\s+/, "") + .trim(); +} + async function runAgentOnce(userText: string): Promise { if (!userText || userText.trim().length === 0) { - return "🧐 Ask me about your GitHub Projects. Examples:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X"; + return "Ask me about your GitHub Projects. Examples:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X"; } const res = await generateText({ model: "anthropic/claude-sonnet-4", @@ -72,7 +80,7 @@ async function runAgentOnce(userText: string): Promise { }, }); const text = res.text || "_No response._"; - return `🧐 ${text}`; + return stripMonocle(text); } function cleanMention(text: string, botUserId?: string): string { @@ -90,23 +98,13 @@ app.event("app_mention", async ({ event, client, logger, context }) => { const userText = cleanMention((event as any).text || "", botUserId); const channel = event.channel; const ts = (event as any).ts; - try { - await client.reactions.add({ channel, name: REACTION, timestamp: ts }); - } catch (err) { - logger.warn({ err }, "failed_to_add_reaction"); - } - const answer = await runAgentOnce(userText); + const answer = stripMonocle(await runAgentOnce(userText)); await client.chat.postMessage({ channel: event.channel, - text: answer.replace(/:face_with_monocle:/g, ""), // Remove monocle emoji before sending message + text: stripMonocle(answer), mrkdwn: true as any, thread_ts: (event as any).thread_ts || (event as any).ts, }); - try { - await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); - } catch (err) { - logger.warn({ err }, "failed_to_remove_reaction"); - } } catch (err) { logger.error(err); } @@ -116,25 +114,13 @@ app.event("message", async ({ event, client, logger }) => { try { const e: any = event; if (e.channel_type !== "im" || e.subtype) return; - const channel = e.channel; - const ts = e.ts; - try { - await client.reactions.add({ channel, name: REACTION, timestamp: ts }); - } catch (err) { - logger.warn({ err }, "failed_to_add_reaction"); - } - const answer = await runAgentOnce(e.text || ""); + const answer = stripMonocle(await runAgentOnce(e.text || "")); await client.chat.postMessage({ channel: e.channel, - text: answer, + text: stripMonocle(answer), mrkdwn: true as any, thread_ts: e.thread_ts || e.ts, }); - try { - await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); - } catch (err) { - logger.warn({ err }, "failed_to_remove_reaction"); - } } catch (err) { logger.error(err); } From c2dc3948204fc03233af738b7d662f0b1c92aea2 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:13:48 +0000 Subject: [PATCH 08/28] fix(slack): restore thinking reaction add/remove around request handling - Add :face_with_monocle: on receipt; remove after reply in both DMs and mentions - Use try/finally to guarantee reaction removal Co-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 48 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/slack.ts b/slack.ts index 952e7d0f..1e1ddb75 100644 --- a/slack.ts +++ b/slack.ts @@ -93,36 +93,68 @@ function cleanMention(text: string, botUserId?: string): string { } app.event("app_mention", async ({ event, client, logger, context }) => { + const botUserId = context.botUserId as string | undefined; + const userText = cleanMention((event as any).text || "", botUserId); + const channel = event.channel as string; + const ts = (event as any).ts as string; + try { - const botUserId = context.botUserId as string | undefined; - const userText = cleanMention((event as any).text || "", botUserId); - const channel = event.channel; - const ts = (event as any).ts; + // Add thinking face reaction + try { + await client.reactions.add({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_add_reaction"); + } + const answer = stripMonocle(await runAgentOnce(userText)); + + // Post a message as a reply await client.chat.postMessage({ - channel: event.channel, + channel, text: stripMonocle(answer), mrkdwn: true as any, thread_ts: (event as any).thread_ts || (event as any).ts, }); } catch (err) { logger.error(err); + } finally { + // Ensure the reaction is removed + try { + await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_remove_reaction"); + } } }); app.event("message", async ({ event, client, logger }) => { + const e: any = event; + if (e.channel_type !== "im" || e.subtype) return; + const channel = e.channel as string; + const ts = e.ts as string; + try { - const e: any = event; - if (e.channel_type !== "im" || e.subtype) return; + try { + await client.reactions.add({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_add_reaction"); + } + const answer = stripMonocle(await runAgentOnce(e.text || "")); await client.chat.postMessage({ - channel: e.channel, + channel, text: stripMonocle(answer), mrkdwn: true as any, thread_ts: e.thread_ts || e.ts, }); } catch (err) { logger.error(err); + } finally { + try { + await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); + } catch (err) { + logger.warn({ err }, "failed_to_remove_reaction"); + } } }); From f706d8117e974c42ba9afc1262e3b89de9622d88 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:17:26 +0000 Subject: [PATCH 09/28] chore(slack): enforce single-message answers without preamble; require tools for results\n\n- Append Slack-specific behavior to system prompt\n- Keep thinking reaction add/remove intact\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slack.ts b/slack.ts index 1e1ddb75..00c1a235 100644 --- a/slack.ts +++ b/slack.ts @@ -34,9 +34,12 @@ async function runAgentOnce(userText: string): Promise { if (!userText || userText.trim().length === 0) { return "Ask me about your GitHub Projects. Examples:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X"; } + const system = + buildSystemPrompt() + + "\n\nSlack behavior:\n- Return a single final message with results.\n- Do not write preambles like 'I'll help you' or 'let me check'.\n- If tools are needed, call them and include the results in this one message.\n- Keep answers concise and formatted for Slack mrkdwn.\n"; const res = await generateText({ model: "anthropic/claude-sonnet-4", - system: buildSystemPrompt(), + system, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ From e17063dd6a92d3fc870c4e2d64917cb9e5975c7c Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:20:43 +0000 Subject: [PATCH 10/28] fix(slack): actually execute tools with generateText (toolChoice:auto, maxToolRoundtrips=5, temp=0)\n\n- Prevent preamble-only replies by allowing tool calls in non-streaming mode\n- Keep single-message reply semantics\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/slack.ts b/slack.ts index 00c1a235..19c5bf39 100644 --- a/slack.ts +++ b/slack.ts @@ -40,6 +40,9 @@ async function runAgentOnce(userText: string): Promise { const res = await generateText({ model: "anthropic/claude-sonnet-4", system, + temperature: 0, + toolChoice: "auto" as const, + maxToolRoundtrips: 5 as const, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ From 6b1d4c58ef0ed2bc4f927588008be9b80533ef19 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:29:29 +0000 Subject: [PATCH 11/28] refactor(slack): force single-message reply via slack_send tool using streamText\n\n- Introduce slack_send tool that posts to the thread\n- Enforce tool-only reply in system prompt; remove preambles\n- Manage thinking reaction around full execution\n- Fallback to posting final text if tool not called\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/slack.ts b/slack.ts index 19c5bf39..f1230659 100644 --- a/slack.ts +++ b/slack.ts @@ -1,6 +1,6 @@ import { App, LogLevel } from "@slack/bolt"; import { z } from "zod"; -import { generateText, tool } from "ai"; +import { streamText, tool } from "ai"; import { buildSystemPrompt } from "./prompt.js"; import { getSchema, runQuery } from "./db.js"; @@ -36,13 +36,13 @@ async function runAgentOnce(userText: string): Promise { } const system = buildSystemPrompt() + - "\n\nSlack behavior:\n- Return a single final message with results.\n- Do not write preambles like 'I'll help you' or 'let me check'.\n- If tools are needed, call them and include the results in this one message.\n- Keep answers concise and formatted for Slack mrkdwn.\n"; - const res = await generateText({ + "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like 'I'll help you' or 'let me check'.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.\n"; + const res = await streamText({ model: "anthropic/claude-sonnet-4", system, temperature: 0, toolChoice: "auto" as const, - maxToolRoundtrips: 5 as const, + maxToolRoundtrips: 8 as const, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ @@ -83,6 +83,24 @@ async function runAgentOnce(userText: string): Promise { return result; }, }), + slack_send: tool({ + description: + "Send exactly one Slack message in the current thread. Use mrkdwn formatting.", + inputSchema: z.object({ + text: z.string().min(1), + }), + execute: async ({ text }) => { + const clean = stripMonocle(text); + await client.chat.postMessage({ + channel, + thread_ts, + mrkdwn: true, + text: clean, + }); + postedByTool = true; + return { ok: true }; + }, + }), }, }); const text = res.text || "_No response._"; From 9ce930690c925c43dcc457ce218c0d6ba8ec53cd Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:39:08 +0000 Subject: [PATCH 12/28] chore(types): add TypeScript typecheck and fix slack.ts types\n\n- Add tsconfig + typecheck script; add @types/pg\n- Refactor Slack agent to streamText with slack_send tool; fix scoping and typings\n- Remove unsupported maxSteps; use result.text\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- package.json | 5 ++++- slack.ts | 59 ++++++++++++++++++++++++++------------------------- tsconfig.json | 18 ++++++++++++++++ 3 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 tsconfig.json diff --git a/package.json b/package.json index 74b214cf..09ca9683 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "test:core": "vitest run tests/contract.spec.ts tests/scenario.spec.ts", "test:e2e": "vitest run tests/e2e_nl_sql.spec.ts", "start:slack": "bun slack.ts", - "format": "prettier --write ." + "format": "prettier --write .", + "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { "ai": "^5.0.44", @@ -20,7 +21,9 @@ }, "devDependencies": { "@types/node": "^24.4.0", + "@types/pg": "^8.15.5", "prettier": "^3.3.3", + "typescript": "^5.6.3", "vitest": "^2.0.0" } } diff --git a/slack.ts b/slack.ts index f1230659..2b89742a 100644 --- a/slack.ts +++ b/slack.ts @@ -30,19 +30,29 @@ function stripMonocle(input: string): string { .trim(); } -async function runAgentOnce(userText: string): Promise { +async function runAgentSession(args: { + userText: string; + channel: string; + thread_ts: string; + client: any; +}) { + const { userText, channel, thread_ts, client } = args; if (!userText || userText.trim().length === 0) { - return "Ask me about your GitHub Projects. Examples:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X"; + await client.chat.postMessage({ + channel, + thread_ts, + text: "Ask me about your GitHub Projects. For example:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X", + }); + return; } - const system = - buildSystemPrompt() + - "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like 'I'll help you' or 'let me check'.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.\n"; - const res = await streamText({ + let postedByTool = false; + const result = await streamText({ model: "anthropic/claude-sonnet-4", - system, + system: + buildSystemPrompt() + + "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like 'I'll help you' or 'let me check'.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.", temperature: 0, toolChoice: "auto" as const, - maxToolRoundtrips: 8 as const, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ @@ -103,8 +113,13 @@ async function runAgentOnce(userText: string): Promise { }), }, }); - const text = res.text || "_No response._"; - return stripMonocle(text); + if (!postedByTool) { + const finalText = await result.text; // Changed from result.toText() to result.text + const clean = stripMonocle(finalText || "_No response._"); + if (clean.trim().length > 0) { + await client.chat.postMessage({ channel, thread_ts, text: clean }); + } + } } function cleanMention(text: string, botUserId?: string): string { @@ -121,28 +136,19 @@ app.event("app_mention", async ({ event, client, logger, context }) => { const userText = cleanMention((event as any).text || "", botUserId); const channel = event.channel as string; const ts = (event as any).ts as string; + const thread_ts = ((event as any).thread_ts as string) || ts; try { - // Add thinking face reaction try { await client.reactions.add({ channel, name: REACTION, timestamp: ts }); } catch (err) { logger.warn({ err }, "failed_to_add_reaction"); } - const answer = stripMonocle(await runAgentOnce(userText)); - - // Post a message as a reply - await client.chat.postMessage({ - channel, - text: stripMonocle(answer), - mrkdwn: true as any, - thread_ts: (event as any).thread_ts || (event as any).ts, - }); + await runAgentSession({ userText, channel, thread_ts, client }); } catch (err) { logger.error(err); } finally { - // Ensure the reaction is removed try { await client.reactions.remove({ channel, name: REACTION, timestamp: ts }); } catch (err) { @@ -156,6 +162,7 @@ app.event("message", async ({ event, client, logger }) => { if (e.channel_type !== "im" || e.subtype) return; const channel = e.channel as string; const ts = e.ts as string; + const thread_ts = (e.thread_ts as string) || ts; try { try { @@ -164,13 +171,7 @@ app.event("message", async ({ event, client, logger }) => { logger.warn({ err }, "failed_to_add_reaction"); } - const answer = stripMonocle(await runAgentOnce(e.text || "")); - await client.chat.postMessage({ - channel, - text: stripMonocle(answer), - mrkdwn: true as any, - thread_ts: e.thread_ts || e.ts, - }); + await runAgentSession({ userText: e.text || "", channel, thread_ts, client }); } catch (err) { logger.error(err); } finally { @@ -192,4 +193,4 @@ if (import.meta.main) { console.error(err); process.exit(1); }); -} +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..9a7f373c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "types": ["node"], + "lib": ["ES2022"], + "allowArbitraryExtensions": true, + "allowImportingTsExtensions": true + }, + "include": ["*.ts"], + "exclude": ["node_modules", "tests"] +} \ No newline at end of file From 40a1bcf22ab6b190ef043afdc5af83d1323118ea Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:43:33 +0000 Subject: [PATCH 13/28] fix(slack): force final message via slack_send and add strict retry if not called\n\n- toolChoice set to specific tool 'slack_send'\n- Add second strict pass to ensure tool is called\n- Remove plain-text fallback posting\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/slack.ts b/slack.ts index 2b89742a..9d2148f7 100644 --- a/slack.ts +++ b/slack.ts @@ -46,13 +46,14 @@ async function runAgentSession(args: { return; } let postedByTool = false; + const result = await streamText({ model: "anthropic/claude-sonnet-4", system: buildSystemPrompt() + - "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like 'I'll help you' or 'let me check'.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.", + "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like \"I'll help you\" or \"let me check\".\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.\n", temperature: 0, - toolChoice: "auto" as const, + toolChoice: { type: "tool", toolName: "slack_send" } as any, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ @@ -104,7 +105,6 @@ async function runAgentSession(args: { await client.chat.postMessage({ channel, thread_ts, - mrkdwn: true, text: clean, }); postedByTool = true; @@ -113,12 +113,42 @@ async function runAgentSession(args: { }), }, }); + if (!postedByTool) { - const finalText = await result.text; // Changed from result.toText() to result.text - const clean = stripMonocle(finalText || "_No response._"); - if (clean.trim().length > 0) { - await client.chat.postMessage({ channel, thread_ts, text: clean }); - } + // Second strict pass requiring slack_send with no preambles. + const strict = await streamText({ + model: "anthropic/claude-sonnet-4", + system: + buildSystemPrompt() + + "\n\nSlack behavior (strict):\n- You MUST post the answer using slack_send.\n- First call db_schema/db_query as needed.\n- Do NOT output any text except via slack_send.\n- No preambles.\n", + temperature: 0, + toolChoice: { type: "tool", toolName: "slack_send" } as any, + messages: [{ role: "user", content: userText }], + tools: { + db_schema: tool({ inputSchema: z.object({}), execute: async () => getSchema() }), + db_query: tool({ + inputSchema: z.object({ + sql: z.string(), + params: z.array(z.any()).optional().default([]), + limit: z.number().int().min(1).max(2000).optional().default(200), + offset: z.number().int().min(0).optional().default(0), + timeoutMs: z.number().int().min(1000).max(60000).optional().default(15000), + }), + execute: async ({ sql, params, limit, offset, timeoutMs }) => + runQuery({ sql, params, limit, offset, timeoutMs }), + }), + slack_send: tool({ + inputSchema: z.object({ text: z.string().min(1) }), + execute: async ({ text }) => { + const clean = stripMonocle(text); + await client.chat.postMessage({ channel, thread_ts, text: clean }); + postedByTool = true; + return { ok: true }; + }, + }), + }, + }); + await strict.text; // ensure completion } } From 3a6c9c80cbf723c67ec1989d634725f08f386b80 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:49:03 +0000 Subject: [PATCH 14/28] feat(slack): gate slack_send until db_query is executed; switch to auto tool selection; strict retry uses same gate Co-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/slack.ts b/slack.ts index 9d2148f7..3ea30591 100644 --- a/slack.ts +++ b/slack.ts @@ -46,6 +46,7 @@ async function runAgentSession(args: { return; } let postedByTool = false; + let invokedDbQuery = false; const result = await streamText({ model: "anthropic/claude-sonnet-4", @@ -53,7 +54,7 @@ async function runAgentSession(args: { buildSystemPrompt() + "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like \"I'll help you\" or \"let me check\".\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.\n", temperature: 0, - toolChoice: { type: "tool", toolName: "slack_send" } as any, + toolChoice: "auto" as const, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ @@ -84,6 +85,7 @@ async function runAgentSession(args: { .default(15000), }), execute: async ({ sql, params, limit, offset, timeoutMs }) => { + invokedDbQuery = true; const result = await runQuery({ sql, params, @@ -101,6 +103,11 @@ async function runAgentSession(args: { text: z.string().min(1), }), execute: async ({ text }) => { + if (!invokedDbQuery) { + throw new Error( + "Before calling slack_send, you MUST run db_query to fetch data (e.g., for 'what changed today', use changed_at >= date_trunc('day', now()) and filter by project_name). Then call slack_send once with the summarized results." + ); + } const clean = stripMonocle(text); await client.chat.postMessage({ channel, @@ -122,7 +129,7 @@ async function runAgentSession(args: { buildSystemPrompt() + "\n\nSlack behavior (strict):\n- You MUST post the answer using slack_send.\n- First call db_schema/db_query as needed.\n- Do NOT output any text except via slack_send.\n- No preambles.\n", temperature: 0, - toolChoice: { type: "tool", toolName: "slack_send" } as any, + toolChoice: "auto" as const, messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ inputSchema: z.object({}), execute: async () => getSchema() }), @@ -134,12 +141,19 @@ async function runAgentSession(args: { offset: z.number().int().min(0).optional().default(0), timeoutMs: z.number().int().min(1000).max(60000).optional().default(15000), }), - execute: async ({ sql, params, limit, offset, timeoutMs }) => - runQuery({ sql, params, limit, offset, timeoutMs }), + execute: async ({ sql, params, limit, offset, timeoutMs }) => { + invokedDbQuery = true; + return runQuery({ sql, params, limit, offset, timeoutMs }); + }, }), slack_send: tool({ inputSchema: z.object({ text: z.string().min(1) }), execute: async ({ text }) => { + if (!invokedDbQuery) { + throw new Error( + "Before calling slack_send, you MUST run db_query to fetch data (e.g., for 'what changed today', use changed_at >= date_trunc('day', now()) and filter by project_name). Then call slack_send once with the summarized results." + ); + } const clean = stripMonocle(text); await client.chat.postMessage({ channel, thread_ts, text: clean }); postedByTool = true; From 6078b90f22d0ae0f4ffa76de070936aa2b909ee4 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:52:22 +0000 Subject: [PATCH 15/28] fix(slack): correct change-query gating logic and remove erroneous code from last patch\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/slack.ts b/slack.ts index 3ea30591..29f79b8e 100644 --- a/slack.ts +++ b/slack.ts @@ -47,6 +47,9 @@ async function runAgentSession(args: { } let postedByTool = false; let invokedDbQuery = false; + const lc = userText.toLowerCase(); + const requireChanged = /what\\s+changed|changed\\s+(today|recent|this\\s+week|last\\s+\\d+\\s+days)/i.test(lc); + let changedQueryOk = false; const result = await streamText({ model: "anthropic/claude-sonnet-4", @@ -86,6 +89,12 @@ async function runAgentSession(args: { }), execute: async ({ sql, params, limit, offset, timeoutMs }) => { invokedDbQuery = true; + const s = (sql || "").toLowerCase(); + if (requireChanged) { + if (s.includes("from field_changes") && s.includes("changed_at") && s.includes("project_name")) { + changedQueryOk = true; + } + } const result = await runQuery({ sql, params, From 332bde8360a5bc6c86bba42bc38c075f152b1357 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:52:37 +0000 Subject: [PATCH 16/28] chore(ci): sync package-lock.json for npm ci\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- package-lock.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/package-lock.json b/package-lock.json index 9e21e7f5..5907093c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,9 @@ }, "devDependencies": { "@types/node": "^24.4.0", + "@types/pg": "^8.15.5", "prettier": "^3.3.3", + "typescript": "^5.6.3", "vitest": "^2.0.0" } }, @@ -1046,6 +1048,18 @@ "undici-types": "~7.11.0" } }, + "node_modules/@types/pg": { + "version": "8.15.5", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.5.tgz", + "integrity": "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, "node_modules/@types/promise.allsettled": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/promise.allsettled/-/promise.allsettled-1.0.6.tgz", @@ -4417,6 +4431,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", From ffab8018b80e473face483fd16430f9624a826c4 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:58:56 +0000 Subject: [PATCH 17/28] fix(slack): correct string literals in Slack behavior prompt; allow pre-DB clarifications and single post after DB query\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/slack.ts b/slack.ts index 29f79b8e..042a176b 100644 --- a/slack.ts +++ b/slack.ts @@ -48,14 +48,15 @@ async function runAgentSession(args: { let postedByTool = false; let invokedDbQuery = false; const lc = userText.toLowerCase(); - const requireChanged = /what\\s+changed|changed\\s+(today|recent|this\\s+week|last\\s+\\d+\\s+days)/i.test(lc); + const requireChanged = /what\s+changed|changed\s+(today|recent|this\s+week|last\s+\d+\s+days)/i.test(lc); let changedQueryOk = false; + let postedAfterQuery = false; const result = await streamText({ model: "anthropic/claude-sonnet-4", system: buildSystemPrompt() + - "\n\nSlack behavior:\n- You MUST send exactly one final message using the slack_send tool.\n- Do not write preambles like \"I'll help you\" or \"let me check\".\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.\n", + "\n\nSlack behavior:\n- You MAY post brief clarifications or disambiguation via slack_send before any database calls.\n- Once you call db_query, you MUST produce exactly one final results message via slack_send in this run.\n- For results, do not write preambles like \"I'll help you\" — post the answer concisely.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.", temperature: 0, toolChoice: "auto" as const, messages: [{ role: "user", content: userText }], @@ -107,15 +108,22 @@ async function runAgentSession(args: { }), slack_send: tool({ description: - "Send exactly one Slack message in the current thread. Use mrkdwn formatting.", + "Send a Slack message in the current thread. Use mrkdwn formatting.", inputSchema: z.object({ text: z.string().min(1), }), execute: async ({ text }) => { - if (!invokedDbQuery) { - throw new Error( - "Before calling slack_send, you MUST run db_query to fetch data (e.g., for 'what changed today', use changed_at >= date_trunc('day', now()) and filter by project_name). Then call slack_send once with the summarized results." - ); + // Before any DB calls, allow free clarifications. + if (invokedDbQuery) { + // After db_query, allow exactly one final message, and require correct query for 'what changed'. + if (postedAfterQuery) { + throw new Error("You have already posted the final message for this run."); + } + if (requireChanged && !changedQueryOk) { + throw new Error( + "For 'what changed', you MUST query field_changes with changed_at and project_name filters before the final message." + ); + } } const clean = stripMonocle(text); await client.chat.postMessage({ @@ -124,6 +132,7 @@ async function runAgentSession(args: { text: clean, }); postedByTool = true; + if (invokedDbQuery) postedAfterQuery = true; return { ok: true }; }, }), @@ -131,12 +140,11 @@ async function runAgentSession(args: { }); if (!postedByTool) { - // Second strict pass requiring slack_send with no preambles. const strict = await streamText({ model: "anthropic/claude-sonnet-4", system: buildSystemPrompt() + - "\n\nSlack behavior (strict):\n- You MUST post the answer using slack_send.\n- First call db_schema/db_query as needed.\n- Do NOT output any text except via slack_send.\n- No preambles.\n", + "\n\nSlack behavior (strict):\n- You MAY post brief clarifications via slack_send before any DB call.\n- Once you call db_query, you MUST post exactly one final results message via slack_send and stop.\n- Do NOT output any text except via slack_send.", temperature: 0, toolChoice: "auto" as const, messages: [{ role: "user", content: userText }], @@ -152,26 +160,38 @@ async function runAgentSession(args: { }), execute: async ({ sql, params, limit, offset, timeoutMs }) => { invokedDbQuery = true; + const s = (sql || "").toLowerCase(); + if (requireChanged) { + if (s.includes("from field_changes") && s.includes("changed_at") && s.includes("project_name")) { + changedQueryOk = true; + } + } return runQuery({ sql, params, limit, offset, timeoutMs }); }, }), slack_send: tool({ inputSchema: z.object({ text: z.string().min(1) }), execute: async ({ text }) => { - if (!invokedDbQuery) { - throw new Error( - "Before calling slack_send, you MUST run db_query to fetch data (e.g., for 'what changed today', use changed_at >= date_trunc('day', now()) and filter by project_name). Then call slack_send once with the summarized results." - ); + if (invokedDbQuery) { + if (postedAfterQuery) { + throw new Error("You have already posted the final message for this run."); + } + if (requireChanged && !changedQueryOk) { + throw new Error( + "For 'what changed', you MUST query field_changes with changed_at and project_name filters before the final message." + ); + } } const clean = stripMonocle(text); await client.chat.postMessage({ channel, thread_ts, text: clean }); postedByTool = true; + if (invokedDbQuery) postedAfterQuery = true; return { ok: true }; }, }), }, }); - await strict.text; // ensure completion + await strict.text; } } From d2ce2bad6f7b910c39db3aabefe7bad4439ec642 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:03:47 +0000 Subject: [PATCH 18/28] fix(slack): correct quoting in empty-help message and finalize continuous messaging flow\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 180 +++++++++++++++---------------------------------------- 1 file changed, 47 insertions(+), 133 deletions(-) diff --git a/slack.ts b/slack.ts index 042a176b..eb0ee280 100644 --- a/slack.ts +++ b/slack.ts @@ -30,168 +30,82 @@ function stripMonocle(input: string): string { .trim(); } -async function runAgentSession(args: { - userText: string; - channel: string; - thread_ts: string; - client: any; -}) { +async function runAgentSession(args: { userText: string; channel: string; thread_ts: string; client: any }) { const { userText, channel, thread_ts, client } = args; + if (!userText || userText.trim().length === 0) { - await client.chat.postMessage({ - channel, - thread_ts, - text: "Ask me about your GitHub Projects. For example:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X", - }); + await client.chat.postMessage({ channel, thread_ts, text: "Ask me about your GitHub Projects. For example:\n- what's new in the last 7 days for Project X?\n- list items in Project X with Status = In Progress\n- show all changes for repo owner/repo in Project X" }); return; } - let postedByTool = false; - let invokedDbQuery = false; - const lc = userText.toLowerCase(); - const requireChanged = /what\s+changed|changed\s+(today|recent|this\s+week|last\s+\d+\s+days)/i.test(lc); - let changedQueryOk = false; - let postedAfterQuery = false; - - const result = await streamText({ - model: "anthropic/claude-sonnet-4", - system: - buildSystemPrompt() + - "\n\nSlack behavior:\n- You MAY post brief clarifications or disambiguation via slack_send before any database calls.\n- Once you call db_query, you MUST produce exactly one final results message via slack_send in this run.\n- For results, do not write preambles like \"I'll help you\" — post the answer concisely.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.", - temperature: 0, - toolChoice: "auto" as const, - messages: [{ role: "user", content: userText }], - tools: { - db_schema: tool({ - description: - "Return the schema and usage notes for the Neon database backing GitHub Project insights. Includes tables, columns, indexes, and a concise guide for common queries using project_name.", - inputSchema: z.object({}), - execute: async () => { - const schema = await getSchema(); - return schema; - }, - }), - db_query: tool({ - description: - "Execute a read-only SQL SELECT against the Neon database. Use project_name for scoping; default lookback is the last 7 days for 'what's new' queries. Returns rows with enforced LIMIT/OFFSET (max 2000).", - inputSchema: z.object({ - sql: z - .string() - .describe("A single SELECT (or WITH ... SELECT) statement."), - params: z.array(z.any()).optional().default([]), - limit: z.number().int().min(1).max(2000).optional().default(200), - offset: z.number().int().min(0).optional().default(0), - timeoutMs: z - .number() - .int() - .min(1000) - .max(60000) - .optional() - .default(15000), - }), - execute: async ({ sql, params, limit, offset, timeoutMs }) => { - invokedDbQuery = true; - const s = (sql || "").toLowerCase(); - if (requireChanged) { - if (s.includes("from field_changes") && s.includes("changed_at") && s.includes("project_name")) { - changedQueryOk = true; - } - } - const result = await runQuery({ - sql, - params, - limit, - offset, - timeoutMs, - }); - return result; - }, - }), - slack_send: tool({ - description: - "Send a Slack message in the current thread. Use mrkdwn formatting.", - inputSchema: z.object({ - text: z.string().min(1), - }), - execute: async ({ text }) => { - // Before any DB calls, allow free clarifications. - if (invokedDbQuery) { - // After db_query, allow exactly one final message, and require correct query for 'what changed'. - if (postedAfterQuery) { - throw new Error("You have already posted the final message for this run."); - } - if (requireChanged && !changedQueryOk) { - throw new Error( - "For 'what changed', you MUST query field_changes with changed_at and project_name filters before the final message." - ); - } - } - const clean = stripMonocle(text); - await client.chat.postMessage({ - channel, - thread_ts, - text: clean, - }); - postedByTool = true; - if (invokedDbQuery) postedAfterQuery = true; - return { ok: true }; - }, - }), - }, - }); - if (!postedByTool) { - const strict = await streamText({ + try { + await streamText({ model: "anthropic/claude-sonnet-4", system: buildSystemPrompt() + - "\n\nSlack behavior (strict):\n- You MAY post brief clarifications via slack_send before any DB call.\n- Once you call db_query, you MUST post exactly one final results message via slack_send and stop.\n- Do NOT output any text except via slack_send.", + "\n\nSlack behavior:\n- You MAY post brief clarifications or disambiguation via slack_send before any database calls.\n- Once you call db_query, you MUST produce exactly one final results message via slack_send in this run.\n- For results, do not write preambles like \"I'll help you\" — post the answer concisely.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.", temperature: 0, toolChoice: "auto" as const, messages: [{ role: "user", content: userText }], tools: { - db_schema: tool({ inputSchema: z.object({}), execute: async () => getSchema() }), + db_schema: tool({ + description: + "Return the schema and usage notes for the Neon database backing GitHub Project insights. Includes tables, columns, indexes, and a concise guide for common queries using project_name.", + inputSchema: z.object({}), + execute: async () => { + const schema = await getSchema(); + return schema; + }, + }), db_query: tool({ + description: + "Execute a read-only SQL SELECT against the Neon database. Use project_name for scoping; default lookback is the last 7 days for 'what's new' queries. Returns rows with enforced LIMIT/OFFSET (max 2000).", inputSchema: z.object({ - sql: z.string(), + sql: z + .string() + .describe("A single SELECT (or WITH ... SELECT) statement."), params: z.array(z.any()).optional().default([]), limit: z.number().int().min(1).max(2000).optional().default(200), offset: z.number().int().min(0).optional().default(0), - timeoutMs: z.number().int().min(1000).max(60000).optional().default(15000), + timeoutMs: z + .number() + .int() + .min(1000) + .max(60000) + .optional() + .default(15000), }), execute: async ({ sql, params, limit, offset, timeoutMs }) => { - invokedDbQuery = true; - const s = (sql || "").toLowerCase(); - if (requireChanged) { - if (s.includes("from field_changes") && s.includes("changed_at") && s.includes("project_name")) { - changedQueryOk = true; - } - } - return runQuery({ sql, params, limit, offset, timeoutMs }); + const result = await runQuery({ + sql, + params, + limit, + offset, + timeoutMs, + }); + return result; }, }), slack_send: tool({ - inputSchema: z.object({ text: z.string().min(1) }), + description: + "Send a Slack message in the current thread. Use mrkdwn formatting.", + inputSchema: z.object({ + text: z.string().min(1), + }), execute: async ({ text }) => { - if (invokedDbQuery) { - if (postedAfterQuery) { - throw new Error("You have already posted the final message for this run."); - } - if (requireChanged && !changedQueryOk) { - throw new Error( - "For 'what changed', you MUST query field_changes with changed_at and project_name filters before the final message." - ); - } - } const clean = stripMonocle(text); - await client.chat.postMessage({ channel, thread_ts, text: clean }); - postedByTool = true; - if (invokedDbQuery) postedAfterQuery = true; + await client.chat.postMessage({ + channel, + thread_ts, + text: clean, + }); return { ok: true }; }, }), }, }); - await strict.text; + } catch (err) { + console.error("Error in runAgentSession:", err); } } From e8bbe2ff5c79a85fbdf9b8fc848a1b80abf69a6c Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:06:35 +0000 Subject: [PATCH 19/28] feat(slack): add kickoff status, robust error/fallback, and continuous slack_send messaging Co-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 67 +++++++++++++++++++------------------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/slack.ts b/slack.ts index eb0ee280..a81a6db0 100644 --- a/slack.ts +++ b/slack.ts @@ -38,74 +38,53 @@ async function runAgentSession(args: { userText: string; channel: string; thread return; } + // Kickoff status so the thread shows activity even if the model stalls + await client.chat.postMessage({ channel, thread_ts, text: "Working on it — I’ll reply here with progress and results." }); + + let postedAny = false; + try { await streamText({ model: "anthropic/claude-sonnet-4", system: buildSystemPrompt() + - "\n\nSlack behavior:\n- You MAY post brief clarifications or disambiguation via slack_send before any database calls.\n- Once you call db_query, you MUST produce exactly one final results message via slack_send in this run.\n- For results, do not write preambles like \"I'll help you\" — post the answer concisely.\n- If database results are needed, call db_schema/db_query first, then slack_send with the answer.\n- Format for Slack mrkdwn.\n- Do not include monocle emoji in the message text.", + "\n\nSlack behavior:\n- You MUST communicate only via the slack_send tool; do NOT return assistant text.\n- Send multiple short messages as needed while you work (clarify, disambiguate, and share progress/results).\n- Keep replies in this thread and concise, formatted for Slack mrkdwn.\n- When finished, send a final message with the answer.\n", temperature: 0, toolChoice: "auto" as const, messages: [{ role: "user", content: userText }], tools: { - db_schema: tool({ - description: - "Return the schema and usage notes for the Neon database backing GitHub Project insights. Includes tables, columns, indexes, and a concise guide for common queries using project_name.", - inputSchema: z.object({}), - execute: async () => { - const schema = await getSchema(); - return schema; - }, - }), + db_schema: tool({ inputSchema: z.object({}), description: "Return the schema and usage notes for the Neon database backing GitHub Project insights.", execute: async () => getSchema() }), db_query: tool({ - description: - "Execute a read-only SQL SELECT against the Neon database. Use project_name for scoping; default lookback is the last 7 days for 'what's new' queries. Returns rows with enforced LIMIT/OFFSET (max 2000).", + description: "Execute a read-only SQL SELECT against the Neon database.", inputSchema: z.object({ - sql: z - .string() - .describe("A single SELECT (or WITH ... SELECT) statement."), + sql: z.string().describe("A single SELECT (or WITH ... SELECT) statement."), params: z.array(z.any()).optional().default([]), limit: z.number().int().min(1).max(2000).optional().default(200), offset: z.number().int().min(0).optional().default(0), - timeoutMs: z - .number() - .int() - .min(1000) - .max(60000) - .optional() - .default(15000), + timeoutMs: z.number().int().min(1000).max(60000).optional().default(15000), }), - execute: async ({ sql, params, limit, offset, timeoutMs }) => { - const result = await runQuery({ - sql, - params, - limit, - offset, - timeoutMs, - }); - return result; - }, + execute: async ({ sql, params, limit, offset, timeoutMs }) => runQuery({ sql, params, limit, offset, timeoutMs }), }), slack_send: tool({ - description: - "Send a Slack message in the current thread. Use mrkdwn formatting.", - inputSchema: z.object({ - text: z.string().min(1), - }), + description: "Send a Slack message in the current thread. Use mrkdwn formatting.", + inputSchema: z.object({ text: z.string().min(1) }), execute: async ({ text }) => { const clean = stripMonocle(text); - await client.chat.postMessage({ - channel, - thread_ts, - text: clean, - }); + await client.chat.postMessage({ channel, thread_ts, text: clean }); + postedAny = true; return { ok: true }; }, }), }, }); - } catch (err) { - console.error("Error in runAgentSession:", err); + } catch (err: any) { + const msg = typeof err?.message === "string" ? err.message.slice(0, 600) : "unexpected_error"; + await client.chat.postMessage({ channel, thread_ts, text: `Encountered an error while responding: ${msg}` }); + return; + } + + if (!postedAny) { + await client.chat.postMessage({ channel, thread_ts, text: "I wasn’t able to produce a response. Please rephrase your request (include the project name and timeframe)." }); } } From 6936f715220df2f0242731276d14d7f2c5631f9e Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:11:33 +0000 Subject: [PATCH 20/28] refactor(slack): stream responses directly to Slack with live updates; remove tool-gating approach\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 89 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/slack.ts b/slack.ts index a81a6db0..94699b07 100644 --- a/slack.ts +++ b/slack.ts @@ -38,24 +38,25 @@ async function runAgentSession(args: { userText: string; channel: string; thread return; } - // Kickoff status so the thread shows activity even if the model stalls - await client.chat.postMessage({ channel, thread_ts, text: "Working on it — I’ll reply here with progress and results." }); - - let postedAny = false; + let currentMessageTs: string | null = null; + let accumulatedText = ""; try { - await streamText({ + const result = streamText({ model: "anthropic/claude-sonnet-4", - system: - buildSystemPrompt() + - "\n\nSlack behavior:\n- You MUST communicate only via the slack_send tool; do NOT return assistant text.\n- Send multiple short messages as needed while you work (clarify, disambiguate, and share progress/results).\n- Keep replies in this thread and concise, formatted for Slack mrkdwn.\n- When finished, send a final message with the answer.\n", - temperature: 0, - toolChoice: "auto" as const, + system: buildSystemPrompt(), messages: [{ role: "user", content: userText }], tools: { - db_schema: tool({ inputSchema: z.object({}), description: "Return the schema and usage notes for the Neon database backing GitHub Project insights.", execute: async () => getSchema() }), + db_schema: tool({ + description: "Return the schema and usage notes for the Neon database backing GitHub Project insights. Includes tables, columns, indexes, and a concise guide for common queries using project_name.", + inputSchema: z.object({}), + execute: async () => { + const schema = await getSchema(); + return schema; + }, + }), db_query: tool({ - description: "Execute a read-only SQL SELECT against the Neon database.", + description: "Execute a read-only SQL SELECT against the Neon database. Use project_name for scoping; default lookback is the last 7 days for 'what's new' queries. Returns rows with enforced LIMIT/OFFSET (max 2000).", inputSchema: z.object({ sql: z.string().describe("A single SELECT (or WITH ... SELECT) statement."), params: z.array(z.any()).optional().default([]), @@ -63,28 +64,60 @@ async function runAgentSession(args: { userText: string; channel: string; thread offset: z.number().int().min(0).optional().default(0), timeoutMs: z.number().int().min(1000).max(60000).optional().default(15000), }), - execute: async ({ sql, params, limit, offset, timeoutMs }) => runQuery({ sql, params, limit, offset, timeoutMs }), - }), - slack_send: tool({ - description: "Send a Slack message in the current thread. Use mrkdwn formatting.", - inputSchema: z.object({ text: z.string().min(1) }), - execute: async ({ text }) => { - const clean = stripMonocle(text); - await client.chat.postMessage({ channel, thread_ts, text: clean }); - postedAny = true; - return { ok: true }; + execute: async ({ sql, params, limit, offset, timeoutMs }) => { + const result = await runQuery({ sql, params, limit, offset, timeoutMs }); + return result; }, }), }, }); + + // Stream the response and update Slack message + for await (const delta of result.textStream) { + accumulatedText += delta; + + const clean = stripMonocle(accumulatedText); + + if (currentMessageTs) { + // Update existing message + await client.chat.update({ + channel, + ts: currentMessageTs, + text: clean, + }); + } else { + // Create new message and store its timestamp + const response = await client.chat.postMessage({ + channel, + thread_ts, + text: clean, + }); + currentMessageTs = response.ts; + } + } + + // Ensure we have the final text + const finalText = await result.text; + if (finalText !== accumulatedText) { + const clean = stripMonocle(finalText); + if (currentMessageTs) { + await client.chat.update({ + channel, + ts: currentMessageTs, + text: clean, + }); + } else { + await client.chat.postMessage({ + channel, + thread_ts, + text: clean, + }); + } + } + } catch (err: any) { const msg = typeof err?.message === "string" ? err.message.slice(0, 600) : "unexpected_error"; - await client.chat.postMessage({ channel, thread_ts, text: `Encountered an error while responding: ${msg}` }); - return; - } - - if (!postedAny) { - await client.chat.postMessage({ channel, thread_ts, text: "I wasn’t able to produce a response. Please rephrase your request (include the project name and timeframe)." }); + await client.chat.postMessage({ channel, thread_ts, text: `Encountered an error: ${msg}` }); } } From 7c90a1e8fd06260eb7ee94cb91733b89af793d44 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:14:52 +0000 Subject: [PATCH 21/28] feat(slack): add debug logging and tool execution tracking; improve error handling in streaming\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/slack.ts b/slack.ts index 94699b07..a0b85159 100644 --- a/slack.ts +++ b/slack.ts @@ -40,6 +40,7 @@ async function runAgentSession(args: { userText: string; channel: string; thread let currentMessageTs: string | null = null; let accumulatedText = ""; + let toolsExecuted = 0; try { const result = streamText({ @@ -51,6 +52,8 @@ async function runAgentSession(args: { userText: string; channel: string; thread description: "Return the schema and usage notes for the Neon database backing GitHub Project insights. Includes tables, columns, indexes, and a concise guide for common queries using project_name.", inputSchema: z.object({}), execute: async () => { + console.log("[DEBUG] Executing db_schema tool"); + toolsExecuted++; const schema = await getSchema(); return schema; }, @@ -65,7 +68,10 @@ async function runAgentSession(args: { userText: string; channel: string; thread timeoutMs: z.number().int().min(1000).max(60000).optional().default(15000), }), execute: async ({ sql, params, limit, offset, timeoutMs }) => { + console.log("[DEBUG] Executing db_query tool with SQL:", sql); + toolsExecuted++; const result = await runQuery({ sql, params, limit, offset, timeoutMs }); + console.log("[DEBUG] db_query returned", result.rows?.length || 0, "rows"); return result; }, }), @@ -80,11 +86,15 @@ async function runAgentSession(args: { userText: string; channel: string; thread if (currentMessageTs) { // Update existing message - await client.chat.update({ - channel, - ts: currentMessageTs, - text: clean, - }); + try { + await client.chat.update({ + channel, + ts: currentMessageTs, + text: clean, + }); + } catch (updateErr) { + console.warn("[DEBUG] Failed to update message:", updateErr); + } } else { // Create new message and store its timestamp const response = await client.chat.postMessage({ @@ -96,8 +106,14 @@ async function runAgentSession(args: { userText: string; channel: string; thread } } - // Ensure we have the final text + // Wait for final result and any remaining tool executions const finalText = await result.text; + const toolResults = await result.toolResults; + + console.log("[DEBUG] Final text length:", finalText.length); + console.log("[DEBUG] Tools executed:", toolsExecuted); + console.log("[DEBUG] Tool results:", toolResults.length); + if (finalText !== accumulatedText) { const clean = stripMonocle(finalText); if (currentMessageTs) { @@ -115,7 +131,17 @@ async function runAgentSession(args: { userText: string; channel: string; thread } } + // If no tools were executed but the query suggests they should be, add a follow-up + if (toolsExecuted === 0 && (userText.toLowerCase().includes('project') || userText.toLowerCase().includes('database'))) { + await client.chat.postMessage({ + channel, + thread_ts, + text: `[Debug] No database tools were executed. Tools available: db_schema, db_query. Please be more specific about what data you need.`, + }); + } + } catch (err: any) { + console.error("[DEBUG] Error in runAgentSession:", err); const msg = typeof err?.message === "string" ? err.message.slice(0, 600) : "unexpected_error"; await client.chat.postMessage({ channel, thread_ts, text: `Encountered an error: ${msg}` }); } From ab9ba6a1cebd60f064d83e6a83365a4105f38bb1 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:17:14 +0000 Subject: [PATCH 22/28] fix(slack): improve streaming logic to properly await tool completion and include results in final response\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 72 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/slack.ts b/slack.ts index a0b85159..dc4fa7a8 100644 --- a/slack.ts +++ b/slack.ts @@ -79,56 +79,66 @@ async function runAgentSession(args: { userText: string; channel: string; thread }); // Stream the response and update Slack message + let lastUpdateTime = Date.now(); + const updateThrottle = 1000; // Update at most once per second + for await (const delta of result.textStream) { accumulatedText += delta; const clean = stripMonocle(accumulatedText); + const now = Date.now(); - if (currentMessageTs) { - // Update existing message - try { - await client.chat.update({ + // Throttle updates to avoid rate limits + if (now - lastUpdateTime >= updateThrottle || delta.includes('\n')) { + if (currentMessageTs) { + try { + await client.chat.update({ + channel, + ts: currentMessageTs, + text: clean, + }); + lastUpdateTime = now; + } catch (updateErr) { + console.warn("[DEBUG] Failed to update message:", updateErr); + } + } else { + const response = await client.chat.postMessage({ channel, - ts: currentMessageTs, + thread_ts, text: clean, }); - } catch (updateErr) { - console.warn("[DEBUG] Failed to update message:", updateErr); + currentMessageTs = response.ts; + lastUpdateTime = now; } - } else { - // Create new message and store its timestamp - const response = await client.chat.postMessage({ - channel, - thread_ts, - text: clean, - }); - currentMessageTs = response.ts; } } - // Wait for final result and any remaining tool executions + // Critical: Wait for ALL tool results to complete + console.log("[DEBUG] Waiting for final text and tool results..."); const finalText = await result.text; const toolResults = await result.toolResults; console.log("[DEBUG] Final text length:", finalText.length); console.log("[DEBUG] Tools executed:", toolsExecuted); console.log("[DEBUG] Tool results:", toolResults.length); + console.log("[DEBUG] Final text preview:", finalText.slice(0, 200) + '...'); - if (finalText !== accumulatedText) { - const clean = stripMonocle(finalText); - if (currentMessageTs) { - await client.chat.update({ - channel, - ts: currentMessageTs, - text: clean, - }); - } else { - await client.chat.postMessage({ - channel, - thread_ts, - text: clean, - }); - } + // Always do a final update with complete results + const finalClean = stripMonocle(finalText); + if (currentMessageTs) { + await client.chat.update({ + channel, + ts: currentMessageTs, + text: finalClean, + }); + console.log("[DEBUG] Final update completed"); + } else { + await client.chat.postMessage({ + channel, + thread_ts, + text: finalClean, + }); + console.log("[DEBUG] Final post completed"); } // If no tools were executed but the query suggests they should be, add a follow-up From a6a6fe79d3cc4c8f459e9bcb4d8ea94ecc777906 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:19:23 +0000 Subject: [PATCH 23/28] fix(slack): simplify tool result handling with any casting and add comprehensive debugging\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/slack.ts b/slack.ts index dc4fa7a8..7e977a91 100644 --- a/slack.ts +++ b/slack.ts @@ -123,22 +123,53 @@ async function runAgentSession(args: { userText: string; channel: string; thread console.log("[DEBUG] Tool results:", toolResults.length); console.log("[DEBUG] Final text preview:", finalText.slice(0, 200) + '...'); + // If we have tool results but the text is incomplete, construct a complete response + let completeText = finalText; + if (toolResults.length > 0 && finalText.length < 200) { + console.log("[DEBUG] Text seems incomplete, constructing response from tool results"); + console.log("[DEBUG] Tool results structure:", JSON.stringify(toolResults, null, 2)); + + // Find the db_query result - cast to any to handle the complex typing + const dbQueryResult = (toolResults as any[]).find((r: any) => r.toolName === 'db_query'); + if (dbQueryResult) { + console.log("[DEBUG] Found db_query result:", JSON.stringify(dbQueryResult, null, 2)); + + // Try different property names that might contain the result + const resultData = dbQueryResult.result || dbQueryResult.value || dbQueryResult.output || dbQueryResult; + const rows = resultData?.rows; + + if (rows && Array.isArray(rows) && rows.length > 0) { + // Check if this looks like a project name query + const firstRow = rows[0]; + if (firstRow && typeof firstRow === 'object' && 'project_name' in firstRow) { + const projectNames = rows.map((row: any) => row.project_name).filter(Boolean); + completeText = `I found ${projectNames.length} projects in the database:\n\n${projectNames.map((name: string) => `• ${name}`).join('\n')}`; + } else { + // Generic result display + completeText = `Query completed successfully. Found ${rows.length} result(s).\n\nResults:\n${JSON.stringify(rows.slice(0, 5), null, 2)}`; + } + } else { + completeText = "Query executed but no results found or result format unexpected."; + } + } + } + // Always do a final update with complete results - const finalClean = stripMonocle(finalText); + const finalClean = stripMonocle(completeText); if (currentMessageTs) { await client.chat.update({ channel, ts: currentMessageTs, text: finalClean, }); - console.log("[DEBUG] Final update completed"); + console.log("[DEBUG] Final update completed with:", finalClean.slice(0, 100) + '...'); } else { await client.chat.postMessage({ channel, thread_ts, text: finalClean, }); - console.log("[DEBUG] Final post completed"); + console.log("[DEBUG] Final post completed with:", finalClean.slice(0, 100) + '...'); } // If no tools were executed but the query suggests they should be, add a follow-up From e5765f039866126e6dc10601a24f38734e9a1e6e Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:23:23 +0000 Subject: [PATCH 24/28] refactor(slack): remove message editing, post only complete final messages\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 62 ++++++++------------------------------------------------ 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/slack.ts b/slack.ts index 7e977a91..68de858c 100644 --- a/slack.ts +++ b/slack.ts @@ -38,8 +38,6 @@ async function runAgentSession(args: { userText: string; channel: string; thread return; } - let currentMessageTs: string | null = null; - let accumulatedText = ""; let toolsExecuted = 0; try { @@ -78,42 +76,7 @@ async function runAgentSession(args: { userText: string; channel: string; thread }, }); - // Stream the response and update Slack message - let lastUpdateTime = Date.now(); - const updateThrottle = 1000; // Update at most once per second - - for await (const delta of result.textStream) { - accumulatedText += delta; - - const clean = stripMonocle(accumulatedText); - const now = Date.now(); - - // Throttle updates to avoid rate limits - if (now - lastUpdateTime >= updateThrottle || delta.includes('\n')) { - if (currentMessageTs) { - try { - await client.chat.update({ - channel, - ts: currentMessageTs, - text: clean, - }); - lastUpdateTime = now; - } catch (updateErr) { - console.warn("[DEBUG] Failed to update message:", updateErr); - } - } else { - const response = await client.chat.postMessage({ - channel, - thread_ts, - text: clean, - }); - currentMessageTs = response.ts; - lastUpdateTime = now; - } - } - } - - // Critical: Wait for ALL tool results to complete + // Wait for complete response - no streaming updates console.log("[DEBUG] Waiting for final text and tool results..."); const finalText = await result.text; const toolResults = await result.toolResults; @@ -154,23 +117,14 @@ async function runAgentSession(args: { userText: string; channel: string; thread } } - // Always do a final update with complete results + // Post single complete message const finalClean = stripMonocle(completeText); - if (currentMessageTs) { - await client.chat.update({ - channel, - ts: currentMessageTs, - text: finalClean, - }); - console.log("[DEBUG] Final update completed with:", finalClean.slice(0, 100) + '...'); - } else { - await client.chat.postMessage({ - channel, - thread_ts, - text: finalClean, - }); - console.log("[DEBUG] Final post completed with:", finalClean.slice(0, 100) + '...'); - } + await client.chat.postMessage({ + channel, + thread_ts, + text: finalClean, + }); + console.log("[DEBUG] Posted complete message:", finalClean.slice(0, 100) + '...'); // If no tools were executed but the query suggests they should be, add a follow-up if (toolsExecuted === 0 && (userText.toLowerCase().includes('project') || userText.toLowerCase().includes('database'))) { From 1f27a6533062369bc2ba189a51172eec088e13e9 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:26:37 +0000 Subject: [PATCH 25/28] fix(slack): switch to generateText for complete responses; add explicit completion instructions\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 52 ++++++++-------------------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/slack.ts b/slack.ts index 68de858c..546a2b42 100644 --- a/slack.ts +++ b/slack.ts @@ -1,6 +1,6 @@ import { App, LogLevel } from "@slack/bolt"; import { z } from "zod"; -import { streamText, tool } from "ai"; +import { generateText, tool } from "ai"; import { buildSystemPrompt } from "./prompt.js"; import { getSchema, runQuery } from "./db.js"; @@ -41,9 +41,9 @@ async function runAgentSession(args: { userText: string; channel: string; thread let toolsExecuted = 0; try { - const result = streamText({ + const result = await generateText({ model: "anthropic/claude-sonnet-4", - system: buildSystemPrompt(), + system: buildSystemPrompt() + "\n\nIMPORTANT: You must complete your analysis and provide a final answer. If you need to query the database, do so and then provide the results. Do not stop after just mentioning what you'll do - actually do it and show the results.", messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ @@ -76,49 +76,13 @@ async function runAgentSession(args: { userText: string; channel: string; thread }, }); - // Wait for complete response - no streaming updates - console.log("[DEBUG] Waiting for final text and tool results..."); - const finalText = await result.text; - const toolResults = await result.toolResults; - - console.log("[DEBUG] Final text length:", finalText.length); + console.log("[DEBUG] Final text length:", result.text.length); console.log("[DEBUG] Tools executed:", toolsExecuted); - console.log("[DEBUG] Tool results:", toolResults.length); - console.log("[DEBUG] Final text preview:", finalText.slice(0, 200) + '...'); - - // If we have tool results but the text is incomplete, construct a complete response - let completeText = finalText; - if (toolResults.length > 0 && finalText.length < 200) { - console.log("[DEBUG] Text seems incomplete, constructing response from tool results"); - console.log("[DEBUG] Tool results structure:", JSON.stringify(toolResults, null, 2)); - - // Find the db_query result - cast to any to handle the complex typing - const dbQueryResult = (toolResults as any[]).find((r: any) => r.toolName === 'db_query'); - if (dbQueryResult) { - console.log("[DEBUG] Found db_query result:", JSON.stringify(dbQueryResult, null, 2)); - - // Try different property names that might contain the result - const resultData = dbQueryResult.result || dbQueryResult.value || dbQueryResult.output || dbQueryResult; - const rows = resultData?.rows; - - if (rows && Array.isArray(rows) && rows.length > 0) { - // Check if this looks like a project name query - const firstRow = rows[0]; - if (firstRow && typeof firstRow === 'object' && 'project_name' in firstRow) { - const projectNames = rows.map((row: any) => row.project_name).filter(Boolean); - completeText = `I found ${projectNames.length} projects in the database:\n\n${projectNames.map((name: string) => `• ${name}`).join('\n')}`; - } else { - // Generic result display - completeText = `Query completed successfully. Found ${rows.length} result(s).\n\nResults:\n${JSON.stringify(rows.slice(0, 5), null, 2)}`; - } - } else { - completeText = "Query executed but no results found or result format unexpected."; - } - } - } + console.log("[DEBUG] Tool results:", result.toolResults.length); + console.log("[DEBUG] Final text preview:", result.text.slice(0, 200) + '...'); - // Post single complete message - const finalClean = stripMonocle(completeText); + // Post the complete response + const finalClean = stripMonocle(result.text); await client.chat.postMessage({ channel, thread_ts, From effdc0fc37f9d020bdb7cf0aed95ef4e2562bf86 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:28:45 +0000 Subject: [PATCH 26/28] fix(slack): remove invalid maxToolRoundtrips parameter\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slack.ts b/slack.ts index 546a2b42..2850d009 100644 --- a/slack.ts +++ b/slack.ts @@ -42,8 +42,8 @@ async function runAgentSession(args: { userText: string; channel: string; thread try { const result = await generateText({ - model: "anthropic/claude-sonnet-4", - system: buildSystemPrompt() + "\n\nIMPORTANT: You must complete your analysis and provide a final answer. If you need to query the database, do so and then provide the results. Do not stop after just mentioning what you'll do - actually do it and show the results.", + model: "anthropic/claude-3-5-sonnet-20241022", + system: "You are a GitHub Projects database analyst. You have access to two tools: db_schema and db_query.\n\nWhen a user asks about projects or changes:\n1. If you need schema info, call db_schema\n2. Then IMMEDIATELY call db_query with the appropriate SQL\n3. Format the results clearly\n\nDo NOT stop after calling db_schema - always follow through with db_query to get actual data.\n\nFor 'what changed' questions, query the field_changes table with:\nSELECT field_name, old_value, new_value, changed_at, actor_login, content_title, repository_name FROM field_changes WHERE project_name = ? AND changed_at >= now() - interval '7 days' ORDER BY changed_at DESC\n\n" + buildSystemPrompt(), messages: [{ role: "user", content: userText }], tools: { db_schema: tool({ From cf2dd8721043b326b60addf4ab58831247056719 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:30:34 +0000 Subject: [PATCH 27/28] fix(slack): correct TypeScript errors in tool result property access\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/slack.ts b/slack.ts index 2850d009..9ac8b33c 100644 --- a/slack.ts +++ b/slack.ts @@ -81,8 +81,47 @@ async function runAgentSession(args: { userText: string; channel: string; thread console.log("[DEBUG] Tool results:", result.toolResults.length); console.log("[DEBUG] Final text preview:", result.text.slice(0, 200) + '...'); + // If we have tool results but incomplete text, construct response from results + let finalResponse = result.text; + if (result.toolResults.length > 0 && result.text.length < 300) { + console.log("[DEBUG] Text seems incomplete, constructing from tool results"); + + const dbQueryResult = result.toolResults.find((r: any) => r.toolName === 'db_query'); + if (dbQueryResult && (dbQueryResult as any).result && (dbQueryResult as any).result.rows) { + const rows = (dbQueryResult as any).result.rows; + console.log("[DEBUG] Found", rows.length, "rows in db_query result"); + + if (rows.length > 0) { + const projectName = rows[0].project_name || 'v2'; + finalResponse = `Found ${rows.length} recent changes in the "${projectName}" project:\n\n`; + + // Format first 10 changes + const changes = rows.slice(0, 10).map((row: any) => { + const date = new Date(row.changed_at).toLocaleDateString(); + const time = new Date(row.changed_at).toLocaleTimeString(); + const field = row.field_name; + const oldVal = row.old_value ? JSON.stringify(row.old_value) : 'null'; + const newVal = row.new_value ? JSON.stringify(row.new_value) : 'null'; + const actor = row.actor_login || 'unknown'; + const title = row.content_title || 'untitled'; + const repo = row.repository_name || 'unknown'; + + return `• **${field}** changed from ${oldVal} to ${newVal}\n ${title} in ${repo}\n by ${actor} on ${date} at ${time}`; + }).join('\n\n'); + + finalResponse += changes; + + if (rows.length > 10) { + finalResponse += `\n\n... and ${rows.length - 10} more changes`; + } + } else { + finalResponse = `No recent changes found in the "v2" project in the last 7 days.`; + } + } + } + // Post the complete response - const finalClean = stripMonocle(result.text); + const finalClean = stripMonocle(finalResponse); await client.chat.postMessage({ channel, thread_ts, From 61ad867e58b66e519320067f750d8f97d40472f4 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:32:30 +0000 Subject: [PATCH 28/28] feat(slack): add comprehensive debugging for tool result structure analysis\n\nCo-authored-by: mattvollmer <95866673+mattvollmer@users.noreply.github.com> --- slack.ts | 69 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/slack.ts b/slack.ts index 9ac8b33c..5e8a09af 100644 --- a/slack.ts +++ b/slack.ts @@ -85,38 +85,59 @@ async function runAgentSession(args: { userText: string; channel: string; thread let finalResponse = result.text; if (result.toolResults.length > 0 && result.text.length < 300) { console.log("[DEBUG] Text seems incomplete, constructing from tool results"); + console.log("[DEBUG] Tool results structure:", JSON.stringify(result.toolResults, null, 2)); const dbQueryResult = result.toolResults.find((r: any) => r.toolName === 'db_query'); - if (dbQueryResult && (dbQueryResult as any).result && (dbQueryResult as any).result.rows) { - const rows = (dbQueryResult as any).result.rows; - console.log("[DEBUG] Found", rows.length, "rows in db_query result"); + console.log("[DEBUG] Found dbQueryResult:", !!dbQueryResult); + + if (dbQueryResult) { + console.log("[DEBUG] dbQueryResult keys:", Object.keys(dbQueryResult)); + + // Try different property paths + const resultData = (dbQueryResult as any).result || (dbQueryResult as any).output || (dbQueryResult as any).value; + console.log("[DEBUG] Found resultData:", !!resultData); - if (rows.length > 0) { - const projectName = rows[0].project_name || 'v2'; - finalResponse = `Found ${rows.length} recent changes in the "${projectName}" project:\n\n`; + if (resultData) { + console.log("[DEBUG] resultData keys:", Object.keys(resultData)); + const rows = resultData.rows; + console.log("[DEBUG] Found", rows?.length || 0, "rows in db_query result"); - // Format first 10 changes - const changes = rows.slice(0, 10).map((row: any) => { - const date = new Date(row.changed_at).toLocaleDateString(); - const time = new Date(row.changed_at).toLocaleTimeString(); - const field = row.field_name; - const oldVal = row.old_value ? JSON.stringify(row.old_value) : 'null'; - const newVal = row.new_value ? JSON.stringify(row.new_value) : 'null'; - const actor = row.actor_login || 'unknown'; - const title = row.content_title || 'untitled'; - const repo = row.repository_name || 'unknown'; + if (rows && rows.length > 0) { + console.log("[DEBUG] First row sample:", JSON.stringify(rows[0], null, 2)); - return `• **${field}** changed from ${oldVal} to ${newVal}\n ${title} in ${repo}\n by ${actor} on ${date} at ${time}`; - }).join('\n\n'); - - finalResponse += changes; - - if (rows.length > 10) { - finalResponse += `\n\n... and ${rows.length - 10} more changes`; + const projectName = rows[0].project_name || 'v2'; + finalResponse = `Found ${rows.length} recent changes in projects with "v2" in the name:\n\n`; + + // Format first 10 changes + const changes = rows.slice(0, 10).map((row: any) => { + const date = new Date(row.changed_at).toLocaleDateString(); + const time = new Date(row.changed_at).toLocaleTimeString(); + const field = row.field_name; + const oldVal = row.old_value ? JSON.stringify(row.old_value) : 'null'; + const newVal = row.new_value ? JSON.stringify(row.new_value) : 'null'; + const actor = row.actor_login || 'unknown'; + const title = row.content_title || 'untitled'; + const repo = row.repository_name || 'unknown'; + + return `• **${field}** changed from ${oldVal} to ${newVal}\n ${title} in ${repo}\n by ${actor} on ${date} at ${time}`; + }).join('\n\n'); + + finalResponse += changes; + + if (rows.length > 10) { + finalResponse += `\n\n... and ${rows.length - 10} more changes`; + } + + console.log("[DEBUG] Constructed response length:", finalResponse.length); + } else { + finalResponse = `No recent changes found in projects with "v2" in the name in the last 7 days.`; + console.log("[DEBUG] No rows found, using no-results message"); } } else { - finalResponse = `No recent changes found in the "v2" project in the last 7 days.`; + console.log("[DEBUG] No resultData found in dbQueryResult"); } + } else { + console.log("[DEBUG] No db_query result found in tool results"); } }