diff --git a/.changeset/cute-dogs-double.md b/.changeset/cute-dogs-double.md new file mode 100644 index 0000000..84e111b --- /dev/null +++ b/.changeset/cute-dogs-double.md @@ -0,0 +1,5 @@ +--- +"@deablabs/cannoli-server": minor +--- + +feat: Improve logging. Display password on first startup. diff --git a/packages/cannoli-server/package.json b/packages/cannoli-server/package.json index 1198aac..0bb4088 100644 --- a/packages/cannoli-server/package.json +++ b/packages/cannoli-server/package.json @@ -49,6 +49,8 @@ "typescript": "^5.8.3" }, "dependencies": { + "@clack/core": "0.5.0", + "@clack/prompts": "0.11.0", "@hono/node-server": "^1.14.0", "@hono/zod-validator": "0.4.3", "@modelcontextprotocol/sdk": "1.9.0", @@ -57,6 +59,7 @@ "hono-openapi": "0.4.6", "mcp-proxy": "2.12.0", "nanoid": "5.0.7", + "picocolors": "1.1.1", "raw-body": "3.0.0", "remeda": "1.61.0", "tiny-invariant": "^1.3.1", diff --git a/packages/cannoli-server/src/logger.ts b/packages/cannoli-server/src/logger.ts new file mode 100644 index 0000000..12e794f --- /dev/null +++ b/packages/cannoli-server/src/logger.ts @@ -0,0 +1,89 @@ +import { log } from "@clack/prompts"; +import { argumentsConfig } from "src/arguments"; + +declare global { + // eslint-disable-next-line no-var + var logger: Logger | undefined; +} + +type LoggerLevel = "info" | "warn" | "error" | "debug"; + +export type Logger = { + getLevel: () => LoggerLevel; + setLevel: (level: LoggerLevel) => void; + success: (message: string, ...rest: string[]) => void; + log: (message: string, ...rest: string[]) => void; + warn: (message: string, ...rest: string[]) => void; + error: (message: string, ...rest: string[]) => void; + debug: (message: string, ...rest: string[]) => void; +}; + +function ensureLogger(level: LoggerLevel): Logger { + if (!globalThis.logger) { + globalThis.logger = new ClackLogger(level); + } + return globalThis.logger; +} + +export const getLogger = ( + level: LoggerLevel = argumentsConfig.verbose ? "debug" : "info", +): Logger => ensureLogger(level); + +export class ClackLogger implements Logger { + private level: LoggerLevel; + + constructor(level: LoggerLevel) { + this.level = level; + } + + getLevel(): LoggerLevel { + return this.level; + } + + setLevel(level: LoggerLevel): void { + this.level = level; + } + + private shouldLog(level: LoggerLevel): boolean { + const levels = { error: 0, warn: 1, info: 2, debug: 3 }; + return levels[level] <= levels[this.level]; + } + + private concatenateMessages(message: string, ...rest: string[]): string { + if (rest.length === 0) { + return message; + } + return `${message} ${rest.join(" ")}`; + } + + log = (message: string, ...rest: string[]): void => { + if (this.shouldLog("info")) { + log.info(this.concatenateMessages(message, ...rest)); + } + }; + + success = (message: string, ...rest: string[]): void => { + if (this.shouldLog("info")) { + log.success(this.concatenateMessages(message, ...rest)); + } + }; + + warn = (message: string, ...rest: string[]): void => { + if (this.shouldLog("warn")) { + log.warn(this.concatenateMessages(message, ...rest)); + } + }; + + error = (message: string, ...rest: string[]): void => { + if (this.shouldLog("error")) { + log.error(this.concatenateMessages(message, ...rest)); + } + }; + + debug = (message: string, ...rest: string[]): void => { + if (this.shouldLog("debug")) { + // Clack doesn't have a debug method, use info with a prefix + log.info(`[DEBUG] ${this.concatenateMessages(message, ...rest)}`); + } + }; +} diff --git a/packages/cannoli-server/src/routes/sse.ts b/packages/cannoli-server/src/routes/sse.ts index 7f9dcab..09461e5 100644 --- a/packages/cannoli-server/src/routes/sse.ts +++ b/packages/cannoli-server/src/routes/sse.ts @@ -10,6 +10,7 @@ import { SSEServerTransport } from "src/impl/SSEServerTransport"; import { zValidator } from "@hono/zod-validator"; import { z } from "zod"; import { EventEmitter } from "events"; +import { getLogger } from "src/logger"; // 4mb in kb const MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024; @@ -17,6 +18,8 @@ const MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024; // Map of sessionId to SSEServerTransport const ActiveSSEConnections = new Map(); +const logger = getLogger(); + const router = new Hono() .get("/ping", async (c: Context) => { return c.text("pong"); @@ -49,7 +52,7 @@ const router = new Hono() env: process.env as Record, stderr: "pipe", onEvent: (event) => { - console.log("transport event", event); + logger.debug(`transport event\n${event}`); }, }); @@ -105,7 +108,7 @@ const router = new Hono() stream, ); sseServerTransport.onerror = (error) => { - console.error("SSE server transport error", error); + logger.error(`SSE server transport error\n${error}`); }; ActiveSSEConnections.set( sseServerTransport.sessionId, @@ -114,14 +117,14 @@ const router = new Hono() try { await mcpServer.connect(sseServerTransport); - await sseServerTransport.send({ jsonrpc: "2.0", method: "sse/connection", params: { message: "SSE Connection established" }, }); + logger.log("Serving connection to MCP server:", server.name); } catch (error) { - console.error("Error sending SSE connection message", error); + logger.error(`Error sending SSE connection message\n${error}`); if (!closed) { stream.writeSSE({ event: "error", @@ -132,21 +135,22 @@ const router = new Hono() // handle abort event from client side c.req.raw.signal.addEventListener("abort", () => { - console.log("stream disconnected from client side"); + logger.debug("stream disconnected from client side"); emitter.emit("close"); }); // keep the connection alive return new Promise((resolve) => { - console.log("waiting for close"); + logger.debug("waiting for close"); const abort = async () => { - console.log("stream aborted"); + logger.debug("stream aborted"); try { await mcpServer.close(); await client.close(); await serverTransport.close(); + logger.log("Closed connection to MCP server:", server.name); } catch (error) { - console.error("Error closing mcp server", error); + logger.error(`Error closing mcp server\n${error}`); } ActiveSSEConnections.delete(requestId); resolve(undefined); @@ -167,19 +171,19 @@ const router = new Hono() const server = await getServerById(configDir, serverId); if (!server) { - console.error("Server not found", serverId); + logger.error(`Server not found\n${serverId}`); return c.json({ error: "Server not found" }, 404); } if (server.type !== "stdio") { - console.error("Server is not a stdio server", serverId); + logger.error(`Server is not a stdio server\n${serverId}`); return c.text("Server is not a stdio server", 400); } const sseServerTransport = ActiveSSEConnections.get(sessionId); if (!sseServerTransport) { - console.error("SSE connection not found", sessionId); + logger.error(`SSE connection not found\n${sessionId}`); return c.text("SSE connection not found", 404); } diff --git a/packages/cannoli-server/src/server.ts b/packages/cannoli-server/src/server.ts index 1950e7a..0957d4a 100644 --- a/packages/cannoli-server/src/server.ts +++ b/packages/cannoli-server/src/server.ts @@ -1,7 +1,7 @@ import { Hono } from "hono"; -import { serve } from "@hono/node-server"; -import { logger } from "hono/logger"; +import { serve, type HttpBindings } from "@hono/node-server"; import { cors } from "hono/cors"; +import { logger as honoLogger } from "hono/logger"; import * as path from "node:path"; import { getConfigDir } from "./utils"; import { ServerInfo } from "./types"; @@ -17,6 +17,9 @@ import settingsRouter from "./routes/settings"; import sseRouter from "./routes/sse"; import { loadSettings } from "src/settings"; import { argumentsConfig, optionsDefinition } from "src/arguments"; +import { getLogger, Logger } from "src/logger"; +import { intro, outro } from "@clack/prompts"; +import colors from "picocolors"; declare module "hono" { interface ContextVariableMap { @@ -24,15 +27,20 @@ declare module "hono" { requestId: string; host: string; port: number; + logger: Logger; } } +intro(`${colors.bgBlueBright(colors.black(` Cannoli Server `))}`); + +const logger = getLogger(); + if (argumentsConfig.help) { // generate help message from options config const helpMessage = Object.entries(optionsDefinition) .map(([key, value]) => `${key}: ${value.type}`) .join("\n"); - console.log(` + logger.log(` Usage: cannoli-server [options] Options: @@ -41,11 +49,12 @@ ${helpMessage} process.exit(0); } +type Bindings = HttpBindings; + // Create the app -const app = new Hono(); -if (argumentsConfig.verbose) { - app.use("*", logger()); -} +const app = new Hono<{ Bindings: Bindings }>(); +app.use(requestId()); +app.use(honoLogger(logger.debug)); // Configuration const HOST = argumentsConfig.host || process.env.HOST || "localhost"; @@ -71,16 +80,12 @@ app.use(async (...args) => { }); // Middleware to add configDir to context -app.use( - "*", - (c, next) => { - c.set("configDir", CONFIG_DIR); - c.set("host", HOST); - c.set("port", Number(PORT)); - return next(); - }, - requestId(), -); +app.use("*", (c, next) => { + c.set("configDir", CONFIG_DIR); + c.set("host", HOST); + c.set("port", Number(PORT)); + return next(); +}); // Mount the routers const routerApp = app @@ -121,6 +126,14 @@ app.get( }), ); +// catch ctrl-c and exit gracefully +process.on("SIGINT", () => { + outro( + `${colors.bgRedBright(colors.white(` Shutting down Cannoli server... Bye! `))}`, + ); + process.exit(0); +}); + // Start server serve( { @@ -129,11 +142,10 @@ serve( hostname: HOST, }, (info: ServerInfo) => { - console.log(`Cannoli server listening on http://${HOST}:${info.port}`); - console.log(`Using config file: ${SETTINGS_FILE}`); - console.log( - `API documentation available at http://${HOST}:${info.port}/docs`, - ); + logger.log("Logger level :", logger.getLevel()); + logger.log(`Using config file : ${SETTINGS_FILE}`); + logger.log(`API documentation : http://${HOST}:${info.port}/docs`); + logger.success(`Listening on : http://${HOST}:${info.port}`); }, ); diff --git a/packages/cannoli-server/src/settings.ts b/packages/cannoli-server/src/settings.ts index e3b9821..229d18c 100644 --- a/packages/cannoli-server/src/settings.ts +++ b/packages/cannoli-server/src/settings.ts @@ -3,48 +3,34 @@ import * as path from "node:path"; import { SettingsSchema } from "./schemas"; import { Settings } from "./types"; import { ensureConfigDir, createDefaultSettings } from "./utils"; +import { getLogger } from "src/logger"; + +const logger = getLogger(); // Load settings from file or create default if not exists export async function loadSettings(configDir: string): Promise { - const settingsFile = path.join(configDir, "settings.json"); - try { - await ensureConfigDir(configDir); + const settingsFile = path.join(configDir, "settings.json"); + const data = await fs.readFile(settingsFile, "utf-8"); const rawSettings = JSON.parse(data); + // Parse with Zod schema + return SettingsSchema.parse(rawSettings); + } catch (parseError) { + await ensureConfigDir(configDir); - try { - // Parse with Zod schema - return SettingsSchema.parse(rawSettings); - } catch (parseError) { - console.log( - "Creating default settings. Any previous invalid settings will be saved to the `oldSettings` key in the settings file.", - ); - // If invalid, return a fresh default settings - const defaultSettings: Settings = createDefaultSettings(); - console.log( - "Your secret is: ", - defaultSettings.serverSecret, - "Enter it within Cannoli settings to access your server!", - ); - await saveSettings(defaultSettings, configDir); - return defaultSettings; - } - } catch (error: unknown) { - // If file doesn't exist, return default settings - if ( - typeof error === "object" && - error !== null && - "code" in error && - error.code === "ENOENT" - ) { - const defaultSettings: Settings = createDefaultSettings(); - await saveSettings(defaultSettings, configDir); - return defaultSettings; - } - - console.error("Error loading settings:", error); - throw error; + logger.warn( + "Creating default settings. Any previous invalid settings will be saved to the `oldSettings` key in the settings file.", + ); + // If invalid, return a fresh default settings + const defaultSettings: Settings = createDefaultSettings(); + logger.warn( + "Your secret is:\n" + + defaultSettings.serverSecret + + "\nEnter it within Cannoli settings to access your server.", + ); + await saveSettings(defaultSettings, configDir); + return defaultSettings; } } @@ -65,7 +51,7 @@ export async function saveSettings( ); return settings; } catch (error) { - console.error("Error saving settings:", error); + logger.error("Error saving settings:", String(error)); throw error; } } diff --git a/packages/cannoli-server/src/utils.ts b/packages/cannoli-server/src/utils.ts index b8fe2ea..b76a8ad 100644 --- a/packages/cannoli-server/src/utils.ts +++ b/packages/cannoli-server/src/utils.ts @@ -3,6 +3,9 @@ import * as path from "node:path"; import * as os from "node:os"; import { Settings } from "./types"; import { nanoid } from "nanoid"; +import { getLogger } from "src/logger"; + +const logger = getLogger(); // Get platform-specific config directory export function getConfigDir(): string { @@ -32,7 +35,7 @@ export async function ensureConfigDir(configDir: string): Promise { try { await fs.mkdir(configDir, { recursive: true }); } catch (error) { - console.error("Failed to create config directory:", error); + logger.error("Failed to create config directory:", String(error)); } } diff --git a/packages/cannoli-server/tsconfig.json b/packages/cannoli-server/tsconfig.json index 50df796..190634b 100644 --- a/packages/cannoli-server/tsconfig.json +++ b/packages/cannoli-server/tsconfig.json @@ -1,6 +1,7 @@ // extend from the root tsconfig.json { "compilerOptions": { + "allowSyntheticDefaultImports": true, "baseUrl": ".", "inlineSourceMap": true, "inlineSources": true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b087d72..b5da820 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,7 +89,7 @@ importers: version: 4.1.0 langchain: specifier: 0.3.21 - version: 0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1) + version: 0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1) nanoid: specifier: 5.0.7 version: 5.0.7 @@ -218,6 +218,12 @@ importers: packages/cannoli-server: dependencies: + '@clack/core': + specifier: 0.5.0 + version: 0.5.0 + '@clack/prompts': + specifier: 0.11.0 + version: 0.11.0 '@hono/node-server': specifier: ^1.14.0 version: 1.14.0(hono@4.7.6) @@ -242,6 +248,9 @@ importers: nanoid: specifier: 5.0.7 version: 5.0.7 + picocolors: + specifier: 1.1.1 + version: 1.1.1 raw-body: specifier: 3.0.0 version: 3.0.0 @@ -414,6 +423,12 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@clack/core@0.5.0': + resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + + '@clack/prompts@0.11.0': + resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + '@codemirror/language@https://codeload.github.com/lishid/cm-language/tar.gz/a9c3c7efe17dd1d24395ee2a179fe12dd6ed1e76': resolution: {tarball: https://codeload.github.com/lishid/cm-language/tar.gz/a9c3c7efe17dd1d24395ee2a179fe12dd6ed1e76} version: 6.11.2 @@ -3073,12 +3088,12 @@ packages: '@codemirror/state': ^6.0.0 '@codemirror/view': ^6.0.0 - obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66: - resolution: {tarball: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66} - version: 1.8.7 + obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/3a2161f440361a0c5466d5ebc4569998933e665b: + resolution: {tarball: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/3a2161f440361a0c5466d5ebc4569998933e665b} + version: 1.10.0 peerDependencies: - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.38.1 ollama@0.5.14: resolution: {integrity: sha512-pvOuEYa2WkkAumxzJP0RdEYHkbZ64AYyyUszXVX7ruLvk5L+EiO2G71da2GqEQ4IAk4j6eLoUbGk5arzFT1wJA==} @@ -3490,6 +3505,9 @@ packages: simple-wcswidth@1.0.1: resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -3789,8 +3807,8 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - wabt@1.0.37: - resolution: {integrity: sha512-2B/TH4ppwtlkUosLtuIimKsTVnqM8aoXxYHnu/WOxiSqa+CGoZXmG+pQyfDQjEKIAc7GqFlJsuCKuK8rIPL1sg==} + wabt@1.0.38: + resolution: {integrity: sha512-RdeuVjC/nwUmqYGd2S1K8fGmjJR8yTCVve735sdgMbB5ff548n7qxbEwSY92/GFL+lej64d9yNFnHvZBQ05RpQ==} hasBin: true web-streams-polyfill@3.3.3: @@ -4119,6 +4137,17 @@ snapshots: human-id: 4.1.1 prettier: 2.8.8 + '@clack/core@0.5.0': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.11.0': + dependencies: + '@clack/core': 0.5.0 + picocolors: 1.1.1 + sisteransi: 1.0.5 + '@codemirror/language@https://codeload.github.com/lishid/cm-language/tar.gz/a9c3c7efe17dd1d24395ee2a179fe12dd6ed1e76': dependencies: '@codemirror/state': 6.4.1 @@ -4448,7 +4477,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.3.2 js-yaml: 4.1.0 - langchain: 0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1) + langchain: 0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1) langsmith: 0.3.15(openai@4.52.0) openai: 4.52.0 uuid: 10.0.0 @@ -4481,13 +4510,13 @@ snapshots: - handlebars - peggy - '@langchain/core@0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0)': + '@langchain/core@0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0)': dependencies: ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.12 - langsmith: 0.1.32(@langchain/core@0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0))(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) + langsmith: 0.1.32(@langchain/core@0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0))(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) ml-distance: 4.0.1 mustache: 4.2.0 p-queue: 6.6.2 @@ -4607,9 +4636,9 @@ snapshots: - encoding - ws - '@langchain/textsplitters@0.0.2(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0)': + '@langchain/textsplitters@0.0.2(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0)': dependencies: - '@langchain/core': 0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) + '@langchain/core': 0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) js-tiktoken: 1.0.12 transitivePeerDependencies: - langchain @@ -5543,7 +5572,7 @@ snapshots: find-cache-dir: 3.3.2 minimist: 1.2.8 parse-imports: 1.2.0 - wabt: 1.0.37 + wabt: 1.0.38 esbuild@0.17.3: optionalDependencies: @@ -6179,11 +6208,11 @@ snapshots: dependencies: json-buffer: 3.0.1 - langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1): + langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1): dependencies: '@langchain/core': 0.3.44(openai@4.52.0) '@langchain/openai': 0.5.5(@langchain/core@0.3.44(openai@4.52.0))(ws@8.18.1) - '@langchain/textsplitters': 0.0.2(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) + '@langchain/textsplitters': 0.0.2(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) js-tiktoken: 1.0.12 js-yaml: 4.1.0 jsonpointer: 5.0.1 @@ -6205,7 +6234,7 @@ snapshots: - openai - ws - langsmith@0.1.32(@langchain/core@0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0))(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0): + langsmith@0.1.32(@langchain/core@0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0))(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0): dependencies: '@types/uuid': 9.0.8 commander: 10.0.1 @@ -6213,8 +6242,8 @@ snapshots: p-retry: 4.6.2 uuid: 9.0.1 optionalDependencies: - '@langchain/core': 0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) - langchain: 0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4(debug@4.4.0))(openai@4.52.0)(ws@8.18.1) + '@langchain/core': 0.2.7(langchain@0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1))(openai@4.52.0) + langchain: 0.3.21(@langchain/anthropic@0.3.17(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/core@0.3.44(openai@4.52.0))(@langchain/google-genai@0.2.3(@langchain/core@0.3.44(openai@4.52.0))(zod@3.23.8))(@langchain/groq@0.2.2(@langchain/core@0.3.44(openai@4.52.0)))(@langchain/ollama@0.2.0(@langchain/core@0.3.44(openai@4.52.0)))(axios@1.8.4)(openai@4.52.0)(ws@8.18.1) openai: 4.52.0 langsmith@0.3.15(openai@4.52.0): @@ -6446,7 +6475,7 @@ snapshots: obsidian-daily-notes-interface@0.8.4(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): dependencies: - obsidian: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.4.1)(@codemirror/view@6.26.3) + obsidian: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/3a2161f440361a0c5466d5ebc4569998933e665b(@codemirror/state@6.4.1)(@codemirror/view@6.26.3) tslib: 2.1.0 transitivePeerDependencies: - '@codemirror/state' @@ -6472,7 +6501,7 @@ snapshots: '@types/codemirror': 5.60.8 moment: 2.29.4 - obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): + obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/3a2161f440361a0c5466d5ebc4569998933e665b(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.26.3 @@ -6891,6 +6920,8 @@ snapshots: simple-wcswidth@1.0.1: {} + sisteransi@1.0.5: {} + slash@3.0.0: {} slashes@3.0.12: {} @@ -7150,7 +7181,7 @@ snapshots: w3c-keyname@2.2.8: {} - wabt@1.0.37: {} + wabt@1.0.38: {} web-streams-polyfill@3.3.3: {}