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,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FrontmatterGenerator - Generates YAML frontmatter for template files
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const yaml = require('js-yaml');
|
|
6
|
+
|
|
7
|
+
class FrontmatterGenerator {
|
|
8
|
+
constructor() {}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generates YAML frontmatter
|
|
12
|
+
* @param {Object} metadata - Template metadata
|
|
13
|
+
* @returns {string} YAML frontmatter block
|
|
14
|
+
*/
|
|
15
|
+
generateFrontmatter(metadata) {
|
|
16
|
+
const frontmatterData = {
|
|
17
|
+
name: metadata.name,
|
|
18
|
+
category: metadata.category,
|
|
19
|
+
description: metadata.description,
|
|
20
|
+
tags: metadata.tags || [],
|
|
21
|
+
author: metadata.author,
|
|
22
|
+
created_at: metadata.created_at,
|
|
23
|
+
updated_at: metadata.updated_at,
|
|
24
|
+
version: metadata.version,
|
|
25
|
+
kse_version: metadata.kse_version
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Add optional fields if present
|
|
29
|
+
if (metadata.difficulty) {
|
|
30
|
+
frontmatterData.difficulty = metadata.difficulty;
|
|
31
|
+
}
|
|
32
|
+
if (metadata.applicable_scenarios) {
|
|
33
|
+
frontmatterData.applicable_scenarios = metadata.applicable_scenarios;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const yamlContent = yaml.dump(frontmatterData, {
|
|
38
|
+
indent: 2,
|
|
39
|
+
lineWidth: -1,
|
|
40
|
+
noRefs: true
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return `---\n${yamlContent}---\n`;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new Error(`Failed to generate YAML frontmatter: ${error.message}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Adds frontmatter to file content
|
|
51
|
+
* @param {string} content - Original content
|
|
52
|
+
* @param {string} frontmatter - YAML frontmatter
|
|
53
|
+
* @returns {string} Content with frontmatter
|
|
54
|
+
*/
|
|
55
|
+
addFrontmatter(content, frontmatter) {
|
|
56
|
+
// Remove existing frontmatter if present
|
|
57
|
+
const withoutFrontmatter = this.removeFrontmatter(content);
|
|
58
|
+
|
|
59
|
+
// Add new frontmatter
|
|
60
|
+
return frontmatter + '\n' + withoutFrontmatter;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Removes existing frontmatter from content
|
|
65
|
+
* @param {string} content - Content with possible frontmatter
|
|
66
|
+
* @returns {string} Content without frontmatter
|
|
67
|
+
*/
|
|
68
|
+
removeFrontmatter(content) {
|
|
69
|
+
// Check if content starts with frontmatter
|
|
70
|
+
if (!content.trim().startsWith('---')) {
|
|
71
|
+
return content;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Find the closing ---
|
|
75
|
+
const lines = content.split('\n');
|
|
76
|
+
let endIndex = -1;
|
|
77
|
+
|
|
78
|
+
for (let i = 1; i < lines.length; i++) {
|
|
79
|
+
if (lines[i].trim() === '---') {
|
|
80
|
+
endIndex = i;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (endIndex === -1) {
|
|
86
|
+
// No closing ---, return original content
|
|
87
|
+
return content;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Return content after frontmatter
|
|
91
|
+
return lines.slice(endIndex + 1).join('\n').trim();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Validates YAML syntax
|
|
96
|
+
* @param {string} yamlContent - YAML content
|
|
97
|
+
* @returns {Object} Validation result
|
|
98
|
+
*/
|
|
99
|
+
validateYaml(yamlContent) {
|
|
100
|
+
try {
|
|
101
|
+
yaml.load(yamlContent);
|
|
102
|
+
return {
|
|
103
|
+
valid: true,
|
|
104
|
+
errors: []
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
errors: [error.message]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Formats array fields for YAML
|
|
116
|
+
* @param {Array} items - Array items
|
|
117
|
+
* @returns {string} Formatted YAML array
|
|
118
|
+
*/
|
|
119
|
+
formatArrayField(items) {
|
|
120
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
121
|
+
return '[]';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return items.map(item => ` - ${item}`).join('\n');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = FrontmatterGenerator;
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHandler - Handles Git operations for template repositories
|
|
3
|
+
*
|
|
4
|
+
* Provides functionality for cloning, updating, and managing Git repositories
|
|
5
|
+
* containing template libraries.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { execSync, exec } = require('child_process');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { GitError } = require('./template-error');
|
|
12
|
+
|
|
13
|
+
class GitHandler {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.gitAvailable = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Checks if Git is installed and available
|
|
20
|
+
*
|
|
21
|
+
* @returns {boolean} True if Git is available
|
|
22
|
+
*/
|
|
23
|
+
isGitInstalled() {
|
|
24
|
+
if (this.gitAvailable !== null) {
|
|
25
|
+
return this.gitAvailable;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
execSync('git --version', { stdio: 'ignore' });
|
|
30
|
+
this.gitAvailable = true;
|
|
31
|
+
return true;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
this.gitAvailable = false;
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Clones a Git repository
|
|
40
|
+
*
|
|
41
|
+
* @param {string} url - Repository URL
|
|
42
|
+
* @param {string} targetPath - Local path to clone to
|
|
43
|
+
* @param {Object} options - Clone options
|
|
44
|
+
* @param {boolean} options.shallow - Use shallow clone (--depth 1)
|
|
45
|
+
* @param {string} options.branch - Branch to clone
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
async cloneRepository(url, targetPath, options = {}) {
|
|
49
|
+
const { shallow = true, branch = null } = options;
|
|
50
|
+
|
|
51
|
+
// Check Git installation
|
|
52
|
+
if (!this.isGitInstalled()) {
|
|
53
|
+
throw new GitError(
|
|
54
|
+
'Git is not installed or not in PATH',
|
|
55
|
+
{
|
|
56
|
+
url,
|
|
57
|
+
targetPath,
|
|
58
|
+
suggestion: 'Install Git from https://git-scm.com/'
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Ensure target directory doesn't exist
|
|
64
|
+
if (await fs.pathExists(targetPath)) {
|
|
65
|
+
throw new GitError(
|
|
66
|
+
'Target directory already exists',
|
|
67
|
+
{
|
|
68
|
+
targetPath,
|
|
69
|
+
suggestion: 'Remove the directory or choose a different path'
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Build clone command
|
|
75
|
+
let command = 'git clone';
|
|
76
|
+
|
|
77
|
+
if (shallow) {
|
|
78
|
+
command += ' --depth 1';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (branch) {
|
|
82
|
+
command += ` --branch ${branch}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
command += ` "${url}" "${targetPath}"`;
|
|
86
|
+
|
|
87
|
+
// Execute clone
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
exec(command, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
90
|
+
if (error) {
|
|
91
|
+
// Classify error type
|
|
92
|
+
const errorMessage = stderr || error.message;
|
|
93
|
+
|
|
94
|
+
if (errorMessage.includes('Authentication failed') ||
|
|
95
|
+
errorMessage.includes('could not read Username')) {
|
|
96
|
+
reject(new GitError(
|
|
97
|
+
'Git authentication failed',
|
|
98
|
+
{
|
|
99
|
+
url,
|
|
100
|
+
error: errorMessage,
|
|
101
|
+
suggestion: 'Check repository URL and authentication credentials'
|
|
102
|
+
}
|
|
103
|
+
));
|
|
104
|
+
} else if (errorMessage.includes('Repository not found') ||
|
|
105
|
+
errorMessage.includes('not found')) {
|
|
106
|
+
reject(new GitError(
|
|
107
|
+
'Repository not found',
|
|
108
|
+
{
|
|
109
|
+
url,
|
|
110
|
+
error: errorMessage,
|
|
111
|
+
suggestion: 'Verify the repository URL is correct'
|
|
112
|
+
}
|
|
113
|
+
));
|
|
114
|
+
} else if (errorMessage.includes('Connection') ||
|
|
115
|
+
errorMessage.includes('network') ||
|
|
116
|
+
errorMessage.includes('timeout')) {
|
|
117
|
+
reject(new GitError(
|
|
118
|
+
'Network error during clone',
|
|
119
|
+
{
|
|
120
|
+
url,
|
|
121
|
+
error: errorMessage,
|
|
122
|
+
suggestion: 'Check your internet connection and try again'
|
|
123
|
+
}
|
|
124
|
+
));
|
|
125
|
+
} else {
|
|
126
|
+
reject(new GitError(
|
|
127
|
+
'Git clone failed',
|
|
128
|
+
{
|
|
129
|
+
url,
|
|
130
|
+
targetPath,
|
|
131
|
+
error: errorMessage
|
|
132
|
+
}
|
|
133
|
+
));
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
resolve();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Checks if a directory is a Git repository
|
|
144
|
+
*
|
|
145
|
+
* @param {string} repoPath - Path to check
|
|
146
|
+
* @returns {Promise<boolean>}
|
|
147
|
+
*/
|
|
148
|
+
async isGitRepository(repoPath) {
|
|
149
|
+
const gitDir = path.join(repoPath, '.git');
|
|
150
|
+
return await fs.pathExists(gitDir);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Gets the remote URL of a Git repository
|
|
155
|
+
*
|
|
156
|
+
* @param {string} repoPath - Repository path
|
|
157
|
+
* @returns {Promise<string>} Remote URL
|
|
158
|
+
*/
|
|
159
|
+
async getRemoteUrl(repoPath) {
|
|
160
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
161
|
+
throw new GitError(
|
|
162
|
+
'Not a Git repository',
|
|
163
|
+
{ repoPath }
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const url = execSync('git remote get-url origin', {
|
|
169
|
+
cwd: repoPath,
|
|
170
|
+
encoding: 'utf8'
|
|
171
|
+
}).trim();
|
|
172
|
+
|
|
173
|
+
return url;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
throw new GitError(
|
|
176
|
+
'Failed to get remote URL',
|
|
177
|
+
{
|
|
178
|
+
repoPath,
|
|
179
|
+
error: error.message
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Gets the current commit hash
|
|
187
|
+
*
|
|
188
|
+
* @param {string} repoPath - Repository path
|
|
189
|
+
* @returns {Promise<string>} Commit hash
|
|
190
|
+
*/
|
|
191
|
+
async getCurrentCommit(repoPath) {
|
|
192
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
193
|
+
throw new GitError(
|
|
194
|
+
'Not a Git repository',
|
|
195
|
+
{ repoPath }
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const hash = execSync('git rev-parse HEAD', {
|
|
201
|
+
cwd: repoPath,
|
|
202
|
+
encoding: 'utf8'
|
|
203
|
+
}).trim();
|
|
204
|
+
|
|
205
|
+
return hash;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
throw new GitError(
|
|
208
|
+
'Failed to get current commit',
|
|
209
|
+
{
|
|
210
|
+
repoPath,
|
|
211
|
+
error: error.message
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Pulls latest changes from remote
|
|
219
|
+
*
|
|
220
|
+
* @param {string} repoPath - Repository path
|
|
221
|
+
* @returns {Promise<void>}
|
|
222
|
+
*/
|
|
223
|
+
async pullUpdates(repoPath) {
|
|
224
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
225
|
+
throw new GitError(
|
|
226
|
+
'Not a Git repository',
|
|
227
|
+
{ repoPath }
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return new Promise((resolve, reject) => {
|
|
232
|
+
exec('git pull', { cwd: repoPath }, (error, stdout, stderr) => {
|
|
233
|
+
if (error) {
|
|
234
|
+
const errorMessage = stderr || error.message;
|
|
235
|
+
|
|
236
|
+
if (errorMessage.includes('conflict') || errorMessage.includes('CONFLICT')) {
|
|
237
|
+
reject(new GitError(
|
|
238
|
+
'Merge conflict during pull',
|
|
239
|
+
{
|
|
240
|
+
repoPath,
|
|
241
|
+
error: errorMessage,
|
|
242
|
+
suggestion: 'Resolve conflicts manually or clear cache and re-download'
|
|
243
|
+
}
|
|
244
|
+
));
|
|
245
|
+
} else if (errorMessage.includes('Authentication') ||
|
|
246
|
+
errorMessage.includes('Permission denied')) {
|
|
247
|
+
reject(new GitError(
|
|
248
|
+
'Authentication failed during pull',
|
|
249
|
+
{
|
|
250
|
+
repoPath,
|
|
251
|
+
error: errorMessage,
|
|
252
|
+
suggestion: 'Check repository access permissions'
|
|
253
|
+
}
|
|
254
|
+
));
|
|
255
|
+
} else {
|
|
256
|
+
reject(new GitError(
|
|
257
|
+
'Git pull failed',
|
|
258
|
+
{
|
|
259
|
+
repoPath,
|
|
260
|
+
error: errorMessage
|
|
261
|
+
}
|
|
262
|
+
));
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
resolve();
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Checks out a specific version (tag or commit)
|
|
273
|
+
*
|
|
274
|
+
* @param {string} repoPath - Repository path
|
|
275
|
+
* @param {string} version - Tag name or commit hash
|
|
276
|
+
* @returns {Promise<void>}
|
|
277
|
+
*/
|
|
278
|
+
async checkoutVersion(repoPath, version) {
|
|
279
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
280
|
+
throw new GitError(
|
|
281
|
+
'Not a Git repository',
|
|
282
|
+
{ repoPath }
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return new Promise((resolve, reject) => {
|
|
287
|
+
exec(`git checkout ${version}`, { cwd: repoPath }, (error, stdout, stderr) => {
|
|
288
|
+
if (error) {
|
|
289
|
+
const errorMessage = stderr || error.message;
|
|
290
|
+
|
|
291
|
+
if (errorMessage.includes('did not match') ||
|
|
292
|
+
errorMessage.includes('pathspec')) {
|
|
293
|
+
reject(new GitError(
|
|
294
|
+
'Version not found',
|
|
295
|
+
{
|
|
296
|
+
repoPath,
|
|
297
|
+
version,
|
|
298
|
+
error: errorMessage,
|
|
299
|
+
suggestion: 'Check that the tag or commit exists'
|
|
300
|
+
}
|
|
301
|
+
));
|
|
302
|
+
} else {
|
|
303
|
+
reject(new GitError(
|
|
304
|
+
'Git checkout failed',
|
|
305
|
+
{
|
|
306
|
+
repoPath,
|
|
307
|
+
version,
|
|
308
|
+
error: errorMessage
|
|
309
|
+
}
|
|
310
|
+
));
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
resolve();
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Gets list of available tags
|
|
321
|
+
*
|
|
322
|
+
* @param {string} repoPath - Repository path
|
|
323
|
+
* @returns {Promise<string[]>} Array of tag names
|
|
324
|
+
*/
|
|
325
|
+
async getTags(repoPath) {
|
|
326
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
327
|
+
throw new GitError(
|
|
328
|
+
'Not a Git repository',
|
|
329
|
+
{ repoPath }
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
const output = execSync('git tag', {
|
|
335
|
+
cwd: repoPath,
|
|
336
|
+
encoding: 'utf8'
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const tags = output.trim().split('\n').filter(tag => tag.length > 0);
|
|
340
|
+
return tags;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
throw new GitError(
|
|
343
|
+
'Failed to get tags',
|
|
344
|
+
{
|
|
345
|
+
repoPath,
|
|
346
|
+
error: error.message
|
|
347
|
+
}
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Gets the current branch name
|
|
354
|
+
*
|
|
355
|
+
* @param {string} repoPath - Repository path
|
|
356
|
+
* @returns {Promise<string>} Branch name
|
|
357
|
+
*/
|
|
358
|
+
async getCurrentBranch(repoPath) {
|
|
359
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
360
|
+
throw new GitError(
|
|
361
|
+
'Not a Git repository',
|
|
362
|
+
{ repoPath }
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
368
|
+
cwd: repoPath,
|
|
369
|
+
encoding: 'utf8'
|
|
370
|
+
}).trim();
|
|
371
|
+
|
|
372
|
+
return branch;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
throw new GitError(
|
|
375
|
+
'Failed to get current branch',
|
|
376
|
+
{
|
|
377
|
+
repoPath,
|
|
378
|
+
error: error.message
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Validates repository structure
|
|
386
|
+
*
|
|
387
|
+
* @param {string} repoPath - Repository path
|
|
388
|
+
* @returns {Promise<Object>} Validation result
|
|
389
|
+
*/
|
|
390
|
+
async validateRepository(repoPath) {
|
|
391
|
+
const result = {
|
|
392
|
+
valid: true,
|
|
393
|
+
errors: [],
|
|
394
|
+
warnings: []
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
// Check if it's a Git repository
|
|
398
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
399
|
+
result.valid = false;
|
|
400
|
+
result.errors.push('Not a Git repository');
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Check if template-registry.json exists
|
|
405
|
+
const registryPath = path.join(repoPath, 'template-registry.json');
|
|
406
|
+
if (!await fs.pathExists(registryPath)) {
|
|
407
|
+
result.valid = false;
|
|
408
|
+
result.errors.push('Missing template-registry.json');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Check if README.md exists
|
|
412
|
+
const readmePath = path.join(repoPath, 'README.md');
|
|
413
|
+
if (!await fs.pathExists(readmePath)) {
|
|
414
|
+
result.warnings.push('Missing README.md');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Check if CONTRIBUTING.md exists
|
|
418
|
+
const contributingPath = path.join(repoPath, 'CONTRIBUTING.md');
|
|
419
|
+
if (!await fs.pathExists(contributingPath)) {
|
|
420
|
+
result.warnings.push('Missing CONTRIBUTING.md');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Gets repository version information
|
|
428
|
+
*
|
|
429
|
+
* @param {string} repoPath - Repository path
|
|
430
|
+
* @returns {Promise<Object>} Version info
|
|
431
|
+
*/
|
|
432
|
+
async getRepoVersion(repoPath) {
|
|
433
|
+
if (!await this.isGitRepository(repoPath)) {
|
|
434
|
+
throw new GitError(
|
|
435
|
+
'Not a Git repository',
|
|
436
|
+
{ repoPath }
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const commit = await this.getCurrentCommit(repoPath);
|
|
441
|
+
const branch = await this.getCurrentBranch(repoPath);
|
|
442
|
+
const tags = await this.getTags(repoPath);
|
|
443
|
+
|
|
444
|
+
// Find if current commit has a tag
|
|
445
|
+
let currentTag = null;
|
|
446
|
+
for (const tag of tags) {
|
|
447
|
+
try {
|
|
448
|
+
const tagCommit = execSync(`git rev-list -n 1 ${tag}`, {
|
|
449
|
+
cwd: repoPath,
|
|
450
|
+
encoding: 'utf8'
|
|
451
|
+
}).trim();
|
|
452
|
+
|
|
453
|
+
if (tagCommit === commit) {
|
|
454
|
+
currentTag = tag;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
// Ignore errors for individual tags
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
commit,
|
|
464
|
+
branch,
|
|
465
|
+
tag: currentTag,
|
|
466
|
+
allTags: tags
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
module.exports = GitHandler;
|