@oneentry/mcp-server 1.0.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.
- package/README.md +143 -0
- package/dist/content.d.ts +11 -0
- package/dist/content.js +34 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +136 -0
- package/dist/registry.d.ts +15 -0
- package/dist/registry.js +157 -0
- package/package.json +30 -0
- package/src/content.ts +48 -0
- package/src/index.ts +166 -0
- package/src/registry.ts +173 -0
- package/tsconfig.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# OneEntry MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server for OneEntry SDK — serves rules and skills to Claude Code automatically from a remote server.
|
|
4
|
+
|
|
5
|
+
Users don't need to copy any files. Connect once — always get the latest rules.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
| MCP concept | What it serves |
|
|
10
|
+
|-------------|----------------|
|
|
11
|
+
| **Resources** | Rules (`oneentry://rules/*`) + `CLAUDE.md` — readable context documents |
|
|
12
|
+
| **Prompts** | Skills (`create-page`, `inspect-api`, etc.) — invocable by the user |
|
|
13
|
+
|
|
14
|
+
Content is fetched from GitHub (configurable) and cached for 5 minutes.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Quick start for users
|
|
19
|
+
|
|
20
|
+
### Option 1 — npx (no install needed)
|
|
21
|
+
|
|
22
|
+
Add to `~/.claude/claude_desktop_config.json` or `.mcp.json` in your project:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"oneentry": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "@oneentry/mcp-server"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Option 2 — global install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g @oneentry/mcp-server
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"oneentry": {
|
|
45
|
+
"command": "oneentry-mcp"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Available resources
|
|
54
|
+
|
|
55
|
+
Read them in Claude Code by typing `@oneentry://rules/<name>`:
|
|
56
|
+
|
|
57
|
+
| URI | Description |
|
|
58
|
+
|-----|-------------|
|
|
59
|
+
| `oneentry://claude-md` | Full CLAUDE.md — main SDK instructions |
|
|
60
|
+
| `oneentry://rules/forms` | Forms & FormsData rules |
|
|
61
|
+
| `oneentry://rules/tokens` | Tokens & makeUserApi rules |
|
|
62
|
+
| `oneentry://rules/attribute-values` | attributeValues access by type |
|
|
63
|
+
| `oneentry://rules/auth-provider` | AuthProvider — auth/signUp rules |
|
|
64
|
+
| `oneentry://rules/nextjs-pages` | Next.js pages, params as Promise |
|
|
65
|
+
| `oneentry://rules/server-actions` | Server Actions rules |
|
|
66
|
+
| `oneentry://rules/orders` | Orders & Payments rules |
|
|
67
|
+
| `oneentry://rules/attribute-sets` | AttributeSets — schema vs values |
|
|
68
|
+
| `oneentry://rules/localization` | Localization, locale from params |
|
|
69
|
+
|
|
70
|
+
## Available prompts (skills)
|
|
71
|
+
|
|
72
|
+
Invoke in Claude Code with `/skill-name`:
|
|
73
|
+
|
|
74
|
+
| Prompt | Description |
|
|
75
|
+
|--------|-------------|
|
|
76
|
+
| `oneentry-context` | Load full SDK context at session start |
|
|
77
|
+
| `setup-oneentry` | Initialize SDK in a Next.js project |
|
|
78
|
+
| `create-page` | Create Next.js page with CMS content |
|
|
79
|
+
| `inspect-api` | Inspect real API markers and structure |
|
|
80
|
+
| `create-auth` | Auth/registration form |
|
|
81
|
+
| `create-product-list` | Product catalog with filters and pagination |
|
|
82
|
+
| `create-product-card` | Single product page |
|
|
83
|
+
| `create-cart-manager` | Cart — Redux + persist |
|
|
84
|
+
| `create-favorites` | Favorites — Redux + persist |
|
|
85
|
+
| `create-filter-panel` | Filter panel with FilterContext |
|
|
86
|
+
| `create-checkout` | Checkout form + payment |
|
|
87
|
+
| `create-orders-list` | User orders list |
|
|
88
|
+
| `create-profile` | User profile page |
|
|
89
|
+
| `create-form` | Dynamic form from Forms API |
|
|
90
|
+
| `create-reviews` | Reviews with hierarchy |
|
|
91
|
+
| `create-menu` | Navigation menu with submenus |
|
|
92
|
+
| `create-search` | Search bar with debounce |
|
|
93
|
+
| `create-locale-switcher` | Locale switcher |
|
|
94
|
+
| `create-server-action` | Next.js Server Action |
|
|
95
|
+
| `create-subscription-events` | Price/availability subscription |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## For OneEntry team — updating content
|
|
100
|
+
|
|
101
|
+
Rules and skills are fetched from the GitHub repo configured in `ONEENTRY_MCP_BASE_URL`.
|
|
102
|
+
|
|
103
|
+
**Default URL:**
|
|
104
|
+
```
|
|
105
|
+
https://raw.githubusercontent.com/ONEENTRY-PLATFORM/oneentry-sdk-rules/main
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Update rules in the repo — all users get the changes automatically within 5 minutes (cache TTL).
|
|
109
|
+
|
|
110
|
+
**To point to a custom repo:**
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"oneentry": {
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["-y", "@oneentry/mcp-server"],
|
|
117
|
+
"env": {
|
|
118
|
+
"ONEENTRY_MCP_BASE_URL": "https://raw.githubusercontent.com/your-org/your-repo/main"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Local development
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd mcp-server
|
|
131
|
+
npm install
|
|
132
|
+
npm run dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
To point at local files during development:
|
|
136
|
+
```bash
|
|
137
|
+
ONEENTRY_MCP_BASE_URL=file:///Users/you/claude-next npm run dev
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Build for production:
|
|
141
|
+
```bash
|
|
142
|
+
npm run build
|
|
143
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches content from a remote URL (GitHub raw or any HTTP server).
|
|
3
|
+
* Caches results for TTL_MS to avoid hammering the server.
|
|
4
|
+
*
|
|
5
|
+
* Configure the base URL via env var:
|
|
6
|
+
* ONEENTRY_MCP_BASE_URL=https://raw.githubusercontent.com/your-org/your-repo/main
|
|
7
|
+
*
|
|
8
|
+
* Default points to the oneentry public repo.
|
|
9
|
+
*/
|
|
10
|
+
export declare function fetchContent(path: string): Promise<string>;
|
|
11
|
+
export declare function clearCache(): void;
|
package/dist/content.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches content from a remote URL (GitHub raw or any HTTP server).
|
|
3
|
+
* Caches results for TTL_MS to avoid hammering the server.
|
|
4
|
+
*
|
|
5
|
+
* Configure the base URL via env var:
|
|
6
|
+
* ONEENTRY_MCP_BASE_URL=https://raw.githubusercontent.com/your-org/your-repo/main
|
|
7
|
+
*
|
|
8
|
+
* Default points to the oneentry public repo.
|
|
9
|
+
*/
|
|
10
|
+
const BASE_URL = process.env.ONEENTRY_MCP_BASE_URL ??
|
|
11
|
+
"https://raw.githubusercontent.com/ONEENTRY-PLATFORM/oneentry-sdk-rules/main";
|
|
12
|
+
const TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
13
|
+
const cache = new Map();
|
|
14
|
+
export async function fetchContent(path) {
|
|
15
|
+
const cached = cache.get(path);
|
|
16
|
+
if (cached && cached.expires > Date.now()) {
|
|
17
|
+
return cached.text;
|
|
18
|
+
}
|
|
19
|
+
const url = `${BASE_URL}/${path}`;
|
|
20
|
+
const res = await fetch(url, {
|
|
21
|
+
headers: {
|
|
22
|
+
"User-Agent": "oneentry-mcp-server/1.0",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch content (${res.status}): ${url}`);
|
|
27
|
+
}
|
|
28
|
+
const text = await res.text();
|
|
29
|
+
cache.set(path, { text, expires: Date.now() + TTL_MS });
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
export function clearCache() {
|
|
33
|
+
cache.clear();
|
|
34
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { fetchContent } from "./content.js";
|
|
6
|
+
import { RULES, SKILLS } from "./registry.js";
|
|
7
|
+
const CLAUDE_MD_PATH = "CLAUDE.md";
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Server
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
const server = new Server({ name: "oneentry-sdk", version: "1.0.0" }, {
|
|
12
|
+
capabilities: {
|
|
13
|
+
resources: {},
|
|
14
|
+
prompts: {},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Resources — rules + CLAUDE.md
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
21
|
+
resources: [
|
|
22
|
+
{
|
|
23
|
+
uri: "oneentry://claude-md",
|
|
24
|
+
name: "OneEntry SDK — Main Instructions (CLAUDE.md)",
|
|
25
|
+
description: "Full system prompt with OneEntry SDK rules, patterns, anti-hallucination guidelines and module reference",
|
|
26
|
+
mimeType: "text/markdown",
|
|
27
|
+
},
|
|
28
|
+
...RULES.map((rule) => ({
|
|
29
|
+
uri: `oneentry://rules/${rule.name}`,
|
|
30
|
+
name: rule.displayName,
|
|
31
|
+
description: rule.description,
|
|
32
|
+
mimeType: "text/markdown",
|
|
33
|
+
})),
|
|
34
|
+
],
|
|
35
|
+
}));
|
|
36
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
37
|
+
const { uri } = request.params;
|
|
38
|
+
// CLAUDE.md
|
|
39
|
+
if (uri === "oneentry://claude-md") {
|
|
40
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
41
|
+
return { contents: [{ uri, mimeType: "text/markdown", text }] };
|
|
42
|
+
}
|
|
43
|
+
// Rules
|
|
44
|
+
if (uri.startsWith("oneentry://rules/")) {
|
|
45
|
+
const name = uri.replace("oneentry://rules/", "");
|
|
46
|
+
const rule = RULES.find((r) => r.name === name);
|
|
47
|
+
if (!rule) {
|
|
48
|
+
throw new Error(`Unknown rule: ${name}`);
|
|
49
|
+
}
|
|
50
|
+
const text = await fetchContent(rule.path);
|
|
51
|
+
return { contents: [{ uri, mimeType: "text/markdown", text }] };
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
54
|
+
});
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Prompts — skills
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
59
|
+
prompts: [
|
|
60
|
+
// Special prompt: load full context from CLAUDE.md
|
|
61
|
+
{
|
|
62
|
+
name: "oneentry-context",
|
|
63
|
+
description: "Load full OneEntry SDK context — system instructions, rules and anti-hallucination guidelines. Use this at the start of a session.",
|
|
64
|
+
arguments: [],
|
|
65
|
+
},
|
|
66
|
+
// All skills
|
|
67
|
+
...SKILLS.map((skill) => ({
|
|
68
|
+
name: skill.name,
|
|
69
|
+
description: skill.description,
|
|
70
|
+
arguments: skill.hasArguments
|
|
71
|
+
? [
|
|
72
|
+
{
|
|
73
|
+
name: "arguments",
|
|
74
|
+
description: skill.argumentDescription ?? "Optional arguments",
|
|
75
|
+
required: false,
|
|
76
|
+
},
|
|
77
|
+
]
|
|
78
|
+
: [],
|
|
79
|
+
})),
|
|
80
|
+
],
|
|
81
|
+
}));
|
|
82
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
83
|
+
const { name, arguments: args } = request.params;
|
|
84
|
+
// Load full CLAUDE.md as system context
|
|
85
|
+
if (name === "oneentry-context") {
|
|
86
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
87
|
+
return {
|
|
88
|
+
description: "OneEntry SDK — full system context loaded",
|
|
89
|
+
messages: [
|
|
90
|
+
{
|
|
91
|
+
role: "user",
|
|
92
|
+
content: {
|
|
93
|
+
type: "text",
|
|
94
|
+
text: `The following are the complete instructions and rules for working with OneEntry SDK. Apply them to all subsequent code generation:\n\n${text}`,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// Skills
|
|
101
|
+
const skill = SKILLS.find((s) => s.name === name);
|
|
102
|
+
if (!skill) {
|
|
103
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
104
|
+
}
|
|
105
|
+
let text = await fetchContent(skill.path);
|
|
106
|
+
// Replace $ARGUMENTS placeholder (used in inspect-api and create-page skills)
|
|
107
|
+
const userArguments = args?.["arguments"];
|
|
108
|
+
if (userArguments) {
|
|
109
|
+
text = text.replace(/\$ARGUMENTS/g, userArguments);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
description: skill.description,
|
|
113
|
+
messages: [
|
|
114
|
+
{
|
|
115
|
+
role: "user",
|
|
116
|
+
content: {
|
|
117
|
+
type: "text",
|
|
118
|
+
text,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Start
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
async function main() {
|
|
128
|
+
const transport = new StdioServerTransport();
|
|
129
|
+
await server.connect(transport);
|
|
130
|
+
// Log to stderr so it doesn't interfere with MCP stdio protocol
|
|
131
|
+
process.stderr.write("OneEntry MCP server running\n");
|
|
132
|
+
}
|
|
133
|
+
main().catch((err) => {
|
|
134
|
+
process.stderr.write(`Fatal error: ${err}\n`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Rule {
|
|
2
|
+
name: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
description: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Skill {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
path: string;
|
|
11
|
+
hasArguments?: boolean;
|
|
12
|
+
argumentDescription?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const RULES: Rule[];
|
|
15
|
+
export declare const SKILLS: Skill[];
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
export const RULES = [
|
|
2
|
+
{
|
|
3
|
+
name: "forms",
|
|
4
|
+
displayName: "Forms & FormsData",
|
|
5
|
+
description: "Rules for working with OneEntry Forms API — getFormByMarker, postFormsData, formData types by field type",
|
|
6
|
+
path: ".claude/rules/forms.md",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: "tokens",
|
|
10
|
+
displayName: "Tokens & Auth",
|
|
11
|
+
description: "Rules for auth tokens — makeUserApi, refreshToken, race condition handling, getNewToken",
|
|
12
|
+
path: ".claude/rules/tokens.md",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "attribute-values",
|
|
16
|
+
displayName: "AttributeValues",
|
|
17
|
+
description: "How to access attributeValues by type — image, text, list, date, timeInterval, etc.",
|
|
18
|
+
path: ".claude/rules/attribute-values.md",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "auth-provider",
|
|
22
|
+
displayName: "AuthProvider",
|
|
23
|
+
description: "Rules for auth/signUp — IAuthPostBody structure, notificationData, server actions",
|
|
24
|
+
path: ".claude/rules/auth-provider.md",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "nextjs-pages",
|
|
28
|
+
displayName: "Next.js Pages",
|
|
29
|
+
description: "Rules for Next.js pages with OneEntry — params as Promise, pageUrl vs route, localizeInfos",
|
|
30
|
+
path: ".claude/rules/nextjs-pages.md",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "server-actions",
|
|
34
|
+
displayName: "Server Actions",
|
|
35
|
+
description: "Rules for Next.js Server Actions with OneEntry — getApi() vs makeUserApi(), which methods need SA",
|
|
36
|
+
path: ".claude/rules/server-actions.md",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "orders",
|
|
40
|
+
displayName: "Orders & Payments",
|
|
41
|
+
description: "Rules for Orders and Payments — getAllOrdersStorage structure, createOrder, createSession, paymentUrl",
|
|
42
|
+
path: ".claude/rules/orders.md",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "attribute-sets",
|
|
46
|
+
displayName: "AttributeSets",
|
|
47
|
+
description: "Rules for AttributesSets — schema vs values, listTitles, additionalFields, validators",
|
|
48
|
+
path: ".claude/rules/attribute-sets.md",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "localization",
|
|
52
|
+
displayName: "Localization",
|
|
53
|
+
description: "Rules for localization — locale from params, langCode, localizeInfos, useParams in client components",
|
|
54
|
+
path: ".claude/rules/localization.md",
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
export const SKILLS = [
|
|
58
|
+
{
|
|
59
|
+
name: "setup-oneentry",
|
|
60
|
+
description: "Initialize OneEntry SDK in a Next.js project — creates lib/oneentry.ts with singleton pattern, configures next.config.ts for images",
|
|
61
|
+
path: ".claude/skills/setup-oneentry/SKILL.md",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "create-page",
|
|
65
|
+
description: "Create a Next.js page with content from OneEntry CMS — getPageByUrl, getBlocksByPageUrl, localizeInfos",
|
|
66
|
+
path: ".claude/skills/create-page/SKILL.md",
|
|
67
|
+
hasArguments: true,
|
|
68
|
+
argumentDescription: "pageMarker — the pageUrl marker in OneEntry (e.g. 'home', 'about')",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "inspect-api",
|
|
72
|
+
description: "Read .env.local and execute curl requests to OneEntry API to get real markers, attributes and data structures before writing code",
|
|
73
|
+
path: ".claude/skills/inspect-api/SKILL.md",
|
|
74
|
+
hasArguments: true,
|
|
75
|
+
argumentDescription: "pages|menus|forms|products|product-statuses|auth-providers|all",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "create-auth",
|
|
79
|
+
description: "Create auth/registration form with OneEntry AuthProvider — Server Actions, dynamic fields from Forms API, token sync",
|
|
80
|
+
path: ".claude/skills/create-auth/SKILL.md",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "create-product-list",
|
|
84
|
+
description: "Create product catalog with URL-based filters, infinite scroll, Server Actions, FilterPanel and ProductGrid",
|
|
85
|
+
path: ".claude/skills/create-product-list/SKILL.md",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "create-product-card",
|
|
89
|
+
description: "Create a single product page with getProductById, attribute extraction, image gallery, price block, related products",
|
|
90
|
+
path: ".claude/skills/create-product-card/SKILL.md",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "create-cart-manager",
|
|
94
|
+
description: "Create cart manager — Redux slice + redux-persist, add/remove/quantity, StoreProvider",
|
|
95
|
+
path: ".claude/skills/create-cart-manager/SKILL.md",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "create-favorites",
|
|
99
|
+
description: "Create favorites list — Redux slice + persist, stores only product IDs, button and page with API data loading",
|
|
100
|
+
path: ".claude/skills/create-favorites/SKILL.md",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "create-filter-panel",
|
|
104
|
+
description: "Create filter panel — price, color, availability + FilterContext + Apply/Reset buttons",
|
|
105
|
+
path: ".claude/skills/create-filter-panel/SKILL.md",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "create-checkout",
|
|
109
|
+
description: "Create checkout form — fields from Forms API, timeInterval delivery slots, one makeUserApi for createOrder + createSession, redirect to payment",
|
|
110
|
+
path: ".claude/skills/create-checkout/SKILL.md",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "create-orders-list",
|
|
114
|
+
description: "Create user orders list — load via all storages, one makeUserApi, client pagination, token race condition protection",
|
|
115
|
+
path: ".claude/skills/create-orders-list/SKILL.md",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "create-profile",
|
|
119
|
+
description: "Create user profile page — Users API fields, data update, token race condition handling",
|
|
120
|
+
path: ".claude/skills/create-profile/SKILL.md",
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "create-form",
|
|
124
|
+
description: "Create dynamic form with fields from OneEntry Forms API — all field types including spam (reCAPTCHA)",
|
|
125
|
+
path: ".claude/skills/create-form/SKILL.md",
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "create-reviews",
|
|
129
|
+
description: "Create reviews with hierarchy — FormData, isNested, entityIdentifier, replayTo",
|
|
130
|
+
path: ".claude/skills/create-reviews/SKILL.md",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "create-menu",
|
|
134
|
+
description: "Create navigation menu with submenu support — hierarchy via parentId, URL normalization",
|
|
135
|
+
path: ".claude/skills/create-menu/SKILL.md",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "create-search",
|
|
139
|
+
description: "Create search bar — 300ms debounce, Server Action, dropdown results",
|
|
140
|
+
path: ".claude/skills/create-search/SKILL.md",
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: "create-locale-switcher",
|
|
144
|
+
description: "Create locale switcher — loads locales via getLocales(), builds links to current page with different locale segment",
|
|
145
|
+
path: ".claude/skills/create-locale-switcher/SKILL.md",
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "create-server-action",
|
|
149
|
+
description: "Create Next.js Server Action for OneEntry — getApi() for public methods, makeUserApi() for user-authorized methods",
|
|
150
|
+
path: ".claude/skills/create-server-action/SKILL.md",
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "create-subscription-events",
|
|
154
|
+
description: "Create product price/availability subscription — Events.subscribeByMarker / unsubscribeByMarker",
|
|
155
|
+
path: ".claude/skills/create-subscription-events/SKILL.md",
|
|
156
|
+
},
|
|
157
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oneentry/mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for OneEntry SDK — rules and skills for Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"oneentry-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsx src/index.ts",
|
|
13
|
+
"start": "node dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.10.1",
|
|
17
|
+
"zod": "^3.24.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.0.0",
|
|
21
|
+
"tsx": "^4.19.0",
|
|
22
|
+
"typescript": "^5.7.0"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/content.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches content from a remote URL (GitHub raw or any HTTP server).
|
|
3
|
+
* Caches results for TTL_MS to avoid hammering the server.
|
|
4
|
+
*
|
|
5
|
+
* Configure the base URL via env var:
|
|
6
|
+
* ONEENTRY_MCP_BASE_URL=https://raw.githubusercontent.com/your-org/your-repo/main
|
|
7
|
+
*
|
|
8
|
+
* Default points to the oneentry public repo.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const BASE_URL =
|
|
12
|
+
process.env.ONEENTRY_MCP_BASE_URL ??
|
|
13
|
+
"https://raw.githubusercontent.com/ONEENTRY-PLATFORM/oneentry-sdk-rules/main";
|
|
14
|
+
|
|
15
|
+
const TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
16
|
+
|
|
17
|
+
interface CacheEntry {
|
|
18
|
+
text: string;
|
|
19
|
+
expires: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const cache = new Map<string, CacheEntry>();
|
|
23
|
+
|
|
24
|
+
export async function fetchContent(path: string): Promise<string> {
|
|
25
|
+
const cached = cache.get(path);
|
|
26
|
+
if (cached && cached.expires > Date.now()) {
|
|
27
|
+
return cached.text;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const url = `${BASE_URL}/${path}`;
|
|
31
|
+
const res = await fetch(url, {
|
|
32
|
+
headers: {
|
|
33
|
+
"User-Agent": "oneentry-mcp-server/1.0",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
throw new Error(`Failed to fetch content (${res.status}): ${url}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const text = await res.text();
|
|
42
|
+
cache.set(path, { text, expires: Date.now() + TTL_MS });
|
|
43
|
+
return text;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function clearCache(): void {
|
|
47
|
+
cache.clear();
|
|
48
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import {
|
|
5
|
+
ListResourcesRequestSchema,
|
|
6
|
+
ReadResourceRequestSchema,
|
|
7
|
+
ListPromptsRequestSchema,
|
|
8
|
+
GetPromptRequestSchema,
|
|
9
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { fetchContent } from "./content.js";
|
|
11
|
+
import { RULES, SKILLS } from "./registry.js";
|
|
12
|
+
|
|
13
|
+
const CLAUDE_MD_PATH = "CLAUDE.md";
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Server
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
const server = new Server(
|
|
20
|
+
{ name: "oneentry-sdk", version: "1.0.0" },
|
|
21
|
+
{
|
|
22
|
+
capabilities: {
|
|
23
|
+
resources: {},
|
|
24
|
+
prompts: {},
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Resources — rules + CLAUDE.md
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
34
|
+
resources: [
|
|
35
|
+
{
|
|
36
|
+
uri: "oneentry://claude-md",
|
|
37
|
+
name: "OneEntry SDK — Main Instructions (CLAUDE.md)",
|
|
38
|
+
description:
|
|
39
|
+
"Full system prompt with OneEntry SDK rules, patterns, anti-hallucination guidelines and module reference",
|
|
40
|
+
mimeType: "text/markdown",
|
|
41
|
+
},
|
|
42
|
+
...RULES.map((rule) => ({
|
|
43
|
+
uri: `oneentry://rules/${rule.name}`,
|
|
44
|
+
name: rule.displayName,
|
|
45
|
+
description: rule.description,
|
|
46
|
+
mimeType: "text/markdown",
|
|
47
|
+
})),
|
|
48
|
+
],
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
52
|
+
const { uri } = request.params;
|
|
53
|
+
|
|
54
|
+
// CLAUDE.md
|
|
55
|
+
if (uri === "oneentry://claude-md") {
|
|
56
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
57
|
+
return { contents: [{ uri, mimeType: "text/markdown", text }] };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Rules
|
|
61
|
+
if (uri.startsWith("oneentry://rules/")) {
|
|
62
|
+
const name = uri.replace("oneentry://rules/", "");
|
|
63
|
+
const rule = RULES.find((r) => r.name === name);
|
|
64
|
+
if (!rule) {
|
|
65
|
+
throw new Error(`Unknown rule: ${name}`);
|
|
66
|
+
}
|
|
67
|
+
const text = await fetchContent(rule.path);
|
|
68
|
+
return { contents: [{ uri, mimeType: "text/markdown", text }] };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Prompts — skills
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
79
|
+
prompts: [
|
|
80
|
+
// Special prompt: load full context from CLAUDE.md
|
|
81
|
+
{
|
|
82
|
+
name: "oneentry-context",
|
|
83
|
+
description:
|
|
84
|
+
"Load full OneEntry SDK context — system instructions, rules and anti-hallucination guidelines. Use this at the start of a session.",
|
|
85
|
+
arguments: [],
|
|
86
|
+
},
|
|
87
|
+
// All skills
|
|
88
|
+
...SKILLS.map((skill) => ({
|
|
89
|
+
name: skill.name,
|
|
90
|
+
description: skill.description,
|
|
91
|
+
arguments: skill.hasArguments
|
|
92
|
+
? [
|
|
93
|
+
{
|
|
94
|
+
name: "arguments",
|
|
95
|
+
description: skill.argumentDescription ?? "Optional arguments",
|
|
96
|
+
required: false,
|
|
97
|
+
},
|
|
98
|
+
]
|
|
99
|
+
: [],
|
|
100
|
+
})),
|
|
101
|
+
],
|
|
102
|
+
}));
|
|
103
|
+
|
|
104
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
105
|
+
const { name, arguments: args } = request.params;
|
|
106
|
+
|
|
107
|
+
// Load full CLAUDE.md as system context
|
|
108
|
+
if (name === "oneentry-context") {
|
|
109
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
110
|
+
return {
|
|
111
|
+
description: "OneEntry SDK — full system context loaded",
|
|
112
|
+
messages: [
|
|
113
|
+
{
|
|
114
|
+
role: "user" as const,
|
|
115
|
+
content: {
|
|
116
|
+
type: "text" as const,
|
|
117
|
+
text: `The following are the complete instructions and rules for working with OneEntry SDK. Apply them to all subsequent code generation:\n\n${text}`,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Skills
|
|
125
|
+
const skill = SKILLS.find((s) => s.name === name);
|
|
126
|
+
if (!skill) {
|
|
127
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let text = await fetchContent(skill.path);
|
|
131
|
+
|
|
132
|
+
// Replace $ARGUMENTS placeholder (used in inspect-api and create-page skills)
|
|
133
|
+
const userArguments = args?.["arguments"];
|
|
134
|
+
if (userArguments) {
|
|
135
|
+
text = text.replace(/\$ARGUMENTS/g, userArguments);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
description: skill.description,
|
|
140
|
+
messages: [
|
|
141
|
+
{
|
|
142
|
+
role: "user" as const,
|
|
143
|
+
content: {
|
|
144
|
+
type: "text" as const,
|
|
145
|
+
text,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Start
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
async function main() {
|
|
157
|
+
const transport = new StdioServerTransport();
|
|
158
|
+
await server.connect(transport);
|
|
159
|
+
// Log to stderr so it doesn't interfere with MCP stdio protocol
|
|
160
|
+
process.stderr.write("OneEntry MCP server running\n");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
main().catch((err) => {
|
|
164
|
+
process.stderr.write(`Fatal error: ${err}\n`);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
});
|
package/src/registry.ts
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export interface Rule {
|
|
2
|
+
name: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
description: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Skill {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
path: string;
|
|
12
|
+
hasArguments?: boolean;
|
|
13
|
+
argumentDescription?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const RULES: Rule[] = [
|
|
17
|
+
{
|
|
18
|
+
name: "forms",
|
|
19
|
+
displayName: "Forms & FormsData",
|
|
20
|
+
description: "Rules for working with OneEntry Forms API — getFormByMarker, postFormsData, formData types by field type",
|
|
21
|
+
path: ".claude/rules/forms.md",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "tokens",
|
|
25
|
+
displayName: "Tokens & Auth",
|
|
26
|
+
description: "Rules for auth tokens — makeUserApi, refreshToken, race condition handling, getNewToken",
|
|
27
|
+
path: ".claude/rules/tokens.md",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "attribute-values",
|
|
31
|
+
displayName: "AttributeValues",
|
|
32
|
+
description: "How to access attributeValues by type — image, text, list, date, timeInterval, etc.",
|
|
33
|
+
path: ".claude/rules/attribute-values.md",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "auth-provider",
|
|
37
|
+
displayName: "AuthProvider",
|
|
38
|
+
description: "Rules for auth/signUp — IAuthPostBody structure, notificationData, server actions",
|
|
39
|
+
path: ".claude/rules/auth-provider.md",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "nextjs-pages",
|
|
43
|
+
displayName: "Next.js Pages",
|
|
44
|
+
description: "Rules for Next.js pages with OneEntry — params as Promise, pageUrl vs route, localizeInfos",
|
|
45
|
+
path: ".claude/rules/nextjs-pages.md",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "server-actions",
|
|
49
|
+
displayName: "Server Actions",
|
|
50
|
+
description: "Rules for Next.js Server Actions with OneEntry — getApi() vs makeUserApi(), which methods need SA",
|
|
51
|
+
path: ".claude/rules/server-actions.md",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "orders",
|
|
55
|
+
displayName: "Orders & Payments",
|
|
56
|
+
description: "Rules for Orders and Payments — getAllOrdersStorage structure, createOrder, createSession, paymentUrl",
|
|
57
|
+
path: ".claude/rules/orders.md",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "attribute-sets",
|
|
61
|
+
displayName: "AttributeSets",
|
|
62
|
+
description: "Rules for AttributesSets — schema vs values, listTitles, additionalFields, validators",
|
|
63
|
+
path: ".claude/rules/attribute-sets.md",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "localization",
|
|
67
|
+
displayName: "Localization",
|
|
68
|
+
description: "Rules for localization — locale from params, langCode, localizeInfos, useParams in client components",
|
|
69
|
+
path: ".claude/rules/localization.md",
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
export const SKILLS: Skill[] = [
|
|
74
|
+
{
|
|
75
|
+
name: "setup-oneentry",
|
|
76
|
+
description: "Initialize OneEntry SDK in a Next.js project — creates lib/oneentry.ts with singleton pattern, configures next.config.ts for images",
|
|
77
|
+
path: ".claude/skills/setup-oneentry/SKILL.md",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "create-page",
|
|
81
|
+
description: "Create a Next.js page with content from OneEntry CMS — getPageByUrl, getBlocksByPageUrl, localizeInfos",
|
|
82
|
+
path: ".claude/skills/create-page/SKILL.md",
|
|
83
|
+
hasArguments: true,
|
|
84
|
+
argumentDescription: "pageMarker — the pageUrl marker in OneEntry (e.g. 'home', 'about')",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "inspect-api",
|
|
88
|
+
description: "Read .env.local and execute curl requests to OneEntry API to get real markers, attributes and data structures before writing code",
|
|
89
|
+
path: ".claude/skills/inspect-api/SKILL.md",
|
|
90
|
+
hasArguments: true,
|
|
91
|
+
argumentDescription: "pages|menus|forms|products|product-statuses|auth-providers|all",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "create-auth",
|
|
95
|
+
description: "Create auth/registration form with OneEntry AuthProvider — Server Actions, dynamic fields from Forms API, token sync",
|
|
96
|
+
path: ".claude/skills/create-auth/SKILL.md",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "create-product-list",
|
|
100
|
+
description: "Create product catalog with URL-based filters, infinite scroll, Server Actions, FilterPanel and ProductGrid",
|
|
101
|
+
path: ".claude/skills/create-product-list/SKILL.md",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "create-product-card",
|
|
105
|
+
description: "Create a single product page with getProductById, attribute extraction, image gallery, price block, related products",
|
|
106
|
+
path: ".claude/skills/create-product-card/SKILL.md",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "create-cart-manager",
|
|
110
|
+
description: "Create cart manager — Redux slice + redux-persist, add/remove/quantity, StoreProvider",
|
|
111
|
+
path: ".claude/skills/create-cart-manager/SKILL.md",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "create-favorites",
|
|
115
|
+
description: "Create favorites list — Redux slice + persist, stores only product IDs, button and page with API data loading",
|
|
116
|
+
path: ".claude/skills/create-favorites/SKILL.md",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "create-filter-panel",
|
|
120
|
+
description: "Create filter panel — price, color, availability + FilterContext + Apply/Reset buttons",
|
|
121
|
+
path: ".claude/skills/create-filter-panel/SKILL.md",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "create-checkout",
|
|
125
|
+
description: "Create checkout form — fields from Forms API, timeInterval delivery slots, one makeUserApi for createOrder + createSession, redirect to payment",
|
|
126
|
+
path: ".claude/skills/create-checkout/SKILL.md",
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "create-orders-list",
|
|
130
|
+
description: "Create user orders list — load via all storages, one makeUserApi, client pagination, token race condition protection",
|
|
131
|
+
path: ".claude/skills/create-orders-list/SKILL.md",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: "create-profile",
|
|
135
|
+
description: "Create user profile page — Users API fields, data update, token race condition handling",
|
|
136
|
+
path: ".claude/skills/create-profile/SKILL.md",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "create-form",
|
|
140
|
+
description: "Create dynamic form with fields from OneEntry Forms API — all field types including spam (reCAPTCHA)",
|
|
141
|
+
path: ".claude/skills/create-form/SKILL.md",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "create-reviews",
|
|
145
|
+
description: "Create reviews with hierarchy — FormData, isNested, entityIdentifier, replayTo",
|
|
146
|
+
path: ".claude/skills/create-reviews/SKILL.md",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: "create-menu",
|
|
150
|
+
description: "Create navigation menu with submenu support — hierarchy via parentId, URL normalization",
|
|
151
|
+
path: ".claude/skills/create-menu/SKILL.md",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "create-search",
|
|
155
|
+
description: "Create search bar — 300ms debounce, Server Action, dropdown results",
|
|
156
|
+
path: ".claude/skills/create-search/SKILL.md",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "create-locale-switcher",
|
|
160
|
+
description: "Create locale switcher — loads locales via getLocales(), builds links to current page with different locale segment",
|
|
161
|
+
path: ".claude/skills/create-locale-switcher/SKILL.md",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "create-server-action",
|
|
165
|
+
description: "Create Next.js Server Action for OneEntry — getApi() for public methods, makeUserApi() for user-authorized methods",
|
|
166
|
+
path: ".claude/skills/create-server-action/SKILL.md",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "create-subscription-events",
|
|
170
|
+
description: "Create product price/availability subscription — Events.subscribeByMarker / unsubscribeByMarker",
|
|
171
|
+
path: ".claude/skills/create-subscription-events/SKILL.md",
|
|
172
|
+
},
|
|
173
|
+
];
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"types": ["node"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"]
|
|
15
|
+
}
|