From e49f7255a01d27c9827e7465abe6984f0e0b4eb4 Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 14:15:38 -0500 Subject: [PATCH 1/8] fix(integrations): commit OpenClaw turns through commitTurn OpenClaw 2026.10 and later runs a context engine for durable turns only when the engine declares current-turn transcript semantics and implements commitTurn(). The Basic Memory engine did neither, so every turn degraded to OpenClaw's legacy engine and automatic capture never ran (#1880). - Declare transcriptSemantics (before-current-turn-entry-v1, atomic-idempotent-v1). The fence holds because assemble() passes the host's messages through unchanged and the engine stores no transcript. - Add commitTurn(), which captures the turn keyed by the host's advancementKey. Each entry carries a hashed marker, and a key already in today's or yesterday's conversation note returns "duplicate". Captures are serialized so the check and the append cannot interleave. Errors now propagate so the host keeps the turn queued and retries it. - Keep afterTurn() for older hosts. OpenClaw skips afterTurn() for turns it routes through commitTurn(), so no turn is written twice. - Build against openclaw ^2026.10.6. The bare "openclaw/plugin-sdk" export is gone, so derive ContextEngine types from OpenClawPluginApi.registerContextEngine in plugin-sdk/core. - README: install commands that work on 2026.10 (`plugins enable --slot` no longer exists), and state that capture and recall need the contextEngine slot; the memory slot alone captures nothing. Verified live on OpenClaw 2026.10.9 with a tool-free turn: no "degraded to legacy" warning, and the turn landed in the conversation note. Four turns across four sessions and one gateway restart produced four entries with four distinct markers. Closes #1880 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/README.md | 18 +- integrations/openclaw/bm-client.test.ts | 140 ++++ integrations/openclaw/bm-client.ts | 83 +- integrations/openclaw/bun.lock | 768 +++++++++++++----- .../basic-memory-context-engine.test.ts | 118 ++- .../basic-memory-context-engine.ts | 63 +- integrations/openclaw/context-engine/types.ts | 21 + integrations/openclaw/package.json | 6 +- 8 files changed, 1002 insertions(+), 215 deletions(-) create mode 100644 integrations/openclaw/context-engine/types.ts diff --git a/integrations/openclaw/README.md b/integrations/openclaw/README.md index 8b1ff1a00..305fc22f2 100644 --- a/integrations/openclaw/README.md +++ b/integrations/openclaw/README.md @@ -53,10 +53,18 @@ Then install the plugin: ```bash openclaw plugins install @basicmemory/openclaw-basic-memory -openclaw plugins enable openclaw-basic-memory --slot memory +openclaw config set plugins.slots.memory openclaw-basic-memory +openclaw config set plugins.slots.contextEngine openclaw-basic-memory openclaw gateway restart ``` +The plugin fills two OpenClaw slots, and each one does a different job: + +- **`memory`** provides the `memory_search` and `memory_get` tools. +- **`contextEngine`** runs automatic recall at session start and automatic conversation capture after each turn. **Without this slot, nothing is captured or recalled automatically**; the agent only remembers what it saves with an explicit tool call. + +Tested with OpenClaw 2026.10.9. OpenClaw 2026.10 and later require context engines to commit turns through `commitTurn`, which this plugin implements; older plugin versions are degraded to OpenClaw's legacy engine on those hosts and capture nothing. + That's it. The plugin auto-installs the `bm` CLI on first startup if it's not already on your PATH. See [SECURITY.md](./SECURITY.md) for details on how this works. Verify: @@ -80,7 +88,8 @@ openclaw plugins doctor } }, slots: { - memory: "openclaw-basic-memory" + memory: "openclaw-basic-memory", + contextEngine: "openclaw-basic-memory" } } } @@ -108,7 +117,8 @@ This uses sensible defaults: auto-generated project name, maps to your workspace } }, slots: { - memory: "openclaw-basic-memory" + memory: "openclaw-basic-memory", + contextEngine: "openclaw-basic-memory" } } } @@ -145,7 +155,7 @@ On each session start, the plugin loads active tasks and recently modified notes ### Auto-capture -After each conversation turn, the plugin records the exchange as a timestamped entry in a daily note. This builds a searchable history of everything your agent has discussed. +After each conversation turn, the plugin records the exchange as a timestamped entry in a daily note. This builds a searchable history of everything your agent has discussed. Capture requires the `contextEngine` slot. Each entry carries a hidden `` marker so a turn OpenClaw retries after a crash is recorded only once. ### Persistent connection diff --git a/integrations/openclaw/bm-client.test.ts b/integrations/openclaw/bm-client.test.ts index 0f00995b6..afb992422 100644 --- a/integrations/openclaw/bm-client.test.ts +++ b/integrations/openclaw/bm-client.test.ts @@ -943,6 +943,146 @@ describe("BmClient MCP behavior", () => { expect(args[4]).toBeUndefined() // overwrite }) + describe("indexConversation with a turn key", () => { + // In-memory stand-in for the conversation notes so the duplicate check, + // append, and create paths run against shared state. + let notes: Map + const notFound = () => + new BmToolError( + "bm_read", + JSON.stringify({ error: "NOT_FOUND", message: "Missing note" }), + ) + const today = () => + `conversations-${new Date().toISOString().split("T")[0]}` + + beforeEach(() => { + notes = new Map() + ;(client as any).readNote = jest.fn(async (identifier: string) => { + const content = notes.get(identifier) + if (content === undefined) throw notFound() + return { title: identifier, permalink: identifier, content } + }) + ;(client as any).editNote = jest.fn( + async (identifier: string, _op: string, entry: string) => { + const content = notes.get(identifier) + if (content === undefined) throw notFound() + notes.set(identifier, `${content}\n${entry}`) + }, + ) + ;(client as any).writeNote = jest.fn( + async (title: string, content: string) => { + notes.set(title, content) + }, + ) + }) + + it("records a marker and reports the first write as committed", async () => { + const status = await client.indexConversation( + "user message long enough", + "assistant reply long enough", + { turnKey: "advance-1" }, + ) + + expect(status).toBe("committed") + expect(notes.get(today())).toMatch(//) + }) + + it("reports a retried key as a duplicate without writing again", async () => { + await client.indexConversation("first user", "first reply", { + turnKey: "advance-1", + }) + const status = await client.indexConversation( + "first user", + "first reply", + { turnKey: "advance-1" }, + ) + + expect(status).toBe("duplicate") + expect(notes.get(today())?.match(/openclaw-turn:/g)).toHaveLength(1) + }) + + it("finds a key recorded in yesterday's note after midnight", async () => { + const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000) + .toISOString() + .split("T")[0] + await client.indexConversation("late user", "late reply", { + turnKey: "advance-1", + }) + notes.set(`conversations-${yesterday}`, notes.get(today()) ?? "") + notes.delete(today()) + + const status = await client.indexConversation("late user", "late reply", { + turnKey: "advance-1", + }) + + expect(status).toBe("duplicate") + expect(notes.has(today())).toBe(false) + }) + + it("writes concurrent retries of one key exactly once", async () => { + const statuses = await Promise.all([ + client.indexConversation("same user", "same reply", { + turnKey: "advance-1", + }), + client.indexConversation("same user", "same reply", { + turnKey: "advance-1", + }), + ]) + + expect(statuses.sort()).toEqual(["committed", "duplicate"]) + expect(notes.get(today())?.match(/openclaw-turn:/g)).toHaveLength(1) + }) + + it("keeps different keys as separate entries", async () => { + await client.indexConversation("user one", "reply one", { + turnKey: "advance-1", + }) + const status = await client.indexConversation("user two", "reply two", { + turnKey: "advance-2", + }) + + expect(status).toBe("committed") + expect(notes.get(today())?.match(/openclaw-turn:/g)).toHaveLength(2) + }) + + it("propagates a failed duplicate check instead of writing blind", async () => { + ;(client as any).readNote = jest + .fn() + .mockRejectedValue(new Error("BM MCP unavailable")) + + await expect( + client.indexConversation("user", "reply", { turnKey: "advance-1" }), + ).rejects.toThrow("BM MCP unavailable") + expect((client as any).editNote).not.toHaveBeenCalled() + }) + + it("propagates a failed note create so the host can retry", async () => { + ;(client as any).writeNote = jest + .fn() + .mockRejectedValue(new Error("disk full")) + + await expect( + client.indexConversation("user", "reply", { turnKey: "advance-1" }), + ).rejects.toThrow("disk full") + }) + + it("keeps capturing after an earlier capture failed", async () => { + ;(client as any).writeNote = jest + .fn() + .mockRejectedValueOnce(new Error("disk full")) + .mockImplementation(async (title: string, content: string) => { + notes.set(title, content) + }) + + await expect( + client.indexConversation("user", "reply", { turnKey: "advance-1" }), + ).rejects.toThrow("disk full") + await expect( + client.indexConversation("user", "reply", { turnKey: "advance-1" }), + ).resolves.toBe("committed") + }) + }) + it("retries recoverable MCP failures with bounded attempts", async () => { ;(client as any).retryDelaysMs = [0, 0, 0] diff --git a/integrations/openclaw/bm-client.ts b/integrations/openclaw/bm-client.ts index dc974a0da..76053abfc 100644 --- a/integrations/openclaw/bm-client.ts +++ b/integrations/openclaw/bm-client.ts @@ -1,3 +1,4 @@ +import { createHash } from "node:crypto" import { setTimeout as delay } from "node:timers/promises" import { Client } from "@modelcontextprotocol/sdk/client" import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js" @@ -252,6 +253,19 @@ function isNoteNotFoundError(err: unknown): boolean { ) } +export type ConversationCaptureStatus = "committed" | "duplicate" + +function conversationDate(date: Date): string { + return date.toISOString().split("T")[0] +} + +// Host advancement keys are opaque and may contain characters that would end +// an HTML comment, so the note stores a fixed-length digest instead. +function conversationTurnMarker(turnKey: string): string { + const digest = createHash("sha256").update(turnKey).digest("hex").slice(0, 32) + return `` +} + function asString(value: unknown): string | null { return typeof value === "string" ? value : null } @@ -296,6 +310,9 @@ export class BmClient { private transport: StdioClientTransport | null = null private connectPromise: Promise | null = null private retryDelaysMs = [...DEFAULT_RETRY_DELAYS_MS] + // Conversation captures run one at a time so a turn-key duplicate check + // and the append that follows it cannot interleave with another capture. + private conversationWrites: Promise = Promise.resolve() constructor(bmPath: string, project: string) { this.bmPath = bmPath @@ -949,17 +966,61 @@ export class BmClient { return payload as unknown as SchemaDiffResult } + /** + * Append one user/assistant exchange to today's conversation note. + * + * With a turnKey the capture is idempotent: the entry carries a marker + * derived from the key, and a key already present in today's or + * yesterday's note is reported as a duplicate instead of written again. + * Yesterday is checked because a host retry can cross midnight. + */ async indexConversation( userMessage: string, assistantResponse: string, - ): Promise { + options: { turnKey?: string } = {}, + ): Promise { + const write = this.conversationWrites.then(() => + this.writeConversationEntry( + userMessage, + assistantResponse, + options.turnKey, + ), + ) + this.conversationWrites = write.catch(() => undefined) + return write + } + + private async writeConversationEntry( + userMessage: string, + assistantResponse: string, + turnKey: string | undefined, + ): Promise { const now = new Date() - const dateStr = now.toISOString().split("T")[0] + const dateStr = conversationDate(now) const timeStr = now.toTimeString().slice(0, 5) const title = `conversations-${dateStr}` + const marker = turnKey ? conversationTurnMarker(turnKey) : null + + // Trigger: the host supplied an advancement key for this turn. + // Why: hosts retry commits after a crash, and a second append would + // duplicate the exchange in the note. + // Outcome: an already-recorded key short-circuits before any write. + if (marker) { + const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000) + for (const candidate of [ + title, + `conversations-${conversationDate(yesterday)}`, + ]) { + if (await this.noteContains(candidate, marker)) { + log.debug(`conversation turn already recorded in: ${candidate}`) + return "duplicate" + } + } + } const entry = [ `### ${timeStr}`, + ...(marker ? [marker] : []), "", "**User:**", userMessage, @@ -973,7 +1034,7 @@ export class BmClient { try { await this.editNote(title, "append", entry) log.debug(`appended conversation to: ${title}`) - return + return "committed" } catch (err) { if (!isNoteNotFoundError(err)) { log.error(`conversation append failed: ${getErrorMessage(err)}`, err) @@ -998,11 +1059,21 @@ export class BmClient { entry, ].join("\n") + await this.writeNote(title, content, "conversations") + log.debug(`created conversation note: ${title}`) + return "committed" + } + + private async noteContains( + identifier: string, + text: string, + ): Promise { try { - await this.writeNote(title, content, "conversations") - log.debug(`created conversation note: ${title}`) + const note = await this.readNote(identifier) + return note.content.includes(text) } catch (err) { - log.error("conversation index failed", err) + if (isNoteNotFoundError(err)) return false + throw err } } diff --git a/integrations/openclaw/bun.lock b/integrations/openclaw/bun.lock index 52e4d3144..c4026ae1a 100644 --- a/integrations/openclaw/bun.lock +++ b/integrations/openclaw/bun.lock @@ -11,7 +11,7 @@ "devDependencies": { "@biomejs/biome": "^2.4.6", "@types/node": "^20.0.0", - "openclaw": "^2026.5.4", + "openclaw": "^2026.10.6", "typescript": "^5.9.3", }, "peerDependencies": { @@ -20,179 +20,215 @@ }, }, "packages": { - "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.22.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-DfqXtl/8gO9NImq094MTaCXEU2vkhh6v7q/kT+9UjZxUqj8hYaya2OjLVIqn16MzNHcXEpShTR2RIauLSYeDQQ=="], + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@1.7.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-ZORuxsuEnLjRly7t6Ad7zAsWitjWsyprswyPUHz/yycPb+tTm3DGa8XheaHhRXqX8LS9snuxaYavXSRA50TlHw=="], - "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.91.1", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw=="], + "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.131.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-9+PepoU7qVMmM70jSahdnfcMHAvAnzhMOLv2W9WjRLO+OG/MAiBETkwKZqv7KIJ1Cj5h8eZ019bHzZaq+Mbepw=="], - "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], + "@babel/code-frame": ["@babel/code-frame@8.0.6", "", { "dependencies": { "@babel/helper-validator-identifier": "^8.0.6", "js-tokens": "^10.0.0" } }, "sha512-uMHhvmDmwFiLuiozaoRYTZHqMFuu3fem/X9JY78lohAuLoh8LSGGC8JqUzo2cVuBsBxkjMZNk56CE7ock8Xxkw=="], - "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], + "@babel/generator": ["@babel/generator@8.0.6", "", { "dependencies": { "@babel/parser": "^8.0.6", "@babel/types": "^8.0.6", "@jridgewell/gen-mapping": "0.4.0-beta.0", "@jridgewell/trace-mapping": "^0.3.31", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-/pcanjdRsonCexCuxgGD8fKnBLLzk2i9uM4kmcmGyyev2R5YDs+rafMYZ89RvaGY1mW8T7C5au0TyYaEeHBGng=="], - "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], + "@babel/helper-globals": ["@babel/helper-globals@8.0.6", "", {}, "sha512-OdnA/N52LhzFpeUuVz5YGuSWjc7TPHiFmVYZbPlSgExocO2GwbxVpSni9MVs5wwW+wZ4kPuwBEBN9pIPDYz1mA=="], - "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.8", "", {}, "sha512-fVM+gSuKbdv9cpmyRNh5EvsDHUZCdxQH3FdnFKSkNYHpbsn95bbrxm+ES3MVeQjcqwi2O5ur/DjLfmTQaO60ng=="], - "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.6", "", {}, "sha512-HYx0YmuchRxRSpnjvcNffnPS8DCauKNmnumIuHG3jnQAVewRA7kfJGwF13ayEpSZs7s4R/oBH4eppuXcAQd5JQ=="], - "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/eventstream-handler-node": "^3.972.16", "@aws-sdk/middleware-eventstream": "^3.972.12", "@aws-sdk/middleware-websocket": "^3.972.19", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ=="], + "@babel/parser": ["@babel/parser@8.0.6", "", { "dependencies": { "@babel/types": "^8.0.6" }, "bin": "./bin/babel-parser.js" }, "sha512-LpGDIYJAzc3Y3PT9x+FxBrGYu2PlWxLmyN7SwPTzaX0LSwEmFJBsRnPBqmaXF2r1v+Zhz6lNiEJ+7yKtM5+Ugg=="], - "@aws-sdk/core": ["@aws-sdk/core@3.974.14", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.26", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.3", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-ppamm04uoj3hhNO5IlQSs5D6rWX1fWkzcn6a4pZrojk8Y6ObY9wzLDdT/Eq3gv6O9hOebi9tYTNB8b8fQj9XJw=="], + "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.40", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-jjT0p0Y7KZtcvExYiPCLJnqM9lkXDV1KBEg/13OE2DXv/9batzlyJHVKUEnRNJccY0O2Sul17E1su38CgdBhGQ=="], + "@babel/template": ["@babel/template@8.0.0", "", { "dependencies": { "@babel/code-frame": "^8.0.0", "@babel/parser": "^8.0.0", "@babel/types": "^8.0.0" } }, "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.42", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/fetch-http-handler": "^5.4.3", "@smithy/node-http-handler": "^4.7.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-+3fsKtWybe5BjKEUA3/07oh7Ayfd82IED2+gyyaVfS/4PU78E3TaOQxSGOJ1t7Imefoidw/ne9QA7apX8wEnJg=="], + "@babel/traverse": ["@babel/traverse@8.0.6", "", { "dependencies": { "@babel/code-frame": "^8.0.6", "@babel/generator": "^8.0.6", "@babel/helper-globals": "^8.0.6", "@babel/parser": "^8.0.6", "@babel/template": "^8.0.0", "@babel/types": "^8.0.6", "obug": "^2.1.1" } }, "sha512-ilYV+qLStGzSKLipJlETdvdtpK3rAuwfCmCoGKv15MU4EoeIuLkespSNoNLFGOPSciEHx9TLWtN5mv0fz5w5mQ=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.44", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/credential-provider-env": "^3.972.40", "@aws-sdk/credential-provider-http": "^3.972.42", "@aws-sdk/credential-provider-login": "^3.972.44", "@aws-sdk/credential-provider-process": "^3.972.40", "@aws-sdk/credential-provider-sso": "^3.972.44", "@aws-sdk/credential-provider-web-identity": "^3.972.44", "@aws-sdk/nested-clients": "^3.997.12", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-gZFw5wBefCIPg9vpT+gV5FdhfNKhYTVDZa1IsZCcn3SRoYUOJ/E05vwIogkJoonqBL0ttBGi5vhthX7xceekRg=="], + "@babel/types": ["@babel/types@8.0.10", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.8", "@babel/helper-validator-identifier": "^8.0.6" } }, "sha512-KV8Y+teoRsmXeEPS4sCJY1kwV+hcPzHP1qQqgCxrjKOehLdBaxpsFBfoJ8MXWFV80y6Jw56+TM95wR0Per8dYw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.44", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/nested-clients": "^3.997.12", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-QqEGHfQeZgUDqh7zpqHufrZ8T644ELEWvB+4gUdewLyRw4IRF+6CJqeQuRWqucZdQzoQeMh7fNAD9BWxFAdNig=="], + "@biomejs/biome": ["@biomejs/biome@2.4.16", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.16", "@biomejs/cli-darwin-x64": "2.4.16", "@biomejs/cli-linux-arm64": "2.4.16", "@biomejs/cli-linux-arm64-musl": "2.4.16", "@biomejs/cli-linux-x64": "2.4.16", "@biomejs/cli-linux-x64-musl": "2.4.16", "@biomejs/cli-win32-arm64": "2.4.16", "@biomejs/cli-win32-x64": "2.4.16" }, "bin": { "biome": "bin/biome" } }, "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.45", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.40", "@aws-sdk/credential-provider-http": "^3.972.42", "@aws-sdk/credential-provider-ini": "^3.972.44", "@aws-sdk/credential-provider-process": "^3.972.40", "@aws-sdk/credential-provider-sso": "^3.972.44", "@aws-sdk/credential-provider-web-identity": "^3.972.44", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-3YCv52ExXIRz3LAVNysevd+s7akSpg9dl39v9LJ7dOQH+s5rHi3jMZYQyxwMmglxQGMuzYRfQ0o1VSP2UOlIRw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.40", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-cXaozlgJCOwmE6D7x4npcPdyk7kiFZdrGjN3D6tXXtItJJMNGPafDfAJn4YQmciMooG/X+b0Y6RTqdVVMx26jg=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.44", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/nested-clients": "^3.997.12", "@aws-sdk/token-providers": "3.1054.0", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-YePoj5kQuPmE0MHnyftXCfsO8ZSBd2kDr50XEIUrdejSbGFlayYvUuCohdb8drhGhPm6b65o7H1eC26EZhwUvA=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.44", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/nested-clients": "^3.997.12", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-Ys/JJe++8Z2Y5meR1taMBaVcrGBA0/XsVTQR+qOKZbdNyg+8Jlv5rYZSwh8SqEHY00goSOZy7PHzZ2rLNQxDLg=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg=="], - "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.17", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-WFwdNcjchKZr7jKYgGimUZO8sSKQF/le7GGqgeCzz/lHozInE6b0gFJ1YMr8NaIeAoWJwgtrF7RE4/qMgosAdQ=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ=="], - "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.13", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-ECfsw7mf6G/sxNbKbGE3/h1xeIArY/yRI1IjDGYkLgDIankh+aDOtDRSr40LVlIHGL9+jEH1cVuxmbJ8NLL/1A=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg=="], - "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/fetch-http-handler": "^5.4.3", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-aumo6pYnvD1/eda3R0UDkRVecwxsuW4zTZLdjbHg7NqYMKmy7vK0bM3NGJzCD+Ys8iqCC7EeDU4LuWVIsXvL+A=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.12", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.14", "@aws-sdk/signature-v4-multi-region": "^3.996.29", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/fetch-http-handler": "^5.4.3", "@smithy/node-http-handler": "^4.7.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-Js2VYaCM269feB0cs0cGmlIhdOgT9aMqzdBx68lCy6kVCYfzr0T36ovUFDvfUmatkuBeyBJhCwaLBh7P8meH5Q=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.16", "", { "os": "win32", "cpu": "x64" }, "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw=="], - "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.29", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-Few9FoQqOt/0KSvZYP+qdW0dfOhfQ9N+gl2UUDvCPW6mkPKHli9LMbKxWj+wZ5zKPaOoqxuR3Hhy3OTpndkfSw=="], + "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="], + "@clack/core": ["@clack/core@1.5.1", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ=="], - "@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="], + "@clack/prompts": ["@clack/prompts@1.8.1", "", { "dependencies": { "@clack/core": "1.5.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ=="], - "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.5", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ=="], + "@earendil-works/pi-tui": ["@earendil-works/pi-tui@1.0.0", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "18.0.11" } }, "sha512-JsT7kXnpZA2YOtQu6RyriyxEO0eJIzPyfiH09bH+OLN5+s18HYkwaUD/tBkjhnSfMu6/50CQPRYJagzSP6HdPw=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.26", "", { "dependencies": { "@smithy/types": "^4.14.2", "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" } }, "sha512-cDbrqvDS73whl6YAPSPq0U6whzG6UWI9PuWh0wrUuGoZexhWEqhdunbukV7iBoaWnFV1AODutM5hOD6rtn439g=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], - "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], - "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], - "@biomejs/biome": ["@biomejs/biome@2.4.16", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.16", "@biomejs/cli-darwin-x64": "2.4.16", "@biomejs/cli-linux-arm64": "2.4.16", "@biomejs/cli-linux-arm64-musl": "2.4.16", "@biomejs/cli-linux-x64": "2.4.16", "@biomejs/cli-linux-x64-musl": "2.4.16", "@biomejs/cli-win32-arm64": "2.4.16", "@biomejs/cli-win32-x64": "2.4.16" }, "bin": { "biome": "bin/biome" } }, "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.16", "", { "os": "win32", "cpu": "x64" }, "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], - "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], - "@clack/core": ["@clack/core@1.3.1", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-fT1qHVGAag4IEkrupZ6lRRbNCs1vS9P01KB/sG8zKgvUztbYtFBtQpjSITNwooDZ83tpsPzP0mRNs1/KVszCRA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], - "@clack/prompts": ["@clack/prompts@1.4.0", "", { "dependencies": { "@clack/core": "1.3.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-S0My7XPGIgpRWMDG8uRqalbgT+a6FmCUdOW+HaIOVVpUPHOb7RrpvjTjiODadKp06fsrVDJZlIzc6yCTp4AnxA=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], - "@earendil-works/pi-agent-core": ["@earendil-works/pi-agent-core@0.75.5", "", { "dependencies": { "@earendil-works/pi-ai": "^0.75.5", "ignore": "7.0.5", "typebox": "1.1.38", "yaml": "2.9.0" } }, "sha512-LHygOgsW2pgXKb3IkXkOAeZPovHr9VF+EixgXVsDNuB4jmhEOXgshy/zksZ7slkUAx10OQ9W1Ed/2jsnhd1NqA=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], - "@earendil-works/pi-ai": ["@earendil-works/pi-ai@0.75.5", "", { "dependencies": { "@anthropic-ai/sdk": "0.91.1", "@aws-sdk/client-bedrock-runtime": "3.1048.0", "@google/genai": "1.52.0", "@mistralai/mistralai": "2.2.1", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "openai": "6.26.0", "partial-json": "0.1.7", "typebox": "1.1.38" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-zf1F5kXk1pqZeFShXOqq9ibUk8QdtRoLCDPAjO+hj44e3EUs9/GFO2qnhTC5+JA2uwVCx+WCNe1PiCjlBYWm5w=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], - "@earendil-works/pi-coding-agent": ["@earendil-works/pi-coding-agent@0.75.5", "", { "dependencies": { "@earendil-works/pi-agent-core": "^0.75.5", "@earendil-works/pi-ai": "^0.75.5", "@earendil-works/pi-tui": "^0.75.5", "@silvia-odwyer/photon-node": "0.3.4", "chalk": "5.6.2", "cross-spawn": "7.0.6", "diff": "8.0.4", "glob": "13.0.6", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.5", "jiti": "2.7.0", "minimatch": "10.2.5", "proper-lockfile": "4.1.2", "typebox": "1.1.38", "undici": "8.3.0", "yaml": "2.9.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.6" }, "bin": { "pi": "dist/cli.js" } }, "sha512-O3CCQDYy28D4uwtP6zZkdEwzHN6X22v49Sb0+SZTC7x37V/YfmogrWPiaFoWeoc2hmdKhSATI7ZAK5bQbJG5NA=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], - "@earendil-works/pi-tui": ["@earendil-works/pi-tui@0.75.5", "", { "dependencies": { "get-east-asian-width": "1.6.0", "marked": "15.0.12" } }, "sha512-LkXUM1/49pvzzeI39Y5wjBMlgafcCf67HCLhB9Z7yuXHy4XgT+VqxWcZVW5hBdhQsHZd0znjJotfGH1BzxMfiA=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], - "@google/genai": ["@google/genai@2.6.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-HjoW3mPuEn7pnuKABJl9VbDoWDSF4nbwYKYvYYor7YjPeDxrrBxHzu2d1Prcd+BAuC4w+85UP6y7ZdcrQAoO7g=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], - "@grammyjs/runner": ["@grammyjs/runner@2.0.3", "", { "dependencies": { "abort-controller": "^3.0.0" }, "peerDependencies": { "grammy": "^1.13.1" } }, "sha512-nckmTs1dPWfVQteK9cxqxzE+0m1VRvluLWB8UgFzsjg62w3qthPJt0TYtJBEdG7OedvfQq4vnFAyE6iaMkR42A=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], + + "@google/genai": ["@google/genai@2.27.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"], "hasInstallScript": true }, "sha512-W6F9Y9d4h7cVQNa85IPCOVVP9PiUzve/ZQPBvQnBmnBJcLvxstEw+R2X/RyCH0SOe0HVDQzeKDpDUf6ZRtbmdQ=="], "@grammyjs/transformer-throttler": ["@grammyjs/transformer-throttler@1.2.1", "", { "dependencies": { "bottleneck": "^2.0.0" }, "peerDependencies": { "grammy": "^1.0.0" } }, "sha512-CpWB0F3rJdUiKsq7826QhQsxbZi4wqfz1ccKX+fr+AOC+o8K7ZvS+wqX0suSu1QCsyUq2MDpNiKhyL2ZOJUS4w=="], - "@grammyjs/types": ["@grammyjs/types@3.27.3", "", {}, "sha512-yUKMLliGsGbnxu96YUJ7km7B0zy4PzeH/Jvti5705R/LeKDMqkDV4DckMSt+OrliWQpTwQljHE0QLol5zgxBkg=="], + "@grammyjs/types": ["@grammyjs/types@5.0.0", "", {}, "sha512-iq1Qrq1iPKkB8yAa0qSuIURMZOCuqTY5pWy5gHpCeL1oQ+GPadGhw/cDTVE8waJwuCzacUzuIjRv1sESvk7u7A=="], - "@homebridge/ciao": ["@homebridge/ciao@1.3.8", "", { "dependencies": { "debug": "^4.4.3", "fast-deep-equal": "^3.1.3", "source-map-support": "^0.5.21", "tslib": "^2.8.1" }, "bin": { "ciao-bcs": "lib/bonjour-conformance-testing.js" } }, "sha512-lNhpCsZVbdbjz2trFjQdzQ3cUIMZQMIMksi7wd3ntTIYgdaGLqT1Ms97DfVIJYHzRuduf56ISvgU8RRLTpK/ng=="], + "@homebridge/ciao": ["@homebridge/ciao@1.3.12", "", { "dependencies": { "debug": "^4.4.3", "fast-deep-equal": "^3.1.3", "source-map-support": "^0.5.21", "tslib": "^2.8.1" }, "bin": { "ciao-bcs": "lib/bonjour-conformance-testing.js" } }, "sha512-84/0u0kqKy4qcKupIDaTtbkmk+3qFDuMzxTC0NPfVlHcUT+jHGdP+QCqwEw94/GJxRezDeBLwxaclkBZgCdeUg=="], "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - "@lydell/node-pty": ["@lydell/node-pty@1.2.0-beta.12", "", { "optionalDependencies": { "@lydell/node-pty-darwin-arm64": "1.2.0-beta.12", "@lydell/node-pty-darwin-x64": "1.2.0-beta.12", "@lydell/node-pty-linux-arm64": "1.2.0-beta.12", "@lydell/node-pty-linux-x64": "1.2.0-beta.12", "@lydell/node-pty-win32-arm64": "1.2.0-beta.12", "@lydell/node-pty-win32-x64": "1.2.0-beta.12" } }, "sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.4.0-beta.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.6.0-beta.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-JdGNkbE4GlNPYQhM0L95fBQr7ctLZJ276QXQLTad4t1oSdnnCI3fDq9DW3BqYAWv8Wc3+HS+4Gsii1oPMCfz1w=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@koromix/koffi-android-arm64": ["@koromix/koffi-android-arm64@3.3.2", "", { "os": "android", "cpu": "arm64" }, "sha512-6mFtwFJCy1skaf/qzl82OtELmT2BwHXbephfrIFqKoxIghc7N+kiW33J3ZNRP8JhBYFI6xJ8jiatGwPJ7mCOMw=="], + + "@koromix/koffi-android-x64": ["@koromix/koffi-android-x64@3.3.2", "", { "os": "android", "cpu": "x64" }, "sha512-wzIWXvldodHWST6KZBdjJlpdH0DJ2rIN5YppY+/T+mTR1DcRYdYhOXzZMGDDx9W3ao8Hry8G4GqVzK9IuYpuWA=="], - "@lydell/node-pty-darwin-arm64": ["@lydell/node-pty-darwin-arm64@1.2.0-beta.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tqaifcY9Cr41SblO1+FLzh8oxxtkNhuW9Dhl22lKme9BreYvKvxEZcdPIXTuqkJc5tagOEC4QHShKmJjLyLXLQ=="], + "@koromix/koffi-darwin-arm64": ["@koromix/koffi-darwin-arm64@3.3.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gQKOkA/4tkOxXP3hdau2MrvVvTYlKQiXd86hK+B2FKErV0QcwqrWt6DWZ3FtJUYGB1scenT0srS9VfsWmbgeMQ=="], - "@lydell/node-pty-darwin-x64": ["@lydell/node-pty-darwin-x64@1.2.0-beta.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-4LrS5pCJwqHKDVf1zS2gyNV0m4hKAXch+XZNhbZ6LY8uwVL8BhchzQBO40Os5anuRxRCWzHpw4Sp64Ie8q7E4Q=="], + "@koromix/koffi-darwin-x64": ["@koromix/koffi-darwin-x64@3.3.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-qxysFokAwiMLiWYYVhooWZHSV3REKJErsUjnX9IeG2rAVpWNkdcXUiQ2GMdfH3hZ0f2fuv0fTuv293/tYu1yew=="], - "@lydell/node-pty-linux-arm64": ["@lydell/node-pty-linux-arm64@1.2.0-beta.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-Sx+A71x5BDGHt9ansfrtGxwq2VFVDWvJUAdlUL0Hv0qeiJUfts+hgopx+CgT4PSwahKjdEgtu0+FAfY9rICKRw=="], + "@koromix/koffi-freebsd-arm64": ["@koromix/koffi-freebsd-arm64@3.3.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EinnZVzK3KVTQe0N+XXnUfUN2fwNiYEY5IuAcMqtJO4rbOR+8S+C+bbViUKwqmkLG8OvL/kBesuwGLn5DLNZCQ=="], - "@lydell/node-pty-linux-x64": ["@lydell/node-pty-linux-x64@1.2.0-beta.12", "", { "os": "linux", "cpu": "x64" }, "sha512-bJzs94njofYhGg/UDqW1nj0dtvvu+2OvxMY+RlLS1T17VgcktKoIR6PuenTwE5HJ/D6StCPADmXcT0nNsCKmIQ=="], + "@koromix/koffi-freebsd-ia32": ["@koromix/koffi-freebsd-ia32@3.3.2", "", { "os": "freebsd", "cpu": "ia32" }, "sha512-gnJFMVbxeyY4dSQbw0p3smSyFGDrp8QzI5krF73QxP7GSIMHR2lplejZseNQGyHIeR3XDdxuJFsfAfXmZdQM3w=="], - "@lydell/node-pty-win32-arm64": ["@lydell/node-pty-win32-arm64@1.2.0-beta.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-p7POgjVEiFaBC3/y+AKuV1FzePCsJ6HmZDv2XK+jBZSfwP8+uBAw181ZiKYN1YuRa/XpmBGaWezcI8hZkbW++g=="], + "@koromix/koffi-freebsd-x64": ["@koromix/koffi-freebsd-x64@3.3.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-56mIFadXceWImQbsO0fN1hoZ76LCIvAjouL4fntoA7IKDI64BFbLSkcJ7Roww31YwxKjJaA9vdk93qt7bXXJZw=="], - "@lydell/node-pty-win32-x64": ["@lydell/node-pty-win32-x64@1.2.0-beta.12", "", { "os": "win32", "cpu": "x64" }, "sha512-IDFa00g7qUDGUYgByrUBJtC+mOjYVt/8KYyWivCg5JjGOHbBUACUQZLl0jTWmnr+tld/UyTpX90a2PY6oTVtRw=="], + "@koromix/koffi-linux-arm": ["@koromix/koffi-linux-arm@3.3.2", "", { "os": "linux", "cpu": "arm" }, "sha512-NhvFzykswakToxAWVhpHf5qA/y8z755MAz4MU1m89yIL1lqUuJDSk6Fy/moD3YIQPOjjuHVf09wO7mlO5ukCbw=="], - "@mariozechner/clipboard": ["@mariozechner/clipboard@0.3.6", "", { "optionalDependencies": { "@mariozechner/clipboard-darwin-arm64": "0.3.6", "@mariozechner/clipboard-darwin-universal": "0.3.6", "@mariozechner/clipboard-darwin-x64": "0.3.6", "@mariozechner/clipboard-linux-arm64-gnu": "0.3.6", "@mariozechner/clipboard-linux-arm64-musl": "0.3.6", "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.6", "@mariozechner/clipboard-linux-x64-gnu": "0.3.6", "@mariozechner/clipboard-linux-x64-musl": "0.3.6", "@mariozechner/clipboard-win32-arm64-msvc": "0.3.6", "@mariozechner/clipboard-win32-x64-msvc": "0.3.6" } }, "sha512-MXdtr+6+ntlIVHdrZYuZNQydu6o8yZswFJ2Ln81j2O/Y9B/LDHvEaIm95xWNPkjGTWriSOeLnQJRFs6dYb60bg=="], + "@koromix/koffi-linux-arm64": ["@koromix/koffi-linux-arm64@3.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-adabETUHezNDJ6jpqpJV01oJRW8rI4KWH3xV6EpFlIAXCtj6l4aLCbJ6DbGH8fNmsJBLnWiuLkyoNm8zkVotCw=="], - "@mariozechner/clipboard-darwin-arm64": ["@mariozechner/clipboard-darwin-arm64@0.3.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HjaisYCAbHi/1+N1yDAQHc8ZXGffufIUT5NSOSVR3f3AuMDusxTtnbK8tZ7JFDkShua1oNGZoNwQHsc8MPtE0Q=="], + "@koromix/koffi-linux-ia32": ["@koromix/koffi-linux-ia32@3.3.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-IMJAp4dg+l1N5Yek43NpDHDVaJFRkMaBnAg9uI3Z1vk61+WxxtaugOl0lC6gDPLBeNE+lzSXcAEeKBIkTwDzdw=="], - "@mariozechner/clipboard-darwin-universal": ["@mariozechner/clipboard-darwin-universal@0.3.6", "", { "os": "darwin" }, "sha512-8BWtPjOtJOJoykml3w0fx0zRrfWP31mXrJwfoA7xzNprkZw1uolCNfgmjDiVBseoKjp16EGITz7bN+61qn8dWA=="], + "@koromix/koffi-linux-loong64": ["@koromix/koffi-linux-loong64@3.3.2", "", { "os": "linux", "cpu": "none" }, "sha512-Sdf+iQ5Fo3Px6e8xFx7eTES+cAIiHxCLt9KDVmnHm0ls6fW2eTVu5ez1+3GUBb/gjLTMODX2U4+dP9LHagwHHg=="], - "@mariozechner/clipboard-darwin-x64": ["@mariozechner/clipboard-darwin-x64@0.3.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-p9syiZD1kU4I+1ya7f7g+zD1GiUvR8fdlRlNmgsZNWlyjtc8rlV2EjTLd/35x1LsdBq020GVvtzp0ZmPgBI09Q=="], + "@koromix/koffi-linux-ppc64": ["@koromix/koffi-linux-ppc64@3.3.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FVHtjljl9vUvT6dSsAE1ObOqmPeJXzS8Ez7cidlsI/rJ5pa7h50KQutU/jPfTaK1cqChRjI66hwnJseLG8VPTA=="], - "@mariozechner/clipboard-linux-arm64-gnu": ["@mariozechner/clipboard-linux-arm64-gnu@0.3.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-5JFf5rGofrm+V29HNF+wLthXphHdQpMbKDUYJ5tML6/Z5DLlLOV/9Ak4kDPtYyZ+Dzf+kAusE0VsFg4+tfP1IA=="], + "@koromix/koffi-linux-riscv64": ["@koromix/koffi-linux-riscv64@3.3.2", "", { "os": "linux", "cpu": "none" }, "sha512-4Q3haXJ3oP5AJ0vlyd9HZsI7gS+s+fycqz1CDDrT6JftlSruIUbfr8be1/jetUlmh7Pd8HtQBM6x2gpQBNTttQ=="], - "@mariozechner/clipboard-linux-arm64-musl": ["@mariozechner/clipboard-linux-arm64-musl@0.3.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-JlVjxxw0GbGC0djXYWRIqyteO3J1KZ/QG3udlEFaOD5TLOM1FnmXXAPDQBqr+aBVr720ef9K00dirYnJ0LDCtw=="], + "@koromix/koffi-linux-x64": ["@koromix/koffi-linux-x64@3.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-78qO1oqd9GYfzcKOxIaRiN0KgvzQzgbPfdClf0/jErlWYdxnr8gB4i9KOFvsYMdnc7kTIa/wnubl1lPCiQnqvA=="], - "@mariozechner/clipboard-linux-riscv64-gnu": ["@mariozechner/clipboard-linux-riscv64-gnu@0.3.6", "", { "os": "linux", "cpu": "none" }, "sha512-4t8BUi5zZ+L77otFQVnVSlaTyAX4TVk9EqQm4syMrEQp96trFEHEwwNHcNEBGzYv5+K7mxay50TthYkz47OWzQ=="], + "@koromix/koffi-openbsd-arm64": ["@koromix/koffi-openbsd-arm64@3.3.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-rB6HZ/RnEAu7CZoD8IMXonCJSD6WJIX8QfZ11RCOy9MXxA8wQR5CRnP3ffy4/8IbABorRoERLLFTFk5wFFZqCw=="], - "@mariozechner/clipboard-linux-x64-gnu": ["@mariozechner/clipboard-linux-x64-gnu@0.3.6", "", { "os": "linux", "cpu": "x64" }, "sha512-trtPwcNLW37irwQCJLtCxLw757jjJZk3TSnY/MU9bhtWtA3K9b/eLW0e4RGhUXDoFRds9opNWWaUDuFLa8dm0w=="], + "@koromix/koffi-openbsd-ia32": ["@koromix/koffi-openbsd-ia32@3.3.2", "", { "os": "openbsd", "cpu": "ia32" }, "sha512-XmzyeUEsCc8f6n26684mzn73I5VdDBxFydm8JxwYCmvrzfkSkDPU7eQyRoxHDRwgveIK/plmRiMUIj3/7J1flw=="], - "@mariozechner/clipboard-linux-x64-musl": ["@mariozechner/clipboard-linux-x64-musl@0.3.6", "", { "os": "linux", "cpu": "x64" }, "sha512-WfnzIvOCCWQiN0MmltCEo6cLceUDbYe+I7xyFZjaps5A+2Op/M2CY7Rey+C4ucQhrvmpoHmTSFgY9ODWk7snoA=="], + "@koromix/koffi-openbsd-x64": ["@koromix/koffi-openbsd-x64@3.3.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Bt+beMlH6yK4X21+y7lgk+lthjBODfwJjREFITVQH68v8rHWZ5UxV7FBInHZ7ZT0o07G/fgIr2l1DG6SpaTbEA=="], - "@mariozechner/clipboard-win32-arm64-msvc": ["@mariozechner/clipboard-win32-arm64-msvc@0.3.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-+8+1aHYsBPUjmW3otmWlg+Hijt0iJvoBBs5e0mxFeUd4gDaKMB8Bn6x7c6KVtscg7E5j5NFXnwQqNSIAO4p8zQ=="], + "@koromix/koffi-win32-arm64": ["@koromix/koffi-win32-arm64@3.3.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-+fLooyTbldECuFH54h1ags7BAOB4fmqnshyVkXr+HbJBhgHdHoIbZ+CcaoH1ELVth7L7G+5XNwbXDH1TOyQMvA=="], - "@mariozechner/clipboard-win32-x64-msvc": ["@mariozechner/clipboard-win32-x64-msvc@0.3.6", "", { "os": "win32", "cpu": "x64" }, "sha512-S4xfPmERC8ZkiLHe3vekZCjdDwNEETCuvCgQK2kP6/TnvmUkq1y2Pk+DjM4t8uh9KMX9bH4zs5ePcKa8GTXmfg=="], + "@koromix/koffi-win32-ia32": ["@koromix/koffi-win32-ia32@3.3.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-knegFlqbXsYfWcbIsAHMrKHqVbLctqzYD9xW3+GfO1Dyt+xe1xY8YDiadjRaWtKkLz5uF1aJD886EfBZUhECLA=="], - "@mistralai/mistralai": ["@mistralai/mistralai@2.2.1", "", { "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.25.0" } }, "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ=="], + "@koromix/koffi-win32-x64": ["@koromix/koffi-win32-x64@3.3.2", "", { "os": "win32", "cpu": "x64" }, "sha512-OWc6s6gziEabkQj+xc+ZNaf5g69hc/DQJLBcmbhxJAifAdXDgj9vB5d8hcjS2mTHjBeAIqQ4nkd9d/Jc7OUuHw=="], + + "@lydell/node-pty": ["@lydell/node-pty@1.2.0-beta.15", "", { "optionalDependencies": { "@lydell/node-pty-darwin-arm64": "1.2.0-beta.15", "@lydell/node-pty-darwin-x64": "1.2.0-beta.15", "@lydell/node-pty-linux-arm64": "1.2.0-beta.15", "@lydell/node-pty-linux-x64": "1.2.0-beta.15", "@lydell/node-pty-win32-arm64": "1.2.0-beta.15", "@lydell/node-pty-win32-x64": "1.2.0-beta.15" } }, "sha512-Br8wBxzbxFwdWgk9uQ+rdzE0xfoxOK4QuGH54swhRwc5IxP6H9Y1/bcyazRGvNUs6XkB5qNVkezuKSRxUwZe7A=="], + + "@lydell/node-pty-darwin-arm64": ["@lydell/node-pty-darwin-arm64@1.2.0-beta.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6TSBbzdcLiNTHl1mTuzflqXrkmcC36USVGvERoDgvHk2ItEDaMaFZuAJ1CqPmwYj0DyhCS16TVS8OGK9xZnjyQ=="], + + "@lydell/node-pty-darwin-x64": ["@lydell/node-pty-darwin-x64@1.2.0-beta.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-yDT2oqPqYMBScyuk1U9Rg5VKcrbMOD9o9jWYYamDADA3NSbUISroPChrqYRQ74Y7BQtNH4gqYAiWOZRi5uQZ0Q=="], + + "@lydell/node-pty-linux-arm64": ["@lydell/node-pty-linux-arm64@1.2.0-beta.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-wkbNF7dYAmtJv+o2+iztVlNwnUB4B0uX0wh/UD+mwMcmE2gNMnW9GChXO7fEE5XJokD0vB5idiHpGegaN+G/sg=="], + + "@lydell/node-pty-linux-x64": ["@lydell/node-pty-linux-x64@1.2.0-beta.15", "", { "os": "linux", "cpu": "x64" }, "sha512-+U/5AVvHT6W+8OCYcnJgN0Qgc0ycO3TfD6aaFJHK+WHij797f8gsi5dV1HEO9l6YQmWCD+VL5gaLDhx3mxHwCA=="], + + "@lydell/node-pty-win32-arm64": ["@lydell/node-pty-win32-arm64@1.2.0-beta.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-pyAk91w7wnnKrD4mrHXtIXRfmzSWV5bEzvRhurXcMCtCc2TJ424ciUskIgWMhAPP6y3KyUnqElj+U6kY3iOt0A=="], + + "@lydell/node-pty-win32-x64": ["@lydell/node-pty-win32-x64@1.2.0-beta.15", "", { "os": "win32", "cpu": "x64" }, "sha512-2f8twEmDVxZ7drchAXjtevpmSPhFok0avAnzXro4t5gmz0xsPNKkoZvymwtuIS3xo7PzQqZOPQ/YzwEMb7oIzQ=="], + + "@mistralai/mistralai": ["@mistralai/mistralai@2.7.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.40.0", "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-trace-otlp-http": "^0.220.0", "@opentelemetry/resources": "^2.9.0", "@opentelemetry/sdk-trace-base": "^2.9.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/resources", "@opentelemetry/sdk-trace-base"] }, "sha512-zCrx6MtNpcz+EL/Nqvg55QubSgmfwJfBmd3d3wSYfJGfnvlNnWcJYlxEW5xQpS3KR6A5qK9KUyRBwMDIWnyVGA=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], "@mozilla/readability": ["@mozilla/readability@0.6.0", "", {}, "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ=="], - "@napi-rs/canvas": ["@napi-rs/canvas@0.1.100", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.100", "@napi-rs/canvas-darwin-arm64": "0.1.100", "@napi-rs/canvas-darwin-x64": "0.1.100", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", "@napi-rs/canvas-linux-arm64-musl": "0.1.100", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", "@napi-rs/canvas-linux-x64-gnu": "0.1.100", "@napi-rs/canvas-linux-x64-musl": "0.1.100", "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", "@napi-rs/canvas-win32-x64-msvc": "0.1.100" } }, "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA=="], - - "@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.100", "", { "os": "android", "cpu": "arm64" }, "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ=="], + "@openclaw/ai": ["@openclaw/ai@2026.10.9", "", { "dependencies": { "@anthropic-ai/sdk": "0.131.0", "@google/genai": "2.27.0", "@mistralai/mistralai": "2.7.0", "openai": "7.27.0", "partial-json": "0.1.7", "typebox": "1.3.34" } }, "sha512-Zy7xHYMSjnKwKJCfOBFl3mi8+SHKlkNDpsOp4LhPVmF/USLSvOINouteXrFHtHb0aFmVa8nG7xG21xo9oWKWIA=="], - "@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.100", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A=="], + "@openclaw/fs-safe": ["@openclaw/fs-safe@0.26.0", "", { "optionalDependencies": { "@openclaw/fs-safe-darwin-arm64": "0.26.0", "@openclaw/fs-safe-darwin-x64": "0.26.0", "@openclaw/fs-safe-freebsd-arm64": "0.26.0", "@openclaw/fs-safe-freebsd-x64": "0.26.0", "@openclaw/fs-safe-linux-arm64-gnu": "0.26.0", "@openclaw/fs-safe-linux-arm64-musl": "0.26.0", "@openclaw/fs-safe-linux-x64-gnu": "0.26.0", "@openclaw/fs-safe-linux-x64-musl": "0.26.0", "@openclaw/fs-safe-win32-arm64-msvc": "0.26.0", "@openclaw/fs-safe-win32-x64-msvc": "0.26.0", "jszip": "^3.10.2" } }, "sha512-tLpVEBUEcFS4YtT43DwM4R8XqPNcJxJzIb23+v8Lyj0vElEHUox2t5+4buv0OiSZ3r3EsVXe5odI3FZDZWcHqg=="], - "@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.100", "", { "os": "darwin", "cpu": "x64" }, "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw=="], + "@openclaw/fs-safe-darwin-arm64": ["@openclaw/fs-safe-darwin-arm64@0.26.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Lyt1rhoDUxCikH7CdkXzYqGdinKGZy3f8MC+D1/VAngXYIGUMSBu6AuR7pTo/vqrdyOI7vHpAW7QEDFobaG2ww=="], - "@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.100", "", { "os": "linux", "cpu": "arm" }, "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA=="], + "@openclaw/fs-safe-darwin-x64": ["@openclaw/fs-safe-darwin-x64@0.26.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-pX8E6FW9xF1INFXyp8rSv9PQyj7LFNovhgytmZD2/EdFlG2OXu1VZ6UQfcfDOwFARtoy0bwqqgEMkQZEBFH9PA=="], - "@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.100", "", { "os": "linux", "cpu": "arm64" }, "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw=="], + "@openclaw/fs-safe-freebsd-arm64": ["@openclaw/fs-safe-freebsd-arm64@0.26.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UNPfDJhOTArrNuKVG+a15UpKsQSH2m7ZnOl+KbKwGFHSHSrVqF0RUwBueooBbuuc+xzH1Y47HmUvQkM+T39K0Q=="], - "@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.100", "", { "os": "linux", "cpu": "arm64" }, "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ=="], + "@openclaw/fs-safe-freebsd-x64": ["@openclaw/fs-safe-freebsd-x64@0.26.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MSrO0yeScP6Gs2GvUTGeSAdTXJSGRtaDkwwM1LIxwc0Ja2lICUmSpAAsArOnvR7asEi+vAJ3KYlJgcHzcW3J4g=="], - "@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.100", "", { "os": "linux", "cpu": "none" }, "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw=="], + "@openclaw/fs-safe-linux-arm64-gnu": ["@openclaw/fs-safe-linux-arm64-gnu@0.26.0", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-P78xFe+KQ9z2Tqb8p7eou22CUNbywO5qyiUS6VlfOxo5Qwpj1O1RNw2xIoPWqxGpBnK+R0OEzTT0NXCu7Nz/8g=="], - "@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.100", "", { "os": "linux", "cpu": "x64" }, "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg=="], + "@openclaw/fs-safe-linux-arm64-musl": ["@openclaw/fs-safe-linux-arm64-musl@0.26.0", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-5ZHnjuW4vWZrSWI+6JDFrjc8QUcQ+1BnAjk+etnMeYhtJhnxau4Q9hJASWjvLsGcNrhHyNR4OmppRYvMxr5iwQ=="], - "@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.100", "", { "os": "linux", "cpu": "x64" }, "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA=="], + "@openclaw/fs-safe-linux-x64-gnu": ["@openclaw/fs-safe-linux-x64-gnu@0.26.0", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-yZC6kP/EnTAFFLuws25nCy4iS4wy1l4bDGvJRFtAcdLBl+M9FOLIWM6p/TcliezYmaezWGb1i+VgxghJ3uB/mg=="], - "@napi-rs/canvas-win32-arm64-msvc": ["@napi-rs/canvas-win32-arm64-msvc@0.1.100", "", { "os": "win32", "cpu": "arm64" }, "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw=="], + "@openclaw/fs-safe-linux-x64-musl": ["@openclaw/fs-safe-linux-x64-musl@0.26.0", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-kxcOv7ANmdpHXD5PdNrRFrbcesZ04x9T4JYNV55eKDbiIgK4Xe2Uo9GmaMcGouDeTrX0Oh+subsOZtUXZnFeFg=="], - "@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.100", "", { "os": "win32", "cpu": "x64" }, "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA=="], + "@openclaw/fs-safe-win32-arm64-msvc": ["@openclaw/fs-safe-win32-arm64-msvc@0.26.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-cKUMfA1rlsimftCZrbxc1UfZ2h9u9ktoPTxY9LQkSOsTlnANVO83XBurY79rv4wq9xl4SgAppOTArP18ET7A6Q=="], - "@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="], + "@openclaw/fs-safe-win32-x64-msvc": ["@openclaw/fs-safe-win32-x64-msvc@0.26.0", "", { "os": "win32", "cpu": "x64" }, "sha512-kNZIpWO7ydMpVS0rFGrmux89LYakG+i/rKuxUIUeB/zK8S35MMAJKmif4w0Px4WSG/FYlxPogav0MXkvgd0/yw=="], - "@openclaw/fs-safe": ["@openclaw/fs-safe@0.3.0", "", { "optionalDependencies": { "jszip": "^3.10.1", "tar": "7.5.13" } }, "sha512-uIBE441CIt1kIURoP9qRGKZ8LkGyfD9ZzeESjwAd29ZPWtghws/5GR3Pjb67jKdcJHP1I6roNXcvnhzAU7lHlA=="], + "@openclaw/proxyline": ["@openclaw/proxyline@0.4.0", "", { "peerDependencies": { "undici": ">=8.5.0 <9" } }, "sha512-Yd32LmKmu1kHrc7Wt8OHK0z+Tjc52fOfWYHl2znIGqskPrC/YaIKUgrhG4x7/oAemGMwBWHf3Eb3iaMKpZ/otg=="], - "@openclaw/proxyline": ["@openclaw/proxyline@0.3.3", "", { "peerDependencies": { "undici": ">=8.3.0 <9" } }, "sha512-sftHnW69NHQqLjCxBTvQ8f/eQl+peZ5pHCBQtuTWBbeuYRHZ0/GXVTmw/O/YKsShMbqPWhJB0UYtPPdvCUSS8w=="], + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.44.0", "", {}, "sha512-E3JkOlMBi3N8OGGkbl7tFyqk2MAS6/lySRZBK3Mu7AzjF1fT8oIChH9ChE48SUWzDn9Kdwta+G/p5LJ4xW4CLQ=="], "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], @@ -214,40 +250,66 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.1", "", {}, "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg=="], + "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], + "@silvia-odwyer/photon-node": ["@silvia-odwyer/photon-node@0.3.4", "", {}, "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA=="], "@sinclair/typebox": ["@sinclair/typebox@0.34.47", "", {}, "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw=="], - "@smithy/core": ["@smithy/core@3.24.5", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-Kt8phUg45M15EjhYAbZ+fFikYneijLu9Liugz8ZsYz2i8j0hzGv27LWKpEHYRfvj+LyCOSijpcR/2i8RouV+cA=="], + "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], - "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-yiF8xHpdkaTfzLVqFzsP6WvNghEK+qZzLYWFD13L2SsFhbXwBGlxdocKF95qjr7s5lE5NRage+EJFK4mAsx88Q=="], + "@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="], - "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.4.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-SK3VMeH0fibgdTg2QeB+O4p7Yy/2E5HBOHJeC58FshkDdeuX8lOgO7PfjYfLyPLP1ch55j91cQqKBzDS0mRjSQ=="], + "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="], - "@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="], + "@trycua/cua-driver": ["@trycua/cua-driver@0.32.0", "", { "dependencies": { "@ubjs/core": "0.31.0-3", "@ubjs/node": "0.31.0-3" }, "optionalDependencies": { "@trycua/cua-driver-darwin-arm64": "0.32.0", "@trycua/cua-driver-darwin-x64": "0.32.0", "@trycua/cua-driver-linux-arm64-gnu": "0.32.0", "@trycua/cua-driver-linux-x64-gnu": "0.32.0", "@trycua/cua-driver-win32-arm64-msvc": "0.32.0", "@trycua/cua-driver-win32-x64-msvc": "0.32.0" } }, "sha512-lg53Ayp2PuI7RdI7NvHerD7Y8/EzSZnfxHkBd9E2xei3XkP4tcmZaVAu10qK9jkAhhTTIwz0wC6pe4IJDza18A=="], - "@smithy/signature-v4": ["@smithy/signature-v4@5.4.5", "", { "dependencies": { "@smithy/core": "^3.24.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-QBJKWGqIknH0dc9LWpfH1mkdokAx6iXYN3UcQ3eY6uIEyScuoQAhfl94ge7ozUy9WgFUdE8xsvwBjaYBbWmPNA=="], + "@trycua/cua-driver-darwin-arm64": ["@trycua/cua-driver-darwin-arm64@0.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wSUwXMj/KJPi+SEy3PfrN94p2ji8TOlIxQn4kPw8GG0NtiVqtfdOA7kOcjLZZeeJdTlS/r0PKKlghG+5JrC9PQ=="], - "@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + "@trycua/cua-driver-darwin-x64": ["@trycua/cua-driver-darwin-x64@0.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-9Q61a7XHSPycuT0fTQtmTT+fbXkVEL05iHgaRv+OtYHTyzJG1KVpTjntJsSlaQgD7NVl1uAapumZ9gMmvrOhuQ=="], - "@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + "@trycua/cua-driver-linux-arm64-gnu": ["@trycua/cua-driver-linux-arm64-gnu@0.32.0", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-E3fJdJYnfguFbEK9VRqqVnT8yMZZKTSxZz08kmF7DAXnKNQ7mfQTdqNeC1qCrx5JuIRyPp7dyBCTQdUAVqEAaA=="], - "@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@trycua/cua-driver-linux-x64-gnu": ["@trycua/cua-driver-linux-x64-gnu@0.32.0", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-br78WwTofTHMAq7HZgKUDYvjLXZsLF2tUX5lKniJ20D6GXq41m5PHakuFBRAJFvA6wAdpoqZE7TsrMxnFbyMog=="], - "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="], + "@trycua/cua-driver-win32-arm64-msvc": ["@trycua/cua-driver-win32-arm64-msvc@0.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-HrxAEGWTf5IO5PudG8apCUW3wnJFTYnCAxfR4PKDzRWBcFdc/fEPW4S3qrYL7i8St8gLPoPSasOgAmLm2InxBQ=="], - "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + "@trycua/cua-driver-win32-x64-msvc": ["@trycua/cua-driver-win32-x64-msvc@0.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-gOcMNjdL42z1QhRFz8ZMIkfmsLWqsqE72RChO9NSj9eeH8XNK31RKZv+KONhCxfL9Hq1sfM2dgozQ33qxFiYlQ=="], + + "@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="], "@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], + "@ubjs/core": ["@ubjs/core@0.31.0-3", "", {}, "sha512-39XrJgUZ2VVb561sSnkXPhczNoeBsNiSRArecsV0JE7CJq69ajFkcn9/tBAUS2NpgHkLIDU+z6Ks2+1wXnboxg=="], + + "@ubjs/node": ["@ubjs/node@0.31.0-3", "", { "optionalDependencies": { "@ubjs/node-darwin-arm64": "0.31.0-3", "@ubjs/node-darwin-x64": "0.31.0-3", "@ubjs/node-linux-arm64-gnu": "0.31.0-3", "@ubjs/node-linux-arm64-musl": "0.31.0-3", "@ubjs/node-linux-x64-gnu": "0.31.0-3", "@ubjs/node-linux-x64-musl": "0.31.0-3", "@ubjs/node-win32-arm64-msvc": "0.31.0-3", "@ubjs/node-win32-x64-msvc": "0.31.0-3" } }, "sha512-qNMpi2LICNwxGXZyRF8fSDBSpbezyZbEsydrbiMPJOmtOWr4tmZIEl7jkWGHVGShoBvHfFo4eHp5B4UVP928Cg=="], + + "@ubjs/node-darwin-arm64": ["@ubjs/node-darwin-arm64@0.31.0-3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GGQVPLkVo4Gc8qVLW4IGvS8bjl8eHXyeP4a97ntGmsAdXwE5gsS29o8xUEFROjhwHKD+9sgVeblCSWVG3CpHsw=="], + + "@ubjs/node-darwin-x64": ["@ubjs/node-darwin-x64@0.31.0-3", "", { "os": "darwin", "cpu": "x64" }, "sha512-2sc47u4XFYOsbmP5EW+Gx8m/yGrYnfFDFQm6+kz7goSWTNg84eEiz3COs9HKJDVuNJ5Khv5XipTO8CFadMLXCw=="], + + "@ubjs/node-linux-arm64-gnu": ["@ubjs/node-linux-arm64-gnu@0.31.0-3", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-YStVXhYz/5jvlWf/p4fhiVT72unYAbGugifFC9QmO/+hnroQDAQ5t8SARbsc15G4olMcamdIB+GETiUB7gmaYg=="], + + "@ubjs/node-linux-arm64-musl": ["@ubjs/node-linux-arm64-musl@0.31.0-3", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-Izp4nvfy/LmibzFowAztkoDOksCR2fb2zl6fh1ojR1HEsg0rAGruxtI8d3fn8DI0lBXwqmn6SF///oD4mFNJPQ=="], + + "@ubjs/node-linux-x64-gnu": ["@ubjs/node-linux-x64-gnu@0.31.0-3", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-Xdm21blyg5U/kW6s7OMvgrr8coGTkUlt26DVR9x8gKISif+E3YwdEskbFScWqystAiJnfjw7xHEc8UMu0Qlz7Q=="], + + "@ubjs/node-linux-x64-musl": ["@ubjs/node-linux-x64-musl@0.31.0-3", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-fFQ9BWS6i2LUH9SJgD9oEiKXXo/say59vHy7usFe1t7C2xvwvP34f5SuxXmWP9R8fHyA0aC4kIZ+TTwyHSv1Kw=="], + + "@ubjs/node-win32-arm64-msvc": ["@ubjs/node-win32-arm64-msvc@0.31.0-3", "", { "os": "win32", "cpu": "arm64" }, "sha512-ID6rSz1NmPsWTNBBNAw4OnJ5Dj8pcbtNJtdPB3OxcGigLBd/e0x7buhSI7os6Mo5iYtEdCynBRQHFJwub5XSPg=="], + + "@ubjs/node-win32-x64-msvc": ["@ubjs/node-win32-x64-msvc@0.31.0-3", "", { "os": "win32", "cpu": "x64" }, "sha512-wevs+Y+szwcCUT8IJFbB4/1nfxyRv/51l8oG7FGUPWD1xLPyuHfJBG27C+PDeC7KRzes/2n6aLo4DGZbr/LYTw=="], + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], @@ -258,8 +320,6 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "asn1.js": ["asn1.js@5.4.1", "", { "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "safer-buffer": "^2.1.0" } }, "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA=="], "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], @@ -272,13 +332,11 @@ "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], - "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + "boolbase": ["boolbase@2.0.0", "", {}, "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA=="], "bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="], - "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], - - "brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + "brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="], "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], @@ -292,19 +350,19 @@ "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], - "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - - "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "chalk": ["chalk@6.0.1", "", {}, "sha512-/Ce6KNm3vIbWdMlNna6RVIZ/ICQxnJxCicet5LBKK9ZffBkqzDw0xh9EiKSljdRtiIQ1S1z4YgcscUUGzNCWrA=="], "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "clawpdf": ["clawpdf@0.3.2", "", { "bin": { "clawpdf": "dist/cli.js" } }, "sha512-1JudW0rZ5B7O2E9+cgnU5F4As7K6HZ3/s/3CHUXm5uG0+965uPOk11gvhmprpwXGJaRXhrmywZ1WWc5a+GZ7TQ=="], + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + "commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="], "content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="], @@ -322,9 +380,9 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + "css-select": ["css-select@7.0.0", "", { "dependencies": { "boolbase": "^2.0.0", "css-what": "^8.0.0", "domhandler": "^6.0.1", "domutils": "^4.0.2", "nth-check": "^3.0.1" } }, "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g=="], - "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "css-what": ["css-what@8.0.0", "", {}, "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw=="], "cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="], @@ -336,19 +394,19 @@ "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], - "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], "dijkstrajs": ["dijkstrajs@1.0.3", "", {}, "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="], - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + "dom-serializer": ["dom-serializer@3.1.1", "", { "dependencies": { "domelementtype": "^3.0.0", "domhandler": "^6.0.0", "entities": "^8.0.0" } }, "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw=="], - "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + "domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], - "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + "domhandler": ["domhandler@6.0.1", "", { "dependencies": { "domelementtype": "^3.0.0" } }, "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg=="], - "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + "domutils": ["domutils@4.0.2", "", { "dependencies": { "dom-serializer": "^3.0.0", "domelementtype": "^3.0.0", "domhandler": "^6.0.0" } }, "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA=="], - "dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="], + "dotenv": ["dotenv@18.0.5", "", { "bin": { "dotenv": "dist/index.cjs" } }, "sha512-aBrGvt6KhjxbEnatqMWOMidftwsrCiCvqh1yNIGB9QyF0J+VcWkKDMsvYOEm7ZS82oiV+BT1sTOtIlAmUlTpwQ=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -360,7 +418,7 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "entities": ["entities@8.1.0", "", {}, "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], @@ -368,6 +426,8 @@ "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], + "esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], @@ -380,6 +440,8 @@ "eventsource-parser": ["eventsource-parser@3.1.0", "", {}, "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg=="], + "execa": ["execa@10.0.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "figures": "^6.1.0", "get-stream": "^9.0.1", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.3.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "which-command": "^0.1.0", "yoctocolors": "^2.1.2" } }, "sha512-ge98qjkRK4IB7tL7Ju/6qmm5LHoH1eEMt5FNZrz3f4UIYhF28lggX20z3FaX1sgc67msLEn0N0BscOs29iuwyw=="], + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], "express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="], @@ -388,6 +450,8 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="], + "fast-string-truncated-width": ["fast-string-truncated-width@3.0.3", "", {}, "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="], "fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="], @@ -396,13 +460,11 @@ "fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="], - "fast-xml-builder": ["fast-xml-builder@1.2.0", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="], - - "fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="], - "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], - "file-type": ["file-type@22.0.1", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.5", "token-types": "^6.1.2", "uint8array-extras": "^1.5.0" } }, "sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA=="], + "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], + + "file-type": ["file-type@22.1.1", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.5", "token-types": "^6.1.2", "uint8array-extras": "^1.5.0" } }, "sha512-sEB0oStmeLGtpmSAD88RDNuLsvhv4iC3u0lE25CUvfCULvj49xoQ3l3K525Vn+ZzsZ6DOLajQCV6RmhwwhqiJg=="], "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], @@ -428,7 +490,7 @@ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], "google-auth-library": ["google-auth-library@10.6.2", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw=="], @@ -436,50 +498,56 @@ "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - - "grammy": ["grammy@1.43.0", "", { "dependencies": { "@grammyjs/types": "3.27.3", "abort-controller": "^3.0.0", "debug": "^4.4.3", "node-fetch": "^2.7.0" } }, "sha512-7dYm06A945mXuIk/5HUlSjeyIYChW8vCEiU2dkOKKqJJzwAWxTkCc91Eqbz7TgODh2rtFFKWI/fekowWHOkmjQ=="], + "grammy": ["grammy@1.46.0", "", { "dependencies": { "@grammyjs/types": "5.0.0", "abort-controller": "^3.0.0", "debug": "^4.4.3", "node-fetch": "^2.7.0" } }, "sha512-/8Qw+iisrUdOMk+p2mjEHouMm/BBdBEN1DHh16wiTpRUZkxDG3PxexdjCvR+wvK3LWPdrEvnQbdrwpU954sPhg=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], - "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], + "highlight.js": ["highlight.js@11.12.0", "", {}, "sha512-nbfWpyRMcMrPMmDwJB+dhX/eiaPKtc2RB+0QZskqJ3WjRA/FDS0e9hZrx8EC/lbEv8gXy98FcDbNa/dspAaJMg=="], "hono": ["hono@4.12.23", "", {}, "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA=="], - "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + "hosted-git-info": ["hosted-git-info@10.1.1", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ=="], "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], - "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + "htmlparser2": ["htmlparser2@12.0.0", "", { "dependencies": { "domelementtype": "^3.0.0", "domhandler": "^6.0.0", "domutils": "^4.0.2", "entities": "^8.0.0" } }, "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw=="], "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - "http_ece": ["http_ece@1.2.0", "", {}, "sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA=="], "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], + + "iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + "ignore": ["ignore@7.0.12", "", {}, "sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg=="], "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], - "ipaddr.js": ["ipaddr.js@2.4.0", "", {}, "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ=="], + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], + + "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -488,6 +556,10 @@ "jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="], + "js-tokens": ["js-tokens@10.0.0", "", {}, "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="], @@ -498,19 +570,19 @@ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="], + "jszip": ["jszip@3.10.2", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-3l+rb15IOWtUhU0H5MFqES/T6Kh7abYwjosBey/vD6hDt8zoEffkSC5Ws5SGtgVw3gBx2NEbhTeSW1+kWkpyTQ=="], "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], - "kysely": ["kysely@0.29.2", "", {}, "sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg=="], + "koffi": ["koffi@3.3.2", "", { "optionalDependencies": { "@koromix/koffi-android-arm64": "3.3.2", "@koromix/koffi-android-x64": "3.3.2", "@koromix/koffi-darwin-arm64": "3.3.2", "@koromix/koffi-darwin-x64": "3.3.2", "@koromix/koffi-freebsd-arm64": "3.3.2", "@koromix/koffi-freebsd-ia32": "3.3.2", "@koromix/koffi-freebsd-x64": "3.3.2", "@koromix/koffi-linux-arm": "3.3.2", "@koromix/koffi-linux-arm64": "3.3.2", "@koromix/koffi-linux-ia32": "3.3.2", "@koromix/koffi-linux-loong64": "3.3.2", "@koromix/koffi-linux-ppc64": "3.3.2", "@koromix/koffi-linux-riscv64": "3.3.2", "@koromix/koffi-linux-x64": "3.3.2", "@koromix/koffi-openbsd-arm64": "3.3.2", "@koromix/koffi-openbsd-ia32": "3.3.2", "@koromix/koffi-openbsd-x64": "3.3.2", "@koromix/koffi-win32-arm64": "3.3.2", "@koromix/koffi-win32-ia32": "3.3.2", "@koromix/koffi-win32-x64": "3.3.2" }, "hasInstallScript": true }, "sha512-f9Rrcmpy7lQs0ayJfhaxiG5OLp1aZjXKOFLXo7Gax6snJRKmdpYnYEOkpQ7ImCBrbvOdzFT06EP+FaLZv35W7Q=="], - "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], + "kysely": ["kysely@0.29.6", "", {}, "sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg=="], - "linkedom": ["linkedom@0.18.12", "", { "dependencies": { "css-select": "^5.1.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q=="], + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], - "linkify-it": ["linkify-it@5.0.1", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg=="], + "linkedom": ["linkedom@0.18.13", "", { "dependencies": { "css-select": "^7.0.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.1.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw=="], "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], @@ -518,14 +590,10 @@ "lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="], - "markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], - - "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], + "marked": ["marked@18.0.11", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], - "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], @@ -536,7 +604,7 @@ "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], - "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -548,95 +616,89 @@ "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "node-addon-api": ["node-addon-api@8.8.0", "", {}, "sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA=="], - "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], "node-edge-tts": ["node-edge-tts@1.2.10", "", { "dependencies": { "https-proxy-agent": "^7.0.1", "ws": "^8.13.0", "yargs": "^17.7.2" }, "bin": { "node-edge-tts": "bin.js" } }, "sha512-bV2i4XU54D45+US0Zm1HcJRkifuB3W438dWyuJEHLQdKxnuqlI1kim2MOvR6Q3XUQZvfF9PoDyR1Rt7aeXhPdQ=="], "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + "npm": ["npm@12.2.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^10.0.3", "@npmcli/config": "^11.2.0", "@npmcli/fs": "^6.0.0", "@npmcli/git": "^8.0.0", "@npmcli/map-workspaces": "^6.0.0", "@npmcli/metavuln-calculator": "^10.0.0", "@npmcli/package-json": "^8.0.0", "@npmcli/promise-spawn": "^10.0.0", "@npmcli/redact": "^5.0.0", "@npmcli/run-script": "^11.0.0", "@sigstore/tuf": "^5.0.0", "abbrev": "^5.0.0", "archy": "~1.0.0", "bin-links": "^7.0.0", "cacache": "^21.0.1", "chalk": "^5.6.2", "ci-info": "^4.4.0", "diff": "^8.0.2", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", "glob": "^13.0.6", "graceful-fs": "^4.2.11", "hosted-git-info": "^10.1.1", "ini": "^7.0.0", "init-package-json": "^9.0.0", "is-cidr": "^7.0.0", "json-parse-even-better-errors": "^6.0.0", "libnpmaccess": "^11.0.0", "libnpmdiff": "^9.0.3", "libnpmexec": "^11.0.3", "libnpmfund": "^8.0.3", "libnpmorg": "^9.0.0", "libnpmpack": "^10.0.3", "libnpmpublish": "^12.0.1", "libnpmsearch": "^10.0.0", "libnpmteam": "^9.0.0", "libnpmversion": "^9.0.0", "make-fetch-happen": "^16.0.1", "minimatch": "^10.2.5", "minipass": "^7.1.3", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^13.0.0", "nopt": "^10.0.1", "npm-audit-report": "^8.0.0", "npm-install-checks": "^9.0.0", "npm-package-arg": "^14.0.0", "npm-pick-manifest": "^12.0.0", "npm-profile": "^13.0.1", "npm-registry-fetch": "^20.0.1", "npm-user-validate": "^5.0.0", "p-map": "^7.0.4", "pacote": "^22.0.0", "parse-conflict-json": "^6.0.0", "proc-log": "^7.0.0", "qrcode-terminal": "^0.12.0", "read": "^6.0.0", "semver": "^7.8.5", "spdx-expression-parse": "^4.0.0", "ssri": "^14.0.0", "supports-color": "^10.2.2", "tar": "^7.5.22", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", "validate-npm-package-name": "^8.0.0", "which": "^7.0.0" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" } }, "sha512-ZsJjKpTnlmSXOLLXiU1xDCzC4Wlok4IwZmh/aw2KUuXytU7q6qMv/cUT7MoeSf95Slwuw/lRXYefGzGCspHPNQ=="], - "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], + + "nth-check": ["nth-check@3.0.1", "", { "dependencies": { "boolbase": "^2.0.0" } }, "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + "obug": ["obug@2.2.1", "", {}, "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q=="], + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - "openai": ["openai@6.39.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-O61LIsimY3acVabwvomwFhwrnN36yvHY2quIfy9keEcFytGgWeV35yLHQ6NVMLSBxRpHmcg2yuhCnlu2HT4pLQ=="], + "openai": ["openai@7.27.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "undici": ">=5 <9", "ws": "^8.21.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "undici", "ws", "zod"] }, "sha512-QDo1FvnRDZn15YwGVOhT9vpyypDiLphkd/7a4mcURWf5upMoEetgA6o4DJeII+ZZkC6m6DvlilCwii3+ynDcTw=="], - "openclaw": ["openclaw@2026.5.26", "", { "dependencies": { "@agentclientprotocol/sdk": "0.22.1", "@clack/core": "1.3.1", "@clack/prompts": "1.4.0", "@earendil-works/pi-agent-core": "0.75.5", "@earendil-works/pi-ai": "0.75.5", "@earendil-works/pi-coding-agent": "0.75.5", "@earendil-works/pi-tui": "0.75.5", "@google/genai": "2.6.0", "@grammyjs/runner": "2.0.3", "@grammyjs/transformer-throttler": "1.2.1", "@homebridge/ciao": "1.3.8", "@lydell/node-pty": "1.2.0-beta.12", "@modelcontextprotocol/sdk": "1.29.0", "@mozilla/readability": "0.6.0", "@openclaw/fs-safe": "0.3.0", "@openclaw/proxyline": "0.3.3", "chalk": "5.6.2", "chokidar": "5.0.0", "commander": "14.0.3", "croner": "10.0.1", "dotenv": "17.4.2", "express": "5.2.1", "file-type": "22.0.1", "grammy": "1.43.0", "ipaddr.js": "2.4.0", "jiti": "2.7.0", "json5": "2.2.3", "jszip": "3.10.1", "kysely": "0.29.2", "linkedom": "0.18.12", "markdown-it": "14.1.1", "node-edge-tts": "1.2.10", "openai": "6.39.0", "pdfjs-dist": "5.7.284", "playwright-core": "1.60.0", "qrcode": "1.5.4", "quickjs-wasi": "2.2.0", "rastermill": "0.3.0", "tar": "7.5.15", "tokenjuice": "0.7.1", "tree-sitter-bash": "0.25.1", "tslog": "4.10.2", "typebox": "1.1.38", "typescript": "6.0.3", "undici": "8.3.0", "web-push": "3.6.7", "web-tree-sitter": "0.26.9", "ws": "8.21.0", "yaml": "2.9.0", "zod": "4.4.3" }, "optionalDependencies": { "sqlite-vec": "0.1.9" }, "bin": { "openclaw": "openclaw.mjs" } }, "sha512-ne6ESyXmspmWO7JlSAWFp1ACmk/um2bnEGnEkiHd4BK62XRUt82DBCCpBGcLsMKA+zNG9G938dA+zCNJCKvUFA=="], + "openclaw": ["openclaw@2026.10.9", "", { "dependencies": { "@agentclientprotocol/sdk": "1.7.0", "@anthropic-ai/sdk": "0.131.0", "@babel/generator": "8.0.6", "@babel/parser": "8.0.6", "@babel/traverse": "8.0.6", "@clack/core": "1.5.1", "@clack/prompts": "1.8.1", "@earendil-works/pi-tui": "1.0.0", "@google/genai": "2.27.0", "@grammyjs/transformer-throttler": "1.2.1", "@homebridge/ciao": "1.3.12", "@lydell/node-pty": "1.2.0-beta.15", "@mistralai/mistralai": "2.7.0", "@modelcontextprotocol/sdk": "1.32.0", "@mozilla/readability": "0.6.0", "@openclaw/ai": "2026.10.9", "@openclaw/fs-safe": "0.26.0", "@openclaw/proxyline": "0.4.0", "@silvia-odwyer/photon-node": "0.3.4", "@trycua/cua-driver": "0.32.0", "acorn": "8.18.0", "chalk": "6.0.1", "chrome-devtools-mcp": "1.10.1", "clawpdf": "0.3.2", "commander": "15.0.0", "croner": "10.0.1", "diff": "9.0.0", "dotenv": "18.0.5", "entities": "8.1.0", "esbuild": "0.28.2", "execa": "10.0.1", "express": "5.2.1", "file-type": "22.1.1", "grammy": "1.46.0", "highlight.js": "11.12.0", "hosted-git-info": "10.1.1", "htmlparser2": "12.0.0", "iconv-lite": "0.7.3", "ignore": "7.0.12", "import-meta-resolve": "4.2.0", "jiti": "2.7.0", "json5": "2.2.3", "jszip": "3.10.2", "koffi": "3.3.2", "kysely": "0.29.6", "linkedom": "0.18.13", "minimatch": "10.2.6", "node-edge-tts": "1.2.10", "npm": "12.2.0", "openai": "7.27.0", "p-limit": "7.3.3", "p-map": "7.0.8", "partial-json": "0.1.7", "playwright-core": "1.63.0", "qrcode": "1.5.4", "rastermill": "0.4.0", "semver": "7.8.5", "tar": "7.5.22", "tslog": "5.2.0", "typebox": "1.3.34", "undici": "8.11.2", "web-push": "3.6.7", "web-tree-sitter": "0.27.0", "ws": "8.22.0", "yaml": "2.9.1", "zod": "4.6.5" }, "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2", "@koromix/koffi-android-arm64": "3.3.2", "@koromix/koffi-android-x64": "3.3.2", "@koromix/koffi-darwin-arm64": "3.3.2", "@koromix/koffi-darwin-x64": "3.3.2", "@koromix/koffi-freebsd-arm64": "3.3.2", "@koromix/koffi-freebsd-ia32": "3.3.2", "@koromix/koffi-freebsd-x64": "3.3.2", "@koromix/koffi-linux-arm": "3.3.2", "@koromix/koffi-linux-arm64": "3.3.2", "@koromix/koffi-linux-ia32": "3.3.2", "@koromix/koffi-linux-loong64": "3.3.2", "@koromix/koffi-linux-ppc64": "3.3.2", "@koromix/koffi-linux-riscv64": "3.3.2", "@koromix/koffi-linux-x64": "3.3.2", "@koromix/koffi-openbsd-arm64": "3.3.2", "@koromix/koffi-openbsd-ia32": "3.3.2", "@koromix/koffi-openbsd-x64": "3.3.2", "@koromix/koffi-win32-arm64": "3.3.2", "@koromix/koffi-win32-ia32": "3.3.2", "@koromix/koffi-win32-x64": "3.3.2", "@lydell/node-pty-darwin-arm64": "1.2.0-beta.15", "@lydell/node-pty-darwin-x64": "1.2.0-beta.15", "@lydell/node-pty-linux-arm64": "1.2.0-beta.15", "@lydell/node-pty-linux-x64": "1.2.0-beta.15", "@lydell/node-pty-win32-arm64": "1.2.0-beta.15", "@lydell/node-pty-win32-x64": "1.2.0-beta.15", "@openclaw/fs-safe-darwin-arm64": "0.26.0", "@openclaw/fs-safe-darwin-x64": "0.26.0", "@openclaw/fs-safe-freebsd-arm64": "0.26.0", "@openclaw/fs-safe-freebsd-x64": "0.26.0", "@openclaw/fs-safe-linux-arm64-gnu": "0.26.0", "@openclaw/fs-safe-linux-arm64-musl": "0.26.0", "@openclaw/fs-safe-linux-x64-gnu": "0.26.0", "@openclaw/fs-safe-linux-x64-musl": "0.26.0", "@openclaw/fs-safe-win32-arm64-msvc": "0.26.0", "@openclaw/fs-safe-win32-x64-msvc": "0.26.0", "@trycua/cua-driver-darwin-arm64": "0.32.0", "@trycua/cua-driver-darwin-x64": "0.32.0", "@trycua/cua-driver-linux-arm64-gnu": "0.32.0", "@trycua/cua-driver-linux-x64-gnu": "0.32.0", "@trycua/cua-driver-win32-arm64-msvc": "0.32.0", "@trycua/cua-driver-win32-x64-msvc": "0.32.0", "@ubjs/node-darwin-arm64": "0.31.0-3", "@ubjs/node-darwin-x64": "0.31.0-3", "@ubjs/node-linux-arm64-gnu": "0.31.0-3", "@ubjs/node-linux-arm64-musl": "0.31.0-3", "@ubjs/node-linux-x64-gnu": "0.31.0-3", "@ubjs/node-linux-x64-musl": "0.31.0-3", "@ubjs/node-win32-arm64-msvc": "0.31.0-3", "@ubjs/node-win32-x64-msvc": "0.31.0-3", "sqlite-vec": "0.1.9", "sqlite-vec-darwin-arm64": "0.1.9", "sqlite-vec-darwin-x64": "0.1.9", "sqlite-vec-linux-arm64": "0.1.9", "sqlite-vec-linux-x64": "0.1.9", "sqlite-vec-windows-x64": "0.1.9" }, "hasInstallScript": true, "bin": { "openclaw": "openclaw.mjs" } }, "sha512-KbIl0/7an0/nKBo92FnJg7LFcEpFVQyOgSRfHNE9yxELg1Ebql7BmBsdLL+1dDOLZnQtuwjt6Hy45CCrmYdJNA=="], - "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "p-limit": ["p-limit@7.3.3", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ=="], "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + "p-map": ["p-map@7.0.8", "", {}, "sha512-MitaVsCuCFIvOLLPIU7NnfrZvS9H9h7kwMUkDo+T2pEISaJD48IV9S8iIdXB7PsvvdxyYcsSTTrr90XKsbulNw=="], + "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - "path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="], - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], - "pdfjs-dist": ["pdfjs-dist@5.7.284", "", { "optionalDependencies": { "@napi-rs/canvas": "^0.1.100" } }, "sha512-h4EdYQczmGhbOlqc3PPZwxevn7ApdWPbovAuWXOB/DjIyigSnwfy2oze7c6mRcSr9XgLp3eN3EeL4DyySTPMFw=="], - "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], - "playwright-core": ["playwright-core@1.60.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA=="], + "playwright-core": ["playwright-core@1.63.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg=="], "pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="], - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "pretty-ms": ["pretty-ms@9.3.1", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA=="], - "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "protobufjs": ["protobufjs@7.6.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], - "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], - "qrcode": ["qrcode@1.5.4", "", { "dependencies": { "dijkstrajs": "^1.0.1", "pngjs": "^5.0.0", "yargs": "^15.3.1" }, "bin": { "qrcode": "bin/qrcode" } }, "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg=="], "qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="], - "quickjs-wasi": ["quickjs-wasi@2.2.0", "", {}, "sha512-zQxXmQMrEoD3S+jQdYsloq4qAuaxKFHZj6hHqOYGwB2iQZH+q9e/lf5zQPXCKOk0WJuAjzRFbO4KwHIp2D05Iw=="], - "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], - "rastermill": ["rastermill@0.3.0", "", { "dependencies": { "@silvia-odwyer/photon-node": "0.3.4" } }, "sha512-4g2i0I7M5sba//lFBh19Wi0hDGw8o+isnt/BtEyqQXIZaYclhcNBwL/Fw/6gDCp7aaLwQHADuUvyHCB0Oat5Vw=="], + "rastermill": ["rastermill@0.4.0", "", { "dependencies": { "@silvia-odwyer/photon-node": "0.3.4" } }, "sha512-5WrZ6tuK54oVk45w/riFm0/VwTSieJ45c/zAGIaNtTKOSYL2zwx1r3VdBB2pKwlOO/tG+A9lmvN+3S6hwU6znA=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], - "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], @@ -644,6 +706,8 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], @@ -666,7 +730,7 @@ "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], @@ -686,6 +750,8 @@ "sqlite-vec-windows-x64": ["sqlite-vec-windows-x64@0.1.9", "", { "os": "win32", "cpu": "x64" }, "sha512-y3gEIyy/17bq2QFPQOWLE68TYWcRZkBQVA2XLrTPHNTOp55xJi/BBBmOm40tVMDMjtP+Elpk6UBUXdaq+46b0Q=="], + "standardwebhooks": ["standardwebhooks@1.1.1", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "fast-sha256": "^1.3.0" } }, "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -694,44 +760,40 @@ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="], + "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], "strtok3": ["strtok3@10.3.5", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA=="], - "tar": ["tar@7.5.15", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="], + "tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="], - "tokenjuice": ["tokenjuice@0.7.1", "", { "bin": { "tokenjuice": "dist/cli/main.js" } }, "sha512-eO048hm9UcGHASjYkIWEij8QN68amGp+S1nJyo685qB1/ol+VGEYjPglcVPvCbJbZyFHvI+BBAMvOfnqYCtpsQ=="], - "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "tree-sitter-bash": ["tree-sitter-bash@0.25.1", "", { "dependencies": { "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.25.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-7hMytuYIMoXOq24yRulgIxthE9YmggZIOHCyPTTuJcu6EU54tYD+4G39cUb28kxC6jMf/AbPfWGLQtgPTdh3xw=="], - "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tslog": ["tslog@4.10.2", "", {}, "sha512-XuELoRpMR+sq8fuWwX7P0bcj+PRNiicOKDEb3fGNURhxWVyykCi9BNq7c4uVz7h7P0sj8qgBsr5SWS6yBClq3g=="], + "tslog": ["tslog@5.2.0", "", { "bin": { "tslog": "esm/subpaths/cli.js" } }, "sha512-bD0FpBIFZ1OInp7uzQmEn1SJe6feTkVTCudw/27ILuISbVZtTryXqauxyCWTa1I8ZgTm9OGQ6YrJPKM+6QTeJA=="], "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], - "typebox": ["typebox@1.1.38", "", {}, "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA=="], + "typebox": ["typebox@1.3.34", "", {}, "sha512-wbnzrXXDW8xEFHDZZs2jo1MkhaYlKAY4FRhpBc1+2LF1fZVBGCXGdLEhA/Z/NBbgzJMFfeM8m7elKPa/+KxaUQ=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], - "uhyphen": ["uhyphen@0.2.0", "", {}, "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA=="], "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], - "undici": ["undici@8.3.0", "", {}, "sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q=="], + "undici": ["undici@8.11.2", "", {}, "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], @@ -742,7 +804,7 @@ "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], - "web-tree-sitter": ["web-tree-sitter@0.26.9", "", {}, "sha512-YJwSHANl6XFgeEjB8nitgj0qZYt5gkIesJ4w2srS2wcLB4GUa4xcOkM0YaMsU6WNR53YVIkDSY7Ej4pf3IXtCA=="], + "web-tree-sitter": ["web-tree-sitter@0.27.0", "", {}, "sha512-XK08gj6RwTMQatAG7uVRP8MunqotL/XC19vHgkSPKmELgbGPBj4ECvB8haHOUnyj6ls2B8t42UTro14zxGgAHg=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -750,58 +812,380 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which-command": ["which-command@0.1.0", "", { "bin": { "which-command": "cli.js" } }, "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA=="], + "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], - - "xml-naming": ["xml-naming@0.1.0", "", {}, "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="], + "ws": ["ws@8.22.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg=="], "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + "yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], + + "yoctocolors": ["yoctocolors@2.2.0", "", {}, "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg=="], + + "zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1054.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.14", "@aws-sdk/nested-clients": "^3.997.12", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-hG9YKApmZOw+drJ9Nuoaf/OvC8e5W1+3eoLeN5p2uVCZRWsv27teIS0b4kiH6Sfv3WMmamqYJxmE2WMwyp/L/A=="], + "@google/genai/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "@mistralai/mistralai/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], - "@earendil-works/pi-ai/@google/genai": ["@google/genai@1.52.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q=="], + "@mistralai/mistralai/zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], - "@earendil-works/pi-ai/openai": ["openai@6.26.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA=="], + "@modelcontextprotocol/sdk/zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], - "@openclaw/fs-safe/tar": ["tar@7.5.13", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng=="], + "body-parser/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], "gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], - "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + "linkedom/htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + + "node-edge-tts/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "npm/@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="], + + "npm/@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + + "npm/@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", { "bundled": true }, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], + + "npm/@npmcli/agent": ["@npmcli/agent@5.0.2", "", { "dependencies": { "agent-base": "^9.0.0", "http-proxy-agent": "^9.0.0", "https-proxy-agent": "^9.0.0", "lru-cache": "^11.2.1", "socks-proxy-agent": "^10.0.0" } }, "sha512-EkzGmEsgbQ1rqWkRJe2P0oQHx/ylZozDUNPMXCklLuSFL3GY+QyEfBUjhjCsgGXzh4OGpnHvkboSQgczjP/jJg=="], + + "npm/@npmcli/arborist": ["@npmcli/arborist@10.0.4", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^6.0.0", "@npmcli/installed-package-contents": "^5.0.0", "@npmcli/map-workspaces": "^6.0.0", "@npmcli/metavuln-calculator": "^10.0.0", "@npmcli/name-from-folder": "^5.0.0", "@npmcli/node-gyp": "^6.0.0", "@npmcli/package-json": "^8.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^5.0.0", "@npmcli/run-script": "^11.0.0", "bin-links": "^7.0.0", "cacache": "^21.0.1", "common-ancestor-path": "^2.0.0", "diff": "^8.0.2", "hosted-git-info": "^10.1.1", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^10.0.1", "npm-install-checks": "^9.0.0", "npm-package-arg": "^14.0.0", "npm-pick-manifest": "^12.0.0", "npm-registry-fetch": "^20.0.1", "pacote": "^22.0.0", "parse-conflict-json": "^6.0.0", "proc-log": "^7.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^14.0.0", "treeverse": "^3.0.0", "validate-npm-package-name": "^8.0.0", "walk-up-path": "^4.0.0" }, "bundled": true, "bin": { "arborist": "bin/index.js" } }, "sha512-QMVxWzrv+XmBjjBGIqEQTQ1uKzfAA7YTT0Q7AaJ5MvmlsfWLffV5mt9pZGUAugHg4q/lIMHzkhFgWMgqFo87kA=="], + + "npm/@npmcli/config": ["@npmcli/config@11.2.0", "", { "dependencies": { "@npmcli/map-workspaces": "^6.0.0", "@npmcli/package-json": "^8.0.0", "ci-info": "^4.0.0", "ini": "^7.0.0", "nopt": "^10.0.1", "proc-log": "^7.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-PZtUL2rXqThZUT5KGsbVEGdrJswgBoY56X8hXIozwoayHC/rRsaJCIz4nsBzHJvNpCjGEbufJqStaqB7Qdd4ww=="], + + "npm/@npmcli/fs": ["@npmcli/fs@6.0.0", "", { "dependencies": { "semver": "^7.3.5" }, "bundled": true }, "sha512-AheOs4swKka/XLtht6xxJDPezlQ7K2IYQ9Y8lST4JLDjnralnWuMM9AE2CdVcgQJ5omrXhsRzM7F7aYmeZBvKQ=="], + + "npm/@npmcli/git": ["@npmcli/git@8.0.0", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^10.0.0", "ini": "^7.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^12.0.0", "proc-log": "^7.0.0", "semver": "^7.3.5", "which": "^7.0.0" }, "bundled": true }, "sha512-5P1oo+TbxZNAiiMBtpzHA8QyEGh5D69LYLexNWJEDXLdxnAZvT/SLitGJBXxjtCE4ftAcFOS/Tu2185MeIjooQ=="], + + "npm/@npmcli/installed-package-contents": ["@npmcli/installed-package-contents@5.0.0", "", { "dependencies": { "npm-bundled": "^6.0.0", "npm-normalize-package-bin": "^6.0.0" }, "bin": { "installed-package-contents": "bin/index.js" } }, "sha512-6Ay12sf2Lh7U1ifvnS1mq7TZFeh/rXHMXye+kV7jQrANIubaoVcleeh4HdFumxhsRYwm9OaHycB5lYmSwGrcIQ=="], + + "npm/@npmcli/map-workspaces": ["@npmcli/map-workspaces@6.0.0", "", { "dependencies": { "@npmcli/name-from-folder": "^5.0.0", "@npmcli/package-json": "^8.0.0", "glob": "^13.0.0", "minimatch": "^10.0.3" }, "bundled": true }, "sha512-Dsex7XBea0BoFRbfALMbNuaNqeI3kbZJxiBMQhFvPUNluv0yEeKMd5FLIXy0NCsOuGMYQkLa+i219CadnoqLbg=="], + + "npm/@npmcli/metavuln-calculator": ["@npmcli/metavuln-calculator@10.0.0", "", { "dependencies": { "cacache": "^21.0.1", "json-parse-even-better-errors": "^6.0.0", "pacote": "^22.0.0", "proc-log": "^7.0.0", "semver": "^7.3.5" }, "bundled": true }, "sha512-fC56lpGOae+unrFx6hoiWeWa0/4q+bLhOQTSrB65qcy+Zm34i1OdBcevAQFJJdUB/3i9uXw7PjdrrRjt0KSKXw=="], + + "npm/@npmcli/name-from-folder": ["@npmcli/name-from-folder@5.0.0", "", {}, "sha512-Mua2i5asmOn4sGGAsANS9Guamo7sgUd4BihhQWzlNGz6l/Ki23CzC2oGe4I94r2k/39ImCjDLbyu/rSJr/SXoA=="], + + "npm/@npmcli/node-gyp": ["@npmcli/node-gyp@6.0.0", "", {}, "sha512-MFakpea4pcZNlHSTbMi15HK8RY8zl2UpgDtxhZCWOer+KRN3x7HFIMk/fKpOMgR55L4LIcA2qn8IHeyABhIFtw=="], + + "npm/@npmcli/package-json": ["@npmcli/package-json@8.0.0", "", { "dependencies": { "@npmcli/git": "^8.0.0", "glob": "^13.0.0", "hosted-git-info": "^10.1.1", "json-parse-even-better-errors": "^6.0.0", "proc-log": "^7.0.0", "semver": "^7.5.3", "spdx-expression-parse": "^4.0.0" }, "bundled": true }, "sha512-agNZzYQ18MR0wKp3Emg1q5QbcC8CXigYp3Z3CvB0Sax9Ge9aF4cVyyuSG+5SbACSrZUKTvMjVULWiE1RJA38wg=="], + + "npm/@npmcli/promise-spawn": ["@npmcli/promise-spawn@10.0.1", "", { "dependencies": { "which": "^7.0.0" }, "bundled": true }, "sha512-IstFcKAoEIZ7olS9iTwBsyNOZkIturafO2da9ocSP3LifRlm1+sxuo8IVM5phg5sNe0tNYLT0ZqCBRTLNzz0AA=="], + + "npm/@npmcli/query": ["@npmcli/query@5.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ=="], + + "npm/@npmcli/redact": ["@npmcli/redact@5.0.0", "", { "bundled": true }, "sha512-3zcN5Q3yEmeyxXBzqB6fXPQFzYa2ROsGFSr69W0ArXIAGJqxl/aFECOVPD2kbkYPm0U/EHxFKgclK3UA9WQg5A=="], + + "npm/@npmcli/run-script": ["@npmcli/run-script@11.0.0", "", { "dependencies": { "@npmcli/node-gyp": "^6.0.0", "@npmcli/package-json": "^8.0.0", "@npmcli/promise-spawn": "^10.0.0", "node-gyp": "^13.0.0", "proc-log": "^7.0.0" }, "bundled": true }, "sha512-leBRl6F5F0TvWut8m1/aZcMTUHi2vXjKeMJ/Ik1lW7Q7Yy16Dhtkklu+cEqQww1p1NeLnUNzV3+uwpzqRcy9vw=="], + + "npm/@sigstore/bundle": ["@sigstore/bundle@5.0.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-wefjygudENbzbQMks1t5u34EP0fFoD0XvaEP7DOUP/sXKvogzEJYFw5E6pegGyp3onGWzVEYKVa3bNZWyTYX+A=="], + + "npm/@sigstore/core": ["@sigstore/core@4.0.1", "", {}, "sha512-9v5hRjujn5NXq8o7XFEUgLyAtdr5Iisb4pzM05u3K61IS5q3hP3luWAndk0RkPPLTUFoTbg7Vb84UQ1ZQeajWQ=="], + + "npm/@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.5.2", "", {}, "sha512-SQqvFMt4V78fdjcDdYX6HbiVSOR4QK3ZgwCa2KOsopAgPIHy1rU5UDUmzLl02r5oyyaYcYHR1hpwDRk/yUe+Mw=="], + + "npm/@sigstore/sign": ["@sigstore/sign@5.0.0", "", { "dependencies": { "@gar/promise-retry": "^1.0.2", "@sigstore/bundle": "^5.0.0", "@sigstore/core": "^4.0.0", "@sigstore/protobuf-specs": "^0.5.0", "make-fetch-happen": "^16.0.0", "proc-log": "^7.0.0" } }, "sha512-DSFivqz9/i5AkwZ5fq0YdjaJlc4o1WeS2Zffon0kqtChx0vy4W9NOjkEet9bF2vkzOufX72eVH8kZBIGtcBp1w=="], + + "npm/@sigstore/tuf": ["@sigstore/tuf@5.0.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0", "tuf-js": "^6.0.0" }, "bundled": true }, "sha512-Zyqg9tcHps3uRAlKHLNmsW4ohsUZAjb9G+31r7lg0ICh/JOcadzmJsIRdjKljlRHpaR0K4aJ2kXXIdywdcdMlA=="], + + "npm/@sigstore/verify": ["@sigstore/verify@4.1.2", "", { "dependencies": { "@sigstore/bundle": "^5.0.0", "@sigstore/core": "^4.0.1", "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-BfD9eLrz3A/DG58aSgfgZYmIR6V9Yw96QVN/frtu2bEH7ctSTk2TDvHU12un3JsDPBTqTNkqkIkucjxljpOFqQ=="], + + "npm/@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], - "openclaw/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + "npm/@tufjs/models": ["@tufjs/models@5.0.1", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.2.6" } }, "sha512-wacy5twbJk36R0dTcGE3qmPNNH095bFselAYNrVCzf0Byd0t3+Qzk3+3gn/rHGP10FuHBVk4swg4aczr1c2z/g=="], - "p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + "npm/abbrev": ["abbrev@5.0.0", "", { "bundled": true }, "sha512-/XrFJgzQQQHpti1raDJC6m4ws6aNktmjBlhk8Fdlk7LwCEuDoieEJJY9OFHjfiFJFFRM2tK+Ky/IsfbbmlMu1w=="], - "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + "npm/agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + + "npm/aproba": ["aproba@2.1.0", "", {}, "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="], + + "npm/archy": ["archy@1.0.0", "", { "bundled": true }, "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="], + + "npm/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "npm/bin-links": ["bin-links@7.0.1", "", { "dependencies": { "cmd-shim": "^9.0.0", "npm-normalize-package-bin": "^6.0.0", "proc-log": "^7.0.0", "read-cmd-shim": "^7.0.0", "write-file-atomic": "^8.0.0" }, "bundled": true }, "sha512-lgxd7FtxW02eSuafotQOGEQf1iGfDExMz2BRaL+e1tU5xTLx+vvSVA5oHIO6B1tR91LDKcWqYGsktUHdFMtHHQ=="], + + "npm/binary-extensions": ["binary-extensions@3.2.0", "", {}, "sha512-DjR9rgAOMQn9TrUHzijJUtvoKviDRvFxuIyqZrubxHqRpQN9OzfXrrLivm7xb3q8oJSKsiuBor4bAS2wafLnVQ=="], + + "npm/brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="], + + "npm/cacache": ["cacache@21.0.1", "", { "dependencies": { "@npmcli/fs": "^6.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^14.0.0" }, "bundled": true }, "sha512-pTwz/uj3Jyp6WXdJ6fWhR+7LVxVs6RyroQSn7KJwHsSxXuyGSp0pcMVcwSwTpCFq1X2YG8QBe0W+vN+cr0SwzA=="], + + "npm/chalk": ["chalk@5.6.2", "", { "bundled": true }, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "npm/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + + "npm/ci-info": ["ci-info@4.4.0", "", { "bundled": true }, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "npm/cidr-regex": ["cidr-regex@7.1.2", "", {}, "sha512-D8F5oI0M5PagJvTjyycBf7LG+LufTNLrg0WY9J0cPUuG1dIWC2hFvl5SNQr8btm4Qtl7bS7IPvhw/+30IyhBmA=="], + + "npm/cmd-shim": ["cmd-shim@9.0.2", "", {}, "sha512-xVHoI+wNrM4tDB9iC1idf/8D0tYnVimlBp/5zHW+x1sGjjRD69NvR9th3Z1JAYGN/BTW4he6aZFYV6kzy+k+jw=="], + + "npm/common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], + + "npm/cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "npm/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "npm/diff": ["diff@8.0.4", "", { "bundled": true }, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + + "npm/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "npm/exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], + + "npm/fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", { "bundled": true }, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="], + + "npm/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "npm/fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" }, "bundled": true }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + + "npm/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" }, "bundled": true }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "npm/graceful-fs": ["graceful-fs@4.2.11", "", { "bundled": true }, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "npm/hosted-git-info": ["hosted-git-info@10.1.1", "", { "dependencies": { "lru-cache": "^11.1.0" }, "bundled": true }, "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ=="], + + "npm/http-cache-semantics": ["http-cache-semantics@4.3.0", "", {}, "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA=="], + + "npm/http-proxy-agent": ["http-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig=="], + + "npm/https-proxy-agent": ["https-proxy-agent@9.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "proxy-agent-negotiate": "1.1.0" } }, "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA=="], + + "npm/iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], + + "npm/ignore-walk": ["ignore-walk@9.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-tCBEZV2z2FNpIDl2vrhiWzIHzs4qOAuIDEO85eS02vZ3L1U3P56qpPL8GuGGAijDktAEaq2swMkO/Fmbo7YmfQ=="], + + "npm/ini": ["ini@7.0.0", "", { "bundled": true }, "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w=="], + + "npm/init-package-json": ["init-package-json@9.0.0", "", { "dependencies": { "@npmcli/package-json": "^8.0.0", "npm-package-arg": "^14.0.0", "promzard": "^4.0.0", "read": "^6.0.0", "semver": "^7.7.2", "validate-npm-package-name": "^8.0.0" }, "bundled": true }, "sha512-aYDqz4jgX1plB2GDCFYStlOh67QXVpAIeNgDq8rRGVDYMvLE39yYlf8+CjYY2chVOVfqLsSIycFYznHWozZ9CA=="], + + "npm/ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], + + "npm/is-cidr": ["is-cidr@7.0.3", "", { "dependencies": { "cidr-regex": "^7.1.1" }, "bundled": true }, "sha512-lNg3nOT+LHKO4vughx1zLUpWUWkt87qu1dBzVrzzOpliIx6gnSIUCXvQfV0FzSHCm6p4ym7BhbakusmZQEC6pw=="], + + "npm/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "npm/json-parse-even-better-errors": ["json-parse-even-better-errors@6.0.0", "", { "bundled": true }, "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A=="], + + "npm/json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], + + "npm/jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], + + "npm/just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="], + + "npm/just-diff-apply": ["just-diff-apply@5.5.0", "", {}, "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw=="], + + "npm/libnpmaccess": ["libnpmaccess@11.0.0", "", { "dependencies": { "npm-package-arg": "^14.0.0", "npm-registry-fetch": "^20.0.1" }, "bundled": true }, "sha512-qku5OaTtCv7f4xq5lmZMh4H6pd9WRalww3WF4PEk/aFo1Bpi7/IRCzy28EQBvyrprhzZGifbpM378U4waB9/0Q=="], + + "npm/libnpmdiff": ["libnpmdiff@9.0.4", "", { "dependencies": { "@npmcli/arborist": "^10.0.4", "@npmcli/installed-package-contents": "^5.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", "minimatch": "^10.0.3", "npm-package-arg": "^14.0.0", "pacote": "^22.0.0", "tar": "^7.5.1" }, "bundled": true }, "sha512-yMXW5Uu/ELhrHmnMQLZ1JXZxErCHCr/eq6ubMzV8ZCzzVOLTOK3ItTld+dYJTmqfM7w9tiuhYtI6ScWA+n88Dw=="], + + "npm/libnpmexec": ["libnpmexec@11.0.4", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/arborist": "^10.0.4", "@npmcli/package-json": "^8.0.0", "@npmcli/run-script": "^11.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^14.0.0", "pacote": "^22.0.0", "proc-log": "^7.0.0", "read": "^6.0.0", "semver": "^7.3.7", "signal-exit": "^4.1.0", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-zpgxYS2Ob56x7YZtK+lb9LPnIYa/leDLKXb/InokZBfcZxaQp4POTCUOge6BKsvhgGcN4ySNsv94GK5JsxhWjQ=="], + + "npm/libnpmfund": ["libnpmfund@8.0.4", "", { "dependencies": { "@npmcli/arborist": "^10.0.4" }, "bundled": true }, "sha512-T4WQsQ/m5Tn+ovr+bfJc+DDTEeBcQvdaHDKDHpLKqIv27bbztdVCDQWIOiAfXhQaqOWkLmHGM/qAi6PeTC8x9Q=="], + + "npm/libnpmorg": ["libnpmorg@9.0.0", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^20.0.1" }, "bundled": true }, "sha512-cPiStT2aFEGu5/so+VZlQDb5AuhiYFsEAHBOCjuXWbBQP2EcGmr6doOUNRV17L2HNTw1Wvqnq2+nSrINdBphAg=="], + + "npm/libnpmpack": ["libnpmpack@10.0.4", "", { "dependencies": { "@npmcli/arborist": "^10.0.4", "@npmcli/run-script": "^11.0.0", "npm-package-arg": "^14.0.0", "pacote": "^22.0.0" }, "bundled": true }, "sha512-I42lWghQC3wow13OBuGr/1zxNlKMe8bc4q8bgqSlyFOceuoPnJH4c0+mcNL7e6hOLshgzBbSILo2TmLCSMgGig=="], + + "npm/libnpmpublish": ["libnpmpublish@12.0.1", "", { "dependencies": { "@npmcli/package-json": "^8.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^14.0.0", "npm-registry-fetch": "^20.0.1", "proc-log": "^7.0.0", "semver": "^7.3.7", "sigstore": "^5.0.0", "ssri": "^14.0.0" }, "bundled": true }, "sha512-gG32Hgikbb8mx+c+b2MKseuQcwKbiIl7wM4a5+scxuRtu/Q7L/fbywMyLD4naUfL0yexdKWzfi6kglMz6BGOWQ=="], + + "npm/libnpmsearch": ["libnpmsearch@10.0.0", "", { "dependencies": { "npm-registry-fetch": "^20.0.1" }, "bundled": true }, "sha512-dNDPxoeIY8IC3ftpOaMGbaHMcxngu4PEyTdR5XZnWgh62QaCucUVK+7z7i2igIEUiOe4HJbZw/sU/5VOCCjkmA=="], + + "npm/libnpmteam": ["libnpmteam@9.0.0", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^20.0.1" }, "bundled": true }, "sha512-zZhmjQlRZDUyoHC1/Knc5lG7NVLZfu3wEGaotvILo6xKxE/njDDeZVJa2CS/cmZZ5ki7rSXg+0GNlqusiHqPTQ=="], + + "npm/libnpmversion": ["libnpmversion@9.0.0", "", { "dependencies": { "@npmcli/git": "^8.0.0", "@npmcli/run-script": "^11.0.0", "json-parse-even-better-errors": "^6.0.0", "proc-log": "^7.0.0", "semver": "^7.3.7" }, "bundled": true }, "sha512-v7vTEPiODFT6ciWXoVWEpsD5fPFNoyQ35OvrZgK7F0ZjJxR23l+UBvGzkhPGYc8Fft39k90Ej+l3/zCGu5tzcg=="], + + "npm/lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="], + + "npm/make-fetch-happen": ["make-fetch-happen@16.0.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^5.0.0", "@npmcli/redact": "^5.0.0", "cacache": "^21.0.0", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^6.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^7.0.0", "ssri": "^14.0.0" }, "bundled": true }, "sha512-uUv1yxHzaKVVEPfcFeGSNov/Cehjv08ovlY8ImTljgL7Q+SiA0dAYLQ6SYVa2kkKqNj4Y3aZEI7xv2teadie0A=="], + + "npm/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" }, "bundled": true }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + + "npm/minipass": ["minipass@7.1.3", "", { "bundled": true }, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "npm/minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + + "npm/minipass-fetch": ["minipass-fetch@6.0.0", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^2.0.0", "minizlib": "^3.0.1" }, "optionalDependencies": { "iconv-lite": "^0.7.2" } }, "sha512-AWI8bKapGmgx/J0E6IGYSKj8TiHebZkmKWSs8raPSw8KXwgEAJ+Bw3+LSdXHR6T/RHKAWCOYk2MiLrYluaUU6w=="], + + "npm/minipass-flush": ["minipass-flush@1.0.7", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA=="], + + "npm/minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" }, "bundled": true }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + + "npm/minipass-sized": ["minipass-sized@2.0.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA=="], + + "npm/minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], + + "npm/ms": ["ms@2.1.3", "", { "bundled": true }, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "npm/mute-stream": ["mute-stream@4.0.0", "", {}, "sha512-gSrprq0fJ3EiOErzjdIZrjysVVmJ4uu1QWfCDss5LypA5OXvrMje5Ym5z6V6RLyJ2eF87lasX7t6a0AnFvZblg=="], + + "npm/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "npm/node-gyp": ["node-gyp@13.1.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "nopt": "^10.0.0", "proc-log": "^7.0.0", "semver": "^7.3.5", "tar": "^7.5.7", "tinyglobby": "^0.2.12", "undici": "^8.4.1", "which": "^7.0.0" }, "bundled": true, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-FpNzOLFACKG0oRBYbZ5WOeWD1EqRTIWX90MaRIWTO18lVYPx8fqIjrdS3pihjnCkSmgop6zVGkSqg1vXZLksuw=="], + + "npm/nopt": ["nopt@10.0.1", "", { "dependencies": { "abbrev": "^5.0.0" }, "bundled": true, "bin": { "nopt": "bin/nopt.js" } }, "sha512-df3sBr/6ax9hSGuC3CspvLlbnX8cP5L5nZwXF8cGN8l0zSWR6BvzmQ6jPUKjvo6+/xdpkNvEcucBNUdBeeV13g=="], + + "npm/npm-audit-report": ["npm-audit-report@8.0.0", "", { "bundled": true }, "sha512-LrRtLB4NKdXin5dw4yxcES8GDXncfoVVcYzkn8bdwc0etpHmxtKKwwI1YTWpQ9+lEmzEnZo10Lzb11QLxuuBnA=="], + + "npm/npm-bundled": ["npm-bundled@6.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^6.0.0" } }, "sha512-EqdodKEW6pYM+dPxA66TZQfMEqVDiuzjDM9edSjuPI1mXUbUJwVxkgqMZSJvs8RTXz2CGq8HUol/AffTZX5g8w=="], + + "npm/npm-install-checks": ["npm-install-checks@9.0.0", "", { "dependencies": { "semver": "^7.1.1" }, "bundled": true }, "sha512-t05Izcgi7p15cpldqoiXYpjzlkTTvBw33sgjmL/JjcvtV0ydbm2O4iEXO8A6smqComu5FAQhUas86HTMQ6Z1Uw=="], + + "npm/npm-normalize-package-bin": ["npm-normalize-package-bin@6.0.0", "", {}, "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw=="], + + "npm/npm-package-arg": ["npm-package-arg@14.0.0", "", { "dependencies": { "hosted-git-info": "^10.1.0", "proc-log": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^8.0.0" }, "bundled": true }, "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q=="], + + "npm/npm-packlist": ["npm-packlist@11.3.0", "", { "dependencies": { "glob": "^13.0.6", "ignore-walk": "^9.0.0", "proc-log": "^7.0.0" } }, "sha512-cS1yVkyriZgQAbiK8PtwhZHEtsFOsKHsCg5Ww2ONckAvXIspgqd6o4WirOzvkupU24iMRZ4xtO4kb2iK2rbnag=="], + + "npm/npm-pick-manifest": ["npm-pick-manifest@12.0.0", "", { "dependencies": { "npm-install-checks": "^9.0.0", "npm-normalize-package-bin": "^6.0.0", "npm-package-arg": "^14.0.0", "semver": "^7.3.5" }, "bundled": true }, "sha512-8Fs3YLrnNOhrCdPNZy18MzNgVC58LTDAFzq1FdZO/p3BHeCC/coz+t4F5Pxabys8HJpyTUorMea26GkXsb4J/Q=="], + + "npm/npm-profile": ["npm-profile@13.0.1", "", { "dependencies": { "npm-registry-fetch": "^20.0.0", "proc-log": "^7.0.0" }, "bundled": true }, "sha512-buFDWLwggBSiT5wsjhoSHNvGy+KHaBI5n8ilvSOBkrQUbEsyKYdCV6PloJGFsQ53ZqXCqhwds/8dbvyHQuH3IA=="], + + "npm/npm-registry-fetch": ["npm-registry-fetch@20.0.1", "", { "dependencies": { "@npmcli/redact": "^5.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^16.0.0", "minipass": "^7.0.2", "minipass-fetch": "^6.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^14.0.0", "proc-log": "^7.0.0" }, "bundled": true }, "sha512-vzc1svxw/kw1IRjFsLi6gaxe1Olqm88V0tIfu2u5raL0b1gChe6ZEXNkyUlKxUC7s/egt5NxZHkbY18tMKKLfQ=="], + + "npm/npm-user-validate": ["npm-user-validate@5.0.0", "", { "bundled": true }, "sha512-yZKlDPJOukQIRzXL+qYyuczXtnQTSF732zT6umGfy/8DxXEAdnv22eA/UpBsC0Fv9s4yfDYkK1pLnCPB0GxsqQ=="], + + "npm/p-map": ["p-map@7.0.8", "", { "bundled": true }, "sha512-MitaVsCuCFIvOLLPIU7NnfrZvS9H9h7kwMUkDo+T2pEISaJD48IV9S8iIdXB7PsvvdxyYcsSTTrr90XKsbulNw=="], + + "npm/pacote": ["pacote@22.0.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^8.0.0", "@npmcli/installed-package-contents": "^5.0.0", "@npmcli/package-json": "^8.0.0", "@npmcli/promise-spawn": "^10.0.0", "@npmcli/run-script": "^11.0.0", "cacache": "^21.0.1", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^14.0.0", "npm-packlist": "^11.2.0", "npm-pick-manifest": "^12.0.0", "npm-registry-fetch": "^20.0.1", "proc-log": "^7.0.0", "sigstore": "^5.0.0", "ssri": "^14.0.0", "tar": "^7.4.3" }, "bundled": true, "bin": { "pacote": "bin/index.js" } }, "sha512-pu51B21E5u3MXD+ujjYO09ppqXmFLph1iPR17ySgKoakAj/iDApcMoQprUff8Wj96emV2tFhMRFkCvEMFnIDPQ=="], + + "npm/parse-conflict-json": ["parse-conflict-json@6.0.0", "", { "dependencies": { "json-parse-even-better-errors": "^6.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" }, "bundled": true }, "sha512-JIdsITvN0yVRpYxiip9DpCduYi75AryIDSCf6ez/Yul6PV46L0B/8SxSvLiMmWiUZKopLrD1BZgexxCfufoT9w=="], + + "npm/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "npm/picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], + + "npm/postcss-selector-parser": ["postcss-selector-parser@7.1.7", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-wWBro/7hJ40ye6TPiXkUQoXKCw23xSsjriUvqd7Uls9Sso3oLiON1flc18cCdnjgCRXw4fBVqUJJeOdDTh3P3g=="], + + "npm/proc-log": ["proc-log@7.0.0", "", { "bundled": true }, "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg=="], + + "npm/proggy": ["proggy@4.0.0", "", {}, "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ=="], + + "npm/promise-all-reject-late": ["promise-all-reject-late@1.0.1", "", {}, "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw=="], + + "npm/promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="], + + "npm/promzard": ["promzard@4.0.0", "", { "dependencies": { "read": "^6.0.0" } }, "sha512-zqf38XGznB+ECFHQPGt0RNQCh0YF+r5iac0EZloSQlEWDxt0vCS39PEtUShBJOZU0tcJ+USPvmnyGo+3CEFwcQ=="], + + "npm/proxy-agent-negotiate": ["proxy-agent-negotiate@1.1.0", "", { "peerDependencies": { "kerberos": "^2.0.0" }, "optionalPeers": ["kerberos"] }, "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ=="], + + "npm/qrcode-terminal": ["qrcode-terminal@0.12.0", "", { "bundled": true, "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="], + + "npm/read": ["read@6.0.0", "", { "dependencies": { "mute-stream": "^4.0.0" }, "bundled": true }, "sha512-Tg/LaEke7h9SDbp0xJJj53oa4s1VPPySVnxQF9nUS9DgA25M/ZCLk7RVF1kHjytC87XbkgQKmQ/79+DQgEIqLA=="], + + "npm/read-cmd-shim": ["read-cmd-shim@7.0.1", "", {}, "sha512-GhAsW4iJS0xNqv8P6HocT3gb5HCKHtEBKLIN7fE2oWr27jGIEihu48lXyGGeexkbiLv1XAbwyXvgjYMfT81kZA=="], + + "npm/safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "npm/semver": ["semver@7.8.5", "", { "bundled": true, "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "npm/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "npm/sigstore": ["sigstore@5.0.0", "", { "dependencies": { "@sigstore/bundle": "^5.0.0", "@sigstore/core": "^4.0.0", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^5.0.0", "@sigstore/tuf": "^5.0.0", "@sigstore/verify": "^4.0.0" } }, "sha512-hJqJfoG/e4qFQaauQL00c6J6FrHLBGKtkFvW3JbTSIEFOhLrSjdSM/gWd/yUOfYo/gsERehTXGC1VZWX+9X4Dg=="], + + "npm/smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + + "npm/socks": ["socks@2.8.10", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ=="], + + "npm/socks-proxy-agent": ["socks-proxy-agent@10.1.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ=="], + + "npm/spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "npm/spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" }, "bundled": true }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="], + + "npm/spdx-license-ids": ["spdx-license-ids@3.0.24", "", {}, "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ=="], + + "npm/ssri": ["ssri@14.0.0", "", { "dependencies": { "minipass": "^7.0.3" }, "bundled": true }, "sha512-jQxKI0yx0ZnTKrqjKkLDV2DXkBQn3k49JVmVqDGcDwKDtGDbImD/GXsq04KD0VVzCQQ9wZJYal3RwR1GzWTSow=="], + + "npm/supports-color": ["supports-color@10.2.2", "", { "bundled": true }, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + + "npm/tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "bundled": true }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], + + "npm/text-table": ["text-table@0.2.0", "", { "bundled": true }, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], + + "npm/tiny-relative-date": ["tiny-relative-date@2.0.2", "", { "bundled": true }, "sha512-rGxAbeL9z3J4pI2GtBEoFaavHdO4RKAU54hEuOef5kfx5aPqiQtbhYktMOTL5OA33db8BjsDcLXuNp+/v19PHw=="], + + "npm/tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + + "npm/treeverse": ["treeverse@3.0.0", "", { "bundled": true }, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], + + "npm/tuf-js": ["tuf-js@6.0.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.3", "@tufjs/models": "5.0.1", "debug": "^4.4.3" } }, "sha512-o59N1PU8xk0bBV3HpJ4jjwldIeze17yXW1XTv02CEEKdC3E/tnJDU3CPWDNT4IZpkx9Srv9v1DJZ+JTdo46THg=="], + + "npm/undici": ["undici@8.11.2", "", {}, "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ=="], + + "npm/util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "npm/validate-npm-package-name": ["validate-npm-package-name@8.0.0", "", { "bundled": true }, "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ=="], + + "npm/walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + + "npm/which": ["which@7.0.0", "", { "dependencies": { "isexe": "^4.0.0" }, "bundled": true, "bin": { "node-which": "bin/which.js" } }, "sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA=="], + + "npm/write-file-atomic": ["write-file-atomic@8.0.0", "", { "dependencies": { "signal-exit": "^4.0.1" } }, "sha512-dYwyZredl67GyLLIHJnRM3h2PcOmN5SkcgC7eM5DPDEOEl6dLFqVrMg3F1Ea32usj4VSVZtd2H4MtKTNOf6nPg=="], + + "npm/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + + "openclaw/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.32.0", "", { "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-8BviX/hK4Gd2eL1KdTwm0gfl4d3wdoErW0Jd00h6nomUAtk6IJk5vwQJc6kfWtJTzN5OEV/lgIiJKI8fiDGAlA=="], + + "openclaw/chrome-devtools-mcp": ["chrome-devtools-mcp@1.10.1", "", { "peerDependencies": { "@blackwell-systems/gcf": "^2.2.2", "@toon-format/toon": "^4.1.0" }, "optionalPeers": ["@blackwell-systems/gcf", "@toon-format/toon"], "bundled": true, "bin": { "chrome-devtools": "build/src/bin/chrome-devtools.js", "chrome-devtools-mcp": "build/src/bin/chrome-devtools-mcp.js" } }, "sha512-Klw6HWDqHC/XS1JwZldd2r49aUhbUJN9m9Mvcx4SEueIPXtzuQX+QelxAViobv8YUkDZ7HWDrmViR6LeYK0wAw=="], + + "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "qrcode/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + "raw-body/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "linkedom/htmlparser2/domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "linkedom/htmlparser2/domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "linkedom/htmlparser2/domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "linkedom/htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "npm/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "npm/minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "npm/minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "openclaw/@modelcontextprotocol/sdk/zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + "qrcode/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], "qrcode/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], "qrcode/yargs/yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + "linkedom/htmlparser2/domutils/dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "npm/glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "npm/minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "npm/minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "qrcode/yargs/cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "linkedom/htmlparser2/domutils/dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], } } diff --git a/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts b/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts index 22394855f..6e23e8cf2 100644 --- a/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts +++ b/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts @@ -1,13 +1,14 @@ import { beforeEach, describe, expect, it, jest } from "bun:test" -import type { ContextEngine } from "openclaw/plugin-sdk" import type { BmClient } from "../bm-client.ts" import type { BasicMemoryConfig } from "../config.ts" import { BasicMemoryContextEngine, MAX_ASSEMBLE_RECALL_CHARS, } from "./basic-memory-context-engine.ts" +import type { ContextEngine } from "./types.ts" type AgentMessage = Parameters[0]["messages"][number] +type CommitTurnParams = Parameters>[0] function makeConfig(overrides?: Partial): BasicMemoryConfig { return { @@ -32,6 +33,39 @@ function makeMessages( return messages as AgentMessage[] } +function makeCommitTurnParams( + advancementKey: string, + messages: Array>, +): CommitTurnParams { + const anchor = { + agentId: "main", + sessionId: "session-commit", + sessionKey: "agent:main:main", + storePath: "/tmp/sessions", + generation: "g1", + rawSeq: 1, + effectiveParentId: null, + activeMessagePosition: 0, + } + return { + advancementKey, + admission: { + ...anchor, + entryId: "user-entry", + logicalTurnId: "turn-1", + role: "user", + }, + terminal: { ...anchor, entryId: "assistant-entry", rawSeq: 2 }, + messages: makeMessages(messages), + sessionId: "session-commit", + } +} + +const CURRENT_TURN = [ + { role: "user", content: "Current question with enough detail" }, + { role: "assistant", content: "Current answer with enough detail" }, +] + describe("BasicMemoryContextEngine", () => { let mockClient: { search: jest.Mock @@ -305,7 +339,7 @@ describe("BasicMemoryContextEngine", () => { "agent/subagents/subagent-handoff-agent-test-subagent-child-1", "append", expect.stringContaining( - "Durable conversation capture continues through the normal afterTurn path.", + "Durable conversation capture continues through the normal turn commit path.", ), ) }) @@ -397,4 +431,84 @@ describe("BasicMemoryContextEngine", () => { }), ).resolves.toBeUndefined() }) + + // OpenClaw 2026.10+ degrades an engine to "legacy" for durable turns unless + // it declares both semantics and implements commitTurn (#1880). The host's + // check is internal to OpenClaw, so this asserts the same two conditions. + it("declares the transcript semantics OpenClaw requires for durable turns", () => { + const engine = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig(), + ) + + expect(engine.info.transcriptSemantics).toEqual({ + currentTurnFence: "before-current-turn-entry-v1", + turnAdvancementIdempotency: "atomic-idempotent-v1", + }) + expect(typeof engine.commitTurn).toBe("function") + }) + + it("captures the committed turn keyed by its advancement key", async () => { + mockClient.indexConversation.mockResolvedValue("committed") + const engine = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig(), + ) + + const result = await engine.commitTurn( + makeCommitTurnParams("advance-1", CURRENT_TURN), + ) + + expect(result).toEqual({ status: "committed" }) + expect(mockClient.indexConversation).toHaveBeenCalledWith( + "Current question with enough detail", + "Current answer with enough detail", + { turnKey: "advance-1" }, + ) + }) + + it("reports a retried advancement key as a duplicate", async () => { + mockClient.indexConversation.mockResolvedValue("duplicate") + const engine = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig(), + ) + + const result = await engine.commitTurn( + makeCommitTurnParams("advance-1", CURRENT_TURN), + ) + + expect(result).toEqual({ status: "duplicate" }) + }) + + it("propagates commitTurn capture failures so the host retries", async () => { + mockClient.indexConversation.mockRejectedValue(new Error("BM down")) + const engine = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig(), + ) + + await expect( + engine.commitTurn(makeCommitTurnParams("advance-2", CURRENT_TURN)), + ).rejects.toThrow("BM down") + }) + + it("acknowledges commitTurn without writing when there is nothing to capture", async () => { + const disabled = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig({ autoCapture: false }), + ) + const strict = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig({ captureMinChars: 500 }), + ) + + await expect( + disabled.commitTurn(makeCommitTurnParams("advance-3", CURRENT_TURN)), + ).resolves.toEqual({ status: "committed" }) + await expect( + strict.commitTurn(makeCommitTurnParams("advance-4", CURRENT_TURN)), + ).resolves.toEqual({ status: "committed" }) + expect(mockClient.indexConversation).not.toHaveBeenCalled() + }) }) diff --git a/integrations/openclaw/context-engine/basic-memory-context-engine.ts b/integrations/openclaw/context-engine/basic-memory-context-engine.ts index 345d6dd5f..3944f196d 100644 --- a/integrations/openclaw/context-engine/basic-memory-context-engine.ts +++ b/integrations/openclaw/context-engine/basic-memory-context-engine.ts @@ -1,16 +1,17 @@ -import type { - AssembleResult, - BootstrapResult, - CompactResult, - ContextEngine, - SubagentSpawnPreparation, -} from "openclaw/plugin-sdk" import { delegateCompactionToRuntime } from "openclaw/plugin-sdk/core" import type { BmClient } from "../bm-client.ts" import type { BasicMemoryConfig } from "../config.ts" import { selectCaptureTurn } from "../hooks/capture.ts" import { loadRecallState } from "../hooks/recall.ts" import { log } from "../logger.ts" +import type { + AssembleResult, + BootstrapResult, + CommitTurnResult, + CompactResult, + ContextEngine, + SubagentSpawnPreparation, +} from "./types.ts" export const MAX_ASSEMBLE_RECALL_CHARS = 1200 const TRUNCATED_RECALL_SUFFIX = "\n\n[Basic Memory recall truncated]" @@ -20,6 +21,7 @@ const MAX_SUBAGENT_RECALL_CHARS = 800 type BootstrapParams = Parameters>[0] type AssembleParams = Parameters[0] type AfterTurnParams = Parameters>[0] +type CommitTurnParams = Parameters>[0] type CompactParams = Parameters[0] type PrepareSubagentSpawnParams = Parameters< NonNullable @@ -98,7 +100,7 @@ function buildSubagentCompletionUpdate(params: { }): string { const statusLine = params.reason === "completed" - ? "Child run completed. Durable conversation capture continues through the normal afterTurn path." + ? "Child run completed. Durable conversation capture continues through the normal turn commit path." : `Child run ended with reason: ${params.reason}.` return [ @@ -118,6 +120,18 @@ export class BasicMemoryContextEngine implements ContextEngine { name: "Basic Memory Context Engine", version: "0.1.5", ownsCompaction: false, + // OpenClaw 2026.10+ runs an engine for durable turns only when it + // declares both semantics; otherwise the turn degrades to "legacy" and + // nothing is captured (#1880). + // - The fence holds because assemble() passes the host's messages through + // unchanged and the engine keeps no transcript of its own, so it never + // reads past the admitted user entry. + // - Advancement is idempotent because commitTurn() records the + // advancement key in the conversation note and skips keys it has seen. + transcriptSemantics: { + currentTurnFence: "before-current-turn-entry-v1", + turnAdvancementIdempotency: "atomic-idempotent-v1", + }, } as const private readonly sessionState = new Map() @@ -171,6 +185,39 @@ export class BasicMemoryContextEngine implements ContextEngine { } } + /** + * Capture one accepted turn on hosts with durable turn advancement. + * + * The host calls this instead of afterTurn() for admitted turns, and may + * call it again with the same advancement key after a crash. Errors + * propagate so the host keeps the turn queued and retries it. + */ + async commitTurn(params: CommitTurnParams): Promise { + if (!this.cfg.autoCapture) return { status: "committed" } + + // messages spans exactly the admitted user entry through the terminal + // entry, so the whole payload is the current turn. + const turn = selectCaptureTurn(params.messages, this.cfg.captureMinChars) + if (!turn) return { status: "committed" } + + log.debug( + `context-engine commitTurn: session=${params.sessionId} user=${turn.userText.length} assistant=${turn.assistantText.length}`, + ) + + const status = await this.client.indexConversation( + turn.userText, + turn.assistantText, + { turnKey: params.advancementKey }, + ) + return { status } + } + + /** + * Capture fallback for hosts that predate commitTurn(). + * + * Hosts that route a turn through commitTurn() skip afterTurn() for that + * turn, so the two paths never record the same exchange. + */ async afterTurn(params: AfterTurnParams): Promise { if (!this.cfg.autoCapture) return diff --git a/integrations/openclaw/context-engine/types.ts b/integrations/openclaw/context-engine/types.ts new file mode 100644 index 000000000..3f27a8059 --- /dev/null +++ b/integrations/openclaw/context-engine/types.ts @@ -0,0 +1,21 @@ +import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core" + +// OpenClaw 2026.10 dropped the bare "openclaw/plugin-sdk" entry point that used +// to export ContextEngine and its result types. Derive them from the public +// registerContextEngine signature so we depend only on plugin-sdk/core. +type ContextEngineFactory = Parameters< + OpenClawPluginApi["registerContextEngine"] +>[1] + +export type ContextEngine = Awaited> +export type AssembleResult = Awaited> +export type BootstrapResult = Awaited< + ReturnType> +> +export type CompactResult = Awaited> +export type SubagentSpawnPreparation = NonNullable< + Awaited>> +> +export type CommitTurnResult = Awaited< + ReturnType> +> diff --git a/integrations/openclaw/package.json b/integrations/openclaw/package.json index 1783ebb2b..370908ec3 100644 --- a/integrations/openclaw/package.json +++ b/integrations/openclaw/package.json @@ -80,8 +80,8 @@ "minGatewayVersion": "2026.5.2" }, "build": { - "openclawVersion": "2026.5.4", - "pluginSdkVersion": "2026.5.4" + "openclawVersion": "2026.10.9", + "pluginSdkVersion": "2026.10.9" }, "install": { "minHostVersion": ">=2026.5.2" @@ -90,7 +90,7 @@ "devDependencies": { "@biomejs/biome": "^2.4.6", "@types/node": "^20.0.0", - "openclaw": "^2026.5.4", + "openclaw": "^2026.10.6", "typescript": "^5.9.3" } } From 16a30828fc0629e795339e12a1015109d7db5bb9 Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 14:47:43 -0500 Subject: [PATCH 2/8] fix(integrations): ship OpenClaw context-engine types in the npm package package.json lists published files explicitly, and context-engine/types.ts (added in the previous commit) was missing. dist/ was complete, so the runtime entry worked, but hosts that load the TypeScript source entry (./index.ts) would fail to resolve the import. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/integrations/openclaw/package.json b/integrations/openclaw/package.json index 370908ec3..c2c61860b 100644 --- a/integrations/openclaw/package.json +++ b/integrations/openclaw/package.json @@ -15,6 +15,7 @@ "index.ts", "bm-client.ts", "context-engine/basic-memory-context-engine.ts", + "context-engine/types.ts", "config.ts", "logger.ts", "commands/cli.ts", From 1e29bb0ddbfa2ed16dcf4b695ea8f6ecf262ac48 Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 15:17:33 -0500 Subject: [PATCH 3/8] fix(integrations): skip OpenClaw heartbeat and silent turns in capture OpenClaw's heartbeat polls reach the context engine as ordinary turns, so each one was saved to the daily conversation note as "[OpenClaw heartbeat poll]" / "NO_REPLY". commitTurn() and afterTurn() now acknowledge heartbeat turns (isHeartbeat) and turns whose reply is the NO_REPLY silent token without recording them. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- .../basic-memory-context-engine.test.ts | 30 +++++++++++++++++++ .../basic-memory-context-engine.ts | 22 ++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts b/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts index 6e23e8cf2..df63d0c20 100644 --- a/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts +++ b/integrations/openclaw/context-engine/basic-memory-context-engine.test.ts @@ -511,4 +511,34 @@ describe("BasicMemoryContextEngine", () => { ).resolves.toEqual({ status: "committed" }) expect(mockClient.indexConversation).not.toHaveBeenCalled() }) + + it("skips heartbeat polls and silent replies on both capture paths", async () => { + const engine = new BasicMemoryContextEngine( + mockClient as unknown as BmClient, + makeConfig(), + ) + const heartbeat = [ + { role: "user", content: "[OpenClaw heartbeat poll]" }, + { role: "assistant", content: "NO_REPLY" }, + ] + + await expect( + engine.commitTurn({ + ...makeCommitTurnParams("advance-hb", CURRENT_TURN), + isHeartbeat: true, + }), + ).resolves.toEqual({ status: "committed" }) + await expect( + engine.commitTurn(makeCommitTurnParams("advance-silent", heartbeat)), + ).resolves.toEqual({ status: "committed" }) + await engine.afterTurn({ + sessionId: "session-hb", + sessionFile: "/tmp/session-hb.jsonl", + prePromptMessageCount: 0, + messages: makeMessages(CURRENT_TURN), + isHeartbeat: true, + }) + + expect(mockClient.indexConversation).not.toHaveBeenCalled() + }) }) diff --git a/integrations/openclaw/context-engine/basic-memory-context-engine.ts b/integrations/openclaw/context-engine/basic-memory-context-engine.ts index 3944f196d..97d9df375 100644 --- a/integrations/openclaw/context-engine/basic-memory-context-engine.ts +++ b/integrations/openclaw/context-engine/basic-memory-context-engine.ts @@ -17,6 +17,9 @@ export const MAX_ASSEMBLE_RECALL_CHARS = 1200 const TRUNCATED_RECALL_SUFFIX = "\n\n[Basic Memory recall truncated]" const SUBAGENT_HANDOFF_FOLDER = "agent/subagents" const MAX_SUBAGENT_RECALL_CHARS = 800 +// OpenClaw's reply for "nothing to say", used by heartbeat polls and silent +// maintenance turns. +const SILENT_REPLY_TOKEN = "NO_REPLY" type BootstrapParams = Parameters>[0] type AssembleParams = Parameters[0] @@ -55,6 +58,19 @@ function boundRecallContext(context: string): string { return `${trimmed}${TRUNCATED_RECALL_SUFFIX}` } +/** + * Heartbeat polls and silent replies are host housekeeping, not + * conversation, so they are acknowledged without being recorded. + */ +function isHousekeepingTurn( + isHeartbeat: boolean | undefined, + turn: { assistantText: string }, +): boolean { + return ( + isHeartbeat === true || turn.assistantText.trim() === SILENT_REPLY_TOKEN + ) +} + function slugifySessionKey(sessionKey: string): string { return sessionKey .toLowerCase() @@ -198,7 +214,9 @@ export class BasicMemoryContextEngine implements ContextEngine { // messages spans exactly the admitted user entry through the terminal // entry, so the whole payload is the current turn. const turn = selectCaptureTurn(params.messages, this.cfg.captureMinChars) - if (!turn) return { status: "committed" } + if (!turn || isHousekeepingTurn(params.isHeartbeat, turn)) { + return { status: "committed" } + } log.debug( `context-engine commitTurn: session=${params.sessionId} user=${turn.userText.length} assistant=${turn.assistantText.length}`, @@ -226,7 +244,7 @@ export class BasicMemoryContextEngine implements ContextEngine { selectCaptureTurn(newMessages, this.cfg.captureMinChars) ?? selectCaptureTurn(params.messages, this.cfg.captureMinChars) - if (!turn) return + if (!turn || isHousekeepingTurn(params.isHeartbeat, turn)) return log.debug( `context-engine afterTurn: session=${params.sessionId} user=${turn.userText.length} assistant=${turn.assistantText.length}`, From 2f554e175fece966447df83be81c67f26427d51d Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 14:51:13 -0500 Subject: [PATCH 4/8] fix(integrations): serve OpenClaw memory through registerMemoryCapability On OpenClaw 2026.10 the plugin's memory_search and memory_get never ran. The bundled Memory Core plugin registers both names even when another plugin owns the memory slot, so OpenClaw rejected ours ("plugin tool name conflict"). The plugin also never called registerMemoryCapability, so the host's memory consumers fell back to Memory Core's file index. Register an OpenClaw memory capability (memory/basic-memory-capability.ts): - providerRuntime: search, get, health and close over the shared BmClient. Gateway memory.search v2, memory.get, memory.status and doctor now read Basic Memory. Fused scores (0-1.3) are capped at 1 for the host's 0-1 minScore scale, and a missing note returns not_found while other failures propagate. - recallToolNames: search_notes, read_note, build_context for Active Memory. - providerFlushPlanResolver: a tools-arm pre-compaction flush that saves through write_note and edit_note instead of a workspace file. - promptBuilder: a system-prompt section pointing agents at search_notes. Without it OpenClaw fills the field from Memory Core, whose section points at its file-only memory_search. Remove the dead memory_search/memory_get registrations (tools/memory- provider.ts) and drop them from the plugin manifest. Show search scores as raw numbers ("score 1.18") in search_notes, /recall and the CLI. They were multiplied by 100 and shown as a percentage, so a strong match on both keyword and vector signals displayed as "118%". Docs: README, CLAUDE.md and DEVELOPMENT.md describe the capability; MEMORY_TASK_FLOW.md is marked superseded. Verified live on OpenClaw 2026.10.9: memory.status returns {providerId: openclaw-basic-memory, status: ready}; memory.search v2 and memory.get return Basic Memory notes, line windows and not_found; no tool name conflicts after a gateway restart. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/CLAUDE.md | 11 +- integrations/openclaw/DEVELOPMENT.md | 7 +- integrations/openclaw/MEMORY_TASK_FLOW.md | 2 + integrations/openclaw/README.md | 20 +- integrations/openclaw/bm-client.ts | 2 +- integrations/openclaw/commands/cli.ts | 2 +- integrations/openclaw/commands/slash.ts | 2 +- integrations/openclaw/index.test.ts | 15 + integrations/openclaw/index.ts | 20 +- .../memory/basic-memory-capability.test.ts | 202 +++++++++++ .../memory/basic-memory-capability.ts | 240 +++++++++++++ integrations/openclaw/openclaw.plugin.json | 2 - integrations/openclaw/package.json | 2 +- .../openclaw/tools/memory-provider.test.ts | 149 -------- .../openclaw/tools/memory-provider.ts | 336 ------------------ .../openclaw/tools/search-notes.test.ts | 10 +- integrations/openclaw/tools/search-notes.ts | 2 +- 17 files changed, 505 insertions(+), 519 deletions(-) create mode 100644 integrations/openclaw/memory/basic-memory-capability.test.ts create mode 100644 integrations/openclaw/memory/basic-memory-capability.ts delete mode 100644 integrations/openclaw/tools/memory-provider.test.ts delete mode 100644 integrations/openclaw/tools/memory-provider.ts diff --git a/integrations/openclaw/CLAUDE.md b/integrations/openclaw/CLAUDE.md index d8fc427e1..d028cada7 100644 --- a/integrations/openclaw/CLAUDE.md +++ b/integrations/openclaw/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code when working with the OpenClaw packag ## Project Overview -`@basicmemory/openclaw-basic-memory` is a TypeScript OpenClaw plugin that integrates [Basic Memory](https://github.com/basicmachines-co/basic-memory) with the OpenClaw agent framework. It lives under `integrations/openclaw/` in the monorepo, manages a persistent MCP stdio session to a `bm mcp` process, exposes 14 agent tools (including workspace/project management and cross-project operations), composited memory search/get providers, slash commands, CLI commands, and optional auto-capture of conversations. +`@basicmemory/openclaw-basic-memory` is a TypeScript OpenClaw plugin that integrates [Basic Memory](https://github.com/basicmachines-co/basic-memory) with the OpenClaw agent framework. It lives under `integrations/openclaw/` in the monorepo, manages a persistent MCP stdio session to a `bm mcp` process, exposes 12 agent tools (including workspace/project management and cross-project operations), registers an OpenClaw memory capability and context engine, slash commands, CLI commands, and optional auto-capture of conversations. ## Development Commands @@ -66,7 +66,14 @@ Central orchestration layer that: Each tool file exports a function that calls `api.registerTool()` with a TypeBox schema and handler. Tools delegate to `BmClient` methods and return OpenClaw-standard responses (`{ content: [{type: "text", text}], details? }`). - `search-notes.ts`, `read-note.ts`, `write-note.ts`, `edit-note.ts`, `delete-note.ts`, `move-note.ts`, `build-context.ts`, `list-memory-projects.ts`, `list-workspaces.ts`, `schema-validate.ts`, `schema-infer.ts`, `schema-diff.ts` — thin wrappers around `BmClient`; all content tools accept an optional `project` param for cross-project operations -- `memory-provider.ts` — composited `memory_search` + `memory_get` providers. `memory_search` queries 3 sources in parallel: MEMORY.md (grep), BM knowledge graph (FTS + vector), and active task notes (YAML frontmatter scan) + +### Memory capability (`memory/basic-memory-capability.ts`) + +Registered with `api.registerMemoryCapability`. OpenClaw 2026.10's bundled Memory Core plugin owns the `memory_search` and `memory_get` tool names, so the plugin does not register them. The capability supplies: +- `providerRuntime` — host-facing search, get, health and close over the shared `BmClient` (gateway `memory.search` v2, `memory.status`, doctor) +- `recallToolNames` — `search_notes`, `read_note`, `build_context` for Active Memory deep recall +- `providerFlushPlanResolver` — a tools-arm pre-compaction flush through `write_note` / `edit_note` +- `promptBuilder` — a system-prompt section steering agents to the Basic Memory tools ### Commands & Hooks diff --git a/integrations/openclaw/DEVELOPMENT.md b/integrations/openclaw/DEVELOPMENT.md index 855c48208..4c3b86a6a 100644 --- a/integrations/openclaw/DEVELOPMENT.md +++ b/integrations/openclaw/DEVELOPMENT.md @@ -118,8 +118,11 @@ openclaw-basic-memory/ │ ├── list-workspaces.ts # list_workspaces │ ├── schema-validate.ts # schema_validate │ ├── schema-infer.ts # schema_infer -│ ├── schema-diff.ts # schema_diff -│ └── memory-provider.ts # Composited memory_search + memory_get +│ └── schema-diff.ts # schema_diff +├── memory/ +│ └── basic-memory-capability.ts # OpenClaw memory capability (host search, recall tools, flush) +├── context-engine/ +│ └── basic-memory-context-engine.ts # Auto-recall and conversation capture ├── commands/ │ ├── slash.ts # /remember, /recall │ ├── skills.ts # /tasks, /reflect, /defrag, /schema diff --git a/integrations/openclaw/MEMORY_TASK_FLOW.md b/integrations/openclaw/MEMORY_TASK_FLOW.md index 9f2d5d83c..de9cd43c5 100644 --- a/integrations/openclaw/MEMORY_TASK_FLOW.md +++ b/integrations/openclaw/MEMORY_TASK_FLOW.md @@ -2,6 +2,8 @@ This document explains how `openclaw-basic-memory` manages short-term memory, long-term memory, and active tasks during normal agent usage. +> **Superseded on OpenClaw 2026.10 and later.** The combined `memory_search` described below no longer runs. OpenClaw's bundled Memory Core plugin owns the `memory_search` and `memory_get` tool names, so this plugin now registers an OpenClaw memory capability instead (`memory/basic-memory-capability.ts`). Agents search Basic Memory with `search_notes` and read notes with `read_note`; see the README's "Memory search" section. The note and task conventions below still apply. + ## Mental Model The plugin composes memory from three places: diff --git a/integrations/openclaw/README.md b/integrations/openclaw/README.md index 305fc22f2..c90be8830 100644 --- a/integrations/openclaw/README.md +++ b/integrations/openclaw/README.md @@ -33,7 +33,7 @@ This plugin connects Basic Memory to OpenClaw so your agent can: - **Remember across sessions** — search and recall past conversations, decisions, and context - **Track work in progress** — structured tasks that survive context compaction - **Build knowledge over time** — notes, observations, and relations that grow into a connected graph -- **Search intelligently** — composited search across working memory, the knowledge graph, and active tasks in parallel +- **Search intelligently** — hybrid full-text and vector search across the knowledge graph All data stays on your machine as Markdown files indexed locally with SQLite. Cloud sync is available but entirely optional. @@ -60,7 +60,7 @@ openclaw gateway restart The plugin fills two OpenClaw slots, and each one does a different job: -- **`memory`** provides the `memory_search` and `memory_get` tools. +- **`memory`** registers Basic Memory as OpenClaw's memory provider: gateway memory search and status, `openclaw doctor` health, Active Memory recall, and the pre-compaction memory flush. - **`contextEngine`** runs automatic recall at session start and automatic conversation capture after each turn. **Without this slot, nothing is captured or recalled automatically**; the agent only remembers what it saves with an explicit tool call. Tested with OpenClaw 2026.10.9. OpenClaw 2026.10 and later require context engines to commit turns through `commitTurn`, which this plugin implements; older plugin versions are degraded to OpenClaw's legacy engine on those hosts and capture nothing. @@ -141,13 +141,17 @@ This uses sensible defaults: auto-generated project name, maps to your workspace ### Memory search -When your agent calls `memory_search`, three sources are queried in parallel: +Agents search Basic Memory with `search_notes` and read results with `read_note`. The plugin adds a short system-prompt section that points the agent at these tools. -1. **MEMORY.md** — text search with surrounding context -2. **Knowledge Graph** — hybrid full-text + vector search across all indexed notes -3. **Active Tasks** — scans `memory/tasks/` for in-progress work +OpenClaw's built-in `memory_search` and `memory_get` tools belong to its bundled Memory Core plugin, which OpenClaw keeps loaded even when this plugin holds the memory slot. Those tools search only the workspace `MEMORY.md` and `memory/` files, not Basic Memory. -Results come back in clear sections so the agent knows where each piece of context came from. +As the memory slot owner, the plugin also serves OpenClaw's own memory consumers: + +- **Gateway memory search, get and status, and `openclaw doctor`** read Basic Memory through the plugin's provider runtime. +- **Active Memory deep recall** uses `search_notes`, `read_note` and `build_context`. +- **Pre-compaction flush** saves durable context with `write_note` and `edit_note` instead of appending to a workspace file. + +Search scores are shown as raw numbers. A score above 1 means the note matched on both keywords and meaning. ### Auto-recall @@ -167,8 +171,6 @@ All tools accept an optional `project` parameter for cross-project operations. | Tool | Description | |------|-------------| -| `memory_search` | Composited search across all memory sources | -| `memory_get` | Read a specific note by title or path | | `search_notes` | Search the knowledge graph directly | | `read_note` | Read a note by title, permalink, or `memory://` URL | | `write_note` | Create or overwrite a note with optional tags, note type, and custom frontmatter metadata | diff --git a/integrations/openclaw/bm-client.ts b/integrations/openclaw/bm-client.ts index 76053abfc..4213b4312 100644 --- a/integrations/openclaw/bm-client.ts +++ b/integrations/openclaw/bm-client.ts @@ -246,7 +246,7 @@ function isRecoverableConnectionError(err: unknown): boolean { ) } -function isNoteNotFoundError(err: unknown): boolean { +export function isNoteNotFoundError(err: unknown): boolean { return ( err instanceof BmToolError && parseRefusalPayload(err.toolMessage)?.error === "NOT_FOUND" diff --git a/integrations/openclaw/commands/cli.ts b/integrations/openclaw/commands/cli.ts index b78cb86b7..a189a4242 100644 --- a/integrations/openclaw/commands/cli.ts +++ b/integrations/openclaw/commands/cli.ts @@ -31,7 +31,7 @@ export function registerCli( } for (const r of results) { - const score = r.score ? ` (${(r.score * 100).toFixed(0)}%)` : "" + const score = r.score ? ` (score ${r.score.toFixed(2)})` : "" console.log(`- ${r.title}${score}`) if (r.content) { const preview = diff --git a/integrations/openclaw/commands/slash.ts b/integrations/openclaw/commands/slash.ts index b9f29948a..d25a3411f 100644 --- a/integrations/openclaw/commands/slash.ts +++ b/integrations/openclaw/commands/slash.ts @@ -89,7 +89,7 @@ export function registerCommands( } const lines = results.map((r, i) => { - const score = r.score ? ` (${(r.score * 100).toFixed(0)}%)` : "" + const score = r.score ? ` (score ${r.score.toFixed(2)})` : "" return `${i + 1}. ${r.title}${score}` }) diff --git a/integrations/openclaw/index.test.ts b/integrations/openclaw/index.test.ts index 64fa67208..b566ad61a 100644 --- a/integrations/openclaw/index.test.ts +++ b/integrations/openclaw/index.test.ts @@ -47,6 +47,7 @@ describe("plugin service lifecycle", () => { registerCommand: jest.fn(), registerCli: jest.fn(), registerContextEngine: jest.fn(), + registerMemoryCapability: jest.fn(), registerService: jest.fn((service: any) => { services.push(service) }), @@ -62,6 +63,20 @@ describe("plugin service lifecycle", () => { ) expect(api.on).not.toHaveBeenCalled() + // memory-core owns memory_search and memory_get on OpenClaw 2026.10, so + // the plugin serves the host through its memory capability instead. + expect(api.registerMemoryCapability).toHaveBeenCalledWith( + expect.objectContaining({ + providerRuntime: expect.any(Object), + recallToolNames: ["search_notes", "read_note", "build_context"], + }), + ) + const toolNames = api.registerTool.mock.calls.map( + ([tool]) => (tool as { name: string }).name, + ) + expect(toolNames).not.toContain("memory_search") + expect(toolNames).not.toContain("memory_get") + await services[0].start({ workspaceDir: "/tmp/workspace" }) expect(startSpy).toHaveBeenCalledWith({ cwd: "/tmp/workspace" }) diff --git a/integrations/openclaw/index.ts b/integrations/openclaw/index.ts index cb5cfe045..c5ae80c09 100644 --- a/integrations/openclaw/index.ts +++ b/integrations/openclaw/index.ts @@ -12,6 +12,7 @@ import { } from "./config.ts" import { BasicMemoryContextEngine } from "./context-engine/basic-memory-context-engine.ts" import { initLogger, log } from "./logger.ts" +import { buildBasicMemoryCapability } from "./memory/basic-memory-capability.ts" import { CONVERSATION_SCHEMA_CONTENT } from "./schema/conversation-schema.ts" import { TASK_SCHEMA_CONTENT } from "./schema/task-schema.ts" import { registerContextTool } from "./tools/build-context.ts" @@ -19,10 +20,6 @@ import { registerDeleteTool } from "./tools/delete-note.ts" import { registerEditTool } from "./tools/edit-note.ts" import { registerProjectListTool } from "./tools/list-memory-projects.ts" import { registerWorkspaceListTool } from "./tools/list-workspaces.ts" -import { - registerMemoryProvider, - setWorkspaceDir, -} from "./tools/memory-provider.ts" import { registerMoveTool } from "./tools/move-note.ts" import { registerReadTool } from "./tools/read-note.ts" import { registerSchemaDiffTool } from "./tools/schema-diff.ts" @@ -44,7 +41,7 @@ export default definePluginEntry({ id: "openclaw-basic-memory", name: "Basic Memory", description: - "Local-first knowledge graph for OpenClaw — persistent memory with graph search and composited memory_search", + "Local-first knowledge graph for OpenClaw — persistent memory with graph search, recall and conversation capture", configSchema: basicMemoryConfigSchema, register(api) { @@ -72,9 +69,14 @@ export default definePluginEntry({ registerSchemaInferTool(api, client) registerSchemaDiffTool(api, client) - // --- Composited memory_search + memory_get (always registered) --- - registerMemoryProvider(api, client, cfg) - log.info("registered composited memory_search + memory_get") + // --- Memory capability --- + // OpenClaw 2026.10 owns the memory_search and memory_get tool names + // (memory-core registers them even when another plugin holds the memory + // slot), so the plugin serves the host through registerMemoryCapability: + // gateway memory search, status and doctor, Active Memory recall, and the + // pre-compaction flush. + api.registerMemoryCapability(buildBasicMemoryCapability(client)) + log.info("registered Basic Memory memory capability") api.registerContextEngine( "openclaw-basic-memory", () => new BasicMemoryContextEngine(client, cfg), @@ -166,8 +168,6 @@ export default definePluginEntry({ } } - setWorkspaceDir(workspace) - log.info("connected — BM MCP stdio session running") }, stop: async () => { diff --git a/integrations/openclaw/memory/basic-memory-capability.test.ts b/integrations/openclaw/memory/basic-memory-capability.test.ts new file mode 100644 index 000000000..a27315dc9 --- /dev/null +++ b/integrations/openclaw/memory/basic-memory-capability.test.ts @@ -0,0 +1,202 @@ +import { beforeEach, describe, expect, it, jest } from "bun:test" +import { type BmClient, BmToolError } from "../bm-client.ts" +import { + buildBasicMemoryCapability, + MEMORY_PROVIDER_ID, + openBasicMemoryReader, +} from "./basic-memory-capability.ts" + +type Context = Parameters[1] + +function makeContext(overrides?: Partial): Context { + return { + authority: { kind: "host", operation: "test" }, + assertCurrent: jest.fn(), + ...overrides, + } as Context +} + +const notFound = () => + new BmToolError( + "bm_read", + JSON.stringify({ error: "NOT_FOUND", message: "Missing note" }), + ) + +describe("Basic Memory memory capability", () => { + let client: { + search: jest.Mock + readNote: jest.Mock + listProjects: jest.Mock + } + + beforeEach(() => { + client = { + search: jest.fn().mockResolvedValue([ + { + title: "Quillfeather", + permalink: "pets/quillfeather", + content: "My test cat is named Quillfeather.", + file_path: "pets/quillfeather.md", + score: 1.18, + }, + { + title: "Weak match", + permalink: "misc/weak", + content: "Barely related.", + file_path: "misc/weak.md", + score: 0.2, + }, + ]), + readNote: jest.fn().mockResolvedValue({ + title: "Quillfeather", + permalink: "pets/quillfeather", + content: "line 1\nline 2\nline 3\nline 4", + file_path: "pets/quillfeather.md", + }), + listProjects: jest.fn().mockResolvedValue([]), + } + }) + + const reader = (context = makeContext()) => + openBasicMemoryReader(client as unknown as BmClient, context) + + it("declares memory-only search without pagination or candidates", () => { + expect(reader().capabilities).toEqual({ + sources: ["memory"], + pagination: false, + candidates: [], + projectFilter: false, + }) + }) + + it("maps BM results to provider hits with capped scores", async () => { + const page = await reader().search({ query: "test cat", maxResults: 3 }) + + expect(client.search).toHaveBeenCalledWith("test cat", 3) + expect(page.hits[0]).toEqual({ + reference: { providerId: MEMORY_PROVIDER_ID, id: "pets/quillfeather" }, + excerpt: "My test cat is named Quillfeather.", + source: "pets/quillfeather.md", + score: 1, + }) + }) + + it("enforces minScore and drops unscored hits when a floor is set", async () => { + client.search.mockResolvedValue([ + ...(await client.search()), + { + title: "Unscored", + permalink: "misc/unscored", + content: "x", + file_path: "misc/unscored.md", + }, + ]) + + const page = await reader().search({ query: "test cat", minScore: 0.5 }) + + expect(page.hits.map((hit) => hit.reference.id)).toEqual([ + "pets/quillfeather", + ]) + }) + + it("reads a note by reference and applies the host line window", async () => { + const result = await reader().get({ + reference: { providerId: MEMORY_PROVIDER_ID, id: "pets/quillfeather" }, + from: 2, + lines: 2, + }) + + expect(client.readNote).toHaveBeenCalledWith("pets/quillfeather") + expect(result).toEqual({ + status: "ok", + reference: { providerId: MEMORY_PROVIDER_ID, id: "pets/quillfeather" }, + text: "line 2\nline 3", + from: 2, + lines: 2, + truncated: true, + nextFrom: 4, + }) + }) + + it("returns the whole note when no line window is requested", async () => { + const result = await reader().get({ + reference: { providerId: MEMORY_PROVIDER_ID, id: "pets/quillfeather" }, + }) + + expect(result).toEqual({ + status: "ok", + reference: { providerId: MEMORY_PROVIDER_ID, id: "pets/quillfeather" }, + text: "line 1\nline 2\nline 3\nline 4", + }) + }) + + it("reports a missing note as not_found but surfaces other failures", async () => { + client.readNote.mockRejectedValueOnce(notFound()) + await expect( + reader().get({ reference: { providerId: MEMORY_PROVIDER_ID, id: "x" } }), + ).resolves.toEqual({ status: "not_found" }) + + client.readNote.mockRejectedValueOnce(new Error("BM MCP unavailable")) + await expect( + reader().get({ reference: { providerId: MEMORY_PROVIDER_ID, id: "x" } }), + ).rejects.toThrow("BM MCP unavailable") + }) + + it("refuses a caller whose authority was revoked", async () => { + const context = makeContext({ + assertCurrent: jest.fn(() => { + throw new Error("caller no longer current") + }), + }) + + await expect(reader(context).search({ query: "cat" })).rejects.toThrow( + "caller no longer current", + ) + expect(client.search).not.toHaveBeenCalled() + }) + + it("reports health from the BM session without reading notes", async () => { + await expect(reader().health()).resolves.toEqual({ status: "ready" }) + expect(client.search).not.toHaveBeenCalled() + expect(client.readNote).not.toHaveBeenCalled() + + client.listProjects.mockRejectedValue(new Error("connection closed")) + await expect(reader().health()).resolves.toEqual({ + status: "unavailable", + message: "Basic Memory is not reachable", + }) + }) + + it("registers recall tools, a tools-arm flush, and Basic Memory prompt guidance", async () => { + const capability = buildBasicMemoryCapability(client as unknown as BmClient) + + expect(capability.recallToolNames).toEqual([ + "search_notes", + "read_note", + "build_context", + ]) + + const plan = capability.providerFlushPlanResolver?.({}) + expect(plan).toMatchObject({ + persistenceToolNames: ["write_note", "edit_note"], + lookupToolNames: ["search_notes", "read_note"], + }) + expect(plan && "relativePath" in plan).toBe(false) + + expect( + capability.promptBuilder?.({ availableTools: new Set(["search_notes"]) }), + ).toContain("## Basic Memory") + expect( + capability.promptBuilder?.({ + availableTools: new Set(["memory_search"]), + }), + ).toEqual([]) + + const opened = await capability.providerRuntime?.open({ + cfg: {}, + agentId: "main", + context: makeContext(), + } as Parameters["open"]>[0]) + expect(opened?.provider?.capabilities.sources).toEqual(["memory"]) + }) +}) diff --git a/integrations/openclaw/memory/basic-memory-capability.ts b/integrations/openclaw/memory/basic-memory-capability.ts new file mode 100644 index 000000000..92b14df54 --- /dev/null +++ b/integrations/openclaw/memory/basic-memory-capability.ts @@ -0,0 +1,240 @@ +import type { MemoryPluginCapability } from "openclaw/plugin-sdk/memory-host-core" +import { type BmClient, isNoteNotFoundError } from "../bm-client.ts" +import { log } from "../logger.ts" + +// OpenClaw documents deriving the provider types from the public capability +// type rather than importing its private memory-host-search facade. +type MemoryProviderRuntime = NonNullable< + MemoryPluginCapability["providerRuntime"] +> +type MemoryProviderHandle = NonNullable< + Awaited>["provider"] +> +type MemorySearchRequest = Parameters[0] +type MemorySearchPage = Awaited> +type MemoryGetRequest = Parameters[0] +type MemoryGetResult = Awaited> +type MemoryHealth = Awaited> +type MemoryCallerContext = Parameters< + MemoryProviderRuntime["open"] +>[0]["context"] +type MemoryProviderFlushPlanResolver = NonNullable< + MemoryPluginCapability["providerFlushPlanResolver"] +> + +export const MEMORY_PROVIDER_ID = "openclaw-basic-memory" + +// Agent tools this plugin registers that Active Memory may use for deep +// recall, and that the pre-compaction flush may use to look before writing. +export const RECALL_TOOL_NAMES = [ + "search_notes", + "read_note", + "build_context", +] as const +const FLUSH_PERSISTENCE_TOOL_NAMES = ["write_note", "edit_note"] as const +const FLUSH_LOOKUP_TOOL_NAMES = ["search_notes", "read_note"] as const + +const DEFAULT_MAX_RESULTS = 10 +const MAX_EXCERPT_CHARS = 700 +// memory-core's flush prompts use the same token for "nothing to save". +const SILENT_REPLY_TOKEN = "NO_REPLY" + +// --- Search and retrieval --- + +/** + * Basic Memory fuses keyword and vector scores into [0, 1.3] (see + * search_reader.py FUSION_BONUS). OpenClaw compares provider scores against a + * caller's minScore on a 0–1 scale, so a fused score above 1 is capped at 1. + */ +function hostScore(score: number | undefined): number | undefined { + return score === undefined ? undefined : Math.min(score, 1) +} + +function excerptOf(content: string): string { + return content.length > MAX_EXCERPT_CHARS + ? `${content.slice(0, MAX_EXCERPT_CHARS)}…` + : content +} + +/** + * Apply the host's optional line window to a note body. `from` is 1-based, + * matching the host's memory_get contract. + */ +function sliceLines( + text: string, + from: number | undefined, + lines: number | undefined, +): Pick< + Extract, + "text" | "truncated" | "from" | "lines" | "nextFrom" +> { + if (from === undefined && lines === undefined) return { text } + + const all = text.split("\n") + const start = Math.max(1, from ?? 1) + const count = lines ?? all.length - start + 1 + const window = all.slice(start - 1, start - 1 + count) + const end = start - 1 + window.length + const truncated = end < all.length + return { + text: window.join("\n"), + from: start, + lines: window.length, + truncated, + ...(truncated ? { nextFrom: end + 1 } : {}), + } +} + +/** + * Open a caller-bound reader over the plugin's shared BM MCP session. + * + * The host rechecks the caller's authority around every provider call; + * context.assertCurrent() is also called before and after each BM request so + * a revoked caller is refused rather than served. Every note in the project + * is visible to every caller, which matches what the plugin's own + * search_notes and read_note tools already expose. + */ +export function openBasicMemoryReader( + client: BmClient, + context: MemoryCallerContext, +): MemoryProviderHandle { + const guarded = async (run: () => Promise): Promise => { + context.assertCurrent() + const result = await run() + context.assertCurrent() + return result + } + + return { + capabilities: { + sources: ["memory"], + pagination: false, + candidates: [], + projectFilter: false, + }, + + async search(request: MemorySearchRequest): Promise { + const results = await guarded(() => + client.search(request.query, request.maxResults ?? DEFAULT_MAX_RESULTS), + ) + + const hits = results + .map((result) => ({ result, score: hostScore(result.score) })) + // Trigger: the caller set a score floor. + // Why: the host contract requires every provider to enforce minScore. + // Outcome: unscored or lower-scored hits are dropped. + .filter( + ({ score }) => + request.minScore === undefined || + (score !== undefined && score >= request.minScore), + ) + .map(({ result, score }) => ({ + reference: { providerId: MEMORY_PROVIDER_ID, id: result.permalink }, + excerpt: excerptOf(result.content ?? ""), + source: result.file_path, + ...(score === undefined ? {} : { score }), + })) + + return { hits } + }, + + async get(request: MemoryGetRequest): Promise { + try { + const note = await guarded(() => client.readNote(request.reference.id)) + return { + status: "ok", + reference: { providerId: MEMORY_PROVIDER_ID, id: note.permalink }, + ...sliceLines(note.content, request.from, request.lines), + } + } catch (err) { + // A missing note is an answer; any other failure must surface so the + // host does not report it as an empty success. + if (isNoteNotFoundError(err)) return { status: "not_found" } + throw err + } + }, + + async health(): Promise { + // Listing projects proves the BM MCP session answers without reading + // any note content, so it is safe for status-only callers. + try { + await guarded(() => client.listProjects()) + return { status: "ready" } + } catch (err) { + log.warn( + `memory health check failed: ${err instanceof Error ? err.message : String(err)}`, + ) + return { + status: "unavailable", + message: "Basic Memory is not reachable", + } + } + }, + + // The BM MCP session is shared by the whole plugin and owned by its + // service lifecycle, so closing one caller's reader releases nothing. + async close(): Promise {}, + } +} + +// --- Pre-compaction flush --- + +const FLUSH_PROMPT = [ + "Pre-compaction memory flush.", + "Save durable facts, decisions and open tasks from this session to Basic Memory.", + "Use search_notes or read_note first to find an existing note, then edit_note to update it;", + "use write_note only for a new topic.", + `If nothing is worth saving, reply with ${SILENT_REPLY_TOKEN}.`, +].join(" ") + +const FLUSH_SYSTEM_PROMPT = [ + "Pre-compaction memory flush turn.", + "The session is near auto-compaction; capture durable memories in Basic Memory with write_note or edit_note.", + `You may reply, but usually ${SILENT_REPLY_TOKEN} is correct.`, +].join(" ") + +// Returning a tools-arm plan makes the host persist through this plugin's own +// tools instead of appending to a workspace memory file. The host has already +// honored agents.defaults.compaction.memoryFlush.enabled before calling this. +const resolveFlushPlan: MemoryProviderFlushPlanResolver = () => ({ + prompt: FLUSH_PROMPT, + systemPrompt: FLUSH_SYSTEM_PROMPT, + persistenceToolNames: FLUSH_PERSISTENCE_TOOL_NAMES, + lookupToolNames: FLUSH_LOOKUP_TOOL_NAMES, +}) + +// --- Prompt guidance --- + +/** + * OpenClaw fills any capability field the slot owner leaves empty from other + * memory registrations, including memory-core's prompt section, which points + * agents at its file-only memory_search. Supplying our own section keeps the + * agent's guidance on the Basic Memory tools. + */ +function buildPromptSection(params: { availableTools: Set }): string[] { + if (!params.availableTools.has("search_notes")) return [] + return [ + "## Basic Memory", + "Long-term memory lives in Basic Memory, a knowledge graph of Markdown notes.", + "Before answering questions about prior work, decisions, people or preferences, search it with search_notes and read the best match with read_note.", + "Earlier conversations are saved automatically in daily conversation notes.", + "memory_search and memory_get cover only the workspace MEMORY.md and memory/ files, not Basic Memory.", + ] +} + +// --- Capability --- + +export function buildBasicMemoryCapability( + client: BmClient, +): MemoryPluginCapability { + return { + providerRuntime: { + async open({ context }) { + return { provider: openBasicMemoryReader(client, context) } + }, + }, + recallToolNames: RECALL_TOOL_NAMES, + providerFlushPlanResolver: resolveFlushPlan, + promptBuilder: buildPromptSection, + } +} diff --git a/integrations/openclaw/openclaw.plugin.json b/integrations/openclaw/openclaw.plugin.json index e1207e526..5a57aa220 100644 --- a/integrations/openclaw/openclaw.plugin.json +++ b/integrations/openclaw/openclaw.plugin.json @@ -8,8 +8,6 @@ "edit_note", "list_memory_projects", "list_workspaces", - "memory_get", - "memory_search", "move_note", "read_note", "schema_diff", diff --git a/integrations/openclaw/package.json b/integrations/openclaw/package.json index c2c61860b..781618961 100644 --- a/integrations/openclaw/package.json +++ b/integrations/openclaw/package.json @@ -16,6 +16,7 @@ "bm-client.ts", "context-engine/basic-memory-context-engine.ts", "context-engine/types.ts", + "memory/basic-memory-capability.ts", "config.ts", "logger.ts", "commands/cli.ts", @@ -28,7 +29,6 @@ "tools/edit-note.ts", "tools/list-memory-projects.ts", "tools/list-workspaces.ts", - "tools/memory-provider.ts", "tools/move-note.ts", "tools/read-note.ts", "tools/schema-diff.ts", diff --git a/integrations/openclaw/tools/memory-provider.test.ts b/integrations/openclaw/tools/memory-provider.test.ts deleted file mode 100644 index 9f596692e..000000000 --- a/integrations/openclaw/tools/memory-provider.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { beforeEach, describe, expect, it, jest } from "bun:test" -import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" -import type { BasicMemoryConfig } from "../config.ts" -import { registerMemoryProvider, setWorkspaceDir } from "./memory-provider.ts" - -function makeCfg(overrides?: Partial): BasicMemoryConfig { - return { - project: "test", - bmPath: "bm", - memoryDir: "memory/", - memoryFile: "MEMORY.md", - projectPath: "/tmp/bm-test", - autoCapture: true, - captureMinChars: 10, - autoRecall: true, - recallPrompt: "Check for active tasks and recent activity.", - debug: false, - ...overrides, - } -} - -describe("memory provider tools", () => { - let mockApi: OpenClawPluginApi - let mockClient: BmClient - - beforeEach(() => { - mockApi = { - registerTool: jest.fn(), - } as any - - mockClient = { - search: jest.fn().mockResolvedValue([]), - readNote: jest.fn(), - } as any - - // Use a temp dir that won't have MEMORY.md - setWorkspaceDir("/tmp/nonexistent-workspace-for-test") - }) - - describe("registerMemoryProvider", () => { - it("should register both memory_search and memory_get tools", () => { - registerMemoryProvider(mockApi, mockClient, makeCfg()) - - expect(mockApi.registerTool).toHaveBeenCalledTimes(2) - - expect(mockApi.registerTool).toHaveBeenCalledWith( - expect.objectContaining({ - name: "memory_search", - label: "Memory Search", - }), - { names: ["memory_search"] }, - ) - - expect(mockApi.registerTool).toHaveBeenCalledWith( - expect.objectContaining({ - name: "memory_get", - label: "Memory Get", - }), - { names: ["memory_get"] }, - ) - }) - }) - - describe("memory_search tool (composited)", () => { - let searchExecute: Function - - beforeEach(() => { - registerMemoryProvider(mockApi, mockClient, makeCfg()) - const searchCall = (mockApi.registerTool as jest.MockedFunction).mock - .calls[0] - searchExecute = searchCall[0].execute - }) - - it("should return BM results in Knowledge Graph section", async () => { - ;(mockClient.search as jest.MockedFunction).mockResolvedValue([ - { - title: "Test Note", - permalink: "test-note", - content: "Some content about testing", - score: 0.95, - file_path: "memory/test-note.md", - }, - ]) - - const result = await searchExecute("id", { query: "testing" }) - const text = result.content[0].text - - expect(text).toContain("## Knowledge Graph") - expect(text).toContain("memory/test-note.md") - expect(text).toContain("Some content about testing") - }) - - it("should return no matches message when all sources empty", async () => { - ;(mockClient.search as jest.MockedFunction).mockResolvedValue([]) - - const result = await searchExecute("id", { query: "nonexistent" }) - - expect(result.content[0].text).toBe( - "No matches found across memory sources.", - ) - }) - - it("should handle BM search errors gracefully", async () => { - ;(mockClient.search as jest.MockedFunction).mockRejectedValue( - new Error("BM down"), - ) - - const result = await searchExecute("id", { query: "test" }) - const text = result.content[0].text - - expect(text).toContain("(search unavailable)") - }) - }) - - describe("memory_get tool", () => { - let getExecute: Function - - beforeEach(() => { - registerMemoryProvider(mockApi, mockClient, makeCfg()) - const getCall = (mockApi.registerTool as jest.MockedFunction).mock - .calls[1] - getExecute = getCall[0].execute - }) - - it("should read note and format with title", async () => { - ;(mockClient.readNote as jest.MockedFunction).mockResolvedValue({ - title: "Test Note", - permalink: "test-note", - content: "Note content here", - file_path: "notes/test.md", - }) - - const result = await getExecute("id", { path: "test-note" }) - - expect(result.content[0].text).toBe("# Test Note\n\nNote content here") - }) - - it("should handle errors gracefully", async () => { - ;(mockClient.readNote as jest.MockedFunction).mockRejectedValue( - new Error("Not found"), - ) - - const result = await getExecute("id", { path: "missing" }) - - expect(result.content[0].text).toContain('Could not read "missing"') - }) - }) -}) diff --git a/integrations/openclaw/tools/memory-provider.ts b/integrations/openclaw/tools/memory-provider.ts deleted file mode 100644 index be7d10277..000000000 --- a/integrations/openclaw/tools/memory-provider.ts +++ /dev/null @@ -1,336 +0,0 @@ -import { readdir, readFile } from "node:fs/promises" -import { join, resolve } from "node:path" -import { Type } from "@sinclair/typebox" -import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" -import type { BasicMemoryConfig } from "../config.ts" -import { log } from "../logger.ts" - -/** - * Search MEMORY.md for lines matching the query. - * Returns matching lines with 1 line of surrounding context. - */ -async function searchMemoryFile( - query: string, - workspaceDir: string, - memoryFile: string, -): Promise { - try { - const filePath = resolve(workspaceDir, memoryFile) - const content = await readFile(filePath, "utf-8") - const lines = content.split("\n") - const queryLower = query.toLowerCase() - const terms = queryLower.split(/\s+/).filter((t) => t.length > 0) - - // Find lines that match any search term - const matchingIndices = new Set() - for (let i = 0; i < lines.length; i++) { - const lineLower = lines[i].toLowerCase() - if (terms.some((term) => lineLower.includes(term))) { - // Add the matching line + 1 line before/after for context - if (i > 0) matchingIndices.add(i - 1) - matchingIndices.add(i) - if (i < lines.length - 1) matchingIndices.add(i + 1) - } - } - - if (matchingIndices.size === 0) return "" - - // Group consecutive lines into snippets - const sorted = [...matchingIndices].sort((a, b) => a - b) - const snippets: string[] = [] - let current: string[] = [] - let lastIdx = -2 - - for (const idx of sorted) { - if (idx !== lastIdx + 1 && current.length > 0) { - snippets.push(current.join("\n")) - current = [] - } - current.push(`- ${lines[idx]}`) - lastIdx = idx - } - if (current.length > 0) snippets.push(current.join("\n")) - - return snippets.join("\n…\n") - } catch { - return "" - } -} - -/** - * Search for active tasks via BM knowledge graph. - * Uses search_notes with note_types and status filters for precise querying. - * Falls back to filesystem scan if search fails. - */ -async function searchActiveTasks( - query: string, - client: BmClient, - workspaceDir: string, - memoryDir: string, -): Promise { - // Try structured search first - try { - const results = await client.search(query || undefined, 10, undefined, { - note_types: ["task"], - status: "active", - }) - - if (results.length > 0) { - const matches: string[] = [] - for (const r of results) { - const score = r.score ? ` (${r.score.toFixed(2)})` : "" - const preview = - (r.content ?? "").length > 200 - ? `${(r.content ?? "").slice(0, 200)}…` - : (r.content ?? "") - matches.push( - `- **${r.title}**${score} — ${r.file_path}\n > ${preview.replace(/\n/g, "\n > ")}`, - ) - } - return matches.join("\n\n") - } - } catch (err) { - log.debug("BM task search failed, falling back to filesystem scan", err) - } - - // Fallback: filesystem scan for tasks not yet indexed - try { - const tasksDir = resolve(workspaceDir, memoryDir, "tasks") - let entries: import("node:fs").Dirent[] - try { - entries = (await readdir(tasksDir, { - withFileTypes: true, - })) as unknown as import("node:fs").Dirent[] - } catch { - return "" - } - - const queryLower = query.toLowerCase() - const terms = queryLower.split(/\s+/).filter((t) => t.length > 0) - const matches: string[] = [] - - for (const entry of entries) { - if (!entry.isFile() || !entry.name.endsWith(".md")) continue - - const filePath = join(entry.parentPath ?? tasksDir, entry.name) - const content = await readFile(filePath, "utf-8") - - const statusMatch = content.match(/status:\s*(\S+)/) - const status = statusMatch?.[1] ?? "unknown" - if (status === "done") continue - - const contentLower = content.toLowerCase() - const matchesQuery = - terms.length === 0 || terms.some((term) => contentLower.includes(term)) - if (!matchesQuery) continue - - const titleMatch = content.match(/title:\s*(.+)/) - const title = titleMatch?.[1] ?? entry.name.replace(/\.md$/, "") - const stepMatch = content.match(/current_step:\s*(\S+)/) - const currentStep = stepMatch?.[1] ?? "?" - - const contextMatch = content.match( - /## Context\s*\n([\s\S]*?)(?=\n##|\n---|$)/, - ) - const context = contextMatch?.[1]?.trim().slice(0, 150) ?? "" - - matches.push( - `- **${title}** (status: ${status}, step: ${currentStep})\n ${context}`, - ) - } - - return matches.join("\n") - } catch { - return "" - } -} - -// Store workspace dir for use in memory_search (set during service start) -let _workspaceDir = "" -export function setWorkspaceDir(dir: string) { - _workspaceDir = dir -} - -/** - * Register composited memory_search and memory_get tools. - * - * memory_search queries 3 sources in parallel: - * 1. MEMORY.md — grep/text search - * 2. BM knowledge graph — semantic + FTS search - * 3. Active tasks — memory/tasks/ files with status != done - * - * memory_get reads a specific note by identifier. - */ -export function registerMemoryProvider( - api: OpenClawPluginApi, - client: BmClient, - cfg: BasicMemoryConfig, -): void { - // --- composited memory_search --- - api.registerTool( - { - name: "memory_search", - label: "Memory Search", - description: - "Search across all memory sources: MEMORY.md (working memory), " + - "Basic Memory knowledge graph (long-term archive), and active tasks. " + - "Returns composited results from all sources. Use it for broad recall; use " + - "search_notes when you need metadata, tag, or status filters or a specific project.", - parameters: Type.Object({ - query: Type.String({ - description: "Search query — natural language or keywords", - }), - }), - async execute(_toolCallId: string, params: { query: string }) { - log.debug(`memory_search: query="${params.query}"`) - - const workspaceDir = _workspaceDir || process.cwd() - - // Query all 3 sources in parallel - const [memoryMd, bmResults, taskResults] = await Promise.all([ - searchMemoryFile(params.query, workspaceDir, cfg.memoryFile), - client - .search(params.query, 5) - .then((results) => { - if (results.length === 0) return "" - return results - .map((r) => { - const score = r.score ? ` (${r.score.toFixed(2)})` : "" - const preview = - (r.content ?? "").length > 200 - ? `${(r.content ?? "").slice(0, 200)}…` - : (r.content ?? "") - const source = r.file_path || r.permalink - return `- ${source}${score}\n > ${preview.replace(/\n/g, "\n > ")}` - }) - .join("\n\n") - }) - .catch((err) => { - log.error("BM search failed in composited search", err) - return "(search unavailable)" - }), - searchActiveTasks(params.query, client, workspaceDir, cfg.memoryDir), - ]) - - // Build composited result - const sections: string[] = [] - - if (memoryMd) { - sections.push(`## ${cfg.memoryFile}\n${memoryMd}`) - } - - if (bmResults) { - sections.push(`## Knowledge Graph (${cfg.memoryDir})\n${bmResults}`) - } - - if (taskResults) { - sections.push(`## Active Tasks\n${taskResults}`) - } - - if (sections.length === 0) { - return { - content: [ - { - type: "text" as const, - text: "No matches found across memory sources.", - }, - ], - details: { - query: params.query, - sectionCount: 0, - hasMemoryFileMatches: false, - hasKnowledgeGraphMatches: false, - hasTaskMatches: false, - }, - } - } - - return { - content: [ - { - type: "text" as const, - text: sections.join("\n\n"), - }, - ], - details: { - query: params.query, - sectionCount: sections.length, - hasMemoryFileMatches: memoryMd.length > 0, - hasKnowledgeGraphMatches: bmResults.length > 0, - hasTaskMatches: taskResults.length > 0, - }, - } - }, - }, - { names: ["memory_search"] }, - ) - - // --- memory_get (unchanged) --- - api.registerTool( - { - name: "memory_get", - label: "Memory Get", - description: - "Read a specific note from the knowledge graph by title, permalink, or path. " + - "Returns the full note content. Use after memory_search to read a specific result in full.", - parameters: Type.Object({ - path: Type.String({ - description: - "Note identifier — title, permalink, memory:// URL, or file path", - }), - from: Type.Optional( - Type.Number({ - description: - "Starting line number (ignored — included for compatibility)", - }), - ), - lines: Type.Optional( - Type.Number({ - description: - "Number of lines to read (ignored — included for compatibility)", - }), - ), - }), - async execute( - _toolCallId: string, - params: { path: string; from?: number; lines?: number }, - ) { - log.debug(`memory_get: path="${params.path}"`) - - try { - const note = await client.readNote(params.path) - - return { - content: [ - { - type: "text" as const, - text: `# ${note.title}\n\n${note.content}`, - }, - ], - details: { - title: note.title, - permalink: note.permalink, - file_path: note.file_path, - }, - } - } catch (err) { - log.error("memory_get failed", err) - return { - content: [ - { - type: "text" as const, - text: `Could not read "${params.path}". It may not exist in the knowledge graph.`, - }, - ], - details: { - path: params.path, - error: "memory_get_failed", - }, - } - } - }, - }, - { names: ["memory_get"] }, - ) -} diff --git a/integrations/openclaw/tools/search-notes.test.ts b/integrations/openclaw/tools/search-notes.test.ts index d138a024e..a403823eb 100644 --- a/integrations/openclaw/tools/search-notes.test.ts +++ b/integrations/openclaw/tools/search-notes.test.ts @@ -138,7 +138,8 @@ describe("search tool", () => { title: "High Score Note", permalink: "high-score", content: "Content with high relevance score", - score: 0.95, + // Fused keyword + vector scores can exceed 1 (BM range is 0–1.3). + score: 1.18, file_path: "notes/high-score.md", }, { @@ -157,8 +158,9 @@ describe("search tool", () => { const result = await executeFunction("tool-call-id", { query: "test" }) const text = result.content[0].text - expect(text).toContain("**High Score Note** (95%)") - expect(text).toContain("**Medium Score Note** (67%)") + expect(text).toContain("**High Score Note** (score 1.18)") + expect(text).toContain("**Medium Score Note** (score 0.67)") + expect(text).not.toContain("%") }) it("should handle results without scores", async () => { @@ -179,7 +181,7 @@ describe("search tool", () => { const text = result.content[0].text expect(text).toContain("No Score Note") - expect(text).not.toContain("(%)") + expect(text).not.toContain("(score") }) it("should truncate long content with ellipsis", async () => { diff --git a/integrations/openclaw/tools/search-notes.ts b/integrations/openclaw/tools/search-notes.ts index 1470b29c6..b4de9100b 100644 --- a/integrations/openclaw/tools/search-notes.ts +++ b/integrations/openclaw/tools/search-notes.ts @@ -98,7 +98,7 @@ export function registerSearchTool( const text = results .map((r, i) => { - const score = r.score ? ` (${(r.score * 100).toFixed(0)}%)` : "" + const score = r.score ? ` (score ${r.score.toFixed(2)})` : "" const content = r.content ?? "" const preview = content.length > 200 ? `${content.slice(0, 200)}...` : content From 60c153d8f042a6eb6f1ffef9e4805f94e1262089 Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 15:21:09 -0500 Subject: [PATCH 5/8] fix(integrations): let one-shot OpenClaw memory CLI commands exit `openclaw memory status --agent main` printed "Health: ready" and then never exited. The CLI loads the plugin without starting its service, so the provider's health() call spawned a `bm mcp` child lazily, and the reader's close() was a no-op. The child's open pipes kept the process alive. BmClient now records whether the plugin service owns the session (isServiceRunning(), true only between start() and stop()). A reader opened while the service is not running owns its connection and stops it on close(). In the gateway, close() still leaves the shared session open. Also rewrite the search_notes description. It told agents to use memory_search for cross-source recall covering MEMORY.md and tasks, which no longer exists on OpenClaw 2026.10. Verified live on OpenClaw 2026.10.9: `openclaw memory status --agent main` exits 0 after about 13 s, reporting the openclaw-basic-memory provider as ready, and leaves no extra `bm mcp` process. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/bm-client.test.ts | 16 ++++++++++++++ integrations/openclaw/bm-client.ts | 10 +++++++++ .../memory/basic-memory-capability.test.ts | 22 +++++++++++++++++++ .../memory/basic-memory-capability.ts | 15 ++++++++++--- integrations/openclaw/tools/search-notes.ts | 5 +++-- 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/integrations/openclaw/bm-client.test.ts b/integrations/openclaw/bm-client.test.ts index afb992422..1d55f9201 100644 --- a/integrations/openclaw/bm-client.test.ts +++ b/integrations/openclaw/bm-client.test.ts @@ -943,6 +943,22 @@ describe("BmClient MCP behavior", () => { expect(args[4]).toBeUndefined() // overwrite }) + it("reports the service as running only between start() and stop()", async () => { + ;(client as any).connectWithRetries = jest.fn().mockResolvedValue(undefined) + ;(client as any).disconnectCurrent = jest.fn().mockResolvedValue(undefined) + + expect(client.isServiceRunning()).toBe(false) + // A lazy connection from a tool call is not service ownership. + setConnected(client, jest.fn()) + expect(client.isServiceRunning()).toBe(false) + + await client.start() + expect(client.isServiceRunning()).toBe(true) + + await client.stop() + expect(client.isServiceRunning()).toBe(false) + }) + describe("indexConversation with a turn key", () => { // In-memory stand-in for the conversation notes so the duplicate check, // append, and create paths run against shared state. diff --git a/integrations/openclaw/bm-client.ts b/integrations/openclaw/bm-client.ts index 4213b4312..39ce4e75a 100644 --- a/integrations/openclaw/bm-client.ts +++ b/integrations/openclaw/bm-client.ts @@ -305,6 +305,10 @@ export class BmClient { private cwd?: string private env?: Record private shouldRun = false + // True only between start() and stop(), i.e. while the plugin service owns + // the BM MCP session. A lazy connection opened by a tool or memory call in a + // one-shot CLI process leaves this false. + private serviceRunning = false private client: Client | null = null private transport: StdioClientTransport | null = null @@ -324,6 +328,7 @@ export class BmClient { env?: Record }): Promise { this.shouldRun = true + this.serviceRunning = true if (options?.cwd) { this.cwd = options.cwd } @@ -334,8 +339,13 @@ export class BmClient { await this.connectWithRetries() } + isServiceRunning(): boolean { + return this.serviceRunning + } + async stop(): Promise { this.shouldRun = false + this.serviceRunning = false await this.disconnectCurrent(this.client, this.transport) this.client = null this.transport = null diff --git a/integrations/openclaw/memory/basic-memory-capability.test.ts b/integrations/openclaw/memory/basic-memory-capability.test.ts index a27315dc9..6b36f2f1d 100644 --- a/integrations/openclaw/memory/basic-memory-capability.test.ts +++ b/integrations/openclaw/memory/basic-memory-capability.test.ts @@ -27,6 +27,8 @@ describe("Basic Memory memory capability", () => { search: jest.Mock readNote: jest.Mock listProjects: jest.Mock + isServiceRunning: jest.Mock + stop: jest.Mock } beforeEach(() => { @@ -54,6 +56,8 @@ describe("Basic Memory memory capability", () => { file_path: "pets/quillfeather.md", }), listProjects: jest.fn().mockResolvedValue([]), + isServiceRunning: jest.fn().mockReturnValue(true), + stop: jest.fn().mockResolvedValue(undefined), } }) @@ -167,6 +171,24 @@ describe("Basic Memory memory capability", () => { }) }) + it("leaves the shared gateway session open when a reader closes", async () => { + await reader().close() + + expect(client.stop).not.toHaveBeenCalled() + }) + + // Regression: `openclaw memory status` loads the plugin without starting its + // service, and the lazily spawned `bm mcp` child kept the CLI from exiting. + it("stops a connection it opened outside the plugin service", async () => { + client.isServiceRunning.mockReturnValue(false) + const handle = reader() + + await expect(handle.health()).resolves.toEqual({ status: "ready" }) + await handle.close() + + expect(client.stop).toHaveBeenCalledTimes(1) + }) + it("registers recall tools, a tools-arm flush, and Basic Memory prompt guidance", async () => { const capability = buildBasicMemoryCapability(client as unknown as BmClient) diff --git a/integrations/openclaw/memory/basic-memory-capability.ts b/integrations/openclaw/memory/basic-memory-capability.ts index 92b14df54..65f73f36b 100644 --- a/integrations/openclaw/memory/basic-memory-capability.ts +++ b/integrations/openclaw/memory/basic-memory-capability.ts @@ -105,6 +105,13 @@ export function openBasicMemoryReader( return result } + // Trigger: the reader opens while the plugin service is not running, as in + // one-shot CLI commands like `openclaw memory status`. + // Why: the first BM call then spawns a `bm mcp` child that nothing else + // will stop, and its open pipes keep the CLI process from exiting. + // Outcome: this reader owns that connection and stops it on close(). + const ownsConnection = !client.isServiceRunning() + return { capabilities: { sources: ["memory"], @@ -171,9 +178,11 @@ export function openBasicMemoryReader( } }, - // The BM MCP session is shared by the whole plugin and owned by its - // service lifecycle, so closing one caller's reader releases nothing. - async close(): Promise {}, + // In the gateway the BM MCP session is shared by the whole plugin and + // owned by its service, so closing one caller's reader releases nothing. + async close(): Promise { + if (ownsConnection) await client.stop() + }, } } diff --git a/integrations/openclaw/tools/search-notes.ts b/integrations/openclaw/tools/search-notes.ts index b4de9100b..664176d3f 100644 --- a/integrations/openclaw/tools/search-notes.ts +++ b/integrations/openclaw/tools/search-notes.ts @@ -15,8 +15,9 @@ export function registerSearchTool( "Search the Basic Memory knowledge graph for relevant notes, concepts, and connections. " + "Returns matching notes with titles, content previews, and relevance scores. " + "Optionally filter by frontmatter metadata fields, tags, or status, or target " + - "another project. For a quick cross-source recall that also covers MEMORY.md " + - "and active tasks, use memory_search.", + "another project. This is the search for long-term memory and earlier " + + "conversations; memory_search covers only the workspace MEMORY.md and memory/ " + + "files. Read a result in full with read_note, or follow its links with build_context.", parameters: Type.Object({ query: Type.String({ description: "Search query" }), limit: Type.Optional( From a32aa1185163d84c0864b3c9a53005fc22b992a1 Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 15:27:56 -0500 Subject: [PATCH 6/8] fix(integrations): show file_path in OpenClaw write_note and edit_note results Both tool descriptions tell the agent to cite the note's permalink and file_path when confirming a save, but file_path appeared only in the structured details, not in the text the agent reads. The result text now includes a File: line. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/tools/edit-note.test.ts | 4 ++++ integrations/openclaw/tools/edit-note.ts | 2 +- integrations/openclaw/tools/write-note.test.ts | 2 +- integrations/openclaw/tools/write-note.ts | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/integrations/openclaw/tools/edit-note.test.ts b/integrations/openclaw/tools/edit-note.test.ts index 54908a5c6..a08cafb27 100644 --- a/integrations/openclaw/tools/edit-note.test.ts +++ b/integrations/openclaw/tools/edit-note.test.ts @@ -97,6 +97,10 @@ describe("edit tool", () => { }, undefined, ) + // The description tells agents to cite file_path, so it must be in the text. + expect(result.content[0].text).toBe( + "Note updated: Test Note (test-note)\nFile: notes/test-note.md", + ) expect(result.details).toEqual({ title: "Test Note", permalink: "test-note", diff --git a/integrations/openclaw/tools/edit-note.ts b/integrations/openclaw/tools/edit-note.ts index e634cf053..0beab6472 100644 --- a/integrations/openclaw/tools/edit-note.ts +++ b/integrations/openclaw/tools/edit-note.ts @@ -103,7 +103,7 @@ export function registerEditTool( content: [ { type: "text" as const, - text: `Note updated: ${note.title} (${note.permalink})`, + text: `Note updated: ${note.title} (${note.permalink})\nFile: ${note.file_path}`, }, ], details: { diff --git a/integrations/openclaw/tools/write-note.test.ts b/integrations/openclaw/tools/write-note.test.ts index f99f7fec5..56dc9ae1a 100644 --- a/integrations/openclaw/tools/write-note.test.ts +++ b/integrations/openclaw/tools/write-note.test.ts @@ -123,7 +123,7 @@ describe("write tool", () => { content: [ { type: "text", - text: "Note saved: Test Note (test-note)", + text: "Note saved: Test Note (test-note)\nFile: notes/test-note.md", }, ], details: { diff --git a/integrations/openclaw/tools/write-note.ts b/integrations/openclaw/tools/write-note.ts index a873d535c..e90d43c4c 100644 --- a/integrations/openclaw/tools/write-note.ts +++ b/integrations/openclaw/tools/write-note.ts @@ -123,7 +123,9 @@ export function registerWriteTool( const checksumSuffix = note.checksum ? `\nChecksum: ${note.checksum}` : "" - const msg = `Note saved: ${note.title} (${note.permalink})${checksumSuffix}` + // The description tells agents to cite permalink and file_path, so both + // must appear in the text the agent reads, not only in details. + const msg = `Note saved: ${note.title} (${note.permalink})\nFile: ${note.file_path}${checksumSuffix}` return { content: [ { From 61a1d3050f501ba816ca7d7f201b47c3276faafc Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 15:37:44 -0500 Subject: [PATCH 7/8] fix(integrations): show bm_edit errors and add section inserts to edit_note edit_note replaced every failure with 'Failed to edit note "...". It may not exist.' An agent that passed `section` with append got that message for an existing note, while the server's real reason was "INVALID_ARGUMENTS: `section` is only for section commands, not append." edit_note now shows the server's reason (new describeToolError helper in bm-client.ts), and still says plainly when the note does not exist. bm_edit already supports insert_before_section and insert_after_section, but the plugin offered only append, prepend, find_replace and replace_section. Agents adding an observation used append, which lands after "## Relations". edit_note now exposes both insert operations, and its description and docs/agent-guide.md say to use insert_after_section to add to a section. Verified live on OpenClaw 2026.10.9 through an agent: append with `section` returned the INVALID_ARGUMENTS reason; insert_after_section "Observations" placed the line directly under that heading. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/bm-client.ts | 26 +++++- integrations/openclaw/docs/agent-guide.md | 11 ++- integrations/openclaw/tools/edit-note.test.ts | 85 +++++++++++++++++-- integrations/openclaw/tools/edit-note.ts | 43 +++++++--- 4 files changed, 143 insertions(+), 22 deletions(-) diff --git a/integrations/openclaw/bm-client.ts b/integrations/openclaw/bm-client.ts index 39ce4e75a..25da573f9 100644 --- a/integrations/openclaw/bm-client.ts +++ b/integrations/openclaw/bm-client.ts @@ -87,7 +87,7 @@ export interface EditNoteResult { title: string permalink: string file_path: string - operation: "append" | "prepend" | "find_replace" | "replace_section" + operation: EditOperation checksum?: string | null } @@ -107,6 +107,16 @@ interface WriteNoteOptions { expectedChecksum?: string } +// bm_edit commands the plugin exposes. set_metadata is left out: edit_note +// already merges `metadata` alongside any other operation. +export type EditOperation = + | "append" + | "prepend" + | "find_replace" + | "replace_section" + | "insert_before_section" + | "insert_after_section" + interface EditNoteOptions { find_text?: string section?: string @@ -283,6 +293,18 @@ function parseRefusalPayload(text: string): Record | null { return isRecord(parsed) && typeof parsed.error === "string" ? parsed : null } +/** + * The server's own explanation of a failed tool call, for showing to an agent. + * A refusal payload becomes "CODE: message"; other tool text passes through. + */ +export function describeToolError(err: unknown): string { + if (!(err instanceof BmToolError)) return getErrorMessage(err) + const payload = parseRefusalPayload(err.toolMessage) + if (!payload) return err.toolMessage || err.message + const message = asString(payload.message) + return message ? `${payload.error}: ${message}` : String(payload.error) +} + function projectMatchesWorkspace( project: ProjectListResult, workspace: string, @@ -811,7 +833,7 @@ export class BmClient { async editNote( identifier: string, - operation: "append" | "prepend" | "find_replace" | "replace_section", + operation: EditOperation, content: string, options: EditNoteOptions = {}, project?: string, diff --git a/integrations/openclaw/docs/agent-guide.md b/integrations/openclaw/docs/agent-guide.md index 43bf0bc6b..55f59777a 100644 --- a/integrations/openclaw/docs/agent-guide.md +++ b/integrations/openclaw/docs/agent-guide.md @@ -166,7 +166,8 @@ write_note( ### `edit_note` **Purpose**: Modify existing notes incrementally **When to use**: To add updates, fix information, or organize existing content -**Operations**: append, prepend, find_replace, replace_section +**Operations**: append, prepend, find_replace, replace_section, insert_after_section, insert_before_section +**Adding to a section**: `append` always adds to the very end of the note, after `## Relations`. To add an observation, use `insert_after_section` with `section="Observations"`; the text goes directly below that heading. `insert_before_section` adds directly above a heading, at the end of the section before it. `section` is only accepted with the three section operations. **Frontmatter updates**: Pass `metadata` to merge custom frontmatter fields in the same call. Provided keys replace existing values, unrelated fields remain unchanged, and nested objects are supported. **Examples**: @@ -183,6 +184,14 @@ Next: Deploy to staging environment. """ ) +# Add an observation to the Observations section +edit_note( + identifier="projects/api-redesign", + operation="insert_after_section", + section="Observations", + content="- [decision] Ship token refresh behind a feature flag" +) + # Update a specific section edit_note( identifier="weekly-review", diff --git a/integrations/openclaw/tools/edit-note.test.ts b/integrations/openclaw/tools/edit-note.test.ts index a08cafb27..d0a230f3b 100644 --- a/integrations/openclaw/tools/edit-note.test.ts +++ b/integrations/openclaw/tools/edit-note.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, jest } from "bun:test" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, BmToolError } from "../bm-client.ts" import { registerEditTool } from "./edit-note.ts" describe("edit tool", () => { @@ -234,30 +234,103 @@ describe("edit tool", () => { ) }) - it("returns friendly error when edit fails", async () => { + it("passes insert_after_section and its heading through to bm_edit", async () => { + ;(mockClient.editNote as jest.MockedFunction).mockResolvedValue({ + title: "Test Note", + permalink: "test-note", + file_path: "notes/test-note.md", + operation: "insert_after_section", + }) + + await executeFunction("tool-call-id", { + identifier: "test-note", + operation: "insert_after_section", + content: "- [test] a new observation", + section: "Observations", + }) + + expect(mockClient.editNote).toHaveBeenCalledWith( + "test-note", + "insert_after_section", + "- [test] a new observation", + { + find_text: undefined, + section: "Observations", + expected_replacements: undefined, + metadata: undefined, + }, + undefined, + ) + }) + + // Regression: every failure used to read "It may not exist", which hid + // the server's actual reason (here, `section` passed with append). + it("shows the server's reason when bm_edit refuses the arguments", async () => { ;(mockClient.editNote as jest.MockedFunction).mockRejectedValue( - new Error("edit failed"), + new BmToolError( + "bm_edit", + JSON.stringify({ + error: "INVALID_ARGUMENTS", + message: "`section` is only for section commands, not append.", + }), + ), ) const result = await executeFunction("tool-call-id", { - identifier: "missing-note", + identifier: "test-note", operation: "append", content: "new", + section: "Observations", }) expect(result).toEqual({ content: [ { type: "text", - text: 'Failed to edit note "missing-note". It may not exist.', + text: 'Failed to edit note "test-note": INVALID_ARGUMENTS: `section` is only for section commands, not append.', }, ], details: { - identifier: "missing-note", + identifier: "test-note", operation: "append", error: "edit_note_failed", }, }) }) + + it("says a missing note does not exist", async () => { + ;(mockClient.editNote as jest.MockedFunction).mockRejectedValue( + new BmToolError( + "bm_edit", + JSON.stringify({ error: "NOT_FOUND", message: "Note not found" }), + ), + ) + + const result = await executeFunction("tool-call-id", { + identifier: "missing-note", + operation: "append", + content: "new", + }) + + expect(result.content[0].text).toBe( + 'Failed to edit note "missing-note": it does not exist. NOT_FOUND: Note not found', + ) + }) + + it("passes through a non-tool error message", async () => { + ;(mockClient.editNote as jest.MockedFunction).mockRejectedValue( + new Error("BM MCP unavailable: connection closed"), + ) + + const result = await executeFunction("tool-call-id", { + identifier: "test-note", + operation: "append", + content: "new", + }) + + expect(result.content[0].text).toBe( + 'Failed to edit note "test-note": BM MCP unavailable: connection closed', + ) + }) }) }) diff --git a/integrations/openclaw/tools/edit-note.ts b/integrations/openclaw/tools/edit-note.ts index 0beab6472..c4aed3177 100644 --- a/integrations/openclaw/tools/edit-note.ts +++ b/integrations/openclaw/tools/edit-note.ts @@ -1,6 +1,11 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { + type BmClient, + describeToolError, + type EditOperation, + isNoteNotFoundError, +} from "../bm-client.ts" import { log } from "../logger.ts" export function registerEditTool( @@ -13,8 +18,11 @@ export function registerEditTool( label: "Edit Note", description: "Incrementally edit an existing note in the Basic Memory knowledge graph. " + - "Supports append, prepend, find/replace, and section replacement " + - "without rewriting the entire note. The result returns the note's " + + "Supports append, prepend, find/replace, replacing a section, and inserting " + + "next to a section heading, without rewriting the entire note. To add to a " + + "specific section (for example a new observation), use insert_after_section " + + "with that heading; append always adds to the very end of the note. " + + "The result returns the note's " + "permalink and file_path: cite those exact values when confirming " + "the edit — never report a save that no tool call performed.", parameters: Type.Object({ @@ -27,11 +35,15 @@ export function registerEditTool( Type.Literal("prepend"), Type.Literal("find_replace"), Type.Literal("replace_section"), + Type.Literal("insert_before_section"), + Type.Literal("insert_after_section"), ], { description: - "Edit operation: append (add to end), prepend (add to start), " + - "find_replace (replace matching text), replace_section (replace a heading section)", + "Edit operation: append (add to end of note), prepend (add to start), " + + "find_replace (replace matching text), replace_section (replace a heading section), " + + "insert_after_section (add directly below a heading, at the top of its section), " + + "insert_before_section (add directly above a heading, at the end of the section before it)", }, ), content: Type.String({ @@ -45,7 +57,8 @@ export function registerEditTool( section: Type.Optional( Type.String({ description: - "Section heading to replace (required for replace_section)", + "Section heading, e.g. 'Observations' (required for replace_section, " + + "insert_before_section and insert_after_section; not allowed with other operations)", }), ), expected_replacements: Type.Optional( @@ -74,7 +87,7 @@ export function registerEditTool( _toolCallId: string, params: { identifier: string - operation: "append" | "prepend" | "find_replace" | "replace_section" + operation: EditOperation content: string find_text?: string section?: string @@ -116,13 +129,17 @@ export function registerEditTool( } } catch (err) { log.error("edit_note failed", err) + // Trigger: any edit failure, including invalid arguments and + // checksum conflicts, not only a missing note. + // Why: a blanket "may not exist" sent agents hunting for the wrong + // problem; the server's message says what to change. + // Outcome: the agent sees the server's reason verbatim. + const reason = describeToolError(err) + const text = isNoteNotFoundError(err) + ? `Failed to edit note "${params.identifier}": it does not exist. ${reason}` + : `Failed to edit note "${params.identifier}": ${reason}` return { - content: [ - { - type: "text" as const, - text: `Failed to edit note "${params.identifier}". It may not exist.`, - }, - ], + content: [{ type: "text" as const, text }], details: { identifier: params.identifier, operation: params.operation, From ccccfbbe7532f0573393e539b3aa94076f5a3377 Mon Sep 17 00:00:00 2001 From: Drew Cain Date: Thu, 29 Oct 2026 15:51:20 -0500 Subject: [PATCH 8/8] fix(integrations): start the OpenClaw plugin in the background and tidy tool output Fixes the follow-ups found while testing the plugin on OpenClaw 2026.10.9. Startup - Service start returned only after connecting to bm, creating the project and seeding two schema notes. A first start took about 12 s (the first note write alone took 4-9 s), against OpenClaw's 5 s service limit. The timed-out start failed the plugin, and the failed hot reload left the gateway unable to list models until a restart. BmClient.start() now runs connect plus project creation as a startup gate. Tool calls wait for it, and a failed startup is retried by the next tool call. The service starts it without waiting, and seeds schemas afterwards. The bm --version probe and the uv auto-install are now async, so neither blocks OpenClaw's event loop. - On a fresh install the workspace directory does not exist until the first agent run, and spawning bm into it failed with a misleading "ENOENT ... posix_spawn 'bm'". The service now creates it first. Tool output - search_notes, the CLI and the memory provider previewed the start of each note. A fact deep in a long note, such as a day of captured conversation, was matched but cut off. They now preview the server's matched_chunk, and search_notes shows up to 500 characters. - build_context printed each note, then repeated its observations. It now lists only observations missing from the shown body, and shows an unresolved [[link]] by its name ("(no note yet)") instead of "null". - Every tool's catch-all ("It may not exist", "Is Basic Memory running? Check logs") now shows the server's reason (describeToolError / describeNoteError in bm-client.ts), and says "does not exist" only when the server reported NOT_FOUND. Verified live on OpenClaw 2026.10.9: a hot install against a brand-new project applied in 0.09 s ("Plugin replacement applied") instead of timing out, and seeding finished in the background. Through an agent, search_notes previewed the matching turn, build_context listed the observation once, and read_note on a missing note returned "it does not exist. NOT_FOUND: ...". Not changed here: most of `openclaw memory status`'s 11-13 s is OpenClaw itself (about 8.7 s before bm starts). The bm mcp share (about 1.7 s) is #1731. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Cain --- integrations/openclaw/bm-client.test.ts | 92 ++++++++++ integrations/openclaw/bm-client.ts | 96 ++++++++++- integrations/openclaw/commands/cli.ts | 9 +- integrations/openclaw/commands/slash.ts | 6 +- integrations/openclaw/index.test.ts | 42 +++-- integrations/openclaw/index.ts | 157 +++++++++--------- .../memory/basic-memory-capability.ts | 8 +- .../openclaw/tools/build-context.test.ts | 67 +++++++- integrations/openclaw/tools/build-context.ts | 19 ++- integrations/openclaw/tools/delete-note.ts | 4 +- integrations/openclaw/tools/edit-note.ts | 8 +- .../tools/list-memory-projects.test.ts | 2 +- .../openclaw/tools/list-memory-projects.ts | 8 +- .../openclaw/tools/list-workspaces.test.ts | 2 +- .../openclaw/tools/list-workspaces.ts | 8 +- integrations/openclaw/tools/move-note.ts | 4 +- integrations/openclaw/tools/read-note.test.ts | 2 +- integrations/openclaw/tools/read-note.ts | 4 +- integrations/openclaw/tools/schema-diff.ts | 4 +- integrations/openclaw/tools/schema-infer.ts | 4 +- .../openclaw/tools/schema-validate.ts | 4 +- .../openclaw/tools/search-notes.test.ts | 31 +++- integrations/openclaw/tools/search-notes.ts | 18 +- .../openclaw/tools/write-note.test.ts | 6 +- integrations/openclaw/tools/write-note.ts | 5 +- 25 files changed, 467 insertions(+), 143 deletions(-) diff --git a/integrations/openclaw/bm-client.test.ts b/integrations/openclaw/bm-client.test.ts index 1d55f9201..cc4fd3529 100644 --- a/integrations/openclaw/bm-client.test.ts +++ b/integrations/openclaw/bm-client.test.ts @@ -2,6 +2,8 @@ import { beforeEach, describe, expect, it, jest } from "bun:test" import { BmClient, BmToolError, + describeNoteError, + describeToolError, NoteAlreadyExistsError, NoteRevisionConflictError, } from "./bm-client.ts" @@ -943,6 +945,96 @@ describe("BmClient MCP behavior", () => { expect(args[4]).toBeUndefined() // overwrite }) + it("describes tool errors with the server's own reason", () => { + expect( + describeToolError( + new BmToolError( + "bm_edit", + JSON.stringify({ error: "CONFLICT", message: "checksum changed" }), + ), + ), + ).toBe("CONFLICT: checksum changed") + // Plain-text tool failures (older servers) pass through unchanged. + expect( + describeToolError(new BmToolError("bm_read", "database is locked")), + ).toBe("database is locked") + expect(describeToolError(new Error("spawn bm ENOENT"))).toBe( + "spawn bm ENOENT", + ) + expect( + describeNoteError( + new BmToolError( + "bm_read", + JSON.stringify({ error: "NOT_FOUND", message: "Missing note" }), + ), + ), + ).toBe("it does not exist. NOT_FOUND: Missing note") + }) + + describe("startup gate", () => { + const structured = (payload: unknown) => ({ structuredContent: payload }) + + it("holds tool calls until startup has created the project", async () => { + let finishConnect = () => {} + ;(client as any).connectWithRetries = jest.fn( + () => + new Promise((resolve) => { + finishConnect = resolve + }), + ) + const callToolRaw = jest.fn( + async (_name: string, args: Record) => + args.command === "create" + ? structured({ ok: true }) + : structured({ projects: [] }), + ) + ;(client as any).callToolRaw = callToolRaw + + const startup = client.start({ projectPath: "/tmp/ws/memory" }) + const listing = client.listProjects() + await Promise.resolve() + expect(callToolRaw).not.toHaveBeenCalled() + + finishConnect() + await startup + await listing + + // Project creation runs first, then the waiting call. + expect(callToolRaw.mock.calls.map(([name]) => name)).toEqual([ + "bm_project", + "bm_project", + ]) + expect(callToolRaw.mock.calls[0][1]).toMatchObject({ command: "create" }) + expect(callToolRaw.mock.calls[1][1]).toMatchObject({ command: "list" }) + }) + + it("retries a failed startup once for the next tool calls", async () => { + const connect = jest + .fn() + .mockRejectedValueOnce(new Error("bm not ready")) + .mockResolvedValue(undefined) + ;(client as any).connectWithRetries = connect + ;(client as any).callToolRaw = jest.fn(async () => + structured({ projects: [] }), + ) + + await expect(client.start()).rejects.toThrow("bm not ready") + await Promise.all([client.listProjects(), client.listProjects()]) + + // One original attempt plus one retry shared by both callers. + expect(connect).toHaveBeenCalledTimes(2) + }) + + it("surfaces the retry's error when startup keeps failing", async () => { + ;(client as any).connectWithRetries = jest + .fn() + .mockRejectedValue(new Error("BM MCP unavailable: spawn bm ENOENT")) + + await expect(client.start()).rejects.toThrow("spawn bm ENOENT") + await expect(client.listProjects()).rejects.toThrow("spawn bm ENOENT") + }) + }) + it("reports the service as running only between start() and stop()", async () => { ;(client as any).connectWithRetries = jest.fn().mockResolvedValue(undefined) ;(client as any).disconnectCurrent = jest.fn().mockResolvedValue(undefined) diff --git a/integrations/openclaw/bm-client.ts b/integrations/openclaw/bm-client.ts index 25da573f9..9b75c5956 100644 --- a/integrations/openclaw/bm-client.ts +++ b/integrations/openclaw/bm-client.ts @@ -71,6 +71,17 @@ export interface SearchResult { content: string score?: number file_path: string + // The chunk of the note that matched, when the server ranked by chunk. + matched_chunk?: string | null +} + +/** + * The text to preview for a search hit. `content` is the start of the note, + * so for a long note (a day of captured conversation) the matching part can + * sit far below any preview cut-off; the matched chunk is the part that hit. + */ +export function searchResultText(result: SearchResult): string { + return result.matched_chunk?.trim() || result.content || "" } export interface NoteResult { @@ -137,7 +148,10 @@ export interface ContextResult { permalink: string relation_type?: string from_entity?: string - to_entity?: string + // Null for a forward reference whose target note does not exist yet; + // to_name then carries the link text. + to_entity?: string | null + to_name?: string | null }> }> } @@ -305,6 +319,12 @@ export function describeToolError(err: unknown): string { return message ? `${payload.error}: ${message}` : String(payload.error) } +/** describeToolError, but saying plainly when the note does not exist. */ +export function describeNoteError(err: unknown): string { + const reason = describeToolError(err) + return isNoteNotFoundError(err) ? `it does not exist. ${reason}` : reason +} + function projectMatchesWorkspace( project: ProjectListResult, workspace: string, @@ -331,6 +351,13 @@ export class BmClient { // the BM MCP session. A lazy connection opened by a tool or memory call in a // one-shot CLI process leaves this false. private serviceRunning = false + // Connect plus project creation, started by start(). Tool calls wait for + // it so none can reach a project that does not exist yet. Null when the + // client was never started (tests, one-shot CLI readers). + private startup: Promise | null = null + private startupRetry: Promise | null = null + private projectPath?: string + private prepare?: () => Promise private client: Client | null = null private transport: StdioClientTransport | null = null @@ -345,9 +372,20 @@ export class BmClient { this.project = project } - async start(options?: { + /** + * Connect to BM and create the plugin's project. + * + * Returns the startup promise; callers that must not block (the plugin + * service, which OpenClaw gives only a few seconds) can leave it running. + * Tool calls made meanwhile wait for it. If it fails, the next tool call + * runs it again, so a transient failure does not leave the plugin dead. + */ + start(options?: { cwd?: string env?: Record + projectPath?: string + // Runs before each connect attempt, e.g. installing the bm CLI. + prepare?: () => Promise }): Promise { this.shouldRun = true this.serviceRunning = true @@ -357,8 +395,42 @@ export class BmClient { if (options?.env) { this.env = options.env } + if (options?.projectPath) { + this.projectPath = options.projectPath + } + if (options?.prepare) { + this.prepare = options.prepare + } + this.startup = this.runStartup() + return this.startup + } + + private async runStartup(): Promise { + await this.prepare?.() await this.connectWithRetries() + if (this.projectPath) await this.createProject(this.projectPath) + } + + private async waitForStartup(): Promise { + if (!this.startup) return + try { + await this.startup + } catch (err) { + // Trigger: the startup this call was waiting on failed. + // Why: the service no longer fails on a slow or failed start, so the + // first tool call afterwards is the place to recover. + // Outcome: one fresh attempt, shared by concurrent callers; its error + // reaches the tool if it fails too. + if (!this.serviceRunning) throw err + if (this.startupRetry === null) { + this.startupRetry = this.runStartup().finally(() => { + this.startupRetry = null + }) + this.startup = this.startupRetry + } + await this.startupRetry + } } isServiceRunning(): boolean { @@ -368,6 +440,10 @@ export class BmClient { async stop(): Promise { this.shouldRun = false this.serviceRunning = false + // Let an in-flight startup settle first, so it cannot reconnect after + // the disconnect below. + await this.startup?.catch(() => undefined) + this.startup = null await this.disconnectCurrent(this.client, this.transport) this.client = null this.transport = null @@ -568,6 +644,15 @@ export class BmClient { private async callTool( name: string, args: Record, + ): Promise { + await this.waitForStartup() + return this.callStructured(name, args) + } + + // Ungated: startup itself calls this to create the project. + private async callStructured( + name: string, + args: Record, ): Promise { const result = await this.callToolRaw(name, args) @@ -594,7 +679,12 @@ export class BmClient { } async ensureProject(projectPath: string): Promise { - const payload = await this.callTool("bm_project", { + await this.waitForStartup() + await this.createProject(projectPath) + } + + private async createProject(projectPath: string): Promise { + const payload = await this.callStructured("bm_project", { command: "create", name: this.project, path: projectPath, diff --git a/integrations/openclaw/commands/cli.ts b/integrations/openclaw/commands/cli.ts index a189a4242..7f0802e1d 100644 --- a/integrations/openclaw/commands/cli.ts +++ b/integrations/openclaw/commands/cli.ts @@ -1,5 +1,5 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, searchResultText } from "../bm-client.ts" import type { BasicMemoryConfig } from "../config.ts" import { log } from "../logger.ts" @@ -33,11 +33,10 @@ export function registerCli( for (const r of results) { const score = r.score ? ` (score ${r.score.toFixed(2)})` : "" console.log(`- ${r.title}${score}`) - if (r.content) { + const text = searchResultText(r) + if (text) { const preview = - r.content.length > 100 - ? `${r.content.slice(0, 100)}...` - : r.content + text.length > 100 ? `${text.slice(0, 100)}...` : text console.log(` ${preview}`) } } diff --git a/integrations/openclaw/commands/slash.ts b/integrations/openclaw/commands/slash.ts index d25a3411f..2b1b9462e 100644 --- a/integrations/openclaw/commands/slash.ts +++ b/integrations/openclaw/commands/slash.ts @@ -2,7 +2,7 @@ import { execSync } from "node:child_process" import { dirname, resolve } from "node:path" import { fileURLToPath } from "node:url" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeToolError } from "../bm-client.ts" import { log } from "../logger.ts" const __dirname = dirname(fileURLToPath(import.meta.url)) @@ -62,7 +62,7 @@ export function registerCommands( } catch (err) { log.error("/remember failed", err) return { - text: "Failed to save memory. Is Basic Memory running?", + text: `Failed to save memory: ${describeToolError(err)}`, } } }, @@ -99,7 +99,7 @@ export function registerCommands( } catch (err) { log.error("/recall failed", err) return { - text: "Failed to search. Is Basic Memory running?", + text: `Failed to search: ${describeToolError(err)}`, } } }, diff --git a/integrations/openclaw/index.test.ts b/integrations/openclaw/index.test.ts index b566ad61a..4c5f93874 100644 --- a/integrations/openclaw/index.test.ts +++ b/integrations/openclaw/index.test.ts @@ -1,5 +1,7 @@ import { afterEach, describe, expect, it, jest } from "bun:test" -import { existsSync, rmSync } from "node:fs" +import { existsSync, mkdtempSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" import { BmClient } from "./bm-client.ts" import plugin, { isCommandAvailable } from "./index.ts" @@ -9,12 +11,13 @@ describe("plugin service lifecycle", () => { }) it("starts MCP client, ensures project path, and stops cleanly", async () => { - const startSpy = jest - .spyOn(BmClient.prototype, "start") - .mockResolvedValue(undefined) - const ensureProjectSpy = jest - .spyOn(BmClient.prototype, "ensureProject") - .mockResolvedValue(undefined) + // Held open so the test can show service start does not wait for it. + let finishStartup = () => {} + const startSpy = jest.spyOn(BmClient.prototype, "start").mockReturnValue( + new Promise((resolve) => { + finishStartup = resolve + }), + ) const readNoteSpy = jest .spyOn(BmClient.prototype, "readNote") .mockRejectedValue(new Error("Entity not found")) @@ -77,10 +80,24 @@ describe("plugin service lifecycle", () => { expect(toolNames).not.toContain("memory_search") expect(toolNames).not.toContain("memory_get") - await services[0].start({ workspaceDir: "/tmp/workspace" }) + // A fresh OpenClaw install has no workspace directory yet. + const root = mkdtempSync(join(tmpdir(), "openclaw-bm-")) + const workspace = join(root, "workspace") + + await services[0].start({ workspaceDir: workspace }) + + // Startup runs in the background: service start returned while the BM + // connection is still pending, with the workspace already created. + expect(existsSync(workspace)).toBe(true) + expect(startSpy).toHaveBeenCalledWith({ + cwd: workspace, + projectPath: join(workspace, "memory"), + prepare: expect.any(Function), + }) + expect(readNoteSpy).not.toHaveBeenCalled() - expect(startSpy).toHaveBeenCalledWith({ cwd: "/tmp/workspace" }) - expect(ensureProjectSpy).toHaveBeenCalledWith("/tmp/workspace/memory") + finishStartup() + await new Promise((resolve) => setTimeout(resolve, 0)) // Schema seed: readNote throws "not found" → writeNote called expect(readNoteSpy).toHaveBeenCalledWith("schema/Task") @@ -93,13 +110,14 @@ describe("plugin service lifecycle", () => { await services[0].stop() expect(stopSpy).toHaveBeenCalledTimes(1) + rmSync(root, { recursive: true, force: true }) }) - it("checks configured bmPath without invoking a shell", () => { + it("checks configured bmPath without invoking a shell", async () => { const marker = `/tmp/openclaw-bm-shell-${process.pid}` rmSync(marker, { force: true }) - expect(isCommandAvailable(`bm; touch ${marker}`)).toBe(false) + expect(await isCommandAvailable(`bm; touch ${marker}`)).toBe(false) expect(existsSync(marker)).toBe(false) }) }) diff --git a/integrations/openclaw/index.ts b/integrations/openclaw/index.ts index c5ae80c09..3bb2ef3b3 100644 --- a/integrations/openclaw/index.ts +++ b/integrations/openclaw/index.ts @@ -1,4 +1,6 @@ -import { execFileSync } from "node:child_process" +import { execFile } from "node:child_process" +import { mkdir } from "node:fs/promises" +import { promisify } from "node:util" import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry" import { BmClient } from "./bm-client.ts" @@ -28,15 +30,66 @@ import { registerSchemaValidateTool } from "./tools/schema-validate.ts" import { registerSearchTool } from "./tools/search-notes.ts" import { registerWriteTool } from "./tools/write-note.ts" -export function isCommandAvailable(command: string): boolean { +const execFileAsync = promisify(execFile) + +// Async so a probe or an install never blocks OpenClaw's event loop during +// plugin startup. +export async function isCommandAvailable(command: string): Promise { try { - execFileSync(command, ["--version"], { stdio: "ignore" }) + await execFileAsync(command, ["--version"]) return true } catch { return false } } +async function installBasicMemoryIfMissing(bmBin: string): Promise { + if (await isCommandAvailable(bmBin)) return + + log.info("bm CLI not found on PATH — attempting auto-install...") + if (!(await isCommandAvailable("uv"))) { + throw new Error( + "Cannot auto-install basic-memory: uv not found. " + + "Install uv first (brew install uv, or curl -LsSf https://astral.sh/uv/install.sh | sh), " + + "then restart the gateway.", + ) + } + + log.info("installing basic-memory via uv (this may take a minute)...") + // basic-memory pins a FastMCP pre-release; without this flag uv silently + // installs the last release that had none (#1338). + const { stdout } = await execFileAsync( + "uv", + ["tool", "install", "basic-memory", "--prerelease=allow", "--force"], + { encoding: "utf-8", timeout: 120_000 }, + ) + log.info(`basic-memory installed: ${stdout.trim().split("\n").pop()}`) + if (!(await isCommandAvailable(bmBin))) { + throw new Error( + "bm installed but not found on PATH. You may need to add uv's bin directory to your PATH (typically ~/.local/bin).", + ) + } +} + +async function seedSchemas(client: BmClient): Promise { + for (const [name, content] of [ + ["Task", TASK_SCHEMA_CONTENT], + ["Conversation", CONVERSATION_SCHEMA_CONTENT], + ] as const) { + try { + await client.readNote(`schema/${name}`) + log.debug(`${name} schema already exists, skipping seed`) + } catch { + try { + await client.writeNote(name, content, "schema") + log.debug(`seeded ${name} schema note`) + } catch (err) { + log.debug(`${name} schema seed failed (non-fatal)`, err) + } + } + } +} + export default definePluginEntry({ id: "openclaw-basic-memory", name: "Basic Memory", @@ -94,81 +147,37 @@ export default definePluginEntry({ start: async (ctx: { config?: unknown; workspaceDir?: string }) => { log.info("starting...") - // Auto-install bm CLI if not found - const bmBin = cfg.bmPath || "bm" - if (!isCommandAvailable(bmBin)) { - log.info("bm CLI not found on PATH — attempting auto-install...") - try { - if (!isCommandAvailable("uv")) { - throw new Error("uv not found") - } - log.info( - "installing basic-memory via uv (this may take a minute)...", - ) - // basic-memory pins a FastMCP pre-release; without this flag uv - // silently installs the last release that had none (#1338). - const result = execFileSync( - "uv", - [ - "tool", - "install", - "basic-memory", - "--prerelease=allow", - "--force", - ], - { - encoding: "utf-8", - timeout: 120_000, - stdio: ["ignore", "pipe", "pipe"], - }, - ) - log.info( - `basic-memory installed: ${result.trim().split("\n").pop()}`, - ) - // Verify it worked - if (isCommandAvailable(bmBin)) { - log.info("bm CLI now available on PATH") - } else { - log.error( - "bm installed but not found on PATH. You may need to add uv's bin directory to your PATH (typically ~/.local/bin).", - ) - } - } catch (_uvErr) { - log.error( - "Cannot auto-install basic-memory: uv not found. " + - "Install uv first (brew install uv, or curl -LsSf https://astral.sh/uv/install.sh | sh), " + - "then restart the gateway.", - ) - } - } - const workspace = ctx.workspaceDir ?? process.cwd() const projectPath = resolveProjectPath(cfg.projectPath, workspace) cfg.projectPath = projectPath - await client.start({ cwd: workspace }) - await client.ensureProject(projectPath) - log.debug(`project "${cfg.project}" at ${projectPath}`) - - // Seed schemas if not already present - for (const [name, content] of [ - ["Task", TASK_SCHEMA_CONTENT], - ["Conversation", CONVERSATION_SCHEMA_CONTENT], - ] as const) { - try { - await client.readNote(`schema/${name}`) - log.debug(`${name} schema already exists, skipping seed`) - } catch { - try { - await client.writeNote(name, content, "schema") - log.debug(`seeded ${name} schema note`) - } catch (err) { - log.debug(`${name} schema seed failed (non-fatal)`, err) - } - } - } - - log.info("connected — BM MCP stdio session running") + // bm runs with the workspace as its working directory. OpenClaw + // creates its default workspace only on the first agent run, and + // spawning into a missing directory fails with an ENOENT that names + // the bm binary instead of the directory. + await mkdir(workspace, { recursive: true }) + + // OpenClaw gives a service about 5 s to start. A first start (bm + // install, cold imports, first indexing) takes far longer, and a + // timed-out start fails the plugin. So startup runs in the + // background; tool calls wait for it inside BmClient, and a failed + // startup is retried by the next tool call instead of failing here. + client + .start({ + cwd: workspace, + projectPath, + prepare: () => installBasicMemoryIfMissing(cfg.bmPath || "bm"), + }) + .then(async () => { + log.info("connected — BM MCP stdio session running") + await seedSchemas(client) + }) + .catch((err) => { + log.error( + "Basic Memory startup failed; the next tool call will retry", + err, + ) + }) }, stop: async () => { log.info("stopping BM MCP session...") diff --git a/integrations/openclaw/memory/basic-memory-capability.ts b/integrations/openclaw/memory/basic-memory-capability.ts index 65f73f36b..8f305f60d 100644 --- a/integrations/openclaw/memory/basic-memory-capability.ts +++ b/integrations/openclaw/memory/basic-memory-capability.ts @@ -1,5 +1,9 @@ import type { MemoryPluginCapability } from "openclaw/plugin-sdk/memory-host-core" -import { type BmClient, isNoteNotFoundError } from "../bm-client.ts" +import { + type BmClient, + isNoteNotFoundError, + searchResultText, +} from "../bm-client.ts" import { log } from "../logger.ts" // OpenClaw documents deriving the provider types from the public capability @@ -137,7 +141,7 @@ export function openBasicMemoryReader( ) .map(({ result, score }) => ({ reference: { providerId: MEMORY_PROVIDER_ID, id: result.permalink }, - excerpt: excerptOf(result.content ?? ""), + excerpt: excerptOf(searchResultText(result)), source: result.file_path, ...(score === undefined ? {} : { score }), })) diff --git a/integrations/openclaw/tools/build-context.test.ts b/integrations/openclaw/tools/build-context.test.ts index c6f52f3b4..d655e40bc 100644 --- a/integrations/openclaw/tools/build-context.test.ts +++ b/integrations/openclaw/tools/build-context.test.ts @@ -190,6 +190,71 @@ describe("context tool", () => { expect(result.content[0].text).toContain("No context found") }) + // Regression: the note body was printed, then its observations again. + it("does not repeat observations already in the note body", async () => { + ;(mockClient.buildContext as jest.MockedFunction).mockResolvedValue({ + results: [ + { + primary_result: { + title: "ctx-probe", + permalink: "tests/ctx-probe", + content: + "# ctx-probe\n\n## Observations\n- [test] alpha fact\n\n## Relations\n- relates_to [[Quillfeather]]", + file_path: "tests/ctx-probe.md", + }, + observations: [ + { category: "test", content: "alpha fact" }, + { category: "idea", content: "only in the index" }, + ], + related_results: [], + }, + ], + }) + + const result = await executeFunction("tool-call-id", { + url: "memory://tests/ctx-probe", + }) + + const text = result.content[0].text + expect(text.match(/\[test\] alpha fact/g)).toHaveLength(1) + expect(text).toContain("### Observations\n- [idea] only in the index") + }) + + // Regression: an unresolved [[link]] rendered as "relates_to → **null**". + it("names the target of a link whose note does not exist yet", async () => { + ;(mockClient.buildContext as jest.MockedFunction).mockResolvedValue({ + results: [ + { + primary_result: { + title: "ctx-smoke", + permalink: "tests/ctx-smoke", + content: "# ctx-smoke", + file_path: "tests/ctx-smoke.md", + }, + observations: [], + related_results: [ + { + type: "relation", + permalink: "tests/ctx-smoke", + relation_type: "relates_to", + to_entity: null, + to_name: "Quillfeather", + }, + ], + }, + ], + }) + + const result = await executeFunction("tool-call-id", { + url: "memory://tests/ctx-smoke", + }) + + expect(result.content[0].text).toContain( + "- relates_to → **Quillfeather** (no note yet)", + ) + expect(result.content[0].text).not.toContain("null") + }) + it("should handle multiple results", async () => { const mockContext = { results: [ @@ -426,7 +491,7 @@ describe("context tool", () => { content: [ { type: "text", - text: 'Failed to build context for "memory://error/test". Check logs for details.', + text: 'Failed to build context for "memory://error/test": Failed to build context', }, ], details: { diff --git a/integrations/openclaw/tools/build-context.ts b/integrations/openclaw/tools/build-context.ts index d1f027ec3..f4552762b 100644 --- a/integrations/openclaw/tools/build-context.ts +++ b/integrations/openclaw/tools/build-context.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeToolError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerContextTool( @@ -67,8 +67,15 @@ export function registerContextTool( const primary = result.primary_result sections.push(`## ${primary.title}\n${primary.content}`) - if (result.observations?.length > 0) { - const obs = result.observations + // The note body already contains its observations as + // "- [category] text" lines, so listing them again doubled the + // output. Only observations missing from the shown body (for + // example when the server truncates a long note) are listed. + const unseen = (result.observations ?? []).filter( + (o) => !primary.content?.includes(`[${o.category}] ${o.content}`), + ) + if (unseen.length > 0) { + const obs = unseen .map((o) => `- [${o.category}] ${o.content}`) .join("\n") sections.push(`### Observations\n${obs}`) @@ -78,7 +85,9 @@ export function registerContextTool( const rels = result.related_results .map((r) => { if (r.type === "relation") { - return `- ${r.relation_type} → **${r.to_entity}**` + return r.to_entity + ? `- ${r.relation_type} → **${r.to_entity}**` + : `- ${r.relation_type} → **${r.to_name ?? "unknown"}** (no note yet)` } const label = r.relation_type ? `${r.relation_type} → **${r.title}**` @@ -111,7 +120,7 @@ export function registerContextTool( content: [ { type: "text" as const, - text: `Failed to build context for "${params.url}". Check logs for details.`, + text: `Failed to build context for "${params.url}": ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/delete-note.ts b/integrations/openclaw/tools/delete-note.ts index e8408ed8e..cfd51c43b 100644 --- a/integrations/openclaw/tools/delete-note.ts +++ b/integrations/openclaw/tools/delete-note.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeNoteError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerDeleteTool( @@ -55,7 +55,7 @@ export function registerDeleteTool( content: [ { type: "text" as const, - text: `Failed to delete "${params.identifier}". It may not exist.`, + text: `Failed to delete "${params.identifier}": ${describeNoteError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/edit-note.ts b/integrations/openclaw/tools/edit-note.ts index c4aed3177..bf86b726e 100644 --- a/integrations/openclaw/tools/edit-note.ts +++ b/integrations/openclaw/tools/edit-note.ts @@ -2,9 +2,8 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" import { type BmClient, - describeToolError, + describeNoteError, type EditOperation, - isNoteNotFoundError, } from "../bm-client.ts" import { log } from "../logger.ts" @@ -134,10 +133,7 @@ export function registerEditTool( // Why: a blanket "may not exist" sent agents hunting for the wrong // problem; the server's message says what to change. // Outcome: the agent sees the server's reason verbatim. - const reason = describeToolError(err) - const text = isNoteNotFoundError(err) - ? `Failed to edit note "${params.identifier}": it does not exist. ${reason}` - : `Failed to edit note "${params.identifier}": ${reason}` + const text = `Failed to edit note "${params.identifier}": ${describeNoteError(err)}` return { content: [{ type: "text" as const, text }], details: { diff --git a/integrations/openclaw/tools/list-memory-projects.test.ts b/integrations/openclaw/tools/list-memory-projects.test.ts index 19d503c8c..0b6d347bc 100644 --- a/integrations/openclaw/tools/list-memory-projects.test.ts +++ b/integrations/openclaw/tools/list-memory-projects.test.ts @@ -198,7 +198,7 @@ describe("project list tool", () => { content: [ { type: "text", - text: "Failed to list Basic Memory projects. Is Basic Memory running? Check logs for details.", + text: "Failed to list Basic Memory projects: boom", }, ], details: { diff --git a/integrations/openclaw/tools/list-memory-projects.ts b/integrations/openclaw/tools/list-memory-projects.ts index b26317061..2c81a21b3 100644 --- a/integrations/openclaw/tools/list-memory-projects.ts +++ b/integrations/openclaw/tools/list-memory-projects.ts @@ -1,6 +1,10 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient, ProjectListResult } from "../bm-client.ts" +import { + type BmClient, + describeToolError, + type ProjectListResult, +} from "../bm-client.ts" import { log } from "../logger.ts" function normalizeProject(project: ProjectListResult) { @@ -102,7 +106,7 @@ export function registerProjectListTool( content: [ { type: "text" as const, - text: "Failed to list Basic Memory projects. Is Basic Memory running? Check logs for details.", + text: `Failed to list Basic Memory projects: ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/list-workspaces.test.ts b/integrations/openclaw/tools/list-workspaces.test.ts index fcdccee9c..2f36044b3 100644 --- a/integrations/openclaw/tools/list-workspaces.test.ts +++ b/integrations/openclaw/tools/list-workspaces.test.ts @@ -119,7 +119,7 @@ describe("workspace list tool", () => { content: [ { type: "text", - text: "Failed to list workspaces. Is Basic Memory running? Check logs for details.", + text: "Failed to list workspaces: boom", }, ], details: { diff --git a/integrations/openclaw/tools/list-workspaces.ts b/integrations/openclaw/tools/list-workspaces.ts index e728b50d6..2ede2d23e 100644 --- a/integrations/openclaw/tools/list-workspaces.ts +++ b/integrations/openclaw/tools/list-workspaces.ts @@ -1,6 +1,10 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient, WorkspaceResult } from "../bm-client.ts" +import { + type BmClient, + describeToolError, + type WorkspaceResult, +} from "../bm-client.ts" import { log } from "../logger.ts" function formatWorkspace(ws: WorkspaceResult, idx: number): string { @@ -64,7 +68,7 @@ export function registerWorkspaceListTool( content: [ { type: "text" as const, - text: "Failed to list workspaces. Is Basic Memory running? Check logs for details.", + text: `Failed to list workspaces: ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/move-note.ts b/integrations/openclaw/tools/move-note.ts index 0f6a82550..73fb085a0 100644 --- a/integrations/openclaw/tools/move-note.ts +++ b/integrations/openclaw/tools/move-note.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeNoteError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerMoveTool( @@ -62,7 +62,7 @@ export function registerMoveTool( content: [ { type: "text" as const, - text: `Failed to move "${params.identifier}". It may not exist.`, + text: `Failed to move "${params.identifier}": ${describeNoteError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/read-note.test.ts b/integrations/openclaw/tools/read-note.test.ts index 705f051ff..87e5f4c2d 100644 --- a/integrations/openclaw/tools/read-note.test.ts +++ b/integrations/openclaw/tools/read-note.test.ts @@ -199,7 +199,7 @@ describe("read tool", () => { content: [ { type: "text", - text: 'Could not read note "missing-note". It may not exist yet.', + text: 'Could not read note "missing-note": not found', }, ], details: { diff --git a/integrations/openclaw/tools/read-note.ts b/integrations/openclaw/tools/read-note.ts index a4fe0e91a..00f74dc31 100644 --- a/integrations/openclaw/tools/read-note.ts +++ b/integrations/openclaw/tools/read-note.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeNoteError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerReadTool( @@ -86,7 +86,7 @@ export function registerReadTool( content: [ { type: "text" as const, - text: `Could not read note "${params.identifier}". It may not exist yet.`, + text: `Could not read note "${params.identifier}": ${describeNoteError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/schema-diff.ts b/integrations/openclaw/tools/schema-diff.ts index 19200b7de..08f18646d 100644 --- a/integrations/openclaw/tools/schema-diff.ts +++ b/integrations/openclaw/tools/schema-diff.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeToolError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerSchemaDiffTool( @@ -93,7 +93,7 @@ export function registerSchemaDiffTool( content: [ { type: "text" as const, - text: "Schema diff failed. Check logs for details.", + text: `Schema diff failed: ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/schema-infer.ts b/integrations/openclaw/tools/schema-infer.ts index 98131b24c..fdcb3595a 100644 --- a/integrations/openclaw/tools/schema-infer.ts +++ b/integrations/openclaw/tools/schema-infer.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeToolError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerSchemaInferTool( @@ -91,7 +91,7 @@ export function registerSchemaInferTool( content: [ { type: "text" as const, - text: "Schema inference failed. Check logs for details.", + text: `Schema inference failed: ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/schema-validate.ts b/integrations/openclaw/tools/schema-validate.ts index 2ffa6feae..8cc393d0e 100644 --- a/integrations/openclaw/tools/schema-validate.ts +++ b/integrations/openclaw/tools/schema-validate.ts @@ -1,6 +1,6 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { type BmClient, describeToolError } from "../bm-client.ts" import { log } from "../logger.ts" export function registerSchemaValidateTool( @@ -89,7 +89,7 @@ export function registerSchemaValidateTool( content: [ { type: "text" as const, - text: "Schema validation failed. Check logs for details.", + text: `Schema validation failed: ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/search-notes.test.ts b/integrations/openclaw/tools/search-notes.test.ts index a403823eb..d1812a741 100644 --- a/integrations/openclaw/tools/search-notes.test.ts +++ b/integrations/openclaw/tools/search-notes.test.ts @@ -185,7 +185,7 @@ describe("search tool", () => { }) it("should truncate long content with ellipsis", async () => { - const longContent = "a".repeat(300) + const longContent = "a".repeat(700) const mockResults = [ { title: "Long Content Note", @@ -203,8 +203,31 @@ describe("search tool", () => { const result = await executeFunction("tool-call-id", { query: "test" }) const text = result.content[0].text - expect(text).toContain(`${"a".repeat(200)}...`) - expect(text).not.toContain("a".repeat(250)) + expect(text).toContain(`${"a".repeat(500)}...`) + expect(text).not.toContain("a".repeat(501)) + }) + + // Regression: a fact deep in a long note (a day of captured + // conversation) was matched but cut off, because the preview showed + // only the start of the note. + it("previews the matched chunk instead of the start of the note", async () => { + ;(mockClient.search as jest.MockedFunction).mockResolvedValue([ + { + title: "conversations-2026-10-29", + permalink: "conversations/conversations-2026-10-29", + content: "# Conversations 2026-10-29\n\n### 14:12\nAbout the cat...", + matched_chunk: + "### 14:15\n**User:**\nmy test plant is a fern called Bramble", + score: 1.19, + file_path: "conversations/conversations-2026-10-29.md", + }, + ]) + + const result = await executeFunction("tool-call-id", { query: "plant" }) + + const text = result.content[0].text + expect(text).toContain("a fern called Bramble") + expect(text).not.toContain("About the cat") }) it("should not truncate short content", async () => { @@ -368,7 +391,7 @@ describe("search tool", () => { content: [ { type: "text", - text: "Search failed. Is Basic Memory running? Check logs for details.", + text: "Search failed: Search service unavailable", }, ], details: { diff --git a/integrations/openclaw/tools/search-notes.ts b/integrations/openclaw/tools/search-notes.ts index 664176d3f..216ae0b25 100644 --- a/integrations/openclaw/tools/search-notes.ts +++ b/integrations/openclaw/tools/search-notes.ts @@ -1,8 +1,16 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" +import { + type BmClient, + describeToolError, + searchResultText, +} from "../bm-client.ts" import { log } from "../logger.ts" +// Long enough to show a whole captured conversation turn from the matched +// chunk, short enough that ten results stay readable. +const MAX_PREVIEW_CHARS = 500 + export function registerSearchTool( api: OpenClawPluginApi, client: BmClient, @@ -100,9 +108,11 @@ export function registerSearchTool( const text = results .map((r, i) => { const score = r.score ? ` (score ${r.score.toFixed(2)})` : "" - const content = r.content ?? "" + const text = searchResultText(r) const preview = - content.length > 200 ? `${content.slice(0, 200)}...` : content + text.length > MAX_PREVIEW_CHARS + ? `${text.slice(0, MAX_PREVIEW_CHARS)}...` + : text return `${i + 1}. **${r.title}**${score}\n ${preview}` }) .join("\n\n") @@ -129,7 +139,7 @@ export function registerSearchTool( content: [ { type: "text" as const, - text: "Search failed. Is Basic Memory running? Check logs for details.", + text: `Search failed: ${describeToolError(err)}`, }, ], details: { diff --git a/integrations/openclaw/tools/write-note.test.ts b/integrations/openclaw/tools/write-note.test.ts index 56dc9ae1a..ef09f2178 100644 --- a/integrations/openclaw/tools/write-note.test.ts +++ b/integrations/openclaw/tools/write-note.test.ts @@ -544,7 +544,7 @@ const code = "example"; content: [ { type: "text", - text: "Failed to write note. Is Basic Memory running? Check logs for details.", + text: "Failed to write note: Failed to write note", }, ], details: { @@ -659,8 +659,8 @@ Normal line folder: "notes", }) - expect(result.content[0].text).toContain( - "Failed to write note. Is Basic Memory running?", + expect(result.content[0].text).toBe( + "Failed to write note: Connection refused", ) }) diff --git a/integrations/openclaw/tools/write-note.ts b/integrations/openclaw/tools/write-note.ts index e90d43c4c..afe3a1687 100644 --- a/integrations/openclaw/tools/write-note.ts +++ b/integrations/openclaw/tools/write-note.ts @@ -1,7 +1,8 @@ import { Type } from "@sinclair/typebox" import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry" -import type { BmClient } from "../bm-client.ts" import { + type BmClient, + describeToolError, NoteAlreadyExistsError, NoteRevisionConflictError, } from "../bm-client.ts" @@ -185,7 +186,7 @@ export function registerWriteTool( content: [ { type: "text" as const, - text: "Failed to write note. Is Basic Memory running? Check logs for details.", + text: `Failed to write note: ${describeToolError(err)}`, }, ], details: {