@jcheesepkg/nanobot 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.mts","names":[],"sources":["../../src/agent/skills.ts"],"mappings":";UAWU,SAAA;EACR,IAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,UAGQ,SAAA;EACR,WAAA;EACA,MAAA;EACA,QAAA;EAAA,CACC,GAAA;AAAA;;;;;cAOU,YAAA;EAAA,QACH,SAAA;EAAA,QACA,eAAA;EAAA,QACA,aAAA;cAEI,SAAA,UAAmB,gBAAA;EALpB;EAYX,UAAA,CAAW,iBAAA,aAA2B,SAAA;;EAsCtC,SAAA,CAAU,IAAA;EAjDF;EAgER,oBAAA,CAAqB,UAAA;EA9Db;EA2ER,kBAAA,CAAA;EAzEY;EA0GZ,eAAA,CAAA;EAnGA;EAgHA,gBAAA,CAAiB,IAAA,WAAe,SAAA;EAAA,QAsBxB,gBAAA;EAAA,QAQA,oBAAA;EAAA,QAWA,iBAAA;EAAA,QAWA,YAAA;EAAA,QAKA,mBAAA;EAAA,QAKA,sBAAA;AAAA"}
1
+ {"version":3,"file":"skills.d.mts","names":[],"sources":["../../src/agent/skills.ts"],"mappings":";UAeU,SAAA;EACR,IAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,UAGQ,SAAA;EACR,WAAA;EACA,MAAA;EACA,QAAA;EAAA,CACC,GAAA;AAAA;;;;;cAOU,YAAA;EAAA,QACH,SAAA;EAAA,QACA,eAAA;EAAA,QACA,aAAA;cAEI,SAAA,UAAmB,gBAAA;EALpB;EAYX,UAAA,CAAW,iBAAA,aAA2B,SAAA;;EAsCtC,SAAA,CAAU,IAAA;EAjDF;EAgER,oBAAA,CAAqB,UAAA;EA9Db;EA2ER,kBAAA,CAAA;EAzEY;EA0GZ,eAAA,CAAA;EAnGA;EAgHA,gBAAA,CAAiB,IAAA,WAAe,SAAA;EAAA,QAsBxB,gBAAA;EAAA,QAQA,oBAAA;EAAA,QAWA,iBAAA;EAAA,QAWA,YAAA;EAAA,QAKA,mBAAA;EAAA,QAKA,sBAAA;AAAA"}
@@ -1,8 +1,10 @@
1
1
  import { which } from "../utils/which.mjs";
2
2
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
4
5
 
5
6
  //#region src/agent/skills.ts
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
8
  /** Default builtin skills directory (relative to this file in dist). */
7
9
  function getBuiltinSkillsDir() {
8
10
  return join(dirname(dirname(__dirname)), "skills");
@@ -1 +1 @@
1
- {"version":3,"file":"skills.mjs","names":[],"sources":["../../src/agent/skills.ts"],"sourcesContent":["import { readFileSync, existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { which } from \"../utils/which.js\";\n\n/** Default builtin skills directory (relative to this file in dist). */\nfunction getBuiltinSkillsDir(): string {\n // In dist: dist/agent/skills.js -> ../../skills\n // In src: src/agent/skills.ts -> ../../skills\n return join(dirname(dirname(__dirname)), \"skills\");\n}\n\ninterface SkillInfo {\n name: string;\n path: string;\n source: \"workspace\" | \"builtin\";\n}\n\ninterface SkillMeta {\n description?: string;\n always?: string;\n metadata?: string;\n [key: string]: string | undefined;\n}\n\n/**\n * Loader for agent skills.\n * Skills are markdown files (SKILL.md) that teach the agent specific capabilities.\n */\nexport class SkillsLoader {\n private workspace: string;\n private workspaceSkills: string;\n private builtinSkills: string;\n\n constructor(workspace: string, builtinSkillsDir?: string) {\n this.workspace = workspace;\n this.workspaceSkills = join(workspace, \"skills\");\n this.builtinSkills = builtinSkillsDir ?? getBuiltinSkillsDir();\n }\n\n /** List all available skills. */\n listSkills(filterUnavailable = true): SkillInfo[] {\n const skills: SkillInfo[] = [];\n\n // Workspace skills (highest priority)\n if (existsSync(this.workspaceSkills)) {\n for (const entry of readdirSync(this.workspaceSkills)) {\n const skillDir = join(this.workspaceSkills, entry);\n const skillFile = join(skillDir, \"SKILL.md\");\n if (statSync(skillDir).isDirectory() && existsSync(skillFile)) {\n skills.push({ name: entry, path: skillFile, source: \"workspace\" });\n }\n }\n }\n\n // Built-in skills\n if (existsSync(this.builtinSkills)) {\n for (const entry of readdirSync(this.builtinSkills)) {\n const skillDir = join(this.builtinSkills, entry);\n const skillFile = join(skillDir, \"SKILL.md\");\n if (\n statSync(skillDir).isDirectory() &&\n existsSync(skillFile) &&\n !skills.some((s) => s.name === entry)\n ) {\n skills.push({ name: entry, path: skillFile, source: \"builtin\" });\n }\n }\n }\n\n if (filterUnavailable) {\n return skills.filter((s) =>\n this.checkRequirements(this.getSkillMeta(s.name)),\n );\n }\n return skills;\n }\n\n /** Load a skill by name. */\n loadSkill(name: string): string | null {\n const wsSkill = join(this.workspaceSkills, name, \"SKILL.md\");\n if (existsSync(wsSkill)) {\n return readFileSync(wsSkill, \"utf-8\");\n }\n\n const builtinSkill = join(this.builtinSkills, name, \"SKILL.md\");\n if (existsSync(builtinSkill)) {\n return readFileSync(builtinSkill, \"utf-8\");\n }\n\n return null;\n }\n\n /** Load specific skills for inclusion in agent context. */\n loadSkillsForContext(skillNames: string[]): string {\n const parts: string[] = [];\n for (const name of skillNames) {\n const content = this.loadSkill(name);\n if (content) {\n const stripped = this.stripFrontmatter(content);\n parts.push(`### Skill: ${name}\\n\\n${stripped}`);\n }\n }\n return parts.join(\"\\n\\n---\\n\\n\");\n }\n\n /** Build a summary of all skills. */\n buildSkillsSummary(): string {\n const allSkills = this.listSkills(false);\n if (allSkills.length === 0) return \"\";\n\n const escapeXml = (s: string) =>\n s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\n const lines = [\"<skills>\"];\n for (const s of allSkills) {\n const name = escapeXml(s.name);\n const desc = escapeXml(this.getSkillDescription(s.name));\n const meta = this.getSkillMeta(s.name);\n const available = this.checkRequirements(meta);\n\n lines.push(` <skill available=\"${available}\">`);\n lines.push(` <name>${name}</name>`);\n lines.push(` <description>${desc}</description>`);\n lines.push(` <location>${s.path}</location>`);\n\n if (!available) {\n const missing = this.getMissingRequirements(meta);\n if (missing) {\n lines.push(` <requires>${escapeXml(missing)}</requires>`);\n }\n }\n\n lines.push(\" </skill>\");\n }\n lines.push(\"</skills>\");\n return lines.join(\"\\n\");\n }\n\n /** Get skills marked as always=true. */\n getAlwaysSkills(): string[] {\n const result: string[] = [];\n for (const s of this.listSkills(true)) {\n const meta = this.getSkillMetadata(s.name);\n const skillMeta = this.parseNanobotMetadata(meta?.metadata ?? \"\");\n if (skillMeta.always || meta?.always) {\n result.push(s.name);\n }\n }\n return result;\n }\n\n /** Get metadata from a skill's frontmatter. */\n getSkillMetadata(name: string): SkillMeta | null {\n const content = this.loadSkill(name);\n if (!content) return null;\n\n if (content.startsWith(\"---\")) {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (match) {\n const metadata: SkillMeta = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx !== -1) {\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim().replace(/^[\"']|[\"']$/g, \"\");\n metadata[key] = value;\n }\n }\n return metadata;\n }\n }\n return null;\n }\n\n private stripFrontmatter(content: string): string {\n if (content.startsWith(\"---\")) {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n/);\n if (match) return content.slice(match[0].length).trim();\n }\n return content;\n }\n\n private parseNanobotMetadata(raw: string): Record<string, unknown> {\n try {\n const data = JSON.parse(raw);\n return typeof data === \"object\" && data !== null\n ? (data.nanobot ?? {})\n : {};\n } catch {\n return {};\n }\n }\n\n private checkRequirements(meta: Record<string, unknown>): boolean {\n const requires = (meta.requires ?? {}) as Record<string, string[]>;\n for (const bin of requires.bins ?? []) {\n if (!which(bin)) return false;\n }\n for (const env of requires.env ?? []) {\n if (!process.env[env]) return false;\n }\n return true;\n }\n\n private getSkillMeta(name: string): Record<string, unknown> {\n const meta = this.getSkillMetadata(name) ?? {};\n return this.parseNanobotMetadata(String(meta.metadata ?? \"\"));\n }\n\n private getSkillDescription(name: string): string {\n const meta = this.getSkillMetadata(name);\n return meta?.description ?? name;\n }\n\n private getMissingRequirements(meta: Record<string, unknown>): string {\n const missing: string[] = [];\n const requires = (meta.requires ?? {}) as Record<string, string[]>;\n for (const bin of requires.bins ?? []) {\n if (!which(bin)) missing.push(`CLI: ${bin}`);\n }\n for (const env of requires.env ?? []) {\n if (!process.env[env]) missing.push(`ENV: ${env}`);\n }\n return missing.join(\", \");\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skills.mjs","names":[],"sources":["../../src/agent/skills.ts"],"sourcesContent":["import { readFileSync, existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { which } from \"../utils/which.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/** Default builtin skills directory (relative to this file in dist). */\nfunction getBuiltinSkillsDir(): string {\n // In dist: dist/agent/skills.js -> ../../skills\n // In src: src/agent/skills.ts -> ../../skills\n return join(dirname(dirname(__dirname)), \"skills\");\n}\n\ninterface SkillInfo {\n name: string;\n path: string;\n source: \"workspace\" | \"builtin\";\n}\n\ninterface SkillMeta {\n description?: string;\n always?: string;\n metadata?: string;\n [key: string]: string | undefined;\n}\n\n/**\n * Loader for agent skills.\n * Skills are markdown files (SKILL.md) that teach the agent specific capabilities.\n */\nexport class SkillsLoader {\n private workspace: string;\n private workspaceSkills: string;\n private builtinSkills: string;\n\n constructor(workspace: string, builtinSkillsDir?: string) {\n this.workspace = workspace;\n this.workspaceSkills = join(workspace, \"skills\");\n this.builtinSkills = builtinSkillsDir ?? getBuiltinSkillsDir();\n }\n\n /** List all available skills. */\n listSkills(filterUnavailable = true): SkillInfo[] {\n const skills: SkillInfo[] = [];\n\n // Workspace skills (highest priority)\n if (existsSync(this.workspaceSkills)) {\n for (const entry of readdirSync(this.workspaceSkills)) {\n const skillDir = join(this.workspaceSkills, entry);\n const skillFile = join(skillDir, \"SKILL.md\");\n if (statSync(skillDir).isDirectory() && existsSync(skillFile)) {\n skills.push({ name: entry, path: skillFile, source: \"workspace\" });\n }\n }\n }\n\n // Built-in skills\n if (existsSync(this.builtinSkills)) {\n for (const entry of readdirSync(this.builtinSkills)) {\n const skillDir = join(this.builtinSkills, entry);\n const skillFile = join(skillDir, \"SKILL.md\");\n if (\n statSync(skillDir).isDirectory() &&\n existsSync(skillFile) &&\n !skills.some((s) => s.name === entry)\n ) {\n skills.push({ name: entry, path: skillFile, source: \"builtin\" });\n }\n }\n }\n\n if (filterUnavailable) {\n return skills.filter((s) =>\n this.checkRequirements(this.getSkillMeta(s.name)),\n );\n }\n return skills;\n }\n\n /** Load a skill by name. */\n loadSkill(name: string): string | null {\n const wsSkill = join(this.workspaceSkills, name, \"SKILL.md\");\n if (existsSync(wsSkill)) {\n return readFileSync(wsSkill, \"utf-8\");\n }\n\n const builtinSkill = join(this.builtinSkills, name, \"SKILL.md\");\n if (existsSync(builtinSkill)) {\n return readFileSync(builtinSkill, \"utf-8\");\n }\n\n return null;\n }\n\n /** Load specific skills for inclusion in agent context. */\n loadSkillsForContext(skillNames: string[]): string {\n const parts: string[] = [];\n for (const name of skillNames) {\n const content = this.loadSkill(name);\n if (content) {\n const stripped = this.stripFrontmatter(content);\n parts.push(`### Skill: ${name}\\n\\n${stripped}`);\n }\n }\n return parts.join(\"\\n\\n---\\n\\n\");\n }\n\n /** Build a summary of all skills. */\n buildSkillsSummary(): string {\n const allSkills = this.listSkills(false);\n if (allSkills.length === 0) return \"\";\n\n const escapeXml = (s: string) =>\n s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\n const lines = [\"<skills>\"];\n for (const s of allSkills) {\n const name = escapeXml(s.name);\n const desc = escapeXml(this.getSkillDescription(s.name));\n const meta = this.getSkillMeta(s.name);\n const available = this.checkRequirements(meta);\n\n lines.push(` <skill available=\"${available}\">`);\n lines.push(` <name>${name}</name>`);\n lines.push(` <description>${desc}</description>`);\n lines.push(` <location>${s.path}</location>`);\n\n if (!available) {\n const missing = this.getMissingRequirements(meta);\n if (missing) {\n lines.push(` <requires>${escapeXml(missing)}</requires>`);\n }\n }\n\n lines.push(\" </skill>\");\n }\n lines.push(\"</skills>\");\n return lines.join(\"\\n\");\n }\n\n /** Get skills marked as always=true. */\n getAlwaysSkills(): string[] {\n const result: string[] = [];\n for (const s of this.listSkills(true)) {\n const meta = this.getSkillMetadata(s.name);\n const skillMeta = this.parseNanobotMetadata(meta?.metadata ?? \"\");\n if (skillMeta.always || meta?.always) {\n result.push(s.name);\n }\n }\n return result;\n }\n\n /** Get metadata from a skill's frontmatter. */\n getSkillMetadata(name: string): SkillMeta | null {\n const content = this.loadSkill(name);\n if (!content) return null;\n\n if (content.startsWith(\"---\")) {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (match) {\n const metadata: SkillMeta = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx !== -1) {\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim().replace(/^[\"']|[\"']$/g, \"\");\n metadata[key] = value;\n }\n }\n return metadata;\n }\n }\n return null;\n }\n\n private stripFrontmatter(content: string): string {\n if (content.startsWith(\"---\")) {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n/);\n if (match) return content.slice(match[0].length).trim();\n }\n return content;\n }\n\n private parseNanobotMetadata(raw: string): Record<string, unknown> {\n try {\n const data = JSON.parse(raw);\n return typeof data === \"object\" && data !== null\n ? (data.nanobot ?? {})\n : {};\n } catch {\n return {};\n }\n }\n\n private checkRequirements(meta: Record<string, unknown>): boolean {\n const requires = (meta.requires ?? {}) as Record<string, string[]>;\n for (const bin of requires.bins ?? []) {\n if (!which(bin)) return false;\n }\n for (const env of requires.env ?? []) {\n if (!process.env[env]) return false;\n }\n return true;\n }\n\n private getSkillMeta(name: string): Record<string, unknown> {\n const meta = this.getSkillMetadata(name) ?? {};\n return this.parseNanobotMetadata(String(meta.metadata ?? \"\"));\n }\n\n private getSkillDescription(name: string): string {\n const meta = this.getSkillMetadata(name);\n return meta?.description ?? name;\n }\n\n private getMissingRequirements(meta: Record<string, unknown>): string {\n const missing: string[] = [];\n const requires = (meta.requires ?? {}) as Record<string, string[]>;\n for (const bin of requires.bins ?? []) {\n if (!which(bin)) missing.push(`CLI: ${bin}`);\n }\n for (const env of requires.env ?? []) {\n if (!process.env[env]) missing.push(`ENV: ${env}`);\n }\n return missing.join(\", \");\n }\n}\n"],"mappings":"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"}
@@ -323,11 +323,13 @@ program.command("status").description("Show nanobot status").action(() => {
323
323
  const hasOpenai = Boolean(config.providers.openai.apiKey);
324
324
  const hasGemini = Boolean(config.providers.gemini.apiKey);
325
325
  const hasDeepseek = Boolean(config.providers.deepseek.apiKey);
326
+ const hasOpenaiCompatible = Boolean(config.providers.openaiCompatible.apiKey);
326
327
  console.log(`OpenRouter API: ${hasOpenrouter ? "[set]" : "[not set]"}`);
327
328
  console.log(`Anthropic API: ${hasAnthropic ? "[set]" : "[not set]"}`);
328
329
  console.log(`OpenAI API: ${hasOpenai ? "[set]" : "[not set]"}`);
329
330
  console.log(`Gemini API: ${hasGemini ? "[set]" : "[not set]"}`);
330
331
  console.log(`DeepSeek API: ${hasDeepseek ? "[set]" : "[not set]"}`);
332
+ console.log(`OpenAI Compatible API: ${hasOpenaiCompatible ? "[set]" : "[not set]"}`);
331
333
  }
332
334
  });
333
335
  program.parse();
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * nanobot CLI - Personal AI Assistant\n */\n\nimport { Command } from \"commander\";\nimport { existsSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { VERSION, LOGO } from \"../index.js\";\nimport { loadConfig, saveConfig } from \"../config/loader.js\";\nimport { getConfigPath, getDataDir } from \"../config/loader.js\";\nimport {\n ConfigSchema,\n getConfigWorkspacePath,\n getApiKey,\n getApiBase,\n} from \"../config/schema.js\";\nimport type { Config } from \"../config/schema.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"nanobot\")\n .description(`${LOGO} nanobot - Personal AI Assistant`)\n .version(`${LOGO} nanobot v${VERSION}`, \"-v, --version\");\n\n// ============================================================================\n// Onboard / Setup\n// ============================================================================\n\nprogram\n .command(\"onboard\")\n .description(\"Initialize nanobot configuration and workspace\")\n .action(() => {\n const configPath = getConfigPath();\n\n if (existsSync(configPath)) {\n console.log(`Config already exists at ${configPath}`);\n console.log(\"Delete it first if you want to start fresh.\");\n return;\n }\n\n // Create default config\n const config = ConfigSchema.parse({});\n saveConfig(config);\n console.log(`Created config at ${configPath}`);\n\n // Create workspace\n const workspace = getConfigWorkspacePath(config);\n createWorkspaceTemplates(workspace);\n\n console.log(`\\n${LOGO} nanobot is ready!`);\n console.log(\"\\nNext steps:\");\n console.log(\" 1. Add your API key to ~/.nanobot/config.json\");\n console.log(\" Get one at: https://openrouter.ai/keys\");\n console.log(' 2. Chat: nanobot agent -m \"Hello!\"');\n console.log(\n \"\\nWant Telegram? See: https://github.com/HKUDS/nanobot#-chat-apps\",\n );\n });\n\nfunction createWorkspaceTemplates(workspace: string): void {\n if (!existsSync(workspace)) {\n mkdirSync(workspace, { recursive: true });\n }\n\n const templates: Record<string, string> = {\n \"AGENTS.md\": `# Agent Instructions\n\nYou are a helpful AI assistant. Be concise, accurate, and friendly.\n\n## Guidelines\n\n- Always explain what you're doing before taking actions\n- Ask for clarification when the request is ambiguous\n- Use tools to help accomplish tasks\n- Remember important information in your memory files\n`,\n \"SOUL.md\": `# Soul\n\nI am nanobot, a lightweight AI assistant.\n\n## Personality\n\n- Helpful and friendly\n- Concise and to the point\n- Curious and eager to learn\n\n## Values\n\n- Accuracy over speed\n- User privacy and safety\n- Transparency in actions\n`,\n \"USER.md\": `# User\n\nInformation about the user goes here.\n\n## Preferences\n\n- Communication style: (casual/formal)\n- Timezone: (your timezone)\n- Language: (your preferred language)\n`,\n };\n\n for (const [filename, content] of Object.entries(templates)) {\n const filePath = join(workspace, filename);\n if (!existsSync(filePath)) {\n writeFileSync(filePath, content);\n console.log(` Created ${filename}`);\n }\n }\n\n // Create memory directory and MEMORY.md\n const memoryDir = join(workspace, \"memory\");\n if (!existsSync(memoryDir)) {\n mkdirSync(memoryDir, { recursive: true });\n }\n const memoryFile = join(memoryDir, \"MEMORY.md\");\n if (!existsSync(memoryFile)) {\n writeFileSync(\n memoryFile,\n `# Long-term Memory\n\nThis file stores important information that should persist across sessions.\n\n## User Information\n\n(Important facts about the user)\n\n## Preferences\n\n(User preferences learned over time)\n\n## Important Notes\n\n(Things to remember)\n`,\n );\n console.log(\" Created memory/MEMORY.md\");\n }\n}\n\n// ============================================================================\n// Gateway / Server\n// ============================================================================\n\nprogram\n .command(\"gateway\")\n .description(\"Start the nanobot gateway\")\n .option(\"-p, --port <number>\", \"Gateway port\", \"18790\")\n .option(\"--verbose\", \"Verbose output\", false)\n .action(async (opts) => {\n console.log(\n `${LOGO} Starting nanobot gateway on port ${opts.port}...`,\n );\n\n const config = loadConfig();\n const apiKey = getApiKey(config);\n const apiBase = getApiBase(config);\n const model = config.agents.defaults.model;\n\n if (!apiKey) {\n console.error(\"Error: No API key configured.\");\n console.error(\n \"Set one in ~/.nanobot/config.json under providers.openrouter.apiKey\",\n );\n process.exit(1);\n }\n\n // Dynamic imports to avoid loading heavy deps up front\n const { MessageBus } = await import(\"../bus/queue.js\");\n const { OpenAIProvider } = await import(\n \"../providers/openai-provider.js\"\n );\n const { AgentLoop } = await import(\"../agent/loop.js\");\n const { ChannelManager } = await import(\"../channels/manager.js\");\n const { CronService } = await import(\"../cron/service.js\");\n const { HeartbeatService } = await import(\n \"../heartbeat/service.js\"\n );\n\n const bus = new MessageBus();\n const workspace = getConfigWorkspacePath(config);\n\n const provider = new OpenAIProvider({\n apiKey,\n apiBase: apiBase ?? undefined,\n defaultModel: model,\n });\n\n // Create cron service\n const cronStorePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const cron = new CronService(cronStorePath);\n\n // Create agent\n const agent = new AgentLoop({\n bus,\n provider,\n workspace,\n model,\n maxIterations: config.agents.defaults.maxToolIterations,\n braveApiKey: config.tools.web.search.apiKey || undefined,\n execConfig: config.tools.exec,\n cronService: cron,\n });\n\n // Wire cron callback\n cron.onJob = async (job) => {\n const response = await agent.processDirect(\n job.payload.message,\n `cron:${job.id}`,\n job.payload.channel ?? \"cli\",\n job.payload.to ?? \"direct\",\n );\n\n if (job.payload.deliver && job.payload.to) {\n const { createOutboundMessage } = await import(\n \"../bus/events.js\"\n );\n await bus.publishOutbound(\n createOutboundMessage({\n channel: job.payload.channel ?? \"cli\",\n chatId: job.payload.to,\n content: response ?? \"\",\n }),\n );\n }\n return response;\n };\n\n // Create heartbeat\n const heartbeat = new HeartbeatService({\n workspace,\n onHeartbeat: (prompt) =>\n agent.processDirect(prompt, \"heartbeat\"),\n intervalS: 30 * 60,\n enabled: true,\n });\n\n // Create channel manager\n const channels = new ChannelManager(config, bus);\n\n if (channels.enabledChannels.length > 0) {\n console.log(\n `Channels enabled: ${channels.enabledChannels.join(\", \")}`,\n );\n } else {\n console.log(\"Warning: No channels enabled\");\n }\n\n const cronStatus = cron.status();\n if (cronStatus.jobs > 0) {\n console.log(`Cron: ${cronStatus.jobs} scheduled jobs`);\n }\n console.log(\"Heartbeat: every 30m\");\n\n // Handle graceful shutdown\n const shutdown = async () => {\n console.log(\"\\nShutting down...\");\n heartbeat.stop();\n cron.stop();\n agent.stop();\n await channels.stopAll();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n try {\n await cron.start();\n await heartbeat.start();\n await Promise.all([agent.run(), channels.startAll()]);\n } catch (err) {\n console.error(\"Gateway error:\", err);\n process.exit(1);\n }\n });\n\n// ============================================================================\n// Agent Commands\n// ============================================================================\n\nprogram\n .command(\"agent\")\n .description(\"Interact with the agent directly\")\n .option(\"-m, --message <text>\", \"Message to send to the agent\")\n .option(\n \"-s, --session <id>\",\n \"Session ID\",\n \"cli:default\",\n )\n .action(async (opts) => {\n const config = loadConfig();\n const apiKey = getApiKey(config);\n const apiBase = getApiBase(config);\n\n if (!apiKey) {\n console.error(\"Error: No API key configured.\");\n process.exit(1);\n }\n\n const { MessageBus } = await import(\"../bus/queue.js\");\n const { OpenAIProvider } = await import(\n \"../providers/openai-provider.js\"\n );\n const { AgentLoop } = await import(\"../agent/loop.js\");\n\n const bus = new MessageBus();\n const workspace = getConfigWorkspacePath(config);\n\n const provider = new OpenAIProvider({\n apiKey,\n apiBase: apiBase ?? undefined,\n defaultModel: config.agents.defaults.model,\n });\n\n const agentLoop = new AgentLoop({\n bus,\n provider,\n workspace,\n braveApiKey: config.tools.web.search.apiKey || undefined,\n execConfig: config.tools.exec,\n });\n\n if (opts.message) {\n // Single message mode\n const response = await agentLoop.processDirect(\n opts.message,\n opts.session,\n );\n console.log(`\\n${LOGO} ${response}`);\n } else {\n // Interactive mode\n console.log(`${LOGO} Interactive mode (Ctrl+C to exit)\\n`);\n\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (): void => {\n rl.question(\"You: \", async (input) => {\n const trimmed = input.trim();\n if (!trimmed) {\n ask();\n return;\n }\n\n try {\n const response = await agentLoop.processDirect(\n trimmed,\n opts.session,\n );\n console.log(`\\n${LOGO} ${response}\\n`);\n } catch (err) {\n console.error(\"Error:\", err);\n }\n ask();\n });\n };\n\n rl.on(\"close\", () => {\n console.log(\"\\nGoodbye!\");\n process.exit(0);\n });\n\n ask();\n }\n });\n\n// ============================================================================\n// Channel Commands\n// ============================================================================\n\nconst channelsCmd = program\n .command(\"channels\")\n .description(\"Manage channels\");\n\nchannelsCmd\n .command(\"status\")\n .description(\"Show channel status\")\n .action(() => {\n const config = loadConfig();\n\n console.log(\"Channel Status\");\n console.log(\"─\".repeat(50));\n\n const tg = config.channels.telegram;\n const tgToken = tg.token\n ? `token: ${tg.token.slice(0, 10)}...`\n : \"not configured\";\n console.log(\n ` Telegram ${tg.enabled ? \"[enabled]\" : \"[disabled]\"} ${tgToken}`,\n );\n });\n\n// ============================================================================\n// Cron Commands\n// ============================================================================\n\nconst cronCmd = program\n .command(\"cron\")\n .description(\"Manage scheduled tasks\");\n\ncronCmd\n .command(\"list\")\n .description(\"List scheduled jobs\")\n .option(\"-a, --all\", \"Include disabled jobs\", false)\n .action((opts) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n const jobs = service.listJobs(opts.all);\n\n if (jobs.length === 0) {\n console.log(\"No scheduled jobs.\");\n return;\n }\n\n console.log(\"Scheduled Jobs\");\n console.log(\"─\".repeat(70));\n console.log(\n `${\"ID\".padEnd(10)} ${\"Name\".padEnd(20)} ${\"Schedule\".padEnd(18)} ${\"Status\".padEnd(10)} Next Run`,\n );\n console.log(\"─\".repeat(70));\n\n for (const job of jobs) {\n let sched: string;\n if (job.schedule.kind === \"every\") {\n sched = `every ${(job.schedule.everyMs ?? 0) / 1000}s`;\n } else if (job.schedule.kind === \"cron\") {\n sched = job.schedule.expr ?? \"\";\n } else {\n sched = \"one-time\";\n }\n\n let nextRun = \"\";\n if (job.state.nextRunAtMs) {\n nextRun = new Date(job.state.nextRunAtMs).toLocaleString();\n }\n\n const status = job.enabled ? \"enabled\" : \"disabled\";\n\n console.log(\n `${job.id.padEnd(10)} ${job.name.padEnd(20)} ${sched.padEnd(18)} ${status.padEnd(10)} ${nextRun}`,\n );\n }\n });\n\ncronCmd\n .command(\"add\")\n .description(\"Add a scheduled job\")\n .requiredOption(\"-n, --name <name>\", \"Job name\")\n .requiredOption(\"-m, --message <text>\", \"Message for agent\")\n .option(\"-e, --every <seconds>\", \"Run every N seconds\")\n .option(\"-c, --cron <expr>\", \"Cron expression (e.g. '0 9 * * *')\")\n .option(\"--at <iso>\", \"Run once at time (ISO format)\")\n .option(\"-d, --deliver\", \"Deliver response to channel\", false)\n .option(\"--to <recipient>\", \"Recipient for delivery\")\n .option(\"--channel <name>\", \"Channel for delivery\")\n .action((opts) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n let schedule: { kind: string; everyMs?: number; expr?: string; atMs?: number };\n if (opts.every) {\n schedule = { kind: \"every\", everyMs: Number(opts.every) * 1000 };\n } else if (opts.cron) {\n schedule = { kind: \"cron\", expr: opts.cron };\n } else if (opts.at) {\n const dt = new Date(opts.at);\n schedule = { kind: \"at\", atMs: dt.getTime() };\n } else {\n console.error(\"Error: Must specify --every, --cron, or --at\");\n process.exit(1);\n }\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n const job = service.addJob({\n name: opts.name,\n schedule: schedule as import(\"../cron/types.js\").CronSchedule,\n message: opts.message,\n deliver: opts.deliver,\n to: opts.to,\n channel: opts.channel,\n });\n\n console.log(`Added job '${job.name}' (${job.id})`);\n });\n\ncronCmd\n .command(\"remove\")\n .description(\"Remove a scheduled job\")\n .argument(\"<jobId>\", \"Job ID to remove\")\n .action((jobId: string) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n if (service.removeJob(jobId)) {\n console.log(`Removed job ${jobId}`);\n } else {\n console.error(`Job ${jobId} not found`);\n }\n });\n\ncronCmd\n .command(\"enable\")\n .description(\"Enable or disable a job\")\n .argument(\"<jobId>\", \"Job ID\")\n .option(\"--disable\", \"Disable instead of enable\", false)\n .action((jobId: string, opts: { disable: boolean }) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n const job = service.enableJob(jobId, !opts.disable);\n if (job) {\n const status = opts.disable ? \"disabled\" : \"enabled\";\n console.log(`Job '${job.name}' ${status}`);\n } else {\n console.error(`Job ${jobId} not found`);\n }\n });\n\n// ============================================================================\n// Status\n// ============================================================================\n\nprogram\n .command(\"status\")\n .description(\"Show nanobot status\")\n .action(() => {\n const configPath = getConfigPath();\n const config = loadConfig();\n const workspace = getConfigWorkspacePath(config);\n\n console.log(`${LOGO} nanobot Status\\n`);\n\n console.log(\n `Config: ${configPath} ${existsSync(configPath) ? \"[ok]\" : \"[missing]\"}`,\n );\n console.log(\n `Workspace: ${workspace} ${existsSync(workspace) ? \"[ok]\" : \"[missing]\"}`,\n );\n\n if (existsSync(configPath)) {\n console.log(`Model: ${config.agents.defaults.model}`);\n\n const hasOpenrouter = Boolean(config.providers.openrouter.apiKey);\n const hasAnthropic = Boolean(config.providers.anthropic.apiKey);\n const hasOpenai = Boolean(config.providers.openai.apiKey);\n const hasGemini = Boolean(config.providers.gemini.apiKey);\n const hasDeepseek = Boolean(config.providers.deepseek.apiKey);\n\n console.log(\n `OpenRouter API: ${hasOpenrouter ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `Anthropic API: ${hasAnthropic ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `OpenAI API: ${hasOpenai ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `Gemini API: ${hasGemini ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `DeepSeek API: ${hasDeepseek ? \"[set]\" : \"[not set]\"}`,\n );\n }\n });\n\nprogram.parse();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * nanobot CLI - Personal AI Assistant\n */\n\nimport { Command } from \"commander\";\nimport { existsSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { VERSION, LOGO } from \"../index.js\";\nimport { loadConfig, saveConfig } from \"../config/loader.js\";\nimport { getConfigPath, getDataDir } from \"../config/loader.js\";\nimport {\n ConfigSchema,\n getConfigWorkspacePath,\n getApiKey,\n getApiBase,\n} from \"../config/schema.js\";\nimport type { Config } from \"../config/schema.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"nanobot\")\n .description(`${LOGO} nanobot - Personal AI Assistant`)\n .version(`${LOGO} nanobot v${VERSION}`, \"-v, --version\");\n\n// ============================================================================\n// Onboard / Setup\n// ============================================================================\n\nprogram\n .command(\"onboard\")\n .description(\"Initialize nanobot configuration and workspace\")\n .action(() => {\n const configPath = getConfigPath();\n\n if (existsSync(configPath)) {\n console.log(`Config already exists at ${configPath}`);\n console.log(\"Delete it first if you want to start fresh.\");\n return;\n }\n\n // Create default config\n const config = ConfigSchema.parse({});\n saveConfig(config);\n console.log(`Created config at ${configPath}`);\n\n // Create workspace\n const workspace = getConfigWorkspacePath(config);\n createWorkspaceTemplates(workspace);\n\n console.log(`\\n${LOGO} nanobot is ready!`);\n console.log(\"\\nNext steps:\");\n console.log(\" 1. Add your API key to ~/.nanobot/config.json\");\n console.log(\" Get one at: https://openrouter.ai/keys\");\n console.log(' 2. Chat: nanobot agent -m \"Hello!\"');\n console.log(\n \"\\nWant Telegram? See: https://github.com/HKUDS/nanobot#-chat-apps\",\n );\n });\n\nfunction createWorkspaceTemplates(workspace: string): void {\n if (!existsSync(workspace)) {\n mkdirSync(workspace, { recursive: true });\n }\n\n const templates: Record<string, string> = {\n \"AGENTS.md\": `# Agent Instructions\n\nYou are a helpful AI assistant. Be concise, accurate, and friendly.\n\n## Guidelines\n\n- Always explain what you're doing before taking actions\n- Ask for clarification when the request is ambiguous\n- Use tools to help accomplish tasks\n- Remember important information in your memory files\n`,\n \"SOUL.md\": `# Soul\n\nI am nanobot, a lightweight AI assistant.\n\n## Personality\n\n- Helpful and friendly\n- Concise and to the point\n- Curious and eager to learn\n\n## Values\n\n- Accuracy over speed\n- User privacy and safety\n- Transparency in actions\n`,\n \"USER.md\": `# User\n\nInformation about the user goes here.\n\n## Preferences\n\n- Communication style: (casual/formal)\n- Timezone: (your timezone)\n- Language: (your preferred language)\n`,\n };\n\n for (const [filename, content] of Object.entries(templates)) {\n const filePath = join(workspace, filename);\n if (!existsSync(filePath)) {\n writeFileSync(filePath, content);\n console.log(` Created ${filename}`);\n }\n }\n\n // Create memory directory and MEMORY.md\n const memoryDir = join(workspace, \"memory\");\n if (!existsSync(memoryDir)) {\n mkdirSync(memoryDir, { recursive: true });\n }\n const memoryFile = join(memoryDir, \"MEMORY.md\");\n if (!existsSync(memoryFile)) {\n writeFileSync(\n memoryFile,\n `# Long-term Memory\n\nThis file stores important information that should persist across sessions.\n\n## User Information\n\n(Important facts about the user)\n\n## Preferences\n\n(User preferences learned over time)\n\n## Important Notes\n\n(Things to remember)\n`,\n );\n console.log(\" Created memory/MEMORY.md\");\n }\n}\n\n// ============================================================================\n// Gateway / Server\n// ============================================================================\n\nprogram\n .command(\"gateway\")\n .description(\"Start the nanobot gateway\")\n .option(\"-p, --port <number>\", \"Gateway port\", \"18790\")\n .option(\"--verbose\", \"Verbose output\", false)\n .action(async (opts) => {\n console.log(\n `${LOGO} Starting nanobot gateway on port ${opts.port}...`,\n );\n\n const config = loadConfig();\n const apiKey = getApiKey(config);\n const apiBase = getApiBase(config);\n const model = config.agents.defaults.model;\n\n if (!apiKey) {\n console.error(\"Error: No API key configured.\");\n console.error(\n \"Set one in ~/.nanobot/config.json under providers.openrouter.apiKey\",\n );\n process.exit(1);\n }\n\n // Dynamic imports to avoid loading heavy deps up front\n const { MessageBus } = await import(\"../bus/queue.js\");\n const { OpenAIProvider } = await import(\n \"../providers/openai-provider.js\"\n );\n const { AgentLoop } = await import(\"../agent/loop.js\");\n const { ChannelManager } = await import(\"../channels/manager.js\");\n const { CronService } = await import(\"../cron/service.js\");\n const { HeartbeatService } = await import(\n \"../heartbeat/service.js\"\n );\n\n const bus = new MessageBus();\n const workspace = getConfigWorkspacePath(config);\n\n const provider = new OpenAIProvider({\n apiKey,\n apiBase: apiBase ?? undefined,\n defaultModel: model,\n });\n\n // Create cron service\n const cronStorePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const cron = new CronService(cronStorePath);\n\n // Create agent\n const agent = new AgentLoop({\n bus,\n provider,\n workspace,\n model,\n maxIterations: config.agents.defaults.maxToolIterations,\n braveApiKey: config.tools.web.search.apiKey || undefined,\n execConfig: config.tools.exec,\n cronService: cron,\n });\n\n // Wire cron callback\n cron.onJob = async (job) => {\n const response = await agent.processDirect(\n job.payload.message,\n `cron:${job.id}`,\n job.payload.channel ?? \"cli\",\n job.payload.to ?? \"direct\",\n );\n\n if (job.payload.deliver && job.payload.to) {\n const { createOutboundMessage } = await import(\n \"../bus/events.js\"\n );\n await bus.publishOutbound(\n createOutboundMessage({\n channel: job.payload.channel ?? \"cli\",\n chatId: job.payload.to,\n content: response ?? \"\",\n }),\n );\n }\n return response;\n };\n\n // Create heartbeat\n const heartbeat = new HeartbeatService({\n workspace,\n onHeartbeat: (prompt) =>\n agent.processDirect(prompt, \"heartbeat\"),\n intervalS: 30 * 60,\n enabled: true,\n });\n\n // Create channel manager\n const channels = new ChannelManager(config, bus);\n\n if (channels.enabledChannels.length > 0) {\n console.log(\n `Channels enabled: ${channels.enabledChannels.join(\", \")}`,\n );\n } else {\n console.log(\"Warning: No channels enabled\");\n }\n\n const cronStatus = cron.status();\n if (cronStatus.jobs > 0) {\n console.log(`Cron: ${cronStatus.jobs} scheduled jobs`);\n }\n console.log(\"Heartbeat: every 30m\");\n\n // Handle graceful shutdown\n const shutdown = async () => {\n console.log(\"\\nShutting down...\");\n heartbeat.stop();\n cron.stop();\n agent.stop();\n await channels.stopAll();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n try {\n await cron.start();\n await heartbeat.start();\n await Promise.all([agent.run(), channels.startAll()]);\n } catch (err) {\n console.error(\"Gateway error:\", err);\n process.exit(1);\n }\n });\n\n// ============================================================================\n// Agent Commands\n// ============================================================================\n\nprogram\n .command(\"agent\")\n .description(\"Interact with the agent directly\")\n .option(\"-m, --message <text>\", \"Message to send to the agent\")\n .option(\n \"-s, --session <id>\",\n \"Session ID\",\n \"cli:default\",\n )\n .action(async (opts) => {\n const config = loadConfig();\n const apiKey = getApiKey(config);\n const apiBase = getApiBase(config);\n\n if (!apiKey) {\n console.error(\"Error: No API key configured.\");\n process.exit(1);\n }\n\n const { MessageBus } = await import(\"../bus/queue.js\");\n const { OpenAIProvider } = await import(\n \"../providers/openai-provider.js\"\n );\n const { AgentLoop } = await import(\"../agent/loop.js\");\n\n const bus = new MessageBus();\n const workspace = getConfigWorkspacePath(config);\n\n const provider = new OpenAIProvider({\n apiKey,\n apiBase: apiBase ?? undefined,\n defaultModel: config.agents.defaults.model,\n });\n\n const agentLoop = new AgentLoop({\n bus,\n provider,\n workspace,\n braveApiKey: config.tools.web.search.apiKey || undefined,\n execConfig: config.tools.exec,\n });\n\n if (opts.message) {\n // Single message mode\n const response = await agentLoop.processDirect(\n opts.message,\n opts.session,\n );\n console.log(`\\n${LOGO} ${response}`);\n } else {\n // Interactive mode\n console.log(`${LOGO} Interactive mode (Ctrl+C to exit)\\n`);\n\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (): void => {\n rl.question(\"You: \", async (input) => {\n const trimmed = input.trim();\n if (!trimmed) {\n ask();\n return;\n }\n\n try {\n const response = await agentLoop.processDirect(\n trimmed,\n opts.session,\n );\n console.log(`\\n${LOGO} ${response}\\n`);\n } catch (err) {\n console.error(\"Error:\", err);\n }\n ask();\n });\n };\n\n rl.on(\"close\", () => {\n console.log(\"\\nGoodbye!\");\n process.exit(0);\n });\n\n ask();\n }\n });\n\n// ============================================================================\n// Channel Commands\n// ============================================================================\n\nconst channelsCmd = program\n .command(\"channels\")\n .description(\"Manage channels\");\n\nchannelsCmd\n .command(\"status\")\n .description(\"Show channel status\")\n .action(() => {\n const config = loadConfig();\n\n console.log(\"Channel Status\");\n console.log(\"─\".repeat(50));\n\n const tg = config.channels.telegram;\n const tgToken = tg.token\n ? `token: ${tg.token.slice(0, 10)}...`\n : \"not configured\";\n console.log(\n ` Telegram ${tg.enabled ? \"[enabled]\" : \"[disabled]\"} ${tgToken}`,\n );\n });\n\n// ============================================================================\n// Cron Commands\n// ============================================================================\n\nconst cronCmd = program\n .command(\"cron\")\n .description(\"Manage scheduled tasks\");\n\ncronCmd\n .command(\"list\")\n .description(\"List scheduled jobs\")\n .option(\"-a, --all\", \"Include disabled jobs\", false)\n .action((opts) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n const jobs = service.listJobs(opts.all);\n\n if (jobs.length === 0) {\n console.log(\"No scheduled jobs.\");\n return;\n }\n\n console.log(\"Scheduled Jobs\");\n console.log(\"─\".repeat(70));\n console.log(\n `${\"ID\".padEnd(10)} ${\"Name\".padEnd(20)} ${\"Schedule\".padEnd(18)} ${\"Status\".padEnd(10)} Next Run`,\n );\n console.log(\"─\".repeat(70));\n\n for (const job of jobs) {\n let sched: string;\n if (job.schedule.kind === \"every\") {\n sched = `every ${(job.schedule.everyMs ?? 0) / 1000}s`;\n } else if (job.schedule.kind === \"cron\") {\n sched = job.schedule.expr ?? \"\";\n } else {\n sched = \"one-time\";\n }\n\n let nextRun = \"\";\n if (job.state.nextRunAtMs) {\n nextRun = new Date(job.state.nextRunAtMs).toLocaleString();\n }\n\n const status = job.enabled ? \"enabled\" : \"disabled\";\n\n console.log(\n `${job.id.padEnd(10)} ${job.name.padEnd(20)} ${sched.padEnd(18)} ${status.padEnd(10)} ${nextRun}`,\n );\n }\n });\n\ncronCmd\n .command(\"add\")\n .description(\"Add a scheduled job\")\n .requiredOption(\"-n, --name <name>\", \"Job name\")\n .requiredOption(\"-m, --message <text>\", \"Message for agent\")\n .option(\"-e, --every <seconds>\", \"Run every N seconds\")\n .option(\"-c, --cron <expr>\", \"Cron expression (e.g. '0 9 * * *')\")\n .option(\"--at <iso>\", \"Run once at time (ISO format)\")\n .option(\"-d, --deliver\", \"Deliver response to channel\", false)\n .option(\"--to <recipient>\", \"Recipient for delivery\")\n .option(\"--channel <name>\", \"Channel for delivery\")\n .action((opts) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n let schedule: { kind: string; everyMs?: number; expr?: string; atMs?: number };\n if (opts.every) {\n schedule = { kind: \"every\", everyMs: Number(opts.every) * 1000 };\n } else if (opts.cron) {\n schedule = { kind: \"cron\", expr: opts.cron };\n } else if (opts.at) {\n const dt = new Date(opts.at);\n schedule = { kind: \"at\", atMs: dt.getTime() };\n } else {\n console.error(\"Error: Must specify --every, --cron, or --at\");\n process.exit(1);\n }\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n const job = service.addJob({\n name: opts.name,\n schedule: schedule as import(\"../cron/types.js\").CronSchedule,\n message: opts.message,\n deliver: opts.deliver,\n to: opts.to,\n channel: opts.channel,\n });\n\n console.log(`Added job '${job.name}' (${job.id})`);\n });\n\ncronCmd\n .command(\"remove\")\n .description(\"Remove a scheduled job\")\n .argument(\"<jobId>\", \"Job ID to remove\")\n .action((jobId: string) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n if (service.removeJob(jobId)) {\n console.log(`Removed job ${jobId}`);\n } else {\n console.error(`Job ${jobId} not found`);\n }\n });\n\ncronCmd\n .command(\"enable\")\n .description(\"Enable or disable a job\")\n .argument(\"<jobId>\", \"Job ID\")\n .option(\"--disable\", \"Disable instead of enable\", false)\n .action((jobId: string, opts: { disable: boolean }) => {\n const { CronService } = require(\"../cron/service.js\") as typeof import(\"../cron/service.js\");\n\n const storePath = join(getDataDir(), \"cron\", \"jobs.json\");\n const service = new CronService(storePath);\n\n const job = service.enableJob(jobId, !opts.disable);\n if (job) {\n const status = opts.disable ? \"disabled\" : \"enabled\";\n console.log(`Job '${job.name}' ${status}`);\n } else {\n console.error(`Job ${jobId} not found`);\n }\n });\n\n// ============================================================================\n// Status\n// ============================================================================\n\nprogram\n .command(\"status\")\n .description(\"Show nanobot status\")\n .action(() => {\n const configPath = getConfigPath();\n const config = loadConfig();\n const workspace = getConfigWorkspacePath(config);\n\n console.log(`${LOGO} nanobot Status\\n`);\n\n console.log(\n `Config: ${configPath} ${existsSync(configPath) ? \"[ok]\" : \"[missing]\"}`,\n );\n console.log(\n `Workspace: ${workspace} ${existsSync(workspace) ? \"[ok]\" : \"[missing]\"}`,\n );\n\n if (existsSync(configPath)) {\n console.log(`Model: ${config.agents.defaults.model}`);\n\n const hasOpenrouter = Boolean(config.providers.openrouter.apiKey);\n const hasAnthropic = Boolean(config.providers.anthropic.apiKey);\n const hasOpenai = Boolean(config.providers.openai.apiKey);\n const hasGemini = Boolean(config.providers.gemini.apiKey);\n const hasDeepseek = Boolean(config.providers.deepseek.apiKey);\n const hasOpenaiCompatible = Boolean(config.providers.openaiCompatible.apiKey);\n console.log(\n `OpenRouter API: ${hasOpenrouter ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `Anthropic API: ${hasAnthropic ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `OpenAI API: ${hasOpenai ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `Gemini API: ${hasGemini ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `DeepSeek API: ${hasDeepseek ? \"[set]\" : \"[not set]\"}`,\n );\n console.log(\n `OpenAI Compatible API: ${hasOpenaiCompatible ? \"[set]\" : \"[not set]\"}`,\n );\n }\n });\n\nprogram.parse();\n"],"mappings":"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"}
@@ -339,27 +339,27 @@ declare const ToolsConfigSchema: z.ZodObject<{
339
339
  restrictToWorkspace?: boolean | undefined;
340
340
  }>>;
341
341
  }, "strip", z.ZodTypeAny, {
342
- exec: {
343
- timeout: number;
344
- restrictToWorkspace: boolean;
345
- };
346
342
  web: {
347
343
  search: {
348
344
  apiKey: string;
349
345
  maxResults: number;
350
346
  };
351
347
  };
348
+ exec: {
349
+ timeout: number;
350
+ restrictToWorkspace: boolean;
351
+ };
352
352
  }, {
353
- exec?: {
354
- timeout?: number | undefined;
355
- restrictToWorkspace?: boolean | undefined;
356
- } | undefined;
357
353
  web?: {
358
354
  search?: {
359
355
  apiKey?: string | undefined;
360
356
  maxResults?: number | undefined;
361
357
  } | undefined;
362
358
  } | undefined;
359
+ exec?: {
360
+ timeout?: number | undefined;
361
+ restrictToWorkspace?: boolean | undefined;
362
+ } | undefined;
363
363
  }>;
364
364
  declare const ConfigSchema: z.ZodObject<{
365
365
  agents: z.ZodDefault<z.ZodObject<{
@@ -605,27 +605,27 @@ declare const ConfigSchema: z.ZodObject<{
605
605
  restrictToWorkspace?: boolean | undefined;
606
606
  }>>;
607
607
  }, "strip", z.ZodTypeAny, {
608
- exec: {
609
- timeout: number;
610
- restrictToWorkspace: boolean;
611
- };
612
608
  web: {
613
609
  search: {
614
610
  apiKey: string;
615
611
  maxResults: number;
616
612
  };
617
613
  };
614
+ exec: {
615
+ timeout: number;
616
+ restrictToWorkspace: boolean;
617
+ };
618
618
  }, {
619
- exec?: {
620
- timeout?: number | undefined;
621
- restrictToWorkspace?: boolean | undefined;
622
- } | undefined;
623
619
  web?: {
624
620
  search?: {
625
621
  apiKey?: string | undefined;
626
622
  maxResults?: number | undefined;
627
623
  } | undefined;
628
624
  } | undefined;
625
+ exec?: {
626
+ timeout?: number | undefined;
627
+ restrictToWorkspace?: boolean | undefined;
628
+ } | undefined;
629
629
  }>>;
630
630
  }, "strip", z.ZodTypeAny, {
631
631
  agents: {
@@ -680,16 +680,16 @@ declare const ConfigSchema: z.ZodObject<{
680
680
  port: number;
681
681
  };
682
682
  tools: {
683
- exec: {
684
- timeout: number;
685
- restrictToWorkspace: boolean;
686
- };
687
683
  web: {
688
684
  search: {
689
685
  apiKey: string;
690
686
  maxResults: number;
691
687
  };
692
688
  };
689
+ exec: {
690
+ timeout: number;
691
+ restrictToWorkspace: boolean;
692
+ };
693
693
  };
694
694
  }, {
695
695
  agents?: {
@@ -744,16 +744,16 @@ declare const ConfigSchema: z.ZodObject<{
744
744
  port?: number | undefined;
745
745
  } | undefined;
746
746
  tools?: {
747
- exec?: {
748
- timeout?: number | undefined;
749
- restrictToWorkspace?: boolean | undefined;
750
- } | undefined;
751
747
  web?: {
752
748
  search?: {
753
749
  apiKey?: string | undefined;
754
750
  maxResults?: number | undefined;
755
751
  } | undefined;
756
752
  } | undefined;
753
+ exec?: {
754
+ timeout?: number | undefined;
755
+ restrictToWorkspace?: boolean | undefined;
756
+ } | undefined;
757
757
  } | undefined;
758
758
  }>;
759
759
  type Config = z.infer<typeof ConfigSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.mts","names":[],"sources":["../../src/config/schema.ts"],"mappings":";;;cAGa,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;KAMrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,mBAAA,EAAmB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;KAOpB,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;AAAA,cAE9B,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KASnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,cAE7B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;KAIrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAI/B,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAStB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,cAEhC,mBAAA,EAAmB,CAAA,CAAA,SAAA;;;;;;;;;;KAIpB,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;AAAA,cAE9B,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;;;;;;;cAKrB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cAIpB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;KAIrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAUjB,YAAA,EAAY,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2Bb,MAAA,GAAS,CAAA,CAAE,KAAA,QAAa,YAAA;;iBAGpB,sBAAA,CAAuB,MAAA,EAAQ,MAAA;;iBAS/B,SAAA,CAAU,MAAA,EAAQ,MAAA;;iBAclB,UAAA,CAAW,MAAA,EAAQ,MAAA"}
1
+ {"version":3,"file":"schema.d.mts","names":[],"sources":["../../src/config/schema.ts"],"mappings":";;;cAGa,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;KAMrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,mBAAA,EAAmB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;KAOpB,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;AAAA,cAE9B,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KASnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,cAE7B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;KAIrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAI/B,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAStB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,cAEhC,mBAAA,EAAmB,CAAA,CAAA,SAAA;;;;;;;;;;KAIpB,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;AAAA,cAE9B,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;;;;;;;cAKrB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cAIpB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;KAIrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAUjB,YAAA,EAAY,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4Bb,MAAA,GAAS,CAAA,CAAE,KAAA,QAAa,YAAA;;iBAGpB,sBAAA,CAAuB,MAAA,EAAQ,MAAA;;iBAS/B,SAAA,CAAU,MAAA,EAAQ,MAAA;;iBAclB,UAAA,CAAW,MAAA,EAAQ,MAAA"}
@@ -86,7 +86,8 @@ const ConfigSchema = z.object({
86
86
  openrouter: defaultProvider,
87
87
  deepseek: defaultProvider,
88
88
  groq: defaultProvider,
89
- gemini: defaultProvider
89
+ gemini: defaultProvider,
90
+ openaiCompatible: defaultProvider
90
91
  }),
91
92
  gateway: GatewayConfigSchema.default({
92
93
  host: "0.0.0.0",
@@ -1 +1 @@
1
- {"version":3,"file":"schema.mjs","names":[],"sources":["../../src/config/schema.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { homedir } from \"node:os\";\n\nexport const TelegramConfigSchema = z.object({\n enabled: z.boolean().default(false),\n token: z.string().default(\"\"),\n allowFrom: z.array(z.string()).default([]),\n proxy: z.string().nullish(),\n});\nexport type TelegramConfig = z.infer<typeof TelegramConfigSchema>;\n\nexport const ChannelsConfigSchema = z.object({\n telegram: TelegramConfigSchema.default({\n enabled: false,\n token: \"\",\n allowFrom: [],\n }),\n});\nexport type ChannelsConfig = z.infer<typeof ChannelsConfigSchema>;\n\nexport const AgentDefaultsSchema = z.object({\n workspace: z.string().default(\"~/.nanobot/workspace\"),\n model: z.string().default(\"anthropic/claude-sonnet-4-20250514\"),\n maxTokens: z.number().default(8192),\n temperature: z.number().default(0.7),\n maxToolIterations: z.number().default(20),\n});\nexport type AgentDefaults = z.infer<typeof AgentDefaultsSchema>;\n\nexport const AgentsConfigSchema = z.object({\n defaults: AgentDefaultsSchema.default({\n workspace: \"~/.nanobot/workspace\",\n model: \"anthropic/claude-sonnet-4-20250514\",\n maxTokens: 8192,\n temperature: 0.7,\n maxToolIterations: 20,\n }),\n});\nexport type AgentsConfig = z.infer<typeof AgentsConfigSchema>;\n\nexport const ProviderConfigSchema = z.object({\n apiKey: z.string().default(\"\"),\n apiBase: z.string().nullish(),\n});\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\n\nconst defaultProvider = { apiKey: \"\" } as const;\n\nexport const ProvidersConfigSchema = z.object({\n anthropic: ProviderConfigSchema.default(defaultProvider),\n openai: ProviderConfigSchema.default(defaultProvider),\n openrouter: ProviderConfigSchema.default(defaultProvider),\n deepseek: ProviderConfigSchema.default(defaultProvider),\n groq: ProviderConfigSchema.default(defaultProvider),\n gemini: ProviderConfigSchema.default(defaultProvider),\n openaiCompatible: ProviderConfigSchema.default(defaultProvider),\n});\nexport type ProvidersConfig = z.infer<typeof ProvidersConfigSchema>;\n\nexport const GatewayConfigSchema = z.object({\n host: z.string().default(\"0.0.0.0\"),\n port: z.number().default(18790),\n});\nexport type GatewayConfig = z.infer<typeof GatewayConfigSchema>;\n\nexport const WebSearchConfigSchema = z.object({\n apiKey: z.string().default(\"\"),\n maxResults: z.number().default(5),\n});\n\nexport const WebToolsConfigSchema = z.object({\n search: WebSearchConfigSchema.default({ apiKey: \"\", maxResults: 5 }),\n});\n\nexport const ExecToolConfigSchema = z.object({\n timeout: z.number().default(60),\n restrictToWorkspace: z.boolean().default(false),\n});\nexport type ExecToolConfig = z.infer<typeof ExecToolConfigSchema>;\n\nexport const ToolsConfigSchema = z.object({\n web: WebToolsConfigSchema.default({\n search: { apiKey: \"\", maxResults: 5 },\n }),\n exec: ExecToolConfigSchema.default({\n timeout: 60,\n restrictToWorkspace: false,\n }),\n});\n\nexport const ConfigSchema = z.object({\n agents: AgentsConfigSchema.default({\n defaults: {\n workspace: \"~/.nanobot/workspace\",\n model: \"anthropic/claude-sonnet-4-20250514\",\n maxTokens: 8192,\n temperature: 0.7,\n maxToolIterations: 20,\n },\n }),\n channels: ChannelsConfigSchema.default({\n telegram: { enabled: false, token: \"\", allowFrom: [] },\n }),\n providers: ProvidersConfigSchema.default({\n anthropic: defaultProvider,\n openai: defaultProvider,\n openrouter: defaultProvider,\n deepseek: defaultProvider,\n groq: defaultProvider,\n gemini: defaultProvider,\n }),\n gateway: GatewayConfigSchema.default({ host: \"0.0.0.0\", port: 18790 }),\n tools: ToolsConfigSchema.default({\n web: { search: { apiKey: \"\", maxResults: 5 } },\n exec: { timeout: 60, restrictToWorkspace: false },\n }),\n});\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Get expanded workspace path. */\nexport function getConfigWorkspacePath(config: Config): string {\n const ws = config.agents.defaults.workspace;\n if (ws.startsWith(\"~\")) {\n return ws.replace(/^~/, homedir());\n }\n return ws;\n}\n\n/** Get API key in priority order. */\nexport function getApiKey(config: Config): string | null {\n return (\n config.providers.openrouter.apiKey ||\n config.providers.deepseek.apiKey ||\n config.providers.anthropic.apiKey ||\n config.providers.openai.apiKey ||\n config.providers.gemini.apiKey ||\n config.providers.groq.apiKey ||\n config.providers.openaiCompatible.apiKey ||\n null\n );\n}\n\n/** Get API base URL if using OpenRouter. */\nexport function getApiBase(config: Config): string | null {\n if (config.providers.openrouter.apiKey) {\n return (\n config.providers.openrouter.apiBase ?? \"https://openrouter.ai/api/v1\"\n );\n }\n if (config.providers.openaiCompatible.apiKey) {\n return config.providers.openaiCompatible.apiBase ?? null;\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schema.mjs","names":[],"sources":["../../src/config/schema.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { homedir } from \"node:os\";\n\nexport const TelegramConfigSchema = z.object({\n enabled: z.boolean().default(false),\n token: z.string().default(\"\"),\n allowFrom: z.array(z.string()).default([]),\n proxy: z.string().nullish(),\n});\nexport type TelegramConfig = z.infer<typeof TelegramConfigSchema>;\n\nexport const ChannelsConfigSchema = z.object({\n telegram: TelegramConfigSchema.default({\n enabled: false,\n token: \"\",\n allowFrom: [],\n }),\n});\nexport type ChannelsConfig = z.infer<typeof ChannelsConfigSchema>;\n\nexport const AgentDefaultsSchema = z.object({\n workspace: z.string().default(\"~/.nanobot/workspace\"),\n model: z.string().default(\"anthropic/claude-sonnet-4-20250514\"),\n maxTokens: z.number().default(8192),\n temperature: z.number().default(0.7),\n maxToolIterations: z.number().default(20),\n});\nexport type AgentDefaults = z.infer<typeof AgentDefaultsSchema>;\n\nexport const AgentsConfigSchema = z.object({\n defaults: AgentDefaultsSchema.default({\n workspace: \"~/.nanobot/workspace\",\n model: \"anthropic/claude-sonnet-4-20250514\",\n maxTokens: 8192,\n temperature: 0.7,\n maxToolIterations: 20,\n }),\n});\nexport type AgentsConfig = z.infer<typeof AgentsConfigSchema>;\n\nexport const ProviderConfigSchema = z.object({\n apiKey: z.string().default(\"\"),\n apiBase: z.string().nullish(),\n});\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\n\nconst defaultProvider = { apiKey: \"\" } as const;\n\nexport const ProvidersConfigSchema = z.object({\n anthropic: ProviderConfigSchema.default(defaultProvider),\n openai: ProviderConfigSchema.default(defaultProvider),\n openrouter: ProviderConfigSchema.default(defaultProvider),\n deepseek: ProviderConfigSchema.default(defaultProvider),\n groq: ProviderConfigSchema.default(defaultProvider),\n gemini: ProviderConfigSchema.default(defaultProvider),\n openaiCompatible: ProviderConfigSchema.default(defaultProvider),\n});\nexport type ProvidersConfig = z.infer<typeof ProvidersConfigSchema>;\n\nexport const GatewayConfigSchema = z.object({\n host: z.string().default(\"0.0.0.0\"),\n port: z.number().default(18790),\n});\nexport type GatewayConfig = z.infer<typeof GatewayConfigSchema>;\n\nexport const WebSearchConfigSchema = z.object({\n apiKey: z.string().default(\"\"),\n maxResults: z.number().default(5),\n});\n\nexport const WebToolsConfigSchema = z.object({\n search: WebSearchConfigSchema.default({ apiKey: \"\", maxResults: 5 }),\n});\n\nexport const ExecToolConfigSchema = z.object({\n timeout: z.number().default(60),\n restrictToWorkspace: z.boolean().default(false),\n});\nexport type ExecToolConfig = z.infer<typeof ExecToolConfigSchema>;\n\nexport const ToolsConfigSchema = z.object({\n web: WebToolsConfigSchema.default({\n search: { apiKey: \"\", maxResults: 5 },\n }),\n exec: ExecToolConfigSchema.default({\n timeout: 60,\n restrictToWorkspace: false,\n }),\n});\n\nexport const ConfigSchema = z.object({\n agents: AgentsConfigSchema.default({\n defaults: {\n workspace: \"~/.nanobot/workspace\",\n model: \"anthropic/claude-sonnet-4-20250514\",\n maxTokens: 8192,\n temperature: 0.7,\n maxToolIterations: 20,\n },\n }),\n channels: ChannelsConfigSchema.default({\n telegram: { enabled: false, token: \"\", allowFrom: [] },\n }),\n providers: ProvidersConfigSchema.default({\n anthropic: defaultProvider,\n openai: defaultProvider,\n openrouter: defaultProvider,\n deepseek: defaultProvider,\n groq: defaultProvider,\n gemini: defaultProvider,\n openaiCompatible: defaultProvider,\n }),\n gateway: GatewayConfigSchema.default({ host: \"0.0.0.0\", port: 18790 }),\n tools: ToolsConfigSchema.default({\n web: { search: { apiKey: \"\", maxResults: 5 } },\n exec: { timeout: 60, restrictToWorkspace: false },\n }),\n});\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Get expanded workspace path. */\nexport function getConfigWorkspacePath(config: Config): string {\n const ws = config.agents.defaults.workspace;\n if (ws.startsWith(\"~\")) {\n return ws.replace(/^~/, homedir());\n }\n return ws;\n}\n\n/** Get API key in priority order. */\nexport function getApiKey(config: Config): string | null {\n return (\n config.providers.openrouter.apiKey ||\n config.providers.deepseek.apiKey ||\n config.providers.anthropic.apiKey ||\n config.providers.openai.apiKey ||\n config.providers.gemini.apiKey ||\n config.providers.groq.apiKey ||\n config.providers.openaiCompatible.apiKey ||\n null\n );\n}\n\n/** Get API base URL if using OpenRouter. */\nexport function getApiBase(config: Config): string | null {\n if (config.providers.openrouter.apiKey) {\n return (\n config.providers.openrouter.apiBase ?? \"https://openrouter.ai/api/v1\"\n );\n }\n if (config.providers.openaiCompatible.apiKey) {\n return config.providers.openaiCompatible.apiBase ?? null;\n }\n return null;\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -16,7 +16,7 @@ import { HeartbeatService } from "./heartbeat/service.mjs";
16
16
  import { OpenAIProvider } from "./providers/openai-provider.mjs";
17
17
 
18
18
  //#region src/index.d.ts
19
- declare const VERSION = "0.1.2";
19
+ declare const VERSION = "0.1.4";
20
20
  declare const LOGO = "\uD83D\uDC08";
21
21
  //#endregion
22
22
  export { AgentLoop, ChannelManager, type Config, ContextBuilder, CronService, HeartbeatService, type InboundMessage, type LLMProvider, type LLMResponse, LOGO, MemoryStore, MessageBus, OpenAIProvider, type OutboundMessage, SessionManager, SkillsLoader, SubagentManager, TelegramChannel, type ToolCallRequest, VERSION, loadConfig, saveConfig };
package/dist/index.mjs CHANGED
@@ -15,7 +15,7 @@ import { HeartbeatService } from "./heartbeat/service.mjs";
15
15
  //#region src/index.ts
16
16
  init_telegram();
17
17
  init_service();
18
- const VERSION = "0.1.2";
18
+ const VERSION = "0.1.4";
19
19
  const LOGO = "🐈";
20
20
 
21
21
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export const VERSION = \"0.1.2\";\nexport const LOGO = \"\\u{1F408}\";\n\n// Core exports\nexport { AgentLoop } from \"./agent/loop.js\";\nexport { ContextBuilder } from \"./agent/context.js\";\nexport { MemoryStore } from \"./agent/memory.js\";\nexport { SkillsLoader } from \"./agent/skills.js\";\nexport { SubagentManager } from \"./agent/subagent.js\";\n\n// Bus\nexport { MessageBus } from \"./bus/queue.js\";\nexport type { InboundMessage, OutboundMessage } from \"./bus/events.js\";\n\n// Config\nexport { loadConfig, saveConfig } from \"./config/loader.js\";\nexport type { Config } from \"./config/schema.js\";\n\n// Providers\nexport { OpenAIProvider } from \"./providers/openai-provider.js\";\nexport type { LLMProvider, LLMResponse, ToolCallRequest } from \"./providers/base.js\";\n\n// Channels\nexport { TelegramChannel } from \"./channels/telegram.js\";\nexport { ChannelManager } from \"./channels/manager.js\";\n\n// Services\nexport { CronService } from \"./cron/service.js\";\nexport { HeartbeatService } from \"./heartbeat/service.js\";\nexport { SessionManager } from \"./session/manager.js\";\n"],"mappings":";;;;;;;;;;;;;;;eAuByD;cAIT;AA3BhD,MAAa,UAAU;AACvB,MAAa,OAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export const VERSION = \"0.1.4\";\nexport const LOGO = \"\\u{1F408}\";\n\n// Core exports\nexport { AgentLoop } from \"./agent/loop.js\";\nexport { ContextBuilder } from \"./agent/context.js\";\nexport { MemoryStore } from \"./agent/memory.js\";\nexport { SkillsLoader } from \"./agent/skills.js\";\nexport { SubagentManager } from \"./agent/subagent.js\";\n\n// Bus\nexport { MessageBus } from \"./bus/queue.js\";\nexport type { InboundMessage, OutboundMessage } from \"./bus/events.js\";\n\n// Config\nexport { loadConfig, saveConfig } from \"./config/loader.js\";\nexport type { Config } from \"./config/schema.js\";\n\n// Providers\nexport { OpenAIProvider } from \"./providers/openai-provider.js\";\nexport type { LLMProvider, LLMResponse, ToolCallRequest } from \"./providers/base.js\";\n\n// Channels\nexport { TelegramChannel } from \"./channels/telegram.js\";\nexport { ChannelManager } from \"./channels/manager.js\";\n\n// Services\nexport { CronService } from \"./cron/service.js\";\nexport { HeartbeatService } from \"./heartbeat/service.js\";\nexport { SessionManager } from \"./session/manager.js\";\n"],"mappings":";;;;;;;;;;;;;;;eAuByD;cAIT;AA3BhD,MAAa,UAAU;AACvB,MAAa,OAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jcheesepkg/nanobot",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Lightweight AI assistant - TypeScript port",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",