Commit 958d6e8fb09f

Vincent Demeester <vincent@sbr.pm>
2026-02-04 14:25:59
Initial implementation of Daneel XMPP research bot
- XMPP transport layer using @xmpp/client with message handling - Multi-provider LLM abstraction supporting Anthropic, Google, OpenAI, Ollama, Groq, and Mistral - Model prefix parsing for dynamic model selection (opus:, gemini:, llama:, etc.) - Per-user session persistence using JSONL format - Tool system with status, save_to_org, research, and web_search tools - TypeBox schema definitions for tool parameters - Slash commands (/help, /ping, /status, /clear, /models, /stats) - NixOS module for service deployment with systemd hardening Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
nix/module.nix
@@ -0,0 +1,171 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+let
+  cfg = config.services.daneel;
+in
+{
+  options.services.daneel = {
+    enable = lib.mkEnableOption "Daneel XMPP research bot";
+
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.callPackage ./package.nix { };
+      description = "The daneel package to use";
+    };
+
+    xmppJid = lib.mkOption {
+      type = lib.types.str;
+      example = "daneel@xmpp.example.com";
+      description = "XMPP JID for the bot";
+    };
+
+    xmppPasswordFile = lib.mkOption {
+      type = lib.types.path;
+      description = "Path to file containing XMPP password";
+    };
+
+    ownerJid = lib.mkOption {
+      type = lib.types.str;
+      example = "user@xmpp.example.com";
+      description = "XMPP JID of the bot owner (only this JID can interact)";
+    };
+
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/daneel";
+      description = "Directory for session data";
+    };
+
+    inboxPath = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/daneel/inbox.org";
+      description = "Path to org-mode inbox file";
+    };
+
+    defaultModel = lib.mkOption {
+      type = lib.types.str;
+      default = "sonnet";
+      description = "Default model alias (e.g., sonnet, opus, gemini)";
+    };
+
+    anthropicApiKeyFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+      description = "Path to file containing Anthropic API key";
+    };
+
+    googleApiKeyFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+      description = "Path to file containing Google API key";
+    };
+
+    openaiApiKeyFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      default = null;
+      description = "Path to file containing OpenAI API key";
+    };
+
+    ollamaBaseUrl = lib.mkOption {
+      type = lib.types.nullOr lib.types.str;
+      default = null;
+      example = "http://localhost:11434";
+      description = "Base URL for Ollama API";
+    };
+
+    debug = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = "Enable debug logging";
+    };
+
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = "daneel";
+      description = "User to run daneel as";
+    };
+
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = "daneel";
+      description = "Group to run daneel as";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users.users.${cfg.user} = {
+      isSystemUser = true;
+      group = cfg.group;
+      home = cfg.dataDir;
+      createHome = true;
+    };
+
+    users.groups.${cfg.group} = { };
+
+    systemd.services.daneel = {
+      description = "Daneel XMPP Research Bot";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        Type = "simple";
+        User = cfg.user;
+        Group = cfg.group;
+        WorkingDirectory = cfg.dataDir;
+        ExecStart = "${cfg.package}/bin/daneel";
+        Restart = "always";
+        RestartSec = "10s";
+
+        # Hardening
+        NoNewPrivileges = true;
+        PrivateTmp = true;
+        ProtectSystem = "strict";
+        ProtectHome = true;
+        ReadWritePaths = [ cfg.dataDir (builtins.dirOf cfg.inboxPath) ];
+        ProtectKernelTunables = true;
+        ProtectKernelModules = true;
+        ProtectControlGroups = true;
+        RestrictAddressFamilies = [
+          "AF_INET"
+          "AF_INET6"
+          "AF_UNIX"
+        ];
+        RestrictNamespaces = true;
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        PrivateDevices = true;
+      };
+
+      script = ''
+        export DANEEL_XMPP_JID="${cfg.xmppJid}"
+        export DANEEL_XMPP_PASSWORD="$(cat ${cfg.xmppPasswordFile})"
+        export DANEEL_OWNER_JID="${cfg.ownerJid}"
+        export DANEEL_DATA_DIR="${cfg.dataDir}"
+        export DANEEL_INBOX_PATH="${cfg.inboxPath}"
+        export DANEEL_DEFAULT_MODEL="${cfg.defaultModel}"
+        ${lib.optionalString cfg.debug ''export DANEEL_DEBUG="true"''}
+
+        ${lib.optionalString (cfg.anthropicApiKeyFile != null) ''
+          export ANTHROPIC_API_KEY="$(cat ${cfg.anthropicApiKeyFile})"
+        ''}
+        ${lib.optionalString (cfg.googleApiKeyFile != null) ''
+          export GOOGLE_API_KEY="$(cat ${cfg.googleApiKeyFile})"
+        ''}
+        ${lib.optionalString (cfg.openaiApiKeyFile != null) ''
+          export OPENAI_API_KEY="$(cat ${cfg.openaiApiKeyFile})"
+        ''}
+        ${lib.optionalString (cfg.ollamaBaseUrl != null) ''
+          export OLLAMA_BASE_URL="${cfg.ollamaBaseUrl}"
+        ''}
+
+        exec ${cfg.package}/bin/daneel
+      '';
+    };
+  };
+}
nix/package.nix
@@ -0,0 +1,48 @@
+{
+  lib,
+  buildNpmPackage,
+  nodejs_22,
+}:
+
+buildNpmPackage {
+  pname = "daneel";
+  version = "0.1.0";
+
+  src = ./..;
+
+  nodejs = nodejs_22;
+
+  npmDepsHash = lib.fakeHash;
+
+  # Build TypeScript
+  buildPhase = ''
+    runHook preBuild
+    npm run build
+    runHook postBuild
+  '';
+
+  # Install the built files
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/lib/daneel
+    cp -r dist $out/lib/daneel/
+    cp -r node_modules $out/lib/daneel/
+    cp package.json $out/lib/daneel/
+
+    mkdir -p $out/bin
+    cat > $out/bin/daneel <<EOF
+    #!${nodejs_22}/bin/node
+    import("$out/lib/daneel/dist/main.js");
+    EOF
+    chmod +x $out/bin/daneel
+    runHook postInstall
+  '';
+
+  meta = {
+    description = "XMPP research bot using AI";
+    homepage = "https://codeberg.org/vdemeester/daneel";
+    license = lib.licenses.asl20;
+    maintainers = [ ];
+    mainProgram = "daneel";
+  };
+}
src/agent/prompts.ts
@@ -0,0 +1,80 @@
+export const SYSTEM_PROMPT = `You are Daneel, a personal research assistant named after R. Daneel Olivaw from Isaac Asimov's Robot/Foundation series. You communicate via XMPP (Jabber) with your owner.
+
+Your core traits:
+- Helpful and thorough in research
+- Concise but complete in responses (this is chat, not email)
+- Honest about limitations and uncertainty
+- You can use tools to help with tasks
+
+When responding:
+- Keep responses focused and scannable
+- Use markdown formatting when helpful
+- If a question requires research, use the research tool
+- If asked to save something, use the save_to_org tool
+- For system status, use the status tool
+
+Remember: You're in an XMPP chat context. Keep responses reasonably sized but don't truncate important information.`;
+
+export const HELP_TEXT = `**Daneel - XMPP Research Bot**
+
+**Commands:**
+- \`/help\` - Show this help message
+- \`/ping\` - Check if I'm alive
+- \`/status\` - Show system status
+- \`/clear\` - Clear conversation history
+- \`/models\` - List available models
+
+**Model Prefixes:**
+Use these prefixes to select a specific model:
+
+*Anthropic:*
+- \`opus:\` or \`o:\` - Claude Opus 4.5
+- \`sonnet:\` or \`s:\` - Claude Sonnet 4.5 (default)
+- \`haiku:\` or \`h:\` - Claude Haiku
+
+*Google:*
+- \`gemini:\` or \`g:\` - Gemini 2.0 Flash
+- \`gemini-pro:\` or \`gp:\` - Gemini 2.5 Pro
+
+*OpenAI:*
+- \`gpt:\` or \`gpt4:\` - GPT-4o
+- \`o1:\` - O1
+- \`o3:\` - O3 Mini
+
+*GitHub Copilot:*
+- \`copilot:\` or \`cp:\` - GPT-4o via Copilot
+- \`copilot-claude:\` - Claude Sonnet via Copilot
+
+*Ollama (Local):*
+- \`ollama:\` or \`llama:\` - Llama 3.2
+- \`qwen:\` - Qwen 2.5
+- \`deepseek:\` - DeepSeek R1
+
+*Others:*
+- \`groq:\` - Llama via Groq
+- \`mistral:\` - Mistral Large
+
+**Examples:**
+- \`opus: What is quantum entanglement?\`
+- \`g: Summarize recent AI news\`
+- \`What's the weather like?\` (uses default model)`;
+
+export const MODELS_TEXT = `**Available Models:**
+
+| Prefix | Provider | Model |
+|--------|----------|-------|
+| opus:, o: | Anthropic | claude-opus-4-5 |
+| sonnet:, s: | Anthropic | claude-sonnet-4-5 |
+| haiku:, h: | Anthropic | claude-haiku |
+| gemini:, g: | Google | gemini-2.0-flash |
+| gemini-pro:, gp: | Google | gemini-2.5-pro |
+| gpt:, gpt4: | OpenAI | gpt-4o |
+| o1: | OpenAI | o1 |
+| o3: | OpenAI | o3-mini |
+| copilot:, cp: | GitHub | gpt-4o |
+| copilot-claude: | GitHub | claude-sonnet-4 |
+| ollama:, llama: | Ollama | llama3.2 |
+| qwen: | Ollama | qwen2.5 |
+| deepseek: | Ollama | deepseek-r1 |
+| groq: | Groq | llama-3.3-70b |
+| mistral: | Mistral | mistral-large |`;
src/agent/runner.ts
@@ -0,0 +1,223 @@
+import { Config, ModelInfo, parseModelPrefix } from "../config.js";
+import { SessionManager } from "./session.js";
+import { SessionEntry, ConversationMessage } from "./types.js";
+import { SYSTEM_PROMPT, HELP_TEXT, MODELS_TEXT } from "./prompts.js";
+import { ToolRegistry } from "../tools/index.js";
+import { createProvider, LLMProvider, Message } from "../llm/index.js";
+import { bareJid } from "../xmpp/types.js";
+
+const MAX_TOOL_ITERATIONS = 10;
+
+export class AgentRunner {
+  private config: Config;
+  private sessionManager: SessionManager;
+  private toolRegistry: ToolRegistry;
+  private jid: string;
+  private processing: boolean = false;
+  private messageQueue: Array<{ message: string; resolve: (response: string) => void }> = [];
+
+  constructor(
+    jid: string,
+    config: Config,
+    sessionManager: SessionManager,
+    toolRegistry: ToolRegistry
+  ) {
+    this.jid = bareJid(jid);
+    this.config = config;
+    this.sessionManager = sessionManager;
+    this.toolRegistry = toolRegistry;
+  }
+
+  async processMessage(message: string): Promise<string> {
+    return new Promise((resolve) => {
+      this.messageQueue.push({ message, resolve });
+      this.processQueue();
+    });
+  }
+
+  private async processQueue(): Promise<void> {
+    if (this.processing || this.messageQueue.length === 0) {
+      return;
+    }
+
+    this.processing = true;
+
+    while (this.messageQueue.length > 0) {
+      const item = this.messageQueue.shift()!;
+      try {
+        const response = await this.handleMessage(item.message);
+        item.resolve(response);
+      } catch (err) {
+        item.resolve(`Error: ${(err as Error).message}`);
+      }
+    }
+
+    this.processing = false;
+  }
+
+  private async handleMessage(message: string): Promise<string> {
+    // Handle slash commands
+    if (message.startsWith("/")) {
+      return this.handleCommand(message);
+    }
+
+    // Parse model prefix
+    const { model, content } = parseModelPrefix(message);
+    const modelInfo = model || this.config.llm.defaultModel;
+
+    // Log user message
+    await this.sessionManager.appendEntry(this.jid, {
+      timestamp: new Date().toISOString(),
+      type: "user",
+      content,
+      model: modelInfo,
+    });
+
+    // Get conversation history
+    const history = await this.sessionManager.getConversationHistory(this.jid);
+
+    // Create provider for this request
+    const provider = createProvider(modelInfo, this.config.llm.providers);
+
+    // Run agent loop
+    const response = await this.runAgentLoop(provider, history, content);
+
+    // Log assistant response
+    await this.sessionManager.appendEntry(this.jid, {
+      timestamp: new Date().toISOString(),
+      type: "assistant",
+      content: response,
+      model: modelInfo,
+    });
+
+    return response;
+  }
+
+  private async handleCommand(message: string): Promise<string> {
+    const parts = message.slice(1).split(/\s+/);
+    const command = parts[0].toLowerCase();
+
+    switch (command) {
+      case "ping":
+        return "Pong!";
+
+      case "help":
+        return HELP_TEXT;
+
+      case "models":
+        return MODELS_TEXT;
+
+      case "status": {
+        const statusTool = this.toolRegistry.get("status");
+        if (statusTool) {
+          const result = await statusTool.execute({});
+          return `**System Status:**\n\`\`\`json\n${result}\n\`\`\``;
+        }
+        return "Status tool not available";
+      }
+
+      case "clear":
+        await this.sessionManager.clearSession(this.jid);
+        return "Conversation history cleared.";
+
+      case "stats": {
+        const stats = await this.sessionManager.getSessionStats(this.jid);
+        return `**Session Stats:**\n- Messages: ${stats.messageCount}\n- First: ${stats.firstMessage || "N/A"}\n- Last: ${stats.lastMessage || "N/A"}`;
+      }
+
+      default:
+        return `Unknown command: /${command}\nType /help for available commands.`;
+    }
+  }
+
+  private async runAgentLoop(
+    provider: LLMProvider,
+    history: ConversationMessage[],
+    currentMessage: string
+  ): Promise<string> {
+    const messages: Message[] = [
+      ...history,
+      { role: "user", content: currentMessage },
+    ];
+
+    const tools = this.toolRegistry.getSchemas();
+
+    let iterations = 0;
+    let finalResponse = "";
+
+    while (iterations < MAX_TOOL_ITERATIONS) {
+      iterations++;
+
+      const response = await provider.chat(messages, {
+        systemPrompt: SYSTEM_PROMPT,
+        tools,
+        maxTokens: 4096,
+      });
+
+      // Handle tool calls
+      if (response.stopReason === "tool_use" && response.toolCalls.length > 0) {
+        // Add assistant message with tool calls
+        if (response.content) {
+          messages.push({ role: "assistant", content: response.content });
+        }
+
+        // Execute each tool
+        for (const toolCall of response.toolCalls) {
+          const tool = this.toolRegistry.get(toolCall.name);
+          if (!tool) {
+            messages.push({
+              role: "user",
+              content: `Tool '${toolCall.name}' not found`,
+            });
+            continue;
+          }
+
+          // Log tool call
+          await this.sessionManager.appendEntry(this.jid, {
+            timestamp: new Date().toISOString(),
+            type: "tool_call",
+            content: JSON.stringify({
+              name: toolCall.name,
+              arguments: toolCall.arguments,
+            }),
+            toolName: toolCall.name,
+            toolCallId: toolCall.id,
+          });
+
+          try {
+            const result = await tool.execute(toolCall.arguments);
+
+            // Log tool result
+            await this.sessionManager.appendEntry(this.jid, {
+              timestamp: new Date().toISOString(),
+              type: "tool_result",
+              content: result,
+              toolName: toolCall.name,
+              toolCallId: toolCall.id,
+            });
+
+            messages.push({
+              role: "user",
+              content: `Tool result for ${toolCall.name}:\n${result}`,
+            });
+          } catch (err) {
+            const errorMsg = `Tool error: ${(err as Error).message}`;
+            messages.push({ role: "user", content: errorMsg });
+          }
+        }
+
+        continue;
+      }
+
+      // No more tool calls, return final response
+      finalResponse = response.content || "";
+      break;
+    }
+
+    if (iterations >= MAX_TOOL_ITERATIONS) {
+      finalResponse += "\n\n(Reached maximum tool iterations)";
+    }
+
+    return finalResponse;
+  }
+}
src/agent/session.ts
@@ -0,0 +1,100 @@
+import * as fs from "fs/promises";
+import * as path from "path";
+import { SessionEntry, ConversationMessage } from "./types.js";
+import { bareJid } from "../xmpp/types.js";
+
+export class SessionManager {
+  private dataDir: string;
+
+  constructor(dataDir: string) {
+    this.dataDir = dataDir;
+  }
+
+  private getSessionDir(jid: string): string {
+    // Sanitize JID for filesystem (replace @ and . with safe chars)
+    const sanitized = bareJid(jid).replace(/@/g, "_at_").replace(/\./g, "_");
+    return path.join(this.dataDir, sanitized);
+  }
+
+  private getContextPath(jid: string): string {
+    return path.join(this.getSessionDir(jid), "context.jsonl");
+  }
+
+  async ensureSessionDir(jid: string): Promise<void> {
+    const dir = this.getSessionDir(jid);
+    await fs.mkdir(dir, { recursive: true });
+  }
+
+  async appendEntry(jid: string, entry: SessionEntry): Promise<void> {
+    await this.ensureSessionDir(jid);
+    const contextPath = this.getContextPath(jid);
+    const line = JSON.stringify(entry) + "\n";
+    await fs.appendFile(contextPath, line, "utf-8");
+  }
+
+  async loadHistory(jid: string): Promise<SessionEntry[]> {
+    const contextPath = this.getContextPath(jid);
+
+    try {
+      const content = await fs.readFile(contextPath, "utf-8");
+      const lines = content.trim().split("\n").filter((l) => l.length > 0);
+      return lines.map((line) => JSON.parse(line) as SessionEntry);
+    } catch (err) {
+      if ((err as NodeJS.ErrnoException).code === "ENOENT") {
+        return [];
+      }
+      throw err;
+    }
+  }
+
+  async getConversationHistory(
+    jid: string,
+    maxEntries: number = 50
+  ): Promise<ConversationMessage[]> {
+    const entries = await this.loadHistory(jid);
+    const messages: ConversationMessage[] = [];
+
+    // Take last N entries and convert to conversation format
+    const recentEntries = entries.slice(-maxEntries);
+
+    for (const entry of recentEntries) {
+      if (entry.type === "user") {
+        messages.push({ role: "user", content: entry.content });
+      } else if (entry.type === "assistant") {
+        messages.push({ role: "assistant", content: entry.content });
+      } else if (entry.type === "system") {
+        messages.push({ role: "system", content: entry.content });
+      }
+      // Tool calls and results are embedded in assistant/user messages
+    }
+
+    return messages;
+  }
+
+  async clearSession(jid: string): Promise<void> {
+    const contextPath = this.getContextPath(jid);
+    try {
+      await fs.unlink(contextPath);
+    } catch (err) {
+      if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
+        throw err;
+      }
+    }
+  }
+
+  async getSessionStats(jid: string): Promise<{
+    messageCount: number;
+    firstMessage: string | null;
+    lastMessage: string | null;
+  }> {
+    const entries = await this.loadHistory(jid);
+    const userEntries = entries.filter((e) => e.type === "user");
+
+    return {
+      messageCount: userEntries.length,
+      firstMessage: entries.length > 0 ? entries[0].timestamp : null,
+      lastMessage:
+        entries.length > 0 ? entries[entries.length - 1].timestamp : null,
+    };
+  }
+}
src/agent/types.ts
@@ -0,0 +1,27 @@
+import { ModelInfo } from "../config.js";
+
+export interface SessionEntry {
+  timestamp: string;
+  type: "user" | "assistant" | "tool_call" | "tool_result" | "system";
+  content: string;
+  model?: ModelInfo;
+  toolName?: string;
+  toolCallId?: string;
+}
+
+export interface ConversationMessage {
+  role: "user" | "assistant" | "system";
+  content: string;
+}
+
+export interface ToolCall {
+  id: string;
+  name: string;
+  arguments: Record<string, unknown>;
+}
+
+export interface ToolResult {
+  toolCallId: string;
+  result: string;
+  isError?: boolean;
+}
src/llm/anthropic.ts
@@ -0,0 +1,155 @@
+import Anthropic from "@anthropic-ai/sdk";
+import { LLMProvider, Message, ToolDefinition, LLMResponse } from "./types.js";
+import { TSchema, Kind } from "@sinclair/typebox";
+
+export class AnthropicProvider implements LLMProvider {
+  name = "anthropic";
+  private client: Anthropic;
+  private model: string;
+
+  constructor(apiKey: string, model: string) {
+    this.client = new Anthropic({ apiKey });
+    this.model = model;
+  }
+
+  async chat(
+    messages: Message[],
+    options: {
+      systemPrompt?: string;
+      tools?: ToolDefinition[];
+      maxTokens?: number;
+    }
+  ): Promise<LLMResponse> {
+    const anthropicMessages: Anthropic.MessageParam[] = messages
+      .filter((m) => m.role !== "system")
+      .map((m) => ({
+        role: m.role as "user" | "assistant",
+        content: m.content,
+      }));
+
+    const tools = options.tools?.map((t) => ({
+      name: t.name,
+      description: t.description,
+      input_schema: typeboxToJsonSchema(t.parameters),
+    }));
+
+    const response = await this.client.messages.create({
+      model: this.model,
+      max_tokens: options.maxTokens || 4096,
+      system: options.systemPrompt,
+      messages: anthropicMessages,
+      tools: tools as Anthropic.Tool[],
+    });
+
+    let textContent: string | null = null;
+    const toolCalls: LLMResponse["toolCalls"] = [];
+
+    for (const block of response.content) {
+      if (block.type === "text") {
+        textContent = block.text;
+      } else if (block.type === "tool_use") {
+        toolCalls.push({
+          id: block.id,
+          name: block.name,
+          arguments: block.input as Record<string, unknown>,
+        });
+      }
+    }
+
+    let stopReason: LLMResponse["stopReason"] = "end_turn";
+    if (response.stop_reason === "tool_use") {
+      stopReason = "tool_use";
+    } else if (response.stop_reason === "max_tokens") {
+      stopReason = "max_tokens";
+    }
+
+    return {
+      content: textContent,
+      toolCalls,
+      stopReason,
+    };
+  }
+}
+
+function typeboxToJsonSchema(schema: TSchema): Record<string, unknown> {
+  // Convert TypeBox schema to JSON Schema for Anthropic
+  const result: Record<string, unknown> = {
+    type: getJsonSchemaType(schema),
+  };
+
+  if (schema.description) {
+    result.description = schema.description;
+  }
+
+  if (schema[Kind] === "Object" && schema.properties) {
+    result.properties = {};
+    const required: string[] = [];
+
+    for (const [key, prop] of Object.entries(
+      schema.properties as Record<string, TSchema>
+    )) {
+      (result.properties as Record<string, unknown>)[key] =
+        typeboxToJsonSchema(prop);
+      // In TypeBox, properties are required by default unless wrapped in Type.Optional
+      const optionalSymbol = Symbol.for("TypeBox.Optional");
+      if (prop[Kind] !== "Optional" && !(optionalSymbol in prop)) {
+        required.push(key);
+      }
+    }
+
+    if (required.length > 0) {
+      result.required = required;
+    }
+  }
+
+  if (schema[Kind] === "Array" && schema.items) {
+    result.items = typeboxToJsonSchema(schema.items as TSchema);
+  }
+
+  if (schema[Kind] === "Union" && schema.anyOf) {
+    result.anyOf = (schema.anyOf as TSchema[]).map(typeboxToJsonSchema);
+    delete result.type;
+  }
+
+  if (schema[Kind] === "Literal") {
+    result.const = schema.const;
+  }
+
+  if (schema.default !== undefined) {
+    result.default = schema.default;
+  }
+
+  if (schema.minimum !== undefined) {
+    result.minimum = schema.minimum;
+  }
+
+  if (schema.maximum !== undefined) {
+    result.maximum = schema.maximum;
+  }
+
+  return result;
+}
+
+function getJsonSchemaType(schema: TSchema): string {
+  const kind = schema[Kind];
+  switch (kind) {
+    case "String":
+      return "string";
+    case "Number":
+    case "Integer":
+      return "number";
+    case "Boolean":
+      return "boolean";
+    case "Array":
+      return "array";
+    case "Object":
+      return "object";
+    case "Null":
+      return "null";
+    case "Optional":
+      // Unwrap optional
+      return getJsonSchemaType(schema.anyOf?.[0] || schema);
+    default:
+      return "object";
+  }
+}
src/llm/google.ts
@@ -0,0 +1,154 @@
+import {
+  GoogleGenerativeAI,
+  Content,
+  Part,
+  FunctionDeclaration,
+  SchemaType,
+} from "@google/generative-ai";
+import { LLMProvider, Message, ToolDefinition, LLMResponse } from "./types.js";
+import { TSchema, Kind } from "@sinclair/typebox";
+
+export class GoogleProvider implements LLMProvider {
+  name = "google";
+  private client: GoogleGenerativeAI;
+  private model: string;
+
+  constructor(apiKey: string, model: string) {
+    this.client = new GoogleGenerativeAI(apiKey);
+    this.model = model;
+  }
+
+  async chat(
+    messages: Message[],
+    options: {
+      systemPrompt?: string;
+      tools?: ToolDefinition[];
+      maxTokens?: number;
+    }
+  ): Promise<LLMResponse> {
+    const genModel = this.client.getGenerativeModel({
+      model: this.model,
+      systemInstruction: options.systemPrompt,
+    });
+
+    const contents: Content[] = messages
+      .filter((m) => m.role !== "system")
+      .map((m) => ({
+        role: m.role === "assistant" ? "model" : "user",
+        parts: [{ text: m.content }] as Part[],
+      }));
+
+    const tools = options.tools?.map((t) => ({
+      functionDeclarations: [
+        {
+          name: t.name,
+          description: t.description,
+          parameters: typeboxToGeminiSchema(t.parameters),
+        } as FunctionDeclaration,
+      ],
+    }));
+
+    const result = await genModel.generateContent({
+      contents,
+      tools,
+      generationConfig: {
+        maxOutputTokens: options.maxTokens || 4096,
+      },
+    });
+
+    const response = result.response;
+    const candidate = response.candidates?.[0];
+
+    if (!candidate) {
+      return {
+        content: null,
+        toolCalls: [],
+        stopReason: "error",
+      };
+    }
+
+    let textContent: string | null = null;
+    const toolCalls: LLMResponse["toolCalls"] = [];
+
+    for (const part of candidate.content.parts) {
+      if ("text" in part && part.text) {
+        textContent = part.text;
+      } else if ("functionCall" in part && part.functionCall) {
+        toolCalls.push({
+          id: `call_${Date.now()}_${Math.random().toString(36).slice(2)}`,
+          name: part.functionCall.name,
+          arguments: (part.functionCall.args as Record<string, unknown>) || {},
+        });
+      }
+    }
+
+    let stopReason: LLMResponse["stopReason"] = "end_turn";
+    if (toolCalls.length > 0) {
+      stopReason = "tool_use";
+    } else if (candidate.finishReason === "MAX_TOKENS") {
+      stopReason = "max_tokens";
+    }
+
+    return {
+      content: textContent,
+      toolCalls,
+      stopReason,
+    };
+  }
+}
+
+function typeboxToGeminiSchema(
+  schema: TSchema
+): FunctionDeclaration["parameters"] {
+  const result: Record<string, unknown> = {
+    type: getGeminiSchemaType(schema),
+  };
+
+  if (schema.description) {
+    result.description = schema.description;
+  }
+
+  if (schema[Kind] === "Object" && schema.properties) {
+    result.properties = {};
+    const required: string[] = [];
+
+    for (const [key, prop] of Object.entries(
+      schema.properties as Record<string, TSchema>
+    )) {
+      (result.properties as Record<string, unknown>)[key] =
+        typeboxToGeminiSchema(prop);
+      if (prop[Kind] !== "Optional") {
+        required.push(key);
+      }
+    }
+
+    if (required.length > 0) {
+      result.required = required;
+    }
+  }
+
+  if (schema[Kind] === "Array" && schema.items) {
+    result.items = typeboxToGeminiSchema(schema.items as TSchema);
+  }
+
+  return result as unknown as FunctionDeclaration["parameters"];
+}
+
+function getGeminiSchemaType(schema: TSchema): SchemaType {
+  const kind = schema[Kind];
+  switch (kind) {
+    case "String":
+      return SchemaType.STRING;
+    case "Number":
+    case "Integer":
+      return SchemaType.NUMBER;
+    case "Boolean":
+      return SchemaType.BOOLEAN;
+    case "Array":
+      return SchemaType.ARRAY;
+    case "Object":
+      return SchemaType.OBJECT;
+    default:
+      return SchemaType.OBJECT;
+  }
+}
src/llm/index.ts
@@ -0,0 +1,99 @@
+import { ModelInfo, Provider, ProviderConfig } from "../config.js";
+import { LLMProvider } from "./types.js";
+import { AnthropicProvider } from "./anthropic.js";
+import { GoogleProvider } from "./google.js";
+import { OpenAIProvider } from "./openai.js";
+import { OllamaProvider } from "./ollama.js";
+
+export type { LLMProvider, Message, ToolDefinition, LLMResponse } from "./types.js";
+
+export function createProvider(
+  modelInfo: ModelInfo,
+  providerConfig: ProviderConfig
+): LLMProvider {
+  const { provider, model } = modelInfo;
+
+  switch (provider) {
+    case "anthropic": {
+      const config = providerConfig.anthropic;
+      if (!config) {
+        throw new Error("Anthropic API key not configured");
+      }
+      return new AnthropicProvider(config.apiKey, model);
+    }
+
+    case "google": {
+      const config = providerConfig.google;
+      if (!config) {
+        throw new Error("Google API key not configured");
+      }
+      return new GoogleProvider(config.apiKey, model);
+    }
+
+    case "openai": {
+      const config = providerConfig.openai;
+      if (!config) {
+        throw new Error("OpenAI API key not configured");
+      }
+      return new OpenAIProvider(config.apiKey, model);
+    }
+
+    case "github": {
+      const config = providerConfig.github;
+      if (!config) {
+        throw new Error("GitHub token not configured");
+      }
+      // GitHub Copilot uses OpenAI-compatible API
+      return new OpenAIProvider(
+        config.token,
+        model,
+        "https://api.githubcopilot.com"
+      );
+    }
+
+    case "ollama": {
+      const config = providerConfig.ollama;
+      const baseUrl = config?.baseUrl || "http://localhost:11434";
+      return new OllamaProvider(baseUrl, model);
+    }
+
+    case "groq": {
+      const config = providerConfig.groq;
+      if (!config) {
+        throw new Error("Groq API key not configured");
+      }
+      return new OpenAIProvider(
+        config.apiKey,
+        model,
+        "https://api.groq.com/openai/v1"
+      );
+    }
+
+    case "mistral": {
+      const config = providerConfig.mistral;
+      if (!config) {
+        throw new Error("Mistral API key not configured");
+      }
+      return new OpenAIProvider(
+        config.apiKey,
+        model,
+        "https://api.mistral.ai/v1"
+      );
+    }
+
+    case "openrouter": {
+      const config = providerConfig.openrouter;
+      if (!config) {
+        throw new Error("OpenRouter API key not configured");
+      }
+      return new OpenAIProvider(
+        config.apiKey,
+        model,
+        "https://openrouter.ai/api/v1"
+      );
+    }
+
+    default:
+      throw new Error(`Unknown provider: ${provider}`);
+  }
+}
src/llm/ollama.ts
@@ -0,0 +1,179 @@
+import { LLMProvider, Message, ToolDefinition, LLMResponse } from "./types.js";
+import { TSchema, Kind } from "@sinclair/typebox";
+
+interface OllamaMessage {
+  role: "system" | "user" | "assistant";
+  content: string;
+}
+
+interface OllamaTool {
+  type: "function";
+  function: {
+    name: string;
+    description: string;
+    parameters: Record<string, unknown>;
+  };
+}
+
+interface OllamaToolCall {
+  function: {
+    name: string;
+    arguments: Record<string, unknown>;
+  };
+}
+
+interface OllamaResponse {
+  message: {
+    role: string;
+    content: string;
+    tool_calls?: OllamaToolCall[];
+  };
+  done: boolean;
+  done_reason?: string;
+}
+
+export class OllamaProvider implements LLMProvider {
+  name = "ollama";
+  private baseUrl: string;
+  private model: string;
+
+  constructor(baseUrl: string, model: string) {
+    this.baseUrl = baseUrl.replace(/\/$/, "");
+    this.model = model;
+  }
+
+  async chat(
+    messages: Message[],
+    options: {
+      systemPrompt?: string;
+      tools?: ToolDefinition[];
+      maxTokens?: number;
+    }
+  ): Promise<LLMResponse> {
+    const ollamaMessages: OllamaMessage[] = [];
+
+    if (options.systemPrompt) {
+      ollamaMessages.push({
+        role: "system",
+        content: options.systemPrompt,
+      });
+    }
+
+    for (const m of messages) {
+      if (m.role === "system") continue;
+      ollamaMessages.push({
+        role: m.role,
+        content: m.content,
+      });
+    }
+
+    const tools: OllamaTool[] | undefined = options.tools?.map((t) => ({
+      type: "function" as const,
+      function: {
+        name: t.name,
+        description: t.description,
+        parameters: typeboxToJsonSchema(t.parameters),
+      },
+    }));
+
+    const response = await fetch(`${this.baseUrl}/api/chat`, {
+      method: "POST",
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify({
+        model: this.model,
+        messages: ollamaMessages,
+        tools: tools?.length ? tools : undefined,
+        stream: false,
+        options: {
+          num_predict: options.maxTokens || 4096,
+        },
+      }),
+    });
+
+    if (!response.ok) {
+      throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
+    }
+
+    const data = (await response.json()) as OllamaResponse;
+
+    const textContent = data.message.content || null;
+    const toolCalls: LLMResponse["toolCalls"] = [];
+
+    if (data.message.tool_calls) {
+      for (const tc of data.message.tool_calls) {
+        toolCalls.push({
+          id: `call_${Date.now()}_${Math.random().toString(36).slice(2)}`,
+          name: tc.function.name,
+          arguments: tc.function.arguments || {},
+        });
+      }
+    }
+
+    let stopReason: LLMResponse["stopReason"] = "end_turn";
+    if (toolCalls.length > 0) {
+      stopReason = "tool_use";
+    } else if (data.done_reason === "length") {
+      stopReason = "max_tokens";
+    }
+
+    return {
+      content: textContent,
+      toolCalls,
+      stopReason,
+    };
+  }
+}
+
+function typeboxToJsonSchema(schema: TSchema): Record<string, unknown> {
+  const result: Record<string, unknown> = {
+    type: getJsonSchemaType(schema),
+  };
+
+  if (schema.description) {
+    result.description = schema.description;
+  }
+
+  if (schema[Kind] === "Object" && schema.properties) {
+    result.properties = {};
+    const required: string[] = [];
+
+    for (const [key, prop] of Object.entries(
+      schema.properties as Record<string, TSchema>
+    )) {
+      (result.properties as Record<string, unknown>)[key] =
+        typeboxToJsonSchema(prop);
+      if (prop[Kind] !== "Optional") {
+        required.push(key);
+      }
+    }
+
+    if (required.length > 0) {
+      result.required = required;
+    }
+  }
+
+  if (schema[Kind] === "Array" && schema.items) {
+    result.items = typeboxToJsonSchema(schema.items as TSchema);
+  }
+
+  return result;
+}
+
+function getJsonSchemaType(schema: TSchema): string {
+  const kind = schema[Kind];
+  switch (kind) {
+    case "String":
+      return "string";
+    case "Number":
+    case "Integer":
+      return "number";
+    case "Boolean":
+      return "boolean";
+    case "Array":
+      return "array";
+    case "Object":
+      return "object";
+    default:
+      return "object";
+  }
+}
src/llm/openai.ts
@@ -0,0 +1,159 @@
+import OpenAI from "openai";
+import { LLMProvider, Message, ToolDefinition, LLMResponse } from "./types.js";
+import { TSchema, Kind } from "@sinclair/typebox";
+
+export class OpenAIProvider implements LLMProvider {
+  name = "openai";
+  private client: OpenAI;
+  private model: string;
+
+  constructor(apiKey: string, model: string, baseUrl?: string) {
+    this.client = new OpenAI({
+      apiKey,
+      baseURL: baseUrl,
+    });
+    this.model = model;
+  }
+
+  async chat(
+    messages: Message[],
+    options: {
+      systemPrompt?: string;
+      tools?: ToolDefinition[];
+      maxTokens?: number;
+    }
+  ): Promise<LLMResponse> {
+    const openaiMessages: OpenAI.ChatCompletionMessageParam[] = [];
+
+    if (options.systemPrompt) {
+      openaiMessages.push({
+        role: "system",
+        content: options.systemPrompt,
+      });
+    }
+
+    for (const m of messages) {
+      if (m.role === "system") continue;
+      openaiMessages.push({
+        role: m.role,
+        content: m.content,
+      });
+    }
+
+    const tools = options.tools?.map((t) => ({
+      type: "function" as const,
+      function: {
+        name: t.name,
+        description: t.description,
+        parameters: typeboxToJsonSchema(t.parameters),
+      },
+    }));
+
+    const response = await this.client.chat.completions.create({
+      model: this.model,
+      messages: openaiMessages,
+      tools: tools?.length ? tools : undefined,
+      max_tokens: options.maxTokens || 4096,
+    });
+
+    const choice = response.choices[0];
+    if (!choice) {
+      return {
+        content: null,
+        toolCalls: [],
+        stopReason: "error",
+      };
+    }
+
+    const textContent = choice.message.content;
+    const toolCalls: LLMResponse["toolCalls"] = [];
+
+    if (choice.message.tool_calls) {
+      for (const tc of choice.message.tool_calls) {
+        if (tc.type === "function") {
+          toolCalls.push({
+            id: tc.id,
+            name: tc.function.name,
+            arguments: JSON.parse(tc.function.arguments || "{}"),
+          });
+        }
+      }
+    }
+
+    let stopReason: LLMResponse["stopReason"] = "end_turn";
+    if (choice.finish_reason === "tool_calls") {
+      stopReason = "tool_use";
+    } else if (choice.finish_reason === "length") {
+      stopReason = "max_tokens";
+    }
+
+    return {
+      content: textContent,
+      toolCalls,
+      stopReason,
+    };
+  }
+}
+
+function typeboxToJsonSchema(schema: TSchema): Record<string, unknown> {
+  const result: Record<string, unknown> = {
+    type: getJsonSchemaType(schema),
+  };
+
+  if (schema.description) {
+    result.description = schema.description;
+  }
+
+  if (schema[Kind] === "Object" && schema.properties) {
+    result.properties = {};
+    const required: string[] = [];
+
+    for (const [key, prop] of Object.entries(
+      schema.properties as Record<string, TSchema>
+    )) {
+      (result.properties as Record<string, unknown>)[key] =
+        typeboxToJsonSchema(prop);
+      if (prop[Kind] !== "Optional") {
+        required.push(key);
+      }
+    }
+
+    if (required.length > 0) {
+      result.required = required;
+    }
+  }
+
+  if (schema[Kind] === "Array" && schema.items) {
+    result.items = typeboxToJsonSchema(schema.items as TSchema);
+  }
+
+  if (schema[Kind] === "Union" && schema.anyOf) {
+    result.anyOf = (schema.anyOf as TSchema[]).map(typeboxToJsonSchema);
+    delete result.type;
+  }
+
+  if (schema.default !== undefined) {
+    result.default = schema.default;
+  }
+
+  return result;
+}
+
+function getJsonSchemaType(schema: TSchema): string {
+  const kind = schema[Kind];
+  switch (kind) {
+    case "String":
+      return "string";
+    case "Number":
+    case "Integer":
+      return "number";
+    case "Boolean":
+      return "boolean";
+    case "Array":
+      return "array";
+    case "Object":
+      return "object";
+    default:
+      return "object";
+  }
+}
src/llm/types.ts
@@ -0,0 +1,46 @@
+import { TSchema } from "@sinclair/typebox";
+
+export interface Message {
+  role: "user" | "assistant" | "system";
+  content: string;
+}
+
+export interface ToolDefinition {
+  name: string;
+  description: string;
+  parameters: TSchema;
+}
+
+export interface ToolCallRequest {
+  id: string;
+  name: string;
+  arguments: Record<string, unknown>;
+}
+
+export interface LLMResponse {
+  content: string | null;
+  toolCalls: ToolCallRequest[];
+  stopReason: "end_turn" | "tool_use" | "max_tokens" | "error";
+}
+
+export interface ToolResultMessage {
+  role: "user";
+  content: Array<{
+    type: "tool_result";
+    tool_use_id: string;
+    content: string;
+    is_error?: boolean;
+  }>;
+}
+
+export interface LLMProvider {
+  name: string;
+  chat(
+    messages: Message[],
+    options: {
+      systemPrompt?: string;
+      tools?: ToolDefinition[];
+      maxTokens?: number;
+    }
+  ): Promise<LLMResponse>;
+}
src/tools/index.ts
@@ -0,0 +1,35 @@
+import { Tool, ToolRegistry } from "./types.js";
+import { createStatusTool } from "./status.js";
+import { createOrgmodeTool } from "./orgmode.js";
+import { createResearchTool } from "./research.js";
+import { createWebSearchTool } from "./websearch.js";
+import { Config } from "../config.js";
+
+export function createToolRegistry(config: Config): ToolRegistry {
+  const tools = new Map<string, Tool>();
+
+  const registry: ToolRegistry = {
+    tools,
+    register: (tool: Tool) => {
+      tools.set(tool.name, tool);
+    },
+    get: (name: string) => tools.get(name),
+    list: () => Array.from(tools.values()),
+    getSchemas: () =>
+      Array.from(tools.values()).map((t) => ({
+        name: t.name,
+        description: t.description,
+        parameters: t.parameters,
+      })),
+  };
+
+  // Register default tools
+  registry.register(createStatusTool());
+  registry.register(createOrgmodeTool(config.paths.inboxPath));
+  registry.register(createResearchTool());
+  registry.register(createWebSearchTool());
+
+  return registry;
+}
+
+export type { Tool, ToolRegistry } from "./types.js";
src/tools/orgmode.ts
@@ -0,0 +1,85 @@
+import { Type } from "@sinclair/typebox";
+import { Tool } from "./types.js";
+import * as fs from "fs/promises";
+
+const OrgmodeParams = Type.Object({
+  title: Type.String({ description: "Title for the org entry" }),
+  content: Type.String({ description: "Content to save (markdown or plain text)" }),
+  tags: Type.Optional(
+    Type.Array(Type.String(), { description: "Optional tags for the entry" })
+  ),
+});
+
+type OrgmodeArgs = typeof OrgmodeParams.static;
+
+export function createOrgmodeTool(inboxPath: string): Tool<OrgmodeArgs> {
+  return {
+    name: "save_to_org",
+    description:
+      "Save content to the org-mode inbox file. Use for saving research results, notes, or any content the user wants to keep.",
+    parameters: OrgmodeParams,
+    execute: async (args) => {
+      const { title, content, tags } = args;
+
+      const timestamp = new Date().toISOString();
+      const dateStr = timestamp.slice(0, 10);
+      const timeStr = timestamp.slice(11, 16);
+
+      // Format tags for org-mode
+      const tagStr = tags && tags.length > 0 ? `:${tags.join(":")}:` : "";
+
+      // Convert markdown to org-mode (basic conversion)
+      const orgContent = convertMarkdownToOrg(content);
+
+      // Create org entry
+      const entry = `
+* TODO ${title} ${tagStr}
+:PROPERTIES:
+:CREATED: [${dateStr} ${timeStr}]
+:SOURCE: daneel
+:END:
+
+${orgContent}
+`;
+
+      // Append to inbox file
+      await fs.appendFile(inboxPath, entry, "utf-8");
+
+      return `Saved to org inbox: "${title}"`;
+    },
+  };
+}
+
+function convertMarkdownToOrg(markdown: string): string {
+  let org = markdown;
+
+  // Convert headers (### -> ***)
+  org = org.replace(/^### (.+)$/gm, "*** $1");
+  org = org.replace(/^## (.+)$/gm, "** $1");
+  org = org.replace(/^# (.+)$/gm, "* $1");
+
+  // Convert bold (**text** -> *text*)
+  org = org.replace(/\*\*(.+?)\*\*/g, "*$1*");
+
+  // Convert italic (*text* or _text_ -> /text/)
+  // Be careful not to convert already-converted bold
+  org = org.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, "/$1/");
+  org = org.replace(/_(.+?)_/g, "/$1/");
+
+  // Convert inline code (`code` -> =code=)
+  org = org.replace(/`([^`]+)`/g, "=$1=");
+
+  // Convert code blocks
+  org = org.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
+    const langStr = lang ? ` ${lang}` : "";
+    return `#+BEGIN_SRC${langStr}\n${code}#+END_SRC`;
+  });
+
+  // Convert links [text](url) -> [[url][text]]
+  org = org.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "[[$2][$1]]");
+
+  // Convert unordered lists (- item -> - item, already compatible)
+  // Convert ordered lists (1. item -> 1. item, already compatible)
+
+  return org;
+}
src/tools/research.ts
@@ -0,0 +1,41 @@
+import { Type } from "@sinclair/typebox";
+import { Tool } from "./types.js";
+
+const ResearchParams = Type.Object({
+  query: Type.String({ description: "The research query or question" }),
+  depth: Type.Optional(
+    Type.Union([Type.Literal("quick"), Type.Literal("thorough")], {
+      description: "How deep to research: quick for fast answers, thorough for comprehensive research",
+      default: "quick",
+    })
+  ),
+});
+
+type ResearchArgs = typeof ResearchParams.static;
+
+export function createResearchTool(): Tool<ResearchArgs> {
+  return {
+    name: "research",
+    description:
+      "Research a topic or answer a question. Use this for queries that require gathering information or analysis.",
+    parameters: ResearchParams,
+    execute: async (args) => {
+      const { query, depth = "quick" } = args;
+
+      // For now, this is a placeholder that returns a message
+      // In a full implementation, this could:
+      // - Call web search APIs
+      // - Query knowledge bases
+      // - Use RAG with local documents
+      // - Aggregate multiple sources
+
+      return JSON.stringify({
+        query,
+        depth,
+        note: "Research tool executed. In the current implementation, the LLM should answer based on its training data. Future versions will integrate web search and other data sources.",
+        suggestion:
+          "Provide your best answer based on your knowledge. If you need real-time data, inform the user that web search is not yet implemented.",
+      });
+    },
+  };
+}
src/tools/status.ts
@@ -0,0 +1,71 @@
+import { Type } from "@sinclair/typebox";
+import { Tool } from "./types.js";
+import * as os from "os";
+
+const StatusParams = Type.Object({});
+
+type StatusArgs = typeof StatusParams.static;
+
+export function createStatusTool(): Tool<StatusArgs> {
+  return {
+    name: "status",
+    description:
+      "Get system status including uptime, memory usage, and bot information",
+    parameters: StatusParams,
+    execute: async () => {
+      const uptime = process.uptime();
+      const memUsage = process.memoryUsage();
+      const systemUptime = os.uptime();
+
+      const formatBytes = (bytes: number): string => {
+        const mb = bytes / 1024 / 1024;
+        return `${mb.toFixed(1)} MB`;
+      };
+
+      const formatDuration = (seconds: number): string => {
+        const days = Math.floor(seconds / 86400);
+        const hours = Math.floor((seconds % 86400) / 3600);
+        const mins = Math.floor((seconds % 3600) / 60);
+        const secs = Math.floor(seconds % 60);
+
+        const parts = [];
+        if (days > 0) parts.push(`${days}d`);
+        if (hours > 0) parts.push(`${hours}h`);
+        if (mins > 0) parts.push(`${mins}m`);
+        if (secs > 0 || parts.length === 0) parts.push(`${secs}s`);
+        return parts.join(" ");
+      };
+
+      return JSON.stringify(
+        {
+          bot: {
+            name: "Daneel",
+            version: "0.1.0",
+            uptime: formatDuration(uptime),
+          },
+          system: {
+            hostname: os.hostname(),
+            platform: os.platform(),
+            arch: os.arch(),
+            uptime: formatDuration(systemUptime),
+            loadAvg: os.loadavg().map((l) => l.toFixed(2)),
+          },
+          memory: {
+            process: {
+              heapUsed: formatBytes(memUsage.heapUsed),
+              heapTotal: formatBytes(memUsage.heapTotal),
+              rss: formatBytes(memUsage.rss),
+            },
+            system: {
+              total: formatBytes(os.totalmem()),
+              free: formatBytes(os.freemem()),
+              used: formatBytes(os.totalmem() - os.freemem()),
+            },
+          },
+        },
+        null,
+        2
+      );
+    },
+  };
+}
src/tools/types.ts
@@ -0,0 +1,25 @@
+import { TSchema } from "@sinclair/typebox";
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export interface Tool<T = any> {
+  name: string;
+  description: string;
+  parameters: TSchema;
+  execute: (args: T) => Promise<string>;
+}
+
+export interface ToolRegistry {
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  tools: Map<string, Tool<any>>;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  register: (tool: Tool<any>) => void;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  get: (name: string) => Tool<any> | undefined;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  list: () => Tool<any>[];
+  getSchemas: () => Array<{
+    name: string;
+    description: string;
+    parameters: TSchema;
+  }>;
+}
src/tools/websearch.ts
@@ -0,0 +1,43 @@
+import { Type } from "@sinclair/typebox";
+import { Tool } from "./types.js";
+
+const WebSearchParams = Type.Object({
+  query: Type.String({ description: "The search query" }),
+  maxResults: Type.Optional(
+    Type.Number({
+      description: "Maximum number of results to return",
+      default: 5,
+      minimum: 1,
+      maximum: 10,
+    })
+  ),
+});
+
+type WebSearchArgs = typeof WebSearchParams.static;
+
+export function createWebSearchTool(): Tool<WebSearchArgs> {
+  return {
+    name: "web_search",
+    description:
+      "Search the web for current information. Use this for queries that require up-to-date data.",
+    parameters: WebSearchParams,
+    execute: async (args) => {
+      const { query, maxResults = 5 } = args;
+
+      // Placeholder implementation
+      // Future: integrate with search APIs like:
+      // - DuckDuckGo API
+      // - Brave Search API
+      // - SearXNG instance
+      // - Tavily API
+
+      return JSON.stringify({
+        query,
+        maxResults,
+        status: "not_implemented",
+        message:
+          "Web search is not yet implemented. Please rely on training data or ask the user to provide the information.",
+      });
+    },
+  };
+}
src/xmpp/client.ts
@@ -0,0 +1,111 @@
+import { client, xml, jid } from "@xmpp/client";
+import type { Element } from "@xmpp/xml";
+import { XmppMessage, bareJid } from "./types.js";
+import { Config } from "../config.js";
+
+export type MessageHandler = (message: XmppMessage) => Promise<void>;
+
+export class XmppClient {
+  private xmpp: ReturnType<typeof client>;
+  private messageHandler: MessageHandler | null = null;
+  private config: Config;
+
+  constructor(config: Config) {
+    this.config = config;
+
+    this.xmpp = client({
+      service: `xmpp://${jid(config.xmpp.jid).domain}`,
+      username: jid(config.xmpp.jid).local,
+      password: config.xmpp.password,
+    });
+
+    this.setupEventHandlers();
+  }
+
+  private setupEventHandlers(): void {
+    this.xmpp.on("error", (err: Error) => {
+      console.error("XMPP error:", err.message);
+    });
+
+    this.xmpp.on("offline", () => {
+      console.log("XMPP offline");
+    });
+
+    this.xmpp.on("online", async (address: ReturnType<typeof jid>) => {
+      console.log(`XMPP online as ${address.toString()}`);
+
+      // Send initial presence
+      await this.xmpp.send(xml("presence"));
+    });
+
+    this.xmpp.on("stanza", async (stanza: Element) => {
+      if (stanza.is("message")) {
+        await this.handleMessage(stanza);
+      }
+    });
+  }
+
+  private async handleMessage(stanza: Element): Promise<void> {
+    const type = stanza.attrs.type as "chat" | "groupchat" | undefined;
+
+    // Only handle chat messages (direct messages)
+    if (type !== "chat") {
+      return;
+    }
+
+    const body = stanza.getChildText("body");
+    if (!body) {
+      return;
+    }
+
+    const from = stanza.attrs.from as string;
+    const to = stanza.attrs.to as string;
+    const id = stanza.attrs.id as string | undefined;
+
+    // Security: only respond to owner
+    if (bareJid(from) !== bareJid(this.config.xmpp.ownerJid)) {
+      console.log(`Ignoring message from unauthorized JID: ${bareJid(from)}`);
+      return;
+    }
+
+    const message: XmppMessage = {
+      from,
+      to,
+      body,
+      type: "chat",
+      id,
+    };
+
+    if (this.messageHandler) {
+      try {
+        await this.messageHandler(message);
+      } catch (err) {
+        console.error("Error handling message:", err);
+        await this.sendMessage(from, `Error: ${(err as Error).message}`);
+      }
+    }
+  }
+
+  onMessage(handler: MessageHandler): void {
+    this.messageHandler = handler;
+  }
+
+  async sendMessage(to: string, body: string): Promise<void> {
+    const message = xml(
+      "message",
+      { type: "chat", to },
+      xml("body", {}, body)
+    );
+    await this.xmpp.send(message);
+  }
+
+  async start(): Promise<void> {
+    console.log("Starting XMPP client...");
+    await this.xmpp.start();
+  }
+
+  async stop(): Promise<void> {
+    console.log("Stopping XMPP client...");
+    await this.xmpp.stop();
+  }
+}
src/xmpp/types.ts
@@ -0,0 +1,36 @@
+export interface XmppMessage {
+  from: string;
+  to: string;
+  body: string;
+  type: "chat" | "groupchat";
+  id?: string;
+}
+
+export interface XmppPresence {
+  from: string;
+  to: string;
+  type?: "available" | "unavailable" | "subscribe" | "subscribed";
+  show?: "away" | "chat" | "dnd" | "xa";
+  status?: string;
+}
+
+// Extract bare JID (without resource)
+export function bareJid(jid: string): string {
+  return jid.split("/")[0];
+}
+
+// Extract resource from JID
+export function resourceFromJid(jid: string): string | null {
+  const parts = jid.split("/");
+  return parts.length > 1 ? parts[1] : null;
+}
+
+// Extract local part (username) from JID
+export function localFromJid(jid: string): string {
+  return bareJid(jid).split("@")[0];
+}
+
+// Extract domain from JID
+export function domainFromJid(jid: string): string {
+  return bareJid(jid).split("@")[1];
+}
src/xmpp/xmpp.d.ts
@@ -0,0 +1,47 @@
+declare module "@xmpp/client" {
+  export interface JID {
+    local: string;
+    domain: string;
+    resource?: string;
+    toString(): string;
+  }
+
+  export interface ClientOptions {
+    service: string;
+    username: string;
+    password: string;
+  }
+
+  export interface XMPPClient {
+    on(event: "error", handler: (err: Error) => void): void;
+    on(event: "offline", handler: () => void): void;
+    on(event: "online", handler: (address: JID) => Promise<void>): void;
+    on(event: "stanza", handler: (stanza: Element) => Promise<void>): void;
+    send(stanza: Element): Promise<void>;
+    start(): Promise<void>;
+    stop(): Promise<void>;
+  }
+
+  export interface Element {
+    is(name: string): boolean;
+    attrs: Record<string, string>;
+    getChildText(name: string): string | null;
+  }
+
+  export function client(options: ClientOptions): XMPPClient;
+  export function xml(name: string, attrs?: Record<string, unknown>, ...children: unknown[]): Element;
+  export function jid(jid: string): JID;
+}
+
+declare module "@xmpp/xml" {
+  export interface Element {
+    is(name: string): boolean;
+    attrs: Record<string, string>;
+    getChildText(name: string): string | null;
+  }
+}
+
+declare module "@xmpp/debug" {
+  import type { XMPPClient } from "@xmpp/client";
+  export default function debug(client: XMPPClient): void;
+}
src/config.ts
@@ -0,0 +1,211 @@
+import * as path from "path";
+import * as os from "os";
+
+// Model aliases for easy selection
+export type ModelAlias =
+  // Anthropic
+  | "opus"
+  | "sonnet"
+  | "haiku"
+  // Google
+  | "gemini"
+  | "gemini-pro"
+  | "gemini-flash"
+  // OpenAI
+  | "gpt4"
+  | "gpt4o"
+  | "o1"
+  | "o3"
+  // GitHub Copilot
+  | "copilot"
+  | "copilot-claude"
+  // Ollama (local)
+  | "ollama"
+  | "llama"
+  | "qwen"
+  | "deepseek"
+  // Others
+  | "groq"
+  | "mistral";
+
+export type Provider =
+  | "anthropic"
+  | "google"
+  | "openai"
+  | "github"
+  | "ollama"
+  | "groq"
+  | "mistral"
+  | "openrouter";
+
+export interface ProviderConfig {
+  anthropic?: { apiKey: string };
+  google?: { apiKey: string };
+  openai?: { apiKey: string };
+  github?: { token: string };
+  ollama?: { baseUrl: string };
+  openrouter?: { apiKey: string };
+  groq?: { apiKey: string };
+  mistral?: { apiKey: string };
+}
+
+export interface ModelInfo {
+  provider: Provider;
+  model: string;
+}
+
+// Model prefix mapping for message parsing
+export const MODEL_PREFIXES: Record<string, ModelInfo> = {
+  // Anthropic
+  "opus:": { provider: "anthropic", model: "claude-opus-4-5-20250514" },
+  "o:": { provider: "anthropic", model: "claude-opus-4-5-20250514" },
+  "sonnet:": { provider: "anthropic", model: "claude-sonnet-4-20250514" },
+  "s:": { provider: "anthropic", model: "claude-sonnet-4-20250514" },
+  "haiku:": { provider: "anthropic", model: "claude-3-5-haiku-20241022" },
+  "h:": { provider: "anthropic", model: "claude-3-5-haiku-20241022" },
+
+  // Google
+  "gemini:": { provider: "google", model: "gemini-2.0-flash" },
+  "g:": { provider: "google", model: "gemini-2.0-flash" },
+  "gemini-pro:": { provider: "google", model: "gemini-2.5-pro-preview-05-06" },
+  "gp:": { provider: "google", model: "gemini-2.5-pro-preview-05-06" },
+
+  // OpenAI
+  "gpt:": { provider: "openai", model: "gpt-4o" },
+  "gpt4:": { provider: "openai", model: "gpt-4o" },
+  "o1:": { provider: "openai", model: "o1" },
+  "o3:": { provider: "openai", model: "o3-mini" },
+
+  // GitHub Copilot
+  "copilot:": { provider: "github", model: "gpt-4o" },
+  "cp:": { provider: "github", model: "gpt-4o" },
+  "copilot-claude:": { provider: "github", model: "claude-sonnet-4" },
+
+  // Ollama (local)
+  "ollama:": { provider: "ollama", model: "llama3.2" },
+  "llama:": { provider: "ollama", model: "llama3.2" },
+  "qwen:": { provider: "ollama", model: "qwen2.5" },
+  "deepseek:": { provider: "ollama", model: "deepseek-r1" },
+
+  // Others
+  "groq:": { provider: "groq", model: "llama-3.3-70b-versatile" },
+  "mistral:": { provider: "mistral", model: "mistral-large-latest" },
+};
+
+export interface XmppConfig {
+  jid: string;
+  password: string;
+  ownerJid: string;
+}
+
+export interface PathsConfig {
+  dataDir: string;
+  inboxPath: string;
+}
+
+export interface Config {
+  xmpp: XmppConfig;
+  llm: {
+    defaultModel: ModelInfo;
+    providers: ProviderConfig;
+  };
+  paths: PathsConfig;
+  debug: boolean;
+}
+
+function getEnvOrThrow(name: string): string {
+  const value = process.env[name];
+  if (!value) {
+    throw new Error(`Required environment variable ${name} is not set`);
+  }
+  return value;
+}
+
+function getEnvOrDefault(name: string, defaultValue: string): string {
+  return process.env[name] || defaultValue;
+}
+
+export function loadConfig(): Config {
+  const xmppJid = getEnvOrThrow("DANEEL_XMPP_JID");
+  const xmppPassword = getEnvOrThrow("DANEEL_XMPP_PASSWORD");
+  const ownerJid = getEnvOrThrow("DANEEL_OWNER_JID");
+
+  const dataDir = getEnvOrDefault(
+    "DANEEL_DATA_DIR",
+    path.join(process.cwd(), "data")
+  );
+
+  const inboxPath = getEnvOrDefault(
+    "DANEEL_INBOX_PATH",
+    path.join(os.homedir(), "org", "inbox.org")
+  );
+
+  const defaultModelPrefix = getEnvOrDefault("DANEEL_DEFAULT_MODEL", "sonnet");
+  const defaultModel = MODEL_PREFIXES[`${defaultModelPrefix}:`] || {
+    provider: "anthropic" as Provider,
+    model: "claude-sonnet-4-20250514",
+  };
+
+  const providers: ProviderConfig = {};
+
+  // Load provider credentials from environment
+  if (process.env.ANTHROPIC_API_KEY) {
+    providers.anthropic = { apiKey: process.env.ANTHROPIC_API_KEY };
+  }
+  if (process.env.GOOGLE_API_KEY) {
+    providers.google = { apiKey: process.env.GOOGLE_API_KEY };
+  }
+  if (process.env.OPENAI_API_KEY) {
+    providers.openai = { apiKey: process.env.OPENAI_API_KEY };
+  }
+  if (process.env.GITHUB_TOKEN) {
+    providers.github = { token: process.env.GITHUB_TOKEN };
+  }
+  if (process.env.OLLAMA_BASE_URL) {
+    providers.ollama = {
+      baseUrl: getEnvOrDefault("OLLAMA_BASE_URL", "http://localhost:11434"),
+    };
+  }
+  if (process.env.GROQ_API_KEY) {
+    providers.groq = { apiKey: process.env.GROQ_API_KEY };
+  }
+  if (process.env.MISTRAL_API_KEY) {
+    providers.mistral = { apiKey: process.env.MISTRAL_API_KEY };
+  }
+  if (process.env.OPENROUTER_API_KEY) {
+    providers.openrouter = { apiKey: process.env.OPENROUTER_API_KEY };
+  }
+
+  return {
+    xmpp: {
+      jid: xmppJid,
+      password: xmppPassword,
+      ownerJid,
+    },
+    llm: {
+      defaultModel,
+      providers,
+    },
+    paths: {
+      dataDir,
+      inboxPath,
+    },
+    debug: process.env.DANEEL_DEBUG === "true",
+  };
+}
+
+// Parse model prefix from message
+export function parseModelPrefix(message: string): {
+  model: ModelInfo | null;
+  content: string;
+} {
+  for (const [prefix, modelInfo] of Object.entries(MODEL_PREFIXES)) {
+    if (message.toLowerCase().startsWith(prefix)) {
+      return {
+        model: modelInfo,
+        content: message.slice(prefix.length).trim(),
+      };
+    }
+  }
+  return { model: null, content: message };
+}
src/main.ts
@@ -0,0 +1,69 @@
+import { loadConfig } from "./config.js";
+import { XmppClient } from "./xmpp/client.js";
+import { SessionManager } from "./agent/session.js";
+import { AgentRunner } from "./agent/runner.js";
+import { createToolRegistry } from "./tools/index.js";
+import { bareJid } from "./xmpp/types.js";
+
+async function main(): Promise<void> {
+  console.log("Daneel - XMPP Research Bot");
+  console.log("==========================\n");
+
+  // Load configuration
+  const config = loadConfig();
+  console.log(`XMPP JID: ${config.xmpp.jid}`);
+  console.log(`Owner JID: ${config.xmpp.ownerJid}`);
+  console.log(`Default model: ${config.llm.defaultModel.provider}/${config.llm.defaultModel.model}`);
+  console.log(`Data directory: ${config.paths.dataDir}`);
+
+  // Initialize components
+  const sessionManager = new SessionManager(config.paths.dataDir);
+  const toolRegistry = createToolRegistry(config);
+
+  // Map of JID -> AgentRunner
+  const agents = new Map<string, AgentRunner>();
+
+  function getOrCreateAgent(jid: string): AgentRunner {
+    const bare = bareJid(jid);
+    let agent = agents.get(bare);
+    if (!agent) {
+      agent = new AgentRunner(bare, config, sessionManager, toolRegistry);
+      agents.set(bare, agent);
+    }
+    return agent;
+  }
+
+  // Create XMPP client
+  const xmpp = new XmppClient(config);
+
+  // Set up message handler
+  xmpp.onMessage(async (message) => {
+    console.log(`[${new Date().toISOString()}] Message from ${bareJid(message.from)}: ${message.body.slice(0, 50)}...`);
+
+    const agent = getOrCreateAgent(message.from);
+    const response = await agent.processMessage(message.body);
+
+    await xmpp.sendMessage(message.from, response);
+    console.log(`[${new Date().toISOString()}] Response sent (${response.length} chars)`);
+  });
+
+  // Graceful shutdown
+  const shutdown = async (signal: string): Promise<void> => {
+    console.log(`\nReceived ${signal}, shutting down...`);
+    await xmpp.stop();
+    process.exit(0);
+  };
+
+  process.on("SIGINT", () => shutdown("SIGINT"));
+  process.on("SIGTERM", () => shutdown("SIGTERM"));
+
+  // Start XMPP client
+  console.log("\nConnecting to XMPP server...");
+  await xmpp.start();
+  console.log("Bot is running. Press Ctrl+C to stop.\n");
+}
+
+main().catch((err) => {
+  console.error("Fatal error:", err);
+  process.exit(1);
+});
.gitignore
@@ -0,0 +1,26 @@
+# Dependencies
+node_modules/
+
+# Build output
+dist/
+
+# Session data
+data/
+
+# Environment
+.env
+.env.local
+
+# IDE
+.idea/
+.vscode/
+*.swp
+*.swo
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Logs
+*.log
+npm-debug.log*
package-lock.json
@@ -0,0 +1,3834 @@
+{
+  "name": "daneel",
+  "version": "0.1.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "daneel",
+      "version": "0.1.0",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@anthropic-ai/sdk": "^0.39.0",
+        "@google/generative-ai": "^0.21.0",
+        "@sinclair/typebox": "^0.32.0",
+        "@xmpp/client": "^0.13.1",
+        "@xmpp/debug": "^0.13.0",
+        "js-yaml": "^4.1.0",
+        "openai": "^4.77.0"
+      },
+      "devDependencies": {
+        "@types/js-yaml": "^4.0.9",
+        "@types/node": "^20.0.0",
+        "typescript": "^5.3.0"
+      }
+    },
+    "node_modules/@anthropic-ai/sdk": {
+      "version": "0.39.0",
+      "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.39.0.tgz",
+      "integrity": "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "^18.11.18",
+        "@types/node-fetch": "^2.6.4",
+        "abort-controller": "^3.0.0",
+        "agentkeepalive": "^4.2.1",
+        "form-data-encoder": "1.7.2",
+        "formdata-node": "^4.3.2",
+        "node-fetch": "^2.6.7"
+      }
+    },
+    "node_modules/@anthropic-ai/sdk/node_modules/@types/node": {
+      "version": "18.19.130",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
+      "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/@anthropic-ai/sdk/node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "license": "MIT"
+    },
+    "node_modules/@babel/cli": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.28.6.tgz",
+      "integrity": "sha512-6EUNcuBbNkj08Oj4gAZ+BUU8yLCgKzgVX4gaTh09Ya2C8ICM4P+G30g4m3akRxSYAp3A/gnWchrNst7px4/nUQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "commander": "^6.2.0",
+        "convert-source-map": "^2.0.0",
+        "fs-readdir-recursive": "^1.1.0",
+        "glob": "^7.2.0",
+        "make-dir": "^2.1.0",
+        "slash": "^2.0.0"
+      },
+      "bin": {
+        "babel": "bin/babel.js",
+        "babel-external-helpers": "bin/babel-external-helpers.js"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "optionalDependencies": {
+        "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3",
+        "chokidar": "^3.6.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+      "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.28.5",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
+      "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+      "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.29.0",
+        "@babel/generator": "^7.29.0",
+        "@babel/helper-compilation-targets": "^7.28.6",
+        "@babel/helper-module-transforms": "^7.28.6",
+        "@babel/helpers": "^7.28.6",
+        "@babel/parser": "^7.29.0",
+        "@babel/template": "^7.28.6",
+        "@babel/traverse": "^7.29.0",
+        "@babel/types": "^7.29.0",
+        "@jridgewell/remapping": "^2.3.5",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz",
+      "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.0",
+        "@babel/types": "^7.29.0",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.27.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
+      "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.27.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+      "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.28.6",
+        "@babel/helper-validator-option": "^7.27.1",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-globals": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+      "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+      "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+      "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.28.6",
+        "@babel/helper-validator-identifier": "^7.28.5",
+        "@babel/traverse": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+      "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.28.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+      "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+      "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
+      "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/node": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/node/-/node-7.29.0.tgz",
+      "integrity": "sha512-9UeU8F3rx2lOZXneEW2HTnTYdA8+fXP0kr54tk7d0fPomWNlZ6WJ2H9lunr5dSvr8FNY0CDnop3Km6jZ5NAUsQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/register": "^7.28.6",
+        "commander": "^6.2.0",
+        "core-js": "^3.48.0",
+        "node-environment-flags": "^1.0.5",
+        "regenerator-runtime": "^0.14.0",
+        "v8flags": "^3.1.1"
+      },
+      "bin": {
+        "babel-node": "bin/babel-node.js"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
+      "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.0"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
+      "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz",
+      "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.27.3",
+        "@babel/helper-module-imports": "^7.28.6",
+        "@babel/helper-plugin-utils": "^7.28.6",
+        "@babel/plugin-syntax-jsx": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/register": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.6.tgz",
+      "integrity": "sha512-pgcbbEl/dWQYb6L6Yew6F94rdwygfuv+vJ/tXfwIOYAfPB6TNWpXUMEtEq3YuTeHRdvMIhvz13bkT9CNaS+wqA==",
+      "license": "MIT",
+      "dependencies": {
+        "clone-deep": "^4.0.1",
+        "find-cache-dir": "^2.0.0",
+        "make-dir": "^2.1.0",
+        "pirates": "^4.0.6",
+        "source-map-support": "^0.5.16"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+      "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.28.6",
+        "@babel/parser": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+      "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.0",
+        "@babel/generator": "^7.29.0",
+        "@babel/helper-globals": "^7.28.0",
+        "@babel/parser": "^7.29.0",
+        "@babel/template": "^7.28.6",
+        "@babel/types": "^7.29.0",
+        "debug": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+      "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.28.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@google/generative-ai": {
+      "version": "0.21.0",
+      "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.21.0.tgz",
+      "integrity": "sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@nicolo-ribaudo/chokidar-2": {
+      "version": "2.1.8-no-fsevents.3",
+      "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
+      "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@sinclair/typebox": {
+      "version": "0.32.35",
+      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.35.tgz",
+      "integrity": "sha512-Ul3YyOTU++to8cgNkttakC0dWvpERr6RYoHO2W47DLbFvrwBDJUY31B1sImH6JZSYc4Kt4PyHtoPNu+vL2r2dA==",
+      "license": "MIT"
+    },
+    "node_modules/@types/js-yaml": {
+      "version": "4.0.9",
+      "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+      "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "20.19.31",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.31.tgz",
+      "integrity": "sha512-5jsi0wpncvTD33Sh1UCgacK37FFwDn+EG7wCmEvs62fCvBL+n8/76cAYDok21NF6+jaVWIqKwCZyX7Vbu8eB3A==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.21.0"
+      }
+    },
+    "node_modules/@types/node-fetch": {
+      "version": "2.6.13",
+      "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz",
+      "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*",
+        "form-data": "^4.0.4"
+      }
+    },
+    "node_modules/@xmpp/base64": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/base64/-/base64-0.13.2.tgz",
+      "integrity": "sha512-RDEq66sW/jqj2HZKoRvnIvlRJMRLEGa0EGyJ0yPCF1+KijmTqrWr1PxZAol850QizXlqpvo8MS8OCFWMryX7RQ==",
+      "license": "ISC",
+      "dependencies": {
+        "base-64": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/client": {
+      "version": "0.13.6",
+      "resolved": "https://registry.npmjs.org/@xmpp/client/-/client-0.13.6.tgz",
+      "integrity": "sha512-e4JTcJQ20HEE1VfO2Wrq/y8ujlNZ8L4jmctX/9uhsZ/46GrNFh8uQJUSRMvaf4LV+T9xV55yu1yGDxjZYjwLsg==",
+      "license": "ISC",
+      "dependencies": {
+        "@babel/cli": "^7.26.4",
+        "@babel/core": "^7.26.0",
+        "@babel/node": "^7.26.0",
+        "@babel/plugin-transform-react-jsx": "^7.25.9",
+        "@xmpp/client-core": "^0.13.3",
+        "@xmpp/iq": "^0.13.3",
+        "@xmpp/middleware": "^0.13.3",
+        "@xmpp/reconnect": "^0.13.2",
+        "@xmpp/resolve": "^0.13.3",
+        "@xmpp/resource-binding": "^0.13.3",
+        "@xmpp/sasl": "^0.13.6",
+        "@xmpp/sasl-anonymous": "^0.13.2",
+        "@xmpp/sasl-plain": "^0.13.2",
+        "@xmpp/sasl-scram-sha-1": "^0.13.2",
+        "@xmpp/session-establishment": "^0.13.3",
+        "@xmpp/starttls": "^0.13.3",
+        "@xmpp/stream-features": "^0.13.2",
+        "@xmpp/stream-management": "^0.13.3",
+        "@xmpp/tcp": "^0.13.3",
+        "@xmpp/tls": "^0.13.3",
+        "@xmpp/websocket": "^0.13.3",
+        "babel-plugin-jsx-pragmatic": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/client-core": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/client-core/-/client-core-0.13.3.tgz",
+      "integrity": "sha512-pOtCozET4BxJZU7aWykT+PFBGaxT/Sl8mC0E3X6QgL7/2Vo39lz2KIhkcvtSwMC8myuaB+klOBrifuKLo3IajA==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/connection": "^0.13.3",
+        "@xmpp/jid": "^0.13.2",
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/connection": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/connection/-/connection-0.13.3.tgz",
+      "integrity": "sha512-EM6/wLUJ6MFJl7Kb+qwQut1gLDp7G107KTOB1W/GljGMd7ydD2Bn0BJt2AAx8EGPve9G2jjhV3+jJmu7KwK4rQ==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/error": "^0.13.2",
+        "@xmpp/events": "^0.13.2",
+        "@xmpp/jid": "^0.13.2",
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/connection-tcp": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/connection-tcp/-/connection-tcp-0.13.3.tgz",
+      "integrity": "sha512-6MMUSM265eBtHeLOYIe5UP1ld3oZaQMso6Cq7KJ0Xe7qC6zDy3YYaRHAe3Z+bdoJxpgmfiN8jvDM+QfypcTpKg==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/connection": "^0.13.3",
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/debug": {
+      "version": "0.13.5",
+      "resolved": "https://registry.npmjs.org/@xmpp/debug/-/debug-0.13.5.tgz",
+      "integrity": "sha512-RNQMDbz6AX0eMZgJ+Xz82T2tbj1wigaDYoGJsy5dt2TMOBZtBRxC+VAx5Pb7sM4T5JpbWQX6iJBhIB7C/gpGgg==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/xml": "^0.13.3",
+        "ltx": "3.0.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/error": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/error/-/error-0.13.2.tgz",
+      "integrity": "sha512-bjbxwF8s6jfQNI+ZHV9Jwcb7K2kBeTlD60QHjMJlxIUrjTH1ZsJoDQh9tMdq1mBu/h/bm2SX7yZUqUb1wY6gMw==",
+      "license": "ISC",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/events": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/events/-/events-0.13.2.tgz",
+      "integrity": "sha512-fXaAMChvLnP9vEQIatFKWoAm/F9U122hShfRfVw4xS6pympThygWVPIuRuAznMt5tOyTVFWBuPge6hgGousT0g==",
+      "license": "ISC",
+      "dependencies": {
+        "events": "^3.3.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/id": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/id/-/id-0.13.2.tgz",
+      "integrity": "sha512-LhSzcaPvjddvL+u/xNAuu6tNtxWR7HZPTyMUck8tyYnbwsXaJQ6sDoS8AEQE8o7iW5E31xJUTOktYd/s6HMo3w==",
+      "license": "ISC",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/iq": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/iq/-/iq-0.13.3.tgz",
+      "integrity": "sha512-sGeyGF4OnYGTZw3PhQaYLYlE8+LRZfYijT/ESGqhY2ed9gm0U4TCR8C8s5oT7Puu6S6smdHehcvYCrcFEeQyBw==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/events": "^0.13.2",
+        "@xmpp/id": "^0.13.2",
+        "@xmpp/middleware": "^0.13.3",
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/jid": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.13.2.tgz",
+      "integrity": "sha512-OuYrxiNdlmXgMFPJqnbZSKe/bdn1wxtc1ASEadrizI9h6T1y7tAEl5YpXFWYb+fdAL9vRD+bGCxrDUrm1er/LQ==",
+      "license": "ISC",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/middleware": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/middleware/-/middleware-0.13.3.tgz",
+      "integrity": "sha512-zZTsqLaHnfTqMBDyZh01HLYUgcHLmbalVfC32CsEcjPG5/bIete9sOUVPaiGH1cicMgi3O7WZK512RvQFcBbwA==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/error": "^0.13.2",
+        "@xmpp/jid": "^0.13.2",
+        "@xmpp/xml": "^0.13.3",
+        "koa-compose": "^4.1.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/reconnect": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/reconnect/-/reconnect-0.13.2.tgz",
+      "integrity": "sha512-FWCC+dzi23N7H99PYPqWZa7oRPNp9G7yYzMZwOpeiVporbNy+op3yUbCszo3YA3XVEsuLRQ1aQJ8evLo+GD5ow==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/events": "^0.13.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/resolve": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/resolve/-/resolve-0.13.3.tgz",
+      "integrity": "sha512-HL86p0a2CI0ILFYUR8vPR77ZXwxQ0xXLLRnyb88TjQ/eNbYsc1gmdXjELE0xRCfQblXZsETvUwWv5RofTYAgrQ==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/events": "^0.13.2",
+        "@xmpp/xml": "^0.13.3",
+        "node-fetch": "^3.3.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/resolve/node_modules/node-fetch": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+      "license": "MIT",
+      "dependencies": {
+        "data-uri-to-buffer": "^4.0.0",
+        "fetch-blob": "^3.1.4",
+        "formdata-polyfill": "^4.0.10"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/node-fetch"
+      }
+    },
+    "node_modules/@xmpp/resource-binding": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/resource-binding/-/resource-binding-0.13.3.tgz",
+      "integrity": "sha512-cph/8vJ5sRHVg7Njx8rR27xAVmKWACSx95jlOw7LmUSTRSxZDw2wHsqie76HxUD5fPszOsTh/Ph7Fw1532aRUQ==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/sasl": {
+      "version": "0.13.6",
+      "resolved": "https://registry.npmjs.org/@xmpp/sasl/-/sasl-0.13.6.tgz",
+      "integrity": "sha512-0WueO7QlHK1F0K7iaC/zW60Y6NIjOccHZlb1WRS1jdHmHqwTLWM8AQTAZMvtxWLDz8oUDiVUKEOJTdIvy9bXow==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/base64": "^0.13.2",
+        "@xmpp/error": "^0.13.2",
+        "@xmpp/xml": "^0.13.3",
+        "saslmechanisms": "^0.1.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/sasl-anonymous": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/sasl-anonymous/-/sasl-anonymous-0.13.2.tgz",
+      "integrity": "sha512-0fI9+A+Vptcyv8+o8J2veRnodtnKahJDy5fappIZbmXLrv4JcrVBChQDWULyta0Hez9M3XWoIyuhp4pyz0IU/Q==",
+      "license": "ISC",
+      "dependencies": {
+        "sasl-anonymous": "^0.1.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/sasl-plain": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/sasl-plain/-/sasl-plain-0.13.2.tgz",
+      "integrity": "sha512-zwS/q+Vd4YsLdnZjmCuS1JCacWWg2Vd3ecqpBmIV3S394s1Mgiwdnd2bVRen5S0kl/de+VzHg/DRLuYvC94SUg==",
+      "license": "ISC",
+      "dependencies": {
+        "sasl-plain": "^0.1.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/sasl-scram-sha-1": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/sasl-scram-sha-1/-/sasl-scram-sha-1-0.13.2.tgz",
+      "integrity": "sha512-qHwooR3m8/BsuG17tK50ZKO97HITG+k6Chjk/pSjRfKG5Fm3mWh2U8K98QWNpJYbgVm9amkIQ0tbTaw+/kMjvQ==",
+      "license": "ISC",
+      "dependencies": {
+        "sasl-scram-sha-1": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/session-establishment": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/session-establishment/-/session-establishment-0.13.3.tgz",
+      "integrity": "sha512-dQhH7aIzsqyMRsjMIuER4UBCxQgvDUHjkmNoeIbUZX5bYJuGeET90tZ4eNAq6yXnpSGJiKoXVfVBxNoiXovfgA==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/starttls": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/starttls/-/starttls-0.13.3.tgz",
+      "integrity": "sha512-FjKrpahL/yBiRlMUL4d88I5N5PxQN2Mirx39Q0kyo479Nj1OY4dTA78Iy5+tsbsBYO3j5aE2tRoLhUQaMPGvBQ==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/events": "^0.13.2",
+        "@xmpp/tls": "^0.13.3",
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/stream-features": {
+      "version": "0.13.2",
+      "resolved": "https://registry.npmjs.org/@xmpp/stream-features/-/stream-features-0.13.2.tgz",
+      "integrity": "sha512-eyxFEEDSfNvG4ybvAYTYkjaUcaytu8sAqT8DfWwrWzCkPgfRzpexsxb9yhe8hAVrvPLavOyr+zh4raUQf4Ogkg==",
+      "license": "ISC",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/stream-management": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/stream-management/-/stream-management-0.13.3.tgz",
+      "integrity": "sha512-hdQAyp6FldEkBktou/mbb7MPOe/EzBxP3sIjWvNQXwRMV8AJxAXyi+DhnW5sigRQoeTJJB0FGTxOlFDeXWGhPg==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/xml": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/tcp": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/tcp/-/tcp-0.13.3.tgz",
+      "integrity": "sha512-WUjAsPVQAr/DTNJGxXOqXEviFvI5Gzp/18TuCJEssAjyHv1Pr7Qn6PjAersIPidEKqVfapNyHOmgyLePh1kAqQ==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/connection-tcp": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/tls": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/tls/-/tls-0.13.3.tgz",
+      "integrity": "sha512-oeXbkzu2i2LkpvPQ4B3RourYnktoUpkWeUS7jRB4wHvdy6ecEli593R+DYVCWr3Hvj+3l40MkyRQSmZp4S7tVg==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/connection": "^0.13.3",
+        "@xmpp/connection-tcp": "^0.13.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/websocket": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/websocket/-/websocket-0.13.3.tgz",
+      "integrity": "sha512-RXZJFecaAlotqhAdNohO0SoP8Rx3eJrl18c78gxybAhNaCexFbuMJIvSj91L/b8bOErJtFMTwreWeMfzP6Ijiw==",
+      "license": "ISC",
+      "dependencies": {
+        "@xmpp/connection": "^0.13.3",
+        "@xmpp/xml": "^0.13.3",
+        "ws": "^8.18.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/xml": {
+      "version": "0.13.3",
+      "resolved": "https://registry.npmjs.org/@xmpp/xml/-/xml-0.13.3.tgz",
+      "integrity": "sha512-lYXBg/VlpUeavGgQE8LADfZUzMFUnWFVYgvKUcx97AqjiEJUuo40ijdRcGmkAVtTg0RBkml5WB+Mo+JqynMk7Q==",
+      "license": "ISC",
+      "dependencies": {
+        "ltx": "^3.1.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@xmpp/xml/node_modules/ltx": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/ltx/-/ltx-3.1.2.tgz",
+      "integrity": "sha512-tFSKojN92FqNK6eRTmKK/ROUTUYVWKAxgohz523TPhF1G3nR3DXQS/I7/705rEPrDSloKDgMdRlh0qgMFQoVYw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 12.4.0"
+      }
+    },
+    "node_modules/abort-controller": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+      "license": "MIT",
+      "dependencies": {
+        "event-target-shim": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=6.5"
+      }
+    },
+    "node_modules/agentkeepalive": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
+      "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
+      "license": "MIT",
+      "dependencies": {
+        "humanize-ms": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 8.0.0"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "license": "ISC",
+      "optional": true,
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "license": "Python-2.0"
+    },
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+      "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "is-array-buffer": "^3.0.5"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.reduce": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz",
+      "integrity": "sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.9",
+        "es-array-method-boxes-properly": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "is-string": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/arraybuffer.prototype.slice": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+      "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+      "license": "MIT",
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.1",
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "is-array-buffer": "^3.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/async-function": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+      "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+      "license": "MIT",
+      "dependencies": {
+        "possible-typed-array-names": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/babel-plugin-jsx-pragmatic": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jsx-pragmatic/-/babel-plugin-jsx-pragmatic-1.0.2.tgz",
+      "integrity": "sha512-+qeGXSbHZwinZzO6R3wP+6XDKup83Pgg2B3TQt2zwfDdgC7NqT9Kd3ws7iqk53zAO/8iOIRU6VUyUzt2LDE3Eg==",
+      "license": "MIT",
+      "dependencies": {
+        "babel-plugin-syntax-jsx": "^6.0.0"
+      }
+    },
+    "node_modules/babel-plugin-syntax-jsx": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
+      "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
+      "license": "MIT"
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "license": "MIT"
+    },
+    "node_modules/base-64": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
+      "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==",
+      "license": "MIT"
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.9.19",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
+      "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.js"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.28.1",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
+      "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "baseline-browser-mapping": "^2.9.0",
+        "caniuse-lite": "^1.0.30001759",
+        "electron-to-chromium": "^1.5.263",
+        "node-releases": "^2.0.27",
+        "update-browserslist-db": "^1.2.0"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "license": "MIT"
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.0",
+        "es-define-property": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "get-intrinsic": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001767",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz",
+      "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/cipher-base": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz",
+      "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "safe-buffer": "^5.2.1",
+        "to-buffer": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/clone-deep": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+      "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
+      "license": "MIT",
+      "dependencies": {
+        "is-plain-object": "^2.0.4",
+        "kind-of": "^6.0.2",
+        "shallow-clone": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "license": "MIT"
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "license": "MIT"
+    },
+    "node_modules/core-js": {
+      "version": "3.48.0",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz",
+      "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "license": "MIT"
+    },
+    "node_modules/create-hash": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+      "license": "MIT",
+      "dependencies": {
+        "cipher-base": "^1.0.1",
+        "inherits": "^2.0.1",
+        "md5.js": "^1.3.4",
+        "ripemd160": "^2.0.1",
+        "sha.js": "^2.4.0"
+      }
+    },
+    "node_modules/create-hmac": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+      "license": "MIT",
+      "dependencies": {
+        "cipher-base": "^1.0.3",
+        "create-hash": "^1.1.0",
+        "inherits": "^2.0.1",
+        "ripemd160": "^2.0.0",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "node_modules/data-uri-to-buffer": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+      "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/data-view-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+      "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-length": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+      "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/inspect-js"
+      }
+    },
+    "node_modules/data-view-byte-offset": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+      "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.286",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
+      "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
+      "license": "ISC"
+    },
+    "node_modules/es-abstract": {
+      "version": "1.24.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
+      "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==",
+      "license": "MIT",
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.2",
+        "arraybuffer.prototype.slice": "^1.0.4",
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "data-view-buffer": "^1.0.2",
+        "data-view-byte-length": "^1.0.2",
+        "data-view-byte-offset": "^1.0.1",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "es-set-tostringtag": "^2.1.0",
+        "es-to-primitive": "^1.3.0",
+        "function.prototype.name": "^1.1.8",
+        "get-intrinsic": "^1.3.0",
+        "get-proto": "^1.0.1",
+        "get-symbol-description": "^1.1.0",
+        "globalthis": "^1.0.4",
+        "gopd": "^1.2.0",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "internal-slot": "^1.1.0",
+        "is-array-buffer": "^3.0.5",
+        "is-callable": "^1.2.7",
+        "is-data-view": "^1.0.2",
+        "is-negative-zero": "^2.0.3",
+        "is-regex": "^1.2.1",
+        "is-set": "^2.0.3",
+        "is-shared-array-buffer": "^1.0.4",
+        "is-string": "^1.1.1",
+        "is-typed-array": "^1.1.15",
+        "is-weakref": "^1.1.1",
+        "math-intrinsics": "^1.1.0",
+        "object-inspect": "^1.13.4",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.7",
+        "own-keys": "^1.0.1",
+        "regexp.prototype.flags": "^1.5.4",
+        "safe-array-concat": "^1.1.3",
+        "safe-push-apply": "^1.0.0",
+        "safe-regex-test": "^1.1.0",
+        "set-proto": "^1.0.0",
+        "stop-iteration-iterator": "^1.1.0",
+        "string.prototype.trim": "^1.2.10",
+        "string.prototype.trimend": "^1.0.9",
+        "string.prototype.trimstart": "^1.0.8",
+        "typed-array-buffer": "^1.0.3",
+        "typed-array-byte-length": "^1.0.3",
+        "typed-array-byte-offset": "^1.0.4",
+        "typed-array-length": "^1.0.7",
+        "unbox-primitive": "^1.1.0",
+        "which-typed-array": "^1.1.19"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-array-method-boxes-properly": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
+      "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
+      "license": "MIT"
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-to-primitive": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+      "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+      "license": "MIT",
+      "dependencies": {
+        "is-callable": "^1.2.7",
+        "is-date-object": "^1.0.5",
+        "is-symbol": "^1.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/event-target-shim": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
+    "node_modules/fetch-blob": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "paypal",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "node-domexception": "^1.0.0",
+        "web-streams-polyfill": "^3.0.3"
+      },
+      "engines": {
+        "node": "^12.20 || >= 14.13"
+      }
+    },
+    "node_modules/fetch-blob/node_modules/web-streams-polyfill": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
+      "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-cache-dir": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+      "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+      "license": "MIT",
+      "dependencies": {
+        "commondir": "^1.0.1",
+        "make-dir": "^2.0.0",
+        "pkg-dir": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+      "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/for-each": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+      "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-callable": "^1.2.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+      "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "hasown": "^2.0.2",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/form-data-encoder": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
+      "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
+      "license": "MIT"
+    },
+    "node_modules/formdata-node": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
+      "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
+      "license": "MIT",
+      "dependencies": {
+        "node-domexception": "1.0.0",
+        "web-streams-polyfill": "4.0.0-beta.3"
+      },
+      "engines": {
+        "node": ">= 12.20"
+      }
+    },
+    "node_modules/formdata-polyfill": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+      "license": "MIT",
+      "dependencies": {
+        "fetch-blob": "^3.1.2"
+      },
+      "engines": {
+        "node": ">=12.20.0"
+      }
+    },
+    "node_modules/fs-readdir-recursive": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
+      "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==",
+      "license": "MIT"
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "license": "ISC"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/function.prototype.name": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+      "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "functions-have-names": "^1.2.3",
+        "hasown": "^2.0.2",
+        "is-callable": "^1.2.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/generator-function": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+      "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/get-symbol-description": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+      "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "license": "ISC",
+      "optional": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.2.1",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-bigints": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+      "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+      "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hash-base": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz",
+      "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==",
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "readable-stream": "^2.3.8",
+        "safe-buffer": "^5.2.1",
+        "to-buffer": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "license": "MIT",
+      "dependencies": {
+        "parse-passwd": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/humanize-ms": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.0.0"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "license": "ISC"
+    },
+    "node_modules/internal-slot": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+      "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "hasown": "^2.0.2",
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/is-array-buffer": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+      "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-async-function": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+      "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+      "license": "MIT",
+      "dependencies": {
+        "async-function": "^1.0.0",
+        "call-bound": "^1.0.3",
+        "get-proto": "^1.0.1",
+        "has-tostringtag": "^1.0.2",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-bigint": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+      "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "has-bigints": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-boolean-object": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+      "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-callable": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-data-view": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+      "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "get-intrinsic": "^1.2.6",
+        "is-typed-array": "^1.1.13"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-date-object": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+      "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-finalizationregistry": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+      "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-generator-function": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+      "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.4",
+        "generator-function": "^2.0.0",
+        "get-proto": "^1.0.1",
+        "has-tostringtag": "^1.0.2",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-negative-zero": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+      "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-number-object": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+      "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "license": "MIT",
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-regex": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+      "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-set": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-shared-array-buffer": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+      "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-string": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+      "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-symbol": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+      "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-symbols": "^1.1.0",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typed-array": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+      "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+      "license": "MIT",
+      "dependencies": {
+        "which-typed-array": "^1.1.16"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakmap": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakref": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+      "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakset": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+      "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "license": "MIT"
+    },
+    "node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+      "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/koa-compose": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz",
+      "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==",
+      "license": "MIT"
+    },
+    "node_modules/locate-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^3.0.0",
+        "path-exists": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/ltx": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ltx/-/ltx-3.0.0.tgz",
+      "integrity": "sha512-bu3/4/ApUmMqVNuIkHaRhqVtEi6didYcBDIF56xhPRCzVpdztCipZ62CUuaxMlMBUzaVL93+4LZRqe02fuAG6A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 12.4.0"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+      "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+      "license": "MIT",
+      "dependencies": {
+        "pify": "^4.0.1",
+        "semver": "^5.6.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/make-dir/node_modules/semver": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/md5.js": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+      "license": "MIT",
+      "dependencies": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "license": "MIT"
+    },
+    "node_modules/node-domexception": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+      "deprecated": "Use your platform's native DOMException instead",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "github",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.5.0"
+      }
+    },
+    "node_modules/node-environment-flags": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
+      "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "object.getownpropertydescriptors": "^2.0.3",
+        "semver": "^5.7.0"
+      }
+    },
+    "node_modules/node-environment-flags/node_modules/semver": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/node-fetch": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+      "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.27",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+      "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
+      "license": "MIT"
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.assign": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+      "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0",
+        "has-symbols": "^1.1.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.getownpropertydescriptors": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.9.tgz",
+      "integrity": "sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g==",
+      "license": "MIT",
+      "dependencies": {
+        "array.prototype.reduce": "^1.0.8",
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.24.0",
+        "es-object-atoms": "^1.1.1",
+        "gopd": "^1.2.0",
+        "safe-array-concat": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/openai": {
+      "version": "4.104.0",
+      "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz",
+      "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/node": "^18.11.18",
+        "@types/node-fetch": "^2.6.4",
+        "abort-controller": "^3.0.0",
+        "agentkeepalive": "^4.2.1",
+        "form-data-encoder": "1.7.2",
+        "formdata-node": "^4.3.2",
+        "node-fetch": "^2.6.7"
+      },
+      "bin": {
+        "openai": "bin/cli"
+      },
+      "peerDependencies": {
+        "ws": "^8.18.0",
+        "zod": "^3.23.8"
+      },
+      "peerDependenciesMeta": {
+        "ws": {
+          "optional": true
+        },
+        "zod": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/openai/node_modules/@types/node": {
+      "version": "18.19.130",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
+      "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/openai/node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "license": "MIT"
+    },
+    "node_modules/own-keys": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+      "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+      "license": "MIT",
+      "dependencies": {
+        "get-intrinsic": "^1.2.6",
+        "object-keys": "^1.1.1",
+        "safe-push-apply": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+      "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+      "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+      "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+      "license": "MIT",
+      "dependencies": {
+        "find-up": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/possible-typed-array-names": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+      "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "license": "MIT"
+    },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "license": "MIT",
+      "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"
+      }
+    },
+    "node_modules/readable-stream/node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "license": "MIT"
+    },
+    "node_modules/readable-stream/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "license": "MIT"
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/reflect.getprototypeof": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+      "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.9",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.7",
+        "get-proto": "^1.0.1",
+        "which-builtin-type": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+      "license": "MIT"
+    },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+      "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-errors": "^1.3.0",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "set-function-name": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/ripemd160": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz",
+      "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==",
+      "license": "MIT",
+      "dependencies": {
+        "hash-base": "^3.1.2",
+        "inherits": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/safe-array-concat": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+      "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "get-intrinsic": "^1.2.6",
+        "has-symbols": "^1.1.0",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">=0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/safe-push-apply": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+      "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safe-regex-test": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+      "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-regex": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/sasl-anonymous": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/sasl-anonymous/-/sasl-anonymous-0.1.0.tgz",
+      "integrity": "sha512-x+0sdsV0Gie2EexxAUsx6ZoB+X6OCthlNBvAQncQxreEWQJByAPntj0EAgTlJc2kZicoc+yFzeR6cl8VfsQGfA==",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/sasl-plain": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/sasl-plain/-/sasl-plain-0.1.0.tgz",
+      "integrity": "sha512-X8mCSfR8y0NryTu0tuVyr4IS2jBunBgyG+3a0gEEkd0nlHGiyqJhlc4EIkzmSwaa7F8S4yo+LS6Cu5qxRkJrmg==",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/sasl-scram-sha-1": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/sasl-scram-sha-1/-/sasl-scram-sha-1-1.3.0.tgz",
+      "integrity": "sha512-hJE3eUCEx0aK+9jwHu6VVrQwb9qxv8RMc3ZciGF/ZzXgxptCX9QbfJT45nloJGxrR9AfBU6GiVNYKA5mrqu2KQ==",
+      "license": "MIT",
+      "dependencies": {
+        "create-hash": "^1.1.0",
+        "create-hmac": "^1.1.3",
+        "randombytes": "^2.0.1"
+      }
+    },
+    "node_modules/saslmechanisms": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/saslmechanisms/-/saslmechanisms-0.1.1.tgz",
+      "integrity": "sha512-pVlvK5ysevz8MzybRnDIa2YMxn0OJ7b9lDiWhMoaKPoJ7YkAg/7YtNjUgaYzElkwHxsw8dBMhaEn7UP6zxEwPg==",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-function-name": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-proto": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+      "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/sha.js": {
+      "version": "2.4.12",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz",
+      "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==",
+      "license": "(MIT AND BSD-3-Clause)",
+      "dependencies": {
+        "inherits": "^2.0.4",
+        "safe-buffer": "^5.2.1",
+        "to-buffer": "^1.2.0"
+      },
+      "bin": {
+        "sha.js": "bin.js"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+      "license": "MIT",
+      "dependencies": {
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3",
+        "side-channel-list": "^1.0.0",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/stop-iteration-iterator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+      "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "internal-slot": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/string_decoder/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "license": "MIT"
+    },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.10",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+      "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "define-data-property": "^1.1.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-object-atoms": "^1.0.0",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimend": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+      "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimstart": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/to-buffer": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz",
+      "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==",
+      "license": "MIT",
+      "dependencies": {
+        "isarray": "^2.0.5",
+        "safe-buffer": "^5.2.1",
+        "typed-array-buffer": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "license": "MIT"
+    },
+    "node_modules/typed-array-buffer": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+      "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/typed-array-byte-length": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+      "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-proto": "^1.2.0",
+        "is-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-byte-offset": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+      "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-proto": "^1.2.0",
+        "is-typed-array": "^1.1.15",
+        "reflect.getprototypeof": "^1.0.9"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-length": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+      "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "is-typed-array": "^1.1.13",
+        "possible-typed-array-names": "^1.0.0",
+        "reflect.getprototypeof": "^1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.9.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/unbox-primitive": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+      "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.1.0",
+        "which-boxed-primitive": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+      "license": "MIT"
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "license": "MIT"
+    },
+    "node_modules/v8flags": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
+      "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==",
+      "license": "MIT",
+      "dependencies": {
+        "homedir-polyfill": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/web-streams-polyfill": {
+      "version": "4.0.0-beta.3",
+      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
+      "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/which-boxed-primitive": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+      "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+      "license": "MIT",
+      "dependencies": {
+        "is-bigint": "^1.1.0",
+        "is-boolean-object": "^1.2.1",
+        "is-number-object": "^1.1.1",
+        "is-string": "^1.1.1",
+        "is-symbol": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-builtin-type": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+      "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "function.prototype.name": "^1.1.6",
+        "has-tostringtag": "^1.0.2",
+        "is-async-function": "^2.0.0",
+        "is-date-object": "^1.1.0",
+        "is-finalizationregistry": "^1.1.0",
+        "is-generator-function": "^1.0.10",
+        "is-regex": "^1.2.1",
+        "is-weakref": "^1.0.2",
+        "isarray": "^2.0.5",
+        "which-boxed-primitive": "^1.1.0",
+        "which-collection": "^1.0.2",
+        "which-typed-array": "^1.1.16"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-collection": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+      "license": "MIT",
+      "dependencies": {
+        "is-map": "^2.0.3",
+        "is-set": "^2.0.3",
+        "is-weakmap": "^2.0.2",
+        "is-weakset": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-typed-array": {
+      "version": "1.1.20",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
+      "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
+      "license": "MIT",
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "for-each": "^0.3.5",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "license": "ISC"
+    },
+    "node_modules/ws": {
+      "version": "8.19.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
+      "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "license": "ISC"
+    }
+  }
+}
package.json
@@ -0,0 +1,28 @@
+{
+  "name": "daneel",
+  "version": "0.1.0",
+  "description": "XMPP research bot using Pi AI toolkit",
+  "type": "module",
+  "main": "dist/main.js",
+  "scripts": {
+    "build": "tsc",
+    "dev": "tsc --watch",
+    "start": "node dist/main.js"
+  },
+  "dependencies": {
+    "@xmpp/client": "^0.13.1",
+    "@xmpp/debug": "^0.13.0",
+    "@anthropic-ai/sdk": "^0.39.0",
+    "@google/generative-ai": "^0.21.0",
+    "openai": "^4.77.0",
+    "@sinclair/typebox": "^0.32.0",
+    "js-yaml": "^4.1.0"
+  },
+  "devDependencies": {
+    "@types/node": "^20.0.0",
+    "@types/js-yaml": "^4.0.9",
+    "typescript": "^5.3.0"
+  },
+  "author": "Vincent Demeester",
+  "license": "Apache-2.0"
+}
README.md
@@ -0,0 +1,137 @@
+# Daneel
+
+XMPP research bot named after R. Daneel Olivaw from Isaac Asimov's Robot/Foundation series.
+
+## Features
+
+- Multi-provider LLM support (Anthropic, Google, OpenAI, Ollama, Groq, Mistral)
+- Model selection via message prefixes (`opus:`, `gemini:`, `llama:`, etc.)
+- Per-user session persistence (JSONL)
+- Tool calling for research, org-mode saving, and system status
+- NixOS service module
+
+## Quick Start
+
+```bash
+# Install dependencies
+npm install
+
+# Build
+npm run build
+
+# Run (with environment variables)
+DANEEL_XMPP_JID="bot@xmpp.example.com" \
+DANEEL_XMPP_PASSWORD="password" \
+DANEEL_OWNER_JID="owner@xmpp.example.com" \
+ANTHROPIC_API_KEY="sk-..." \
+npm start
+```
+
+## Environment Variables
+
+### Required
+
+| Variable | Description |
+|----------|-------------|
+| `DANEEL_XMPP_JID` | Bot's XMPP JID |
+| `DANEEL_XMPP_PASSWORD` | Bot's XMPP password |
+| `DANEEL_OWNER_JID` | Owner's JID (only this user can interact) |
+
+### Optional
+
+| Variable | Description | Default |
+|----------|-------------|---------|
+| `DANEEL_DATA_DIR` | Session storage directory | `./data` |
+| `DANEEL_INBOX_PATH` | Org-mode inbox path | `~/org/inbox.org` |
+| `DANEEL_DEFAULT_MODEL` | Default model alias | `sonnet` |
+| `DANEEL_DEBUG` | Enable debug logging | `false` |
+
+### Provider API Keys
+
+| Variable | Provider |
+|----------|----------|
+| `ANTHROPIC_API_KEY` | Anthropic (Claude) |
+| `GOOGLE_API_KEY` | Google (Gemini) |
+| `OPENAI_API_KEY` | OpenAI (GPT-4) |
+| `GITHUB_TOKEN` | GitHub Copilot |
+| `OLLAMA_BASE_URL` | Ollama (local) |
+| `GROQ_API_KEY` | Groq |
+| `MISTRAL_API_KEY` | Mistral |
+| `OPENROUTER_API_KEY` | OpenRouter |
+
+## Usage
+
+### Commands
+
+- `/help` - Show help message
+- `/ping` - Check if bot is alive
+- `/status` - Show system status
+- `/clear` - Clear conversation history
+- `/models` - List available models
+- `/stats` - Show session statistics
+
+### Model Prefixes
+
+Prefix your message to use a specific model:
+
+```
+opus: What is quantum entanglement?
+gemini: Summarize the latest AI news
+llama: Explain this concept simply
+```
+
+#### Available Prefixes
+
+| Prefix | Provider | Model |
+|--------|----------|-------|
+| `opus:`, `o:` | Anthropic | Claude Opus 4.5 |
+| `sonnet:`, `s:` | Anthropic | Claude Sonnet 4.5 |
+| `haiku:`, `h:` | Anthropic | Claude Haiku |
+| `gemini:`, `g:` | Google | Gemini 2.0 Flash |
+| `gemini-pro:`, `gp:` | Google | Gemini 2.5 Pro |
+| `gpt:`, `gpt4:` | OpenAI | GPT-4o |
+| `o1:` | OpenAI | O1 |
+| `o3:` | OpenAI | O3 Mini |
+| `copilot:`, `cp:` | GitHub | GPT-4o via Copilot |
+| `copilot-claude:` | GitHub | Claude via Copilot |
+| `ollama:`, `llama:` | Ollama | Llama 3.2 |
+| `qwen:` | Ollama | Qwen 2.5 |
+| `deepseek:` | Ollama | DeepSeek R1 |
+| `groq:` | Groq | Llama 3.3 70B |
+| `mistral:` | Mistral | Mistral Large |
+
+## NixOS Integration
+
+```nix
+{
+  imports = [ ./path/to/daneel/nix/module.nix ];
+
+  services.daneel = {
+    enable = true;
+    xmppJid = "daneel@xmpp.example.com";
+    xmppPasswordFile = config.age.secrets.daneel-xmpp.path;
+    ownerJid = "owner@xmpp.example.com";
+    anthropicApiKeyFile = config.age.secrets.anthropic-api.path;
+  };
+}
+```
+
+## Architecture
+
+```
+┌─────────────────────────────────────────────────────────┐
+│                        Daneel                            │
+├─────────────────────────────────────────────────────────┤
+│  @xmpp/client  →  SessionManager  →  AgentRunner        │
+│       │              (per-JID)         (LLM provider)   │
+│       ↓                  ↓                   ↓          │
+│  Message Router → context.jsonl → Tool Execution        │
+│                                                         │
+│  Tools: research, save_to_org, status, web_search       │
+│  LLMs:  Claude, Gemini, GPT-4, Llama, etc.              │
+└─────────────────────────────────────────────────────────┘
+```
+
+## License
+
+Apache-2.0
tsconfig.json
@@ -0,0 +1,15 @@
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "NodeNext",
+    "moduleResolution": "NodeNext",
+    "esModuleInterop": true,
+    "strict": true,
+    "outDir": "dist",
+    "rootDir": "src",
+    "declaration": true,
+    "sourceMap": true,
+    "skipLibCheck": true
+  },
+  "include": ["src/**/*"]
+}