@teamix-evo/mcp 0.3.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/server.ts","../src/groups/registry.ts","../src/manifest-loader.ts","../src/groups/adr.ts","../src/adr-loader.ts","../src/groups/skills.ts","../src/skills-loader.ts","../src/groups/design.ts","../src/design-loader.ts"],"sourcesContent":["/**\n * Bin entry — speaks stdio MCP.\n *\n * Invoked by AI editors (Cursor / Claude Code / Cline / Aider) via:\n * npx @teamix-evo/mcp\n * or directly:\n * node ./packages/mcp/dist/cli.js\n *\n * See README.md for the per-IDE config snippets.\n */\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createServer } from './server.js';\n\nasync function main(): Promise<void> {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // Stdio transport keeps the process alive while client is connected.\n}\n\nmain().catch((err) => {\n // Write to stderr so MCP client logs surface the failure.\n // eslint-disable-next-line no-console -- stderr logging at process boundary\n console.error('[teamix-evo-mcp] fatal:', err);\n process.exit(1);\n});\n","/**\n * Main MCP server — composes multiple tool groups into one stdio process.\n *\n * Architecture per [ADR 0011](../../../docs/adr/0011-mcp-single-package-multi-group.md):\n * single package / single bin / multiple tool groups. Groups added in later\n * milestones (design v0.6, adr v0.7, scenario v0.8) plug in here without\n * touching the transport or ListTools/CallTool handler logic.\n *\n * Tool dispatch:\n * - `tools/list` returns the union of all groups' tools.\n * - `tools/call` walks the group list in registration order; the first group\n * whose `handle` returns a non-`undefined` result wins. Tool-name uniqueness\n * across groups is the responsibility of group authors (see ADR 0011 §5\n * for the `<group>_<verb>_<noun>` naming convention; `registry` is the\n * historical exception).\n */\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { createRegistryGroup, type RegistryGroupOptions } from './groups/registry.js';\nimport { createAdrGroup, type AdrGroupOptions } from './groups/adr.js';\nimport { createSkillsGroup, type SkillsGroupOptions } from './groups/skills.js';\nimport { createDesignGroup, type DesignGroupOptions } from './groups/design.js';\nimport type { ToolGroup } from './types.js';\n\nexport interface ServerOptions {\n /** Options forwarded to the registry group. Pass `loaded` in tests. */\n registry?: RegistryGroupOptions;\n /** Options forwarded to the adr group. Pass `loaded` in tests. */\n adr?: AdrGroupOptions;\n /** Options forwarded to the skills group. Pass `loaded` in tests. */\n skills?: SkillsGroupOptions;\n /** Options forwarded to the design group. Pass `loaded` in tests. */\n design?: DesignGroupOptions;\n}\n\nexport function createServer(opts: ServerOptions = {}): Server {\n const groups: ToolGroup[] = [\n createRegistryGroup(opts.registry),\n createAdrGroup(opts.adr),\n createSkillsGroup(opts.skills),\n createDesignGroup(opts.design),\n // Future: createScenarioGroup(opts.scenario), // ADR 0011, v0.8\n ];\n\n // Sanity check: tool names must be unique across groups.\n const seen = new Set<string>();\n for (const group of groups) {\n for (const tool of group.tools) {\n if (seen.has(tool.name)) {\n throw new Error(\n `Duplicate MCP tool name across groups: ${tool.name}. ` +\n `Each group must use unique tool names — see ADR 0011 §5.`,\n );\n }\n seen.add(tool.name);\n }\n }\n\n const allTools = groups.flatMap((g) => g.tools);\n\n const server = new Server(\n {\n name: '@teamix-evo/mcp',\n version: '0.2.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: allTools,\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (req) => {\n const { name, arguments: args } = req.params;\n for (const group of groups) {\n const result = await group.handle(name, args);\n if (result !== undefined) return result;\n }\n return {\n content: [\n {\n type: 'text',\n text: `Unknown tool: ${name}. Use tools/list to discover available tools.`,\n },\n ],\n isError: true,\n };\n });\n\n return server;\n}\n","/**\n * Registry tool group — exposes the @teamix-evo/ui component registry to AI\n * editors.\n *\n * Originally `src/server.ts` of `@teamix-evo/registry-mcp`. Moved here as part\n * of [ADR 0011](../../../../docs/adr/0011-mcp-single-package-multi-group.md)\n * single-package / multi-group restructure.\n *\n * Tool naming is the **historical exception**: `list_components` /\n * `get_component_meta` / `find_components` keep their unprefixed names because\n * they're already in production AI client memory (see ADR 0011 §5). All\n * future groups (`design_*`, `adr_*`, `scenario_*`) MUST use the\n * `<group>_<verb>_<noun>` prefix convention.\n */\nimport { z } from 'zod';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n loadManifest,\n loadMeta,\n type LoadedManifest,\n} from '../manifest-loader.js';\nimport type { ToolGroup, ToolResult } from '../types.js';\nimport type { UiEntry } from '@teamix-evo/registry';\n\nconst ListComponentsInput = z.object({\n status: z.enum(['stable', 'experimental', 'deprecated']).optional(),\n});\n\nconst GetComponentMetaInput = z.object({\n id: z.string().min(1),\n});\n\nconst FindComponentsInput = z.object({\n query: z.string().min(1),\n limit: z.number().int().positive().max(100).optional(),\n});\n\nconst TOOLS: Tool[] = [\n {\n name: 'list_components',\n description:\n 'List all UI components in the @teamix-evo/ui registry. Optionally filter by status (stable / experimental / deprecated). Returns id, name, description, status, registryDependencies — small enough for the model to scan whole.',\n inputSchema: {\n type: 'object',\n properties: {\n status: {\n type: 'string',\n enum: ['stable', 'experimental', 'deprecated'],\n description: 'Filter by maturity status.',\n },\n },\n },\n },\n {\n name: 'get_component_meta',\n description:\n 'Fetch the full registry entry + parsed meta.md for a single component by id. Returns props schema reference, registryDependencies, npm dependencies, AI generation rules, and the component description.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Component id (e.g. \"button\", \"data-table\").',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'find_components',\n description:\n 'Substring match over component id / name / description. Use when you need a component but don\\'t know its exact id (e.g. \"find a component supporting async search and pagination\"). Returns up to `limit` matches (default 10). Note: substring match is a v0.1 implementation; semantic search is planned for v0.7 (see ADR 0009).',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Free-text query.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: 100,\n description: 'Max matches to return (default 10).',\n },\n },\n required: ['query'],\n },\n },\n];\n\nconst TOOL_NAMES = new Set(TOOLS.map((t) => t.name));\n\nfunction pickListEntry(entry: UiEntry) {\n return {\n id: entry.id,\n name: entry.name,\n type: entry.type,\n description: entry.description,\n status: entry.status,\n deprecatedReason: entry.deprecatedReason,\n replacedBy: entry.replacedBy,\n registryDependencies: entry.registryDependencies ?? [],\n };\n}\n\nexport interface RegistryGroupOptions {\n /** Pre-loaded manifest (used in tests to avoid filesystem). */\n loaded?: LoadedManifest;\n}\n\nexport function createRegistryGroup(opts: RegistryGroupOptions = {}): ToolGroup {\n // Lazy-load the manifest so failures yield a tool-call error rather than\n // blocking server startup (which would prevent the MCP client from even\n // discovering the tools and seeing a usable error message).\n let cache: LoadedManifest | null = opts.loaded ?? null;\n function getManifest(): LoadedManifest {\n if (!cache) cache = loadManifest();\n return cache;\n }\n\n return {\n name: 'registry',\n tools: TOOLS,\n async handle(name, args): Promise<ToolResult | undefined> {\n if (!TOOL_NAMES.has(name)) return undefined;\n\n if (name === 'list_components') {\n const input = ListComponentsInput.parse(args ?? {});\n const { manifest } = getManifest();\n const entries = manifest.entries\n .filter((e) => e.type === 'component')\n .filter((e) => (input.status ? e.status === input.status : true))\n .map(pickListEntry);\n return {\n content: [{ type: 'text', text: JSON.stringify(entries, null, 2) }],\n };\n }\n\n if (name === 'get_component_meta') {\n const input = GetComponentMetaInput.parse(args);\n const { manifest, rootDir } = getManifest();\n const entry = manifest.entries.find((e) => e.id === input.id);\n if (!entry) {\n return {\n content: [\n {\n type: 'text',\n text: `Component not found: ${input.id}. Use list_components to discover ids.`,\n },\n ],\n isError: true,\n };\n }\n const meta = loadMeta(entry, rootDir);\n const payload = {\n entry,\n meta: meta ?? null,\n };\n return {\n content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],\n };\n }\n\n if (name === 'find_components') {\n const input = FindComponentsInput.parse(args);\n const limit = input.limit ?? 10;\n const q = input.query.toLowerCase();\n const { manifest } = getManifest();\n const matches = manifest.entries\n .filter((e) => e.type === 'component')\n .filter((e) => {\n return (\n e.id.toLowerCase().includes(q) ||\n e.name.toLowerCase().includes(q) ||\n e.description.toLowerCase().includes(q)\n );\n })\n .slice(0, limit)\n .map(pickListEntry);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n query: input.query,\n limit,\n count: matches.length,\n results: matches,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // Unreachable — TOOL_NAMES guard above ensures we only enter known names.\n return undefined;\n },\n };\n}\n","import { readFileSync, existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { UiPackageManifestSchema } from '@teamix-evo/registry';\nimport type { UiEntry, UiPackageManifest } from '@teamix-evo/registry';\n\n/**\n * Resolves the `@teamix-evo/ui/manifest.json` path using a layered strategy:\n *\n * 1. `TEAMIX_EVO_UI_MANIFEST` env var (absolute path)\n * 2. `<cwd>/node_modules/@teamix-evo/ui/manifest.json`\n * 3. Walking up parent directories until a matching `node_modules/...` is found\n * 4. Throws with a clear error message\n */\nexport function resolveManifestPath(startDir: string = process.cwd()): string {\n const envPath = process.env.TEAMIX_EVO_UI_MANIFEST;\n if (envPath && existsSync(envPath)) {\n return envPath;\n }\n\n let dir = resolve(startDir);\n // Limit walk to prevent runaway in pathological filesystems.\n for (let i = 0; i < 16; i++) {\n const candidate = join(\n dir,\n 'node_modules',\n '@teamix-evo',\n 'ui',\n 'manifest.json',\n );\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break; // reached filesystem root\n dir = parent;\n }\n\n throw new Error(\n [\n 'Could not locate @teamix-evo/ui/manifest.json.',\n `Tried env TEAMIX_EVO_UI_MANIFEST + walking up from ${startDir}.`,\n 'Either install @teamix-evo/ui in the consumer project, or set TEAMIX_EVO_UI_MANIFEST to an absolute path.',\n ].join(' '),\n );\n}\n\nexport interface LoadedManifest {\n manifest: UiPackageManifest;\n /** Directory of the manifest.json itself; used to resolve `meta.md` paths. */\n rootDir: string;\n}\n\n/**\n * Loads and Zod-validates the UI package manifest.\n * Throws on invalid manifest with the underlying Zod error attached.\n */\nexport function loadManifest(path?: string): LoadedManifest {\n const manifestPath = path ?? resolveManifestPath();\n const raw = JSON.parse(readFileSync(manifestPath, 'utf-8')) as unknown;\n const result = UiPackageManifestSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(\n `Invalid manifest at ${manifestPath}: ${result.error.message}`,\n );\n }\n return {\n manifest: result.data,\n rootDir: dirname(manifestPath),\n };\n}\n\n/**\n * Frontmatter + body extracted from a `<id>.meta.md` file.\n * Frontmatter is parsed as a flat key/value map (no YAML library dep —\n * meta.md frontmatters are intentionally simple).\n */\nexport interface ParsedMeta {\n frontmatter: Record<string, string>;\n body: string;\n}\n\n/**\n * Reads and minimally parses a `<id>.meta.md` file. Returns `null` if the\n * meta file is missing or the entry didn't declare one.\n *\n * Frontmatter parser is minimal (single-line `key: value` pairs only). It\n * does NOT support nested or array YAML — sufficient for the meta.md format\n * documented in packages/ui/AGENTS.md §三.E.\n */\nexport function loadMeta(\n entry: UiEntry,\n rootDir: string,\n): ParsedMeta | null {\n if (!entry.meta) return null;\n const path = join(rootDir, entry.meta);\n if (!existsSync(path)) return null;\n const text = readFileSync(path, 'utf-8');\n return parseFrontmatter(text);\n}\n\nfunction parseFrontmatter(text: string): ParsedMeta {\n const FM_RE = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?/;\n const match = text.match(FM_RE);\n if (!match) {\n return { frontmatter: {}, body: text };\n }\n const fm: Record<string, string> = {};\n // Capture group [1] is guaranteed when match succeeds.\n for (const line of match[1]!.split('\\n')) {\n const m = line.match(/^([A-Za-z_][\\w-]*)\\s*:\\s*(.+?)\\s*$/);\n if (m) fm[m[1]!] = m[2]!.replace(/^['\"]|['\"]$/g, '');\n }\n return {\n frontmatter: fm,\n body: text.slice(match[0].length),\n };\n}\n","/**\n * ADR tool group — exposes Architecture Decision Records to AI editors.\n *\n * Per [ADR 0011 §5](../../../../docs/adr/0011-mcp-single-package-multi-group.md),\n * new groups use the `<group>_<verb>` prefix convention:\n *\n * - `adr_list` — index of all ADRs (id, title, status, date)\n * - `adr_get` — full markdown body for one ADR\n * - `adr_find` — substring search across title + body\n *\n * Use this group to let AI agents:\n *\n * - Cite ADRs in PR reviews (\"this change violates ADR 0008 §2.B\")\n * - Resolve \"why was this done?\" questions before recommending refactors\n * - Discover related ADRs when proposing a new decision\n */\nimport { z } from 'zod';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n loadAdrIndex,\n loadAdrContent,\n findAdr,\n type LoadedAdrs,\n} from '../adr-loader.js';\nimport type { ToolGroup, ToolResult } from '../types.js';\n\nconst ListInput = z.object({\n /** Match `Status` line by substring (case-insensitive). */\n status: z.string().min(1).optional(),\n});\n\nconst GetInput = z.object({\n /** ADR id (\"0011\") or full slug (\"0011-mcp-single-package-multi-group\"). */\n id: z.string().min(1),\n});\n\nconst FindInput = z.object({\n query: z.string().min(1),\n limit: z.number().int().positive().max(50).optional(),\n /**\n * When true, returns a snippet (~200 chars) around each match so the model\n * can decide whether to fetch the full ADR. Defaults to true.\n */\n withSnippets: z.boolean().optional(),\n});\n\nconst TOOLS: Tool[] = [\n {\n name: 'adr_list',\n description:\n 'List all Architecture Decision Records (ADRs) in docs/adr/. Returns id (4-digit), slug, title, status, date, region for each. Use this as the first call to discover which decisions exist before drilling into one with adr_get. Filter by status substring (e.g. \"Accepted\" / \"Proposed\" / \"Superseded\") to narrow down.',\n inputSchema: {\n type: 'object',\n properties: {\n status: {\n type: 'string',\n description:\n 'Optional case-insensitive substring filter against the ADR Status line. Examples: \"Accepted\", \"Proposed\", \"Superseded\".',\n },\n },\n },\n },\n {\n name: 'adr_get',\n description:\n 'Fetch the full markdown body of one ADR by id (\"0011\") or slug (\"0011-mcp-single-package-multi-group\"). Returns the entry metadata + raw markdown so the model can cite specific sections (Context / Decision / Consequences / Source). Use after adr_list / adr_find to read a specific decision in full.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description:\n 'ADR id (\"0011\") or full slug (\"0011-mcp-single-package-multi-group\").',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'adr_find',\n description:\n 'Substring search across ADR titles and bodies (case-insensitive). Use when you remember a phrase (\"source-mirror\", \"lint-core\", \"no baseline\") but not which ADR it lives in. Returns up to `limit` matches (default 10) with optional snippets (~200 chars around each match). Combine with adr_get for the full text.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Free-text query.' },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: 50,\n description: 'Max matches to return (default 10).',\n },\n withSnippets: {\n type: 'boolean',\n description: 'Include ~200-char snippet around each match (default true).',\n },\n },\n required: ['query'],\n },\n },\n];\n\nconst TOOL_NAMES = new Set(TOOLS.map((t) => t.name));\n\nfunction pickEntry(e: {\n id: string;\n slug: string;\n title: string;\n status: string;\n date: string;\n region: string;\n}) {\n return {\n id: e.id,\n slug: e.slug,\n title: e.title,\n status: e.status,\n date: e.date,\n region: e.region,\n };\n}\n\nconst SNIPPET_RADIUS = 100;\n\nfunction snippet(text: string, index: number): string {\n const start = Math.max(0, index - SNIPPET_RADIUS);\n const end = Math.min(text.length, index + SNIPPET_RADIUS);\n const prefix = start > 0 ? '…' : '';\n const suffix = end < text.length ? '…' : '';\n return prefix + text.slice(start, end).replace(/\\s+/g, ' ').trim() + suffix;\n}\n\nexport interface AdrGroupOptions {\n /** Pre-loaded index (used in tests to avoid filesystem). */\n loaded?: LoadedAdrs;\n}\n\nexport function createAdrGroup(opts: AdrGroupOptions = {}): ToolGroup {\n let cache: LoadedAdrs | null = opts.loaded ?? null;\n function getIndex(): LoadedAdrs {\n if (!cache) cache = loadAdrIndex();\n return cache;\n }\n\n return {\n name: 'adr',\n tools: TOOLS,\n async handle(name, args): Promise<ToolResult | undefined> {\n if (!TOOL_NAMES.has(name)) return undefined;\n\n if (name === 'adr_list') {\n const input = ListInput.parse(args ?? {});\n const idx = getIndex();\n const needle = input.status?.toLowerCase();\n const entries = idx.entries\n .filter((e) =>\n needle ? e.status.toLowerCase().includes(needle) : true,\n )\n .map(pickEntry);\n return {\n content: [{ type: 'text', text: JSON.stringify(entries, null, 2) }],\n };\n }\n\n if (name === 'adr_get') {\n const input = GetInput.parse(args);\n const idx = getIndex();\n const entry = findAdr(idx, input.id);\n if (!entry) {\n return {\n content: [\n {\n type: 'text',\n text: `ADR not found: ${input.id}. Use adr_list to discover ids.`,\n },\n ],\n isError: true,\n };\n }\n const text = loadAdrContent(entry);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n { entry: pickEntry(entry), content: text },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n if (name === 'adr_find') {\n const input = FindInput.parse(args);\n const limit = input.limit ?? 10;\n const withSnippets = input.withSnippets ?? true;\n const needle = input.query.toLowerCase();\n const idx = getIndex();\n\n const matches: Array<{\n entry: ReturnType<typeof pickEntry>;\n snippets?: string[];\n hitCount: number;\n }> = [];\n for (const entry of idx.entries) {\n const body = loadAdrContent(entry).toLowerCase();\n const titleHit = entry.title.toLowerCase().includes(needle);\n if (!titleHit && !body.includes(needle)) continue;\n\n const snippets: string[] = [];\n if (withSnippets) {\n const rawBody = loadAdrContent(entry);\n let from = 0;\n // Up to 3 snippets per ADR to keep response compact.\n for (let i = 0; i < 3; i++) {\n const at = rawBody.toLowerCase().indexOf(needle, from);\n if (at < 0) break;\n snippets.push(snippet(rawBody, at));\n from = at + needle.length;\n }\n }\n // Count total hits in body for ranking.\n let hits = titleHit ? 1 : 0;\n let from = 0;\n for (;;) {\n const at = body.indexOf(needle, from);\n if (at < 0) break;\n hits++;\n from = at + needle.length;\n }\n matches.push({\n entry: pickEntry(entry),\n ...(withSnippets ? { snippets } : {}),\n hitCount: hits,\n });\n }\n matches.sort((a, b) => b.hitCount - a.hitCount);\n const sliced = matches.slice(0, limit);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n query: input.query,\n limit,\n count: sliced.length,\n totalMatchingAdrs: matches.length,\n results: sliced,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n return undefined;\n },\n };\n}\n","/**\n * Loader for ADR (Architecture Decision Record) markdown files.\n *\n * ADRs live in `docs/adr/<NNNN>-<slug>.md` per [ADR 0007](../../../docs/adr/0007-governance-docs-at-root.md).\n * Each file has the shape:\n *\n * ```md\n * # 0011. <title>\n *\n * - **Status**: Proposed | Accepted | Superseded by NNNN | Deprecated\n * - **Date**: YYYY-MM-DD\n * - **Region**: 0100–0999 协议与工具\n * - **Related ADR**: [0007 ...](...)\n *\n * ## Context\n * ...\n * ```\n *\n * This loader parses just enough metadata to power the `adr_list` /\n * `adr_get` / `adr_find` MCP tools (see [`groups/adr.ts`](./groups/adr.ts)).\n * `README.md` and `_template.md` are skipped — they are not ADRs.\n */\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\nexport interface AdrEntry {\n /** Numeric id, e.g. \"0011\". Derived from the filename prefix. */\n id: string;\n /** Filename without `.md`, e.g. \"0011-mcp-single-package-multi-group\". */\n slug: string;\n /** Title after \"NNNN. \" in the H1 line. */\n title: string;\n /** Raw status string from the `- **Status**:` line. Empty if missing. */\n status: string;\n /** Date from the `- **Date**:` line (YYYY-MM-DD). Empty if missing. */\n date: string;\n /** Optional region label (`0100–0999 协议与工具`). Empty if missing. */\n region: string;\n /** Absolute path to the source file (for `adr_get`). */\n filePath: string;\n}\n\nexport interface LoadedAdrs {\n /** Directory containing the ADR `.md` files. */\n rootDir: string;\n entries: AdrEntry[];\n}\n\n/**\n * Resolves the ADR directory using a layered strategy:\n *\n * 1. `TEAMIX_EVO_ADR_ROOT` env var (absolute path)\n * 2. Walk up from cwd looking for `docs/adr/` (monorepo layout)\n * 3. Walk up from cwd looking for `.teamix-evo/adr/` (consumer layout — future)\n * 4. Throws with a clear error\n */\nexport function resolveAdrRoot(startDir: string = process.cwd()): string {\n const envPath = process.env.TEAMIX_EVO_ADR_ROOT;\n if (envPath && existsSync(envPath)) {\n return envPath;\n }\n\n let dir = resolve(startDir);\n for (let i = 0; i < 16; i++) {\n const candidates = [\n join(dir, 'docs', 'adr'),\n join(dir, '.teamix-evo', 'adr'),\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n throw new Error(\n [\n 'Could not locate ADR directory.',\n `Tried env TEAMIX_EVO_ADR_ROOT + walking up from ${startDir} for docs/adr/ or .teamix-evo/adr/.`,\n 'Either run from a teamix-evo monorepo, or set TEAMIX_EVO_ADR_ROOT to an absolute path.',\n ].join(' '),\n );\n}\n\nconst SKIP_FILES = new Set(['README.md', '_template.md']);\nconst ID_RE = /^(\\d{4})-/;\nconst H1_RE = /^#\\s+\\d{4}\\.\\s+(.+?)\\s*$/m;\nconst STATUS_RE = /^-\\s+\\*\\*Status\\*\\*:\\s*(.+?)\\s*$/m;\nconst DATE_RE = /^-\\s+\\*\\*Date\\*\\*:\\s*(.+?)\\s*$/m;\nconst REGION_RE = /^-\\s+\\*\\*Region\\*\\*:\\s*(.+?)\\s*$/m;\n\nfunction parseAdr(slug: string, filePath: string): AdrEntry | null {\n const idMatch = slug.match(ID_RE);\n if (!idMatch) return null;\n const id = idMatch[1]!;\n\n const text = readFileSync(filePath, 'utf-8');\n const titleMatch = text.match(H1_RE);\n const statusMatch = text.match(STATUS_RE);\n const dateMatch = text.match(DATE_RE);\n const regionMatch = text.match(REGION_RE);\n\n return {\n id,\n slug,\n title: titleMatch?.[1] ?? slug,\n status: statusMatch?.[1] ?? '',\n date: dateMatch?.[1] ?? '',\n region: regionMatch?.[1] ?? '',\n filePath,\n };\n}\n\nexport function loadAdrIndex(rootDir?: string): LoadedAdrs {\n const root = rootDir ?? resolveAdrRoot();\n const files = readdirSync(root).filter(\n (f) => f.endsWith('.md') && !SKIP_FILES.has(f),\n );\n const entries: AdrEntry[] = [];\n for (const f of files) {\n const slug = f.replace(/\\.md$/, '');\n const entry = parseAdr(slug, join(root, f));\n if (entry) entries.push(entry);\n }\n entries.sort((a, b) => a.id.localeCompare(b.id));\n return { rootDir: root, entries };\n}\n\n/**\n * Look up one ADR by id (\"0011\") or full slug (\"0011-mcp-single-package-multi-group\").\n * Returns `null` if no match.\n */\nexport function findAdr(\n loaded: LoadedAdrs,\n idOrSlug: string,\n): AdrEntry | null {\n const needle = idOrSlug.trim();\n if (/^\\d{4}$/.test(needle)) {\n return loaded.entries.find((e) => e.id === needle) ?? null;\n }\n return (\n loaded.entries.find((e) => e.slug === needle) ??\n loaded.entries.find((e) => e.id === needle) ??\n null\n );\n}\n\nexport function loadAdrContent(entry: AdrEntry): string {\n return readFileSync(entry.filePath, 'utf-8');\n}\n","/**\n * Skills tool group — exposes `@teamix-evo/skills` SKILL.md content to AI editors.\n *\n * Per [ADR 0011 §5](../../../../docs/adr/0011-mcp-single-package-multi-group.md):\n *\n * - `skills_list` — index of all shipped skills (id, name, description, version)\n * - `skills_get` — full SKILL.md content + attachment names for one skill\n * - `skills_find` — substring search across `description` (the AI trigger) + body\n *\n * `description` in SKILL.md frontmatter is the AI trigger contract per\n * [ADR 0013](../../../../docs/adr/0013-skills-source-mirror.md). Searching it\n * is the primary use of `skills_find`.\n */\nimport { z } from 'zod';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n loadSkillsManifest,\n loadSkillContent,\n findSkill,\n type LoadedSkills,\n} from '../skills-loader.js';\nimport type { ToolGroup, ToolResult } from '../types.js';\nimport type { SkillEntry } from '@teamix-evo/registry';\n\nconst ListInput = z.object({});\n\nconst GetInput = z.object({\n id: z.string().min(1),\n});\n\nconst FindInput = z.object({\n query: z.string().min(1),\n limit: z.number().int().positive().max(50).optional(),\n /**\n * Scope: 'description' (default — fast, only matches the AI trigger contract)\n * or 'body' (slower — matches across SKILL.md prose, useful for \"where do we\n * mention X\" questions).\n */\n scope: z.enum(['description', 'body', 'all']).optional(),\n});\n\nconst TOOLS: Tool[] = [\n {\n name: 'skills_list',\n description:\n 'List all SKILL.md entries shipped by @teamix-evo/skills. Returns id, name, description (the AI trigger contract), version, source path, ides, updateStrategy. Use this to discover which skills exist before invoking one via the IDE\\'s skill mechanism.',\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'skills_get',\n description:\n 'Fetch the full SKILL.md content (frontmatter + body) for one skill by id or name. Also lists attachment files (sibling .md docs the skill references). Use after skills_list / skills_find to read the actual rules / decision tree / checklist that the skill encodes.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Skill id or name (matches manifest.skills[].id or .name).',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'skills_find',\n description:\n 'Substring search across skill descriptions and bodies. Default scope is `description` (matches the AI trigger contract — fast). Set `scope: \"body\"` to search SKILL.md prose, or `scope: \"all\"` for both. Use when you remember a phrase (\"token refresh\", \"design review\", \"drift scan\") but not the skill id.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Free-text query.' },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: 50,\n description: 'Max matches to return (default 10).',\n },\n scope: {\n type: 'string',\n enum: ['description', 'body', 'all'],\n description:\n 'Where to search: \"description\" (frontmatter, default), \"body\" (SKILL.md prose), or \"all\".',\n },\n },\n required: ['query'],\n },\n },\n];\n\nconst TOOL_NAMES = new Set(TOOLS.map((t) => t.name));\n\nfunction pickEntry(s: SkillEntry) {\n return {\n id: s.id,\n name: s.name,\n description: s.description,\n version: s.version,\n source: s.source,\n ides: s.ides ?? [],\n updateStrategy: s.updateStrategy ?? 'managed',\n template: s.template ?? false,\n };\n}\n\nexport interface SkillsGroupOptions {\n loaded?: LoadedSkills;\n}\n\nexport function createSkillsGroup(opts: SkillsGroupOptions = {}): ToolGroup {\n let cache: LoadedSkills | null = opts.loaded ?? null;\n function getManifest(): LoadedSkills {\n if (!cache) cache = loadSkillsManifest();\n return cache;\n }\n\n return {\n name: 'skills',\n tools: TOOLS,\n async handle(name, args): Promise<ToolResult | undefined> {\n if (!TOOL_NAMES.has(name)) return undefined;\n\n if (name === 'skills_list') {\n ListInput.parse(args ?? {});\n const { manifest } = getManifest();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(manifest.skills.map(pickEntry), null, 2),\n },\n ],\n };\n }\n\n if (name === 'skills_get') {\n const input = GetInput.parse(args);\n const loaded = getManifest();\n const entry = findSkill(loaded, input.id);\n if (!entry) {\n return {\n content: [\n {\n type: 'text',\n text: `Skill not found: ${input.id}. Use skills_list to discover ids.`,\n },\n ],\n isError: true,\n };\n }\n const content = loadSkillContent(entry, loaded.rootDir);\n if (!content) {\n return {\n content: [\n {\n type: 'text',\n text: `Skill source missing on disk for \"${entry.id}\" (expected at ${entry.source}). Check packages/skills installation.`,\n },\n ],\n isError: true,\n };\n }\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n entry: pickEntry(entry),\n attachments: content.attachments,\n content: content.text,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n if (name === 'skills_find') {\n const input = FindInput.parse(args);\n const limit = input.limit ?? 10;\n const scope = input.scope ?? 'description';\n const needle = input.query.toLowerCase();\n const loaded = getManifest();\n\n const matches: Array<{\n entry: ReturnType<typeof pickEntry>;\n hitIn: 'description' | 'body' | 'both';\n }> = [];\n\n for (const entry of loaded.manifest.skills) {\n const descHit =\n scope !== 'body' &&\n entry.description.toLowerCase().includes(needle);\n let bodyHit = false;\n if (scope === 'body' || scope === 'all') {\n const content = loadSkillContent(entry, loaded.rootDir);\n if (content) {\n bodyHit = content.text.toLowerCase().includes(needle);\n }\n }\n if (!descHit && !bodyHit) continue;\n matches.push({\n entry: pickEntry(entry),\n hitIn:\n descHit && bodyHit\n ? 'both'\n : descHit\n ? 'description'\n : 'body',\n });\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n query: input.query,\n scope,\n limit,\n count: Math.min(matches.length, limit),\n totalMatches: matches.length,\n results: matches.slice(0, limit),\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n return undefined;\n },\n };\n}\n","/**\n * Loader for `@teamix-evo/skills` (the skills source-of-truth package).\n *\n * Reads `packages/skills/manifest.json` + each `skills/<id>/SKILL.md`. The\n * frontmatter `description` is the AI trigger contract (see ADR 0013) and is\n * what `skills_find` searches over.\n *\n * In a consumer project, the same shape lives under `node_modules/@teamix-evo/skills/`.\n * Resolution order mirrors the registry/adr loaders:\n *\n * 1. `TEAMIX_EVO_SKILLS_ROOT` env var (absolute path to the package dir)\n * 2. Walk up from cwd looking for `packages/skills/` (monorepo)\n * 3. Walk up from cwd looking for `node_modules/@teamix-evo/skills/` (consumer)\n * 4. Throws with a clear error\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport {\n SkillsPackageManifestSchema,\n type SkillsPackageManifest,\n type SkillEntry,\n} from '@teamix-evo/registry';\n\nexport interface LoadedSkills {\n /** Absolute path to the package root containing manifest.json. */\n rootDir: string;\n manifest: SkillsPackageManifest;\n}\n\nexport function resolveSkillsRoot(startDir: string = process.cwd()): string {\n const envPath = process.env.TEAMIX_EVO_SKILLS_ROOT;\n if (envPath && existsSync(join(envPath, 'manifest.json'))) {\n return envPath;\n }\n\n let dir = resolve(startDir);\n for (let i = 0; i < 16; i++) {\n const candidates = [\n join(dir, 'packages', 'skills'),\n join(dir, 'node_modules', '@teamix-evo', 'skills'),\n ];\n for (const c of candidates) {\n if (existsSync(join(c, 'manifest.json'))) return c;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n throw new Error(\n [\n 'Could not locate @teamix-evo/skills root.',\n `Tried env TEAMIX_EVO_SKILLS_ROOT + walking up from ${startDir}.`,\n 'Either install @teamix-evo/skills or run from a monorepo, or set TEAMIX_EVO_SKILLS_ROOT to an absolute path.',\n ].join(' '),\n );\n}\n\nexport function loadSkillsManifest(rootDir?: string): LoadedSkills {\n const root = rootDir ?? resolveSkillsRoot();\n const manifestPath = join(root, 'manifest.json');\n const raw = JSON.parse(readFileSync(manifestPath, 'utf-8')) as unknown;\n const parsed = SkillsPackageManifestSchema.safeParse(raw);\n if (!parsed.success) {\n throw new Error(\n `Invalid skills manifest at ${manifestPath}: ${parsed.error.message}`,\n );\n }\n return { rootDir: root, manifest: parsed.data };\n}\n\nexport interface SkillContent {\n entry: SkillEntry;\n /** Full SKILL.md text (frontmatter + body). */\n text: string;\n /** Just the body, frontmatter stripped. Null if SKILL.md missing. */\n body: string | null;\n /** Parsed frontmatter as flat string map. */\n frontmatter: Record<string, string>;\n /** Absolute path to SKILL.md. */\n filePath: string;\n /**\n * Other markdown files attached to the skill (siblings of SKILL.md), e.g.\n * generation-flow.md / boundaries.md / checklist.md. Just the relative names —\n * the model can fetch them by name via a follow-up tool call.\n */\n attachments: string[];\n}\n\nconst FM_RE = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?/;\n\nfunction parseFrontmatter(text: string): {\n frontmatter: Record<string, string>;\n body: string;\n} {\n const m = text.match(FM_RE);\n if (!m) return { frontmatter: {}, body: text };\n const fm: Record<string, string> = {};\n for (const line of m[1]!.split('\\n')) {\n const kv = line.match(/^([A-Za-z_][\\w-]*)\\s*:\\s*(.+?)\\s*$/);\n if (kv) fm[kv[1]!] = kv[2]!.replace(/^['\"]|['\"]$/g, '');\n }\n return { frontmatter: fm, body: text.slice(m[0].length) };\n}\n\nexport function loadSkillContent(\n entry: SkillEntry,\n rootDir: string,\n): SkillContent | null {\n const sourcePath = join(rootDir, entry.source);\n if (!existsSync(sourcePath)) return null;\n\n // Skills are typically directories with SKILL.md inside.\n let skillMdPath: string;\n let attachments: string[] = [];\n const dirCandidate = join(sourcePath, 'SKILL.md');\n if (existsSync(dirCandidate)) {\n skillMdPath = dirCandidate;\n // Light attachment scan: top-level .md siblings of SKILL.md.\n try {\n attachments = readdirSync(sourcePath)\n .filter((f) => f.endsWith('.md') && f !== 'SKILL.md')\n .filter((f) => {\n try {\n return statSync(join(sourcePath, f)).isFile();\n } catch {\n return false;\n }\n });\n } catch {\n attachments = [];\n }\n } else {\n // Single-file skill (entry.source points directly at a .md).\n skillMdPath = sourcePath;\n }\n\n const text = readFileSync(skillMdPath, 'utf-8');\n const { frontmatter, body } = parseFrontmatter(text);\n return {\n entry,\n text,\n body,\n frontmatter,\n filePath: skillMdPath,\n attachments,\n };\n}\n\nexport function findSkill(\n loaded: LoadedSkills,\n idOrName: string,\n): SkillEntry | null {\n const needle = idOrName.trim();\n return (\n loaded.manifest.skills.find((s) => s.id === needle) ??\n loaded.manifest.skills.find((s) => s.name === needle) ??\n null\n );\n}\n","/**\n * Design tool group — exposes the consumer project's `.teamix-evo/design/**`\n * tree to AI editors via MCP.\n *\n * Per [ADR 0017](../../../../docs/adr/0017-mcp-design-group.md) the group\n * reads the **installed** design system in the consumer project (not the\n * upstream `@teamix-evo/design` source). Tools:\n *\n * - `design_list_principles` — parsed principles from `philosophy/principles.md`\n * - `design_get_tokens` — base/semantic JSON + theme/overrides CSS\n * - `design_list_patterns` — index of `patterns/*.md` (with variantSpecific flag)\n * - `design_get_pattern` — full markdown of one pattern\n * - `design_get_brand` — tone / voice / examples (variant-scoped, optional)\n *\n * When `.teamix-evo/design/` is absent (project hasn't run `design init`), the\n * group does not throw — each tool returns an empty result with a `note`\n * field telling the caller what's missing.\n */\nimport { z } from 'zod';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n loadDesign,\n readPrinciples,\n readTokens,\n readPatternIndex,\n readPatternContent,\n readBrand,\n type LoadedDesign,\n} from '../design-loader.js';\nimport type { ToolGroup, ToolResult } from '../types.js';\n\nconst EmptyInput = z.object({});\n\nconst GetPatternInput = z.object({\n id: z.string().min(1),\n});\n\nconst TOOLS: Tool[] = [\n {\n name: 'design_list_principles',\n description:\n \"List the design principles defined by the consumer project's installed design variant. Reads `.teamix-evo/design/philosophy/principles.md` and parses headings of the form `## P1 · Name`. Returns id, display name, and a one-line definition for each. Use this when the user asks about \\\"the four principles\\\", \\\"design philosophy\\\", or to ground a design review in the variant's stated values. Returns `{ principles: [], note: \\\"...\\\" }` if the project hasn't installed a design pack.\",\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'design_get_tokens',\n description:\n \"Fetch the consumer project's design tokens — parsed JSON from `.teamix-evo/tokens/base.tokens.json` and `semantic.tokens.json`, plus raw text of `tokens.theme.css` (variant theme) and `tokens.overrides.css` (user-owned overrides) when present. Use when AI needs to know what semantic colors / spacing / radii are available before writing component styles. JSON is for introspection; CSS is for copy-paste. Each tool result lists `sources` so you can cite paths.\",\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'design_list_patterns',\n description:\n \"Index every pattern in `.teamix-evo/design/patterns/*.md` (page types, journeys, flows, plus variant-specific markers like `cloud-*`, `opentrek-*`, `uni-manager-*`). Returns `{ id, title, sourcePath, variantSpecific }` for each. Use this before `design_get_pattern` to discover which patterns exist. When both a baseline (`page-types`) and a variant-specific (`cloud-page-types`) entry are available, prefer the variant-specific one for projects that match.\",\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'design_get_pattern',\n description:\n 'Fetch the full markdown body of one pattern by id (filename stem, e.g. `page-types` or `cloud-page-types`). Use after `design_list_patterns` discovered the id. Returns the raw markdown plus `sourcePath`. Returns isError if the id does not exist — call `design_list_patterns` first to discover available ids.',\n inputSchema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description:\n 'Pattern id — filename stem under `patterns/`, e.g. \"page-types\", \"cloud-page-types\".',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'design_get_brand',\n description:\n \"Fetch the consumer project's variant-specific brand voice — `brand/tone.md`, `brand/voice.md`, `brand/examples.md`. Each is optional; the response contains only the files that exist. Some variants (like `_template` or `default`) ship no brand content — that's not an error, the response simply lists no entries. Use this when generating or reviewing user-facing copy, error messages, empty states, or onboarding text where brand voice matters.\",\n inputSchema: { type: 'object', properties: {} },\n },\n];\n\nconst TOOL_NAMES = new Set(TOOLS.map((t) => t.name));\n\nexport interface DesignGroupOptions {\n /** Pre-loaded design snapshot (used by tests). When omitted, the loader walks cwd. */\n loaded?: LoadedDesign | null;\n /** Override the start directory for cwd-relative resolution (used by tests). */\n rootDir?: string;\n}\n\nconst NO_DESIGN_NOTE =\n '.teamix-evo/design/ not found in this project. Run `npx teamix-evo design init <variant>` to install a design pack.';\n\nexport function createDesignGroup(opts: DesignGroupOptions = {}): ToolGroup {\n let cache: LoadedDesign | null | undefined =\n opts.loaded === undefined ? undefined : opts.loaded;\n function getDesign(): LoadedDesign | null {\n if (cache === undefined) cache = loadDesign(opts.rootDir);\n return cache;\n }\n\n return {\n name: 'design',\n tools: TOOLS,\n async handle(name, args): Promise<ToolResult | undefined> {\n if (!TOOL_NAMES.has(name)) return undefined;\n\n const loaded = getDesign();\n\n if (name === 'design_list_principles') {\n EmptyInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({ principles: [], sourcePath: null, note: NO_DESIGN_NOTE });\n }\n return jsonResult(readPrinciples(loaded));\n }\n\n if (name === 'design_get_tokens') {\n EmptyInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({ sources: [], note: NO_DESIGN_NOTE });\n }\n return jsonResult(readTokens(loaded));\n }\n\n if (name === 'design_list_patterns') {\n EmptyInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({ patterns: [], note: NO_DESIGN_NOTE });\n }\n return jsonResult({\n variant: loaded.variant,\n patterns: readPatternIndex(loaded),\n });\n }\n\n if (name === 'design_get_pattern') {\n const input = GetPatternInput.parse(args);\n if (!loaded) {\n return {\n content: [{ type: 'text', text: NO_DESIGN_NOTE }],\n isError: true,\n };\n }\n const result = readPatternContent(loaded, input.id);\n if (!result) {\n return {\n content: [\n {\n type: 'text',\n text: `Pattern not found: ${input.id}. Use design_list_patterns to discover available ids.`,\n },\n ],\n isError: true,\n };\n }\n return jsonResult(result);\n }\n\n if (name === 'design_get_brand') {\n EmptyInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({ note: NO_DESIGN_NOTE });\n }\n return jsonResult(readBrand(loaded));\n }\n\n return undefined;\n },\n };\n}\n\nfunction jsonResult(payload: unknown): ToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],\n };\n}\n","/**\n * Loader for the consumer project's `.teamix-evo/design/**` tree.\n *\n * Per [ADR 0017](../../../docs/adr/0017-mcp-design-group.md) the design MCP\n * group reads the **installed** design system, not the upstream package. The\n * loader walks `.teamix-evo/design/` from the project root (cwd by default)\n * and returns a typed snapshot the group's tools can serve.\n *\n * Resolution order:\n *\n * 1. `TEAMIX_EVO_DESIGN_ROOT` env var (absolute path to the .teamix-evo/design dir)\n * 2. Walk up from cwd looking for `.teamix-evo/design/`\n * 3. Returns `null` (not an error — projects without design init should get\n * empty tool results with a `note`, not a thrown exception)\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\nexport interface LoadedDesign {\n /** Absolute path to `.teamix-evo/design/` in the consumer project. */\n rootDir: string;\n /** Variant name read from `pack.lock.json`, or null if missing. */\n variant: string | null;\n}\n\nexport function resolveDesignRoot(startDir: string = process.cwd()): string | null {\n const envPath = process.env.TEAMIX_EVO_DESIGN_ROOT;\n if (envPath && existsSync(envPath)) {\n return envPath;\n }\n\n let dir = resolve(startDir);\n for (let i = 0; i < 16; i++) {\n const candidate = join(dir, '.teamix-evo', 'design');\n if (existsSync(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nexport function loadDesign(rootDir?: string): LoadedDesign | null {\n const root = rootDir ?? resolveDesignRoot();\n if (!root) return null;\n\n let variant: string | null = null;\n const lockPath = join(root, 'pack.lock.json');\n if (existsSync(lockPath)) {\n try {\n const raw = JSON.parse(readFileSync(lockPath, 'utf-8')) as {\n variant?: string;\n };\n variant = typeof raw.variant === 'string' ? raw.variant : null;\n } catch {\n variant = null;\n }\n }\n return { rootDir: root, variant };\n}\n\nexport interface PrincipleEntry {\n id: string;\n name: string;\n oneLineDef: string;\n}\n\nconst PRINCIPLE_HEADING_RE = /^#{2,3}\\s+(P\\d+)\\s*[·:]\\s*(.+?)\\s*$/;\n\n/**\n * Parse `philosophy/principles.md` for headings of the form `## P1 · Name`.\n * Returns the principle id, display name, and the first non-blank line below\n * the heading as a one-line definition.\n */\nexport function readPrinciples(loaded: LoadedDesign): {\n principles: PrincipleEntry[];\n sourcePath: string | null;\n note?: string;\n} {\n const filePath = join(loaded.rootDir, 'philosophy', 'principles.md');\n if (!existsSync(filePath)) {\n return {\n principles: [],\n sourcePath: null,\n note:\n 'philosophy/principles.md not found in this project. Run `teamix-evo design init <variant>` to install it.',\n };\n }\n const text = readFileSync(filePath, 'utf-8');\n const lines = text.split(/\\r?\\n/);\n const out: PrincipleEntry[] = [];\n for (let i = 0; i < lines.length; i++) {\n const m = lines[i]!.match(PRINCIPLE_HEADING_RE);\n if (!m) continue;\n let def = '';\n for (let j = i + 1; j < lines.length && j < i + 8; j++) {\n const candidate = lines[j]!.trim();\n if (!candidate) continue;\n if (/^#{1,6}\\s/.test(candidate)) break;\n def = candidate.replace(/^[*_>\\s-]+/, '').trim();\n break;\n }\n out.push({ id: m[1]!, name: m[2]!.trim(), oneLineDef: def });\n }\n return { principles: out, sourcePath: filePath };\n}\n\nexport interface TokenSnapshot {\n /** Parsed contents of `base.tokens.json` if present. */\n base?: unknown;\n /** Parsed contents of `semantic.tokens.json` if present. */\n semantic?: unknown;\n /** Raw text of `tokens.theme.css` if present. */\n themeCss?: string;\n /** Raw text of `tokens.overrides.css` if present (user-owned overrides). */\n overridesCss?: string;\n /** Source paths discovered, in load order. */\n sources: string[];\n note?: string;\n}\n\n/**\n * Locate the tokens directory. Tokens live at `<projectRoot>/.teamix-evo/tokens/`\n * since v0.7 (lifted out of `design/foundations/tokens/`). Falls back to the\n * legacy in-design location for projects installed before the lift.\n */\nfunction resolveTokensDir(loaded: LoadedDesign): string | null {\n const projectRoot = dirname(loaded.rootDir); // .teamix-evo/\n const lifted = join(projectRoot, 'tokens');\n if (existsSync(lifted)) return lifted;\n const legacy = join(loaded.rootDir, 'foundations', 'tokens');\n if (existsSync(legacy)) return legacy;\n return null;\n}\n\nexport function readTokens(loaded: LoadedDesign): TokenSnapshot {\n const tokensDir = resolveTokensDir(loaded);\n const out: TokenSnapshot = { sources: [] };\n if (!tokensDir) {\n out.note =\n '.teamix-evo/tokens/ not found in this project (and no legacy foundations/tokens/).';\n return out;\n }\n const tryJson = (rel: string): unknown | undefined => {\n const fp = join(tokensDir, rel);\n if (!existsSync(fp)) return undefined;\n out.sources.push(fp);\n try {\n return JSON.parse(readFileSync(fp, 'utf-8'));\n } catch {\n return undefined;\n }\n };\n const tryText = (rel: string): string | undefined => {\n const fp = join(tokensDir, rel);\n if (!existsSync(fp)) return undefined;\n out.sources.push(fp);\n return readFileSync(fp, 'utf-8');\n };\n out.base = tryJson('base.tokens.json');\n out.semantic = tryJson('semantic.tokens.json');\n out.themeCss = tryText('tokens.theme.css');\n out.overridesCss = tryText('tokens.overrides.css');\n return out;\n}\n\nexport interface PatternIndexEntry {\n id: string; // file stem, e.g. \"page-types\" or \"cloud-page-types\"\n title: string; // first H1 in the file, fallback to id\n sourcePath: string;\n variantSpecific: boolean; // true for files prefixed with a known variant marker\n}\n\nconst VARIANT_PREFIX_RE = /^(cloud|opentrek|uni-manager|enterprise)-/i;\n\nexport function readPatternIndex(loaded: LoadedDesign): PatternIndexEntry[] {\n const patternsDir = join(loaded.rootDir, 'patterns');\n if (!existsSync(patternsDir)) return [];\n const out: PatternIndexEntry[] = [];\n for (const name of readdirSync(patternsDir)) {\n if (!name.endsWith('.md')) continue;\n const fp = join(patternsDir, name);\n try {\n if (!statSync(fp).isFile()) continue;\n } catch {\n continue;\n }\n const stem = name.replace(/\\.md$/, '');\n const text = readFileSync(fp, 'utf-8');\n const titleMatch = text.match(/^#\\s+(.+?)\\s*$/m);\n out.push({\n id: stem,\n title: titleMatch ? titleMatch[1]! : stem,\n sourcePath: fp,\n variantSpecific: VARIANT_PREFIX_RE.test(stem),\n });\n }\n return out.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nexport function readPatternContent(\n loaded: LoadedDesign,\n id: string,\n): { id: string; sourcePath: string; content: string } | null {\n const stem = id.replace(/\\.md$/, '');\n const fp = join(loaded.rootDir, 'patterns', `${stem}.md`);\n if (!existsSync(fp)) return null;\n return {\n id: stem,\n sourcePath: fp,\n content: readFileSync(fp, 'utf-8'),\n };\n}\n\nexport interface BrandSnapshot {\n tone?: { sourcePath: string; content: string };\n voice?: { sourcePath: string; content: string };\n examples?: { sourcePath: string; content: string };\n note?: string;\n}\n\nexport function readBrand(loaded: LoadedDesign): BrandSnapshot {\n const brandDir = join(loaded.rootDir, 'brand');\n const out: BrandSnapshot = {};\n if (!existsSync(brandDir)) {\n out.note =\n 'brand/ not present — this design variant does not ship brand-specific tone / voice / examples.';\n return out;\n }\n for (const key of ['tone', 'voice', 'examples'] as const) {\n const fp = join(brandDir, `${key}.md`);\n if (existsSync(fp)) {\n out[key] = { sourcePath: fp, content: readFileSync(fp, 'utf-8') };\n }\n }\n return out;\n}\n"],"mappings":"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","names":["FM_RE","z","existsSync","readFileSync","dirname","join","resolve","z","TOOLS","TOOL_NAMES","from","z","existsSync","readFileSync","readdirSync","dirname","join","resolve","parseFrontmatter","ListInput","z","GetInput","FindInput","TOOLS","TOOL_NAMES","pickEntry","z","existsSync","readFileSync","readdirSync","statSync","dirname","join","resolve","z","TOOLS","TOOL_NAMES"]}
@@ -0,0 +1,257 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { UiPackageManifest, UiEntry, SkillsPackageManifest, SkillEntry } from '@teamix-evo/registry';
3
+ import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
4
+
5
+ /**
6
+ * Resolves the `@teamix-evo/ui/manifest.json` path using a layered strategy:
7
+ *
8
+ * 1. `TEAMIX_EVO_UI_MANIFEST` env var (absolute path)
9
+ * 2. `<cwd>/node_modules/@teamix-evo/ui/manifest.json`
10
+ * 3. Walking up parent directories until a matching `node_modules/...` is found
11
+ * 4. Throws with a clear error message
12
+ */
13
+ declare function resolveManifestPath(startDir?: string): string;
14
+ interface LoadedManifest {
15
+ manifest: UiPackageManifest;
16
+ /** Directory of the manifest.json itself; used to resolve `meta.md` paths. */
17
+ rootDir: string;
18
+ }
19
+ /**
20
+ * Loads and Zod-validates the UI package manifest.
21
+ * Throws on invalid manifest with the underlying Zod error attached.
22
+ */
23
+ declare function loadManifest(path?: string): LoadedManifest;
24
+ /**
25
+ * Frontmatter + body extracted from a `<id>.meta.md` file.
26
+ * Frontmatter is parsed as a flat key/value map (no YAML library dep —
27
+ * meta.md frontmatters are intentionally simple).
28
+ */
29
+ interface ParsedMeta {
30
+ frontmatter: Record<string, string>;
31
+ body: string;
32
+ }
33
+ /**
34
+ * Reads and minimally parses a `<id>.meta.md` file. Returns `null` if the
35
+ * meta file is missing or the entry didn't declare one.
36
+ *
37
+ * Frontmatter parser is minimal (single-line `key: value` pairs only). It
38
+ * does NOT support nested or array YAML — sufficient for the meta.md format
39
+ * documented in packages/ui/AGENTS.md §三.E.
40
+ */
41
+ declare function loadMeta(entry: UiEntry, rootDir: string): ParsedMeta | null;
42
+
43
+ /**
44
+ * Shared types for MCP tool groups.
45
+ *
46
+ * Each tool group exports a `createXxxGroup(opts)` factory returning a
47
+ * `ToolGroup`. The main server (`src/server.ts`) collects all groups and
48
+ * dispatches `tools/call` requests by tool name.
49
+ *
50
+ * See [ADR 0011](../../../docs/adr/0011-mcp-single-package-multi-group.md).
51
+ */
52
+
53
+ /**
54
+ * The result envelope a tool handler returns. Mirrors MCP SDK's CallToolResult
55
+ * but kept narrow to what our handlers actually emit.
56
+ */
57
+ type ToolResult = CallToolResult;
58
+ /**
59
+ * One registered tool group (e.g. registry / design / adr / scenario).
60
+ *
61
+ * - `tools`: the tool descriptors this group contributes to `tools/list`.
62
+ * - `handle`: receives a tool-call name + args. Returns a `ToolResult` if the
63
+ * tool name belongs to this group; returns `undefined` otherwise so the main
64
+ * server can try the next group.
65
+ */
66
+ interface ToolGroup {
67
+ readonly name: string;
68
+ readonly tools: Tool[];
69
+ handle(toolName: string, args: unknown): Promise<ToolResult | undefined>;
70
+ }
71
+
72
+ interface RegistryGroupOptions {
73
+ /** Pre-loaded manifest (used in tests to avoid filesystem). */
74
+ loaded?: LoadedManifest;
75
+ }
76
+ declare function createRegistryGroup(opts?: RegistryGroupOptions): ToolGroup;
77
+
78
+ interface AdrEntry {
79
+ /** Numeric id, e.g. "0011". Derived from the filename prefix. */
80
+ id: string;
81
+ /** Filename without `.md`, e.g. "0011-mcp-single-package-multi-group". */
82
+ slug: string;
83
+ /** Title after "NNNN. " in the H1 line. */
84
+ title: string;
85
+ /** Raw status string from the `- **Status**:` line. Empty if missing. */
86
+ status: string;
87
+ /** Date from the `- **Date**:` line (YYYY-MM-DD). Empty if missing. */
88
+ date: string;
89
+ /** Optional region label (`0100–0999 协议与工具`). Empty if missing. */
90
+ region: string;
91
+ /** Absolute path to the source file (for `adr_get`). */
92
+ filePath: string;
93
+ }
94
+ interface LoadedAdrs {
95
+ /** Directory containing the ADR `.md` files. */
96
+ rootDir: string;
97
+ entries: AdrEntry[];
98
+ }
99
+ /**
100
+ * Resolves the ADR directory using a layered strategy:
101
+ *
102
+ * 1. `TEAMIX_EVO_ADR_ROOT` env var (absolute path)
103
+ * 2. Walk up from cwd looking for `docs/adr/` (monorepo layout)
104
+ * 3. Walk up from cwd looking for `.teamix-evo/adr/` (consumer layout — future)
105
+ * 4. Throws with a clear error
106
+ */
107
+ declare function resolveAdrRoot(startDir?: string): string;
108
+ declare function loadAdrIndex(rootDir?: string): LoadedAdrs;
109
+ /**
110
+ * Look up one ADR by id ("0011") or full slug ("0011-mcp-single-package-multi-group").
111
+ * Returns `null` if no match.
112
+ */
113
+ declare function findAdr(loaded: LoadedAdrs, idOrSlug: string): AdrEntry | null;
114
+ declare function loadAdrContent(entry: AdrEntry): string;
115
+
116
+ interface AdrGroupOptions {
117
+ /** Pre-loaded index (used in tests to avoid filesystem). */
118
+ loaded?: LoadedAdrs;
119
+ }
120
+ declare function createAdrGroup(opts?: AdrGroupOptions): ToolGroup;
121
+
122
+ interface LoadedSkills {
123
+ /** Absolute path to the package root containing manifest.json. */
124
+ rootDir: string;
125
+ manifest: SkillsPackageManifest;
126
+ }
127
+ declare function resolveSkillsRoot(startDir?: string): string;
128
+ declare function loadSkillsManifest(rootDir?: string): LoadedSkills;
129
+ interface SkillContent {
130
+ entry: SkillEntry;
131
+ /** Full SKILL.md text (frontmatter + body). */
132
+ text: string;
133
+ /** Just the body, frontmatter stripped. Null if SKILL.md missing. */
134
+ body: string | null;
135
+ /** Parsed frontmatter as flat string map. */
136
+ frontmatter: Record<string, string>;
137
+ /** Absolute path to SKILL.md. */
138
+ filePath: string;
139
+ /**
140
+ * Other markdown files attached to the skill (siblings of SKILL.md), e.g.
141
+ * generation-flow.md / boundaries.md / checklist.md. Just the relative names —
142
+ * the model can fetch them by name via a follow-up tool call.
143
+ */
144
+ attachments: string[];
145
+ }
146
+ declare function loadSkillContent(entry: SkillEntry, rootDir: string): SkillContent | null;
147
+ declare function findSkill(loaded: LoadedSkills, idOrName: string): SkillEntry | null;
148
+
149
+ interface SkillsGroupOptions {
150
+ loaded?: LoadedSkills;
151
+ }
152
+ declare function createSkillsGroup(opts?: SkillsGroupOptions): ToolGroup;
153
+
154
+ interface LoadedDesign {
155
+ /** Absolute path to `.teamix-evo/design/` in the consumer project. */
156
+ rootDir: string;
157
+ /** Variant name read from `pack.lock.json`, or null if missing. */
158
+ variant: string | null;
159
+ }
160
+ declare function resolveDesignRoot(startDir?: string): string | null;
161
+ declare function loadDesign(rootDir?: string): LoadedDesign | null;
162
+ interface PrincipleEntry {
163
+ id: string;
164
+ name: string;
165
+ oneLineDef: string;
166
+ }
167
+ /**
168
+ * Parse `philosophy/principles.md` for headings of the form `## P1 · Name`.
169
+ * Returns the principle id, display name, and the first non-blank line below
170
+ * the heading as a one-line definition.
171
+ */
172
+ declare function readPrinciples(loaded: LoadedDesign): {
173
+ principles: PrincipleEntry[];
174
+ sourcePath: string | null;
175
+ note?: string;
176
+ };
177
+ interface TokenSnapshot {
178
+ /** Parsed contents of `base.tokens.json` if present. */
179
+ base?: unknown;
180
+ /** Parsed contents of `semantic.tokens.json` if present. */
181
+ semantic?: unknown;
182
+ /** Raw text of `tokens.theme.css` if present. */
183
+ themeCss?: string;
184
+ /** Raw text of `tokens.overrides.css` if present (user-owned overrides). */
185
+ overridesCss?: string;
186
+ /** Source paths discovered, in load order. */
187
+ sources: string[];
188
+ note?: string;
189
+ }
190
+ declare function readTokens(loaded: LoadedDesign): TokenSnapshot;
191
+ interface PatternIndexEntry {
192
+ id: string;
193
+ title: string;
194
+ sourcePath: string;
195
+ variantSpecific: boolean;
196
+ }
197
+ declare function readPatternIndex(loaded: LoadedDesign): PatternIndexEntry[];
198
+ declare function readPatternContent(loaded: LoadedDesign, id: string): {
199
+ id: string;
200
+ sourcePath: string;
201
+ content: string;
202
+ } | null;
203
+ interface BrandSnapshot {
204
+ tone?: {
205
+ sourcePath: string;
206
+ content: string;
207
+ };
208
+ voice?: {
209
+ sourcePath: string;
210
+ content: string;
211
+ };
212
+ examples?: {
213
+ sourcePath: string;
214
+ content: string;
215
+ };
216
+ note?: string;
217
+ }
218
+ declare function readBrand(loaded: LoadedDesign): BrandSnapshot;
219
+
220
+ interface DesignGroupOptions {
221
+ /** Pre-loaded design snapshot (used by tests). When omitted, the loader walks cwd. */
222
+ loaded?: LoadedDesign | null;
223
+ /** Override the start directory for cwd-relative resolution (used by tests). */
224
+ rootDir?: string;
225
+ }
226
+ declare function createDesignGroup(opts?: DesignGroupOptions): ToolGroup;
227
+
228
+ /**
229
+ * Main MCP server — composes multiple tool groups into one stdio process.
230
+ *
231
+ * Architecture per [ADR 0011](../../../docs/adr/0011-mcp-single-package-multi-group.md):
232
+ * single package / single bin / multiple tool groups. Groups added in later
233
+ * milestones (design v0.6, adr v0.7, scenario v0.8) plug in here without
234
+ * touching the transport or ListTools/CallTool handler logic.
235
+ *
236
+ * Tool dispatch:
237
+ * - `tools/list` returns the union of all groups' tools.
238
+ * - `tools/call` walks the group list in registration order; the first group
239
+ * whose `handle` returns a non-`undefined` result wins. Tool-name uniqueness
240
+ * across groups is the responsibility of group authors (see ADR 0011 §5
241
+ * for the `<group>_<verb>_<noun>` naming convention; `registry` is the
242
+ * historical exception).
243
+ */
244
+
245
+ interface ServerOptions {
246
+ /** Options forwarded to the registry group. Pass `loaded` in tests. */
247
+ registry?: RegistryGroupOptions;
248
+ /** Options forwarded to the adr group. Pass `loaded` in tests. */
249
+ adr?: AdrGroupOptions;
250
+ /** Options forwarded to the skills group. Pass `loaded` in tests. */
251
+ skills?: SkillsGroupOptions;
252
+ /** Options forwarded to the design group. Pass `loaded` in tests. */
253
+ design?: DesignGroupOptions;
254
+ }
255
+ declare function createServer(opts?: ServerOptions): Server;
256
+
257
+ export { type AdrEntry, type AdrGroupOptions, type BrandSnapshot, type DesignGroupOptions, type LoadedAdrs, type LoadedDesign, type LoadedManifest, type LoadedSkills, type ParsedMeta, type PatternIndexEntry, type PrincipleEntry, type RegistryGroupOptions, type ServerOptions, type SkillContent, type SkillsGroupOptions, type TokenSnapshot, type ToolGroup, type ToolResult, createAdrGroup, createDesignGroup, createRegistryGroup, createServer, createSkillsGroup, findAdr, findSkill, loadAdrContent, loadAdrIndex, loadDesign, loadManifest, loadMeta, loadSkillContent, loadSkillsManifest, readBrand, readPatternContent, readPatternIndex, readPrinciples, readTokens, resolveAdrRoot, resolveDesignRoot, resolveManifestPath, resolveSkillsRoot };