kcode-pi 0.1.6 → 0.1.7

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.
Files changed (47) hide show
  1. package/README.md +18 -2
  2. package/package.json +1 -1
  3. package/src/official/kingdee-skills.ts +60 -13
  4. package/src/rules/checker.ts +143 -0
  5. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +2 -2
  6. package/vendor/kingdee-skills/ok-cosmic/SKILL.md +52 -101
  7. package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +4 -4
  8. package/vendor/kingdee-skills/ok-cosmic/manifest.json +21 -20
  9. package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +1 -1
  10. package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +1 -1
  11. package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +2 -2
  12. package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +4 -4
  13. package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +3 -3
  14. package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +8 -8
  15. package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +1 -1
  16. package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +19 -18
  17. package/vendor/kingdee-skills/ok-ksql/SKILL.md +9 -9
  18. package/vendor/kingdee-skills/ok-ksql/manifest.json +2 -1
  19. package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +2 -2
  20. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +0 -336
  21. package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +0 -121
  22. package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +0 -295
  23. package/vendor/kingdee-skills/ok-cosmic/README.md +0 -460
  24. package/vendor/kingdee-skills/ok-cosmic/requirements.txt +0 -2
  25. package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +0 -204
  26. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +0 -910
  27. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +0 -359
  28. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +0 -181
  29. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +0 -389
  30. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +0 -856
  31. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +0 -262
  32. package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +0 -293
  33. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +0 -2
  34. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +0 -393
  35. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +0 -176
  36. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +0 -375
  37. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +0 -434
  38. package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +0 -36
  39. package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +0 -186
  40. package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +0 -40
  41. package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +0 -142
  42. package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
  43. package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
  44. package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +0 -18
  45. package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +0 -53
  46. package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
  47. package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +0 -363
package/README.md CHANGED
@@ -414,10 +414,26 @@ kd_debug 分析金蝶日志和堆栈
414
414
  这些工具不依赖本机 Python:
415
415
 
416
416
  - `kd_ksql_lint` 是内置 Node 静态检查器。
417
- - `kd_cosmic_config` 使用 Node 读取并校验 `ok-cosmic.json`。
418
- - `kd_cosmic_metadata` 使用 `ok-cosmic.json` 中的统一路由 API,并在当前项目 `.pi/kd/official-skills/` 下维护 JSON 缓存。
417
+ - `kd_cosmic_config` 使用 Node 校验 Cosmic 官方能力配置;项目没有 `ok-cosmic.json` 时会自动使用 KCode 随包默认配置。
418
+ - `kd_cosmic_metadata` 使用统一路由 API 查询真实单据/表单元数据,并在当前项目 `.pi/kd/official-skills/` 下维护 JSON 缓存。
419
419
  - `kd_cosmic_api` 查询随包金蝶知识库;需要精确方法签名时,仍要结合当前项目 SDK、编译输出或红绿证据确认。
420
420
 
421
+ `ok-cosmic.json` 是可选的 KCode 官方能力覆盖配置,不是苍穹工程模板里的 `cosmic.json`。业务项目里的 `cosmic.json` 通常只包含开发者标识、工程标识、MC 资源地址等运行环境信息,不能替代 `ok-cosmic.json`。
422
+
423
+ 只有需要指定企业统一路由 API 或覆盖知识库路径时,才需要在业务项目根目录创建 `ok-cosmic.json`:
424
+
425
+ ```json
426
+ {
427
+ "graph": {
428
+ "dbPath": "D:\\path\\to\\ok-cosmic-docs.db"
429
+ },
430
+ "route": {
431
+ "apiUrl": "https://your-runtime-route.example.com/api",
432
+ "timeoutSeconds": 10
433
+ }
434
+ }
435
+ ```
436
+
421
437
  ## 升级
422
438
 
423
439
  查看当前安装版本:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kcode-pi",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Kingdee-specific package and harness for Pi Coding Agent",
5
5
  "type": "module",
6
6
  "private": false,
@@ -109,8 +109,8 @@ export async function runOfficialCommand(command: OfficialCommand): Promise<Comm
109
109
  export async function cosmicConfigCommand(cwd: string, config?: string): Promise<OfficialCommand> {
110
110
  await ensureOfficialSkillRoot(cwd, "ok-cosmic");
111
111
  const configPath = resolveConfigPath(cwd, config);
112
- const display = formatCommand("kcode-node:cosmic-config", config ? ["--config", configPath] : []);
113
- return officialCommand(display, () => runCosmicConfig(cwd, configPath));
112
+ const display = formatCommand("kcode-node:cosmic-config", config && configPath ? ["--config", configPath] : []);
113
+ return officialCommand(display, () => runCosmicConfig(cwd, configPath, Boolean(config)));
114
114
  }
115
115
 
116
116
  export async function cosmicMetadataCommand(
@@ -133,7 +133,7 @@ export async function cosmicMetadataCommand(
133
133
  if (params.fuzzy) args.push("--fuzzy", ...splitTerms(params.fuzzy));
134
134
  if (params.typeFilter) args.push("--type", params.typeFilter);
135
135
  const configPath = resolveConfigPath(cwd, params.config);
136
- return officialCommand(formatCommand("kcode-node:cosmic-metadata", args), () => runCosmicMetadata(cwd, configPath, params));
136
+ return officialCommand(formatCommand("kcode-node:cosmic-metadata", args), () => runCosmicMetadata(cwd, configPath, Boolean(params.config), params));
137
137
  }
138
138
 
139
139
  export async function cosmicApiCommand(
@@ -219,8 +219,10 @@ function officialCommand(display: string, run: () => Promise<Omit<CommandResult,
219
219
  };
220
220
  }
221
221
 
222
- function resolveConfigPath(cwd: string, config?: string): string {
223
- return config ? resolveWorkspacePath(cwd, config) : resolve(cwd, "ok-cosmic.json");
222
+ function resolveConfigPath(cwd: string, config?: string): string | undefined {
223
+ if (config) return resolveWorkspacePath(cwd, config);
224
+ const projectConfig = resolve(cwd, "ok-cosmic.json");
225
+ return existsSync(projectConfig) ? projectConfig : undefined;
224
226
  }
225
227
 
226
228
  function readJsonObject(path: string): Record<string, unknown> {
@@ -231,20 +233,34 @@ function readJsonObject(path: string): Record<string, unknown> {
231
233
  return data as Record<string, unknown>;
232
234
  }
233
235
 
234
- async function runCosmicConfig(_cwd: string, configPath: string): Promise<Omit<CommandResult, "command">> {
236
+ interface LoadedCosmicConfig {
237
+ config: Record<string, unknown>;
238
+ path?: string;
239
+ source: "project" | "explicit" | "bundled";
240
+ baseDir: string;
241
+ }
242
+
243
+ async function runCosmicConfig(cwd: string, configPath: string | undefined, explicitConfig: boolean): Promise<Omit<CommandResult, "command">> {
235
244
  const issues: Array<{ level: "OK" | "WARNING" | "ERROR"; key: string; message: string }> = [];
236
245
  issues.push({ level: "OK", key: "runtime.node", message: `Node ${process.version}` });
237
246
 
238
- let config: Record<string, unknown> | undefined;
247
+ let loaded: LoadedCosmicConfig | undefined;
239
248
  try {
240
- if (!existsSync(configPath)) throw new Error(`找不到配置文件: ${configPath}`);
241
- config = readJsonObject(configPath);
242
- issues.push({ level: "OK", key: "__file__", message: `已找到配置文件: ${configPath}` });
249
+ loaded = loadCosmicConfig(cwd, configPath, explicitConfig);
250
+ if (loaded.path) {
251
+ issues.push({ level: "OK", key: "__file__", message: `已找到配置文件: ${loaded.path}` });
252
+ } else {
253
+ issues.push({
254
+ level: "WARNING",
255
+ key: "__file__",
256
+ message: "当前项目未提供 ok-cosmic.json,已使用 KCode 随包默认配置。项目根目录 cosmic.json 是苍穹工程配置,不是 KCode 官方能力配置。",
257
+ });
258
+ }
243
259
  } catch (error) {
244
260
  issues.push({ level: "ERROR", key: "__file__", message: error instanceof Error ? error.message : String(error) });
245
261
  }
246
262
 
247
- if (config) issues.push(...validateCosmicConfig(config, dirname(configPath)));
263
+ if (loaded) issues.push(...validateCosmicConfig(loaded.config, loaded.baseDir));
248
264
  const errors = issues.filter((issue) => issue.level === "ERROR").length;
249
265
  const warnings = issues.filter((issue) => issue.level === "WARNING").length;
250
266
  const lines = issues.map((issue) => `[${issue.level}] ${issue.key}: ${issue.message}`);
@@ -252,6 +268,36 @@ async function runCosmicConfig(_cwd: string, configPath: string): Promise<Omit<C
252
268
  return { exitCode: errors ? 1 : 0, stdout: `${lines.join("\n")}\n`, stderr: "" };
253
269
  }
254
270
 
271
+ function loadCosmicConfig(cwd: string, configPath: string | undefined, explicitConfig: boolean): LoadedCosmicConfig {
272
+ if (configPath) {
273
+ if (!existsSync(configPath)) throw new Error(`找不到配置文件: ${configPath}`);
274
+ return {
275
+ config: readJsonObject(configPath),
276
+ path: configPath,
277
+ source: explicitConfig ? "explicit" : "project",
278
+ baseDir: dirname(configPath),
279
+ };
280
+ }
281
+ if (explicitConfig) throw new Error("指定的 ok-cosmic.json 配置文件不存在。");
282
+ return {
283
+ config: defaultCosmicConfig(),
284
+ source: "bundled",
285
+ baseDir: cwd,
286
+ };
287
+ }
288
+
289
+ function defaultCosmicConfig(): Record<string, unknown> {
290
+ return {
291
+ graph: {
292
+ dbPath: join(packageRoot, "vendor", "kingdee-skills", "ok-cosmic", "setup", "ok-cosmic-docs.db"),
293
+ },
294
+ route: {
295
+ apiUrl: process.env.COSMIC_ROUTE_API || process.env.COSMIC_RUNTIME_ROUTE_API || "",
296
+ timeoutSeconds: Number(process.env.COSMIC_ROUTE_TIMEOUT || 10),
297
+ },
298
+ };
299
+ }
300
+
255
301
  function validateCosmicConfig(config: Record<string, unknown>, baseDir: string): Array<{ level: "OK" | "WARNING" | "ERROR"; key: string; message: string }> {
256
302
  const issues: Array<{ level: "OK" | "WARNING" | "ERROR"; key: string; message: string }> = [];
257
303
  const graph = objectValue(config.graph);
@@ -308,10 +354,11 @@ function validateCosmicConfig(config: Record<string, unknown>, baseDir: string):
308
354
 
309
355
  async function runCosmicMetadata(
310
356
  cwd: string,
311
- configPath: string,
357
+ configPath: string | undefined,
358
+ explicitConfig: boolean,
312
359
  params: { form: string; fuzzy?: string; typeFilter?: string; sql?: boolean; op?: boolean; showDetail?: boolean },
313
360
  ): Promise<Omit<CommandResult, "command">> {
314
- const config = readJsonObject(configPath);
361
+ const config = loadCosmicConfig(cwd, configPath, explicitConfig).config;
315
362
  const cache = readMetadataCache(cwd);
316
363
  const targets = params.form.split(/[,,]/).map((item) => item.trim()).filter(Boolean);
317
364
  if (targets.length === 0) return { exitCode: 1, stdout: "", stderr: "必须提供 formId 或中文单据名。" };
@@ -65,6 +65,7 @@ function checkCosmicReviewerRules(lines: string[]): CheckResult[] {
65
65
  ...checkSecurityPatterns(lines),
66
66
  ...checkThreadingPatterns(lines),
67
67
  ...checkUiPerformance(lines),
68
+ ...checkViewInteractionOrder(lines),
68
69
  ...checkLoggingAndDiagnostics(lines),
69
70
  ];
70
71
  }
@@ -134,6 +135,17 @@ function checkResourceHandling(lines: string[]): CheckResult[] {
134
135
  results.push(makeResult(i, line, "DataSet", "resource", "error", "P0:DataSet 创建后未明显使用 try-with-resources 关闭,可能导致连接泄漏", "p0-dataset-not-closed"));
135
136
  }
136
137
 
138
+ for (let i = 0; i < lines.length; i++) {
139
+ const line = lines[i];
140
+ if (isCommentLine(line)) continue;
141
+ if (/\.\s*getDynamicObject\s*\([^)]*\)\s*\.\s*get(?:String|Long|Int|Integer|Double|Date|PkValue|DynamicObject|DynamicObjectCollection)\s*\(/.test(line)) {
142
+ results.push(makeResult(i, line, "getDynamicObject", "resource", "warning", "P1:嵌套 DynamicObject 直接取值缺少空值保护,引用字段为空时可能 NPE;先取对象并判空或用安全取值工具", "p1-dynamicobject-chain-null-risk"));
143
+ }
144
+ if (/row\s*\.\s*get(?:BigDecimal|String|Long|Int|Integer|Date)\s*\(/.test(line) && !nearbyLineHas(lines, i, -2, /\brow\b\s*(?:!=|==)\s*null|Optional\.ofNullable\s*\(\s*row\s*\)|Objects\.nonNull\s*\(\s*row\s*\)/)) {
145
+ results.push(makeResult(i, line, "row", "resource", "warning", "P1:DataSet.Row 取值可能返回 null,参与运算或解包前应判空或给默认值", "p1-dataset-row-null-risk"));
146
+ }
147
+ }
148
+
137
149
  return results;
138
150
  }
139
151
 
@@ -159,6 +171,20 @@ function checkSecurityPatterns(lines: string[]): CheckResult[] {
159
171
  if (/(password|passwd|secret|token|ak|sk)\s*=\s*"[^"]{4,}"/i.test(line)) {
160
172
  results.push(makeResult(i, line, "=", "security", "error", "P0:疑似敏感信息硬编码,请改为安全配置或密文存储", "p0-secret-hardcode"));
161
173
  }
174
+
175
+ if (/\bcache\s*\.\s*put\s*\(/i.test(line) || /\bCacheFactory\b/.test(line)) {
176
+ const statement = collectStatement(lines, i, 5);
177
+ if (/\bput\s*\(/i.test(statement) && !/(account|acct|tenant|org|dcId|getAccountId|getOrgId|RequestContext|UserServiceHelper)/i.test(statement)) {
178
+ results.push(makeResult(i, line, "put", "security", "warning", "P1:缓存写入 key 未体现账套/租户/组织隔离,跨账套环境可能串数据", "p1-cache-key-without-tenant"));
179
+ }
180
+ }
181
+
182
+ if (/\b(openConnection|HttpClient\s*\.|HttpClientBuilder|OkHttpClient|RestTemplate|WebClient)\b/.test(line)) {
183
+ const statement = collectStatement(lines, i, 8);
184
+ if (!/(timeout|setConnectTimeout|setReadTimeout|connectTimeout|readTimeout|callTimeout|responseTimeout)/i.test(statement)) {
185
+ results.push(makeResult(i, line, line.match(/\b(openConnection|HttpClient|HttpClientBuilder|OkHttpClient|RestTemplate|WebClient)\b/)?.[1] ?? "HTTP", "security", "warning", "P1:第三方 HTTP 调用未看到超时设置,生产环境可能阻塞业务线程", "p1-http-without-timeout"));
186
+ }
187
+ }
162
188
  }
163
189
 
164
190
  return results;
@@ -197,6 +223,22 @@ function checkUiPerformance(lines: string[]): CheckResult[] {
197
223
  if (isInsideLoop(lines, i) && /getFieldIndex\s*\(/.test(line)) {
198
224
  results.push(makeResult(i, line, "getFieldIndex", "performance", "warning", "P1:循环内重复获取 FieldIndex 会造成性能损耗;应在循环外缓存", "p1-loop-field-index"));
199
225
  }
226
+
227
+ if (/SerializationUtils\s*\.\s*toJsonString\s*\(/.test(line) && /(view|model|event|page|args|this|getView\s*\(|getModel\s*\(|\be\b)/i.test(line)) {
228
+ results.push(makeResult(i, line, "SerializationUtils", "performance", "warning", "P1:不要序列化页面、模型或事件大对象做日志,容易造成 CPU 和内存压力;只记录关键字段", "p1-heavy-json-serialization"));
229
+ }
230
+
231
+ const entryUiMatch = line.match(/\bgetView\s*\(\)\s*\.\s*(setEnable|setVisible)\s*\(/);
232
+ if (entryUiMatch) {
233
+ const statement = collectStatement(lines, i, 3);
234
+ const args = extractCallArgs(statement, /(setEnable|setVisible)\s*\(/);
235
+ if (args.length >= 2 && !looksLikeRowIndexedViewCall(args)) {
236
+ const fieldArgs = args.slice(1).join(",");
237
+ if (/(entry|entries|detail|row|qty|price|amount|material|item)/i.test(fieldArgs)) {
238
+ results.push(makeResult(i, line, entryUiMatch[1], "performance", "warning", "P1:疑似对分录字段使用单头 setEnable/setVisible;分录字段应使用带 rowIndex 的重载", "p1-entry-field-without-row-index"));
239
+ }
240
+ }
241
+ }
200
242
  }
201
243
 
202
244
  if (beginInitCount > endInitCount) {
@@ -209,6 +251,45 @@ function checkUiPerformance(lines: string[]): CheckResult[] {
209
251
  return results;
210
252
  }
211
253
 
254
+ function checkViewInteractionOrder(lines: string[]): CheckResult[] {
255
+ const results: CheckResult[] = [];
256
+
257
+ for (let i = 0; i < lines.length; i++) {
258
+ const line = lines[i];
259
+ if (isCommentLine(line)) continue;
260
+
261
+ if (/setDataChanged\s*\(\s*false\s*\)/.test(line)) {
262
+ for (let j = i + 1; j < Math.min(lines.length, i + 25); j++) {
263
+ if (/^\s*}\s*$/.test(lines[j])) break;
264
+ if (!isCommentLine(lines[j]) && /(getModel\s*\(\)\s*\.\s*)?setValue\s*\(/.test(lines[j])) {
265
+ results.push(makeResult(i, line, "setDataChanged", "lifecycle", "warning", "P1:setDataChanged(false) 后仍继续 setValue,脏标记会被重新置回;应放到所有 setValue 之后", "p1-set-data-changed-before-setvalue"));
266
+ break;
267
+ }
268
+ }
269
+ }
270
+
271
+ if (/showConfirm\s*\(/.test(line)) {
272
+ const statement = collectStatement(lines, i, 8);
273
+ const args = extractCallArgs(statement, /showConfirm\s*\(/);
274
+ if (args.length < 3 || /\bnull\b/.test(args[2] ?? "")) {
275
+ results.push(makeResult(i, line, "showConfirm", "lifecycle", "error", "P0:showConfirm 未提供有效回调监听器,用户选择不会触发业务处理", "p0-show-confirm-without-callback"));
276
+ }
277
+ }
278
+
279
+ if (/getView\s*\(\)\s*\.\s*close\s*\(/.test(line)) {
280
+ for (let j = i + 1; j < Math.min(lines.length, i + 10); j++) {
281
+ if (/^\s*}\s*$/.test(lines[j])) break;
282
+ if (!isCommentLine(lines[j]) && /returnDataToParent\s*\(/.test(lines[j])) {
283
+ results.push(makeResult(i, line, "close", "lifecycle", "error", "P0:先 close 再 returnDataToParent 会导致返回数据不执行;应先 returnDataToParent 再 close", "p0-close-before-return-data"));
284
+ break;
285
+ }
286
+ }
287
+ }
288
+ }
289
+
290
+ return results;
291
+ }
292
+
212
293
  function checkLoggingAndDiagnostics(lines: string[]): CheckResult[] {
213
294
  const results: CheckResult[] = [];
214
295
 
@@ -548,6 +629,68 @@ function isInsideLoop(lines: string[], index: number): boolean {
548
629
  return false;
549
630
  }
550
631
 
632
+ function collectStatement(lines: string[], start: number, maxExtraLines: number): string {
633
+ const parts: string[] = [];
634
+ for (let i = start; i < Math.min(lines.length, start + maxExtraLines + 1); i++) {
635
+ parts.push(lines[i]);
636
+ if (/[;{}]\s*$/.test(lines[i].trim())) break;
637
+ }
638
+ return parts.join("\n");
639
+ }
640
+
641
+ function extractCallArgs(statement: string, callPattern: RegExp): string[] {
642
+ const match = callPattern.exec(statement);
643
+ if (!match || match.index === undefined) return [];
644
+ const open = statement.indexOf("(", match.index);
645
+ if (open < 0) return [];
646
+
647
+ const args: string[] = [];
648
+ let depth = 0;
649
+ let current = "";
650
+ let quote: "'" | '"' | undefined;
651
+ for (let i = open + 1; i < statement.length; i++) {
652
+ const ch = statement[i];
653
+ const prev = statement[i - 1];
654
+ if (quote) {
655
+ current += ch;
656
+ if (ch === quote && prev !== "\\") quote = undefined;
657
+ continue;
658
+ }
659
+ if (ch === "'" || ch === '"') {
660
+ quote = ch;
661
+ current += ch;
662
+ continue;
663
+ }
664
+ if (ch === "(" || ch === "[" || ch === "{") {
665
+ depth++;
666
+ current += ch;
667
+ continue;
668
+ }
669
+ if (ch === ")" && depth === 0) {
670
+ if (current.trim()) args.push(current.trim());
671
+ return args;
672
+ }
673
+ if (ch === ")" || ch === "]" || ch === "}") {
674
+ depth--;
675
+ current += ch;
676
+ continue;
677
+ }
678
+ if (ch === "," && depth === 0) {
679
+ args.push(current.trim());
680
+ current = "";
681
+ continue;
682
+ }
683
+ current += ch;
684
+ }
685
+ return [];
686
+ }
687
+
688
+ function looksLikeRowIndexedViewCall(args: string[]): boolean {
689
+ if (args.length < 3) return false;
690
+ const second = args[1].trim();
691
+ return /^(rowIndex|index|idx|i|row|entryIndex|\d+)$/.test(second) || /\bgetRowIndex\s*\(/.test(second);
692
+ }
693
+
551
694
  function isCommentLine(line: string): boolean {
552
695
  const trimmed = line.trim();
553
696
  return trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*");
@@ -304,7 +304,7 @@ references/
304
304
 
305
305
  ### 📌 步骤3: 执行模式匹配扫描
306
306
 
307
- **使用 pattern-matcher.py 或手动执行以下模式检查**:
307
+ **使用 KCode `kd_check` 或手动执行以下模式检查**:
308
308
 
309
309
  ```
310
310
  📌 步骤3: 执行模式匹配扫描
@@ -671,4 +671,4 @@ D:\new_workspace\macc-dev\pm\report\代码审查报告_xxx.html ❌ 子模块
671
671
  ### 幂等性
672
672
  - 重复执行是否产生副作用
673
673
  - MQ 消费是否支持重复消费
674
- - 操作是否可安全重试
674
+ - 操作是否可安全重试
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "ok-cosmic"
3
- description: "金蝶云苍穹开发主 Skill,优先复用 kd-cd-cosmic-commons 封装。适用于插件开发、单据/列表/表单逻辑、操作服务、BOTP 转换、后台视图打开、附件处理、DynamicObject 与元数据处理、弹性域解析及 OpenAPI 集成。默认优先使用仓库封装;在涉及原生插件事件、SDK API、方法签名或封装未覆盖场景时,使用内置脚本进行查询。"
3
+ description: "金蝶云苍穹开发主 Skill,优先复用 kd-cd-cosmic-commons 封装。适用于插件开发、单据/列表/表单逻辑、操作服务、BOTP 转换、后台视图打开、附件处理、DynamicObject 与元数据处理、弹性域解析及 OpenAPI 集成。默认优先使用仓库封装;在涉及原生插件事件、SDK API、方法签名或封装未覆盖场景时,使用 KCode Node 适配器查询。"
4
4
  ---
5
5
 
6
6
  # 苍穹开发
@@ -13,18 +13,18 @@ description: "金蝶云苍穹开发主 Skill,优先复用 kd-cd-cosmic-commons
13
13
 
14
14
  ## Step 0. 配置预检(先于一切)
15
15
 
16
- 1. Step 0 的第一个动作必须直接执行:
17
- `python3 <SKILL_ROOT>/scripts/cosmic-config-check.py`
16
+ 1. Step 0 的第一个动作必须直接执行 KCode 工具:
17
+ `kd_cosmic_config`
18
18
  2. 默认在当前项目工作目录直接执行;不要先询问或搜索 `ok-cosmic.json` 的位置。
19
19
  3. 只有用户明确提供了其他配置路径,或当前工作目录不是目标项目根目录时,才改用:
20
- `python3 <SKILL_ROOT>/scripts/cosmic-config-check.py --config <显式路径>`
20
+ `kd_cosmic_config config=<显式路径>`
21
21
  4. 若脚本返回非 0 或输出含 `ERROR`:停止生成代码,明确提示用户补齐缺失项。
22
- 5. 若仅有 `WARNING`:先告知用户哪些在线能力不可用,再决定是否继续当前任务。后续脚本调用受以下限制:
22
+ 5. 若仅有 `WARNING`:先告知用户哪些在线能力不可用,再决定是否继续当前任务。后续工具调用受以下限制:
23
23
 
24
24
  | WARNING 类型 | 限制 |
25
25
  |---|---|
26
- | "API 不可达" 或 "在线服务不可用" | **禁止调用** `cosmic-basedata-query.py`;`cosmic-form-metadata.py` 仅允许使用本地缓存,**禁止 `--refresh` 刷新** |
27
- | "知识库不存在" | `cosmic-api-knowledge.py` 不可用,改为仅依赖 `cheat-sheet.md` 和模板中的方法签名 |
26
+ | "API 不可达" 或 "在线服务不可用" | `kd_cosmic_metadata` 只能使用 KCode 本地缓存;需要实时基础资料数据时停止并要求项目侧证据 |
27
+ | "知识库不存在" | `kd_cosmic_api` 随包知识不可用,改为仅依赖 `cheat-sheet.md`、项目 SDK 和编译结果 |
28
28
 
29
29
  ## 自然语言意图路由(首读)
30
30
 
@@ -100,15 +100,15 @@ description: "金蝶云苍穹开发主 Skill,优先复用 kd-cd-cosmic-commons
100
100
  - 🔍 **Agent A — 事件参考**:读对应 `references/*.md` 的 TL;DR 摘要 + `assets/*.java` 模板,提取事件签名与骨架。只读当前任务需要的事件方法段,不要一次性通读整个模板。如果卡在事件先后顺序,先读 [references/adv/event-lifecycle.md](references/adv/event-lifecycle.md)。
101
101
  - 🔍 **Agent B — 项目探索**:在用户项目中搜索相似插件实现(同类型插件、相似业务场景),分析已有代码风格、import 习惯、封装用法,确保生成代码与项目风格一致。
102
102
  3. **‖ 并行验证**字段与 API 签名(互不依赖的查询应同时发起):
103
- - 调用脚本前,先查下方“脚本路由”表格确认调用模板;表格未覆盖时才执行 `python3 <script> --help`。
104
- - 3a. 若目标 API 已在 `rules/cheat-sheet.md` 中列出 → 直接使用,**无需脚本验证**。
105
- - 3b. 字段 / `entityId` / 枚举值验证 → 查 `cosmic-form-metadata.py`。**只要要生成代码且已知目标单据/表单,凡涉及字段(无论用户给中文名还是英文标识),都必须验证字段是否存在、字段类型、所属实体和特殊取值规则;多个字段合并到同一次调用**。
106
- - 3c. SDK 类名/方法签名不在 cheat-sheet 中 → 查 `cosmic-api-knowledge.py`。**与 3b 互不依赖,应同时发起**。
103
+ - 调用工具前,先查下方“KCode 工具路由”表格确认参数;表格未覆盖时读取工具 schema。
104
+ - 3a. 若目标 API 已在 `rules/cheat-sheet.md` 中列出 → 直接使用,**无需额外工具验证**。
105
+ - 3b. 字段 / `entityId` / 枚举值验证 → 查 `kd_cosmic_metadata`。**只要要生成代码且已知目标单据/表单,凡涉及字段(无论用户给中文名还是英文标识),都必须验证字段是否存在、字段类型、所属实体和特殊取值规则;多个字段合并到同一次调用**。
106
+ - 3c. SDK 类名/方法签名不在 cheat-sheet 中 → 查 `kd_cosmic_api`,并优先结合项目 SDK/编译结果做红绿验证。**与 3b 互不依赖,应同时发起**。
107
107
  - 3d. 需要查询多个不同类的 detail → **多个 `detail` 调用也可并行**。
108
- - ⚠️ `cosmic-basedata-query.py` 必须等 `entityId` 从 3b 确认后才能调用,**不可并行**。
108
+ - ⚠️ 基础资料实时数据查询必须等 `entityId` 从 3b 确认后才能进行;npm 包不再内置 Python 基础资料脚本,需要项目侧接口、SQL 或人工证据。
109
109
  4. 只有"插件类型 + 事件方法 + 字段/签名"都确认后,才开始生成代码。
110
110
  5. 编写代码时遵守最小干预:插件只做当前事件该做的事;能用封装就不退回原生。
111
- 6. **代码生成后,必须执行 `cosmic-post-check.py` 自动校验**,详见"代码生成后自动校验"章节。
111
+ 6. **代码生成后,必须执行 `kd_check`,条件允许时再执行 `kd_build` 或项目编译命令**,详见"代码生成后自动校验"章节。
112
112
 
113
113
  ## 写代码前的最小确认卡
114
114
 
@@ -119,105 +119,56 @@ description: "金蝶云苍穹开发主 Skill,优先复用 kd-cd-cosmic-commons
119
119
  | 1 | 插件类型 | 决策矩阵 |
120
120
  | 2 | 目标事件方法 | 模板 / references |
121
121
  | 3 | 使用模板 | `assets/*.java` |
122
- | 4 | 已验证字段 / refType / entityId | 生成代码且已知目标单据/表单时,字段中文名/英文标识都必须经 `cosmic-form-metadata.py` 确认;`entityId` 来自用户明确给出或元数据脚本确认 |
123
- | 5 | 已确认枚举/下拉选项值(有使用时) | `cosmic-form-metadata.py --show-detail` |
124
- | 6 | 已验证类/方法签名 | cheat-sheet / `cosmic-api-knowledge.py` / 业务拓展点 `--full` 返回的清晰 Java 示例 |
122
+ | 4 | 已验证字段 / refType / entityId | 生成代码且已知目标单据/表单时,字段中文名/英文标识都必须经 `kd_cosmic_metadata` 确认;`entityId` 来自用户明确给出或元数据证据确认 |
123
+ | 5 | 已确认枚举/下拉选项值(有使用时) | `kd_cosmic_metadata showDetail=true` |
124
+ | 6 | 已验证类/方法签名 | cheat-sheet / `kd_cosmic_api` / 项目 SDK / 编译结果 / 业务拓展点清晰 Java 示例 |
125
125
 
126
- ## 脚本路由
126
+ ## KCode 工具路由
127
127
 
128
- ### 脚本调用协议
128
+ ### 工具调用协议
129
129
 
130
- 常用脚本的调用模板已列在下方表格,可直接按模板执行。仅当参数不确定或下表未覆盖时,才需先执行 `python3 <script> --help` 确认调用方式。
130
+ npm 包不发布 Python/JAR/bat/sh 运行资产;官方脚本能力已迁移为 KCode Node 适配器。所有查询和校验优先使用下表工具,不要尝试执行 `scripts/*.py`。
131
131
 
132
- ### 先选脚本,再按模板调用
133
-
134
- | 场景 | 优先脚本 | 常用用法 | 调用模板 | 备注 |
135
- |---|---|---|---|---|
136
- | SDK 类名、方法名、继承链、`@Override` 签名确认 | `scripts/cosmic-api-knowledge.py` | `search` / `search-method` / `detail` | `python3 <SKILL_ROOT>/scripts/cosmic-api-knowledge.py --config ok-cosmic.json <subcommand> ...` | `detail` 支持逗号分隔批量查类详情(并发请求) |
137
- | 字段标识、枚举映射、`refType`、按中文名确认真实英文标识 | `scripts/cosmic-form-metadata.py` | `get` | `python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get ...` | 字段不确定先查它。`formIdOrName` 支持逗号分隔批量查询(formId 与中文名可混合,自动识别,并发请求) |
138
- | 已确认 `entityId` 后查询基础资料编码/名称/完整数据 | `scripts/cosmic-basedata-query.py` | `get` | `python3 <SKILL_ROOT>/scripts/cosmic-basedata-query.py --config ok-cosmic.json get ...` | 只在 `entityId` 来源已确认后调用 |
139
- | 查询业务拓展点 / SDK 扩展接口候选 | `scripts/cosmic-extpoints-query.py` | `get` | `python3 <SKILL_ROOT>/scripts/cosmic-extpoints-query.py --config ok-cosmic.json get --keyword ...` | 默认摘要模式;仅在需要生成代码或查看 Java 示例时加 `--full`;若 `--full` 已返回清晰 Java 示例,可先按示例,不强制立即 `detail` |
140
- | 生成或修改苍穹 Java 代码后的统一校验 | `scripts/cosmic-post-check.py` | 直接执行 | `python3 <SKILL_ROOT>/scripts/cosmic-post-check.py <file_or_directory> --fix-hint` | 必须形成"生成 -> 校验 -> 修复 -> 复检"闭环 |
132
+ | 场景 | 优先工具 | 常用参数 | 备注 |
133
+ |---|---|---|---|
134
+ | SDK 类名、方法名、继承链、`@Override` 签名确认 | `kd_cosmic_api` | `mode=search/search-method/detail`、`query`、`method`、`compact` | 随包知识给线索;精确签名优先结合项目 SDK/编译红绿验证 |
135
+ | 字段标识、枚举映射、`refType`、按中文名确认真实英文标识 | `kd_cosmic_metadata` | `form`、`fuzzy`、`typeFilter`、`sql`、`op`、`showDetail` | 字段不确定先查它;多个表单用逗号合并 |
136
+ | 已确认 `entityId` 后查询基础资料编码/名称/完整数据 | 项目侧接口/SQL/人工证据 | 先由 `kd_cosmic_metadata` 确认 `entityId` | KCode 不内置实时基础资料 Python 查询脚本 |
137
+ | 查询业务拓展点 / SDK 扩展接口候选 | `kd_search` + `kd_cosmic_api` | 业务关键词、接口类名、方法名 | 命中接口类名后用 `kd_cosmic_api detail` 或编译确认签名 |
138
+ | 生成或修改苍穹 Java 代码后的统一校验 | `kd_check` + `kd_build` | 修改文件路径、项目构建命令 | 必须形成"生成 -> 校验 -> 修复 -> 复检"闭环 |
141
139
 
142
140
  ### 常用用法示例
143
141
 
144
- ```bash
145
- # 搜索类名
146
- python3 <SKILL_ROOT>/scripts/cosmic-api-knowledge.py --config ok-cosmic.json search QueryServiceHelper
147
-
148
- # 搜索方法名
149
- python3 <SKILL_ROOT>/scripts/cosmic-api-knowledge.py --config ok-cosmic.json search-method loadSingle
150
-
151
- # 查看类详情(全部方法)
152
- python3 <SKILL_ROOT>/scripts/cosmic-api-knowledge.py --config ok-cosmic.json detail kd.bos.servicehelper.QueryServiceHelper
153
-
154
- # 查看类详情(单个方法筛选)
155
- python3 <SKILL_ROOT>/scripts/cosmic-api-knowledge.py --config ok-cosmic.json detail kd.bos.servicehelper.QueryServiceHelper --method loadSingle --compact
156
-
157
- # 批量查类详情(逗号分隔,并发请求)
158
- python3 <SKILL_ROOT>/scripts/cosmic-api-knowledge.py --config ok-cosmic.json detail kd.bos.servicehelper.QueryServiceHelper,kd.bos.servicehelper.SaveServiceHelper --method save --compact
159
-
160
- # 查元数据字段
161
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order
162
-
163
- # 查元数据字段(带数据库相关信息)
164
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order,ap_finapbill --sql
165
-
166
- # 批量查询多个单据(逗号分隔)
167
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order,ap_finapbill --fuzzy supplier
168
-
169
- # 混合查询:formId + 中文单据名(自动识别)
170
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get "ap_finapbill,物料,bd_supplier" --fuzzy number
171
-
172
- # 模糊筛选字段
173
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order --fuzzy qty price amount
174
-
175
- # 按多种字段类型筛选(正则 OR)
176
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order --type "combo|check"
177
-
178
- # 类型 + 关键词交集筛选(Decimal 类型且含 amount)
179
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order --type decimal --fuzzy amount
180
-
181
- # 按单据中文名查元数据
182
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get 物料
183
-
184
- # 查看单据所有操作
185
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order --op
186
-
187
- # 按关键词筛选操作
188
- python3 <SKILL_ROOT>/scripts/cosmic-form-metadata.py --config ok-cosmic.json get sal_order --op 审核 提交
189
-
190
- # 查基础资料
191
- python3 <SKILL_ROOT>/scripts/cosmic-basedata-query.py --config ok-cosmic.json get --entity-id bd_material --number-or-name 01.0001
192
-
193
- # 查业务拓展点
194
- python3 <SKILL_ROOT>/scripts/cosmic-extpoints-query.py --config ok-cosmic.json get --keyword 应付
195
-
196
- # 代码校验
197
- python3 <SKILL_ROOT>/scripts/cosmic-post-check.py ./src/main/java/MyPlugin.java --fix-hint
142
+ ```text
143
+ kd_cosmic_config
144
+ kd_cosmic_api mode=search query=QueryServiceHelper
145
+ kd_cosmic_api mode=search-method query=loadSingle
146
+ kd_cosmic_api mode=detail query=kd.bos.servicehelper.QueryServiceHelper method=loadSingle compact=true
147
+ kd_cosmic_metadata form=sal_order
148
+ kd_cosmic_metadata form=sal_order,ap_finapbill sql=true
149
+ kd_cosmic_metadata form=sal_order fuzzy="qty price amount"
150
+ kd_cosmic_metadata form=sal_order typeFilter="combo|check" showDetail=true
151
+ kd_cosmic_metadata form=sal_order op=true fuzzy="审核 提交"
152
+ kd_check path=./src/main/java/MyPlugin.java
153
+ kd_build
198
154
  ```
199
155
 
200
- ### 跨脚本硬约束
201
-
202
- - 完成 Step 0 后,后续脚本优先显式使用 `--config ok-cosmic.json`;若当前工作目录不是项目根目录,再传绝对路径。不要为了拼配置路径先额外搜索 `ok-cosmic.json`。
203
- - **参数不确定时**,先执行 `python3 <script> --help` 确认调用方式;如果 `--help` 仍不足以确认,就停止并报告。
204
- - **凡是带子命令的脚本,`--config` 等全局参数统一放在子命令前,按 `python3 <script> --config ok-cosmic.json <subcommand> ...` 组织。**
205
- - `entityId` 只允许来自"用户明确给出的准确英文标识"或"元数据脚本确认出的真实标识";来源不明时,先查 `cosmic-form-metadata.py`,不得直接执行基础资料查询。
206
- - **字段生成代码强制验证**:只要要生成/修改代码,且已知目标单据/表单(`formId` 或 `billName`),凡涉及字段(无论用户给的是中文名还是英文标识),都必须先用 `cosmic-form-metadata.py` 验证字段是否存在、字段类型、所属实体(表头/表体/子表体/容器)和特殊取值规则(如 `BasedataPropField` 的 `refType`、`LargeTextField` 的 `{fieldKey}_tag`、Combo/下拉字段的 Ext 映射)。目标单据/表单不明确时,先确认目标,不要直接把用户给的字段写进代码。
207
- - **枚举/下拉选项值禁猜 [A1.8]**:使用 ComboField / 下拉字段的具体选项值前,必须先查 `cosmic-form-metadata.py` 的 Ext 列确认真实映射,详见 [constraints.md](rules/constraints.md) A1.8。
208
- - 需要确认多个字段时,优先一次性合并到同一次元数据查询里;不要逐个字段重复调用脚本。
209
- - **并行调用**:`cosmic-form-metadata.py`(字段/枚举验证)与 `cosmic-api-knowledge.py`(类/方法签名验证)查询不同数据源、互不依赖,应在同一轮并行发起。同理,多个 `detail` 查询、多个文件读取也应并行。唯一例外:`cosmic-basedata-query.py` 依赖 `entityId` 确认结果,必须串行等待。
210
- - **元数据批量查询**:`cosmic-form-metadata.py` 的 `formIdOrName` 位置参数支持逗号分隔多个查询目标(如 `get sal_order,ap_finapbill,物料`),含中文的自动走 billName、英文标识走 formId,脚本内部通过 `ThreadPoolExecutor` 并发请求(最多 4 线程),结果按原始顺序拼接输出。跨单据场景(如下推、对比源单与目标单字段)优先使用批量查询,减少脚本调用次数。
156
+ ### 跨工具硬约束
157
+
158
+ - 完成 Step 0 后,后续工具可显式传 `config=<ok-cosmic.json>`;当前项目没有 `ok-cosmic.json` 时,KCode 使用随包默认知识库并输出 warning。不要把苍穹工程 `cosmic.json` 当成 `ok-cosmic.json`。
159
+ - `entityId` 只允许来自"用户明确给出的准确英文标识"或"`kd_cosmic_metadata` 确认出的真实标识";来源不明时,先查元数据,不得直接查询基础资料或写入代码。
160
+ - **字段生成代码强制验证**:只要要生成/修改代码,且已知目标单据/表单(`formId` `billName`),凡涉及字段(无论用户给的是中文名还是英文标识),都必须先用 `kd_cosmic_metadata` 验证字段是否存在、字段类型、所属实体和特殊取值规则。目标单据/表单不明确时,先确认目标,不要直接把用户给的字段写进代码。
161
+ - **枚举/下拉选项值禁猜 [A1.8]**:使用 ComboField / 下拉字段的具体选项值前,必须先查 `kd_cosmic_metadata showDetail=true` 的附加信息确认真实映射,详见 [constraints.md](rules/constraints.md) A1.8。
162
+ - 需要确认多个字段时,优先一次性合并到同一次元数据查询里;不要逐个字段重复调用工具。
163
+ - **并行调用**:`kd_cosmic_metadata`(字段/枚举验证)与 `kd_cosmic_api`(类/方法签名验证)查询不同数据源、互不依赖,应在同一轮并行发起。
211
164
  - 查询超时或远端失败时,只能基于当前会话里已确认的字段、`refType`、`entityId`、接口返回继续;若本次查询结果是继续前提,则停止。
212
- - 若 Traceback 明确指向 Skill 脚本实现问题,立即停止并报告命令与错误摘要;不要绕过验证继续生成依赖该事实的代码。
213
- - 只有在用户已修正配置/环境,或本次明确修改了查询条件后,才允许重试同类脚本;不要原样重复执行。
214
165
 
215
166
  ### 项目级配置文件 (`ok-cosmic.json`)
216
167
 
217
- 脚本依赖 `ok-cosmic.json` 获取数据库路径及 API 地址。若需模板可参考 `<SKILL_ROOT>/setup/ok-cosmic.json`。
168
+ KCode 适配器可读取 `ok-cosmic.json` 获取知识库路径及在线路由 API 地址。若项目没有该文件,会使用随包默认知识库并输出 warning;苍穹工程自带的 `cosmic.json` 不是 KCode 官方能力配置。
218
169
 
219
- - **显式指定**: 调用脚本时建议指定 `--config <路径>`。未指定时读取**当前执行目录**下的 `ok-cosmic.json`;不存在则报错。
220
- - **在线查询配置**: 三个在线查询脚本统一走 `route.apiUrl`(`runtime/route`,URL 中包含 `openApiSign`)/ `route.timeoutSeconds`;脚本内部通过 `data.type=meta|basedata|extpoint` 路由。
170
+ - **显式指定**: 调用工具时可指定 `config=<路径>`。未指定时优先读取当前项目根目录下的 `ok-cosmic.json`;不存在则使用随包默认配置。
171
+ - **在线查询配置**: 元数据在线查询走 `route.apiUrl`(`runtime/route`,URL 中可包含 `openApiSign`)/ `route.timeoutSeconds`;KCode 内部通过 `data.type=meta` 路由。
221
172
  - **统一路由请求体**: 元数据 `data.type=meta` + `reqData.entityId/formId/billName/full`;基础资料 `data.type=basedata` + `reqData.entityId/numberOrName/full`;业务拓展点 `data.type=extpoint` + `reqData.keyword`。
222
173
 
223
174
  ## 扩展代码库探索(Extension Repos Fallback)
@@ -236,16 +187,16 @@ python3 <SKILL_ROOT>/scripts/cosmic-post-check.py ./src/main/java/MyPlugin.java
236
187
  - 扩展代码库仅作为**实现参考**,不等同于 ok-cosmic 推荐写法。
237
188
  - 生成代码时仍须遵守 A 层硬约束(`rules/constraints.md`、`rules/anti-patterns.md`)与 B 层编码偏好(`rules/coding-preferences.md`)。
238
189
  - 若扩展代码与 ok-cosmic 规范冲突,**以 ok-cosmic 规范为准**;只借鉴参考项目的业务组装方式与字段暴露结构。
239
- - 若扩展代码库中未搜到相关实现,回落到 fallback 第 3 步(`cosmic-api-knowledge.py search`)后再向用户确认。
190
+ - 若扩展代码库中未搜到相关实现,回落到 fallback 第 3 步(`kd_cosmic_api mode=search`)后再向用户确认。
240
191
 
241
192
  ## 代码生成后自动校验(Post-Check)
242
193
 
243
194
  修改任何苍穹 `.java` 文件后,必须执行:
244
195
 
245
- `python3 <SKILL_ROOT>/scripts/cosmic-post-check.py <生成的文件或目录> --fix-hint`
196
+ `kd_check path=<生成的文件或目录>`
246
197
 
247
198
  - `ERROR` → 必须修复并复检;`WARNING` → 优先修复;`INFO` → 治理参考,不阻断。
248
- - Gradle 项目编译成功后仍串联 post-lint 静态校验,以综合结果为准;非 Gradle 直接回退静态 lint。
199
+ - 条件允许时继续执行 `kd_build` 或项目 Gradle/Maven 编译命令;编译与静态校验以综合结果为准。
249
200
  - 最多连续 3 轮"修复 → 复检";3 轮后仍有 `ERROR`,向用户报告。
250
201
  - 规则 ID 映射、修复示例、历史项目解释口径见 [rules/post-check.md](rules/post-check.md)。
251
202
 
@@ -3,14 +3,14 @@ interface:
3
3
  short_description: "封装优先的苍穹开发主 skill"
4
4
  default_prompt: |
5
5
  使用 $ok-cosmic 来实现或审查苍穹插件代码。严格遵循以下流程:
6
- 0. 首先执行 cosmic-config-check.py 完成配置预检;ERROR 必须停止,WARNING 需告知用户受限能力
6
+ 0. 首先执行 kd_cosmic_config 完成配置预检;ERROR 必须停止,WARNING 需告知用户受限能力
7
7
  1. 先查 SKILL.md 决策矩阵确定插件类型和对应模板
8
8
  2. 读 references/*.md 确认事件边界和适用场景
9
9
  3. 读 assets/*.java 模板沿用已有骨架,小场景查 snippets 映射表
10
- 4. 首次调用任何脚本前,先执行 --help 读取调用契约,定好命令模板后再填参数执行(三步首调协议)
11
- 5. 字段不确定先查 cosmic-form-metadata.py;entityId 来源不明先查 cosmic-form-metadata.py(查 refType 或按中文名确认英文标识),严禁凭经验猜 entityId;枚举/下拉选项值必须查 --show-detail 的 Ext 列确认(A1.8 硬约束),严禁凭空编造;SDK 签名不确定先查 cosmic-api-knowledge.py
10
+ 4. 首次调用任何 KCode 工具前,先读取工具 schema,定好参数后再执行
11
+ 5. 字段不确定先查 kd_cosmic_metadata;entityId 来源不明先查 kd_cosmic_metadata(查 refType 或按中文名确认英文标识),严禁凭经验猜 entityId;枚举/下拉选项值必须查 showDetail=true 的 Ext 列确认(A1.8 硬约束),严禁凭空编造;SDK 签名不确定先查 kd_cosmic_api
12
12
  6. 只有"插件类型 + 事件方法 + 字段/基础资料/签名 + 枚举值来源"都确认后,才开始生成代码
13
- 7. 代码生成后,执行 cosmic-post-check.py 自动校验,有 ERROR 须修复后重验
13
+ 7. 代码生成后,执行 kd_check,条件允许时执行 kd_build 或项目编译;有 ERROR 须修复后重验
14
14
  核心原则:封装优先(kd-cd-cosmic-commons),原生兜底;严禁凭记忆猜测 API 签名。
15
15
 
16
16
  policy: