kcode-pi 0.1.0
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 +358 -0
- package/dist/cli/kcode.d.ts +15 -0
- package/dist/cli/kcode.js +153 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +7 -0
- package/docs/KCODE_DISTRIBUTION.md +91 -0
- package/extensions/kingdee-harness.ts +180 -0
- package/extensions/kingdee-header.ts +122 -0
- package/extensions/kingdee-tools.ts +379 -0
- package/knowledge/.backup/v1.0.0/version.json +10 -0
- package/knowledge/cangqiong/product-notes.md +15 -0
- package/knowledge/common/business-flows.md +115 -0
- package/knowledge/common/config-guides.md +110 -0
- package/knowledge/common/error-patterns.md +170 -0
- package/knowledge/common/implementation.md +144 -0
- package/knowledge/cosmic/hard-constraints.md +38 -0
- package/knowledge/cosmic/ksql-datafix.md +34 -0
- package/knowledge/cosmic/platform-baseline.md +32 -0
- package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
- package/knowledge/cosmic/review-checklist.md +40 -0
- package/knowledge/cosmic/unittest.md +35 -0
- package/knowledge/enterprise/api-reference.md +186 -0
- package/knowledge/enterprise/code-patterns.md +217 -0
- package/knowledge/enterprise/plugin-lifecycle.md +188 -0
- package/knowledge/enterprise/tables.json +159 -0
- package/knowledge/flagship/api-reference.md +237 -0
- package/knowledge/flagship/code-patterns.md +246 -0
- package/knowledge/flagship/cosmic-platform-note.md +15 -0
- package/knowledge/flagship/plugin-lifecycle.md +248 -0
- package/knowledge/flagship/tables.json +159 -0
- package/knowledge/version.json +10 -0
- package/knowledge/xinghan/product-notes.md +15 -0
- package/package.json +71 -0
- package/prompts/kd-discuss.md +11 -0
- package/prompts/kd-execute.md +12 -0
- package/prompts/kd-plan.md +12 -0
- package/prompts/kd-ship.md +12 -0
- package/prompts/kd-spec.md +12 -0
- package/prompts/kd-verify.md +12 -0
- package/skills/kd-check/SKILL.md +26 -0
- package/skills/kd-cosmic-dev/SKILL.md +82 -0
- package/skills/kd-cosmic-review/SKILL.md +90 -0
- package/skills/kd-cosmic-unittest/SKILL.md +92 -0
- package/skills/kd-debug/SKILL.md +30 -0
- package/skills/kd-discuss/SKILL.md +24 -0
- package/skills/kd-execute/SKILL.md +22 -0
- package/skills/kd-gen/SKILL.md +34 -0
- package/skills/kd-ksql/SKILL.md +86 -0
- package/skills/kd-plan/SKILL.md +24 -0
- package/skills/kd-ship/SKILL.md +22 -0
- package/skills/kd-spec/SKILL.md +24 -0
- package/skills/kd-verify/SKILL.md +22 -0
- package/themes/kcode-dark.json +81 -0
- package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
- package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
- package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
- package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
- 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/ok-cosmic-docs.db +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
- package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
- package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
- package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
2
|
+
import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { formatStatus } from "../src/harness/format.ts";
|
|
4
|
+
import { PHASE_ORDER, isKdPhase, type KdPhase } from "../src/harness/types.ts";
|
|
5
|
+
import {
|
|
6
|
+
advanceRun,
|
|
7
|
+
createActiveRun,
|
|
8
|
+
ensurePhaseArtifact,
|
|
9
|
+
readActiveRun,
|
|
10
|
+
refreshGate,
|
|
11
|
+
updateProductProfile,
|
|
12
|
+
updatePhaseArtifact,
|
|
13
|
+
} from "../src/harness/state.ts";
|
|
14
|
+
|
|
15
|
+
function requireRun(cwd: string): ReturnType<typeof readActiveRun> {
|
|
16
|
+
return readActiveRun(cwd);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseArtifactArgs(args: string, currentPhase: KdPhase): { phase: KdPhase; content?: string } | undefined {
|
|
20
|
+
const trimmed = args.trim();
|
|
21
|
+
if (!trimmed) return { phase: currentPhase };
|
|
22
|
+
|
|
23
|
+
const [first, ...rest] = trimmed.split(/\s+/);
|
|
24
|
+
if (isKdPhase(first)) {
|
|
25
|
+
const contentStart = trimmed.indexOf(first) + first.length;
|
|
26
|
+
const content = trimmed.slice(contentStart).trim();
|
|
27
|
+
return { phase: first, content: content || undefined };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { phase: currentPhase, content: trimmed };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseStartArgs(args: string): { goal: string; product?: string; version?: string } {
|
|
34
|
+
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
35
|
+
const goal: string[] = [];
|
|
36
|
+
let product: string | undefined;
|
|
37
|
+
let version: string | undefined;
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
40
|
+
const token = tokens[i];
|
|
41
|
+
if ((token === "--product" || token === "-p") && tokens[i + 1]) {
|
|
42
|
+
product = tokens[++i];
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if ((token === "--version" || token === "-v") && tokens[i + 1]) {
|
|
46
|
+
version = tokens[++i];
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
goal.push(token);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { goal: goal.join(" "), product, version };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseProductArgs(args: string): { product: string; version?: string } | undefined {
|
|
56
|
+
const parsed = parseStartArgs(args);
|
|
57
|
+
const product = parsed.product ?? parsed.goal.split(/\s+/)[0];
|
|
58
|
+
if (!product) return undefined;
|
|
59
|
+
return { product, version: parsed.version };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const kdPlanStatusTool = defineTool({
|
|
63
|
+
name: "kd_plan_status",
|
|
64
|
+
label: "KD Status",
|
|
65
|
+
description: "Inspect the active Kingdee Harness Engineering run, current phase, required artifacts, and gate status.",
|
|
66
|
+
parameters: Type.Object({}),
|
|
67
|
+
|
|
68
|
+
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
69
|
+
const run = readActiveRun(ctx.cwd);
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: "text", text: formatStatus(ctx.cwd, run) }],
|
|
72
|
+
details: { run },
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export default function (pi: ExtensionAPI) {
|
|
78
|
+
pi.registerTool(kdPlanStatusTool);
|
|
79
|
+
|
|
80
|
+
pi.registerCommand("kd-status", {
|
|
81
|
+
description: "Show the active Kingdee harness run and gate status",
|
|
82
|
+
handler: async (_args, ctx) => {
|
|
83
|
+
ctx.ui.notify(formatStatus(ctx.cwd, readActiveRun(ctx.cwd)), "info");
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
pi.registerCommand("kd-gate", {
|
|
88
|
+
description: "Refresh and show the active Kingdee harness gate",
|
|
89
|
+
handler: async (_args, ctx) => {
|
|
90
|
+
const run = requireRun(ctx.cwd);
|
|
91
|
+
if (!run) {
|
|
92
|
+
ctx.ui.notify("No active Kingdee harness run. Use /kd-start <goal>.", "error");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const refreshed = refreshGate(ctx.cwd, run);
|
|
96
|
+
ctx.ui.notify(refreshed.gate.passed ? "Gate passed" : `Gate blocked: ${refreshed.gate.reason}`, "info");
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
pi.registerCommand("kd-start", {
|
|
101
|
+
description: "Start a Kingdee harness run: /kd-start [--product product] [--version version] <goal>",
|
|
102
|
+
handler: async (args, ctx) => {
|
|
103
|
+
const parsed = parseStartArgs(args);
|
|
104
|
+
const goal = parsed.goal;
|
|
105
|
+
if (!goal) {
|
|
106
|
+
ctx.ui.notify("Usage: /kd-start [--product product] [--version version] <goal>", "error");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const run = createActiveRun(ctx.cwd, goal, parsed.product, parsed.version);
|
|
111
|
+
ctx.ui.notify(`Started Kingdee harness run: ${run.id} (${run.profile?.product}/${run.profile?.techStack})`, "info");
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
pi.registerCommand("kd-product", {
|
|
116
|
+
description: "Set the active Kingdee product profile: /kd-product <flagship|cosmic|xinghan|cangqiong|enterprise> [--version version]",
|
|
117
|
+
handler: async (args, ctx) => {
|
|
118
|
+
const run = requireRun(ctx.cwd);
|
|
119
|
+
if (!run) {
|
|
120
|
+
ctx.ui.notify("No active Kingdee harness run. Use /kd-start <goal>.", "error");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const parsed = parseProductArgs(args);
|
|
125
|
+
if (!parsed) {
|
|
126
|
+
ctx.ui.notify("Usage: /kd-product <flagship|cosmic|xinghan|cangqiong|enterprise> [--version version]", "error");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const updated = updateProductProfile(ctx.cwd, run, parsed.product, parsed.version);
|
|
131
|
+
ctx.ui.notify(`Product profile: ${updated.profile?.product}/${updated.profile?.techStack}/${updated.profile?.language}`, "info");
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
pi.registerCommand("kd-advance", {
|
|
136
|
+
description: `Advance Kingdee run to the next phase or a named phase: ${PHASE_ORDER.join("|")}`,
|
|
137
|
+
handler: async (args, ctx) => {
|
|
138
|
+
const run = requireRun(ctx.cwd);
|
|
139
|
+
if (!run) {
|
|
140
|
+
ctx.ui.notify("No active Kingdee harness run. Use /kd-start <goal>.", "error");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const requestedText = args.trim();
|
|
145
|
+
let requested: KdPhase | undefined;
|
|
146
|
+
if (requestedText) {
|
|
147
|
+
if (!isKdPhase(requestedText)) {
|
|
148
|
+
ctx.ui.notify(`Unknown phase "${requestedText}". Valid phases: ${PHASE_ORDER.join(", ")}`, "error");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
requested = requestedText;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = advanceRun(ctx.cwd, run, requested);
|
|
155
|
+
ctx.ui.notify(result.message, result.run.gate.passed ? "info" : "warning");
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
pi.registerCommand("kd-artifact", {
|
|
160
|
+
description: "Create or update a phase artifact: /kd-artifact [phase] [content]",
|
|
161
|
+
handler: async (args, ctx) => {
|
|
162
|
+
const run = requireRun(ctx.cwd);
|
|
163
|
+
if (!run) {
|
|
164
|
+
ctx.ui.notify("No active Kingdee harness run. Use /kd-start <goal>.", "error");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const parsed = parseArtifactArgs(args, run.phase);
|
|
169
|
+
if (!parsed) {
|
|
170
|
+
ctx.ui.notify("Usage: /kd-artifact [phase] [content]", "error");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const path = parsed.content
|
|
175
|
+
? updatePhaseArtifact(ctx.cwd, run, parsed.phase, parsed.content)
|
|
176
|
+
: ensurePhaseArtifact(ctx.cwd, run, parsed.phase);
|
|
177
|
+
ctx.ui.notify(`Artifact ready: ${path}`, "info");
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
|
|
5
|
+
type KdPhase = "discuss" | "spec" | "plan" | "execute" | "verify" | "ship";
|
|
6
|
+
|
|
7
|
+
interface ActiveRun {
|
|
8
|
+
id?: string;
|
|
9
|
+
phase?: KdPhase;
|
|
10
|
+
product?: string;
|
|
11
|
+
profile?: {
|
|
12
|
+
product?: string;
|
|
13
|
+
techStack?: string;
|
|
14
|
+
language?: string;
|
|
15
|
+
};
|
|
16
|
+
risk?: "low" | "medium" | "high";
|
|
17
|
+
gate?: {
|
|
18
|
+
passed?: boolean;
|
|
19
|
+
reason?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readActiveRun(cwd: string): ActiveRun | undefined {
|
|
24
|
+
const activeRunPath = join(cwd, ".pi", "kd", "active-run.json");
|
|
25
|
+
if (!existsSync(activeRunPath)) return undefined;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(readFileSync(activeRunPath, "utf8")) as ActiveRun;
|
|
29
|
+
} catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formatProduct(run: ActiveRun | undefined): string {
|
|
35
|
+
if (!run) return "unselected";
|
|
36
|
+
const product = run.profile?.product ?? run.product ?? "unknown";
|
|
37
|
+
const techStack = run.profile?.techStack ?? "unknown";
|
|
38
|
+
const language = run.profile?.language ?? "unknown";
|
|
39
|
+
return `${product}/${techStack}/${language}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatPhase(phase: ActiveRun["phase"]): string {
|
|
43
|
+
return phase ?? "idle";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function formatGate(run: ActiveRun | undefined): string {
|
|
47
|
+
if (!run?.gate) return "gate: pending";
|
|
48
|
+
if (run.gate.passed) return "gate: pass";
|
|
49
|
+
return `gate: blocked${run.gate.reason ? ` - ${run.gate.reason}` : ""}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function padOrTrim(text: string, width: number): string {
|
|
53
|
+
if (width <= 0) return "";
|
|
54
|
+
if (text.length > width) return text.slice(0, Math.max(0, width - 1)) + ">";
|
|
55
|
+
return text + " ".repeat(width - text.length);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function logoLines(theme: Theme): string[] {
|
|
59
|
+
const accent = (text: string) => theme.fg("accent", text);
|
|
60
|
+
const muted = (text: string) => theme.fg("muted", text);
|
|
61
|
+
|
|
62
|
+
return [
|
|
63
|
+
`${accent("KCode")} ${muted("Kingdee Pi Harness")}`,
|
|
64
|
+
`${accent("=====")} ${muted("discuss -> spec -> plan -> execute -> verify -> ship")}`,
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default function (pi: ExtensionAPI) {
|
|
69
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
70
|
+
if (ctx.mode !== "tui") return;
|
|
71
|
+
|
|
72
|
+
ctx.ui.setHeader((_tui, theme) => {
|
|
73
|
+
return {
|
|
74
|
+
render(width: number): string[] {
|
|
75
|
+
const run = readActiveRun(ctx.cwd);
|
|
76
|
+
const phase = formatPhase(run?.phase);
|
|
77
|
+
const product = formatProduct(run);
|
|
78
|
+
const gate = formatGate(run);
|
|
79
|
+
const risk = run?.risk ?? "unknown";
|
|
80
|
+
const runId = run?.id ?? "none";
|
|
81
|
+
|
|
82
|
+
const status = [
|
|
83
|
+
theme.fg("muted", "phase: "),
|
|
84
|
+
theme.fg("accent", phase),
|
|
85
|
+
theme.fg("muted", " | product: "),
|
|
86
|
+
theme.fg("text", product),
|
|
87
|
+
theme.fg("muted", " | risk: "),
|
|
88
|
+
theme.fg(risk === "high" ? "error" : risk === "medium" ? "warning" : "success", risk),
|
|
89
|
+
theme.fg("muted", " | "),
|
|
90
|
+
theme.fg(run?.gate?.passed === false ? "error" : "muted", gate),
|
|
91
|
+
].join("");
|
|
92
|
+
|
|
93
|
+
return [
|
|
94
|
+
"",
|
|
95
|
+
...logoLines(theme).map((line) => padOrTrim(line, width)),
|
|
96
|
+
padOrTrim(status, width),
|
|
97
|
+
padOrTrim(theme.fg("dim", `run: ${runId}`), width),
|
|
98
|
+
"",
|
|
99
|
+
];
|
|
100
|
+
},
|
|
101
|
+
invalidate() {},
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
pi.registerCommand("kcode-header", {
|
|
107
|
+
description: "Restore the KCode Kingdee header",
|
|
108
|
+
handler: async (_args, ctx) => {
|
|
109
|
+
if (ctx.mode !== "tui") return;
|
|
110
|
+
ctx.ui.notify("Restart the session or reload extensions to restore the KCode header.", "info");
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
pi.registerCommand("builtin-header", {
|
|
115
|
+
description: "Restore Pi's built-in header",
|
|
116
|
+
handler: async (_args, ctx) => {
|
|
117
|
+
if (ctx.mode !== "tui") return;
|
|
118
|
+
ctx.ui.setHeader(undefined);
|
|
119
|
+
ctx.ui.notify("Built-in header restored", "info");
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
5
|
+
import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { formatSearchResults, formatTableSchema } from "../src/knowledge/format.ts";
|
|
7
|
+
import { findTableSchema, searchKnowledge } from "../src/knowledge/search.ts";
|
|
8
|
+
import type { Edition, KnowledgeScope } from "../src/knowledge/types.ts";
|
|
9
|
+
import { resolveProductProfile, type ProductProfile } from "../src/product/profile.ts";
|
|
10
|
+
import { checkCode, formatCheckResults, type CheckLanguage } from "../src/rules/checker.ts";
|
|
11
|
+
import { analyzeDebugText, formatDebugFindings, planBuild, readDebugInput, runBuild } from "../src/tools/build-debug.ts";
|
|
12
|
+
import {
|
|
13
|
+
cosmicApiCommand,
|
|
14
|
+
cosmicConfigCommand,
|
|
15
|
+
cosmicMetadataCommand,
|
|
16
|
+
formatCommandResult,
|
|
17
|
+
type OfficialEvidenceFile,
|
|
18
|
+
isCosmicFamily,
|
|
19
|
+
ksqlLintCommand,
|
|
20
|
+
runCommand,
|
|
21
|
+
writeOfficialEvidence,
|
|
22
|
+
} from "../src/official/kingdee-skills.ts";
|
|
23
|
+
|
|
24
|
+
const extensionDir = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const knowledgePath = join(extensionDir, "..", "knowledge");
|
|
26
|
+
|
|
27
|
+
function normalizeEdition(value: string | undefined): Edition {
|
|
28
|
+
return value === "enterprise" ? "enterprise" : "flagship";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveToolProfile(product: string | undefined, edition: string | undefined): ProductProfile {
|
|
32
|
+
return resolveProductProfile(product ?? edition);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function editionForBundledKnowledge(profile: ProductProfile, edition: string | undefined): Edition | undefined {
|
|
36
|
+
if (profile.product === "enterprise") return "enterprise";
|
|
37
|
+
if (profile.product === "flagship") return "flagship";
|
|
38
|
+
if (profile.product === "unknown" && edition) return normalizeEdition(edition);
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function scopesForProfile(profile: ProductProfile, edition: string | undefined): KnowledgeScope[] | undefined {
|
|
43
|
+
if (profile.product === "unknown") return edition ? [normalizeEdition(edition)] : undefined;
|
|
44
|
+
if (profile.platform === "enterprise-csharp") return ["enterprise"];
|
|
45
|
+
if (profile.platform === "cosmic") {
|
|
46
|
+
const scopes: KnowledgeScope[] = ["cosmic"];
|
|
47
|
+
if (profile.knowledgeScope !== "cosmic" && profile.knowledgeScope !== "common") scopes.push(profile.knowledgeScope);
|
|
48
|
+
return scopes;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function normalizeLanguage(value: string | undefined): CheckLanguage {
|
|
54
|
+
return value === "csharp" ? "csharp" : "java";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function languageForProfile(profile: ProductProfile, value: string | undefined): CheckLanguage {
|
|
58
|
+
if (value) return normalizeLanguage(value);
|
|
59
|
+
if (profile.language === "csharp") return "csharp";
|
|
60
|
+
return "java";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function rejectNonCosmic(profile: ProductProfile): string | undefined {
|
|
64
|
+
if (isCosmicFamily(profile)) return undefined;
|
|
65
|
+
if (profile.product === "unknown") return "Provide a Cosmic-family product first: cangqiong, xinghan, flagship, or cosmic.";
|
|
66
|
+
return `Product ${profile.product} uses ${profile.platform}/${profile.techStack}; Cosmic official scripts are not applicable.`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function runOrDryRun(
|
|
70
|
+
commandPromise: Promise<ReturnType<typeof cosmicConfigCommand> extends Promise<infer T> ? T : never>,
|
|
71
|
+
dryRun: boolean | undefined,
|
|
72
|
+
ctx: { cwd: string },
|
|
73
|
+
evidenceFile?: OfficialEvidenceFile,
|
|
74
|
+
) {
|
|
75
|
+
const command = await commandPromise;
|
|
76
|
+
if (dryRun) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text" as const, text: `Dry run command:\n${command.display}` }],
|
|
79
|
+
details: { command: command.display, dryRun: true },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const result = await runCommand(command);
|
|
84
|
+
const evidencePath = evidenceFile ? writeOfficialEvidence(ctx.cwd, evidenceFile, result) : undefined;
|
|
85
|
+
return {
|
|
86
|
+
content: [{ type: "text" as const, text: formatCommandResult(result) }],
|
|
87
|
+
details: { command: result.command, exitCode: result.exitCode, evidencePath },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const kdSearchTool = defineTool({
|
|
92
|
+
name: "kd_search",
|
|
93
|
+
label: "KD Search",
|
|
94
|
+
description: "Search bundled Kingdee SDK knowledge, plugin lifecycle notes, code patterns, and common implementation guidance.",
|
|
95
|
+
parameters: Type.Object({
|
|
96
|
+
query: Type.String({ description: "Keyword or API/class/table/lifecycle term to search for" }),
|
|
97
|
+
product: Type.Optional(Type.String({ description: "Kingdee product: flagship, cosmic, xinghan, cangqiong, or enterprise." })),
|
|
98
|
+
edition: Type.Optional(Type.String({ description: "Legacy alias for product. Prefer product." })),
|
|
99
|
+
limit: Type.Optional(Type.Number({ description: "Maximum number of results. Defaults to 5." })),
|
|
100
|
+
}),
|
|
101
|
+
|
|
102
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
103
|
+
const profile = resolveToolProfile(params.product, params.edition);
|
|
104
|
+
const scopes = scopesForProfile(profile, params.edition);
|
|
105
|
+
if (!scopes) {
|
|
106
|
+
const guidance =
|
|
107
|
+
profile.product === "unknown"
|
|
108
|
+
? "Provide product first, for example product=flagship, enterprise, cosmic, xinghan, or cangqiong."
|
|
109
|
+
: "No knowledge scope is configured for this product profile.";
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "text",
|
|
114
|
+
text: [
|
|
115
|
+
`Product profile: ${profile.product}/${profile.techStack}/${profile.language}`,
|
|
116
|
+
"Bundled searchable knowledge requires a known product profile.",
|
|
117
|
+
guidance,
|
|
118
|
+
].join("\n"),
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
details: { query: params.query, product: profile.product, knowledgeImported: false },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const limit = Math.max(1, Math.min(params.limit ?? 5, 10));
|
|
126
|
+
const results = searchKnowledge(params.query, { scopes, topK: limit, minScore: 1 }, knowledgePath);
|
|
127
|
+
return {
|
|
128
|
+
content: [{ type: "text", text: formatSearchResults(params.query, results, knowledgePath) }],
|
|
129
|
+
details: { query: params.query, product: profile.product, scopes, count: results.length },
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const kdTableTool = defineTool({
|
|
135
|
+
name: "kd_table",
|
|
136
|
+
label: "KD Table",
|
|
137
|
+
description: "Look up a bundled Kingdee table schema by table name for the selected product profile.",
|
|
138
|
+
parameters: Type.Object({
|
|
139
|
+
table: Type.String({ description: "Table name, for example T_PUR_POORDER" }),
|
|
140
|
+
product: Type.Optional(Type.String({ description: "Kingdee product: flagship, cosmic, xinghan, cangqiong, or enterprise." })),
|
|
141
|
+
edition: Type.Optional(Type.String({ description: "Legacy alias for product. Prefer product." })),
|
|
142
|
+
}),
|
|
143
|
+
|
|
144
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
145
|
+
const profile = resolveToolProfile(params.product, params.edition);
|
|
146
|
+
const edition = editionForBundledKnowledge(profile, params.edition);
|
|
147
|
+
if (!edition) {
|
|
148
|
+
const guidance =
|
|
149
|
+
profile.product === "unknown"
|
|
150
|
+
? "Provide product first. Do not assume a table schema across Kingdee product families."
|
|
151
|
+
: "Do not reuse flagship/enterprise table assumptions for Cosmic/Xinghan/Cangqiong without metadata verification.";
|
|
152
|
+
return {
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: "text",
|
|
156
|
+
text: [
|
|
157
|
+
`Product profile: ${profile.product}/${profile.techStack}/${profile.language}`,
|
|
158
|
+
"Bundled table schemas currently cover flagship and enterprise only.",
|
|
159
|
+
guidance,
|
|
160
|
+
].join("\n"),
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
details: { table: params.table, product: profile.product, knowledgeImported: false },
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const schema = findTableSchema(params.table, edition, knowledgePath);
|
|
168
|
+
return {
|
|
169
|
+
content: [{ type: "text", text: formatTableSchema(params.table, schema) }],
|
|
170
|
+
details: { table: params.table, product: profile.product, edition, found: Boolean(schema) },
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const kdCheckTool = defineTool({
|
|
176
|
+
name: "kd_check",
|
|
177
|
+
label: "KD Check",
|
|
178
|
+
description:
|
|
179
|
+
"Check Kingdee Java/C# plugin code for magic values, naming issues, DB calls in loops, and empty catch blocks.",
|
|
180
|
+
parameters: Type.Object({
|
|
181
|
+
code: Type.Optional(Type.String({ description: "Source code to check. Use this or path." })),
|
|
182
|
+
path: Type.Optional(Type.String({ description: "Path to a source file to check. Use this or code." })),
|
|
183
|
+
product: Type.Optional(Type.String({ description: "Kingdee product. Used to derive Java or C# when language is omitted." })),
|
|
184
|
+
language: Type.Optional(Type.String({ description: "Language: java or csharp. Overrides product-derived language." })),
|
|
185
|
+
}),
|
|
186
|
+
|
|
187
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
188
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
189
|
+
const language = languageForProfile(profile, params.language);
|
|
190
|
+
let code = params.code;
|
|
191
|
+
let source = "inline";
|
|
192
|
+
|
|
193
|
+
if (!code && params.path) {
|
|
194
|
+
const filePath = join(ctx.cwd, params.path);
|
|
195
|
+
code = readFileSync(filePath, "utf8");
|
|
196
|
+
source = params.path;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!code) {
|
|
200
|
+
return {
|
|
201
|
+
content: [{ type: "text", text: "Provide either code or path for kd_check." }],
|
|
202
|
+
details: { error: "missing-code-or-path" },
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const results = checkCode(code, language);
|
|
207
|
+
return {
|
|
208
|
+
content: [
|
|
209
|
+
{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: `Source: ${source}\nProduct: ${profile.product}/${profile.techStack}\nLanguage: ${language}\n\n${formatCheckResults(results)}`,
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
details: { source, product: profile.product, language, issues: results },
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const kdCosmicConfigTool = defineTool({
|
|
220
|
+
name: "kd_cosmic_config",
|
|
221
|
+
label: "KD Cosmic Config",
|
|
222
|
+
description: "Run the official ok-cosmic configuration precheck for Cosmic-family Kingdee products.",
|
|
223
|
+
parameters: Type.Object({
|
|
224
|
+
product: Type.String({ description: "Cosmic-family product: cangqiong, xinghan, flagship, or cosmic." }),
|
|
225
|
+
config: Type.Optional(Type.String({ description: "Optional ok-cosmic.json path. Defaults to current working directory behavior." })),
|
|
226
|
+
dryRun: Type.Optional(Type.Boolean({ description: "Return the command without executing it." })),
|
|
227
|
+
}),
|
|
228
|
+
|
|
229
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
230
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
231
|
+
const rejection = rejectNonCosmic(profile);
|
|
232
|
+
if (rejection) return { content: [{ type: "text", text: rejection }], details: { rejected: true, product: profile.product } };
|
|
233
|
+
return runOrDryRun(cosmicConfigCommand(ctx.cwd, params.config), params.dryRun, ctx, "cosmic-config.txt");
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const kdCosmicMetadataTool = defineTool({
|
|
238
|
+
name: "kd_cosmic_metadata",
|
|
239
|
+
label: "KD Cosmic Metadata",
|
|
240
|
+
description: "Query official Cosmic form/bill metadata for fields, enum values, operations, and SQL table details.",
|
|
241
|
+
parameters: Type.Object({
|
|
242
|
+
product: Type.String({ description: "Cosmic-family product: cangqiong, xinghan, flagship, or cosmic." }),
|
|
243
|
+
form: Type.String({ description: "Form ID, bill ID, or Chinese bill name. Multiple targets can be comma-separated." }),
|
|
244
|
+
config: Type.Optional(Type.String({ description: "Optional ok-cosmic.json path." })),
|
|
245
|
+
fuzzy: Type.Optional(Type.String({ description: "Optional field keywords separated by spaces or commas." })),
|
|
246
|
+
typeFilter: Type.Optional(Type.String({ description: "Optional field type regex, for example combo|check or decimal." })),
|
|
247
|
+
sql: Type.Optional(Type.Boolean({ description: "Include database table and field information." })),
|
|
248
|
+
op: Type.Optional(Type.Boolean({ description: "Show operations for the form/bill." })),
|
|
249
|
+
showDetail: Type.Optional(Type.Boolean({ description: "Show detailed metadata output." })),
|
|
250
|
+
dryRun: Type.Optional(Type.Boolean({ description: "Return the command without executing it." })),
|
|
251
|
+
}),
|
|
252
|
+
|
|
253
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
254
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
255
|
+
const rejection = rejectNonCosmic(profile);
|
|
256
|
+
if (rejection) return { content: [{ type: "text", text: rejection }], details: { rejected: true, product: profile.product } };
|
|
257
|
+
return runOrDryRun(cosmicMetadataCommand(ctx.cwd, params), params.dryRun, ctx, "cosmic-metadata.json");
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const kdCosmicApiTool = defineTool({
|
|
262
|
+
name: "kd_cosmic_api",
|
|
263
|
+
label: "KD Cosmic API",
|
|
264
|
+
description: "Query official Cosmic API knowledge for class names, method names, and method signatures.",
|
|
265
|
+
parameters: Type.Object({
|
|
266
|
+
product: Type.String({ description: "Cosmic-family product: cangqiong, xinghan, flagship, or cosmic." }),
|
|
267
|
+
mode: Type.String({ description: "search, search-method, or detail." }),
|
|
268
|
+
query: Type.String({ description: "Class name, method name, or fully qualified class name." }),
|
|
269
|
+
config: Type.Optional(Type.String({ description: "Optional ok-cosmic.json path." })),
|
|
270
|
+
method: Type.Optional(Type.String({ description: "Optional method filter for detail mode." })),
|
|
271
|
+
compact: Type.Optional(Type.Boolean({ description: "Request compact detail output when supported." })),
|
|
272
|
+
dryRun: Type.Optional(Type.Boolean({ description: "Return the command without executing it." })),
|
|
273
|
+
}),
|
|
274
|
+
|
|
275
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
276
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
277
|
+
const rejection = rejectNonCosmic(profile);
|
|
278
|
+
if (rejection) return { content: [{ type: "text", text: rejection }], details: { rejected: true, product: profile.product } };
|
|
279
|
+
if (!["search", "search-method", "detail"].includes(params.mode)) {
|
|
280
|
+
return { content: [{ type: "text", text: "mode must be one of: search, search-method, detail" }], details: { error: "invalid-mode" } };
|
|
281
|
+
}
|
|
282
|
+
return runOrDryRun(
|
|
283
|
+
cosmicApiCommand(ctx.cwd, {
|
|
284
|
+
...params,
|
|
285
|
+
mode: params.mode as "search" | "search-method" | "detail",
|
|
286
|
+
}),
|
|
287
|
+
params.dryRun,
|
|
288
|
+
ctx,
|
|
289
|
+
"cosmic-api.txt",
|
|
290
|
+
);
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const kdKsqlLintTool = defineTool({
|
|
295
|
+
name: "kd_ksql_lint",
|
|
296
|
+
label: "KD KSQL Lint",
|
|
297
|
+
description: "Run the official ok-ksql lint script against a generated KSQL/SQL file.",
|
|
298
|
+
parameters: Type.Object({
|
|
299
|
+
product: Type.String({ description: "Cosmic-family product: cangqiong, xinghan, flagship, or cosmic." }),
|
|
300
|
+
path: Type.String({ description: "SQL/KSQL file path, relative to workspace or absolute." }),
|
|
301
|
+
dryRun: Type.Optional(Type.Boolean({ description: "Return the command without executing it." })),
|
|
302
|
+
}),
|
|
303
|
+
|
|
304
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
305
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
306
|
+
const rejection = rejectNonCosmic(profile);
|
|
307
|
+
if (rejection) return { content: [{ type: "text", text: rejection }], details: { rejected: true, product: profile.product } };
|
|
308
|
+
return runOrDryRun(ksqlLintCommand(ctx.cwd, params.path), params.dryRun, ctx, "ksql-lint.txt");
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const kdBuildTool = defineTool({
|
|
313
|
+
name: "kd_build",
|
|
314
|
+
label: "KD Build",
|
|
315
|
+
description: "Run or dry-run a product-aware Kingdee build command for Cosmic Java or enterprise C# projects.",
|
|
316
|
+
parameters: Type.Object({
|
|
317
|
+
product: Type.String({ description: "Kingdee product: cangqiong, xinghan, flagship, cosmic, or enterprise." }),
|
|
318
|
+
target: Type.Optional(Type.String({ description: "Optional Gradle/Maven task for Java or .sln/.csproj path for C#." })),
|
|
319
|
+
dryRun: Type.Optional(Type.Boolean({ description: "Return the build command without executing it." })),
|
|
320
|
+
}),
|
|
321
|
+
|
|
322
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
323
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
324
|
+
try {
|
|
325
|
+
const plan = planBuild(ctx.cwd, profile, params.target);
|
|
326
|
+
return runBuild(plan, params.dryRun);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
return {
|
|
329
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
330
|
+
details: { error: "build-plan-failed", product: profile.product },
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const kdDebugTool = defineTool({
|
|
337
|
+
name: "kd_debug",
|
|
338
|
+
label: "KD Debug",
|
|
339
|
+
description: "Analyze Kingdee build/runtime logs or stack traces and map them to likely causes and next checks.",
|
|
340
|
+
parameters: Type.Object({
|
|
341
|
+
text: Type.Optional(Type.String({ description: "Log text or stack trace. Use this or path." })),
|
|
342
|
+
path: Type.Optional(Type.String({ description: "Path to a log file. Use this or text." })),
|
|
343
|
+
product: Type.Optional(Type.String({ description: "Optional product hint for context." })),
|
|
344
|
+
}),
|
|
345
|
+
|
|
346
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
347
|
+
const profile = resolveToolProfile(params.product, undefined);
|
|
348
|
+
try {
|
|
349
|
+
const input = readDebugInput(ctx.cwd, params.text, params.path);
|
|
350
|
+
const findings = analyzeDebugText(input.text);
|
|
351
|
+
return {
|
|
352
|
+
content: [
|
|
353
|
+
{
|
|
354
|
+
type: "text",
|
|
355
|
+
text: `Source: ${input.source}\nProduct: ${profile.product}/${profile.platform}/${profile.techStack}\n\n${formatDebugFindings(findings)}`,
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
details: { source: input.source, product: profile.product, findings },
|
|
359
|
+
};
|
|
360
|
+
} catch (error) {
|
|
361
|
+
return {
|
|
362
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
363
|
+
details: { error: "debug-input-failed", product: profile.product },
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
export default function (pi: ExtensionAPI) {
|
|
370
|
+
pi.registerTool(kdSearchTool);
|
|
371
|
+
pi.registerTool(kdTableTool);
|
|
372
|
+
pi.registerTool(kdCheckTool);
|
|
373
|
+
pi.registerTool(kdCosmicConfigTool);
|
|
374
|
+
pi.registerTool(kdCosmicMetadataTool);
|
|
375
|
+
pi.registerTool(kdCosmicApiTool);
|
|
376
|
+
pi.registerTool(kdKsqlLintTool);
|
|
377
|
+
pi.registerTool(kdBuildTool);
|
|
378
|
+
pi.registerTool(kdDebugTool);
|
|
379
|
+
}
|