@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,380 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hallucination Guard - Prevents AI hallucinations by requiring citations
|
|
10
|
+
* and flagging uncertainty in AI-generated content.
|
|
11
|
+
*
|
|
12
|
+
* Exports:
|
|
13
|
+
* - checkCitation(claim, context) - Searches codebase for claim evidence
|
|
14
|
+
* - verifyClaim(claim) - Verifies library/dependency claims
|
|
15
|
+
* - flagUncertainty(output) - Flags uncertain claims for review
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Uncertainty markers that indicate potential hallucinations
|
|
20
|
+
*/
|
|
21
|
+
const UNCERTAINTY_MARKERS = [
|
|
22
|
+
'might',
|
|
23
|
+
'could',
|
|
24
|
+
'possibly',
|
|
25
|
+
'perhaps',
|
|
26
|
+
'may',
|
|
27
|
+
'probably',
|
|
28
|
+
'likely',
|
|
29
|
+
'seems',
|
|
30
|
+
'appears',
|
|
31
|
+
'suggests',
|
|
32
|
+
'presumably',
|
|
33
|
+
'potentially',
|
|
34
|
+
'i think',
|
|
35
|
+
'i believe',
|
|
36
|
+
'in my opinion',
|
|
37
|
+
'as far as i know',
|
|
38
|
+
'to the best of my knowledge',
|
|
39
|
+
'not sure',
|
|
40
|
+
'uncertain',
|
|
41
|
+
'maybe'
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Search the codebase for evidence of a claim using grep-like search
|
|
46
|
+
* @param {string} claim - The claim to search for
|
|
47
|
+
* @param {string} context - Optional context directory path
|
|
48
|
+
* @returns {{ cited: boolean, citations: Array<{source: string, evidence: string}>, uncertainty: boolean }}
|
|
49
|
+
*/
|
|
50
|
+
function checkCitation(claim, context = process.cwd()) {
|
|
51
|
+
const citations = [];
|
|
52
|
+
let uncertainty = false;
|
|
53
|
+
|
|
54
|
+
// Normalize claim
|
|
55
|
+
const normalizedClaim = claim.trim().toLowerCase();
|
|
56
|
+
|
|
57
|
+
// Handle empty claims
|
|
58
|
+
if (!normalizedClaim) {
|
|
59
|
+
return {
|
|
60
|
+
cited: false,
|
|
61
|
+
citations: [],
|
|
62
|
+
uncertainty: false
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check if claim itself contains uncertainty markers
|
|
67
|
+
uncertainty = hasUncertainty(claim);
|
|
68
|
+
|
|
69
|
+
// Search in codebase using JavaScript fallback (Windows-compatible)
|
|
70
|
+
const searchResults = searchCodebase(normalizedClaim, context);
|
|
71
|
+
|
|
72
|
+
if (searchResults.length > 0) {
|
|
73
|
+
citations.push(...searchResults);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Also check package.json for library claims
|
|
77
|
+
if (isLibraryClaim(normalizedClaim)) {
|
|
78
|
+
const packageResult = checkPackageJson(normalizedClaim, context);
|
|
79
|
+
if (packageResult) {
|
|
80
|
+
citations.push(packageResult);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
cited: citations.length > 0,
|
|
86
|
+
citations,
|
|
87
|
+
uncertainty
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Search codebase for claim evidence using pure JavaScript (Windows-compatible)
|
|
93
|
+
* @param {string} claim - Normalized claim text
|
|
94
|
+
* @param {string} context - Search directory
|
|
95
|
+
* @returns {Array<{source: string, evidence: string}>}
|
|
96
|
+
*/
|
|
97
|
+
function searchCodebase(claim, context) {
|
|
98
|
+
const results = [];
|
|
99
|
+
const searchDirs = [
|
|
100
|
+
path.join(context, 'ez-agents'),
|
|
101
|
+
path.join(context, 'bin'),
|
|
102
|
+
path.join(context, 'commands'),
|
|
103
|
+
path.join(context, 'agents'),
|
|
104
|
+
path.join(context, '.planning')
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
// Filter to existing directories
|
|
108
|
+
const validDirs = searchDirs.filter(dir => fs.existsSync(dir));
|
|
109
|
+
|
|
110
|
+
for (const dir of validDirs) {
|
|
111
|
+
const files = getAllFiles(dir);
|
|
112
|
+
for (const file of files) {
|
|
113
|
+
if (!file.endsWith('.cjs') && !file.endsWith('.js') &&
|
|
114
|
+
!file.endsWith('.md') && !file.endsWith('.json')) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
120
|
+
const lines = content.split('\n');
|
|
121
|
+
|
|
122
|
+
for (let i = 0; i < lines.length; i++) {
|
|
123
|
+
const line = lines[i].toLowerCase();
|
|
124
|
+
// Check for claim keywords in the line
|
|
125
|
+
const claimWords = claim.split(/\s+/).filter(w => w.length > 3);
|
|
126
|
+
const matches = claimWords.filter(word => line.includes(word));
|
|
127
|
+
|
|
128
|
+
if (matches.length >= Math.min(2, claimWords.length)) {
|
|
129
|
+
const relativePath = path.relative(context, file);
|
|
130
|
+
results.push({
|
|
131
|
+
source: relativePath,
|
|
132
|
+
evidence: lines[i].trim(),
|
|
133
|
+
line: i + 1
|
|
134
|
+
});
|
|
135
|
+
break; // One match per file is enough
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
// Skip binary or unreadable files
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get all files recursively from a directory
|
|
149
|
+
* @param {string} dir - Directory path
|
|
150
|
+
* @returns {string[]} - Array of file paths
|
|
151
|
+
*/
|
|
152
|
+
function getAllFiles(dir) {
|
|
153
|
+
const files = [];
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
157
|
+
for (const entry of entries) {
|
|
158
|
+
const fullPath = path.join(dir, entry.name);
|
|
159
|
+
if (entry.isDirectory()) {
|
|
160
|
+
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
161
|
+
files.push(...getAllFiles(fullPath));
|
|
162
|
+
}
|
|
163
|
+
} else if (entry.isFile()) {
|
|
164
|
+
files.push(fullPath);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
// Skip inaccessible directories
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return files;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Check if claim is about a library/dependency
|
|
176
|
+
* @param {string} claim - Claim text
|
|
177
|
+
* @returns {boolean}
|
|
178
|
+
*/
|
|
179
|
+
function isLibraryClaim(claim) {
|
|
180
|
+
const libraryKeywords = [
|
|
181
|
+
'library', 'package', 'module', 'dependency', 'npm',
|
|
182
|
+
'install', 'require', 'import', 'devdependency'
|
|
183
|
+
];
|
|
184
|
+
return libraryKeywords.some(keyword => claim.includes(keyword));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check package.json for library claims
|
|
189
|
+
* @param {string} claim - Normalized claim text
|
|
190
|
+
* @param {string} context - Context directory
|
|
191
|
+
* @returns {{source: string, evidence: string} | null}
|
|
192
|
+
*/
|
|
193
|
+
function checkPackageJson(claim, context) {
|
|
194
|
+
const packageJsonPath = path.join(context, 'package.json');
|
|
195
|
+
|
|
196
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const packageData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
202
|
+
const allDeps = {
|
|
203
|
+
...packageData.dependencies,
|
|
204
|
+
...packageData.devDependencies
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Extract library name from claim (look for quoted strings or common patterns)
|
|
208
|
+
const libMatch = claim.match(/["']([^"']+)["']/);
|
|
209
|
+
if (libMatch) {
|
|
210
|
+
const libName = libMatch[1];
|
|
211
|
+
if (allDeps[libName]) {
|
|
212
|
+
return {
|
|
213
|
+
source: 'package.json',
|
|
214
|
+
evidence: `${libName}: ${allDeps[libName]}`,
|
|
215
|
+
verified: true
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Check if any dependency name appears in claim
|
|
221
|
+
for (const [depName, depVersion] of Object.entries(allDeps)) {
|
|
222
|
+
if (claim.includes(depName)) {
|
|
223
|
+
return {
|
|
224
|
+
source: 'package.json',
|
|
225
|
+
evidence: `${depName}: ${depVersion}`,
|
|
226
|
+
verified: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} catch (err) {
|
|
231
|
+
// Invalid package.json
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Check if text contains uncertainty markers
|
|
239
|
+
* @param {string} text - Text to check
|
|
240
|
+
* @returns {boolean}
|
|
241
|
+
*/
|
|
242
|
+
function hasUncertainty(text) {
|
|
243
|
+
const lowerText = text.toLowerCase();
|
|
244
|
+
return UNCERTAINTY_MARKERS.some(marker => lowerText.includes(marker));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Verify a claim about libraries, dependencies, or codebase features
|
|
249
|
+
* @param {string} claim - Claim to verify
|
|
250
|
+
* @param {string} context - Context directory
|
|
251
|
+
* @returns {{ verified: boolean, source: string, details: any }}
|
|
252
|
+
*/
|
|
253
|
+
function verifyClaim(claim, context = process.cwd()) {
|
|
254
|
+
const normalizedClaim = claim.trim().toLowerCase();
|
|
255
|
+
|
|
256
|
+
// Check for library/dependency claims
|
|
257
|
+
if (isLibraryClaim(normalizedClaim)) {
|
|
258
|
+
const packageResult = checkPackageJson(normalizedClaim, context);
|
|
259
|
+
if (packageResult) {
|
|
260
|
+
return {
|
|
261
|
+
verified: true,
|
|
262
|
+
source: 'package.json',
|
|
263
|
+
details: packageResult
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Would call Context7 MCP here for external libraries
|
|
268
|
+
// For now, mark as unverified but not necessarily false
|
|
269
|
+
return {
|
|
270
|
+
verified: false,
|
|
271
|
+
source: 'context7',
|
|
272
|
+
details: { message: 'External library verification requires Context7 MCP' }
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// For codebase claims, use checkCitation
|
|
277
|
+
const citationResult = checkCitation(claim, context);
|
|
278
|
+
return {
|
|
279
|
+
verified: citationResult.cited,
|
|
280
|
+
source: 'codebase',
|
|
281
|
+
details: citationResult
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Scan AI output for uncertainty markers and flag for review
|
|
287
|
+
* @param {string} output - AI-generated text to scan
|
|
288
|
+
* @returns {{ flagged: boolean, markers: Array<{marker: string, position: number}>, confidence: number }}
|
|
289
|
+
*/
|
|
290
|
+
function flagUncertainty(output) {
|
|
291
|
+
const markers = [];
|
|
292
|
+
const lowerOutput = output.toLowerCase();
|
|
293
|
+
|
|
294
|
+
for (const marker of UNCERTAINTY_MARKERS) {
|
|
295
|
+
let position = lowerOutput.indexOf(marker);
|
|
296
|
+
while (position !== -1) {
|
|
297
|
+
markers.push({
|
|
298
|
+
marker,
|
|
299
|
+
position
|
|
300
|
+
});
|
|
301
|
+
position = lowerOutput.indexOf(marker, position + 1);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Calculate confidence score (inverse of uncertainty)
|
|
306
|
+
const uncertaintyRatio = markers.length / Math.max(1, output.split(/\s+/).length);
|
|
307
|
+
const confidence = Math.max(0, 1 - (uncertaintyRatio * 10));
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
flagged: markers.length > 0,
|
|
311
|
+
markers,
|
|
312
|
+
confidence: Math.round(confidence * 100) / 100
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* CLI entry point
|
|
318
|
+
*/
|
|
319
|
+
function main() {
|
|
320
|
+
const args = process.argv.slice(2);
|
|
321
|
+
|
|
322
|
+
if (args.length === 0) {
|
|
323
|
+
console.log('Hallucination Guard - Citation checker and uncertainty flagger');
|
|
324
|
+
console.log('');
|
|
325
|
+
console.log('Usage:');
|
|
326
|
+
console.log(' node hallucination-guard.cjs check "claim text"');
|
|
327
|
+
console.log(' node hallucination-guard.cjs verify "claim text"');
|
|
328
|
+
console.log(' node hallucination-guard.cjs flag "output text"');
|
|
329
|
+
console.log('');
|
|
330
|
+
console.log('Commands:');
|
|
331
|
+
console.log(' check - Check if claim has citations in codebase');
|
|
332
|
+
console.log(' verify - Verify library/dependency claims');
|
|
333
|
+
console.log(' flag - Flag uncertainty in AI output');
|
|
334
|
+
process.exit(0);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const command = args[0];
|
|
338
|
+
const text = args.slice(1).join(' ').replace(/^["']|["']$/g, '');
|
|
339
|
+
|
|
340
|
+
switch (command) {
|
|
341
|
+
case 'check': {
|
|
342
|
+
const result = checkCitation(text);
|
|
343
|
+
console.log(JSON.stringify(result, null, 2));
|
|
344
|
+
process.exit(result.cited ? 0 : 1);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
case 'verify': {
|
|
348
|
+
const result = verifyClaim(text);
|
|
349
|
+
console.log(JSON.stringify(result, null, 2));
|
|
350
|
+
process.exit(result.verified ? 0 : 1);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
case 'flag': {
|
|
354
|
+
const result = flagUncertainty(text);
|
|
355
|
+
console.log(JSON.stringify(result, null, 2));
|
|
356
|
+
process.exit(result.flagged ? 1 : 0);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
default:
|
|
360
|
+
console.error(`Unknown command: ${command}`);
|
|
361
|
+
console.log('Use "node hallucination-guard.cjs" for usage information');
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Export functions for programmatic use
|
|
367
|
+
module.exports = {
|
|
368
|
+
checkCitation,
|
|
369
|
+
verifyClaim,
|
|
370
|
+
flagUncertainty,
|
|
371
|
+
hasUncertainty,
|
|
372
|
+
searchCodebase,
|
|
373
|
+
checkPackageJson,
|
|
374
|
+
UNCERTAINTY_MARKERS
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// Run CLI if executed directly
|
|
378
|
+
if (require.main === module) {
|
|
379
|
+
main();
|
|
380
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EDGE-03: Hidden State Guard
|
|
3
|
+
*
|
|
4
|
+
* Detects state not persisted to .planning/ files.
|
|
5
|
+
* Ensures all state is explicitly persisted for auditability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* List all state files in .planning/ directory
|
|
13
|
+
* @param {string} phaseDir - Phase directory
|
|
14
|
+
* @returns {string[]} Array of state file paths
|
|
15
|
+
*/
|
|
16
|
+
function listStateFiles(phaseDir) {
|
|
17
|
+
const stateFiles = [];
|
|
18
|
+
const planningDir = path.join(phaseDir, '.planning');
|
|
19
|
+
|
|
20
|
+
if (!fs.existsSync(planningDir)) {
|
|
21
|
+
return stateFiles;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Recursively find all .md files in .planning/
|
|
25
|
+
function scanDir(dir) {
|
|
26
|
+
try {
|
|
27
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const fullPath = path.join(dir, entry.name);
|
|
30
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
31
|
+
scanDir(fullPath);
|
|
32
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
33
|
+
stateFiles.push(fullPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
// Ignore permission errors
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
scanDir(planningDir);
|
|
42
|
+
return stateFiles;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Extract state references from text
|
|
47
|
+
* @param {string} text - Text to analyze
|
|
48
|
+
* @returns {string[]} Array of state references
|
|
49
|
+
*/
|
|
50
|
+
function extractStateReferences(text) {
|
|
51
|
+
const statePatterns = [
|
|
52
|
+
/(?:state|status|progress|phase|step|current)[\s:]+([A-Z_]+\d*(?:\.\d+)?)/gi,
|
|
53
|
+
/(?:task|plan|gate|edge)[\s:]+(\d+(?:-\d+)?)/gi,
|
|
54
|
+
/(?:completed|finished|done|pending|blocked)[\s:]+([A-Z_]+)/gi
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const references = new Set();
|
|
58
|
+
|
|
59
|
+
for (const pattern of statePatterns) {
|
|
60
|
+
let match;
|
|
61
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
62
|
+
references.add(match[0].toLowerCase());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return Array.from(references);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check for hidden state (state not persisted to files)
|
|
71
|
+
* @param {string} output - AI generated output
|
|
72
|
+
* @param {string} phaseDir - Phase directory
|
|
73
|
+
* @returns {object} { hasHiddenState: boolean, stateFiles: array, missing: array }
|
|
74
|
+
*/
|
|
75
|
+
function checkHiddenState(output, phaseDir) {
|
|
76
|
+
const stateFiles = listStateFiles(phaseDir);
|
|
77
|
+
const stateReferences = extractStateReferences(output);
|
|
78
|
+
|
|
79
|
+
// Read all state file contents
|
|
80
|
+
const stateContents = stateFiles.map(file => {
|
|
81
|
+
try {
|
|
82
|
+
return fs.readFileSync(file, 'utf8').toLowerCase();
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return '';
|
|
85
|
+
}
|
|
86
|
+
}).join(' ');
|
|
87
|
+
|
|
88
|
+
// Check which state references are not in persisted files
|
|
89
|
+
const missing = stateReferences.filter(ref => {
|
|
90
|
+
// Skip common false positives
|
|
91
|
+
if (['state', 'status', 'phase', 'plan'].includes(ref)) return false;
|
|
92
|
+
return !stateContents.includes(ref);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
hasHiddenState: missing.length > 0,
|
|
97
|
+
stateFiles,
|
|
98
|
+
stateReferences,
|
|
99
|
+
missing,
|
|
100
|
+
recommendation: missing.length > 0
|
|
101
|
+
? `Persist the following state to .planning/ files: ${missing.join(', ')}`
|
|
102
|
+
: 'All state appears to be persisted'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Validate that all state is persisted
|
|
108
|
+
* @param {string} output - AI generated output
|
|
109
|
+
* @param {string} phaseDir - Phase directory
|
|
110
|
+
* @returns {object} Validation result
|
|
111
|
+
*/
|
|
112
|
+
function validatePersistence(output, phaseDir) {
|
|
113
|
+
const result = checkHiddenState(output, phaseDir);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
valid: !result.hasHiddenState,
|
|
117
|
+
...result
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* CLI entry point
|
|
123
|
+
*/
|
|
124
|
+
if (require.main === module) {
|
|
125
|
+
const args = process.argv.slice(2);
|
|
126
|
+
const command = args[0];
|
|
127
|
+
|
|
128
|
+
if (command === 'check' && args[1]) {
|
|
129
|
+
const phaseDir = args[1];
|
|
130
|
+
console.log(`Checking for hidden state in ${phaseDir}`);
|
|
131
|
+
|
|
132
|
+
const stateFiles = listStateFiles(phaseDir);
|
|
133
|
+
console.log(`Found ${stateFiles.length} state files in .planning/`);
|
|
134
|
+
|
|
135
|
+
if (stateFiles.length > 0) {
|
|
136
|
+
console.log('State files:');
|
|
137
|
+
stateFiles.slice(0, 10).forEach(f => console.log(` - ${path.relative(phaseDir, f)}`));
|
|
138
|
+
if (stateFiles.length > 10) {
|
|
139
|
+
console.log(` ... and ${stateFiles.length - 10} more`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
process.exit(0);
|
|
144
|
+
|
|
145
|
+
} else if (command === 'validate' && args[1]) {
|
|
146
|
+
const phaseDir = args[1];
|
|
147
|
+
const outputFile = args[2];
|
|
148
|
+
|
|
149
|
+
if (!outputFile || !fs.existsSync(outputFile)) {
|
|
150
|
+
console.error('Usage: node hidden-state-guard.cjs validate <phaseDir> <outputFile>');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const output = fs.readFileSync(outputFile, 'utf8');
|
|
155
|
+
const result = validatePersistence(output, phaseDir);
|
|
156
|
+
|
|
157
|
+
if (result.valid) {
|
|
158
|
+
console.log('✅ All state is persisted');
|
|
159
|
+
console.log(` State files: ${result.stateFiles.length}`);
|
|
160
|
+
process.exit(0);
|
|
161
|
+
} else {
|
|
162
|
+
console.log('⚠️ Hidden state detected');
|
|
163
|
+
console.log(` Missing: ${result.missing.join(', ')}`);
|
|
164
|
+
console.log(` ${result.recommendation}`);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
} else {
|
|
169
|
+
console.log('Usage: node hidden-state-guard.cjs <command> [args]');
|
|
170
|
+
console.log('Commands:');
|
|
171
|
+
console.log(' check <phaseDir> - List state files');
|
|
172
|
+
console.log(' validate <phaseDir> <file> - Validate output persistence');
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
listStateFiles,
|
|
179
|
+
extractStateReferences,
|
|
180
|
+
checkHiddenState,
|
|
181
|
+
validatePersistence
|
|
182
|
+
};
|