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,502 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress Tracker
|
|
3
|
+
* Real-time monitoring and reporting of autonomous execution
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
class ProgressTracker {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.currentPhase = 'initialization';
|
|
12
|
+
this.overallProgress = 0;
|
|
13
|
+
this.phaseProgress = {
|
|
14
|
+
requirements: 0,
|
|
15
|
+
design: 0,
|
|
16
|
+
tasks: 0,
|
|
17
|
+
implementation: 0,
|
|
18
|
+
qa: 0
|
|
19
|
+
};
|
|
20
|
+
this.executionLog = [];
|
|
21
|
+
this.startTime = Date.now();
|
|
22
|
+
this.currentTask = null;
|
|
23
|
+
this.tasksCompleted = 0;
|
|
24
|
+
this.tasksTotal = 0;
|
|
25
|
+
this.errorsEncountered = 0;
|
|
26
|
+
this.errorsResolved = 0;
|
|
27
|
+
this.taskDurations = new Map(); // taskId -> duration
|
|
28
|
+
this.historicalDataPath = path.join(process.cwd(), '.kiro', 'auto', 'historical-data.json');
|
|
29
|
+
this.historicalData = {
|
|
30
|
+
taskDurations: {}, // taskType -> [durations]
|
|
31
|
+
phaseDurations: {}, // phase -> [durations]
|
|
32
|
+
errorRates: {} // taskType -> error count
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Load historical data
|
|
36
|
+
this.loadHistoricalData();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Update current phase
|
|
41
|
+
* @param {string} phase - Phase name
|
|
42
|
+
* @param {number} percentage - Progress percentage (0-100)
|
|
43
|
+
*/
|
|
44
|
+
async updateProgress(phase, percentage) {
|
|
45
|
+
this.currentPhase = phase;
|
|
46
|
+
this.phaseProgress[phase] = Math.min(100, Math.max(0, percentage));
|
|
47
|
+
|
|
48
|
+
// Calculate overall progress (weighted average)
|
|
49
|
+
const weights = {
|
|
50
|
+
requirements: 0.15,
|
|
51
|
+
design: 0.15,
|
|
52
|
+
tasks: 0.10,
|
|
53
|
+
implementation: 0.50,
|
|
54
|
+
qa: 0.10
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
this.overallProgress = Object.keys(weights).reduce((sum, p) => {
|
|
58
|
+
return sum + (this.phaseProgress[p] * weights[p]);
|
|
59
|
+
}, 0);
|
|
60
|
+
|
|
61
|
+
await this.logAction('progress-update', {
|
|
62
|
+
phase,
|
|
63
|
+
percentage,
|
|
64
|
+
overallProgress: this.overallProgress
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Log an action
|
|
70
|
+
* @param {string} action - Action type
|
|
71
|
+
* @param {Object} details - Action details
|
|
72
|
+
*/
|
|
73
|
+
async logAction(action, details = {}) {
|
|
74
|
+
const entry = {
|
|
75
|
+
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
type: 'action',
|
|
78
|
+
phase: this.currentPhase,
|
|
79
|
+
task: this.currentTask,
|
|
80
|
+
data: {
|
|
81
|
+
message: action,
|
|
82
|
+
details,
|
|
83
|
+
duration: null
|
|
84
|
+
},
|
|
85
|
+
metadata: {
|
|
86
|
+
attemptNumber: 1,
|
|
87
|
+
success: true,
|
|
88
|
+
impact: 'low'
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
this.executionLog.push(entry);
|
|
93
|
+
return entry;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Log a decision
|
|
98
|
+
* @param {Object} decision - Decision details
|
|
99
|
+
*/
|
|
100
|
+
async logDecision(decision) {
|
|
101
|
+
const entry = {
|
|
102
|
+
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
103
|
+
timestamp: new Date().toISOString(),
|
|
104
|
+
type: 'decision',
|
|
105
|
+
phase: this.currentPhase,
|
|
106
|
+
task: this.currentTask,
|
|
107
|
+
data: {
|
|
108
|
+
message: decision.decision,
|
|
109
|
+
details: {
|
|
110
|
+
rationale: decision.rationale,
|
|
111
|
+
alternatives: decision.alternatives || [],
|
|
112
|
+
impact: decision.impact || 'medium'
|
|
113
|
+
},
|
|
114
|
+
duration: null
|
|
115
|
+
},
|
|
116
|
+
metadata: {
|
|
117
|
+
attemptNumber: 1,
|
|
118
|
+
success: true,
|
|
119
|
+
impact: decision.impact || 'medium'
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
this.executionLog.push(entry);
|
|
124
|
+
return entry;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Log an error and recovery attempt
|
|
129
|
+
* @param {Error} error - Error object
|
|
130
|
+
* @param {Object} recovery - Recovery details
|
|
131
|
+
*/
|
|
132
|
+
async logError(error, recovery = {}) {
|
|
133
|
+
this.errorsEncountered++;
|
|
134
|
+
|
|
135
|
+
if (recovery.success) {
|
|
136
|
+
this.errorsResolved++;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const entry = {
|
|
140
|
+
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
type: recovery.success ? 'recovery' : 'error',
|
|
143
|
+
phase: this.currentPhase,
|
|
144
|
+
task: this.currentTask,
|
|
145
|
+
data: {
|
|
146
|
+
message: error.message,
|
|
147
|
+
details: {
|
|
148
|
+
errorType: error.name,
|
|
149
|
+
stack: error.stack,
|
|
150
|
+
recovery: recovery
|
|
151
|
+
},
|
|
152
|
+
duration: recovery.duration || null
|
|
153
|
+
},
|
|
154
|
+
metadata: {
|
|
155
|
+
attemptNumber: recovery.attemptNumber || 1,
|
|
156
|
+
success: recovery.success || false,
|
|
157
|
+
impact: 'high'
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
this.executionLog.push(entry);
|
|
162
|
+
return entry;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Set current task
|
|
167
|
+
* @param {string} taskId - Task ID
|
|
168
|
+
*/
|
|
169
|
+
setCurrentTask(taskId) {
|
|
170
|
+
// Record start time for duration tracking
|
|
171
|
+
if (this.currentTask && this.taskDurations.has(this.currentTask)) {
|
|
172
|
+
const startTime = this.taskDurations.get(this.currentTask);
|
|
173
|
+
const duration = Date.now() - startTime;
|
|
174
|
+
|
|
175
|
+
// Extract task type (e.g., "2.1" -> "implementation")
|
|
176
|
+
const taskType = this.inferTaskType(this.currentTask);
|
|
177
|
+
|
|
178
|
+
// Record duration for estimation improvement
|
|
179
|
+
this.recordTaskDuration(taskType, duration);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
this.currentTask = taskId;
|
|
183
|
+
this.taskDurations.set(taskId, Date.now());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Infer task type from task ID
|
|
188
|
+
* @param {string} taskId - Task ID
|
|
189
|
+
* @returns {string} - Task type
|
|
190
|
+
*/
|
|
191
|
+
inferTaskType(taskId) {
|
|
192
|
+
// Simple heuristic: use first number as task type indicator
|
|
193
|
+
const match = taskId.match(/^(\d+)/);
|
|
194
|
+
if (!match) return 'unknown';
|
|
195
|
+
|
|
196
|
+
const taskNum = parseInt(match[1]);
|
|
197
|
+
|
|
198
|
+
// Map task numbers to types (based on common patterns)
|
|
199
|
+
if (taskNum <= 2) return 'setup';
|
|
200
|
+
if (taskNum <= 5) return 'core-implementation';
|
|
201
|
+
if (taskNum <= 8) return 'feature-implementation';
|
|
202
|
+
if (taskNum <= 12) return 'cli-implementation';
|
|
203
|
+
if (taskNum <= 15) return 'integration';
|
|
204
|
+
if (taskNum <= 17) return 'documentation';
|
|
205
|
+
|
|
206
|
+
return 'other';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Record task duration for learning
|
|
211
|
+
* @param {string} taskType - Task type
|
|
212
|
+
* @param {number} duration - Duration in milliseconds
|
|
213
|
+
*/
|
|
214
|
+
async recordTaskDuration(taskType, duration) {
|
|
215
|
+
if (!this.historicalData.taskDurations[taskType]) {
|
|
216
|
+
this.historicalData.taskDurations[taskType] = [];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.historicalData.taskDurations[taskType].push(duration);
|
|
220
|
+
|
|
221
|
+
// Keep only last 100 entries per type
|
|
222
|
+
if (this.historicalData.taskDurations[taskType].length > 100) {
|
|
223
|
+
this.historicalData.taskDurations[taskType].shift();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
await this.saveHistoricalData();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get estimated task duration based on historical data
|
|
231
|
+
* @param {string} taskType - Task type
|
|
232
|
+
* @returns {number} - Estimated duration in milliseconds
|
|
233
|
+
*/
|
|
234
|
+
getEstimatedTaskDuration(taskType) {
|
|
235
|
+
const durations = this.historicalData.taskDurations[taskType];
|
|
236
|
+
|
|
237
|
+
if (!durations || durations.length === 0) {
|
|
238
|
+
// Default estimates (in milliseconds)
|
|
239
|
+
const defaults = {
|
|
240
|
+
'setup': 60000, // 1 minute
|
|
241
|
+
'core-implementation': 300000, // 5 minutes
|
|
242
|
+
'feature-implementation': 600000, // 10 minutes
|
|
243
|
+
'cli-implementation': 180000, // 3 minutes
|
|
244
|
+
'integration': 240000, // 4 minutes
|
|
245
|
+
'documentation': 120000, // 2 minutes
|
|
246
|
+
'other': 300000 // 5 minutes
|
|
247
|
+
};
|
|
248
|
+
return defaults[taskType] || 300000;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Calculate weighted average (more weight to recent data)
|
|
252
|
+
const weights = durations.map((_, i) => i + 1);
|
|
253
|
+
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
|
|
254
|
+
|
|
255
|
+
const weightedSum = durations.reduce((sum, duration, i) => {
|
|
256
|
+
return sum + (duration * weights[i]);
|
|
257
|
+
}, 0);
|
|
258
|
+
|
|
259
|
+
return weightedSum / totalWeight;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Load historical data from disk
|
|
264
|
+
*/
|
|
265
|
+
async loadHistoricalData() {
|
|
266
|
+
try {
|
|
267
|
+
if (await fs.pathExists(this.historicalDataPath)) {
|
|
268
|
+
this.historicalData = await fs.readJson(this.historicalDataPath);
|
|
269
|
+
}
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.warn('Failed to load historical data:', error.message);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Save historical data to disk
|
|
277
|
+
*/
|
|
278
|
+
async saveHistoricalData() {
|
|
279
|
+
try {
|
|
280
|
+
await fs.ensureDir(path.dirname(this.historicalDataPath));
|
|
281
|
+
await fs.writeJson(this.historicalDataPath, this.historicalData, { spaces: 2 });
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.warn('Failed to save historical data:', error.message);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Update task counts
|
|
289
|
+
* @param {number} completed - Completed tasks
|
|
290
|
+
* @param {number} total - Total tasks
|
|
291
|
+
*/
|
|
292
|
+
updateTaskCounts(completed, total) {
|
|
293
|
+
this.tasksCompleted = completed;
|
|
294
|
+
this.tasksTotal = total;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get current status
|
|
299
|
+
* @returns {Object} - Current status
|
|
300
|
+
*/
|
|
301
|
+
getCurrentStatus() {
|
|
302
|
+
return {
|
|
303
|
+
phase: this.currentPhase,
|
|
304
|
+
overallProgress: Math.round(this.overallProgress),
|
|
305
|
+
currentTask: this.currentTask,
|
|
306
|
+
tasksCompleted: this.tasksCompleted,
|
|
307
|
+
tasksTotal: this.tasksTotal,
|
|
308
|
+
errorsEncountered: this.errorsEncountered,
|
|
309
|
+
errorsResolved: this.errorsResolved,
|
|
310
|
+
startedAt: new Date(this.startTime).toISOString(),
|
|
311
|
+
estimatedCompletion: this.getEstimatedCompletion(),
|
|
312
|
+
recentActions: this.getRecentActions(5)
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Get progress summary
|
|
318
|
+
* @returns {Object} - Progress summary
|
|
319
|
+
*/
|
|
320
|
+
getProgressSummary() {
|
|
321
|
+
const elapsed = Date.now() - this.startTime;
|
|
322
|
+
const elapsedMinutes = Math.floor(elapsed / 60000);
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
overallProgress: Math.round(this.overallProgress),
|
|
326
|
+
phaseProgress: this.phaseProgress,
|
|
327
|
+
currentPhase: this.currentPhase,
|
|
328
|
+
tasksCompleted: this.tasksCompleted,
|
|
329
|
+
tasksTotal: this.tasksTotal,
|
|
330
|
+
tasksRemaining: this.tasksTotal - this.tasksCompleted,
|
|
331
|
+
errorsEncountered: this.errorsEncountered,
|
|
332
|
+
errorsResolved: this.errorsResolved,
|
|
333
|
+
errorRecoveryRate: this.getErrorRecoveryRate(),
|
|
334
|
+
elapsedTime: `${elapsedMinutes} minutes`,
|
|
335
|
+
estimatedCompletion: this.getEstimatedCompletion()
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get detailed report
|
|
341
|
+
* @returns {Object} - Detailed report
|
|
342
|
+
*/
|
|
343
|
+
getDetailedReport() {
|
|
344
|
+
return {
|
|
345
|
+
summary: this.getProgressSummary(),
|
|
346
|
+
timeline: this.getExecutionTimeline(),
|
|
347
|
+
metrics: {
|
|
348
|
+
taskCompletionRate: this.getTaskCompletionRate(),
|
|
349
|
+
errorRecoveryRate: this.getErrorRecoveryRate(),
|
|
350
|
+
averageTaskDuration: this.getAverageTaskDuration()
|
|
351
|
+
},
|
|
352
|
+
log: this.executionLog
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get execution timeline
|
|
358
|
+
* @returns {Array} - Timeline entries
|
|
359
|
+
*/
|
|
360
|
+
getExecutionTimeline() {
|
|
361
|
+
return this.executionLog.map(entry => ({
|
|
362
|
+
timestamp: entry.timestamp,
|
|
363
|
+
type: entry.type,
|
|
364
|
+
phase: entry.phase,
|
|
365
|
+
message: entry.data.message,
|
|
366
|
+
success: entry.metadata.success
|
|
367
|
+
}));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get recent actions
|
|
372
|
+
* @param {number} count - Number of recent actions
|
|
373
|
+
* @returns {Array} - Recent actions
|
|
374
|
+
*/
|
|
375
|
+
getRecentActions(count = 10) {
|
|
376
|
+
return this.executionLog.slice(-count).map(entry => ({
|
|
377
|
+
timestamp: entry.timestamp,
|
|
378
|
+
type: entry.type,
|
|
379
|
+
message: entry.data.message,
|
|
380
|
+
success: entry.metadata.success
|
|
381
|
+
}));
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get task completion rate
|
|
386
|
+
* @returns {number} - Completion rate (0-1)
|
|
387
|
+
*/
|
|
388
|
+
getTaskCompletionRate() {
|
|
389
|
+
if (this.tasksTotal === 0) return 0;
|
|
390
|
+
return this.tasksCompleted / this.tasksTotal;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get error recovery rate
|
|
395
|
+
* @returns {number} - Recovery rate (0-1)
|
|
396
|
+
*/
|
|
397
|
+
getErrorRecoveryRate() {
|
|
398
|
+
if (this.errorsEncountered === 0) return 1;
|
|
399
|
+
return this.errorsResolved / this.errorsEncountered;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get average task duration
|
|
404
|
+
* @returns {number} - Average duration in milliseconds
|
|
405
|
+
*/
|
|
406
|
+
getAverageTaskDuration() {
|
|
407
|
+
const taskActions = this.executionLog.filter(e =>
|
|
408
|
+
e.type === 'action' && e.data.duration
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
if (taskActions.length === 0) return 0;
|
|
412
|
+
|
|
413
|
+
const totalDuration = taskActions.reduce((sum, e) => sum + e.data.duration, 0);
|
|
414
|
+
return totalDuration / taskActions.length;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Get estimated completion time
|
|
419
|
+
* @returns {string|null} - ISO timestamp or null
|
|
420
|
+
*/
|
|
421
|
+
getEstimatedCompletion() {
|
|
422
|
+
if (this.overallProgress === 0) return null;
|
|
423
|
+
|
|
424
|
+
// Use historical data for better estimation
|
|
425
|
+
const remainingTasks = this.tasksTotal - this.tasksCompleted;
|
|
426
|
+
|
|
427
|
+
if (remainingTasks > 0 && this.currentTask) {
|
|
428
|
+
const taskType = this.inferTaskType(this.currentTask);
|
|
429
|
+
const avgDuration = this.getEstimatedTaskDuration(taskType);
|
|
430
|
+
const estimatedRemaining = avgDuration * remainingTasks;
|
|
431
|
+
|
|
432
|
+
const completionTime = new Date(Date.now() + estimatedRemaining);
|
|
433
|
+
return completionTime.toISOString();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Fallback to simple calculation
|
|
437
|
+
const elapsed = Date.now() - this.startTime;
|
|
438
|
+
const estimatedTotal = (elapsed / this.overallProgress) * 100;
|
|
439
|
+
const remaining = estimatedTotal - elapsed;
|
|
440
|
+
|
|
441
|
+
const completionTime = new Date(Date.now() + remaining);
|
|
442
|
+
return completionTime.toISOString();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Export report to file
|
|
447
|
+
* @param {string} format - Format (json, markdown)
|
|
448
|
+
* @param {string} outputPath - Output file path
|
|
449
|
+
*/
|
|
450
|
+
async exportReport(format, outputPath) {
|
|
451
|
+
const fs = require('fs-extra');
|
|
452
|
+
const report = this.getDetailedReport();
|
|
453
|
+
|
|
454
|
+
if (format === 'json') {
|
|
455
|
+
await fs.writeJson(outputPath, report, { spaces: 2 });
|
|
456
|
+
} else if (format === 'markdown') {
|
|
457
|
+
const markdown = this.generateMarkdownReport(report);
|
|
458
|
+
await fs.writeFile(outputPath, markdown, 'utf-8');
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Generate markdown report
|
|
464
|
+
* @param {Object} report - Report data
|
|
465
|
+
* @returns {string} - Markdown content
|
|
466
|
+
*/
|
|
467
|
+
generateMarkdownReport(report) {
|
|
468
|
+
const { summary, timeline, metrics } = report;
|
|
469
|
+
|
|
470
|
+
let md = '# Autonomous Execution Report\n\n';
|
|
471
|
+
md += `**Generated**: ${new Date().toISOString()}\n\n`;
|
|
472
|
+
|
|
473
|
+
md += '## Summary\n\n';
|
|
474
|
+
md += `- **Overall Progress**: ${summary.overallProgress}%\n`;
|
|
475
|
+
md += `- **Current Phase**: ${summary.currentPhase}\n`;
|
|
476
|
+
md += `- **Tasks**: ${summary.tasksCompleted}/${summary.tasksTotal} completed\n`;
|
|
477
|
+
md += `- **Errors**: ${summary.errorsResolved}/${summary.errorsEncountered} resolved\n`;
|
|
478
|
+
md += `- **Elapsed Time**: ${summary.elapsedTime}\n`;
|
|
479
|
+
md += `- **Estimated Completion**: ${summary.estimatedCompletion || 'N/A'}\n\n`;
|
|
480
|
+
|
|
481
|
+
md += '## Phase Progress\n\n';
|
|
482
|
+
for (const [phase, progress] of Object.entries(summary.phaseProgress)) {
|
|
483
|
+
md += `- **${phase}**: ${progress}%\n`;
|
|
484
|
+
}
|
|
485
|
+
md += '\n';
|
|
486
|
+
|
|
487
|
+
md += '## Metrics\n\n';
|
|
488
|
+
md += `- **Task Completion Rate**: ${(metrics.taskCompletionRate * 100).toFixed(1)}%\n`;
|
|
489
|
+
md += `- **Error Recovery Rate**: ${(metrics.errorRecoveryRate * 100).toFixed(1)}%\n`;
|
|
490
|
+
md += `- **Average Task Duration**: ${(metrics.averageTaskDuration / 1000).toFixed(1)}s\n\n`;
|
|
491
|
+
|
|
492
|
+
md += '## Timeline\n\n';
|
|
493
|
+
for (const entry of timeline.slice(-20)) {
|
|
494
|
+
const icon = entry.success ? '✅' : '❌';
|
|
495
|
+
md += `- ${icon} **${entry.timestamp}** [${entry.type}] ${entry.message}\n`;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return md;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
module.exports = ProgressTracker;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safety Manager
|
|
3
|
+
* Enforces safety boundaries and validates operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class SafetyManager {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
this.config = config.safety || {};
|
|
9
|
+
this.auditLog = [];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if operation is allowed
|
|
14
|
+
* @param {string} operation - Operation type
|
|
15
|
+
* @param {Object} context - Operation context
|
|
16
|
+
* @returns {Object} - { allowed: boolean, reason: string }
|
|
17
|
+
*/
|
|
18
|
+
async checkOperation(operation, context = {}) {
|
|
19
|
+
// Check blocked operations
|
|
20
|
+
if (this.config.blockedOperations?.includes(operation)) {
|
|
21
|
+
return {
|
|
22
|
+
allowed: false,
|
|
23
|
+
reason: `Operation '${operation}' is blocked by configuration`
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check allowed operations (if whitelist exists)
|
|
28
|
+
if (this.config.allowedOperations?.length > 0) {
|
|
29
|
+
if (!this.config.allowedOperations.includes(operation)) {
|
|
30
|
+
return {
|
|
31
|
+
allowed: false,
|
|
32
|
+
reason: `Operation '${operation}' is not in allowed list`
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check specific safety rules
|
|
38
|
+
const checks = [
|
|
39
|
+
this.checkProductionAccess(operation, context),
|
|
40
|
+
this.checkWorkspaceBoundary(operation, context),
|
|
41
|
+
this.checkExternalAccess(operation, context),
|
|
42
|
+
this.checkDestructiveOperation(operation, context)
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
for (const check of checks) {
|
|
46
|
+
if (!check.allowed) {
|
|
47
|
+
return check;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { allowed: true, reason: 'Operation permitted' };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check production environment access
|
|
56
|
+
* @param {string} operation - Operation type
|
|
57
|
+
* @param {Object} context - Context
|
|
58
|
+
* @returns {Object} - Check result
|
|
59
|
+
*/
|
|
60
|
+
checkProductionAccess(operation, context) {
|
|
61
|
+
if (context.environment === 'production' || context.isProduction) {
|
|
62
|
+
if (this.config.requireProductionConfirmation !== false) {
|
|
63
|
+
return {
|
|
64
|
+
allowed: false,
|
|
65
|
+
reason: 'Production environment access requires user confirmation',
|
|
66
|
+
requiresConfirmation: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { allowed: true };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Check workspace boundary
|
|
75
|
+
* @param {string} operation - Operation type
|
|
76
|
+
* @param {Object} context - Context
|
|
77
|
+
* @returns {Object} - Check result
|
|
78
|
+
*/
|
|
79
|
+
checkWorkspaceBoundary(operation, context) {
|
|
80
|
+
if (context.filePath) {
|
|
81
|
+
const path = require('path');
|
|
82
|
+
const workspace = process.cwd();
|
|
83
|
+
const absolutePath = path.resolve(context.filePath);
|
|
84
|
+
|
|
85
|
+
if (!absolutePath.startsWith(workspace)) {
|
|
86
|
+
return {
|
|
87
|
+
allowed: false,
|
|
88
|
+
reason: `File '${context.filePath}' is outside workspace boundary`,
|
|
89
|
+
requiresConfirmation: true
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { allowed: true };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Check external system access
|
|
98
|
+
* @param {string} operation - Operation type
|
|
99
|
+
* @param {Object} context - Context
|
|
100
|
+
* @returns {Object} - Check result
|
|
101
|
+
*/
|
|
102
|
+
checkExternalAccess(operation, context) {
|
|
103
|
+
const externalOps = ['api-call', 'network-request', 'external-service'];
|
|
104
|
+
|
|
105
|
+
if (externalOps.includes(operation)) {
|
|
106
|
+
if (this.config.requireExternalResourceConfirmation !== false) {
|
|
107
|
+
return {
|
|
108
|
+
allowed: false,
|
|
109
|
+
reason: 'External system access requires user confirmation',
|
|
110
|
+
requiresConfirmation: true
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { allowed: true };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check destructive operation
|
|
119
|
+
* @param {string} operation - Operation type
|
|
120
|
+
* @param {Object} context - Context
|
|
121
|
+
* @returns {Object} - Check result
|
|
122
|
+
*/
|
|
123
|
+
checkDestructiveOperation(operation, context) {
|
|
124
|
+
const destructiveOps = ['delete-file', 'drop-database', 'clear-data'];
|
|
125
|
+
|
|
126
|
+
if (destructiveOps.includes(operation)) {
|
|
127
|
+
if (this.config.requireDestructiveOperationConfirmation !== false) {
|
|
128
|
+
return {
|
|
129
|
+
allowed: false,
|
|
130
|
+
reason: 'Destructive operation requires user confirmation',
|
|
131
|
+
requiresConfirmation: true
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { allowed: true };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Request user confirmation
|
|
140
|
+
* @param {Object} check - Check result
|
|
141
|
+
* @returns {boolean} - User response
|
|
142
|
+
*/
|
|
143
|
+
async requestUserConfirmation(check) {
|
|
144
|
+
// In real implementation, this would prompt user
|
|
145
|
+
console.log(`⚠️ Safety check: ${check.reason}`);
|
|
146
|
+
console.log(' Waiting for user confirmation...');
|
|
147
|
+
|
|
148
|
+
// For now, return false (deny by default)
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Log operation to audit log
|
|
154
|
+
* @param {string} operation - Operation type
|
|
155
|
+
* @param {Object} context - Context
|
|
156
|
+
* @param {boolean} allowed - Whether allowed
|
|
157
|
+
*/
|
|
158
|
+
logOperation(operation, context, allowed) {
|
|
159
|
+
this.auditLog.push({
|
|
160
|
+
timestamp: new Date().toISOString(),
|
|
161
|
+
operation,
|
|
162
|
+
context,
|
|
163
|
+
allowed,
|
|
164
|
+
user: process.env.USER || 'unknown'
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get audit log
|
|
170
|
+
* @returns {Array} - Audit log entries
|
|
171
|
+
*/
|
|
172
|
+
getAuditLog() {
|
|
173
|
+
return this.auditLog;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Export audit log
|
|
178
|
+
* @param {string} outputPath - Output file path
|
|
179
|
+
*/
|
|
180
|
+
async exportAuditLog(outputPath) {
|
|
181
|
+
const fs = require('fs-extra');
|
|
182
|
+
await fs.writeJson(outputPath, this.auditLog, { spaces: 2 });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = SafetyManager;
|