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,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conflict Resolver
|
|
3
|
+
*
|
|
4
|
+
* Manages both automatic and interactive conflict resolution.
|
|
5
|
+
* - Automatic mode: Uses FileClassifier for smart resolution
|
|
6
|
+
* - Interactive mode: Prompts user for decisions
|
|
7
|
+
* Provides three-tier resolution: skip-all, overwrite-all, or review-each.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const inquirer = require('inquirer');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const DiffViewer = require('./diff-viewer');
|
|
14
|
+
const { FileClassifier, FileCategory, ResolutionAction } = require('./file-classifier');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ConflictResolver class for automatic and interactive conflict resolution
|
|
18
|
+
*/
|
|
19
|
+
class ConflictResolver {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.diffViewer = new DiffViewer();
|
|
22
|
+
this.fileClassifier = new FileClassifier();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Resolves conflicts automatically using FileClassifier
|
|
27
|
+
*
|
|
28
|
+
* @param {FileConflict[]} conflicts - Array of conflicts
|
|
29
|
+
* @returns {Object} Resolution result with map and summary
|
|
30
|
+
*/
|
|
31
|
+
resolveConflictAutomatic(conflicts) {
|
|
32
|
+
const resolutionMap = {};
|
|
33
|
+
const summary = {
|
|
34
|
+
total: conflicts.length,
|
|
35
|
+
update: 0,
|
|
36
|
+
preserve: 0,
|
|
37
|
+
merge: 0,
|
|
38
|
+
skip: 0,
|
|
39
|
+
byCategory: {
|
|
40
|
+
[FileCategory.TEMPLATE]: [],
|
|
41
|
+
[FileCategory.USER_CONTENT]: [],
|
|
42
|
+
[FileCategory.CONFIG]: [],
|
|
43
|
+
[FileCategory.GENERATED]: []
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Process each conflict
|
|
48
|
+
for (const conflict of conflicts) {
|
|
49
|
+
// Get resolution rule from FileClassifier
|
|
50
|
+
const rule = this.fileClassifier.getResolutionRule(conflict.path);
|
|
51
|
+
|
|
52
|
+
// Map ResolutionAction to file resolution
|
|
53
|
+
let resolution;
|
|
54
|
+
switch (rule.action) {
|
|
55
|
+
case ResolutionAction.UPDATE:
|
|
56
|
+
resolution = 'overwrite';
|
|
57
|
+
summary.update++;
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
case ResolutionAction.PRESERVE:
|
|
61
|
+
resolution = 'keep';
|
|
62
|
+
summary.preserve++;
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case ResolutionAction.MERGE:
|
|
66
|
+
resolution = 'merge';
|
|
67
|
+
summary.merge++;
|
|
68
|
+
break;
|
|
69
|
+
|
|
70
|
+
case ResolutionAction.SKIP:
|
|
71
|
+
resolution = 'skip';
|
|
72
|
+
summary.skip++;
|
|
73
|
+
break;
|
|
74
|
+
|
|
75
|
+
default:
|
|
76
|
+
// Fallback: preserve for safety
|
|
77
|
+
resolution = 'keep';
|
|
78
|
+
summary.preserve++;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Store resolution
|
|
82
|
+
resolutionMap[conflict.path] = resolution;
|
|
83
|
+
|
|
84
|
+
// Track by category
|
|
85
|
+
summary.byCategory[rule.category].push({
|
|
86
|
+
path: conflict.path,
|
|
87
|
+
action: rule.action,
|
|
88
|
+
resolution: resolution,
|
|
89
|
+
reason: rule.reason
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
resolutionMap,
|
|
95
|
+
summary
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Displays automatic resolution summary
|
|
101
|
+
*
|
|
102
|
+
* @param {Object} summary - Resolution summary from resolveConflictAutomatic
|
|
103
|
+
* @returns {void}
|
|
104
|
+
*/
|
|
105
|
+
displayAutomaticResolutionSummary(summary) {
|
|
106
|
+
console.log();
|
|
107
|
+
console.log(chalk.blue('🤖 Automatic Conflict Resolution'));
|
|
108
|
+
console.log(chalk.blue('═══════════════════════════════════════════════════════'));
|
|
109
|
+
console.log();
|
|
110
|
+
|
|
111
|
+
console.log(chalk.cyan(`Total conflicts: ${summary.total}`));
|
|
112
|
+
console.log();
|
|
113
|
+
|
|
114
|
+
// Display by action
|
|
115
|
+
if (summary.update > 0) {
|
|
116
|
+
console.log(chalk.green(`✅ Update (backup + use template): ${summary.update} file(s)`));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (summary.preserve > 0) {
|
|
120
|
+
console.log(chalk.yellow(`⏭️ Preserve (keep existing): ${summary.preserve} file(s)`));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (summary.merge > 0) {
|
|
124
|
+
console.log(chalk.blue(`🔀 Merge (backup + merge): ${summary.merge} file(s)`));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (summary.skip > 0) {
|
|
128
|
+
console.log(chalk.gray(`⏩ Skip (regenerate): ${summary.skip} file(s)`));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log();
|
|
132
|
+
|
|
133
|
+
// Display by category
|
|
134
|
+
console.log(chalk.blue('By Category:'));
|
|
135
|
+
console.log();
|
|
136
|
+
|
|
137
|
+
// Template files
|
|
138
|
+
const templates = summary.byCategory[FileCategory.TEMPLATE];
|
|
139
|
+
if (templates.length > 0) {
|
|
140
|
+
console.log(chalk.green(`📝 Template Files (${templates.length}):`));
|
|
141
|
+
templates.forEach(item => {
|
|
142
|
+
console.log(chalk.gray(` → ${item.path} (${item.action})`));
|
|
143
|
+
});
|
|
144
|
+
console.log();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// User content
|
|
148
|
+
const userContent = summary.byCategory[FileCategory.USER_CONTENT];
|
|
149
|
+
if (userContent.length > 0) {
|
|
150
|
+
console.log(chalk.yellow(`📦 User Content (${userContent.length}):`));
|
|
151
|
+
userContent.forEach(item => {
|
|
152
|
+
console.log(chalk.gray(` → ${item.path} (${item.action})`));
|
|
153
|
+
});
|
|
154
|
+
console.log();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Config files
|
|
158
|
+
const configs = summary.byCategory[FileCategory.CONFIG];
|
|
159
|
+
if (configs.length > 0) {
|
|
160
|
+
console.log(chalk.blue(`⚙️ Config Files (${configs.length}):`));
|
|
161
|
+
configs.forEach(item => {
|
|
162
|
+
console.log(chalk.gray(` → ${item.path} (${item.action})`));
|
|
163
|
+
});
|
|
164
|
+
console.log();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Generated files
|
|
168
|
+
const generated = summary.byCategory[FileCategory.GENERATED];
|
|
169
|
+
if (generated.length > 0) {
|
|
170
|
+
console.log(chalk.gray(`🔄 Generated Files (${generated.length}):`));
|
|
171
|
+
generated.forEach(item => {
|
|
172
|
+
console.log(chalk.gray(` → ${item.path} (${item.action})`));
|
|
173
|
+
});
|
|
174
|
+
console.log();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
console.log(chalk.blue('═══════════════════════════════════════════════════════'));
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Displays conflict summary grouped by category
|
|
183
|
+
*
|
|
184
|
+
* @param {FileConflict[]} conflicts - Array of conflicts
|
|
185
|
+
* @returns {void}
|
|
186
|
+
*/
|
|
187
|
+
displayConflictSummary(conflicts) {
|
|
188
|
+
console.log();
|
|
189
|
+
console.log(chalk.yellow('⚠️ Conflicts Detected'));
|
|
190
|
+
console.log(chalk.yellow('═══════════════════════════════════════════════════════'));
|
|
191
|
+
console.log();
|
|
192
|
+
|
|
193
|
+
// Categorize conflicts
|
|
194
|
+
const categorized = this.categorizeConflicts(conflicts);
|
|
195
|
+
|
|
196
|
+
// Display by category
|
|
197
|
+
if (categorized.steering.length > 0) {
|
|
198
|
+
console.log(chalk.blue('Steering Files:'));
|
|
199
|
+
categorized.steering.forEach(c => console.log(` - ${c.path}`));
|
|
200
|
+
console.log();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (categorized.documentation.length > 0) {
|
|
204
|
+
console.log(chalk.blue('Documentation:'));
|
|
205
|
+
categorized.documentation.forEach(c => console.log(` - ${c.path}`));
|
|
206
|
+
console.log();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (categorized.tools.length > 0) {
|
|
210
|
+
console.log(chalk.blue('Tools:'));
|
|
211
|
+
categorized.tools.forEach(c => console.log(` - ${c.path}`));
|
|
212
|
+
console.log();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (categorized.other.length > 0) {
|
|
216
|
+
console.log(chalk.blue('Other:'));
|
|
217
|
+
categorized.other.forEach(c => console.log(` - ${c.path}`));
|
|
218
|
+
console.log();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
console.log(chalk.yellow(`Total: ${conflicts.length} conflict(s)`));
|
|
222
|
+
console.log(chalk.yellow('═══════════════════════════════════════════════════════'));
|
|
223
|
+
console.log();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Categorizes conflicts by type
|
|
228
|
+
*
|
|
229
|
+
* @param {FileConflict[]} conflicts - Array of conflicts
|
|
230
|
+
* @returns {CategorizedConflicts}
|
|
231
|
+
*/
|
|
232
|
+
categorizeConflicts(conflicts) {
|
|
233
|
+
return {
|
|
234
|
+
steering: conflicts.filter(c => c.path.startsWith('steering/')),
|
|
235
|
+
documentation: conflicts.filter(c =>
|
|
236
|
+
c.path.endsWith('.md') && !c.path.startsWith('steering/')
|
|
237
|
+
),
|
|
238
|
+
tools: conflicts.filter(c => c.path.startsWith('tools/')),
|
|
239
|
+
other: conflicts.filter(c =>
|
|
240
|
+
!c.path.startsWith('steering/') &&
|
|
241
|
+
!c.path.startsWith('tools/') &&
|
|
242
|
+
!c.path.endsWith('.md')
|
|
243
|
+
)
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Prompts user for overall conflict resolution strategy
|
|
249
|
+
*
|
|
250
|
+
* @param {FileConflict[]} conflicts - Array of detected conflicts
|
|
251
|
+
* @returns {Promise<ConflictStrategy>} - 'skip-all' | 'overwrite-all' | 'review-each'
|
|
252
|
+
*/
|
|
253
|
+
async promptStrategy(conflicts) {
|
|
254
|
+
const { strategy } = await inquirer.prompt([
|
|
255
|
+
{
|
|
256
|
+
type: 'list',
|
|
257
|
+
name: 'strategy',
|
|
258
|
+
message: 'How would you like to handle these conflicts?',
|
|
259
|
+
choices: [
|
|
260
|
+
{
|
|
261
|
+
name: 'Skip conflicting files (keep existing files)',
|
|
262
|
+
value: 'skip-all'
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'Overwrite conflicting files (backup will be created)',
|
|
266
|
+
value: 'overwrite-all'
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: 'Review conflicts one by one',
|
|
270
|
+
value: 'review-each'
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
default: 'skip-all'
|
|
274
|
+
}
|
|
275
|
+
]);
|
|
276
|
+
|
|
277
|
+
return strategy;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Prompts user for resolution of a single file conflict
|
|
282
|
+
*
|
|
283
|
+
* @param {FileConflict} conflict - The conflict to resolve
|
|
284
|
+
* @param {number} currentIndex - Current conflict number (for display)
|
|
285
|
+
* @param {number} totalConflicts - Total number of conflicts
|
|
286
|
+
* @param {string} projectPath - Project root path
|
|
287
|
+
* @returns {Promise<FileResolution>} - 'keep' | 'overwrite'
|
|
288
|
+
*/
|
|
289
|
+
async promptFileResolution(conflict, currentIndex, totalConflicts, projectPath) {
|
|
290
|
+
console.log();
|
|
291
|
+
console.log(chalk.blue('─────────────────────────────────────────────────────'));
|
|
292
|
+
console.log(chalk.blue(`Conflict ${currentIndex} of ${totalConflicts}`));
|
|
293
|
+
console.log(chalk.blue('─────────────────────────────────────────────────────'));
|
|
294
|
+
console.log();
|
|
295
|
+
console.log(chalk.cyan('File:'), conflict.path);
|
|
296
|
+
console.log();
|
|
297
|
+
|
|
298
|
+
let resolution = null;
|
|
299
|
+
|
|
300
|
+
while (resolution === null) {
|
|
301
|
+
const { action } = await inquirer.prompt([
|
|
302
|
+
{
|
|
303
|
+
type: 'list',
|
|
304
|
+
name: 'action',
|
|
305
|
+
message: 'What would you like to do?',
|
|
306
|
+
choices: [
|
|
307
|
+
{
|
|
308
|
+
name: 'Keep existing file',
|
|
309
|
+
value: 'keep'
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: 'Use template file (backup will be created)',
|
|
313
|
+
value: 'overwrite'
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: 'View diff',
|
|
317
|
+
value: 'view-diff'
|
|
318
|
+
}
|
|
319
|
+
],
|
|
320
|
+
default: 'keep'
|
|
321
|
+
}
|
|
322
|
+
]);
|
|
323
|
+
|
|
324
|
+
if (action === 'view-diff') {
|
|
325
|
+
// Show diff
|
|
326
|
+
const existingPath = path.join(projectPath, '.kiro', conflict.path);
|
|
327
|
+
const templatePath = conflict.templatePath || path.join(projectPath, 'template', '.kiro', conflict.path);
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
await this.diffViewer.showDiff(existingPath, templatePath);
|
|
331
|
+
} catch (diffError) {
|
|
332
|
+
console.log();
|
|
333
|
+
console.log(chalk.yellow('⚠️ Unable to generate diff for this file'));
|
|
334
|
+
console.log(chalk.gray(` Reason: ${diffError.message}`));
|
|
335
|
+
console.log();
|
|
336
|
+
console.log(chalk.gray(' You can open the files in your editor to compare:'));
|
|
337
|
+
console.log(chalk.gray(` Existing: ${existingPath}`));
|
|
338
|
+
console.log(chalk.gray(` Template: ${templatePath}`));
|
|
339
|
+
console.log();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Re-prompt with only keep/overwrite options
|
|
343
|
+
const { finalAction } = await inquirer.prompt([
|
|
344
|
+
{
|
|
345
|
+
type: 'list',
|
|
346
|
+
name: 'finalAction',
|
|
347
|
+
message: 'After viewing the diff, what would you like to do?',
|
|
348
|
+
choices: [
|
|
349
|
+
{
|
|
350
|
+
name: 'Keep existing file',
|
|
351
|
+
value: 'keep'
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: 'Use template file (backup will be created)',
|
|
355
|
+
value: 'overwrite'
|
|
356
|
+
}
|
|
357
|
+
],
|
|
358
|
+
default: 'keep'
|
|
359
|
+
}
|
|
360
|
+
]);
|
|
361
|
+
|
|
362
|
+
resolution = finalAction;
|
|
363
|
+
} else {
|
|
364
|
+
resolution = action;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return resolution;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Processes all conflicts based on strategy and returns resolution map
|
|
373
|
+
*
|
|
374
|
+
* @param {FileConflict[]} conflicts - Array of conflicts
|
|
375
|
+
* @param {ConflictStrategy} strategy - Overall strategy
|
|
376
|
+
* @param {string} projectPath - Project root path
|
|
377
|
+
* @returns {Promise<ResolutionMap>} - Map of file paths to resolutions
|
|
378
|
+
*/
|
|
379
|
+
async resolveConflicts(conflicts, strategy, projectPath) {
|
|
380
|
+
const resolutionMap = {};
|
|
381
|
+
|
|
382
|
+
if (strategy === 'skip-all') {
|
|
383
|
+
// Mark all as 'keep'
|
|
384
|
+
conflicts.forEach(conflict => {
|
|
385
|
+
resolutionMap[conflict.path] = 'keep';
|
|
386
|
+
});
|
|
387
|
+
} else if (strategy === 'overwrite-all') {
|
|
388
|
+
// Mark all as 'overwrite'
|
|
389
|
+
conflicts.forEach(conflict => {
|
|
390
|
+
resolutionMap[conflict.path] = 'overwrite';
|
|
391
|
+
});
|
|
392
|
+
} else if (strategy === 'review-each') {
|
|
393
|
+
// Prompt for each conflict
|
|
394
|
+
for (let i = 0; i < conflicts.length; i++) {
|
|
395
|
+
const conflict = conflicts[i];
|
|
396
|
+
const resolution = await this.promptFileResolution(
|
|
397
|
+
conflict,
|
|
398
|
+
i + 1,
|
|
399
|
+
conflicts.length,
|
|
400
|
+
projectPath
|
|
401
|
+
);
|
|
402
|
+
resolutionMap[conflict.path] = resolution;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return resolutionMap;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
module.exports = ConflictResolver;
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection Engine
|
|
3
|
+
*
|
|
4
|
+
* Analyzes project structure and determines the appropriate adoption strategy.
|
|
5
|
+
* Detects project type, existing .kiro/ components, and potential conflicts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const {
|
|
10
|
+
pathExists,
|
|
11
|
+
listFiles,
|
|
12
|
+
readJSON
|
|
13
|
+
} = require('../utils/fs-utils');
|
|
14
|
+
const SteeringManager = require('../steering/steering-manager');
|
|
15
|
+
|
|
16
|
+
class DetectionEngine {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.kiroDir = '.kiro';
|
|
19
|
+
this.versionFile = 'version.json';
|
|
20
|
+
this.specsDir = 'specs';
|
|
21
|
+
this.steeringDir = 'steering';
|
|
22
|
+
this.toolsDir = 'tools';
|
|
23
|
+
this.steeringManager = new SteeringManager();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Analyzes project directory and returns detection result
|
|
28
|
+
*
|
|
29
|
+
* @param {string} projectPath - Absolute path to project root
|
|
30
|
+
* @returns {Promise<DetectionResult>}
|
|
31
|
+
*/
|
|
32
|
+
async analyze(projectPath) {
|
|
33
|
+
try {
|
|
34
|
+
const kiroPath = path.join(projectPath, this.kiroDir);
|
|
35
|
+
const hasKiroDir = await pathExists(kiroPath);
|
|
36
|
+
|
|
37
|
+
let hasVersionFile = false;
|
|
38
|
+
let hasSpecs = false;
|
|
39
|
+
let hasSteering = false;
|
|
40
|
+
let hasTools = false;
|
|
41
|
+
let existingVersion = null;
|
|
42
|
+
let steeringDetection = null;
|
|
43
|
+
|
|
44
|
+
if (hasKiroDir) {
|
|
45
|
+
// Check for version.json
|
|
46
|
+
const versionPath = path.join(kiroPath, this.versionFile);
|
|
47
|
+
hasVersionFile = await pathExists(versionPath);
|
|
48
|
+
|
|
49
|
+
if (hasVersionFile) {
|
|
50
|
+
try {
|
|
51
|
+
const versionInfo = await readJSON(versionPath);
|
|
52
|
+
existingVersion = versionInfo['kse-version'] || null;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
// Invalid version file
|
|
55
|
+
hasVersionFile = false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check for specs/
|
|
60
|
+
const specsPath = path.join(kiroPath, this.specsDir);
|
|
61
|
+
hasSpecs = await pathExists(specsPath);
|
|
62
|
+
|
|
63
|
+
// Check for steering/ using SteeringManager
|
|
64
|
+
steeringDetection = await this.steeringManager.detectSteering(projectPath);
|
|
65
|
+
hasSteering = steeringDetection.hasExistingSteering;
|
|
66
|
+
|
|
67
|
+
// Check for tools/
|
|
68
|
+
const toolsPath = path.join(kiroPath, this.toolsDir);
|
|
69
|
+
hasTools = await pathExists(toolsPath);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Detect project type
|
|
73
|
+
const projectType = await this.detectProjectType(projectPath);
|
|
74
|
+
|
|
75
|
+
// Detect conflicts (only if we're going to add template files)
|
|
76
|
+
const conflicts = hasKiroDir ? await this.detectConflicts(projectPath) : [];
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
hasKiroDir,
|
|
80
|
+
hasVersionFile,
|
|
81
|
+
hasSpecs,
|
|
82
|
+
hasSteering,
|
|
83
|
+
hasTools,
|
|
84
|
+
projectType,
|
|
85
|
+
existingVersion,
|
|
86
|
+
conflicts,
|
|
87
|
+
steeringDetection // Add steering detection details
|
|
88
|
+
};
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw new Error(`Failed to analyze project: ${error.message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Determines which adoption strategy to use
|
|
96
|
+
*
|
|
97
|
+
* @param {DetectionResult} result - Detection result from analyze()
|
|
98
|
+
* @returns {AdoptionMode} - 'fresh', 'partial', or 'full'
|
|
99
|
+
*/
|
|
100
|
+
determineStrategy(result) {
|
|
101
|
+
// Fresh adoption: no .kiro/ directory
|
|
102
|
+
if (!result.hasKiroDir) {
|
|
103
|
+
return 'fresh';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Partial adoption: .kiro/ exists but no version.json
|
|
107
|
+
if (!result.hasVersionFile) {
|
|
108
|
+
return 'partial';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Full adoption: complete .kiro/ with version.json
|
|
112
|
+
return 'full';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Detects project type (Node.js, Python, mixed, unknown)
|
|
117
|
+
*
|
|
118
|
+
* @param {string} projectPath - Absolute path to project root
|
|
119
|
+
* @returns {Promise<ProjectType>}
|
|
120
|
+
*/
|
|
121
|
+
async detectProjectType(projectPath) {
|
|
122
|
+
try {
|
|
123
|
+
const hasPackageJson = await pathExists(path.join(projectPath, 'package.json'));
|
|
124
|
+
const hasRequirementsTxt = await pathExists(path.join(projectPath, 'requirements.txt'));
|
|
125
|
+
const hasPyprojectToml = await pathExists(path.join(projectPath, 'pyproject.toml'));
|
|
126
|
+
const hasSetupPy = await pathExists(path.join(projectPath, 'setup.py'));
|
|
127
|
+
|
|
128
|
+
const isNodeJs = hasPackageJson;
|
|
129
|
+
const isPython = hasRequirementsTxt || hasPyprojectToml || hasSetupPy;
|
|
130
|
+
|
|
131
|
+
if (isNodeJs && isPython) {
|
|
132
|
+
return 'mixed';
|
|
133
|
+
} else if (isNodeJs) {
|
|
134
|
+
return 'nodejs';
|
|
135
|
+
} else if (isPython) {
|
|
136
|
+
return 'python';
|
|
137
|
+
} else {
|
|
138
|
+
return 'unknown';
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
throw new Error(`Failed to detect project type: ${error.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Detects conflicts between existing files and template files
|
|
147
|
+
*
|
|
148
|
+
* @param {string} projectPath - Absolute path to project root
|
|
149
|
+
* @returns {Promise<FileConflict[]>}
|
|
150
|
+
*/
|
|
151
|
+
async detectConflicts(projectPath) {
|
|
152
|
+
const conflicts = [];
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const kiroPath = path.join(projectPath, this.kiroDir);
|
|
156
|
+
|
|
157
|
+
// Define template files that might conflict
|
|
158
|
+
const templateFiles = [
|
|
159
|
+
'steering/CORE_PRINCIPLES.md',
|
|
160
|
+
'steering/ENVIRONMENT.md',
|
|
161
|
+
'steering/CURRENT_CONTEXT.md',
|
|
162
|
+
'steering/RULES_GUIDE.md',
|
|
163
|
+
'tools/ultrawork_enhancer.py',
|
|
164
|
+
'README.md',
|
|
165
|
+
'ultrawork-application-guide.md',
|
|
166
|
+
'ultrawork-integration-summary.md',
|
|
167
|
+
'sisyphus-deep-dive.md'
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
for (const templateFile of templateFiles) {
|
|
171
|
+
const filePath = path.join(kiroPath, templateFile);
|
|
172
|
+
const exists = await pathExists(filePath);
|
|
173
|
+
|
|
174
|
+
if (exists) {
|
|
175
|
+
conflicts.push({
|
|
176
|
+
path: templateFile,
|
|
177
|
+
type: 'file',
|
|
178
|
+
existingContent: filePath,
|
|
179
|
+
templateContent: `template:${templateFile}`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return conflicts;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
throw new Error(`Failed to detect conflicts: ${error.message}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Categorizes conflicts by type for better display
|
|
192
|
+
*
|
|
193
|
+
* @param {FileConflict[]} conflicts - Array of conflicts
|
|
194
|
+
* @returns {CategorizedConflicts}
|
|
195
|
+
*/
|
|
196
|
+
categorizeConflicts(conflicts) {
|
|
197
|
+
return {
|
|
198
|
+
steering: conflicts.filter(c => c.path.startsWith('steering/')),
|
|
199
|
+
documentation: conflicts.filter(c =>
|
|
200
|
+
c.path.endsWith('.md') &&
|
|
201
|
+
!c.path.startsWith('steering/') &&
|
|
202
|
+
!c.path.startsWith('tools/')
|
|
203
|
+
),
|
|
204
|
+
tools: conflicts.filter(c => c.path.startsWith('tools/')),
|
|
205
|
+
other: conflicts.filter(c =>
|
|
206
|
+
!c.path.startsWith('steering/') &&
|
|
207
|
+
!c.path.startsWith('tools/') &&
|
|
208
|
+
!c.path.endsWith('.md')
|
|
209
|
+
)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Validates that a project path is valid
|
|
215
|
+
*
|
|
216
|
+
* @param {string} projectPath - Path to validate
|
|
217
|
+
* @returns {Promise<boolean>}
|
|
218
|
+
*/
|
|
219
|
+
async validateProjectPath(projectPath) {
|
|
220
|
+
try {
|
|
221
|
+
const exists = await pathExists(projectPath);
|
|
222
|
+
if (!exists) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Check if it's a directory
|
|
227
|
+
const fs = require('fs-extra');
|
|
228
|
+
const stats = await fs.stat(projectPath);
|
|
229
|
+
return stats.isDirectory();
|
|
230
|
+
} catch (error) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Gets a summary of the detection result for display
|
|
237
|
+
*
|
|
238
|
+
* @param {DetectionResult} result - Detection result
|
|
239
|
+
* @returns {string} - Human-readable summary
|
|
240
|
+
*/
|
|
241
|
+
getSummary(result) {
|
|
242
|
+
const lines = [];
|
|
243
|
+
|
|
244
|
+
lines.push('Project Analysis:');
|
|
245
|
+
lines.push(` Project Type: ${result.projectType}`);
|
|
246
|
+
lines.push(` .kiro/ Directory: ${result.hasKiroDir ? 'Yes' : 'No'}`);
|
|
247
|
+
|
|
248
|
+
if (result.hasKiroDir) {
|
|
249
|
+
lines.push(` version.json: ${result.hasVersionFile ? 'Yes' : 'No'}`);
|
|
250
|
+
if (result.existingVersion) {
|
|
251
|
+
lines.push(` Current Version: ${result.existingVersion}`);
|
|
252
|
+
}
|
|
253
|
+
lines.push(` specs/: ${result.hasSpecs ? 'Yes' : 'No'}`);
|
|
254
|
+
lines.push(` steering/: ${result.hasSteering ? 'Yes' : 'No'}`);
|
|
255
|
+
|
|
256
|
+
// Show steering details if available
|
|
257
|
+
if (result.steeringDetection && result.steeringDetection.hasExistingSteering) {
|
|
258
|
+
lines.push(` Files: ${result.steeringDetection.count} file(s)`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
lines.push(` tools/: ${result.hasTools ? 'Yes' : 'No'}`);
|
|
262
|
+
|
|
263
|
+
if (result.conflicts.length > 0) {
|
|
264
|
+
lines.push(` Conflicts: ${result.conflicts.length} file(s)`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const strategy = this.determineStrategy(result);
|
|
269
|
+
lines.push(` Recommended Strategy: ${strategy}`);
|
|
270
|
+
|
|
271
|
+
return lines.join('\n');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = DetectionEngine;
|