@humanbased/crosscheck 1.2.0 → 1.3.0-beta.100
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/LICENSE +1 -1
- package/README.md +183 -375
- package/README.zh.md +1 -1
- package/assets/icon-256.png +0 -0
- package/assets/linear-comment.svg +18 -0
- package/assets/linear-onboard.svg +30 -0
- package/assets/linear-status.svg +23 -0
- package/assets/linear-test.svg +34 -0
- package/assets/skills/code-review/.crosscheck-skill.json +9 -0
- package/assets/skills/code-review/LICENSE +21 -0
- package/assets/skills/code-review/SKILL.md +89 -0
- package/assets/skills/code-review/agents/openai.yaml +3 -0
- package/assets/skills/code-review-skill/.crosscheck-skill.json +9 -0
- package/assets/skills/code-review-skill/LICENSE +21 -0
- package/assets/skills/code-review-skill/SKILL.md +231 -0
- package/assets/skills/code-review-skill/assets/pr-review-template.md +137 -0
- package/assets/skills/code-review-skill/assets/review-checklist.md +123 -0
- package/assets/skills/code-review-skill/reference/angular.md +768 -0
- package/assets/skills/code-review-skill/reference/architecture-review-guide.md +472 -0
- package/assets/skills/code-review-skill/reference/c.md +890 -0
- package/assets/skills/code-review-skill/reference/code-quality-universal.md +488 -0
- package/assets/skills/code-review-skill/reference/code-review-best-practices.md +136 -0
- package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +286 -0
- package/assets/skills/code-review-skill/reference/cpp.md +893 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +515 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +492 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +309 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +308 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +264 -0
- package/assets/skills/code-review-skill/reference/csharp.md +525 -0
- package/assets/skills/code-review-skill/reference/css-less-sass.md +661 -0
- package/assets/skills/code-review-skill/reference/django.md +985 -0
- package/assets/skills/code-review-skill/reference/fastapi.md +580 -0
- package/assets/skills/code-review-skill/reference/go.md +993 -0
- package/assets/skills/code-review-skill/reference/java.md +409 -0
- package/assets/skills/code-review-skill/reference/java8.md +586 -0
- package/assets/skills/code-review-skill/reference/kotlin.md +1018 -0
- package/assets/skills/code-review-skill/reference/nestjs.md +593 -0
- package/assets/skills/code-review-skill/reference/performance-review-guide.md +816 -0
- package/assets/skills/code-review-skill/reference/php.md +684 -0
- package/assets/skills/code-review-skill/reference/python.md +1073 -0
- package/assets/skills/code-review-skill/reference/qt.md +757 -0
- package/assets/skills/code-review-skill/reference/react.md +871 -0
- package/assets/skills/code-review-skill/reference/ruby.md +964 -0
- package/assets/skills/code-review-skill/reference/rust.md +846 -0
- package/assets/skills/code-review-skill/reference/security-review-guide.md +494 -0
- package/assets/skills/code-review-skill/reference/svelte.md +1064 -0
- package/assets/skills/code-review-skill/reference/swift.md +936 -0
- package/assets/skills/code-review-skill/reference/typescript.md +1016 -0
- package/assets/skills/code-review-skill/reference/vue.md +924 -0
- package/assets/skills/code-review-skill/reference/zig.md +440 -0
- package/assets/skills/code-review-skill/scripts/pr-analyzer.py +435 -0
- package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +380 -0
- package/assets/skills/codebase-design/.crosscheck-skill.json +9 -0
- package/assets/skills/codebase-design/DEEPENING.md +37 -0
- package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/assets/skills/codebase-design/LICENSE +21 -0
- package/assets/skills/codebase-design/SKILL.md +114 -0
- package/assets/skills/codebase-design/agents/openai.yaml +3 -0
- package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +9 -0
- package/assets/skills/diagnosing-bugs/LICENSE +21 -0
- package/assets/skills/diagnosing-bugs/SKILL.md +134 -0
- package/assets/skills/diagnosing-bugs/agents/openai.yaml +3 -0
- package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/crosscheck.config.example.yml +124 -11
- package/dist/__tests__/adoption.test.d.ts +2 -0
- package/dist/__tests__/adoption.test.d.ts.map +1 -0
- package/dist/__tests__/adoption.test.js +175 -0
- package/dist/__tests__/adoption.test.js.map +1 -0
- package/dist/__tests__/auto-fix-branch.test.d.ts +2 -0
- package/dist/__tests__/auto-fix-branch.test.d.ts.map +1 -0
- package/dist/__tests__/auto-fix-branch.test.js +143 -0
- package/dist/__tests__/auto-fix-branch.test.js.map +1 -0
- package/dist/__tests__/board.test.js +13 -0
- package/dist/__tests__/board.test.js.map +1 -1
- package/dist/__tests__/can-write-verdict.test.d.ts +2 -0
- package/dist/__tests__/can-write-verdict.test.d.ts.map +1 -0
- package/dist/__tests__/can-write-verdict.test.js +31 -0
- package/dist/__tests__/can-write-verdict.test.js.map +1 -0
- package/dist/__tests__/codex-env.test.d.ts +2 -0
- package/dist/__tests__/codex-env.test.d.ts.map +1 -0
- package/dist/__tests__/codex-env.test.js +70 -0
- package/dist/__tests__/codex-env.test.js.map +1 -0
- package/dist/__tests__/codex.test.js +100 -25
- package/dist/__tests__/codex.test.js.map +1 -1
- package/dist/__tests__/comment-bodies.test.js +49 -1
- package/dist/__tests__/comment-bodies.test.js.map +1 -1
- package/dist/__tests__/commit-subject.test.d.ts +2 -0
- package/dist/__tests__/commit-subject.test.d.ts.map +1 -0
- package/dist/__tests__/commit-subject.test.js +72 -0
- package/dist/__tests__/commit-subject.test.js.map +1 -0
- package/dist/__tests__/conflict-resolve.test.js +44 -1
- package/dist/__tests__/conflict-resolve.test.js.map +1 -1
- package/dist/__tests__/credential-free-origin.test.d.ts +2 -0
- package/dist/__tests__/credential-free-origin.test.d.ts.map +1 -0
- package/dist/__tests__/credential-free-origin.test.js +59 -0
- package/dist/__tests__/credential-free-origin.test.js.map +1 -0
- package/dist/__tests__/detector.test.js +87 -1
- package/dist/__tests__/detector.test.js.map +1 -1
- package/dist/__tests__/error-classification.test.js +34 -0
- package/dist/__tests__/error-classification.test.js.map +1 -1
- package/dist/__tests__/fix.test.js +69 -0
- package/dist/__tests__/fix.test.js.map +1 -1
- package/dist/__tests__/harness-section.test.d.ts +2 -0
- package/dist/__tests__/harness-section.test.d.ts.map +1 -0
- package/dist/__tests__/harness-section.test.js +46 -0
- package/dist/__tests__/harness-section.test.js.map +1 -0
- package/dist/__tests__/kickass.test.js +31 -0
- package/dist/__tests__/kickass.test.js.map +1 -1
- package/dist/__tests__/linear-branding.test.d.ts +2 -0
- package/dist/__tests__/linear-branding.test.d.ts.map +1 -0
- package/dist/__tests__/linear-branding.test.js +156 -0
- package/dist/__tests__/linear-branding.test.js.map +1 -0
- package/dist/__tests__/linear-client.test.d.ts +2 -0
- package/dist/__tests__/linear-client.test.d.ts.map +1 -0
- package/dist/__tests__/linear-client.test.js +120 -0
- package/dist/__tests__/linear-client.test.js.map +1 -0
- package/dist/__tests__/linear-comment.test.d.ts +2 -0
- package/dist/__tests__/linear-comment.test.d.ts.map +1 -0
- package/dist/__tests__/linear-comment.test.js +151 -0
- package/dist/__tests__/linear-comment.test.js.map +1 -0
- package/dist/__tests__/linear-identity.test.d.ts +2 -0
- package/dist/__tests__/linear-identity.test.d.ts.map +1 -0
- package/dist/__tests__/linear-identity.test.js +253 -0
- package/dist/__tests__/linear-identity.test.js.map +1 -0
- package/dist/__tests__/linear-notify.test.d.ts +2 -0
- package/dist/__tests__/linear-notify.test.d.ts.map +1 -0
- package/dist/__tests__/linear-notify.test.js +144 -0
- package/dist/__tests__/linear-notify.test.js.map +1 -0
- package/dist/__tests__/linear-ref.test.d.ts +2 -0
- package/dist/__tests__/linear-ref.test.d.ts.map +1 -0
- package/dist/__tests__/linear-ref.test.js +261 -0
- package/dist/__tests__/linear-ref.test.js.map +1 -0
- package/dist/__tests__/linear-test-ref.test.d.ts +2 -0
- package/dist/__tests__/linear-test-ref.test.d.ts.map +1 -0
- package/dist/__tests__/linear-test-ref.test.js +81 -0
- package/dist/__tests__/linear-test-ref.test.js.map +1 -0
- package/dist/__tests__/linear-verify.test.d.ts +2 -0
- package/dist/__tests__/linear-verify.test.d.ts.map +1 -0
- package/dist/__tests__/linear-verify.test.js +132 -0
- package/dist/__tests__/linear-verify.test.js.map +1 -0
- package/dist/__tests__/linear-worker.test.d.ts +2 -0
- package/dist/__tests__/linear-worker.test.d.ts.map +1 -0
- package/dist/__tests__/linear-worker.test.js +83 -0
- package/dist/__tests__/linear-worker.test.js.map +1 -0
- package/dist/__tests__/linear-write-possible.test.d.ts +2 -0
- package/dist/__tests__/linear-write-possible.test.d.ts.map +1 -0
- package/dist/__tests__/linear-write-possible.test.js +30 -0
- package/dist/__tests__/linear-write-possible.test.js.map +1 -0
- package/dist/__tests__/loader.test.js +2 -2
- package/dist/__tests__/loader.test.js.map +1 -1
- package/dist/__tests__/onboard-preservation.test.js +59 -4
- package/dist/__tests__/onboard-preservation.test.js.map +1 -1
- package/dist/__tests__/optimize.test.js +2 -0
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/__tests__/pr-status.test.js +213 -3
- package/dist/__tests__/pr-status.test.js.map +1 -1
- package/dist/__tests__/pr-workflow-state.test.js +247 -7
- package/dist/__tests__/pr-workflow-state.test.js.map +1 -1
- package/dist/__tests__/repo-picker.test.js +7 -1
- package/dist/__tests__/repo-picker.test.js.map +1 -1
- package/dist/__tests__/repository-guidance.test.d.ts +2 -0
- package/dist/__tests__/repository-guidance.test.d.ts.map +1 -0
- package/dist/__tests__/repository-guidance.test.js +107 -0
- package/dist/__tests__/repository-guidance.test.js.map +1 -0
- package/dist/__tests__/review-comment-body.test.js +35 -0
- package/dist/__tests__/review-comment-body.test.js.map +1 -1
- package/dist/__tests__/review-models.test.js +19 -3
- package/dist/__tests__/review-models.test.js.map +1 -1
- package/dist/__tests__/review-strategy.test.d.ts +2 -0
- package/dist/__tests__/review-strategy.test.d.ts.map +1 -0
- package/dist/__tests__/review-strategy.test.js +397 -0
- package/dist/__tests__/review-strategy.test.js.map +1 -0
- package/dist/__tests__/reviewed-sha.test.d.ts +2 -0
- package/dist/__tests__/reviewed-sha.test.d.ts.map +1 -0
- package/dist/__tests__/reviewed-sha.test.js +116 -0
- package/dist/__tests__/reviewed-sha.test.js.map +1 -0
- package/dist/__tests__/runner.test.js +206 -2
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/__tests__/skill-attribution.test.d.ts +2 -0
- package/dist/__tests__/skill-attribution.test.d.ts.map +1 -0
- package/dist/__tests__/skill-attribution.test.js +53 -0
- package/dist/__tests__/skill-attribution.test.js.map +1 -0
- package/dist/__tests__/skill-broker.test.d.ts +2 -0
- package/dist/__tests__/skill-broker.test.d.ts.map +1 -0
- package/dist/__tests__/skill-broker.test.js +186 -0
- package/dist/__tests__/skill-broker.test.js.map +1 -0
- package/dist/__tests__/skill-catalog.test.d.ts +2 -0
- package/dist/__tests__/skill-catalog.test.d.ts.map +1 -0
- package/dist/__tests__/skill-catalog.test.js +40 -0
- package/dist/__tests__/skill-catalog.test.js.map +1 -0
- package/dist/__tests__/skill-installer.test.d.ts +2 -0
- package/dist/__tests__/skill-installer.test.d.ts.map +1 -0
- package/dist/__tests__/skill-installer.test.js +96 -0
- package/dist/__tests__/skill-installer.test.js.map +1 -0
- package/dist/__tests__/skills-config.test.d.ts +2 -0
- package/dist/__tests__/skills-config.test.d.ts.map +1 -0
- package/dist/__tests__/skills-config.test.js +12 -0
- package/dist/__tests__/skills-config.test.js.map +1 -0
- package/dist/__tests__/superseded-fix-pr.test.d.ts +2 -0
- package/dist/__tests__/superseded-fix-pr.test.d.ts.map +1 -0
- package/dist/__tests__/superseded-fix-pr.test.js +225 -0
- package/dist/__tests__/superseded-fix-pr.test.js.map +1 -0
- package/dist/__tests__/webhook.test.js +60 -0
- package/dist/__tests__/webhook.test.js.map +1 -1
- package/dist/cli.js +37 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/adoption.d.ts +6 -0
- package/dist/commands/adoption.d.ts.map +1 -0
- package/dist/commands/adoption.js +132 -0
- package/dist/commands/adoption.js.map +1 -0
- package/dist/commands/detect-step.d.ts.map +1 -1
- package/dist/commands/detect-step.js +5 -1
- package/dist/commands/detect-step.js.map +1 -1
- package/dist/commands/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +2 -2
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/issue.js +1 -1
- package/dist/commands/issue.js.map +1 -1
- package/dist/commands/kickass.d.ts +1 -1
- package/dist/commands/kickass.d.ts.map +1 -1
- package/dist/commands/kickass.js +36 -22
- package/dist/commands/kickass.js.map +1 -1
- package/dist/commands/linear-test.d.ts +18 -0
- package/dist/commands/linear-test.d.ts.map +1 -0
- package/dist/commands/linear-test.js +130 -0
- package/dist/commands/linear-test.js.map +1 -0
- package/dist/commands/onboard.d.ts +36 -3
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +263 -45
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/optimize.d.ts.map +1 -1
- package/dist/commands/optimize.js +1 -0
- package/dist/commands/optimize.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +65 -6
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +85 -11
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +6 -0
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/skill.d.ts +2 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +16 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +53 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +215 -66
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/loader.d.ts +3 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +19 -6
- package/dist/config/loader.js.map +1 -1
- package/dist/config/review-model-tiers.json +3 -3
- package/dist/config/review-strategy.json +204 -0
- package/dist/config/schema.d.ts +269 -15
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +109 -10
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.d.ts +21 -1
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +46 -7
- package/dist/github/client.js.map +1 -1
- package/dist/github/detector.d.ts.map +1 -1
- package/dist/github/detector.js +28 -1
- package/dist/github/detector.js.map +1 -1
- package/dist/github/merge.d.ts +0 -5
- package/dist/github/merge.d.ts.map +1 -1
- package/dist/github/merge.js +0 -9
- package/dist/github/merge.js.map +1 -1
- package/dist/github/reviewed-sha.d.ts +13 -0
- package/dist/github/reviewed-sha.d.ts.map +1 -0
- package/dist/github/reviewed-sha.js +62 -0
- package/dist/github/reviewed-sha.js.map +1 -0
- package/dist/github/superseded-fix-pr.d.ts +19 -0
- package/dist/github/superseded-fix-pr.d.ts.map +1 -0
- package/dist/github/superseded-fix-pr.js +97 -0
- package/dist/github/superseded-fix-pr.js.map +1 -0
- package/dist/github/webhook.d.ts +8 -1
- package/dist/github/webhook.d.ts.map +1 -1
- package/dist/github/webhook.js +8 -1
- package/dist/github/webhook.js.map +1 -1
- package/dist/issues/ticket-ref.d.ts.map +1 -1
- package/dist/issues/ticket-ref.js +6 -5
- package/dist/issues/ticket-ref.js.map +1 -1
- package/dist/lib/adoption.d.ts +64 -0
- package/dist/lib/adoption.d.ts.map +1 -0
- package/dist/lib/adoption.js +165 -0
- package/dist/lib/adoption.js.map +1 -0
- package/dist/lib/annotation.d.ts +7 -0
- package/dist/lib/annotation.d.ts.map +1 -1
- package/dist/lib/annotation.js +11 -8
- package/dist/lib/annotation.js.map +1 -1
- package/dist/lib/auto-fix-branch.d.ts +35 -0
- package/dist/lib/auto-fix-branch.d.ts.map +1 -0
- package/dist/lib/auto-fix-branch.js +88 -0
- package/dist/lib/auto-fix-branch.js.map +1 -0
- package/dist/lib/board.d.ts +3 -0
- package/dist/lib/board.d.ts.map +1 -1
- package/dist/lib/board.js +4 -2
- package/dist/lib/board.js.map +1 -1
- package/dist/lib/clone.d.ts +2 -0
- package/dist/lib/clone.d.ts.map +1 -1
- package/dist/lib/clone.js +69 -10
- package/dist/lib/clone.js.map +1 -1
- package/dist/lib/comment-bodies.d.ts +37 -0
- package/dist/lib/comment-bodies.d.ts.map +1 -1
- package/dist/lib/comment-bodies.js +50 -9
- package/dist/lib/comment-bodies.js.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +17 -1
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/pr-picker.d.ts +1 -1
- package/dist/lib/pr-picker.d.ts.map +1 -1
- package/dist/lib/pr-picker.js +10 -5
- package/dist/lib/pr-picker.js.map +1 -1
- package/dist/lib/pr-status.d.ts +2 -1
- package/dist/lib/pr-status.d.ts.map +1 -1
- package/dist/lib/pr-status.js +70 -6
- package/dist/lib/pr-status.js.map +1 -1
- package/dist/lib/pr-workflow-state.d.ts +17 -1
- package/dist/lib/pr-workflow-state.d.ts.map +1 -1
- package/dist/lib/pr-workflow-state.js +110 -5
- package/dist/lib/pr-workflow-state.js.map +1 -1
- package/dist/lib/repo-picker.d.ts +3 -0
- package/dist/lib/repo-picker.d.ts.map +1 -1
- package/dist/lib/repo-picker.js +45 -10
- package/dist/lib/repo-picker.js.map +1 -1
- package/dist/lib/repository-guidance.d.ts +2 -0
- package/dist/lib/repository-guidance.d.ts.map +1 -0
- package/dist/lib/repository-guidance.js +55 -0
- package/dist/lib/repository-guidance.js.map +1 -0
- package/dist/lib/review-models.d.ts +15 -2
- package/dist/lib/review-models.d.ts.map +1 -1
- package/dist/lib/review-models.js +26 -6
- package/dist/lib/review-models.js.map +1 -1
- package/dist/lib/review-strategy.d.ts +92 -0
- package/dist/lib/review-strategy.d.ts.map +1 -0
- package/dist/lib/review-strategy.js +282 -0
- package/dist/lib/review-strategy.js.map +1 -0
- package/dist/lib/runner.d.ts +123 -1
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +919 -101
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/vendor.d.ts +1 -0
- package/dist/lib/vendor.d.ts.map +1 -1
- package/dist/lib/vendor.js +6 -0
- package/dist/lib/vendor.js.map +1 -1
- package/dist/lib/workflow.d.ts +13 -0
- package/dist/lib/workflow.d.ts.map +1 -1
- package/dist/lib/workflow.js +24 -1
- package/dist/lib/workflow.js.map +1 -1
- package/dist/linear/client.d.ts +18 -0
- package/dist/linear/client.d.ts.map +1 -0
- package/dist/linear/client.js +67 -0
- package/dist/linear/client.js.map +1 -0
- package/dist/linear/comment.d.ts +20 -0
- package/dist/linear/comment.d.ts.map +1 -0
- package/dist/linear/comment.js +57 -0
- package/dist/linear/comment.js.map +1 -0
- package/dist/linear/identity.d.ts +59 -0
- package/dist/linear/identity.d.ts.map +1 -0
- package/dist/linear/identity.js +187 -0
- package/dist/linear/identity.js.map +1 -0
- package/dist/linear/notify.d.ts +35 -0
- package/dist/linear/notify.d.ts.map +1 -0
- package/dist/linear/notify.js +76 -0
- package/dist/linear/notify.js.map +1 -0
- package/dist/linear/ref.d.ts +13 -0
- package/dist/linear/ref.d.ts.map +1 -0
- package/dist/linear/ref.js +90 -0
- package/dist/linear/ref.js.map +1 -0
- package/dist/linear/verify.d.ts +26 -0
- package/dist/linear/verify.d.ts.map +1 -0
- package/dist/linear/verify.js +67 -0
- package/dist/linear/verify.js.map +1 -0
- package/dist/reviewers/address.d.ts +1 -1
- package/dist/reviewers/address.d.ts.map +1 -1
- package/dist/reviewers/address.js +1 -1
- package/dist/reviewers/address.js.map +1 -1
- package/dist/reviewers/claude.d.ts +4 -1
- package/dist/reviewers/claude.d.ts.map +1 -1
- package/dist/reviewers/claude.js +39 -7
- package/dist/reviewers/claude.js.map +1 -1
- package/dist/reviewers/codex-env.d.ts +12 -0
- package/dist/reviewers/codex-env.d.ts.map +1 -0
- package/dist/reviewers/codex-env.js +54 -0
- package/dist/reviewers/codex-env.js.map +1 -0
- package/dist/reviewers/codex.d.ts +18 -1
- package/dist/reviewers/codex.d.ts.map +1 -1
- package/dist/reviewers/codex.js +164 -81
- package/dist/reviewers/codex.js.map +1 -1
- package/dist/reviewers/conflict-resolve.d.ts +3 -1
- package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
- package/dist/reviewers/conflict-resolve.js +21 -6
- package/dist/reviewers/conflict-resolve.js.map +1 -1
- package/dist/reviewers/fix.d.ts +5 -2
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +38 -12
- package/dist/reviewers/fix.js.map +1 -1
- package/dist/skills/attribution.d.ts +4 -0
- package/dist/skills/attribution.d.ts.map +1 -0
- package/dist/skills/attribution.js +14 -0
- package/dist/skills/attribution.js.map +1 -0
- package/dist/skills/broker-server.d.ts +2 -0
- package/dist/skills/broker-server.d.ts.map +1 -0
- package/dist/skills/broker-server.js +17 -0
- package/dist/skills/broker-server.js.map +1 -0
- package/dist/skills/broker.d.ts +43 -0
- package/dist/skills/broker.d.ts.map +1 -0
- package/dist/skills/broker.js +311 -0
- package/dist/skills/broker.js.map +1 -0
- package/dist/skills/catalog.d.ts +28 -0
- package/dist/skills/catalog.d.ts.map +1 -0
- package/dist/skills/catalog.js +104 -0
- package/dist/skills/catalog.js.map +1 -0
- package/dist/skills/installer.d.ts +10 -0
- package/dist/skills/installer.d.ts.map +1 -0
- package/dist/skills/installer.js +138 -0
- package/dist/skills/installer.js.map +1 -0
- package/dist/skills/integrity.d.ts +4 -0
- package/dist/skills/integrity.d.ts.map +1 -0
- package/dist/skills/integrity.js +36 -0
- package/dist/skills/integrity.js.map +1 -0
- package/docs/dynamic-thoroughness.md +738 -0
- package/docs/linear-identity-contract.md +139 -0
- package/docs/linear-identity.md +293 -0
- package/docs/metrics.md +115 -0
- package/docs/trust.md +159 -0
- package/get-started.md +322 -16
- package/package.json +6 -3
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Linear identity: the shared contract
|
|
2
|
+
|
|
3
|
+
**Contract version: 1.1.** Additive changes bump the minor; removing or renaming a
|
|
4
|
+
field is a major bump and a breaking change for every adopter. 1.1 added
|
|
5
|
+
`identity.per_step_actor`, `identity.icon_url`, and the `{model}` / `{reviewer}` /
|
|
6
|
+
`{icon}` signature placeholders — all optional, all defaulted, so a 1.0
|
|
7
|
+
implementation stays conformant.
|
|
8
|
+
|
|
9
|
+
crosscheck and symphony are separate open-source products that both write to Linear.
|
|
10
|
+
This document is the contract they implement identically, so an operator configures
|
|
11
|
+
identity once and it means the same thing in both — and so a third product can adopt
|
|
12
|
+
it without inventing a fourth shape.
|
|
13
|
+
|
|
14
|
+
Humanbased's HB Agent Gateway is not special here. It is one `client_credentials`
|
|
15
|
+
configuration of this contract.
|
|
16
|
+
|
|
17
|
+
For step-by-step setup, see [linear-identity.md](linear-identity.md). This document is
|
|
18
|
+
the specification.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Config shape
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
linear:
|
|
26
|
+
enabled: false # opt-in; default off
|
|
27
|
+
auth:
|
|
28
|
+
mode: api_key # api_key | client_credentials
|
|
29
|
+
api_key_env: LINEAR_API_KEY
|
|
30
|
+
client_id_env: LINEAR_CLIENT_ID
|
|
31
|
+
client_secret_env: LINEAR_CLIENT_SECRET
|
|
32
|
+
scopes: "read write"
|
|
33
|
+
identity:
|
|
34
|
+
actor: crosscheck # product name; symphony uses `symphony`
|
|
35
|
+
signature: "🤖 {actor} · {product}"
|
|
36
|
+
per_step_actor: true # suffix the actor with the unit of work
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Every key under `auth` ending in `_env` names an **environment variable**, never a
|
|
40
|
+
secret. A product implementing this contract must not accept an inline credential in
|
|
41
|
+
config. Non-credential fields (`mode`, `scopes`, everything under `identity`) are
|
|
42
|
+
ordinary config values and are written literally.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Tiers
|
|
47
|
+
|
|
48
|
+
| Tier | Mode | Setup | Attribution |
|
|
49
|
+
|---|---|---|---|
|
|
50
|
+
| **T0** | `api_key` | none | Operator's account; signature line only |
|
|
51
|
+
| **T1** | `client_credentials` | one OAuth app | The app itself (botActor), via `createAsUser` |
|
|
52
|
+
| **T2** | public app | none (future) | Centrally operated app — see IN-2272 |
|
|
53
|
+
|
|
54
|
+
T0 is the default so an existing `api_key` config keeps working unchanged. T2 is not
|
|
55
|
+
implemented; it is gated on T1 adoption feedback.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Required behaviours
|
|
60
|
+
|
|
61
|
+
A conforming implementation must:
|
|
62
|
+
|
|
63
|
+
1. **Lead every write with the rendered signature.** `{actor}` and `{product}` are the
|
|
64
|
+
defined placeholders. This is T0's entire attribution mechanism and is retained in
|
|
65
|
+
T1 as fallback text.
|
|
66
|
+
|
|
67
|
+
2. **Mint T1 tokens per run, not per write.** Linear app tokens carry roughly a 30-day
|
|
68
|
+
TTL; treat them as ephemeral anyway. Resolve identity at run start so a
|
|
69
|
+
misconfiguration fails before any expensive work.
|
|
70
|
+
|
|
71
|
+
3. **Abort when a configured T1 mint fails.** Never fall back to `api_key`. A silent
|
|
72
|
+
downgrade re-attributes agent writes to a human, which is the failure the whole
|
|
73
|
+
contract exists to prevent. Surface the env var name that needs fixing.
|
|
74
|
+
|
|
75
|
+
4. **Keep secrets off argv.** The mint sends credentials in a POST body; the token
|
|
76
|
+
travels in an `Authorization` header. Nothing reaches a process list. Failure
|
|
77
|
+
messages carry HTTP status codes, never credential material.
|
|
78
|
+
|
|
79
|
+
5. **Preserve backward compatibility.** An existing `api_key` configuration must keep
|
|
80
|
+
working with T0 semantics and no new required keys.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Per-worker actors
|
|
85
|
+
|
|
86
|
+
`per_step_actor: true` suffixes the actor with the unit of work, so a fleet does not
|
|
87
|
+
collapse into one indistinguishable bot:
|
|
88
|
+
|
|
89
|
+
| Product | Unit of work | Example actor |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| crosscheck | workflow step | `crosscheck/review`, `crosscheck/fix`, `crosscheck/recheck` |
|
|
92
|
+
| symphony | worker | `symphony/worker-3` |
|
|
93
|
+
|
|
94
|
+
In T1 the suffixed name is what `createAsUser` sends, so it is what Linear renders. In
|
|
95
|
+
T0 it reaches only the signature line — still worth doing, since that is all T0 has.
|
|
96
|
+
|
|
97
|
+
The suffix composes: deriving twice yields `crosscheck/review/shard-2`. Deriving must
|
|
98
|
+
not mutate the base identity, so one run can produce several scoped identities from a
|
|
99
|
+
single minted token.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## The token mint
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
POST https://api.linear.app/oauth/token
|
|
107
|
+
Content-Type: application/x-www-form-urlencoded
|
|
108
|
+
|
|
109
|
+
grant_type=client_credentials&client_id=<id>&client_secret=<secret>&scope=read+write
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Response: `{ "access_token": "..." }`, used as `Authorization: Bearer <token>`.
|
|
113
|
+
|
|
114
|
+
T0 keys are sent **bare** — `Authorization: <key>` with no `Bearer` prefix. Getting
|
|
115
|
+
this backwards is the most common integration bug.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Two Linear gotchas worth encoding
|
|
120
|
+
|
|
121
|
+
Both cost real debugging time and neither is discoverable from the API:
|
|
122
|
+
|
|
123
|
+
- The OAuth application form **requires a Redirect URI** even though
|
|
124
|
+
`client_credentials` never uses one. Any placeholder on a domain you control works.
|
|
125
|
+
- `read write` does **not** cover initiatives. `initiative:read` and `initiative:write`
|
|
126
|
+
are separate scopes.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Reference implementation
|
|
131
|
+
|
|
132
|
+
crosscheck's lives in `src/linear/`:
|
|
133
|
+
|
|
134
|
+
| Concern | File |
|
|
135
|
+
|---|---|
|
|
136
|
+
| Auth resolution, token mint, `withWorker` | `identity.ts` |
|
|
137
|
+
| All Linear API traffic | `client.ts` |
|
|
138
|
+
| Which issue a write targets | `ref.ts` |
|
|
139
|
+
| Credential reads (the only place) | `../config/loader.ts` |
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Linear identity setup for your workspace
|
|
2
|
+
|
|
3
|
+
crosscheck can mirror a review verdict onto the Linear issue a PR belongs to. This
|
|
4
|
+
guide gets those writes attributed to *crosscheck* rather than to whoever's API key
|
|
5
|
+
the daemon happens to hold.
|
|
6
|
+
|
|
7
|
+
It assumes no prior Linear API experience. Budget about five minutes.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
By default an agent writing to Linear uses whatever API key the operator supplied —
|
|
14
|
+
usually a person's personal key. Every comment then looks like that person wrote it,
|
|
15
|
+
and there is no way to tell agent activity from human activity.
|
|
16
|
+
|
|
17
|
+
There is a ladder here. Each rung buys stronger attribution for a bit more setup —
|
|
18
|
+
**start at the bottom.** Most people never need to climb it.
|
|
19
|
+
|
|
20
|
+
| Rung | Mode | Setup | How writes appear |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| **T0** | `api_key` | one env var | Your account, led by a `🤖 crosscheck · <model>` signature line |
|
|
23
|
+
| **T1** | `client_credentials` | one OAuth app, ~5 min, once per workspace | crosscheck itself, with its own icon |
|
|
24
|
+
|
|
25
|
+
**T0 is not a broken version of T1.** Linear write-back is fully functional with just
|
|
26
|
+
an API key: crosscheck finds the issue and posts the comment. What T0 lacks is
|
|
27
|
+
*attribution*, not capability.
|
|
28
|
+
|
|
29
|
+
So the question isn't "which is better", it's **how many things write to your
|
|
30
|
+
workspace**. If you're the only one, T0 is the right answer and the app is ceremony.
|
|
31
|
+
If several agents and several humans all write, T0 makes them indistinguishable —
|
|
32
|
+
that's the problem T1 solves.
|
|
33
|
+
|
|
34
|
+
`crosscheck onboard` asks which rung you want and writes the config for you:
|
|
35
|
+
|
|
36
|
+
<img src="../assets/linear-onboard.svg" alt="crosscheck onboard, step 9.5 — choosing a Linear attribution rung" width="700" />
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## T0 — api_key (zero setup)
|
|
41
|
+
|
|
42
|
+
Create a personal API key under **Linear → Settings → API → Personal API keys**, then:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
export LINEAR_API_KEY=lin_api_...
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
linear:
|
|
50
|
+
enabled: true
|
|
51
|
+
auth:
|
|
52
|
+
mode: api_key
|
|
53
|
+
team_keys:
|
|
54
|
+
- IN # your team's key prefix
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Every write leads with `🤖 crosscheck · <model>`. Linear still records your account
|
|
58
|
+
as the author — the signature is a convention, not an identity.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## T1 — client_credentials (recommended)
|
|
63
|
+
|
|
64
|
+
### 1. Create an OAuth application
|
|
65
|
+
|
|
66
|
+
Go to **Linear → Settings → API → OAuth applications → Create new**.
|
|
67
|
+
|
|
68
|
+
Fill in a name (`crosscheck`, or whatever you want to see on comments) and an icon —
|
|
69
|
+
upload [`assets/icon-256.png`](../assets/icon-256.png) from this repo. That avatar is
|
|
70
|
+
what Linear renders beside every comment crosscheck posts, and it is the *only* way to
|
|
71
|
+
get the logo onto a comment: the icon comes from Linear's app settings, not from
|
|
72
|
+
anything crosscheck sends. On T0 your own avatar appears, because Linear genuinely
|
|
73
|
+
believes you wrote it.
|
|
74
|
+
|
|
75
|
+
> **Gotcha:** the form **requires a Redirect URI** even though client credentials never
|
|
76
|
+
> uses one. Any placeholder URL on a domain you control is fine —
|
|
77
|
+
> `https://example.com/callback`. It is never called.
|
|
78
|
+
|
|
79
|
+
### 2. Enable the client credentials toggle
|
|
80
|
+
|
|
81
|
+
On the application page, enable **Client credentials**. Without this the token mint in
|
|
82
|
+
step 5 returns `invalid_client`.
|
|
83
|
+
|
|
84
|
+
Also authorize the app for your workspace with **app-actor** ("application acts as
|
|
85
|
+
itself") so writes render as the app.
|
|
86
|
+
|
|
87
|
+
### 3. Choose scopes
|
|
88
|
+
|
|
89
|
+
`read,write` covers issues and comments — that is all crosscheck needs.
|
|
90
|
+
|
|
91
|
+
> **Gotcha:** `read,write` does **not** cover initiatives. `initiative:read` and
|
|
92
|
+
> `initiative:write` are separate scopes. Add them only if something else in your
|
|
93
|
+
> workspace needs them. Skip the admin scope.
|
|
94
|
+
|
|
95
|
+
### 4. Store the credentials
|
|
96
|
+
|
|
97
|
+
Copy the client ID and secret into your environment — never into the config file:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
export LINEAR_CLIENT_ID=...
|
|
101
|
+
export LINEAR_CLIENT_SECRET=...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 5. Verify the mint by hand
|
|
105
|
+
|
|
106
|
+
Confirm the credentials work before wiring crosscheck up. The form body goes through
|
|
107
|
+
**stdin**, so the secret never lands in your shell history or in `ps` output:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
printf 'grant_type=client_credentials&client_id=%s&client_secret=%s&scope=read,write' "$LINEAR_CLIENT_ID" "$LINEAR_CLIENT_SECRET" | curl -s -X POST https://api.linear.app/oauth/token -H 'Content-Type: application/x-www-form-urlencoded' --data @-
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A successful response contains `access_token`. If you get `invalid_client`, revisit
|
|
114
|
+
step 2 — the toggle is the usual cause.
|
|
115
|
+
|
|
116
|
+
### 6. Configure crosscheck
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
linear:
|
|
120
|
+
enabled: true
|
|
121
|
+
auth:
|
|
122
|
+
mode: client_credentials
|
|
123
|
+
client_id_env: LINEAR_CLIENT_ID
|
|
124
|
+
client_secret_env: LINEAR_CLIENT_SECRET
|
|
125
|
+
scopes: "read,write"
|
|
126
|
+
identity:
|
|
127
|
+
actor: crosscheck
|
|
128
|
+
comment_on: # default; add APPROVE to comment on clean reviews too
|
|
129
|
+
- NEEDS_WORK
|
|
130
|
+
- BLOCK
|
|
131
|
+
team_keys:
|
|
132
|
+
- IN
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Run a review against a PR whose branch or body references a Linear issue. The comment
|
|
136
|
+
should appear authored by the app, not by you.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## What the comment looks like
|
|
141
|
+
|
|
142
|
+
On the app rung, with the icon uploaded — the avatar and **APP** badge come from
|
|
143
|
+
Linear, which knows the writer is an application rather than a person:
|
|
144
|
+
|
|
145
|
+
<img src="../assets/linear-comment.svg" alt="A crosscheck review comment on a Linear issue, authored by the app actor" width="740" />
|
|
146
|
+
|
|
147
|
+
The raw markdown behind that:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
🤖 crosscheck/review · gpt-5.6-terra
|
|
151
|
+
|
|
152
|
+
**NEEDS_WORK** — codex (gpt-5.6-terra) review of [feat: add rate limiting to the public API](https://github.com/acme/app/pull/312)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The signature is a template — `linear.identity.signature`, with placeholders
|
|
156
|
+
`{actor}`, `{product}`, `{model}`, `{reviewer}`, and `{icon}`. Placeholders with no
|
|
157
|
+
value resolve to empty and the leftover separators are tidied, so one template works
|
|
158
|
+
whether or not the model is known.
|
|
159
|
+
|
|
160
|
+
The model appears in two places: the signature (if your template asks for it) and the
|
|
161
|
+
verdict line. When the vendor CLI picks the model without reporting which, the model
|
|
162
|
+
is omitted rather than guessed.
|
|
163
|
+
|
|
164
|
+
`{icon}` renders `linear.identity.icon_url` as an inline image. Before reaching for
|
|
165
|
+
it, note the caveat above: the app avatar is the supported way to brand a comment, and
|
|
166
|
+
inline images may render block-level rather than inline. Test it on a scratch issue
|
|
167
|
+
before adopting it.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Testing without waiting for a PR
|
|
172
|
+
|
|
173
|
+
`crosscheck linear-test` exercises the whole path and posts nothing:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
crosscheck linear-test ENG-42
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
<img src="../assets/linear-test.svg" alt="crosscheck linear-test verifying the Linear setup end to end without posting" width="700" />
|
|
180
|
+
|
|
181
|
+
It resolves your identity, looks the issue up for real, checks whether the verdict
|
|
182
|
+
would pass `comment_on`, and prints the exact comment body a review would post. Each
|
|
183
|
+
step reports separately, so a failure names itself rather than leaving you guessing.
|
|
184
|
+
|
|
185
|
+
Pass `--branch` or `--title` to test ref resolution the way a real PR would hit it,
|
|
186
|
+
and `--verdict` to preview a different outcome.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Verifying which identity you're on
|
|
191
|
+
|
|
192
|
+
`crosscheck status` shows a **Linear** section whenever `linear.enabled` is true. It
|
|
193
|
+
resolves the configured identity for real — minting a T1 token if that's the mode —
|
|
194
|
+
and reports what a write would render as:
|
|
195
|
+
|
|
196
|
+
<img src="../assets/linear-status.svg" alt="crosscheck status showing the Linear identity section" width="620" />
|
|
197
|
+
|
|
198
|
+
On the app rung the same rows read:
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
Linear
|
|
202
|
+
✓ auth mode client_credentials
|
|
203
|
+
organization Inductive Network
|
|
204
|
+
✓ writes as crosscheck/<step> (crosscheck itself)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
On T0 it names the human account instead, because that's the state worth seeing:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
Linear
|
|
211
|
+
✓ auth mode api_key
|
|
212
|
+
organization Inductive Network
|
|
213
|
+
✗ writes as yi@example.com (human — switch to client_credentials)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Run this before and after a cutover. The `✗` is the condition to eliminate.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Deploying with an existing OAuth app
|
|
221
|
+
|
|
222
|
+
If your organization already operates a gateway app, point the daemon at its
|
|
223
|
+
credentials rather than creating a second app. Only the env var *names* go in config:
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
linear:
|
|
227
|
+
enabled: true
|
|
228
|
+
auth:
|
|
229
|
+
mode: client_credentials
|
|
230
|
+
client_id_env: LINEAR_HB_AGENT_GATEWAY_CLIENT_ID
|
|
231
|
+
client_secret_env: LINEAR_HB_AGENT_GATEWAY_CLIENT_SECRET
|
|
232
|
+
identity:
|
|
233
|
+
actor: crosscheck
|
|
234
|
+
per_step_actor: true
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Cutover sequence:
|
|
238
|
+
|
|
239
|
+
1. Make the gateway credentials available to the **daemon's** environment — not just
|
|
240
|
+
your interactive shell. A systemd unit or launchd plist needs them explicitly.
|
|
241
|
+
2. Run `crosscheck status` and confirm `writes as ... (app actor)`.
|
|
242
|
+
3. Run one review end to end and confirm the Linear comment is authored by the app.
|
|
243
|
+
4. Only then retire the old personal API key from the daemon's environment.
|
|
244
|
+
|
|
245
|
+
Step 4 last, deliberately: until steps 2 and 3 pass, the old key is your rollback.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## How crosscheck finds the issue
|
|
250
|
+
|
|
251
|
+
Checked in order — branch name, then PR title, then PR body. Within each, an explicit
|
|
252
|
+
URL wins over a bare identifier.
|
|
253
|
+
|
|
254
|
+
1. **A `linear.app` issue URL** — `https://linear.app/acme/issue/IN-2269/slug`. Works
|
|
255
|
+
with no configuration, because it is unambiguous.
|
|
256
|
+
2. **A bare identifier** — `IN-2269`, matched case-insensitively so a branch like
|
|
257
|
+
`feat/in-2269-thing` resolves. **Only for keys listed in `team_keys`.**
|
|
258
|
+
|
|
259
|
+
That second restriction is deliberate. `UTF-8`, `SHA-256`, `ISO-8601`, `GPT-5` and
|
|
260
|
+
`RFC-2119` all have the same shape as a Linear identifier. Reading the wrong issue is
|
|
261
|
+
harmless; *commenting* on the wrong issue is not. So bare matching stays off until you
|
|
262
|
+
name your team keys.
|
|
263
|
+
|
|
264
|
+
If no issue is found, crosscheck skips the Linear write and the review proceeds
|
|
265
|
+
normally.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Security properties
|
|
270
|
+
|
|
271
|
+
- **Secrets never reach argv.** The mint sends them in a POST body; the GraphQL token
|
|
272
|
+
rides in a header. Nothing shows up in `ps`.
|
|
273
|
+
- **Secrets never reach logs or error traces.** Failure messages carry HTTP status
|
|
274
|
+
codes, not credentials.
|
|
275
|
+
- **Tokens are minted per run** and held in memory only. Linear app tokens have a ~30
|
|
276
|
+
day TTL, but crosscheck treats them as ephemeral.
|
|
277
|
+
- **A failed T1 mint aborts the run.** crosscheck will not fall back to `api_key` when
|
|
278
|
+
you configured `client_credentials` — a silent downgrade would put agent writes back
|
|
279
|
+
under a human's name, which is the exact failure this feature exists to prevent. You
|
|
280
|
+
get a non-zero exit and a message naming the env var to fix.
|
|
281
|
+
- **Config holds env var *names*, never values.**
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Troubleshooting
|
|
286
|
+
|
|
287
|
+
| Symptom | Cause |
|
|
288
|
+
|---|---|
|
|
289
|
+
| `LINEAR_CLIENT_ID and LINEAR_CLIENT_SECRET is not set` | Env vars missing from the daemon's environment (not just your shell) |
|
|
290
|
+
| `token mint rejected (HTTP 401)` | Client credentials toggle off, or wrong secret |
|
|
291
|
+
| `Linear API error: Access denied` | Scope too narrow — needs `write` |
|
|
292
|
+
| Comment never appears, no error | No issue ref found. Set `team_keys`, or put a `linear.app` URL in the PR body |
|
|
293
|
+
| Comment appears as you, not the app | Still on `mode: api_key` |
|
package/docs/metrics.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Metrics: what Crosscheck records, and where it stays
|
|
2
|
+
|
|
3
|
+
Crosscheck records what it did so you can tell whether it is working. Every number comes from local log files, and **nothing is transmitted**: there is no endpoint, no account, no upload, and no network call in any of the code that produces or reads these metrics. Telemetry is opt-in in the strongest available sense — it does not exist yet.
|
|
4
|
+
|
|
5
|
+
This document is the field-by-field inventory. If you find a field written to disk that is not listed here, that is a bug worth reporting.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Where it lives
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Location | `~/.crosscheck/logs/<YYYY-MM-DD>.ndjson` — one JSON object per line |
|
|
14
|
+
| On by default | Yes (`logs.enabled: true`) |
|
|
15
|
+
| Retention | `logs.retention_days`, default 30 — older files are deleted at startup |
|
|
16
|
+
| Turn it off | `logs.enabled: false` in `crosscheck.config.yml` |
|
|
17
|
+
|
|
18
|
+
Turning logging off is supported and costs you the reader commands: `crosscheck adoption`, `impact`, `diagnose`, and `optimize` all read these files and have nothing else to read.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Reading it
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
crosscheck adoption # activation, usage, weekly active repos, latency, first-run failures
|
|
26
|
+
crosscheck adoption --json # the same report as JSON
|
|
27
|
+
crosscheck adoption --since 2026-07-01 # narrow the window
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`crosscheck adoption` answers "is this being used, and does a PR get a verdict fast enough to matter". Its sibling `crosscheck impact` prices reviews that already happened. Both read the same files and neither makes a network call.
|
|
31
|
+
|
|
32
|
+
What the report shows:
|
|
33
|
+
|
|
34
|
+
| Metric | Derived from |
|
|
35
|
+
|---|---|
|
|
36
|
+
| onboard started / completed / abandoned | `onboard_started`, `onboard_completed` |
|
|
37
|
+
| reviews started / completed | `review_started`, `review_complete` |
|
|
38
|
+
| rechecks completed | `review_complete` with `step_type: recheck` |
|
|
39
|
+
| blocking findings posted | `blocking_finding_posted` |
|
|
40
|
+
| fixes applied | `fix_complete` with `applied_count > 0` |
|
|
41
|
+
| active repos, weekly active repos | distinct `repo` on `review_complete`, bucketed by ISO week |
|
|
42
|
+
| PR open → verdict (median, p90, slowest) | `open_to_verdict_ms` on `review_complete` |
|
|
43
|
+
| first-run failures | first `error` in a session that never logged a `review_complete` |
|
|
44
|
+
|
|
45
|
+
Two honest limits worth knowing before you quote a number:
|
|
46
|
+
|
|
47
|
+
- **Latency is only measured when the PR event carried an open time.** Hand-built events and some third-party webhook redeliveries do not. Those verdicts are excluded and counted separately as `unmeasured` rather than being given an invented start time.
|
|
48
|
+
- **Everything is bounded by the retention window.** A 30-day default means a "total" is a 30-day total. Raise `logs.retention_days` if you need a longer baseline.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## What is recorded
|
|
53
|
+
|
|
54
|
+
Identifying fields, on every event that has them:
|
|
55
|
+
|
|
56
|
+
| Field | Example | Why |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `ts` | `2026-07-08T10:00:00.000Z` | ordering, weekly bucketing |
|
|
59
|
+
| `event` | `review_complete` | what happened |
|
|
60
|
+
| `repo` | `acme/web` | which repo — this is a name, and it is the most identifying field written |
|
|
61
|
+
| `pr` | `245` | which PR number |
|
|
62
|
+
|
|
63
|
+
Everything else is a count, an enum, a duration, or a commit sha:
|
|
64
|
+
|
|
65
|
+
| Field | Shape |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `verdict` | `APPROVE` / `NEEDS WORK` / `BLOCK` |
|
|
68
|
+
| `reviewer`, `model`, `effort` | vendor and model identifiers |
|
|
69
|
+
| `step_type`, `step_name`, `round`, `trigger` | which step ran, and why |
|
|
70
|
+
| `duration_ms` | how long the reviewer ran |
|
|
71
|
+
| `open_to_verdict_ms` | PR open → verdict, in ms |
|
|
72
|
+
| `tokens_used`, `input_tokens`, `output_tokens` | integer counts |
|
|
73
|
+
| `applied_count`, `commentCount` | integer counts |
|
|
74
|
+
| `sha`, `head_sha` | commit shas |
|
|
75
|
+
| `category` | error class: `auth`, `permission`, `rate_limit`, `overloaded`, `budget`, `timeout`, `network`, `git`, `subprocess`, `unknown` |
|
|
76
|
+
| `message`, `stack`, `stderr` | on error events only — the failure text, truncated |
|
|
77
|
+
| `outcome`, `stage` | on `onboard_completed`: `completed` / `abandoned`, and where it stopped |
|
|
78
|
+
| `deployment`, `repos`, `orgs`, `quality_tier`, `quality_mode`, `pipeline`, `tunnel`, `linear` | on `onboard_completed`: the **shape** of the setup — counts and enums, never repo or org names |
|
|
79
|
+
|
|
80
|
+
## What is not recorded
|
|
81
|
+
|
|
82
|
+
Standard logs never contain:
|
|
83
|
+
|
|
84
|
+
- **source code or diffs**
|
|
85
|
+
- **reviewer prompts**
|
|
86
|
+
- **review text** — the verdict is recorded; the prose is not
|
|
87
|
+
- **PR titles or bodies**
|
|
88
|
+
- **PR author logins**
|
|
89
|
+
- **tokens, keys, or secrets** — the one place a token could appear is the clone URL, which is redacted to `x-access-token:[REDACTED]` on every path that could log it
|
|
90
|
+
|
|
91
|
+
Error events are the one place free text lands, because a failure you cannot read is a failure you cannot fix. `message`, `stack`, and `stderr` come from the failing subprocess or API call and are truncated. They can quote a file path or a git ref. They are local files, like everything else here.
|
|
92
|
+
|
|
93
|
+
### The extended tier
|
|
94
|
+
|
|
95
|
+
Richer fields — PR title, body, file paths, review text, author — exist behind `logs.extended.enabled`, which is:
|
|
96
|
+
|
|
97
|
+
- **off by default**,
|
|
98
|
+
- **not settable from any CLI flag** and not offered by `crosscheck onboard`, so it can only be turned on by hand-editing config, and
|
|
99
|
+
- **tagged** — every line it writes carries `"_extended": true`, so it can be filtered or scrubbed independently of standard logs.
|
|
100
|
+
|
|
101
|
+
If you have not deliberately edited your config, this tier is off and nothing in the product will nudge you toward it.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Transmission
|
|
106
|
+
|
|
107
|
+
There is none. To be specific about what that means:
|
|
108
|
+
|
|
109
|
+
- No Crosscheck-operated server exists, so there is nowhere for a payload to go.
|
|
110
|
+
- No code in `src/lib/adoption.ts` or `src/commands/adoption.ts` opens a socket.
|
|
111
|
+
- Reporting is a local CLI command that prints to your terminal.
|
|
112
|
+
|
|
113
|
+
If opt-in transmission is ever built, it will be per-category, individually documented, off unless you turn it on, and it will print the payload that leaves your machine. Until then, "opt-in telemetry" describes a design in `prd.md`, not shipped behaviour — and the metrics above are yours alone.
|
|
114
|
+
|
|
115
|
+
Related: [docs/trust.md](./trust.md) covers what leaves your machine during normal operation, which is a different question from what gets logged.
|