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,176 @@
|
|
|
1
|
+
const RepoManager = require('../repo-manager');
|
|
2
|
+
const ConfigManager = require('../config-manager');
|
|
3
|
+
const OutputFormatter = require('../output-formatter');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* StatusHandler - Handles repository status command
|
|
7
|
+
*
|
|
8
|
+
* Displays the Git status of all configured repositories in a
|
|
9
|
+
* tabular format with optional verbose output.
|
|
10
|
+
*/
|
|
11
|
+
class StatusHandler {
|
|
12
|
+
/**
|
|
13
|
+
* Create a new StatusHandler
|
|
14
|
+
* @param {string} projectRoot - The project root directory
|
|
15
|
+
*/
|
|
16
|
+
constructor(projectRoot) {
|
|
17
|
+
this.projectRoot = projectRoot;
|
|
18
|
+
this.repoManager = new RepoManager(projectRoot);
|
|
19
|
+
this.configManager = new ConfigManager(projectRoot);
|
|
20
|
+
this.formatter = new OutputFormatter();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Execute status command
|
|
25
|
+
* @param {Object} options - Status options
|
|
26
|
+
* @param {boolean} options.verbose - Show detailed file-level changes
|
|
27
|
+
* @returns {Promise<void>}
|
|
28
|
+
*/
|
|
29
|
+
async execute(options = {}) {
|
|
30
|
+
const { verbose = false } = options;
|
|
31
|
+
|
|
32
|
+
// Load configuration
|
|
33
|
+
let config;
|
|
34
|
+
try {
|
|
35
|
+
config = await this.configManager.loadConfig();
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.log(this.formatter.error(error.message));
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (config.repositories.length === 0) {
|
|
42
|
+
console.log(this.formatter.warning('No repositories configured'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get status for all repositories
|
|
47
|
+
const progress = this.formatter.createProgress('Checking repository status...');
|
|
48
|
+
progress.start();
|
|
49
|
+
|
|
50
|
+
let statuses;
|
|
51
|
+
try {
|
|
52
|
+
statuses = await this.repoManager.getAllRepoStatuses(config.repositories);
|
|
53
|
+
progress.stop();
|
|
54
|
+
} catch (error) {
|
|
55
|
+
progress.fail('Failed to get repository status');
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Display status
|
|
60
|
+
if (verbose) {
|
|
61
|
+
this.formatVerboseStatus(statuses);
|
|
62
|
+
} else {
|
|
63
|
+
this.formatStatusTable(statuses);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Display summary
|
|
67
|
+
const cleanRepos = statuses.filter(s => s.isClean && !s.error).length;
|
|
68
|
+
const dirtyRepos = statuses.filter(s => !s.isClean && !s.error).length;
|
|
69
|
+
const errorRepos = statuses.filter(s => s.error).length;
|
|
70
|
+
|
|
71
|
+
console.log('\nSummary:');
|
|
72
|
+
console.log(` Clean: ${cleanRepos}`);
|
|
73
|
+
console.log(` Modified: ${dirtyRepos}`);
|
|
74
|
+
if (errorRepos > 0) {
|
|
75
|
+
console.log(this.formatter.error(` Errors: ${errorRepos}`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Format status output as table
|
|
81
|
+
* @param {Array<Object>} statuses - Array of repository statuses
|
|
82
|
+
*/
|
|
83
|
+
formatStatusTable(statuses) {
|
|
84
|
+
const tableData = statuses.map(status => {
|
|
85
|
+
if (status.error) {
|
|
86
|
+
return [
|
|
87
|
+
status.name,
|
|
88
|
+
status.path,
|
|
89
|
+
this.formatter.error('ERROR'),
|
|
90
|
+
status.error
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const statusStr = status.isClean
|
|
95
|
+
? this.formatter.success('Clean')
|
|
96
|
+
: this.formatter.warning('Modified');
|
|
97
|
+
|
|
98
|
+
let changes = '';
|
|
99
|
+
if (!status.isClean) {
|
|
100
|
+
const parts = [];
|
|
101
|
+
if (status.modified > 0) parts.push(`M:${status.modified}`);
|
|
102
|
+
if (status.added > 0) parts.push(`A:${status.added}`);
|
|
103
|
+
if (status.deleted > 0) parts.push(`D:${status.deleted}`);
|
|
104
|
+
if (status.ahead > 0) parts.push(`↑${status.ahead}`);
|
|
105
|
+
if (status.behind > 0) parts.push(`↓${status.behind}`);
|
|
106
|
+
changes = parts.join(' ');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return [
|
|
110
|
+
status.name,
|
|
111
|
+
status.path,
|
|
112
|
+
status.branch || 'N/A',
|
|
113
|
+
statusStr,
|
|
114
|
+
changes
|
|
115
|
+
];
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const table = this.formatter.formatTable([], {
|
|
119
|
+
head: ['Name', 'Path', 'Branch', 'Status', 'Changes'],
|
|
120
|
+
rows: tableData
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log('\n' + table);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Format verbose status output
|
|
128
|
+
* @param {Array<Object>} statuses - Array of repository statuses
|
|
129
|
+
*/
|
|
130
|
+
formatVerboseStatus(statuses) {
|
|
131
|
+
console.log('\n' + this.formatter.info('Repository Status (Verbose)'));
|
|
132
|
+
console.log('='.repeat(80));
|
|
133
|
+
|
|
134
|
+
statuses.forEach((status, index) => {
|
|
135
|
+
if (index > 0) {
|
|
136
|
+
console.log('\n' + '-'.repeat(80));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(`\n${this.formatter.info('Repository:')} ${status.name}`);
|
|
140
|
+
console.log(`${this.formatter.info('Path:')} ${status.path}`);
|
|
141
|
+
|
|
142
|
+
if (status.error) {
|
|
143
|
+
console.log(`${this.formatter.error('Error:')} ${status.error}`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(`${this.formatter.info('Branch:')} ${status.branch}`);
|
|
148
|
+
|
|
149
|
+
if (status.isClean) {
|
|
150
|
+
console.log(this.formatter.success('Status: Clean - no changes'));
|
|
151
|
+
} else {
|
|
152
|
+
console.log(this.formatter.warning('Status: Modified'));
|
|
153
|
+
|
|
154
|
+
if (status.modified > 0) {
|
|
155
|
+
console.log(` Modified files: ${status.modified}`);
|
|
156
|
+
}
|
|
157
|
+
if (status.added > 0) {
|
|
158
|
+
console.log(` Added files: ${status.added}`);
|
|
159
|
+
}
|
|
160
|
+
if (status.deleted > 0) {
|
|
161
|
+
console.log(` Deleted files: ${status.deleted}`);
|
|
162
|
+
}
|
|
163
|
+
if (status.ahead > 0) {
|
|
164
|
+
console.log(` Commits ahead: ${status.ahead}`);
|
|
165
|
+
}
|
|
166
|
+
if (status.behind > 0) {
|
|
167
|
+
console.log(` Commits behind: ${status.behind}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
console.log('\n' + '='.repeat(80));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = StatusHandler;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const Table = require('cli-table3');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* OutputFormatter provides consistent formatting for command output
|
|
6
|
+
* with color-coding and table support.
|
|
7
|
+
*/
|
|
8
|
+
class OutputFormatter {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.chalk = chalk;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Format data as table
|
|
15
|
+
* @param {Object[]} data - Array of data objects
|
|
16
|
+
* @param {Object} options - Table options
|
|
17
|
+
* @param {string[]} options.head - Table header columns
|
|
18
|
+
* @param {string[][]} options.rows - Table rows (optional, will be extracted from data if not provided)
|
|
19
|
+
* @param {Object} options.style - Table style options (optional)
|
|
20
|
+
* @returns {string} Formatted table string
|
|
21
|
+
*/
|
|
22
|
+
formatTable(data, options = {}) {
|
|
23
|
+
const tableConfig = {
|
|
24
|
+
head: options.head || [],
|
|
25
|
+
style: {
|
|
26
|
+
head: ['cyan'],
|
|
27
|
+
border: ['gray'],
|
|
28
|
+
...options.style
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const table = new Table(tableConfig);
|
|
33
|
+
|
|
34
|
+
// If rows are provided directly, use them
|
|
35
|
+
if (options.rows) {
|
|
36
|
+
options.rows.forEach(row => table.push(row));
|
|
37
|
+
} else if (Array.isArray(data) && data.length > 0) {
|
|
38
|
+
// Otherwise, extract rows from data objects
|
|
39
|
+
data.forEach(item => {
|
|
40
|
+
const row = options.head.map(header => {
|
|
41
|
+
const key = header.toLowerCase().replace(/\s+/g, '');
|
|
42
|
+
return item[key] !== undefined ? String(item[key]) : '';
|
|
43
|
+
});
|
|
44
|
+
table.push(row);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return table.toString();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Format success message
|
|
53
|
+
* @param {string} message - Success message
|
|
54
|
+
* @returns {string} Formatted success message
|
|
55
|
+
*/
|
|
56
|
+
success(message) {
|
|
57
|
+
return chalk.green(`✅ ${message}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Format error message
|
|
62
|
+
* @param {string} message - Error message
|
|
63
|
+
* @returns {string} Formatted error message
|
|
64
|
+
*/
|
|
65
|
+
error(message) {
|
|
66
|
+
return chalk.red(`❌ ${message}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Format warning message
|
|
71
|
+
* @param {string} message - Warning message
|
|
72
|
+
* @returns {string} Formatted warning message
|
|
73
|
+
*/
|
|
74
|
+
warning(message) {
|
|
75
|
+
return chalk.yellow(`⚠️ ${message}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Format info message
|
|
80
|
+
* @param {string} message - Info message
|
|
81
|
+
* @returns {string} Formatted info message
|
|
82
|
+
*/
|
|
83
|
+
info(message) {
|
|
84
|
+
return chalk.blue(`ℹ️ ${message}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create progress indicator
|
|
89
|
+
* @param {string} message - Progress message
|
|
90
|
+
* @returns {ProgressIndicator} Progress indicator object
|
|
91
|
+
*/
|
|
92
|
+
createProgress(message) {
|
|
93
|
+
return new ProgressIndicator(message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* ProgressIndicator provides a simple progress indicator for long-running operations
|
|
99
|
+
*/
|
|
100
|
+
class ProgressIndicator {
|
|
101
|
+
constructor(message) {
|
|
102
|
+
this.message = message;
|
|
103
|
+
this.started = false;
|
|
104
|
+
this.frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
105
|
+
this.currentFrame = 0;
|
|
106
|
+
this.interval = null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Start the progress indicator
|
|
111
|
+
*/
|
|
112
|
+
start() {
|
|
113
|
+
if (this.started) return;
|
|
114
|
+
|
|
115
|
+
this.started = true;
|
|
116
|
+
process.stdout.write(`${this.frames[0]} ${this.message}`);
|
|
117
|
+
|
|
118
|
+
this.interval = setInterval(() => {
|
|
119
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
120
|
+
process.stdout.write(`\r${this.frames[this.currentFrame]} ${this.message}`);
|
|
121
|
+
}, 80);
|
|
122
|
+
if (this.interval && typeof this.interval.unref === 'function') {
|
|
123
|
+
this.interval.unref();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Update the progress message
|
|
129
|
+
* @param {string} message - New progress message
|
|
130
|
+
*/
|
|
131
|
+
update(message) {
|
|
132
|
+
this.message = message;
|
|
133
|
+
if (this.started) {
|
|
134
|
+
process.stdout.write(`\r${this.frames[this.currentFrame]} ${this.message}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Stop the progress indicator with a success message
|
|
140
|
+
* @param {string} message - Success message (optional)
|
|
141
|
+
*/
|
|
142
|
+
succeed(message) {
|
|
143
|
+
this.stop();
|
|
144
|
+
const finalMessage = message || this.message;
|
|
145
|
+
console.log(chalk.green(`✅ ${finalMessage}`));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Stop the progress indicator with an error message
|
|
150
|
+
* @param {string} message - Error message (optional)
|
|
151
|
+
*/
|
|
152
|
+
fail(message) {
|
|
153
|
+
this.stop();
|
|
154
|
+
const finalMessage = message || this.message;
|
|
155
|
+
console.log(chalk.red(`❌ ${finalMessage}`));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Stop the progress indicator with a warning message
|
|
160
|
+
* @param {string} message - Warning message (optional)
|
|
161
|
+
*/
|
|
162
|
+
warn(message) {
|
|
163
|
+
this.stop();
|
|
164
|
+
const finalMessage = message || this.message;
|
|
165
|
+
console.log(chalk.yellow(`⚠️ ${finalMessage}`));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Stop the progress indicator
|
|
170
|
+
*/
|
|
171
|
+
stop() {
|
|
172
|
+
if (!this.started) return;
|
|
173
|
+
|
|
174
|
+
if (this.interval) {
|
|
175
|
+
clearInterval(this.interval);
|
|
176
|
+
this.interval = null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
process.stdout.write('\r\x1b[K'); // Clear the line
|
|
180
|
+
this.started = false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = OutputFormatter;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PathResolver handles cross-platform path resolution and validation
|
|
5
|
+
* for repository paths. It ensures consistent path handling across
|
|
6
|
+
* Windows, Linux, and Mac platforms.
|
|
7
|
+
*/
|
|
8
|
+
class PathResolver {
|
|
9
|
+
/**
|
|
10
|
+
* Resolve repository path relative to project root
|
|
11
|
+
* @param {string} repoPath - The repository path (relative or absolute)
|
|
12
|
+
* @param {string} projectRoot - The project root directory
|
|
13
|
+
* @returns {string} Resolved absolute path
|
|
14
|
+
*/
|
|
15
|
+
resolvePath(repoPath, projectRoot) {
|
|
16
|
+
if (!repoPath) {
|
|
17
|
+
throw new Error('Repository path cannot be empty');
|
|
18
|
+
}
|
|
19
|
+
if (!projectRoot) {
|
|
20
|
+
throw new Error('Project root cannot be empty');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If path is absolute, return normalized version
|
|
24
|
+
if (this.isAbsolute(repoPath)) {
|
|
25
|
+
return this.normalizePath(path.resolve(repoPath));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Resolve relative path against project root
|
|
29
|
+
return this.normalizePath(path.resolve(projectRoot, repoPath));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Normalize path to use forward slashes consistently
|
|
34
|
+
* @param {string} pathStr - The path to normalize
|
|
35
|
+
* @returns {string} Normalized path with forward slashes
|
|
36
|
+
*/
|
|
37
|
+
normalizePath(pathStr) {
|
|
38
|
+
if (!pathStr) {
|
|
39
|
+
return pathStr;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Normalize the path first (resolves . and ..)
|
|
43
|
+
let normalized = path.normalize(pathStr);
|
|
44
|
+
|
|
45
|
+
// Convert backslashes to forward slashes
|
|
46
|
+
normalized = normalized.replace(/\\/g, '/');
|
|
47
|
+
|
|
48
|
+
// Handle Windows drive letters - keep them uppercase
|
|
49
|
+
if (this._isWindowsPath(normalized)) {
|
|
50
|
+
normalized = normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Remove trailing slashes (except for root paths)
|
|
54
|
+
if (normalized.length > 1 && normalized.endsWith('/')) {
|
|
55
|
+
// Don't remove trailing slash from root paths like '/' or 'C:/'
|
|
56
|
+
if (!(normalized.length === 3 && this._isWindowsPath(normalized))) {
|
|
57
|
+
normalized = normalized.slice(0, -1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return normalized;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if path is absolute (cross-platform)
|
|
66
|
+
* @param {string} pathStr - The path to check
|
|
67
|
+
* @returns {boolean} True if path is absolute
|
|
68
|
+
*/
|
|
69
|
+
isAbsolute(pathStr) {
|
|
70
|
+
if (!pathStr) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check for Windows absolute paths (C:/ or C:\) - must check first
|
|
75
|
+
// because path.isAbsolute() is platform-dependent
|
|
76
|
+
if (this._isWindowsPath(pathStr)) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for Unix absolute paths (starts with /)
|
|
81
|
+
// On Unix systems, this will correctly identify /home/user
|
|
82
|
+
// On Windows systems, this will correctly identify C:/... (already handled above)
|
|
83
|
+
return pathStr.startsWith('/');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Convert absolute path to relative path
|
|
88
|
+
* @param {string} absolutePath - The absolute path
|
|
89
|
+
* @param {string} basePath - The base path to make it relative to
|
|
90
|
+
* @returns {string} Relative path
|
|
91
|
+
*/
|
|
92
|
+
toRelative(absolutePath, basePath) {
|
|
93
|
+
if (!absolutePath || !basePath) {
|
|
94
|
+
throw new Error('Both absolutePath and basePath are required');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const relativePath = path.relative(basePath, absolutePath);
|
|
98
|
+
return this.normalizePath(relativePath);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Validate that paths don't overlap or nest within each other
|
|
103
|
+
* @param {string[]} paths - Array of absolute paths to validate
|
|
104
|
+
* @returns {{valid: boolean, errors: string[]}} Validation result
|
|
105
|
+
*/
|
|
106
|
+
validateNoOverlap(paths) {
|
|
107
|
+
const errors = [];
|
|
108
|
+
|
|
109
|
+
if (!Array.isArray(paths)) {
|
|
110
|
+
return { valid: false, errors: ['Paths must be an array'] };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (paths.length === 0) {
|
|
114
|
+
return { valid: true, errors: [] };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Normalize all paths for comparison
|
|
118
|
+
const normalizedPaths = paths.map(p => this.normalizePath(p));
|
|
119
|
+
|
|
120
|
+
// Check for duplicates
|
|
121
|
+
const seen = new Set();
|
|
122
|
+
for (let i = 0; i < normalizedPaths.length; i++) {
|
|
123
|
+
const p = normalizedPaths[i];
|
|
124
|
+
if (seen.has(p)) {
|
|
125
|
+
errors.push(`Duplicate path found: ${paths[i]}`);
|
|
126
|
+
}
|
|
127
|
+
seen.add(p);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check for overlapping/nested paths
|
|
131
|
+
for (let i = 0; i < normalizedPaths.length; i++) {
|
|
132
|
+
for (let j = i + 1; j < normalizedPaths.length; j++) {
|
|
133
|
+
const path1 = normalizedPaths[i];
|
|
134
|
+
const path2 = normalizedPaths[j];
|
|
135
|
+
|
|
136
|
+
// Check if path2 is nested within path1
|
|
137
|
+
if (this._isNestedPath(path2, path1)) {
|
|
138
|
+
errors.push(`Path "${paths[j]}" is nested within "${paths[i]}"`);
|
|
139
|
+
}
|
|
140
|
+
// Check if path1 is nested within path2
|
|
141
|
+
else if (this._isNestedPath(path1, path2)) {
|
|
142
|
+
errors.push(`Path "${paths[i]}" is nested within "${paths[j]}"`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
valid: errors.length === 0,
|
|
149
|
+
errors
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check if a path is nested within another path
|
|
155
|
+
* @private
|
|
156
|
+
* @param {string} childPath - The potential child path
|
|
157
|
+
* @param {string} parentPath - The potential parent path
|
|
158
|
+
* @returns {boolean} True if childPath is nested within parentPath
|
|
159
|
+
*/
|
|
160
|
+
_isNestedPath(childPath, parentPath) {
|
|
161
|
+
// Ensure paths end with separator for accurate comparison
|
|
162
|
+
const normalizedParent = parentPath.endsWith('/') ? parentPath : parentPath + '/';
|
|
163
|
+
return childPath.startsWith(normalizedParent);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Check if path is a Windows path (has drive letter)
|
|
168
|
+
* @private
|
|
169
|
+
* @param {string} pathStr - The path to check
|
|
170
|
+
* @returns {boolean} True if path is a Windows path
|
|
171
|
+
*/
|
|
172
|
+
_isWindowsPath(pathStr) {
|
|
173
|
+
// Check for drive letter pattern: C:/ or C:\
|
|
174
|
+
return /^[a-zA-Z]:/.test(pathStr);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports = PathResolver;
|