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
package/dist/bin/soloforge.js
CHANGED
|
@@ -81,6 +81,9 @@ async function main() {
|
|
|
81
81
|
case "validate-release":
|
|
82
82
|
await cmdValidateReleaseGate();
|
|
83
83
|
break;
|
|
84
|
+
case "audit-template-visibility":
|
|
85
|
+
await cmdAuditTemplateVisibility();
|
|
86
|
+
break;
|
|
84
87
|
case "sync-templates":
|
|
85
88
|
await cmdSyncTemplates();
|
|
86
89
|
break;
|
|
@@ -132,6 +135,12 @@ async function main() {
|
|
|
132
135
|
case "status":
|
|
133
136
|
await cmdStatus();
|
|
134
137
|
break;
|
|
138
|
+
case "next":
|
|
139
|
+
await cmdNext();
|
|
140
|
+
break;
|
|
141
|
+
case "stage":
|
|
142
|
+
await cmdStage();
|
|
143
|
+
break;
|
|
135
144
|
case "cleanup":
|
|
136
145
|
await cmdCleanup();
|
|
137
146
|
break;
|
|
@@ -170,6 +179,11 @@ async function main() {
|
|
|
170
179
|
config confirm <field> <value> 确认配置字段(写入 config + evidence)
|
|
171
180
|
config unset <field> 移除确认配置
|
|
172
181
|
status 显示当前项目的 SoloForge 状态
|
|
182
|
+
next 查询下一步操作和可执行工作包(默认只读)
|
|
183
|
+
next --json 纯 JSON 输出(无日志污染)
|
|
184
|
+
next --write-snapshot 将导航快照写入 .soloforge/navigation-snapshot.json
|
|
185
|
+
stage 显示当前项目阶段和任务阶段
|
|
186
|
+
stage --explain 详细解释当前阶段(判断依据、必要条件、下一阶段)
|
|
173
187
|
cleanup 清理过期任务和 evidence(默认 dry-run,--apply 执行实际清理)
|
|
174
188
|
`);
|
|
175
189
|
}
|
|
@@ -460,56 +474,32 @@ async function cmdInit() {
|
|
|
460
474
|
"请打开 Claude Code 开始使用。"}`);
|
|
461
475
|
}
|
|
462
476
|
async function copyGlobalPatterns(projectPath) {
|
|
477
|
+
const { copyPatternsToGlobal } = await import("../engine/template_init_sync.js");
|
|
463
478
|
const globalDir = getGlobalPatternsDir();
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (!fss.existsSync(dest)) {
|
|
474
|
-
fss.copyFileSync(src, dest);
|
|
475
|
-
copiedCount++;
|
|
476
|
-
}
|
|
477
|
-
else {
|
|
478
|
-
skippedCount++;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
const parts = [];
|
|
482
|
-
if (copiedCount > 0)
|
|
483
|
-
parts.push(`新增 ${copiedCount} 个`);
|
|
484
|
-
if (skippedCount > 0)
|
|
485
|
-
parts.push(`跳过 ${skippedCount} 个(已存在)`);
|
|
486
|
-
userInfo(`✅ 全局模板 ~/.soloforge/patterns/: ${parts.length > 0 ? parts.join(",") : `${files.length} 个(已全部存在)`}`);
|
|
479
|
+
const templatesRoot = path.resolve(import.meta.dirname, "..", "..");
|
|
480
|
+
const result = await copyPatternsToGlobal(templatesRoot, globalDir);
|
|
481
|
+
const parts = [];
|
|
482
|
+
if (result.copied > 0)
|
|
483
|
+
parts.push(`新增 ${result.copied} 个`);
|
|
484
|
+
if (result.skipped > 0)
|
|
485
|
+
parts.push(`跳过 ${result.skipped} 个(已存在)`);
|
|
486
|
+
if (parts.length > 0) {
|
|
487
|
+
userInfo(`✅ 全局模板 ~/.soloforge/patterns/: ${parts.join(",")}`);
|
|
487
488
|
}
|
|
488
489
|
}
|
|
489
490
|
async function copyKnowledgeTemplates(projectPath) {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const src = path.join(srcDir, f);
|
|
503
|
-
const dest = path.join(destDir, f);
|
|
504
|
-
if (!fss.existsSync(dest)) {
|
|
505
|
-
fss.copyFileSync(src, dest);
|
|
506
|
-
copiedCount++;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
if (copiedCount > 0) {
|
|
511
|
-
userInfo(`✅ ${copiedCount} 个知识模板已复制到 .soloforge/knowledge/`);
|
|
512
|
-
}
|
|
491
|
+
const { copyKnowledgeToProject } = await import("../engine/template_init_sync.js");
|
|
492
|
+
const templatesRoot = path.resolve(import.meta.dirname, "..", "..");
|
|
493
|
+
const result = await copyKnowledgeToProject(templatesRoot, projectPath);
|
|
494
|
+
const parts = [];
|
|
495
|
+
if (result.copied > 0)
|
|
496
|
+
parts.push(`${result.copied} 个已复制`);
|
|
497
|
+
if (result.skipped_internal > 0)
|
|
498
|
+
parts.push(`${result.skipped_internal} 个内部资产已跳过`);
|
|
499
|
+
if (result.skipped_no_contract > 0)
|
|
500
|
+
parts.push(`${result.skipped_no_contract} 个无合同已跳过`);
|
|
501
|
+
if (parts.length > 0) {
|
|
502
|
+
userInfo(`✅ 知识模板: ${parts.join(",")}`);
|
|
513
503
|
}
|
|
514
504
|
}
|
|
515
505
|
async function generateAdapterConfigs(projectPath, adapter) {
|
|
@@ -870,8 +860,7 @@ async function cmdValidate() {
|
|
|
870
860
|
try {
|
|
871
861
|
const { config, source } = await resolveProjectConfig(projectPath);
|
|
872
862
|
if (source === "inferred") {
|
|
873
|
-
userInfo("ℹ️
|
|
874
|
-
userInfo(" 运行 'soloforge init --auto' 可持久化。");
|
|
863
|
+
userInfo("ℹ️ 配置来源: 自动推断");
|
|
875
864
|
}
|
|
876
865
|
else {
|
|
877
866
|
userInfo("✅ config.yaml 有效");
|
|
@@ -1068,6 +1057,18 @@ async function cmdValidate() {
|
|
|
1068
1057
|
hasHardFail = true;
|
|
1069
1058
|
}
|
|
1070
1059
|
} // 双层机制检查结束
|
|
1060
|
+
try {
|
|
1061
|
+
const { planNextAction } = await import("../engine/next_action_planner.js");
|
|
1062
|
+
const navigation = await planNextAction(projectPath);
|
|
1063
|
+
userInfo(` 阶段: ${navigation.project_stage}${navigation.task_stage ? ` / ${navigation.task_stage}` : ""}`);
|
|
1064
|
+
if (navigation.blocking_reasons.length > 0) {
|
|
1065
|
+
userInfo(` 导航阻断: ${navigation.blocking_reasons.join("; ")}`);
|
|
1066
|
+
}
|
|
1067
|
+
userInfo(` 下一步: ${navigation.work_package?.goal_zh ?? navigation.recommended_prompt_zh}`);
|
|
1068
|
+
}
|
|
1069
|
+
catch (e) {
|
|
1070
|
+
userInfo(` ⚠ 导航摘要异常: ${e instanceof Error ? e.message : String(e)}`);
|
|
1071
|
+
}
|
|
1071
1072
|
if (hasHardFail) {
|
|
1072
1073
|
userError("❌ validate 失败: 配置优先级存在 hard_fail");
|
|
1073
1074
|
process.exit(1);
|
|
@@ -1590,14 +1591,14 @@ async function cmdSyncTemplates() {
|
|
|
1590
1591
|
else {
|
|
1591
1592
|
userInfo(apply ? "模板同步: apply 模式" : "模板同步: dry-run 模式(不写入文件)");
|
|
1592
1593
|
userInfo(` 资产总数: ${assets.length}`);
|
|
1593
|
-
userInfo(`
|
|
1594
|
+
userInfo(` 应用安全: ${safeCheck.safe ? "安全" : "需确认"}`);
|
|
1594
1595
|
userInfo(` 结果: ${syncResult.success ? "成功" : "失败"}`);
|
|
1595
1596
|
userInfo(` 新增: ${syncResult.report.added.length}`);
|
|
1596
1597
|
userInfo(` 更新: ${syncResult.report.updated.length}`);
|
|
1597
1598
|
userInfo(` 跳过(用户修改): ${syncResult.report.skipped_user_modified.length}`);
|
|
1598
1599
|
userInfo(` 废弃: ${syncResult.report.deprecated.length}`);
|
|
1599
1600
|
if (!apply)
|
|
1600
|
-
userInfo(" 使用 --apply --confirm
|
|
1601
|
+
userInfo(" 使用 --apply --confirm 应用同步;需确认表示 dry-run 发现现有用户资产,不会自动覆盖");
|
|
1601
1602
|
}
|
|
1602
1603
|
if (!syncResult.success)
|
|
1603
1604
|
process.exit(1);
|
|
@@ -1973,8 +1974,8 @@ async function cmdValidateNewIssue() {
|
|
|
1973
1974
|
userInfo(JSON.stringify(output, null, 2));
|
|
1974
1975
|
}
|
|
1975
1976
|
else {
|
|
1976
|
-
userInfo(
|
|
1977
|
-
userInfo(` 已检查 ${allProblems.length}
|
|
1977
|
+
userInfo(`需求演进检查: ${output.gate_status}`);
|
|
1978
|
+
userInfo(` 已检查 ${allProblems.length} 个已有功能记录`);
|
|
1978
1979
|
if (output.duplicate_detected) {
|
|
1979
1980
|
userInfo(` ⚠ 重复检测: 发现 ${output.duplicates.join(", ")}`);
|
|
1980
1981
|
for (const d of matchedDetails) {
|
|
@@ -1987,7 +1988,7 @@ async function cmdValidateNewIssue() {
|
|
|
1987
1988
|
userInfo(` - ${r}`);
|
|
1988
1989
|
}
|
|
1989
1990
|
if (output.can_proceed) {
|
|
1990
|
-
userInfo(` ✓ 可继续:
|
|
1991
|
+
userInfo(` ✓ 可继续: 需求新增已通过演进检查 (ID: ${candidateId})`);
|
|
1991
1992
|
}
|
|
1992
1993
|
}
|
|
1993
1994
|
if (!output.can_proceed) {
|
|
@@ -1997,8 +1998,8 @@ async function cmdValidateNewIssue() {
|
|
|
1997
1998
|
async function cmdStatus() {
|
|
1998
1999
|
debug("CLI", "执行 cmdStatus");
|
|
1999
2000
|
const projectPath = resolveProjectPath();
|
|
2000
|
-
userInfo(`SoloForge 状态: ${projectPath}`);
|
|
2001
2001
|
const { config, source } = await resolveProjectConfig(projectPath);
|
|
2002
|
+
userInfo(`SoloForge 状态: ${projectPath}`);
|
|
2002
2003
|
userInfo(` 配置来源: ${source === "config_file" ? "config.yaml" : "自动推断"}`);
|
|
2003
2004
|
userInfo(` 产品: ${config.product_profile}`);
|
|
2004
2005
|
userInfo(` 后端: ${config.tech_stack.backend.framework || "未配置"}`);
|
|
@@ -2051,6 +2052,19 @@ async function cmdStatus() {
|
|
|
2051
2052
|
else {
|
|
2052
2053
|
userInfo(" 知识: 未初始化");
|
|
2053
2054
|
}
|
|
2055
|
+
// 导航摘要(消费同一规划模块,包含阻断项和下一步)
|
|
2056
|
+
try {
|
|
2057
|
+
const { planNextAction } = await import("../engine/next_action_planner.js");
|
|
2058
|
+
const navigation = await planNextAction(projectPath);
|
|
2059
|
+
userInfo(` 阶段: ${navigation.project_stage}${navigation.task_stage ? ` / ${navigation.task_stage}` : ""}`);
|
|
2060
|
+
if (navigation.blocking_reasons.length > 0) {
|
|
2061
|
+
userInfo(` 导航阻断: ${navigation.blocking_reasons.join("; ")}`);
|
|
2062
|
+
}
|
|
2063
|
+
userInfo(` 下一步: ${navigation.work_package?.goal_zh ?? navigation.recommended_prompt_zh}`);
|
|
2064
|
+
}
|
|
2065
|
+
catch (e) {
|
|
2066
|
+
userInfo(` ⚠ 导航摘要异常: ${e instanceof Error ? e.message : String(e)}`);
|
|
2067
|
+
}
|
|
2054
2068
|
}
|
|
2055
2069
|
async function interactiveConfig(projectPath) {
|
|
2056
2070
|
debug("CLI", "执行 interactiveConfig");
|
|
@@ -2113,6 +2127,200 @@ function cmdVersion() {
|
|
|
2113
2127
|
userInfo("SoloForge v" + pkg.version);
|
|
2114
2128
|
}
|
|
2115
2129
|
}
|
|
2130
|
+
async function cmdNext() {
|
|
2131
|
+
debug("CLI", "执行 cmdNext");
|
|
2132
|
+
const projectPath = resolveProjectPath();
|
|
2133
|
+
const isJson = args.includes("--json");
|
|
2134
|
+
const writeSnapshot = args.includes("--write-snapshot");
|
|
2135
|
+
const { planNextAction } = await import("../engine/next_action_planner.js");
|
|
2136
|
+
const plan = await planNextAction(projectPath);
|
|
2137
|
+
if (isJson) {
|
|
2138
|
+
// JSON 模式: 纯 JSON 到 stdout,无日志污染
|
|
2139
|
+
const wp = plan.work_package;
|
|
2140
|
+
const output = {
|
|
2141
|
+
project_stage: plan.project_stage,
|
|
2142
|
+
task_stage: plan.task_stage,
|
|
2143
|
+
confidence: plan.confidence,
|
|
2144
|
+
stage_evidence: plan.stage_evidence,
|
|
2145
|
+
blocking_reasons: plan.blocking_reasons,
|
|
2146
|
+
recommended_commands: plan.recommended_commands,
|
|
2147
|
+
recommended_prompt: plan.recommended_prompt_zh,
|
|
2148
|
+
disallowed_next_actions: plan.disallowed_actions.map((da) => ({
|
|
2149
|
+
rule_id: da.rule_id,
|
|
2150
|
+
blocked_actions: da.blocked_actions,
|
|
2151
|
+
reason_zh: da.reason_zh,
|
|
2152
|
+
})),
|
|
2153
|
+
work_package: wp ? {
|
|
2154
|
+
id: wp.id,
|
|
2155
|
+
goal: wp.goal_zh,
|
|
2156
|
+
input_files: wp.input_files,
|
|
2157
|
+
must_read: wp.must_read,
|
|
2158
|
+
forbidden_changes: wp.forbidden_changes,
|
|
2159
|
+
expected_outputs: wp.expected_outputs,
|
|
2160
|
+
acceptance_commands: wp.acceptance_commands,
|
|
2161
|
+
user_confirmation_points: wp.user_confirmation_points,
|
|
2162
|
+
rollback_or_fallback: wp.rollback_or_fallback,
|
|
2163
|
+
} : null,
|
|
2164
|
+
};
|
|
2165
|
+
process.stdout.write(JSON.stringify(output, null, 2) + "\n");
|
|
2166
|
+
}
|
|
2167
|
+
else {
|
|
2168
|
+
// 人类可读输出
|
|
2169
|
+
userInfo(`\n项目阶段: ${plan.project_stage}`);
|
|
2170
|
+
if (plan.task_stage) {
|
|
2171
|
+
userInfo(`任务阶段: ${plan.task_stage}`);
|
|
2172
|
+
}
|
|
2173
|
+
else {
|
|
2174
|
+
userInfo("任务阶段: 无活跃任务");
|
|
2175
|
+
}
|
|
2176
|
+
userInfo(`置信度: ${plan.confidence}`);
|
|
2177
|
+
if (plan.stage_evidence.length > 0) {
|
|
2178
|
+
userInfo(`\n判断依据:`);
|
|
2179
|
+
for (const ev of plan.stage_evidence) {
|
|
2180
|
+
userInfo(` - ${ev}`);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
// 陈旧任务
|
|
2184
|
+
if (plan.stale_task?.is_stale) {
|
|
2185
|
+
userInfo(`\n⚠️ 检测到陈旧任务: ${plan.stale_task.reason_zh}`);
|
|
2186
|
+
userInfo(` 任务 ID: ${plan.stale_task.task_id}`);
|
|
2187
|
+
userInfo(` 建议操作: ${plan.stale_task.suggested_resolutions.join(" / ")}`);
|
|
2188
|
+
userInfo(` ⚠️ 不要绕过 SoloForge 状态直接操作`);
|
|
2189
|
+
}
|
|
2190
|
+
// 阻断项
|
|
2191
|
+
if (plan.blocking_reasons.length > 0) {
|
|
2192
|
+
userInfo(`\n阻断项:`);
|
|
2193
|
+
for (const r of plan.blocking_reasons) {
|
|
2194
|
+
userInfo(` - ${r}`);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
// 工作包
|
|
2198
|
+
if (plan.work_package) {
|
|
2199
|
+
const wp = plan.work_package;
|
|
2200
|
+
userInfo(`\n下一步: ${wp.goal_zh}`);
|
|
2201
|
+
userInfo(` 描述: ${wp.description_zh}`);
|
|
2202
|
+
if (wp.tool_name) {
|
|
2203
|
+
userInfo(` 工具: ${wp.tool_name}`);
|
|
2204
|
+
}
|
|
2205
|
+
if (wp.must_read.length > 0) {
|
|
2206
|
+
userInfo(` 必读文件:`);
|
|
2207
|
+
for (const f of wp.must_read)
|
|
2208
|
+
userInfo(` - ${f}`);
|
|
2209
|
+
}
|
|
2210
|
+
if (wp.forbidden_changes.length > 0) {
|
|
2211
|
+
userInfo(` 禁止操作:`);
|
|
2212
|
+
for (const f of wp.forbidden_changes)
|
|
2213
|
+
userInfo(` - ${f}`);
|
|
2214
|
+
}
|
|
2215
|
+
if (wp.expected_outputs.length > 0) {
|
|
2216
|
+
userInfo(` 预期产出:`);
|
|
2217
|
+
for (const e of wp.expected_outputs)
|
|
2218
|
+
userInfo(` - ${e}`);
|
|
2219
|
+
}
|
|
2220
|
+
if (wp.acceptance_commands.length > 0) {
|
|
2221
|
+
userInfo(` 验收命令:`);
|
|
2222
|
+
for (const c of wp.acceptance_commands)
|
|
2223
|
+
userInfo(` - ${c}`);
|
|
2224
|
+
}
|
|
2225
|
+
if (wp.user_confirmation_points.length > 0) {
|
|
2226
|
+
userInfo(` 需用户确认:`);
|
|
2227
|
+
for (const u of wp.user_confirmation_points)
|
|
2228
|
+
userInfo(` - ${u}`);
|
|
2229
|
+
}
|
|
2230
|
+
if (wp.rollback_or_fallback.length > 0) {
|
|
2231
|
+
userInfo(` 失败回退:`);
|
|
2232
|
+
for (const r of wp.rollback_or_fallback)
|
|
2233
|
+
userInfo(` - ${r}`);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
// 推荐命令
|
|
2237
|
+
if (plan.recommended_commands.length > 0) {
|
|
2238
|
+
userInfo(`\n推荐命令:`);
|
|
2239
|
+
for (const c of plan.recommended_commands) {
|
|
2240
|
+
userInfo(` ${c}`);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
// 禁止动作
|
|
2244
|
+
if (plan.disallowed_actions.length > 0) {
|
|
2245
|
+
userInfo(`\n禁止动作:`);
|
|
2246
|
+
for (const da of plan.disallowed_actions) {
|
|
2247
|
+
userInfo(` [${da.rule_id}] ${da.blocked_actions.join(", ")}: ${da.reason_zh}`);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
// 推荐给 AI 的指令
|
|
2251
|
+
userInfo(`\n推荐指令: ${plan.recommended_prompt_zh}`);
|
|
2252
|
+
}
|
|
2253
|
+
// 写入快照(只在显式 --write-snapshot 时)
|
|
2254
|
+
if (writeSnapshot) {
|
|
2255
|
+
const snapshotPath = path.join(projectPath, ".soloforge", "navigation-snapshot.json");
|
|
2256
|
+
const snapshot = {
|
|
2257
|
+
plan_id: plan.plan_id,
|
|
2258
|
+
generated_at: plan.generated_at,
|
|
2259
|
+
project_stage: plan.project_stage,
|
|
2260
|
+
task_stage: plan.task_stage,
|
|
2261
|
+
current_task_id: plan.current_task_id,
|
|
2262
|
+
work_package: plan.work_package,
|
|
2263
|
+
};
|
|
2264
|
+
fss.mkdirSync(path.join(projectPath, ".soloforge"), { recursive: true });
|
|
2265
|
+
fss.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
|
|
2266
|
+
if (!isJson) {
|
|
2267
|
+
userInfo(`\n导航快照已写入: ${snapshotPath}`);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
async function cmdStage() {
|
|
2272
|
+
debug("CLI", "执行 cmdStage");
|
|
2273
|
+
const projectPath = resolveProjectPath();
|
|
2274
|
+
const explain = args.includes("--explain");
|
|
2275
|
+
const isJson = args.includes("--json");
|
|
2276
|
+
const { detectProjectStage, explainProjectStage } = await import("../engine/project_stage_detector.js");
|
|
2277
|
+
const { detectTaskStage, explainTaskStage } = await import("../engine/task_stage_detector.js");
|
|
2278
|
+
const projectStage = await detectProjectStage(projectPath);
|
|
2279
|
+
// 加载当前任务
|
|
2280
|
+
let taskStage = null;
|
|
2281
|
+
let taskId = null;
|
|
2282
|
+
try {
|
|
2283
|
+
const { TaskContextManager } = await import("../engine/task_context.js");
|
|
2284
|
+
const stateDir = path.join(projectPath, ".soloforge", "state");
|
|
2285
|
+
if (fss.existsSync(stateDir)) {
|
|
2286
|
+
const manager = new TaskContextManager(stateDir);
|
|
2287
|
+
const ctx = await manager.getCurrentTask();
|
|
2288
|
+
if (ctx) {
|
|
2289
|
+
taskStage = detectTaskStage(ctx);
|
|
2290
|
+
taskId = ctx.task_id;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
catch { }
|
|
2295
|
+
if (isJson) {
|
|
2296
|
+
const projExplanation = explainProjectStage(projectStage);
|
|
2297
|
+
process.stdout.write(JSON.stringify({
|
|
2298
|
+
project: projExplanation,
|
|
2299
|
+
task: taskStage ? explainTaskStage(taskStage) : null,
|
|
2300
|
+
task_id: taskId,
|
|
2301
|
+
}, null, 2) + "\n");
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
userInfo(`\n项目阶段: ${projectStage}`);
|
|
2305
|
+
if (explain) {
|
|
2306
|
+
const projExplanation = explainProjectStage(projectStage);
|
|
2307
|
+
userInfo(` ${projExplanation.description_zh}`);
|
|
2308
|
+
userInfo(` 必要条件: ${projExplanation.required_evidence.join(", ") || "无"}`);
|
|
2309
|
+
userInfo(` 下一步可能: ${projExplanation.next_possible_stages.join(", ")}`);
|
|
2310
|
+
}
|
|
2311
|
+
if (taskStage) {
|
|
2312
|
+
userInfo(`\n任务阶段: ${taskStage} (${taskId ?? "unknown"})`);
|
|
2313
|
+
if (explain) {
|
|
2314
|
+
const taskExplanation = explainTaskStage(taskStage);
|
|
2315
|
+
userInfo(` ${taskExplanation.description_zh}`);
|
|
2316
|
+
userInfo(` 必要条件: ${taskExplanation.required_evidence.join(", ")}`);
|
|
2317
|
+
userInfo(` 下一步可能: ${taskExplanation.next_possible_stages.join(", ")}`);
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
else {
|
|
2321
|
+
userInfo("\n当前无活跃任务");
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2116
2324
|
async function cmdCleanup() {
|
|
2117
2325
|
debug("CLI", "执行 cmdCleanup");
|
|
2118
2326
|
const dryRun = !args.includes("--apply");
|
|
@@ -2266,4 +2474,58 @@ function getArgValue(flag) {
|
|
|
2266
2474
|
return undefined;
|
|
2267
2475
|
return result;
|
|
2268
2476
|
}
|
|
2477
|
+
async function cmdAuditTemplateVisibility() {
|
|
2478
|
+
const projectPath = process.env.SOLOFORGE_PROJECT ?? process.cwd();
|
|
2479
|
+
const { auditStandardAssetCoverage } = await import("../engine/standard_asset_coverage.js");
|
|
2480
|
+
const { listBuiltinConsumableAssets } = await import("../engine/consumable_asset_registry.js");
|
|
2481
|
+
const { listTemplateAssetContracts, auditContractCoverage } = await import("../engine/template_asset_contract_registry.js");
|
|
2482
|
+
const { userInfo, userJson } = await import("../engine/logger.js");
|
|
2483
|
+
// 使用权威合同注册表作为单一数据源
|
|
2484
|
+
const contracts = listTemplateAssetContracts();
|
|
2485
|
+
const registeredAssets = listBuiltinConsumableAssets();
|
|
2486
|
+
const consumablePaths = new Set(registeredAssets.map((a) => a.path));
|
|
2487
|
+
const ownerMap = new Map(contracts.map((c) => [c.path, c.owner_mechanism_id]));
|
|
2488
|
+
const consumerMap = new Map(contracts.map((c) => [c.path, [c.mainline_consumer, c.validation_entrypoint].filter(Boolean)]));
|
|
2489
|
+
const visibilityMap = new Map(contracts.map((c) => [c.path, c.asset_visibility]));
|
|
2490
|
+
// 运行覆盖审计(使用真实合同数据)
|
|
2491
|
+
const report = auditStandardAssetCoverage(projectPath, consumablePaths, ownerMap, consumerMap, visibilityMap);
|
|
2492
|
+
// 合同覆盖统计
|
|
2493
|
+
const coverageReport = auditContractCoverage(projectPath);
|
|
2494
|
+
// 可见性统计(从权威合同直接计算)
|
|
2495
|
+
const internalCount = contracts.filter((c) => c.asset_visibility === "soloforge_internal" || c.asset_visibility === "scaffold_only").length;
|
|
2496
|
+
const userVisibleCount = contracts.filter((c) => c.user_visible).length;
|
|
2497
|
+
// 输出报告
|
|
2498
|
+
const isJson = args.includes("--json");
|
|
2499
|
+
const result = {
|
|
2500
|
+
total_assets: report.total_assets,
|
|
2501
|
+
contract_covered: coverageReport.contract_covered,
|
|
2502
|
+
uncovered_assets: coverageReport.uncovered,
|
|
2503
|
+
user_visible_count: userVisibleCount,
|
|
2504
|
+
internal_count: internalCount,
|
|
2505
|
+
unknown_visibility: coverageReport.visibility_unknown,
|
|
2506
|
+
conflict_count: 0,
|
|
2507
|
+
missing_bearer: report.missing_standard_bearer,
|
|
2508
|
+
missing_revalidation: report.missing_revalidation,
|
|
2509
|
+
missing_consumer: report.missing_consumer,
|
|
2510
|
+
missing_owner: report.missing_owner,
|
|
2511
|
+
unregistered: report.unregistered_assets,
|
|
2512
|
+
};
|
|
2513
|
+
if (isJson) {
|
|
2514
|
+
userJson(JSON.stringify(result, null, 2));
|
|
2515
|
+
}
|
|
2516
|
+
else {
|
|
2517
|
+
userInfo("═══ 模板资产可见性审计报告 ═══");
|
|
2518
|
+
userInfo(`总资产数: ${report.total_assets}`);
|
|
2519
|
+
userInfo(`合同覆盖: ${coverageReport.contract_covered}`);
|
|
2520
|
+
userInfo(`未覆盖: ${coverageReport.uncovered}`);
|
|
2521
|
+
userInfo(`用户可见: ${userVisibleCount}`);
|
|
2522
|
+
userInfo(`内部资产: ${internalCount}`);
|
|
2523
|
+
userInfo(`未知可见性: ${coverageReport.visibility_unknown}`);
|
|
2524
|
+
userInfo(`缺标准承载: ${report.missing_standard_bearer}`);
|
|
2525
|
+
userInfo(`缺复验入口: ${report.missing_revalidation}`);
|
|
2526
|
+
userInfo(`缺消费者: ${report.missing_consumer}`);
|
|
2527
|
+
userInfo(`缺 owner: ${report.missing_owner}`);
|
|
2528
|
+
userInfo(`未注册: ${report.unregistered_assets}`);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2269
2531
|
//# sourceMappingURL=soloforge.js.map
|