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,439 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agent Reaper — Precision process cleanup for completed spawned Claude sessions.
|
|
4
|
+
*
|
|
5
|
+
* Finds agents tracked by agent-tracker that have finished their work
|
|
6
|
+
* (last JSONL line is assistant-only text with no tool_use) and kills them.
|
|
7
|
+
*
|
|
8
|
+
* Safety guarantees:
|
|
9
|
+
* - Only kills processes whose session file starts with [Task] (automated)
|
|
10
|
+
* - Only kills processes whose last assistant message has no tool_use blocks
|
|
11
|
+
* - Never kills interactive (non-[Task]) sessions
|
|
12
|
+
* - Never kills processes it can't match to a known session file
|
|
13
|
+
* - Processes that are already dead are simply marked completed
|
|
14
|
+
*
|
|
15
|
+
* @version 2.0.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import os from 'os';
|
|
21
|
+
|
|
22
|
+
// Lazy-loaded SQLite for TODO reconciliation
|
|
23
|
+
let Database = null;
|
|
24
|
+
try {
|
|
25
|
+
Database = (await import('better-sqlite3')).default;
|
|
26
|
+
} catch {
|
|
27
|
+
// Non-fatal: TODO reconciliation will be skipped
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Configuration
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), '.claude', 'projects');
|
|
35
|
+
const HEAD_BYTES = 2000; // Bytes to read from start of JSONL for agent ID match
|
|
36
|
+
const TAIL_BYTES = 4000; // Bytes to read from end of JSONL for completion check
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Core Functions
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if a process is alive.
|
|
44
|
+
* @param {number} pid
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
function isProcessAlive(pid) {
|
|
48
|
+
try {
|
|
49
|
+
process.kill(pid, 0);
|
|
50
|
+
return true;
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return err.code !== 'ESRCH';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Discover the normalized session directory for a project.
|
|
58
|
+
* @param {string} projectDir
|
|
59
|
+
* @returns {string|null}
|
|
60
|
+
*/
|
|
61
|
+
function getSessionDir(projectDir) {
|
|
62
|
+
const projectPath = projectDir.replace(/[^a-zA-Z0-9]/g, '-');
|
|
63
|
+
const sessionDir = path.join(CLAUDE_PROJECTS_DIR, projectPath);
|
|
64
|
+
if (fs.existsSync(sessionDir)) return sessionDir;
|
|
65
|
+
|
|
66
|
+
const altPath = path.join(CLAUDE_PROJECTS_DIR, projectPath.replace(/^-/, ''));
|
|
67
|
+
if (fs.existsSync(altPath)) return altPath;
|
|
68
|
+
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Read the first N bytes of a file using a file descriptor (no full-file read).
|
|
74
|
+
* @param {string} filePath
|
|
75
|
+
* @param {number} numBytes
|
|
76
|
+
* @returns {string}
|
|
77
|
+
*/
|
|
78
|
+
function readHead(filePath, numBytes) {
|
|
79
|
+
let fd;
|
|
80
|
+
try {
|
|
81
|
+
fd = fs.openSync(filePath, 'r');
|
|
82
|
+
const buf = Buffer.alloc(numBytes);
|
|
83
|
+
const bytesRead = fs.readSync(fd, buf, 0, numBytes, 0);
|
|
84
|
+
return buf.toString('utf8', 0, bytesRead);
|
|
85
|
+
} catch {
|
|
86
|
+
return '';
|
|
87
|
+
} finally {
|
|
88
|
+
if (fd !== undefined) fs.closeSync(fd);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Read the last N bytes of a file using a file descriptor (seek to end).
|
|
94
|
+
* @param {string} filePath
|
|
95
|
+
* @param {number} numBytes
|
|
96
|
+
* @returns {string}
|
|
97
|
+
*/
|
|
98
|
+
function readTail(filePath, numBytes) {
|
|
99
|
+
let fd;
|
|
100
|
+
try {
|
|
101
|
+
fd = fs.openSync(filePath, 'r');
|
|
102
|
+
const stat = fs.fstatSync(fd);
|
|
103
|
+
const start = Math.max(0, stat.size - numBytes);
|
|
104
|
+
const buf = Buffer.alloc(Math.min(numBytes, stat.size));
|
|
105
|
+
const bytesRead = fs.readSync(fd, buf, 0, buf.length, start);
|
|
106
|
+
return buf.toString('utf8', 0, bytesRead);
|
|
107
|
+
} catch {
|
|
108
|
+
return '';
|
|
109
|
+
} finally {
|
|
110
|
+
if (fd !== undefined) fs.closeSync(fd);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Find the session file that contains a given agent tracking ID
|
|
116
|
+
* by scanning the first bytes of each JSONL file.
|
|
117
|
+
*
|
|
118
|
+
* @param {string} sessionDir - Directory containing JSONL session files
|
|
119
|
+
* @param {string} agentId - The agent ID to search for (e.g. "agent-mlr08lpw-2444b1e0")
|
|
120
|
+
* @returns {string|null} Full path to matching session file, or null
|
|
121
|
+
*/
|
|
122
|
+
function findSessionFileByAgentId(sessionDir, agentId) {
|
|
123
|
+
const marker = `[AGENT:${agentId}]`;
|
|
124
|
+
|
|
125
|
+
let files;
|
|
126
|
+
try {
|
|
127
|
+
files = fs.readdirSync(sessionDir).filter(f => f.endsWith('.jsonl'));
|
|
128
|
+
} catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const file of files) {
|
|
133
|
+
const filePath = path.join(sessionDir, file);
|
|
134
|
+
const head = readHead(filePath, HEAD_BYTES);
|
|
135
|
+
if (head.includes(marker)) {
|
|
136
|
+
return filePath;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if a session's last assistant message indicates completion.
|
|
145
|
+
* Completion = last JSON line is type=assistant with text-only content (no tool_use).
|
|
146
|
+
*
|
|
147
|
+
* @param {string} sessionFile - Path to the JSONL session file
|
|
148
|
+
* @returns {boolean}
|
|
149
|
+
*/
|
|
150
|
+
function isSessionComplete(sessionFile) {
|
|
151
|
+
const tail = readTail(sessionFile, TAIL_BYTES);
|
|
152
|
+
if (!tail) return false;
|
|
153
|
+
|
|
154
|
+
// Split into lines and find the last parseable JSON line
|
|
155
|
+
const lines = tail.split('\n').filter(l => l.trim());
|
|
156
|
+
|
|
157
|
+
// Work backwards to find the last parseable line
|
|
158
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
159
|
+
let parsed;
|
|
160
|
+
try {
|
|
161
|
+
parsed = JSON.parse(lines[i]);
|
|
162
|
+
} catch {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Must be an assistant message
|
|
167
|
+
if (parsed.type !== 'assistant') return false;
|
|
168
|
+
|
|
169
|
+
// Check content array for tool_use blocks
|
|
170
|
+
const content = parsed.message?.content;
|
|
171
|
+
if (!Array.isArray(content)) {
|
|
172
|
+
// If content isn't an array, it's text-only — session is complete
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// If any content block is tool_use, agent is still working
|
|
177
|
+
const hasToolUse = content.some(c => c.type === 'tool_use');
|
|
178
|
+
return !hasToolUse;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Verify that a session is automated (starts with [Task]) — defense-in-depth.
|
|
186
|
+
*
|
|
187
|
+
* @param {string} sessionFile - Path to the JSONL session file
|
|
188
|
+
* @returns {boolean}
|
|
189
|
+
*/
|
|
190
|
+
function isAutomatedSession(sessionFile) {
|
|
191
|
+
const head = readHead(sessionFile, HEAD_BYTES);
|
|
192
|
+
return head.includes('[Task]');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Check if a session JSONL contains evidence of a complete_task MCP tool call.
|
|
197
|
+
* Searches the last 16KB for the tool name pattern.
|
|
198
|
+
*
|
|
199
|
+
* @param {string} sessionFile - Path to the JSONL session file
|
|
200
|
+
* @returns {boolean}
|
|
201
|
+
*/
|
|
202
|
+
function sessionContainsCompleteTask(sessionFile) {
|
|
203
|
+
const tail = readTail(sessionFile, 16384);
|
|
204
|
+
return tail.includes('"mcp__todo-db__complete_task"') ||
|
|
205
|
+
tail.includes('"name":"complete_task"');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Reconcile a TODO item after an agent is reaped.
|
|
210
|
+
* - If session completed normally but forgot to mark TODO: mark it completed
|
|
211
|
+
* - If session died unexpectedly: reset TODO to pending for re-spawn
|
|
212
|
+
*
|
|
213
|
+
* @param {object} agent - Agent record from tracker history
|
|
214
|
+
* @param {string} projectDir - Project directory
|
|
215
|
+
* @param {string} reapReason - Why the agent was reaped
|
|
216
|
+
* @returns {{ action: string, taskId: string } | null}
|
|
217
|
+
*/
|
|
218
|
+
function reconcileTodo(agent, projectDir, reapReason) {
|
|
219
|
+
if (!Database) return null;
|
|
220
|
+
|
|
221
|
+
// Only reconcile agents that have a linked task ID
|
|
222
|
+
const taskId = agent.metadata?.taskId;
|
|
223
|
+
if (!taskId) return null;
|
|
224
|
+
|
|
225
|
+
const todoDbPath = path.join(projectDir, '.claude', 'todo.db');
|
|
226
|
+
if (!fs.existsSync(todoDbPath)) return null;
|
|
227
|
+
|
|
228
|
+
let db;
|
|
229
|
+
try {
|
|
230
|
+
db = new Database(todoDbPath);
|
|
231
|
+
|
|
232
|
+
// Check current task status
|
|
233
|
+
const task = db.prepare('SELECT id, status FROM tasks WHERE id = ?').get(taskId);
|
|
234
|
+
if (!task) return null;
|
|
235
|
+
|
|
236
|
+
// Only act on in_progress tasks (already completed = no action needed)
|
|
237
|
+
if (task.status !== 'in_progress') return null;
|
|
238
|
+
|
|
239
|
+
if (reapReason === 'session_complete') {
|
|
240
|
+
// Agent completed normally - check if it called complete_task
|
|
241
|
+
const sessionFile = agent.sessionFile;
|
|
242
|
+
if (sessionFile && fs.existsSync(sessionFile) && sessionContainsCompleteTask(sessionFile)) {
|
|
243
|
+
// complete_task was called, TODO should already be marked - no action needed
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
// Agent finished but didn't mark TODO as complete
|
|
247
|
+
db.prepare("UPDATE tasks SET status = 'completed' WHERE id = ?").run(taskId);
|
|
248
|
+
return { action: 'completed', taskId };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (reapReason === 'process_already_dead') {
|
|
252
|
+
// Session died unexpectedly - reset TODO so automation can re-spawn
|
|
253
|
+
db.prepare("UPDATE tasks SET status = 'pending', started_at = NULL WHERE id = ?").run(taskId);
|
|
254
|
+
return { action: 'reset_to_pending', taskId };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return null;
|
|
258
|
+
} catch {
|
|
259
|
+
return null;
|
|
260
|
+
} finally {
|
|
261
|
+
if (db) {
|
|
262
|
+
try { db.close(); } catch { /* ignore */ }
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Reap completed automated agents.
|
|
269
|
+
*
|
|
270
|
+
* @param {string} projectDir - The project directory
|
|
271
|
+
* @returns {{ reaped: Array<{agentId: string, pid: number, reason: string}>, skipped: Array<{agentId: string, reason: string}>, errors: Array<{agentId: string, error: string}>, todoReconciled: Array<{agentId: string, taskId: string, action: string}> }}
|
|
272
|
+
*/
|
|
273
|
+
export function reapCompletedAgents(projectDir) {
|
|
274
|
+
const result = { reaped: [], skipped: [], errors: [], todoReconciled: [] };
|
|
275
|
+
|
|
276
|
+
// Load agent tracker
|
|
277
|
+
const historyPath = path.join(projectDir, '.claude', 'state', 'agent-tracker-history.json');
|
|
278
|
+
let history;
|
|
279
|
+
try {
|
|
280
|
+
if (!fs.existsSync(historyPath)) return result;
|
|
281
|
+
history = JSON.parse(fs.readFileSync(historyPath, 'utf8'));
|
|
282
|
+
} catch {
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!Array.isArray(history.agents)) return result;
|
|
287
|
+
|
|
288
|
+
// Find the session directory
|
|
289
|
+
const sessionDir = getSessionDir(projectDir);
|
|
290
|
+
if (!sessionDir) return result;
|
|
291
|
+
|
|
292
|
+
// Track whether we made any changes
|
|
293
|
+
let dirty = false;
|
|
294
|
+
|
|
295
|
+
for (const agent of history.agents) {
|
|
296
|
+
// Only process agents with status=running and a stored PID
|
|
297
|
+
if (agent.status !== 'running' || !agent.pid) continue;
|
|
298
|
+
|
|
299
|
+
const agentId = agent.id;
|
|
300
|
+
const pid = agent.pid;
|
|
301
|
+
|
|
302
|
+
// Step 1: Check if process is still alive
|
|
303
|
+
if (!isProcessAlive(pid)) {
|
|
304
|
+
// Try to discover session file before marking dead (needed for TODO reconciliation)
|
|
305
|
+
if (!agent.sessionFile) {
|
|
306
|
+
const discovered = findSessionFileByAgentId(sessionDir, agentId);
|
|
307
|
+
if (discovered) {
|
|
308
|
+
agent.sessionFile = discovered;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
agent.status = 'completed';
|
|
313
|
+
agent.reapReason = 'process_already_dead';
|
|
314
|
+
agent.reapedAt = new Date().toISOString();
|
|
315
|
+
dirty = true;
|
|
316
|
+
result.reaped.push({ agentId, pid, reason: 'process_already_dead' });
|
|
317
|
+
|
|
318
|
+
// Reconcile linked TODO item
|
|
319
|
+
const todoResult = reconcileTodo(agent, projectDir, 'process_already_dead');
|
|
320
|
+
if (todoResult) {
|
|
321
|
+
result.todoReconciled.push({ agentId, ...todoResult });
|
|
322
|
+
}
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Step 2: Discover session file (use cached if available)
|
|
327
|
+
let sessionFile = agent.sessionFile || null;
|
|
328
|
+
if (!sessionFile) {
|
|
329
|
+
sessionFile = findSessionFileByAgentId(sessionDir, agentId);
|
|
330
|
+
if (!sessionFile) {
|
|
331
|
+
result.skipped.push({ agentId, reason: 'session_file_not_found' });
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
// Cache for future runs
|
|
335
|
+
agent.sessionFile = sessionFile;
|
|
336
|
+
dirty = true;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Step 3: Check completion via JSONL
|
|
340
|
+
if (!isSessionComplete(sessionFile)) {
|
|
341
|
+
result.skipped.push({ agentId, reason: 'session_not_complete' });
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Step 4: Verify automated session (defense-in-depth)
|
|
346
|
+
if (!isAutomatedSession(sessionFile)) {
|
|
347
|
+
result.skipped.push({ agentId, reason: 'not_automated_session' });
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Step 5: Kill the process
|
|
352
|
+
try {
|
|
353
|
+
process.kill(pid, 'SIGKILL');
|
|
354
|
+
agent.status = 'reaped';
|
|
355
|
+
agent.reapedAt = new Date().toISOString();
|
|
356
|
+
agent.reapReason = 'session_complete';
|
|
357
|
+
dirty = true;
|
|
358
|
+
result.reaped.push({ agentId, pid, reason: 'session_complete' });
|
|
359
|
+
|
|
360
|
+
// Reconcile linked TODO item
|
|
361
|
+
const todoResult = reconcileTodo(agent, projectDir, 'session_complete');
|
|
362
|
+
if (todoResult) {
|
|
363
|
+
result.todoReconciled.push({ agentId, ...todoResult });
|
|
364
|
+
}
|
|
365
|
+
} catch (err) {
|
|
366
|
+
if (err.code === 'ESRCH') {
|
|
367
|
+
// Already dead between our check and kill
|
|
368
|
+
agent.status = 'completed';
|
|
369
|
+
agent.reapedAt = new Date().toISOString();
|
|
370
|
+
agent.reapReason = 'process_already_dead';
|
|
371
|
+
dirty = true;
|
|
372
|
+
result.reaped.push({ agentId, pid, reason: 'process_already_dead' });
|
|
373
|
+
|
|
374
|
+
// Reconcile linked TODO item
|
|
375
|
+
const todoResult = reconcileTodo(agent, projectDir, 'process_already_dead');
|
|
376
|
+
if (todoResult) {
|
|
377
|
+
result.todoReconciled.push({ agentId, ...todoResult });
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
result.errors.push({ agentId, error: `kill failed: ${err.message}` });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Write back if changes were made
|
|
386
|
+
if (dirty) {
|
|
387
|
+
try {
|
|
388
|
+
fs.writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf8');
|
|
389
|
+
} catch (err) {
|
|
390
|
+
result.errors.push({ agentId: '_history_write', error: err.message });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ============================================================================
|
|
398
|
+
// CLI Entry Point
|
|
399
|
+
// ============================================================================
|
|
400
|
+
|
|
401
|
+
if (process.argv[1] && (
|
|
402
|
+
process.argv[1].endsWith('reap-completed-agents.js') ||
|
|
403
|
+
process.argv[1].endsWith('reap-completed-agents')
|
|
404
|
+
)) {
|
|
405
|
+
const projectDir = process.argv[2] || process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
406
|
+
const result = reapCompletedAgents(projectDir);
|
|
407
|
+
|
|
408
|
+
if (result.reaped.length > 0) {
|
|
409
|
+
console.log(`Reaped ${result.reaped.length} completed agent(s):`);
|
|
410
|
+
for (const r of result.reaped) {
|
|
411
|
+
console.log(` ${r.agentId} (PID ${r.pid}): ${r.reason}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (result.skipped.length > 0) {
|
|
416
|
+
console.log(`Skipped ${result.skipped.length} agent(s):`);
|
|
417
|
+
for (const s of result.skipped) {
|
|
418
|
+
console.log(` ${s.agentId}: ${s.reason}`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (result.errors.length > 0) {
|
|
423
|
+
console.error(`Errors: ${result.errors.length}`);
|
|
424
|
+
for (const e of result.errors) {
|
|
425
|
+
console.error(` ${e.agentId}: ${e.error}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (result.todoReconciled.length > 0) {
|
|
430
|
+
console.log(`TODO reconciled for ${result.todoReconciled.length} agent(s):`);
|
|
431
|
+
for (const t of result.todoReconciled) {
|
|
432
|
+
console.log(` ${t.agentId}: TODO ${t.taskId} → ${t.action}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (result.reaped.length === 0 && result.skipped.length === 0) {
|
|
437
|
+
console.log('No agents with tracking data found (expected for pre-tracking agents).');
|
|
438
|
+
}
|
|
439
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Reinstall GENTYR (unprotect → install → protect)
|
|
3
|
+
#
|
|
4
|
+
# Usage: sudo scripts/reinstall.sh --path /path/to/project [--op-token <token>] [--makerkit|--no-makerkit]
|
|
5
|
+
#
|
|
6
|
+
# Requires sudo since it handles protection.
|
|
7
|
+
# After reinstall, start a new Claude Code session and run /setup-gentyr
|
|
8
|
+
# to configure credentials interactively.
|
|
9
|
+
#
|
|
10
|
+
# DEPRECATION NOTICE:
|
|
11
|
+
# This script will be superseded by the `npx gentyr` CLI in a future release.
|
|
12
|
+
# Prefer: sudo npx gentyr sync --path /path/to/project
|
|
13
|
+
|
|
14
|
+
set -e
|
|
15
|
+
|
|
16
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
17
|
+
PROJECT_DIR=""
|
|
18
|
+
OP_TOKEN=""
|
|
19
|
+
MAKERKIT_FLAG=""
|
|
20
|
+
|
|
21
|
+
while [[ $# -gt 0 ]]; do
|
|
22
|
+
case "$1" in
|
|
23
|
+
--path)
|
|
24
|
+
PROJECT_DIR="$2"
|
|
25
|
+
shift 2
|
|
26
|
+
;;
|
|
27
|
+
--op-token)
|
|
28
|
+
OP_TOKEN="$2"
|
|
29
|
+
shift 2
|
|
30
|
+
;;
|
|
31
|
+
--makerkit)
|
|
32
|
+
MAKERKIT_FLAG="--makerkit"
|
|
33
|
+
shift
|
|
34
|
+
;;
|
|
35
|
+
--no-makerkit)
|
|
36
|
+
MAKERKIT_FLAG="--no-makerkit"
|
|
37
|
+
shift
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
echo "Usage: sudo $0 --path /path/to/project [--op-token <token>] [--makerkit|--no-makerkit]"
|
|
41
|
+
exit 1
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
done
|
|
45
|
+
|
|
46
|
+
if [ -z "$PROJECT_DIR" ]; then
|
|
47
|
+
echo "Usage: sudo $0 --path /path/to/project [--op-token <token>] [--makerkit|--no-makerkit]"
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [ "$EUID" -ne 0 ]; then
|
|
52
|
+
echo "Error: requires sudo"
|
|
53
|
+
echo "Usage: sudo $0 --path /path/to/project"
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
ORIGINAL_USER="${SUDO_USER:-$(logname 2>/dev/null || echo $USER)}"
|
|
58
|
+
|
|
59
|
+
echo "Reinstalling framework at: $PROJECT_DIR"
|
|
60
|
+
echo "Running install step as: $ORIGINAL_USER"
|
|
61
|
+
echo ""
|
|
62
|
+
|
|
63
|
+
# 1. Unprotect (as root)
|
|
64
|
+
"$SCRIPT_DIR/setup.sh" --path "$PROJECT_DIR" --unprotect-only 2>/dev/null || true
|
|
65
|
+
|
|
66
|
+
# 2. Install (as user)
|
|
67
|
+
SETUP_ARGS=(--path "$PROJECT_DIR")
|
|
68
|
+
if [ -n "$OP_TOKEN" ]; then
|
|
69
|
+
SETUP_ARGS+=(--op-token "$OP_TOKEN")
|
|
70
|
+
fi
|
|
71
|
+
if [ -n "$MAKERKIT_FLAG" ]; then
|
|
72
|
+
SETUP_ARGS+=("$MAKERKIT_FLAG")
|
|
73
|
+
fi
|
|
74
|
+
sudo -u "$ORIGINAL_USER" "$SCRIPT_DIR/setup.sh" "${SETUP_ARGS[@]}"
|
|
75
|
+
|
|
76
|
+
# 3. Protect (as root)
|
|
77
|
+
"$SCRIPT_DIR/setup.sh" --path "$PROJECT_DIR" --protect-only
|
|
78
|
+
|
|
79
|
+
echo ""
|
|
80
|
+
echo "════════════════════════════════════════════════════════════"
|
|
81
|
+
echo " Reinstall complete!"
|
|
82
|
+
echo ""
|
|
83
|
+
echo " Next steps:"
|
|
84
|
+
echo " 1. Start a new Claude Code session"
|
|
85
|
+
echo " 2. Run /setup-gentyr to configure credentials"
|
|
86
|
+
echo "════════════════════════════════════════════════════════════"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Re-sign Homebrew's Node.js binary for macOS TCC persistence
|
|
3
|
+
#
|
|
4
|
+
# macOS TCC (Transparency, Consent, and Control) requires binaries to have
|
|
5
|
+
# a stable code identity to remember permission grants. Homebrew's node is
|
|
6
|
+
# ad-hoc signed (no team identifier), so macOS re-prompts on every new
|
|
7
|
+
# process. This script creates a self-signed certificate and re-signs node,
|
|
8
|
+
# giving it a stable identity that TCC can persist.
|
|
9
|
+
#
|
|
10
|
+
# Run after: brew upgrade node
|
|
11
|
+
# Run during: GENTYR setup (called automatically by setup.sh)
|
|
12
|
+
#
|
|
13
|
+
# Usage: scripts/resign-node.sh [--check] [--trigger-tcc]
|
|
14
|
+
|
|
15
|
+
set -eo pipefail
|
|
16
|
+
|
|
17
|
+
CERT_NAME="NodeLocalDev"
|
|
18
|
+
RED='\033[0;31m'
|
|
19
|
+
GREEN='\033[0;32m'
|
|
20
|
+
YELLOW='\033[1;33m'
|
|
21
|
+
NC='\033[0m'
|
|
22
|
+
|
|
23
|
+
# Resolve the actual node binary (follow symlinks)
|
|
24
|
+
NODE_SYMLINK="/opt/homebrew/bin/node"
|
|
25
|
+
if [ ! -e "$NODE_SYMLINK" ]; then
|
|
26
|
+
# Fallback for non-Homebrew installs
|
|
27
|
+
NODE_SYMLINK="$(which node 2>/dev/null || true)"
|
|
28
|
+
if [ -z "$NODE_SYMLINK" ]; then
|
|
29
|
+
echo -e "${RED}Error: node not found${NC}"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
NODE_PATH="$(readlink -f "$NODE_SYMLINK" 2>/dev/null || realpath "$NODE_SYMLINK" 2>/dev/null || echo "$NODE_SYMLINK")"
|
|
34
|
+
|
|
35
|
+
# --check mode: just report current signing status
|
|
36
|
+
if [ "$1" = "--check" ]; then
|
|
37
|
+
AUTHORITY=$(codesign -dvv "$NODE_PATH" 2>&1 | grep "^Authority=" | head -1 | cut -d= -f2)
|
|
38
|
+
if [ "$AUTHORITY" = "$CERT_NAME" ]; then
|
|
39
|
+
echo -e "${GREEN}Node is signed with $CERT_NAME${NC}"
|
|
40
|
+
echo " Binary: $NODE_PATH"
|
|
41
|
+
exit 0
|
|
42
|
+
elif echo "$AUTHORITY" | grep -q "adhoc"; then
|
|
43
|
+
echo -e "${YELLOW}Node has ad-hoc signature (TCC prompts will repeat)${NC}"
|
|
44
|
+
echo " Binary: $NODE_PATH"
|
|
45
|
+
exit 1
|
|
46
|
+
else
|
|
47
|
+
echo -e "${YELLOW}Node signed by: ${AUTHORITY:-unknown}${NC}"
|
|
48
|
+
echo " Binary: $NODE_PATH"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# TCC trigger: run op through node so macOS attributes the access to node
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
trigger_tcc_prompt() {
|
|
57
|
+
# Check if op is installed
|
|
58
|
+
if ! command -v op &>/dev/null; then
|
|
59
|
+
echo -e " ${YELLOW}1Password CLI (op) not found - skipping TCC trigger${NC}"
|
|
60
|
+
return 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo -e "${YELLOW}Triggering macOS TCC permission for 1Password access...${NC}"
|
|
64
|
+
echo -e " (If a macOS dialog appears, click Allow to grant permission)"
|
|
65
|
+
|
|
66
|
+
# Run op through node so macOS attributes the IPC access to node's code identity.
|
|
67
|
+
# This mirrors what hourly-automation.js does with execFileSync('op', ...).
|
|
68
|
+
TCC_RESULT=$("$NODE_PATH" -e "
|
|
69
|
+
const { execFileSync } = require('child_process');
|
|
70
|
+
try {
|
|
71
|
+
execFileSync('op', ['vault', 'list', '--format', 'json'], {
|
|
72
|
+
encoding: 'utf-8',
|
|
73
|
+
timeout: 30000,
|
|
74
|
+
stdio: 'pipe',
|
|
75
|
+
});
|
|
76
|
+
process.stdout.write('ok');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
process.stderr.write(err.message || 'failed');
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
" 2>/dev/null) || true
|
|
82
|
+
|
|
83
|
+
if [ "$TCC_RESULT" = "ok" ]; then
|
|
84
|
+
echo -e " ${GREEN}TCC permission granted - verifying persistence...${NC}"
|
|
85
|
+
# Run a second time to confirm no new prompt appears
|
|
86
|
+
VERIFY_RESULT=$("$NODE_PATH" -e "
|
|
87
|
+
const { execFileSync } = require('child_process');
|
|
88
|
+
try {
|
|
89
|
+
execFileSync('op', ['vault', 'list', '--format', 'json'], {
|
|
90
|
+
encoding: 'utf-8',
|
|
91
|
+
timeout: 15000,
|
|
92
|
+
stdio: 'pipe',
|
|
93
|
+
});
|
|
94
|
+
process.stdout.write('persisted');
|
|
95
|
+
} catch {
|
|
96
|
+
process.stdout.write('failed');
|
|
97
|
+
}
|
|
98
|
+
" 2>/dev/null) || true
|
|
99
|
+
|
|
100
|
+
if [ "$VERIFY_RESULT" = "persisted" ]; then
|
|
101
|
+
echo -e " ${GREEN}TCC permission verified and persisted - no future prompts expected${NC}"
|
|
102
|
+
else
|
|
103
|
+
echo -e " ${YELLOW}TCC verification inconclusive - permission may need re-granting${NC}"
|
|
104
|
+
fi
|
|
105
|
+
else
|
|
106
|
+
echo -e " ${YELLOW}1Password access check failed (may not be signed in)${NC}"
|
|
107
|
+
echo -e " ${YELLOW}TCC prompt will appear on first automation run instead${NC}"
|
|
108
|
+
fi
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# --trigger-tcc mode: just trigger and verify TCC without re-signing
|
|
112
|
+
if [ "$1" = "--trigger-tcc" ]; then
|
|
113
|
+
trigger_tcc_prompt
|
|
114
|
+
exit 0
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
echo -e "${YELLOW}Re-signing node for macOS TCC persistence...${NC}"
|
|
118
|
+
echo " Binary: $NODE_PATH"
|
|
119
|
+
|
|
120
|
+
# Check if certificate exists
|
|
121
|
+
CERT_EXISTS=$(security find-identity -v -p codesigning 2>&1 | grep "$CERT_NAME" || true)
|
|
122
|
+
|
|
123
|
+
if [ -z "$CERT_EXISTS" ]; then
|
|
124
|
+
echo -e " ${YELLOW}Creating self-signed codesigning certificate '$CERT_NAME'...${NC}"
|
|
125
|
+
|
|
126
|
+
# Generate certificate with openssl
|
|
127
|
+
TMPDIR_CERT="$(mktemp -d)"
|
|
128
|
+
openssl req -x509 -newkey rsa:2048 \
|
|
129
|
+
-keyout "$TMPDIR_CERT/key.pem" \
|
|
130
|
+
-out "$TMPDIR_CERT/cert.pem" \
|
|
131
|
+
-days 3650 \
|
|
132
|
+
-nodes \
|
|
133
|
+
-subj "/CN=$CERT_NAME/O=LocalDev" \
|
|
134
|
+
-addext "keyUsage=digitalSignature" \
|
|
135
|
+
-addext "extendedKeyUsage=codeSigning" \
|
|
136
|
+
2>/dev/null
|
|
137
|
+
|
|
138
|
+
# Create PKCS12 bundle and import into login keychain
|
|
139
|
+
openssl pkcs12 -export \
|
|
140
|
+
-out "$TMPDIR_CERT/cert.p12" \
|
|
141
|
+
-inkey "$TMPDIR_CERT/key.pem" \
|
|
142
|
+
-in "$TMPDIR_CERT/cert.pem" \
|
|
143
|
+
-passout pass:temp123 \
|
|
144
|
+
2>/dev/null
|
|
145
|
+
|
|
146
|
+
security import "$TMPDIR_CERT/cert.p12" \
|
|
147
|
+
-k ~/Library/Keychains/login.keychain-db \
|
|
148
|
+
-P temp123 \
|
|
149
|
+
-T /usr/bin/codesign \
|
|
150
|
+
-T /usr/bin/security \
|
|
151
|
+
2>/dev/null
|
|
152
|
+
|
|
153
|
+
# Trust the certificate for code signing
|
|
154
|
+
security add-trusted-cert -d -r trustRoot -p codeSign \
|
|
155
|
+
-k ~/Library/Keychains/login.keychain-db \
|
|
156
|
+
"$TMPDIR_CERT/cert.pem" \
|
|
157
|
+
2>/dev/null
|
|
158
|
+
|
|
159
|
+
# Clean up temp files
|
|
160
|
+
rm -rf "$TMPDIR_CERT"
|
|
161
|
+
|
|
162
|
+
echo -e " ${GREEN}Certificate '$CERT_NAME' created and trusted${NC}"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# Check current signature
|
|
166
|
+
CURRENT_AUTHORITY=$(codesign -dvv "$NODE_PATH" 2>&1 | grep "^Authority=" | head -1 | cut -d= -f2)
|
|
167
|
+
if [ "$CURRENT_AUTHORITY" = "$CERT_NAME" ]; then
|
|
168
|
+
echo -e " ${GREEN}Already signed with $CERT_NAME - no re-signing needed${NC}"
|
|
169
|
+
trigger_tcc_prompt
|
|
170
|
+
exit 0
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
# Re-sign the node binary
|
|
174
|
+
codesign -fs "$CERT_NAME" "$NODE_PATH" 2>&1
|
|
175
|
+
echo -e " ${GREEN}Signed: $NODE_PATH${NC}"
|
|
176
|
+
|
|
177
|
+
# Verify
|
|
178
|
+
VERIFY=$(codesign -dvv "$NODE_PATH" 2>&1 | grep "^Authority=" | head -1)
|
|
179
|
+
echo -e " ${GREEN}Verified: $VERIFY${NC}"
|
|
180
|
+
echo ""
|
|
181
|
+
echo -e "${GREEN}Done. Node re-signed with $CERT_NAME.${NC}"
|
|
182
|
+
|
|
183
|
+
# Trigger TCC prompt so the user grants permission now (during setup),
|
|
184
|
+
# not randomly later during background automation.
|
|
185
|
+
trigger_tcc_prompt
|