From 03fe33234584f3571029acade6357a3728ced3c2 Mon Sep 17 00:00:00 2001 From: MestreY0d4-Uninter Date: Mon, 9 Mar 2026 10:14:10 -0300 Subject: [PATCH 1/6] feat: add messageThreadId passthrough for Telegram forum topics Adds optional messageThreadId parameter through the notification chain: Channel type -> resolveNotifyChannel -> notify -> sendMessage -> Telegram API. This enables per-topic routing in Telegram forum groups, where each project can have notifications sent to a specific forum topic instead of the main chat. Co-Authored-By: Claude Opus 4.6 --- lib/dispatch/index.ts | 1 + lib/dispatch/notify.ts | 11 +- lib/projects/types.ts | 1 + lib/services/heartbeat/passes.ts | 4 + lib/services/pipeline.ts | 4 +- lib/workflow/labels.ts | 4 +- package-lock.json | 3191 ++++++++++++++++++++++++++---- 7 files changed, 2846 insertions(+), 370 deletions(-) diff --git a/lib/dispatch/index.ts b/lib/dispatch/index.ts index 4efd8ca7..a1fcb515 100644 --- a/lib/dispatch/index.ts +++ b/lib/dispatch/index.ts @@ -271,6 +271,7 @@ export async function dispatchTask( channel: notifyTarget?.channel ?? "telegram", runtime, accountId: notifyTarget?.accountId, + messageThreadId: notifyTarget?.messageThreadId, runCommand: rc, }, ).catch((err) => { diff --git a/lib/dispatch/notify.ts b/lib/dispatch/notify.ts index e9abca46..a9c1fbfb 100644 --- a/lib/dispatch/notify.ts +++ b/lib/dispatch/notify.ts @@ -262,13 +262,16 @@ async function sendMessage( runtime?: PluginRuntime, accountId?: string, runCommand?: RunCommand, + messageThreadId?: number, ): Promise { try { // Use runtime API when available (avoids CLI subprocess timeouts) if (runtime) { if (channel === "telegram") { - // Cast to any to bypass TypeScript type limitation; disableWebPagePreview is valid in Telegram API - await runtime.channel.telegram.sendMessageTelegram(target, message, { silent: true, disableWebPagePreview: true, accountId } as any); + // Cast to any to bypass TypeScript type limitation; disableWebPagePreview and messageThreadId are valid in Telegram API + const telegramOpts: Record = { silent: true, disableWebPagePreview: true, accountId }; + if (messageThreadId != null) telegramOpts.messageThreadId = messageThreadId; + await runtime.channel.telegram.sendMessageTelegram(target, message, telegramOpts as any); return true; } if (channel === "whatsapp") { @@ -341,6 +344,8 @@ export async function notify( accountId?: string; /** Injected runCommand for dependency injection. */ runCommand?: RunCommand; + /** Optional Telegram forum topic ID for per-topic routing */ + messageThreadId?: number; }, ): Promise { if (opts.config?.[event.type] === false) return true; @@ -364,7 +369,7 @@ export async function notify( message, }); - return sendMessage(target, message, channel, opts.workspaceDir, opts.runtime, opts.accountId, opts.runCommand); + return sendMessage(target, message, channel, opts.workspaceDir, opts.runtime, opts.accountId, opts.runCommand, opts.messageThreadId); } /** diff --git a/lib/projects/types.ts b/lib/projects/types.ts index 26526235..a51c9313 100644 --- a/lib/projects/types.ts +++ b/lib/projects/types.ts @@ -33,6 +33,7 @@ export type Channel = { name: string; // e.g. "primary", "dev-chat" events: string[]; // e.g. ["*"] for all, ["workerComplete"] for filtered accountId?: string; // Optional account ID for multi-account setups + messageThreadId?: number; // Optional Telegram forum topic ID for per-topic routing }; /** diff --git a/lib/services/heartbeat/passes.ts b/lib/services/heartbeat/passes.ts index ad4de16c..4c19e69a 100644 --- a/lib/services/heartbeat/passes.ts +++ b/lib/services/heartbeat/passes.ts @@ -133,6 +133,7 @@ export async function performReviewPass( channel: target?.channel ?? "telegram", runtime, accountId: target?.accountId, + messageThreadId: target?.messageThreadId, runCommand, }, ).catch(() => {}); @@ -162,6 +163,7 @@ export async function performReviewPass( channel: target?.channel ?? "telegram", runtime, accountId: target?.accountId, + messageThreadId: target?.messageThreadId, runCommand, }, ).catch(() => {}); @@ -185,6 +187,7 @@ export async function performReviewPass( channel: target?.channel ?? "telegram", runtime, accountId: target?.accountId, + messageThreadId: target?.messageThreadId, runCommand, }, ).catch(() => {}); @@ -242,6 +245,7 @@ export async function performReviewSkipPass( channel: target?.channel ?? "telegram", runtime, accountId: target?.accountId, + messageThreadId: target?.messageThreadId, runCommand, }, ).catch(() => {}); diff --git a/lib/services/pipeline.ts b/lib/services/pipeline.ts index 681ebb9d..c220c6a0 100644 --- a/lib/services/pipeline.ts +++ b/lib/services/pipeline.ts @@ -176,6 +176,7 @@ export async function executeCompletion(opts: { channel: notifyTarget?.channel ?? "telegram", runtime, accountId: notifyTarget?.accountId, + messageThreadId: notifyTarget?.messageThreadId, }, ).catch((err) => { auditLog(workspaceDir, "pipeline_warning", { step: "notify", issue: issueId, role, error: (err as Error).message ?? String(err) }).catch(() => {}); @@ -195,7 +196,7 @@ export async function executeCompletion(opts: { sourceBranch, mergedBy: "pipeline", }, - { workspaceDir, config: notifyConfig, channelId: notifyTarget?.channelId, channel: notifyTarget?.channel ?? "telegram", runtime, accountId: notifyTarget?.accountId }, + { workspaceDir, config: notifyConfig, channelId: notifyTarget?.channelId, channel: notifyTarget?.channel ?? "telegram", runtime, accountId: notifyTarget?.accountId, messageThreadId: notifyTarget?.messageThreadId }, ).catch((err) => { auditLog(workspaceDir, "pipeline_warning", { step: "mergeNotify", issue: issueId, role, error: (err as Error).message ?? String(err) }).catch(() => {}); }); @@ -245,6 +246,7 @@ export async function executeCompletion(opts: { channel: notifyTarget?.channel ?? "telegram", runtime, accountId: notifyTarget?.accountId, + messageThreadId: notifyTarget?.messageThreadId, }, ).catch((err) => { auditLog(workspaceDir, "pipeline_warning", { step: "reviewNotify", issue: issueId, role, error: (err as Error).message ?? String(err) }).catch(() => {}); diff --git a/lib/workflow/labels.ts b/lib/workflow/labels.ts index cb712693..773ed0b1 100644 --- a/lib/workflow/labels.ts +++ b/lib/workflow/labels.ts @@ -44,8 +44,8 @@ export function getNotifyLabel(channel: string, nameOrIndex: string): string { */ export function resolveNotifyChannel( issueLabels: string[], - channels: Array<{ channelId: string; channel: string; name?: string; accountId?: string }>, -): { channelId: string; channel: string; accountId?: string } | undefined { + channels: Array<{ channelId: string; channel: string; name?: string; accountId?: string; messageThreadId?: number }>, +): { channelId: string; channel: string; accountId?: string; messageThreadId?: number } | undefined { const notifyLabel = issueLabels.find((l) => l.startsWith(NOTIFY_LABEL_PREFIX)); if (notifyLabel) { const value = notifyLabel.slice(NOTIFY_LABEL_PREFIX.length); diff --git a/package-lock.json b/package-lock.json index 47d03855..5063d883 100644 --- a/package-lock.json +++ b/package-lock.json @@ -949,6 +949,160 @@ "sisteransi": "^1.0.5" } }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20260120.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260120.0.tgz", + "integrity": "sha512-B8pueG+a5S+mdK3z8oKu1ShcxloZ7qWb68IEyLLaepvdryIbNC7JVPcY0bWsjS56UQVKc5fnyRge3yZIwc9bxw==", + "license": "MIT OR Apache-2.0", + "optional": true, + "peer": true + }, + "node_modules/@discordjs/node-pre-gyp": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@discordjs/node-pre-gyp/-/node-pre-gyp-0.4.5.tgz", + "integrity": "sha512-YJOVVZ545x24mHzANfYoy0BJX5PDyeZlpiJjDkUBM/V/Ao7TFX9lcUvCN4nr0tbr5ubeaXxtEBILUrHtTphVeQ==", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true, + "peer": true + }, + "node_modules/@discordjs/opus": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@discordjs/opus/-/opus-0.10.0.tgz", + "integrity": "sha512-HHEnSNrSPmFEyndRdQBJN2YE6egyXS9JUnJWyP6jficK0Y+qKMEZXyYTgmzpjrxXP1exM/hKaNP7BRBUEWkU5w==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@discordjs/node-pre-gyp": "^0.4.5", + "node-addon-api": "^8.1.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@discordjs/voice": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.19.0.tgz", @@ -996,6 +1150,40 @@ } } }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -1534,6 +1722,20 @@ "ciao-bcs": "lib/bonjour-conformance-testing.js" } }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@huggingface/jinja": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.5.tgz", @@ -1554,351 +1756,1674 @@ "node": ">=18" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "peer": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, "engines": { - "node": ">=12" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT", - "peer": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "peer": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], "peer": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], "peer": true, - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@keyv/bigmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", - "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", - "license": "MIT", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], "peer": true, - "dependencies": { - "hashery": "^1.4.0", - "hookified": "^1.15.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "keyv": "^5.6.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@keyv/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", - "license": "MIT", - "peer": true + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT", + "peer": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "peer": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "license": "MIT", + "peer": true + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT", + "peer": true + }, + "node_modules/@larksuiteoapi/node-sdk": { + "version": "1.59.0", + "resolved": "https://registry.npmjs.org/@larksuiteoapi/node-sdk/-/node-sdk-1.59.0.tgz", + "integrity": "sha512-sBpkruTvZDOxnVtoTbepWKRX0j1Y1ZElQYu0x7+v088sI9pcpbVp6ZzCGn62dhrKPatzNyCJyzYCPXPYQWccrA==", + "license": "MIT", + "peer": true, + "dependencies": { + "axios": "~1.13.3", + "lodash.identity": "^3.0.0", + "lodash.merge": "^4.6.2", + "lodash.pickby": "^4.6.0", + "protobufjs": "^7.2.6", + "qs": "^6.14.2", + "ws": "^8.19.0" + } + }, + "node_modules/@line/bot-sdk": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@line/bot-sdk/-/bot-sdk-10.6.0.tgz", + "integrity": "sha512-4hSpglL/G/cW2JCcohaYz/BS0uOSJNV9IEYdMm0EiPEvDLayoI2hGq2D86uYPQFD2gvgkyhmzdShpWLG3P5r3w==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/node": "^24.0.0" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "axios": "^1.7.4" + } + }, + "node_modules/@line/bot-sdk/node_modules/@types/node": { + "version": "24.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz", + "integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==", + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@line/bot-sdk/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT", + "peer": true + }, + "node_modules/@lydell/node-pty": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty/-/node-pty-1.2.0-beta.3.tgz", + "integrity": "sha512-ngGAItlRhmJXrhspxt8kX13n1dVFqzETOq0m/+gqSkO8NJBvNMwP7FZckMwps2UFySdr4yxCXNGu/bumg5at6A==", + "license": "MIT", + "peer": true, + "optionalDependencies": { + "@lydell/node-pty-darwin-arm64": "1.2.0-beta.3", + "@lydell/node-pty-darwin-x64": "1.2.0-beta.3", + "@lydell/node-pty-linux-arm64": "1.2.0-beta.3", + "@lydell/node-pty-linux-x64": "1.2.0-beta.3", + "@lydell/node-pty-win32-arm64": "1.2.0-beta.3", + "@lydell/node-pty-win32-x64": "1.2.0-beta.3" + } + }, + "node_modules/@lydell/node-pty-darwin-arm64": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty-darwin-arm64/-/node-pty-darwin-arm64-1.2.0-beta.3.tgz", + "integrity": "sha512-owcv+e1/OSu3bf9ZBdUQqJsQF888KyuSIiPYFNn0fLhgkhm9F3Pvha76Kj5mCPnodf7hh3suDe7upw7GPRXftQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@lydell/node-pty-darwin-x64": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty-darwin-x64/-/node-pty-darwin-x64-1.2.0-beta.3.tgz", + "integrity": "sha512-k38O+UviWrWdxtqZBBc/D8NJU11Rey8Y2YMwSWNxLv3eXZZdF5IVpbBkI/2RmLsV5nCcciqLPbukxeZnEfPlwA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@lydell/node-pty-linux-arm64": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty-linux-arm64/-/node-pty-linux-arm64-1.2.0-beta.3.tgz", + "integrity": "sha512-HUwRpGu3O+4sv9DAQFKnyW5LYhyYu2SDUa/bdFO/t4dIFCM4uDJEq47wfRM7+aYtJTi1b3lakN8SlWeuFQqJQQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@lydell/node-pty-linux-x64": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty-linux-x64/-/node-pty-linux-x64-1.2.0-beta.3.tgz", + "integrity": "sha512-+RRY0PoCUeQaCvPR7/UnkGbxulwbFtoTWJfe+o4T1RcNtngrgaI55I9nl8CD8uqhGrB3smKuyvPM5UtwGhASUw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@lydell/node-pty-win32-arm64": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty-win32-arm64/-/node-pty-win32-arm64-1.2.0-beta.3.tgz", + "integrity": "sha512-UEDd9ASp2M3iIYpIzfmfBlpyn4+K1G4CAjYcHWStptCkefoSVXWTiUBIa1KjBjZi3/xmsHIDpBEYTkGWuvLt2Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@lydell/node-pty-win32-x64": { + "version": "1.2.0-beta.3", + "resolved": "https://registry.npmjs.org/@lydell/node-pty-win32-x64/-/node-pty-win32-x64-1.2.0-beta.3.tgz", + "integrity": "sha512-TpdqSFYx7/Rj+68tuP6F/lkRYrHCYAIJgaS1bx3SctTkb5QAQCFwOKHd4xlsivmEOMT2LdhkJggPxwX9PAO5pQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@mariozechner/clipboard": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.2.tgz", + "integrity": "sha512-IHQpksNjo7EAtGuHFU+tbWDp5LarH3HU/8WiB9O70ZEoBPHOg0/6afwSLK0QyNMMmx4Bpi/zl6+DcBXe95nWYA==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@mariozechner/clipboard-darwin-arm64": "0.3.2", + "@mariozechner/clipboard-darwin-universal": "0.3.2", + "@mariozechner/clipboard-darwin-x64": "0.3.2", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.2", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-x64-musl": "0.3.2", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.2", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.2" + } + }, + "node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.2.tgz", + "integrity": "sha512-uBf6K7Je1ihsgvmWxA8UCGCeI+nbRVRXoarZdLjl6slz94Zs1tNKFZqx7aCI5O1i3e0B6ja82zZ06BWrl0MCVw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.2.tgz", + "integrity": "sha512-mxSheKTW2U9LsBdXy0SdmdCAE5HqNS9QUmpNHLnfJ+SsbFKALjEZc5oRrVMXxGQSirDvYf5bjmRyT0QYYonnlg==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.2.tgz", + "integrity": "sha512-U1BcVEoidvwIp95+HJswSW+xr28EQiHR7rZjH6pn8Sja5yO4Yoe3yCN0Zm8Lo72BbSOK/fTSq0je7CJpaPCspg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.2.tgz", + "integrity": "sha512-BsinwG3yWTIjdgNCxsFlip7LkfwPk+ruw/aFCXHUg/fb5XC/Ksp+YMQ7u0LUtiKzIv/7LMXgZInJQH6gxbAaqQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.2.tgz", + "integrity": "sha512-0/Gi5Xq2V6goXBop19ePoHvXsmJD9SzFlO3S+d6+T2b+BlPcpOu3Oa0wTjl+cZrLAAEzA86aPNBI+VVAFDFPKw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.2.tgz", + "integrity": "sha512-2AFFiXB24qf0zOZsxI1GJGb9wQGlOJyN6UwoXqmKS3dpQi/l6ix30IzDDA4c4ZcCcx4D+9HLYXhC1w7Sov8pXA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.2.tgz", + "integrity": "sha512-v6fVnsn7WMGg73Dab8QMwyFce7tzGfgEixKgzLP8f1GJqkJZi5zO4k4FOHzSgUufgLil63gnxvMpjWkgfeQN7A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.2.tgz", + "integrity": "sha512-xVUtnoMQ8v2JVyfJLKKXACA6avdnchdbBkTsZs8BgJQo29qwCp5NIHAUO8gbJ40iaEGToW5RlmVk2M9V0HsHEw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.2.tgz", + "integrity": "sha512-AEgg95TNi8TGgak2wSXZkXKCvAUTjWoU1Pqb0ON7JHrX78p616XUFNTJohtIon3e0w6k0pYPZeCuqRCza/Tqeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.2.tgz", + "integrity": "sha512-tGRuYpZwDOD7HBrCpyRuhGnHHSCknELvqwKKUG4JSfSB7JIU7LKRh6zx6fMUOQd8uISK35TjFg5UcNih+vJhFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/jiti": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@mariozechner/jiti/-/jiti-2.6.5.tgz", + "integrity": "sha512-faGUlTcXka5l7rv0lP3K3vGW/ejRuOS24RR2aSFWREUQqzjgdsuWNo/IiPqL3kWRGt6Ahl2+qcDAwtdeWeuGUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "std-env": "^3.10.0", + "yoctocolors": "^2.1.2" + }, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@mariozechner/pi-agent-core": { + "version": "0.55.3", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.55.3.tgz", + "integrity": "sha512-rqbfpQ9BrP6BDiW+Ps3A8Z/p9+Md/pAfc/ECq8JP6cwnZL/jQgU355KWZKtF8zM9az1p0Q9hIWi9cQygVo6Auw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@mariozechner/pi-ai": "^0.55.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@mariozechner/pi-ai": { + "version": "0.55.3", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.55.3.tgz", + "integrity": "sha512-f9jWoDzJR9Wy/H8JPMbjoM4WvVUeFZ65QdYA9UHIfoOopDfwWE8F8JHQOj5mmmILMacXuzsqA3J7MYqNWZRvvQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@anthropic-ai/sdk": "^0.73.0", + "@aws-sdk/client-bedrock-runtime": "^3.983.0", + "@google/genai": "^1.40.0", + "@mistralai/mistralai": "1.10.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "6.10.0", + "partial-json": "^0.1.7", + "proxy-agent": "^6.5.0", + "undici": "^7.19.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@mariozechner/pi-coding-agent": { + "version": "0.55.3", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-coding-agent/-/pi-coding-agent-0.55.3.tgz", + "integrity": "sha512-5SFbB7/BIp/Crjre7UNjUeNfpoU1KSW/i6LXa+ikJTBqI5LukWq2avE5l0v0M8Pg/dt1go2XCLrNFlQJiQDSPQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@mariozechner/jiti": "^2.6.2", + "@mariozechner/pi-agent-core": "^0.55.3", + "@mariozechner/pi-ai": "^0.55.3", + "@mariozechner/pi-tui": "^0.55.3", + "@silvia-odwyer/photon-node": "^0.3.4", + "chalk": "^5.5.0", + "cli-highlight": "^2.1.11", + "diff": "^8.0.2", + "extract-zip": "^2.0.1", + "file-type": "^21.1.1", + "glob": "^13.0.1", + "hosted-git-info": "^9.0.2", + "ignore": "^7.0.5", + "marked": "^15.0.12", + "minimatch": "^10.2.3", + "proper-lockfile": "^4.1.2", + "yaml": "^2.8.2" + }, + "bin": { + "pi": "dist/cli.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "^0.3.2" + } + }, + "node_modules/@mariozechner/pi-tui": { + "version": "0.55.3", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.55.3.tgz", + "integrity": "sha512-Gh4wkYgiSPCJJaB/4wEWSL7Ga8bxSq1Crp1RPRT4vKybE/DG0W/MQr5VJDvktarxtJrD16ixScwE4dzdox/PIA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "get-east-asian-width": "^1.3.0", + "koffi": "^2.9.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@mistralai/mistralai": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.10.0.tgz", + "integrity": "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg==", + "peer": true, + "dependencies": { + "zod": "^3.20.0", + "zod-to-json-schema": "^3.24.1" + } + }, + "node_modules/@mistralai/mistralai/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@mozilla/readability": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz", + "integrity": "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.95.tgz", + "integrity": "sha512-lkg23ge+rgyhgUwXmlbkPEhuhHq/hUi/gXKH+4I7vO+lJrbNfEYcQdJLIGjKyXLQzgFiiyDAwh5vAe/tITAE+w==", + "license": "MIT", + "peer": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.95", + "@napi-rs/canvas-darwin-arm64": "0.1.95", + "@napi-rs/canvas-darwin-x64": "0.1.95", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.95", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.95", + "@napi-rs/canvas-linux-arm64-musl": "0.1.95", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.95", + "@napi-rs/canvas-linux-x64-gnu": "0.1.95", + "@napi-rs/canvas-linux-x64-musl": "0.1.95", + "@napi-rs/canvas-win32-arm64-msvc": "0.1.95", + "@napi-rs/canvas-win32-x64-msvc": "0.1.95" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.95.tgz", + "integrity": "sha512-SqTh0wsYbetckMXEvHqmR7HKRJujVf1sYv1xdlhkifg6TlCSysz1opa49LlS3+xWuazcQcfRfmhA07HxxxGsAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.95.tgz", + "integrity": "sha512-F7jT0Syu+B9DGBUBcMk3qCRIxAWiDXmvEjamwbYfbZl7asI1pmXZUnCOoIu49Wt0RNooToYfRDxU9omD6t5Xuw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.95.tgz", + "integrity": "sha512-54eb2Ho15RDjYGXO/harjRznBrAvu+j5nQ85Z4Qd6Qg3slR8/Ja+Yvvy9G4yo7rdX6NR9GPkZeSTf2UcKXwaXw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.95.tgz", + "integrity": "sha512-hYaLCSLx5bmbnclzQc3ado3PgZ66blJWzjXp0wJmdwpr/kH+Mwhj6vuytJIomgksyJoCdIqIa4N6aiqBGJtJ5Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.95.tgz", + "integrity": "sha512-J7VipONahKsmScPZsipHVQBqpbZx4favaD8/enWzzlGcjiwycOoymL7f4tNeqdjK0su19bDOUt6mjp9gsPWYlw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.95.tgz", + "integrity": "sha512-PXy0UT1J/8MPG8UAkWp6Fd51ZtIZINFzIjGH909JjQrtCuJf3X6nanHYdz1A+Wq9o4aoPAw1YEUpFS1lelsVlg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } }, - "node_modules/@kwsites/file-exists": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.95.tgz", + "integrity": "sha512-2IzCkW2RHRdcgF9W5/plHvYFpc6uikyjMb5SxjqmNxfyDFz9/HB89yhi8YQo0SNqrGRI7yBVDec7Pt+uMyRWsg==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "peer": true, - "dependencies": { - "debug": "^4.1.1" + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.95.tgz", + "integrity": "sha512-OV/ol/OtcUr4qDhQg8G7SdViZX8XyQeKpPsVv/j3+7U178FGoU4M+yIocdVo1ih/A8GQ63+LjF4jDoEjaVU8Pw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "peer": true + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } }, - "node_modules/@larksuiteoapi/node-sdk": { - "version": "1.59.0", - "resolved": "https://registry.npmjs.org/@larksuiteoapi/node-sdk/-/node-sdk-1.59.0.tgz", - "integrity": "sha512-sBpkruTvZDOxnVtoTbepWKRX0j1Y1ZElQYu0x7+v088sI9pcpbVp6ZzCGn62dhrKPatzNyCJyzYCPXPYQWccrA==", + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.95.tgz", + "integrity": "sha512-Z5KzqBK/XzPz5+SFHKz7yKqClEQ8pOiEDdgk5SlphBLVNb8JFIJkxhtJKSvnJyHh2rjVgiFmvtJzMF0gNwwKyQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "peer": true, - "dependencies": { - "axios": "~1.13.3", - "lodash.identity": "^3.0.0", - "lodash.merge": "^4.6.2", - "lodash.pickby": "^4.6.0", - "protobufjs": "^7.2.6", - "qs": "^6.14.2", - "ws": "^8.19.0" + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@line/bot-sdk": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/@line/bot-sdk/-/bot-sdk-10.6.0.tgz", - "integrity": "sha512-4hSpglL/G/cW2JCcohaYz/BS0uOSJNV9IEYdMm0EiPEvDLayoI2hGq2D86uYPQFD2gvgkyhmzdShpWLG3P5r3w==", - "license": "Apache-2.0", + "node_modules/@napi-rs/canvas-win32-arm64-msvc": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.95.tgz", + "integrity": "sha512-aj0YbRpe8qVJ4OzMsK7NfNQePgcf9zkGFzNZ9mSuaxXzhpLHmlF2GivNdCdNOg8WzA/NxV6IU4c5XkXadUMLeA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "@types/node": "^24.0.0" + "engines": { + "node": ">= 10" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.95", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.95.tgz", + "integrity": "sha512-GA8leTTCfdjuHi8reICTIxU0081PhXvl3lzIniLUjeLACx9GubUiyzkwFb+oyeKLS5IAGZFLKnzAf4wm2epRlA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=20" + "node": ">= 10" }, - "optionalDependencies": { - "axios": "^1.7.4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@line/bot-sdk/node_modules/@types/node": { - "version": "24.11.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz", - "integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", "license": "MIT", + "optional": true, "peer": true, "dependencies": { - "undici-types": "~7.16.0" + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@line/bot-sdk/node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "node_modules/@node-llama-cpp/linux-arm64": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/linux-arm64/-/linux-arm64-3.16.2.tgz", + "integrity": "sha512-CxzgPsS84wL3W5sZRgxP3c9iJKEW+USrak1SmX6EAJxW/v9QGzehvT6W/aR1FyfidiIyQtOp3ga0Gg/9xfJPGw==", + "cpu": [ + "arm64", + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "peer": true + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=20.0.0" + } }, - "node_modules/@lydell/node-pty": { - "version": "1.2.0-beta.3", - "resolved": "https://registry.npmjs.org/@lydell/node-pty/-/node-pty-1.2.0-beta.3.tgz", - "integrity": "sha512-ngGAItlRhmJXrhspxt8kX13n1dVFqzETOq0m/+gqSkO8NJBvNMwP7FZckMwps2UFySdr4yxCXNGu/bumg5at6A==", + "node_modules/@node-llama-cpp/linux-armv7l": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/linux-armv7l/-/linux-armv7l-3.16.2.tgz", + "integrity": "sha512-9G6W/MkQ/DLwGmpcj143NQ50QJg5gQZfzVf5RYx77VczBqhgwkgYHILekYrOs4xanOeqeJ8jnOnQQSp1YaJZUg==", + "cpu": [ + "arm", + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "peer": true, - "optionalDependencies": { - "@lydell/node-pty-darwin-arm64": "1.2.0-beta.3", - "@lydell/node-pty-darwin-x64": "1.2.0-beta.3", - "@lydell/node-pty-linux-arm64": "1.2.0-beta.3", - "@lydell/node-pty-linux-x64": "1.2.0-beta.3", - "@lydell/node-pty-win32-arm64": "1.2.0-beta.3", - "@lydell/node-pty-win32-x64": "1.2.0-beta.3" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@mariozechner/jiti": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@mariozechner/jiti/-/jiti-2.6.5.tgz", - "integrity": "sha512-faGUlTcXka5l7rv0lP3K3vGW/ejRuOS24RR2aSFWREUQqzjgdsuWNo/IiPqL3kWRGt6Ahl2+qcDAwtdeWeuGUw==", + "node_modules/@node-llama-cpp/linux-x64": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/linux-x64/-/linux-x64-3.16.2.tgz", + "integrity": "sha512-OXYf8rVfoDyvN+YrfKk8F9An9a5GOxVIM8OcR1U911tc0oRNf8yfJrQ8KrM75R26gwq0Y6YZwVTP0vRCInwWOw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "peer": true, - "dependencies": { - "std-env": "^3.10.0", - "yoctocolors": "^2.1.2" - }, - "bin": { - "jiti": "lib/jiti-cli.mjs" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@mariozechner/pi-agent-core": { - "version": "0.55.3", - "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.55.3.tgz", - "integrity": "sha512-rqbfpQ9BrP6BDiW+Ps3A8Z/p9+Md/pAfc/ECq8JP6cwnZL/jQgU355KWZKtF8zM9az1p0Q9hIWi9cQygVo6Auw==", + "node_modules/@node-llama-cpp/linux-x64-cuda": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/linux-x64-cuda/-/linux-x64-cuda-3.16.2.tgz", + "integrity": "sha512-LTBQFqjin7tyrLNJz0XWTB5QAHDsZV71/qiiRRjXdBKSZHVVaPLfdgxypGu7ggPeBNsv+MckRXdlH5C7yMtE4A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "peer": true, - "dependencies": { - "@mariozechner/pi-ai": "^0.55.3" - }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@mariozechner/pi-ai": { - "version": "0.55.3", - "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.55.3.tgz", - "integrity": "sha512-f9jWoDzJR9Wy/H8JPMbjoM4WvVUeFZ65QdYA9UHIfoOopDfwWE8F8JHQOj5mmmILMacXuzsqA3J7MYqNWZRvvQ==", + "node_modules/@node-llama-cpp/linux-x64-cuda-ext": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/linux-x64-cuda-ext/-/linux-x64-cuda-ext-3.16.2.tgz", + "integrity": "sha512-47d9myCJauZyzAlN7IK1eIt/4CcBMslF+yHy4q+yJotD/RV/S6qRpK2kGn+ybtdVjkPGNCoPkHKcyla9iIVjbw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@node-llama-cpp/linux-x64-vulkan": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/linux-x64-vulkan/-/linux-x64-vulkan-3.16.2.tgz", + "integrity": "sha512-HDLAw4ZhwJuhKuF6n4x520yZXAQZahUOXtCGvPubjfpmIOElKrfDvCVlRsthAP0JwcwINzIQlVys3boMIXfBgw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@node-llama-cpp/mac-arm64-metal": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/mac-arm64-metal/-/mac-arm64-metal-3.16.2.tgz", + "integrity": "sha512-nEZ74qB0lUohF88yR741YUrUqz/qD+FJFzUTHj0FwxAynSZCjvwtzEDtavRlh3qd3yLD/0ChNn00/RQ54ISImw==", + "cpu": [ + "arm64", + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "peer": true, - "dependencies": { - "@anthropic-ai/sdk": "^0.73.0", - "@aws-sdk/client-bedrock-runtime": "^3.983.0", - "@google/genai": "^1.40.0", - "@mistralai/mistralai": "1.10.0", - "@sinclair/typebox": "^0.34.41", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "chalk": "^5.6.2", - "openai": "6.10.0", - "partial-json": "^0.1.7", - "proxy-agent": "^6.5.0", - "undici": "^7.19.1", - "zod-to-json-schema": "^3.24.6" - }, - "bin": { - "pi-ai": "dist/cli.js" - }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@mariozechner/pi-coding-agent": { - "version": "0.55.3", - "resolved": "https://registry.npmjs.org/@mariozechner/pi-coding-agent/-/pi-coding-agent-0.55.3.tgz", - "integrity": "sha512-5SFbB7/BIp/Crjre7UNjUeNfpoU1KSW/i6LXa+ikJTBqI5LukWq2avE5l0v0M8Pg/dt1go2XCLrNFlQJiQDSPQ==", + "node_modules/@node-llama-cpp/mac-x64": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/mac-x64/-/mac-x64-3.16.2.tgz", + "integrity": "sha512-BjA+DgeDt+kRxVMV6kChb9XVXm7U5b90jUif7Z/s6ZXtOOnV6exrTM2W09kbSqAiNhZmctcVY83h2dwNTZ/yIw==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "peer": true, - "dependencies": { - "@mariozechner/jiti": "^2.6.2", - "@mariozechner/pi-agent-core": "^0.55.3", - "@mariozechner/pi-ai": "^0.55.3", - "@mariozechner/pi-tui": "^0.55.3", - "@silvia-odwyer/photon-node": "^0.3.4", - "chalk": "^5.5.0", - "cli-highlight": "^2.1.11", - "diff": "^8.0.2", - "extract-zip": "^2.0.1", - "file-type": "^21.1.1", - "glob": "^13.0.1", - "hosted-git-info": "^9.0.2", - "ignore": "^7.0.5", - "marked": "^15.0.12", - "minimatch": "^10.2.3", - "proper-lockfile": "^4.1.2", - "yaml": "^2.8.2" - }, - "bin": { - "pi": "dist/cli.js" - }, "engines": { "node": ">=20.0.0" - }, - "optionalDependencies": { - "@mariozechner/clipboard": "^0.3.2" } }, - "node_modules/@mariozechner/pi-tui": { - "version": "0.55.3", - "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.55.3.tgz", - "integrity": "sha512-Gh4wkYgiSPCJJaB/4wEWSL7Ga8bxSq1Crp1RPRT4vKybE/DG0W/MQr5VJDvktarxtJrD16ixScwE4dzdox/PIA==", + "node_modules/@node-llama-cpp/win-arm64": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/win-arm64/-/win-arm64-3.16.2.tgz", + "integrity": "sha512-XHNFQzUjYODtkZjIn4NbQVrBtGB9RI9TpisiALryqfrIqagQmjBh6dmxZWlt5uduKAfT7M2/2vrABGR490FACA==", + "cpu": [ + "arm64", + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "@types/mime-types": "^2.1.4", - "chalk": "^5.5.0", - "get-east-asian-width": "^1.3.0", - "koffi": "^2.9.0", - "marked": "^15.0.12", - "mime-types": "^3.0.1" - }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@mistralai/mistralai": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.10.0.tgz", - "integrity": "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg==", + "node_modules/@node-llama-cpp/win-x64": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/win-x64/-/win-x64-3.16.2.tgz", + "integrity": "sha512-etrivzbyLNVhZlUosFW8JSL0OSiuKQf9qcI3dNdehD907sHquQbBJrG7lXcdL6IecvXySp3oAwCkM87VJ0b3Fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "zod": "^3.20.0", - "zod-to-json-schema": "^3.24.1" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@mistralai/mistralai/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "node_modules/@node-llama-cpp/win-x64-cuda": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/win-x64-cuda/-/win-x64-cuda-3.16.2.tgz", + "integrity": "sha512-jStDELHrU3rKQMOk5Hs5bWEazyjE2hzHwpNf6SblOpaGkajM/HJtxEZoL0mLHJx5qeXs4oOVkr7AzuLy0WPpNA==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@mozilla/readability": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz", - "integrity": "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==", - "license": "Apache-2.0", + "node_modules/@node-llama-cpp/win-x64-cuda-ext": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/win-x64-cuda-ext/-/win-x64-cuda-ext-3.16.2.tgz", + "integrity": "sha512-sdv4Kzn9bOQWNBRvw6B/zcn8dQRfZhjIHv5AfDBIOfRlSCgjebFpBeYUoU4wZPpjr3ISwcqO5MEWsw+AbUdV3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@napi-rs/canvas": { - "version": "0.1.95", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.95.tgz", - "integrity": "sha512-lkg23ge+rgyhgUwXmlbkPEhuhHq/hUi/gXKH+4I7vO+lJrbNfEYcQdJLIGjKyXLQzgFiiyDAwh5vAe/tITAE+w==", + "node_modules/@node-llama-cpp/win-x64-vulkan": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/@node-llama-cpp/win-x64-vulkan/-/win-x64-vulkan-3.16.2.tgz", + "integrity": "sha512-9xuHFCOhCQjZgQSFrk79EuSKn9nGWt/SAq/3wujQSQLtgp8jGdtZgwcmuDUoemInf10en2dcOmEt7t8dQdC3XA==", + "cpu": [ + "x64" + ], "license": "MIT", - "peer": true, - "workspaces": [ - "e2e/*" + "optional": true, + "os": [ + "win32" ], + "peer": true, "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.95", - "@napi-rs/canvas-darwin-arm64": "0.1.95", - "@napi-rs/canvas-darwin-x64": "0.1.95", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.95", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.95", - "@napi-rs/canvas-linux-arm64-musl": "0.1.95", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.95", - "@napi-rs/canvas-linux-x64-gnu": "0.1.95", - "@napi-rs/canvas-linux-x64-musl": "0.1.95", - "@napi-rs/canvas-win32-arm64-msvc": "0.1.95", - "@napi-rs/canvas-win32-x64-msvc": "0.1.95" + "node": ">=20.0.0" } }, "node_modules/@octokit/app": { @@ -2275,6 +3800,17 @@ "license": "MIT", "peer": true }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -2335,19 +3871,188 @@ "license": "BSD-3-Clause", "peer": true }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause", - "peer": true + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@reflink/reflink": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink/-/reflink-0.1.19.tgz", + "integrity": "sha512-DmCG8GzysnCZ15bres3N5AHCmwBwYgp0As6xjhQ47rAUTUXxJiK+lLUxaGsX3hd/30qUpVElh05PbGuxRPgJwA==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@reflink/reflink-darwin-arm64": "0.1.19", + "@reflink/reflink-darwin-x64": "0.1.19", + "@reflink/reflink-linux-arm64-gnu": "0.1.19", + "@reflink/reflink-linux-arm64-musl": "0.1.19", + "@reflink/reflink-linux-x64-gnu": "0.1.19", + "@reflink/reflink-linux-x64-musl": "0.1.19", + "@reflink/reflink-win32-arm64-msvc": "0.1.19", + "@reflink/reflink-win32-x64-msvc": "0.1.19" + } + }, + "node_modules/@reflink/reflink-darwin-arm64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-darwin-arm64/-/reflink-darwin-arm64-0.1.19.tgz", + "integrity": "sha512-ruy44Lpepdk1FqDz38vExBY/PVUsjxZA+chd9wozjUH9JjuDT/HEaQYA6wYN9mf041l0yLVar6BCZuWABJvHSA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@reflink/reflink-darwin-x64": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-darwin-x64/-/reflink-darwin-x64-0.1.19.tgz", + "integrity": "sha512-By85MSWrMZa+c26TcnAy8SDk0sTUkYlNnwknSchkhHpGXOtjNDUOxJE9oByBnGbeuIE1PiQsxDG3Ud+IVV9yuA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@reflink/reflink-linux-arm64-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-linux-arm64-gnu/-/reflink-linux-arm64-gnu-0.1.19.tgz", + "integrity": "sha512-7P+er8+rP9iNeN+bfmccM4hTAaLP6PQJPKWSA4iSk2bNvo6KU6RyPgYeHxXmzNKzPVRcypZQTpFgstHam6maVg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@reflink/reflink-linux-arm64-musl": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-linux-arm64-musl/-/reflink-linux-arm64-musl-0.1.19.tgz", + "integrity": "sha512-37iO/Dp6m5DDaC2sf3zPtx/hl9FV3Xze4xoYidrxxS9bgP3S8ALroxRK6xBG/1TtfXKTvolvp+IjrUU6ujIGmA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@reflink/reflink-linux-x64-gnu": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-linux-x64-gnu/-/reflink-linux-x64-gnu-0.1.19.tgz", + "integrity": "sha512-jbI8jvuYCaA3MVUdu8vLoLAFqC+iNMpiSuLbxlAgg7x3K5bsS8nOpTRnkLF7vISJ+rVR8W+7ThXlXlUQ93ulkw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@reflink/reflink-linux-x64-musl": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-linux-x64-musl/-/reflink-linux-x64-musl-0.1.19.tgz", + "integrity": "sha512-e9FBWDe+lv7QKAwtKOt6A2W/fyy/aEEfr0g6j/hWzvQcrzHCsz07BNQYlNOjTfeytrtLU7k449H1PI95jA4OjQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@reflink/reflink-win32-arm64-msvc": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-win32-arm64-msvc/-/reflink-win32-arm64-msvc-0.1.19.tgz", + "integrity": "sha512-09PxnVIQcd+UOn4WAW73WU6PXL7DwGS6wPlkMhMg2zlHHG65F3vHepOw06HFCq+N42qkaNAc8AKIabWvtk6cIQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause", - "peer": true + "node_modules/@reflink/reflink-win32-x64-msvc": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@reflink/reflink-win32-x64-msvc/-/reflink-win32-x64-msvc-0.1.19.tgz", + "integrity": "sha512-E//yT4ni2SyhwP8JRjVGWr3cbnhWDiPLgnQ66qqaanjjnMiu3O/2tjCPQXlcGc/DEYofpDc9fvhv6tALQsMV9w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } }, "node_modules/@silvia-odwyer/photon-node": { "version": "0.3.4", @@ -3117,87 +4822,337 @@ "integrity": "sha512-c7awZV6cxY0czgDDSr+Bz0XfRtg8AwW2BWhrHhLJISrpmwv8QzA2qzTllWyMVNdy1+UJr9vCm29hzuh3l8TTFw==", "license": "Apache-2.0", "peer": true, - "dependencies": { - "@smithy/fetch-http-handler": "^5.3.12", - "@smithy/node-http-handler": "^4.4.13", - "@smithy/types": "^4.13.0", - "@smithy/util-base64": "^4.3.1", - "@smithy/util-buffer-from": "^4.2.1", - "@smithy/util-hex-encoding": "^4.2.1", - "@smithy/util-utf8": "^4.2.1", - "tslib": "^2.6.2" - }, + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.12", + "@smithy/node-http-handler": "^4.4.13", + "@smithy/types": "^4.13.0", + "@smithy/util-base64": "^4.3.1", + "@smithy/util-buffer-from": "^4.2.1", + "@smithy/util-hex-encoding": "^4.2.1", + "@smithy/util-utf8": "^4.2.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.1.tgz", + "integrity": "sha512-YmiUDn2eo2IOiWYYvGQkgX5ZkBSiTQu4FlDo5jNPpAxng2t6Sjb6WutnZV9l6VR4eJul1ABmCrnWBC9hKHQa6Q==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.1.tgz", + "integrity": "sha512-DSIwNaWtmzrNQHv8g7DBGR9mulSit65KSj5ymGEIAknmIN8IpbZefEep10LaMG/P/xquwbmJ1h9ectz8z6mV6g==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@smithy/util-buffer-from": "^4.2.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.1.tgz", + "integrity": "sha512-dSfDCeihDmZlV2oyr0yWPTUfh07suS+R5OB+FZGiv/hHyK3hrFBW5rR1UYjfa57vBsrP9lciFkRPzebaV1Qujw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@snazzah/davey": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey/-/davey-0.1.10.tgz", + "integrity": "sha512-J5f7vV5/tnj0xGnqufFRd6qiWn3FcR3iXjpjpEmO2Ok+Io0AASkMaZ3I39TsL45as0Qo5bq9wWuamFQ77PjJ+g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "url": "https://github.com/sponsors/Snazzah" + }, + "optionalDependencies": { + "@snazzah/davey-android-arm-eabi": "0.1.10", + "@snazzah/davey-android-arm64": "0.1.10", + "@snazzah/davey-darwin-arm64": "0.1.10", + "@snazzah/davey-darwin-x64": "0.1.10", + "@snazzah/davey-freebsd-x64": "0.1.10", + "@snazzah/davey-linux-arm-gnueabihf": "0.1.10", + "@snazzah/davey-linux-arm64-gnu": "0.1.10", + "@snazzah/davey-linux-arm64-musl": "0.1.10", + "@snazzah/davey-linux-x64-gnu": "0.1.10", + "@snazzah/davey-linux-x64-musl": "0.1.10", + "@snazzah/davey-wasm32-wasi": "0.1.10", + "@snazzah/davey-win32-arm64-msvc": "0.1.10", + "@snazzah/davey-win32-ia32-msvc": "0.1.10", + "@snazzah/davey-win32-x64-msvc": "0.1.10" + } + }, + "node_modules/@snazzah/davey-android-arm-eabi": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-android-arm-eabi/-/davey-android-arm-eabi-0.1.10.tgz", + "integrity": "sha512-7bwHxSNEI2wVXOT6xnmpnO9SHb2xwAnf9oEdL45dlfVHTgU1Okg5rwGwRvZ2aLVFFbTyecfC8EVZyhpyTkjLSw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-android-arm64": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-android-arm64/-/davey-android-arm64-0.1.10.tgz", + "integrity": "sha512-68WUf2LQwQTP9MgPcCqTWwJztJSIk0keGfF2Y/b+MihSDh29fYJl7C0rbz69aUrVCvCC2lYkB/46P8X1kBz7yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-darwin-arm64": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-darwin-arm64/-/davey-darwin-arm64-0.1.10.tgz", + "integrity": "sha512-nYC+DWCGUC1jUGEenCNQE/jJpL/02m0ebY/NvTCQbul5ktI/ShVzgA3kzssEhZvhf6jbH048Rs39wDhp/b24Jg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-darwin-x64": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-darwin-x64/-/davey-darwin-x64-0.1.10.tgz", + "integrity": "sha512-0q5Rrcs+O9sSSnPX+A3R3djEQs2nTAtMe5N3lApO6lZas/QNMl6wkEWCvTbDc2cfAYBMSk2jgc1awlRXi4LX3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-freebsd-x64": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-freebsd-x64/-/davey-freebsd-x64-0.1.10.tgz", + "integrity": "sha512-/Gq5YDD6Oz8iBqVJLswUnetCv9JCRo1quYX5ujzpAG8zPCNItZo4g4h5p9C+h4Yoay2quWBYhoaVqQKT96bm8g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-linux-arm-gnueabihf": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-linux-arm-gnueabihf/-/davey-linux-arm-gnueabihf-0.1.10.tgz", + "integrity": "sha512-0Z7Vrt0WIbgxws9CeHB9qlueYJlvltI44rUuZmysdi70UcHGxlr7nE3MnzYCr9nRWRegohn8EQPWHMKMDJH2GA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-linux-arm64-gnu": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-linux-arm64-gnu/-/davey-linux-arm64-gnu-0.1.10.tgz", + "integrity": "sha512-xhZQycn4QB+qXhqm/QmZ+kb9MHMXcbjjoPfvcIL4WMQXFG/zUWHW8EiBk7ZTEGMOpeab3F9D1+MlgumglYByUQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-linux-arm64-musl": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-linux-arm64-musl/-/davey-linux-arm64-musl-0.1.10.tgz", + "integrity": "sha512-pudzQCP9rZItwW4qHHvciMwtNd9kWH4l73g6Id1LRpe6sc8jiFBV7W+YXITj2PZbI0by6XPfkRP6Dk5IkGOuAw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-linux-x64-gnu": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-linux-x64-gnu/-/davey-linux-x64-gnu-0.1.10.tgz", + "integrity": "sha512-DC8qRmk+xJEFNqjxKB46cETKeDQqgUqE5p39KXS2k6Vl/XTi8pw8pXOxrPfYte5neoqlWAVQzbxuLnwpyRJVEQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@snazzah/davey-linux-x64-musl": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-linux-x64-musl/-/davey-linux-x64-musl-0.1.10.tgz", + "integrity": "sha512-wPR5/2QmsF7sR0WUaCwbk4XI3TLcxK9PVK8mhgcAYyuRpbhcVgNGWXs8ulcyMSXve5pFRJAFAuMTGCEb014peg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=18.0.0" + "node": ">= 10" } }, - "node_modules/@smithy/util-uri-escape": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.1.tgz", - "integrity": "sha512-YmiUDn2eo2IOiWYYvGQkgX5ZkBSiTQu4FlDo5jNPpAxng2t6Sjb6WutnZV9l6VR4eJul1ABmCrnWBC9hKHQa6Q==", - "license": "Apache-2.0", + "node_modules/@snazzah/davey-wasm32-wasi": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-wasm32-wasi/-/davey-wasm32-wasi-0.1.10.tgz", + "integrity": "sha512-SfQavU+eKTDbRmPeLRodrVSfsWq25PYTmH1nIZW3B27L6IkijzjXZZuxiU1ZG1gdI5fB7mwXrOTtx34t+vAG7Q==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, "peer": true, "dependencies": { - "tslib": "^2.6.2" + "@napi-rs/wasm-runtime": "^1.1.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@smithy/util-utf8": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.1.tgz", - "integrity": "sha512-DSIwNaWtmzrNQHv8g7DBGR9mulSit65KSj5ymGEIAknmIN8IpbZefEep10LaMG/P/xquwbmJ1h9ectz8z6mV6g==", - "license": "Apache-2.0", + "node_modules/@snazzah/davey-win32-arm64-msvc": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-win32-arm64-msvc/-/davey-win32-arm64-msvc-0.1.10.tgz", + "integrity": "sha512-Raafk53smYs67wZCY9bQXHXzbaiRMS5QCdjTdin3D9fF5A06T/0Zv1z7/YnaN+O3GSL/Ou3RvynF7SziToYiFQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "@smithy/util-buffer-from": "^4.2.1", - "tslib": "^2.6.2" - }, "engines": { - "node": ">=18.0.0" + "node": ">= 10" } }, - "node_modules/@smithy/uuid": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.1.tgz", - "integrity": "sha512-dSfDCeihDmZlV2oyr0yWPTUfh07suS+R5OB+FZGiv/hHyK3hrFBW5rR1UYjfa57vBsrP9lciFkRPzebaV1Qujw==", - "license": "Apache-2.0", + "node_modules/@snazzah/davey-win32-ia32-msvc": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@snazzah/davey-win32-ia32-msvc/-/davey-win32-ia32-msvc-0.1.10.tgz", + "integrity": "sha512-pAs43l/DiZ+icqBwxIwNePzuYxFM1ZblVuf7t6vwwSLxvova7vnREnU7qDVjbc5/YTUHOsqYy3S6TpZMzDo2lw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, "engines": { - "node": ">=18.0.0" + "node": ">= 10" } }, - "node_modules/@snazzah/davey": { + "node_modules/@snazzah/davey-win32-x64-msvc": { "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@snazzah/davey/-/davey-0.1.10.tgz", - "integrity": "sha512-J5f7vV5/tnj0xGnqufFRd6qiWn3FcR3iXjpjpEmO2Ok+Io0AASkMaZ3I39TsL45as0Qo5bq9wWuamFQ77PjJ+g==", + "resolved": "https://registry.npmjs.org/@snazzah/davey-win32-x64-msvc/-/davey-win32-x64-msvc-0.1.10.tgz", + "integrity": "sha512-kr6148VVBoUT4CtD+5hYshTFRny7R/xQZxXFhFc0fYjtmdMVM8Px9M91olg1JFNxuNzdfMfTufR58Q3wfBocug==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "peer": true, "engines": { "node": ">= 10" - }, - "funding": { - "url": "https://github.com/sponsors/Snazzah" - }, - "optionalDependencies": { - "@snazzah/davey-android-arm-eabi": "0.1.10", - "@snazzah/davey-android-arm64": "0.1.10", - "@snazzah/davey-darwin-arm64": "0.1.10", - "@snazzah/davey-darwin-x64": "0.1.10", - "@snazzah/davey-freebsd-x64": "0.1.10", - "@snazzah/davey-linux-arm-gnueabihf": "0.1.10", - "@snazzah/davey-linux-arm64-gnu": "0.1.10", - "@snazzah/davey-linux-arm64-musl": "0.1.10", - "@snazzah/davey-linux-x64-gnu": "0.1.10", - "@snazzah/davey-linux-x64-musl": "0.1.10", - "@snazzah/davey-wasm32-wasi": "0.1.10", - "@snazzah/davey-win32-arm64-msvc": "0.1.10", - "@snazzah/davey-win32-ia32-msvc": "0.1.10", - "@snazzah/davey-win32-x64-msvc": "0.1.10" } }, "node_modules/@tinyhttp/content-disposition": { @@ -3246,6 +5201,17 @@ "license": "MIT", "peer": true }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/aws-lambda": { "version": "8.10.161", "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.161.tgz", @@ -3264,6 +5230,17 @@ "@types/node": "*" } }, + "node_modules/@types/bun": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.9.tgz", + "integrity": "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bun-types": "1.3.9" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -3399,6 +5376,17 @@ "@types/node": "*" } }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@whiskeysockets/baileys": { "version": "7.0.0-rc.9", "resolved": "https://registry.npmjs.org/@whiskeysockets/baileys/-/baileys-7.0.0-rc.9.tgz", @@ -3469,6 +5457,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true, + "peer": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -3587,6 +5583,46 @@ "license": "MIT", "peer": true }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true, + "peer": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3797,6 +5833,17 @@ "license": "MIT", "peer": true }, + "node_modules/bun-types": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.9.tgz", + "integrity": "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4154,6 +6201,17 @@ "license": "MIT", "peer": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4177,6 +6235,22 @@ "node": ">=14" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true, + "peer": true + }, "node_modules/content-disposition": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", @@ -4393,6 +6467,14 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5126,62 +7208,154 @@ "node": ">= 0.6" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true, + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true, + "peer": true + }, + "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", "peer": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, "peer": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", + "optional": true, "peer": true, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/fs-extra": { - "version": "11.3.4", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", - "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", + "optional": true, "peer": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=14.14" - } - }, - "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", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/gaxios": { @@ -5553,6 +7727,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true, + "peer": true + }, "node_modules/hashery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.0.tgz", @@ -5589,6 +7771,17 @@ "node": "*" } }, + "node_modules/hono": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.5.tgz", + "integrity": "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/hookified": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", @@ -5753,6 +7946,19 @@ "license": "MIT", "peer": true }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -6368,6 +8574,34 @@ "node": "20 || >=22" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/markdown-it": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", @@ -6528,6 +8762,20 @@ "node": ">= 18" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6755,6 +9003,46 @@ } } }, + "node_modules/node-readable-to-web-readable-stream": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/node-readable-to-web-readable-stream/-/node-readable-to-web-readable-stream-0.4.2.tgz", + "integrity": "sha512-/cMZNI34v//jUTrI+UIo4ieHAB5EZRY/+7OmXZgBxaWBMcW2tGdceIw06RFxWxrKZ5Jp3sI2i5TsRo+CBhtVLQ==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -7208,6 +9496,17 @@ "license": "MIT", "peer": true }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7696,6 +9995,81 @@ "node": ">= 4" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -7811,6 +10185,14 @@ "url": "https://opencollective.com/express" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true, + "peer": true + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -8119,6 +10501,76 @@ "sqlite-vec-windows-x64": "0.1.7-alpha.2" } }, + "node_modules/sqlite-vec-darwin-arm64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-darwin-arm64/-/sqlite-vec-darwin-arm64-0.1.7-alpha.2.tgz", + "integrity": "sha512-raIATOqFYkeCHhb/t3r7W7Cf2lVYdf4J3ogJ6GFc8PQEgHCPEsi+bYnm2JT84MzLfTlSTIdxr4/NKv+zF7oLPw==", + "cpu": [ + "arm64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/sqlite-vec-darwin-x64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-darwin-x64/-/sqlite-vec-darwin-x64-0.1.7-alpha.2.tgz", + "integrity": "sha512-jeZEELsQjjRsVojsvU5iKxOvkaVuE+JYC8Y4Ma8U45aAERrDYmqZoHvgSG7cg1PXL3bMlumFTAmHynf1y4pOzA==", + "cpu": [ + "x64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/sqlite-vec-linux-arm64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-linux-arm64/-/sqlite-vec-linux-arm64-0.1.7-alpha.2.tgz", + "integrity": "sha512-6Spj4Nfi7tG13jsUG+W7jnT0bCTWbyPImu2M8nWp20fNrd1SZ4g3CSlDAK8GBdavX7wRlbBHCZ+BDa++rbDewA==", + "cpu": [ + "arm64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/sqlite-vec-linux-x64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-linux-x64/-/sqlite-vec-linux-x64-0.1.7-alpha.2.tgz", + "integrity": "sha512-IcgrbHaDccTVhXDf8Orwdc2+hgDLAFORl6OBUhcvlmwswwBP1hqBTSEhovClG4NItwTOBNgpwOoQ7Qp3VDPWLg==", + "cpu": [ + "x64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/sqlite-vec-windows-x64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-windows-x64/-/sqlite-vec-windows-x64-0.1.7-alpha.2.tgz", + "integrity": "sha512-TRP6hTjAcwvQ6xpCZvjP00pdlda8J38ArFy1lMYhtQWXiIBmWnhMaMbq4kaeCYwvTTddfidatRS+TJrwIKB/oQ==", + "cpu": [ + "x64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -8737,6 +11189,17 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/win-guid": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/win-guid/-/win-guid-0.2.1.tgz", From 6d965eca4605adb0247b17bac59d20e5c0786e42 Mon Sep 17 00:00:00 2001 From: MestreY0d4-Uninter Date: Mon, 9 Mar 2026 10:14:53 -0300 Subject: [PATCH 2/6] feat: add issueComplete notification when issue is closed Adds a new "issueComplete" notification event type that fires when an issue is closed via the CLOSE_ISSUE completion action. This provides visibility into the final delivery milestone of the pipeline. Co-Authored-By: Claude Opus 4.6 --- lib/dispatch/notify.ts | 17 +++++++++++++++++ lib/services/pipeline.ts | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lib/dispatch/notify.ts b/lib/dispatch/notify.ts index e9abca46..1bd2c64b 100644 --- a/lib/dispatch/notify.ts +++ b/lib/dispatch/notify.ts @@ -85,6 +85,14 @@ export type NotifyEvent = issueUrl: string; issueTitle: string; prUrl?: string; + } + | { + type: "issueComplete"; + project: string; + issueId: number; + issueUrl: string; + issueTitle: string; + prUrl?: string; }; /** @@ -245,6 +253,15 @@ function buildMessage(event: NotifyEvent): string { msg += `\n→ Moving to To Improve for developer attention`; return msg; } + + case "issueComplete": { + let msg = `🏁 Issue completed: #${event.issueId} — ${event.issueTitle}`; + msg += `\n📦 Project: ${event.project}`; + if (event.prUrl) msg += `\n🔗 ${prLink(event.prUrl)}`; + msg += `\n📋 [Issue #${event.issueId}](${event.issueUrl})`; + msg += `\n✅ Issue closed — work delivered.`; + return msg; + } } } diff --git a/lib/services/pipeline.ts b/lib/services/pipeline.ts index 681ebb9d..fcfaf91a 100644 --- a/lib/services/pipeline.ts +++ b/lib/services/pipeline.ts @@ -212,6 +212,27 @@ export async function executeCompletion(opts: { switch (action) { case Action.CLOSE_ISSUE: await provider.closeIssue(issueId); + // Notify that the issue has been fully completed and closed + notify( + { + type: "issueComplete", + project: projectName, + issueId, + issueUrl: issue.web_url, + issueTitle: issue.title, + prUrl, + }, + { + workspaceDir, + config: notifyConfig, + channelId: notifyTarget?.channelId, + channel: notifyTarget?.channel ?? "telegram", + runtime, + accountId: notifyTarget?.accountId, + }, + ).catch((err) => { + auditLog(workspaceDir, "pipeline_warning", { step: "issueCompleteNotify", issue: issueId, role, error: (err as Error).message ?? String(err) }).catch(() => {}); + }); break; case Action.REOPEN_ISSUE: await provider.reopenIssue(issueId); From 2e2382f29df40f70e26adc4e8689b3ad2a2f54a5 Mon Sep 17 00:00:00 2001 From: MinglesAI Date: Fri, 13 Mar 2026 07:30:49 +0000 Subject: [PATCH 3/6] fix: use project.slug (lowercase) for session key instead of project.name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a project is registered with a mixed-case name (e.g. 'UpMoltWork'), the session key was built using project.name, resulting in keys like: agent:main:subagent:UpMoltWork-developer-junior-annabelle However, the gateway stores and looks up session keys case-sensitively, and new sessions are created with lowercase keys. This mismatch caused the heartbeat to not find the active session, consider the worker dead, and re-dispatch — resulting in workers being restarted every heartbeat cycle. Fix: use project.slug (which is always lowercase) to build the session key. Falls back to project.name.toLowerCase() for safety. Fixes: worker restart loop on projects with mixed-case names --- lib/dispatch/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/dispatch/index.ts b/lib/dispatch/index.ts index 4efd8ca7..bcb612a3 100644 --- a/lib/dispatch/index.ts +++ b/lib/dispatch/index.ts @@ -132,7 +132,11 @@ export async function dispatchTask( // Compute session key deterministically (avoids waiting for gateway) // Slot name provides both collision prevention and human-readable identity const botName = slotName(project.name, role, level, slotIndex); - const sessionKey = `agent:${agentId ?? "unknown"}:subagent:${project.name}-${role}-${level}-${botName.toLowerCase()}`; + // Use project.slug (always lowercase) to build session key. + // project.name may have mixed case (e.g. "UpMoltWork"), which caused heartbeat + // mismatches when the gateway stores session keys in lowercase format. + const projectKey = (project.slug ?? project.name).toLowerCase(); + const sessionKey = `agent:${agentId ?? "unknown"}:subagent:${projectKey}-${role}-${level}-${botName.toLowerCase()}`; // Clear stale session key if it doesn't match the current deterministic key // (handles migration from old numeric format like ...-0 to name-based ...-Cordelia) From 0376e213e1af6c560ae2f780ee939caebc331fd7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 13 Mar 2026 16:38:22 +0400 Subject: [PATCH 4/6] fix #508: improve slot session key comparison in work-finish tool. Updated the logic for finding active slots to ensure case-insensitive comparison of session keys, enhancing the accuracy of slot matching for the current session. --- lib/tools/worker/work-finish.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/tools/worker/work-finish.ts b/lib/tools/worker/work-finish.ts index 4b3ba989..ac39efdc 100644 --- a/lib/tools/worker/work-finish.ts +++ b/lib/tools/worker/work-finish.ts @@ -224,16 +224,20 @@ export function createWorkFinishTool(ctx: PluginContext) { const { project } = await resolveProject(workspaceDir, channelId); const roleWorker = getRoleWorker(project, role); - // Find the first active slot across all levels + // Find the first active slot across all levels that matches this session. + // Session keys can differ slightly in casing between the tool context and + // stored slot state, so comparisons are case-insensitive. let slotIndex: number | null = null; let slotLevel: string | null = null; let issueId: number | null = null; for (const [level, slots] of Object.entries(roleWorker.levels)) { for (let i = 0; i < slots.length; i++) { - if (slots[i]!.active && slots[i]!.issueId && - (!toolCtx.sessionKey || !slots[i]!.sessionKey || - slots[i]!.sessionKey === toolCtx.sessionKey)) { + const slot = slots[i]!; + if (slot.active && slot.issueId && + (!toolCtx.sessionKey || !slot.sessionKey || + (slot.sessionKey && toolCtx.sessionKey && + slot.sessionKey.toLowerCase() === toolCtx.sessionKey.toLowerCase()))) { slotLevel = level; slotIndex = i; issueId = Number(slots[i]!.issueId); From 2b8eedde06f81e96324f11e75c4c714706ca4f7d Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 20 Mar 2026 21:56:35 +0400 Subject: [PATCH 5/6] feat: enhance project resolution with messageThreadId support This update introduces support for the optional messageThreadId parameter across various project resolution functions and tools, enabling topic-aware routing for Telegram channels. Key changes include: - New function `resolveProjectChannelScope` for building stable scope keys. - Updates to `resolveProjectSlug` and `getProject` to handle scoped inputs. - Migration logic for normalizing legacy topic fields in projects. - Adjustments in admin tools to accommodate messageThreadId for channel linking, un-linking, and listing. These enhancements improve the flexibility and accuracy of project management within chat environments, particularly for Telegram forum topics. --- lib/projects/io.ts | 114 ++++++++++++++++++++++++---- lib/projects/migrations.ts | 21 ++++- lib/projects/types.ts | 6 +- lib/tools/admin/channel-link.ts | 32 ++++++-- lib/tools/admin/channel-list.ts | 27 +++++-- lib/tools/admin/channel-unlink.ts | 22 +++++- lib/tools/admin/health.ts | 4 +- lib/tools/admin/project-register.ts | 36 +++++++++ lib/tools/admin/project-status.ts | 13 +++- lib/tools/helpers.ts | 10 ++- lib/tools/tasks/task-attach.ts | 16 +++- lib/tools/tasks/task-comment.ts | 13 +++- lib/tools/tasks/task-create.ts | 13 +++- lib/tools/tasks/task-edit-body.ts | 13 +++- lib/tools/tasks/task-list.ts | 13 +++- lib/tools/tasks/task-owner.ts | 13 +++- lib/tools/tasks/task-set-level.ts | 13 +++- lib/tools/tasks/task-start.ts | 13 +++- lib/tools/tasks/tasks-status.ts | 13 +++- lib/tools/worker/work-finish.ts | 10 ++- 20 files changed, 366 insertions(+), 49 deletions(-) diff --git a/lib/projects/io.ts b/lib/projects/io.ts index bd11b278..48d456e2 100644 --- a/lib/projects/io.ts +++ b/lib/projects/io.ts @@ -7,7 +7,7 @@ import { homedir } from "node:os"; import { migrateProject } from "./migrations.js"; import { ensureWorkspaceMigrated, DATA_DIR } from "../setup/migrate-layout.js"; import { isLegacySchema, migrateLegacySchema } from "./schema-migration.js"; -import type { ProjectsData, Project } from "./types.js"; +import type { ProjectsData, Project, Channel } from "./types.js"; import { emptySlot } from "./slots.js"; @@ -102,36 +102,122 @@ export async function writeProjects( } /** - * Resolve a project by slug or channelId (for backward compatibility). - * Returns the slug of the found project. + * Build a stable scope key for a channel binding. + * Used for topic-aware project resolution. + */ +export function resolveProjectChannelScope(opts: { + channel: string; + channelId: string; + accountId?: string; + messageThreadId?: number | string | null; +}): string { + const account = opts.accountId ?? "default"; + const topic = opts.messageThreadId ?? "root"; + return `${opts.channel}:${account}:${opts.channelId}:topic:${topic}`; +} + +/** + * Normalize a channel's topic-related fields for resolution. + * - For Telegram, map legacy topicId into messageThreadId when needed. + * - Leaves non-Telegram channels unchanged (they are effectively root-scope). + */ +function normalizeChannelTopic(ch: Channel): Channel { + if (ch.channel !== "telegram") { + return ch; + } + const legacy = ch as Channel & { topicId?: number }; + if (ch.messageThreadId == null && legacy.topicId != null) { + ch.messageThreadId = legacy.topicId; + } + return ch; +} + +/** + * Resolve a project by slug or channel scope (for backward compatibility). + * When given a bare string, treats it as slug or channelId (legacy behavior). + * When given a scope object, performs topic-aware resolution. */ export function resolveProjectSlug( data: ProjectsData, - slugOrChannelId: string, + slugOrChannelIdOrScope: string | { + channelId: string; + channel?: string; + accountId?: string; + messageThreadId?: number | string | null; + }, ): string | undefined { - // Direct lookup by slug - if (data.projects[slugOrChannelId]) { - return slugOrChannelId; + // String input: legacy mode (slug or channelId) + if (typeof slugOrChannelIdOrScope === "string") { + const slugOrChannelId = slugOrChannelIdOrScope; + // Direct lookup by slug + if (data.projects[slugOrChannelId]) { + return slugOrChannelId; + } + + // Reverse lookup by channelId in channels + for (const [slug, project] of Object.entries(data.projects)) { + if (project.channels.some((ch) => ch.channelId === slugOrChannelId)) { + return slug; + } + } + + return undefined; } - // Reverse lookup by channelId in channels + // Scoped input: topic-aware resolution + const { channelId, channel, accountId, messageThreadId } = slugOrChannelIdOrScope; + const requestedChannel = channel ?? "telegram"; + const requestedKey = resolveProjectChannelScope({ + channel: requestedChannel, + channelId, + accountId, + messageThreadId, + }); + + let fallbackSlug: string | undefined; + for (const [slug, project] of Object.entries(data.projects)) { - if (project.channels.some(ch => ch.channelId === slugOrChannelId)) { - return slug; + for (const rawCh of project.channels) { + const ch = normalizeChannelTopic(rawCh); + const scopeKey = resolveProjectChannelScope({ + channel: ch.channel, + channelId: ch.channelId, + accountId: ch.accountId, + messageThreadId: ch.messageThreadId, + }); + + // Exact topic match wins immediately + if (scopeKey === requestedKey) { + return slug; + } + + // Record chat-level fallback when messageThreadId is undefined/root + const isRootScope = + ch.channel === requestedChannel && + ch.channelId === channelId && + (ch.messageThreadId == null || ch.messageThreadId === ("root" as any)); + if (isRootScope && !fallbackSlug) { + fallbackSlug = slug; + } } } - return undefined; + return fallbackSlug; } /** - * Get a project by slug or channelId (dual-mode resolution). + * Get a project by slug or channel scope (dual-mode resolution). */ export function getProject( data: ProjectsData, - slugOrChannelId: string, + slugOrChannelIdOrScope: string | { + channelId: string; + channel?: string; + accountId?: string; + messageThreadId?: number | string | null; + }, ): Project | undefined { - const slug = resolveProjectSlug(data, slugOrChannelId); + const slug = resolveProjectSlug(data, slugOrChannelIdOrScope); return slug ? data.projects[slug] : undefined; } diff --git a/lib/projects/migrations.ts b/lib/projects/migrations.ts index 80a96265..7d36dff6 100644 --- a/lib/projects/migrations.ts +++ b/lib/projects/migrations.ts @@ -12,7 +12,7 @@ * - projects.json format: flat slots → per-level format */ -import type { RoleWorkerState, SlotState, Project } from "./types.js"; +import type { RoleWorkerState, SlotState, Project, Channel } from "./types.js"; // --------------------------------------------------------------------------- // Role aliases — old role IDs → canonical IDs @@ -230,6 +230,25 @@ export function migrateProject(project: Project): boolean { project.workers = {}; } + // Normalize channel topic fields for Telegram channels: + // - Migrate legacy groupId -> channelId (handled below) + // - Migrate legacy topicId -> messageThreadId when messageThreadId is missing + if (project.channels) { + for (const ch of project.channels) { + const rawCh = ch as unknown as Record & Channel; + + // Normalize legacy Telegram topic field: topicId -> messageThreadId + if ( + rawCh.channel === "telegram" && + rawCh.topicId != null && + rawCh.messageThreadId == null + ) { + rawCh.messageThreadId = Number(rawCh.topicId); + changed = true; + } + } + } + // Migrate legacy `groupId` field to `channelId` in channel objects. // Before the rename, channels were stored with { groupId: "..." } on disk. if (project.channels) { diff --git a/lib/projects/types.ts b/lib/projects/types.ts index a51c9313..24302edd 100644 --- a/lib/projects/types.ts +++ b/lib/projects/types.ts @@ -33,7 +33,11 @@ export type Channel = { name: string; // e.g. "primary", "dev-chat" events: string[]; // e.g. ["*"] for all, ["workerComplete"] for filtered accountId?: string; // Optional account ID for multi-account setups - messageThreadId?: number; // Optional Telegram forum topic ID for per-topic routing + /** + * Telegram forum topic ID used for topic-scoped routing. + * Mirrors Telegram API naming for clarity and interoperability. + */ + messageThreadId?: number; }; /** diff --git a/lib/tools/admin/channel-link.ts b/lib/tools/admin/channel-link.ts index 8e0324f3..555594c8 100644 --- a/lib/tools/admin/channel-link.ts +++ b/lib/tools/admin/channel-link.ts @@ -45,6 +45,11 @@ export function createChannelLinkTool(_ctx: PluginContext) { description: "Display name for this channel (e.g. 'general', 'dev-chat'). Auto-generated if omitted.", }, + messageThreadId: { + type: "number", + description: + "Optional Telegram forum topic ID (message_thread_id). When provided, links this specific topic instead of the whole chat.", + }, }, }, @@ -53,6 +58,7 @@ export function createChannelLinkTool(_ctx: PluginContext) { const projectRef = params.project as string; const channelType = (params.channel as Channel["channel"]) ?? "telegram"; const channelName = params.name as string | undefined; + const messageThreadId = params.messageThreadId as number | undefined; const workspaceDir = requireWorkspaceDir(toolCtx); if (!channelId) throw new Error("channelId is required."); @@ -78,9 +84,11 @@ export function createChannelLinkTool(_ctx: PluginContext) { ); } - // Already linked to this project? - const alreadyLinked = target.channels.some( - (ch) => ch.channelId === channelId, + // Already linked to this project for the same scope? + const alreadyLinked = target.channels.some((ch) => + ch.channelId === channelId && + ch.channel === channelType && + (messageThreadId == null || ch.messageThreadId === messageThreadId) ); if (alreadyLinked) { return jsonResult({ @@ -93,11 +101,13 @@ export function createChannelLinkTool(_ctx: PluginContext) { }); } - // Auto-detach from any other project that has this channelId + // Auto-detach from any other project that has this exact scoped binding let detachedFrom: string | null = null; for (const project of Object.values(data.projects)) { - const idx = project.channels.findIndex( - (ch) => ch.channelId === channelId, + const idx = project.channels.findIndex((ch) => + ch.channelId === channelId && + ch.channel === channelType && + (messageThreadId == null || ch.messageThreadId === messageThreadId) ); if (idx !== -1) { detachedFrom = project.name; @@ -112,6 +122,9 @@ export function createChannelLinkTool(_ctx: PluginContext) { channel: channelType, name: channelName ?? `channel-${target.channels.length + 1}`, events: ["*"], + ...(messageThreadId != null && channelType === "telegram" + ? { messageThreadId } + : {}), }; target.channels.push(newChannel); @@ -123,6 +136,7 @@ export function createChannelLinkTool(_ctx: PluginContext) { channelId, channelType, channelName: newChannel.name, + messageThreadId: messageThreadId ?? null, detachedFrom, }); @@ -136,8 +150,12 @@ export function createChannelLinkTool(_ctx: PluginContext) { projectSlug: target.slug, channelId, channelName: newChannel.name, + messageThreadId: messageThreadId ?? null, detachedFrom, - announcement: `Channel linked to "${target.name}"${detachNote}.`, + announcement: + messageThreadId != null && channelType === "telegram" + ? `Channel topic ${messageThreadId} linked to "${target.name}"${detachNote}.` + : `Channel linked to "${target.name}"${detachNote}.`, }); }, }); diff --git a/lib/tools/admin/channel-list.ts b/lib/tools/admin/channel-list.ts index f5bed3cc..a4864dda 100644 --- a/lib/tools/admin/channel-list.ts +++ b/lib/tools/admin/channel-list.ts @@ -57,6 +57,7 @@ export function createChannelListTool(_ctx: PluginContext) { name: ch.name, events: ch.events, accountId: ch.accountId, + messageThreadId: ch.messageThreadId ?? null, })); const announcement = @@ -65,10 +66,16 @@ export function createChannelListTool(_ctx: PluginContext) { ? "_(none)_" : channels .map( - (ch) => - `• **${ch.name}** (${ch.type})\n ID: \`${ch.channelId}\`\n Events: ${ch.events.join(", ")}${ - ch.accountId ? `\n Account: ${ch.accountId}` : "" - }`, + (ch) => { + const topicSuffix = + ch.type === "telegram" && ch.messageThreadId != null + ? `\n Topic: ${ch.messageThreadId}` + : ""; + const accountSuffix = ch.accountId ? `\n Account: ${ch.accountId}` : ""; + return `• **${ch.name}** (${ch.type})\n ID: \`${ch.channelId}\`${topicSuffix}\n Events: ${ch.events.join( + ", ", + )}${accountSuffix}`; + }, ) .join("\n\n")); @@ -100,6 +107,7 @@ export function createChannelListTool(_ctx: PluginContext) { name: ch.name, events: ch.events, accountId: ch.accountId, + messageThreadId: ch.messageThreadId ?? null, })), })); @@ -111,10 +119,13 @@ export function createChannelListTool(_ctx: PluginContext) { p.channels.length === 0 ? " _(no channels)_" : p.channels - .map( - (ch) => - ` • **${ch.name}** (${ch.type}) — \`${ch.channelId}\``, - ) + .map((ch) => { + const topicSuffix = + ch.type === "telegram" && ch.messageThreadId != null + ? ` topic:${ch.messageThreadId}` + : ""; + return ` • **${ch.name}** (${ch.type}) — \`${ch.channelId}\`${topicSuffix}`; + }) .join("\n"); return `**${p.project}** (${p.projectSlug}):\n${channelList}`; }) diff --git a/lib/tools/admin/channel-unlink.ts b/lib/tools/admin/channel-unlink.ts index ed1e3642..e08fcbb7 100644 --- a/lib/tools/admin/channel-unlink.ts +++ b/lib/tools/admin/channel-unlink.ts @@ -35,6 +35,10 @@ export function createChannelUnlinkTool(_ctx: PluginContext) { type: "boolean", description: "Set to true to confirm the removal. Defaults to false (dry-run).", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID. When provided, only unlinks the matching topic binding for this channel instead of all bindings for the chat.", + }, }, }, @@ -42,6 +46,7 @@ export function createChannelUnlinkTool(_ctx: PluginContext) { const channelId = params.channelId as string; const projectRef = params.project as string; const confirm = params.confirm as boolean | undefined; + const messageThreadId = params.messageThreadId as number | undefined; const workspaceDir = requireWorkspaceDir(toolCtx); if (!channelId) throw new Error("channelId is required."); @@ -66,8 +71,11 @@ export function createChannelUnlinkTool(_ctx: PluginContext) { ); } - // Find the channel - const idx = target.channels.findIndex((ch) => ch.channelId === channelId); + // Find the channel (optionally scoped by messageThreadId) + const idx = target.channels.findIndex((ch) => + ch.channelId === channelId && + (messageThreadId == null || ch.messageThreadId === messageThreadId) + ); if (idx === -1) { throw new Error( `Channel ${channelId} not found in project "${target.name}".`, @@ -93,9 +101,12 @@ export function createChannelUnlinkTool(_ctx: PluginContext) { channelId, channelName: channel.name, channelType: channel.channel, + messageThreadId: channel.messageThreadId ?? null, remainingChannels: target.channels.length - 1, announcement: - `DRY-RUN: Would remove channel "${channel.name}" (${channelId}) from project "${target.name}". ` + + `DRY-RUN: Would remove channel "${channel.name}" (${channelId}${ + channel.messageThreadId != null ? ` topic ${channel.messageThreadId}` : "" + }) from project "${target.name}". ` + `${target.channels.length - 1} channel(s) would remain. Set confirm=true to proceed.`, }); } @@ -111,6 +122,7 @@ export function createChannelUnlinkTool(_ctx: PluginContext) { channelId, channelName: channel.name, channelType: channel.channel, + messageThreadId: channel.messageThreadId ?? null, }); return jsonResult({ @@ -122,7 +134,9 @@ export function createChannelUnlinkTool(_ctx: PluginContext) { channelType: channel.channel, remainingChannels: target.channels.length, announcement: - `Channel "${channel.name}" (${channelId}) unlinked from project "${target.name}". ` + + `Channel "${channel.name}" (${channelId}${ + channel.messageThreadId != null ? ` topic ${channel.messageThreadId}` : "" + }) unlinked from project "${target.name}". ` + `${target.channels.length} channel(s) remaining.`, }); }, diff --git a/lib/tools/admin/health.ts b/lib/tools/admin/health.ts index 6ba03d3f..77e348f9 100644 --- a/lib/tools/admin/health.ts +++ b/lib/tools/admin/health.ts @@ -12,7 +12,7 @@ * * Read-only by default (surfaces issues). Pass fix=true to apply fixes. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "openclaw/plugin-sdk/channel-runtime"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { readProjects, getProject } from "../../projects/index.js"; @@ -44,6 +44,8 @@ export function createHealthTool(ctx: PluginContext) { // Resolve slug from slugOrChannelId let slugs = Object.keys(data.projects); if (slugOrChannelId) { + // Use legacy resolution by channelId or slug (health is not topic-scoped; + // it scans the full project), so we intentionally pass the bare string. const project = getProject(data, slugOrChannelId); const slug = project ? (data.projects[slugOrChannelId] ? slugOrChannelId : diff --git a/lib/tools/admin/project-register.ts b/lib/tools/admin/project-register.ts index 3ed4a27e..c6e0ab78 100644 --- a/lib/tools/admin/project-register.ts +++ b/lib/tools/admin/project-register.ts @@ -7,6 +7,7 @@ * Replaces the manual steps of running glab/gh label create + editing projects.json. */ import { jsonResult } from "openclaw/plugin-sdk"; +import * as pluginSdk from "openclaw/plugin-sdk"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import fs from "node:fs/promises"; @@ -93,6 +94,11 @@ export function createProjectRegisterTool(ctx: PluginContext) { type: "string", description: "Channel ID — the chat/group ID where this project is managed (e.g. Telegram group ID)", }, + messageThreadId: { + type: "number", + description: + "Optional Telegram forum topic ID (message_thread_id). When provided with channel='telegram', binds the project to this topic instead of the whole chat.", + }, name: { type: "string", description: "Short project name (e.g. 'my-webapp')", @@ -125,6 +131,29 @@ export function createProjectRegisterTool(ctx: PluginContext) { }, async execute(_id: string, params: Record) { + // #region debug log agent log + void fetch("http://127.0.0.1:7466/ingest/5d97a7af-7976-4064-b520-dc7c79f3b068", { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-Debug-Session-Id": "052428", + }, + body: JSON.stringify({ + sessionId: "052428", + runId: "attach-topic-precheck", + hypothesisId: "H1-jsonResult-export-mismatch", + location: "devclaw/lib/tools/admin/project-register.ts:execute", + message: "Verify openclaw/plugin-sdk.jsonResult at runtime", + data: { + jsonResultType: typeof jsonResult, + pluginSdkJsonResultType: typeof (pluginSdk as unknown as { jsonResult?: unknown }).jsonResult, + pluginSdkKeys: Object.keys(pluginSdk as Record).slice(0, 30), + }, + timestamp: Date.now(), + }), + }).catch(() => {}); + // #endregion + const channelId = params.channelId as string; const name = params.name as string; const repo = params.repo as string; @@ -133,6 +162,7 @@ export function createProjectRegisterTool(ctx: PluginContext) { const baseBranch = params.baseBranch as string; const deployBranch = (params.deployBranch as string) ?? baseBranch; const deployUrl = (params.deployUrl as string) ?? ""; + const messageThreadId = params.messageThreadId as number | undefined; const workspaceDir = toolCtx.workspaceDir; if (!workspaceDir) { @@ -208,6 +238,9 @@ export function createProjectRegisterTool(ctx: PluginContext) { channel: channel as "telegram" | "whatsapp" | "discord" | "slack", name: `channel-${existing.channels.length + 1}`, events: ["*"], + ...(messageThreadId != null && channel === "telegram" + ? { messageThreadId } + : {}), }; existing.channels.push(newChannel); if (repoRemote && !existing.repoRemote) { @@ -226,6 +259,9 @@ export function createProjectRegisterTool(ctx: PluginContext) { channel: channel as "telegram" | "whatsapp" | "discord" | "slack", name: "primary", events: ["*"], + ...(messageThreadId != null && channel === "telegram" + ? { messageThreadId } + : {}), }; data.projects[slug] = { diff --git a/lib/tools/admin/project-status.ts b/lib/tools/admin/project-status.ts index 2ff84cd6..6a8bee86 100644 --- a/lib/tools/admin/project-status.ts +++ b/lib/tools/admin/project-status.ts @@ -28,14 +28,25 @@ export function createProjectStatusTool(ctx: PluginContext) { type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the project bound to this topic within the chat.", + }, }, }, async execute(_id: string, params: Record) { const workspaceDir = requireWorkspaceDir(toolCtx); const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; - const { project } = await resolveProject(workspaceDir, channelId); + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const pluginConfig = ctx.pluginConfig; const projectExecution = (pluginConfig?.projectExecution as string) ?? ExecutionMode.PARALLEL; diff --git a/lib/tools/helpers.ts b/lib/tools/helpers.ts index 3e0ab2dc..5cf219a2 100644 --- a/lib/tools/helpers.ts +++ b/lib/tools/helpers.ts @@ -41,9 +41,17 @@ export function resolveChannelId(_ctx: ToolContext, explicitChannelId?: string): export async function resolveProject( workspaceDir: string, channelId: string, + opts?: { channel?: string; accountId?: string; messageThreadId?: number | string | null }, ): Promise<{ data: ProjectsData; project: Project }> { const data = await readProjects(workspaceDir); - const project = getProject(data, channelId); + const project = opts + ? getProject(data, { + channelId, + channel: opts.channel, + accountId: opts.accountId, + messageThreadId: opts.messageThreadId, + }) + : getProject(data, channelId); if (!project) { throw new Error( `No project found for "${channelId}". ` + diff --git a/lib/tools/tasks/task-attach.ts b/lib/tools/tasks/task-attach.ts index de2cdf85..87916fa4 100644 --- a/lib/tools/tasks/task-attach.ts +++ b/lib/tools/tasks/task-attach.ts @@ -38,6 +38,10 @@ Use cases: type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, issueId: { type: "number", description: "Issue ID", @@ -60,11 +64,18 @@ Use cases: async execute(_id: string, params: Record) { const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; const issueId = params.issueId as number; const action = (params.action as string) ?? "list"; const workspaceDir = requireWorkspaceDir(toolCtx); - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); if (action === "list") { const attachments = await listAttachments(workspaceDir, project.slug, issueId); @@ -114,7 +125,8 @@ Use cases: const filename = path.basename(resolvedPath); // Detect mime type - const { detectMime } = await import("openclaw/plugin-sdk"); + // OpenClaw only exports detectMime from some channel submodules in this version. + const { detectMime } = await import("openclaw/plugin-sdk/msteams"); const mimeType = await detectMime({ filePath: resolvedPath, buffer }) ?? "application/octet-stream"; const { provider } = await resolveProvider(project, ctx.runCommand); diff --git a/lib/tools/tasks/task-comment.ts b/lib/tools/tasks/task-comment.ts index 3a7b12da..974a9894 100644 --- a/lib/tools/tasks/task-comment.ts +++ b/lib/tools/tasks/task-comment.ts @@ -41,6 +41,10 @@ Examples: type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, issueId: { type: "number", description: "Issue ID to comment on", @@ -59,6 +63,7 @@ Examples: async execute(_id: string, params: Record) { const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; const issueId = params.issueId as number; const body = params.body as string; const authorRole = (params.authorRole as AuthorRole) ?? undefined; @@ -68,7 +73,13 @@ Examples: throw new Error("Comment body cannot be empty."); } - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider, type: providerType } = await resolveProvider(project, ctx.runCommand); const issue = await provider.getIssue(issueId); diff --git a/lib/tools/tasks/task-create.ts b/lib/tools/tasks/task-create.ts index 28d29f90..b34345ad 100644 --- a/lib/tools/tasks/task-create.ts +++ b/lib/tools/tasks/task-create.ts @@ -32,6 +32,10 @@ export function createTaskCreateTool(ctx: PluginContext) { type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, title: { type: "string", description: "Short, descriptive issue title (e.g., 'Fix login timeout bug')", @@ -54,6 +58,7 @@ export function createTaskCreateTool(ctx: PluginContext) { async execute(_id: string, params: Record) { const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; const title = params.title as string; const description = (params.description as string) ?? ""; const label = INITIAL_LABEL; @@ -61,7 +66,13 @@ export function createTaskCreateTool(ctx: PluginContext) { const pickup = (params.pickup as boolean) ?? false; const workspaceDir = requireWorkspaceDir(toolCtx); - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider, type: providerType } = await resolveProvider(project, ctx.runCommand); const issue = await provider.createIssue(title, description, label, assignees); diff --git a/lib/tools/tasks/task-edit-body.ts b/lib/tools/tasks/task-edit-body.ts index 93bba48b..7f4ef1fa 100644 --- a/lib/tools/tasks/task-edit-body.ts +++ b/lib/tools/tasks/task-edit-body.ts @@ -37,6 +37,10 @@ Examples: type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, issueId: { type: "number", description: "Issue ID to edit", @@ -62,6 +66,7 @@ Examples: async execute(_id: string, params: Record) { const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; const issueId = params.issueId as number; const newTitle = (params.title as string | undefined); const newBody = (params.body as string | undefined); @@ -73,7 +78,13 @@ Examples: throw new Error("At least one of 'title' or 'body' must be provided."); } - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider, type: providerType } = await resolveProvider(project, ctx.runCommand); // Determine editable states from per-project workflow config. diff --git a/lib/tools/tasks/task-list.ts b/lib/tools/tasks/task-list.ts index 5e27aaaa..325660fc 100644 --- a/lib/tools/tasks/task-list.ts +++ b/lib/tools/tasks/task-list.ts @@ -24,6 +24,10 @@ export function createTaskListTool(ctx: PluginContext) { type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, stateType: { type: "string", enum: ["queue", "active", "hold", "terminal", "all"], @@ -47,12 +51,19 @@ export function createTaskListTool(ctx: PluginContext) { async execute(_id: string, params: Record) { const workspaceDir = requireWorkspaceDir(toolCtx); const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; const stateType = params.stateType as string | undefined; const label = params.label as string | undefined; const search = params.search as string | undefined; const limit = (params.limit as number) ?? 20; - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider } = await resolveProvider(project, ctx.runCommand); const workflow = await loadWorkflow(workspaceDir, project.name); diff --git a/lib/tools/tasks/task-owner.ts b/lib/tools/tasks/task-owner.ts index 6aecc1be..23eeeffe 100644 --- a/lib/tools/tasks/task-owner.ts +++ b/lib/tools/tasks/task-owner.ts @@ -35,6 +35,10 @@ export function createTaskOwnerTool(ctx: PluginContext) { type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, issueId: { type: "number", description: @@ -54,7 +58,14 @@ export function createTaskOwnerTool(ctx: PluginContext) { const force = (params.force as boolean) ?? false; const workspaceDir = requireWorkspaceDir(toolCtx); - const { project } = await resolveProject(workspaceDir, channelId); + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider } = await resolveProvider(project, ctx.runCommand); const resolvedConfig = await loadConfig(workspaceDir, project.name); const instanceName = await loadInstanceName( diff --git a/lib/tools/tasks/task-set-level.ts b/lib/tools/tasks/task-set-level.ts index 39fed954..7a7780c3 100644 --- a/lib/tools/tasks/task-set-level.ts +++ b/lib/tools/tasks/task-set-level.ts @@ -30,6 +30,10 @@ Examples: type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, issueId: { type: "number", description: "Issue ID to update", @@ -56,7 +60,14 @@ Examples: throw new Error("'level' is required."); } - const { project } = await resolveProject(workspaceDir, channelId); + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider, type: providerType } = await resolveProvider(project, ctx.runCommand); const resolvedConfig = await loadConfig(workspaceDir, project.name); diff --git a/lib/tools/tasks/task-start.ts b/lib/tools/tasks/task-start.ts index 35b53764..93c4f8b3 100644 --- a/lib/tools/tasks/task-start.ts +++ b/lib/tools/tasks/task-start.ts @@ -47,6 +47,10 @@ Examples: type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, issueId: { type: "number", description: "Issue ID to advance.", @@ -64,7 +68,14 @@ Examples: const levelHint = params.level as string | undefined; const workspaceDir = requireWorkspaceDir(toolCtx); - const { project } = await resolveProject(workspaceDir, channelId); + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider } = await resolveProvider(project, ctx.runCommand); const resolvedConfig = await loadConfig(workspaceDir, project.name); const workflow = resolvedConfig.workflow; diff --git a/lib/tools/tasks/tasks-status.ts b/lib/tools/tasks/tasks-status.ts index 164d32ba..768b2c40 100644 --- a/lib/tools/tasks/tasks-status.ts +++ b/lib/tools/tasks/tasks-status.ts @@ -30,14 +30,25 @@ export function createTasksStatusTool(ctx: PluginContext) { type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the project bound to this topic within the chat.", + }, }, }, async execute(_id: string, params: Record) { const workspaceDir = requireWorkspaceDir(toolCtx); const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; - const { project } = await resolveProject(workspaceDir, channelId); + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider } = await resolveProvider(project, ctx.runCommand); const projectConfig = await loadConfig(workspaceDir, project.name); diff --git a/lib/tools/worker/work-finish.ts b/lib/tools/worker/work-finish.ts index ac39efdc..0da66fde 100644 --- a/lib/tools/worker/work-finish.ts +++ b/lib/tools/worker/work-finish.ts @@ -185,6 +185,7 @@ export function createWorkFinishTool(ctx: PluginContext) { required: ["channelId", "role", "result"], properties: { channelId: { type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from." }, + messageThreadId: { type: "number", description: "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the project bound to this topic within the chat." }, role: { type: "string", enum: getAllRoleIds(), description: "Worker role" }, result: { type: "string", enum: ["done", "pass", "fail", "refine", "blocked", "approve", "reject"], description: "Completion result" }, summary: { type: "string", description: "Brief summary" }, @@ -209,6 +210,7 @@ export function createWorkFinishTool(ctx: PluginContext) { const role = params.role as string; const result = params.result as string; const channelId = resolveChannelId(toolCtx, params.channelId as string | undefined); + const messageThreadId = params.messageThreadId as number | undefined; const summary = params.summary as string | undefined; const prUrl = params.prUrl as string | undefined; const createdTasks = params.createdTasks as Array<{ id: number; title: string; url: string }> | undefined; @@ -221,7 +223,13 @@ export function createWorkFinishTool(ctx: PluginContext) { } // Resolve project + worker - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const roleWorker = getRoleWorker(project, role); // Find the first active slot across all levels that matches this session. From 501cba7cf5b350cf1bcb82e8eb832e225f327bcb Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 21 Mar 2026 04:14:52 +0400 Subject: [PATCH 6/6] feat: integrate notifyTarget for enhanced Telegram routing This update introduces the `notifyTarget` parameter in the dispatch and agent communication processes, allowing for more precise routing of messages to specific Telegram channels and topics. Key changes include: - Addition of `notifyTarget` in the `dispatchTask` and `sendToAgent` functions. - Implementation of `applyNotifyRoutingToGatewayParams` to handle the new routing logic. - Updates to project migration logic to ensure legacy topic fields are correctly normalized. These enhancements improve the flexibility of message delivery within Telegram environments, particularly for forum topics. --- lib/dispatch/index.ts | 1 + lib/dispatch/session.ts | 52 +++++++++++++++- lib/json-result.ts | 14 +++++ lib/projects/io.ts | 21 +------ lib/projects/migrations.ts | 17 ++--- lib/projects/projects.test.ts | 82 +++++++++++++++++++++++++ lib/services/heartbeat/health.ts | 5 ++ lib/tools/admin/autoconfigure-models.ts | 2 +- lib/tools/admin/channel-link.ts | 2 +- lib/tools/admin/channel-list.ts | 2 +- lib/tools/admin/channel-unlink.ts | 2 +- lib/tools/admin/config-diff.ts | 2 +- lib/tools/admin/config-reset.ts | 2 +- lib/tools/admin/config.ts | 2 +- lib/tools/admin/health.ts | 35 +++++++---- lib/tools/admin/onboard.ts | 2 +- lib/tools/admin/project-register.ts | 26 +------- lib/tools/admin/project-status.ts | 2 +- lib/tools/admin/setup.ts | 2 +- lib/tools/admin/sync-labels.ts | 22 ++++++- lib/tools/admin/workflow-guide.ts | 2 +- lib/tools/tasks/research-task.ts | 16 ++++- lib/tools/tasks/task-attach.ts | 2 +- lib/tools/tasks/task-comment.ts | 2 +- lib/tools/tasks/task-create.ts | 2 +- lib/tools/tasks/task-edit-body.ts | 2 +- lib/tools/tasks/task-list.ts | 2 +- lib/tools/tasks/task-owner.ts | 2 +- lib/tools/tasks/task-set-level.ts | 2 +- lib/tools/tasks/task-start.ts | 2 +- lib/tools/tasks/tasks-status.ts | 2 +- lib/tools/worker/work-finish.ts | 2 +- 32 files changed, 238 insertions(+), 95 deletions(-) create mode 100644 lib/json-result.ts diff --git a/lib/dispatch/index.ts b/lib/dispatch/index.ts index fad8403f..25e3cf36 100644 --- a/lib/dispatch/index.ts +++ b/lib/dispatch/index.ts @@ -299,6 +299,7 @@ export async function dispatchTask( dispatchTimeoutMs: timeouts.dispatchMs, extraSystemPrompt: roleInstructions.trim() || undefined, runCommand: rc, + notifyTarget, }); // Step 5: Update worker state diff --git a/lib/dispatch/session.ts b/lib/dispatch/session.ts index 68ce616d..04384146 100644 --- a/lib/dispatch/session.ts +++ b/lib/dispatch/session.ts @@ -82,12 +82,56 @@ export function ensureSessionFireAndForget(sessionKey: string, model: string, wo }); } +/** Same shape as `resolveNotifyChannel()` — used to pass Telegram chat/topic into the gateway agent run. */ +export type NotifyRoutingTarget = { + channelId: string; + channel: string; + accountId?: string; + messageThreadId?: number; +}; + +function applyNotifyRoutingToGatewayParams( + params: Record, + target: NotifyRoutingTarget | undefined, +): void { + if (!target?.channelId) { + return; + } + params.to = target.channelId; + params.channel = target.channel; + if (target.accountId) { + params.accountId = target.accountId; + } + if (target.messageThreadId != null && Number.isFinite(Number(target.messageThreadId))) { + params.threadId = String(Math.trunc(Number(target.messageThreadId))); + } +} + export function sendToAgent( sessionKey: string, taskMessage: string, - opts: { agentId?: string; projectName: string; issueId: number; role: string; level?: string; slotIndex?: number; fromLabel?: string; orchestratorSessionKey?: string; workspaceDir: string; dispatchTimeoutMs?: number; extraSystemPrompt?: string; runCommand: RunCommand }, + opts: { + agentId?: string; + projectName: string; + issueId: number; + role: string; + level?: string; + slotIndex?: number; + fromLabel?: string; + orchestratorSessionKey?: string; + workspaceDir: string; + dispatchTimeoutMs?: number; + extraSystemPrompt?: string; + runCommand: RunCommand; + /** + * When set (e.g. from `resolveNotifyChannel`), forwarded to the gateway `agent` call as + * `to`, `channel`, `accountId`, and `threadId` so plugin tools get `messageThreadId` injection + * (Telegram forum topics) on the worker run. + */ + notifyTarget?: NotifyRoutingTarget; + }, ): void { const rc = opts.runCommand; - const gatewayParams = JSON.stringify({ + const gatewayParamsRecord: Record = { idempotencyKey: `devclaw-${opts.projectName}-${opts.issueId}-${opts.role}-${opts.level ?? "unknown"}-${opts.slotIndex ?? 0}-${opts.fromLabel ?? "unknown"}-${sessionKey}`, agentId: opts.agentId ?? "devclaw", sessionKey, @@ -96,7 +140,9 @@ export function sendToAgent( lane: "subagent", ...(opts.orchestratorSessionKey ? { spawnedBy: opts.orchestratorSessionKey } : {}), ...(opts.extraSystemPrompt ? { extraSystemPrompt: opts.extraSystemPrompt } : {}), - }); + }; + applyNotifyRoutingToGatewayParams(gatewayParamsRecord, opts.notifyTarget); + const gatewayParams = JSON.stringify(gatewayParamsRecord); // Fire-and-forget: long-running agent turn, don't await rc( ["openclaw", "gateway", "call", "agent", "--params", gatewayParams, "--expect-final", "--json"], diff --git a/lib/json-result.ts b/lib/json-result.ts new file mode 100644 index 00000000..5696d604 --- /dev/null +++ b/lib/json-result.ts @@ -0,0 +1,14 @@ +/** + * OpenClaw tool success shape — mirrors `jsonResult` from `openclaw/plugin-sdk`. + * Implemented locally so DevClaw tools work when the host resolves `openclaw/plugin-sdk` + * in a way that breaks named imports (e.g. interop / bundling). + */ +export function jsonResult(payload: unknown): { + content: Array<{ type: "text"; text: string }>; + details: unknown; +} { + return { + content: [{ type: "text", text: JSON.stringify(payload, null, 2) }], + details: payload, + }; +} diff --git a/lib/projects/io.ts b/lib/projects/io.ts index 48d456e2..42ba4afd 100644 --- a/lib/projects/io.ts +++ b/lib/projects/io.ts @@ -7,7 +7,7 @@ import { homedir } from "node:os"; import { migrateProject } from "./migrations.js"; import { ensureWorkspaceMigrated, DATA_DIR } from "../setup/migrate-layout.js"; import { isLegacySchema, migrateLegacySchema } from "./schema-migration.js"; -import type { ProjectsData, Project, Channel } from "./types.js"; +import type { ProjectsData, Project } from "./types.js"; import { emptySlot } from "./slots.js"; @@ -116,22 +116,6 @@ export function resolveProjectChannelScope(opts: { return `${opts.channel}:${account}:${opts.channelId}:topic:${topic}`; } -/** - * Normalize a channel's topic-related fields for resolution. - * - For Telegram, map legacy topicId into messageThreadId when needed. - * - Leaves non-Telegram channels unchanged (they are effectively root-scope). - */ -function normalizeChannelTopic(ch: Channel): Channel { - if (ch.channel !== "telegram") { - return ch; - } - const legacy = ch as Channel & { topicId?: number }; - if (ch.messageThreadId == null && legacy.topicId != null) { - ch.messageThreadId = legacy.topicId; - } - return ch; -} - /** * Resolve a project by slug or channel scope (for backward compatibility). * When given a bare string, treats it as slug or channelId (legacy behavior). @@ -177,8 +161,7 @@ export function resolveProjectSlug( let fallbackSlug: string | undefined; for (const [slug, project] of Object.entries(data.projects)) { - for (const rawCh of project.channels) { - const ch = normalizeChannelTopic(rawCh); + for (const ch of project.channels) { const scopeKey = resolveProjectChannelScope({ channel: ch.channel, channelId: ch.channelId, diff --git a/lib/projects/migrations.ts b/lib/projects/migrations.ts index 7d36dff6..ced82bba 100644 --- a/lib/projects/migrations.ts +++ b/lib/projects/migrations.ts @@ -195,6 +195,7 @@ function parseWorkerState(worker: Record, role: string): RoleWo * 3. Old level names in worker state * 4. Old slot-based format → per-level format * 5. Missing channel field defaults to "telegram" + * 6. Telegram: legacy topicId → messageThreadId; topicId removed from stored shape */ /** * Returns true if any migration was applied (caller should persist). @@ -230,22 +231,16 @@ export function migrateProject(project: Project): boolean { project.workers = {}; } - // Normalize channel topic fields for Telegram channels: - // - Migrate legacy groupId -> channelId (handled below) - // - Migrate legacy topicId -> messageThreadId when messageThreadId is missing + // Telegram channels: legacy topicId → messageThreadId; drop topicId (canonical field only) if (project.channels) { for (const ch of project.channels) { const rawCh = ch as unknown as Record & Channel; - - // Normalize legacy Telegram topic field: topicId -> messageThreadId - if ( - rawCh.channel === "telegram" && - rawCh.topicId != null && - rawCh.messageThreadId == null - ) { + if (rawCh.channel !== "telegram" || rawCh.topicId == null) continue; + if (rawCh.messageThreadId == null) { rawCh.messageThreadId = Number(rawCh.topicId); - changed = true; } + delete rawCh.topicId; + changed = true; } } diff --git a/lib/projects/projects.test.ts b/lib/projects/projects.test.ts index bc8735ed..fddc2999 100644 --- a/lib/projects/projects.test.ts +++ b/lib/projects/projects.test.ts @@ -17,6 +17,7 @@ import { countActiveSlots, reconcileSlots, writeProjects, + resolveProjectSlug, type ProjectsData, type RoleWorkerState, } from "./index.js"; @@ -260,6 +261,87 @@ describe("readProjects migration", () => { await fs.rm(tmpDir, { recursive: true }); }); + + it("should migrate legacy topicId to messageThreadId and strip topicId from disk", async () => { + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "devclaw-proj-")); + const dataDir = path.join(tmpDir, "devclaw"); + await fs.mkdir(dataDir, { recursive: true }); + + const raw = { + projects: { + p1: { + slug: "p1", + name: "P1", + repo: "~/p1", + groupName: "P1", + deployUrl: "", + baseBranch: "main", + deployBranch: "main", + channels: [ + { + channelId: "-100", + channel: "telegram", + name: "primary", + events: ["*"], + topicId: 42, + }, + ], + workers: { + developer: emptyRoleWorkerState({ junior: 1 }), + tester: emptyRoleWorkerState({ junior: 1 }), + architect: emptyRoleWorkerState({ senior: 1 }), + }, + }, + p2: { + slug: "p2", + name: "P2", + repo: "~/p2", + groupName: "P2", + deployUrl: "", + baseBranch: "main", + deployBranch: "main", + channels: [ + { + channelId: "-100", + channel: "telegram", + name: "primary", + events: ["*"], + topicId: 176, + messageThreadId: 176, + }, + ], + workers: { + developer: emptyRoleWorkerState({ junior: 1 }), + tester: emptyRoleWorkerState({ junior: 1 }), + architect: emptyRoleWorkerState({ senior: 1 }), + }, + }, + }, + }; + await fs.writeFile(path.join(dataDir, "projects.json"), JSON.stringify(raw), "utf-8"); + + const data = await readProjects(tmpDir); + const ch1 = data.projects.p1.channels[0]!; + assert.strictEqual(ch1.messageThreadId, 42); + assert.strictEqual((ch1 as { topicId?: unknown }).topicId, undefined); + + const ch2 = data.projects.p2.channels[0]!; + assert.strictEqual(ch2.messageThreadId, 176); + assert.strictEqual((ch2 as { topicId?: unknown }).topicId, undefined); + + const disk = JSON.parse(await fs.readFile(path.join(dataDir, "projects.json"), "utf-8")) as { + projects: { p1: { channels: Array<{ topicId?: number }> }; p2: { channels: Array<{ topicId?: number }> } }; + }; + assert.strictEqual(disk.projects.p1.channels[0]!.topicId, undefined); + assert.strictEqual(disk.projects.p2.channels[0]!.topicId, undefined); + + assert.strictEqual( + resolveProjectSlug(data, { channelId: "-100", channel: "telegram", messageThreadId: 42 }), + "p1", + ); + + await fs.rm(tmpDir, { recursive: true }); + }); }); describe("per-level slot helpers", () => { diff --git a/lib/services/heartbeat/health.ts b/lib/services/heartbeat/health.ts index 253dbea4..811d395b 100644 --- a/lib/services/heartbeat/health.ts +++ b/lib/services/heartbeat/health.ts @@ -45,6 +45,7 @@ import { getCurrentStateLabel, isOwnedByOrUnclaimed, isFeedbackState, + resolveNotifyChannel, type WorkflowConfig, type Role, } from "../../workflow/index.js"; @@ -456,6 +457,9 @@ export async function checkWorkerHealth(opts: { await deactivateSlot(); } else { // Task arrived but worker stalled → nudge the session + const notifyTarget = issue + ? resolveNotifyChannel(issue.labels, project.channels) + : undefined; sendToAgent(sessionKey, NUDGE_MESSAGE, { agentId: opts.agentId, projectName: project.name, @@ -465,6 +469,7 @@ export async function checkWorkerHealth(opts: { slotIndex, workspaceDir, runCommand: opts.runCommand, + notifyTarget, }); fix.nudgeSent = true; } diff --git a/lib/tools/admin/autoconfigure-models.ts b/lib/tools/admin/autoconfigure-models.ts index c4bada45..8445b8d8 100644 --- a/lib/tools/admin/autoconfigure-models.ts +++ b/lib/tools/admin/autoconfigure-models.ts @@ -3,7 +3,7 @@ * * Queries available authenticated models and intelligently assigns them to DevClaw roles. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext, RunCommand } from "../../context.js"; import { diff --git a/lib/tools/admin/channel-link.ts b/lib/tools/admin/channel-link.ts index 555594c8..20c5fba3 100644 --- a/lib/tools/admin/channel-link.ts +++ b/lib/tools/admin/channel-link.ts @@ -6,7 +6,7 @@ * (auto-detach). This is the primary way to switch which project a chat * controls. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { readProjects, writeProjects, type Channel } from "../../projects/index.js"; diff --git a/lib/tools/admin/channel-list.ts b/lib/tools/admin/channel-list.ts index a4864dda..3e0dc895 100644 --- a/lib/tools/admin/channel-list.ts +++ b/lib/tools/admin/channel-list.ts @@ -4,7 +4,7 @@ * Shows registered channels with their type, ID, name, and event subscriptions. * Can list channels for a specific project or all projects. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { readProjects } from "../../projects/index.js"; diff --git a/lib/tools/admin/channel-unlink.ts b/lib/tools/admin/channel-unlink.ts index e08fcbb7..59b2da05 100644 --- a/lib/tools/admin/channel-unlink.ts +++ b/lib/tools/admin/channel-unlink.ts @@ -5,7 +5,7 @@ * exists and prevents removing the last channel from a project (projects must * have at least one notification endpoint). */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { readProjects, writeProjects } from "../../projects/index.js"; diff --git a/lib/tools/admin/config-diff.ts b/lib/tools/admin/config-diff.ts index 33afa135..e19bbc85 100644 --- a/lib/tools/admin/config-diff.ts +++ b/lib/tools/admin/config-diff.ts @@ -6,7 +6,7 @@ */ import fs from "node:fs/promises"; import path from "node:path"; -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { requireWorkspaceDir } from "../helpers.js"; diff --git a/lib/tools/admin/config-reset.ts b/lib/tools/admin/config-reset.ts index 4cc0966f..5157c78a 100644 --- a/lib/tools/admin/config-reset.ts +++ b/lib/tools/admin/config-reset.ts @@ -6,7 +6,7 @@ */ import fs from "node:fs/promises"; import path from "node:path"; -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { requireWorkspaceDir } from "../helpers.js"; diff --git a/lib/tools/admin/config.ts b/lib/tools/admin/config.ts index 4e5284e2..0d3c1ba0 100644 --- a/lib/tools/admin/config.ts +++ b/lib/tools/admin/config.ts @@ -8,7 +8,7 @@ */ import fs from "node:fs/promises"; import path from "node:path"; -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { writeAllDefaults, backupAndWrite, fileExists } from "../../setup/workspace.js"; diff --git a/lib/tools/admin/health.ts b/lib/tools/admin/health.ts index 77e348f9..ce0e5da5 100644 --- a/lib/tools/admin/health.ts +++ b/lib/tools/admin/health.ts @@ -12,7 +12,7 @@ * * Read-only by default (surfaces issues). Pass fix=true to apply fixes. */ -import { jsonResult } from "openclaw/plugin-sdk/channel-runtime"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { readProjects, getProject } from "../../projects/index.js"; @@ -24,11 +24,19 @@ export function createHealthTool(ctx: PluginContext) { return (toolCtx: ToolContext) => ({ name: "health", label: "Health", - description: `Scan worker health across projects. Detects zombies, stale workers, orphaned state. Pass fix=true to auto-fix. Context-aware: auto-filters in group chats.`, + description: `Scan worker health across projects. Detects zombies, stale workers, orphaned state. Pass fix=true to auto-fix. When channelId is set, pass messageThreadId in Telegram forum topics so the correct project is selected.`, parameters: { type: "object", properties: { - channelId: { type: "string", description: "Channel ID identifying the project. Omit for all." }, + channelId: { + type: "string", + description: "Project slug or channel ID. Omit to scan all registered projects.", + }, + messageThreadId: { + type: "number", + description: + "Optional Telegram forum topic ID (message_thread_id). When provided with a channel ID, resolves the topic-bound project within the chat.", + }, fix: { type: "boolean", description: "Apply fixes for detected issues. Default: false (read-only)." }, }, }, @@ -38,19 +46,24 @@ export function createHealthTool(ctx: PluginContext) { const fix = (params.fix as boolean) ?? false; const slugOrChannelId = params.channelId as string | undefined; + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; const data = await readProjects(workspaceDir); - // Resolve slug from slugOrChannelId let slugs = Object.keys(data.projects); if (slugOrChannelId) { - // Use legacy resolution by channelId or slug (health is not topic-scoped; - // it scans the full project), so we intentionally pass the bare string. - const project = getProject(data, slugOrChannelId); - const slug = project ? - (data.projects[slugOrChannelId] ? slugOrChannelId : - Object.keys(data.projects).find(s => data.projects[s].channels.some(ch => ch.channelId === slugOrChannelId))) - : undefined; + const project = + data.projects[slugOrChannelId] !== undefined + ? data.projects[slugOrChannelId] + : getProject(data, { + channelId: slugOrChannelId, + channel: channelType, + accountId, + messageThreadId, + }); + const slug = project?.slug; slugs = slug ? [slug] : []; } diff --git a/lib/tools/admin/onboard.ts b/lib/tools/admin/onboard.ts index 8ac3dad8..f16f99e1 100644 --- a/lib/tools/admin/onboard.ts +++ b/lib/tools/admin/onboard.ts @@ -3,7 +3,7 @@ * * Returns step-by-step guidance. Call this before setup. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { isPluginConfigured, hasWorkspaceFiles, buildOnboardToolContext, buildReconfigContext } from "../../setup/onboarding.js"; diff --git a/lib/tools/admin/project-register.ts b/lib/tools/admin/project-register.ts index c6e0ab78..7c8c4e05 100644 --- a/lib/tools/admin/project-register.ts +++ b/lib/tools/admin/project-register.ts @@ -6,8 +6,7 @@ * * Replaces the manual steps of running glab/gh label create + editing projects.json. */ -import { jsonResult } from "openclaw/plugin-sdk"; -import * as pluginSdk from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import fs from "node:fs/promises"; @@ -131,29 +130,6 @@ export function createProjectRegisterTool(ctx: PluginContext) { }, async execute(_id: string, params: Record) { - // #region debug log agent log - void fetch("http://127.0.0.1:7466/ingest/5d97a7af-7976-4064-b520-dc7c79f3b068", { - method: "POST", - headers: { - "Content-Type": "application/json", - "X-Debug-Session-Id": "052428", - }, - body: JSON.stringify({ - sessionId: "052428", - runId: "attach-topic-precheck", - hypothesisId: "H1-jsonResult-export-mismatch", - location: "devclaw/lib/tools/admin/project-register.ts:execute", - message: "Verify openclaw/plugin-sdk.jsonResult at runtime", - data: { - jsonResultType: typeof jsonResult, - pluginSdkJsonResultType: typeof (pluginSdk as unknown as { jsonResult?: unknown }).jsonResult, - pluginSdkKeys: Object.keys(pluginSdk as Record).slice(0, 30), - }, - timestamp: Date.now(), - }), - }).catch(() => {}); - // #endregion - const channelId = params.channelId as string; const name = params.name as string; const repo = params.repo as string; diff --git a/lib/tools/admin/project-status.ts b/lib/tools/admin/project-status.ts index 6a8bee86..16631e02 100644 --- a/lib/tools/admin/project-status.ts +++ b/lib/tools/admin/project-status.ts @@ -5,7 +5,7 @@ * workflow config, and execution settings. No issue-tracker API calls. * Use `tasks_status` for live issue counts. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { requireWorkspaceDir, resolveChannelId, resolveProject } from "../helpers.js"; diff --git a/lib/tools/admin/setup.ts b/lib/tools/admin/setup.ts index a29be596..a45b7225 100644 --- a/lib/tools/admin/setup.ts +++ b/lib/tools/admin/setup.ts @@ -4,7 +4,7 @@ * Creates agent, configures model levels, writes workspace files. * Thin wrapper around lib/setup/. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { runSetup, type SetupOpts } from "../../setup/index.js"; diff --git a/lib/tools/admin/sync-labels.ts b/lib/tools/admin/sync-labels.ts index 27e5786c..7b189940 100644 --- a/lib/tools/admin/sync-labels.ts +++ b/lib/tools/admin/sync-labels.ts @@ -8,7 +8,7 @@ * Calls provider.ensureLabel() directly instead of provider.ensureAllStateLabels() * so that custom workflow states from workspace/project overrides are included. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { requireWorkspaceDir } from "../helpers.js"; @@ -36,7 +36,12 @@ export function createSyncLabelsTool(ctx: PluginContext) { channelId: { type: "string", description: - "Channel ID identifying the project. Omit to sync all registered projects.", + "Project slug or channel ID. Omit to sync all registered projects.", + }, + messageThreadId: { + type: "number", + description: + "Optional Telegram forum topic ID (message_thread_id). When provided with a channel ID, resolves the topic-bound project within the chat.", }, }, }, @@ -44,12 +49,23 @@ export function createSyncLabelsTool(ctx: PluginContext) { async execute(_id: string, params: Record) { const workspaceDir = requireWorkspaceDir(toolCtx); const targetChannelId = params.channelId as string | undefined; + const messageThreadId = params.messageThreadId as number | undefined; + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; const data = await readProjects(workspaceDir); let slugs: string[]; if (targetChannelId) { - const project = getProject(data, targetChannelId); + let project = + data.projects[targetChannelId] !== undefined + ? data.projects[targetChannelId] + : getProject(data, { + channelId: targetChannelId, + channel: channelType, + accountId, + messageThreadId, + }); if (!project) { throw new Error( `No project found for "${targetChannelId}". Register a new project with project_register first.`, diff --git a/lib/tools/admin/workflow-guide.ts b/lib/tools/admin/workflow-guide.ts index 33cb4df8..053cabec 100644 --- a/lib/tools/admin/workflow-guide.ts +++ b/lib/tools/admin/workflow-guide.ts @@ -8,7 +8,7 @@ * * No parameters, no side effects — pure documentation. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { requireWorkspaceDir } from "../helpers.js"; diff --git a/lib/tools/tasks/research-task.ts b/lib/tools/tasks/research-task.ts index 403202e0..1e10d429 100644 --- a/lib/tools/tasks/research-task.ts +++ b/lib/tools/tasks/research-task.ts @@ -12,7 +12,7 @@ * → architect calls work_finish(result="done") → "Researching" → "Done" (issue closed) * → operator reviews created tasks in Planning, moves to "To Do" when ready */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import type { StateLabel } from "../../providers/provider.js"; @@ -60,6 +60,11 @@ Example: type: "string", description: "YOUR chat/group ID — the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from.", }, + messageThreadId: { + type: "number", + description: + "Optional Telegram forum topic ID for this project (message_thread_id). When provided, resolves the topic-bound project within the chat.", + }, title: { type: "string", description: "Research title (e.g., 'Research: Session persistence strategy')", @@ -92,12 +97,19 @@ Example: const focusAreas = (params.focusAreas as string[]) ?? []; const complexity = (params.complexity as "simple" | "medium" | "complex") ?? "medium"; const dryRun = (params.dryRun as boolean) ?? false; + const messageThreadId = params.messageThreadId as number | undefined; const workspaceDir = requireWorkspaceDir(toolCtx); if (!title) throw new Error("title is required"); if (!description) throw new Error("description is required — provide detailed background context for the architect"); - const { project } = await resolveProject(workspaceDir, channelId); + const channelType = (toolCtx.messageChannel as string | undefined) ?? "telegram"; + const accountId = toolCtx.agentAccountId as string | undefined; + const { project } = await resolveProject(workspaceDir, channelId, { + channel: channelType, + accountId, + messageThreadId, + }); const { provider } = await resolveProvider(project, ctx.runCommand); const pluginConfig = ctx.pluginConfig; const role = "architect"; diff --git a/lib/tools/tasks/task-attach.ts b/lib/tools/tasks/task-attach.ts index 87916fa4..d6a3ec74 100644 --- a/lib/tools/tasks/task-attach.ts +++ b/lib/tools/tasks/task-attach.ts @@ -6,7 +6,7 @@ * - Manually attach a local file to an issue * - View attachment metadata and local paths */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/task-comment.ts b/lib/tools/tasks/task-comment.ts index 974a9894..ab2b5032 100644 --- a/lib/tools/tasks/task-comment.ts +++ b/lib/tools/tasks/task-comment.ts @@ -6,7 +6,7 @@ * - Developer worker posts implementation notes * - Orchestrator adds summary comments */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/task-create.ts b/lib/tools/tasks/task-create.ts index b34345ad..6fe8087b 100644 --- a/lib/tools/tasks/task-create.ts +++ b/lib/tools/tasks/task-create.ts @@ -9,7 +9,7 @@ * - A sub-agent finds a bug and needs to file a follow-up issue * - Breaking down an epic into smaller tasks */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/task-edit-body.ts b/lib/tools/tasks/task-edit-body.ts index 7f4ef1fa..b69c31fd 100644 --- a/lib/tools/tasks/task-edit-body.ts +++ b/lib/tools/tasks/task-edit-body.ts @@ -8,7 +8,7 @@ * DevClaw adds an explicit audit entry with who, when, and what changed. * Optionally posts an auto-comment on the issue for traceability. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/task-list.ts b/lib/tools/tasks/task-list.ts index 325660fc..9bb9c2c3 100644 --- a/lib/tools/tasks/task-list.ts +++ b/lib/tools/tasks/task-list.ts @@ -4,7 +4,7 @@ * Lists issues grouped by state label with optional filtering by state type, * specific label, or text search. Supports terminal (closed) issues. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/task-owner.ts b/lib/tools/tasks/task-owner.ts index 23eeeffe..bfb3be2d 100644 --- a/lib/tools/tasks/task-owner.ts +++ b/lib/tools/tasks/task-owner.ts @@ -5,7 +5,7 @@ * owns them for queue scanning and dispatch. Supports claiming a * single issue or all unclaimed queued issues for a project. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { requireWorkspaceDir, resolveChannelId, resolveProject, resolveProvider } from "../helpers.js"; diff --git a/lib/tools/tasks/task-set-level.ts b/lib/tools/tasks/task-set-level.ts index 7a7780c3..65250fc8 100644 --- a/lib/tools/tasks/task-set-level.ts +++ b/lib/tools/tasks/task-set-level.ts @@ -5,7 +5,7 @@ * applied as a role:level label and respected by the heartbeat when the * issue is later advanced via task_start. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/task-start.ts b/lib/tools/tasks/task-start.ts index 93c4f8b3..b9d198e9 100644 --- a/lib/tools/tasks/task-start.ts +++ b/lib/tools/tasks/task-start.ts @@ -8,7 +8,7 @@ * The heartbeat is the sole dispatcher — this tool only places issues in * queues, never dispatches workers directly. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { PluginContext } from "../../context.js"; import type { ToolContext } from "../../types.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/tasks/tasks-status.ts b/lib/tools/tasks/tasks-status.ts index 768b2c40..4c4b8c78 100644 --- a/lib/tools/tasks/tasks-status.ts +++ b/lib/tools/tasks/tasks-status.ts @@ -4,7 +4,7 @@ * Fetches all non-terminal issues grouped by state type (hold, active, queue). * Use `project_status` for instant local info, this tool for live issue data. */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import type { ToolContext } from "../../types.js"; import type { PluginContext } from "../../context.js"; import { log as auditLog } from "../../audit.js"; diff --git a/lib/tools/worker/work-finish.ts b/lib/tools/worker/work-finish.ts index 0da66fde..a3789ae0 100644 --- a/lib/tools/worker/work-finish.ts +++ b/lib/tools/worker/work-finish.ts @@ -7,7 +7,7 @@ * All roles (including architect) use the standard pipeline via executeCompletion. * Architect workflow: Researching → Done (done, closes issue), Researching → Refining (blocked). */ -import { jsonResult } from "openclaw/plugin-sdk"; +import { jsonResult } from "../../json-result.js"; import { readFile } from "node:fs/promises"; import { join } from "node:path"; import type { ToolContext } from "../../types.js";