@teamix-evo/mcp 0.3.0 → 0.4.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.
Files changed (29) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +161 -162
  3. package/dist/cli.js.map +1 -1
  4. package/dist/data/adr/0001-three-layer-alignment.md +54 -0
  5. package/dist/data/adr/0002-package-naming.md +50 -0
  6. package/dist/data/adr/0003-update-strategy-tri-state.md +62 -0
  7. package/dist/data/adr/0004-cli-command-structure.md +61 -0
  8. package/dist/data/adr/0005-ui-no-variant.md +67 -0
  9. package/dist/data/adr/0006-ui-upgrade-no-baseline.md +67 -0
  10. package/dist/data/adr/0007-governance-docs-at-root.md +62 -0
  11. package/dist/data/adr/0008-eslint-visual-rules-warn-baseline.md +110 -0
  12. package/dist/data/adr/0009-registry-mcp-protocol-layer.md +87 -0
  13. package/dist/data/adr/0010-design-default-and-variants.md +319 -0
  14. package/dist/data/adr/0011-mcp-single-package-multi-group.md +169 -0
  15. package/dist/data/adr/0012-lint-shared-core.md +215 -0
  16. package/dist/data/adr/0013-skills-source-mirror.md +154 -0
  17. package/dist/data/adr/0014-ui-biz-ui-templates-tier.md +274 -0
  18. package/dist/data/adr/0015-skill-description-trigger-contract.md +122 -0
  19. package/dist/data/adr/0016-design-md-brand-charter.md +93 -0
  20. package/dist/data/adr/0017-mcp-design-group.md +107 -0
  21. package/dist/data/adr/0018-ai-context-routing.md +112 -0
  22. package/dist/data/adr/0019-project-upgrade-flow.md +156 -0
  23. package/dist/data/adr/0020-design-to-tokens-skill-fusion.md +139 -0
  24. package/dist/data/adr/README.md +70 -0
  25. package/dist/data/adr/_template.md +36 -0
  26. package/dist/index.d.ts +64 -59
  27. package/dist/index.js +168 -170
  28. package/dist/index.js.map +1 -1
  29. package/package.json +1 -1
package/dist/cli.js.map CHANGED
@@ -1 +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"]}
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/tokens.ts","../src/tokens-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 (tokens 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 { createTokensGroup, type TokensGroupOptions } from './groups/tokens.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 tokens group. Pass `loaded` in tests. */\n tokens?: TokensGroupOptions;\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 createTokensGroup(opts.tokens),\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 — the UI registry is not installed in this project.',\n '',\n 'Fix one of:',\n ` 1. Install the package: pnpm add @teamix-evo/ui (or npm/yarn equivalent)`,\n ` 2. Point env at an existing manifest: export TEAMIX_EVO_UI_MANIFEST=/abs/path/to/manifest.json`,\n '',\n `Searched: $TEAMIX_EVO_UI_MANIFEST, then walked up from ${startDir} looking for node_modules/@teamix-evo/ui/manifest.json (16 levels).`,\n 'Note: MCP currently has no online fallback — it does not fetch from the npm registry / unpkg.',\n ].join('\\n'),\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';\nimport { fileURLToPath } from 'node:url';\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. Bundled snapshot at `<mcp-pkg>/dist/data/adr/` (works in consumer projects\n * after `pnpm add @teamix-evo/mcp` — see tsup.config.ts onSuccess copy)\n * 3. Walk up from cwd looking for `docs/adr/` (monorepo layout)\n * 4. Walk up from cwd looking for `.teamix-evo/adr/` (consumer override)\n * 5. 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 // Bundled snapshot inside the mcp package itself. import.meta.url at\n // runtime resolves to dist/cli.js or dist/index.js inside the published\n // package; its sibling `data/adr/` is populated by tsup onSuccess.\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n const bundled = join(here, 'data', 'adr');\n if (existsSync(bundled)) return bundled;\n } catch {\n // import.meta.url may be unavailable in some test environments.\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, mcp-bundled snapshot, and walked up from ${startDir} for docs/adr/ or .teamix-evo/adr/.`,\n 'Either install @teamix-evo/mcp (carries ADR snapshot) 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 and walked up from ${startDir} for packages/skills/ or node_modules/@teamix-evo/skills/.`,\n 'Install @teamix-evo/skills as a devDependency in your project (the scaffold adds it automatically).',\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 * Tokens tool group — exposes the consumer project's design tokens\n * to AI editors via MCP.\n *\n * Per [ADR 0020](../../../../docs/adr/0020-design-to-tokens-skill-fusion.md),\n * design knowledge now lives in @teamix-evo/skills (AI reads skill files\n * directly). MCP only provides token value lookup — the one thing AI\n * can't get from a static skill file.\n *\n * - `tokens_get` — full snapshot (base JSON + theme/overrides CSS) for copy-paste\n * - `tokens_list` — flat list of token entries for introspection (category/name/values)\n * - `tokens_search` — substring search across category / name / description / values\n *\n * When `tokens/` directory is absent (project hasn't run `tokens init`),\n * the tools return empty results with a `note` field.\n */\nimport { z } from 'zod';\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n loadTokens,\n readTokens,\n listTokens,\n searchTokens,\n type LoadedTokens,\n} from '../tokens-loader.js';\nimport type { ToolGroup, ToolResult } from '../types.js';\n\nconst EmptyInput = z.object({});\nconst SearchInput = z.object({\n query: z.string().min(1),\n limit: z.number().int().min(1).max(100).optional(),\n});\n\nconst TOOLS: Tool[] = [\n {\n name: 'tokens_get',\n description:\n \"Fetch the consumer project's design tokens — parsed JSON from `tokens/base.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 result lists `sources` so you can cite paths.\",\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'tokens_list',\n description:\n 'List ALL design tokens as a flat array of entries `{ category, name, type, values, description }`. Categories come from top-level keys of base.tokens.json (e.g. `color`, `radius`, `spacing`). Each entry exposes resolved values keyed by mode (e.g. `light` / `dark` / `default`). Use this BEFORE writing styles to discover what semantic names are available — much cheaper than parsing the whole CSS file. Use `tokens_search` instead when you have a keyword.',\n inputSchema: { type: 'object', properties: {} },\n },\n {\n name: 'tokens_search',\n description:\n 'Substring match across token category / name / description / values (case-insensitive). Use when you remember a phrase (\"primary\" / \"destructive\" / \"card-gap\") but not the exact path. Returns up to `limit` matches (default 20). Combine with `tokens_get` if you need raw CSS text after locating an entry.',\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: 100,\n description: 'Max matches to return (default 20).',\n },\n },\n required: ['query'],\n },\n },\n];\n\nconst TOOL_NAMES = new Set(TOOLS.map((t) => t.name));\n\nexport interface TokensGroupOptions {\n /** Pre-loaded tokens snapshot (used by tests). When omitted, the loader walks cwd. */\n loaded?: LoadedTokens | null;\n /** Override the start directory for cwd-relative resolution (used by tests). */\n rootDir?: string;\n}\n\nconst NO_TOKENS_NOTE =\n 'tokens/ directory not found in this project. Run `npx teamix-evo tokens init <variant>` to install design tokens.';\n\nexport function createTokensGroup(opts: TokensGroupOptions = {}): ToolGroup {\n let cache: LoadedTokens | null | undefined =\n opts.loaded === undefined ? undefined : opts.loaded;\n function getLoaded(): LoadedTokens | null {\n if (cache === undefined) cache = loadTokens(opts.rootDir);\n return cache;\n }\n\n return {\n name: 'tokens',\n tools: TOOLS,\n async handle(name, args): Promise<ToolResult | undefined> {\n if (!TOOL_NAMES.has(name)) return undefined;\n\n const loaded = getLoaded();\n\n if (name === 'tokens_get') {\n EmptyInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({ sources: [], note: NO_TOKENS_NOTE });\n }\n return jsonResult(readTokens(loaded));\n }\n\n if (name === 'tokens_list') {\n EmptyInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({\n variant: null,\n tokens: [],\n sources: [],\n note: NO_TOKENS_NOTE,\n });\n }\n return jsonResult(listTokens(loaded));\n }\n\n if (name === 'tokens_search') {\n const parsed = SearchInput.parse(args ?? {});\n if (!loaded) {\n return jsonResult({\n variant: null,\n query: parsed.query,\n matches: [],\n sources: [],\n note: NO_TOKENS_NOTE,\n });\n }\n return jsonResult(searchTokens(loaded, parsed.query, parsed.limit));\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/` state.\n *\n * Per [ADR 0020](../../../docs/adr/0020-design-to-tokens-skill-fusion.md) the\n * MCP `tokens` group reads the **installed** tokens of a teamix-evo project.\n * The loader walks up from the cwd looking for `.teamix-evo/` and, if a\n * `tokens-lock.json` is present, records the variant for downstream tools.\n *\n * Resolution order:\n *\n * 1. `TEAMIX_EVO_TOKENS_ROOT` env var (absolute path to the `.teamix-evo/` dir)\n * 2. Walk up from cwd looking for `.teamix-evo/`\n * 3. Returns `null` (not an error — projects without teamix-evo init should\n * get empty tool results with a `note`, not a thrown exception)\n */\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\nexport interface LoadedTokens {\n /** Absolute path to `.teamix-evo/` in the consumer project. */\n rootDir: string;\n /** Variant name read from `tokens-lock.json`, or null if missing. */\n variant: string | null;\n}\n\nexport function resolveTokensRoot(\n startDir: string = process.cwd(),\n): string | null {\n const envPath = process.env.TEAMIX_EVO_TOKENS_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');\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 loadTokens(rootDir?: string): LoadedTokens | null {\n const root = rootDir ?? resolveTokensRoot();\n if (!root) return null;\n\n let variant: string | null = null;\n const lockPath = join(root, 'tokens-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 TokenSnapshot {\n /** Parsed contents of `base.tokens.json` if present. */\n base?: 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>/tokens/`\n * (root-level, per ADR 0020).\n */\nfunction resolveTokensDir(loaded: LoadedTokens): string | null {\n const projectRoot = dirname(loaded.rootDir);\n const rootTokens = join(projectRoot, 'tokens');\n if (existsSync(rootTokens)) return rootTokens;\n return null;\n}\n\nexport function readTokens(loaded: LoadedTokens): TokenSnapshot {\n const tokensDir = resolveTokensDir(loaded);\n const out: TokenSnapshot = { sources: [] };\n if (!tokensDir) {\n out.note = 'tokens/ not found at project root.';\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.themeCss = tryText('tokens.theme.css');\n out.overridesCss = tryText('tokens.overrides.css');\n return out;\n}\n\nexport interface TokenEntry {\n /** Top-level group from base.tokens.json, e.g. \"color\" / \"radius\" / \"spacing\". */\n category: string;\n /** Token leaf name within the category, e.g. \"primary\" / \"card-foreground\". */\n name: string;\n /** W3C `$type` declared on the token, when present. */\n type?: string;\n /**\n * Resolved values keyed by mode. For W3C tokens with `light` / `dark`\n * sub-objects we emit both; for flat tokens (single `$value`) we emit\n * `default`.\n */\n values: Record<string, string>;\n /** First non-empty `$description` found on the token or its modes. */\n description?: string;\n}\n\nconst W3C_KEYS = new Set(['$value', '$type', '$description', '$extensions']);\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/**\n * Flatten a W3C-format design-token JSON tree into a list of token entries.\n *\n * The format we ingest is the one shipped by `@teamix-evo/tokens`:\n *\n * { color: { primary: { $type, light: { $value, $description }, dark: { ... } } } }\n *\n * For tokens with `$value` directly under the leaf (no light/dark split) we\n * emit `values = { default: <value> }`.\n *\n * Top-level keys starting with `$` (e.g. `$schema`, `$version`) are skipped.\n */\nexport function flattenTokens(base: unknown): TokenEntry[] {\n if (!isPlainObject(base)) return [];\n const out: TokenEntry[] = [];\n\n for (const [category, group] of Object.entries(base)) {\n if (category.startsWith('$')) continue;\n if (!isPlainObject(group)) continue;\n\n for (const [name, leaf] of Object.entries(group)) {\n if (name.startsWith('$')) continue;\n if (!isPlainObject(leaf)) continue;\n\n const type =\n typeof leaf.$type === 'string' ? (leaf.$type as string) : undefined;\n const values: Record<string, string> = {};\n let description =\n typeof leaf.$description === 'string'\n ? (leaf.$description as string)\n : undefined;\n\n if (typeof leaf.$value === 'string') {\n values.default = leaf.$value as string;\n }\n\n for (const [modeKey, modeVal] of Object.entries(leaf)) {\n if (W3C_KEYS.has(modeKey)) continue;\n if (!isPlainObject(modeVal)) continue;\n if (typeof modeVal.$value === 'string') {\n values[modeKey] = modeVal.$value as string;\n }\n if (\n !description &&\n typeof modeVal.$description === 'string'\n ) {\n description = modeVal.$description as string;\n }\n }\n\n if (Object.keys(values).length === 0) continue;\n\n out.push({\n category,\n name,\n ...(type ? { type } : {}),\n values,\n ...(description ? { description } : {}),\n });\n }\n }\n\n return out;\n}\n\nexport interface TokenListResult {\n variant: string | null;\n tokens: TokenEntry[];\n sources: string[];\n note?: string;\n}\n\nexport function listTokens(loaded: LoadedTokens): TokenListResult {\n const snapshot = readTokens(loaded);\n if (!snapshot.base) {\n return {\n variant: loaded.variant,\n tokens: [],\n sources: snapshot.sources,\n note: snapshot.note ?? 'base.tokens.json not found.',\n };\n }\n return {\n variant: loaded.variant,\n tokens: flattenTokens(snapshot.base),\n sources: snapshot.sources,\n };\n}\n\nexport interface TokenSearchResult {\n variant: string | null;\n query: string;\n matches: TokenEntry[];\n sources: string[];\n note?: string;\n}\n\n/**\n * Substring match across category / name / description / values. Case-insensitive.\n * Returns up to `limit` (default 20) matches ordered by category > name.\n */\nexport function searchTokens(\n loaded: LoadedTokens,\n query: string,\n limit = 20,\n): TokenSearchResult {\n const list = listTokens(loaded);\n const q = query.trim().toLowerCase();\n if (!q) {\n return {\n variant: list.variant,\n query,\n matches: [],\n sources: list.sources,\n note: 'query is empty.',\n };\n }\n if (list.note && list.tokens.length === 0) {\n return {\n variant: list.variant,\n query,\n matches: [],\n sources: list.sources,\n note: list.note,\n };\n }\n const hits = list.tokens.filter((t) => {\n if (t.category.toLowerCase().includes(q)) return true;\n if (t.name.toLowerCase().includes(q)) return true;\n if (t.description?.toLowerCase().includes(q)) return true;\n return Object.values(t.values).some((v) => v.toLowerCase().includes(q));\n });\n hits.sort((a, b) => {\n const c = a.category.localeCompare(b.category);\n return c !== 0 ? c : a.name.localeCompare(b.name);\n });\n return {\n variant: list.variant,\n query,\n matches: hits.slice(0, limit),\n sources: list.sources,\n };\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","dirname","join","resolve","z","TOOLS","TOOL_NAMES"]}
@@ -0,0 +1,54 @@
1
+ # 0001. UI 组件研发三层对齐:能力 = shadcn ∪ antd / 理念 = design / 工程 = shadcn
2
+
3
+ - **Status**: Accepted
4
+ - **Date**: 2026-05-15
5
+ - **Region**: 0001–0099 工程哲学
6
+ - **Related ADR**: [0005 UI 包不分 variant](0005-ui-no-variant.md) / [0014 ui/biz-ui/templates 三层](0014-ui-biz-ui-templates-tier.md)(本 ADR 在三个粒度上落实)
7
+
8
+ ## Context
9
+
10
+ teamix-evo 的 ui 包面对一个上游生态的取舍问题:**shadcn/ui** 与 **Ant Design** 这两个广泛使用的 React 组件库,各自有不同的能力、视觉、工程范式。在 ui 包内研发新组件时,必须有一套明确的对齐规则,否则:
11
+
12
+ - 不同人在不同组件上的"参考对象"不同,组件能力面会塌陷成残缺集合;
13
+ - 视觉风格在不同组件上漂移(有的像 antd 蓝色,有的像 shadcn 黑白);
14
+ - 工程范式混乱(有的用 cva,有的用 less + ConfigProvider)。
15
+
16
+ ## Options Considered
17
+
18
+ | 选项 | 优点 | 缺点 |
19
+ | ---- | ---- | ---- |
20
+ | 全盘对齐 shadcn | 工程一致、生态成熟 | antd 用户惯用的能力(loading / icon prop / shape / block 等)缺失 |
21
+ | 全盘对齐 antd | 能力完整、中后台用户熟悉 | 工程笨重(less + ConfigProvider 运行时主题),与源码注入模式不兼容 |
22
+ | **三层切分对齐(本决策)** | 各取所长,覆盖最广 | 每新增组件需做并集对照表(维护成本) |
23
+
24
+ ## Decision
25
+
26
+ UI 组件研发的对齐规则按三层切分,**任何冲突时三层切分优先于其它细则**:
27
+
28
+ | 维度 | 对齐对象 | 含义 |
29
+ | ---- | -------- | ---- |
30
+ | **能力 / 功能** | **shadcn ∪ antd 的合集** | shadcn 缺什么、antd 有什么,补;反之亦然。**做并集,不做交集** |
31
+ | **设计理念** | **`@teamix-evo/design` 的 OpenTrek 体系** | 视觉 / 间距 / 圆角 / 字号 / 阴影 / 动效 / 交互预期 / AI 生成纪律全部走 design,**不参照 antd 视觉,也不参照 shadcn 视觉** |
32
+ | **代码实现 / 部署 / 规范** | **shadcn** | 文件结构、源码注入分发、cva 范式、forwardRef + Slot、TypeScript 写法、命名风格、registryDependencies 思想全部对齐 shadcn,**不照搬 antd 的运行时主题 / less / 样式封装方式** |
33
+
34
+ 简记:**能力做并集,理念跟 design,工程跟 shadcn**。
35
+
36
+ 研发前必须列对照表(写在 PR 描述或 issue 里):shadcn 提供 → antd 提供 → 本组件实现。
37
+
38
+ ## Consequences
39
+
40
+ - **Positive**:
41
+ - 组件能力面稳定:antd 用户惯用的 `loading` / `icon` / `shape` / `block` / `htmlType` 都有;shadcn 用户惯用的 `asChild` 也有
42
+ - 视觉强一致:所有视觉决策走 design tokens 一处真值
43
+ - 工程一致:cva + forwardRef + 假路径 import 是统一范式
44
+ - **Negative**:
45
+ - 每新增组件都要做并集对照表,前期维护成本上升 ~30%
46
+ - 偶发命名分歧(antd 叫 `htmlType`,shadcn 叫 `type`)需要团队仲裁
47
+ - **Trade-off**:
48
+ - 用"前期对照表的成本" 换 "组件能力 / 视觉 / 工程三维度长期一致性"
49
+ - 用"不照搬 antd 视觉"放弃了 antd 用户的视觉熟悉度,换得 design 体系的统一权威
50
+
51
+ ## Source
52
+
53
+ - [`packages/ui/AGENTS.md`](../../packages/ui/AGENTS.md) §第零条准则
54
+ - [`PLAN.md`](../../PLAN.md) 附录 B 2026-05-15 行
@@ -0,0 +1,50 @@
1
+ # 0002. 包命名方案:`teamix-evo`(unscoped)+ `@teamix-evo/*`(资产)
2
+
3
+ - **Status**: Accepted
4
+ - **Date**: 2026-05-13
5
+ - **Region**: 0001–0099 工程哲学(命名 = 项目 identity,跨 5 年都不变)
6
+ - **Related ADR**: [0011 mcp 单包单 bin 多 group + 改名](0011-mcp-single-package-multi-group.md)(本 ADR 命名规范的具体应用:`registry-mcp` → `mcp`,在未发布前免费窗口期内完成)/ [0014 ui/biz-ui/templates 三层](0014-ui-biz-ui-templates-tier.md)(`@teamix-evo/biz-ui` / `@teamix-evo/templates` 锁名)
7
+
8
+ ## Context
9
+
10
+ teamix-evo 是 monorepo,需要决定:
11
+
12
+ 1. 主命令(用户敲 `npx XXX` 时的那个 XXX)叫什么?
13
+ 2. 内部资产包(design / skills / ui / registry / docs)的 npm 命名空间是什么?
14
+ 3. 是否注册短别名(`tx` / `evo`)?
15
+
16
+ 命名是项目 identity 的一部分,改动成本极高(用户、文档、社区记忆都钉死)。需要在写第一行代码前定下来。
17
+
18
+ ## Options Considered
19
+
20
+ | 选项 | 优点 | 缺点 |
21
+ | ---- | ---- | ---- |
22
+ | A. 全 scoped:`@teamix-evo/cli` + `@teamix-evo/<asset>` | scope 清晰,组织感强 | 与 `npm create xxx` 协议不兼容(`npm create @teamix-evo/cli` 别扭) |
23
+ | **B. 主入口 unscoped + 资产 scoped(本决策)** | 与 npm create 协议天然兼容;主入口短易记 | 需在 npm 注册一个 unscoped 主包 + 一个 scope 组织 |
24
+ | C. 全 unscoped:`teamix-evo` + `teamix-evo-<asset>` | 最简单 | 资产包 squat 风险大;无 scope 隔离 |
25
+ | D. 注册短别名(`tx` / `evo`) | 用户敲得快 | 短名命中重名概率极高;别名维护成本 |
26
+
27
+ ## Decision
28
+
29
+ 采用**方案 B**:
30
+
31
+ - **主入口**: `teamix-evo`(unscoped)
32
+ - **资产**: `@teamix-evo/<name>`(`@teamix-evo/registry` / `@teamix-evo/design` / `@teamix-evo/skills` / `@teamix-evo/ui`)
33
+ - **不注册短命令别名**(不做 `tx` / `evo`)
34
+ - **目录与命令对齐**:仓库根目录 `teamix-evo/`、主命令 `teamix-evo`
35
+
36
+ ## Consequences
37
+
38
+ - **Positive**:
39
+ - `npm create teamix-evo my-app` 与 npm 协议天然对齐,装机一行
40
+ - 资产 scope 清晰,版本独立(`@teamix-evo/registry` 与主入口 linked,其它独立 — 见 ADR 待写 0007 版本策略)
41
+ - 主入口短(`teamix-evo`)易记,不依赖别名
42
+ - **Negative**:
43
+ - 需在 npm 注册组织 `@teamix-evo` + 注册主包 `teamix-evo`(已注册)
44
+ - 主入口与资产 import 风格不一致(`teamix-evo` vs `@teamix-evo/registry`),需文档明示
45
+ - **Trade-off**:
46
+ - 不做短别名 = 用一点点击率换长期 identity 稳定(短别名重名是技术债)
47
+
48
+ ## Source
49
+
50
+ [`PLAN.md`](../../PLAN.md) §1.A / 附录 B 2026-05-13 行
@@ -0,0 +1,62 @@
1
+ # 0003. 资源升级语义:`frozen` / `regenerable` / `managed` 三态
2
+
3
+ - **Status**: Accepted
4
+ - **Date**: 2026-05-13
5
+ - **Region**: 0001–0099 工程哲学(配置驱动 / 用户可预期)
6
+ - **Related ADR**: [0006 UI 升级机制无 baseline](0006-ui-upgrade-no-baseline.md) / [0013 Skills source-mirror 模型](0013-skills-source-mirror.md)(本 ADR 三态语义在 skills 装机层的具象:IDE 镜像即 `regenerable`)
7
+
8
+ ## Context
9
+
10
+ teamix-evo CLI `update` 命令会把上游资产(tokens / DESIGN.md / 组件源码 / skill / 等)同步到业务侧。但:
11
+
12
+ - 业务侧可能已经修改了某些文件(自定义视觉 token、补充设计文档段落、改组件实现);
13
+ - 直接覆盖会丢失业务定制;
14
+ - 完全不覆盖又失去"升级"语义(用户拿不到上游修复 / 新功能)。
15
+
16
+ 需要给每类资产一个明确的"update 时怎么处理"语义,让用户可预期、不被坑。
17
+
18
+ ## Options Considered
19
+
20
+ | 选项 | 缺点 |
21
+ | ---- | ---- |
22
+ | 单一覆盖式 | 用户定制必丢失 |
23
+ | 单一保留式 | 升级语义失效 |
24
+ | 给每个文件做 diff + 三方合并 | 维护复杂、对非代码资源不适用 |
25
+ | **三态语义(本决策)** | 需要为每类资源静态声明语义(可控成本) |
26
+
27
+ ## Decision
28
+
29
+ 资源级 `updateStrategy` 三态:
30
+
31
+ | 状态 | 语义 | 典型例子 |
32
+ | ---- | ---- | -------- |
33
+ | `frozen` | 用户接管,update 跳过 | UI 组件源码、`tokens.overrides.css` |
34
+ | `regenerable` | CLI 完全重写 | 自动派生的 `tokens.theme.css` / `tailwind.preset.ts` / 组件 `meta.md` |
35
+ | `managed` | 仅标记区内重写,标记外保留 | `DESIGN.md` / `AGENTS.md` |
36
+
37
+ `managed` 态使用 HTML 注释标记托管区:
38
+
39
+ ```markdown
40
+ <!-- teamix-evo:managed:start id="foundation" -->
41
+ (CLI 重写区,用户不要编辑)
42
+ <!-- teamix-evo:managed:end -->
43
+ ```
44
+
45
+ 每个资源在 [`@teamix-evo/registry`](../../packages/registry/src/schema/manifest.ts) 的 `ResourceSchema` 中静态声明 `updateStrategy`。
46
+
47
+ ## Consequences
48
+
49
+ - **Positive**:
50
+ - 用户可在 install 时清楚知道每类资源的升级行为
51
+ - 业务定制不丢失(frozen + managed 区外)
52
+ - 上游修复可达(regenerable + managed 区内)
53
+ - **Negative**:
54
+ - `managed` 标记被用户误删时找不到锚点 → CLI 必须报错并提示恢复路径,不静默重写
55
+ - 每条新资源都需要决定 strategy,可能误判
56
+ - **Trade-off**:
57
+ - 用"声明负担"换"用户可预期"。前者一次性,后者长期红利
58
+
59
+ ## Source
60
+
61
+ - [`PLAN.md`](../../PLAN.md) §1.D.D3 / §4.2 / §4.3
62
+ - [`packages/registry/src/schema/manifest.ts`](../../packages/registry/src/schema/manifest.ts)