soloforge 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
- package/dist/adapters/claude_code/claude_md.js +4 -0
- package/dist/adapters/claude_code/claude_md.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts +10 -10
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +603 -18
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/shared/workflow_template.d.ts +26 -0
- package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
- package/dist/adapters/shared/workflow_template.js +140 -46
- package/dist/adapters/shared/workflow_template.js.map +1 -1
- package/dist/bin/soloforge.d.ts.map +1 -1
- package/dist/bin/soloforge.js +316 -54
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/asset_manifest.d.ts +7 -1
- package/dist/engine/asset_manifest.d.ts.map +1 -1
- package/dist/engine/asset_manifest.js +41 -18
- package/dist/engine/asset_manifest.js.map +1 -1
- package/dist/engine/backend_implementation_contract.d.ts +51 -0
- package/dist/engine/backend_implementation_contract.d.ts.map +1 -0
- package/dist/engine/backend_implementation_contract.js +142 -0
- package/dist/engine/backend_implementation_contract.js.map +1 -0
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
- package/dist/engine/consumable_asset_registry.js +159 -0
- package/dist/engine/consumable_asset_registry.js.map +1 -1
- package/dist/engine/consumption_trace_store.d.ts +8 -8
- package/dist/engine/consumption_trace_store.d.ts.map +1 -1
- package/dist/engine/consumption_trace_store.js +11 -7
- package/dist/engine/consumption_trace_store.js.map +1 -1
- package/dist/engine/decision_workshop.d.ts +160 -0
- package/dist/engine/decision_workshop.d.ts.map +1 -0
- package/dist/engine/decision_workshop.js +279 -0
- package/dist/engine/decision_workshop.js.map +1 -0
- package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.js +300 -2
- package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
- package/dist/engine/explicit_asset_registry.d.ts +30 -0
- package/dist/engine/explicit_asset_registry.d.ts.map +1 -0
- package/dist/engine/explicit_asset_registry.js +3712 -0
- package/dist/engine/explicit_asset_registry.js.map +1 -0
- package/dist/engine/implementation_roadmap_registry.d.ts +2 -2
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
- package/dist/engine/implementation_roadmap_registry.js +110 -16
- package/dist/engine/implementation_roadmap_registry.js.map +1 -1
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +46 -2
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/intent_router.d.ts +1 -1
- package/dist/engine/intent_router.d.ts.map +1 -1
- package/dist/engine/intent_router.js +2 -1
- package/dist/engine/intent_router.js.map +1 -1
- package/dist/engine/knowledge_injection_boundary.d.ts +3 -0
- package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -1
- package/dist/engine/knowledge_injection_boundary.js +48 -5
- package/dist/engine/knowledge_injection_boundary.js.map +1 -1
- package/dist/engine/mechanism_contract_registry.d.ts +1 -1
- package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
- package/dist/engine/mechanism_contract_registry.js +142 -2
- package/dist/engine/mechanism_contract_registry.js.map +1 -1
- package/dist/engine/next_action_planner.d.ts +19 -0
- package/dist/engine/next_action_planner.d.ts.map +1 -0
- package/dist/engine/next_action_planner.js +453 -0
- package/dist/engine/next_action_planner.js.map +1 -0
- package/dist/engine/observed_consumption.d.ts +54 -0
- package/dist/engine/observed_consumption.d.ts.map +1 -0
- package/dist/engine/observed_consumption.js +377 -0
- package/dist/engine/observed_consumption.js.map +1 -0
- package/dist/engine/ood_solid_contract.d.ts +51 -0
- package/dist/engine/ood_solid_contract.d.ts.map +1 -0
- package/dist/engine/ood_solid_contract.js +115 -0
- package/dist/engine/ood_solid_contract.js.map +1 -0
- package/dist/engine/project_stage_detector.d.ts +17 -0
- package/dist/engine/project_stage_detector.d.ts.map +1 -0
- package/dist/engine/project_stage_detector.js +185 -0
- package/dist/engine/project_stage_detector.js.map +1 -0
- package/dist/engine/release_issue_scenario_registry.d.ts +64 -0
- package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -0
- package/dist/engine/release_issue_scenario_registry.js +1362 -0
- package/dist/engine/release_issue_scenario_registry.js.map +1 -0
- package/dist/engine/release_readiness_gate.d.ts +1 -1
- package/dist/engine/release_readiness_gate.d.ts.map +1 -1
- package/dist/engine/release_readiness_gate.js +721 -47
- package/dist/engine/release_readiness_gate.js.map +1 -1
- package/dist/engine/release_tool_harness.d.ts +71 -0
- package/dist/engine/release_tool_harness.d.ts.map +1 -0
- package/dist/engine/release_tool_harness.js +161 -0
- package/dist/engine/release_tool_harness.js.map +1 -0
- package/dist/engine/scaffolder.d.ts.map +1 -1
- package/dist/engine/scaffolder.js +144 -7
- package/dist/engine/scaffolder.js.map +1 -1
- package/dist/engine/stale_current_task_detector.d.ts +30 -0
- package/dist/engine/stale_current_task_detector.d.ts.map +1 -0
- package/dist/engine/stale_current_task_detector.js +168 -0
- package/dist/engine/stale_current_task_detector.js.map +1 -0
- package/dist/engine/standard_asset_contract.d.ts +75 -0
- package/dist/engine/standard_asset_contract.d.ts.map +1 -0
- package/dist/engine/standard_asset_contract.js +388 -0
- package/dist/engine/standard_asset_contract.js.map +1 -0
- package/dist/engine/standard_asset_coverage.d.ts +45 -0
- package/dist/engine/standard_asset_coverage.d.ts.map +1 -0
- package/dist/engine/standard_asset_coverage.js +220 -0
- package/dist/engine/standard_asset_coverage.js.map +1 -0
- package/dist/engine/task_stage_detector.d.ts +19 -0
- package/dist/engine/task_stage_detector.d.ts.map +1 -0
- package/dist/engine/task_stage_detector.js +201 -0
- package/dist/engine/task_stage_detector.js.map +1 -0
- package/dist/engine/template_asset_contract_registry.d.ts +162 -0
- package/dist/engine/template_asset_contract_registry.d.ts.map +1 -0
- package/dist/engine/template_asset_contract_registry.js +598 -0
- package/dist/engine/template_asset_contract_registry.js.map +1 -0
- package/dist/engine/template_asset_visibility.d.ts +109 -0
- package/dist/engine/template_asset_visibility.d.ts.map +1 -0
- package/dist/engine/template_asset_visibility.js +321 -0
- package/dist/engine/template_asset_visibility.js.map +1 -0
- package/dist/engine/template_init_sync.d.ts +68 -0
- package/dist/engine/template_init_sync.d.ts.map +1 -0
- package/dist/engine/template_init_sync.js +218 -0
- package/dist/engine/template_init_sync.js.map +1 -0
- package/dist/engine/template_manifest_io.d.ts +10 -0
- package/dist/engine/template_manifest_io.d.ts.map +1 -1
- package/dist/engine/template_manifest_io.js +63 -30
- package/dist/engine/template_manifest_io.js.map +1 -1
- package/dist/engine/template_mechanism_auditor.d.ts +3 -1
- package/dist/engine/template_mechanism_auditor.d.ts.map +1 -1
- package/dist/engine/template_mechanism_auditor.js +27 -24
- package/dist/engine/template_mechanism_auditor.js.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.js +21 -1
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -1
- package/dist/engine/workflow_navigation_contract.d.ts +115 -0
- package/dist/engine/workflow_navigation_contract.d.ts.map +1 -0
- package/dist/engine/workflow_navigation_contract.js +39 -0
- package/dist/engine/workflow_navigation_contract.js.map +1 -0
- package/dist/knowledge/index_manager.d.ts +20 -0
- package/dist/knowledge/index_manager.d.ts.map +1 -1
- package/dist/knowledge/index_manager.js +234 -3
- package/dist/knowledge/index_manager.js.map +1 -1
- package/dist/types.d.ts +44 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/templates/knowledge/acceptance_templates/OOD/350/256/276/350/256/241/346/221/230/350/246/201/346/250/241/347/211/210.md +60 -0
- package/templates/knowledge/acceptance_templates//345/220/216/347/253/257/345/256/236/347/216/260/351/252/214/346/224/266/346/270/205/345/215/225.md +46 -0
- package/templates/knowledge/procedures/OOD/350/256/276/350/256/241/345/267/245/344/275/234/346/265/201.md +50 -0
- package/templates/knowledge/procedures//345/205/250/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201/345/257/274/350/210/252.md +100 -0
- package/templates/knowledge/procedures//345/220/216/347/253/257/346/216/245/345/217/243/345/256/236/347/216/260/345/267/245/344/275/234/346/265/201.md +50 -0
- package/templates/knowledge/review_rules/SOLID/344/273/243/347/240/201/345/256/241/346/237/245/350/247/204/345/210/231.md +40 -0
- package/templates/knowledge/review_rules//345/220/216/347/253/257/345/256/236/347/216/260/345/267/245/347/250/213/345/256/241/346/237/245/350/247/204/345/210/231.md +38 -0
- package/templates/knowledge/rules/OOD/344/270/216SOLID/350/256/276/350/256/241/350/247/204/345/210/231.md +62 -0
- package/templates/knowledge/rules//345/220/216/347/253/257/345/256/236/347/216/260/345/267/245/347/250/213/345/245/221/347/272/246/350/247/204/345/210/231.md +55 -0
- package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/345/257/274/350/210/252/345/245/221/347/272/246/350/247/204/345/210/231.md +113 -0
- package/templates/knowledge/rules//346/240/207/345/207/206/350/265/204/344/272/247/350/246/206/347/233/226/350/247/204/345/210/231.md +72 -0
- package/templates/knowledge/rules//346/250/241/346/235/277/350/265/204/344/272/247/345/217/257/350/247/201/346/200/247/350/247/204/345/210/231.md +71 -0
- package/templates/knowledge/rules//347/224/250/346/210/267/345/217/215/351/246/210/345/245/221/347/272/246/350/247/204/345/210/231.md +62 -1
- package/templates/knowledge/rules//351/200/232/347/224/250/345/206/263/347/255/226/347/240/224/350/256/250/350/247/204/345/210/231.md +77 -0
- package/templates/knowledge/rules//351/252/214/346/224/266/346/250/241/346/235/277/350/276/223/345/207/272/345/245/221/347/272/246/350/247/204/345/210/231.md +96 -0
- package/templates/patterns/SOLID/350/256/276/350/256/241/350/247/204/350/214/203.md +39 -0
- package/templates/patterns//345/220/216/347/253/257/345/256/236/347/216/260/345/267/245/347/250/213/350/247/204/350/214/203.md +39 -0
|
@@ -80,6 +80,12 @@ const lazyFirstPrinciples = createLazy(() => import("../../engine/first_principl
|
|
|
80
80
|
const lazyBrainstormContract = createLazy(() => import("../../engine/brainstorm_contract.js"));
|
|
81
81
|
const lazyArchitectureWorkshop = createLazy(() => import("../../engine/architecture_decision_workshop.js"));
|
|
82
82
|
const lazyDesignArtifactPack = createLazy(() => import("../../engine/design_artifact_pack.js"));
|
|
83
|
+
const lazyStandardAssetContract = createLazy(() => import("../../engine/standard_asset_contract.js"));
|
|
84
|
+
const lazyTemplateVisibility = createLazy(() => import("../../engine/template_asset_visibility.js"));
|
|
85
|
+
const lazyDecisionWorkshop = createLazy(() => import("../../engine/decision_workshop.js"));
|
|
86
|
+
const lazyNavigation = createLazy(() => import("../../engine/next_action_planner.js"));
|
|
87
|
+
const lazyOodSolid = createLazy(() => import("../../engine/ood_solid_contract.js"));
|
|
88
|
+
const lazyBackendImplementation = createLazy(() => import("../../engine/backend_implementation_contract.js"));
|
|
83
89
|
// ── Zod Schema 定义 ──
|
|
84
90
|
const ClassifySchema = {
|
|
85
91
|
intent: z.string().describe("开发者意图描述"),
|
|
@@ -90,7 +96,10 @@ const ExpandSchema = {
|
|
|
90
96
|
clarification_answers: z.array(z.string()).optional().describe("对澄清问题的回答"),
|
|
91
97
|
input_material_confirmations: z.array(z.string()).optional().describe("已确认安全的输入材料路径列表"),
|
|
92
98
|
architecture_decision_workshop: z.unknown().optional().describe("架构设计前已讨论并确认的六域决策记录"),
|
|
99
|
+
decision_workshop: z.unknown().optional().describe("通用决策研讨合同(技术选型/数据迁移/安全策略/部署/重构/第三方集成等)"),
|
|
93
100
|
design_artifact_pack: z.unknown().optional().describe("设计产物包路径映射或已复验状态"),
|
|
101
|
+
ood_solid_summary: z.unknown().optional().describe("复杂编码任务的 OOD/SOLID 设计摘要"),
|
|
102
|
+
backend_implementation_work_package: z.unknown().optional().describe("后端接口实现的工程工作包"),
|
|
94
103
|
};
|
|
95
104
|
const VerifySchema = {
|
|
96
105
|
task_id: z.string().describe("任务 ID"),
|
|
@@ -139,6 +148,24 @@ const RecordVerificationExecutionSchema = {
|
|
|
139
148
|
evidence_id: z.string().describe("执行证据 ID"),
|
|
140
149
|
})).describe("真实执行记录列表"),
|
|
141
150
|
};
|
|
151
|
+
const AcceptSchema = {
|
|
152
|
+
task_id: z.string().describe("任务 ID"),
|
|
153
|
+
confirm: z.boolean().describe("用户显式确认验收结果,必须为 true"),
|
|
154
|
+
confirmed_by: z.string().describe("执行确认的用户或审批者标识"),
|
|
155
|
+
confirmation_ref: z.string().describe("可审计的用户确认引用"),
|
|
156
|
+
acceptance_notes: z.string().describe("验收备注或不适用理由"),
|
|
157
|
+
run_mode: z.enum(["manual_review", "not_applicable"]).describe("验收模式"),
|
|
158
|
+
final_access: z.object({
|
|
159
|
+
frontend_urls: z.array(z.string()),
|
|
160
|
+
backend_urls: z.array(z.string()),
|
|
161
|
+
docs_or_swagger_urls: z.array(z.string()),
|
|
162
|
+
start_commands: z.array(z.string()),
|
|
163
|
+
stop_commands: z.array(z.string()),
|
|
164
|
+
running_status: z.string(),
|
|
165
|
+
manual_review_steps_zh: z.array(z.string()),
|
|
166
|
+
known_limits_zh: z.array(z.string()),
|
|
167
|
+
}).optional().describe("manual_review 模式下的真实本地访问证据"),
|
|
168
|
+
};
|
|
142
169
|
const DeliverSchema = {
|
|
143
170
|
task_id: z.string().describe("任务 ID"),
|
|
144
171
|
changed_files: z.array(z.string()).optional().describe("变更文件列表(不传则使用任务记录中的文件)"),
|
|
@@ -222,7 +249,7 @@ export function checkWriteToolPlanGate(params) {
|
|
|
222
249
|
}
|
|
223
250
|
/**
|
|
224
251
|
* 施工指令契约门 — 写操作前检查施工指令完整性。
|
|
225
|
-
*
|
|
252
|
+
* 通过引擎模块函数真实消费。
|
|
226
253
|
* 调用链 1: registerInstructionIssueCandidate(无契约时创建候选 draft)
|
|
227
254
|
* 调用链 2: enforceInstructionBeforeImplementation → checkInstructionCompleteness → validateInstructionContract
|
|
228
255
|
*/
|
|
@@ -282,7 +309,7 @@ export function checkDesignArtifactWriteGate(params) {
|
|
|
282
309
|
}
|
|
283
310
|
/**
|
|
284
311
|
* 架构设计门 — 架构设计类任务膨胀前执行 reviewArchitectureDesign。
|
|
285
|
-
*
|
|
312
|
+
* Architecture Design Contract enforcement。
|
|
286
313
|
*/
|
|
287
314
|
export async function checkArchitectureDesignGate(params) {
|
|
288
315
|
const route = params.route;
|
|
@@ -309,7 +336,7 @@ export async function checkArchitectureDesignGate(params) {
|
|
|
309
336
|
}
|
|
310
337
|
/**
|
|
311
338
|
* 架构决策研讨门 — 正式架构设计前六域决策必须闭合。
|
|
312
|
-
*
|
|
339
|
+
* 与是否存在施工指令契约无关,架构设计路由必经此门。
|
|
313
340
|
*/
|
|
314
341
|
export async function checkArchitectureDecisionWorkshopGate(params) {
|
|
315
342
|
const workshopModule = await lazyArchitectureWorkshop();
|
|
@@ -333,7 +360,7 @@ export async function checkArchitectureDecisionWorkshopGate(params) {
|
|
|
333
360
|
}
|
|
334
361
|
/**
|
|
335
362
|
* 现有系统分析门 — 现有项目编码前必须先做分析。
|
|
336
|
-
*
|
|
363
|
+
* Existing System Analysis Contract enforcement。
|
|
337
364
|
*/
|
|
338
365
|
export async function checkExistingSystemAnalysisGate(params) {
|
|
339
366
|
const archModule = await lazyExistingSystemAnalysis();
|
|
@@ -350,7 +377,7 @@ export async function checkExistingSystemAnalysisGate(params) {
|
|
|
350
377
|
}
|
|
351
378
|
/**
|
|
352
379
|
* 编码就绪门 — 编码前必须有测试计划 + 验收标准。
|
|
353
|
-
*
|
|
380
|
+
* Coding Readiness / Test-First enforcement。
|
|
354
381
|
*/
|
|
355
382
|
export async function checkCodingReadinessGate(params) {
|
|
356
383
|
if (!params.ctx)
|
|
@@ -375,7 +402,7 @@ export async function checkCodingReadinessGate(params) {
|
|
|
375
402
|
}
|
|
376
403
|
/**
|
|
377
404
|
* 本地验收门 — 前端/全栈交付前必须有本地访问证据。
|
|
378
|
-
*
|
|
405
|
+
* Local Docker / Browser Acceptance enforcement。
|
|
379
406
|
*/
|
|
380
407
|
export async function checkLocalAcceptanceGate(params) {
|
|
381
408
|
const acceptanceModule = await lazyLocalAcceptance();
|
|
@@ -397,6 +424,21 @@ export async function checkLocalAcceptanceGate(params) {
|
|
|
397
424
|
required_but_missing: ["local_acceptance_evidence", "final_access_url"],
|
|
398
425
|
};
|
|
399
426
|
}
|
|
427
|
+
if (evidence.run_mode === "not_applicable") {
|
|
428
|
+
return {
|
|
429
|
+
allowed: false,
|
|
430
|
+
reason_zh: "该项目需要本地验收,不得以 not_applicable 代替真实访问证据",
|
|
431
|
+
required_but_missing: ["manual_review", "final_access_url"],
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const finalAccessResult = acceptanceModule.validateFinalAccess(evidence.final_access, requirement.run_mode);
|
|
435
|
+
if (!finalAccessResult.passed) {
|
|
436
|
+
return {
|
|
437
|
+
allowed: false,
|
|
438
|
+
reason_zh: `本地验收证据不完整: ${finalAccessResult.blocking_reasons.join("; ")}`,
|
|
439
|
+
required_but_missing: ["validated_final_access"],
|
|
440
|
+
};
|
|
441
|
+
}
|
|
400
442
|
return { allowed: true };
|
|
401
443
|
}
|
|
402
444
|
// ── S4 触发判定函数 ──
|
|
@@ -485,7 +527,7 @@ export function requiresBrainstorm(ctx, route) {
|
|
|
485
527
|
}
|
|
486
528
|
/**
|
|
487
529
|
* 技术选型决策门 — 高影响技术决策需用户确认。
|
|
488
|
-
*
|
|
530
|
+
* Decision Sovereignty enforcement。
|
|
489
531
|
* 不依赖 hasInstructionContract — 触发由 requiresDecisionSovereignty 判定。
|
|
490
532
|
*/
|
|
491
533
|
export async function checkDecisionSovereigntyGate(params) {
|
|
@@ -525,7 +567,7 @@ export async function checkDecisionSovereigntyGate(params) {
|
|
|
525
567
|
}
|
|
526
568
|
/**
|
|
527
569
|
* 细节纪律门 — 复杂任务缺关键细节维度时阻断。
|
|
528
|
-
*
|
|
570
|
+
* Detail Discipline enforcement。
|
|
529
571
|
* 不依赖 hasInstructionContract — 触发由 requiresDetailDiscipline 判定。
|
|
530
572
|
*/
|
|
531
573
|
export async function checkDetailDisciplineGate(params) {
|
|
@@ -550,7 +592,7 @@ export async function checkDetailDisciplineGate(params) {
|
|
|
550
592
|
}
|
|
551
593
|
/**
|
|
552
594
|
* 第一性原理门 — 高影响任务需目标/约束/本质问题/权衡。
|
|
553
|
-
*
|
|
595
|
+
* First Principles enforcement。
|
|
554
596
|
* 不依赖 hasInstructionContract — 触发由 requiresFirstPrinciples 判定。
|
|
555
597
|
*/
|
|
556
598
|
export async function checkFirstPrinciplesGate(params) {
|
|
@@ -573,7 +615,7 @@ export async function checkFirstPrinciplesGate(params) {
|
|
|
573
615
|
}
|
|
574
616
|
/**
|
|
575
617
|
* 脑暴/方案探索门 — 不确定项需多方案+推荐理由+用户确认。
|
|
576
|
-
*
|
|
618
|
+
* Brainstorm Contract enforcement。
|
|
577
619
|
* 不依赖 hasInstructionContract — 触发由 requiresBrainstorm 判定。
|
|
578
620
|
*/
|
|
579
621
|
export async function checkBrainstormGate(params) {
|
|
@@ -784,12 +826,14 @@ export async function registerTools(server, deps) {
|
|
|
784
826
|
}
|
|
785
827
|
/** State precheck: validate task status before contract guard */
|
|
786
828
|
const STATE_PRECHECKS = {
|
|
829
|
+
sf_accept: ["executing", "verifying", "retrying"],
|
|
787
830
|
sf_verify: ["executing", "retrying"],
|
|
788
831
|
sf_record_verification_execution: ["verifying", "executing"],
|
|
789
832
|
sf_learn: ["verifying", "executing"],
|
|
790
833
|
sf_expand: ["classifying", "expanding", "clarifying"],
|
|
791
834
|
};
|
|
792
835
|
const STATE_ERROR_LABELS = {
|
|
836
|
+
sf_accept: "不可验收",
|
|
793
837
|
sf_verify: "不可验证",
|
|
794
838
|
sf_record_verification_execution: "不可录入验证结果",
|
|
795
839
|
sf_learn: "不可学习",
|
|
@@ -1090,13 +1134,19 @@ export async function registerTools(server, deps) {
|
|
|
1090
1134
|
// 从 { result } 模式中提取数据
|
|
1091
1135
|
const data = raw?.result !== undefined ? raw.result : raw;
|
|
1092
1136
|
const hasError = !!(data && typeof data === "object" && "error" in data);
|
|
1093
|
-
|
|
1137
|
+
const recoveryNextTools = hasError && Array.isArray(data.recovery_next_tools)
|
|
1138
|
+
? data.recovery_next_tools
|
|
1139
|
+
: contract.default_next_tools;
|
|
1140
|
+
const recoveryForbiddenTools = hasError && Array.isArray(data.recovery_forbidden_tools)
|
|
1141
|
+
? data.recovery_forbidden_tools
|
|
1142
|
+
: contract.forbidden_next_tools;
|
|
1143
|
+
// 构建 trace;失败处理器可显式开放修复重验路径
|
|
1094
1144
|
const trace = createToolTrace({
|
|
1095
1145
|
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
1096
1146
|
workflow_id: ctx?.expansion?.workflow_trace?.workflow_id,
|
|
1097
1147
|
actual_side_effects: effectiveSideEffects,
|
|
1098
|
-
next_allowed_tools:
|
|
1099
|
-
forbidden_tools:
|
|
1148
|
+
next_allowed_tools: recoveryNextTools,
|
|
1149
|
+
forbidden_tools: recoveryForbiddenTools,
|
|
1100
1150
|
authorization, bypass,
|
|
1101
1151
|
});
|
|
1102
1152
|
// 将 trace 写入 TaskContext
|
|
@@ -1107,8 +1157,8 @@ export async function registerTools(server, deps) {
|
|
|
1107
1157
|
const response = {
|
|
1108
1158
|
...data,
|
|
1109
1159
|
tool_trace: trace,
|
|
1110
|
-
next_allowed_tools:
|
|
1111
|
-
forbidden_tools:
|
|
1160
|
+
next_allowed_tools: recoveryNextTools,
|
|
1161
|
+
forbidden_tools: recoveryForbiddenTools,
|
|
1112
1162
|
};
|
|
1113
1163
|
// 基于状态的回退: 在响应中暴露降级 workflow
|
|
1114
1164
|
if (authorization.reason === "task in valid state for tool") {
|
|
@@ -1205,9 +1255,33 @@ export async function registerTools(server, deps) {
|
|
|
1205
1255
|
debug("工具注册", "批量注册核心/辅助/知识维护工具...");
|
|
1206
1256
|
// ── sf_classify: 意图分类入口,创建任务上下文并返回分类结果 ──
|
|
1207
1257
|
registerSafeTool("sf_classify", "分析开发者意图,返回任务类型、风险、复杂度和执行策略", ClassifySchema, async (args) => {
|
|
1258
|
+
const asksForNavigation = /(?:下一步|继续(?:做|执行|开发)?|现在(?:可以|能)(?:开始)?(?:写代码|编码|开发|测试|交付)|接下来(?:做什么|该做什么)|该(?:做什么|怎么继续))/i.test(args.intent);
|
|
1259
|
+
if (asksForNavigation) {
|
|
1260
|
+
const navigation = await (await lazyNavigation()).planNextAction(projectPath);
|
|
1261
|
+
return {
|
|
1262
|
+
result: {
|
|
1263
|
+
status: "navigation_required",
|
|
1264
|
+
reason_zh: "检测到阶段推进意图,必须先依据 SoloForge 状态规划下一步",
|
|
1265
|
+
navigation,
|
|
1266
|
+
},
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1208
1269
|
// 检查是否存在进行中的任务
|
|
1209
1270
|
const existing = await taskContext.getCurrentTask();
|
|
1210
1271
|
if (existing && !["done", "failed"].includes(existing.status)) {
|
|
1272
|
+
const navigation = await (await lazyNavigation()).planNextAction(projectPath);
|
|
1273
|
+
if (navigation.stale_task?.is_stale) {
|
|
1274
|
+
return {
|
|
1275
|
+
result: {
|
|
1276
|
+
status: "stale_task_requires_resolution",
|
|
1277
|
+
error: "存在陈旧任务指针,必须先选择恢复、归档或开始新任务",
|
|
1278
|
+
existing_task_id: existing.task_id,
|
|
1279
|
+
existing_status: existing.status,
|
|
1280
|
+
navigation,
|
|
1281
|
+
hint: "先调用 sf_navigation 查看可执行处理步骤,不得绕过 SoloForge 状态直接分析或编码",
|
|
1282
|
+
},
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1211
1285
|
return {
|
|
1212
1286
|
result: {
|
|
1213
1287
|
error: "存在未完成的任务",
|
|
@@ -1244,10 +1318,20 @@ export async function registerTools(server, deps) {
|
|
|
1244
1318
|
if (args.architecture_decision_workshop) {
|
|
1245
1319
|
ctx.architecture_decision_workshop = args.architecture_decision_workshop;
|
|
1246
1320
|
}
|
|
1321
|
+
if (args.decision_workshop) {
|
|
1322
|
+
ctx.decision_workshop = args.decision_workshop;
|
|
1323
|
+
}
|
|
1247
1324
|
if (args.design_artifact_pack) {
|
|
1248
1325
|
ctx.design_artifact_pack = args.design_artifact_pack;
|
|
1249
1326
|
}
|
|
1250
|
-
if (args.
|
|
1327
|
+
if (args.ood_solid_summary) {
|
|
1328
|
+
ctx.ood_solid_summary = args.ood_solid_summary;
|
|
1329
|
+
}
|
|
1330
|
+
if (args.backend_implementation_work_package) {
|
|
1331
|
+
ctx.backend_implementation_work_package = args.backend_implementation_work_package;
|
|
1332
|
+
}
|
|
1333
|
+
if (args.architecture_decision_workshop || args.decision_workshop || args.design_artifact_pack
|
|
1334
|
+
|| args.ood_solid_summary || args.backend_implementation_work_package) {
|
|
1251
1335
|
await taskContext.save(ctx);
|
|
1252
1336
|
}
|
|
1253
1337
|
// 状态守卫:classifying/expanding/clarifying → expanding
|
|
@@ -1330,6 +1414,39 @@ export async function registerTools(server, deps) {
|
|
|
1330
1414
|
gateway.endTask();
|
|
1331
1415
|
}
|
|
1332
1416
|
expansion.task_id = args.task_id;
|
|
1417
|
+
const projectRoot = fss.realpathSync(projectPath);
|
|
1418
|
+
const referencedMaterialPaths = new Set((expansion.input_materials ?? [])
|
|
1419
|
+
.map((material) => material.path_or_ref)
|
|
1420
|
+
.filter((materialPath) => typeof materialPath === "string" && materialPath.length > 0)
|
|
1421
|
+
.map((materialPath) => path.resolve(projectRoot, materialPath)));
|
|
1422
|
+
const confirmedProjectSourcePaths = (args.input_material_confirmations ?? [])
|
|
1423
|
+
.map((materialPath) => path.resolve(projectRoot, materialPath))
|
|
1424
|
+
.filter((absolutePath) => absolutePath === projectRoot || absolutePath.startsWith(`${projectRoot}${path.sep}`))
|
|
1425
|
+
.filter((absolutePath) => referencedMaterialPaths.has(absolutePath))
|
|
1426
|
+
.filter((absolutePath) => {
|
|
1427
|
+
try {
|
|
1428
|
+
return fss.statSync(absolutePath).isFile()
|
|
1429
|
+
&& fss.realpathSync(absolutePath).startsWith(`${projectRoot}${path.sep}`);
|
|
1430
|
+
}
|
|
1431
|
+
catch {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
});
|
|
1435
|
+
const registerConfirmedProjectSources = (registry) => {
|
|
1436
|
+
for (const absolutePath of confirmedProjectSourcePaths) {
|
|
1437
|
+
const sourceRef = path.relative(projectRoot, absolutePath);
|
|
1438
|
+
registry.register({
|
|
1439
|
+
source_type: "project_file",
|
|
1440
|
+
evidence_role: "project_source_file",
|
|
1441
|
+
authority: "authoritative",
|
|
1442
|
+
freshness: "current",
|
|
1443
|
+
permission: "allowed",
|
|
1444
|
+
scope: "confirmed_input_material",
|
|
1445
|
+
description: `已确认项目输入材料: ${sourceRef}`,
|
|
1446
|
+
source_ref: sourceRef,
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1333
1450
|
const workflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification.route_decision?.workflow_intent;
|
|
1334
1451
|
// 问题六十: 高风险项目事实声明先过证据门,避免后续架构研讨门遮蔽无证据问题。
|
|
1335
1452
|
{
|
|
@@ -1383,6 +1500,7 @@ export async function registerTools(server, deps) {
|
|
|
1383
1500
|
source_ref: `decision:${tdc.decision_id ?? args.task_id}`,
|
|
1384
1501
|
});
|
|
1385
1502
|
}
|
|
1503
|
+
registerConfirmedProjectSources(evg.registry);
|
|
1386
1504
|
const evClaims = [
|
|
1387
1505
|
{
|
|
1388
1506
|
id: "claim-expand-0",
|
|
@@ -1463,6 +1581,34 @@ export async function registerTools(server, deps) {
|
|
|
1463
1581
|
ctx.design_artifact_pack.user_confirmation_ref = ctx.architecture_decision_workshop?.document_output_confirmation_ref;
|
|
1464
1582
|
await taskContext.save(ctx);
|
|
1465
1583
|
}
|
|
1584
|
+
// 问题六十一(通用): 可组合决策包门禁
|
|
1585
|
+
const dwModule = await lazyDecisionWorkshop();
|
|
1586
|
+
const packMatch = dwModule.matchDecisionPacks({
|
|
1587
|
+
workflow_intent: workflowIntent,
|
|
1588
|
+
intent: ctx.intent,
|
|
1589
|
+
task_type: ctx.classification?.task_type,
|
|
1590
|
+
});
|
|
1591
|
+
// 过滤掉架构(架构由上面的专用子包处理)
|
|
1592
|
+
const nonArchPacks = packMatch.packs.filter((p) => p !== "architecture");
|
|
1593
|
+
if (nonArchPacks.length > 0) {
|
|
1594
|
+
const dwContract = ctx.decision_workshop ?? dwModule.createDecisionWorkshop(args.task_id, nonArchPacks, detectedArchitectureContext, packMatch.reasons.join(";"));
|
|
1595
|
+
const dwGate = dwModule.evaluateDecisionWorkshop(dwContract);
|
|
1596
|
+
ctx.decision_workshop = dwModule.applyDecisionWorkshopGate(dwContract);
|
|
1597
|
+
await taskContext.save(ctx);
|
|
1598
|
+
if (!dwGate.allowed) {
|
|
1599
|
+
return {
|
|
1600
|
+
result: {
|
|
1601
|
+
error: `${packMatch.reasons.join(";")},必须先完成决策研讨与用户确认`,
|
|
1602
|
+
status: "awaiting_confirmation",
|
|
1603
|
+
decision_workshop: ctx.decision_workshop,
|
|
1604
|
+
blocking_findings: dwGate.blocking_findings,
|
|
1605
|
+
next_domain: dwGate.next_domain,
|
|
1606
|
+
activated_packs: nonArchPacks,
|
|
1607
|
+
recovery: "请从当前待讨论域开始,提供候选方案、推荐理由、风险和用户确认后重新调用 sf_expand",
|
|
1608
|
+
},
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1466
1612
|
// 问题四十九/五十: 已有架构合同或现有系统证据的进一步审查。
|
|
1467
1613
|
const expansionRoute = expansion.workflow_trace
|
|
1468
1614
|
? expansion.workflow_trace?.route
|
|
@@ -1558,6 +1704,56 @@ export async function registerTools(server, deps) {
|
|
|
1558
1704
|
};
|
|
1559
1705
|
}
|
|
1560
1706
|
}
|
|
1707
|
+
// 问题六十六: 复杂业务编码必须先具备对象职责、接口和依赖方向摘要。
|
|
1708
|
+
{
|
|
1709
|
+
const oodModule = await lazyOodSolid();
|
|
1710
|
+
const oodGate = oodModule.evaluateOodDesignGate({
|
|
1711
|
+
task_id: args.task_id,
|
|
1712
|
+
intent: ctx.intent,
|
|
1713
|
+
route: expansionRoute,
|
|
1714
|
+
summary: ctx.ood_solid_summary,
|
|
1715
|
+
});
|
|
1716
|
+
if (oodGate.applicable) {
|
|
1717
|
+
ctx.ood_solid_summary = oodGate.required_summary;
|
|
1718
|
+
await taskContext.save(ctx);
|
|
1719
|
+
}
|
|
1720
|
+
if (!oodGate.allowed) {
|
|
1721
|
+
return {
|
|
1722
|
+
result: {
|
|
1723
|
+
error: oodGate.reason_zh,
|
|
1724
|
+
status: "awaiting_ood_design",
|
|
1725
|
+
diagnostic_code: "SF-OOD-6601",
|
|
1726
|
+
ood_solid_summary: oodGate.required_summary,
|
|
1727
|
+
recovery: "请确认对象职责、接口边界、依赖方向、变化点和 SOLID 风险后重新调用 sf_expand",
|
|
1728
|
+
},
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
// 问题六十七: 后端接口编码必须先确认工程边界与验收证据。
|
|
1733
|
+
{
|
|
1734
|
+
const backendModule = await lazyBackendImplementation();
|
|
1735
|
+
const backendGate = backendModule.evaluateBackendImplementationGate({
|
|
1736
|
+
task_id: args.task_id,
|
|
1737
|
+
intent: ctx.intent,
|
|
1738
|
+
route: expansionRoute,
|
|
1739
|
+
work_package: ctx.backend_implementation_work_package,
|
|
1740
|
+
});
|
|
1741
|
+
if (backendGate.applicable) {
|
|
1742
|
+
ctx.backend_implementation_work_package = backendGate.work_package;
|
|
1743
|
+
await taskContext.save(ctx);
|
|
1744
|
+
}
|
|
1745
|
+
if (!backendGate.allowed) {
|
|
1746
|
+
return {
|
|
1747
|
+
result: {
|
|
1748
|
+
error: backendGate.reason_zh,
|
|
1749
|
+
status: "awaiting_backend_contract",
|
|
1750
|
+
diagnostic_code: "SF-BACKEND-6701",
|
|
1751
|
+
backend_implementation_work_package: backendGate.work_package,
|
|
1752
|
+
recovery: "请补齐 DTO/校验、事务一致性、安全审计、契约对齐与测试证据后重新调用 sf_expand",
|
|
1753
|
+
},
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1561
1757
|
// Input Material Contract: 处理 hard-blocking 结果
|
|
1562
1758
|
// Privacy Gate: 隐私/敏感信息策略阻断
|
|
1563
1759
|
const isBlocked = expansion.prompt.startsWith("## 阻塞:输入材料禁止读取")
|
|
@@ -1628,6 +1824,7 @@ export async function registerTools(server, deps) {
|
|
|
1628
1824
|
source_ref: `decision:${_tdc.decision_id ?? args.task_id}`,
|
|
1629
1825
|
});
|
|
1630
1826
|
}
|
|
1827
|
+
registerConfirmedProjectSources(_evg.registry);
|
|
1631
1828
|
const _evClaims = [
|
|
1632
1829
|
{
|
|
1633
1830
|
id: "claim-expand-0",
|
|
@@ -1761,6 +1958,102 @@ export async function registerTools(server, deps) {
|
|
|
1761
1958
|
result: { error: "任务不存在" },
|
|
1762
1959
|
};
|
|
1763
1960
|
}
|
|
1961
|
+
const implementationFiles = args.changed_files.filter((file) => /\.(?:ts|tsx|js|jsx|java|kt|cs|go|py)$/.test(file)
|
|
1962
|
+
&& !/(?:^|\/)tests?\//.test(file));
|
|
1963
|
+
if (implementationFiles.length > 0) {
|
|
1964
|
+
const implementationContents = {};
|
|
1965
|
+
for (const changedFile of implementationFiles) {
|
|
1966
|
+
const absoluteFile = path.resolve(projectPath, changedFile);
|
|
1967
|
+
try {
|
|
1968
|
+
if (absoluteFile.startsWith(`${path.resolve(projectPath)}${path.sep}`) && fss.statSync(absoluteFile).isFile()) {
|
|
1969
|
+
implementationContents[changedFile] = fss.readFileSync(absoluteFile, "utf-8");
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
catch {
|
|
1973
|
+
// 文件缺失会由验证命令或现有产物检查报告。
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
const oodModule = await lazyOodSolid();
|
|
1977
|
+
const oodGate = oodModule.evaluateOodDesignGate({
|
|
1978
|
+
task_id: args.task_id,
|
|
1979
|
+
intent: ctx.intent,
|
|
1980
|
+
route: ctx.expansion?.workflow_trace?.route,
|
|
1981
|
+
changed_files: implementationFiles,
|
|
1982
|
+
summary: ctx.ood_solid_summary,
|
|
1983
|
+
});
|
|
1984
|
+
if (!oodGate.allowed) {
|
|
1985
|
+
return {
|
|
1986
|
+
result: {
|
|
1987
|
+
error: oodGate.reason_zh,
|
|
1988
|
+
status: "blocked",
|
|
1989
|
+
diagnostic_code: "SF-OOD-6601",
|
|
1990
|
+
ood_solid_summary: oodGate.required_summary,
|
|
1991
|
+
recovery: "完成 OOD/SOLID 摘要后重新执行 sf_expand 与 sf_verify",
|
|
1992
|
+
},
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
const backendModule = await lazyBackendImplementation();
|
|
1996
|
+
const backendGate = backendModule.evaluateBackendImplementationGate({
|
|
1997
|
+
task_id: args.task_id,
|
|
1998
|
+
intent: ctx.intent,
|
|
1999
|
+
route: ctx.expansion?.workflow_trace?.route,
|
|
2000
|
+
changed_files: implementationFiles,
|
|
2001
|
+
work_package: ctx.backend_implementation_work_package,
|
|
2002
|
+
});
|
|
2003
|
+
if (!backendGate.allowed) {
|
|
2004
|
+
return {
|
|
2005
|
+
result: {
|
|
2006
|
+
error: backendGate.reason_zh,
|
|
2007
|
+
status: "blocked",
|
|
2008
|
+
diagnostic_code: "SF-BACKEND-6701",
|
|
2009
|
+
backend_implementation_work_package: backendGate.work_package,
|
|
2010
|
+
recovery: "完成后端工程工作包后重新执行 sf_expand 与 sf_verify",
|
|
2011
|
+
},
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
const solidFindings = oodGate.applicable ? oodModule.reviewSolidCode(implementationContents) : [];
|
|
2015
|
+
const backendFindings = backendGate.applicable ? backendModule.reviewBackendImplementationFiles(implementationContents) : [];
|
|
2016
|
+
if (backendGate.applicable) {
|
|
2017
|
+
const openApiPath = path.join(projectPath, "docs", "api", "openapi.yaml");
|
|
2018
|
+
const apiMarkdownPath = path.join(projectPath, "docs", "architecture", "03-API接口规格文档.md");
|
|
2019
|
+
const migrationDirectory = path.join(projectPath, "db", "migrations");
|
|
2020
|
+
const openapiText = fss.existsSync(openApiPath) ? fss.readFileSync(openApiPath, "utf-8") : undefined;
|
|
2021
|
+
const apiDocumentText = fss.existsSync(apiMarkdownPath) ? fss.readFileSync(apiMarkdownPath, "utf-8") : undefined;
|
|
2022
|
+
const migrationText = fss.existsSync(migrationDirectory)
|
|
2023
|
+
? fss.readdirSync(migrationDirectory).filter((name) => /\.sql$/i.test(name))
|
|
2024
|
+
.map((name) => fss.readFileSync(path.join(migrationDirectory, name), "utf-8")).join("\n")
|
|
2025
|
+
: undefined;
|
|
2026
|
+
backendFindings.push(...backendModule.verifyBackendArtifactAlignment({
|
|
2027
|
+
openapiText,
|
|
2028
|
+
apiDocumentText,
|
|
2029
|
+
migrationText,
|
|
2030
|
+
sourceFiles: implementationContents,
|
|
2031
|
+
}));
|
|
2032
|
+
}
|
|
2033
|
+
ctx.ood_solid_findings = solidFindings;
|
|
2034
|
+
ctx.backend_implementation_findings = backendFindings;
|
|
2035
|
+
await taskContext.save(ctx);
|
|
2036
|
+
if (oodModule.hasBlockingSolidFindings(solidFindings)) {
|
|
2037
|
+
return {
|
|
2038
|
+
result: {
|
|
2039
|
+
error: "OOD/SOLID 代码复验发现阻断项,需修复后重验",
|
|
2040
|
+
status: "blocked",
|
|
2041
|
+
diagnostic_code: "SF-OOD-6602",
|
|
2042
|
+
ood_solid_findings: solidFindings,
|
|
2043
|
+
},
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
if (backendModule.hasBlockingBackendFindings(backendFindings)) {
|
|
2047
|
+
return {
|
|
2048
|
+
result: {
|
|
2049
|
+
error: "后端实现工程复验发现阻断项,需修复后重验",
|
|
2050
|
+
status: "blocked",
|
|
2051
|
+
diagnostic_code: "SF-BACKEND-6702",
|
|
2052
|
+
backend_implementation_findings: backendFindings,
|
|
2053
|
+
},
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
1764
2057
|
// 问题六十二: 设计产物验证必须读取用户项目真实文件,不接受占位合同自证通过。
|
|
1765
2058
|
const verifyWorkflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification?.route_decision?.workflow_intent;
|
|
1766
2059
|
const touchesDesignArtifacts = args.changed_files.some((file) => /docs\/architecture\/|docs\/api\/|openapi|db\/(?:migrations|schema)|架构设计|数据库设计|API接口规格/i.test(file));
|
|
@@ -1789,6 +2082,83 @@ export async function registerTools(server, deps) {
|
|
|
1789
2082
|
};
|
|
1790
2083
|
}
|
|
1791
2084
|
}
|
|
2085
|
+
// 问题六十三: 模板契约验证 — 按文件逐一匹配契约并校验
|
|
2086
|
+
const sacModule = await lazyStandardAssetContract();
|
|
2087
|
+
const formalArtifactContract = sacModule.matchTemplateContract({
|
|
2088
|
+
output_artifact_kind: ctx.artifact_output?.kind,
|
|
2089
|
+
workflow_intent: verifyWorkflowIntent,
|
|
2090
|
+
route_decision: ctx.route_decision?.workflow_intent,
|
|
2091
|
+
});
|
|
2092
|
+
if (formalArtifactContract || !sacModule.isLowRiskTask({
|
|
2093
|
+
route_decision: verifyWorkflowIntent ?? ctx.classification?.route_decision?.workflow_intent,
|
|
2094
|
+
workflow_intent: verifyWorkflowIntent,
|
|
2095
|
+
changed_files: args.changed_files,
|
|
2096
|
+
})) {
|
|
2097
|
+
for (const changedFile of args.changed_files) {
|
|
2098
|
+
const absFile = path.join(projectPath, changedFile);
|
|
2099
|
+
if (!fss.existsSync(absFile) || !/\.md$/.test(changedFile))
|
|
2100
|
+
continue;
|
|
2101
|
+
// 按实际文件路径匹配契约(不再使用 changed_files[0] 的契约校验全部文件)
|
|
2102
|
+
const perFileContract = sacModule.matchTemplateContract({
|
|
2103
|
+
output_artifact_kind: ctx.artifact_output?.kind,
|
|
2104
|
+
workflow_intent: verifyWorkflowIntent,
|
|
2105
|
+
route_decision: ctx.route_decision?.workflow_intent,
|
|
2106
|
+
file_path: changedFile,
|
|
2107
|
+
});
|
|
2108
|
+
if (!perFileContract)
|
|
2109
|
+
continue;
|
|
2110
|
+
const content = fss.readFileSync(absFile, "utf-8");
|
|
2111
|
+
// 草稿阻断下游消费 — 不再静默跳过
|
|
2112
|
+
if (sacModule.isDraftDocument(content)) {
|
|
2113
|
+
ctx.repair_reverify_directive = {
|
|
2114
|
+
contract_id: perFileContract.asset_id,
|
|
2115
|
+
file_path: changedFile,
|
|
2116
|
+
status: "draft_blocked",
|
|
2117
|
+
repair_suggestion: `文件 ${changedFile} 仍为草稿状态,草稿不可用于实现。请完善内容后重新验证。`,
|
|
2118
|
+
blocked: true,
|
|
2119
|
+
};
|
|
2120
|
+
await taskContext.save(ctx);
|
|
2121
|
+
return {
|
|
2122
|
+
result: {
|
|
2123
|
+
error: `草稿文件 ${changedFile} 不可用于实现,需完善后重新验证`,
|
|
2124
|
+
status: "blocked",
|
|
2125
|
+
diagnostic_code: "SF-CONTRACT-DRAFT",
|
|
2126
|
+
template_contract_id: perFileContract.asset_id,
|
|
2127
|
+
recovery: "完善草稿内容后重新执行 sf_verify",
|
|
2128
|
+
},
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
const contractResult = sacModule.verifyOutputAgainstContract(perFileContract, content, projectPath);
|
|
2132
|
+
if (!contractResult.passed) {
|
|
2133
|
+
const repairDirective = sacModule.createRepairReverifyDirective(perFileContract, contractResult);
|
|
2134
|
+
ctx.repair_reverify_directive = {
|
|
2135
|
+
contract_id: perFileContract.asset_id,
|
|
2136
|
+
file_path: changedFile,
|
|
2137
|
+
status: "repair_required",
|
|
2138
|
+
repair_suggestion: repairDirective.repair_suggestion,
|
|
2139
|
+
blocked: true,
|
|
2140
|
+
};
|
|
2141
|
+
await taskContext.save(ctx);
|
|
2142
|
+
return {
|
|
2143
|
+
result: {
|
|
2144
|
+
error: `文件 ${changedFile} 模板契约验证未通过,进入修复重验闭环`,
|
|
2145
|
+
status: "blocked",
|
|
2146
|
+
diagnostic_code: "SF-CONTRACT-0003",
|
|
2147
|
+
template_contract_id: perFileContract.asset_id,
|
|
2148
|
+
missing_fields: contractResult.missing_fields,
|
|
2149
|
+
messages: contractResult.messages,
|
|
2150
|
+
repair_suggestion: repairDirective.repair_suggestion,
|
|
2151
|
+
recovery: "修复文档缺口后重新执行 sf_verify;不得只报告不修复",
|
|
2152
|
+
},
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
// 全部契约验证通过 — 清零修复重验指令
|
|
2157
|
+
if (ctx.repair_reverify_directive) {
|
|
2158
|
+
delete ctx.repair_reverify_directive;
|
|
2159
|
+
await taskContext.save(ctx);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
1792
2162
|
// RouteDecision 合同验证 — 无条件,在状态预检之前
|
|
1793
2163
|
const rdFromCtx = ctx.route_decision ?? ctx.classification?.route_decision ?? null;
|
|
1794
2164
|
const wtFromCtx = ctx.workflow_trace ?? ctx.expansion?.workflow_trace ?? null;
|
|
@@ -2445,12 +2815,55 @@ export async function registerTools(server, deps) {
|
|
|
2445
2815
|
}, tracker);
|
|
2446
2816
|
result.task_id = args.task_id;
|
|
2447
2817
|
await taskContext.setCodeReview(args.task_id, result);
|
|
2818
|
+
const contractContents = { ...(args.file_contents ?? {}) };
|
|
2819
|
+
for (const changedFile of args.changed_files) {
|
|
2820
|
+
if (contractContents[changedFile] !== undefined)
|
|
2821
|
+
continue;
|
|
2822
|
+
const absoluteFile = path.resolve(projectPath, changedFile);
|
|
2823
|
+
try {
|
|
2824
|
+
if (absoluteFile.startsWith(`${path.resolve(projectPath)}${path.sep}`) && fss.statSync(absoluteFile).isFile()) {
|
|
2825
|
+
contractContents[changedFile] = fss.readFileSync(absoluteFile, "utf-8");
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
catch {
|
|
2829
|
+
// 无法读取的文件留给现有 reviewer 报告,不制造假结论。
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
const oodModule = await lazyOodSolid();
|
|
2833
|
+
const solidFindings = oodModule.requiresOodSolidContract(ctx.intent, ctx.expansion?.workflow_trace?.route, args.changed_files)
|
|
2834
|
+
|| ctx.ood_solid_summary
|
|
2835
|
+
? [
|
|
2836
|
+
...oodModule.reviewSolidCode(contractContents),
|
|
2837
|
+
...oodModule.evaluateOverdesignRisk(ctx.intent, ctx.ood_solid_summary),
|
|
2838
|
+
]
|
|
2839
|
+
: [];
|
|
2840
|
+
const backendModule = await lazyBackendImplementation();
|
|
2841
|
+
const backendFindings = backendModule.requiresBackendImplementationContract(ctx.intent, ctx.expansion?.workflow_trace?.route, args.changed_files)
|
|
2842
|
+
|| ctx.backend_implementation_work_package
|
|
2843
|
+
? backendModule.reviewBackendImplementationFiles(contractContents)
|
|
2844
|
+
: [];
|
|
2845
|
+
if (solidFindings.length > 0 || backendFindings.length > 0) {
|
|
2846
|
+
const updatedCtx = await taskContext.load(args.task_id);
|
|
2847
|
+
if (updatedCtx) {
|
|
2848
|
+
updatedCtx.ood_solid_findings = solidFindings;
|
|
2849
|
+
updatedCtx.backend_implementation_findings = backendFindings;
|
|
2850
|
+
await taskContext.save(updatedCtx);
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2448
2853
|
// 决策契约 advisory: 校验 review 输出
|
|
2449
2854
|
const decisionContract = (await lazyDecision()).validateDecisionOutput(result);
|
|
2450
2855
|
const reviewExtras = {};
|
|
2451
2856
|
if (!decisionContract.passed) {
|
|
2452
2857
|
reviewExtras.decision_contract_advisory = decisionContract.advisory;
|
|
2453
2858
|
}
|
|
2859
|
+
if (solidFindings.length > 0)
|
|
2860
|
+
reviewExtras.ood_solid_findings = solidFindings;
|
|
2861
|
+
if (backendFindings.length > 0)
|
|
2862
|
+
reviewExtras.backend_implementation_findings = backendFindings;
|
|
2863
|
+
if (oodModule.hasBlockingSolidFindings(solidFindings) || backendModule.hasBlockingBackendFindings(backendFindings)) {
|
|
2864
|
+
reviewExtras.delivery_blocked = true;
|
|
2865
|
+
reviewExtras.diagnostic_code = "SF-IMPLEMENTATION-CONTRACT-REVIEW-BLOCKED";
|
|
2866
|
+
}
|
|
2454
2867
|
return { result: Object.keys(reviewExtras).length > 0 ? { ...result, ...reviewExtras } : result };
|
|
2455
2868
|
});
|
|
2456
2869
|
// ── sf_scaffold: 生成标准化代码骨架 ──
|
|
@@ -2481,6 +2894,103 @@ export async function registerTools(server, deps) {
|
|
|
2481
2894
|
};
|
|
2482
2895
|
});
|
|
2483
2896
|
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
2897
|
+
// ── sf_accept: 记录任务验收证据(本地验收 + 产物确认) ──
|
|
2898
|
+
registerSafeTool("sf_accept", "记录任务验收证据,解除 sf_deliver 的本地验收门和产物确认门", AcceptSchema, async (args) => {
|
|
2899
|
+
const ctx = await taskContext.load(args.task_id);
|
|
2900
|
+
if (!ctx) {
|
|
2901
|
+
return { result: { error: "任务不存在" } };
|
|
2902
|
+
}
|
|
2903
|
+
const runMode = args.run_mode;
|
|
2904
|
+
const notes = String(args.acceptance_notes ?? "").trim();
|
|
2905
|
+
const confirmedBy = String(args.confirmed_by ?? "").trim();
|
|
2906
|
+
const confirmationRef = String(args.confirmation_ref ?? "").trim();
|
|
2907
|
+
if (args.confirm !== true || !confirmedBy || !confirmationRef || !notes) {
|
|
2908
|
+
return {
|
|
2909
|
+
result: {
|
|
2910
|
+
error: "验收必须包含显式确认、确认者、可审计确认引用和验收说明",
|
|
2911
|
+
diagnostic_code: "SF-ACCEPT-CONFIRMATION-REQUIRED",
|
|
2912
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2913
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2914
|
+
},
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
const currentVerification = ctx.verification_result ?? ctx.batch2_verification_result;
|
|
2918
|
+
if (currentVerification?.status !== "passed") {
|
|
2919
|
+
return {
|
|
2920
|
+
result: {
|
|
2921
|
+
error: "验收前必须已有真实执行并通过的 verification_result",
|
|
2922
|
+
diagnostic_code: "SF-ACCEPT-VERIFICATION-REQUIRED",
|
|
2923
|
+
recovery_next_tools: ["sf_verify", "sf_record_verification_execution", "sf_status"],
|
|
2924
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2925
|
+
},
|
|
2926
|
+
};
|
|
2927
|
+
}
|
|
2928
|
+
const evidenceRef = `acceptance:user_confirmation:${confirmationRef}`;
|
|
2929
|
+
if (runMode === "manual_review") {
|
|
2930
|
+
const acceptanceModule = await lazyLocalAcceptance();
|
|
2931
|
+
if (!args.final_access) {
|
|
2932
|
+
return {
|
|
2933
|
+
result: {
|
|
2934
|
+
error: "manual_review 验收缺少 final_access 真实访问证据",
|
|
2935
|
+
diagnostic_code: "SF-ACCEPT-FINAL-ACCESS-REQUIRED",
|
|
2936
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2937
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2938
|
+
},
|
|
2939
|
+
};
|
|
2940
|
+
}
|
|
2941
|
+
const finalAccessResult = acceptanceModule.validateFinalAccess(args.final_access, "local_dev_server");
|
|
2942
|
+
if (!finalAccessResult.passed) {
|
|
2943
|
+
return {
|
|
2944
|
+
result: {
|
|
2945
|
+
error: `manual_review 验收证据不完整: ${finalAccessResult.blocking_reasons.join("; ")}`,
|
|
2946
|
+
diagnostic_code: "SF-ACCEPT-FINAL-ACCESS-INVALID",
|
|
2947
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2948
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2949
|
+
},
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
// 设置本地验收证据
|
|
2954
|
+
ctx.local_acceptance_evidence = {
|
|
2955
|
+
status: runMode === "manual_review" ? "passed" : "not_applicable",
|
|
2956
|
+
run_mode: runMode,
|
|
2957
|
+
confirmed_by: confirmedBy,
|
|
2958
|
+
confirmation_ref: confirmationRef,
|
|
2959
|
+
final_access: args.final_access ?? {
|
|
2960
|
+
frontend_urls: [],
|
|
2961
|
+
backend_urls: [],
|
|
2962
|
+
docs_or_swagger_urls: [],
|
|
2963
|
+
start_commands: [],
|
|
2964
|
+
stop_commands: [],
|
|
2965
|
+
running_status: "not_started",
|
|
2966
|
+
manual_review_steps_zh: [notes],
|
|
2967
|
+
known_limits_zh: [],
|
|
2968
|
+
},
|
|
2969
|
+
evidence_refs: [evidenceRef],
|
|
2970
|
+
};
|
|
2971
|
+
await taskContext.save(ctx);
|
|
2972
|
+
let updatedCtx = ctx;
|
|
2973
|
+
// 产物确认必须经过统一生命周期校验,不直接改写 status。
|
|
2974
|
+
if (ctx.artifact_output && ctx.artifact_output.status === "verified") {
|
|
2975
|
+
updatedCtx = await taskContext.updateArtifactStatus(args.task_id, {
|
|
2976
|
+
status: "accepted",
|
|
2977
|
+
evidenceRef,
|
|
2978
|
+
hasAcceptance: true,
|
|
2979
|
+
}) ?? ctx;
|
|
2980
|
+
}
|
|
2981
|
+
return {
|
|
2982
|
+
result: {
|
|
2983
|
+
task_id: args.task_id,
|
|
2984
|
+
acceptance_status: "passed",
|
|
2985
|
+
run_mode: runMode,
|
|
2986
|
+
evidence_ref: evidenceRef,
|
|
2987
|
+
artifact_transition: updatedCtx.artifact_output
|
|
2988
|
+
? `${updatedCtx.artifact_output.status}`
|
|
2989
|
+
: "no_artifact",
|
|
2990
|
+
},
|
|
2991
|
+
};
|
|
2992
|
+
});
|
|
2993
|
+
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
2484
2994
|
registerSafeTool("sf_deliver", "验收后自动提交代码、推送、创建 PR 和生成变更日志", DeliverSchema, async (args) => {
|
|
2485
2995
|
const ctx = await taskContext.load(args.task_id);
|
|
2486
2996
|
if (!ctx) {
|
|
@@ -2493,6 +3003,42 @@ export async function registerTools(server, deps) {
|
|
|
2493
3003
|
const h4DeliverWarning = !deliverIntegrity.clean
|
|
2494
3004
|
? { warning: `H4 advisory: ${deliverIntegrity.message}`, dirty_files: deliverIntegrity.dirty_files }
|
|
2495
3005
|
: undefined;
|
|
3006
|
+
// 模板契约修复指令优先于通用产物状态提示,确保客户端获得可执行的修复重验路径。
|
|
3007
|
+
if (ctx.repair_reverify_directive) {
|
|
3008
|
+
return {
|
|
3009
|
+
result: {
|
|
3010
|
+
error: "存在未清零的模板契约修复指令,需完成修复重验后才能交付",
|
|
3011
|
+
diagnostic_code: "SF-CONTRACT-0003",
|
|
3012
|
+
repair_directive: ctx.repair_reverify_directive,
|
|
3013
|
+
recovery: "修复文档缺口后重新执行 sf_verify,验证通过后 repair_reverify_directive 自动清零",
|
|
3014
|
+
recovery_next_tools: ["sf_learn", "sf_verify", "sf_status"],
|
|
3015
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
3016
|
+
},
|
|
3017
|
+
};
|
|
3018
|
+
}
|
|
3019
|
+
// 问题六十六/六十七: 审查或验证阶段产生的工程硬失败不得进入交付。
|
|
3020
|
+
const oodModule = await lazyOodSolid();
|
|
3021
|
+
if (oodModule.hasBlockingSolidFindings(ctx.ood_solid_findings ?? [])) {
|
|
3022
|
+
return {
|
|
3023
|
+
result: {
|
|
3024
|
+
error: "OOD/SOLID 契约仍存在硬失败,不得交付",
|
|
3025
|
+
diagnostic_code: "SF-OOD-6602",
|
|
3026
|
+
findings: ctx.ood_solid_findings,
|
|
3027
|
+
recovery: "按 finding 修复职责或依赖边界,并重新执行 sf_review 与 sf_verify",
|
|
3028
|
+
},
|
|
3029
|
+
};
|
|
3030
|
+
}
|
|
3031
|
+
const backendModule = await lazyBackendImplementation();
|
|
3032
|
+
if (backendModule.hasBlockingBackendFindings(ctx.backend_implementation_findings ?? [])) {
|
|
3033
|
+
return {
|
|
3034
|
+
result: {
|
|
3035
|
+
error: "后端实现工程契约仍存在硬失败,不得交付",
|
|
3036
|
+
diagnostic_code: "SF-BACKEND-6702",
|
|
3037
|
+
findings: ctx.backend_implementation_findings,
|
|
3038
|
+
recovery: "按 finding 修复后端边界、安全或一致性问题,并重新执行 sf_review 与 sf_verify",
|
|
3039
|
+
},
|
|
3040
|
+
};
|
|
3041
|
+
}
|
|
2496
3042
|
// 产物状态门控: deliver 需要产物状态为 accepted 且有证据
|
|
2497
3043
|
if (ctx.artifact_output) {
|
|
2498
3044
|
const status = ctx.artifact_output.status;
|
|
@@ -2574,6 +3120,7 @@ export async function registerTools(server, deps) {
|
|
|
2574
3120
|
const metricsData = await (await lazyObservability()).collectDeliveryMetricSamples(taskContext.getStateDir());
|
|
2575
3121
|
// acceptanceConfig: 从项目配置推断 project_run_mode
|
|
2576
3122
|
const projectHasFrontend = config.tech_stack.frontend.lang && config.tech_stack.frontend.lang !== "none";
|
|
3123
|
+
const projectHasBackend = config.tech_stack.backend.lang && config.tech_stack.backend.lang !== "none";
|
|
2577
3124
|
const readinessReport = drModule.evaluateDeliveryReadiness(args.task_id, currentVResult, guardFindings, true, // scope_check — 已在 sf_verify 写入护栏中检查
|
|
2578
3125
|
deliverLease.conflicts.length === 0, // lease_check — 无冲突即通过
|
|
2579
3126
|
true, // privacy_check — 已在任务创建时脱敏
|
|
@@ -2603,7 +3150,7 @@ export async function registerTools(server, deps) {
|
|
|
2603
3150
|
const localAcceptanceGate = await checkLocalAcceptanceGate({
|
|
2604
3151
|
ctx,
|
|
2605
3152
|
hasFrontend: !!projectHasFrontend,
|
|
2606
|
-
hasBackend: !!
|
|
3153
|
+
hasBackend: !!projectHasBackend,
|
|
2607
3154
|
hasDockerCompose: false,
|
|
2608
3155
|
hasDockerfile: false,
|
|
2609
3156
|
});
|
|
@@ -2688,7 +3235,7 @@ export async function registerTools(server, deps) {
|
|
|
2688
3235
|
task_id: args.task_id,
|
|
2689
3236
|
verification_passed: currentVResult?.status === "passed",
|
|
2690
3237
|
build_passed: (currentVResult?.passed_commands ?? 0) > 0,
|
|
2691
|
-
browser_acceptance_passed: ctx.artifact_output?.status === "
|
|
3238
|
+
browser_acceptance_passed: ctx.artifact_output?.status === "accepted" || ctx.artifact_output === undefined,
|
|
2692
3239
|
guard_passed: guardFindings.length === 0 || guardFindings.every((f) => f.severity !== "hard_fail"),
|
|
2693
3240
|
evidence_sufficient: (currentVResult?.evidence_ids?.length ?? 0) > 0,
|
|
2694
3241
|
current_status: ctx.status === "done" ? "completed" : ctx.status,
|
|
@@ -3164,5 +3711,43 @@ export async function registerTools(server, deps) {
|
|
|
3164
3711
|
result: { text: lines.join("\n") },
|
|
3165
3712
|
};
|
|
3166
3713
|
});
|
|
3714
|
+
// ── sf_navigation: 工作流导航 — 问题六十五 ──
|
|
3715
|
+
const NavigationSchema = {
|
|
3716
|
+
type: "object",
|
|
3717
|
+
properties: {
|
|
3718
|
+
project_path: { type: "string", description: "项目路径(可选,默认当前目录)" },
|
|
3719
|
+
},
|
|
3720
|
+
required: [],
|
|
3721
|
+
};
|
|
3722
|
+
registerSafeTool("sf_navigation", "查询工作流导航: 当前项目阶段、任务阶段、下一步操作和禁止操作。用于\"下一步\"\"继续\"\"现在能写代码吗\"等模糊推进意图。不得靠模型经验回答,必须调用此工具获取真实导航状态", NavigationSchema, async (args) => {
|
|
3723
|
+
const projectPath = args.project_path || config._projectPath || process.cwd();
|
|
3724
|
+
const { planNextAction } = await import("../../engine/next_action_planner.js");
|
|
3725
|
+
const plan = await planNextAction(projectPath);
|
|
3726
|
+
return {
|
|
3727
|
+
result: {
|
|
3728
|
+
project_stage: plan.project_stage,
|
|
3729
|
+
task_stage: plan.task_stage,
|
|
3730
|
+
current_task_id: plan.current_task_id,
|
|
3731
|
+
confidence: plan.confidence,
|
|
3732
|
+
stage_evidence: plan.stage_evidence,
|
|
3733
|
+
blocking_reasons: plan.blocking_reasons,
|
|
3734
|
+
stale_task: plan.stale_task,
|
|
3735
|
+
work_package: plan.work_package ? {
|
|
3736
|
+
id: plan.work_package.id,
|
|
3737
|
+
goal_zh: plan.work_package.goal_zh,
|
|
3738
|
+
description_zh: plan.work_package.description_zh,
|
|
3739
|
+
action: plan.work_package.action,
|
|
3740
|
+
tool_name: plan.work_package.tool_name,
|
|
3741
|
+
must_read: plan.work_package.must_read,
|
|
3742
|
+
forbidden_changes: plan.work_package.forbidden_changes,
|
|
3743
|
+
expected_outputs: plan.work_package.expected_outputs,
|
|
3744
|
+
acceptance_commands: plan.work_package.acceptance_commands,
|
|
3745
|
+
} : null,
|
|
3746
|
+
disallowed_actions: plan.disallowed_actions,
|
|
3747
|
+
recommended_commands: plan.recommended_commands,
|
|
3748
|
+
recommended_prompt_zh: plan.recommended_prompt_zh,
|
|
3749
|
+
},
|
|
3750
|
+
};
|
|
3751
|
+
});
|
|
3167
3752
|
}
|
|
3168
3753
|
//# sourceMappingURL=tools.js.map
|