@lism-css/mcp 0.28.0 → 0.28.1

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.
package/README.ja.md CHANGED
@@ -9,7 +9,7 @@ AIツール(Claude Code, Cursor 等)が、インストールされている
9
9
 
10
10
  | ツール | 説明 |
11
11
  |--------|------|
12
- | `get_overview` | フレームワークの全体像(アーキテクチャ、設計思想、パッケージ構成、ブレークポイント、CSS Layers、実装ルール) |
12
+ | `get_overview` | フレームワークの全体像(基本ルール、何を書く前にどの資料を引くか、目的別のPrimitive/コンポーネント選定、クラス一覧、CSS Layers、ブレークポイント) |
13
13
  | `get_tokens` | デザイントークン(色、余白、フォントサイズ、影、角丸など)のリファレンス全文を取得 |
14
14
  | `get_props_system` | Propsシステム対応表 — React/Astro のpropsがCSSクラス・スタイルにどう変換されるか。CSSプロパティ名での逆引き(例: `padding` → `p`)や Property Class 記法(`-g:5` 等)にも対応 |
15
15
  | `get_component` | コンポーネント詳細(props、使用例、サブコンポーネント構成)。パッケージ(`lism-css` / `@lism-css/ui`)での絞り込みも可能 |
package/README.md CHANGED
@@ -9,7 +9,7 @@ Enables AI tools (Claude Code, Cursor, etc.) to accurately reference Lism CSS do
9
9
 
10
10
  | Tool | Description |
11
11
  |------|-------------|
12
- | `get_overview` | Framework overview (architecture, design philosophy, packages, breakpoints, CSS layers, implementation rules) |
12
+ | `get_overview` | Framework overview (core rules, which reference to look up before writing what, primitive/component selection by goal, class inventory, CSS layers, breakpoints) |
13
13
  | `get_tokens` | Get the full design token reference (colors, spacing, font sizes, shadows, radii, etc.) |
14
14
  | `get_props_system` | Props system reference — how React/Astro props map to CSS classes and styles. Supports reverse lookup by CSS property name (e.g. `padding` → `p`) and Property Class notation (e.g. `-g:5`) |
15
15
  | `get_component` | Component details (props, usage examples, sub-component structure). Optionally filter by package (`lism-css` or `@lism-css/ui`) |
@@ -1,6 +1,6 @@
1
1
  # ページ定番セクションの構成例
2
2
 
3
- ヒーロー・サイトヘッダー・フッターなど、ページの定番セクションを`Group`/`Wrapper`/`Stack`+Propsで組む時の出発点です。ここにある構成をベースにし、実際の値は値・トークン照合(C5)を通してから確定します。
3
+ ヒーロー・サイトヘッダー・フッターなど、ページの定番セクションを`Group`/`Wrapper`/`Stack`+Propsで組む時の出発点です。ここにある構成をベースにし、実際の値は`tokens.md`のトークンと照合してから確定します。
4
4
 
5
5
  共通の考え方:
6
6
 
@@ -94,6 +94,6 @@ import { Group, Wrapper, Stack, Heading, Columns } from 'lism-css/astro';
94
94
 
95
95
  ## 使う前の確認
96
96
 
97
- - 使うPrimitive/Traitの詳細ファイル(`primitives/l--*.md`・`trait-class/*.md`)を、`SKILL.md`の資料確認トリガーに従って読む。
97
+ - 使うPrimitive/Traitの詳細ファイル(`primitives/*.md`・`trait-class/*.md`)で、既定のスタイル・Props・CSS変数を確認する。
98
98
  - レスポンシブ値(配列・オブジェクト指定)を使う場合は、祖先の`isContainer`または`@media`運用の確認が必要([`responsive.md`](../responsive.md))。
99
- - ここに書いた値はすべて例。実際のデザイン値は`tokens.md`との照合(C5)とトークン差分表を通す。
99
+ - ここに書いた値はすべて例。実際のデザイン値を`tokens.md`と照合し、使うトークンを決める。
@@ -1,5 +1,7 @@
1
1
  /** 指定見出しから同レベル以上の次の見出しまでを抽出する。headingは#の有無を問わない。 */
2
2
  export declare function extractSection(md: string, heading: string): string;
3
+ /** 冒頭(frontmatter を除き、最初の `##` 見出しの手前まで)を返す。H1 は含む。 */
4
+ export declare function extractPreamble(md: string): string;
3
5
  export declare function listHeadings(md: string): {
4
6
  level: number;
5
7
  text: string;
@@ -28,6 +28,13 @@ export function extractSection(md, heading) {
28
28
  }
29
29
  return lines.slice(startIdx, endIdx).join('\n').trimEnd();
30
30
  }
31
+ /** 冒頭(frontmatter を除き、最初の `##` 見出しの手前まで)を返す。H1 は含む。 */
32
+ export function extractPreamble(md) {
33
+ const body = md.replace(/^---\n[\s\S]*?\n---\n/, '');
34
+ const lines = body.split('\n');
35
+ const endIdx = lines.findIndex((line) => headingLevel(line) >= 2);
36
+ return (endIdx === -1 ? lines : lines.slice(0, endIdx)).join('\n').trim();
37
+ }
31
38
  export function listHeadings(md) {
32
39
  return md.split('\n').flatMap((line, i) => {
33
40
  const lv = headingLevel(line);
@@ -97,6 +97,9 @@ function getBasename(withoutExt) {
97
97
  function getNextTool(entry, guideTopics) {
98
98
  const withoutExt = entry.sourcePath.replace(/\.mdx$/, '');
99
99
  const basename = getBasename(withoutExt);
100
+ if (withoutExt === 'overview') {
101
+ return 'get_overview()';
102
+ }
100
103
  if (withoutExt === 'core-components/lism-props') {
101
104
  return 'get_props_system()';
102
105
  }
@@ -124,7 +124,8 @@ function detectComponent(declarations) {
124
124
  const display = propMap.get('display');
125
125
  const flexDirection = propMap.get('flex-direction');
126
126
  const placeItems = propMap.get('place-items');
127
- if (display === 'flex' && (flexDirection === 'column' || flexDirection === 'column-reverse')) {
127
+ // column-reverse Stack にせず、Flex + fxd で方向を保つ。
128
+ if (display === 'flex' && flexDirection === 'column') {
128
129
  return {
129
130
  name: 'Stack',
130
131
  reason: 'display: flex + flex-direction: column → Stack (vertical flex)',
@@ -161,20 +162,25 @@ function findCategory(mappings, propName) {
161
162
  const found = mappings.find((m) => m.prop === propName);
162
163
  return found?.sectionName ?? 'unknown';
163
164
  }
165
+ /** `property: value` を比較用に正規化する。 */
166
+ function normalizeDeclaration(css) {
167
+ const [prop, ...rest] = css.split(':');
168
+ return `${prop.trim().toLowerCase()}: ${rest.join(':').trim().toLowerCase()}`;
169
+ }
164
170
  /** 変換結果からJSX使用例を組み立てる。 */
165
171
  function buildExample(conversions, component) {
166
172
  const tagName = component?.name ?? 'Lism';
167
- const implicitCssSet = new Set(component?.implicitCss.map((c) => c.split(':')[0].trim()) ?? []);
173
+ // プロパティ名だけで照合すると値違い(例: flex-direction: column-reverse)まで落ちるため、値込みで照合する。
174
+ const implicitCssSet = new Set(component?.implicitCss.map(normalizeDeclaration) ?? []);
168
175
  const props = [];
169
176
  const styles = [];
170
177
  for (const conv of conversions) {
171
- const cssProp = conv.css.split(':')[0].trim();
172
178
  if (!conv.lismProp) {
173
179
  styles.push(conv.css);
174
180
  continue;
175
181
  }
176
182
  // コンポーネントが暗黙に持つCSSは重複出力しない。
177
- if (implicitCssSet.has(cssProp))
183
+ if (implicitCssSet.has(normalizeDeclaration(conv.css)))
178
184
  continue;
179
185
  if (conv.suggestedValue != null) {
180
186
  props.push(`${conv.lismProp}='${conv.suggestedValue}'`);
@@ -9,7 +9,7 @@ function normalizeComponentKey(input) {
9
9
  .trim()
10
10
  .toLowerCase()
11
11
  .replace(/^<|>$/g, '')
12
- .replace(/^(l--|is--|a--|c--)/, '');
12
+ .replace(/^(l--|is--|has--|a--|c--)/, '');
13
13
  }
14
14
  /** 入力が `<ComponentName>` 形式(React コンポーネントとしての問い合わせ)か判定する */
15
15
  function isAngleBracketNotation(input) {
@@ -18,7 +18,7 @@ function isAngleBracketNotation(input) {
18
18
  /** primitives/*.md の先頭行 `# l--flex / \`<Flex>\`` からクラス名とコンポーネント名を抽出する */
19
19
  function parsePrimitiveHeading(md) {
20
20
  const firstLine = md.split('\n', 1)[0] ?? '';
21
- const match = firstLine.match(/^#\s+((?:l|is|a|c)--[A-Za-z0-9]+)(?:\s*\/\s*`<([A-Za-z0-9]+)>`)?/);
21
+ const match = firstLine.match(/^#\s+((?:l|is|has|a|c)--[A-Za-z0-9]+)(?:\s*\/\s*`<([A-Za-z0-9]+)>`)?/);
22
22
  if (!match)
23
23
  return null;
24
24
  return { className: match[1], componentName: match[2] };
@@ -63,7 +63,7 @@ export function registerGetComponent(server) {
63
63
  'Accepts multiple notations: "Flex", "<Flex>", "l--flex", "flex" all resolve to the same entry.\n' +
64
64
  'Do NOT use this for broad topic guides (use get_guide with "components-core" or "components-ui") or keyword search across all docs (use search_docs).\n' +
65
65
  'If the component is not found, suggestions will be provided — follow up with search_docs for a broader query.\n' +
66
- 'The response is pre-formatted Markdown. Output it verbatim. Do NOT summarize or omit code examples.',
66
+ 'The response is Markdown reference material. Use it as context; when you write code, follow the code examples and class names exactly as documented rather than inventing variants.',
67
67
  inputSchema: {
68
68
  name: z.string().describe('Component name to look up (e.g. "Box", "Flex", "Accordion", "l--flex", "<Flex>").'),
69
69
  package: z
@@ -4,7 +4,6 @@ import { markdownResponse, loadFailureError, READ_ONLY_ANNOTATIONS } from '../li
4
4
  // files に複数指定したトピックは結合して返す。
5
5
  // MCP クライアントは Markdown 内の相対リンクを辿れないため、分冊ファイルは本体に結合する。
6
6
  const GUIDE_TOPICS = {
7
- overview: { files: ['SKILL.md'], label: 'Framework overview, packages, implementation rules' },
8
7
  tokens: { files: ['tokens.md'], label: 'Design tokens (spacing, colors, font sizes, etc.)' },
9
8
  'property-class': {
10
9
  files: ['property-class.md', 'property-class/all-props.md', 'property-class/bd.md', 'property-class/hov.md', 'property-class/max-sz.md'],
@@ -47,6 +46,10 @@ const GUIDE_TOPICS = {
47
46
  files: ['antipatterns-layout.md'],
48
47
  label: 'AI code-generation antipatterns (structure / layout / responsive): layout choice errors, responsive omissions, is-- misuse, naming mistakes',
49
48
  },
49
+ 'page-sections': {
50
+ files: ['references/page-sections.md'],
51
+ label: 'Standard page section patterns (hero, site header, footer, etc.) built from Group + Wrapper / Stack / Cluster',
52
+ },
50
53
  };
51
54
  /** get_guide が受理するトピックキーの集合。search.ts の nextTool 判定で利用する。 */
52
55
  export const GUIDE_TOPIC_KEYS = new Set(Object.keys(GUIDE_TOPICS));
@@ -56,8 +59,8 @@ const TOPIC_DESCRIPTION = Object.entries(GUIDE_TOPICS)
56
59
  export function registerGetGuide(server) {
57
60
  server.registerTool('get_guide', {
58
61
  description: 'Get a detailed guide on a specific lism-css topic. Use this when you need comprehensive documentation on a broad topic rather than a specific component or prop.\n' +
59
- 'For individual component lookup, get_component is more direct. For individual prop lookup, use get_props_system.\n' +
60
- 'The response is the full guide as pre-formatted Markdown. Output it verbatim. Do NOT summarize or omit sections.\n' +
62
+ 'For the framework overview, use get_overview. For individual component lookup, get_component is more direct. For individual prop lookup, use get_props_system.\n' +
63
+ 'The response is the full guide as Markdown reference material. Use it as context; apply its rules and examples exactly as documented rather than paraphrasing them from memory.\n' +
61
64
  `\nAvailable topics:\n${TOPIC_DESCRIPTION}`,
62
65
  inputSchema: {
63
66
  topic: z.enum(Object.keys(GUIDE_TOPICS)).describe('The guide topic to retrieve.'),
@@ -1,33 +1,53 @@
1
1
  import { loadMarkdown } from '../lib/load-markdown.js';
2
- import { extractSection } from '../lib/markdown-utils.js';
2
+ import { extractPreamble, extractSection } from '../lib/markdown-utils.js';
3
3
  import { markdownResponse, loadFailureError, READ_ONLY_ANNOTATIONS } from '../lib/response.js';
4
4
  /**
5
- * SKILL.md を中核に、css-rules.md Layer 構造セクションと
6
- * responsive.md のブレイクポイントセクションを付加して返す。
5
+ * SKILL.md から MCP でも意味を持つ節だけを抜き出す。
6
+ * 実装フロー・判定記号・C0–C8・実行レベル・提出前セルフチェックはスキル(ファイル参照と `.lism/` 保存)前提の作業手順なので含めない。
7
7
  */
8
+ const SKILL_SECTIONS = ['最小ゲート', '資料確認トリガー', '目的別実装ガイド', 'クラス単位の詳細リファレンス'];
9
+ /** 抜き出した節に残るガイドファイル名・判定記号を MCP ツールへ読み替えるための案内。 */
10
+ const TOOL_ROUTING = `## Looking up details with this MCP server
11
+
12
+ Guide file names mentioned below map to tools as follows:
13
+
14
+ - \`primitives/*.md\`, \`trait-class/*.md\` → \`get_component\` with the class or component name (e.g. "l--stack", "Stack", "a--icon", "is--container", "has--transition")
15
+ - \`tokens.md\` → \`get_tokens\`
16
+ - \`property-class.md\`, \`property-class/*.md\` → \`get_props_system\` for a single prop, or \`get_guide\` topic "property-class" for the whole system
17
+ - \`references/page-sections.md\` → \`get_guide\` topic "page-sections"
18
+ - Any other \`*.md\` → \`get_guide\` with the topic of the same name (e.g. \`css-rules.md\` → "css-rules", \`antipatterns.md\` → "antipatterns")
19
+ - Keyword search across all docs → \`search_docs\`; bulk CSS-to-Lism conversion → \`convert_css\`
20
+
21
+ Markers used in the rules below: 🔁 = look up the referenced guide before writing that code; ⏸ = confirm with the user before implementing (hardcoded px values, rounding to a nearby token, changing public classes, etc.). Do not write code while a decision is still 🔁. A hardcoded value is allowed as a documented exception (✅例外) only when the "直書きしてよい例外" section of \`antipatterns.md\` (\`get_guide\` topic "antipatterns") lists that case; user instructions such as "reproduce it exactly" do not count.`;
8
22
  function buildOverviewMarkdown() {
9
23
  const skill = loadMarkdown('SKILL.md');
10
24
  const cssRules = loadMarkdown('css-rules.md');
11
25
  const responsive = loadMarkdown('responsive.md');
26
+ // 冒頭(タイトル・公式ドキュメント URL・対象バージョン)。
27
+ // スキルの作業手順(実行レベル判定→セルフチェック)の一文は落とし、スキル更新の案内は MCP 向けに読み替える。
28
+ const preamble = extractPreamble(skill)
29
+ .replace(/変更規模から実行レベルを判定し、[^。]*。/, '')
30
+ .replace('このスキルの更新', '`@lism-css/mcp`の更新');
31
+ const parts = [preamble, TOOL_ROUTING];
32
+ for (const heading of SKILL_SECTIONS) {
33
+ const section = extractSection(skill, heading);
34
+ if (section)
35
+ parts.push(section);
36
+ }
12
37
  const layerSection = extractSection(cssRules, 'CSS Layer 構造');
13
- const bpSection = extractSection(responsive, 'ブレイクポイント');
14
- const parts = [skill];
15
- if (layerSection) {
16
- parts.push('\n---\n');
38
+ if (layerSection)
17
39
  parts.push(layerSection);
18
- }
19
- if (bpSection) {
20
- parts.push('\n---\n');
40
+ const bpSection = extractSection(responsive, 'ブレイクポイント');
41
+ if (bpSection)
21
42
  parts.push(bpSection);
22
- }
23
- return parts.join('\n');
43
+ return parts.join('\n\n---\n\n');
24
44
  }
25
45
  export function registerGetOverview(server) {
26
46
  server.registerTool('get_overview', {
27
- description: 'Get an overview of the lism-css framework: architecture, design philosophy, packages, breakpoints, CSS layers, and implementation rules.\n' +
47
+ description: 'Get an overview of the lism-css framework: core rules (minimum gates), which reference to look up before writing what, primitive/component selection by goal, class inventory, CSS layers, and breakpoints.\n' +
28
48
  'Use this as your FIRST call when starting any lism-css task — it provides the foundational context needed to use other tools effectively.\n' +
29
49
  'Do NOT use this to look up specific components (use get_component), individual props (use get_props_system), or design tokens (use get_tokens).\n' +
30
- 'The response is pre-formatted Markdown. Output it verbatim to the user. Do NOT summarize or omit sections.',
50
+ 'The response is Markdown reference material. Use it as context for your answer or implementation; do not paraphrase rules or invent class names, props, or token values that are not in it.',
31
51
  annotations: READ_ONLY_ANNOTATIONS,
32
52
  }, () => {
33
53
  try {
@@ -16,7 +16,7 @@ export function registerGetPropsSystem(server) {
16
16
  description: 'Get the lism-css Props system reference: how React/Astro props map to CSS classes and styles. Supports lookup by lism prop name (e.g. "p", "fz") OR by CSS property name (e.g. "padding", "font-size"). Omit the prop parameter to get the full reference.\n' +
17
17
  'Use this when you need to find a specific prop mapping, understand the Property Class system, or check what CSS property a lism prop corresponds to.\n' +
18
18
  'For bulk CSS-to-lism conversion, convert_css is more efficient. For component-specific documentation, use get_component.\n' +
19
- 'The response is pre-formatted Markdown. Output it verbatim. Do NOT summarize the prop tables.',
19
+ 'The response is Markdown reference material. Use prop names and preset values exactly as listed in the tables; do not invent props or values that are not there.',
20
20
  inputSchema: {
21
21
  prop: z
22
22
  .string()
@@ -5,7 +5,7 @@ export function registerGetTokens(server) {
5
5
  description: 'Get design tokens (colors, spacing, font sizes, shadows, etc.) used in lism-css. Returns the full token reference including CSS variable names and available values.\n' +
6
6
  'Use this when you need to check available token values, variable names, or design scales (e.g. "what spacing values exist?", "what are the font size tokens?").\n' +
7
7
  'For prop-to-CSS mappings, get_props_system is more suitable. For CSS conversion, use convert_css. Call get_overview first if you have not yet.\n' +
8
- 'The response is pre-formatted Markdown. Output it verbatim. Do NOT summarize or omit token values.',
8
+ 'The response is Markdown reference material. Use token names and values exactly as listed; do not invent tokens or values that are not there.',
9
9
  annotations: READ_ONLY_ANNOTATIONS,
10
10
  }, () => {
11
11
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lism-css/mcp",
3
- "version": "0.28.0",
3
+ "version": "0.28.1",
4
4
  "description": "MCP server for lism-css documentation and API reference.",
5
5
  "keywords": [
6
6
  "mcp",