claude-flow-novice 2.15.3 → 2.15.5
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/.claude/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/.claude/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/.claude/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/.claude/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/.claude/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/.claude/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/.claude/commands/cfn-loop-cli.md +29 -6
- package/.claude/commands/switch-api.md +31 -10
- package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +238 -29
- package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
- package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/.claude/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +6 -2
- package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/.claude/skills/cfn-redis-coordination/redis-functions.sh +34 -0
- package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- package/README.md +116 -475
- package/claude-assets/agents/cfn-dev-team/README.md +103 -0
- package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
- package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
- package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
- package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
- package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
- package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
- package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
- package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
- package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
- package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
- package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
- package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
- package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
- package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
- package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
- package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
- package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
- package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
- package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
- package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/claude-assets/commands/cfn-loop-cli.md +29 -6
- package/claude-assets/commands/switch-api.md +31 -10
- package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
- package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +84 -113
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +33 -6
- package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
- package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
- package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
- package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
- package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
- package/claude-assets/skills/bootstrap/database-connection.md +464 -0
- package/claude-assets/skills/bootstrap/error-handling.md +580 -0
- package/claude-assets/skills/bootstrap/file-operations.md +699 -0
- package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
- package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
- package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
- package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
- package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
- package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
- package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
- package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
- package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
- package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
- package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
- package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
- package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
- package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
- package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
- package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +238 -29
- package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
- package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
- package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
- package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
- package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
- package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
- package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +6 -2
- package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +34 -0
- package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
- package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
- package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
- package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
- package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
- package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
- package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
- package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
- package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
- package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
- package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
- package/claude-assets/skills/cfn-utilities/test.sh +317 -0
- package/claude-assets/skills/integration/agent-handoff.sh +62 -64
- package/claude-assets/skills/json-validation/SKILL.md +431 -0
- package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
- package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
- package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
- package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
- package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
- package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
- package/claude-assets/skills/workflow-codification/test-integration.sh +15 -0
- package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +55 -14
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +27 -60
- package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
- package/dist/ace/ace-curator.js +10 -2
- package/dist/ace/ace-curator.js.map +1 -1
- package/dist/ace/ace-generator.js +4 -0
- package/dist/ace/ace-generator.js.map +1 -1
- package/dist/ace/ace-reflector.js +1 -1
- package/dist/ace/ace-reflector.js.map +1 -1
- package/dist/ace/context-injection.js +24 -2
- package/dist/ace/context-injection.js.map +1 -1
- package/dist/agents/task-agent-integration.js +1 -1
- package/dist/agents/task-agent-integration.js.map +1 -1
- package/dist/api/health-endpoints.js +390 -0
- package/dist/api/health-endpoints.js.map +1 -0
- package/dist/cli/agent-executor.js +4 -1
- package/dist/cli/agent-executor.js.map +1 -1
- package/dist/cli/agent-prompt-builder.js +89 -1
- package/dist/cli/agent-prompt-builder.js.map +1 -1
- package/dist/cli/agent-spawn.js +130 -37
- package/dist/cli/agent-spawn.js.map +1 -1
- package/dist/cli/config-manager.js +109 -91
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/conversation-fork-cleanup.js +201 -0
- package/dist/cli/conversation-fork-cleanup.js.map +1 -0
- package/dist/cli/conversation-fork.js +16 -3
- package/dist/cli/conversation-fork.js.map +1 -1
- package/dist/cli/skill-cache-validator.js +412 -0
- package/dist/cli/skill-cache-validator.js.map +1 -0
- package/dist/cli/skill-cli.js +991 -0
- package/dist/cli/skill-cli.js.map +1 -0
- package/dist/cli/skill-execution-logger.js +284 -0
- package/dist/cli/skill-execution-logger.js.map +1 -0
- package/dist/cli/skill-loader.js +457 -0
- package/dist/cli/skill-loader.js.map +1 -0
- package/dist/coordination/event-bus.js +2 -2
- package/dist/coordination/event-bus.js.map +1 -1
- package/dist/coordination/fleet-manager.js +1 -1
- package/dist/coordination/fleet-manager.js.map +1 -1
- package/dist/coordination/index.js +23 -9
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/types/fleet-manager.types.js.map +1 -1
- package/dist/db/migration-manager.js +483 -0
- package/dist/db/migration-manager.js.map +1 -0
- package/dist/db/skills-query.js +535 -0
- package/dist/db/skills-query.js.map +1 -0
- package/dist/integration/DatabaseHandoff.js +1 -1
- package/dist/integration/DatabaseHandoff.js.map +1 -1
- package/dist/jobs/edge-case-analyzer.js +367 -0
- package/dist/jobs/edge-case-analyzer.js.map +1 -0
- package/dist/jobs/promotion-sla-enforcer.js +288 -0
- package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
- package/dist/lib/agent-output-parser.js.map +1 -1
- package/dist/lib/agent-output-validator.js.map +1 -1
- package/dist/lib/agent-workspace.js +281 -0
- package/dist/lib/agent-workspace.js.map +1 -0
- package/dist/lib/atomic-file-writer.js +377 -0
- package/dist/lib/atomic-file-writer.js.map +1 -0
- package/dist/lib/backup-manager.js +779 -0
- package/dist/lib/backup-manager.js.map +1 -0
- package/dist/lib/checkpoint-manager.js +837 -0
- package/dist/lib/checkpoint-manager.js.map +1 -0
- package/dist/lib/circuit-breaker.js +340 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/completion-signal-handler.js +243 -0
- package/dist/lib/completion-signal-handler.js.map +1 -0
- package/dist/lib/config-manager.js +312 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/config-migrator.js +386 -0
- package/dist/lib/config-migrator.js.map +1 -0
- package/dist/lib/config-validator.js.map +1 -1
- package/dist/lib/correlation-cache.js +311 -0
- package/dist/lib/correlation-cache.js.map +1 -0
- package/dist/lib/correlation.js +263 -0
- package/dist/lib/correlation.js.map +1 -0
- package/dist/lib/database-service/connection-pool-manager.js +520 -0
- package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
- package/dist/lib/database-service/correlation.js +329 -0
- package/dist/lib/database-service/correlation.js.map +1 -0
- package/dist/lib/database-service/errors.js +120 -0
- package/dist/lib/database-service/errors.js.map +1 -0
- package/dist/lib/database-service/index.js +168 -0
- package/dist/lib/database-service/index.js.map +1 -0
- package/dist/lib/database-service/postgres-adapter.js +526 -0
- package/dist/lib/database-service/postgres-adapter.js.map +1 -0
- package/dist/lib/database-service/redis-adapter.js +360 -0
- package/dist/lib/database-service/redis-adapter.js.map +1 -0
- package/dist/lib/database-service/sqlite-adapter.js +544 -0
- package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
- package/dist/lib/database-service/transaction-manager.js +773 -0
- package/dist/lib/database-service/transaction-manager.js.map +1 -0
- package/dist/lib/database-service/types.js +23 -0
- package/dist/lib/database-service/types.js.map +1 -0
- package/dist/lib/deadlock-resolver.js +292 -0
- package/dist/lib/deadlock-resolver.js.map +1 -0
- package/dist/lib/distributed-lock.js +451 -0
- package/dist/lib/distributed-lock.js.map +1 -0
- package/dist/lib/edge-case-deduplicator.js +227 -0
- package/dist/lib/edge-case-deduplicator.js.map +1 -0
- package/dist/lib/encryption-manager.js +322 -0
- package/dist/lib/encryption-manager.js.map +1 -0
- package/dist/lib/error-aggregator.js +234 -0
- package/dist/lib/error-aggregator.js.map +1 -0
- package/dist/lib/errors.js +287 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-lock-manager.js +578 -0
- package/dist/lib/file-lock-manager.js.map +1 -0
- package/dist/lib/file-operations.js +367 -0
- package/dist/lib/file-operations.js.map +1 -0
- package/dist/lib/idempotent-write.js +237 -0
- package/dist/lib/idempotent-write.js.map +1 -0
- package/dist/lib/integration-schema-validator.js +522 -0
- package/dist/lib/integration-schema-validator.js.map +1 -0
- package/dist/lib/lock-health-monitor.js +298 -0
- package/dist/lib/lock-health-monitor.js.map +1 -0
- package/dist/lib/log-shipper.js +422 -0
- package/dist/lib/log-shipper.js.map +1 -0
- package/dist/lib/logging.js +146 -0
- package/dist/lib/logging.js.map +1 -0
- package/dist/lib/message-deduplicator.js +439 -0
- package/dist/lib/message-deduplicator.js.map +1 -0
- package/dist/lib/multi-system-query.js +604 -0
- package/dist/lib/multi-system-query.js.map +1 -0
- package/dist/lib/orphan-detector.js +332 -0
- package/dist/lib/orphan-detector.js.map +1 -0
- package/dist/lib/password-generator.js +166 -0
- package/dist/lib/password-generator.js.map +1 -0
- package/dist/lib/path-validator.js +429 -0
- package/dist/lib/path-validator.js.map +1 -0
- package/dist/lib/query-translator.js +905 -0
- package/dist/lib/query-translator.js.map +1 -0
- package/dist/lib/queue-recovery.js +469 -0
- package/dist/lib/queue-recovery.js.map +1 -0
- package/dist/lib/redis-queue-manager.js +512 -0
- package/dist/lib/redis-queue-manager.js.map +1 -0
- package/dist/lib/reflection-archiver.js +272 -0
- package/dist/lib/reflection-archiver.js.map +1 -0
- package/dist/lib/retry-manager.js +453 -0
- package/dist/lib/retry-manager.js.map +1 -0
- package/dist/lib/retry.js +262 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/schema-transform.js +695 -0
- package/dist/lib/schema-transform.js.map +1 -0
- package/dist/lib/schema-validator.js +491 -0
- package/dist/lib/schema-validator.js.map +1 -0
- package/dist/lib/skill-cache.js +297 -0
- package/dist/lib/skill-cache.js.map +1 -0
- package/dist/lib/skill-content-manager.js +337 -0
- package/dist/lib/skill-content-manager.js.map +1 -0
- package/dist/lib/skill-frontmatter-parser.js +237 -0
- package/dist/lib/skill-frontmatter-parser.js.map +1 -0
- package/dist/lib/skill-git-integration.js +275 -0
- package/dist/lib/skill-git-integration.js.map +1 -0
- package/dist/lib/skill-markdown-validator.js +396 -0
- package/dist/lib/skill-markdown-validator.js.map +1 -0
- package/dist/lib/skill-output-parser.js +312 -0
- package/dist/lib/skill-output-parser.js.map +1 -0
- package/dist/lib/unified-query-api.js +467 -0
- package/dist/lib/unified-query-api.js.map +1 -0
- package/dist/middleware/auth-middleware.js +350 -0
- package/dist/middleware/auth-middleware.js.map +1 -0
- package/dist/middleware/schema-validation.js +347 -0
- package/dist/middleware/schema-validation.js.map +1 -0
- package/dist/providers/anthropic-provider.js +1 -1
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/provider-factory.js +2 -2
- package/dist/providers/provider-factory.js.map +1 -1
- package/dist/services/edge-case-analyzer.js +321 -0
- package/dist/services/edge-case-analyzer.js.map +1 -0
- package/dist/services/edge-case-deduplicator.js +266 -0
- package/dist/services/edge-case-deduplicator.js.map +1 -0
- package/dist/services/edge-case-detector.js +337 -0
- package/dist/services/edge-case-detector.js.map +1 -0
- package/dist/services/edge-case-tracker.js +547 -0
- package/dist/services/edge-case-tracker.js.map +1 -0
- package/dist/services/health-check-system.js +586 -0
- package/dist/services/health-check-system.js.map +1 -0
- package/dist/services/metrics-logger.js +412 -0
- package/dist/services/metrics-logger.js.map +1 -0
- package/dist/services/patch-generator.js +378 -0
- package/dist/services/patch-generator.js.map +1 -0
- package/dist/services/patch-validator.js +337 -0
- package/dist/services/patch-validator.js.map +1 -0
- package/dist/services/performance-monitor.js +811 -0
- package/dist/services/performance-monitor.js.map +1 -0
- package/dist/services/promotion-pipeline.js +918 -0
- package/dist/services/promotion-pipeline.js.map +1 -0
- package/dist/services/promotion-validator.js +394 -0
- package/dist/services/promotion-validator.js.map +1 -0
- package/dist/services/reflection-logger.js +388 -0
- package/dist/services/reflection-logger.js.map +1 -0
- package/dist/services/skill-deployment.js +472 -0
- package/dist/services/skill-deployment.js.map +1 -0
- package/dist/services/skill-loader.js +427 -0
- package/dist/services/skill-loader.js.map +1 -0
- package/dist/services/skill-promotion.js +372 -0
- package/dist/services/skill-promotion.js.map +1 -0
- package/dist/services/skill-validator.js +454 -0
- package/dist/services/skill-validator.js.map +1 -0
- package/dist/services/skill-versioning.js +244 -0
- package/dist/services/skill-versioning.js.map +1 -0
- package/dist/services/workspace-supervisor.js +597 -0
- package/dist/services/workspace-supervisor.js.map +1 -0
- package/dist/types/edge-case.js +45 -0
- package/dist/types/edge-case.js.map +1 -0
- package/docs/BUG_19_MEMORY_LEAK_TASK_MODE.md +405 -0
- package/docs/MEMORY_CLEANUP_GUIDE.md +358 -0
- package/docs/MEMORY_LEAK_FIX_SUMMARY.md +322 -0
- package/docs/REDIS_CLEANUP_EXECUTIVE_SUMMARY.md +319 -0
- package/docs/REDIS_CLEANUP_VERIFICATION_REPORT.md +574 -0
- package/package.json +35 -4
- package/readme/README.md +53 -5
- package/scripts/backup-cleanup.sh +627 -0
- package/scripts/cleanup-workspaces.sh +412 -0
- package/scripts/cleanup-yaml-configs.sh +141 -0
- package/scripts/deploy-approved-skills.sh +263 -0
- package/scripts/health-check.sh +447 -0
- package/scripts/log-aggregator.sh +554 -0
- package/scripts/log-monitor.sh +629 -0
- package/scripts/manage-agent-workspaces.sh +434 -0
- package/scripts/migrate-schema.sh +533 -0
- package/scripts/promote-staged-skills.sh +423 -0
- package/scripts/verify-no-secrets.sh +88 -35
- package/scripts/verify-redis-cleanup.sh +173 -0
- package/tests/README.md +84 -0
- package/tests/test-memory-leak-task-mode.sh +435 -0
- package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/.claude/skills/agent-lifecycle/SKILL.md +0 -60
- package/.claude/skills/agent-lifecycle/execute-lifecycle-hook.sh +0 -573
- package/.claude/skills/agent-lifecycle/simple-audit.sh +0 -31
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
- package/README.md.backup_before_replace +0 -781
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomic File Writer
|
|
3
|
+
*
|
|
4
|
+
* Provides atomic file write operations with SHA256 checksum verification,
|
|
5
|
+
* rollback capability, and permission preservation.
|
|
6
|
+
* Part of Task 4.2: Centralized File Locking & Atomic Operations
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Write-then-move pattern (write to temp, verify, move to target)
|
|
10
|
+
* - SHA256 checksum verification
|
|
11
|
+
* - Automatic rollback on failure
|
|
12
|
+
* - Preserve file permissions and ownership
|
|
13
|
+
* - Backup creation before overwrite
|
|
14
|
+
* - Integration with file lock manager
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* const writer = new AtomicFileWriter();
|
|
18
|
+
* await writer.writeFile('/path/to/file.txt', content, {
|
|
19
|
+
* createBackup: true,
|
|
20
|
+
* preservePermissions: true
|
|
21
|
+
* });
|
|
22
|
+
*/ import * as fs from 'fs';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
import * as crypto from 'crypto';
|
|
25
|
+
import { promisify } from 'util';
|
|
26
|
+
import { randomUUID } from 'crypto';
|
|
27
|
+
import { createLogger } from './logging.js';
|
|
28
|
+
import { createError, ErrorCode } from './errors.js';
|
|
29
|
+
import { withFileLock } from './file-lock-manager.js';
|
|
30
|
+
const logger = createLogger('atomic-file-writer');
|
|
31
|
+
const fsWriteFile = promisify(fs.writeFile);
|
|
32
|
+
const fsReadFile = promisify(fs.readFile);
|
|
33
|
+
const fsRename = promisify(fs.rename);
|
|
34
|
+
const fsUnlink = promisify(fs.unlink);
|
|
35
|
+
const fsStat = promisify(fs.stat);
|
|
36
|
+
const fsMkdir = promisify(fs.mkdir);
|
|
37
|
+
const fsChmod = promisify(fs.chmod);
|
|
38
|
+
const fsChown = promisify(fs.chown);
|
|
39
|
+
const fsAccess = promisify(fs.access);
|
|
40
|
+
const fsCopyFile = promisify(fs.copyFile);
|
|
41
|
+
/**
|
|
42
|
+
* Atomic File Writer
|
|
43
|
+
*
|
|
44
|
+
* Provides safe atomic file writes with verification and rollback.
|
|
45
|
+
*/ export class AtomicFileWriter {
|
|
46
|
+
/**
|
|
47
|
+
* Write file atomically with verification
|
|
48
|
+
*
|
|
49
|
+
* @param filePath - Target file path
|
|
50
|
+
* @param content - Content to write (string or Buffer)
|
|
51
|
+
* @param options - Write options
|
|
52
|
+
* @returns Promise<WriteResult> - Write result with metadata
|
|
53
|
+
*/ async writeFile(filePath, content, options = {}) {
|
|
54
|
+
const startTime = Date.now();
|
|
55
|
+
const absolutePath = path.resolve(filePath);
|
|
56
|
+
const opts = {
|
|
57
|
+
encoding: options.encoding || 'utf8',
|
|
58
|
+
createBackup: options.createBackup || false,
|
|
59
|
+
preservePermissions: options.preservePermissions !== false,
|
|
60
|
+
preserveOwnership: options.preserveOwnership || false,
|
|
61
|
+
verifyChecksum: options.verifyChecksum !== false,
|
|
62
|
+
useLock: options.useLock !== false,
|
|
63
|
+
lockOptions: options.lockOptions || {},
|
|
64
|
+
backupDir: options.backupDir
|
|
65
|
+
};
|
|
66
|
+
logger.debug('Starting atomic write', {
|
|
67
|
+
filePath: absolutePath,
|
|
68
|
+
contentLength: typeof content === 'string' ? content.length : content.length,
|
|
69
|
+
options: opts
|
|
70
|
+
});
|
|
71
|
+
// Calculate expected checksum
|
|
72
|
+
const expectedChecksum = this.calculateChecksum(content);
|
|
73
|
+
// Execute write with lock if requested
|
|
74
|
+
if (opts.useLock) {
|
|
75
|
+
return withFileLock(absolutePath, async ()=>this.performWrite(absolutePath, content, opts, expectedChecksum, startTime), opts.lockOptions);
|
|
76
|
+
} else {
|
|
77
|
+
return this.performWrite(absolutePath, content, opts, expectedChecksum, startTime);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Perform the actual write operation
|
|
82
|
+
*/ async performWrite(absolutePath, content, options, expectedChecksum, startTime) {
|
|
83
|
+
const dir = path.dirname(absolutePath);
|
|
84
|
+
const tempPath = path.join(dir, `.${path.basename(absolutePath)}.${randomUUID()}.tmp`);
|
|
85
|
+
let backupPath;
|
|
86
|
+
let originalMetadata = null;
|
|
87
|
+
let rolledBack = false;
|
|
88
|
+
try {
|
|
89
|
+
// Ensure directory exists
|
|
90
|
+
await this.ensureDirectory(dir);
|
|
91
|
+
// Get original file metadata (if exists)
|
|
92
|
+
originalMetadata = await this.getFileMetadata(absolutePath);
|
|
93
|
+
// Create backup if requested and file exists
|
|
94
|
+
if (options.createBackup && originalMetadata.exists) {
|
|
95
|
+
backupPath = await this.createBackup(absolutePath, options.backupDir);
|
|
96
|
+
logger.info('Backup created', {
|
|
97
|
+
original: absolutePath,
|
|
98
|
+
backup: backupPath
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Write to temporary file
|
|
102
|
+
logger.debug('Writing to temporary file', {
|
|
103
|
+
tempPath
|
|
104
|
+
});
|
|
105
|
+
await fsWriteFile(tempPath, content, options.encoding);
|
|
106
|
+
// Verify checksum
|
|
107
|
+
if (options.verifyChecksum) {
|
|
108
|
+
const actualChecksum = await this.calculateFileChecksum(tempPath);
|
|
109
|
+
if (actualChecksum !== expectedChecksum) {
|
|
110
|
+
throw createError(ErrorCode.CHECKSUM_MISMATCH, 'Checksum verification failed after write', {
|
|
111
|
+
expected: expectedChecksum,
|
|
112
|
+
actual: actualChecksum,
|
|
113
|
+
filePath: absolutePath
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
logger.debug('Checksum verified', {
|
|
117
|
+
checksum: actualChecksum
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Preserve permissions if requested
|
|
121
|
+
if (options.preservePermissions && originalMetadata.exists) {
|
|
122
|
+
await fsChmod(tempPath, originalMetadata.mode);
|
|
123
|
+
logger.debug('Permissions preserved', {
|
|
124
|
+
mode: originalMetadata.mode.toString(8)
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// Preserve ownership if requested (requires privileges)
|
|
128
|
+
if (options.preserveOwnership && originalMetadata.exists) {
|
|
129
|
+
try {
|
|
130
|
+
await fsChown(tempPath, originalMetadata.uid, originalMetadata.gid);
|
|
131
|
+
logger.debug('Ownership preserved', {
|
|
132
|
+
uid: originalMetadata.uid,
|
|
133
|
+
gid: originalMetadata.gid
|
|
134
|
+
});
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logger.warn('Failed to preserve ownership (requires elevated privileges)', error instanceof Error ? error : undefined);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Atomic move to target location
|
|
140
|
+
logger.debug('Moving to target location', {
|
|
141
|
+
from: tempPath,
|
|
142
|
+
to: absolutePath
|
|
143
|
+
});
|
|
144
|
+
await fsRename(tempPath, absolutePath);
|
|
145
|
+
// Get final file size
|
|
146
|
+
const stat = await fsStat(absolutePath);
|
|
147
|
+
const bytesWritten = stat.size;
|
|
148
|
+
const durationMs = Date.now() - startTime;
|
|
149
|
+
logger.info('Atomic write completed successfully', {
|
|
150
|
+
filePath: absolutePath,
|
|
151
|
+
bytesWritten,
|
|
152
|
+
checksum: expectedChecksum,
|
|
153
|
+
durationMs
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
success: true,
|
|
157
|
+
filePath: absolutePath,
|
|
158
|
+
checksum: expectedChecksum,
|
|
159
|
+
bytesWritten,
|
|
160
|
+
durationMs,
|
|
161
|
+
backupPath,
|
|
162
|
+
rolledBack: false
|
|
163
|
+
};
|
|
164
|
+
} catch (error) {
|
|
165
|
+
logger.error('Atomic write failed, attempting rollback', error instanceof Error ? error : undefined, {
|
|
166
|
+
filePath: absolutePath
|
|
167
|
+
});
|
|
168
|
+
// Attempt rollback
|
|
169
|
+
try {
|
|
170
|
+
// Remove temp file if it exists
|
|
171
|
+
if (await this.fileExists(tempPath)) {
|
|
172
|
+
await fsUnlink(tempPath);
|
|
173
|
+
logger.debug('Temporary file removed', {
|
|
174
|
+
tempPath
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// Restore from backup if available
|
|
178
|
+
if (backupPath && await this.fileExists(backupPath)) {
|
|
179
|
+
await fsCopyFile(backupPath, absolutePath);
|
|
180
|
+
logger.info('Restored from backup after failed write', {
|
|
181
|
+
backup: backupPath,
|
|
182
|
+
target: absolutePath
|
|
183
|
+
});
|
|
184
|
+
rolledBack = true;
|
|
185
|
+
}
|
|
186
|
+
} catch (rollbackError) {
|
|
187
|
+
logger.error('Rollback failed', rollbackError instanceof Error ? rollbackError : undefined, {
|
|
188
|
+
filePath: absolutePath,
|
|
189
|
+
backupPath
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const durationMs = Date.now() - startTime;
|
|
193
|
+
throw createError(ErrorCode.FILE_WRITE_FAILED, `Atomic write failed: ${absolutePath}`, {
|
|
194
|
+
filePath: absolutePath,
|
|
195
|
+
durationMs,
|
|
196
|
+
backupPath,
|
|
197
|
+
rolledBack
|
|
198
|
+
}, error instanceof Error ? error : undefined);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Calculate SHA256 checksum of content
|
|
203
|
+
*/ calculateChecksum(content) {
|
|
204
|
+
const hash = crypto.createHash('sha256');
|
|
205
|
+
hash.update(content);
|
|
206
|
+
return hash.digest('hex');
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Calculate SHA256 checksum of file
|
|
210
|
+
*/ async calculateFileChecksum(filePath) {
|
|
211
|
+
return new Promise((resolve, reject)=>{
|
|
212
|
+
const hash = crypto.createHash('sha256');
|
|
213
|
+
const stream = fs.createReadStream(filePath);
|
|
214
|
+
stream.on('data', (chunk)=>hash.update(chunk));
|
|
215
|
+
stream.on('end', ()=>resolve(hash.digest('hex')));
|
|
216
|
+
stream.on('error', reject);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get file metadata for permission preservation
|
|
221
|
+
*/ async getFileMetadata(filePath) {
|
|
222
|
+
try {
|
|
223
|
+
const stats = await fsStat(filePath);
|
|
224
|
+
return {
|
|
225
|
+
mode: stats.mode,
|
|
226
|
+
uid: stats.uid,
|
|
227
|
+
gid: stats.gid,
|
|
228
|
+
exists: true
|
|
229
|
+
};
|
|
230
|
+
} catch (error) {
|
|
231
|
+
// File doesn't exist
|
|
232
|
+
return {
|
|
233
|
+
mode: 0o644,
|
|
234
|
+
uid: process.getuid ? process.getuid() : 0,
|
|
235
|
+
gid: process.getgid ? process.getgid() : 0,
|
|
236
|
+
exists: false
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Create backup of existing file
|
|
242
|
+
*/ async createBackup(filePath, backupDir) {
|
|
243
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
244
|
+
const basename = path.basename(filePath);
|
|
245
|
+
const targetDir = backupDir || path.dirname(filePath);
|
|
246
|
+
// Ensure backup directory exists
|
|
247
|
+
await this.ensureDirectory(targetDir);
|
|
248
|
+
const backupPath = path.join(targetDir, `${basename}.${timestamp}.backup`);
|
|
249
|
+
try {
|
|
250
|
+
await fsCopyFile(filePath, backupPath);
|
|
251
|
+
return backupPath;
|
|
252
|
+
} catch (error) {
|
|
253
|
+
throw createError(ErrorCode.BACKUP_FAILED, `Failed to create backup: ${filePath}`, {
|
|
254
|
+
filePath,
|
|
255
|
+
backupPath
|
|
256
|
+
}, error instanceof Error ? error : undefined);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Check if file exists
|
|
261
|
+
*/ async fileExists(filePath) {
|
|
262
|
+
try {
|
|
263
|
+
await fsAccess(filePath, fs.constants.F_OK);
|
|
264
|
+
return true;
|
|
265
|
+
} catch {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Ensure directory exists
|
|
271
|
+
*/ async ensureDirectory(dirPath) {
|
|
272
|
+
try {
|
|
273
|
+
await fsMkdir(dirPath, {
|
|
274
|
+
recursive: true
|
|
275
|
+
});
|
|
276
|
+
} catch (error) {
|
|
277
|
+
// Ignore error if directory already exists
|
|
278
|
+
if (error.code !== 'EEXIST') {
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Read file atomically with checksum verification
|
|
285
|
+
*
|
|
286
|
+
* @param filePath - File to read
|
|
287
|
+
* @param expectedChecksum - Optional expected checksum
|
|
288
|
+
* @param encoding - File encoding (default: 'utf8')
|
|
289
|
+
* @returns Promise<{content: string, checksum: string}> - File content and checksum
|
|
290
|
+
*/ async readFile(filePath, expectedChecksum, encoding = 'utf8') {
|
|
291
|
+
const absolutePath = path.resolve(filePath);
|
|
292
|
+
try {
|
|
293
|
+
const content = await fsReadFile(absolutePath, encoding);
|
|
294
|
+
const checksum = this.calculateChecksum(content);
|
|
295
|
+
if (expectedChecksum && checksum !== expectedChecksum) {
|
|
296
|
+
throw createError(ErrorCode.CHECKSUM_MISMATCH, 'Checksum verification failed during read', {
|
|
297
|
+
expected: expectedChecksum,
|
|
298
|
+
actual: checksum,
|
|
299
|
+
filePath: absolutePath
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
logger.debug('File read with checksum verification', {
|
|
303
|
+
filePath: absolutePath,
|
|
304
|
+
checksum,
|
|
305
|
+
verified: !!expectedChecksum
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
content,
|
|
309
|
+
checksum
|
|
310
|
+
};
|
|
311
|
+
} catch (error) {
|
|
312
|
+
throw createError(ErrorCode.FILE_READ_FAILED, `Failed to read file: ${absolutePath}`, {
|
|
313
|
+
filePath: absolutePath
|
|
314
|
+
}, error instanceof Error ? error : undefined);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Verify file checksum
|
|
319
|
+
*
|
|
320
|
+
* @param filePath - File to verify
|
|
321
|
+
* @param expectedChecksum - Expected SHA256 checksum
|
|
322
|
+
* @returns Promise<boolean> - True if checksum matches
|
|
323
|
+
*/ async verifyChecksum(filePath, expectedChecksum) {
|
|
324
|
+
const absolutePath = path.resolve(filePath);
|
|
325
|
+
try {
|
|
326
|
+
const actualChecksum = await this.calculateFileChecksum(absolutePath);
|
|
327
|
+
const matches = actualChecksum === expectedChecksum;
|
|
328
|
+
logger.debug('Checksum verification', {
|
|
329
|
+
filePath: absolutePath,
|
|
330
|
+
expected: expectedChecksum,
|
|
331
|
+
actual: actualChecksum,
|
|
332
|
+
matches
|
|
333
|
+
});
|
|
334
|
+
return matches;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
logger.error('Checksum verification failed', error instanceof Error ? error : undefined, {
|
|
337
|
+
filePath: absolutePath
|
|
338
|
+
});
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Singleton instance
|
|
345
|
+
*/ let defaultWriter = null;
|
|
346
|
+
/**
|
|
347
|
+
* Get the default atomic file writer instance
|
|
348
|
+
*/ export function getAtomicFileWriter() {
|
|
349
|
+
if (!defaultWriter) {
|
|
350
|
+
defaultWriter = new AtomicFileWriter();
|
|
351
|
+
}
|
|
352
|
+
return defaultWriter;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Helper function for atomic writes
|
|
356
|
+
*
|
|
357
|
+
* @param filePath - Target file path
|
|
358
|
+
* @param content - Content to write
|
|
359
|
+
* @param options - Write options
|
|
360
|
+
* @returns Promise<WriteResult> - Write result
|
|
361
|
+
*/ export async function atomicWriteFile(filePath, content, options = {}) {
|
|
362
|
+
const writer = getAtomicFileWriter();
|
|
363
|
+
return writer.writeFile(filePath, content, options);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Helper function for atomic reads with checksum
|
|
367
|
+
*
|
|
368
|
+
* @param filePath - File to read
|
|
369
|
+
* @param expectedChecksum - Optional expected checksum
|
|
370
|
+
* @param encoding - File encoding
|
|
371
|
+
* @returns Promise<{content: string, checksum: string}>
|
|
372
|
+
*/ export async function atomicReadFile(filePath, expectedChecksum, encoding = 'utf8') {
|
|
373
|
+
const writer = getAtomicFileWriter();
|
|
374
|
+
return writer.readFile(filePath, expectedChecksum, encoding);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
//# sourceMappingURL=atomic-file-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/atomic-file-writer.ts"],"sourcesContent":["/**\r\n * Atomic File Writer\r\n *\r\n * Provides atomic file write operations with SHA256 checksum verification,\r\n * rollback capability, and permission preservation.\r\n * Part of Task 4.2: Centralized File Locking & Atomic Operations\r\n *\r\n * Features:\r\n * - Write-then-move pattern (write to temp, verify, move to target)\r\n * - SHA256 checksum verification\r\n * - Automatic rollback on failure\r\n * - Preserve file permissions and ownership\r\n * - Backup creation before overwrite\r\n * - Integration with file lock manager\r\n *\r\n * Usage:\r\n * const writer = new AtomicFileWriter();\r\n * await writer.writeFile('/path/to/file.txt', content, {\r\n * createBackup: true,\r\n * preservePermissions: true\r\n * });\r\n */\r\n\r\nimport * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport * as crypto from 'crypto';\r\nimport { promisify } from 'util';\r\nimport { randomUUID } from 'crypto';\r\nimport { createLogger } from './logging.js';\r\nimport { createError, ErrorCode } from './errors.js';\r\nimport { withFileLock, LockAcquisitionOptions } from './file-lock-manager.js';\r\n\r\nconst logger = createLogger('atomic-file-writer');\r\n\r\nconst fsWriteFile = promisify(fs.writeFile);\r\nconst fsReadFile = promisify(fs.readFile);\r\nconst fsRename = promisify(fs.rename);\r\nconst fsUnlink = promisify(fs.unlink);\r\nconst fsStat = promisify(fs.stat);\r\nconst fsMkdir = promisify(fs.mkdir);\r\nconst fsChmod = promisify(fs.chmod);\r\nconst fsChown = promisify(fs.chown);\r\nconst fsAccess = promisify(fs.access);\r\nconst fsCopyFile = promisify(fs.copyFile);\r\n\r\n/**\r\n * File write options\r\n */\r\nexport interface WriteOptions {\r\n /** File encoding (default: 'utf8') */\r\n encoding?: BufferEncoding;\r\n /** Create backup before overwrite (default: false) */\r\n createBackup?: boolean;\r\n /** Preserve file permissions (default: true) */\r\n preservePermissions?: boolean;\r\n /** Preserve file ownership (default: false, requires sudo) */\r\n preserveOwnership?: boolean;\r\n /** Verify checksum after write (default: true) */\r\n verifyChecksum?: boolean;\r\n /** Lock file during write (default: true) */\r\n useLock?: boolean;\r\n /** Lock options (if useLock is true) */\r\n lockOptions?: LockAcquisitionOptions;\r\n /** Backup directory (default: same as target) */\r\n backupDir?: string;\r\n}\r\n\r\n/**\r\n * Write result with metadata\r\n */\r\nexport interface WriteResult {\r\n /** Success status */\r\n success: boolean;\r\n /** File path */\r\n filePath: string;\r\n /** SHA256 checksum of written content */\r\n checksum: string;\r\n /** Bytes written */\r\n bytesWritten: number;\r\n /** Write duration in milliseconds */\r\n durationMs: number;\r\n /** Backup path (if created) */\r\n backupPath?: string;\r\n /** Whether rollback occurred */\r\n rolledBack: boolean;\r\n}\r\n\r\n/**\r\n * File metadata for permission preservation\r\n */\r\ninterface FileMetadata {\r\n mode: number;\r\n uid: number;\r\n gid: number;\r\n exists: boolean;\r\n}\r\n\r\n/**\r\n * Atomic File Writer\r\n *\r\n * Provides safe atomic file writes with verification and rollback.\r\n */\r\nexport class AtomicFileWriter {\r\n /**\r\n * Write file atomically with verification\r\n *\r\n * @param filePath - Target file path\r\n * @param content - Content to write (string or Buffer)\r\n * @param options - Write options\r\n * @returns Promise<WriteResult> - Write result with metadata\r\n */\r\n async writeFile(\r\n filePath: string,\r\n content: string | Buffer,\r\n options: WriteOptions = {}\r\n ): Promise<WriteResult> {\r\n const startTime = Date.now();\r\n const absolutePath = path.resolve(filePath);\r\n\r\n const opts = {\r\n encoding: (options.encoding || 'utf8') as BufferEncoding,\r\n createBackup: options.createBackup || false,\r\n preservePermissions: options.preservePermissions !== false,\r\n preserveOwnership: options.preserveOwnership || false,\r\n verifyChecksum: options.verifyChecksum !== false,\r\n useLock: options.useLock !== false,\r\n lockOptions: options.lockOptions || {},\r\n backupDir: options.backupDir,\r\n };\r\n\r\n logger.debug('Starting atomic write', {\r\n filePath: absolutePath,\r\n contentLength: typeof content === 'string' ? content.length : content.length,\r\n options: opts,\r\n });\r\n\r\n // Calculate expected checksum\r\n const expectedChecksum = this.calculateChecksum(content);\r\n\r\n // Execute write with lock if requested\r\n if (opts.useLock) {\r\n return withFileLock(\r\n absolutePath,\r\n async () => this.performWrite(absolutePath, content, opts, expectedChecksum, startTime),\r\n opts.lockOptions\r\n );\r\n } else {\r\n return this.performWrite(absolutePath, content, opts, expectedChecksum, startTime);\r\n }\r\n }\r\n\r\n /**\r\n * Perform the actual write operation\r\n */\r\n private async performWrite(\r\n absolutePath: string,\r\n content: string | Buffer,\r\n options: Required<WriteOptions>,\r\n expectedChecksum: string,\r\n startTime: number\r\n ): Promise<WriteResult> {\r\n const dir = path.dirname(absolutePath);\r\n const tempPath = path.join(dir, `.${path.basename(absolutePath)}.${randomUUID()}.tmp`);\r\n let backupPath: string | undefined;\r\n let originalMetadata: FileMetadata | null = null;\r\n let rolledBack = false;\r\n\r\n try {\r\n // Ensure directory exists\r\n await this.ensureDirectory(dir);\r\n\r\n // Get original file metadata (if exists)\r\n originalMetadata = await this.getFileMetadata(absolutePath);\r\n\r\n // Create backup if requested and file exists\r\n if (options.createBackup && originalMetadata.exists) {\r\n backupPath = await this.createBackup(absolutePath, options.backupDir);\r\n logger.info('Backup created', { original: absolutePath, backup: backupPath });\r\n }\r\n\r\n // Write to temporary file\r\n logger.debug('Writing to temporary file', { tempPath });\r\n await fsWriteFile(tempPath, content, options.encoding);\r\n\r\n // Verify checksum\r\n if (options.verifyChecksum) {\r\n const actualChecksum = await this.calculateFileChecksum(tempPath);\r\n if (actualChecksum !== expectedChecksum) {\r\n throw createError(\r\n ErrorCode.CHECKSUM_MISMATCH,\r\n 'Checksum verification failed after write',\r\n {\r\n expected: expectedChecksum,\r\n actual: actualChecksum,\r\n filePath: absolutePath,\r\n }\r\n );\r\n }\r\n logger.debug('Checksum verified', { checksum: actualChecksum });\r\n }\r\n\r\n // Preserve permissions if requested\r\n if (options.preservePermissions && originalMetadata.exists) {\r\n await fsChmod(tempPath, originalMetadata.mode);\r\n logger.debug('Permissions preserved', { mode: originalMetadata.mode.toString(8) });\r\n }\r\n\r\n // Preserve ownership if requested (requires privileges)\r\n if (options.preserveOwnership && originalMetadata.exists) {\r\n try {\r\n await fsChown(tempPath, originalMetadata.uid, originalMetadata.gid);\r\n logger.debug('Ownership preserved', {\r\n uid: originalMetadata.uid,\r\n gid: originalMetadata.gid,\r\n });\r\n } catch (error) {\r\n logger.warn(\r\n 'Failed to preserve ownership (requires elevated privileges)',\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n // Atomic move to target location\r\n logger.debug('Moving to target location', { from: tempPath, to: absolutePath });\r\n await fsRename(tempPath, absolutePath);\r\n\r\n // Get final file size\r\n const stat = await fsStat(absolutePath);\r\n const bytesWritten = stat.size;\r\n\r\n const durationMs = Date.now() - startTime;\r\n\r\n logger.info('Atomic write completed successfully', {\r\n filePath: absolutePath,\r\n bytesWritten,\r\n checksum: expectedChecksum,\r\n durationMs,\r\n });\r\n\r\n return {\r\n success: true,\r\n filePath: absolutePath,\r\n checksum: expectedChecksum,\r\n bytesWritten,\r\n durationMs,\r\n backupPath,\r\n rolledBack: false,\r\n };\r\n } catch (error) {\r\n logger.error(\r\n 'Atomic write failed, attempting rollback',\r\n error instanceof Error ? error : undefined,\r\n { filePath: absolutePath }\r\n );\r\n\r\n // Attempt rollback\r\n try {\r\n // Remove temp file if it exists\r\n if (await this.fileExists(tempPath)) {\r\n await fsUnlink(tempPath);\r\n logger.debug('Temporary file removed', { tempPath });\r\n }\r\n\r\n // Restore from backup if available\r\n if (backupPath && (await this.fileExists(backupPath))) {\r\n await fsCopyFile(backupPath, absolutePath);\r\n logger.info('Restored from backup after failed write', {\r\n backup: backupPath,\r\n target: absolutePath,\r\n });\r\n rolledBack = true;\r\n }\r\n } catch (rollbackError) {\r\n logger.error(\r\n 'Rollback failed',\r\n rollbackError instanceof Error ? rollbackError : undefined,\r\n { filePath: absolutePath, backupPath }\r\n );\r\n }\r\n\r\n const durationMs = Date.now() - startTime;\r\n\r\n throw createError(\r\n ErrorCode.FILE_WRITE_FAILED,\r\n `Atomic write failed: ${absolutePath}`,\r\n {\r\n filePath: absolutePath,\r\n durationMs,\r\n backupPath,\r\n rolledBack,\r\n },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Calculate SHA256 checksum of content\r\n */\r\n private calculateChecksum(content: string | Buffer): string {\r\n const hash = crypto.createHash('sha256');\r\n hash.update(content);\r\n return hash.digest('hex');\r\n }\r\n\r\n /**\r\n * Calculate SHA256 checksum of file\r\n */\r\n private async calculateFileChecksum(filePath: string): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const hash = crypto.createHash('sha256');\r\n const stream = fs.createReadStream(filePath);\r\n\r\n stream.on('data', (chunk) => hash.update(chunk));\r\n stream.on('end', () => resolve(hash.digest('hex')));\r\n stream.on('error', reject);\r\n });\r\n }\r\n\r\n /**\r\n * Get file metadata for permission preservation\r\n */\r\n private async getFileMetadata(filePath: string): Promise<FileMetadata> {\r\n try {\r\n const stats = await fsStat(filePath);\r\n return {\r\n mode: stats.mode,\r\n uid: stats.uid,\r\n gid: stats.gid,\r\n exists: true,\r\n };\r\n } catch (error) {\r\n // File doesn't exist\r\n return {\r\n mode: 0o644, // Default permissions\r\n uid: process.getuid ? process.getuid() : 0,\r\n gid: process.getgid ? process.getgid() : 0,\r\n exists: false,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Create backup of existing file\r\n */\r\n private async createBackup(filePath: string, backupDir?: string): Promise<string> {\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const basename = path.basename(filePath);\r\n const targetDir = backupDir || path.dirname(filePath);\r\n\r\n // Ensure backup directory exists\r\n await this.ensureDirectory(targetDir);\r\n\r\n const backupPath = path.join(targetDir, `${basename}.${timestamp}.backup`);\r\n\r\n try {\r\n await fsCopyFile(filePath, backupPath);\r\n return backupPath;\r\n } catch (error) {\r\n throw createError(\r\n ErrorCode.BACKUP_FAILED,\r\n `Failed to create backup: ${filePath}`,\r\n { filePath, backupPath },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Check if file exists\r\n */\r\n private async fileExists(filePath: string): Promise<boolean> {\r\n try {\r\n await fsAccess(filePath, fs.constants.F_OK);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Ensure directory exists\r\n */\r\n private async ensureDirectory(dirPath: string): Promise<void> {\r\n try {\r\n await fsMkdir(dirPath, { recursive: true });\r\n } catch (error) {\r\n // Ignore error if directory already exists\r\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {\r\n throw error;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Read file atomically with checksum verification\r\n *\r\n * @param filePath - File to read\r\n * @param expectedChecksum - Optional expected checksum\r\n * @param encoding - File encoding (default: 'utf8')\r\n * @returns Promise<{content: string, checksum: string}> - File content and checksum\r\n */\r\n async readFile(\r\n filePath: string,\r\n expectedChecksum?: string,\r\n encoding: BufferEncoding = 'utf8'\r\n ): Promise<{ content: string; checksum: string }> {\r\n const absolutePath = path.resolve(filePath);\r\n\r\n try {\r\n const content = await fsReadFile(absolutePath, encoding);\r\n const checksum = this.calculateChecksum(content);\r\n\r\n if (expectedChecksum && checksum !== expectedChecksum) {\r\n throw createError(\r\n ErrorCode.CHECKSUM_MISMATCH,\r\n 'Checksum verification failed during read',\r\n {\r\n expected: expectedChecksum,\r\n actual: checksum,\r\n filePath: absolutePath,\r\n }\r\n );\r\n }\r\n\r\n logger.debug('File read with checksum verification', {\r\n filePath: absolutePath,\r\n checksum,\r\n verified: !!expectedChecksum,\r\n });\r\n\r\n return { content, checksum };\r\n } catch (error) {\r\n throw createError(\r\n ErrorCode.FILE_READ_FAILED,\r\n `Failed to read file: ${absolutePath}`,\r\n { filePath: absolutePath },\r\n error instanceof Error ? error : undefined\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Verify file checksum\r\n *\r\n * @param filePath - File to verify\r\n * @param expectedChecksum - Expected SHA256 checksum\r\n * @returns Promise<boolean> - True if checksum matches\r\n */\r\n async verifyChecksum(filePath: string, expectedChecksum: string): Promise<boolean> {\r\n const absolutePath = path.resolve(filePath);\r\n\r\n try {\r\n const actualChecksum = await this.calculateFileChecksum(absolutePath);\r\n const matches = actualChecksum === expectedChecksum;\r\n\r\n logger.debug('Checksum verification', {\r\n filePath: absolutePath,\r\n expected: expectedChecksum,\r\n actual: actualChecksum,\r\n matches,\r\n });\r\n\r\n return matches;\r\n } catch (error) {\r\n logger.error(\r\n 'Checksum verification failed',\r\n error instanceof Error ? error : undefined,\r\n { filePath: absolutePath }\r\n );\r\n return false;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Singleton instance\r\n */\r\nlet defaultWriter: AtomicFileWriter | null = null;\r\n\r\n/**\r\n * Get the default atomic file writer instance\r\n */\r\nexport function getAtomicFileWriter(): AtomicFileWriter {\r\n if (!defaultWriter) {\r\n defaultWriter = new AtomicFileWriter();\r\n }\r\n return defaultWriter;\r\n}\r\n\r\n/**\r\n * Helper function for atomic writes\r\n *\r\n * @param filePath - Target file path\r\n * @param content - Content to write\r\n * @param options - Write options\r\n * @returns Promise<WriteResult> - Write result\r\n */\r\nexport async function atomicWriteFile(\r\n filePath: string,\r\n content: string | Buffer,\r\n options: WriteOptions = {}\r\n): Promise<WriteResult> {\r\n const writer = getAtomicFileWriter();\r\n return writer.writeFile(filePath, content, options);\r\n}\r\n\r\n/**\r\n * Helper function for atomic reads with checksum\r\n *\r\n * @param filePath - File to read\r\n * @param expectedChecksum - Optional expected checksum\r\n * @param encoding - File encoding\r\n * @returns Promise<{content: string, checksum: string}>\r\n */\r\nexport async function atomicReadFile(\r\n filePath: string,\r\n expectedChecksum?: string,\r\n encoding: BufferEncoding = 'utf8'\r\n): Promise<{ content: string; checksum: string }> {\r\n const writer = getAtomicFileWriter();\r\n return writer.readFile(filePath, expectedChecksum, encoding);\r\n}\r\n"],"names":["fs","path","crypto","promisify","randomUUID","createLogger","createError","ErrorCode","withFileLock","logger","fsWriteFile","writeFile","fsReadFile","readFile","fsRename","rename","fsUnlink","unlink","fsStat","stat","fsMkdir","mkdir","fsChmod","chmod","fsChown","chown","fsAccess","access","fsCopyFile","copyFile","AtomicFileWriter","filePath","content","options","startTime","Date","now","absolutePath","resolve","opts","encoding","createBackup","preservePermissions","preserveOwnership","verifyChecksum","useLock","lockOptions","backupDir","debug","contentLength","length","expectedChecksum","calculateChecksum","performWrite","dir","dirname","tempPath","join","basename","backupPath","originalMetadata","rolledBack","ensureDirectory","getFileMetadata","exists","info","original","backup","actualChecksum","calculateFileChecksum","CHECKSUM_MISMATCH","expected","actual","checksum","mode","toString","uid","gid","error","warn","Error","undefined","from","to","bytesWritten","size","durationMs","success","fileExists","target","rollbackError","FILE_WRITE_FAILED","hash","createHash","update","digest","Promise","reject","stream","createReadStream","on","chunk","stats","process","getuid","getgid","timestamp","toISOString","replace","targetDir","BACKUP_FAILED","constants","F_OK","dirPath","recursive","code","verified","FILE_READ_FAILED","matches","defaultWriter","getAtomicFileWriter","atomicWriteFile","writer","atomicReadFile"],"mappings":"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"}
|