openyida 2026.7.8 → 2026.7.10
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/package.json +1 -1
- package/scripts/postinstall.js +23 -23
- package/scripts/validate-skills.js +175 -0
- package/yida-skills/SKILL.md +68 -57
- package/yida-skills/references/development-rules.md +13 -9
- package/yida-skills/skills/large-file-write/SKILL.md +12 -10
- package/yida-skills/skills/large-file-write/references/write-patterns.md +13 -15
- package/yida-skills/skills/large-file-write/scripts/write.js +10 -10
- package/yida-skills/skills/yida-app/SKILL.md +92 -77
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +4 -2
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-design-system.md +1 -1
- package/yida-skills/skills/yida-canvas-upgrade/SKILL.md +1 -1
- package/yida-skills/skills/yida-chart/SKILL.md +4 -4
- package/yida-skills/skills/yida-chart/references/echarts-bindding-guide.md +6 -7
- package/yida-skills/skills/yida-chart/references/echarts-code-template.md +1 -1
- package/yida-skills/skills/yida-chart/references/echarts-design-spec.md +1 -1
- package/yida-skills/skills/yida-chart/references/examples.md +2 -2
- package/yida-skills/skills/yida-connector/SKILL.md +4 -0
- package/yida-skills/skills/yida-connector-safe-actions/SKILL.md +7 -4
- package/yida-skills/skills/yida-create-form-page/SKILL.md +11 -8
- package/yida-skills/skills/yida-create-process/SKILL.md +12 -6
- package/yida-skills/skills/yida-custom-page/SKILL.md +12 -6
- package/yida-skills/skills/yida-custom-page/references/coding-guide.md +1 -1
- package/yida-skills/skills/yida-custom-page/references/component-jsx-guide.md +3 -1
- package/yida-skills/skills/yida-custom-page/references/design-system.md +1 -1
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-data-management/SKILL.md +14 -11
- package/yida-skills/skills/yida-data-source-connectors/SKILL.md +3 -1
- package/yida-skills/skills/yida-flash-note-to-prd/references/examples.md +3 -2
- package/yida-skills/skills/yida-formula/references/examples.md +4 -4
- package/yida-skills/skills/yida-formula-evaluate/SKILL.md +4 -2
- package/yida-skills/skills/yida-get-schema/SKILL.md +14 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +4 -2
- package/yida-skills/skills/yida-integration/SKILL.md +5 -2
- package/yida-skills/skills/yida-integration/references/examples.md +2 -2
- package/yida-skills/skills/yida-openyida-publish-guard/SKILL.md +2 -2
- package/yida-skills/skills/yida-page-uiux/SKILL.md +1 -1
- package/yida-skills/skills/yida-page-uiux/workflow/step-0-nav-shape.md +2 -2
- package/yida-skills/skills/yida-ppt/SKILL.md +2 -2
- package/yida-skills/skills/yida-ppt-slider/SKILL.md +1 -1
- package/yida-skills/skills/yida-ppt-slider/references/echarts-race-example.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +5 -2
- package/yida-skills/skills/yida-process-rule/references/examples.md +12 -12
- package/yida-skills/skills/yida-publish-page/SKILL.md +2 -2
- package/yida-skills/skills/yida-report/SKILL.md +5 -2
- package/yida-skills/skills/yida-report/references/examples.md +4 -4
- package/yida-skills/skills/yida-table-form/references/examples.md +3 -3
- package/yida-skills/skills-index.json +430 -0
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -251,32 +251,32 @@ openyida copy
|
|
|
251
251
|
|
|
252
252
|
## 子技能索引
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
根据用户意图选择最匹配的子技能。支持 \`use_skill\` / \`search_skills\` 的宿主中,必须调用 \`use_skill("<技能名>", "<本次目的>")\` 加载子技能;不要用 Read / read_file / cat 读取 SKILL.md 路径。\`skills-index.json\` 仅供 yida-agent 或同构宿主机器发现,不支持该索引的宿主忽略它。完全没有 \`use_skill\` 的本地工具,才允许按根技能路由表和技能包相对路径逐个读取当前阶段唯一必要的 SKILL.md,禁止并发批量读取多个 SKILL.md。
|
|
255
255
|
|
|
256
256
|
| 意图 | 子技能 |
|
|
257
257
|
| --- | --- |
|
|
258
|
-
| 完整应用开发编排 |
|
|
259
|
-
| 登录态管理 |
|
|
260
|
-
| 退出登录 / 切换账号 |
|
|
261
|
-
| 创建应用 |
|
|
262
|
-
| 创建自定义页面 |
|
|
263
|
-
| 创建 / 更新表单页面 |
|
|
264
|
-
| 创建流程表单 |
|
|
265
|
-
| 获取单个 / 全部表单 Schema |
|
|
266
|
-
| 自定义页面 JSX 开发 |
|
|
267
|
-
| 发布自定义页面 |
|
|
268
|
-
| 页面公开访问 / 分享配置 |
|
|
269
|
-
| 表单权限 |
|
|
270
|
-
| 数据查询与管理 |
|
|
271
|
-
| 流程规则 |
|
|
272
|
-
| 集成自动化 |
|
|
273
|
-
| HTTP 连接器 |
|
|
274
|
-
| 图表页面 |
|
|
275
|
-
| 原生报表 |
|
|
276
|
-
| 公式字段 |
|
|
277
|
-
| 公式静态检查 |
|
|
278
|
-
| VOC 反馈整理 |
|
|
279
|
-
| 闪记 / 会议纪要转 PRD |
|
|
258
|
+
| 完整应用开发编排 | \`yida-app\` |
|
|
259
|
+
| 登录态管理 | \`yida-login\` |
|
|
260
|
+
| 退出登录 / 切换账号 | \`yida-logout\` |
|
|
261
|
+
| 创建应用 | \`yida-create-app\` |
|
|
262
|
+
| 创建自定义页面 | \`yida-create-page\` |
|
|
263
|
+
| 创建 / 更新表单页面 | \`yida-create-form-page\` |
|
|
264
|
+
| 创建流程表单 | \`yida-create-process\` |
|
|
265
|
+
| 获取单个 / 全部表单 Schema | \`yida-get-schema\` |
|
|
266
|
+
| 自定义页面 JSX 开发 | \`yida-custom-page\` |
|
|
267
|
+
| 发布自定义页面 | \`yida-publish-page\` |
|
|
268
|
+
| 页面公开访问 / 分享配置 | \`yida-page-config\` |
|
|
269
|
+
| 表单权限 | \`yida-form-permission\` |
|
|
270
|
+
| 数据查询与管理 | \`yida-data-management\` |
|
|
271
|
+
| 流程规则 | \`yida-process-rule\` |
|
|
272
|
+
| 集成自动化 | \`yida-integration\` |
|
|
273
|
+
| HTTP 连接器 | \`yida-connector\` |
|
|
274
|
+
| 图表页面 | \`yida-chart\` |
|
|
275
|
+
| 原生报表 | \`yida-report\` |
|
|
276
|
+
| 公式字段 | \`yida-formula\` |
|
|
277
|
+
| 公式静态检查 | \`yida-formula-evaluate\` |
|
|
278
|
+
| VOC 反馈整理 | \`yida-voc\` |
|
|
279
|
+
| 闪记 / 会议纪要转 PRD | \`yida-flash-note-to-prd\` |
|
|
280
280
|
|
|
281
281
|
## 执行规则
|
|
282
282
|
|
|
@@ -9,6 +9,7 @@ const ROOT = path.resolve(__dirname, '..');
|
|
|
9
9
|
const SKILLS_ROOT = path.join(ROOT, 'yida-skills');
|
|
10
10
|
const SKILLS_DIR = path.join(SKILLS_ROOT, 'skills');
|
|
11
11
|
const INDEX_FILE = path.join(SKILLS_ROOT, 'SKILL.md');
|
|
12
|
+
const SKILLS_INDEX_FILE = path.join(SKILLS_ROOT, 'skills-index.json');
|
|
12
13
|
const MAX_RECOMMENDED_LINES = 500;
|
|
13
14
|
|
|
14
15
|
const errors = [];
|
|
@@ -22,6 +23,10 @@ function readText(filePath) {
|
|
|
22
23
|
return fs.readFileSync(filePath, 'utf8');
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
function readJson(filePath) {
|
|
27
|
+
return JSON.parse(readText(filePath));
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
function collectMarkdownFiles(dir, files) {
|
|
26
31
|
if (!fs.existsSync(dir)) {
|
|
27
32
|
return;
|
|
@@ -159,6 +164,158 @@ function validateIndexEntry(skillDirName, skillFile) {
|
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
166
|
|
|
167
|
+
function validateSkillsIndex(skillDirNames) {
|
|
168
|
+
if (!fs.existsSync(SKILLS_INDEX_FILE)) {
|
|
169
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': missing machine-readable skills index');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let index;
|
|
174
|
+
try {
|
|
175
|
+
index = readJson(SKILLS_INDEX_FILE);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': invalid JSON: ' + error.message);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (index.version !== 1) {
|
|
182
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': version must be 1');
|
|
183
|
+
}
|
|
184
|
+
if (index.source !== 'openyida') {
|
|
185
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': source must be "openyida"');
|
|
186
|
+
}
|
|
187
|
+
if (index.entry !== 'openyida') {
|
|
188
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': entry must be "openyida"');
|
|
189
|
+
}
|
|
190
|
+
if (!Array.isArray(index.skills)) {
|
|
191
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': skills must be an array');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const expectedPaths = new Set(skillDirNames.map(function(skillDirName) {
|
|
196
|
+
return 'skills/' + skillDirName + '/SKILL.md';
|
|
197
|
+
}));
|
|
198
|
+
const seenNames = new Set();
|
|
199
|
+
const seenPaths = new Set();
|
|
200
|
+
|
|
201
|
+
for (let i = 0; i < index.skills.length; i++) {
|
|
202
|
+
const entry = index.skills[i];
|
|
203
|
+
const entryLabel = toRelative(SKILLS_INDEX_FILE) + ': skills[' + i + ']';
|
|
204
|
+
|
|
205
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
206
|
+
errors.push(entryLabel + ': entry must be an object');
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!entry.name || typeof entry.name !== 'string') {
|
|
211
|
+
errors.push(entryLabel + ': missing string field "name"');
|
|
212
|
+
} else if (seenNames.has(entry.name)) {
|
|
213
|
+
errors.push(entryLabel + ': duplicate name "' + entry.name + '"');
|
|
214
|
+
} else {
|
|
215
|
+
seenNames.add(entry.name);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!entry.path || typeof entry.path !== 'string') {
|
|
219
|
+
errors.push(entryLabel + ': missing string field "path"');
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (seenPaths.has(entry.path)) {
|
|
223
|
+
errors.push(entryLabel + ': duplicate path "' + entry.path + '"');
|
|
224
|
+
} else {
|
|
225
|
+
seenPaths.add(entry.path);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (!/^skills\/[a-z0-9-]+\/SKILL\.md$/.test(entry.path)) {
|
|
229
|
+
errors.push(entryLabel + ': path must look like skills/<skill-name>/SKILL.md');
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const skillFile = path.join(SKILLS_ROOT, entry.path);
|
|
234
|
+
if (!fs.existsSync(skillFile)) {
|
|
235
|
+
errors.push(entryLabel + ': path does not exist: ' + entry.path);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const content = readText(skillFile);
|
|
240
|
+
const frontmatter = parseFrontmatter(content);
|
|
241
|
+
const frontmatterName = frontmatter ? frontmatterField(frontmatter, 'name') : null;
|
|
242
|
+
if (frontmatterName && entry.name !== frontmatterName) {
|
|
243
|
+
errors.push(entryLabel + ': name "' + entry.name + '" does not match frontmatter name "' + frontmatterName + '"');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const pathSkillName = entry.path.split('/')[1];
|
|
247
|
+
if (entry.name && entry.name !== pathSkillName) {
|
|
248
|
+
errors.push(entryLabel + ': name "' + entry.name + '" does not match path skill name "' + pathSkillName + '"');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!entry.display_name || typeof entry.display_name !== 'string') {
|
|
252
|
+
errors.push(entryLabel + ': missing string field "display_name"');
|
|
253
|
+
}
|
|
254
|
+
if (!entry.description || typeof entry.description !== 'string') {
|
|
255
|
+
errors.push(entryLabel + ': missing string field "description"');
|
|
256
|
+
}
|
|
257
|
+
if (!entry.category || typeof entry.category !== 'string') {
|
|
258
|
+
errors.push(entryLabel + ': missing string field "category"');
|
|
259
|
+
}
|
|
260
|
+
if (!Array.isArray(entry.tags) || entry.tags.length === 0) {
|
|
261
|
+
errors.push(entryLabel + ': tags must be a non-empty array');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
for (const expectedPath of expectedPaths) {
|
|
266
|
+
if (!seenPaths.has(expectedPath)) {
|
|
267
|
+
errors.push(toRelative(SKILLS_INDEX_FILE) + ': missing skill path "' + expectedPath + '"');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function validateSkillLoadingInstructions(instructionFiles) {
|
|
273
|
+
const forbiddenPatterns = [
|
|
274
|
+
{
|
|
275
|
+
pattern: /skills\/[a-z0-9-]+\/SKILL\.md/,
|
|
276
|
+
message: 'must load subskills via use_skill instead of source skill paths',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
pattern: /\.\.\/[a-z0-9-]+\/SKILL\.md/,
|
|
280
|
+
message: 'must load sibling subskills via use_skill instead of relative SKILL.md paths',
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
pattern: /(?:先读|先读取|完整读取|完整学习|读它的|详见|参考|查阅).{0,60}SKILL\.md/,
|
|
284
|
+
message: 'must not instruct agents to read SKILL.md directly',
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
pattern: /未读取.{0,60}SKILL\.md/,
|
|
288
|
+
message: 'must express prerequisites as loaded skills, not direct SKILL.md reads',
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
pattern: /一次性(?:读取|加载).{0,40}(?:全部|多个|全量).{0,20}技能|全部技能文档/,
|
|
292
|
+
message: 'must not describe bulk loading multiple skills',
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
for (const instructionFile of instructionFiles) {
|
|
297
|
+
const content = readText(instructionFile);
|
|
298
|
+
const lines = content.split(/\r?\n/);
|
|
299
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
300
|
+
const line = lines[lineIndex];
|
|
301
|
+
const isAllowedFallback = /没有\s*`?use_skill\/search_skills`?|当前阶段唯一必要/.test(line);
|
|
302
|
+
const isAllowedBan = /禁止.*(?:Read|read_file|cat).*SKILL\.md/.test(line);
|
|
303
|
+
if (isAllowedFallback || isAllowedBan) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
for (const rule of forbiddenPatterns) {
|
|
308
|
+
if (rule.pattern.test(line)) {
|
|
309
|
+
errors.push(
|
|
310
|
+
toRelative(instructionFile) + ':' + (lineIndex + 1) + ': ' + rule.message
|
|
311
|
+
);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
162
319
|
function isExternalLink(target) {
|
|
163
320
|
return /^(https?:|mailto:|tel:|app:\/\/|plugin:\/\/|#)/i.test(target);
|
|
164
321
|
}
|
|
@@ -220,6 +377,7 @@ function run() {
|
|
|
220
377
|
return fs.statSync(fullPath).isDirectory();
|
|
221
378
|
}).sort();
|
|
222
379
|
|
|
380
|
+
const skillDirNamesWithSkillFile = [];
|
|
223
381
|
for (const skillDirName of skillDirNames) {
|
|
224
382
|
const skillFile = path.join(SKILLS_DIR, skillDirName, 'SKILL.md');
|
|
225
383
|
if (!fs.existsSync(skillFile)) {
|
|
@@ -227,9 +385,12 @@ function run() {
|
|
|
227
385
|
continue;
|
|
228
386
|
}
|
|
229
387
|
|
|
388
|
+
skillDirNamesWithSkillFile.push(skillDirName);
|
|
230
389
|
validateSkillFrontmatter(skillDirName, skillFile);
|
|
231
390
|
validateIndexEntry(skillDirName, skillFile);
|
|
232
391
|
}
|
|
392
|
+
|
|
393
|
+
validateSkillsIndex(skillDirNamesWithSkillFile);
|
|
233
394
|
}
|
|
234
395
|
|
|
235
396
|
const markdownFiles = [];
|
|
@@ -238,6 +399,20 @@ function run() {
|
|
|
238
399
|
validateMarkdownLinks(markdownFile);
|
|
239
400
|
}
|
|
240
401
|
|
|
402
|
+
const instructionFiles = [INDEX_FILE];
|
|
403
|
+
if (fs.existsSync(SKILLS_DIR)) {
|
|
404
|
+
const skillDirNames = fs.readdirSync(SKILLS_DIR).filter(function(name) {
|
|
405
|
+
return fs.statSync(path.join(SKILLS_DIR, name)).isDirectory();
|
|
406
|
+
}).sort();
|
|
407
|
+
for (const skillDirName of skillDirNames) {
|
|
408
|
+
const skillFile = path.join(SKILLS_DIR, skillDirName, 'SKILL.md');
|
|
409
|
+
if (fs.existsSync(skillFile)) {
|
|
410
|
+
instructionFiles.push(skillFile);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
validateSkillLoadingInstructions(instructionFiles);
|
|
415
|
+
|
|
241
416
|
if (warnings.length > 0) {
|
|
242
417
|
console.warn('Skill validation warnings:');
|
|
243
418
|
for (const warning of warnings) {
|
package/yida-skills/SKILL.md
CHANGED
|
@@ -12,6 +12,15 @@ description: >
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
+
## 宿主能力适配
|
|
16
|
+
|
|
17
|
+
- 如果当前宿主提供 `use_skill` / `search_skills`:必须通过 `use_skill("<技能名>", "<本阶段目的>")` 加载主技能和子技能,禁止用 `Read` / `read_file` / `cat` 读取 `SKILL.md` 路径;`use_skill` 会稳定返回技能内容和可读取的辅助文件列表。
|
|
18
|
+
- `skills-index.json` 仅供 yida-agent 或同构宿主做机器可读发现;不支持该索引的宿主忽略它,不要把它当作运行前置条件。
|
|
19
|
+
- 如果当前宿主没有 `use_skill` / `search_skills`:按本文的技能路由表选定技能名,再按技能包相对路径逐个读取当前阶段唯一必要的 `SKILL.md`;禁止并发批量读取多个 `SKILL.md`;禁止预读未来阶段技能。
|
|
20
|
+
- `references/`、`scripts/`、`assets/` 等辅助文件只能在已加载对应技能后按需读取。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
15
24
|
## 第一步:环境与登录态检测(必做必读,先于一切操作)
|
|
16
25
|
|
|
17
26
|
> ⚡ **前置门槛**:确认 openyida 已安装、Node/npm 依赖达标、登录态就绪。**未通过只读验证前,禁止创建应用/页面/表单或发布等任何真实资源操作。**
|
|
@@ -36,13 +45,14 @@ description: >
|
|
|
36
45
|
| 用户诉求信号 | 判定 | 走哪条路线 |
|
|
37
46
|
|------------|------|-----------|
|
|
38
47
|
| 创建/搭建/做一个 + 应用/系统/管理系统;或明确表达从零开始 | **全量搭建** | 走 [完整开发流程](#完整开发流程全量搭建),从 Step 1 顺序执行 |
|
|
39
|
-
| 对已有应用/表单/页面的单点操作(加字段、查改数据、配公式、建报表、改权限、发布、美化…) | **单一 / 增量任务** | 到 [技能路由](#技能路由单一--增量任务) 选定 **1
|
|
48
|
+
| 对已有应用/表单/页面的单点操作(加字段、查改数据、配公式、建报表、改权限、发布、美化…) | **单一 / 增量任务** | 到 [技能路由](#技能路由单一--增量任务) 选定 **1 个**,加载对应子技能执行,不回退流程 |
|
|
40
49
|
|
|
41
50
|
---
|
|
42
51
|
|
|
43
52
|
## 完整开发流程(全量搭建)
|
|
44
53
|
|
|
45
54
|
> 📌 仅当第二步判定为「全量搭建」时进入;单一/增量任务请跳「技能路由」。
|
|
55
|
+
> 在支持 `use_skill` 的宿主中,先加载 `yida-app` 流程编排技能;进入每个阶段前,再加载该阶段唯一需要的子技能,不要预读未来阶段技能。
|
|
46
56
|
|
|
47
57
|
```
|
|
48
58
|
[Step 1] 创建应用 → openyida create-app → 获得 appType
|
|
@@ -50,9 +60,9 @@ description: >
|
|
|
50
60
|
[Step 2] 需求分析 → 写入 prd/<项目名>.md
|
|
51
61
|
↓ (必须含 MVP 边界、角色权限、核心旅程、状态机、数据约束、验收标准)
|
|
52
62
|
↓
|
|
53
|
-
[Step 3]
|
|
63
|
+
[Step 3](按需)创建/更新表单 → openyida create-form → 获得 formUuid + fieldId(表单)
|
|
54
64
|
↓
|
|
55
|
-
[Step 4]
|
|
65
|
+
[Step 4] 创建自定义页面 → openyida create-page → 获得 formUuid(看板用 --mode dashboard)
|
|
56
66
|
↓
|
|
57
67
|
[Step 5] 编写自定义页面代码 → 先按「自定义页面选路」定链路(**默认 Code Canvas yida-canvas-custom-page**,含开放 API 读数据页;仅强依赖原生实例数据桥的页回退 native yida-custom-page)
|
|
58
68
|
↓ (首次生成面向用户的页必做:先用 yida-page-uiux 产出「视觉方向决策块」,避免统一灰白圆角的 AI 味模板脸,再交所选链路落地)
|
|
@@ -70,18 +80,18 @@ description: >
|
|
|
70
80
|
[Step 10] 输出访问链接,用系统浏览器打开
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
> **Step 5 先定视觉方向(首次生成面向用户页必做)**:写 JSX
|
|
83
|
+
> **Step 5 先定视觉方向(首次生成面向用户页必做)**:写 JSX 前调用 `use_skill("yida-page-uiux", "确定自定义页面视觉方向并产出决策块")` 锁定视觉方向(页面类型判定 → 意图解码 → 差异化决策 → 去 AI 味自检),产出「视觉方向决策块」,再交所选链路(默认 `yida-canvas-custom-page`,回退 `yida-custom-page`)按 `design-system.md` token 落地。跳过此步会直接套用统一灰白圆角模板,生成有 AI 味的平庸页面。
|
|
74
84
|
>
|
|
75
|
-
> **Step 7
|
|
85
|
+
> **Step 7 导航整理(含看板/多页面时必做)**:首次生成完整应用后,必须基于业务信息架构重排导航,不能保留创建时的默认顺序。默认原则:面向决策者的**总览/驾驶舱看板作为应用门面靠前**,数据录入/明细表单在其后;同级多个专题看板按业务优先级排,不要把所有页面无脑堆最前。进入本阶段前调用 `use_skill("yida-nav-group", "整理应用导航顺序")`。
|
|
76
86
|
>
|
|
77
|
-
> **Step 8 灌入示例数据(有表单时默认执行)**:新建应用的表单默认无数据,看板会空。导航整理完成后,默认向核心表单灌入 **2-3 条**覆盖关键维度(如不同活动/渠道/日期)的示例记录,让看板首屏可展示真实聚合效果。`DateField`/`CascadeDateField` 必须用 13 位毫秒时间戳;灌后执行 `openyida data query` 抽查至少 1
|
|
87
|
+
> **Step 8 灌入示例数据(有表单时默认执行)**:新建应用的表单默认无数据,看板会空。导航整理完成后,默认向核心表单灌入 **2-3 条**覆盖关键维度(如不同活动/渠道/日期)的示例记录,让看板首屏可展示真实聚合效果。`DateField`/`CascadeDateField` 必须用 13 位毫秒时间戳;灌后执行 `openyida data query` 抽查至少 1 条,确认字段值非空。进入本阶段前调用 `use_skill("yida-data-management", "写入和抽查示例数据")`。
|
|
78
88
|
|
|
79
89
|
---
|
|
80
90
|
|
|
81
91
|
## 技能路由(单一 / 增量任务)
|
|
82
92
|
|
|
83
93
|
> 选定 **1 个**最匹配的项执行。表**按业务域分组**,每组内既可能是 skill 也可能是 CLI:
|
|
84
|
-
> - 行名为 `yida-xxx` / `sls-log-workbench` / `large-file-write` 的是 **skill** →
|
|
94
|
+
> - 行名为 `yida-xxx` / `sls-log-workbench` / `large-file-write` 的是 **skill** → 在支持 `use_skill` 的宿主中调用 `use_skill("<技能名>", "<本次目的>")` 加载后执行;
|
|
85
95
|
> - 行名为 `openyida xxx` 并标 **`CLI`** 的**无 SKILL.md** → 识别到诉求直接执行命令、**不要当 skill 去 read**。
|
|
86
96
|
>
|
|
87
97
|
> 按分组 +「何时选择」内联区别对号入座即可。
|
|
@@ -95,56 +105,56 @@ description: >
|
|
|
95
105
|
>
|
|
96
106
|
> 依据(源码核实):Canvas 代码在宿主页真实 `window` 中 `new Function` 执行,但物料只透传 `code/runtimeCode/importedModules/pageType`,**无 `this` 上下文、无 `dataSourceMap`**,`this.utils.yida.*` 不可用;宿主 window 全局(`__yida_plugin_runtime__` 插件系统、`__VcDeepYidaUtils__`)均非表单数据桥,也无 `window.Deep` 字段组件。Canvas 读宜搭数据 = 在 `YidaComp` 内自写 HTTP 调开放 API。只有需要免费 `this` 实例桥的页才留 native。
|
|
97
107
|
|
|
98
|
-
| 分组 |
|
|
108
|
+
| 分组 | 加载目标 | 何时选择(关键区别已内联) |
|
|
99
109
|
|------|------|--------------------------|
|
|
100
|
-
| **应用与登录** | `yida-app` | 从零搭建整个应用(多步骤全流程编排) |
|
|
101
|
-
| | `yida-create-app` | 只需创建应用、拿 appType |
|
|
102
|
-
| | `yida-login` | 手动触发登录(通常自动触发) |
|
|
103
|
-
| | `yida-logout` | 切换账号或组织 |
|
|
104
|
-
| **页面与表单** | `yida-create-page` | 创建空白自定义页面拿 formUuid,后续写 JSX |
|
|
105
|
-
| | `yida-create-form-page` | 创建/更新表单、增删改**字段结构**(普通表单,无审批) |
|
|
106
|
-
| | `yida-create-process` | 从零建**带审批**流程表单(表单还不存在,一步到位) |
|
|
107
|
-
| | `yida-page-uiux` | 写自定义页面 UI 前先定视觉方向、去 AI 味(工作台/看板/列表/详情/官网落地页;产出决策块,不写代码;canvas / native 两链路通用) |
|
|
108
|
-
| | `yida-canvas-custom-page` | **自定义页面默认链路**:现代 React 交互 / hooks / 可视化 / AI 页,含只需开放 API HTTP 读数据的页(Code Canvas,`runtimeCode` + `importedModules`,真 React18 + 崩溃隔离) |
|
|
109
|
-
| | `yida-custom-page` | 回退项:仅当强依赖原生实例数据桥(`this.$(fieldId)` 双向绑定 / `this.utils.yida.*` / `dataSourceMap` / 提交流程深度耦合)时才用(native `.oyd.jsx` 链路) |
|
|
110
|
-
| | `yida-canvas-upgrade` | 将已有普通 `.oyd.jsx` / `Jsx` 页面升级迁移到 Code Canvas / `YidaCodeCanvas` 链路 |
|
|
111
|
-
| | `yida-nav-shell` | 自定义页**隐藏应用导航**(`isRenderNav=false`,沉浸/门户/大屏/分享)后,页面内用 JSX 自绘侧边/顶部/浮动/标签导航壳;发布后要配置隐藏原导航,跨页导航项要拼完整 URL 并合并 `isRenderNav=false` / `corpid` / 业务参数(**区别** `yida-nav-group` 平台左侧菜单分组:那是真实导航树,本项是页面内自建导航) |
|
|
112
|
-
| | `yida-publish-page` | JSX 写完后编译并发布 |
|
|
113
|
-
| | `yida-openyida-publish-guard` | 发布已有自定义页面前检查线上设计器状态,避免本地旧源码覆盖用户在线改动 |
|
|
114
|
-
| | `yida-table-form` | Excel 式表格批量录入提交 |
|
|
115
|
-
| | `yida-ppt-slider` | 全屏幻灯片页面(分享/路演/培训/演示) |
|
|
110
|
+
| **应用与登录** | 加载子技能 `yida-app` | 从零搭建整个应用(多步骤全流程编排) |
|
|
111
|
+
| | 加载子技能 `yida-create-app` | 只需创建应用、拿 appType |
|
|
112
|
+
| | 加载子技能 `yida-login` | 手动触发登录(通常自动触发) |
|
|
113
|
+
| | 加载子技能 `yida-logout` | 切换账号或组织 |
|
|
114
|
+
| **页面与表单** | 加载子技能 `yida-create-page` | 创建空白自定义页面拿 formUuid,后续写 JSX |
|
|
115
|
+
| | 加载子技能 `yida-create-form-page` | 创建/更新表单、增删改**字段结构**(普通表单,无审批) |
|
|
116
|
+
| | 加载子技能 `yida-create-process` | 从零建**带审批**流程表单(表单还不存在,一步到位) |
|
|
117
|
+
| | 加载子技能 `yida-page-uiux` | 写自定义页面 UI 前先定视觉方向、去 AI 味(工作台/看板/列表/详情/官网落地页;产出决策块,不写代码;canvas / native 两链路通用) |
|
|
118
|
+
| | 加载子技能 `yida-canvas-custom-page` | **自定义页面默认链路**:现代 React 交互 / hooks / 可视化 / AI 页,含只需开放 API HTTP 读数据的页(Code Canvas,`runtimeCode` + `importedModules`,真 React18 + 崩溃隔离) |
|
|
119
|
+
| | 加载子技能 `yida-custom-page` | 回退项:仅当强依赖原生实例数据桥(`this.$(fieldId)` 双向绑定 / `this.utils.yida.*` / `dataSourceMap` / 提交流程深度耦合)时才用(native `.oyd.jsx` 链路) |
|
|
120
|
+
| | 加载子技能 `yida-canvas-upgrade` | 将已有普通 `.oyd.jsx` / `Jsx` 页面升级迁移到 Code Canvas / `YidaCodeCanvas` 链路 |
|
|
121
|
+
| | 加载子技能 `yida-nav-shell` | 自定义页**隐藏应用导航**(`isRenderNav=false`,沉浸/门户/大屏/分享)后,页面内用 JSX 自绘侧边/顶部/浮动/标签导航壳;发布后要配置隐藏原导航,跨页导航项要拼完整 URL 并合并 `isRenderNav=false` / `corpid` / 业务参数(**区别** `yida-nav-group` 平台左侧菜单分组:那是真实导航树,本项是页面内自建导航) |
|
|
122
|
+
| | 加载子技能 `yida-publish-page` | JSX 写完后编译并发布 |
|
|
123
|
+
| | 加载子技能 `yida-openyida-publish-guard` | 发布已有自定义页面前检查线上设计器状态,避免本地旧源码覆盖用户在线改动 |
|
|
124
|
+
| | 加载子技能 `yida-table-form` | Excel 式表格批量录入提交 |
|
|
125
|
+
| | 加载子技能 `yida-ppt-slider` | 全屏幻灯片页面(分享/路演/培训/演示) |
|
|
116
126
|
| | `openyida aggregate-table` `CLI` | 聚合表 / 虚拟视图(virtualView):`list` 列出 · `create-empty` 建空白(返回设计器 URL)· `preview` 预览不保存 · `publish` 发布配置 |
|
|
117
|
-
| **数据可视化** | `yida-report` | 普通报表/统计,开箱即用(原生 16 组件) |
|
|
118
|
-
| | `yida-chart` | 更美观/定制化/数据大屏(ECharts) |
|
|
119
|
-
| | `yida-dashboard` | 完整看板 / 驾驶舱产品化交付 |
|
|
120
|
-
| **连接器** | `yida-connector` | 创建/管理连接器、配鉴权 |
|
|
121
|
-
| | `yida-connector-safe-actions` | 连接器已有,从 API 代码生成执行动作 |
|
|
122
|
-
| | `yida-data-source-connectors` | 自定义页面中通过数据源调用连接器 |
|
|
123
|
-
| **数据与公式** | `yida-data-management` | 增删改查**数据记录**,不动字段结构 |
|
|
124
|
-
| | `yida-get-schema` | **只读**查 Schema / 字段 ID,不改结构 |
|
|
125
|
-
| | `yida-formula` | 配在**字段属性**上的实时计算/默认值/校验 |
|
|
126
|
-
| | `yida-formula-evaluate` | 公式语法与字段引用静态检查 |
|
|
127
|
-
| | `yida-business-rule` | 提交后**跨表**高级函数 INSERT/UPDATE/DELETE |
|
|
128
|
-
| **流程与自动化** | `yida-process-rule` | **改已有**流程节点/分支/字段权限(表单已存在) |
|
|
129
|
-
| | `yida-integration` | 提交后**逻辑编排**(图形化自动化流,推荐) |
|
|
130
|
-
| | `yida-agent-center` | 流程代理(在职/离职代理人) |
|
|
127
|
+
| **数据可视化** | 加载子技能 `yida-report` | 普通报表/统计,开箱即用(原生 16 组件) |
|
|
128
|
+
| | 加载子技能 `yida-chart` | 更美观/定制化/数据大屏(ECharts) |
|
|
129
|
+
| | 加载子技能 `yida-dashboard` | 完整看板 / 驾驶舱产品化交付 |
|
|
130
|
+
| **连接器** | 加载子技能 `yida-connector` | 创建/管理连接器、配鉴权 |
|
|
131
|
+
| | 加载子技能 `yida-connector-safe-actions` | 连接器已有,从 API 代码生成执行动作 |
|
|
132
|
+
| | 加载子技能 `yida-data-source-connectors` | 自定义页面中通过数据源调用连接器 |
|
|
133
|
+
| **数据与公式** | 加载子技能 `yida-data-management` | 增删改查**数据记录**,不动字段结构 |
|
|
134
|
+
| | 加载子技能 `yida-get-schema` | **只读**查 Schema / 字段 ID,不改结构 |
|
|
135
|
+
| | 加载子技能 `yida-formula` | 配在**字段属性**上的实时计算/默认值/校验 |
|
|
136
|
+
| | 加载子技能 `yida-formula-evaluate` | 公式语法与字段引用静态检查 |
|
|
137
|
+
| | 加载子技能 `yida-business-rule` | 提交后**跨表**高级函数 INSERT/UPDATE/DELETE |
|
|
138
|
+
| **流程与自动化** | 加载子技能 `yida-process-rule` | **改已有**流程节点/分支/字段权限(表单已存在) |
|
|
139
|
+
| | 加载子技能 `yida-integration` | 提交后**逻辑编排**(图形化自动化流,推荐) |
|
|
140
|
+
| | 加载子技能 `yida-agent-center` | 流程代理(在职/离职代理人) |
|
|
131
141
|
| | `openyida ai-form-setting` `CLI` | 流程表单 AI 审批提示:`models` 查模型 · `fields` 查可插入字段(TEXT/IMAGE/ATTACHMENT)· `get` 查配置 |
|
|
132
|
-
| **权限与访问** | `yida-corp-manager` | **组织级**权限(平台/子管理员、通讯录,影响整个组织) |
|
|
133
|
-
| | `yida-app-permission` | **单应用级**权限(应用管理员/开发成员) |
|
|
134
|
-
| | `yida-form-permission` | **单表单级**权限(权限组/数据范围) |
|
|
135
|
-
| | `yida-page-config` | **页面级**:公开访问 / 组织内分享 |
|
|
136
|
-
| **应用配置与平台** | `yida-nav-group` | 应用**左侧菜单**分组/排序(真实导航树;页面内自绘导航壳见 `yida-nav-shell`) |
|
|
137
|
-
| | `yida-form-detail` | 只注 **CSS** 美化详情页,不改字段 |
|
|
138
|
-
| | `yida-density` | 列表/表格信息密度选择 |
|
|
139
|
-
| | `yida-i18n` | 应用多语言 / 国际化 |
|
|
140
|
-
| | `yida-basic-info` | 组织版本/容量/域名/额度查询 |
|
|
141
|
-
| | `yida-corp-efficiency` | 企业效能 / 低代码学习成果 |
|
|
142
|
-
| **辅助工具** | `yida-flash-note-to-prd` | 会议纪要/闪记转 PRD |
|
|
143
|
-
| | `yida-export-conversation` | 导出当前对话为 Markdown |
|
|
144
|
-
| | `yida-voc` | 整理故障/需求反馈材料 |
|
|
145
|
-
| | `sls-log-workbench` | SLS 平台问题日志查询 |
|
|
146
|
-
| | `yida-db-seq-fix` | PostgreSQL 主键冲突 / Sequence 修复 |
|
|
147
|
-
| | `large-file-write` | 可靠写入 100+ 行大文件 |
|
|
142
|
+
| **权限与访问** | 加载子技能 `yida-corp-manager` | **组织级**权限(平台/子管理员、通讯录,影响整个组织) |
|
|
143
|
+
| | 加载子技能 `yida-app-permission` | **单应用级**权限(应用管理员/开发成员) |
|
|
144
|
+
| | 加载子技能 `yida-form-permission` | **单表单级**权限(权限组/数据范围) |
|
|
145
|
+
| | 加载子技能 `yida-page-config` | **页面级**:公开访问 / 组织内分享 |
|
|
146
|
+
| **应用配置与平台** | 加载子技能 `yida-nav-group` | 应用**左侧菜单**分组/排序(真实导航树;页面内自绘导航壳见 `yida-nav-shell`) |
|
|
147
|
+
| | 加载子技能 `yida-form-detail` | 只注 **CSS** 美化详情页,不改字段 |
|
|
148
|
+
| | 加载子技能 `yida-density` | 列表/表格信息密度选择 |
|
|
149
|
+
| | 加载子技能 `yida-i18n` | 应用多语言 / 国际化 |
|
|
150
|
+
| | 加载子技能 `yida-basic-info` | 组织版本/容量/域名/额度查询 |
|
|
151
|
+
| | 加载子技能 `yida-corp-efficiency` | 企业效能 / 低代码学习成果 |
|
|
152
|
+
| **辅助工具** | 加载子技能 `yida-flash-note-to-prd` | 会议纪要/闪记转 PRD |
|
|
153
|
+
| | 加载子技能 `yida-export-conversation` | 导出当前对话为 Markdown |
|
|
154
|
+
| | 加载子技能 `yida-voc` | 整理故障/需求反馈材料 |
|
|
155
|
+
| | 加载子技能 `sls-log-workbench` | SLS 平台问题日志查询 |
|
|
156
|
+
| | 加载子技能 `yida-db-seq-fix` | PostgreSQL 主键冲突 / Sequence 修复 |
|
|
157
|
+
| | 加载子技能 `large-file-write` | 可靠写入 100+ 行大文件 |
|
|
148
158
|
| | `openyida ai` `CLI` | 调用宜搭 AI 通用能力:文生文(文本生成)/ 识图(图片识别) |
|
|
149
159
|
| | `openyida batch` `CLI` | 批量顺序执行多条 OpenYida 命令(读 tasks 文件,支持 `--json --quiet`) |
|
|
150
160
|
|
|
@@ -154,20 +164,21 @@ description: >
|
|
|
154
164
|
|
|
155
165
|
### 致命规则(FATAL,违反即失败/报错)
|
|
156
166
|
|
|
157
|
-
1.
|
|
167
|
+
1. **技能加载唯一入口**:执行任何子技能前,支持 `use_skill` 的宿主必须调用 `use_skill("<技能名>", "<本阶段目的>")` 加载对应技能;不要用 `Read` / `read_file` / `cat` 读取 SKILL.md 路径,不凭记忆猜参数格式。
|
|
158
168
|
2. **corpId 一致性检查**:创建页面前对比 prd 与 `.cache/cookies.json` 的 corpId,不一致必须询问用户(重新登录 or 当前组织新建)。
|
|
159
169
|
3. **发布前本地校验**:自定义页面发布前跑 `openyida check-page` + `openyida compile`;JSON 配置写盘后先解析校验,再调用平台命令。
|
|
170
|
+
4. **命令输入文件禁止 shell 写入**:当 OpenYida 命令需要 JSON/YAML/CSV/config/script 文件参数时,先使用当前 agent 运行时提供的结构化文件写入工具(如 create_file / Write / file edit tool)创建文件,再把路径传给命令;禁止用 shell heredoc、`cat`/`echo`/`printf`/`tee` 加输出重定向,或把命令 stdout 重定向成业务文件。
|
|
160
171
|
|
|
161
172
|
### 重要规则(IMPORTANT,影响质量/性能/可维护性)
|
|
162
173
|
|
|
163
|
-
1.
|
|
174
|
+
1. **按阶段加载必要技能**:按意图选 1 个主技能;完整应用按阶段加载当下唯一需要的子技能,禁止并发批量读取多个 `SKILL.md` 或预读未来阶段技能。
|
|
164
175
|
2. **优先复用缓存**:`appType`/`formUuid`/`fieldId` 优先从 `.cache/<项目名>-schema.json` 读,缺失再 `get-schema`。
|
|
165
176
|
3. **模板优先**:复杂产物先用 `openyida sample` 或现有示例生成骨架,再做最小改动。
|
|
166
177
|
4. **配置承载优先于代码**:字段/公式/联动/报表/审批/集成交给对应技能,自定义页面只做展示与胶水。
|
|
167
178
|
5. **数据性能优先**:统计聚合用 `yida-report` 服务端聚合,不在前端拉全量后自行聚合。
|
|
168
179
|
6. **避免无效重试**:失败先查登录态/组织/参数/字段 ID,无修改不连续重试超 1 次。
|
|
169
180
|
7. **配置分两处存**:业务语义 → `prd/<项目名>.md`;Schema ID → `.cache/<项目名>-schema.json`(prd 不记 ID)。
|
|
170
|
-
8. **临时文件入 `.cache/`**:
|
|
181
|
+
8. **临时文件入 project `.cache/`**:OpenYida 业务中间文件写入 `<projectRoot>/.cache/openyida/<项目名或任务名>/`;Schema ID 映射仍写 `<projectRoot>/.cache/<项目名>-schema.json`。从 workspace 根执行命令时使用 `project/.cache/...`,从 project 工作目录内执行时使用 `.cache/...`;不要写仓库根目录或系统临时目录。
|
|
171
182
|
9. **报表美化先问方案**:用户说"优化/美化报表"时先问选原生报表(`yida-report`)还是 ECharts(`yida-chart`)。
|
|
172
183
|
10. **按 schema 证据选技能**:先看 `formType`、组件树、`dataSource.online`;`receipt/process/report` 分别落到表单/流程/报表技能。
|
|
173
184
|
11. **官方示例范式优先**:蒸馏官方示例时先理解脱敏 schema 承载方式,不凭截图/标题/视觉判断。
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# 核心规则详解
|
|
2
2
|
|
|
3
|
-
> 逐条展开主 SKILL.md「核心规则」的操作细节,编号与主文件一一对应(FATAL 1–
|
|
3
|
+
> 逐条展开主 SKILL.md「核心规则」的操作细节,编号与主文件一一对应(FATAL 1–4 / IMPORTANT 1–11)。需要更多篇幅的规则指向文末专节。
|
|
4
4
|
|
|
5
5
|
## 致命规则(FATAL)
|
|
6
6
|
|
|
7
|
-
**F1
|
|
7
|
+
**F1 技能加载唯一入口**:执行任何子技能前,支持 `use_skill` 的宿主必须调用 `use_skill("<技能名>", "<本阶段目的>")` 加载对应技能;不要用 `Read` / `read_file` / `cat` 读取 `SKILL.md` 路径。`skills-index.json` 仅供 yida-agent 或同构宿主机器发现,不支持该索引的宿主忽略它。完全没有 `use_skill` / `search_skills` 的本地工具,才允许按根技能路由表和技能包相对路径逐个读取当前阶段唯一必要的技能文档;禁止并发批量读取多个 `SKILL.md`,禁止预读未来阶段技能。
|
|
8
8
|
|
|
9
9
|
**F2 corpId 一致性检查**:创建页面前对比 prd 文档与 `.cache/cookies.json` 的 corpId——
|
|
10
10
|
- 一致 → 继续;
|
|
@@ -15,18 +15,20 @@
|
|
|
15
15
|
- 发布时留意"同名双副本内容不一致"警告,必要时加 `--health-check` 做首屏 HTTP 健康检查;
|
|
16
16
|
- 任何 JSON 配置写盘后先做 JSON 解析校验,再调用平台命令。
|
|
17
17
|
|
|
18
|
+
**F4 命令输入文件禁止 shell 写入**:当 OpenYida 命令需要 JSON/YAML/CSV/config/script 文件参数时,必须先使用当前 agent 运行时提供的结构化文件写入工具(如 create_file / Write / file edit tool)创建文件,再把文件路径传给命令。禁止用 shell heredoc、`cat`/`echo`/`printf`/`tee` 加输出重定向,或把 `openyida` 命令 stdout 重定向成业务配置、Schema、导入数据或一次性脚本。
|
|
19
|
+
|
|
18
20
|
## 重要规则(IMPORTANT)
|
|
19
21
|
|
|
20
22
|
| # | 规则 | 操作细节 |
|
|
21
23
|
|---|------|---------|
|
|
22
|
-
| 1 |
|
|
24
|
+
| 1 | 按阶段加载必要技能 | 按意图选定 1 个主技能;完整应用按阶段加载当下唯一需要的子技能,仅在已加载技能明确要求时才读对应 `references/`。 |
|
|
23
25
|
| 2 | 优先复用缓存 | `appType`/`formUuid`/`fieldId`/`reportId` 先从 `.cache/<项目名>-schema.json` 读,缺失或不确定再 `openyida get-schema`。 |
|
|
24
26
|
| 3 | 模板优先 | 自定义页面、表单字段、报表配置等复杂产物先用 `openyida sample` 或现有示例生成骨架,再做最小改动。 |
|
|
25
27
|
| 4 | 配置承载优先于代码 | 字段结构/公式/联动/报表聚合/审批/集成/连接器动作交给对应技能承载;自定义页面代码只做展示、事件分发和必要胶水。 |
|
|
26
28
|
| 5 | 数据性能优先 | 统计聚合用 `yida-report` 服务端聚合;不在自定义页面前端分页拉全量后自行聚合。 |
|
|
27
29
|
| 6 | 避免无效重试 | 失败先按错误信息查登录态/组织/参数/字段 ID;无修改不连续重试超 1 次。 |
|
|
28
30
|
| 7 | 配置分两处存 | 详见 [配置信息分两处存储](#配置信息分两处存储) 与 [PRD 质量门槛](#prd-质量门槛)。 |
|
|
29
|
-
| 8 | 临时文件入 `.cache/` | 详见 [临时文件规范](#临时文件规范)。 |
|
|
31
|
+
| 8 | 临时文件入 project `.cache/` | 详见 [临时文件规范](#临时文件规范)。 |
|
|
30
32
|
| 9 | 报表美化先问方案 | 详见 [报表优化 / 美化提示规则](#报表优化--美化提示规则)。 |
|
|
31
33
|
| 10 | 按 schema 证据选技能 | 先看 `formType`、组件树、`dataSource.online`;`receipt/process/report` 分别落到表单/流程/报表技能,只有默认页是自定义展示页、或确需列表/看板/工具页交互时才落到 `yida-custom-page`。 |
|
|
32
34
|
| 11 | 官方示例范式优先 | 蒸馏宜搭示例中心时,先按 [官方示例 Schema 范式](official-example-schema-patterns.md) 理解脱敏 schema 的承载方式,不凭截图/卡片标题/页面视觉判断。 |
|
|
@@ -55,14 +57,16 @@
|
|
|
55
57
|
|
|
56
58
|
## 临时文件规范
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
所有 OpenYida 业务中间文件(cookies、schema 缓存、字段/报表/流程配置、导入数据、一次性脚本等)**必须写在 OpenYida project 工作目录的 `.cache/` 下**,不写业务仓库根目录、系统 `/tmp` 或其他位置。源码中的 `<projectRoot>` 指 OpenYida project 工作目录;从 workspace 根执行命令时路径通常是 `project/.cache/...`,从 project 工作目录内执行时路径是 `.cache/...`。
|
|
61
|
+
|
|
62
|
+
文件必须由 agent 的结构化文件写入工具创建,再传给 OpenYida 命令。不要通过 `execute_shell` 加 heredoc、`cat`/`echo`/`printf`/`tee`、管道或重定向来生成 JSON/YAML/CSV/config/script 文件。`/tmp` 只允许用于外部工具强制要求的系统临时路径,OpenYida 业务配置、schema、导入数据和一次性脚本不写 `/tmp`。
|
|
59
63
|
|
|
60
64
|
| 工件类型 | 推荐位置 |
|
|
61
65
|
|---------|---------|
|
|
62
|
-
| Schema / ID 映射 |
|
|
63
|
-
| 字段 / 报表 /
|
|
64
|
-
| 批量导入数据(JSON/JSONL/CSV) |
|
|
65
|
-
| 一次性 Python / JS 脚本 |
|
|
66
|
+
| Schema / ID 映射 | `<projectRoot>/.cache/<项目名>-schema.json` |
|
|
67
|
+
| 字段 / 报表 / 流程 / 连接器配置 | `<projectRoot>/.cache/openyida/<项目名或任务名>/` |
|
|
68
|
+
| 批量导入数据(JSON/JSONL/CSV) | `<projectRoot>/.cache/openyida/<项目名或任务名>/data-import/` |
|
|
69
|
+
| 一次性 Python / JS 脚本 | `<projectRoot>/.cache/openyida/<项目名或任务名>/scripts/` |
|
|
66
70
|
|
|
67
71
|
> 只有需长期维护的 PRD、页面源码、示例资源才写入 `prd/`、`pages/src/`、`project/` 等正式目录。
|
|
68
72
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: large-file-write
|
|
3
|
-
description: 解决 heredoc 或 shell
|
|
3
|
+
description: 解决 heredoc 或 shell 命令写入大文件内容被截断的问题。优先使用 agent 结构化文件写入工具;超大文件可用该工具创建 Node.js payload 后执行。适用于需要可靠写入超过 100 行文本文件时。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Large File Write Skill
|
|
7
7
|
|
|
8
8
|
## 问题背景
|
|
9
9
|
|
|
10
|
-
在 AI Agent 模式下,使用
|
|
10
|
+
在 AI Agent 模式下,使用 shell here-document 或其他 shell 命令向文件写入大块内容时,经常出现:
|
|
11
11
|
- 内容被截断(工具输出超过 token 限制)
|
|
12
12
|
- heredoc 内容未生效(zsh 特殊字符转义问题)
|
|
13
13
|
- 多次追加导致重复内容或语法错误
|
|
@@ -15,20 +15,22 @@ description: 解决 heredoc 或 shell 命令写入大文件内容被截断的问
|
|
|
15
15
|
|
|
16
16
|
## 解决方案
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
优先使用当前 agent 运行时提供的结构化文件写入工具(如 create_file / Write / file edit tool)直接创建目标文件。内容过大、单次写入可能截断时,再用结构化写入工具创建 Node.js payload 脚本,由 payload 调用 `fs.writeFileSync` 写目标文件。
|
|
19
|
+
|
|
20
|
+
OpenYida 业务场景下,payload、内容片段和验证脚本必须放在 `<projectRoot>/.cache/openyida/<项目名或任务名>/scripts/`,不要写系统临时目录、仓库根目录或 `.cache/` 顶层。
|
|
19
21
|
|
|
20
22
|
## 使用方式
|
|
21
23
|
|
|
22
24
|
三种写入模式的完整代码示例,详见 [references/write-patterns.md](./references/write-patterns.md):
|
|
23
25
|
|
|
24
|
-
- **模式一**:创建内容脚本后执行(推荐)—
|
|
26
|
+
- **模式一**:创建内容脚本后执行(推荐)— 用结构化文件写入工具创建临时 JS 脚本,再 `node` 执行
|
|
25
27
|
- **模式二**:追加内容到已有文件 — 用 `fs.appendFileSync` 追加大块内容
|
|
26
|
-
- **模式三**:使用通用写入脚本(
|
|
28
|
+
- **模式三**:使用通用写入脚本(content-file 模式)— 内容文件也先由结构化文件写入工具创建
|
|
27
29
|
|
|
28
30
|
### 快速示例
|
|
29
31
|
|
|
30
32
|
```js
|
|
31
|
-
// /
|
|
33
|
+
// <projectRoot>/.cache/openyida/<任务名>/scripts/content-payload.js
|
|
32
34
|
const fs = require('fs');
|
|
33
35
|
const content = `// 你的大块内容(支持任意长度)
|
|
34
36
|
export function myFunction() { ... }
|
|
@@ -38,17 +40,17 @@ console.log('写入完成,行数:', content.split('\n').length);
|
|
|
38
40
|
```
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
|
-
node /
|
|
43
|
+
node .cache/openyida/<任务名>/scripts/content-payload.js
|
|
42
44
|
wc -l /path/to/target.js # 验证行数
|
|
43
45
|
```
|
|
44
46
|
|
|
45
47
|
## 核心原则
|
|
46
48
|
|
|
47
|
-
1. **永远不要用 heredoc 写大文件** —
|
|
49
|
+
1. **永远不要用 heredoc 写大文件** — 改用结构化文件写入工具创建临时 JS 脚本
|
|
48
50
|
2. **永远不要用 PowerShell JSON 化大文件** — 禁止 `Get-Content -Raw <file> | ConvertTo-Json`、`ConvertFrom-Json` 处理 `.oyd.jsx/.jsx/.js` 页面源码
|
|
49
51
|
3. **内容放在 JS 模板字符串里** — 支持任意长度,不受 shell 限制
|
|
50
52
|
4. **写完立即验证** — `wc -l` 检查行数,`tail` 检查末尾内容
|
|
51
|
-
5. **分段写入大文件** — 超过 300
|
|
53
|
+
5. **分段写入大文件** — 超过 300 行的内容,拆分为多个结构化写入 + `node` 执行
|
|
52
54
|
6. **本技能不读写 memory**:文件写入为纯本地操作,不依赖跨会话的 memory 状态
|
|
53
55
|
|
|
54
56
|
## 适用场景
|
|
@@ -88,4 +90,4 @@ Get-Content -Raw project\pages\src\vendor-section.oyd.jsx | ConvertTo-Json
|
|
|
88
90
|
| `node: command not found` | Node.js 未安装 | 先安装 Node.js ≥ 16 |
|
|
89
91
|
| 脚本执行后文件为空 | 模板字符串语法错误 | 检查反引号是否闭合,特殊字符是否转义 |
|
|
90
92
|
| 写入不完整 | 内容超过单次 create_file 限制 | 按「分段写入」方式拆分为多个脚本 |
|
|
91
|
-
| 权限拒绝 | 目标路径无写权限 |
|
|
93
|
+
| 权限拒绝 | 目标路径无写权限 | 检查目标目录权限;OpenYida 业务文件仍应留在 project 工作目录内 |
|