gentyr 1.3.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/.claude/agents/antipattern-hunter.md +176 -0
- package/.claude/agents/code-reviewer.md +205 -0
- package/.claude/agents/code-writer.md +154 -0
- package/.claude/agents/deputy-cto.md +309 -0
- package/.claude/agents/feedback-agent.md +101 -0
- package/.claude/agents/investigator.md +136 -0
- package/.claude/agents/product-manager.md +97 -0
- package/.claude/agents/project-manager.md +116 -0
- package/.claude/agents/repo-hygiene-expert.md +626 -0
- package/.claude/agents/secret-manager.md +324 -0
- package/.claude/agents/test-writer.md +354 -0
- package/.claude/commands/configure-personas.md +144 -0
- package/.claude/commands/cto-report.md +36 -0
- package/.claude/commands/demo.md +89 -0
- package/.claude/commands/deputy-cto.md +345 -0
- package/.claude/commands/hotfix.md +31 -0
- package/.claude/commands/overdrive-gentyr.md +167 -0
- package/.claude/commands/product-manager.md +32 -0
- package/.claude/commands/push-migrations.md +86 -0
- package/.claude/commands/push-secrets.md +97 -0
- package/.claude/commands/services.json.example +30 -0
- package/.claude/commands/setup-gentyr.md +396 -0
- package/.claude/commands/show.md +42 -0
- package/.claude/commands/spawn-tasks.md +79 -0
- package/.claude/commands/toggle-automation-gentyr.md +75 -0
- package/.claude/commands/toggle-product-manager.md +19 -0
- package/.claude/commands/triage.md +69 -0
- package/.claude/hooks/README.md +686 -0
- package/.claude/hooks/__tests__/README.md +129 -0
- package/.claude/hooks/agent-tracker.js +434 -0
- package/.claude/hooks/antipattern-hunter-hook.js +401 -0
- package/.claude/hooks/api-key-watcher.js +289 -0
- package/.claude/hooks/block-no-verify.js +301 -0
- package/.claude/hooks/bypass-approval-hook.js +313 -0
- package/.claude/hooks/compliance-checker.js +1309 -0
- package/.claude/hooks/config-reader.js +143 -0
- package/.claude/hooks/credential-file-guard.js +1139 -0
- package/.claude/hooks/credential-health-check.js +168 -0
- package/.claude/hooks/credential-sync-hook.js +79 -0
- package/.claude/hooks/cto-notification-hook.js +656 -0
- package/.claude/hooks/feedback-launcher.js +424 -0
- package/.claude/hooks/feedback-orchestrator.js +367 -0
- package/.claude/hooks/gentyr-splash.js +47 -0
- package/.claude/hooks/gentyr-sync.js +389 -0
- package/.claude/hooks/hourly-automation.js +3340 -0
- package/.claude/hooks/key-sync.js +899 -0
- package/.claude/hooks/lib/approval-utils.js +731 -0
- package/.claude/hooks/lib/feature-branch-helper.js +102 -0
- package/.claude/hooks/lib/worktree-manager.js +330 -0
- package/.claude/hooks/mapping-validator.js +285 -0
- package/.claude/hooks/plan-executor.js +398 -0
- package/.claude/hooks/playwright-cli-guard.js +104 -0
- package/.claude/hooks/playwright-health-check.js +71 -0
- package/.claude/hooks/pre-commit-review.js +725 -0
- package/.claude/hooks/prompts/local-spec-enforcement.md +310 -0
- package/.claude/hooks/prompts/mapping-fix.md +92 -0
- package/.claude/hooks/prompts/mapping-review.md +140 -0
- package/.claude/hooks/prompts/schema-mapper.md +185 -0
- package/.claude/hooks/prompts/spec-enforcement.md +233 -0
- package/.claude/hooks/protected-action-approval-hook.js +336 -0
- package/.claude/hooks/protected-action-gate.js +562 -0
- package/.claude/hooks/protected-actions.json +208 -0
- package/.claude/hooks/protected-actions.json.template +122 -0
- package/.claude/hooks/quota-monitor.js +490 -0
- package/.claude/hooks/reporters/jest-failure-reporter.js +401 -0
- package/.claude/hooks/reporters/playwright-failure-reporter.js +446 -0
- package/.claude/hooks/reporters/vitest-failure-reporter.js +443 -0
- package/.claude/hooks/schema-mapper-hook.js +544 -0
- package/.claude/hooks/secret-leak-detector.js +216 -0
- package/.claude/hooks/session-reviver.js +514 -0
- package/.claude/hooks/slash-command-prefetch.js +1145 -0
- package/.claude/hooks/stale-work-detector.js +205 -0
- package/.claude/hooks/stop-continue-hook.js +414 -0
- package/.claude/hooks/todo-maintenance.js +522 -0
- package/.claude/hooks/todo-processing-prompt.md +75 -0
- package/.claude/hooks/usage-optimizer.js +791 -0
- package/.claude/mcp/README.md +246 -0
- package/.claude/settings.json.template +168 -0
- package/.mcp.json.template +207 -0
- package/CLAUDE.md +340 -0
- package/CLAUDE.md.gentyr-section +89 -0
- package/LICENSE +21 -0
- package/README.md +297 -0
- package/cli/commands/init.js +471 -0
- package/cli/commands/migrate.js +132 -0
- package/cli/commands/protect.js +271 -0
- package/cli/commands/scaffold.js +48 -0
- package/cli/commands/status.js +133 -0
- package/cli/commands/sync.js +101 -0
- package/cli/commands/uninstall.js +207 -0
- package/cli/index.js +111 -0
- package/cli/lib/config-gen.js +214 -0
- package/cli/lib/resolve-framework.js +97 -0
- package/cli/lib/state.js +140 -0
- package/cli/lib/symlinks.js +260 -0
- package/docs/AUTOMATION-SYSTEMS.md +484 -0
- package/docs/BINARY-PATCHING.md +212 -0
- package/docs/CHANGELOG.md +2830 -0
- package/docs/CREDENTIAL-DETECTION.md +151 -0
- package/docs/CTO-DASHBOARD.md +476 -0
- package/docs/DEPLOYMENT-FLOW.md +477 -0
- package/docs/DEVELOPER.md +116 -0
- package/docs/Executive.md +372 -0
- package/docs/SECRET-PATHS.md +77 -0
- package/docs/SETUP-GUIDE.md +419 -0
- package/docs/STACK.md +109 -0
- package/docs/TESTING.md +440 -0
- package/docs/assets/claude-logo.svg +3 -0
- package/docs/sessions/2026-01-24-spec-suite-implementation.md +190 -0
- package/docs/sessions/2026-02-15-feedback-e2e-audit.md +484 -0
- package/docs/sessions/2026-02-20-credential-rotation-experiments.md +340 -0
- package/docs/sessions/TEST-COVERAGE-REPORT-2026-02-20.md +168 -0
- package/docs/shared/EPHEMERAL-STATE-FILES.md +115 -0
- package/docs/shared/PROTECTION-SYSTEM.md +341 -0
- package/husky/post-commit +10 -0
- package/husky/pre-commit +40 -0
- package/husky/pre-push +94 -0
- package/package.json +43 -0
- package/packages/cto-dashboard/package-lock.json +3510 -0
- package/packages/cto-dashboard/package.json +41 -0
- package/packages/cto-dashboard/pnpm-lock.yaml +2168 -0
- package/packages/mcp-servers/dist/__testUtils__/fixtures.d.ts +220 -0
- package/packages/mcp-servers/dist/__testUtils__/fixtures.d.ts.map +1 -0
- package/packages/mcp-servers/dist/__testUtils__/fixtures.js +376 -0
- package/packages/mcp-servers/dist/__testUtils__/fixtures.js.map +1 -0
- package/packages/mcp-servers/dist/__testUtils__/index.d.ts +121 -0
- package/packages/mcp-servers/dist/__testUtils__/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/__testUtils__/index.js +180 -0
- package/packages/mcp-servers/dist/__testUtils__/index.js.map +1 -0
- package/packages/mcp-servers/dist/__testUtils__/schemas.d.ts +84 -0
- package/packages/mcp-servers/dist/__testUtils__/schemas.d.ts.map +1 -0
- package/packages/mcp-servers/dist/__testUtils__/schemas.js +309 -0
- package/packages/mcp-servers/dist/__testUtils__/schemas.js.map +1 -0
- package/packages/mcp-servers/dist/agent-reports/index.d.ts +7 -0
- package/packages/mcp-servers/dist/agent-reports/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/agent-reports/index.js +8 -0
- package/packages/mcp-servers/dist/agent-reports/index.js.map +1 -0
- package/packages/mcp-servers/dist/agent-reports/server.d.ts +22 -0
- package/packages/mcp-servers/dist/agent-reports/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/agent-reports/server.js +535 -0
- package/packages/mcp-servers/dist/agent-reports/server.js.map +1 -0
- package/packages/mcp-servers/dist/agent-reports/types.d.ts +258 -0
- package/packages/mcp-servers/dist/agent-reports/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/agent-reports/types.js +81 -0
- package/packages/mcp-servers/dist/agent-reports/types.js.map +1 -0
- package/packages/mcp-servers/dist/agent-tracker/index.d.ts +5 -0
- package/packages/mcp-servers/dist/agent-tracker/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/agent-tracker/index.js +5 -0
- package/packages/mcp-servers/dist/agent-tracker/index.js.map +1 -0
- package/packages/mcp-servers/dist/agent-tracker/server.d.ts +12 -0
- package/packages/mcp-servers/dist/agent-tracker/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/agent-tracker/server.js +919 -0
- package/packages/mcp-servers/dist/agent-tracker/server.js.map +1 -0
- package/packages/mcp-servers/dist/agent-tracker/types.d.ts +328 -0
- package/packages/mcp-servers/dist/agent-tracker/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/agent-tracker/types.js +128 -0
- package/packages/mcp-servers/dist/agent-tracker/types.js.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/browser-tips.d.ts +27 -0
- package/packages/mcp-servers/dist/chrome-bridge/browser-tips.d.ts.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/browser-tips.js +167 -0
- package/packages/mcp-servers/dist/chrome-bridge/browser-tips.js.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/index.d.ts +6 -0
- package/packages/mcp-servers/dist/chrome-bridge/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/index.js +6 -0
- package/packages/mcp-servers/dist/chrome-bridge/index.js.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/server.d.ts +13 -0
- package/packages/mcp-servers/dist/chrome-bridge/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/server.js +959 -0
- package/packages/mcp-servers/dist/chrome-bridge/server.js.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/types.d.ts +41 -0
- package/packages/mcp-servers/dist/chrome-bridge/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/chrome-bridge/types.js +8 -0
- package/packages/mcp-servers/dist/chrome-bridge/types.js.map +1 -0
- package/packages/mcp-servers/dist/cloudflare/index.d.ts +8 -0
- package/packages/mcp-servers/dist/cloudflare/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cloudflare/index.js +8 -0
- package/packages/mcp-servers/dist/cloudflare/index.js.map +1 -0
- package/packages/mcp-servers/dist/cloudflare/server.d.ts +16 -0
- package/packages/mcp-servers/dist/cloudflare/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cloudflare/server.js +253 -0
- package/packages/mcp-servers/dist/cloudflare/server.js.map +1 -0
- package/packages/mcp-servers/dist/cloudflare/types.d.ts +141 -0
- package/packages/mcp-servers/dist/cloudflare/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cloudflare/types.js +53 -0
- package/packages/mcp-servers/dist/cloudflare/types.js.map +1 -0
- package/packages/mcp-servers/dist/codecov/index.d.ts +7 -0
- package/packages/mcp-servers/dist/codecov/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/codecov/index.js +7 -0
- package/packages/mcp-servers/dist/codecov/index.js.map +1 -0
- package/packages/mcp-servers/dist/codecov/server.d.ts +21 -0
- package/packages/mcp-servers/dist/codecov/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/codecov/server.js +376 -0
- package/packages/mcp-servers/dist/codecov/server.js.map +1 -0
- package/packages/mcp-servers/dist/codecov/types.d.ts +269 -0
- package/packages/mcp-servers/dist/codecov/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/codecov/types.js +128 -0
- package/packages/mcp-servers/dist/codecov/types.js.map +1 -0
- package/packages/mcp-servers/dist/cto-report/index.d.ts +9 -0
- package/packages/mcp-servers/dist/cto-report/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cto-report/index.js +9 -0
- package/packages/mcp-servers/dist/cto-report/index.js.map +1 -0
- package/packages/mcp-servers/dist/cto-report/server.d.ts +14 -0
- package/packages/mcp-servers/dist/cto-report/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cto-report/server.js +859 -0
- package/packages/mcp-servers/dist/cto-report/server.js.map +1 -0
- package/packages/mcp-servers/dist/cto-report/types.d.ts +213 -0
- package/packages/mcp-servers/dist/cto-report/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cto-report/types.js +29 -0
- package/packages/mcp-servers/dist/cto-report/types.js.map +1 -0
- package/packages/mcp-servers/dist/cto-reports/index.d.ts +7 -0
- package/packages/mcp-servers/dist/cto-reports/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cto-reports/index.js +8 -0
- package/packages/mcp-servers/dist/cto-reports/index.js.map +1 -0
- package/packages/mcp-servers/dist/cto-reports/server.d.ts +20 -0
- package/packages/mcp-servers/dist/cto-reports/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cto-reports/server.js +538 -0
- package/packages/mcp-servers/dist/cto-reports/server.js.map +1 -0
- package/packages/mcp-servers/dist/cto-reports/types.d.ts +236 -0
- package/packages/mcp-servers/dist/cto-reports/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/cto-reports/types.js +77 -0
- package/packages/mcp-servers/dist/cto-reports/types.js.map +1 -0
- package/packages/mcp-servers/dist/deputy-cto/index.d.ts +7 -0
- package/packages/mcp-servers/dist/deputy-cto/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/deputy-cto/index.js +8 -0
- package/packages/mcp-servers/dist/deputy-cto/index.js.map +1 -0
- package/packages/mcp-servers/dist/deputy-cto/server.d.ts +23 -0
- package/packages/mcp-servers/dist/deputy-cto/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/deputy-cto/server.js +1700 -0
- package/packages/mcp-servers/dist/deputy-cto/server.js.map +1 -0
- package/packages/mcp-servers/dist/deputy-cto/types.d.ts +439 -0
- package/packages/mcp-servers/dist/deputy-cto/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/deputy-cto/types.js +102 -0
- package/packages/mcp-servers/dist/deputy-cto/types.js.map +1 -0
- package/packages/mcp-servers/dist/elastic-logs/index.d.ts +5 -0
- package/packages/mcp-servers/dist/elastic-logs/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/elastic-logs/index.js +5 -0
- package/packages/mcp-servers/dist/elastic-logs/index.js.map +1 -0
- package/packages/mcp-servers/dist/elastic-logs/server.d.ts +18 -0
- package/packages/mcp-servers/dist/elastic-logs/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/elastic-logs/server.js +259 -0
- package/packages/mcp-servers/dist/elastic-logs/server.js.map +1 -0
- package/packages/mcp-servers/dist/elastic-logs/types.d.ts +107 -0
- package/packages/mcp-servers/dist/elastic-logs/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/elastic-logs/types.js +31 -0
- package/packages/mcp-servers/dist/elastic-logs/types.js.map +1 -0
- package/packages/mcp-servers/dist/feedback-explorer/index.d.ts +2 -0
- package/packages/mcp-servers/dist/feedback-explorer/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/feedback-explorer/index.js +2 -0
- package/packages/mcp-servers/dist/feedback-explorer/index.js.map +1 -0
- package/packages/mcp-servers/dist/feedback-explorer/server.d.ts +21 -0
- package/packages/mcp-servers/dist/feedback-explorer/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/feedback-explorer/server.js +580 -0
- package/packages/mcp-servers/dist/feedback-explorer/server.js.map +1 -0
- package/packages/mcp-servers/dist/feedback-explorer/types.d.ts +331 -0
- package/packages/mcp-servers/dist/feedback-explorer/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/feedback-explorer/types.js +40 -0
- package/packages/mcp-servers/dist/feedback-explorer/types.js.map +1 -0
- package/packages/mcp-servers/dist/feedback-reporter/index.d.ts +9 -0
- package/packages/mcp-servers/dist/feedback-reporter/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/feedback-reporter/index.js +9 -0
- package/packages/mcp-servers/dist/feedback-reporter/index.js.map +1 -0
- package/packages/mcp-servers/dist/feedback-reporter/server.d.ts +36 -0
- package/packages/mcp-servers/dist/feedback-reporter/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/feedback-reporter/server.js +392 -0
- package/packages/mcp-servers/dist/feedback-reporter/server.js.map +1 -0
- package/packages/mcp-servers/dist/feedback-reporter/types.d.ts +152 -0
- package/packages/mcp-servers/dist/feedback-reporter/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/feedback-reporter/types.js +67 -0
- package/packages/mcp-servers/dist/feedback-reporter/types.js.map +1 -0
- package/packages/mcp-servers/dist/github/index.d.ts +7 -0
- package/packages/mcp-servers/dist/github/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/github/index.js +7 -0
- package/packages/mcp-servers/dist/github/index.js.map +1 -0
- package/packages/mcp-servers/dist/github/server.d.ts +15 -0
- package/packages/mcp-servers/dist/github/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/github/server.js +686 -0
- package/packages/mcp-servers/dist/github/server.js.map +1 -0
- package/packages/mcp-servers/dist/github/types.d.ts +660 -0
- package/packages/mcp-servers/dist/github/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/github/types.js +209 -0
- package/packages/mcp-servers/dist/github/types.js.map +1 -0
- package/packages/mcp-servers/dist/index.d.ts +30 -0
- package/packages/mcp-servers/dist/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/index.js +32 -0
- package/packages/mcp-servers/dist/index.js.map +1 -0
- package/packages/mcp-servers/dist/makerkit-docs/index.d.ts +5 -0
- package/packages/mcp-servers/dist/makerkit-docs/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/makerkit-docs/index.js +5 -0
- package/packages/mcp-servers/dist/makerkit-docs/index.js.map +1 -0
- package/packages/mcp-servers/dist/makerkit-docs/server.d.ts +15 -0
- package/packages/mcp-servers/dist/makerkit-docs/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/makerkit-docs/server.js +252 -0
- package/packages/mcp-servers/dist/makerkit-docs/server.js.map +1 -0
- package/packages/mcp-servers/dist/makerkit-docs/types.d.ts +74 -0
- package/packages/mcp-servers/dist/makerkit-docs/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/makerkit-docs/types.js +20 -0
- package/packages/mcp-servers/dist/makerkit-docs/types.js.map +1 -0
- package/packages/mcp-servers/dist/onepassword/index.d.ts +2 -0
- package/packages/mcp-servers/dist/onepassword/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/onepassword/index.js +2 -0
- package/packages/mcp-servers/dist/onepassword/index.js.map +1 -0
- package/packages/mcp-servers/dist/onepassword/server.d.ts +2 -0
- package/packages/mcp-servers/dist/onepassword/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/onepassword/server.js +159 -0
- package/packages/mcp-servers/dist/onepassword/server.js.map +1 -0
- package/packages/mcp-servers/dist/onepassword/types.d.ts +55 -0
- package/packages/mcp-servers/dist/onepassword/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/onepassword/types.js +22 -0
- package/packages/mcp-servers/dist/onepassword/types.js.map +1 -0
- package/packages/mcp-servers/dist/playwright/helpers.d.ts +20 -0
- package/packages/mcp-servers/dist/playwright/helpers.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright/helpers.js +31 -0
- package/packages/mcp-servers/dist/playwright/helpers.js.map +1 -0
- package/packages/mcp-servers/dist/playwright/index.d.ts +5 -0
- package/packages/mcp-servers/dist/playwright/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright/index.js +5 -0
- package/packages/mcp-servers/dist/playwright/index.js.map +1 -0
- package/packages/mcp-servers/dist/playwright/server.d.ts +13 -0
- package/packages/mcp-servers/dist/playwright/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright/server.js +1201 -0
- package/packages/mcp-servers/dist/playwright/server.js.map +1 -0
- package/packages/mcp-servers/dist/playwright/types.d.ts +216 -0
- package/packages/mcp-servers/dist/playwright/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright/types.js +172 -0
- package/packages/mcp-servers/dist/playwright/types.js.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/browser-manager.d.ts +39 -0
- package/packages/mcp-servers/dist/playwright-feedback/browser-manager.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/browser-manager.js +71 -0
- package/packages/mcp-servers/dist/playwright-feedback/browser-manager.js.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/index.d.ts +5 -0
- package/packages/mcp-servers/dist/playwright-feedback/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/index.js +5 -0
- package/packages/mcp-servers/dist/playwright-feedback/index.js.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/server.d.ts +34 -0
- package/packages/mcp-servers/dist/playwright-feedback/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/server.js +538 -0
- package/packages/mcp-servers/dist/playwright-feedback/server.js.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/types.d.ts +305 -0
- package/packages/mcp-servers/dist/playwright-feedback/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/playwright-feedback/types.js +123 -0
- package/packages/mcp-servers/dist/playwright-feedback/types.js.map +1 -0
- package/packages/mcp-servers/dist/product-manager/server.d.ts +17 -0
- package/packages/mcp-servers/dist/product-manager/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/product-manager/server.js +690 -0
- package/packages/mcp-servers/dist/product-manager/server.js.map +1 -0
- package/packages/mcp-servers/dist/product-manager/types.d.ts +286 -0
- package/packages/mcp-servers/dist/product-manager/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/product-manager/types.js +99 -0
- package/packages/mcp-servers/dist/product-manager/types.js.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/index.d.ts +7 -0
- package/packages/mcp-servers/dist/programmatic-feedback/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/index.js +7 -0
- package/packages/mcp-servers/dist/programmatic-feedback/index.js.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/sandbox.d.ts +19 -0
- package/packages/mcp-servers/dist/programmatic-feedback/sandbox.d.ts.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/sandbox.js +174 -0
- package/packages/mcp-servers/dist/programmatic-feedback/sandbox.js.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/server.d.ts +35 -0
- package/packages/mcp-servers/dist/programmatic-feedback/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/server.js +465 -0
- package/packages/mcp-servers/dist/programmatic-feedback/server.js.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/types.d.ts +127 -0
- package/packages/mcp-servers/dist/programmatic-feedback/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/programmatic-feedback/types.js +80 -0
- package/packages/mcp-servers/dist/programmatic-feedback/types.js.map +1 -0
- package/packages/mcp-servers/dist/render/index.d.ts +8 -0
- package/packages/mcp-servers/dist/render/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/render/index.js +8 -0
- package/packages/mcp-servers/dist/render/index.js.map +1 -0
- package/packages/mcp-servers/dist/render/server.d.ts +15 -0
- package/packages/mcp-servers/dist/render/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/render/server.js +428 -0
- package/packages/mcp-servers/dist/render/server.js.map +1 -0
- package/packages/mcp-servers/dist/render/types.d.ts +273 -0
- package/packages/mcp-servers/dist/render/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/render/types.js +102 -0
- package/packages/mcp-servers/dist/render/types.js.map +1 -0
- package/packages/mcp-servers/dist/resend/index.d.ts +7 -0
- package/packages/mcp-servers/dist/resend/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/resend/index.js +7 -0
- package/packages/mcp-servers/dist/resend/index.js.map +1 -0
- package/packages/mcp-servers/dist/resend/server.d.ts +15 -0
- package/packages/mcp-servers/dist/resend/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/resend/server.js +298 -0
- package/packages/mcp-servers/dist/resend/server.js.map +1 -0
- package/packages/mcp-servers/dist/resend/types.d.ts +222 -0
- package/packages/mcp-servers/dist/resend/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/resend/types.js +58 -0
- package/packages/mcp-servers/dist/resend/types.js.map +1 -0
- package/packages/mcp-servers/dist/review-queue/index.d.ts +6 -0
- package/packages/mcp-servers/dist/review-queue/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/review-queue/index.js +6 -0
- package/packages/mcp-servers/dist/review-queue/index.js.map +1 -0
- package/packages/mcp-servers/dist/review-queue/server.d.ts +17 -0
- package/packages/mcp-servers/dist/review-queue/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/review-queue/server.js +348 -0
- package/packages/mcp-servers/dist/review-queue/server.js.map +1 -0
- package/packages/mcp-servers/dist/review-queue/types.d.ts +162 -0
- package/packages/mcp-servers/dist/review-queue/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/review-queue/types.js +56 -0
- package/packages/mcp-servers/dist/review-queue/types.js.map +1 -0
- package/packages/mcp-servers/dist/secret-sync/server.d.ts +19 -0
- package/packages/mcp-servers/dist/secret-sync/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/secret-sync/server.js +1139 -0
- package/packages/mcp-servers/dist/secret-sync/server.js.map +1 -0
- package/packages/mcp-servers/dist/secret-sync/types.d.ts +442 -0
- package/packages/mcp-servers/dist/secret-sync/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/secret-sync/types.js +113 -0
- package/packages/mcp-servers/dist/secret-sync/types.js.map +1 -0
- package/packages/mcp-servers/dist/session-events/index.d.ts +5 -0
- package/packages/mcp-servers/dist/session-events/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/session-events/index.js +5 -0
- package/packages/mcp-servers/dist/session-events/index.js.map +1 -0
- package/packages/mcp-servers/dist/session-events/server.d.ts +11 -0
- package/packages/mcp-servers/dist/session-events/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/session-events/server.js +290 -0
- package/packages/mcp-servers/dist/session-events/server.js.map +1 -0
- package/packages/mcp-servers/dist/session-events/types.d.ts +213 -0
- package/packages/mcp-servers/dist/session-events/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/session-events/types.js +69 -0
- package/packages/mcp-servers/dist/session-events/types.js.map +1 -0
- package/packages/mcp-servers/dist/session-restart/index.d.ts +9 -0
- package/packages/mcp-servers/dist/session-restart/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/session-restart/index.js +9 -0
- package/packages/mcp-servers/dist/session-restart/index.js.map +1 -0
- package/packages/mcp-servers/dist/session-restart/server.d.ts +20 -0
- package/packages/mcp-servers/dist/session-restart/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/session-restart/server.js +411 -0
- package/packages/mcp-servers/dist/session-restart/server.js.map +1 -0
- package/packages/mcp-servers/dist/session-restart/types.d.ts +26 -0
- package/packages/mcp-servers/dist/session-restart/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/session-restart/types.js +16 -0
- package/packages/mcp-servers/dist/session-restart/types.js.map +1 -0
- package/packages/mcp-servers/dist/setup-helper/index.d.ts +5 -0
- package/packages/mcp-servers/dist/setup-helper/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/setup-helper/index.js +5 -0
- package/packages/mcp-servers/dist/setup-helper/index.js.map +1 -0
- package/packages/mcp-servers/dist/setup-helper/server.d.ts +14 -0
- package/packages/mcp-servers/dist/setup-helper/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/setup-helper/server.js +454 -0
- package/packages/mcp-servers/dist/setup-helper/server.js.map +1 -0
- package/packages/mcp-servers/dist/setup-helper/types.d.ts +81 -0
- package/packages/mcp-servers/dist/setup-helper/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/setup-helper/types.js +41 -0
- package/packages/mcp-servers/dist/setup-helper/types.js.map +1 -0
- package/packages/mcp-servers/dist/shared/audited-server.d.ts +31 -0
- package/packages/mcp-servers/dist/shared/audited-server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/audited-server.js +126 -0
- package/packages/mcp-servers/dist/shared/audited-server.js.map +1 -0
- package/packages/mcp-servers/dist/shared/constants.d.ts +26 -0
- package/packages/mcp-servers/dist/shared/constants.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/constants.js +41 -0
- package/packages/mcp-servers/dist/shared/constants.js.map +1 -0
- package/packages/mcp-servers/dist/shared/index.d.ts +6 -0
- package/packages/mcp-servers/dist/shared/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/index.js +6 -0
- package/packages/mcp-servers/dist/shared/index.js.map +1 -0
- package/packages/mcp-servers/dist/shared/readonly-db.d.ts +11 -0
- package/packages/mcp-servers/dist/shared/readonly-db.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/readonly-db.js +47 -0
- package/packages/mcp-servers/dist/shared/readonly-db.js.map +1 -0
- package/packages/mcp-servers/dist/shared/resolve-framework.d.ts +20 -0
- package/packages/mcp-servers/dist/shared/resolve-framework.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/resolve-framework.js +65 -0
- package/packages/mcp-servers/dist/shared/resolve-framework.js.map +1 -0
- package/packages/mcp-servers/dist/shared/server.d.ts +86 -0
- package/packages/mcp-servers/dist/shared/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/server.js +291 -0
- package/packages/mcp-servers/dist/shared/server.js.map +1 -0
- package/packages/mcp-servers/dist/shared/types.d.ts +113 -0
- package/packages/mcp-servers/dist/shared/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/shared/types.js +36 -0
- package/packages/mcp-servers/dist/shared/types.js.map +1 -0
- package/packages/mcp-servers/dist/show/server.d.ts +12 -0
- package/packages/mcp-servers/dist/show/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/show/server.js +97 -0
- package/packages/mcp-servers/dist/show/server.js.map +1 -0
- package/packages/mcp-servers/dist/show/types.d.ts +19 -0
- package/packages/mcp-servers/dist/show/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/show/types.js +32 -0
- package/packages/mcp-servers/dist/show/types.js.map +1 -0
- package/packages/mcp-servers/dist/specs-browser/index.d.ts +5 -0
- package/packages/mcp-servers/dist/specs-browser/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/specs-browser/index.js +5 -0
- package/packages/mcp-servers/dist/specs-browser/index.js.map +1 -0
- package/packages/mcp-servers/dist/specs-browser/server.d.ts +13 -0
- package/packages/mcp-servers/dist/specs-browser/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/specs-browser/server.js +692 -0
- package/packages/mcp-servers/dist/specs-browser/server.js.map +1 -0
- package/packages/mcp-servers/dist/specs-browser/types.d.ts +337 -0
- package/packages/mcp-servers/dist/specs-browser/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/specs-browser/types.js +134 -0
- package/packages/mcp-servers/dist/specs-browser/types.js.map +1 -0
- package/packages/mcp-servers/dist/supabase/index.d.ts +10 -0
- package/packages/mcp-servers/dist/supabase/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/supabase/index.js +10 -0
- package/packages/mcp-servers/dist/supabase/index.js.map +1 -0
- package/packages/mcp-servers/dist/supabase/server.d.ts +20 -0
- package/packages/mcp-servers/dist/supabase/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/supabase/server.js +451 -0
- package/packages/mcp-servers/dist/supabase/server.js.map +1 -0
- package/packages/mcp-servers/dist/supabase/types.d.ts +196 -0
- package/packages/mcp-servers/dist/supabase/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/supabase/types.js +76 -0
- package/packages/mcp-servers/dist/supabase/types.js.map +1 -0
- package/packages/mcp-servers/dist/todo-db/index.d.ts +5 -0
- package/packages/mcp-servers/dist/todo-db/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/todo-db/index.js +5 -0
- package/packages/mcp-servers/dist/todo-db/index.js.map +1 -0
- package/packages/mcp-servers/dist/todo-db/server.d.ts +13 -0
- package/packages/mcp-servers/dist/todo-db/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/todo-db/server.js +649 -0
- package/packages/mcp-servers/dist/todo-db/server.js.map +1 -0
- package/packages/mcp-servers/dist/todo-db/types.d.ts +225 -0
- package/packages/mcp-servers/dist/todo-db/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/todo-db/types.js +69 -0
- package/packages/mcp-servers/dist/todo-db/types.js.map +1 -0
- package/packages/mcp-servers/dist/user-feedback/index.d.ts +7 -0
- package/packages/mcp-servers/dist/user-feedback/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/user-feedback/index.js +8 -0
- package/packages/mcp-servers/dist/user-feedback/index.js.map +1 -0
- package/packages/mcp-servers/dist/user-feedback/server.d.ts +25 -0
- package/packages/mcp-servers/dist/user-feedback/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/user-feedback/server.js +914 -0
- package/packages/mcp-servers/dist/user-feedback/server.js.map +1 -0
- package/packages/mcp-servers/dist/user-feedback/types.d.ts +415 -0
- package/packages/mcp-servers/dist/user-feedback/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/user-feedback/types.js +132 -0
- package/packages/mcp-servers/dist/user-feedback/types.js.map +1 -0
- package/packages/mcp-servers/dist/vercel/index.d.ts +9 -0
- package/packages/mcp-servers/dist/vercel/index.d.ts.map +1 -0
- package/packages/mcp-servers/dist/vercel/index.js +9 -0
- package/packages/mcp-servers/dist/vercel/index.js.map +1 -0
- package/packages/mcp-servers/dist/vercel/server.d.ts +17 -0
- package/packages/mcp-servers/dist/vercel/server.d.ts.map +1 -0
- package/packages/mcp-servers/dist/vercel/server.js +265 -0
- package/packages/mcp-servers/dist/vercel/server.js.map +1 -0
- package/packages/mcp-servers/dist/vercel/types.d.ts +189 -0
- package/packages/mcp-servers/dist/vercel/types.d.ts.map +1 -0
- package/packages/mcp-servers/dist/vercel/types.js +65 -0
- package/packages/mcp-servers/dist/vercel/types.js.map +1 -0
- package/packages/mcp-servers/package-lock.json +3765 -0
- package/packages/mcp-servers/package.json +64 -0
- package/packages/mcp-servers/test/reporters/test-failure-reporter.ts +372 -0
- package/packages/mcp-servers/vitest.config.ts +27 -0
- package/scripts/__tests__/README.md +163 -0
- package/scripts/apply-credential-hardening.sh +271 -0
- package/scripts/credential-providers/manual.js +56 -0
- package/scripts/credential-providers/onepassword.js +85 -0
- package/scripts/credential-providers/provider-interface.js +104 -0
- package/scripts/encrypt-credential.js +337 -0
- package/scripts/feedback-launcher.js +338 -0
- package/scripts/feedback-orchestrator.js +373 -0
- package/scripts/fix-mcp-launcher-issues.sh +97 -0
- package/scripts/force-spawn-tasks.js +651 -0
- package/scripts/force-triage-reports.js +560 -0
- package/scripts/generate-protected-actions-spec.js +142 -0
- package/scripts/generate-proxy-certs.sh +158 -0
- package/scripts/grant-chrome-ext-permissions.sh +242 -0
- package/scripts/mcp-launcher.js +125 -0
- package/scripts/merge-settings.cjs +167 -0
- package/scripts/patch-clawd.py +844 -0
- package/scripts/patch-credential-cache.py +313 -0
- package/scripts/patches/credential-file-guard-patched.mjs +573 -0
- package/scripts/patches/credential-file-guard.js.patched +573 -0
- package/scripts/patches/verify-tokenizer.mjs +132 -0
- package/scripts/protect-framework.sh +478 -0
- package/scripts/readme-chrome.template +12 -0
- package/scripts/reap-completed-agents.js +439 -0
- package/scripts/reinstall.sh +86 -0
- package/scripts/resign-node.sh +185 -0
- package/scripts/rotation-proxy.js +656 -0
- package/scripts/rotation-stress-monitor.mjs +862 -0
- package/scripts/setup-automation-service.sh +648 -0
- package/scripts/setup-check.js +251 -0
- package/scripts/watch-claude-version.js +142 -0
- package/specs/framework/CORE-INVARIANTS.md +161 -0
- package/specs/patterns/AGENT-PATTERNS.md +223 -0
- package/specs/patterns/HOOK-PATTERNS.md +242 -0
- package/specs/patterns/MCP-SERVER-PATTERNS.md +144 -0
- package/templates/config/gitignore.template +14 -0
- package/templates/config/merge-chain-check.yml.template +51 -0
- package/templates/config/package.json.template +18 -0
- package/templates/config/pnpm-workspace.yaml +5 -0
- package/templates/config/services.json.template +18 -0
- package/templates/config/tsconfig.base.json +17 -0
- package/templates/scaffold/integrations/_template/.gitkeep +0 -0
- package/templates/scaffold/packages/logger/package.json +17 -0
- package/templates/scaffold/packages/logger/src/logger.ts +44 -0
- package/templates/scaffold/packages/shared/package.json +17 -0
- package/templates/scaffold/packages/shared/src/errors.ts +43 -0
- package/templates/scaffold/products/_product/apps/backend/package.json +21 -0
- package/templates/scaffold/products/_product/apps/backend/src/index.ts +17 -0
- package/templates/scaffold/products/_product/apps/extension/.gitkeep +0 -0
- package/templates/scaffold/products/_product/apps/web/.gitkeep +0 -0
- package/templates/scaffold/specs/global/.gitkeep +0 -0
- package/templates/scaffold/specs/local/.gitkeep +0 -0
- package/templates/scaffold/specs/reference/.gitkeep +0 -0
- package/version.json +15 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PreToolUse Hook: Block --no-verify flag
|
|
4
|
+
*
|
|
5
|
+
* This hook intercepts Bash tool calls and blocks any git commands
|
|
6
|
+
* that include --no-verify or -n flags, which would skip git hooks.
|
|
7
|
+
*
|
|
8
|
+
* Uses Claude Code's permissionDecision JSON output for hard blocking.
|
|
9
|
+
* Supports CTO bypass via bypass-approval-token.json.
|
|
10
|
+
*
|
|
11
|
+
* Input: JSON on stdin from Claude Code PreToolUse event
|
|
12
|
+
* Output: JSON on stdout with permissionDecision (deny/allow)
|
|
13
|
+
*
|
|
14
|
+
* SECURITY: This file should be root-owned via protect-framework.sh
|
|
15
|
+
*
|
|
16
|
+
* @version 3.0.0
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import crypto from 'node:crypto';
|
|
22
|
+
|
|
23
|
+
// Patterns that indicate hook bypass attempts
|
|
24
|
+
const forbiddenPatterns = [
|
|
25
|
+
{ pattern: /--no-verify/i, reason: 'Using --no-verify skips pre-commit hooks (lint, deputy-cto review)' },
|
|
26
|
+
{ pattern: /\bgit\b.*\s-n\s/, reason: 'The -n flag is shorthand for --no-verify, which skips pre-commit hooks' },
|
|
27
|
+
{ pattern: /\bgit\b.*\s-n$/, reason: 'The -n flag is shorthand for --no-verify, which skips pre-commit hooks' },
|
|
28
|
+
{ pattern: /--(no-)?gpg-sign/i, reason: 'Skipping GPG signing bypasses commit verification' },
|
|
29
|
+
{ pattern: /\bgit\s+config\s+.*core\.hooksPath/i, reason: 'Changing core.hooksPath redirects or disables git hooks' },
|
|
30
|
+
{ pattern: /\brm\s+(-rf?|--recursive)?\s+.*\.husky/i, reason: 'Deleting .husky/ removes the git hook infrastructure' },
|
|
31
|
+
{ pattern: /\brm\s+(-rf?|--recursive)?\s+.*\.claude\/hooks/i, reason: 'Deleting .claude/hooks/ removes Claude Code hook enforcement' },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// Additional patterns for weakening lint
|
|
35
|
+
const lintWeakeningPatterns = [
|
|
36
|
+
{ pattern: /eslint.*--quiet/i, reason: 'The --quiet flag suppresses ESLint warnings' },
|
|
37
|
+
{ pattern: /eslint.*--max-warnings\s+[1-9]/i, reason: 'Allowing warnings violates zero-tolerance lint policy' },
|
|
38
|
+
{ pattern: /eslint.*--no-error-on-unmatched-pattern/i, reason: 'This flag can silently skip linting of files' },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Patterns blocking direct credential/secret access via CLI tools
|
|
42
|
+
// Even if OP_SERVICE_ACCOUNT_TOKEN is in the shell environment, agents cannot use
|
|
43
|
+
// the 1Password CLI to extract secrets. Secrets flow only through MCP server env
|
|
44
|
+
// fields (which are spawned by MCP infrastructure, not by Bash).
|
|
45
|
+
const credentialAccessPatterns = [
|
|
46
|
+
{ pattern: /\bop\s+(run|read|item|inject|signin|signout|whoami|vault|document|connect|account|group|user|service-account|events-api|plugin)\b/i,
|
|
47
|
+
reason: '1Password CLI access blocked — secrets must only flow through MCP server env fields, not Bash' },
|
|
48
|
+
{ pattern: /\bop\s+--/i,
|
|
49
|
+
reason: '1Password CLI access blocked — global op flags indicate CLI usage' },
|
|
50
|
+
{ pattern: /(?:^|[\/\s])op\s+(run|read|item|inject|signin|signout|whoami|vault|document|connect|account|group|user|service-account|events-api|plugin)\b/i,
|
|
51
|
+
reason: '1Password CLI access blocked (full-path variant) — secrets must only flow through MCP server env fields' },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load the protection key for HMAC verification.
|
|
56
|
+
* @param {string} projectDir
|
|
57
|
+
* @returns {string|null} Base64-encoded key or null
|
|
58
|
+
*/
|
|
59
|
+
function loadProtectionKey(projectDir) {
|
|
60
|
+
try {
|
|
61
|
+
const keyPath = path.join(projectDir, '.claude', 'protection-key');
|
|
62
|
+
if (!fs.existsSync(keyPath)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return fs.readFileSync(keyPath, 'utf8').trim();
|
|
66
|
+
} catch (err) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Compute HMAC-SHA256 over pipe-delimited fields.
|
|
73
|
+
* @param {string} key - Base64-encoded key
|
|
74
|
+
* @param {...string} fields - Fields to include in HMAC
|
|
75
|
+
* @returns {string} Hex-encoded HMAC
|
|
76
|
+
*/
|
|
77
|
+
function computeHmac(key, ...fields) {
|
|
78
|
+
const keyBuffer = Buffer.from(key, 'base64');
|
|
79
|
+
return crypto.createHmac('sha256', keyBuffer)
|
|
80
|
+
.update(fields.join('|'))
|
|
81
|
+
.digest('hex');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check if a valid, HMAC-verified CTO bypass token exists.
|
|
86
|
+
* Consumes the token on successful verification (one-time use).
|
|
87
|
+
*
|
|
88
|
+
* SECURITY FIX (H1): Now verifies HMAC-SHA256 signature to prevent agent forgery.
|
|
89
|
+
* Previously only checked expiry, allowing agents to write fake tokens.
|
|
90
|
+
*
|
|
91
|
+
* SECURITY FIX (H2): Token is consumed (deleted) on use, preventing reuse
|
|
92
|
+
* across different blocked actions.
|
|
93
|
+
*/
|
|
94
|
+
function hasValidBypassToken(projectDir) {
|
|
95
|
+
try {
|
|
96
|
+
const tokenPath = path.join(projectDir, '.claude', 'bypass-approval-token.json');
|
|
97
|
+
const clearToken = () => { try { fs.writeFileSync(tokenPath, '{}'); } catch { /* ignore */ } };
|
|
98
|
+
|
|
99
|
+
if (!fs.existsSync(tokenPath)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const token = JSON.parse(fs.readFileSync(tokenPath, 'utf-8'));
|
|
104
|
+
|
|
105
|
+
// Empty object means token was consumed (overwrite pattern for sticky-bit compat)
|
|
106
|
+
if (!token.code && !token.request_id && !token.expires_timestamp) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check expiry
|
|
111
|
+
if (token.expires_timestamp && Date.now() > token.expires_timestamp) {
|
|
112
|
+
// Clean up expired token
|
|
113
|
+
clearToken();
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (token.expires_at && new Date(token.expires_at).getTime() < Date.now()) {
|
|
117
|
+
clearToken();
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Verify required fields
|
|
122
|
+
if (!token.code || !token.request_id || !token.expires_timestamp) {
|
|
123
|
+
console.error('[block-no-verify] FORGERY DETECTED: Token missing required fields. Clearing.');
|
|
124
|
+
clearToken();
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// HMAC verification: ensure token was created by the bypass-approval-hook
|
|
129
|
+
const key = loadProtectionKey(projectDir);
|
|
130
|
+
if (key) {
|
|
131
|
+
if (!token.hmac) {
|
|
132
|
+
console.error('[block-no-verify] FORGERY DETECTED: Token missing HMAC field. Clearing.');
|
|
133
|
+
clearToken();
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
const expectedHmac = computeHmac(key, token.code, token.request_id, String(token.expires_timestamp), 'bypass-approved');
|
|
137
|
+
if (token.hmac !== expectedHmac) {
|
|
138
|
+
console.error('[block-no-verify] FORGERY DETECTED: Invalid HMAC on bypass token. Clearing.');
|
|
139
|
+
clearToken();
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
// G001 Fail-Closed: No protection key available -- cannot verify token authenticity
|
|
144
|
+
console.error('[block-no-verify] G001 FAIL-CLOSED: Protection key missing, cannot verify bypass token. Rejecting.');
|
|
145
|
+
clearToken();
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Token is valid - consume it (one-time use)
|
|
150
|
+
clearToken();
|
|
151
|
+
|
|
152
|
+
return true;
|
|
153
|
+
} catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Block the tool call using Claude Code's permissionDecision system.
|
|
160
|
+
*/
|
|
161
|
+
function blockCommand(command, reason, category, bypassContext) {
|
|
162
|
+
const bypassInstructions = [
|
|
163
|
+
'',
|
|
164
|
+
' HOW TO REQUEST A CTO BYPASS (if you have a valid reason):',
|
|
165
|
+
'',
|
|
166
|
+
' 1. Call: mcp__deputy-cto__request_bypass({',
|
|
167
|
+
` reason: "${bypassContext}",`,
|
|
168
|
+
' reporting_agent: "your-agent-name",',
|
|
169
|
+
' blocked_by: "block-no-verify hook"',
|
|
170
|
+
' })',
|
|
171
|
+
'',
|
|
172
|
+
' 2. You will receive a 6-character bypass code (e.g. X7K9M2)',
|
|
173
|
+
'',
|
|
174
|
+
' 3. STOP and ask the CTO to type in chat:',
|
|
175
|
+
' APPROVE BYPASS <CODE>',
|
|
176
|
+
'',
|
|
177
|
+
' 4. After CTO approval, retry your command.',
|
|
178
|
+
' The bypass token is valid for 5 minutes (one-time use).',
|
|
179
|
+
].join('\n');
|
|
180
|
+
|
|
181
|
+
const fullReason = [
|
|
182
|
+
`BLOCKED: ${category}`,
|
|
183
|
+
'',
|
|
184
|
+
`Why: ${reason}`,
|
|
185
|
+
'',
|
|
186
|
+
`Command: ${command.substring(0, 100)}${command.length > 100 ? '...' : ''}`,
|
|
187
|
+
'',
|
|
188
|
+
bypassInstructions,
|
|
189
|
+
].join('\n');
|
|
190
|
+
|
|
191
|
+
// Output JSON to stdout for Claude Code's permission system (hard deny)
|
|
192
|
+
console.log(JSON.stringify({
|
|
193
|
+
hookSpecificOutput: {
|
|
194
|
+
hookEventName: 'PreToolUse',
|
|
195
|
+
permissionDecision: 'deny',
|
|
196
|
+
permissionDecisionReason: fullReason,
|
|
197
|
+
},
|
|
198
|
+
}));
|
|
199
|
+
|
|
200
|
+
// Also output to stderr for visibility
|
|
201
|
+
console.error('');
|
|
202
|
+
console.error('══════════════════════════════════════════════════════════════');
|
|
203
|
+
console.error(` COMMAND BLOCKED: ${category}`);
|
|
204
|
+
console.error('══════════════════════════════════════════════════════════════');
|
|
205
|
+
console.error('');
|
|
206
|
+
console.error(` Why: ${reason}`);
|
|
207
|
+
console.error('');
|
|
208
|
+
console.error(` Command: ${command.substring(0, 100)}${command.length > 100 ? '...' : ''}`);
|
|
209
|
+
console.error('');
|
|
210
|
+
console.error(' ──────────────────────────────────────────────────────────');
|
|
211
|
+
console.error(bypassInstructions);
|
|
212
|
+
console.error(' ──────────────────────────────────────────────────────────');
|
|
213
|
+
console.error('');
|
|
214
|
+
console.error('══════════════════════════════════════════════════════════════');
|
|
215
|
+
console.error('');
|
|
216
|
+
|
|
217
|
+
process.exit(0); // Exit 0 - the JSON output handles the deny
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Read JSON input from stdin
|
|
221
|
+
let input = '';
|
|
222
|
+
|
|
223
|
+
process.stdin.on('data', (chunk) => {
|
|
224
|
+
input += chunk.toString();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
process.stdin.on('end', () => {
|
|
228
|
+
try {
|
|
229
|
+
const hookInput = JSON.parse(input);
|
|
230
|
+
|
|
231
|
+
const toolName = hookInput.tool_name;
|
|
232
|
+
const toolInput = hookInput.tool_input || {};
|
|
233
|
+
const projectDir = hookInput.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
234
|
+
|
|
235
|
+
// Only check Bash commands
|
|
236
|
+
if (toolName !== 'Bash') {
|
|
237
|
+
process.exit(0);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const command = toolInput.command || '';
|
|
241
|
+
|
|
242
|
+
// Check if CTO has granted a bypass
|
|
243
|
+
if (hasValidBypassToken(projectDir)) {
|
|
244
|
+
console.error('[block-no-verify] Active CTO bypass token found - allowing command through');
|
|
245
|
+
process.exit(0);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Check for forbidden patterns
|
|
249
|
+
for (const { pattern, reason } of forbiddenPatterns) {
|
|
250
|
+
if (pattern.test(command)) {
|
|
251
|
+
blockCommand(
|
|
252
|
+
command,
|
|
253
|
+
reason,
|
|
254
|
+
'Security Hook Bypass Attempt',
|
|
255
|
+
'Explain why --no-verify is needed'
|
|
256
|
+
);
|
|
257
|
+
return; // blockCommand calls process.exit, but just in case
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Check for lint weakening
|
|
262
|
+
for (const { pattern, reason } of lintWeakeningPatterns) {
|
|
263
|
+
if (pattern.test(command)) {
|
|
264
|
+
blockCommand(
|
|
265
|
+
command,
|
|
266
|
+
reason,
|
|
267
|
+
'Lint Enforcement Weakening Attempt',
|
|
268
|
+
'Explain why lint relaxation is needed'
|
|
269
|
+
);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Check for credential/secret access via CLI
|
|
275
|
+
for (const { pattern, reason } of credentialAccessPatterns) {
|
|
276
|
+
if (pattern.test(command)) {
|
|
277
|
+
blockCommand(
|
|
278
|
+
command,
|
|
279
|
+
reason,
|
|
280
|
+
'Credential Access Attempt',
|
|
281
|
+
'Explain why direct 1Password CLI access is needed'
|
|
282
|
+
);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Command is allowed
|
|
288
|
+
process.exit(0);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
// G001: fail-closed on parse errors — output deny JSON so Claude Code blocks the action
|
|
291
|
+
console.error(`[block-no-verify] G001 FAIL-CLOSED: Error parsing input: ${err.message}`);
|
|
292
|
+
console.log(JSON.stringify({
|
|
293
|
+
hookSpecificOutput: {
|
|
294
|
+
hookEventName: 'PreToolUse',
|
|
295
|
+
permissionDecision: 'deny',
|
|
296
|
+
permissionDecisionReason: `G001 FAIL-CLOSED: Hook error - ${err.message}`,
|
|
297
|
+
},
|
|
298
|
+
}));
|
|
299
|
+
process.exit(0);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Bypass Approval Hook (UserPromptSubmit)
|
|
4
|
+
*
|
|
5
|
+
* Watches for CTO bypass approval messages in the format:
|
|
6
|
+
* APPROVE BYPASS <6-char-code>
|
|
7
|
+
*
|
|
8
|
+
* When detected, validates the code exists in pending bypass requests
|
|
9
|
+
* and writes an approval token that execute_bypass can verify.
|
|
10
|
+
*
|
|
11
|
+
* This ensures only the CTO (human user) can approve bypasses by typing
|
|
12
|
+
* the approval phrase - agents cannot trigger UserPromptSubmit hooks.
|
|
13
|
+
*
|
|
14
|
+
* @version 1.0.0
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'fs';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import crypto from 'crypto';
|
|
20
|
+
import { fileURLToPath } from 'url';
|
|
21
|
+
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = path.dirname(__filename);
|
|
24
|
+
|
|
25
|
+
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || path.resolve(__dirname, '..', '..');
|
|
26
|
+
const DEPUTY_CTO_DB = path.join(PROJECT_DIR, '.claude', 'deputy-cto.db');
|
|
27
|
+
const APPROVAL_TOKEN_FILE = path.join(PROJECT_DIR, '.claude', 'bypass-approval-token.json');
|
|
28
|
+
const PROTECTION_KEY_PATH = path.join(PROJECT_DIR, '.claude', 'protection-key');
|
|
29
|
+
|
|
30
|
+
// Token expires after 5 minutes
|
|
31
|
+
const TOKEN_EXPIRY_MS = 5 * 60 * 1000;
|
|
32
|
+
|
|
33
|
+
// Pattern to match: APPROVE BYPASS XXXXXX (6 alphanumeric chars)
|
|
34
|
+
const APPROVAL_PATTERN = /APPROVE\s+BYPASS\s+([A-Z0-9]{6})/i;
|
|
35
|
+
|
|
36
|
+
// Pattern to match: APPROVE HOTFIX XXXXXX (6 alphanumeric chars)
|
|
37
|
+
const HOTFIX_PATTERN = /APPROVE\s+HOTFIX\s+([A-Z0-9]{6})/i;
|
|
38
|
+
const HOTFIX_APPROVAL_TOKEN_FILE = path.join(PROJECT_DIR, '.claude', 'hotfix-approval-token.json');
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read user message from stdin (passed by Claude Code for UserPromptSubmit hooks)
|
|
42
|
+
*/
|
|
43
|
+
async function readUserMessage() {
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
let data = '';
|
|
46
|
+
|
|
47
|
+
// Set a short timeout in case no data is available
|
|
48
|
+
const timeout = setTimeout(() => {
|
|
49
|
+
resolve(data.trim());
|
|
50
|
+
}, 100);
|
|
51
|
+
|
|
52
|
+
process.stdin.setEncoding('utf8');
|
|
53
|
+
process.stdin.on('data', (chunk) => {
|
|
54
|
+
data += chunk;
|
|
55
|
+
});
|
|
56
|
+
process.stdin.on('end', () => {
|
|
57
|
+
clearTimeout(timeout);
|
|
58
|
+
resolve(data.trim());
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// If stdin is not readable, resolve immediately
|
|
62
|
+
if (!process.stdin.readable) {
|
|
63
|
+
clearTimeout(timeout);
|
|
64
|
+
resolve('');
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Try to import better-sqlite3 and check if bypass code is valid
|
|
71
|
+
*/
|
|
72
|
+
async function validateBypassCode(code) {
|
|
73
|
+
try {
|
|
74
|
+
const Database = (await import('better-sqlite3')).default;
|
|
75
|
+
|
|
76
|
+
if (!fs.existsSync(DEPUTY_CTO_DB)) {
|
|
77
|
+
return { valid: false, reason: 'Database not found' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const db = new Database(DEPUTY_CTO_DB, { readonly: true });
|
|
81
|
+
|
|
82
|
+
// Look for pending bypass-request with this code in context field
|
|
83
|
+
const question = db.prepare(`
|
|
84
|
+
SELECT id, title, created_at FROM questions
|
|
85
|
+
WHERE type = 'bypass-request'
|
|
86
|
+
AND status = 'pending'
|
|
87
|
+
AND context = ?
|
|
88
|
+
`).get(code);
|
|
89
|
+
|
|
90
|
+
db.close();
|
|
91
|
+
|
|
92
|
+
if (!question) {
|
|
93
|
+
return { valid: false, reason: 'No pending bypass request with this code' };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
valid: true,
|
|
98
|
+
request_id: question.id,
|
|
99
|
+
title: question.title,
|
|
100
|
+
created_at: question.created_at
|
|
101
|
+
};
|
|
102
|
+
} catch (err) {
|
|
103
|
+
return { valid: false, reason: `Database error: ${err.message}` };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Try to import better-sqlite3 and check if hotfix code is valid
|
|
109
|
+
*/
|
|
110
|
+
async function validateHotfixCode(code) {
|
|
111
|
+
try {
|
|
112
|
+
const Database = (await import('better-sqlite3')).default;
|
|
113
|
+
|
|
114
|
+
if (!fs.existsSync(DEPUTY_CTO_DB)) {
|
|
115
|
+
return { valid: false, reason: 'Database not found' };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const db = new Database(DEPUTY_CTO_DB, { readonly: true });
|
|
119
|
+
|
|
120
|
+
const row = db.prepare(`
|
|
121
|
+
SELECT id, code, commits_json, created_at, expires_at FROM hotfix_requests
|
|
122
|
+
WHERE code = ? AND status = 'pending' AND expires_at > datetime('now')
|
|
123
|
+
`).get(code);
|
|
124
|
+
|
|
125
|
+
db.close();
|
|
126
|
+
|
|
127
|
+
if (!row) {
|
|
128
|
+
return { valid: false, reason: 'No pending hotfix request with this code' };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
valid: true,
|
|
133
|
+
request_id: row.id,
|
|
134
|
+
code: row.code,
|
|
135
|
+
expires_at: row.expires_at,
|
|
136
|
+
};
|
|
137
|
+
} catch (err) {
|
|
138
|
+
return { valid: false, reason: `Database error: ${err.message}` };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Write hotfix approval token with HMAC signature.
|
|
144
|
+
*/
|
|
145
|
+
function writeHotfixApprovalToken(code, requestId, expiresAt) {
|
|
146
|
+
const key = loadProtectionKey();
|
|
147
|
+
const hmac = key ? computeHmac(key, code, String(requestId), expiresAt, 'hotfix-approved') : undefined;
|
|
148
|
+
|
|
149
|
+
const token = {
|
|
150
|
+
code,
|
|
151
|
+
request_id: requestId,
|
|
152
|
+
created_at: new Date().toISOString(),
|
|
153
|
+
expires_at: expiresAt,
|
|
154
|
+
...(hmac && { hmac }),
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
fs.writeFileSync(HOTFIX_APPROVAL_TOKEN_FILE, JSON.stringify(token, null, 2));
|
|
159
|
+
return true;
|
|
160
|
+
} catch (err) {
|
|
161
|
+
console.error(`[bypass-approval] Failed to write hotfix token: ${err.message}`);
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Mark the hotfix request as approved in the database.
|
|
168
|
+
*/
|
|
169
|
+
async function markHotfixApproved(requestId) {
|
|
170
|
+
try {
|
|
171
|
+
const Database = (await import('better-sqlite3')).default;
|
|
172
|
+
const db = new Database(DEPUTY_CTO_DB);
|
|
173
|
+
db.prepare("UPDATE hotfix_requests SET status = 'approved' WHERE id = ?").run(requestId);
|
|
174
|
+
db.close();
|
|
175
|
+
} catch (err) {
|
|
176
|
+
console.error(`[bypass-approval] Failed to mark hotfix approved: ${err.message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Load the protection key for HMAC signing.
|
|
182
|
+
* @returns {string|null} Base64-encoded key or null
|
|
183
|
+
*/
|
|
184
|
+
function loadProtectionKey() {
|
|
185
|
+
try {
|
|
186
|
+
if (!fs.existsSync(PROTECTION_KEY_PATH)) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
return fs.readFileSync(PROTECTION_KEY_PATH, 'utf8').trim();
|
|
190
|
+
} catch (err) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Compute HMAC-SHA256 over pipe-delimited fields.
|
|
197
|
+
* @param {string} key - Base64-encoded key
|
|
198
|
+
* @param {...string} fields - Fields to include in HMAC
|
|
199
|
+
* @returns {string} Hex-encoded HMAC
|
|
200
|
+
*/
|
|
201
|
+
function computeHmac(key, ...fields) {
|
|
202
|
+
const keyBuffer = Buffer.from(key, 'base64');
|
|
203
|
+
return crypto.createHmac('sha256', keyBuffer)
|
|
204
|
+
.update(fields.join('|'))
|
|
205
|
+
.digest('hex');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Write approval token with HMAC signature to prevent forgery.
|
|
210
|
+
*
|
|
211
|
+
* SECURITY FIX (H1): Token now includes HMAC-SHA256 signature computed from
|
|
212
|
+
* code, request_id, and expires_timestamp using the protection key.
|
|
213
|
+
* block-no-verify.js verifies this signature before accepting the token.
|
|
214
|
+
*/
|
|
215
|
+
function writeApprovalToken(code, requestId, userMessage) {
|
|
216
|
+
const now = Date.now();
|
|
217
|
+
const expiresTimestamp = now + TOKEN_EXPIRY_MS;
|
|
218
|
+
|
|
219
|
+
// Compute HMAC signature to prevent agent forgery
|
|
220
|
+
const key = loadProtectionKey();
|
|
221
|
+
const hmac = key ? computeHmac(key, code, requestId, String(expiresTimestamp), 'bypass-approved') : undefined;
|
|
222
|
+
|
|
223
|
+
const token = {
|
|
224
|
+
code,
|
|
225
|
+
request_id: requestId,
|
|
226
|
+
user_message: userMessage,
|
|
227
|
+
created_at: new Date(now).toISOString(),
|
|
228
|
+
expires_at: new Date(expiresTimestamp).toISOString(),
|
|
229
|
+
expires_timestamp: expiresTimestamp,
|
|
230
|
+
...(hmac && { hmac }),
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
fs.writeFileSync(APPROVAL_TOKEN_FILE, JSON.stringify(token, null, 2));
|
|
235
|
+
return true;
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.error(`[bypass-approval] Failed to write token: ${err.message}`);
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Main entry point
|
|
244
|
+
*/
|
|
245
|
+
async function main() {
|
|
246
|
+
const userMessage = await readUserMessage();
|
|
247
|
+
|
|
248
|
+
if (!userMessage) {
|
|
249
|
+
// No message, nothing to do
|
|
250
|
+
process.exit(0);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Skip for slash commands (contain GENTYR sentinel markers)
|
|
254
|
+
if (userMessage.includes('<!-- HOOK:GENTYR:')) {
|
|
255
|
+
process.exit(0);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Check if message matches bypass approval pattern
|
|
259
|
+
const match = userMessage.match(APPROVAL_PATTERN);
|
|
260
|
+
|
|
261
|
+
if (match) {
|
|
262
|
+
const code = match[1].toUpperCase();
|
|
263
|
+
|
|
264
|
+
const validation = await validateBypassCode(code);
|
|
265
|
+
|
|
266
|
+
if (!validation.valid) {
|
|
267
|
+
console.error(`[bypass-approval] Invalid bypass code "${code}": ${validation.reason}`);
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const written = writeApprovalToken(code, validation.request_id, userMessage);
|
|
272
|
+
|
|
273
|
+
if (written) {
|
|
274
|
+
console.error(`[bypass-approval] Bypass approved for code ${code}`);
|
|
275
|
+
console.error(`[bypass-approval] Request: ${validation.title}`);
|
|
276
|
+
console.error(`[bypass-approval] Token valid for 5 minutes`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
process.exit(0);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Check if message matches hotfix approval pattern
|
|
283
|
+
const hotfixMatch = userMessage.match(HOTFIX_PATTERN);
|
|
284
|
+
|
|
285
|
+
if (hotfixMatch) {
|
|
286
|
+
const code = hotfixMatch[1].toUpperCase();
|
|
287
|
+
|
|
288
|
+
const validation = await validateHotfixCode(code);
|
|
289
|
+
|
|
290
|
+
if (!validation.valid) {
|
|
291
|
+
console.error(`[bypass-approval] Invalid hotfix code "${code}": ${validation.reason}`);
|
|
292
|
+
process.exit(0);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const written = writeHotfixApprovalToken(code, validation.request_id, validation.expires_at);
|
|
296
|
+
|
|
297
|
+
if (written) {
|
|
298
|
+
await markHotfixApproved(validation.request_id);
|
|
299
|
+
console.error(`[bypass-approval] Hotfix approved for code ${code}`);
|
|
300
|
+
console.error(`[bypass-approval] Token valid until ${validation.expires_at}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
process.exit(0);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Not an approval message, pass through silently
|
|
307
|
+
process.exit(0);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
main().catch((err) => {
|
|
311
|
+
console.error(`[bypass-approval] Error: ${err.message}`);
|
|
312
|
+
process.exit(0); // Don't block on errors
|
|
313
|
+
});
|