@goondocks/myco 0.21.1 → 0.21.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 (111) hide show
  1. package/dist/{agent-eval-YK2VP2S4.js → agent-eval-2MQKTXX3.js} +4 -4
  2. package/dist/{agent-run-GEJBD2YD.js → agent-run-XJBTSVJR.js} +4 -4
  3. package/dist/{agent-tasks-5XSRGTRX.js → agent-tasks-7MWBZOC7.js} +4 -4
  4. package/dist/{chunk-VRI56337.js → chunk-4D22KTXY.js} +2 -2
  5. package/dist/{chunk-KTTSXYEK.js → chunk-6FBLL7MD.js} +8 -2
  6. package/dist/chunk-6FBLL7MD.js.map +1 -0
  7. package/dist/{chunk-N7Z3LUEZ.js → chunk-DBBO6FHE.js} +2 -10
  8. package/dist/{chunk-N7Z3LUEZ.js.map → chunk-DBBO6FHE.js.map} +1 -1
  9. package/dist/{chunk-EEOJWLMP.js → chunk-DMPCC7V6.js} +15 -3
  10. package/dist/chunk-DMPCC7V6.js.map +1 -0
  11. package/dist/{chunk-XL75KZGI.js → chunk-EKZG2MCD.js} +7 -3
  12. package/dist/chunk-EKZG2MCD.js.map +1 -0
  13. package/dist/{chunk-X2IRGXGF.js → chunk-HCT7RMM2.js} +154 -24
  14. package/dist/chunk-HCT7RMM2.js.map +1 -0
  15. package/dist/{chunk-NFO7BRCO.js → chunk-IMW5TJ3O.js} +5 -4
  16. package/dist/chunk-IMW5TJ3O.js.map +1 -0
  17. package/dist/{chunk-OZ3FBAK5.js → chunk-TFRUDNLI.js} +2 -2
  18. package/dist/{chunk-6ALVMIB4.js → chunk-TMAXWERS.js} +85 -2
  19. package/dist/chunk-TMAXWERS.js.map +1 -0
  20. package/dist/{chunk-QDLVIW2O.js → chunk-W5L5IHP5.js} +2 -2
  21. package/dist/{chunk-ENZR5NG7.js → chunk-Z55WGA2J.js} +2 -2
  22. package/dist/{cli-HSLIG7EX.js → cli-DDHTHU2J.js} +35 -35
  23. package/dist/{client-Z43DNLJH.js → client-PQU53UQU.js} +5 -3
  24. package/dist/{doctor-HJCWHAU4.js → doctor-QK6KFY6H.js} +4 -4
  25. package/dist/{executor-DO6QFC6G.js → executor-FJCMNSXM.js} +5 -5
  26. package/dist/{init-4KVK7W2E.js → init-GQPD6HHX.js} +5 -5
  27. package/dist/{main-4J4QZZTZ.js → main-4HKTZFIM.js} +365 -142
  28. package/dist/main-4HKTZFIM.js.map +1 -0
  29. package/dist/{open-7TXJQM3H.js → open-3P3DDAOA.js} +4 -4
  30. package/dist/{post-compact-7AEFVCZS.js → post-compact-QA5LME2J.js} +4 -4
  31. package/dist/{post-tool-use-TZINWWDH.js → post-tool-use-QRZMPNYL.js} +3 -3
  32. package/dist/{post-tool-use-failure-TCFEU2GI.js → post-tool-use-failure-XNHIKBZG.js} +4 -4
  33. package/dist/{pre-compact-LO2VZCGR.js → pre-compact-HDV6X5QM.js} +4 -4
  34. package/dist/{remove-F77AAALE.js → remove-USQDLGTJ.js} +4 -4
  35. package/dist/{restart-UEFDPMLT.js → restart-FQLZE2TW.js} +5 -5
  36. package/dist/{search-NHNVUAQQ.js → search-5COKV6TD.js} +4 -4
  37. package/dist/{server-AZJSTQEK.js → server-KRMBRW4T.js} +22 -6
  38. package/dist/{server-AZJSTQEK.js.map → server-KRMBRW4T.js.map} +1 -1
  39. package/dist/{session-3HLC5KOD.js → session-NJCUW3OX.js} +4 -4
  40. package/dist/{session-end-FS46UARX.js → session-end-XD27GRYF.js} +3 -3
  41. package/dist/{session-start-46KPFV2H.js → session-start-RDTXUSYL.js} +7 -7
  42. package/dist/{setup-llm-JMWSNQ2C.js → setup-llm-FYPPJI6W.js} +4 -4
  43. package/dist/src/agent/definitions/tasks/skill-evolve.yaml +4 -4
  44. package/dist/src/cli.js +1 -1
  45. package/dist/src/daemon/main.js +1 -1
  46. package/dist/src/hooks/post-tool-use.js +1 -1
  47. package/dist/src/hooks/session-end.js +1 -1
  48. package/dist/src/hooks/session-start.js +1 -1
  49. package/dist/src/hooks/stop.js +1 -1
  50. package/dist/src/hooks/user-prompt-submit.js +1 -1
  51. package/dist/src/mcp/server.js +1 -1
  52. package/dist/src/symbionts/templates/opencode/plugin.ts +41 -1
  53. package/dist/src/symbionts/templates/pi/plugin.ts +12 -1
  54. package/dist/{stats-MKMETHMA.js → stats-JCLZLA5G.js} +5 -5
  55. package/dist/{stop-OUEX6KA4.js → stop-B7XCXEM5.js} +3 -3
  56. package/dist/{stop-failure-2BWVNZEG.js → stop-failure-R6QZCUOZ.js} +4 -4
  57. package/dist/{subagent-start-J4VV6DEE.js → subagent-start-N7A622F3.js} +4 -4
  58. package/dist/{subagent-stop-JMLVEPIA.js → subagent-stop-SVOG5MZJ.js} +4 -4
  59. package/dist/{task-completed-65CHMMKA.js → task-completed-3DL5LJXF.js} +4 -4
  60. package/dist/{team-U2LDKIS4.js → team-VJ3M263F.js} +2 -2
  61. package/dist/ui/assets/{index-BUGor9dk.js → index-O1kNWlWM.js} +119 -119
  62. package/dist/ui/assets/index-z2Jm8i4A.css +1 -0
  63. package/dist/ui/index.html +2 -2
  64. package/dist/{update-ZSHVXWSQ.js → update-TVXAUJMZ.js} +42 -8
  65. package/dist/update-TVXAUJMZ.js.map +1 -0
  66. package/dist/{user-prompt-submit-APMO6FVU.js → user-prompt-submit-KYO2VGLB.js} +7 -6
  67. package/dist/user-prompt-submit-KYO2VGLB.js.map +1 -0
  68. package/dist/{version-TXPPS3L5.js → version-LDFEALUJ.js} +2 -2
  69. package/package.json +1 -1
  70. package/dist/chunk-6ALVMIB4.js.map +0 -1
  71. package/dist/chunk-EEOJWLMP.js.map +0 -1
  72. package/dist/chunk-KTTSXYEK.js.map +0 -1
  73. package/dist/chunk-NFO7BRCO.js.map +0 -1
  74. package/dist/chunk-X2IRGXGF.js.map +0 -1
  75. package/dist/chunk-XL75KZGI.js.map +0 -1
  76. package/dist/main-4J4QZZTZ.js.map +0 -1
  77. package/dist/ui/assets/index-_OP4ifzH.css +0 -1
  78. package/dist/update-ZSHVXWSQ.js.map +0 -1
  79. package/dist/user-prompt-submit-APMO6FVU.js.map +0 -1
  80. /package/dist/{agent-eval-YK2VP2S4.js.map → agent-eval-2MQKTXX3.js.map} +0 -0
  81. /package/dist/{agent-run-GEJBD2YD.js.map → agent-run-XJBTSVJR.js.map} +0 -0
  82. /package/dist/{agent-tasks-5XSRGTRX.js.map → agent-tasks-7MWBZOC7.js.map} +0 -0
  83. /package/dist/{chunk-VRI56337.js.map → chunk-4D22KTXY.js.map} +0 -0
  84. /package/dist/{chunk-OZ3FBAK5.js.map → chunk-TFRUDNLI.js.map} +0 -0
  85. /package/dist/{chunk-QDLVIW2O.js.map → chunk-W5L5IHP5.js.map} +0 -0
  86. /package/dist/{chunk-ENZR5NG7.js.map → chunk-Z55WGA2J.js.map} +0 -0
  87. /package/dist/{cli-HSLIG7EX.js.map → cli-DDHTHU2J.js.map} +0 -0
  88. /package/dist/{client-Z43DNLJH.js.map → client-PQU53UQU.js.map} +0 -0
  89. /package/dist/{doctor-HJCWHAU4.js.map → doctor-QK6KFY6H.js.map} +0 -0
  90. /package/dist/{executor-DO6QFC6G.js.map → executor-FJCMNSXM.js.map} +0 -0
  91. /package/dist/{init-4KVK7W2E.js.map → init-GQPD6HHX.js.map} +0 -0
  92. /package/dist/{open-7TXJQM3H.js.map → open-3P3DDAOA.js.map} +0 -0
  93. /package/dist/{post-compact-7AEFVCZS.js.map → post-compact-QA5LME2J.js.map} +0 -0
  94. /package/dist/{post-tool-use-TZINWWDH.js.map → post-tool-use-QRZMPNYL.js.map} +0 -0
  95. /package/dist/{post-tool-use-failure-TCFEU2GI.js.map → post-tool-use-failure-XNHIKBZG.js.map} +0 -0
  96. /package/dist/{pre-compact-LO2VZCGR.js.map → pre-compact-HDV6X5QM.js.map} +0 -0
  97. /package/dist/{remove-F77AAALE.js.map → remove-USQDLGTJ.js.map} +0 -0
  98. /package/dist/{restart-UEFDPMLT.js.map → restart-FQLZE2TW.js.map} +0 -0
  99. /package/dist/{search-NHNVUAQQ.js.map → search-5COKV6TD.js.map} +0 -0
  100. /package/dist/{session-3HLC5KOD.js.map → session-NJCUW3OX.js.map} +0 -0
  101. /package/dist/{session-end-FS46UARX.js.map → session-end-XD27GRYF.js.map} +0 -0
  102. /package/dist/{session-start-46KPFV2H.js.map → session-start-RDTXUSYL.js.map} +0 -0
  103. /package/dist/{setup-llm-JMWSNQ2C.js.map → setup-llm-FYPPJI6W.js.map} +0 -0
  104. /package/dist/{stats-MKMETHMA.js.map → stats-JCLZLA5G.js.map} +0 -0
  105. /package/dist/{stop-OUEX6KA4.js.map → stop-B7XCXEM5.js.map} +0 -0
  106. /package/dist/{stop-failure-2BWVNZEG.js.map → stop-failure-R6QZCUOZ.js.map} +0 -0
  107. /package/dist/{subagent-start-J4VV6DEE.js.map → subagent-start-N7A622F3.js.map} +0 -0
  108. /package/dist/{subagent-stop-JMLVEPIA.js.map → subagent-stop-SVOG5MZJ.js.map} +0 -0
  109. /package/dist/{task-completed-65CHMMKA.js.map → task-completed-3DL5LJXF.js.map} +0 -0
  110. /package/dist/{team-U2LDKIS4.js.map → team-VJ3M263F.js.map} +0 -0
  111. /package/dist/{version-TXPPS3L5.js.map → version-LDFEALUJ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vault/types.ts","../src/mcp/tool-definitions.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const SessionFrontmatterSchema = z.object({\n type: z.literal('session'),\n id: z.string(),\n agent: z.string(),\n user: z.string(),\n started: z.string(),\n ended: z.string().optional(),\n parent: z.string().optional(),\n parent_reason: z.string().optional(),\n plan: z.string().optional(), // backward compat read path\n plans: z.array(z.string()).optional(), // new: multiple plans\n branch: z.string().optional(),\n tags: z.array(z.string()).default([]),\n tools_used: z.number().int().optional(),\n files_changed: z.number().int().optional(),\n});\n\nexport const PLAN_STATUSES = ['active', 'in_progress', 'completed', 'abandoned'] as const;\n\nexport const PlanFrontmatterSchema = z.object({\n type: z.literal('plan'),\n id: z.string(),\n status: z.enum(PLAN_STATUSES).default('active'),\n created: z.string(),\n author: z.string().optional(),\n tags: z.array(z.string()).default([]),\n});\n\nexport const OBSERVATION_TYPES = ['gotcha', 'bug_fix', 'decision', 'discovery', 'trade_off', 'cross-cutting'] as const;\n\nexport const SPORE_STATUSES = ['active', 'superseded', 'archived'] as const;\nexport type SporeStatus = (typeof SPORE_STATUSES)[number];\n\nexport const SporeFrontmatterSchema = z.object({\n type: z.literal('spore'),\n id: z.string(),\n observation_type: z.string(),\n status: z.enum(SPORE_STATUSES).default('active'),\n session: z.string().optional(),\n plan: z.string().optional(),\n superseded_by: z.string().optional(),\n consolidated_from: z.array(z.string()).optional(),\n created: z.string(),\n tags: z.array(z.string()).default([]),\n});\n\nexport const ARTIFACT_TYPES = ['spec', 'plan', 'rfc', 'doc', 'other'] as const;\nexport type ArtifactType = (typeof ARTIFACT_TYPES)[number];\n\nexport const ArtifactFrontmatterSchema = z.object({\n type: z.literal('artifact'),\n id: z.string(),\n artifact_type: z.enum(ARTIFACT_TYPES).default('other'),\n source_path: z.string(),\n title: z.string(),\n last_captured_by: z.string(),\n created: z.string(),\n updated: z.string(),\n tags: z.array(z.string()).default([]),\n});\n\nexport const TeamMemberFrontmatterSchema = z.object({\n type: z.literal('team-member'),\n user: z.string(),\n joined: z.string(),\n role: z.string().optional(),\n tags: z.array(z.string()).default([]),\n});\n\nexport type SessionFrontmatter = z.infer<typeof SessionFrontmatterSchema>;\nexport type PlanFrontmatter = z.infer<typeof PlanFrontmatterSchema>;\nexport type SporeFrontmatter = z.infer<typeof SporeFrontmatterSchema>;\nexport type ObservationType = SporeFrontmatter['observation_type'];\nexport type ArtifactFrontmatter = z.infer<typeof ArtifactFrontmatterSchema>;\nexport type TeamMemberFrontmatter = z.infer<typeof TeamMemberFrontmatterSchema>;\n\nexport type NoteFrontmatter =\n | SessionFrontmatter\n | PlanFrontmatter\n | SporeFrontmatter\n | ArtifactFrontmatter\n | TeamMemberFrontmatter;\n\nexport interface VaultNote<T extends NoteFrontmatter = NoteFrontmatter> {\n path: string;\n frontmatter: T;\n content: string;\n}\n\nconst schemasByType: Record<string, z.ZodSchema> = {\n session: SessionFrontmatterSchema,\n plan: PlanFrontmatterSchema,\n spore: SporeFrontmatterSchema,\n artifact: ArtifactFrontmatterSchema,\n 'team-member': TeamMemberFrontmatterSchema,\n};\n\nexport function parseNoteFrontmatter(data: Record<string, unknown>): NoteFrontmatter {\n const type = data.type as string;\n const schema = schemasByType[type];\n if (!schema) {\n throw new Error(`Unknown note type: ${type}. Known types: ${Object.keys(schemasByType).join(', ')}`);\n }\n // gray-matter and YAML.parse return Date objects for ISO date strings.\n // Coerce them to strings before Zod validation.\n const coerced = coerceDatesToStrings(data);\n return schema.parse(coerced) as NoteFrontmatter;\n}\n\nfunction coerceDatesToStrings(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (value instanceof Date) {\n result[key] = value.toISOString();\n } else if (Array.isArray(value)) {\n result[key] = value.map((item) => item instanceof Date ? item.toISOString() : item);\n } else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n result[key] = coerceDatesToStrings(value as Record<string, unknown>);\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n","/**\n * MCP tool names, descriptions, and schema definitions.\n * Single source of truth for all tool metadata — referenced by the MCP server\n * and available to tests, logging, and documentation generators.\n */\nimport { OBSERVATION_TYPES, PLAN_STATUSES } from '../vault/types.js';\nimport { MCP_SEARCH_DEFAULT_LIMIT, MCP_SESSIONS_DEFAULT_LIMIT, MCP_SKILLS_DEFAULT_LIMIT } from '../constants.js';\n\n/** Plan statuses plus 'all' for filtering. */\nconst PLAN_STATUS_FILTER = [...PLAN_STATUSES, 'all'] as const;\nconst DEFAULT_CORTEX_PRIORITY = 100;\n\ninterface ToolInputSchema {\n type: 'object';\n properties: Record<string, unknown>;\n required?: string[];\n}\n\nexport interface ToolCortexMetadata {\n guidance: string;\n priority?: number;\n requiresTeam?: boolean;\n requiresCollective?: boolean;\n}\n\n/**\n * MCP tool annotations. These follow the MCP spec's `annotations` envelope\n * so clients can show the right UI affordances (confirm-before-run for\n * destructive tools, quiet auto-run for read-only ones, etc.). Bundle D\n * makes these mandatory for every Myco-registered tool.\n */\nexport interface ToolAnnotations {\n /** True if the tool never mutates state. */\n readOnlyHint: boolean;\n /**\n * True if the tool can destroy data or start work that's hard to undo.\n * For multi-op tools, set true if ANY op is destructive and describe\n * the op matrix in the tool description.\n */\n destructiveHint: boolean;\n /** True if calling the tool twice with the same input is safe. */\n idempotentHint: boolean;\n /** True if the tool reaches outside the local vault (network, other machines). */\n openWorldHint: boolean;\n}\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n inputSchema: ToolInputSchema;\n annotations?: ToolAnnotations;\n cortex?: ToolCortexMetadata;\n}\n\nexport function getToolCortexPriority(tool: Pick<ToolDefinition, 'cortex'>): number {\n return tool.cortex?.priority ?? DEFAULT_CORTEX_PRIORITY;\n}\n\n// --- Tool names ---\nexport const TOOL_SEARCH = 'myco_search';\nexport const TOOL_RECALL = 'myco_recall';\nexport const TOOL_REMEMBER = 'myco_remember';\nexport const TOOL_PLANS = 'myco_plans';\nexport const TOOL_SAVE_PLAN = 'myco_save_plan';\nexport const TOOL_SESSIONS = 'myco_sessions';\nexport const TOOL_TEAM = 'myco_team';\nexport const TOOL_GRAPH = 'myco_graph';\nexport const TOOL_SUPERSEDE = 'myco_supersede';\nexport const TOOL_CONSOLIDATE = 'myco_consolidate';\nexport const TOOL_CONTEXT = 'myco_context';\nexport const TOOL_SKILLS = 'myco_skills';\nexport const TOOL_SKILL_CANDIDATES = 'myco_skill_candidates';\nexport const TOOL_COLLECTIVE_SEARCH = 'collective_search';\nexport const TOOL_COLLECTIVE_PROJECTS = 'collective_projects';\nexport const TOOL_COLLECTIVE_PROJECT = 'collective_project';\nexport const TOOL_CORTEX = 'myco_cortex';\nexport const TOOL_RUNS = 'myco_runs';\nexport const TOOL_EVALUATIONS = 'myco_evaluations';\nexport const TOOL_WRITE_INTENTS = 'myco_write_intents';\nexport const TOOL_PHASE_AUDIT = 'myco_phase_audit';\nexport const TOOL_RESUME_RUN = 'myco_resume_run';\nexport const TOOL_DIGEST_REVISIONS = 'myco_digest_revisions';\n\n// --- Shared property descriptions (used by multiple tools) ---\nconst PROP_BRANCH = 'Git branch name to find related sessions and plans';\nconst PROP_SINCE = 'ISO timestamp — entries after this date';\nconst PROP_TAGS = 'Tags for discoverability — component names, technologies, concepts';\n\n// --- Tool definitions ---\nexport const TOOL_DEFINITIONS: ToolDefinition[] = [\n {\n name: TOOL_SEARCH,\n description: 'Search the vault for prior sessions, spores, plans, and artifacts. Use before making design decisions, when debugging non-obvious issues, or when wondering why code is structured a certain way.',\n cortex: {\n guidance: 'Use for prior decisions, bugs, and rationale when you know the topic but not the exact note.',\n priority: 20,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n query: { type: 'string', description: 'Natural language search query — describe what you are looking for' },\n type: { type: 'string', enum: ['session', 'plan', 'spore', 'all'], description: 'Filter by note type (default: all)' },\n limit: { type: 'number', description: `Max results (default: ${MCP_SEARCH_DEFAULT_LIMIT})` },\n observation_type: { type: 'string', description: 'Optional semantic filter for spore observation type (decision, gotcha, discovery, etc.)' },\n status: { type: 'string', description: 'Optional semantic filter for record status (for example active)' },\n since: { type: 'number', description: 'Optional created_at lower bound in epoch seconds' },\n until: { type: 'number', description: 'Optional created_at upper bound in epoch seconds' },\n },\n required: ['query'],\n },\n },\n {\n name: TOOL_RECALL,\n description: 'Look up a specific vault note by ID — returns the full content of a session, spore, or plan. Use when you have a note ID from search results or graph traversal and need the complete details.',\n cortex: {\n guidance: 'Use after search finds a promising result and you need the full note.',\n priority: 30,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n note_id: { type: 'string', description: 'Note ID to look up (e.g., \"session-abc123\", \"decision-xyz789\", \"plan-feature-x\")' },\n },\n required: ['note_id'],\n },\n },\n {\n name: TOOL_REMEMBER,\n description: 'Save a decision, gotcha, bug fix, discovery, or trade-off as a permanent spore. Use after making a key decision, fixing a tricky bug, discovering something non-obvious, or encountering a gotcha. Session association is derived by the daemon — the MCP client does not pass it.',\n cortex: {\n guidance: 'Use to save durable decisions, gotchas, discoveries, or bug fixes from this work.',\n priority: 90,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n content: { type: 'string', description: 'The observation — include context, reasoning, and what someone encountering this in the future needs to know' },\n type: { type: 'string', enum: OBSERVATION_TYPES, description: `Observation type: ${OBSERVATION_TYPES.join(', ')}` },\n tags: { type: 'array', items: { type: 'string' }, description: PROP_TAGS },\n },\n required: ['content', 'type'],\n },\n },\n {\n name: TOOL_PLANS,\n description: 'List or delete implementation plans. op: \"list\" (default) returns plan summaries — filter by status, session, or a single id. op: \"delete\" removes a plan by id; cross-machine rows require force_remote: true. Use list to check what work is in flight before starting new tasks; use delete when retiring obsolete plans.',\n annotations: {\n // Destructive because op: \"delete\" removes a plan and enqueues a tombstone.\n // Consumers should confirm before running this tool with op: \"delete\".\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use op: \"list\" before implementation when approved plans or specs may already exist; pass session to scope to the current work, or id to fetch a single plan with content.',\n priority: 50,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n op: { type: 'string', enum: ['list', 'delete'], description: 'Operation (default: \"list\")' },\n status: { type: 'string', enum: PLAN_STATUS_FILTER, description: 'Filter by status (default: all statuses); ignored for op: \"delete\"' },\n id: { type: 'string', description: 'Plan id. Required for op: \"delete\". For op: \"list\" returns that plan with content.' },\n session: { type: 'string', description: 'Filter list to plans belonging to this session; mutually exclusive with id.' },\n limit: { type: 'number', description: 'Max results for op: \"list\"' },\n force_remote: { type: 'boolean', description: 'Allow op: \"delete\" to remove a plan belonging to another machine. Enqueues a tombstone for team sync.' },\n },\n },\n },\n {\n name: TOOL_SAVE_PLAN,\n description: 'Persist a plan directly into Myco for a session. Use this when you generated or revised a plan and want it captured reliably. Pass exactly one of `source_path` or `plan_key` — `source_path` when the plan is also written to disk (so direct persistence and file capture reconcile to one logical plan), or `plan_key` for non-file-backed plans. The daemon rejects requests that set neither or both. Note: plan_key creates a stable namespace (session:<id>:key:<name>) distinct from transcript <tag> capture (session:<id>:tag:<name>) — the two do not merge. Dropping the transcript tag while also calling myco_save_plan with plan_key=tag will produce two separate rows.',\n cortex: {\n guidance: 'Use when you create or materially revise a plan and want it persisted to Myco. Pass `source_path` when the plan is also written to disk; otherwise use a stable `plan_key`. Note: `plan_key` rows are a separate namespace from transcript `<tag>` capture — reusing the same name in both channels creates two rows, not one.',\n priority: 60,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n session_id: { type: 'string', description: 'Session id the plan belongs to' },\n content: { type: 'string', description: 'Markdown plan content to persist' },\n source_path: { type: 'string', description: 'Path to the plan file when the plan is also written to disk. Pass this OR plan_key, never both.' },\n plan_key: { type: 'string', description: 'Stable key for non-file-backed plans (for example: primary). Pass this OR source_path, never both.' },\n title: { type: 'string', description: 'Optional explicit title. Defaults to the first Markdown H1, then file name or humanized plan_key.' },\n status: { type: 'string', enum: PLAN_STATUSES, description: `Plan status: ${PLAN_STATUSES.join(', ')}` },\n tags: { type: 'array', items: { type: 'string' }, description: PROP_TAGS },\n },\n required: ['session_id', 'content'],\n },\n },\n {\n name: TOOL_SESSIONS,\n description: 'Browse past coding sessions with summaries, tools used, and linked spores. Use to understand what work has been done on a feature or branch.',\n cortex: {\n guidance: 'Use when continuing related work or recovering recent implementation context.',\n priority: 40,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n plan: { type: 'string', description: 'Filter to the session linked to this plan id' },\n branch: { type: 'string', description: PROP_BRANCH },\n user: { type: 'string', description: 'Filter sessions by user' },\n since: { type: 'string', description: PROP_SINCE },\n status: { type: 'string', description: 'Filter by session status (e.g., active, completed)' },\n limit: { type: 'number', description: `Max results (default: ${MCP_SESSIONS_DEFAULT_LIMIT})` },\n },\n },\n },\n {\n name: TOOL_TEAM,\n description: 'List team members registered in the vault. Returns id, user, role, joined, and tags per member. Phase-1 scope: no filters.',\n cortex: {\n guidance: 'Use for current team topology and shared project context.',\n priority: 70,\n requiresTeam: true,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {},\n },\n },\n {\n name: TOOL_GRAPH,\n description: 'Traverse connections between records via graph edges — explore how sessions, spores, and plans relate to each other.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n note_id: { type: 'string', description: 'Note ID to start from (e.g., \"session-abc123\" or \"decision-xyz789\")' },\n direction: { type: 'string', enum: ['incoming', 'outgoing', 'both'], description: 'Link direction to follow (default: both)' },\n depth: { type: 'number', description: 'How many hops to traverse, 1-3 (default: 1)' },\n },\n required: ['note_id'],\n },\n },\n {\n name: TOOL_SUPERSEDE,\n description: 'Mark a spore as outdated and replaced by a newer one. Use when a decision was reversed, a gotcha was fixed, a discovery was wrong, or the codebase changed and an observation no longer applies. The old spore is preserved but marked superseded.',\n cortex: {\n guidance: 'Use when existing knowledge is outdated and should stop guiding future runs.',\n priority: 100,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n old_spore_id: { type: 'string', description: 'ID of the outdated spore (e.g., \"decision-abc123\")' },\n new_spore_id: { type: 'string', description: 'ID of the replacement spore' },\n reason: { type: 'string', description: 'Why the old spore is being superseded' },\n },\n required: ['old_spore_id', 'new_spore_id'],\n },\n },\n {\n name: TOOL_CONSOLIDATE,\n description: 'Merge 2+ related spores into a single comprehensive wisdom note. Inserts a new spore with the consolidated content; each source spore is marked superseded with a resolution_events row linking it to the new wisdom spore. Use when multiple observations describe aspects of the same insight, share a root cause, or would be more useful as one reference.',\n cortex: {\n guidance: 'Use when several related learnings should become one durable wisdom artifact.',\n priority: 110,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n source_spore_ids: { type: 'array', items: { type: 'string' }, description: 'IDs of the spores to merge (minimum 2)' },\n consolidated_content: { type: 'string', description: 'The merged, comprehensive content — synthesize, do not just concatenate' },\n observation_type: { type: 'string', enum: OBSERVATION_TYPES, description: `Type for the consolidated wisdom note: ${OBSERVATION_TYPES.join(', ')}` },\n tags: { type: 'array', items: { type: 'string' }, description: PROP_TAGS },\n reason: { type: 'string', description: 'Optional reason recorded on each resolution event' },\n },\n required: ['source_spore_ids', 'consolidated_content', 'observation_type'],\n },\n },\n {\n name: TOOL_CONTEXT,\n description: \"Retrieve Myco's pre-computed project digest — a rich, always-current synthesis of project history, decisions, patterns, active work, and institutional knowledge. Call this at the start of a new task or session to orient yourself on the project before taking action; call it again after long interruptions or when switching contexts. This is NOT a search — it's the project's accumulated understanding, served instantly. Available tiers: 1500 (executive briefing, one-screen overview), 5000 (deep onboarding, default), 10000 (comprehensive institutional knowledge). Prefer this over myco_search when you need broad project orientation; use myco_search when you need to find specific prior decisions or bug fixes.\",\n cortex: {\n guidance: 'Use for broad project orientation or when you want the current digest before planning changes.',\n priority: 10,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n tier: {\n type: 'number',\n enum: [1500, 5000, 10000],\n description: 'Token budget tier. Larger tiers include more detail. Default: 5000.',\n },\n },\n },\n },\n {\n name: TOOL_SKILLS,\n description: 'List and inspect skills generated by Myco. Use to see what skills are active, check skill details, or find skills by status.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n id: { type: 'string', description: 'Get a specific skill by ID or name' },\n status: { type: 'string', description: 'Filter by status: active, stale, retired' },\n limit: { type: 'number', description: `Max results (default: ${MCP_SKILLS_DEFAULT_LIMIT})` },\n },\n },\n },\n {\n name: TOOL_SKILL_CANDIDATES,\n description: 'List and manage skill candidates — observations identified as potential skills. Use to see pending candidates, approve, or dismiss them.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n id: { type: 'string', description: 'Get a specific candidate by ID' },\n action: { type: 'string', enum: ['list', 'approve', 'dismiss'], description: \"Action to perform (default: 'list')\" },\n status: { type: 'string', description: 'Filter by status: identified, approved, generated, dismissed' },\n limit: { type: 'number', description: `Max results (default: ${MCP_SKILLS_DEFAULT_LIMIT})` },\n },\n },\n },\n {\n name: TOOL_CORTEX,\n description: 'Cortex instruction + prompt-builder surface. op: \"get\" returns the current session-start instructions snapshot. op: \"refresh\" triggers the cortex-instructions task to regenerate them. op: \"build_prompt\" starts the cortex-prompt-builder task for a goal (required) and optional symbiont. op: \"get_prompt_result\" polls a prompt-builder run by run_id. Refresh and build_prompt are not read-only — they start background runs.',\n annotations: {\n // Mixed: get/get_prompt_result are read-only, refresh/build_prompt kick\n // off background work. Mark conservatively — consumers should not silently\n // auto-run this tool.\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use op: \"get\" to read your own session-start Cortex instructions; use op: \"build_prompt\" + \"get_prompt_result\" when you need the prompt-builder to draft a prompt for a specific goal.',\n priority: 95,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n op: { type: 'string', enum: ['get', 'refresh', 'build_prompt', 'get_prompt_result'], description: 'Cortex operation' },\n run_id: { type: 'string', description: 'Required for op: \"get_prompt_result\"' },\n goal: { type: 'string', description: 'Required for op: \"build_prompt\" — the task the prompt will be built for' },\n symbiont: { type: 'string', description: 'Optional symbiont/agent name the prompt should be tuned for; defaults to the first enabled symbiont' },\n },\n required: ['op'],\n },\n },\n {\n name: TOOL_RUNS,\n description: 'Read agent run history. op: \"list\" (default) returns recent runs with runtime/provider/model/token/cost/reasoning fields — filter by task, agent_id, limit. op: \"get\" with id returns a single run including write_intents totals and duration_ms. Use after a run completes to check your own token budget, cost, and reasoning level — particularly useful when debugging a run that exhausted context.',\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use op: \"get\" with your run id to check your own token budget, cost, and reasoning level — especially after a run that exhausted context or failed. Use op: \"list\" to browse recent runs for a task.',\n priority: 85,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n op: { type: 'string', enum: ['list', 'get'], description: 'Operation (default: \"list\")' },\n id: { type: 'string', description: 'Required for op: \"get\" — the run id' },\n task: { type: 'string', description: 'Filter op: \"list\" by task name' },\n agent_id: { type: 'string', description: 'Filter op: \"list\" by agent id' },\n limit: { type: 'number', description: 'Max results for op: \"list\" (default: 50)' },\n },\n },\n },\n {\n name: TOOL_EVALUATIONS,\n description: 'Create, list, or fetch agent evaluations. An evaluation fans out a single task across a cartesian product of (runtime × reasoning × model) cells so outputs can be compared side by side. op: \"list\" (default) returns newest-first summaries with an optional limit. op: \"get\" with id returns the evaluation + child runs + aggregate stats. op: \"create\" requires task_id and matrix; cells execute sequentially in the background — the response returns the evaluationId + cellCount. op: \"create\" is NOT read-only; it starts background runs.',\n annotations: {\n // Mixed ops: list/get are read-only, create kicks off background runs.\n // Mark conservatively so clients confirm before auto-running with op: \"create\".\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use op: \"list\" to see recent matrix evaluations, op: \"get\" to inspect cells + aggregate stats, and op: \"create\" to fan a task out across runtime/reasoning/model cells for side-by-side comparison.',\n priority: 88,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n op: { type: 'string', enum: ['list', 'get', 'create'], description: 'Operation (default: \"list\")' },\n status: { type: 'string', description: 'Filter op: \"list\" by status (reserved; currently ignored by the route)' },\n limit: { type: 'number', description: 'Max results for op: \"list\" (default: 50)' },\n id: { type: 'string', description: 'Required for op: \"get\" — the evaluation id' },\n task_id: { type: 'string', description: 'Required for op: \"create\" — id of the agent task to evaluate' },\n matrix: {\n type: 'object',\n description: 'Required for op: \"create\". Matrix payload: { runtimes?, reasoningLevels?, models?, dryRun?, notes?, phases? }. Empty arrays expand to defaults. See /api/agent/evaluations POST body for full shape.',\n },\n notes: { type: 'string', description: 'Optional notes stored alongside the evaluation row (op: \"create\" only)' },\n },\n },\n },\n {\n name: TOOL_WRITE_INTENTS,\n description: 'Inspect the write-intents recorded during a dry-run — what the agent would have done (tool_name, tool_input, synthetic_output) without actually writing. Paginated via limit (default 500, max 5000) and offset. Use with myco_runs to verify safety before re-running the same task without dry_run.',\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use after a dry-run to inspect what writes the agent would have performed — close the \"dry-run → verify → real-run\" loop before repeating the task without dry_run.',\n priority: 86,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n run_id: { type: 'string', description: 'The run id whose write-intents you want to inspect' },\n limit: { type: 'number', description: 'Max results (default: 500, max: 5000)' },\n offset: { type: 'number', description: 'Pagination offset (default: 0)' },\n },\n required: ['run_id'],\n },\n },\n {\n name: TOOL_PHASE_AUDIT,\n description: 'Read the per-phase audit trail for an agent run — what each phase did, its cost, tool-call counts, reasoning level, and any write intents. Returns a joined view over agent_runs, agent_reports, agent_turns, usage_data, checkpoints, and (for dry runs) agent_run_write_intents. Essential for debugging a failed or mis-executing run.',\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use when debugging a failed or mis-executing run — returns the per-phase cost, tool counts, reasoning level, and write intents in one payload.',\n priority: 87,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n run_id: { type: 'string', description: 'The run id whose phase audit you want to inspect' },\n },\n required: ['run_id'],\n },\n },\n {\n name: TOOL_RESUME_RUN,\n description: 'Resume a paused or interrupted agent run. The run must be in a resumable state (resumable=1 AND status=\"failed\" per the route) — check status via myco_runs first. The resume starts a new background phase and returns immediately with {ok, message, runId}. NOT idempotent: each successful call starts a fresh phase.',\n annotations: {\n // Starts a new background phase; mark as mutating + non-idempotent so\n // clients confirm before repeating. Not \"destructive\" (no data is\n // removed) but also not \"read-only\".\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use to resume a paused or interrupted agent run after verifying (via myco_runs) that its resumable flag is set and its status is \"failed\".',\n priority: 89,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n id: { type: 'string', description: 'The run id to resume' },\n mode: { type: 'string', enum: ['manual', 'scheduled'], description: 'Resume mode (default: \"manual\"). Scheduled is reserved for the daemon scheduler.' },\n },\n required: ['id'],\n },\n },\n {\n name: TOOL_DIGEST_REVISIONS,\n description: 'List historical digest revisions for the given (agent_id, tier). Revisions are append-only, so this surface shows how the project\\'s digest has evolved over time. tier is required; agent_id defaults to the primary agent on the daemon side. Restore (rolling a past revision back into the live digest) is intentionally UI-only and is NOT exposed via MCP.',\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n cortex: {\n guidance: 'Use to see how the project digest has evolved for a given tier — restore is UI-only.',\n priority: 92,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n agent_id: { type: 'string', description: 'Optional — defaults to the primary agent on the daemon side' },\n tier: { type: 'number', description: 'Required — the digest tier (for example 1500, 5000, 10000)' },\n limit: { type: 'number', description: 'Max results (default: 50)' },\n },\n required: ['tier'],\n },\n },\n];\n\nexport const COLLECTIVE_TOOL_DEFINITIONS: ToolDefinition[] = [\n {\n name: TOOL_COLLECTIVE_SEARCH,\n description: 'Search across connected projects in the active Myco Collective. Results include project attribution.',\n cortex: {\n guidance: 'Use for cross-project knowledge across the connected collective.',\n priority: 80,\n requiresCollective: true,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n query: { type: 'string', description: 'Natural language search query across the connected Collective projects' },\n project: { type: 'string', description: 'Optional project id or project name filter' },\n limit: { type: 'number', description: `Max results (default: ${MCP_SEARCH_DEFAULT_LIMIT})` },\n types: { type: 'array', items: { type: 'string' }, description: 'Optional content type filter for remote semantic search' },\n observation_type: { type: 'string', description: 'Optional spore observation type filter for remote semantic search' },\n status: { type: 'string', description: 'Optional record status filter for remote semantic search' },\n since: { type: 'number', description: 'Optional created_at lower bound in epoch seconds' },\n until: { type: 'number', description: 'Optional created_at upper bound in epoch seconds' },\n session_id: { type: 'string', description: 'Optional session id metadata filter' },\n source_path: { type: 'string', description: 'Optional source path metadata filter' },\n name: { type: 'string', description: 'Optional name metadata filter' },\n },\n required: ['query'],\n },\n },\n {\n name: TOOL_COLLECTIVE_PROJECTS,\n description: 'List the projects connected to the active Myco Collective.',\n cortex: {\n guidance: 'Use to discover relevant collective projects before drilling deeper.',\n priority: 81,\n requiresCollective: true,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {},\n },\n },\n {\n name: TOOL_COLLECTIVE_PROJECT,\n description: 'Get metadata for a single project connected to the active Myco Collective.',\n cortex: {\n guidance: 'Use when you know the collective project and need its focused context.',\n priority: 82,\n requiresCollective: true,\n },\n inputSchema: {\n type: 'object' as const,\n properties: {\n project: { type: 'string', description: 'Project id or project name' },\n include_digest: { type: 'boolean', description: 'Request digest information when available' },\n },\n required: ['project'],\n },\n },\n] as const;\n"],"mappings":";;;;;;;;;;;AAEO,IAAM,2BAA2B,iBAAE,OAAO;AAAA,EAC/C,MAAM,iBAAE,QAAQ,SAAS;AAAA,EACzB,IAAI,iBAAE,OAAO;AAAA,EACb,OAAO,iBAAE,OAAO;AAAA,EAChB,MAAM,iBAAE,OAAO;AAAA,EACf,SAAS,iBAAE,OAAO;AAAA,EAClB,OAAO,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,QAAQ,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,eAAe,iBAAE,OAAO,EAAE,SAAS;AAAA,EACnC,MAAM,iBAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAC1B,OAAO,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,EACpC,QAAQ,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,MAAM,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpC,YAAY,iBAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EACtC,eAAe,iBAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAC3C,CAAC;AAEM,IAAM,gBAAgB,CAAC,UAAU,eAAe,aAAa,WAAW;AAExE,IAAM,wBAAwB,iBAAE,OAAO;AAAA,EAC5C,MAAM,iBAAE,QAAQ,MAAM;AAAA,EACtB,IAAI,iBAAE,OAAO;AAAA,EACb,QAAQ,iBAAE,KAAK,aAAa,EAAE,QAAQ,QAAQ;AAAA,EAC9C,SAAS,iBAAE,OAAO;AAAA,EAClB,QAAQ,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,MAAM,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAEM,IAAM,oBAAoB,CAAC,UAAU,WAAW,YAAY,aAAa,aAAa,eAAe;AAErG,IAAM,iBAAiB,CAAC,UAAU,cAAc,UAAU;AAG1D,IAAM,yBAAyB,iBAAE,OAAO;AAAA,EAC7C,MAAM,iBAAE,QAAQ,OAAO;AAAA,EACvB,IAAI,iBAAE,OAAO;AAAA,EACb,kBAAkB,iBAAE,OAAO;AAAA,EAC3B,QAAQ,iBAAE,KAAK,cAAc,EAAE,QAAQ,QAAQ;AAAA,EAC/C,SAAS,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,MAAM,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,eAAe,iBAAE,OAAO,EAAE,SAAS;AAAA,EACnC,mBAAmB,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAChD,SAAS,iBAAE,OAAO;AAAA,EAClB,MAAM,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAEM,IAAM,iBAAiB,CAAC,QAAQ,QAAQ,OAAO,OAAO,OAAO;AAG7D,IAAM,4BAA4B,iBAAE,OAAO;AAAA,EAChD,MAAM,iBAAE,QAAQ,UAAU;AAAA,EAC1B,IAAI,iBAAE,OAAO;AAAA,EACb,eAAe,iBAAE,KAAK,cAAc,EAAE,QAAQ,OAAO;AAAA,EACrD,aAAa,iBAAE,OAAO;AAAA,EACtB,OAAO,iBAAE,OAAO;AAAA,EAChB,kBAAkB,iBAAE,OAAO;AAAA,EAC3B,SAAS,iBAAE,OAAO;AAAA,EAClB,SAAS,iBAAE,OAAO;AAAA,EAClB,MAAM,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAEM,IAAM,8BAA8B,iBAAE,OAAO;AAAA,EAClD,MAAM,iBAAE,QAAQ,aAAa;AAAA,EAC7B,MAAM,iBAAE,OAAO;AAAA,EACf,QAAQ,iBAAE,OAAO;AAAA,EACjB,MAAM,iBAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,MAAM,iBAAE,MAAM,iBAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;;;AC5DD,IAAM,qBAAqB,CAAC,GAAG,eAAe,KAAK;AACnD,IAAM,0BAA0B;AA4CzB,SAAS,sBAAsB,MAA8C;AAClF,SAAO,KAAK,QAAQ,YAAY;AAClC;AAGO,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,aAAa;AACnB,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AACtB,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AACzB,IAAM,eAAe;AACrB,IAAM,cAAc;AACpB,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,cAAc;AACpB,IAAM,YAAY;AAClB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAGrC,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,YAAY;AAGX,IAAM,mBAAqC;AAAA,EAChD;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO,EAAE,MAAM,UAAU,aAAa,yEAAoE;AAAA,QAC1G,MAAM,EAAE,MAAM,UAAU,MAAM,CAAC,WAAW,QAAQ,SAAS,KAAK,GAAG,aAAa,qCAAqC;AAAA,QACrH,OAAO,EAAE,MAAM,UAAU,aAAa,yBAAyB,wBAAwB,IAAI;AAAA,QAC3F,kBAAkB,EAAE,MAAM,UAAU,aAAa,0FAA0F;AAAA,QAC3I,QAAQ,EAAE,MAAM,UAAU,aAAa,kEAAkE;AAAA,QACzG,OAAO,EAAE,MAAM,UAAU,aAAa,mDAAmD;AAAA,QACzF,OAAO,EAAE,MAAM,UAAU,aAAa,mDAAmD;AAAA,MAC3F;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,mFAAmF;AAAA,MAC7H;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,oHAA+G;AAAA,QACvJ,MAAM,EAAE,MAAM,UAAU,MAAM,mBAAmB,aAAa,qBAAqB,kBAAkB,KAAK,IAAI,CAAC,GAAG;AAAA,QAClH,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,UAAU;AAAA,MAC3E;AAAA,MACA,UAAU,CAAC,WAAW,MAAM;AAAA,IAC9B;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA;AAAA;AAAA,MAGX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,MAAM,CAAC,QAAQ,QAAQ,GAAG,aAAa,8BAA8B;AAAA,QAC3F,QAAQ,EAAE,MAAM,UAAU,MAAM,oBAAoB,aAAa,qEAAqE;AAAA,QACtI,IAAI,EAAE,MAAM,UAAU,aAAa,qFAAqF;AAAA,QACxH,SAAS,EAAE,MAAM,UAAU,aAAa,8EAA8E;AAAA,QACtH,OAAO,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,QACnE,cAAc,EAAE,MAAM,WAAW,aAAa,wGAAwG;AAAA,MACxJ;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,YAAY,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,QAC5E,SAAS,EAAE,MAAM,UAAU,aAAa,mCAAmC;AAAA,QAC3E,aAAa,EAAE,MAAM,UAAU,aAAa,kGAAkG;AAAA,QAC9I,UAAU,EAAE,MAAM,UAAU,aAAa,qGAAqG;AAAA,QAC9I,OAAO,EAAE,MAAM,UAAU,aAAa,oGAAoG;AAAA,QAC1I,QAAQ,EAAE,MAAM,UAAU,MAAM,eAAe,aAAa,gBAAgB,cAAc,KAAK,IAAI,CAAC,GAAG;AAAA,QACvG,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,UAAU;AAAA,MAC3E;AAAA,MACA,UAAU,CAAC,cAAc,SAAS;AAAA,IACpC;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,MAAM,EAAE,MAAM,UAAU,aAAa,+CAA+C;AAAA,QACpF,QAAQ,EAAE,MAAM,UAAU,aAAa,YAAY;AAAA,QACnD,MAAM,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,QAC/D,OAAO,EAAE,MAAM,UAAU,aAAa,WAAW;AAAA,QACjD,QAAQ,EAAE,MAAM,UAAU,aAAa,qDAAqD;AAAA,QAC5F,OAAO,EAAE,MAAM,UAAU,aAAa,yBAAyB,0BAA0B,IAAI;AAAA,MAC/F;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,IACf;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,sEAAsE;AAAA,QAC9G,WAAW,EAAE,MAAM,UAAU,MAAM,CAAC,YAAY,YAAY,MAAM,GAAG,aAAa,2CAA2C;AAAA,QAC7H,OAAO,EAAE,MAAM,UAAU,aAAa,8CAA8C;AAAA,MACtF;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,cAAc,EAAE,MAAM,UAAU,aAAa,qDAAqD;AAAA,QAClG,cAAc,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,QAC3E,QAAQ,EAAE,MAAM,UAAU,aAAa,wCAAwC;AAAA,MACjF;AAAA,MACA,UAAU,CAAC,gBAAgB,cAAc;AAAA,IAC3C;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,kBAAkB,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,yCAAyC;AAAA,QACpH,sBAAsB,EAAE,MAAM,UAAU,aAAa,+EAA0E;AAAA,QAC/H,kBAAkB,EAAE,MAAM,UAAU,MAAM,mBAAmB,aAAa,0CAA0C,kBAAkB,KAAK,IAAI,CAAC,GAAG;AAAA,QACnJ,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,UAAU;AAAA,QACzE,QAAQ,EAAE,MAAM,UAAU,aAAa,oDAAoD;AAAA,MAC7F;AAAA,MACA,UAAU,CAAC,oBAAoB,wBAAwB,kBAAkB;AAAA,IAC3E;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,MAAM,CAAC,MAAM,KAAM,GAAK;AAAA,UACxB,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,aAAa,qCAAqC;AAAA,QACxE,QAAQ,EAAE,MAAM,UAAU,aAAa,2CAA2C;AAAA,QAClF,OAAO,EAAE,MAAM,UAAU,aAAa,yBAAyB,wBAAwB,IAAI;AAAA,MAC7F;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,QACpE,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,QAAQ,WAAW,SAAS,GAAG,aAAa,sCAAsC;AAAA,QACnH,QAAQ,EAAE,MAAM,UAAU,aAAa,+DAA+D;AAAA,QACtG,OAAO,EAAE,MAAM,UAAU,aAAa,yBAAyB,wBAAwB,IAAI;AAAA,MAC7F;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA;AAAA;AAAA;AAAA,MAIX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,WAAW,gBAAgB,mBAAmB,GAAG,aAAa,mBAAmB;AAAA,QACrH,QAAQ,EAAE,MAAM,UAAU,aAAa,uCAAuC;AAAA,QAC9E,MAAM,EAAE,MAAM,UAAU,aAAa,+EAA0E;AAAA,QAC/G,UAAU,EAAE,MAAM,UAAU,aAAa,sGAAsG;AAAA,MACjJ;AAAA,MACA,UAAU,CAAC,IAAI;AAAA,IACjB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,MAAM,CAAC,QAAQ,KAAK,GAAG,aAAa,8BAA8B;AAAA,QACxF,IAAI,EAAE,MAAM,UAAU,aAAa,2CAAsC;AAAA,QACzE,MAAM,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,QACtE,UAAU,EAAE,MAAM,UAAU,aAAa,gCAAgC;AAAA,QACzE,OAAO,EAAE,MAAM,UAAU,aAAa,2CAA2C;AAAA,MACnF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA;AAAA;AAAA,MAGX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,MAAM,CAAC,QAAQ,OAAO,QAAQ,GAAG,aAAa,8BAA8B;AAAA,QAClG,QAAQ,EAAE,MAAM,UAAU,aAAa,yEAAyE;AAAA,QAChH,OAAO,EAAE,MAAM,UAAU,aAAa,2CAA2C;AAAA,QACjF,IAAI,EAAE,MAAM,UAAU,aAAa,kDAA6C;AAAA,QAChF,SAAS,EAAE,MAAM,UAAU,aAAa,oEAA+D;AAAA,QACvG,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,OAAO,EAAE,MAAM,UAAU,aAAa,yEAAyE;AAAA,MACjH;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,QAAQ,EAAE,MAAM,UAAU,aAAa,qDAAqD;AAAA,QAC5F,OAAO,EAAE,MAAM,UAAU,aAAa,wCAAwC;AAAA,QAC9E,QAAQ,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,MAC1E;AAAA,MACA,UAAU,CAAC,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,QAAQ,EAAE,MAAM,UAAU,aAAa,mDAAmD;AAAA,MAC5F;AAAA,MACA,UAAU,CAAC,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA;AAAA;AAAA;AAAA,MAIX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,IAAI,EAAE,MAAM,UAAU,aAAa,uBAAuB;AAAA,QAC1D,MAAM,EAAE,MAAM,UAAU,MAAM,CAAC,UAAU,WAAW,GAAG,aAAa,mFAAmF;AAAA,MACzJ;AAAA,MACA,UAAU,CAAC,IAAI;AAAA,IACjB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,UAAU,EAAE,MAAM,UAAU,aAAa,mEAA8D;AAAA,QACvG,MAAM,EAAE,MAAM,UAAU,aAAa,kEAA6D;AAAA,QAClG,OAAO,EAAE,MAAM,UAAU,aAAa,4BAA4B;AAAA,MACpE;AAAA,MACA,UAAU,CAAC,MAAM;AAAA,IACnB;AAAA,EACF;AACF;AAEO,IAAM,8BAAgD;AAAA,EAC3D;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,MACV,oBAAoB;AAAA,IACtB;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO,EAAE,MAAM,UAAU,aAAa,yEAAyE;AAAA,QAC/G,SAAS,EAAE,MAAM,UAAU,aAAa,6CAA6C;AAAA,QACrF,OAAO,EAAE,MAAM,UAAU,aAAa,yBAAyB,wBAAwB,IAAI;AAAA,QAC3F,OAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,0DAA0D;AAAA,QAC1H,kBAAkB,EAAE,MAAM,UAAU,aAAa,oEAAoE;AAAA,QACrH,QAAQ,EAAE,MAAM,UAAU,aAAa,2DAA2D;AAAA,QAClG,OAAO,EAAE,MAAM,UAAU,aAAa,mDAAmD;AAAA,QACzF,OAAO,EAAE,MAAM,UAAU,aAAa,mDAAmD;AAAA,QACzF,YAAY,EAAE,MAAM,UAAU,aAAa,sCAAsC;AAAA,QACjF,aAAa,EAAE,MAAM,UAAU,aAAa,uCAAuC;AAAA,QACnF,MAAM,EAAE,MAAM,UAAU,aAAa,gCAAgC;AAAA,MACvE;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,MACV,oBAAoB;AAAA,IACtB;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,IACf;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,UAAU;AAAA,MACV,UAAU;AAAA,MACV,oBAAoB;AAAA,IACtB;AAAA,IACA,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,QACrE,gBAAgB,EAAE,MAAM,WAAW,aAAa,4CAA4C;AAAA,MAC9F;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AACF;","names":[]}
@@ -2,6 +2,9 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  getAtPath
4
4
  } from "./chunk-ZXZPJJN3.js";
5
+ import {
6
+ DEFAULT_SYMBIONT_NAME
7
+ } from "./chunk-6C6QZ4PM.js";
5
8
 
6
9
  // src/hooks/capture-rules.ts
7
10
  function evaluateUserPromptRules(manifests, detectedAgent, ctx) {
@@ -34,8 +37,9 @@ function evaluateSessionCaptureRules(manifests, detectedAgent, ctx) {
34
37
  return evaluateSessionStartRules(manifests, detectedAgent, ctx);
35
38
  }
36
39
  function scopePermits(rule, owningAgent, detectedAgent) {
37
- if (rule.scope === "any_agent") return true;
38
- return owningAgent === detectedAgent;
40
+ if (owningAgent === detectedAgent) return true;
41
+ if (rule.scope !== "any_agent") return false;
42
+ return detectedAgent === DEFAULT_SYMBIONT_NAME;
39
43
  }
40
44
  function whenMatches(rule, ctx) {
41
45
  const {
@@ -114,4 +118,4 @@ export {
114
118
  evaluateSessionCaptureRules,
115
119
  readTranscriptMeta
116
120
  };
117
- //# sourceMappingURL=chunk-XL75KZGI.js.map
121
+ //# sourceMappingURL=chunk-EKZG2MCD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/capture-rules.ts","../src/hooks/transcript-meta.ts"],"sourcesContent":["/**\n * Generic capture-rule evaluator.\n *\n * Each symbiont manifest declares `capture.rules` — a list of `{ event,\n * when, action }` records that describe how Myco should filter captured\n * events for that agent. This module loads rules from every manifest\n * in one place and exposes a pure evaluator the hook handlers call\n * without knowing anything symbiont-specific.\n *\n * Adding a new symbiont's capture behavior is a YAML-only change: edit\n * that agent's manifest file, no hook or evaluator changes needed.\n *\n * Rule scope (`this_agent` vs `any_agent`) lets rules opt into running\n * even when agent detection itself fails — useful for ephemeral\n * sub-invocations that legitimately lack the signals we key on.\n *\n * Conditions should prefer structural signals (e.g.,\n * `transcript_path_missing`) over text matching so rules stay robust\n * across upstream agent updates.\n */\n\nimport type { CaptureRule, SymbiontManifest } from '../symbionts/manifest-schema.js';\nimport { getAtPath } from '../utils/dot-path.js';\nimport { DEFAULT_SYMBIONT_NAME } from '../constants.js';\n\n/** Structured context a rule can match against at UserPromptSubmit time. */\nexport interface UserPromptRuleContext {\n /** The user prompt text as received from the hook. */\n prompt: string;\n /** Transcript path from the hook payload, if any. Empty/undefined signals an ephemeral session. */\n transcriptPath?: string;\n /** Parsed first JSON line (session_meta) from the transcript, if available. */\n transcriptMeta?: Record<string, unknown>;\n}\n\n/** Structured context a rule can match against at SessionStart time. */\nexport interface SessionStartRuleContext {\n /** Transcript path from the hook payload, if any. Empty/undefined signals an ephemeral session. */\n transcriptPath?: string;\n /** Parsed first JSON line (session_meta) from the transcript, if available. */\n transcriptMeta?: Record<string, unknown>;\n}\n\n/** Outcome of evaluating user_prompt rules. */\nexport type UserPromptDecision =\n | { action: 'pass'; prompt: string }\n | { action: 'rewrite'; prompt: string; reason?: string }\n | { action: 'drop'; reason?: string };\n\n/** Outcome of evaluating session capture rules. No rewrite — there's no prompt text yet. */\nexport type SessionStartDecision =\n | { action: 'pass' }\n | { action: 'drop'; reason?: string };\n\n/**\n * Evaluate all user_prompt rules from every manifest against one context.\n *\n * Rules are checked in declaration order, first-match-wins. A rule only\n * fires when:\n * 1. its `event` is `user_prompt`,\n * 2. its scope permits it (see scope semantics in manifest-schema.ts),\n * 3. every condition in its `when` block matches the context.\n *\n * If no rule matches, the prompt passes through unchanged.\n */\nexport function evaluateUserPromptRules(\n manifests: SymbiontManifest[],\n detectedAgent: string,\n ctx: UserPromptRuleContext,\n): UserPromptDecision {\n for (const manifest of manifests) {\n const rules = manifest.capture?.rules ?? [];\n for (const rule of rules) {\n if (rule.event !== 'user_prompt') continue;\n if (!scopePermits(rule, manifest.name, detectedAgent)) continue;\n if (!whenMatches(rule, ctx)) continue;\n return applyAction(rule, ctx);\n }\n }\n return { action: 'pass', prompt: ctx.prompt };\n}\n\n/**\n * Evaluate all session_start rules from every manifest.\n *\n * Same first-match-wins semantics as user_prompt rules. The only action\n * session_start rules can take is `drop` — text rewriting doesn't apply\n * because there's no prompt text at SessionStart time. Rules that\n * specify prompt-based conditions (prompt_starts_with / prompt_contains)\n * match against an empty prompt here, so they'll never fire on the\n * session_start pass.\n *\n * Callers should skip session registration when the result is `drop`.\n */\nexport function evaluateSessionStartRules(\n manifests: SymbiontManifest[],\n detectedAgent: string,\n ctx: SessionStartRuleContext,\n): SessionStartDecision {\n for (const manifest of manifests) {\n const rules = manifest.capture?.rules ?? [];\n for (const rule of rules) {\n if (rule.event !== 'session_start') continue;\n if (!scopePermits(rule, manifest.name, detectedAgent)) continue;\n if (!whenMatches(rule, { prompt: '', transcriptPath: ctx.transcriptPath, transcriptMeta: ctx.transcriptMeta })) continue;\n if (rule.action === 'drop') {\n return { action: 'drop', reason: rule.reason };\n }\n // rewrite_prompt is meaningless at session_start — skip and let\n // later rules have a chance to match.\n }\n }\n return { action: 'pass' };\n}\n\n/**\n * Evaluate whether a session should be materialized at a lifecycle boundary.\n *\n * SessionStart uses this before registering a session row. Stop processing uses\n * the same decision before transcript-backed capture or stop-driven\n * auto-registration. Keeping both boundaries on the same manifest-driven\n * evaluator makes the rule sustainable for every symbiont, not just the one\n * that first exposed the gap.\n */\nexport function evaluateSessionCaptureRules(\n manifests: SymbiontManifest[],\n detectedAgent: string,\n ctx: SessionStartRuleContext,\n): SessionStartDecision {\n return evaluateSessionStartRules(manifests, detectedAgent, ctx);\n}\n\n/**\n * `any_agent` scope lets a manifest's rule fire even when its own agent isn't\n * the detected one — designed for phantom sub-invocations that arrive with\n * ambiguous attribution. Detection falls back to `DEFAULT_SYMBIONT_NAME` when\n * it fails (see normalize.ts and event-dispatch.ts), so `any_agent` only\n * crosses the agent boundary in that exact case. Events carrying a specific\n * non-default agent (e.g., plugin-delivered `agent: \"opencode\"`) are trusted\n * attribution and must not be touched by another manifest's `any_agent` rules\n * — otherwise codex's phantom-drop rule contaminates opencode, silently\n * dropping every event for any opencode session whose registry was lost.\n */\nfunction scopePermits(rule: CaptureRule, owningAgent: string, detectedAgent: string): boolean {\n if (owningAgent === detectedAgent) return true;\n if (rule.scope !== 'any_agent') return false;\n return detectedAgent === DEFAULT_SYMBIONT_NAME;\n}\n\nfunction whenMatches(rule: CaptureRule, ctx: UserPromptRuleContext): boolean {\n const {\n prompt_starts_with,\n prompt_contains,\n transcript_path_missing,\n transcript_meta_field_exists,\n transcript_meta_field_equals,\n } = rule.when;\n\n // Refuse rules with no conditions — prevents a mistyped YAML file from\n // accidentally creating a blanket \"drop everything\" rule.\n const hasAnyCondition =\n prompt_starts_with !== undefined ||\n prompt_contains !== undefined ||\n transcript_path_missing !== undefined ||\n transcript_meta_field_exists !== undefined ||\n transcript_meta_field_equals !== undefined;\n if (!hasAnyCondition) return false;\n\n if (prompt_starts_with && !ctx.prompt.startsWith(prompt_starts_with)) return false;\n if (prompt_contains && !ctx.prompt.includes(prompt_contains)) return false;\n\n if (transcript_path_missing !== undefined) {\n const missing = !ctx.transcriptPath || ctx.transcriptPath.length === 0;\n if (transcript_path_missing && !missing) return false;\n if (!transcript_path_missing && missing) return false;\n }\n\n if (transcript_meta_field_exists !== undefined) {\n if (!ctx.transcriptMeta) return false;\n if (!getAtPath(ctx.transcriptMeta, transcript_meta_field_exists)) return false;\n }\n\n if (transcript_meta_field_equals !== undefined) {\n if (!ctx.transcriptMeta) return false;\n if (getAtPath(ctx.transcriptMeta, transcript_meta_field_equals.path) !== transcript_meta_field_equals.value) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction applyAction(rule: CaptureRule, ctx: UserPromptRuleContext): UserPromptDecision {\n if (rule.action === 'drop') {\n return { action: 'drop', reason: rule.reason };\n }\n // rewrite_prompt — keep only the substring after the extract_after marker.\n // If the marker isn't in the prompt, fall through to `pass` so we don't\n // accidentally blank out a prompt that turned out not to match after all.\n const marker = rule.extract_after;\n if (!marker) return { action: 'pass', prompt: ctx.prompt };\n const idx = ctx.prompt.indexOf(marker);\n if (idx === -1) return { action: 'pass', prompt: ctx.prompt };\n const after = ctx.prompt.slice(idx + marker.length);\n const next = rule.trim ? after.trim() : after;\n if (!next) return { action: 'pass', prompt: ctx.prompt };\n return { action: 'rewrite', prompt: next, reason: rule.reason };\n}\n","/**\n * Read the first JSON line (session_meta) from an agent's transcript file.\n *\n * Every supported agent writes a JSONL transcript where the first entry\n * is a `session_meta` record containing session identity, source info,\n * model, and other structural signals. This reader extracts that record\n * so capture rules can make decisions based on it — e.g., detecting\n * sub-agent thread spawns that have real transcript files but aren't\n * user-initiated sessions.\n *\n * Returns the parsed `payload` object from the session_meta entry, or\n * null if the file doesn't exist, isn't readable, or doesn't contain\n * valid session_meta JSON.\n */\n\nimport fs from 'node:fs';\n\n/**\n * Read and parse the session_meta payload from a transcript file.\n *\n * @param transcriptPath - Absolute path to the JSONL transcript.\n * @returns The session_meta payload object, or null on any failure.\n */\nexport function readTranscriptMeta(transcriptPath: string): Record<string, unknown> | null {\n try {\n const fd = fs.openSync(transcriptPath, 'r');\n try {\n // Read enough bytes for the first line. Session meta can be large\n // when it embeds the full system prompt (base_instructions) — Codex\n // sessions routinely exceed 16 KB. 128 KB covers all known cases.\n const buf = Buffer.alloc(131072);\n const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);\n if (bytesRead === 0) return null;\n\n const chunk = buf.toString('utf-8', 0, bytesRead);\n const newlineIdx = chunk.indexOf('\\n');\n const firstLine = newlineIdx >= 0 ? chunk.slice(0, newlineIdx) : chunk;\n if (!firstLine) return null;\n\n const entry = JSON.parse(firstLine);\n\n // session_meta entries have { type: \"session_meta\", payload: {...} }\n if (entry?.type === 'session_meta' && typeof entry.payload === 'object') {\n return entry.payload as Record<string, unknown>;\n }\n\n // Some agents may write the meta directly without the wrapper\n if (typeof entry === 'object' && entry !== null) {\n return entry as Record<string, unknown>;\n }\n\n return null;\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
@@ -63,12 +63,11 @@ import {
63
63
  getSpore,
64
64
  insertSpore,
65
65
  listDigestExtracts,
66
- listSporeIdsSince,
67
66
  listSpores,
68
67
  updateSporeStatus,
69
68
  upsertCortexInstructions,
70
69
  upsertDigestExtract
71
- } from "./chunk-N7Z3LUEZ.js";
70
+ } from "./chunk-DBBO6FHE.js";
72
71
  import {
73
72
  countSessions,
74
73
  getActiveSessionIds,
@@ -93,7 +92,7 @@ import {
93
92
  } from "./chunk-MYX5NCRH.js";
94
93
  import {
95
94
  getPluginVersion
96
- } from "./chunk-ENZR5NG7.js";
95
+ } from "./chunk-Z55WGA2J.js";
97
96
  import {
98
97
  findPackageRoot
99
98
  } from "./chunk-LPUQPDC2.js";
@@ -1257,6 +1256,32 @@ function deleteSkillRecordCascade(idOrName) {
1257
1256
  return { id: record.id, name: record.name };
1258
1257
  }
1259
1258
 
1259
+ // src/agent/semantic-shortlist.ts
1260
+ async function shortlistSemanticIds(options) {
1261
+ const {
1262
+ provider,
1263
+ namespace,
1264
+ query: query2,
1265
+ candidateIds,
1266
+ maxResults,
1267
+ overFetch,
1268
+ threshold,
1269
+ filters
1270
+ } = options;
1271
+ if (!provider || maxResults <= 0) return [];
1272
+ const queryVector = await provider.embedQuery(query2);
1273
+ if (!queryVector) return [];
1274
+ const results = provider.searchVectors(queryVector, {
1275
+ namespace,
1276
+ limit: Math.max(maxResults, maxResults * overFetch),
1277
+ threshold,
1278
+ filters
1279
+ });
1280
+ const shortlisted = candidateIds ? results.filter((result) => candidateIds.has(result.id)) : results;
1281
+ shortlisted.sort((a, b) => b.similarity - a.similarity);
1282
+ return shortlisted.slice(0, maxResults).map((result) => result.id);
1283
+ }
1284
+
1260
1285
  // src/agent/tools/skill-validator.ts
1261
1286
  var import_yaml = __toESM(require_dist(), 1);
1262
1287
  var MAX_SKILL_LINES = 800;
@@ -1712,7 +1737,57 @@ function buildSkillSurveyInstruction(agentId) {
1712
1737
  return { instruction: parts.join("\n") };
1713
1738
  }
1714
1739
  var SKILL_EVOLVE_DEFAULT_ASSESS_INTERVAL_HOURS = 24;
1715
- var SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN = 8;
1740
+ var SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN = 3;
1741
+ var SKILL_EVOLVE_RECENT_SPORE_SCAN_LIMIT = 40;
1742
+ var SKILL_EVOLVE_RELEVANT_SPORE_LIMIT = 10;
1743
+ var SKILL_EVOLVE_SEMANTIC_OVERFETCH = 4;
1744
+ var SKILL_EVOLVE_SEMANTIC_THRESHOLD = 0;
1745
+ function normalizeSkillName(name) {
1746
+ return name.replace(/[-_:]+/g, " ");
1747
+ }
1748
+ function buildSporeSearchText(spore) {
1749
+ return [spore.observation_type, spore.content, spore.context, spore.tags, spore.file_path].filter(Boolean).join(" ");
1750
+ }
1751
+ function selectRelevantSporeIdsByLexicalOverlap(skill, recentSpores) {
1752
+ if (recentSpores.length === 0) return [];
1753
+ const skillName = normalizeSkillName(skill.name);
1754
+ const skillQuery = `${skillName} ${skill.description}`;
1755
+ return recentSpores.map((spore) => {
1756
+ const sporeText = buildSporeSearchText(spore);
1757
+ const descriptionScore = descriptionSimilarity(skillQuery, sporeText);
1758
+ const nameScore = descriptionSimilarity(skillName, sporeText);
1759
+ const totalScore = descriptionScore + nameScore * 1.5;
1760
+ return { id: spore.id, totalScore, createdAt: spore.created_at, importance: spore.importance };
1761
+ }).filter((candidate) => candidate.totalScore > 0).sort((a, b) => {
1762
+ if (b.totalScore !== a.totalScore) return b.totalScore - a.totalScore;
1763
+ if (b.importance !== a.importance) return b.importance - a.importance;
1764
+ return b.createdAt - a.createdAt;
1765
+ }).slice(0, SKILL_EVOLVE_RELEVANT_SPORE_LIMIT).map((candidate) => candidate.id);
1766
+ }
1767
+ async function selectRelevantSporeIdsForSkill(skill, sinceEpoch, retrievalProvider) {
1768
+ const recentSpores = listSpores({
1769
+ status: "active",
1770
+ since: sinceEpoch,
1771
+ includeActive: false,
1772
+ limit: SKILL_EVOLVE_RECENT_SPORE_SCAN_LIMIT
1773
+ });
1774
+ if (recentSpores.length === 0) return [];
1775
+ const semanticIds = await shortlistSemanticIds({
1776
+ provider: retrievalProvider,
1777
+ namespace: "spores",
1778
+ query: `${normalizeSkillName(skill.name)} ${skill.description}`,
1779
+ candidateIds: new Set(recentSpores.map((spore) => spore.id)),
1780
+ maxResults: SKILL_EVOLVE_RELEVANT_SPORE_LIMIT,
1781
+ overFetch: SKILL_EVOLVE_SEMANTIC_OVERFETCH,
1782
+ threshold: SKILL_EVOLVE_SEMANTIC_THRESHOLD,
1783
+ filters: {
1784
+ status: "active",
1785
+ created_at_gte: sinceEpoch
1786
+ }
1787
+ });
1788
+ if (semanticIds.length > 0) return semanticIds;
1789
+ return selectRelevantSporeIdsByLexicalOverlap(skill, recentSpores);
1790
+ }
1716
1791
  var MIN_SECTIONS_FOR_STANDALONE = 2;
1717
1792
  function extractHeadings(content) {
1718
1793
  const bodyMatch = content.match(/^---[\s\S]*?---\n([\s\S]*)$/);
@@ -1739,7 +1814,7 @@ function headingOverlap(headingsA, headingsB) {
1739
1814
  const smaller = Math.min(headingsA.length, headingsB.length);
1740
1815
  return { score: smaller > 0 ? shared.length / smaller : 0, shared };
1741
1816
  }
1742
- function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
1817
+ async function buildSkillEvolveInstruction(params, projectRoot, retrievalProvider) {
1743
1818
  const assessIntervalHours = Number(params?.assess_interval_hours ?? SKILL_EVOLVE_DEFAULT_ASSESS_INTERVAL_HOURS);
1744
1819
  const maxSkillsPerRun = Number(params?.max_skills_per_run ?? SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN);
1745
1820
  const now = epochSeconds();
@@ -1756,20 +1831,20 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
1756
1831
  const lastAssessedAt = typeof props.last_assessed_at === "number" ? props.last_assessed_at : 0;
1757
1832
  const knowledgeWatermark = typeof props.knowledge_watermark === "number" ? props.knowledge_watermark : 0;
1758
1833
  if (lastAssessedAt > 0 && now - lastAssessedAt < intervalSeconds) continue;
1759
- const newSporeIds = listSporeIdsSince(knowledgeWatermark, 10);
1834
+ const newSporeIds = await selectRelevantSporeIdsForSkill(skill, knowledgeWatermark, retrievalProvider);
1760
1835
  if (newSporeIds.length === 0) continue;
1761
1836
  needsAssessment.push({
1762
1837
  id: skill.id,
1763
1838
  name: skill.name,
1764
1839
  generation: skill.generation,
1765
1840
  description: skill.description,
1766
- newSporeIds
1841
+ newSporeIds,
1842
+ lastAssessedAt
1767
1843
  });
1768
- if (needsAssessment.length >= maxSkillsPerRun) {
1769
- break;
1770
- }
1771
1844
  }
1772
- if (needsAssessment.length === 0) {
1845
+ needsAssessment.sort((a, b) => a.lastAssessedAt - b.lastAssessedAt);
1846
+ const selectedSkills = needsAssessment.slice(0, maxSkillsPerRun);
1847
+ if (selectedSkills.length === 0) {
1773
1848
  return "No skills need assessment. All active skills are current or were recently assessed. Report skip via vault_report and finish.";
1774
1849
  }
1775
1850
  const structures = [];
@@ -1815,11 +1890,11 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
1815
1890
  }
1816
1891
  }
1817
1892
  const parts = [
1818
- `${needsAssessment.length} skill(s) need assessment.`,
1893
+ `${selectedSkills.length} skill(s) need assessment.`,
1819
1894
  `assess_interval_hours: ${assessIntervalHours}`,
1820
1895
  `max_skills_per_run: ${maxSkillsPerRun}`
1821
1896
  ];
1822
- for (const skill of needsAssessment) {
1897
+ for (const skill of selectedSkills) {
1823
1898
  parts.push("");
1824
1899
  parts.push("---");
1825
1900
  parts.push(`## Skill: ${skill.name} (gen ${skill.generation})`);
@@ -1858,10 +1933,10 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
1858
1933
  }
1859
1934
  }
1860
1935
  }
1861
- if (similarityProvider) {
1936
+ if (retrievalProvider) {
1862
1937
  const idToName = new Map(allSkills.map((s) => [s.id, s.name]));
1863
1938
  try {
1864
- const semanticPairs = similarityProvider.pairwiseSimilarity("skill_records", 0.65);
1939
+ const semanticPairs = retrievalProvider.pairwiseSimilarity("skill_records", 0.65);
1865
1940
  if (semanticPairs.length > 0) {
1866
1941
  parts.push("");
1867
1942
  parts.push("## Semantic Similarity (embedding cosine distance)");
@@ -1878,14 +1953,14 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
1878
1953
  }
1879
1954
  return parts.join("\n");
1880
1955
  }
1881
- async function buildTaskInstruction(taskName, taskParams, agentId, projectRoot, similarityProvider, config, getTeamClient) {
1956
+ async function buildTaskInstruction(taskName, taskParams, agentId, projectRoot, retrievalProvider, config, getTeamClient) {
1882
1957
  switch (taskName) {
1883
1958
  case SKILL_GENERATE_TASK:
1884
1959
  return buildSkillGenerateInstruction();
1885
1960
  case SKILL_SURVEY_TASK:
1886
1961
  return agentId ? buildSkillSurveyInstruction(agentId) : void 0;
1887
1962
  case SKILL_EVOLVE_TASK: {
1888
- const instruction = buildSkillEvolveInstruction(taskParams, projectRoot, similarityProvider);
1963
+ const instruction = await buildSkillEvolveInstruction(taskParams, projectRoot, retrievalProvider);
1889
1964
  return instruction ? { instruction } : void 0;
1890
1965
  }
1891
1966
  case CORTEX_INSTRUCTIONS_TASK: {
@@ -3068,6 +3143,27 @@ function countWriteIntentsByToolForEvaluation(evaluationId) {
3068
3143
  // src/agent/tools/read-tools.ts
3069
3144
  import { tool } from "@anthropic-ai/claude-agent-sdk";
3070
3145
 
3146
+ // src/semantic-search-filters.ts
3147
+ function hasSemanticSearchFilters(filters) {
3148
+ if (!filters) return false;
3149
+ return Object.values(filters).some((value) => value !== void 0);
3150
+ }
3151
+ function matchesSemanticSearchFilters(metadata, filters) {
3152
+ if (!filters) return true;
3153
+ if (filters.status !== void 0 && metadata?.status !== filters.status) return false;
3154
+ if (filters.session_id !== void 0 && metadata?.session_id !== filters.session_id) return false;
3155
+ if (filters.observation_type !== void 0 && metadata?.observation_type !== filters.observation_type) return false;
3156
+ if (filters.project_root !== void 0 && metadata?.project_root !== filters.project_root) return false;
3157
+ if (filters.name !== void 0 && metadata?.name !== filters.name) return false;
3158
+ if (filters.source_path !== void 0 && metadata?.source_path !== filters.source_path) return false;
3159
+ const createdAt = typeof metadata?.created_at === "number" ? metadata.created_at : void 0;
3160
+ if (filters.created_at_gte !== void 0 && (createdAt === void 0 || createdAt < filters.created_at_gte)) return false;
3161
+ if (filters.created_at_lte !== void 0 && (createdAt === void 0 || createdAt > filters.created_at_lte)) return false;
3162
+ if (filters.created_at_gt !== void 0 && (createdAt === void 0 || createdAt <= filters.created_at_gt)) return false;
3163
+ if (filters.created_at_lt !== void 0 && (createdAt === void 0 || createdAt >= filters.created_at_lt)) return false;
3164
+ return true;
3165
+ }
3166
+
3071
3167
  // src/db/queries/graph-edges.ts
3072
3168
  import crypto3 from "crypto";
3073
3169
  var DEFAULT_BFS_DEPTH = 2;
@@ -3409,7 +3505,12 @@ function createReadTools(deps) {
3409
3505
  query: external_exports.string().describe("Search query text"),
3410
3506
  namespace: external_exports.string().optional().describe("Restrict to a content type: spores, sessions, plans, artifacts, skill_records. Omit to search all."),
3411
3507
  limit: external_exports.number().optional().describe("Maximum results to return"),
3412
- include_active: external_exports.boolean().optional().describe("Include results from sessions still in active status (default: false)")
3508
+ include_active: external_exports.boolean().optional().describe("Include results from sessions still in active status (default: false)"),
3509
+ status: external_exports.string().optional().describe("Optional metadata filter, e.g. active/superseded for spores and skill_records."),
3510
+ session_id: external_exports.string().optional().describe("Optional metadata filter for a linked session id."),
3511
+ observation_type: external_exports.string().optional().describe("Optional metadata filter for spore observation type."),
3512
+ since: external_exports.number().optional().describe("Optional created_at lower bound (epoch seconds)."),
3513
+ until: external_exports.number().optional().describe("Optional created_at upper bound (epoch seconds).")
3413
3514
  },
3414
3515
  async (args) => {
3415
3516
  if (!embeddingManager) {
@@ -3423,21 +3524,39 @@ function createReadTools(deps) {
3423
3524
  const searchLimit = args.limit ?? DEFAULT_SEARCH_LIMIT;
3424
3525
  const excludeActive = args.include_active !== true;
3425
3526
  const activeIds = excludeActive ? getActiveSessionIds() : /* @__PURE__ */ new Set();
3527
+ const metadataFilters = {
3528
+ ...args.status !== void 0 ? { status: args.status } : {},
3529
+ ...args.session_id !== void 0 ? { session_id: args.session_id } : {},
3530
+ ...args.observation_type !== void 0 ? { observation_type: args.observation_type } : {},
3531
+ ...args.since !== void 0 ? { created_at_gte: args.since } : {},
3532
+ ...args.until !== void 0 ? { created_at_lte: args.until } : {}
3533
+ };
3534
+ const vectorFilters = hasSemanticSearchFilters(metadataFilters) ? metadataFilters : void 0;
3426
3535
  const [rawLocalResults, teamResults] = await Promise.all([
3427
3536
  Promise.resolve(
3428
3537
  embeddingManager.searchVectors(queryVector, {
3429
3538
  namespace: args.namespace,
3430
3539
  limit: searchLimit,
3431
- threshold: SEARCH_SIMILARITY_THRESHOLD
3540
+ threshold: SEARCH_SIMILARITY_THRESHOLD,
3541
+ filters: vectorFilters
3432
3542
  }).map((r) => ({ ...r, source: "local" }))
3433
3543
  ),
3434
- teamClient ? teamClient.search(args.query, { limit: searchLimit }).then((res) => res.results.map((r) => ({ ...r, source: `${TEAM_SOURCE_PREFIX}${r.machine_id}` }))).catch(() => []) : Promise.resolve([])
3544
+ teamClient ? teamClient.search(args.query, {
3545
+ limit: searchLimit,
3546
+ tables: args.namespace ? [args.namespace] : void 0,
3547
+ status: args.status,
3548
+ observation_type: args.observation_type,
3549
+ since: args.since,
3550
+ until: args.until,
3551
+ session_id: args.session_id
3552
+ }).then((res) => res.results.map((r) => ({ ...r, source: `${TEAM_SOURCE_PREFIX}${r.machine_id}` }))).catch(() => []) : Promise.resolve([])
3435
3553
  ]);
3436
3554
  const localResults = activeIds.size > 0 ? rawLocalResults.filter((r) => {
3437
3555
  const sid = r.metadata?.session_id;
3438
3556
  return typeof sid !== "string" || !activeIds.has(sid);
3439
3557
  }) : rawLocalResults;
3440
- const hydratedLocalResults = hydrateSearchResults(localResults).map((r) => ({
3558
+ const filteredLocalResults = vectorFilters ? localResults.filter((r) => matchesSemanticSearchFilters(r.metadata, metadataFilters)) : localResults;
3559
+ const hydratedLocalResults = hydrateSearchResults(filteredLocalResults).map((r) => ({
3441
3560
  ...r,
3442
3561
  source: "local"
3443
3562
  }));
@@ -3448,6 +3567,12 @@ function createReadTools(deps) {
3448
3567
  return typeof sid !== "string" || !activeIds.has(sid);
3449
3568
  });
3450
3569
  }
3570
+ if (vectorFilters) {
3571
+ dedupedTeam = dedupedTeam.filter((r) => matchesSemanticSearchFilters(
3572
+ r.metadata,
3573
+ metadataFilters
3574
+ ));
3575
+ }
3451
3576
  const merged = [
3452
3577
  ...hydratedLocalResults,
3453
3578
  ...dedupedTeam
@@ -3676,7 +3801,8 @@ function createWriteTools(deps) {
3676
3801
  embeddingManager?.onContentWritten("spores", spore.id, args.content, {
3677
3802
  status: "active",
3678
3803
  observation_type: args.observation_type,
3679
- session_id: args.session_id
3804
+ session_id: args.session_id,
3805
+ created_at: now
3680
3806
  }).catch(() => {
3681
3807
  });
3682
3808
  return textResult(spore);
@@ -13874,7 +14000,8 @@ async function runAgent(vaultDir, options) {
13874
14000
  agentId,
13875
14001
  runId,
13876
14002
  runContext: options?.runContext,
13877
- instruction: options?.instruction
14003
+ instruction: options?.instruction,
14004
+ dryRun: options?.dryRun
13878
14005
  });
13879
14006
  const completedAt = epochSeconds();
13880
14007
  updateRunStatus(runId, STATUS_COMPLETED, {
@@ -14001,6 +14128,7 @@ async function cleanupOnTaskFailure(args) {
14001
14128
  }
14002
14129
  async function finalizeOnTaskSuccess(args) {
14003
14130
  if (args.taskName !== CORTEX_INSTRUCTIONS_TASK) return;
14131
+ if (args.dryRun) return;
14004
14132
  const reports = listReports(args.runId);
14005
14133
  let report;
14006
14134
  for (let i = reports.length - 1; i >= 0; i -= 1) {
@@ -14091,6 +14219,8 @@ export {
14091
14219
  countWriteIntents,
14092
14220
  countWriteIntentsByTool,
14093
14221
  countWriteIntentsByToolForEvaluation,
14222
+ hasSemanticSearchFilters,
14223
+ matchesSemanticSearchFilters,
14094
14224
  getGraphForNode,
14095
14225
  createBatchLineage,
14096
14226
  insertResolutionEvent,
@@ -14100,4 +14230,4 @@ export {
14100
14230
  cleanupOnTaskFailure,
14101
14231
  finalizeOnTaskSuccess
14102
14232
  };
14103
- //# sourceMappingURL=chunk-X2IRGXGF.js.map
14233
+ //# sourceMappingURL=chunk-HCT7RMM2.js.map