@howlil/ez-agents 3.4.2 → 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 -462
- 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 -0
- package/agents/ez-requirements-agent.md +377 -0
- 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/install.js +3221 -3272
- 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 -41
- 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 -45
- package/commands/ez/progress.md +36 -24
- 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 +1692 -716
- 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 -0
- 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 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- 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/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- 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 -0
- package/ez-agents/bin/lib/git-utils.cjs +118 -0
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +40 -2
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +99 -154
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- 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 -0
- package/ez-agents/bin/lib/safe-exec.cjs +128 -214
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- 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 -0
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- 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 -0
- 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 -200
- package/ez-agents/references/tier-strategy.md +103 -0
- 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 -0
- 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 -0
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- 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 -0
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -0
- 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 +131 -30
- 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 +169 -3
- package/ez-agents/workflows/help.md +86 -133
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/new-milestone.md +340 -11
- package/ez-agents/workflows/new-project.md +294 -318
- package/ez-agents/workflows/plan-phase.md +22 -40
- package/ez-agents/workflows/progress.md +15 -25
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/resume-session.md +215 -0
- 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 -64
- 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-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- 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/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/health.md +0 -22
- 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/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/set-profile.md +0 -34
- 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/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/research-phase.md +0 -74
- 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,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Content Security Scanner
|
|
5
|
+
*
|
|
6
|
+
* Scans fetched content for XSS vectors, malicious scripts, and dangerous patterns.
|
|
7
|
+
* Detects script tags, JavaScript URLs, event handlers, and other security threats.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { SecurityScanError } = require('./context-errors.cjs');
|
|
11
|
+
|
|
12
|
+
class ContentSecurityScanner {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.maxSize = 1048576; // 1MB
|
|
15
|
+
|
|
16
|
+
// XSS detection patterns with severity levels
|
|
17
|
+
this.patterns = [
|
|
18
|
+
{
|
|
19
|
+
name: 'script_tag_open',
|
|
20
|
+
regex: /<script\b[^>]*>/gi,
|
|
21
|
+
severity: 'high',
|
|
22
|
+
description: 'Opening script tag'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'script_tag_close',
|
|
26
|
+
regex: /<\/script>/gi,
|
|
27
|
+
severity: 'high',
|
|
28
|
+
description: 'Closing script tag'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'javascript_url',
|
|
32
|
+
regex: /javascript\s*:/gi,
|
|
33
|
+
severity: 'high',
|
|
34
|
+
description: 'JavaScript URL protocol'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'vbscript_url',
|
|
38
|
+
regex: /vbscript\s*:/gi,
|
|
39
|
+
severity: 'high',
|
|
40
|
+
description: 'VBScript URL protocol'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'data_html_url',
|
|
44
|
+
regex: /data\s*:\s*text\/html/gi,
|
|
45
|
+
severity: 'high',
|
|
46
|
+
description: 'Data URL with HTML content'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'event_handler',
|
|
50
|
+
regex: /\bon\w+\s*=/gi,
|
|
51
|
+
severity: 'medium',
|
|
52
|
+
description: 'Event handler attribute'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'iframe_tag',
|
|
56
|
+
regex: /<iframe\b[^>]*>/gi,
|
|
57
|
+
severity: 'medium',
|
|
58
|
+
description: 'IFRAME tag'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'embed_tag',
|
|
62
|
+
regex: /<embed\b[^>]*>/gi,
|
|
63
|
+
severity: 'medium',
|
|
64
|
+
description: 'EMBED tag'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'object_tag',
|
|
68
|
+
regex: /<object\b[^>]*>/gi,
|
|
69
|
+
severity: 'medium',
|
|
70
|
+
description: 'OBJECT tag'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'svg_tag',
|
|
74
|
+
regex: /<svg\b[^>]*>/gi,
|
|
75
|
+
severity: 'medium',
|
|
76
|
+
description: 'SVG tag (potential XSS vector)'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'img_onerror',
|
|
80
|
+
regex: /<img[^>]*\s+onerror\s*=/gi,
|
|
81
|
+
severity: 'high',
|
|
82
|
+
description: 'IMG tag with onerror handler'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'expression_css',
|
|
86
|
+
regex: /expression\s*\(/gi,
|
|
87
|
+
severity: 'medium',
|
|
88
|
+
description: 'CSS expression (IE XSS vector)'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'eval_call',
|
|
92
|
+
regex: /\beval\s*\(/gi,
|
|
93
|
+
severity: 'high',
|
|
94
|
+
description: 'eval() call'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'document_cookie',
|
|
98
|
+
regex: /document\.cookie/gi,
|
|
99
|
+
severity: 'medium',
|
|
100
|
+
description: 'Document cookie access'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'window_location',
|
|
104
|
+
regex: /window\.location/gi,
|
|
105
|
+
severity: 'low',
|
|
106
|
+
description: 'Window location access'
|
|
107
|
+
}
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
// Binary content types to reject
|
|
111
|
+
this.binaryContentTypes = [
|
|
112
|
+
'application/octet-stream',
|
|
113
|
+
'image/',
|
|
114
|
+
'video/',
|
|
115
|
+
'audio/',
|
|
116
|
+
'application/pdf',
|
|
117
|
+
'application/zip',
|
|
118
|
+
'application/x-rar',
|
|
119
|
+
'application/x-executable'
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Scan content for security issues
|
|
125
|
+
* @param {string} content - The content to scan
|
|
126
|
+
* @param {string} contentType - Optional content type header
|
|
127
|
+
* @returns {{safe: boolean, findings: Array}} - Scan results
|
|
128
|
+
*/
|
|
129
|
+
scan(content, contentType = '') {
|
|
130
|
+
const findings = [];
|
|
131
|
+
|
|
132
|
+
// Check content size
|
|
133
|
+
if (content && content.length > this.maxSize) {
|
|
134
|
+
return {
|
|
135
|
+
safe: false,
|
|
136
|
+
findings: [{
|
|
137
|
+
type: 'size_limit',
|
|
138
|
+
severity: 'high',
|
|
139
|
+
description: `Content exceeds maximum size (${content.length} > ${this.maxSize} bytes)`,
|
|
140
|
+
pattern: null,
|
|
141
|
+
matches: []
|
|
142
|
+
}]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check for binary content types
|
|
147
|
+
if (contentType) {
|
|
148
|
+
const lowerContentType = contentType.toLowerCase();
|
|
149
|
+
for (const binaryType of this.binaryContentTypes) {
|
|
150
|
+
if (lowerContentType.includes(binaryType.toLowerCase())) {
|
|
151
|
+
return {
|
|
152
|
+
safe: false,
|
|
153
|
+
findings: [{
|
|
154
|
+
type: 'binary_content',
|
|
155
|
+
severity: 'high',
|
|
156
|
+
description: `Binary content type detected: ${contentType}`,
|
|
157
|
+
pattern: null,
|
|
158
|
+
matches: []
|
|
159
|
+
}]
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Scan for XSS patterns
|
|
166
|
+
if (content) {
|
|
167
|
+
for (const pattern of this.patterns) {
|
|
168
|
+
// Reset regex lastIndex
|
|
169
|
+
pattern.regex.lastIndex = 0;
|
|
170
|
+
|
|
171
|
+
const matches = [];
|
|
172
|
+
let match;
|
|
173
|
+
|
|
174
|
+
while ((match = pattern.regex.exec(content)) !== null) {
|
|
175
|
+
matches.push(match[0]);
|
|
176
|
+
// Limit matches to prevent memory issues
|
|
177
|
+
if (matches.length >= 5) {
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (matches.length > 0) {
|
|
183
|
+
findings.push({
|
|
184
|
+
type: pattern.name,
|
|
185
|
+
severity: pattern.severity,
|
|
186
|
+
description: pattern.description,
|
|
187
|
+
pattern: pattern.regex.toString(),
|
|
188
|
+
matches: [...new Set(matches)] // Deduplicate
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
safe: findings.length === 0,
|
|
196
|
+
findings
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get severity level for a pattern
|
|
202
|
+
* @param {string} patternName - The pattern name
|
|
203
|
+
* @returns {string} - 'high', 'medium', or 'low'
|
|
204
|
+
*/
|
|
205
|
+
getSeverity(patternName) {
|
|
206
|
+
const pattern = this.patterns.find(p => p.name === patternName);
|
|
207
|
+
if (!pattern) {
|
|
208
|
+
return 'low';
|
|
209
|
+
}
|
|
210
|
+
return pattern.severity;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Check if content is safe (convenience method)
|
|
215
|
+
* @param {string} content - The content to check
|
|
216
|
+
* @param {string} contentType - Optional content type
|
|
217
|
+
* @returns {boolean} - True if safe
|
|
218
|
+
*/
|
|
219
|
+
isSafe(content, contentType = '') {
|
|
220
|
+
return this.scan(content, contentType).safe;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Validate content and throw error if unsafe
|
|
225
|
+
* @param {string} content - The content to validate
|
|
226
|
+
* @param {string} contentType - Optional content type
|
|
227
|
+
* @throws {SecurityScanError} - If content is unsafe
|
|
228
|
+
*/
|
|
229
|
+
validate(content, contentType = '') {
|
|
230
|
+
const result = this.scan(content, contentType);
|
|
231
|
+
if (!result.safe) {
|
|
232
|
+
throw new SecurityScanError(result.findings);
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = ContentSecurityScanner;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context Cache (Session-Only)
|
|
5
|
+
*
|
|
6
|
+
* Provides temporary, session-only caching for fetched content.
|
|
7
|
+
* Cache is stored in system temp directory and auto-cleared on process exit.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
|
|
14
|
+
class ContextCache {
|
|
15
|
+
constructor() {
|
|
16
|
+
// Cache stored in system temp directory with PID for isolation
|
|
17
|
+
this.cacheDir = path.join(os.tmpdir(), `ez-agents-context-${process.pid}`);
|
|
18
|
+
this.cache = new Map();
|
|
19
|
+
|
|
20
|
+
// Register process exit handlers
|
|
21
|
+
this._registerExitHandlers();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Register process exit handlers to clean up cache
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
_registerExitHandlers() {
|
|
29
|
+
// Clean up on normal exit
|
|
30
|
+
process.on('exit', () => {
|
|
31
|
+
this.clear();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Clean up on SIGINT (Ctrl+C)
|
|
35
|
+
process.on('SIGINT', () => {
|
|
36
|
+
this.clear();
|
|
37
|
+
process.exit(130);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Clean up on SIGTERM
|
|
41
|
+
process.on('SIGTERM', () => {
|
|
42
|
+
this.clear();
|
|
43
|
+
process.exit(143);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Clean up on uncaught exceptions
|
|
47
|
+
process.on('uncaughtException', () => {
|
|
48
|
+
this.clear();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get cached content by key
|
|
54
|
+
* @param {string} key - The cache key (usually URL or file path)
|
|
55
|
+
* @returns {{content: string, timestamp: number, type: string, contentType?: string}|undefined}
|
|
56
|
+
*/
|
|
57
|
+
get(key) {
|
|
58
|
+
return this.cache.get(key);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Store content in cache
|
|
63
|
+
* @param {string} key - The cache key
|
|
64
|
+
* @param {string} content - The content to cache
|
|
65
|
+
* @param {Object} metadata - Additional metadata (type, contentType, etc.)
|
|
66
|
+
*/
|
|
67
|
+
set(key, content, metadata = {}) {
|
|
68
|
+
this.cache.set(key, {
|
|
69
|
+
content,
|
|
70
|
+
...metadata,
|
|
71
|
+
timestamp: Date.now()
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if key exists in cache
|
|
77
|
+
* @param {string} key - The cache key
|
|
78
|
+
* @returns {boolean} - True if key exists
|
|
79
|
+
*/
|
|
80
|
+
has(key) {
|
|
81
|
+
return this.cache.has(key);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Remove item from cache
|
|
86
|
+
* @param {string} key - The cache key
|
|
87
|
+
* @returns {boolean} - True if item was removed
|
|
88
|
+
*/
|
|
89
|
+
delete(key) {
|
|
90
|
+
return this.cache.delete(key);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get the size of the cache
|
|
95
|
+
* @returns {number} - Number of items in cache
|
|
96
|
+
*/
|
|
97
|
+
size() {
|
|
98
|
+
return this.cache.size;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Clear all cached content and remove temp directory
|
|
103
|
+
*/
|
|
104
|
+
clear() {
|
|
105
|
+
// Clear the in-memory cache
|
|
106
|
+
this.cache.clear();
|
|
107
|
+
|
|
108
|
+
// Remove temp directory if it exists
|
|
109
|
+
if (fs.existsSync(this.cacheDir)) {
|
|
110
|
+
try {
|
|
111
|
+
fs.rmSync(this.cacheDir, { recursive: true, force: true });
|
|
112
|
+
} catch (err) {
|
|
113
|
+
// Ignore errors during cleanup (directory may already be gone)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get cache directory path
|
|
120
|
+
* @returns {string} - Path to cache directory
|
|
121
|
+
*/
|
|
122
|
+
getCacheDir() {
|
|
123
|
+
return this.cacheDir;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get all cache keys
|
|
128
|
+
* @returns {Array<string>} - Array of cache keys
|
|
129
|
+
*/
|
|
130
|
+
keys() {
|
|
131
|
+
return Array.from(this.cache.keys());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get all cached entries
|
|
136
|
+
* @returns {Array<{key: string, value: Object}>} - Array of key-value pairs
|
|
137
|
+
*/
|
|
138
|
+
entries() {
|
|
139
|
+
return Array.from(this.cache.entries()).map(([key, value]) => ({ key, value }));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get cache statistics
|
|
144
|
+
* @returns {{size: number, keys: Array<string>}} - Cache statistics
|
|
145
|
+
*/
|
|
146
|
+
stats() {
|
|
147
|
+
return {
|
|
148
|
+
size: this.cache.size,
|
|
149
|
+
keys: this.keys()
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = ContextCache;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context Access Error Classes
|
|
5
|
+
*
|
|
6
|
+
* Provides structured error handling for context access operations
|
|
7
|
+
* including file access, URL fetching, and security scanning.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
class ContextAccessError extends Error {
|
|
11
|
+
constructor(message, options = {}) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'ContextAccessError';
|
|
14
|
+
this.code = options.code || 'CONTEXT_ACCESS_ERROR';
|
|
15
|
+
this.details = options.details || {};
|
|
16
|
+
this.timestamp = new Date().toISOString();
|
|
17
|
+
Error.captureStackTrace(this, ContextAccessError);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toJSON() {
|
|
21
|
+
return {
|
|
22
|
+
name: this.name,
|
|
23
|
+
code: this.code,
|
|
24
|
+
message: this.message,
|
|
25
|
+
details: this.details,
|
|
26
|
+
timestamp: this.timestamp
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class URLFetchError extends ContextAccessError {
|
|
32
|
+
constructor(url, reason, options = {}) {
|
|
33
|
+
super(`Failed to fetch URL: ${reason}`, {
|
|
34
|
+
code: 'URL_FETCH_ERROR',
|
|
35
|
+
details: { url, reason, ...options.details }
|
|
36
|
+
});
|
|
37
|
+
this.name = 'URLFetchError';
|
|
38
|
+
this.url = url;
|
|
39
|
+
this.reason = reason;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class FileAccessError extends ContextAccessError {
|
|
44
|
+
constructor(path, reason, options = {}) {
|
|
45
|
+
super(`Failed to access file: ${reason}`, {
|
|
46
|
+
code: 'FILE_ACCESS_ERROR',
|
|
47
|
+
details: { path, reason, ...options.details }
|
|
48
|
+
});
|
|
49
|
+
this.name = 'FileAccessError';
|
|
50
|
+
this.path = path;
|
|
51
|
+
this.reason = reason;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class SecurityScanError extends ContextAccessError {
|
|
56
|
+
constructor(findings, options = {}) {
|
|
57
|
+
super(`Security scan failed: ${findings.length} issue(s) detected`, {
|
|
58
|
+
code: 'SECURITY_SCAN_ERROR',
|
|
59
|
+
details: { findings, ...options.details }
|
|
60
|
+
});
|
|
61
|
+
this.name = 'SecurityScanError';
|
|
62
|
+
this.findings = findings;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
ContextAccessError,
|
|
68
|
+
URLFetchError,
|
|
69
|
+
FileAccessError,
|
|
70
|
+
SecurityScanError
|
|
71
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context Manager
|
|
5
|
+
*
|
|
6
|
+
* Orchestrates context gathering from files and URLs.
|
|
7
|
+
* Aggregates content, tracks sources, and updates STATE.md with context metadata.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const FileAccessService = require('./file-access.cjs');
|
|
13
|
+
const URLFetchService = require('./url-fetch.cjs');
|
|
14
|
+
const ContentSecurityScanner = require('./content-scanner.cjs');
|
|
15
|
+
const ContextCache = require('./context-cache.cjs');
|
|
16
|
+
const { SecurityScanError, FileAccessError, URLFetchError } = require('./context-errors.cjs');
|
|
17
|
+
|
|
18
|
+
class ContextManager {
|
|
19
|
+
/**
|
|
20
|
+
* Create a new ContextManager instance
|
|
21
|
+
* @param {string} cwd - Current working directory
|
|
22
|
+
*/
|
|
23
|
+
constructor(cwd) {
|
|
24
|
+
this.cwd = cwd || process.cwd();
|
|
25
|
+
this.sources = [];
|
|
26
|
+
this.cache = new ContextCache();
|
|
27
|
+
this.fileAccess = new FileAccessService(this.cwd);
|
|
28
|
+
this.urlFetch = new URLFetchService();
|
|
29
|
+
this.scanner = new ContentSecurityScanner();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Request context from files and URLs
|
|
34
|
+
* @param {{files?: string[], urls?: string[]}} options - Context options
|
|
35
|
+
* @returns {{context: string, sources: Array, errors: Array}} - Aggregated context
|
|
36
|
+
*/
|
|
37
|
+
async requestContext(options = {}) {
|
|
38
|
+
const { files = [], urls = [] } = options;
|
|
39
|
+
const contextParts = [];
|
|
40
|
+
const sources = [];
|
|
41
|
+
const errors = [];
|
|
42
|
+
|
|
43
|
+
// Process file patterns
|
|
44
|
+
for (const pattern of files) {
|
|
45
|
+
try {
|
|
46
|
+
const fileResults = this.fileAccess.readFiles(pattern);
|
|
47
|
+
for (const file of fileResults) {
|
|
48
|
+
contextParts.push(`## File: ${file.path}\n\n${file.content}`);
|
|
49
|
+
const source = {
|
|
50
|
+
type: 'file',
|
|
51
|
+
source: file.path,
|
|
52
|
+
timestamp: new Date().toISOString(),
|
|
53
|
+
size: file.content.length
|
|
54
|
+
};
|
|
55
|
+
sources.push(source);
|
|
56
|
+
this.trackSources([source]);
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
errors.push({
|
|
60
|
+
source: pattern,
|
|
61
|
+
type: 'file',
|
|
62
|
+
message: err.message
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Process URLs
|
|
68
|
+
for (const url of urls) {
|
|
69
|
+
try {
|
|
70
|
+
// Confirm URL fetch with user
|
|
71
|
+
const confirmed = await URLFetchService.confirmUrlFetch(url);
|
|
72
|
+
if (!confirmed) {
|
|
73
|
+
errors.push({
|
|
74
|
+
source: url,
|
|
75
|
+
type: 'url',
|
|
76
|
+
message: 'User declined to fetch URL'
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Fetch the URL
|
|
82
|
+
const result = await this.urlFetch.fetchUrl(url);
|
|
83
|
+
|
|
84
|
+
// Scan for security issues
|
|
85
|
+
const scanResult = this.scanner.scan(result.content, result.contentType);
|
|
86
|
+
if (!scanResult.safe) {
|
|
87
|
+
throw new SecurityScanError(scanResult.findings);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add to context
|
|
91
|
+
contextParts.push(`## URL: ${url}\n\n${result.content}`);
|
|
92
|
+
|
|
93
|
+
const source = {
|
|
94
|
+
type: 'url',
|
|
95
|
+
source: url,
|
|
96
|
+
timestamp: new Date().toISOString(),
|
|
97
|
+
contentType: result.contentType,
|
|
98
|
+
size: result.content.length
|
|
99
|
+
};
|
|
100
|
+
sources.push(source);
|
|
101
|
+
this.trackSources([source]);
|
|
102
|
+
|
|
103
|
+
// Cache the content
|
|
104
|
+
this.cache.set(url, result.content, {
|
|
105
|
+
type: 'url',
|
|
106
|
+
contentType: result.contentType
|
|
107
|
+
});
|
|
108
|
+
} catch (err) {
|
|
109
|
+
errors.push({
|
|
110
|
+
source: url,
|
|
111
|
+
type: 'url',
|
|
112
|
+
message: err.message
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
context: contextParts.join('\n\n---\n\n'),
|
|
119
|
+
sources,
|
|
120
|
+
errors
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Track source metadata (with deduplication)
|
|
126
|
+
* @param {Array} sources - Array of source objects
|
|
127
|
+
*/
|
|
128
|
+
trackSources(sources) {
|
|
129
|
+
for (const source of sources) {
|
|
130
|
+
// Check for duplicates (same type and source)
|
|
131
|
+
const isDuplicate = this.sources.some(
|
|
132
|
+
s => s.type === source.type && s.source === source.source
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (!isDuplicate) {
|
|
136
|
+
this.sources.push(source);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Update STATE.md with context sources
|
|
143
|
+
* Creates or appends to the Context Sources section
|
|
144
|
+
*/
|
|
145
|
+
updateStateMd() {
|
|
146
|
+
const statePath = path.join(this.cwd, '.planning', 'STATE.md');
|
|
147
|
+
|
|
148
|
+
// Ensure .planning directory exists
|
|
149
|
+
const planningDir = path.join(this.cwd, '.planning');
|
|
150
|
+
if (!fs.existsSync(planningDir)) {
|
|
151
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let content = '';
|
|
155
|
+
|
|
156
|
+
// Read existing content or start fresh
|
|
157
|
+
if (fs.existsSync(statePath)) {
|
|
158
|
+
content = fs.readFileSync(statePath, 'utf-8');
|
|
159
|
+
} else {
|
|
160
|
+
content = '# Project State\n\n';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Build the context sources table
|
|
164
|
+
const tableHeader = '| Source | Type | Timestamp |\n|--------|------|-----------|';
|
|
165
|
+
const tableRows = this.sources.map(s =>
|
|
166
|
+
`| ${s.source} | ${s.type.toUpperCase()} | ${s.timestamp} |`
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const contextSection = `\n## Context Sources\n\n${tableHeader}\n${tableRows.join('\n')}\n`;
|
|
170
|
+
|
|
171
|
+
// Check if Context Sources section already exists
|
|
172
|
+
const sectionRegex = /## Context Sources\n[\s\S]*?(?=\n## |\n$|$)/i;
|
|
173
|
+
const existingSection = content.match(sectionRegex);
|
|
174
|
+
|
|
175
|
+
if (existingSection) {
|
|
176
|
+
// Replace existing section
|
|
177
|
+
content = content.replace(sectionRegex, contextSection);
|
|
178
|
+
} else {
|
|
179
|
+
// Append new section
|
|
180
|
+
content = content.trimEnd() + '\n' + contextSection;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Write back to STATE.md
|
|
184
|
+
fs.writeFileSync(statePath, content, 'utf-8');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get all tracked sources
|
|
189
|
+
* @returns {Array} - Array of source objects
|
|
190
|
+
*/
|
|
191
|
+
getSources() {
|
|
192
|
+
return [...this.sources];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get cached content for a URL
|
|
197
|
+
* @param {string} key - Cache key (URL)
|
|
198
|
+
* @returns {{content: string, timestamp: number, type: string}|undefined}
|
|
199
|
+
*/
|
|
200
|
+
getCached(key) {
|
|
201
|
+
return this.cache.get(key);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Clear the cache
|
|
206
|
+
*/
|
|
207
|
+
clearCache() {
|
|
208
|
+
this.cache.clear();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get cache statistics
|
|
213
|
+
* @returns {{size: number, keys: Array<string>}}
|
|
214
|
+
*/
|
|
215
|
+
getCacheStats() {
|
|
216
|
+
return this.cache.stats();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = ContextManager;
|