@loom-framework/core 0.1.0-alpha.58 → 0.1.0-alpha.59
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/dist/capability-generator.d.ts +12 -3
- package/dist/capability-generator.d.ts.map +1 -1
- package/dist/capability-generator.js +66 -30
- package/dist/capability-generator.js.map +1 -1
- package/dist/cli/commands/generate-capabilities.d.ts +1 -1
- package/dist/cli/commands/generate-capabilities.js +2 -2
- package/dist/cli/commands/generate-capabilities.js.map +1 -1
- package/dist/cli/commands/init.js +2 -2
- package/package.json +1 -1
- package/templates/skill/SKILL.md +53 -42
- package/templates/skill/references/data-model.md +39 -62
- package/templates/skill/references/skill-development.md +0 -46
- package/templates/skill/references/troubleshooting.md +0 -42
|
@@ -4,18 +4,27 @@
|
|
|
4
4
|
* Core innovation: One schema definition → Skill + CLI data access
|
|
5
5
|
*
|
|
6
6
|
* From loom.config.ts model definitions, generates:
|
|
7
|
-
* 1.
|
|
7
|
+
* 1. SKILL.md — user-written natural language (only generated on first run, never overwritten)
|
|
8
|
+
* 2. references/models.md — auto-generated technical content (always overwritten on generate)
|
|
9
|
+
*
|
|
10
|
+
* This split ensures that user-filled descriptions/overview/scenarios survive re-generation.
|
|
8
11
|
*/
|
|
9
12
|
import type { LoomConfig } from './types.js';
|
|
10
13
|
export interface GenerateResult {
|
|
11
14
|
/** Path to the generated skill directory */
|
|
12
15
|
skillDir: string;
|
|
13
|
-
/** Path to the
|
|
16
|
+
/** Path to the SKILL.md file */
|
|
14
17
|
skillPromptFile: string;
|
|
18
|
+
/** Path to the references/models.md file */
|
|
19
|
+
modelsFile: string;
|
|
15
20
|
filesWritten: string[];
|
|
16
21
|
}
|
|
17
22
|
/**
|
|
18
|
-
* Generate all capabilities from config
|
|
23
|
+
* Generate all capabilities from config.
|
|
24
|
+
*
|
|
25
|
+
* Two-file strategy:
|
|
26
|
+
* - SKILL.md: natural language content (only created if not exists, never overwritten)
|
|
27
|
+
* - references/models.md: technical content (always regenerated)
|
|
19
28
|
*/
|
|
20
29
|
export declare function generateCapabilities(projectRoot: string, config: LoomConfig): Promise<GenerateResult>;
|
|
21
30
|
//# sourceMappingURL=capability-generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-generator.d.ts","sourceRoot":"","sources":["../src/capability-generator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capability-generator.d.ts","sourceRoot":"","sources":["../src/capability-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAe,UAAU,EAAmB,MAAM,YAAY,CAAC;AAqK3E,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,cAAc,CAAC,CA+BzB"}
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
* Core innovation: One schema definition → Skill + CLI data access
|
|
5
5
|
*
|
|
6
6
|
* From loom.config.ts model definitions, generates:
|
|
7
|
-
* 1.
|
|
7
|
+
* 1. SKILL.md — user-written natural language (only generated on first run, never overwritten)
|
|
8
|
+
* 2. references/models.md — auto-generated technical content (always overwritten on generate)
|
|
9
|
+
*
|
|
10
|
+
* This split ensures that user-filled descriptions/overview/scenarios survive re-generation.
|
|
8
11
|
*/
|
|
9
12
|
import { promises as fs } from 'fs';
|
|
10
13
|
import path from 'path';
|
|
@@ -62,13 +65,43 @@ loom data delete ${name} --id ${firstRecordId}
|
|
|
62
65
|
\`\`\``;
|
|
63
66
|
}
|
|
64
67
|
/**
|
|
65
|
-
* Generate
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* for Claude Code to fill in based on the project's business semantics.
|
|
68
|
+
* Generate the SKILL.md skeleton — only created on first run.
|
|
69
|
+
* Contains natural language sections with TODO placeholders for the user to fill in.
|
|
70
|
+
* References references/models.md for auto-generated technical content.
|
|
69
71
|
*/
|
|
70
|
-
function
|
|
72
|
+
function generateSkillSkeleton(config) {
|
|
71
73
|
const projectName = config.project.name;
|
|
74
|
+
return `---
|
|
75
|
+
name: ${projectName}-data
|
|
76
|
+
description: |
|
|
77
|
+
TODO: Add trigger phrases for this project's app skill.
|
|
78
|
+
Example: "This skill should be used when the user asks to 'create a record', 'query data', 'update a record', or 'delete a record' in the ${projectName} project."
|
|
79
|
+
version: 1.0.0
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
# ${projectName} — App Skill
|
|
83
|
+
|
|
84
|
+
## Overview
|
|
85
|
+
|
|
86
|
+
TODO: Describe what this project does and how users interact with the data. For example: "This is an error tracking platform for elementary students. Users can manage subjects, wrong questions, and review plans through AI conversations."
|
|
87
|
+
|
|
88
|
+
## Usage Scenarios
|
|
89
|
+
|
|
90
|
+
TODO: Add typical user requests and how to handle them with CLI commands. For example:
|
|
91
|
+
- "创建一个语文科目" → \`loom data write subjects --data '{"name": "语文"}'\`
|
|
92
|
+
- "查看所有未掌握的错题" → \`loom data read wrong_questions --filter '{"status": "未掌握"}'\`
|
|
93
|
+
- "把这道题标记为已掌握" → \`loom data update wrong_questions --id <id> --data '{"status": "已掌握"}'\`
|
|
94
|
+
|
|
95
|
+
## Technical Reference
|
|
96
|
+
|
|
97
|
+
For model schemas, CLI commands, AI buttons, and guidelines, see **references/models.md**.
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Generate references/models.md — always overwritten with latest technical content.
|
|
102
|
+
* Contains model schema tables, CLI command reference, AI button configs, and data access guidelines.
|
|
103
|
+
*/
|
|
104
|
+
function generateModelsReference(config) {
|
|
72
105
|
const models = config.data.models;
|
|
73
106
|
const aiButtons = config.aiButtons || [];
|
|
74
107
|
// Build model schema sections
|
|
@@ -88,19 +121,9 @@ function generateAppSkill(config) {
|
|
|
88
121
|
return `- **${btn.id}** ("${btn.label}"): \`${btn.prompt}\`${placement}`;
|
|
89
122
|
}).join('\n')}`
|
|
90
123
|
: '';
|
|
91
|
-
return
|
|
92
|
-
name: ${projectName}-data
|
|
93
|
-
description: |
|
|
94
|
-
TODO: Add trigger phrases for this project's data access skill.
|
|
95
|
-
Example: "This skill should be used when the user asks to 'create a record', 'query data', 'update a record', or 'delete a record' in the ${projectName} project."
|
|
96
|
-
version: 1.0.0
|
|
97
|
-
---
|
|
124
|
+
return `# Data Models & CLI Reference
|
|
98
125
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
## Overview
|
|
102
|
-
|
|
103
|
-
TODO: Describe what this project does and how users interact with the data. For example: "This is an error tracking platform for elementary students. Users can manage subjects, wrong questions, and review plans through AI conversations."
|
|
126
|
+
> This file is auto-generated by \`loom generate capabilities\`. Do not edit manually — changes will be overwritten.
|
|
104
127
|
|
|
105
128
|
## Data Models
|
|
106
129
|
|
|
@@ -136,29 +159,42 @@ ${buttonSection ? '\n' + buttonSection + '\n' : ''}
|
|
|
136
159
|
8. For write/update, ensure required fields are included. Use \`loom data schema <model>\` if unsure.
|
|
137
160
|
9. The \`update\` command only needs the fields to change; unspecified fields are preserved.
|
|
138
161
|
10. After data modifications, inform the user that the page will auto-refresh.
|
|
139
|
-
|
|
140
|
-
## Usage Scenarios
|
|
141
|
-
|
|
142
|
-
TODO: Add typical user requests and how to handle them with CLI commands. For example:
|
|
143
|
-
- "创建一个语文科目" → \`loom data write subjects --data '{"name": "语文"}'\`
|
|
144
|
-
- "查看所有未掌握的错题" → \`loom data read wrong_questions --filter '{"status": "未掌握"}'\`
|
|
145
|
-
- "把这道题标记为已掌握" → \`loom data update wrong_questions --id <id> --data '{"status": "已掌握"}'\`
|
|
146
162
|
`;
|
|
147
163
|
}
|
|
148
164
|
/**
|
|
149
|
-
* Generate all capabilities from config
|
|
165
|
+
* Generate all capabilities from config.
|
|
166
|
+
*
|
|
167
|
+
* Two-file strategy:
|
|
168
|
+
* - SKILL.md: natural language content (only created if not exists, never overwritten)
|
|
169
|
+
* - references/models.md: technical content (always regenerated)
|
|
150
170
|
*/
|
|
151
171
|
export async function generateCapabilities(projectRoot, config) {
|
|
152
172
|
const projectName = config.project.name;
|
|
153
173
|
const skillDir = path.join(projectRoot, '.claude', 'skills', projectName);
|
|
154
174
|
const skillPromptFile = path.join(skillDir, 'SKILL.md');
|
|
155
175
|
const referencesDir = path.join(skillDir, 'references');
|
|
176
|
+
const modelsFile = path.join(referencesDir, 'models.md');
|
|
156
177
|
const filesWritten = [];
|
|
157
178
|
// Create skill directory structure
|
|
158
179
|
await fs.mkdir(referencesDir, { recursive: true });
|
|
159
|
-
//
|
|
160
|
-
await fs.
|
|
161
|
-
|
|
162
|
-
|
|
180
|
+
// SKILL.md: only write if it doesn't exist (preserve user-written content)
|
|
181
|
+
const skillExists = await fs.access(skillPromptFile).then(() => true, () => false);
|
|
182
|
+
if (skillExists) {
|
|
183
|
+
// Update the reference pointer in existing SKILL.md if it doesn't have one
|
|
184
|
+
const existingContent = await fs.readFile(skillPromptFile, 'utf-8');
|
|
185
|
+
if (!existingContent.includes('references/models.md')) {
|
|
186
|
+
const updated = existingContent + '\n\n## Technical Reference\n\nFor model schemas, CLI commands, AI buttons, and guidelines, see **references/models.md**.\n';
|
|
187
|
+
await fs.writeFile(skillPromptFile, updated, 'utf-8');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// First time: generate skeleton with TODO placeholders
|
|
192
|
+
await fs.writeFile(skillPromptFile, generateSkillSkeleton(config), 'utf-8');
|
|
193
|
+
filesWritten.push(skillPromptFile);
|
|
194
|
+
}
|
|
195
|
+
// references/models.md: always regenerated with latest technical content
|
|
196
|
+
await fs.writeFile(modelsFile, generateModelsReference(config), 'utf-8');
|
|
197
|
+
filesWritten.push(modelsFile);
|
|
198
|
+
return { skillDir, skillPromptFile, modelsFile, filesWritten };
|
|
163
199
|
}
|
|
164
200
|
//# sourceMappingURL=capability-generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-generator.js","sourceRoot":"","sources":["../src/capability-generator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capability-generator.js","sourceRoot":"","sources":["../src/capability-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* loom generate capabilities
|
|
3
3
|
*
|
|
4
|
-
* Read loom.config.ts, call generateCapabilities(), produce app
|
|
4
|
+
* Read loom.config.ts, call generateCapabilities(), produce app Skill for CLI-based data operations.
|
|
5
5
|
*/
|
|
6
6
|
import type { Command } from 'commander';
|
|
7
7
|
export declare function registerGenerateCapabilitiesCommand(program: Command): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* loom generate capabilities
|
|
3
3
|
*
|
|
4
|
-
* Read loom.config.ts, call generateCapabilities(), produce app
|
|
4
|
+
* Read loom.config.ts, call generateCapabilities(), produce app Skill for CLI-based data operations.
|
|
5
5
|
*/
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import ora from 'ora';
|
|
@@ -10,7 +10,7 @@ import { resolveProjectRoot } from '../utils.js';
|
|
|
10
10
|
export function registerGenerateCapabilitiesCommand(program) {
|
|
11
11
|
program
|
|
12
12
|
.command('capabilities')
|
|
13
|
-
.description('Generate app
|
|
13
|
+
.description('Generate app Skill for CLI-based data operations')
|
|
14
14
|
.action(async () => {
|
|
15
15
|
const spinner = ora('Loading config...').start();
|
|
16
16
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-capabilities.js","sourceRoot":"","sources":["../../../src/cli/commands/generate-capabilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,mCAAmC,CAAC,OAAgB;IAClE,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"generate-capabilities.js","sourceRoot":"","sources":["../../../src/cli/commands/generate-capabilities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,mCAAmC,CAAC,OAAgB;IAClE,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,kDAAkD,CAAC;SAC/D,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC;QAEjD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;YAE7C,OAAO,CAAC,IAAI,GAAG,+BAA+B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;YAEnF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAE/D,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;YAErE,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;YAE5C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;gBACrD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;YAC7C,CAAC;YAED,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,YAAY,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -171,8 +171,8 @@ async function createPackageJson(targetDir, options) {
|
|
|
171
171
|
generate: 'loom generate capabilities',
|
|
172
172
|
},
|
|
173
173
|
dependencies: {
|
|
174
|
-
'@loom-framework/core': '^0.1.0-alpha.
|
|
175
|
-
'@loom-framework/frontend-antd': '^0.1.0-alpha.
|
|
174
|
+
'@loom-framework/core': '^0.1.0-alpha.59',
|
|
175
|
+
'@loom-framework/frontend-antd': '^0.1.0-alpha.59',
|
|
176
176
|
'fastify': '^5.2.0',
|
|
177
177
|
'@ant-design/x': '^2.5.0',
|
|
178
178
|
'@ant-design/x-sdk': '^2.5.0',
|
package/package.json
CHANGED
package/templates/skill/SKILL.md
CHANGED
|
@@ -16,58 +16,74 @@ Loom 是**配置驱动、自动生成**的框架。工作流程为:
|
|
|
16
16
|
1. **写配置** — 编辑 `loom.config.ts`,定义数据模型和 AI 按钮
|
|
17
17
|
2. **跑命令** — CLI 读取配置,自动生成页面、API 和路由接线
|
|
18
18
|
|
|
19
|
-
`loom generate page` 会自动生成:CRUD 页面(含 AI 按钮)、App.tsx 路由接线、后端 API +
|
|
19
|
+
`loom generate page` 会自动生成:CRUD 页面(含 AI 按钮)、App.tsx 路由接线、后端 API + 应用 Skill。
|
|
20
20
|
生成的页面自带 AI 助手浮动按钮,支持流式对话、多会话和数据自动刷新。
|
|
21
21
|
|
|
22
22
|
技术架构细节见 `references/README.md`。
|
|
23
23
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
1. 创建项目:
|
|
27
|
-
`npx -p @loom-framework/core loom init <name> --description <desc> --adapter <filesystem|sqlite>`
|
|
28
|
-
2. 编辑 `loom.config.ts` — 定义数据模型和 AI 按钮(见下方 Schema)
|
|
29
|
-
3. 生成页面:`loom generate page <Name> --model <model>`
|
|
30
|
-
4. 启动开发:`loom dev` → http://localhost:5173 (前端), http://localhost:3000 (后端)
|
|
24
|
+
## 开发流程
|
|
31
25
|
|
|
32
26
|
**重要:** 始终在项目目录下运行命令(不是 loom monorepo 根目录)。
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
### 1. 创建项目
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx -p @loom-framework/core loom init <name> --description <desc> --adapter <filesystem|sqlite>
|
|
32
|
+
```
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
- `--skip-generate`, `--backend-only`, `--frontend-only`
|
|
38
|
-
- `loom build` - 生产构建
|
|
39
|
-
- `loom generate capabilities` - 根据 config 生成数据访问 Skill
|
|
40
|
-
- `loom generate page <name> --model <model>` - 生成 CRUD 页面(若配置了 aiButtons 则自动集成)
|
|
41
|
-
- `loom generate skill <name>` - 生成 Skill 脚手架
|
|
34
|
+
### 2. 编辑配置
|
|
42
35
|
|
|
43
|
-
|
|
36
|
+
编辑 `loom.config.ts`,定义数据模型(`data.models`)和 AI 按钮(`aiButtons`),Schema 见下方。高级选项见 `references/data-model.md`。
|
|
44
37
|
|
|
45
|
-
###
|
|
38
|
+
### 3. 生成页面 + 应用 Skill
|
|
46
39
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
```bash
|
|
41
|
+
loom generate page <Name> --model <model-name>
|
|
42
|
+
```
|
|
50
43
|
|
|
51
|
-
|
|
44
|
+
此命令自动生成:CRUD 页面(含 AI 按钮)、App.tsx 路由接线、后端 API、应用 Skill。模型立即可通过 `loom data` CLI 和 AI 对话使用。
|
|
52
45
|
|
|
53
|
-
|
|
46
|
+
### 4. 补充应用 Skill 描述(必须)
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
2. 打开 `.claude/skills/<项目名>/SKILL.md`
|
|
57
|
-
3. 补充 frontmatter 中的 `description`:描述项目的业务场景和触发短语(如"创建科目"、"查看错题"、"修改复习计划")
|
|
58
|
-
4. 补充 Overview 部分:用自然语言描述这个项目做什么、用户会如何与数据交互
|
|
59
|
-
5. 补充 Usage Scenarios 部分:用户在 AI 对话中可能会说的典型请求,以及对应的 CLI 命令
|
|
48
|
+
首次生成后,必须补充 `.claude/skills/<项目名>/SKILL.md` 中以下三处 TODO,AI 对话才能正确理解项目业务语义:
|
|
60
49
|
|
|
61
|
-
|
|
50
|
+
1. **frontmatter `description`**:写入用户在 AI 对话中会说的触发短语。格式参考:
|
|
51
|
+
```
|
|
52
|
+
This skill should be used when the user asks to "创建XXX", "查看XXX", "删除XXX",
|
|
53
|
+
or any request about managing XXX in the <项目名> project.
|
|
54
|
+
```
|
|
55
|
+
2. **Overview 部分**:用 2-3 句话描述项目做什么、有哪些数据、用户如何与数据交互
|
|
56
|
+
3. **Usage Scenarios 部分**:列出 5-10 个典型用户请求,格式为 `- "用户说的话" → 对应的 CLI 命令`
|
|
57
|
+
|
|
58
|
+
### 5. 启动开发
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
loom dev
|
|
62
|
+
```
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
- 前端:http://localhost:5173
|
|
65
|
+
- 后端:http://localhost:3000
|
|
65
66
|
|
|
66
|
-
###
|
|
67
|
+
### 迭代:修改配置 → 重新生成
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
编辑 `loom.config.ts`(添加/修改模型或 AI 按钮)→ 重新执行步骤 3。
|
|
70
|
+
|
|
71
|
+
### 可选:添加更多 Skill
|
|
72
|
+
|
|
73
|
+
`.claude/skills/` 下的所有 Skill 都会被 AI 自动发现。除了自动生成的应用 Skill,还可以添加新的:
|
|
74
|
+
|
|
75
|
+
- `loom generate skill <name>` — 创建脚手架,然后编辑 `.claude/skills/<name>/SKILL.md`
|
|
76
|
+
- 或直接复制一个已有的 Skill 目录到 `.claude/skills/` 下
|
|
77
|
+
|
|
78
|
+
### CLI 命令速查
|
|
79
|
+
|
|
80
|
+
| 命令 | 说明 |
|
|
81
|
+
|------|------|
|
|
82
|
+
| `loom dev` | 启动开发环境(`--skip-generate` `--backend-only` `--frontend-only`) |
|
|
83
|
+
| `loom build` | 生产构建 |
|
|
84
|
+
| `loom generate page <name> --model <model>` | 生成 CRUD 页面 + 应用 Skill(含 aiButtons 则自动集成) |
|
|
85
|
+
| `loom generate capabilities` | 仅重新生成应用 Skill 的 `references/models.md` |
|
|
86
|
+
| `loom generate skill <name>` | 生成自定义 Skill 脚手架 |
|
|
71
87
|
|
|
72
88
|
## loom.config.ts Schema(核心)
|
|
73
89
|
|
|
@@ -82,7 +98,7 @@ export default defineConfig({
|
|
|
82
98
|
data: {
|
|
83
99
|
defaultAdapter: 'filesystem', // 'filesystem' | 'sqlite'
|
|
84
100
|
models: [{
|
|
85
|
-
name: 'items', // 将作为 React
|
|
101
|
+
name: 'items', // 将作为 React 组件名生成页面,字母开头,字母/数字/下划线
|
|
86
102
|
description: '...',', // 可选:显示在生成页面中
|
|
87
103
|
fields: [{
|
|
88
104
|
name: 'status', // 字母/下划线开头,字母数字下划线
|
|
@@ -120,10 +136,5 @@ AI 相关:`POST /api/v1/chat`(SSE 流式对话)、`GET /api/v1/sessions`
|
|
|
120
136
|
|
|
121
137
|
## 常见问题
|
|
122
138
|
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
- **模型名含连字符报错 "Invalid model name"**:模型名只能用字母、数字、下划线。将 `wrong-questions` 改为 `wrong_questions` 或 `wrongQuestions`
|
|
126
|
-
- **better-sqlite3 加载失败 "Could not locate the bindings file"**:Node.js 版本缺少预编译包。修复:(1) `cd node_modules/better-sqlite3 && npx node-gyp rebuild`,或 (2) 将 loom.config.ts 中 `defaultAdapter` 改为 `'filesystem'`
|
|
127
|
-
- **aiButtons 校验失败 "Expected string"**:`prompt` 是必填字段,支持 `{{var}}` 模板语法
|
|
128
|
-
|
|
129
|
-
更多问题见 `references/troubleshooting.md`。
|
|
139
|
+
- **better-sqlite3 加载失败**:Node.js 版本缺少预编译包。修复:(1) `cd node_modules/better-sqlite3 && npx node-gyp rebuild`,或 (2) 将 `defaultAdapter` 改为 `'filesystem'`
|
|
140
|
+
- **`loom` 命令报错 "No loom.config.ts found"**:在项目目录下运行命令
|
|
@@ -1,53 +1,63 @@
|
|
|
1
1
|
# Data Model Reference
|
|
2
2
|
|
|
3
|
-
Advanced configuration for `loom.config.ts
|
|
3
|
+
Advanced configuration for `loom.config.ts`. Full type definitions from `packages/core/src/types.ts`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## FieldDefinition
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
{
|
|
9
|
-
name: 'status', //
|
|
9
|
+
name: 'status', // ^[a-zA-Z_][a-zA-Z0-9_]*$
|
|
10
10
|
type: 'string', // 'string' | 'number' | 'boolean' | 'date' | 'string[]' | 'number[]' | 'json'
|
|
11
11
|
required: true, // optional, default false
|
|
12
|
-
description: '...',
|
|
12
|
+
description: '...', // optional: shown in generated forms
|
|
13
13
|
default: 'active', // optional: auto-filled on write if not provided
|
|
14
|
-
enum: ['active', 'inactive', 'archived'], // optional: restrict to allowed values
|
|
14
|
+
enum: ['active', 'inactive', 'archived'], // optional: restrict string field to allowed values
|
|
15
15
|
}
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## ModelSchema
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
{
|
|
22
|
-
name: 'orders',
|
|
23
|
-
description: 'Order records',
|
|
22
|
+
name: 'orders', // ^[a-zA-Z][a-zA-Z0-9_]*$, will be used as React component name
|
|
23
|
+
description: 'Order records', // optional: shown in generated page heading
|
|
24
24
|
fields: [...],
|
|
25
|
-
indexes: [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
adapters: { // optional: per-model adapter override
|
|
29
|
-
filesystem: { dir: 'orders', format: 'json' | 'yaml', datePattern: 'yyyy-MM-dd' },
|
|
25
|
+
indexes?: [{ fields: ['userId', 'status'], unique: false }],
|
|
26
|
+
adapters?: { // optional: per-model adapter override
|
|
27
|
+
filesystem: { dir: 'orders', format: 'json' | 'yaml', datePattern: 'YYYY-MM' },
|
|
30
28
|
sqlite: { table: 'orders' },
|
|
31
29
|
},
|
|
32
|
-
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## AIButtonConfig
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
aiButtons: [{
|
|
37
|
+
id: 'summarize', // required: unique identifier
|
|
38
|
+
label: '总结', // required: button text
|
|
39
|
+
icon: 'FileTextOutlined', // optional: Ant Design icon component name
|
|
40
|
+
prompt: '请总结以下内容', // required: supports {{var}} placeholders, replaced with current row field values
|
|
41
|
+
placement: 'wrong_questions', // optional: limit to specific model pages, comma-separated; omit for all pages
|
|
42
|
+
}]
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
##
|
|
45
|
+
## AIConfig
|
|
36
46
|
|
|
37
47
|
```typescript
|
|
38
48
|
ai: {
|
|
39
|
-
engine: 'claude-code',
|
|
49
|
+
engine: 'claude-code', // default 'claude-code'
|
|
40
50
|
claudeCode: {
|
|
41
|
-
path: '/usr/local/bin/claude',
|
|
42
|
-
pluginRoot: '.claude',
|
|
43
|
-
timeout: 120000,
|
|
44
|
-
skipPermissions: false,
|
|
45
|
-
defaultModel: 'claude-sonnet-4-6',
|
|
51
|
+
path: '/usr/local/bin/claude', // optional: custom claude binary path
|
|
52
|
+
pluginRoot: '.claude', // optional: plugin root directory
|
|
53
|
+
timeout: 120000, // optional: command timeout in ms
|
|
54
|
+
skipPermissions: false, // optional: skip permission prompts
|
|
55
|
+
defaultModel: 'claude-sonnet-4-6', // optional: default model
|
|
46
56
|
},
|
|
47
|
-
}
|
|
57
|
+
}
|
|
48
58
|
```
|
|
49
59
|
|
|
50
|
-
##
|
|
60
|
+
## ServerConfig
|
|
51
61
|
|
|
52
62
|
```typescript
|
|
53
63
|
server: {
|
|
@@ -55,48 +65,15 @@ server: {
|
|
|
55
65
|
host: '0.0.0.0',
|
|
56
66
|
cors: true, // default true
|
|
57
67
|
staticDir: './dist/frontend',
|
|
58
|
-
}
|
|
68
|
+
}
|
|
59
69
|
```
|
|
60
70
|
|
|
61
|
-
##
|
|
71
|
+
## DataConfig
|
|
62
72
|
|
|
63
73
|
```typescript
|
|
64
74
|
data: {
|
|
65
|
-
defaultAdapter: 'sqlite',
|
|
66
|
-
|
|
75
|
+
defaultAdapter: 'filesystem' | 'sqlite',
|
|
76
|
+
models: [...],
|
|
77
|
+
sqlite: { filename: 'data.db' }, // optional, default 'loom.db'
|
|
67
78
|
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## AI Buttons (Full Options)
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
aiButtons: [{
|
|
74
|
-
id: 'summarize', // required: unique identifier
|
|
75
|
-
label: '总结', // required: button text
|
|
76
|
-
icon: 'FileTextOutlined', // optional: Ant Design icon name
|
|
77
|
-
prompt: '请总结以下内容', // required: prompt text, supports {{var}} placeholders
|
|
78
|
-
// {{var}} is replaced with the current row's field value at runtime
|
|
79
|
-
placement: 'page-header', // optional: UI placement hint
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
id: 'analyze', // example with template variables
|
|
83
|
-
label: '分析',
|
|
84
|
-
prompt: '分析{{questionContent}},错误答案:{{wrongAnswer}}',
|
|
85
|
-
}],
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### AI Button Behavior
|
|
89
|
-
|
|
90
|
-
When configured, AI buttons are automatically integrated into CRUD page action columns:
|
|
91
|
-
|
|
92
|
-
1. Each table row shows an "AI" dropdown button with all configured buttons as menu items
|
|
93
|
-
2. Clicking a button opens the ChatDrawer and sends `buttonId` + row `context` to the server
|
|
94
|
-
3. Server resolves `prompt` with `{{fieldName}}` replaced by the current row's field values
|
|
95
|
-
4. Context fields not referenced in the template are automatically appended to the prompt
|
|
96
|
-
5. If AI performs CRUD via tool calls, the page auto-refreshes (via `loom:data-changed` event)
|
|
97
|
-
|
|
98
|
-
## Data Access in Skills
|
|
99
|
-
|
|
100
|
-
- `loom generate capabilities` 自动生成 `.claude/skills/<project-name>/SKILL.md`,包含模型 schema 和 CLI 命令
|
|
101
|
-
- AI 引擎(`claude -p`)自动发现并加载此 Skill
|
|
102
|
-
- 使用 `loom data` CLI 命令进行数据 CRUD:`read`、`write`、`update`、`delete`、`schema`
|
|
79
|
+
```
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Skill Development Reference
|
|
2
|
-
|
|
3
|
-
Guide for creating and managing Loom Skills. Load this when adding or editing `.claude/skills/`.
|
|
4
|
-
|
|
5
|
-
## Skill Structure
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
.claude/skills/<skill-name>/
|
|
9
|
-
├── SKILL.md # Required: trigger conditions + workflow
|
|
10
|
-
└── references/ # Optional: detailed rules and reference docs
|
|
11
|
-
└── *.md
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## SKILL.md Format
|
|
15
|
-
|
|
16
|
-
```markdown
|
|
17
|
-
---
|
|
18
|
-
name: <skill-name>
|
|
19
|
-
description: |
|
|
20
|
-
This skill should be used when the user asks to "<trigger phrases>".
|
|
21
|
-
Include both English and Chinese trigger phrases.
|
|
22
|
-
version: 1.0.0
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
# <Skill Name>
|
|
26
|
-
|
|
27
|
-
<Description of what this skill does>
|
|
28
|
-
|
|
29
|
-
## Workflow
|
|
30
|
-
|
|
31
|
-
1. <Step 1>
|
|
32
|
-
2. <Step 2>
|
|
33
|
-
|
|
34
|
-
## Rules
|
|
35
|
-
|
|
36
|
-
- <Rule 1>
|
|
37
|
-
- <Rule 2>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Best Practices
|
|
41
|
-
|
|
42
|
-
- Keep SKILL.md focused on one capability domain
|
|
43
|
-
- Use `references/` for detailed rules that would clutter the main SKILL.md
|
|
44
|
-
- Specify which MCP Tools (`read_<model>`, `write_<model>`) the skill should use
|
|
45
|
-
- Skills define behavior through prompts, not code generation
|
|
46
|
-
- Run `loom skill validate [name]` to check SKILL.md structure
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Troubleshooting Guide
|
|
2
|
-
|
|
3
|
-
Common issues when creating and running Loom projects.
|
|
4
|
-
|
|
5
|
-
## `loom generate` Fails: Cannot find module '@loom-framework/core'
|
|
6
|
-
|
|
7
|
-
Dependencies not installed. Run `npm install` from the project directory.
|
|
8
|
-
|
|
9
|
-
## `npx @loom-framework/core loom init` Fails
|
|
10
|
-
|
|
11
|
-
The `npx` command cannot find the executable. Use the `-p` flag to specify the package:
|
|
12
|
-
```bash
|
|
13
|
-
npx -p @loom-framework/core loom init <name> --description <desc> --adapter <adapter>
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## `loom dev` Port Already in Use (EADDRINUSE)
|
|
17
|
-
|
|
18
|
-
Previous process still running. Kill it: `lsof -ti:3000 | xargs kill -9`
|
|
19
|
-
|
|
20
|
-
## Commands Fail: "No loom.config.ts found"
|
|
21
|
-
|
|
22
|
-
Running from the wrong directory. `cd` into the project directory before running `loom` commands.
|
|
23
|
-
|
|
24
|
-
## Model Name Validation Error
|
|
25
|
-
|
|
26
|
-
Model names must match `^[a-z][a-z0-9_-]*$` (lowercase, hyphens/underscores allowed).
|
|
27
|
-
Field names must match `^[a-zA-Z_][a-zA-Z0-9_]*$`.
|
|
28
|
-
|
|
29
|
-
## `loom build` Backend TSC Fails: Cannot use JSX
|
|
30
|
-
|
|
31
|
-
Root `tsconfig.json` includes `frontend/` with `.tsx` files.
|
|
32
|
-
Add `"frontend"` to `exclude` in root `tsconfig.json`:
|
|
33
|
-
```json
|
|
34
|
-
{ "exclude": ["node_modules", "dist", "frontend"] }
|
|
35
|
-
```
|
|
36
|
-
Frontend has its own `frontend/tsconfig.json` with `jsx: "react-jsx"`.
|
|
37
|
-
|
|
38
|
-
## Debug Tips
|
|
39
|
-
|
|
40
|
-
- `loom data schema <model>` — inspect model fields
|
|
41
|
-
- `loom observe logs` — view AI interaction logs
|
|
42
|
-
- `loom skill validate` — check skill structure
|