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,859 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CTO Report MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Provides comprehensive metrics and status reports for CTO oversight.
|
|
6
|
+
* Aggregates data from session JSONL files, todo-db, deputy-cto, agent-reports
|
|
7
|
+
* (database: cto-reports.db), and agent-tracker.
|
|
8
|
+
*
|
|
9
|
+
* Protocol: JSON-RPC 2.0 over stdin/stdout (stdio MCP)
|
|
10
|
+
*
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import * as os from 'os';
|
|
16
|
+
import { McpServer } from '../shared/server.js';
|
|
17
|
+
import { openReadonlyDb } from '../shared/readonly-db.js';
|
|
18
|
+
import { GetReportArgsSchema, GetSessionMetricsArgsSchema, GetTaskMetricsArgsSchema, } from './types.js';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Configuration
|
|
21
|
+
// ============================================================================
|
|
22
|
+
const PROJECT_DIR = path.resolve(process.env['CLAUDE_PROJECT_DIR'] || process.cwd());
|
|
23
|
+
const TODO_DB_PATH = path.join(PROJECT_DIR, '.claude', 'todo.db');
|
|
24
|
+
const DEPUTY_CTO_DB_PATH = path.join(PROJECT_DIR, '.claude', 'deputy-cto.db');
|
|
25
|
+
const CTO_REPORTS_DB_PATH = path.join(PROJECT_DIR, '.claude', 'cto-reports.db');
|
|
26
|
+
const AUTONOMOUS_CONFIG_PATH = path.join(PROJECT_DIR, '.claude', 'autonomous-mode.json');
|
|
27
|
+
const AUTOMATION_STATE_PATH = path.join(PROJECT_DIR, '.claude', 'hourly-automation-state.json');
|
|
28
|
+
const KEY_ROTATION_STATE_PATH = path.join(os.homedir(), '.claude', 'api-key-rotation.json');
|
|
29
|
+
const AGENT_TRACKER_PATH = path.join(PROJECT_DIR, '.claude', 'state', 'agent-tracker-history.json');
|
|
30
|
+
const AUTOMATION_CONFIG_PATH = path.join(PROJECT_DIR, '.claude', 'state', 'automation-config.json');
|
|
31
|
+
const CREDENTIALS_PATH = path.join(os.homedir(), '.claude', '.credentials.json');
|
|
32
|
+
const ANTHROPIC_API_URL = 'https://api.anthropic.com/api/oauth/usage';
|
|
33
|
+
const ANTHROPIC_BETA_HEADER = 'oauth-2025-04-20';
|
|
34
|
+
const COOLDOWN_MINUTES = 55;
|
|
35
|
+
// Protected files for system health check
|
|
36
|
+
const PROTECTED_FILES = [
|
|
37
|
+
path.join(PROJECT_DIR, '.claude', 'hooks', 'pre-commit-review.js'),
|
|
38
|
+
path.join(PROJECT_DIR, 'eslint.config.js'),
|
|
39
|
+
path.join(PROJECT_DIR, '.husky', 'pre-commit'),
|
|
40
|
+
];
|
|
41
|
+
// Claude session directory - path format: ~/.claude/projects/-{project-path}
|
|
42
|
+
// Claude Code replaces all non-alphanumeric characters with hyphens
|
|
43
|
+
function getSessionDir() {
|
|
44
|
+
const projectPath = PROJECT_DIR.replace(/[^a-zA-Z0-9]/g, '-').replace(/^-/, '');
|
|
45
|
+
return path.join(os.homedir(), '.claude', 'projects', `-${projectPath}`);
|
|
46
|
+
}
|
|
47
|
+
function calculateHoursUntil(isoDate) {
|
|
48
|
+
const resetTime = new Date(isoDate).getTime();
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const hoursUntil = (resetTime - now) / (1000 * 60 * 60);
|
|
51
|
+
return Math.max(0, Math.round(hoursUntil * 10) / 10);
|
|
52
|
+
}
|
|
53
|
+
function parseBucket(bucket) {
|
|
54
|
+
if (!bucket) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
utilization: bucket.utilization,
|
|
59
|
+
resets_at: bucket.resets_at,
|
|
60
|
+
resets_in_hours: calculateHoursUntil(bucket.resets_at),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get an access token from available sources.
|
|
65
|
+
* Checks rotation state first (project-level, accumulates keys from multiple accounts),
|
|
66
|
+
* then falls back to credentials file (user-level, current session only).
|
|
67
|
+
*/
|
|
68
|
+
function getAccessToken() {
|
|
69
|
+
// Source 1: Rotation state (project-level, has accumulated keys)
|
|
70
|
+
if (fs.existsSync(KEY_ROTATION_STATE_PATH)) {
|
|
71
|
+
try {
|
|
72
|
+
const state = JSON.parse(fs.readFileSync(KEY_ROTATION_STATE_PATH, 'utf8'));
|
|
73
|
+
if (state?.version === 1 && state.keys) {
|
|
74
|
+
// Prefer the active key
|
|
75
|
+
const activeToken = state.active_key_id ? state.keys[state.active_key_id]?.accessToken : undefined;
|
|
76
|
+
if (activeToken)
|
|
77
|
+
return activeToken;
|
|
78
|
+
// Fall back to any key with a token (prefer active, then try any)
|
|
79
|
+
let fallbackToken = null;
|
|
80
|
+
for (const keyData of Object.values(state.keys)) {
|
|
81
|
+
if (keyData.accessToken) {
|
|
82
|
+
if (keyData.status === 'active')
|
|
83
|
+
return keyData.accessToken;
|
|
84
|
+
if (!fallbackToken)
|
|
85
|
+
fallbackToken = keyData.accessToken;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (fallbackToken)
|
|
89
|
+
return fallbackToken;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Silently fall through to next source
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Source 2: Credentials file (user-level, current session)
|
|
97
|
+
if (fs.existsSync(CREDENTIALS_PATH)) {
|
|
98
|
+
try {
|
|
99
|
+
const creds = JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));
|
|
100
|
+
if (creds.claudeAiOauth?.accessToken) {
|
|
101
|
+
if (creds.claudeAiOauth.expiresAt && creds.claudeAiOauth.expiresAt < Date.now()) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return creds.claudeAiOauth.accessToken;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Silently return null
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
async function getQuotaStatus() {
|
|
114
|
+
const emptyStatus = {
|
|
115
|
+
five_hour: null,
|
|
116
|
+
seven_day: null,
|
|
117
|
+
extra_usage_enabled: false,
|
|
118
|
+
error: null,
|
|
119
|
+
};
|
|
120
|
+
const accessToken = getAccessToken();
|
|
121
|
+
if (!accessToken) {
|
|
122
|
+
return { ...emptyStatus, error: 'No credentials found' };
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const response = await fetch(ANTHROPIC_API_URL, {
|
|
126
|
+
method: 'GET',
|
|
127
|
+
headers: {
|
|
128
|
+
Authorization: `Bearer ${accessToken}`,
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
'User-Agent': 'claude-code/2.1.14',
|
|
131
|
+
'anthropic-beta': ANTHROPIC_BETA_HEADER,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
return { ...emptyStatus, error: `API error: ${response.status}` };
|
|
136
|
+
}
|
|
137
|
+
const data = await response.json();
|
|
138
|
+
return {
|
|
139
|
+
five_hour: parseBucket(data.five_hour),
|
|
140
|
+
seven_day: parseBucket(data.seven_day),
|
|
141
|
+
extra_usage_enabled: data.extra_usage?.is_enabled ?? false,
|
|
142
|
+
error: null,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
147
|
+
return { ...emptyStatus, error: `Fetch error: ${message}` };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function getTokenUsage(hours) {
|
|
151
|
+
const sessionDir = getSessionDir();
|
|
152
|
+
const since = Date.now() - (hours * 60 * 60 * 1000);
|
|
153
|
+
const totals = {
|
|
154
|
+
input: 0,
|
|
155
|
+
output: 0,
|
|
156
|
+
cache_read: 0,
|
|
157
|
+
cache_creation: 0,
|
|
158
|
+
total: 0,
|
|
159
|
+
};
|
|
160
|
+
if (!fs.existsSync(sessionDir)) {
|
|
161
|
+
return totals;
|
|
162
|
+
}
|
|
163
|
+
const files = fs.readdirSync(sessionDir).filter(f => f.endsWith('.jsonl'));
|
|
164
|
+
for (const file of files) {
|
|
165
|
+
const filePath = path.join(sessionDir, file);
|
|
166
|
+
// Check file modification time first - skip files not modified in time range
|
|
167
|
+
const stat = fs.statSync(filePath);
|
|
168
|
+
if (stat.mtime.getTime() < since) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
172
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
173
|
+
for (const line of lines) {
|
|
174
|
+
try {
|
|
175
|
+
const entry = JSON.parse(line);
|
|
176
|
+
// Check timestamp
|
|
177
|
+
if (entry.timestamp) {
|
|
178
|
+
const entryTime = new Date(entry.timestamp).getTime();
|
|
179
|
+
if (entryTime < since) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Extract usage
|
|
184
|
+
const usage = entry.message?.usage;
|
|
185
|
+
if (usage) {
|
|
186
|
+
totals.input += usage.input_tokens || 0;
|
|
187
|
+
totals.output += usage.output_tokens || 0;
|
|
188
|
+
totals.cache_read += usage.cache_read_input_tokens || 0;
|
|
189
|
+
totals.cache_creation += usage.cache_creation_input_tokens || 0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Skip malformed JSONL lines
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
totals.total = totals.input + totals.output + totals.cache_read + totals.cache_creation;
|
|
198
|
+
return totals;
|
|
199
|
+
}
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Autonomous Mode Status
|
|
202
|
+
// ============================================================================
|
|
203
|
+
function getAutonomousModeStatus() {
|
|
204
|
+
let enabled = false;
|
|
205
|
+
// Get config
|
|
206
|
+
if (fs.existsSync(AUTONOMOUS_CONFIG_PATH)) {
|
|
207
|
+
const config = JSON.parse(fs.readFileSync(AUTONOMOUS_CONFIG_PATH, 'utf8'));
|
|
208
|
+
enabled = config.enabled === true;
|
|
209
|
+
}
|
|
210
|
+
// Get next run time
|
|
211
|
+
let next_run_minutes = null;
|
|
212
|
+
if (enabled && fs.existsSync(AUTOMATION_STATE_PATH)) {
|
|
213
|
+
const state = JSON.parse(fs.readFileSync(AUTOMATION_STATE_PATH, 'utf8'));
|
|
214
|
+
const lastRun = state.lastRun || 0;
|
|
215
|
+
const now = Date.now();
|
|
216
|
+
const timeSinceLastRun = now - lastRun;
|
|
217
|
+
const cooldownMs = COOLDOWN_MINUTES * 60 * 1000;
|
|
218
|
+
if (timeSinceLastRun >= cooldownMs) {
|
|
219
|
+
next_run_minutes = 0;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
next_run_minutes = Math.ceil((cooldownMs - timeSinceLastRun) / 60000);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else if (enabled) {
|
|
226
|
+
next_run_minutes = 0; // First run
|
|
227
|
+
}
|
|
228
|
+
return { enabled, next_run_minutes };
|
|
229
|
+
}
|
|
230
|
+
// ============================================================================
|
|
231
|
+
// Session Metrics
|
|
232
|
+
// ============================================================================
|
|
233
|
+
/**
|
|
234
|
+
* Parse task type from message content.
|
|
235
|
+
* Supports formats:
|
|
236
|
+
* - [Task][type-name] ... → extracts "type-name"
|
|
237
|
+
* - [Task] ... → returns "unknown"
|
|
238
|
+
*/
|
|
239
|
+
function parseTaskType(messageContent) {
|
|
240
|
+
if (!messageContent.startsWith('[Task]')) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
// Check for [Task][type] format
|
|
244
|
+
const typeMatch = messageContent.match(/^\[Task\]\[([^\]]+)\]/);
|
|
245
|
+
if (typeMatch && typeMatch[1]) {
|
|
246
|
+
return typeMatch[1];
|
|
247
|
+
}
|
|
248
|
+
// Legacy [Task] format without type
|
|
249
|
+
return 'unknown';
|
|
250
|
+
}
|
|
251
|
+
function getSessionMetricsData(hours) {
|
|
252
|
+
const since = Date.now() - (hours * 60 * 60 * 1000);
|
|
253
|
+
const sessionDir = getSessionDir();
|
|
254
|
+
const metrics = {
|
|
255
|
+
task_triggered: 0,
|
|
256
|
+
user_triggered: 0,
|
|
257
|
+
task_by_type: {},
|
|
258
|
+
};
|
|
259
|
+
if (!fs.existsSync(sessionDir)) {
|
|
260
|
+
return metrics;
|
|
261
|
+
}
|
|
262
|
+
const files = fs.readdirSync(sessionDir).filter(f => f.endsWith('.jsonl'));
|
|
263
|
+
for (const file of files) {
|
|
264
|
+
const filePath = path.join(sessionDir, file);
|
|
265
|
+
// Check file modification time - only count recent sessions
|
|
266
|
+
const stat = fs.statSync(filePath);
|
|
267
|
+
if (stat.mtime.getTime() < since) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// Read file and detect task session by checking if first user message starts with [Task]
|
|
271
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
272
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
273
|
+
let taskType = null;
|
|
274
|
+
for (const line of lines) {
|
|
275
|
+
try {
|
|
276
|
+
const entry = JSON.parse(line);
|
|
277
|
+
// Look for first user message
|
|
278
|
+
if (entry.type === 'human' || entry.type === 'user') {
|
|
279
|
+
const messageContent = typeof entry.message?.content === 'string'
|
|
280
|
+
? entry.message.content
|
|
281
|
+
: entry.content;
|
|
282
|
+
if (messageContent) {
|
|
283
|
+
taskType = parseTaskType(messageContent);
|
|
284
|
+
}
|
|
285
|
+
break; // Stop after first user message
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// Skip malformed JSONL lines
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (taskType !== null) {
|
|
293
|
+
metrics.task_triggered++;
|
|
294
|
+
metrics.task_by_type[taskType] = (metrics.task_by_type[taskType] || 0) + 1;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
metrics.user_triggered++;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return metrics;
|
|
301
|
+
}
|
|
302
|
+
function getPendingItems() {
|
|
303
|
+
const items = {
|
|
304
|
+
cto_questions: 0,
|
|
305
|
+
commit_rejections: 0,
|
|
306
|
+
pending_triage: 0,
|
|
307
|
+
commits_blocked: false,
|
|
308
|
+
};
|
|
309
|
+
// Check deputy-cto database
|
|
310
|
+
if (fs.existsSync(DEPUTY_CTO_DB_PATH)) {
|
|
311
|
+
const db = openReadonlyDb(DEPUTY_CTO_DB_PATH);
|
|
312
|
+
const pending = db.prepare("SELECT COUNT(*) as count FROM questions WHERE status = 'pending'").get();
|
|
313
|
+
const rejections = db.prepare("SELECT COUNT(*) as count FROM questions WHERE type = 'rejection' AND status = 'pending'").get();
|
|
314
|
+
db.close();
|
|
315
|
+
items.cto_questions = pending?.count || 0;
|
|
316
|
+
items.commit_rejections = rejections?.count || 0;
|
|
317
|
+
}
|
|
318
|
+
// Check cto-reports database for pending triage (deputy-cto responsibility, not CTO)
|
|
319
|
+
if (fs.existsSync(CTO_REPORTS_DB_PATH)) {
|
|
320
|
+
const db = openReadonlyDb(CTO_REPORTS_DB_PATH);
|
|
321
|
+
const pending = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'pending'").get();
|
|
322
|
+
items.pending_triage = pending?.count || 0;
|
|
323
|
+
db.close();
|
|
324
|
+
}
|
|
325
|
+
// G020: Block commits when ANY pending items exist (questions OR triage)
|
|
326
|
+
items.commits_blocked = items.cto_questions > 0 || items.pending_triage > 0;
|
|
327
|
+
return items;
|
|
328
|
+
}
|
|
329
|
+
// ============================================================================
|
|
330
|
+
// Triage Metrics
|
|
331
|
+
// ============================================================================
|
|
332
|
+
function getTriageMetrics() {
|
|
333
|
+
const metrics = {
|
|
334
|
+
pending: 0,
|
|
335
|
+
in_progress: 0,
|
|
336
|
+
self_handled_24h: 0,
|
|
337
|
+
self_handled_7d: 0,
|
|
338
|
+
escalated_24h: 0,
|
|
339
|
+
escalated_7d: 0,
|
|
340
|
+
dismissed_24h: 0,
|
|
341
|
+
dismissed_7d: 0,
|
|
342
|
+
};
|
|
343
|
+
if (!fs.existsSync(CTO_REPORTS_DB_PATH)) {
|
|
344
|
+
return metrics;
|
|
345
|
+
}
|
|
346
|
+
const db = openReadonlyDb(CTO_REPORTS_DB_PATH);
|
|
347
|
+
const now = Date.now();
|
|
348
|
+
const cutoff24h = new Date(now - 24 * 60 * 60 * 1000).toISOString();
|
|
349
|
+
const cutoff7d = new Date(now - 7 * 24 * 60 * 60 * 1000).toISOString();
|
|
350
|
+
const pending = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'pending'").get();
|
|
351
|
+
metrics.pending = pending?.count || 0;
|
|
352
|
+
const inProgress = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'in_progress'").get();
|
|
353
|
+
metrics.in_progress = inProgress?.count || 0;
|
|
354
|
+
const selfHandled24h = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'self_handled' AND triage_completed_at >= ?").get(cutoff24h);
|
|
355
|
+
metrics.self_handled_24h = selfHandled24h?.count || 0;
|
|
356
|
+
const selfHandled7d = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'self_handled' AND triage_completed_at >= ?").get(cutoff7d);
|
|
357
|
+
metrics.self_handled_7d = selfHandled7d?.count || 0;
|
|
358
|
+
const escalated24h = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'escalated' AND triage_completed_at >= ?").get(cutoff24h);
|
|
359
|
+
metrics.escalated_24h = escalated24h?.count || 0;
|
|
360
|
+
const escalated7d = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'escalated' AND triage_completed_at >= ?").get(cutoff7d);
|
|
361
|
+
metrics.escalated_7d = escalated7d?.count || 0;
|
|
362
|
+
const dismissed24h = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'dismissed' AND triage_completed_at >= ?").get(cutoff24h);
|
|
363
|
+
metrics.dismissed_24h = dismissed24h?.count || 0;
|
|
364
|
+
const dismissed7d = db.prepare("SELECT COUNT(*) as count FROM reports WHERE triage_status = 'dismissed' AND triage_completed_at >= ?").get(cutoff7d);
|
|
365
|
+
metrics.dismissed_7d = dismissed7d?.count || 0;
|
|
366
|
+
db.close();
|
|
367
|
+
return metrics;
|
|
368
|
+
}
|
|
369
|
+
function getTaskMetricsData(hours) {
|
|
370
|
+
const metrics = {
|
|
371
|
+
pending_total: 0,
|
|
372
|
+
in_progress_total: 0,
|
|
373
|
+
completed_total: 0,
|
|
374
|
+
by_section: {},
|
|
375
|
+
completed_24h: 0,
|
|
376
|
+
completed_24h_by_section: {},
|
|
377
|
+
};
|
|
378
|
+
if (!fs.existsSync(TODO_DB_PATH)) {
|
|
379
|
+
return metrics;
|
|
380
|
+
}
|
|
381
|
+
const db = openReadonlyDb(TODO_DB_PATH);
|
|
382
|
+
// Get current task counts by section and status
|
|
383
|
+
const tasks = db.prepare(`
|
|
384
|
+
SELECT section, status, COUNT(*) as count
|
|
385
|
+
FROM tasks
|
|
386
|
+
GROUP BY section, status
|
|
387
|
+
`).all();
|
|
388
|
+
for (const row of tasks) {
|
|
389
|
+
if (!metrics.by_section[row.section]) {
|
|
390
|
+
metrics.by_section[row.section] = { pending: 0, in_progress: 0, completed: 0 };
|
|
391
|
+
}
|
|
392
|
+
metrics.by_section[row.section][row.status] = row.count;
|
|
393
|
+
// Accumulate totals
|
|
394
|
+
if (row.status === 'pending') {
|
|
395
|
+
metrics.pending_total += row.count;
|
|
396
|
+
}
|
|
397
|
+
else if (row.status === 'in_progress') {
|
|
398
|
+
metrics.in_progress_total += row.count;
|
|
399
|
+
}
|
|
400
|
+
else if (row.status === 'completed') {
|
|
401
|
+
metrics.completed_total += row.count;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// Get completed tasks within time range
|
|
405
|
+
const since = Date.now() - (hours * 60 * 60 * 1000);
|
|
406
|
+
const sinceTimestamp = Math.floor(since / 1000);
|
|
407
|
+
const completed = db.prepare(`
|
|
408
|
+
SELECT section, COUNT(*) as count
|
|
409
|
+
FROM tasks
|
|
410
|
+
WHERE status = 'completed' AND completed_timestamp >= ?
|
|
411
|
+
GROUP BY section
|
|
412
|
+
`).all(sinceTimestamp);
|
|
413
|
+
let total = 0;
|
|
414
|
+
for (const row of completed) {
|
|
415
|
+
metrics.completed_24h_by_section[row.section] = row.count;
|
|
416
|
+
total += row.count;
|
|
417
|
+
}
|
|
418
|
+
metrics.completed_24h = total;
|
|
419
|
+
db.close();
|
|
420
|
+
return metrics;
|
|
421
|
+
}
|
|
422
|
+
// ============================================================================
|
|
423
|
+
// System Health
|
|
424
|
+
// ============================================================================
|
|
425
|
+
function getSystemHealth() {
|
|
426
|
+
let protectionStatus = 'unknown';
|
|
427
|
+
let allProtected = true;
|
|
428
|
+
let anyExists = false;
|
|
429
|
+
for (const file of PROTECTED_FILES) {
|
|
430
|
+
if (fs.existsSync(file)) {
|
|
431
|
+
anyExists = true;
|
|
432
|
+
try {
|
|
433
|
+
const stats = fs.statSync(file);
|
|
434
|
+
if (stats.uid !== 0) {
|
|
435
|
+
allProtected = false;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
allProtected = false;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (anyExists) {
|
|
444
|
+
protectionStatus = allProtected ? 'protected' : 'unprotected';
|
|
445
|
+
}
|
|
446
|
+
return { protection_status: protectionStatus };
|
|
447
|
+
}
|
|
448
|
+
function getAgentActivity() {
|
|
449
|
+
const result = {
|
|
450
|
+
spawns_24h: 0,
|
|
451
|
+
spawns_7d: 0,
|
|
452
|
+
by_type: {},
|
|
453
|
+
};
|
|
454
|
+
if (!fs.existsSync(AGENT_TRACKER_PATH)) {
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
const content = fs.readFileSync(AGENT_TRACKER_PATH, 'utf8');
|
|
458
|
+
const history = JSON.parse(content);
|
|
459
|
+
const now = Date.now();
|
|
460
|
+
const cutoff24h = now - 24 * 60 * 60 * 1000;
|
|
461
|
+
const cutoff7d = now - 7 * 24 * 60 * 60 * 1000;
|
|
462
|
+
for (const agent of history.agents || []) {
|
|
463
|
+
const agentTime = new Date(agent.timestamp).getTime();
|
|
464
|
+
if (agentTime >= cutoff7d) {
|
|
465
|
+
result.spawns_7d++;
|
|
466
|
+
if (agentTime >= cutoff24h) {
|
|
467
|
+
result.spawns_24h++;
|
|
468
|
+
result.by_type[agent.type] = (result.by_type[agent.type] || 0) + 1;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
function getHookExecutions() {
|
|
475
|
+
const result = {
|
|
476
|
+
total_24h: 0,
|
|
477
|
+
success_rate: 100,
|
|
478
|
+
by_hook: {},
|
|
479
|
+
recent_failures: [],
|
|
480
|
+
};
|
|
481
|
+
if (!fs.existsSync(AGENT_TRACKER_PATH)) {
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
const content = fs.readFileSync(AGENT_TRACKER_PATH, 'utf8');
|
|
485
|
+
const history = JSON.parse(content);
|
|
486
|
+
const now = Date.now();
|
|
487
|
+
const cutoff24h = now - 24 * 60 * 60 * 1000;
|
|
488
|
+
let successCount = 0;
|
|
489
|
+
for (const exec of history.hookExecutions || []) {
|
|
490
|
+
const execTime = new Date(exec.timestamp).getTime();
|
|
491
|
+
if (execTime < cutoff24h)
|
|
492
|
+
continue;
|
|
493
|
+
result.total_24h++;
|
|
494
|
+
if (exec.status === 'success')
|
|
495
|
+
successCount++;
|
|
496
|
+
// Aggregate by hook
|
|
497
|
+
if (!result.by_hook[exec.hookType]) {
|
|
498
|
+
result.by_hook[exec.hookType] = { total: 0, success: 0, failure: 0 };
|
|
499
|
+
}
|
|
500
|
+
const stats = result.by_hook[exec.hookType];
|
|
501
|
+
stats.total++;
|
|
502
|
+
if (exec.status === 'success')
|
|
503
|
+
stats.success++;
|
|
504
|
+
if (exec.status === 'failure')
|
|
505
|
+
stats.failure++;
|
|
506
|
+
// Collect recent failures
|
|
507
|
+
if (exec.status === 'failure' && result.recent_failures.length < 5) {
|
|
508
|
+
result.recent_failures.push({
|
|
509
|
+
hook: exec.hookType,
|
|
510
|
+
error: exec.metadata?.error || 'Unknown error',
|
|
511
|
+
timestamp: exec.timestamp,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (result.total_24h > 0) {
|
|
516
|
+
result.success_rate = Math.round((successCount / result.total_24h) * 100);
|
|
517
|
+
}
|
|
518
|
+
return result;
|
|
519
|
+
}
|
|
520
|
+
function getKeyRotationMetrics(hours) {
|
|
521
|
+
if (!fs.existsSync(KEY_ROTATION_STATE_PATH)) {
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
const content = fs.readFileSync(KEY_ROTATION_STATE_PATH, 'utf8');
|
|
525
|
+
const state = JSON.parse(content);
|
|
526
|
+
if (!state || state.version !== 1 || typeof state.keys !== 'object') {
|
|
527
|
+
throw new Error(`Invalid key rotation state file at ${KEY_ROTATION_STATE_PATH}`);
|
|
528
|
+
}
|
|
529
|
+
const now = Date.now();
|
|
530
|
+
const since = now - (hours * 60 * 60 * 1000);
|
|
531
|
+
// Count keys by status and build active key list
|
|
532
|
+
const keys = [];
|
|
533
|
+
let fiveHourSum = 0;
|
|
534
|
+
let sevenDaySum = 0;
|
|
535
|
+
let activeKeysWithData = 0;
|
|
536
|
+
let expiredKeys = 0;
|
|
537
|
+
let invalidKeys = 0;
|
|
538
|
+
let exhaustedKeys = 0;
|
|
539
|
+
for (const [keyId, keyData] of Object.entries(state.keys)) {
|
|
540
|
+
if (keyData.status === 'expired') {
|
|
541
|
+
expiredKeys++;
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
if (keyData.status === 'invalid') {
|
|
545
|
+
invalidKeys++;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
if (keyData.status === 'exhausted') {
|
|
549
|
+
exhaustedKeys++;
|
|
550
|
+
}
|
|
551
|
+
// Include active and exhausted keys in the list
|
|
552
|
+
if (keyData.status !== 'active' && keyData.status !== 'exhausted')
|
|
553
|
+
continue;
|
|
554
|
+
const isCurrent = keyId === state.active_key_id;
|
|
555
|
+
keys.push({
|
|
556
|
+
key_id: `${keyId.slice(0, 8)}...`,
|
|
557
|
+
subscription_type: keyData.subscriptionType || 'unknown',
|
|
558
|
+
five_hour_pct: keyData.last_usage?.five_hour ?? null,
|
|
559
|
+
seven_day_pct: keyData.last_usage?.seven_day ?? null,
|
|
560
|
+
is_current: isCurrent,
|
|
561
|
+
});
|
|
562
|
+
// Accumulate for aggregate (active keys only)
|
|
563
|
+
if (keyData.status === 'active' && keyData.last_usage) {
|
|
564
|
+
fiveHourSum += keyData.last_usage.five_hour ?? 0;
|
|
565
|
+
sevenDaySum += keyData.last_usage.seven_day ?? 0;
|
|
566
|
+
activeKeysWithData++;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// Count rotation events in time range
|
|
570
|
+
const rotationEvents24h = state.rotation_log.filter(entry => entry.timestamp >= since && entry.event === 'key_switched').length;
|
|
571
|
+
// Compute aggregate (% of total capacity)
|
|
572
|
+
const aggregate = activeKeysWithData > 0 ? {
|
|
573
|
+
active_keys: activeKeysWithData,
|
|
574
|
+
five_hour_pct: Math.round(fiveHourSum / activeKeysWithData),
|
|
575
|
+
seven_day_pct: Math.round(sevenDaySum / activeKeysWithData),
|
|
576
|
+
} : null;
|
|
577
|
+
return {
|
|
578
|
+
current_key_id: state.active_key_id ? `${state.active_key_id.slice(0, 8)}...` : null,
|
|
579
|
+
active_keys: keys.length - exhaustedKeys,
|
|
580
|
+
expired_keys: expiredKeys,
|
|
581
|
+
invalid_keys: invalidKeys,
|
|
582
|
+
exhausted_keys: exhaustedKeys,
|
|
583
|
+
keys,
|
|
584
|
+
rotation_events_24h: rotationEvents24h,
|
|
585
|
+
aggregate,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
// ============================================================================
|
|
589
|
+
// Usage Projection
|
|
590
|
+
// ============================================================================
|
|
591
|
+
const DEFAULT_COOLDOWNS = {
|
|
592
|
+
hourly_tasks: 55,
|
|
593
|
+
triage_check: 5,
|
|
594
|
+
antipattern_hunter: 360,
|
|
595
|
+
schema_mapper: 1440,
|
|
596
|
+
lint_checker: 30,
|
|
597
|
+
todo_maintenance: 15,
|
|
598
|
+
task_runner: 60,
|
|
599
|
+
triage_per_item: 60,
|
|
600
|
+
};
|
|
601
|
+
function getUsageProjection() {
|
|
602
|
+
const defaults = { ...DEFAULT_COOLDOWNS };
|
|
603
|
+
const effective = { ...DEFAULT_COOLDOWNS };
|
|
604
|
+
const result = {
|
|
605
|
+
factor: 1.0,
|
|
606
|
+
target_pct: 90,
|
|
607
|
+
projected_at_reset_pct: null,
|
|
608
|
+
constraining_metric: null,
|
|
609
|
+
last_updated: null,
|
|
610
|
+
effective_cooldowns: effective,
|
|
611
|
+
default_cooldowns: defaults,
|
|
612
|
+
};
|
|
613
|
+
if (!fs.existsSync(AUTOMATION_CONFIG_PATH)) {
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
616
|
+
const content = fs.readFileSync(AUTOMATION_CONFIG_PATH, 'utf8');
|
|
617
|
+
const config = JSON.parse(content);
|
|
618
|
+
if (!config || config.version !== 1) {
|
|
619
|
+
throw new Error(`Invalid automation config at ${AUTOMATION_CONFIG_PATH}`);
|
|
620
|
+
}
|
|
621
|
+
// Merge defaults from config
|
|
622
|
+
if (config.defaults) {
|
|
623
|
+
Object.assign(defaults, config.defaults);
|
|
624
|
+
result.default_cooldowns = defaults;
|
|
625
|
+
}
|
|
626
|
+
// Merge effective (dynamically adjusted) values
|
|
627
|
+
if (config.effective) {
|
|
628
|
+
Object.assign(effective, config.defaults || {}, config.effective);
|
|
629
|
+
result.effective_cooldowns = effective;
|
|
630
|
+
}
|
|
631
|
+
// Extract adjustment info
|
|
632
|
+
if (config.adjustment) {
|
|
633
|
+
result.factor = config.adjustment.factor ?? 1.0;
|
|
634
|
+
result.target_pct = config.adjustment.target_pct ?? 90;
|
|
635
|
+
result.projected_at_reset_pct = config.adjustment.projected_at_reset ?? null;
|
|
636
|
+
result.constraining_metric = config.adjustment.constraining_metric ?? null;
|
|
637
|
+
result.last_updated = config.adjustment.last_updated ?? null;
|
|
638
|
+
}
|
|
639
|
+
return result;
|
|
640
|
+
}
|
|
641
|
+
// ============================================================================
|
|
642
|
+
// Product-Market-Fit Summary
|
|
643
|
+
// ============================================================================
|
|
644
|
+
const PRODUCT_MANAGER_DB_PATH = path.join(PROJECT_DIR, '.claude', 'state', 'product-manager.db');
|
|
645
|
+
function getProductMarketFitSummary() {
|
|
646
|
+
// Check feature toggle
|
|
647
|
+
let pmEnabled = false;
|
|
648
|
+
if (fs.existsSync(AUTONOMOUS_CONFIG_PATH)) {
|
|
649
|
+
try {
|
|
650
|
+
const config = JSON.parse(fs.readFileSync(AUTONOMOUS_CONFIG_PATH, 'utf8'));
|
|
651
|
+
pmEnabled = config.productManagerEnabled === true;
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
// Default to disabled
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (!pmEnabled) {
|
|
658
|
+
return {
|
|
659
|
+
enabled: false,
|
|
660
|
+
status: 'not_started',
|
|
661
|
+
sections_populated: 0,
|
|
662
|
+
total_sections: 6,
|
|
663
|
+
sections: [],
|
|
664
|
+
compliance: null,
|
|
665
|
+
last_updated: null,
|
|
666
|
+
tip: 'Enable product-market-fit analysis with /toggle-product-manager or ask the deputy CTO.',
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
if (!fs.existsSync(PRODUCT_MANAGER_DB_PATH)) {
|
|
670
|
+
return {
|
|
671
|
+
enabled: true,
|
|
672
|
+
status: 'not_started',
|
|
673
|
+
sections_populated: 0,
|
|
674
|
+
total_sections: 6,
|
|
675
|
+
sections: [],
|
|
676
|
+
compliance: null,
|
|
677
|
+
last_updated: null,
|
|
678
|
+
tip: 'Start product-market-fit analysis with /product-manager.',
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
const db = openReadonlyDb(PRODUCT_MANAGER_DB_PATH);
|
|
682
|
+
try {
|
|
683
|
+
const meta = db.prepare("SELECT status, last_updated_at FROM analysis_meta WHERE id = 'default'").get();
|
|
684
|
+
if (!meta) {
|
|
685
|
+
db.close();
|
|
686
|
+
return {
|
|
687
|
+
enabled: true,
|
|
688
|
+
status: 'not_started',
|
|
689
|
+
sections_populated: 0,
|
|
690
|
+
total_sections: 6,
|
|
691
|
+
sections: [],
|
|
692
|
+
compliance: null,
|
|
693
|
+
last_updated: null,
|
|
694
|
+
tip: 'Start product-market-fit analysis with /product-manager.',
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
const sections = db.prepare('SELECT section_number, title, content FROM sections ORDER BY section_number').all();
|
|
698
|
+
const LIST_SECTIONS = [2, 6];
|
|
699
|
+
const sectionInfos = [];
|
|
700
|
+
let populatedCount = 0;
|
|
701
|
+
for (const sec of sections) {
|
|
702
|
+
const isList = LIST_SECTIONS.includes(sec.section_number);
|
|
703
|
+
let populated = false;
|
|
704
|
+
let contentPreview = null;
|
|
705
|
+
let entryCount;
|
|
706
|
+
if (isList) {
|
|
707
|
+
const count = db.prepare('SELECT COUNT(*) as c FROM section_entries WHERE section_number = ?').get(sec.section_number).c;
|
|
708
|
+
populated = count > 0;
|
|
709
|
+
entryCount = count;
|
|
710
|
+
if (populated) {
|
|
711
|
+
const firstEntry = db.prepare('SELECT content FROM section_entries WHERE section_number = ? ORDER BY id LIMIT 1').get(sec.section_number);
|
|
712
|
+
if (firstEntry?.content) {
|
|
713
|
+
contentPreview = firstEntry.content.length > 200
|
|
714
|
+
? firstEntry.content.slice(0, 200) + '...'
|
|
715
|
+
: firstEntry.content;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
else {
|
|
720
|
+
populated = !!sec.content;
|
|
721
|
+
if (populated && sec.content) {
|
|
722
|
+
contentPreview = sec.content.length > 200
|
|
723
|
+
? sec.content.slice(0, 200) + '...'
|
|
724
|
+
: sec.content;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (populated)
|
|
728
|
+
populatedCount++;
|
|
729
|
+
const info = {
|
|
730
|
+
number: sec.section_number,
|
|
731
|
+
title: sec.title,
|
|
732
|
+
populated,
|
|
733
|
+
content_preview: contentPreview,
|
|
734
|
+
};
|
|
735
|
+
if (entryCount !== undefined) {
|
|
736
|
+
info.entry_count = entryCount;
|
|
737
|
+
}
|
|
738
|
+
sectionInfos.push(info);
|
|
739
|
+
}
|
|
740
|
+
// Compliance stats
|
|
741
|
+
let compliance = null;
|
|
742
|
+
const totalPainPoints = db.prepare("SELECT COUNT(*) as c FROM section_entries WHERE section_number = 6").get().c;
|
|
743
|
+
if (totalPainPoints > 0) {
|
|
744
|
+
const mapped = db.prepare("SELECT COUNT(DISTINCT pain_point_id) as c FROM pain_point_personas").get().c;
|
|
745
|
+
compliance = {
|
|
746
|
+
total_pain_points: totalPainPoints,
|
|
747
|
+
mapped,
|
|
748
|
+
unmapped: totalPainPoints - mapped,
|
|
749
|
+
pct: Math.round((mapped / totalPainPoints) * 100),
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
db.close();
|
|
753
|
+
return {
|
|
754
|
+
enabled: true,
|
|
755
|
+
status: meta.status,
|
|
756
|
+
sections_populated: populatedCount,
|
|
757
|
+
total_sections: 6,
|
|
758
|
+
sections: sectionInfos,
|
|
759
|
+
compliance,
|
|
760
|
+
last_updated: meta.last_updated_at,
|
|
761
|
+
tip: 'Use /show product-market-fit or ask the deputy CTO for the full untruncated analysis.',
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
catch {
|
|
765
|
+
try {
|
|
766
|
+
db.close();
|
|
767
|
+
}
|
|
768
|
+
catch { /* ignore */ }
|
|
769
|
+
return {
|
|
770
|
+
enabled: true,
|
|
771
|
+
status: 'not_started',
|
|
772
|
+
sections_populated: 0,
|
|
773
|
+
total_sections: 6,
|
|
774
|
+
sections: [],
|
|
775
|
+
compliance: null,
|
|
776
|
+
last_updated: null,
|
|
777
|
+
tip: 'Use /show product-market-fit or ask the deputy CTO for the full untruncated analysis.',
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
// ============================================================================
|
|
782
|
+
// Tool Implementations
|
|
783
|
+
// ============================================================================
|
|
784
|
+
async function getReport(args) {
|
|
785
|
+
const hours = args.hours ?? 24;
|
|
786
|
+
const tokenUsage = getTokenUsage(hours);
|
|
787
|
+
const quotaStatus = await getQuotaStatus();
|
|
788
|
+
const keyRotation = getKeyRotationMetrics(hours);
|
|
789
|
+
const report = {
|
|
790
|
+
generated_at: new Date().toISOString(),
|
|
791
|
+
hours,
|
|
792
|
+
system_health: getSystemHealth(),
|
|
793
|
+
autonomous_mode: getAutonomousModeStatus(),
|
|
794
|
+
quota: quotaStatus,
|
|
795
|
+
usage: {
|
|
796
|
+
plan_type: 'unknown',
|
|
797
|
+
tokens_24h: tokenUsage,
|
|
798
|
+
estimated_remaining_pct: keyRotation?.aggregate?.seven_day_pct != null
|
|
799
|
+
? 100 - keyRotation.aggregate.seven_day_pct
|
|
800
|
+
: quotaStatus.seven_day?.utilization
|
|
801
|
+
? 100 - quotaStatus.seven_day.utilization
|
|
802
|
+
: null,
|
|
803
|
+
},
|
|
804
|
+
usage_projection: getUsageProjection(),
|
|
805
|
+
key_rotation: keyRotation,
|
|
806
|
+
agents: getAgentActivity(),
|
|
807
|
+
hooks: getHookExecutions(),
|
|
808
|
+
sessions: getSessionMetricsData(hours),
|
|
809
|
+
pending_items: getPendingItems(),
|
|
810
|
+
triage: getTriageMetrics(),
|
|
811
|
+
tasks: getTaskMetricsData(hours),
|
|
812
|
+
product_market_fit: getProductMarketFitSummary(),
|
|
813
|
+
};
|
|
814
|
+
return report;
|
|
815
|
+
}
|
|
816
|
+
function getSessionMetrics(args) {
|
|
817
|
+
const hours = args.hours ?? 24;
|
|
818
|
+
return {
|
|
819
|
+
hours,
|
|
820
|
+
sessions: getSessionMetricsData(hours),
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
function getTaskMetrics(args) {
|
|
824
|
+
const hours = args.hours ?? 24;
|
|
825
|
+
return {
|
|
826
|
+
hours,
|
|
827
|
+
tasks: getTaskMetricsData(hours),
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
// ============================================================================
|
|
831
|
+
// Server Setup
|
|
832
|
+
// ============================================================================
|
|
833
|
+
const tools = [
|
|
834
|
+
{
|
|
835
|
+
name: 'get_report',
|
|
836
|
+
description: 'Generate comprehensive CTO report with token usage, session metrics, pending items, and task status.',
|
|
837
|
+
schema: GetReportArgsSchema,
|
|
838
|
+
handler: getReport,
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
name: 'get_session_metrics',
|
|
842
|
+
description: 'Get session metrics only: task-triggered vs user-triggered sessions within time range.',
|
|
843
|
+
schema: GetSessionMetricsArgsSchema,
|
|
844
|
+
handler: getSessionMetrics,
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
name: 'get_task_metrics',
|
|
848
|
+
description: 'Get task metrics only: counts by section/status and recently completed tasks.',
|
|
849
|
+
schema: GetTaskMetricsArgsSchema,
|
|
850
|
+
handler: getTaskMetrics,
|
|
851
|
+
},
|
|
852
|
+
];
|
|
853
|
+
const server = new McpServer({
|
|
854
|
+
name: 'cto-report',
|
|
855
|
+
version: '1.0.0',
|
|
856
|
+
tools,
|
|
857
|
+
});
|
|
858
|
+
server.start();
|
|
859
|
+
//# sourceMappingURL=server.js.map
|