soloforge 1.3.1 → 1.3.2
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 +6 -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 +317 -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 +139 -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 +85 -53
- 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 +28 -18
- package/dist/engine/asset_manifest.js.map +1 -1
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
- package/dist/engine/consumable_asset_registry.js +26 -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 +176 -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 +3508 -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 +44 -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 +74 -2
- package/dist/engine/mechanism_contract_registry.js.map +1 -1
- 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/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 +1349 -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 +574 -46
- 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/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/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 +11 -1
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -1
- 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 +36 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- 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 +29 -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 +27 -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 +30 -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 +50 -0
|
@@ -80,6 +80,9 @@ 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"));
|
|
83
86
|
// ── Zod Schema 定义 ──
|
|
84
87
|
const ClassifySchema = {
|
|
85
88
|
intent: z.string().describe("开发者意图描述"),
|
|
@@ -90,6 +93,7 @@ const ExpandSchema = {
|
|
|
90
93
|
clarification_answers: z.array(z.string()).optional().describe("对澄清问题的回答"),
|
|
91
94
|
input_material_confirmations: z.array(z.string()).optional().describe("已确认安全的输入材料路径列表"),
|
|
92
95
|
architecture_decision_workshop: z.unknown().optional().describe("架构设计前已讨论并确认的六域决策记录"),
|
|
96
|
+
decision_workshop: z.unknown().optional().describe("通用决策研讨合同(技术选型/数据迁移/安全策略/部署/重构/第三方集成等)"),
|
|
93
97
|
design_artifact_pack: z.unknown().optional().describe("设计产物包路径映射或已复验状态"),
|
|
94
98
|
};
|
|
95
99
|
const VerifySchema = {
|
|
@@ -139,6 +143,24 @@ const RecordVerificationExecutionSchema = {
|
|
|
139
143
|
evidence_id: z.string().describe("执行证据 ID"),
|
|
140
144
|
})).describe("真实执行记录列表"),
|
|
141
145
|
};
|
|
146
|
+
const AcceptSchema = {
|
|
147
|
+
task_id: z.string().describe("任务 ID"),
|
|
148
|
+
confirm: z.boolean().describe("用户显式确认验收结果,必须为 true"),
|
|
149
|
+
confirmed_by: z.string().describe("执行确认的用户或审批者标识"),
|
|
150
|
+
confirmation_ref: z.string().describe("可审计的用户确认引用"),
|
|
151
|
+
acceptance_notes: z.string().describe("验收备注或不适用理由"),
|
|
152
|
+
run_mode: z.enum(["manual_review", "not_applicable"]).describe("验收模式"),
|
|
153
|
+
final_access: z.object({
|
|
154
|
+
frontend_urls: z.array(z.string()),
|
|
155
|
+
backend_urls: z.array(z.string()),
|
|
156
|
+
docs_or_swagger_urls: z.array(z.string()),
|
|
157
|
+
start_commands: z.array(z.string()),
|
|
158
|
+
stop_commands: z.array(z.string()),
|
|
159
|
+
running_status: z.string(),
|
|
160
|
+
manual_review_steps_zh: z.array(z.string()),
|
|
161
|
+
known_limits_zh: z.array(z.string()),
|
|
162
|
+
}).optional().describe("manual_review 模式下的真实本地访问证据"),
|
|
163
|
+
};
|
|
142
164
|
const DeliverSchema = {
|
|
143
165
|
task_id: z.string().describe("任务 ID"),
|
|
144
166
|
changed_files: z.array(z.string()).optional().describe("变更文件列表(不传则使用任务记录中的文件)"),
|
|
@@ -222,7 +244,7 @@ export function checkWriteToolPlanGate(params) {
|
|
|
222
244
|
}
|
|
223
245
|
/**
|
|
224
246
|
* 施工指令契约门 — 写操作前检查施工指令完整性。
|
|
225
|
-
*
|
|
247
|
+
* 通过引擎模块函数真实消费。
|
|
226
248
|
* 调用链 1: registerInstructionIssueCandidate(无契约时创建候选 draft)
|
|
227
249
|
* 调用链 2: enforceInstructionBeforeImplementation → checkInstructionCompleteness → validateInstructionContract
|
|
228
250
|
*/
|
|
@@ -282,7 +304,7 @@ export function checkDesignArtifactWriteGate(params) {
|
|
|
282
304
|
}
|
|
283
305
|
/**
|
|
284
306
|
* 架构设计门 — 架构设计类任务膨胀前执行 reviewArchitectureDesign。
|
|
285
|
-
*
|
|
307
|
+
* Architecture Design Contract enforcement。
|
|
286
308
|
*/
|
|
287
309
|
export async function checkArchitectureDesignGate(params) {
|
|
288
310
|
const route = params.route;
|
|
@@ -309,7 +331,7 @@ export async function checkArchitectureDesignGate(params) {
|
|
|
309
331
|
}
|
|
310
332
|
/**
|
|
311
333
|
* 架构决策研讨门 — 正式架构设计前六域决策必须闭合。
|
|
312
|
-
*
|
|
334
|
+
* 与是否存在施工指令契约无关,架构设计路由必经此门。
|
|
313
335
|
*/
|
|
314
336
|
export async function checkArchitectureDecisionWorkshopGate(params) {
|
|
315
337
|
const workshopModule = await lazyArchitectureWorkshop();
|
|
@@ -333,7 +355,7 @@ export async function checkArchitectureDecisionWorkshopGate(params) {
|
|
|
333
355
|
}
|
|
334
356
|
/**
|
|
335
357
|
* 现有系统分析门 — 现有项目编码前必须先做分析。
|
|
336
|
-
*
|
|
358
|
+
* Existing System Analysis Contract enforcement。
|
|
337
359
|
*/
|
|
338
360
|
export async function checkExistingSystemAnalysisGate(params) {
|
|
339
361
|
const archModule = await lazyExistingSystemAnalysis();
|
|
@@ -350,7 +372,7 @@ export async function checkExistingSystemAnalysisGate(params) {
|
|
|
350
372
|
}
|
|
351
373
|
/**
|
|
352
374
|
* 编码就绪门 — 编码前必须有测试计划 + 验收标准。
|
|
353
|
-
*
|
|
375
|
+
* Coding Readiness / Test-First enforcement。
|
|
354
376
|
*/
|
|
355
377
|
export async function checkCodingReadinessGate(params) {
|
|
356
378
|
if (!params.ctx)
|
|
@@ -375,7 +397,7 @@ export async function checkCodingReadinessGate(params) {
|
|
|
375
397
|
}
|
|
376
398
|
/**
|
|
377
399
|
* 本地验收门 — 前端/全栈交付前必须有本地访问证据。
|
|
378
|
-
*
|
|
400
|
+
* Local Docker / Browser Acceptance enforcement。
|
|
379
401
|
*/
|
|
380
402
|
export async function checkLocalAcceptanceGate(params) {
|
|
381
403
|
const acceptanceModule = await lazyLocalAcceptance();
|
|
@@ -397,6 +419,21 @@ export async function checkLocalAcceptanceGate(params) {
|
|
|
397
419
|
required_but_missing: ["local_acceptance_evidence", "final_access_url"],
|
|
398
420
|
};
|
|
399
421
|
}
|
|
422
|
+
if (evidence.run_mode === "not_applicable") {
|
|
423
|
+
return {
|
|
424
|
+
allowed: false,
|
|
425
|
+
reason_zh: "该项目需要本地验收,不得以 not_applicable 代替真实访问证据",
|
|
426
|
+
required_but_missing: ["manual_review", "final_access_url"],
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const finalAccessResult = acceptanceModule.validateFinalAccess(evidence.final_access, requirement.run_mode);
|
|
430
|
+
if (!finalAccessResult.passed) {
|
|
431
|
+
return {
|
|
432
|
+
allowed: false,
|
|
433
|
+
reason_zh: `本地验收证据不完整: ${finalAccessResult.blocking_reasons.join("; ")}`,
|
|
434
|
+
required_but_missing: ["validated_final_access"],
|
|
435
|
+
};
|
|
436
|
+
}
|
|
400
437
|
return { allowed: true };
|
|
401
438
|
}
|
|
402
439
|
// ── S4 触发判定函数 ──
|
|
@@ -485,7 +522,7 @@ export function requiresBrainstorm(ctx, route) {
|
|
|
485
522
|
}
|
|
486
523
|
/**
|
|
487
524
|
* 技术选型决策门 — 高影响技术决策需用户确认。
|
|
488
|
-
*
|
|
525
|
+
* Decision Sovereignty enforcement。
|
|
489
526
|
* 不依赖 hasInstructionContract — 触发由 requiresDecisionSovereignty 判定。
|
|
490
527
|
*/
|
|
491
528
|
export async function checkDecisionSovereigntyGate(params) {
|
|
@@ -525,7 +562,7 @@ export async function checkDecisionSovereigntyGate(params) {
|
|
|
525
562
|
}
|
|
526
563
|
/**
|
|
527
564
|
* 细节纪律门 — 复杂任务缺关键细节维度时阻断。
|
|
528
|
-
*
|
|
565
|
+
* Detail Discipline enforcement。
|
|
529
566
|
* 不依赖 hasInstructionContract — 触发由 requiresDetailDiscipline 判定。
|
|
530
567
|
*/
|
|
531
568
|
export async function checkDetailDisciplineGate(params) {
|
|
@@ -550,7 +587,7 @@ export async function checkDetailDisciplineGate(params) {
|
|
|
550
587
|
}
|
|
551
588
|
/**
|
|
552
589
|
* 第一性原理门 — 高影响任务需目标/约束/本质问题/权衡。
|
|
553
|
-
*
|
|
590
|
+
* First Principles enforcement。
|
|
554
591
|
* 不依赖 hasInstructionContract — 触发由 requiresFirstPrinciples 判定。
|
|
555
592
|
*/
|
|
556
593
|
export async function checkFirstPrinciplesGate(params) {
|
|
@@ -573,7 +610,7 @@ export async function checkFirstPrinciplesGate(params) {
|
|
|
573
610
|
}
|
|
574
611
|
/**
|
|
575
612
|
* 脑暴/方案探索门 — 不确定项需多方案+推荐理由+用户确认。
|
|
576
|
-
*
|
|
613
|
+
* Brainstorm Contract enforcement。
|
|
577
614
|
* 不依赖 hasInstructionContract — 触发由 requiresBrainstorm 判定。
|
|
578
615
|
*/
|
|
579
616
|
export async function checkBrainstormGate(params) {
|
|
@@ -784,12 +821,14 @@ export async function registerTools(server, deps) {
|
|
|
784
821
|
}
|
|
785
822
|
/** State precheck: validate task status before contract guard */
|
|
786
823
|
const STATE_PRECHECKS = {
|
|
824
|
+
sf_accept: ["executing", "verifying", "retrying"],
|
|
787
825
|
sf_verify: ["executing", "retrying"],
|
|
788
826
|
sf_record_verification_execution: ["verifying", "executing"],
|
|
789
827
|
sf_learn: ["verifying", "executing"],
|
|
790
828
|
sf_expand: ["classifying", "expanding", "clarifying"],
|
|
791
829
|
};
|
|
792
830
|
const STATE_ERROR_LABELS = {
|
|
831
|
+
sf_accept: "不可验收",
|
|
793
832
|
sf_verify: "不可验证",
|
|
794
833
|
sf_record_verification_execution: "不可录入验证结果",
|
|
795
834
|
sf_learn: "不可学习",
|
|
@@ -1090,13 +1129,19 @@ export async function registerTools(server, deps) {
|
|
|
1090
1129
|
// 从 { result } 模式中提取数据
|
|
1091
1130
|
const data = raw?.result !== undefined ? raw.result : raw;
|
|
1092
1131
|
const hasError = !!(data && typeof data === "object" && "error" in data);
|
|
1093
|
-
|
|
1132
|
+
const recoveryNextTools = hasError && Array.isArray(data.recovery_next_tools)
|
|
1133
|
+
? data.recovery_next_tools
|
|
1134
|
+
: contract.default_next_tools;
|
|
1135
|
+
const recoveryForbiddenTools = hasError && Array.isArray(data.recovery_forbidden_tools)
|
|
1136
|
+
? data.recovery_forbidden_tools
|
|
1137
|
+
: contract.forbidden_next_tools;
|
|
1138
|
+
// 构建 trace;失败处理器可显式开放修复重验路径
|
|
1094
1139
|
const trace = createToolTrace({
|
|
1095
1140
|
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
1096
1141
|
workflow_id: ctx?.expansion?.workflow_trace?.workflow_id,
|
|
1097
1142
|
actual_side_effects: effectiveSideEffects,
|
|
1098
|
-
next_allowed_tools:
|
|
1099
|
-
forbidden_tools:
|
|
1143
|
+
next_allowed_tools: recoveryNextTools,
|
|
1144
|
+
forbidden_tools: recoveryForbiddenTools,
|
|
1100
1145
|
authorization, bypass,
|
|
1101
1146
|
});
|
|
1102
1147
|
// 将 trace 写入 TaskContext
|
|
@@ -1107,8 +1152,8 @@ export async function registerTools(server, deps) {
|
|
|
1107
1152
|
const response = {
|
|
1108
1153
|
...data,
|
|
1109
1154
|
tool_trace: trace,
|
|
1110
|
-
next_allowed_tools:
|
|
1111
|
-
forbidden_tools:
|
|
1155
|
+
next_allowed_tools: recoveryNextTools,
|
|
1156
|
+
forbidden_tools: recoveryForbiddenTools,
|
|
1112
1157
|
};
|
|
1113
1158
|
// 基于状态的回退: 在响应中暴露降级 workflow
|
|
1114
1159
|
if (authorization.reason === "task in valid state for tool") {
|
|
@@ -1244,10 +1289,13 @@ export async function registerTools(server, deps) {
|
|
|
1244
1289
|
if (args.architecture_decision_workshop) {
|
|
1245
1290
|
ctx.architecture_decision_workshop = args.architecture_decision_workshop;
|
|
1246
1291
|
}
|
|
1292
|
+
if (args.decision_workshop) {
|
|
1293
|
+
ctx.decision_workshop = args.decision_workshop;
|
|
1294
|
+
}
|
|
1247
1295
|
if (args.design_artifact_pack) {
|
|
1248
1296
|
ctx.design_artifact_pack = args.design_artifact_pack;
|
|
1249
1297
|
}
|
|
1250
|
-
if (args.architecture_decision_workshop || args.design_artifact_pack) {
|
|
1298
|
+
if (args.architecture_decision_workshop || args.decision_workshop || args.design_artifact_pack) {
|
|
1251
1299
|
await taskContext.save(ctx);
|
|
1252
1300
|
}
|
|
1253
1301
|
// 状态守卫:classifying/expanding/clarifying → expanding
|
|
@@ -1330,6 +1378,39 @@ export async function registerTools(server, deps) {
|
|
|
1330
1378
|
gateway.endTask();
|
|
1331
1379
|
}
|
|
1332
1380
|
expansion.task_id = args.task_id;
|
|
1381
|
+
const projectRoot = fss.realpathSync(projectPath);
|
|
1382
|
+
const referencedMaterialPaths = new Set((expansion.input_materials ?? [])
|
|
1383
|
+
.map((material) => material.path_or_ref)
|
|
1384
|
+
.filter((materialPath) => typeof materialPath === "string" && materialPath.length > 0)
|
|
1385
|
+
.map((materialPath) => path.resolve(projectRoot, materialPath)));
|
|
1386
|
+
const confirmedProjectSourcePaths = (args.input_material_confirmations ?? [])
|
|
1387
|
+
.map((materialPath) => path.resolve(projectRoot, materialPath))
|
|
1388
|
+
.filter((absolutePath) => absolutePath === projectRoot || absolutePath.startsWith(`${projectRoot}${path.sep}`))
|
|
1389
|
+
.filter((absolutePath) => referencedMaterialPaths.has(absolutePath))
|
|
1390
|
+
.filter((absolutePath) => {
|
|
1391
|
+
try {
|
|
1392
|
+
return fss.statSync(absolutePath).isFile()
|
|
1393
|
+
&& fss.realpathSync(absolutePath).startsWith(`${projectRoot}${path.sep}`);
|
|
1394
|
+
}
|
|
1395
|
+
catch {
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
const registerConfirmedProjectSources = (registry) => {
|
|
1400
|
+
for (const absolutePath of confirmedProjectSourcePaths) {
|
|
1401
|
+
const sourceRef = path.relative(projectRoot, absolutePath);
|
|
1402
|
+
registry.register({
|
|
1403
|
+
source_type: "project_file",
|
|
1404
|
+
evidence_role: "project_source_file",
|
|
1405
|
+
authority: "authoritative",
|
|
1406
|
+
freshness: "current",
|
|
1407
|
+
permission: "allowed",
|
|
1408
|
+
scope: "confirmed_input_material",
|
|
1409
|
+
description: `已确认项目输入材料: ${sourceRef}`,
|
|
1410
|
+
source_ref: sourceRef,
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1333
1414
|
const workflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification.route_decision?.workflow_intent;
|
|
1334
1415
|
// 问题六十: 高风险项目事实声明先过证据门,避免后续架构研讨门遮蔽无证据问题。
|
|
1335
1416
|
{
|
|
@@ -1383,6 +1464,7 @@ export async function registerTools(server, deps) {
|
|
|
1383
1464
|
source_ref: `decision:${tdc.decision_id ?? args.task_id}`,
|
|
1384
1465
|
});
|
|
1385
1466
|
}
|
|
1467
|
+
registerConfirmedProjectSources(evg.registry);
|
|
1386
1468
|
const evClaims = [
|
|
1387
1469
|
{
|
|
1388
1470
|
id: "claim-expand-0",
|
|
@@ -1463,6 +1545,34 @@ export async function registerTools(server, deps) {
|
|
|
1463
1545
|
ctx.design_artifact_pack.user_confirmation_ref = ctx.architecture_decision_workshop?.document_output_confirmation_ref;
|
|
1464
1546
|
await taskContext.save(ctx);
|
|
1465
1547
|
}
|
|
1548
|
+
// 问题六十一(通用): 可组合决策包门禁
|
|
1549
|
+
const dwModule = await lazyDecisionWorkshop();
|
|
1550
|
+
const packMatch = dwModule.matchDecisionPacks({
|
|
1551
|
+
workflow_intent: workflowIntent,
|
|
1552
|
+
intent: ctx.intent,
|
|
1553
|
+
task_type: ctx.classification?.task_type,
|
|
1554
|
+
});
|
|
1555
|
+
// 过滤掉架构(架构由上面的专用子包处理)
|
|
1556
|
+
const nonArchPacks = packMatch.packs.filter((p) => p !== "architecture");
|
|
1557
|
+
if (nonArchPacks.length > 0) {
|
|
1558
|
+
const dwContract = ctx.decision_workshop ?? dwModule.createDecisionWorkshop(args.task_id, nonArchPacks, detectedArchitectureContext, packMatch.reasons.join(";"));
|
|
1559
|
+
const dwGate = dwModule.evaluateDecisionWorkshop(dwContract);
|
|
1560
|
+
ctx.decision_workshop = dwModule.applyDecisionWorkshopGate(dwContract);
|
|
1561
|
+
await taskContext.save(ctx);
|
|
1562
|
+
if (!dwGate.allowed) {
|
|
1563
|
+
return {
|
|
1564
|
+
result: {
|
|
1565
|
+
error: `${packMatch.reasons.join(";")},必须先完成决策研讨与用户确认`,
|
|
1566
|
+
status: "awaiting_confirmation",
|
|
1567
|
+
decision_workshop: ctx.decision_workshop,
|
|
1568
|
+
blocking_findings: dwGate.blocking_findings,
|
|
1569
|
+
next_domain: dwGate.next_domain,
|
|
1570
|
+
activated_packs: nonArchPacks,
|
|
1571
|
+
recovery: "请从当前待讨论域开始,提供候选方案、推荐理由、风险和用户确认后重新调用 sf_expand",
|
|
1572
|
+
},
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1466
1576
|
// 问题四十九/五十: 已有架构合同或现有系统证据的进一步审查。
|
|
1467
1577
|
const expansionRoute = expansion.workflow_trace
|
|
1468
1578
|
? expansion.workflow_trace?.route
|
|
@@ -1628,6 +1738,7 @@ export async function registerTools(server, deps) {
|
|
|
1628
1738
|
source_ref: `decision:${_tdc.decision_id ?? args.task_id}`,
|
|
1629
1739
|
});
|
|
1630
1740
|
}
|
|
1741
|
+
registerConfirmedProjectSources(_evg.registry);
|
|
1631
1742
|
const _evClaims = [
|
|
1632
1743
|
{
|
|
1633
1744
|
id: "claim-expand-0",
|
|
@@ -1789,6 +1900,83 @@ export async function registerTools(server, deps) {
|
|
|
1789
1900
|
};
|
|
1790
1901
|
}
|
|
1791
1902
|
}
|
|
1903
|
+
// 问题六十三: 模板契约验证 — 按文件逐一匹配契约并校验
|
|
1904
|
+
const sacModule = await lazyStandardAssetContract();
|
|
1905
|
+
const formalArtifactContract = sacModule.matchTemplateContract({
|
|
1906
|
+
output_artifact_kind: ctx.artifact_output?.kind,
|
|
1907
|
+
workflow_intent: verifyWorkflowIntent,
|
|
1908
|
+
route_decision: ctx.route_decision?.workflow_intent,
|
|
1909
|
+
});
|
|
1910
|
+
if (formalArtifactContract || !sacModule.isLowRiskTask({
|
|
1911
|
+
route_decision: verifyWorkflowIntent ?? ctx.classification?.route_decision?.workflow_intent,
|
|
1912
|
+
workflow_intent: verifyWorkflowIntent,
|
|
1913
|
+
changed_files: args.changed_files,
|
|
1914
|
+
})) {
|
|
1915
|
+
for (const changedFile of args.changed_files) {
|
|
1916
|
+
const absFile = path.join(projectPath, changedFile);
|
|
1917
|
+
if (!fss.existsSync(absFile) || !/\.md$/.test(changedFile))
|
|
1918
|
+
continue;
|
|
1919
|
+
// 按实际文件路径匹配契约(不再使用 changed_files[0] 的契约校验全部文件)
|
|
1920
|
+
const perFileContract = sacModule.matchTemplateContract({
|
|
1921
|
+
output_artifact_kind: ctx.artifact_output?.kind,
|
|
1922
|
+
workflow_intent: verifyWorkflowIntent,
|
|
1923
|
+
route_decision: ctx.route_decision?.workflow_intent,
|
|
1924
|
+
file_path: changedFile,
|
|
1925
|
+
});
|
|
1926
|
+
if (!perFileContract)
|
|
1927
|
+
continue;
|
|
1928
|
+
const content = fss.readFileSync(absFile, "utf-8");
|
|
1929
|
+
// 草稿阻断下游消费 — 不再静默跳过
|
|
1930
|
+
if (sacModule.isDraftDocument(content)) {
|
|
1931
|
+
ctx.repair_reverify_directive = {
|
|
1932
|
+
contract_id: perFileContract.asset_id,
|
|
1933
|
+
file_path: changedFile,
|
|
1934
|
+
status: "draft_blocked",
|
|
1935
|
+
repair_suggestion: `文件 ${changedFile} 仍为草稿状态,草稿不可用于实现。请完善内容后重新验证。`,
|
|
1936
|
+
blocked: true,
|
|
1937
|
+
};
|
|
1938
|
+
await taskContext.save(ctx);
|
|
1939
|
+
return {
|
|
1940
|
+
result: {
|
|
1941
|
+
error: `草稿文件 ${changedFile} 不可用于实现,需完善后重新验证`,
|
|
1942
|
+
status: "blocked",
|
|
1943
|
+
diagnostic_code: "SF-CONTRACT-DRAFT",
|
|
1944
|
+
template_contract_id: perFileContract.asset_id,
|
|
1945
|
+
recovery: "完善草稿内容后重新执行 sf_verify",
|
|
1946
|
+
},
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
const contractResult = sacModule.verifyOutputAgainstContract(perFileContract, content, projectPath);
|
|
1950
|
+
if (!contractResult.passed) {
|
|
1951
|
+
const repairDirective = sacModule.createRepairReverifyDirective(perFileContract, contractResult);
|
|
1952
|
+
ctx.repair_reverify_directive = {
|
|
1953
|
+
contract_id: perFileContract.asset_id,
|
|
1954
|
+
file_path: changedFile,
|
|
1955
|
+
status: "repair_required",
|
|
1956
|
+
repair_suggestion: repairDirective.repair_suggestion,
|
|
1957
|
+
blocked: true,
|
|
1958
|
+
};
|
|
1959
|
+
await taskContext.save(ctx);
|
|
1960
|
+
return {
|
|
1961
|
+
result: {
|
|
1962
|
+
error: `文件 ${changedFile} 模板契约验证未通过,进入修复重验闭环`,
|
|
1963
|
+
status: "blocked",
|
|
1964
|
+
diagnostic_code: "SF-CONTRACT-0003",
|
|
1965
|
+
template_contract_id: perFileContract.asset_id,
|
|
1966
|
+
missing_fields: contractResult.missing_fields,
|
|
1967
|
+
messages: contractResult.messages,
|
|
1968
|
+
repair_suggestion: repairDirective.repair_suggestion,
|
|
1969
|
+
recovery: "修复文档缺口后重新执行 sf_verify;不得只报告不修复",
|
|
1970
|
+
},
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
// 全部契约验证通过 — 清零修复重验指令
|
|
1975
|
+
if (ctx.repair_reverify_directive) {
|
|
1976
|
+
delete ctx.repair_reverify_directive;
|
|
1977
|
+
await taskContext.save(ctx);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1792
1980
|
// RouteDecision 合同验证 — 无条件,在状态预检之前
|
|
1793
1981
|
const rdFromCtx = ctx.route_decision ?? ctx.classification?.route_decision ?? null;
|
|
1794
1982
|
const wtFromCtx = ctx.workflow_trace ?? ctx.expansion?.workflow_trace ?? null;
|
|
@@ -2481,6 +2669,103 @@ export async function registerTools(server, deps) {
|
|
|
2481
2669
|
};
|
|
2482
2670
|
});
|
|
2483
2671
|
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
2672
|
+
// ── sf_accept: 记录任务验收证据(本地验收 + 产物确认) ──
|
|
2673
|
+
registerSafeTool("sf_accept", "记录任务验收证据,解除 sf_deliver 的本地验收门和产物确认门", AcceptSchema, async (args) => {
|
|
2674
|
+
const ctx = await taskContext.load(args.task_id);
|
|
2675
|
+
if (!ctx) {
|
|
2676
|
+
return { result: { error: "任务不存在" } };
|
|
2677
|
+
}
|
|
2678
|
+
const runMode = args.run_mode;
|
|
2679
|
+
const notes = String(args.acceptance_notes ?? "").trim();
|
|
2680
|
+
const confirmedBy = String(args.confirmed_by ?? "").trim();
|
|
2681
|
+
const confirmationRef = String(args.confirmation_ref ?? "").trim();
|
|
2682
|
+
if (args.confirm !== true || !confirmedBy || !confirmationRef || !notes) {
|
|
2683
|
+
return {
|
|
2684
|
+
result: {
|
|
2685
|
+
error: "验收必须包含显式确认、确认者、可审计确认引用和验收说明",
|
|
2686
|
+
diagnostic_code: "SF-ACCEPT-CONFIRMATION-REQUIRED",
|
|
2687
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2688
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2689
|
+
},
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
const currentVerification = ctx.verification_result ?? ctx.batch2_verification_result;
|
|
2693
|
+
if (currentVerification?.status !== "passed") {
|
|
2694
|
+
return {
|
|
2695
|
+
result: {
|
|
2696
|
+
error: "验收前必须已有真实执行并通过的 verification_result",
|
|
2697
|
+
diagnostic_code: "SF-ACCEPT-VERIFICATION-REQUIRED",
|
|
2698
|
+
recovery_next_tools: ["sf_verify", "sf_record_verification_execution", "sf_status"],
|
|
2699
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2700
|
+
},
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
const evidenceRef = `acceptance:user_confirmation:${confirmationRef}`;
|
|
2704
|
+
if (runMode === "manual_review") {
|
|
2705
|
+
const acceptanceModule = await lazyLocalAcceptance();
|
|
2706
|
+
if (!args.final_access) {
|
|
2707
|
+
return {
|
|
2708
|
+
result: {
|
|
2709
|
+
error: "manual_review 验收缺少 final_access 真实访问证据",
|
|
2710
|
+
diagnostic_code: "SF-ACCEPT-FINAL-ACCESS-REQUIRED",
|
|
2711
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2712
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2713
|
+
},
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
const finalAccessResult = acceptanceModule.validateFinalAccess(args.final_access, "local_dev_server");
|
|
2717
|
+
if (!finalAccessResult.passed) {
|
|
2718
|
+
return {
|
|
2719
|
+
result: {
|
|
2720
|
+
error: `manual_review 验收证据不完整: ${finalAccessResult.blocking_reasons.join("; ")}`,
|
|
2721
|
+
diagnostic_code: "SF-ACCEPT-FINAL-ACCESS-INVALID",
|
|
2722
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2723
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2724
|
+
},
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
// 设置本地验收证据
|
|
2729
|
+
ctx.local_acceptance_evidence = {
|
|
2730
|
+
status: runMode === "manual_review" ? "passed" : "not_applicable",
|
|
2731
|
+
run_mode: runMode,
|
|
2732
|
+
confirmed_by: confirmedBy,
|
|
2733
|
+
confirmation_ref: confirmationRef,
|
|
2734
|
+
final_access: args.final_access ?? {
|
|
2735
|
+
frontend_urls: [],
|
|
2736
|
+
backend_urls: [],
|
|
2737
|
+
docs_or_swagger_urls: [],
|
|
2738
|
+
start_commands: [],
|
|
2739
|
+
stop_commands: [],
|
|
2740
|
+
running_status: "not_started",
|
|
2741
|
+
manual_review_steps_zh: [notes],
|
|
2742
|
+
known_limits_zh: [],
|
|
2743
|
+
},
|
|
2744
|
+
evidence_refs: [evidenceRef],
|
|
2745
|
+
};
|
|
2746
|
+
await taskContext.save(ctx);
|
|
2747
|
+
let updatedCtx = ctx;
|
|
2748
|
+
// 产物确认必须经过统一生命周期校验,不直接改写 status。
|
|
2749
|
+
if (ctx.artifact_output && ctx.artifact_output.status === "verified") {
|
|
2750
|
+
updatedCtx = await taskContext.updateArtifactStatus(args.task_id, {
|
|
2751
|
+
status: "accepted",
|
|
2752
|
+
evidenceRef,
|
|
2753
|
+
hasAcceptance: true,
|
|
2754
|
+
}) ?? ctx;
|
|
2755
|
+
}
|
|
2756
|
+
return {
|
|
2757
|
+
result: {
|
|
2758
|
+
task_id: args.task_id,
|
|
2759
|
+
acceptance_status: "passed",
|
|
2760
|
+
run_mode: runMode,
|
|
2761
|
+
evidence_ref: evidenceRef,
|
|
2762
|
+
artifact_transition: updatedCtx.artifact_output
|
|
2763
|
+
? `${updatedCtx.artifact_output.status}`
|
|
2764
|
+
: "no_artifact",
|
|
2765
|
+
},
|
|
2766
|
+
};
|
|
2767
|
+
});
|
|
2768
|
+
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
2484
2769
|
registerSafeTool("sf_deliver", "验收后自动提交代码、推送、创建 PR 和生成变更日志", DeliverSchema, async (args) => {
|
|
2485
2770
|
const ctx = await taskContext.load(args.task_id);
|
|
2486
2771
|
if (!ctx) {
|
|
@@ -2493,6 +2778,19 @@ export async function registerTools(server, deps) {
|
|
|
2493
2778
|
const h4DeliverWarning = !deliverIntegrity.clean
|
|
2494
2779
|
? { warning: `H4 advisory: ${deliverIntegrity.message}`, dirty_files: deliverIntegrity.dirty_files }
|
|
2495
2780
|
: undefined;
|
|
2781
|
+
// 模板契约修复指令优先于通用产物状态提示,确保客户端获得可执行的修复重验路径。
|
|
2782
|
+
if (ctx.repair_reverify_directive) {
|
|
2783
|
+
return {
|
|
2784
|
+
result: {
|
|
2785
|
+
error: "存在未清零的模板契约修复指令,需完成修复重验后才能交付",
|
|
2786
|
+
diagnostic_code: "SF-CONTRACT-0003",
|
|
2787
|
+
repair_directive: ctx.repair_reverify_directive,
|
|
2788
|
+
recovery: "修复文档缺口后重新执行 sf_verify,验证通过后 repair_reverify_directive 自动清零",
|
|
2789
|
+
recovery_next_tools: ["sf_learn", "sf_verify", "sf_status"],
|
|
2790
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2791
|
+
},
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2496
2794
|
// 产物状态门控: deliver 需要产物状态为 accepted 且有证据
|
|
2497
2795
|
if (ctx.artifact_output) {
|
|
2498
2796
|
const status = ctx.artifact_output.status;
|
|
@@ -2574,6 +2872,7 @@ export async function registerTools(server, deps) {
|
|
|
2574
2872
|
const metricsData = await (await lazyObservability()).collectDeliveryMetricSamples(taskContext.getStateDir());
|
|
2575
2873
|
// acceptanceConfig: 从项目配置推断 project_run_mode
|
|
2576
2874
|
const projectHasFrontend = config.tech_stack.frontend.lang && config.tech_stack.frontend.lang !== "none";
|
|
2875
|
+
const projectHasBackend = config.tech_stack.backend.lang && config.tech_stack.backend.lang !== "none";
|
|
2577
2876
|
const readinessReport = drModule.evaluateDeliveryReadiness(args.task_id, currentVResult, guardFindings, true, // scope_check — 已在 sf_verify 写入护栏中检查
|
|
2578
2877
|
deliverLease.conflicts.length === 0, // lease_check — 无冲突即通过
|
|
2579
2878
|
true, // privacy_check — 已在任务创建时脱敏
|
|
@@ -2603,7 +2902,7 @@ export async function registerTools(server, deps) {
|
|
|
2603
2902
|
const localAcceptanceGate = await checkLocalAcceptanceGate({
|
|
2604
2903
|
ctx,
|
|
2605
2904
|
hasFrontend: !!projectHasFrontend,
|
|
2606
|
-
hasBackend: !!
|
|
2905
|
+
hasBackend: !!projectHasBackend,
|
|
2607
2906
|
hasDockerCompose: false,
|
|
2608
2907
|
hasDockerfile: false,
|
|
2609
2908
|
});
|
|
@@ -2688,7 +2987,7 @@ export async function registerTools(server, deps) {
|
|
|
2688
2987
|
task_id: args.task_id,
|
|
2689
2988
|
verification_passed: currentVResult?.status === "passed",
|
|
2690
2989
|
build_passed: (currentVResult?.passed_commands ?? 0) > 0,
|
|
2691
|
-
browser_acceptance_passed: ctx.artifact_output?.status === "
|
|
2990
|
+
browser_acceptance_passed: ctx.artifact_output?.status === "accepted" || ctx.artifact_output === undefined,
|
|
2692
2991
|
guard_passed: guardFindings.length === 0 || guardFindings.every((f) => f.severity !== "hard_fail"),
|
|
2693
2992
|
evidence_sufficient: (currentVResult?.evidence_ids?.length ?? 0) > 0,
|
|
2694
2993
|
current_status: ctx.status === "done" ? "completed" : ctx.status,
|