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.
- package/README.md +18 -2
- package/package.json +1 -1
- package/src/official/kingdee-skills.ts +60 -13
- package/src/rules/checker.ts +143 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +2 -2
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +52 -101
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +4 -4
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +21 -20
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +1 -1
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +1 -1
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +2 -2
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +4 -4
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +3 -3
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +8 -8
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +1 -1
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +19 -18
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +9 -9
- package/vendor/kingdee-skills/ok-ksql/manifest.json +2 -1
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +2 -2
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +0 -336
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +0 -121
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +0 -295
- package/vendor/kingdee-skills/ok-cosmic/README.md +0 -460
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +0 -2
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +0 -204
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +0 -910
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +0 -359
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +0 -181
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +0 -389
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +0 -856
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +0 -262
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +0 -293
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +0 -2
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +0 -393
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +0 -176
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +0 -375
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +0 -434
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +0 -36
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +0 -186
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +0 -40
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +0 -142
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +0 -18
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +0 -53
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- 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
|
|
418
|
-
- `kd_cosmic_metadata`
|
|
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
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
247
|
+
let loaded: LoadedCosmicConfig | undefined;
|
|
239
248
|
try {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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 (
|
|
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 =
|
|
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 或中文单据名。" };
|
package/src/rules/checker.ts
CHANGED
|
@@ -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
|
-
**使用
|
|
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
|
-
`
|
|
16
|
+
1. Step 0 的第一个动作必须直接执行 KCode 工具:
|
|
17
|
+
`kd_cosmic_config`
|
|
18
18
|
2. 默认在当前项目工作目录直接执行;不要先询问或搜索 `ok-cosmic.json` 的位置。
|
|
19
19
|
3. 只有用户明确提供了其他配置路径,或当前工作目录不是目标项目根目录时,才改用:
|
|
20
|
-
`
|
|
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 不可达" 或 "在线服务不可用" |
|
|
27
|
-
| "知识库不存在" | `
|
|
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
|
-
-
|
|
104
|
-
- 3a. 若目标 API 已在 `rules/cheat-sheet.md` 中列出 →
|
|
105
|
-
- 3b. 字段 / `entityId` / 枚举值验证 → 查 `
|
|
106
|
-
- 3c. SDK 类名/方法签名不在 cheat-sheet 中 → 查 `
|
|
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
|
-
- ⚠️
|
|
108
|
+
- ⚠️ 基础资料实时数据查询必须等 `entityId` 从 3b 确认后才能进行;npm 包不再内置 Python 基础资料脚本,需要项目侧接口、SQL 或人工证据。
|
|
109
109
|
4. 只有"插件类型 + 事件方法 + 字段/签名"都确认后,才开始生成代码。
|
|
110
110
|
5. 编写代码时遵守最小干预:插件只做当前事件该做的事;能用封装就不退回原生。
|
|
111
|
-
6. **代码生成后,必须执行 `
|
|
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 | 生成代码且已知目标单据/表单时,字段中文名/英文标识都必须经 `
|
|
123
|
-
| 5 | 已确认枚举/下拉选项值(有使用时) | `
|
|
124
|
-
| 6 | 已验证类/方法签名 | cheat-sheet / `
|
|
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
|
-
|
|
130
|
+
本 npm 包不发布 Python/JAR/bat/sh 运行资产;官方脚本能力已迁移为 KCode Node 适配器。所有查询和校验优先使用下表工具,不要尝试执行 `scripts/*.py`。
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
|
135
|
-
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
|
|
|
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
|
-
```
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
- `
|
|
206
|
-
-
|
|
207
|
-
-
|
|
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
|
-
|
|
168
|
+
KCode 适配器可读取 `ok-cosmic.json` 获取知识库路径及在线路由 API 地址。若项目没有该文件,会使用随包默认知识库并输出 warning;苍穹工程自带的 `cosmic.json` 不是 KCode 官方能力配置。
|
|
218
169
|
|
|
219
|
-
- **显式指定**:
|
|
220
|
-
- **在线查询配置**:
|
|
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 步(`
|
|
190
|
+
- 若扩展代码库中未搜到相关实现,回落到 fallback 第 3 步(`kd_cosmic_api mode=search`)后再向用户确认。
|
|
240
191
|
|
|
241
192
|
## 代码生成后自动校验(Post-Check)
|
|
242
193
|
|
|
243
194
|
修改任何苍穹 `.java` 文件后,必须执行:
|
|
244
195
|
|
|
245
|
-
`
|
|
196
|
+
`kd_check path=<生成的文件或目录>`
|
|
246
197
|
|
|
247
198
|
- `ERROR` → 必须修复并复检;`WARNING` → 优先修复;`INFO` → 治理参考,不阻断。
|
|
248
|
-
-
|
|
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. 首先执行
|
|
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.
|
|
11
|
-
5. 字段不确定先查
|
|
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. 代码生成后,执行
|
|
13
|
+
7. 代码生成后,执行 kd_check,条件允许时执行 kd_build 或项目编译;有 ERROR 须修复后重验
|
|
14
14
|
核心原则:封装优先(kd-cd-cosmic-commons),原生兜底;严禁凭记忆猜测 API 签名。
|
|
15
15
|
|
|
16
16
|
policy:
|