@oneentry/mcp-server 1.1.6 → 1.1.8
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 +79 -46
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/index.js +218 -114
- package/package.json +2 -16
- package/eslint.config.mjs +0 -19
- package/src/config.ts +0 -16
- package/src/content.ts +0 -34
- package/src/index.ts +0 -185
- package/src/registry.ts +0 -206
- package/tsconfig.json +0 -15
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ MCP server for OneEntry SDK — gives AI assistants (Claude Code, Cursor, Windsu
|
|
|
6
6
|
|
|
7
7
|
## Two ways to connect
|
|
8
8
|
|
|
9
|
-
| | npm package
|
|
10
|
-
| ------------ |
|
|
11
|
-
| **Install** | `npx -y @oneentry/mcp-server@latest` | No install — just a URL
|
|
12
|
-
| **Works in** | Claude Code only
|
|
13
|
-
| **Requires** | Nothing
|
|
14
|
-
| **Provides** | Rules + Skills (context docs)
|
|
15
|
-
| **Best for** | Quick local setup
|
|
9
|
+
| | npm package | Remote server |
|
|
10
|
+
| ------------ | ------------------------------------ | -------------------------------------------- |
|
|
11
|
+
| **Install** | `npx -y @oneentry/mcp-server@latest` | No install — just a URL |
|
|
12
|
+
| **Works in** | Claude Code only | Claude Code, Cursor, Windsurf |
|
|
13
|
+
| **Requires** | Nothing | OneEntry project token + URL |
|
|
14
|
+
| **Provides** | Rules + Skills (context docs) | Rules + Skills + **SDK documentation tools** |
|
|
15
|
+
| **Best for** | Quick local setup | Full AI-assisted development |
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -31,16 +31,16 @@ You will need:
|
|
|
31
31
|
|
|
32
32
|
```json
|
|
33
33
|
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"oneentry": {
|
|
36
|
+
"type": "streamable-http",
|
|
37
|
+
"url": "https://mcp-sdk-js.oneentry.cloud/mcp",
|
|
38
|
+
"headers": {
|
|
39
|
+
"X-OneEntry-Token": "YOUR_TOKEN",
|
|
40
|
+
"X-OneEntry-URL": "https://yourproject.oneentry.cloud"
|
|
41
|
+
}
|
|
43
42
|
}
|
|
43
|
+
}
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
@@ -48,15 +48,15 @@ You will need:
|
|
|
48
48
|
|
|
49
49
|
```json
|
|
50
50
|
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
51
|
+
"mcpServers": {
|
|
52
|
+
"oneentry": {
|
|
53
|
+
"url": "https://mcp-sdk-js.oneentry.cloud/mcp",
|
|
54
|
+
"headers": {
|
|
55
|
+
"X-OneEntry-Token": "YOUR_TOKEN",
|
|
56
|
+
"X-OneEntry-URL": "https://yourproject.oneentry.cloud"
|
|
57
|
+
}
|
|
59
58
|
}
|
|
59
|
+
}
|
|
60
60
|
}
|
|
61
61
|
```
|
|
62
62
|
|
|
@@ -64,14 +64,14 @@ You will need:
|
|
|
64
64
|
|
|
65
65
|
Add via **Settings → MCP Servers**:
|
|
66
66
|
|
|
67
|
-
```
|
|
67
|
+
```text
|
|
68
68
|
URL: https://mcp-sdk-js.oneentry.cloud/mcp?token=YOUR_TOKEN&url=https://yourproject.oneentry.cloud
|
|
69
69
|
Authentication: None
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
### Alternative — custom headers (instead of query params)
|
|
73
73
|
|
|
74
|
-
```
|
|
74
|
+
```text
|
|
75
75
|
URL: https://mcp-sdk-js.oneentry.cloud/mcp
|
|
76
76
|
X-OneEntry-Token: YOUR_TOKEN
|
|
77
77
|
X-OneEntry-URL: https://yourproject.oneentry.cloud
|
|
@@ -81,48 +81,68 @@ X-OneEntry-URL: https://yourproject.oneentry.cloud
|
|
|
81
81
|
|
|
82
82
|
## Option B — npm package (Claude Code only)
|
|
83
83
|
|
|
84
|
-
Serves rules and skills as readable context documents.
|
|
84
|
+
Serves rules and skills as readable context documents.
|
|
85
|
+
|
|
86
|
+
You can optionally add your OneEntry project URL and token via `env` — this lets the `/inspect-api` skill work without reading `.env.local` or asking you each time.
|
|
85
87
|
|
|
86
88
|
**npx — no install:**
|
|
87
89
|
|
|
88
90
|
```json
|
|
89
91
|
{
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"oneentry": {
|
|
94
|
+
"command": "npx",
|
|
95
|
+
"args": ["-y", "@oneentry/mcp-server@latest"],
|
|
96
|
+
"env": {
|
|
97
|
+
"ONEENTRY_URL": "https://yourproject.oneentry.cloud",
|
|
98
|
+
"ONEENTRY_TOKEN": "YOUR_TOKEN"
|
|
99
|
+
}
|
|
95
100
|
}
|
|
101
|
+
}
|
|
96
102
|
}
|
|
97
103
|
```
|
|
98
104
|
|
|
99
|
-
**
|
|
105
|
+
**Local install (per project):**
|
|
100
106
|
|
|
101
107
|
```bash
|
|
102
|
-
npm install -
|
|
108
|
+
npm install --save-dev @oneentry/mcp-server
|
|
103
109
|
```
|
|
104
110
|
|
|
105
111
|
```json
|
|
106
112
|
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"oneentry": {
|
|
115
|
+
"command": "./node_modules/.bin/oneentry-mcp",
|
|
116
|
+
"env": {
|
|
117
|
+
"ONEENTRY_URL": "https://yourproject.oneentry.cloud",
|
|
118
|
+
"ONEENTRY_TOKEN": "YOUR_TOKEN"
|
|
119
|
+
}
|
|
111
120
|
}
|
|
121
|
+
}
|
|
112
122
|
}
|
|
113
123
|
```
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
## ⚠️ Required for Claude Code: add to your project's CLAUDE.md
|
|
118
|
-
|
|
119
|
-
After connecting the MCP server, create or edit `CLAUDE.md` in the root of your project and add:
|
|
125
|
+
**Global install:**
|
|
120
126
|
|
|
127
|
+
```bash
|
|
128
|
+
npm install -g @oneentry/mcp-server
|
|
121
129
|
```
|
|
122
|
-
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"mcpServers": {
|
|
134
|
+
"oneentry": {
|
|
135
|
+
"command": "oneentry-mcp",
|
|
136
|
+
"env": {
|
|
137
|
+
"ONEENTRY_URL": "https://yourproject.oneentry.cloud",
|
|
138
|
+
"ONEENTRY_TOKEN": "YOUR_TOKEN"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
123
143
|
```
|
|
124
144
|
|
|
125
|
-
>
|
|
145
|
+
> `env` is optional. If omitted, `/inspect-api` reads from `.env.local` / `.env`, or asks you for the URL and token.
|
|
126
146
|
|
|
127
147
|
---
|
|
128
148
|
|
|
@@ -146,13 +166,26 @@ Read them in Claude Code by typing `@oneentry://rules/<name>`:
|
|
|
146
166
|
| `oneentry://rules/localization` | Localization, locale from params |
|
|
147
167
|
| `oneentry://rules/product-statuses` | Product statuses rules |
|
|
148
168
|
|
|
169
|
+
## Available tools
|
|
170
|
+
|
|
171
|
+
Called automatically by the AI when needed:
|
|
172
|
+
|
|
173
|
+
| Tool | Description |
|
|
174
|
+
| -------------------- | ------------------------------------------------------------------ |
|
|
175
|
+
| `load-context` | Reload the full OneEntry SDK instructions into context |
|
|
176
|
+
| `get-rule` | Fetch a specific rule by name |
|
|
177
|
+
| `get-skill` | Fetch a specific skill by name (supports `$ARGUMENTS` placeholder) |
|
|
178
|
+
| `get-project-config` | Return project URL and token from `.mcp.json` env |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
149
182
|
## Available prompts (skills)
|
|
150
183
|
|
|
151
184
|
Invoke in Claude Code with `/mcp__oneentry__<name>`:
|
|
152
185
|
|
|
153
186
|
| Prompt | Description |
|
|
154
187
|
| ---------------------------- | ----------------------------------------------------- |
|
|
155
|
-
| `oneentry-context` |
|
|
188
|
+
| `oneentry-context` | Reload full SDK context manually |
|
|
156
189
|
| `setup-nextjs` | Initialize Next.js project |
|
|
157
190
|
| `setup-oneentry` | Initialize SDK in a Next.js project |
|
|
158
191
|
| `inspect-api` | Inspect real API markers and structure |
|
package/dist/config.d.ts
CHANGED
|
@@ -4,3 +4,7 @@ export declare const USER_AGENT: string;
|
|
|
4
4
|
export declare const CLAUDE_MD_PATH = "CLAUDE.md";
|
|
5
5
|
export declare const BASE_URL: string;
|
|
6
6
|
export declare const TTL_MS: number;
|
|
7
|
+
/** OneEntry project URL — set via ONEENTRY_URL in .mcp.json env */
|
|
8
|
+
export declare const ONEENTRY_URL: string;
|
|
9
|
+
/** OneEntry App Token — set via ONEENTRY_TOKEN in .mcp.json env */
|
|
10
|
+
export declare const ONEENTRY_TOKEN: string;
|
package/dist/config.js
CHANGED
|
@@ -8,3 +8,7 @@ export const CLAUDE_MD_PATH = "CLAUDE.md";
|
|
|
8
8
|
export const BASE_URL = process.env.ONEENTRY_MCP_BASE_URL ??
|
|
9
9
|
"https://raw.githubusercontent.com/ONEENTRY-PLATFORM/oneentry-sdk-rules/main";
|
|
10
10
|
export const TTL_MS = Number(process.env.ONEENTRY_MCP_CACHE_TTL_MS) || 5 * 60 * 1000;
|
|
11
|
+
/** OneEntry project URL — set via ONEENTRY_URL in .mcp.json env */
|
|
12
|
+
export const ONEENTRY_URL = process.env.ONEENTRY_URL ?? "";
|
|
13
|
+
/** OneEntry App Token — set via ONEENTRY_TOKEN in .mcp.json env */
|
|
14
|
+
export const ONEENTRY_TOKEN = process.env.ONEENTRY_TOKEN ?? "";
|
package/dist/index.js
CHANGED
|
@@ -4,128 +4,232 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { fetchContent } from "./content.js";
|
|
6
6
|
import { RULES, SKILLS } from "./registry.js";
|
|
7
|
-
import { CLAUDE_MD_PATH, SERVER_NAME, VERSION } from "./config.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
import { CLAUDE_MD_PATH, ONEENTRY_TOKEN, ONEENTRY_URL, SERVER_NAME, VERSION } from "./config.js";
|
|
8
|
+
/**
|
|
9
|
+
* Точка входа MCP-сервера OneEntry SDK.
|
|
10
|
+
*
|
|
11
|
+
* ## Архитектура
|
|
12
|
+
*
|
|
13
|
+
* MCP (Model Context Protocol) — протокол, по которому AI-клиент (Claude Code,
|
|
14
|
+
* Cursor, Windsurf) общается с внешним сервером контекста. Сервер предоставляет
|
|
15
|
+
* три типа объектов:
|
|
16
|
+
*
|
|
17
|
+
* - **Resources** — документы, которые AI может прочитать по URI (`@oneentry://...`).
|
|
18
|
+
* Аналог файловой системы: клиент сам решает, когда читать.
|
|
19
|
+
*
|
|
20
|
+
* - **Prompts** — готовые шаблоны сообщений (скиллы). AI-клиент подставляет их
|
|
21
|
+
* в чат по команде пользователя (`/mcp__oneentry__<name>`).
|
|
22
|
+
*
|
|
23
|
+
* - **Tools** — функции, которые AI вызывает автоматически по ситуации.
|
|
24
|
+
* Возвращают текст прямо в контекст разговора.
|
|
25
|
+
*
|
|
26
|
+
* ## Как загружается CLAUDE.md
|
|
27
|
+
*
|
|
28
|
+
* При подключении MCP-сервер отвечает на `initialize`-запрос клиента и
|
|
29
|
+
* включает в ответ поле `instructions`. Claude Code читает это поле и
|
|
30
|
+
* автоматически добавляет его в системный контекст сессии — без каких-либо
|
|
31
|
+
* дополнительных действий от пользователя.
|
|
32
|
+
*
|
|
33
|
+
* Поэтому CLAUDE.md загружается **первым делом**, до регистрации всего
|
|
34
|
+
* остального, и передаётся в конструктор `McpServer` через `{ instructions }`.
|
|
35
|
+
*/
|
|
36
|
+
async function main() {
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Загрузка CLAUDE.md и создание сервера
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/**
|
|
41
|
+
* Загружаем CLAUDE.md с GitHub до создания сервера — нам нужно передать
|
|
42
|
+
* содержимое в конструктор как `instructions`.
|
|
43
|
+
*
|
|
44
|
+
* `instructions` — стандартное поле MCP InitializeResult. Клиент получает
|
|
45
|
+
* его в ответ на первый `initialize`-запрос и автоматически включает в
|
|
46
|
+
* системный промпт сессии. Именно так другие MCP-серверы "работают сразу"
|
|
47
|
+
* без дополнительной настройки CLAUDE.md в проекте.
|
|
48
|
+
*/
|
|
49
|
+
const instructions = await fetchContent(CLAUDE_MD_PATH);
|
|
50
|
+
const server = new McpServer({ name: SERVER_NAME, version: VERSION }, { instructions });
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Resources — документы для явного чтения по URI
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
/**
|
|
55
|
+
* Главный ресурс: полный CLAUDE.md как документ.
|
|
56
|
+
* Доступен в Claude Code по `@oneentry://claude-md`.
|
|
57
|
+
* Полезен если нужно явно переподгрузить контекст или вставить его в чат.
|
|
58
|
+
*/
|
|
59
|
+
server.registerResource("OneEntry SDK — Main Instructions (CLAUDE.md)", "oneentry://claude-md", {
|
|
60
|
+
description: "Full system prompt with OneEntry SDK rules, patterns, anti-hallucination guidelines and module reference",
|
|
61
|
+
mimeType: "text/markdown",
|
|
62
|
+
}, async (uri) => {
|
|
63
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
25
64
|
return { contents: [{ uri: uri.toString(), mimeType: "text/markdown", text }] };
|
|
26
65
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
messages: [
|
|
39
|
-
{
|
|
40
|
-
role: "user",
|
|
41
|
-
content: {
|
|
42
|
-
type: "text",
|
|
43
|
-
text: `The following are the complete instructions and rules for working with OneEntry SDK. Apply them to all subsequent code generation:\n\n${text}`,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
};
|
|
48
|
-
});
|
|
49
|
-
// Skills
|
|
50
|
-
for (const skill of SKILLS) {
|
|
51
|
-
if (skill.hasArguments) {
|
|
52
|
-
server.registerPrompt(skill.name, {
|
|
53
|
-
description: skill.description,
|
|
54
|
-
argsSchema: {
|
|
55
|
-
arguments: z
|
|
56
|
-
.string()
|
|
57
|
-
.optional()
|
|
58
|
-
.describe(skill.argumentDescription ?? "Optional arguments"),
|
|
59
|
-
},
|
|
60
|
-
}, async (args) => {
|
|
61
|
-
let text = await fetchContent(skill.path);
|
|
62
|
-
// Replace $ARGUMENTS placeholder (used in inspect-api and create-page skills)
|
|
63
|
-
if (args.arguments) {
|
|
64
|
-
text = text.replace(/\$ARGUMENTS/g, args.arguments);
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
description: skill.description,
|
|
68
|
-
messages: [{ role: "user", content: { type: "text", text } }],
|
|
69
|
-
};
|
|
66
|
+
/**
|
|
67
|
+
* Отдельные правила из registry.ts — каждое доступно по своему URI:
|
|
68
|
+
* `@oneentry://rules/linting`, `@oneentry://rules/tokens`, и т.д.
|
|
69
|
+
*
|
|
70
|
+
* Ресурсы удобны когда нужно прочитать только одно конкретное правило,
|
|
71
|
+
* не загружая весь CLAUDE.md целиком.
|
|
72
|
+
*/
|
|
73
|
+
for (const rule of RULES) {
|
|
74
|
+
server.registerResource(rule.displayName, `oneentry://rules/${rule.name}`, { description: rule.description, mimeType: "text/markdown" }, async (uri) => {
|
|
75
|
+
const text = await fetchContent(rule.path);
|
|
76
|
+
return { contents: [{ uri: uri.toString(), mimeType: "text/markdown", text }] };
|
|
70
77
|
});
|
|
71
78
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Prompts (скиллы) — шаблоны сообщений для вставки в чат
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
/**
|
|
83
|
+
* Специальный промпт для ручной перезагрузки контекста.
|
|
84
|
+
* Вызывается командой `/mcp__oneentry__oneentry-context`.
|
|
85
|
+
*
|
|
86
|
+
* Возвращает CLAUDE.md завёрнутым в сообщение с ролью `user` — это
|
|
87
|
+
* стандартный способ подачи контекста через MCP Prompts API.
|
|
88
|
+
* Клиент вставляет это сообщение в историю чата.
|
|
89
|
+
*/
|
|
90
|
+
server.registerPrompt("oneentry-context", {
|
|
91
|
+
description: "Load full OneEntry SDK context — system instructions, rules and anti-hallucination guidelines. Use this at the start of a session.",
|
|
92
|
+
}, async () => {
|
|
93
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
94
|
+
return {
|
|
95
|
+
description: "OneEntry SDK — full system context loaded",
|
|
96
|
+
messages: [
|
|
97
|
+
{
|
|
98
|
+
role: "user",
|
|
99
|
+
content: {
|
|
100
|
+
type: "text",
|
|
101
|
+
text: `The following are the complete instructions and rules for working with OneEntry SDK. Apply them to all subsequent code generation:\n\n${text}`,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* Регистрируем все скиллы из registry.ts как MCP Prompts.
|
|
109
|
+
* Каждый скилл — это markdown-инструкция для выполнения конкретной задачи
|
|
110
|
+
* (создание страницы, формы, корзины и т.д.).
|
|
111
|
+
*
|
|
112
|
+
* Скиллы делятся на два типа:
|
|
113
|
+
* - `hasArguments: true` — принимают аргумент (например, маркер страницы),
|
|
114
|
+
* который подставляется вместо плейсхолдера `$ARGUMENTS` в тексте скилла.
|
|
115
|
+
* - без аргументов — возвращают текст как есть.
|
|
116
|
+
*/
|
|
117
|
+
for (const skill of SKILLS) {
|
|
118
|
+
if (skill.hasArguments) {
|
|
119
|
+
server.registerPrompt(skill.name, {
|
|
76
120
|
description: skill.description,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}, async (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
server.registerTool("get-skill", {
|
|
106
|
-
description: "Fetch the content of a specific OneEntry skill/slash-command by name",
|
|
107
|
-
inputSchema: {
|
|
108
|
-
name: z.string().describe(`Skill name. Available: ${SKILLS.map((s) => s.name).join(", ")}`),
|
|
109
|
-
arguments: z.string().optional().describe("Optional arguments passed to the skill (replaces $ARGUMENTS placeholder)"),
|
|
110
|
-
},
|
|
111
|
-
}, async (args) => {
|
|
112
|
-
const skill = SKILLS.find((s) => s.name === args.name);
|
|
113
|
-
if (!skill) {
|
|
114
|
-
return { content: [{ type: "text", text: `Unknown skill: ${args.name}. Available: ${SKILLS.map((s) => s.name).join(", ")}` }], isError: true };
|
|
115
|
-
}
|
|
116
|
-
let text = await fetchContent(skill.path);
|
|
117
|
-
if (args.arguments) {
|
|
118
|
-
text = text.replace(/\$ARGUMENTS/g, args.arguments);
|
|
121
|
+
argsSchema: {
|
|
122
|
+
arguments: z
|
|
123
|
+
.string()
|
|
124
|
+
.optional()
|
|
125
|
+
.describe(skill.argumentDescription ?? "Optional arguments"),
|
|
126
|
+
},
|
|
127
|
+
}, async (args) => {
|
|
128
|
+
let text = await fetchContent(skill.path);
|
|
129
|
+
// Подставляем аргумент вместо плейсхолдера $ARGUMENTS в тексте скилла.
|
|
130
|
+
// Используется, например, в inspect-api (тип данных) и create-page (маркер страницы).
|
|
131
|
+
if (args.arguments) {
|
|
132
|
+
text = text.replace(/\$ARGUMENTS/g, args.arguments);
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
description: skill.description,
|
|
136
|
+
messages: [{ role: "user", content: { type: "text", text } }],
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
server.registerPrompt(skill.name, { description: skill.description }, async () => {
|
|
142
|
+
const text = await fetchContent(skill.path);
|
|
143
|
+
return {
|
|
144
|
+
description: skill.description,
|
|
145
|
+
messages: [{ role: "user", content: { type: "text", text } }],
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
}
|
|
119
149
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// Tools — функции, вызываемые AI автоматически по ситуации
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
/**
|
|
154
|
+
* Инструмент для ручной перезагрузки CLAUDE.md в контекст разговора.
|
|
155
|
+
* В отличие от `instructions` (которые загружаются один раз при коннекте),
|
|
156
|
+
* этот tool позволяет получить свежую версию документа прямо в чат —
|
|
157
|
+
* например, если кэш устарел или контекст был сброшен.
|
|
158
|
+
*/
|
|
159
|
+
server.registerTool("load-context", {
|
|
160
|
+
description: "Reload the full OneEntry SDK instructions, rules, and anti-hallucination guidelines into the context. " +
|
|
161
|
+
"Call this if you need a fresh copy of the SDK documentation.",
|
|
162
|
+
inputSchema: {},
|
|
163
|
+
}, async () => {
|
|
164
|
+
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
165
|
+
return { content: [{ type: "text", text }] };
|
|
166
|
+
});
|
|
167
|
+
/**
|
|
168
|
+
* Инструмент для загрузки отдельного правила по имени.
|
|
169
|
+
* AI может вызвать его когда нужно уточнить конкретный аспект SDK
|
|
170
|
+
* (например, правила работы с токенами или формами) без загрузки всего CLAUDE.md.
|
|
171
|
+
*/
|
|
172
|
+
server.registerTool("get-rule", {
|
|
173
|
+
description: "Fetch the content of a specific OneEntry SDK rule by name",
|
|
174
|
+
inputSchema: { name: z.string().describe(`Rule name. Available: ${RULES.map((r) => r.name).join(", ")}`) },
|
|
175
|
+
}, async ({ name }) => {
|
|
176
|
+
const rule = RULES.find((r) => r.name === name);
|
|
177
|
+
if (!rule) {
|
|
178
|
+
return { content: [{ type: "text", text: `Unknown rule: ${name}. Available: ${RULES.map((r) => r.name).join(", ")}` }], isError: true };
|
|
179
|
+
}
|
|
180
|
+
const text = await fetchContent(rule.path);
|
|
181
|
+
return { content: [{ type: "text", text }] };
|
|
182
|
+
});
|
|
183
|
+
/**
|
|
184
|
+
* Инструмент для получения URL и токена проекта из MCP-конфигурации.
|
|
185
|
+
* Пользователь может задать их в `.mcp.json` через `env.ONEENTRY_URL` и `env.ONEENTRY_TOKEN`.
|
|
186
|
+
* Если переменные не заданы — возвращает пустые строки, скилл `/inspect-api`
|
|
187
|
+
* тогда читает `.env.local` / `.env` или спрашивает у пользователя.
|
|
188
|
+
*/
|
|
189
|
+
server.registerTool("get-project-config", {
|
|
190
|
+
description: "Get OneEntry project URL and token from MCP configuration (set via ONEENTRY_URL and ONEENTRY_TOKEN in .mcp.json env). " +
|
|
191
|
+
"Returns empty strings if not configured — fall back to .env.local or ask the user.",
|
|
192
|
+
inputSchema: {},
|
|
193
|
+
}, async () => {
|
|
194
|
+
const configured = ONEENTRY_URL !== "" && ONEENTRY_TOKEN !== "";
|
|
195
|
+
const text = configured
|
|
196
|
+
? JSON.stringify({ url: ONEENTRY_URL, token: ONEENTRY_TOKEN, source: ".mcp.json" })
|
|
197
|
+
: JSON.stringify({ url: "", token: "", source: "not configured" });
|
|
198
|
+
return { content: [{ type: "text", text }] };
|
|
199
|
+
});
|
|
200
|
+
/**
|
|
201
|
+
* Инструмент для загрузки конкретного скилла по имени.
|
|
202
|
+
* Аналог вызова промпта, но через tool API — удобно когда AI сам
|
|
203
|
+
* определяет что нужен тот или иной скилл в процессе работы.
|
|
204
|
+
* Поддерживает аргументы: подставляет их вместо `$ARGUMENTS` в тексте.
|
|
205
|
+
*/
|
|
206
|
+
server.registerTool("get-skill", {
|
|
207
|
+
description: "Fetch the content of a specific OneEntry skill/slash-command by name",
|
|
208
|
+
inputSchema: {
|
|
209
|
+
name: z.string().describe(`Skill name. Available: ${SKILLS.map((s) => s.name).join(", ")}`),
|
|
210
|
+
arguments: z.string().optional().describe("Optional arguments passed to the skill (replaces $ARGUMENTS placeholder)"),
|
|
211
|
+
},
|
|
212
|
+
}, async (args) => {
|
|
213
|
+
const skill = SKILLS.find((s) => s.name === args.name);
|
|
214
|
+
if (!skill) {
|
|
215
|
+
return { content: [{ type: "text", text: `Unknown skill: ${args.name}. Available: ${SKILLS.map((s) => s.name).join(", ")}` }], isError: true };
|
|
216
|
+
}
|
|
217
|
+
let text = await fetchContent(skill.path);
|
|
218
|
+
if (args.arguments) {
|
|
219
|
+
text = text.replace(/\$ARGUMENTS/g, args.arguments);
|
|
220
|
+
}
|
|
221
|
+
return { content: [{ type: "text", text }] };
|
|
222
|
+
});
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Запуск транспорта
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
/**
|
|
227
|
+
* StdioServerTransport — транспорт на основе stdin/stdout.
|
|
228
|
+
* MCP-клиент запускает этот процесс и общается с ним через стандартные потоки.
|
|
229
|
+
* Все логи пишем в stderr чтобы не засорять MCP-протокол в stdout.
|
|
230
|
+
*/
|
|
126
231
|
const transport = new StdioServerTransport();
|
|
127
232
|
await server.connect(transport);
|
|
128
|
-
// Log to stderr so it doesn't interfere with MCP stdio protocol
|
|
129
233
|
process.stderr.write("OneEntry MCP server running\n");
|
|
130
234
|
}
|
|
131
235
|
main().catch((err) => {
|
package/package.json
CHANGED
|
@@ -1,34 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oneentry/mcp-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "MCP server for OneEntry SDK — rules and skills for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"oneentry-mcp": "dist/index.js"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"dev": "tsx src/index.ts",
|
|
13
|
-
"start": "node dist/index.js",
|
|
14
|
-
"lint": "eslint src"
|
|
15
|
-
},
|
|
16
10
|
"dependencies": {
|
|
17
11
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
18
12
|
"zod": "^4.3.6"
|
|
19
13
|
},
|
|
20
|
-
"devDependencies": {
|
|
21
|
-
"@eslint/js": "^10.0.1",
|
|
22
|
-
"@types/node": "^25.3.5",
|
|
23
|
-
"eslint": "^10.0.2",
|
|
24
|
-
"tsx": "^4.21.0",
|
|
25
|
-
"typescript": "^5.8.3",
|
|
26
|
-
"typescript-eslint": "^8.56.1"
|
|
27
|
-
},
|
|
28
14
|
"engines": {
|
|
29
15
|
"node": ">=18"
|
|
30
16
|
},
|
|
31
17
|
"publishConfig": {
|
|
32
18
|
"access": "public"
|
|
33
19
|
}
|
|
34
|
-
}
|
|
20
|
+
}
|
package/eslint.config.mjs
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import js from "@eslint/js";
|
|
2
|
-
import tseslint from "typescript-eslint";
|
|
3
|
-
|
|
4
|
-
export default tseslint.config(
|
|
5
|
-
{ ignores: ["eslint.config.mjs"] },
|
|
6
|
-
js.configs.recommended,
|
|
7
|
-
tseslint.configs.recommended,
|
|
8
|
-
{
|
|
9
|
-
languageOptions: {
|
|
10
|
-
parserOptions: {
|
|
11
|
-
project: "./tsconfig.json",
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
rules: {
|
|
15
|
-
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
16
|
-
"@typescript-eslint/no-explicit-any": "warn",
|
|
17
|
-
},
|
|
18
|
-
}
|
|
19
|
-
);
|
package/src/config.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "module";
|
|
2
|
-
|
|
3
|
-
const require = createRequire(import.meta.url);
|
|
4
|
-
const pkg = require("../package.json") as { version: string };
|
|
5
|
-
|
|
6
|
-
export const VERSION = pkg.version;
|
|
7
|
-
export const SERVER_NAME = "oneentry-sdk";
|
|
8
|
-
export const USER_AGENT = `oneentry-mcp-server/${VERSION}`;
|
|
9
|
-
export const CLAUDE_MD_PATH = "CLAUDE.md";
|
|
10
|
-
|
|
11
|
-
export const BASE_URL =
|
|
12
|
-
process.env.ONEENTRY_MCP_BASE_URL ??
|
|
13
|
-
"https://raw.githubusercontent.com/ONEENTRY-PLATFORM/oneentry-sdk-rules/main";
|
|
14
|
-
|
|
15
|
-
export const TTL_MS =
|
|
16
|
-
Number(process.env.ONEENTRY_MCP_CACHE_TTL_MS) || 5 * 60 * 1000;
|
package/src/content.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { BASE_URL, TTL_MS, USER_AGENT } from "./config.js";
|
|
2
|
-
|
|
3
|
-
interface CacheEntry {
|
|
4
|
-
text: string;
|
|
5
|
-
expires: number;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const cache = new Map<string, CacheEntry>();
|
|
9
|
-
|
|
10
|
-
export async function fetchContent(path: string): Promise<string> {
|
|
11
|
-
const cached = cache.get(path);
|
|
12
|
-
if (cached && cached.expires > Date.now()) {
|
|
13
|
-
return cached.text;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const url = `${BASE_URL}/${path}`;
|
|
17
|
-
const res = await fetch(url, {
|
|
18
|
-
headers: {
|
|
19
|
-
"User-Agent": USER_AGENT,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
if (!res.ok) {
|
|
24
|
-
throw new Error(`Failed to fetch content (${res.status}): ${url}`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const text = await res.text();
|
|
28
|
-
cache.set(path, { text, expires: Date.now() + TTL_MS });
|
|
29
|
-
return text;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function clearCache(): void {
|
|
33
|
-
cache.clear();
|
|
34
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import { fetchContent } from "./content.js";
|
|
6
|
-
import { RULES, SKILLS } from "./registry.js";
|
|
7
|
-
import { CLAUDE_MD_PATH, SERVER_NAME, VERSION } from "./config.js";
|
|
8
|
-
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
// Server
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
|
|
13
|
-
const server = new McpServer({ name: SERVER_NAME, version: VERSION });
|
|
14
|
-
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// Resources — rules + CLAUDE.md
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
server.registerResource(
|
|
20
|
-
"OneEntry SDK — Main Instructions (CLAUDE.md)",
|
|
21
|
-
"oneentry://claude-md",
|
|
22
|
-
{
|
|
23
|
-
description:
|
|
24
|
-
"Full system prompt with OneEntry SDK rules, patterns, anti-hallucination guidelines and module reference",
|
|
25
|
-
mimeType: "text/markdown",
|
|
26
|
-
},
|
|
27
|
-
async (uri) => {
|
|
28
|
-
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
29
|
-
return { contents: [{ uri: uri.toString(), mimeType: "text/markdown", text }] };
|
|
30
|
-
}
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
for (const rule of RULES) {
|
|
34
|
-
server.registerResource(
|
|
35
|
-
rule.displayName,
|
|
36
|
-
`oneentry://rules/${rule.name}`,
|
|
37
|
-
{ description: rule.description, mimeType: "text/markdown" },
|
|
38
|
-
async (uri) => {
|
|
39
|
-
const text = await fetchContent(rule.path);
|
|
40
|
-
return { contents: [{ uri: uri.toString(), mimeType: "text/markdown", text }] };
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
// Prompts — skills
|
|
47
|
-
// ---------------------------------------------------------------------------
|
|
48
|
-
|
|
49
|
-
// Special prompt: load full context from CLAUDE.md
|
|
50
|
-
server.registerPrompt(
|
|
51
|
-
"oneentry-context",
|
|
52
|
-
{
|
|
53
|
-
description:
|
|
54
|
-
"Load full OneEntry SDK context — system instructions, rules and anti-hallucination guidelines. Use this at the start of a session.",
|
|
55
|
-
},
|
|
56
|
-
async () => {
|
|
57
|
-
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
58
|
-
return {
|
|
59
|
-
description: "OneEntry SDK — full system context loaded",
|
|
60
|
-
messages: [
|
|
61
|
-
{
|
|
62
|
-
role: "user" as const,
|
|
63
|
-
content: {
|
|
64
|
-
type: "text" as const,
|
|
65
|
-
text: `The following are the complete instructions and rules for working with OneEntry SDK. Apply them to all subsequent code generation:\n\n${text}`,
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
// Skills
|
|
74
|
-
for (const skill of SKILLS) {
|
|
75
|
-
if (skill.hasArguments) {
|
|
76
|
-
server.registerPrompt(
|
|
77
|
-
skill.name,
|
|
78
|
-
{
|
|
79
|
-
description: skill.description,
|
|
80
|
-
argsSchema: {
|
|
81
|
-
arguments: z
|
|
82
|
-
.string()
|
|
83
|
-
.optional()
|
|
84
|
-
.describe(skill.argumentDescription ?? "Optional arguments"),
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
async (args) => {
|
|
88
|
-
let text = await fetchContent(skill.path);
|
|
89
|
-
// Replace $ARGUMENTS placeholder (used in inspect-api and create-page skills)
|
|
90
|
-
if (args.arguments) {
|
|
91
|
-
text = text.replace(/\$ARGUMENTS/g, args.arguments);
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
description: skill.description,
|
|
95
|
-
messages: [{ role: "user" as const, content: { type: "text" as const, text } }],
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
} else {
|
|
100
|
-
server.registerPrompt(
|
|
101
|
-
skill.name,
|
|
102
|
-
{ description: skill.description },
|
|
103
|
-
async () => {
|
|
104
|
-
const text = await fetchContent(skill.path);
|
|
105
|
-
return {
|
|
106
|
-
description: skill.description,
|
|
107
|
-
messages: [{ role: "user" as const, content: { type: "text" as const, text } }],
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
// Tools
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
|
|
118
|
-
server.registerTool(
|
|
119
|
-
"load-context",
|
|
120
|
-
{
|
|
121
|
-
description:
|
|
122
|
-
"IMPORTANT: Call this tool automatically at the start of EVERY session when working on a project that uses OneEntry CMS or OneEntry SDK. " +
|
|
123
|
-
"This loads the full OneEntry SDK instructions, rules, and anti-hallucination guidelines into the context. " +
|
|
124
|
-
"Do not skip this — without it you will make mistakes working with OneEntry API.",
|
|
125
|
-
inputSchema: {},
|
|
126
|
-
},
|
|
127
|
-
async () => {
|
|
128
|
-
const text = await fetchContent(CLAUDE_MD_PATH);
|
|
129
|
-
return { content: [{ type: "text" as const, text }] };
|
|
130
|
-
}
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
server.registerTool(
|
|
134
|
-
"get-rule",
|
|
135
|
-
{
|
|
136
|
-
description: "Fetch the content of a specific OneEntry SDK rule by name",
|
|
137
|
-
inputSchema: { name: z.string().describe(`Rule name. Available: ${RULES.map((r) => r.name).join(", ")}`) },
|
|
138
|
-
},
|
|
139
|
-
async ({ name }) => {
|
|
140
|
-
const rule = RULES.find((r) => r.name === name);
|
|
141
|
-
if (!rule) {
|
|
142
|
-
return { content: [{ type: "text" as const, text: `Unknown rule: ${name}. Available: ${RULES.map((r) => r.name).join(", ")}` }], isError: true };
|
|
143
|
-
}
|
|
144
|
-
const text = await fetchContent(rule.path);
|
|
145
|
-
return { content: [{ type: "text" as const, text }] };
|
|
146
|
-
}
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
server.registerTool(
|
|
150
|
-
"get-skill",
|
|
151
|
-
{
|
|
152
|
-
description: "Fetch the content of a specific OneEntry skill/slash-command by name",
|
|
153
|
-
inputSchema: {
|
|
154
|
-
name: z.string().describe(`Skill name. Available: ${SKILLS.map((s) => s.name).join(", ")}`),
|
|
155
|
-
arguments: z.string().optional().describe("Optional arguments passed to the skill (replaces $ARGUMENTS placeholder)"),
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
async (args) => {
|
|
159
|
-
const skill = SKILLS.find((s) => s.name === args.name);
|
|
160
|
-
if (!skill) {
|
|
161
|
-
return { content: [{ type: "text" as const, text: `Unknown skill: ${args.name}. Available: ${SKILLS.map((s) => s.name).join(", ")}` }], isError: true };
|
|
162
|
-
}
|
|
163
|
-
let text = await fetchContent(skill.path);
|
|
164
|
-
if (args.arguments) {
|
|
165
|
-
text = text.replace(/\$ARGUMENTS/g, args.arguments);
|
|
166
|
-
}
|
|
167
|
-
return { content: [{ type: "text" as const, text }] };
|
|
168
|
-
}
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
// ---------------------------------------------------------------------------
|
|
172
|
-
// Start
|
|
173
|
-
// ---------------------------------------------------------------------------
|
|
174
|
-
|
|
175
|
-
async function main() {
|
|
176
|
-
const transport = new StdioServerTransport();
|
|
177
|
-
await server.connect(transport);
|
|
178
|
-
// Log to stderr so it doesn't interfere with MCP stdio protocol
|
|
179
|
-
process.stderr.write("OneEntry MCP server running\n");
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
main().catch((err) => {
|
|
183
|
-
process.stderr.write(`Fatal error: ${err}\n`);
|
|
184
|
-
process.exit(1);
|
|
185
|
-
});
|
package/src/registry.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
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: "linting",
|
|
19
|
-
displayName: "Linting",
|
|
20
|
-
description: "Rules for working with linters",
|
|
21
|
-
path: ".claude/rules/linting.md",
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: "typescript",
|
|
25
|
-
displayName: "Typescript",
|
|
26
|
-
description: "Rules for working with typescript",
|
|
27
|
-
path: ".claude/rules/typescript.md",
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: "nextjs-pages",
|
|
31
|
-
displayName: "Next.js Pages",
|
|
32
|
-
description: "Rules for Next.js pages with OneEntry — params as Promise, pageUrl vs route, localizeInfos",
|
|
33
|
-
path: ".claude/rules/nextjs-pages.md",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: "attribute-values",
|
|
37
|
-
displayName: "AttributeValues",
|
|
38
|
-
description: "How to access attributeValues by type — image, text, list, date, timeInterval, etc.",
|
|
39
|
-
path: ".claude/rules/attribute-values.md",
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: "attribute-sets",
|
|
43
|
-
displayName: "AttributeSets",
|
|
44
|
-
description: "Rules for AttributesSets — schema vs values, listTitles, additionalFields, validators",
|
|
45
|
-
path: ".claude/rules/attribute-sets.md",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: "auth-provider",
|
|
49
|
-
displayName: "AuthProvider",
|
|
50
|
-
description: "Rules for auth/signUp — IAuthPostBody structure, notificationData, server actions",
|
|
51
|
-
path: ".claude/rules/auth-provider.md",
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: "tokens",
|
|
55
|
-
displayName: "Tokens & Auth",
|
|
56
|
-
description: "Rules for auth tokens — makeUserApi, refreshToken, race condition handling, getNewToken",
|
|
57
|
-
path: ".claude/rules/tokens.md",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: "server-actions",
|
|
61
|
-
displayName: "Server Actions",
|
|
62
|
-
description: "Rules for Next.js Server Actions with OneEntry — getApi() vs makeUserApi(), which methods need SA",
|
|
63
|
-
path: ".claude/rules/server-actions.md",
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
name: "forms",
|
|
67
|
-
displayName: "Forms & FormsData",
|
|
68
|
-
description: "Rules for working with OneEntry Forms API — getFormByMarker, postFormsData, formData types by field type",
|
|
69
|
-
path: ".claude/rules/forms.md",
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: "orders",
|
|
73
|
-
displayName: "Orders & Payments",
|
|
74
|
-
description: "Rules for Orders and Payments — getAllOrdersStorage structure, createOrder, createSession, paymentUrl",
|
|
75
|
-
path: ".claude/rules/orders.md",
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: "localization",
|
|
79
|
-
displayName: "Localization",
|
|
80
|
-
description: "Rules for localization — locale from params, langCode, localizeInfos, useParams in client components",
|
|
81
|
-
path: ".claude/rules/localization.md",
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: "product-statuses",
|
|
85
|
-
displayName: "Product statuses",
|
|
86
|
-
description: "Rules product statuses",
|
|
87
|
-
path: ".claude/rules/product-statuses.md",
|
|
88
|
-
},
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
export const SKILLS: Skill[] = [
|
|
92
|
-
{
|
|
93
|
-
name: "setup-nextjs",
|
|
94
|
-
description: "Initialize Next.js project — configures nextjs",
|
|
95
|
-
path: ".claude/skills/setup-nextjs/SKILL.md",
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: "setup-oneentry",
|
|
99
|
-
description: "Initialize OneEntry SDK in a Next.js project — creates lib/oneentry.ts with singleton pattern, configures next.config.ts for images",
|
|
100
|
-
path: ".claude/skills/setup-oneentry/SKILL.md",
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: "inspect-api",
|
|
104
|
-
description: "Read .env.local and execute curl requests to OneEntry API to get real markers, attributes and data structures before writing code",
|
|
105
|
-
path: ".claude/skills/inspect-api/SKILL.md",
|
|
106
|
-
hasArguments: true,
|
|
107
|
-
argumentDescription: "pages|menus|forms|products|product-statuses|auth-providers|all",
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
name: "create-page",
|
|
111
|
-
description: "Create a Next.js page with content from OneEntry CMS — getPageByUrl, getBlocksByPageUrl, localizeInfos",
|
|
112
|
-
path: ".claude/skills/create-page/SKILL.md",
|
|
113
|
-
hasArguments: true,
|
|
114
|
-
argumentDescription: "pageMarker — the pageUrl marker in OneEntry (e.g. 'home', 'about')",
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: "create-auth",
|
|
118
|
-
description: "Create auth/registration form with OneEntry AuthProvider — Server Actions, dynamic fields from Forms API, token sync",
|
|
119
|
-
path: ".claude/skills/create-auth/SKILL.md",
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: "create-product-list",
|
|
123
|
-
description: "Create product catalog with URL-based filters, infinite scroll, Server Actions, FilterPanel and ProductGrid",
|
|
124
|
-
path: ".claude/skills/create-product-list/SKILL.md",
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
name: "create-product-card",
|
|
128
|
-
description: "Create a single product card, attribute extraction, image, price, etc",
|
|
129
|
-
path: ".claude/skills/create-product-card/SKILL.md",
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
name: "create-product-page",
|
|
133
|
-
description: "Create a single product page with getProductById, attribute extraction, image gallery, price block, related products",
|
|
134
|
-
path: ".claude/skills/create-product-page/SKILL.md",
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: "create-cart-manager",
|
|
138
|
-
description: "Create cart manager — Redux slice + redux-persist, add/remove/quantity, StoreProvider",
|
|
139
|
-
path: ".claude/skills/create-cart-manager/SKILL.md",
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
name: "create-favorites",
|
|
143
|
-
description: "Create favorites list — Redux slice + persist, stores only product IDs, button and page with API data loading",
|
|
144
|
-
path: ".claude/skills/create-favorites/SKILL.md",
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "create-filter-panel",
|
|
148
|
-
description: "Create filter panel — price, color, availability + FilterContext + Apply/Reset buttons",
|
|
149
|
-
path: ".claude/skills/create-filter-panel/SKILL.md",
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
name: "create-checkout",
|
|
153
|
-
description: "Create checkout form — fields from Forms API, timeInterval delivery slots, one makeUserApi for createOrder + createSession, redirect to payment",
|
|
154
|
-
path: ".claude/skills/create-checkout/SKILL.md",
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
name: "create-orders-list",
|
|
158
|
-
description: "Create user orders list — load via all storages, one makeUserApi, client pagination, token race condition protection",
|
|
159
|
-
path: ".claude/skills/create-orders-list/SKILL.md",
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
name: "create-profile",
|
|
163
|
-
description: "Create user profile page — Users API fields, data update, token race condition handling",
|
|
164
|
-
path: ".claude/skills/create-profile/SKILL.md",
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
name: "create-form",
|
|
168
|
-
description: "Create dynamic form with fields from OneEntry Forms API — all field types including spam (reCAPTCHA)",
|
|
169
|
-
path: ".claude/skills/create-form/SKILL.md",
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: "create-reviews",
|
|
173
|
-
description: "Create reviews with hierarchy — FormData, isNested, entityIdentifier, replayTo",
|
|
174
|
-
path: ".claude/skills/create-reviews/SKILL.md",
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
name: "create-menu",
|
|
178
|
-
description: "Create navigation menu with submenu support — hierarchy via parentId, URL normalization",
|
|
179
|
-
path: ".claude/skills/create-menu/SKILL.md",
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: "create-search",
|
|
183
|
-
description: "Create search bar — 300ms debounce, Server Action, dropdown results",
|
|
184
|
-
path: ".claude/skills/create-search/SKILL.md",
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
name: "create-locale-switcher",
|
|
188
|
-
description: "Create locale switcher — loads locales via getLocales(), builds links to current page with different locale segment",
|
|
189
|
-
path: ".claude/skills/create-locale-switcher/SKILL.md",
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
name: "create-server-action",
|
|
193
|
-
description: "Create Next.js Server Action for OneEntry — getApi() for public methods, makeUserApi() for user-authorized methods",
|
|
194
|
-
path: ".claude/skills/create-server-action/SKILL.md",
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
name: "create-subscription-events",
|
|
198
|
-
description: "Create product price/availability subscription — Events.subscribeByMarker / unsubscribeByMarker",
|
|
199
|
-
path: ".claude/skills/create-subscription-events/SKILL.md",
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
name: "setup-playwright",
|
|
203
|
-
description: "Setup playwright testing framework",
|
|
204
|
-
path: ".claude/skills/setup-playwright/SKILL.md",
|
|
205
|
-
},
|
|
206
|
-
];
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
}
|