@dawipong/opcflow 0.4.0 → 0.6.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.en.md +3 -1
- package/README.md +3 -2
- package/dist/cli.mjs +346 -118
- package/package.json +3 -1
- package/web/dist/assets/{abnfDiagram-VRR7QNED-DAx6EpGI.js → abnfDiagram-VRR7QNED-Cwj4KBKb.js} +1 -1
- package/web/dist/assets/{arc-DPoWLLje.js → arc-Ci--dbFA.js} +1 -1
- package/web/dist/assets/architecture-TIHT7OUA-Dx_ZsFnL.js +1 -0
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-Dvr2nr59.js → architectureDiagram-ZJ3FMSHR-B83QZuM-.js} +2 -2
- package/web/dist/assets/{blockDiagram-677ZJIJ3-CUYUzMZC.js → blockDiagram-677ZJIJ3-C5lnvD0j.js} +1 -1
- package/web/dist/assets/{c4Diagram-LMCZKHZV-DhT2uxnj.js → c4Diagram-LMCZKHZV-Di1TmZQy.js} +1 -1
- package/web/dist/assets/channel-Bk0jbqCs.js +1 -0
- package/web/dist/assets/{chunk-32BRIVSS-CztnJRkA.js → chunk-32BRIVSS-BWSjcFoD.js} +1 -1
- package/web/dist/assets/{chunk-C7G6YPKG-jsbUGVSb.js → chunk-C7G6YPKG-DSkQqM00.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-M3QhKBUG.js → chunk-EX3LRPZG-DOdm7LPI.js} +1 -1
- package/web/dist/assets/{chunk-HOUHSVGY-DDAtZMtg.js → chunk-HOUHSVGY-D1LueKb6.js} +1 -1
- package/web/dist/assets/{chunk-ICXQ74PX-C2h9d1ob.js → chunk-ICXQ74PX-CFh6Ch4J.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-DXlFl9Jv.js → chunk-MOJQB5TN-BrFLYoih.js} +1 -1
- package/web/dist/assets/{chunk-OGEWGWER-B5mrusUD.js → chunk-OGEWGWER-C1n7EcC_.js} +1 -1
- package/web/dist/assets/{chunk-PUDLZKDR-BTWHaeTZ.js → chunk-PUDLZKDR-D4rKEnrx.js} +1 -1
- package/web/dist/assets/{chunk-Q4XR5HBZ-Cfw3UWMb.js → chunk-Q4XR5HBZ-DVm0yUET.js} +1 -1
- package/web/dist/assets/{chunk-RYQCIY6F-CCUojmgb.js → chunk-RYQCIY6F-BlZZOayN.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-Cbgml1c1.js → chunk-V7JOEXUC-Bb-id9Vk.js} +1 -1
- package/web/dist/assets/{chunk-VR4S4FIN-CUMv178C.js → chunk-VR4S4FIN-DbbNoX70.js} +1 -1
- package/web/dist/assets/{chunk-WYO6CB5R-BaRUDpDl.js → chunk-WYO6CB5R-C0vPAP7X.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-tmq33VNh.js → chunk-XXDRQBXY-BS9H__hw.js} +1 -1
- package/web/dist/assets/{chunk-ZGVPDNZ5-DK9a-Iwy.js → chunk-ZGVPDNZ5-BiBGMdZe.js} +1 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-XODf2seK.js +1 -0
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-XODf2seK.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-BV8ttTSE.js → cose-bilkent-JH36ORCC-TcTcCWyr.js} +1 -1
- package/web/dist/assets/{cynefin-VYW2F7L2-BncvlU8s.js → cynefin-VYW2F7L2-D6vfZhRU.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-DrrKaXmw.js → cynefinDiagram-TSTJHNR4-BQ_p-vVW.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-BxDsa977.js → dagre-VKFMJZFB-sC49sUfv.js} +1 -1
- package/web/dist/assets/{diagram-FQU43EPY-DkeAFpQM.js → diagram-FQU43EPY-znBmjqaC.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-BxVnT5Li.js → diagram-G47NLZAW-BFZHUq5q.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-BT56mGuK.js → diagram-NH7WQ7WH-CnF3KhFt.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-CezybdJA.js → diagram-OA4YK3LP-DyxQbSTl.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-CO8JNWNf.js → diagram-WEI45ONY-u45fnoLo.js} +1 -1
- package/web/dist/assets/{dist-zlHGdC4Y.js → dist-DeM6hNwF.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-B-OkdWz4.js → ebnfDiagram-CCIWWBDH-CRWFKre6.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-DQNn2L0y.js → erDiagram-Q63AITRT-BWW0EF63.js} +1 -1
- package/web/dist/assets/eventmodeling-45OFAUF4-C8O_2_YB.js +1 -0
- package/web/dist/assets/flowDiagram-23GEKE2U-ADg31f6W.js +1 -0
- package/web/dist/assets/{ganttDiagram-NO4QXBWP-CFmDEUpW.js → ganttDiagram-NO4QXBWP-Cs24RF6t.js} +2 -2
- package/web/dist/assets/{gitGraph-TEB2WS4Q-BiEBwxQy.js → gitGraph-TEB2WS4Q-CWN94LWl.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-IHSO6WYX--62v4OfD.js → gitGraphDiagram-IHSO6WYX-B_EZLwDH.js} +1 -1
- package/web/dist/assets/index-C58B02oD.css +1 -0
- package/web/dist/assets/index-Cf-76g9P.js +420 -0
- package/web/dist/assets/{info-DKCQHKI2-BLKxCcH7.js → info-DKCQHKI2-_3TeAGLT.js} +1 -1
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-DM429PMt.js → infoDiagram-FWYZ7A6U-C2mnh_tb.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-D-nr9wXb.js → ishikawaDiagram-FXEZZL3T-B_eQA-ns.js} +1 -1
- package/web/dist/assets/{journeyDiagram-5HDEW3XC-CsPvawEB.js → journeyDiagram-5HDEW3XC-pWgngszB.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-Cq6fbJBF.js → kanban-definition-HUTT4EX6-ov2PISLL.js} +1 -1
- package/web/dist/assets/{line-CE9BvxIa.js → line-DdBTKf-T.js} +1 -1
- package/web/dist/assets/linear-BcjVZ8a_.js +1 -0
- package/web/dist/assets/{mermaid-parser.core-CAAH_OSq.js → mermaid-parser.core-CICKlqAN.js} +3 -3
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-zZ5w-lPU.js → mindmap-definition-LN4V7U3C-0NmEERgv.js} +1 -1
- package/web/dist/assets/{packet-7NZHBO7P-ap_XD9pB.js → packet-7NZHBO7P-TpNRNd61.js} +1 -1
- package/web/dist/assets/{pegDiagram-2B236MQR-BL13lL1j.js → pegDiagram-2B236MQR-CiAlAiVi.js} +1 -1
- package/web/dist/assets/{pie-RZYD4A2V-C7RWGzoe.js → pie-RZYD4A2V-x4UQuGC2.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-B1mmu34A.js → pieDiagram-ENE6RG2P-inbfmWLn.js} +1 -1
- package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-CotpR7ZY.js → quadrantDiagram-ABIIQ3AL-BG-L4IlR.js} +1 -1
- package/web/dist/assets/{radar-I7S5WNFK-D8ICPnt1.js → radar-I7S5WNFK-ifrr9rf8.js} +1 -1
- package/web/dist/assets/{railroad-3IZDKUUU-B7ZJ3IRr.js → railroad-3IZDKUUU-3WK9FStR.js} +1 -1
- package/web/dist/assets/railroad-abnf-AHOZXSZD-DI7lfwbp.js +1 -0
- package/web/dist/assets/railroad-ebnf-EBAXGLYW-COZaOyR2.js +1 -0
- package/web/dist/assets/railroad-peg-LSFZ7HO6-BE8vI_mk.js +1 -0
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-BUbf08v3.js → railroadDiagram-RFXS5EU6-zGdHxvjI.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-CgepHMpy.js → requirementDiagram-TGXJPOKE-DYBqltr1.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-HTMAVEWB-9CV0aY5J.js → sankeyDiagram-HTMAVEWB-Cwthl6yk.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-CkIJuJ5O.js → sequenceDiagram-DBY2YBRQ-yoZvzY4D.js} +1 -1
- package/web/dist/assets/src-Bp5IDfvJ.js +1 -0
- package/web/dist/assets/{stateDiagram-2N3HPSRC-wX6zU3Hv.js → stateDiagram-2N3HPSRC-UXu_N6p7.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-K2x-LOU8.js +1 -0
- package/web/dist/assets/{swimlanes-5IMT3BWC-YXgGP77C.js → swimlanes-5IMT3BWC-CJml4vNZ.js} +1 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-BJTq-tR6.js +8 -0
- package/web/dist/assets/{timeline-definition-FHXFAJF6-CtMf684d.js → timeline-definition-FHXFAJF6-DmHx8Bri.js} +1 -1
- package/web/dist/assets/{treeView-QDETBFTQ-lUySd_Pd.js → treeView-QDETBFTQ-CW1zfcRK.js} +1 -1
- package/web/dist/assets/{treemap-6X3UGDF4-BewRw9PG.js → treemap-6X3UGDF4-ReFheQXq.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-DbFoFgBM.js → vennDiagram-L72KCM5P-jIe_jCw3.js} +1 -1
- package/web/dist/assets/{wardley-OPB4EBWU-BCrrgDHP.js → wardley-OPB4EBWU-DqwQFz9-.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-C3J4of-x.js → wardleyDiagram-EHGQE667-DEJFp47s.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-Fbzeb84K.js → xychartDiagram-FW5EYKEG-DBBG2OXr.js} +1 -1
- package/web/dist/index.html +12 -12
- package/web/dist/assets/architecture-TIHT7OUA-Bgyz4pDY.js +0 -1
- package/web/dist/assets/channel-vHKEEV51.js +0 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-Blusw6t4.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-Blusw6t4.js +0 -1
- package/web/dist/assets/eventmodeling-45OFAUF4-CA5_fuzk.js +0 -1
- package/web/dist/assets/flowDiagram-23GEKE2U-CPO1BGjg.js +0 -1
- package/web/dist/assets/index-BUs4sN1r.css +0 -1
- package/web/dist/assets/index-HsPwY2CU.js +0 -414
- package/web/dist/assets/linear-B8yeZliB.js +0 -1
- package/web/dist/assets/railroad-abnf-AHOZXSZD-uSXjMlP2.js +0 -1
- package/web/dist/assets/railroad-ebnf-EBAXGLYW-9im8bOEZ.js +0 -1
- package/web/dist/assets/railroad-peg-LSFZ7HO6-62Yk_rP2.js +0 -1
- package/web/dist/assets/src-W4W9ly-y.js +0 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-CAdDNary.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV--Ha4WrTi.js +0 -8
package/dist/cli.mjs
CHANGED
|
@@ -66,6 +66,7 @@ var init_config = __esm({
|
|
|
66
66
|
moduleMapping: {},
|
|
67
67
|
feedbackHalfLifeDays: 15,
|
|
68
68
|
gates: { approvalMode: "warn", writeGate: "observe" },
|
|
69
|
+
taskPreconditions: [{ role: "qa", type: "qa", requiresSiblingRoleCompleted: "developer" }],
|
|
69
70
|
git: { taskTrailer: "off", trailerKey: "Task" },
|
|
70
71
|
legacyDb: "tasks/task.db",
|
|
71
72
|
dataDir: ".workbench",
|
|
@@ -279,7 +280,14 @@ CREATE INDEX IF NOT EXISTS idx_events_event ON events(event);
|
|
|
279
280
|
}
|
|
280
281
|
},
|
|
281
282
|
// 迁移 3:claim 时记录 git HEAD,供 hotfix 契约触碰检测与 trailer 交叉验证
|
|
282
|
-
{ version: 3, up: (db) => db.exec("ALTER TABLE tasks ADD COLUMN claim_commit TEXT") }
|
|
283
|
+
{ version: 3, up: (db) => db.exec("ALTER TABLE tasks ADD COLUMN claim_commit TEXT") },
|
|
284
|
+
// 迁移 4:边来源(derived=scan 按 parents×坐标推导,对账维护;manual=用户手动声明,可解绑、scan 永不动)
|
|
285
|
+
{
|
|
286
|
+
version: 4,
|
|
287
|
+
up: (db) => db.exec(
|
|
288
|
+
"ALTER TABLE artifact_edges ADD COLUMN source TEXT NOT NULL DEFAULT 'derived' CHECK (source IN ('derived','manual'))"
|
|
289
|
+
)
|
|
290
|
+
}
|
|
283
291
|
];
|
|
284
292
|
CURRENT_SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
|
|
285
293
|
}
|
|
@@ -402,6 +410,13 @@ var init_events = __esm({
|
|
|
402
410
|
});
|
|
403
411
|
|
|
404
412
|
// core/platforms.ts
|
|
413
|
+
var platforms_exports = {};
|
|
414
|
+
__export(platforms_exports, {
|
|
415
|
+
PLATFORM_IDS: () => PLATFORM_IDS,
|
|
416
|
+
getAdapter: () => getAdapter,
|
|
417
|
+
resolveModel: () => resolveModel,
|
|
418
|
+
resolvePlatforms: () => resolvePlatforms
|
|
419
|
+
});
|
|
405
420
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync } from "node:fs";
|
|
406
421
|
import { dirname as dirname2, join as join4 } from "node:path";
|
|
407
422
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
@@ -493,6 +508,12 @@ var init_platforms = __esm({
|
|
|
493
508
|
hooksScanDir: ".claude/hooks",
|
|
494
509
|
defaultModel: "opus",
|
|
495
510
|
memoryBlock: (role, lang) => claudeMemory(role, lang),
|
|
511
|
+
projectDirEnvVar: "CLAUDE_PROJECT_DIR",
|
|
512
|
+
parseHookInput: (raw) => ({
|
|
513
|
+
filePath: raw?.tool_input?.file_path ?? raw?.tool_input?.filePath
|
|
514
|
+
}),
|
|
515
|
+
respondBlocked: (msg) => ({ exitCode: 2, stderr: msg }),
|
|
516
|
+
formatModel: (_providerId, modelId) => modelId,
|
|
496
517
|
notes: [],
|
|
497
518
|
agentFile: (role) => `${role}.md`,
|
|
498
519
|
renderAgent: (spec) => yamlFrontmatter(
|
|
@@ -536,6 +557,12 @@ var init_platforms = __esm({
|
|
|
536
557
|
hooksScanDir: null,
|
|
537
558
|
defaultModel: "gpt-5.1-codex",
|
|
538
559
|
memoryBlock: (_role, lang) => agentsMdMemory("Codex", lang),
|
|
560
|
+
projectDirEnvVar: "CODEX_PROJECT_DIR",
|
|
561
|
+
parseHookInput: (raw) => ({
|
|
562
|
+
filePath: raw?.arguments?.file_path ?? raw?.arguments?.filePath
|
|
563
|
+
}),
|
|
564
|
+
respondBlocked: (msg) => ({ exitCode: 2, stderr: msg }),
|
|
565
|
+
formatModel: (_providerId, modelId) => modelId,
|
|
539
566
|
notes: [
|
|
540
567
|
'Codex:\u9879\u76EE\u7EA7 .codex/* \u4EC5\u5F53\u9879\u76EE\u88AB\u6807\u8BB0 trusted \u624D\u52A0\u8F7D \u2014\u2014 \u5728 ~/.codex/config.toml \u91CC\u4E3A\u672C\u9879\u76EE\u8BBE trust_level="trusted"',
|
|
541
568
|
"Codex:skill \u8D70 .agents/skills/(\u975E .codex/skills)"
|
|
@@ -576,6 +603,12 @@ var init_platforms = __esm({
|
|
|
576
603
|
hooksScanDir: null,
|
|
577
604
|
defaultModel: "anthropic/claude-opus-4-8",
|
|
578
605
|
memoryBlock: (_role, lang) => agentsMdMemory("OpenCode", lang),
|
|
606
|
+
projectDirEnvVar: "OPENCODE_PROJECT_DIR",
|
|
607
|
+
parseHookInput: (raw) => ({
|
|
608
|
+
filePath: raw?.args?.file_path ?? raw?.args?.filePath
|
|
609
|
+
}),
|
|
610
|
+
respondBlocked: (msg) => ({ exitCode: 2, stderr: msg }),
|
|
611
|
+
formatModel: (providerId, modelId) => `${providerId}/${modelId}`,
|
|
579
612
|
notes: [
|
|
580
613
|
"OpenCode:\u6A21\u578B\u4E32\u662F provider/model \u683C\u5F0F(\u89C1 models.dev);API key \u5EFA\u8BAE\u8D70\u73AF\u5883\u53D8\u91CF\u6216 {env:...}"
|
|
581
614
|
],
|
|
@@ -644,6 +677,15 @@ export const opcflow = async () => ({
|
|
|
644
677
|
hooksScanDir: null,
|
|
645
678
|
defaultModel: "claude-opus-4-8",
|
|
646
679
|
memoryBlock: (_role, lang) => cursorMemory(lang),
|
|
680
|
+
projectDirEnvVar: "CURSOR_PROJECT_DIR",
|
|
681
|
+
parseHookInput: (raw) => ({
|
|
682
|
+
filePath: raw?.file_path ?? raw?.filePath
|
|
683
|
+
}),
|
|
684
|
+
respondBlocked: (msg) => ({
|
|
685
|
+
exitCode: 0,
|
|
686
|
+
stdout: JSON.stringify({ permission: "deny", userMessage: msg, agentMessage: msg })
|
|
687
|
+
}),
|
|
688
|
+
formatModel: (_providerId, modelId) => modelId,
|
|
647
689
|
notes: [
|
|
648
690
|
"Cursor:\u4E3B agent \u6A21\u578B\u7531 UI \u9009,--model \u53EA\u4F5C\u7528\u4E8E\u751F\u6210\u7684 subagent(.cursor/agents/*.md)"
|
|
649
691
|
],
|
|
@@ -985,20 +1027,27 @@ function requirementSatisfied(ctx, req, matched) {
|
|
|
985
1027
|
(a) => kindSpec(ctx.config, a.kind).approval === "thumbs" ? prototypeEndorsed(ctx.db, a) : reviewStatus(a) === "approved"
|
|
986
1028
|
);
|
|
987
1029
|
}
|
|
988
|
-
function
|
|
989
|
-
const
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
const dev = ctx.db.prepare(
|
|
1030
|
+
function siblingRoleBlocking(ctx, task) {
|
|
1031
|
+
for (const rule of ctx.config.taskPreconditions ?? []) {
|
|
1032
|
+
if (rule.role !== task.role) continue;
|
|
1033
|
+
if (rule.type && rule.type !== task.type) continue;
|
|
1034
|
+
const done = ctx.db.prepare(
|
|
994
1035
|
`SELECT COUNT(*) AS c FROM tasks
|
|
995
|
-
WHERE role =
|
|
1036
|
+
WHERE role = ? AND status = 'completed' AND module IS ? AND endpoint IS ?
|
|
996
1037
|
AND (? IS NULL OR page IS ?)`
|
|
997
|
-
).get(task.module, task.endpoint, task.page, task.page);
|
|
998
|
-
if (
|
|
999
|
-
|
|
1038
|
+
).get(rule.requiresSiblingRoleCompleted, task.module, task.endpoint, task.page, task.page);
|
|
1039
|
+
if (done.c === 0) {
|
|
1040
|
+
return `\u5BF9\u5E94\u7684 ${rule.requiresSiblingRoleCompleted} ${task.endpoint ?? ""} \u4EFB\u52A1\u5C1A\u672A\u5B8C\u6210,\u65E0\u6CD5\u9886\u53D6 ${task.role} \u4EFB\u52A1\u3002`;
|
|
1000
1041
|
}
|
|
1001
1042
|
}
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
function validateClaim(ctx, task) {
|
|
1046
|
+
const warnings = [];
|
|
1047
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
1048
|
+
const mode = ctx.config.gates.approvalMode;
|
|
1049
|
+
const blockMsg = siblingRoleBlocking(ctx, task);
|
|
1050
|
+
if (blockMsg) throw new Error(`[\u524D\u7F6E\u6761\u4EF6] ${blockMsg}`);
|
|
1002
1051
|
if (task.module && (task.type === "build" || task.type === "hotfix") && !moduleCleared(ctx.db, task.module)) {
|
|
1003
1052
|
warnings.push(
|
|
1004
1053
|
`[\u6E05\u7B97] \u6A21\u5757 ${task.module} \u672A\u6E05\u7B97(module-prd \u672A\u5BA1\u6279)\u3002\u5EFA\u8BAE\u5148\u5BF9\u8D26:${ctx.config.cli} audit --module=${task.module}`
|
|
@@ -1061,19 +1110,18 @@ function validateComplete(ctx, task, status, opts = {}) {
|
|
|
1061
1110
|
warnings.push(msg);
|
|
1062
1111
|
}
|
|
1063
1112
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
const detail = violations.slice(0, 10).map((v) => ` ${v.file}:${v.line} [${v.lint}] ${v.message}
|
|
1113
|
+
const violations = runProtocolLints(ctx, { role: task.role, endpoint: task.endpoint });
|
|
1114
|
+
if (violations.length > 0) {
|
|
1115
|
+
const detail = violations.slice(0, 10).map((v) => ` ${v.file}:${v.line} [${v.lint}] ${v.message}
|
|
1068
1116
|
${v.text}`).join("\n");
|
|
1069
|
-
|
|
1070
|
-
|
|
1117
|
+
throw new Error(
|
|
1118
|
+
`[\u534F\u8BAE lint \u5931\u8D25] ${violations.length} \u5904\u8FDD\u4F8B,\u4FEE\u590D\u540E\u518D\u5B8C\u6210:
|
|
1071
1119
|
${detail}${violations.length > 10 ? `
|
|
1072
1120
|
...\u7B49 ${violations.length} \u5904` : ""}`
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1121
|
+
);
|
|
1075
1122
|
}
|
|
1076
|
-
|
|
1123
|
+
const producesMachineKind = producedKinds(ctx, task).some((k) => kindSpec(ctx.config, k).approval === "machine");
|
|
1124
|
+
if (producesMachineKind && task.endpoint && ctx.config.machineChecks.enabled) {
|
|
1077
1125
|
const cmds = ctx.config.machineChecks[task.endpoint];
|
|
1078
1126
|
if (Array.isArray(cmds)) {
|
|
1079
1127
|
for (const cmd of cmds) {
|
|
@@ -1118,7 +1166,7 @@ function taskBlocked(ctx, task) {
|
|
|
1118
1166
|
validateClaim(ctx, task);
|
|
1119
1167
|
return false;
|
|
1120
1168
|
} catch (err) {
|
|
1121
|
-
return err instanceof Error && err.message.includes("\
|
|
1169
|
+
return err instanceof Error && err.message.includes("[\u524D\u7F6E\u6761\u4EF6]");
|
|
1122
1170
|
}
|
|
1123
1171
|
}
|
|
1124
1172
|
function coordHealth(ctx, artifacts, tasks) {
|
|
@@ -1199,6 +1247,7 @@ function buildTree(ctx, opts = {}) {
|
|
|
1199
1247
|
eTasks.filter((t) => !t.page)
|
|
1200
1248
|
);
|
|
1201
1249
|
for (const child of pageNodes) health2 = worse(health2, child.health);
|
|
1250
|
+
if (coordFailed(ctx, module, endpoint, null)) health2 = "failed";
|
|
1202
1251
|
return {
|
|
1203
1252
|
key: `${module}/${endpoint}`,
|
|
1204
1253
|
title: endpoint,
|
|
@@ -1747,16 +1796,16 @@ function ownerRole(ctx, kind) {
|
|
|
1747
1796
|
if (kind === "code") return "developer";
|
|
1748
1797
|
return null;
|
|
1749
1798
|
}
|
|
1750
|
-
function
|
|
1751
|
-
const
|
|
1752
|
-
`SELECT
|
|
1799
|
+
function openReviewTargetKeys(ctx, artifactId) {
|
|
1800
|
+
const rows = ctx.db.prepare(
|
|
1801
|
+
`SELECT t.role, t.endpoint, t.module FROM tasks t
|
|
1753
1802
|
JOIN task_inputs ti ON ti.task_id = t.id
|
|
1754
1803
|
WHERE t.type = 'review' AND t.status IN ('pending', 'in_progress') AND ti.artifact_id = ?`
|
|
1755
|
-
).
|
|
1756
|
-
return
|
|
1804
|
+
).all(artifactId);
|
|
1805
|
+
return new Set(rows.map((r) => `${r.role}|${r.endpoint ?? ""}|${r.module ?? ""}`));
|
|
1757
1806
|
}
|
|
1758
1807
|
function spawnReviews(ctx, source, reason) {
|
|
1759
|
-
|
|
1808
|
+
const openKeys = openReviewTargetKeys(ctx, source.id);
|
|
1760
1809
|
const registry = getKindRegistry(ctx.config);
|
|
1761
1810
|
const downstream = ctx.db.prepare(`SELECT a.* FROM artifacts a JOIN artifact_edges e ON e.to_id = a.id WHERE e.from_id = ?`).all(source.id);
|
|
1762
1811
|
const targets = /* @__PURE__ */ new Map();
|
|
@@ -1765,6 +1814,7 @@ function spawnReviews(ctx, source, reason) {
|
|
|
1765
1814
|
const role = ownerRole(ctx, child.kind);
|
|
1766
1815
|
if (!role) continue;
|
|
1767
1816
|
const key = `${role}|${child.endpoint ?? ""}|${child.module ?? source.module ?? ""}`;
|
|
1817
|
+
if (openKeys.has(key)) continue;
|
|
1768
1818
|
targets.set(key, { role, endpoint: child.endpoint, module: child.module ?? source.module });
|
|
1769
1819
|
}
|
|
1770
1820
|
let spawned = 0;
|
|
@@ -1962,6 +2012,7 @@ function updateTask(ctx, { id, status, operator, force = false }) {
|
|
|
1962
2012
|
throw new Error(`\u53EA\u6709\u6267\u884C\u4EBA\u624D\u80FD\u66F4\u65B0\u4EFB\u52A1\u72B6\u6001`);
|
|
1963
2013
|
}
|
|
1964
2014
|
const { warnings } = validateComplete(ctx, task, status, { force });
|
|
2015
|
+
let followupQaId = null;
|
|
1965
2016
|
const tx = ctx.db.transaction(() => {
|
|
1966
2017
|
ctx.db.prepare("UPDATE tasks SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(status, id);
|
|
1967
2018
|
logEvent(ctx.db, {
|
|
@@ -1974,15 +2025,15 @@ function updateTask(ctx, { id, status, operator, force = false }) {
|
|
|
1974
2025
|
endpoint: task.endpoint,
|
|
1975
2026
|
page: task.page
|
|
1976
2027
|
});
|
|
2028
|
+
if (task.type === "rework" && status === "completed") {
|
|
2029
|
+
followupQaId = spawnFollowupQa(ctx, task);
|
|
2030
|
+
}
|
|
1977
2031
|
});
|
|
1978
2032
|
tx();
|
|
2033
|
+
if (followupQaId !== null) warnings.push(`[\u590D\u9A8C] \u5DF2\u81EA\u52A8\u6D3E\u65B0\u4E00\u8F6E qa \u4EFB\u52A1 #${followupQaId}`);
|
|
1979
2034
|
if (task.type === "hotfix" && status === "completed") {
|
|
1980
2035
|
warnings.push(...checkContractTouch(ctx, task, operator));
|
|
1981
2036
|
}
|
|
1982
|
-
if (task.type === "rework" && status === "completed") {
|
|
1983
|
-
const qaId = spawnFollowupQa(ctx, task);
|
|
1984
|
-
warnings.push(`[\u590D\u9A8C] \u5DF2\u81EA\u52A8\u6D3E\u65B0\u4E00\u8F6E qa \u4EFB\u52A1 #${qaId}`);
|
|
1985
|
-
}
|
|
1986
2037
|
if (status === "completed" && task.external_ref?.startsWith("gh#")) {
|
|
1987
2038
|
const closed = closeLinkedIssue(ctx, task.external_ref, task.id);
|
|
1988
2039
|
warnings.push(closed ? `[issue] \u5DF2\u5173\u95ED ${task.external_ref}` : `[issue] ${task.external_ref} \u5173\u95ED\u5931\u8D25(gh \u4E0D\u53EF\u7528),\u8BF7\u624B\u52A8\u5904\u7406`);
|
|
@@ -2512,30 +2563,42 @@ function deriveEdges(ctx) {
|
|
|
2512
2563
|
list.push(a);
|
|
2513
2564
|
byKind.set(a.kind, list);
|
|
2514
2565
|
}
|
|
2515
|
-
const
|
|
2566
|
+
const expected = /* @__PURE__ */ new Set();
|
|
2567
|
+
for (const child of nonMeta) {
|
|
2568
|
+
const parents = registry[child.kind]?.parents ?? [];
|
|
2569
|
+
for (const parentKind of parents) {
|
|
2570
|
+
const level = registry[parentKind]?.level ?? "module";
|
|
2571
|
+
const candidates = (byKind.get(parentKind) ?? []).filter((p) => {
|
|
2572
|
+
if ((level === "module" || level === "page") && child.module && p.module !== child.module) return false;
|
|
2573
|
+
if ((level === "endpoint" || level === "page") && child.endpoint && p.endpoint !== child.endpoint) return false;
|
|
2574
|
+
if (level === "page" && child.page && p.page !== child.page) return false;
|
|
2575
|
+
return true;
|
|
2576
|
+
});
|
|
2577
|
+
for (const parent of candidates) expected.add(`${parent.id}|${child.id}`);
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
const existing = ctx.db.prepare("SELECT id, from_id, to_id, source FROM artifact_edges").all();
|
|
2581
|
+
const have = new Set(existing.map((e) => `${e.from_id}|${e.to_id}`));
|
|
2582
|
+
const insert = ctx.db.prepare("INSERT OR IGNORE INTO artifact_edges (from_id, to_id, source) VALUES (?, ?, 'derived')");
|
|
2583
|
+
const del = ctx.db.prepare("DELETE FROM artifact_edges WHERE id = ?");
|
|
2516
2584
|
let created = 0;
|
|
2585
|
+
let pruned = 0;
|
|
2517
2586
|
const tx = ctx.db.transaction(() => {
|
|
2518
|
-
for (const
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
return true;
|
|
2527
|
-
});
|
|
2528
|
-
for (const parent of candidates) {
|
|
2529
|
-
created += insert.run(parent.id, child.id).changes;
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2587
|
+
for (const key of expected) {
|
|
2588
|
+
if (have.has(key)) continue;
|
|
2589
|
+
const [from, to] = key.split("|");
|
|
2590
|
+
created += insert.run(Number(from), Number(to)).changes;
|
|
2591
|
+
}
|
|
2592
|
+
for (const e of existing) {
|
|
2593
|
+
if (e.source !== "derived") continue;
|
|
2594
|
+
if (!expected.has(`${e.from_id}|${e.to_id}`)) pruned += del.run(e.id).changes;
|
|
2532
2595
|
}
|
|
2533
2596
|
});
|
|
2534
2597
|
tx();
|
|
2535
|
-
return created;
|
|
2598
|
+
return { created, pruned };
|
|
2536
2599
|
}
|
|
2537
2600
|
function scanArtifacts(ctx, actor = "system") {
|
|
2538
|
-
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, skipped: [], unresolved: [] };
|
|
2601
|
+
const summary = { registered: 0, refreshed: 0, remapped: 0, edges: 0, edgesPruned: 0, moved: 0, skipped: [], unresolved: [] };
|
|
2539
2602
|
const files = [];
|
|
2540
2603
|
for (const dir of Object.values(ctx.config.docs)) {
|
|
2541
2604
|
const abs = join10(ctx.root, dir);
|
|
@@ -2588,6 +2651,26 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2588
2651
|
}
|
|
2589
2652
|
const hash = hashPath(join10(ctx.root, relPath));
|
|
2590
2653
|
if (hash === null) return;
|
|
2654
|
+
const movedFrom = ctx.db.prepare("SELECT * FROM artifacts WHERE content_hash = ? AND kind = ?").all(hash, kind).filter((a) => !existsSync9(join10(ctx.root, a.path)));
|
|
2655
|
+
if (movedFrom.length === 1) {
|
|
2656
|
+
const old = movedFrom[0];
|
|
2657
|
+
const tx2 = ctx.db.transaction(() => {
|
|
2658
|
+
ctx.db.prepare("UPDATE artifacts SET path = ?, module = ?, endpoint = ?, page = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(relPath, coords.module, coords.endpoint, coords.page, old.id);
|
|
2659
|
+
logEvent(ctx.db, {
|
|
2660
|
+
entityType: "artifact",
|
|
2661
|
+
entityId: old.id,
|
|
2662
|
+
event: "auto_moved",
|
|
2663
|
+
actor,
|
|
2664
|
+
payload: { from: old.path, to: relPath },
|
|
2665
|
+
module: coords.module,
|
|
2666
|
+
endpoint: coords.endpoint,
|
|
2667
|
+
page: coords.page
|
|
2668
|
+
});
|
|
2669
|
+
});
|
|
2670
|
+
tx2();
|
|
2671
|
+
summary.moved++;
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2591
2674
|
const tx = ctx.db.transaction(() => {
|
|
2592
2675
|
const result = insert.run(kind, coords.module, coords.endpoint, coords.page, relPath, hash);
|
|
2593
2676
|
logEvent(ctx.db, {
|
|
@@ -2615,9 +2698,35 @@ function scanArtifacts(ctx, actor = "system") {
|
|
|
2615
2698
|
for (const code of expandCodeRoots(ctx)) {
|
|
2616
2699
|
registerOne(code.dir, "code", { module: code.module, endpoint: code.endpoint, page: null });
|
|
2617
2700
|
}
|
|
2618
|
-
|
|
2701
|
+
const edgeResult = deriveEdges(ctx);
|
|
2702
|
+
summary.edges = edgeResult.created;
|
|
2703
|
+
summary.edgesPruned = edgeResult.pruned;
|
|
2619
2704
|
return summary;
|
|
2620
2705
|
}
|
|
2706
|
+
function registerAdHocArtifact(ctx, relPathRaw, actor) {
|
|
2707
|
+
const relPath = normalizeRelPath(ctx, relPathRaw);
|
|
2708
|
+
const existing = ctx.db.prepare("SELECT * FROM artifacts WHERE path = ?").get(relPath);
|
|
2709
|
+
if (existing) return existing;
|
|
2710
|
+
const hash = hashPath(join10(ctx.root, relPath));
|
|
2711
|
+
if (hash === null) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${relPath}`);
|
|
2712
|
+
const kind = inferKind(relPath, ctx.config);
|
|
2713
|
+
const coords = parseCoords(ctx, kind, relPath) ?? { module: null, endpoint: null, page: null };
|
|
2714
|
+
const tx = ctx.db.transaction(() => {
|
|
2715
|
+
const r = ctx.db.prepare("INSERT INTO artifacts (kind, module, endpoint, page, path, content_hash) VALUES (?, ?, ?, ?, ?, ?)").run(kind, coords.module, coords.endpoint, coords.page, relPath, hash);
|
|
2716
|
+
logEvent(ctx.db, {
|
|
2717
|
+
entityType: "artifact",
|
|
2718
|
+
entityId: r.lastInsertRowid,
|
|
2719
|
+
event: "scan_registered",
|
|
2720
|
+
actor,
|
|
2721
|
+
payload: { path: relPath, kind, adHoc: true },
|
|
2722
|
+
module: coords.module,
|
|
2723
|
+
endpoint: coords.endpoint,
|
|
2724
|
+
page: coords.page
|
|
2725
|
+
});
|
|
2726
|
+
});
|
|
2727
|
+
tx();
|
|
2728
|
+
return ctx.db.prepare("SELECT * FROM artifacts WHERE path = ?").get(relPath);
|
|
2729
|
+
}
|
|
2621
2730
|
var stripExt;
|
|
2622
2731
|
var init_scan_command = __esm({
|
|
2623
2732
|
"core/commands/scan.command.ts"() {
|
|
@@ -2873,6 +2982,8 @@ var init_retro_command = __esm({
|
|
|
2873
2982
|
});
|
|
2874
2983
|
|
|
2875
2984
|
// core/commands/plan.command.ts
|
|
2985
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
2986
|
+
import { join as join12 } from "node:path";
|
|
2876
2987
|
function planModule(ctx, moduleRaw, creator = "product-manager") {
|
|
2877
2988
|
const module = normalizeModule(moduleRaw, ctx.config);
|
|
2878
2989
|
const summary = { created: [], skipped: 0, cancelled: 0, warnings: [] };
|
|
@@ -2896,7 +3007,7 @@ function planModule(ctx, moduleRaw, creator = "product-manager") {
|
|
|
2896
3007
|
if (ctx.config.gates.approvalMode === "enforce") throw new Error(`[\u524D\u7F6E\u6761\u4EF6] ${msg}`);
|
|
2897
3008
|
summary.warnings.push(msg);
|
|
2898
3009
|
}
|
|
2899
|
-
const pagePrds = byKind("page-prd").filter((a) => a.endpoint && a.page);
|
|
3010
|
+
const pagePrds = byKind("page-prd").filter((a) => a.endpoint && a.page && existsSync10(join12(ctx.root, a.path)));
|
|
2900
3011
|
const endpoints = [...new Set(pagePrds.map((a) => a.endpoint))];
|
|
2901
3012
|
const desired = [
|
|
2902
3013
|
{ role: "architect", endpoint: "common", page: null, type: "build", assignee: "architect", content: `\u8BBE\u8BA1 ${module} \u6A21\u5757\u6570\u636E\u5E93` },
|
|
@@ -2976,11 +3087,11 @@ var init_plan_command = __esm({
|
|
|
2976
3087
|
});
|
|
2977
3088
|
|
|
2978
3089
|
// core/commands/install-hooks.command.ts
|
|
2979
|
-
import { chmodSync, existsSync as
|
|
2980
|
-
import { join as
|
|
3090
|
+
import { chmodSync, existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3091
|
+
import { join as join13 } from "node:path";
|
|
2981
3092
|
function installGitHooks(ctx) {
|
|
2982
|
-
const hooksDir =
|
|
2983
|
-
if (!
|
|
3093
|
+
const hooksDir = join13(ctx.root, ".git", "hooks");
|
|
3094
|
+
if (!existsSync11(join13(ctx.root, ".git"))) throw new Error("\u4E0D\u662F git \u4ED3\u5E93");
|
|
2984
3095
|
mkdirSync5(hooksDir, { recursive: true });
|
|
2985
3096
|
const installed = [];
|
|
2986
3097
|
const postCommit = `#!/bin/sh
|
|
@@ -2988,9 +3099,9 @@ function installGitHooks(ctx) {
|
|
|
2988
3099
|
${WORKBENCH_BIN} postcommit >/dev/null 2>&1 &
|
|
2989
3100
|
exit 0
|
|
2990
3101
|
`;
|
|
2991
|
-
writeFileSync4(
|
|
3102
|
+
writeFileSync4(join13(hooksDir, "post-commit"), postCommit);
|
|
2992
3103
|
try {
|
|
2993
|
-
chmodSync(
|
|
3104
|
+
chmodSync(join13(hooksDir, "post-commit"), 493);
|
|
2994
3105
|
} catch {
|
|
2995
3106
|
}
|
|
2996
3107
|
installed.push("post-commit(sync \u5BF9\u8D26)");
|
|
@@ -3004,9 +3115,9 @@ if [ -n "$WORKBENCH_TASK_ID" ] && [ "$2" != "merge" ]; then
|
|
|
3004
3115
|
fi
|
|
3005
3116
|
exit 0
|
|
3006
3117
|
`;
|
|
3007
|
-
writeFileSync4(
|
|
3118
|
+
writeFileSync4(join13(hooksDir, "prepare-commit-msg"), prepare);
|
|
3008
3119
|
try {
|
|
3009
|
-
chmodSync(
|
|
3120
|
+
chmodSync(join13(hooksDir, "prepare-commit-msg"), 493);
|
|
3010
3121
|
} catch {
|
|
3011
3122
|
}
|
|
3012
3123
|
installed.push(`prepare-commit-msg(${ctx.config.git.trailerKey} trailer \u6CE8\u5165)`);
|
|
@@ -3021,8 +3132,8 @@ var init_install_hooks_command = __esm({
|
|
|
3021
3132
|
});
|
|
3022
3133
|
|
|
3023
3134
|
// core/commands/gen-agents.command.ts
|
|
3024
|
-
import { existsSync as
|
|
3025
|
-
import { dirname as dirname3, join as
|
|
3135
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3136
|
+
import { dirname as dirname3, join as join14 } from "node:path";
|
|
3026
3137
|
function expandPath(ctx, kind) {
|
|
3027
3138
|
const spec = getKindRegistry(ctx.config)[kind];
|
|
3028
3139
|
const raw = spec?.pathPatterns?.[0] ?? "";
|
|
@@ -3048,8 +3159,8 @@ function parseTemplate(rawInput) {
|
|
|
3048
3159
|
function genAgents(ctx, templatesDir) {
|
|
3049
3160
|
const lang = ctx.config.language;
|
|
3050
3161
|
const blocks = SHARED[lang] ?? SHARED.zh;
|
|
3051
|
-
const dir = templatesDir ??
|
|
3052
|
-
if (!
|
|
3162
|
+
const dir = templatesDir ?? join14(WORKBENCH_DIR, "templates/agents", lang);
|
|
3163
|
+
if (!existsSync12(dir)) throw new Error(`\u6A21\u677F\u76EE\u5F55\u4E0D\u5B58\u5728: ${dir}`);
|
|
3053
3164
|
const cli = ctx.config.cli;
|
|
3054
3165
|
const baseTokens = {
|
|
3055
3166
|
CLI: cli,
|
|
@@ -3086,7 +3197,7 @@ function genAgents(ctx, templatesDir) {
|
|
|
3086
3197
|
if (!file.endsWith(".md")) continue;
|
|
3087
3198
|
const role = file.replace(/\.md$/, "");
|
|
3088
3199
|
if (!pipeline.has(role)) continue;
|
|
3089
|
-
const tpl = parseTemplate(readFileSync6(
|
|
3200
|
+
const tpl = parseTemplate(readFileSync6(join14(dir, file), "utf-8"));
|
|
3090
3201
|
for (const adapter of adapters) {
|
|
3091
3202
|
const memory = adapter.memoryBlock(role, lang);
|
|
3092
3203
|
const spec = {
|
|
@@ -3097,7 +3208,7 @@ function genAgents(ctx, templatesDir) {
|
|
|
3097
3208
|
body: renderTokens(tpl.body, memory)
|
|
3098
3209
|
};
|
|
3099
3210
|
const rel = `${adapter.agentsDir}/${adapter.agentFile(role)}`;
|
|
3100
|
-
const abs =
|
|
3211
|
+
const abs = join14(ctx.root, rel);
|
|
3101
3212
|
mkdirSync6(dirname3(abs), { recursive: true });
|
|
3102
3213
|
writeFileSync5(abs, adapter.renderAgent(spec));
|
|
3103
3214
|
written.push(rel);
|
|
@@ -3181,8 +3292,8 @@ When MCP is registered, prefer the \`wb_*\` typed tools (same source & transacti
|
|
|
3181
3292
|
});
|
|
3182
3293
|
|
|
3183
3294
|
// core/commands/audit.command.ts
|
|
3184
|
-
import { existsSync as
|
|
3185
|
-
import { join as
|
|
3295
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
3296
|
+
import { join as join15 } from "node:path";
|
|
3186
3297
|
function auditModule(ctx, moduleRaw) {
|
|
3187
3298
|
const module = normalizeModule(moduleRaw, ctx.config);
|
|
3188
3299
|
const kinds = contractKinds(ctx.config);
|
|
@@ -3192,9 +3303,9 @@ function auditModule(ctx, moduleRaw) {
|
|
|
3192
3303
|
path: a.path,
|
|
3193
3304
|
status: reviewStatus(a),
|
|
3194
3305
|
everApproved: everApproved(a),
|
|
3195
|
-
onDisk:
|
|
3306
|
+
onDisk: existsSync13(join15(ctx.root, a.path))
|
|
3196
3307
|
}));
|
|
3197
|
-
const codeDirs = artifacts.filter((a) => a.kind === "code").map((a) => ({ path: a.path, endpoint: a.endpoint, onDisk:
|
|
3308
|
+
const codeDirs = artifacts.filter((a) => a.kind === "code").map((a) => ({ path: a.path, endpoint: a.endpoint, onDisk: existsSync13(join15(ctx.root, a.path)) }));
|
|
3198
3309
|
return {
|
|
3199
3310
|
module,
|
|
3200
3311
|
cleared: moduleCleared(ctx.db, module),
|
|
@@ -3258,28 +3369,28 @@ var init_intake_command = __esm({
|
|
|
3258
3369
|
// core/commands/init.command.ts
|
|
3259
3370
|
import {
|
|
3260
3371
|
copyFileSync,
|
|
3261
|
-
existsSync as
|
|
3372
|
+
existsSync as existsSync14,
|
|
3262
3373
|
mkdirSync as mkdirSync7,
|
|
3263
3374
|
readFileSync as readFileSync7,
|
|
3264
3375
|
readdirSync as readdirSync6,
|
|
3265
3376
|
writeFileSync as writeFileSync6
|
|
3266
3377
|
} from "node:fs";
|
|
3267
|
-
import { dirname as dirname4, join as
|
|
3378
|
+
import { dirname as dirname4, join as join16 } from "node:path";
|
|
3268
3379
|
function deployPreset(root) {
|
|
3269
3380
|
const deployed = [];
|
|
3270
|
-
if (!
|
|
3381
|
+
if (!existsSync14(PRESET_DIR)) return deployed;
|
|
3271
3382
|
const walk = (rel) => {
|
|
3272
|
-
for (const ent of readdirSync6(
|
|
3383
|
+
for (const ent of readdirSync6(join16(PRESET_DIR, rel), {
|
|
3273
3384
|
withFileTypes: true
|
|
3274
3385
|
})) {
|
|
3275
|
-
const childRel = rel ?
|
|
3386
|
+
const childRel = rel ? join16(rel, ent.name) : ent.name;
|
|
3276
3387
|
if (ent.isDirectory()) {
|
|
3277
3388
|
walk(childRel);
|
|
3278
3389
|
} else if (ent.isFile()) {
|
|
3279
|
-
const dest =
|
|
3280
|
-
if (
|
|
3390
|
+
const dest = join16(root, childRel);
|
|
3391
|
+
if (existsSync14(dest)) continue;
|
|
3281
3392
|
mkdirSync7(dirname4(dest), { recursive: true });
|
|
3282
|
-
copyFileSync(
|
|
3393
|
+
copyFileSync(join16(PRESET_DIR, childRel), dest);
|
|
3283
3394
|
deployed.push(childRel);
|
|
3284
3395
|
}
|
|
3285
3396
|
}
|
|
@@ -3288,8 +3399,8 @@ function deployPreset(root) {
|
|
|
3288
3399
|
return deployed;
|
|
3289
3400
|
}
|
|
3290
3401
|
function ensureRootTsx(root) {
|
|
3291
|
-
const pkgPath =
|
|
3292
|
-
if (!
|
|
3402
|
+
const pkgPath = join16(root, "package.json");
|
|
3403
|
+
if (!existsSync14(pkgPath)) return false;
|
|
3293
3404
|
const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
|
|
3294
3405
|
if (pkg.devDependencies?.tsx) return false;
|
|
3295
3406
|
pkg.devDependencies = { ...pkg.devDependencies ?? {}, tsx: TSX_VERSION };
|
|
@@ -3297,8 +3408,8 @@ function ensureRootTsx(root) {
|
|
|
3297
3408
|
return true;
|
|
3298
3409
|
}
|
|
3299
3410
|
function initProject(root, opts) {
|
|
3300
|
-
const configPath =
|
|
3301
|
-
if (
|
|
3411
|
+
const configPath = join16(root, CONFIG_FILENAME);
|
|
3412
|
+
if (existsSync14(configPath)) {
|
|
3302
3413
|
throw new Error(
|
|
3303
3414
|
`${CONFIG_FILENAME} \u5DF2\u5B58\u5728,init \u53EA\u7528\u4E8E\u7A7A\u9879\u76EE\u5F15\u5BFC(\u6539\u914D\u7F6E\u8BF7\u76F4\u63A5\u7F16\u8F91\u8BE5\u6587\u4EF6)`
|
|
3304
3415
|
);
|
|
@@ -3332,10 +3443,10 @@ function initProject(root, opts) {
|
|
|
3332
3443
|
const scaffolded = [];
|
|
3333
3444
|
if (opts.scaffold !== false) {
|
|
3334
3445
|
for (const dir of DOC_DIRS) {
|
|
3335
|
-
const abs =
|
|
3336
|
-
if (!
|
|
3446
|
+
const abs = join16(root, dir);
|
|
3447
|
+
if (!existsSync14(abs)) {
|
|
3337
3448
|
mkdirSync7(abs, { recursive: true });
|
|
3338
|
-
writeFileSync6(
|
|
3449
|
+
writeFileSync6(join16(abs, ".gitkeep"), "");
|
|
3339
3450
|
scaffolded.push(dir);
|
|
3340
3451
|
}
|
|
3341
3452
|
}
|
|
@@ -3367,7 +3478,7 @@ function initProject(root, opts) {
|
|
|
3367
3478
|
}
|
|
3368
3479
|
const notes = adapters.flatMap((a) => a.notes);
|
|
3369
3480
|
let hooks = [];
|
|
3370
|
-
if (opts.gitHooks !== false &&
|
|
3481
|
+
if (opts.gitHooks !== false && existsSync14(join16(root, ".git"))) {
|
|
3371
3482
|
try {
|
|
3372
3483
|
hooks = installGitHooks(ctx);
|
|
3373
3484
|
} catch {
|
|
@@ -3409,7 +3520,7 @@ var init_init_command = __esm({
|
|
|
3409
3520
|
"docs/design/prototypes",
|
|
3410
3521
|
"docs/acceptance"
|
|
3411
3522
|
];
|
|
3412
|
-
PRESET_DIR =
|
|
3523
|
+
PRESET_DIR = join16(WORKBENCH_DIR, "preset");
|
|
3413
3524
|
TSX_VERSION = "^4";
|
|
3414
3525
|
}
|
|
3415
3526
|
});
|
|
@@ -3487,6 +3598,7 @@ __export(core_exports, {
|
|
|
3487
3598
|
recordNote: () => recordNote,
|
|
3488
3599
|
recordQaResult: () => recordQaResult,
|
|
3489
3600
|
refreshArtifact: () => refreshArtifact,
|
|
3601
|
+
registerAdHocArtifact: () => registerAdHocArtifact,
|
|
3490
3602
|
registerMetaArtifacts: () => registerMetaArtifacts,
|
|
3491
3603
|
registerOutput: () => registerOutput,
|
|
3492
3604
|
rejectArtifact: () => rejectArtifact,
|
|
@@ -3696,17 +3808,17 @@ __export(app_exports, {
|
|
|
3696
3808
|
import fastifyCors from "@fastify/cors";
|
|
3697
3809
|
import fastifyStatic from "@fastify/static";
|
|
3698
3810
|
import Fastify from "fastify";
|
|
3699
|
-
import { existsSync as
|
|
3700
|
-
import { isAbsolute as isAbsolute2, join as
|
|
3811
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync8, readdirSync as readdirSync7, statSync as statSync6 } from "node:fs";
|
|
3812
|
+
import { isAbsolute as isAbsolute2, join as join17, normalize, relative as relative2 } from "node:path";
|
|
3701
3813
|
function getArtifact(ctx, id) {
|
|
3702
3814
|
const row = ctx.db.prepare("SELECT * FROM artifacts WHERE id = ?").get(id);
|
|
3703
3815
|
if (!row) throw Object.assign(new Error(`artifact #${id} \u4E0D\u5B58\u5728`), { statusCode: 404 });
|
|
3704
3816
|
return row;
|
|
3705
3817
|
}
|
|
3706
3818
|
function guardedAbsPath(ctx, artifact, rel) {
|
|
3707
|
-
const base = normalize(
|
|
3819
|
+
const base = normalize(join17(ctx.root, artifact.path));
|
|
3708
3820
|
if (!rel) return base;
|
|
3709
|
-
const target = normalize(
|
|
3821
|
+
const target = normalize(join17(base, rel));
|
|
3710
3822
|
const r = relative2(base, target);
|
|
3711
3823
|
if (r === "" || r === "." || r.startsWith("..") || isAbsolute2(r)) {
|
|
3712
3824
|
throw Object.assign(new Error("\u8DEF\u5F84\u8D8A\u754C"), { statusCode: 403 });
|
|
@@ -3716,11 +3828,11 @@ function guardedAbsPath(ctx, artifact, rel) {
|
|
|
3716
3828
|
async function createServer(ctx) {
|
|
3717
3829
|
const app = Fastify({ logger: false });
|
|
3718
3830
|
await app.register(fastifyCors, { origin: true });
|
|
3719
|
-
const webDist =
|
|
3720
|
-
if (
|
|
3831
|
+
const webDist = join17(WORKBENCH_DIR, "web/dist");
|
|
3832
|
+
if (existsSync15(webDist)) {
|
|
3721
3833
|
await app.register(fastifyStatic, { root: webDist });
|
|
3722
3834
|
}
|
|
3723
|
-
const protoRoot =
|
|
3835
|
+
const protoRoot = join17(ctx.root, ctx.config.docs.design, "prototypes");
|
|
3724
3836
|
mkdirSync8(protoRoot, { recursive: true });
|
|
3725
3837
|
await app.register(fastifyStatic, { root: protoRoot, prefix: "/proto/", decorateReply: false });
|
|
3726
3838
|
app.get("/api/meta", async () => ({
|
|
@@ -3755,7 +3867,7 @@ async function createServer(ctx) {
|
|
|
3755
3867
|
let content = null;
|
|
3756
3868
|
let isDirectory = false;
|
|
3757
3869
|
let missing = false;
|
|
3758
|
-
if (!
|
|
3870
|
+
if (!existsSync15(abs)) {
|
|
3759
3871
|
missing = true;
|
|
3760
3872
|
} else if (statSync6(abs).isDirectory()) {
|
|
3761
3873
|
isDirectory = true;
|
|
@@ -3771,20 +3883,20 @@ async function createServer(ctx) {
|
|
|
3771
3883
|
const walk = (dir, rel) => {
|
|
3772
3884
|
for (const name of readdirSync7(dir).sort()) {
|
|
3773
3885
|
if (name === "node_modules" || name.startsWith(".")) continue;
|
|
3774
|
-
const full =
|
|
3886
|
+
const full = join17(dir, name);
|
|
3775
3887
|
const relPath = rel ? `${rel}/${name}` : name;
|
|
3776
3888
|
const st = statSync6(full);
|
|
3777
3889
|
if (st.isDirectory()) walk(full, relPath);
|
|
3778
3890
|
else files.push({ rel: relPath, size: st.size });
|
|
3779
3891
|
}
|
|
3780
3892
|
};
|
|
3781
|
-
if (
|
|
3893
|
+
if (existsSync15(base) && statSync6(base).isDirectory()) walk(base, "");
|
|
3782
3894
|
return { files };
|
|
3783
3895
|
});
|
|
3784
3896
|
app.get("/api/artifact/:id/file", async (req) => {
|
|
3785
3897
|
const artifact = getArtifact(ctx, parseInt(req.params.id));
|
|
3786
3898
|
const abs = guardedAbsPath(ctx, artifact, req.query.rel);
|
|
3787
|
-
if (!
|
|
3899
|
+
if (!existsSync15(abs) || statSync6(abs).isDirectory()) {
|
|
3788
3900
|
throw Object.assign(new Error("\u6587\u4EF6\u4E0D\u5B58\u5728"), { statusCode: 404 });
|
|
3789
3901
|
}
|
|
3790
3902
|
if (statSync6(abs).size > MAX_INLINE_SIZE) {
|
|
@@ -3825,6 +3937,117 @@ data: {"cursor":${cursor2}}
|
|
|
3825
3937
|
}, 500);
|
|
3826
3938
|
req.raw.on("close", () => clearInterval(timer));
|
|
3827
3939
|
});
|
|
3940
|
+
app.get("/api/graph", async () => {
|
|
3941
|
+
const registry = getKindRegistry(ctx.config);
|
|
3942
|
+
const rows = ctx.db.prepare("SELECT * FROM artifacts ORDER BY id").all().filter(
|
|
3943
|
+
(a) => !registry[a.kind]?.meta
|
|
3944
|
+
);
|
|
3945
|
+
const ids = new Set(rows.map((a) => a.id));
|
|
3946
|
+
const nodes = rows.map((a) => ({
|
|
3947
|
+
id: a.id,
|
|
3948
|
+
kind: a.kind,
|
|
3949
|
+
path: a.path,
|
|
3950
|
+
module: a.module,
|
|
3951
|
+
endpoint: a.endpoint,
|
|
3952
|
+
page: a.page,
|
|
3953
|
+
review_status: reviewStatus(a),
|
|
3954
|
+
missing: !existsSync15(join17(ctx.root, a.path))
|
|
3955
|
+
}));
|
|
3956
|
+
const edges = ctx.db.prepare("SELECT id, from_id, to_id, source FROM artifact_edges").all().filter((e) => ids.has(e.from_id) && ids.has(e.to_id));
|
|
3957
|
+
return { nodes, edges };
|
|
3958
|
+
});
|
|
3959
|
+
app.get("/api/search", async (req) => {
|
|
3960
|
+
const q = (req.query.q ?? "").trim().toLowerCase();
|
|
3961
|
+
if (!q) return { artifacts: [], files: [] };
|
|
3962
|
+
const like = `%${q.replace(/[%_\\]/g, (c) => "\\" + c)}%`;
|
|
3963
|
+
const artifacts = ctx.db.prepare("SELECT * FROM artifacts WHERE path LIKE ? ESCAPE '\\' ORDER BY path LIMIT 30").all(like).map((a) => ({ id: a.id, kind: a.kind, path: a.path, module: a.module, endpoint: a.endpoint, review_status: reviewStatus(a) }));
|
|
3964
|
+
const registered = new Set(ctx.db.prepare("SELECT path FROM artifacts").all().map((r) => r.path));
|
|
3965
|
+
const files = [];
|
|
3966
|
+
const walk = (dir, rel) => {
|
|
3967
|
+
if (files.length >= 30) return;
|
|
3968
|
+
for (const name of readdirSync7(dir).sort()) {
|
|
3969
|
+
if (files.length >= 30) return;
|
|
3970
|
+
if (name.startsWith(".") || name === "node_modules" || name === "dist" || name === "build") continue;
|
|
3971
|
+
const full = join17(dir, name);
|
|
3972
|
+
const relPath = rel ? `${rel}/${name}` : name;
|
|
3973
|
+
if (statSync6(full).isDirectory()) walk(full, relPath);
|
|
3974
|
+
else if (relPath.toLowerCase().includes(q) && !registered.has(relPath)) files.push(relPath);
|
|
3975
|
+
}
|
|
3976
|
+
};
|
|
3977
|
+
walk(ctx.root, "");
|
|
3978
|
+
return { artifacts, files };
|
|
3979
|
+
});
|
|
3980
|
+
app.post("/api/artifact/register", async (req) => {
|
|
3981
|
+
return registerAdHocArtifact(ctx, req.body.path, req.body.actor || "user");
|
|
3982
|
+
});
|
|
3983
|
+
app.post("/api/edge", async (req, reply) => {
|
|
3984
|
+
const { fromId, toId } = req.body;
|
|
3985
|
+
const actor = req.body.actor || "user";
|
|
3986
|
+
if (!fromId || !toId || fromId === toId) {
|
|
3987
|
+
return reply.code(400).send({ error: "\u65E0\u6548\u7684\u8FB9:\u9700\u8981\u4E24\u4E2A\u4E0D\u540C\u7684\u4EA7\u7269" });
|
|
3988
|
+
}
|
|
3989
|
+
const has = (id) => ctx.db.prepare("SELECT COUNT(*) c FROM artifacts WHERE id = ?").get(id).c > 0;
|
|
3990
|
+
if (!has(fromId) || !has(toId)) return reply.code(404).send({ error: "\u4EA7\u7269\u4E0D\u5B58\u5728" });
|
|
3991
|
+
const seen = /* @__PURE__ */ new Set([toId]);
|
|
3992
|
+
const queue = [toId];
|
|
3993
|
+
const next = ctx.db.prepare("SELECT to_id FROM artifact_edges WHERE from_id = ?");
|
|
3994
|
+
while (queue.length) {
|
|
3995
|
+
const cur = queue.pop();
|
|
3996
|
+
for (const row of next.all(cur)) {
|
|
3997
|
+
if (row.to_id === fromId) return reply.code(400).send({ error: "\u4F1A\u5F62\u6210\u73AF,\u5DF2\u62D2\u7EDD" });
|
|
3998
|
+
if (!seen.has(row.to_id)) {
|
|
3999
|
+
seen.add(row.to_id);
|
|
4000
|
+
queue.push(row.to_id);
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
const r = ctx.db.prepare("INSERT OR IGNORE INTO artifact_edges (from_id, to_id, source) VALUES (?, ?, 'manual')").run(fromId, toId);
|
|
4005
|
+
if (r.changes === 0) return reply.code(409).send({ error: "\u8BE5\u5173\u7CFB\u5DF2\u5B58\u5728" });
|
|
4006
|
+
logEvent(ctx.db, { entityType: "artifact", entityId: toId, event: "edge_added", actor, payload: { fromId, toId, source: "manual" } });
|
|
4007
|
+
return { id: r.lastInsertRowid, fromId, toId, source: "manual" };
|
|
4008
|
+
});
|
|
4009
|
+
app.delete("/api/artifact/:id", async (req, reply) => {
|
|
4010
|
+
const id = parseInt(req.params.id);
|
|
4011
|
+
const row = ctx.db.prepare("SELECT * FROM artifacts WHERE id = ?").get(id);
|
|
4012
|
+
if (!row) return reply.code(404).send({ error: "\u4EA7\u7269\u4E0D\u5B58\u5728" });
|
|
4013
|
+
if (row.approved_hash !== null) return reply.code(403).send({ error: "\u8BE5\u4EA7\u7269\u6709\u5BA1\u6279\u5386\u53F2,\u4E0D\u53EF\u53D6\u6D88\u767B\u8BB0" });
|
|
4014
|
+
const refs = ctx.db.prepare(
|
|
4015
|
+
`SELECT (SELECT COUNT(*) FROM task_inputs WHERE artifact_id = ?) +
|
|
4016
|
+
(SELECT COUNT(*) FROM task_outputs WHERE artifact_id = ?) +
|
|
4017
|
+
(SELECT COUNT(*) FROM artifact_feedback WHERE artifact_id = ?) AS c`
|
|
4018
|
+
).get(id, id, id);
|
|
4019
|
+
if (refs.c > 0) return reply.code(403).send({ error: "\u8BE5\u4EA7\u7269\u5DF2\u88AB\u4EFB\u52A1/\u53CD\u9988\u5F15\u7528,\u4E0D\u53EF\u53D6\u6D88\u767B\u8BB0" });
|
|
4020
|
+
const tx = ctx.db.transaction(() => {
|
|
4021
|
+
logEvent(ctx.db, {
|
|
4022
|
+
entityType: "artifact",
|
|
4023
|
+
entityId: id,
|
|
4024
|
+
event: "unregistered",
|
|
4025
|
+
actor: req.body?.actor || "user",
|
|
4026
|
+
payload: { path: row.path, kind: row.kind },
|
|
4027
|
+
module: row.module,
|
|
4028
|
+
endpoint: row.endpoint,
|
|
4029
|
+
page: row.page
|
|
4030
|
+
});
|
|
4031
|
+
ctx.db.prepare("DELETE FROM artifacts WHERE id = ?").run(id);
|
|
4032
|
+
});
|
|
4033
|
+
tx();
|
|
4034
|
+
return { ok: true };
|
|
4035
|
+
});
|
|
4036
|
+
app.delete("/api/edge/:id", async (req, reply) => {
|
|
4037
|
+
const id = parseInt(req.params.id);
|
|
4038
|
+
const edge = ctx.db.prepare("SELECT * FROM artifact_edges WHERE id = ?").get(id);
|
|
4039
|
+
if (!edge) return reply.code(404).send({ error: "\u8FB9\u4E0D\u5B58\u5728" });
|
|
4040
|
+
if (edge.source !== "manual") return reply.code(403).send({ error: "\u81EA\u52A8\u63A8\u5BFC\u7684\u5173\u7CFB\u4E0D\u53EF\u89E3\u7ED1(\u7531 scan \u6309\u5750\u6807\u4E8B\u5B9E\u7EF4\u62A4)" });
|
|
4041
|
+
ctx.db.prepare("DELETE FROM artifact_edges WHERE id = ?").run(id);
|
|
4042
|
+
logEvent(ctx.db, {
|
|
4043
|
+
entityType: "artifact",
|
|
4044
|
+
entityId: edge.to_id,
|
|
4045
|
+
event: "edge_removed",
|
|
4046
|
+
actor: req.body?.actor || "user",
|
|
4047
|
+
payload: { fromId: edge.from_id, toId: edge.to_id }
|
|
4048
|
+
});
|
|
4049
|
+
return { ok: true };
|
|
4050
|
+
});
|
|
3828
4051
|
app.get("/api/review-queue", async () => {
|
|
3829
4052
|
return listArtifacts(ctx, {}).filter((r) => r.review_status === "pending" || r.review_status === "invalidated").map((r) => ({
|
|
3830
4053
|
...r,
|
|
@@ -3845,7 +4068,7 @@ data: {"cursor":${cursor2}}
|
|
|
3845
4068
|
app.get("/api/artifact/:id/diff", async (req) => {
|
|
3846
4069
|
const artifact = getArtifact(ctx, parseInt(req.params.id));
|
|
3847
4070
|
const abs = guardedAbsPath(ctx, artifact);
|
|
3848
|
-
const current =
|
|
4071
|
+
const current = existsSync15(abs) && !statSync6(abs).isDirectory() ? readFileSync8(abs, "utf-8") : null;
|
|
3849
4072
|
return { approved: approvedContent(ctx, artifact.id), current };
|
|
3850
4073
|
});
|
|
3851
4074
|
app.post(
|
|
@@ -3894,11 +4117,13 @@ var init_app = __esm({
|
|
|
3894
4117
|
"use strict";
|
|
3895
4118
|
init_artifact_commands();
|
|
3896
4119
|
init_retro_command();
|
|
4120
|
+
init_scan_command();
|
|
3897
4121
|
init_sync_command();
|
|
3898
4122
|
init_config();
|
|
3899
4123
|
init_task_commands();
|
|
3900
4124
|
init_derive();
|
|
3901
4125
|
init_events();
|
|
4126
|
+
init_kind();
|
|
3902
4127
|
init_tree();
|
|
3903
4128
|
MAX_INLINE_SIZE = 1024 * 1024;
|
|
3904
4129
|
}
|
|
@@ -3909,15 +4134,17 @@ function hookPlatform() {
|
|
|
3909
4134
|
const arg = process.argv.find((a) => a.startsWith("--platform="));
|
|
3910
4135
|
return arg ? arg.slice("--platform=".length) : "claude";
|
|
3911
4136
|
}
|
|
3912
|
-
function extractFilePath(input) {
|
|
4137
|
+
function extractFilePath(input, adapter) {
|
|
4138
|
+
const fromAdapter = adapter?.parseHookInput(input).filePath;
|
|
4139
|
+
if (fromAdapter) return fromAdapter;
|
|
3913
4140
|
return input?.tool_input?.file_path ?? // claude PreToolUse/PostToolUse
|
|
3914
4141
|
input?.tool_input?.filePath ?? input?.file_path ?? // cursor afterFileEdit / 通用
|
|
3915
4142
|
input?.filePath ?? input?.args?.file_path ?? // opencode tool 参数
|
|
3916
4143
|
input?.args?.filePath ?? input?.arguments?.file_path ?? // codex 兜底
|
|
3917
4144
|
input?.arguments?.filePath ?? input?.input?.file_path ?? void 0;
|
|
3918
4145
|
}
|
|
3919
|
-
function hookProjectDir() {
|
|
3920
|
-
return process.env.CLAUDE_PROJECT_DIR ?? process.env.CODEX_PROJECT_DIR ?? process.env.CURSOR_PROJECT_DIR ?? process.env.OPENCODE_PROJECT_DIR ?? process.env.WORKBENCH_PROJECT ?? void 0;
|
|
4146
|
+
function hookProjectDir(adapter) {
|
|
4147
|
+
return (adapter && process.env[adapter.projectDirEnvVar]) ?? process.env.CLAUDE_PROJECT_DIR ?? process.env.CODEX_PROJECT_DIR ?? process.env.CURSOR_PROJECT_DIR ?? process.env.OPENCODE_PROJECT_DIR ?? process.env.WORKBENCH_PROJECT ?? void 0;
|
|
3921
4148
|
}
|
|
3922
4149
|
async function readStdinJson() {
|
|
3923
4150
|
const chunks = [];
|
|
@@ -3941,14 +4168,16 @@ __export(hook_pretooluse_exports, {
|
|
|
3941
4168
|
});
|
|
3942
4169
|
async function writeGateHook(platform) {
|
|
3943
4170
|
const input = await readStdinJson();
|
|
3944
|
-
const
|
|
4171
|
+
const { getAdapter: getAdapter2, PLATFORM_IDS: PLATFORM_IDS2 } = await Promise.resolve().then(() => (init_platforms(), platforms_exports));
|
|
4172
|
+
const adapter = PLATFORM_IDS2.includes(platform) ? getAdapter2(platform) : void 0;
|
|
4173
|
+
const filePath = extractFilePath(input, adapter);
|
|
3945
4174
|
if (!filePath) return;
|
|
3946
4175
|
const { openWorkbench: openWorkbench2 } = await Promise.resolve().then(() => (init_db(), db_exports));
|
|
3947
4176
|
const { normalizeRelPath: normalizeRelPath2 } = await Promise.resolve().then(() => (init_artifact_commands(), artifact_commands_exports));
|
|
3948
4177
|
const { reviewStatus: reviewStatus2 } = await Promise.resolve().then(() => (init_derive(), derive_exports));
|
|
3949
4178
|
const { contractKinds: contractKinds2 } = await Promise.resolve().then(() => (init_kind(), kind_exports));
|
|
3950
4179
|
const { logEvent: logEvent2 } = await Promise.resolve().then(() => (init_events(), events_exports));
|
|
3951
|
-
const ctx = openWorkbench2(hookProjectDir());
|
|
4180
|
+
const ctx = openWorkbench2(hookProjectDir(adapter));
|
|
3952
4181
|
const mode = ctx.config.gates.writeGate;
|
|
3953
4182
|
if (mode === "off") return;
|
|
3954
4183
|
const rel = normalizeRelPath2(ctx, filePath);
|
|
@@ -3975,12 +4204,10 @@ async function writeGateHook(platform) {
|
|
|
3975
4204
|
const msg = `\u8BE5\u6587\u4EF6\u662F\u5DF2\u5BA1\u6279\u5951\u7EA6(${artifact.kind}): ${rel}\u3002
|
|
3976
4205
|
\u4FEE\u6539\u524D\u8BF7\u5148\u9886\u53D6\u5BF9\u5E94\u4EFB\u52A1:${ctx.config.cli} list --module=${artifact.module ?? ""} --status=pending
|
|
3977
4206
|
\u9886\u53D6\u540E\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF WORKBENCH_TASK_ID=<\u4EFB\u52A1id> \u518D\u4FEE\u6539;\u82E5\u5BF9\u5185\u5BB9\u672C\u8EAB\u6709\u5F02\u8BAE,\u7528 dispute \u547D\u4EE4\u7559\u75D5\u5E76\u505C\u6B62\u3002`;
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
console.error(msg);
|
|
3983
|
-
process.exit(2);
|
|
4207
|
+
const resp = adapter?.respondBlocked(msg) ?? { exitCode: 2, stderr: msg };
|
|
4208
|
+
if (resp.stdout) process.stdout.write(resp.stdout);
|
|
4209
|
+
if (resp.stderr) console.error(resp.stderr);
|
|
4210
|
+
process.exit(resp.exitCode);
|
|
3984
4211
|
}
|
|
3985
4212
|
}
|
|
3986
4213
|
var init_hook_pretooluse = __esm({
|
|
@@ -3999,13 +4226,15 @@ var hook_refresh_exports = {};
|
|
|
3999
4226
|
__export(hook_refresh_exports, {
|
|
4000
4227
|
refreshHook: () => refreshHook
|
|
4001
4228
|
});
|
|
4002
|
-
async function refreshHook(
|
|
4229
|
+
async function refreshHook(platform) {
|
|
4003
4230
|
const input = await readStdinJson();
|
|
4004
|
-
const
|
|
4231
|
+
const { getAdapter: getAdapter2, PLATFORM_IDS: PLATFORM_IDS2 } = await Promise.resolve().then(() => (init_platforms(), platforms_exports));
|
|
4232
|
+
const adapter = platform && PLATFORM_IDS2.includes(platform) ? getAdapter2(platform) : void 0;
|
|
4233
|
+
const filePath = extractFilePath(input, adapter);
|
|
4005
4234
|
if (!filePath) return;
|
|
4006
4235
|
const { openWorkbench: openWorkbench2 } = await Promise.resolve().then(() => (init_db(), db_exports));
|
|
4007
4236
|
const { refreshArtifact: refreshArtifact2, normalizeRelPath: normalizeRelPath2 } = await Promise.resolve().then(() => (init_artifact_commands(), artifact_commands_exports));
|
|
4008
|
-
const ctx = openWorkbench2(hookProjectDir());
|
|
4237
|
+
const ctx = openWorkbench2(hookProjectDir(adapter));
|
|
4009
4238
|
const rel = normalizeRelPath2(ctx, filePath);
|
|
4010
4239
|
const exact = ctx.db.prepare("SELECT id FROM artifacts WHERE path = ?").get(rel);
|
|
4011
4240
|
if (exact) {
|
|
@@ -4105,7 +4334,6 @@ function printTaskDetail(ctx, id) {
|
|
|
4105
4334
|
}
|
|
4106
4335
|
console.log();
|
|
4107
4336
|
}
|
|
4108
|
-
var ALL_PLATFORMS = ["claude", "codex", "opencode", "cursor"];
|
|
4109
4337
|
var PRIORITY_PROVIDERS = [
|
|
4110
4338
|
"anthropic",
|
|
4111
4339
|
"openai",
|
|
@@ -4151,7 +4379,7 @@ async function promptInit() {
|
|
|
4151
4379
|
const zh = language === "zh";
|
|
4152
4380
|
const platform = await select({
|
|
4153
4381
|
message: zh ? "\u5E73\u53F0" : "Platform",
|
|
4154
|
-
choices:
|
|
4382
|
+
choices: PLATFORM_IDS.map((p) => ({ name: p, value: p })),
|
|
4155
4383
|
default: "claude"
|
|
4156
4384
|
});
|
|
4157
4385
|
const platforms = [platform];
|
|
@@ -4179,14 +4407,14 @@ async function promptInit() {
|
|
|
4179
4407
|
choices: prov.models.map((m) => ({ name: m.name, value: m.id })),
|
|
4180
4408
|
pageSize: 12
|
|
4181
4409
|
});
|
|
4182
|
-
if (modelId) modelObj[p] = p
|
|
4410
|
+
if (modelId) modelObj[p] = getAdapter(p).formatModel(provId, modelId);
|
|
4183
4411
|
}
|
|
4184
4412
|
return { platforms, endpoints, model: Object.keys(modelObj).length ? modelObj : void 0, language };
|
|
4185
4413
|
}
|
|
4186
4414
|
async function runInit(root, a) {
|
|
4187
|
-
const { existsSync:
|
|
4188
|
-
const { join:
|
|
4189
|
-
if (
|
|
4415
|
+
const { existsSync: existsSync16 } = await import("node:fs");
|
|
4416
|
+
const { join: join18 } = await import("node:path");
|
|
4417
|
+
if (existsSync16(join18(root, "workbench.config.json"))) {
|
|
4190
4418
|
console.log(chalk.red("\u9519\u8BEF: workbench.config.json \u5DF2\u5B58\u5728,init \u53EA\u7528\u4E8E\u7A7A\u9879\u76EE\u5F15\u5BFC(\u6539\u914D\u7F6E\u8BF7\u76F4\u63A5\u7F16\u8F91\u8BE5\u6587\u4EF6)"));
|
|
4191
4419
|
process.exit(1);
|
|
4192
4420
|
}
|
|
@@ -4447,7 +4675,7 @@ async function runCommand(ctx, command, a) {
|
|
|
4447
4675
|
}
|
|
4448
4676
|
case "scan": {
|
|
4449
4677
|
const s = scanArtifacts(ctx, a.actor || "system");
|
|
4450
|
-
console.log(chalk.green(`\u2705 \u626B\u63CF\u5B8C\u6210:\u65B0\u767B\u8BB0 ${s.registered},\u5185\u5BB9\u5237\u65B0 ${s.refreshed},\u91CD\u6302\u5750\u6807 ${s.remapped},\u65B0\u589E\u8FB9 ${s.edges},\u6392\u9664\u5143\u4EA7\u7269 ${s.skipped.length}`));
|
|
4678
|
+
console.log(chalk.green(`\u2705 \u626B\u63CF\u5B8C\u6210:\u65B0\u767B\u8BB0 ${s.registered},\u5185\u5BB9\u5237\u65B0 ${s.refreshed},\u91CD\u6302\u5750\u6807 ${s.remapped},\u81EA\u52A8\u8DDF\u968F\u79FB\u52A8 ${s.moved},\u65B0\u589E\u8FB9 ${s.edges},\u6E05\u7406\u6B8B\u7559\u8FB9 ${s.edgesPruned},\u6392\u9664\u5143\u4EA7\u7269 ${s.skipped.length}`));
|
|
4451
4679
|
if (s.unresolved.length > 0) {
|
|
4452
4680
|
console.log(chalk.yellow(`\u26A0 ${s.unresolved.length} \u4E2A\u6587\u4EF6\u547D\u4E2D kind \u4F46\u8DEF\u5F84\u4E0D\u7B26 coords \u6587\u6CD5,\u672A\u767B\u8BB0(\u975E\u89C4\u8303/\u5E9F\u5F03\u7AEF?):`));
|
|
4453
4681
|
for (const p of s.unresolved) console.log(chalk.yellow(` - ${p}`));
|