@howlil/ez-agents 3.5.0 → 4.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/README.md +735 -537
- package/agents/ez-architect-agent.md +267 -0
- package/agents/ez-backend-agent.md +303 -0
- package/agents/ez-chief-strategist.md +271 -0
- package/agents/ez-codebase-mapper.md +770 -770
- package/agents/ez-context-manager.md +319 -0
- package/agents/ez-debugger.md +1255 -1255
- package/agents/ez-design-expert.md +347 -0
- package/agents/ez-devops-agent.md +331 -0
- package/agents/ez-executor.md +487 -487
- package/agents/ez-frontend-agent.md +322 -0
- package/agents/ez-phase-researcher.md +553 -553
- package/agents/ez-planner.md +1307 -1307
- package/agents/ez-product-engineer.md +435 -0
- package/agents/ez-project-researcher.md +629 -629
- package/agents/ez-qa-agent.md +320 -0
- package/agents/ez-release-agent.md +333 -333
- package/agents/ez-requirements-agent.md +377 -377
- package/agents/ez-roadmapper.md +650 -650
- package/agents/ez-technical-writer.md +551 -0
- package/agents/ez-ux-expert.md +393 -0
- package/agents/ez-verifier.md +579 -579
- package/bin/guards/autonomy-guard.cjs +346 -0
- package/bin/guards/context-budget-guard.cjs +278 -0
- package/bin/guards/hallucination-guard.cjs +380 -0
- package/bin/guards/hidden-state-guard.cjs +182 -0
- package/bin/guards/team-overhead-guard.cjs +266 -0
- package/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/bin/lib/archetype-detector.cjs +289 -0
- package/bin/lib/assistant-adapter.cjs +361 -0
- package/bin/lib/audit-exec.cjs +175 -0
- package/bin/lib/auth.cjs +176 -0
- package/bin/lib/backup-service.cjs +422 -0
- package/bin/lib/bdd-validator.cjs +622 -0
- package/bin/lib/business-flow-mapper.cjs +429 -0
- package/bin/lib/circuit-breaker.cjs +276 -0
- package/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/bin/lib/codebase-analyzer.cjs +241 -0
- package/bin/lib/commands.cjs +691 -0
- package/bin/lib/config.cjs +236 -0
- package/bin/lib/constraint-extractor.cjs +526 -0
- package/bin/lib/content-scanner.cjs +238 -0
- package/bin/lib/context-cache.cjs +154 -0
- package/bin/lib/context-compressor.cjs +102 -0
- package/bin/lib/context-deduplicator.cjs +105 -0
- package/bin/lib/context-errors.cjs +78 -0
- package/bin/lib/context-manager.cjs +338 -0
- package/bin/lib/context-metadata-tracker.cjs +140 -0
- package/bin/lib/context-relevance-scorer.cjs +99 -0
- package/bin/lib/core.cjs +507 -0
- package/bin/lib/cost-alerts.cjs +174 -0
- package/bin/lib/cost-tracker.cjs +275 -0
- package/bin/lib/crash-recovery.cjs +220 -0
- package/bin/lib/dependency-graph.cjs +319 -0
- package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/bin/lib/deploy/deploy-status.cjs +74 -0
- package/bin/lib/discussion-synthesizer.cjs +439 -0
- package/bin/lib/error-cache.cjs +114 -0
- package/bin/lib/error-registry.cjs +177 -0
- package/bin/lib/file-access.cjs +207 -0
- package/bin/lib/file-lock.cjs +236 -0
- package/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/bin/lib/finops/cost-reporter.cjs +132 -0
- package/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/bin/lib/finops/spot-manager.cjs +118 -0
- package/bin/lib/framework-detector.cjs +396 -0
- package/bin/lib/frontmatter.cjs +313 -0
- package/bin/lib/fs-utils.cjs +153 -0
- package/bin/lib/gate-executor.cjs +272 -0
- package/bin/lib/gates/README.md +374 -0
- package/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/bin/lib/gates/gate-03-code.cjs +635 -0
- package/bin/lib/gates/gate-04-security.cjs +829 -0
- package/bin/lib/git-errors.cjs +83 -0
- package/bin/lib/git-utils.cjs +321 -0
- package/bin/lib/git-workflow-engine.cjs +1157 -0
- package/bin/lib/health-check.cjs +227 -0
- package/bin/lib/index.cjs +279 -0
- package/bin/lib/init.cjs +725 -0
- package/bin/lib/lock-logger.cjs +194 -0
- package/bin/lib/lock-state.cjs +263 -0
- package/bin/lib/lockfile-validator.cjs +227 -0
- package/bin/lib/log-rotation.cjs +71 -0
- package/bin/lib/logger.cjs +125 -0
- package/bin/lib/memory-compression.cjs +256 -0
- package/bin/lib/milestone.cjs +247 -0
- package/bin/lib/model-provider.cjs +241 -0
- package/bin/lib/package-manager-detector.cjs +203 -0
- package/bin/lib/package-manager-executor.cjs +385 -0
- package/bin/lib/package-manager-service.cjs +216 -0
- package/bin/lib/perf/api-monitor.cjs +88 -0
- package/bin/lib/perf/db-optimizer.cjs +78 -0
- package/bin/lib/perf/frontend-performance.cjs +56 -0
- package/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/bin/lib/perf/perf-baseline.cjs +102 -0
- package/bin/lib/perf/perf-reporter.cjs +117 -0
- package/bin/lib/perf/regression-detector.cjs +92 -0
- package/bin/lib/phase.cjs +963 -0
- package/bin/lib/planning-write.cjs +123 -0
- package/bin/lib/project-reporter.cjs +565 -0
- package/bin/lib/quality-gate.cjs +332 -0
- package/bin/lib/quality-metrics.cjs +324 -0
- package/bin/lib/recovery-manager.cjs +98 -0
- package/bin/lib/release-validator.cjs +617 -0
- package/bin/lib/retry.cjs +119 -0
- package/bin/lib/roadmap.cjs +309 -0
- package/bin/lib/safe-exec.cjs +173 -0
- package/bin/lib/safe-path.cjs +130 -0
- package/bin/lib/security-errors.cjs +62 -0
- package/bin/lib/session-chain.cjs +304 -0
- package/bin/lib/session-errors.cjs +81 -0
- package/bin/lib/session-export.cjs +251 -0
- package/bin/lib/session-import.cjs +262 -0
- package/bin/lib/session-manager.cjs +280 -0
- package/bin/lib/skill-context.cjs +148 -0
- package/bin/lib/skill-matcher.cjs +236 -0
- package/bin/lib/skill-registry.cjs +360 -0
- package/bin/lib/skill-resolver.cjs +449 -0
- package/bin/lib/skill-triggers.cjs +90 -0
- package/bin/lib/skill-validator.cjs +270 -0
- package/bin/lib/skill-versioning.cjs +355 -0
- package/bin/lib/stack-detector.cjs +399 -0
- package/bin/lib/state.cjs +736 -0
- package/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/bin/lib/temp-file.cjs +239 -0
- package/bin/lib/template.cjs +223 -0
- package/bin/lib/test-file-lock.cjs +112 -0
- package/bin/lib/test-graceful.cjs +93 -0
- package/bin/lib/test-logger.cjs +60 -0
- package/bin/lib/test-safe-exec.cjs +38 -0
- package/bin/lib/test-safe-path.cjs +33 -0
- package/bin/lib/test-temp-file.cjs +125 -0
- package/bin/lib/tier-manager.cjs +428 -0
- package/bin/lib/timeout-exec.cjs +63 -0
- package/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/bin/lib/url-fetch.cjs +170 -0
- package/bin/lib/verify.cjs +863 -0
- package/bin/update.js +217 -214
- package/commands/deploy.cjs +53 -0
- package/commands/ez/add-tests.md +41 -41
- package/commands/ez/audit-milestone.md +36 -36
- package/commands/ez/complete-milestone.md +136 -136
- package/commands/ez/discuss-phase.md +90 -90
- package/commands/ez/execute-phase.md +52 -52
- package/commands/ez/help.md +22 -22
- package/commands/ez/map-codebase.md +71 -71
- package/commands/ez/new-milestone.md +44 -44
- package/commands/ez/new-project.md +51 -42
- package/commands/ez/plan-phase.md +53 -53
- package/commands/ez/progress.md +36 -36
- package/commands/ez/quick.md +45 -45
- package/commands/ez/resume-work.md +40 -40
- package/commands/ez/run-phase.md +580 -0
- package/commands/ez/settings.md +36 -36
- package/commands/ez/update.md +37 -37
- package/commands/ez/verify-work.md +402 -38
- package/commands/health-check.cjs +44 -0
- package/commands/rollback.cjs +47 -0
- package/ez-agents/bin/ez-tools.cjs +599 -2
- package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
- package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
- package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
- package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
- package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
- package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
- package/ez-agents/bin/lib/audit-exec.cjs +166 -167
- package/ez-agents/bin/lib/auth.cjs +176 -176
- package/ez-agents/bin/lib/backup-service.cjs +422 -0
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -622
- package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
- package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
- package/ez-agents/bin/lib/commands.cjs +685 -685
- package/ez-agents/bin/lib/config.cjs +41 -1
- package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -238
- package/ez-agents/bin/lib/context-cache.cjs +154 -154
- package/ez-agents/bin/lib/context-errors.cjs +71 -71
- package/ez-agents/bin/lib/context-manager.cjs +220 -220
- package/ez-agents/bin/lib/core.cjs +507 -512
- package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
- package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
- package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
- package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -207
- package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
- package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
- package/ez-agents/bin/lib/framework-detector.cjs +396 -0
- package/ez-agents/bin/lib/frontmatter.cjs +3 -1
- package/ez-agents/bin/lib/gates/README.md +374 -0
- package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
- package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -83
- package/ez-agents/bin/lib/git-utils.cjs +321 -321
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -1157
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +2 -8
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -227
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +22 -47
- package/ez-agents/bin/lib/memory-compression.cjs +256 -256
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -203
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -385
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -216
- package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
- package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
- package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
- package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
- package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
- package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
- package/ez-agents/bin/lib/project-reporter.cjs +502 -0
- package/ez-agents/bin/lib/quality-gate.cjs +332 -0
- package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
- package/ez-agents/bin/lib/release-validator.cjs +617 -614
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -304
- package/ez-agents/bin/lib/session-errors.cjs +81 -81
- package/ez-agents/bin/lib/session-export.cjs +251 -251
- package/ez-agents/bin/lib/session-import.cjs +262 -262
- package/ez-agents/bin/lib/session-manager.cjs +280 -280
- package/ez-agents/bin/lib/skill-context.cjs +148 -0
- package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
- package/ez-agents/bin/lib/skill-registry.cjs +341 -0
- package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
- package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
- package/ez-agents/bin/lib/skill-validator.cjs +270 -0
- package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
- package/ez-agents/bin/lib/stack-detector.cjs +399 -0
- package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -428
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -170
- package/ez-agents/bin/lib/verify.cjs +863 -863
- package/ez-agents/references/decimal-phase-calculation.md +65 -65
- package/ez-agents/references/git-integration.md +248 -248
- package/ez-agents/references/git-planning-commit.md +38 -38
- package/ez-agents/references/metrics-schema.md +118 -118
- package/ez-agents/references/model-profile-resolution.md +34 -34
- package/ez-agents/references/model-profiles.md +93 -93
- package/ez-agents/references/phase-argument-parsing.md +61 -61
- package/ez-agents/references/planning-config.md +340 -340
- package/ez-agents/references/tier-strategy.md +103 -103
- package/ez-agents/references/ui-brand.md +160 -160
- package/ez-agents/references/verification-patterns.md +612 -612
- package/ez-agents/templates/DEBUG.md +164 -164
- package/ez-agents/templates/UAT.md +247 -247
- package/ez-agents/templates/agent-output-format.md +404 -0
- package/ez-agents/templates/bdd-feature.md +173 -173
- package/ez-agents/templates/codebase/architecture.md +255 -255
- package/ez-agents/templates/codebase/structure.md +285 -285
- package/ez-agents/templates/copilot-instructions.md +7 -7
- package/ez-agents/templates/debug-subagent-prompt.md +91 -91
- package/ez-agents/templates/discovery.md +146 -146
- package/ez-agents/templates/discussion.md +68 -68
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -205
- package/ez-agents/templates/mode-workflow-templates.md +301 -0
- package/ez-agents/templates/phase-prompt.md +610 -610
- package/ez-agents/templates/planner-subagent-prompt.md +117 -117
- package/ez-agents/templates/project.md +184 -184
- package/ez-agents/templates/release-checklist.md +136 -133
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -201
- package/ez-agents/templates/security-user-setup.md +244 -0
- package/ez-agents/templates/skill-validation-rules.md +476 -0
- package/ez-agents/templates/state.md +180 -176
- package/ez-agents/templates/summary-complex.md +59 -59
- package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
- package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
- package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
- package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
- package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
- package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
- package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
- package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
- package/ez-agents/workflows/audit-milestone.md +1 -1
- package/ez-agents/workflows/autonomous.md +844 -844
- package/ez-agents/workflows/complete-milestone.md +1 -1
- package/ez-agents/workflows/discuss-phase.md +1 -1
- package/ez-agents/workflows/execute-phase.md +124 -3
- package/ez-agents/workflows/help.md +42 -181
- package/ez-agents/workflows/hotfix.md +291 -291
- package/ez-agents/workflows/new-milestone.md +713 -713
- package/ez-agents/workflows/new-project.md +1089 -1107
- package/ez-agents/workflows/plan-phase.md +0 -40
- package/ez-agents/workflows/release.md +253 -253
- package/ez-agents/workflows/resume-session.md +215 -215
- package/ez-agents/workflows/run-phase.md +531 -0
- package/ez-agents/workflows/settings.md +2 -35
- package/hooks/dist/ez-check-update.js +81 -81
- package/hooks/dist/ez-context-monitor.js +148 -141
- package/hooks/dist/ez-statusline.js +115 -115
- package/package.json +78 -71
- package/scripts/fix-qwen-installation.js +144 -144
- package/agents/ez-integration-checker.md +0 -443
- package/agents/ez-nyquist-auditor.md +0 -176
- package/agents/ez-observer-agent.md +0 -260
- package/agents/ez-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- package/agents/ez-scrum-master-agent.md +0 -242
- package/agents/ez-tech-lead-agent.md +0 -267
- package/agents/ez-ui-auditor.md +0 -439
- package/agents/ez-ui-checker.md +0 -300
- package/agents/ez-ui-researcher.md +0 -353
- package/commands/ez/add-phase.md +0 -43
- package/commands/ez/add-todo.md +0 -47
- package/commands/ez/arch-review.md +0 -102
- package/commands/ez/auth.md +0 -87
- package/commands/ez/autonomous.md +0 -41
- package/commands/ez/check-todos.md +0 -45
- package/commands/ez/cleanup.md +0 -18
- package/commands/ez/debug.md +0 -168
- package/commands/ez/export-session.md +0 -79
- package/commands/ez/gather-requirements.md +0 -117
- package/commands/ez/git-workflow.md +0 -72
- package/commands/ez/health.md +0 -22
- package/commands/ez/hotfix.md +0 -120
- package/commands/ez/import-session.md +0 -82
- package/commands/ez/insert-phase.md +0 -32
- package/commands/ez/join-discord.md +0 -18
- package/commands/ez/list-phase-assumptions.md +0 -46
- package/commands/ez/list-sessions.md +0 -96
- package/commands/ez/package-manager.md +0 -316
- package/commands/ez/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/preflight.md +0 -79
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/release.md +0 -153
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/resume.md +0 -107
- package/commands/ez/set-profile.md +0 -34
- package/commands/ez/standup.md +0 -85
- package/commands/ez/stats.md +0 -18
- package/commands/ez/ui-phase.md +0 -34
- package/commands/ez/ui-review.md +0 -32
- package/commands/ez/validate-phase.md +0 -35
- package/ez-agents/bin/lib/metrics-tracker.cjs +0 -406
- package/ez-agents/templates/UI-SPEC.md +0 -100
- package/ez-agents/templates/VALIDATION.md +0 -76
- package/ez-agents/templates/context.md +0 -352
- package/ez-agents/templates/verification-report.md +0 -322
- package/ez-agents/workflows/arch-review.md +0 -54
- package/ez-agents/workflows/export-session.md +0 -255
- package/ez-agents/workflows/gather-requirements.md +0 -206
- package/ez-agents/workflows/import-session.md +0 -303
- package/ez-agents/workflows/research-phase.md +0 -74
- package/ez-agents/workflows/standup.md +0 -64
- package/ez-agents/workflows/ui-phase.md +0 -290
- package/ez-agents/workflows/ui-review.md +0 -157
- package/ez-agents/workflows/validate-phase.md +0 -167
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Security Operations Error Classes
|
|
5
|
+
*
|
|
6
|
+
* Provides structured error handling for security operations
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
class SecurityOpsError extends Error {
|
|
10
|
+
constructor(message, context = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'SecurityOpsError';
|
|
13
|
+
this.context = context;
|
|
14
|
+
this.timestamp = new Date().toISOString();
|
|
15
|
+
Error.captureStackTrace(this, SecurityOpsError);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
toJSON() {
|
|
19
|
+
return {
|
|
20
|
+
name: this.name,
|
|
21
|
+
message: this.message,
|
|
22
|
+
context: this.context,
|
|
23
|
+
timestamp: this.timestamp
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class SecurityScanError extends SecurityOpsError {
|
|
29
|
+
constructor(message, context = {}) {
|
|
30
|
+
super(message, context);
|
|
31
|
+
this.name = 'SecurityScanError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class SecurityProviderError extends SecurityOpsError {
|
|
36
|
+
constructor(message, context = {}) {
|
|
37
|
+
super(message, context);
|
|
38
|
+
this.name = 'SecurityProviderError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class SecurityComplianceError extends SecurityOpsError {
|
|
43
|
+
constructor(message, context = {}) {
|
|
44
|
+
super(message, context);
|
|
45
|
+
this.name = 'SecurityComplianceError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class SecurityAuditError extends SecurityOpsError {
|
|
50
|
+
constructor(message, context = {}) {
|
|
51
|
+
super(message, context);
|
|
52
|
+
this.name = 'SecurityAuditError';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
SecurityOpsError,
|
|
58
|
+
SecurityScanError,
|
|
59
|
+
SecurityProviderError,
|
|
60
|
+
SecurityComplianceError,
|
|
61
|
+
SecurityAuditError
|
|
62
|
+
};
|
|
@@ -1,304 +1,304 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Session Chain — Navigate linked sessions
|
|
5
|
-
*
|
|
6
|
-
* Provides chain navigation, visualization, and repair capabilities
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const { SessionChainError } = require('./session-errors.cjs');
|
|
12
|
-
const { defaultLogger: logger } = require('./logger.cjs');
|
|
13
|
-
|
|
14
|
-
class SessionChain {
|
|
15
|
-
/**
|
|
16
|
-
* Create a SessionChain instance
|
|
17
|
-
* @param {Object} sessionManager - SessionManager instance
|
|
18
|
-
*/
|
|
19
|
-
constructor(sessionManager) {
|
|
20
|
-
this.sessionManager = sessionManager;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Navigate to adjacent session in chain
|
|
25
|
-
* @param {string} sessionId - Current session ID
|
|
26
|
-
* @param {string} direction - Navigation direction ('previous' or 'next')
|
|
27
|
-
* @returns {Object|null} Adjacent session or null
|
|
28
|
-
*/
|
|
29
|
-
navigate(sessionId, direction) {
|
|
30
|
-
const session = this.sessionManager.loadSession(sessionId);
|
|
31
|
-
if (!session) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const chain = session.metadata?.session_chain || [];
|
|
36
|
-
const currentIndex = chain.indexOf(sessionId);
|
|
37
|
-
|
|
38
|
-
if (currentIndex === -1) {
|
|
39
|
-
// Session not in chain, check if it's the last one
|
|
40
|
-
logger.warn('Session not in chain', { sessionId });
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (direction === 'previous') {
|
|
45
|
-
if (currentIndex > 0) {
|
|
46
|
-
const previousId = chain[currentIndex - 1];
|
|
47
|
-
return this.sessionManager.loadSession(previousId);
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (direction === 'next') {
|
|
53
|
-
if (currentIndex < chain.length - 1) {
|
|
54
|
-
const nextId = chain[currentIndex + 1];
|
|
55
|
-
return this.sessionManager.loadSession(nextId);
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
throw new SessionChainError(`Invalid direction: ${direction}`, chain);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Get full chain as array of session objects
|
|
65
|
-
* @param {string} sessionId - Session ID in the chain
|
|
66
|
-
* @returns {Array} Array of session objects
|
|
67
|
-
*/
|
|
68
|
-
getChain(sessionId) {
|
|
69
|
-
const session = this.sessionManager.loadSession(sessionId);
|
|
70
|
-
if (!session) {
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const chain = session.metadata?.session_chain || [];
|
|
75
|
-
const chainSessions = [];
|
|
76
|
-
|
|
77
|
-
for (const id of chain) {
|
|
78
|
-
const chainSession = this.sessionManager.loadSession(id);
|
|
79
|
-
if (chainSession) {
|
|
80
|
-
chainSessions.push(chainSession);
|
|
81
|
-
} else {
|
|
82
|
-
logger.warn('Missing session in chain', { id });
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Include current session if not already in chain
|
|
87
|
-
if (!chain.includes(sessionId)) {
|
|
88
|
-
chainSessions.push(session);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return chainSessions;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get chain visualization string
|
|
96
|
-
* @param {string} sessionId - Session ID
|
|
97
|
-
* @returns {string} Formatted chain visualization
|
|
98
|
-
*/
|
|
99
|
-
getChainVisualization(sessionId) {
|
|
100
|
-
const session = this.sessionManager.loadSession(sessionId);
|
|
101
|
-
if (!session) {
|
|
102
|
-
return `Session not found: ${sessionId}`;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const chain = session.metadata?.session_chain || [];
|
|
106
|
-
const currentIndex = chain.indexOf(sessionId);
|
|
107
|
-
|
|
108
|
-
let viz = `Session Chain for ${sessionId}:\n\n`;
|
|
109
|
-
|
|
110
|
-
chain.forEach((id, index) => {
|
|
111
|
-
const chainSession = this.sessionManager.loadSession(id);
|
|
112
|
-
const startedAt = chainSession?.metadata?.started_at || 'Unknown';
|
|
113
|
-
const status = chainSession?.metadata?.status || 'unknown';
|
|
114
|
-
const marker = index === currentIndex ? ' <-- Current' : '';
|
|
115
|
-
viz += `[${index + 1}] ${id} (${startedAt}) - ${status}${marker}\n`;
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (!chain.includes(sessionId)) {
|
|
119
|
-
const startedAt = session.metadata?.started_at || 'Unknown';
|
|
120
|
-
const status = session.metadata?.status || 'unknown';
|
|
121
|
-
viz += `[${chain.length + 1}] ${sessionId} (${startedAt}) - ${status} <-- Current\n`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
viz += `\nNavigation:\n`;
|
|
125
|
-
if (currentIndex > 0) {
|
|
126
|
-
viz += `- Previous: ${chain[currentIndex - 1]}\n`;
|
|
127
|
-
} else {
|
|
128
|
-
viz += `- Previous: none\n`;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (currentIndex < chain.length - 1) {
|
|
132
|
-
viz += `- Next: ${chain[currentIndex + 1]}\n`;
|
|
133
|
-
} else {
|
|
134
|
-
viz += `- Next: none\n`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return viz;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Repair broken chain links
|
|
142
|
-
* @param {string} sessionId - Session ID
|
|
143
|
-
* @returns {Object} Repair result with warnings
|
|
144
|
-
*/
|
|
145
|
-
repairChain(sessionId) {
|
|
146
|
-
const session = this.sessionManager.loadSession(sessionId);
|
|
147
|
-
if (!session) {
|
|
148
|
-
throw new SessionChainError(`Session not found: ${sessionId}`, []);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const chain = session.metadata?.session_chain || [];
|
|
152
|
-
const warnings = [];
|
|
153
|
-
const repaired = [];
|
|
154
|
-
|
|
155
|
-
// Get all available sessions
|
|
156
|
-
const allSessions = this.sessionManager.listSessions();
|
|
157
|
-
const availableIds = new Set(allSessions.map(s => s.session_id));
|
|
158
|
-
|
|
159
|
-
// Find missing links
|
|
160
|
-
const missingLinks = [];
|
|
161
|
-
for (const id of chain) {
|
|
162
|
-
if (!availableIds.has(id)) {
|
|
163
|
-
missingLinks.push(id);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (missingLinks.length === 0) {
|
|
168
|
-
return { repaired: false, warnings: ['Chain is intact'] };
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Attempt to repair by finding closest timestamp match
|
|
172
|
-
for (const missingId of missingLinks) {
|
|
173
|
-
const match = this._findClosestSessionMatch(missingId, allSessions);
|
|
174
|
-
if (match) {
|
|
175
|
-
logger.info('Auto-repaired chain link', { missing: missingId, found: match.session_id });
|
|
176
|
-
repaired.push({ missing: missingId, found: match.session_id });
|
|
177
|
-
} else {
|
|
178
|
-
warnings.push(`Unrecoverable link: ${missingId}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Update chain with repaired links
|
|
183
|
-
if (repaired.length > 0) {
|
|
184
|
-
const newChain = chain.map(id => {
|
|
185
|
-
const repair = repaired.find(r => r.missing === id);
|
|
186
|
-
return repair ? repair.found : id;
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
this.sessionManager.updateSession(sessionId, {
|
|
190
|
-
metadata: { session_chain: newChain }
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
repaired: repaired.length > 0,
|
|
196
|
-
repairs: repaired,
|
|
197
|
-
warnings
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Find closest session match by timestamp
|
|
203
|
-
* @private
|
|
204
|
-
*/
|
|
205
|
-
_findClosestSessionMatch(missingId, allSessions) {
|
|
206
|
-
// Extract timestamp from missing ID
|
|
207
|
-
const timestampMatch = missingId.match(/session-(.+)/);
|
|
208
|
-
if (!timestampMatch) {
|
|
209
|
-
return null;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const missingTimestamp = timestampMatch[1];
|
|
213
|
-
|
|
214
|
-
// Find session with closest timestamp
|
|
215
|
-
let closestMatch = null;
|
|
216
|
-
let minDiff = Infinity;
|
|
217
|
-
|
|
218
|
-
for (const session of allSessions) {
|
|
219
|
-
const sessionTimestamp = session.session_id.replace('session-', '');
|
|
220
|
-
const diff = this._compareTimestamps(missingTimestamp, sessionTimestamp);
|
|
221
|
-
|
|
222
|
-
if (diff < minDiff) {
|
|
223
|
-
minDiff = diff;
|
|
224
|
-
closestMatch = session;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Only return match if within reasonable threshold (1 hour)
|
|
229
|
-
if (minDiff < 3600000) {
|
|
230
|
-
return closestMatch;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Compare timestamps and return difference in ms
|
|
238
|
-
* @private
|
|
239
|
-
*/
|
|
240
|
-
_compareTimestamps(ts1, ts2) {
|
|
241
|
-
try {
|
|
242
|
-
const date1 = new Date(ts1.replace(/-/g, ':').replace('T', ' '));
|
|
243
|
-
const date2 = new Date(ts2.replace(/-/g, ':').replace('T', ' '));
|
|
244
|
-
return Math.abs(date1 - date2);
|
|
245
|
-
} catch {
|
|
246
|
-
return Infinity;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Add session to chain
|
|
252
|
-
* @param {string} sessionId - Session ID to add to
|
|
253
|
-
* @param {string} linkedSessionId - Session ID to link
|
|
254
|
-
* @param {string} position - Position ('before' or 'after')
|
|
255
|
-
* @returns {boolean} Success
|
|
256
|
-
*/
|
|
257
|
-
addToChain(sessionId, linkedSessionId, position = 'after') {
|
|
258
|
-
const session = this.sessionManager.loadSession(sessionId);
|
|
259
|
-
if (!session) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const linkedSession = this.sessionManager.loadSession(linkedSessionId);
|
|
264
|
-
if (!linkedSession) {
|
|
265
|
-
return false;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
let chain = session.metadata?.session_chain || [];
|
|
269
|
-
|
|
270
|
-
// Ensure current session is in chain
|
|
271
|
-
if (!chain.includes(sessionId)) {
|
|
272
|
-
chain.push(sessionId);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const currentIndex = chain.indexOf(sessionId);
|
|
276
|
-
|
|
277
|
-
if (position === 'after') {
|
|
278
|
-
// Insert after current
|
|
279
|
-
chain.splice(currentIndex + 1, 0, linkedSessionId);
|
|
280
|
-
} else if (position === 'before') {
|
|
281
|
-
// Insert before current
|
|
282
|
-
chain.splice(currentIndex, 0, linkedSessionId);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Update both sessions
|
|
286
|
-
this.sessionManager.updateSession(sessionId, {
|
|
287
|
-
metadata: { session_chain: chain }
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
// Also update linked session's chain
|
|
291
|
-
const linkedChain = linkedSession.metadata?.session_chain || [];
|
|
292
|
-
if (!linkedChain.includes(sessionId)) {
|
|
293
|
-
linkedChain.push(sessionId);
|
|
294
|
-
this.sessionManager.updateSession(linkedSessionId, {
|
|
295
|
-
metadata: { session_chain: linkedChain }
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
logger.info('Session added to chain', { sessionId, linkedSessionId, position });
|
|
300
|
-
return true;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
module.exports = SessionChain;
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session Chain — Navigate linked sessions
|
|
5
|
+
*
|
|
6
|
+
* Provides chain navigation, visualization, and repair capabilities
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { SessionChainError } = require('./session-errors.cjs');
|
|
12
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
13
|
+
|
|
14
|
+
class SessionChain {
|
|
15
|
+
/**
|
|
16
|
+
* Create a SessionChain instance
|
|
17
|
+
* @param {Object} sessionManager - SessionManager instance
|
|
18
|
+
*/
|
|
19
|
+
constructor(sessionManager) {
|
|
20
|
+
this.sessionManager = sessionManager;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Navigate to adjacent session in chain
|
|
25
|
+
* @param {string} sessionId - Current session ID
|
|
26
|
+
* @param {string} direction - Navigation direction ('previous' or 'next')
|
|
27
|
+
* @returns {Object|null} Adjacent session or null
|
|
28
|
+
*/
|
|
29
|
+
navigate(sessionId, direction) {
|
|
30
|
+
const session = this.sessionManager.loadSession(sessionId);
|
|
31
|
+
if (!session) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const chain = session.metadata?.session_chain || [];
|
|
36
|
+
const currentIndex = chain.indexOf(sessionId);
|
|
37
|
+
|
|
38
|
+
if (currentIndex === -1) {
|
|
39
|
+
// Session not in chain, check if it's the last one
|
|
40
|
+
logger.warn('Session not in chain', { sessionId });
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (direction === 'previous') {
|
|
45
|
+
if (currentIndex > 0) {
|
|
46
|
+
const previousId = chain[currentIndex - 1];
|
|
47
|
+
return this.sessionManager.loadSession(previousId);
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (direction === 'next') {
|
|
53
|
+
if (currentIndex < chain.length - 1) {
|
|
54
|
+
const nextId = chain[currentIndex + 1];
|
|
55
|
+
return this.sessionManager.loadSession(nextId);
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throw new SessionChainError(`Invalid direction: ${direction}`, chain);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get full chain as array of session objects
|
|
65
|
+
* @param {string} sessionId - Session ID in the chain
|
|
66
|
+
* @returns {Array} Array of session objects
|
|
67
|
+
*/
|
|
68
|
+
getChain(sessionId) {
|
|
69
|
+
const session = this.sessionManager.loadSession(sessionId);
|
|
70
|
+
if (!session) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const chain = session.metadata?.session_chain || [];
|
|
75
|
+
const chainSessions = [];
|
|
76
|
+
|
|
77
|
+
for (const id of chain) {
|
|
78
|
+
const chainSession = this.sessionManager.loadSession(id);
|
|
79
|
+
if (chainSession) {
|
|
80
|
+
chainSessions.push(chainSession);
|
|
81
|
+
} else {
|
|
82
|
+
logger.warn('Missing session in chain', { id });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Include current session if not already in chain
|
|
87
|
+
if (!chain.includes(sessionId)) {
|
|
88
|
+
chainSessions.push(session);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return chainSessions;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get chain visualization string
|
|
96
|
+
* @param {string} sessionId - Session ID
|
|
97
|
+
* @returns {string} Formatted chain visualization
|
|
98
|
+
*/
|
|
99
|
+
getChainVisualization(sessionId) {
|
|
100
|
+
const session = this.sessionManager.loadSession(sessionId);
|
|
101
|
+
if (!session) {
|
|
102
|
+
return `Session not found: ${sessionId}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const chain = session.metadata?.session_chain || [];
|
|
106
|
+
const currentIndex = chain.indexOf(sessionId);
|
|
107
|
+
|
|
108
|
+
let viz = `Session Chain for ${sessionId}:\n\n`;
|
|
109
|
+
|
|
110
|
+
chain.forEach((id, index) => {
|
|
111
|
+
const chainSession = this.sessionManager.loadSession(id);
|
|
112
|
+
const startedAt = chainSession?.metadata?.started_at || 'Unknown';
|
|
113
|
+
const status = chainSession?.metadata?.status || 'unknown';
|
|
114
|
+
const marker = index === currentIndex ? ' <-- Current' : '';
|
|
115
|
+
viz += `[${index + 1}] ${id} (${startedAt}) - ${status}${marker}\n`;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!chain.includes(sessionId)) {
|
|
119
|
+
const startedAt = session.metadata?.started_at || 'Unknown';
|
|
120
|
+
const status = session.metadata?.status || 'unknown';
|
|
121
|
+
viz += `[${chain.length + 1}] ${sessionId} (${startedAt}) - ${status} <-- Current\n`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
viz += `\nNavigation:\n`;
|
|
125
|
+
if (currentIndex > 0) {
|
|
126
|
+
viz += `- Previous: ${chain[currentIndex - 1]}\n`;
|
|
127
|
+
} else {
|
|
128
|
+
viz += `- Previous: none\n`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (currentIndex < chain.length - 1) {
|
|
132
|
+
viz += `- Next: ${chain[currentIndex + 1]}\n`;
|
|
133
|
+
} else {
|
|
134
|
+
viz += `- Next: none\n`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return viz;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Repair broken chain links
|
|
142
|
+
* @param {string} sessionId - Session ID
|
|
143
|
+
* @returns {Object} Repair result with warnings
|
|
144
|
+
*/
|
|
145
|
+
repairChain(sessionId) {
|
|
146
|
+
const session = this.sessionManager.loadSession(sessionId);
|
|
147
|
+
if (!session) {
|
|
148
|
+
throw new SessionChainError(`Session not found: ${sessionId}`, []);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const chain = session.metadata?.session_chain || [];
|
|
152
|
+
const warnings = [];
|
|
153
|
+
const repaired = [];
|
|
154
|
+
|
|
155
|
+
// Get all available sessions
|
|
156
|
+
const allSessions = this.sessionManager.listSessions();
|
|
157
|
+
const availableIds = new Set(allSessions.map(s => s.session_id));
|
|
158
|
+
|
|
159
|
+
// Find missing links
|
|
160
|
+
const missingLinks = [];
|
|
161
|
+
for (const id of chain) {
|
|
162
|
+
if (!availableIds.has(id)) {
|
|
163
|
+
missingLinks.push(id);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (missingLinks.length === 0) {
|
|
168
|
+
return { repaired: false, warnings: ['Chain is intact'] };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Attempt to repair by finding closest timestamp match
|
|
172
|
+
for (const missingId of missingLinks) {
|
|
173
|
+
const match = this._findClosestSessionMatch(missingId, allSessions);
|
|
174
|
+
if (match) {
|
|
175
|
+
logger.info('Auto-repaired chain link', { missing: missingId, found: match.session_id });
|
|
176
|
+
repaired.push({ missing: missingId, found: match.session_id });
|
|
177
|
+
} else {
|
|
178
|
+
warnings.push(`Unrecoverable link: ${missingId}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Update chain with repaired links
|
|
183
|
+
if (repaired.length > 0) {
|
|
184
|
+
const newChain = chain.map(id => {
|
|
185
|
+
const repair = repaired.find(r => r.missing === id);
|
|
186
|
+
return repair ? repair.found : id;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
this.sessionManager.updateSession(sessionId, {
|
|
190
|
+
metadata: { session_chain: newChain }
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
repaired: repaired.length > 0,
|
|
196
|
+
repairs: repaired,
|
|
197
|
+
warnings
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Find closest session match by timestamp
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
_findClosestSessionMatch(missingId, allSessions) {
|
|
206
|
+
// Extract timestamp from missing ID
|
|
207
|
+
const timestampMatch = missingId.match(/session-(.+)/);
|
|
208
|
+
if (!timestampMatch) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const missingTimestamp = timestampMatch[1];
|
|
213
|
+
|
|
214
|
+
// Find session with closest timestamp
|
|
215
|
+
let closestMatch = null;
|
|
216
|
+
let minDiff = Infinity;
|
|
217
|
+
|
|
218
|
+
for (const session of allSessions) {
|
|
219
|
+
const sessionTimestamp = session.session_id.replace('session-', '');
|
|
220
|
+
const diff = this._compareTimestamps(missingTimestamp, sessionTimestamp);
|
|
221
|
+
|
|
222
|
+
if (diff < minDiff) {
|
|
223
|
+
minDiff = diff;
|
|
224
|
+
closestMatch = session;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Only return match if within reasonable threshold (1 hour)
|
|
229
|
+
if (minDiff < 3600000) {
|
|
230
|
+
return closestMatch;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Compare timestamps and return difference in ms
|
|
238
|
+
* @private
|
|
239
|
+
*/
|
|
240
|
+
_compareTimestamps(ts1, ts2) {
|
|
241
|
+
try {
|
|
242
|
+
const date1 = new Date(ts1.replace(/-/g, ':').replace('T', ' '));
|
|
243
|
+
const date2 = new Date(ts2.replace(/-/g, ':').replace('T', ' '));
|
|
244
|
+
return Math.abs(date1 - date2);
|
|
245
|
+
} catch {
|
|
246
|
+
return Infinity;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Add session to chain
|
|
252
|
+
* @param {string} sessionId - Session ID to add to
|
|
253
|
+
* @param {string} linkedSessionId - Session ID to link
|
|
254
|
+
* @param {string} position - Position ('before' or 'after')
|
|
255
|
+
* @returns {boolean} Success
|
|
256
|
+
*/
|
|
257
|
+
addToChain(sessionId, linkedSessionId, position = 'after') {
|
|
258
|
+
const session = this.sessionManager.loadSession(sessionId);
|
|
259
|
+
if (!session) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const linkedSession = this.sessionManager.loadSession(linkedSessionId);
|
|
264
|
+
if (!linkedSession) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let chain = session.metadata?.session_chain || [];
|
|
269
|
+
|
|
270
|
+
// Ensure current session is in chain
|
|
271
|
+
if (!chain.includes(sessionId)) {
|
|
272
|
+
chain.push(sessionId);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const currentIndex = chain.indexOf(sessionId);
|
|
276
|
+
|
|
277
|
+
if (position === 'after') {
|
|
278
|
+
// Insert after current
|
|
279
|
+
chain.splice(currentIndex + 1, 0, linkedSessionId);
|
|
280
|
+
} else if (position === 'before') {
|
|
281
|
+
// Insert before current
|
|
282
|
+
chain.splice(currentIndex, 0, linkedSessionId);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Update both sessions
|
|
286
|
+
this.sessionManager.updateSession(sessionId, {
|
|
287
|
+
metadata: { session_chain: chain }
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Also update linked session's chain
|
|
291
|
+
const linkedChain = linkedSession.metadata?.session_chain || [];
|
|
292
|
+
if (!linkedChain.includes(sessionId)) {
|
|
293
|
+
linkedChain.push(sessionId);
|
|
294
|
+
this.sessionManager.updateSession(linkedSessionId, {
|
|
295
|
+
metadata: { session_chain: linkedChain }
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
logger.info('Session added to chain', { sessionId, linkedSessionId, position });
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
module.exports = SessionChain;
|