@hupan56/wlkj 3.1.32 → 3.3.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/bin/cli.js +117 -0
- package/package.json +1 -1
- package/templates/qoder/agents/insight-planning.md +67 -67
- package/templates/qoder/agents/prd-reference.md +47 -47
- package/templates/qoder/commands/optional/wl-insight.md +4 -4
- package/templates/qoder/commands/optional/wl-report.md +1 -1
- package/templates/qoder/commands/optional/wl-spec.md +23 -3
- package/templates/qoder/commands/optional/wl-status.md +12 -1
- package/templates/qoder/commands/wl-code.md +138 -7
- package/templates/qoder/commands/wl-commit.md +12 -1
- package/templates/qoder/commands/wl-design.md +70 -6
- package/templates/qoder/commands/wl-init.md +27 -0
- package/templates/qoder/commands/wl-prd.md +230 -15
- package/templates/qoder/commands/wl-req.md +10 -3
- package/templates/qoder/commands/wl-search.md +74 -20
- package/templates/qoder/commands/wl-task.md +3 -3
- package/templates/qoder/commands/wl-test.md +17 -2
- package/templates/qoder/contracts/CHANGELOG.md +418 -0
- package/templates/qoder/contracts/README.md +180 -0
- package/templates/qoder/contracts/code.md +82 -0
- package/templates/qoder/contracts/commit.md +86 -0
- package/templates/qoder/contracts/contract-header.md +76 -0
- package/templates/qoder/contracts/design.md +106 -0
- package/templates/qoder/contracts/fallback.md +126 -0
- package/templates/qoder/contracts/isolation.md +119 -0
- package/templates/qoder/contracts/prd.md +118 -0
- package/templates/qoder/contracts/schemas/design-spec.schema.json +46 -0
- package/templates/qoder/contracts/schemas/prd.schema.json +36 -0
- package/templates/qoder/contracts/schemas/test-cases.schema.json +40 -0
- package/templates/qoder/contracts/spec.md +116 -0
- package/templates/qoder/contracts/task.md +125 -0
- package/templates/qoder/contracts/test.md +112 -0
- package/templates/qoder/hooks/post-tool-use.py +61 -0
- package/templates/qoder/hooks/session-start.py +34 -66
- package/templates/qoder/hooks/stop-eval.py +47 -0
- package/templates/qoder/rules/wl-pipeline.md +37 -0
- package/templates/qoder/scripts/capability/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/__pycache__/registry.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/__pycache__/registry_mcp.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/adapters/__init__.py +1 -1
- package/templates/qoder/scripts/capability/adapters/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/adapters/__pycache__/cli.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/adapters/__pycache__/mcp.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/adapters/__pycache__/qw.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/adapters/mcp.py +76 -100
- package/templates/qoder/scripts/capability/adapters/qw.py +295 -295
- package/templates/qoder/scripts/capability/caps/__init__.py +1 -1
- package/templates/qoder/scripts/capability/caps/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/context.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/cron.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/identity.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/memory.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/notify.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/present.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/repo.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/__pycache__/sandbox.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/capability/caps/memory.py +1 -1
- package/templates/qoder/scripts/capability/registry.py +21 -23
- package/templates/qoder/scripts/capability/registry_mcp.py +69 -5
- package/templates/qoder/scripts/capability/smoke_test_report.json +34 -20
- package/templates/qoder/scripts/deployment/setup/carriers.py +3 -1
- package/templates/qoder/scripts/deployment/setup/init_doctor.py +10 -3
- package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +11 -0
- package/templates/qoder/scripts/deployment/setup/wlkj_shim.py +104 -0
- package/templates/qoder/scripts/domain/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/domain/deployment/deploy_to_test.py +298 -0
- package/templates/qoder/scripts/domain/integration/__init__.py +0 -0
- package/templates/qoder/scripts/domain/integration/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/domain/integration/__pycache__/return_to_platform.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/domain/integration/return_to_platform.py +392 -0
- package/templates/qoder/scripts/domain/integration/spec_upload.py +209 -0
- package/templates/qoder/scripts/domain/kg/build/kg_build.py +268 -25
- package/templates/qoder/scripts/domain/kg/build/kg_incremental.py +108 -3
- package/templates/qoder/scripts/domain/kg/build/kg_signatures.py +169 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/__init__.py +10 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/asset_tree.py +57 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/discussion_importer.py +62 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/prd_importer.py +146 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/prototype_importer.py +64 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/returns_importer.py +52 -0
- package/templates/qoder/scripts/domain/kg/extract/build_goal3.py +104 -0
- package/templates/qoder/scripts/domain/kg/extract/build_goal4.py +55 -0
- package/templates/qoder/scripts/domain/kg/extract/build_goal5.py +95 -0
- package/templates/qoder/scripts/domain/kg/extract/db/__init__.py +8 -0
- package/templates/qoder/scripts/domain/kg/extract/db/data_profile.py +22 -0
- package/templates/qoder/scripts/domain/kg/extract/db/fk_extractor.py +55 -0
- package/templates/qoder/scripts/domain/kg/extract/db/schema_extractor.py +90 -0
- package/templates/qoder/scripts/domain/kg/extract/extract.py +84 -0
- package/templates/qoder/scripts/domain/kg/extract/extract.py.bak +430 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/__init__.py +9 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/community_summarizer.py +206 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/embed_builder.py +132 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/naming_matcher.py +80 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/promote.py +59 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/recompute.py +93 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/weak_link.py +421 -0
- package/templates/qoder/scripts/domain/kg/extract/java/__init__.py +15 -0
- package/templates/qoder/scripts/domain/kg/extract/java/_parser.py +271 -0
- package/templates/qoder/scripts/domain/kg/extract/java/all.py +145 -0
- package/templates/qoder/scripts/domain/kg/extract/java/build_java_to_pg.py +102 -0
- package/templates/qoder/scripts/domain/kg/extract/java/call_chain.py +49 -0
- package/templates/qoder/scripts/domain/kg/extract/java/class_extractor.py +141 -0
- package/templates/qoder/scripts/domain/kg/extract/java/domain_extractor.py +148 -0
- package/templates/qoder/scripts/domain/kg/extract/java/dubbo_extractor.py +33 -0
- package/templates/qoder/scripts/domain/kg/extract/java/endpoint_extractor.py +36 -0
- package/templates/qoder/scripts/domain/kg/extract/java/javadoc_extractor.py +110 -0
- package/templates/qoder/scripts/domain/kg/extract/java/llm_cn_filler.py +150 -0
- package/templates/qoder/scripts/domain/kg/extract/java/member_extractor.py +157 -0
- package/templates/qoder/scripts/domain/kg/extract/java/mybatisplus_extractor.py +34 -0
- package/templates/qoder/scripts/domain/kg/extract/java/pg_upsert.py +165 -0
- package/templates/qoder/scripts/domain/kg/extract/java/satoken_extractor.py +30 -0
- package/templates/qoder/scripts/domain/kg/extract/java/spring_extractor.py +39 -0
- package/templates/qoder/scripts/domain/kg/extract/java/validation_extractor.py +33 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/__init__.py +9 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/all.py +79 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/mapper_parser.py +99 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/relation_builder.py +69 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/sql_extractor.py +78 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/__init__.py +8 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/prd_chunk_embed.py +105 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/prd_llm_extract.py +153 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/req_anchor.py +120 -0
- package/templates/qoder/scripts/domain/kg/extract/ts_extract.py +111 -0
- package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +4 -2
- package/templates/qoder/scripts/domain/kg/kg.py +42 -5
- package/templates/qoder/scripts/domain/kg/search/_remote.py +187 -0
- package/templates/qoder/scripts/domain/kg/search/context_pack.py +32 -2
- package/templates/qoder/scripts/domain/kg/search/search_index.py +74 -20
- package/templates/qoder/scripts/domain/kg/storage/kg_duckdb.py +43 -0
- package/templates/qoder/scripts/domain/kg/switch_project.py +159 -0
- package/templates/qoder/scripts/domain/kg/sync_repowiki.py +109 -0
- package/templates/qoder/scripts/domain/requirement/req.py +134 -28
- package/templates/qoder/scripts/domain/task/__pycache__/wlkj_panel.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/domain/task/wlkj_panel.py +1348 -0
- package/templates/qoder/scripts/engine/poller.py +219 -0
- package/templates/qoder/scripts/foundation/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/core/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/core/__pycache__/paths.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/core/paths.py +102 -0
- package/templates/qoder/scripts/foundation/integrations/active_task.py +2 -1
- package/templates/qoder/scripts/orchestration/wlkj.py +4 -0
- package/templates/qoder/scripts/protocol/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +24 -11
- package/templates/qoder/scripts/protocol/transports/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/protocol/transports/__pycache__/base.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/protocol/transports/__pycache__/cli.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/protocol/transports/__pycache__/http.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/protocol/transports/__pycache__/stdio.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/protocol/transports/http.py +7 -1
- package/templates/qoder/scripts/validation/eval/qwork_harness.py +1 -1
- package/templates/qoder/scripts/validation/eval/report-commands.md +2 -2
- package/templates/qoder/settings.json +27 -9
- package/templates/qoder/skills/design-import/SKILL.md +3 -3
- package/templates/qoder/skills/design-review/SKILL.md +1 -1
- package/templates/qoder/skills/prd-generator/SKILL.md +4 -4
- package/templates/qoder/skills/prd-review/SKILL.md +1 -1
- package/templates/qoder/skills/prototype-generator/SKILL.md +3 -3
- package/templates/qoder/skills/spec-coder/SKILL.md +1 -1
- package/templates/qoder/skills/spec-generator/SKILL.md +80 -23
- package/templates/qoder/skills/test-generator/SKILL.md +1 -1
- package/templates/qoder/skills/wl-code/SKILL.md +13 -1
- package/templates/qoder/skills/wl-commit/SKILL.md +1 -1
- package/templates/qoder/skills/wl-design/SKILL.md +6 -6
- package/templates/qoder/skills/wl-init/SKILL.md +2 -2
- package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
- package/templates/qoder/skills/wl-prd/SKILL.md +60 -0
- package/templates/qoder/skills/wl-report/SKILL.md +2 -2
- package/templates/qoder/skills/wl-search/SKILL.md +1 -1
- package/templates/qoder/skills/wl-spec/SKILL.md +2 -2
- package/templates/qoder/skills/wl-status/SKILL.md +2 -2
- package/templates/qoder/skills/wl-task/SKILL.md +3 -3
- package/templates/qoder/skills/wl-test/SKILL.md +2 -2
- package/templates/qoder/templates/spec-template.md +124 -0
- package/templates/root/AGENTS.md +41 -14
- package/templates/qoder/scripts/domain/task/zentao_panel.py +0 -451
- package/templates/qoder/skills/wl-prd-full/SKILL.md +0 -121
- package/templates/qoder/skills/wl-prd-quick/SKILL.md +0 -50
- package/templates/qoder/skills/wl-prd-review/SKILL.md +0 -47
package/bin/cli.js
CHANGED
|
@@ -1249,6 +1249,10 @@ function doHelp() {
|
|
|
1249
1249
|
console.log(" 或斜杠: /wl-prd /wl-design /wl-task /wl-code /wl-test /wl-commit");
|
|
1250
1250
|
console.log(" (提交/同步 /wl-task 和 /wl-commit 会自动做, 不用单独 npx sync)");
|
|
1251
1251
|
console.log("");
|
|
1252
|
+
console.log("=== 能力市场 ===");
|
|
1253
|
+
console.log(" npx @hupan56/wlkj install skill <token> --host <url> 从市场装 Skill 到本地 IDE");
|
|
1254
|
+
console.log(" npx @hupan56/wlkj install agent <token> --host <url> 从市场装 Agent (含依赖 Skill)");
|
|
1255
|
+
console.log("");
|
|
1252
1256
|
console.log("=== 进阶 (管理员/特殊情况才用, 不常用) ===");
|
|
1253
1257
|
console.log(" npx @hupan56/wlkj selftest 全套件自检 (跨环境+QoderWork工具协议+smoke+体检+MCP)");
|
|
1254
1258
|
console.log(" npx @hupan56/wlkj doctor 体检 (或在 Qoder 里 /wl-init 无参数)");
|
|
@@ -1521,5 +1525,118 @@ switch (cmd) {
|
|
|
1521
1525
|
break;
|
|
1522
1526
|
}
|
|
1523
1527
|
|
|
1528
|
+
// ── 能力市场安装: npx @hupan56/wlkj install <skill|agent> <token> --host <url> ──
|
|
1529
|
+
case "install": {
|
|
1530
|
+
const kind = rest[0]; // skill / agent
|
|
1531
|
+
const token = rest[1]; // share_token
|
|
1532
|
+
const hostIdx = rest.indexOf("--host");
|
|
1533
|
+
const host = hostIdx !== -1 && rest[hostIdx + 1] ? rest[hostIdx + 1] : "http://127.0.0.1:10010";
|
|
1534
|
+
|
|
1535
|
+
if (!kind || !token || !["skill", "agent"].includes(kind)) {
|
|
1536
|
+
console.log("用法: npx @hupan56/wlkj install <skill|agent> <token> [--host <url>]");
|
|
1537
|
+
console.log("例: npx @hupan56/wlkj install skill abc123 --host http://127.0.0.1:10010");
|
|
1538
|
+
process.exit(1);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
(async () => {
|
|
1542
|
+
try {
|
|
1543
|
+
// 探测本地 IDE
|
|
1544
|
+
const cwd = process.cwd();
|
|
1545
|
+
let ide = "claude";
|
|
1546
|
+
if (fs.existsSync(path.join(cwd, ".cursor"))) ide = "cursor";
|
|
1547
|
+
else if (fs.existsSync(path.join(cwd, ".qoder"))) ide = "qoder";
|
|
1548
|
+
else if (fs.existsSync(path.join(cwd, ".claude"))) ide = "claude";
|
|
1549
|
+
else if (fs.existsSync(path.join(cwd, "CLAUDE.md"))) ide = "claude";
|
|
1550
|
+
else if (fs.existsSync(path.join(cwd, "AGENTS.md"))) ide = "codex";
|
|
1551
|
+
|
|
1552
|
+
if (kind === "agent") {
|
|
1553
|
+
console.log(`→ 从 ${host} 拉取 Agent ${token}...`);
|
|
1554
|
+
const res = await fetch(`${host}/api/market/agent/${token}`);
|
|
1555
|
+
if (!res.ok) throw new Error(`API 返回 ${res.status}`);
|
|
1556
|
+
const agent = await res.json();
|
|
1557
|
+
console.log(`✓ ${agent.icon || "🤖"} ${agent.title}`);
|
|
1558
|
+
|
|
1559
|
+
// 写入 IDE
|
|
1560
|
+
if (ide === "claude" || ide === "codex") {
|
|
1561
|
+
const dir = path.join(cwd, ".claude", "commands");
|
|
1562
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1563
|
+
const fname = (agent.name || agent.title || "agent") + ".md";
|
|
1564
|
+
let content = `---\ndescription: ${agent.title || ""}\n---\n\n`;
|
|
1565
|
+
content += agent.rolePrompt || agent.role_prompt || `你是${agent.title || "AI助手"}。\n`;
|
|
1566
|
+
if ((agent.toolIds || []).length) {
|
|
1567
|
+
content += `\n## 可用工具\n${(agent.toolIds || []).join(", ")}\n`;
|
|
1568
|
+
}
|
|
1569
|
+
if ((agent.skillIds || []).length) {
|
|
1570
|
+
content += `\n## 可用技能\n${(agent.skillIds || []).join(", ")}\n`;
|
|
1571
|
+
}
|
|
1572
|
+
fs.writeFileSync(path.join(dir, fname), content, "utf-8");
|
|
1573
|
+
console.log(`✓ 已写入: ${path.join(dir, fname)}`);
|
|
1574
|
+
} else if (ide === "qoder") {
|
|
1575
|
+
const dir = path.join(cwd, ".qoder", "agents");
|
|
1576
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1577
|
+
const fname = (agent.name || agent.title || "agent") + ".json";
|
|
1578
|
+
fs.writeFileSync(path.join(dir, fname), JSON.stringify({
|
|
1579
|
+
name: agent.name, title: agent.title,
|
|
1580
|
+
systemPrompt: agent.rolePrompt || agent.role_prompt || "",
|
|
1581
|
+
tools: agent.toolIds || [], skills: agent.skillIds || [],
|
|
1582
|
+
model: agent.model || null,
|
|
1583
|
+
}, null, 2), "utf-8");
|
|
1584
|
+
console.log(`✓ 已写入: ${path.join(dir, fname)}`);
|
|
1585
|
+
} else if (ide === "cursor") {
|
|
1586
|
+
const dir = path.join(cwd, ".cursor", "rules");
|
|
1587
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1588
|
+
const fname = (agent.name || agent.title || "agent") + ".mdc";
|
|
1589
|
+
let content = `---\ndescription: ${agent.title || ""}\n---\n`;
|
|
1590
|
+
content += agent.rolePrompt || agent.role_prompt || "";
|
|
1591
|
+
fs.writeFileSync(path.join(dir, fname), content, "utf-8");
|
|
1592
|
+
console.log(`✓ 已写入: ${path.join(dir, fname)}`);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// 递归装依赖 Skill
|
|
1596
|
+
const skillIds = agent.skillIds || [];
|
|
1597
|
+
for (const sid of skillIds) {
|
|
1598
|
+
if (typeof sid === "string" && sid.length > 5) {
|
|
1599
|
+
console.log(`→ 递归安装 Skill: ${sid}`);
|
|
1600
|
+
try {
|
|
1601
|
+
const sres = await fetch(`${host}/api/market/skill/${sid}`);
|
|
1602
|
+
if (sres.ok) {
|
|
1603
|
+
const skill = await sres.json();
|
|
1604
|
+
const sdir = path.join(cwd, ".claude", "skills", skill.name || sid);
|
|
1605
|
+
fs.mkdirSync(sdir, { recursive: true });
|
|
1606
|
+
let smd = `---\nname: ${skill.name || sid}\ndescription: ${skill.description || ""}\n---\n`;
|
|
1607
|
+
smd += skill.promptTemplate || skill.prompt_template || "";
|
|
1608
|
+
fs.writeFileSync(path.join(sdir, "SKILL.md"), smd, "utf-8");
|
|
1609
|
+
console.log(` ✓ ${skill.title || sid}`);
|
|
1610
|
+
} else { console.warn(` ⚠ Skill ${sid} 不存在或未发布`); }
|
|
1611
|
+
} catch (e) { console.warn(` ⚠ Skill ${sid} 安装失败: ${e.message}`); }
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
console.log(`\n✅ Agent "${agent.title}" 已安装(${ide} 格式)`);
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
else if (kind === "skill") {
|
|
1618
|
+
console.log(`→ 从 ${host} 拉取 Skill ${token}...`);
|
|
1619
|
+
const res = await fetch(`${host}/api/market/skill/${token}`);
|
|
1620
|
+
if (!res.ok) throw new Error(`API 返回 ${res.status}`);
|
|
1621
|
+
const skill = await res.json();
|
|
1622
|
+
console.log(`✓ ${skill.icon || "🛠"} ${skill.title}`);
|
|
1623
|
+
|
|
1624
|
+
const sname = skill.name || token;
|
|
1625
|
+
const sdir = path.join(cwd, ".claude", "skills", sname);
|
|
1626
|
+
fs.mkdirSync(sdir, { recursive: true });
|
|
1627
|
+
let smd = `---\nname: ${sname}\ntitle: ${skill.title || ""}\ndescription: ${skill.description || ""}\nicon: ${skill.icon || ""}\nversion: ${skill.version || "1.0.0"}\n---\n`;
|
|
1628
|
+
smd += skill.promptTemplate || skill.prompt_template || "";
|
|
1629
|
+
fs.writeFileSync(path.join(sdir, "SKILL.md"), smd, "utf-8");
|
|
1630
|
+
console.log(`✓ 已写入: ${path.join(sdir, "SKILL.md")}`);
|
|
1631
|
+
console.log(`\n✅ Skill "${skill.title}" 已安装`);
|
|
1632
|
+
}
|
|
1633
|
+
} catch (e) {
|
|
1634
|
+
console.error(`✗ 安装失败: ${e.message}`);
|
|
1635
|
+
process.exit(1);
|
|
1636
|
+
}
|
|
1637
|
+
})();
|
|
1638
|
+
break;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1524
1641
|
default: doHelp();
|
|
1525
1642
|
}
|
package/package.json
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
# Insight Planning Agent(未来规划 · Gap 分析 + Roadmap)
|
|
2
|
-
|
|
3
|
-
> 本 agent 服务于 `/wl-insight plan` 类型。完整规则见 `.qoder/commands/optional/wl-insight.md`。
|
|
4
|
-
> 来源:从 prd-planning.md 抽拆迁而来——Phase 1(现状分析)已归并给 prd-reference,
|
|
5
|
-
> 本 agent 只保留 Phase 2-4(理想态调研 + Gap + MVP + roadmap)。
|
|
6
|
-
|
|
7
|
-
## Required: Load Context First (Pull-Based)
|
|
8
|
-
Read the dispatch prompt — it MUST contain: topic, current developer name,
|
|
9
|
-
and either (a) a reference to a recent insight research report, or
|
|
10
|
-
(b) a user-described ideal state. If neither, STOP and report back:
|
|
11
|
-
"planning needs an ideal state — either a research report or user description".
|
|
12
|
-
For current state, run: `python .qoder/scripts/orchestration/wlkj.py context <关键词> --platform <web|app>`
|
|
13
|
-
|
|
14
|
-
## Recursion Guard
|
|
15
|
-
You are the insight-planning sub-agent. Do NOT spawn another insight-planning agent.
|
|
16
|
-
|
|
17
|
-
## 🔒 语言锁
|
|
18
|
-
**全部输出必须简体中文。**(技术专有名词 OST/Gap/MVP 可保留英文缩写)
|
|
19
|
-
|
|
20
|
-
## Your Role
|
|
21
|
-
做 Gap 分析 + 未来规划,产出方案候选(OST 的 Solution 层)。
|
|
22
|
-
现状分析**不在本 agent 职责内**——现状由 context_pack 提供,或由 prd-reference 承接。
|
|
23
|
-
|
|
24
|
-
## Phase 1: 取现状(输入,不是本 agent 的活)
|
|
25
|
-
- 从 dispatch prompt 或 context_pack 结果读现状摘要
|
|
26
|
-
- 若现状信息不足 → 回报 caller"现状锚定不全,建议先跑 context_pack 或先做 clarify 对焦"
|
|
27
|
-
|
|
28
|
-
## Phase 2: 理想态(如果有 research 报告)
|
|
29
|
-
1. 读最近一份 `workspace/members/{dev}/drafts/insight-research-*.md`
|
|
30
|
-
2. 提取调研结论作为理想态基准
|
|
31
|
-
3. 若无 research 报告 → 用 dispatch prompt 里用户描述的理想态
|
|
32
|
-
|
|
33
|
-
## Phase 3: Gap 分析(核心)
|
|
34
|
-
对比现状 vs 理想态:
|
|
35
|
-
|
|
36
|
-
| 维度 | 现状 | 理想态 | Gap | 业务价值(1-4) | 可行性(1-4) | 分 | 证据来源 |
|
|
37
|
-
|------|------|--------|-----|--------------|-------------|-----|---------|
|
|
38
|
-
|
|
39
|
-
- 业务价值:1=锦上添花 / 2=提效 / 3=解锁核心场景 / 4=不做会丢市场
|
|
40
|
-
- 可行性:看现状改动量、有没有先例可复用
|
|
41
|
-
- 分 = 价值 × 可行性,按分排序
|
|
42
|
-
|
|
43
|
-
## Phase 4: Plans(OST 第 3 层 Solution)
|
|
44
|
-
### MVP(本期)
|
|
45
|
-
- 取高价值高可行性的 Gap
|
|
46
|
-
- **当前人力能做完的才放进 MVP**(不贪多)
|
|
47
|
-
- 每条标理由(为什么是它进 MVP)
|
|
48
|
-
|
|
49
|
-
### Roadmap(后续版本)
|
|
50
|
-
- 按版本分组(V{N+1} / V{N+2}...)
|
|
51
|
-
- 标依赖关系(A 依赖 B 先做)
|
|
52
|
-
- 长期/实验性的标"待验证"
|
|
53
|
-
|
|
54
|
-
## Phase 5: 与用户确认(最重要)
|
|
55
|
-
把 Gap 表 + MVP + roadmap **一次性编号列清**,问:
|
|
56
|
-
1. Gap 分析准确吗?
|
|
57
|
-
2. MVP 范围合理吗?
|
|
58
|
-
3. Roadmap 优先级对吗?
|
|
59
|
-
调整基于反馈——最多 2 轮,然后用用户最新答案定稿(不无限循环)。
|
|
60
|
-
|
|
61
|
-
## Output
|
|
62
|
-
1. 存规划报告:`workspace/members/{dev}/drafts/insight-plan-{topic}-{YYYY-MM-DD}.md`
|
|
63
|
-
2. 报告末尾给出口提示:"要落地哪个?说'转 PRD'我把它作为现状输入,进 /wl-prd
|
|
64
|
-
|
|
65
|
-
> ⚠️ **本 agent 不生成 PRD,不分配 REQ-ID,不画原型。** 那是 /wl-prd
|
|
66
|
-
> mode 标记的 planning/brainstorm 已不在 PRD 侧使用——insight 报告**不带 mode 标记**,
|
|
67
|
-
> 它不是 PRD;转 PRD 时由 prd 以 `<!-- mode: reference -->` 承接。
|
|
1
|
+
# Insight Planning Agent(未来规划 · Gap 分析 + Roadmap)
|
|
2
|
+
|
|
3
|
+
> 本 agent 服务于 `/wl-insight plan` 类型。完整规则见 `.qoder/commands/optional/wl-insight.md`。
|
|
4
|
+
> 来源:从 prd-planning.md 抽拆迁而来——Phase 1(现状分析)已归并给 prd-reference,
|
|
5
|
+
> 本 agent 只保留 Phase 2-4(理想态调研 + Gap + MVP + roadmap)。
|
|
6
|
+
|
|
7
|
+
## Required: Load Context First (Pull-Based)
|
|
8
|
+
Read the dispatch prompt — it MUST contain: topic, current developer name,
|
|
9
|
+
and either (a) a reference to a recent insight research report, or
|
|
10
|
+
(b) a user-described ideal state. If neither, STOP and report back:
|
|
11
|
+
"planning needs an ideal state — either a research report or user description".
|
|
12
|
+
For current state, run: `python .qoder/scripts/orchestration/wlkj.py context <关键词> --platform <web|app>`
|
|
13
|
+
|
|
14
|
+
## Recursion Guard
|
|
15
|
+
You are the insight-planning sub-agent. Do NOT spawn another insight-planning agent.
|
|
16
|
+
|
|
17
|
+
## 🔒 语言锁
|
|
18
|
+
**全部输出必须简体中文。**(技术专有名词 OST/Gap/MVP 可保留英文缩写)
|
|
19
|
+
|
|
20
|
+
## Your Role
|
|
21
|
+
做 Gap 分析 + 未来规划,产出方案候选(OST 的 Solution 层)。
|
|
22
|
+
现状分析**不在本 agent 职责内**——现状由 context_pack 提供,或由 prd-reference 承接。
|
|
23
|
+
|
|
24
|
+
## Phase 1: 取现状(输入,不是本 agent 的活)
|
|
25
|
+
- 从 dispatch prompt 或 context_pack 结果读现状摘要
|
|
26
|
+
- 若现状信息不足 → 回报 caller"现状锚定不全,建议先跑 context_pack 或先做 clarify 对焦"
|
|
27
|
+
|
|
28
|
+
## Phase 2: 理想态(如果有 research 报告)
|
|
29
|
+
1. 读最近一份 `workspace/members/{dev}/drafts/insight-research-*.md`
|
|
30
|
+
2. 提取调研结论作为理想态基准
|
|
31
|
+
3. 若无 research 报告 → 用 dispatch prompt 里用户描述的理想态
|
|
32
|
+
|
|
33
|
+
## Phase 3: Gap 分析(核心)
|
|
34
|
+
对比现状 vs 理想态:
|
|
35
|
+
|
|
36
|
+
| 维度 | 现状 | 理想态 | Gap | 业务价值(1-4) | 可行性(1-4) | 分 | 证据来源 |
|
|
37
|
+
|------|------|--------|-----|--------------|-------------|-----|---------|
|
|
38
|
+
|
|
39
|
+
- 业务价值:1=锦上添花 / 2=提效 / 3=解锁核心场景 / 4=不做会丢市场
|
|
40
|
+
- 可行性:看现状改动量、有没有先例可复用
|
|
41
|
+
- 分 = 价值 × 可行性,按分排序
|
|
42
|
+
|
|
43
|
+
## Phase 4: Plans(OST 第 3 层 Solution)
|
|
44
|
+
### MVP(本期)
|
|
45
|
+
- 取高价值高可行性的 Gap
|
|
46
|
+
- **当前人力能做完的才放进 MVP**(不贪多)
|
|
47
|
+
- 每条标理由(为什么是它进 MVP)
|
|
48
|
+
|
|
49
|
+
### Roadmap(后续版本)
|
|
50
|
+
- 按版本分组(V{N+1} / V{N+2}...)
|
|
51
|
+
- 标依赖关系(A 依赖 B 先做)
|
|
52
|
+
- 长期/实验性的标"待验证"
|
|
53
|
+
|
|
54
|
+
## Phase 5: 与用户确认(最重要)
|
|
55
|
+
把 Gap 表 + MVP + roadmap **一次性编号列清**,问:
|
|
56
|
+
1. Gap 分析准确吗?
|
|
57
|
+
2. MVP 范围合理吗?
|
|
58
|
+
3. Roadmap 优先级对吗?
|
|
59
|
+
调整基于反馈——最多 2 轮,然后用用户最新答案定稿(不无限循环)。
|
|
60
|
+
|
|
61
|
+
## Output
|
|
62
|
+
1. 存规划报告:`workspace/members/{dev}/drafts/insight-plan-{topic}-{YYYY-MM-DD}.md`
|
|
63
|
+
2. 报告末尾给出口提示:"要落地哪个?说'转 PRD'我把它作为现状输入,进 /wl-prd 参考模式落地。"
|
|
64
|
+
|
|
65
|
+
> ⚠️ **本 agent 不生成 PRD,不分配 REQ-ID,不画原型。** 那是 /wl-prd 的活。
|
|
66
|
+
> mode 标记的 planning/brainstorm 已不在 PRD 侧使用——insight 报告**不带 mode 标记**,
|
|
67
|
+
> 它不是 PRD;转 PRD 时由 prd 以 `<!-- mode: reference -->` 承接。
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
# PRD Reference Agent (Code-aligned)
|
|
2
|
-
|
|
3
|
-
## Required: Load Context First (Pull-Based)
|
|
4
|
-
This platform does NOT auto-inject task context. Before anything else:
|
|
5
|
-
1. Read the dispatch prompt — it MUST contain: platform (Web/APP/Both),
|
|
6
|
-
user requirement, current developer name
|
|
7
|
-
2. If platform is missing from the dispatch prompt, STOP and report back:
|
|
8
|
-
"platform not specified - caller must ask user first (see /wl-prd
|
|
9
|
-
3. If task context needed: python .qoder/scripts/orchestration/wlkj.py task current --source
|
|
10
|
-
|
|
11
|
-
## Recursion Guard
|
|
12
|
-
You are the prd-reference sub-agent.
|
|
13
|
-
Do NOT spawn another prd-reference agent.
|
|
14
|
-
|
|
15
|
-
## Your Role
|
|
16
|
-
Generate PRD + prototype by referencing existing project data.
|
|
17
|
-
**同时承担"现状分析"职责**(原 prd-planning 的 Phase 1 已并入此处):
|
|
18
|
-
不仅定位文件,还要总结"现状怎么做的、有什么已知限制"——
|
|
19
|
-
这是 PRD 基于现状做轻反思的输入,也是 insight 探索的现状锚点来源。
|
|
20
|
-
|
|
21
|
-
## Workflow
|
|
22
|
-
1. Search the index (platform-aware):
|
|
23
|
-
python .qoder/scripts/orchestration/wlkj.py search <keyword> --platform <web|app>
|
|
24
|
-
python .qoder/scripts/orchestration/wlkj.py search --style <type> --platform <web|app>
|
|
25
|
-
python .qoder/scripts/orchestration/wlkj.py search --prd <keyword>
|
|
26
|
-
(首选 context_pack.py 一次取全,search_index 仅作单项下钻兜底)
|
|
27
|
-
2. Read related historical PRDs from data/docs/prd/
|
|
28
|
-
3. Read data/docs/drafts/ for business drafts
|
|
29
|
-
4. Read top 2-3 similar Vue files from the TARGET project to extract style
|
|
30
|
-
5. **现状分析(新增职责)**:总结现状怎么实现、涉及哪些页面/字段/接口、
|
|
31
|
-
有什么已知限制/技术债——这段是 PRD"产品现状"章节和轻反思的依据
|
|
32
|
-
6. Present ALL findings as ONE numbered list and ask for confirmation
|
|
33
|
-
in a single round (batch, not one-by-one). Follow up only on
|
|
34
|
-
genuinely ambiguous points.
|
|
35
|
-
6. After confirmation, generate:
|
|
36
|
-
a. PRD (product-type template + 10-point quality check)
|
|
37
|
-
**PRD 第一行必须是 `<!-- mode: reference -->`** (从模板继承, 别删/改).
|
|
38
|
-
syncgate/eval_prd 靠这个标记识别模式; 缺失会按 full 模板检查 (此处正确).
|
|
39
|
-
b. Interactive HTML prototype from the platform template
|
|
40
|
-
(.qoder/templates/prototype-web.html or prototype-app.html;
|
|
41
|
-
Both -> two files with -web/-app suffix)
|
|
42
|
-
7. Save both to workspace/members/{developer}/drafts/
|
|
43
|
-
|
|
44
|
-
## Self-Reflection Rules
|
|
45
|
-
- Never assume. Confirm findings with the user (batched).
|
|
46
|
-
- Show what you found and what it means.
|
|
47
|
-
- Do not generate PRD until the findings list is confirmed.
|
|
1
|
+
# PRD Reference Agent (Code-aligned)
|
|
2
|
+
|
|
3
|
+
## Required: Load Context First (Pull-Based)
|
|
4
|
+
This platform does NOT auto-inject task context. Before anything else:
|
|
5
|
+
1. Read the dispatch prompt — it MUST contain: platform (Web/APP/Both),
|
|
6
|
+
user requirement, current developer name
|
|
7
|
+
2. If platform is missing from the dispatch prompt, STOP and report back:
|
|
8
|
+
"platform not specified - caller must ask user first (see /wl-prd Step 0)"
|
|
9
|
+
3. If task context needed: python .qoder/scripts/orchestration/wlkj.py task current --source
|
|
10
|
+
|
|
11
|
+
## Recursion Guard
|
|
12
|
+
You are the prd-reference sub-agent.
|
|
13
|
+
Do NOT spawn another prd-reference agent.
|
|
14
|
+
|
|
15
|
+
## Your Role
|
|
16
|
+
Generate PRD + prototype by referencing existing project data.
|
|
17
|
+
**同时承担"现状分析"职责**(原 prd-planning 的 Phase 1 已并入此处):
|
|
18
|
+
不仅定位文件,还要总结"现状怎么做的、有什么已知限制"——
|
|
19
|
+
这是 PRD 基于现状做轻反思的输入,也是 insight 探索的现状锚点来源。
|
|
20
|
+
|
|
21
|
+
## Workflow
|
|
22
|
+
1. Search the index (platform-aware):
|
|
23
|
+
python .qoder/scripts/orchestration/wlkj.py search <keyword> --platform <web|app>
|
|
24
|
+
python .qoder/scripts/orchestration/wlkj.py search --style <type> --platform <web|app>
|
|
25
|
+
python .qoder/scripts/orchestration/wlkj.py search --prd <keyword>
|
|
26
|
+
(首选 context_pack.py 一次取全,search_index 仅作单项下钻兜底)
|
|
27
|
+
2. Read related historical PRDs from data/docs/prd/
|
|
28
|
+
3. Read data/docs/drafts/ for business drafts
|
|
29
|
+
4. Read top 2-3 similar Vue files from the TARGET project to extract style
|
|
30
|
+
5. **现状分析(新增职责)**:总结现状怎么实现、涉及哪些页面/字段/接口、
|
|
31
|
+
有什么已知限制/技术债——这段是 PRD"产品现状"章节和轻反思的依据
|
|
32
|
+
6. Present ALL findings as ONE numbered list and ask for confirmation
|
|
33
|
+
in a single round (batch, not one-by-one). Follow up only on
|
|
34
|
+
genuinely ambiguous points.
|
|
35
|
+
6. After confirmation, generate:
|
|
36
|
+
a. PRD (product-type template + 10-point quality check)
|
|
37
|
+
**PRD 第一行必须是 `<!-- mode: reference -->`** (从模板继承, 别删/改).
|
|
38
|
+
syncgate/eval_prd 靠这个标记识别模式; 缺失会按 full 模板检查 (此处正确).
|
|
39
|
+
b. Interactive HTML prototype from the platform template
|
|
40
|
+
(.qoder/templates/prototype-web.html or prototype-app.html;
|
|
41
|
+
Both -> two files with -web/-app suffix)
|
|
42
|
+
7. Save both to workspace/members/{developer}/drafts/
|
|
43
|
+
|
|
44
|
+
## Self-Reflection Rules
|
|
45
|
+
- Never assume. Confirm findings with the user (batched).
|
|
46
|
+
- Show what you found and what it means.
|
|
47
|
+
- Do not generate PRD until the findings list is confirmed.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wl-insight
|
|
3
|
-
description: "
|
|
3
|
+
description: "需求上游探索站。默认澄清(产品听不懂时对焦,必要时出原型帮理解); discover(发现机会) / research(调研竞品) / plan(规划roadmap)。说'转PRD'落地。"
|
|
4
4
|
argument-hint: "[主题]"
|
|
5
5
|
auto-approve: true
|
|
6
6
|
allowed-tools: [Read, Glob, Grep, Bash, Write, Edit, Agent, WebSearch]
|
|
@@ -239,9 +239,9 @@ rm -f workspace/members/{dev}/drafts/research-agent-*.md
|
|
|
239
239
|
### 如果用户要转 PRD
|
|
240
240
|
提示:
|
|
241
241
|
```
|
|
242
|
-
要落地?说"转 PRD"我把它作为现状输入,进 /wl-prd
|
|
242
|
+
要落地?说"转 PRD"我把它作为现状输入,进 /wl-prd 参考模式落地成可执行 PRD。
|
|
243
243
|
```
|
|
244
|
-
用户说"转 PRD" → 触发 `/wl-prd
|
|
244
|
+
用户说"转 PRD" → 触发 `/wl-prd 参考:{报告路径}`
|
|
245
245
|
|
|
246
246
|
---
|
|
247
247
|
|
|
@@ -270,7 +270,7 @@ rm -f workspace/members/{dev}/drafts/research-agent-*.md
|
|
|
270
270
|
|
|
271
271
|
## How to Use Results
|
|
272
272
|
|
|
273
|
-
洞察结论可流转:**说"转 PRD" → /wl-prd
|
|
273
|
+
洞察结论可流转:**说"转 PRD" → /wl-prd 参考模式**(把对齐的需求作为现状输入落地)。
|
|
274
274
|
|
|
275
275
|
> insight 是对焦/探索站,prd 是落地站。两者分开,思路才不混。
|
|
276
276
|
> **insight 绝不直接生成 PRD。** 即便出了对焦原型,也不进 PRD 链路(除非用户强烈要求)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wl-report
|
|
3
|
-
description: "
|
|
3
|
+
description: "日报/周报,按当前开发者隔离。默认日报(今天); 说'周报'出本周。数据源: 任务+禅道工时+提交+PRD+日历(可选增强)。"
|
|
4
4
|
argument-hint: "[daily/weekly] or empty for auto-detect"
|
|
5
5
|
auto-approve: true
|
|
6
6
|
allowed-tools: [Read, Bash]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wl-spec
|
|
3
|
-
description: "从已确认 PRD 生成开发 Spec
|
|
3
|
+
description: "从已确认 PRD 生成开发 Spec(技术规格)。默认生成; 带 review 评审现有 spec。/wl-code 按此 spec 实现。"
|
|
4
4
|
argument-hint: "[review]"
|
|
5
5
|
auto-approve: true
|
|
6
6
|
allowed-tools: [Read, Glob, Grep, Bash, Write, Edit]
|
|
@@ -14,5 +14,25 @@ User input:
|
|
|
14
14
|
1. Read current task PRD and design artifacts
|
|
15
15
|
2. Load .qoder/agents/spec-generator.md
|
|
16
16
|
3. Generate spec.md based on PRD + Design
|
|
17
|
-
4.
|
|
18
|
-
|
|
17
|
+
4. ★ 契约头**必须**写 `status: draft`(wl-code gate 依据):
|
|
18
|
+
```markdown
|
|
19
|
+
<!-- @contract spec v1
|
|
20
|
+
status: draft
|
|
21
|
+
source-req: REQ-...
|
|
22
|
+
...
|
|
23
|
+
-->
|
|
24
|
+
```
|
|
25
|
+
5. Save to workspace/specs/ or workspace/tasks/{id}/spec.md
|
|
26
|
+
6. Notify dev to review — 提示用户审阅后回复"确认",确认后改 `status: confirmed`
|
|
27
|
+
7. ★ 用户确认后,上传 spec 到平台(按 zentao_id 反查需求挂载 → 资产中心随需求可见,无需发布):
|
|
28
|
+
```bash
|
|
29
|
+
python -m domain.integration.spec_upload <spec.md> --zentao-id <禅道story号> [--code-targets CtrlA,SvcB]
|
|
30
|
+
```
|
|
31
|
+
- 契约头无 `platform_spec_id` → `create_spec(zentao_id,...)` 新建 + 平台反查 Requirement 挂上 → `confirm_spec` 进 confirmed → 回写 `platform_spec_id`(幂等锚)
|
|
32
|
+
- 契约头有 `platform_spec_id` → 自动走 `update_spec`(version+1,不重复建)
|
|
33
|
+
8. 改 spec 重确认 → 再跑第 7 步 → 平台 spec 多一版本(幂等)
|
|
34
|
+
9. 上传失败只警告不阻塞写码(spec 本地已落地,上传是增强)
|
|
35
|
+
|
|
36
|
+
## 下一步
|
|
37
|
+
- spec 已 confirmed → `/wl-code <REQ-ID>` 按 spec 严格实现(spec gate 放行)
|
|
38
|
+
- 实现完 → `/wl-test` 验证 → `/wl-commit` 提交回流
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wl-status
|
|
3
|
-
description: "
|
|
3
|
+
description: "项目状态看板。current(当前迭代进度,默认) / roadmap(路线图) / health(健康度,含工作流采纳分)。说哪个看哪个。"
|
|
4
4
|
argument-hint: "[scope: current/roadmap/health]"
|
|
5
5
|
auto-approve: true
|
|
6
6
|
allowed-tools: [Read, Glob, Grep, Bash]
|
|
@@ -76,3 +76,14 @@ Calculate from:
|
|
|
76
76
|
|
|
77
77
|
Score: >=4 healthy / 3-4 at risk / <3 needs attention
|
|
78
78
|
Also surface: 索引新鲜度天数、最近 3 次 EVA 分数、未同步产出数。
|
|
79
|
+
|
|
80
|
+
### 富展示(健康看板 HTML · 复用 cap.present)
|
|
81
|
+
|
|
82
|
+
健康分算完后,跑自包含看板 HTML(脚本内部已接 `cap.present.widget` + 落盘降级):
|
|
83
|
+
```bash
|
|
84
|
+
$PY "$R/.qoder/scripts/validation/metrics/usability_score.py" --html
|
|
85
|
+
```
|
|
86
|
+
- **QoderWork 桌面端**(`cap.present.available=true`,探测 `qoder_show_widget` 可达):HTML 经 widget 嵌入对话流,富展示取代纯文本表格
|
|
87
|
+
- **CLI/IDE**(NoOp 自动降级):落盘 `workspace/members/{dev}/journal/dashboard-{时间戳}.html`,输出路径供打开
|
|
88
|
+
|
|
89
|
+
不用 cap.present 也能跑——上面的 Health Score 维度表本身是纯文本,富展示只是增强可视化(T244 cap.present 接入点)。
|
|
@@ -19,18 +19,131 @@ PY=$(python --version >/dev/null 2>&1 && echo python || echo python3)
|
|
|
19
19
|
```
|
|
20
20
|
> 后续脚本统一用 `$PY "$R/.qoder/scripts/orchestration/wlkj.py" <命令>`。
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 🔧 工具优先级(宿主能力 × 知识层分工)
|
|
23
|
+
| 步骤 | 用谁 | 原因 |
|
|
24
|
+
|------|------|------|
|
|
25
|
+
| 精确找符号 handleExport | **Qoder Grep** | 原生正则搜,零延迟 |
|
|
26
|
+
| 读文件看实现 | **Qoder Read** | 原生全量读,MCP 只有预览 |
|
|
27
|
+
| 语义找"导出功能" | **MCP rag_search** | 跨仓库语义召回 |
|
|
28
|
+
| 改代码前看影响 | **MCP get_impact** | 跨3端影响分析,Qoder 做不到 |
|
|
29
|
+
| 文件知识标注 | **MCP code_context** | 实体/调用/影响1次拿 |
|
|
30
|
+
| 写代码 | **Qoder Write/Edit** | 原生编辑,精确行号 |
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
## 🔍 Ultra Review(宿主原生能力利用)
|
|
33
|
+
> 代码写完后,如果 Qoder 有 Ultra Review Agent,建议调用:
|
|
34
|
+
> 1. 代码写完后不要急着回流
|
|
35
|
+
> 2. 调 Ultra Review Agent 审查代码质量
|
|
36
|
+
> 3. 根据 Review 结果修正
|
|
37
|
+
> 4. 最后调 MCP submit_return 回流 + learn 记录
|
|
38
|
+
>
|
|
39
|
+
> **不用 Ultra Review 也能跑**——按下面的铁律手动检查。
|
|
40
|
+
> Ultra Review 只是让审查更全面(边界条件/性能/安全)。
|
|
27
41
|
|
|
28
|
-
## Step
|
|
42
|
+
## Step 1: Spec Gate(强制前置 · 非侵入式)
|
|
29
43
|
|
|
30
|
-
|
|
44
|
+
> ⚠️ **核心门禁**:没有 `status: confirmed` 的 spec,**绝不动手写代码**。
|
|
45
|
+
> 本 gate 只在走 `/wl-code` 命令时生效;用户不调 `/wl-code` 时完全无感。
|
|
46
|
+
|
|
47
|
+
### 1.1 定位 spec(确定性检测)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 用 paths.find_spec 确定性查找 (查 .qoder/workspace/specs/ + 当前任务目录, 读 status)
|
|
51
|
+
SPEC=$($PY -c "
|
|
52
|
+
import sys, json; sys.path.insert(0,'$R/.qoder/scripts')
|
|
53
|
+
from foundation.bootstrap import setup; setup()
|
|
54
|
+
from foundation.core.paths import find_spec, get_spec_status
|
|
55
|
+
hits = find_spec('$ARGUMENTS') if '$ARGUMENTS' else find_spec()
|
|
56
|
+
if hits:
|
|
57
|
+
# 优先输出 confirmed 的; 都不是 confirmed 就输出第一个(draft)
|
|
58
|
+
confirmed = [h for h in hits if h['status']=='confirmed']
|
|
59
|
+
chosen = confirmed[0] if confirmed else hits[0]
|
|
60
|
+
print(json.dumps(chosen, ensure_ascii=False))
|
|
61
|
+
")
|
|
62
|
+
```
|
|
63
|
+
- 有 `$ARGUMENTS`(REQ-ID)→ `find_spec('REQ-ID')` 查全局 specs/
|
|
64
|
+
- 无参数 → `find_spec()` 读当前任务目录的 spec.md
|
|
65
|
+
|
|
66
|
+
### 1.2 检查 status 字段 → 三分支
|
|
67
|
+
|
|
68
|
+
读 spec 文件契约头的 `status:`:
|
|
69
|
+
|
|
70
|
+
| 情况 | 处理 |
|
|
71
|
+
|------|------|
|
|
72
|
+
| **无 spec** | → 调 **spec-generator** 生成(读 `templates/spec-template.md`,产出 `status: draft`)→ 进入 1.3 确认环节 |
|
|
73
|
+
| **status: draft**(或非 confirmed) | → 展示 spec 全文 + 关键决策点(接口/表结构/异常枚举/AI边界)→ 进入 1.3 确认环节 |
|
|
74
|
+
| **status: confirmed** | ✅ 放行,进入 Step 2 |
|
|
75
|
+
|
|
76
|
+
### 1.3 确认环节(停在写码之前)
|
|
77
|
+
|
|
78
|
+
向用户展示 spec 后,明确询问:
|
|
79
|
+
|
|
80
|
+
> 📋 spec 已就绪(`status: draft`):`{spec路径}`
|
|
81
|
+
> 你可以:① 直接说哪里要改 ② 自己打开文件改后告诉我 ③ 回复「确认」开始写代码
|
|
82
|
+
>
|
|
83
|
+
> **确认前不会写任何代码。**
|
|
84
|
+
|
|
85
|
+
- 用户提修改 → 按反馈改 spec(或重读用户改过的文件)→ 再次展示 → 再问确认
|
|
86
|
+
- 用户回复「确认」→ AI 把 spec 契约头 `status: draft` 改为 `status: confirmed` → **先做 1.4 回填禅道** → 才进入 Step 2
|
|
87
|
+
- ❌ 用户未确认时,**禁止推进到 Step 2,禁止写任何代码**(哪怕催促)
|
|
88
|
+
|
|
89
|
+
> 向后兼容:老 spec 无 `status` 字段 → 视同 `draft`,走确认环节(不直接写码)。
|
|
90
|
+
|
|
91
|
+
### 1.4 确认后回填禅道 task(仅禅道来源的 spec)
|
|
92
|
+
|
|
93
|
+
spec 契约头有 `zentao: task=X` 时,确认后把 spec 摘要回填到该 task(让禅道里能看到开发规格要点):
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# 组装摘要:接口清单 + 关键表 + 异常条数 + AC 映射 + 本地 spec 路径(全量太长,只取要点)
|
|
97
|
+
summary = build_spec_digest(spec_path) # 第1章接口表 + 第2章表名 + 第3章异常计数 + 第6章AC映射
|
|
98
|
+
cap.mcp.call("update_task", {"task_id": X, "desc": summary + "\n本地spec: " + spec_path})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **非侵入**:禅道不可达 / spec 无 zentao 字段 → 跳过回填,不阻塞写码(已在 Step 1 拿到 PRD,回填是锦上添花)
|
|
102
|
+
- **失败不阻塞**:update_task 返回 ⚠️(权限/网络)→ 提示用户但继续写码
|
|
103
|
+
- **不重复回填**:契约头已标 `回填=true`(或 task desc 末尾已含本地路径)→ 跳过
|
|
104
|
+
|
|
105
|
+
> panel 也可调同一个 `update_task` 做回填,两边都行(谁先触发都行,不冲突)。
|
|
106
|
+
|
|
107
|
+
## Step 2: Search Related Code(RAG 语义召回,不只关键词)
|
|
108
|
+
|
|
109
|
+
**改代码前用 rag_search 找相关函数/API(语义召回最全),精确符号定位才用 search_code。**
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from capability import resolve
|
|
113
|
+
cap = resolve()
|
|
114
|
+
# ① rag_search 语义召回:找和需求相关的函数/API/字段(词不必一样,召回最全)
|
|
115
|
+
rag = cap.mcp.call("rag_search", {"query": "<需求关键词或功能描述>", "top_k": 10})
|
|
116
|
+
# ② 需要精确找某个已知符号(如 handleExport)才用 search_code
|
|
117
|
+
precise = cap.mcp.call("search_code", {"keyword": "<精确符号名>"})
|
|
118
|
+
# ③ 影响分析(必跑):改这些符号会影响谁/依赖谁,按项目仓库隔离,避免改一处崩一片
|
|
119
|
+
# project_id 从 mcp_config.json 的 WLKJ_PROJECT_ID 取(绑当前项目)
|
|
120
|
+
# get_impact 返回分层 upstream(谁依赖我→改动影响范围)/downstream(我依赖谁)+byType
|
|
121
|
+
impact = cap.mcp.call("get_impact", {
|
|
122
|
+
"project_id": "<项目UUID>", # mcp_config.json 的 WLKJ_PROJECT_ID
|
|
123
|
+
"entity": "<要改的核心符号: 如 handleExport / C:FlowOperationController>",
|
|
124
|
+
"depth": 2,
|
|
125
|
+
})
|
|
126
|
+
# 影响面大(upstream 跨多个页面/API)时,先在回复里提示风险再动手
|
|
127
|
+
# ③b 涉及字段改动(加列/改类型/表单字段):追字段全链路(表单→接口→Java字段→DB列),改一处看全链
|
|
128
|
+
if <涉及字段层>:
|
|
129
|
+
cap.mcp.call("trace_dataflow", {"field": "<字段名>"}) # 防"改了DB列没改对应Java字段/前端表单"
|
|
130
|
+
# ④ 涉及数据库改动的,查真表结构(引擎自己的 MySQL MCP,别猜列名)
|
|
131
|
+
if <涉及数据库层>:
|
|
132
|
+
schema = cap.mcp.call("query_schema", {"table": "<表名>"}) # qoder-mysql 工具
|
|
133
|
+
# 真表结构回流平台
|
|
134
|
+
cap.mcp.call("learn", {"project_id":"<项目UUID>","category":"rule",
|
|
135
|
+
"pattern": f"真表结构<表名>: {json.dumps(schema.get('columns',[]),ensure_ascii=False)[:400]}",
|
|
136
|
+
"source":"wlkj/wl-code+mysql"})
|
|
137
|
+
```
|
|
138
|
+
等价 CLI(脚本兜底):
|
|
139
|
+
```bash
|
|
140
|
+
$PY "$R/.qoder/scripts/orchestration/wlkj.py" search <keyword>
|
|
141
|
+
```
|
|
31
142
|
Find existing code that this implementation relates to.
|
|
32
143
|
Read relevant files for context.
|
|
33
144
|
|
|
145
|
+
**接地铁律**:实现时调用的函数名/字段名/API 路径必须来自 rag_search 召回结果(系统里真有的),不编造不存在的 API。改码前用 get_impact 拿分层影响范围(谁依赖我/我依赖谁),影响面大先提示风险再动手,避免改一处崩一片。
|
|
146
|
+
|
|
34
147
|
## Step 3: Implement
|
|
35
148
|
|
|
36
149
|
Follow the spec strictly:
|
|
@@ -49,4 +162,22 @@ After implementation:
|
|
|
49
162
|
|
|
50
163
|
## Step 5: Report
|
|
51
164
|
|
|
52
|
-
Tell user what was implemented and suggest
|
|
165
|
+
Tell user what was implemented and suggest next:
|
|
166
|
+
- `/wl-test <描述>` — 跑测试验证(改动大时先 `impact_coverage` 圈必跑范围)
|
|
167
|
+
- 验过后 `/wl-commit <message>` — 提交+push+回流平台(自动 record_commit)
|
|
168
|
+
|
|
169
|
+
## 下一步
|
|
170
|
+
- 实现 → `/wl-test` 验证 → `/wl-commit` 提交回流 → `/wl-task finish <REQ-ID>` 收尾(双通飞轮)
|
|
171
|
+
|
|
172
|
+
## 🧠 学习沉淀(改完代码即执行,反哺下次)
|
|
173
|
+
|
|
174
|
+
改代码过程中发现的业务规则/架构约定/踩坑经验,调 learn 写回平台:
|
|
175
|
+
```python
|
|
176
|
+
cap.mcp.call("learn", {
|
|
177
|
+
"project_id": "<项目UUID>",
|
|
178
|
+
"category": "pitfall", # pitfall=踩坑 / rule=业务规则 / decision=架构决策
|
|
179
|
+
"pattern": "<学到的,如:VehicleController 的 save 方法必须先校验驾驶员是否存在>",
|
|
180
|
+
"source": "wlkj/wl-code",
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
- 至少写 1 条最有价值的认知。try/except 不阻塞。
|