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,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostic Engine
|
|
3
|
+
*
|
|
4
|
+
* Scans and analyzes project documentation structure
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const FileScanner = require('./file-scanner');
|
|
9
|
+
const ConfigManager = require('./config-manager');
|
|
10
|
+
|
|
11
|
+
class DiagnosticEngine {
|
|
12
|
+
constructor(projectPath, config) {
|
|
13
|
+
this.projectPath = projectPath;
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.scanner = new FileScanner(projectPath);
|
|
16
|
+
this.violations = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Run full diagnostic scan
|
|
21
|
+
*
|
|
22
|
+
* @returns {Promise<DiagnosticReport>}
|
|
23
|
+
*/
|
|
24
|
+
async scan() {
|
|
25
|
+
this.violations = []; // Reset violations
|
|
26
|
+
|
|
27
|
+
await this.scanRootDirectory();
|
|
28
|
+
await this.scanSpecDirectories();
|
|
29
|
+
|
|
30
|
+
return this.generateReport();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Scan root directory for violations
|
|
35
|
+
*
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
38
|
+
async scanRootDirectory() {
|
|
39
|
+
const mdFiles = await this.scanner.findMarkdownFiles(this.projectPath);
|
|
40
|
+
const allowedFiles = this.config.rootAllowedFiles || [];
|
|
41
|
+
|
|
42
|
+
for (const filePath of mdFiles) {
|
|
43
|
+
const basename = path.basename(filePath);
|
|
44
|
+
|
|
45
|
+
if (!allowedFiles.includes(basename)) {
|
|
46
|
+
// Check if it's a temporary document
|
|
47
|
+
const isTemporary = this.scanner.matchesPattern(filePath, this.config.temporaryPatterns || []);
|
|
48
|
+
|
|
49
|
+
this.violations.push({
|
|
50
|
+
type: 'root_violation',
|
|
51
|
+
path: filePath,
|
|
52
|
+
description: `Unexpected markdown file in root directory: ${basename}`,
|
|
53
|
+
severity: isTemporary ? 'warning' : 'error',
|
|
54
|
+
recommendation: isTemporary
|
|
55
|
+
? `Delete temporary file: ${basename}`
|
|
56
|
+
: `Move ${basename} to appropriate location or delete if temporary`
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Scan all Spec directories
|
|
64
|
+
*
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
*/
|
|
67
|
+
async scanSpecDirectories() {
|
|
68
|
+
const specDirs = await this.scanner.findSpecDirectories();
|
|
69
|
+
|
|
70
|
+
for (const specDir of specDirs) {
|
|
71
|
+
await this.scanSpecDirectory(specDir);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Scan a single Spec directory
|
|
77
|
+
*
|
|
78
|
+
* @param {string} specPath - Path to Spec directory
|
|
79
|
+
* @returns {Promise<void>}
|
|
80
|
+
*/
|
|
81
|
+
async scanSpecDirectory(specPath) {
|
|
82
|
+
const specName = path.basename(specPath);
|
|
83
|
+
const requiredFiles = ['requirements.md', 'design.md', 'tasks.md'];
|
|
84
|
+
|
|
85
|
+
// Check for missing required files
|
|
86
|
+
for (const requiredFile of requiredFiles) {
|
|
87
|
+
const filePath = path.join(specPath, requiredFile);
|
|
88
|
+
const exists = await this.scanner.exists(filePath);
|
|
89
|
+
|
|
90
|
+
if (!exists) {
|
|
91
|
+
this.violations.push({
|
|
92
|
+
type: 'missing_required_file',
|
|
93
|
+
path: filePath,
|
|
94
|
+
description: `Missing required file in Spec ${specName}: ${requiredFile}`,
|
|
95
|
+
severity: 'error',
|
|
96
|
+
recommendation: `Create ${requiredFile} in ${specName}`
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check for temporary documents in Spec directory
|
|
102
|
+
const mdFiles = await this.scanner.findMarkdownFiles(specPath);
|
|
103
|
+
const temporaryFiles = this.scanner.matchPatterns(mdFiles, this.config.temporaryPatterns || []);
|
|
104
|
+
|
|
105
|
+
for (const tempFile of temporaryFiles) {
|
|
106
|
+
const basename = path.basename(tempFile);
|
|
107
|
+
|
|
108
|
+
// Don't flag required files as temporary even if they match patterns
|
|
109
|
+
if (!requiredFiles.includes(basename)) {
|
|
110
|
+
this.violations.push({
|
|
111
|
+
type: 'temporary_document',
|
|
112
|
+
path: tempFile,
|
|
113
|
+
description: `Temporary document should be deleted: ${basename}`,
|
|
114
|
+
severity: 'warning',
|
|
115
|
+
recommendation: `Delete temporary file: ${basename} from ${specName}`
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check for misplaced artifacts (files not in subdirectories)
|
|
121
|
+
const allFiles = await this.scanner.getFiles(specPath);
|
|
122
|
+
|
|
123
|
+
for (const filePath of allFiles) {
|
|
124
|
+
const basename = path.basename(filePath);
|
|
125
|
+
|
|
126
|
+
// Skip required files
|
|
127
|
+
if (requiredFiles.includes(basename)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Skip temporary files (already flagged as temporary_document)
|
|
132
|
+
if (this.scanner.matchesPattern(filePath, this.config.temporaryPatterns || [])) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// This is a misplaced artifact
|
|
137
|
+
this.violations.push({
|
|
138
|
+
type: 'misplaced_artifact',
|
|
139
|
+
path: filePath,
|
|
140
|
+
description: `Artifact not in subdirectory: ${basename}`,
|
|
141
|
+
severity: 'warning',
|
|
142
|
+
recommendation: `Move ${basename} to appropriate subdirectory (${this.config.specSubdirs.join(', ')})`
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check subdirectory naming
|
|
147
|
+
const subdirs = await this.scanner.getSubdirectories(specPath);
|
|
148
|
+
const allowedSubdirs = this.config.specSubdirs || [];
|
|
149
|
+
|
|
150
|
+
for (const subdirPath of subdirs) {
|
|
151
|
+
const subdirName = path.basename(subdirPath);
|
|
152
|
+
|
|
153
|
+
// Skip hidden directories
|
|
154
|
+
if (subdirName.startsWith('.')) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!allowedSubdirs.includes(subdirName)) {
|
|
159
|
+
this.violations.push({
|
|
160
|
+
type: 'invalid_subdirectory',
|
|
161
|
+
path: subdirPath,
|
|
162
|
+
description: `Non-standard subdirectory in Spec ${specName}: ${subdirName}`,
|
|
163
|
+
severity: 'info',
|
|
164
|
+
recommendation: `Rename to one of: ${allowedSubdirs.join(', ')}, or remove if not needed`
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Generate diagnostic report
|
|
172
|
+
*
|
|
173
|
+
* @returns {DiagnosticReport}
|
|
174
|
+
*/
|
|
175
|
+
generateReport() {
|
|
176
|
+
const compliant = this.violations.length === 0;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
compliant,
|
|
180
|
+
violations: this.violations,
|
|
181
|
+
summary: this.generateSummary(),
|
|
182
|
+
recommendations: this.generateRecommendations()
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Generate summary statistics
|
|
188
|
+
*
|
|
189
|
+
* @returns {Object}
|
|
190
|
+
*/
|
|
191
|
+
generateSummary() {
|
|
192
|
+
const summary = {
|
|
193
|
+
totalViolations: this.violations.length,
|
|
194
|
+
byType: {},
|
|
195
|
+
bySeverity: {
|
|
196
|
+
error: 0,
|
|
197
|
+
warning: 0,
|
|
198
|
+
info: 0
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Count by type
|
|
203
|
+
for (const violation of this.violations) {
|
|
204
|
+
summary.byType[violation.type] = (summary.byType[violation.type] || 0) + 1;
|
|
205
|
+
summary.bySeverity[violation.severity] = (summary.bySeverity[violation.severity] || 0) + 1;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return summary;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Generate actionable recommendations
|
|
213
|
+
*
|
|
214
|
+
* @returns {string[]}
|
|
215
|
+
*/
|
|
216
|
+
generateRecommendations() {
|
|
217
|
+
const recommendations = [];
|
|
218
|
+
const summary = this.generateSummary();
|
|
219
|
+
|
|
220
|
+
// Root violations
|
|
221
|
+
if (summary.byType.root_violation > 0) {
|
|
222
|
+
recommendations.push('Run `kse cleanup` to remove temporary files from root directory');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Temporary documents
|
|
226
|
+
if (summary.byType.temporary_document > 0) {
|
|
227
|
+
recommendations.push('Run `kse cleanup` to remove temporary documents from Spec directories');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Misplaced artifacts
|
|
231
|
+
if (summary.byType.misplaced_artifact > 0) {
|
|
232
|
+
recommendations.push('Run `kse docs archive --spec <spec-name>` to organize artifacts into subdirectories');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Missing required files
|
|
236
|
+
if (summary.byType.missing_required_file > 0) {
|
|
237
|
+
recommendations.push('Create missing required files (requirements.md, design.md, tasks.md) in affected Specs');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Invalid subdirectories
|
|
241
|
+
if (summary.byType.invalid_subdirectory > 0) {
|
|
242
|
+
recommendations.push('Rename non-standard subdirectories to match allowed names');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// General recommendation
|
|
246
|
+
if (recommendations.length > 0) {
|
|
247
|
+
recommendations.push('Run `kse validate --all` after fixes to confirm compliance');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return recommendations;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @typedef {Object} DiagnosticReport
|
|
256
|
+
* @property {boolean} compliant - Whether project is compliant
|
|
257
|
+
* @property {Violation[]} violations - List of violations found
|
|
258
|
+
* @property {Object} summary - Summary statistics
|
|
259
|
+
* @property {string[]} recommendations - Actionable recommendations
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* @typedef {Object} Violation
|
|
264
|
+
* @property {string} type - Violation type (root_violation, spec_violation, etc.)
|
|
265
|
+
* @property {string} path - File or directory path
|
|
266
|
+
* @property {string} description - Human-readable description
|
|
267
|
+
* @property {string} severity - Severity level (error, warning, info)
|
|
268
|
+
* @property {string} recommendation - How to fix
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
module.exports = DiagnosticEngine;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Reference Checker
|
|
3
|
+
*
|
|
4
|
+
* Checks for incorrect project references and unresolved placeholders in documentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
class DocReferenceChecker {
|
|
11
|
+
constructor(projectRoot = process.cwd()) {
|
|
12
|
+
this.projectRoot = projectRoot;
|
|
13
|
+
|
|
14
|
+
// Common incorrect references to check
|
|
15
|
+
this.incorrectReferences = [
|
|
16
|
+
'上海图书馆',
|
|
17
|
+
'MinIO',
|
|
18
|
+
'测试项目',
|
|
19
|
+
'简化测试项目',
|
|
20
|
+
'Kiro AI-OS'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// Placeholder patterns to check
|
|
24
|
+
this.placeholderPatterns = [
|
|
25
|
+
/\[TODO:.*?\]/g,
|
|
26
|
+
/\[项目名称.*?\]/g,
|
|
27
|
+
/\[请修改.*?\]/g,
|
|
28
|
+
/\[根据项目.*?\]/g
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// Files to check
|
|
32
|
+
this.filesToCheck = [
|
|
33
|
+
'.kiro/specs/SPEC_WORKFLOW_GUIDE.md',
|
|
34
|
+
'.kiro/steering/ENVIRONMENT.md',
|
|
35
|
+
'.kiro/steering/CURRENT_CONTEXT.md',
|
|
36
|
+
'.kiro/README.md',
|
|
37
|
+
'README.md',
|
|
38
|
+
'package.json'
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check all documentation files
|
|
44
|
+
*
|
|
45
|
+
* @returns {Promise<Object>} Check results
|
|
46
|
+
*/
|
|
47
|
+
async checkAll() {
|
|
48
|
+
const results = {
|
|
49
|
+
incorrectReferences: [],
|
|
50
|
+
unresolvedPlaceholders: [],
|
|
51
|
+
filesChecked: 0,
|
|
52
|
+
issuesFound: 0
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
for (const file of this.filesToCheck) {
|
|
56
|
+
const filePath = path.join(this.projectRoot, file);
|
|
57
|
+
|
|
58
|
+
if (await fs.pathExists(filePath)) {
|
|
59
|
+
results.filesChecked++;
|
|
60
|
+
const fileResults = await this.checkFile(filePath);
|
|
61
|
+
|
|
62
|
+
if (fileResults.incorrectReferences.length > 0) {
|
|
63
|
+
results.incorrectReferences.push({
|
|
64
|
+
file,
|
|
65
|
+
references: fileResults.incorrectReferences
|
|
66
|
+
});
|
|
67
|
+
results.issuesFound += fileResults.incorrectReferences.length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (fileResults.unresolvedPlaceholders.length > 0) {
|
|
71
|
+
results.unresolvedPlaceholders.push({
|
|
72
|
+
file,
|
|
73
|
+
placeholders: fileResults.unresolvedPlaceholders
|
|
74
|
+
});
|
|
75
|
+
results.issuesFound += fileResults.unresolvedPlaceholders.length;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check a single file
|
|
85
|
+
*
|
|
86
|
+
* @param {string} filePath - Path to file
|
|
87
|
+
* @returns {Promise<Object>} File check results
|
|
88
|
+
*/
|
|
89
|
+
async checkFile(filePath) {
|
|
90
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
91
|
+
const lines = content.split('\n');
|
|
92
|
+
|
|
93
|
+
const results = {
|
|
94
|
+
incorrectReferences: [],
|
|
95
|
+
unresolvedPlaceholders: []
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Check for incorrect references
|
|
99
|
+
lines.forEach((line, index) => {
|
|
100
|
+
this.incorrectReferences.forEach(ref => {
|
|
101
|
+
if (line.includes(ref)) {
|
|
102
|
+
results.incorrectReferences.push({
|
|
103
|
+
line: index + 1,
|
|
104
|
+
content: line.trim(),
|
|
105
|
+
reference: ref
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Check for unresolved placeholders (only in non-template files)
|
|
112
|
+
if (!filePath.includes('template/')) {
|
|
113
|
+
lines.forEach((line, index) => {
|
|
114
|
+
this.placeholderPatterns.forEach(pattern => {
|
|
115
|
+
const matches = line.match(pattern);
|
|
116
|
+
if (matches) {
|
|
117
|
+
matches.forEach(match => {
|
|
118
|
+
results.unresolvedPlaceholders.push({
|
|
119
|
+
line: index + 1,
|
|
120
|
+
content: line.trim(),
|
|
121
|
+
placeholder: match
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Generate report
|
|
134
|
+
*
|
|
135
|
+
* @param {Object} results - Check results
|
|
136
|
+
* @returns {string} Formatted report
|
|
137
|
+
*/
|
|
138
|
+
generateReport(results) {
|
|
139
|
+
let report = '# Document Reference Check Report\n\n';
|
|
140
|
+
report += `**Date**: ${new Date().toISOString().split('T')[0]}\n`;
|
|
141
|
+
report += `**Files Checked**: ${results.filesChecked}\n`;
|
|
142
|
+
report += `**Issues Found**: ${results.issuesFound}\n\n`;
|
|
143
|
+
|
|
144
|
+
if (results.issuesFound === 0) {
|
|
145
|
+
report += '✅ **No issues found!** All documentation is clean.\n';
|
|
146
|
+
return report;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Incorrect references
|
|
150
|
+
if (results.incorrectReferences.length > 0) {
|
|
151
|
+
report += '## 🔴 Incorrect Project References\n\n';
|
|
152
|
+
results.incorrectReferences.forEach(item => {
|
|
153
|
+
report += `### ${item.file}\n\n`;
|
|
154
|
+
item.references.forEach(ref => {
|
|
155
|
+
report += `- **Line ${ref.line}**: Found "${ref.reference}"\n`;
|
|
156
|
+
report += ` \`\`\`\n ${ref.content}\n \`\`\`\n\n`;
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Unresolved placeholders
|
|
162
|
+
if (results.unresolvedPlaceholders.length > 0) {
|
|
163
|
+
report += '## 🟡 Unresolved Placeholders\n\n';
|
|
164
|
+
results.unresolvedPlaceholders.forEach(item => {
|
|
165
|
+
report += `### ${item.file}\n\n`;
|
|
166
|
+
item.placeholders.forEach(ph => {
|
|
167
|
+
report += `- **Line ${ph.line}**: ${ph.placeholder}\n`;
|
|
168
|
+
report += ` \`\`\`\n ${ph.content}\n \`\`\`\n\n`;
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Recommendations
|
|
174
|
+
report += '## 💡 Recommendations\n\n';
|
|
175
|
+
if (results.incorrectReferences.length > 0) {
|
|
176
|
+
report += '1. Remove or replace incorrect project references\n';
|
|
177
|
+
report += '2. Ensure all documentation reflects the correct project identity\n';
|
|
178
|
+
}
|
|
179
|
+
if (results.unresolvedPlaceholders.length > 0) {
|
|
180
|
+
report += '3. Replace all [TODO: ...] placeholders with actual project information\n';
|
|
181
|
+
report += '4. Update ENVIRONMENT.md with correct project details\n';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return report;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Save report to file
|
|
189
|
+
*
|
|
190
|
+
* @param {string} report - Report content
|
|
191
|
+
* @param {string} outputPath - Output file path
|
|
192
|
+
* @returns {Promise<void>}
|
|
193
|
+
*/
|
|
194
|
+
async saveReport(report, outputPath) {
|
|
195
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
196
|
+
await fs.writeFile(outputPath, report, 'utf-8');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = DocReferenceChecker;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution Logger
|
|
3
|
+
*
|
|
4
|
+
* Tracks governance tool executions for metrics and reporting
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
class ExecutionLogger {
|
|
11
|
+
constructor(projectPath) {
|
|
12
|
+
this.projectPath = projectPath;
|
|
13
|
+
this.logDir = path.join(projectPath, '.kiro', 'logs');
|
|
14
|
+
this.logFile = path.join(this.logDir, 'governance-history.json');
|
|
15
|
+
this.maxLogSize = 10 * 1024 * 1024; // 10MB
|
|
16
|
+
this.maxRotatedLogs = 5;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Log a governance tool execution
|
|
21
|
+
*
|
|
22
|
+
* @param {string} tool - Tool name (diagnostic, cleanup, validation, archive)
|
|
23
|
+
* @param {string} operation - Operation performed
|
|
24
|
+
* @param {Object} results - Operation results
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
async logExecution(tool, operation, results) {
|
|
28
|
+
try {
|
|
29
|
+
// Ensure log directory exists
|
|
30
|
+
await fs.ensureDir(this.logDir);
|
|
31
|
+
|
|
32
|
+
// Check if log rotation is needed
|
|
33
|
+
await this.rotateLogIfNeeded();
|
|
34
|
+
|
|
35
|
+
// Create log entry
|
|
36
|
+
const entry = {
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
tool,
|
|
39
|
+
operation,
|
|
40
|
+
results: this.sanitizeResults(results)
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Read existing log or create new array
|
|
44
|
+
let logEntries = [];
|
|
45
|
+
if (await fs.pathExists(this.logFile)) {
|
|
46
|
+
try {
|
|
47
|
+
const content = await fs.readFile(this.logFile, 'utf8');
|
|
48
|
+
logEntries = JSON.parse(content);
|
|
49
|
+
|
|
50
|
+
// Ensure it's an array
|
|
51
|
+
if (!Array.isArray(logEntries)) {
|
|
52
|
+
logEntries = [];
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// If log file is corrupted, start fresh
|
|
56
|
+
console.warn('Log file corrupted, starting fresh');
|
|
57
|
+
logEntries = [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Append new entry
|
|
62
|
+
logEntries.push(entry);
|
|
63
|
+
|
|
64
|
+
// Write back to file
|
|
65
|
+
await fs.writeFile(this.logFile, JSON.stringify(logEntries, null, 2), 'utf8');
|
|
66
|
+
} catch (error) {
|
|
67
|
+
// Log errors should not break the main operation
|
|
68
|
+
console.error('Failed to log execution:', error.message);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get execution history
|
|
74
|
+
*
|
|
75
|
+
* @param {Object} options - Filter options
|
|
76
|
+
* @param {string} options.tool - Filter by tool name
|
|
77
|
+
* @param {Date} options.since - Filter by date
|
|
78
|
+
* @param {number} options.limit - Limit number of entries
|
|
79
|
+
* @returns {Promise<Array>}
|
|
80
|
+
*/
|
|
81
|
+
async getHistory(options = {}) {
|
|
82
|
+
try {
|
|
83
|
+
// Check if log file exists
|
|
84
|
+
if (!await fs.pathExists(this.logFile)) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Read log file
|
|
89
|
+
const content = await fs.readFile(this.logFile, 'utf8');
|
|
90
|
+
let entries = JSON.parse(content);
|
|
91
|
+
|
|
92
|
+
// Ensure it's an array
|
|
93
|
+
if (!Array.isArray(entries)) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Apply filters
|
|
98
|
+
if (options.tool) {
|
|
99
|
+
entries = entries.filter(entry => entry.tool === options.tool);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (options.since) {
|
|
103
|
+
const sinceTime = options.since.getTime();
|
|
104
|
+
entries = entries.filter(entry => {
|
|
105
|
+
const entryTime = new Date(entry.timestamp).getTime();
|
|
106
|
+
return entryTime >= sinceTime;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Apply limit
|
|
111
|
+
if (options.limit && options.limit > 0) {
|
|
112
|
+
entries = entries.slice(-options.limit);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return entries;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('Failed to read execution history:', error.message);
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Rotate log file if it exceeds max size
|
|
124
|
+
*
|
|
125
|
+
* @returns {Promise<void>}
|
|
126
|
+
*/
|
|
127
|
+
async rotateLogIfNeeded() {
|
|
128
|
+
try {
|
|
129
|
+
// Check if log file exists
|
|
130
|
+
if (!await fs.pathExists(this.logFile)) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Check file size
|
|
135
|
+
const stats = await fs.stat(this.logFile);
|
|
136
|
+
|
|
137
|
+
if (stats.size < this.maxLogSize) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Rotate logs
|
|
142
|
+
await this.rotateLog();
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('Failed to check log size:', error.message);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Rotate log file
|
|
150
|
+
*
|
|
151
|
+
* @returns {Promise<void>}
|
|
152
|
+
*/
|
|
153
|
+
async rotateLog() {
|
|
154
|
+
try {
|
|
155
|
+
// Remove oldest rotated log if we have max number
|
|
156
|
+
const oldestLog = path.join(this.logDir, `governance-history.${this.maxRotatedLogs}.json`);
|
|
157
|
+
if (await fs.pathExists(oldestLog)) {
|
|
158
|
+
await fs.remove(oldestLog);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Shift existing rotated logs
|
|
162
|
+
for (let i = this.maxRotatedLogs - 1; i >= 1; i--) {
|
|
163
|
+
const currentLog = path.join(this.logDir, `governance-history.${i}.json`);
|
|
164
|
+
const nextLog = path.join(this.logDir, `governance-history.${i + 1}.json`);
|
|
165
|
+
|
|
166
|
+
if (await fs.pathExists(currentLog)) {
|
|
167
|
+
await fs.move(currentLog, nextLog, { overwrite: true });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Rotate current log to .1
|
|
172
|
+
const rotatedLog = path.join(this.logDir, 'governance-history.1.json');
|
|
173
|
+
await fs.move(this.logFile, rotatedLog, { overwrite: true });
|
|
174
|
+
|
|
175
|
+
// Create new empty log
|
|
176
|
+
await fs.writeFile(this.logFile, '[]', 'utf8');
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error('Failed to rotate log:', error.message);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Sanitize results for logging (remove sensitive data, limit size)
|
|
184
|
+
*
|
|
185
|
+
* @param {Object} results - Operation results
|
|
186
|
+
* @returns {Object}
|
|
187
|
+
*/
|
|
188
|
+
sanitizeResults(results) {
|
|
189
|
+
// Create a shallow copy
|
|
190
|
+
const sanitized = { ...results };
|
|
191
|
+
|
|
192
|
+
// Limit array sizes to prevent huge logs
|
|
193
|
+
const maxArraySize = 100;
|
|
194
|
+
|
|
195
|
+
if (Array.isArray(sanitized.violations) && sanitized.violations.length > maxArraySize) {
|
|
196
|
+
sanitized.violations = sanitized.violations.slice(0, maxArraySize);
|
|
197
|
+
sanitized.violationsTruncated = true;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (Array.isArray(sanitized.deletedFiles) && sanitized.deletedFiles.length > maxArraySize) {
|
|
201
|
+
sanitized.deletedFiles = sanitized.deletedFiles.slice(0, maxArraySize);
|
|
202
|
+
sanitized.deletedFilesTruncated = true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (Array.isArray(sanitized.movedFiles) && sanitized.movedFiles.length > maxArraySize) {
|
|
206
|
+
sanitized.movedFiles = sanitized.movedFiles.slice(0, maxArraySize);
|
|
207
|
+
sanitized.movedFilesTruncated = true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (Array.isArray(sanitized.errors) && sanitized.errors.length > maxArraySize) {
|
|
211
|
+
sanitized.errors = sanitized.errors.slice(0, maxArraySize);
|
|
212
|
+
sanitized.errorsTruncated = true;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return sanitized;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Clear all logs (for testing or reset)
|
|
220
|
+
*
|
|
221
|
+
* @returns {Promise<void>}
|
|
222
|
+
*/
|
|
223
|
+
async clearLogs() {
|
|
224
|
+
try {
|
|
225
|
+
// Remove main log file
|
|
226
|
+
if (await fs.pathExists(this.logFile)) {
|
|
227
|
+
await fs.remove(this.logFile);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Remove rotated logs
|
|
231
|
+
for (let i = 1; i <= this.maxRotatedLogs; i++) {
|
|
232
|
+
const rotatedLog = path.join(this.logDir, `governance-history.${i}.json`);
|
|
233
|
+
if (await fs.pathExists(rotatedLog)) {
|
|
234
|
+
await fs.remove(rotatedLog);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error('Failed to clear logs:', error.message);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
module.exports = ExecutionLogger;
|