titan-agent 5.4.0 → 5.4.2

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.
Files changed (48) hide show
  1. package/dist/agent/agent.js +1 -1
  2. package/dist/agent/agent.js.map +1 -1
  3. package/dist/agent/agentLoop.js +77 -12
  4. package/dist/agent/agentLoop.js.map +1 -1
  5. package/dist/agent/agentWakeup.js +8 -3
  6. package/dist/agent/agentWakeup.js.map +1 -1
  7. package/dist/agent/commandPost.js +6 -1
  8. package/dist/agent/commandPost.js.map +1 -1
  9. package/dist/agent/heartbeatScheduler.js +36 -4
  10. package/dist/agent/heartbeatScheduler.js.map +1 -1
  11. package/dist/agent/toolRunner.js +30 -0
  12. package/dist/agent/toolRunner.js.map +1 -1
  13. package/dist/config/config.js +30 -8
  14. package/dist/config/config.js.map +1 -1
  15. package/dist/config/schema.js +10 -1
  16. package/dist/config/schema.js.map +1 -1
  17. package/dist/eval/record.js +1 -1
  18. package/dist/eval/record.js.map +1 -1
  19. package/dist/gateway/server.js +26 -0
  20. package/dist/gateway/server.js.map +1 -1
  21. package/dist/mesh/transport.js +60 -8
  22. package/dist/mesh/transport.js.map +1 -1
  23. package/dist/providers/anthropic.js +3 -2
  24. package/dist/providers/anthropic.js.map +1 -1
  25. package/dist/providers/base.js.map +1 -1
  26. package/dist/providers/google.js +94 -20
  27. package/dist/providers/google.js.map +1 -1
  28. package/dist/providers/modelCapabilities.js +59 -0
  29. package/dist/providers/modelCapabilities.js.map +1 -0
  30. package/dist/providers/ollama.js +3 -2
  31. package/dist/providers/ollama.js.map +1 -1
  32. package/dist/providers/openai.js +4 -3
  33. package/dist/providers/openai.js.map +1 -1
  34. package/dist/providers/openai_compat.js +3 -2
  35. package/dist/providers/openai_compat.js.map +1 -1
  36. package/dist/providers/router.js +63 -21
  37. package/dist/providers/router.js.map +1 -1
  38. package/dist/skills/registry.js +176 -163
  39. package/dist/skills/registry.js.map +1 -1
  40. package/dist/telemetry/activityLog.js +1 -1
  41. package/dist/telemetry/activityLog.js.map +1 -1
  42. package/dist/utils/constants.js +2 -2
  43. package/dist/utils/constants.js.map +1 -1
  44. package/docs/AGENT-HIERARCHY.md +154 -0
  45. package/docs/superpowers/plans/2026-04-29-titan-production-fix.md +241 -0
  46. package/package.json +2 -2
  47. package/scripts/start-workers.sh +39 -0
  48. package/scripts/task-feeder.ts +38 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/skills/registry.ts"],"sourcesContent":["/**\n * TITAN — Skills Registry\n * Discovers, loads, and manages skills from bundled, workspace, and marketplace sources.\n */\nimport { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport vm from 'vm';\nimport { TITAN_HOME, TITAN_SKILLS_DIR } from '../utils/constants.js';\nimport { registerTool, type ToolHandler } from '../agent/toolRunner.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'Skills';\nconst DISABLED_SKILLS_PATH = join(TITAN_HOME, 'disabled-skills.json');\n\nexport interface SkillMeta {\n name: string;\n description: string;\n version: string;\n author?: string;\n source: 'bundled' | 'workspace' | 'marketplace' | 'frontmatter';\n enabled: boolean;\n}\n\nconst registeredSkills: Map<string, SkillMeta> = new Map();\n\n/** Maps skill name → tool names belonging to that skill */\nconst skillToolMap: Map<string, Set<string>> = new Map();\n\n/** Register a built-in skill (tool handler + metadata) */\nexport function registerSkill(meta: SkillMeta, handler: ToolHandler): void {\n registeredSkills.set(meta.name, meta);\n // Track which tools belong to this skill\n if (!skillToolMap.has(meta.name)) {\n skillToolMap.set(meta.name, new Set());\n }\n skillToolMap.get(meta.name)!.add(handler.name);\n registerTool(handler);\n logger.debug(COMPONENT, `Registered skill: ${meta.name} (${meta.source})`);\n}\n\n/** Get all registered skills (with persisted enabled/disabled state applied) */\nexport function getSkills(): SkillMeta[] {\n const disabled = loadDisabledSkills();\n return Array.from(registeredSkills.values()).map(s => ({\n ...s,\n enabled: !disabled.includes(s.name),\n }));\n}\n\n/** Get a skill by name */\nexport function getSkill(name: string): SkillMeta | undefined {\n return registeredSkills.get(name);\n}\n\n/** Get tool names belonging to a skill */\nexport function getSkillTools(skillName: string): string[] {\n return Array.from(skillToolMap.get(skillName) || []);\n}\n\n/** Check if a skill is enabled */\nexport function isSkillEnabled(skillName: string): boolean {\n return !loadDisabledSkills().includes(skillName);\n}\n\n/** Check if a specific tool's parent skill is enabled */\nexport function isToolSkillEnabled(toolName: string): boolean {\n for (const [skillName, tools] of skillToolMap.entries()) {\n if (tools.has(toolName)) {\n return isSkillEnabled(skillName);\n }\n }\n return true; // Tools not belonging to any skill are always enabled\n}\n\n/** Toggle a skill on/off. Returns the new enabled state. */\nexport function toggleSkill(skillName: string): boolean {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n let nowEnabled: boolean;\n\n if (idx >= 0) {\n disabled.splice(idx, 1);\n nowEnabled = true;\n } else {\n disabled.push(skillName);\n nowEnabled = false;\n }\n\n saveDisabledSkills(disabled);\n logger.info(COMPONENT, `Skill \"${skillName}\" ${nowEnabled ? 'enabled' : 'disabled'}`);\n return nowEnabled;\n}\n\n/** Set a skill's enabled state explicitly */\nexport function setSkillEnabled(skillName: string, enabled: boolean): void {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n\n if (enabled && idx >= 0) {\n disabled.splice(idx, 1);\n } else if (!enabled && idx < 0) {\n disabled.push(skillName);\n }\n\n saveDisabledSkills(disabled);\n}\n\n/** Load disabled skills list from disk */\nfunction loadDisabledSkills(): string[] {\n try {\n if (existsSync(DISABLED_SKILLS_PATH)) {\n return JSON.parse(readFileSync(DISABLED_SKILLS_PATH, 'utf-8')) as string[];\n }\n } catch {\n // Corrupt file — treat as empty\n }\n return [];\n}\n\n/** Save disabled skills list to disk */\nfunction saveDisabledSkills(disabled: string[]): void {\n try {\n const dir = dirname(DISABLED_SKILLS_PATH);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(DISABLED_SKILLS_PATH, JSON.stringify(disabled, null, 2), 'utf-8');\n } catch (e) {\n logger.warn(COMPONENT, `Failed to save disabled skills: ${(e as Error).message}`);\n }\n}\n\n/** Discover workspace skills from ~/.titan/workspace/skills/ */\nexport function discoverWorkspaceSkills(): SkillMeta[] {\n ensureDir(TITAN_SKILLS_DIR);\n const discovered: SkillMeta[] = [];\n\n if (!existsSync(TITAN_SKILLS_DIR)) return discovered;\n\n const entries = readdirSync(TITAN_SKILLS_DIR, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillDir = join(TITAN_SKILLS_DIR, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n\n if (!existsSync(skillMdPath)) continue;\n\n try {\n const content = readFileSync(skillMdPath, 'utf-8');\n const meta = parseSkillMd(content, entry.name);\n if (meta) {\n discovered.push({ ...meta, source: 'workspace', enabled: true });\n }\n } catch (error) {\n logger.warn(COMPONENT, `Failed to load skill ${entry.name}: ${(error as Error).message}`);\n }\n }\n\n logger.info(COMPONENT, `Discovered ${discovered.length} workspace skills`);\n return discovered;\n}\n\n/** Parse SKILL.md frontmatter to extract metadata */\nfunction parseSkillMd(content: string, fallbackName: string): Omit<SkillMeta, 'source' | 'enabled'> | null {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!frontmatterMatch) {\n return {\n name: fallbackName,\n description: content.split('\\n')[0] || 'No description',\n version: '1.0.0',\n };\n }\n\n const frontmatter = frontmatterMatch[1];\n const name = frontmatter.match(/name:\\s*(.+)/)?.[1]?.trim() || fallbackName;\n const description = frontmatter.match(/description:\\s*(.+)/)?.[1]?.trim() || 'No description';\n const version = frontmatter.match(/version:\\s*(.+)/)?.[1]?.trim() || '1.0.0';\n const author = frontmatter.match(/author:\\s*(.+)/)?.[1]?.trim();\n\n return { name, description, version, author };\n}\n\n/** Initialize all built-in skills */\nexport async function initBuiltinSkills(): Promise<void> {\n logger.info(COMPONENT, 'Loading built-in skills...');\n\n // Import and register built-in skills\n const { registerShellSkill } = await import('./builtin/shell.js');\n const { registerFilesystemSkill } = await import('./builtin/filesystem.js');\n const { registerWebSearchSkill } = await import('./builtin/web_search.js');\n const { registerCronSkill } = await import('./builtin/cron.js');\n const { registerWebhookSkill } = await import('./builtin/webhook.js');\n const { registerMemorySkill } = await import('./builtin/memory_skill.js');\n const { registerBrowserSkill } = await import('./builtin/browser.js');\n const { registerSessionsSkill } = await import('./builtin/sessions.js');\n const { registerProcessSkill } = await import('./builtin/process.js');\n const { registerWebFetchSkill } = await import('./builtin/web_fetch.js');\n const { registerApplyPatchSkill } = await import('./builtin/apply_patch.js');\n const { registerAutoGenerateSkill } = await import('./builtin/auto_generate.js');\n const { registerVisionSkill } = await import('./builtin/vision.js');\n const { registerVoiceSkills } = await import('./builtin/voice.js');\n const { registerMemoryGraphSkill } = await import('./builtin/memory_graph.js');\n const { initWebBrowserTool } = await import('./builtin/web_browser.js');\n const { registerGitHubSkill } = await import('./builtin/github.js');\n const { registerEmailSkill } = await import('./builtin/email.js');\n const { registerComputerUseSkill } = await import('./builtin/computer_use.js');\n const { registerImageGenSkill } = await import('./builtin/image_gen.js');\n const { registerPdfSkill } = await import('./builtin/pdf.js');\n const { registerCalendarSkill } = await import('./builtin/calendar.js');\n const { registerSmartHomeSkill } = await import('./builtin/smart_home.js');\n const { registerDataAnalysisSkill } = await import('./builtin/data_analysis.js');\n const { registerSkyvernSkill } = await import('./builtin/skyvern.js');\n const { registerWebBrowseLlmSkill } = await import('./builtin/web_browse_llm.js');\n const { registerIncomeTrackerSkill } = await import('./builtin/income_tracker.js');\n const { registerFreelanceMonitorSkill } = await import('./builtin/freelance_monitor.js');\n const { registerContentPublisherSkill } = await import('./builtin/content_publisher.js');\n const { registerLeadScorerSkill } = await import('./builtin/lead_scorer.js');\n const { registerHunterSkill } = await import('./builtin/hunter.js');\n const { registerCodeExecSkill } = await import('./builtin/code_exec.js');\n const { registerExecuteCodeSkill } = await import('./builtin/executeCode.js');\n const { registerWeatherSkill } = await import('./builtin/weather.js');\n const { registerGoalsSkill } = await import('./builtin/goals.js');\n const { registerXPosterSkill } = await import('./builtin/x_poster.js');\n const { initModelSwitchTool } = await import('./builtin/model_switch.js');\n const { registerRagSkill } = await import('./builtin/rag.js');\n const { registerDeepResearchSkill } = await import('./builtin/deep_research.js');\n const { registerSystemInfoSkill } = await import('./builtin/system_info.js');\n const { registerPersonaManagerSkill } = await import('./builtin/persona_manager.js');\n const { registerResearchPipelineSkill } = await import('./builtin/research_pipeline.js');\n const { registerAutoresearchSkill } = await import('./builtin/autoresearch.js');\n const { registerSelfDoctorSkill } = await import('./builtin/self_doctor.js');\n const { registerInteractionTrackerSkill } = await import('./builtin/interaction_tracker.js');\n const { registerFeedbackTrackerSkill } = await import('./builtin/feedback_tracker.js');\n const { registerGrowthExperimentsSkill } = await import('./builtin/growth_experiments.js');\n const { registerContentCalendarSkill } = await import('./builtin/content_calendar.js');\n const { registerSlackSkill } = await import('./builtin/slack.js');\n const { registerRevenueCatKBSkill } = await import('./builtin/revenuecat_kb.js');\n const { registerWeeklyReportSkill } = await import('./builtin/weekly_report.js');\n const { registerSelfImproveSkill } = await import('./builtin/self_improve.js');\n const { registerGepaSkill } = await import('./builtin/gepa.js');\n const { registerModelTrainerSkill } = await import('./builtin/model_trainer.js');\n const { registerSocialSchedulerSkill } = await import('./builtin/social_scheduler.js');\n const { registerStructuredOutputSkill } = await import('./builtin/structured_output.js');\n const { registerWorkflowsSkill } = await import('./builtin/workflows.js');\n const { registerAgentHandoffSkill } = await import('./builtin/agent_handoff.js');\n const { registerKnowledgeBaseSkill } = await import('./builtin/knowledge_base.js');\n const { registerEventTriggersSkill } = await import('./builtin/event_triggers.js');\n const { registerA2AProtocolSkill } = await import('./builtin/a2a_protocol.js');\n const { registerEvalsSkill } = await import('./builtin/evals.js');\n const { registerApprovalGatesSkill } = await import('./builtin/approval_gates.js');\n const { registerVRAMSkills } = await import('./builtin/vram.js');\n const { registerSecurityScanSkill } = await import('./builtin/security_scan.js');\n const { registerChangelogGenSkill } = await import('./builtin/changelog_gen.js');\n const { registerJiraLinearSkill } = await import('./builtin/jira_linear.js');\n const { registerAuditTrailSkill } = await import('./builtin/audit_trail.js');\n const { registerVisualPlanSkill } = await import('./builtin/visual_plan.js');\n const { registerScreenRecordSkill } = await import('./builtin/screen_record.js');\n const { registerSessionTeleportSkill } = await import('./builtin/session_teleport.js');\n const { registerCrossProviderSkill } = await import('./builtin/cross_provider.js');\n const { registerSentrySkill } = await import('./builtin/sentry.js');\n const { registerVideoSkill } = await import('./builtin/video.js');\n const { registerMixtureOfAgentsSkill } = await import('./builtin/mixture_of_agents.js');\n const { registerAgentDebateSkill } = await import('./builtin/agent_debate.js');\n const { registerFileCheckpointsSkill } = await import('./builtin/file_checkpoints.js');\n const { registerVerifyPageSkill } = await import('./builtin/verify_page.js');\n const { registerAgentMessagingSkill } = await import('./builtin/agent_messaging.js');\n const { registerFacebookSkill } = await import('./builtin/facebook.js');\n const { registerFBAutopilotSkill } = await import('./builtin/fb_autopilot.js');\n const { registerWidgetGallerySkill } = await import('./builtin/widget_gallery.js');\n\n const registrations: [string, () => void][] = [\n ['shell', registerShellSkill],\n ['filesystem', registerFilesystemSkill],\n ['web_search', registerWebSearchSkill],\n ['cron', registerCronSkill],\n ['webhook', registerWebhookSkill],\n ['memory', registerMemorySkill],\n ['browser', registerBrowserSkill],\n ['sessions', registerSessionsSkill],\n ['process', registerProcessSkill],\n ['web_fetch', registerWebFetchSkill],\n ['apply_patch', registerApplyPatchSkill],\n ['auto_generate', registerAutoGenerateSkill],\n ['vision', registerVisionSkill],\n ['voice', registerVoiceSkills],\n ['memory_graph', registerMemoryGraphSkill],\n ['web_browser', initWebBrowserTool],\n ['github', registerGitHubSkill],\n ['email', registerEmailSkill],\n ['computer_use', registerComputerUseSkill],\n ['image_gen', registerImageGenSkill],\n ['pdf', registerPdfSkill],\n ['calendar', registerCalendarSkill],\n ['smart_home', registerSmartHomeSkill],\n ['data_analysis', registerDataAnalysisSkill],\n ['skyvern', registerSkyvernSkill],\n ['web_browse_llm', registerWebBrowseLlmSkill],\n ['income_tracker', registerIncomeTrackerSkill],\n ['freelance_monitor', registerFreelanceMonitorSkill],\n ['content_publisher', registerContentPublisherSkill],\n ['lead_scorer', registerLeadScorerSkill],\n ['hunter', registerHunterSkill],\n ['code_exec', registerCodeExecSkill],\n ['execute_code', registerExecuteCodeSkill],\n ['weather', registerWeatherSkill],\n ['goals', registerGoalsSkill],\n ['x_poster', registerXPosterSkill],\n ['model_switch', initModelSwitchTool],\n ['rag', registerRagSkill],\n ['deep_research', registerDeepResearchSkill],\n ['system_info', registerSystemInfoSkill],\n ['persona_manager', registerPersonaManagerSkill],\n ['research_pipeline', registerResearchPipelineSkill],\n ['autoresearch', registerAutoresearchSkill],\n ['self_doctor', registerSelfDoctorSkill],\n ['interaction_tracker', registerInteractionTrackerSkill],\n ['feedback_tracker', registerFeedbackTrackerSkill],\n ['growth_experiments', registerGrowthExperimentsSkill],\n ['content_calendar', registerContentCalendarSkill],\n ['slack', registerSlackSkill],\n ['revenuecat_kb', registerRevenueCatKBSkill],\n ['weekly_report', registerWeeklyReportSkill],\n ['self_improve', registerSelfImproveSkill],\n ['gepa', registerGepaSkill],\n ['model_trainer', registerModelTrainerSkill],\n ['social_scheduler', registerSocialSchedulerSkill],\n ['structured_output', registerStructuredOutputSkill],\n ['workflows', registerWorkflowsSkill],\n ['agent_handoff', registerAgentHandoffSkill],\n ['knowledge_base', registerKnowledgeBaseSkill],\n ['event_triggers', registerEventTriggersSkill],\n ['evals', registerEvalsSkill],\n ['a2a_protocol', registerA2AProtocolSkill],\n ['approval_gates', registerApprovalGatesSkill],\n ['vram', registerVRAMSkills],\n ['security_scan', registerSecurityScanSkill],\n ['changelog_gen', registerChangelogGenSkill],\n ['jira_linear', registerJiraLinearSkill],\n ['audit_trail', registerAuditTrailSkill],\n ['visual_plan', registerVisualPlanSkill],\n ['screen_record', registerScreenRecordSkill],\n ['session_teleport', registerSessionTeleportSkill],\n ['cross_provider', registerCrossProviderSkill],\n ['sentry', registerSentrySkill],\n ['video', registerVideoSkill],\n ['mixture_of_agents', registerMixtureOfAgentsSkill],\n ['agent_debate', registerAgentDebateSkill],\n ['file_checkpoints', registerFileCheckpointsSkill],\n ['verify_page', registerVerifyPageSkill],\n ['agent_messaging', registerAgentMessagingSkill],\n ['facebook', registerFacebookSkill],\n ['fb_autopilot', registerFBAutopilotSkill],\n ['widget_gallery', registerWidgetGallerySkill],\n ];\n\n for (const [name, fn] of registrations) {\n try { fn(); } catch (e) { logger.warn(COMPONENT, `Failed to register skill \"${name}\": ${(e as Error).message}`); }\n }\n\n // Register planner as an LLM-invocable tool\n const { registerPlannerTool } = await import('../agent/planner.js');\n try { registerPlannerTool(); } catch (e) { logger.warn(COMPONENT, `Failed to register planner: ${(e as Error).message}`); }\n\n // Register TopFacts context engine plugin (DeerFlow-inspired persistent memory)\n try {\n const { createTopFactsPlugin } = await import('../plugins/topFacts.js');\n const { createMemoryRetrievalPlugin } = await import('../plugins/memoryRetrieval.js');\n const { registerPlugin } = await import('../plugins/registry.js');\n const topFacts = createTopFactsPlugin();\n registerPlugin(topFacts);\n if (topFacts.bootstrap) await topFacts.bootstrap({});\n const memoryRetrieval = createMemoryRetrievalPlugin();\n registerPlugin(memoryRetrieval);\n if (memoryRetrieval.bootstrap) await memoryRetrieval.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register TopFacts plugin: ${(e as Error).message}`); }\n\n // Register SmartCompress context engine plugin (task-type-aware compression)\n try {\n const { createSmartCompressPlugin } = await import('../plugins/smartCompress.js');\n const { registerPlugin: regPlugin } = await import('../plugins/registry.js');\n const smartCompress = createSmartCompressPlugin();\n regPlugin(smartCompress);\n if (smartCompress.bootstrap) await smartCompress.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register SmartCompress plugin: ${(e as Error).message}`); }\n\n // Register tool_search + tool_expand — meta-tools for discovering tools on demand\n // tool_expand is the progressive disclosure extension (Hermes competitive gap fix)\n const { getToolSearchHandler, getToolExpandHandler } = await import('../agent/toolSearch.js');\n try { registerTool(getToolSearchHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_search: ${(e as Error).message}`); }\n try { registerTool(getToolExpandHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_expand: ${(e as Error).message}`); }\n\n // F3: Register procedural memory tools (Hermes-inspired skill learning)\n try {\n const { saveSkill, searchSkills } = await import('./proceduralMemory.js');\n registerTool({\n name: 'save_skill',\n description: 'Save a reusable approach/technique as a procedural skill for future tasks. Use this when you discover an effective approach that could help in similar future situations.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Short descriptive name for the skill (e.g., \"Deploy Node.js app to Docker\")' },\n tags: { type: 'array', items: { type: 'string' }, description: 'Tags for searchability (e.g., [\"docker\", \"deployment\", \"nodejs\"])' },\n content: { type: 'string', description: 'The reusable approach/technique in markdown format. Include key steps, commands, and gotchas.' },\n },\n required: ['name', 'tags', 'content'],\n },\n execute: async (args: Record<string, unknown>) => {\n const name = args.name as string;\n const tags = (args.tags as string[]) || [];\n const content = args.content as string;\n if (!name || !content) return 'Error: name and content are required';\n const skill = saveSkill(name, tags, content);\n return `Skill saved: \"${skill.name}\" (tags: ${skill.tags.join(', ')}). It will be auto-recalled in future tasks matching these tags.`;\n },\n });\n registerTool({\n name: 'recall_skill',\n description: 'Search for previously saved procedural skills by keyword or tag. Returns reusable approaches from past tasks.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query — keywords or tags to find relevant skills' },\n },\n required: ['query'],\n },\n execute: async (args: Record<string, unknown>) => {\n const query = args.query as string;\n if (!query) return 'Error: query is required';\n const results = searchSkills(query, 5);\n if (results.length === 0) return 'No matching skills found. Consider saving useful approaches with save_skill.';\n return results.map(s =>\n `### ${s.name}\\nTags: ${s.tags.join(', ')} | Used ${s.useCount}x\\n${s.content.slice(0, 800)}`\n ).join('\\n\\n---\\n\\n');\n },\n });\n logger.info(COMPONENT, 'Registered procedural memory tools (save_skill, recall_skill)');\n } catch (e) { logger.warn(COMPONENT, `Failed to register procedural memory tools: ${(e as Error).message}`); }\n\n logger.info(COMPONENT, `Loaded ${registeredSkills.size} built-in skills`);\n\n // Load dev skills (only in dev mode — skip import entirely in production)\n if (process.env.NODE_ENV !== 'production' || process.env.TITAN_DEV) {\n const { initDevSkills } = await import('./dev/loader.js');\n await initDevSkills();\n }\n\n // Load NVIDIA skills (optional — only when TITAN_NVIDIA=1 or nvidia.enabled in config)\n try {\n let nvidiaEnabled = process.env.TITAN_NVIDIA === '1';\n if (!nvidiaEnabled) {\n try {\n const { loadConfig: _loadConfig } = await import('../config/config.js');\n const cfg = _loadConfig() as Record<string, unknown>;\n const nvCfg = cfg.nvidia as Record<string, unknown> | undefined;\n nvidiaEnabled = nvCfg?.enabled === true;\n } catch { /* config not available in test env */ }\n }\n if (nvidiaEnabled) {\n const { initNvidiaSkills } = await import('./nvidia/loader.js');\n await initNvidiaSkills();\n }\n } catch (err) {\n logger.warn(COMPONENT, `NVIDIA skills failed to load: ${(err as Error).message}`);\n }\n\n // Load personal skills (private, gitignored — only when TITAN_PERSONAL=1)\n // Primary location: dist/skills/personal/loader.js (co-located with dist/skills/registry.js\n // so `../registry` resolves to the SAME module instance — tools register into the correct registry)\n // Fallback: ~/.titan/personal/loader.js (legacy / TITAN_PERSONAL_DIR override)\n if (process.env.TITAN_PERSONAL === '1') {\n try {\n const { pathToFileURL, fileURLToPath } = await import('node:url');\n const { join: _join, dirname: _dirname } = await import('node:path');\n // Compute dist/skills/ dir from this file's location (works on any machine)\n const thisDir = _dirname(fileURLToPath(import.meta.url));\n const distPersonalDir = _join(thisDir, 'personal');\n // TITAN_PERSONAL_DIR env var overrides; otherwise try dist-local first, then ~/.titan/personal/\n const personalDir = process.env.TITAN_PERSONAL_DIR\n || (existsSync(_join(distPersonalDir, 'loader.js')) ? distPersonalDir : _join(TITAN_HOME, 'personal'));\n const loaderPath = _join(personalDir, 'loader.js');\n if (existsSync(loaderPath)) {\n // Inject the main app's registerSkill into a global so the personal bundle\n // (which has its own bundled copy) uses the correct shared toolRegistry instance.\n (globalThis as Record<string, unknown>).__titanRegisterSkill = registerSkill;\n const { initPersonalSkills } = await import(pathToFileURL(loaderPath).href) as { initPersonalSkills: () => Promise<void> };\n await initPersonalSkills();\n } else {\n logger.warn(COMPONENT, `TITAN_PERSONAL=1 but ${loaderPath} not found — run: npm run build:personal`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `Personal skills failed to load: ${(err as Error).message}`);\n }\n }\n}\n\n/**\n * Discover and load user skills from ~/.titan/skills/ (all subdirs).\n * Supports:\n * 1. JavaScript files (.js) that export default { name, description, parameters, execute }\n * 2. YAML skill definitions (.yaml/.yml) with inline scripts\n * 3. Auto-generated skills from ~/.titan/skills/auto/\n */\nexport async function loadAutoSkills(): Promise<void> {\n const skillsRoot = join(TITAN_HOME, 'skills');\n if (!existsSync(skillsRoot)) return;\n\n logger.info(COMPONENT, 'Scanning for user skills...');\n let loadedCount = 0;\n\n // Scan both root and all subdirectories\n const dirsToScan = [skillsRoot];\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) dirsToScan.push(join(skillsRoot, entry.name));\n }\n\n for (const dir of dirsToScan) {\n const files = readdirSync(dir).filter(f =>\n f.endsWith('.js') || f.endsWith('.yaml') || f.endsWith('.yml')\n );\n\n for (const file of files) {\n const filePath = join(dir, file);\n try {\n if (file.endsWith('.js')) {\n // JavaScript skill — export default { name, description, parameters, execute }\n const modulePath = `file://${filePath}?t=${Date.now()}`;\n const mod = await import(modulePath);\n if (mod.default && mod.default.name && mod.default.execute) {\n const handler = mod.default as ToolHandler;\n if (registeredSkills.has(handler.name)) continue; // Skip duplicates\n registerSkill({\n name: handler.name,\n description: handler.description || 'User skill',\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n } else {\n // YAML skill definition\n const loaded = loadYamlSkill(filePath);\n if (loaded && !registeredSkills.has(loaded.name)) {\n registerSkill({\n name: loaded.name,\n description: loaded.description,\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, loaded);\n loadedCount++;\n }\n }\n } catch (e: unknown) {\n logger.warn(COMPONENT, `Failed to load skill ${file}: ${(e as Error).message}`);\n }\n }\n }\n\n if (loadedCount > 0) {\n logger.info(COMPONENT, `Loaded ${loadedCount} user skill(s) from ~/.titan/skills/`);\n }\n\n // Load frontmatter skills (*.skill.md) — Space Agent / Hermes parity\n try {\n const { getFrontmatterToolHandlers } = await import('./frontmatterLoader.js');\n const fmHandlers = getFrontmatterToolHandlers();\n for (const { name, handler } of fmHandlers) {\n if (registeredSkills.has(name)) continue;\n registerSkill({\n name: handler.name,\n description: handler.description,\n version: '1.0.0',\n source: 'frontmatter',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n if (fmHandlers.length > 0) {\n logger.info(COMPONENT, `Loaded ${fmHandlers.length} frontmatter skill(s)`);\n }\n } catch (e) {\n logger.warn(COMPONENT, `Frontmatter skills failed to load: ${(e as Error).message}`);\n }\n}\n\n/**\n * Load a YAML skill definition.\n * Format:\n * name: my_tool\n * description: What it does\n * parameters:\n * myParam:\n * type: string\n * description: A parameter\n * required: true\n * script: |\n * // JavaScript code. Use `args.myParam` for inputs.\n * // Return a string result.\n * return \"Hello \" + args.myParam;\n */\nfunction loadYamlSkill(filePath: string): ToolHandler | null {\n const content = readFileSync(filePath, 'utf-8');\n\n // Simple YAML parser (no dependency needed for this basic format)\n const name = content.match(/^name:\\s*(.+)$/m)?.[1]?.trim();\n const description = content.match(/^description:\\s*(.+)$/m)?.[1]?.trim();\n const scriptMatch = content.match(/^script:\\s*\\|\\n([\\s\\S]+?)(?=\\n\\w|\\n$|$)/m);\n const script = scriptMatch?.[1]?.replace(/^ {2}/gm, ''); // Remove YAML indent\n\n if (!name || !description || !script) {\n logger.debug(COMPONENT, `Skipping ${filePath}: missing name, description, or script`);\n return null;\n }\n\n // Parse parameters section\n const paramsSection = content.match(/^parameters:\\n((?:\\s{2}\\w[\\s\\S]*?)(?=\\nscript:|\\n\\w|\\n$))/m);\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n\n if (paramsSection) {\n const paramLines = paramsSection[1].split('\\n');\n let currentParam = '';\n for (const line of paramLines) {\n const paramMatch = line.match(/^\\s{2}(\\w+):\\s*$/);\n if (paramMatch) {\n currentParam = paramMatch[1];\n properties[currentParam] = {};\n continue;\n }\n if (currentParam) {\n const typeMatch = line.match(/^\\s{4}type:\\s*(.+)$/);\n const descMatch = line.match(/^\\s{4}description:\\s*(.+)$/);\n const reqMatch = line.match(/^\\s{4}required:\\s*true$/);\n const defMatch = line.match(/^\\s{4}default:\\s*(.+)$/);\n if (typeMatch) properties[currentParam].type = typeMatch[1].trim();\n if (descMatch) properties[currentParam].description = descMatch[1].trim();\n if (reqMatch) required.push(currentParam);\n if (defMatch) properties[currentParam].default = defMatch[1].trim();\n }\n }\n }\n\n // Create the execute function from the script\n const handler: ToolHandler = {\n name,\n description,\n parameters: {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined,\n },\n execute: async (args: Record<string, unknown>) => {\n try {\n // Run in a restricted VM context — no access to globalThis, process, eval, or Function\n const safeRequire = (mod: string) => {\n // SECURITY: child_process, http, https removed — YAML skills must use builtin tools for shell/network\n const allowed = ['fs', 'path', 'os', 'crypto', 'url', 'util'];\n if (!allowed.includes(mod)) throw new Error(`Module \"${mod}\" not allowed in YAML skills`);\n return require(mod); // eslint-disable-line @typescript-eslint/no-require-imports\n };\n const sandbox: Record<string, unknown> = {\n args,\n require: safeRequire,\n console: { log: console.log },\n JSON,\n Math,\n Date,\n String,\n Number,\n Array,\n Object,\n RegExp,\n Map,\n Set,\n Promise,\n setTimeout,\n Buffer,\n };\n // Wrap the user script in an async IIFE so `return` works and we can await it\n const wrapped = `(async function() { ${script} })()`;\n const result = await vm.runInNewContext(wrapped, sandbox, { timeout: 10000 });\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n } catch (err) {\n return `Error: ${(err as Error).message}`;\n }\n },\n };\n\n logger.debug(COMPONENT, `Loaded YAML skill: ${name} from ${filePath}`);\n return handler;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/skills/registry.ts"],"sourcesContent":["/**\n * TITAN — Skills Registry\n * Discovers, loads, and manages skills from bundled, workspace, and marketplace sources.\n */\nimport { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport vm from 'vm';\nimport { TITAN_HOME, TITAN_SKILLS_DIR } from '../utils/constants.js';\nimport { registerTool, type ToolHandler } from '../agent/toolRunner.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport logger from '../utils/logger.js';\nimport { loadConfig } from '../config/config.js';\n\nconst COMPONENT = 'Skills';\nconst DISABLED_SKILLS_PATH = join(TITAN_HOME, 'disabled-skills.json');\n\nexport interface SkillMeta {\n name: string;\n description: string;\n version: string;\n author?: string;\n source: 'bundled' | 'workspace' | 'marketplace' | 'frontmatter';\n enabled: boolean;\n}\n\nconst registeredSkills: Map<string, SkillMeta> = new Map();\n\n/** Maps skill name → tool names belonging to that skill */\nconst skillToolMap: Map<string, Set<string>> = new Map();\n\n/** Register a built-in skill (tool handler + metadata) */\nexport function registerSkill(meta: SkillMeta, handler: ToolHandler): void {\n registeredSkills.set(meta.name, meta);\n // Track which tools belong to this skill\n if (!skillToolMap.has(meta.name)) {\n skillToolMap.set(meta.name, new Set());\n }\n skillToolMap.get(meta.name)!.add(handler.name);\n registerTool(handler);\n logger.debug(COMPONENT, `Registered skill: ${meta.name} (${meta.source})`);\n}\n\n/** Get all registered skills (with persisted enabled/disabled state applied) */\nexport function getSkills(): SkillMeta[] {\n const disabled = loadDisabledSkills();\n return Array.from(registeredSkills.values()).map(s => ({\n ...s,\n enabled: !disabled.includes(s.name),\n }));\n}\n\n/** Get a skill by name */\nexport function getSkill(name: string): SkillMeta | undefined {\n return registeredSkills.get(name);\n}\n\n/** Get tool names belonging to a skill */\nexport function getSkillTools(skillName: string): string[] {\n return Array.from(skillToolMap.get(skillName) || []);\n}\n\n/** Check if a skill is enabled */\nexport function isSkillEnabled(skillName: string): boolean {\n return !loadDisabledSkills().includes(skillName);\n}\n\n/** Check if a specific tool's parent skill is enabled */\nexport function isToolSkillEnabled(toolName: string): boolean {\n for (const [skillName, tools] of skillToolMap.entries()) {\n if (tools.has(toolName)) {\n return isSkillEnabled(skillName);\n }\n }\n return true; // Tools not belonging to any skill are always enabled\n}\n\n/** Toggle a skill on/off. Returns the new enabled state. */\nexport function toggleSkill(skillName: string): boolean {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n let nowEnabled: boolean;\n\n if (idx >= 0) {\n disabled.splice(idx, 1);\n nowEnabled = true;\n } else {\n disabled.push(skillName);\n nowEnabled = false;\n }\n\n saveDisabledSkills(disabled);\n logger.info(COMPONENT, `Skill \"${skillName}\" ${nowEnabled ? 'enabled' : 'disabled'}`);\n return nowEnabled;\n}\n\n/** Set a skill's enabled state explicitly */\nexport function setSkillEnabled(skillName: string, enabled: boolean): void {\n const skill = registeredSkills.get(skillName);\n if (!skill) {\n throw new Error(`Skill \"${skillName}\" not found`);\n }\n\n const disabled = loadDisabledSkills();\n const idx = disabled.indexOf(skillName);\n\n if (enabled && idx >= 0) {\n disabled.splice(idx, 1);\n } else if (!enabled && idx < 0) {\n disabled.push(skillName);\n }\n\n saveDisabledSkills(disabled);\n}\n\n/** Load disabled skills list from disk */\nfunction loadDisabledSkills(): string[] {\n try {\n if (existsSync(DISABLED_SKILLS_PATH)) {\n return JSON.parse(readFileSync(DISABLED_SKILLS_PATH, 'utf-8')) as string[];\n }\n } catch {\n // Corrupt file — treat as empty\n }\n return [];\n}\n\n/** Save disabled skills list to disk */\nfunction saveDisabledSkills(disabled: string[]): void {\n try {\n const dir = dirname(DISABLED_SKILLS_PATH);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(DISABLED_SKILLS_PATH, JSON.stringify(disabled, null, 2), 'utf-8');\n } catch (e) {\n logger.warn(COMPONENT, `Failed to save disabled skills: ${(e as Error).message}`);\n }\n}\n\n/** Discover workspace skills from ~/.titan/workspace/skills/ */\nexport function discoverWorkspaceSkills(): SkillMeta[] {\n ensureDir(TITAN_SKILLS_DIR);\n const discovered: SkillMeta[] = [];\n\n if (!existsSync(TITAN_SKILLS_DIR)) return discovered;\n\n const entries = readdirSync(TITAN_SKILLS_DIR, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillDir = join(TITAN_SKILLS_DIR, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n\n if (!existsSync(skillMdPath)) continue;\n\n try {\n const content = readFileSync(skillMdPath, 'utf-8');\n const meta = parseSkillMd(content, entry.name);\n if (meta) {\n discovered.push({ ...meta, source: 'workspace', enabled: true });\n }\n } catch (error) {\n logger.warn(COMPONENT, `Failed to load skill ${entry.name}: ${(error as Error).message}`);\n }\n }\n\n logger.info(COMPONENT, `Discovered ${discovered.length} workspace skills`);\n return discovered;\n}\n\n/** Parse SKILL.md frontmatter to extract metadata */\nfunction parseSkillMd(content: string, fallbackName: string): Omit<SkillMeta, 'source' | 'enabled'> | null {\n const frontmatterMatch = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!frontmatterMatch) {\n return {\n name: fallbackName,\n description: content.split('\\n')[0] || 'No description',\n version: '1.0.0',\n };\n }\n\n const frontmatter = frontmatterMatch[1];\n const name = frontmatter.match(/name:\\s*(.+)/)?.[1]?.trim() || fallbackName;\n const description = frontmatter.match(/description:\\s*(.+)/)?.[1]?.trim() || 'No description';\n const version = frontmatter.match(/version:\\s*(.+)/)?.[1]?.trim() || '1.0.0';\n const author = frontmatter.match(/author:\\s*(.+)/)?.[1]?.trim();\n\n return { name, description, version, author };\n}\n\n/** Initialize all built-in skills */\nexport async function initBuiltinSkills(): Promise<void> {\n logger.info(COMPONENT, 'Loading built-in skills...');\n\n // Import and register built-in skills\n const { registerShellSkill } = await import('./builtin/shell.js');\n const { registerFilesystemSkill } = await import('./builtin/filesystem.js');\n const { registerWebSearchSkill } = await import('./builtin/web_search.js');\n const { registerCronSkill } = await import('./builtin/cron.js');\n const { registerWebhookSkill } = await import('./builtin/webhook.js');\n const { registerMemorySkill } = await import('./builtin/memory_skill.js');\n const { registerBrowserSkill } = await import('./builtin/browser.js');\n const { registerSessionsSkill } = await import('./builtin/sessions.js');\n const { registerProcessSkill } = await import('./builtin/process.js');\n const { registerWebFetchSkill } = await import('./builtin/web_fetch.js');\n const { registerApplyPatchSkill } = await import('./builtin/apply_patch.js');\n const { registerAutoGenerateSkill } = await import('./builtin/auto_generate.js');\n const { registerVisionSkill } = await import('./builtin/vision.js');\n const { registerVoiceSkills } = await import('./builtin/voice.js');\n const { registerMemoryGraphSkill } = await import('./builtin/memory_graph.js');\n const { initWebBrowserTool } = await import('./builtin/web_browser.js');\n const { registerGitHubSkill } = await import('./builtin/github.js');\n const { registerEmailSkill } = await import('./builtin/email.js');\n const { registerComputerUseSkill } = await import('./builtin/computer_use.js');\n const { registerImageGenSkill } = await import('./builtin/image_gen.js');\n const { registerPdfSkill } = await import('./builtin/pdf.js');\n const { registerCalendarSkill } = await import('./builtin/calendar.js');\n const { registerSmartHomeSkill } = await import('./builtin/smart_home.js');\n const { registerDataAnalysisSkill } = await import('./builtin/data_analysis.js');\n const { registerSkyvernSkill } = await import('./builtin/skyvern.js');\n const { registerWebBrowseLlmSkill } = await import('./builtin/web_browse_llm.js');\n const { registerIncomeTrackerSkill } = await import('./builtin/income_tracker.js');\n const { registerFreelanceMonitorSkill } = await import('./builtin/freelance_monitor.js');\n const { registerContentPublisherSkill } = await import('./builtin/content_publisher.js');\n const { registerLeadScorerSkill } = await import('./builtin/lead_scorer.js');\n const { registerHunterSkill } = await import('./builtin/hunter.js');\n const { registerCodeExecSkill } = await import('./builtin/code_exec.js');\n const { registerExecuteCodeSkill } = await import('./builtin/executeCode.js');\n const { registerWeatherSkill } = await import('./builtin/weather.js');\n const { registerGoalsSkill } = await import('./builtin/goals.js');\n const { registerXPosterSkill } = await import('./builtin/x_poster.js');\n const { initModelSwitchTool } = await import('./builtin/model_switch.js');\n const { registerRagSkill } = await import('./builtin/rag.js');\n const { registerDeepResearchSkill } = await import('./builtin/deep_research.js');\n const { registerSystemInfoSkill } = await import('./builtin/system_info.js');\n const { registerPersonaManagerSkill } = await import('./builtin/persona_manager.js');\n const { registerResearchPipelineSkill } = await import('./builtin/research_pipeline.js');\n const { registerAutoresearchSkill } = await import('./builtin/autoresearch.js');\n const { registerSelfDoctorSkill } = await import('./builtin/self_doctor.js');\n const { registerInteractionTrackerSkill } = await import('./builtin/interaction_tracker.js');\n const { registerFeedbackTrackerSkill } = await import('./builtin/feedback_tracker.js');\n const { registerGrowthExperimentsSkill } = await import('./builtin/growth_experiments.js');\n const { registerContentCalendarSkill } = await import('./builtin/content_calendar.js');\n const { registerSlackSkill } = await import('./builtin/slack.js');\n const { registerRevenueCatKBSkill } = await import('./builtin/revenuecat_kb.js');\n const { registerWeeklyReportSkill } = await import('./builtin/weekly_report.js');\n const { registerSelfImproveSkill } = await import('./builtin/self_improve.js');\n const { registerGepaSkill } = await import('./builtin/gepa.js');\n const { registerModelTrainerSkill } = await import('./builtin/model_trainer.js');\n const { registerSocialSchedulerSkill } = await import('./builtin/social_scheduler.js');\n const { registerStructuredOutputSkill } = await import('./builtin/structured_output.js');\n const { registerWorkflowsSkill } = await import('./builtin/workflows.js');\n const { registerAgentHandoffSkill } = await import('./builtin/agent_handoff.js');\n const { registerKnowledgeBaseSkill } = await import('./builtin/knowledge_base.js');\n const { registerEventTriggersSkill } = await import('./builtin/event_triggers.js');\n const { registerA2AProtocolSkill } = await import('./builtin/a2a_protocol.js');\n const { registerEvalsSkill } = await import('./builtin/evals.js');\n const { registerApprovalGatesSkill } = await import('./builtin/approval_gates.js');\n const { registerVRAMSkills } = await import('./builtin/vram.js');\n const { registerSecurityScanSkill } = await import('./builtin/security_scan.js');\n const { registerChangelogGenSkill } = await import('./builtin/changelog_gen.js');\n const { registerJiraLinearSkill } = await import('./builtin/jira_linear.js');\n const { registerAuditTrailSkill } = await import('./builtin/audit_trail.js');\n const { registerVisualPlanSkill } = await import('./builtin/visual_plan.js');\n const { registerScreenRecordSkill } = await import('./builtin/screen_record.js');\n const { registerSessionTeleportSkill } = await import('./builtin/session_teleport.js');\n const { registerCrossProviderSkill } = await import('./builtin/cross_provider.js');\n const { registerSentrySkill } = await import('./builtin/sentry.js');\n const { registerVideoSkill } = await import('./builtin/video.js');\n const { registerMixtureOfAgentsSkill } = await import('./builtin/mixture_of_agents.js');\n const { registerAgentDebateSkill } = await import('./builtin/agent_debate.js');\n const { registerFileCheckpointsSkill } = await import('./builtin/file_checkpoints.js');\n const { registerVerifyPageSkill } = await import('./builtin/verify_page.js');\n const { registerAgentMessagingSkill } = await import('./builtin/agent_messaging.js');\n const { registerFacebookSkill } = await import('./builtin/facebook.js');\n const { registerFBAutopilotSkill } = await import('./builtin/fb_autopilot.js');\n const { registerWidgetGallerySkill } = await import('./builtin/widget_gallery.js');\n\n const config = loadConfig();\n const primitiveMode = config.skills.primitiveMode;\n\n if (primitiveMode) {\n logger.info(COMPONENT, 'PRIMITIVE MODE ENABLED — loading only shell, filesystem, web_search');\n }\n\n const registrations: [string, () => void][] = [\n ['shell', registerShellSkill],\n ['filesystem', registerFilesystemSkill],\n ['web_search', registerWebSearchSkill],\n ];\n\n if (!primitiveMode) {\n registrations.push(\n ['cron', registerCronSkill],\n ['webhook', registerWebhookSkill],\n ['memory', registerMemorySkill],\n ['browser', registerBrowserSkill],\n ['sessions', registerSessionsSkill],\n ['process', registerProcessSkill],\n ['web_fetch', registerWebFetchSkill],\n ['apply_patch', registerApplyPatchSkill],\n ['auto_generate', registerAutoGenerateSkill],\n ['vision', registerVisionSkill],\n ['voice', registerVoiceSkills],\n ['memory_graph', registerMemoryGraphSkill],\n ['web_browser', initWebBrowserTool],\n ['github', registerGitHubSkill],\n ['email', registerEmailSkill],\n ['computer_use', registerComputerUseSkill],\n ['image_gen', registerImageGenSkill],\n ['pdf', registerPdfSkill],\n ['calendar', registerCalendarSkill],\n ['smart_home', registerSmartHomeSkill],\n ['data_analysis', registerDataAnalysisSkill],\n ['skyvern', registerSkyvernSkill],\n ['web_browse_llm', registerWebBrowseLlmSkill],\n ['income_tracker', registerIncomeTrackerSkill],\n ['freelance_monitor', registerFreelanceMonitorSkill],\n ['content_publisher', registerContentPublisherSkill],\n ['lead_scorer', registerLeadScorerSkill],\n ['hunter', registerHunterSkill],\n ['code_exec', registerCodeExecSkill],\n ['execute_code', registerExecuteCodeSkill],\n ['weather', registerWeatherSkill],\n ['goals', registerGoalsSkill],\n ['x_poster', registerXPosterSkill],\n ['model_switch', initModelSwitchTool],\n ['rag', registerRagSkill],\n ['deep_research', registerDeepResearchSkill],\n ['system_info', registerSystemInfoSkill],\n ['persona_manager', registerPersonaManagerSkill],\n ['research_pipeline', registerResearchPipelineSkill],\n ['autoresearch', registerAutoresearchSkill],\n ['self_doctor', registerSelfDoctorSkill],\n ['interaction_tracker', registerInteractionTrackerSkill],\n ['feedback_tracker', registerFeedbackTrackerSkill],\n ['growth_experiments', registerGrowthExperimentsSkill],\n ['content_calendar', registerContentCalendarSkill],\n ['slack', registerSlackSkill],\n ['revenuecat_kb', registerRevenueCatKBSkill],\n ['weekly_report', registerWeeklyReportSkill],\n ['self_improve', registerSelfImproveSkill],\n ['gepa', registerGepaSkill],\n ['model_trainer', registerModelTrainerSkill],\n ['social_scheduler', registerSocialSchedulerSkill],\n ['structured_output', registerStructuredOutputSkill],\n ['workflows', registerWorkflowsSkill],\n ['agent_handoff', registerAgentHandoffSkill],\n ['knowledge_base', registerKnowledgeBaseSkill],\n ['event_triggers', registerEventTriggersSkill],\n ['evals', registerEvalsSkill],\n ['a2a_protocol', registerA2AProtocolSkill],\n ['approval_gates', registerApprovalGatesSkill],\n ['vram', registerVRAMSkills],\n ['security_scan', registerSecurityScanSkill],\n ['changelog_gen', registerChangelogGenSkill],\n ['jira_linear', registerJiraLinearSkill],\n ['audit_trail', registerAuditTrailSkill],\n ['visual_plan', registerVisualPlanSkill],\n ['screen_record', registerScreenRecordSkill],\n ['session_teleport', registerSessionTeleportSkill],\n ['cross_provider', registerCrossProviderSkill],\n ['sentry', registerSentrySkill],\n ['video', registerVideoSkill],\n ['mixture_of_agents', registerMixtureOfAgentsSkill],\n ['agent_debate', registerAgentDebateSkill],\n ['file_checkpoints', registerFileCheckpointsSkill],\n ['verify_page', registerVerifyPageSkill],\n ['agent_messaging', registerAgentMessagingSkill],\n ['facebook', registerFacebookSkill],\n ['fb_autopilot', registerFBAutopilotSkill],\n ['widget_gallery', registerWidgetGallerySkill],\n ['widget_gallery', registerWidgetGallerySkill],\n );\n }\n for (const [name, fn] of registrations) {\n try { fn(); } catch (e) { logger.warn(COMPONENT, `Failed to register skill \"${name}\": ${(e as Error).message}`); }\n }\n\n if (!primitiveMode) {\n // Register planner as an LLM-invocable tool\n const { registerPlannerTool } = await import('../agent/planner.js');\n try { registerPlannerTool(); } catch (e) { logger.warn(COMPONENT, `Failed to register planner: ${(e as Error).message}`); }\n\n // Register TopFacts context engine plugin (DeerFlow-inspired persistent memory)\n try {\n const { createTopFactsPlugin } = await import('../plugins/topFacts.js');\n const { createMemoryRetrievalPlugin } = await import('../plugins/memoryRetrieval.js');\n const { registerPlugin } = await import('../plugins/registry.js');\n const topFacts = createTopFactsPlugin();\n registerPlugin(topFacts);\n if (topFacts.bootstrap) await topFacts.bootstrap({});\n const memoryRetrieval = createMemoryRetrievalPlugin();\n registerPlugin(memoryRetrieval);\n if (memoryRetrieval.bootstrap) await memoryRetrieval.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register TopFacts plugin: ${(e as Error).message}`); }\n\n // Register SmartCompress context engine plugin (task-type-aware compression)\n try {\n const { createSmartCompressPlugin } = await import('../plugins/smartCompress.js');\n const { registerPlugin: regPlugin } = await import('../plugins/registry.js');\n const smartCompress = createSmartCompressPlugin();\n regPlugin(smartCompress);\n if (smartCompress.bootstrap) await smartCompress.bootstrap({});\n } catch (e) { logger.warn(COMPONENT, `Failed to register SmartCompress plugin: ${(e as Error).message}`); }\n\n // Register tool_search + tool_expand — meta-tools for discovering tools on demand\n // tool_expand is the progressive disclosure extension (Hermes competitive gap fix)\n const { getToolSearchHandler, getToolExpandHandler } = await import('../agent/toolSearch.js');\n try { registerTool(getToolSearchHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_search: ${(e as Error).message}`); }\n try { registerTool(getToolExpandHandler()); } catch (e) { logger.warn(COMPONENT, `Failed to register tool_expand: ${(e as Error).message}`); }\n\n // F3: Register procedural memory tools (Hermes-inspired skill learning)\n try {\n const { saveSkill, searchSkills } = await import('./proceduralMemory.js');\n registerTool({\n name: 'save_skill',\n description: 'Save a reusable approach/technique as a procedural skill for future tasks. Use this when you discover an effective approach that could help in similar future situations.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Short descriptive name for the skill (e.g., \"Deploy Node.js app to Docker\")' },\n tags: { type: 'array', items: { type: 'string' }, description: 'Tags for searchability (e.g., [\"docker\", \"deployment\", \"nodejs\"])' },\n content: { type: 'string', description: 'The reusable approach/technique in markdown format. Include key steps, commands, and gotchas.' },\n },\n required: ['name', 'tags', 'content'],\n },\n execute: async (args: Record<string, unknown>) => {\n const name = args.name as string;\n const tags = (args.tags as string[]) || [];\n const content = args.content as string;\n if (!name || !content) return 'Error: name and content are required';\n const skill = saveSkill(name, tags, content);\n return `Skill saved: \"${skill.name}\" (tags: ${skill.tags.join(', ')}). It will be auto-recalled in future tasks matching these tags.`;\n },\n });\n registerTool({\n name: 'recall_skill',\n description: 'Search for previously saved procedural skills by keyword or tag. Returns reusable approaches from past tasks.',\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query — keywords or tags to find relevant skills' },\n },\n required: ['query'],\n },\n execute: async (args: Record<string, unknown>) => {\n const query = args.query as string;\n if (!query) return 'Error: query is required';\n const results = searchSkills(query, 5);\n if (results.length === 0) return 'No matching skills found. Consider saving useful approaches with save_skill.';\n return results.map(s =>\n `### ${s.name}\\nTags: ${s.tags.join(', ')} | Used ${s.useCount}x\\n${s.content.slice(0, 800)}`\n ).join('\\n\\n---\\n\\n');\n },\n });\n logger.info(COMPONENT, 'Registered procedural memory tools (save_skill, recall_skill)');\n } catch (e) { logger.warn(COMPONENT, `Failed to register procedural memory tools: ${(e as Error).message}`); }\n }\n\n logger.info(COMPONENT, `Loaded ${registeredSkills.size} built-in skills`);\n\n // Load dev skills (only in dev mode — skip import entirely in production)\n if (process.env.NODE_ENV !== 'production' || process.env.TITAN_DEV) {\n const { initDevSkills } = await import('./dev/loader.js');\n await initDevSkills();\n }\n\n // Load NVIDIA skills (optional — only when TITAN_NVIDIA=1 or nvidia.enabled in config)\n try {\n let nvidiaEnabled = process.env.TITAN_NVIDIA === '1';\n if (!nvidiaEnabled) {\n try {\n const { loadConfig: _loadConfig } = await import('../config/config.js');\n const cfg = _loadConfig() as Record<string, unknown>;\n const nvCfg = cfg.nvidia as Record<string, unknown> | undefined;\n nvidiaEnabled = nvCfg?.enabled === true;\n } catch { /* config not available in test env */ }\n }\n if (nvidiaEnabled) {\n const { initNvidiaSkills } = await import('./nvidia/loader.js');\n await initNvidiaSkills();\n }\n } catch (err) {\n logger.warn(COMPONENT, `NVIDIA skills failed to load: ${(err as Error).message}`);\n }\n\n // Load personal skills (private, gitignored — only when TITAN_PERSONAL=1)\n // Primary location: dist/skills/personal/loader.js (co-located with dist/skills/registry.js\n // so `../registry` resolves to the SAME module instance — tools register into the correct registry)\n // Fallback: ~/.titan/personal/loader.js (legacy / TITAN_PERSONAL_DIR override)\n if (process.env.TITAN_PERSONAL === '1') {\n try {\n const { pathToFileURL, fileURLToPath } = await import('node:url');\n const { join: _join, dirname: _dirname } = await import('node:path');\n // Compute dist/skills/ dir from this file's location (works on any machine)\n const thisDir = _dirname(fileURLToPath(import.meta.url));\n const distPersonalDir = _join(thisDir, 'personal');\n // TITAN_PERSONAL_DIR env var overrides; otherwise try dist-local first, then ~/.titan/personal/\n const personalDir = process.env.TITAN_PERSONAL_DIR\n || (existsSync(_join(distPersonalDir, 'loader.js')) ? distPersonalDir : _join(TITAN_HOME, 'personal'));\n const loaderPath = _join(personalDir, 'loader.js');\n if (existsSync(loaderPath)) {\n // Inject the main app's registerSkill into a global so the personal bundle\n // (which has its own bundled copy) uses the correct shared toolRegistry instance.\n (globalThis as Record<string, unknown>).__titanRegisterSkill = registerSkill;\n const { initPersonalSkills } = await import(pathToFileURL(loaderPath).href) as { initPersonalSkills: () => Promise<void> };\n await initPersonalSkills();\n } else {\n logger.warn(COMPONENT, `TITAN_PERSONAL=1 but ${loaderPath} not found — run: npm run build:personal`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `Personal skills failed to load: ${(err as Error).message}`);\n }\n }\n}\n\n/**\n * Discover and load user skills from ~/.titan/skills/ (all subdirs).\n * Supports:\n * 1. JavaScript files (.js) that export default { name, description, parameters, execute }\n * 2. YAML skill definitions (.yaml/.yml) with inline scripts\n * 3. Auto-generated skills from ~/.titan/skills/auto/\n */\nexport async function loadAutoSkills(): Promise<void> {\n const skillsRoot = join(TITAN_HOME, 'skills');\n if (!existsSync(skillsRoot)) return;\n\n logger.info(COMPONENT, 'Scanning for user skills...');\n let loadedCount = 0;\n\n // Scan both root and all subdirectories\n const dirsToScan = [skillsRoot];\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) dirsToScan.push(join(skillsRoot, entry.name));\n }\n\n for (const dir of dirsToScan) {\n const files = readdirSync(dir).filter(f =>\n f.endsWith('.js') || f.endsWith('.yaml') || f.endsWith('.yml')\n );\n\n for (const file of files) {\n const filePath = join(dir, file);\n try {\n if (file.endsWith('.js')) {\n // JavaScript skill — export default { name, description, parameters, execute }\n const modulePath = `file://${filePath}?t=${Date.now()}`;\n const mod = await import(modulePath);\n if (mod.default && mod.default.name && mod.default.execute) {\n const handler = mod.default as ToolHandler;\n if (registeredSkills.has(handler.name)) continue; // Skip duplicates\n registerSkill({\n name: handler.name,\n description: handler.description || 'User skill',\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n } else {\n // YAML skill definition\n const loaded = loadYamlSkill(filePath);\n if (loaded && !registeredSkills.has(loaded.name)) {\n registerSkill({\n name: loaded.name,\n description: loaded.description,\n version: '1.0.0',\n source: 'workspace',\n enabled: true,\n }, loaded);\n loadedCount++;\n }\n }\n } catch (e: unknown) {\n logger.warn(COMPONENT, `Failed to load skill ${file}: ${(e as Error).message}`);\n }\n }\n }\n\n if (loadedCount > 0) {\n logger.info(COMPONENT, `Loaded ${loadedCount} user skill(s) from ~/.titan/skills/`);\n }\n\n // Load frontmatter skills (*.skill.md) — Space Agent / Hermes parity\n try {\n const { getFrontmatterToolHandlers } = await import('./frontmatterLoader.js');\n const fmHandlers = getFrontmatterToolHandlers();\n for (const { name, handler } of fmHandlers) {\n if (registeredSkills.has(name)) continue;\n registerSkill({\n name: handler.name,\n description: handler.description,\n version: '1.0.0',\n source: 'frontmatter',\n enabled: true,\n }, handler);\n loadedCount++;\n }\n if (fmHandlers.length > 0) {\n logger.info(COMPONENT, `Loaded ${fmHandlers.length} frontmatter skill(s)`);\n }\n } catch (e) {\n logger.warn(COMPONENT, `Frontmatter skills failed to load: ${(e as Error).message}`);\n }\n}\n\n/**\n * Load a YAML skill definition.\n * Format:\n * name: my_tool\n * description: What it does\n * parameters:\n * myParam:\n * type: string\n * description: A parameter\n * required: true\n * script: |\n * // JavaScript code. Use `args.myParam` for inputs.\n * // Return a string result.\n * return \"Hello \" + args.myParam;\n */\nfunction loadYamlSkill(filePath: string): ToolHandler | null {\n const content = readFileSync(filePath, 'utf-8');\n\n // Simple YAML parser (no dependency needed for this basic format)\n const name = content.match(/^name:\\s*(.+)$/m)?.[1]?.trim();\n const description = content.match(/^description:\\s*(.+)$/m)?.[1]?.trim();\n const scriptMatch = content.match(/^script:\\s*\\|\\n([\\s\\S]+?)(?=\\n\\w|\\n$|$)/m);\n const script = scriptMatch?.[1]?.replace(/^ {2}/gm, ''); // Remove YAML indent\n\n if (!name || !description || !script) {\n logger.debug(COMPONENT, `Skipping ${filePath}: missing name, description, or script`);\n return null;\n }\n\n // Parse parameters section\n const paramsSection = content.match(/^parameters:\\n((?:\\s{2}\\w[\\s\\S]*?)(?=\\nscript:|\\n\\w|\\n$))/m);\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n\n if (paramsSection) {\n const paramLines = paramsSection[1].split('\\n');\n let currentParam = '';\n for (const line of paramLines) {\n const paramMatch = line.match(/^\\s{2}(\\w+):\\s*$/);\n if (paramMatch) {\n currentParam = paramMatch[1];\n properties[currentParam] = {};\n continue;\n }\n if (currentParam) {\n const typeMatch = line.match(/^\\s{4}type:\\s*(.+)$/);\n const descMatch = line.match(/^\\s{4}description:\\s*(.+)$/);\n const reqMatch = line.match(/^\\s{4}required:\\s*true$/);\n const defMatch = line.match(/^\\s{4}default:\\s*(.+)$/);\n if (typeMatch) properties[currentParam].type = typeMatch[1].trim();\n if (descMatch) properties[currentParam].description = descMatch[1].trim();\n if (reqMatch) required.push(currentParam);\n if (defMatch) properties[currentParam].default = defMatch[1].trim();\n }\n }\n }\n\n // Create the execute function from the script\n const handler: ToolHandler = {\n name,\n description,\n parameters: {\n type: 'object',\n properties,\n required: required.length > 0 ? required : undefined,\n },\n execute: async (args: Record<string, unknown>) => {\n try {\n // Run in a restricted VM context — no access to globalThis, process, eval, or Function\n const safeRequire = (mod: string) => {\n // SECURITY: child_process, http, https removed — YAML skills must use builtin tools for shell/network\n const allowed = ['fs', 'path', 'os', 'crypto', 'url', 'util'];\n if (!allowed.includes(mod)) throw new Error(`Module \"${mod}\" not allowed in YAML skills`);\n return require(mod); // eslint-disable-line @typescript-eslint/no-require-imports\n };\n const sandbox: Record<string, unknown> = {\n args,\n require: safeRequire,\n console: { log: console.log },\n JSON,\n Math,\n Date,\n String,\n Number,\n Array,\n Object,\n RegExp,\n Map,\n Set,\n Promise,\n setTimeout,\n Buffer,\n };\n // Wrap the user script in an async IIFE so `return` works and we can await it\n const wrapped = `(async function() { ${script} })()`;\n const result = await vm.runInNewContext(wrapped, sandbox, { timeout: 10000 });\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n } catch (err) {\n return `Error: ${(err as Error).message}`;\n }\n },\n };\n\n logger.debug(COMPONENT, `Loaded YAML skill: ${name} from ${filePath}`);\n return handler;\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import logger from "../utils/logger.js";
5
5
  const COMPONENT = "ActivityLog";
6
6
  const MAX_LINES = 1e3;
7
7
  let _inMemoryBuffer = [];
8
- let _bufferFlushMs = 5e3;
8
+ const _bufferFlushMs = 5e3;
9
9
  let _bufferTimer = null;
10
10
  function logActivity(event) {
11
11
  const entry = { t: Date.now(), ...event };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/telemetry/activityLog.ts"],"sourcesContent":["/**\n * TITAN — Activity Log (Phase 8)\n *\n * Lightweight append-only telemetry for \"what TITAN did today\".\n * Drives real Facebook \"activity\" posts instead of fictional templates.\n *\n * Format: JSON Lines (~/.titan/activity-log.jsonl)\n * { \"t\": 1714141200000, \"event\": \"tool_call\", \"tool\": \"write_file\", \"session\": \"abc\" }\n * { \"t\": 1714141205000, \"event\": \"agent_spawn\", \"agent\": \"builder\", \"task\": \"fix bug\" }\n *\n * Rotation: keep last 1000 lines (≈ 50-100KB).\n */\nimport { appendFileSync, existsSync, readFileSync, writeFileSync } from 'fs';\nimport { ACTIVITY_LOG_PATH } from '../utils/constants.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'ActivityLog';\nconst MAX_LINES = 1000;\n\nexport type ActivityEventType =\n | 'tool_call'\n | 'agent_spawn'\n | 'agent_complete'\n | 'file_edit'\n | 'web_search'\n | 'web_fetch'\n | 'eval_run'\n | 'goal_complete'\n | 'self_improve_proposal'\n | 'error_recovery'\n | 'milestone';\n\nexport interface ActivityEvent {\n t: number; // timestamp ms\n event: ActivityEventType;\n [key: string]: unknown;\n}\n\nexport interface ActivitySummary {\n periodHours: number;\n toolCalls: number;\n agentSpawns: number;\n agentCompletions: number;\n fileEdits: number;\n webSearches: number;\n webFetches: number;\n evalRuns: number;\n goalsCompleted: number;\n selfImproveProposals: number;\n errorRecoveries: number;\n highlights: string[];\n}\n\nlet _inMemoryBuffer: ActivityEvent[] = [];\nlet _bufferFlushMs = 5000;\nlet _bufferTimer: ReturnType<typeof setTimeout> | null = null;\n\n/** Append an event to the activity log (buffered + flushed async) */\nexport function logActivity(event: Omit<ActivityEvent, 't'>): void {\n // The string indexer on ActivityEvent confuses TS's spread narrowing —\n // it loses sight of `event` being a required field after the spread.\n // Cast through unknown is safe because logActivity's parameter type\n // already requires the `event` discriminator.\n const entry = { t: Date.now(), ...event } as unknown as ActivityEvent;\n _inMemoryBuffer.push(entry);\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (_bufferTimer) return;\n _bufferTimer = setTimeout(() => {\n _bufferTimer = null;\n flushBuffer();\n }, _bufferFlushMs);\n}\n\n/** Flush buffered events to disk. Exposed for tests and shutdown hooks. */\nexport function flushBuffer(): void {\n if (_inMemoryBuffer.length === 0) return;\n const lines = _inMemoryBuffer.map(e => JSON.stringify(e)).join('\\n') + '\\n';\n _inMemoryBuffer = [];\n try {\n appendFileSync(ACTIVITY_LOG_PATH, lines, 'utf-8');\n enforceRotation();\n } catch (e) {\n logger.error(COMPONENT, `Failed to write activity log: ${(e as Error).message}`);\n }\n}\n\nfunction enforceRotation(): void {\n try {\n if (!existsSync(ACTIVITY_LOG_PATH)) return;\n const data = readFileSync(ACTIVITY_LOG_PATH, 'utf-8');\n const lines = data.split('\\n').filter(l => l.trim());\n if (lines.length <= MAX_LINES) return;\n const keep = lines.slice(-MAX_LINES);\n writeFileSync(ACTIVITY_LOG_PATH, keep.join('\\n') + '\\n', 'utf-8');\n logger.debug(COMPONENT, `Rotated activity log to ${keep.length} lines`);\n } catch (e) {\n logger.warn(COMPONENT, `Rotation failed: ${(e as Error).message}`);\n }\n}\n\n/** Read all events from disk + buffer */\nexport function readActivityEvents(): ActivityEvent[] {\n const events: ActivityEvent[] = [];\n try {\n if (existsSync(ACTIVITY_LOG_PATH)) {\n const data = readFileSync(ACTIVITY_LOG_PATH, 'utf-8');\n for (const line of data.split('\\n')) {\n if (!line.trim()) continue;\n try { events.push(JSON.parse(line) as ActivityEvent); } catch { /* skip bad line */ }\n }\n }\n } catch (e) {\n logger.warn(COMPONENT, `Failed to read activity log: ${(e as Error).message}`);\n }\n return events.concat(_inMemoryBuffer);\n}\n\n/** Summarize activity over the last N hours */\nexport function getActivitySummary(periodHours = 24): ActivitySummary {\n const cutoff = Date.now() - periodHours * 60 * 60 * 1000;\n const events = readActivityEvents().filter(e => e.t >= cutoff);\n\n const summary: ActivitySummary = {\n periodHours,\n toolCalls: 0,\n agentSpawns: 0,\n agentCompletions: 0,\n fileEdits: 0,\n webSearches: 0,\n webFetches: 0,\n evalRuns: 0,\n goalsCompleted: 0,\n selfImproveProposals: 0,\n errorRecoveries: 0,\n highlights: [],\n };\n\n for (const e of events) {\n switch (e.event) {\n case 'tool_call': summary.toolCalls++; break;\n case 'agent_spawn': summary.agentSpawns++; break;\n case 'agent_complete': summary.agentCompletions++; break;\n case 'file_edit': summary.fileEdits++; break;\n case 'web_search': summary.webSearches++; break;\n case 'web_fetch': summary.webFetches++; break;\n case 'eval_run': summary.evalRuns++; break;\n case 'goal_complete': summary.goalsCompleted++; break;\n case 'self_improve_proposal': summary.selfImproveProposals++; break;\n case 'error_recovery': summary.errorRecoveries++; break;\n case 'milestone':\n if (e.description && typeof e.description === 'string') {\n summary.highlights.push(e.description);\n }\n break;\n }\n }\n\n // Auto-detect highlights: milestone thresholds\n if (summary.toolCalls > 0 && summary.toolCalls % 1000 === 0) {\n summary.highlights.push(`Hit ${summary.toolCalls.toLocaleString()} tool calls`);\n }\n if (summary.agentSpawns > 0 && summary.agentSpawns % 100 === 0) {\n summary.highlights.push(`Spawned ${summary.agentSpawns} agents today`);\n }\n\n return summary;\n}\n\n/** Check if there's anything worth posting about */\nexport function hasInterestingActivity(periodHours = 24): boolean {\n const s = getActivitySummary(periodHours);\n return s.toolCalls > 0 || s.agentSpawns > 0 || s.fileEdits > 0 || s.highlights.length > 0;\n}\n\n/** Format a short narrative from the summary for the LLM prompt */\nexport function formatActivityNarrative(summary: ActivitySummary): string {\n const parts: string[] = [];\n if (summary.agentSpawns > 0) parts.push(`spawned ${summary.agentSpawns} sub-agent${summary.agentSpawns === 1 ? '' : 's'}`);\n if (summary.agentCompletions > 0) parts.push(`completed ${summary.agentCompletions} agent task${summary.agentCompletions === 1 ? '' : 's'}`);\n if (summary.toolCalls > 0) parts.push(`made ${summary.toolCalls.toLocaleString()} tool call${summary.toolCalls === 1 ? '' : 's'}`);\n if (summary.fileEdits > 0) parts.push(`edited ${summary.fileEdits} file${summary.fileEdits === 1 ? '' : 's'}`);\n if (summary.webSearches > 0) parts.push(`ran ${summary.webSearches} web search${summary.webSearches === 1 ? '' : 'es'}`);\n if (summary.evalRuns > 0) parts.push(`ran ${summary.evalRuns} eval suite${summary.evalRuns === 1 ? '' : 's'}`);\n if (summary.goalsCompleted > 0) parts.push(`completed ${summary.goalsCompleted} goal${summary.goalsCompleted === 1 ? '' : 's'}`);\n if (summary.selfImproveProposals > 0) parts.push(`filed ${summary.selfImproveProposals} self-improvement proposal${summary.selfImproveProposals === 1 ? '' : 's'}`);\n if (summary.errorRecoveries > 0) parts.push(`recovered from ${summary.errorRecoveries} error${summary.errorRecoveries === 1 ? '' : 's'}`);\n\n if (parts.length === 0) return '';\n\n let narrative = `In the last ${summary.periodHours}h, TITAN ${parts.join(', ')}.`;\n if (summary.highlights.length > 0) {\n narrative += ` Highlights: ${summary.highlights.join('; ')}.`;\n }\n return narrative;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/telemetry/activityLog.ts"],"sourcesContent":["/**\n * TITAN — Activity Log (Phase 8)\n *\n * Lightweight append-only telemetry for \"what TITAN did today\".\n * Drives real Facebook \"activity\" posts instead of fictional templates.\n *\n * Format: JSON Lines (~/.titan/activity-log.jsonl)\n * { \"t\": 1714141200000, \"event\": \"tool_call\", \"tool\": \"write_file\", \"session\": \"abc\" }\n * { \"t\": 1714141205000, \"event\": \"agent_spawn\", \"agent\": \"builder\", \"task\": \"fix bug\" }\n *\n * Rotation: keep last 1000 lines (≈ 50-100KB).\n */\nimport { appendFileSync, existsSync, readFileSync, writeFileSync } from 'fs';\nimport { ACTIVITY_LOG_PATH } from '../utils/constants.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'ActivityLog';\nconst MAX_LINES = 1000;\n\nexport type ActivityEventType =\n | 'tool_call'\n | 'agent_spawn'\n | 'agent_complete'\n | 'file_edit'\n | 'web_search'\n | 'web_fetch'\n | 'eval_run'\n | 'goal_complete'\n | 'self_improve_proposal'\n | 'error_recovery'\n | 'milestone';\n\nexport interface ActivityEvent {\n t: number; // timestamp ms\n event: ActivityEventType;\n [key: string]: unknown;\n}\n\nexport interface ActivitySummary {\n periodHours: number;\n toolCalls: number;\n agentSpawns: number;\n agentCompletions: number;\n fileEdits: number;\n webSearches: number;\n webFetches: number;\n evalRuns: number;\n goalsCompleted: number;\n selfImproveProposals: number;\n errorRecoveries: number;\n highlights: string[];\n}\n\nlet _inMemoryBuffer: ActivityEvent[] = [];\nconst _bufferFlushMs = 5000;\nlet _bufferTimer: ReturnType<typeof setTimeout> | null = null;\n\n/** Append an event to the activity log (buffered + flushed async) */\nexport function logActivity(event: Omit<ActivityEvent, 't'>): void {\n // The string indexer on ActivityEvent confuses TS's spread narrowing —\n // it loses sight of `event` being a required field after the spread.\n // Cast through unknown is safe because logActivity's parameter type\n // already requires the `event` discriminator.\n const entry = { t: Date.now(), ...event } as unknown as ActivityEvent;\n _inMemoryBuffer.push(entry);\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (_bufferTimer) return;\n _bufferTimer = setTimeout(() => {\n _bufferTimer = null;\n flushBuffer();\n }, _bufferFlushMs);\n}\n\n/** Flush buffered events to disk. Exposed for tests and shutdown hooks. */\nexport function flushBuffer(): void {\n if (_inMemoryBuffer.length === 0) return;\n const lines = _inMemoryBuffer.map(e => JSON.stringify(e)).join('\\n') + '\\n';\n _inMemoryBuffer = [];\n try {\n appendFileSync(ACTIVITY_LOG_PATH, lines, 'utf-8');\n enforceRotation();\n } catch (e) {\n logger.error(COMPONENT, `Failed to write activity log: ${(e as Error).message}`);\n }\n}\n\nfunction enforceRotation(): void {\n try {\n if (!existsSync(ACTIVITY_LOG_PATH)) return;\n const data = readFileSync(ACTIVITY_LOG_PATH, 'utf-8');\n const lines = data.split('\\n').filter(l => l.trim());\n if (lines.length <= MAX_LINES) return;\n const keep = lines.slice(-MAX_LINES);\n writeFileSync(ACTIVITY_LOG_PATH, keep.join('\\n') + '\\n', 'utf-8');\n logger.debug(COMPONENT, `Rotated activity log to ${keep.length} lines`);\n } catch (e) {\n logger.warn(COMPONENT, `Rotation failed: ${(e as Error).message}`);\n }\n}\n\n/** Read all events from disk + buffer */\nexport function readActivityEvents(): ActivityEvent[] {\n const events: ActivityEvent[] = [];\n try {\n if (existsSync(ACTIVITY_LOG_PATH)) {\n const data = readFileSync(ACTIVITY_LOG_PATH, 'utf-8');\n for (const line of data.split('\\n')) {\n if (!line.trim()) continue;\n try { events.push(JSON.parse(line) as ActivityEvent); } catch { /* skip bad line */ }\n }\n }\n } catch (e) {\n logger.warn(COMPONENT, `Failed to read activity log: ${(e as Error).message}`);\n }\n return events.concat(_inMemoryBuffer);\n}\n\n/** Summarize activity over the last N hours */\nexport function getActivitySummary(periodHours = 24): ActivitySummary {\n const cutoff = Date.now() - periodHours * 60 * 60 * 1000;\n const events = readActivityEvents().filter(e => e.t >= cutoff);\n\n const summary: ActivitySummary = {\n periodHours,\n toolCalls: 0,\n agentSpawns: 0,\n agentCompletions: 0,\n fileEdits: 0,\n webSearches: 0,\n webFetches: 0,\n evalRuns: 0,\n goalsCompleted: 0,\n selfImproveProposals: 0,\n errorRecoveries: 0,\n highlights: [],\n };\n\n for (const e of events) {\n switch (e.event) {\n case 'tool_call': summary.toolCalls++; break;\n case 'agent_spawn': summary.agentSpawns++; break;\n case 'agent_complete': summary.agentCompletions++; break;\n case 'file_edit': summary.fileEdits++; break;\n case 'web_search': summary.webSearches++; break;\n case 'web_fetch': summary.webFetches++; break;\n case 'eval_run': summary.evalRuns++; break;\n case 'goal_complete': summary.goalsCompleted++; break;\n case 'self_improve_proposal': summary.selfImproveProposals++; break;\n case 'error_recovery': summary.errorRecoveries++; break;\n case 'milestone':\n if (e.description && typeof e.description === 'string') {\n summary.highlights.push(e.description);\n }\n break;\n }\n }\n\n // Auto-detect highlights: milestone thresholds\n if (summary.toolCalls > 0 && summary.toolCalls % 1000 === 0) {\n summary.highlights.push(`Hit ${summary.toolCalls.toLocaleString()} tool calls`);\n }\n if (summary.agentSpawns > 0 && summary.agentSpawns % 100 === 0) {\n summary.highlights.push(`Spawned ${summary.agentSpawns} agents today`);\n }\n\n return summary;\n}\n\n/** Check if there's anything worth posting about */\nexport function hasInterestingActivity(periodHours = 24): boolean {\n const s = getActivitySummary(periodHours);\n return s.toolCalls > 0 || s.agentSpawns > 0 || s.fileEdits > 0 || s.highlights.length > 0;\n}\n\n/** Format a short narrative from the summary for the LLM prompt */\nexport function formatActivityNarrative(summary: ActivitySummary): string {\n const parts: string[] = [];\n if (summary.agentSpawns > 0) parts.push(`spawned ${summary.agentSpawns} sub-agent${summary.agentSpawns === 1 ? '' : 's'}`);\n if (summary.agentCompletions > 0) parts.push(`completed ${summary.agentCompletions} agent task${summary.agentCompletions === 1 ? '' : 's'}`);\n if (summary.toolCalls > 0) parts.push(`made ${summary.toolCalls.toLocaleString()} tool call${summary.toolCalls === 1 ? '' : 's'}`);\n if (summary.fileEdits > 0) parts.push(`edited ${summary.fileEdits} file${summary.fileEdits === 1 ? '' : 's'}`);\n if (summary.webSearches > 0) parts.push(`ran ${summary.webSearches} web search${summary.webSearches === 1 ? '' : 'es'}`);\n if (summary.evalRuns > 0) parts.push(`ran ${summary.evalRuns} eval suite${summary.evalRuns === 1 ? '' : 's'}`);\n if (summary.goalsCompleted > 0) parts.push(`completed ${summary.goalsCompleted} goal${summary.goalsCompleted === 1 ? '' : 's'}`);\n if (summary.selfImproveProposals > 0) parts.push(`filed ${summary.selfImproveProposals} self-improvement proposal${summary.selfImproveProposals === 1 ? '' : 's'}`);\n if (summary.errorRecoveries > 0) parts.push(`recovered from ${summary.errorRecoveries} error${summary.errorRecoveries === 1 ? '' : 's'}`);\n\n if (parts.length === 0) return '';\n\n let narrative = `In the last ${summary.periodHours}h, TITAN ${parts.join(', ')}.`;\n if (summary.highlights.length > 0) {\n narrative += ` Highlights: ${summary.highlights.join('; ')}.`;\n }\n return narrative;\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
- const TITAN_VERSION = "5.4.0";
4
+ const TITAN_VERSION = "5.4.1";
5
5
  const TITAN_CODENAME = "Spacewalk";
6
6
  const TITAN_NAME = "TITAN";
7
7
  const TITAN_FULL_NAME = "The Intelligent Task Automation Network";
@@ -57,7 +57,7 @@ const DEFAULT_GATEWAY_HOST = "0.0.0.0";
57
57
  const DEFAULT_GATEWAY_PORT = 48420;
58
58
  const DEFAULT_WEB_PORT = 48421;
59
59
  const DEFAULT_MODEL = "anthropic/claude-sonnet-4-20250514";
60
- const DEFAULT_MAX_TOKENS = 12e3;
60
+ const DEFAULT_MAX_TOKENS = 2e5;
61
61
  const DEFAULT_TEMPERATURE = 0.7;
62
62
  const MAX_CONTEXT_MESSAGES = 50;
63
63
  const SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * TITAN Constants\n */\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport const TITAN_VERSION = '5.4.0';\nexport const TITAN_CODENAME = 'Spacewalk';\nexport const TITAN_NAME = 'TITAN';\nexport const TITAN_FULL_NAME = 'The Intelligent Task Automation Network';\nexport const TITAN_ASCII_LOGO = `\n╔══════════════════════════════════════════════════════╗\n║ ║\n║ ████████╗██╗████████╗ █████╗ ███╗ ██╗ ║\n║ ██║ ██║ ██║ ██╔══██╗████╗ ██║ ║\n║ ██║ ██║ ██║ ███████║██╔██╗ ██║ ║\n║ ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ║\n║ ██║ ██║ ██║ ██║ ██║██║ ╚████║ ║\n║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ║\n║ ║\n║ The Intelligent Task Automation Network ║\n║ v${TITAN_VERSION} • by Tony Elliott ║\n╚══════════════════════════════════════════════════════╝`;\n\n// Paths\n// Hunt Finding #03 (2026-04-14): honor TITAN_HOME env var if set.\n// Previously this was hardcoded to `~/.titan`, which meant:\n// - Docker containers couldn't override the config path\n// - Shared machines couldn't isolate per-user state\n// - Test fixtures couldn't run against an isolated home\n// - The systemd unit's `Environment=TITAN_HOME=...` was silently ignored\n// The env var is read once at module load (constants are resolved at import time).\n// If TITAN_HOME starts with `~/`, expand it to the user's home dir.\nfunction resolveTitanHome(): string {\n const envHome = process.env.TITAN_HOME;\n if (envHome && envHome.trim().length > 0) {\n const trimmed = envHome.trim();\n if (trimmed.startsWith('~/')) {\n return join(homedir(), trimmed.slice(2));\n }\n if (trimmed === '~') {\n return homedir();\n }\n return trimmed;\n }\n return join(homedir(), '.titan');\n}\nexport const TITAN_HOME = resolveTitanHome();\nexport const TITAN_CONFIG_PATH = join(TITAN_HOME, 'titan.json');\nexport const TITAN_DB_PATH = join(TITAN_HOME, 'titan.db');\nexport const TITAN_WORKSPACE = join(TITAN_HOME, 'workspace');\nexport const TITAN_SKILLS_DIR = join(TITAN_WORKSPACE, 'skills');\nexport const TITAN_LOGS_DIR = join(TITAN_HOME, 'logs');\nexport const TITAN_MEMORY_DIR = join(TITAN_HOME, 'memory');\n\n// Workspace prompt files (injected into agent context)\nexport const AGENTS_MD = join(TITAN_WORKSPACE, 'AGENTS.md');\nexport const SOUL_MD = join(TITAN_WORKSPACE, 'SOUL.md');\nexport const TOOLS_MD = join(TITAN_WORKSPACE, 'TOOLS.md');\nexport const TITAN_MD_FILENAME = 'TITAN.md';\nexport const AUTOPILOT_MD = join(TITAN_HOME, 'AUTOPILOT.md');\nexport const AUTOPILOT_RUNS_PATH = join(TITAN_HOME, 'autopilot-runs.jsonl');\nexport const TITAN_CREDENTIALS_DIR = join(TITAN_HOME, 'credentials');\n\n// Income & lead tracking\nexport const INCOME_LEDGER_PATH = join(TITAN_HOME, 'income-ledger.jsonl');\nexport const FREELANCE_LEADS_PATH = join(TITAN_HOME, 'freelance-leads.jsonl');\nexport const FREELANCE_PROFILE_PATH = join(TITAN_HOME, 'freelance-profile.json');\nexport const LEADS_PATH = join(TITAN_HOME, 'leads.jsonl');\nexport const TELEMETRY_EVENTS_PATH = join(TITAN_HOME, 'telemetry-events.jsonl');\nexport const SOMADRIVE_STATE_PATH = join(TITAN_HOME, 'soma-drive-state.json');\nexport const ACTIVITY_LOG_PATH = join(TITAN_HOME, 'activity-log.jsonl');\n\n// Gateway defaults\nexport const DEFAULT_GATEWAY_HOST = '0.0.0.0';\nexport const DEFAULT_GATEWAY_PORT = 48420;\nexport const DEFAULT_WEB_PORT = 48421;\n\n// Agent defaults\nexport const DEFAULT_MODEL = 'anthropic/claude-sonnet-4-20250514';\nexport const DEFAULT_MAX_TOKENS = 12000;\nexport const DEFAULT_TEMPERATURE = 0.7;\nexport const MAX_CONTEXT_MESSAGES = 50;\nexport const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n// Security\nexport const DEFAULT_SANDBOX_MODE = 'host';\n/** Default allowed tools. Empty = allow ALL registered tools.\n * Use security.deniedTools to block specific tools instead. */\nexport const ALLOWED_TOOLS_DEFAULT: string[] = [];\nexport const DENIED_TOOLS_DEFAULT: string[] = [];\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAW1B,aAAa;AAAA;AAYnB,SAAS,mBAA2B;AAChC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAG;AACtC,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC1B,aAAO,KAAK,QAAQ,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C;AACA,QAAI,YAAY,KAAK;AACjB,aAAO,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACnC;AACO,MAAM,aAAa,iBAAiB;AACpC,MAAM,oBAAoB,KAAK,YAAY,YAAY;AACvD,MAAM,gBAAgB,KAAK,YAAY,UAAU;AACjD,MAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,MAAM,mBAAmB,KAAK,iBAAiB,QAAQ;AACvD,MAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,MAAM,mBAAmB,KAAK,YAAY,QAAQ;AAGlD,MAAM,YAAY,KAAK,iBAAiB,WAAW;AACnD,MAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,MAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,MAAM,oBAAoB;AAC1B,MAAM,eAAe,KAAK,YAAY,cAAc;AACpD,MAAM,sBAAsB,KAAK,YAAY,sBAAsB;AACnE,MAAM,wBAAwB,KAAK,YAAY,aAAa;AAG5D,MAAM,qBAAqB,KAAK,YAAY,qBAAqB;AACjE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,yBAAyB,KAAK,YAAY,wBAAwB;AACxE,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,MAAM,wBAAwB,KAAK,YAAY,wBAAwB;AACvE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,oBAAoB,KAAK,YAAY,oBAAoB;AAG/D,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAGzB,MAAM,gBAAgB;AACtB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB,KAAK,KAAK;AAGrC,MAAM,uBAAuB;AAG7B,MAAM,wBAAkC,CAAC;AACzC,MAAM,uBAAiC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * TITAN Constants\n */\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport const TITAN_VERSION = '5.4.1';\nexport const TITAN_CODENAME = 'Spacewalk';\nexport const TITAN_NAME = 'TITAN';\nexport const TITAN_FULL_NAME = 'The Intelligent Task Automation Network';\nexport const TITAN_ASCII_LOGO = `\n╔══════════════════════════════════════════════════════╗\n║ ║\n║ ████████╗██╗████████╗ █████╗ ███╗ ██╗ ║\n║ ██║ ██║ ██║ ██╔══██╗████╗ ██║ ║\n║ ██║ ██║ ██║ ███████║██╔██╗ ██║ ║\n║ ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ║\n║ ██║ ██║ ██║ ██║ ██║██║ ╚████║ ║\n║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ║\n║ ║\n║ The Intelligent Task Automation Network ║\n║ v${TITAN_VERSION} • by Tony Elliott ║\n╚══════════════════════════════════════════════════════╝`;\n\n// Paths\n// Hunt Finding #03 (2026-04-14): honor TITAN_HOME env var if set.\n// Previously this was hardcoded to `~/.titan`, which meant:\n// - Docker containers couldn't override the config path\n// - Shared machines couldn't isolate per-user state\n// - Test fixtures couldn't run against an isolated home\n// - The systemd unit's `Environment=TITAN_HOME=...` was silently ignored\n// The env var is read once at module load (constants are resolved at import time).\n// If TITAN_HOME starts with `~/`, expand it to the user's home dir.\nfunction resolveTitanHome(): string {\n const envHome = process.env.TITAN_HOME;\n if (envHome && envHome.trim().length > 0) {\n const trimmed = envHome.trim();\n if (trimmed.startsWith('~/')) {\n return join(homedir(), trimmed.slice(2));\n }\n if (trimmed === '~') {\n return homedir();\n }\n return trimmed;\n }\n return join(homedir(), '.titan');\n}\nexport const TITAN_HOME = resolveTitanHome();\nexport const TITAN_CONFIG_PATH = join(TITAN_HOME, 'titan.json');\nexport const TITAN_DB_PATH = join(TITAN_HOME, 'titan.db');\nexport const TITAN_WORKSPACE = join(TITAN_HOME, 'workspace');\nexport const TITAN_SKILLS_DIR = join(TITAN_WORKSPACE, 'skills');\nexport const TITAN_LOGS_DIR = join(TITAN_HOME, 'logs');\nexport const TITAN_MEMORY_DIR = join(TITAN_HOME, 'memory');\n\n// Workspace prompt files (injected into agent context)\nexport const AGENTS_MD = join(TITAN_WORKSPACE, 'AGENTS.md');\nexport const SOUL_MD = join(TITAN_WORKSPACE, 'SOUL.md');\nexport const TOOLS_MD = join(TITAN_WORKSPACE, 'TOOLS.md');\nexport const TITAN_MD_FILENAME = 'TITAN.md';\nexport const AUTOPILOT_MD = join(TITAN_HOME, 'AUTOPILOT.md');\nexport const AUTOPILOT_RUNS_PATH = join(TITAN_HOME, 'autopilot-runs.jsonl');\nexport const TITAN_CREDENTIALS_DIR = join(TITAN_HOME, 'credentials');\n\n// Income & lead tracking\nexport const INCOME_LEDGER_PATH = join(TITAN_HOME, 'income-ledger.jsonl');\nexport const FREELANCE_LEADS_PATH = join(TITAN_HOME, 'freelance-leads.jsonl');\nexport const FREELANCE_PROFILE_PATH = join(TITAN_HOME, 'freelance-profile.json');\nexport const LEADS_PATH = join(TITAN_HOME, 'leads.jsonl');\nexport const TELEMETRY_EVENTS_PATH = join(TITAN_HOME, 'telemetry-events.jsonl');\nexport const SOMADRIVE_STATE_PATH = join(TITAN_HOME, 'soma-drive-state.json');\nexport const ACTIVITY_LOG_PATH = join(TITAN_HOME, 'activity-log.jsonl');\n\n// Gateway defaults\nexport const DEFAULT_GATEWAY_HOST = '0.0.0.0';\nexport const DEFAULT_GATEWAY_PORT = 48420;\nexport const DEFAULT_WEB_PORT = 48421;\n\n// Agent defaults\nexport const DEFAULT_MODEL = 'anthropic/claude-sonnet-4-20250514';\n/** v5.4.1: User-preference ceiling. Providers clamp per-model via\n * clampMaxTokens() so this can be high without causing 400s on\n * capped endpoints (e.g. Claude Sonnet 4 8K, Cohere 4K). */\nexport const DEFAULT_MAX_TOKENS = 200000;\nexport const DEFAULT_TEMPERATURE = 0.7;\nexport const MAX_CONTEXT_MESSAGES = 50;\nexport const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n// Security\nexport const DEFAULT_SANDBOX_MODE = 'host';\n/** Default allowed tools. Empty = allow ALL registered tools.\n * Use security.deniedTools to block specific tools instead. */\nexport const ALLOWED_TOOLS_DEFAULT: string[] = [];\nexport const DENIED_TOOLS_DEFAULT: string[] = [];\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAW1B,aAAa;AAAA;AAYnB,SAAS,mBAA2B;AAChC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAG;AACtC,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC1B,aAAO,KAAK,QAAQ,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C;AACA,QAAI,YAAY,KAAK;AACjB,aAAO,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACnC;AACO,MAAM,aAAa,iBAAiB;AACpC,MAAM,oBAAoB,KAAK,YAAY,YAAY;AACvD,MAAM,gBAAgB,KAAK,YAAY,UAAU;AACjD,MAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,MAAM,mBAAmB,KAAK,iBAAiB,QAAQ;AACvD,MAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,MAAM,mBAAmB,KAAK,YAAY,QAAQ;AAGlD,MAAM,YAAY,KAAK,iBAAiB,WAAW;AACnD,MAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,MAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,MAAM,oBAAoB;AAC1B,MAAM,eAAe,KAAK,YAAY,cAAc;AACpD,MAAM,sBAAsB,KAAK,YAAY,sBAAsB;AACnE,MAAM,wBAAwB,KAAK,YAAY,aAAa;AAG5D,MAAM,qBAAqB,KAAK,YAAY,qBAAqB;AACjE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,yBAAyB,KAAK,YAAY,wBAAwB;AACxE,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,MAAM,wBAAwB,KAAK,YAAY,wBAAwB;AACvE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,oBAAoB,KAAK,YAAY,oBAAoB;AAG/D,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAGzB,MAAM,gBAAgB;AAItB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB,KAAK,KAAK;AAGrC,MAAM,uBAAuB;AAG7B,MAAM,wBAAkC,CAAC;AACzC,MAAM,uBAAiC,CAAC;","names":[]}
@@ -0,0 +1,154 @@
1
+ # TITAN Agent Orchestration Hierarchy
2
+
3
+ > **Audience:** anyone touching `src/agent/`. If you're about to add a new
4
+ > file or another way to spawn a sub-agent, read this first. Most of the
5
+ > time the answer is "use the existing path."
6
+
7
+ TITAN's agent layer has three distinct concerns. Keeping them separate
8
+ prevents the "I'll just add another orchestrator" cycle that produced
9
+ the v5.4.x cleanup pass.
10
+
11
+ ---
12
+
13
+ ## The three layers
14
+
15
+ ```
16
+ ┌─────────────────────────────────────────────────────────────┐
17
+ │ LAYER 1 — Conversation loop (one user, one turn) │
18
+ │ │
19
+ │ /api/message → multiAgent.routeMessage │
20
+ │ → agent.processMessage │
21
+ │ → agentLoop (THINK → ACT → RESPOND) │
22
+ │ │
23
+ │ Files: agent/loop/{agent,agentLoop,agentEvents, │
24
+ │ contextManager,contextCompressor,promptBudget}.ts │
25
+ └─────────────────────────────────────────────────────────────┘
26
+
27
+ │ needs parallel / specialized work?
28
+
29
+ ┌─────────────────────────────────────────────────────────────┐
30
+ │ LAYER 2 — Delegation (this turn spawns sub-agents) │
31
+ │ │
32
+ │ orchestrator.analyzeForDelegation │
33
+ │ → spawnSubAgent(template, task, ctx) ← CANONICAL │
34
+ │ hierarchicalPlanner.decomposeHierarchically │
35
+ │ → spawnSubAgent for each leaf │
36
+ │ │
37
+ │ Specialists: explorer, coder, browser, analyst, … │
38
+ │ │
39
+ │ Files: agent/delegation/{subAgent,orchestrator, │
40
+ │ specialists,specialistRouter, │
41
+ │ hierarchicalPlanner,structuredSpawn,swarm}.ts │
42
+ └─────────────────────────────────────────────────────────────┘
43
+
44
+ │ no user prompt at all? scheduled / autonomous?
45
+
46
+ ┌─────────────────────────────────────────────────────────────┐
47
+ │ LAYER 3 — Autonomy (no-user-prompt background work) │
48
+ │ │
49
+ │ driverScheduler (10s tick, concurrency cap = 5) │
50
+ │ │ │
51
+ │ ├─ goalDriver (per-goal state machine) │
52
+ │ ├─ missionDriver (multi-goal coordination) │
53
+ │ ├─ autopilot (fallback chain orchestration) │
54
+ │ └─ initiative (build-loop initiative engine) │
55
+ │ │
56
+ │ Soma drives → goalProposer → driverScheduler picks up │
57
+ │ │
58
+ │ Files: agent/autonomy/{driverScheduler,goalDriver, │
59
+ │ missionDriver,autopilot,initiative, │
60
+ │ driverAwareChat,heartbeatScheduler}.ts │
61
+ └─────────────────────────────────────────────────────────────┘
62
+
63
+ │ spans every layer
64
+
65
+ ┌─────────────────────────────────────────────────────────────┐
66
+ │ GOVERNANCE OVERLAY (runs alongside, not below) │
67
+ │ │
68
+ │ commandPost — atomic checkout, registry, ancestry │
69
+ │ budgetEnforcer — token + dollar caps per goal │
70
+ │ guardrails — input/tool/output content filters │
71
+ │ approvalClassifier — auto-approve vs ask-user │
72
+ │ │
73
+ │ Files: agent/governance/{commandPost,budgetEnforcer, │
74
+ │ guardrails,approvalClassifier,auditLog, │
75
+ │ auditStore,outputGuardrails}.ts │
76
+ └─────────────────────────────────────────────────────────────┘
77
+ ```
78
+
79
+ ---
80
+
81
+ ## When do I use which?
82
+
83
+ | You want to… | Layer | Use |
84
+ |---|---|---|
85
+ | Process a message from the user / a channel / voice | 1 | `agent.processMessage(msg, channel, userId)` |
86
+ | Spawn a fresh sub-agent for a parallel sub-task in the current turn | 2 | `subAgent.spawnSubAgent(template, task, ctx)` ← **always this** |
87
+ | Decompose a multi-step request into a planned tree | 2 | `hierarchicalPlanner.decomposeHierarchically(...)` then iterate `spawnSubAgent` per leaf |
88
+ | Decide *whether* to delegate at all | 2 | `orchestrator.analyzeForDelegation(message)` |
89
+ | Run a goal in the background until it completes | 3 | Create the goal via Command Post → `driverScheduler` picks it up automatically |
90
+ | Coordinate multiple goals into one outcome | 3 | `missionDriver.createMission({...})` |
91
+ | Add a budget / approval / audit gate | overlay | Hook into `commandPost`, `budgetEnforcer`, or `guardrails` — **don't add a new gate file**, extend an existing one |
92
+
93
+ ---
94
+
95
+ ## Anti-patterns (these are **deprecated** as of v5.4.x cleanup)
96
+
97
+ - ❌ `swarm.runSubAgent` — was a parallel implementation of `spawnSubAgent`. Re-exports through the canonical path; new call sites should use `spawnSubAgent` directly.
98
+ - ❌ `structuredSpawn.spawn` — was a third copy. Same re-export shim.
99
+ - ❌ Inline `chat({ systemPrompt: 'You are an explorer...', ... })` calls — bypasses the specialist registry, the governance overlay, and the trace bus. **Always go through `spawnSubAgent`.**
100
+ - ❌ A new file in `src/agent/` to "do something kind of like sub-agents but different" — talk to the architecture before adding. 99% of the time, an existing primitive covers it.
101
+
102
+ ---
103
+
104
+ ## Soma feedback loop
105
+
106
+ The autonomous layer has one input the others lack: **homeostatic drives**.
107
+
108
+ ```
109
+ driveTickWatcher (every N seconds)
110
+
111
+
112
+ organism/pressure.ts computes pressure per drive
113
+
114
+ ▼ if pressure > threshold
115
+ goalProposer emits a draft goal
116
+
117
+
118
+ commandPost.createIssue (governance entry point)
119
+
120
+
121
+ driverScheduler picks up the new goal next tick
122
+ ```
123
+
124
+ This is the part that's actually hard to copy. LangGraph / CrewAI / Mastra have nothing equivalent. If you're touching this loop, read `docs/ADR-001-soma.md` first.
125
+
126
+ ---
127
+
128
+ ## File-organization contract
129
+
130
+ Every file in `src/agent/` lives in one of six subdirectories:
131
+
132
+ | Directory | What goes here |
133
+ |---|---|
134
+ | `agent/loop/` | Per-turn conversation processing |
135
+ | `agent/delegation/` | Sub-agent spawn + specialist registry + hierarchical planning |
136
+ | `agent/autonomy/` | Background drivers, schedulers, mission/goal state machines |
137
+ | `agent/governance/` | Cross-cutting policy: budgets, approvals, audit, guardrails |
138
+ | `agent/self-mod/` | Self-improvement: GEPA, proposals, staging, shadow git |
139
+ | `agent/tooling/` | Tool execution: runner, search, sandbox, parallel exec |
140
+
141
+ When in doubt, check which **layer** above your concern belongs to and the
142
+ subdirectory follows.
143
+
144
+ ---
145
+
146
+ ## Testing the contract
147
+
148
+ `tests/architecture-contract.test.ts` (TODO: write) should grep `src/agent/` for:
149
+
150
+ - Any file outside the six subdirectories → fail
151
+ - Any inline `chat({ systemPrompt: 'You are a ...' })` outside `delegation/specialists.ts` → fail
152
+ - Any `runSubAgent` / `structuredSpawn` import that isn't the deprecated re-export shim → fail
153
+
154
+ That's how this contract stays a contract instead of a doc nobody reads.