kcode-pi 0.1.14 → 0.1.16
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 +31 -25
- package/dist/context/project-context.js +20 -20
- package/extensions/kingdee-harness.ts +89 -82
- package/extensions/kingdee-header.ts +16 -16
- package/extensions/kingdee-tools.ts +112 -83
- package/package.json +2 -2
- package/prompts/kd-discuss.md +4 -4
- package/prompts/kd-execute.md +4 -5
- package/prompts/kd-plan.md +4 -5
- package/prompts/kd-ship.md +4 -5
- package/prompts/kd-spec.md +4 -5
- package/prompts/kd-verify.md +4 -5
- package/src/context/project-context.ts +20 -20
- package/src/harness/artifacts.ts +52 -47
- package/src/harness/format.ts +12 -12
- package/src/harness/gates.ts +23 -13
- package/src/harness/plan-steps.ts +3 -3
- package/src/harness/sdk-policy.ts +37 -0
- package/src/harness/state.ts +4 -4
- package/src/harness/tdd-policy.ts +2 -2
- package/src/knowledge/format.ts +11 -12
- package/src/product/profile.ts +16 -16
- package/src/tools/build-debug.ts +35 -35
- package/src/tools/sdk-signature.ts +10 -10
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
3
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { Type } from "@earendil-works/pi-ai";
|
|
5
5
|
import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { formatSearchResults, formatTableSchema } from "../src/knowledge/format.ts";
|
|
@@ -22,6 +22,9 @@ import {
|
|
|
22
22
|
writeOfficialEvidence,
|
|
23
23
|
} from "../src/official/kingdee-skills.ts";
|
|
24
24
|
import { resolveWorkspacePath } from "../src/platform/path.ts";
|
|
25
|
+
import { readActiveRun } from "../src/harness/state.ts";
|
|
26
|
+
import { runArtifactPath } from "../src/harness/paths.ts";
|
|
27
|
+
import { SDK_SIGNATURE_EVIDENCE } from "../src/harness/sdk-policy.ts";
|
|
25
28
|
|
|
26
29
|
const extensionDir = dirname(fileURLToPath(import.meta.url));
|
|
27
30
|
const knowledgePath = join(extensionDir, "..", "knowledge");
|
|
@@ -74,8 +77,8 @@ function sdkLanguageForProfile(profile: ProductProfile, value: string | undefine
|
|
|
74
77
|
|
|
75
78
|
function rejectNonCosmic(profile: ProductProfile): string | undefined {
|
|
76
79
|
if (isCosmicFamily(profile)) return undefined;
|
|
77
|
-
if (profile.product === "unknown") return "
|
|
78
|
-
return
|
|
80
|
+
if (profile.product === "unknown") return "请先提供 Cosmic 家族产品:cangqiong、xinghan、flagship 或 cosmic。";
|
|
81
|
+
return `当前产品 ${profile.product} 使用 ${profile.platform}/${profile.techStack},不适用 Cosmic 官方能力。`;
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
async function runOrDryRun(
|
|
@@ -87,7 +90,7 @@ async function runOrDryRun(
|
|
|
87
90
|
const command = await commandPromise;
|
|
88
91
|
if (dryRun) {
|
|
89
92
|
return {
|
|
90
|
-
content: [{ type: "text" as const, text:
|
|
93
|
+
content: [{ type: "text" as const, text: `仅展示命令,不执行:\n${command.display}` }],
|
|
91
94
|
details: { command: command.display, dryRun: true },
|
|
92
95
|
};
|
|
93
96
|
}
|
|
@@ -102,13 +105,13 @@ async function runOrDryRun(
|
|
|
102
105
|
|
|
103
106
|
const kdSearchTool = defineTool({
|
|
104
107
|
name: "kd_search",
|
|
105
|
-
label: "KD
|
|
106
|
-
description: "
|
|
108
|
+
label: "KD 搜索",
|
|
109
|
+
description: "搜索 KCode 随包金蝶知识库,包括 SDK、插件生命周期、代码模式和常见实现建议。",
|
|
107
110
|
parameters: Type.Object({
|
|
108
|
-
query: Type.String({ description: "
|
|
109
|
-
product: Type.Optional(Type.String({ description: "
|
|
110
|
-
edition: Type.Optional(Type.String({ description: "
|
|
111
|
-
limit: Type.Optional(Type.Number({ description: "
|
|
111
|
+
query: Type.String({ description: "要搜索的关键词、API、类名、表名或生命周期术语。" }),
|
|
112
|
+
product: Type.Optional(Type.String({ description: "金蝶产品:flagship、cosmic、xinghan、cangqiong 或 enterprise。" })),
|
|
113
|
+
edition: Type.Optional(Type.String({ description: "旧参数,等同于 product。优先使用 product。" })),
|
|
114
|
+
limit: Type.Optional(Type.Number({ description: "最大结果数,默认 5。" })),
|
|
112
115
|
}),
|
|
113
116
|
|
|
114
117
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
@@ -117,15 +120,15 @@ const kdSearchTool = defineTool({
|
|
|
117
120
|
if (!scopes) {
|
|
118
121
|
const guidance =
|
|
119
122
|
profile.product === "unknown"
|
|
120
|
-
? "
|
|
121
|
-
: "
|
|
123
|
+
? "请先提供 product,例如 flagship、enterprise、cosmic、xinghan 或 cangqiong。"
|
|
124
|
+
: "当前产品画像未配置可搜索知识范围。";
|
|
122
125
|
return {
|
|
123
126
|
content: [
|
|
124
127
|
{
|
|
125
128
|
type: "text",
|
|
126
129
|
text: [
|
|
127
|
-
|
|
128
|
-
"
|
|
130
|
+
`产品画像:${profile.product}/${profile.techStack}/${profile.language}`,
|
|
131
|
+
"KCode 随包知识库搜索需要明确产品画像。",
|
|
129
132
|
guidance,
|
|
130
133
|
].join("\n"),
|
|
131
134
|
},
|
|
@@ -145,12 +148,12 @@ const kdSearchTool = defineTool({
|
|
|
145
148
|
|
|
146
149
|
const kdTableTool = defineTool({
|
|
147
150
|
name: "kd_table",
|
|
148
|
-
label: "KD
|
|
149
|
-
description: "
|
|
151
|
+
label: "KD 表结构",
|
|
152
|
+
description: "按表名查询 KCode 随包金蝶表结构,查询结果受产品画像约束。",
|
|
150
153
|
parameters: Type.Object({
|
|
151
|
-
table: Type.String({ description: "
|
|
152
|
-
product: Type.Optional(Type.String({ description: "
|
|
153
|
-
edition: Type.Optional(Type.String({ description: "
|
|
154
|
+
table: Type.String({ description: "表名,例如 T_PUR_POORDER。" }),
|
|
155
|
+
product: Type.Optional(Type.String({ description: "金蝶产品:flagship、cosmic、xinghan、cangqiong 或 enterprise。" })),
|
|
156
|
+
edition: Type.Optional(Type.String({ description: "旧参数,等同于 product。优先使用 product。" })),
|
|
154
157
|
}),
|
|
155
158
|
|
|
156
159
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
@@ -159,15 +162,15 @@ const kdTableTool = defineTool({
|
|
|
159
162
|
if (!edition) {
|
|
160
163
|
const guidance =
|
|
161
164
|
profile.product === "unknown"
|
|
162
|
-
? "
|
|
163
|
-
: "
|
|
165
|
+
? "请先提供 product。不要跨金蝶产品族猜测表结构。"
|
|
166
|
+
: "没有元数据查证前,不要把旗舰版/企业版表结构假设复用到苍穹/星瀚/Cosmic。";
|
|
164
167
|
return {
|
|
165
168
|
content: [
|
|
166
169
|
{
|
|
167
170
|
type: "text",
|
|
168
171
|
text: [
|
|
169
|
-
|
|
170
|
-
"
|
|
172
|
+
`产品画像:${profile.product}/${profile.techStack}/${profile.language}`,
|
|
173
|
+
"KCode 随包表结构目前主要覆盖旗舰版和企业版。",
|
|
171
174
|
guidance,
|
|
172
175
|
].join("\n"),
|
|
173
176
|
},
|
|
@@ -186,14 +189,14 @@ const kdTableTool = defineTool({
|
|
|
186
189
|
|
|
187
190
|
const kdCheckTool = defineTool({
|
|
188
191
|
name: "kd_check",
|
|
189
|
-
label: "KD
|
|
192
|
+
label: "KD 检查",
|
|
190
193
|
description:
|
|
191
|
-
"
|
|
194
|
+
"检查金蝶 Java/C#/Python 插件代码中的魔法值、命名问题、循环内 DB 调用和空 catch 等问题。",
|
|
192
195
|
parameters: Type.Object({
|
|
193
|
-
code: Type.Optional(Type.String({ description: "
|
|
194
|
-
path: Type.Optional(Type.String({ description: "
|
|
195
|
-
product: Type.Optional(Type.String({ description: "
|
|
196
|
-
language: Type.Optional(Type.String({ description: "
|
|
196
|
+
code: Type.Optional(Type.String({ description: "要检查的源码。与 path 二选一。" })),
|
|
197
|
+
path: Type.Optional(Type.String({ description: "要检查的源码文件路径。与 code 二选一。" })),
|
|
198
|
+
product: Type.Optional(Type.String({ description: "金蝶产品。未提供 language 时用于推导 Java 或 C#。" })),
|
|
199
|
+
language: Type.Optional(Type.String({ description: "语言:java、csharp 或 python。会覆盖产品推导结果。" })),
|
|
197
200
|
}),
|
|
198
201
|
|
|
199
202
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -210,7 +213,7 @@ const kdCheckTool = defineTool({
|
|
|
210
213
|
|
|
211
214
|
if (!code) {
|
|
212
215
|
return {
|
|
213
|
-
content: [{ type: "text", text: "
|
|
216
|
+
content: [{ type: "text", text: "kd_check 需要提供 code 或 path。" }],
|
|
214
217
|
details: { error: "missing-code-or-path" },
|
|
215
218
|
};
|
|
216
219
|
}
|
|
@@ -220,7 +223,7 @@ const kdCheckTool = defineTool({
|
|
|
220
223
|
content: [
|
|
221
224
|
{
|
|
222
225
|
type: "text",
|
|
223
|
-
text:
|
|
226
|
+
text: `来源:${source}\n产品:${profile.product}/${profile.techStack}\n语言:${language}\n\n${formatCheckResults(results)}`,
|
|
224
227
|
},
|
|
225
228
|
],
|
|
226
229
|
details: { source, product: profile.product, language, issues: results },
|
|
@@ -230,12 +233,12 @@ const kdCheckTool = defineTool({
|
|
|
230
233
|
|
|
231
234
|
const kdCosmicConfigTool = defineTool({
|
|
232
235
|
name: "kd_cosmic_config",
|
|
233
|
-
label: "KD Cosmic
|
|
234
|
-
description: "
|
|
236
|
+
label: "KD Cosmic 配置",
|
|
237
|
+
description: "运行 Cosmic 家族金蝶产品的官方能力配置预检查。",
|
|
235
238
|
parameters: Type.Object({
|
|
236
|
-
product: Type.String({ description: "Cosmic
|
|
237
|
-
config: Type.Optional(Type.String({ description: "
|
|
238
|
-
dryRun: Type.Optional(Type.Boolean({ description: "
|
|
239
|
+
product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagship 或 cosmic。" }),
|
|
240
|
+
config: Type.Optional(Type.String({ description: "可选 ok-cosmic.json 路径。默认按当前工作目录解析。" })),
|
|
241
|
+
dryRun: Type.Optional(Type.Boolean({ description: "只返回命令,不实际执行。" })),
|
|
239
242
|
}),
|
|
240
243
|
|
|
241
244
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -248,18 +251,18 @@ const kdCosmicConfigTool = defineTool({
|
|
|
248
251
|
|
|
249
252
|
const kdCosmicMetadataTool = defineTool({
|
|
250
253
|
name: "kd_cosmic_metadata",
|
|
251
|
-
label: "KD Cosmic
|
|
252
|
-
description: "
|
|
254
|
+
label: "KD Cosmic 元数据",
|
|
255
|
+
description: "查询官方 Cosmic 表单/单据元数据,包括字段、枚举值、操作和 SQL 表信息。",
|
|
253
256
|
parameters: Type.Object({
|
|
254
|
-
product: Type.String({ description: "Cosmic
|
|
255
|
-
form: Type.String({ description: "Form ID
|
|
256
|
-
config: Type.Optional(Type.String({ description: "
|
|
257
|
-
fuzzy: Type.Optional(Type.String({ description: "
|
|
258
|
-
typeFilter: Type.Optional(Type.String({ description: "
|
|
259
|
-
sql: Type.Optional(Type.Boolean({ description: "
|
|
260
|
-
op: Type.Optional(Type.Boolean({ description: "
|
|
261
|
-
showDetail: Type.Optional(Type.Boolean({ description: "
|
|
262
|
-
dryRun: Type.Optional(Type.Boolean({ description: "
|
|
257
|
+
product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagship 或 cosmic。" }),
|
|
258
|
+
form: Type.String({ description: "Form ID、单据 ID 或中文单据名;多个目标可用逗号分隔。" }),
|
|
259
|
+
config: Type.Optional(Type.String({ description: "可选 ok-cosmic.json 路径。" })),
|
|
260
|
+
fuzzy: Type.Optional(Type.String({ description: "可选字段关键词,用空格或逗号分隔。" })),
|
|
261
|
+
typeFilter: Type.Optional(Type.String({ description: "可选字段类型正则,例如 combo|check 或 decimal。" })),
|
|
262
|
+
sql: Type.Optional(Type.Boolean({ description: "是否包含数据库表和字段信息。" })),
|
|
263
|
+
op: Type.Optional(Type.Boolean({ description: "是否显示表单/单据操作。" })),
|
|
264
|
+
showDetail: Type.Optional(Type.Boolean({ description: "是否显示详细元数据输出。" })),
|
|
265
|
+
dryRun: Type.Optional(Type.Boolean({ description: "只返回命令,不实际执行。" })),
|
|
263
266
|
}),
|
|
264
267
|
|
|
265
268
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -273,15 +276,15 @@ const kdCosmicMetadataTool = defineTool({
|
|
|
273
276
|
const kdCosmicApiTool = defineTool({
|
|
274
277
|
name: "kd_cosmic_api",
|
|
275
278
|
label: "KD Cosmic API",
|
|
276
|
-
description: "
|
|
279
|
+
description: "查询随包 Cosmic API 知识,获取类和方法线索;最终签名事实应以 kd_sdk_signature 或项目构建输出为准。",
|
|
277
280
|
parameters: Type.Object({
|
|
278
|
-
product: Type.String({ description: "Cosmic
|
|
279
|
-
mode: Type.String({ description: "search
|
|
280
|
-
query: Type.String({ description: "
|
|
281
|
-
config: Type.Optional(Type.String({ description: "
|
|
282
|
-
method: Type.Optional(Type.String({ description: "
|
|
283
|
-
compact: Type.Optional(Type.Boolean({ description: "
|
|
284
|
-
dryRun: Type.Optional(Type.Boolean({ description: "
|
|
281
|
+
product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagship 或 cosmic。" }),
|
|
282
|
+
mode: Type.String({ description: "查询模式:search、search-method 或 detail。" }),
|
|
283
|
+
query: Type.String({ description: "类名、方法名或完整限定类名。" }),
|
|
284
|
+
config: Type.Optional(Type.String({ description: "可选 ok-cosmic.json 路径。" })),
|
|
285
|
+
method: Type.Optional(Type.String({ description: "detail 模式下的可选方法过滤条件。" })),
|
|
286
|
+
compact: Type.Optional(Type.Boolean({ description: "支持时请求紧凑详情输出。" })),
|
|
287
|
+
dryRun: Type.Optional(Type.Boolean({ description: "只返回命令,不实际执行。" })),
|
|
285
288
|
}),
|
|
286
289
|
|
|
287
290
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -289,7 +292,7 @@ const kdCosmicApiTool = defineTool({
|
|
|
289
292
|
const rejection = rejectNonCosmic(profile);
|
|
290
293
|
if (rejection) return { content: [{ type: "text", text: rejection }], details: { rejected: true, product: profile.product } };
|
|
291
294
|
if (!["search", "search-method", "detail"].includes(params.mode)) {
|
|
292
|
-
return { content: [{ type: "text", text: "mode
|
|
295
|
+
return { content: [{ type: "text", text: "mode 必须是 search、search-method 或 detail。" }], details: { error: "invalid-mode" } };
|
|
293
296
|
}
|
|
294
297
|
return runOrDryRun(
|
|
295
298
|
cosmicApiCommand(ctx.cwd, {
|
|
@@ -305,17 +308,17 @@ const kdCosmicApiTool = defineTool({
|
|
|
305
308
|
|
|
306
309
|
const kdSdkSignatureTool = defineTool({
|
|
307
310
|
name: "kd_sdk_signature",
|
|
308
|
-
label: "KD SDK
|
|
311
|
+
label: "KD SDK 签名",
|
|
309
312
|
description:
|
|
310
|
-
"
|
|
313
|
+
"从当前项目真实存在的 SDK jar 或 dll 中检查方法/类型签名。涉及 API 签名事实时,优先使用它而不是随包知识库。",
|
|
311
314
|
parameters: Type.Object({
|
|
312
|
-
product: Type.Optional(Type.String({ description: "
|
|
313
|
-
language: Type.Optional(Type.String({ description: "java
|
|
314
|
-
query: Type.Optional(Type.String({ description: "
|
|
315
|
-
className: Type.Optional(Type.String({ description: "
|
|
316
|
-
method: Type.Optional(Type.String({ description: "
|
|
317
|
-
path: Type.Optional(Type.String({ description: "
|
|
318
|
-
limit: Type.Optional(Type.Number({ description: "
|
|
315
|
+
product: Type.Optional(Type.String({ description: "金蝶产品。未提供 language 时用于推导 Java 或 C#。" })),
|
|
316
|
+
language: Type.Optional(Type.String({ description: "java 或 csharp。默认由产品画像推导。" })),
|
|
317
|
+
query: Type.Optional(Type.String({ description: "要搜索的类/类型关键词,例如 QueryServiceHelper 或 DynamicObject。" })),
|
|
318
|
+
className: Type.Optional(Type.String({ description: "已知时提供完整限定 Java/C# 类型名。" })),
|
|
319
|
+
method: Type.Optional(Type.String({ description: "在匹配类/类型内过滤方法或属性;不会全局扫描所有方法。" })),
|
|
320
|
+
path: Type.Optional(Type.String({ description: "可选 SDK lib/bin 目录或依赖根路径。默认从当前项目查找。" })),
|
|
321
|
+
limit: Type.Optional(Type.Number({ description: "最大检查 jar/dll/class 数量。默认 20 个结果类、200 个文件。" })),
|
|
319
322
|
}),
|
|
320
323
|
|
|
321
324
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -329,21 +332,23 @@ const kdSdkSignatureTool = defineTool({
|
|
|
329
332
|
path: params.path,
|
|
330
333
|
limit: params.limit,
|
|
331
334
|
});
|
|
335
|
+
const text = formatSdkSignatureResult(result);
|
|
336
|
+
const evidencePath = result.exitCode === 0 ? writeSdkSignatureEvidence(ctx.cwd, text) : undefined;
|
|
332
337
|
return {
|
|
333
|
-
content: [{ type: "text", text:
|
|
334
|
-
details: { product: profile.product, ...result },
|
|
338
|
+
content: [{ type: "text", text: evidencePath ? `${text}\n\n已写入 SDK 签名证据:${evidencePath}` : text }],
|
|
339
|
+
details: { product: profile.product, evidencePath, ...result },
|
|
335
340
|
};
|
|
336
341
|
},
|
|
337
342
|
});
|
|
338
343
|
|
|
339
344
|
const kdKsqlLintTool = defineTool({
|
|
340
345
|
name: "kd_ksql_lint",
|
|
341
|
-
label: "KD KSQL
|
|
342
|
-
description: "
|
|
346
|
+
label: "KD KSQL 检查",
|
|
347
|
+
description: "对生成的 KSQL/SQL 文件运行官方 ok-ksql lint 检查。",
|
|
343
348
|
parameters: Type.Object({
|
|
344
|
-
product: Type.String({ description: "Cosmic
|
|
345
|
-
path: Type.String({ description: "SQL/KSQL
|
|
346
|
-
dryRun: Type.Optional(Type.Boolean({ description: "
|
|
349
|
+
product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagship 或 cosmic。" }),
|
|
350
|
+
path: Type.String({ description: "SQL/KSQL 文件路径,可为工作区相对路径或绝对路径。" }),
|
|
351
|
+
dryRun: Type.Optional(Type.Boolean({ description: "只返回命令,不实际执行。" })),
|
|
347
352
|
}),
|
|
348
353
|
|
|
349
354
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -356,12 +361,12 @@ const kdKsqlLintTool = defineTool({
|
|
|
356
361
|
|
|
357
362
|
const kdBuildTool = defineTool({
|
|
358
363
|
name: "kd_build",
|
|
359
|
-
label: "KD
|
|
360
|
-
description: "
|
|
364
|
+
label: "KD 构建",
|
|
365
|
+
description: "按产品画像运行或预览金蝶构建命令,支持 Cosmic Java 和企业版 C# 项目。",
|
|
361
366
|
parameters: Type.Object({
|
|
362
|
-
product: Type.String({ description: "
|
|
363
|
-
target: Type.Optional(Type.String({ description: "
|
|
364
|
-
dryRun: Type.Optional(Type.Boolean({ description: "
|
|
367
|
+
product: Type.String({ description: "金蝶产品:cangqiong、xinghan、flagship、cosmic 或 enterprise。" }),
|
|
368
|
+
target: Type.Optional(Type.String({ description: "Java 可提供 Gradle/Maven task;C# 可提供 .sln/.csproj 路径。" })),
|
|
369
|
+
dryRun: Type.Optional(Type.Boolean({ description: "只返回构建命令,不实际执行。" })),
|
|
365
370
|
}),
|
|
366
371
|
|
|
367
372
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -380,12 +385,12 @@ const kdBuildTool = defineTool({
|
|
|
380
385
|
|
|
381
386
|
const kdDebugTool = defineTool({
|
|
382
387
|
name: "kd_debug",
|
|
383
|
-
label: "KD
|
|
384
|
-
description: "
|
|
388
|
+
label: "KD 调试",
|
|
389
|
+
description: "分析金蝶构建/运行日志或堆栈,给出可能原因和下一步检查建议。",
|
|
385
390
|
parameters: Type.Object({
|
|
386
|
-
text: Type.Optional(Type.String({ description: "
|
|
387
|
-
path: Type.Optional(Type.String({ description: "
|
|
388
|
-
product: Type.Optional(Type.String({ description: "
|
|
391
|
+
text: Type.Optional(Type.String({ description: "日志文本或堆栈。与 path 二选一。" })),
|
|
392
|
+
path: Type.Optional(Type.String({ description: "日志文件路径。与 text 二选一。" })),
|
|
393
|
+
product: Type.Optional(Type.String({ description: "可选产品提示,用于补充上下文。" })),
|
|
389
394
|
}),
|
|
390
395
|
|
|
391
396
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -397,7 +402,7 @@ const kdDebugTool = defineTool({
|
|
|
397
402
|
content: [
|
|
398
403
|
{
|
|
399
404
|
type: "text",
|
|
400
|
-
text:
|
|
405
|
+
text: `来源:${input.source}\n产品:${profile.product}/${profile.platform}/${profile.techStack}\n\n${formatDebugFindings(findings)}`,
|
|
401
406
|
},
|
|
402
407
|
],
|
|
403
408
|
details: { source: input.source, product: profile.product, findings },
|
|
@@ -423,3 +428,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
423
428
|
pi.registerTool(kdBuildTool);
|
|
424
429
|
pi.registerTool(kdDebugTool);
|
|
425
430
|
}
|
|
431
|
+
|
|
432
|
+
function writeSdkSignatureEvidence(cwd: string, content: string): string | undefined {
|
|
433
|
+
const run = readActiveRun(cwd);
|
|
434
|
+
if (!run) return undefined;
|
|
435
|
+
|
|
436
|
+
const path = runArtifactPath(cwd, run, SDK_SIGNATURE_EVIDENCE);
|
|
437
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
438
|
+
writeFileSync(
|
|
439
|
+
path,
|
|
440
|
+
[
|
|
441
|
+
"# SDK 签名证据",
|
|
442
|
+
"",
|
|
443
|
+
`- 生成时间:${new Date().toISOString()}`,
|
|
444
|
+
"- 来源:kd_sdk_signature 当前项目本地 SDK jar/dll",
|
|
445
|
+
"",
|
|
446
|
+
"```text",
|
|
447
|
+
content.trim(),
|
|
448
|
+
"```",
|
|
449
|
+
"",
|
|
450
|
+
].join("\n"),
|
|
451
|
+
"utf8",
|
|
452
|
+
);
|
|
453
|
+
return path;
|
|
454
|
+
}
|
package/package.json
CHANGED
package/prompts/kd-discuss.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 开始或继续金蝶 Harness 工作流的需求讨论阶段。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
使用 `kd-discuss` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
围绕本次请求开始或更新当前金蝶 Harness run:
|
|
8
8
|
|
|
9
9
|
{{args}}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
请把业务目标、金蝶产品/版本、技术栈、插件类型、目标单据/表单/实体、非目标范围和待确认问题记录到 `CONTEXT.md`。
|
package/prompts/kd-execute.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 在 Harness 门禁约束下执行当前金蝶实施计划。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
使用 `kd-execute` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
编辑代码前,先使用 `kd_plan_status` 检查当前 run。如果缺少 `PLAN.md`、`evidence/sdk-signature.md` 或门禁被阻塞,必须停止并说明缺少的文档或证据。通过后只实现 `PLAN.md` 批准的内容,并更新 `EXECUTION.md`。禁止凭记忆、模型知识或随包知识库猜 SDK 方法签名。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
用户补充说明:
|
|
10
10
|
|
|
11
11
|
{{args}}
|
|
12
|
-
|
package/prompts/kd-plan.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 为当前金蝶 Harness run 编写实施计划。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
使用 `kd-plan` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
读取 `CONTEXT.md` 和 `SPEC.md`,编写或更新 `PLAN.md`。必须包含已检查的项目结构、需要查看的文件、预计修改的真实路径、必须查证的金蝶 API/元数据、SDK 签名证据、验证命令和回滚说明。Java/C# SDK 方法签名必须来自 `kd_sdk_signature` 当前项目 jar/dll、项目构建输出或官方元数据,不能凭记忆猜。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
用户补充说明:
|
|
10
10
|
|
|
11
11
|
{{args}}
|
|
12
|
-
|
package/prompts/kd-ship.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 验证后整理金蝶交付摘要。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
使用 `kd-ship` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
读取当前 run 的阶段文档,生成 `SHIP.md`,说明行为变化、验证证据、残余风险和后续事项。缺少 `VERIFY.md` 时不得进入交付总结。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
用户补充说明:
|
|
10
10
|
|
|
11
11
|
{{args}}
|
|
12
|
-
|
package/prompts/kd-spec.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 为当前金蝶 Harness run 编写需求规格文档。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
使用 `kd-spec` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
读取当前金蝶 run 的上下文,编写或更新 `SPEC.md`。必须包含验收标准、生命周期/扩展点、数据对象、异常行为、性能约束、假设和风险。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
用户补充说明:
|
|
10
10
|
|
|
11
11
|
{{args}}
|
|
12
|
-
|
package/prompts/kd-verify.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 验证当前金蝶实现并收集证据。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
使用 `kd-verify` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
执行计划中的验证命令,收集证据,运行可用检查,并更新 `VERIFY.md`。如果某项验证无法运行,记录具体阻塞原因和残余风险。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
用户补充说明:
|
|
10
10
|
|
|
11
11
|
{{args}}
|
|
12
|
-
|
|
@@ -59,33 +59,33 @@ export function generateProjectContext(cwd: string): string {
|
|
|
59
59
|
const sourceSamples = scan.files.filter((file) => SOURCE_EXTENSIONS.has(extname(file).toLowerCase())).slice(0, MAX_SOURCE_SAMPLES);
|
|
60
60
|
|
|
61
61
|
return [
|
|
62
|
-
"# KCode
|
|
62
|
+
"# KCode 项目上下文",
|
|
63
63
|
"",
|
|
64
|
-
`-
|
|
65
|
-
`-
|
|
66
|
-
`-
|
|
64
|
+
`- 项目根目录:${cwd}`,
|
|
65
|
+
`- 项目名称:${basename(cwd)}`,
|
|
66
|
+
`- 生成时间:${new Date().toISOString()}`,
|
|
67
67
|
"",
|
|
68
|
-
"##
|
|
68
|
+
"## 持久规则",
|
|
69
69
|
"",
|
|
70
|
-
"-
|
|
71
|
-
"-
|
|
72
|
-
"-
|
|
73
|
-
"-
|
|
74
|
-
"-
|
|
75
|
-
"-
|
|
70
|
+
"- 本文件是 KCode 的项目记忆,计划或编辑代码前必须读取。",
|
|
71
|
+
"- 业务需求不得生成 demo/sample/scaffold 代码。",
|
|
72
|
+
"- 不要假设模块结构。必须基于下方真实路径,并在编辑前确认目标文件。",
|
|
73
|
+
"- 调用文件工具时优先使用项目相对路径。在 Windows 中,不要把路径改写为 /mnt/<drive>/... 或 /<drive>/...;只有确需绝对路径时才使用 Windows 路径。",
|
|
74
|
+
"- 如果本文件过期,计划前先运行 `kcode context --refresh` 重新生成。",
|
|
75
|
+
"- 只有 Harness 进入 `execute` 且 PLAN.md 写明真实目标路径后,才能写产品代码。",
|
|
76
76
|
"",
|
|
77
|
-
"##
|
|
77
|
+
"## 项目结构摘要",
|
|
78
78
|
"",
|
|
79
|
-
`-
|
|
80
|
-
`-
|
|
81
|
-
`-
|
|
82
|
-
`-
|
|
79
|
+
`- 是否存在 code 目录:${codeDir ? "是" : "否"}`,
|
|
80
|
+
`- 可能的源码根:${formatList(likelyRoots)}`,
|
|
81
|
+
`- 构建文件:${formatList(buildFiles)}`,
|
|
82
|
+
`- 识别到的模块:${formatList(modules)}`,
|
|
83
83
|
"",
|
|
84
|
-
"##
|
|
84
|
+
"## 源码样例",
|
|
85
85
|
"",
|
|
86
86
|
formatBlockList(sourceSamples),
|
|
87
87
|
"",
|
|
88
|
-
"##
|
|
88
|
+
"## 顶层目录",
|
|
89
89
|
"",
|
|
90
90
|
formatBlockList(scan.directories.filter((dir) => !dir.includes("/") && !dir.includes("\\")).sort()),
|
|
91
91
|
"",
|
|
@@ -202,11 +202,11 @@ function isSolutionOrProject(file: string): boolean {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
function formatList(values: string[]): string {
|
|
205
|
-
return values.length > 0 ? values.join(", ") : "
|
|
205
|
+
return values.length > 0 ? values.join(", ") : "未识别";
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
function formatBlockList(values: string[]): string {
|
|
209
|
-
if (values.length === 0) return "-
|
|
209
|
+
if (values.length === 0) return "- 未识别";
|
|
210
210
|
return values.map((value) => `- ${value}`).join("\n");
|
|
211
211
|
}
|
|
212
212
|
|