scene-capability-engine 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2513 -0
- package/LICENSE +21 -0
- package/README.md +765 -0
- package/README.zh.md +630 -0
- package/bin/kiro-spec-engine.js +796 -0
- package/bin/kse.js +3 -0
- package/bin/sce.js +3 -0
- package/bin/sco.js +3 -0
- package/docs/331-poc-adaptation-roadmap.md +156 -0
- package/docs/331-poc-dual-track-integration-guide.md +120 -0
- package/docs/331-poc-weekly-delivery-checklist.md +52 -0
- package/docs/OFFLINE_INSTALL.md +96 -0
- package/docs/README.md +279 -0
- package/docs/adopt-migration-guide.md +599 -0
- package/docs/adoption-guide.md +616 -0
- package/docs/agent-hooks-analysis.md +815 -0
- package/docs/architecture.md +733 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice-review.md +208 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +459 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.md +492 -0
- package/docs/autonomous-control-guide.md +851 -0
- package/docs/command-reference.md +1368 -0
- package/docs/community.md +115 -0
- package/docs/cross-tool-guide.md +555 -0
- package/docs/developer-guide.md +619 -0
- package/docs/document-governance.md +865 -0
- package/docs/environment-management-guide.md +526 -0
- package/docs/examples/add-export-command/design.md +194 -0
- package/docs/examples/add-export-command/requirements.md +110 -0
- package/docs/examples/add-export-command/tasks.md +88 -0
- package/docs/examples/add-rest-api/design.md +855 -0
- package/docs/examples/add-rest-api/requirements.md +323 -0
- package/docs/examples/add-rest-api/tasks.md +355 -0
- package/docs/examples/add-user-dashboard/design.md +192 -0
- package/docs/examples/add-user-dashboard/requirements.md +143 -0
- package/docs/examples/add-user-dashboard/tasks.md +91 -0
- package/docs/faq.md +697 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +156 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +24 -0
- package/docs/images/wechat-qr.png +0 -0
- package/docs/integration-modes.md +529 -0
- package/docs/integration-philosophy.md +313 -0
- package/docs/knowledge-management-guide.md +263 -0
- package/docs/manual-workflows-guide.md +418 -0
- package/docs/moqui-capability-matrix.md +73 -0
- package/docs/moqui-template-core-library-playbook.md +109 -0
- package/docs/multi-agent-coordination-guide.md +553 -0
- package/docs/multi-repo-management-guide.md +1344 -0
- package/docs/quick-start-with-ai-tools.md +375 -0
- package/docs/quick-start.md +146 -0
- package/docs/release-checklist.md +121 -0
- package/docs/releases/README.md +13 -0
- package/docs/releases/v1.46.2-validation.md +45 -0
- package/docs/releases/v1.46.2.md +50 -0
- package/docs/scene-runtime-guide.md +347 -0
- package/docs/spec-collaboration-guide.md +369 -0
- package/docs/spec-locking-guide.md +225 -0
- package/docs/spec-numbering-guide.md +348 -0
- package/docs/spec-workflow.md +519 -0
- package/docs/steering-strategy-guide.md +196 -0
- package/docs/team-collaboration-guide.md +465 -0
- package/docs/testing-strategy.md +272 -0
- package/docs/tools/claude-guide.md +654 -0
- package/docs/tools/cursor-guide.md +706 -0
- package/docs/tools/generic-guide.md +446 -0
- package/docs/tools/kiro-guide.md +308 -0
- package/docs/tools/vscode-guide.md +445 -0
- package/docs/tools/windsurf-guide.md +391 -0
- package/docs/troubleshooting.md +1135 -0
- package/docs/upgrade-guide.md +639 -0
- package/docs/value-observability-guide.md +127 -0
- package/docs/zh/README.md +341 -0
- package/docs/zh/quick-start.md +764 -0
- package/docs/zh/release-checklist.md +121 -0
- package/docs/zh/releases/README.md +13 -0
- package/docs/zh/releases/v1.46.2-validation.md +45 -0
- package/docs/zh/releases/v1.46.2.md +50 -0
- package/docs/zh/spec-numbering-guide.md +348 -0
- package/docs/zh/tools/claude-guide.md +349 -0
- package/docs/zh/tools/cursor-guide.md +281 -0
- package/docs/zh/tools/generic-guide.md +499 -0
- package/docs/zh/tools/kiro-guide.md +342 -0
- package/docs/zh/tools/vscode-guide.md +449 -0
- package/docs/zh/tools/windsurf-guide.md +378 -0
- package/docs/zh/value-observability-guide.md +127 -0
- package/docs//344/272/244/344/273/230/346/270/205/345/215/225.md +75 -0
- package/lib/adoption/adoption-logger.js +487 -0
- package/lib/adoption/adoption-strategy.js +538 -0
- package/lib/adoption/backup-manager.js +420 -0
- package/lib/adoption/conflict-resolver.js +410 -0
- package/lib/adoption/detection-engine.js +275 -0
- package/lib/adoption/diff-viewer.js +226 -0
- package/lib/adoption/error-formatter.js +509 -0
- package/lib/adoption/file-classifier.js +385 -0
- package/lib/adoption/progress-reporter.js +534 -0
- package/lib/adoption/smart-orchestrator.js +470 -0
- package/lib/adoption/strategy-selector.js +218 -0
- package/lib/adoption/summary-generator.js +493 -0
- package/lib/adoption/template-sync.js +605 -0
- package/lib/auto/autonomous-engine.js +485 -0
- package/lib/auto/checkpoint-manager.js +300 -0
- package/lib/auto/close-loop-runner.js +2476 -0
- package/lib/auto/config-schema.js +176 -0
- package/lib/auto/decision-engine.js +344 -0
- package/lib/auto/error-recovery-manager.js +580 -0
- package/lib/auto/goal-decomposer.js +278 -0
- package/lib/auto/progress-tracker.js +502 -0
- package/lib/auto/safety-manager.js +186 -0
- package/lib/auto/semantic-decomposer.js +137 -0
- package/lib/auto/state-manager.js +126 -0
- package/lib/auto/task-queue-manager.js +340 -0
- package/lib/backup/backup-system.js +372 -0
- package/lib/backup/selective-backup.js +207 -0
- package/lib/collab/agent-registry.js +240 -0
- package/lib/collab/collab-manager.js +285 -0
- package/lib/collab/contract-manager.js +320 -0
- package/lib/collab/coordinator.js +370 -0
- package/lib/collab/dependency-manager.js +280 -0
- package/lib/collab/index.js +20 -0
- package/lib/collab/integration-manager.js +202 -0
- package/lib/collab/merge-coordinator.js +252 -0
- package/lib/collab/metadata-manager.js +233 -0
- package/lib/collab/multi-agent-config.js +120 -0
- package/lib/collab/spec-lifecycle-manager.js +304 -0
- package/lib/collab/sync-barrier.js +88 -0
- package/lib/collab/visualizer.js +208 -0
- package/lib/commands/adopt.js +749 -0
- package/lib/commands/auto.js +19559 -0
- package/lib/commands/collab.js +275 -0
- package/lib/commands/context.js +99 -0
- package/lib/commands/docs.js +808 -0
- package/lib/commands/doctor.js +273 -0
- package/lib/commands/env.js +420 -0
- package/lib/commands/knowledge.js +309 -0
- package/lib/commands/lock.js +235 -0
- package/lib/commands/ops.js +409 -0
- package/lib/commands/orchestrate.js +446 -0
- package/lib/commands/prompt.js +105 -0
- package/lib/commands/repo.js +118 -0
- package/lib/commands/rollback.js +219 -0
- package/lib/commands/scene.js +15549 -0
- package/lib/commands/spec-bootstrap.js +147 -0
- package/lib/commands/spec-gate.js +157 -0
- package/lib/commands/spec-pipeline.js +205 -0
- package/lib/commands/status.js +321 -0
- package/lib/commands/task.js +199 -0
- package/lib/commands/templates.js +654 -0
- package/lib/commands/upgrade.js +231 -0
- package/lib/commands/value.js +569 -0
- package/lib/commands/watch.js +684 -0
- package/lib/commands/workflows.js +240 -0
- package/lib/commands/workspace-multi.js +325 -0
- package/lib/commands/workspace.js +189 -0
- package/lib/context/context-exporter.js +378 -0
- package/lib/context/prompt-generator.js +482 -0
- package/lib/data/moqui-capability-lexicon.json +45 -0
- package/lib/environment/backup-system.js +189 -0
- package/lib/environment/environment-manager.js +379 -0
- package/lib/environment/environment-registry.js +168 -0
- package/lib/gitignore/gitignore-backup.js +229 -0
- package/lib/gitignore/gitignore-detector.js +239 -0
- package/lib/gitignore/gitignore-integration.js +267 -0
- package/lib/gitignore/gitignore-transformer.js +193 -0
- package/lib/gitignore/layered-rules-template.js +42 -0
- package/lib/governance/archive-tool.js +284 -0
- package/lib/governance/cleanup-tool.js +237 -0
- package/lib/governance/config-manager.js +186 -0
- package/lib/governance/diagnostic-engine.js +271 -0
- package/lib/governance/doc-reference-checker.js +200 -0
- package/lib/governance/execution-logger.js +243 -0
- package/lib/governance/file-scanner.js +285 -0
- package/lib/governance/hooks-manager.js +333 -0
- package/lib/governance/reporter.js +337 -0
- package/lib/governance/validation-engine.js +181 -0
- package/lib/i18n.js +79 -0
- package/lib/knowledge/entry-manager.js +208 -0
- package/lib/knowledge/index-manager.js +261 -0
- package/lib/knowledge/knowledge-manager.js +273 -0
- package/lib/knowledge/template-manager.js +191 -0
- package/lib/lock/index.js +21 -0
- package/lib/lock/lock-file.js +192 -0
- package/lib/lock/lock-manager.js +321 -0
- package/lib/lock/machine-identifier.js +135 -0
- package/lib/lock/steering-file-lock.js +207 -0
- package/lib/lock/task-lock-manager.js +345 -0
- package/lib/operations/audit-logger.js +293 -0
- package/lib/operations/feedback-manager.js +1147 -0
- package/lib/operations/index.js +23 -0
- package/lib/operations/models/index.js +170 -0
- package/lib/operations/operations-manager.js +151 -0
- package/lib/operations/operations-validator.js +280 -0
- package/lib/operations/permission-manager.js +354 -0
- package/lib/operations/template-loader.js +143 -0
- package/lib/orchestrator/agent-spawner.js +629 -0
- package/lib/orchestrator/bootstrap-prompt-builder.js +236 -0
- package/lib/orchestrator/index.js +19 -0
- package/lib/orchestrator/orchestration-engine.js +1270 -0
- package/lib/orchestrator/orchestrator-config.js +173 -0
- package/lib/orchestrator/status-monitor.js +591 -0
- package/lib/python-checker.js +209 -0
- package/lib/repo/config-manager.js +580 -0
- package/lib/repo/errors/config-error.js +13 -0
- package/lib/repo/errors/git-error.js +15 -0
- package/lib/repo/errors/repo-error.js +14 -0
- package/lib/repo/git-operations.js +181 -0
- package/lib/repo/handlers/.gitkeep +1 -0
- package/lib/repo/handlers/exec-handler.js +155 -0
- package/lib/repo/handlers/health-handler.js +169 -0
- package/lib/repo/handlers/init-handler.js +197 -0
- package/lib/repo/handlers/status-handler.js +176 -0
- package/lib/repo/output-formatter.js +184 -0
- package/lib/repo/path-resolver.js +178 -0
- package/lib/repo/repo-manager.js +514 -0
- package/lib/scene-runtime/audit-emitter.js +59 -0
- package/lib/scene-runtime/binding-plugin-loader.js +351 -0
- package/lib/scene-runtime/binding-registry.js +349 -0
- package/lib/scene-runtime/eval-bridge.js +44 -0
- package/lib/scene-runtime/index.js +19 -0
- package/lib/scene-runtime/moqui-adapter.js +620 -0
- package/lib/scene-runtime/moqui-client.js +606 -0
- package/lib/scene-runtime/moqui-extractor.js +2029 -0
- package/lib/scene-runtime/plan-compiler.js +208 -0
- package/lib/scene-runtime/policy-gate.js +58 -0
- package/lib/scene-runtime/runtime-executor.js +358 -0
- package/lib/scene-runtime/scene-loader.js +96 -0
- package/lib/scene-runtime/scene-ontology.js +959 -0
- package/lib/scene-runtime/scene-template-linter.js +852 -0
- package/lib/scene-runtime/templates/scene-template-erp-query-v0.1.yaml +28 -0
- package/lib/scene-runtime/templates/scene-template-hybrid-shadow-v0.1.yaml +34 -0
- package/lib/spec/bootstrap/context-collector.js +48 -0
- package/lib/spec/bootstrap/draft-generator.js +158 -0
- package/lib/spec/bootstrap/questionnaire-engine.js +70 -0
- package/lib/spec/bootstrap/trace-emitter.js +59 -0
- package/lib/spec/multi-spec-orchestrate.js +93 -0
- package/lib/spec/pipeline/constants.js +6 -0
- package/lib/spec/pipeline/stage-adapters.js +118 -0
- package/lib/spec/pipeline/stage-runner.js +146 -0
- package/lib/spec/pipeline/state-store.js +119 -0
- package/lib/spec-gate/engine/gate-engine.js +165 -0
- package/lib/spec-gate/policy/default-policy.js +22 -0
- package/lib/spec-gate/policy/policy-loader.js +103 -0
- package/lib/spec-gate/result-emitter.js +81 -0
- package/lib/spec-gate/rules/default-rules.js +156 -0
- package/lib/spec-gate/rules/rule-registry.js +51 -0
- package/lib/steering/adoption-config.js +164 -0
- package/lib/steering/compliance-auto-fixer.js +204 -0
- package/lib/steering/compliance-cache.js +99 -0
- package/lib/steering/compliance-error-reporter.js +70 -0
- package/lib/steering/context-sync-manager.js +273 -0
- package/lib/steering/index.js +92 -0
- package/lib/steering/spec-steering.js +230 -0
- package/lib/steering/steering-compliance-checker.js +73 -0
- package/lib/steering/steering-loader.js +144 -0
- package/lib/steering/steering-manager.js +289 -0
- package/lib/task/index.js +12 -0
- package/lib/task/task-claimer.js +489 -0
- package/lib/task/task-status-store.js +418 -0
- package/lib/templates/cache-manager.js +440 -0
- package/lib/templates/content-generalizer.js +247 -0
- package/lib/templates/frontmatter-generator.js +128 -0
- package/lib/templates/git-handler.js +471 -0
- package/lib/templates/metadata-collector.js +328 -0
- package/lib/templates/path-utils.js +144 -0
- package/lib/templates/registry-parser.js +505 -0
- package/lib/templates/spec-reader.js +216 -0
- package/lib/templates/template-applicator.js +249 -0
- package/lib/templates/template-creator.js +256 -0
- package/lib/templates/template-error.js +143 -0
- package/lib/templates/template-exporter.js +502 -0
- package/lib/templates/template-manager.js +782 -0
- package/lib/templates/template-validator.js +361 -0
- package/lib/upgrade/migration-engine.js +382 -0
- package/lib/upgrade/migrations/.gitkeep +52 -0
- package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +78 -0
- package/lib/utils/file-diff.js +177 -0
- package/lib/utils/fs-utils.js +274 -0
- package/lib/utils/tool-detector.js +383 -0
- package/lib/utils/validation.js +324 -0
- package/lib/value/gate-summary-emitter.js +99 -0
- package/lib/value/metric-contract-loader.js +210 -0
- package/lib/value/risk-evaluator.js +117 -0
- package/lib/value/weekly-snapshot-builder.js +61 -0
- package/lib/version/version-checker.js +156 -0
- package/lib/version/version-manager.js +327 -0
- package/lib/watch/action-executor.js +458 -0
- package/lib/watch/event-debouncer.js +323 -0
- package/lib/watch/execution-logger.js +550 -0
- package/lib/watch/file-watcher.js +499 -0
- package/lib/watch/presets.js +266 -0
- package/lib/watch/watch-manager.js +533 -0
- package/lib/workspace/multi/global-config.js +150 -0
- package/lib/workspace/multi/index.js +22 -0
- package/lib/workspace/multi/path-utils.js +173 -0
- package/lib/workspace/multi/workspace-context-resolver.js +244 -0
- package/lib/workspace/multi/workspace-registry.js +196 -0
- package/lib/workspace/multi/workspace-state-manager.js +537 -0
- package/lib/workspace/multi/workspace.js +90 -0
- package/lib/workspace/workspace-manager.js +370 -0
- package/lib/workspace/workspace-sync.js +356 -0
- package/locales/en.json +114 -0
- package/locales/zh.json +114 -0
- package/package.json +102 -0
- package/template/.kiro/README.md +247 -0
- package/template/.kiro/hooks/check-spec-on-create.kiro.hook +17 -0
- package/template/.kiro/hooks/run-tests-on-save.kiro.hook +13 -0
- package/template/.kiro/hooks/sync-tasks-on-edit.kiro.hook +16 -0
- package/template/.kiro/specs/SPEC_WORKFLOW_GUIDE.md +134 -0
- package/template/.kiro/steering/CORE_PRINCIPLES.md +133 -0
- package/template/.kiro/steering/CURRENT_CONTEXT.md +30 -0
- package/template/.kiro/steering/ENVIRONMENT.md +35 -0
- package/template/.kiro/steering/RULES_GUIDE.md +46 -0
- package/template/.kiro/templates/operations/default/change-impact.md +112 -0
- package/template/.kiro/templates/operations/default/deployment.md +91 -0
- package/template/.kiro/templates/operations/default/feedback-response.md +269 -0
- package/template/.kiro/templates/operations/default/migration-plan.md +172 -0
- package/template/.kiro/templates/operations/default/monitoring.md +135 -0
- package/template/.kiro/templates/operations/default/operations.md +135 -0
- package/template/.kiro/templates/operations/default/rollback.md +143 -0
- package/template/.kiro/templates/operations/default/tools.yaml +364 -0
- package/template/.kiro/templates/operations/default/troubleshooting.md +123 -0
- package/template/.kiro/tools/backup_manager.py +295 -0
- package/template/.kiro/tools/configuration_manager.py +218 -0
- package/template/.kiro/tools/document_evaluator.py +550 -0
- package/template/.kiro/tools/enhancement_logger.py +168 -0
- package/template/.kiro/tools/error_handler.py +335 -0
- package/template/.kiro/tools/improvement_identifier.py +444 -0
- package/template/.kiro/tools/modification_applicator.py +737 -0
- package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
- package/template/.kiro/tools/quality_scorer.py +305 -0
- package/template/.kiro/tools/report_generator.py +154 -0
- package/template/.kiro/tools/ultrawork_enhancer.py +676 -0
- package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
- package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
- package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
- package/template/.kiro/tools/workflow_quality_gate.py +100 -0
- package/template/README.md +111 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SteeringComplianceChecker - Validates steering directory compliance
|
|
6
|
+
*
|
|
7
|
+
* Ensures the .kiro/steering/ directory contains only allowed files
|
|
8
|
+
* and no subdirectories to prevent context pollution and excessive
|
|
9
|
+
* token consumption in AI sessions.
|
|
10
|
+
*/
|
|
11
|
+
class SteeringComplianceChecker {
|
|
12
|
+
/**
|
|
13
|
+
* Get list of allowed files in steering directory
|
|
14
|
+
*
|
|
15
|
+
* @returns {string[]} Array of allowed file names
|
|
16
|
+
*/
|
|
17
|
+
getAllowedFiles() {
|
|
18
|
+
return [
|
|
19
|
+
'CORE_PRINCIPLES.md',
|
|
20
|
+
'ENVIRONMENT.md',
|
|
21
|
+
'CURRENT_CONTEXT.md',
|
|
22
|
+
'RULES_GUIDE.md'
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if steering directory is compliant
|
|
28
|
+
*
|
|
29
|
+
* @param {string} steeringPath - Path to steering directory
|
|
30
|
+
* @returns {ComplianceResult} Result with status and violations
|
|
31
|
+
*/
|
|
32
|
+
check(steeringPath) {
|
|
33
|
+
// Non-existent directory is compliant
|
|
34
|
+
if (!fs.existsSync(steeringPath)) {
|
|
35
|
+
return { compliant: true };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const violations = [];
|
|
39
|
+
const allowedFiles = this.getAllowedFiles();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const entries = fs.readdirSync(steeringPath, { withFileTypes: true });
|
|
43
|
+
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (entry.isDirectory()) {
|
|
46
|
+
// Subdirectories are not allowed
|
|
47
|
+
violations.push({
|
|
48
|
+
type: 'subdirectory',
|
|
49
|
+
name: entry.name,
|
|
50
|
+
path: path.join(steeringPath, entry.name)
|
|
51
|
+
});
|
|
52
|
+
} else if (!allowedFiles.includes(entry.name)) {
|
|
53
|
+
// File not in allowlist
|
|
54
|
+
violations.push({
|
|
55
|
+
type: 'disallowed_file',
|
|
56
|
+
name: entry.name,
|
|
57
|
+
path: path.join(steeringPath, entry.name)
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
compliant: violations.length === 0,
|
|
64
|
+
violations
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
// Re-throw unexpected errors
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = SteeringComplianceChecker;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SteeringLoader - 统一加载并合并 L1-L4 四层 Steering 约束
|
|
3
|
+
*
|
|
4
|
+
* L1: CORE_PRINCIPLES.md (通用约束)
|
|
5
|
+
* L2: ENVIRONMENT.md (环境约束)
|
|
6
|
+
* L3: CURRENT_CONTEXT.md (全局上下文)
|
|
7
|
+
* L4: .kiro/specs/{spec-name}/steering.md (Spec 级约束, via SpecSteering)
|
|
8
|
+
*
|
|
9
|
+
* 单 Agent 模式下跳过 L4。
|
|
10
|
+
*
|
|
11
|
+
* Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 6.4
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const fs = require('fs-extra');
|
|
16
|
+
const { SpecSteering } = require('./spec-steering');
|
|
17
|
+
const { MultiAgentConfig } = require('../collab/multi-agent-config');
|
|
18
|
+
|
|
19
|
+
const STEERING_DIR = '.kiro/steering';
|
|
20
|
+
|
|
21
|
+
const LAYER_FILES = {
|
|
22
|
+
l1: 'CORE_PRINCIPLES.md',
|
|
23
|
+
l2: 'ENVIRONMENT.md',
|
|
24
|
+
l3: 'CURRENT_CONTEXT.md',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
class SteeringLoader {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} workspaceRoot - Absolute path to the project root
|
|
30
|
+
*/
|
|
31
|
+
constructor(workspaceRoot) {
|
|
32
|
+
this._workspaceRoot = workspaceRoot;
|
|
33
|
+
this._specSteering = new SpecSteering(workspaceRoot);
|
|
34
|
+
this._multiAgentConfig = new MultiAgentConfig(workspaceRoot);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 加载所有层级的 Steering 内容。
|
|
39
|
+
* 单 Agent 模式下跳过 L4。
|
|
40
|
+
*
|
|
41
|
+
* @param {string|null} specName - 当前 Spec 名称,null 时跳过 L4
|
|
42
|
+
* @returns {Promise<{
|
|
43
|
+
* l1: string|null,
|
|
44
|
+
* l2: string|null,
|
|
45
|
+
* l3: string|null,
|
|
46
|
+
* l4: {constraints: string[], notes: string[], decisions: string[]}|null
|
|
47
|
+
* }>}
|
|
48
|
+
*/
|
|
49
|
+
async load(specName = null) {
|
|
50
|
+
const [l1, l2, l3] = await Promise.all([
|
|
51
|
+
this._loadLayerFile('l1'),
|
|
52
|
+
this._loadLayerFile('l2'),
|
|
53
|
+
this._loadLayerFile('l3'),
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
let l4 = null;
|
|
57
|
+
if (specName) {
|
|
58
|
+
const enabled = await this._multiAgentConfig.isEnabled();
|
|
59
|
+
if (enabled) {
|
|
60
|
+
l4 = await this._loadL4(specName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { l1, l2, l3, l4 };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 加载并合并所有层级,L4 覆盖 L1-L3 的冲突项。
|
|
69
|
+
* L4 内容追加在最后,使其优先级最高。
|
|
70
|
+
*
|
|
71
|
+
* @param {string|null} specName
|
|
72
|
+
* @returns {Promise<{layers: object, merged: string}>}
|
|
73
|
+
*/
|
|
74
|
+
async loadMerged(specName = null) {
|
|
75
|
+
const layers = await this.load(specName);
|
|
76
|
+
const parts = [];
|
|
77
|
+
|
|
78
|
+
if (layers.l1) {
|
|
79
|
+
parts.push(layers.l1);
|
|
80
|
+
}
|
|
81
|
+
if (layers.l2) {
|
|
82
|
+
parts.push(layers.l2);
|
|
83
|
+
}
|
|
84
|
+
if (layers.l3) {
|
|
85
|
+
parts.push(layers.l3);
|
|
86
|
+
}
|
|
87
|
+
if (layers.l4) {
|
|
88
|
+
parts.push(this._formatL4(layers.l4));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
layers,
|
|
93
|
+
merged: parts.join('\n\n---\n\n'),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── Private helpers ──────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Load a L1/L2/L3 layer file. Returns null if the file doesn't exist.
|
|
101
|
+
* @param {'l1'|'l2'|'l3'} layerKey
|
|
102
|
+
* @returns {Promise<string|null>}
|
|
103
|
+
*/
|
|
104
|
+
async _loadLayerFile(layerKey) {
|
|
105
|
+
const filename = LAYER_FILES[layerKey];
|
|
106
|
+
const filePath = path.join(this._workspaceRoot, STEERING_DIR, filename);
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const exists = await fs.pathExists(filePath);
|
|
110
|
+
if (!exists) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return await fs.readFile(filePath, 'utf8');
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.warn(`[SteeringLoader] Failed to read ${layerKey} (${filename}): ${err.message}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Load L4 via SpecSteering. Returns null if the file doesn't exist or is corrupted.
|
|
122
|
+
* @param {string} specName
|
|
123
|
+
* @returns {Promise<{constraints: string[], notes: string[], decisions: string[]}|null>}
|
|
124
|
+
*/
|
|
125
|
+
async _loadL4(specName) {
|
|
126
|
+
try {
|
|
127
|
+
return await this._specSteering.read(specName);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.warn(`[SteeringLoader] Failed to read L4 for ${specName}: ${err.message}`);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Format L4 structured object back to a Markdown string for merging.
|
|
136
|
+
* @param {{constraints: string[], notes: string[], decisions: string[]}} l4
|
|
137
|
+
* @returns {string}
|
|
138
|
+
*/
|
|
139
|
+
_formatL4(l4) {
|
|
140
|
+
return this._specSteering.format(l4);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = { SteeringLoader };
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SteeringManager - 管理 Steering 文件的独占使用
|
|
7
|
+
*
|
|
8
|
+
* 负责检测、备份、安装和恢复 steering 文件
|
|
9
|
+
*/
|
|
10
|
+
class SteeringManager {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.steeringDir = '.kiro/steering';
|
|
13
|
+
this.backupBaseDir = '.kiro/backups';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 检测项目中的 steering 文件
|
|
18
|
+
*
|
|
19
|
+
* @param {string} projectPath - 项目根目录路径
|
|
20
|
+
* @returns {Promise<Object>} 检测结果
|
|
21
|
+
*/
|
|
22
|
+
async detectSteering(projectPath) {
|
|
23
|
+
const steeringPath = path.join(projectPath, this.steeringDir);
|
|
24
|
+
|
|
25
|
+
// 检查 steering 目录是否存在
|
|
26
|
+
const exists = await fs.pathExists(steeringPath);
|
|
27
|
+
|
|
28
|
+
if (!exists) {
|
|
29
|
+
return {
|
|
30
|
+
hasExistingSteering: false,
|
|
31
|
+
files: [],
|
|
32
|
+
path: steeringPath
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 读取 steering 目录中的文件
|
|
37
|
+
const files = await fs.readdir(steeringPath);
|
|
38
|
+
|
|
39
|
+
// 过滤出 .md 文件
|
|
40
|
+
const mdFiles = files.filter(f => f.endsWith('.md'));
|
|
41
|
+
|
|
42
|
+
// 获取文件详细信息
|
|
43
|
+
const fileDetails = await Promise.all(
|
|
44
|
+
mdFiles.map(async (file) => {
|
|
45
|
+
const filePath = path.join(steeringPath, file);
|
|
46
|
+
const stats = await fs.stat(filePath);
|
|
47
|
+
return {
|
|
48
|
+
name: file,
|
|
49
|
+
path: filePath,
|
|
50
|
+
size: stats.size,
|
|
51
|
+
modified: stats.mtime
|
|
52
|
+
};
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
hasExistingSteering: mdFiles.length > 0,
|
|
58
|
+
files: fileDetails,
|
|
59
|
+
path: steeringPath,
|
|
60
|
+
count: mdFiles.length
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 提示用户选择 steering 策略
|
|
66
|
+
*
|
|
67
|
+
* @param {Object} detection - detectSteering 的返回结果
|
|
68
|
+
* @returns {Promise<string>} 选择的策略 ('use-kse' | 'use-project')
|
|
69
|
+
*/
|
|
70
|
+
async promptStrategy(detection) {
|
|
71
|
+
if (!detection.hasExistingSteering) {
|
|
72
|
+
// 没有现有 steering 文件,默认使用 kse
|
|
73
|
+
return 'use-kse';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log('\n⚠️ Steering Conflict Detected');
|
|
77
|
+
console.log('━'.repeat(60));
|
|
78
|
+
console.log(`Found ${detection.count} existing steering file(s) in ${this.steeringDir}:`);
|
|
79
|
+
console.log('');
|
|
80
|
+
|
|
81
|
+
detection.files.forEach(file => {
|
|
82
|
+
console.log(` • ${file.name} (${(file.size / 1024).toFixed(1)} KB)`);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
console.log('');
|
|
86
|
+
console.log('Kiro IDE loads all files in .kiro/steering/, which means you must');
|
|
87
|
+
console.log('choose between kse steering rules OR your project\'s existing rules.');
|
|
88
|
+
console.log('');
|
|
89
|
+
|
|
90
|
+
const response = await inquirer.prompt([{
|
|
91
|
+
type: 'list',
|
|
92
|
+
name: 'strategy',
|
|
93
|
+
message: 'How would you like to proceed?',
|
|
94
|
+
choices: [
|
|
95
|
+
{
|
|
96
|
+
name: 'Use kse steering (backup existing files) - Recommended for new kse users',
|
|
97
|
+
value: 'use-kse'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'Keep existing steering (skip kse steering) - For projects with custom steering rules',
|
|
101
|
+
value: 'use-project'
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}]);
|
|
105
|
+
|
|
106
|
+
return response.strategy;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 备份现有的 steering 文件
|
|
111
|
+
*
|
|
112
|
+
* @param {string} projectPath - 项目根目录路径
|
|
113
|
+
* @returns {Promise<Object>} 备份结果
|
|
114
|
+
*/
|
|
115
|
+
async backupSteering(projectPath) {
|
|
116
|
+
const steeringPath = path.join(projectPath, this.steeringDir);
|
|
117
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
118
|
+
const backupId = `steering-${timestamp}`;
|
|
119
|
+
const backupPath = path.join(projectPath, this.backupBaseDir, backupId);
|
|
120
|
+
|
|
121
|
+
// 检查 steering 目录是否存在
|
|
122
|
+
const exists = await fs.pathExists(steeringPath);
|
|
123
|
+
if (!exists) {
|
|
124
|
+
return {
|
|
125
|
+
success: false,
|
|
126
|
+
error: 'Steering directory does not exist',
|
|
127
|
+
backupId: null,
|
|
128
|
+
backupPath: null
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
// 创建备份目录
|
|
134
|
+
await fs.ensureDir(backupPath);
|
|
135
|
+
|
|
136
|
+
// 复制所有文件
|
|
137
|
+
await fs.copy(steeringPath, backupPath, {
|
|
138
|
+
overwrite: false,
|
|
139
|
+
errorOnExist: false
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// 验证备份
|
|
143
|
+
const backupFiles = await fs.readdir(backupPath);
|
|
144
|
+
const originalFiles = await fs.readdir(steeringPath);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
backupId,
|
|
149
|
+
backupPath,
|
|
150
|
+
filesBackedUp: backupFiles.length,
|
|
151
|
+
timestamp,
|
|
152
|
+
verified: backupFiles.length === originalFiles.length
|
|
153
|
+
};
|
|
154
|
+
} catch (error) {
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
error: error.message,
|
|
158
|
+
backupId,
|
|
159
|
+
backupPath
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 安装 kse steering 文件
|
|
166
|
+
*
|
|
167
|
+
* @param {string} projectPath - 项目根目录路径
|
|
168
|
+
* @returns {Promise<Object>} 安装结果
|
|
169
|
+
*/
|
|
170
|
+
async installKseSteering(projectPath) {
|
|
171
|
+
const steeringPath = path.join(projectPath, this.steeringDir);
|
|
172
|
+
const templatePath = path.join(__dirname, '../../template/.kiro/steering');
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
// 确保 steering 目录存在
|
|
176
|
+
await fs.ensureDir(steeringPath);
|
|
177
|
+
|
|
178
|
+
// 检查模板目录是否存在
|
|
179
|
+
const templateExists = await fs.pathExists(templatePath);
|
|
180
|
+
if (!templateExists) {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
error: 'kse steering template directory not found',
|
|
184
|
+
filesInstalled: 0
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 复制模板文件
|
|
189
|
+
const templateFiles = await fs.readdir(templatePath);
|
|
190
|
+
const mdFiles = templateFiles.filter(f => f.endsWith('.md'));
|
|
191
|
+
|
|
192
|
+
let installedCount = 0;
|
|
193
|
+
for (const file of mdFiles) {
|
|
194
|
+
const srcPath = path.join(templatePath, file);
|
|
195
|
+
const destPath = path.join(steeringPath, file);
|
|
196
|
+
|
|
197
|
+
await fs.copy(srcPath, destPath, {
|
|
198
|
+
overwrite: true
|
|
199
|
+
});
|
|
200
|
+
installedCount++;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
success: true,
|
|
205
|
+
filesInstalled: installedCount,
|
|
206
|
+
files: mdFiles
|
|
207
|
+
};
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
error: error.message,
|
|
212
|
+
filesInstalled: 0
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 从备份恢复 steering 文件
|
|
219
|
+
*
|
|
220
|
+
* @param {string} projectPath - 项目根目录路径
|
|
221
|
+
* @param {string} backupId - 备份 ID
|
|
222
|
+
* @returns {Promise<Object>} 恢复结果
|
|
223
|
+
*/
|
|
224
|
+
async restoreSteering(projectPath, backupId) {
|
|
225
|
+
const steeringPath = path.join(projectPath, this.steeringDir);
|
|
226
|
+
const backupPath = path.join(projectPath, this.backupBaseDir, backupId);
|
|
227
|
+
|
|
228
|
+
// 检查备份是否存在
|
|
229
|
+
const backupExists = await fs.pathExists(backupPath);
|
|
230
|
+
if (!backupExists) {
|
|
231
|
+
return {
|
|
232
|
+
success: false,
|
|
233
|
+
error: `Backup not found: ${backupId}`,
|
|
234
|
+
filesRestored: 0
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
// 清空现有 steering 目录
|
|
240
|
+
await fs.emptyDir(steeringPath);
|
|
241
|
+
|
|
242
|
+
// 从备份恢复
|
|
243
|
+
await fs.copy(backupPath, steeringPath, {
|
|
244
|
+
overwrite: true
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// 验证恢复
|
|
248
|
+
const restoredFiles = await fs.readdir(steeringPath);
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
success: true,
|
|
252
|
+
filesRestored: restoredFiles.length,
|
|
253
|
+
backupId,
|
|
254
|
+
files: restoredFiles
|
|
255
|
+
};
|
|
256
|
+
} catch (error) {
|
|
257
|
+
return {
|
|
258
|
+
success: false,
|
|
259
|
+
error: error.message,
|
|
260
|
+
filesRestored: 0,
|
|
261
|
+
backupId
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 列出所有可用的 steering 备份
|
|
268
|
+
*
|
|
269
|
+
* @param {string} projectPath - 项目根目录路径
|
|
270
|
+
* @returns {Promise<Array>} 备份列表
|
|
271
|
+
*/
|
|
272
|
+
async listBackups(projectPath) {
|
|
273
|
+
const backupBasePath = path.join(projectPath, this.backupBaseDir);
|
|
274
|
+
|
|
275
|
+
const exists = await fs.pathExists(backupBasePath);
|
|
276
|
+
if (!exists) {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const entries = await fs.readdir(backupBasePath, { withFileTypes: true });
|
|
281
|
+
const steeringBackups = entries
|
|
282
|
+
.filter(entry => entry.isDirectory() && entry.name.startsWith('steering-'))
|
|
283
|
+
.map(entry => entry.name);
|
|
284
|
+
|
|
285
|
+
return steeringBackups;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
module.exports = SteeringManager;
|